2 * m68k/ColdFire Semihosting syscall interface
4 * Copyright (c) 2005-2007 CodeSourcery.
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.
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.
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/>.
20 #include "qemu/osdep.h"
23 #include "exec/gdbstub.h"
24 #include "semihosting/softmmu-uaccess.h"
25 #include "hw/boards.h"
29 #define HOSTED_INIT_SIM 1
31 #define HOSTED_CLOSE 3
33 #define HOSTED_WRITE 5
34 #define HOSTED_LSEEK 6
35 #define HOSTED_RENAME 7
36 #define HOSTED_UNLINK 8
38 #define HOSTED_FSTAT 10
39 #define HOSTED_GETTIMEOFDAY 11
40 #define HOSTED_ISATTY 12
41 #define HOSTED_SYSTEM 13
43 static int translate_openflags(int flags
)
47 if (flags
& GDB_O_WRONLY
)
49 else if (flags
& GDB_O_RDWR
)
54 if (flags
& GDB_O_APPEND
) hf
|= O_APPEND
;
55 if (flags
& GDB_O_CREAT
) hf
|= O_CREAT
;
56 if (flags
& GDB_O_TRUNC
) hf
|= O_TRUNC
;
57 if (flags
& GDB_O_EXCL
) hf
|= O_EXCL
;
62 static void translate_stat(CPUM68KState
*env
, target_ulong addr
, struct stat
*s
)
66 p
= lock_user(VERIFY_WRITE
, addr
, sizeof(struct gdb_stat
), 0);
68 /* FIXME - should this return an error code? */
71 p
->gdb_st_dev
= cpu_to_be32(s
->st_dev
);
72 p
->gdb_st_ino
= cpu_to_be32(s
->st_ino
);
73 p
->gdb_st_mode
= cpu_to_be32(s
->st_mode
);
74 p
->gdb_st_nlink
= cpu_to_be32(s
->st_nlink
);
75 p
->gdb_st_uid
= cpu_to_be32(s
->st_uid
);
76 p
->gdb_st_gid
= cpu_to_be32(s
->st_gid
);
77 p
->gdb_st_rdev
= cpu_to_be32(s
->st_rdev
);
78 p
->gdb_st_size
= cpu_to_be64(s
->st_size
);
80 /* Windows stat is missing some fields. */
81 p
->gdb_st_blksize
= 0;
84 p
->gdb_st_blksize
= cpu_to_be64(s
->st_blksize
);
85 p
->gdb_st_blocks
= cpu_to_be64(s
->st_blocks
);
87 p
->gdb_st_atime
= cpu_to_be32(s
->st_atime
);
88 p
->gdb_st_mtime
= cpu_to_be32(s
->st_mtime
);
89 p
->gdb_st_ctime
= cpu_to_be32(s
->st_ctime
);
90 unlock_user(p
, addr
, sizeof(struct gdb_stat
));
93 static void m68k_semi_u32_cb(CPUState
*cs
, uint64_t ret
, int err
)
95 M68kCPU
*cpu
= M68K_CPU(cs
);
96 CPUM68KState
*env
= &cpu
->env
;
98 target_ulong args
= env
->dregs
[1];
99 if (put_user_u32(ret
, args
) ||
100 put_user_u32(err
, args
+ 4)) {
102 * The m68k semihosting ABI does not provide any way to report this
103 * error to the guest, so the best we can do is log it in qemu.
104 * It is always a guest error not to pass us a valid argument block.
106 qemu_log_mask(LOG_GUEST_ERROR
, "m68k-semihosting: return value "
107 "discarded because argument block not writable\n");
111 static void m68k_semi_u64_cb(CPUState
*cs
, uint64_t ret
, int err
)
113 M68kCPU
*cpu
= M68K_CPU(cs
);
114 CPUM68KState
*env
= &cpu
->env
;
116 target_ulong args
= env
->dregs
[1];
117 if (put_user_u32(ret
>> 32, args
) ||
118 put_user_u32(ret
, args
+ 4) ||
119 put_user_u32(err
, args
+ 8)) {
120 /* No way to report this via m68k semihosting ABI; just log it */
121 qemu_log_mask(LOG_GUEST_ERROR
, "m68k-semihosting: return value "
122 "discarded because argument block not writable\n");
127 * Read the input value from the argument block; fail the semihosting
128 * call if the memory read fails.
130 #define GET_ARG(n) do { \
131 if (get_user_ual(arg ## n, args + (n) * 4)) { \
138 void do_m68k_semihosting(CPUM68KState
*env
, int nr
)
140 CPUState
*cs
= env_cpu(env
);
142 target_ulong arg0
, arg1
, arg2
, arg3
;
148 args
= env
->dregs
[1];
151 gdb_exit(env
->dregs
[0]);
158 if (use_gdb_syscalls()) {
159 gdb_do_syscall(m68k_semi_u32_cb
, "open,%s,%x,%x", arg0
, (int)arg1
,
163 p
= lock_user_string(arg0
);
165 /* FIXME - check error code? */
168 result
= open(p
, translate_openflags(arg2
), arg3
);
169 unlock_user(p
, arg0
, 0);
175 /* Ignore attempts to close stdin/out/err. */
179 if (use_gdb_syscalls()) {
180 gdb_do_syscall(m68k_semi_u32_cb
, "close,%x", arg0
);
195 if (use_gdb_syscalls()) {
196 gdb_do_syscall(m68k_semi_u32_cb
, "read,%x,%x,%x",
200 p
= lock_user(VERIFY_WRITE
, arg1
, len
, 0);
202 /* FIXME - check error code? */
205 result
= read(arg0
, p
, len
);
206 unlock_user(p
, arg1
, len
);
215 if (use_gdb_syscalls()) {
216 gdb_do_syscall(m68k_semi_u32_cb
, "write,%x,%x,%x",
220 p
= lock_user(VERIFY_READ
, arg1
, len
, 1);
222 /* FIXME - check error code? */
225 result
= write(arg0
, p
, len
);
226 unlock_user(p
, arg0
, 0);
237 off
= (uint32_t)arg2
| ((uint64_t)arg1
<< 32);
238 if (use_gdb_syscalls()) {
239 gdb_do_syscall(m68k_semi_u64_cb
, "fseek,%x,%lx,%x",
242 off
= lseek(arg0
, off
, arg3
);
243 m68k_semi_u64_cb(cs
, off
, errno
);
252 if (use_gdb_syscalls()) {
253 gdb_do_syscall(m68k_semi_u32_cb
, "rename,%s,%s",
254 arg0
, (int)arg1
, arg2
, (int)arg3
);
257 p
= lock_user_string(arg0
);
258 q
= lock_user_string(arg2
);
260 /* FIXME - check error code? */
263 result
= rename(p
, q
);
265 unlock_user(p
, arg0
, 0);
266 unlock_user(q
, arg2
, 0);
272 if (use_gdb_syscalls()) {
273 gdb_do_syscall(m68k_semi_u32_cb
, "unlink,%s",
277 p
= lock_user_string(arg0
);
279 /* FIXME - check error code? */
283 unlock_user(p
, arg0
, 0);
291 if (use_gdb_syscalls()) {
292 gdb_do_syscall(m68k_semi_u32_cb
, "stat,%s,%x",
293 arg0
, (int)arg1
, arg2
);
297 p
= lock_user_string(arg0
);
299 /* FIXME - check error code? */
302 result
= stat(p
, &s
);
303 unlock_user(p
, arg0
, 0);
306 translate_stat(env
, arg2
, &s
);
313 if (use_gdb_syscalls()) {
314 gdb_do_syscall(m68k_semi_u32_cb
, "fstat,%x,%x",
319 result
= fstat(arg0
, &s
);
321 translate_stat(env
, arg1
, &s
);
325 case HOSTED_GETTIMEOFDAY
:
328 if (use_gdb_syscalls()) {
329 gdb_do_syscall(m68k_semi_u32_cb
, "gettimeofday,%x,%x",
333 struct gdb_timeval
*p
;
334 int64_t rt
= g_get_real_time();
335 p
= lock_user(VERIFY_WRITE
, arg0
, sizeof(struct gdb_timeval
), 0);
337 /* FIXME - check error code? */
341 p
->tv_sec
= cpu_to_be32(rt
/ G_USEC_PER_SEC
);
342 p
->tv_usec
= cpu_to_be64(rt
% G_USEC_PER_SEC
);
343 unlock_user(p
, arg0
, sizeof(struct gdb_timeval
));
349 if (use_gdb_syscalls()) {
350 gdb_do_syscall(m68k_semi_u32_cb
, "isatty,%x", arg0
);
353 result
= isatty(arg0
);
359 if (use_gdb_syscalls()) {
360 gdb_do_syscall(m68k_semi_u32_cb
, "system,%s",
364 p
= lock_user_string(arg0
);
366 /* FIXME - check error code? */
370 unlock_user(p
, arg0
, 0);
374 case HOSTED_INIT_SIM
:
376 * FIXME: This is wrong for boards where RAM does not start at
379 env
->dregs
[1] = current_machine
->ram_size
;
380 env
->aregs
[7] = current_machine
->ram_size
;
383 cpu_abort(env_cpu(env
), "Unsupported semihosting syscall %d\n", nr
);
387 m68k_semi_u32_cb(cs
, result
, errno
);