[U-Boot] [PATCH v3 18/28] efi: Add 64-bit payload support

Bin Meng bmeng.cn at gmail.com
Wed Aug 5 10:02:15 CEST 2015


On Wed, Aug 5, 2015 at 2:33 AM, Simon Glass <sjg at chromium.org> wrote:
> 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 at chromium.org>
> Improvements to how the payload is built:
> Signed-off-by: Bin Meng <bmeng.cn at gmail.com>
> ---
>
> Changes in v3:
> - Add spaces around EFIARCH=
> - Use CONFIG_SYS_MONITOR_LEN as a more accurate value for U-Boot's size
>
> Changes in v2:
> - Add -no-red-zone for 64-bit only
> - Check the GDT selector's base and limit against the target address
> - Drop use of CONFIG_X86_64 since we don't support a 64-bit EFI application yet
> - Merge in Bin's implementation of adding a U-Boot payload with objcopy
> - Move the 64-bit crt and reloc code into this patch
> - Move the 64-bit efi.h additions into this patch
> - Rename GDT_4GB to GDT_4KB
>
>  Makefile                           |  2 +-
>  arch/x86/config.mk                 | 10 ++++++
>  arch/x86/include/asm/types.h       |  5 ++-
>  arch/x86/lib/efi/crt0-efi-x86_64.S | 51 ++++++++++++++++++++++++++
>  include/efi.h                      |  7 ++++
>  lib/efi/efi_stub.c                 | 74 +++++++++++++++++++++++++++++++++++---
>  6 files changed, 143 insertions(+), 6 deletions(-)
>  create mode 100644 arch/x86/lib/efi/crt0-efi-x86_64.S
>
> diff --git a/Makefile b/Makefile
> index 752ee0d..bb0ba9f 100644
> --- a/Makefile
> +++ b/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
>  quiet_cmd_u-boot_payload ?= LD      $@
>        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 \
>        $(addprefix arch/$(ARCH)/lib/efi/,$(EFISTUB))
>
> diff --git a/arch/x86/config.mk b/arch/x86/config.mk
> index 334c10b..d7addd8 100644
> --- a/arch/x86/config.mk
> +++ b/arch/x86/config.mk
> @@ -34,14 +34,24 @@ OBJCOPYFLAGS_EFI := -j .text -j .sdata -j .data -j .dynamic -j .dynsym \
>  CFLAGS_NON_EFI := -mregparm=3
>  CFLAGS_EFI := -fpic -fshort-wchar
>
> +ifeq ($(CONFIG_EFI_STUB_64BIT),)
> +CFLAGS_EFI += $(call cc-option, -mno-red-zone)
>  EFIARCH = ia32
>  EFIPAYLOAD_BFDTARGET = elf32-i386
> +else
> +EFIARCH = x86_64
> +EFIPAYLOAD_BFDTARGET = elf64-x86-64
> +endif
>
>  EFIPAYLOAD_BFDARCH = i386
>
>  LDSCRIPT_EFI := $(srctree)/$(CPUDIR)/efi/elf_$(EFIARCH)_efi.lds
> +EFISTUB := crt0-efi-$(EFIARCH).o reloc_$(EFIARCH).o
>  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)
>
>  PLATFORM_CPPFLAGS += $(CFLAGS_EFI)
> diff --git a/arch/x86/include/asm/types.h b/arch/x86/include/asm/types.h
> index e272c90..766617f 100644
> --- a/arch/x86/include/asm/types.h
> +++ b/arch/x86/include/asm/types.h
> @@ -44,8 +44,11 @@ typedef __INT64_TYPE__ s64;
>  typedef __UINT64_TYPE__ u64;
>  #endif
>
> +#ifdef CONFIG_EFI_STUB_64BIT
> +#define BITS_PER_LONG 64
> +#else
>  #define BITS_PER_LONG 32
> -
> +#endif
>  /* Dma addresses are 32-bits wide.  */
>
>  typedef u32 dma_addr_t;
> diff --git a/arch/x86/lib/efi/crt0-efi-x86_64.S b/arch/x86/lib/efi/crt0-efi-x86_64.S
> new file mode 100644
> index 0000000..c5cbf41
> --- /dev/null
> +++ b/arch/x86/lib/efi/crt0-efi-x86_64.S
> @@ -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 at hpl.hp.com>.
> + * Copyright (C) 2005 Intel Co.
> + * Contributed by Fenghua Yu <fenghua.yu at 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 */
> diff --git a/include/efi.h b/include/efi.h
> index 1470c08..fcafda0 100644
> --- a/include/efi.h
> +++ b/include/efi.h
> @@ -18,6 +18,13 @@
>  #include <linux/string.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;
>
>  #define EFI_SUCCESS            0
> diff --git a/lib/efi/efi_stub.c b/lib/efi/efi_stub.c
> index 1e46f6e..d4d3e49 100644
> --- a/lib/efi/efi_stub.c
> +++ b/lib/efi/efi_stub.c
> @@ -6,8 +6,8 @@
>   * EFI information obtained here:
>   * http://wiki.phoenix.com/wiki/index.php/EFI_BOOT_SERVICES
>   *
> - * Loads a payload (U-Boot) within the EFI environment. This is built as a
> - * 32-bit EFI application.
> + * Loads a payload (U-Boot) within the EFI environment. This is built as an
> + * EFI application. It can be built either in 32-bit or 64-bit mode.
>   */
>
>  #include <common.h>
> @@ -126,14 +126,16 @@ static void jump_to_uboot(ulong cs32, ulong addr, ulong info)
>
>         ((func_t)addr)(0, 0, info);
>  #else
> -       /* TODO: Implement this */
> +       cpu_call32(cs32, CONFIG_SYS_TEXT_BASE, info);
>  #endif
>  }
>
> +#ifdef CONFIG_EFI_STUB_64BIT
>  static void get_gdt(struct desctab_info *info)
>  {
>         asm volatile ("sgdt %0" : : "m"(*info) : "memory");
>  }
> +#endif
>
>  static inline unsigned long read_cr3(void)
>  {
> @@ -156,7 +158,71 @@ static int get_codeseg32(void)
>  {
>         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;
>  }
>
> --

Reviewed-by: Bin Meng <bmeng.cn at gmail.com>

Tested on QEMU 32-bit and 64-bit
Tested-by: Bin Meng <bmeng.cn at gmail.com>


More information about the U-Boot mailing list