Revision a87295e8
b/Makefile.target | ||
---|---|---|
468 | 468 |
endif |
469 | 469 |
ifeq ($(TARGET_BASE_ARCH), m68k) |
470 | 470 |
VL_OBJS+= an5206.o mcf5206.o ptimer.o |
471 |
VL_OBJS+= m68k-semi.o |
|
471 | 472 |
endif |
472 | 473 |
ifdef CONFIG_GDBSTUB |
473 | 474 |
VL_OBJS+=gdbstub.o |
b/arm-semi.c | ||
---|---|---|
112 | 112 |
return code; |
113 | 113 |
} |
114 | 114 |
|
115 |
static uint32_t softmmu_tget32(CPUState *env, uint32_t addr) |
|
116 |
{ |
|
117 |
uint32_t val; |
|
118 |
|
|
119 |
cpu_memory_rw_debug(env, addr, (uint8_t *)&val, 4, 0); |
|
120 |
return tswap32(val); |
|
121 |
} |
|
122 |
static uint32_t softmmu_tget8(CPUState *env, uint32_t addr) |
|
123 |
{ |
|
124 |
uint8_t val; |
|
125 |
|
|
126 |
cpu_memory_rw_debug(env, addr, &val, 1, 0); |
|
127 |
return val; |
|
128 |
} |
|
129 |
#define tget32(p) softmmu_tget32(env, p) |
|
130 |
#define tget8(p) softmmu_tget8(env, p) |
|
131 |
|
|
132 |
static void *softmmu_lock_user(CPUState *env, uint32_t addr, uint32_t len, |
|
133 |
int copy) |
|
134 |
{ |
|
135 |
char *p; |
|
136 |
/* TODO: Make this something that isn't fixed size. */ |
|
137 |
p = malloc(len); |
|
138 |
if (copy) |
|
139 |
cpu_memory_rw_debug(env, addr, p, len, 0); |
|
140 |
return p; |
|
141 |
} |
|
142 |
#define lock_user(p, len, copy) softmmu_lock_user(env, p, len, copy) |
|
143 |
static char *softmmu_lock_user_string(CPUState *env, uint32_t addr) |
|
144 |
{ |
|
145 |
char *p; |
|
146 |
char *s; |
|
147 |
uint8_t c; |
|
148 |
/* TODO: Make this something that isn't fixed size. */ |
|
149 |
s = p = malloc(1024); |
|
150 |
do { |
|
151 |
cpu_memory_rw_debug(env, addr, &c, 1, 0); |
|
152 |
addr++; |
|
153 |
*(p++) = c; |
|
154 |
} while (c); |
|
155 |
return s; |
|
156 |
} |
|
157 |
#define lock_user_string(p) softmmu_lock_user_string(env, p) |
|
158 |
static void softmmu_unlock_user(CPUState *env, void *p, target_ulong addr, |
|
159 |
target_ulong len) |
|
160 |
{ |
|
161 |
if (len) |
|
162 |
cpu_memory_rw_debug(env, addr, p, len, 1); |
|
163 |
free(p); |
|
164 |
} |
|
165 |
#define unlock_user(s, args, len) softmmu_unlock_user(env, s, args, len) |
|
115 |
#include "softmmu-semi.h" |
|
166 | 116 |
#endif |
167 | 117 |
|
168 | 118 |
static target_ulong arm_semi_syscall_len; |
b/gdbstub.c | ||
---|---|---|
963 | 963 |
|
964 | 964 |
/* Send a gdb syscall request. |
965 | 965 |
This accepts limited printf-style format specifiers, specifically: |
966 |
%x - target_ulong argument printed in hex. |
|
967 |
%s - string pointer (target_ulong) and length (int) pair. */ |
|
966 |
%x - target_ulong argument printed in hex. |
|
967 |
%lx - 64-bit argument printed in hex. |
|
968 |
%s - string pointer (target_ulong) and length (int) pair. */ |
|
968 | 969 |
void gdb_do_syscall(gdb_syscall_complete_cb cb, char *fmt, ...) |
969 | 970 |
{ |
970 | 971 |
va_list va; |
971 | 972 |
char buf[256]; |
972 | 973 |
char *p; |
973 | 974 |
target_ulong addr; |
975 |
uint64_t i64; |
|
974 | 976 |
GDBState *s; |
975 | 977 |
|
976 | 978 |
s = gdb_syscall_state; |
... | ... | |
993 | 995 |
addr = va_arg(va, target_ulong); |
994 | 996 |
p += sprintf(p, TARGET_FMT_lx, addr); |
995 | 997 |
break; |
998 |
case 'l': |
|
999 |
if (*(fmt++) != 'x') |
|
1000 |
goto bad_format; |
|
1001 |
i64 = va_arg(va, uint64_t); |
|
1002 |
p += sprintf(p, "%" PRIx64, i64); |
|
1003 |
break; |
|
996 | 1004 |
case 's': |
997 | 1005 |
addr = va_arg(va, target_ulong); |
998 | 1006 |
p += sprintf(p, TARGET_FMT_lx "/%x", addr, va_arg(va, int)); |
999 | 1007 |
break; |
1000 | 1008 |
default: |
1009 |
bad_format: |
|
1001 | 1010 |
fprintf(stderr, "gdbstub: Bad syscall format string '%s'\n", |
1002 | 1011 |
fmt - 1); |
1003 | 1012 |
break; |
/dev/null | ||
---|---|---|
1 |
/* |
|
2 |
* m68k/ColdFire Semihosting ssycall 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, write to the Free Software |
|
18 |
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
|
19 |
*/ |
|
20 |
|
|
21 |
#include <sys/types.h> |
|
22 |
#include <sys/stat.h> |
|
23 |
#include <errno.h> |
|
24 |
#include <fcntl.h> |
|
25 |
#include <unistd.h> |
|
26 |
#include <stdlib.h> |
|
27 |
#include <stdio.h> |
|
28 |
#include <sys/time.h> |
|
29 |
#include <time.h> |
|
30 |
|
|
31 |
#include "qemu.h" |
|
32 |
|
|
33 |
#define HOSTED_EXIT 0 |
|
34 |
#define HOSTED_PUTCHAR 1 /* Obsolete */ |
|
35 |
#define HOSTED_OPEN 2 |
|
36 |
#define HOSTED_CLOSE 3 |
|
37 |
#define HOSTED_READ 4 |
|
38 |
#define HOSTED_WRITE 5 |
|
39 |
#define HOSTED_LSEEK 6 |
|
40 |
#define HOSTED_RENAME 7 |
|
41 |
#define HOSTED_UNLINK 8 |
|
42 |
#define HOSTED_STAT 9 |
|
43 |
#define HOSTED_FSTAT 10 |
|
44 |
#define HOSTED_GETTIMEOFDAY 11 |
|
45 |
#define HOSTED_ISATTY 12 |
|
46 |
#define HOSTED_SYSTEM 13 |
|
47 |
|
|
48 |
typedef uint32_t gdb_mode_t; |
|
49 |
typedef uint32_t gdb_time_t; |
|
50 |
|
|
51 |
struct m68k_gdb_stat { |
|
52 |
uint32_t gdb_st_dev; /* device */ |
|
53 |
uint32_t gdb_st_ino; /* inode */ |
|
54 |
gdb_mode_t gdb_st_mode; /* protection */ |
|
55 |
uint32_t gdb_st_nlink; /* number of hard links */ |
|
56 |
uint32_t gdb_st_uid; /* user ID of owner */ |
|
57 |
uint32_t gdb_st_gid; /* group ID of owner */ |
|
58 |
uint32_t gdb_st_rdev; /* device type (if inode device) */ |
|
59 |
uint64_t gdb_st_size; /* total size, in bytes */ |
|
60 |
uint64_t gdb_st_blksize; /* blocksize for filesystem I/O */ |
|
61 |
uint64_t gdb_st_blocks; /* number of blocks allocated */ |
|
62 |
gdb_time_t gdb_st_atime; /* time of last access */ |
|
63 |
gdb_time_t gdb_st_mtime; /* time of last modification */ |
|
64 |
gdb_time_t gdb_st_ctime; /* time of last change */ |
|
65 |
}; |
|
66 |
|
|
67 |
struct gdb_timeval { |
|
68 |
gdb_time_t tv_sec; /* second */ |
|
69 |
uint64_t tv_usec; /* microsecond */ |
|
70 |
}; |
|
71 |
|
|
72 |
#define GDB_O_RDONLY 0x0 |
|
73 |
#define GDB_O_WRONLY 0x1 |
|
74 |
#define GDB_O_RDWR 0x2 |
|
75 |
#define GDB_O_APPEND 0x8 |
|
76 |
#define GDB_O_CREAT 0x200 |
|
77 |
#define GDB_O_TRUNC 0x400 |
|
78 |
#define GDB_O_EXCL 0x800 |
|
79 |
|
|
80 |
static int translate_openflags(int flags) |
|
81 |
{ |
|
82 |
int hf; |
|
83 |
|
|
84 |
if (flags & GDB_O_WRONLY) |
|
85 |
hf = O_WRONLY; |
|
86 |
else if (flags & GDB_O_RDWR) |
|
87 |
hf = O_RDWR; |
|
88 |
else |
|
89 |
hf = O_RDONLY; |
|
90 |
|
|
91 |
if (flags & GDB_O_APPEND) hf |= O_APPEND; |
|
92 |
if (flags & GDB_O_CREAT) hf |= O_CREAT; |
|
93 |
if (flags & GDB_O_TRUNC) hf |= O_TRUNC; |
|
94 |
if (flags & GDB_O_EXCL) hf |= O_EXCL; |
|
95 |
|
|
96 |
return hf; |
|
97 |
} |
|
98 |
|
|
99 |
static void translate_stat(struct m68k_gdb_stat *p, struct stat *s) |
|
100 |
{ |
|
101 |
p->gdb_st_dev = tswap16(s->st_dev); |
|
102 |
p->gdb_st_ino = tswap16(s->st_ino); |
|
103 |
p->gdb_st_mode = tswap32(s->st_mode); |
|
104 |
p->gdb_st_nlink = tswap16(s->st_nlink); |
|
105 |
p->gdb_st_uid = tswap16(s->st_uid); |
|
106 |
p->gdb_st_gid = tswap16(s->st_gid); |
|
107 |
p->gdb_st_rdev = tswap16(s->st_rdev); |
|
108 |
p->gdb_st_size = tswap32(s->st_size); |
|
109 |
p->gdb_st_atime = tswap32(s->st_atime); |
|
110 |
p->gdb_st_mtime = tswap32(s->st_mtime); |
|
111 |
p->gdb_st_ctime = tswap32(s->st_ctime); |
|
112 |
p->gdb_st_blksize = tswap32(s->st_blksize); |
|
113 |
p->gdb_st_blocks = tswap32(s->st_blocks); |
|
114 |
} |
|
115 |
|
|
116 |
static inline uint32_t check_err(CPUM68KState *env, uint32_t code) |
|
117 |
{ |
|
118 |
if (code == (uint32_t)-1) { |
|
119 |
env->sr |= CCF_C; |
|
120 |
} else { |
|
121 |
env->sr &= ~CCF_C; |
|
122 |
env->dregs[0] = code; |
|
123 |
} |
|
124 |
return code; |
|
125 |
} |
|
126 |
|
|
127 |
#define ARG(x) tswap32(args[x]) |
|
128 |
void do_m68k_semihosting(CPUM68KState *env, int nr) |
|
129 |
{ |
|
130 |
uint32_t *args; |
|
131 |
|
|
132 |
args = (uint32_t *)env->dregs[1]; |
|
133 |
switch (nr) { |
|
134 |
case HOSTED_EXIT: |
|
135 |
exit(env->dregs[0]); |
|
136 |
case HOSTED_OPEN: |
|
137 |
/* Assume name is NULL terminated. */ |
|
138 |
check_err(env, open((char *)ARG(0), translate_openflags(ARG(2)), |
|
139 |
ARG(3))); |
|
140 |
break; |
|
141 |
case HOSTED_CLOSE: |
|
142 |
{ |
|
143 |
/* Ignore attempts to close stdin/out/err. */ |
|
144 |
int fd = ARG(0); |
|
145 |
if (fd > 2) |
|
146 |
check_err(env, close(fd)); |
|
147 |
else |
|
148 |
check_err(env, 0); |
|
149 |
break; |
|
150 |
} |
|
151 |
case HOSTED_READ: |
|
152 |
check_err(env, read(ARG(0), (void *)ARG(1), ARG(2))); |
|
153 |
break; |
|
154 |
case HOSTED_WRITE: |
|
155 |
check_err(env, write(ARG(0), (void *)ARG(1), ARG(2))); |
|
156 |
break; |
|
157 |
case HOSTED_LSEEK: |
|
158 |
{ |
|
159 |
uint64_t off; |
|
160 |
off = (uint32_t)ARG(2) | ((uint64_t)ARG(1) << 32); |
|
161 |
check_err(env, lseek(ARG(0), off, ARG(3))); |
|
162 |
} |
|
163 |
break; |
|
164 |
case HOSTED_RENAME: |
|
165 |
/* Assume names are NULL terminated. */ |
|
166 |
check_err(env, rename((char *)ARG(0), (char *)ARG(2))); |
|
167 |
break; |
|
168 |
case HOSTED_UNLINK: |
|
169 |
/* Assume name is NULL terminated. */ |
|
170 |
check_err(env, unlink((char *)ARG(0))); |
|
171 |
break; |
|
172 |
case HOSTED_STAT: |
|
173 |
/* Assume name is NULL terminated. */ |
|
174 |
{ |
|
175 |
struct stat s; |
|
176 |
int rc; |
|
177 |
rc = check_err(env, stat((char *)ARG(0), &s)); |
|
178 |
if (rc == 0) { |
|
179 |
translate_stat((struct m68k_gdb_stat *)ARG(2), &s); |
|
180 |
} |
|
181 |
} |
|
182 |
break; |
|
183 |
case HOSTED_FSTAT: |
|
184 |
{ |
|
185 |
struct stat s; |
|
186 |
int rc; |
|
187 |
rc = check_err(env, fstat(ARG(0), &s)); |
|
188 |
if (rc == 0) { |
|
189 |
translate_stat((struct m68k_gdb_stat *)ARG(1), &s); |
|
190 |
} |
|
191 |
} |
|
192 |
break; |
|
193 |
case HOSTED_GETTIMEOFDAY: |
|
194 |
{ |
|
195 |
struct timeval tv; |
|
196 |
struct gdb_timeval *p; |
|
197 |
int rc; |
|
198 |
rc = check_err(env, gettimeofday(&tv, NULL)); |
|
199 |
if (rc != 0) { |
|
200 |
p = (struct gdb_timeval *)ARG(0); |
|
201 |
p->tv_sec = tswap32(tv.tv_sec); |
|
202 |
p->tv_usec = tswap64(tv.tv_usec); |
|
203 |
} |
|
204 |
} |
|
205 |
break; |
|
206 |
case HOSTED_ISATTY: |
|
207 |
check_err(env, isatty(ARG(0))); |
|
208 |
break; |
|
209 |
case HOSTED_SYSTEM: |
|
210 |
/* Assume name is NULL terminated. */ |
|
211 |
check_err(env, system((char *)ARG(0))); |
|
212 |
break; |
|
213 |
default: |
|
214 |
cpu_abort(env, "Unsupported semihosting syscall %d\n", nr); |
|
215 |
} |
|
216 |
} |
b/linux-user/main.c | ||
---|---|---|
1502 | 1502 |
} |
1503 | 1503 |
} |
1504 | 1504 |
break; |
1505 |
case EXCP_HALTED:
|
|
1505 |
case EXCP_HALT_INSN:
|
|
1506 | 1506 |
/* Semihosing syscall. */ |
1507 |
env->pc += 2;
|
|
1507 |
env->pc += 4;
|
|
1508 | 1508 |
do_m68k_semihosting(env, env->dregs[0]); |
1509 | 1509 |
break; |
1510 | 1510 |
case EXCP_LINEA: |
... | ... | |
1918 | 1918 |
for(i = 0; i < 16; i++) { |
1919 | 1919 |
env->regs[i] = regs->uregs[i]; |
1920 | 1920 |
} |
1921 |
ts->stack_base = info->start_stack; |
|
1922 |
ts->heap_base = info->brk; |
|
1923 |
/* This will be filled in on the first SYS_HEAPINFO call. */ |
|
1924 |
ts->heap_limit = 0; |
|
1925 | 1921 |
} |
1926 | 1922 |
#elif defined(TARGET_SPARC) |
1927 | 1923 |
{ |
... | ... | |
2049 | 2045 |
#error unsupported target CPU |
2050 | 2046 |
#endif |
2051 | 2047 |
|
2048 |
#if defined(TARGET_ARM) || defined(TARGET_M68K) |
|
2049 |
ts->stack_base = info->start_stack; |
|
2050 |
ts->heap_base = info->brk; |
|
2051 |
/* This will be filled in on the first SYS_HEAPINFO call. */ |
|
2052 |
ts->heap_limit = 0; |
|
2053 |
#endif |
|
2054 |
|
|
2052 | 2055 |
if (gdbstub_port) { |
2053 | 2056 |
gdbserver_start (gdbstub_port); |
2054 | 2057 |
gdb_handlesig(env, 0); |
b/linux-user/qemu.h | ||
---|---|---|
62 | 62 |
#ifdef TARGET_ARM |
63 | 63 |
/* FPA state */ |
64 | 64 |
FPA11 fpa; |
65 |
/* Extra fields for semihosted binaries. */ |
|
66 |
uint32_t stack_base; |
|
67 |
uint32_t heap_base; |
|
68 |
uint32_t heap_limit; |
|
69 | 65 |
int swi_errno; |
70 | 66 |
#endif |
71 | 67 |
#if defined(TARGET_I386) && !defined(TARGET_X86_64) |
... | ... | |
78 | 74 |
#ifdef TARGET_M68K |
79 | 75 |
int sim_syscalls; |
80 | 76 |
#endif |
77 |
#if defined(TARGET_ARM) || defined(TARGET_M68K) |
|
78 |
/* Extra fields for semihosted binaries. */ |
|
79 |
uint32_t stack_base; |
|
80 |
uint32_t heap_base; |
|
81 |
uint32_t heap_limit; |
|
82 |
#endif |
|
81 | 83 |
int used; /* non zero if used */ |
82 | 84 |
struct image_info *info; |
83 | 85 |
uint8_t stack[0]; |
b/m68k-semi.c | ||
---|---|---|
1 |
/* |
|
2 |
* m68k/ColdFire Semihosting syscall interface |
|
3 |
* |
|
4 |
* Copyright (c) 2005-2007 CodeSourcery. |
|
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, write to the Free Software |
|
18 |
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
|
19 |
*/ |
|
20 |
|
|
21 |
#include <sys/types.h> |
|
22 |
#include <sys/stat.h> |
|
23 |
#include <errno.h> |
|
24 |
#include <fcntl.h> |
|
25 |
#include <unistd.h> |
|
26 |
#include <stdlib.h> |
|
27 |
#include <stdio.h> |
|
28 |
#include <sys/time.h> |
|
29 |
#include <time.h> |
|
30 |
|
|
31 |
#include "cpu.h" |
|
32 |
#if defined(CONFIG_USER_ONLY) |
|
33 |
#include "qemu.h" |
|
34 |
#define SEMIHOSTING_HEAP_SIZE (128 * 1024 * 1024) |
|
35 |
#else |
|
36 |
#include "vl.h" |
|
37 |
#include "softmmu-semi.h" |
|
38 |
#endif |
|
39 |
|
|
40 |
#define HOSTED_EXIT 0 |
|
41 |
#define HOSTED_INIT_SIM 1 |
|
42 |
#define HOSTED_OPEN 2 |
|
43 |
#define HOSTED_CLOSE 3 |
|
44 |
#define HOSTED_READ 4 |
|
45 |
#define HOSTED_WRITE 5 |
|
46 |
#define HOSTED_LSEEK 6 |
|
47 |
#define HOSTED_RENAME 7 |
|
48 |
#define HOSTED_UNLINK 8 |
|
49 |
#define HOSTED_STAT 9 |
|
50 |
#define HOSTED_FSTAT 10 |
|
51 |
#define HOSTED_GETTIMEOFDAY 11 |
|
52 |
#define HOSTED_ISATTY 12 |
|
53 |
#define HOSTED_SYSTEM 13 |
|
54 |
|
|
55 |
typedef uint32_t gdb_mode_t; |
|
56 |
typedef uint32_t gdb_time_t; |
|
57 |
|
|
58 |
struct m68k_gdb_stat { |
|
59 |
uint32_t gdb_st_dev; /* device */ |
|
60 |
uint32_t gdb_st_ino; /* inode */ |
|
61 |
gdb_mode_t gdb_st_mode; /* protection */ |
|
62 |
uint32_t gdb_st_nlink; /* number of hard links */ |
|
63 |
uint32_t gdb_st_uid; /* user ID of owner */ |
|
64 |
uint32_t gdb_st_gid; /* group ID of owner */ |
|
65 |
uint32_t gdb_st_rdev; /* device type (if inode device) */ |
|
66 |
uint64_t gdb_st_size; /* total size, in bytes */ |
|
67 |
uint64_t gdb_st_blksize; /* blocksize for filesystem I/O */ |
|
68 |
uint64_t gdb_st_blocks; /* number of blocks allocated */ |
|
69 |
gdb_time_t gdb_st_atime; /* time of last access */ |
|
70 |
gdb_time_t gdb_st_mtime; /* time of last modification */ |
|
71 |
gdb_time_t gdb_st_ctime; /* time of last change */ |
|
72 |
} __attribute__((packed)); |
|
73 |
|
|
74 |
struct gdb_timeval { |
|
75 |
gdb_time_t tv_sec; /* second */ |
|
76 |
uint64_t tv_usec; /* microsecond */ |
|
77 |
} __attribute__((packed)); |
|
78 |
|
|
79 |
#define GDB_O_RDONLY 0x0 |
|
80 |
#define GDB_O_WRONLY 0x1 |
|
81 |
#define GDB_O_RDWR 0x2 |
|
82 |
#define GDB_O_APPEND 0x8 |
|
83 |
#define GDB_O_CREAT 0x200 |
|
84 |
#define GDB_O_TRUNC 0x400 |
|
85 |
#define GDB_O_EXCL 0x800 |
|
86 |
|
|
87 |
static int translate_openflags(int flags) |
|
88 |
{ |
|
89 |
int hf; |
|
90 |
|
|
91 |
if (flags & GDB_O_WRONLY) |
|
92 |
hf = O_WRONLY; |
|
93 |
else if (flags & GDB_O_RDWR) |
|
94 |
hf = O_RDWR; |
|
95 |
else |
|
96 |
hf = O_RDONLY; |
|
97 |
|
|
98 |
if (flags & GDB_O_APPEND) hf |= O_APPEND; |
|
99 |
if (flags & GDB_O_CREAT) hf |= O_CREAT; |
|
100 |
if (flags & GDB_O_TRUNC) hf |= O_TRUNC; |
|
101 |
if (flags & GDB_O_EXCL) hf |= O_EXCL; |
|
102 |
|
|
103 |
return hf; |
|
104 |
} |
|
105 |
|
|
106 |
static void translate_stat(CPUState *env, target_ulong addr, struct stat *s) |
|
107 |
{ |
|
108 |
struct m68k_gdb_stat *p; |
|
109 |
|
|
110 |
p = lock_user(addr, sizeof(struct m68k_gdb_stat), 0); |
|
111 |
p->gdb_st_dev = cpu_to_be32(s->st_dev); |
|
112 |
p->gdb_st_ino = cpu_to_be32(s->st_ino); |
|
113 |
p->gdb_st_mode = cpu_to_be32(s->st_mode); |
|
114 |
p->gdb_st_nlink = cpu_to_be32(s->st_nlink); |
|
115 |
p->gdb_st_uid = cpu_to_be32(s->st_uid); |
|
116 |
p->gdb_st_gid = cpu_to_be32(s->st_gid); |
|
117 |
p->gdb_st_rdev = cpu_to_be32(s->st_rdev); |
|
118 |
p->gdb_st_size = cpu_to_be64(s->st_size); |
|
119 |
p->gdb_st_blksize = cpu_to_be64(s->st_blksize); |
|
120 |
p->gdb_st_blocks = cpu_to_be64(s->st_blocks); |
|
121 |
p->gdb_st_atime = cpu_to_be32(s->st_atime); |
|
122 |
p->gdb_st_mtime = cpu_to_be32(s->st_mtime); |
|
123 |
p->gdb_st_ctime = cpu_to_be32(s->st_ctime); |
|
124 |
unlock_user(p, addr, sizeof(struct m68k_gdb_stat)); |
|
125 |
} |
|
126 |
|
|
127 |
static int m68k_semi_is_fseek; |
|
128 |
|
|
129 |
static void m68k_semi_cb(CPUState *env, target_ulong ret, target_ulong err) |
|
130 |
{ |
|
131 |
target_ulong args; |
|
132 |
|
|
133 |
args = env->dregs[1]; |
|
134 |
if (m68k_semi_is_fseek) { |
|
135 |
/* FIXME: We've already lost the high bits of the fseek |
|
136 |
return value. */ |
|
137 |
tput32(args, 0); |
|
138 |
args += 4; |
|
139 |
m68k_semi_is_fseek = 0; |
|
140 |
} |
|
141 |
tput32(args, ret); |
|
142 |
tput32(args + 4, errno); |
|
143 |
} |
|
144 |
|
|
145 |
#define ARG(x) tget32(args + (x) * 4) |
|
146 |
#define PARG(x) ((unsigned long)ARG(x)) |
|
147 |
void do_m68k_semihosting(CPUM68KState *env, int nr) |
|
148 |
{ |
|
149 |
uint32_t args; |
|
150 |
void *p; |
|
151 |
void *q; |
|
152 |
uint32_t len; |
|
153 |
uint32_t result; |
|
154 |
|
|
155 |
args = env->dregs[1]; |
|
156 |
switch (nr) { |
|
157 |
case HOSTED_EXIT: |
|
158 |
exit(env->dregs[0]); |
|
159 |
case HOSTED_OPEN: |
|
160 |
if (use_gdb_syscalls()) { |
|
161 |
gdb_do_syscall(m68k_semi_cb, "open,%s,%x,%x", ARG(0), (int)ARG(1), |
|
162 |
ARG(2), ARG(3)); |
|
163 |
return; |
|
164 |
} else { |
|
165 |
p = lock_user_string(ARG(0)); |
|
166 |
result = open(p, translate_openflags(ARG(2)), ARG(3)); |
|
167 |
unlock_user(p, ARG(0), 0); |
|
168 |
} |
|
169 |
break; |
|
170 |
case HOSTED_CLOSE: |
|
171 |
{ |
|
172 |
/* Ignore attempts to close stdin/out/err. */ |
|
173 |
int fd = ARG(0); |
|
174 |
if (fd > 2) { |
|
175 |
if (use_gdb_syscalls()) { |
|
176 |
gdb_do_syscall(m68k_semi_cb, "close,%x", ARG(0)); |
|
177 |
return; |
|
178 |
} else { |
|
179 |
result = close(fd); |
|
180 |
} |
|
181 |
} else { |
|
182 |
result = 0; |
|
183 |
} |
|
184 |
break; |
|
185 |
} |
|
186 |
case HOSTED_READ: |
|
187 |
len = ARG(2); |
|
188 |
if (use_gdb_syscalls()) { |
|
189 |
gdb_do_syscall(m68k_semi_cb, "read,%x,%x,%x", |
|
190 |
ARG(0), ARG(1), len); |
|
191 |
return; |
|
192 |
} else { |
|
193 |
p = lock_user(ARG(1), len, 0); |
|
194 |
result = read(ARG(0), p, len); |
|
195 |
unlock_user(p, ARG(1), len); |
|
196 |
} |
|
197 |
break; |
|
198 |
case HOSTED_WRITE: |
|
199 |
len = ARG(2); |
|
200 |
if (use_gdb_syscalls()) { |
|
201 |
gdb_do_syscall(m68k_semi_cb, "write,%x,%x,%x", |
|
202 |
ARG(0), ARG(1), len); |
|
203 |
return; |
|
204 |
} else { |
|
205 |
p = lock_user(ARG(1), len, 1); |
|
206 |
result = write(ARG(0), p, len); |
|
207 |
unlock_user(p, ARG(0), 0); |
|
208 |
} |
|
209 |
break; |
|
210 |
case HOSTED_LSEEK: |
|
211 |
{ |
|
212 |
uint64_t off; |
|
213 |
off = (uint32_t)ARG(2) | ((uint64_t)ARG(1) << 32); |
|
214 |
if (use_gdb_syscalls()) { |
|
215 |
m68k_semi_is_fseek = 1; |
|
216 |
gdb_do_syscall(m68k_semi_cb, "fseek,%x,%lx,%x", |
|
217 |
ARG(0), off, ARG(3)); |
|
218 |
} else { |
|
219 |
off = lseek(ARG(0), off, ARG(3)); |
|
220 |
tput32(args, off >> 32); |
|
221 |
tput32(args + 4, off); |
|
222 |
tput32(args + 8, errno); |
|
223 |
} |
|
224 |
return; |
|
225 |
} |
|
226 |
case HOSTED_RENAME: |
|
227 |
if (use_gdb_syscalls()) { |
|
228 |
gdb_do_syscall(m68k_semi_cb, "rename,%s,%s", |
|
229 |
ARG(0), (int)ARG(1), ARG(2), (int)ARG(3)); |
|
230 |
return; |
|
231 |
} else { |
|
232 |
p = lock_user_string(ARG(0)); |
|
233 |
q = lock_user_string(ARG(2)); |
|
234 |
result = rename(p, q); |
|
235 |
unlock_user(p, ARG(0), 0); |
|
236 |
unlock_user(q, ARG(2), 0); |
|
237 |
} |
|
238 |
break; |
|
239 |
case HOSTED_UNLINK: |
|
240 |
if (use_gdb_syscalls()) { |
|
241 |
gdb_do_syscall(m68k_semi_cb, "unlink,%s", |
|
242 |
ARG(0), (int)ARG(1)); |
|
243 |
return; |
|
244 |
} else { |
|
245 |
p = lock_user_string(ARG(0)); |
|
246 |
result = unlink(p); |
|
247 |
unlock_user(p, ARG(0), 0); |
|
248 |
} |
|
249 |
break; |
|
250 |
case HOSTED_STAT: |
|
251 |
if (use_gdb_syscalls()) { |
|
252 |
gdb_do_syscall(m68k_semi_cb, "stat,%s,%x", |
|
253 |
ARG(0), (int)ARG(1), ARG(2)); |
|
254 |
return; |
|
255 |
} else { |
|
256 |
struct stat s; |
|
257 |
p = lock_user_string(ARG(0)); |
|
258 |
result = stat(p, &s); |
|
259 |
unlock_user(p, ARG(0), 0); |
|
260 |
if (result == 0) { |
|
261 |
translate_stat(env, ARG(2), &s); |
|
262 |
} |
|
263 |
} |
|
264 |
break; |
|
265 |
case HOSTED_FSTAT: |
|
266 |
if (use_gdb_syscalls()) { |
|
267 |
gdb_do_syscall(m68k_semi_cb, "fstat,%x,%x", |
|
268 |
ARG(0), ARG(1)); |
|
269 |
return; |
|
270 |
} else { |
|
271 |
struct stat s; |
|
272 |
result = fstat(ARG(0), &s); |
|
273 |
if (result == 0) { |
|
274 |
translate_stat(env, ARG(1), &s); |
|
275 |
} |
|
276 |
} |
|
277 |
break; |
|
278 |
case HOSTED_GETTIMEOFDAY: |
|
279 |
if (use_gdb_syscalls()) { |
|
280 |
gdb_do_syscall(m68k_semi_cb, "gettimeofday,%x,%x", |
|
281 |
ARG(0), ARG(1)); |
|
282 |
return; |
|
283 |
} else { |
|
284 |
struct timeval tv; |
|
285 |
struct gdb_timeval *p; |
|
286 |
result = gettimeofday(&tv, NULL); |
|
287 |
if (result != 0) { |
|
288 |
p = lock_user(ARG(0), sizeof(struct gdb_timeval), 0); |
|
289 |
p->tv_sec = cpu_to_be32(tv.tv_sec); |
|
290 |
p->tv_usec = cpu_to_be64(tv.tv_usec); |
|
291 |
unlock_user(p, ARG(0), sizeof(struct gdb_timeval)); |
|
292 |
} |
|
293 |
} |
|
294 |
break; |
|
295 |
case HOSTED_ISATTY: |
|
296 |
if (use_gdb_syscalls()) { |
|
297 |
gdb_do_syscall(m68k_semi_cb, "isatty,%x", ARG(0)); |
|
298 |
return; |
|
299 |
} else { |
|
300 |
result = isatty(ARG(0)); |
|
301 |
} |
|
302 |
break; |
|
303 |
case HOSTED_SYSTEM: |
|
304 |
if (use_gdb_syscalls()) { |
|
305 |
gdb_do_syscall(m68k_semi_cb, "system,%s", |
|
306 |
ARG(0), (int)ARG(1)); |
|
307 |
return; |
|
308 |
} else { |
|
309 |
p = lock_user_string(ARG(0)); |
|
310 |
result = system(p); |
|
311 |
unlock_user(p, ARG(0), 0); |
|
312 |
} |
|
313 |
break; |
|
314 |
case HOSTED_INIT_SIM: |
|
315 |
#if defined(CONFIG_USER_ONLY) |
|
316 |
{ |
|
317 |
TaskState *ts = env->opaque; |
|
318 |
/* Allocate the heap using sbrk. */ |
|
319 |
if (!ts->heap_limit) { |
|
320 |
long ret; |
|
321 |
uint32_t size; |
|
322 |
uint32_t base; |
|
323 |
|
|
324 |
base = do_brk(0); |
|
325 |
size = SEMIHOSTING_HEAP_SIZE; |
|
326 |
/* Try a big heap, and reduce the size if that fails. */ |
|
327 |
for (;;) { |
|
328 |
ret = do_brk(base + size); |
|
329 |
if (ret != -1) |
|
330 |
break; |
|
331 |
size >>= 1; |
|
332 |
} |
|
333 |
ts->heap_limit = base + size; |
|
334 |
} |
|
335 |
/* This call may happen before we have writable memory, so return |
|
336 |
values directly in registers. */ |
|
337 |
env->dregs[1] = ts->heap_limit; |
|
338 |
env->aregs[7] = ts->stack_base; |
|
339 |
} |
|
340 |
#else |
|
341 |
/* FIXME: This is wrong for boards where RAM does not start at |
|
342 |
address zero. */ |
|
343 |
env->dregs[1] = ram_size; |
|
344 |
env->aregs[7] = ram_size; |
|
345 |
#endif |
|
346 |
return; |
|
347 |
default: |
|
348 |
cpu_abort(env, "Unsupported semihosting syscall %d\n", nr); |
|
349 |
result = 0; |
|
350 |
} |
|
351 |
tput32(args, result); |
|
352 |
tput32(args + 4, errno); |
|
353 |
} |
b/qemu-doc.texi | ||
---|---|---|
715 | 715 |
Start right away with a saved state (@code{loadvm} in monitor) |
716 | 716 |
|
717 | 717 |
@item -semihosting |
718 |
Enable "Angel" semihosting interface (ARM target machines only). |
|
718 |
Enable semihosting syscall emulation (ARM and M68K target machines only). |
|
719 |
|
|
720 |
On ARM this implements the "Angel" interface. |
|
721 |
On M68K this implements the "ColdFire GDB" interface used by libgloss. |
|
722 |
|
|
719 | 723 |
Note that this allows guest direct access to the host filesystem, |
720 | 724 |
so should only be used with trusted guest OS. |
721 | 725 |
@end table |
b/target-m68k/cpu.h | ||
---|---|---|
51 | 51 |
#define EXCP_ICE 13 |
52 | 52 |
|
53 | 53 |
#define EXCP_RTE 0x100 |
54 |
#define EXCP_HALT_INSN 0x101 |
|
54 | 55 |
|
55 | 56 |
typedef struct CPUM68KState { |
56 | 57 |
uint32_t dregs[8]; |
... | ... | |
148 | 149 |
|
149 | 150 |
#define M68K_FPCR_PREC (1 << 6) |
150 | 151 |
|
152 |
void do_m68k_semihosting(CPUM68KState *env, int nr); |
|
153 |
|
|
151 | 154 |
#ifdef CONFIG_USER_ONLY |
152 | 155 |
/* Linux uses 8k pages. */ |
153 | 156 |
#define TARGET_PAGE_BITS 13 |
b/target-m68k/op.c | ||
---|---|---|
383 | 383 |
FORCE_RET(); |
384 | 384 |
} |
385 | 385 |
|
386 |
/* Halt is special because it may be a semihosting call. */ |
|
386 | 387 |
OP(halt) |
387 | 388 |
{ |
389 |
RAISE_EXCEPTION(EXCP_HALT_INSN); |
|
390 |
FORCE_RET(); |
|
391 |
} |
|
392 |
|
|
393 |
OP(stop) |
|
394 |
{ |
|
388 | 395 |
env->halted = 1; |
389 | 396 |
RAISE_EXCEPTION(EXCP_HLT); |
390 | 397 |
FORCE_RET(); |
b/target-m68k/op_helper.c | ||
---|---|---|
28 | 28 |
|
29 | 29 |
#else |
30 | 30 |
|
31 |
extern int semihosting_enabled; |
|
32 |
|
|
31 | 33 |
#define MMUSUFFIX _mmu |
32 | 34 |
#define GETPC() (__builtin_return_address(0)) |
33 | 35 |
|
... | ... | |
104 | 106 |
/* Return from an exception. */ |
105 | 107 |
do_rte(); |
106 | 108 |
return; |
109 |
case EXCP_HALT_INSN: |
|
110 |
if (semihosting_enabled |
|
111 |
&& (env->sr & SR_S) != 0 |
|
112 |
&& (env->pc & 3) == 0 |
|
113 |
&& lduw_code(env->pc - 4) == 0x4e71 |
|
114 |
&& ldl_code(env->pc) == 0x4e7bf000) { |
|
115 |
env->pc += 4; |
|
116 |
do_m68k_semihosting(env, env->dregs[0]); |
|
117 |
return; |
|
118 |
} |
|
119 |
env->halted = 1; |
|
120 |
env->exception_index = EXCP_HLT; |
|
121 |
cpu_loop_exit(); |
|
122 |
return; |
|
107 | 123 |
} |
108 | 124 |
if (env->exception_index >= EXCP_TRAP0 |
109 | 125 |
&& env->exception_index <= EXCP_TRAP15) { |
b/target-m68k/translate.c | ||
---|---|---|
1901 | 1901 |
|
1902 | 1902 |
DISAS_INSN(halt) |
1903 | 1903 |
{ |
1904 |
gen_flush_cc_op(s); |
|
1905 | 1904 |
gen_jmp(s, gen_im32(s->pc)); |
1906 | 1905 |
gen_op_halt(); |
1907 | 1906 |
} |
... | ... | |
1919 | 1918 |
s->pc += 2; |
1920 | 1919 |
|
1921 | 1920 |
gen_set_sr_im(s, ext, 0); |
1922 |
disas_halt(s, insn); |
|
1921 |
gen_jmp(s, gen_im32(s->pc)); |
|
1922 |
gen_op_stop(); |
|
1923 | 1923 |
} |
1924 | 1924 |
|
1925 | 1925 |
DISAS_INSN(rte) |
b/vl.c | ||
---|---|---|
6865 | 6865 |
{ "show-cursor", 0, QEMU_OPTION_show_cursor }, |
6866 | 6866 |
{ "daemonize", 0, QEMU_OPTION_daemonize }, |
6867 | 6867 |
{ "option-rom", HAS_ARG, QEMU_OPTION_option_rom }, |
6868 |
#if defined(TARGET_ARM) |
|
6868 |
#if defined(TARGET_ARM) || defined(TARGET_M68K)
|
|
6869 | 6869 |
{ "semihosting", 0, QEMU_OPTION_semihosting }, |
6870 | 6870 |
#endif |
6871 | 6871 |
{ "name", HAS_ARG, QEMU_OPTION_name }, |
Also available in: Unified diff