Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions arch/riscv/Kbuild
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,7 @@ obj-$(CONFIG_KVM) += kvm/

obj-$(CONFIG_ARCH_SUPPORTS_KEXEC_PURGATORY) += purgatory/

obj-$(CONFIG_MULTIKERNEL) += multikernel/

# for cleaning
subdir- += boot
8 changes: 8 additions & 0 deletions arch/riscv/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
48 changes: 48 additions & 0 deletions arch/riscv/include/asm/multikernel.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _ASM_RISCV_MULTIKERNEL_H
#define _ASM_RISCV_MULTIKERNEL_H

#ifndef __ASSEMBLY__

#include <linux/errno.h>
#include <linux/sizes.h>
#include <linux/types.h>

#include <asm/page.h>
#include <asm/smp.h>

/*
* 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 */
3 changes: 3 additions & 0 deletions arch/riscv/multikernel/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only

obj-y += spawn.o
73 changes: 73 additions & 0 deletions arch/riscv/multikernel/spawn.c
Original file line number Diff line number Diff line change
@@ -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 <linux/errno.h>
#include <linux/kernel.h>
#include <linux/kexec.h>
#include <linux/multikernel.h>

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mk_enter_pool_state() panics the host. If the generic core reaches this on a CPU-pool path (it is the __noreturn hook other arches use when offlining a CPU into the pool), an unsupported operation takes down the whole host instead of failing the offline request. Same intent-vs-behavior mismatch: better to reject the pool transition earlier (e.g. from mk_arch_register_cpu() or a capability check) so this hook is never reached.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in dcc1932 with a temporary ARCH_HAS_MK_POOL_STATE capability. x86 enables it; the RISC-V skeleton leaves it disabled. mk_do_cpu_remove() checks the capability before marking or offlining the CPU and returns -EOPNOTSUPP, so generic pool and hotplug removal paths cannot reach mk_enter_pool_state() on RISC-V. The rv64 Image build and an x86 focused hotplug build both pass.

}

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;
}
3 changes: 3 additions & 0 deletions arch/x86/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
2 changes: 2 additions & 0 deletions include/linux/multikernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
8 changes: 8 additions & 0 deletions kernel/multikernel/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions kernel/multikernel/hotplug.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down