📄 syscall.c
字号:
/* * 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: bosch $ * Date: $Date: 1998/02/10 00:33:37 $ * * ************************************************************** */#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 4096extern 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 intReadSyscallStringNolength(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 intReadSyscallString(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 intWriteSyscallString(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. */intSoloEmulateSyscall(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"));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -