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))
83 /* For RDIError_BreakpointReached. */
86 extern unsigned ARMul_OSInit (ARMul_State
* state
);
87 extern void ARMul_OSExit (ARMul_State
* state
);
88 extern unsigned ARMul_OSHandleSWI (ARMul_State
* state
, ARMword number
);
89 extern unsigned ARMul_OSException (ARMul_State
* state
, ARMword vector
,
91 extern ARMword
ARMul_OSLastErrorP (ARMul_State
* state
);
92 extern ARMword
ARMul_Debug (ARMul_State
* state
, ARMword pc
, ARMword instr
);
94 #define BUFFERSIZE 4096
98 #define UNIQUETEMPS 256
100 /***************************************************************************\
101 * OS private Information *
102 \***************************************************************************/
109 FILE *FileTable
[FOPEN_MAX
];
110 char FileFlags
[FOPEN_MAX
];
111 char *tempnames
[UNIQUETEMPS
];
120 #define FIXCRLF(t,c) ((t & BINARY) ? \
122 ((c == '\n' || c == '\r' ) ? (c ^ 7) : c) \
125 #define FIXCRLF(t,c) c
128 static ARMword softvectorcode
[] =
129 { /* basic: swi tidyexception + event; mov pc, lr;
130 ldmia r11,{r11,pc}; swi generateexception + event. */
131 0xef000090, 0xe1a0e00f, 0xe89b8800, 0xef000080, /*Reset */
132 0xef000091, 0xe1a0e00f, 0xe89b8800, 0xef000081, /*Undef */
133 0xef000092, 0xe1a0e00f, 0xe89b8800, 0xef000082, /*SWI */
134 0xef000093, 0xe1a0e00f, 0xe89b8800, 0xef000083, /*Prefetch abort */
135 0xef000094, 0xe1a0e00f, 0xe89b8800, 0xef000084, /*Data abort */
136 0xef000095, 0xe1a0e00f, 0xe89b8800, 0xef000085, /*Address exception */
137 0xef000096, 0xe1a0e00f, 0xe89b8800, 0xef000086, /*IRQ*/
138 0xef000097, 0xe1a0e00f, 0xe89b8800, 0xef000087, /*FIQ*/
139 0xef000098, 0xe1a0e00f, 0xe89b8800, 0xef000088, /*Error */
140 0xe1a0f00e /* default handler */
143 /***************************************************************************\
144 * Time for the Operating System to initialise itself. *
145 \***************************************************************************/
148 ARMul_OSInit (ARMul_State
* state
)
153 struct OSblock
*OSptr
= (struct OSblock
*) state
->OSptr
;
155 if (state
->OSptr
== NULL
)
157 state
->OSptr
= (unsigned char *) malloc (sizeof (struct OSblock
));
158 if (state
->OSptr
== NULL
)
160 perror ("OS Memory");
164 OSptr
= (struct OSblock
*) state
->OSptr
;
166 state
->Reg
[13] = ADDRSUPERSTACK
; /* set up a stack for the current mode */
167 ARMul_SetReg (state
, SVC32MODE
, 13, ADDRSUPERSTACK
); /* and for supervisor mode */
168 ARMul_SetReg (state
, ABORT32MODE
, 13, ADDRSUPERSTACK
); /* and for abort 32 mode */
169 ARMul_SetReg (state
, UNDEF32MODE
, 13, ADDRSUPERSTACK
); /* and for undef 32 mode */
170 ARMul_SetReg (state
, SYSTEMMODE
, 13, ADDRSUPERSTACK
); /* and for system mode */
171 instr
= 0xe59ff000 | (ADDRSOFTVECTORS
- 8); /* load pc from soft vector */
172 for (i
= ARMul_ResetV
; i
<= ARMFIQV
; i
+= 4)
173 ARMul_WriteWord (state
, i
, instr
); /* write hardware vectors */
174 for (i
= ARMul_ResetV
; i
<= ARMFIQV
+ 4; i
+= 4)
176 ARMul_WriteWord (state
, ADDRSOFTVECTORS
+ i
, SOFTVECTORCODE
+ i
* 4);
177 ARMul_WriteWord (state
, ADDRSOFHANDLERS
+ 2 * i
+ 4L,
178 SOFTVECTORCODE
+ sizeof (softvectorcode
) - 4L);
180 for (i
= 0; i
< sizeof (softvectorcode
); i
+= 4)
181 ARMul_WriteWord (state
, SOFTVECTORCODE
+ i
, softvectorcode
[i
/ 4]);
182 for (i
= 0; i
< FOPEN_MAX
; i
++)
183 OSptr
->FileTable
[i
] = NULL
;
184 for (i
= 0; i
< UNIQUETEMPS
; i
++)
185 OSptr
->tempnames
[i
] = NULL
;
186 ARMul_ConsolePrint (state
, ", Demon 1.01");
191 for (i
= 0; i
< fpesize
; i
+= 4) /* copy the code */
192 ARMul_WriteWord (state
, FPESTART
+ i
, fpecode
[i
>> 2]);
193 for (i
= FPESTART
+ fpesize
;; i
-= 4)
194 { /* reverse the error strings */
195 if ((j
= ARMul_ReadWord (state
, i
)) == 0xffffffff)
197 if (state
->bigendSig
&& j
< 0x80000000)
198 { /* it's part of the string so swap it */
199 j
= ((j
>> 0x18) & 0x000000ff) |
200 ((j
>> 0x08) & 0x0000ff00) |
201 ((j
<< 0x08) & 0x00ff0000) | ((j
<< 0x18) & 0xff000000);
202 ARMul_WriteWord (state
, i
, j
);
205 ARMul_WriteWord (state
, FPEOLDVECT
, ARMul_ReadWord (state
, 4)); /* copy old illegal instr vector */
206 ARMul_WriteWord (state
, 4, FPENEWVECT (ARMul_ReadWord (state
, i
- 4))); /* install new vector */
207 ARMul_ConsolePrint (state
, ", FPE");
210 #endif /* VALIDATE */
217 ARMul_OSExit (ARMul_State
* state
)
219 free ((char *) state
->OSptr
);
223 /***************************************************************************\
224 * Return the last Operating System Error. *
225 \***************************************************************************/
227 ARMword
ARMul_OSLastErrorP (ARMul_State
* state
)
229 return ((struct OSblock
*) state
->OSptr
)->ErrorP
;
232 static int translate_open_mode
[] = {
234 O_RDONLY
+ O_BINARY
, /* "rb" */
236 O_RDWR
+ O_BINARY
, /* "r+b" */
237 O_WRONLY
+ O_CREAT
+ O_TRUNC
, /* "w" */
238 O_WRONLY
+ O_BINARY
+ O_CREAT
+ O_TRUNC
, /* "wb" */
239 O_RDWR
+ O_CREAT
+ O_TRUNC
, /* "w+" */
240 O_RDWR
+ O_BINARY
+ O_CREAT
+ O_TRUNC
, /* "w+b" */
241 O_WRONLY
+ O_APPEND
+ O_CREAT
, /* "a" */
242 O_WRONLY
+ O_BINARY
+ O_APPEND
+ O_CREAT
, /* "ab" */
243 O_RDWR
+ O_APPEND
+ O_CREAT
, /* "a+" */
244 O_RDWR
+ O_BINARY
+ O_APPEND
+ O_CREAT
/* "a+b" */
248 SWIWrite0 (ARMul_State
* state
, ARMword addr
)
251 struct OSblock
*OSptr
= (struct OSblock
*) state
->OSptr
;
253 while ((temp
= ARMul_ReadByte (state
, addr
++)) != 0)
254 (void) fputc ((char) temp
, stdout
);
256 OSptr
->ErrorNo
= errno
;
260 WriteCommandLineTo (ARMul_State
* state
, ARMword addr
)
263 char *cptr
= state
->CommandLine
;
268 temp
= (ARMword
) * cptr
++;
269 ARMul_WriteByte (state
, addr
++, temp
);
275 SWIopen (ARMul_State
* state
, ARMword name
, ARMword SWIflags
)
277 struct OSblock
*OSptr
= (struct OSblock
*) state
->OSptr
;
282 for (i
= 0; (dummy
[i
] = ARMul_ReadByte (state
, name
+ i
)); i
++)
285 /* Now we need to decode the Demon open mode */
286 flags
= translate_open_mode
[SWIflags
];
288 /* Filename ":tt" is special: it denotes stdin/out */
289 if (strcmp (dummy
, ":tt") == 0)
291 if (flags
== O_RDONLY
) /* opening tty "r" */
292 state
->Reg
[0] = 0; /* stdin */
294 state
->Reg
[0] = 1; /* stdout */
298 state
->Reg
[0] = (int) open (dummy
, flags
, 0666);
299 OSptr
->ErrorNo
= errno
;
304 SWIread (ARMul_State
* state
, ARMword f
, ARMword ptr
, ARMword len
)
306 struct OSblock
*OSptr
= (struct OSblock
*) state
->OSptr
;
309 char *local
= malloc (len
);
313 fprintf (stderr
, "sim: Unable to read 0x%ulx bytes - out of memory\n",
318 res
= read (f
, local
, len
);
320 for (i
= 0; i
< res
; i
++)
321 ARMul_WriteByte (state
, ptr
+ i
, local
[i
]);
323 state
->Reg
[0] = res
== -1 ? -1 : len
- res
;
324 OSptr
->ErrorNo
= errno
;
328 SWIwrite (ARMul_State
* state
, ARMword f
, ARMword ptr
, ARMword len
)
330 struct OSblock
*OSptr
= (struct OSblock
*) state
->OSptr
;
333 char *local
= malloc (len
);
337 fprintf (stderr
, "sim: Unable to write 0x%lx bytes - out of memory\n",
342 for (i
= 0; i
< len
; i
++)
343 local
[i
] = ARMul_ReadByte (state
, ptr
+ i
);
345 res
= write (f
, local
, len
);
346 state
->Reg
[0] = res
== -1 ? -1 : len
- res
;
348 OSptr
->ErrorNo
= errno
;
352 SWIflen (ARMul_State
* state
, ARMword fh
)
354 struct OSblock
*OSptr
= (struct OSblock
*) state
->OSptr
;
357 if (fh
== 0 || fh
> FOPEN_MAX
)
359 OSptr
->ErrorNo
= EBADF
;
364 addr
= lseek (fh
, 0, SEEK_CUR
);
366 state
->Reg
[0] = lseek (fh
, 0L, SEEK_END
);
367 (void) lseek (fh
, addr
, SEEK_SET
);
369 OSptr
->ErrorNo
= errno
;
372 /***************************************************************************\
373 * The emulator calls this routine when a SWI instruction is encuntered. The *
374 * parameter passed is the SWI number (lower 24 bits of the instruction). *
375 \***************************************************************************/
378 ARMul_OSHandleSWI (ARMul_State
* state
, ARMword number
)
381 struct OSblock
*OSptr
= (struct OSblock
*) state
->OSptr
;
386 SWIread (state
, state
->Reg
[0], state
->Reg
[1], state
->Reg
[2]);
390 SWIwrite (state
, state
->Reg
[0], state
->Reg
[1], state
->Reg
[2]);
394 SWIopen (state
, state
->Reg
[0], state
->Reg
[1]);
398 /* return number of centi-seconds... */
400 #ifdef CLOCKS_PER_SEC
401 (CLOCKS_PER_SEC
>= 100)
402 ? (ARMword
) (clock () / (CLOCKS_PER_SEC
/ 100))
403 : (ARMword
) ((clock () * 100) / CLOCKS_PER_SEC
);
405 /* presume unix... clock() returns microseconds */
406 (ARMword
) (clock () / 10000);
408 OSptr
->ErrorNo
= errno
;
412 state
->Reg
[0] = (ARMword
) time (NULL
);
413 OSptr
->ErrorNo
= errno
;
417 state
->Reg
[0] = close (state
->Reg
[0]);
418 OSptr
->ErrorNo
= errno
;
422 SWIflen (state
, state
->Reg
[0]);
426 state
->Emulate
= FALSE
;
431 /* We must return non-zero for failure */
432 state
->Reg
[0] = -1 >= lseek (state
->Reg
[0], state
->Reg
[1], SEEK_SET
);
433 OSptr
->ErrorNo
= errno
;
438 (void) fputc ((int) state
->Reg
[0], stdout
);
439 OSptr
->ErrorNo
= errno
;
443 SWIWrite0 (state
, state
->Reg
[0]);
447 state
->Reg
[0] = OSptr
->ErrorNo
;
451 state
->Reg
[0] = ADDRCMDLINE
;
453 state
->Reg
[1] = state
->MemSize
;
455 state
->Reg
[1] = ADDRUSERSTACK
;
457 WriteCommandLineTo (state
, state
->Reg
[0]);
461 state
->EndCondition
= RDIError_BreakpointReached
;
462 state
->Emulate
= FALSE
;
465 /* Handle Angel SWIs as well as Demon ones */
468 /* R1 is almost always a parameter block */
469 addr
= state
->Reg
[1];
470 /* R0 is a reason code */
471 switch (state
->Reg
[0])
473 /* Unimplemented reason codes */
474 case AngelSWI_Reason_ReadC
:
475 case AngelSWI_Reason_IsTTY
:
476 case AngelSWI_Reason_TmpNam
:
477 case AngelSWI_Reason_Remove
:
478 case AngelSWI_Reason_Rename
:
479 case AngelSWI_Reason_System
:
480 case AngelSWI_Reason_EnterSVC
:
482 state
->Emulate
= FALSE
;
485 case AngelSWI_Reason_Clock
:
486 /* return number of centi-seconds... */
488 #ifdef CLOCKS_PER_SEC
489 (CLOCKS_PER_SEC
>= 100)
490 ? (ARMword
) (clock () / (CLOCKS_PER_SEC
/ 100))
491 : (ARMword
) ((clock () * 100) / CLOCKS_PER_SEC
);
493 /* presume unix... clock() returns microseconds */
494 (ARMword
) (clock () / 10000);
496 OSptr
->ErrorNo
= errno
;
499 case AngelSWI_Reason_Time
:
500 state
->Reg
[0] = (ARMword
) time (NULL
);
501 OSptr
->ErrorNo
= errno
;
504 case AngelSWI_Reason_WriteC
:
505 (void) fputc ((int) ARMul_ReadByte (state
, addr
), stdout
);
506 OSptr
->ErrorNo
= errno
;
509 case AngelSWI_Reason_Write0
:
510 SWIWrite0 (state
, addr
);
513 case AngelSWI_Reason_Close
:
514 state
->Reg
[0] = close (ARMul_ReadWord (state
, addr
));
515 OSptr
->ErrorNo
= errno
;
518 case AngelSWI_Reason_Seek
:
519 state
->Reg
[0] = -1 >= lseek (ARMul_ReadWord (state
, addr
),
520 ARMul_ReadWord (state
, addr
+ 4),
522 OSptr
->ErrorNo
= errno
;
525 case AngelSWI_Reason_FLen
:
526 SWIflen (state
, ARMul_ReadWord (state
, addr
));
529 case AngelSWI_Reason_GetCmdLine
:
530 WriteCommandLineTo (state
, ARMul_ReadWord (state
, addr
));
533 case AngelSWI_Reason_HeapInfo
:
534 /* R1 is a pointer to a pointer */
535 addr
= ARMul_ReadWord (state
, addr
);
537 /* Pick up the right memory limit */
539 temp
= state
->MemSize
;
541 temp
= ADDRUSERSTACK
;
543 ARMul_WriteWord (state
, addr
, 0); /* Heap base */
544 ARMul_WriteWord (state
, addr
+ 4, temp
); /* Heap limit */
545 ARMul_WriteWord (state
, addr
+ 8, temp
); /* Stack base */
546 ARMul_WriteWord (state
, addr
+ 12, temp
); /* Stack limit */
549 case AngelSWI_Reason_ReportException
:
550 if (state
->Reg
[1] == ADP_Stopped_ApplicationExit
)
554 state
->Emulate
= FALSE
;
557 case ADP_Stopped_ApplicationExit
:
559 state
->Emulate
= FALSE
;
562 case ADP_Stopped_RunTimeError
:
564 state
->Emulate
= FALSE
;
567 case AngelSWI_Reason_Errno
:
568 state
->Reg
[0] = OSptr
->ErrorNo
;
571 case AngelSWI_Reason_Open
:
573 ARMul_ReadWord (state
, addr
),
574 ARMul_ReadWord (state
, addr
+ 4));
577 case AngelSWI_Reason_Read
:
579 ARMul_ReadWord (state
, addr
),
580 ARMul_ReadWord (state
, addr
+ 4),
581 ARMul_ReadWord (state
, addr
+ 8));
584 case AngelSWI_Reason_Write
:
586 ARMul_ReadWord (state
, addr
),
587 ARMul_ReadWord (state
, addr
+ 4),
588 ARMul_ReadWord (state
, addr
+ 8));
594 /* These are used by the FPE code. */
599 /* If there is a SWI vector installed use it. */
600 extern int SWI_vector_installed
;
602 if (SWI_vector_installed
&& number
!= SWI_Breakpoint
)
607 cpsr
= ARMul_GetCPSR (state
);
610 ARMul_SetSPSR (state
, SVC32MODE
, cpsr
);
613 cpsr
|= SVC32MODE
| 0x80;
614 ARMul_SetCPSR (state
, cpsr
);
616 state
->RegBank
[SVCBANK
][14] = state
->Reg
[14] = state
->Reg
[15] - i_size
;
617 state
->NextInstr
= RESUME
;
618 state
->Reg
[15] = state
->pc
= ARMSWIV
;
622 fprintf (stderr
, "unknown SWI encountered - %x - ignoring\n", number
);
631 /* The emulator calls this routine when an Exception occurs. The second
632 parameter is the address of the relevant exception vector. Returning
633 FALSE from this routine causes the trap to be taken, TRUE causes it to
634 be ignored (so set state->Emulate to FALSE!). */
638 ARMul_State
* state ATTRIBUTE_UNUSED
,
639 ARMword vector ATTRIBUTE_UNUSED
,
640 ARMword pc ATTRIBUTE_UNUSED
)