diff --git a/arch/x86/cpu/coreboot/Kconfig b/arch/x86/cpu/coreboot/Kconfig index fa3b64f..392c258 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/intel_common/car.S b/arch/x86/cpu/intel_common/car.S index fe8dfbc..52a77bb 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 11b1ec8..c7a539d 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/cpu/qemu/Kconfig b/arch/x86/cpu/qemu/Kconfig index 31428dd..fdf558d 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 diff --git a/arch/x86/include/asm/microcode.h b/arch/x86/include/asm/microcode.h index f7b32a5..4ab7504 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/e820.c b/arch/x86/lib/e820.c index 9a9ec99..8b34f67 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) */ diff --git a/arch/x86/lib/fsp/fsp_car.S b/arch/x86/lib/fsp/fsp_car.S index 549d863..48edc83 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 */ diff --git a/cmd/bootefi.c b/cmd/bootefi.c index f55a40d..cd755b6 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/doc/README.vxworks b/doc/README.vxworks index 1aa8e44..3e08711 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 diff --git a/doc/README.x86 b/doc/README.x86 index 9f657df..9162ea1 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. diff --git a/drivers/timer/tsc_timer.c b/drivers/timer/tsc_timer.c index cf86999..747f190 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; diff --git a/include/efi_api.h b/include/efi_api.h index 094be6e..0c3dd3c 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 c66252a..d837e7b 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -215,6 +215,14 @@ efi_status_t efi_net_register(void); 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 * * Called by bootefi to make SMBIOS tables available diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index c6046e3..d6402c4 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 0000000..a4e5e53 --- /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); +} diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 50d3115..261d66d 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 /* diff --git a/lib/efi_loader/helloworld.c b/lib/efi_loader/helloworld.c index 046b46a..3b8de5b 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");