From: uverma@linux.ibm.com
To: qemu-devel@nongnu.org, qemu-ppc@nongnu.org, aik@ozlabs.ru
Cc: pbonzini@redhat.com, th.huth@posteo.eu, nnmlinux@linux.ibm.com,
sbhat@linux.ibm.com, harshpb@linux.ibm.com,
amachhiw@linux.ibm.com, rathc@linux.ibm.com, balaton@eik.bme.hu,
philmd@oss.qualcomm.com, npiggin@gmail.com,
marcandre.lureau@redhat.com, fam@euphon.net,
Utkarsh Verma <uverma@linux.ibm.com>
Subject: [RFC PATCH 3/8] ppc/spapr: add baseline VOF disk boot support
Date: Mon, 17 Aug 2026 15:57:20 +0530 [thread overview]
Message-ID: <20260817102733.605346-4-uverma@linux.ibm.com> (raw)
In-Reply-To: <20260817102733.605346-1-uverma@linux.ibm.com>
From: Utkarsh Verma <uverma@linux.ibm.com>
Add initial support for disk boot via VOF.
Scan all the block devices, and for each device search for PReP partition,
load the ELF payload (GRUB), and set the '/chosen' node in FDT with boot kernel
and bootpath properties.
AI-used-for: code
Signed-off-by: Utkarsh Verma <uverma@linux.ibm.com>
---
hw/ppc/spapr_vof.c | 142 ++++++++++++++++++++++++++++++++++++++++---
hw/ppc/vof.c | 3 +
include/hw/ppc/vof.h | 2 +
3 files changed, 139 insertions(+), 8 deletions(-)
diff --git a/hw/ppc/spapr_vof.c b/hw/ppc/spapr_vof.c
index 46d78756e6..5bf9613005 100644
--- a/hw/ppc/spapr_vof.c
+++ b/hw/ppc/spapr_vof.c
@@ -10,8 +10,15 @@
#include "hw/ppc/spapr_cpu_core.h"
#include "hw/ppc/fdt.h"
#include "hw/ppc/vof.h"
+#include "hw/ppc/spapr_vof.h"
+#include "hw/core/qdev.h"
+#include "hw/core/loader.h"
#include "system/system.h"
+#include "system/block-backend.h"
+#include "system/block-backend-global-state.h"
#include "qom/qom-qobject.h"
+#include "target/ppc/cpu.h"
+#include "elf.h"
#include "trace.h"
target_ulong spapr_h_vof_client(PowerPCCPU *cpu, SpaprMachineState *spapr,
@@ -32,10 +39,10 @@ void spapr_vof_client_dt_finalize(SpaprMachineState *spapr, void *fdt)
vof_build_dt(fdt, spapr->vof);
- if (spapr->vof->bootargs) {
- int chosen;
+ int chosen;
+ _FDT(chosen = fdt_path_offset(fdt, "/chosen"));
- _FDT(chosen = fdt_path_offset(fdt, "/chosen"));
+ if (spapr->vof->bootargs) {
/*
* If the client did not change "bootargs", spapr_dt_chosen() must have
* stored machine->kernel_cmdline in it before getting here.
@@ -43,6 +50,22 @@ void spapr_vof_client_dt_finalize(SpaprMachineState *spapr, void *fdt)
_FDT(fdt_setprop_string(fdt, chosen, "bootargs", spapr->vof->bootargs));
}
+ if (spapr->vof->disk_boot) {
+ /*
+ * If disk boot is detected change the "qemu,boot-kernel" to hold
+ * kernel_addr/kernel_size which contain the GRUB entry point and size
+ */
+ uint64_t kern[2];
+ kern[0] = cpu_to_be64(spapr->kernel_addr);
+ kern[1] = cpu_to_be64(spapr->kernel_size);
+ _FDT(fdt_setprop(fdt, chosen, "qemu,boot-kernel", &kern, sizeof(kern)));
+
+ if (spapr->vof->bootpath) {
+ _FDT(fdt_setprop_string(fdt, chosen, "bootpath",
+ spapr->vof->bootpath));
+ }
+ }
+
/*
* SLOF-less setup requires an open instance of stdout for early
* kernel printk. By now all phandles are settled so we can open
@@ -54,11 +77,100 @@ void spapr_vof_client_dt_finalize(SpaprMachineState *spapr, void *fdt)
}
}
+static bool vof_elf_segment_cb(void *opaque,
+ uint64_t paddr, uint64_t vaddr,
+ uint64_t filesz, uint64_t memsz)
+{
+ Vof *vof = opaque;
+
+ if (memsz == 0) {
+ return true;
+ }
+
+ if (paddr != vaddr) {
+ error_report("spapr_vof_load_elf: segment paddr/vaddr mismatch "
+ "(paddr=0x%" PRIx64 " vaddr=0x%" PRIx64 ")",
+ paddr, vaddr);
+ return false;
+ }
+
+ if (vof_claim(vof, paddr, memsz, 0) == -1) {
+ error_report("spapr_vof_load_elf: vof_claim failed for "
+ "paddr=0x%" PRIx64 " size=0x%" PRIx64, paddr, memsz);
+ return false;
+ }
+
+ return true;
+}
+
+static bool spapr_vof_try_prep_boot(SpaprMachineState *spapr, Vof *vof)
+{
+ BlockBackend *blk;
+ DeviceState *dev;
+ uint64_t partition_offset;
+ uint64_t partition_size;
+ uint8_t *prep_data;
+ uint64_t entry_point;
+ uint64_t load_size;
+
+ for (blk = blk_next(NULL); blk; blk = blk_next(blk)) {
+
+ if (!blk_is_inserted(blk)) {
+ continue;
+ }
+
+ partition_offset = 0;
+ partition_size = 0;
+
+ if (!spapr_vof_find_prep_partition(blk, &partition_offset,
+ &partition_size)) {
+ continue;
+ }
+
+ prep_data = g_malloc(partition_size);
+ if (blk_pread(blk, partition_offset, partition_size,
+ prep_data, 0) < 0) {
+ g_free(prep_data);
+ continue;
+ }
+
+ uint64_t lowaddr = UINT64_MAX, highaddr = 0;
+ entry_point = 0;
+ ssize_t ret = load_elf_ram_sym_buf(prep_data, partition_size,
+ NULL, NULL, NULL,
+ &entry_point, &lowaddr, &highaddr,
+ NULL, ELFDATA2MSB,
+ PPC_ELF_MACHINE, 0, 0,
+ NULL, false, NULL,
+ vof_elf_segment_cb, vof);
+ if (ret <= 0) {
+ error_report("spapr_vof_try_prep_boot: %s", load_elf_strerror(ret));
+ g_free(prep_data);
+ continue;
+ }
+ load_size = highaddr - lowaddr;
+
+ g_free(prep_data);
+
+ spapr->kernel_addr = entry_point;
+ spapr->kernel_size = load_size;
+
+ vof->disk_boot = true;
+ dev = blk_get_attached_dev(blk);
+ if (dev) {
+ vof->bootpath = qdev_get_fw_dev_path(dev);
+ }
+ return true;
+ }
+ return false;
+}
+
void spapr_vof_reset(SpaprMachineState *spapr, void *fdt, Error **errp)
{
target_ulong stack_ptr;
Vof *vof = spapr->vof;
PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
+ MachineState *machine = MACHINE(spapr);
vof_init(vof, spapr->rma_size, errp);
@@ -70,7 +182,7 @@ void spapr_vof_reset(SpaprMachineState *spapr, void *fdt, Error **errp)
/* Stack grows downwards plus reserve space for the minimum stack frame */
stack_ptr += VOF_STACK_SIZE - 0x20;
- if (spapr->kernel_size &&
+ if (machine->kernel_filename && spapr->kernel_size &&
vof_claim(vof, spapr->kernel_addr, spapr->kernel_size, 0) == -1) {
error_setg(errp, "Memory for kernel is in use");
return;
@@ -82,6 +194,14 @@ void spapr_vof_reset(SpaprMachineState *spapr, void *fdt, Error **errp)
return;
}
+ /*
+ * Disk boot: load GRUB from the PReP boot partition on the block device, if
+ * no kernel/initrd are provided
+ */
+ if (!machine->kernel_filename) {
+ spapr_vof_try_prep_boot(spapr, vof);
+ }
+
spapr_vof_client_dt_finalize(spapr, fdt);
spapr_cpu_set_entry_state(first_ppc_cpu, SPAPR_ENTRY_POINT,
@@ -91,10 +211,16 @@ void spapr_vof_reset(SpaprMachineState *spapr, void *fdt, Error **errp)
/*
* At this point the expected allocation map is:
*
- * 0..c38 - the initial firmware
- * 8000..10000 - stack
- * 400000.. - kernel
- * 3ea0000.. - initramdisk
+ * Kernel + initrd boot:
+ * 0..c38 - the initial firmware
+ * 8000..10000 - stack
+ * 400000.. - kernel
+ * 3ea0000.. - initramdisk
+ *
+ * Disk (GRUB) boot:
+ * 0..c38 - the initial firmware
+ * 8000..10000 - stack
+ * 400000.. - GRUB (loaded from PReP partition)
*
* We skip writing FDT as nothing expects it; OF client interface is
* going to be used for reading the device tree.
diff --git a/hw/ppc/vof.c b/hw/ppc/vof.c
index fa7b73159a..a78bb1f116 100644
--- a/hw/ppc/vof.c
+++ b/hw/ppc/vof.c
@@ -1041,6 +1041,9 @@ void vof_cleanup(Vof *vof)
vof->of_instances = NULL;
vof->of_instance_last = 0;
vof->claimed_base = 0;
+ g_free(vof->bootpath);
+ vof->bootpath = NULL;
+ vof->disk_boot = false;
}
void vof_build_dt(void *fdt, Vof *vof)
diff --git a/include/hw/ppc/vof.h b/include/hw/ppc/vof.h
index 3a0fbffe54..e17779ee8a 100644
--- a/include/hw/ppc/vof.h
+++ b/include/hw/ppc/vof.h
@@ -18,6 +18,8 @@ typedef struct Vof {
GHashTable *of_instances; /* ihandle -> SpaprOfInstance */
uint32_t of_instance_last;
char *bootargs;
+ char *bootpath;
+ bool disk_boot;
long fw_size;
} Vof;
--
2.54.0
next prev parent reply other threads:[~2026-08-17 10:30 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-17 10:27 [RFC PATCH 0/8] ppc/spapr: VOF disk image (qcow2) boot support uverma
2026-08-17 10:27 ` [RFC PATCH 1/8] ppc/spapr: add PReP boot partition detection uverma
2026-08-17 10:27 ` [RFC PATCH 2/8] hw/loader: add load_elf_ram_sym_buf() for in-memory ELF loading uverma
2026-08-17 10:27 ` uverma [this message]
2026-08-17 10:27 ` [RFC PATCH 4/8] ppc/spapr: add VTY backend support to OF read/write/open services uverma
2026-08-17 10:27 ` [RFC PATCH 5/8] ppc/spapr: add block device backend to VOF open/read/write/seek services uverma
2026-08-17 10:27 ` [RFC PATCH 6/8] spapr_vscsi: add VOF disk nodes to the device tree uverma
2026-08-17 10:27 ` [RFC PATCH 7/8] ppc/spapr: strip OF path argument suffix in path_offset uverma
2026-08-17 10:27 ` [RFC PATCH 8/8] ppc/spapr: implement vscsi-report-luns call-method for PAPR vSCSI uverma
2026-08-19 6:55 ` [RFC PATCH 0/8] ppc/spapr: VOF disk image (qcow2) boot support Utkarsh Verma
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260817102733.605346-4-uverma@linux.ibm.com \
--to=uverma@linux.ibm.com \
--cc=aik@ozlabs.ru \
--cc=amachhiw@linux.ibm.com \
--cc=balaton@eik.bme.hu \
--cc=fam@euphon.net \
--cc=harshpb@linux.ibm.com \
--cc=marcandre.lureau@redhat.com \
--cc=nnmlinux@linux.ibm.com \
--cc=npiggin@gmail.com \
--cc=pbonzini@redhat.com \
--cc=philmd@oss.qualcomm.com \
--cc=qemu-devel@nongnu.org \
--cc=qemu-ppc@nongnu.org \
--cc=rathc@linux.ibm.com \
--cc=sbhat@linux.ibm.com \
--cc=th.huth@posteo.eu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox