[PATCH v1 3/6] xen/riscv: add zImage kernel loading support

Oleksii Kurochko posted 6 patches 1 month, 4 weeks ago
There is a newer version of this series
[PATCH v1 3/6] xen/riscv: add zImage kernel loading support
Posted by Oleksii Kurochko 1 month, 4 weeks ago
Introduce support for loading a Linux zImage kernel on RISC-V.

Note that if panic() is used instead of returning an error as common code
doesn't expect to have return code and it is something that should be
done separately.

This prepares the RISC-V port for booting Linux guests using the common
domain build infrastructure.

The code is based on Xen Arm code.

Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
---
 xen/arch/riscv/Makefile             |   1 +
 xen/arch/riscv/include/asm/config.h |  13 +++
 xen/arch/riscv/kernel.c             | 156 ++++++++++++++++++++++++++++
 3 files changed, 170 insertions(+)
 create mode 100644 xen/arch/riscv/kernel.c

diff --git a/xen/arch/riscv/Makefile b/xen/arch/riscv/Makefile
index 90210799e038..2e15f894fdd4 100644
--- a/xen/arch/riscv/Makefile
+++ b/xen/arch/riscv/Makefile
@@ -7,6 +7,7 @@ obj-y += guestcopy.o
 obj-y += imsic.o
 obj-y += intc.o
 obj-y += irq.o
+obj-y += kernel.o
 obj-y += mm.o
 obj-y += p2m.o
 obj-y += paging.o
diff --git a/xen/arch/riscv/include/asm/config.h b/xen/arch/riscv/include/asm/config.h
index 86a95df018b5..d24b54d656b8 100644
--- a/xen/arch/riscv/include/asm/config.h
+++ b/xen/arch/riscv/include/asm/config.h
@@ -152,6 +152,19 @@
 extern unsigned long phys_offset; /* = load_start - XEN_VIRT_START */
 #endif
 
