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. */
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 static ARMword softvectorcode
[] =
130 /* Basic: swi tidyexception + event; mov pc, lr;
131 ldmia r11,{r11,pc}; swi generateexception + event. */
132 0xef000090, 0xe1a0e00f, 0xe89b8800, 0xef000080, /* Reset */
133 0xef000091, 0xe1a0e00f, 0xe89b8800, 0xef000081, /* Undef */
134 0xef000092, 0xe1a0e00f, 0xe89b8800, 0xef000082, /* SWI */
135 0xef000093, 0xe1a0e00f, 0xe89b8800, 0xef000083, /* Prefetch abort */
136 0xef000094, 0xe1a0e00f, 0xe89b8800, 0xef000084, /* Data abort */
137 0xef000095, 0xe1a0e00f, 0xe89b8800, 0xef000085, /* Address exception */
138 0xef000096, 0xe1a0e00f, 0xe89b8800, 0xef000086, /* IRQ */
139 0xef000097, 0xe1a0e00f, 0xe89b8800, 0xef000087, /* FIQ */
140 0xef000098, 0xe1a0e00f, 0xe89b8800, 0xef000088, /* Error */
141 0xe1a0f00e /* Default handler */
144 /* Time for the Operating System to initialise itself. */
147 ARMul_OSInit (ARMul_State
* state
)
152 struct OSblock
*OSptr
= (struct OSblock
*) state
->OSptr
;
154 if (state
->OSptr
== NULL
)
156 state
->OSptr
= (unsigned char *) malloc (sizeof (struct OSblock
));
157 if (state
->OSptr
== NULL
)
159 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 */
173 for (i
= ARMul_ResetV
; i
<= ARMFIQV
; i
+= 4)
174 /* Write hardware vectors. */
175 ARMul_WriteWord (state
, i
, instr
);
177 SWI_vector_installed
= 0;
179 for (i
= ARMul_ResetV
; i
<= ARMFIQV
+ 4; i
+= 4)
181 ARMul_WriteWord (state
, ADDRSOFTVECTORS
+ i
, SOFTVECTORCODE
+ i
* 4);
182 ARMul_WriteWord (state
, ADDRSOFHANDLERS
+ 2 * i
+ 4L,
183 SOFTVECTORCODE
+ sizeof (softvectorcode
) - 4L);
186 for (i
= 0; i
< sizeof (softvectorcode
); i
+= 4)
187 ARMul_WriteWord (state
, SOFTVECTORCODE
+ i
, softvectorcode
[i
/ 4]);
189 for (i
= 0; i
< FOPEN_MAX
; i
++)
190 OSptr
->FileTable
[i
] = NULL
;
192 for (i
= 0; i
< UNIQUETEMPS
; i
++)
193 OSptr
->tempnames
[i
] = NULL
;
195 ARMul_ConsolePrint (state
, ", Demon 1.01");
200 for (i
= 0; i
< fpesize
; i
+= 4)
202 ARMul_WriteWord (state
, FPESTART
+ i
, fpecode
[i
>> 2]);
204 for (i
= FPESTART
+ fpesize
;; i
-= 4)
206 /* Reverse the error strings. */
207 if ((j
= ARMul_ReadWord (state
, i
)) == 0xffffffff)
209 if (state
->bigendSig
&& j
< 0x80000000)
211 /* It's part of the string so swap it. */
212 j
= ((j
>> 0x18) & 0x000000ff) |
213 ((j
>> 0x08) & 0x0000ff00) |
214 ((j
<< 0x08) & 0x00ff0000) | ((j
<< 0x18) & 0xff000000);
215 ARMul_WriteWord (state
, i
, j
);
219 /* Copy old illegal instr vector. */
220 ARMul_WriteWord (state
, FPEOLDVECT
, ARMul_ReadWord (state
, 4));
221 /* Install new vector. */
222 ARMul_WriteWord (state
, 4, FPENEWVECT (ARMul_ReadWord (state
, i
- 4)));
223 ARMul_ConsolePrint (state
, ", FPE");
226 #endif /* VALIDATE */
233 ARMul_OSExit (ARMul_State
* state
)
235 free ((char *) state
->OSptr
);
239 /* Return the last Operating System Error. */
241 ARMword
ARMul_OSLastErrorP (ARMul_State
* state
)
243 return ((struct OSblock
*) state
->OSptr
)->ErrorP
;
246 static int translate_open_mode
[] =
249 O_RDONLY
+ O_BINARY
, /* "rb" */
251 O_RDWR
+ O_BINARY
, /* "r+b" */
252 O_WRONLY
+ O_CREAT
+ O_TRUNC
, /* "w" */
253 O_WRONLY
+ O_BINARY
+ O_CREAT
+ O_TRUNC
, /* "wb" */
254 O_RDWR
+ O_CREAT
+ O_TRUNC
, /* "w+" */
255 O_RDWR
+ O_BINARY
+ O_CREAT
+ O_TRUNC
, /* "w+b" */
256 O_WRONLY
+ O_APPEND
+ O_CREAT
, /* "a" */
257 O_WRONLY
+ O_BINARY
+ O_APPEND
+ O_CREAT
, /* "ab" */
258 O_RDWR
+ O_APPEND
+ O_CREAT
, /* "a+" */
259 O_RDWR
+ O_BINARY
+ O_APPEND
+ O_CREAT
/* "a+b" */
263 SWIWrite0 (ARMul_State
* state
, ARMword addr
)
266 struct OSblock
*OSptr
= (struct OSblock
*) state
->OSptr
;
268 while ((temp
= ARMul_SafeReadByte (state
, addr
++)) != 0)
269 (void) sim_callback
->write_stdout (sim_callback
, (char *) &temp
, 1);
271 OSptr
->ErrorNo
= sim_callback
->get_errno (sim_callback
);
275 WriteCommandLineTo (ARMul_State
* state
, ARMword addr
)
278 char *cptr
= state
->CommandLine
;
284 temp
= (ARMword
) * cptr
++;
285 ARMul_SafeWriteByte (state
, addr
++, temp
);
291 SWIopen (ARMul_State
* state
, ARMword name
, ARMword SWIflags
)
293 struct OSblock
*OSptr
= (struct OSblock
*) state
->OSptr
;
298 for (i
= 0; (dummy
[i
] = ARMul_SafeReadByte (state
, name
+ i
)); i
++)
301 /* Now we need to decode the Demon open mode. */
302 flags
= translate_open_mode
[SWIflags
];
304 /* Filename ":tt" is special: it denotes stdin/out. */
305 if (strcmp (dummy
, ":tt") == 0)
307 if (flags
== O_RDONLY
) /* opening tty "r" */
308 state
->Reg
[0] = 0; /* stdin */
310 state
->Reg
[0] = 1; /* stdout */
314 state
->Reg
[0] = sim_callback
->open (sim_callback
, dummy
, flags
);
315 OSptr
->ErrorNo
= sim_callback
->get_errno (sim_callback
);
320 SWIread (ARMul_State
* state
, ARMword f
, ARMword ptr
, ARMword len
)
322 struct OSblock
*OSptr
= (struct OSblock
*) state
->OSptr
;
325 char *local
= malloc (len
);
329 sim_callback
->printf_filtered
331 "sim: Unable to read 0x%ulx bytes - out of memory\n",
336 res
= sim_callback
->read (sim_callback
, f
, local
, len
);
338 for (i
= 0; i
< res
; i
++)
339 ARMul_SafeWriteByte (state
, ptr
+ i
, local
[i
]);
342 state
->Reg
[0] = res
== -1 ? -1 : len
- res
;
343 OSptr
->ErrorNo
= sim_callback
->get_errno (sim_callback
);
347 SWIwrite (ARMul_State
* state
, ARMword f
, ARMword ptr
, ARMword len
)
349 struct OSblock
*OSptr
= (struct OSblock
*) state
->OSptr
;
352 char *local
= malloc (len
);
356 sim_callback
->printf_filtered
358 "sim: Unable to write 0x%lx bytes - out of memory\n",
363 for (i
= 0; i
< len
; i
++)
364 local
[i
] = ARMul_SafeReadByte (state
, ptr
+ i
);
366 res
= sim_callback
->write (sim_callback
, f
, local
, len
);
367 state
->Reg
[0] = res
== -1 ? -1 : len
- res
;
370 OSptr
->ErrorNo
= sim_callback
->get_errno (sim_callback
);
374 SWIflen (ARMul_State
* state
, ARMword fh
)
376 struct OSblock
*OSptr
= (struct OSblock
*) state
->OSptr
;
379 if (fh
== 0 || fh
> FOPEN_MAX
)
381 OSptr
->ErrorNo
= EBADF
;
386 addr
= sim_callback
->lseek (sim_callback
, fh
, 0, SEEK_CUR
);
388 state
->Reg
[0] = sim_callback
->lseek (sim_callback
, fh
, 0L, SEEK_END
);
389 (void) sim_callback
->lseek (sim_callback
, fh
, addr
, SEEK_SET
);
391 OSptr
->ErrorNo
= sim_callback
->get_errno (sim_callback
);
394 /* The emulator calls this routine when a SWI instruction is encuntered.
395 The parameter passed is the SWI number (lower 24 bits of the instruction). */
398 ARMul_OSHandleSWI (ARMul_State
* state
, ARMword number
)
402 ARMword saved_number
= 0;
403 struct OSblock
* OSptr
= (struct OSblock
*) state
->OSptr
;
405 /* Intel do not want DEMON SWI support. */
406 if (state
->is_XScale
)
422 saved_number
= number
;
431 SWIread (state
, state
->Reg
[0], state
->Reg
[1], state
->Reg
[2]);
435 SWIwrite (state
, state
->Reg
[0], state
->Reg
[1], state
->Reg
[2]);
439 SWIopen (state
, state
->Reg
[0], state
->Reg
[1]);
443 /* Return number of centi-seconds. */
445 #ifdef CLOCKS_PER_SEC
446 (CLOCKS_PER_SEC
>= 100)
447 ? (ARMword
) (clock () / (CLOCKS_PER_SEC
/ 100))
448 : (ARMword
) ((clock () * 100) / CLOCKS_PER_SEC
);
450 /* Presume unix... clock() returns microseconds. */
451 (ARMword
) (clock () / 10000);
453 OSptr
->ErrorNo
= errno
;
457 state
->Reg
[0] = (ARMword
) sim_callback
->time (sim_callback
, NULL
);
458 OSptr
->ErrorNo
= sim_callback
->get_errno (sim_callback
);
462 state
->Reg
[0] = sim_callback
->close (sim_callback
, state
->Reg
[0]);
463 OSptr
->ErrorNo
= sim_callback
->get_errno (sim_callback
);
467 SWIflen (state
, state
->Reg
[0]);
471 state
->Emulate
= FALSE
;
475 /* We must return non-zero for failure. */
476 state
->Reg
[0] = -1 >= sim_callback
->lseek (sim_callback
, state
->Reg
[0], state
->Reg
[1], SEEK_SET
);
477 OSptr
->ErrorNo
= sim_callback
->get_errno (sim_callback
);
482 char tmp
= state
->Reg
[0];
483 (void) sim_callback
->write_stdout (sim_callback
, &tmp
, 1);
484 OSptr
->ErrorNo
= sim_callback
->get_errno (sim_callback
);
489 SWIWrite0 (state
, state
->Reg
[0]);
493 state
->Reg
[0] = OSptr
->ErrorNo
;
497 state
->Reg
[0] = ADDRCMDLINE
;
499 state
->Reg
[1] = state
->MemSize
;
501 state
->Reg
[1] = ADDRUSERSTACK
;
503 WriteCommandLineTo (state
, state
->Reg
[0]);
507 state
->EndCondition
= RDIError_BreakpointReached
;
508 state
->Emulate
= FALSE
;
511 /* Handle Angel SWIs as well as Demon ones. */
514 /* R1 is almost always a parameter block. */
515 addr
= state
->Reg
[1];
516 /* R0 is a reason code. */
517 switch (state
->Reg
[0])
519 /* Unimplemented reason codes. */
520 case AngelSWI_Reason_ReadC
:
521 case AngelSWI_Reason_IsTTY
:
522 case AngelSWI_Reason_TmpNam
:
523 case AngelSWI_Reason_Remove
:
524 case AngelSWI_Reason_Rename
:
525 case AngelSWI_Reason_System
:
526 case AngelSWI_Reason_EnterSVC
:
528 state
->Emulate
= FALSE
;
531 case AngelSWI_Reason_Clock
:
532 /* Return number of centi-seconds. */
534 #ifdef CLOCKS_PER_SEC
535 (CLOCKS_PER_SEC
>= 100)
536 ? (ARMword
) (clock () / (CLOCKS_PER_SEC
/ 100))
537 : (ARMword
) ((clock () * 100) / CLOCKS_PER_SEC
);
539 /* Presume unix... clock() returns microseconds. */
540 (ARMword
) (clock () / 10000);
542 OSptr
->ErrorNo
= errno
;
545 case AngelSWI_Reason_Time
:
546 state
->Reg
[0] = (ARMword
) sim_callback
->time (sim_callback
, NULL
);
547 OSptr
->ErrorNo
= sim_callback
->get_errno (sim_callback
);
550 case AngelSWI_Reason_WriteC
:
552 char tmp
= ARMul_SafeReadByte (state
, addr
);
553 (void) sim_callback
->write_stdout (sim_callback
, &tmp
, 1);
554 OSptr
->ErrorNo
= sim_callback
->get_errno (sim_callback
);
558 case AngelSWI_Reason_Write0
:
559 SWIWrite0 (state
, addr
);
562 case AngelSWI_Reason_Close
:
563 state
->Reg
[0] = sim_callback
->close (sim_callback
, ARMul_ReadWord (state
, addr
));
564 OSptr
->ErrorNo
= sim_callback
->get_errno (sim_callback
);
567 case AngelSWI_Reason_Seek
:
568 state
->Reg
[0] = -1 >= sim_callback
->lseek (sim_callback
, ARMul_ReadWord (state
, addr
),
569 ARMul_ReadWord (state
, addr
+ 4),
571 OSptr
->ErrorNo
= sim_callback
->get_errno (sim_callback
);
574 case AngelSWI_Reason_FLen
:
575 SWIflen (state
, ARMul_ReadWord (state
, addr
));
578 case AngelSWI_Reason_GetCmdLine
:
579 WriteCommandLineTo (state
, ARMul_ReadWord (state
, addr
));
582 case AngelSWI_Reason_HeapInfo
:
583 /* R1 is a pointer to a pointer. */
584 addr
= ARMul_ReadWord (state
, addr
);
586 /* Pick up the right memory limit. */
588 temp
= state
->MemSize
;
590 temp
= ADDRUSERSTACK
;
592 ARMul_WriteWord (state
, addr
, 0); /* Heap base. */
593 ARMul_WriteWord (state
, addr
+ 4, temp
); /* Heap limit. */
594 ARMul_WriteWord (state
, addr
+ 8, temp
); /* Stack base. */
595 ARMul_WriteWord (state
, addr
+ 12, temp
); /* Stack limit. */
598 case AngelSWI_Reason_ReportException
:
599 if (state
->Reg
[1] == ADP_Stopped_ApplicationExit
)
603 state
->Emulate
= FALSE
;
606 case ADP_Stopped_ApplicationExit
:
608 state
->Emulate
= FALSE
;
611 case ADP_Stopped_RunTimeError
:
613 state
->Emulate
= FALSE
;
616 case AngelSWI_Reason_Errno
:
617 state
->Reg
[0] = OSptr
->ErrorNo
;
620 case AngelSWI_Reason_Open
:
622 ARMul_ReadWord (state
, addr
),
623 ARMul_ReadWord (state
, addr
+ 4));
626 case AngelSWI_Reason_Read
:
628 ARMul_ReadWord (state
, addr
),
629 ARMul_ReadWord (state
, addr
+ 4),
630 ARMul_ReadWord (state
, addr
+ 8));
633 case AngelSWI_Reason_Write
:
635 ARMul_ReadWord (state
, addr
),
636 ARMul_ReadWord (state
, addr
+ 4),
637 ARMul_ReadWord (state
, addr
+ 8));
644 /* These are used by the FPE code. */
647 case 0x180001: /* RedBoot's Syscall SWI in ARM mode. */
648 switch (state
->Reg
[0])
650 /* These numbers are defined in libgloss/syscall.h
651 but the simulator should not be dependend upon
652 libgloss being installed. */
654 state
->Emulate
= FALSE
;
658 SWIopen (state
, state
->Reg
[1], state
->Reg
[2]);
662 state
->Reg
[0] = sim_callback
->close (sim_callback
, state
->Reg
[1]);
663 OSptr
->ErrorNo
= sim_callback
->get_errno (sim_callback
);
667 SWIread (state
, state
->Reg
[1], state
->Reg
[2], state
->Reg
[3]);
671 SWIwrite (state
, state
->Reg
[1], state
->Reg
[2], state
->Reg
[3]);
675 state
->Reg
[0] = sim_callback
->lseek (sim_callback
,
679 OSptr
->ErrorNo
= sim_callback
->get_errno (sim_callback
);
682 case 17: /* Utime. */
683 state
->Reg
[0] = (ARMword
) sim_callback
->time (sim_callback
,
684 (long *) state
->Reg
[1]);
685 OSptr
->ErrorNo
= sim_callback
->get_errno (sim_callback
);
688 case 7: /* Unlink. */
689 case 8: /* Getpid. */
691 case 10: /* Fstat. */
693 case 12: /* Argvlen. */
695 case 14: /* ChDir. */
697 case 16: /* Chmod. */
699 sim_callback
->printf_filtered
701 "sim: unhandled RedBoot syscall '%d' encountered - ignoring\n",
706 sim_callback
->printf_filtered
708 "sim: unknown RedBoot syscall '%d' encountered - ignoring\n",
715 /* If there is a SWI vector installed use it. */
716 if (state
->is_XScale
&& saved_number
!= -1)
717 number
= saved_number
;
719 if (SWI_vector_installed
&& number
!= SWI_Breakpoint
)
724 cpsr
= ARMul_GetCPSR (state
);
727 ARMul_SetSPSR (state
, SVC32MODE
, cpsr
);
730 cpsr
|= SVC32MODE
| 0x80;
731 ARMul_SetCPSR (state
, cpsr
);
733 state
->RegBank
[SVCBANK
][14] = state
->Reg
[14] = state
->Reg
[15] - i_size
;
734 state
->NextInstr
= RESUME
;
735 state
->Reg
[15] = state
->pc
= ARMSWIV
;
740 sim_callback
->printf_filtered
742 "sim: unknown SWI encountered - %x - ignoring\n",
754 /* The emulator calls this routine when an Exception occurs. The second
755 parameter is the address of the relevant exception vector. Returning
756 FALSE from this routine causes the trap to be taken, TRUE causes it to
757 be ignored (so set state->Emulate to FALSE!). */
760 ARMul_OSException (ARMul_State
* state ATTRIBUTE_UNUSED
,
761 ARMword vector ATTRIBUTE_UNUSED
,
762 ARMword pc ATTRIBUTE_UNUSED
)