From patchwork Fri Aug 19 22:43:22 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Kiper X-Patchwork-Id: 9291303 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 8D0E8600CB for ; Fri, 19 Aug 2016 22:47:37 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8FE8C295CE for ; Fri, 19 Aug 2016 22:47:37 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 84BB9295D6; Fri, 19 Aug 2016 22:47:37 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id C8432295CE for ; Fri, 19 Aug 2016 22:47:36 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1basXc-00035t-7m; Fri, 19 Aug 2016 22:45:32 +0000 Received: from mail6.bemta6.messagelabs.com ([193.109.254.103]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1basXb-000355-0s for xen-devel@lists.xenproject.org; Fri, 19 Aug 2016 22:45:31 +0000 Received: from [85.158.143.35] by server-11.bemta-6.messagelabs.com id 11/C9-08498-A0C87B75; Fri, 19 Aug 2016 22:45:30 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFvrDLMWRWlGSWpSXmKPExsXSO6nOVZezZ3u 4wdK5whbft0xmcmD0OPzhCksAYxRrZl5SfkUCa8a1li/MBdvtKl6c3cLSwDjLqIuRi0NIoI1J 4tHBDuYuRk4g5wujxK49zBCJjYwSx66dZ4JwJjJKdM5dyg5SxSagI3Hxy0MwW0RASeLeqslgR cwCc5gkrvbuYgJJCAu4SBw5sAWsiEVAVeJ3ZyfYCl4BD4mZzzaD2RICihLdzyawgdicQPE/mx 4xQZzhLvH4zw82iBpDidMPtzFOYORbwMiwilG9OLWoLLVI11AvqSgzPaMkNzEzR9fQwEwvN7W 4ODE9NScxqVgvOT93EyMwVBiAYAfjzudOhxglOZiURHn91LaHC/El5adUZiQWZ8QXleakFh9i lOHgUJLgbegCygkWpaanVqRl5gCDFiYtwcGjJMK7BSTNW1yQmFucmQ6ROsWoKCXOGw2SEABJZ JTmwbXBIuUSo6yUMC8j0CFCPAWpRbmZJajyrxjFORiVhHl3g0zhycwrgZv+CmgxE9BiXv4tII tLEhFSUg2MSlfzd52bvYx1UWLr9qanL4vcLezm+gjvv+1u3PWwxpknbc1Dh5JL9xw5Go9xyHg wcvbvTj75ntlAb1GsqujCt6XNh51t6i8em8MX7fdklWLH0hV+KVN3bZ7+MPTiuoLrjDf/CBfm SJsUaDz+b2uzrHOyrWl8dWLcbHu77RxmObwrUlLUz9YqsRRnJBpqMRcVJwIAqif++Y8CAAA= X-Env-Sender: daniel.kiper@oracle.com X-Msg-Ref: server-5.tower-21.messagelabs.com!1471646727!29293125!1 X-Originating-IP: [141.146.126.69] X-SpamReason: No, hits=0.0 required=7.0 tests=sa_preprocessor: VHJ1c3RlZCBJUDogMTQxLjE0Ni4xMjYuNjkgPT4gMjc3MjE4\n X-StarScan-Received: X-StarScan-Version: 8.84; banners=-,-,- X-VirusChecked: Checked Received: (qmail 46546 invoked from network); 19 Aug 2016 22:45:29 -0000 Received: from aserp1040.oracle.com (HELO aserp1040.oracle.com) (141.146.126.69) by server-5.tower-21.messagelabs.com with DHE-RSA-AES256-GCM-SHA384 encrypted SMTP; 19 Aug 2016 22:45:29 -0000 Received: from userv0021.oracle.com (userv0021.oracle.com [156.151.31.71]) by aserp1040.oracle.com (Sentrion-MTA-4.3.2/Sentrion-MTA-4.3.2) with ESMTP id u7JMjJOi014017 (version=TLSv1 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Fri, 19 Aug 2016 22:45:20 GMT Received: from userv0121.oracle.com (userv0121.oracle.com [156.151.31.72]) by userv0021.oracle.com (8.13.8/8.13.8) with ESMTP id u7JMjIuT011379 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Fri, 19 Aug 2016 22:45:19 GMT Received: from abhmp0019.oracle.com (abhmp0019.oracle.com [141.146.116.25]) by userv0121.oracle.com (8.13.8/8.13.8) with ESMTP id u7JMjGdn017707; Fri, 19 Aug 2016 22:45:17 GMT Received: from olila.local.net-space.pl (/10.175.190.131) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Fri, 19 Aug 2016 15:45:16 -0700 From: Daniel Kiper To: xen-devel@lists.xenproject.org Date: Sat, 20 Aug 2016 00:43:22 +0200 Message-Id: <1471646606-28519-13-git-send-email-daniel.kiper@oracle.com> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1471646606-28519-1-git-send-email-daniel.kiper@oracle.com> References: <1471646606-28519-1-git-send-email-daniel.kiper@oracle.com> X-Source-IP: userv0021.oracle.com [156.151.31.71] Cc: jgross@suse.com, sstabellini@kernel.org, andrew.cooper3@citrix.com, cardoe@cardoe.com, pgnet.dev@gmail.com, ning.sun@intel.com, david.vrabel@citrix.com, jbeulich@suse.com, qiaowei.ren@intel.com, gang.wei@intel.com, fu.wei@linaro.org Subject: [Xen-devel] [PATCH v5 12/16] x86/efi: create new early memory allocator X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: xen-devel-bounces@lists.xen.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP There is a problem with place_string() which is used as early memory allocator. It gets memory chunks starting from start symbol and goes down. Sadly this does not work when Xen is loaded using multiboot2 protocol because then the start lives on 1 MiB address and we should not allocate a memory from below of it. So, I tried to use mem_lower address calculated by GRUB2. However, this solution works only on some machines. There are machines in the wild (e.g. Dell PowerEdge R820) which uses first ~640 KiB for boot services code or data... :-((( Hence, we need new memory allocator for Xen EFI boot code which is quite simple and generic and could be used by place_string() and efi_arch_allocate_mmap_buffer(). I think about following solutions: 1) We could use native EFI allocation functions (e.g. AllocatePool() or AllocatePages()) to get memory chunk. However, later (somewhere in __start_xen()) we must copy its contents to safe place or reserve it in e820 memory map and map it in Xen virtual address space. This means that the code referring to Xen command line, loaded modules and EFI memory map, mostly in __start_xen(), will be further complicated and diverge from legacy BIOS cases. Additionally, both former things have to be placed below 4 GiB because their addresses are stored in multiboot_info_t structure which has 32-bit relevant members. 2) We may allocate memory area statically somewhere in Xen code which could be used as memory pool for early dynamic allocations. Looks quite simple. Additionally, it would not depend on EFI at all and could be used on legacy BIOS platforms if we need it. However, we must carefully choose size of this pool. We do not want increase Xen binary size too much and waste too much memory but also we must fit at least memory map on x86 EFI platforms. As I saw on small machine, e.g. IBM System x3550 M2 with 8 GiB RAM, memory map may contain more than 200 entries. Every entry on x86-64 platform is 40 bytes in size. So, it means that we need more than 8 KiB for EFI memory map only. Additionally, if we use this memory pool for Xen and modules command line storage (it would be used when xen.efi is executed as EFI application) then we should add, I think, about 1 KiB. In this case, to be on safe side, we should assume at least 64 KiB pool for early memory allocations. Which is about 4 times of our earlier calculations. However, during discussion on Xen-devel Jan Beulich suggested that just in case we should use 1 MiB memory pool like it is in original place_string() implementation. So, let's use 1 MiB as it was proposed. If we think that we should not waste unallocated memory in the pool on running system then we can mark this region as __initdata and move all required data to dynamically allocated places somewhere in __start_xen(). 2a) We could put memory pool into .bss.page_aligned section. Then allocate memory chunks starting from the lowest address. After init phase we can free unused portion of the memory pool as in case of .init.text or .init.data sections. This way we do not need to allocate any space in image file and freeing of unused area in the memory pool is very simple. Now #2a solution is implemented because it is quite simple and requires limited number of changes, especially in __start_xen(). Signed-off-by: Daniel Kiper --- v4 - suggestions/fixes: - move from #2 solution to #2a solution, - improve commit message. --- xen/arch/x86/efi/efi-boot.h | 58 +++++++++++++++++++++++++++++++++++++------ xen/arch/x86/efi/stub.c | 2 ++ xen/arch/x86/setup.c | 5 ++-- xen/include/xen/efi.h | 1 + 4 files changed, 56 insertions(+), 10 deletions(-) diff --git a/xen/arch/x86/efi/efi-boot.h b/xen/arch/x86/efi/efi-boot.h index 1fa9e47..3f87b7c 100644 --- a/xen/arch/x86/efi/efi-boot.h +++ b/xen/arch/x86/efi/efi-boot.h @@ -103,9 +103,56 @@ static void __init relocate_trampoline(unsigned long phys) *(u16 *)(*trampoline_ptr + (long)trampoline_ptr) = phys >> 4; } +#define EBMALLOC_SIZE MB(1) + +static char __section(".bss.page_aligned") ebmalloc_mem[EBMALLOC_SIZE]; +static char __initdata *ebmalloc_free = NULL; + +/* EFI boot allocator. */ +static void __init *ebmalloc(size_t size) +{ + void *ptr; + + /* + * Init ebmalloc_free on runtime. Static initialization + * will not work because it puts virtual address there. + */ + if ( ebmalloc_free == NULL ) + ebmalloc_free = ebmalloc_mem; + + ptr = ebmalloc_free; + + ebmalloc_free += size; + + if ( ebmalloc_free - ebmalloc_mem > sizeof(ebmalloc_mem) ) + blexit(L"Out of static memory\r\n"); + + return ptr; +} + +void __init free_ebmalloc_unused_mem(void) +{ + unsigned long start, end; + + if ( ebmalloc_free ) + { + start = (unsigned long)ebmalloc_free - xen_phys_start; + start = PAGE_ALIGN(start + XEN_VIRT_START); + } + else + start = (unsigned long)ebmalloc_mem; + + end = (unsigned long)ebmalloc_mem + sizeof(ebmalloc_mem); + + destroy_xen_mappings(start, end); + init_xenheap_pages(__pa(start), __pa(end)); + + printk("Freed %lukB unused BSS memory\n", (end - start) >> 10); +} + static void __init place_string(u32 *addr, const char *s) { - static char *__initdata alloc = start; + char *alloc = NULL; if ( s && *s ) { @@ -113,7 +160,7 @@ static void __init place_string(u32 *addr, const char *s) const char *old = (char *)(long)*addr; size_t len2 = *addr ? strlen(old) + 1 : 0; - alloc -= len1 + len2; + alloc = ebmalloc(len1 + len2); /* * Insert new string before already existing one. This is needed * for options passed on the command line to override options from @@ -196,12 +243,7 @@ static void __init efi_arch_process_memory_map(EFI_SYSTEM_TABLE *SystemTable, static void *__init efi_arch_allocate_mmap_buffer(UINTN map_size) { - place_string(&mbi.mem_upper, NULL); - mbi.mem_upper -= map_size; - mbi.mem_upper &= -__alignof__(EFI_MEMORY_DESCRIPTOR); - if ( mbi.mem_upper < xen_phys_start ) - return NULL; - return (void *)(long)mbi.mem_upper; + return ebmalloc(map_size); } static void __init efi_arch_pre_exit_boot(void) diff --git a/xen/arch/x86/efi/stub.c b/xen/arch/x86/efi/stub.c index f087023..f7bc042 100644 --- a/xen/arch/x86/efi/stub.c +++ b/xen/arch/x86/efi/stub.c @@ -9,6 +9,8 @@ bool_t efi_enabled(int feature) return false; } +void __init free_ebmalloc_unused_mem(void) { } + void __init efi_init_memory(void) { } void efi_update_l4_pgtable(unsigned int l4idx, l4_pgentry_t l4e) { } diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index 360ca59..bc48351 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -520,6 +520,8 @@ static void noinline init_done(void) system_state = SYS_STATE_active; + free_ebmalloc_unused_mem(); + /* MUST be done prior to removing .init data. */ unregister_init_virtual_region(); @@ -1080,8 +1082,7 @@ void __init noreturn __start_xen(unsigned long mbi_p) if ( !xen_phys_start ) panic("Not enough memory to relocate Xen."); - reserve_e820_ram(&boot_e820, efi_enabled(EFI_BOOT) ? mbi->mem_upper : __pa(&_start), - __pa(&_end)); + reserve_e820_ram(&boot_e820, __pa(&_start), __pa(&_end)); /* Late kexec reservation (dynamic start address). */ kexec_reserve_area(&boot_e820); diff --git a/xen/include/xen/efi.h b/xen/include/xen/efi.h index 8372ae2..147a0e8 100644 --- a/xen/include/xen/efi.h +++ b/xen/include/xen/efi.h @@ -33,6 +33,7 @@ struct xenpf_efi_runtime_call; struct compat_pf_efi_runtime_call; bool_t efi_enabled(int feature); +void free_ebmalloc_unused_mem(void); void efi_init_memory(void); bool_t efi_rs_using_pgtables(void); unsigned long efi_get_time(void);