syscall.c
18.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
/*
* Copyright (C) 1996-1998 by the Board of Trustees
* of Leland Stanford Junior University.
*
* This file is part of the SimOS distribution.
* See LICENSE file for terms of the license.
*
*/
/**************************************************************
* Syscall.c
*
* This file is used to emulate the system calls I want to
* provide reliably. Since Mipsy sometimes uses data handling,
* I'll need to do this so that the system calls can see
* coherent memory, which I provide by reading the caches
* appropriately. If the calls ran directly, as they do now,
* incorrect memory can easily be seen by these calls
*
* Author: $Author: blythe $
* Date: $Date: 2002/05/29 01:09:11 $
*
* **************************************************************
*/
#include <stdio.h>
#include "simtypes.h"
#include "mipsy.h"
#include "cpu.h"
#include "sim_error.h"
#include "cp0.h"
#include "fpu.h"
#include "eventcallback.h"
#include "pcache.h"
#include "cpu_stats.h"
#include "simstats.h"
#include "cpu_interface.h"
#include "malloc.h"
#include "sim_error.h"
#include "solo_interface.h"
#include <bstring.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <math.h>
#include <errno.h>
extern int errno;
/* Includes for syscalls we emulate */
#include <unistd.h>
#include "solo.h"
#include "solo_extras.h"
#include "sys.s"
#define PAGE_SIZE 4096
extern char *AppBrk;
extern uint soloLockBase;
/*
* ReadSyscallStringNolength
*
* This routine reads, a byte at a time, a null terminated ascii string
* used for input to a syscall. This read goes through Mipsy Caches. As
* such, it must issue a read and the go away if it misses.
*
* This routine should return 1 only when the string is completely intact in
* S->syscallBuf[which]. It should return 0 when the processor is stalling
* for memory it needs.
*
*/
static int
ReadSyscallStringNolength(int cpuNum, int which, int base)
{
int i;
byte data;
SoloState *S = &machineState[cpuNum];
if (S->syscallState[which] == -1) {
S->syscallState[which] = 0;
}
/* AllocateSyscallString(P, which, length); */
/* Allocate buffer area */
SIM_DEBUG(('o', "Reading ascii string starting at index %d for syscall #%d(%s)\n",
S->syscallState[which], S->syscallNum,
syscallName[S->syscallNum]));
/* Fill buffer coherently, bailing of if I miss */
for (i=S->syscallState[which];; i++) {
if (SoloReadByte(cpuNum, base+i, &data) != SUCCESS) {
/* syscall_op case will set up P's stall information */
SIM_DEBUG(('o', "Ascii string read stalling at addr %8.8x for syscall #%d(%s)\n",
base+i,S->syscallNum, syscallName[S->syscallNum]));
return 0;
} else {
if (i >= SYSCALL_BUF_SIZE) {
S->syscallBuf[which][SYSCALL_BUF_SIZE - 1] = 0;
CPUError("Syscall string parameter with length > SYSCALL_BUF_SIZE\n%s\n",
S->syscallBuf[which]);
}
S->syscallBuf[which][i] = data;
S->syscallState[which]=i+1;
if(data == 0)
break;
}
}
SIM_DEBUG(('o', "Ascii string read done for for syscall #%d(%s)\n",
S->syscallNum, syscallName[S->syscallNum]));
return 1;
}
/*
* ReadSyscallString
*
* This routine reads, a byte at a time, a string used for input to a
* syscall. This read goes through Mipsy Caches. As such, it must issue a
* read and the go away if it misses.
*
* This routine should return 1 only when the string is completely intact in
* S->syscallBuf[which]. It should return 0 when the processor is stalling
* for memory it needs.
*
*/
static int
ReadSyscallString(int cpuNum, int which, int base, int length)
{
int i;
byte data;
SoloState *S = &machineState[cpuNum];
if (length == 0) { /* If length is zero...I do nothing */
/* Currently using static allocation */
/* S->syscallBuf[which] = NULL; */
return 1;
}
if (S->syscallState[which] >= length) {
return 1; /* This buffer is all ready to go */
}
if (S->syscallState[0] == -1) { /* I suspect the [0] here is a bug */
S->syscallState[0] = 0;
}
/* AllocateSyscallString(P, which, length); */
/* Allocate buffer area */
SIM_DEBUG(('o', "Reading string starting at index %d(/%d) for syscall #%d(%s)\n",
S->syscallState[which], length, S->syscallNum,
syscallName[S->syscallNum]));
/* Fill buffer coherently, bailing of if I miss */
for (i=S->syscallState[which]; i<length; i++) {
if (SoloReadByte(cpuNum, base+i, &data) != SUCCESS) {
/* syscall_op case will set up P's stall information */
SIM_DEBUG(('o', "String read stalling at addr %8.8x for syscall #%d(%s)\n",
base+i,S->syscallNum, syscallName[S->syscallNum]));
return 0;
} else {
S->syscallBuf[which][i] = data;
S->syscallState[which]=i+1;
}
}
SIM_DEBUG(('o', "String read done for for syscall #%d(%s)\n",
S->syscallNum, syscallName[S->syscallNum]));
return 1;
}
/*
* WriteSyscallString
*
* This routine writes, a byte at a time, a string derived from output of a
* syscall. This write goes through Mipsy Caches. As such, it must issue a
* write and the go away if it misses.
*
* This routine should return 1 only when the string is completely written from
* S->syscallBuf[which]. It should return 0 when the processor is stalling
* for memory it needs.
*
*/
static int
WriteSyscallString(int cpuNum, int which, int base, int length)
{
int i;
SoloState *S = &machineState[cpuNum];
if (length == 0) { /* If length is zero...I do nothing */
return 1;
}
if (S->syscallState[which] >= length) {
return 1; /* This buffer is all ready to go */
}
SIM_DEBUG(('o', "Writing string starting at index %d(/%d) for syscall #%d(%s)\n",
S->syscallState[which], length, S->syscallNum,
syscallName[S->syscallNum]));
/* Fill buffer coherently, bailing of if I miss */
for (i=S->syscallState[which]; i<length; i++) {
if (SoloWriteByte(cpuNum, base+i, S->syscallBuf[which][i]) != SUCCESS) {
S->syscallState[which] = i;
/* Store partial progress indication */
/* syscall_op case will set up P's stall information */
SIM_DEBUG(('o', "String write stalling at addr %8.8x for syscall #%d(%s)\n",
base+i,S->syscallNum, syscallName[S->syscallNum]));
return 0;
}
}
SIM_DEBUG(('o', "String write done for for syscall #%d(%s)\n",
S->syscallNum, syscallName[S->syscallNum]));
return 1;
}
/*
* SoloEmulateSystemCall
*
* This routine emulates system calls, often over multiple steps. A call
* may come here multiple times before the syscall is ultimately
* satisfied.
*
* This routine must return 0 if the system call is not complete!
*
* Switch cases should break(!) to the end if they complete successfully for
* cleanup code to run.
*/
int
SoloEmulateSyscall(int cpuNum, int syscallNum)
{
long r4, r5, r6;
long err;
SoloState *S = &machineState[cpuNum];
CPUState *P = &(PE[cpuNum]);
if (!(((syscallNum+SYSVoffset) == SYS_pause) && (S->syscallState[0] != -1))) {
SIM_DEBUG(('o',"EmulateSyscall by cpu %d syscallNum %d (%s)\n", cpuNum,
syscallNum, syscallName[syscallNum]));
}
if (S->syscallNum != -1 &&
S->syscallNum != syscallNum) {
/*
* This is the BEGINNING of emulation of a new
* system call, not the continuation of an old
* one!! Initialize the state! I do this
* same work at the completion of a syscall,
* so if I see this it means something is
* wrong!
*/
CPUWarning("EmulateSyscall saw different syscallNum (new: %d, old %d\n",
syscallNum, S->syscallNum);
/* Clean up */
S->syscallState[0] = -1; /* Strings are uninitialized */
S->syscallState[1] = -1; /* Strings are uninitialized */
}
S->syscallNum = syscallNum;
/* WARNING: Do not return 1 inside this switch. Use "break" instead */
switch (syscallNum+SYSVoffset) {
/* Handled syscalls */
case SYS_exit:
CPUError("SoloMipsy should handle exit() (SYS_exit) in CPURun!\n");
break;
case SYS_brk:
{
int fd;
void *ret;
unsigned long incr;
SIM_DEBUG(('o', "Mipsy caught brk()...pP->R[4] = 0x%8.8x\n",P->R[4]));
if ((char *) P->R[4] > AppBrk) {
/* Will need more heap..grab 1MB more,
or how much the application requested,
whichever is more */
if ( ((unsigned long) P->R[4] - (unsigned long) AppBrk) > 0x100000) {
incr = ((unsigned long) P->R[4] - (unsigned long) AppBrk);
/* has to be page aligned */
incr = ((incr + PAGE_SIZE - 1)/PAGE_SIZE)*PAGE_SIZE;
} else {
incr = 0x100000;
}
#if 0
if ((uint) AppBrk+incr > soloLockBase) {
CPUError("Mipsy: application brk() would have encroached on lock space:\nCurrent heap top: %8.8x soloLockBase: %8.8x\n",
AppBrk, soloLockBase);
}
#endif
CPUPrint("Mipsy: Extending application heap region: %8.8x to %8.8x\n",
AppBrk, AppBrk + incr);
fd = open("/dev/zero", O_RDWR);
if (fd == -1) {
CPUError("brk emulation: /dev/zero open (for heap mmap) failed");
}
ret = (char *) mmap((void *) AppBrk, incr,
PROT_READ|PROT_WRITE,
MAP_SHARED|MAP_FIXED, fd, 0);
if (ret != (char *) (AppBrk)) {
perror("Mapping new heap region for application");
(void) close(fd);
return -1;
}
AppBrk += incr; /* incr more memory now available */
}
/* memory already ready from before, just return success */
P->R[7] = 0; /* Return success */
break;
}
case SYS_fxstat:
SIM_DEBUG(('o', "Emulating fxstat() system call\n"));
r4 = P->R[4];
r5 = P->R[5];
r6 = P->R[6];
if (S->syscallState[0] == -1) {
/* first time through */
S->syscallState[0] = 0;
/* the libc stub code looks at a3 to decide if the call succeeded or failed */
err = _fxstat(r4, r5, (struct stat *)S->syscallBuf[0]);
if(err < 0) {
P->R[7] = 1;
P->R[2] = errno;
break;
} else {
P->syscallStatus = 0;
P->syscallResult = err;
}
}
if (!WriteSyscallString(cpuNum, 0, r6, sizeof(struct stat))) {
return STALL;
} else {
P->R[7] = P->syscallStatus;
P->R[2] = P->syscallResult;
}
/* errno may not be supported correctly across threads */
/* Success */
break;
case SYS_open:
SIM_DEBUG(('o', "Emulating open() system call\n"));
r4 = P->R[4];
r5 = P->R[5];
r6 = P->R[6];
if (!ReadSyscallStringNolength(cpuNum, 0, r4)) {
return STALL;
}
err = open((const void *) S->syscallBuf[0], r5, r6);
/* the libc stub code looks at a3 to decide if the call succeeded or failed */
if(err < 0) {
P->R[7] = 1;
P->R[2] = errno;
} else {
P->R[7] = 0;
P->R[2] = err;
}
/* errno may not be supported correctly across threads */
/* Success */
break;
case SYS_close:
SIM_DEBUG(('o', "Emulating close() system call\n"));
r4 = P->R[4];
err = close(r4);
/* the libc stub code looks at a3 to decide if the call succeeded or failed */
if(err < 0) {
P->R[7] = 1;
P->R[2] = errno;
} else {
P->R[7] = 0;
P->R[2] = err;
}
break;
case SYS_read:
SIM_DEBUG(('o', "Emulating read() system call...WARNING: incompletely tested!\n"));
r4 = P->R[4];
r5 = P->R[5];
r6 = P->R[6];
if (r6 > SYSCALL_BUF_SIZE) {
CPUError("Detected read syscall length (%d) > SYSCALL_BUF_SIZE",
r6);
}
if (S->syscallState[0] == -1) {
/* first time through */
/* AllocateSyscallString(P, 0, r6); */
S->syscallState[0] = 0;
err = read(r4, (void *) S->syscallBuf[0], r6);
/* the libc stub code looks at a3 to decide if the call succeeded or failed */
if(err < 0) {
P->R[7] = 1;
P->R[2] = errno;
break;
} else {
P->syscallStatus = 0;
P->syscallResult = err;
}
}
if (!WriteSyscallString(cpuNum, 0, r5, P->syscallResult)) {
SIM_DEBUG(('o', "read() returning STALL\n"));
return STALL;
} else {
P->R[7] = P->syscallStatus;
P->R[2] = P->syscallResult;
}
/* errno may not be supported correctly across threads */
/* Success */
break;
case SYS_write:
SIM_DEBUG(('o', "Emulating write() system call\n"));
r4 = P->R[4];
r5 = P->R[5];
r6 = P->R[6];
if (r6 > SYSCALL_BUF_SIZE) {
CPUError("Detected write syscall length (%d) > SYSCALL_BUF_SIZE",
r6);
}
if (!ReadSyscallString(cpuNum, 0, r5, r6)) {
return STALL;
}
err = write(r4, (const void *) S->syscallBuf[0], r6);
/* the libc stub code looks at a3 to decide if the call succeeded or failed */
if(err < 0) {
P->R[7] = 1;
P->R[2] = errno;
} else {
P->R[7] = 0;
P->R[2] = err;
}
/* errno may not be supported correctly across threads */
/* Success */
break;
case SYS_prctl:
if (P->R[4] == PR_GETNSHARE) {
P->R[7] = 0; /* Allow Share Group queries */
} else {
CPUError("Encountered unsupported %d (prctl) function code #%d, exiting\n",
syscallNum, P->R[4]);
}
break; /* Success if here */
/* Passed MipsyHandleSyscall after some Prologue*/
/* Passed directly to MipsyHandleSyscall */
/* These functions areguments are clean and can be sent directly */
case SYS_syscall: /* I have NO IDEA what this does */
case SYS_ioctl:
case SYS_dup:
case SYS_pipe:
case SYS_setuid:
case SYS_getuid:
case SYS_getpid:
case SYS_kill:
case SYS_lseek:
/* WARNING: --- Watch ksigaction --- */
case SYS_ksigaction:
MipsyHandleSyscall(P);
break;
/* Intercept this call as a request to determine if you're on mipsy. The user
program can check the return value */
case SYS_sync:
P->R[REG_V0] = IN_MIPSY;
break;
/* Yet Another Syscall Hack -- this one stalls the CPU for a small, random
number of cycles. Register a2 provides a 'shift factor' which allows us
to model exponential backoff. */
case SYS_pause:
{
static uint stallTime[SIM_MAXCPUS];
uint shiftamount, mask;
if (S->syscallState[0] == -1) {
shiftamount = (P->R[4] > 24) ? 24 : P->R[4];
mask = (32 << shiftamount) - 1;
S->syscallState[0] = 0;
stallTime[cpuNum] = random() & mask;
CPUPrint("EmulateSyscall: SYS_pause cpu %d backs off for %d cycles (MAX %d)\n",
cpuNum, stallTime[cpuNum], mask);
}
if (stallTime[cpuNum] > 0) {
stallTime[cpuNum]--;
return STALL;
}
}
break;
/* Non-handled syscalls */
case SYS_fork:
case SYS_creat:
case SYS_link:
case SYS_unlink:
case SYS_execv:
case SYS_chdir:
case SYS_time:
case SYS_chmod:
case SYS_chown:
case SYS_mount:
case SYS_umount:
case SYS_stime:
case SYS_stat:
case SYS_ptrace:
case SYS_alarm:
case SYS_utime:
case SYS_access:
case SYS_nice:
case SYS_statfs:
case SYS_fstatfs:
case SYS_setpgrp:
case SYS_syssgi:
case SYS_times:
case SYS_profil:
case SYS_plock:
case SYS_setgid:
case SYS_getgid:
case SYS_msgsys:
case SYS_sysmips:
case SYS_acct:
case SYS_shmsys:
case SYS_semsys:
case SYS_uadmin:
case SYS_sysmp:
case SYS_utssys:
case SYS_execve:
case SYS_umask:
case SYS_chroot:
case SYS_fcntl:
case SYS_ulimit:
case SYS_rmdir:
case SYS_mkdir:
case SYS_getdents:
case SYS_sginap:
case SYS_sgikopt:
case SYS_sysfs:
case SYS_getmsg:
case SYS_putmsg:
case SYS_poll:
/* This system call is internal for mips signal handling code */
case SYS_sigreturn:
/* 4.3BSD-compatible socket/protocol system calls */
case SYS_accept:
case SYS_bind:
case SYS_connect:
case SYS_gethostid:
case SYS_getpeername:
case SYS_getsockname:
case SYS_getsockopt:
case SYS_listen:
case SYS_recv:
case SYS_recvfrom:
case SYS_recvmsg:
case SYS_select:
case SYS_send:
case SYS_sendmsg:
case SYS_sendto:
case SYS_sethostid:
case SYS_setsockopt:
case SYS_shutdown:
case SYS_socket:
case SYS_gethostname:
case SYS_sethostname:
case SYS_getdomainname:
case SYS_setdomainname:
/* other 4.3BSD system calls */
case SYS_truncate:
case SYS_ftruncate:
case SYS_rename:
case SYS_symlink:
case SYS_readlink:
case SYS_nfssvc:
case SYS_getfh:
case SYS_async_daemon:
case SYS_exportfs:
case SYS_setregid:
case SYS_setreuid:
case SYS_getitimer:
case SYS_setitimer:
case SYS_adjtime:
case SYS_BSD_getime:
/* Parallel processing system calls */
case SYS_sproc:
case SYS_procblk:
case SYS_sprocsp:
/* memory-mapped file calls */
case SYS_mmap:
case SYS_munmap:
case SYS_mprotect:
case SYS_msync:
case SYS_madvise:
case SYS_pagelock:
case SYS_getpagesize:
/* BSD quotactl syscall, used to be libattach */
case SYS_quotactl:
/* 4.3BSD set/getpgrp syscalls */
case SYS_BSDgetpgrp:
case SYS_BSDsetpgrp:
/* 4.3BSD vhangup, fsync, and fchdir */
case SYS_vhangup:
case SYS_fsync:
case SYS_fchdir:
/* 4.3BSD getrlimit/setrlimit syscalls */
case SYS_getrlimit:
case SYS_setrlimit:
/* mips cache syscalls */
case SYS_cacheflush:
case SYS_cachectl:
/* 4.3BSD fchown/fchmod syscalls */
case SYS_fchown:
case SYS_fchmod:
/* 4.3BSD socketpair syscall */
case SYS_socketpair:
/* SVR4.1 new syscalls */
case SYS_sysinfo:
case SYS_nuname:
case SYS_xstat:
case SYS_lxstat:
case SYS_xmknod:
/* Posix.1 signal calls */
case SYS_sigpending:
case SYS_sigprocmask:
case SYS_sigsuspend:
/* Posix.4 signal calls */
case SYS_sigpoll:
case SYS_swapctl:
case SYS_getcontext:
case SYS_setcontext:
case SYS_waitsys:
case SYS_sigstack:
case SYS_sigaltstack:
case SYS_sigsendset:
case SYS_statvfs:
case SYS_fstatvfs:
case SYS_getpmsg:
case SYS_putpmsg:
/* more SVR4.1 new syscall */
case SYS_lchown:
case SYS_priocntl:
/* Posix.4 signal calls */
case SYS_ksigqueue:
CPUError("Encountered unsupported system call #%d (%s), exiting\n",
syscallNum, syscallName[syscallNum]);
break;
default:
CPUError("Encountered invalid system call #%d (?? %s), exiting\n",
syscallNum, syscallName[syscallNum]);
break;
}
/* Clean up this syscall's internal state */
if (S->syscallState[0] != -1) {
S->syscallState[0]=-1;
}
if (S->syscallState[1] != -1) {
S->syscallState[1]=-1;
}
S->syscallNum = -1;
return 1; /* This instruction is now complete */
}