From 0d1fcfa70d817442f75e257c28602c7fdec9f262 Mon Sep 17 00:00:00 2001 From: yasuoka Date: Mon, 5 Oct 2015 22:59:39 +0000 Subject: [PATCH] Fix efiboot not to use the usual kernel load address. Load the kernel in an allocated region and also move the stack to the end of the heap region. Then move the kernel to the usual place just before run the kernel, after calling ExitBootService(). report/test Toby Slight, Brian Conway --- sys/arch/amd64/include/loadfile_machdep.h | 8 ++++- sys/arch/amd64/stand/efiboot/efiboot.c | 42 +++++++++++++++++++---- sys/arch/amd64/stand/libsa/exec_i386.c | 31 ++++++++++++----- 3 files changed, 65 insertions(+), 16 deletions(-) diff --git a/sys/arch/amd64/include/loadfile_machdep.h b/sys/arch/amd64/include/loadfile_machdep.h index 65a92496d9a..1b51946b62a 100644 --- a/sys/arch/amd64/include/loadfile_machdep.h +++ b/sys/arch/amd64/include/loadfile_machdep.h @@ -1,5 +1,5 @@ /* XXX - DSR */ -/* $OpenBSD: loadfile_machdep.h,v 1.5 2015/07/17 20:44:38 miod Exp $ */ +/* $OpenBSD: loadfile_machdep.h,v 1.6 2015/10/05 22:59:39 yasuoka Exp $ */ /* $NetBSD: loadfile_machdep.h,v 1.1 1999/04/29 03:17:12 tsubai Exp $ */ /*- @@ -41,7 +41,13 @@ #define LOAD_KERNEL LOAD_ALL #define COUNT_KERNEL COUNT_ALL +#ifdef EFIBOOT +extern u_long efi_loadaddr; +#define LOADADDR(a) (((((u_long)(a)) + offset)&0xfffffff) + \ + efi_loadaddr) +#else #define LOADADDR(a) ((((u_long)(a)) + offset)&0xfffffff) +#endif #define ALIGNENTRY(a) ((u_long)(a)) #define READ(f, b, c) read((f), (void *)LOADADDR(b), (c)) #define BCOPY(s, d, c) memcpy((void *)LOADADDR(d), (void *)(s), (c)) diff --git a/sys/arch/amd64/stand/efiboot/efiboot.c b/sys/arch/amd64/stand/efiboot/efiboot.c index 086d0a466af..a28818fd55f 100644 --- a/sys/arch/amd64/stand/efiboot/efiboot.c +++ b/sys/arch/amd64/stand/efiboot/efiboot.c @@ -1,4 +1,4 @@ -/* $OpenBSD: efiboot.c,v 1.5 2015/09/23 03:29:26 yasuoka Exp $ */ +/* $OpenBSD: efiboot.c,v 1.6 2015/10/05 22:59:39 yasuoka Exp $ */ /* * Copyright (c) 2015 YASUOKA Masahiko @@ -36,6 +36,8 @@ #include "eficall.h" #include "run_i386.h" +#define KERN_LOADSPACE_SIZE (32 * 1024 * 1024) + EFI_SYSTEM_TABLE *ST; EFI_BOOT_SERVICES *BS; EFI_RUNTIME_SERVICES *RS; @@ -46,6 +48,7 @@ UINTN heapsiz = 1 * 1024 * 1024; UINTN mmap_key; static EFI_GUID imgdp_guid = { 0xbc62157e, 0x3e33, 0x4fec, { 0x99, 0x20, 0x2d, 0x3b, 0x36, 0xd7, 0x50, 0xdf }}; +u_long efi_loadaddr; static void efi_heap_init(void); static void efi_memprobe_internal(void); @@ -61,9 +64,10 @@ extern int bios_bootdev; EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) { - extern char *progname; - EFI_DEVICE_PATH *dp0 = NULL, *dp; - EFI_STATUS status; + extern char *progname; + EFI_DEVICE_PATH *dp0 = NULL, *dp; + EFI_STATUS status; + EFI_PHYSICAL_ADDRESS stack; ST = systab; BS = ST->BootServices; @@ -101,8 +105,23 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) progname = "EFIBOOT"; - boot(bios_bootdev); - + /* + * Move the stack before calling boot(). UEFI on some machines + * locate the stack on our kernel load address. + */ + stack = heap + heapsiz; +#if defined(__amd64__) + asm("movq %0, %%rsp;" + "mov %1, %%edi;" + "call boot;" + :: "r"(stack - 32), "r"(bios_bootdev)); +#else + asm("movl %0, %%esp;" + "movl %1, (%%esp);" + "call boot;" + :: "r"(stack - 32), "r"(bios_bootdev)); +#endif + /* must not reach here */ return (EFI_SUCCESS); } @@ -212,6 +231,15 @@ efi_memprobe(void) { u_int n = 0; bios_memmap_t *bm; + EFI_STATUS status; + EFI_PHYSICAL_ADDRESS + addr = 0x10000000ULL; /* Below 256MB */ + + status = EFI_CALL(BS->AllocatePages, AllocateMaxAddress, EfiLoaderData, + EFI_SIZE_TO_PAGES(KERN_LOADSPACE_SIZE), &addr); + if (status != EFI_SUCCESS) + panic("BS->AllocatePages()"); + efi_loadaddr = addr; printf(" mem["); efi_memprobe_internal(); @@ -236,7 +264,7 @@ efi_memprobe_internal(void) UINT32 mmver; EFI_MEMORY_DESCRIPTOR *mm0, *mm; int i, n; - bios_memmap_t *bm, bm0; + bios_memmap_t *bm, bm0; cnvmem = extmem = 0; bios_memmap[0].type = BIOS_MAP_END; diff --git a/sys/arch/amd64/stand/libsa/exec_i386.c b/sys/arch/amd64/stand/libsa/exec_i386.c index 687e5435963..9134844a43c 100644 --- a/sys/arch/amd64/stand/libsa/exec_i386.c +++ b/sys/arch/amd64/stand/libsa/exec_i386.c @@ -1,4 +1,4 @@ -/* $OpenBSD: exec_i386.c,v 1.14 2015/09/02 04:09:24 yasuoka Exp $ */ +/* $OpenBSD: exec_i386.c,v 1.15 2015/10/05 22:59:39 yasuoka Exp $ */ /* * Copyright (c) 1997-1998 Michael Shalayeff @@ -72,8 +72,11 @@ run_loadfile(u_long *marks, int howto) bios_bootsr_t bootsr; struct sr_boot_volume *bv; #endif +#if defined(EFIBOOT) + int i; + u_long delta; + extern u_long efi_loadaddr; -#ifdef EFIBOOT if ((av = alloc(ac)) == NULL) panic("alloc for bootarg"); efi_makebootargs(); @@ -131,17 +134,29 @@ run_loadfile(u_long *marks, int howto) printf("entry point at 0x%lx [%x, %x, %x, %x]\n", entry, ((int *)entry)[0], ((int *)entry)[1], ((int *)entry)[2], ((int *)entry)[3]); - -#if defined(EFIBOOT) +#ifndef EFIBOOT + /* stack and the gung is ok at this point, so, no need for asm setup */ + (*(startfuncp)entry)(howto, bootdev, BOOTARG_APIVER, marks[MARK_END], + extmem, cnvmem, ac, (int)av); +#else + /* + * Move the loaded kernel image to the usual place after calling + * ExitBootServervice() + */ + delta = DEFAULT_KERNEL_ADDRESS - efi_loadaddr; efi_cleanup(); -#endif -#if defined(EFIBOOT) && defined(__amd64__) + memcpy((void *)marks[MARK_START] + delta, (void *)marks[MARK_START], + marks[MARK_END] - marks[MARK_START]); + for (i = 0; i < MARK_MAX; i++) + marks[i] += delta; + entry += delta; +#ifdef __amd64__ (*run_i386)((u_long)run_i386, entry, howto, bootdev, BOOTARG_APIVER, marks[MARK_END], extmem, cnvmem, ac, (intptr_t)av); #else - /* stack and the gung is ok at this point, so, no need for asm setup */ (*(startfuncp)entry)(howto, bootdev, BOOTARG_APIVER, marks[MARK_END], extmem, cnvmem, ac, (int)av); - /* not reached */ #endif +#endif + /* not reached */ } -- 2.20.1