Commit b346ff468efed71e42e9f306c6bf975809cd2c0f

Authored by bellard
1 parent 5a9fdfec

ARM emulation support


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@244 c046a42c-6fe2-441c-8c8c-71466251a162
... ... @@ -70,7 +70,7 @@ unsigned long host_page_mask;
70 70  
71 71 static PageDesc *l1_map[L1_SIZE];
72 72  
73   -void page_init(void)
  73 +static void page_init(void)
74 74 {
75 75 /* NOTE: we can always suppose that host_page_size >=
76 76 TARGET_PAGE_SIZE */
... ... @@ -190,10 +190,11 @@ void page_set_flags(unsigned long start, unsigned long end, int flags)
190 190 spin_unlock(&tb_lock);
191 191 }
192 192  
193   -void cpu_x86_tblocks_init(void)
  193 +void cpu_exec_init(void)
194 194 {
195 195 if (!code_gen_ptr) {
196 196 code_gen_ptr = code_gen_buffer;
  197 + page_init();
197 198 }
198 199 }
199 200  
... ...
... ... @@ -18,6 +18,31 @@
18 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 19 */
20 20  
  21 +/* allow to see translation results - the slowdown should be negligible, so we leave it */
  22 +#define DEBUG_DISAS
  23 +
  24 +/* is_jmp field values */
  25 +#define DISAS_NEXT 0 /* next instruction can be analyzed */
  26 +#define DISAS_JUMP 1 /* only pc was modified dynamically */
  27 +#define DISAS_UPDATE 2 /* cpu state was modified dynamically */
  28 +#define DISAS_TB_JUMP 3 /* only pc was modified statically */
  29 +
  30 +struct TranslationBlock;
  31 +
  32 +/* XXX: make safe guess about sizes */
  33 +#define MAX_OP_PER_INSTR 32
  34 +#define OPC_BUF_SIZE 512
  35 +#define OPC_MAX_SIZE (OPC_BUF_SIZE - MAX_OP_PER_INSTR)
  36 +
  37 +#define OPPARAM_BUF_SIZE (OPC_BUF_SIZE * 3)
  38 +
  39 +extern uint16_t gen_opc_buf[OPC_BUF_SIZE];
  40 +extern uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE];
  41 +extern uint32_t gen_opc_pc[OPC_BUF_SIZE];
  42 +extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
  43 +
  44 +#if defined(TARGET_I386)
  45 +
21 46 #define GEN_FLAG_CODE32_SHIFT 0
22 47 #define GEN_FLAG_ADDSEG_SHIFT 1
23 48 #define GEN_FLAG_SS32_SHIFT 2
... ... @@ -27,13 +52,18 @@
27 52 #define GEN_FLAG_CPL_SHIFT 9
28 53 #define GEN_FLAG_IOPL_SHIFT 12 /* same position as eflags */
29 54  
30   -struct TranslationBlock;
31   -int cpu_x86_gen_code(struct TranslationBlock *tb,
32   - int max_code_size, int *gen_code_size_ptr);
33   -int cpu_x86_search_pc(struct TranslationBlock *tb,
34   - uint32_t *found_pc, unsigned long searched_pc);
35   -void cpu_x86_tblocks_init(void);
36   -void page_init(void);
  55 +#endif
  56 +
  57 +extern FILE *logfile;
  58 +extern int loglevel;
  59 +
  60 +int gen_intermediate_code(struct TranslationBlock *tb, int search_pc);
  61 +void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf);
  62 +int cpu_gen_code(struct TranslationBlock *tb,
  63 + int max_code_size, int *gen_code_size_ptr);
  64 +int cpu_search_pc(struct TranslationBlock *tb,
  65 + uint32_t *found_pc, unsigned long searched_pc);
  66 +void cpu_exec_init(void);
