📄 syscall.c
字号:
/* * syscall.c - proxy system call handler routines * * This file is an adaptation of the software in the SimpleScalar tool suite * originally written by Todd M. Austin for the Multiscalar Research Project * at the University of Wisconsin-Madison. * * The modifications were made by Naraig Manjikian at Queen's University, * Kingston, Ontario, Canada. * * The remainder of this header comment is unchanged from the original text. * *.......................................................................... * * Copyright (C) 1994, 1995, 1996, 1997 by Todd M. Austin * * This source file is distributed "as is" in the hope that it will be * useful. The tool set comes with no warranty, and no author or * distributor accepts any responsibility for the consequences of its * use. * * Everyone is granted permission to copy, modify and redistribute * this tool set under the following conditions: * * This source code is distributed for non-commercial use only. * Please contact the maintainer for restrictions applying to * commercial use. * * Permission is granted to anyone to make or distribute copies * of this source code, either as received or modified, in any * medium, provided that all copyright notices, permission and * nonwarranty notices are preserved, and that the distributor * grants the recipient permission for further redistribution as * permitted by this document. * * Permission is granted to distribute this file in compiled * or executable form under the same conditions that apply for * source code, provided that either: * * A. it is accompanied by the corresponding machine-readable * source code, * B. it is accompanied by a written offer, with no time limit, * to give anyone a machine-readable copy of the corresponding * source code in return for reimbursement of the cost of * distribution. This written offer must permit verbatim * duplication by anyone, or * C. it is distributed by someone who received only the * executable form, and is accompanied by a copy of the * written offer of source code that they received concurrently. * * In other words, you are welcome to use, share and improve this * source file. You are forbidden to forbid anyone else to use, share * and improve what you give them. * * INTERNET: dburger@cs.wisc.edu * US Mail: 1210 W. Dayton Street, Madison, WI 53706 * * $Id: syscall.c,v 1.5 1997/04/16 22:12:17 taustin Exp taustin $ * * $Log: syscall.c,v $ * Revision 1.5 1997/04/16 22:12:17 taustin * added Ultrix host support * * Revision 1.4 1997/03/11 01:37:37 taustin * updated copyright * long/int tweaks made for ALPHA target support * syscall structures are now more portable across platforms * various target supports added * * Revision 1.3 1996/12/27 15:56:09 taustin * updated comments * removed system prototypes * * Revision 1.1 1996/12/05 18:52:32 taustin * Initial revision * * */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <fcntl.h>#include <sys/types.h>#include <sys/param.h>#include <errno.h>#include <time.h>#include <sys/time.h>#include <sys/resource.h>#include <signal.h>#include <sys/file.h>#include <sys/stat.h>#include <sys/uio.h>#include <setjmp.h>#include <sys/times.h>#include <limits.h>#include <sys/ioctl.h>#if !defined(linux) && !defined(sparc) && !defined(hpux) && !defined(__hpux) && !defined(__CYGWIN32__) && !defined(ultrix)#include <sys/select.h>#endif#ifdef linux#include <bsd/sgtty.h>#endif /* linux */#ifdef __CYGWIN32__#include <sgtty.h>#endif /* __CYGWIN32__ */#if defined(sparc) && defined(__unix__)#if defined(__svr4__) || defined(__USLC__)#include <dirent.h>#else#include <sys/dir.h>#endif/* dorks */#undef NL0#undef NL1#undef CR0#undef CR1#undef CR2#undef CR3#undef TAB0#undef TAB1#undef TAB2#undef XTABS#undef BS0#undef BS1#undef FF0#undef FF1#undef ECHO#undef NOFLSH#undef TOSTOP#undef FLUSHO#undef PENDIN#endif#if defined(hpux) || defined(__hpux)#undef CR0#endif#ifdef __FreeBSD__#include <sys/ioctl_compat.h>#else#include <termio.h>#endif#if defined(hpux) || defined(__hpux)/* et tu, dorks! */#undef HUPCL#undef ECHO#undef B50#undef B75#undef B110#undef B134#undef B150#undef B200#undef B300#undef B600#undef B1200#undef B1800#undef B2400#undef B4800#undef B9600#undef B19200#undef B38400#undef NL0#undef NL1#undef CR0#undef CR1#undef CR2#undef CR3#undef TAB0#undef TAB1#undef BS0#undef BS1#undef FF0#undef FF1#undef EXTA#undef EXTB#undef B900#undef B3600#undef B7200#undef XTABS#include <sgtty.h>#include <utime.h>#endif#include "misc.h"#include "ss.h"#include "regs.h"#include "memory.h"#include "loader.h"#include "sim.h"#include "endian.h"#include "syscall.h"/* open(2) flags translation table for SimpleScalar target */struct { int ss_flag; int local_flag;} ss_flag_table[] = { /* target flag */ /* host flag */ { SS_O_RDONLY, O_RDONLY }, { SS_O_WRONLY, O_WRONLY }, { SS_O_RDWR, O_RDWR }, { SS_O_APPEND, O_APPEND }, { SS_O_CREAT, O_CREAT }, { SS_O_TRUNC, O_TRUNC }, { SS_O_EXCL, O_EXCL }, { SS_O_NONBLOCK, O_NONBLOCK }, { SS_O_NOCTTY, O_NOCTTY },#ifdef O_SYNC { SS_O_SYNC, O_SYNC },#endif};#define SS_NFLAGS (sizeof(ss_flag_table)/sizeof(ss_flag_table[0]))/*--------------------------------------------------------------------*//* the following are additions to support multiprocessing */typedef struct _synchqnode{ struct _synchqnode *next; int pid; enum {FREE, WAITING_FOR_LOCK, HOLDING_LOCK, BLOCKED_ON_BARRIER, BLOCKED_ON_SEMAPHORE} synch_state; int synch_var; /* which synch var for above state */} SynchQNode;/* amount by which to increase array sizes for synchronization variables */#define LOCK_INCREMENT 1024#define BARRIER_INCREMENT 64#define SEMAPHORE_INCREMENT 64/* a (reasonable?) upper bound on number of synch vars of each type */#define SANITY_LIMIT 65535/* each processor has a node that may appear in exactly _one_ queue associated with a synchronization variable */SynchQNode synchq[MAX_PROCS];/* There is a queue pointer for each lock, barrier, or semaphore, and each of these pointers is actually a pointer to the _tail_ item of the queue, and the 'next' field of the tail item points to the head item: |___| |___| |___|--------------------------+ |___| | |___| head V tail |___| +----+ +----+ +----+ |___| +->|next|->|next|->|next|--+ |___| | | | | | | | | |___| | +----+ +----+ +----+ | |___| |__________________________+ | | array of pointers (one array for each type of synch var) The array of pointers may grow in size as more synchronization variables of a particular type are needed by the user program.*/ static SynchQNode **locks;static int num_allocated_locks = 0;static int num_used_locks = 0;static SynchQNode **barriers;static int *barrier_counts;static int num_allocated_barriers = 0;static int num_used_barriers = 0;static SynchQNode **semaphores;static int *sema_counts;static int num_allocated_semaphores = 0;static int num_used_semaphores = 0;#define NEW_THREAD_STACK_BASE 0x6ffffff0 /* arbitrary choice */#define NEW_THREAD_STACK_SIZE (1 << 20) /* 1 Megabyte *//* the following array of flags is used in the main simulation loop */int active[MAX_PROCS];/* the following is made volatile because it is changed with a new process and it is the upper bound of a 'for' loop nested in the main sim loop */volatile int num_created_processes;static int num_terminated_processes = 0;/*--------------------------------------------------------------------*//* This function is called from ss_syscall() below when the user program executes the runtime library code for thread creation. The 'wrapper' function is also in the runtime library code, and is the function that is actually called when the new thread is created. The 'func_ptr' refers to the user program function that will then be called from the wrapper function in the runtime library. Upon return from the user function, the wrapper function will invoke the 'terminate thread' system call and thereby support the semantics of the return from the user function causing thread termination.*/static void CreateNewProcess (int pid, void (*func_ptr) (void), void (*wrapper) (void *)){ int new_pid; SS_ADDR_TYPE stack_top; new_pid = num_created_processes++; if (num_created_processes > MAX_PROCS) { panic ("too many processes; the limit is %d\n", MAX_PROCS); } /* determine new top of stack; this pointer will be passed on to register initialization */ stack_top = NEW_THREAD_STACK_BASE - (new_pid-1) * NEW_THREAD_STACK_SIZE; /* the entry point (PC value) for a new thread is the 'wrapper' function */ regs_init (new_pid, stack_top, (SS_ADDR_TYPE) wrapper); /* _after_ registers have been initialized, set register $a0 ($4) with the user-supplied function pointer; wrapper will call it */ regs_R[new_pid][4] = (SS_ADDR_TYPE) func_ptr; /* for synch queue node for this thread, set the pid and state fields */ synchq[new_pid].pid = new_pid; synchq[new_pid].synch_state = FREE; /* not waiting, holding, or blocked */ /* mark the new thread/process as active */ active[new_pid] = 1; /* because the thread is now marked as active, and the total number of created processes has been incremented, the main simulation loop will shortly execute the first instruction of the new thread */}/*--------------------------------------------------------------------*//* syscall proxy handler, architect registers and memory are assumed to be precise when this function is called, register and memory are updated with the results of the system call */voidss_syscall(mem_access_fn mem_fn, /* generic memory accessor */ SS_INST_TYPE inst, /* system call inst */ int pid) /* which processor */{ SS_WORD_TYPE syscode = regs_R[pid][2]; switch (syscode) { case SS_SYS_exit: { ++num_terminated_processes; active[pid] = 0; /* mark this one as inactive */ if (num_terminated_processes == num_created_processes) { /* exit jumps to the target set in main() */ longjmp(sim_exit_buf, /* exitcode + fudge */regs_R[pid][4]+1); } /* else we must wait until last process finishes (this one has been marked inactive, so when we return to the main simulation loop, no further instructions will be fetched for this process) */ } break;#if 0 case SS_SYS_fork: break;#endif #if 0 case SS_SYS_vfork: break;#endif case SS_SYS_read: { char *buf; /* allocate same-sized input buffer in host memory */ if (!(buf = (char *)calloc(/*nbytes*/regs_R[pid][6], sizeof(char)))) fatal("out of memory in SYS_read"); /* read data from file */ /*nread*/regs_R[pid][2] = read(/*fd*/regs_R[pid][4], buf, /*nbytes*/regs_R[pid][6]); /* check for error condition */ if (regs_R[pid][2] != -1) regs_R[pid][7] = 0; else { /* got an error, return details */ regs_R[pid][2] = errno; regs_R[pid][7] = 1; } /* copy results back into host memory */ mem_bcopy(mem_fn, Write, /*buf*/regs_R[pid][5], buf, /*nread*/regs_R[pid][2]); /* done with input buffer */ free(buf); } break; case SS_SYS_write: { char *buf; /* allocate same-sized output buffer in host memory */ if (!(buf = (char *)calloc(/*nbytes*/regs_R[pid][6], sizeof(char)))) fatal("out of memory in SYS_write"); /* copy inputs into host memory */ mem_bcopy(mem_fn, Read, /*buf*/regs_R[pid][5], buf, /*nbytes*/regs_R[pid][6]); /* write data to file */ /*nwritten*/regs_R[pid][2] = write(/*fd*/regs_R[pid][4], buf, /*nbytes*/regs_R[pid][6]); /* check for an error condition */ if (regs_R[pid][2] == regs_R[pid][6]) /*result*/regs_R[pid][7] = 0; else { /* got an error, return details */ regs_R[pid][2] = errno; regs_R[pid][7] = 1; } /* done with output buffer */ free(buf); } break; case SS_SYS_open: { char buf[MAXBUFSIZE]; unsigned int i; int ss_flags = regs_R[pid][5], local_flags = 0; /* translate open(2) flags */ for (i=0; i<SS_NFLAGS; i++) { if (ss_flags & ss_flag_table[i].ss_flag) { ss_flags &= ~ss_flag_table[i].ss_flag; local_flags |= ss_flag_table[i].local_flag; } } /* any target flags left? */ if (ss_flags != 0) fatal("syscall: open: cannot decode flags: 0x%08x", ss_flags); /* copy filename to host memory */ mem_strcpy(mem_fn, Read, /*fname*/regs_R[pid][4], buf); /* open the file */ /*fd*/regs_R[pid][2] = open(buf, local_flags, /*mode*/regs_R[pid][6]); /* check for an error condition */ if (regs_R[pid][2] != -1) regs_R[pid][7] = 0; else { /* got an error, return details */ regs_R[pid][2] = errno;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -