Compare commits

...

11 Commits

Author SHA1 Message Date
Simon Glass
77146a1a0b pxe_utils: Support the SAY command
This shows a message for the user. Implement it to keep the user
informed.

Series-to: u-boot
Cover-letter:
pxe: Support an automatic localboot
It seems that extlinux expects that boards know how to boot a local OS
from attached media. U-Boot currently assumes that boards define a
"localcmd" environment variable to support this. None does.

Provide an automatic means to find a kernel and ramdisk, using common
filenames. This addresses booting on MAAS, at least.
END

Signed-off-by: Simon Glass <sjg@chromium.org>
2024-12-19 20:59:40 -07:00
Simon Glass
39c0d81749 pxe_utils: Support a backup for localboot
The current localboot implementation assumes that a 'localcmd'
environment variable is provided, with the instructions to follow. This
may not be included, so provide a fallback in that case.

Add a test image and test as well.

Signed-off-by: Simon Glass <sjg@chromium.org>
2024-12-19 19:35:58 -07:00
Simon Glass
db6c671cbb pxe_utils: Allow the FDT to be missing
The devicetree file may not be provided, so avoid a failure in that
case.

Signed-off-by: Simon Glass <sjg@chromium.org>
2024-12-19 19:35:58 -07:00
Simon Glass
9fd2c2ec0d test: bootflow: Avoid a confusing error condition
The prep_mmc_bootdev() function replaces bootstd's bootdev_order with
its own static version, then returns it.

From then on std->bootdev_order cannot be freed, since it was not
allocated.

So long as the test passes, all is well. But if a test fails, the test
system will try to free std->bootdev_order and this will fail.

Adjust prep_mmc_bootdev() to allocate the boot_dev order, instead.

Signed-off-by: Simon Glass <sjg@chromium.org>
2024-12-19 19:35:57 -07:00
Simon Glass
2e86338708 test/py: Refactor extlinux-image creation into a function
We would like to make another image which is very similar, so create a
function to produce an extlinux image.

Signed-off-by: Simon Glass <sjg@chromium.org>
2024-12-19 19:02:17 -07:00
Simon Glass
f51ba0874d sandbox: Adjust configuration to hang on panic()
It is annoying to have sandbox enter a boot loop when an assertion
fails. Hang instead, since then the error message is only printed once
and Ctrl-C can be used to quit, as per normal.

Series-to: u-boot

Signed-off-by: Simon Glass <sjg@chromium.org>
2024-12-19 19:02:17 -07:00
Simon Glass
05b4aabcd6 rpi: Use the U-Boot control FDT for fdt_addr
The fdt_addr variable is used in extlinux as a fallback devicetree if
none is provided by the boot command.

The existing mechanism uses the devicetree provided to U-Boot, but in
its original, unrelocated position. For the rpi_4 I am using, this is
at 2b35ef00 which is not a convenient place in memory, if the ramdisk
is large.

U-Boot already deals with this sort of problem by relocating the FDT
to a safe address.

So use the control-FDT address instead.

Remove the existing comment, which is confusing, since the FDT is not
actually passed unmodified to the kernel: U-Boot adds various things
using its FDT-fixup mechanism.

Note that board_get_usable_ram_top() reduces the RAM top for boards with
less RAM. This behaviour is left unchanged as there is no other
mechanism for U-Boot to handle this.

In version 2, it incorporates some changes to fdt_addr, etc. suggested
by Tom, as well as adding myself as a maintainer.

Series-to: u-boot
Series-cc: trini, rpi
Series-version: 3
Series-links: 435918
Series-changes: 2
- Drop patch to allow expanding the devicetree during relocation

Cover-letter:
rpi: Tidy up booting
This series allows rpi to boot a compressed Ubuntu kernel with ~100MB
ramdisk, by expanding the available space.

It also tidies up some strange behaviour with the provided FDT, where a
separate pointer is maintained to it, even though U-Boot has copied it
and placed it in its own space. This avoids strange bugs where it
accidentally gets overwritten when loading a file into memory.

