Define the On-Core KHO serialization ABI (include/linux/kho/abi/cpu.h) and public session and job management APIs (include/linux/oncore.h).
Signed-off-by: Pasha Tatashin <[email protected]> --- arch/arm64/include/asm/oncore.h | 24 ++++++ arch/x86/include/asm/oncore.h | 25 +++++++ include/linux/kho/abi/cpu.h | 1 + include/linux/oncore.h | 129 ++++++++++++++++++++++++++++++++ kernel/liveupdate/Kconfig | 10 +++ 5 files changed, 189 insertions(+) create mode 100644 arch/arm64/include/asm/oncore.h create mode 100644 arch/x86/include/asm/oncore.h create mode 100644 include/linux/oncore.h diff --git a/arch/arm64/include/asm/oncore.h b/arch/arm64/include/asm/oncore.h new file mode 100644 index 000000000000..fbd0f218d867 --- /dev/null +++ b/arch/arm64/include/asm/oncore.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2026, Google LLC. + * Pasha Tatashin <[email protected]> + * + * ARM64 architecture hooks for On-Core execution. + */ +#ifndef _ASM_ARM64_ONCORE_H +#define _ASM_ARM64_ONCORE_H + +#include <linux/types.h> +#include <asm/arch_timer.h> + +static inline u64 __cpu_preserved_text arch_oncore_read_counter(void) +{ + return __arch_counter_get_cntpct(); +} + +static inline u64 arch_oncore_counter_freq_hz(void) +{ + return arch_timer_get_cntfrq(); +} + +#endif /* _ASM_ARM64_ONCORE_H */ diff --git a/arch/x86/include/asm/oncore.h b/arch/x86/include/asm/oncore.h new file mode 100644 index 000000000000..f64697a95d6a --- /dev/null +++ b/arch/x86/include/asm/oncore.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2026, Google LLC. + * Pasha Tatashin <[email protected]> + * + * x86 architecture hooks for On-Core execution. + */ +#ifndef _ASM_X86_ONCORE_H +#define _ASM_X86_ONCORE_H + +#include <linux/types.h> +#include <asm/msr.h> +#include <asm/tsc.h> + +static inline u64 __cpu_preserved_text arch_oncore_read_counter(void) +{ + return rdtsc(); +} + +static inline u64 arch_oncore_counter_freq_hz(void) +{ + return (u64)tsc_khz * 1000ULL; +} + +#endif /* _ASM_X86_ONCORE_H */ diff --git a/include/linux/kho/abi/cpu.h b/include/linux/kho/abi/cpu.h index f75bfb4c6161..4d63e623f162 100644 --- a/include/linux/kho/abi/cpu.h +++ b/include/linux/kho/abi/cpu.h @@ -145,6 +145,7 @@ struct cpu_preserved_file_ser { u32 cpu; u32 reserved; u64 stack_pa; + DECLARE_KHOSER_PTR(oncore, struct oncore_session_ser *); } __packed; #endif /* _LINUX_KHO_ABI_CPU_H */ diff --git a/include/linux/oncore.h b/include/linux/oncore.h new file mode 100644 index 000000000000..2817b0282a32 --- /dev/null +++ b/include/linux/oncore.h @@ -0,0 +1,129 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2026, Google LLC. + * Pasha Tatashin <[email protected]> + * + * On-Core Session and Scheduling Framework for Live Update + */ +#ifndef __LINUX_ONCORE_H +#define __LINUX_ONCORE_H + +#include <linux/cpu_preserve.h> +#include <linux/types.h> + +/* + * Only ever used as an opaque handle here, so do not include + * <linux/liveupdate.h>: this header is reached from <linux/kvm_host.h> via + * <linux/kvm_caretaker.h>, and including it would drag the entire LUO header + * stack into every KVM translation unit on every architecture. + */ +struct liveupdate_session; +struct oncore_session; +struct oncore_session_ser; +struct oncore_job; + +#include <asm/oncore.h> + +/** + * enum oncore_exit_reason - Why an on-core job returned to the scheduler + * @ONCORE_EXIT_QUANTUM_EXPIRED: Time slice elapsed; the job is still runnable. + * @ONCORE_EXIT_ATTACH_SIGNALED: The incoming kernel asked for the CPU back. + * @ONCORE_EXIT_YIELD_IDLE: The job has no work right now (guest HLT/WFI). + * @ONCORE_EXIT_ERROR: The job hit an unrecoverable error and must be dropped. + * @ONCORE_EXIT_STALL: The job hit something it cannot handle on-core and + * cannot make forward progress until the incoming kernel + * reclaims it. Unlike %ONCORE_EXIT_QUANTUM_EXPIRED, an + * immediate re-run is guaranteed to hit the same wall, so + * the scheduler backs off instead of spinning. + */ +enum oncore_exit_reason { + ONCORE_EXIT_QUANTUM_EXPIRED = 0, + ONCORE_EXIT_ATTACH_SIGNALED, + ONCORE_EXIT_YIELD_IDLE, + ONCORE_EXIT_ERROR, + ONCORE_EXIT_STALL, +}; + +typedef enum oncore_exit_reason (*oncore_job_fn)(void *data, + u64 deadline_ticks); + +#ifdef CONFIG_LIVEUPDATE_ONCORE +int oncore_session_add_cpu(struct liveupdate_session *s, int cpu); +void oncore_session_remove_cpu(struct liveupdate_session *s, int cpu); +struct oncore_session_ser *oncore_session_get_ser(struct liveupdate_session *s); +void oncore_session_restore(struct liveupdate_session *s, + struct oncore_session_ser *ser); +phys_addr_t oncore_session_get_pgd_pa(struct oncore_session *sess); +struct oncore_job *oncore_session_submit_job(struct liveupdate_session *s, + oncore_job_fn run_fn, + void *data); +int oncore_session_activate_job(struct liveupdate_session *s, + struct oncore_job *job); +void oncore_job_set_data(struct oncore_job *job, void *data); +int oncore_job_cpu(const struct oncore_job *job); +struct oncore_session *oncore_job_session(const struct oncore_job *job); +int oncore_session_cancel_job(struct liveupdate_session *s, + struct oncore_job *job); +int oncore_session_map_range(struct oncore_session *sess, phys_addr_t pa, + unsigned long va, size_t size, pgprot_t prot); +int oncore_session_map_buffer(struct oncore_session *sess, void *va, + size_t size); +#else +static inline int oncore_session_add_cpu(struct liveupdate_session *s, int cpu) { return 0; } + +static inline void oncore_session_remove_cpu(struct liveupdate_session *s, int cpu) {} + +static inline struct oncore_session_ser * +oncore_session_get_ser(struct liveupdate_session *s) +{ + return NULL; +} + +static inline void oncore_session_restore(struct liveupdate_session *s, + struct oncore_session_ser *ser) {} + +static inline phys_addr_t oncore_session_get_pgd_pa(struct oncore_session *sess) { return 0; } + +static inline struct oncore_job *oncore_session_submit_job(struct liveupdate_session *s, + oncore_job_fn run_fn, + void *data) +{ + return NULL; +} + +static inline int oncore_session_activate_job(struct liveupdate_session *s, + struct oncore_job *job) +{ + return -EOPNOTSUPP; +} + +static inline void oncore_job_set_data(struct oncore_job *job, void *data) {} + +static inline int oncore_job_cpu(const struct oncore_job *job) { return -1; } + +static inline struct oncore_session * +oncore_job_session(const struct oncore_job *job) +{ + return NULL; +} + +static inline int oncore_session_cancel_job(struct liveupdate_session *s, + struct oncore_job *job) +{ + return 0; +} + +static inline int oncore_session_map_range(struct oncore_session *sess, phys_addr_t pa, + unsigned long va, size_t size, pgprot_t prot) +{ + return 0; +} + +static inline int oncore_session_map_buffer(struct oncore_session *sess, void *va, + size_t size) +{ + return 0; +} +#endif /* CONFIG_LIVEUPDATE_ONCORE */ + +#endif /* __LINUX_ONCORE_H */ diff --git a/kernel/liveupdate/Kconfig b/kernel/liveupdate/Kconfig index 52c5fd7a620b..0e1f72de2a48 100644 --- a/kernel/liveupdate/Kconfig +++ b/kernel/liveupdate/Kconfig @@ -136,4 +136,14 @@ config LIVEUPDATE_CPU If unsure, say N. +config LIVEUPDATE_ONCORE + bool "On-core execution framework" + depends on LIVEUPDATE_CPU + default LIVEUPDATE_CPU + help + Provide the on-core execution session and job scheduling framework + for workloads running on preserved physical CPUs across a host + live update (kexec handover). This allows subsystems such as KVM + Caretaker to bind jobs to isolated physical cores during kexec. + endmenu -- 2.55.0.1082.g2b9226bbc0-goog

