aboutsummaryrefslogtreecommitdiff
path: root/linux-user/elfload.c
diff options
context:
space:
mode:
authorDr. David Alan Gilbert <david.gilbert@linaro.org>2011-08-31 17:24:34 +0100
committerRiku Voipio <riku.voipio@linaro.org>2011-09-09 10:46:02 +0300
commit97cc75606aef406e90a243cdb25347039003e7f0 (patch)
tree26fc8e31ebe00fdd98da851adaaec5b828fecd5c /linux-user/elfload.c
parent70afc343c75ecc8895b9308ee6a15fcc7a3b0f3e (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.c56
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;