The patch to expand the devicetree was dropped, meaning that people
should be careful to unset fdt_addr in the environment.
END

Signed-off-by: Simon Glass <sjg@chromium.org>
2024-12-19 17:35:18 -07:00
Simon Glass
6a92f0bb7a rpi: Update environment to support booti and large initrd
The existing values don't provide for decompressing an arm64 boot-image.
Add those values and move things apart a bit so that a 50MB kernel can be
accommodated.

Series-changes: 3
- Update the comment block with the new values, including compression

Signed-off-by: Simon Glass <sjg@chromium.org>
2024-12-19 17:35:18 -07:00
Simon Glass
bbfd79236c rpi: Drop fdt_high and initrd_high
These are not needed now since there is a bootm_size setting to keep
things within the lower part of memory.

Drop them.

Series-changes: 2
- Add new patch to drop fdt_high and initrd_high

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Tom Rini <trini@konsulko.com>
Suggested-by: Tom Rini <trini@konsulko.com>
2024-12-19 17:35:18 -07:00
Simon Glass
98368a8f49 rpi: Set bootm_size to 512MB
Set this option so that all boot images stay within the bottom 512MB of
memory. This should allow us to drop the fdt_high and initrd_high
options.

Series-changes: 2
- Add new patch to set bootm_size

Series-changes: 3
- Add to the existing comment block

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Tom Rini <trini@konsulko.com>
Suggested-by: Tom Rini <trini@konsulko.com>
2024-12-19 17:35:18 -07:00
Simon Glass
f4ed8a3aad rpi: Add myself to the list of maintainers
Add my own name to the list, since existing maintainers are fairly busy.

Series-changes: 2
- Add new patch to make myself an rpi maintainer

Signed-off-by: Simon Glass <sjg@chromium.org>
2024-12-19 17:35:18 -07:00
9 changed files with 203 additions and 64 deletions

View File

@@ -210,6 +210,7 @@ N: aspeed
ARM BROADCOM BCM283X / BCM27XX
M: Matthias Brugger <mbrugger@suse.com>
M: Peter Robinson <pbrobinson@gmail.com>
M: Simon Glass <sjg@chromium.org>
S: Maintained
F: arch/arm/dts/bcm283*
F: arch/arm/mach-bcm283x/

View File

@@ -45,6 +45,7 @@
mmc6 = "/mmc6";
mmc7 = "/mmc7";
mmc8 = "/mmc8";
mmc9 = "/mmc9";
pci0 = &pci0;
pci1 = &pci1;
pci2 = &pci2;
@@ -1153,6 +1154,13 @@
filename = "mmc8.img";
};
/* This is used for extlinux localboot */
mmc9 {
status = "disabled";
compatible = "sandbox,mmc";
filename = "mmc9.img";
};
pch {
compatible = "sandbox,pch";
};

View File

