Commit 8e71621f784b27ac06c3b6301df161e445132b88

Authored by pbrook
1 parent 57be54bb

Add ARM Angel semihosting to system emulation.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2340 c046a42c-6fe2-441c-8c8c-71466251a162
Makefile.target
... ... @@ -397,6 +397,7 @@ VL_OBJS+= integratorcp.o versatilepb.o ps2.o smc91c111.o arm_pic.o arm_timer.o
397 397 VL_OBJS+= arm_boot.o pl011.o pl050.o pl080.o pl110.o pl190.o
398 398 VL_OBJS+= versatile_pci.o
399 399 VL_OBJS+= arm_gic.o realview.o arm_sysctl.o
  400 +VL_OBJS+= arm-semi.o
400 401 endif
401 402 ifeq ($(TARGET_BASE_ARCH), sh4)
402 403 VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o
... ...
linux-user/arm-semi.c renamed to arm-semi.c
1 1 /*
2 2 * Arm "Angel" semihosting syscalls
3 3 *
4   - * Copyright (c) 2005 CodeSourcery, LLC. Written by Paul Brook.
  4 + * Copyright (c) 2005, 2007 CodeSourcery.
  5 + * Written by Paul Brook.
5 6 *
6 7 * This program is free software; you can redistribute it and/or modify
7 8 * it under the terms of the GNU General Public License as published by
... ... @@ -26,9 +27,14 @@
26 27 #include <stdio.h>
27 28 #include <time.h>
28 29  
  30 +#include "cpu.h"
  31 +#ifdef CONFIG_USER_ONLY
29 32 #include "qemu.h"
30 33  
31 34 #define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024)
  35 +#else
  36 +#include "vl.h"
  37 +#endif
32 38  
33 39 #define SYS_OPEN 0x01
34 40 #define SYS_CLOSE 0x02
... ... @@ -70,12 +76,71 @@ int open_modeflags[12] = {
70 76 O_RDWR | O_CREAT | O_APPEND | O_BINARY
71 77 };
72 78  
  79 +#ifdef CONFIG_USER_ONLY
73 80 static inline uint32_t set_swi_errno(TaskState *ts, uint32_t code)
74 81 {
75   - if (code == (uint32_t)-1)
76   - ts->swi_errno = errno;
77   - return code;
  82 + if (code == (uint32_t)-1)
  83 + ts->swi_errno = errno;
  84 + return code;
  85 +}
  86 +#else
  87 +static inline uint32_t set_swi_errno(CPUState *env, uint32_t code)
  88 +{
  89 + return code;
  90 +}
  91 +
  92 +static uint32_t softmmu_tget32(CPUState *env, uint32_t addr)
  93 +{
  94 + uint32_t val;
  95 +
  96 + cpu_memory_rw_debug(env, addr, (uint8_t *)&val, 4, 0);
  97 + return tswap32(val);
78 98 }
  99 +static uint32_t softmmu_tget8(CPUState *env, uint32_t addr)
  100 +{
  101 + uint8_t val;
  102 +
  103 + cpu_memory_rw_debug(env, addr, &val, 1, 0);
  104 + return val;
  105 +}
  106 +#define tget32(p) softmmu_tget32(env, p)
  107 +#define tget8(p) softmmu_tget8(env, p)
  108 +
  109 +static void *softmmu_lock_user(CPUState *env, uint32_t addr, uint32_t len,
  110 + int copy)
  111 +{
  112 + char *p;
  113 + /* TODO: Make this something that isn't fixed size. */
  114 + p = malloc(len);
  115 + if (copy)
  116 + cpu_memory_rw_debug(env, addr, p, len, 0);
  117 + return p;
  118 +}
  119 +#define lock_user(p, len, copy) softmmu_lock_user(env, p, len, copy)
  120 +static char *softmmu_lock_user_string(CPUState *env, uint32_t addr)
  121 +{
  122 + char *p;
  123 + char *s;
  124 + uint8_t c;
  125 + /* TODO: Make this something that isn't fixed size. */
  126 + s = p = malloc(1024);
  127 + do {
  128 + cpu_memory_rw_debug(env, addr, &c, 1, 0);
  129 + addr++;
  130 + *(p++) = c;
  131 + } while (c);
  132 + return s;
  133 +}
  134 +#define lock_user_string(p) softmmu_lock_user_string(env, p)
  135 +static void softmmu_unlock_user(CPUState *env, void *p, target_ulong addr,
  136 + target_ulong len)
  137 +{
  138 + if (len)
  139 + cpu_memory_rw_debug(env, addr, p, len, 1);
  140 + free(p);
  141 +}
  142 +#define unlock_user(s, args, len) softmmu_unlock_user(env, s, args, len)
  143 +#endif
