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,6 +397,7 @@ VL_OBJS+= integratorcp.o versatilepb.o ps2.o smc91c111.o arm_pic.o arm_timer.o
397 VL_OBJS+= arm_boot.o pl011.o pl050.o pl080.o pl110.o pl190.o 397 VL_OBJS+= arm_boot.o pl011.o pl050.o pl080.o pl110.o pl190.o
398 VL_OBJS+= versatile_pci.o 398 VL_OBJS+= versatile_pci.o
399 VL_OBJS+= arm_gic.o realview.o arm_sysctl.o 399 VL_OBJS+= arm_gic.o realview.o arm_sysctl.o
  400 +VL_OBJS+= arm-semi.o
400 endif 401 endif
401 ifeq ($(TARGET_BASE_ARCH), sh4) 402 ifeq ($(TARGET_BASE_ARCH), sh4)
402 VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o 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 * Arm "Angel" semihosting syscalls 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 * This program is free software; you can redistribute it and/or modify 7 * 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 * it under the terms of the GNU General Public License as published by
@@ -26,9 +27,14 @@ @@ -26,9 +27,14 @@
26 #include <stdio.h> 27 #include <stdio.h>
27 #include <time.h> 28 #include <time.h>
28 29
  30 +#include "cpu.h"
  31 +#ifdef CONFIG_USER_ONLY
29 #include "qemu.h" 32 #include "qemu.h"
30 33
31 #define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024) 34 #define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024)
  35 +#else
  36 +#include "vl.h"
  37 +#endif
32 38
33 #define SYS_OPEN 0x01 39 #define SYS_OPEN 0x01
34 #define SYS_CLOSE 0x02 40 #define SYS_CLOSE 0x02
@@ -70,12 +76,71 @@ int open_modeflags[12] = { @@ -70,12 +76,71 @@ int open_modeflags[12] = {
70 O_RDWR | O_CREAT | O_APPEND | O_BINARY 76 O_RDWR | O_CREAT | O_APPEND | O_BINARY
71 }; 77 };
72 78
  79 +#ifdef CONFIG_USER_ONLY
73 static inline uint32_t set_swi_errno(TaskState *ts, uint32_t code) 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 #define ARG(n) tget32(args + (n) * 4) 145 #define ARG(n) tget32(args + (n) * 4)
81 #define SET_ARG(n, val) tput32(args + (n) * 4,val) 146 #define SET_ARG(n, val) tput32(args + (n) * 4,val)
@@ -85,13 +150,18 @@ uint32_t do_arm_semihosting(CPUState *env) @@ -85,13 +150,18 @@ uint32_t do_arm_semihosting(CPUState *env)
85 char * s; 150 char * s;
86 int nr; 151 int nr;
87 uint32_t ret; 152 uint32_t ret;
  153 + uint32_t len;
  154 +#ifdef CONFIG_USER_ONLY
88 TaskState *ts = env->opaque; 155 TaskState *ts = env->opaque;
  156 +#else
  157 + CPUState *ts = env;
  158 +#endif