@@ -3,6 +3,8 @@
* (C) Copyright 2012-2016 Stephen Warren
*/
#define LOG_CATEGORY LOGC_BOARD
#include <config.h>
#include <dm.h>
#include <env.h>
@@ -325,19 +327,10 @@ static void set_fdtfile(void)
env_set("fdtfile", fdtfile);
}
/*
* If the firmware provided a valid FDT at boot time, let's expose it in
* ${fdt_addr} so it may be passed unmodified to the kernel.
*/
/* Allow U-Boot to use its control FDT with extlinux if one is not provided */
static void set_fdt_addr(void)
{
if (env_get("fdt_addr"))
return;
if (fdt_magic(fw_dtb_pointer) != FDT_MAGIC)
return;
env_set_hex("fdt_addr", fw_dtb_pointer);
env_set_hex("fdt_addr", (ulong)gd->fdt_blob);
}
/*
@@ -571,7 +564,10 @@ int ft_board_setup(void *blob, struct bd_info *bd)
{
int node;
update_fdt_from_fw(blob, (void *)fw_dtb_pointer);
if (blob == gd->fdt_blob)
log_debug("Same FDT: nothing to do\n");
else
update_fdt_from_fw(blob, (void *)gd->fdt_blob);
node = fdt_node_offset_by_compatible(blob, -1, "simple-framebuffer");
if (node < 0)

View File

@@ -48,30 +48,33 @@ dfu_alt_info+=zImage fat 0 1
*
* scriptaddr and pxefile_addr_r can be pretty much anywhere that doesn't
* conflict with something else. Reserving 1M for each of them at
* 0x02400000-0x02500000 and 0x02500000-0x02600000 should be plenty.
* 0x05400000-0x05500000 and 0x05500000-0x05600000 should be plenty.
*
* On ARM, both the DTB and any possible initrd must be loaded such that they
* fit inside the lowmem mapping in Linux. In practice, this usually means not
* more than ~700M away from the start of the kernel image but this number can
* be larger OR smaller depending on e.g. the 'vmalloc=xxxM' command line
* parameter given to the kernel. So reserving memory from low to high
* satisfies this constraint again. Reserving 1M at 0x02600000-0x02700000 for
* the DTB leaves rest of the free RAM to the initrd starting at 0x02700000.
* Even with the smallest possible CPU-GPU memory split of the CPU getting
* only 64M, the remaining 25M starting at 0x02700000 should allow quite
* large initrds before they start colliding with U-Boot.
* satisfies this constraint again. Reserving 1M at 0x05600000-0x05700000 for
* the DTB leaves rest of the free RAM to the initrd starting at 0x05700000.
* This means that the board must have at least 128MB of RAM available to
* U-Boot, more if the initrd is large.
*
* For compressed kernels, the maximum size is just under 32MB, with an area for
* decompression at 0x02000000 with space for 52MB, which is plenty for current
* kernels.
*
* limit bootm_size to 512MB so that all boot images stay within the bottom
* 512MB of memory
*/
#ifdef CONFIG_ARM64
fdt_high=ffffffffffffffff
initrd_high=ffffffffffffffff
#else
fdt_high=ffffffff
initrd_high=ffffffff
#endif
bootm_size=0x20000000
kernel_addr_r=0x00080000
scriptaddr=0x02400000
pxefile_addr_r=0x02500000
fdt_addr_r=0x02600000
ramdisk_addr_r=0x02700000
kernel_comp_addr_r=0x02000000
kernel_comp_size=0x03400000
scriptaddr=0x05400000
pxefile_addr_r=0x05500000
fdt_addr_r=0x05600000
ramdisk_addr_r=0x05700000
boot_targets=mmc usb pxe dhcp

View File

@@ -556,6 +556,15 @@ config BOOTMETH_EXTLINUX_PXE
This provides a way to try out standard boot on an existing boot flow.
config BOOTMETH_EXTLINUX_LOCALBOOT
bool "Boot method for extlinux localboot"
depends on BOOTMETH_EXTLINUX
default y
help
Enables standard boot support for the extlinux 'localboot' feature.
This attempts to find a kernel and initrd on the disk and boot it,
in the case where there is no "localcmd" in the environment.
config BOOTMETH_EFILOADER
bool "Bootdev support for EFI boot"
depends on EFI_BINARY_EXEC

View File

