xref: /qemu/target/m68k/m68k-semi.c (revision fcf5ef2a)
1*fcf5ef2aSThomas Huth /*
2*fcf5ef2aSThomas Huth  *  m68k/ColdFire Semihosting syscall interface
3*fcf5ef2aSThomas Huth  *
4*fcf5ef2aSThomas Huth  *  Copyright (c) 2005-2007 CodeSourcery.
5*fcf5ef2aSThomas Huth  *
6*fcf5ef2aSThomas Huth  *  This program is free software; you can redistribute it and/or modify
7*fcf5ef2aSThomas Huth  *  it under the terms of the GNU General Public License as published by
8*fcf5ef2aSThomas Huth  *  the Free Software Foundation; either version 2 of the License, or
9*fcf5ef2aSThomas Huth  *  (at your option) any later version.
10*fcf5ef2aSThomas Huth  *
11*fcf5ef2aSThomas Huth  *  This program is distributed in the hope that it will be useful,
12*fcf5ef2aSThomas Huth  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13*fcf5ef2aSThomas Huth  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*fcf5ef2aSThomas Huth  *  GNU General Public License for more details.
15*fcf5ef2aSThomas Huth  *
16*fcf5ef2aSThomas Huth  *  You should have received a copy of the GNU General Public License
17*fcf5ef2aSThomas Huth  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
18*fcf5ef2aSThomas Huth  */
19*fcf5ef2aSThomas Huth 
20*fcf5ef2aSThomas Huth #include "qemu/osdep.h"
21*fcf5ef2aSThomas Huth 
22*fcf5ef2aSThomas Huth #include "cpu.h"
23*fcf5ef2aSThomas Huth #if defined(CONFIG_USER_ONLY)
24*fcf5ef2aSThomas Huth #include "qemu.h"
25*fcf5ef2aSThomas Huth #define SEMIHOSTING_HEAP_SIZE (128 * 1024 * 1024)
26*fcf5ef2aSThomas Huth #else
27*fcf5ef2aSThomas Huth #include "qemu-common.h"
28*fcf5ef2aSThomas Huth #include "exec/gdbstub.h"
29*fcf5ef2aSThomas Huth #include "exec/softmmu-semi.h"
30*fcf5ef2aSThomas Huth #endif
31*fcf5ef2aSThomas Huth #include "qemu/log.h"
32*fcf5ef2aSThomas Huth #include "sysemu/sysemu.h"
33*fcf5ef2aSThomas Huth 
34*fcf5ef2aSThomas Huth #define HOSTED_EXIT  0
35*fcf5ef2aSThomas Huth #define HOSTED_INIT_SIM 1
36*fcf5ef2aSThomas Huth #define HOSTED_OPEN 2
37*fcf5ef2aSThomas Huth #define HOSTED_CLOSE 3
38*fcf5ef2aSThomas Huth #define HOSTED_READ 4
39*fcf5ef2aSThomas Huth #define HOSTED_WRITE 5
40*fcf5ef2aSThomas Huth #define HOSTED_LSEEK 6
41*fcf5ef2aSThomas Huth #define HOSTED_RENAME 7
42*fcf5ef2aSThomas Huth #define HOSTED_UNLINK 8
43*fcf5ef2aSThomas Huth #define HOSTED_STAT 9
44*fcf5ef2aSThomas Huth #define HOSTED_FSTAT 10
45*fcf5ef2aSThomas Huth #define HOSTED_GETTIMEOFDAY 11
46*fcf5ef2aSThomas Huth #define HOSTED_ISATTY 12
47*fcf5ef2aSThomas Huth #define HOSTED_SYSTEM 13
48*fcf5ef2aSThomas Huth 
49*fcf5ef2aSThomas Huth typedef uint32_t gdb_mode_t;
50*fcf5ef2aSThomas Huth typedef uint32_t gdb_time_t;
51*fcf5ef2aSThomas Huth 
52*fcf5ef2aSThomas Huth struct m68k_gdb_stat {
53*fcf5ef2aSThomas Huth   uint32_t    gdb_st_dev;     /* device */
54*fcf5ef2aSThomas Huth   uint32_t    gdb_st_ino;     /* inode */
55*fcf5ef2aSThomas Huth   gdb_mode_t  gdb_st_mode;    /* protection */
56*fcf5ef2aSThomas Huth   uint32_t    gdb_st_nlink;   /* number of hard links */
57*fcf5ef2aSThomas Huth   uint32_t    gdb_st_uid;     /* user ID of owner */
58*fcf5ef2aSThomas Huth   uint32_t    gdb_st_gid;     /* group ID of owner */
59*fcf5ef2aSThomas Huth   uint32_t    gdb_st_rdev;    /* device type (if inode device) */
60*fcf5ef2aSThomas Huth   uint64_t    gdb_st_size;    /* total size, in bytes */
61*fcf5ef2aSThomas Huth   uint64_t    gdb_st_blksize; /* blocksize for filesystem I/O */
62*fcf5ef2aSThomas Huth   uint64_t    gdb_st_blocks;  /* number of blocks allocated */
63*fcf5ef2aSThomas Huth   gdb_time_t  gdb_st_atime;   /* time of last access */
64*fcf5ef2aSThomas Huth   gdb_time_t  gdb_st_mtime;   /* time of last modification */
65*fcf5ef2aSThomas Huth   gdb_time_t  gdb_st_ctime;   /* time of last change */
66*fcf5ef2aSThomas Huth } QEMU_PACKED;
67*fcf5ef2aSThomas Huth 
68*fcf5ef2aSThomas Huth struct gdb_timeval {
69*fcf5ef2aSThomas Huth   gdb_time_t tv_sec;  /* second */
70*fcf5ef2aSThomas Huth   uint64_t tv_usec;   /* microsecond */
71*fcf5ef2aSThomas Huth } QEMU_PACKED;
72*fcf5ef2aSThomas Huth 
73*fcf5ef2aSThomas Huth #define GDB_O_RDONLY   0x0
74*fcf5ef2aSThomas Huth #define GDB_O_WRONLY   0x1
75*fcf5ef2aSThomas Huth #define GDB_O_RDWR     0x2
76*fcf5ef2aSThomas Huth #define GDB_O_APPEND   0x8
77*fcf5ef2aSThomas Huth #define GDB_O_CREAT  0x200
78*fcf5ef2aSThomas Huth #define GDB_O_TRUNC  0x400
79*fcf5ef2aSThomas Huth #define GDB_O_EXCL   0x800
80*fcf5ef2aSThomas Huth 
81*fcf5ef2aSThomas Huth static int translate_openflags(int flags)
82*fcf5ef2aSThomas Huth {
83*fcf5ef2aSThomas Huth     int hf;
84*fcf5ef2aSThomas Huth 
85*fcf5ef2aSThomas Huth     if (flags & GDB_O_WRONLY)
86*fcf5ef2aSThomas Huth         hf = O_WRONLY;
87*fcf5ef2aSThomas Huth     else if (flags & GDB_O_RDWR)
88*fcf5ef2aSThomas Huth         hf = O_RDWR;
89*fcf5ef2aSThomas Huth     else
90*fcf5ef2aSThomas Huth         hf = O_RDONLY;
91*fcf5ef2aSThomas Huth 
92*fcf5ef2aSThomas Huth     if (flags & GDB_O_APPEND) hf |= O_APPEND;
93*fcf5ef2aSThomas Huth     if (flags & GDB_O_CREAT) hf |= O_CREAT;
94*fcf5ef2aSThomas Huth     if (flags & GDB_O_TRUNC) hf |= O_TRUNC;
95*fcf5ef2aSThomas Huth     if (flags & GDB_O_EXCL) hf |= O_EXCL;
96*fcf5ef2aSThomas Huth 
97*fcf5ef2aSThomas Huth     return hf;
98*fcf5ef2aSThomas Huth }
99*fcf5ef2aSThomas Huth 
100*fcf5ef2aSThomas Huth static void translate_stat(CPUM68KState *env, target_ulong addr, struct stat *s)
101*fcf5ef2aSThomas Huth {
102*fcf5ef2aSThomas Huth     struct m68k_gdb_stat *p;
103*fcf5ef2aSThomas Huth 
104*fcf5ef2aSThomas Huth     if (!(p = lock_user(VERIFY_WRITE, addr, sizeof(struct m68k_gdb_stat), 0)))
105*fcf5ef2aSThomas Huth         /* FIXME - should this return an error code? */
106*fcf5ef2aSThomas Huth         return;
107*fcf5ef2aSThomas Huth     p->gdb_st_dev = cpu_to_be32(s->st_dev);
108*fcf5ef2aSThomas Huth     p->gdb_st_ino = cpu_to_be32(s->st_ino);
109*fcf5ef2aSThomas Huth     p->gdb_st_mode = cpu_to_be32(s->st_mode);
110*fcf5ef2aSThomas Huth     p->gdb_st_nlink = cpu_to_be32(s->st_nlink);
111*fcf5ef2aSThomas Huth     p->gdb_st_uid = cpu_to_be32(s->st_uid);
112*fcf5ef2aSThomas Huth     p->gdb_st_gid = cpu_to_be32(s->st_gid);
113*fcf5ef2aSThomas Huth     p->gdb_st_rdev = cpu_to_be32(s->st_rdev);
114*fcf5ef2aSThomas Huth     p->gdb_st_size = cpu_to_be64(s->st_size);
115*fcf5ef2aSThomas Huth #ifdef _WIN32
116*fcf5ef2aSThomas Huth     /* Windows stat is missing some fields.  */
117*fcf5ef2aSThomas Huth     p->gdb_st_blksize = 0;
118*fcf5ef2aSThomas Huth     p->gdb_st_blocks = 0;
119*fcf5ef2aSThomas Huth #else
120*fcf5ef2aSThomas Huth     p->gdb_st_blksize = cpu_to_be64(s->st_blksize);
121*fcf5ef2aSThomas Huth     p->gdb_st_blocks = cpu_to_be64(s->st_blocks);
122*fcf5ef2aSThomas Huth #endif
123*fcf5ef2aSThomas Huth     p->gdb_st_atime = cpu_to_be32(s->st_atime);
124*fcf5ef2aSThomas Huth     p->gdb_st_mtime = cpu_to_be32(s->st_mtime);
125*fcf5ef2aSThomas Huth     p->gdb_st_ctime = cpu_to_be32(s->st_ctime);
126*fcf5ef2aSThomas Huth     unlock_user(p, addr, sizeof(struct m68k_gdb_stat));
127*fcf5ef2aSThomas Huth }
128*fcf5ef2aSThomas Huth 
129*fcf5ef2aSThomas Huth static void m68k_semi_return_u32(CPUM68KState *env, uint32_t ret, uint32_t err)
130*fcf5ef2aSThomas Huth {
131*fcf5ef2aSThomas Huth     target_ulong args = env->dregs[1];
132*fcf5ef2aSThomas Huth     if (put_user_u32(ret, args) ||
133*fcf5ef2aSThomas Huth         put_user_u32(err, args + 4)) {
134*fcf5ef2aSThomas Huth         /* The m68k semihosting ABI does not provide any way to report this
135*fcf5ef2aSThomas Huth          * error to the guest, so the best we can do is log it in qemu.
136*fcf5ef2aSThomas Huth          * It is always a guest error not to pass us a valid argument block.
137*fcf5ef2aSThomas Huth          */
138*fcf5ef2aSThomas Huth         qemu_log_mask(LOG_GUEST_ERROR, "m68k-semihosting: return value "
139*fcf5ef2aSThomas Huth                       "discarded because argument block not writable\n");
140*fcf5ef2aSThomas Huth     }
141*fcf5ef2aSThomas Huth }
142*fcf5ef2aSThomas Huth 
143*fcf5ef2aSThomas Huth static void m68k_semi_return_u64(CPUM68KState *env, uint64_t ret, uint32_t err)
144*fcf5ef2aSThomas Huth {
145*fcf5ef2aSThomas Huth     target_ulong args = env->dregs[1];
146*fcf5ef2aSThomas Huth     if (put_user_u32(ret >> 32, args) ||
147*fcf5ef2aSThomas Huth         put_user_u32(ret, args + 4) ||
148*fcf5ef2aSThomas Huth         put_user_u32(err, args + 8)) {
149*fcf5ef2aSThomas Huth         /* No way to report this via m68k semihosting ABI; just log it */
150*fcf5ef2aSThomas Huth         qemu_log_mask(LOG_GUEST_ERROR, "m68k-semihosting: return value "
151*fcf5ef2aSThomas Huth                       "discarded because argument block not writable\n");
152*fcf5ef2aSThomas Huth     }
153*fcf5ef2aSThomas Huth }
154*fcf5ef2aSThomas Huth 
155*fcf5ef2aSThomas Huth static int m68k_semi_is_fseek;
156*fcf5ef2aSThomas Huth 
157*fcf5ef2aSThomas Huth static void m68k_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
158*fcf5ef2aSThomas Huth {
159*fcf5ef2aSThomas Huth     M68kCPU *cpu = M68K_CPU(cs);
160*fcf5ef2aSThomas Huth     CPUM68KState *env = &cpu->env;
161*fcf5ef2aSThomas Huth 
162*fcf5ef2aSThomas Huth     if (m68k_semi_is_fseek) {
163*fcf5ef2aSThomas Huth         /* FIXME: We've already lost the high bits of the fseek
164*fcf5ef2aSThomas Huth            return value.  */
165*fcf5ef2aSThomas Huth         m68k_semi_return_u64(env, ret, err);
166*fcf5ef2aSThomas Huth         m68k_semi_is_fseek = 0;
167*fcf5ef2aSThomas Huth     } else {
168*fcf5ef2aSThomas Huth         m68k_semi_return_u32(env, ret, err);
169*fcf5ef2aSThomas Huth     }
170*fcf5ef2aSThomas Huth }
171*fcf5ef2aSThomas Huth 
172*fcf5ef2aSThomas Huth /* Read the input value from the argument block; fail the semihosting
173*fcf5ef2aSThomas Huth  * call if the memory read fails.
174*fcf5ef2aSThomas Huth  */
175*fcf5ef2aSThomas Huth #define GET_ARG(n) do {                                 \
176*fcf5ef2aSThomas Huth     if (get_user_ual(arg ## n, args + (n) * 4)) {       \
177*fcf5ef2aSThomas Huth         result = -1;                                    \
178*fcf5ef2aSThomas Huth         errno = EFAULT;                                 \
179*fcf5ef2aSThomas Huth         goto failed;                                    \
180*fcf5ef2aSThomas Huth     }                                                   \
181*fcf5ef2aSThomas Huth } while (0)
182*fcf5ef2aSThomas Huth 
183*fcf5ef2aSThomas Huth void do_m68k_semihosting(CPUM68KState *env, int nr)
184*fcf5ef2aSThomas Huth {
185*fcf5ef2aSThomas Huth     uint32_t args;
186*fcf5ef2aSThomas Huth     target_ulong arg0, arg1, arg2, arg3;
187*fcf5ef2aSThomas Huth     void *p;
188*fcf5ef2aSThomas Huth     void *q;
189*fcf5ef2aSThomas Huth     uint32_t len;
190*fcf5ef2aSThomas Huth     uint32_t result;
191*fcf5ef2aSThomas Huth 
192*fcf5ef2aSThomas Huth     args = env->dregs[1];
193*fcf5ef2aSThomas Huth     switch (nr) {
194*fcf5ef2aSThomas Huth     case HOSTED_EXIT:
195*fcf5ef2aSThomas Huth         gdb_exit(env, env->dregs[0]);
196*fcf5ef2aSThomas Huth         exit(env->dregs[0]);
197*fcf5ef2aSThomas Huth     case HOSTED_OPEN:
198*fcf5ef2aSThomas Huth         GET_ARG(0);
199*fcf5ef2aSThomas Huth         GET_ARG(1);
200*fcf5ef2aSThomas Huth         GET_ARG(2);
201*fcf5ef2aSThomas Huth         GET_ARG(3);
202*fcf5ef2aSThomas Huth         if (use_gdb_syscalls()) {
203*fcf5ef2aSThomas Huth             gdb_do_syscall(m68k_semi_cb, "open,%s,%x,%x", arg0, (int)arg1,
204*fcf5ef2aSThomas Huth                            arg2, arg3);
205*fcf5ef2aSThomas Huth             return;
206*fcf5ef2aSThomas Huth         } else {
207*fcf5ef2aSThomas Huth             p = lock_user_string(arg0);
208*fcf5ef2aSThomas Huth             if (!p) {
209*fcf5ef2aSThomas Huth                 /* FIXME - check error code? */
210*fcf5ef2aSThomas Huth                 result = -1;
211*fcf5ef2aSThomas Huth             } else {
212*fcf5ef2aSThomas Huth                 result = open(p, translate_openflags(arg2), arg3);
213*fcf5ef2aSThomas Huth                 unlock_user(p, arg0, 0);
214*fcf5ef2aSThomas Huth             }
215*fcf5ef2aSThomas Huth         }
216*fcf5ef2aSThomas Huth         break;
217*fcf5ef2aSThomas Huth     case HOSTED_CLOSE:
218*fcf5ef2aSThomas Huth         {
219*fcf5ef2aSThomas Huth             /* Ignore attempts to close stdin/out/err.  */
220*fcf5ef2aSThomas Huth             GET_ARG(0);
221*fcf5ef2aSThomas Huth             int fd = arg0;
222*fcf5ef2aSThomas Huth             if (fd > 2) {
223*fcf5ef2aSThomas Huth                 if (use_gdb_syscalls()) {
224*fcf5ef2aSThomas Huth                     gdb_do_syscall(m68k_semi_cb, "close,%x", arg0);
225*fcf5ef2aSThomas Huth                     return;
226*fcf5ef2aSThomas Huth                 } else {
227*fcf5ef2aSThomas Huth                     result = close(fd);
228*fcf5ef2aSThomas Huth                 }
229*fcf5ef2aSThomas Huth             } else {
230*fcf5ef2aSThomas Huth                 result = 0;
231*fcf5ef2aSThomas Huth             }
232*fcf5ef2aSThomas Huth             break;
233*fcf5ef2aSThomas Huth         }
234*fcf5ef2aSThomas Huth     case HOSTED_READ:
235*fcf5ef2aSThomas Huth         GET_ARG(0);
236*fcf5ef2aSThomas Huth         GET_ARG(1);
237*fcf5ef2aSThomas Huth         GET_ARG(2);
238*fcf5ef2aSThomas Huth         len = arg2;
239*fcf5ef2aSThomas Huth         if (use_gdb_syscalls()) {
240*fcf5ef2aSThomas Huth             gdb_do_syscall(m68k_semi_cb, "read,%x,%x,%x",
241*fcf5ef2aSThomas Huth                            arg0, arg1, len);
242*fcf5ef2aSThomas Huth             return;
243*fcf5ef2aSThomas Huth         } else {
244*fcf5ef2aSThomas Huth             p = lock_user(VERIFY_WRITE, arg1, len, 0);
245*fcf5ef2aSThomas Huth             if (!p) {
246*fcf5ef2aSThomas Huth                 /* FIXME - check error code? */
247*fcf5ef2aSThomas Huth                 result = -1;
248*fcf5ef2aSThomas Huth             } else {
249*fcf5ef2aSThomas Huth                 result = read(arg0, p, len);
250*fcf5ef2aSThomas Huth                 unlock_user(p, arg1, len);
251*fcf5ef2aSThomas Huth             }
252*fcf5ef2aSThomas Huth         }
253*fcf5ef2aSThomas Huth         break;
254*fcf5ef2aSThomas Huth     case HOSTED_WRITE:
255*fcf5ef2aSThomas Huth         GET_ARG(0);
256*fcf5ef2aSThomas Huth         GET_ARG(1);
257*fcf5ef2aSThomas Huth         GET_ARG(2);
258*fcf5ef2aSThomas Huth         len = arg2;
259*fcf5ef2aSThomas Huth         if (use_gdb_syscalls()) {
260*fcf5ef2aSThomas Huth             gdb_do_syscall(m68k_semi_cb, "write,%x,%x,%x",
261*fcf5ef2aSThomas Huth                            arg0, arg1, len);
262*fcf5ef2aSThomas Huth             return;
263*fcf5ef2aSThomas Huth         } else {
264*fcf5ef2aSThomas Huth             p = lock_user(VERIFY_READ, arg1, len, 1);
265*fcf5ef2aSThomas Huth             if (!p) {
266*fcf5ef2aSThomas Huth                 /* FIXME - check error code? */
267*fcf5ef2aSThomas Huth                 result = -1;
268*fcf5ef2aSThomas Huth             } else {
269*fcf5ef2aSThomas Huth                 result = write(arg0, p, len);
270*fcf5ef2aSThomas Huth                 unlock_user(p, arg0, 0);
271*fcf5ef2aSThomas Huth             }
272*fcf5ef2aSThomas Huth         }
273*fcf5ef2aSThomas Huth         break;
274*fcf5ef2aSThomas Huth     case HOSTED_LSEEK:
275*fcf5ef2aSThomas Huth         {
276*fcf5ef2aSThomas Huth             uint64_t off;
277*fcf5ef2aSThomas Huth             GET_ARG(0);
278*fcf5ef2aSThomas Huth             GET_ARG(1);
279*fcf5ef2aSThomas Huth             GET_ARG(2);
280*fcf5ef2aSThomas Huth             GET_ARG(3);
281*fcf5ef2aSThomas Huth             off = (uint32_t)arg2 | ((uint64_t)arg1 << 32);
282*fcf5ef2aSThomas Huth             if (use_gdb_syscalls()) {
283*fcf5ef2aSThomas Huth                 m68k_semi_is_fseek = 1;
284*fcf5ef2aSThomas Huth                 gdb_do_syscall(m68k_semi_cb, "fseek,%x,%lx,%x",
285*fcf5ef2aSThomas Huth                                arg0, off, arg3);
286*fcf5ef2aSThomas Huth             } else {
287*fcf5ef2aSThomas Huth                 off = lseek(arg0, off, arg3);
288*fcf5ef2aSThomas Huth                 m68k_semi_return_u64(env, off, errno);
289*fcf5ef2aSThomas Huth             }
290*fcf5ef2aSThomas Huth             return;
291*fcf5ef2aSThomas Huth         }
292*fcf5ef2aSThomas Huth     case HOSTED_RENAME:
293*fcf5ef2aSThomas Huth         GET_ARG(0);
294*fcf5ef2aSThomas Huth         GET_ARG(1);
295*fcf5ef2aSThomas Huth         GET_ARG(2);
296*fcf5ef2aSThomas Huth         GET_ARG(3);
297*fcf5ef2aSThomas Huth         if (use_gdb_syscalls()) {
298*fcf5ef2aSThomas Huth             gdb_do_syscall(m68k_semi_cb, "rename,%s,%s",
299*fcf5ef2aSThomas Huth                            arg0, (int)arg1, arg2, (int)arg3);
300*fcf5ef2aSThomas Huth             return;
301*fcf5ef2aSThomas Huth         } else {
302*fcf5ef2aSThomas Huth             p = lock_user_string(arg0);
303*fcf5ef2aSThomas Huth             q = lock_user_string(arg2);
304*fcf5ef2aSThomas Huth             if (!p || !q) {
305*fcf5ef2aSThomas Huth                 /* FIXME - check error code? */
306*fcf5ef2aSThomas Huth                 result = -1;
307*fcf5ef2aSThomas Huth             } else {
308*fcf5ef2aSThomas Huth                 result = rename(p, q);
309*fcf5ef2aSThomas Huth             }
310*fcf5ef2aSThomas Huth             unlock_user(p, arg0, 0);
311*fcf5ef2aSThomas Huth             unlock_user(q, arg2, 0);
312*fcf5ef2aSThomas Huth         }
313*fcf5ef2aSThomas Huth         break;
314*fcf5ef2aSThomas Huth     case HOSTED_UNLINK:
315*fcf5ef2aSThomas Huth         GET_ARG(0);
316*fcf5ef2aSThomas Huth         GET_ARG(1);
317*fcf5ef2aSThomas Huth         if (use_gdb_syscalls()) {
318*fcf5ef2aSThomas Huth             gdb_do_syscall(m68k_semi_cb, "unlink,%s",
319*fcf5ef2aSThomas Huth                            arg0, (int)arg1);
320*fcf5ef2aSThomas Huth             return;
321*fcf5ef2aSThomas Huth         } else {
322*fcf5ef2aSThomas Huth             p = lock_user_string(arg0);
323*fcf5ef2aSThomas Huth             if (!p) {
324*fcf5ef2aSThomas Huth                 /* FIXME - check error code? */
325*fcf5ef2aSThomas Huth                 result = -1;
326*fcf5ef2aSThomas Huth             } else {
327*fcf5ef2aSThomas Huth                 result = unlink(p);
328*fcf5ef2aSThomas Huth                 unlock_user(p, arg0, 0);
329*fcf5ef2aSThomas Huth             }
330*fcf5ef2aSThomas Huth         }
331*fcf5ef2aSThomas Huth         break;
332*fcf5ef2aSThomas Huth     case HOSTED_STAT:
333*fcf5ef2aSThomas Huth         GET_ARG(0);
334*fcf5ef2aSThomas Huth         GET_ARG(1);
335*fcf5ef2aSThomas Huth         GET_ARG(2);
336*fcf5ef2aSThomas Huth         if (use_gdb_syscalls()) {
337*fcf5ef2aSThomas Huth             gdb_do_syscall(m68k_semi_cb, "stat,%s,%x",
338*fcf5ef2aSThomas Huth                            arg0, (int)arg1, arg2);
339*fcf5ef2aSThomas Huth             return;
340*fcf5ef2aSThomas Huth         } else {
341*fcf5ef2aSThomas Huth             struct stat s;
342*fcf5ef2aSThomas Huth             p = lock_user_string(arg0);
343*fcf5ef2aSThomas Huth             if (!p) {
344*fcf5ef2aSThomas Huth                 /* FIXME - check error code? */
345*fcf5ef2aSThomas Huth                 result = -1;
346*fcf5ef2aSThomas Huth             } else {
347*fcf5ef2aSThomas Huth                 result = stat(p, &s);
348*fcf5ef2aSThomas Huth                 unlock_user(p, arg0, 0);
349*fcf5ef2aSThomas Huth             }
350*fcf5ef2aSThomas Huth             if (result == 0) {
351*fcf5ef2aSThomas Huth                 translate_stat(env, arg2, &s);
352*fcf5ef2aSThomas Huth             }
353*fcf5ef2aSThomas Huth         }
354*fcf5ef2aSThomas Huth         break;
355*fcf5ef2aSThomas Huth     case HOSTED_FSTAT:
356*fcf5ef2aSThomas Huth         GET_ARG(0);
357*fcf5ef2aSThomas Huth         GET_ARG(1);
358*fcf5ef2aSThomas Huth         if (use_gdb_syscalls()) {
359*fcf5ef2aSThomas Huth             gdb_do_syscall(m68k_semi_cb, "fstat,%x,%x",
360*fcf5ef2aSThomas Huth                            arg0, arg1);
361*fcf5ef2aSThomas Huth             return;
362*fcf5ef2aSThomas Huth         } else {
363*fcf5ef2aSThomas Huth             struct stat s;
364*fcf5ef2aSThomas Huth             result = fstat(arg0, &s);
365*fcf5ef2aSThomas Huth             if (result == 0) {
366*fcf5ef2aSThomas Huth                 translate_stat(env, arg1, &s);
367*fcf5ef2aSThomas Huth             }
368*fcf5ef2aSThomas Huth         }
369*fcf5ef2aSThomas Huth         break;
370*fcf5ef2aSThomas Huth     case HOSTED_GETTIMEOFDAY:
371*fcf5ef2aSThomas Huth         GET_ARG(0);
372*fcf5ef2aSThomas Huth         GET_ARG(1);
373*fcf5ef2aSThomas Huth         if (use_gdb_syscalls()) {
374*fcf5ef2aSThomas Huth             gdb_do_syscall(m68k_semi_cb, "gettimeofday,%x,%x",
375*fcf5ef2aSThomas Huth                            arg0, arg1);
376*fcf5ef2aSThomas Huth             return;
377*fcf5ef2aSThomas Huth         } else {
378*fcf5ef2aSThomas Huth             qemu_timeval tv;
379*fcf5ef2aSThomas Huth             struct gdb_timeval *p;
380*fcf5ef2aSThomas Huth             result = qemu_gettimeofday(&tv);
381*fcf5ef2aSThomas Huth             if (result != 0) {
382*fcf5ef2aSThomas Huth                 if (!(p = lock_user(VERIFY_WRITE,
383*fcf5ef2aSThomas Huth                                     arg0, sizeof(struct gdb_timeval), 0))) {
384*fcf5ef2aSThomas Huth                     /* FIXME - check error code? */
385*fcf5ef2aSThomas Huth                     result = -1;
386*fcf5ef2aSThomas Huth                 } else {
387*fcf5ef2aSThomas Huth                     p->tv_sec = cpu_to_be32(tv.tv_sec);
388*fcf5ef2aSThomas Huth                     p->tv_usec = cpu_to_be64(tv.tv_usec);
389*fcf5ef2aSThomas Huth                     unlock_user(p, arg0, sizeof(struct gdb_timeval));
390*fcf5ef2aSThomas Huth                 }
391*fcf5ef2aSThomas Huth             }
392*fcf5ef2aSThomas Huth         }
393*fcf5ef2aSThomas Huth         break;
394*fcf5ef2aSThomas Huth     case HOSTED_ISATTY:
395*fcf5ef2aSThomas Huth         GET_ARG(0);
396*fcf5ef2aSThomas Huth         if (use_gdb_syscalls()) {
397*fcf5ef2aSThomas Huth             gdb_do_syscall(m68k_semi_cb, "isatty,%x", arg0);
398*fcf5ef2aSThomas Huth             return;
399*fcf5ef2aSThomas Huth         } else {
400*fcf5ef2aSThomas Huth             result = isatty(arg0);
401*fcf5ef2aSThomas Huth         }
402*fcf5ef2aSThomas Huth         break;
403*fcf5ef2aSThomas Huth     case HOSTED_SYSTEM:
404*fcf5ef2aSThomas Huth         GET_ARG(0);
405*fcf5ef2aSThomas Huth         GET_ARG(1);
406*fcf5ef2aSThomas Huth         if (use_gdb_syscalls()) {
407*fcf5ef2aSThomas Huth             gdb_do_syscall(m68k_semi_cb, "system,%s",
408*fcf5ef2aSThomas Huth                            arg0, (int)arg1);
409*fcf5ef2aSThomas Huth             return;
410*fcf5ef2aSThomas Huth         } else {
411*fcf5ef2aSThomas Huth             p = lock_user_string(arg0);
412*fcf5ef2aSThomas Huth             if (!p) {
413*fcf5ef2aSThomas Huth                 /* FIXME - check error code? */
414*fcf5ef2aSThomas Huth                 result = -1;
415*fcf5ef2aSThomas Huth             } else {
416*fcf5ef2aSThomas Huth                 result = system(p);
417*fcf5ef2aSThomas Huth                 unlock_user(p, arg0, 0);
418*fcf5ef2aSThomas Huth             }
419*fcf5ef2aSThomas Huth         }
420*fcf5ef2aSThomas Huth         break;
421*fcf5ef2aSThomas Huth     case HOSTED_INIT_SIM:
422*fcf5ef2aSThomas Huth #if defined(CONFIG_USER_ONLY)
423*fcf5ef2aSThomas Huth         {
424*fcf5ef2aSThomas Huth         CPUState *cs = CPU(m68k_env_get_cpu(env));
425*fcf5ef2aSThomas Huth         TaskState *ts = cs->opaque;
426*fcf5ef2aSThomas Huth         /* Allocate the heap using sbrk.  */
427*fcf5ef2aSThomas Huth         if (!ts->heap_limit) {
428*fcf5ef2aSThomas Huth             abi_ulong ret;
429*fcf5ef2aSThomas Huth             uint32_t size;
430*fcf5ef2aSThomas Huth             uint32_t base;
431*fcf5ef2aSThomas Huth 
432*fcf5ef2aSThomas Huth             base = do_brk(0);
433*fcf5ef2aSThomas Huth             size = SEMIHOSTING_HEAP_SIZE;
434*fcf5ef2aSThomas Huth             /* Try a big heap, and reduce the size if that fails.  */
435*fcf5ef2aSThomas Huth             for (;;) {
436*fcf5ef2aSThomas Huth                 ret = do_brk(base + size);
437*fcf5ef2aSThomas Huth                 if (ret >= (base + size)) {
438*fcf5ef2aSThomas Huth                     break;
439*fcf5ef2aSThomas Huth                 }
440*fcf5ef2aSThomas Huth                 size >>= 1;
441*fcf5ef2aSThomas Huth             }
442*fcf5ef2aSThomas Huth             ts->heap_limit = base + size;
443*fcf5ef2aSThomas Huth         }
444*fcf5ef2aSThomas Huth         /* This call may happen before we have writable memory, so return
445*fcf5ef2aSThomas Huth            values directly in registers.  */
446*fcf5ef2aSThomas Huth         env->dregs[1] = ts->heap_limit;
447*fcf5ef2aSThomas Huth         env->aregs[7] = ts->stack_base;
448*fcf5ef2aSThomas Huth         }
449*fcf5ef2aSThomas Huth #else
450*fcf5ef2aSThomas Huth         /* FIXME: This is wrong for boards where RAM does not start at
451*fcf5ef2aSThomas Huth            address zero.  */
452*fcf5ef2aSThomas Huth         env->dregs[1] = ram_size;
453*fcf5ef2aSThomas Huth         env->aregs[7] = ram_size;
454*fcf5ef2aSThomas Huth #endif
455*fcf5ef2aSThomas Huth         return;
456*fcf5ef2aSThomas Huth     default:
457*fcf5ef2aSThomas Huth         cpu_abort(CPU(m68k_env_get_cpu(env)), "Unsupported semihosting syscall %d\n", nr);
458*fcf5ef2aSThomas Huth         result = 0;
459*fcf5ef2aSThomas Huth     }
460*fcf5ef2aSThomas Huth failed:
461*fcf5ef2aSThomas Huth     m68k_semi_return_u32(env, result, errno);
462*fcf5ef2aSThomas Huth }
463