Compare commits

...

29 Commits
acpi ... qemu

Author SHA1 Message Date
Simon Glass
066165f9b3 test: Add a test for booting Ubuntu 24.04
Now that U-Boot can boot this quickly, using kvm, add a test that the
installer starts up correctly.

Use the qemu-x86_64 board in the SJG lab.

Series-to: u-boot
Series-cc: bin
Series-version: 2
Series-changes: 2
- Add more patches to support booting with kvm
- Add new patch with a test for booting Ubuntu 24.04

Cover-letter:
x86: Improve operation under QEMU
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
END

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-02-17 12:14:02 -07:00
Simon Glass
b57abc103a RFC: test/py: Deal with timeouts
The distro test takes a little longer to shut down and restart, so
add more time to this operation.

Disable the sleep command for now, as it seems to be unreliable on
QEMU with '-cpu host'.

More thought will be needed for both of these problems.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-02-17 12:14:02 -07:00
Simon Glass
56d237b07a test/py: Allow tests to be filtered by role
Some test can only be run by a particular board in a lab, e.g. because
they are loaded with an OS image used by the test. Add a way to specify
this in tests.

Series-changes: 2
- Add new patch to allow tests to be filtered by role

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-02-17 12:14:01 -07:00
Simon Glass
34051458cd test/py: Add a helper to send characters
The existing run_command() method is not great for sending things other
than U-Boot commands. Add a helper for sending arbitrary strings as well
as control characters.

Series-changes: 2
- Add new patch with a helper to send characters

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-02-17 12:14:01 -07:00
Simon Glass
ca35d5f966 scripts: Expand a few options
This gets the script to where it can boot with kvm:

- Use -cpu host with kvm so that the host CPU is used
- Show the full QEMU arguments

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-02-17 12:14:01 -07:00
Simon Glass
e9418f47b7 x86: emulation: Set an MTRR for the RAM
QEMU likes to have an MTRR set up, just like real machines. Add an MTRR
which covers the total RAM size.

This does nothing on machines without MTRRs.

Series-changes: 2
- Add new patch to set an MTRR for the RAM in QEMU

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-02-17 12:14:01 -07:00
Simon Glass
2b5821219d x86: Support MTRRs of 4GB on 32-bit machines
Use the 64-bit function to detect a power-of-two. This allows use of
a full 4GB MTRR on 32-bit machines.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-02-17 12:14:01 -07:00
Simon Glass
3b3607e577 Add a 64-bit version of is_power_of_2()
The existing function only works with ulong which is not enough on
32-bit x86 machines which need to set up MTRRs up to 4GB.

There doesn't seem to be a 64-bit version in Linux, so add one here.

Series-changes: 2
- Add new patch with a 64-bit version of is_power_of_2()

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-02-17 12:14:01 -07:00
Simon Glass
417467d331 x86: Tidy up address size in MTRR calculations
The CONFIG value should only be used when it cannot be read from the
CPU. This is particularly important when using kvm since the CPU size
depends on the host CPU.

Update set_var_mtrr() to use the correct function for this, which now
supports 64-bit operation. Ensure that the lower bits of the mask are
zeroed as required.

Series-changes: 2
- Add new patch to tidy up address size in MTRR calculations

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-02-17 12:14:01 -07:00
Simon Glass
849b044815 x86: Support CPU functions in long mode
At present it is not possible to find out the physical-address size in
long mode, so a predefined value is used.

Update the macros to support this properly, since it is important when
programming MTRRs.

Series-changes: 2
- Add new patch to support CPU functions in long mode

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-02-17 12:14:01 -07:00
Simon Glass
f7a87603b6 x86: Rename the _D dirty flag
This value happens to be used by ctype.h so chose a different name.

Series-changes: 2
- Add new patch to rename the _D dirty flag

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-02-17 12:14:01 -07:00
Simon Glass
c45106f504 x86: Use a simple jump into long mode
With the 64-bit descriptor we can use a jump instruction, rather than
pushing things on the stack.

Since the processor is in 64-bit mode by this point, pop a 64-bit value
from the stack, containing the target address.

This simplifies the code slightly, in particular its use of the stack.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-02-17 12:14:01 -07:00
Simon Glass
328d088c2b x86: Use the same GDT when jumping to long mode
Make use the existing GDT which now includes entries for 64-bit code.
Leave the interrupt descriptors alone. They can be tidied up once U-Boot
starts up.

