1 /*
2  *  m68k simulator syscall interface
3  *
4  *  Copyright (c) 2005 CodeSourcery, LLC. Written by Paul Brook.
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "qemu/osdep.h"
21 
22 #include "qemu.h"
23 
24 #define SYS_EXIT        1
25 #define SYS_READ        3
26 #define SYS_WRITE       4
27 #define SYS_OPEN        5
28 #define SYS_CLOSE       6
29 #define SYS_BRK         17
30 #define SYS_FSTAT       28
31 #define SYS_ISATTY      29
32 #define SYS_LSEEK       199
33 
34 struct m68k_sim_stat {
35     uint16_t sim_st_dev;
36     uint16_t sim_st_ino;
37     uint32_t sim_st_mode;
38     uint16_t sim_st_nlink;
39     uint16_t sim_st_uid;
40     uint16_t sim_st_gid;
41     uint16_t sim_st_rdev;
42     uint32_t sim_st_size;
43     uint32_t sim_st_atime;
44     uint32_t sim_st_mtime;
45     uint32_t sim_st_ctime;
46     uint32_t sim_st_blksize;
47     uint32_t sim_st_blocks;
48 };
49 
check_err(CPUM68KState * env,uint32_t code)50 static inline uint32_t check_err(CPUM68KState *env, uint32_t code)
51 {
52   env->dregs[0] = code;
53   if (code == (uint32_t)-1) {
54       env->dregs[1] = errno;
55   } else {
56       env->dregs[1] = 0;
57   }
58   return code;
59 }
60 
61 #define SIM_O_APPEND    0x0008
62 #define SIM_O_CREAT     0x0200
63 #define SIM_O_TRUNC     0x0400
64 #define SIM_O_EXCL      0x0800
65 #define SIM_O_NONBLOCK  0x4000
66 #define SIM_O_NOCTTY    0x8000
67 #define SIM_O_SYNC      0x2000
68 
translate_openflags(int flags)69 static int translate_openflags(int flags)
70 {
71     int hf;
72 
73     switch (flags & 3) {
74     case 0: hf = O_RDONLY; break;
75     case 1: hf = O_WRONLY; break;
76     case 2: hf = O_RDWR; break;
77     default: hf = O_RDWR; break;
78     }
79 
80     if (flags & SIM_O_APPEND) hf |= O_APPEND;
81     if (flags & SIM_O_CREAT) hf |= O_CREAT;
82     if (flags & SIM_O_TRUNC) hf |= O_TRUNC;
83     if (flags & SIM_O_EXCL) hf |= O_EXCL;
84     if (flags & SIM_O_NONBLOCK) hf |= O_NONBLOCK;
85     if (flags & SIM_O_NOCTTY) hf |= O_NOCTTY;
86     if (flags & SIM_O_SYNC) hf |= O_SYNC;
87 
88     return hf;
89 }
90 
91 #define ARG(x) tswap32(args[x])
do_m68k_simcall(CPUM68KState * env,int nr)92 void do_m68k_simcall(CPUM68KState *env, int nr)
93 {
94     M68kCPU *cpu = m68k_env_get_cpu(env);
95     uint32_t *args;
96 
97     args = (uint32_t *)(unsigned long)(env->aregs[7] + 4);
98     switch (nr) {
99     case SYS_EXIT:
100         exit(ARG(0));
101     case SYS_READ:
102         check_err(env, read(ARG(0), (void *)(unsigned long)ARG(1), ARG(2)));
103         break;
104     case SYS_WRITE:
105         check_err(env, write(ARG(0), (void *)(unsigned long)ARG(1), ARG(2)));
106         break;
107     case SYS_OPEN:
108         check_err(env, open((char *)(unsigned long)ARG(0),
109                             translate_openflags(ARG(1)), ARG(2)));
110         break;
111     case SYS_CLOSE:
112         {
113             /* Ignore attempts to close stdin/out/err.  */
114             int fd = ARG(0);
115             if (fd > 2)
116               check_err(env, close(fd));
117             else
118               check_err(env, 0);
119             break;
120         }
121     case SYS_BRK:
122         {
123             int32_t ret;
124 
125             ret = do_brk((abi_ulong)ARG(0));
126             if (ret == -ENOMEM)
127                 ret = -1;
128             check_err(env, ret);
129         }
130         break;
131     case SYS_FSTAT:
132         {
133             struct stat s;
134             int rc;
135             struct m68k_sim_stat *p;
136             rc = check_err(env, fstat(ARG(0), &s));
137             if (rc == 0) {
138                 p = (struct m68k_sim_stat *)(unsigned long)ARG(1);
139                 p->sim_st_dev = tswap16(s.st_dev);
140                 p->sim_st_ino = tswap16(s.st_ino);
141                 p->sim_st_mode = tswap32(s.st_mode);
142                 p->sim_st_nlink = tswap16(s.st_nlink);
143                 p->sim_st_uid = tswap16(s.st_uid);
144                 p->sim_st_gid = tswap16(s.st_gid);
145                 p->sim_st_rdev = tswap16(s.st_rdev);
146                 p->sim_st_size = tswap32(s.st_size);
147                 p->sim_st_atime = tswap32(s.st_atime);
148                 p->sim_st_mtime = tswap32(s.st_mtime);
149                 p->sim_st_ctime = tswap32(s.st_ctime);
150                 p->sim_st_blksize = tswap32(s.st_blksize);
151                 p->sim_st_blocks = tswap32(s.st_blocks);
152             }
153         }
154         break;
155     case SYS_ISATTY:
156         check_err(env, isatty(ARG(0)));
157         break;
158     case SYS_LSEEK:
159         check_err(env, lseek(ARG(0), (int32_t)ARG(1), ARG(2)));
160         break;
161     default:
162         cpu_abort(CPU(cpu), "Unsupported m68k sim syscall %d\n", nr);
163     }
164 }
165