#include "config.h"
#include "ansidecl.h"
#include <time.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#ifndef O_RDONLY
#define O_RDONLY 0
#endif
#ifndef O_WRONLY
#define O_WRONLY 1
#endif
#ifndef O_RDWR
#define O_RDWR 2
#endif
#ifndef O_BINARY
#define O_BINARY 0
#endif
#ifdef __STDC__
#define unlink(s) remove(s)
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef __riscos
extern int _fisatty (FILE *);
#define isatty_(f) _fisatty(f)
#else
#ifdef __ZTC__
#include <io.h>
#define isatty_(f) isatty((f)->_file)
#else
#ifdef macintosh
#include <ioctl.h>
#define isatty_(f) (~ioctl ((f)->_file, FIOINTERACTIVE, NULL))
#else
#define isatty_(f) isatty (fileno (f))
#endif
#endif
#endif
#include "armdefs.h"
#include "armos.h"
#include "armemu.h"
#ifndef NOOS
#ifndef VALIDATE
#include "armfpe.h"
#endif
#endif
#include "dbg_rdi.h"
#include "gdb/callback.h"
extern host_callback *sim_callback;
extern unsigned ARMul_OSInit (ARMul_State *);
extern void ARMul_OSExit (ARMul_State *);
extern unsigned ARMul_OSHandleSWI (ARMul_State *, ARMword);
extern unsigned ARMul_OSException (ARMul_State *, ARMword, ARMword);
extern ARMword ARMul_OSLastErrorP (ARMul_State *);
extern ARMword ARMul_Debug (ARMul_State *, ARMword, ARMword);
#define BUFFERSIZE 4096
#ifndef FOPEN_MAX
#define FOPEN_MAX 64
#endif
#define UNIQUETEMPS 256
struct OSblock
{
ARMword Time0;
ARMword ErrorP;
ARMword ErrorNo;
FILE *FileTable[FOPEN_MAX];
char FileFlags[FOPEN_MAX];
char *tempnames[UNIQUETEMPS];
};
#define NOOP 0
#define BINARY 1
#define READOP 2
#define WRITEOP 4
#ifdef macintosh
#define FIXCRLF(t,c) ((t & BINARY) ? \
c : \
((c == '\n' || c == '\r' ) ? (c ^ 7) : c) \
)
#else
#define FIXCRLF(t,c) c
#endif
unsigned int swi_mask = -1;
static ARMword softvectorcode[] =
{
0xef000090, 0xe1a0e00f, 0xe89b8800, 0xef000080,
0xef000091, 0xe1a0e00f, 0xe89b8800, 0xef000081,
0xef000092, 0xe1a0e00f, 0xe89b8800, 0xef000082,
0xef000093, 0xe1a0e00f, 0xe89b8800, 0xef000083,
0xef000094, 0xe1a0e00f, 0xe89b8800, 0xef000084,
0xef000095, 0xe1a0e00f, 0xe89b8800, 0xef000085,
0xef000096, 0xe1a0e00f, 0xe89b8800, 0xef000086,
0xef000097, 0xe1a0e00f, 0xe89b8800, 0xef000087,
0xef000098, 0xe1a0e00f, 0xe89b8800, 0xef000088,
0xe1a0f00e
};
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;
OSptr->ErrorP = 0;
state->Reg[13] = ADDRSUPERSTACK;
ARMul_SetReg (state, SVC32MODE, 13, ADDRSUPERSTACK);
ARMul_SetReg (state, ABORT32MODE, 13, ADDRSUPERSTACK);
ARMul_SetReg (state, UNDEF32MODE, 13, ADDRSUPERSTACK);
ARMul_SetReg (state, SYSTEMMODE, 13, ADDRSUPERSTACK);
instr = 0xe59ff000 | (ADDRSOFTVECTORS - 8);
for (i = ARMul_ResetV; i <= ARMFIQV; i += 4)
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]);
for (i = 0; i < FOPEN_MAX; i++)
OSptr->FileTable[i] = NULL;
for (i = 0; i < UNIQUETEMPS; i++)
OSptr->tempnames[i] = NULL;
ARMul_ConsolePrint (state, ", Demon 1.01");
for (i = 0; i < fpesize; i += 4)
ARMul_WriteWord (state, FPESTART + i, fpecode[i >> 2]);
for (i = FPESTART + fpesize;; i -= 4)
{
if ((j = ARMul_ReadWord (state, i)) == 0xffffffff)
break;
if (state->bigendSig && j < 0x80000000)
{
j = ((j >> 0x18) & 0x000000ff) |
((j >> 0x08) & 0x0000ff00) |
((j << 0x08) & 0x00ff0000) | ((j << 0x18) & 0xff000000);
ARMul_WriteWord (state, i, j);
}
}
ARMul_WriteWord (state, FPEOLDVECT, ARMul_ReadWord (state, 4));
ARMul_WriteWord (state, 4, FPENEWVECT (ARMul_ReadWord (state, i - 4)));
ARMul_ConsolePrint (state, ", FPE");
#endif
#endif
if (state->is_XScale)
swi_mask = SWI_MASK_ANGEL;
return TRUE;
}
void
ARMul_OSExit (ARMul_State * state)
{
free ((char *) state->OSptr);
}
ARMword ARMul_OSLastErrorP (ARMul_State * state)
{
return ((struct OSblock *) state->OSptr)->ErrorP;
}
static int translate_open_mode[] =
{
O_RDONLY,
O_RDONLY + O_BINARY,
O_RDWR,
O_RDWR + O_BINARY,
O_WRONLY + O_CREAT + O_TRUNC,
O_WRONLY + O_BINARY + O_CREAT + O_TRUNC,
O_RDWR + O_CREAT + O_TRUNC,
O_RDWR + O_BINARY + O_CREAT + O_TRUNC,
O_WRONLY + O_APPEND + O_CREAT,
O_WRONLY + O_BINARY + O_APPEND + O_CREAT,
O_RDWR + O_APPEND + O_CREAT,
O_RDWR + O_BINARY + O_APPEND + O_CREAT
};
static void
SWIWrite0 (ARMul_State * state, ARMword addr)
{
ARMword temp;
struct OSblock *OSptr = (struct OSblock *) state->OSptr;
while ((temp = ARMul_SafeReadByte (state, addr++)) != 0)
(void) sim_callback->write_stdout (sim_callback, (char *) &temp, 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 void
SWIopen (ARMul_State * state, ARMword name, ARMword SWIflags)
{
struct OSblock *OSptr = (struct OSblock *) state->OSptr;
char dummy[2000];
int flags;
int i;
for (i = 0; (dummy[i] = ARMul_SafeReadByte (state, name + i)); i++)
;
flags = translate_open_mode[SWIflags];
if (strcmp (dummy, ":tt") == 0)
{
if (flags == O_RDONLY)
state->Reg[0] = 0;
else
state->Reg[0] = 1;
}
else
{
state->Reg[0] = sim_callback->open (sim_callback, dummy, 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 == 0 || 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);
}
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)
{
state->Reg[0] =
#ifdef CLOCKS_PER_SEC
(CLOCKS_PER_SEC >= 100)
? (ARMword) (clock () / (CLOCKS_PER_SEC / 100))
: (ARMword) ((clock () * 100) / CLOCKS_PER_SEC);
#else
(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)
{
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 AngelSWI_ARM:
case AngelSWI_Thumb:
if (swi_mask & SWI_MASK_ANGEL)
{
ARMword addr;
ARMword temp;
addr = state->Reg[1];
switch (state->Reg[0])
{
case -1:
return TRUE;
case AngelSWI_Reason_ReadC:
case AngelSWI_Reason_IsTTY:
case AngelSWI_Reason_TmpNam:
case AngelSWI_Reason_Remove:
case AngelSWI_Reason_Rename:
case AngelSWI_Reason_System:
case AngelSWI_Reason_EnterSVC:
default:
state->Emulate = FALSE;
return FALSE;
case AngelSWI_Reason_Clock:
state->Reg[0] =
#ifdef CLOCKS_PER_SEC
(CLOCKS_PER_SEC >= 100)
? (ARMword) (clock () / (CLOCKS_PER_SEC / 100))
: (ARMword) ((clock () * 100) / CLOCKS_PER_SEC);
#else
(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:
addr = ARMul_ReadWord (state, addr);
if (state->MemSize)
temp = state->MemSize;
else
temp = ADDRUSERSTACK;
ARMul_WriteWord (state, addr, 0);
ARMul_WriteWord (state, addr + 4, temp);
ARMul_WriteWord (state, addr + 8, temp);
ARMul_WriteWord (state, addr + 12, temp);
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;
}
}
else
unhandled = TRUE;
break;
case 0x90:
case 0x91:
case 0x92:
break;
case -1:
return TRUE;
case 0x180001:
if (swi_mask & SWI_MASK_REDBOOT)
{
switch (state->Reg[0])
{
case 1:
state->Emulate = FALSE;
state->Reg[0] = state->Reg[1];
break;
case 2:
SWIopen (state, state->Reg[1], state->Reg[2]);
break;
case 3:
state->Reg[0] = sim_callback->close (sim_callback, state->Reg[1]);
OSptr->ErrorNo = sim_callback->get_errno (sim_callback);
break;
case 4:
SWIread (state, state->Reg[1], state->Reg[2], state->Reg[3]);
break;
case 5:
SWIwrite (state, state->Reg[1], state->Reg[2], state->Reg[3]);
break;
case 6:
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:
state->Reg[0] = (ARMword) sim_callback->time (sim_callback,
(long *) state->Reg[1]);
OSptr->ErrorNo = sim_callback->get_errno (sim_callback);
break;
case 7:
case 8:
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
case 16:
case 18:
sim_callback->printf_filtered
(sim_callback,
"sim: unhandled RedBoot syscall '%d' encountered - ignoring\n",
state->Reg[0]);
return FALSE;
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;
}
#ifndef NOOS
#ifndef ASIM
unsigned
ARMul_OSException (ARMul_State * state ATTRIBUTE_UNUSED,
ARMword vector ATTRIBUTE_UNUSED,
ARMword pc ATTRIBUTE_UNUSED)
{
return FALSE;
}
#endif
#endif