With this, kvm mode works with QEMU.

Signed-off-by: Simon Glass <sjg@chromium.org>
Fixes: https://source.denx.de/u-boot/custodians/u-boot-dm/-/issues/31
2025-02-17 12:14:01 -07:00
Simon Glass
05e9c555b4 x86: Disable paging before changing to long mode
This is required as part of the procedure. The existing code works
because it changes the GDT at the same time, but this makes kvm
unhappy.

Update the algorithm to disable and then re-enable paging.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-02-17 12:14:01 -07:00
Simon Glass
1003f27657 x86: Tidy up the GDT size in start/16.S
Use a symbol to select the size of the GDT, rather than hard-coding a
value. This matches how it is done in start64

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-02-17 12:14:01 -07:00
Simon Glass
166b5295fc x86: Include stdbool.h in interrupt header
This makes use of a 'bool' type, so include the required header.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-02-17 12:14:01 -07:00
Simon Glass
f7872bb0a8 x86: Drop the message about features missing in 64-bit
This functions normally and has done for a while, so drop this scary
message.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-02-17 12:14:01 -07:00
Simon Glass
f3c75fc39e x86: spl: Drop duplicate CPU init
x86_cpu_init_f() is called by arch_cpu_init() a few lines below this
code. Drop the duplicate call.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-02-17 12:14:01 -07:00
Simon Glass
aa879a9345 x86: Use defines for the cache flags
Use some named flags when setting up the cache, so it is easier to see
what is going on.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-02-17 12:14:01 -07:00
Simon Glass
c2e9fe0ea7 x86: Add 64-bit entries to the GDT
At present it is not possible to execution 64-bit code without
installing an entire new Global Descriptor Table. This is inconvenient
since kvm does not seem to like switching into long mode with a new
table.

It isn't actually necessary, since we can just extend the existing
table. Add some new entries to this effect.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-02-17 12:14:01 -07:00
Simon Glass
98ea430d51 x86: Avoid clearing the VESA display
U-Boot clears the display when it starts up, so there is no need to ask
the VESA driver to do this. Fix this and add a comment explaining the
flags.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-02-17 12:14:01 -07:00
Simon Glass
26774686ac x86: Drop use of CONFIG_REALMODE_DEBUG
This option is not actually defined in Kconfig anymore. Use a normal
debug print instead, which has a similar effect.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-02-17 12:14:01 -07:00
Simon Glass
a6d6b8b7be x86: Add some log categories
Add categories for i8259 and bios files, so that log statements have the
right category.
2025-02-17 12:14:01 -07:00
Simon Glass
eac76060ec x86: Drop mpspec from the SPL build
This is not needed in SPL, so drop it.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-02-17 12:14:01 -07:00
Simon Glass
9494270349 x86: qemu: Avoid accessing BSS too early
BSS is placed in DRAM which is actually available early with QEMU. But
it is cleared by the init sequence, so values stored there are lost.

Move the system-type flag into a function, instead.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-02-17 12:14:01 -07:00
Simon Glass
ef405956c3 x86: qemu: Enable dhrystone
Provide the 'dhry' command, which helps to check that kvm is being used
properly with QEMU.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-02-17 12:14:01 -07:00
Simon Glass
b96c349afa x86: qemu: Switch to bochs display
The vesa display is widely used on hardware, but it is a bit of a pain
with QEMU. It requires executing option ROMs, which either doesn't work
with kvm, or is difficult to do in a kvm/QEMU-friendly way.

THe bochs display is probably better anyway, so switch to that. It works
fine with kvm as it doesn't need an option ROM.

Series-changes: 2
- Redo commit message

Signed-off-by: Simon Glass <sjg@chromium.org>
Fixes: https://source.denx.de/u-boot/custodians/u-boot-dm/-/issues/31
2025-02-17 12:14:01 -07:00
Simon Glass
8289ee01ea x86: Expand x86_64 early memory
The SPL and pre-reloc malloc()-space is not large enough to start up
with a display. Expand it.

Switch the order of SPL_SYS_MALLOC_F_LEN and SPL_TEXT_BASE since this
matches what 'savedefconfig' gives us.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-02-17 12:14:01 -07:00
Simon Glass
406ffc2dfc Revert "efi_memory: do not add U-Boot memory to the memory map"
A bisect of Ubuntu 2022.04 boot-failure on qemu-x86_64 resulted in this
patch. I am not sure how to investigate it.