89 159
90 nr = env->regs[0]; 160 nr = env->regs[0];
91 args = env->regs[1]; 161 args = env->regs[1];
92 switch (nr) { 162 switch (nr) {
93 case SYS_OPEN: 163 case SYS_OPEN:
94 - s = (char *)g2h(ARG(0)); 164 + s = lock_user_string(ARG(0));
95 if (ARG(1) >= 12) 165 if (ARG(1) >= 12)
96 return (uint32_t)-1; 166 return (uint32_t)-1;
97 if (strcmp(s, ":tt") == 0) { 167 if (strcmp(s, ":tt") == 0) {
@@ -100,7 +170,9 @@ uint32_t do_arm_semihosting(CPUState *env) @@ -100,7 +170,9 @@ uint32_t do_arm_semihosting(CPUState *env)
100 else 170 else
101 return STDOUT_FILENO; 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 case SYS_CLOSE: 176 case SYS_CLOSE:
105 return set_swi_errno(ts, close(ARG(0))); 177 return set_swi_errno(ts, close(ARG(0)));
106 case SYS_WRITEC: 178 case SYS_WRITEC:
@@ -115,12 +187,20 @@ uint32_t do_arm_semihosting(CPUState *env) @@ -115,12 +187,20 @@ uint32_t do_arm_semihosting(CPUState *env)
115 unlock_user(s, args, 0); 187 unlock_user(s, args, 0);
116 return ret; 188 return ret;
117 case SYS_WRITE: 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 if (ret == (uint32_t)-1) 194 if (ret == (uint32_t)-1)
120 return -1; 195 return -1;
121 return ARG(2) - ret; 196 return ARG(2) - ret;
122 case SYS_READ: 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 if (ret == (uint32_t)-1) 204 if (ret == (uint32_t)-1)
125 return -1; 205 return -1;
126 return ARG(2) - ret; 206 return ARG(2) - ret;
@@ -146,19 +226,36 @@ uint32_t do_arm_semihosting(CPUState *env) @@ -146,19 +226,36 @@ uint32_t do_arm_semihosting(CPUState *env)
146 /* XXX: Not implemented. */ 226 /* XXX: Not implemented. */
147 return -1; 227 return -1;
148 case SYS_REMOVE: 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 case SYS_RENAME: 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 case SYS_CLOCK: 243 case SYS_CLOCK:
154 return clock() / (CLOCKS_PER_SEC / 100); 244 return clock() / (CLOCKS_PER_SEC / 100);
155 case SYS_TIME: 245 case SYS_TIME:
156 return set_swi_errno(ts, time(NULL)); 246 return set_swi_errno(ts, time(NULL));
157 case SYS_SYSTEM: 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 case SYS_ERRNO: 251 case SYS_ERRNO:
  252 +#ifdef CONFIG_USER_ONLY
160 return ts->swi_errno; 253 return ts->swi_errno;
  254 +#else
  255 + return 0;
  256 +#endif
161 case SYS_GET_CMDLINE: 257 case SYS_GET_CMDLINE:
  258 +#ifdef CONFIG_USER_ONLY
162 /* Build a commandline from the original argv. */ 259 /* Build a commandline from the original argv. */
163 { 260 {
164 char **arg = ts->info->host_argv; 261 char **arg = ts->info->host_argv;
@@ -194,12 +291,16 @@ uint32_t do_arm_semihosting(CPUState *env) @@ -194,12 +291,16 @@ uint32_t do_arm_semihosting(CPUState *env)
194 /* Return success if commandline fit into buffer. */ 291 /* Return success if commandline fit into buffer. */
195 return *arg ? -1 : 0; 292 return *arg ? -1 : 0;
196 } 293 }
  294 +#else
  295 + return -1;
  296 +#endif
197 case SYS_HEAPINFO: 297 case SYS_HEAPINFO:
198 { 298 {
199 uint32_t *ptr; 299 uint32_t *ptr;
200 uint32_t limit; 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 allocate it using sbrk. */ 304 allocate it using sbrk. */
204 if (!ts->heap_limit) { 305 if (!ts->heap_limit) {
205 long ret; 306 long ret;
@@ -216,12 +317,22 @@ uint32_t do_arm_semihosting(CPUState *env) @@ -216,12 +317,22 @@ uint32_t do_arm_semihosting(CPUState *env)
216 ts->heap_limit = limit; 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 ptr[0] = tswap32(ts->heap_base); 321 ptr[0] = tswap32(ts->heap_base);
222 ptr[1] = tswap32(ts->heap_limit); 322 ptr[1] = tswap32(ts->heap_limit);
223 ptr[2] = tswap32(ts->stack_base); 323 ptr[2] = tswap32(ts->stack_base);
224 ptr[3] = tswap32(0); /* Stack limit. */ 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 return 0; 336 return 0;
226 } 337 }
227 case SYS_EXIT: 338 case SYS_EXIT:
@@ -232,4 +343,3 @@ uint32_t do_arm_semihosting(CPUState *env) @@ -232,4 +343,3 @@ uint32_t do_arm_semihosting(CPUState *env)
232 abort(); 343 abort();
233 } 344 }
234 } 345 }
235 -  
qemu-doc.texi
@@ -661,6 +661,11 @@ Exit instead of rebooting. @@ -661,6 +661,11 @@ Exit instead of rebooting.
661 661
662 @item -loadvm file 662 @item -loadvm file
663 Start right away with a saved state (@code{loadvm} in monitor) 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 @end table 669 @end table
665 670
666 @c man end 671 @c man end
target-arm/helper.c
@@ -105,6 +105,8 @@ void switch_mode(CPUState *env, int mode) @@ -105,6 +105,8 @@ void switch_mode(CPUState *env, int mode)
105 105
106 #else 106 #else
107 107
  108 +extern int semihosting_enabled;
  109 +
108 /* Map CPU modes onto saved register banks. */ 110 /* Map CPU modes onto saved register banks. */
109 static inline int bank_number (int mode) 111 static inline int bank_number (int mode)
110 { 112 {
@@ -175,6 +177,22 @@ void do_interrupt(CPUARMState *env) @@ -175,6 +177,22 @@ void do_interrupt(CPUARMState *env)
175 offset = 4; 177 offset = 4;
176 break; 178 break;
177 case EXCP_SWI: 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 new_mode = ARM_CPU_MODE_SVC; 196 new_mode = ARM_CPU_MODE_SVC;
179 addr = 0x08; 197 addr = 0x08;
180 mask = CPSR_I; 198 mask = CPSR_I;
@@ -171,6 +171,7 @@ int no_reboot = 0; @@ -171,6 +171,7 @@ int no_reboot = 0;
171 int daemonize = 0; 171 int daemonize = 0;
172 const char *option_rom[MAX_OPTION_ROMS]; 172 const char *option_rom[MAX_OPTION_ROMS];
173 int nb_option_roms; 173 int nb_option_roms;
  174 +int semihosting_enabled = 0;
174 175
175 /***********************************************************/ 176 /***********************************************************/
176 /* x86 ISA bus support */ 177 /* x86 ISA bus support */
@@ -6227,6 +6228,7 @@ enum { @@ -6227,6 +6228,7 @@ enum {
6227 QEMU_OPTION_no_reboot, 6228 QEMU_OPTION_no_reboot,
6228 QEMU_OPTION_daemonize, 6229 QEMU_OPTION_daemonize,
6229 QEMU_OPTION_option_rom, 6230 QEMU_OPTION_option_rom,
  6231 + QEMU_OPTION_semihosting
6230 }; 6232 };
6231 6233
6232 typedef struct QEMUOption { 6234 typedef struct QEMUOption {
@@ -6309,6 +6311,9 @@ const QEMUOption qemu_options[] = { @@ -6309,6 +6311,9 @@ const QEMUOption qemu_options[] = {
6309 { "no-reboot", 0, QEMU_OPTION_no_reboot }, 6311 { "no-reboot", 0, QEMU_OPTION_no_reboot },
6310 { "daemonize", 0, QEMU_OPTION_daemonize }, 6312 { "daemonize", 0, QEMU_OPTION_daemonize },
6311 { "option-rom", HAS_ARG, QEMU_OPTION_option_rom }, 6313 { "option-rom", HAS_ARG, QEMU_OPTION_option_rom },
  6314 +#if defined(TARGET_ARM)
  6315 + { "semihosting", 0, QEMU_OPTION_semihosting },
  6316 +#endif
6312 { NULL }, 6317 { NULL },
6313 }; 6318 };
6314 6319
@@ -6970,6 +6975,9 @@ int main(int argc, char **argv) @@ -6970,6 +6975,9 @@ int main(int argc, char **argv)
6970 option_rom[nb_option_roms] = optarg; 6975 option_rom[nb_option_roms] = optarg;
6971 nb_option_roms++; 6976 nb_option_roms++;
6972 break; 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,6 +159,7 @@ extern int win2k_install_hack;
159 extern int usb_enabled; 159 extern int usb_enabled;
160 extern int smp_cpus; 160 extern int smp_cpus;
161 extern int no_quit; 161 extern int no_quit;
  162 +extern int semihosting_enabled;
162 163
163 #define MAX_OPTION_ROMS 16 164 #define MAX_OPTION_ROMS 16
164 extern const char *option_rom[MAX_OPTION_ROMS]; 165 extern const char *option_rom[MAX_OPTION_ROMS];