37 67 int page_unprotect(unsigned long address);
38 68  
39 69 #define CODE_GEN_MAX_SIZE 65536
... ... @@ -167,6 +197,33 @@ TranslationBlock *tb_find_pc(unsigned long pc_ptr);
167 197 #define offsetof(type, field) ((size_t) &((type *)0)->field)
168 198 #endif
169 199  
  200 +#if defined(__powerpc__)
  201 +
  202 +/* on PowerPC we patch the jump instruction directly */
  203 +#define JUMP_TB(tbparam, n, eip)\
  204 +do {\
  205 + static void __attribute__((unused)) *__op_label ## n = &&label ## n;\
  206 + asm volatile ("b %0" : : "i" (&__op_jmp ## n));\
  207 +label ## n:\
  208 + T0 = (long)(tbparam) + (n);\
  209 + EIP = eip;\
  210 +} while (0)
  211 +
  212 +#else
  213 +
  214 +/* jump to next block operations (more portable code, does not need
  215 + cache flushing, but slower because of indirect jump) */
  216 +#define JUMP_TB(tbparam, n, eip)\
  217 +do {\
  218 + static void __attribute__((unused)) *__op_label ## n = &&label ## n;\
  219 + goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\
  220 +label ## n:\
  221 + T0 = (long)(tbparam) + (n);\
  222 + EIP = eip;\
  223 +} while (0)
  224 +
  225 +#endif
  226 +
170 227 #ifdef __powerpc__
171 228 static inline int testandset (int *p)
172 229 {
... ...
linux-user/elfload.c
... ... @@ -38,6 +38,45 @@
38 38 A value of 0 tells we have no such handler. */
39 39 #define ELF_PLAT_INIT(_r) _r->edx = 0
40 40  
  41 +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
  42 +{
  43 + regs->esp = infop->start_stack;
  44 + regs->eip = infop->entry;
  45 +}
  46 +
  47 +#define USE_ELF_CORE_DUMP
  48 +#define ELF_EXEC_PAGESIZE 4096
  49 +
  50 +#endif
  51 +
  52 +#ifdef TARGET_ARM
  53 +
  54 +#define ELF_START_MMAP 0x80000000
  55 +
  56 +#define elf_check_arch(x) ( (x) == EM_ARM )
  57 +
  58 +#define ELF_CLASS ELFCLASS32
  59 +#ifdef TARGET_WORDS_BIGENDIAN
  60 +#define ELF_DATA ELFDATA2MSB
  61 +#else
  62 +#define ELF_DATA ELFDATA2LSB
  63 +#endif
  64 +#define ELF_ARCH EM_ARM
  65 +
  66 +#define ELF_PLAT_INIT(_r) _r->ARM_r0 = 0
  67 +
  68 +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
  69 +{
  70 + target_long *stack = (void *)infop->start_stack;
  71 + memset(regs, 0, sizeof(*regs));
  72 + regs->ARM_cpsr = 0x10;
  73 + regs->ARM_pc = infop->entry;
  74 + regs->ARM_sp = infop->start_stack;
  75 + regs->ARM_r2 = tswapl(stack[2]); /* envp */
  76 + regs->ARM_r1 = tswapl(stack[1]); /* argv */
  77 + regs->ARM_r0 = tswapl(stack[0]); /* argc */
  78 +}
  79 +
41 80 #define USE_ELF_CORE_DUMP
42 81 #define ELF_EXEC_PAGESIZE 4096
43 82  
... ... @@ -1148,8 +1187,7 @@ int elf_exec(const char * filename, char ** argv, char ** envp,
1148 1187 }
1149 1188 if(retval>=0) {
1150 1189 /* success. Initialize important registers */
1151   - regs->esp = infop->start_stack;
1152   - regs->eip = infop->entry;
  1190 + init_thread(regs, infop);
1153 1191 return retval;
1154 1192 }
1155 1193  
... ...
linux-user/main.c
... ... @@ -63,6 +63,7 @@ void gemu_log(const char *fmt, ...)
63 63 va_end(ap);
64 64 }
65 65  
  66 +#ifdef TARGET_I386
66 67 /***********************************************************/
67 68 /* CPUX86 core interface */
68 69  
... ... @@ -238,20 +239,76 @@ void cpu_loop(CPUX86State *env)
238 239 process_pending_signals(env);
239 240 }
240 241 }
  242 +#endif
  243 +
  244 +#ifdef TARGET_ARM
  245 +
  246 +#define ARM_SYSCALL_BASE 0x900000
  247 +
  248 +void cpu_loop(CPUARMState *env)
  249 +{
  250 + int trapnr;
  251 + unsigned int n, insn;
  252 + target_siginfo_t info;
  253 +
  254 + for(;;) {
  255 + trapnr = cpu_arm_exec(env);
  256 + switch(trapnr) {
  257 + case EXCP_UDEF:
  258 + info.si_signo = SIGILL;
  259 + info.si_errno = 0;
  260 + info.si_code = TARGET_ILL_ILLOPN;
  261 + info._sifields._sigfault._addr = env->regs[15];
  262 + queue_signal(info.si_signo, &info);
  263 + break;
  264 + case EXCP_SWI:
  265 + {
  266 + /* system call */
  267 + insn = ldl((void *)(env->regs[15] - 4));
  268 + n = insn & 0xffffff;
  269 + if (n >= ARM_SYSCALL_BASE) {
  270 + /* linux syscall */
  271 + n -= ARM_SYSCALL_BASE;
  272 + env->regs[0] = do_syscall(env,
  273 + n,
  274 + env->regs[0],
  275 + env->regs[1],
  276 + env->regs[2],
  277 + env->regs[3],
  278 + env->regs[4],
  279 + 0);
  280 + } else {
  281 + goto error;
  282 + }
  283 + }
  284 + break;
  285 + default:
  286 + error:
  287 + fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
  288 + trapnr);
  289 + cpu_arm_dump_state(env, stderr, 0);
  290 + abort();
  291 + }
  292 + process_pending_signals(env);
  293 + }
  294 +}
  295 +
  296 +#endif