@@ -640,6 +640,25 @@ static int label_run_boot(struct pxe_context *ctx, struct pxe_label *label,
return 0;
}
/**
* generate_localboot() - Try to come up with a localboot definition
*
* Adds a default kernel and initrd filename for use with localboot
*
* @label: Label to process
* Return 0 if OK, -ENOMEM if out of memory
*/
static int generate_localboot(struct pxe_label *label)
{
label->kernel = strdup("/vmlinuz");
label->kernel_label = strdup(label->kernel);
label->initrd = strdup("/initrd.img");
if (!label->kernel || !label->kernel_label || !label->initrd)
return -ENOMEM;
return 0;
}
/**
* label_boot() - Boot according to the contents of a pxe_label
*
@@ -677,9 +696,17 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label)
label->attempted = 1;
if (label->localboot) {
if (label->localboot_val >= 0)
label_localboot(label);
return 0;
if (label->localboot_val >= 0) {
ret = label_localboot(label);
if (IS_ENABLED(CONFIG_BOOTMETH_EXTLINUX_LOCALBOOT) &&
ret == -ENOENT)
ret = generate_localboot(label);
if (ret)
return ret;
} else {
return 0;
}
}
if (!label->kernel) {
@@ -799,7 +826,7 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label)
}
unmap_sysmem(buf);
}
if (ctx->bflow)
if (ctx->bflow && conf_fdt)
ctx->bflow->fdt_addr = hextoul(conf_fdt, NULL);
if (IS_ENABLED(CONFIG_BOOTSTD_FULL) && ctx->no_boot) {
@@ -819,7 +846,7 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label)
ctx->initrd_addr_str, ctx->initrd_filesize,
ctx->initrd_str);
}
if (!ctx->kernel_addr || !ctx->conf_fdt ||
if (!ctx->kernel_addr || (conf_fdt && !ctx->conf_fdt) ||
(initrd_addr_str && (!ctx->initrd_addr_str ||
!ctx->initrd_filesize || !ctx->initrd_str))) {
printf("malloc fail (saving label)\n");
@@ -863,6 +890,7 @@ enum token_type {
T_BACKGROUND,
T_KASLRSEED,
T_FALLBACK,
T_SAY,
T_INVALID
};
@@ -897,6 +925,7 @@ static const struct token keywords[] = {
{"background", T_BACKGROUND,},
{"kaslrseed", T_KASLRSEED,},
{"fallback", T_FALLBACK,},
{"say", T_SAY,},
{NULL, T_INVALID}
};
@@ -1361,6 +1390,17 @@ static int parse_label(char **c, struct pxe_menu *cfg)
case T_EOL:
break;
case T_SAY: {
char *p = strchr(s, '\n');
if (p) {
printf("%.*s\n", (int)(p - *c) - 1, *c + 1);
*c = p;
}
break;
}
default:
/*
* put the token back! we don't want it - it's the end

View File

@@ -354,6 +354,7 @@ CONFIG_WDT_FTWDT010=y
CONFIG_FS_CBFS=y
CONFIG_FS_CRAMFS=y
CONFIG_ADDR_MAP=y
CONFIG_PANIC_HANG=y
CONFIG_CMD_DHRYSTONE=y
CONFIG_MBEDTLS_LIB=y
CONFIG_ECDSA=y

View File

@@ -540,12 +540,15 @@ BOOTSTD_TEST(bootflow_cmd_boot, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);
static int prep_mmc_bootdev(struct unit_test_state *uts, const char *mmc_dev,
bool bind_cros_android, const char ***old_orderp)
{
static const char *order[] = {"mmc2", "mmc1", NULL, NULL};
static const char **order;
struct udevice *dev, *bootstd;
struct bootstd_priv *std;
const char **old_order;
ofnode root, node;
order = calloc(sizeof(void *), 4);
order[0] = "mmc2";
order[1] = "mmc1";
order[2] = mmc_dev;
/* Enable the requested mmc node since we need a second bootflow */
@@ -605,6 +608,7 @@ static int scan_mmc_bootdev(struct unit_test_state *uts, const char *mmc_dev,
/* Restore the order used by the device tree */
ut_assertok(uclass_first_device_err(UCLASS_BOOTSTD, &bootstd));
std = dev_get_priv(bootstd);
free(std->bootdev_order);
std->bootdev_order = old_order;
return 0;
@@ -635,6 +639,7 @@ static int scan_mmc_android_bootdev(struct unit_test_state *uts, const char *mmc
/* Restore the order used by the device tree */
ut_assertok(uclass_first_device_err(UCLASS_BOOTSTD, &bootstd));
std = dev_get_priv(bootstd);
free(std->bootdev_order);
std->bootdev_order = old_order;
return 0;
@@ -726,6 +731,7 @@ static int bootflow_scan_menu(struct unit_test_state *uts)
std->bootdev_order = new_order; /* Blue Monday */
ut_assertok(run_command("bootflow scan -lm", 0));
free(std->bootdev_order);
std->bootdev_order = old_order;
ut_assertnull(std->cur_bootflow);
@@ -1504,3 +1510,51 @@ static int bootflow_scan_extlinux(struct unit_test_state *uts)
return 0;
}
BOOTSTD_TEST(bootflow_scan_extlinux, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);
/* Check automatically generating a extlinux 'localboot' */
static int bootflow_extlinux_localboot(struct unit_test_state *uts)
{
const struct bootflow_img *img;
struct bootstd_priv *std;
const char **old_order;
struct bootflow *bflow;
ut_assertok(prep_mmc_bootdev(uts, "mmc9", false, &old_order));
ut_assertok(run_command("bootflow scan", 0));
ut_assert_console_end();
/* Restore the order used by the device tree */
ut_assertok(bootstd_get_priv(&std));
free(std->bootdev_order);
std->bootdev_order = old_order;
/* boot the second bootflow */
ut_asserteq(2, std->bootflows.count);
bflow = alist_getw(&std->bootflows, 1, struct bootflow);
std->cur_bootflow = bflow;
/* read all the images, but don't actually boot */
ut_assertok(bootflow_read_all(bflow));
ut_assert_nextline("Doing local boot...");
ut_assert_nextline("1:\tlocal");
ut_assert_nextline("missing environment variable: localcmd");
ut_assert_nextline("Retrieving file: /vmlinuz");
ut_assert_nextline("Retrieving file: /initrd.img");
ut_assert_console_end();
ut_asserteq(3, bflow->images.count);
/* check the two localboot images */
img = alist_get(&bflow->images, 1, struct bootflow_img);
ut_asserteq(IH_TYPE_KERNEL, img->type);
ut_asserteq(0x1000000, img->addr); /* kernel_addr_r */
img = alist_get(&bflow->images, 2, struct bootflow_img);
ut_asserteq(IH_TYPE_RAMDISK, img->type);
ut_asserteq(0x2000000, img->addr); /* ramdisk_addr_r */
return 0;
}
BOOTSTD_TEST(bootflow_extlinux_localboot, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);

View File

@@ -57,6 +57,43 @@ def setup_image(cons, devnum, part_type, img_size=20, second_part=False,
stdin=spec.encode('utf-8'))
return fname, mnt
def setup_extlinux_image(cons, mmc_dev, vmlinux, initrd, dtbdir, script):
"""Create a 20MB disk image with a single FAT partition"""
fname, mnt = setup_image(cons, mmc_dev, 0xc, second_part=True)
ext = os.path.join(mnt, 'extlinux')
mkdir_cond(ext)
conf = os.path.join(ext, 'extlinux.conf')
with open(conf, 'w', encoding='ascii') as fd:
print(script, file=fd)
inf = os.path.join(cons.config.persistent_data_dir, 'inf')
with open(inf, 'wb') as fd:
fd.write(gzip.compress(b'vmlinux'))
mkimage = cons.config.build_dir + '/tools/mkimage'
u_boot_utils.run_and_log(
cons, f'{mkimage} -f auto -d {inf} {os.path.join(mnt, vmlinux)}')
with open(os.path.join(mnt, initrd), 'w', encoding='ascii') as fd:
print('initrd', file=fd)
if dtbdir:
mkdir_cond(os.path.join(mnt, dtbdir))
dtb_file = os.path.join(mnt, f'{dtbdir}/sandbox.dtb')
u_boot_utils.run_and_log(
cons, f'dtc -o {dtb_file}', stdin=b'/dts-v1/; / {};')
fsfile = 'vfat18M.img'
u_boot_utils.run_and_log(cons, f'fallocate -l 18M {fsfile}')
u_boot_utils.run_and_log(cons, f'mkfs.vfat {fsfile}')
u_boot_utils.run_and_log(cons, ['sh', '-c', f'mcopy -i {fsfile} {mnt}/* ::/'])
u_boot_utils.run_and_log(cons, f'dd if={fsfile} of={fname} bs=1M seek=1')
u_boot_utils.run_and_log(cons, f'rm -rf {mnt}')
u_boot_utils.run_and_log(cons, f'rm -f {fsfile}')
def setup_bootmenu_image(cons):
"""Create a 20MB disk image with a single ext4 partition
@@ -197,36 +234,8 @@ label Fedora-Workstation-armhfp-31-1.9 (5.3.7-301.fc31.armv7hl)
append ro root=UUID=9732b35b-4cd5-458b-9b91-80f7047e0b8a rhgb quiet LANG=en_US.UTF-8 cma=192MB cma=256MB
fdtdir /%s/
initrd /%s''' % (vmlinux, dtbdir, initrd)
ext = os.path.join(mnt, 'extlinux')
mkdir_cond(ext)
conf = os.path.join(ext, 'extlinux.conf')
with open(conf, 'w', encoding='ascii') as fd:
print(script, file=fd)
inf = os.path.join(cons.config.persistent_data_dir, 'inf')
with open(inf, 'wb') as fd:
fd.write(gzip.compress(b'vmlinux'))
mkimage = cons.config.build_dir + '/tools/mkimage'
u_boot_utils.run_and_log(
cons, f'{mkimage} -f auto -d {inf} {os.path.join(mnt, vmlinux)}')
with open(os.path.join(mnt, initrd), 'w', encoding='ascii') as fd:
print('initrd', file=fd)
mkdir_cond(os.path.join(mnt, dtbdir))
dtb_file = os.path.join(mnt, f'{dtbdir}/sandbox.dtb')
u_boot_utils.run_and_log(
cons, f'dtc -o {dtb_file}', stdin=b'/dts-v1/; / {};')
fsfile = 'vfat18M.img'
u_boot_utils.run_and_log(cons, f'fallocate -l 18M {fsfile}')
u_boot_utils.run_and_log(cons, f'mkfs.vfat {fsfile}')
u_boot_utils.run_and_log(cons, ['sh', '-c', f'mcopy -i {fsfile} {mnt}/* ::/'])
u_boot_utils.run_and_log(cons, f'dd if={fsfile} of={fname} bs=1M seek=1')
u_boot_utils.run_and_log(cons, f'rm -rf {mnt}')
u_boot_utils.run_and_log(cons, f'rm -f {fsfile}')
setup_extlinux_image(cons, mmc_dev, vmlinux, initrd, dtbdir, script)
def setup_cros_image(cons):
"""Create a 20MB disk image with ChromiumOS partitions"""
@@ -566,6 +575,23 @@ def setup_efi_image(cons):
u_boot_utils.run_and_log(cons, f'rm -rf {mnt}')
u_boot_utils.run_and_log(cons, f'rm -f {fsfile}')
def setup_localboot_image(cons):
"""Create a 20MB disk image with a single FAT partition"""
mmc_dev = 9
fname, mnt = setup_image(cons, mmc_dev, 0xc, second_part=True)
script = '''DEFAULT local
LABEL local
SAY Doing local boot...
LOCALBOOT 0
'''
vmlinux = 'vmlinuz'
initrd = 'initrd.img'
setup_extlinux_image(cons, mmc_dev, vmlinux, initrd, None, script)
@pytest.mark.buildconfigspec('cmd_bootflow')
@pytest.mark.buildconfigspec('sandbox')
def test_ut_dm_init_bootstd(u_boot_console):
@@ -577,6 +603,7 @@ def test_ut_dm_init_bootstd(u_boot_console):
setup_cros_image(u_boot_console)
setup_android_image(u_boot_console)
setup_efi_image(u_boot_console)
setup_localboot_image(u_boot_console)
# Restart so that the new mmc1.img is picked up
u_boot_console.restart_uboot()