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