241 297  
242 298 void usage(void)
243 299 {
244 300 printf("qemu version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
245 301 "usage: qemu [-h] [-d] [-L path] [-s size] program [arguments...]\n"
246   - "Linux x86 emulator\n"
  302 + "Linux CPU emulator (compiled for %s emulation)\n"
247 303 "\n"
248 304 "-h print this help\n"
249   - "-L path set the x86 elf interpreter prefix (default=%s)\n"
250   - "-s size set the x86 stack size in bytes (default=%ld)\n"
  305 + "-L path set the elf interpreter prefix (default=%s)\n"
  306 + "-s size set the stack size in bytes (default=%ld)\n"
251 307 "\n"
252 308 "debug options:\n"
253 309 "-d activate log (logfile=%s)\n"
254 310 "-p pagesize set the host page size to 'pagesize'\n",
  311 + TARGET_ARCH,
255 312 interp_prefix,
256 313 x86_stack_size,
257 314 DEBUG_LOGFILE);
... ... @@ -259,7 +316,7 @@ void usage(void)
259 316 }
260 317  
261 318 /* XXX: currently only used for async signals (see signal.c) */
262   -CPUX86State *global_env;
  319 +CPUState *global_env;
263 320 /* used to free thread contexts */
264 321 TaskState *first_task_state;
265 322  
... ... @@ -269,7 +326,7 @@ int main(int argc, char **argv)
269 326 struct target_pt_regs regs1, *regs = &regs1;
270 327 struct image_info info1, *info = &info1;
271 328 TaskState ts1, *ts = &ts1;
272   - CPUX86State *env;
  329 + CPUState *env;
273 330 int optind;
274 331 const char *r;
275 332  
... ... @@ -337,7 +394,7 @@ int main(int argc, char **argv)
337 394  
338 395 /* NOTE: we need to init the CPU at this stage to get the
339 396 host_page_size */
340   - env = cpu_x86_init();
  397 + env = cpu_init();
341 398  
342 399 if (elf_exec(filename, argv+optind, environ, regs, info) != 0) {
343 400 printf("Error loading %s\n", filename);
... ... @@ -353,8 +410,7 @@ int main(int argc, char **argv)
353 410 fprintf(logfile, "end_data 0x%08lx\n" , info->end_data);
354 411 fprintf(logfile, "start_stack 0x%08lx\n" , info->start_stack);
355 412 fprintf(logfile, "brk 0x%08lx\n" , info->brk);
356   - fprintf(logfile, "esp 0x%08lx\n" , regs->esp);
357   - fprintf(logfile, "eip 0x%08lx\n" , regs->eip);
  413 + fprintf(logfile, "entry 0x%08lx\n" , info->entry);
358 414 }
359 415  
360 416 target_set_brk((char *)info->brk);
... ... @@ -368,6 +424,7 @@ int main(int argc, char **argv)
368 424 env->opaque = ts;
369 425 ts->used = 1;
370 426  
  427 +#if defined(TARGET_I386)
371 428 /* linux register setup */
372 429 env->regs[R_EAX] = regs->eax;
373 430 env->regs[R_EBX] = regs->ebx;
... ... @@ -419,6 +476,17 @@ int main(int argc, char **argv)
419 476 cpu_x86_load_seg(env, R_SS, __USER_DS);
420 477 cpu_x86_load_seg(env, R_FS, __USER_DS);
421 478 cpu_x86_load_seg(env, R_GS, __USER_DS);
  479 +#elif defined(TARGET_ARM)
  480 + {
  481 + int i;
  482 + for(i = 0; i < 16; i++) {
  483 + env->regs[i] = regs->uregs[i];
  484 + }
  485 + env->cpsr = regs->uregs[16];
  486 + }
  487 +#else
  488 +#error unsupported target CPU
  489 +#endif
422 490  
423 491 cpu_loop(env);
424 492 /* never exits */
... ...
linux-user/qemu.h
... ... @@ -6,10 +6,8 @@
6 6 #include <signal.h>
7 7 #include "syscall_defs.h"
8 8  
9   -#ifdef TARGET_I386
10   -#include "cpu-i386.h"
11   -#include "syscall-i386.h"
12   -#endif
  9 +#include "cpu-" TARGET_ARCH ".h"
  10 +#include "syscall-" TARGET_ARCH ".h"
