From dcc1932f9d8e04a81636218ee5dafc6a73944a1a Mon Sep 17 00:00:00 2001 From: Nikolay Nikolaev Date: Wed, 26 Aug 2026 13:15:05 +0300 Subject: [PATCH] riscv: add multikernel architecture skeleton Wire CONFIG_MULTIKERNEL into the 64-bit RISC-V build and add sparse hart ID translations. Reject the invalid hart sentinel before lookup so it cannot alias an unused logical CPU slot. Declare the generic contiguous-allocation and memory-hotplug dependencies so CONFIG_MULTIKERNEL cannot expose an unbuildable configuration. Reserve the architecture control block for the spawn context, DTB and entry stub. Provide safe stubs for the full architecture interface so the functional SBI HSM, Image loader and doorbell work can land incrementally. Signed-off-by: Nikolay Nikolaev --- arch/riscv/Kbuild | 2 + arch/riscv/Kconfig | 8 +++ arch/riscv/include/asm/multikernel.h | 48 ++++++++++++++++++ arch/riscv/multikernel/Makefile | 3 ++ arch/riscv/multikernel/spawn.c | 73 ++++++++++++++++++++++++++++ arch/x86/Kconfig | 3 ++ include/linux/multikernel.h | 2 + kernel/multikernel/Kconfig | 8 +++ kernel/multikernel/hotplug.c | 4 ++ 9 files changed, 151 insertions(+) create mode 100644 arch/riscv/include/asm/multikernel.h create mode 100644 arch/riscv/multikernel/Makefile create mode 100644 arch/riscv/multikernel/spawn.c diff --git a/arch/riscv/Kbuild b/arch/riscv/Kbuild index 126fb738fc4423..635b24b5af7053 100644 --- a/arch/riscv/Kbuild +++ b/arch/riscv/Kbuild @@ -7,5 +7,7 @@ obj-$(CONFIG_KVM) += kvm/ obj-$(CONFIG_ARCH_SUPPORTS_KEXEC_PURGATORY) += purgatory/ +obj-$(CONFIG_MULTIKERNEL) += multikernel/ + # for cleaning subdir- += boot diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 90c531e6abf5cf..458f2a6d4588c8 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -1087,6 +1087,14 @@ config ARCH_SELECTS_KEXEC_FILE config ARCH_SUPPORTS_KEXEC_PURGATORY def_bool ARCH_SUPPORTS_KEXEC_FILE +config ARCH_SUPPORTS_MULTIKERNEL + def_bool y + depends on 64BIT + depends on RISCV_SBI + depends on KEXEC_FILE + depends on HOTPLUG_CPU + depends on !RISCV_M_MODE + config ARCH_SUPPORTS_CRASH_DUMP def_bool y diff --git a/arch/riscv/include/asm/multikernel.h b/arch/riscv/include/asm/multikernel.h new file mode 100644 index 00000000000000..f4d9685bf0abc4 --- /dev/null +++ b/arch/riscv/include/asm/multikernel.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef _ASM_RISCV_MULTIKERNEL_H +#define _ASM_RISCV_MULTIKERNEL_H + +#ifndef __ASSEMBLY__ + +#include +#include +#include + +#include +#include + +/* + * Hart IDs are sparse firmware identifiers and may exceed NR_CPUS. Keep + * them as values and always translate through the architecture CPU maps. + */ +static inline u64 arch_cpu_physical_id(int cpu) +{ + return cpuid_to_hartid_map(cpu); +} + +static inline int arch_cpu_from_physical_id(u64 hartid) +{ + if (hartid == INVALID_HARTID) + return -ENOENT; + + return riscv_hartid_to_cpuid(hartid); +} + +/* + * The RISC-V spawn path will use one page for its context, up to 64 KiB + * for the generated DTB, and one page for the fence.i entry stub. SBI HSM + * starts a hart in the existing address space, so no trampoline page tables + * are needed. + */ +#define MK_CTRL_BLOCK_SIZE (SZ_64K + 2 * PAGE_SIZE) + +/* + * Architecture-private spawn state is added with the SBI HSM and Image + * loader support. The compile-only skeleton intentionally has none. + */ +struct mk_instance_arch { +}; + +#endif /* !__ASSEMBLY__ */ + +#endif /* _ASM_RISCV_MULTIKERNEL_H */ diff --git a/arch/riscv/multikernel/Makefile b/arch/riscv/multikernel/Makefile new file mode 100644 index 00000000000000..3ef62e5996af69 --- /dev/null +++ b/arch/riscv/multikernel/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-y += spawn.o diff --git a/arch/riscv/multikernel/spawn.c b/arch/riscv/multikernel/spawn.c new file mode 100644 index 00000000000000..a576346bc94f25 --- /dev/null +++ b/arch/riscv/multikernel/spawn.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * RISC-V multikernel architecture interface skeleton. + * + * The SBI HSM spawn and park implementation is added by the follow-up + * architecture patches. Until then, operations which would change CPU + * ownership fail explicitly instead of pretending that a hart moved. + */ + +#include +#include +#include +#include + +void mk_arch_send_ipi(mk_phys_cpu_t phys_cpu) +{ + pr_warn_once("RISC-V multikernel IPI support is not implemented\n"); +} + +void mk_arch_register_cpu(mk_phys_cpu_t phys_id) +{ + /* RISC-V CPU topology already records possible harts. */ +} + +void __noreturn mk_enter_pool_state(void *info) +{ + /* Unreachable while CONFIG_ARCH_HAS_MK_POOL_STATE is disabled. */ + panic("RISC-V multikernel pool parking is not implemented"); +} + +int mk_arch_register_force_stop(void) +{ + return -EOPNOTSUPP; +} + +void mk_force_stop_cpu(mk_phys_cpu_t phys_cpu) +{ + pr_warn_once("RISC-V multikernel force-stop is not implemented\n"); +} + +int mk_arch_spawn_instance(struct kimage *image, struct mk_instance *instance, + int cpu) +{ + return -EOPNOTSUPP; +} + +int mk_arch_release_instance(struct mk_instance *instance) +{ + return 0; +} + +int mk_arch_confirm_parked(struct mk_instance *instance, + mk_phys_cpu_t phys_cpu) +{ + return -EOPNOTSUPP; +} + +int mk_repark_instance_to_host(struct mk_instance *instance) +{ + return -EOPNOTSUPP; +} + +int mk_repark_cpu_to_instance(struct mk_instance *instance, + mk_phys_cpu_t phys_cpu) +{ + return -EOPNOTSUPP; +} + +int mk_repark_cpu_to_host(struct mk_instance *instance, + mk_phys_cpu_t phys_cpu) +{ + return -EOPNOTSUPP; +} diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index d68cb9af266cf2..e7826bc9f23e13 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -2026,6 +2026,9 @@ config ARCH_SUPPORTS_MULTIKERNEL config ARCH_HAS_MK_HOST_PARK def_bool X86_64 +config ARCH_HAS_MK_POOL_STATE + def_bool X86_64 + config ARCH_SUPPORTS_CRASH_DUMP def_bool X86_64 || (X86_32 && HIGHMEM) diff --git a/include/linux/multikernel.h b/include/linux/multikernel.h index 5ca15323c4722d..7d5e27e1a9fd65 100644 --- a/include/linux/multikernel.h +++ b/include/linux/multikernel.h @@ -1029,6 +1029,8 @@ void *mk_instance_ctrl_alloc(struct mk_instance *instance, size_t size, * - CONFIG_ARCH_HAS_MK_HOST_PARK and the host park functions declared * with the pool chunk API above, for architectures that park CPUs in * software rather than in firmware. + * - CONFIG_ARCH_HAS_MK_POOL_STATE, if the architecture can park an + * offlined CPU for reassignment to another kernel instance. */ /* Doorbell for the message ring: IPI a CPU owned by another kernel */ diff --git a/kernel/multikernel/Kconfig b/kernel/multikernel/Kconfig index d71b25cce19116..dc918adb43daf8 100644 --- a/kernel/multikernel/Kconfig +++ b/kernel/multikernel/Kconfig @@ -10,10 +10,18 @@ config ARCH_SUPPORTS_MULTIKERNEL config ARCH_HAS_MK_HOST_PARK bool +# The arch can park an offlined CPU in a state from which multikernel can +# reassign it to another kernel instance. +config ARCH_HAS_MK_POOL_STATE + bool + config MULTIKERNEL bool "Multikernel support" depends on ARCH_SUPPORTS_MULTIKERNEL + depends on CONTIG_ALLOC depends on KEXEC_CORE + depends on MEMORY_HOTPLUG + depends on MEMORY_HOTREMOVE select LIBFDT help Enable multikernel support, which allows running multiple kernel diff --git a/kernel/multikernel/hotplug.c b/kernel/multikernel/hotplug.c index cf4125b480f35b..810e6b7bc06e60 100644 --- a/kernel/multikernel/hotplug.c +++ b/kernel/multikernel/hotplug.c @@ -192,6 +192,10 @@ static int mk_do_cpu_remove(mk_phys_cpu_t cpu_id) int ret; struct mk_hotplug_op *op; + /* Reject unsupported pool transitions before offlining the CPU. */ + if (!IS_ENABLED(CONFIG_ARCH_HAS_MK_POOL_STATE)) + return -EOPNOTSUPP; + logical_cpu = mk_cpu_to_logical(cpu_id); if (logical_cpu < 0) { pr_err("Multikernel hotplug: Physical CPU %llu not found\n", cpu_id);