| /* 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%lx bytes - out of memory\n", |
| (long)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; |
| } |