Commit | Line | Data |
---|---|---|
7d449b44 JM |
1 | /* armos.c -- ARMulator OS interface: ARM6 Instruction Emulator. |
2 | Copyright (C) 1994 Advanced RISC Machines Ltd. | |
3 | ||
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. | |
8 | ||
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. | |
13 | ||
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. */ | |
17 | ||
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. */ | |
24 | ||
25 | #include "config.h" | |
26 | ||
27 | #include <time.h> | |
28 | #include <errno.h> | |
29 | #include <string.h> | |
30 | #include <fcntl.h> | |
31 | ||
32 | #ifndef O_RDONLY | |
33 | #define O_RDONLY 0 | |
34 | #endif | |
35 | #ifndef O_WRONLY | |
36 | #define O_WRONLY 1 | |
37 | #endif | |
38 | #ifndef O_RDWR | |
39 | #define O_RDWR 2 | |
40 | #endif | |
41 | #ifndef O_BINARY | |
42 | #define O_BINARY 0 | |
43 | #endif | |
44 | ||
45 | #ifdef __STDC__ | |
46 | #define unlink(s) remove(s) | |
47 | #endif | |
48 | ||
49 | #ifdef HAVE_UNISTD_H | |
50 | #include <unistd.h> /* For SEEK_SET etc */ | |
51 | #endif | |
52 | ||
53 | #ifdef __riscos | |
54 | extern int _fisatty(FILE *); | |
55 | #define isatty_(f) _fisatty(f) | |
56 | #else | |
57 | #ifdef __ZTC__ | |
58 | #include <io.h> | |
59 | #define isatty_(f) isatty((f)->_file) | |
60 | #else | |
61 | #ifdef macintosh | |
62 | #include <ioctl.h> | |
63 | #define isatty_(f) (~ioctl((f)->_file,FIOINTERACTIVE,NULL)) | |
64 | #else | |
65 | #define isatty_(f) isatty(fileno(f)) | |
66 | #endif | |
67 | #endif | |
68 | #endif | |
69 | ||
70 | #include "armdefs.h" | |
71 | #include "armos.h" | |
72 | #ifndef NOOS | |
73 | #ifndef VALIDATE | |
74 | /* #ifndef ASIM */ | |
75 | #include "armfpe.h" | |
76 | /* #endif */ | |
77 | #endif | |
78 | #endif | |
79 | ||
80 | /* For RDIError_BreakpointReached. */ | |
81 | #include "dbg_rdi.h" | |
82 | ||
83 | extern unsigned ARMul_OSInit(ARMul_State *state) ; | |
84 | extern void ARMul_OSExit(ARMul_State *state) ; | |
85 | extern unsigned ARMul_OSHandleSWI(ARMul_State *state,ARMword number) ; | |
86 | extern unsigned ARMul_OSException(ARMul_State *state, ARMword vector, ARMword pc) ; | |
87 | extern ARMword ARMul_OSLastErrorP(ARMul_State *state) ; | |
88 | extern ARMword ARMul_Debug(ARMul_State *state, ARMword pc, ARMword instr) ; | |
89 | ||
90 | #define BUFFERSIZE 4096 | |
91 | #ifndef FOPEN_MAX | |
92 | #define FOPEN_MAX 64 | |
93 | #endif | |
94 | #define UNIQUETEMPS 256 | |
95 | ||
96 | #ifndef NOOS | |
97 | static void UnwindDataAbort(ARMul_State *state, ARMword addr); | |
98 | static void getstring(ARMul_State *state, ARMword from, char *to) ; | |
99 | #endif | |
100 | ||
101 | /***************************************************************************\ | |
102 | * OS private Information * | |
103 | \***************************************************************************/ | |
104 | ||
105 | struct OSblock { | |
106 | ARMword Time0 ; | |
107 | ARMword ErrorP ; | |
108 | ARMword ErrorNo ; | |
109 | FILE *FileTable[FOPEN_MAX] ; | |
110 | char FileFlags[FOPEN_MAX] ; | |
111 | char *tempnames[UNIQUETEMPS] ; | |
112 | } ; | |
113 | ||
114 | #define NOOP 0 | |
115 | #define BINARY 1 | |
116 | #define READOP 2 | |
117 | #define WRITEOP 4 | |
118 | ||
119 | #ifdef macintosh | |
120 | #define FIXCRLF(t,c) ((t & BINARY)?c:((c=='\n'||c=='\r')?(c ^ 7):c)) | |
121 | #else | |
122 | #define FIXCRLF(t,c) c | |
123 | #endif | |
124 | ||
125 | static ARMword softvectorcode[] = | |
126 | { /* basic: swi tidyexception + event; mov pc, lr; | |
127 | ldmia r11,{r11,pc}; swi generateexception + event | |
128 | */ | |
129 | 0xef000090, 0xe1a0e00f, 0xe89b8800, 0xef000080, /*Reset*/ | |
130 | 0xef000091, 0xe1a0e00f, 0xe89b8800, 0xef000081, /*Undef*/ | |
131 | 0xef000092, 0xe1a0e00f, 0xe89b8800, 0xef000082, /*SWI */ | |
132 | 0xef000093, 0xe1a0e00f, 0xe89b8800, 0xef000083, /*Prefetch abort*/ | |
133 | 0xef000094, 0xe1a0e00f, 0xe89b8800, 0xef000084, /*Data abort*/ | |
134 | 0xef000095, 0xe1a0e00f, 0xe89b8800, 0xef000085, /*Address exception*/ | |
135 | 0xef000096, 0xe1a0e00f, 0xe89b8800, 0xef000086, /*IRQ*/ | |
136 | 0xef000097, 0xe1a0e00f, 0xe89b8800, 0xef000087, /*FIQ*/ | |
137 | 0xef000098, 0xe1a0e00f, 0xe89b8800, 0xef000088, /*Error*/ | |
138 | 0xe1a0f00e /* default handler */ | |
139 | }; | |
140 | ||
141 | /***************************************************************************\ | |
142 | * Time for the Operating System to initialise itself. * | |
143 | \***************************************************************************/ | |
144 | ||
145 | unsigned ARMul_OSInit(ARMul_State *state) | |
146 | { | |
147 | #ifndef NOOS | |
148 | #ifndef VALIDATE | |
149 | ARMword instr, i , j ; | |
150 | struct OSblock* OSptr = (struct OSblock*)state->OSptr; | |
151 | ||
152 | if (state->OSptr == NULL) { | |
153 | state->OSptr = (unsigned char *)malloc(sizeof(struct OSblock)); | |
154 | if (state->OSptr == NULL) { | |
155 | perror("OS Memory"); | |
156 | exit(15); | |
157 | } | |
158 | } | |
159 | OSptr = (struct OSblock*)state->OSptr; | |
160 | OSptr->ErrorP = 0; | |
161 | state->Reg[13] = ADDRSUPERSTACK; /* set up a stack for the current mode */ | |
162 | ARMul_SetReg(state,SVC32MODE,13,ADDRSUPERSTACK); /* and for supervisor mode */ | |
163 | ARMul_SetReg(state,ABORT32MODE,13,ADDRSUPERSTACK); /* and for abort 32 mode */ | |
164 | ARMul_SetReg(state,UNDEF32MODE,13,ADDRSUPERSTACK); /* and for undef 32 mode */ | |
165 | instr = 0xe59ff000 | (ADDRSOFTVECTORS - 8); /* load pc from soft vector */ | |
166 | for (i = ARMul_ResetV ; i <= ARMFIQV ; i += 4) | |
167 | ARMul_WriteWord(state, i, instr); /* write hardware vectors */ | |
168 | for (i = ARMul_ResetV ; i <= ARMFIQV + 4 ; i += 4) { | |
169 | ARMul_WriteWord(state, ADDRSOFTVECTORS + i, SOFTVECTORCODE + i * 4); | |
170 | ARMul_WriteWord(state, ADDRSOFHANDLERS + 2*i + 4L, SOFTVECTORCODE + sizeof(softvectorcode) - 4L); | |
171 | } | |
172 | for (i = 0 ; i < sizeof(softvectorcode) ; i += 4) | |
173 | ARMul_WriteWord(state, SOFTVECTORCODE + i, softvectorcode[i/4]); | |
174 | for (i = 0 ; i < FOPEN_MAX ; i++) | |
175 | OSptr->FileTable[i] = NULL ; | |
176 | for (i = 0 ; i < UNIQUETEMPS ; i++) | |
177 | OSptr->tempnames[i] = NULL ; | |
178 | ARMul_ConsolePrint (state, ", Demon 1.01"); | |
179 | ||
180 | /* #ifndef ASIM */ | |
181 | ||
182 | /* install fpe */ | |
183 | for (i = 0 ; i < fpesize ; i+=4) /* copy the code */ | |
184 | ARMul_WriteWord(state,FPESTART + i,fpecode[i >> 2]) ; | |
185 | for (i = FPESTART + fpesize ; ; i-=4) { /* reverse the error strings */ | |
186 | if ((j = ARMul_ReadWord(state,i)) == 0xffffffff) | |
187 | break ; | |
188 | if (state->bigendSig && j < 0x80000000) { /* it's part of the string so swap it */ | |
189 | j = ((j >> 0x18) & 0x000000ff) | | |
190 | ((j >> 0x08) & 0x0000ff00) | | |
191 | ((j << 0x08) & 0x00ff0000) | | |
192 | ((j << 0x18) & 0xff000000) ; | |
193 | ARMul_WriteWord(state,i,j) ; | |
194 | } | |
195 | } | |
196 | ARMul_WriteWord(state,FPEOLDVECT,ARMul_ReadWord(state,4)) ; /* copy old illegal instr vector */ | |
197 | ARMul_WriteWord(state,4,FPENEWVECT(ARMul_ReadWord(state,i-4))) ; /* install new vector */ | |
198 | ARMul_ConsolePrint (state, ", FPE") ; | |
199 | ||
200 | /* #endif /* ASIM */ | |
201 | #endif /* VALIDATE */ | |
202 | #endif /* NOOS */ | |
203 | ||
204 | return(TRUE) ; | |
205 | } | |
206 | ||
207 | void ARMul_OSExit(ARMul_State *state) | |
208 | { | |
209 | free((char *)state->OSptr) ; | |
210 | } | |
211 | ||
212 | ||
213 | /***************************************************************************\ | |
214 | * Return the last Operating System Error. * | |
215 | \***************************************************************************/ | |
216 | ||
217 | ARMword ARMul_OSLastErrorP(ARMul_State *state) | |
218 | { | |
219 | return ((struct OSblock *)state->OSptr)->ErrorP; | |
220 | } | |
221 | ||
222 | /***************************************************************************\ | |
223 | * The emulator calls this routine when a SWI instruction is encuntered. The * | |
224 | * parameter passed is the SWI number (lower 24 bits of the instruction). * | |
225 | \***************************************************************************/ | |
226 | ||
227 | #if 1 | |
228 | /* This is the cygnus way of doing it, which makes it simple | |
229 | to do our tests */ | |
230 | ||
231 | ||
232 | static int translate_open_mode[] = | |
233 | { | |
234 | O_RDONLY, /* "r" */ | |
235 | O_RDONLY+O_BINARY, /* "rb" */ | |
236 | O_RDWR, /* "r+" */ | |
237 | O_RDWR +O_BINARY, /* "r+b" */ | |
238 | O_WRONLY +O_CREAT+O_TRUNC, /* "w" */ | |
239 | O_WRONLY+O_BINARY+O_CREAT+O_TRUNC, /* "wb" */ | |
240 | O_RDWR +O_CREAT+O_TRUNC, /* "w+" */ | |
241 | O_RDWR +O_BINARY+O_CREAT+O_TRUNC, /* "w+b" */ | |
242 | O_WRONLY +O_APPEND+O_CREAT,/* "a" */ | |
243 | O_WRONLY+O_BINARY+O_APPEND+O_CREAT,/* "ab" */ | |
244 | O_RDWR +O_APPEND+O_CREAT,/* "a+" */ | |
245 | O_RDWR +O_BINARY+O_APPEND+O_CREAT /* "a+b" */ | |
246 | }; | |
247 | ||
248 | unsigned ARMul_OSHandleSWI(ARMul_State *state,ARMword number) | |
249 | { | |
250 | ARMword addr, temp, fildes ; | |
251 | char buffer[BUFFERSIZE], *cptr ; | |
252 | FILE *fptr ; | |
253 | struct OSblock* OSptr = (struct OSblock*)state->OSptr ; | |
254 | ||
255 | switch (number) | |
256 | { | |
257 | case SWI_Read: | |
258 | { | |
259 | int f = state->Reg[0]; | |
260 | int ptr = state->Reg[1]; | |
261 | int len = state->Reg[2]; | |
262 | int res; | |
263 | int i; | |
264 | char *local = malloc (len); | |
265 | res = read (f,local, len); | |
266 | if (res > 0) | |
267 | for (i = 0; i < res; i++) | |
268 | ARMul_WriteByte(state, ptr + i, local[i]) ; | |
269 | free (local); | |
270 | state->Reg[0] = res == -1 ? -1 : len - res; | |
271 | OSptr->ErrorNo = errno; | |
272 | return TRUE; | |
273 | } | |
274 | ||
275 | case SWI_Write: | |
276 | { | |
277 | int f = state->Reg[0]; | |
278 | int ptr = state->Reg[1]; | |
279 | int len = state->Reg[2]; | |
280 | int res; | |
281 | int i; | |
282 | char *local = malloc (len); | |
283 | ||
284 | for (i = 0; i < len; i++) | |
285 | { | |
286 | local[i] = ARMul_ReadByte(state, ptr + i); | |
287 | } | |
288 | res = write (f, local, len); | |
289 | state->Reg[0] = res == -1 ? -1 : len - res; | |
290 | free (local); | |
291 | OSptr->ErrorNo = errno; | |
292 | return TRUE; | |
293 | } | |
294 | ||
295 | case SWI_Open: | |
296 | { | |
297 | char dummy[2000]; | |
298 | int i; | |
e3ace30a NC |
299 | int flags; |
300 | ||
7d449b44 JM |
301 | for (i = 0; |
302 | dummy[i] = ARMul_ReadByte(state, state->Reg[0] + i); | |
303 | i++) | |
304 | ; | |
305 | ||
306 | /* Now we need to decode the Demon open mode */ | |
307 | flags = translate_open_mode[state->Reg[1]]; | |
308 | ||
309 | /* Filename ":tt" is special: it denotes stdin/out */ | |
310 | if (strcmp (dummy, ":tt") == 0) | |
311 | { | |
312 | if (flags == O_RDONLY) /* opening tty "r" */ | |
313 | state->Reg[0] = 0 /* stdin */ ; | |
314 | else | |
315 | state->Reg[0] = 1 /* stdout */ ; | |
316 | } | |
317 | else | |
318 | { | |
319 | state->Reg[0] = (int) open (dummy, flags); | |
320 | OSptr->ErrorNo = errno; | |
321 | } | |
322 | ||
323 | return TRUE; | |
324 | } | |
325 | ||
326 | case SWI_Clock : | |
327 | /* return number of centi-seconds... */ | |
328 | state->Reg[0] = | |
329 | #ifdef CLOCKS_PER_SEC | |
330 | (CLOCKS_PER_SEC >= 100) | |
331 | ? (ARMword) (clock() / (CLOCKS_PER_SEC / 100)) | |
332 | : (ARMword) ((clock() * 100) / CLOCKS_PER_SEC) ; | |
333 | #else | |
334 | /* presume unix... clock() returns microseconds */ | |
335 | (ARMword) (clock() / 10000) ; | |
336 | #endif | |
337 | OSptr->ErrorNo = errno ; | |
338 | return(TRUE) ; | |
339 | ||
340 | case SWI_Time : | |
341 | state->Reg[0] = (ARMword)time(NULL) ; | |
342 | OSptr->ErrorNo = errno ; | |
343 | return(TRUE) ; | |
344 | ||
345 | case SWI_Close: | |
346 | state->Reg[0] = close (state->Reg[0]); | |
347 | OSptr->ErrorNo = errno; | |
348 | return TRUE; | |
349 | ||
350 | case SWI_Flen : | |
351 | if (state->Reg[0] == 0 || state->Reg[0] > FOPEN_MAX) | |
352 | { | |
353 | OSptr->ErrorNo = EBADF ; | |
354 | state->Reg[0] = -1L ; | |
355 | return(TRUE) ; | |
356 | } | |
357 | fildes = state->Reg[0]; | |
358 | addr = lseek(fildes, 0, SEEK_CUR); | |
359 | if (addr < 0) | |
360 | state->Reg[0] = -1L ; | |
361 | else | |
362 | { | |
363 | state->Reg[0] = lseek(fildes, 0L, SEEK_END); | |
364 | (void)lseek(fildes, addr, SEEK_SET); | |
365 | } | |
366 | OSptr->ErrorNo = errno ; | |
367 | return(TRUE) ; | |
368 | ||
369 | ||
370 | case SWI_Exit: | |
371 | state->Emulate = FALSE ; | |
372 | return TRUE; | |
373 | ||
374 | case SWI_Seek: | |
375 | { | |
376 | /* We must return non-zero for failure */ | |
377 | state->Reg[0] = -1 >= lseek (state->Reg[0], | |
378 | state->Reg[1], | |
379 | SEEK_SET); | |
380 | OSptr->ErrorNo = errno; | |
381 | return TRUE; | |
382 | } | |
383 | ||
384 | case SWI_WriteC : | |
385 | (void)fputc((int)state->Reg[0],stderr) ; | |
386 | OSptr->ErrorNo = errno ; | |
387 | return(TRUE) ; | |
388 | ||
389 | case SWI_Write0 : | |
390 | addr = state->Reg[0] ; | |
391 | while ((temp = ARMul_ReadByte(state,addr++)) != 0) | |
392 | (void)fputc((char)temp,stderr) ; | |
393 | OSptr->ErrorNo = errno ; | |
394 | return(TRUE) ; | |
395 | ||
396 | case SWI_GetErrno : | |
397 | state->Reg[0] = OSptr->ErrorNo ; | |
398 | return(TRUE) ; | |
399 | ||
400 | case SWI_Breakpoint : | |
401 | state->EndCondition = RDIError_BreakpointReached ; | |
402 | state->Emulate = FALSE ; | |
403 | return(TRUE) ; | |
404 | ||
405 | case SWI_GetEnv : | |
406 | state->Reg[0] = ADDRCMDLINE ; | |
407 | if (state->MemSize) | |
408 | state->Reg[1] = state->MemSize ; | |
409 | else | |
410 | state->Reg[1] = ADDRUSERSTACK ; | |
411 | ||
412 | addr = state->Reg[0] ; | |
413 | cptr = state->CommandLine ; | |
414 | if (cptr == NULL) | |
415 | cptr = "\0" ; | |
416 | do { | |
417 | temp = (ARMword)*cptr++ ; | |
418 | ARMul_WriteByte(state,addr++,temp) ; | |
419 | } while (temp != 0) ; | |
420 | return(TRUE) ; | |
421 | ||
e3ace30a NC |
422 | case AngelSWI_ARM: |
423 | case AngelSWI_Thumb: | |
424 | /* Ignore these SWIs (for now). */ | |
425 | return TRUE; | |
426 | ||
7d449b44 JM |
427 | default : |
428 | state->Emulate = FALSE ; | |
429 | return(FALSE) ; | |
430 | } | |
431 | } | |
432 | #else | |
433 | unsigned ARMul_OSHandleSWI(ARMul_State *state,ARMword number) | |
434 | { | |
435 | #ifdef NOOS | |
436 | return(FALSE) ; | |
437 | #else | |
438 | #ifdef VALIDATE | |
439 | switch (number) { | |
440 | case 0x11 : | |
441 | state->Emulate = FALSE ; | |
442 | return(TRUE) ; | |
443 | case 0x01 : | |
444 | if (ARM32BITMODE) | |
445 | ARMul_SetCPSR(state, (ARMul_GetCPSR(state) & 0xffffffc0) | 0x13) ; | |
446 | else | |
447 | ARMul_SetCPSR(state, (ARMul_GetCPSR(state) & 0xffffffc0) | 0x3) ; | |
448 | return(TRUE) ; | |
449 | default : | |
450 | return(FALSE) ; | |
451 | } | |
452 | #else | |
453 | ARMword addr, temp ; | |
454 | char buffer[BUFFERSIZE], *cptr ; | |
455 | FILE *fptr ; | |
456 | struct OSblock* OSptr = (struct OSblock*)state->OSptr ; | |
457 | ||
458 | switch (number) { | |
459 | case SWI_WriteC : | |
460 | (void)fputc((int)state->Reg[0],stderr) ; | |
461 | OSptr->ErrorNo = errno ; | |
462 | return(TRUE) ; | |
463 | ||
464 | case SWI_Write0 : | |
465 | addr = state->Reg[0] ; | |
466 | while ((temp = ARMul_ReadByte(state,addr++)) != 0) | |
467 | fputc((char)temp,stderr) ; | |
468 | OSptr->ErrorNo = errno ; | |
469 | return(TRUE) ; | |
470 | ||
471 | case SWI_ReadC : | |
472 | state->Reg[0] = (ARMword)fgetc(stdin) ; | |
473 | OSptr->ErrorNo = errno ; | |
474 | return(TRUE) ; | |
475 | ||
476 | case SWI_CLI : | |
477 | addr = state->Reg[0] ; | |
478 | getstring(state,state->Reg[0],buffer) ; | |
479 | state->Reg[0] = (ARMword)system(buffer) ; | |
480 | OSptr->ErrorNo = errno ; | |
481 | return(TRUE) ; | |
482 | ||
483 | case SWI_GetEnv : | |
484 | state->Reg[0] = ADDRCMDLINE ; | |
485 | if (state->MemSize) | |
486 | state->Reg[1] = state->MemSize ; | |
487 | else | |
488 | state->Reg[1] = ADDRUSERSTACK ; | |
489 | ||
490 | addr = state->Reg[0] ; | |
491 | cptr = state->CommandLine ; | |
492 | if (cptr == NULL) | |
493 | cptr = "\0" ; | |
494 | do { | |
495 | temp = (ARMword)*cptr++ ; | |
496 | ARMul_WriteByte(state,addr++,temp) ; | |
497 | } while (temp != 0) ; | |
498 | return(TRUE) ; | |
499 | ||
500 | case SWI_Exit : | |
501 | #ifdef ASIM | |
502 | simkernel1_abort_run() ; | |
503 | #else | |
504 | state->Emulate = FALSE ; | |
505 | #endif | |
506 | return(TRUE) ; | |
507 | ||
508 | case SWI_EnterOS : | |
509 | if (ARM32BITMODE) | |
510 | ARMul_SetCPSR(state, (ARMul_GetCPSR(state) & 0xffffffc0) | 0x13) ; | |
511 | else | |
512 | ARMul_SetCPSR(state, (ARMul_GetCPSR(state) & 0xffffffc0) | 0x3) ; | |
513 | return(TRUE) ; | |
514 | ||
515 | case SWI_GetErrno : | |
516 | state->Reg[0] = OSptr->ErrorNo ; | |
517 | return(TRUE) ; | |
518 | ||
519 | case SWI_Clock : | |
520 | /* return muber of centi-seconds... */ | |
521 | state->Reg[0] = | |
522 | #ifdef CLOCKS_PER_SEC | |
523 | (CLOCKS_PER_SEC >= 100) | |
524 | ? (ARMword) (clock() / (CLOCKS_PER_SEC / 100)) | |
525 | : (ARMword) ((clock() * 100) / CLOCKS_PER_SEC) ; | |
526 | #else | |
527 | /* presume unix... clock() returns microseconds */ | |
528 | (ARMword) (clock() / 10000) ; | |
529 | #endif | |
530 | OSptr->ErrorNo = errno ; | |
531 | return(TRUE) ; | |
532 | ||
533 | case SWI_Time : | |
534 | state->Reg[0] = (ARMword)time(NULL) ; | |
535 | OSptr->ErrorNo = errno ; | |
536 | return(TRUE) ; | |
537 | ||
538 | case SWI_Remove : | |
539 | getstring(state,state->Reg[0],buffer) ; | |
540 | state->Reg[0] = unlink(buffer) ; | |
541 | OSptr->ErrorNo = errno ; | |
542 | return(TRUE) ; | |
543 | ||
544 | case SWI_Rename : { | |
545 | char buffer2[BUFFERSIZE] ; | |
546 | ||
547 | getstring(state,state->Reg[0],buffer) ; | |
548 | getstring(state,state->Reg[1],buffer2) ; | |
549 | state->Reg[0] = rename(buffer,buffer2) ; | |
550 | OSptr->ErrorNo = errno ; | |
551 | return(TRUE) ; | |
552 | } | |
553 | ||
554 | case SWI_Open : { | |
555 | #if 0 | |
556 | /* It seems to me that these are in the wrong order | |
557 | sac@cygnus.com, so I've redone it to use the | |
558 | flags instead, with the functionality which was already | |
559 | there -- ahh, perhaps the TRUNC bit is in a different | |
560 | place on the original host ?*/ | |
561 | static char* fmode[] = {"r","rb","r+","r+b", | |
562 | "w","wb","w+","w+b", | |
563 | "a","ab","a+","a+b", | |
564 | "r","r","r","r"} /* last 4 are illegal */ ; | |
565 | #endif | |
566 | ||
567 | unsigned type ; | |
568 | ||
569 | type = (unsigned)(state->Reg[1] & 3L) ; | |
570 | getstring(state,state->Reg[0],buffer) ; | |
571 | if (strcmp(buffer,":tt")==0 && (type == O_RDONLY )) /* opening tty "r" */ | |
572 | fptr = stdin ; | |
573 | else if (strcmp(buffer,":tt")==0 && (type == O_WRONLY)) /* opening tty "w" */ | |
574 | fptr = stderr ; | |
575 | else | |
576 | { | |
577 | switch (type) | |
578 | { | |
579 | case O_RDONLY: | |
580 | fptr = fopen(buffer,"r") ; | |
581 | break; | |
582 | case O_WRONLY: | |
583 | fptr = fopen(buffer,"w") ; | |
584 | break; | |
585 | case O_RDWR: | |
586 | fptr = fopen(buffer,"rw") ; | |
587 | break; | |
588 | } | |
589 | } | |
590 | ||
591 | state->Reg[0] = 0 ; | |
592 | if (fptr != NULL) { | |
593 | for (temp = 0 ; temp < FOPEN_MAX ; temp++) | |
594 | if (OSptr->FileTable[temp] == NULL) { | |
595 | OSptr->FileTable[temp] = fptr ; | |
596 | OSptr->FileFlags[temp] = type & 1 ; /* preserve the binary bit */ | |
597 | state->Reg[0] = (ARMword)(temp + 1) ; | |
598 | break ; | |
599 | } | |
600 | if (state->Reg[0] == 0) | |
601 | OSptr->ErrorNo = EMFILE ; /* too many open files */ | |
602 | else | |
603 | OSptr->ErrorNo = errno ; | |
604 | } | |
605 | else | |
606 | OSptr->ErrorNo = errno ; | |
607 | return(TRUE) ; | |
608 | } | |
609 | ||
610 | case SWI_Close : | |
611 | temp = state->Reg[0] ; | |
612 | if (temp == 0 || temp > FOPEN_MAX || OSptr->FileTable[temp - 1] == 0) { | |
613 | OSptr->ErrorNo = EBADF ; | |
614 | state->Reg[0] = -1L ; | |
615 | return(TRUE) ; | |
616 | } | |
617 | temp-- ; | |
618 | fptr = OSptr->FileTable[temp] ; | |
619 | if (fptr == stdin || fptr == stderr) | |
620 | state->Reg[0] = 0 ; | |
621 | else | |
622 | state->Reg[0] = fclose(fptr) ; | |
623 | OSptr->FileTable[temp] = NULL ; | |
624 | OSptr->ErrorNo = errno ; | |
625 | return(TRUE) ; | |
626 | ||
627 | case SWI_Write : { | |
628 | unsigned size, upto, type ; | |
629 | char ch ; | |
630 | ||
631 | temp = state->Reg[0] ; | |
632 | if (temp == 0 || temp > FOPEN_MAX || OSptr->FileTable[temp - 1] == 0) { | |
633 | OSptr->ErrorNo = EBADF ; | |
634 | state->Reg[0] = -1L ; | |
635 | return(TRUE) ; | |
636 | } | |
637 | temp-- ; | |
638 | fptr = OSptr->FileTable[temp] ; | |
639 | type = OSptr->FileFlags[temp] ; | |
640 | addr = state->Reg[1] ; | |
641 | size = (unsigned)state->Reg[2] ; | |
642 | ||
643 | if (type & READOP) | |
644 | fseek(fptr,0L,SEEK_CUR) ; | |
645 | OSptr->FileFlags[temp] = (type & BINARY) | WRITEOP ; ; | |
646 | while (size > 0) { | |
647 | if (size >= BUFFERSIZE) | |
648 | upto = BUFFERSIZE ; | |
649 | else | |
650 | upto = size ; | |
651 | for (cptr = buffer ; (cptr - buffer) < upto ; cptr++) { | |
652 | ch = (char)ARMul_ReadByte(state,(ARMword)addr++) ; | |
653 | *cptr = FIXCRLF(type,ch) ; | |
654 | } | |
655 | temp = fwrite(buffer,1,upto,fptr) ; | |
656 | if (temp < upto) { | |
657 | state->Reg[0] = (ARMword)(size - temp) ; | |
658 | OSptr->ErrorNo = errno ; | |
659 | return(TRUE) ; | |
660 | } | |
661 | size -= upto ; | |
662 | } | |
663 | state->Reg[0] = 0 ; | |
664 | OSptr->ErrorNo = errno ; | |
665 | return(TRUE) ; | |
666 | } | |
667 | ||
668 | case SWI_Read : { | |
669 | unsigned size, upto, type ; | |
670 | char ch ; | |
671 | ||
672 | temp = state->Reg[0] ; | |
673 | if (temp == 0 || temp > FOPEN_MAX || OSptr->FileTable[temp - 1] == 0) { | |
674 | OSptr->ErrorNo = EBADF ; | |
675 | state->Reg[0] = -1L ; | |
676 | return(TRUE) ; | |
677 | } | |
678 | temp-- ; | |
679 | fptr = OSptr->FileTable[temp] ; | |
680 | addr = state->Reg[1] ; | |
681 | size = (unsigned)state->Reg[2] ; | |
682 | type = OSptr->FileFlags[temp] ; | |
683 | ||
684 | if (type & WRITEOP) | |
685 | fseek(fptr,0L,SEEK_CUR) ; | |
686 | OSptr->FileFlags[temp] = (type & BINARY) | READOP ; ; | |
687 | while (size > 0) { | |
688 | if (isatty_(fptr)) { | |
689 | upto = (size >= BUFFERSIZE)?BUFFERSIZE:size + 1 ; | |
690 | if (fgets(buffer, upto, fptr) != 0) | |
691 | temp = strlen(buffer) ; | |
692 | else | |
693 | temp = 0 ; | |
694 | upto-- ; /* 1 char used for terminating null */ | |
695 | } | |
696 | else { | |
697 | upto = (size>=BUFFERSIZE)?BUFFERSIZE:size ; | |
698 | temp = fread(buffer,1,upto,fptr) ; | |
699 | } | |
700 | for (cptr = buffer ; (cptr - buffer) < temp ; cptr++) { | |
701 | ch = *cptr ; | |
702 | ARMul_WriteByte(state,(ARMword)addr++,FIXCRLF(type,ch)) ; | |
703 | } | |
704 | if (temp < upto) { | |
705 | state->Reg[0] = (ARMword)(size - temp) ; | |
706 | OSptr->ErrorNo = errno ; | |
707 | return(TRUE) ; | |
708 | } | |
709 | size -= upto ; | |
710 | } | |
711 | state->Reg[0] = 0 ; | |
712 | OSptr->ErrorNo = errno ; | |
713 | return(TRUE) ; | |
714 | } | |
715 | ||
716 | case SWI_Seek : | |
717 | if (state->Reg[0] == 0 || state->Reg[0] > FOPEN_MAX | |
718 | || OSptr->FileTable[state->Reg[0] - 1] == 0) { | |
719 | OSptr->ErrorNo = EBADF ; | |
720 | state->Reg[0] = -1L ; | |
721 | return(TRUE) ; | |
722 | } | |
723 | fptr = OSptr->FileTable[state->Reg[0] - 1] ; | |
724 | state->Reg[0] = fseek(fptr,(long)state->Reg[1],SEEK_SET) ; | |
725 | OSptr->ErrorNo = errno ; | |
726 | return(TRUE) ; | |
727 | ||
728 | case SWI_Flen : | |
729 | if (state->Reg[0] == 0 || state->Reg[0] > FOPEN_MAX | |
730 | || OSptr->FileTable[state->Reg[0] - 1] == 0) { | |
731 | OSptr->ErrorNo = EBADF ; | |
732 | state->Reg[0] = -1L ; | |
733 | return(TRUE) ; | |
734 | } | |
735 | fptr = OSptr->FileTable[state->Reg[0] - 1] ; | |
736 | addr = (ARMword)ftell(fptr) ; | |
737 | if (fseek(fptr,0L,SEEK_END) < 0) | |
738 | state->Reg[0] = -1 ; | |
739 | else { | |
740 | state->Reg[0] = (ARMword)ftell(fptr) ; | |
741 | (void)fseek(fptr,addr,SEEK_SET) ; | |
742 | } | |
743 | OSptr->ErrorNo = errno ; | |
744 | return(TRUE) ; | |
745 | ||
746 | case SWI_IsTTY : | |
747 | if (state->Reg[0] == 0 || state->Reg[0] > FOPEN_MAX | |
748 | || OSptr->FileTable[state->Reg[0] - 1] == 0) { | |
749 | OSptr->ErrorNo = EBADF ; | |
750 | state->Reg[0] = -1L ; | |
751 | return(TRUE) ; | |
752 | } | |
753 | fptr = OSptr->FileTable[state->Reg[0] - 1] ; | |
754 | state->Reg[0] = isatty_(fptr) ; | |
755 | OSptr->ErrorNo = errno ; | |
756 | return(TRUE) ; | |
757 | ||
758 | case SWI_TmpNam :{ | |
759 | ARMword size ; | |
760 | ||
761 | addr = state->Reg[0] ; | |
762 | temp = state->Reg[1] & 0xff ; | |
763 | size = state->Reg[2] ; | |
764 | if (OSptr->tempnames[temp] == NULL) { | |
765 | if ((OSptr->tempnames[temp] = malloc(L_tmpnam)) == NULL) { | |
766 | state->Reg[0] = 0 ; | |
767 | return(TRUE) ; | |
768 | } | |
769 | (void)tmpnam(OSptr->tempnames[temp]) ; | |
770 | } | |
771 | cptr = OSptr->tempnames[temp] ; | |
772 | if (strlen(cptr) > state->Reg[2]) | |
773 | state->Reg[0] = 0 ; | |
774 | else | |
775 | do { | |
776 | ARMul_WriteByte(state,addr++,*cptr) ; | |
777 | } while (*cptr++ != 0) ; | |
778 | OSptr->ErrorNo = errno ; | |
779 | return(TRUE) ; | |
780 | } | |
781 | ||
782 | case SWI_InstallHandler: | |
783 | { ARMword handlerp = ADDRSOFHANDLERS + state->Reg[0] * 8; | |
784 | ARMword oldr1 = ARMul_ReadWord(state, handlerp), | |
785 | oldr2 = ARMul_ReadWord(state, handlerp + 4); | |
786 | ARMul_WriteWord(state, handlerp, state->Reg[1]); | |
787 | ARMul_WriteWord(state, handlerp + 4, state->Reg[2]); | |
788 | state->Reg[1] = oldr1; | |
789 | state->Reg[2] = oldr2; | |
790 | return(TRUE); | |
791 | } | |
792 | ||
793 | case SWI_GenerateError: | |
794 | ARMul_Abort(state, ARMSWIV) ; | |
795 | if (state->Emulate) | |
796 | ARMul_SetR15(state, ARMul_ReadWord(state, ADDRSOFTVECTORS + ARMErrorV)); | |
797 | return(TRUE); | |
798 | ||
799 | /* SWI's 0x9x unwind the state of the CPU after an abort of type x */ | |
800 | ||
801 | case 0x90: /* Branch through zero */ | |
802 | { ARMword oldpsr = ARMul_GetCPSR(state) ; | |
803 | ARMul_SetCPSR(state, (oldpsr & 0xffffffc0) | 0x13) ; | |
804 | ARMul_SetSPSR(state, SVC32MODE, oldpsr) ; | |
805 | state->Reg[14] = 0; | |
806 | goto TidyCommon; | |
807 | } | |
808 | ||
809 | case 0x98: /* Error */ | |
810 | { ARMword errorp = state->Reg[0], | |
811 | regp = state->Reg[1]; | |
812 | unsigned i; | |
813 | ARMword errorpsr = ARMul_ReadWord(state, regp + 16*4); | |
814 | for (i = 0; i < 15; i++) | |
815 | ARMul_SetReg(state,errorpsr,i,ARMul_ReadWord(state, regp + i*4L)) ; | |
816 | state->Reg[14] = ARMul_ReadWord(state, regp + 15*4L); | |
817 | state->Reg[10] = errorp; | |
818 | ARMul_SetSPSR(state,state->Mode,errorpsr) ; | |
819 | OSptr->ErrorP = errorp; | |
820 | goto TidyCommon; | |
821 | } | |
822 | ||
823 | case 0x94: /* Data abort */ | |
824 | { ARMword addr = state->Reg[14] - 8; | |
825 | ARMword cpsr = ARMul_GetCPSR(state) ; | |
826 | if (ARM26BITMODE) | |
827 | addr = addr & 0x3fffffc ; | |
828 | ARMul_SetCPSR(state,ARMul_GetSPSR(state,cpsr)) ; | |
829 | UnwindDataAbort(state, addr); | |
830 | if (addr >= FPESTART && addr < FPEEND) { /* in the FPE */ | |
831 | ARMword sp, spsr ; | |
832 | unsigned i ; | |
833 | ||
834 | sp = state->Reg[13] ; | |
835 | state->Reg[13] += 64 ; /* fix the aborting mode sp */ | |
836 | state->Reg[14] = ARMul_ReadWord(state,sp + 60) ; /* and its lr */ | |
837 | spsr = ARMul_GetSPSR(state,state->Mode) ; | |
838 | state->Mode = ARMul_SwitchMode(state, state->Mode, spsr); | |
839 | for (i = 0 ; i < 15 ; i++) { | |
840 | ARMul_SetReg(state,spsr,i,ARMul_ReadWord(state,sp)) ; | |
841 | sp += 4 ; | |
842 | } | |
843 | ARMul_SetCPSR(state,cpsr) ; | |
844 | state->Reg[14] = ARMul_ReadWord(state,sp) + 4 ; /* botch it */ | |
845 | ARMul_SetSPSR(state,state->Mode,spsr) ; | |
846 | } | |
847 | else | |
848 | ARMul_SetCPSR(state,cpsr) ; | |
849 | ||
850 | /* and fall through to correct r14 */ | |
851 | } | |
852 | case 0x95: /* Address Exception */ | |
853 | state->Reg[14] -= 4; | |
854 | case 0x91: /* Undefined instruction */ | |
855 | case 0x92: /* SWI */ | |
856 | case 0x93: /* Prefetch abort */ | |
857 | case 0x96: /* IRQ */ | |
858 | case 0x97: /* FIQ */ | |
859 | state->Reg[14] -= 4; | |
860 | TidyCommon: | |
861 | if (state->VectorCatch & (1 << (number - 0x90))) { | |
862 | ARMul_SetR15(state, state->Reg[14] + 8) ; /* the 8 is the pipelining the the RDI will undo */ | |
863 | ARMul_SetCPSR(state,ARMul_GetSPSR(state,ARMul_GetCPSR(state))) ; | |
864 | if (number == 0x90) | |
865 | state->EndCondition = 10 ; /* Branch through Zero Error */ | |
866 | else | |
867 | state->EndCondition = (unsigned)number - 0x8f; | |
868 | state->Emulate = FALSE ; | |
869 | } | |
870 | else { | |
871 | ARMword sp = state->Reg[13]; | |
872 | ARMul_WriteWord(state, sp - 4, state->Reg[14]); | |
873 | ARMul_WriteWord(state, sp - 8, state->Reg[12]); | |
874 | ARMul_WriteWord(state, sp - 12, state->Reg[11]); | |
875 | ARMul_WriteWord(state, sp - 16, state->Reg[10]); | |
876 | state->Reg[13] = sp - 16; | |
877 | state->Reg[11] = ADDRSOFHANDLERS + 8 * (number - 0x90); | |
878 | } | |
879 | return(TRUE); | |
880 | ||
881 | /* SWI's 0x8x pass an abort of type x to the debugger if a handler returns */ | |
882 | ||
883 | case 0x80: case 0x81: case 0x82: case 0x83: | |
884 | case 0x84: case 0x85: case 0x86: case 0x87: case 0x88: | |
885 | { ARMword sp = state->Reg[13]; | |
886 | state->Reg[10] = ARMul_ReadWord(state, sp); | |
887 | state->Reg[11] = ARMul_ReadWord(state, sp + 4); | |
888 | state->Reg[12] = ARMul_ReadWord(state, sp + 8); | |
889 | state->Reg[14] = ARMul_ReadWord(state, sp + 12); | |
890 | state->Reg[13] = sp + 16; | |
891 | ARMul_SetR15(state, state->Reg[14] + 8) ; /* the 8 is the pipelining the the RDI will undo */ | |
892 | ARMul_SetCPSR(state,ARMul_GetSPSR(state,ARMul_GetCPSR(state))) ; | |
893 | if (number == 0x80) | |
894 | state->EndCondition = 10 ; /* Branch through Zero Error */ | |
895 | else | |
896 | state->EndCondition = (unsigned)number - 0x7f; | |
897 | state->Emulate = FALSE ; | |
898 | return(TRUE); | |
899 | } | |
900 | ||
901 | default : | |
902 | state->Emulate = FALSE ; | |
903 | return(FALSE) ; | |
904 | } | |
905 | #endif | |
906 | #endif | |
907 | } | |
908 | #endif | |
909 | ||
910 | #ifndef NOOS | |
911 | #ifndef ASIM | |
912 | ||
913 | /***************************************************************************\ | |
914 | * The emulator calls this routine when an Exception occurs. The second * | |
915 | * parameter is the address of the relevant exception vector. Returning * | |
916 | * FALSE from this routine causes the trap to be taken, TRUE causes it to * | |
917 | * be ignored (so set state->Emulate to FALSE!). * | |
918 | \***************************************************************************/ | |
919 | ||
920 | unsigned ARMul_OSException(ARMul_State *state, ARMword vector, ARMword pc) | |
921 | { /* don't use this here */ | |
922 | return(FALSE) ; | |
923 | } | |
924 | ||
925 | #endif | |
926 | ||
927 | /***************************************************************************\ | |
928 | * Unwind a data abort * | |
929 | \***************************************************************************/ | |
930 | ||
931 | static void UnwindDataAbort(ARMul_State *state, ARMword addr) | |
932 | { | |
933 | ARMword instr = ARMul_ReadWord(state, addr); | |
934 | ARMword rn = BITS(16, 19); | |
935 | ARMword itype = BITS(24, 27); | |
936 | ARMword offset; | |
937 | if (rn == 15) return; | |
938 | if (itype == 8 || itype == 9) { | |
939 | /* LDM or STM */ | |
940 | unsigned long regs = BITS(0, 15); | |
941 | offset = 0; | |
942 | if (!BIT(21)) return; /* no wb */ | |
943 | for (; regs != 0; offset++) | |
944 | regs ^= (regs & -regs); | |
945 | if (offset == 0) offset = 16; | |
946 | } else if (itype == 12 || /* post-indexed CPDT */ | |
947 | (itype == 13 && BIT(21))) { /* pre_indexed CPDT with WB */ | |
948 | offset = BITS(0, 7); | |
949 | } else | |
950 | return; | |
951 | ||
952 | if (BIT(23)) | |
953 | state->Reg[rn] -= offset * 4; | |
954 | else | |
955 | state->Reg[rn] += offset * 4; | |
956 | } | |
957 | ||
958 | /***************************************************************************\ | |
959 | * Copy a string from the debuggee's memory to the host's * | |
960 | \***************************************************************************/ | |
961 | ||
962 | static void getstring(ARMul_State *state, ARMword from, char *to) | |
963 | {do { | |
964 | *to = (char)ARMul_ReadByte(state,from++) ; | |
965 | } while (*to++ != '\0') ; | |
966 | } | |
967 | ||
968 | #endif /* NOOS */ |