
On Wed, 10 May 2023 17:58:06 +0200 Heinrich Schuchardt xypron.glpk@gmx.de wrote:
Hi,
On 5/10/23 16:13, Andre Przywara wrote:
At the moment any naive attempt to boot an EFI payload that has just been loaded via "hostfs" (sandbox or semihosting) is met by a rather confusing error message: =========== VExpress64# load hostfs - $kernel_addr_r Image 52752896 bytes read in 8 ms (6.1 GiB/s) VExpress64# bootefi $kernel_addr_r No UEFI binary known at 0x80080000 =========== Actually explicitly providing the filesize: VExpress64# bootefi $kernel_addr_r:$filesize works around that problem, but the issue lies deeper: the call to efi_set_bootdev() (as done by the generic load code) bails out at some point, leaving the image_addr and image_size variables unset, which triggers this message. The problem seems to be that "-" is not understood by the code creating an UEFI device path. We could try to fix just that, but actually semihosting seems to have some explicit support in UEFI (at least it does in EDK II): there is a separate GUID for it, and hostfs is significantly different in some aspects to justify special handling.
Check for the device name being "hostfs" and create a specific UEFI device path for semihosting in this case. This uses the GUID used by EDK II for almost 15 years. This fixes the above load/bootefi sequence without requiring an explicit file size argument.
Signed-off-by: Andre Przywara andre.przywara@arm.com
Could you, please, indicate how to invoke QEMU with semihosting enabled. This information needs to be added to doc/usage/semihosting.rst.
It's already there: https://u-boot.readthedocs.io/en/latest/usage/semihosting.html#qemu
It's mostly just "-semihosting" on the QEMU side, but it's not enabled by default in the QEMU defconfig, because it *was* needed to be provided in sync with the QEMU option. It's a debug feature, so there is no good discovery mechanism, really. I think Sean made this work, with this autodetect via trap feature, so we might want to enable this option now, at least for the filesystem part.
Regardless I was doing those experiments with the FVP fastmodel, which is the most original semihosting provider, I think, and always enables semihosting.
Can there be multiple semihosting block devices?
There is no semihosting *block device*, it's a pure filesystem interface. And there is conceptually only one instance of that: it's basically a hook in the debugger (or emulation software) to provide some kind of syscall interface, triggered by a certain instruction ("brk" on AArch64). This allows some very limited access to the host filesystem - read files, write files, but no listing, for instance. It is super convenient to launch the model and load the kernel (or whatever) directly from your build machine's filesystem - especially if you do bisects or trial-and-error experiments.
lib/efi_loader/efi_device_path.c | 34 ++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+)
diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c index e2e98a39be1..b6d2074dd70 100644 --- a/lib/efi_loader/efi_device_path.c +++ b/lib/efi_loader/efi_device_path.c @@ -1079,6 +1079,35 @@ struct efi_device_path *efi_dp_from_uart(void) return buf; }
+#define SEMIHOSTING_GUID \
- EFI_GUID(0xc5b9c74a, 0x6d72, 0x4719, \
0x99, 0xab, 0xc5, 0x9f, 0x19, 0x90, 0x91, 0xeb)
Can semihosting be moved to the driver model?
Mmh, I am not sure this is a thing, since there is no block device, it's a filesystem. Which is part of the problem, I believe, and probably also a good reason to treat it separately.
Then we could create a generic catch all for device path nodes for all uclasses.
Need to digest that idea ....
Cheers, Andre
Best regards
Heinrich
+struct efi_device_path *efi_dp_from_semihosting(void) +{
- const struct efi_device_path_vendor smh_vendor = {
.dp = {
.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE,
.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR,
.length = sizeof(smh_vendor),
},
.guid = SEMIHOSTING_GUID,
- };
- void *buf, *pos;
- size_t dpsize = sizeof(smh_vendor) + sizeof(END);
- buf = efi_alloc(dpsize);
- if (!buf)
return NULL;
- pos = buf;
- memcpy(pos, &smh_vendor, sizeof(smh_vendor));
- pos += sizeof(smh_vendor);
- memcpy(pos, &END, sizeof(END));
- return buf;
+}
- #ifdef CONFIG_NETDEVICES struct efi_device_path *efi_dp_from_eth(void) {
@@ -1210,6 +1239,11 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr, *device = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE, (uintptr_t)image_addr, image_size);
- } else if (!strcmp(dev, "hostfs")) {
efi_get_image_parameters(&image_addr, &image_size);
if (device)
} else { part = blk_get_device_part_str(dev, devnr, &desc, &fs_partition, 1);*device = efi_dp_from_semihosting();