1 /* syscalls.c --- implement system calls for the RX simulator. 2 3 Copyright (C) 2005, 2007, 2008, 2009, 2010, 2011 4 Free Software Foundation, Inc. 5 Contributed by Red Hat, Inc. 6 7 This file is part of the GNU simulators. 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 3 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 21 22 23 #include "config.h" 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <fcntl.h> 27 #include <unistd.h> 28 #include <sys/time.h> 29 30 #include "gdb/callback.h" 31 32 #include "cpu.h" 33 #include "mem.h" 34 #include "syscalls.h" 35 36 #include "syscall.h" 37 38 /* The current syscall callbacks we're using. */ 39 static struct host_callback_struct *callbacks; 40 41 void 42 set_callbacks (struct host_callback_struct *cb) 43 { 44 callbacks = cb; 45 } 46 47 48 /* Arguments 1..4 are in R1..R4, remainder on stack. 49 50 Return value in R1..R4 as needed. 51 structs bigger than 16 bytes: pointer pushed on stack last 52 53 We only support arguments that fit in general registers. 54 55 The system call number is in R5. We expect ssycalls to look like 56 this in libgloss: 57 58 _exit: 59 mov #SYS_exit, r5 60 int #255 61 rts 62 */ 63 64 int argp, stackp; 65 66 static int 67 arg () 68 { 69 int rv = 0; 70 argp++; 71 72 if (argp < 4) 73 return get_reg (argp); 74 75 rv = mem_get_si (get_reg (sp) + stackp); 76 stackp += 4; 77 return rv; 78 } 79 80 static void 81 read_target (char *buffer, int address, int count, int asciiz) 82 { 83 char byte; 84 while (count > 0) 85 { 86 byte = mem_get_qi (address++); 87 *buffer++ = byte; 88 if (asciiz && (byte == 0)) 89 return; 90 count--; 91 } 92 } 93 94 static void 95 write_target (char *buffer, int address, int count, int asciiz) 96 { 97 char byte; 98 while (count > 0) 99 { 100 byte = *buffer++; 101 mem_put_qi (address++, byte); 102 if (asciiz && (byte == 0)) 103 return; 104 count--; 105 } 106 } 107 108 #define PTRSZ (A16 ? 2 : 3) 109 110 static char *callnames[] = { 111 "SYS_zero", 112 "SYS_exit", 113 "SYS_open", 114 "SYS_close", 115 "SYS_read", 116 "SYS_write", 117 "SYS_lseek", 118 "SYS_unlink", 119 "SYS_getpid", 120 "SYS_kill", 121 "SYS_fstat", 122 "SYS_sbrk", 123 "SYS_argvlen", 124 "SYS_argv", 125 "SYS_chdir", 126 "SYS_stat", 127 "SYS_chmod", 128 "SYS_utime", 129 "SYS_time", 130 "SYS_gettimeofday", 131 "SYS_times", 132 "SYS_link" 133 }; 134 135 int 136 rx_syscall (int id) 137 { 138 static char buf[256]; 139 int rv; 140 141 argp = 0; 142 stackp = 4; 143 if (trace) 144 printf ("\033[31m/* SYSCALL(%d) = %s */\033[0m\n", id, id <= SYS_link ? callnames[id] : "unknown"); 145 switch (id) 146 { 147 case SYS_exit: 148 { 149 int ec = arg (); 150 if (verbose) 151 printf ("[exit %d]\n", ec); 152 return RX_MAKE_EXITED (ec); 153 } 154 break; 155 156 case SYS_open: 157 { 158 int path = arg (); 159 /* The open function is defined as taking a variable number of arguments 160 because the third parameter to it is optional: 161 open (const char * filename, int flags, ...); 162 Hence the oflags and cflags arguments will be on the stack and we need 163 to skip the (empty) argument registers r3 and r4. */ 164 argp = 4; 165 int oflags = arg (); 166 int cflags = arg (); 167 168 read_target (buf, path, 256, 1); 169 if (trace) 170 printf ("open(\"%s\",0x%x,%#o) = ", buf, oflags, cflags); 171 172 if (callbacks) 173 /* The callback vector ignores CFLAGS. */ 174 rv = callbacks->open (callbacks, buf, oflags); 175 else 176 { 177 int h_oflags = 0; 178 179 if (oflags & 0x0001) 180 h_oflags |= O_WRONLY; 181 if (oflags & 0x0002) 182 h_oflags |= O_RDWR; 183 if (oflags & 0x0200) 184 h_oflags |= O_CREAT; 185 if (oflags & 0x0008) 186 h_oflags |= O_APPEND; 187 if (oflags & 0x0400) 188 h_oflags |= O_TRUNC; 189 rv = open (buf, h_oflags, cflags); 190 } 191 if (trace) 192 printf ("%d\n", rv); 193 put_reg (1, rv); 194 } 195 break; 196 197 case SYS_close: 198 { 199 int fd = arg (); 200 201 if (callbacks) 202 rv = callbacks->close (callbacks, fd); 203 else if (fd > 2) 204 rv = close (fd); 205 else 206 rv = 0; 207 if (trace) 208 printf ("close(%d) = %d\n", fd, rv); 209 put_reg (1, rv); 210 } 211 break; 212 213 case SYS_read: 214 { 215 int fd = arg (); 216 int addr = arg (); 217 int count = arg (); 218 219 if (count > sizeof (buf)) 220 count = sizeof (buf); 221 if (callbacks) 222 rv = callbacks->read (callbacks, fd, buf, count); 223 else 224 rv = read (fd, buf, count); 225 if (trace) 226 printf ("read(%d,%d) = %d\n", fd, count, rv); 227 if (rv > 0) 228 write_target (buf, addr, rv, 0); 229 put_reg (1, rv); 230 } 231 break; 232 233 case SYS_write: 234 { 235 int fd = arg (); 236 int addr = arg (); 237 int count = arg (); 238 239 if (count > sizeof (buf)) 240 count = sizeof (buf); 241 if (trace) 242 printf ("write(%d,0x%x,%d)\n", fd, addr, count); 243 read_target (buf, addr, count, 0); 244 if (trace) 245 fflush (stdout); 246 if (callbacks) 247 rv = callbacks->write (callbacks, fd, buf, count); 248 else 249 rv = write (fd, buf, count); 250 if (trace) 251 printf ("write(%d,%d) = %d\n", fd, count, rv); 252 put_reg (1, rv); 253 } 254 break; 255 256 case SYS_getpid: 257 put_reg (1, 42); 258 break; 259 260 case SYS_gettimeofday: 261 { 262 int tvaddr = arg (); 263 struct timeval tv; 264 265 rv = gettimeofday (&tv, 0); 266 if (trace) 267 printf ("gettimeofday: %ld sec %ld usec to 0x%x\n", tv.tv_sec, 268 tv.tv_usec, tvaddr); 269 mem_put_si (tvaddr, tv.tv_sec); 270 mem_put_si (tvaddr + 4, tv.tv_usec); 271 put_reg (1, rv); 272 } 273 break; 274 275 case SYS_kill: 276 { 277 int pid = arg (); 278 int sig = arg (); 279 if (pid == 42) 280 { 281 if (verbose) 282 printf ("[signal %d]\n", sig); 283 return RX_MAKE_STOPPED (sig); 284 } 285 } 286 break; 287 288 case 11: 289 { 290 int heaptop_arg = arg (); 291 if (trace) 292 printf ("sbrk: heap top set to %x\n", heaptop_arg); 293 heaptop = heaptop_arg; 294 if (heapbottom == 0) 295 heapbottom = heaptop_arg; 296 } 297 break; 298 299 case 255: 300 { 301 int addr = arg (); 302 mem_put_si (addr, rx_cycles + mem_usage_cycles()); 303 } 304 break; 305 306 } 307 return RX_MAKE_STEPPED (); 308 } 309