Commit a87295e8df0923dab9857c1a340d23fe3278a336

Authored by pbrook
1 parent 20c9f095

M68k system mode semihosting.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2861 c046a42c-6fe2-441c-8c8c-71466251a162
Makefile.target
... ... @@ -468,6 +468,7 @@ VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o
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
... ...
arm-semi.c
... ... @@ -112,57 +112,7 @@ static inline uint32_t set_swi_errno(CPUState *env, uint32_t code)
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;
... ...
gdbstub.c
... ... @@ -963,14 +963,16 @@ static void gdb_vm_stopped(void *opaque, int reason)
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,11 +995,18 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb, char *fmt, ...)
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;
... ...
linux-user/m68k-semi.c deleted 100644 โ†’ 0
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   -}
linux-user/main.c
... ... @@ -1502,9 +1502,9 @@ void cpu_loop(CPUM68KState *env)
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,10 +1918,6 @@ int main(int argc, char **argv)
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,6 +2045,13 @@ int main(int argc, char **argv)
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);
... ...
linux-user/qemu.h
... ... @@ -62,10 +62,6 @@ typedef struct TaskState {
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,6 +74,12 @@ typedef struct TaskState {
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];
... ...
m68k-semi.c 0 โ†’ 100644
  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 +}
... ...
qemu-doc.texi
... ... @@ -715,7 +715,11 @@ Exit instead of rebooting.
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
... ...
target-m68k/cpu.h
... ... @@ -51,6 +51,7 @@
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,6 +149,8 @@ void m68k_set_irq_level(CPUM68KState *env, int level, uint8_t vector);
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
... ...
target-m68k/op.c
... ... @@ -383,8 +383,15 @@ OP(divs)
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();
... ...
target-m68k/op_helper.c
... ... @@ -28,6 +28,8 @@ void do_interrupt(int is_hw)
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,6 +106,20 @@ void do_interrupt(int is_hw)
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) {
... ...
target-m68k/translate.c
... ... @@ -1901,7 +1901,6 @@ DISAS_INSN(move_to_usp)
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,7 +1918,8 @@ DISAS_INSN(stop)
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)
... ...
... ... @@ -6865,7 +6865,7 @@ const QEMUOption qemu_options[] = {
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 },
... ...