Files
erofs-linux/include/linux/kexec_handover.h
T
Mike Rapoport (Microsoft) fc33e4b44b kexec: enable KHO support for memory preservation
Introduce APIs allowing KHO users to preserve memory across kexec and get
access to that memory after boot of the kexeced kernel

kho_preserve_folio() - record a folio to be preserved over kexec
kho_restore_folio() - recreates the folio from the preserved memory
kho_preserve_phys() - record physically contiguous range to be
preserved over kexec.

The memory preservations are tracked by two levels of xarrays to manage
chunks of per-order 512 byte bitmaps.  For instance if PAGE_SIZE = 4096,
the entire 1G order of a 1TB x86 system would fit inside a single 512 byte
bitmap.  For order 0 allocations each bitmap will cover 16M of address
space.  Thus, for 16G of memory at most 512K of bitmap memory will be
needed for order 0.

At serialization time all bitmaps are recorded in a linked list of pages
for the next kernel to process and the physical address of the list is
recorded in KHO FDT.

The next kernel then processes that list, reserves the memory ranges and
later, when a user requests a folio or a physical range, KHO restores
corresponding memory map entries.

Link: https://lkml.kernel.org/r/[email protected]
Suggested-by: Jason Gunthorpe <[email protected]>
Signed-off-by: Mike Rapoport (Microsoft) <[email protected]>
Co-developed-by: Changyuan Lyu <[email protected]>
Signed-off-by: Changyuan Lyu <[email protected]>
Cc: Alexander Graf <[email protected]>
Cc: Andy Lutomirski <[email protected]>
Cc: Anthony Yznaga <[email protected]>
Cc: Arnd Bergmann <[email protected]>
Cc: Ashish Kalra <[email protected]>
Cc: Ben Herrenschmidt <[email protected]>
Cc: Borislav Betkov <[email protected]>
Cc: Catalin Marinas <[email protected]>
Cc: Dave Hansen <[email protected]>
Cc: David Woodhouse <[email protected]>
Cc: Eric Biederman <[email protected]>
Cc: "H. Peter Anvin" <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: James Gowans <[email protected]>
Cc: Jonathan Corbet <[email protected]>
Cc: Krzysztof Kozlowski <[email protected]>
Cc: Marc Rutland <[email protected]>
Cc: Paolo Bonzini <[email protected]>
Cc: Pasha Tatashin <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Pratyush Yadav <[email protected]>
Cc: Rob Herring <[email protected]>
Cc: Saravana Kannan <[email protected]>
Cc: Stanislav Kinsburskii <[email protected]>
Cc: Steven Rostedt <[email protected]>
Cc: Thomas Gleinxer <[email protected]>
Cc: Thomas Lendacky <[email protected]>
Cc: Will Deacon <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
2025-05-12 23:50:40 -07:00

110 lines
2.5 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
#ifndef LINUX_KEXEC_HANDOVER_H
#define LINUX_KEXEC_HANDOVER_H
#include <linux/types.h>
#include <linux/errno.h>
struct kho_scratch {
phys_addr_t addr;
phys_addr_t size;
};
/* KHO Notifier index */
enum kho_event {
KEXEC_KHO_FINALIZE = 0,
KEXEC_KHO_ABORT = 1,
};
struct folio;
struct notifier_block;
#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_serialization;
#ifdef CONFIG_KEXEC_HANDOVER
bool kho_is_enabled(void);
int kho_preserve_folio(struct folio *folio);
int kho_preserve_phys(phys_addr_t phys, size_t size);
struct folio *kho_restore_folio(phys_addr_t phys);
int kho_add_subtree(struct kho_serialization *ser, const char *name, void *fdt);
int kho_retrieve_subtree(const char *name, phys_addr_t *phys);
int register_kho_notifier(struct notifier_block *nb);
int unregister_kho_notifier(struct notifier_block *nb);
void kho_memory_init(void);
void kho_populate(phys_addr_t fdt_phys, u64 fdt_len, phys_addr_t scratch_phys,
u64 scratch_len);
#else
static inline bool kho_is_enabled(void)
{
return false;
}
static inline int kho_preserve_folio(struct folio *folio)
{
return -EOPNOTSUPP;
}
static inline int kho_preserve_phys(phys_addr_t phys, size_t size)
{
return -EOPNOTSUPP;
}
static inline struct folio *kho_restore_folio(phys_addr_t phys)
{
return NULL;
}
static inline int kho_add_subtree(struct kho_serialization *ser,
const char *name, void *fdt)
{
return -EOPNOTSUPP;
}
static inline int kho_retrieve_subtree(const char *name, phys_addr_t *phys)
{
return -EOPNOTSUPP;
}
static inline int register_kho_notifier(struct notifier_block *nb)
{
return -EOPNOTSUPP;
}
static inline int unregister_kho_notifier(struct notifier_block *nb)
{
return -EOPNOTSUPP;
}
static inline void kho_memory_init(void)
{
}
static inline void kho_populate(phys_addr_t fdt_phys, u64 fdt_len,
phys_addr_t scratch_phys, u64 scratch_len)
{
}
#endif /* CONFIG_KEXEC_HANDOVER */
#endif /* LINUX_KEXEC_HANDOVER_H */