diff options
Diffstat (limited to 'sim/ppc/system.c')
-rw-r--r-- | sim/ppc/system.c | 387 |
1 files changed, 387 insertions, 0 deletions
diff --git a/sim/ppc/system.c b/sim/ppc/system.c new file mode 100644 index 0000000..ca62b27 --- /dev/null +++ b/sim/ppc/system.c @@ -0,0 +1,387 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef _SYSTEM_C_ +#define _SYSTEM_C_ + +#include <sys/types.h> +#include <sys/stat.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> +#include <sys/errno.h> +#include <sys/param.h> + +#if (NetBSD >= 199306) /* here NetBSD as that is what we're emulating */ +#include <sys/syscall.h> /* FIXME - should not be including this one */ +#include <sys/sysctl.h> +#endif + +#if (BSD < 199306) /* here BSD as just a bug */ +extern int errno; +#endif + +#include "cpu.h" +#include "idecode.h" +#include "system.h" + + +void +system_call(cpu *processor, + unsigned_word cia) +{ + switch (cpu_registers(processor)->gpr[0]) { + + + case 1/*SYS_exit*/: +#if (NetBSD >= 199306) && (SYS_exit != 1) +# error "SYS_exit" +#endif + { + int status = (int)cpu_registers(processor)->gpr[3]; + cpu_halt(processor, cia, was_exited, status); + break; + } + + + case 3/*SYS_read*/: +#if (NetBSD >= 199306) && (SYS_read != 3) +# error "SYS_read" +#endif + { + void *scratch_buffer; + int d = (int)cpu_registers(processor)->gpr[3]; + unsigned_word buf = cpu_registers(processor)->gpr[4]; + int nbytes = cpu_registers(processor)->gpr[5]; + int status; + int nr_moved; + + /* get a tempoary bufer */ + scratch_buffer = zalloc(cpu_registers(processor)->gpr[5]); + + /* check if buffer exists by reading it */ + nr_moved = vm_data_map_read_buffer(cpu_data_map(processor), + scratch_buffer, + buf, + nbytes, + raw_transfer); + if (nr_moved != nbytes) + error("system_call()read - check on buffer failed\n"); + + /* read */ + if (d == 0) { + status = fread (scratch_buffer, 1, nbytes, stdin); + if (status == 0 && ferror (stdin)) + status = -1; + } else { + status = read (d, scratch_buffer, nbytes); + } + + if (status == -1) { + cpu_registers(processor)->gpr[0] = errno; + break; + } else { + cpu_registers(processor)->gpr[0] = 0; + cpu_registers(processor)->gpr[3] = status; + + if (status > 0) { + nr_moved = vm_data_map_write_buffer(cpu_data_map(processor), + scratch_buffer, + buf, + status, + raw_transfer, + 0/*violate_ro*/); + + if (nr_moved != nbytes) + error("system_call()read - write to buffer failed\n"); + } + } + + zfree(scratch_buffer); + + break; + } + + + case 4/*SYS_write*/: +#if (NetBSD >= 199306) && (SYS_write != 4) +# error "SYS_write" +#endif + { + void *scratch_buffer; + int nr_moved; + int d = (int)cpu_registers(processor)->gpr[3]; + unsigned_word buf = cpu_registers(processor)->gpr[4]; + int nbytes = cpu_registers(processor)->gpr[5]; + int status; + + /* get a tempoary bufer */ + scratch_buffer = zalloc(cpu_registers(processor)->gpr[5]); + + /* copy in */ + nr_moved = vm_data_map_read_buffer(cpu_data_map(processor), + scratch_buffer, + buf, + nbytes, + raw_transfer); + if (nr_moved != nbytes) { + /* FIXME - should handle better */ + error("system_call()write copy failed (nr_moved=%d != nbytes=%d)\n", + nr_moved, nbytes); + } + + /* write */ + status = write(d, scratch_buffer, nbytes); + if (status == -1) { + cpu_registers(processor)->gpr[0] = errno; + break; + } + cpu_registers(processor)->gpr[0] = 0; + cpu_registers(processor)->gpr[3] = status; + + zfree(scratch_buffer); + + break; + } + + + case 17/*SYS_break*/: +#if (NetBSD >= 199306) && (SYS_break != 17) +# error "SYS_break" +#endif + { + unsigned_word new_sbrk = ALIGN_PAGE(cpu_registers(processor)->gpr[3]); + unsigned_word old_sbrk = core_data_upper_bound(cpu_core(processor)); + signed_word delta = new_sbrk - old_sbrk; + if (delta > 0) + core_add_data(cpu_core(processor), delta); + cpu_registers(processor)->gpr[0] = 0; + cpu_registers(processor)->gpr[3] = new_sbrk; + break; + } + + + case 20/*SYS_getpid*/: +#if (NetBSD >= 199306) && (SYS_getpid != 20) +# error "SYS_getpid" +#endif + { + cpu_registers(processor)->gpr[3] = (int)getpid(); + break; + } + + + case 37/*SYS_kill*/: +#if (NetBSD >= 199306) && (SYS_kill != 37) +# error "SYS_kill" +#endif + { + pid_t pid = cpu_registers(processor)->gpr[3]; + int sig = cpu_registers(processor)->gpr[4]; + TRACE(trace_tbd, ("SYS_kill - more to this than just a kill\n")); + cpu_halt(processor, cia, was_signalled, sig); + break; + } + + + case 48/*SYS_sigprocmask*/: +#if (NetBSD >= 199306) && (SYS_sigprocmask != 48) +# error "SYS_sigprocmask" +#endif + { + natural_word how = cpu_registers(processor)->gpr[3]; + unsigned_word set = cpu_registers(processor)->gpr[4]; + unsigned_word oset = cpu_registers(processor)->gpr[5]; + TRACE(trace_system, ("SYS_sigprocmask: how=%d, set=0x%x, oset=0x%x\n", + how, set, oset)); + cpu_registers(processor)->gpr[0] = 0; + cpu_registers(processor)->gpr[3] = 0; + cpu_registers(processor)->gpr[4] = set; + break; + } + + + case 54/*SYS_ioctl*/: +#if (NetBSD >= 199306) && (SYS_ioctl != 54) +# error "SYS_ioctl" +#endif + { + TRACE(trace_system, ("SYS_ioctl: d=%d, request=0x%x, argp=0x%x\n", + cpu_registers(processor)->gpr[3], cpu_registers(processor)->gpr[4], cpu_registers(processor)->gpr[5])); + cpu_registers(processor)->gpr[0] = 0; + cpu_registers(processor)->gpr[3] = 0; + break; + } + + + case 189/*SYS_fstat*/: +#if (NetBSD >= 199306) && (SYS_fstat != 189) +# error "SYS_fstat" +#endif + { + int fd = cpu_registers(processor)->gpr[3]; + unsigned_word stat_buf_addr = cpu_registers(processor)->gpr[4]; + struct stat buf; + int nr_moved; + int status; + + /* check buffer all there, by reading it */ + nr_moved = vm_data_map_read_buffer(cpu_data_map(processor), + &buf, + stat_buf_addr, + sizeof(buf), + raw_transfer); + if (nr_moved != sizeof(buf)) + error("system_call()fstat - check on buffer failed\n"); + + /* do the fstat call */ + status = fstat(fd, &buf); + if (status == -1) { + cpu_registers(processor)->gpr[0] = errno; + break; + } + cpu_registers(processor)->gpr[0] = 0; + cpu_registers(processor)->gpr[3] = 0; + + H2T(buf.st_dev); + H2T(buf.st_ino); + H2T(buf.st_mode); + H2T(buf.st_nlink); + H2T(buf.st_uid); + H2T(buf.st_gid); + H2T(buf.st_rdev); + H2T(buf.st_size); + H2T(buf.st_atime); + /* H2T(buf.st_spare1); */ + H2T(buf.st_mtime); + /* H2T(buf.st_spare2); */ + H2T(buf.st_ctime); + /* H2T(buf.st_spare3); */ + H2T(buf.st_blksize); + H2T(buf.st_blocks); +#if (NetBSD >= 199306) + H2T(buf.st_flags); + H2T(buf.st_gen); +#endif + + nr_moved = vm_data_map_write_buffer(cpu_data_map(processor), + &buf, + stat_buf_addr, + sizeof(buf), + raw_transfer, + 0/*violate_ro*/); + break; + } + + + case 202/*SYS___sysctl*/: +#if (NetBSD >= 199306) && (SYS___sysctl != 202) +# error "SYS__sysctl" +#endif + { + /* call the arguments by their real name */ + unsigned_word name = cpu_registers(processor)->gpr[3]; + natural_word namelen = cpu_registers(processor)->gpr[4]; + unsigned_word oldp = cpu_registers(processor)->gpr[5]; + unsigned_word oldlenp = cpu_registers(processor)->gpr[6]; + natural_word oldlen; + natural_word mib; + natural_word int_val; + + /* pluck out the management information base id */ + if (namelen < 1 + || sizeof(mib) != vm_data_map_read_buffer(cpu_data_map(processor), + &mib, + name, + sizeof(mib), + cooked_transfer)) + error("system_call()SYS___sysctl bad name[0]\n"); + name += sizeof(mib); + + /* see what to do with it ... */ + switch (mib) { + case 6/*CTL_HW*/: +#if (NetBSD >= 199306) && (CTL_HW != 6) +# error "CTL_HW" +#endif + if (namelen < 2 + || sizeof(mib) != vm_data_map_read_buffer(cpu_data_map(processor), + &mib, + name, + sizeof(mib), + cooked_transfer)) + error("system_call()SYS___sysctl - CTL_HW - bad name[1]\n"); + name += sizeof(mib); + switch (mib) { + case 7/*HW_PAGESIZE*/: +#if (NetBSD >= 199306) && (HW_PAGESIZE != 7) +# error "HW_PAGESIZE" +#endif + if (sizeof(oldlen) != vm_data_map_read_buffer(cpu_data_map(processor), + &oldlen, + oldlenp, + sizeof(oldlen), + cooked_transfer)) + error("system_call()sysctl - CTL_HW.HW_PAGESIZE - oldlen read\n"); + if (sizeof(natural_word) > oldlen) + error("system_call()sysctl - CTL_HW.HW_PAGESIZE - to small\n"); + int_val = 8192; + oldlen = sizeof(int_val); + if (sizeof(int_val) != vm_data_map_write_buffer(cpu_data_map(processor), + &int_val, + oldp, + sizeof(int_val), + cooked_transfer, + 0/*violate_ro*/)) + error("system_call()sysctl - CTL_HW.HW_PAGESIZE - int_val\n"); + if (sizeof(oldlen) != vm_data_map_write_buffer(cpu_data_map(processor), + &oldlen, + oldlenp, + sizeof(oldlen), + cooked_transfer, + 0/*violate_ro*/)) + error("system_call()sysctl - CTL_HW.HW_PAGESIZE - oldlen write\n"); + break; + default: + error("sysctl() CTL_HW.%d unknown\n", mib); + break; + } + break; + default: + error("sysctl() name[0]=%s unknown\n", (int)mib); + break; + } + cpu_registers(processor)->gpr[0] = 0; + cpu_registers(processor)->gpr[3] = 0; + break; + } + + + default: + error("system_call() unimplemented system call %d, cia=0x%x, arg[0]=0x%x, lr=0x%x\n", + cpu_registers(processor)->gpr[0], cia, cpu_registers(processor)->gpr[3], LR); + break; + + } +} + +#endif /* _SYSTEM_C_ */ |