The boot hangs at some point during booting of the install image, before
the Ubuntu logo appears.

I will sent a series with a script showing how it is run.

Series-to: u-boot
Series-cc: sughosh, trini

This reverts commit a68c9ac5d8.
2025-02-17 12:14:01 -07:00
28 changed files with 286 additions and 112 deletions

View File

@@ -745,3 +745,8 @@ zybo:
variables:
ROLE: zybo
<<: *lab_dfn
qemu-x86_64:
variables:
ROLE: qemu-x86_64
<<: *lab_dfn

View File

@@ -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;
}

View File

@@ -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:

View File

@@ -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)

View File

@@ -16,6 +16,7 @@
* since the MTRR registers are sometimes in flux.
*/
#include <cpu.h>
#include <cpu_func.h>
#include <log.h>
#include <sort.h>
@@ -70,9 +71,10 @@ static void set_var_mtrr(uint reg, uint type, uint64_t start, uint64_t size)
{
u64 mask;
wrmsrl(MTRR_PHYS_BASE_MSR(reg), start | type);
mask = ~(size - 1);
mask &= (1ULL << CONFIG_CPU_ADDR_BITS) - 1;
mask &= (1ull << cpu_phys_address_size()) - 1;
wrmsrl(MTRR_PHYS_BASE_MSR(reg), start | type);
wrmsrl(MTRR_PHYS_MASK_MSR(reg), mask | MTRR_PHYS_MASK_VALID);
}
@@ -193,7 +195,7 @@ int mtrr_add_request(int type, uint64_t start, uint64_t size)
if (!gd->arch.has_mtrr)
return -ENOSYS;
if (!is_power_of_2(size))
if (!is_power_of_2_u64(size))
return -EINVAL;
if (gd->arch.mtrr_req_count == MAX_MTRR_REQUESTS)
@@ -205,7 +207,7 @@ int mtrr_add_request(int type, uint64_t start, uint64_t 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 &= (1ULL << cpu_phys_address_size()) - 1;
mask |= MTRR_PHYS_MASK_VALID;
debug(" %016llx %016llx\n", req->start | req->type, mask);
@@ -360,7 +362,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 = ~mask & ((1ULL << cpu_phys_address_size()) - 1);
size |= (1 << 12) - 1;
size += 1;
valid = mask & MTRR_PHYS_MASK_VALID;

View File

@@ -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>
@@ -40,10 +42,23 @@ u64 qemu_get_high_memory_size(void)
int dram_init(void)
{
int ret;
gd->ram_size = qemu_get_low_memory_size();
gd->ram_size += qemu_get_high_memory_size();
post_code(POST_DRAM);
if (xpl_phase() == PHASE_BOARD_F) {
ret = mtrr_add_request(MTRR_TYPE_WRBACK, 0, gd->ram_size);
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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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:

View File

@@ -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;

View File

@@ -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;
@@ -161,12 +165,33 @@ static inline unsigned int cpuid_edx(unsigned int op)
return edx;
}
#if !CONFIG_IS_ENABLED(X86_64)
#if CONFIG_IS_ENABLED(X86_64)
/* 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(u64 flag)
{
uint32_t f1, f2;
u64 f1, f2;
asm (
"pushfq\n\t"
"pushfq\n\t"
"popq %0\n\t"
"movq %0,%1\n\t"
"xorq %2,%0\n\t"
"pushq %0\n\t"
"popfq\n\t"
"pushfq\n\t"
"popq %0\n\t"
"popfq\n\t"
: "=&r" (f1), "=&r" (f2)
: "ir" (flag));
return ((f1 ^ f2) & flag) != 0;
}
#else
/* Standard macro to see if a specific flag is changeable */
static inline int flag_is_changeable_p(u32 flag)
{
u32 f1, f2;
asm(
"pushfl\n\t"
@@ -181,9 +206,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

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -13,6 +13,8 @@
* Programmable Interrupt Controllers.
*/
#define LOG_CATEGORY UCLASS_IRQ
#include <log.h>
#include <asm/io.h>
#include <asm/i8259.h>

View File

@@ -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();

View File

@@ -1,13 +1,13 @@
CONFIG_X86=y
CONFIG_TEXT_BASE=0x1110000
CONFIG_SYS_MALLOC_F_LEN=0x1000
CONFIG_SYS_MALLOC_F_LEN=0x1800
CONFIG_BLOBLIST_SIZE_RELOC=0x20000
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
@@ -83,11 +83,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

View File

@@ -62,9 +62,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

View File

@@ -52,6 +52,12 @@ bool is_power_of_2(unsigned long n)
return (n != 0 && ((n & (n - 1)) == 0));
}
static inline __attribute__((const))
bool is_power_of_2_u64(u64 n)
{
return (n != 0 && ((n & (n - 1)) == 0));
}
/**
* __roundup_pow_of_two() - round up to nearest power of two
* @n: value to round up

View File

@@ -799,6 +799,18 @@ static void add_u_boot_and_runtime(void)
{
unsigned long runtime_start, runtime_end, runtime_pages;
unsigned long runtime_mask = EFI_PAGE_MASK;
unsigned long uboot_start, uboot_pages;
unsigned long uboot_stack_size = CONFIG_STACK_SIZE;
if (!IS_ENABLED(CONFIG_SANDBOX)) {
/* Add U-Boot */
uboot_start = ((uintptr_t)map_sysmem(gd->start_addr_sp, 0) -
uboot_stack_size) & ~EFI_PAGE_MASK;
uboot_pages = ((uintptr_t)map_sysmem(gd->ram_top - 1, 0) -
uboot_start + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT;
efi_add_memory_map_pg(uboot_start, uboot_pages,
EFI_BOOT_SERVICES_CODE, false);
}
#if defined(__aarch64__)
/*

View File

@@ -93,7 +93,7 @@ while getopts "a:Beko:rR:sS:w" opt; do
extra+=" -netdev user,id=net0"
;;
k)
kvm="-enable-kvm"
kvm="-enable-kvm -cpu host"
;;
o)
os=$OPTARG
@@ -150,7 +150,7 @@ run_qemu() {
else
extra+=" -serial mon:stdio"
fi
echo "Running ${qemu} ${extra}"
echo "Running ${qemu} -bios "$DIR/${BIOS}" ${kvm} ${extra}"
"${qemu}" -bios "$DIR/${BIOS}" \
-m 512 \
-nic none \

View File

@@ -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.

View File

@@ -369,21 +369,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.
@@ -455,7 +464,7 @@ class ConsoleBase(object):
finally:
self.p.timeout = orig_timeout
def ensure_spawned(self, expect_reset=False):
def ensure_spawned(self, expect_reset=False, timeout=None):
"""Ensure a connection to a correctly running U-Boot instance.
This may require spawning a new Sandbox process or resetting target
@@ -476,7 +485,7 @@ class ConsoleBase(object):
# Reset the console timeout value as some tests may change
# its default value during the execution
if not self.config.gdbserver:
self.p.timeout = TIMEOUT_MS
self.p.timeout = timeout or TIMEOUT_MS
return
try:
self.log.start_section('Starting U-Boot')
@@ -487,7 +496,7 @@ class ConsoleBase(object):
# future, possibly per-test to be optimal. This works for 'help'
# on board 'seaboard'.
if not self.config.gdbserver:
self.p.timeout = TIMEOUT_MS
self.p.timeout = timeout or TIMEOUT_MS
self.p.logfile_read = self.logstream
if self.config.use_running_system:
# Send an empty command to set up the 'expect' logic. This has
@@ -535,7 +544,7 @@ class ConsoleBase(object):
def restart_uboot(self, expect_reset=False):
"""Shut down and restart U-Boot."""
self.cleanup_spawn()
self.ensure_spawned(expect_reset)
self.ensure_spawned(expect_reset, 60 * 1000)
def get_spawn_output(self):
"""Return the start-up output from U-Boot

View File

@@ -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

View File

@@ -0,0 +1,53 @@
# SPDX-License-Identifier: GPL-2.0+
# Copyright 2025 Canonical Ltd.
# Written by Simon Glass <simon.glass@canonical.com>
import pytest
DOWN = '\x1b\x5b\x42\x0d'
# 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.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
ubman.send(DOWN * 3)
# Go to end of line
ubman.ctrl('E')
# Backspace to remove 'quiet splash'
ubman.send('\b' * len('quiet splash'))
# Send our noisy console
ubman.send(CONSOLE)
# Tell grub to 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()

View File

@@ -19,6 +19,7 @@ env__sleep_margin = 0.25
"""
@pytest.mark.role('!qemu-x86_64')
def test_sleep(ubman):
"""Test the sleep command, and validate that it sleeps for approximately
the correct amount of time."""