From patchwork Wed Jan 25 22:11:28 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Kiper X-Patchwork-Id: 9538023 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 BEC4D6042B for ; Wed, 25 Jan 2017 22:15:53 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A922820700 for ; Wed, 25 Jan 2017 22:15:53 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 9D4FB26E75; Wed, 25 Jan 2017 22:15:53 +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 39B2420700 for ; Wed, 25 Jan 2017 22:15:52 +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 1cWVnq-0002nr-8D; Wed, 25 Jan 2017 22:12:30 +0000 Received: from mail6.bemta5.messagelabs.com ([195.245.231.135]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cWVno-0002m6-Go for xen-devel@lists.xenproject.org; Wed, 25 Jan 2017 22:12:28 +0000 Received: from [85.158.139.211] by server-5.bemta-5.messagelabs.com id A1/CA-04025-BC229885; Wed, 25 Jan 2017 22:12:27 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFupmkeJIrShJLcpLzFFi42KZM10+UPeUUme EQXerucX3LZOZHBg9Dn+4whLAGMWamZeUX5HAmnGgexJrwc5bjBU7Jr5gbmA8PJexi5GTQ0hg IpPEvEPWXYxcQPY3RonFs+azQzgbGCWeHPjOCOFMYJQ4d/4BM0gLm4COxMUvD9lBbBEBJYl7q yYzgRQxC8xkkjh95yQLSEJYwF/i7vVLTCA2i4CqxKKbW8EaeAXcJfbO2QdWIyGgKNH9bAIbiM 0p4CHRvbCLDeImd4kNLy8yQ9QYSpx+uI1xAiPfAkaGVYwaxalFZalFukbGeklFmekZJbmJmTm 6hgamermpxcWJ6ak5iUnFesn5uZsYgQFTz8DAuINxR7vfIUZJDiYlUd5TpzoihPiS8lMqMxKL M+KLSnNSiw8xynBwKEnwPlLsjBASLEpNT61Iy8wBhi5MWoKDR0mE9xlImre4IDG3ODMdInWKU Zfj1I3TL5mEWPLy81KlxHkPghQJgBRllObBjYDF0SVGWSlhXkYGBgYhnoLUotzMElT5V4ziHI xKwrw1IFN4MvNK4Da9AjqCCeiIC8ztIEeUJCKkpBoYZ/teu3Rz+7fKDAbn1TNefZnM3N/UMJV 1h87ivKSrdrFvU6d7Hq7Yunh91QItpnd2515bnTz9ccfCzNadvDf/G4TYHc0+6GOreLftHKOC 1XLhieXRru//GiTaqcw5e+DLskNW1dcT06vulV5+o3T3+sUJr9Va3wktb4m9PP9BA8uJVfJ85 fVvnymxFGckGmoxFxUnAgCkhHnRngIAAA== X-Env-Sender: daniel.kiper@oracle.com X-Msg-Ref: server-4.tower-206.messagelabs.com!1485382344!81900268!1 X-Originating-IP: [156.151.31.81] X-SpamReason: No, hits=0.0 required=7.0 tests=sa_preprocessor: VHJ1c3RlZCBJUDogMTU2LjE1MS4zMS44MSA9PiAyODgzMzk=\n X-StarScan-Received: X-StarScan-Version: 9.1.1; banners=-,-,- X-VirusChecked: Checked Received: (qmail 44118 invoked from network); 25 Jan 2017 22:12:26 -0000 Received: from userp1040.oracle.com (HELO userp1040.oracle.com) (156.151.31.81) by server-4.tower-206.messagelabs.com with DHE-RSA-AES256-GCM-SHA384 encrypted SMTP; 25 Jan 2017 22:12:26 -0000 Received: from userv0021.oracle.com (userv0021.oracle.com [156.151.31.71]) by userp1040.oracle.com (Sentrion-MTA-4.3.2/Sentrion-MTA-4.3.2) with ESMTP id v0PMC9FE031469 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 25 Jan 2017 22:12:10 GMT Received: from aserv0121.oracle.com (aserv0121.oracle.com [141.146.126.235]) by userv0021.oracle.com (8.14.4/8.14.4) with ESMTP id v0PMC9rw023881 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Wed, 25 Jan 2017 22:12:09 GMT Received: from abhmp0003.oracle.com (abhmp0003.oracle.com [141.146.116.9]) by aserv0121.oracle.com (8.13.8/8.13.8) with ESMTP id v0PMC7TS005095; Wed, 25 Jan 2017 22:12:08 GMT Received: from olila.local.net-space.pl (/10.175.228.37) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Wed, 25 Jan 2017 14:12:06 -0800 From: Daniel Kiper To: xen-devel@lists.xenproject.org Date: Wed, 25 Jan 2017 23:11:28 +0100 Message-Id: <1485382293-13800-5-git-send-email-daniel.kiper@oracle.com> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1485382293-13800-1-git-send-email-daniel.kiper@oracle.com> References: <1485382293-13800-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, julien.grall@arm.com, jbeulich@suse.com, qiaowei.ren@intel.com, gang.wei@intel.com, fu.wei@linaro.org Subject: [Xen-devel] [PATCH v13 4/9] x86: add multiboot2 protocol support for EFI platforms 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 This way Xen can be loaded on EFI platforms using GRUB2 and other boot loaders which support multiboot2 protocol. Signed-off-by: Daniel Kiper --- v13 - suggestions/fixes: - move vga_text_buffer and efi_platform to .init.data section (suggested by Jan Beulich), - reduce number of error branches in EFI code in xen/arch/x86/boot/head.S (suggested by Jan Beulich), - rename run_bs label to .Lrun_bs (suggested by Jan Beulich), - align the stack as UEFI spec requires (suggested by Jan Beulich), - change trampoline region memory layout (suggested by Jan Beulich), - revert changes in efi_arch_pre_exit_boot() (suggested by Jan Beulich), - relocate_trampoline() must set trampoline_phys for all bootloaders; otherwise fallback allocator is always used if Xen was loaded with Multiboot2 protocol, - change err type in efi_multiboot2() to "static const CHAR16 __initconst" (suggested by Jan Beulich), - change asm "g" constraint to "rm" in efi_multiboot2() (suggested by Jan Beulich), - improve comments (suggested by Jan Beulich and Doug Goldstein). v12 - suggestions/fixes: - rename __efi64_start to __efi64_mb2_start (suggested by Andrew Cooper), - use efi_arch_memory_setup() machinery as trampoline et consortes main memory allocator (suggested by Doug Goldstein), - allocate space for mbi struct in efi_arch_memory_setup() too; this thing was not taken into account in earlier releases, - revert trampoline et consortes fallback memory allocator code in efi_arch_process_memory_map() to current upstream state (suggested by Doug Goldstein), - further simplify efi_arch_pre_exit_boot() code, - call efi_arch_memory_setup() from efi_multiboot2() (suggested by Doug Goldstein), - fix asembly call argument in xen/arch/x86/efi/stub.c (suggested by Andrew Cooper), - add ASSERT() for trampoline size (suggested by Doug Goldstein), - add KB() macro (suggested by Doug Goldstein), - improve comments (suggested by Andrew Cooper and Doug Goldstein). v10 - suggestions/fixes: - replace ljmpl with lretq (suggested by Andrew Cooper), - introduce efi_platform to increase code readability (suggested by Andrew Cooper). v9 - suggestions/fixes: - use .L labels instead of numeric ones in multiboot2 data scanning loops (suggested by Jan Beulich). v8 - suggestions/fixes: - use __bss_start(%rip)/__bss_end(%rip) instead of of .startof.(.bss)(%rip)/$.sizeof.(.bss) because latter is not tested extensively in different built environments yet (suggested by Andrew Cooper), - fix multiboot2 data scanning loop in x86_32 code (suggested by Jan Beulich), - add check for extra mem for mbi data if Xen is loaded via multiboot2 protocol on EFI platform (suggested by Jan Beulich), - improve comments (suggested by Jan Beulich). v7 - suggestions/fixes: - do not allocate twice memory for trampoline if we were loaded via multiboot2 protocol on EFI platform, - wrap long line (suggested by Jan Beulich), - improve comments (suggested by Jan Beulich). v6 - suggestions/fixes: - improve label names in assembly error printing code (suggested by Jan Beulich), - improve comments (suggested by Jan Beulich), - various minor cleanups and fixes (suggested by Jan Beulich). v4 - suggestions/fixes: - remove redundant BSS alignment, - update BSS alignment check, - use __set_bit() instead of set_bit() if possible (suggested by Jan Beulich), - call efi_arch_cpu() from efi_multiboot2() even if the same work is done later in other place right now (suggested by Jan Beulich), - xen/arch/x86/efi/stub.c:efi_multiboot2() fail properly on EFI platforms, - do not read data beyond the end of multiboot2 information in xen/arch/x86/boot/head.S (suggested by Jan Beulich), - use 32-bit registers in x86_64 code if possible (suggested by Jan Beulich), - multiboot2 information address is 64-bit in x86_64 code, so, treat it is as is (suggested by Jan Beulich), - use cmovcc if possible, - leave only one space between rep and stosq (suggested by Jan Beulich), - improve error handling, - improve early error messages, (suggested by Jan Beulich), - improve early error messages printing code, - improve label names (suggested by Jan Beulich), - improve comments (suggested by Jan Beulich), - various minor cleanups. v3 - suggestions/fixes: - take into account alignment when skipping multiboot2 fixed part (suggested by Konrad Rzeszutek Wilk), - improve segment registers initialization (suggested by Jan Beulich), - improve comments (suggested by Jan Beulich and Konrad Rzeszutek Wilk), - improve commit message (suggested by Jan Beulich). v2 - suggestions/fixes: - generate multiboot2 header using macros (suggested by Jan Beulich), - switch CPU to x86_32 mode before jumping to 32-bit code (suggested by Andrew Cooper), - reduce code changes to increase patch readability (suggested by Jan Beulich), - improve comments (suggested by Jan Beulich), - ignore MULTIBOOT2_TAG_TYPE_BASIC_MEMINFO tag on EFI platform and find on my own multiboot2.mem_lower value, - stop execution if EFI platform is detected in legacy BIOS path. --- xen/arch/x86/boot/head.S | 297 ++++++++++++++++++++++++++++++++++--- xen/arch/x86/boot/reloc.c | 2 +- xen/arch/x86/efi/efi-boot.h | 52 ++++++- xen/arch/x86/efi/stub.c | 39 +++++ xen/arch/x86/x86_64/asm-offsets.c | 2 + xen/arch/x86/xen.lds.S | 7 +- xen/common/efi/boot.c | 11 ++ xen/include/asm-x86/config.h | 3 + xen/include/xen/config.h | 1 + 9 files changed, 391 insertions(+), 23 deletions(-) diff --git a/xen/arch/x86/boot/head.S b/xen/arch/x86/boot/head.S index 84cf44d..2ecdcb3 100644 --- a/xen/arch/x86/boot/head.S +++ b/xen/arch/x86/boot/head.S @@ -89,6 +89,13 @@ multiboot2_header_start: 0, /* Number of the lines - no preference. */ \ 0 /* Number of bits per pixel - no preference. */ + /* Request that ExitBootServices() not be called. */ + mb2ht_init MB2_HT(EFI_BS), MB2_HT(OPTIONAL) + + /* EFI64 Multiboot2 entry point. */ + mb2ht_init MB2_HT(ENTRY_ADDRESS_EFI64), MB2_HT(OPTIONAL), \ + sym_phys(__efi64_mb2_start) + /* Multiboot2 header end tag. */ mb2ht_init MB2_HT(END), MB2_HT(REQUIRED) .Lmultiboot2_header_end: @@ -100,20 +107,50 @@ multiboot2_header_start: gdt_boot_descr: .word 6*8-1 .long sym_phys(trampoline_gdt) + .long 0 /* Needed for 64-bit lgdt */ .Lbad_cpu_msg: .asciz "ERR: Not a 64-bit CPU!" .Lbad_ldr_msg: .asciz "ERR: Not a Multiboot bootloader!" +.Lbad_ldr_nbs: .asciz "ERR: Bootloader shutdown EFI x64 boot services!" +.Lbad_ldr_nst: .asciz "ERR: EFI SystemTable is not provided by bootloader!" +.Lbad_ldr_nih: .asciz "ERR: EFI ImageHandle is not provided by bootloader!" +.Lbad_efi_msg: .asciz "ERR: EFI IA-32 platforms are not supported!" + + .section .init.data, "a", @progbits + .align 4 + +vga_text_buffer: + .long 0xb8000 + +efi_platform: + .byte 0 .section .init.text, "ax", @progbits bad_cpu: mov $(sym_phys(.Lbad_cpu_msg)),%esi # Error message - jmp print_err + jmp .Lget_vtb not_multiboot: mov $(sym_phys(.Lbad_ldr_msg)),%esi # Error message -print_err: - mov $0xB8000,%edi # VGA framebuffer -1: mov (%esi),%bl + jmp .Lget_vtb +.Lmb2_no_st: + mov $(sym_phys(.Lbad_ldr_nst)),%esi # Error message + jmp .Lget_vtb +.Lmb2_no_ih: + mov $(sym_phys(.Lbad_ldr_nih)),%esi # Error message + jmp .Lget_vtb +.Lmb2_no_bs: + mov $(sym_phys(.Lbad_ldr_nbs)),%esi # Error message + xor %edi,%edi # No VGA text buffer + jmp .Lsend_chr +.Lmb2_efi_ia_32: + mov $(sym_phys(.Lbad_efi_msg)),%esi # Error message + xor %edi,%edi # No VGA text buffer + jmp .Lsend_chr +.Lget_vtb: + mov sym_phys(vga_text_buffer),%edi +.Lsend_chr: + mov (%esi),%bl test %bl,%bl # Terminate on '\0' sentinel je .Lhalt mov $0x3f8+5,%dx # UART Line Status Register @@ -123,13 +160,193 @@ print_err: mov $0x3f8+0,%dx # UART Transmit Holding Register mov %bl,%al out %al,%dx # Send a character over the serial line - movsb # Write a character to the VGA framebuffer + test %edi,%edi # Is the VGA text buffer available? + jz .Lsend_chr + movsb # Write a character to the VGA text buffer mov $7,%al - stosb # Write an attribute to the VGA framebuffer - jmp 1b + stosb # Write an attribute to the VGA text buffer + jmp .Lsend_chr .Lhalt: hlt jmp .Lhalt + .code64 + +__efi64_mb2_start: + /* + * Multiboot2 spec says that here CPU is in 64-bit mode. However, there + * is also guarantee that all code and data is always put by the bootloader + * below 4 GiB. Hence, we can safely use in most cases 32-bit addressing. + */ + + cld + + /* VGA is not available on EFI platforms. */ + movl $0,vga_text_buffer(%rip) + + /* Check for Multiboot2 bootloader. */ + cmp $MULTIBOOT2_BOOTLOADER_MAGIC,%eax + je .Lefi_multiboot2_proto + + /* Jump to not_multiboot after switching CPU to x86_32 mode. */ + lea not_multiboot(%rip),%r15d + jmp x86_32_switch + +.Lefi_multiboot2_proto: + /* Zero EFI SystemTable and EFI ImageHandle addresses. */ + xor %esi,%esi + xor %edi,%edi + + /* Skip Multiboot2 information fixed part. */ + lea (MB2_fixed_sizeof+MULTIBOOT2_TAG_ALIGN-1)(%rbx),%ecx + and $~(MULTIBOOT2_TAG_ALIGN-1),%ecx + +.Lefi_mb2_tsize: + /* Check Multiboot2 information total size. */ + mov %ecx,%r8d + sub %ebx,%r8d + cmp %r8d,MB2_fixed_total_size(%rbx) + jbe .Lrun_bs + + /* Are EFI boot services available? */ + cmpl $MULTIBOOT2_TAG_TYPE_EFI_BS,MB2_tag_type(%rcx) + jne .Lefi_mb2_st + + /* We are on EFI platform and EFI boot services are available. */ + incb efi_platform(%rip) + + /* + * Disable real mode and other legacy stuff which should not + * be run on EFI platforms. + */ + incb skip_realmode(%rip) + jmp .Lefi_mb2_next_tag + +.Lefi_mb2_st: + /* Get EFI SystemTable address from Multiboot2 information. */ + cmpl $MULTIBOOT2_TAG_TYPE_EFI64,MB2_tag_type(%rcx) + cmove MB2_efi64_st(%rcx),%rsi + je .Lefi_mb2_next_tag + + /* Get EFI ImageHandle address from Multiboot2 information. */ + cmpl $MULTIBOOT2_TAG_TYPE_EFI64_IH,MB2_tag_type(%rcx) + cmove MB2_efi64_ih(%rcx),%rdi + je .Lefi_mb2_next_tag + + /* Is it the end of Multiboot2 information? */ + cmpl $MULTIBOOT2_TAG_TYPE_END,MB2_tag_type(%rcx) + je .Lrun_bs + +.Lefi_mb2_next_tag: + /* Go to next Multiboot2 information tag. */ + add MB2_tag_size(%rcx),%ecx + add $(MULTIBOOT2_TAG_ALIGN-1),%ecx + and $~(MULTIBOOT2_TAG_ALIGN-1),%ecx + jmp .Lefi_mb2_tsize + +.Lrun_bs: + /* Are EFI boot services available? */ + cmpb $0,efi_platform(%rip) + + /* Jump to .Lmb2_no_bs after switching CPU to x86_32 mode. */ + lea .Lmb2_no_bs(%rip),%r15d + jz x86_32_switch + + /* Is EFI SystemTable address provided by boot loader? */ + test %rsi,%rsi + + /* Jump to .Lmb2_no_st after switching CPU to x86_32 mode. */ + lea .Lmb2_no_st(%rip),%r15d + jz x86_32_switch + + /* Is EFI ImageHandle address provided by boot loader? */ + test %rdi,%rdi + + /* Jump to .Lmb2_no_ih after switching CPU to x86_32 mode. */ + lea .Lmb2_no_ih(%rip),%r15d + jz x86_32_switch + + /* Align the stack as UEFI spec requires. */ + add $15,%rsp + and $~15,%rsp + + push %rax + push %rdi + + /* + * Initialize BSS (no nasty surprises!). + * It must be done earlier than in BIOS case + * because efi_multiboot2() touches it. + */ + lea __bss_start(%rip),%edi + lea __bss_end(%rip),%ecx + sub %edi,%ecx + shr $3,%ecx + xor %eax,%eax + rep stosq + + pop %rdi + + /* Align the stack as UEFI spec requires. */ + push %rdi + + /* + * efi_multiboot2() is called according to System V AMD64 ABI: + * - IN: %rdi - EFI ImageHandle, %rsi - EFI SystemTable, + * - OUT: %rax - trampoline address. + * + * MULTIBOOT2_TAG_TYPE_BASIC_MEMINFO tag is not provided + * on EFI platforms. Hence, it could not be used like + * on legacy BIOS platforms. + */ + call efi_multiboot2 + + /* Convert memory address to bytes/16 and store it in safe place. */ + shr $4,%eax + mov %eax,%ecx + + pop %rdi + pop %rax + + /* Jump to trampoline_setup after switching CPU to x86_32 mode. */ + lea trampoline_setup(%rip),%r15d + +x86_32_switch: + mov %r15d,%edi + + cli + + /* Initialize GDTR. */ + lgdt gdt_boot_descr(%rip) + + /* Reload code selector. */ + pushq $BOOT_CS32 + lea cs32_switch(%rip),%edx + push %rdx + lretq + + .code32 + +cs32_switch: + /* Initialize basic data segments. */ + mov $BOOT_DS,%edx + mov %edx,%ds + mov %edx,%es + mov %edx,%ss + /* %esp is initialized later. */ + + /* Load null descriptor to unused segment registers. */ + xor %edx,%edx + mov %edx,%fs + mov %edx,%gs + + /* Disable paging. */ + mov %cr0,%edx + and $(~X86_CR0_PG),%edx + mov %edx,%cr0 + + /* Jump to earlier loaded address. */ + jmp *%edi + __start: cld cli @@ -157,7 +374,7 @@ __start: /* Not available? BDA value will be fine. */ cmovnz MB_mem_lower(%ebx),%edx - jmp trampoline_setup + jmp trampoline_bios_setup .Lmultiboot2_proto: /* Skip Multiboot2 information fixed part. */ @@ -169,24 +386,33 @@ __start: mov %ecx,%edi sub %ebx,%edi cmp %edi,MB2_fixed_total_size(%ebx) - jbe trampoline_setup + jbe trampoline_bios_setup /* Get mem_lower from Multiboot2 information. */ cmpl $MULTIBOOT2_TAG_TYPE_BASIC_MEMINFO,MB2_tag_type(%ecx) cmove MB2_mem_lower(%ecx),%edx - je trampoline_setup + je .Lmb2_next_tag + + /* EFI IA-32 platforms are not supported. */ + cmpl $MULTIBOOT2_TAG_TYPE_EFI32,MB2_tag_type(%ecx) + je .Lmb2_efi_ia_32 + + /* Bootloader shutdown EFI x64 boot services. */ + cmpl $MULTIBOOT2_TAG_TYPE_EFI64,MB2_tag_type(%ecx) + je .Lmb2_no_bs /* Is it the end of Multiboot2 information? */ cmpl $MULTIBOOT2_TAG_TYPE_END,MB2_tag_type(%ecx) - je trampoline_setup + je trampoline_bios_setup +.Lmb2_next_tag: /* Go to next Multiboot2 information tag. */ add MB2_tag_size(%ecx),%ecx add $(MULTIBOOT2_TAG_ALIGN-1),%ecx and $~(MULTIBOOT2_TAG_ALIGN-1),%ecx jmp .Lmb2_tsize -trampoline_setup: +trampoline_bios_setup: /* Set up trampoline segment 64k below EBDA */ movzwl 0x40e,%ecx /* EBDA segment */ cmp $0xa000,%ecx /* sanity check (high) */ @@ -202,28 +428,56 @@ trampoline_setup: * multiboot structure (if available) and use the smallest. */ cmp $0x100,%edx /* is the multiboot value too small? */ - jb 2f /* if so, do not use it */ + jb trampoline_setup /* if so, do not use it */ shl $10-4,%edx cmp %ecx,%edx /* compare with BDA value */ cmovb %edx,%ecx /* and use the smaller */ -2: /* Reserve 64kb for the trampoline */ - sub $0x1000,%ecx + /* Reserve memory for the trampoline and the low-memory stack. */ + sub $((TRAMPOLINE_SPACE+TRAMPOLINE_STACK_SPACE)>>4),%ecx /* From arch/x86/smpboot.c: start_eip had better be page-aligned! */ xor %cl, %cl + +trampoline_setup: shl $4, %ecx mov %ecx,sym_phys(trampoline_phys) + /* Get topmost low-memory stack address. */ + add $TRAMPOLINE_SPACE,%ecx + /* Save the Multiboot info struct (after relocation) for later use. */ mov $sym_phys(cpu0_stack)+1024,%esp - push %ecx /* Boot trampoline address. */ + push %ecx /* Topmost low-memory stack address. */ push %ebx /* Multiboot information address. */ push %eax /* Multiboot magic. */ call reloc mov %eax,sym_phys(multiboot_ptr) - /* Initialize BSS (no nasty surprises!) */ + /* + * Now trampoline_phys points to the following structure (lowest + * address is at the top): + * + * +------------------------+ + * | TRAMPOLINE_SPACE | + * +- - - - - - - - - - - - + + * | mbi struct | + * +------------------------+ + * | TRAMPOLINE_STACK_SPACE | + * +------------------------+ + * + * mbi struct lives at the end of TRAMPOLINE_SPACE. The rest of + * TRAMPOLINE_SPACE is reserved for trampoline code and data. + */ + + /* + * Do not zero BSS on EFI platform here. + * It was initialized earlier. + */ + cmpb $0,sym_phys(efi_platform) + jnz 1f + + /* Initialize BSS (no nasty surprises!). */ mov $sym_phys(__bss_start),%edi mov $sym_phys(__bss_end),%ecx sub %edi,%ecx @@ -231,6 +485,7 @@ trampoline_setup: shr $2,%ecx rep stosl +1: /* Interrogate CPU extended features via CPUID. */ mov $0x80000000,%eax cpuid @@ -282,6 +537,10 @@ trampoline_setup: cmp $sym_phys(__trampoline_seg_stop),%edi jb 1b + /* Do not parse command line on EFI platform here. */ + cmpb $0,sym_phys(efi_platform) + jnz 1f + /* Bail if there is no command line to parse. */ mov sym_phys(multiboot_ptr),%ebx testl $MBI_CMDLINE,MB_flags(%ebx) @@ -292,9 +551,9 @@ trampoline_setup: call cmdline_parse_early 1: - /* Switch to low-memory stack. */ + /* Switch to low-memory stack which lives at the end of trampoline region. */ mov sym_phys(trampoline_phys),%edi - lea 0x10000(%edi),%esp + lea TRAMPOLINE_SPACE+TRAMPOLINE_STACK_SPACE(%edi),%esp lea trampoline_boot_cpu_entry-trampoline_start(%edi),%eax pushl $BOOT_CS32 push %eax diff --git a/xen/arch/x86/boot/reloc.c b/xen/arch/x86/boot/reloc.c index 91fab9d..b992678 100644 --- a/xen/arch/x86/boot/reloc.c +++ b/xen/arch/x86/boot/reloc.c @@ -16,7 +16,7 @@ * This entry point is entered from xen/arch/x86/boot/head.S with: * - 0x4(%esp) = MULTIBOOT_MAGIC, * - 0x8(%esp) = MULTIBOOT_INFORMATION_ADDRESS, - * - 0xc(%esp) = BOOT_TRAMPOLINE_ADDRESS. + * - 0xc(%esp) = TOPMOST_LOW_MEMORY_STACK_ADDRESS. */ asm ( " .text \n" diff --git a/xen/arch/x86/efi/efi-boot.h b/xen/arch/x86/efi/efi-boot.h index 62c010e..d193847 100644 --- a/xen/arch/x86/efi/efi-boot.h +++ b/xen/arch/x86/efi/efi-boot.h @@ -101,6 +101,10 @@ static void __init relocate_trampoline(unsigned long phys) const s32 *trampoline_ptr; trampoline_phys = phys; + + if ( !efi_enabled(EFI_LOADER) ) + return; + /* Apply relocations to trampoline. */ for ( trampoline_ptr = __trampoline_rel_start; trampoline_ptr < __trampoline_rel_stop; @@ -550,7 +554,12 @@ static void __init efi_arch_memory_setup(void) /* Allocate space for trampoline (in first Mb). */ cfg.addr = 0x100000; - cfg.size = trampoline_end - trampoline_start; + + if ( efi_enabled(EFI_LOADER) ) + cfg.size = trampoline_end - trampoline_start; + else + cfg.size = TRAMPOLINE_SPACE + TRAMPOLINE_STACK_SPACE; + status = efi_bs->AllocatePages(AllocateMaxAddress, EfiLoaderData, PFN_UP(cfg.size), &cfg.addr); if ( status == EFI_SUCCESS ) @@ -561,6 +570,9 @@ static void __init efi_arch_memory_setup(void) PrintStr(L"Trampoline space cannot be allocated; will try fallback.\r\n"); } + if ( !efi_enabled(EFI_LOADER) ) + return; + /* Initialise L2 identity-map and boot-map page table entries (16MB). */ for ( i = 0; i < 8; ++i ) { @@ -653,6 +665,44 @@ static bool_t __init efi_arch_use_config_file(EFI_SYSTEM_TABLE *SystemTable) static void efi_arch_flush_dcache_area(const void *vaddr, UINTN size) { } +paddr_t __init efi_multiboot2(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) +{ + EFI_GRAPHICS_OUTPUT_PROTOCOL *gop; + UINTN cols, gop_mode = ~0, rows; + + __set_bit(EFI_BOOT, &efi_flags); + __set_bit(EFI_RS, &efi_flags); + + efi_init(ImageHandle, SystemTable); + + efi_console_set_mode(); + + if ( StdOut->QueryMode(StdOut, StdOut->Mode->Mode, + &cols, &rows) == EFI_SUCCESS ) + efi_arch_console_init(cols, rows); + + gop = efi_get_gop(); + + if ( gop ) + gop_mode = efi_find_gop_mode(gop, 0, 0, 0); + + efi_arch_edd(); + efi_arch_cpu(); + + efi_tables(); + setup_efi_pci(); + efi_variables(); + efi_arch_memory_setup(); + + if ( gop ) + efi_set_gop_mode(gop, gop_mode); + + efi_exit_boot(ImageHandle, SystemTable); + + /* Return trampoline address. */ + return trampoline_phys; +} + /* * Local variables: * mode: C diff --git a/xen/arch/x86/efi/stub.c b/xen/arch/x86/efi/stub.c index 4158124..8df9ba2 100644 --- a/xen/arch/x86/efi/stub.c +++ b/xen/arch/x86/efi/stub.c @@ -3,6 +3,45 @@ #include #include #include +#include +#include +#include +#include +#include +#include + +/* + * Here we are in EFI stub. EFI calls are not supported due to lack + * of relevant functionality in compiler and/or linker. + * + * efi_multiboot2() is an exception. Please look below for more details. + */ + +paddr_t __init noreturn efi_multiboot2(EFI_HANDLE ImageHandle, + EFI_SYSTEM_TABLE *SystemTable) +{ + static const CHAR16 __initconst err[] = + L"(XEN) Xen does not have EFI code build in!\r\n(XEN) System halted!\r\n"; + SIMPLE_TEXT_OUTPUT_INTERFACE *StdErr; + + StdErr = SystemTable->StdErr ? SystemTable->StdErr : SystemTable->ConOut; + + /* + * Print error message and halt the system. + * + * We have to open code MS x64 calling convention + * in assembly because here this convention may + * not be directly supported by C compiler. + */ + asm volatile( + " call *%2 \n" + "0: hlt \n" + " jmp 0b \n" + : "+c" (StdErr), "+d" (err) : "rm" (StdErr->OutputString) + : "rax", "r8", "r9", "r10", "r11", "memory"); + + unreachable(); +} bool efi_enabled(unsigned int feature) { diff --git a/xen/arch/x86/x86_64/asm-offsets.c b/xen/arch/x86/x86_64/asm-offsets.c index 92f5d81..f135654 100644 --- a/xen/arch/x86/x86_64/asm-offsets.c +++ b/xen/arch/x86/x86_64/asm-offsets.c @@ -175,6 +175,8 @@ void __dummy__(void) OFFSET(MB2_tag_type, multiboot2_tag_t, type); OFFSET(MB2_tag_size, multiboot2_tag_t, size); OFFSET(MB2_mem_lower, multiboot2_tag_basic_meminfo_t, mem_lower); + OFFSET(MB2_efi64_st, multiboot2_tag_efi64_t, pointer); + OFFSET(MB2_efi64_ih, multiboot2_tag_efi64_ih_t, pointer); BLANK(); OFFSET(DOMAIN_vm_assist, struct domain, vm_assist); diff --git a/xen/arch/x86/xen.lds.S b/xen/arch/x86/xen.lds.S index b0b1c9b..addf2ef 100644 --- a/xen/arch/x86/xen.lds.S +++ b/xen/arch/x86/xen.lds.S @@ -331,5 +331,8 @@ ASSERT(IS_ALIGNED(__init_end, PAGE_SIZE), "__init_end misaligned") ASSERT(IS_ALIGNED(trampoline_start, 4), "trampoline_start misaligned") ASSERT(IS_ALIGNED(trampoline_end, 4), "trampoline_end misaligned") -ASSERT(IS_ALIGNED(__bss_start, 4), "__bss_start misaligned") -ASSERT(IS_ALIGNED(__bss_end, 4), "__bss_end misaligned") +ASSERT(IS_ALIGNED(__bss_start, 8), "__bss_start misaligned") +ASSERT(IS_ALIGNED(__bss_end, 8), "__bss_end misaligned") + +ASSERT((trampoline_end - trampoline_start) < TRAMPOLINE_SPACE, + "not enough room for trampoline") diff --git a/xen/common/efi/boot.c b/xen/common/efi/boot.c index 36dbb71..b6cbdad 100644 --- a/xen/common/efi/boot.c +++ b/xen/common/efi/boot.c @@ -79,6 +79,17 @@ static size_t wstrlen(const CHAR16 * s); static int set_color(u32 mask, int bpp, u8 *pos, u8 *sz); static bool_t match_guid(const EFI_GUID *guid1, const EFI_GUID *guid2); +static void efi_init(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable); +static void efi_console_set_mode(void); +static EFI_GRAPHICS_OUTPUT_PROTOCOL *efi_get_gop(void); +static UINTN efi_find_gop_mode(EFI_GRAPHICS_OUTPUT_PROTOCOL *gop, + UINTN cols, UINTN rows, UINTN depth); +static void efi_tables(void); +static void setup_efi_pci(void); +static void efi_variables(void); +static void efi_set_gop_mode(EFI_GRAPHICS_OUTPUT_PROTOCOL *gop, UINTN gop_mode); +static void efi_exit_boot(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable); + static const EFI_BOOT_SERVICES *__initdata efi_bs; static UINT32 __initdata efi_bs_revision; static EFI_HANDLE __initdata efi_ih; diff --git a/xen/include/asm-x86/config.h b/xen/include/asm-x86/config.h index 6fd84e7..9cd05a2 100644 --- a/xen/include/asm-x86/config.h +++ b/xen/include/asm-x86/config.h @@ -73,6 +73,9 @@ #define STACK_ORDER 3 #define STACK_SIZE (PAGE_SIZE << STACK_ORDER) +#define TRAMPOLINE_STACK_SPACE PAGE_SIZE +#define TRAMPOLINE_SPACE (KB(64) - TRAMPOLINE_STACK_SPACE) + /* Primary stack is restricted to 8kB by guard pages. */ #define PRIMARY_STACK_SIZE 8192 diff --git a/xen/include/xen/config.h b/xen/include/xen/config.h index 473c5e8..04e4da5 100644 --- a/xen/include/xen/config.h +++ b/xen/include/xen/config.h @@ -70,6 +70,7 @@ #define __force #define __bitwise +#define KB(_kb) (_AC(_kb, ULL) << 10) #define MB(_mb) (_AC(_mb, ULL) << 20) #define GB(_gb) (_AC(_gb, ULL) << 30)