1 /* armos.c -- ARMulator OS interface: ARM6 Instruction Emulator.
2 Copyright (C) 1994 Advanced RISC Machines Ltd.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18 /* This file contains a model of Demon, ARM Ltd's Debug Monitor,
19 including all the SWI's required to support the C library. The code in
20 it is not really for the faint-hearted (especially the abort handling
21 code), but it is a complete example. Defining NOOS will disable all the
22 fun, and definign VAILDATE will define SWI 1 to enter SVC mode, and SWI
23 0x11 to halt the emulator. */
47 #define unlink(s) remove(s)
51 #include <unistd.h> /* For SEEK_SET etc */
55 extern int _fisatty (FILE *);
56 #define isatty_(f) _fisatty(f)
60 #define isatty_(f) isatty((f)->_file)
64 #define isatty_(f) (~ioctl ((f)->_file, FIOINTERACTIVE, NULL))
66 #define isatty_(f) isatty (fileno (f))
81 /* For RDIError_BreakpointReached. */
84 extern unsigned ARMul_OSInit (ARMul_State
* state
);
85 extern void ARMul_OSExit (ARMul_State
* state
);
86 extern unsigned ARMul_OSHandleSWI (ARMul_State
* state
, ARMword number
);
87 extern unsigned ARMul_OSException (ARMul_State
* state
, ARMword vector
,
89 extern ARMword
ARMul_OSLastErrorP (ARMul_State
* state
);
90 extern ARMword
ARMul_Debug (ARMul_State
* state
, ARMword pc
, ARMword instr
);
92 #define BUFFERSIZE 4096
96 #define UNIQUETEMPS 256
98 /***************************************************************************\
99 * OS private Information *
100 \***************************************************************************/
107 FILE *FileTable
[FOPEN_MAX
];
108 char FileFlags
[FOPEN_MAX
];
109 char *tempnames
[UNIQUETEMPS
];
118 #define FIXCRLF(t,c) ((t & BINARY) ? \
120 ((c == '\n' || c == '\r' ) ? (c ^ 7) : c) \
123 #define FIXCRLF(t,c) c
126 static ARMword softvectorcode
[] =
127 { /* basic: swi tidyexception + event; mov pc, lr;
128 ldmia r11,{r11,pc}; swi generateexception + event. */
129 0xef000090, 0xe1a0e00f, 0xe89b8800, 0xef000080, /*Reset */
130 0xef000091, 0xe1a0e00f, 0xe89b8800, 0xef000081, /*Undef */
131 0xef000092, 0xe1a0e00f, 0xe89b8800, 0xef000082, /*SWI */
132 0xef000093, 0xe1a0e00f, 0xe89b8800, 0xef000083, /*Prefetch abort */
133 0xef000094, 0xe1a0e00f, 0xe89b8800, 0xef000084, /*Data abort */
134 0xef000095, 0xe1a0e00f, 0xe89b8800, 0xef000085, /*Address exception */
135 0xef000096, 0xe1a0e00f, 0xe89b8800, 0xef000086, /*IRQ*/
136 0xef000097, 0xe1a0e00f, 0xe89b8800, 0xef000087, /*FIQ*/
137 0xef000098, 0xe1a0e00f, 0xe89b8800, 0xef000088, /*Error */
138 0xe1a0f00e /* default handler */
141 /***************************************************************************\
142 * Time for the Operating System to initialise itself. *
143 \***************************************************************************/
146 ARMul_OSInit (ARMul_State
* state
)
151 struct OSblock
*OSptr
= (struct OSblock
*) state
->OSptr
;
153 if (state
->OSptr
== NULL
)
155 state
->OSptr
= (unsigned char *) malloc (sizeof (struct OSblock
));
156 if (state
->OSptr
== NULL
)
158 perror ("OS Memory");
162 OSptr
= (struct OSblock
*) state
->OSptr
;
164 state
->Reg
[13] = ADDRSUPERSTACK
; /* set up a stack for the current mode */
165 ARMul_SetReg (state
, SVC32MODE
, 13, ADDRSUPERSTACK
); /* and for supervisor mode */
166 ARMul_SetReg (state
, ABORT32MODE
, 13, ADDRSUPERSTACK
); /* and for abort 32 mode */
167 ARMul_SetReg (state
, UNDEF32MODE
, 13, ADDRSUPERSTACK
); /* and for undef 32 mode */
168 ARMul_SetReg (state
, SYSTEMMODE
, 13, ADDRSUPERSTACK
); /* and for system mode */
169 instr
= 0xe59ff000 | (ADDRSOFTVECTORS
- 8); /* load pc from soft vector */
170 for (i
= ARMul_ResetV
; i
<= ARMFIQV
; i
+= 4)
171 ARMul_WriteWord (state
, i
, instr
); /* write hardware vectors */
172 for (i
= ARMul_ResetV
; i
<= ARMFIQV
+ 4; i
+= 4)
174 ARMul_WriteWord (state
, ADDRSOFTVECTORS
+ i
, SOFTVECTORCODE
+ i
* 4);
175 ARMul_WriteWord (state
, ADDRSOFHANDLERS
+ 2 * i
+ 4L,
176 SOFTVECTORCODE
+ sizeof (softvectorcode
) - 4L);
178 for (i
= 0; i
< sizeof (softvectorcode
); i
+= 4)
179 ARMul_WriteWord (state
, SOFTVECTORCODE
+ i
, softvectorcode
[i
/ 4]);
180 for (i
= 0; i
< FOPEN_MAX
; i
++)
181 OSptr
->FileTable
[i
] = NULL
;
182 for (i
= 0; i
< UNIQUETEMPS
; i
++)
183 OSptr
->tempnames
[i
] = NULL
;
184 ARMul_ConsolePrint (state
, ", Demon 1.01");
189 for (i
= 0; i
< fpesize
; i
+= 4) /* copy the code */
190 ARMul_WriteWord (state
, FPESTART
+ i
, fpecode
[i
>> 2]);
191 for (i
= FPESTART
+ fpesize
;; i
-= 4)
192 { /* reverse the error strings */
193 if ((j
= ARMul_ReadWord (state
, i
)) == 0xffffffff)
195 if (state
->bigendSig
&& j
< 0x80000000)
196 { /* it's part of the string so swap it */
197 j
= ((j
>> 0x18) & 0x000000ff) |
198 ((j
>> 0x08) & 0x0000ff00) |
199 ((j
<< 0x08) & 0x00ff0000) | ((j
<< 0x18) & 0xff000000);
200 ARMul_WriteWord (state
, i
, j
);
203 ARMul_WriteWord (state
, FPEOLDVECT
, ARMul_ReadWord (state
, 4)); /* copy old illegal instr vector */
204 ARMul_WriteWord (state
, 4, FPENEWVECT (ARMul_ReadWord (state
, i
- 4))); /* install new vector */
205 ARMul_ConsolePrint (state
, ", FPE");
208 #endif /* VALIDATE */
215 ARMul_OSExit (ARMul_State
* state
)
217 free ((char *) state
->OSptr
);
221 /***************************************************************************\
222 * Return the last Operating System Error. *
223 \***************************************************************************/
225 ARMword
ARMul_OSLastErrorP (ARMul_State
* state
)
227 return ((struct OSblock
*) state
->OSptr
)->ErrorP
;
230 static int translate_open_mode
[] = {
232 O_RDONLY
+ O_BINARY
, /* "rb" */
234 O_RDWR
+ O_BINARY
, /* "r+b" */
235 O_WRONLY
+ O_CREAT
+ O_TRUNC
, /* "w" */
236 O_WRONLY
+ O_BINARY
+ O_CREAT
+ O_TRUNC
, /* "wb" */
237 O_RDWR
+ O_CREAT
+ O_TRUNC
, /* "w+" */
238 O_RDWR
+ O_BINARY
+ O_CREAT
+ O_TRUNC
, /* "w+b" */
239 O_WRONLY
+ O_APPEND
+ O_CREAT
, /* "a" */
240 O_WRONLY
+ O_BINARY
+ O_APPEND
+ O_CREAT
, /* "ab" */
241 O_RDWR
+ O_APPEND
+ O_CREAT
, /* "a+" */
242 O_RDWR
+ O_BINARY
+ O_APPEND
+ O_CREAT
/* "a+b" */
246 SWIWrite0 (ARMul_State
* state
, ARMword addr
)
249 struct OSblock
*OSptr
= (struct OSblock
*) state
->OSptr
;
251 while ((temp
= ARMul_ReadByte (state
, addr
++)) != 0)
252 (void) fputc ((char) temp
, stdout
);
254 OSptr
->ErrorNo
= errno
;
258 WriteCommandLineTo (ARMul_State
* state
, ARMword addr
)
261 char *cptr
= state
->CommandLine
;
266 temp
= (ARMword
) * cptr
++;
267 ARMul_WriteByte (state
, addr
++, temp
);
273 SWIopen (ARMul_State
* state
, ARMword name
, ARMword SWIflags
)
275 struct OSblock
*OSptr
= (struct OSblock
*) state
->OSptr
;
280 for (i
= 0; (dummy
[i
] = ARMul_ReadByte (state
, name
+ i
)); i
++)
283 /* Now we need to decode the Demon open mode */
284 flags
= translate_open_mode
[SWIflags
];
286 /* Filename ":tt" is special: it denotes stdin/out */
287 if (strcmp (dummy
, ":tt") == 0)
289 if (flags
== O_RDONLY
) /* opening tty "r" */
290 state
->Reg
[0] = 0; /* stdin */
292 state
->Reg
[0] = 1; /* stdout */
296 state
->Reg
[0] = (int) open (dummy
, flags
, 0666);
297 OSptr
->ErrorNo
= errno
;
302 SWIread (ARMul_State
* state
, ARMword f
, ARMword ptr
, ARMword len
)
304 struct OSblock
*OSptr
= (struct OSblock
*) state
->OSptr
;
307 char *local
= malloc (len
);
311 fprintf (stderr
, "sim: Unable to read 0x%ulx bytes - out of memory\n",
316 res
= read (f
, local
, len
);
318 for (i
= 0; i
< res
; i
++)
319 ARMul_WriteByte (state
, ptr
+ i
, local
[i
]);
321 state
->Reg
[0] = res
== -1 ? -1 : len
- res
;
322 OSptr
->ErrorNo
= errno
;
326 SWIwrite (ARMul_State
* state
, ARMword f
, ARMword ptr
, ARMword len
)
328 struct OSblock
*OSptr
= (struct OSblock
*) state
->OSptr
;
331 char *local
= malloc (len
);
335 fprintf (stderr
, "sim: Unable to write 0x%lx bytes - out of memory\n",
340 for (i
= 0; i
< len
; i
++)
341 local
[i
] = ARMul_ReadByte (state
, ptr
+ i
);
343 res
= write (f
, local
, len
);
344 state
->Reg
[0] = res
== -1 ? -1 : len
- res
;
346 OSptr
->ErrorNo
= errno
;
350 SWIflen (ARMul_State
* state
, ARMword fh
)
352 struct OSblock
*OSptr
= (struct OSblock
*) state
->OSptr
;
355 if (fh
== 0 || fh
> FOPEN_MAX
)
357 OSptr
->ErrorNo
= EBADF
;
362 addr
= lseek (fh
, 0, SEEK_CUR
);
364 state
->Reg
[0] = lseek (fh
, 0L, SEEK_END
);
365 (void) lseek (fh
, addr
, SEEK_SET
);
367 OSptr
->ErrorNo
= errno
;
370 /***************************************************************************\
371 * The emulator calls this routine when a SWI instruction is encuntered. The *
372 * parameter passed is the SWI number (lower 24 bits of the instruction). *
373 \***************************************************************************/
376 ARMul_OSHandleSWI (ARMul_State
* state
, ARMword number
)
379 struct OSblock
*OSptr
= (struct OSblock
*) state
->OSptr
;
384 SWIread (state
, state
->Reg
[0], state
->Reg
[1], state
->Reg
[2]);
388 SWIwrite (state
, state
->Reg
[0], state
->Reg
[1], state
->Reg
[2]);
392 SWIopen (state
, state
->Reg
[0], state
->Reg
[1]);
396 /* return number of centi-seconds... */
398 #ifdef CLOCKS_PER_SEC
399 (CLOCKS_PER_SEC
>= 100)
400 ? (ARMword
) (clock () / (CLOCKS_PER_SEC
/ 100))
401 : (ARMword
) ((clock () * 100) / CLOCKS_PER_SEC
);
403 /* presume unix... clock() returns microseconds */
404 (ARMword
) (clock () / 10000);
406 OSptr
->ErrorNo
= errno
;
410 state
->Reg
[0] = (ARMword
) time (NULL
);
411 OSptr
->ErrorNo
= errno
;
415 state
->Reg
[0] = close (state
->Reg
[0]);
416 OSptr
->ErrorNo
= errno
;
420 SWIflen (state
, state
->Reg
[0]);
424 state
->Emulate
= FALSE
;
429 /* We must return non-zero for failure */
430 state
->Reg
[0] = -1 >= lseek (state
->Reg
[0], state
->Reg
[1], SEEK_SET
);
431 OSptr
->ErrorNo
= errno
;
436 (void) fputc ((int) state
->Reg
[0], stdout
);
437 OSptr
->ErrorNo
= errno
;
441 SWIWrite0 (state
, state
->Reg
[0]);
445 state
->Reg
[0] = OSptr
->ErrorNo
;
449 state
->EndCondition
= RDIError_BreakpointReached
;
450 state
->Emulate
= FALSE
;
454 state
->Reg
[0] = ADDRCMDLINE
;
456 state
->Reg
[1] = state
->MemSize
;
458 state
->Reg
[1] = ADDRUSERSTACK
;
460 WriteCommandLineTo (state
, state
->Reg
[0]);
463 /* Handle Angel SWIs as well as Demon ones */
466 /* R1 is almost always a parameter block */
467 addr
= state
->Reg
[1];
468 /* R0 is a reason code */
469 switch (state
->Reg
[0])
471 /* Unimplemented reason codes */
472 case AngelSWI_Reason_ReadC
:
473 case AngelSWI_Reason_IsTTY
:
474 case AngelSWI_Reason_TmpNam
:
475 case AngelSWI_Reason_Remove
:
476 case AngelSWI_Reason_Rename
:
477 case AngelSWI_Reason_System
:
478 case AngelSWI_Reason_EnterSVC
:
480 state
->Emulate
= FALSE
;
483 case AngelSWI_Reason_Clock
:
484 /* return number of centi-seconds... */
486 #ifdef CLOCKS_PER_SEC
487 (CLOCKS_PER_SEC
>= 100)
488 ? (ARMword
) (clock () / (CLOCKS_PER_SEC
/ 100))
489 : (ARMword
) ((clock () * 100) / CLOCKS_PER_SEC
);
491 /* presume unix... clock() returns microseconds */
492 (ARMword
) (clock () / 10000);
494 OSptr
->ErrorNo
= errno
;
497 case AngelSWI_Reason_Time
:
498 state
->Reg
[0] = (ARMword
) time (NULL
);
499 OSptr
->ErrorNo
= errno
;
502 case AngelSWI_Reason_WriteC
:
503 (void) fputc ((int) ARMul_ReadByte (state
, addr
), stdout
);
504 OSptr
->ErrorNo
= errno
;
507 case AngelSWI_Reason_Write0
:
508 SWIWrite0 (state
, addr
);
511 case AngelSWI_Reason_Close
:
512 state
->Reg
[0] = close (ARMul_ReadWord (state
, addr
));
513 OSptr
->ErrorNo
= errno
;
516 case AngelSWI_Reason_Seek
:
517 state
->Reg
[0] = -1 >= lseek (ARMul_ReadWord (state
, addr
),
518 ARMul_ReadWord (state
, addr
+ 4),
520 OSptr
->ErrorNo
= errno
;
523 case AngelSWI_Reason_FLen
:
524 SWIflen (state
, ARMul_ReadWord (state
, addr
));
527 case AngelSWI_Reason_GetCmdLine
:
528 WriteCommandLineTo (state
, ARMul_ReadWord (state
, addr
));
531 case AngelSWI_Reason_HeapInfo
:
532 /* R1 is a pointer to a pointer */
533 addr
= ARMul_ReadWord (state
, addr
);
535 /* Pick up the right memory limit */
537 temp
= state
->MemSize
;
539 temp
= ADDRUSERSTACK
;
541 ARMul_WriteWord (state
, addr
, 0); /* Heap base */
542 ARMul_WriteWord (state
, addr
+ 4, temp
); /* Heap limit */
543 ARMul_WriteWord (state
, addr
+ 8, temp
); /* Stack base */
544 ARMul_WriteWord (state
, addr
+ 12, temp
); /* Stack limit */
547 case AngelSWI_Reason_ReportException
:
548 if (state
->Reg
[1] == ADP_Stopped_ApplicationExit
)
552 state
->Emulate
= FALSE
;
555 case ADP_Stopped_ApplicationExit
:
557 state
->Emulate
= FALSE
;
560 case ADP_Stopped_RunTimeError
:
562 state
->Emulate
= FALSE
;
565 case AngelSWI_Reason_Errno
:
566 state
->Reg
[0] = OSptr
->ErrorNo
;
569 case AngelSWI_Reason_Open
:
571 ARMul_ReadWord (state
, addr
),
572 ARMul_ReadWord (state
, addr
+ 4));
575 case AngelSWI_Reason_Read
:
577 ARMul_ReadWord (state
, addr
),
578 ARMul_ReadWord (state
, addr
+ 4),
579 ARMul_ReadWord (state
, addr
+ 8));
582 case AngelSWI_Reason_Write
:
584 ARMul_ReadWord (state
, addr
),
585 ARMul_ReadWord (state
, addr
+ 4),
586 ARMul_ReadWord (state
, addr
+ 8));
591 state
->Emulate
= FALSE
;
599 /***************************************************************************\
600 * The emulator calls this routine when an Exception occurs. The second *
601 * parameter is the address of the relevant exception vector. Returning *
602 * FALSE from this routine causes the trap to be taken, TRUE causes it to *
603 * be ignored (so set state->Emulate to FALSE!). *
604 \***************************************************************************/
607 ARMul_OSException (ARMul_State
* state ATTRIBUTE_UNUSED
, ARMword vector ATTRIBUTE_UNUSED
, ARMword pc ATTRIBUTE_UNUSED
)
608 { /* don't use this here */