Commit fbb4a2e371f2fa7d3bbe479795d8c79a795f7cd3
1 parent
ce5232c5
Implement ARM magic kernel page and TLS register.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4610 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
4 changed files
with
96 additions
and
10 deletions
linux-user/arm/syscall.h
... | ... | @@ -28,7 +28,9 @@ struct target_pt_regs { |
28 | 28 | #define ARM_SYSCALL_BASE 0x900000 |
29 | 29 | #define ARM_THUMB_SYSCALL 0 |
30 | 30 | |
31 | -#define ARM_NR_cacheflush (ARM_SYSCALL_BASE + 0xf0000 + 2) | |
31 | +#define ARM_NR_BASE 0xf0000 | |
32 | +#define ARM_NR_cacheflush (ARM_NR_BASE + 2) | |
33 | +#define ARM_NR_set_tls (ARM_NR_BASE + 5) | |
32 | 34 | |
33 | 35 | #define ARM_NR_semihosting 0x123456 |
34 | 36 | #define ARM_NR_thumb_semihosting 0xAB | ... | ... |
linux-user/main.c
... | ... | @@ -365,6 +365,55 @@ static void arm_cache_flush(abi_ulong start, abi_ulong last) |
365 | 365 | } |
366 | 366 | } |
367 | 367 | |
368 | +/* Handle a jump to the kernel code page. */ | |
369 | +static int | |
370 | +do_kernel_trap(CPUARMState *env) | |
371 | +{ | |
372 | + uint32_t addr; | |
373 | + uint32_t cpsr; | |
374 | + uint32_t val; | |
375 | + | |
376 | + switch (env->regs[15]) { | |
377 | + case 0xffff0fa0: /* __kernel_memory_barrier */ | |
378 | + /* ??? No-op. Will need to do better for SMP. */ | |
379 | + break; | |
380 | + case 0xffff0fc0: /* __kernel_cmpxchg */ | |
381 | + /* ??? This is not really atomic. However we don't support | |
382 | + threads anyway, so it doesn't realy matter. */ | |
383 | + cpsr = cpsr_read(env); | |
384 | + addr = env->regs[2]; | |
385 | + /* FIXME: This should SEGV if the access fails. */ | |
386 | + if (get_user_u32(val, addr)) | |
387 | + val = ~env->regs[0]; | |
388 | + if (val == env->regs[0]) { | |
389 | + val = env->regs[1]; | |
390 | + /* FIXME: Check for segfaults. */ | |
391 | + put_user_u32(val, addr); | |
392 | + env->regs[0] = 0; | |
393 | + cpsr |= CPSR_C; | |
394 | + } else { | |
395 | + env->regs[0] = -1; | |
396 | + cpsr &= ~CPSR_C; | |
397 | + } | |
398 | + cpsr_write(env, cpsr, CPSR_C); | |
399 | + break; | |
400 | + case 0xffff0fe0: /* __kernel_get_tls */ | |
401 | + env->regs[0] = env->cp15.c13_tls2; | |
402 | + break; | |
403 | + default: | |
404 | + return 1; | |
405 | + } | |
406 | + /* Jump back to the caller. */ | |
407 | + addr = env->regs[14]; | |
408 | + if (addr & 1) { | |
409 | + env->thumb = 1; | |
410 | + addr &= ~1; | |
411 | + } | |
412 | + env->regs[15] = addr; | |
413 | + | |
414 | + return 0; | |
415 | +} | |
416 | + | |
368 | 417 | void cpu_loop(CPUARMState *env) |
369 | 418 | { |
370 | 419 | int trapnr; |
... | ... | @@ -489,14 +538,31 @@ void cpu_loop(CPUARMState *env) |
489 | 538 | n -= ARM_SYSCALL_BASE; |
490 | 539 | env->eabi = 0; |
491 | 540 | } |
492 | - env->regs[0] = do_syscall(env, | |
493 | - n, | |
494 | - env->regs[0], | |
495 | - env->regs[1], | |
496 | - env->regs[2], | |
497 | - env->regs[3], | |
498 | - env->regs[4], | |
499 | - env->regs[5]); | |
541 | + if ( n > ARM_NR_BASE) { | |
542 | + switch (n) { | |
543 | + case ARM_NR_cacheflush: | |
544 | + arm_cache_flush(env->regs[0], env->regs[1]); | |
545 | + break; | |
546 | + case ARM_NR_set_tls: | |
547 | + cpu_set_tls(env, env->regs[0]); | |
548 | + env->regs[0] = 0; | |
549 | + break; | |
550 | + default: | |
551 | + gemu_log("qemu: Unsupported ARM syscall: 0x%x\n", | |
552 | + n); | |
553 | + env->regs[0] = -TARGET_ENOSYS; | |
554 | + break; | |
555 | + } | |
556 | + } else { | |
557 | + env->regs[0] = do_syscall(env, | |
558 | + n, | |
559 | + env->regs[0], | |
560 | + env->regs[1], | |
561 | + env->regs[2], | |
562 | + env->regs[3], | |
563 | + env->regs[4], | |
564 | + env->regs[5]); | |
565 | + } | |
500 | 566 | } else { |
501 | 567 | goto error; |
502 | 568 | } |
... | ... | @@ -535,6 +601,10 @@ void cpu_loop(CPUARMState *env) |
535 | 601 | } |
536 | 602 | } |
537 | 603 | break; |
604 | + case EXCP_KERNEL_TRAP: | |
605 | + if (do_kernel_trap(env)) | |
606 | + goto error; | |
607 | + break; | |
538 | 608 | default: |
539 | 609 | error: |
540 | 610 | fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", | ... | ... |
target-arm/cpu.h
... | ... | @@ -38,6 +38,7 @@ |
38 | 38 | #define EXCP_FIQ 6 |
39 | 39 | #define EXCP_BKPT 7 |
40 | 40 | #define EXCP_EXCEPTION_EXIT 8 /* Return from v7M exception. */ |
41 | +#define EXCP_KERNEL_TRAP 9 /* Jumped to kernel code page. */ | |
41 | 42 | |
42 | 43 | #define ARMV7M_EXCP_RESET 1 |
43 | 44 | #define ARMV7M_EXCP_NMI 2 |
... | ... | @@ -216,6 +217,10 @@ int cpu_arm_signal_handler(int host_signum, void *pinfo, |
216 | 217 | |
217 | 218 | void cpu_lock(void); |
218 | 219 | void cpu_unlock(void); |
220 | +static inline void cpu_set_tls(CPUARMState *env, target_ulong newtls) | |
221 | +{ | |
222 | + env->cp15.c13_tls2 = newtls; | |
223 | +} | |
219 | 224 | |
220 | 225 | #define CPSR_M (0x1f) |
221 | 226 | #define CPSR_T (1 << 5) | ... | ... |
target-arm/translate.c
... | ... | @@ -8583,7 +8583,16 @@ static inline int gen_intermediate_code_internal(CPUState *env, |
8583 | 8583 | store_cpu_field(tmp, condexec_bits); |
8584 | 8584 | } |
8585 | 8585 | do { |
8586 | -#ifndef CONFIG_USER_ONLY | |
8586 | +#ifdef CONFIG_USER_ONLY | |
8587 | + /* Intercept jump to the magic kernel page. */ | |
8588 | + if (dc->pc >= 0xffff0000) { | |
8589 | + /* We always get here via a jump, so know we are not in a | |
8590 | + conditional execution block. */ | |
8591 | + gen_exception(EXCP_KERNEL_TRAP); | |
8592 | + dc->is_jmp = DISAS_UPDATE; | |
8593 | + break; | |
8594 | + } | |
8595 | +#else | |
8587 | 8596 | if (dc->pc >= 0xfffffff0 && IS_M(env)) { |
8588 | 8597 | /* We always get here via a jump, so know we are not in a |
8589 | 8598 | conditional execution block. */ | ... | ... |