From: Jason Miu <jasonmiu@google.com>
The `struct kho_vmalloc` defines the in-memory layout for preserving
vmalloc regions across kexec. This layout is a contract between kernels
and part of the KHO ABI.
To reflect this relationship, the related structs and helper macros are
relocated to the ABI header, `include/linux/kho/abi/kexec_handover.h`.
This move places the structure's definition under the protection of the
KHO_FDT_COMPATIBLE version string.
The structure and its components are now also documented within the
ABI header to describe the contract and prevent ABI breaks.
Signed-off-by: Jason Miu <jasonmiu@google.com>
Co-developed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
---
Documentation/core-api/kho/abi.rst | 6 ++
include/linux/kexec_handover.h | 27 +--------
include/linux/kho/abi/kexec_handover.h | 78 ++++++++++++++++++++++++++
include/linux/kho/abi/memfd.h | 2 +-
kernel/liveupdate/kexec_handover.c | 15 -----
lib/test_kho.c | 1 +
6 files changed, 88 insertions(+), 41 deletions(-)
diff --git a/Documentation/core-api/kho/abi.rst b/Documentation/core-api/kho/abi.rst
index a1ee0f481727..1d9916adee23 100644
--- a/Documentation/core-api/kho/abi.rst
+++ b/Documentation/core-api/kho/abi.rst
@@ -10,6 +10,12 @@ Core Kexec Handover ABI
.. kernel-doc:: include/linux/kho/abi/kexec_handover.h
:doc: Kexec Handover ABI
+vmalloc preservation ABI
+========================
+
+.. kernel-doc:: include/linux/kho/abi/kexec_handover.h
+ :doc: Kexec Handover ABI for vmalloc Preservation
+
See Also
========
diff --git a/include/linux/kexec_handover.h b/include/linux/kexec_handover.h
index 5f7b9de97e8d..a56ff3ffaf17 100644
--- a/include/linux/kexec_handover.h
+++ b/include/linux/kexec_handover.h
@@ -11,34 +11,11 @@ struct kho_scratch {
phys_addr_t size;
};
+struct kho_vmalloc;
+
struct folio;
struct page;
-#define DECLARE_KHOSER_PTR(name, type) \
- union { \
- phys_addr_t phys; \
- type ptr; \
- } name
-#define KHOSER_STORE_PTR(dest, val) \
- ({ \
- typeof(val) v = val; \
- typecheck(typeof((dest).ptr), v); \
- (dest).phys = virt_to_phys(v); \
- })
-#define KHOSER_LOAD_PTR(src) \
- ({ \
- typeof(src) s = src; \
- (typeof((s).ptr))((s).phys ? phys_to_virt((s).phys) : NULL); \
- })
-
-struct kho_vmalloc_chunk;
-struct kho_vmalloc {
- DECLARE_KHOSER_PTR(first, struct kho_vmalloc_chunk *);
- unsigned int total_pages;
- unsigned short flags;
- unsigned short order;
-};
-
#ifdef CONFIG_KEXEC_HANDOVER
bool kho_is_enabled(void);
bool is_kho_boot(void);
diff --git a/include/linux/kho/abi/kexec_handover.h b/include/linux/kho/abi/kexec_handover.h
index af9fa8c134c7..285eda8a36e4 100644
--- a/include/linux/kho/abi/kexec_handover.h
+++ b/include/linux/kho/abi/kexec_handover.h
@@ -10,6 +10,8 @@
#ifndef _LINUX_KHO_ABI_KEXEC_HANDOVER_H
#define _LINUX_KHO_ABI_KEXEC_HANDOVER_H
+#include <linux/types.h>
+
/**
* DOC: Kexec Handover ABI
*
@@ -82,4 +84,80 @@
/* The FDT property for sub-FDTs. */
#define KHO_FDT_SUB_TREE_PROP_NAME "fdt"
+/**
+ * DOC: Kexec Handover ABI for vmalloc Preservation
+ *
+ * The Kexec Handover ABI for preserving vmalloc'ed memory is defined by
+ * a set of structures and helper macros. The layout of these structures is a
+ * stable contract between kernels and is versioned by the KHO_FDT_COMPATIBLE
+ * string.
+ *
+ * The preservation is managed through a main descriptor &struct kho_vmalloc,
+ * which points to a linked list of &struct kho_vmalloc_chunk structures. These
+ * chunks contain the physical addresses of the preserved pages, allowing the
+ * next kernel to reconstruct the vmalloc area with the same content and layout.
+ * Helper macros are also defined for storing and loading pointers within
+ * these structures.
+ */
+
+/* Helper macro to define a union for a serializable pointer. */
+#define DECLARE_KHOSER_PTR(name, type) \
+ union { \
+ u64 phys; \
+ type ptr; \
+ } name
+
+/* Stores the physical address of a serializable pointer. */
+#define KHOSER_STORE_PTR(dest, val) \
+ ({ \
+ typeof(val) v = val; \
+ typecheck(typeof((dest).ptr), v); \
+ (dest).phys = virt_to_phys(v); \
+ })
+
+/* Loads the stored physical address back to a pointer. */
+#define KHOSER_LOAD_PTR(src) \
+ ({ \
+ typeof(src) s = src; \
+ (typeof((s).ptr))((s).phys ? phys_to_virt((s).phys) : NULL); \
+ })
+
+/*
+ * This header is embedded at the beginning of each `kho_vmalloc_chunk`
+ * and contains a pointer to the next chunk in the linked list,
+ * stored as a physical address for handover.
+ */
+struct kho_vmalloc_hdr {
+ DECLARE_KHOSER_PTR(next, struct kho_vmalloc_chunk *);
+};
+
+#define KHO_VMALLOC_SIZE \
+ ((PAGE_SIZE - sizeof(struct kho_vmalloc_hdr)) / \
+ sizeof(u64))
+
+/*
+ * Each chunk is a single page and is part of a linked list that describes
+ * a preserved vmalloc area. It contains the header with the link to the next
+ * chunk and an array of physical addresses of the pages that make up the
+ * preserved vmalloc area.
+ */
+struct kho_vmalloc_chunk {
+ struct kho_vmalloc_hdr hdr;
+ u64 phys[KHO_VMALLOC_SIZE];
+};
+
+static_assert(sizeof(struct kho_vmalloc_chunk) == PAGE_SIZE);
+
+/*
+ * Describes a preserved vmalloc memory area, including the
+ * total number of pages, allocation flags, page order, and a pointer to the
+ * first chunk of physical page addresses.
+ */
+struct kho_vmalloc {
+ DECLARE_KHOSER_PTR(first, struct kho_vmalloc_chunk *);
+ unsigned int total_pages;
+ unsigned short flags;
+ unsigned short order;
+};
+
#endif /* _LINUX_KHO_ABI_KEXEC_HANDOVER_H */
diff --git a/include/linux/kho/abi/memfd.h b/include/linux/kho/abi/memfd.h
index c211c31334a3..68cb6303b846 100644
--- a/include/linux/kho/abi/memfd.h
+++ b/include/linux/kho/abi/memfd.h
@@ -12,7 +12,7 @@
#define _LINUX_KHO_ABI_MEMFD_H
#include <linux/types.h>
-#include <linux/kexec_handover.h>
+#include <linux/kho/abi/kexec_handover.h>
/**
* DOC: memfd Live Update ABI
diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c
index d3d02a9ea391..a180b3367e8f 100644
--- a/kernel/liveupdate/kexec_handover.c
+++ b/kernel/liveupdate/kexec_handover.c
@@ -882,21 +882,6 @@ void kho_unpreserve_pages(struct page *page, unsigned int nr_pages)
}
EXPORT_SYMBOL_GPL(kho_unpreserve_pages);
-struct kho_vmalloc_hdr {
- DECLARE_KHOSER_PTR(next, struct kho_vmalloc_chunk *);
-};
-
-#define KHO_VMALLOC_SIZE \
- ((PAGE_SIZE - sizeof(struct kho_vmalloc_hdr)) / \
- sizeof(phys_addr_t))
-
-struct kho_vmalloc_chunk {
- struct kho_vmalloc_hdr hdr;
- phys_addr_t phys[KHO_VMALLOC_SIZE];
-};
-
-static_assert(sizeof(struct kho_vmalloc_chunk) == PAGE_SIZE);
-
/* vmalloc flags KHO supports */
#define KHO_VMALLOC_SUPPORTED_FLAGS (VM_ALLOC | VM_ALLOW_HUGE_VMAP)
diff --git a/lib/test_kho.c b/lib/test_kho.c
index 47de56280795..3431daca6968 100644
--- a/lib/test_kho.c
+++ b/lib/test_kho.c
@@ -19,6 +19,7 @@
#include <linux/printk.h>
#include <linux/vmalloc.h>
#include <linux/kexec_handover.h>
+#include <linux/kho/abi/kexec_handover.h>
#include <net/checksum.h>
--
2.51.0
On Mon, Jan 05 2026, Mike Rapoport wrote:
> From: Jason Miu <jasonmiu@google.com>
>
> The `struct kho_vmalloc` defines the in-memory layout for preserving
> vmalloc regions across kexec. This layout is a contract between kernels
> and part of the KHO ABI.
>
> To reflect this relationship, the related structs and helper macros are
> relocated to the ABI header, `include/linux/kho/abi/kexec_handover.h`.
> This move places the structure's definition under the protection of the
> KHO_FDT_COMPATIBLE version string.
>
> The structure and its components are now also documented within the
> ABI header to describe the contract and prevent ABI breaks.
>
> Signed-off-by: Jason Miu <jasonmiu@google.com>
> Co-developed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
[...]
> +/* Helper macro to define a union for a serializable pointer. */
> +#define DECLARE_KHOSER_PTR(name, type) \
> + union { \
> + u64 phys; \
> + type ptr; \
> + } name
> +
> +/* Stores the physical address of a serializable pointer. */
> +#define KHOSER_STORE_PTR(dest, val) \
> + ({ \
> + typeof(val) v = val; \
> + typecheck(typeof((dest).ptr), v); \
> + (dest).phys = virt_to_phys(v); \
> + })
> +
> +/* Loads the stored physical address back to a pointer. */
> +#define KHOSER_LOAD_PTR(src) \
> + ({ \
> + typeof(src) s = src; \
> + (typeof((s).ptr))((s).phys ? phys_to_virt((s).phys) : NULL); \
> + })
Nit: not a fan of exposing code internals to the ABI header. But without
this the definition of kho_vmalloc_hdr won't make any sense to someone
reading the doc without looking at the code. Dunno if we can do anything
better though...
> +
> +/*
> + * This header is embedded at the beginning of each `kho_vmalloc_chunk`
> + * and contains a pointer to the next chunk in the linked list,
> + * stored as a physical address for handover.
> + */
> +struct kho_vmalloc_hdr {
> + DECLARE_KHOSER_PTR(next, struct kho_vmalloc_chunk *);
> +};
> +
> +#define KHO_VMALLOC_SIZE \
> + ((PAGE_SIZE - sizeof(struct kho_vmalloc_hdr)) / \
> + sizeof(u64))
> +
> +/*
> + * Each chunk is a single page and is part of a linked list that describes
> + * a preserved vmalloc area. It contains the header with the link to the next
> + * chunk and an array of physical addresses of the pages that make up the
> + * preserved vmalloc area.
Perhaps also mention that the array is 0-terminated?
Looks good otherwise.
[...]
--
Regards,
Pratyush Yadav
On Tue, Jan 20, 2026 at 04:26:51PM +0000, Pratyush Yadav wrote:
> On Mon, Jan 05 2026, Mike Rapoport wrote:
>
> > From: Jason Miu <jasonmiu@google.com>
> >
> > The `struct kho_vmalloc` defines the in-memory layout for preserving
> > vmalloc regions across kexec. This layout is a contract between kernels
> > and part of the KHO ABI.
> >
> > To reflect this relationship, the related structs and helper macros are
> > relocated to the ABI header, `include/linux/kho/abi/kexec_handover.h`.
> > This move places the structure's definition under the protection of the
> > KHO_FDT_COMPATIBLE version string.
> >
> > The structure and its components are now also documented within the
> > ABI header to describe the contract and prevent ABI breaks.
> >
> > Signed-off-by: Jason Miu <jasonmiu@google.com>
> > Co-developed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> > Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> [...]
> > +/* Helper macro to define a union for a serializable pointer. */
> > +#define DECLARE_KHOSER_PTR(name, type) \
> > + union { \
> > + u64 phys; \
> > + type ptr; \
> > + } name
> > +
> > +/* Stores the physical address of a serializable pointer. */
> > +#define KHOSER_STORE_PTR(dest, val) \
> > + ({ \
> > + typeof(val) v = val; \
> > + typecheck(typeof((dest).ptr), v); \
> > + (dest).phys = virt_to_phys(v); \
> > + })
> > +
> > +/* Loads the stored physical address back to a pointer. */
> > +#define KHOSER_LOAD_PTR(src) \
> > + ({ \
> > + typeof(src) s = src; \
> > + (typeof((s).ptr))((s).phys ? phys_to_virt((s).phys) : NULL); \
> > + })
>
> Nit: not a fan of exposing code internals to the ABI header. But without
> this the definition of kho_vmalloc_hdr won't make any sense to someone
> reading the doc without looking at the code. Dunno if we can do anything
> better though...
These might be actually useful for other KHO users.
> > +/*
> > + * This header is embedded at the beginning of each `kho_vmalloc_chunk`
> > + * and contains a pointer to the next chunk in the linked list,
> > + * stored as a physical address for handover.
> > + */
> > +struct kho_vmalloc_hdr {
> > + DECLARE_KHOSER_PTR(next, struct kho_vmalloc_chunk *);
> > +};
> > +
> > +#define KHO_VMALLOC_SIZE \
> > + ((PAGE_SIZE - sizeof(struct kho_vmalloc_hdr)) / \
> > + sizeof(u64))
> > +
> > +/*
> > + * Each chunk is a single page and is part of a linked list that describes
> > + * a preserved vmalloc area. It contains the header with the link to the next
> > + * chunk and an array of physical addresses of the pages that make up the
> > + * preserved vmalloc area.
>
> Perhaps also mention that the array is 0-terminated?
Yeah, sure.
@Andrew, can you please add this as a fixup:
diff --git a/include/linux/kho/abi/kexec_handover.h b/include/linux/kho/abi/kexec_handover.h
index 285eda8a36e4..2201a0d2c159 100644
--- a/include/linux/kho/abi/kexec_handover.h
+++ b/include/linux/kho/abi/kexec_handover.h
@@ -138,8 +138,8 @@ struct kho_vmalloc_hdr {
/*
* Each chunk is a single page and is part of a linked list that describes
* a preserved vmalloc area. It contains the header with the link to the next
- * chunk and an array of physical addresses of the pages that make up the
- * preserved vmalloc area.
+ * chunk and a zero terminated array of physical addresses of the pages that
+ * make up the preserved vmalloc area.
*/
struct kho_vmalloc_chunk {
struct kho_vmalloc_hdr hdr;
> Looks good otherwise.
> --
> Regards,
> Pratyush Yadav
--
Sincerely yours,
Mike.
On Tue, Jan 20 2026, Mike Rapoport wrote:
> On Tue, Jan 20, 2026 at 04:26:51PM +0000, Pratyush Yadav wrote:
>> On Mon, Jan 05 2026, Mike Rapoport wrote:
>>
>> > From: Jason Miu <jasonmiu@google.com>
>> >
>> > The `struct kho_vmalloc` defines the in-memory layout for preserving
>> > vmalloc regions across kexec. This layout is a contract between kernels
>> > and part of the KHO ABI.
>> >
>> > To reflect this relationship, the related structs and helper macros are
>> > relocated to the ABI header, `include/linux/kho/abi/kexec_handover.h`.
>> > This move places the structure's definition under the protection of the
>> > KHO_FDT_COMPATIBLE version string.
>> >
>> > The structure and its components are now also documented within the
>> > ABI header to describe the contract and prevent ABI breaks.
>> >
>> > Signed-off-by: Jason Miu <jasonmiu@google.com>
>> > Co-developed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
>> > Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
>> [...]
>> > +/* Helper macro to define a union for a serializable pointer. */
>> > +#define DECLARE_KHOSER_PTR(name, type) \
>> > + union { \
>> > + u64 phys; \
>> > + type ptr; \
>> > + } name
>> > +
>> > +/* Stores the physical address of a serializable pointer. */
>> > +#define KHOSER_STORE_PTR(dest, val) \
>> > + ({ \
>> > + typeof(val) v = val; \
>> > + typecheck(typeof((dest).ptr), v); \
>> > + (dest).phys = virt_to_phys(v); \
>> > + })
>> > +
>> > +/* Loads the stored physical address back to a pointer. */
>> > +#define KHOSER_LOAD_PTR(src) \
>> > + ({ \
>> > + typeof(src) s = src; \
>> > + (typeof((s).ptr))((s).phys ? phys_to_virt((s).phys) : NULL); \
>> > + })
>>
>> Nit: not a fan of exposing code internals to the ABI header. But without
>> this the definition of kho_vmalloc_hdr won't make any sense to someone
>> reading the doc without looking at the code. Dunno if we can do anything
>> better though...
>
> These might be actually useful for other KHO users.
Hmm, okay. Let's keep them here then.
[...]
--
Regards,
Pratyush Yadav
On Tue, Jan 20, 2026 at 1:56 PM Pratyush Yadav <pratyush@kernel.org> wrote:
>
> On Tue, Jan 20 2026, Mike Rapoport wrote:
>
> > On Tue, Jan 20, 2026 at 04:26:51PM +0000, Pratyush Yadav wrote:
> >> On Mon, Jan 05 2026, Mike Rapoport wrote:
> >>
> >> > From: Jason Miu <jasonmiu@google.com>
> >> >
> >> > The `struct kho_vmalloc` defines the in-memory layout for preserving
> >> > vmalloc regions across kexec. This layout is a contract between kernels
> >> > and part of the KHO ABI.
> >> >
> >> > To reflect this relationship, the related structs and helper macros are
> >> > relocated to the ABI header, `include/linux/kho/abi/kexec_handover.h`.
> >> > This move places the structure's definition under the protection of the
> >> > KHO_FDT_COMPATIBLE version string.
> >> >
> >> > The structure and its components are now also documented within the
> >> > ABI header to describe the contract and prevent ABI breaks.
> >> >
> >> > Signed-off-by: Jason Miu <jasonmiu@google.com>
> >> > Co-developed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> >> > Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> >> [...]
> >> > +/* Helper macro to define a union for a serializable pointer. */
> >> > +#define DECLARE_KHOSER_PTR(name, type) \
> >> > + union { \
> >> > + u64 phys; \
> >> > + type ptr; \
> >> > + } name
> >> > +
> >> > +/* Stores the physical address of a serializable pointer. */
> >> > +#define KHOSER_STORE_PTR(dest, val) \
> >> > + ({ \
> >> > + typeof(val) v = val; \
> >> > + typecheck(typeof((dest).ptr), v); \
> >> > + (dest).phys = virt_to_phys(v); \
> >> > + })
> >> > +
> >> > +/* Loads the stored physical address back to a pointer. */
> >> > +#define KHOSER_LOAD_PTR(src) \
> >> > + ({ \
> >> > + typeof(src) s = src; \
> >> > + (typeof((s).ptr))((s).phys ? phys_to_virt((s).phys) : NULL); \
> >> > + })
> >>
> >> Nit: not a fan of exposing code internals to the ABI header. But without
> >> this the definition of kho_vmalloc_hdr won't make any sense to someone
> >> reading the doc without looking at the code. Dunno if we can do anything
> >> better though...
> >
> > These might be actually useful for other KHO users.
In my view, khoser definition belongs in the kernel implementation
rather than the cross-kernel ABI. The ABI describes the preserved data
format and should be independent of C types. However, this is a minor
complaint compared to the overall effort of moving the preserved
format into the ABI and making KHO stateless. For that reason, let's
merge it.
Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com>
© 2016 - 2026 Red Hat, Inc.