+/*
+ * KERNEL_LOAD_ADDR_ALIGNMENT is defined based on paragraph of
+ * "Kernel location" of boot.rst:
+ * https://docs.kernel.org/arch/riscv/boot.html#kernel-location
+ */
+#if defined(CONFIG_RISCV_32)
+#define KERNEL_LOAD_ADDR_ALIGNMENT MB(4)
+#elif defined(CONFIG_RISCV_64)
+#define KERNEL_LOAD_ADDR_ALIGNMENT MB(2)
+#else
+#error "Define KERNEL_LOAD_ADDR_ALIGNMENT"
+#endif
+
 #endif /* ASM__RISCV__CONFIG_H */
 /*
  * Local variables:
diff --git a/xen/arch/riscv/kernel.c b/xen/arch/riscv/kernel.c
new file mode 100644
index 000000000000..f91e9ada8a9c
--- /dev/null
+++ b/xen/arch/riscv/kernel.c
@@ -0,0 +1,156 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <xen/bug.h>
+#include <xen/compiler.h>
+#include <xen/errno.h>
+#include <xen/fdt-kernel.h>
+#include <xen/guest_access.h>
+#include <xen/init.h>
+#include <xen/libfdt/libfdt.h>
+#include <xen/mm.h>
+#include <xen/types.h>
+#include <xen/vmap.h>
+
+#include <asm/setup.h>
+
+#define ZIMAGE64_MAGIC_V2 0x05435352 /* Magic number 2, le, "RSC\x05" */
+
+static void __init place_modules(struct kernel_info *info, paddr_t kernbase,
+                                 paddr_t kernend)
+{
+    const struct boot_module *mod = info->bd.initrd;
+
+    const paddr_t initrd_len = ROUNDUP(mod ? mod->size : 0, MB(2));
+    const paddr_t dtb_len = ROUNDUP(fdt_totalsize(info->fdt), MB(2));
+    const paddr_t modsize = initrd_len + dtb_len;
+
+    const paddr_t ramsize = info->mem.bank[0].size;
+    const paddr_t kernsize = ROUNDUP(kernend, MB(2)) - kernbase;
+
+    if ( modsize + kernsize > ramsize )
+        panic("Not enough memory in the first bank for the kernel+dtb+initrd\n");
+
+    info->dtb_paddr = ROUNDUP(kernend, MB(2));
+
+    info->initrd_paddr = info->dtb_paddr + dtb_len;
+}
+
+static paddr_t __init kernel_zimage_place(struct kernel_info *info)
+{
+    paddr_t load_addr;
+
+    /*
+     * At the moment, RISC-V's Linux kernel should be always position
+     * independent based on "Per-MMU execution" of boot.rst:
+     *   https://docs.kernel.org/arch/riscv/boot.html#pre-mmu-execution
+     *
+     * But just for the case when RISC-V's Linux kernel isn't position
+     * indepenet it is needed to take load address from
+     * info->zimage.start.
+     *
+     * If `start` is zero, the zImage is position independent. */
+    if ( likely(!info->zimage.start) )
+        /*
+         * According to boot.rst kernel load address should be properly
+         * aligned:
+         *   https://docs.kernel.org/arch/riscv/boot.html#kernel-location
+         */
+        load_addr = ROUNDUP(info->mem.bank[0].start, KERNEL_LOAD_ADDR_ALIGNMENT);
+    else
+        load_addr = info->zimage.start;
+
+    return load_addr;
+}
+
+static void __init kernel_zimage_load(struct kernel_info *info)
+{
+    int rc;
+    paddr_t load_addr = kernel_zimage_place(info);
+    paddr_t paddr = info->zimage.kernel_addr;
+    paddr_t len = info->zimage.len;
+    void *kernel;
+
+    info->entry = load_addr;
+
+    place_modules(info, load_addr, load_addr + len);
+
+    printk("Loading zImage from %"PRIpaddr" to %"PRIpaddr"-%"PRIpaddr"\n",
+            paddr, load_addr, load_addr + len);
+
+    kernel = ioremap_wc(paddr, len);
+
+    if ( !kernel )
+        panic("Unable to map kernel\n");
+
+    /* Move kernel to proper location in guest phys map */
+    rc = copy_to_guest_phys(info->bd.d, load_addr, kernel, len);
+
+    if ( rc )
+        panic("Unable to copy kernel to proper guest location\n");
+
+    iounmap(kernel);
+}
+
+/* Check if the image is a 64-bit Image */
+static int __init kernel_zimage64_probe(struct kernel_info *info,
+                                        paddr_t addr, paddr_t size)
+{
+    /* riscv/boot-image-header.rst */
+    struct {
+        u32 code0;		  /* Executable code */
+        u32 code1;		  /* Executable code */
+        u64 text_offset;  /* Image load offset, little endian */
+        u64 image_size;	  /* Effective Image size, little endian */
+        u64 flags;		  /* kernel flags, little endian */
+        u32 version;	  /* Version of this header */
+        u32 res1;		  /* Reserved */
+        u64 res2;		  /* Reserved */
+        u64 magic;        /* Deprecated: Magic number, little endian, "RISCV" */
+        u32 magic2;       /* Magic number 2, little endian, "RSC\x05" */
+        u32 res3;		  /* Reserved for PE COFF offset */
+    } zimage;
+    uint64_t start, end;
+
+    if ( size < sizeof(zimage) )
+        return -EINVAL;
+
+    copy_from_paddr(&zimage, addr, sizeof(zimage));
+
+    /* Magic v1 is deprecated and may be removed.  Only use v2 */
+    if ( zimage.magic2 != ZIMAGE64_MAGIC_V2 )
+        return -EINVAL;
+
+    /* Currently there is no length in the header, so just use the size */
+    start = 0;
+    end = size;
+
+    /*
+     * Given the above this check is a bit pointless, but leave it
+     * here in case someone adds a length field in the future.
+     */
+    if ( (end - start) > size )
+        return -EINVAL;
+
+    info->zimage.kernel_addr = addr;
+    info->zimage.len = end - start;
+    info->zimage.text_offset = zimage.text_offset;
+    info->zimage.start = 0;
+
+    info->load = kernel_zimage_load;
+
+    return 0;
+}
+
+int __init kernel_zimage_probe(struct kernel_info *info, paddr_t addr,
+                               paddr_t size)
+{
+    int rc;
+
+#ifdef CONFIG_RISCV_64
+    rc = kernel_zimage64_probe(info, addr, size);
+    if (rc < 0)
+#endif
+        panic("only RISC-V 64 is supported\n");
+
+    return rc;
+}
-- 
2.52.0
Re: [PATCH v1 3/6] xen/riscv: add zImage kernel loading support
Posted by Jan Beulich 1 month, 3 weeks ago
On 12.02.2026 17:21, Oleksii Kurochko wrote:
> Introduce support for loading a Linux zImage kernel on RISC-V.

Before I look here in any detail - where would a zImage come from? I can't
spot any support for it in Linux'es arch/riscv/Makefile (whereas
arch/arm/Makefile has such).

> Note that if panic() is used instead of returning an error as common code
> doesn't expect to have return code and it is something that should be
> done separately.

