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 #include "gdb/callback.h"
87 extern host_callback
*sim_callback
;
89 extern unsigned ARMul_OSInit (ARMul_State
*);
90 extern void ARMul_OSExit (ARMul_State
*);
91 extern unsigned ARMul_OSHandleSWI (ARMul_State
*, ARMword
);
92 extern unsigned ARMul_OSException (ARMul_State
*, ARMword
, ARMword
);
93 extern ARMword
ARMul_OSLastErrorP (ARMul_State
*);
94 extern ARMword
ARMul_Debug (ARMul_State
*, ARMword
, ARMword
);
96 #define BUFFERSIZE 4096
100 #define UNIQUETEMPS 256
102 /* OS private Information. */
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 /* Bit mask of enabled SWI implementations. */
129 unsigned int swi_mask
= -1;
132 static ARMword softvectorcode
[] =
134 /* Basic: swi tidyexception + event; mov pc, lr;
135 ldmia r11,{r11,pc}; swi generateexception + event. */
136 0xef000090, 0xe1a0e00f, 0xe89b8800, 0xef000080, /* Reset */
137 0xef000091, 0xe1a0e00f, 0xe89b8800, 0xef000081, /* Undef */
138 0xef000092, 0xe1a0e00f, 0xe89b8800, 0xef000082, /* SWI */
139 0xef000093, 0xe1a0e00f, 0xe89b8800, 0xef000083, /* Prefetch abort */
140 0xef000094, 0xe1a0e00f, 0xe89b8800, 0xef000084, /* Data abort */
141 0xef000095, 0xe1a0e00f, 0xe89b8800, 0xef000085, /* Address exception */
142 0xef000096, 0xe1a0e00f, 0xe89b8800, 0xef000086, /* IRQ */
143 0xef000097, 0xe1a0e00f, 0xe89b8800, 0xef000087, /* FIQ */
144 0xef000098, 0xe1a0e00f, 0xe89b8800, 0xef000088, /* Error */
145 0xe1a0f00e /* Default handler */
148 /* Time for the Operating System to initialise itself. */
151 ARMul_OSInit (ARMul_State
* state
)
156 struct OSblock
*OSptr
= (struct OSblock
*) state
->OSptr
;
158 if (state
->OSptr
== NULL
)
160 state
->OSptr
= (unsigned char *) malloc (sizeof (struct OSblock
));
161 if (state
->OSptr
== NULL
)
163 perror ("OS Memory");
168 OSptr
= (struct OSblock
*) state
->OSptr
;
170 state
->Reg
[13] = ADDRSUPERSTACK
; /* Set up a stack for the current mode... */
171 ARMul_SetReg (state
, SVC32MODE
, 13, ADDRSUPERSTACK
);/* ...and for supervisor mode... */
172 ARMul_SetReg (state
, ABORT32MODE
, 13, ADDRSUPERSTACK
);/* ...and for abort 32 mode... */
173 ARMul_SetReg (state
, UNDEF32MODE
, 13, ADDRSUPERSTACK
);/* ...and for undef 32 mode... */
174 ARMul_SetReg (state
, SYSTEMMODE
, 13, ADDRSUPERSTACK
);/* ...and for system mode. */
175 instr
= 0xe59ff000 | (ADDRSOFTVECTORS
- 8); /* Load pc from soft vector */
177 for (i
= ARMul_ResetV
; i
<= ARMFIQV
; i
+= 4)
178 /* Write hardware vectors. */
179 ARMul_WriteWord (state
, i
, instr
);
181 SWI_vector_installed
= 0;
183 for (i
= ARMul_ResetV
; i
<= ARMFIQV
+ 4; i
+= 4)
185 ARMul_WriteWord (state
, ADDRSOFTVECTORS
+ i
, SOFTVECTORCODE
+ i
* 4);
186 ARMul_WriteWord (state
, ADDRSOFHANDLERS
+ 2 * i
+ 4L,
187 SOFTVECTORCODE
+ sizeof (softvectorcode
) - 4L);
190 for (i
= 0; i
< sizeof (softvectorcode
); i
+= 4)
191 ARMul_WriteWord (state
, SOFTVECTORCODE
+ i
, softvectorcode
[i
/ 4]);
193 for (i
= 0; i
< FOPEN_MAX
; i
++)
194 OSptr
->FileTable
[i
] = NULL
;
196 for (i
= 0; i
< UNIQUETEMPS
; i
++)
197 OSptr
->tempnames
[i
] = NULL
;
199 ARMul_ConsolePrint (state
, ", Demon 1.01");
204 for (i
= 0; i
< fpesize
; i
+= 4)
206 ARMul_WriteWord (state
, FPESTART
+ i
, fpecode
[i
>> 2]);
208 for (i
= FPESTART
+ fpesize
;; i
-= 4)
210 /* Reverse the error strings. */
211 if ((j
= ARMul_ReadWord (state
, i
)) == 0xffffffff)
213 if (state
->bigendSig
&& j
< 0x80000000)
215 /* It's part of the string so swap it. */
216 j
= ((j
>> 0x18) & 0x000000ff) |
217 ((j
>> 0x08) & 0x0000ff00) |
218 ((j
<< 0x08) & 0x00ff0000) | ((j
<< 0x18) & 0xff000000);
219 ARMul_WriteWord (state
, i
, j
);
223 /* Copy old illegal instr vector. */
224 ARMul_WriteWord (state
, FPEOLDVECT
, ARMul_ReadWord (state
, 4));
225 /* Install new vector. */
226 ARMul_WriteWord (state
, 4, FPENEWVECT (ARMul_ReadWord (state
, i
- 4)));
227 ARMul_ConsolePrint (state
, ", FPE");
230 #endif /* VALIDATE */
233 /* Intel do not want DEMON SWI support. */
234 if (state
->is_XScale
)
235 swi_mask
= SWI_MASK_ANGEL
;
241 ARMul_OSExit (ARMul_State
* state
)
243 free ((char *) state
->OSptr
);
247 /* Return the last Operating System Error. */
249 ARMword
ARMul_OSLastErrorP (ARMul_State
* state
)
251 return ((struct OSblock
*) state
->OSptr
)->ErrorP
;
254 static int translate_open_mode
[] =
257 O_RDONLY
+ O_BINARY
, /* "rb" */
259 O_RDWR
+ O_BINARY
, /* "r+b" */
260 O_WRONLY
+ O_CREAT
+ O_TRUNC
, /* "w" */
261 O_WRONLY
+ O_BINARY
+ O_CREAT
+ O_TRUNC
, /* "wb" */
262 O_RDWR
+ O_CREAT
+ O_TRUNC
, /* "w+" */
263 O_RDWR
+ O_BINARY
+ O_CREAT
+ O_TRUNC
, /* "w+b" */
264 O_WRONLY
+ O_APPEND
+ O_CREAT
, /* "a" */
265 O_WRONLY
+ O_BINARY
+ O_APPEND
+ O_CREAT
, /* "ab" */
266 O_RDWR
+ O_APPEND
+ O_CREAT
, /* "a+" */
267 O_RDWR
+ O_BINARY
+ O_APPEND
+ O_CREAT
/* "a+b" */
271 SWIWrite0 (ARMul_State
* state
, ARMword addr
)
274 struct OSblock
*OSptr
= (struct OSblock
*) state
->OSptr
;
276 while ((temp
= ARMul_SafeReadByte (state
, addr
++)) != 0)
277 (void) sim_callback
->write_stdout (sim_callback
, (char *) &temp
, 1);
279 OSptr
->ErrorNo
= sim_callback
->get_errno (sim_callback
);
283 WriteCommandLineTo (ARMul_State
* state
, ARMword addr
)
286 char *cptr
= state
->CommandLine
;
292 temp
= (ARMword
) * cptr
++;
293 ARMul_SafeWriteByte (state
, addr
++, temp
);
299 SWIopen (ARMul_State
* state
, ARMword name
, ARMword SWIflags
)
301 struct OSblock
*OSptr
= (struct OSblock
*) state
->OSptr
;
306 for (i
= 0; (dummy
[i
] = ARMul_SafeReadByte (state
, name
+ i
)); i
++)
309 /* Now we need to decode the Demon open mode. */
310 flags
= translate_open_mode
[SWIflags
];
312 /* Filename ":tt" is special: it denotes stdin/out. */
313 if (strcmp (dummy
, ":tt") == 0)
315 if (flags
== O_RDONLY
) /* opening tty "r" */
316 state
->Reg
[0] = 0; /* stdin */
318 state
->Reg
[0] = 1; /* stdout */
322 state
->Reg
[0] = sim_callback
->open (sim_callback
, dummy
, flags
);
323 OSptr
->ErrorNo
= sim_callback
->get_errno (sim_callback
);
328 SWIread (ARMul_State
* state
, ARMword f
, ARMword ptr
, ARMword len
)
330 struct OSblock
*OSptr
= (struct OSblock
*) state
->OSptr
;
333 char *local
= malloc (len
);
337 sim_callback
->printf_filtered
339 "sim: Unable to read 0x%ulx bytes - out of memory\n",
344 res
= sim_callback
->read (sim_callback
, f
, local
, len
);
346 for (i
= 0; i
< res
; i
++)
347 ARMul_SafeWriteByte (state
, ptr
+ i
, local
[i
]);
350 state
->Reg
[0] = res
== -1 ? -1 : len
- res
;
351 OSptr
->ErrorNo
= sim_callback
->get_errno (sim_callback
);
355 SWIwrite (ARMul_State
* state
, ARMword f
, ARMword ptr
, ARMword len
)
357 struct OSblock
*OSptr
= (struct OSblock
*) state
->OSptr
;
360 char *local
= malloc (len
);
364 sim_callback
->printf_filtered
366 "sim: Unable to write 0x%lx bytes - out of memory\n",
371 for (i
= 0; i
< len
; i
++)
372 local
[i
] = ARMul_SafeReadByte (state
, ptr
+ i
);
374 res
= sim_callback
->write (sim_callback
, f
, local
, len
);
375 state
->Reg
[0] = res
== -1 ? -1 : len
- res
;
378 OSptr
->ErrorNo
= sim_callback
->get_errno (sim_callback
);
382 SWIflen (ARMul_State
* state
, ARMword fh
)
384 struct OSblock
*OSptr
= (struct OSblock
*) state
->OSptr
;
387 if (fh
== 0 || fh
> FOPEN_MAX
)
389 OSptr
->ErrorNo
= EBADF
;
394 addr
= sim_callback
->lseek (sim_callback
, fh
, 0, SEEK_CUR
);
396 state
->Reg
[0] = sim_callback
->lseek (sim_callback
, fh
, 0L, SEEK_END
);
397 (void) sim_callback
->lseek (sim_callback
, fh
, addr
, SEEK_SET
);
399 OSptr
->ErrorNo
= sim_callback
->get_errno (sim_callback
);
402 /* The emulator calls this routine when a SWI instruction is encuntered.
403 The parameter passed is the SWI number (lower 24 bits of the instruction). */
406 ARMul_OSHandleSWI (ARMul_State
* state
, ARMword number
)
408 struct OSblock
* OSptr
= (struct OSblock
*) state
->OSptr
;
409 int unhandled
= FALSE
;
414 if (swi_mask
& SWI_MASK_DEMON
)
415 SWIread (state
, state
->Reg
[0], state
->Reg
[1], state
->Reg
[2]);
421 if (swi_mask
& SWI_MASK_DEMON
)
422 SWIwrite (state
, state
->Reg
[0], state
->Reg
[1], state
->Reg
[2]);
428 if (swi_mask
& SWI_MASK_DEMON
)
429 SWIopen (state
, state
->Reg
[0], state
->Reg
[1]);
435 if (swi_mask
& SWI_MASK_DEMON
)
437 /* Return number of centi-seconds. */
439 #ifdef CLOCKS_PER_SEC
440 (CLOCKS_PER_SEC
>= 100)
441 ? (ARMword
) (clock () / (CLOCKS_PER_SEC
/ 100))
442 : (ARMword
) ((clock () * 100) / CLOCKS_PER_SEC
);
444 /* Presume unix... clock() returns microseconds. */
445 (ARMword
) (clock () / 10000);
447 OSptr
->ErrorNo
= errno
;
454 if (swi_mask
& SWI_MASK_DEMON
)
456 state
->Reg
[0] = (ARMword
) sim_callback
->time (sim_callback
, NULL
);
457 OSptr
->ErrorNo
= sim_callback
->get_errno (sim_callback
);
464 if (swi_mask
& SWI_MASK_DEMON
)
466 state
->Reg
[0] = sim_callback
->close (sim_callback
, state
->Reg
[0]);
467 OSptr
->ErrorNo
= sim_callback
->get_errno (sim_callback
);
474 if (swi_mask
& SWI_MASK_DEMON
)
475 SWIflen (state
, state
->Reg
[0]);
481 if (swi_mask
& SWI_MASK_DEMON
)
482 state
->Emulate
= FALSE
;
488 if (swi_mask
& SWI_MASK_DEMON
)
490 /* We must return non-zero for failure. */
491 state
->Reg
[0] = -1 >= sim_callback
->lseek (sim_callback
, state
->Reg
[0], state
->Reg
[1], SEEK_SET
);
492 OSptr
->ErrorNo
= sim_callback
->get_errno (sim_callback
);
499 if (swi_mask
& SWI_MASK_DEMON
)
501 char tmp
= state
->Reg
[0];
502 (void) sim_callback
->write_stdout (sim_callback
, &tmp
, 1);
503 OSptr
->ErrorNo
= sim_callback
->get_errno (sim_callback
);
510 if (swi_mask
& SWI_MASK_DEMON
)
511 SWIWrite0 (state
, state
->Reg
[0]);
517 if (swi_mask
& SWI_MASK_DEMON
)
518 state
->Reg
[0] = OSptr
->ErrorNo
;
524 if (swi_mask
& SWI_MASK_DEMON
)
526 state
->Reg
[0] = ADDRCMDLINE
;
528 state
->Reg
[1] = state
->MemSize
;
530 state
->Reg
[1] = ADDRUSERSTACK
;
532 WriteCommandLineTo (state
, state
->Reg
[0]);
539 state
->EndCondition
= RDIError_BreakpointReached
;
540 state
->Emulate
= FALSE
;
543 /* Handle Angel SWIs as well as Demon ones. */
546 if (swi_mask
& SWI_MASK_ANGEL
)
551 /* R1 is almost always a parameter block. */
552 addr
= state
->Reg
[1];
553 /* R0 is a reason code. */
554 switch (state
->Reg
[0])
557 /* This can happen when a SWI is interrupted (eg receiving a
558 ctrl-C whilst processing SWIRead()). The SWI will complete
559 returning -1 in r0 to the caller. If GDB is then used to
560 resume the system call the reason code will now be -1. */
563 /* Unimplemented reason codes. */
564 case AngelSWI_Reason_ReadC
:
565 case AngelSWI_Reason_IsTTY
:
566 case AngelSWI_Reason_TmpNam
:
567 case AngelSWI_Reason_Remove
:
568 case AngelSWI_Reason_Rename
:
569 case AngelSWI_Reason_System
:
570 case AngelSWI_Reason_EnterSVC
:
572 state
->Emulate
= FALSE
;
575 case AngelSWI_Reason_Clock
:
576 /* Return number of centi-seconds. */
578 #ifdef CLOCKS_PER_SEC
579 (CLOCKS_PER_SEC
>= 100)
580 ? (ARMword
) (clock () / (CLOCKS_PER_SEC
/ 100))
581 : (ARMword
) ((clock () * 100) / CLOCKS_PER_SEC
);
583 /* Presume unix... clock() returns microseconds. */
584 (ARMword
) (clock () / 10000);
586 OSptr
->ErrorNo
= errno
;
589 case AngelSWI_Reason_Time
:
590 state
->Reg
[0] = (ARMword
) sim_callback
->time (sim_callback
, NULL
);
591 OSptr
->ErrorNo
= sim_callback
->get_errno (sim_callback
);
594 case AngelSWI_Reason_WriteC
:
596 char tmp
= ARMul_SafeReadByte (state
, addr
);
597 (void) sim_callback
->write_stdout (sim_callback
, &tmp
, 1);
598 OSptr
->ErrorNo
= sim_callback
->get_errno (sim_callback
);
602 case AngelSWI_Reason_Write0
:
603 SWIWrite0 (state
, addr
);
606 case AngelSWI_Reason_Close
:
607 state
->Reg
[0] = sim_callback
->close (sim_callback
, ARMul_ReadWord (state
, addr
));
608 OSptr
->ErrorNo
= sim_callback
->get_errno (sim_callback
);
611 case AngelSWI_Reason_Seek
:
612 state
->Reg
[0] = -1 >= sim_callback
->lseek (sim_callback
, ARMul_ReadWord (state
, addr
),
613 ARMul_ReadWord (state
, addr
+ 4),
615 OSptr
->ErrorNo
= sim_callback
->get_errno (sim_callback
);
618 case AngelSWI_Reason_FLen
:
619 SWIflen (state
, ARMul_ReadWord (state
, addr
));
622 case AngelSWI_Reason_GetCmdLine
:
623 WriteCommandLineTo (state
, ARMul_ReadWord (state
, addr
));
626 case AngelSWI_Reason_HeapInfo
:
627 /* R1 is a pointer to a pointer. */
628 addr
= ARMul_ReadWord (state
, addr
);
630 /* Pick up the right memory limit. */
632 temp
= state
->MemSize
;
634 temp
= ADDRUSERSTACK
;
636 ARMul_WriteWord (state
, addr
, 0); /* Heap base. */
637 ARMul_WriteWord (state
, addr
+ 4, temp
); /* Heap limit. */
638 ARMul_WriteWord (state
, addr
+ 8, temp
); /* Stack base. */
639 ARMul_WriteWord (state
, addr
+ 12, temp
); /* Stack limit. */
642 case AngelSWI_Reason_ReportException
:
643 if (state
->Reg
[1] == ADP_Stopped_ApplicationExit
)
647 state
->Emulate
= FALSE
;
650 case ADP_Stopped_ApplicationExit
:
652 state
->Emulate
= FALSE
;
655 case ADP_Stopped_RunTimeError
:
657 state
->Emulate
= FALSE
;
660 case AngelSWI_Reason_Errno
:
661 state
->Reg
[0] = OSptr
->ErrorNo
;
664 case AngelSWI_Reason_Open
:
666 ARMul_ReadWord (state
, addr
),
667 ARMul_ReadWord (state
, addr
+ 4));
670 case AngelSWI_Reason_Read
:
672 ARMul_ReadWord (state
, addr
),
673 ARMul_ReadWord (state
, addr
+ 4),
674 ARMul_ReadWord (state
, addr
+ 8));
677 case AngelSWI_Reason_Write
:
679 ARMul_ReadWord (state
, addr
),
680 ARMul_ReadWord (state
, addr
+ 4),
681 ARMul_ReadWord (state
, addr
+ 8));
692 /* These are used by the FPE code. */
696 /* This can happen when a SWI is interrupted (eg receiving a
697 ctrl-C whilst processing SWIRead()). The SWI will complete
698 returning -1 in r0 to the caller. If GDB is then used to
699 resume the system call the reason code will now be -1. */
702 case 0x180001: /* RedBoot's Syscall SWI in ARM mode. */
703 if (swi_mask
& SWI_MASK_REDBOOT
)
705 switch (state
->Reg
[0])
707 /* These numbers are defined in libgloss/syscall.h
708 but the simulator should not be dependend upon
709 libgloss being installed. */
711 state
->Emulate
= FALSE
;
712 /* Copy exit code into r0. */
713 state
->Reg
[0] = state
->Reg
[1];
717 SWIopen (state
, state
->Reg
[1], state
->Reg
[2]);
721 state
->Reg
[0] = sim_callback
->close (sim_callback
, state
->Reg
[1]);
722 OSptr
->ErrorNo
= sim_callback
->get_errno (sim_callback
);
726 SWIread (state
, state
->Reg
[1], state
->Reg
[2], state
->Reg
[3]);
730 SWIwrite (state
, state
->Reg
[1], state
->Reg
[2], state
->Reg
[3]);
734 state
->Reg
[0] = sim_callback
->lseek (sim_callback
,
738 OSptr
->ErrorNo
= sim_callback
->get_errno (sim_callback
);
741 case 17: /* Utime. */
742 state
->Reg
[0] = (ARMword
) sim_callback
->time (sim_callback
,
743 (long *) state
->Reg
[1]);
744 OSptr
->ErrorNo
= sim_callback
->get_errno (sim_callback
);
747 case 7: /* Unlink. */
748 case 8: /* Getpid. */
750 case 10: /* Fstat. */
752 case 12: /* Argvlen. */
754 case 14: /* ChDir. */
756 case 16: /* Chmod. */
758 sim_callback
->printf_filtered
760 "sim: unhandled RedBoot syscall '%d' encountered - ignoring\n",
765 sim_callback
->printf_filtered
767 "sim: unknown RedBoot syscall '%d' encountered - ignoring\n",
780 if (SWI_vector_installed
)
785 cpsr
= ARMul_GetCPSR (state
);
788 ARMul_SetSPSR (state
, SVC32MODE
, cpsr
);
791 cpsr
|= SVC32MODE
| 0x80;
792 ARMul_SetCPSR (state
, cpsr
);
794 state
->RegBank
[SVCBANK
][14] = state
->Reg
[14] = state
->Reg
[15] - i_size
;
795 state
->NextInstr
= RESUME
;
796 state
->Reg
[15] = state
->pc
= ARMSWIV
;
801 sim_callback
->printf_filtered
803 "sim: unknown SWI encountered - %x - ignoring\n",
815 /* The emulator calls this routine when an Exception occurs. The second
816 parameter is the address of the relevant exception vector. Returning
817 FALSE from this routine causes the trap to be taken, TRUE causes it to
818 be ignored (so set state->Emulate to FALSE!). */
821 ARMul_OSException (ARMul_State
* state ATTRIBUTE_UNUSED
,
822 ARMword vector ATTRIBUTE_UNUSED
,
823 ARMword pc ATTRIBUTE_UNUSED
)