| /* armos.c -- ARMulator OS interface: ARM6 Instruction Emulator. | |
| Copyright (C) 1994 Advanced RISC Machines Ltd. | |
| This program is free software; you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published by | |
| the Free Software Foundation; either version 3 of the License, or | |
| (at your option) any later version. | |
| This program is distributed in the hope that it will be useful, | |
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| GNU General Public License for more details. | |
| You should have received a copy of the GNU General Public License | |
| along with this program; if not, see <http://www.gnu.org/licenses/>. */ | |
| /* This file contains a model of Demon, ARM Ltd's Debug Monitor, | |
| including all the SWI's required to support the C library. The code in | |
| it is not really for the faint-hearted (especially the abort handling | |
| code), but it is a complete example. Defining NOOS will disable all the | |
| fun, and definign VAILDATE will define SWI 1 to enter SVC mode, and SWI | |
| 0x11 to halt the emulator. */ | |
| #include "config.h" | |
| #include "ansidecl.h" | |
| #include "libiberty.h" | |
| #include <time.h> | |
| #include <errno.h> | |
| #include <limits.h> | |
| #include <string.h> | |
| #include "targ-vals.h" | |
| #ifndef TARGET_O_BINARY | |
| #define TARGET_O_BINARY 0 | |
| #endif | |
| #ifdef HAVE_UNISTD_H | |
| #include <unistd.h> /* For SEEK_SET etc. */ | |
| #endif | |
| #include "armdefs.h" | |
| #include "armos.h" | |
| #include "armemu.h" | |
| #ifndef NOOS | |
| #ifndef VALIDATE | |
| /* #ifndef ASIM */ | |
| #include "armfpe.h" | |
| /* #endif */ | |
| #endif | |
| #endif | |
| /* For RDIError_BreakpointReached. */ | |
| #include "dbg_rdi.h" | |
| #include "gdb/callback.h" | |
| extern host_callback *sim_callback; | |
| extern unsigned ARMul_OSInit (ARMul_State *); | |
| extern unsigned ARMul_OSHandleSWI (ARMul_State *, ARMword); | |
| #ifndef FOPEN_MAX | |
| #define FOPEN_MAX 64 | |
| #endif | |
| #ifndef PATH_MAX | |
| #define PATH_MAX 1024 | |
| #endif | |
| /* OS private Information. */ | |
| struct OSblock | |
| { | |
| ARMword ErrorNo; | |
| }; | |
| /* Bit mask of enabled SWI implementations. */ | |
| unsigned int swi_mask = -1; | |
| static ARMword softvectorcode[] = | |
| { | |
| /* Installed instructions: | |
| swi tidyexception + event; | |
| mov lr, pc; | |
| ldmia fp, {fp, pc}; | |
| swi generateexception + event. */ | |
| 0xef000090, 0xe1a0e00f, 0xe89b8800, 0xef000080, /* Reset */ | |
| 0xef000091, 0xe1a0e00f, 0xe89b8800, 0xef000081, /* Undef */ | |
| 0xef000092, 0xe1a0e00f, 0xe89b8800, 0xef000082, /* SWI */ | |
| 0xef000093, 0xe1a0e00f, 0xe89b8800, 0xef000083, /* Prefetch abort */ | |
| 0xef000094, 0xe1a0e00f, 0xe89b8800, 0xef000084, /* Data abort */ | |
| 0xef000095, 0xe1a0e00f, 0xe89b8800, 0xef000085, /* Address exception */ | |
| 0xef000096, 0xe1a0e00f, 0xe89b8800, 0xef000086, /* IRQ */ | |
| 0xef000097, 0xe1a0e00f, 0xe89b8800, 0xef000087, /* FIQ */ | |
| 0xef000098, 0xe1a0e00f, 0xe89b8800, 0xef000088, /* Error */ | |
| 0xe1a0f00e /* Default handler */ | |
| }; | |
| /* Time for the Operating System to initialise itself. */ | |
| unsigned | |
| ARMul_OSInit (ARMul_State * state) | |
| { | |
| #ifndef NOOS | |
| #ifndef VALIDATE | |
| ARMword instr, i, j; | |
| struct OSblock *OSptr = (struct OSblock *) state->OSptr; | |
| if (state->OSptr == NULL) | |
| { | |
| state->OSptr = (unsigned char *) malloc (sizeof (struct OSblock)); | |
| if (state->OSptr == NULL) | |
| { | |
| perror ("OS Memory"); | |
| exit (15); | |
| } | |
| } | |
| OSptr = (struct OSblock *) state->OSptr; | |
| state->Reg[13] = ADDRSUPERSTACK; /* Set up a stack for the current mode... */ | |
| ARMul_SetReg (state, SVC32MODE, 13, ADDRSUPERSTACK);/* ...and for supervisor mode... */ | |
| ARMul_SetReg (state, ABORT32MODE, 13, ADDRSUPERSTACK);/* ...and for abort 32 mode... */ | |
| ARMul_SetReg (state, UNDEF32MODE, 13, ADDRSUPERSTACK);/* ...and for undef 32 mode... */ | |
| ARMul_SetReg (state, SYSTEMMODE, 13, ADDRSUPERSTACK);/* ...and for system mode. */ | |
| instr = 0xe59ff000 | (ADDRSOFTVECTORS - 8); /* Load pc from soft vector */ | |
| for (i = ARMul_ResetV; i <= ARMFIQV; i += 4) | |
| /* Write hardware vectors. */ | |
| ARMul_WriteWord (state, i, instr); | |
| SWI_vector_installed = 0; | |
| for (i = ARMul_ResetV; i <= ARMFIQV + 4; i += 4) | |
| { | |
| ARMul_WriteWord (state, ADDRSOFTVECTORS + i, SOFTVECTORCODE + i * 4); | |
| ARMul_WriteWord (state, ADDRSOFHANDLERS + 2 * i + 4L, | |
| SOFTVECTORCODE + sizeof (softvectorcode) - 4L); | |
| } | |
| for (i = 0; i < sizeof (softvectorcode); i += 4) | |
| ARMul_WriteWord (state, SOFTVECTORCODE + i, softvectorcode[i / 4]); | |
| ARMul_ConsolePrint (state, ", Demon 1.01"); | |
| /* #ifndef ASIM */ | |
| /* Install FPE. */ | |
| for (i = 0; i < fpesize; i += 4) | |
| /* Copy the code. */ | |
| ARMul_WriteWord (state, FPESTART + i, fpecode[i >> 2]); | |
| /* Scan backwards from the end of the code. */ | |
| for (i = FPESTART + fpesize;; i -= 4) | |
| { | |
| /* When we reach the marker value, break out of | |
| the loop, leaving i pointing at the maker. */ | |
| if ((j = ARMul_ReadWord (state, i)) == 0xffffffff) | |
| break; | |
| /* If necessary, reverse the error strings. */ | |
| if (state->bigendSig && j < 0x80000000) | |
| { | |
| /* It's part of the string so swap it. */ | |
| j = ((j >> 0x18) & 0x000000ff) | | |
| ((j >> 0x08) & 0x0000ff00) | | |
| ((j << 0x08) & 0x00ff0000) | ((j << 0x18) & 0xff000000); | |
| ARMul_WriteWord (state, i, j); | |
| } | |
| } | |
| /* Copy old illegal instr vector. */ | |
| ARMul_WriteWord (state, FPEOLDVECT, ARMul_ReadWord (state, ARMUndefinedInstrV)); | |
| /* Install new vector. */ | |
| ARMul_WriteWord (state, ARMUndefinedInstrV, FPENEWVECT (ARMul_ReadWord (state, i - 4))); | |
| ARMul_ConsolePrint (state, ", FPE"); | |
| /* #endif ASIM */ | |
| #endif /* VALIDATE */ | |
| #endif /* NOOS */ | |
| /* Intel do not want DEMON SWI support. */ | |
| if (state->is_XScale) | |
| swi_mask = SWI_MASK_ANGEL; | |
| return TRUE; | |
| } | |
| static int translate_open_mode[] = | |
| { | |
| TARGET_O_RDONLY, /* "r" */ | |
| TARGET_O_RDONLY + TARGET_O_BINARY, /* "rb" */ | |
| TARGET_O_RDWR, /* "r+" */ | |
| TARGET_O_RDWR + TARGET_O_BINARY, /* "r+b" */ | |
| TARGET_O_WRONLY + TARGET_O_CREAT + TARGET_O_TRUNC, /* "w" */ | |
| TARGET_O_WRONLY + TARGET_O_BINARY + TARGET_O_CREAT + TARGET_O_TRUNC, /* "wb" */ | |
| TARGET_O_RDWR + TARGET_O_CREAT + TARGET_O_TRUNC, /* "w+" */ | |
| TARGET_O_RDWR + TARGET_O_BINARY + TARGET_O_CREAT + TARGET_O_TRUNC, /* "w+b" */ | |
| TARGET_O_WRONLY + TARGET_O_APPEND + TARGET_O_CREAT, /* "a" */ | |
| TARGET_O_WRONLY + TARGET_O_BINARY + TARGET_O_APPEND + TARGET_O_CREAT, /* "ab" */ | |
| TARGET_O_RDWR + TARGET_O_APPEND + TARGET_O_CREAT, /* "a+" */ | |
| TARGET_O_RDWR + TARGET_O_BINARY + TARGET_O_APPEND + TARGET_O_CREAT /* "a+b" */ | |
| }; | |
| static void | |
| SWIWrite0 (ARMul_State * state, ARMword addr) | |
| { | |
| ARMword temp; | |
| struct OSblock *OSptr = (struct OSblock *) state->OSptr; | |
| while ((temp = ARMul_SafeReadByte (state, addr++)) != 0) | |
| { | |
| char buffer = temp; | |
| /* Note - we cannot just cast 'temp' to a (char *) here, | |
| since on a big-endian host the byte value will end | |
| up in the wrong place and a nul character will be printed. */ | |
| (void) sim_callback->write_stdout (sim_callback, & buffer, 1); | |
| } | |
| OSptr->ErrorNo = sim_callback->get_errno (sim_callback); | |
| } | |
| static void | |
| WriteCommandLineTo (ARMul_State * state, ARMword addr) | |
| { | |
| ARMword temp; | |
| char *cptr = state->CommandLine; | |
| if (cptr == NULL) | |
| cptr = "\0"; | |
| do | |
| { | |
| temp = (ARMword) * cptr++; | |
| ARMul_SafeWriteByte (state, addr++, temp); | |
| } | |
| while (temp != 0); | |
| } | |
| static int | |
| ReadFileName (ARMul_State * state, char *buf, ARMword src, size_t n) | |
| { | |
| struct OSblock *OSptr = (struct OSblock *) state->OSptr; | |
| char *p = buf; | |
| while (n--) | |
| if ((*p++ = ARMul_SafeReadByte (state, src++)) == '\0') | |
| return 0; | |
| OSptr->ErrorNo = cb_host_to_target_errno (sim_callback, ENAMETOOLONG); | |
| state->Reg[0] = -1; | |
| return -1; | |
| } | |
| static void | |
| SWIopen (ARMul_State * state, ARMword name, ARMword SWIflags) | |
| { | |
| struct OSblock *OSptr = (struct OSblock *) state->OSptr; | |
| char buf[PATH_MAX]; | |
| int flags; | |
| if (ReadFileName (state, buf, name, sizeof buf) == -1) | |
| return; | |
| /* Now we need to decode the Demon open mode. */ | |
| if (SWIflags >= ARRAY_SIZE (translate_open_mode)) | |
| flags = 0; | |
| else | |
| flags = translate_open_mode[SWIflags]; | |
| /* Filename ":tt" is special: it denotes stdin/out. */ | |
| if (strcmp (buf, ":tt") == 0) | |
| { | |
| if (flags == TARGET_O_RDONLY) /* opening tty "r" */ | |
| state->Reg[0] = 0; /* stdin */ | |
| else | |
| state->Reg[0] = 1; /* stdout */ | |
| } | |
| else | |
| { | |
| state->Reg[0] = sim_callback->open (sim_callback, buf, flags); | |
| OSptr->ErrorNo = sim_callback->get_errno (sim_callback); | |
| } | |
| } | |
| static void | |
| SWIread (ARMul_State * state, ARMword f, ARMword ptr, ARMword len) | |
| { | |
| struct OSblock *OSptr = (struct OSblock *) state->OSptr; | |
| int res; | |
| int i; | |
| char *local = malloc (len); | |
| if (local == NULL) | |
| { | |
| sim_callback->printf_filtered | |
| (sim_callback, | |
| "sim: Unable to read 0x%ulx bytes - out of memory\n", | |
| len); | |
| return; | |
| } | |
| res = sim_callback->read (sim_callback, f, local, len); | |
| if (res > 0) | |
| for (i = 0; i < res; i++) | |
| ARMul_SafeWriteByte (state, ptr + i, local[i]); | |
| free (local); | |
| state->Reg[0] = res == -1 ? -1 : len - res; | |
| OSptr->ErrorNo = sim_callback->get_errno (sim_callback); | |
| } | |
| static void | |
| SWIwrite (ARMul_State * state, ARMword f, ARMword ptr, ARMword len) | |
| { | |
| struct OSblock *OSptr = (struct OSblock *) state->OSptr; | |
| int res; | |
| ARMword i; | |
| char *local = malloc (len); | |
| if (local == NULL) | |
| { | |
| sim_callback->printf_filtered | |
| (sim_callback, | |
| "sim: Unable to write 0x%lx bytes - out of memory\n", | |
| (long) len); | |
| return; | |
| } | |
| for (i = 0; i < len; i++) | |
| local[i] = ARMul_SafeReadByte (state, ptr + i); | |
| res = sim_callback->write (sim_callback, f, local, len); | |
| state->Reg[0] = res == -1 ? -1 : len - res; | |
| free (local); | |
| OSptr->ErrorNo = sim_callback->get_errno (sim_callback); | |
| } | |
| static void | |
| SWIflen (ARMul_State * state, ARMword fh) | |
| { | |
| struct OSblock *OSptr = (struct OSblock *) state->OSptr; | |
| ARMword addr; | |
| if (fh > FOPEN_MAX) | |
| { | |
| OSptr->ErrorNo = EBADF; | |
| state->Reg[0] = -1L; | |
| return; | |
| } | |
| addr = sim_callback->lseek (sim_callback, fh, 0, SEEK_CUR); | |
| state->Reg[0] = sim_callback->lseek (sim_callback, fh, 0L, SEEK_END); | |
| (void) sim_callback->lseek (sim_callback, fh, addr, SEEK_SET); | |
| OSptr->ErrorNo = sim_callback->get_errno (sim_callback); | |
| } | |
| static void | |
| SWIremove (ARMul_State * state, ARMword path) | |
| { | |
| char buf[PATH_MAX]; | |
| if (ReadFileName (state, buf, path, sizeof buf) != -1) | |
| { | |
| struct OSblock *OSptr = (struct OSblock *) state->OSptr; | |
| state->Reg[0] = sim_callback->unlink (sim_callback, buf); | |
| OSptr->ErrorNo = sim_callback->get_errno (sim_callback); | |
| } | |
| } | |
| static void | |
| SWIrename (ARMul_State * state, ARMword old, ARMword new) | |
| { | |
| char oldbuf[PATH_MAX], newbuf[PATH_MAX]; | |
| if (ReadFileName (state, oldbuf, old, sizeof oldbuf) != -1 | |
| && ReadFileName (state, newbuf, new, sizeof newbuf) != -1) | |
| { | |
| struct OSblock *OSptr = (struct OSblock *) state->OSptr; | |
| state->Reg[0] = sim_callback->rename (sim_callback, oldbuf, newbuf); | |
| OSptr->ErrorNo = sim_callback->get_errno (sim_callback); | |
| } | |
| } | |
| /* The emulator calls this routine when a SWI instruction is encuntered. | |
| The parameter passed is the SWI number (lower 24 bits of the instruction). */ | |
| unsigned | |
| ARMul_OSHandleSWI (ARMul_State * state, ARMword number) | |
| { | |
| struct OSblock * OSptr = (struct OSblock *) state->OSptr; | |
| int unhandled = FALSE; | |
| switch (number) | |
| { | |
| case SWI_Read: | |
| if (swi_mask & SWI_MASK_DEMON) | |
| SWIread (state, state->Reg[0], state->Reg[1], state->Reg[2]); | |
| else | |
| unhandled = TRUE; | |
| break; | |
| case SWI_Write: | |
| if (swi_mask & SWI_MASK_DEMON) | |
| SWIwrite (state, state->Reg[0], state->Reg[1], state->Reg[2]); | |
| else | |
| unhandled = TRUE; | |
| break; | |
| case SWI_Open: | |
| if (swi_mask & SWI_MASK_DEMON) | |
| SWIopen (state, state->Reg[0], state->Reg[1]); | |
| else | |
| unhandled = TRUE; | |
| break; | |
| case SWI_Clock: | |
| if (swi_mask & SWI_MASK_DEMON) | |
| { | |
| /* Return number of centi-seconds. */ | |
| state->Reg[0] = | |
| #ifdef CLOCKS_PER_SEC | |
| (CLOCKS_PER_SEC >= 100) | |
| ? (ARMword) (clock () / (CLOCKS_PER_SEC / 100)) | |
| : (ARMword) ((clock () * 100) / CLOCKS_PER_SEC); | |
| #else | |
| /* Presume unix... clock() returns microseconds. */ | |
| (ARMword) (clock () / 10000); | |
| #endif | |
| OSptr->ErrorNo = errno; | |
| } | |
| else | |
| unhandled = TRUE; | |
| break; | |
| case SWI_Time: | |
| if (swi_mask & SWI_MASK_DEMON) | |
| { | |
| state->Reg[0] = (ARMword) sim_callback->time (sim_callback, NULL); | |
| OSptr->ErrorNo = sim_callback->get_errno (sim_callback); | |
| } | |
| else | |
| unhandled = TRUE; | |
| break; | |
| case SWI_Close: | |
| if (swi_mask & SWI_MASK_DEMON) | |
| { | |
| state->Reg[0] = sim_callback->close (sim_callback, state->Reg[0]); | |
| OSptr->ErrorNo = sim_callback->get_errno (sim_callback); | |
| } | |
| else | |
| unhandled = TRUE; | |
| break; | |
| case SWI_Flen: | |
| if (swi_mask & SWI_MASK_DEMON) | |
| SWIflen (state, state->Reg[0]); | |
| else | |
| unhandled = TRUE; | |
| break; | |
| case SWI_Exit: | |
| if (swi_mask & SWI_MASK_DEMON) | |
| state->Emulate = FALSE; | |
| else | |
| unhandled = TRUE; | |
| break; | |
| case SWI_Seek: | |
| if (swi_mask & SWI_MASK_DEMON) | |
| { | |
| /* We must return non-zero for failure. */ | |
| state->Reg[0] = -1 >= sim_callback->lseek (sim_callback, state->Reg[0], state->Reg[1], SEEK_SET); | |
| OSptr->ErrorNo = sim_callback->get_errno (sim_callback); | |
| } | |
| else | |
| unhandled = TRUE; | |
| break; | |
| case SWI_WriteC: | |
| if (swi_mask & SWI_MASK_DEMON) | |
| { | |
| char tmp = state->Reg[0]; | |
| (void) sim_callback->write_stdout (sim_callback, &tmp, 1); | |
| OSptr->ErrorNo = sim_callback->get_errno (sim_callback); | |
| } | |
| else | |
| unhandled = TRUE; | |
| break; | |
| case SWI_Write0: | |
| if (swi_mask & SWI_MASK_DEMON) | |
| SWIWrite0 (state, state->Reg[0]); | |
| else | |
| unhandled = TRUE; | |
| break; | |
| case SWI_GetErrno: | |
| if (swi_mask & SWI_MASK_DEMON) | |
| state->Reg[0] = OSptr->ErrorNo; | |
| else | |
| unhandled = TRUE; | |
| break; | |
| case SWI_GetEnv: | |
| if (swi_mask & SWI_MASK_DEMON) | |
| { | |
| state->Reg[0] = ADDRCMDLINE; | |
| if (state->MemSize) | |
| state->Reg[1] = state->MemSize; | |
| else | |
| state->Reg[1] = ADDRUSERSTACK; | |
| WriteCommandLineTo (state, state->Reg[0]); | |
| } | |
| else | |
| unhandled = TRUE; | |
| break; | |
| case SWI_Breakpoint: | |
| state->EndCondition = RDIError_BreakpointReached; | |
| state->Emulate = FALSE; | |
| break; | |
| case SWI_Remove: | |
| if (swi_mask & SWI_MASK_DEMON) | |
| SWIremove (state, state->Reg[0]); | |
| else | |
| unhandled = TRUE; | |
| break; | |
| case SWI_Rename: | |
| if (swi_mask & SWI_MASK_DEMON) | |
| SWIrename (state, state->Reg[0], state->Reg[1]); | |
| else | |
| unhandled = TRUE; | |
| break; | |
| case SWI_IsTTY: | |
| if (swi_mask & SWI_MASK_DEMON) | |
| { | |
| state->Reg[0] = sim_callback->isatty (sim_callback, state->Reg[0]); | |
| OSptr->ErrorNo = sim_callback->get_errno (sim_callback); | |
| } | |
| else | |
| unhandled = TRUE; | |
| break; | |
| /* Handle Angel SWIs as well as Demon ones. */ | |
| case AngelSWI_ARM: | |
| case AngelSWI_Thumb: | |
| if (swi_mask & SWI_MASK_ANGEL) | |
| { | |
| ARMword addr; | |
| ARMword temp; | |
| /* R1 is almost always a parameter block. */ | |
| addr = state->Reg[1]; | |
| /* R0 is a reason code. */ | |
| switch (state->Reg[0]) | |
| { | |
| case -1: | |
| /* This can happen when a SWI is interrupted (eg receiving a | |
| ctrl-C whilst processing SWIRead()). The SWI will complete | |
| returning -1 in r0 to the caller. If GDB is then used to | |
| resume the system call the reason code will now be -1. */ | |
| return TRUE; | |
| /* Unimplemented reason codes. */ | |
| case AngelSWI_Reason_ReadC: | |
| case AngelSWI_Reason_TmpNam: | |
| case AngelSWI_Reason_System: | |
| case AngelSWI_Reason_EnterSVC: | |
| default: | |
| state->Emulate = FALSE; | |
| return FALSE; | |
| case AngelSWI_Reason_Clock: | |
| /* Return number of centi-seconds. */ | |
| state->Reg[0] = | |
| #ifdef CLOCKS_PER_SEC | |
| (CLOCKS_PER_SEC >= 100) | |
| ? (ARMword) (clock () / (CLOCKS_PER_SEC / 100)) | |
| : (ARMword) ((clock () * 100) / CLOCKS_PER_SEC); | |
| #else | |
| /* Presume unix... clock() returns microseconds. */ | |
| (ARMword) (clock () / 10000); | |
| #endif | |
| OSptr->ErrorNo = errno; | |
| break; | |
| case AngelSWI_Reason_Time: | |
| state->Reg[0] = (ARMword) sim_callback->time (sim_callback, NULL); | |
| OSptr->ErrorNo = sim_callback->get_errno (sim_callback); | |
| break; | |
| case AngelSWI_Reason_WriteC: | |
| { | |
| char tmp = ARMul_SafeReadByte (state, addr); | |
| (void) sim_callback->write_stdout (sim_callback, &tmp, 1); | |
| OSptr->ErrorNo = sim_callback->get_errno (sim_callback); | |
| break; | |
| } | |
| case AngelSWI_Reason_Write0: | |
| SWIWrite0 (state, addr); | |
| break; | |
| case AngelSWI_Reason_Close: | |
| state->Reg[0] = sim_callback->close (sim_callback, ARMul_ReadWord (state, addr)); | |
| OSptr->ErrorNo = sim_callback->get_errno (sim_callback); | |
| break; | |
| case AngelSWI_Reason_Seek: | |
| state->Reg[0] = -1 >= sim_callback->lseek (sim_callback, ARMul_ReadWord (state, addr), | |
| ARMul_ReadWord (state, addr + 4), | |
| SEEK_SET); | |
| OSptr->ErrorNo = sim_callback->get_errno (sim_callback); | |
| break; | |
| case AngelSWI_Reason_FLen: | |
| SWIflen (state, ARMul_ReadWord (state, addr)); | |
| break; | |
| case AngelSWI_Reason_GetCmdLine: | |
| WriteCommandLineTo (state, ARMul_ReadWord (state, addr)); | |
| break; | |
| case AngelSWI_Reason_HeapInfo: | |
| /* R1 is a pointer to a pointer. */ | |
| addr = ARMul_ReadWord (state, addr); | |
| /* Pick up the right memory limit. */ | |
| if (state->MemSize) | |
| temp = state->MemSize; | |
| else | |
| temp = ADDRUSERSTACK; | |
| ARMul_WriteWord (state, addr, 0); /* Heap base. */ | |
| ARMul_WriteWord (state, addr + 4, temp); /* Heap limit. */ | |
| ARMul_WriteWord (state, addr + 8, temp); /* Stack base. */ | |
| ARMul_WriteWord (state, addr + 12, temp); /* Stack limit. */ | |
| break; | |
| case AngelSWI_Reason_ReportException: | |
| if (state->Reg[1] == ADP_Stopped_ApplicationExit) | |
| state->Reg[0] = 0; | |
| else | |
| state->Reg[0] = -1; | |
| state->Emulate = FALSE; | |
| break; | |
| case ADP_Stopped_ApplicationExit: | |
| state->Reg[0] = 0; | |
| state->Emulate = FALSE; | |
| break; | |
| case ADP_Stopped_RunTimeError: | |
| state->Reg[0] = -1; | |
| state->Emulate = FALSE; | |
| break; | |
| case AngelSWI_Reason_Errno: | |
| state->Reg[0] = OSptr->ErrorNo; | |
| break; | |
| case AngelSWI_Reason_Open: | |
| SWIopen (state, | |
| ARMul_ReadWord (state, addr), | |
| ARMul_ReadWord (state, addr + 4)); | |
| break; | |
| case AngelSWI_Reason_Read: | |
| SWIread (state, | |
| ARMul_ReadWord (state, addr), | |
| ARMul_ReadWord (state, addr + 4), | |
| ARMul_ReadWord (state, addr + 8)); | |
| break; | |
| case AngelSWI_Reason_Write: | |
| SWIwrite (state, | |
| ARMul_ReadWord (state, addr), | |
| ARMul_ReadWord (state, addr + 4), | |
| ARMul_ReadWord (state, addr + 8)); | |
| break; | |
| case AngelSWI_Reason_IsTTY: | |
| state->Reg[0] = sim_callback->isatty (sim_callback, | |
| ARMul_ReadWord (state, addr)); | |
| OSptr->ErrorNo = sim_callback->get_errno (sim_callback); | |
| break; | |
| case AngelSWI_Reason_Remove: | |
| SWIremove (state, | |
| ARMul_ReadWord (state, addr)); | |
| case AngelSWI_Reason_Rename: | |
| SWIrename (state, | |
| ARMul_ReadWord (state, addr), | |
| ARMul_ReadWord (state, addr + 4)); | |
| } | |
| } | |
| else | |
| unhandled = TRUE; | |
| break; | |
| /* The following SWIs are generated by the softvectorcode[] | |
| installed by default by the simulator. */ | |
| case 0x91: /* Undefined Instruction. */ | |
| { | |
| ARMword addr = state->RegBank[UNDEFBANK][14] - 4; | |
| sim_callback->printf_filtered | |
| (sim_callback, "sim: exception: Unhandled Instruction '0x%08x' at 0x%08x. Stopping.\n", | |
| ARMul_ReadWord (state, addr), addr); | |
| state->EndCondition = RDIError_SoftwareInterrupt; | |
| state->Emulate = FALSE; | |
| return FALSE; | |
| } | |
| case 0x90: /* Reset. */ | |
| case 0x92: /* SWI. */ | |
| /* These two can be safely ignored. */ | |
| break; | |
| case 0x93: /* Prefetch Abort. */ | |
| case 0x94: /* Data Abort. */ | |
| case 0x95: /* Address Exception. */ | |
| case 0x96: /* IRQ. */ | |
| case 0x97: /* FIQ. */ | |
| case 0x98: /* Error. */ | |
| unhandled = TRUE; | |
| break; | |
| case -1: | |
| /* This can happen when a SWI is interrupted (eg receiving a | |
| ctrl-C whilst processing SWIRead()). The SWI will complete | |
| returning -1 in r0 to the caller. If GDB is then used to | |
| resume the system call the reason code will now be -1. */ | |
| return TRUE; | |
| case 0x180001: /* RedBoot's Syscall SWI in ARM mode. */ | |
| if (swi_mask & SWI_MASK_REDBOOT) | |
| { | |
| switch (state->Reg[0]) | |
| { | |
| /* These numbers are defined in libgloss/syscall.h | |
| but the simulator should not be dependend upon | |
| libgloss being installed. */ | |
| case 1: /* Exit. */ | |
| state->Emulate = FALSE; | |
| /* Copy exit code into r0. */ | |
| state->Reg[0] = state->Reg[1]; | |
| break; | |
| case 2: /* Open. */ | |
| SWIopen (state, state->Reg[1], state->Reg[2]); | |
| break; | |
| case 3: /* Close. */ | |
| state->Reg[0] = sim_callback->close (sim_callback, state->Reg[1]); | |
| OSptr->ErrorNo = sim_callback->get_errno (sim_callback); | |
| break; | |
| case 4: /* Read. */ | |
| SWIread (state, state->Reg[1], state->Reg[2], state->Reg[3]); | |
| break; | |
| case 5: /* Write. */ | |
| SWIwrite (state, state->Reg[1], state->Reg[2], state->Reg[3]); | |
| break; | |
| case 6: /* Lseek. */ | |
| state->Reg[0] = sim_callback->lseek (sim_callback, | |
| state->Reg[1], | |
| state->Reg[2], | |
| state->Reg[3]); | |
| OSptr->ErrorNo = sim_callback->get_errno (sim_callback); | |
| break; | |
| case 17: /* Utime. */ | |
| state->Reg[0] = state->Reg[1] = (ARMword) sim_callback->time (sim_callback, NULL); | |
| OSptr->ErrorNo = sim_callback->get_errno (sim_callback); | |
| break; | |
| case 7: /* Unlink. */ | |
| case 8: /* Getpid. */ | |
| case 9: /* Kill. */ | |
| case 10: /* Fstat. */ | |
| case 11: /* Sbrk. */ | |
| case 12: /* Argvlen. */ | |
| case 13: /* Argv. */ | |
| case 14: /* ChDir. */ | |
| case 15: /* Stat. */ | |
| case 16: /* Chmod. */ | |
| case 18: /* Time. */ | |
| sim_callback->printf_filtered | |
| (sim_callback, | |
| "sim: unhandled RedBoot syscall `%d' encountered - " | |
| "returning ENOSYS\n", | |
| state->Reg[0]); | |
| state->Reg[0] = -1; | |
| OSptr->ErrorNo = cb_host_to_target_errno | |
| (sim_callback, ENOSYS); | |
| break; | |
| case 1001: /* Meminfo. */ | |
| { | |
| ARMword totmem = state->Reg[1], | |
| topmem = state->Reg[2]; | |
| ARMword stack = state->MemSize > 0 | |
| ? state->MemSize : ADDRUSERSTACK; | |
| if (totmem != 0) | |
| ARMul_WriteWord (state, totmem, stack); | |
| if (topmem != 0) | |
| ARMul_WriteWord (state, topmem, stack); | |
| state->Reg[0] = 0; | |
| break; | |
| } | |
| default: | |
| sim_callback->printf_filtered | |
| (sim_callback, | |
| "sim: unknown RedBoot syscall '%d' encountered - ignoring\n", | |
| state->Reg[0]); | |
| return FALSE; | |
| } | |
| break; | |
| } | |
| default: | |
| unhandled = TRUE; | |
| } | |
| if (unhandled) | |
| { | |
| if (SWI_vector_installed) | |
| { | |
| ARMword cpsr; | |
| ARMword i_size; | |
| cpsr = ARMul_GetCPSR (state); | |
| i_size = INSN_SIZE; | |
| ARMul_SetSPSR (state, SVC32MODE, cpsr); | |
| cpsr &= ~0xbf; | |
| cpsr |= SVC32MODE | 0x80; | |
| ARMul_SetCPSR (state, cpsr); | |
| state->RegBank[SVCBANK][14] = state->Reg[14] = state->Reg[15] - i_size; | |
| state->NextInstr = RESUME; | |
| state->Reg[15] = state->pc = ARMSWIV; | |
| FLUSHPIPE; | |
| } | |
| else | |
| { | |
| sim_callback->printf_filtered | |
| (sim_callback, | |
| "sim: unknown SWI encountered - %x - ignoring\n", | |
| number); | |
| return FALSE; | |
| } | |
| } | |
| return TRUE; | |
| } |