From patchwork Fri Jul 27 02:50:02 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Meador Inge X-Patchwork-Id: 173552 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 0A0472C0096 for ; Fri, 27 Jul 2012 12:50:31 +1000 (EST) Received: from localhost ([::1]:54780 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SuadJ-0002md-4Y for incoming@patchwork.ozlabs.org; Thu, 26 Jul 2012 22:50:29 -0400 Received: from eggs.gnu.org ([208.118.235.92]:54929) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Suad5-0002cc-Ef for qemu-devel@nongnu.org; Thu, 26 Jul 2012 22:50:16 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Suad3-00005K-Vb for qemu-devel@nongnu.org; Thu, 26 Jul 2012 22:50:15 -0400 Received: from relay1.mentorg.com ([192.94.38.131]:49299) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Suad3-00005C-NL for qemu-devel@nongnu.org; Thu, 26 Jul 2012 22:50:13 -0400 Received: from svr-orw-fem-01.mgc.mentorg.com ([147.34.98.93]) by relay1.mentorg.com with esmtp id 1Suad3-0002af-5H from meador_inge@mentor.com ; Thu, 26 Jul 2012 19:50:13 -0700 Received: from SVR-ORW-FEM-03.mgc.mentorg.com ([147.34.97.39]) by svr-orw-fem-01.mgc.mentorg.com over TLS secured channel with Microsoft SMTPSVC(6.0.3790.4675); Thu, 26 Jul 2012 19:50:12 -0700 Received: from dhalsim.gateway.2wire.net (147.34.91.1) by svr-orw-fem-03.mgc.mentorg.com (147.34.97.39) with Microsoft SMTP Server id 14.1.289.1; Thu, 26 Jul 2012 19:50:12 -0700 From: Meador Inge To: Date: Thu, 26 Jul 2012 21:50:02 -0500 Message-ID: <1343357402-20685-3-git-send-email-meadori@codesourcery.com> X-Mailer: git-send-email 1.7.7.6 In-Reply-To: <1343357402-20685-1-git-send-email-meadori@codesourcery.com> References: <1343357402-20685-1-git-send-email-meadori@codesourcery.com> MIME-Version: 1.0 X-OriginalArrivalTime: 27 Jul 2012 02:50:12.0985 (UTC) FILETIME=[8B515690:01CD6BA2] X-detected-operating-system: by eggs.gnu.org: Solaris 10 (beta) X-Received-From: 192.94.38.131 Cc: riku.voipio@iki.fi, paul@codesourcery.com Subject: [Qemu-devel] [PATCH v2 2/2] linux-user: Use init_guest_space when -R and -B are specified X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 Reviewed-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 7d8d866..977521a 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, @@ -1377,9 +1394,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; } @@ -1398,7 +1416,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; @@ -1415,6 +1433,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. @@ -1425,9 +1445,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. @@ -1449,6 +1488,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 d0e0e4f..f569a7e 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -3425,39 +3425,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 7d4e23e..69b27d7 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