diff options
49 files changed, 803 insertions, 298 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2dbe6325f33..0f27e67abb9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -565,7 +565,7 @@ coreboot test.py: - export USE_LABGRID_SJG=1 # export verbose="-v" - ${SRC}/test/py/test.py --role ${ROLE} --build-dir "${OUT}" - --capture=tee-sys -k "not bootstd" || ret=$? + --capture=tee-sys -k "not bootstd ${TEST_PY_TEST_SPEC}" || ret=$? - U_BOOT_BOARD_IDENTITY="${ROLE}" u-boot-test-release || true - if [[ $ret -ne 0 ]]; then exit $ret; @@ -702,3 +702,9 @@ vf2: variables: ROLE: vf2 <<: *lab_dfn + +qemu-x86_64: + variables: + ROLE: qemu-x86_64 + TEST_PY_TEST_SPEC: "and not sleep" + <<: *lab_dfn diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index a8b21406ac0..c373b14df30 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -364,3 +364,27 @@ long locate_coreboot_table(void) return addr; } + +static bool has_cpuid(void) +{ + return flag_is_changeable_p(X86_EFLAGS_ID); +} + +static uint cpu_cpuid_extended_level(void) +{ + return cpuid_eax(0x80000000); +} + +int cpu_phys_address_size(void) +{ + if (!has_cpuid()) + return 32; + + if (cpu_cpuid_extended_level() >= 0x80000008) + return cpuid_eax(0x80000008) & 0xff; + + if (cpuid_edx(1) & (CPUID_FEATURE_PAE | CPUID_FEATURE_PSE36)) + return 36; + + return 32; +} diff --git a/arch/x86/cpu/i386/call64.S b/arch/x86/cpu/i386/call64.S index 424732fa3fa..a9d3f16a6ad 100644 --- a/arch/x86/cpu/i386/call64.S +++ b/arch/x86/cpu/i386/call64.S @@ -7,6 +7,7 @@ */ #include <asm/msr-index.h> +#include <asm/processor.h> #include <asm/processor-flags.h> .code32 @@ -21,17 +22,19 @@ cpu_call64: * ecx - target */ cli + pushl $0 /* top 64-bits of target */ push %ecx /* arg2 = target */ push %edx /* arg1 = setup_base */ mov %eax, %ebx - /* Load new GDT with the 64bit segments using 32bit descriptor */ - leal gdt, %eax - movl %eax, gdt+2 - lgdt gdt + # disable paging + movl %cr0, %eax + andl $~X86_CR0_PG, %eax + movl %eax, %cr0 /* Enable PAE mode */ - movl $(X86_CR4_PAE), %eax + movl %cr4, %eax + orl $X86_CR4_PAE, %eax movl %eax, %cr4 /* Enable the boot page tables */ @@ -44,12 +47,6 @@ cpu_call64: btsl $_EFER_LME, %eax wrmsr - /* After gdt is loaded */ - xorl %eax, %eax - lldt %ax - movl $0x20, %eax - ltr %ax - /* * Setup for the jump to 64bit mode * @@ -62,22 +59,18 @@ cpu_call64: */ pop %esi /* setup_base */ - pushl $0x10 - leal lret_target, %eax - pushl %eax - /* Enter paged protected Mode, activating Long Mode */ - movl $(X86_CR0_PG | X86_CR0_PE), %eax + movl %cr0, %eax + orl $X86_CR0_PG, %eax movl %eax, %cr0 /* Jump from 32bit compatibility mode into 64bit mode. */ - lret + ljmp $(X86_GDT_ENTRY_64BIT_CS * X86_GDT_ENTRY_SIZE), $lret_target -code64: +.code64 lret_target: - pop %eax /* target */ - mov %eax, %eax /* Clear bits 63:32 */ - jmp *%eax /* Jump to the 64-bit target */ + pop %rax /* target */ + jmp *%rax /* Jump to the 64-bit target */ .globl call64_stub_size call64_stub_size: diff --git a/arch/x86/cpu/i386/cpu.c b/arch/x86/cpu/i386/cpu.c index a51a24498a7..ee6dbeb5c48 100644 --- a/arch/x86/cpu/i386/cpu.c +++ b/arch/x86/cpu/i386/cpu.c @@ -35,10 +35,6 @@ DECLARE_GLOBAL_DATA_PTR; -#define CPUID_FEATURE_PAE BIT(6) -#define CPUID_FEATURE_PSE36 BIT(17) -#define CPUID_FEAURE_HTT BIT(28) - /* * Constructor for a conventional segment GDT (or LDT) entry * This is a macro so it can be used in initialisers @@ -160,6 +156,9 @@ void arch_setup_gd(gd_t *new_gd) gdt_addr[X86_GDT_ENTRY_16BIT_FLAT_CS] = GDT_ENTRY(0x809b, 0, 0xfffff); gdt_addr[X86_GDT_ENTRY_16BIT_FLAT_DS] = GDT_ENTRY(0x8093, 0, 0xfffff); + gdt_addr[X86_GDT_ENTRY_64BIT_CS] = GDT_ENTRY(0xaf9b, 0, 0xfffff); + gdt_addr[X86_GDT_ENTRY_64BIT_TS1] = GDT_ENTRY(0x8980, 0, 0xfffff); + gdt_addr[X86_GDT_ENTRY_64BIT_TS2] = 0; load_gdt(gdt_addr, X86_GDT_NUM_ENTRIES); load_ds(X86_GDT_ENTRY_32BIT_DS); @@ -409,25 +408,6 @@ static void setup_identity(void) } } -static uint cpu_cpuid_extended_level(void) -{ - return cpuid_eax(0x80000000); -} - -int cpu_phys_address_size(void) -{ - if (!has_cpuid()) - return 32; - - if (cpu_cpuid_extended_level() >= 0x80000008) - return cpuid_eax(0x80000008) & 0xff; - - if (cpuid_edx(1) & (CPUID_FEATURE_PAE | CPUID_FEATURE_PSE36)) - return 36; - - return 32; -} - static void setup_mtrr(void) { u64 mtrr_cap; @@ -589,6 +569,13 @@ int cpu_has_64bit(void) #define PAGETABLE_BASE 0x80000 #define PAGETABLE_SIZE (6 * 4096) +#define _PRES BIT(0) /* present */ +#define _RW BIT(1) /* write allowed */ +#define _US BIT(2) /* user-access allowed */ +#define _A BIT(5) /* has been accessed */ +#define _DT BIT(6) /* has been written to */ +#define _PS BIT(7) /* indicates 2MB page size here */ + /** * build_pagetable() - build a flat 4GiB page table structure for 64-bti mode * @@ -601,15 +588,17 @@ static void build_pagetable(uint32_t *pgtable) memset(pgtable, '\0', PAGETABLE_SIZE); /* Level 4 needs a single entry */ - pgtable[0] = (ulong)&pgtable[1024] + 7; + pgtable[0] = (ulong)&pgtable[1024] + _PRES + _RW + _US + _A; /* Level 3 has one 64-bit entry for each GiB of memory */ for (i = 0; i < 4; i++) - pgtable[1024 + i * 2] = (ulong)&pgtable[2048] + 0x1000 * i + 7; + pgtable[1024 + i * 2] = (ulong)&pgtable[2048] + 0x1000 * i + + _PRES + _RW + _US + _A; /* Level 2 has 2048 64-bit entries, each repesenting 2MiB */ for (i = 0; i < 2048; i++) - pgtable[2048 + i * 2] = 0x183 + (i << 21UL); + pgtable[2048 + i * 2] = _PRES + _RW + _US + _PS + _A + _DT + + (i << 21UL); } int cpu_jump_to_64bit(ulong setup_base, ulong target) diff --git a/arch/x86/cpu/mtrr.c b/arch/x86/cpu/mtrr.c index 07ea89162de..7a0f00b9b8f 100644 --- a/arch/x86/cpu/mtrr.c +++ b/arch/x86/cpu/mtrr.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ /* * (C) Copyright 2014 Google, Inc + * Portions added from coreboot * * Memory Type Range Regsters - these are used to tell the CPU whether * memory is cacheable and if so the cache write mode to use. @@ -16,6 +17,7 @@ * since the MTRR registers are sometimes in flux. */ +#include <cpu.h> #include <cpu_func.h> #include <log.h> #include <sort.h> @@ -39,6 +41,27 @@ static const char *const mtrr_type_name[MTRR_TYPE_COUNT] = { "Back", }; +u64 mtrr_to_size(u64 mask) +{ + u64 size; + + size = ~mask & ((1ULL << cpu_phys_address_size()) - 1); + size |= (1 << 12) - 1; + size += 1; + + return size; +} + +u64 mtrr_to_mask(u64 size) +{ + u64 mask; + + mask = ~(size - 1); + mask &= (1ull << cpu_phys_address_size()) - 1; + + return mask; +} + /* Prepare to adjust MTRRs */ void mtrr_open(struct mtrr_state *state, bool do_caches) { @@ -68,11 +91,9 @@ void mtrr_close(struct mtrr_state *state, bool do_caches) static void set_var_mtrr(uint reg, uint type, uint64_t start, uint64_t size) { - u64 mask; + u64 mask = mtrr_to_mask(size); wrmsrl(MTRR_PHYS_BASE_MSR(reg), start | type); - mask = ~(size - 1); - mask &= (1ULL << CONFIG_CPU_ADDR_BITS) - 1; wrmsrl(MTRR_PHYS_MASK_MSR(reg), mask | MTRR_PHYS_MASK_VALID); } @@ -184,30 +205,80 @@ int mtrr_commit(bool do_caches) return 0; } -int mtrr_add_request(int type, uint64_t start, uint64_t size) +/* fms: find most significant bit set (from Linux) */ +static inline uint fms(uint val) +{ + uint ret; + + __asm__("bsrl %1,%0\n\t" + "jnz 1f\n\t" + "movl $0,%0\n" + "1:" : "=r" (ret) : "mr" (val)); + + return ret; +} + +/* + * fms64: find most significant bit set in a 64-bit word + * As samples, fms64(0x0) = 0; fms64(0x4400) = 14; + * fms64(0x40400000000) = 42. + */ +static uint fms64(uint64_t val) +{ + u32 hi = (u32)(val >> 32); + + if (!hi) + return fms((u32)val); + + return fms(hi) + 32; +} + +int mtrr_add_request(int type, u64 base, uint64_t size) { struct mtrr_request *req; - uint64_t mask; + u64 mask; debug("%s: count=%d\n", __func__, gd->arch.mtrr_req_count); if (!gd->arch.has_mtrr) return -ENOSYS; - if (!is_power_of_2(size)) - return -EINVAL; - - if (gd->arch.mtrr_req_count == MAX_MTRR_REQUESTS) - return -ENOSPC; - req = &gd->arch.mtrr_req[gd->arch.mtrr_req_count++]; - req->type = type; - req->start = start; - req->size = size; - debug("%d: type=%d, %08llx %08llx\n", gd->arch.mtrr_req_count - 1, - req->type, req->start, req->size); - mask = ~(req->size - 1); - mask &= (1ULL << CONFIG_CPU_ADDR_BITS) - 1; - mask |= MTRR_PHYS_MASK_VALID; - debug(" %016llx %016llx\n", req->start | req->type, mask); + while (size) { + uint addr_lsb; + uint size_msb; + u64 mtrr_size; + + addr_lsb = fls64(base); + size_msb = fms64(size); + + /* + * All MTRR entries need to have their base aligned to the + * mask size. The maximum size is calculated by a function of + * the min base bit set and maximum size bit set. + * Algorithm is from coreboot + */ + if (!addr_lsb || addr_lsb > size_msb) + mtrr_size = 1ull << size_msb; + else + mtrr_size = 1ull << addr_lsb; + log_debug("addr_lsb %x size_msb %x mtrr_size %llx\n", + addr_lsb, size_msb, mtrr_size); + + if (gd->arch.mtrr_req_count == MAX_MTRR_REQUESTS) + return -ENOSPC; + req = &gd->arch.mtrr_req[gd->arch.mtrr_req_count++]; + req->type = type; + req->start = base; + req->size = mtrr_size; + log_debug("%d: type=%d, %08llx %08llx ", + gd->arch.mtrr_req_count - 1, req->type, req->start, + req->size); + mask = mtrr_to_mask(req->size); + mask |= MTRR_PHYS_MASK_VALID; + log_debug(" %016llx %016llx\n", req->start | req->type, mask); + + size -= mtrr_size; + base += mtrr_size; + } return 0; } @@ -360,9 +431,7 @@ int mtrr_list(int reg_count, int cpu_select) base = info.mtrr[i].base; mask = info.mtrr[i].mask; - size = ~mask & ((1ULL << CONFIG_CPU_ADDR_BITS) - 1); - size |= (1 << 12) - 1; - size += 1; + size = mtrr_to_size(mask); valid = mask & MTRR_PHYS_MASK_VALID; type = mtrr_type_name[base & MTRR_BASE_TYPE_MASK]; printf("%d %-5s %-12s %016llx %016llx %016llx\n", i, diff --git a/arch/x86/cpu/qemu/dram.c b/arch/x86/cpu/qemu/dram.c index 62a301c0fd3..ba3638e6acc 100644 --- a/arch/x86/cpu/qemu/dram.c +++ b/arch/x86/cpu/qemu/dram.c @@ -4,7 +4,9 @@ */ #include <init.h> +#include <spl.h> #include <asm/global_data.h> +#include <asm/mtrr.h> #include <asm/post.h> #include <asm/arch/qemu.h> #include <linux/sizes.h> @@ -44,6 +46,22 @@ int dram_init(void) gd->ram_size += qemu_get_high_memory_size(); post_code(POST_DRAM); + if (xpl_phase() == PHASE_BOARD_F) { + u64 total = gd->ram_size; + int ret; + + if (total > SZ_2G + SZ_1G) + total += SZ_1G; + ret = mtrr_add_request(MTRR_TYPE_WRBACK, 0, total); + if (ret != -ENOSYS) { + if (ret) + return log_msg_ret("mta", ret); + ret = mtrr_commit(false); + if (ret) + return log_msg_ret("mtc", ret); + } + } + return 0; } diff --git a/arch/x86/cpu/qemu/e820.c b/arch/x86/cpu/qemu/e820.c index 17a04f86479..078d1d86b02 100644 --- a/arch/x86/cpu/qemu/e820.c +++ b/arch/x86/cpu/qemu/e820.c @@ -6,6 +6,7 @@ * (C) Copyright 2019 Bin Meng <bmeng.cn@gmail.com> */ +#include <bloblist.h> #include <env_internal.h> #include <malloc.h> #include <asm/e820.h> @@ -19,51 +20,34 @@ unsigned int install_e820_map(unsigned int max_entries, struct e820_entry *entries) { u64 high_mem_size; - int n = 0; + struct e820_ctx ctx; - entries[n].addr = 0; - entries[n].size = ISA_START_ADDRESS; - entries[n].type = E820_RAM; - n++; + e820_init(&ctx, entries, max_entries); - entries[n].addr = ISA_START_ADDRESS; - entries[n].size = ISA_END_ADDRESS - ISA_START_ADDRESS; - entries[n].type = E820_RESERVED; - n++; + e820_next(&ctx, E820_RAM, ISA_START_ADDRESS); + e820_next(&ctx, E820_RESERVED, ISA_END_ADDRESS); /* - * since we use memalign(malloc) to allocate high memory for - * storing ACPI tables, we need to reserve them in e820 tables, - * otherwise kernel will reclaim them and data will be corrupted + * if we use bloblist to allocate high memory for storing ACPI tables, + * we need to reserve that region in e820 tables, otherwise the kernel + * will reclaim them and data will be corrupted. The ACPI tables may not + * have been written yet, so use the whole bloblist size */ - entries[n].addr = ISA_END_ADDRESS; - entries[n].size = gd->relocaddr - TOTAL_MALLOC_LEN - ISA_END_ADDRESS; - entries[n].type = E820_RAM; - n++; - - /* for simplicity, reserve entire malloc space */ - entries[n].addr = gd->relocaddr - TOTAL_MALLOC_LEN; - entries[n].size = TOTAL_MALLOC_LEN; - entries[n].type = E820_RESERVED; - n++; - - entries[n].addr = gd->relocaddr; - entries[n].size = qemu_get_low_memory_size() - gd->relocaddr; - entries[n].type = E820_RESERVED; - n++; - - entries[n].addr = CONFIG_PCIE_ECAM_BASE; - entries[n].size = CONFIG_PCIE_ECAM_SIZE; - entries[n].type = E820_RESERVED; - n++; + if (IS_ENABLED(CONFIG_BLOBLIST_TABLES)) { + e820_to_addr(&ctx, E820_RAM, (ulong)gd->bloblist); + e820_next(&ctx, E820_ACPI, bloblist_get_total_size()); + } else { + /* If using memalign() reserve that whole region instead */ + e820_to_addr(&ctx, E820_RAM, gd->relocaddr - TOTAL_MALLOC_LEN); + e820_next(&ctx, E820_ACPI, TOTAL_MALLOC_LEN); + } + e820_to_addr(&ctx, E820_RAM, qemu_get_low_memory_size()); + e820_add(&ctx, E820_RESERVED, CONFIG_PCIE_ECAM_BASE, + CONFIG_PCIE_ECAM_SIZE); high_mem_size = qemu_get_high_memory_size(); - if (high_mem_size) { - entries[n].addr = SZ_4G; - entries[n].size = high_mem_size; - entries[n].type = E820_RAM; - n++; - } + if (high_mem_size) + e820_add(&ctx, E820_RAM, SZ_4G, high_mem_size); - return n; + return e820_finish(&ctx); } diff --git a/arch/x86/cpu/qemu/qemu.c b/arch/x86/cpu/qemu/qemu.c index 563f63e2bc8..e846ccd44aa 100644 --- a/arch/x86/cpu/qemu/qemu.c +++ b/arch/x86/cpu/qemu/qemu.c @@ -15,14 +15,21 @@ #include <asm/arch/qemu.h> #include <asm/u-boot-x86.h> -static bool i440fx; - #if CONFIG_IS_ENABLED(QFW_PIO) U_BOOT_DRVINFO(x86_qfw_pio) = { .name = "qfw_pio", }; #endif +static bool is_i440fx(void) +{ + u16 device; + + pci_read_config16(PCI_BDF(0, 0, 0), PCI_DEVICE_ID, &device); + + return device == PCI_DEVICE_ID_INTEL_82441; +} + static void enable_pm_piix(void) { u8 en; @@ -50,16 +57,17 @@ static void enable_pm_ich9(void) void qemu_chipset_init(void) { - u16 device, xbcs; + bool i440fx; + u16 xbcs; int pam, i; + i440fx = is_i440fx(); + /* * i440FX and Q35 chipset have different PAM register offset, but with * the same bitfield layout. Here we determine the offset based on its * PCI device ID. */ - pci_read_config16(PCI_BDF(0, 0, 0), PCI_DEVICE_ID, &device); - i440fx = (device == PCI_DEVICE_ID_INTEL_82441); pam = i440fx ? I440FX_PAM : Q35_PAM; /* @@ -123,7 +131,7 @@ int mp_determine_pci_dstirq(int bus, int dev, int func, int pirq) { u8 irq; - if (i440fx) { + if (is_i440fx()) { /* * Not like most x86 platforms, the PIRQ[A-D] on PIIX3 are not * connected to I/O APIC INTPIN#16-19. Instead they are routed diff --git a/arch/x86/cpu/start.S b/arch/x86/cpu/start.S index 0ef27cc5a00..385a691265e 100644 --- a/arch/x86/cpu/start.S +++ b/arch/x86/cpu/start.S @@ -254,7 +254,7 @@ multiboot_header: * GDT is setup in a safe location in RAM */ gdt_ptr2: - .word 0x1f /* limit (31 bytes = 4 GDT entries - 1) */ + .word gdt2_end - gdt_ptr2 - 1 .long gdt_rom2 /* base */ /* Some CPUs are picky about GDT alignment... */ @@ -313,4 +313,6 @@ gdt_rom2: .byte 0x93 /* access */ .byte 0xcf /* flags + limit_high */ .byte 0x00 /* base_high */ +gdt2_end: + #endif diff --git a/arch/x86/cpu/start16.S b/arch/x86/cpu/start16.S index 865a49731e5..8d9acb193e0 100644 --- a/arch/x86/cpu/start16.S +++ b/arch/x86/cpu/start16.S @@ -61,7 +61,7 @@ idt_ptr: * GDT is setup in a safe location in RAM */ gdt_ptr: - .word 0x1f /* limit (31 bytes = 4 GDT entries - 1) */ + .word gdt_end - gdt_rom - 1 .long BOOT_SEG + gdt_rom /* base */ /* Some CPUs are picky about GDT alignment... */ @@ -120,3 +120,4 @@ gdt_rom: .byte 0x93 /* access */ .byte 0xcf /* flags + limit_high */ .byte 0x00 /* base_high */ +gdt_end: diff --git a/arch/x86/cpu/x86_64/cpu.c b/arch/x86/cpu/x86_64/cpu.c index 71bc07f872a..25ae92c702f 100644 --- a/arch/x86/cpu/x86_64/cpu.c +++ b/arch/x86/cpu/x86_64/cpu.c @@ -59,11 +59,6 @@ int x86_cpu_reinit_f(void) return 0; } -int cpu_phys_address_size(void) -{ - return CONFIG_CPU_ADDR_BITS; -} - int x86_cpu_init_f(void) { return 0; diff --git a/arch/x86/include/asm/bootparam.h b/arch/x86/include/asm/bootparam.h index ac4865300f1..657d920b14f 100644 --- a/arch/x86/include/asm/bootparam.h +++ b/arch/x86/include/asm/bootparam.h @@ -122,6 +122,14 @@ struct efi_info { __u32 efi_memmap_hi; }; +/* Gleaned from OFW's set-parameters in cpu/x86/pc/linux.fth */ +struct olpc_ofw_header { + __u32 ofw_magic; /* OFW signature */ + __u32 ofw_version; + __u32 cif_handler; /* callback into OFW */ + __u32 irq_desc_table; +} __attribute__((packed)); + /* The so-called "zeropage" */ struct boot_params { struct screen_info screen_info; /* 0x000 */ @@ -134,7 +142,12 @@ struct boot_params { __u8 hd0_info[16]; /* obsolete! */ /* 0x080 */ __u8 hd1_info[16]; /* obsolete! */ /* 0x090 */ struct sys_desc_table sys_desc_table; /* 0x0a0 */ - __u8 _pad4[144]; /* 0x0b0 */ + struct olpc_ofw_header olpc_ofw_header; /* 0x0b0 */ + __u32 ext_ramdisk_image; /* 0x0c0 */ + __u32 ext_ramdisk_size; /* 0x0c4 */ + __u32 ext_cmd_line_ptr; /* 0x0c8 */ + __u8 _pad4[112]; /* 0x0cc */ + __u32 cc_blob_address; /* 0x13c */ struct edid_info edid_info; /* 0x140 */ struct efi_info efi_info; /* 0x1c0 */ __u32 alt_mem_k; /* 0x1e0 */ diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h index fd389d4024c..5d24c17f8a3 100644 --- a/arch/x86/include/asm/cpu.h +++ b/arch/x86/include/asm/cpu.h @@ -58,6 +58,10 @@ enum { X86_SYSCON_PUNIT, /* Power unit */ }; +#define CPUID_FEATURE_PAE BIT(6) +#define CPUID_FEATURE_PSE36 BIT(17) +#define CPUID_FEAURE_HTT BIT(28) + struct cpuid_result { uint32_t eax; uint32_t ebx; @@ -105,68 +109,47 @@ static inline struct cpuid_result cpuid_ext(int op, unsigned ecx) return result; } -/* - * CPUID functions returning a single datum - */ -static inline unsigned int cpuid_eax(unsigned int op) +static inline void native_cpuid(unsigned int *eax, unsigned int *ebx, + unsigned int *ecx, unsigned int *edx) { - unsigned int eax; - - __asm__("mov %%ebx, %%edi;" - "cpuid;" - "mov %%edi, %%ebx;" - : "=a" (eax) - : "0" (op) - : "ecx", "edx", "edi"); - return eax; + /* ecx is often an input as well as an output. */ + asm volatile("cpuid" + : "=a" (*eax), + "=b" (*ebx), + "=c" (*ecx), + "=d" (*edx) + : "0" (*eax), "2" (*ecx) + : "memory"); } -static inline unsigned int cpuid_ebx(unsigned int op) -{ - unsigned int eax, ebx; - - __asm__("mov %%ebx, %%edi;" - "cpuid;" - "mov %%ebx, %%esi;" - "mov %%edi, %%ebx;" - : "=a" (eax), "=S" (ebx) - : "0" (op) - : "ecx", "edx", "edi"); - return ebx; +#define native_cpuid_reg(reg) \ +static inline unsigned int cpuid_##reg(unsigned int op) \ +{ \ + unsigned int eax = op, ebx, ecx = 0, edx; \ + \ + native_cpuid(&eax, &ebx, &ecx, &edx); \ + \ + return reg; \ } -static inline unsigned int cpuid_ecx(unsigned int op) -{ - unsigned int eax, ecx; - - __asm__("mov %%ebx, %%edi;" - "cpuid;" - "mov %%edi, %%ebx;" - : "=a" (eax), "=c" (ecx) - : "0" (op) - : "edx", "edi"); - return ecx; -} +/* + * Native CPUID functions returning a single datum. + */ +native_cpuid_reg(eax) +native_cpuid_reg(ebx) +native_cpuid_reg(ecx) +native_cpuid_reg(edx) -static inline unsigned int cpuid_edx(unsigned int op) +#if CONFIG_IS_ENABLED(X86_64) +static inline int flag_is_changeable_p(u32 flag) { - unsigned int eax, edx; - - __asm__("mov %%ebx, %%edi;" - "cpuid;" - "mov %%edi, %%ebx;" - : "=a" (eax), "=d" (edx) - : "0" (op) - : "ecx", "edi"); - return edx; + return 1; } - -#if !CONFIG_IS_ENABLED(X86_64) - +#else /* Standard macro to see if a specific flag is changeable */ -static inline int flag_is_changeable_p(uint32_t flag) +static inline int flag_is_changeable_p(u32 flag) { - uint32_t f1, f2; + u32 f1, f2; asm( "pushfl\n\t" @@ -181,9 +164,9 @@ static inline int flag_is_changeable_p(uint32_t flag) "popfl\n\t" : "=&r" (f1), "=&r" (f2) : "ir" (flag)); - return ((f1^f2) & flag) != 0; + return ((f1 ^ f2) & flag) != 0; } -#endif +#endif /* X86_64 */ /** * cpu_enable_paging_pae() - Enable PAE-paging diff --git a/arch/x86/include/asm/e820.h b/arch/x86/include/asm/e820.h index 1ab709abfc8..a535818b2d5 100644 --- a/arch/x86/include/asm/e820.h +++ b/arch/x86/include/asm/e820.h @@ -3,6 +3,8 @@ #define E820MAX 128 /* number of entries in E820MAP */ +#ifdef __ASSEMBLY__ + #define E820_RAM 1 #define E820_RESERVED 2 #define E820_ACPI 3 @@ -10,9 +12,21 @@ #define E820_UNUSABLE 5 #define E820_COUNT 6 /* Number of types */ -#ifndef __ASSEMBLY__ +#else + #include <linux/types.h> +/* Available e820 memory-region types */ +enum e820_type { + E820_RAM = 1, + E820_RESERVED, + E820_ACPI, + E820_NVS, + E820_UNUSABLE, + + E820_COUNT, +}; + struct e820_entry { __u64 addr; /* start of memory segment */ __u64 size; /* size of memory segment */ @@ -22,11 +36,82 @@ struct e820_entry { #define ISA_START_ADDRESS 0xa0000 #define ISA_END_ADDRESS 0x100000 +/** + * Context to use for e820_add() + * + * @entries: Table being filled in + * @addr: Current address we are up to + * @count: Number of entries added to @entries so far + * @max_entries: Maximum number of entries allowed + */ +struct e820_ctx { + struct e820_entry *entries; + u64 addr; + int count; + int max_entries; +}; + +/** + * e820_init() - Start setting up an e820 table + * + * @ctx: Context to set up + * @entries: Place to put entries + * @max_entries: Maximum size of @entries + */ +void e820_init(struct e820_ctx *ctx, struct e820_entry *entries, + int max_entries); + +/** + * e820_add() - Add an entry to the table + * + * @ctx: Context + * @type: Type of entry + * @addr: Start address of entry + * @size Size of entry + */ +void e820_add(struct e820_ctx *ctx, enum e820_type type, u64 addr, u64 size); + +/** + * e820_to_addr() - Add an entry that covers the space up to a given address + * + * @ctx: Context + * @type: Type of entry + * @end_addr: Address where the entry should finish + */ +void e820_to_addr(struct e820_ctx *ctx, enum e820_type type, u64 end_addr); + +/** + * e820_next() - Add an entry that carries on from the last one + * + * @ctx: Context + * @type: Type of entry + * @size Size of entry + */ +void e820_next(struct e820_ctx *ctx, enum e820_type type, u64 size); + +/** + * e820_finish() - Finish the table + * + * Checks the table is not too large, panics if so + * + * @ctx: Context + * Returns: Number of entries + */ +int e820_finish(struct e820_ctx *ctx); + /* Implementation-defined function to install an e820 map */ unsigned int install_e820_map(unsigned int max_entries, struct e820_entry *); /** + * e820_dump() - Dump the e820 table + * + * @entries: Pointer to start of table + * @count: Number of entries in the table + */ +void e820_dump(struct e820_entry *entries, uint count); + +/** * cb_install_e820_map() - Install e820 map provided by coreboot sysinfo * * This should be used when booting from coreboot, since in that case the @@ -39,6 +124,14 @@ unsigned int install_e820_map(unsigned int max_entries, unsigned int cb_install_e820_map(unsigned int max_entries, struct e820_entry *entries); +/** + * e820_dump() - Dump an e820 table + * + * @entries: Pointer to first entry + * @count: Number of entries in the table + */ +void e820_dump(struct e820_entry *entries, uint count); + #endif /* __ASSEMBLY__ */ #endif /* _ASM_X86_E820_H */ diff --git a/arch/x86/include/asm/interrupt.h b/arch/x86/include/asm/interrupt.h index e23fb2c8e72..c689fc23d08 100644 --- a/arch/x86/include/asm/interrupt.h +++ b/arch/x86/include/asm/interrupt.h @@ -10,6 +10,7 @@ #ifndef __ASM_INTERRUPT_H_ #define __ASM_INTERRUPT_H_ 1 +#include <stdbool.h> #include <asm/types.h> #define SYS_NUM_IRQS 16 diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h index af5f9a11980..39dc7b33aa0 100644 --- a/arch/x86/include/asm/msr.h +++ b/arch/x86/include/asm/msr.h @@ -59,15 +59,14 @@ static inline unsigned long long native_read_tscp(unsigned int *aux) * edx:eax, while for x86_64 it doesn't mean rdx:rax or edx:eax. Instead, * it means rax *or* rdx. */ -#ifdef CONFIG_X86_64 -#define DECLARE_ARGS(val, low, high) unsigned low, high -#define EAX_EDX_VAL(val, low, high) ((low) | ((u64)(high) << 32)) -#define EAX_EDX_ARGS(val, low, high) "a" (low), "d" (high) +#if CONFIG_IS_ENABLED(X86_64) +/* Using 64-bit values saves one instruction clearing the high half of low */ +#define DECLARE_ARGS(val, low, high) unsigned long low, high +#define EAX_EDX_VAL(val, low, high) ((low) | (high) << 32) #define EAX_EDX_RET(val, low, high) "=a" (low), "=d" (high) #else #define DECLARE_ARGS(val, low, high) unsigned long long val #define EAX_EDX_VAL(val, low, high) (val) -#define EAX_EDX_ARGS(val, low, high) "A" (val) #define EAX_EDX_RET(val, low, high) "=A" (val) #endif diff --git a/arch/x86/include/asm/mtrr.h b/arch/x86/include/asm/mtrr.h index 2e995f54061..67e897daa25 100644 --- a/arch/x86/include/asm/mtrr.h +++ b/arch/x86/include/asm/mtrr.h @@ -91,6 +91,22 @@ struct mtrr_info { }; /** + * mtrr_to_size() - Convert a mask to a size value + * + * @mask: Value of the mask register + * Return: associated size + */ +u64 mtrr_to_size(u64 mask); + +/** + * mtrr_to_mask() - Convert a size to a mask value + * + * @size: Value of the size register + * Return: associated mask, without MTRR_PHYS_MASK_VALID + */ +u64 mtrr_to_mask(u64 size); + +/** * mtrr_open() - Prepare to adjust MTRRs * * Use mtrr_open() passing in a structure - this function will init it. Then diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index d7b68367861..ad8240be387 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -18,7 +18,10 @@ #define X86_GDT_ENTRY_16BIT_DS 6 #define X86_GDT_ENTRY_16BIT_FLAT_CS 7 #define X86_GDT_ENTRY_16BIT_FLAT_DS 8 -#define X86_GDT_NUM_ENTRIES 9 +#define X86_GDT_ENTRY_64BIT_CS 9 +#define X86_GDT_ENTRY_64BIT_TS1 10 +#define X86_GDT_ENTRY_64BIT_TS2 11 +#define X86_GDT_NUM_ENTRIES 12 #define X86_GDT_SIZE (X86_GDT_NUM_ENTRIES * X86_GDT_ENTRY_SIZE) 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); diff --git a/boot/bootdev-uclass.c b/boot/bootdev-uclass.c index c39147940b6..3791ebfcb42 100644 --- a/boot/bootdev-uclass.c +++ b/boot/bootdev-uclass.c @@ -168,8 +168,10 @@ int bootdev_find_in_blk(struct udevice *dev, struct udevice *blk, */ /* if there are bootable partitions, scan only those */ - } else if (iter->first_bootable >= 0 && + } else if ((iter->flags & BOOTFLOWIF_ONLY_BOOTABLE) && + iter->first_bootable >= 0 && (iter->first_bootable ? !info.bootable : iter->part != 1)) { + log_debug("Skipping non-bootable partition %d\n", iter->part); return log_msg_ret("boot", -EINVAL); } else { ret = fs_set_blk_dev_with_part(desc, bflow->part); @@ -577,6 +579,9 @@ int bootdev_next_label(struct bootflow_iter *iter, struct udevice **devp, struct udevice *dev; log_debug("next\n"); + if (iter->cur_label >= 0 && !iter->labels[iter->cur_label]) + return log_msg_ret("fil", -ENODEV); + for (dev = NULL; !dev && iter->labels[++iter->cur_label];) { const char *label = iter->labels[iter->cur_label]; int ret; diff --git a/boot/bootflow.c b/boot/bootflow.c index 58a1afa7a75..4054a966af8 100644 --- a/boot/bootflow.c +++ b/boot/bootflow.c @@ -942,8 +942,9 @@ int bootflow_cmdline_auto(struct bootflow *bflow, const char *arg) *buf = '\0'; if (!strcmp("earlycon", arg) && info.type == SERIAL_CHIP_16550_COMPATIBLE) { snprintf(buf, sizeof(buf), - "uart8250,mmio32,%#lx,%dn8", info.addr, - info.baudrate); + "uart8250,%s,%#lx,%dn8", + info.addr_space == SERIAL_ADDRESS_SPACE_IO ? "io" : + "mmio", info.addr, info.baudrate); } else if (!strcmp("earlycon", arg) && info.type == SERIAL_CHIP_PL01X) { snprintf(buf, sizeof(buf), "pl011,mmio32,%#lx,%dn8", info.addr, @@ -954,7 +955,7 @@ int bootflow_cmdline_auto(struct bootflow *bflow, const char *arg) } if (!*buf) { - printf("Unknown param '%s\n", arg); + printf("Unknown param '%s'\n", arg); return -ENOENT; } diff --git a/cmd/acpi.c b/cmd/acpi.c index 094d9d4e858..bb243202009 100644 --- a/cmd/acpi.c +++ b/cmd/acpi.c @@ -7,6 +7,7 @@ #include <display_options.h> #include <log.h> #include <mapmem.h> +#include <tables_csum.h> #include <acpi/acpi_table.h> #include <asm/acpi_table.h> #include <asm/global_data.h> @@ -15,6 +16,17 @@ DECLARE_GLOBAL_DATA_PTR; +static const char *show_checksum(void *ptr, uint size, bool chksums) +{ + uint checksum; + + if (!chksums) + return ""; + checksum = table_compute_checksum(ptr, size); + + return checksum ? " bad" : " OK"; +} + /** * dump_hdr() - Dump an ACPI header * @@ -23,16 +35,17 @@ DECLARE_GLOBAL_DATA_PTR; * * @hdr: ACPI header to dump */ -static void dump_hdr(struct acpi_table_header *hdr) +static void dump_hdr(struct acpi_table_header *hdr, bool chksums) { bool has_hdr = memcmp(hdr->signature, "FACS", ACPI_NAME_LEN); printf("%.*s %16lx %5x", ACPI_NAME_LEN, hdr->signature, (ulong)map_to_sysmem(hdr), hdr->length); if (has_hdr) { - printf(" v%02d %.6s %.8s %x %.4s %x\n", hdr->revision, + printf(" v%02d %.6s %.8s %x %.4s %x%s\n", hdr->revision, hdr->oem_id, hdr->oem_table_id, hdr->oem_revision, - hdr->creator_id, hdr->creator_revision); + hdr->creator_id, hdr->creator_revision, + show_checksum(hdr, hdr->length, chksums)); } else { printf("\n"); } @@ -52,22 +65,22 @@ static int dump_table_name(const char *sig) return 0; } -static void list_fadt(struct acpi_fadt *fadt) +static void list_fadt(struct acpi_fadt *fadt, bool chksums) { if (fadt->header.revision >= 3 && fadt->x_dsdt) - dump_hdr(nomap_sysmem(fadt->x_dsdt, 0)); + dump_hdr(nomap_sysmem(fadt->x_dsdt, 0), chksums); else if (fadt->dsdt) - dump_hdr(nomap_sysmem(fadt->dsdt, 0)); - if (!IS_ENABLED(CONFIG_X86) && + dump_hdr(nomap_sysmem(fadt->dsdt, 0), chksums); + if (!IS_ENABLED(CONFIG_X86) && !IS_ENABLED(CONFIG_SANDBOX) && !(fadt->flags & ACPI_FADT_HW_REDUCED_ACPI)) log_err("FADT not ACPI-hardware-reduced-compliant\n"); if (fadt->header.revision >= 3 && fadt->x_firmware_ctrl) - dump_hdr(nomap_sysmem(fadt->x_firmware_ctrl, 0)); + dump_hdr(nomap_sysmem(fadt->x_firmware_ctrl, 0), chksums); else if (fadt->firmware_ctrl) - dump_hdr(nomap_sysmem(fadt->firmware_ctrl, 0)); + dump_hdr(nomap_sysmem(fadt->firmware_ctrl, 0), chksums); } -static void list_rsdt(struct acpi_rsdp *rsdp) +static void list_rsdt(struct acpi_rsdp *rsdp, bool chksums) { int len, i, count; struct acpi_rsdt *rsdt; @@ -75,11 +88,11 @@ static void list_rsdt(struct acpi_rsdp *rsdp) if (rsdp->rsdt_address) { rsdt = nomap_sysmem(rsdp->rsdt_address, 0); - dump_hdr(&rsdt->header); + dump_hdr(&rsdt->header, chksums); } if (rsdp->xsdt_address) { xsdt = nomap_sysmem(rsdp->xsdt_address, 0); - dump_hdr(&xsdt->header); + dump_hdr(&xsdt->header, chksums); len = xsdt->header.length - sizeof(xsdt->header); count = len / sizeof(u64); } else if (rsdp->rsdt_address) { @@ -100,24 +113,28 @@ static void list_rsdt(struct acpi_rsdp *rsdp) if (!entry) break; hdr = nomap_sysmem(entry, 0); - dump_hdr(hdr); + dump_hdr(hdr, chksums); if (!memcmp(hdr->signature, "FACP", ACPI_NAME_LEN)) - list_fadt((struct acpi_fadt *)hdr); + list_fadt((struct acpi_fadt *)hdr, chksums); } } -static void list_rsdp(struct acpi_rsdp *rsdp) +static void list_rsdp(struct acpi_rsdp *rsdp, bool chksums) { - printf("RSDP %16lx %5x v%02d %.6s\n", (ulong)map_to_sysmem(rsdp), - rsdp->length, rsdp->revision, rsdp->oem_id); - list_rsdt(rsdp); + printf("RSDP %16lx %5x v%02d %.6s%s%s\n", + (ulong)map_to_sysmem(rsdp), rsdp->length, rsdp->revision, + rsdp->oem_id, show_checksum(rsdp, 0x14, chksums), + show_checksum(rsdp, rsdp->length, chksums)); + list_rsdt(rsdp, chksums); } static int do_acpi_list(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { struct acpi_rsdp *rsdp; + bool chksums; + chksums = argc >= 2 && !strcmp("-c", argv[1]); rsdp = map_sysmem(gd_acpi_start(), 0); if (!rsdp) { printf("No ACPI tables present\n"); @@ -125,7 +142,7 @@ static int do_acpi_list(struct cmd_tbl *cmdtp, int flag, int argc, } printf("Name Base Size Detail\n" "---- ---------------- ----- ----------------------------\n"); - list_rsdp(rsdp); + list_rsdp(rsdp, chksums); return 0; } @@ -187,13 +204,13 @@ static int do_acpi_dump(struct cmd_tbl *cmdtp, int flag, int argc, } U_BOOT_LONGHELP(acpi, - "list - list ACPI tables\n" + "list [-c] - list ACPI tables [check checksums]\n" "acpi items [-d] - List/dump each piece of ACPI data from devices\n" "acpi set [<addr>] - Set or show address of ACPI tables\n" "acpi dump <name> - Dump ACPI table"); U_BOOT_CMD_WITH_SUBCMDS(acpi, "ACPI tables", acpi_help_text, - U_BOOT_SUBCMD_MKENT(list, 1, 1, do_acpi_list), + U_BOOT_SUBCMD_MKENT(list, 2, 1, do_acpi_list), U_BOOT_SUBCMD_MKENT(items, 2, 1, do_acpi_items), U_BOOT_SUBCMD_MKENT(set, 2, 1, do_acpi_set), U_BOOT_SUBCMD_MKENT(dump, 2, 1, do_acpi_dump)); diff --git a/cmd/bootflow.c b/cmd/bootflow.c index 6d0be320bdb..5349abe49b5 100644 --- a/cmd/bootflow.c +++ b/cmd/bootflow.c @@ -173,7 +173,7 @@ static int do_bootflow_scan(struct cmd_tbl *cmdtp, int flag, int argc, std->cur_bootflow = NULL; - flags = 0; + flags = BOOTFLOWIF_ONLY_BOOTABLE; if (list) flags |= BOOTFLOWIF_SHOW; if (all) diff --git a/cmd/x86/mtrr.c b/cmd/x86/mtrr.c index b2afb598c73..289865515ef 100644 --- a/cmd/x86/mtrr.c +++ b/cmd/x86/mtrr.c @@ -13,8 +13,8 @@ static int do_mtrr_set(int cpu_select, uint reg, int argc, char *const argv[]) { const char *typename = argv[0]; - uint32_t start, size; - uint64_t base, mask; + u64 start, size; + u64 base, mask; int type = -1; bool valid; int ret; @@ -26,13 +26,12 @@ static int do_mtrr_set(int cpu_select, uint reg, int argc, char *const argv[]) printf("Invalid type name %s\n", typename); return CMD_RET_USAGE; } - start = hextoul(argv[1], NULL); - size = hextoul(argv[2], NULL); + start = hextoull(argv[1], NULL); + size = hextoull(argv[2], NULL); base = start | type; valid = native_read_msr(MTRR_PHYS_MASK_MSR(reg)) & MTRR_PHYS_MASK_VALID; - mask = ~((uint64_t)size - 1); - mask &= (1ULL << CONFIG_CPU_ADDR_BITS) - 1; + mask = mtrr_to_mask(size); if (valid) mask |= MTRR_PHYS_MASK_VALID; diff --git a/configs/qemu-x86_64_defconfig b/configs/qemu-x86_64_defconfig index 792ba06c2b8..58b1fbf132d 100644 --- a/configs/qemu-x86_64_defconfig +++ b/configs/qemu-x86_64_defconfig @@ -1,13 +1,13 @@ CONFIG_X86=y CONFIG_TEXT_BASE=0x1110000 -CONFIG_SYS_MALLOC_F_LEN=0x1000 -CONFIG_BLOBLIST_SIZE_RELOC=0x20000 +CONFIG_SYS_MALLOC_F_LEN=0x1800 +CONFIG_BLOBLIST_SIZE_RELOC=0x40000 CONFIG_NR_DRAM_BANKS=8 CONFIG_ENV_SIZE=0x40000 CONFIG_MAX_CPUS=2 CONFIG_SPL_DM_SPI=y CONFIG_DEFAULT_DEVICE_TREE="qemu-x86_i440fx" -CONFIG_SPL_SYS_MALLOC_F_LEN=0x3000 +CONFIG_SPL_SYS_MALLOC_F_LEN=0x4800 CONFIG_SPL_TEXT_BASE=0xfffd0000 CONFIG_DEBUG_UART_BASE=0x3f8 CONFIG_DEBUG_UART_CLOCK=1843200 @@ -41,9 +41,7 @@ CONFIG_SPL_NO_BSS_LIMIT=y CONFIG_SPL_BOARD_INIT=y CONFIG_SPL_SYS_MALLOC_SIMPLE=y CONFIG_SPL_CPU=y -CONFIG_SPL_ENV_SUPPORT=y CONFIG_SPL_DM_SPI_FLASH=y -CONFIG_SPL_NET=y CONFIG_SPL_PCI=y CONFIG_SPL_PCH=y CONFIG_SPL_RTC=y @@ -54,6 +52,7 @@ CONFIG_CMD_MEM_SEARCH=y CONFIG_CMD_IDE=y CONFIG_CMD_SPI=y CONFIG_CMD_USB=y +CONFIG_CMD_CAT=y # CONFIG_CMD_SETEXPR is not set CONFIG_BOOTP_BOOTFILESIZE=y CONFIG_CMD_EFIDEBUG=y @@ -61,6 +60,9 @@ CONFIG_CMD_TIME=y CONFIG_CMD_BOOTSTAGE=y CONFIG_CMD_EXT4_WRITE=y CONFIG_ENV_OVERWRITE=y +CONFIG_ENV_IS_IN_FAT=y +CONFIG_ENV_FAT_INTERFACE="virtio" +CONFIG_ENV_FAT_DEVICE_AND_PART="0:1" CONFIG_SYS_RELOC_GD_ENV_ADDR=y CONFIG_USE_BOOTFILE=y CONFIG_BOOTFILE="bzImage" @@ -83,11 +85,11 @@ CONFIG_SYS_NS16550_PORT_MAPPED=y CONFIG_SPI=y CONFIG_USB_KEYBOARD=y CONFIG_CONSOLE_TRUETYPE=y -CONFIG_FRAMEBUFFER_SET_VESA_MODE=y -CONFIG_FRAMEBUFFER_VESA_MODE_USER=y -CONFIG_FRAMEBUFFER_VESA_MODE=0x144 +CONFIG_VIDEO_BOCHS=y +# CONFIG_VIDEO_VESA is not set CONFIG_CONSOLE_SCROLL_LINES=5 CONFIG_SPL_VIDEO=y # CONFIG_SPL_USE_TINY_PRINTF is not set CONFIG_GENERATE_ACPI_TABLE=y +CONFIG_CMD_DHRYSTONE=y # CONFIG_GZIP is not set diff --git a/configs/qemu-x86_defconfig b/configs/qemu-x86_defconfig index 0b0e10c795f..099d3f32d1b 100644 --- a/configs/qemu-x86_defconfig +++ b/configs/qemu-x86_defconfig @@ -1,7 +1,7 @@ CONFIG_X86=y CONFIG_TEXT_BASE=0xFFF00000 CONFIG_SYS_MALLOC_F_LEN=0x1000 -CONFIG_BLOBLIST_SIZE_RELOC=0x20000 +CONFIG_BLOBLIST_SIZE_RELOC=0x40000 CONFIG_NR_DRAM_BANKS=8 CONFIG_ENV_SIZE=0x40000 CONFIG_MAX_CPUS=2 @@ -34,6 +34,7 @@ CONFIG_CMD_MEM_SEARCH=y CONFIG_CMD_IDE=y CONFIG_CMD_SPI=y CONFIG_CMD_USB=y +CONFIG_CMD_CAT=y # CONFIG_CMD_SETEXPR is not set CONFIG_BOOTP_BOOTFILESIZE=y CONFIG_CMD_EFIDEBUG=y @@ -42,6 +43,9 @@ CONFIG_CMD_BOOTSTAGE=y CONFIG_CMD_EXT4_WRITE=y CONFIG_MAC_PARTITION=y CONFIG_ENV_OVERWRITE=y +CONFIG_ENV_IS_IN_FAT=y +CONFIG_ENV_FAT_INTERFACE="virtio" +CONFIG_ENV_FAT_DEVICE_AND_PART="0:1" CONFIG_SYS_RELOC_GD_ENV_ADDR=y CONFIG_USE_BOOTFILE=y CONFIG_BOOTFILE="bzImage" @@ -62,9 +66,9 @@ CONFIG_SYS_NS16550_PORT_MAPPED=y CONFIG_SPI=y CONFIG_USB_KEYBOARD=y CONFIG_CONSOLE_TRUETYPE=y -CONFIG_FRAMEBUFFER_SET_VESA_MODE=y -CONFIG_FRAMEBUFFER_VESA_MODE_USER=y -CONFIG_FRAMEBUFFER_VESA_MODE=0x144 +CONFIG_VIDEO_BOCHS=y +# CONFIG_VIDEO_VESA is not set CONFIG_CONSOLE_SCROLL_LINES=5 CONFIG_GENERATE_ACPI_TABLE=y +CONFIG_CMD_DHRYSTONE=y # CONFIG_GZIP is not set diff --git a/doc/develop/bootstd/overview.rst b/doc/develop/bootstd/overview.rst index e3ce97cc4f5..9fe5630ab16 100644 --- a/doc/develop/bootstd/overview.rst +++ b/doc/develop/bootstd/overview.rst @@ -235,8 +235,9 @@ means that `default_get_bootflow()` is used. This simply obtains the block device and calls a bootdev helper function to do the rest. The implementation of `bootdev_find_in_blk()` checks the partition table, and attempts to read a file from a filesystem on the partition number given by the -`@iter->part` parameter. If there are any bootable partitions in the table, -then only bootable partitions are considered. +`@iter->part` parameter. If there are any bootable partitions in the table and +the BOOTFLOWIF_ONLY_BOOTABLE flag is set in `@iter->flags`, then only bootable +partitions are considered. Each bootdev has a priority, which indicates the order in which it is used, if `boot_targets` is not used. Faster bootdevs are used first, since they are diff --git a/doc/usage/cmd/acpi.rst b/doc/usage/cmd/acpi.rst index 9f30972fe53..e652968d584 100644 --- a/doc/usage/cmd/acpi.rst +++ b/doc/usage/cmd/acpi.rst @@ -11,7 +11,7 @@ Synopsis :: - acpi list + acpi list [-c] acpi items [-d] acpi dump <name> acpi set <address> @@ -38,6 +38,9 @@ List the ACPI tables that have been generated. Each table has a 4-character table name (e.g. SSDT, FACS) and has a format defined by the `ACPI specification`_. +The `-c` flag tells U-Boot to verify the checksums and print 'OK' or 'BAD' next +to each table. + U-Boot does not currently support decoding the tables. Unlike devicetree, ACPI tables have no regular schema and also some include bytecode, so decoding the tables requires a lot of code. @@ -259,5 +262,20 @@ pointer:: WAET bff76a3b 28 v01 BOCHS BXPC 1 BXPC 1 SSDT bff95040 c5 v02 COREv4 COREBOOT 2a CORE 20221020 +This shows checking that the checksums are correct for each table:: + + => acpi list -c + Name Base Size Detail + ---- ---------------- ----- ---------------------------- + RSDP bec9a000 24 v00 BOCHS OK OK + RSDT bec9bd4a 38 v01 BOCHS BXPC 1 BXPC 1 OK + FACP bec9bb46 74 v01 BOCHS BXPC 1 BXPC 1 OK + DSDT bec9a080 1ac6 v01 BOCHS BXPC 1 BXPC 1 OK + FACS bec9a040 40 + APIC bec9bbba 78 v03 BOCHS BXPC 1 BXPC 1 OK + HPET bec9bc32 38 v01 BOCHS BXPC 1 BXPC 1 OK + SRAT bec9bc6a b8 v01 BOCHS BXPC 1 BXPC 1 OK + WAET bec9bd22 28 v01 BOCHS BXPC 1 BXPC 1 OK + .. _`ACPI specification`: https://uefi.org/sites/default/files/resources/ACPI_6_3_final_Jan30.pdf diff --git a/drivers/misc/qfw_acpi.c b/drivers/misc/qfw_acpi.c index 0d0cf764689..ec00ba65ade 100644 --- a/drivers/misc/qfw_acpi.c +++ b/drivers/misc/qfw_acpi.c @@ -25,17 +25,18 @@ DECLARE_GLOBAL_DATA_PTR; * * @entry : BIOS linker command entry which tells where to allocate memory * (either high memory or low memory) - * @addr : The address that should be used for low memory allcation. If the + * @addr : The address that should be used for low memory allocation. If the * memory allocation request is 'ZONE_HIGH' then this parameter will * be ignored. * @return: 0 on success, or negative value on failure */ -static int bios_linker_allocate(struct udevice *dev, +static int bios_linker_allocate(struct acpi_ctx *ctx, struct udevice *dev, struct bios_linker_entry *entry, ulong *addr) { uint32_t size, align; struct fw_file *file; unsigned long aligned_addr; + struct acpi_rsdp *rsdp; align = le32_to_cpu(entry->alloc.align); /* align must be power of 2 */ @@ -58,7 +59,9 @@ static int bios_linker_allocate(struct udevice *dev, * If allocation zone is ZONE_FSEG, then we use the 'addr' passed * in which is low memory */ - if (entry->alloc.zone == BIOS_LINKER_LOADER_ALLOC_ZONE_HIGH) { + if (IS_ENABLED(CONFIG_BLOBLIST_TABLES)) { + aligned_addr = ALIGN(*addr, align); + } else if (entry->alloc.zone == BIOS_LINKER_LOADER_ALLOC_ZONE_HIGH) { aligned_addr = (unsigned long)memalign(align, size); if (!aligned_addr) { printf("error: allocating resource\n"); @@ -83,8 +86,13 @@ static int bios_linker_allocate(struct udevice *dev, (void *)aligned_addr); file->addr = aligned_addr; + rsdp = (void *)aligned_addr; + if (!strncmp(rsdp->signature, RSDP_SIG, sizeof(rsdp->signature))) + ctx->rsdp = rsdp; + /* adjust address for low memory allocation */ - if (entry->alloc.zone == BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG) + if (IS_ENABLED(CONFIG_BLOBLIST_TABLES) || + entry->alloc.zone == BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG) *addr = (aligned_addr + size); return 0; @@ -209,19 +217,23 @@ ulong write_acpi_tables(ulong addr) qfw_read_entry(dev, be16_to_cpu(file->cfg.select), size, table_loader); for (i = 0; i < (size / sizeof(*entry)); i++) { + log_content("entry %d: addr %lx\n", i, addr); entry = table_loader + i; switch (le32_to_cpu(entry->command)) { case BIOS_LINKER_LOADER_COMMAND_ALLOCATE: - ret = bios_linker_allocate(dev, entry, &addr); + log_content(" - %s\n", entry->alloc.file); + ret = bios_linker_allocate(ctx, dev, entry, &addr); if (ret) goto out; break; case BIOS_LINKER_LOADER_COMMAND_ADD_POINTER: + log_content(" - %s\n", entry->pointer.src_file); ret = bios_linker_add_pointer(dev, entry); if (ret) goto out; break; case BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM: + log_content(" - %s\n", entry->cksum.file); ret = bios_linker_add_checksum(dev, entry); if (ret) goto out; @@ -246,6 +258,16 @@ out: free(table_loader); + if (!ctx->rsdp) { + printf("error: no RSDP found\n"); + return addr; + } + struct acpi_rsdp *rsdp = ctx->rsdp; + + rsdp->length = sizeof(*rsdp); + rsdp->xsdt_address = 0; + rsdp->ext_checksum = table_compute_checksum((u8 *)rsdp, sizeof(*rsdp)); + gd_set_acpi_start(acpi_get_rsdp_addr()); return addr; diff --git a/include/acpi/acpi_table.h b/include/acpi/acpi_table.h index b8b1f1338c6..8ef19adc990 100644 --- a/include/acpi/acpi_table.h +++ b/include/acpi/acpi_table.h @@ -36,7 +36,7 @@ struct acpi_ctx; * RSDP (Root System Description Pointer) * Note: ACPI 1.0 didn't have length, xsdt_address, and ext_checksum */ -struct acpi_rsdp { +struct __packed acpi_rsdp { char signature[8]; /* RSDP signature */ u8 checksum; /* Checksum of the first 20 bytes */ char oem_id[6]; /* OEM ID */ diff --git a/include/bootflow.h b/include/bootflow.h index 480cf8a5af1..d408b8c85bd 100644 --- a/include/bootflow.h +++ b/include/bootflow.h @@ -160,6 +160,7 @@ struct bootflow_img { * before using it * @BOOTFLOWIF_ALL: Return bootflows with errors as well * @BOOTFLOWIF_HUNT: Hunt for new bootdevs using the bootdrv hunters + * @BOOTFLOWIF_ONLY_BOOTABLE: Only consider partitions marked 'bootable' * * Internal flags: * @BOOTFLOWIF_SINGLE_DEV: (internal) Just scan one bootdev @@ -176,6 +177,7 @@ enum bootflow_iter_flags_t { BOOTFLOWIF_SHOW = 1 << 1, BOOTFLOWIF_ALL = 1 << 2, BOOTFLOWIF_HUNT = 1 << 3, + BOOTFLOWIF_ONLY_BOOTABLE = BIT(4), /* * flags used internally by standard boot - do not set these when diff --git a/include/bootstd.h b/include/bootstd.h index 3398e48e88b..2bc464756dd 100644 --- a/include/bootstd.h +++ b/include/bootstd.h @@ -22,6 +22,9 @@ struct udevice; * This is attached to the (only) bootstd device, so there is only one instance * of this struct. It provides overall information about bootdevs and bootflows. * + * TODO(sjg@chromium.org): Convert prefixes, bootdev_order and env_order to use + * alist + * * @prefixes: NULL-terminated list of prefixes to use for bootflow filenames, * e.g. "/", "/boot/"; NULL if none * @bootdev_order: Order to use for bootdevs (or NULL if none), with each item diff --git a/include/mapmem.h b/include/mapmem.h index f496c96d16c..8ec03d59f0b 100644 --- a/include/mapmem.h +++ b/include/mapmem.h @@ -33,7 +33,7 @@ static inline phys_addr_t map_to_sysmem(const void *ptr) * nomap_sysmem() - pass through an address unchanged * * This is used to indicate an address which should NOT be mapped, e.g. in - * SMBIOS tables. Using this function instead of a case shows that the sandbox + * SMBIOS tables. Using this function instead of a cast shows that the sandbox * conversion has been done */ static inline void *nomap_sysmem(phys_addr_t paddr, unsigned long len) diff --git a/lib/acpi/acpi_table.c b/lib/acpi/acpi_table.c index 4ad1f56e961..12215f5d90a 100644 --- a/lib/acpi/acpi_table.c +++ b/lib/acpi/acpi_table.c @@ -66,6 +66,7 @@ int acpi_create_dmar(struct acpi_dmar *dmar, enum dmar_flags flags) dmar->host_address_width = info.address_width - 1; dmar->flags = flags; + header->checksum = table_compute_checksum(dmar, header->length); return 0; } @@ -255,8 +256,8 @@ int acpi_write_fadt(struct acpi_ctx *ctx, const struct acpi_writer *entry) header->creator_revision = 1; fadt->minor_revision = 2; - fadt->x_firmware_ctrl = map_to_sysmem(ctx->facs); - fadt->x_dsdt = map_to_sysmem(ctx->dsdt); + fadt->x_firmware_ctrl = nomap_to_sysmem(ctx->facs); + fadt->x_dsdt = nomap_to_sysmem(ctx->dsdt); if (fadt->x_firmware_ctrl < 0x100000000ULL) fadt->firmware_ctrl = fadt->x_firmware_ctrl; diff --git a/test/boot/bootdev.c b/test/boot/bootdev.c index 5f07430714e..d5499918249 100644 --- a/test/boot/bootdev.c +++ b/test/boot/bootdev.c @@ -509,6 +509,7 @@ static int bootdev_test_bootable(struct unit_test_state *uts) iter.part = 0; ut_assertok(uclass_get_device_by_name(UCLASS_BLK, "mmc1.blk", &blk)); iter.dev = blk; + iter.flags = BOOTFLOWIF_ONLY_BOOTABLE; ut_assertok(device_find_next_child(&iter.dev)); uclass_first_device(UCLASS_BOOTMETH, &bflow.method); diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c index eb7f00af39a..5f9c037ff53 100644 --- a/test/boot/bootflow.c +++ b/test/boot/bootflow.c @@ -297,8 +297,9 @@ static int bootflow_iter(struct unit_test_state *uts) /* The first device is mmc2.bootdev which has no media */ ut_asserteq(-EPROTONOSUPPORT, - bootflow_scan_first(NULL, NULL, &iter, - BOOTFLOWIF_ALL | BOOTFLOWIF_SKIP_GLOBAL, &bflow)); + bootflow_scan_first(NULL, NULL, &iter, BOOTFLOWIF_ALL | + BOOTFLOWIF_SKIP_GLOBAL | + BOOTFLOWIF_ONLY_BOOTABLE, &bflow)); ut_asserteq(2, iter.num_methods); ut_asserteq(0, iter.cur_method); ut_asserteq(0, iter.part); diff --git a/test/dm/acpi.c b/test/dm/acpi.c index 39a26bbb492..db012b6d2f1 100644 --- a/test/dm/acpi.c +++ b/test/dm/acpi.c @@ -309,6 +309,8 @@ static int dm_test_acpi_write_tables(struct unit_test_state *uts) } ut_asserteq(0, ctx.rsdt->entry[3]); ut_asserteq(0, ctx.xsdt->entry[3]); + unmap_sysmem(buf); + free(buf); return 0; } @@ -386,6 +388,8 @@ static int dm_test_acpi_ctx_and_base_tables(struct unit_test_state *uts) ut_asserteq(nomap_to_sysmem(rsdt), rsdp->rsdt_address); ut_asserteq(nomap_to_sysmem(xsdt), rsdp->xsdt_address); + unmap_sysmem(buf); + free(buf); return 0; } @@ -428,11 +432,59 @@ static int dm_test_acpi_cmd_list(struct unit_test_state *uts) ut_assert_nextline("DMAR %16lx %5zx v01 U-BOOT U-BOOTBL %x INTL 0", addr, sizeof(struct acpi_dmar), OEM_REVISION); ut_assert_console_end(); + unmap_sysmem(buf); + free(buf); return 0; } DM_TEST(dm_test_acpi_cmd_list, UTF_SCAN_PDATA | UTF_SCAN_FDT | UTF_CONSOLE); +/* Test 'acpi list -c' command */ +static int dm_test_acpi_cmd_list_chksum(struct unit_test_state *uts) +{ + struct acpi_ctx ctx; + ulong addr; + void *buf; + + buf = memalign(16, BUF_SIZE); + ut_assertnonnull(buf); + addr = map_to_sysmem(buf); + ut_assertok(setup_ctx_and_base_tables(uts, &ctx, addr)); + + ut_assertok(acpi_write_dev_tables(&ctx)); + + run_command("acpi list -c", 0); + ut_assert_nextline("Name Base Size Detail"); + ut_assert_nextline("---- ---------------- ----- ----------------------------"); + ut_assert_nextline("RSDP %16lx %5zx v02 U-BOOT OK OK", addr, + sizeof(struct acpi_rsdp)); + addr = ALIGN(addr + sizeof(struct acpi_rsdp), 16); + ut_assert_nextline("RSDT %16lx %5zx v01 U-BOOT U-BOOTBL %x INTL 0 OK", + addr, sizeof(struct acpi_table_header) + + 3 * sizeof(u32), OEM_REVISION); + addr = ALIGN(addr + sizeof(struct acpi_rsdt), 16); + ut_assert_nextline("XSDT %16lx %5zx v01 U-BOOT U-BOOTBL %x INTL 0 OK", + addr, sizeof(struct acpi_table_header) + + 3 * sizeof(u64), OEM_REVISION); + addr = ALIGN(addr + sizeof(struct acpi_xsdt), 64); + ut_assert_nextline("DMAR %16lx %5zx v01 U-BOOT U-BOOTBL %x INTL 0 OK", + addr, sizeof(struct acpi_dmar), OEM_REVISION); + addr = ALIGN(addr + sizeof(struct acpi_dmar), 16); + ut_assert_nextline("DMAR %16lx %5zx v01 U-BOOT U-BOOTBL %x INTL 0 OK", + addr, sizeof(struct acpi_dmar), OEM_REVISION); + addr = ALIGN(addr + sizeof(struct acpi_dmar), 16); + ut_assert_nextline("DMAR %16lx %5zx v01 U-BOOT U-BOOTBL %x INTL 0 OK", + addr, sizeof(struct acpi_dmar), OEM_REVISION); + ut_assert_console_end(); + ut_assert_console_end(); + unmap_sysmem(buf); + free(buf); + + return 0; +} +DM_TEST(dm_test_acpi_cmd_list_chksum, + UTF_SCAN_PDATA | UTF_SCAN_FDT | UTF_CONSOLE); + /* Test 'acpi dump' command */ static int dm_test_acpi_cmd_dump(struct unit_test_state *uts) { @@ -458,6 +510,8 @@ static int dm_test_acpi_cmd_dump(struct unit_test_state *uts) ut_assert_nextline("DMAR @ %16lx", addr); ut_assert_nextlines_are_dump(0x30); ut_assert_console_end(); + unmap_sysmem(buf); + free(buf); return 0; } @@ -642,6 +696,8 @@ static int dm_test_acpi_cmd_items(struct unit_test_state *uts) ut_assert_nextlines_are_dump(2); ut_assert_nextline("%s", ""); ut_assert_console_end(); + unmap_sysmem(buf); + free(buf); return 0; } @@ -679,6 +735,8 @@ static int dm_test_acpi_cmd_set(struct unit_test_state *uts) ut_asserteq(addr, gd_acpi_start()); ut_assert_console_end(); + unmap_sysmem(buf); + free(buf); return 0; } @@ -774,6 +832,7 @@ static int dm_test_acpi_find_table(struct unit_test_state *uts) /* Restore previous ACPI tables */ gd_set_acpi_start(acpi_start); + unmap_sysmem(buf); free(buf); return 0; diff --git a/test/py/conftest.py b/test/py/conftest.py index e59897c1f78..5aea85647af 100644 --- a/test/py/conftest.py +++ b/test/py/conftest.py @@ -334,6 +334,7 @@ def pytest_configure(config): ubconfig.dtb = build_dir + '/arch/sandbox/dts/test.dtb' ubconfig.connection_ok = True ubconfig.timing = config.getoption('timing') + ubconfig.role = config.getoption('role') env_vars = ( 'board_type', @@ -760,6 +761,26 @@ def setup_singlethread(item): if worker_id and worker_id != 'master': pytest.skip('must run single-threaded') +def setup_role(item): + """Process any 'role' marker for a test. + + Skip this test if the role does not match. + + Args: + item (pytest.Item): The pytest test item + """ + required_roles = [] + for roles in item.iter_markers('role'): + role = roles.args[0] + if role.startswith('!'): + if ubconfig.role == role[1:]: + pytest.skip(f'role "{ubconfig.role}" not supported') + return + else: + required_roles.append(role) + if required_roles and ubconfig.role not in required_roles: + pytest.skip(f'board "{ubconfig.role}" not supported') + def start_test_section(item): anchors[item.name] = log.start_section(item.name) @@ -781,6 +802,7 @@ def pytest_runtest_setup(item): setup_buildconfigspec(item) setup_requiredtool(item) setup_singlethread(item) + setup_role(item) def pytest_runtest_protocol(item, nextitem): """pytest hook: Called to execute a test. diff --git a/test/py/console_base.py b/test/py/console_base.py index 260df773bac..88d444b44b8 100644 --- a/test/py/console_base.py +++ b/test/py/console_base.py @@ -370,21 +370,30 @@ class ConsoleBase(object): output.append(self.run_command(cmd)) return output - def ctrlc(self): - """Send a CTRL-C character to U-Boot. + def send(self, msg): + """Send characters without waiting for echo, etc.""" + self.run_command(msg, wait_for_prompt=False, wait_for_echo=False, + send_nl=False) + + def ctrl(self, char): + """Send a CTRL- character to U-Boot. This is useful in order to stop execution of long-running synchronous commands such as "ums". Args: - None. - - Returns: - Nothing. + char (str): Character to send, e.g. 'C' to send Ctrl-C """ + self.log.action(f'Sending Ctrl-{char}') + self.send(chr(ord(char) - ord('@'))) - self.log.action('Sending Ctrl-C') - self.run_command(chr(3), wait_for_echo=False, send_nl=False) + def ctrlc(self): + """Send a CTRL-C character to U-Boot. + + This is useful in order to stop execution of long-running synchronous + commands such as "ums". + """ + self.ctrl('C') def wait_for(self, text): """Wait for a pattern to be emitted by U-Boot. diff --git a/test/py/pytest.ini b/test/py/pytest.ini index 26d83f83e00..361be0178ee 100644 --- a/test/py/pytest.ini +++ b/test/py/pytest.ini @@ -12,3 +12,4 @@ markers = requiredtool: U-Boot: Required host tools for a test. slow: U-Boot: Specific test will run slowly. singlethread: Cannot run in parallel + role: U-Boot: Indicates the lab 'role' which can execute this test diff --git a/test/py/tests/test_distro.py b/test/py/tests/test_distro.py new file mode 100644 index 00000000000..bdf4ab657d1 --- /dev/null +++ b/test/py/tests/test_distro.py @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright 2025 Canonical Ltd. +# Written by Simon Glass <simon.glass@canonical.com> + +import pytest + +# Enable early console so that the test can see if something goes wrong +CONSOLE = 'earlycon=uart8250,io,0x3f8 console=uart8250,io,0x3f8' + +@pytest.mark.boardspec('qemu-x86_64') +@pytest.mark.role('qemu-x86_64') +def test_distro(ubman): + """Test that of-platdata can be generated and used in sandbox""" + with ubman.log.section('boot'): + ubman.run_command('boot', wait_for_prompt=False) + + with ubman.log.section('Grub'): + # Wait for grub to come up and offset a menu + ubman.p.expect(['Try or Install Ubuntu']) + + # Press 'e' to edit the command line + ubman.log.info("Pressing 'e'") + ubman.run_command('e', wait_for_prompt=False, send_nl=False) + + # Wait until we see the editor appear + ubman.p.expect(['/casper/initrd']) + + # Go down to the 'linux' line. Avoid using down-arrow as that includes + # an Escape character, which may be parsed by Grub as such, causing it + # to return to the top menu + ubman.log.info("Going DOWN") + ubman.ctrl('N') + ubman.ctrl('N') + ubman.ctrl('N') + + # Go to end of line + ubman.log.info("Going to EOL") + ubman.ctrl('E') + + # Backspace to remove 'quiet splash' + ubman.log.info("Erasing quiet and splash") + ubman.send('\b' * len('quiet splash')) + + # Send our noisy console + ubman.log.info("Noisy console") + ubman.send(CONSOLE) + + # Tell grub to boot + ubman.log.info("boot") + ubman.ctrl('X') + ubman.p.expect(['Booting a command list']) + + with ubman.log.section('Linux'): + # Linux should start immediately + ubman.p.expect(['Linux version']) + + with ubman.log.section('Ubuntu'): + # Shortly later, we should see this banner + ubman.p.expect(['Welcome to .*Ubuntu 24.04.1 LTS.*!']) + + ubman.restart_uboot() diff --git a/test/py/tests/test_ut.py b/test/py/tests/test_ut.py index ea0c43cd4fc..b8adb597e11 100644 --- a/test/py/tests/test_ut.py +++ b/test/py/tests/test_ut.py @@ -57,6 +57,17 @@ def setup_image(ubman, devnum, part_type, img_size=20, second_part=False, stdin=spec.encode('utf-8')) return fname, mnt +def copy_partition(ubman, fsfile, outname): + """Copy a partition into a disk iamge + + Args: + ubman (ConsoleBase): U-Boot fixture + fsfile (str): Name of partition file + outname (str): Name of full-disk file to update + """ + utils.run_and_log(ubman, + f'dd if={fsfile} of={outname} bs=1M seek=1 conv=notrunc') + def setup_bootmenu_image(ubman): """Create a 20MB disk image with a single ext4 partition @@ -172,7 +183,7 @@ booti ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r} fsfile = 'ext18M.img' utils.run_and_log(ubman, f'fallocate -l 18M {fsfile}') utils.run_and_log(ubman, f'mkfs.ext4 {fsfile} -d {mnt}') - utils.run_and_log(ubman, f'dd if={fsfile} of={fname} bs=1M seek=1') + copy_partition(ubman, fsfile, fname) utils.run_and_log(ubman, f'rm -rf {mnt}') utils.run_and_log(ubman, f'rm -f {fsfile}') @@ -224,7 +235,7 @@ label Fedora-Workstation-armhfp-31-1.9 (5.3.7-301.fc31.armv7hl) utils.run_and_log(ubman, f'fallocate -l 18M {fsfile}') utils.run_and_log(ubman, f'mkfs.vfat {fsfile}') utils.run_and_log(ubman, ['sh', '-c', f'mcopy -i {fsfile} {mnt}/* ::/']) - utils.run_and_log(ubman, f'dd if={fsfile} of={fname} bs=1M seek=1') + copy_partition(ubman, fsfile, fname) utils.run_and_log(ubman, f'rm -rf {mnt}') utils.run_and_log(ubman, f'rm -f {fsfile}') @@ -562,7 +573,7 @@ def setup_efi_image(ubman): utils.run_and_log(ubman, f'fallocate -l 18M {fsfile}') utils.run_and_log(ubman, f'mkfs.vfat {fsfile}') utils.run_and_log(ubman, ['sh', '-c', f'mcopy -vs -i {fsfile} {mnt}/* ::/']) - utils.run_and_log(ubman, f'dd if={fsfile} of={fname} bs=1M seek=1') + copy_partition(ubman, fsfile, fname) utils.run_and_log(ubman, f'rm -rf {mnt}') utils.run_and_log(ubman, f'rm -f {fsfile}') |