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. */ | ... | ... |