From 456ee909d63a35daa51b70231c4abffa4709e9f3 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 30 Jul 2015 03:49:14 -0700 Subject: x86: minnowmax: Remove smsc47x superio codes On Intel BayTrail SoC, there is a legacy UART (I/O 0x3f8) integrated into the SoC which is enabled by the FSP. Remove the smsc47x superio initialization codes. Signed-off-by: Bin Meng Acked-by: Simon Glass --- include/configs/minnowmax.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include') diff --git a/include/configs/minnowmax.h b/include/configs/minnowmax.h index 4781e792f9b..655ce3d422e 100644 --- a/include/configs/minnowmax.h +++ b/include/configs/minnowmax.h @@ -14,11 +14,9 @@ #include #define CONFIG_SYS_MONITOR_LEN (1 << 20) -#define CONFIG_BOARD_EARLY_INIT_F #define CONFIG_ARCH_EARLY_INIT_R #define CONFIG_X86_SERIAL -#define CONFIG_SMSC_LPC47M #define CONFIG_PCI_MEM_BUS 0xd0000000 #define CONFIG_PCI_MEM_PHYS CONFIG_PCI_MEM_BUS -- cgit v1.3.1 From 9b911bed78c3926fe1129dcc6b0ffbca667dff74 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 30 Jul 2015 03:49:17 -0700 Subject: x86: Add Intel Bayley Bay board support Intel Bayley Bay board is a BayTrail based board. Add this board with existing baytrail fsp support. Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/dts/Makefile | 3 +- arch/x86/dts/bayleybay.dts | 134 ++++++++++++++++++++++++++++++++++++++ board/intel/Kconfig | 9 +++ board/intel/bayleybay/Kconfig | 27 ++++++++ board/intel/bayleybay/MAINTAINERS | 6 ++ board/intel/bayleybay/Makefile | 7 ++ board/intel/bayleybay/bayleybay.c | 19 ++++++ board/intel/bayleybay/start.S | 9 +++ configs/bayleybay_defconfig | 25 +++++++ include/configs/bayleybay.h | 45 +++++++++++++ 10 files changed, 283 insertions(+), 1 deletion(-) create mode 100644 arch/x86/dts/bayleybay.dts create mode 100644 board/intel/bayleybay/Kconfig create mode 100644 board/intel/bayleybay/MAINTAINERS create mode 100644 board/intel/bayleybay/Makefile create mode 100644 board/intel/bayleybay/bayleybay.c create mode 100644 board/intel/bayleybay/start.S create mode 100644 configs/bayleybay_defconfig create mode 100644 include/configs/bayleybay.h (limited to 'include') diff --git a/arch/x86/dts/Makefile b/arch/x86/dts/Makefile index f86514ce839..44e2829f25a 100644 --- a/arch/x86/dts/Makefile +++ b/arch/x86/dts/Makefile @@ -1,4 +1,5 @@ -dtb-y += chromebook_link.dtb \ +dtb-y += bayleybay.dtb \ + chromebook_link.dtb \ chromebox_panther.dtb \ crownbay.dtb \ galileo.dtb \ diff --git a/arch/x86/dts/bayleybay.dts b/arch/x86/dts/bayleybay.dts new file mode 100644 index 00000000000..cbbdee27305 --- /dev/null +++ b/arch/x86/dts/bayleybay.dts @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2015, Bin Meng + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/dts-v1/; + +#include + +/include/ "skeleton.dtsi" +/include/ "serial.dtsi" +/include/ "rtc.dtsi" + +/ { + model = "Intel Bayley Bay"; + compatible = "intel,bayleybay", "intel,baytrail"; + + aliases { + serial0 = &serial; + spi0 = "/spi"; + }; + + config { + silent_console = <0>; + }; + + chosen { + stdout-path = "/serial"; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "intel,baytrail-cpu"; + reg = <0>; + intel,apic-id = <0>; + }; + + cpu@1 { + device_type = "cpu"; + compatible = "intel,baytrail-cpu"; + reg = <1>; + intel,apic-id = <2>; + }; + + cpu@2 { + device_type = "cpu"; + compatible = "intel,baytrail-cpu"; + reg = <2>; + intel,apic-id = <4>; + }; + + cpu@3 { + device_type = "cpu"; + compatible = "intel,baytrail-cpu"; + reg = <3>; + intel,apic-id = <6>; + }; + }; + + spi { + #address-cells = <1>; + #size-cells = <0>; + compatible = "intel,ich-spi"; + spi-flash@0 { + reg = <0>; + compatible = "winbond,w25q64dw", "spi-flash"; + memory-map = <0xff800000 0x00800000>; + }; + }; + + gpioa { + compatible = "intel,ich6-gpio"; + u-boot,dm-pre-reloc; + reg = <0 0x20>; + bank-name = "A"; + }; + + gpiob { + compatible = "intel,ich6-gpio"; + u-boot,dm-pre-reloc; + reg = <0x20 0x20>; + bank-name = "B"; + }; + + gpioc { + compatible = "intel,ich6-gpio"; + u-boot,dm-pre-reloc; + reg = <0x40 0x20>; + bank-name = "C"; + }; + + gpiod { + compatible = "intel,ich6-gpio"; + u-boot,dm-pre-reloc; + reg = <0x60 0x20>; + bank-name = "D"; + }; + + gpioe { + compatible = "intel,ich6-gpio"; + u-boot,dm-pre-reloc; + reg = <0x80 0x20>; + bank-name = "E"; + }; + + gpiof { + compatible = "intel,ich6-gpio"; + u-boot,dm-pre-reloc; + reg = <0xA0 0x20>; + bank-name = "F"; + }; + + pci { + compatible = "pci-x86"; + #address-cells = <3>; + #size-cells = <2>; + u-boot,dm-pre-reloc; + ranges = <0x02000000 0x0 0x80000000 0x80000000 0 0x40000000 + 0x42000000 0x0 0xc0000000 0xc0000000 0 0x20000000 + 0x01000000 0x0 0x2000 0x2000 0 0xe000>; + }; + + microcode { + update@0 { +#include "microcode/m0230671117.dtsi" + }; + }; + +}; diff --git a/board/intel/Kconfig b/board/intel/Kconfig index 3d9ecf06930..f7d71c3612a 100644 --- a/board/intel/Kconfig +++ b/board/intel/Kconfig @@ -10,6 +10,14 @@ choice prompt "Mainboard model" optional +config TARGET_BAYLEYBAY + bool "Bayley Bay" + help + This is the Intel Bayley Bay Customer Reference Board. It contains an + Intel quad-core Atom Processor E3800 with dual-channel DDR3L SODIMM + 4GB memory, HDMI/DP/VGA display, HD audio, SATA, USB2, USB3, SD, eMMC, + PCIe and some other sensor interfaces. + config TARGET_CROWNBAY bool "Crown Bay" help @@ -45,6 +53,7 @@ config TARGET_MINNOWMAX endchoice +source "board/intel/bayleybay/Kconfig" source "board/intel/crownbay/Kconfig" source "board/intel/galileo/Kconfig" source "board/intel/minnowmax/Kconfig" diff --git a/board/intel/bayleybay/Kconfig b/board/intel/bayleybay/Kconfig new file mode 100644 index 00000000000..597228fdbca --- /dev/null +++ b/board/intel/bayleybay/Kconfig @@ -0,0 +1,27 @@ +if TARGET_BAYLEYBAY + +config SYS_BOARD + default "bayleybay" + +config SYS_VENDOR + default "intel" + +config SYS_SOC + default "baytrail" + +config SYS_CONFIG_NAME + default "bayleybay" + +config SYS_TEXT_BASE + default 0xfff00000 + +config BOARD_SPECIFIC_OPTIONS # dummy + def_bool y + select X86_RESET_VECTOR + select INTEL_BAYTRAIL + select BOARD_ROMSIZE_KB_8192 + +config PCIE_ECAM_BASE + default 0xe0000000 + +endif diff --git a/board/intel/bayleybay/MAINTAINERS b/board/intel/bayleybay/MAINTAINERS new file mode 100644 index 00000000000..85fa51626af --- /dev/null +++ b/board/intel/bayleybay/MAINTAINERS @@ -0,0 +1,6 @@ +Intel Bayley Bay +M: Bin Meng +S: Maintained +F: board/intel/bayleybay +F: include/configs/bayleybay.h +F: configs/bayleybay_defconfig diff --git a/board/intel/bayleybay/Makefile b/board/intel/bayleybay/Makefile new file mode 100644 index 00000000000..88b5aad6345 --- /dev/null +++ b/board/intel/bayleybay/Makefile @@ -0,0 +1,7 @@ +# +# Copyright (C) 2015, Bin Meng +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y += bayleybay.o start.o diff --git a/board/intel/bayleybay/bayleybay.c b/board/intel/bayleybay/bayleybay.c new file mode 100644 index 00000000000..78447965b92 --- /dev/null +++ b/board/intel/bayleybay/bayleybay.c @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2015, Bin Meng + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +void setup_pch_gpios(u16 gpiobase, const struct pch_gpio_map *gpio) +{ + return; +} + +int board_eth_init(bd_t *bis) +{ + return pci_eth_init(bis); +} diff --git a/board/intel/bayleybay/start.S b/board/intel/bayleybay/start.S new file mode 100644 index 00000000000..a71db69be9c --- /dev/null +++ b/board/intel/bayleybay/start.S @@ -0,0 +1,9 @@ +/* + * Copyright (C) 2015, Bin Meng + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +.globl early_board_init +early_board_init: + jmp early_board_init_ret diff --git a/configs/bayleybay_defconfig b/configs/bayleybay_defconfig new file mode 100644 index 00000000000..e10e86a4c11 --- /dev/null +++ b/configs/bayleybay_defconfig @@ -0,0 +1,25 @@ +CONFIG_X86=y +CONFIG_VENDOR_INTEL=y +CONFIG_DEFAULT_DEVICE_TREE="bayleybay" +CONFIG_TARGET_BAYLEYBAY=y +CONFIG_HAVE_INTEL_ME=y +CONFIG_SMP=y +CONFIG_HAVE_VGA_BIOS=y +CONFIG_CMD_CPU=y +# CONFIG_CMD_IMLS is not set +# CONFIG_CMD_FLASH is not set +# CONFIG_CMD_SETEXPR is not set +# CONFIG_CMD_NFS is not set +CONFIG_BOOTSTAGE=y +CONFIG_BOOTSTAGE_REPORT=y +CONFIG_CMD_BOOTSTAGE=y +CONFIG_OF_CONTROL=y +CONFIG_CPU=y +CONFIG_DM_PCI=y +CONFIG_SPI_FLASH=y +CONFIG_VIDEO_VESA=y +CONFIG_FRAMEBUFFER_SET_VESA_MODE=y +CONFIG_FRAMEBUFFER_VESA_MODE_11A=y +CONFIG_DM_RTC=y +CONFIG_USE_PRIVATE_LIBGCC=y +CONFIG_SYS_VSNPRINTF=y diff --git a/include/configs/bayleybay.h b/include/configs/bayleybay.h new file mode 100644 index 00000000000..cc95aec458e --- /dev/null +++ b/include/configs/bayleybay.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2015, Bin Meng + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * board/config.h - configuration options, board specific + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#include + +#define CONFIG_SYS_MONITOR_LEN (1 << 20) + +#define CONFIG_X86_SERIAL + +#define CONFIG_PCI_CONFIG_HOST_BRIDGE +#define CONFIG_SYS_EARLY_PCI_INIT +#define CONFIG_PCI_PNP +#define CONFIG_E1000 + +#define CONFIG_STD_DEVICES_SETTINGS "stdin=serial,vga,usbkbd\0" \ + "stdout=serial,vga\0" \ + "stderr=serial,vga\0" + +#define CONFIG_SCSI_DEV_LIST \ + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VALLEYVIEW_SATA} + +#define CONFIG_MMC +#define CONFIG_SDHCI +#define CONFIG_GENERIC_MMC +#define CONFIG_MMC_SDMA +#define CONFIG_CMD_MMC + +/* BayTrail IGD support */ +#define CONFIG_VGA_AS_SINGLE_DEVICE + +/* Environment configuration */ +#define CONFIG_ENV_SECT_SIZE 0x1000 +#define CONFIG_ENV_OFFSET 0x006ff000 + +#endif /* __CONFIG_H */ -- cgit v1.3.1 From fe3fbd302427b3690c4d682c1d7d03ca94771afd Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 30 Jul 2015 03:49:18 -0700 Subject: x86: bayleybay: Configure PCI IRQ Add PCI IRQ routing information in the board device tree and enable writing PIRQ routing table and MP table. Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/cpu/baytrail/valleyview.c | 8 +++++ arch/x86/dts/bayleybay.dts | 63 ++++++++++++++++++++++++++++++++++++++ configs/bayleybay_defconfig | 2 ++ include/configs/bayleybay.h | 1 + 4 files changed, 74 insertions(+) (limited to 'include') diff --git a/arch/x86/cpu/baytrail/valleyview.c b/arch/x86/cpu/baytrail/valleyview.c index 9915da5bd7d..d8d2b8d418b 100644 --- a/arch/x86/cpu/baytrail/valleyview.c +++ b/arch/x86/cpu/baytrail/valleyview.c @@ -7,6 +7,7 @@ #include #include #include +#include #include static struct pci_device_id mmc_supported[] = { @@ -35,3 +36,10 @@ int arch_cpu_init(void) return 0; } + +int arch_misc_init(void) +{ + pirq_init(); + + return 0; +} diff --git a/arch/x86/dts/bayleybay.dts b/arch/x86/dts/bayleybay.dts index cbbdee27305..9f8fa70f967 100644 --- a/arch/x86/dts/bayleybay.dts +++ b/arch/x86/dts/bayleybay.dts @@ -7,6 +7,7 @@ /dts-v1/; #include +#include /include/ "skeleton.dtsi" /include/ "serial.dtsi" @@ -123,6 +124,68 @@ ranges = <0x02000000 0x0 0x80000000 0x80000000 0 0x40000000 0x42000000 0x0 0xc0000000 0xc0000000 0 0x20000000 0x01000000 0x0 0x2000 0x2000 0 0xe000>; + + irq-router@1f,0 { + reg = <0x0000f800 0 0 0 0>; + compatible = "intel,irq-router"; + intel,pirq-config = "ibase"; + intel,ibase-offset = <0x50>; + intel,pirq-link = <8 8>; + intel,pirq-mask = <0xdee0>; + intel,pirq-routing = < + /* BayTrail PCI devices */ + PCI_BDF(0, 2, 0) INTA PIRQA + PCI_BDF(0, 3, 0) INTA PIRQA + PCI_BDF(0, 16, 0) INTA PIRQA + PCI_BDF(0, 17, 0) INTA PIRQA + PCI_BDF(0, 18, 0) INTA PIRQA + PCI_BDF(0, 19, 0) INTA PIRQA + PCI_BDF(0, 20, 0) INTA PIRQA + PCI_BDF(0, 21, 0) INTA PIRQA + PCI_BDF(0, 22, 0) INTA PIRQA + PCI_BDF(0, 23, 0) INTA PIRQA + PCI_BDF(0, 24, 0) INTA PIRQA + PCI_BDF(0, 24, 1) INTC PIRQC + PCI_BDF(0, 24, 2) INTD PIRQD + PCI_BDF(0, 24, 3) INTB PIRQB + PCI_BDF(0, 24, 4) INTA PIRQA + PCI_BDF(0, 24, 5) INTC PIRQC + PCI_BDF(0, 24, 6) INTD PIRQD + PCI_BDF(0, 24, 7) INTB PIRQB + PCI_BDF(0, 26, 0) INTA PIRQA + PCI_BDF(0, 27, 0) INTA PIRQA + PCI_BDF(0, 28, 0) INTA PIRQA + PCI_BDF(0, 28, 1) INTB PIRQB + PCI_BDF(0, 28, 2) INTC PIRQC + PCI_BDF(0, 28, 3) INTD PIRQD + PCI_BDF(0, 29, 0) INTA PIRQA + PCI_BDF(0, 30, 0) INTA PIRQA + PCI_BDF(0, 30, 1) INTD PIRQD + PCI_BDF(0, 30, 2) INTB PIRQB + PCI_BDF(0, 30, 3) INTC PIRQC + PCI_BDF(0, 30, 4) INTD PIRQD + PCI_BDF(0, 30, 5) INTB PIRQB + PCI_BDF(0, 31, 3) INTB PIRQB + + /* PCIe root ports downstream interrupts */ + PCI_BDF(1, 0, 0) INTA PIRQA + PCI_BDF(1, 0, 0) INTB PIRQB + PCI_BDF(1, 0, 0) INTC PIRQC + PCI_BDF(1, 0, 0) INTD PIRQD + PCI_BDF(2, 0, 0) INTA PIRQB + PCI_BDF(2, 0, 0) INTB PIRQC + PCI_BDF(2, 0, 0) INTC PIRQD + PCI_BDF(2, 0, 0) INTD PIRQA + PCI_BDF(3, 0, 0) INTA PIRQC + PCI_BDF(3, 0, 0) INTB PIRQD + PCI_BDF(3, 0, 0) INTC PIRQA + PCI_BDF(3, 0, 0) INTD PIRQB + PCI_BDF(4, 0, 0) INTA PIRQD + PCI_BDF(4, 0, 0) INTB PIRQA + PCI_BDF(4, 0, 0) INTC PIRQB + PCI_BDF(4, 0, 0) INTD PIRQC + >; + }; }; microcode { diff --git a/configs/bayleybay_defconfig b/configs/bayleybay_defconfig index e10e86a4c11..7f92ead9a61 100644 --- a/configs/bayleybay_defconfig +++ b/configs/bayleybay_defconfig @@ -5,6 +5,8 @@ CONFIG_TARGET_BAYLEYBAY=y CONFIG_HAVE_INTEL_ME=y CONFIG_SMP=y CONFIG_HAVE_VGA_BIOS=y +CONFIG_GENERATE_PIRQ_TABLE=y +CONFIG_GENERATE_MP_TABLE=y CONFIG_CMD_CPU=y # CONFIG_CMD_IMLS is not set # CONFIG_CMD_FLASH is not set diff --git a/include/configs/bayleybay.h b/include/configs/bayleybay.h index cc95aec458e..740166afd37 100644 --- a/include/configs/bayleybay.h +++ b/include/configs/bayleybay.h @@ -14,6 +14,7 @@ #include #define CONFIG_SYS_MONITOR_LEN (1 << 20) +#define CONFIG_ARCH_MISC_INIT #define CONFIG_X86_SERIAL -- cgit v1.3.1 From 5efa28139cac60683387415df479f6413988aa65 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 31 Jul 2015 09:31:21 -0600 Subject: elf: Add a few definitions for 64-bit relocation Provide the types necessary to relocate 64-bit images. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- include/elf.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'include') diff --git a/include/elf.h b/include/elf.h index 63d93416a3e..a35e085d82a 100644 --- a/include/elf.h +++ b/include/elf.h @@ -28,6 +28,16 @@ typedef int32_t Elf32_Sword; /* Signed large integer */ typedef uint32_t Elf32_Word; /* Unsigned large integer */ typedef uint16_t Elf32_Half; /* Unsigned medium integer */ +/* 64-bit ELF base types. */ +typedef uint64_t Elf64_Addr; +typedef uint16_t Elf64_Half; +typedef int16_t Elf64_SHalf; +typedef uint64_t Elf64_Off; +typedef int32_t Elf64_Sword; +typedef uint32_t Elf64_Word; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; + /* e_ident[] identification indexes */ #define EI_MAG0 0 /* file ID */ #define EI_MAG1 1 /* file ID */ @@ -379,6 +389,11 @@ typedef struct Elf32_Sword r_addend; } Elf32_Rela; +typedef struct { + Elf64_Addr r_offset; /* Location at which to apply the action */ + Elf64_Xword r_info; /* index and type of relocation */ +} Elf64_Rel; + /* Extract relocation info - r_info */ #define ELF32_R_SYM(i) ((i) >> 8) #define ELF32_R_TYPE(i) ((unsigned char) (i)) @@ -431,6 +446,17 @@ typedef struct extern Elf32_Dyn _DYNAMIC[]; +typedef struct { + Elf64_Sxword d_tag; /* entry tag value */ + union { + Elf64_Xword d_val; + Elf64_Addr d_ptr; + } d_un; +} Elf64_Dyn; + +#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((i) & 0xffffffff) + /* Dynamic Array Tags - d_tag */ #define DT_NULL 0 /* marks end of _DYNAMIC array */ #define DT_NEEDED 1 /* string table offset of needed lib */ -- cgit v1.3.1 From 5598facbd24c762d1143ace2fe1005595623e88f Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 31 Jul 2015 09:31:24 -0600 Subject: Bring in __aligned_u64 and friends to linux/types.h These will be used for efi.h both for U-Boot running as an EFI application and as a payload. They come from Linux 4.1. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- include/linux/types.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/types.h b/include/linux/types.h index c9a8d9a8c2c..6f75be42537 100644 --- a/include/linux/types.h +++ b/include/linux/types.h @@ -113,6 +113,11 @@ typedef __s64 int64_t; #endif /* __KERNEL_STRICT_NAMES */ +/* this is a special 64bit data type that is 8-byte aligned */ +#define aligned_u64 __u64 __aligned(8) +#define aligned_be64 __be64 __aligned(8) +#define aligned_le64 __le64 __aligned(8) + #if defined(CONFIG_USE_STDINT) && defined(__INT64_TYPE__) typedef __UINT64_TYPE__ uint64_t; typedef __UINT64_TYPE__ u_int64_t; @@ -145,7 +150,6 @@ typedef __u64 __bitwise __be64; typedef __u16 __bitwise __sum16; typedef __u32 __bitwise __wsum; - typedef unsigned __bitwise__ gfp_t; struct ustat { -- cgit v1.3.1 From b0b403d954081520ba82fef24dee6486ffebe017 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 31 Jul 2015 09:31:27 -0600 Subject: Reserve the top 16 flag bits for architecture-specific use Add a convention that the generic global_data only occupy the bottom 16 bits of the flags word, so that there is less chance of a conflict. At present the x86 flags conflict. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- include/asm-generic/global_data.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index 7ef3e259b46..9f5db0f5afb 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -104,7 +104,7 @@ typedef struct global_data { #endif /* - * Global Data Flags + * Global Data Flags - the top 16 bits are reserved for arch-specific flags */ #define GD_FLG_RELOC 0x00001 /* Code was relocated to RAM */ #define GD_FLG_DEVINIT 0x00002 /* Devices have been initialized */ -- cgit v1.3.1 From 867a6ac86dd823de409752e9ca5dc8f4d4880f26 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 31 Jul 2015 09:31:36 -0600 Subject: efi: Add start-up library code When running as an EFI application, U-Boot must request memory from EFI, and provide access to the boot services U-Boot needs. Add library code to perform these tasks. This includes efi_main() which is the entry point from EFI. U-Boot is built as a shared library. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/include/asm/fsp/fsp_hob.h | 59 +----- include/efi.h | 356 +++++++++++++++++++++++++++++++++++++ include/efi_api.h | 244 +++++++++++++++++++++++++ include/part_efi.h | 9 +- lib/Kconfig | 2 + lib/Makefile | 1 + lib/efi/Kconfig | 33 ++++ lib/efi/Makefile | 7 + lib/efi/efi.c | 101 +++++++++++ lib/efi/efi_app.c | 139 +++++++++++++++ 10 files changed, 887 insertions(+), 64 deletions(-) create mode 100644 include/efi.h create mode 100644 include/efi_api.h create mode 100644 lib/efi/Kconfig create mode 100644 lib/efi/Makefile create mode 100644 lib/efi/efi.c create mode 100644 lib/efi/efi_app.c (limited to 'include') diff --git a/arch/x86/include/asm/fsp/fsp_hob.h b/arch/x86/include/asm/fsp/fsp_hob.h index 6cca7f56541..3fb3546e27f 100644 --- a/arch/x86/include/asm/fsp/fsp_hob.h +++ b/arch/x86/include/asm/fsp/fsp_hob.h @@ -8,6 +8,8 @@ #ifndef __FSP_HOB_H__ #define __FSP_HOB_H__ +#include + /* Type of HOB Header */ #define HOB_TYPE_MEM_ALLOC 0x0002 #define HOB_TYPE_RES_DESC 0x0003 @@ -25,63 +27,6 @@ struct hob_header { u32 reserved; /* always zero */ }; -/* Enumeration of memory types introduced in UEFI */ -enum efi_mem_type { - EFI_RESERVED_MEMORY_TYPE, - /* - * The code portions of a loaded application. - * (Note that UEFI OS loaders are UEFI applications.) - */ - EFI_LOADER_CODE, - /* - * The data portions of a loaded application and - * the default data allocation type used by an application - * to allocate pool memory. - */ - EFI_LOADER_DATA, - /* The code portions of a loaded Boot Services Driver */ - EFI_BOOT_SERVICES_CODE, - /* - * The data portions of a loaded Boot Serves Driver and - * the default data allocation type used by a Boot Services - * Driver to allocate pool memory. - */ - EFI_BOOT_SERVICES_DATA, - /* The code portions of a loaded Runtime Services Driver */ - EFI_RUNTIME_SERVICES_CODE, - /* - * The data portions of a loaded Runtime Services Driver and - * the default data allocation type used by a Runtime Services - * Driver to allocate pool memory. - */ - EFI_RUNTIME_SERVICES_DATA, - /* Free (unallocated) memory */ - EFI_CONVENTIONAL_MEMORY, - /* Memory in which errors have been detected */ - EFI_UNUSABLE_MEMORY, - /* Memory that holds the ACPI tables */ - EFI_ACPI_RECLAIM_MEMORY, - /* Address space reserved for use by the firmware */ - EFI_ACPI_MEMORY_NVS, - /* - * Used by system firmware to request that a memory-mapped IO region - * be mapped by the OS to a virtual address so it can be accessed by - * EFI runtime services. - */ - EFI_MMAP_IO, - /* - * System memory-mapped IO region that is used to translate - * memory cycles to IO cycles by the processor. - */ - EFI_MMAP_IO_PORT, - /* - * Address space reserved by the firmware for code that is - * part of the processor. - */ - EFI_PAL_CODE, - EFI_MAX_MEMORY_TYPE -}; - /* * Describes all memory ranges used during the HOB producer phase that * exist outside the HOB list. This HOB type describes how memory is used, diff --git a/include/efi.h b/include/efi.h new file mode 100644 index 00000000000..f0097017b3c --- /dev/null +++ b/include/efi.h @@ -0,0 +1,356 @@ +/* + * Extensible Firmware Interface + * Based on 'Extensible Firmware Interface Specification' version 0.9, + * April 30, 1999 + * + * Copyright (C) 1999 VA Linux Systems + * Copyright (C) 1999 Walt Drummond + * Copyright (C) 1999, 2002-2003 Hewlett-Packard Co. + * David Mosberger-Tang + * Stephane Eranian + * + * From include/linux/efi.h in kernel 4.1 with some additions/subtractions + */ + +#ifndef _EFI_H +#define _EFI_H + +#include +#include + +struct efi_device_path; + +#define EFI_SUCCESS 0 +#define EFI_LOAD_ERROR (1 | (1UL << (BITS_PER_LONG - 1))) +#define EFI_INVALID_PARAMETER (2 | (1UL << (BITS_PER_LONG - 1))) +#define EFI_UNSUPPORTED (3 | (1UL << (BITS_PER_LONG - 1))) +#define EFI_BAD_BUFFER_SIZE (4 | (1UL << (BITS_PER_LONG - 1))) +#define EFI_BUFFER_TOO_SMALL (5 | (1UL << (BITS_PER_LONG - 1))) +#define EFI_NOT_READY (6 | (1UL << (BITS_PER_LONG - 1))) +#define EFI_DEVICE_ERROR (7 | (1UL << (BITS_PER_LONG - 1))) +#define EFI_WRITE_PROTECTED (8 | (1UL << (BITS_PER_LONG - 1))) +#define EFI_OUT_OF_RESOURCES (9 | (1UL << (BITS_PER_LONG - 1))) +#define EFI_NOT_FOUND (14 | (1UL << (BITS_PER_LONG - 1))) +#define EFI_SECURITY_VIOLATION (26 | (1UL << (BITS_PER_LONG - 1))) + +typedef unsigned long efi_status_t; +typedef u64 efi_physical_addr_t; +typedef u64 efi_virtual_addr_t; +typedef void *efi_handle_t; + +#define EFI_GUID(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \ + ((efi_guid_t) \ + {{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, \ + ((a) >> 24) & 0xff, \ + (b) & 0xff, ((b) >> 8) & 0xff, \ + (c) & 0xff, ((c) >> 8) & 0xff, \ + (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) } }) + +/* Generic EFI table header */ +struct efi_table_hdr { + u64 signature; + u32 revision; + u32 headersize; + u32 crc32; + u32 reserved; +}; + +/* Enumeration of memory types introduced in UEFI */ +enum efi_mem_type { + EFI_RESERVED_MEMORY_TYPE, + /* + * The code portions of a loaded application. + * (Note that UEFI OS loaders are UEFI applications.) + */ + EFI_LOADER_CODE, + /* + * The data portions of a loaded application and + * the default data allocation type used by an application + * to allocate pool memory. + */ + EFI_LOADER_DATA, + /* The code portions of a loaded Boot Services Driver */ + EFI_BOOT_SERVICES_CODE, + /* + * The data portions of a loaded Boot Serves Driver and + * the default data allocation type used by a Boot Services + * Driver to allocate pool memory. + */ + EFI_BOOT_SERVICES_DATA, + /* The code portions of a loaded Runtime Services Driver */ + EFI_RUNTIME_SERVICES_CODE, + /* + * The data portions of a loaded Runtime Services Driver and + * the default data allocation type used by a Runtime Services + * Driver to allocate pool memory. + */ + EFI_RUNTIME_SERVICES_DATA, + /* Free (unallocated) memory */ + EFI_CONVENTIONAL_MEMORY, + /* Memory in which errors have been detected */ + EFI_UNUSABLE_MEMORY, + /* Memory that holds the ACPI tables */ + EFI_ACPI_RECLAIM_MEMORY, + /* Address space reserved for use by the firmware */ + EFI_ACPI_MEMORY_NVS, + /* + * Used by system firmware to request that a memory-mapped IO region + * be mapped by the OS to a virtual address so it can be accessed by + * EFI runtime services. + */ + EFI_MMAP_IO, + /* + * System memory-mapped IO region that is used to translate + * memory cycles to IO cycles by the processor. + */ + EFI_MMAP_IO_PORT, + /* + * Address space reserved by the firmware for code that is + * part of the processor. + */ + EFI_PAL_CODE, + + EFI_MAX_MEMORY_TYPE, + EFI_TABLE_END, /* For efi_build_mem_table() */ +}; + +/* Attribute values */ +enum { + EFI_MEMORY_UC_SHIFT = 0, /* uncached */ + EFI_MEMORY_WC_SHIFT = 1, /* write-coalescing */ + EFI_MEMORY_WT_SHIFT = 2, /* write-through */ + EFI_MEMORY_WB_SHIFT = 3, /* write-back */ + EFI_MEMORY_UCE_SHIFT = 4, /* uncached, exported */ + EFI_MEMORY_WP_SHIFT = 12, /* write-protect */ + EFI_MEMORY_RP_SHIFT = 13, /* read-protect */ + EFI_MEMORY_XP_SHIFT = 14, /* execute-protect */ + EFI_MEMORY_RUNTIME_SHIFT = 63, /* range requires runtime mapping */ + + EFI_MEMORY_RUNTIME = 1ULL << EFI_MEMORY_RUNTIME_SHIFT, + EFI_MEM_DESC_VERSION = 1, +}; + +#define EFI_PAGE_SHIFT 12 +#define EFI_PAGE_SIZE (1UL << EFI_PAGE_SHIFT) + +struct efi_mem_desc { + u32 type; + u32 reserved; + efi_physical_addr_t physical_start; + efi_virtual_addr_t virtual_start; + u64 num_pages; + u64 attribute; +}; + +/* Allocation types for calls to boottime->allocate_pages*/ +#define EFI_ALLOCATE_ANY_PAGES 0 +#define EFI_ALLOCATE_MAX_ADDRESS 1 +#define EFI_ALLOCATE_ADDRESS 2 +#define EFI_MAX_ALLOCATE_TYPE 3 + +/* Types and defines for Time Services */ +#define EFI_TIME_ADJUST_DAYLIGHT 0x1 +#define EFI_TIME_IN_DAYLIGHT 0x2 +#define EFI_UNSPECIFIED_TIMEZONE 0x07ff + +struct efi_time { + u16 year; + u8 month; + u8 day; + u8 hour; + u8 minute; + u8 second; + u8 pad1; + u32 nanosecond; + s16 timezone; + u8 daylight; + u8 pad2; +}; + +struct efi_time_cap { + u32 resolution; + u32 accuracy; + u8 sets_to_zero; +}; + +enum efi_locate_search_type { + all_handles, + by_register_notify, + by_protocol +}; + +struct efi_open_protocol_info_entry { + efi_handle_t agent_handle; + efi_handle_t controller_handle; + u32 attributes; + u32 open_count; +}; + +enum efi_entry_t { + EFIET_END, /* Signals this is the last (empty) entry */ + EFIET_MEMORY_MAP, + + /* Number of entries */ + EFIET_MEMORY_COUNT, +}; + +#define EFI_TABLE_VERSION 1 + +/** + * struct efi_info_hdr - Header for the EFI info table + * + * @version: EFI_TABLE_VERSION + * @hdr_size: Size of this struct in bytes + * @total_size: Total size of this header plus following data + * @spare: Spare space for expansion + */ +struct efi_info_hdr { + u32 version; + u32 hdr_size; + u32 total_size; + u32 spare[5]; +}; + +/** + * struct efi_entry_hdr - Header for a table entry + * + * @type: enum eft_entry_t + * @size size of entry bytes excluding header and padding + * @addr: address of this entry (0 if it follows the header ) + * @link: size of entry including header and padding + * @spare1: Spare space for expansion + * @spare2: Spare space for expansion + */ +struct efi_entry_hdr { + u32 type; + u32 size; + u64 addr; + u32 link; + u32 spare1; + u64 spare2; +}; + +/** + * struct efi_entry_memmap - a memory map table passed to U-Boot + * + * @version: EFI's memory map table version + * @desc_size: EFI's size of each memory descriptor + * @spare: Spare space for expansion + * @desc: An array of descriptors, each @desc_size bytes apart + */ +struct efi_entry_memmap { + u32 version; + u32 desc_size; + u64 spare; + struct efi_mem_desc desc[]; +}; + +static inline struct efi_mem_desc *efi_get_next_mem_desc( + struct efi_entry_memmap *map, struct efi_mem_desc *desc) +{ + return (struct efi_mem_desc *)((ulong)desc + map->desc_size); +} + +struct efi_priv { + efi_handle_t parent_image; + struct efi_device_path *device_path; + struct efi_system_table *sys_table; + struct efi_boot_services *boot; + struct efi_runtime_services *run; + bool use_pool_for_malloc; + unsigned long ram_base; + unsigned int image_data_type; + struct efi_info_hdr *info; + unsigned int info_size; + void *next_hdr; +}; + +/* Base address of the EFI image */ +extern char image_base[]; + +/** + * efi_get_sys_table() - Get access to the main EFI system table + * + * @return pointer to EFI system table + */ +struct efi_system_table *efi_get_sys_table(void); + +/** + * efi_get_ram_base() - Find the base of RAM + * + * This is used when U-Boot is built as an EFI application. + * + * @return the base of RAM as known to U-Boot + */ +unsigned long efi_get_ram_base(void); + +/** + * efi_init() - Set up ready for use of EFI boot services + * + * @priv: Pointer to our private EFI structure to fill in + * @banner: Banner to display when starting + * @image: The image handle passed to efi_main() + * @sys_table: The EFI system table pointer passed to efi_main() + */ +int efi_init(struct efi_priv *priv, const char *banner, efi_handle_t image, + struct efi_system_table *sys_table); + +/** + * efi_malloc() - Allocate some memory from EFI + * + * @priv: Pointer to private EFI structure + * @size: Number of bytes to allocate + * @retp: Return EFI status result + * @return pointer to memory allocated, or NULL on error + */ +void *efi_malloc(struct efi_priv *priv, int size, efi_status_t *retp); + +/** + * efi_free() - Free memory allocated from EFI + * + * @priv: Pointer to private EFI structure + * @ptr: Pointer to memory to free + */ +void efi_free(struct efi_priv *priv, void *ptr); + +/** + * efi_puts() - Write out a string to the EFI console + * + * @priv: Pointer to private EFI structure + * @str: String to write (note this is a ASCII, not unicode) + */ +void efi_puts(struct efi_priv *priv, const char *str); + +/** + * efi_putc() - Write out a character to the EFI console + * + * @priv: Pointer to private EFI structure + * @ch: Character to write (note this is not unicode) + */ +void efi_putc(struct efi_priv *priv, const char ch); + +/** + * efi_info_get() - get an entry from an EFI table + * + * @type: Entry type to search for + * @datap: Returns pointer to entry data + * @sizep: Returns pointer to entry size + * @return 0 if OK, -ENODATA if there is no table, -ENOENT if there is no entry + * of the requested type, -EPROTONOSUPPORT if the table has the wrong version + */ +int efi_info_get(enum efi_entry_t type, void **datap, int *sizep); + +/** + * efi_build_mem_table() - make a sorted copy of the memory table + * + * @map: Pointer to EFI memory map table + * @size: Size of table in bytes + * @skip_bs: True to skip boot-time memory and merge it with conventional + * memory. This will significantly reduce the number of table + * entries. + * @return pointer to the new table. It should be freed with free() by the + * caller + */ +void *efi_build_mem_table(struct efi_entry_memmap *map, int size, bool skip_bs); + +#endif /* _LINUX_EFI_H */ diff --git a/include/efi_api.h b/include/efi_api.h new file mode 100644 index 00000000000..4fd17d6b687 --- /dev/null +++ b/include/efi_api.h @@ -0,0 +1,244 @@ +/* + * Extensible Firmware Interface + * Based on 'Extensible Firmware Interface Specification' version 0.9, + * April 30, 1999 + * + * Copyright (C) 1999 VA Linux Systems + * Copyright (C) 1999 Walt Drummond + * Copyright (C) 1999, 2002-2003 Hewlett-Packard Co. + * David Mosberger-Tang + * Stephane Eranian + * + * From include/linux/efi.h in kernel 4.1 with some additions/subtractions + */ + +#ifndef _EFI_API_H +#define _EFI_API_H + +#include + +/* EFI Boot Services table */ +struct efi_boot_services { + struct efi_table_hdr hdr; + void *raise_tpl; + void *restore_tpl; + + efi_status_t (EFIAPI *allocate_pages)(int, int, unsigned long, + efi_physical_addr_t *); + efi_status_t (EFIAPI *free_pages)(efi_physical_addr_t, unsigned long); + efi_status_t (EFIAPI *get_memory_map)(unsigned long *memory_map_size, + struct efi_mem_desc *desc, unsigned long *key, + unsigned long *desc_size, u32 *desc_version); + efi_status_t (EFIAPI *allocate_pool)(int, unsigned long, void **); + efi_status_t (EFIAPI *free_pool)(void *); + + void *create_event; + void *set_timer; + efi_status_t(EFIAPI *wait_for_event)(unsigned long number_of_events, + void *event, unsigned long *index); + void *signal_event; + void *close_event; + void *check_event; + + void *install_protocol_interface; + void *reinstall_protocol_interface; + void *uninstall_protocol_interface; + efi_status_t (EFIAPI *handle_protocol)(efi_handle_t, efi_guid_t *, + void **); + void *reserved; + void *register_protocol_notify; + efi_status_t (EFIAPI *locate_handle)( + enum efi_locate_search_type search_type, + efi_guid_t *protocol, void *search_key, + unsigned long *buffer_size, efi_handle_t *buffer); + efi_status_t (EFIAPI *locate_device_path)(efi_guid_t *protocol, + struct efi_device_path **device_path, + efi_handle_t *device); + void *install_configuration_table; + + efi_status_t (EFIAPI *load_image)(bool boot_policiy, + efi_handle_t parent_image, + struct efi_device_path *file_path, void *source_buffer, + unsigned long source_size, efi_handle_t *image); + efi_status_t (EFIAPI *start_image)(efi_handle_t handle, + unsigned long *exitdata_size, + s16 **exitdata); + efi_status_t (EFIAPI *exit)(efi_handle_t handle, + efi_status_t exit_status, + unsigned long exitdata_size, s16 *exitdata); + void *unload_image; + efi_status_t (EFIAPI *exit_boot_services)(efi_handle_t, unsigned long); + + efi_status_t (EFIAPI *get_next_monotonic_count)(u64 *count); + efi_status_t (EFIAPI *stall)(unsigned long usecs); + void *set_watchdog_timer; + efi_status_t(EFIAPI *connect_controller)(efi_handle_t controller_handle, + efi_handle_t *driver_image_handle, + struct efi_device_path *remaining_device_path, + bool recursive); + void *disconnect_controller; +#define EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL 0x00000001 +#define EFI_OPEN_PROTOCOL_GET_PROTOCOL 0x00000002 +#define EFI_OPEN_PROTOCOL_TEST_PROTOCOL 0x00000004 +#define EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 0x00000008 +#define EFI_OPEN_PROTOCOL_BY_DRIVER 0x00000010 +#define EFI_OPEN_PROTOCOL_EXCLUSIVE 0x00000020 + efi_status_t (EFIAPI *open_protocol)(efi_handle_t handle, + efi_guid_t *protocol, void **interface, + efi_handle_t agent_handle, + efi_handle_t controller_handle, u32 attributes); + void *close_protocol; + efi_status_t(EFIAPI *open_protocol_information)(efi_handle_t handle, + efi_guid_t *protocol, + struct efi_open_protocol_info_entry **entry_buffer, + unsigned long *entry_count); + efi_status_t (EFIAPI *protocols_per_handle)(efi_handle_t handle, + efi_guid_t ***protocol_buffer, + unsigned long *protocols_buffer_count); + efi_status_t (EFIAPI *locate_handle_buffer) ( + enum efi_locate_search_type search_type, + efi_guid_t *protocol, void *search_key, + unsigned long *no_handles, efi_handle_t **buffer); + void *locate_protocol; + void *install_multiple_protocol_interfaces; + void *uninstall_multiple_protocol_interfaces; + void *calculate_crc32; + void *copy_mem; + void *set_mem; + void *create_event_ex; +}; + +/* Types and defines for EFI ResetSystem */ +enum efi_reset_type { + EFI_RESET_COLD = 0, + EFI_RESET_WARM = 1, + EFI_RESET_SHUTDOWN = 2 +}; + +/* EFI Runtime Services table */ +#define EFI_RUNTIME_SERVICES_SIGNATURE 0x5652453544e5552ULL +#define EFI_RUNTIME_SERVICES_REVISION 0x00010000 + +struct efi_runtime_services { + struct efi_table_hdr hdr; + void *get_time; + void *set_time; + void *get_wakeup_time; + void *set_wakeup_time; + void *set_virtual_address_map; + void *convert_pointer; + efi_status_t (EFIAPI *get_variable)(s16 *variable_name, + efi_guid_t *vendor, u32 *attributes, + unsigned long *data_size, void *data); + efi_status_t (EFIAPI *get_next_variable)( + unsigned long *variable_name_size, + s16 *variable_name, efi_guid_t *vendor); + efi_status_t (EFIAPI *set_variable)(s16 *variable_name, + efi_guid_t *vendor, u32 attributes, + unsigned long data_size, void *data); + void *get_next_high_mono_count; + void (EFIAPI *reset_system)(enum efi_reset_type reset_type, + efi_status_t reset_status, + unsigned long data_size, void *reset_data); + void *update_capsule; + void *query_capsule_caps; + void *query_variable_info; +}; + +/* EFI Configuration Table and GUID definitions */ +#define NULL_GUID \ + EFI_GUID(0x00000000, 0x0000, 0x0000, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) + +#define LOADED_IMAGE_PROTOCOL_GUID \ + EFI_GUID(0x5b1b31a1, 0x9562, 0x11d2, 0x8e, 0x3f, \ + 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) + +struct efi_system_table { + struct efi_table_hdr hdr; + unsigned long fw_vendor; /* physical addr of wchar_t vendor string */ + u32 fw_revision; + unsigned long con_in_handle; + struct efi_simple_input_interface *con_in; + unsigned long con_out_handle; + struct efi_simple_text_output_protocol *con_out; + unsigned long stderr_handle; + unsigned long std_err; + struct efi_runtime_services *runtime; + struct efi_boot_services *boottime; + unsigned long nr_tables; + unsigned long tables; +}; + +struct efi_loaded_image { + u32 revision; + void *parent_handle; + struct efi_system_table *system_table; + void *device_handle; + void *file_path; + void *reserved; + u32 load_options_size; + void *load_options; + void *image_base; + aligned_u64 image_size; + unsigned int image_code_type; + unsigned int image_data_type; + unsigned long unload; +}; + +struct efi_device_path { + u8 type; + u8 sub_type; + u16 length; +}; + +struct simple_text_output_mode { + s32 max_mode; + s32 mode; + s32 attribute; + s32 cursor_column; + s32 cursor_row; + bool cursor_visible; +}; + +struct efi_simple_text_output_protocol { + void *reset; + efi_status_t (EFIAPI *output_string)( + struct efi_simple_text_output_protocol *this, + const unsigned short *str); + void *test_string; + + efi_status_t(EFIAPI *query_mode)( + struct efi_simple_text_output_protocol *this, + unsigned long mode_number, unsigned long *columns, + unsigned long *rows); + efi_status_t(EFIAPI *set_mode)( + struct efi_simple_text_output_protocol *this, + unsigned long mode_number); + efi_status_t(EFIAPI *set_attribute)( + struct efi_simple_text_output_protocol *this, + unsigned long attribute); + efi_status_t(EFIAPI *clear_screen) ( + struct efi_simple_text_output_protocol *this); + efi_status_t(EFIAPI *set_cursor_position) ( + struct efi_simple_text_output_protocol *this, + unsigned long column, unsigned long row); + efi_status_t(EFIAPI *enable_cursor)(void *, bool enable); + struct simple_text_output_mode *mode; +}; + +struct efi_input_key { + u16 scan_code; + s16 unicode_char; +}; + +struct efi_simple_input_interface { + efi_status_t(EFIAPI *reset)(struct efi_simple_input_interface *this, + bool ExtendedVerification); + efi_status_t(EFIAPI *read_key_stroke)( + struct efi_simple_input_interface *this, + struct efi_input_key *key); + void *wait_for_key; +}; + +#endif diff --git a/include/part_efi.h b/include/part_efi.h index d68ef3bb374..3012b91adee 100644 --- a/include/part_efi.h +++ b/include/part_efi.h @@ -18,6 +18,8 @@ #ifndef _DISK_PART_EFI_H #define _DISK_PART_EFI_H +#include + #define MSDOS_MBR_SIGNATURE 0xAA55 #define EFI_PMBR_OSTYPE_EFI 0xEF #define EFI_PMBR_OSTYPE_EFI_GPT 0xEE @@ -29,13 +31,6 @@ #define GPT_ENTRY_NUMBERS 128 #define GPT_ENTRY_SIZE 128 -#define EFI_GUID(a,b,c,d0,d1,d2,d3,d4,d5,d6,d7) \ - ((efi_guid_t) \ - {{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \ - (b) & 0xff, ((b) >> 8) & 0xff, \ - (c) & 0xff, ((c) >> 8) & 0xff, \ - (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }}) - #define PARTITION_SYSTEM_GUID \ EFI_GUID( 0xC12A7328, 0xF81F, 0x11d2, \ 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B) diff --git a/lib/Kconfig b/lib/Kconfig index 972ac1793da..884218a3c66 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -98,4 +98,6 @@ config ERRNO_STR - if errno is null or positive number - a pointer to "Success" message - if errno is negative - a pointer to errno related message +source lib/efi/Kconfig + endmenu diff --git a/lib/Makefile b/lib/Makefile index fd106b91c80..db7d9806df8 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -7,6 +7,7 @@ ifndef CONFIG_SPL_BUILD +obj-$(CONFIG_EFI) += efi/ obj-$(CONFIG_RSA) += rsa/ obj-$(CONFIG_LZMA) += lzma/ obj-$(CONFIG_LZO) += lzo/ diff --git a/lib/efi/Kconfig b/lib/efi/Kconfig new file mode 100644 index 00000000000..b23ba5b5041 --- /dev/null +++ b/lib/efi/Kconfig @@ -0,0 +1,33 @@ +config EFI + bool "Support running U-Boot from EFI" + depends on X86 + help + U-Boot can be started from EFI on certain platforms. This allows + EFI to perform most of the system init and then jump to U-Boot for + final system boot. Another option is to run U-Boot as an EFI + application, with U-Boot using EFI's drivers instead of its own. + +choice + prompt "Select EFI mode to use" + depends on X86 && EFI + +config EFI_APP + bool "Support running as an EFI application" + help + Build U-Boot as an application which can be started from EFI. This + is useful for examining a platform in the early stages of porting + U-Boot to it. It allows only very basic functionality, such as a + command prompt and memory and I/O functions. Use 'reset' to return + to EFI. + +config EFI_RAM_SIZE + hex "Amount of EFI RAM for U-Boot" + depends on EFI_APP + default 0x2000000 + help + Set the amount of EFI RAM which is claimed by U-Boot for its own + use. U-Boot allocates this from EFI on start-up (along with a few + other smaller amounts) and it can never be increased after that. + It is used as the RAM size in with U-Boot. + +endchoice diff --git a/lib/efi/Makefile b/lib/efi/Makefile new file mode 100644 index 00000000000..5ee344c7d6d --- /dev/null +++ b/lib/efi/Makefile @@ -0,0 +1,7 @@ +# +# (C) Copyright 2015 Google, Inc +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_EFI_APP) += efi_app.o efi.o diff --git a/lib/efi/efi.c b/lib/efi/efi.c new file mode 100644 index 00000000000..81af27caab1 --- /dev/null +++ b/lib/efi/efi.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2015 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + * + * EFI information obtained here: + * http://wiki.phoenix.com/wiki/index.php/EFI_BOOT_SERVICES + * + * Common EFI functions + */ + +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +/* + * Unfortunately we cannot access any code outside what is built especially + * for the stub. lib/string.c is already being built for the U-Boot payload + * so it uses the wrong compiler flags. Add our own memset() here. + */ +static void efi_memset(void *ptr, int ch, int size) +{ + char *dest = ptr; + + while (size-- > 0) + *dest++ = ch; +} + +/* + * Since the EFI stub cannot access most of the U-Boot code, add our own + * simple console output functions here. The EFI app will not use these since + * it can use the normal console. + */ +void efi_putc(struct efi_priv *priv, const char ch) +{ + struct efi_simple_text_output_protocol *con = priv->sys_table->con_out; + uint16_t ucode[2]; + + ucode[0] = ch; + ucode[1] = '\0'; + con->output_string(con, ucode); +} + +void efi_puts(struct efi_priv *priv, const char *str) +{ + while (*str) + efi_putc(priv, *str++); +} + +int efi_init(struct efi_priv *priv, const char *banner, efi_handle_t image, + struct efi_system_table *sys_table) +{ + efi_guid_t loaded_image_guid = LOADED_IMAGE_PROTOCOL_GUID; + struct efi_boot_services *boot = sys_table->boottime; + struct efi_loaded_image *loaded_image; + int ret; + + efi_memset(priv, '\0', sizeof(*priv)); + priv->sys_table = sys_table; + priv->boot = sys_table->boottime; + priv->parent_image = image; + priv->run = sys_table->runtime; + + efi_puts(priv, "U-Boot EFI "); + efi_puts(priv, banner); + efi_putc(priv, ' '); + + ret = boot->open_protocol(priv->parent_image, &loaded_image_guid, + (void **)&loaded_image, &priv->parent_image, + NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret) { + efi_puts(priv, "Failed to get loaded image protocol\n"); + return ret; + } + priv->image_data_type = loaded_image->image_data_type; + + return 0; +} + +void *efi_malloc(struct efi_priv *priv, int size, efi_status_t *retp) +{ + struct efi_boot_services *boot = priv->boot; + void *buf = NULL; + + *retp = boot->allocate_pool(priv->image_data_type, size, &buf); + + return buf; +} + +void efi_free(struct efi_priv *priv, void *ptr) +{ + struct efi_boot_services *boot = priv->boot; + + boot->free_pool(ptr); +} diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c new file mode 100644 index 00000000000..452ab5d6cec --- /dev/null +++ b/lib/efi/efi_app.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2015 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + * + * EFI information obtained here: + * http://wiki.phoenix.com/wiki/index.php/EFI_BOOT_SERVICES + * + * This file implements U-Boot running as an EFI application. + */ + +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +static struct efi_priv *global_priv; + +struct efi_system_table *efi_get_sys_table(void) +{ + return global_priv->sys_table; +} + +unsigned long efi_get_ram_base(void) +{ + return global_priv->ram_base; +} + +static efi_status_t setup_memory(struct efi_priv *priv) +{ + struct efi_boot_services *boot = priv->boot; + efi_physical_addr_t addr; + efi_status_t ret; + int pages; + + /* + * Use global_data_ptr instead of gd since it is an assignment. There + * are very few assignments to global_data in U-Boot and this makes + * it easier to find them. + */ + global_data_ptr = efi_malloc(priv, sizeof(struct global_data), &ret); + if (!global_data_ptr) + return ret; + memset(gd, '\0', sizeof(*gd)); + + gd->malloc_base = (ulong)efi_malloc(priv, CONFIG_SYS_MALLOC_F_LEN, + &ret); + if (!gd->malloc_base) + return ret; + pages = CONFIG_EFI_RAM_SIZE >> 12; + + /* + * Don't allocate any memory above 4GB. U-Boot is a 32-bit application + * so we want it to load below 4GB. + */ + addr = 1ULL << 32; + ret = boot->allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, + priv->image_data_type, pages, &addr); + if (ret) { + printf("(using pool %lx) ", ret); + priv->ram_base = (ulong)efi_malloc(priv, CONFIG_EFI_RAM_SIZE, + &ret); + if (!priv->ram_base) + return ret; + priv->use_pool_for_malloc = true; + } else { + priv->ram_base = addr; + } + gd->ram_size = pages << 12; + + return 0; +} + +static void free_memory(struct efi_priv *priv) +{ + struct efi_boot_services *boot = priv->boot; + + if (priv->use_pool_for_malloc) + efi_free(priv, (void *)priv->ram_base); + else + boot->free_pages(priv->ram_base, gd->ram_size >> 12); + + efi_free(priv, (void *)gd->malloc_base); + efi_free(priv, gd); + global_data_ptr = NULL; +} + +/** + * efi_main() - Start an EFI image + * + * This function is called by our EFI start-up code. It handles running + * U-Boot. If it returns, EFI will continue. Another way to get back to EFI + * is via reset_cpu(). + */ +efi_status_t efi_main(efi_handle_t image, struct efi_system_table *sys_table) +{ + struct efi_priv local_priv, *priv = &local_priv; + efi_status_t ret; + + /* Set up access to EFI data structures */ + efi_init(priv, "App", image, sys_table); + + global_priv = priv; + + /* + * Set up the EFI debug UART so that printf() works. This is + * implemented in the EFI serial driver, serial_efi.c. The application + * can use printf() freely. + */ + debug_uart_init(); + + ret = setup_memory(priv); + if (ret) { + printf("Failed to set up memory: ret=%lx\n", ret); + return ret; + } + + printf("starting\n"); + + board_init_f(GD_FLG_SKIP_RELOC); + board_init_r(NULL, 0); + free_memory(priv); + + return EFI_SUCCESS; +} + +void reset_cpu(ulong addr) +{ + struct efi_priv *priv = global_priv; + + free_memory(priv); + printf("U-Boot EFI exiting\n"); + priv->boot->exit(priv->parent_image, EFI_SUCCESS, 0, NULL); +} -- cgit v1.3.1 From 5f48d798eb151f50d79b93913b59190a679ee9b5 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 27 Jul 2015 15:47:17 -0600 Subject: pci: Add a constant for an invalid interrupt Rather than using 0xff in the code, add a constant. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- drivers/pci/pci.c | 3 ++- include/pci.h | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index df50b480035..645ecd423f8 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -269,7 +269,8 @@ int pci_hose_config_device(struct pci_controller *hose, /* Disable interrupt line, if device says it wants to use interrupts */ pci_hose_read_config_byte(hose, dev, PCI_INTERRUPT_PIN, &pin); if (pin != 0) { - pci_hose_write_config_byte(hose, dev, PCI_INTERRUPT_LINE, 0xff); + pci_hose_write_config_byte(hose, dev, PCI_INTERRUPT_LINE, + PCI_INTERRUPT_LINE_DISABLE); } pci_hose_read_config_dword(hose, dev, PCI_COMMAND, &old_command); diff --git a/include/pci.h b/include/pci.h index dce159f2776..628ede0957b 100644 --- a/include/pci.h +++ b/include/pci.h @@ -231,6 +231,8 @@ #define PCI_MIN_GNT 0x3e /* 8 bits */ #define PCI_MAX_LAT 0x3f /* 8 bits */ +#define PCI_INTERRUPT_LINE_DISABLE 0xff + /* Header type 1 (PCI-to-PCI bridges) */ #define PCI_PRIMARY_BUS 0x18 /* Primary bus number */ #define PCI_SECONDARY_BUS 0x19 /* Secondary bus number */ -- cgit v1.3.1 From 3f416f336e0d87519217777a460516c5cc1310e3 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 27 Jul 2015 15:47:19 -0600 Subject: dm: Add a return value comment to device_get_child() At present this function does not specify its return value. Fix it. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- include/dm/device.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/dm/device.h b/include/dm/device.h index 9fa0048bd0a..12fd02d09a7 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -318,6 +318,8 @@ const char *dev_get_uclass_name(struct udevice *dev); * @dev: Parent device to check * @index: Child index * @devp: Returns pointer to device + * @return 0 if OK, -ENODEV if no such device, other error if the device fails + * to probe */ int device_get_child(struct udevice *parent, int index, struct udevice **devp); @@ -413,7 +415,7 @@ int device_get_global_by_of_offset(int of_offset, struct udevice **devp); int device_find_first_child(struct udevice *parent, struct udevice **devp); /** - * device_find_first_child() - Find the first child of a device + * device_find_next_child() - Find the next child of a device * * @devp: Pointer to previous child device on entry. Returns pointer to next * child device, or NULL if none -- cgit v1.3.1 From ca4435ef28d13371c31b98cfd41fb8fa28aeabc9 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 27 Jul 2015 15:47:22 -0600 Subject: x86: Move Chrome OS options to defconfig Drop these from the header file and use Kconfig instead. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- configs/chromebook_link_defconfig | 3 +++ configs/chromebox_panther_defconfig | 3 +++ include/configs/x86-chromebook.h | 3 --- 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/configs/chromebook_link_defconfig b/configs/chromebook_link_defconfig index e394dab719b..b987f3f52f6 100644 --- a/configs/chromebook_link_defconfig +++ b/configs/chromebook_link_defconfig @@ -14,6 +14,9 @@ CONFIG_CMD_BOOTSTAGE=y CONFIG_OF_CONTROL=y CONFIG_DM_PCI=y CONFIG_SPI_FLASH=y +CONFIG_CMD_CROS_EC=y +CONFIG_CROS_EC=y +CONFIG_CROS_EC_LPC=y CONFIG_VIDEO_VESA=y CONFIG_FRAMEBUFFER_SET_VESA_MODE=y CONFIG_FRAMEBUFFER_VESA_MODE_11A=y diff --git a/configs/chromebox_panther_defconfig b/configs/chromebox_panther_defconfig index 340510f71a6..e82c8ecf64e 100644 --- a/configs/chromebox_panther_defconfig +++ b/configs/chromebox_panther_defconfig @@ -14,6 +14,9 @@ CONFIG_CMD_BOOTSTAGE=y CONFIG_OF_CONTROL=y CONFIG_DM_PCI=y CONFIG_SPI_FLASH=y +CONFIG_CMD_CROS_EC=y +CONFIG_CROS_EC=y +CONFIG_CROS_EC_LPC=y CONFIG_VIDEO_VESA=y CONFIG_FRAMEBUFFER_SET_VESA_MODE=y CONFIG_FRAMEBUFFER_VESA_MODE_11A=y diff --git a/include/configs/x86-chromebook.h b/include/configs/x86-chromebook.h index 408cbb19577..e8f0bac01c4 100644 --- a/include/configs/x86-chromebook.h +++ b/include/configs/x86-chromebook.h @@ -45,9 +45,6 @@ #define VIDEO_IO_OFFSET 0 #define CONFIG_X86EMU_RAW_IO -#define CONFIG_CROS_EC -#define CONFIG_CROS_EC_LPC -#define CONFIG_CMD_CROS_EC #define CONFIG_ARCH_EARLY_INIT_R #undef CONFIG_ENV_IS_NOWHERE -- cgit v1.3.1 From dcfe4a54edb1af90e9aec866a43592efff1f1974 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 27 Jul 2015 15:47:23 -0600 Subject: x86: Move CONFIG_X86_SERIAL to Kconfig Move this config option to Kconfig and tidy up. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- drivers/serial/Kconfig | 10 ++++++++++ include/configs/bayleybay.h | 2 -- include/configs/crownbay.h | 1 - include/configs/galileo.h | 2 -- include/configs/minnowmax.h | 2 +- include/configs/qemu-x86.h | 2 -- include/configs/x86-chromebook.h | 2 -- 7 files changed, 11 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 4829284216c..078246d22fa 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -102,3 +102,13 @@ config UNIPHIER_SERIAL help If you have a UniPhier based board and want to use the on-chip serial ports, say Y to this option. If unsure, say N. + +config X86_SERIAL + bool "Support for 16550 serial port on x86 machines" + depends on X86 + default y + help + Most x86 machines have a ns16550 UART or compatible. This can be + enabled in the device tree with the correct input clock frequency + provided (default 1843200). Enable this to obtain serial console + output. diff --git a/include/configs/bayleybay.h b/include/configs/bayleybay.h index 740166afd37..ecda4bae08d 100644 --- a/include/configs/bayleybay.h +++ b/include/configs/bayleybay.h @@ -16,8 +16,6 @@ #define CONFIG_SYS_MONITOR_LEN (1 << 20) #define CONFIG_ARCH_MISC_INIT -#define CONFIG_X86_SERIAL - #define CONFIG_PCI_CONFIG_HOST_BRIDGE #define CONFIG_SYS_EARLY_PCI_INIT #define CONFIG_PCI_PNP diff --git a/include/configs/crownbay.h b/include/configs/crownbay.h index 6cf53a3e42a..1ea320bcb57 100644 --- a/include/configs/crownbay.h +++ b/include/configs/crownbay.h @@ -17,7 +17,6 @@ #define CONFIG_BOARD_EARLY_INIT_F #define CONFIG_ARCH_MISC_INIT -#define CONFIG_X86_SERIAL #define CONFIG_SMSC_LPC47M #define CONFIG_PCI_MEM_BUS 0x40000000 diff --git a/include/configs/galileo.h b/include/configs/galileo.h index fd89bf30ef3..3c3c6e9d543 100644 --- a/include/configs/galileo.h +++ b/include/configs/galileo.h @@ -17,8 +17,6 @@ #define CONFIG_BOARD_EARLY_INIT_F #define CONFIG_ARCH_MISC_INIT -#define CONFIG_X86_SERIAL - /* ns16550 UART is memory-mapped in Quark SoC */ #undef CONFIG_SYS_NS16550_PORT_MAPPED diff --git a/include/configs/minnowmax.h b/include/configs/minnowmax.h index 655ce3d422e..d0a8aa696a6 100644 --- a/include/configs/minnowmax.h +++ b/include/configs/minnowmax.h @@ -16,7 +16,7 @@ #define CONFIG_SYS_MONITOR_LEN (1 << 20) #define CONFIG_ARCH_EARLY_INIT_R -#define CONFIG_X86_SERIAL +#define CONFIG_SMSC_LPC47M #define CONFIG_PCI_MEM_BUS 0xd0000000 #define CONFIG_PCI_MEM_PHYS CONFIG_PCI_MEM_BUS diff --git a/include/configs/qemu-x86.h b/include/configs/qemu-x86.h index 78c296f5ad6..c25e331579e 100644 --- a/include/configs/qemu-x86.h +++ b/include/configs/qemu-x86.h @@ -16,8 +16,6 @@ #define CONFIG_SYS_MONITOR_LEN (1 << 20) #define CONFIG_ARCH_MISC_INIT -#define CONFIG_X86_SERIAL - #define CONFIG_PCI_MEM_BUS 0xc0000000 #define CONFIG_PCI_MEM_PHYS CONFIG_PCI_MEM_BUS #define CONFIG_PCI_MEM_SIZE 0x10000000 diff --git a/include/configs/x86-chromebook.h b/include/configs/x86-chromebook.h index e8f0bac01c4..d5dd61913c4 100644 --- a/include/configs/x86-chromebook.h +++ b/include/configs/x86-chromebook.h @@ -17,8 +17,6 @@ #define CONFIG_X86_MRC_ADDR 0xfffa0000 #define CONFIG_CACHE_MRC_SIZE_KB 512 -#define CONFIG_X86_SERIAL - #define CONFIG_SCSI_DEV_LIST \ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_NM10_AHCI}, \ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COUGARPOINT_AHCI_MOBILE}, \ -- cgit v1.3.1 From 1f2be4cea4a29b3c62f7ae3ae16a4edb6e09c4b8 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 27 Jul 2015 15:47:25 -0600 Subject: x86: Drop CONFIG_DCACHE_RAM_MRC_VAR_SIZE from header file This is provided in Kconfig so we don't need it here. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- include/configs/x86-chromebook.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include') diff --git a/include/configs/x86-chromebook.h b/include/configs/x86-chromebook.h index d5dd61913c4..2be885079e9 100644 --- a/include/configs/x86-chromebook.h +++ b/include/configs/x86-chromebook.h @@ -10,7 +10,6 @@ #define CONFIG_SYS_MONITOR_LEN (1 << 20) -#define CONFIG_DCACHE_RAM_MRC_VAR_SIZE 0x4000 #define CONFIG_BOARD_EARLY_INIT_F #define CONFIG_MISC_INIT_R -- cgit v1.3.1 From 82bc22ac8f2ac665d8c6cf2ac35e544873c2004e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 27 Jul 2015 15:47:29 -0600 Subject: x86: minnowmax: Drop the old PCI settings These are now in the device tree so we don't need to use the CONFIG options. Drop them. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- include/configs/minnowmax.h | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'include') diff --git a/include/configs/minnowmax.h b/include/configs/minnowmax.h index d0a8aa696a6..2a40d1f947f 100644 --- a/include/configs/minnowmax.h +++ b/include/configs/minnowmax.h @@ -18,18 +18,6 @@ #define CONFIG_SMSC_LPC47M -#define CONFIG_PCI_MEM_BUS 0xd0000000 -#define CONFIG_PCI_MEM_PHYS CONFIG_PCI_MEM_BUS -#define CONFIG_PCI_MEM_SIZE 0x10000000 - -#define CONFIG_PCI_PREF_BUS 0xc0000000 -#define CONFIG_PCI_PREF_PHYS CONFIG_PCI_PREF_BUS -#define CONFIG_PCI_PREF_SIZE 0x10000000 - -#define CONFIG_PCI_IO_BUS 0x2000 -#define CONFIG_PCI_IO_PHYS CONFIG_PCI_IO_BUS -#define CONFIG_PCI_IO_SIZE 0xe000 - #define CONFIG_PCI_CONFIG_HOST_BRIDGE #define CONFIG_SYS_EARLY_PCI_INIT #define CONFIG_PCI_PNP -- cgit v1.3.1 From f05ad9ba4c22b5c5929406394a0889791c2778da Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 4 Aug 2015 12:33:39 -0600 Subject: Add a way to skip relocation When running U-Boot as an EFI application we cannot relocate since we do not have relocation information. U-Boot has already been relocated to a suitable address. Add a global_data flag to control skipping relocation. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- common/board_f.c | 9 +++++++++ include/asm-generic/global_data.h | 1 + 2 files changed, 10 insertions(+) (limited to 'include') diff --git a/common/board_f.c b/common/board_f.c index 6d922b8c86b..c7cc67c7a48 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -654,6 +654,8 @@ static int setup_dram_config(void) static int reloc_fdt(void) { + if (gd->flags & GD_FLG_SKIP_RELOC) + return 0; if (gd->new_fdt) { memcpy(gd->new_fdt, gd->fdt_blob, gd->fdt_size); gd->fdt_blob = gd->new_fdt; @@ -664,6 +666,11 @@ static int reloc_fdt(void) static int setup_reloc(void) { + if (gd->flags & GD_FLG_SKIP_RELOC) { + debug("Skipping relocation due to flag\n"); + return 0; + } + #ifdef CONFIG_SYS_TEXT_BASE gd->reloc_off = gd->relocaddr - CONFIG_SYS_TEXT_BASE; #ifdef CONFIG_M68K @@ -689,6 +696,8 @@ static int setup_reloc(void) static int jump_to_copy(void) { + if (gd->flags & GD_FLG_SKIP_RELOC) + return 0; /* * x86 is special, but in a nice way. It uses a trampoline which * enables the dcache if possible. diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index 9f5db0f5afb..21552650025 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -117,5 +117,6 @@ typedef struct global_data { #define GD_FLG_SERIAL_READY 0x00100 /* Pre-reloc serial console ready */ #define GD_FLG_FULL_MALLOC_INIT 0x00200 /* Full malloc() is ready */ #define GD_FLG_SPL_INIT 0x00400 /* spl_init() has been called */ +#define GD_FLG_SKIP_RELOC 0x00800 /* Don't relocate */ #endif /* __ASM_GENERIC_GBL_DATA_H */ -- cgit v1.3.1 From cd326a32c9fc317af30d682db2ba8f3242bc1221 Mon Sep 17 00:00:00 2001 From: Ben Stoltz Date: Tue, 4 Aug 2015 12:33:50 -0600 Subject: x86: Add definitions for the x86-efi board and plumb it in Add configuration and Kconfig changes for this board. Signed-off-by: Ben Stoltz Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- configs/efi-x86_defconfig | 16 ++++++++++++++++ include/configs/efi-x86.h | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 configs/efi-x86_defconfig create mode 100644 include/configs/efi-x86.h (limited to 'include') diff --git a/configs/efi-x86_defconfig b/configs/efi-x86_defconfig new file mode 100644 index 00000000000..1aa0655a178 --- /dev/null +++ b/configs/efi-x86_defconfig @@ -0,0 +1,16 @@ +CONFIG_X86=y +CONFIG_VENDOR_EFI=y +CONFIG_TARGET_EFI=y +CONFIG_TSC_CALIBRATION_BYPASS=y +CONFIG_OF_CONTROL=y +CONFIG_OF_EMBED=y +CONFIG_DM_PCI=y +CONFIG_DEFAULT_DEVICE_TREE="efi" +CONFIG_EFI=y +CONFIG_EFI_APP=y +CONFIG_DEBUG_UART=y +CONFIG_DEBUG_EFI_CONSOLE=y +CONFIG_DEBUG_UART_BASE=0 +CONFIG_DEBUG_UART_CLOCK=0 +# CONFIG_CMD_NET is not set +# CONFIG_CMD_BOOTM is not set diff --git a/include/configs/efi-x86.h b/include/configs/efi-x86.h new file mode 100644 index 00000000000..5779cfdb66b --- /dev/null +++ b/include/configs/efi-x86.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#include + +#undef CONFIG_CMD_SF_TEST + +#undef CONFIG_TPM +#undef CONFIG_TPM_TIS_LPC +#undef CONFIG_TPM_TIS_BASE_ADDRESS + +#undef CONFIG_CMD_IMLS + +#undef CONFIG_SYS_NS16550 +#undef CONFIG_X86_SERIAL +#undef CONFIG_ENV_IS_IN_SPI_FLASH +#define CONFIG_ENV_IS_NOWHERE +#undef CONFIG_VIDEO +#undef CONFIG_CFB_CONSOLE +#undef CONFIG_SCSI_AHCI +#undef CONFIG_CMD_SCSI +#undef CONFIG_INTEL_ICH6_GPIO + +#define CONFIG_STD_DEVICES_SETTINGS "stdin=usbkbd,vga,serial\0" \ + "stdout=vga,serial\0" \ + "stderr=vga,serial\0" + +#endif -- cgit v1.3.1 From 476476e73b14696563524cbc2627a4c033ea64da Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 4 Aug 2015 12:33:52 -0600 Subject: efi: Add support for loading U-Boot through an EFI stub It is useful to be able to load U-Boot onto a board even if is it already running EFI. This can allow access to the U-Boot command interface, flexible booting options and easier development. The easiest way to do this is to build U-Boot as a binary blob and have an EFI stub copy it into RAM. Add support for this feature, targeting 32-bit initially. Also add a way to detect when U-Boot has been loaded via a stub. This goes in common.h since it needs to be widely available so that we avoid redoing initialisation that should be skipped. Signed-off-by: Simon Glass Improvements to how the payload is built: Signed-off-by: Bin Meng Reviewed-by: Bin Meng Tested-by: Bin Meng --- Makefile | 24 +++++ arch/x86/config.mk | 7 ++ include/common.h | 7 ++ include/efi.h | 4 + lib/efi/Kconfig | 21 ++++ lib/efi/Makefile | 9 ++ lib/efi/efi_stub.c | 304 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 376 insertions(+) create mode 100644 lib/efi/efi_stub.c (limited to 'include') diff --git a/Makefile b/Makefile index 620c18f1e7e..752ee0dbeaa 100644 --- a/Makefile +++ b/Makefile @@ -755,6 +755,7 @@ ALL-$(CONFIG_SPL) += $(CONFIG_SPL_TARGET:"%"=%) endif ALL-$(CONFIG_REMAKE_ELF) += u-boot.elf ALL-$(CONFIG_EFI_APP) += u-boot-app.efi +ALL-$(CONFIG_EFI_STUB) += u-boot-payload.efi ifneq ($(BUILD_ROM),) ALL-$(CONFIG_X86_RESET_VECTOR) += u-boot.rom @@ -790,6 +791,9 @@ cmd_objcopy = $(OBJCOPY) --gap-fill=0xff $(OBJCOPYFLAGS) \ quiet_cmd_zobjcopy = OBJCOPY $@ cmd_zobjcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@ +quiet_cmd_efipayload = OBJCOPY $@ +cmd_efipayload = $(OBJCOPY) -I binary -O $(EFIPAYLOAD_BFDTARGET) -B $(EFIPAYLOAD_BFDARCH) $< $@ + quiet_cmd_mkimage = MKIMAGE $@ cmd_mkimage = $(objtree)/tools/mkimage $(MKIMAGEFLAGS_$(@F)) -d $< $@ \ $(if $(KBUILD_VERBOSE:1=), >/dev/null) @@ -1087,6 +1091,26 @@ OBJCOPYFLAGS_u-boot-app.efi := $(OBJCOPYFLAGS_EFI) u-boot-app.efi: u-boot FORCE $(call if_changed,zobjcopy) +u-boot-dtb.bin.o: u-boot-dtb.bin FORCE + $(call if_changed,efipayload) + +u-boot-payload.lds: $(LDSCRIPT_EFI) FORCE + $(call if_changed_dep,cpp_lds) + +# 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 \ + lib/efi/efi.o lib/efi/efi_stub.o u-boot-dtb.bin.o \ + $(addprefix arch/$(ARCH)/lib/efi/,$(EFISTUB)) + +u-boot-payload: u-boot-dtb.bin.o u-boot-payload.lds FORCE + $(call if_changed,u-boot_payload) + +OBJCOPYFLAGS_u-boot-payload.efi := $(OBJCOPYFLAGS_EFI) +u-boot-payload.efi: u-boot-payload FORCE + $(call if_changed,zobjcopy) + u-boot-img.bin: spl/u-boot-spl.bin u-boot.img FORCE $(call if_changed,cat) diff --git a/arch/x86/config.mk b/arch/x86/config.mk index e27f84abdad..334c10b882d 100644 --- a/arch/x86/config.mk +++ b/arch/x86/config.mk @@ -24,6 +24,10 @@ PLATFORM_LDFLAGS += -Bsymbolic -Bsymbolic-functions -m elf_i386 LDFLAGS_FINAL += --wrap=__divdi3 --wrap=__udivdi3 LDFLAGS_FINAL += --wrap=__moddi3 --wrap=__umoddi3 +# This is used in the top-level Makefile which does not include +# PLATFORM_LDFLAGS +LDFLAGS_EFI_PAYLOAD := -Bsymbolic -Bsymbolic-functions -shared --no-undefined + OBJCOPYFLAGS_EFI := -j .text -j .sdata -j .data -j .dynamic -j .dynsym \ -j .rel -j .rela -j .reloc @@ -31,6 +35,9 @@ CFLAGS_NON_EFI := -mregparm=3 CFLAGS_EFI := -fpic -fshort-wchar EFIARCH = ia32 +EFIPAYLOAD_BFDTARGET = elf32-i386 + +EFIPAYLOAD_BFDARCH = i386 LDSCRIPT_EFI := $(srctree)/$(CPUDIR)/efi/elf_$(EFIARCH)_efi.lds OBJCOPYFLAGS_EFI += --target=efi-app-$(EFIARCH) diff --git a/include/common.h b/include/common.h index 4566bd11111..fcc9ae7c21c 100644 --- a/include/common.h +++ b/include/common.h @@ -1021,6 +1021,13 @@ int cpu_release(int nr, int argc, char * const argv[]); offsetof(struct structure, member) == offset, \ "`struct " #structure "` offset for `" #member "` is not " #offset) +/* Avoid using CONFIG_EFI_STUB directly as we may boot from other loaders */ +#ifdef CONFIG_EFI_STUB +#define ll_boot_init() false +#else +#define ll_boot_init() true +#endif + /* Pull in stuff for the build system */ #ifdef DO_DEPS_ONLY # include diff --git a/include/efi.h b/include/efi.h index f0097017b3c..1470c0825c4 100644 --- a/include/efi.h +++ b/include/efi.h @@ -268,11 +268,15 @@ struct efi_priv { /* Base address of the EFI image */ extern char image_base[]; +/* Start and end of U-Boot image (for payload) */ +extern char _binary_u_boot_dtb_bin_start[], _binary_u_boot_dtb_bin_end[]; + /** * efi_get_sys_table() - Get access to the main EFI system table * * @return pointer to EFI system table */ + struct efi_system_table *efi_get_sys_table(void); /** diff --git a/lib/efi/Kconfig b/lib/efi/Kconfig index b23ba5b5041..919e314a0ce 100644 --- a/lib/efi/Kconfig +++ b/lib/efi/Kconfig @@ -20,6 +20,11 @@ config EFI_APP command prompt and memory and I/O functions. Use 'reset' to return to EFI. +config EFI_STUB + bool "Support running as an EFI payload" + +endchoice + config EFI_RAM_SIZE hex "Amount of EFI RAM for U-Boot" depends on EFI_APP @@ -30,4 +35,20 @@ config EFI_RAM_SIZE other smaller amounts) and it can never be increased after that. It is used as the RAM size in with U-Boot. +choice + prompt "EFI 32/64-bit selection" + depends on EFI_STUB + help + EFI does not support mixing 32-bit and 64-bit modes. This is a + significant problem because it means that you must build a stub with + the correct type for EFI to load it correctly. If you are using + 32-bit EFI, select 32-bit here, else select 64-bit. Failure to do + this may produce no error message - it just won't start! + +config EFI_STUB_32BIT + bool "Produce a stub for running with 32-bit EFI" + +config EFI_STUB_64BIT + bool "Produce a stub for running with 64-bit EFI" + endchoice diff --git a/lib/efi/Makefile b/lib/efi/Makefile index 5ee344c7d6d..4bc67f01f95 100644 --- a/lib/efi/Makefile +++ b/lib/efi/Makefile @@ -5,3 +5,12 @@ # obj-$(CONFIG_EFI_APP) += efi_app.o efi.o + +CFLAGS_REMOVE_efi_stub.o := -mregparm=3 \ + $(if $(CONFIG_EFI_STUB_64BIT),-march=i386 -m32) +CFLAGS_efi_stub.o := -fpic -fshort-wchar +CFLAGS_REMOVE_efi.o := -mregparm=3 \ + $(if $(CONFIG_EFI_STUB_64BIT),-march=i386 -m32) +CFLAGS_efi.o := -fpic -fshort-wchar + +extra-$(CONFIG_EFI_STUB) += efi_stub.o efi.o diff --git a/lib/efi/efi_stub.c b/lib/efi/efi_stub.c new file mode 100644 index 00000000000..1e46f6ece14 --- /dev/null +++ b/lib/efi/efi_stub.c @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2015 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +#ifndef CONFIG_X86 +/* + * Problem areas: + * - putc() uses the ns16550 address directly and assumed I/O access. Many + * platforms will use memory access + * get_codeseg32() is only meaningful on x86 + */ +#error "This file needs to be ported for use on architectures" +#endif + +static struct efi_priv *global_priv; +static bool use_uart; + +struct __packed desctab_info { + uint16_t limit; + uint64_t addr; + uint16_t pad; +}; + +/* + * EFI uses Unicode and we don't. The easiest way to get a sensible output + * function is to use the U-Boot debug UART. We use EFI's console output + * function where available, and assume the built-in UART after that. We rely + * on EFI to set up the UART for us and just bring in the functions here. + * This last bit is a bit icky, but it's only for debugging anyway. We could + * build in ns16550.c with some effort, but this is a payload loader after + * all. + * + * Note: We avoid using printf() so we don't need to bring in lib/vsprintf.c. + * That would require some refactoring since we already build this for U-Boot. + * Building an EFI shared library version would have to be a separate stem. + * That might push us to using the SPL framework to build this stub. However + * that would involve a round of EFI-specific changes in SPL. Worth + * considering if we start needing more U-Boot functionality. Note that we + * could then move get_codeseg32() to arch/x86/cpu/cpu.c. + */ +void debug_uart_init(void) +{ +} + +void putc(const char ch) +{ + if (use_uart) { + NS16550_t com_port = (NS16550_t)0x3f8; + + while ((inb((ulong)&com_port->lsr) & UART_LSR_THRE) == 0) + ; + outb(ch, (ulong)&com_port->thr); + } else { + efi_putc(global_priv, ch); + } + if (ch == '\n') + putc('\r'); +} + +void puts(const char *str) +{ + while (*str) + putc(*str++); +} + +static void _debug_uart_putc(int ch) +{ + putc(ch); +} + +DEBUG_UART_FUNCS + +void *memcpy(void *dest, const void *src, size_t size) +{ + unsigned char *dptr = dest; + const unsigned char *ptr = src; + const unsigned char *end = src + size; + + while (ptr < end) + *dptr++ = *ptr++; + + return dest; +} + +void *memset(void *inptr, int ch, size_t size) +{ + char *ptr = inptr; + char *end = ptr + size; + + while (ptr < end) + *ptr++ = ch; + + return ptr; +} + +static void jump_to_uboot(ulong cs32, ulong addr, ulong info) +{ +#ifdef CONFIG_EFI_STUB_32BIT + /* + * U-Boot requires these parameters in registers, not on the stack. + * See _x86boot_start() for this code. + */ + typedef void (*func_t)(int bist, int unused, ulong info) + __attribute__((regparm(3))); + + ((func_t)addr)(0, 0, info); +#else + /* TODO: Implement this */ +#endif +} + +static void get_gdt(struct desctab_info *info) +{ + asm volatile ("sgdt %0" : : "m"(*info) : "memory"); +} + +static inline unsigned long read_cr3(void) +{ + unsigned long val; + + asm volatile("mov %%cr3,%0" : "=r" (val) : : "memory"); + return val; +} + +/** + * get_codeseg32() - Find the code segment to use for 32-bit code + * + * U-Boot only works in 32-bit mode at present, so when booting from 64-bit + * EFI we must first change to 32-bit mode. To do this we need to find the + * correct code segment to use (an entry in the Global Descriptor Table). + * + * @return code segment GDT offset, or 0 for 32-bit EFI, -ENOENT if not found + */ +static int get_codeseg32(void) +{ + int cs32 = 0; + + /* TODO(sjg): Implement this for 64-bit mode */ + return cs32; +} + +static int setup_info_table(struct efi_priv *priv, int size) +{ + struct efi_info_hdr *info; + efi_status_t ret; + + /* Get some memory for our info table */ + priv->info_size = size; + info = efi_malloc(priv, priv->info_size, &ret); + if (ret) { + printhex2(ret); + puts(" No memory for info table: "); + return ret; + } + + memset(info, '\0', sizeof(*info)); + info->version = EFI_TABLE_VERSION; + info->hdr_size = sizeof(*info); + priv->info = info; + priv->next_hdr = (char *)info + info->hdr_size; + + return 0; +} + +static void add_entry_addr(struct efi_priv *priv, enum efi_entry_t type, + void *ptr1, int size1, void *ptr2, int size2) +{ + struct efi_entry_hdr *hdr = priv->next_hdr; + + hdr->type = type; + hdr->size = size1 + size2; + hdr->addr = 0; + hdr->link = ALIGN(sizeof(*hdr) + hdr->size, 16); + priv->next_hdr += hdr->link; + memcpy(hdr + 1, ptr1, size1); + memcpy((void *)(hdr + 1) + size1, ptr2, size2); + priv->info->total_size = (ulong)priv->next_hdr - (ulong)priv->info; +} + +/** + * efi_main() - Start an EFI image + * + * This function is called by our EFI start-up code. It handles running + * U-Boot. If it returns, EFI will continue. + */ +efi_status_t efi_main(efi_handle_t image, struct efi_system_table *sys_table) +{ + struct efi_priv local_priv, *priv = &local_priv; + struct efi_boot_services *boot = sys_table->boottime; + struct efi_mem_desc *desc; + struct efi_entry_memmap map; + ulong key, desc_size, size; + efi_status_t ret; + u32 version; + int cs32; + + ret = efi_init(priv, "Payload", image, sys_table); + if (ret) { + printhex2(ret); puts(" efi_init() failed\n"); + return ret; + } + global_priv = priv; + + cs32 = get_codeseg32(); + if (cs32 < 0) + return EFI_UNSUPPORTED; + + /* Get the memory map so we can switch off EFI */ + size = 0; + ret = boot->get_memory_map(&size, NULL, &key, &desc_size, &version); + if (ret != EFI_BUFFER_TOO_SMALL) { + printhex2(BITS_PER_LONG); + printhex2(ret); + puts(" No memory map\n"); + return ret; + } + size += 1024; /* Since doing a malloc() may change the memory map! */ + desc = efi_malloc(priv, size, &ret); + if (!desc) { + printhex2(ret); + puts(" No memory for memory descriptor: "); + return ret; + } + ret = setup_info_table(priv, size + 128); + if (ret) + return ret; + + ret = boot->get_memory_map(&size, desc, &key, &desc_size, &version); + if (ret) { + printhex2(ret); + puts(" Can't get memory map\n"); + return ret; + } + + ret = boot->exit_boot_services(image, key); + if (ret) { + /* + * Unfortunately it happens that we cannot exit boot services + * the first time. But the second time it work. I don't know + * why but this seems to be a repeatable problem. To get + * around it, just try again. + */ + printhex2(ret); + puts(" Can't exit boot services\n"); + size = sizeof(desc); + ret = boot->get_memory_map(&size, desc, &key, &desc_size, + &version); + if (ret) { + printhex2(ret); + puts(" Can't get memory map\n"); + return ret; + } + ret = boot->exit_boot_services(image, key); + if (ret) { + printhex2(ret); + puts(" Can't exit boot services 2\n"); + return ret; + } + } + + map.version = version; + map.desc_size = desc_size; + add_entry_addr(priv, EFIET_MEMORY_MAP, &map, sizeof(map), desc, size); + add_entry_addr(priv, EFIET_END, NULL, 0, 0, 0); + + /* The EFI UART won't work now, switch to a debug one */ + use_uart = true; + + memcpy((void *)CONFIG_SYS_TEXT_BASE, _binary_u_boot_dtb_bin_start, + (ulong)_binary_u_boot_dtb_bin_end - + (ulong)_binary_u_boot_dtb_bin_start); + +#ifdef DEBUG + puts("EFI table at "); + printhex8((ulong)priv->info); + puts(" size "); + printhex8(priv->info->total_size); +#endif + putc('\n'); + jump_to_uboot(cs32, CONFIG_SYS_TEXT_BASE, (ulong)priv->info); + + return EFI_LOAD_ERROR; +} -- cgit v1.3.1 From 96a8d409a75af99ac7a9a9ba707d544f9cf44fc0 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 4 Aug 2015 12:33:56 -0600 Subject: 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 Improvements to how the payload is built: Signed-off-by: Bin Meng Reviewed-by: Bin Meng Tested-by: Bin Meng --- 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 (limited to 'include') diff --git a/Makefile b/Makefile index 752ee0dbeaa..bb0ba9f8a22 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 334c10b882d..d7addd87286 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 e272c90eb7f..766617f9aa3 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 00000000000..c5cbf4108b3 --- /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 . + * Copyright (C) 2005 Intel Co. + * Contributed by Fenghua Yu . + * + * 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 1470c0825c4..fcafda0b0bf 100644 --- a/include/efi.h +++ b/include/efi.h @@ -18,6 +18,13 @@ #include #include +#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 1e46f6ece14..d4d3e496899 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 @@ -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; } -- cgit v1.3.1