79 144  
80 145 #define ARG(n) tget32(args + (n) * 4)
81 146 #define SET_ARG(n, val) tput32(args + (n) * 4,val)
... ... @@ -85,13 +150,18 @@ uint32_t do_arm_semihosting(CPUState *env)
85 150 char * s;
86 151 int nr;
87 152 uint32_t ret;
  153 + uint32_t len;
  154 +#ifdef CONFIG_USER_ONLY
88 155 TaskState *ts = env->opaque;
  156 +#else
  157 + CPUState *ts = env;
  158 +#endif
89 159  
90 160 nr = env->regs[0];
91 161 args = env->regs[1];
92 162 switch (nr) {
93 163 case SYS_OPEN:
94   - s = (char *)g2h(ARG(0));
  164 + s = lock_user_string(ARG(0));
95 165 if (ARG(1) >= 12)
96 166 return (uint32_t)-1;
97 167 if (strcmp(s, ":tt") == 0) {
... ... @@ -100,7 +170,9 @@ uint32_t do_arm_semihosting(CPUState *env)
100 170 else
101 171 return STDOUT_FILENO;
102 172 }
103   - return set_swi_errno(ts, open(s, open_modeflags[ARG(1)], 0644));
  173 + ret = set_swi_errno(ts, open(s, open_modeflags[ARG(1)], 0644));
  174 + unlock_user(s, ARG(0), 0);
  175 + return ret;
104 176 case SYS_CLOSE:
105 177 return set_swi_errno(ts, close(ARG(0)));
106 178 case SYS_WRITEC:
... ... @@ -115,12 +187,20 @@ uint32_t do_arm_semihosting(CPUState *env)
115 187 unlock_user(s, args, 0);
116 188 return ret;
117 189 case SYS_WRITE:
118   - ret = set_swi_errno(ts, write(ARG(0), g2h(ARG(1)), ARG(2)));
  190 + len = ARG(2);
  191 + s = lock_user(ARG(1), len, 1);
  192 + ret = set_swi_errno(ts, write(ARG(0), s, len));
  193 + unlock_user(s, ARG(1), 0);
119 194 if (ret == (uint32_t)-1)
120 195 return -1;
121 196 return ARG(2) - ret;
122 197 case SYS_READ:
123   - ret = set_swi_errno(ts, read(ARG(0), g2h(ARG(1)), ARG(2)));
  198 + len = ARG(2);
  199 + s = lock_user(ARG(1), len, 0);
  200 + do
  201 + ret = set_swi_errno(ts, read(ARG(0), s, len));
  202 + while (ret == -1 && errno == EINTR);
  203 + unlock_user(s, ARG(1), len);
124 204 if (ret == (uint32_t)-1)
125 205 return -1;
126 206 return ARG(2) - ret;
... ... @@ -146,19 +226,36 @@ uint32_t do_arm_semihosting(CPUState *env)
146 226 /* XXX: Not implemented. */
147 227 return -1;
148 228 case SYS_REMOVE:
149   - return set_swi_errno(ts, remove((char *)g2h(ARG(0))));
  229 + s = lock_user_string(ARG(0));
  230 + ret = set_swi_errno(ts, remove(s));
  231 + unlock_user(s, ARG(0), 0);
  232 + return ret;
150 233 case SYS_RENAME:
151   - return set_swi_errno(ts, rename((char *)g2h(ARG(0)),
152   - (char *)g2h(ARG(2))));
  234 + {
  235 + char *s2;
  236 + s = lock_user_string(ARG(0));
  237 + s2 = lock_user_string(ARG(2));
  238 + ret = set_swi_errno(ts, rename(s, s2));
  239 + unlock_user(s2, ARG(2), 0);
  240 + unlock_user(s, ARG(0), 0);
  241 + return ret;
  242 + }
153 243 case SYS_CLOCK:
154 244 return clock() / (CLOCKS_PER_SEC / 100);
155 245 case SYS_TIME:
156 246 return set_swi_errno(ts, time(NULL));
157 247 case SYS_SYSTEM:
158   - return set_swi_errno(ts, system((char *)g2h(ARG(0))));
  248 + s = lock_user_string(ARG(0));
  249 + ret = set_swi_errno(ts, system(s));
  250 + unlock_user(s, ARG(0), 0);
159 251 case SYS_ERRNO:
  252 +#ifdef CONFIG_USER_ONLY
160 253 return ts->swi_errno;
  254 +#else
  255 + return 0;
  256 +#endif
161 257 case SYS_GET_CMDLINE:
  258 +#ifdef CONFIG_USER_ONLY
162 259 /* Build a commandline from the original argv. */
163 260 {
164 261 char **arg = ts->info->host_argv;
... ... @@ -194,12 +291,16 @@ uint32_t do_arm_semihosting(CPUState *env)
194 291 /* Return success if commandline fit into buffer. */
195 292 return *arg ? -1 : 0;
196 293 }
  294 +#else
  295 + return -1;
  296 +#endif
197 297 case SYS_HEAPINFO:
198 298 {
199 299 uint32_t *ptr;
200 300 uint32_t limit;
201 301  
202   - /* Some C llibraries assume the heap immediately follows .bss, so
  302 +#ifdef CONFIG_USER_ONLY
  303 + /* Some C libraries assume the heap immediately follows .bss, so
203 304 allocate it using sbrk. */
204 305 if (!ts->heap_limit) {
205 306 long ret;
... ... @@ -216,12 +317,22 @@ uint32_t do_arm_semihosting(CPUState *env)
216 317 ts->heap_limit = limit;
217 318 }
218 319  
219   - page_unprotect_range (ARG(0), 32);
220   - ptr = (uint32_t *)g2h(ARG(0));
  320 + ptr = lock_user(ARG(0), 16, 0);
221 321 ptr[0] = tswap32(ts->heap_base);
222 322 ptr[1] = tswap32(ts->heap_limit);
223 323 ptr[2] = tswap32(ts->stack_base);
224 324 ptr[3] = tswap32(0); /* Stack limit. */
  325 + unlock_user(ptr, ARG(0), 16);
  326 +#else
  327 + limit = ram_size;
  328 + ptr = lock_user(ARG(0), 16, 0);
  329 + /* TODO: Make this use the limit of the loaded application. */
  330 + ptr[0] = tswap32(limit / 2);
  331 + ptr[1] = tswap32(limit);
  332 + ptr[2] = tswap32(limit); /* Stack base */
  333 + ptr[3] = tswap32(0); /* Stack limit. */
  334 + unlock_user(ptr, ARG(0), 16);
  335 +#endif
225 336 return 0;
226 337 }
227 338 case SYS_EXIT:
... ... @@ -232,4 +343,3 @@ uint32_t do_arm_semihosting(CPUState *env)
232 343 abort();
233 344 }
234 345 }
235   -
... ...
qemu-doc.texi
... ... @@ -661,6 +661,11 @@ Exit instead of rebooting.
661 661  
662 662 @item -loadvm file
663 663 Start right away with a saved state (@code{loadvm} in monitor)
  664 +
  665 +@item -semihosting
  666 +Enable "Angel" semihosting interface (ARM target machines only).
  667 +Note that this allows guest direct access to the host filesystem,
  668 +so should only be used with trusted guest OS.
