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);