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,7 +28,9 @@ struct target_pt_regs { | ||
| 28 | #define ARM_SYSCALL_BASE 0x900000 | 28 | #define ARM_SYSCALL_BASE 0x900000 |
| 29 | #define ARM_THUMB_SYSCALL 0 | 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 | #define ARM_NR_semihosting 0x123456 | 35 | #define ARM_NR_semihosting 0x123456 |
| 34 | #define ARM_NR_thumb_semihosting 0xAB | 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,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 | void cpu_loop(CPUARMState *env) | 417 | void cpu_loop(CPUARMState *env) |
| 369 | { | 418 | { |
| 370 | int trapnr; | 419 | int trapnr; |
| @@ -489,14 +538,31 @@ void cpu_loop(CPUARMState *env) | @@ -489,14 +538,31 @@ void cpu_loop(CPUARMState *env) | ||
| 489 | n -= ARM_SYSCALL_BASE; | 538 | n -= ARM_SYSCALL_BASE; |
| 490 | env->eabi = 0; | 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 | } else { | 566 | } else { |
| 501 | goto error; | 567 | goto error; |
| 502 | } | 568 | } |
| @@ -535,6 +601,10 @@ void cpu_loop(CPUARMState *env) | @@ -535,6 +601,10 @@ void cpu_loop(CPUARMState *env) | ||
| 535 | } | 601 | } |
| 536 | } | 602 | } |
| 537 | break; | 603 | break; |
| 604 | + case EXCP_KERNEL_TRAP: | ||
| 605 | + if (do_kernel_trap(env)) | ||
| 606 | + goto error; | ||
| 607 | + break; | ||
| 538 | default: | 608 | default: |
| 539 | error: | 609 | error: |
| 540 | fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", | 610 | fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", |
target-arm/cpu.h
| @@ -38,6 +38,7 @@ | @@ -38,6 +38,7 @@ | ||
| 38 | #define EXCP_FIQ 6 | 38 | #define EXCP_FIQ 6 |
| 39 | #define EXCP_BKPT 7 | 39 | #define EXCP_BKPT 7 |
| 40 | #define EXCP_EXCEPTION_EXIT 8 /* Return from v7M exception. */ | 40 | #define EXCP_EXCEPTION_EXIT 8 /* Return from v7M exception. */ |
| 41 | +#define EXCP_KERNEL_TRAP 9 /* Jumped to kernel code page. */ | ||
| 41 | 42 | ||
| 42 | #define ARMV7M_EXCP_RESET 1 | 43 | #define ARMV7M_EXCP_RESET 1 |
| 43 | #define ARMV7M_EXCP_NMI 2 | 44 | #define ARMV7M_EXCP_NMI 2 |
| @@ -216,6 +217,10 @@ int cpu_arm_signal_handler(int host_signum, void *pinfo, | @@ -216,6 +217,10 @@ int cpu_arm_signal_handler(int host_signum, void *pinfo, | ||
| 216 | 217 | ||
| 217 | void cpu_lock(void); | 218 | void cpu_lock(void); |
| 218 | void cpu_unlock(void); | 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 | #define CPSR_M (0x1f) | 225 | #define CPSR_M (0x1f) |
| 221 | #define CPSR_T (1 << 5) | 226 | #define CPSR_T (1 << 5) |
target-arm/translate.c
| @@ -8583,7 +8583,16 @@ static inline int gen_intermediate_code_internal(CPUState *env, | @@ -8583,7 +8583,16 @@ static inline int gen_intermediate_code_internal(CPUState *env, | ||
| 8583 | store_cpu_field(tmp, condexec_bits); | 8583 | store_cpu_field(tmp, condexec_bits); |
| 8584 | } | 8584 | } |
| 8585 | do { | 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 | if (dc->pc >= 0xfffffff0 && IS_M(env)) { | 8596 | if (dc->pc >= 0xfffffff0 && IS_M(env)) { |
| 8588 | /* We always get here via a jump, so know we are not in a | 8597 | /* We always get here via a jump, so know we are not in a |
| 8589 | conditional execution block. */ | 8598 | conditional execution block. */ |