diff options
author | Dr. David Alan Gilbert <david.gilbert@linaro.org> | 2011-08-31 17:24:34 +0100 |
---|---|---|
committer | Riku Voipio <riku.voipio@linaro.org> | 2011-09-09 10:46:02 +0300 |
commit | 97cc75606aef406e90a243cdb25347039003e7f0 (patch) | |
tree | 26fc8e31ebe00fdd98da851adaaec5b828fecd5c /linux-user/elfload.c | |
parent | 70afc343c75ecc8895b9308ee6a15fcc7a3b0f3e (diff) |
linux-user: Implement new ARM 64 bit cmpxchg kernel helper
linux-user: Implement new ARM 64 bit cmpxchg kernel helper
Linux 3.1 will have a new kernel-page helper for ARM implementing
64 bit cmpxchg. Implement this helper in QEMU linux-user mode:
* Provide kernel helper emulation for 64bit cmpxchg
* Allow guest to object to guest offset to ensure it can map a page
* Populate page with kernel helper version
Signed-off-by: Riku Voipio <riku.voipio@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Dr. David Alan Gilbert <david.gilbert@linaro.org>
Diffstat (limited to 'linux-user/elfload.c')
-rw-r--r-- | linux-user/elfload.c | 56 |
1 files changed, 54 insertions, 2 deletions
diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 04e8e6e065..8677bba0d8 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -332,6 +332,49 @@ enum ARM_HWCAP_ARM_VFPv3D16 = 1 << 13, }; +#define TARGET_HAS_GUEST_VALIDATE_BASE +/* We want the opportunity to check the suggested base */ +bool guest_validate_base(unsigned long guest_base) +{ + unsigned long real_start, test_page_addr; + + /* We need to check that we can force a fault on access to the + * commpage at 0xffff0fxx + */ + test_page_addr = guest_base + (0xffff0f00 & qemu_host_page_mask); + /* Note it needs to be writeable to let us initialise it */ + real_start = (unsigned long) + mmap((void *)test_page_addr, qemu_host_page_size, + PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + /* If we can't map it then try another address */ + if (real_start == -1ul) { + return 0; + } + + if (real_start != test_page_addr) { + /* OS didn't put the page where we asked - unmap and reject */ + munmap((void *)real_start, qemu_host_page_size); + return 0; + } + + /* Leave the page mapped + * Populate it (mmap should have left it all 0'd) + */ + + /* Kernel helper versions */ + __put_user(5, (uint32_t *)g2h(0xffff0ffcul)); + + /* Now it's populated make it RO */ + if (mprotect((void *)test_page_addr, qemu_host_page_size, PROT_READ)) { + perror("Protecting guest commpage"); + exit(-1); + } + + return 1; /* All good */ +} + #define ELF_HWCAP (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF \ | ARM_HWCAP_ARM_THUMB | ARM_HWCAP_ARM_FAST_MULT \ | ARM_HWCAP_ARM_FPA | ARM_HWCAP_ARM_VFP \ @@ -1309,6 +1352,14 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, return sp; } +#ifndef TARGET_HAS_GUEST_VALIDATE_BASE +/* If the guest doesn't have a validation function just agree */ +bool guest_validate_base(unsigned long guest_base) +{ + return 1; +} +#endif + static void probe_guest_base(const char *image_name, abi_ulong loaddr, abi_ulong hiaddr) { @@ -1345,7 +1396,9 @@ static void probe_guest_base(const char *image_name, if (real_start == (unsigned long)-1) { goto exit_perror; } - if (real_start == host_start) { + guest_base = real_start - loaddr; + if ((real_start == host_start) && + guest_validate_base(guest_base)) { break; } /* That address didn't work. Unmap and try a different one. @@ -1368,7 +1421,6 @@ static void probe_guest_base(const char *image_name, qemu_log("Relocating guest address space from 0x" TARGET_ABI_FMT_lx " to 0x%lx\n", loaddr, real_start); - guest_base = real_start - loaddr; } return; |