Compare commits

...

23 Commits

Author SHA1 Message Date
Simon Glass
6745ec44d9 wip 2025-06-22 12:02:42 -06:00
Simon Glass
ae65270530 more 2025-06-09 11:13:29 -06:00
Simon Glass
4bc5ceac65 speed hacks 2025-06-09 10:49:37 -06:00
Simon Glass
cc88f32641 wip 2025-06-09 10:33:12 -06:00
Simon Glass
a97042cdf6 emulation: Support zboot in the qfw bootmeth
The zboot option is used on x86, so add support for it. Use the
programmatic boot API rather than building a command to run, so that it
can work without CONFIG_CMDLINE

For now the other boot options still use the cmdline.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-06-09 10:19:22 -06:00
Simon Glass
5414785620 emulation: Support read_all() in qfw bootmeth
It is useful to be able to read the images into memory without actually
booting the kernel. This allows the cmdline to be changed using
'bootflow cmd', for example. Implement this for the QFW bootmeth.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-06-09 10:19:18 -06:00
Simon Glass
0ed5f6b991 emulation: Place the setup area as QEMU requests
QEMU provides a SETUP_ADDR value which should be honoured when placing
the setup block, since that block can include pointers into other parts
of itself.

Instead of putting the setup block immediately before the kernel, put it
where QEMU requests.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-06-09 10:17:06 -06:00
Simon Glass
f6c413a993 emulation: Move qfw reading into a new function
Add a new qemu_fwcfg_read_files() function which reads files into the
provided location. Use this from qemu_fwcfg_setup_kernel()

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-06-09 10:17:06 -06:00
Simon Glass
bd3ef58432 emulation: Refactor how the kernel is set up
The qemu_fwcfg_setup_kernel() function checks whether a kernel exists
and also reads it. With bootstd we want to do those two steps
separately.

Add a new qemu_fwcfg_read_info() function which gets all the values and
returns then, including the full cmdline. Use that from the outer
function.

The new function also reads the setup address, although this it not used
by the code at present.

Use an abuf for the cmdline since we don't want the read_info function
to alter unallocated memory.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-06-09 10:17:05 -06:00
Simon Glass
4d8ad27f8e emulation: Move endianness conversion into qfw_read_size()
Instead of worrying about endianness in each expression, move the
conversion into the function.

Use ulong for values, since this is the normal type for addresses in
U-Boot

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-06-09 10:17:05 -06:00
Simon Glass
5f65048550 emulation: Use a function to get a selector size
Move the selector reading into a separate function so we can simplify qemu_fwcfg_setup_kernel().

Read all sizes at the start and add an enum for the selector.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-06-09 10:17:05 -06:00
Simon Glass
9fea52af75 emulation: Rename data_addr in qemu_fwcfg_setup_kernel()
This is a pointer, not an address, so rename the variable. Also drop the
unnecessary assignment.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-06-09 10:17:05 -06:00
Simon Glass
1aa8ff8220 contrib: Add a script to time booting with QEMU
It is possible to use QEMU and kvm to measure the time taken by U-Boot
to hand off to Linux. Add a script to support this and print the
resulting time.

This requires a fair bit of setup, including

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-06-09 10:17:05 -06:00
Simon Glass
be79f70a11 boot: Add a way to get writable image information
The bootflow_img_find() function does not permit

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-06-09 10:15:11 -06:00
Simon Glass
80c56d399c abuf: Add a way to set up an abuf with a given address
In some cases it is convenient to provide an address when initing an
abuf, instead of a pointer. Add a function for this.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-06-09 10:15:11 -06:00
Simon Glass
c872780ba6 x86: Move ramdisk higher
With kernel size going above 15M we need enough space between where the
kernel loaded and the ramdisk, otherwise the kernel corrupts its ramdisk
while relocating itself. Move the ramdisk up to 128M

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-06-09 10:15:11 -06:00
Simon Glass
21abce189f x86: Emit a post code before booting
It is possible to benchmark U-Boot using QEMU as described here:

   https://github.com/stefano-garzarella/qemu-boot-time

On x86 devices, that script can read post codes from a perf trace. Add
a code which is emitted just before handing off to the Linux kernel.
Existing post codes can be used to determine when U-Boot starts.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-06-09 10:15:11 -06:00
Simon Glass
8099cce624 scripts: build-qemu: Support running qboot
Qboot is a good demonstration of the fastest possible boot on x86. Add
a way to run Qboot instead of U-Boot, for easy comparison. For now, use
a fixed cmdline and hard-code the UUID of the root disk.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-06-09 10:15:11 -06:00
Simon Glass
793bb912e1 scripts: build-qemu: Add a way to set the linux root
Add -t and -U flags to set the root for Linux, to a device or a UUID,
respectively.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-06-09 10:15:10 -06:00
Simon Glass
403ad10115 scripts: build-qemu: Add a way to enable linux console
Add a -C flag to enable the serial console when booting Linux. This is
only supported on x86, but a future -c flag might perhaps support other
archs.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-06-09 10:01:41 -06:00
Simon Glass
add868d853 scripts: build-qemu: Add a way to pass kernel and ramdisk
QEMU provides a special way to pass a kernel and a devicetree via the
QFW interface. Add -K and -I options to provide these.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-06-09 10:01:08 -06:00
Simon Glass
057ec035cf scripts: build-qemu: Fix message when creating config file
The message is missing an f-string specifier. Add it.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-06-09 10:01:08 -06:00
Simon Glass
7665482b11 Add a contrib directory
Add a place where people can add contributions, along with
documentation. These may be useful to other developers of U-Boot but are
not maintained / supported by the core developers.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-06-09 08:48:30 -06:00
23 changed files with 524 additions and 65 deletions

