nkeynes@102: /** nkeynes@561: * $Id$ nkeynes@102: * nkeynes@102: * DC-load syscall implementation. nkeynes@102: * nkeynes@102: * Copyright (c) 2005 Nathan Keynes. nkeynes@102: * nkeynes@102: * This program is free software; you can redistribute it and/or modify nkeynes@102: * it under the terms of the GNU General Public License as published by nkeynes@102: * the Free Software Foundation; either version 2 of the License, or nkeynes@102: * (at your option) any later version. nkeynes@102: * nkeynes@102: * This program is distributed in the hope that it will be useful, nkeynes@102: * but WITHOUT ANY WARRANTY; without even the implied warranty of nkeynes@102: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nkeynes@102: * GNU General Public License for more details. nkeynes@102: */ nkeynes@102: nkeynes@102: #include nkeynes@422: #include nkeynes@422: #include nkeynes@422: nkeynes@102: #include "dream.h" nkeynes@422: #include "mem.h" nkeynes@182: #include "dreamcast.h" nkeynes@102: #include "syscall.h" nkeynes@564: #include "sh4/sh4.h" nkeynes@102: nkeynes@102: #define SYS_READ 0 nkeynes@102: #define SYS_WRITE 1 nkeynes@102: #define SYS_OPEN 2 nkeynes@102: #define SYS_CLOSE 3 nkeynes@102: #define SYS_CREAT 4 nkeynes@102: #define SYS_LINK 5 nkeynes@102: #define SYS_UNLINK 6 nkeynes@102: #define SYS_CHDIR 7 nkeynes@102: #define SYS_CHMOD 8 nkeynes@102: #define SYS_LSEEK 9 nkeynes@102: #define SYS_FSTAT 10 nkeynes@102: #define SYS_TIME 11 nkeynes@102: #define SYS_STAT 12 nkeynes@102: #define SYS_UTIME 13 nkeynes@102: #define SYS_ASSIGNWRKMEM 14 nkeynes@102: #define SYS_EXIT 15 nkeynes@102: #define SYS_OPENDIR 16 nkeynes@102: #define SYS_CLOSEDIR 17 nkeynes@102: #define SYS_READDIR 18 nkeynes@102: #define SYS_GETHOSTINFO 19 nkeynes@102: nkeynes@102: #define SYS_MAGIC 0xDEADBEEF nkeynes@102: #define SYS_MAGIC_ADDR 0x8c004004 nkeynes@102: #define SYSCALL_ADDR 0x8c004008 nkeynes@102: nkeynes@209: static gboolean dcload_allow_unsafe = FALSE; nkeynes@182: nkeynes@209: void dcload_set_allow_unsafe( gboolean allow ) nkeynes@182: { nkeynes@209: dcload_allow_unsafe = allow; nkeynes@209: } nkeynes@209: nkeynes@209: #define MAX_OPEN_FDS 16 nkeynes@209: /** nkeynes@209: * Mapping from emulator fd to real fd (so we can limit read/write nkeynes@209: * to only fds we've explicitly granted access to). nkeynes@209: */ nkeynes@209: int open_fds[MAX_OPEN_FDS]; nkeynes@209: nkeynes@209: int dcload_alloc_fd() nkeynes@209: { nkeynes@209: int i; nkeynes@209: for( i=0; i= MAX_OPEN_FDS || open_fds[fd] == -1 ) { nkeynes@736: sh4r.r[0] = -1; nkeynes@736: } else { nkeynes@736: sh4ptr_t buf = mem_get_region( sh4r.r[6] ); nkeynes@736: int length = sh4r.r[7]; nkeynes@736: sh4r.r[0] = read( open_fds[fd], buf, length ); nkeynes@736: } nkeynes@736: break; nkeynes@209: case SYS_WRITE: nkeynes@736: fd = sh4r.r[5]; nkeynes@736: if( fd < 0 || fd >= MAX_OPEN_FDS || open_fds[fd] == -1 ) { nkeynes@736: sh4r.r[0] = -1; nkeynes@736: } else { nkeynes@736: sh4ptr_t buf = mem_get_region( sh4r.r[6] ); nkeynes@736: int length = sh4r.r[7]; nkeynes@736: sh4r.r[0] = write( open_fds[fd], buf, length ); nkeynes@736: } nkeynes@736: break; nkeynes@209: case SYS_LSEEK: nkeynes@736: fd = sh4r.r[5]; nkeynes@736: if( fd < 0 || fd >= MAX_OPEN_FDS || open_fds[fd] == -1 ) { nkeynes@736: sh4r.r[0] = -1; nkeynes@736: } else { nkeynes@736: sh4r.r[0] = lseek( open_fds[fd], sh4r.r[6], sh4r.r[7] ); nkeynes@736: } nkeynes@736: break; nkeynes@209: nkeynes@736: /* Secure access only */ nkeynes@209: case SYS_OPEN: nkeynes@736: if( dcload_allow_unsafe ) { nkeynes@736: fd = dcload_alloc_fd(); nkeynes@736: if( fd == -1 ) { nkeynes@736: sh4r.r[0] = -1; nkeynes@736: } else { nkeynes@736: char *filename = (char *)mem_get_region( sh4r.r[5] ); nkeynes@736: int realfd = open( filename, sh4r.r[6] ); nkeynes@736: open_fds[fd] = realfd; nkeynes@736: sh4r.r[0] = realfd; nkeynes@736: } nkeynes@736: } else { nkeynes@736: ERROR( "Denying access to local filesystem" ); nkeynes@736: sh4r.r[0] = -1; nkeynes@736: } nkeynes@736: break; nkeynes@209: case SYS_CLOSE: nkeynes@736: if( dcload_allow_unsafe ) { nkeynes@736: fd = sh4r.r[5]; nkeynes@736: if( fd < 0 || fd >= MAX_OPEN_FDS || open_fds[fd] == -1 ) { nkeynes@736: sh4r.r[0] = -1; nkeynes@736: } else { nkeynes@736: if( open_fds[fd] > 2 ) { nkeynes@736: sh4r.r[0] = close( open_fds[fd] ); nkeynes@736: } else { nkeynes@736: /* Don't actually close real fds 0-2 */ nkeynes@736: sh4r.r[0] = 0; nkeynes@736: } nkeynes@736: open_fds[fd] = -1; nkeynes@736: } nkeynes@736: } nkeynes@736: break; nkeynes@102: case SYS_EXIT: nkeynes@736: if( dcload_allow_unsafe ) { nkeynes@736: dreamcast_shutdown(); nkeynes@736: exit( sh4r.r[5] ); nkeynes@736: } else { nkeynes@736: dreamcast_stop(); nkeynes@736: } nkeynes@102: default: nkeynes@736: sh4r.r[0] = -1; nkeynes@102: } nkeynes@102: nkeynes@102: } nkeynes@102: nkeynes@102: void dcload_install() nkeynes@102: { nkeynes@209: memset( &open_fds, -1, sizeof(open_fds) ); nkeynes@209: open_fds[0] = 0; nkeynes@209: open_fds[1] = 1; nkeynes@209: open_fds[2] = 2; nkeynes@102: syscall_add_hook_vector( 0xF0, SYSCALL_ADDR, dcload_syscall ); nkeynes@669: mem_write_long( SYS_MAGIC_ADDR, SYS_MAGIC ); nkeynes@102: }