14e98e3e1Schristos /* syscalls.c --- implement system calls for the RX simulator. 24e98e3e1Schristos 3*1f4e7eb9Schristos Copyright (C) 2005-2024 Free Software Foundation, Inc. 44e98e3e1Schristos Contributed by Red Hat, Inc. 54e98e3e1Schristos 64e98e3e1Schristos This file is part of the GNU simulators. 74e98e3e1Schristos 84e98e3e1Schristos This program is free software; you can redistribute it and/or modify 94e98e3e1Schristos it under the terms of the GNU General Public License as published by 104e98e3e1Schristos the Free Software Foundation; either version 3 of the License, or 114e98e3e1Schristos (at your option) any later version. 124e98e3e1Schristos 134e98e3e1Schristos This program is distributed in the hope that it will be useful, 144e98e3e1Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of 154e98e3e1Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 164e98e3e1Schristos GNU General Public License for more details. 174e98e3e1Schristos 184e98e3e1Schristos You should have received a copy of the GNU General Public License 194e98e3e1Schristos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 204e98e3e1Schristos 214b169a6bSchristos /* This must come before any other includes. */ 224b169a6bSchristos #include "defs.h" 234e98e3e1Schristos 244e98e3e1Schristos #include <stdio.h> 254e98e3e1Schristos #include <stdlib.h> 264e98e3e1Schristos #include <fcntl.h> 274e98e3e1Schristos #include <unistd.h> 284e98e3e1Schristos #include <sys/time.h> 294e98e3e1Schristos 304b169a6bSchristos #include "sim/callback.h" 314e98e3e1Schristos 324e98e3e1Schristos #include "cpu.h" 334e98e3e1Schristos #include "mem.h" 344e98e3e1Schristos #include "syscalls.h" 354b169a6bSchristos #include "target-newlib-syscall.h" 364e98e3e1Schristos 374e98e3e1Schristos /* The current syscall callbacks we're using. */ 384e98e3e1Schristos static struct host_callback_struct *callbacks; 394e98e3e1Schristos 404e98e3e1Schristos void 414e98e3e1Schristos set_callbacks (struct host_callback_struct *cb) 424e98e3e1Schristos { 434e98e3e1Schristos callbacks = cb; 444e98e3e1Schristos } 454e98e3e1Schristos 46a2e2270fSchristos struct host_callback_struct * 47a2e2270fSchristos get_callbacks (void) 48a2e2270fSchristos { 49a2e2270fSchristos return callbacks; 50a2e2270fSchristos } 51a2e2270fSchristos 524e98e3e1Schristos 534e98e3e1Schristos /* Arguments 1..4 are in R1..R4, remainder on stack. 544e98e3e1Schristos 554e98e3e1Schristos Return value in R1..R4 as needed. 564e98e3e1Schristos structs bigger than 16 bytes: pointer pushed on stack last 574e98e3e1Schristos 584e98e3e1Schristos We only support arguments that fit in general registers. 594e98e3e1Schristos 604e98e3e1Schristos The system call number is in R5. We expect ssycalls to look like 614e98e3e1Schristos this in libgloss: 624e98e3e1Schristos 634e98e3e1Schristos _exit: 644e98e3e1Schristos mov #SYS_exit, r5 654e98e3e1Schristos int #255 664e98e3e1Schristos rts 674e98e3e1Schristos */ 684e98e3e1Schristos 694e98e3e1Schristos int argp, stackp; 704e98e3e1Schristos 714e98e3e1Schristos static int 724b169a6bSchristos arg (void) 734e98e3e1Schristos { 744e98e3e1Schristos int rv = 0; 754e98e3e1Schristos argp++; 764e98e3e1Schristos 774e98e3e1Schristos if (argp < 4) 784e98e3e1Schristos return get_reg (argp); 794e98e3e1Schristos 804e98e3e1Schristos rv = mem_get_si (get_reg (sp) + stackp); 814e98e3e1Schristos stackp += 4; 824e98e3e1Schristos return rv; 834e98e3e1Schristos } 844e98e3e1Schristos 854e98e3e1Schristos static void 864e98e3e1Schristos read_target (char *buffer, int address, int count, int asciiz) 874e98e3e1Schristos { 884e98e3e1Schristos char byte; 894e98e3e1Schristos while (count > 0) 904e98e3e1Schristos { 914e98e3e1Schristos byte = mem_get_qi (address++); 924e98e3e1Schristos *buffer++ = byte; 934e98e3e1Schristos if (asciiz && (byte == 0)) 944e98e3e1Schristos return; 954e98e3e1Schristos count--; 964e98e3e1Schristos } 974e98e3e1Schristos } 984e98e3e1Schristos 994e98e3e1Schristos static void 1004e98e3e1Schristos write_target (char *buffer, int address, int count, int asciiz) 1014e98e3e1Schristos { 1024e98e3e1Schristos char byte; 1034e98e3e1Schristos while (count > 0) 1044e98e3e1Schristos { 1054e98e3e1Schristos byte = *buffer++; 1064e98e3e1Schristos mem_put_qi (address++, byte); 1074e98e3e1Schristos if (asciiz && (byte == 0)) 1084e98e3e1Schristos return; 1094e98e3e1Schristos count--; 1104e98e3e1Schristos } 1114e98e3e1Schristos } 1124e98e3e1Schristos 1134e98e3e1Schristos #define PTRSZ (A16 ? 2 : 3) 1144e98e3e1Schristos 1154e98e3e1Schristos static char *callnames[] = { 1164e98e3e1Schristos "SYS_zero", 1174e98e3e1Schristos "SYS_exit", 1184e98e3e1Schristos "SYS_open", 1194e98e3e1Schristos "SYS_close", 1204e98e3e1Schristos "SYS_read", 1214e98e3e1Schristos "SYS_write", 1224e98e3e1Schristos "SYS_lseek", 1234e98e3e1Schristos "SYS_unlink", 1244e98e3e1Schristos "SYS_getpid", 1254e98e3e1Schristos "SYS_kill", 1264e98e3e1Schristos "SYS_fstat", 1274e98e3e1Schristos "SYS_sbrk", 1284e98e3e1Schristos "SYS_argvlen", 1294e98e3e1Schristos "SYS_argv", 1304e98e3e1Schristos "SYS_chdir", 1314e98e3e1Schristos "SYS_stat", 1324e98e3e1Schristos "SYS_chmod", 1334e98e3e1Schristos "SYS_utime", 1344e98e3e1Schristos "SYS_time", 1354e98e3e1Schristos "SYS_gettimeofday", 1364e98e3e1Schristos "SYS_times", 1374e98e3e1Schristos "SYS_link" 1384e98e3e1Schristos }; 1394e98e3e1Schristos 1404e98e3e1Schristos int 1414e98e3e1Schristos rx_syscall (int id) 1424e98e3e1Schristos { 1434e98e3e1Schristos static char buf[256]; 1444e98e3e1Schristos int rv; 1454e98e3e1Schristos 1464e98e3e1Schristos argp = 0; 1474e98e3e1Schristos stackp = 4; 1484e98e3e1Schristos if (trace) 1494b169a6bSchristos printf ("\033[31m/* SYSCALL(%d) = %s */\033[0m\n", id, id <= TARGET_NEWLIB_SYS_link ? callnames[id] : "unknown"); 1504e98e3e1Schristos switch (id) 1514e98e3e1Schristos { 1524b169a6bSchristos case TARGET_NEWLIB_SYS_exit: 1534e98e3e1Schristos { 1544e98e3e1Schristos int ec = arg (); 1554e98e3e1Schristos if (verbose) 1564e98e3e1Schristos printf ("[exit %d]\n", ec); 1574e98e3e1Schristos return RX_MAKE_EXITED (ec); 1584e98e3e1Schristos } 1594e98e3e1Schristos break; 1604e98e3e1Schristos 1614b169a6bSchristos case TARGET_NEWLIB_SYS_open: 1624e98e3e1Schristos { 1634b169a6bSchristos int oflags, cflags; 1644e98e3e1Schristos int path = arg (); 1654e98e3e1Schristos /* The open function is defined as taking a variable number of arguments 1664e98e3e1Schristos because the third parameter to it is optional: 1674e98e3e1Schristos open (const char * filename, int flags, ...); 1684e98e3e1Schristos Hence the oflags and cflags arguments will be on the stack and we need 1694e98e3e1Schristos to skip the (empty) argument registers r3 and r4. */ 1704e98e3e1Schristos argp = 4; 1714b169a6bSchristos oflags = arg (); 1724b169a6bSchristos cflags = arg (); 1734e98e3e1Schristos 1744e98e3e1Schristos read_target (buf, path, 256, 1); 1754e98e3e1Schristos if (trace) 1764e98e3e1Schristos printf ("open(\"%s\",0x%x,%#o) = ", buf, oflags, cflags); 1774e98e3e1Schristos 1784e98e3e1Schristos if (callbacks) 1794e98e3e1Schristos /* The callback vector ignores CFLAGS. */ 1804e98e3e1Schristos rv = callbacks->open (callbacks, buf, oflags); 1814e98e3e1Schristos else 1824e98e3e1Schristos { 1834e98e3e1Schristos int h_oflags = 0; 1844e98e3e1Schristos 1854e98e3e1Schristos if (oflags & 0x0001) 1864e98e3e1Schristos h_oflags |= O_WRONLY; 1874e98e3e1Schristos if (oflags & 0x0002) 1884e98e3e1Schristos h_oflags |= O_RDWR; 1894e98e3e1Schristos if (oflags & 0x0200) 1904e98e3e1Schristos h_oflags |= O_CREAT; 1914e98e3e1Schristos if (oflags & 0x0008) 1924e98e3e1Schristos h_oflags |= O_APPEND; 1934e98e3e1Schristos if (oflags & 0x0400) 1944e98e3e1Schristos h_oflags |= O_TRUNC; 1954e98e3e1Schristos rv = open (buf, h_oflags, cflags); 1964e98e3e1Schristos } 1974e98e3e1Schristos if (trace) 1984e98e3e1Schristos printf ("%d\n", rv); 1994e98e3e1Schristos put_reg (1, rv); 2004e98e3e1Schristos } 2014e98e3e1Schristos break; 2024e98e3e1Schristos 2034b169a6bSchristos case TARGET_NEWLIB_SYS_close: 2044e98e3e1Schristos { 2054e98e3e1Schristos int fd = arg (); 2064e98e3e1Schristos 2074e98e3e1Schristos if (callbacks) 2084e98e3e1Schristos rv = callbacks->close (callbacks, fd); 2094e98e3e1Schristos else if (fd > 2) 2104e98e3e1Schristos rv = close (fd); 2114e98e3e1Schristos else 2124e98e3e1Schristos rv = 0; 2134e98e3e1Schristos if (trace) 2144e98e3e1Schristos printf ("close(%d) = %d\n", fd, rv); 2154e98e3e1Schristos put_reg (1, rv); 2164e98e3e1Schristos } 2174e98e3e1Schristos break; 2184e98e3e1Schristos 2194b169a6bSchristos case TARGET_NEWLIB_SYS_read: 2204e98e3e1Schristos { 2214e98e3e1Schristos int fd = arg (); 2224e98e3e1Schristos int addr = arg (); 2234e98e3e1Schristos int count = arg (); 2244e98e3e1Schristos 2254e98e3e1Schristos if (count > sizeof (buf)) 2264e98e3e1Schristos count = sizeof (buf); 2274e98e3e1Schristos if (callbacks) 2284e98e3e1Schristos rv = callbacks->read (callbacks, fd, buf, count); 2294e98e3e1Schristos else 2304e98e3e1Schristos rv = read (fd, buf, count); 2314e98e3e1Schristos if (trace) 2324e98e3e1Schristos printf ("read(%d,%d) = %d\n", fd, count, rv); 2334e98e3e1Schristos if (rv > 0) 2344e98e3e1Schristos write_target (buf, addr, rv, 0); 2354e98e3e1Schristos put_reg (1, rv); 2364e98e3e1Schristos } 2374e98e3e1Schristos break; 2384e98e3e1Schristos 2394b169a6bSchristos case TARGET_NEWLIB_SYS_write: 2404e98e3e1Schristos { 2414e98e3e1Schristos int fd = arg (); 2424e98e3e1Schristos int addr = arg (); 2434e98e3e1Schristos int count = arg (); 2444e98e3e1Schristos 2454e98e3e1Schristos if (count > sizeof (buf)) 2464e98e3e1Schristos count = sizeof (buf); 2474e98e3e1Schristos if (trace) 2484e98e3e1Schristos printf ("write(%d,0x%x,%d)\n", fd, addr, count); 2494e98e3e1Schristos read_target (buf, addr, count, 0); 2504e98e3e1Schristos if (trace) 2514e98e3e1Schristos fflush (stdout); 2524e98e3e1Schristos if (callbacks) 2534e98e3e1Schristos rv = callbacks->write (callbacks, fd, buf, count); 2544e98e3e1Schristos else 2554e98e3e1Schristos rv = write (fd, buf, count); 2564e98e3e1Schristos if (trace) 2574e98e3e1Schristos printf ("write(%d,%d) = %d\n", fd, count, rv); 2584e98e3e1Schristos put_reg (1, rv); 2594e98e3e1Schristos } 2604e98e3e1Schristos break; 2614e98e3e1Schristos 2624b169a6bSchristos case TARGET_NEWLIB_SYS_getpid: 2634e98e3e1Schristos put_reg (1, 42); 2644e98e3e1Schristos break; 2654e98e3e1Schristos 2664b169a6bSchristos case TARGET_NEWLIB_SYS_gettimeofday: 2674e98e3e1Schristos { 2684e98e3e1Schristos int tvaddr = arg (); 2694e98e3e1Schristos struct timeval tv; 2704e98e3e1Schristos 2714e98e3e1Schristos rv = gettimeofday (&tv, 0); 2724e98e3e1Schristos if (trace) 2734b169a6bSchristos printf ("gettimeofday: %" PRId64 " sec %" PRId64 " usec to 0x%x\n", 2744b169a6bSchristos (int64_t)tv.tv_sec, (int64_t)tv.tv_usec, tvaddr); 2754e98e3e1Schristos mem_put_si (tvaddr, tv.tv_sec); 2764e98e3e1Schristos mem_put_si (tvaddr + 4, tv.tv_usec); 2774e98e3e1Schristos put_reg (1, rv); 2784e98e3e1Schristos } 2794e98e3e1Schristos break; 2804e98e3e1Schristos 2814b169a6bSchristos case TARGET_NEWLIB_SYS_kill: 2824e98e3e1Schristos { 2834e98e3e1Schristos int pid = arg (); 2844e98e3e1Schristos int sig = arg (); 2854e98e3e1Schristos if (pid == 42) 2864e98e3e1Schristos { 2874e98e3e1Schristos if (verbose) 2884e98e3e1Schristos printf ("[signal %d]\n", sig); 2894e98e3e1Schristos return RX_MAKE_STOPPED (sig); 2904e98e3e1Schristos } 2914e98e3e1Schristos } 2924e98e3e1Schristos break; 2934e98e3e1Schristos 2944e98e3e1Schristos case 11: 2954e98e3e1Schristos { 2964e98e3e1Schristos int heaptop_arg = arg (); 2974e98e3e1Schristos if (trace) 2984e98e3e1Schristos printf ("sbrk: heap top set to %x\n", heaptop_arg); 2994e98e3e1Schristos heaptop = heaptop_arg; 3004e98e3e1Schristos if (heapbottom == 0) 3014e98e3e1Schristos heapbottom = heaptop_arg; 3024e98e3e1Schristos } 3034e98e3e1Schristos break; 3044e98e3e1Schristos 3054e98e3e1Schristos case 255: 3064e98e3e1Schristos { 3074e98e3e1Schristos int addr = arg (); 3084e98e3e1Schristos mem_put_si (addr, rx_cycles + mem_usage_cycles()); 3094e98e3e1Schristos } 3104e98e3e1Schristos break; 3114e98e3e1Schristos 3124e98e3e1Schristos } 3134e98e3e1Schristos return RX_MAKE_STEPPED (); 3144e98e3e1Schristos } 315