13 11  
14 12 /* This struct is used to hold certain information about the image.
15 13 * Basically, it replicates in user space what would be certain
... ... @@ -33,6 +31,7 @@ struct image_info {
33 31 int personality;
34 32 };
35 33  
  34 +#ifdef TARGET_I386
36 35 /* Information about the current linux thread */
37 36 struct vm86_saved_state {
38 37 uint32_t eax; /* return code */
... ... @@ -47,16 +46,19 @@ struct vm86_saved_state {
47 46 uint32_t eip;
48 47 uint16_t cs, ss, ds, es, fs, gs;
49 48 };
  49 +#endif
50 50  
51 51 /* NOTE: we force a big alignment so that the stack stored after is
52 52 aligned too */
53 53 typedef struct TaskState {
54 54 struct TaskState *next;
  55 +#ifdef TARGET_I386
55 56 struct target_vm86plus_struct *target_v86;
56 57 struct vm86_saved_state vm86_saved_regs;
57 58 struct target_vm86plus_struct vm86plus;
58 59 uint32_t v86flags;
59 60 uint32_t v86mask;
  61 +#endif
60 62 int used; /* non zero if used */
61 63 uint8_t stack[0];
62 64 } __attribute__((aligned(16))) TaskState;
... ... @@ -71,23 +73,31 @@ void syscall_init(void);
71 73 long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
72 74 long arg4, long arg5, long arg6);
73 75 void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2)));
74   -extern CPUX86State *global_env;
75   -void cpu_loop(CPUX86State *env);
76   -void process_pending_signals(void *cpu_env);
77   -void signal_init(void);
78   -int queue_signal(int sig, target_siginfo_t *info);
  76 +extern CPUState *global_env;
  77 +void cpu_loop(CPUState *env);
79 78 void init_paths(const char *prefix);
80 79 const char *path(const char *pathname);
81 80  
82 81 extern int loglevel;
83 82 extern FILE *logfile;
84 83  
  84 +/* signal.c */
  85 +void process_pending_signals(void *cpu_env);
  86 +void signal_init(void);
  87 +int queue_signal(int sig, target_siginfo_t *info);
  88 +void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info);
  89 +void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo);
  90 +long do_sigreturn(CPUState *env);
  91 +long do_rt_sigreturn(CPUState *env);
  92 +
  93 +#ifdef TARGET_I386
85 94 /* vm86.c */
86 95 void save_v86_state(CPUX86State *env);
87 96 void handle_vm86_trap(CPUX86State *env, int trapno);
88 97 void handle_vm86_fault(CPUX86State *env);
89 98 int do_vm86(CPUX86State *env, long subfunction,
90 99 struct target_vm86plus_struct * target_v86);
  100 +#endif
91 101  
92 102 /* mmap.c */
93 103 int target_mprotect(unsigned long start, unsigned long len, int prot);
... ...
linux-user/signal.c
... ... @@ -318,7 +318,7 @@ static void host_signal_handler(int host_signum, siginfo_t *info,
318 318 /* the CPU emulator uses some host signals to detect exceptions,
319 319 we we forward to it some signals */
320 320 if (host_signum == SIGSEGV || host_signum == SIGBUS) {
321   - if (cpu_x86_signal_handler(host_signum, info, puc))
  321 + if (cpu_signal_handler(host_signum, info, puc))
322 322 return;
323 323 }
324 324  
... ... @@ -333,7 +333,7 @@ static void host_signal_handler(int host_signum, siginfo_t *info,
333 333 host_to_target_siginfo_noswap(&tinfo, info);
334 334 if (queue_signal(sig, &tinfo) == 1) {
335 335 /* interrupt the virtual CPU as soon as possible */
336   - cpu_x86_interrupt(global_env);
  336 + cpu_interrupt(global_env);
337 337 }
338 338 }
339 339  
... ... @@ -824,6 +824,33 @@ badframe:
824 824 return 0;
825 825 }
826 826  
  827 +#else
  828 +
  829 +static void setup_frame(int sig, struct emulated_sigaction *ka,
  830 + target_sigset_t *set, CPUState *env)
  831 +{
  832 + fprintf(stderr, "setup_frame: not implemented\n");
  833 +}
  834 +
  835 +static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
  836 + target_siginfo_t *info,
  837 + target_sigset_t *set, CPUState *env)
  838 +{
  839 + fprintf(stderr, "setup_rt_frame: not implemented\n");
  840 +}
  841 +
  842 +long do_sigreturn(CPUState *env)
  843 +{
  844 + fprintf(stderr, "do_sigreturn: not implemented\n");
  845 + return -ENOSYS;
  846 +}
  847 +
  848 +long do_rt_sigreturn(CPUState *env)
  849 +{
  850 + fprintf(stderr, "do_rt_sigreturn: not implemented\n");
  851 + return -ENOSYS;
  852 +}
  853 +
827 854 #endif
828 855  
829 856 void process_pending_signals(void *cpu_env)
... ...