664 669 @end table
665 670  
666 671 @c man end
... ...
target-arm/helper.c
... ... @@ -105,6 +105,8 @@ void switch_mode(CPUState *env, int mode)
105 105  
106 106 #else
107 107  
  108 +extern int semihosting_enabled;
  109 +
108 110 /* Map CPU modes onto saved register banks. */
109 111 static inline int bank_number (int mode)
110 112 {
... ... @@ -175,6 +177,22 @@ void do_interrupt(CPUARMState *env)
175 177 offset = 4;
176 178 break;
177 179 case EXCP_SWI:
  180 + if (semihosting_enabled) {
  181 + /* Check for semihosting interrupt. */
  182 + if (env->thumb) {
  183 + mask = lduw_code(env->regs[15] - 2) & 0xff;
  184 + } else {
  185 + mask = ldl_code(env->regs[15] - 4) & 0xffffff;
  186 + }
  187 + /* Only intercept calls from privileged modes, to provide some
  188 + semblance of security. */
  189 + if (((mask == 0x123456 && !env->thumb)
  190 + || (mask == 0xab && env->thumb))
  191 + && (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR) {
  192 + env->regs[0] = do_arm_semihosting(env);
  193 + return;
  194 + }
  195 + }
178 196 new_mode = ARM_CPU_MODE_SVC;
179 197 addr = 0x08;
180 198 mask = CPSR_I;
... ...
... ... @@ -171,6 +171,7 @@ int no_reboot = 0;
171 171 int daemonize = 0;
172 172 const char *option_rom[MAX_OPTION_ROMS];
173 173 int nb_option_roms;
  174 +int semihosting_enabled = 0;
174 175  
175 176 /***********************************************************/
176 177 /* x86 ISA bus support */
... ... @@ -6227,6 +6228,7 @@ enum {
6227 6228 QEMU_OPTION_no_reboot,
6228 6229 QEMU_OPTION_daemonize,
6229 6230 QEMU_OPTION_option_rom,
  6231 + QEMU_OPTION_semihosting
6230 6232 };
6231 6233  
6232 6234 typedef struct QEMUOption {
... ... @@ -6309,6 +6311,9 @@ const QEMUOption qemu_options[] = {
6309 6311 { "no-reboot", 0, QEMU_OPTION_no_reboot },
6310 6312 { "daemonize", 0, QEMU_OPTION_daemonize },
6311 6313 { "option-rom", HAS_ARG, QEMU_OPTION_option_rom },
  6314 +#if defined(TARGET_ARM)
  6315 + { "semihosting", 0, QEMU_OPTION_semihosting },
  6316 +#endif
6312 6317 { NULL },
6313 6318 };
6314 6319  
... ... @@ -6970,6 +6975,9 @@ int main(int argc, char **argv)
6970 6975 option_rom[nb_option_roms] = optarg;
6971 6976 nb_option_roms++;
6972 6977 break;
  6978 + case QEMU_OPTION_semihosting:
  6979 + semihosting_enabled = 1;
  6980 + break;
6973 6981 }
6974 6982 }
6975 6983 }
... ...
... ... @@ -159,6 +159,7 @@ extern int win2k_install_hack;
159 159 extern int usb_enabled;
160 160 extern int smp_cpus;
161 161 extern int no_quit;
  162 +extern int semihosting_enabled;
162 163  
163 164 #define MAX_OPTION_ROMS 16
164 165 extern const char *option_rom[MAX_OPTION_ROMS];
... ...