View File

@@ -31,6 +31,7 @@
#define POST_DRAM 0x30
#define POST_LAPIC 0x31
#define POST_OS_RESUME 0x40
#define POST_BOOT 0x42
#define POST_RAM_FAILURE 0xea
#define POST_BIST_FAILURE 0xeb

View File

@@ -24,6 +24,7 @@
#include <asm/bootparam.h>
#include <asm/cpu.h>
#include <asm/byteorder.h>
#include <asm/post.h>
#include <asm/zimage.h>
#ifdef CONFIG_SYS_COREBOOT
#include <asm/arch/timestamp.h>
@@ -201,6 +202,8 @@ int boot_linux_kernel(ulong setup_base, ulong entry, bool image_64bit)
if (IS_ENABLED(CONFIG_EFI_APP))
return efi_boot(setup_base, entry, image_64bit);
post_code(POST_BOOT);
if (image_64bit) {
if (!cpu_has_64bit()) {
puts("Cannot boot 64-bit kernel on 32-bit machine\n");

View File

@@ -17,7 +17,7 @@ config BOARD_SPECIFIC_OPTIONS # dummy
def_bool y
select X86_RESET_VECTOR
select QEMU
select QFW_PIO if CMD_QFW
select QFW_PIO
select BOARD_ROMSIZE_KB_1024 if TARGET_QEMU_X86
select BOARD_ROMSIZE_KB_2048 if TARGET_QEMU_X86_64
imply VIRTIO_PCI

View File

@@ -557,7 +557,7 @@ config BOOTSTD_DEFAULTS
bool "Select some common defaults for standard boot"
depends on BOOTSTD
select BOOT_DEFAULTS
select BOOTMETH_DISTRO
imply BOOTMETH_DISTRO
help
These are not required but are commonly needed to support a good
selection of booting methods. Enable this to improve the capability
@@ -731,9 +731,9 @@ config BOOTMETH_VBE
config BOOTMETH_DISTRO
bool # Options needed to boot any distro
select BOOTMETH_SCRIPT if CMDLINE # E.g. Armbian uses scripts
select BOOTMETH_EXTLINUX # E.g. Debian uses these
imply BOOTMETH_EXTLINUX # E.g. Debian uses these
select BOOTMETH_EXTLINUX_PXE if CMD_PXE && CMD_NET && DM_ETH
select BOOTMETH_EFILOADER if EFI_BINARY_EXEC # E.g. Ubuntu uses this
imply BOOTMETH_EFILOADER if EFI_BINARY_EXEC # E.g. Ubuntu uses this
config SPL_BOOTMETH_VBE
bool "Bootdev support for Verified Boot for Embedded (SPL)"

View File

@@ -998,10 +998,10 @@ struct bootflow_img *bootflow_img_add(struct bootflow *bflow, const char *fname,
return ptr;
}
const struct bootflow_img *bootflow_img_find(const struct bootflow *bflow,
enum bootflow_img_t type)
struct bootflow_img *bootflow_img_findw(const struct bootflow *bflow,
enum bootflow_img_t type)
{
const struct bootflow_img *img;
struct bootflow_img *img;
alist_for_each(img, &bflow->images) {
if (img->type == type)

View File

@@ -8,11 +8,14 @@
#define LOG_CATEGORY UCLASS_BOOTSTD
#include <abuf.h>
#include <command.h>
#include <bootdev.h>
#include <bootflow.h>
#include <bootm.h>
#include <bootmeth.h>
#include <env.h>
#include <mapmem.h>
#include <qfw.h>
#include <dm.h>
@@ -31,26 +34,86 @@ static int qfw_check(struct udevice *dev, struct bootflow_iter *iter)
static int qfw_read_bootflow(struct udevice *dev, struct bootflow *bflow)
{
struct udevice *qfw_dev = dev_get_parent(bflow->dev);
ulong load, initrd;
ulong setup, kern, ramdisk, cmdline_size, setup_addr;
struct abuf cmdline;
int ret;
load = env_get_hex("kernel_addr_r", 0);
initrd = env_get_hex("ramdisk_addr_r", 0);
log_debug("setup kernel %s %lx %lx\n", qfw_dev->name, load, initrd);
/* Get the size of each region */
ret = qemu_fwcfg_read_info(qfw_dev, &setup, &kern, &ramdisk, &cmdline,
&setup_addr);
if (ret)
return log_msg_ret("qri", ret);
bflow->cmdline = abuf_uninit_move(&cmdline, &cmdline_size);
bflow->name = strdup("qfw");
if (!bflow->name)
return log_msg_ret("name", -ENOMEM);
ret = qemu_fwcfg_setup_kernel(qfw_dev, load, initrd);
log_debug("setup kernel result %d\n", ret);
if (ret)
return log_msg_ret("cmd", -EIO);
/*
* create images for each; only cmdline has the actual data; the others
* only have a size for now, since the data has yet not been read
*/
if (!bootflow_img_add(bflow, "setup",
(enum bootflow_img_t)IH_TYPE_X86_SETUP,
setup_addr, setup))
return log_msg_ret("cri", -ENOMEM);
if (!bootflow_img_add(bflow, "kernel",
(enum bootflow_img_t)IH_TYPE_KERNEL, 0, kern))
return log_msg_ret("qrk", -ENOMEM);
if (ramdisk && !bootflow_img_add(bflow, "ramdisk",
(enum bootflow_img_t)IH_TYPE_RAMDISK,
0, ramdisk))
return log_msg_ret("qrr", -ENOMEM);
if (!bootflow_img_add(bflow, "cmdline", BFI_CMDLINE,
map_to_sysmem(bflow->cmdline), cmdline_size))
return log_msg_ret("qrc", -ENOMEM);
bflow->state = BOOTFLOWST_READY;
return 0;
}
static int qfw_read_files(struct udevice *dev, struct bootflow *bflow,
bool re_read, const struct bootflow_img **simgp,
const struct bootflow_img **kimgp,
const struct bootflow_img **rimgp)
{
struct udevice *qfw_dev = dev_get_parent(bflow->dev);
struct bootflow_img *kimg, *rimg;
struct abuf setup, kern, ramdisk;
const struct bootflow_img *simg;
simg = bootflow_img_find(bflow,
(enum bootflow_img_t)IH_TYPE_X86_SETUP);
kimg = bootflow_img_findw(bflow, (enum bootflow_img_t)IH_TYPE_KERNEL);
rimg = bootflow_img_findw(bflow, (enum bootflow_img_t)IH_TYPE_RAMDISK);
if (!kimg)
return log_msg_ret("qfs", -EINVAL);
/* read files only if not already read */
if (re_read || !kimg->addr) {
abuf_init_const_addr(&setup, simg ? simg->addr : 0,
simg ? simg->size : 0);
abuf_init_const_addr(&kern, env_get_hex("kernel_addr_r", 0),
kimg->size);
abuf_init_const_addr(&ramdisk, env_get_hex("ramdisk_addr_r", 0),
rimg ? rimg->size : 0);
qemu_fwcfg_read_files(qfw_dev, &setup, &kern, &ramdisk);
kimg->addr = abuf_addr(&kern);
if (rimg)
rimg->addr = abuf_addr(&ramdisk);
}
if (simgp)
*simgp = simg;
if (kimgp)
*kimgp = kimg;
if (rimgp)
*rimgp = rimg;
return 0;
}
static int qfw_read_file(struct udevice *dev, struct bootflow *bflow,
const char *file_path, ulong addr,
enum bootflow_img_t type, ulong *sizep)
@@ -58,15 +121,55 @@ static int qfw_read_file(struct udevice *dev, struct bootflow *bflow,
return -ENOSYS;
}
static int qfw_boot(struct udevice *dev, struct bootflow *bflow)
#if CONFIG_IS_ENABLED(BOOTSTD_FULL)
static int qfw_read_all(struct udevice *dev, struct bootflow *bflow)
{
struct bootflow_img *kimg;
int ret;
ret = run_command("booti ${kernel_addr_r} ${ramdisk_addr_r}:${filesize} ${fdtcontroladdr}",
0);
if (ret) {
ret = run_command("bootz ${kernel_addr_r} ${ramdisk_addr_r}:${filesize} "
"${fdtcontroladdr}", 0);
kimg = bootflow_img_findw(bflow, (enum bootflow_img_t)IH_TYPE_KERNEL);
if (!kimg)
return log_msg_ret("qra", -ENOENT);
ret = qfw_read_files(dev, bflow, true, NULL, NULL, NULL);
if (ret)
return log_msg_ret("qrA", ret);
return 0;
}
#endif
static int qfw_boot(struct udevice *dev, struct bootflow *bflow)
{
const struct bootflow_img *simg, *kimg, *rimg;
char conf_fdt[20], conf_ramdisk[40], addr_img_str[20];
struct bootm_info bmi;
int ret;
/* read the files if not already done */
ret = qfw_read_files(dev, bflow, false, &simg, &kimg, &rimg);
if (!kimg)
return log_msg_ret("qkf", -EINVAL);
ret = booti_run(&bmi);
bootm_init(&bmi);
snprintf(conf_fdt, sizeof(conf_fdt), "%lx",
(ulong)map_to_sysmem(gd->fdt_blob));
snprintf(addr_img_str, sizeof(addr_img_str), "%lx", kimg->addr);
bmi.addr_img = addr_img_str;
snprintf(conf_ramdisk, sizeof(conf_ramdisk), "%lx:%lx", rimg->addr,
rimg->size);
bmi.conf_ramdisk = conf_ramdisk;
ret = -ENOENT;
if (IS_ENABLED(CONFIG_CMD_BOOTI))
ret = booti_run(&bmi);
if (ret && IS_ENABLED(CONFIG_CMD_BOOTZ))
ret = bootz_run(&bmi);
if (ret && IS_ENABLED(CONFIG_ZBOOT) && simg) {
ret = zboot_run_args(kimg->addr, kimg->size,
rimg->addr, rimg->size, simg->addr,
*bflow->cmdline ? bflow->cmdline : NULL);
}
return ret ? -EIO : 0;
@@ -85,6 +188,9 @@ static struct bootmeth_ops qfw_bootmeth_ops = {
.check = qfw_check,
.read_bootflow = qfw_read_bootflow,
.read_file = qfw_read_file,
#if CONFIG_IS_ENABLED(BOOTSTD_FULL)
.read_all = qfw_read_all,
#endif
.boot = qfw_boot,
};

View File

@@ -1413,7 +1413,7 @@ static int parse_pxefile_top(struct pxe_context *ctx, char *p, unsigned long bas
err = 0;
switch (t.type) {
case T_MENU:
cfg->prompt = 1;
// cfg->prompt = 1;
err = parse_menu(ctx, &p, cfg,
base + ALIGN(strlen(b) + 1, 4),
nest_level);
@@ -1460,6 +1460,7 @@ static int parse_pxefile_top(struct pxe_context *ctx, char *p, unsigned long bas
case T_PROMPT:
err = parse_integer(&p, &cfg->prompt);
cfg->prompt = 0;
// Do not fail if prompt configuration is undefined
if (err < 0)
eol_or_eof(&p);
@@ -1732,6 +1733,7 @@ struct pxe_menu *pxe_prepare(struct pxe_context *ctx, ulong pxefile_addr_r,
if (prompt)
cfg->prompt = prompt;
cfg->prompt = 0;
return cfg;
}

View File

@@ -95,7 +95,10 @@ __weak void board_add_ram_info(int use_default)
static int init_baud_rate(void)
{
#ifdef CONFIG_SERIAL
gd->baudrate = env_get_ulong("baudrate", 10, CONFIG_BAUDRATE);
#endif
return 0;
}

View File

@@ -4,6 +4,7 @@
* (C) Copyright 2021 Asherah Connor <ashe@kivikakk.ee>
*/
#include <abuf.h>
#include <dm.h>
#include <env.h>
#include <mapmem.h>
@@ -105,62 +106,106 @@ bool qfw_file_iter_end(struct fw_cfg_file_iter *iter)
return iter->entry == iter->end;
}
/**
* qfw_read_size() - Read the size of an entry
*
* @sel: Selector value, e.g. FW_CFG_SETUP_SIZE, FW_CFG_CMDLINE_SIZE
* Return: Size of the entry
*/
static ulong qfw_read_size(struct udevice *qfw_dev, enum fw_cfg_selector sel)
{
u32 size = 0;
qfw_read_entry(qfw_dev, sel, 4, &size);
return le32_to_cpu(size);
}
int qemu_fwcfg_read_info(struct udevice *qfw_dev, ulong *setupp, ulong *kernp,
ulong *initrdp, struct abuf *cmdline,
ulong *setup_addrp)
{
uint cmdline_size;
*setupp = qfw_read_size(qfw_dev, FW_CFG_SETUP_SIZE);
*kernp = qfw_read_size(qfw_dev, FW_CFG_KERNEL_SIZE);
*initrdp = qfw_read_size(qfw_dev, FW_CFG_INITRD_SIZE);
cmdline_size = qfw_read_size(qfw_dev, FW_CFG_CMDLINE_SIZE);
if (!*kernp)
return -ENOENT;
*setup_addrp = qfw_read_size(qfw_dev, FW_CFG_SETUP_ADDR);
if (!abuf_init_size(cmdline, cmdline_size))
return log_msg_ret("qri", -ENOMEM);
qfw_read_entry(qfw_dev, FW_CFG_CMDLINE_DATA, cmdline_size,
cmdline->data);
return 0;
}
void qemu_fwcfg_read_files(struct udevice *qfw_dev, const struct abuf *setup,
const struct abuf *kern, const struct abuf *initrd)
{
if (setup->size) {
qfw_read_entry(qfw_dev, FW_CFG_SETUP_DATA, setup->size,
setup->data);
}
qfw_read_entry(qfw_dev, FW_CFG_KERNEL_DATA, kern->size, kern->data);
if (initrd->size) {
qfw_read_entry(qfw_dev, FW_CFG_INITRD_DATA, initrd->size,
initrd->data);
}
}
int qemu_fwcfg_setup_kernel(struct udevice *qfw_dev, ulong load_addr,
ulong initrd_addr)
{
char *data_addr;
u32 setup_size, kernel_size, cmdline_size, initrd_size;
ulong setup_size, kernel_size, initrd_size, setup_addr;
struct abuf cmdline, setup, kern, initrd;
int ret;
qfw_read_entry(qfw_dev, FW_CFG_SETUP_SIZE, 4, &setup_size);
qfw_read_entry(qfw_dev, FW_CFG_KERNEL_SIZE, 4, &kernel_size);
if (!kernel_size) {
ret = qemu_fwcfg_read_info(qfw_dev, &setup_size, &initrd_size,
&kernel_size, &cmdline, &setup_addr);
if (ret) {
printf("fatal: no kernel available\n");
return -ENOENT;
return log_msg_ret("qsk", ret);
}
data_addr = map_sysmem(load_addr, 0);
if (setup_size) {
qfw_read_entry(qfw_dev, FW_CFG_SETUP_DATA,
le32_to_cpu(setup_size), data_addr);
data_addr += le32_to_cpu(setup_size);
}
/*
* always put the setup area where QEMU wants it, since it includes
* absolute pointers to itself
*/
abuf_init_const_addr(&setup, setup_addr, 0);
abuf_init_const_addr(&kern, load_addr, 0);
qfw_read_entry(qfw_dev, FW_CFG_KERNEL_DATA,
le32_to_cpu(kernel_size), data_addr);
data_addr += le32_to_cpu(kernel_size);
env_set_hex("filesize", le32_to_cpu(kernel_size));
abuf_init_const_addr(&initrd, initrd_addr, 0);
qemu_fwcfg_read_files(qfw_dev, &setup, &kern, &initrd);
data_addr = map_sysmem(initrd_addr, 0);
qfw_read_entry(qfw_dev, FW_CFG_INITRD_SIZE, 4, &initrd_size);
if (!initrd_size) {
env_set_hex("filesize", kern.size);
if (!initrd_size)
printf("warning: no initrd available\n");
} else {
qfw_read_entry(qfw_dev, FW_CFG_INITRD_DATA,
le32_to_cpu(initrd_size), data_addr);
data_addr += le32_to_cpu(initrd_size);
env_set_hex("filesize", le32_to_cpu(initrd_size));
}
else
env_set_hex("filesize", initrd_size);
qfw_read_entry(qfw_dev, FW_CFG_CMDLINE_SIZE, 4, &cmdline_size);
if (cmdline_size) {
qfw_read_entry(qfw_dev, FW_CFG_CMDLINE_DATA,
le32_to_cpu(cmdline_size), data_addr);
if (cmdline.data) {
/*
* if kernel cmdline only contains '\0', (e.g. no -append
* when invoking qemu), do not update bootargs
*/
if (*data_addr) {
if (env_set("bootargs", data_addr) < 0)
if (*(char *)cmdline.data) {
if (env_set("bootargs", cmdline.data) < 0)
printf("warning: unable to change bootargs\n");
}
}
abuf_uninit(&cmdline);
printf("loading kernel to address %lx size %x", load_addr,
le32_to_cpu(kernel_size));
printf("loading kernel to address %lx size %zx", abuf_addr(&kern),
kern.size);
if (initrd_size)
printf(" initrd %lx size %x\n", initrd_addr,
le32_to_cpu(initrd_size));
printf(" initrd %lx size %lx\n", abuf_addr(&initrd),
initrd_size);
else
printf("\n");

View File

@@ -94,3 +94,34 @@ CONFIG_GENERATE_ACPI_TABLE=y
CONFIG_CMD_DHRYSTONE=y
# CONFIG_GZIP is not set
CONFIG_UNIT_TEST=y
CONFIG_BOOTDELAY=-1
# CONFIG_DM_ETH is not set
# CONFIG_VIRTIO_NET is not set
CONFIG_NO_NET=y
# CONFIG_VIDEO is not set
# CONFIG_SPL_VIDEO is not set
# CONFIG_CMDLINE is not set
# CONFIG_BOOTMETH_GLOBAL is not set
# CONFIG_BOOTMETH_CROS is not set
# CONFIG_BOOTMETH_EXTLINUX is not set
# CONFIG_BOOTMETH_EFILOADER is not set
# CONFIG_BOOTMETH_EFI_BOOTMGR is not set
# CONFIG_BOOTMETH_VBE is not set
CONFIG_PXE_UTILS=y
CONFIG_AUTOBOOT=y
CONFIG_PARTITION_TYPE_GUID=y
CONFIG_QFW_PIO=y
# CONFIG_EFI_LOADER is not set
# CONFIG_FIT is not set
# CONFIG_USB is not set
# CONFIG_SPI is not set
# CONFIG_SCSI is not set
# CONFIG_FS_FAT is not set
CONFIG_ENV_IS_NOWHERE=y
# CONFIG_ENV_IS_IN_FAT is not set
# CONFIG_DOS_PARTITION is not set
# CONFIG_ISO_PARTITION is not set
# CONFIG_SPL_PARTITIONS is not set
# CONFIG_NVME_PCI is not set
# CONFIG_SCSI_AHCI is not set
# CONFIG_FS_EXT4 is not set

15
contrib/README.rst Normal file
View File

@@ -0,0 +1,15 @@
.. SPDX-License-Identifier: GPL-2.0-or-later
The `contrib` directory contains software / files which have been contributed
to the U-Boot project but are not maintained by the core developers.
Note to contributors: Each item must have at least an entry in this file. Be
sure to add the appropriate GPL-2.0-or-later SPDX tag to files.
QEMU boot-timer script
----------------------
Runs qboot (or builds and starts U-Boot) and measures how long it takes to
start Lunux. Must be run in the U-Boot source directory.
File: `qemu-boot-timer.sh <../../../../contrib/qemu-boot-timer.sh>`_

99
contrib/qemu-boot-timer.sh Executable file
View File

@@ -0,0 +1,99 @@
#/bin/bash
# SPDX-License-Identifier: GPL-2.0-or-later
# .. code-block:: bash
# qemu-boot-timer.sh
#
# Runs qboot (or builds and starts U-Boot) and measures how long it takes to
# start Linux. Must be run in the U-Boot source directory.
# You will need to first install tracing tools, e.g.:
#
# sudo apt install linux-tools-common linux-tools-generic linux-tools-`uname -r`
#
# and also change files and directories below
#
# Example usage to test qboot:
# $ ./contrib/qemu-boot-timer.sh
# qemu-system-x86_64: terminating on signal 15 from pid 3548708 (bash)
# 1) pid 3548829
# qemu_init_end: 48.352996
# fw_start: 48.480586 (+0.12759)
# linux_start_boot: 66.16271 (+17.682124)
# Exit point 0: 66.37544 (+0.21273)
#
# That shows a time of 17.7 milliseconds for qboot itself
# Enable this to boot qboot instead of U-Boot
#QBOOT=-QB
# Linux version to boot (read from /boot)
version=6.8.0-60-generic
# UUID of root disk within your disk image, which must be called root.img
uuid=bcfdda4a-8249-4f40-9f0f-7c1a76b6cbe8
# Set up directories to use
DIR=/scratch/sglass/qemu-boot-time/
PERF_DATA=perf.data
export PERF_EXEC_PATH=/scratch/sglass/linux/tools/perf
# No settings below here:
# Turn on tracing in Linux
sudo bash <<EOF
echo 1 > /sys/kernel/debug/tracing/events/kvm/enable
echo -1 > /proc/sys/kernel/perf_event_paranoid
mount -o remount,mode=755 /sys/kernel/debug
mount -o remount,mode=755 /sys/kernel/debug/tracing
EOF
# Start recording
echo "starting perf"
sleep 1
cd $DIR
sudo perf record -a -e kvm:kvm_entry -e kvm:kvm_pio -e sched:sched_process_exec \
-o $PERF_DATA 2> /tmp/trace.log &
PERF_PID=$!
# Run QEWU with qboot or U-Boot (builds U-Boot automatically)
sleep 1
cd ~/u
echo "building U-Boot"
./scripts/build-qemu -a x86 ${QBOOT} -s -v -K /boot/vmlinuz-${version} \
-k -d root.img -I /boot/initrd.img-${version} -C -U ${uuid} \
2>&1 >/tmp/qemu.log
echo "running U-Boot in QEMU"
./scripts/build-qemu -a x86 ${QBOOT} -rsB -v -K /boot/vmlinuz-${version} \
-k -d root.img -I /boot/initrd.img-${version} -C -U ${uuid} \
2>&1 >/tmp/qemu.log &
while [[ -z "$QEMU_PID" ]]; do
QEMU_PID=$(pgrep qemu-system-x86)
done
# Wait for it to boot (increase this on slow machines)
echo "waiting for a bit"
sleep 2
# Kill QEMU and the perf process
kill $QEMU_PID
sleep 1
kill $PERF_PID
wait $PERF_PID
# Adjust permissions on perf data
cd $DIR
sudo chmod a+r $PERF_DATA
# Generate the Python script to permit access to the trace
perf script -g python 2>/dev/null
# Run our script which looks for timing points and prints the results
echo "parsing perf results"
perf script -s ~/perf-script.py -s ${DIR}/perf-script/qemu-perf-script.py \
-i $PERF_DATA

View File

@@ -0,0 +1,6 @@
.. SPDX-License-Identifier: GPL-2.0+
Contributions
=============
.. include:: ../../../contrib/README.rst

View File

@@ -113,3 +113,11 @@ Historical documentation
:maxdepth: 2
historical/index
Contributions
-------------
.. toctree::
:maxdepth: 2
contrib/index

View File

@@ -202,6 +202,18 @@ void abuf_init_set(struct abuf *abuf, void *data, size_t size);
*/
void abuf_init_const(struct abuf *abuf, const void *data, size_t size);
/**
* abuf_init_const_addr() - Set up a new buffer at a given address
*
* This is similar to abuf_init_const() except that it takes an address instead
* of a pointer. Note that the abuf is unallocated.
*
* @abuf: abuf to set up
* @addr: Address to use
* @size: Size of buffer
*/
void abuf_init_const_addr(struct abuf *abuf, ulong addr, size_t size);
/**
* abuf_init_size() - Set up an allocated abuf
*

View File

@@ -648,6 +648,16 @@ struct bootflow_img *bootflow_img_add(struct bootflow *bflow, const char *fname,
enum bootflow_img_t type, ulong addr,
ulong size);
/**
* bootflow_img_findw() - Find the first image of a given type
*
* @bflow: Bootflow to search
* @type: Image type to search for
* Return: Non-const pointer to image, or NULL if not found
*/
struct bootflow_img *bootflow_img_findw(const struct bootflow *bflow,
enum bootflow_img_t type);
/**
* bootflow_img_find() - Find the first image of a given type
*
@@ -655,8 +665,12 @@ struct bootflow_img *bootflow_img_add(struct bootflow *bflow, const char *fname,
* @type: Image type to search for
* Return: Pointer to image, or NULL if not found
*/
const struct bootflow_img *bootflow_img_find(const struct bootflow *bflow,
enum bootflow_img_t type);
static inline const struct bootflow_img *
bootflow_img_find(const struct bootflow *bflow,
enum bootflow_img_t type)
{
return bootflow_img_findw(bflow, type);
}
/**
* bootflow_get_seq() - Get the sequence number of a bootflow

2
include/env/x86.env vendored
View File

@@ -11,7 +11,7 @@ netdev=eth0
consoledev=ttyS0
scriptaddr=0x7000000
kernel_addr_r=0x1000000
ramdisk_addr_r=0x4000000
ramdisk_addr_r=0x8000000
ramdiskfile=initramfs.gz
/* common console settings */

View File

@@ -8,12 +8,14 @@
#include <linux/list.h>
struct abuf;
/*
* List of firmware configuration item selectors. The official source of truth
* for these is the QEMU source itself; see
* https://github.com/qemu/qemu/blob/master/hw/nvram/fw_cfg.c
*/
enum {
enum fw_cfg_selector {
FW_CFG_SIGNATURE = 0x00,
FW_CFG_ID = 0x01,
FW_CFG_UUID = 0x02,
@@ -316,12 +318,47 @@ bool qfw_file_iter_end(struct fw_cfg_file_iter *iter);
*/
int qemu_cpu_fixup(void);
/**
* qemu_fwcfg_read_info() - See if QEMU has provided kernel, etc.
*
* Read info about the kernel and cmdline
*
* @qfw_dev: UCLASS_QFW device
* @setupp: Returns the size of the setup area on succes
* @kernp: Returns kernel size on success
* @initrd: Returns initrd size on success
* @cmdline: Set to the cmdline in the image (allocated by this function, must
* be freed by the caller)
* @setup_addrp: Address for the setup block, as requested by QEMU
*
* Return 0 on success, -ENOENT if there is no kernel provided, -ENOMEM if there
* was no memory for the cmdline
*/
int qemu_fwcfg_read_info(struct udevice *qfw_dev, ulong *setupp, ulong *kernp,
ulong *initrdp, struct abuf *cmdline,
ulong *setup_addrp);
/**
* qemu_fwcfg_read_files() - Read files from a qfw
*
* Reads kernel and optional setup/initrd images. For each image, the abuf
* controls how many bytes are read and the address into which they are read
*
* @qfw_dev: UCLASS_QFW device
* @setup: Buffer into which to read setup (skipped if setup->size is 0)
* @kern: Buffer into which to read kernel
* @initrd: Buffer into which to read initrd (skipped if initrd->size is 0)
*/
void qemu_fwcfg_read_files(struct udevice *qfw_dev, const struct abuf *setup,
const struct abuf *kern, const struct abuf *initrd);
/*
* qemu_fwcfg_setup_kernel() - Prepare the kernel for zboot
*
* Loads kernel data to 'load_addr', initrd to 'initrd_addr' and kernel command
* line using qemu fw_cfg interface
*
* @qfw_dev: UCLASS_QFW device
* @load_addr: Load address for kernel
* @initrd_addr: Load address for ramdisk
* @return 0 if OK, -ENOENT if no kernel

View File

@@ -183,6 +183,13 @@ void abuf_init_const(struct abuf *abuf, const void *data, size_t size)
abuf_init_set(abuf, (void *)data, size);
}
#ifndef USE_HOSTCC
void abuf_init_const_addr(struct abuf *abuf, ulong addr, size_t size)
{
return abuf_init_const(abuf, map_sysmem(addr, size), size);
}
#endif
void abuf_init_move(struct abuf *abuf, void *data, size_t size)
{
abuf_init_set(abuf, data, size);

View File

@@ -44,6 +44,8 @@ def parse_args():
help='Select architecture (arm, x86) Default: arm')
parser.add_argument('-B', '--no-build', action='store_true',
help="Don't build; assume a build exists")
parser.add_argument('-C', '--enable-console', action='store_true',
help="Enable linux console (x86 only)")
parser.add_argument('-d', '--disk',
help='Root disk image file to use with QEMU')
parser.add_argument('-D', '--share-dir', metavar='DIR',
@@ -52,11 +54,17 @@ def parse_args():
help='Run UEFI Self-Certification Test (SCT)')
parser.add_argument('-E', '--use-tianocore', action='store_true',
help='Run Tianocore (OVMF) instead of U-Boot')
parser.add_argument('-I', '--initrd',
help='Initial ramdisk to run using -initrd')
parser.add_argument(
'-k', '--kvm', action='store_true',
help='Use KVM (Kernel-based Virtual Machine) for acceleration')
parser.add_argument('-K', '--kernel',
help='Kernel to run using -kernel')
parser.add_argument('-o', '--os', metavar='NAME', choices=['ubuntu'],
help='Run a specified Operating System')
parser.add_argument('-Q', '--use-qboot', action='store_true',
help='Run qboot instead of U-Boot')
parser.add_argument('-r', '--run', action='store_true',
help='Run QEMU with the built/specified image')
parser.add_argument('-x', '--xpl', action='store_true',
@@ -70,6 +78,12 @@ def parse_args():
parser.add_argument(
'-S', '--sct-seq',
help='SCT sequence-file to be written into the SCT image if -e')
parser.add_argument(
'-t', '--root',
help='Pass the given root device to linux via root=xxx')
parser.add_argument(
'-U', '--uuid',
help='Pass the given root device to linux via root=/dev/disk/by-uuid/')
parser.add_argument('-v', '--verbose', action='store_true',
help='Show executed commands')
parser.add_argument('-w', '--word-32bit', action='store_true',
@@ -92,6 +106,7 @@ class BuildQemu:
self.sctdir = Path(self.helper.get_setting('sct_dir', '~/dev/efi/sct'))
self.tiano = Path(self.helper.get_setting('tianocore_dir',
'~/dev/tiano'))
self.qboot = Path(self.helper.get_setting('qboot_dir', '~/dev/qboot'))
self.mnt = Path(self.helper.get_setting('sct_mnt', '/mnt/sct'))
self.bitness = 32 if args.word_32bit else 64
@@ -138,6 +153,12 @@ class BuildQemu:
tout.fatal(
'Error: Tianocore BIOS specified (-E) but not found at '
f'{bios_override}')
elif args.use_qboot:
bios_override = Path(self.qboot, 'bios.bin')
if not bios_override.exists():
tout.fatal(
'Error: qboot BIOS specified (-Q) but not found at '
f'{bios_override}')
self.seq_fname = Path(args.sct_seq) if args.sct_seq else None
self.img_fname = Path(args.disk) if args.disk else None
@@ -281,13 +302,15 @@ class BuildQemu:
if not self.bios.exists():
tout.fatal(f"Error: BIOS file '{self.bios}' not found")
cmdline = []
qemu_cmd = [str(self.qemu)]
if self.bios:
qemu_cmd.extend(['-bios', str(self.bios)])
qemu_cmd.extend(self.kvm_params)
qemu_cmd.extend(['-m', self.mem])
if not self.args.sct_run:
if not self.args.sct_run and not self.qboot:
qemu_cmd.extend(['-netdev', 'user,id=net0,hostfwd=tcp::2222-:22',
'-device', 'virtio-net-pci,netdev=net0'])
@@ -301,6 +324,21 @@ class BuildQemu:
if not any(item.startswith('-serial') for item in self.qemu_extra):
qemu_cmd.extend(['-serial', 'mon:stdio'])
if self.args.kernel:
qemu_cmd.extend(['-kernel', self.args.kernel])
if self.args.initrd:
qemu_cmd.extend(['-initrd', self.args.initrd])
if self.args.enable_console:
cmdline.append('console=ttyS0,115200,8n1')
if self.args.root:
cmdline.append(f'root={self.args.root}')
if self.args.uuid:
cmdline.append(f'root=/dev/disk/by-uuid/{self.args.uuid}')
if cmdline:
qemu_cmd.extend(['-append'] + [' '.join(cmdline)])
# Add other parameters gathered from options
qemu_cmd.extend(self.qemu_extra)
if self.os_path:

View File

@@ -34,7 +34,7 @@ class Helper:
self.settings = configparser.ConfigParser()
fname = f'{os.getenv("HOME")}/.u_boot_qemu'
if not os.path.exists(fname):
print('No config file found: {fname}\nCreating one...\n')
print(f'No config file found: {fname}\nCreating one...\n')
tools.write_file(fname, '''# U-Boot QEMU-scripts config
[DEFAULT]

View File

@@ -1417,6 +1417,7 @@ static int bootstd_images(struct unit_test_state *uts)
const struct legacy_img_hdr *hdr;
const struct bootflow_img *img;
const struct bootflow *bflow;
struct bootflow_img *wimg;
struct bootstd_priv *std;
const char **old_order;
struct udevice *dev;
@@ -1504,6 +1505,15 @@ static int bootstd_images(struct unit_test_state *uts)
ut_assertnull(bootflow_img_find(bflow, BFI_CMDLINE));
/* check we can update an image size */
wimg = bootflow_img_findw(bflow, (enum bootflow_img_t)IH_TYPE_SCRIPT);
ut_assertnonnull(wimg);
wimg->size = 123;
img = bootflow_img_find(bflow, (enum bootflow_img_t)IH_TYPE_SCRIPT);
ut_assertnonnull(img);
ut_asserteq(123, img->size);
ut_assert_console_end();
return 0;

View File

@@ -68,6 +68,28 @@ static int lib_test_abuf_init_const(struct unit_test_state *uts)
}
LIB_TEST(lib_test_abuf_init_const, 0);
/* Test abuf_init_const_addr() */
static int lib_test_abuf_init_const_addr(struct unit_test_state *uts)
{
struct abuf buf;
ulong start;
void *ptr;
start = ut_check_free();
ptr = map_sysmem(0x100, 0);
abuf_init_const_addr(&buf, 0x100, 10);
ut_asserteq_ptr(ptr, buf.data);
ut_asserteq(10, buf.size);
/* No memory should have been allocated */
ut_assertok(ut_check_delta(start));
return 0;
}
LIB_TEST(lib_test_abuf_init_const_addr, 0);
/* Test abuf_map_sysmem() and abuf_addr() */
static int lib_test_abuf_map_sysmem(struct unit_test_state *uts)
{