Is the "if" in this sentence a leftover from some editing of earlier
different text? I can't make sense of it. Also, which "common code" do you
mean? kernel_zimage_probe()'s sole caller does respect the return value
(handing it on).

> This prepares the RISC-V port for booting Linux guests using the common
> domain build infrastructure.

Again, what's "common" here? Not something x86 uses, afaict.

Jan
Re: [PATCH v1 3/6] xen/riscv: add zImage kernel loading support
Posted by Oleksii Kurochko 1 month, 3 weeks ago
On 2/16/26 5:31 PM, Jan Beulich wrote:
> On 12.02.2026 17:21, Oleksii Kurochko wrote:
>> Introduce support for loading a Linux zImage kernel on RISC-V.
> Before I look here in any detail - where would a zImage come from? I can't
> spot any support for it in Linux'es arch/riscv/Makefile (whereas
> arch/arm/Makefile has such).

Good point.

It is something that should be renamed as not Arm64 (Arm32 really has such
target), not RISC-V doesn't really work with zImage. They are using Image plus
Image.gz as compressed image.

Maybe it would be better to rename kernel_zimage_probe() to something more
generic kernel_image_probe().

>
>> Note that if panic() is used instead of returning an error as common code
>> doesn't expect to have return code and it is something that should be
>> done separately.
> Is the "if" in this sentence a leftover from some editing of earlier
> different text? I can't make sense of it. Also, which "common code" do you
> mean? kernel_zimage_probe()'s sole caller does respect the return value
> (handing it on).

It is about kernel_zimage_load() which is used to set:
   struct kernel_info->load = kernel_zimage_load
in kernel_zimage64_probe().

and which is called (and is in common code) from:
   void __init kernel_load(struct kernel_info *info)
   {
       ASSERT(info && info->load);

       info->load(info);
   }


>
>> This prepares the RISC-V port for booting Linux guests using the common
>> domain build infrastructure.
> Again, what's "common" here? Not something x86 uses, afaict.

By "common" here I meant dom0less's common code which may use functions
from this file.
I will update that part to use more specific instead of "common".

~ Oleksii
Re: [PATCH v1 3/6] xen/riscv: add zImage kernel loading support
Posted by Jan Beulich 1 month, 3 weeks ago
On 17.02.2026 12:58, Oleksii Kurochko wrote:
> On 2/16/26 5:31 PM, Jan Beulich wrote:
>> On 12.02.2026 17:21, Oleksii Kurochko wrote:
>>> Introduce support for loading a Linux zImage kernel on RISC-V.
>> Before I look here in any detail - where would a zImage come from? I can't
>> spot any support for it in Linux'es arch/riscv/Makefile (whereas
>> arch/arm/Makefile has such).
> 
> Good point.
> 
> It is something that should be renamed as not Arm64 (Arm32 really has such
> target), not RISC-V doesn't really work with zImage. They are using Image plus
> Image.gz as compressed image.
> 
> Maybe it would be better to rename kernel_zimage_probe() to something more
> generic kernel_image_probe().

Well, it's two things. In the description you explicitly say zImage. That's
simply misleading. Renaming the function (if indeed it copes with more than
just zImage) would likely be a good thing too, but needs sorting with its
maintainers.

Jan
Re: [PATCH v1 3/6] xen/riscv: add zImage kernel loading support
Posted by Oleksii Kurochko 1 month, 3 weeks ago
On 2/17/26 2:02 PM, Jan Beulich wrote:
> On 17.02.2026 12:58, Oleksii Kurochko wrote:
>> On 2/16/26 5:31 PM, Jan Beulich wrote:
>>> On 12.02.2026 17:21, Oleksii Kurochko wrote:
>>>> Introduce support for loading a Linux zImage kernel on RISC-V.
>>> Before I look here in any detail - where would a zImage come from? I can't
>>> spot any support for it in Linux'es arch/riscv/Makefile (whereas
>>> arch/arm/Makefile has such).
>> Good point.
>>
>> It is something that should be renamed as not Arm64 (Arm32 really has such
>> target), not RISC-V doesn't really work with zImage. They are using Image plus
>> Image.gz as compressed image.
>>
>> Maybe it would be better to rename kernel_zimage_probe() to something more
>> generic kernel_image_probe().
> Well, it's two things. In the description you explicitly say zImage. That's
> simply misleading.

Agree, it should be just Image, I'll update that part of commit description
in the next version.

>   Renaming the function (if indeed it copes with more than
> just zImage) would likely be a good thing too, but needs sorting with its
> maintainers.

I will suggest that then in a separate patch.

~ Oleksii