efi: Add 64-bit payload support
Most EFI implementations use 64-bit. Add a way to build U-Boot as a 64-bit EFI payload. The payload unpacks a (32-bit) U-Boot and starts it. This can be enabled for x86 boards at present. Signed-off-by: Simon Glass <sjg@chromium.org> Improvements to how the payload is built: Signed-off-by: Bin Meng <bmeng.cn@gmail.com> Reviewed-by: Bin Meng <bmeng.cn@gmail.com> Tested-by: Bin Meng <bmeng.cn@gmail.com>
This commit is contained in:
parent
6f92ed8f1a
commit
96a8d409a7
6 changed files with 143 additions and 6 deletions
2
Makefile
2
Makefile
|
@ -1100,7 +1100,7 @@ u-boot-payload.lds: $(LDSCRIPT_EFI) FORCE
|
||||||
# Rule to link the EFI payload which contains a stub and a U-Boot binary
|
# Rule to link the EFI payload which contains a stub and a U-Boot binary
|
||||||
quiet_cmd_u-boot_payload ?= LD $@
|
quiet_cmd_u-boot_payload ?= LD $@
|
||||||
cmd_u-boot_payload ?= $(LD) $(LDFLAGS_EFI_PAYLOAD) -o $@ \
|
cmd_u-boot_payload ?= $(LD) $(LDFLAGS_EFI_PAYLOAD) -o $@ \
|
||||||
-T u-boot-payload.lds \
|
-T u-boot-payload.lds arch/x86/cpu/call32.o \
|
||||||
lib/efi/efi.o lib/efi/efi_stub.o u-boot-dtb.bin.o \
|
lib/efi/efi.o lib/efi/efi_stub.o u-boot-dtb.bin.o \
|
||||||
$(addprefix arch/$(ARCH)/lib/efi/,$(EFISTUB))
|
$(addprefix arch/$(ARCH)/lib/efi/,$(EFISTUB))
|
||||||
|
|
||||||
|
|
|
@ -34,14 +34,24 @@ OBJCOPYFLAGS_EFI := -j .text -j .sdata -j .data -j .dynamic -j .dynsym \
|
||||||
CFLAGS_NON_EFI := -mregparm=3
|
CFLAGS_NON_EFI := -mregparm=3
|
||||||
CFLAGS_EFI := -fpic -fshort-wchar
|
CFLAGS_EFI := -fpic -fshort-wchar
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_EFI_STUB_64BIT),)
|
||||||
|
CFLAGS_EFI += $(call cc-option, -mno-red-zone)
|
||||||
EFIARCH = ia32
|
EFIARCH = ia32
|
||||||
EFIPAYLOAD_BFDTARGET = elf32-i386
|
EFIPAYLOAD_BFDTARGET = elf32-i386
|
||||||
|
else
|
||||||
|
EFIARCH = x86_64
|
||||||
|
EFIPAYLOAD_BFDTARGET = elf64-x86-64
|
||||||
|
endif
|
||||||
|
|
||||||
EFIPAYLOAD_BFDARCH = i386
|
EFIPAYLOAD_BFDARCH = i386
|
||||||
|
|
||||||
LDSCRIPT_EFI := $(srctree)/$(CPUDIR)/efi/elf_$(EFIARCH)_efi.lds
|
LDSCRIPT_EFI := $(srctree)/$(CPUDIR)/efi/elf_$(EFIARCH)_efi.lds
|
||||||
|
EFISTUB := crt0-efi-$(EFIARCH).o reloc_$(EFIARCH).o
|
||||||
OBJCOPYFLAGS_EFI += --target=efi-app-$(EFIARCH)
|
OBJCOPYFLAGS_EFI += --target=efi-app-$(EFIARCH)
|
||||||
|
|
||||||
|
CPPFLAGS_REMOVE_crt0-efi-$(EFIARCH).o += $(CFLAGS_NON_EFI)
|
||||||
|
CPPFLAGS_crt0-efi-$(EFIARCH).o += $(CFLAGS_EFI)
|
||||||
|
|
||||||
ifeq ($(CONFIG_EFI_APP),y)
|
ifeq ($(CONFIG_EFI_APP),y)
|
||||||
|
|
||||||
PLATFORM_CPPFLAGS += $(CFLAGS_EFI)
|
PLATFORM_CPPFLAGS += $(CFLAGS_EFI)
|
||||||
|
|
|
@ -44,8 +44,11 @@ typedef __INT64_TYPE__ s64;
|
||||||
typedef __UINT64_TYPE__ u64;
|
typedef __UINT64_TYPE__ u64;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_EFI_STUB_64BIT
|
||||||
|
#define BITS_PER_LONG 64
|
||||||
|
#else
|
||||||
#define BITS_PER_LONG 32
|
#define BITS_PER_LONG 32
|
||||||
|
#endif
|
||||||
/* Dma addresses are 32-bits wide. */
|
/* Dma addresses are 32-bits wide. */
|
||||||
|
|
||||||
typedef u32 dma_addr_t;
|
typedef u32 dma_addr_t;
|
||||||
|
|
51
arch/x86/lib/efi/crt0-efi-x86_64.S
Normal file
51
arch/x86/lib/efi/crt0-efi-x86_64.S
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* crt0-efi-x86_64.S - x86_64 EFI startup code.
|
||||||
|
* Copyright (C) 1999 Hewlett-Packard Co.
|
||||||
|
* Contributed by David Mosberger <davidm@hpl.hp.com>.
|
||||||
|
* Copyright (C) 2005 Intel Co.
|
||||||
|
* Contributed by Fenghua Yu <fenghua.yu@intel.com>.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
.text
|
||||||
|
.align 4
|
||||||
|
|
||||||
|
.globl _start
|
||||||
|
_start:
|
||||||
|
subq $8, %rsp
|
||||||
|
pushq %rcx
|
||||||
|
pushq %rdx
|
||||||
|
|
||||||
|
0:
|
||||||
|
lea image_base(%rip), %rdi
|
||||||
|
lea _DYNAMIC(%rip), %rsi
|
||||||
|
|
||||||
|
popq %rcx
|
||||||
|
popq %rdx
|
||||||
|
pushq %rcx
|
||||||
|
pushq %rdx
|
||||||
|
call _relocate
|
||||||
|
|
||||||
|
popq %rdi
|
||||||
|
popq %rsi
|
||||||
|
|
||||||
|
call efi_main
|
||||||
|
addq $8, %rsp
|
||||||
|
|
||||||
|
.exit:
|
||||||
|
ret
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hand-craft a dummy .reloc section so EFI knows it's a relocatable
|
||||||
|
* executable:
|
||||||
|
*/
|
||||||
|
.data
|
||||||
|
dummy: .long 0
|
||||||
|
|
||||||
|
#define IMAGE_REL_ABSOLUTE 0
|
||||||
|
.section .reloc, "a"
|
||||||
|
label1:
|
||||||
|
.long dummy-label1 /* Page RVA */
|
||||||
|
.long 10 /* Block Size (2*4+2) */
|
||||||
|
.word (IMAGE_REL_ABSOLUTE << 12) + 0 /* reloc for dummy */
|
|
@ -18,6 +18,13 @@
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_EFI_STUB_64BIT
|
||||||
|
/* EFI uses the Microsoft ABI which is not the default for GCC */
|
||||||
|
#define EFIAPI __attribute__((ms_abi))
|
||||||
|
#else
|
||||||
|
#define EFIAPI
|
||||||
|
#endif
|
||||||
|
|
||||||
struct efi_device_path;
|
struct efi_device_path;
|
||||||
|
|
||||||
#define EFI_SUCCESS 0
|
#define EFI_SUCCESS 0
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
* EFI information obtained here:
|
* EFI information obtained here:
|
||||||
* http://wiki.phoenix.com/wiki/index.php/EFI_BOOT_SERVICES
|
* http://wiki.phoenix.com/wiki/index.php/EFI_BOOT_SERVICES
|
||||||
*
|
*
|
||||||
* Loads a payload (U-Boot) within the EFI environment. This is built as a
|
* Loads a payload (U-Boot) within the EFI environment. This is built as an
|
||||||
* 32-bit EFI application.
|
* EFI application. It can be built either in 32-bit or 64-bit mode.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
|
@ -126,14 +126,16 @@ static void jump_to_uboot(ulong cs32, ulong addr, ulong info)
|
||||||
|
|
||||||
((func_t)addr)(0, 0, info);
|
((func_t)addr)(0, 0, info);
|
||||||
#else
|
#else
|
||||||
/* TODO: Implement this */
|
cpu_call32(cs32, CONFIG_SYS_TEXT_BASE, info);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_EFI_STUB_64BIT
|
||||||
static void get_gdt(struct desctab_info *info)
|
static void get_gdt(struct desctab_info *info)
|
||||||
{
|
{
|
||||||
asm volatile ("sgdt %0" : : "m"(*info) : "memory");
|
asm volatile ("sgdt %0" : : "m"(*info) : "memory");
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline unsigned long read_cr3(void)
|
static inline unsigned long read_cr3(void)
|
||||||
{
|
{
|
||||||
|
@ -156,7 +158,71 @@ static int get_codeseg32(void)
|
||||||
{
|
{
|
||||||
int cs32 = 0;
|
int cs32 = 0;
|
||||||
|
|
||||||
/* TODO(sjg): Implement this for 64-bit mode */
|
#ifdef CONFIG_EFI_STUB_64BIT
|
||||||
|
struct desctab_info gdt;
|
||||||
|
uint64_t *ptr;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
get_gdt(&gdt);
|
||||||
|
for (ptr = (uint64_t *)(unsigned long)gdt.addr, i = 0; i < gdt.limit;
|
||||||
|
i += 8, ptr++) {
|
||||||
|
uint64_t desc = *ptr;
|
||||||
|
uint64_t base, limit;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check that the target U-Boot jump address is within the
|
||||||
|
* selector and that the selector is of the right type.
|
||||||
|
*/
|
||||||
|
base = ((desc >> GDT_BASE_LOW_SHIFT) & GDT_BASE_LOW_MASK) |
|
||||||
|
((desc >> GDT_BASE_HIGH_SHIFT) & GDT_BASE_HIGH_MASK)
|
||||||
|
<< 16;
|
||||||
|
limit = ((desc >> GDT_LIMIT_LOW_SHIFT) & GDT_LIMIT_LOW_MASK) |
|
||||||
|
((desc >> GDT_LIMIT_HIGH_SHIFT) & GDT_LIMIT_HIGH_MASK)
|
||||||
|
<< 16;
|
||||||
|
base <<= 12; /* 4KB granularity */
|
||||||
|
limit <<= 12;
|
||||||
|
if ((desc & GDT_PRESENT) && (desc && GDT_NOTSYS) &&
|
||||||
|
!(desc & GDT_LONG) && (desc & GDT_4KB) &&
|
||||||
|
(desc & GDT_32BIT) && (desc & GDT_CODE) &&
|
||||||
|
CONFIG_SYS_TEXT_BASE > base &&
|
||||||
|
CONFIG_SYS_TEXT_BASE + CONFIG_SYS_MONITOR_LEN < limit
|
||||||
|
) {
|
||||||
|
cs32 = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
puts("\ngdt: ");
|
||||||
|
printhex8(gdt.limit);
|
||||||
|
puts(", addr: ");
|
||||||
|
printhex8(gdt.addr >> 32);
|
||||||
|
printhex8(gdt.addr);
|
||||||
|
for (i = 0; i < gdt.limit; i += 8) {
|
||||||
|
uint32_t *ptr = (uint32_t *)((unsigned long)gdt.addr + i);
|
||||||
|
|
||||||
|
puts("\n");
|
||||||
|
printhex2(i);
|
||||||
|
puts(": ");
|
||||||
|
printhex8(ptr[1]);
|
||||||
|
puts(" ");
|
||||||
|
printhex8(ptr[0]);
|
||||||
|
}
|
||||||
|
puts("\n ");
|
||||||
|
puts("32-bit code segment: ");
|
||||||
|
printhex2(cs32);
|
||||||
|
puts("\n ");
|
||||||
|
|
||||||
|
puts("page_table: ");
|
||||||
|
printhex8(read_cr3());
|
||||||
|
puts("\n ");
|
||||||
|
#endif
|
||||||
|
if (!cs32) {
|
||||||
|
puts("Can't find 32-bit code segment\n");
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return cs32;
|
return cs32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue