* [PATCH] x86, boot: Allow 64bit EFI kernel to be loaded above 4G @ 2015-02-04 2:03 Yinghai Lu 2015-02-05 3:25 ` Dave Young 2015-02-09 18:27 ` Matt Fleming 0 siblings, 2 replies; 10+ messages in thread From: Yinghai Lu @ 2015-02-04 2:03 UTC (permalink / raw) To: Thomas Gleixner, H. Peter Anvin, Ingo Molnar, Jonathan Corbet, Matt Fleming Cc: Kees Cook, Junjie Mao, linux-doc, linux-efi, linux-kernel, Yinghai Lu Now could use kexec to place kernel/boot_params/cmd_line/initrd above 4G, but that is with legacy interface with startup_64 directly. This patch will allow 64bit EFI kernel to be loaded above 4G and use EFI HANDOVER PROTOCOL to start the kernel. Current code32_start is used for passing around loading address, so it will overflow when kernel is loaded abover 4G. The patch mainly add ext_code32_start to take address high 32bit. After this patch, could use patched grub2-x86_64.efi to place kernel/boot_params/cmd_line/initrd all above 4G and execute the kernel above 4G. bootlog like: params: [1618fc000,1618fffff] cmdline: [1618fb000,1618fb7fe] kernel: [15e000000,161385fff] kernel: done [ linux 9.25MiB 100% 6.66MiB/s ] initrd: [15bcbe000,15dffffbb] initrd: 1 file done [ initrd.img 35.26MiB 100% 11.93MiB/s ] early console in decompress_kernel decompress_kernel: input: [0x15fd0b3b4-0x16063c803], output: 0x15e000000, heap: [0x160645b00-0x16064daff] Decompressing Linux... xz... Parsing ELF... done. Booting the kernel. [ 0.000000] bootconsole [uart0] enabled [ 0.000000] real_mode_data : phys 00000001618fc000 [ 0.000000] real_mode_data : virt ffff8801618fc000 [ 0.000000] Kernel Layout: [ 0.000000] .text: [0x15e000000-0x15f08f72c] [ 0.000000] .rodata: [0x15f200000-0x15fa44fff] [ 0.000000] .data: [0x15fc00000-0x15fe545ff] [ 0.000000] .init: [0x15fe56000-0x16021afff] [ 0.000000] .bss: [0x160229000-0x16135ffff] [ 0.000000] .brk: [0x161360000-0x161385fff] [ 0.000000] memblock_reserve: [0x0000000009f000-0x000000000fffff] flags 0x0 * BIOS reserved ... [ 0.000000] memblock_reserve: [0x0000015e000000-0x0000016135ffff] flags 0x0 TEXT DATA BSS [ 0.000000] memblock_reserve: [0x0000015bcbe000-0x0000015dffffff] flags 0x0 RAMDISK Signed-off-by: Yinghai Lu <yinghai@kernel.org> --- Documentation/x86/boot.txt | 18 ++++++++++++++++++ arch/x86/boot/compressed/eboot.c | 15 ++++++++++----- arch/x86/boot/compressed/head_64.S | 7 ++++++- arch/x86/boot/header.S | 3 ++- arch/x86/include/uapi/asm/bootparam.h | 1 + arch/x86/kernel/asm-offsets.c | 1 + 6 files changed, 38 insertions(+), 7 deletions(-) Index: linux-2.6/arch/x86/include/uapi/asm/bootparam.h =================================================================== --- linux-2.6.orig/arch/x86/include/uapi/asm/bootparam.h +++ linux-2.6/arch/x86/include/uapi/asm/bootparam.h @@ -83,6 +83,7 @@ struct setup_header { __u64 pref_address; __u32 init_size; __u32 handover_offset; + __u32 ext_code32_start; } __attribute__((packed)); struct sys_desc_table { Index: linux-2.6/arch/x86/kernel/asm-offsets.c =================================================================== --- linux-2.6.orig/arch/x86/kernel/asm-offsets.c +++ linux-2.6/arch/x86/kernel/asm-offsets.c @@ -68,6 +68,7 @@ void common(void) { OFFSET(BP_kernel_alignment, boot_params, hdr.kernel_alignment); OFFSET(BP_pref_address, boot_params, hdr.pref_address); OFFSET(BP_code32_start, boot_params, hdr.code32_start); + OFFSET(BP_ext_code32_start, boot_params, hdr.ext_code32_start); BLANK(); DEFINE(PTREGS_SIZE, sizeof(struct pt_regs)); Index: linux-2.6/arch/x86/boot/compressed/head_64.S =================================================================== --- linux-2.6.orig/arch/x86/boot/compressed/head_64.S +++ linux-2.6/arch/x86/boot/compressed/head_64.S @@ -263,6 +263,8 @@ ENTRY(efi_pe_entry) mov %rax, %rsi leaq startup_32(%rip), %rax movl %eax, BP_code32_start(%rsi) + shr $32, %rax + movl %eax, BP_ext_code32_start(%rsi) jmp 2f /* Skip the relocation */ handover_entry: @@ -286,7 +288,10 @@ fail: hlt jmp fail 2: - movl BP_code32_start(%esi), %eax + movl BP_code32_start(%rsi), %eax + movl BP_ext_code32_start(%rsi), %ebx + shl $32, %rbx + orq %rbx, %rax leaq preferred_addr(%rax), %rax jmp *%rax Index: linux-2.6/arch/x86/boot/compressed/eboot.c =================================================================== --- linux-2.6.orig/arch/x86/boot/compressed/eboot.c +++ linux-2.6/arch/x86/boot/compressed/eboot.c @@ -1389,6 +1389,7 @@ struct boot_params *efi_main(struct efi_ void *handle; efi_system_table_t *_table; bool is64; + unsigned long loaded_addr; efi_early = c; @@ -1430,9 +1431,12 @@ struct boot_params *efi_main(struct efi_ * If the kernel isn't already loaded at the preferred load * address, relocate it. */ - if (hdr->pref_address != hdr->code32_start) { - unsigned long bzimage_addr = hdr->code32_start; - status = efi_relocate_kernel(sys_table, &bzimage_addr, + loaded_addr = hdr->code32_start; + loaded_addr |= (unsigned long)hdr->ext_code32_start << 32; + if (hdr->pref_address != loaded_addr) { + unsigned long loaded_addr_orig = loaded_addr; + + status = efi_relocate_kernel(sys_table, &loaded_addr, hdr->init_size, hdr->init_size, hdr->pref_address, hdr->kernel_alignment); @@ -1441,8 +1445,9 @@ struct boot_params *efi_main(struct efi_ goto fail; } - hdr->pref_address = hdr->code32_start; - hdr->code32_start = bzimage_addr; + hdr->pref_address = loaded_addr_orig; + hdr->code32_start = loaded_addr & 0xffffffff; + hdr->ext_code32_start = loaded_addr >> 32; } status = exit_boot(boot_params, handle, is64); Index: linux-2.6/arch/x86/boot/header.S =================================================================== --- linux-2.6.orig/arch/x86/boot/header.S +++ linux-2.6/arch/x86/boot/header.S @@ -301,7 +301,7 @@ _start: # Part 2 of the header, from the old setup.S .ascii "HdrS" # header signature - .word 0x020d # header version number (>= 0x0105) + .word 0x020e # header version number (>= 0x0105) # or else old loadlin-1.5 will fail) .globl realmode_swtch realmode_swtch: .word 0, 0 # default_switch, SETUPSEG @@ -449,6 +449,7 @@ pref_address: .quad LOAD_PHYSICAL_ADDR #endif init_size: .long INIT_SIZE # kernel initialization size handover_offset: .long 0 # Filled in by build.c +ext_code32_start: .long 0 # werid one! # End of setup header ##################################################### Index: linux-2.6/Documentation/x86/boot.txt =================================================================== --- linux-2.6.orig/Documentation/x86/boot.txt +++ linux-2.6/Documentation/x86/boot.txt @@ -61,6 +61,9 @@ Protocol 2.12: (Kernel 3.8) Added the xl to struct boot_params for loading bzImage and ramdisk above 4G in 64bit. +Protocol 2.14: (Kernel 3.20) Added the ext_code32_start to support EFI64 + to be loaded above 4G. + **** MEMORY LAYOUT The traditional memory map for the kernel loader, used for Image or @@ -197,6 +200,7 @@ Offset Proto Name Meaning 0258/8 2.10+ pref_address Preferred loading address 0260/4 2.10+ init_size Linear memory required during initialization 0264/4 2.11+ handover_offset Offset of handover entry point +0268/4 2.14+ ext_code32_start Extended part for code32_start (1) For backwards compatibility, if the setup_sects field contains 0, the real value is 4. @@ -738,6 +742,13 @@ Offset/size: 0x264/4 See EFI HANDOVER PROTOCOL below for more details. +Field name: ext_code32_start +Type: modify (optional, reloc) +Offset/size: 0x268/4 +Protocol: 2.14+ + + The address is used with code32_start to compare pref_address + to support EFI 64bit kernel get loaded above 4G. **** THE IMAGE CHECKSUM @@ -1122,4 +1133,11 @@ The boot loader *must* fill out the foll o hdr.ramdisk_image (if applicable) o hdr.ramdisk_size (if applicable) +for 64bit, when loading above 4G, *must* fill out the following fields, + + o hdr.ext_code32_start + o ext_cmd_line_ptr + o ext_ramdisk_image (if applicable) + o ext_ramdisk_size (if applicable) + All other fields should be zero. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] x86, boot: Allow 64bit EFI kernel to be loaded above 4G 2015-02-04 2:03 [PATCH] x86, boot: Allow 64bit EFI kernel to be loaded above 4G Yinghai Lu @ 2015-02-05 3:25 ` Dave Young 2015-02-05 5:25 ` Yinghai Lu 2015-02-09 18:27 ` Matt Fleming 1 sibling, 1 reply; 10+ messages in thread From: Dave Young @ 2015-02-05 3:25 UTC (permalink / raw) To: Yinghai Lu Cc: Thomas Gleixner, H. Peter Anvin, Ingo Molnar, Jonathan Corbet, Matt Fleming, Kees Cook, Junjie Mao, linux-doc, linux-efi, linux-kernel Hi, Thanks, it will be useful for possible efi rebooting to kdump reserved memory. On 02/03/15 at 06:03pm, Yinghai Lu wrote: > Now could use kexec to place kernel/boot_params/cmd_line/initrd > above 4G, but that is with legacy interface with startup_64 directly. > > This patch will allow 64bit EFI kernel to be loaded above 4G > and use EFI HANDOVER PROTOCOL to start the kernel. > > Current code32_start is used for passing around loading address, > so it will overflow when kernel is loaded abover 4G. > > The patch mainly add ext_code32_start to take address high 32bit. > > After this patch, could use patched grub2-x86_64.efi to place > kernel/boot_params/cmd_line/initrd all above 4G and execute the kernel > above 4G. Can you share the grub2 patch for testing? > > bootlog like: > > params: [1618fc000,1618fffff] > cmdline: [1618fb000,1618fb7fe] > kernel: [15e000000,161385fff] > kernel: done [ linux 9.25MiB 100% 6.66MiB/s ] > initrd: [15bcbe000,15dffffbb] > initrd: 1 file done [ initrd.img 35.26MiB 100% 11.93MiB/s ] > early console in decompress_kernel > decompress_kernel: > input: [0x15fd0b3b4-0x16063c803], output: 0x15e000000, heap: [0x160645b00-0x16064daff] > > Decompressing Linux... xz... Parsing ELF... done. > Booting the kernel. > [ 0.000000] bootconsole [uart0] enabled > [ 0.000000] real_mode_data : phys 00000001618fc000 > [ 0.000000] real_mode_data : virt ffff8801618fc000 > [ 0.000000] Kernel Layout: > [ 0.000000] .text: [0x15e000000-0x15f08f72c] > [ 0.000000] .rodata: [0x15f200000-0x15fa44fff] > [ 0.000000] .data: [0x15fc00000-0x15fe545ff] > [ 0.000000] .init: [0x15fe56000-0x16021afff] > [ 0.000000] .bss: [0x160229000-0x16135ffff] > [ 0.000000] .brk: [0x161360000-0x161385fff] > [ 0.000000] memblock_reserve: [0x0000000009f000-0x000000000fffff] flags 0x0 * BIOS reserved > ... > [ 0.000000] memblock_reserve: [0x0000015e000000-0x0000016135ffff] flags 0x0 TEXT DATA BSS > [ 0.000000] memblock_reserve: [0x0000015bcbe000-0x0000015dffffff] flags 0x0 RAMDISK > > > Signed-off-by: Yinghai Lu <yinghai@kernel.org> > > --- > Documentation/x86/boot.txt | 18 ++++++++++++++++++ > arch/x86/boot/compressed/eboot.c | 15 ++++++++++----- > arch/x86/boot/compressed/head_64.S | 7 ++++++- > arch/x86/boot/header.S | 3 ++- > arch/x86/include/uapi/asm/bootparam.h | 1 + > arch/x86/kernel/asm-offsets.c | 1 + > 6 files changed, 38 insertions(+), 7 deletions(-) > > Index: linux-2.6/arch/x86/include/uapi/asm/bootparam.h > =================================================================== > --- linux-2.6.orig/arch/x86/include/uapi/asm/bootparam.h > +++ linux-2.6/arch/x86/include/uapi/asm/bootparam.h > @@ -83,6 +83,7 @@ struct setup_header { > __u64 pref_address; > __u32 init_size; > __u32 handover_offset; > + __u32 ext_code32_start; > } __attribute__((packed)); > > struct sys_desc_table { > Index: linux-2.6/arch/x86/kernel/asm-offsets.c > =================================================================== > --- linux-2.6.orig/arch/x86/kernel/asm-offsets.c > +++ linux-2.6/arch/x86/kernel/asm-offsets.c > @@ -68,6 +68,7 @@ void common(void) { > OFFSET(BP_kernel_alignment, boot_params, hdr.kernel_alignment); > OFFSET(BP_pref_address, boot_params, hdr.pref_address); > OFFSET(BP_code32_start, boot_params, hdr.code32_start); > + OFFSET(BP_ext_code32_start, boot_params, hdr.ext_code32_start); > > BLANK(); > DEFINE(PTREGS_SIZE, sizeof(struct pt_regs)); > Index: linux-2.6/arch/x86/boot/compressed/head_64.S > =================================================================== > --- linux-2.6.orig/arch/x86/boot/compressed/head_64.S > +++ linux-2.6/arch/x86/boot/compressed/head_64.S > @@ -263,6 +263,8 @@ ENTRY(efi_pe_entry) > mov %rax, %rsi > leaq startup_32(%rip), %rax > movl %eax, BP_code32_start(%rsi) > + shr $32, %rax > + movl %eax, BP_ext_code32_start(%rsi) > jmp 2f /* Skip the relocation */ > > handover_entry: > @@ -286,7 +288,10 @@ fail: > hlt > jmp fail > 2: > - movl BP_code32_start(%esi), %eax > + movl BP_code32_start(%rsi), %eax > + movl BP_ext_code32_start(%rsi), %ebx > + shl $32, %rbx > + orq %rbx, %rax > leaq preferred_addr(%rax), %rax > jmp *%rax > > Index: linux-2.6/arch/x86/boot/compressed/eboot.c > =================================================================== > --- linux-2.6.orig/arch/x86/boot/compressed/eboot.c > +++ linux-2.6/arch/x86/boot/compressed/eboot.c > @@ -1389,6 +1389,7 @@ struct boot_params *efi_main(struct efi_ > void *handle; > efi_system_table_t *_table; > bool is64; > + unsigned long loaded_addr; > > efi_early = c; > > @@ -1430,9 +1431,12 @@ struct boot_params *efi_main(struct efi_ > * If the kernel isn't already loaded at the preferred load > * address, relocate it. > */ > - if (hdr->pref_address != hdr->code32_start) { > - unsigned long bzimage_addr = hdr->code32_start; > - status = efi_relocate_kernel(sys_table, &bzimage_addr, > + loaded_addr = hdr->code32_start; > + loaded_addr |= (unsigned long)hdr->ext_code32_start << 32; > + if (hdr->pref_address != loaded_addr) { > + unsigned long loaded_addr_orig = loaded_addr; > + > + status = efi_relocate_kernel(sys_table, &loaded_addr, > hdr->init_size, hdr->init_size, > hdr->pref_address, > hdr->kernel_alignment); > @@ -1441,8 +1445,9 @@ struct boot_params *efi_main(struct efi_ > goto fail; > } > > - hdr->pref_address = hdr->code32_start; > - hdr->code32_start = bzimage_addr; > + hdr->pref_address = loaded_addr_orig; > + hdr->code32_start = loaded_addr & 0xffffffff; > + hdr->ext_code32_start = loaded_addr >> 32; > } > > status = exit_boot(boot_params, handle, is64); > Index: linux-2.6/arch/x86/boot/header.S > =================================================================== > --- linux-2.6.orig/arch/x86/boot/header.S > +++ linux-2.6/arch/x86/boot/header.S > @@ -301,7 +301,7 @@ _start: > # Part 2 of the header, from the old setup.S > > .ascii "HdrS" # header signature > - .word 0x020d # header version number (>= 0x0105) > + .word 0x020e # header version number (>= 0x0105) > # or else old loadlin-1.5 will fail) > .globl realmode_swtch > realmode_swtch: .word 0, 0 # default_switch, SETUPSEG > @@ -449,6 +449,7 @@ pref_address: .quad LOAD_PHYSICAL_ADDR > #endif > init_size: .long INIT_SIZE # kernel initialization size > handover_offset: .long 0 # Filled in by build.c > +ext_code32_start: .long 0 # werid one! > > # End of setup header ##################################################### > > Index: linux-2.6/Documentation/x86/boot.txt > =================================================================== > --- linux-2.6.orig/Documentation/x86/boot.txt > +++ linux-2.6/Documentation/x86/boot.txt > @@ -61,6 +61,9 @@ Protocol 2.12: (Kernel 3.8) Added the xl > to struct boot_params for loading bzImage and ramdisk > above 4G in 64bit. > > +Protocol 2.14: (Kernel 3.20) Added the ext_code32_start to support EFI64 > + to be loaded above 4G. > + > **** MEMORY LAYOUT > > The traditional memory map for the kernel loader, used for Image or > @@ -197,6 +200,7 @@ Offset Proto Name Meaning > 0258/8 2.10+ pref_address Preferred loading address > 0260/4 2.10+ init_size Linear memory required during initialization > 0264/4 2.11+ handover_offset Offset of handover entry point > +0268/4 2.14+ ext_code32_start Extended part for code32_start > > (1) For backwards compatibility, if the setup_sects field contains 0, the > real value is 4. > @@ -738,6 +742,13 @@ Offset/size: 0x264/4 > > See EFI HANDOVER PROTOCOL below for more details. > > +Field name: ext_code32_start > +Type: modify (optional, reloc) > +Offset/size: 0x268/4 > +Protocol: 2.14+ > + > + The address is used with code32_start to compare pref_address > + to support EFI 64bit kernel get loaded above 4G. > > **** THE IMAGE CHECKSUM > > @@ -1122,4 +1133,11 @@ The boot loader *must* fill out the foll > o hdr.ramdisk_image (if applicable) > o hdr.ramdisk_size (if applicable) > > +for 64bit, when loading above 4G, *must* fill out the following fields, > + > + o hdr.ext_code32_start > + o ext_cmd_line_ptr > + o ext_ramdisk_image (if applicable) > + o ext_ramdisk_size (if applicable) > + > All other fields should be zero. > -- > To unsubscribe from this list: send the line "unsubscribe linux-efi" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] x86, boot: Allow 64bit EFI kernel to be loaded above 4G 2015-02-05 3:25 ` Dave Young @ 2015-02-05 5:25 ` Yinghai Lu 2015-02-05 6:09 ` Dave Young 0 siblings, 1 reply; 10+ messages in thread From: Yinghai Lu @ 2015-02-05 5:25 UTC (permalink / raw) To: Dave Young Cc: Thomas Gleixner, H. Peter Anvin, Ingo Molnar, Jonathan Corbet, Matt Fleming, Kees Cook, Junjie Mao, linux-doc, linux-efi, Linux Kernel Mailing List [-- Attachment #1: Type: text/plain, Size: 499 bytes --] On Wed, Feb 4, 2015 at 7:25 PM, Dave Young <dyoung@redhat.com> wrote: >> After this patch, could use patched grub2-x86_64.efi to place >> kernel/boot_params/cmd_line/initrd all above 4G and execute the kernel >> above 4G. > > Can you share the grub2 patch for testing? Please check attached 5 patches. last one is for debug purpose. You need to apply them on top of git://git.savannah.gnu.org/grub.git plus http://pkgs.fedoraproject.org/cgit/grub2.git/plain/0091-Add-support-for-linuxefi.patch [-- Attachment #2: ramdisk_above_4g_7_1.patch --] [-- Type: text/x-patch, Size: 1877 bytes --] Subject: [PATCH] update setup_header and boot_params to 2.12 the one that is used by kernel v3.8... --- include/grub/i386/linux.h | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) Index: grub/include/grub/i386/linux.h =================================================================== --- grub.orig/include/grub/i386/linux.h +++ grub/include/grub/i386/linux.h @@ -130,7 +130,7 @@ struct linux_kernel_header grub_uint32_t kernel_alignment; grub_uint8_t relocatable; grub_uint8_t min_alignment; - grub_uint8_t pad[2]; + grub_uint16_t xloadflags; grub_uint32_t cmdline_size; grub_uint32_t hardware_subarch; grub_uint64_t hardware_subarch_data; @@ -221,7 +221,11 @@ struct linux_kernel_params grub_uint32_t ofw_cif_handler; /* b8 */ grub_uint32_t ofw_idt; /* bc */ - grub_uint8_t padding7[0x1b8 - 0xc0]; + grub_uint32_t ext_ramdisk_image; /* c0 */ + grub_uint32_t ext_ramdisk_size; /* c4 */ + grub_uint32_t ext_cmd_line_ptr; /* c8 */ + + grub_uint8_t padding7[0x1b8 - 0xcc]; union { @@ -300,14 +304,18 @@ struct linux_kernel_params grub_uint32_t initrd_addr_max; /* Maximum initrd address */ grub_uint32_t kernel_alignment; /* Alignment of the kernel */ grub_uint8_t relocatable_kernel; /* Is the kernel relocatable */ - grub_uint8_t pad1[3]; + grub_uint8_t min_alignment; + grub_uint16_t xloadflags; grub_uint32_t cmdline_size; /* Size of the kernel command line */ grub_uint32_t hardware_subarch; grub_uint64_t hardware_subarch_data; grub_uint32_t payload_offset; grub_uint32_t payload_length; grub_uint64_t setup_data; - grub_uint8_t pad2[120]; /* 258 */ + grub_uint64_t pref_address; + grub_uint32_t init_size; + grub_uint32_t handover_offset; + grub_uint8_t pad2[104]; /* 248 */ struct grub_e820_mmap e820_map[(0x400 - 0x2d0) / 20]; /* 2d0 */ } GRUB_PACKED; [-- Attachment #3: ramdisk_above_4g_7_2.patch --] [-- Type: text/x-patch, Size: 5110 bytes --] Subject: [PATCH] x86, efi: add allocate_pages_high The allocate_pages_max one does not return above 4G. translate the version in linux kernel. --- grub-core/kern/efi/mm.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++++ include/grub/efi/efi.h | 3 + 2 files changed, 147 insertions(+) Index: grub/grub-core/kern/efi/mm.c =================================================================== --- grub.orig/grub-core/kern/efi/mm.c +++ grub/grub-core/kern/efi/mm.c @@ -557,3 +557,147 @@ grub_efi_mm_init (void) grub_efi_free_pages ((grub_addr_t) memory_map, 2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE)); } + +#define EFI_PAGE_SIZE 0x1000 +static grub_efi_status_t grub2_efi_get_memory_map(grub_efi_uintn_t *map_size, + grub_efi_memory_descriptor_t **map, + grub_efi_uintn_t *key_ptr, + grub_efi_uintn_t *desc_size, + grub_efi_uint32_t *desc_ver) +{ + grub_efi_memory_descriptor_t *m = NULL; + grub_efi_status_t status; + grub_efi_uintn_t key; + grub_efi_uint32_t desc_version; + grub_efi_boot_services_t *b; + + b = grub_efi_system_table->boot_services; + + *map_size = 0; + *desc_size = 0; + key = 0; + status = efi_call_5 (b->get_memory_map, map_size, NULL, &key, + desc_size, &desc_version); + + if (status != GRUB_EFI_BUFFER_TOO_SMALL) + return GRUB_EFI_LOAD_ERROR; + + /* + * Add an additional efi_memory_desc_t because we're doing an + * allocation which may be in a new descriptor region. + */ + *map_size += *desc_size; + status = efi_call_3 (b->allocate_pool, GRUB_EFI_LOADER_DATA, + *map_size, (void **)&m); + if (status != GRUB_EFI_SUCCESS) + goto fail; + + status = efi_call_5 (b->get_memory_map, map_size, m, &key, + desc_size, &desc_version); + if (status == GRUB_EFI_BUFFER_TOO_SMALL) + { + efi_call_1 (b->free_pool, m); + return GRUB_EFI_LOAD_ERROR; + } + + if (status != GRUB_EFI_SUCCESS) + efi_call_1 (b->free_pool, m); + + if (key_ptr && status == GRUB_EFI_SUCCESS) + *key_ptr = key; + if (desc_ver && status == GRUB_EFI_SUCCESS) + *desc_ver = desc_version; + +fail: + *map = m; + return status; +} + +/* + * Allocate at the highest possible address that is not above 'max'. + */ +void *grub2_efi_allocate_pages_high(grub_efi_physical_address_t max, + grub_efi_uint64_t pages, grub_efi_uint64_t align) +{ + grub_efi_boot_services_t *b; + grub_efi_uintn_t map_size, desc_size; + grub_efi_memory_descriptor_t *map= NULL; + grub_efi_status_t status; + grub_uint64_t max_addr = 0; + grub_uint64_t addr = 0; + grub_efi_uintn_t i; + grub_uint64_t size = PAGES_TO_BYTES(pages); + + /* Obtain descriptors for available memory. */ + status = grub2_efi_get_memory_map (&map_size, &map, 0, &desc_size, 0); + if (status != GRUB_EFI_SUCCESS) + goto fail; + + if (align < EFI_PAGE_SIZE) + align = EFI_PAGE_SIZE; + + b = grub_efi_system_table->boot_services; + +again: + for (i = 0; i < map_size / desc_size; i++) + { + grub_efi_memory_descriptor_t *desc; + unsigned long m = (unsigned long)map; + grub_uint64_t start, end; + + desc = (grub_efi_memory_descriptor_t *)(m + (i * desc_size)); + if (desc->type != GRUB_EFI_CONVENTIONAL_MEMORY) + continue; + + if (desc->num_pages < pages) + continue; + + start = desc->physical_start; + end = start + PAGES_TO_BYTES(desc->num_pages); + + if ((start + size) > end || (start + size) > max) + continue; + + if (end - size > max) + end = max; + + if ((((end - size)/align)*align) < start) + continue; + + start = (((end - size)/align)*align); + + /* + * Don't allocate at 0x0. It will confuse code that + * checks pointers against NULL. + */ + if (start == 0x0) + continue; + + if (start > max_addr) + max_addr = start; + } + + if (!max_addr) + addr = 0; + else + { + status = efi_call_4 (b->allocate_pages, + GRUB_EFI_ALLOCATE_ADDRESS, GRUB_EFI_LOADER_DATA, + pages, &max_addr); + if (status != GRUB_EFI_SUCCESS) + { + max = max_addr; + max_addr = 0; + goto again; + } + + addr = max_addr; + } + + /* Release the memory maps. */ + efi_call_1 (b->free_pool, map); + +fail: + return (void *)((grub_addr_t) addr); +} + Index: grub/include/grub/efi/efi.h =================================================================== --- grub.orig/include/grub/efi/efi.h +++ grub/include/grub/efi/efi.h @@ -43,6 +43,9 @@ EXPORT_FUNC(grub_efi_allocate_pages) (gr void * EXPORT_FUNC(grub_efi_allocate_pages_max) (grub_efi_physical_address_t max, grub_efi_uintn_t pages); +void * +EXPORT_FUNC(grub2_efi_allocate_pages_high) (grub_efi_physical_address_t max, + grub_efi_uint64_t pages, grub_efi_uint64_t align); void EXPORT_FUNC(grub_efi_free_pages) (grub_efi_physical_address_t address, grub_efi_uintn_t pages); int [-- Attachment #4: ramdisk_above_4g_7_3.patch --] [-- Type: text/x-patch, Size: 1851 bytes --] Subject: [PATCH] x86, efi: make initrd load high if it is supported for kernel after v3.9 and later. --- grub-core/loader/i386/efi/linux.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) Index: grub/grub-core/loader/i386/efi/linux.c =================================================================== --- grub.orig/grub-core/loader/i386/efi/linux.c +++ grub/grub-core/loader/i386/efi/linux.c @@ -108,6 +108,8 @@ static grub_err_t grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]) { + grub_uint64_t addr_max = 0x3fffffff; + int load_high = 0; grub_file_t *files = 0; int i, nfiles = 0; grub_size_t size = 0; @@ -139,7 +141,14 @@ grub_cmd_initrd (grub_command_t cmd __at size += ALIGN_UP (grub_file_size (files[i]), 4); } - initrd_mem = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(size)); + if (params->version > grub_cpu_to_le16 (0x020b) && + params->xloadflags & (1<<1)) /* XLF_CAN_BE_LOADED_ABOVE_4G */ + { + addr_max = -1UL; + load_high = 1; + } + + initrd_mem = grub2_efi_allocate_pages_high (addr_max, BYTES_TO_PAGES(size), 4096); if (!initrd_mem) { @@ -147,8 +156,13 @@ grub_cmd_initrd (grub_command_t cmd __at goto fail; } - params->ramdisk_size = size; + params->ramdisk_size = (grub_uint32_t) size; params->ramdisk_image = (grub_uint32_t)(grub_uint64_t) initrd_mem; + if ( load_high ) + { + params->ext_ramdisk_image = (grub_uint64_t) initrd_mem >> 32; + params->ext_ramdisk_size = size >> 32; + } ptr = initrd_mem; @@ -167,8 +181,6 @@ grub_cmd_initrd (grub_command_t cmd __at ptr += ALIGN_UP_OVERHEAD (cursize, 4); } - params->ramdisk_size = size; - fail: for (i = 0; i < nfiles; i++) grub_file_close (files[i]); [-- Attachment #5: ramdisk_above_4g_7_4.patch --] [-- Type: text/x-patch, Size: 8521 bytes --] Subject: [PATCH] x86, efi: make kernel/boot_params/cmdline could be above 4G if supported for kernel that support ext_code32_start. Also reduce kernel reading to one time only. --- grub-core/loader/i386/efi/linux.c | 146 +++++++++++++++++++++++--------------- include/grub/i386/linux.h | 4 - 2 files changed, 93 insertions(+), 57 deletions(-) Index: grub/grub-core/loader/i386/efi/linux.c =================================================================== --- grub.orig/grub-core/loader/i386/efi/linux.c +++ grub/grub-core/loader/i386/efi/linux.c @@ -192,14 +192,27 @@ grub_cmd_initrd (grub_command_t cmd __at return grub_errno; } +static void copy_setup_header(unsigned char *param, unsigned char *h) +{ + unsigned long setup_header_size = h[0x201] + 0x202 - 0x1f1; + + /* only copy setup_header */ + if (setup_header_size > 0x7f) + setup_header_size = 0x7f; + memcpy(param + 0x1f1, h + 0x1f1, setup_header_size); +} + static grub_err_t grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]) { + grub_uint64_t addr_max = 0x3fffffff; + int load_high = 0; grub_file_t file = 0; struct linux_kernel_header lh; - grub_ssize_t len, start, filelen; - void *kernel; + grub_ssize_t start, filelen; + void *kernel = NULL; + int kernel_high = 0; grub_dl_ref (my_mod); @@ -213,77 +226,96 @@ grub_cmd_linux (grub_command_t cmd __att if (! file) goto fail; - filelen = grub_file_size (file); + if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh)) + { + if (!grub_errno) + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), + argv[0]); + goto fail; + } - kernel = grub_malloc(filelen); + if (lh.boot_flag != grub_cpu_to_le16 (0xaa55)) + { + grub_error (GRUB_ERR_BAD_OS, N_("invalid magic number")); + goto fail; + } - if (!kernel) + if (lh.setup_sects > GRUB_LINUX_MAX_SETUP_SECTS) { - grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer")); + grub_error (GRUB_ERR_BAD_OS, N_("too many setup sectors")); goto fail; } - if (grub_file_read (file, kernel, filelen) != filelen) + if (lh.version < grub_cpu_to_le16 (0x020b)) { - grub_error (GRUB_ERR_FILE_READ_ERROR, N_("Can't read kernel %s"), argv[0]); + grub_error (GRUB_ERR_BAD_OS, N_("kernel too old")); goto fail; } - if (! grub_linuxefi_secure_validate (kernel, filelen)) + if (!lh.handover_offset) { - grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), argv[0]); - grub_free (kernel); + grub_error (GRUB_ERR_BAD_OS, N_("kernel doesn't support EFI handover")); goto fail; } - grub_file_seek (file, 0); + if (lh.version > grub_cpu_to_le16 (0x020d) && + lh.xloadflags & (1<<1)) /* XLF_CAN_BE_LOADED_ABOVE_4G */ + { + addr_max = -1UL; + load_high = 1; + } - grub_free(kernel); + filelen = grub_file_size (file); - params = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(16384)); + kernel = grub_malloc(filelen); - if (! params) + if (!kernel && !load_high) { - grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters"); + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer")); goto fail; } - memset (params, 0, 16384); - - if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh)) + if (!kernel) { - if (!grub_errno) - grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), - argv[0]); - goto fail; + kernel = grub2_efi_allocate_pages_high (addr_max, BYTES_TO_PAGES(filelen), 4096); + kernel_high = 1; } - if (lh.boot_flag != grub_cpu_to_le16 (0xaa55)) + if (!kernel) { - grub_error (GRUB_ERR_BAD_OS, N_("invalid magic number")); + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer")); goto fail; } - if (lh.setup_sects > GRUB_LINUX_MAX_SETUP_SECTS) + grub_file_seek (file, 0); + if (grub_file_read (file, kernel, filelen) != filelen) { - grub_error (GRUB_ERR_BAD_OS, N_("too many setup sectors")); + grub_error (GRUB_ERR_FILE_READ_ERROR, N_("Can't read kernel %s"), argv[0]); goto fail; } + grub_file_close(file); + file = 0; - if (lh.version < grub_cpu_to_le16 (0x020b)) + if (! grub_linuxefi_secure_validate (kernel, filelen)) { - grub_error (GRUB_ERR_BAD_OS, N_("kernel too old")); + grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), argv[0]); goto fail; } - if (!lh.handover_offset) + params = grub2_efi_allocate_pages_high (addr_max, BYTES_TO_PAGES(16384), 4096); + + if (! params) { - grub_error (GRUB_ERR_BAD_OS, N_("kernel doesn't support EFI handover")); + grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters"); goto fail; } - linux_cmdline = grub_efi_allocate_pages_max(0x3fffffff, - BYTES_TO_PAGES(lh.cmdline_size + 1)); + memset (params, 0, 16384); + copy_setup_header((unsigned char *) params, (unsigned char *) &lh); + params->type_of_loader = 0x21; + + linux_cmdline = grub2_efi_allocate_pages_high (addr_max, + BYTES_TO_PAGES(lh.cmdline_size + 1), 4096); if (!linux_cmdline) { @@ -296,19 +328,20 @@ grub_cmd_linux (grub_command_t cmd __att linux_cmdline + sizeof (LINUX_IMAGE) - 1, lh.cmdline_size - (sizeof (LINUX_IMAGE) - 1)); - lh.cmd_line_ptr = (grub_uint32_t)(grub_uint64_t)linux_cmdline; + params->cmd_line_ptr = (grub_uint32_t)(grub_uint64_t) linux_cmdline; + if ( load_high ) + params->ext_cmd_line_ptr = (grub_uint64_t) linux_cmdline >> 32; handover_offset = lh.handover_offset; - start = (lh.setup_sects + 1) * 512; - len = grub_file_size(file) - start; - - kernel_mem = grub_efi_allocate_pages(lh.pref_address, + kernel_mem = NULL; + if ( !load_high ) + kernel_mem = grub_efi_allocate_pages(lh.pref_address, BYTES_TO_PAGES(lh.init_size)); if (!kernel_mem) - kernel_mem = grub_efi_allocate_pages_max(0x3fffffff, - BYTES_TO_PAGES(lh.init_size)); + kernel_mem = grub2_efi_allocate_pages_high (addr_max, + BYTES_TO_PAGES(lh.init_size), lh.kernel_alignment); if (!kernel_mem) { @@ -316,31 +349,32 @@ grub_cmd_linux (grub_command_t cmd __att goto fail; } - if (grub_file_seek (file, start) == (grub_off_t) -1) - { - grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), - argv[0]); - goto fail; - } + kernel_size = lh.init_size; - if (grub_file_read (file, kernel_mem, len) != len && !grub_errno) - { - grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), - argv[0]); - } + start = (lh.setup_sects + 1) * 512; + memcpy(kernel_mem, (unsigned char *)kernel + start, filelen - start); if (grub_errno == GRUB_ERR_NONE) { grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0); loaded = 1; - lh.code32_start = (grub_uint32_t)(grub_uint64_t) kernel_mem; + params->code32_start = (grub_uint32_t)(grub_uint64_t) kernel_mem; + if ( load_high ) + { + params->ext_code32_start = (grub_uint64_t) kernel_mem >> 32; + /* don't not relocate down in kernel eboot.c::efi_main() */ + params->pref_address = (grub_uint64_t) kernel_mem; + } } - memcpy(params, &lh, 2 * 512); - - params->type_of_loader = 0x21; - fail: + if (kernel) + { + if (!kernel_high) + grub_free(kernel); + else + grub_efi_free_pages((grub_efi_physical_address_t)kernel, BYTES_TO_PAGES(filelen)); + } if (file) grub_file_close (file); Index: grub/include/grub/i386/linux.h =================================================================== --- grub.orig/include/grub/i386/linux.h +++ grub/include/grub/i386/linux.h @@ -140,6 +140,7 @@ struct linux_kernel_header grub_uint64_t pref_address; grub_uint32_t init_size; grub_uint32_t handover_offset; + grub_uint32_t ext_code32_start; } GRUB_PACKED; /* Boot parameters for Linux based on 2.6.12. This is used by the setup @@ -315,7 +316,8 @@ struct linux_kernel_params grub_uint64_t pref_address; grub_uint32_t init_size; grub_uint32_t handover_offset; - grub_uint8_t pad2[104]; /* 248 */ + grub_uint32_t ext_code32_start; + grub_uint8_t pad2[100]; /* 24c */ struct grub_e820_mmap e820_map[(0x400 - 0x2d0) / 20]; /* 2d0 */ } GRUB_PACKED; [-- Attachment #6: ramdisk_above_4g_7_5.patch --] [-- Type: text/x-patch, Size: 2822 bytes --] Subject: [PATCH] x86, efi: enable debug print out for debug purpose --- grub-core/loader/i386/efi/linux.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) Index: grub/grub-core/loader/i386/efi/linux.c =================================================================== --- grub.orig/grub-core/loader/i386/efi/linux.c +++ grub/grub-core/loader/i386/efi/linux.c @@ -29,6 +29,8 @@ GRUB_MOD_LICENSE ("GPLv3+"); +#define DEBUG_PRINT 1 + static grub_dl_t my_mod; static int loaded; static void *kernel_mem; @@ -166,6 +168,12 @@ grub_cmd_initrd (grub_command_t cmd __at ptr = initrd_mem; +#ifdef DEBUG_PRINT + /* before initrd read */ + grub_printf("initrd: [%lx,%lx]\n", + (unsigned long)initrd_mem, (unsigned long)initrd_mem + size - 1); +#endif + for (i = 0; i < nfiles; i++) { grub_ssize_t cursize = grub_file_size (files[i]); @@ -181,6 +189,11 @@ grub_cmd_initrd (grub_command_t cmd __at ptr += ALIGN_UP_OVERHEAD (cursize, 4); } +#ifdef DEBUG_PRINT + /* after initrd read */ + grub_printf("initrd: read %d file%sdone\n", nfiles, nfiles==1 ? " ": "s "); +#endif + fail: for (i = 0; i < nfiles; i++) grub_file_close (files[i]); @@ -296,6 +309,11 @@ grub_cmd_linux (grub_command_t cmd __att grub_file_close(file); file = 0; +#ifdef DEBUG_PRINT + /* after kernel read */ + grub_printf("kernel: read done\n"); +#endif + if (! grub_linuxefi_secure_validate (kernel, filelen)) { grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), argv[0]); @@ -314,6 +332,12 @@ grub_cmd_linux (grub_command_t cmd __att copy_setup_header((unsigned char *) params, (unsigned char *) &lh); params->type_of_loader = 0x21; +#ifdef DEBUG_PRINT + /* after params */ + grub_printf("params: [%lx,%lx]\n", + (unsigned long)params, (unsigned long)params + 16384 - 1); +#endif + linux_cmdline = grub2_efi_allocate_pages_high (addr_max, BYTES_TO_PAGES(lh.cmdline_size + 1), 4096); @@ -332,6 +356,12 @@ grub_cmd_linux (grub_command_t cmd __att if ( load_high ) params->ext_cmd_line_ptr = (grub_uint64_t) linux_cmdline >> 32; +#ifdef DEBUG_PRINT + /* after cmdline */ + grub_printf("cmdline: [%lx,%lx]\n", (unsigned long)linux_cmdline, + (unsigned long)linux_cmdline + lh.cmdline_size - 1); +#endif + handover_offset = lh.handover_offset; kernel_mem = NULL; @@ -351,6 +381,12 @@ grub_cmd_linux (grub_command_t cmd __att kernel_size = lh.init_size; +#ifdef DEBUG_PRINT + /* after kernel alloc */ + grub_printf("kernel: [%lx,%lx]\n", (unsigned long)kernel_mem, + (unsigned long)kernel_mem + lh.init_size - 1); +#endif + start = (lh.setup_sects + 1) * 512; memcpy(kernel_mem, (unsigned char *)kernel + start, filelen - start); ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] x86, boot: Allow 64bit EFI kernel to be loaded above 4G 2015-02-05 5:25 ` Yinghai Lu @ 2015-02-05 6:09 ` Dave Young 2015-02-18 7:29 ` Yinghai Lu 0 siblings, 1 reply; 10+ messages in thread From: Dave Young @ 2015-02-05 6:09 UTC (permalink / raw) To: Yinghai Lu Cc: Thomas Gleixner, H. Peter Anvin, Ingo Molnar, Jonathan Corbet, Matt Fleming, Kees Cook, Junjie Mao, linux-doc, linux-efi, Linux Kernel Mailing List On 02/04/15 at 09:25pm, Yinghai Lu wrote: > On Wed, Feb 4, 2015 at 7:25 PM, Dave Young <dyoung@redhat.com> wrote: > >> After this patch, could use patched grub2-x86_64.efi to place > >> kernel/boot_params/cmd_line/initrd all above 4G and execute the kernel > >> above 4G. > > > > Can you share the grub2 patch for testing? > > Please check attached 5 patches. last one is for debug purpose. > > You need to apply them on top of > > git://git.savannah.gnu.org/grub.git > > plus http://pkgs.fedoraproject.org/cgit/grub2.git/plain/0091-Add-support-for-linuxefi.patch > Subject: [PATCH] update setup_header and boot_params to 2.12 > > the one that is used by kernel v3.8... Thanks for quick feedback.. Dave ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] x86, boot: Allow 64bit EFI kernel to be loaded above 4G 2015-02-05 6:09 ` Dave Young @ 2015-02-18 7:29 ` Yinghai Lu 0 siblings, 0 replies; 10+ messages in thread From: Yinghai Lu @ 2015-02-18 7:29 UTC (permalink / raw) To: Dave Young Cc: Thomas Gleixner, H. Peter Anvin, Ingo Molnar, Jonathan Corbet, Matt Fleming, Kees Cook, Junjie Mao, linux-doc, linux-efi, Linux Kernel Mailing List On Wed, Feb 4, 2015 at 10:09 PM, Dave Young <dyoung@redhat.com> wrote: > On 02/04/15 at 09:25pm, Yinghai Lu wrote: >> On Wed, Feb 4, 2015 at 7:25 PM, Dave Young <dyoung@redhat.com> wrote: >> >> After this patch, could use patched grub2-x86_64.efi to place >> >> kernel/boot_params/cmd_line/initrd all above 4G and execute the kernel >> >> above 4G. >> > >> > Can you share the grub2 patch for testing? >> >> Please check attached 5 patches. last one is for debug purpose. >> >> You need to apply them on top of >> >> git://git.savannah.gnu.org/grub.git >> >> plus http://pkgs.fedoraproject.org/cgit/grub2.git/plain/0091-Add-support-for-linuxefi.patch > FYI, I put those patches together with patches that extend grub2 to load kernel/initrd above 4G into github tree. https://github.com/yhlu/grub2.git Thanks Yinghai ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] x86, boot: Allow 64bit EFI kernel to be loaded above 4G 2015-02-04 2:03 [PATCH] x86, boot: Allow 64bit EFI kernel to be loaded above 4G Yinghai Lu 2015-02-05 3:25 ` Dave Young @ 2015-02-09 18:27 ` Matt Fleming 2015-02-09 20:23 ` Yinghai Lu 1 sibling, 1 reply; 10+ messages in thread From: Matt Fleming @ 2015-02-09 18:27 UTC (permalink / raw) To: Yinghai Lu Cc: Thomas Gleixner, H. Peter Anvin, Ingo Molnar, Jonathan Corbet, Matt Fleming, Kees Cook, Junjie Mao, linux-doc, linux-efi, linux-kernel On Tue, 03 Feb, at 06:03:20PM, Yinghai Lu wrote: > Now could use kexec to place kernel/boot_params/cmd_line/initrd > above 4G, but that is with legacy interface with startup_64 directly. > > This patch will allow 64bit EFI kernel to be loaded above 4G > and use EFI HANDOVER PROTOCOL to start the kernel. > > Current code32_start is used for passing around loading address, > so it will overflow when kernel is loaded abover 4G. > > The patch mainly add ext_code32_start to take address high 32bit. > > After this patch, could use patched grub2-x86_64.efi to place > kernel/boot_params/cmd_line/initrd all above 4G and execute the kernel > above 4G. The first thing that comes to mind is the issues we experienced last year when adding support for loading initrds above 4GB to the EFI boot stub, c.f. commit 47226ad4f4cf ("x86/efi: Only load initrd above 4g on second try"). Are things going to work correctly this time? > Index: linux-2.6/arch/x86/boot/compressed/eboot.c > =================================================================== > --- linux-2.6.orig/arch/x86/boot/compressed/eboot.c > +++ linux-2.6/arch/x86/boot/compressed/eboot.c > @@ -1389,6 +1389,7 @@ struct boot_params *efi_main(struct efi_ > void *handle; > efi_system_table_t *_table; > bool is64; > + unsigned long loaded_addr; > > efi_early = c; > > @@ -1430,9 +1431,12 @@ struct boot_params *efi_main(struct efi_ > * If the kernel isn't already loaded at the preferred load > * address, relocate it. > */ > - if (hdr->pref_address != hdr->code32_start) { > - unsigned long bzimage_addr = hdr->code32_start; > - status = efi_relocate_kernel(sys_table, &bzimage_addr, > + loaded_addr = hdr->code32_start; > + loaded_addr |= (unsigned long)hdr->ext_code32_start << 32; Please compile this for CONFIG_X86_32 and fix any compiler warnings. > @@ -738,6 +742,13 @@ Offset/size: 0x264/4 > > See EFI HANDOVER PROTOCOL below for more details. > > +Field name: ext_code32_start > +Type: modify (optional, reloc) > +Offset/size: 0x268/4 > +Protocol: 2.14+ > + > + The address is used with code32_start to compare pref_address > + to support EFI 64bit kernel get loaded above 4G. It would be good to mention that this new field contains the upper 32-bits of the 64-bit address. -- Matt Fleming, Intel Open Source Technology Center ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] x86, boot: Allow 64bit EFI kernel to be loaded above 4G 2015-02-09 18:27 ` Matt Fleming @ 2015-02-09 20:23 ` Yinghai Lu [not found] ` <CAE9FiQUFO4yfEVgGZ9U0Q-RaokFor1gMbKJ7As2vvqGVkqrDbw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 0 siblings, 1 reply; 10+ messages in thread From: Yinghai Lu @ 2015-02-09 20:23 UTC (permalink / raw) To: Matt Fleming Cc: Thomas Gleixner, H. Peter Anvin, Ingo Molnar, Jonathan Corbet, Matt Fleming, Kees Cook, Junjie Mao, linux-doc, linux-efi, Linux Kernel Mailing List On Mon, Feb 9, 2015 at 10:27 AM, Matt Fleming <matt@codeblueprint.co.uk> wrote: > On Tue, 03 Feb, at 06:03:20PM, Yinghai Lu wrote: > > The first thing that comes to mind is the issues we experienced last > year when adding support for loading initrds above 4GB to the EFI boot > stub, c.f. commit 47226ad4f4cf ("x86/efi: Only load initrd above 4g on > second try"). > > Are things going to work correctly this time? That should be addressed the grub2. I was thinking that we may need to add mem_limit command together with linuxefi and initrdefi. or add linuxefi64/initrdefi64? BTW, I tested loading kernel above grub2 on virutalbox, qemu/kvm/OVMF, and real servers (ami ...) all work without problem. wonder if we need have one black list for 64bit UEFI that does not support access memory above 4G. >> @@ -1430,9 +1431,12 @@ struct boot_params *efi_main(struct efi_ >> * If the kernel isn't already loaded at the preferred load >> * address, relocate it. >> */ >> - if (hdr->pref_address != hdr->code32_start) { >> - unsigned long bzimage_addr = hdr->code32_start; >> - status = efi_relocate_kernel(sys_table, &bzimage_addr, >> + loaded_addr = hdr->code32_start; >> + loaded_addr |= (unsigned long)hdr->ext_code32_start << 32; > > Please compile this for CONFIG_X86_32 and fix any compiler warnings. Ok. > >> @@ -738,6 +742,13 @@ Offset/size: 0x264/4 >> >> See EFI HANDOVER PROTOCOL below for more details. >> >> +Field name: ext_code32_start >> +Type: modify (optional, reloc) >> +Offset/size: 0x268/4 >> +Protocol: 2.14+ >> + >> + The address is used with code32_start to compare pref_address >> + to support EFI 64bit kernel get loaded above 4G. > > It would be good to mention that this new field contains the upper > 32-bits of the 64-bit address. ok. that is: upper 32bits of the 64bit address of startup_32 when kernel loaded above 4G. Thanks Yinghai ^ permalink raw reply [flat|nested] 10+ messages in thread
[parent not found: <CAE9FiQUFO4yfEVgGZ9U0Q-RaokFor1gMbKJ7As2vvqGVkqrDbw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* Re: [PATCH] x86, boot: Allow 64bit EFI kernel to be loaded above 4G [not found] ` <CAE9FiQUFO4yfEVgGZ9U0Q-RaokFor1gMbKJ7As2vvqGVkqrDbw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> @ 2015-02-11 15:55 ` Matt Fleming 2015-02-11 16:29 ` Peter Jones 0 siblings, 1 reply; 10+ messages in thread From: Matt Fleming @ 2015-02-11 15:55 UTC (permalink / raw) To: Yinghai Lu Cc: Thomas Gleixner, H. Peter Anvin, Ingo Molnar, Jonathan Corbet, Kees Cook, Junjie Mao, linux-doc-u79uwXL29TY76Z2rM5mHXA, linux-efi-u79uwXL29TY76Z2rM5mHXA, Linux Kernel Mailing List, Matthew Garrett, Peter Jones On Mon, 09 Feb, at 12:23:15PM, Yinghai Lu wrote: > On Mon, Feb 9, 2015 at 10:27 AM, Matt Fleming <matt-mF/unelCI9GS6iBeEJttW/XRex20P6io@public.gmane.org> wrote: > > On Tue, 03 Feb, at 06:03:20PM, Yinghai Lu wrote: > > > > The first thing that comes to mind is the issues we experienced last > > year when adding support for loading initrds above 4GB to the EFI boot > > stub, c.f. commit 47226ad4f4cf ("x86/efi: Only load initrd above 4g on > > second try"). > > > > Are things going to work correctly this time? > > That should be addressed the grub2. I vaguely remember thinking that the issue was only experienced when using the EFI_FILE protocol, which grub2 doesn't use. So the grub developers may be OK, but we should at least give them a heads up. > I was thinking that we may need to add mem_limit command together with > linuxefi and initrdefi. > or add linuxefi64/initrdefi64? No, we definitely do not want to add any more grub commands. > BTW, I tested loading kernel above grub2 on > virutalbox, qemu/kvm/OVMF, and real servers (ami ...) all work without problem. > > wonder if we need have one black list for 64bit UEFI that does not > support access > memory above 4G. We have been successful, so far, in not introducing these kind of blacklists. It would be a shame to start now. -- Matt Fleming, Intel Open Source Technology Center ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] x86, boot: Allow 64bit EFI kernel to be loaded above 4G 2015-02-11 15:55 ` Matt Fleming @ 2015-02-11 16:29 ` Peter Jones 2015-02-12 14:59 ` Matt Fleming 0 siblings, 1 reply; 10+ messages in thread From: Peter Jones @ 2015-02-11 16:29 UTC (permalink / raw) To: Matt Fleming Cc: Yinghai Lu, Thomas Gleixner, H. Peter Anvin, Ingo Molnar, Jonathan Corbet, Kees Cook, Junjie Mao, linux-doc, linux-efi, Linux Kernel Mailing List, Matthew Garrett On Wed, Feb 11, 2015 at 03:55:24PM +0000, Matt Fleming wrote: > On Mon, 09 Feb, at 12:23:15PM, Yinghai Lu wrote: > > On Mon, Feb 9, 2015 at 10:27 AM, Matt Fleming <matt@codeblueprint.co.uk> wrote: > > > On Tue, 03 Feb, at 06:03:20PM, Yinghai Lu wrote: > > > > > > The first thing that comes to mind is the issues we experienced last > > > year when adding support for loading initrds above 4GB to the EFI boot > > > stub, c.f. commit 47226ad4f4cf ("x86/efi: Only load initrd above 4g on > > > second try"). > > > > > > Are things going to work correctly this time? > > > > That should be addressed the grub2. > > I vaguely remember thinking that the issue was only experienced when > using the EFI_FILE protocol, which grub2 doesn't use. So the grub > developers may be OK, but we should at least give them a heads up. Looks correct to me. > > I was thinking that we may need to add mem_limit command together with > > linuxefi and initrdefi. > > or add linuxefi64/initrdefi64? > > No, we definitely do not want to add any more grub commands. Definitely agree. > > BTW, I tested loading kernel above grub2 on > > virutalbox, qemu/kvm/OVMF, and real servers (ami ...) all work without problem. > > > > wonder if we need have one black list for 64bit UEFI that does not > > support access > > memory above 4G. > > We have been successful, so far, in not introducing these kind of > blacklists. It would be a shame to start now. >From grub's point of view I'm not sure why we'd care - the pages kernel and initramfs land in are both from the Boot Services allocator, so if the machine doesn't support high addresses, they won't be there. -- Peter ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] x86, boot: Allow 64bit EFI kernel to be loaded above 4G 2015-02-11 16:29 ` Peter Jones @ 2015-02-12 14:59 ` Matt Fleming 0 siblings, 0 replies; 10+ messages in thread From: Matt Fleming @ 2015-02-12 14:59 UTC (permalink / raw) To: Peter Jones Cc: Yinghai Lu, Thomas Gleixner, H. Peter Anvin, Ingo Molnar, Jonathan Corbet, Kees Cook, Junjie Mao, linux-doc, linux-efi, Linux Kernel Mailing List, Matthew Garrett On Wed, 11 Feb, at 11:29:58AM, Peter Jones wrote: > > From grub's point of view I'm not sure why we'd care - the pages kernel > and initramfs land in are both from the Boot Services allocator, so if the > machine doesn't support high addresses, they won't be there. It's not that some implementations don't "support" higher addresses, it's that the EFI_FILE_PROTOCOL is buggy and it corrupts the memory when reading into it; you can allocate it just fine. At least, that's what I remember from the limited investigation I performed. But since grub doesn't use EFI_FILE_PROTOCOL, we should be cool. -- Matt Fleming, Intel Open Source Technology Center ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2015-02-18 7:29 UTC | newest] Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2015-02-04 2:03 [PATCH] x86, boot: Allow 64bit EFI kernel to be loaded above 4G Yinghai Lu 2015-02-05 3:25 ` Dave Young 2015-02-05 5:25 ` Yinghai Lu 2015-02-05 6:09 ` Dave Young 2015-02-18 7:29 ` Yinghai Lu 2015-02-09 18:27 ` Matt Fleming 2015-02-09 20:23 ` Yinghai Lu [not found] ` <CAE9FiQUFO4yfEVgGZ9U0Q-RaokFor1gMbKJ7As2vvqGVkqrDbw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2015-02-11 15:55 ` Matt Fleming 2015-02-11 16:29 ` Peter Jones 2015-02-12 14:59 ` Matt Fleming
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).