diff options
author | Tom Rini <trini@konsulko.com> | 2025-04-03 11:43:38 -0600 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2025-04-03 11:43:38 -0600 |
commit | 1f2a3d066c99f57675162ce09586e9de30407f1b (patch) | |
tree | 40bfceab01cc1c6a035eb66792638149400db1ef /arch/x86/lib | |
parent | 39ff722b3ee0bd569388a3b89c59899511ac1a24 (diff) | |
parent | a3d255d996b346c527962926ff80343e02ae8f00 (diff) |
Merge patch series "x86: Improve operation under QEMU"
Simon Glass <sjg@chromium.org> says:
U-Boot can start and boot an OS in both qemu-x86 and qemu-x86_64 but it
is not perfect.
With both builds, executing the VESA ROM causes an intermittent hang, at
least on some AMD CPUs.
With qemu-x86_64 kvm cannot be used since the move to long mode (64-bit)
is done in a way that works on real hardware but not with QEMU. This
means that performance is 4-5x slower than it could be, at least on my
CPU.
We can work around the first problem by using Bochs, which is anyway a
better choice than VESA for QEMU. The second can be addressed by using
the same descriptor across the jump to long mode.
With an MTRR fix this allows booting into Ubuntu on qemu-x86_64
In v3 some e820 patches are included to make booting reliable and avoid
ACPI tables being dropped. Also, several MTTR problems are addressed, to
support memory sizes above 4GB reliably.
Link: https://lore.kernel.org/all/20250315142643.2600605-1-sjg@chromium.org/
Diffstat (limited to 'arch/x86/lib')
-rw-r--r-- | arch/x86/lib/Makefile | 2 | ||||
-rw-r--r-- | arch/x86/lib/bios.c | 27 | ||||
-rw-r--r-- | arch/x86/lib/bios_interrupts.c | 8 | ||||
-rw-r--r-- | arch/x86/lib/e820.c | 70 | ||||
-rw-r--r-- | arch/x86/lib/i8259.c | 2 | ||||
-rw-r--r-- | arch/x86/lib/spl.c | 4 | ||||
-rw-r--r-- | arch/x86/lib/tables.c | 9 | ||||
-rw-r--r-- | arch/x86/lib/zimage.c | 34 |
8 files changed, 112 insertions, 44 deletions
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 43e6a1de77d..a908356e8a6 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -26,7 +26,9 @@ obj-y += e820.o obj-y += init_helpers.o obj-y += interrupts.o obj-y += lpc-uclass.o +ifndef CONFIG_XPL_BUILD obj-y += mpspec.o +endif obj-$(CONFIG_$(PHASE_)ACPIGEN) += acpi_nhlt.o obj-y += northbridge-uclass.o obj-$(CONFIG_I8259_PIC) += i8259.o diff --git a/arch/x86/lib/bios.c b/arch/x86/lib/bios.c index 03f7360032c..de4578666fb 100644 --- a/arch/x86/lib/bios.c +++ b/arch/x86/lib/bios.c @@ -5,6 +5,9 @@ * Copyright (C) 2007 Advanced Micro Devices, Inc. * Copyright (C) 2009-2010 coresystems GmbH */ + +#define LOG_CATEGRORY LOGC_ARCH + #include <compiler.h> #include <bios_emul.h> #include <irq_func.h> @@ -228,7 +231,11 @@ static void vbe_set_graphics(int vesa_mode, struct vesa_state *mode_info) { unsigned char *framebuffer; - mode_info->video_mode = (1 << 14) | vesa_mode; + /* + * bit 14 is linear-framebuffer mode + * bit 15 means don't clear the display + */ + mode_info->video_mode = (1 << 14) | (1 << 15) | vesa_mode; vbe_get_mode_info(mode_info); framebuffer = (unsigned char *)(ulong)mode_info->vesa.phys_base_ptr; @@ -298,16 +305,14 @@ asmlinkage int interrupt_handler(u32 intnumber, u32 gsfs, u32 dses, cs = cs_ip >> 16; flags = stackflags; -#ifdef CONFIG_REALMODE_DEBUG - debug("oprom: INT# 0x%x\n", intnumber); - debug("oprom: eax: %08x ebx: %08x ecx: %08x edx: %08x\n", - eax, ebx, ecx, edx); - debug("oprom: ebp: %08x esp: %08x edi: %08x esi: %08x\n", - ebp, esp, edi, esi); - debug("oprom: ip: %04x cs: %04x flags: %08x\n", - ip, cs, flags); - debug("oprom: stackflags = %04x\n", stackflags); -#endif + log_debug("oprom: INT# 0x%x\n", intnumber); + log_debug("oprom: eax: %08x ebx: %08x ecx: %08x edx: %08x\n", + eax, ebx, ecx, edx); + log_debug("oprom: ebp: %08x esp: %08x edi: %08x esi: %08x\n", + ebp, esp, edi, esi); + log_debug("oprom: ip: %04x cs: %04x flags: %08x\n", + ip, cs, flags); + log_debug("oprom: stackflags = %04x\n", stackflags); /* * Fetch arguments from the stack and put them to a place diff --git a/arch/x86/lib/bios_interrupts.c b/arch/x86/lib/bios_interrupts.c index b2cf1527b1c..e0c2284a901 100644 --- a/arch/x86/lib/bios_interrupts.c +++ b/arch/x86/lib/bios_interrupts.c @@ -7,6 +7,8 @@ * Copyright (C) 2007-2009 coresystems GmbH */ +#define LOG_CATEGRORY LOGC_ARCH + #include <log.h> #include <asm/pci.h> #include "bios_emul.h" @@ -198,10 +200,8 @@ int int1a_handler(void) dm_pci_write_config32(dev, reg, dword); break; } -#ifdef CONFIG_REALMODE_DEBUG - debug("0x%x: bus %d devfn 0x%x reg 0x%x val 0x%x\n", func, - bus, devfn, reg, M.x86.R_ECX); -#endif + log_debug("0x%x: bus %d devfn 0x%x reg 0x%x val 0x%x\n", func, + bus, devfn, reg, M.x86.R_ECX); M.x86.R_EAX &= 0xffff00ff; /* Clear AH */ M.x86.R_EAX |= PCIBIOS_SUCCESSFUL; retval = 1; diff --git a/arch/x86/lib/e820.c b/arch/x86/lib/e820.c index d478b7486e3..bcc5f6f3044 100644 --- a/arch/x86/lib/e820.c +++ b/arch/x86/lib/e820.c @@ -3,13 +3,39 @@ * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com> */ +#define LOG_CATEGORY LOGC_ARCH + #include <efi_loader.h> #include <lmb.h> +#include <log.h> #include <asm/e820.h> #include <asm/global_data.h> DECLARE_GLOBAL_DATA_PTR; +static const char *const e820_type_name[E820_COUNT] = { + [E820_RAM] = "RAM", + [E820_RESERVED] = "Reserved", + [E820_ACPI] = "ACPI", + [E820_NVS] = "ACPI NVS", + [E820_UNUSABLE] = "Unusable", +}; + +void e820_dump(struct e820_entry *entries, uint count) +{ + int i; + + printf("%12s %10s %s\n", "Addr", "Size", "Type"); + for (i = 0; i < count; i++) { + struct e820_entry *entry = &entries[i]; + + printf("%12llx %10llx %s\n", entry->addr, entry->size, + entry->type < E820_COUNT ? + e820_type_name[entry->type] : + simple_itoa(entry->type)); + } +} + /* * Install a default e820 table with 4 entries as follows: * @@ -37,6 +63,50 @@ __weak unsigned int install_e820_map(unsigned int max_entries, return 4; } +void e820_init(struct e820_ctx *ctx, struct e820_entry *entries, + int max_entries) +{ + memset(ctx, '\0', sizeof(*ctx)); + ctx->entries = entries; + ctx->max_entries = max_entries; +} + +void e820_add(struct e820_ctx *ctx, enum e820_type type, u64 addr, u64 size) +{ + struct e820_entry *entry = &ctx->entries[ctx->count++]; + + if (ctx->count <= ctx->max_entries) { + entry->addr = addr; + entry->size = size; + entry->type = type; + } + ctx->addr = addr + size; +} + +void e820_next(struct e820_ctx *ctx, enum e820_type type, u64 size) +{ + e820_add(ctx, type, ctx->addr, size); +} + +void e820_to_addr(struct e820_ctx *ctx, enum e820_type type, u64 addr) +{ + e820_next(ctx, type, addr - ctx->addr); +} + +int e820_finish(struct e820_ctx *ctx) +{ + if (ctx->count > ctx->max_entries) { + printf("e820 has %d entries but room for only %d\n", ctx->count, + ctx->max_entries); + panic("e820 table too large"); + } + log_debug("e820 map installed, n=%d\n", ctx->count); + if (_DEBUG) + e820_dump(ctx->entries, ctx->count); + + return ctx->count; +} + #if CONFIG_IS_ENABLED(EFI_LOADER) void efi_add_known_memory(void) { diff --git a/arch/x86/lib/i8259.c b/arch/x86/lib/i8259.c index 465ff70146f..088f78f4661 100644 --- a/arch/x86/lib/i8259.c +++ b/arch/x86/lib/i8259.c @@ -13,6 +13,8 @@ * Programmable Interrupt Controllers. */ +#define LOG_CATEGORY UCLASS_IRQ + #include <log.h> #include <asm/io.h> #include <asm/i8259.h> diff --git a/arch/x86/lib/spl.c b/arch/x86/lib/spl.c index 7a033505101..0a6a761987e 100644 --- a/arch/x86/lib/spl.c +++ b/arch/x86/lib/spl.c @@ -84,8 +84,6 @@ static int x86_spl_init(void) log_debug("x86 spl starting\n"); if (IS_ENABLED(TPL)) ret = x86_cpu_reinit_f(); - else - ret = x86_cpu_init_f(); ret = spl_init(); if (ret) { log_debug("spl_init() failed (err=%d)\n", ret); @@ -283,7 +281,7 @@ void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image) { int ret; - printf("Jumping to 64-bit U-Boot: Note many features are missing\n"); + log_debug("Jumping to 64-bit U-Boot\n"); ret = cpu_jump_to_64bit_uboot(spl_image->entry_point); debug("ret=%d\n", ret); hang(); diff --git a/arch/x86/lib/tables.c b/arch/x86/lib/tables.c index 44fe80c5224..ec52992209f 100644 --- a/arch/x86/lib/tables.c +++ b/arch/x86/lib/tables.c @@ -45,6 +45,13 @@ struct table_info { int align; }; +/* QEMU's tables include quite a bit of empty space */ +#ifdef CONFIG_QEMU +#define ACPI_SIZE (192 << 10) +#else +#define ACPI_SIZE SZ_64K +#endif + static struct table_info table_list[] = { #ifdef CONFIG_GENERATE_PIRQ_TABLE { "pirq", write_pirq_routing_table }, @@ -60,7 +67,7 @@ static struct table_info table_list[] = { * that the calculation of gd->table_end works properly */ #ifdef CONFIG_GENERATE_ACPI_TABLE - { "acpi", write_acpi_tables, BLOBLISTT_ACPI_TABLES, SZ_64K, SZ_4K}, + { "acpi", write_acpi_tables, BLOBLISTT_ACPI_TABLES, ACPI_SIZE, SZ_4K}, #endif #ifdef CONFIG_GENERATE_SMBIOS_TABLE /* diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c index ba7a008fec7..65bccdae9b2 100644 --- a/arch/x86/lib/zimage.c +++ b/arch/x86/lib/zimage.c @@ -222,7 +222,7 @@ struct boot_params *load_zimage(char *image, unsigned long kernel_size, else *load_addressp = ZIMAGE_LOAD_ADDR; - printf("Building boot_params at 0x%8.8lx\n", (ulong)setup_base); + printf("Building boot_params at %lx\n", (ulong)setup_base); memset(setup_base, 0, sizeof(*setup_base)); setup_base->hdr = params->hdr; @@ -298,10 +298,13 @@ int setup_zimage(struct boot_params *setup_base, char *cmd_line, int auto_boot, hdr->type_of_loader = 0x80; /* U-Boot version 0 */ if (initrd_addr) { printf("Initial RAM disk at linear address " - "0x%08lx, size %ld bytes\n", - initrd_addr, initrd_size); + "%lx, size %lx (%ld bytes)\n", + initrd_addr, initrd_size, initrd_size); hdr->ramdisk_image = initrd_addr; + setup_base->ext_ramdisk_image = 0; + setup_base->ext_ramdisk_size = 0; + setup_base->ext_cmd_line_ptr = 0; hdr->ramdisk_size = initrd_size; } } @@ -372,8 +375,7 @@ int zboot_load(struct bootm_info *bmi) struct boot_params *from = (struct boot_params *)bmi->base_ptr; base_ptr = (struct boot_params *)DEFAULT_SETUP_BASE; - log_debug("Building boot_params at 0x%8.8lx\n", - (ulong)base_ptr); + log_debug("Building boot_params at %lx\n", (ulong)base_ptr); memset(base_ptr, '\0', sizeof(*base_ptr)); base_ptr->hdr = from->hdr; } else { @@ -474,14 +476,6 @@ static void print_num64(const char *name, u64 value) printf("%-20s: %llx\n", name, value); } -static const char *const e820_type_name[E820_COUNT] = { - [E820_RAM] = "RAM", - [E820_RESERVED] = "Reserved", - [E820_ACPI] = "ACPI", - [E820_NVS] = "ACPI NVS", - [E820_UNUSABLE] = "Unusable", -}; - static const char *const bootloader_id[] = { "LILO", "Loadlin", @@ -569,24 +563,14 @@ void zimage_dump(struct bootm_info *bmi, bool show_cmdline) { struct boot_params *base_ptr; struct setup_header *hdr; - int i; base_ptr = bmi->base_ptr; printf("Setup located at %p:\n\n", base_ptr); print_num64("ACPI RSDP addr", base_ptr->acpi_rsdp_addr); printf("E820: %d entries\n", base_ptr->e820_entries); - if (base_ptr->e820_entries) { - printf("%12s %10s %s\n", "Addr", "Size", "Type"); - for (i = 0; i < base_ptr->e820_entries; i++) { - struct e820_entry *entry = &base_ptr->e820_map[i]; - - printf("%12llx %10llx %s\n", entry->addr, entry->size, - entry->type < E820_COUNT ? - e820_type_name[entry->type] : - simple_itoa(entry->type)); - } - } + if (base_ptr->e820_entries) + e820_dump(base_ptr->e820_map, base_ptr->e820_entries); hdr = &base_ptr->hdr; print_num("Setup sectors", hdr->setup_sects); |