[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v2 20/23] x86: add multiboot2 protocol support for EFI platforms
From: |
Daniel Kiper |
Subject: |
[PATCH v2 20/23] x86: add multiboot2 protocol support for EFI platforms |
Date: |
Mon, 20 Jul 2015 16:29:15 +0200 |
Signed-off-by: Daniel Kiper <address@hidden>
---
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 | 157 +++++++++++++++++++++++++++++++++++--
xen/arch/x86/efi/efi-boot.h | 30 +++++++
xen/arch/x86/efi/stub.c | 5 ++
xen/arch/x86/setup.c | 10 ++-
xen/arch/x86/x86_64/asm-offsets.c | 2 +
xen/arch/x86/xen.lds.S | 4 +-
xen/common/efi/boot.c | 12 +++
xen/include/xen/efi.h | 1 +
8 files changed, 210 insertions(+), 11 deletions(-)
diff --git a/xen/arch/x86/boot/head.S b/xen/arch/x86/boot/head.S
index 57197db..056047f 100644
--- a/xen/arch/x86/boot/head.S
+++ b/xen/arch/x86/boot/head.S
@@ -89,6 +89,13 @@ multiboot1_header_end:
0, /* Number of the lines - no preference. */ \
0 /* Number of bits per pixel - no preference. */
+ /* Do not disable EFI boot services. */
+ mb2ht_init MB2_HT(EFI_BS), MB2_HT(OPTIONAL)
+
+ /* EFI64 entry point. */
+ mb2ht_init MB2_HT(ENTRY_ADDRESS_EFI64), MB2_HT(OPTIONAL), \
+ sym_phys(__efi64_start)
+
/* Multiboot2 header end tag. */
mb2ht_init MB2_HT(END), MB2_HT(REQUIRED)
.Lmultiboot2_header_end:
@@ -100,9 +107,15 @@ multiboot1_header_end:
gdt_boot_descr:
.word 6*8-1
.long sym_phys(trampoline_gdt)
+ .long 0 /* Needed for 64-bit lgdt */
+
+cs32_switch_addr:
+ .long sym_phys(cs32_switch)
+ .word BOOT_CS32
.Lbad_cpu_msg: .asciz "ERR: Not a 64-bit CPU!"
.Lbad_ldr_msg: .asciz "ERR: Not a Multiboot bootloader!"
+.Lbad_mb2_ldr: .asciz "ERR: Use latest Multiboot2 compatible bootloader!"
.section .init.text, "ax", @progbits
@@ -111,6 +124,9 @@ bad_cpu:
jmp print_err
not_multiboot:
mov $(sym_phys(.Lbad_ldr_msg)),%esi # Error message
+ jmp print_err
+mb2_too_old:
+ mov $(sym_phys(.Lbad_mb2_ldr)),%esi # Error message
print_err:
mov $0xB8000,%edi # VGA framebuffer
1: mov (%esi),%bl
@@ -130,6 +146,119 @@ print_err:
.Lhalt: hlt
jmp .Lhalt
+ .code64
+
+__efi64_start:
+ cld
+
+ /* Check for Multiboot2 bootloader. */
+ cmp $MULTIBOOT2_BOOTLOADER_MAGIC,%eax
+ je efi_multiboot2_proto
+
+ /* Jump to not_multiboot after switching CPU to x86_32 mode. */
+ lea not_multiboot(%rip),%rdi
+ jmp x86_32_switch
+
+efi_multiboot2_proto:
+ /*
+ * Multiboot2 information address is 32-bit,
+ * so, zero higher half of %rbx.
+ */
+ mov %ebx,%ebx
+
+ /* Skip Multiboot2 information fixed part. */
+ lea MB2_fixed_sizeof(%rbx),%rcx
+
+0:
+ /* Get EFI SystemTable address from Multiboot2 information. */
+ cmpl $MULTIBOOT2_TAG_TYPE_EFI64,MB2_tag_type(%rcx)
+ jne 1f
+
+ mov MB2_efi64_st(%rcx),%rsi
+
+ /* Do not go into real mode on EFI platform. */
+ movb $1,skip_realmode(%rip)
+ jmp 3f
+
+1:
+ /* Get EFI ImageHandle address from Multiboot2 information. */
+ cmpl $MULTIBOOT2_TAG_TYPE_EFI64_IH,MB2_tag_type(%rcx)
+ jne 2f
+
+ mov MB2_efi64_ih(%rcx),%rdi
+ jmp 3f
+
+2:
+ /* Is it the end of Multiboot2 information? */
+ cmpl $MULTIBOOT2_TAG_TYPE_END,MB2_tag_type(%rcx)
+ je run_bs
+
+3:
+ /* Go to next Multiboot2 information tag. */
+ add MB2_tag_size(%rcx),%ecx
+ add $(MULTIBOOT2_TAG_ALIGN-1),%rcx
+ and $~(MULTIBOOT2_TAG_ALIGN-1),%rcx
+ jmp 0b
+
+run_bs:
+ push %rax
+ push %rdi
+
+ /* Initialize BSS (no nasty surprises!). */
+ lea __bss_start(%rip),%rdi
+ lea __bss_end(%rip),%rcx
+ sub %rdi,%rcx
+ shr $3,%rcx
+ xor %eax,%eax
+ rep stosq
+
+ pop %rdi
+
+ /*
+ * IN: %rdi - EFI ImageHandle, %rsi - EFI SystemTable.
+ * OUT: %rax - multiboot2.mem_lower. Do not get this value from
+ * MULTIBOOT2_TAG_TYPE_BASIC_MEMINFO tag. It could be bogus on
+ * EFI platforms.
+ */
+ call efi_multiboot2
+
+ /* Convert multiboot2.mem_lower to bytes/16. */
+ mov %rax,%rcx
+ shr $4,%rcx
+
+ pop %rax
+
+ /* Jump to trampoline_setup after switching CPU to x86_32 mode. */
+ lea trampoline_setup(%rip),%rdi
+
+x86_32_switch:
+ cli
+
+ /* Initialise GDT. */
+ lgdt gdt_boot_descr(%rip)
+
+ /* Reload code selector. */
+ ljmpl *cs32_switch_addr(%rip)
+
+ .code32
+
+cs32_switch:
+ /* Initialise basic data segments. */
+ mov $BOOT_DS,%edx
+ mov %edx,%ds
+ mov %edx,%es
+ mov %edx,%fs
+ mov %edx,%gs
+ mov %edx,%ss
+
+ /* 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 +286,7 @@ __start:
/* Not available? BDA value will be fine. */
cmovnz MB_mem_lower(%ebx),%edx
- jmp trampoline_setup
+ jmp trampoline_bios_setup
multiboot2_proto:
/* Skip Multiboot2 information fixed part. */
@@ -169,12 +298,19 @@ multiboot2_proto:
jne 1f
mov MB2_mem_lower(%ecx),%edx
- jmp trampoline_setup
+ jmp trampoline_bios_setup
1:
+ /* EFI mode is not supported via legacy BIOS path. */
+ cmpl $MULTIBOOT2_TAG_TYPE_EFI32,MB2_tag_type(%ecx)
+ je mb2_too_old
+
+ cmpl $MULTIBOOT2_TAG_TYPE_EFI64,MB2_tag_type(%ecx)
+ je mb2_too_old
+
/* Is it the end of Multiboot2 information? */
cmpl $MULTIBOOT2_TAG_TYPE_END,MB2_tag_type(%ecx)
- je trampoline_setup
+ je trampoline_bios_setup
/* Go to next Multiboot2 information tag. */
add MB2_tag_size(%ecx),%ecx
@@ -182,7 +318,7 @@ multiboot2_proto:
and $~(MULTIBOOT2_TAG_ALIGN-1),%ecx
jmp 0b
-trampoline_setup:
+trampoline_bios_setup:
/* Set up trampoline segment 64k below EBDA */
movzwl 0x40e,%ecx /* EBDA segment */
cmp $0xa000,%ecx /* sanity check (high) */
@@ -198,12 +334,13 @@ 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 */
+trampoline_setup:
+ /* Reserve 64kb for the trampoline. */
sub $0x1000,%ecx
/* From arch/x86/smpboot.c: start_eip had better be page-aligned! */
@@ -220,6 +357,13 @@ trampoline_setup:
add $12,%esp /* Remove reloc() args from stack. */
mov %eax,sym_phys(multiboot_ptr)
+ /*
+ * Do not zero BSS on EFI platform here.
+ * It was initialized earlier.
+ */
+ cmpb $1,sym_phys(skip_realmode)
+ je 1f
+
/* Initialize BSS (no nasty surprises!). */
mov $sym_phys(__bss_start),%edi
mov $sym_phys(__bss_end),%ecx
@@ -228,6 +372,7 @@ trampoline_setup:
xor %eax,%eax
rep stosl
+1:
/* Interrogate CPU extended features via CPUID. */
mov $0x80000000,%eax
cpuid
diff --git a/xen/arch/x86/efi/efi-boot.h b/xen/arch/x86/efi/efi-boot.h
index 3d25c48..1b25a2d 100644
--- a/xen/arch/x86/efi/efi-boot.h
+++ b/xen/arch/x86/efi/efi-boot.h
@@ -228,6 +228,9 @@ static void *__init efi_arch_allocate_mmap_buffer(UINTN
map_size)
static void __init efi_arch_pre_exit_boot(void)
{
+ if ( !efi_enabled(EFI_LOADER) )
+ return;
+
if ( !trampoline_phys )
{
if ( !cfg.addr )
@@ -662,6 +665,33 @@ static bool_t __init
efi_arch_use_config_file(EFI_SYSTEM_TABLE *SystemTable)
return 1; /* x86 always uses a config file */
}
+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_PLATFORM, &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();
+ gop_mode = efi_find_gop_mode(gop, 0, 0, 0);
+ efi_arch_edd();
+ efi_tables();
+ setup_efi_pci();
+ efi_variables();
+ efi_set_gop_mode(gop, gop_mode);
+ efi_exit_boot(ImageHandle, SystemTable);
+
+ return cfg.addr;
+}
+
/*
* Local variables:
* mode: C
diff --git a/xen/arch/x86/efi/stub.c b/xen/arch/x86/efi/stub.c
index c5ae369..d30fe89 100644
--- a/xen/arch/x86/efi/stub.c
+++ b/xen/arch/x86/efi/stub.c
@@ -13,6 +13,11 @@ struct efi __read_mostly efi = {
.smbios3 = EFI_INVALID_TABLE_ADDR
};
+void __init efi_multiboot2(void)
+{
+ /* TODO: Fail if entered! */
+}
+
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 a59fc4e..8bec67f 100644
--- a/xen/arch/x86/setup.c
+++ b/xen/arch/x86/setup.c
@@ -695,7 +695,7 @@ void __init noreturn __start_xen(unsigned long mbi_p)
if ( !(mbi->flags & MBI_MODULES) || (mbi->mods_count == 0) )
panic("dom0 kernel not specified. Check bootloader configuration.");
- if ( efi_enabled(EFI_PLATFORM) )
+ if ( efi_enabled(EFI_LOADER) )
{
set_pdx_range(xen_phys_start >> PAGE_SHIFT,
(xen_phys_start + BOOTSTRAP_MAP_BASE) >> PAGE_SHIFT);
@@ -708,7 +708,11 @@ void __init noreturn __start_xen(unsigned long mbi_p)
l3_bootmap[l3_table_offset(BOOTSTRAP_MAP_BASE)] =
l3e_from_paddr(__pa(l2_bootmap), __PAGE_HYPERVISOR);
- memmap_type = loader;
+ memmap_type = "EFI";
+ }
+ else if ( efi_enabled(EFI_PLATFORM) )
+ {
+ memmap_type = "EFI";
}
else if ( e820_raw_nr != 0 )
{
@@ -806,7 +810,7 @@ void __init noreturn __start_xen(unsigned long mbi_p)
* we can relocate the dom0 kernel and other multiboot modules. Also, on
* x86/64, we relocate Xen to higher memory.
*/
- for ( i = 0; !efi_enabled(EFI_PLATFORM) && i < mbi->mods_count; i++ )
+ for ( i = 0; !efi_enabled(EFI_LOADER) && i < mbi->mods_count; i++ )
{
if ( mod[i].mod_start & (PAGE_SIZE - 1) )
panic("Bootloader didn't honor module alignment request.");
diff --git a/xen/arch/x86/x86_64/asm-offsets.c
b/xen/arch/x86/x86_64/asm-offsets.c
index b926082..b7aed49 100644
--- a/xen/arch/x86/x86_64/asm-offsets.c
+++ b/xen/arch/x86/x86_64/asm-offsets.c
@@ -173,4 +173,6 @@ 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);
}
diff --git a/xen/arch/x86/xen.lds.S b/xen/arch/x86/xen.lds.S
index 87f3e83..a399615 100644
--- a/xen/arch/x86/xen.lds.S
+++ b/xen/arch/x86/xen.lds.S
@@ -162,7 +162,7 @@ SECTIONS
. = ALIGN(STACK_SIZE);
__init_end = .;
- . = ALIGN(4);
+ . = ALIGN(8);
.bss : { /* BSS */
__bss_start = .;
*(.bss.stack_aligned)
@@ -176,7 +176,7 @@ SECTIONS
*(.bss.percpu.read_mostly)
. = ALIGN(SMP_CACHE_BYTES);
__per_cpu_data_end = .;
- . = ALIGN(4);
+ . = ALIGN(8);
__bss_end = .;
} :text
_end = . ;
diff --git a/xen/common/efi/boot.c b/xen/common/efi/boot.c
index bf2f198..5a02e71 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;
@@ -960,6 +971,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE
*SystemTable)
#ifndef CONFIG_ARM /* Disabled until runtime services implemented. */
set_bit(EFI_PLATFORM, &efi.flags);
+ set_bit(EFI_LOADER, &efi.flags);
#endif
efi_init(ImageHandle, SystemTable);
diff --git a/xen/include/xen/efi.h b/xen/include/xen/efi.h
index 318bbec..6b952df 100644
--- a/xen/include/xen/efi.h
+++ b/xen/include/xen/efi.h
@@ -9,6 +9,7 @@
#define EFI_INVALID_TABLE_ADDR (~0UL)
#define EFI_PLATFORM 0
+#define EFI_LOADER 1
/* Add fields here only if they need to be referenced from non-EFI code. */
struct efi {
--
1.7.10.4
- [PATCH v2 05/23] x86/boot/reloc: create generic alloc and copy functions, (continued)
- [PATCH v2 05/23] x86/boot/reloc: create generic alloc and copy functions, Daniel Kiper, 2015/07/20
- [PATCH v2 08/23] x86: add multiboot2 protocol support, Daniel Kiper, 2015/07/20
- [PATCH v2 11/23] efi: split out efi_init(), Daniel Kiper, 2015/07/20
- [PATCH v2 12/23] efi: split out efi_console_set_mode(), Daniel Kiper, 2015/07/20
- [PATCH v2 02/23] x86/boot: copy only text section from *.lnk file to *.bin file, Daniel Kiper, 2015/07/20
- [PATCH v2 13/23] efi: split out efi_get_gop(), Daniel Kiper, 2015/07/20
- [PATCH v2 16/23] efi: split out efi_variables(), Daniel Kiper, 2015/07/20
- [PATCH v2 19/23] x86/efi: create new early memory allocator, Daniel Kiper, 2015/07/20
- [PATCH v2 18/23] efi: split out efi_exit_boot(), Daniel Kiper, 2015/07/20
- [PATCH v2 21/23] x86/boot: implement early command line parser in C, Daniel Kiper, 2015/07/20
- [PATCH v2 20/23] x86: add multiboot2 protocol support for EFI platforms,
Daniel Kiper <=
- [PATCH v2 09/23] efi: create efi_enabled(), Daniel Kiper, 2015/07/20
- [PATCH v2 14/23] efi: split out efi_find_gop_mode(), Daniel Kiper, 2015/07/20
- [PATCH v2 10/23] efi: build xen.gz with EFI code, Daniel Kiper, 2015/07/20
- [PATCH v2 22/23] x86: make Xen early boot code relocatable, Daniel Kiper, 2015/07/20
- [PATCH v2 17/23] efi: split out efi_set_gop_mode(), Daniel Kiper, 2015/07/20
- [PATCH v2 15/23] efi: split out efi_tables(), Daniel Kiper, 2015/07/20
- [PATCH v2 23/23] x86: add multiboot2 protocol support for relocatable images, Daniel Kiper, 2015/07/20
- Re: [PATCH v2 00/23] x86: multiboot2 protocol support, Jan Beulich, 2015/07/21