| /* | 
 |  *  m68k simulator syscall interface | 
 |  * | 
 |  *  Copyright (c) 2005 CodeSourcery, LLC. Written by Paul Brook. | 
 |  * | 
 |  *  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, see <http://www.gnu.org/licenses/>. | 
 |  */ | 
 |  | 
 | #include <sys/types.h> | 
 | #include <sys/stat.h> | 
 | #include <errno.h> | 
 | #include <fcntl.h> | 
 | #include <unistd.h> | 
 | #include <stdlib.h> | 
 | #include <stdio.h> | 
 | #include <time.h> | 
 |  | 
 | #include "qemu.h" | 
 |  | 
 | #define SYS_EXIT        1 | 
 | #define SYS_READ        3 | 
 | #define SYS_WRITE       4 | 
 | #define SYS_OPEN        5 | 
 | #define SYS_CLOSE       6 | 
 | #define SYS_BRK         17 | 
 | #define SYS_FSTAT       28 | 
 | #define SYS_ISATTY      29 | 
 | #define SYS_LSEEK       199 | 
 |  | 
 | struct m68k_sim_stat { | 
 |     uint16_t sim_st_dev; | 
 |     uint16_t sim_st_ino; | 
 |     uint32_t sim_st_mode; | 
 |     uint16_t sim_st_nlink; | 
 |     uint16_t sim_st_uid; | 
 |     uint16_t sim_st_gid; | 
 |     uint16_t sim_st_rdev; | 
 |     uint32_t sim_st_size; | 
 |     uint32_t sim_st_atime; | 
 |     uint32_t sim_st_mtime; | 
 |     uint32_t sim_st_ctime; | 
 |     uint32_t sim_st_blksize; | 
 |     uint32_t sim_st_blocks; | 
 | }; | 
 |  | 
 | static inline uint32_t check_err(CPUM68KState *env, uint32_t code) | 
 | { | 
 |   env->dregs[0] = code; | 
 |   if (code == (uint32_t)-1) { | 
 |       env->dregs[1] = errno; | 
 |   } else { | 
 |       env->dregs[1] = 0; | 
 |   } | 
 |   return code; | 
 | } | 
 |  | 
 | #define SIM_O_APPEND    0x0008 | 
 | #define SIM_O_CREAT     0x0200 | 
 | #define SIM_O_TRUNC     0x0400 | 
 | #define SIM_O_EXCL      0x0800 | 
 | #define SIM_O_NONBLOCK  0x4000 | 
 | #define SIM_O_NOCTTY    0x8000 | 
 | #define SIM_O_SYNC      0x2000 | 
 |  | 
 | static int translate_openflags(int flags) | 
 | { | 
 |     int hf; | 
 |  | 
 |     switch (flags & 3) { | 
 |     case 0: hf = O_RDONLY; break; | 
 |     case 1: hf = O_WRONLY; break; | 
 |     case 2: hf = O_RDWR; break; | 
 |     default: hf = O_RDWR; break; | 
 |     } | 
 |  | 
 |     if (flags & SIM_O_APPEND) hf |= O_APPEND; | 
 |     if (flags & SIM_O_CREAT) hf |= O_CREAT; | 
 |     if (flags & SIM_O_TRUNC) hf |= O_TRUNC; | 
 |     if (flags & SIM_O_EXCL) hf |= O_EXCL; | 
 |     if (flags & SIM_O_NONBLOCK) hf |= O_NONBLOCK; | 
 |     if (flags & SIM_O_NOCTTY) hf |= O_NOCTTY; | 
 |     if (flags & SIM_O_SYNC) hf |= O_SYNC; | 
 |  | 
 |     return hf; | 
 | } | 
 |  | 
 | #define ARG(x) tswap32(args[x]) | 
 | void do_m68k_simcall(CPUM68KState *env, int nr) | 
 | { | 
 |     uint32_t *args; | 
 |  | 
 |     args = (uint32_t *)(unsigned long)(env->aregs[7] + 4); | 
 |     switch (nr) { | 
 |     case SYS_EXIT: | 
 |         exit(ARG(0)); | 
 |     case SYS_READ: | 
 |         check_err(env, read(ARG(0), (void *)(unsigned long)ARG(1), ARG(2))); | 
 |         break; | 
 |     case SYS_WRITE: | 
 |         check_err(env, write(ARG(0), (void *)(unsigned long)ARG(1), ARG(2))); | 
 |         break; | 
 |     case SYS_OPEN: | 
 |         check_err(env, open((char *)(unsigned long)ARG(0), | 
 |                             translate_openflags(ARG(1)), ARG(2))); | 
 |         break; | 
 |     case SYS_CLOSE: | 
 |         { | 
 |             /* Ignore attempts to close stdin/out/err.  */ | 
 |             int fd = ARG(0); | 
 |             if (fd > 2) | 
 |               check_err(env, close(fd)); | 
 |             else | 
 |               check_err(env, 0); | 
 |             break; | 
 |         } | 
 |     case SYS_BRK: | 
 |         { | 
 |             int32_t ret; | 
 |  | 
 |             ret = do_brk((abi_ulong)ARG(0)); | 
 |             if (ret == -ENOMEM) | 
 |                 ret = -1; | 
 |             check_err(env, ret); | 
 |         } | 
 |         break; | 
 |     case SYS_FSTAT: | 
 |         { | 
 |             struct stat s; | 
 |             int rc; | 
 |             struct m68k_sim_stat *p; | 
 |             rc = check_err(env, fstat(ARG(0), &s)); | 
 |             if (rc == 0) { | 
 |                 p = (struct m68k_sim_stat *)(unsigned long)ARG(1); | 
 |                 p->sim_st_dev = tswap16(s.st_dev); | 
 |                 p->sim_st_ino = tswap16(s.st_ino); | 
 |                 p->sim_st_mode = tswap32(s.st_mode); | 
 |                 p->sim_st_nlink = tswap16(s.st_nlink); | 
 |                 p->sim_st_uid = tswap16(s.st_uid); | 
 |                 p->sim_st_gid = tswap16(s.st_gid); | 
 |                 p->sim_st_rdev = tswap16(s.st_rdev); | 
 |                 p->sim_st_size = tswap32(s.st_size); | 
 |                 p->sim_st_atime = tswap32(s.st_atime); | 
 |                 p->sim_st_mtime = tswap32(s.st_mtime); | 
 |                 p->sim_st_ctime = tswap32(s.st_ctime); | 
 |                 p->sim_st_blksize = tswap32(s.st_blksize); | 
 |                 p->sim_st_blocks = tswap32(s.st_blocks); | 
 |             } | 
 |         } | 
 |         break; | 
 |     case SYS_ISATTY: | 
 |         check_err(env, isatty(ARG(0))); | 
 |         break; | 
 |     case SYS_LSEEK: | 
 |         check_err(env, lseek(ARG(0), (int32_t)ARG(1), ARG(2))); | 
 |         break; | 
 |     default: | 
 |         cpu_abort(env, "Unsupported m68k sim syscall %d\n", nr); | 
 |     } | 
 | } |