From 94e72a6bd994078674188bee2efb727a110a1cc6 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sat, 23 Jun 2018 03:03:47 -0700 Subject: [PATCH 1/9] x86: timer: tsc: Allow specifying clock rate from device tree again With the introduction of early timer support in the TSC driver, the capability of getting clock rate from device tree was lost unfortunately. Now we bring such functionality back, but with a limitation that when TSC is used as early timer, specifying clock rate from device tree does not work. This fixes random boot failures seen on QEMU targets: printing "TSC frequency is ZERO" and reset forever. Signed-off-by: Bin Meng Reviewed-by: Simon Glass --- drivers/timer/tsc_timer.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/timer/tsc_timer.c b/drivers/timer/tsc_timer.c index cf869998bf..747f190d38 100644 --- a/drivers/timer/tsc_timer.c +++ b/drivers/timer/tsc_timer.c @@ -377,14 +377,23 @@ static int tsc_timer_probe(struct udevice *dev) { struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev); - tsc_timer_ensure_setup(); - uc_priv->clock_rate = gd->arch.clock_rate; + if (!uc_priv->clock_rate) { + tsc_timer_ensure_setup(); + uc_priv->clock_rate = gd->arch.clock_rate; + } else { + gd->arch.tsc_base = rdtsc(); + } return 0; } unsigned long notrace timer_early_get_rate(void) { + /* + * When TSC timer is used as the early timer, be warned that the timer + * clock rate can only be calibrated via some hardware ways. Specifying + * it in the device tree won't work for the early timer. + */ tsc_timer_ensure_setup(); return gd->arch.clock_rate; From fc48ebe6dff059a799c8f85e31ee8dea6c2f77d8 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 26 Jun 2018 03:58:55 -0700 Subject: [PATCH 2/9] x86: Add scsi command to coreboot and qemu This adds the scsi command to coreboot and qemu, to be in consistent with other x86 targets. Signed-off-by: Bin Meng Reviewed-by: Simon Glass --- arch/x86/cpu/coreboot/Kconfig | 1 + arch/x86/cpu/qemu/Kconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/x86/cpu/coreboot/Kconfig b/arch/x86/cpu/coreboot/Kconfig index fa3b64f2bb..392c258945 100644 --- a/arch/x86/cpu/coreboot/Kconfig +++ b/arch/x86/cpu/coreboot/Kconfig @@ -10,6 +10,7 @@ config SYS_COREBOOT imply MMC_PCI imply MMC_SDHCI imply MMC_SDHCI_SDMA + imply SCSI imply SCSI_AHCI imply SPI_FLASH imply SYS_NS16550 diff --git a/arch/x86/cpu/qemu/Kconfig b/arch/x86/cpu/qemu/Kconfig index 31428dd0a0..fdf558d660 100644 --- a/arch/x86/cpu/qemu/Kconfig +++ b/arch/x86/cpu/qemu/Kconfig @@ -7,6 +7,7 @@ config QEMU select ARCH_EARLY_INIT_R imply AHCI_PCI imply E1000 + imply SCSI imply SCSI_AHCI imply SYS_NS16550 imply USB From 8199a145c40791f0bc272fc016494028cf250195 Mon Sep 17 00:00:00 2001 From: Ivan Gorinov Date: Thu, 21 Jun 2018 21:16:16 -0700 Subject: [PATCH 3/9] x86: Use microcode update from device tree for all processors Built without a ROM image with FSP (u-boot.rom), the U-Boot loader applies the microcode update data block encoded in Device Tree to the bootstrap processor but not passed to the other CPUs when multiprocessing is enabled. If the bootstrap processor successfully performs a microcode update from Device Tree, use the same data block for the other processors. Signed-off-by: Ivan Gorinov Reviewed-by: Bin Meng [bmeng: fixed build errors on edison and qemu-x86] Signed-off-by: Bin Meng --- arch/x86/cpu/intel_common/car.S | 2 ++ arch/x86/cpu/intel_common/microcode.c | 10 +++++++--- arch/x86/include/asm/microcode.h | 1 + arch/x86/lib/fsp/fsp_car.S | 4 +++- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/arch/x86/cpu/intel_common/car.S b/arch/x86/cpu/intel_common/car.S index fe8dfbc9ca..52a77bb2d1 100644 --- a/arch/x86/cpu/intel_common/car.S +++ b/arch/x86/cpu/intel_common/car.S @@ -239,4 +239,6 @@ _dt_ucode_base_size: .globl ucode_base ucode_base: /* Declared in microcode.h */ .long 0 /* microcode base */ +.globl ucode_size +ucode_size: /* Declared in microcode.h */ .long 0 /* microcode size */ diff --git a/arch/x86/cpu/intel_common/microcode.c b/arch/x86/cpu/intel_common/microcode.c index 11b1ec8955..c7a539d281 100644 --- a/arch/x86/cpu/intel_common/microcode.c +++ b/arch/x86/cpu/intel_common/microcode.c @@ -43,8 +43,6 @@ static int microcode_decode_node(const void *blob, int node, update->data = fdt_getprop(blob, node, "data", &update->size); if (!update->data) return -ENOENT; - update->data += UCODE_HEADER_LEN; - update->size -= UCODE_HEADER_LEN; update->header_version = fdtdec_get_int(blob, node, "intel,header-version", 0); @@ -124,6 +122,7 @@ static void microcode_read_cpu(struct microcode_update *cpu) int microcode_update_intel(void) { struct microcode_update cpu, update; + ulong address; const void *blob = gd->fdt_blob; int skipped; int count; @@ -167,7 +166,8 @@ int microcode_update_intel(void) skipped++; continue; } - wrmsr(MSR_IA32_UCODE_WRITE, (ulong)update.data, 0); + address = (ulong)update.data + UCODE_HEADER_LEN; + wrmsr(MSR_IA32_UCODE_WRITE, address, 0); rev = microcode_read_rev(); debug("microcode: updated to revision 0x%x date=%04x-%02x-%02x\n", rev, update.date_code & 0xffff, @@ -178,5 +178,9 @@ int microcode_update_intel(void) return -EFAULT; } count++; + if (!ucode_base) { + ucode_base = (ulong)update.data; + ucode_size = update.size; + } } while (1); } diff --git a/arch/x86/include/asm/microcode.h b/arch/x86/include/asm/microcode.h index f7b32a5eb1..4ab7504931 100644 --- a/arch/x86/include/asm/microcode.h +++ b/arch/x86/include/asm/microcode.h @@ -10,6 +10,7 @@ /* This is a declaration for ucode_base in start.S */ extern u32 ucode_base; +extern u32 ucode_size; /** * microcode_update_intel() - Apply microcode updates diff --git a/arch/x86/lib/fsp/fsp_car.S b/arch/x86/lib/fsp/fsp_car.S index 549d863070..48edc8362a 100644 --- a/arch/x86/lib/fsp/fsp_car.S +++ b/arch/x86/lib/fsp/fsp_car.S @@ -102,8 +102,10 @@ temp_ram_init_params: _dt_ucode_base_size: /* These next two fields are filled in by ifdtool */ .globl ucode_base -ucode_base: /* Declared in micrcode.h */ +ucode_base: /* Declared in microcode.h */ .long 0 /* microcode base */ +.globl ucode_size +ucode_size: /* Declared in microcode.h */ .long 0 /* microcode size */ .long CONFIG_SYS_MONITOR_BASE /* code region base */ .long CONFIG_SYS_MONITOR_LEN /* code region size */ From abe47ca728f5b22d1ec9fcf609e00b331c4d5273 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 27 Jun 2018 20:38:01 -0700 Subject: [PATCH 4/9] x86: efi_loader: Build EFI memory map per E820 table On x86 traditional E820 table is used to pass the memory information to kernel. With EFI loader we can build the EFI memory map from it. Signed-off-by: Bin Meng Reviewed-by: Simon Glass --- arch/x86/lib/e820.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/arch/x86/lib/e820.c b/arch/x86/lib/e820.c index 9a9ec991ca..8b34f677d9 100644 --- a/arch/x86/lib/e820.c +++ b/arch/x86/lib/e820.c @@ -4,6 +4,7 @@ */ #include +#include #include DECLARE_GLOBAL_DATA_PTR; @@ -34,3 +35,41 @@ __weak unsigned int install_e820_map(unsigned int max_entries, return 4; } + +#if defined(CONFIG_EFI_LOADER) && !defined(CONFIG_SPL_BUILD) +void efi_add_known_memory(void) +{ + struct e820_entry e820[E820MAX]; + unsigned int i, num; + u64 start, pages; + int type; + + num = install_e820_map(ARRAY_SIZE(e820), e820); + + for (i = 0; i < num; ++i) { + start = e820[i].addr; + pages = ALIGN(e820[i].size, EFI_PAGE_SIZE) >> EFI_PAGE_SHIFT; + + switch (e820[i].type) { + case E820_RAM: + type = EFI_CONVENTIONAL_MEMORY; + break; + case E820_RESERVED: + type = EFI_RESERVED_MEMORY_TYPE; + break; + case E820_ACPI: + type = EFI_ACPI_RECLAIM_MEMORY; + break; + case E820_NVS: + type = EFI_ACPI_MEMORY_NVS; + break; + case E820_UNUSABLE: + default: + type = EFI_UNUSABLE_MEMORY; + break; + } + + efi_add_memory_map(start, pages, type, false); + } +} +#endif /* defined(EFI_LOADER) && !defined(CONFIG_SPL_BUILD) */ From bb68c7fba07621ae4dfe3ea10737fa18049d3e51 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 27 Jun 2018 20:38:02 -0700 Subject: [PATCH 5/9] efi_loader: Increase number of configuration tables to 16 At present the number of configuration tables is set to 2. By looking at which tables the Linux EFI stub or iPXE can process, it looks 16 is a reasonable number. Signed-off-by: Bin Meng Reviewed-by: Heinrich Schuchardt --- lib/efi_loader/efi_boottime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 50d311548e..261d66d97f 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -43,7 +43,7 @@ static bool efi_is_direct_boot = true; * In most cases we want to pass an FDT to the payload, so reserve one slot of * config table space for it. The pointer gets populated by do_bootefi_exec(). */ -static struct efi_configuration_table __efi_runtime_data efi_conf_table[2]; +static struct efi_configuration_table __efi_runtime_data efi_conf_table[16]; #ifdef CONFIG_ARM /* From 86df34d42b05f574854f19c96142d8e5d30f5d8d Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 27 Jun 2018 20:38:03 -0700 Subject: [PATCH 6/9] efi_loader: Install ACPI configuration tables ACPI tables can be passed via EFI configuration table to an EFI application. This is only supported on x86 so far. Signed-off-by: Bin Meng Reviewed-by: Simon Glass --- cmd/bootefi.c | 5 +++++ include/efi_api.h | 4 ++++ include/efi_loader.h | 8 ++++++++ lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_acpi.c | 42 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 60 insertions(+) create mode 100644 lib/efi_loader/efi_acpi.c diff --git a/cmd/bootefi.c b/cmd/bootefi.c index f55a40dc84..cd755b6bf4 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -61,6 +61,11 @@ efi_status_t efi_init_obj_list(void) if (ret != EFI_SUCCESS) goto out; #endif +#ifdef CONFIG_GENERATE_ACPI_TABLE + ret = efi_acpi_register(); + if (ret != EFI_SUCCESS) + goto out; +#endif #ifdef CONFIG_GENERATE_SMBIOS_TABLE ret = efi_smbios_register(); if (ret != EFI_SUCCESS) diff --git a/include/efi_api.h b/include/efi_api.h index 094be6edf9..0c3dd3cdd4 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -282,6 +282,10 @@ struct efi_runtime_services { EFI_GUID(0xb1b621d5, 0xf19c, 0x41a5, \ 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0) +#define EFI_ACPI_TABLE_GUID \ + EFI_GUID(0x8868e871, 0xe4f1, 0x11d3, \ + 0xbc, 0x22, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81) + #define SMBIOS_TABLE_GUID \ EFI_GUID(0xeb9d2d31, 0x2d88, 0x11d3, \ 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) diff --git a/include/efi_loader.h b/include/efi_loader.h index c66252a7dd..d837e7b157 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -214,6 +214,14 @@ efi_status_t efi_net_register(void); /* Called by bootefi to make the watchdog available */ efi_status_t efi_watchdog_register(void); /* Called by bootefi to make SMBIOS tables available */ +/** + * efi_acpi_register() - write out ACPI tables + * + * Called by bootefi to make ACPI tables available + * + * @return 0 if OK, -ENOMEM if no memory is available for the tables + */ +efi_status_t efi_acpi_register(void); /** * efi_smbios_register() - write out SMBIOS tables * diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index c6046e36d2..d6402c4615 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -22,4 +22,5 @@ obj-$(CONFIG_LCD) += efi_gop.o obj-$(CONFIG_DM_VIDEO) += efi_gop.o obj-$(CONFIG_PARTITIONS) += efi_disk.o obj-$(CONFIG_NET) += efi_net.o +obj-$(CONFIG_GENERATE_ACPI_TABLE) += efi_acpi.o obj-$(CONFIG_GENERATE_SMBIOS_TABLE) += efi_smbios.o diff --git a/lib/efi_loader/efi_acpi.c b/lib/efi_loader/efi_acpi.c new file mode 100644 index 0000000000..a4e5e53d15 --- /dev/null +++ b/lib/efi_loader/efi_acpi.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * EFI application ACPI tables support + * + * Copyright (C) 2018, Bin Meng + */ + +#include +#include +#include + +static const efi_guid_t acpi_guid = EFI_ACPI_TABLE_GUID; + +/* + * Install the ACPI table as a configuration table. + * + * @return status code + */ +efi_status_t efi_acpi_register(void) +{ + /* Map within the low 32 bits, to allow for 32bit ACPI tables */ + u64 acpi = U32_MAX; + efi_status_t ret; + + /* Reserve 64kiB page for ACPI */ + ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, + EFI_RUNTIME_SERVICES_DATA, 16, &acpi); + if (ret != EFI_SUCCESS) + return ret; + + /* + * Generate ACPI tables - we know that efi_allocate_pages() returns + * a 4k-aligned address, so it is safe to assume that + * write_acpi_tables() will write the table at that address. + */ + assert(!(acpi & 0xf)); + write_acpi_tables(acpi); + + /* And expose them to our EFI payload */ + return efi_install_configuration_table(&acpi_guid, + (void *)(uintptr_t)acpi); +} From 47cae019efb39c649015b3534344e50125e9f1d9 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 27 Jun 2018 20:38:04 -0700 Subject: [PATCH 7/9] efi_loader: helloworld: Output ACPI configuration table Output ACPI configuration table if it exists. Signed-off-by: Bin Meng Reviewed-by: Heinrich Schuchardt --- lib/efi_loader/helloworld.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/efi_loader/helloworld.c b/lib/efi_loader/helloworld.c index 046b46a2c1..3b8de5b4ea 100644 --- a/lib/efi_loader/helloworld.c +++ b/lib/efi_loader/helloworld.c @@ -14,6 +14,7 @@ static const efi_guid_t loaded_image_guid = LOADED_IMAGE_GUID; static const efi_guid_t fdt_guid = EFI_FDT_GUID; +static const efi_guid_t acpi_guid = EFI_ACPI_TABLE_GUID; static const efi_guid_t smbios_guid = SMBIOS_TABLE_GUID; static int hw_memcmp(const void *buf1, const void *buf2, size_t length) @@ -79,6 +80,9 @@ efi_status_t EFIAPI efi_main(efi_handle_t handle, if (!hw_memcmp(&systable->tables[i].guid, &fdt_guid, sizeof(efi_guid_t))) con_out->output_string(con_out, L"Have device tree\n"); + if (!hw_memcmp(&systable->tables[i].guid, &acpi_guid, + sizeof(efi_guid_t))) + con_out->output_string(con_out, L"Have ACPI 2.0 table\n"); if (!hw_memcmp(&systable->tables[i].guid, &smbios_guid, sizeof(efi_guid_t))) con_out->output_string(con_out, L"Have SMBIOS table\n"); From 73149164f4cd07051018f423cd8a47165eb8156b Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 27 Jun 2018 20:38:05 -0700 Subject: [PATCH 8/9] x86: doc: Update EFI loader support CONFIG_EFI_LOADER is fully supported on x86 now. Signed-off-by: Bin Meng Reviewed-by: Simon Glass Reviewed-by: Alexander Graf --- doc/README.x86 | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/doc/README.x86 b/doc/README.x86 index 9f657df6bf..9162ea17d8 100644 --- a/doc/README.x86 +++ b/doc/README.x86 @@ -1136,9 +1136,34 @@ EFI Support U-Boot supports booting as a 32-bit or 64-bit EFI payload, e.g. with UEFI. This is enabled with CONFIG_EFI_STUB to boot from both 32-bit and 64-bit UEFI BIOS. U-Boot can also run as an EFI application, with CONFIG_EFI_APP. -The CONFIG_EFI_LOADER option, where U-Booot provides an EFI environment to +The CONFIG_EFI_LOADER option, where U-Boot provides an EFI environment to the kernel (i.e. replaces UEFI completely but provides the same EFI run-time -services) is not currently supported on x86. +services) is supported too. For example, we can even use 'bootefi' command +to load a 'u-boot-payload.efi', see below test logs on QEMU. + + => load ide 0 3000000 u-boot-payload.efi + 489787 bytes read in 138 ms (3.4 MiB/s) + => bootefi 3000000 + Scanning disk ide.blk#0... + Found 2 disks + WARNING: booting without device tree + ## Starting EFI application at 03000000 ... + U-Boot EFI Payload + + + U-Boot 2018.07-rc2 (Jun 23 2018 - 17:12:58 +0800) + + CPU: x86_64, vendor AMD, device 663h + DRAM: 2 GiB + MMC: + Video: 1024x768x32 + Model: EFI x86 Payload + Net: e1000: 52:54:00:12:34:56 + + Warning: e1000#0 using MAC address from ROM + eth0: e1000#0 + No controllers found + Hit any key to stop autoboot: 0 See README.u-boot_on_efi and README.uefi for details of EFI support in U-Boot. From 40144260a9c8c5228500824ad9b7b19597a4bb0b Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 27 Jun 2018 20:38:06 -0700 Subject: [PATCH 9/9] doc: vxworks: Mention chain-loading an x86 kernel via 'bootefi' This updates the doc to mention chain-loading an x86 kernel via 'bootefi' command, along with several typos fix. Signed-off-by: Bin Meng Reviewed-by: Simon Glass Reviewed-by: Alexander Graf --- doc/README.vxworks | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/doc/README.vxworks b/doc/README.vxworks index 1aa8e44f42..3e08711207 100644 --- a/doc/README.vxworks +++ b/doc/README.vxworks @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0+ # # Copyright (C) 2013, Miao Yan -# Copyright (C) 2015, Bin Meng +# Copyright (C) 2015-2018, Bin Meng VxWorks Support =============== @@ -15,10 +15,13 @@ For booting old kernels (6.9.x) on PowerPC and ARM, and all kernel versions on other architectures, 'bootvx' shall be used. For booting VxWorks 7 kernels on PowerPC and ARM, 'bootm' shall be used. +With CONFIG_EFI_LOADER option, it's possible to chain load a VxWorks x86 kernel +via the UEFI boot loader application for VxWorks loaded by 'bootefi' command. + VxWorks 7 on PowerPC and ARM --------------------------- -From VxWorks 7, VxWorks starts adopting device tree as its hardware decription -mechansim (for PowerPC and ARM), thus requiring boot interface changes. +From VxWorks 7, VxWorks starts adopting device tree as its hardware description +mechanism (for PowerPC and ARM), thus requiring boot interface changes. This section will describe the new interface. For PowerPC, the calling convention of the new VxWorks entry point conforms to @@ -53,6 +56,9 @@ gatewayip, hostname, othbootargs. When using 'bootm', just define "bootargs" in the environment and U-Boot will handle bootline fix up for the kernel dtb automatically. +When using 'bootefi' to chain load an x86 kernel, the UEFI boot loader +application for VxWorks takes care of the kernel bootline preparation. + Serial console -------------- It's very common that VxWorks BSPs configure a different baud rate for the @@ -63,9 +69,9 @@ look like VxWorks hangs somewhere as nothing outputs on the serial console. x86-specific information ------------------------ -Before loading an x86 kernel, one additional environment variable need to be -provided. This is "vx_phys_mem_base", which represent the physical memory -base address of VxWorks. +Before direct loading an x86 kernel via 'bootvx', one additional environment +variable need to be provided. This is "vx_phys_mem_base", which represent the +physical memory base address of VxWorks. Check VxWorks kernel configuration to look for LOCAL_MEM_LOCAL_ADRS. For VxWorks 7, this is normally a virtual address and you need find out its