From c8b0bf545631b55f9e8288252a7b026a97872dd3 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 23 Jul 2012 08:05:20 +0000 Subject: [PATCH 01/10] linux-user: Fix incorrect TARGET_BLKBSZGET, TARGET_BLKBSZSET The definitions for the ioctl numbers TARGET_BLKBSZGET and TARGET_BLKBSZSET had the wrong size parameters (they are defined with size_t, not int, even though the ioctl implementations themselves read and write integers). Since commit 354a0008 we now have an ioctl wrapper definition for BLKBSZGET and so on an x86-64-to-x86-64 linux-user binary we were triggering the mismatch warning in syscall_init(). Signed-off-by: Peter Maydell --- linux-user/syscall_defs.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index ba9a58c814..20265798cd 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -880,8 +880,8 @@ struct target_pollfd { #define TARGET_BLKSECTGET TARGET_IO(0x12,103)/* get max sectors per request (ll_rw_blk.c) */ #define TARGET_BLKSSZGET TARGET_IO(0x12,104)/* get block device sector size */ /* A jump here: 108-111 have been used for various private purposes. */ -#define TARGET_BLKBSZGET TARGET_IOR(0x12,112,int) -#define TARGET_BLKBSZSET TARGET_IOW(0x12,113,int) +#define TARGET_BLKBSZGET TARGET_IOR(0x12, 112, abi_ulong) +#define TARGET_BLKBSZSET TARGET_IOW(0x12, 113, abi_ulong) #define TARGET_BLKGETSIZE64 TARGET_IOR(0x12,114,abi_ulong) /* return device size in bytes (u64 *arg) */ From 5f72307d90a00caabdf786d940418f810bd7c095 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 23 Jul 2012 08:06:15 +0000 Subject: [PATCH 02/10] linux-user: Fix SNDCTL_DSP_MAP{IN, OUT}BUF ioctl definitions Fix the SNDCTL_DSP_MAP{IN,OUT}BUF ioctl definitions so that they refer to a suitably defined target struct layout rather than hardcoding the ioctl number. This fixes complaints from the syscall_init() consistency check when running an x86_64-to-x86_64 linux-user qemu. Signed-off-by: Peter Maydell --- linux-user/ioctls.h | 4 ++-- linux-user/syscall_defs.h | 4 ++-- linux-user/syscall_types.h | 3 +++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index eb96a084c2..8a4776756a 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -186,8 +186,8 @@ IOCTL(SNDCTL_DSP_GETISPACE, IOC_R, MK_PTR(MK_STRUCT(STRUCT_audio_buf_info))) IOCTL(SNDCTL_DSP_GETOSPACE, IOC_R, MK_PTR(MK_STRUCT(STRUCT_audio_buf_info))) IOCTL(SNDCTL_DSP_GETTRIGGER, IOC_R, MK_PTR(TYPE_INT)) - IOCTL(SNDCTL_DSP_MAPINBUF, IOC_R, MK_PTR(TYPE_INT)) - IOCTL(SNDCTL_DSP_MAPOUTBUF, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_DSP_MAPINBUF, IOC_R, MK_PTR(MK_STRUCT(STRUCT_buffmem_desc))) + IOCTL(SNDCTL_DSP_MAPOUTBUF, IOC_R, MK_PTR(MK_STRUCT(STRUCT_buffmem_desc))) IOCTL(SNDCTL_DSP_NONBLOCK, 0, TYPE_NULL) IOCTL(SNDCTL_DSP_POST, 0, TYPE_NULL) IOCTL(SNDCTL_DSP_RESET, 0, TYPE_NULL) diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 20265798cd..2cfda5afd5 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -2226,8 +2226,8 @@ struct target_eabi_flock64 { #define TARGET_SNDCTL_DSP_GETTRIGGER TARGET_IOR('P',16, int) #define TARGET_SNDCTL_DSP_GETIPTR TARGET_IORU('P',17) #define TARGET_SNDCTL_DSP_GETOPTR TARGET_IORU('P',18) -#define TARGET_SNDCTL_DSP_MAPINBUF 0x80085013 -#define TARGET_SNDCTL_DSP_MAPOUTBUF 0x80085014 +#define TARGET_SNDCTL_DSP_MAPINBUF TARGET_IORU('P', 19) +#define TARGET_SNDCTL_DSP_MAPOUTBUF TARGET_IORU('P', 20) #define TARGET_SNDCTL_DSP_NONBLOCK 0x0000500e #define TARGET_SNDCTL_DSP_SAMPLESIZE 0xc0045005 #define TARGET_SNDCTL_DSP_SETDUPLEX 0x00005016 diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h index 601618df98..44b6a58820 100644 --- a/linux-user/syscall_types.h +++ b/linux-user/syscall_types.h @@ -77,6 +77,9 @@ STRUCT(audio_buf_info, STRUCT(count_info, TYPE_INT, TYPE_INT, TYPE_INT) +STRUCT(buffmem_desc, + TYPE_PTRVOID, TYPE_INT) + STRUCT(mixer_info, MK_ARRAY(TYPE_CHAR, 16), MK_ARRAY(TYPE_CHAR, 32), TYPE_INT, MK_ARRAY(TYPE_INT, 10)) From dd6e957a142d9582df766b5c6de2fbb6773241f2 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 23 Jul 2012 08:07:22 +0000 Subject: [PATCH 03/10] linux-user: Move target_to_host_errno_table[] setup out of ioctl loop The code to initialise the target_to_host_errno_table[] array was accidentally inside the loop through checking and initialising all the supported ioctls. This was harmless but meant that we reinitialised the array several hundred times on startup. Signed-off-by: Peter Maydell --- linux-user/syscall.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 3ba3ef5719..8a06131166 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -4606,6 +4606,12 @@ void syscall_init(void) #undef STRUCT #undef STRUCT_SPECIAL + /* Build target_to_host_errno_table[] table from + * host_to_target_errno_table[]. */ + for (i = 0; i < ERRNO_TABLE_SIZE; i++) { + target_to_host_errno_table[host_to_target_errno_table[i]] = i; + } + /* we patch the ioctl size if necessary. We rely on the fact that no ioctl has all the bits at '1' in the size field */ ie = ioctl_entries; @@ -4625,11 +4631,6 @@ void syscall_init(void) (size << TARGET_IOC_SIZESHIFT); } - /* Build target_to_host_errno_table[] table from - * host_to_target_errno_table[]. */ - for (i=0; i < ERRNO_TABLE_SIZE; i++) - target_to_host_errno_table[host_to_target_errno_table[i]] = i; - /* automatic consistency check if same arch */ #if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \ (defined(__x86_64__) && defined(TARGET_X86_64)) From ca6190673c90e283897740b243f6508055c9de5a Mon Sep 17 00:00:00 2001 From: Jing Huang Date: Tue, 24 Jul 2012 13:58:02 +0000 Subject: [PATCH 04/10] linux-user: pass sockaddr from host to target Signed-off-by: Jing Huang Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- linux-user/syscall.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 8a06131166..4bc11f186d 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1268,7 +1268,6 @@ static inline abi_long host_to_target_sockaddr(abi_ulong target_addr, return 0; } -/* ??? Should this also swap msgh->name? */ static inline abi_long target_to_host_cmsg(struct msghdr *msgh, struct target_msghdr *target_msgh) { @@ -1325,7 +1324,6 @@ static inline abi_long target_to_host_cmsg(struct msghdr *msgh, return 0; } -/* ??? Should this also swap msgh->name? */ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh, struct msghdr *msgh) { @@ -1885,10 +1883,22 @@ static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg, if (!is_error(ret)) { len = ret; ret = host_to_target_cmsg(msgp, &msg); - if (!is_error(ret)) + if (!is_error(ret)) { + msgp->msg_namelen = tswap32(msg.msg_namelen); + if (msg.msg_name != NULL) { + ret = host_to_target_sockaddr(tswapal(msgp->msg_name), + msg.msg_name, msg.msg_namelen); + if (ret) { + goto out; + } + } + ret = len; + } } } + +out: unlock_iovec(vec, target_vec, count, !send); unlock_user_struct(msgp, target_msg, send ? 0 : 1); return ret; From 920394db819e30fbbfa527f25e45360061d1a220 Mon Sep 17 00:00:00 2001 From: Jing Huang Date: Tue, 24 Jul 2012 13:59:23 +0000 Subject: [PATCH 05/10] linux-user: make do_setsockopt support SOL_RAW ICMP_FILTER socket option Signed-off-by: Jing Huang Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- linux-user/syscall.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 4bc11f186d..ae9c1d0d12 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -60,6 +60,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base, #include #include #include +#include #include "qemu-common.h" #ifdef TARGET_GPROF #include @@ -1448,6 +1449,25 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, unlock_user (ip_mreq_source, optval_addr, 0); break; + default: + goto unimplemented; + } + break; + case SOL_RAW: + switch (optname) { + case ICMP_FILTER: + /* struct icmp_filter takes an u32 value */ + if (optlen < sizeof(uint32_t)) { + return -TARGET_EINVAL; + } + + if (get_user_u32(val, optval_addr)) { + return -TARGET_EFAULT; + } + ret = get_errno(setsockopt(sockfd, level, optname, + &val, sizeof(val))); + break; + default: goto unimplemented; } From aebf5bc727fa1837b3c5296c5325b560f19ed9ee Mon Sep 17 00:00:00 2001 From: Jing Huang Date: Tue, 24 Jul 2012 14:01:42 +0000 Subject: [PATCH 06/10] linux-user: make host_to_target_cmsg support SO_TIMESTAMP cmsg_type Signed-off-by: Jing Huang Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- linux-user/syscall.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index ae9c1d0d12..41c869bfe0 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1359,16 +1359,28 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh, target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type); target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(len)); - if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { - gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type); - memcpy(target_data, data, len); - } else { + if ((cmsg->cmsg_level == TARGET_SOL_SOCKET) && + (cmsg->cmsg_type == SCM_RIGHTS)) { int *fd = (int *)data; int *target_fd = (int *)target_data; int i, numfds = len / sizeof(int); for (i = 0; i < numfds; i++) target_fd[i] = tswap32(fd[i]); + } else if ((cmsg->cmsg_level == TARGET_SOL_SOCKET) && + (cmsg->cmsg_type == SO_TIMESTAMP) && + (len == sizeof(struct timeval))) { + /* copy struct timeval to target */ + struct timeval *tv = (struct timeval *)data; + struct target_timeval *target_tv = + (struct target_timeval *)target_data; + + target_tv->tv_sec = tswapal(tv->tv_sec); + target_tv->tv_usec = tswapal(tv->tv_usec); + } else { + gemu_log("Unsupported ancillary data: %d/%d\n", + cmsg->cmsg_level, cmsg->cmsg_type); + memcpy(target_data, data, len); } cmsg = CMSG_NXTHDR(msgh, cmsg); From cd8e407d24657569e0d6e323b2e8c274fafab590 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Mon, 9 Jul 2012 03:04:57 +0000 Subject: [PATCH 07/10] flatload: fix bss clearing The current bss clear logic assumes the target mmap address and host address are the same. Use g2h to translate from the target address space to the host so we can call memset on it. Signed-off-by: Mike Frysinger Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- linux-user/flatload.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/flatload.c b/linux-user/flatload.c index be794960cc..58f679e072 100644 --- a/linux-user/flatload.c +++ b/linux-user/flatload.c @@ -660,7 +660,7 @@ static int load_flat_file(struct linux_binprm * bprm, } /* zero the BSS. */ - memset((void *)((unsigned long)datapos + data_len), 0, bss_len); + memset(g2h(datapos + data_len), 0, bss_len); return 0; } From dce104013d1b393d39a89c4417d7771d928c08f3 Mon Sep 17 00:00:00 2001 From: Meador Inge Date: Thu, 26 Jul 2012 16:50:01 +0000 Subject: [PATCH 08/10] linux-user: Factor out guest space probing into a function Signed-off-by: Meador Inge Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- linux-user/elfload.c | 110 ++++++++++++++++++++++++++++++------------- linux-user/qemu.h | 13 +++++ 2 files changed, 90 insertions(+), 33 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 6b622d4ff9..cbc7617765 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -1426,6 +1426,73 @@ bool guest_validate_base(unsigned long guest_base) } #endif +unsigned long init_guest_space(unsigned long host_start, + unsigned long host_size, + unsigned long guest_start, + bool fixed) +{ + unsigned long current_start, real_start; + int flags; + + assert(host_start || host_size); + + /* If just a starting address is given, then just verify that + * address. */ + if (host_start && !host_size) { + if (guest_validate_base(host_start)) { + return host_start; + } else { + return (unsigned long)-1; + } + } + + /* Setup the initial flags and start address. */ + current_start = host_start & qemu_host_page_mask; + flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE; + if (fixed) { + flags |= MAP_FIXED; + } + + /* Otherwise, a non-zero size region of memory needs to be mapped + * and validated. */ + while (1) { + /* Do not use mmap_find_vma here because that is limited to the + * guest address space. We are going to make the + * guest address space fit whatever we're given. + */ + real_start = (unsigned long) + mmap((void *)current_start, host_size, PROT_NONE, flags, -1, 0); + if (real_start == (unsigned long)-1) { + return (unsigned long)-1; + } + + if ((real_start == current_start) + && guest_validate_base(real_start - guest_start)) { + break; + } + + /* That address didn't work. Unmap and try a different one. + * The address the host picked because is typically right at + * the top of the host address space and leaves the guest with + * no usable address space. Resort to a linear search. We + * already compensated for mmap_min_addr, so this should not + * happen often. Probably means we got unlucky and host + * address space randomization put a shared library somewhere + * inconvenient. + */ + munmap((void *)real_start, host_size); + current_start += qemu_host_page_size; + if (host_start == current_start) { + /* Theoretically possible if host doesn't have any suitably + * aligned areas. Normally the first mmap will fail. + */ + return (unsigned long)-1; + } + } + + return real_start; +} + static void probe_guest_base(const char *image_name, abi_ulong loaddr, abi_ulong hiaddr) { @@ -1452,46 +1519,23 @@ static void probe_guest_base(const char *image_name, } } host_size = hiaddr - loaddr; - while (1) { - /* Do not use mmap_find_vma here because that is limited to the - guest address space. We are going to make the - guest address space fit whatever we're given. */ - real_start = (unsigned long) - mmap((void *)host_start, host_size, PROT_NONE, - MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, -1, 0); - if (real_start == (unsigned long)-1) { - goto exit_perror; - } - 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. - The address the host picked because is typically right at - the top of the host address space and leaves the guest with - no usable address space. Resort to a linear search. We - already compensated for mmap_min_addr, so this should not - happen often. Probably means we got unlucky and host - address space randomization put a shared library somewhere - inconvenient. */ - munmap((void *)real_start, host_size); - host_start += qemu_host_page_size; - if (host_start == loaddr) { - /* Theoretically possible if host doesn't have any suitably - aligned areas. Normally the first mmap will fail. */ - errmsg = "Unable to find space for application"; - goto exit_errmsg; - } + + /* Setup the initial guest memory space with ranges gleaned from + * the ELF image that is being loaded. + */ + real_start = init_guest_space(host_start, host_size, loaddr, false); + if (real_start == (unsigned long)-1) { + errmsg = "Unable to find space for application"; + goto exit_errmsg; } + guest_base = real_start - loaddr; + qemu_log("Relocating guest address space from 0x" TARGET_ABI_FMT_lx " to 0x%lx\n", loaddr, real_start); } return; -exit_perror: - errmsg = strerror(errno); exit_errmsg: fprintf(stderr, "%s: %s\n", image_name, errmsg); exit(-1); diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 7b299b7bc3..7d4e23e4c1 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -210,6 +210,19 @@ void fork_end(int child); */ bool guest_validate_base(unsigned long guest_base); +/* Creates the initial guest address space in the host memory space using + * the given host start address hint and size. The guest_start parameter + * specifies the start address of the guest space. guest_base will be the + * difference between the host start address computed by this function and + * guest_start. If fixed is specified, then the mapped address space must + * start at host_start. The real start address of the mapped memory space is + * returned or -1 if there was an error. + */ +unsigned long init_guest_space(unsigned long host_start, + unsigned long host_size, + unsigned long guest_start, + bool fixed); + #include "qemu-log.h" /* strace.c */ From 806d102141b99d4f1e55a97d68b7ea8c8ba3129f Mon Sep 17 00:00:00 2001 From: Meador Inge Date: Thu, 26 Jul 2012 16:50:02 +0000 Subject: [PATCH 09/10] linux-user: Use init_guest_space when -R and -B are specified Roll the code used to initialize the guest memory space when -R or -B is used into 'init_guest_space' and then call 'init_guest_space' from the driver. This way the reserved guest memory space can be probed for. Calling 'mmap' just once as is currently done is not guaranteed to succeed since the host address space validation might fail. Signed-off-by: Meador Inge [PMM: Fixed minor whitespace errors.] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- linux-user/elfload.c | 59 +++++++++++++++++++++++++++++++++++++------- linux-user/main.c | 35 +++++--------------------- linux-user/qemu.h | 6 ----- 3 files changed, 56 insertions(+), 44 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index cbc7617765..819fdd515a 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -332,9 +332,17 @@ 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) +#define TARGET_HAS_VALIDATE_GUEST_SPACE +/* Return 1 if the proposed guest space is suitable for the guest. + * Return 0 if the proposed guest space isn't suitable, but another + * address space should be tried. + * Return -1 if there is no way the proposed guest space can be + * valid regardless of the base. + * The guest code may leave a page mapped and populate it if the + * address is suitable. + */ +static int validate_guest_space(unsigned long guest_base, + unsigned long guest_size) { unsigned long real_start, test_page_addr; @@ -342,6 +350,15 @@ bool guest_validate_base(unsigned long guest_base) * commpage at 0xffff0fxx */ test_page_addr = guest_base + (0xffff0f00 & qemu_host_page_mask); + + /* If the commpage lies within the already allocated guest space, + * then there is no way we can allocate it. + */ + if (test_page_addr >= guest_base + && test_page_addr <= (guest_base + guest_size)) { + return -1; + } + /* Note it needs to be writeable to let us initialise it */ real_start = (unsigned long) mmap((void *)test_page_addr, qemu_host_page_size, @@ -1418,9 +1435,10 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, return sp; } -#ifndef TARGET_HAS_GUEST_VALIDATE_BASE +#ifndef TARGET_HAS_VALIDATE_GUEST_SPACE /* If the guest doesn't have a validation function just agree */ -bool guest_validate_base(unsigned long guest_base) +static int validate_guest_space(unsigned long guest_base, + unsigned long guest_size) { return 1; } @@ -1439,7 +1457,7 @@ unsigned long init_guest_space(unsigned long host_start, /* If just a starting address is given, then just verify that * address. */ if (host_start && !host_size) { - if (guest_validate_base(host_start)) { + if (validate_guest_space(host_start, host_size) == 1) { return host_start; } else { return (unsigned long)-1; @@ -1456,6 +1474,8 @@ unsigned long init_guest_space(unsigned long host_start, /* Otherwise, a non-zero size region of memory needs to be mapped * and validated. */ while (1) { + unsigned long real_size = host_size; + /* Do not use mmap_find_vma here because that is limited to the * guest address space. We are going to make the * guest address space fit whatever we're given. @@ -1466,9 +1486,28 @@ unsigned long init_guest_space(unsigned long host_start, return (unsigned long)-1; } - if ((real_start == current_start) - && guest_validate_base(real_start - guest_start)) { - break; + /* Ensure the address is properly aligned. */ + if (real_start & ~qemu_host_page_mask) { + munmap((void *)real_start, host_size); + real_size = host_size + qemu_host_page_size; + real_start = (unsigned long) + mmap((void *)real_start, real_size, PROT_NONE, flags, -1, 0); + if (real_start == (unsigned long)-1) { + return (unsigned long)-1; + } + real_start = HOST_PAGE_ALIGN(real_start); + } + + /* Check to see if the address is valid. */ + if (!host_start || real_start == current_start) { + int valid = validate_guest_space(real_start - guest_start, + real_size); + if (valid == 1) { + break; + } else if (valid == -1) { + return (unsigned long)-1; + } + /* valid == 0, so try again. */ } /* That address didn't work. Unmap and try a different one. @@ -1490,6 +1529,8 @@ unsigned long init_guest_space(unsigned long host_start, } } + qemu_log("Reserved 0x%lx bytes of guest address space\n", host_size); + return real_start; } diff --git a/linux-user/main.c b/linux-user/main.c index 9d921aa4f0..63c1249576 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -3516,39 +3516,16 @@ int main(int argc, char **argv, char **envp) */ guest_base = HOST_PAGE_ALIGN(guest_base); - if (reserved_va) { - void *p; - int flags; - - flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE; - if (have_guest_base) { - flags |= MAP_FIXED; - } - p = mmap((void *)guest_base, reserved_va, PROT_NONE, flags, -1, 0); - if (p == MAP_FAILED) { + if (reserved_va || have_guest_base) { + guest_base = init_guest_space(guest_base, reserved_va, 0, + have_guest_base); + if (guest_base == (unsigned long)-1) { fprintf(stderr, "Unable to reserve guest address space\n"); exit(1); } - guest_base = (unsigned long)p; - /* Make sure the address is properly aligned. */ - if (guest_base & ~qemu_host_page_mask) { - munmap(p, reserved_va); - p = mmap((void *)guest_base, reserved_va + qemu_host_page_size, - PROT_NONE, flags, -1, 0); - if (p == MAP_FAILED) { - fprintf(stderr, "Unable to reserve guest address space\n"); - exit(1); - } - guest_base = HOST_PAGE_ALIGN((unsigned long)p); - } - qemu_log("Reserved 0x%lx bytes of guest address space\n", reserved_va); - mmap_next_start = reserved_va; - } - if (reserved_va || have_guest_base) { - if (!guest_validate_base(guest_base)) { - fprintf(stderr, "Guest base/Reserved VA rejected by guest code\n"); - exit(1); + if (reserved_va) { + mmap_next_start = reserved_va; } } #endif /* CONFIG_USE_GUEST_BASE */ diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 7d4e23e4c1..69b27d7146 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -204,12 +204,6 @@ int get_osversion(void); void fork_start(void); void fork_end(int child); -/* Return true if the proposed guest_base is suitable for the guest. - * The guest code may leave a page mapped and populate it if the - * address is suitable. - */ -bool guest_validate_base(unsigned long guest_base); - /* Creates the initial guest address space in the host memory space using * the given host start address hint and size. The guest_start parameter * specifies the start address of the guest space. guest_base will be the From 3a1363acf9648bc26989b01b87c7c3c494df2138 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 29 May 2012 05:30:26 +0000 Subject: [PATCH 10/10] linux-user: ARM: Ignore immediate value for svc in thumb mode When running in thumb mode, Linux doesn't evaluate the immediate value of the svc instruction, but instead just always assumes the syscall number to be in r7. This fixes executing go_bootstrap while building go for me. Signed-off-by: Alexander Graf Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- linux-user/main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 63c1249576..7dea084873 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -822,8 +822,7 @@ void cpu_loop(CPUARMState *env) } else if (n == ARM_NR_semihosting || n == ARM_NR_thumb_semihosting) { env->regs[0] = do_arm_semihosting (env); - } else if (n == 0 || n >= ARM_SYSCALL_BASE - || (env->thumb && n == ARM_THUMB_SYSCALL)) { + } else if (n == 0 || n >= ARM_SYSCALL_BASE || env->thumb) { /* linux syscall */ if (env->thumb || n == 0) { n = env->regs[7];