Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
98 commits
Select commit Hold shift + click to select a range
4cdb139
vsock: Unhash released sockets in mk_transport
congwang-mk Sep 27, 2026
3f867f5
x86/multikernel: Verify appended signatures on ELF vmlinux kernels
congwang-mk Sep 30, 2026
45b3c72
kexec: Publish a multikernel image only once it is loaded
congwang-mk Sep 30, 2026
07f5e9c
multikernel: Keep the manifest page and IPI ring in the instance
congwang-mk Sep 30, 2026
e372932
kexec: Load multikernel images only through kexec_file_load()
congwang-mk Sep 30, 2026
40368e0
multikernel: Keep one instance pool chunk for every memory region
congwang-mk Sep 30, 2026
4ad8799
multikernel: Let a message be sent and answered with interrupts off
congwang-mk Sep 21, 2026
893d42d
multikernel: Add a request that waits for its answer on the ring
congwang-mk Oct 16, 2026
be43750
multikernel: Serve the config space of lent PCI functions over the ring
congwang-mk Oct 16, 2026
767a0ae
multikernel: Filter the config writes of an instance
congwang-mk Oct 16, 2026
564b177
multikernel: Describe each bus of an instance as a root bus of its own
congwang-mk Oct 16, 2026
f7c65bf
multikernel: Reach the config space of a spawn's PCI devices through …
congwang-mk Oct 16, 2026
159351a
multikernel: Keep a spawn's PCI devices reachable after its host is lost
congwang-mk Oct 16, 2026
95c2315
multikernel: Park a panicked CPU that perf would keep from a force halt
congwang-mk Oct 16, 2026
221776e
multikernel: Start an instance from the instance code
congwang-mk Oct 16, 2026
0f57761
multikernel: Let a running spawn take a PCI function it did not boot …
congwang-mk Oct 16, 2026
fe20140
multikernel: Describe every PCI bus to a backup
congwang-mk Oct 17, 2026
5f22157
multikernel: Answer only a spawn's own functions once its host is fenced
congwang-mk Oct 17, 2026
09d81d9
multikernel: Take a lone function of a slot on a new bus
congwang-mk Oct 17, 2026
7dbc219
multikernel: Let a spawn adopt a function of its fenced host
congwang-mk Oct 17, 2026
a80ee44
multikernel: Stop claiming instance memory as System RAM
congwang-mk Oct 17, 2026
73df40d
x86/mm: Make kernel_physical_mapping_remove() available to multikernel
congwang-mk Oct 17, 2026
6de743a
multikernel: Hot-remove pool memory from the host
congwang-mk Oct 17, 2026
9731a23
x86/mm: Split a 1G direct mapping that hot-remove only partly covers
congwang-mk Oct 18, 2026
98a86fb
mm/memory_hotplug: Remove and add back parts of memory blocks
congwang-mk Oct 18, 2026
38d7514
multikernel: Take pool memory without whole memory blocks
congwang-mk Oct 18, 2026
57f5b3a
multikernel: Add and remove instance memory without whole memory blocks
congwang-mk Oct 18, 2026
2955ca7
multikernel: Account instance memory-add at the range the kernel adds
congwang-mk Oct 18, 2026
f66eb66
x86/multikernel: Don't reserve RAM buffers in spawn kernels
congwang-mk Oct 18, 2026
ae0ac31
multikernel: Publish the memory granule in the device tree
congwang-mk Oct 18, 2026
e6a5422
multikernel: Bind an added device only where the bus would
congwang-mk Oct 19, 2026
ac022f1
multikernel: Lend PCI functions without MSI-X
congwang-mk Oct 19, 2026
ae8d89a
multikernel: Take a lone function of a slot on a bus a spawn boots with
congwang-mk Oct 19, 2026
7f84c4e
multikernel: Reset a PCI function taken back from an instance
congwang-mk Oct 19, 2026
2e160e6
x86/multikernel: Don't pass the host's RSDP to a spawn kernel
congwang-mk Oct 20, 2026
8947fea
x86/multikernel: Keep ACPI disabled in a spawn kernel against acpi=force
congwang-mk Oct 20, 2026
913f340
x86/multikernel: Don't use IPI shorthands when the APIC bus is shared
congwang-mk Oct 21, 2026
39c88f5
mklinux: v7.0-mk4
congwang-mk Oct 26, 2026
735f178
selftests: multikernel: reproduce stale and duplicate ACK completion
pro-utkarshM Sep 27, 2026
ccd11fe
multikernel: make pending message completion single-shot
pro-utkarshM Sep 27, 2026
c9533b7
multikernel: correlate resource and shutdown ACKs by request ID
pro-utkarshM Sep 27, 2026
985a53a
multikernel: keep PCI ACK resource keys unsigned
pro-utkarshM Sep 27, 2026
8de9d04
multikernel: decode resource and system payloads in aligned storage
pro-utkarshM Oct 4, 2026
5c4a958
multikernel: retain CPU ownership across uncertain handoffs
pro-utkarshM Oct 4, 2026
4bac9e7
multikernel: serialize controller image and resource operations
pro-utkarshM Oct 4, 2026
862d1a1
multikernel: order received CPU hotplug requests
pro-utkarshM Oct 4, 2026
4278cf3
multikernel: quiesce incoming hotplug work before requested shutdown
pro-utkarshM Oct 4, 2026
021d794
multikernel: fence controller workers and require confirmed stop befo…
pro-utkarshM Oct 4, 2026
f721070
x86/multikernel: confirm destination arrival before retiring a park area
pro-utkarshM Oct 4, 2026
6d65f17
multikernel: serialize callback registration and close cleanup admission
pro-utkarshM Oct 4, 2026
629c379
multikernel: order ring capacity release before slot reuse
pro-utkarshM Oct 4, 2026
14af387
multikernel: preserve the shared host receive ring across respawn
pro-utkarshM Oct 4, 2026
ec0fa03
selftests: multikernel: expand compact fixture statements
pro-utkarshM Oct 5, 2026
a80b359
multikernel: use raw locking for pending ACK completion from hard IPI
pro-utkarshM Oct 5, 2026
bab3aed
x86/multikernel: wake locally donated CPUs on the local pool slot
pro-utkarshM Oct 5, 2026
de9907e
x86/kexec: guard multikernel E820 setup in the bzImage loader
pro-utkarshM Oct 5, 2026
6f88735
tty: defer multikernel host receive wakeups out of hard IPI context
pro-utkarshM Oct 5, 2026
8263cb7
tty: defer multikernel spawn input delivery to preallocated work
pro-utkarshM Oct 5, 2026
dbe2700
tty: close multikernel receive initialization and session teardown gaps
pro-utkarshM Oct 5, 2026
aaa4f94
multikernel: serialize pool CPU set updates with x86 wake readers
pro-utkarshM Oct 5, 2026
86bdec0
test: format multikernel lifecycle fixtures
pro-utkarshM Oct 6, 2026
468b237
multikernel: reject execution before active halt settlement
pro-utkarshM Oct 6, 2026
ce39676
multikernel: drain native CPU hotplug before shutdown acknowledgment
pro-utkarshM Oct 6, 2026
049e998
x86/multikernel: qualify voluntary halt notifications before reuse
pro-utkarshM Oct 6, 2026
3b90b06
multikernel: serialize kernfs device-tree snapshots with resource wri…
pro-utkarshM Oct 6, 2026
7c3f71c
kexec: free command line on early file-load failure
pro-utkarshM Oct 6, 2026
f90212b
cpu/hotplug: withdraw presence before completing multikernel departure
pro-utkarshM Oct 7, 2026
c4cd652
cpu/hotplug: serialize multikernel handback and retain uncertain owne…
pro-utkarshM Oct 7, 2026
15e00c7
x86/multikernel: quarantine uncertain mailbox handoffs
pro-utkarshM Oct 7, 2026
e5287ca
multikernel: require CPU hotplug for lifecycle support
pro-utkarshM Oct 7, 2026
70d58bc
multikernel: preserve early PCI message handler registration
pro-utkarshM Oct 23, 2026
9a4ca35
selftests: multikernel: account for pool mapping retirement
pro-utkarshM Oct 23, 2026
9921b7f
multikernel: require boot Device Tree support for manifests
pro-utkarshM Oct 23, 2026
d83cf00
multikernel: retire admitted PCI requests before instance reuse
pro-utkarshM Oct 23, 2026
76fa2b1
multikernel: retain uncertain resource transfers and failed overlays
pro-utkarshM Oct 23, 2026
71b6b4b
multikernel: drain stopped-peer inbox requests before reuse
pro-utkarshM Oct 23, 2026
81f7ffb
multikernel: retain memory when pool unmapping fails
pro-utkarshM Oct 23, 2026
893d7e9
multikernel: allow the empty host memory record at first baseline
pro-utkarshM Oct 23, 2026
b2c404e
multikernel: preallocate one-shot requested shutdown work
pro-utkarshM Oct 24, 2026
2560b0e
multikernel: pin preallocated voluntary halt work through settlement
pro-utkarshM Oct 24, 2026
d5a6fdf
multikernel: assemble messages in the reserved IPI slot
pro-utkarshM Oct 24, 2026
248188a
multikernel: preallocate bounded resource request work
pro-utkarshM Oct 24, 2026
efffba4
multikernel: preallocate deferred PCI config requests
pro-utkarshM Oct 24, 2026
501cb24
vsock/multikernel: defer receive allocation out of raw IPI context
pro-utkarshM Oct 24, 2026
b7a6f1c
multikernel: reject local PCI hotplug without PCI support
pro-utkarshM Oct 25, 2026
70bc274
riscv: avoid indexing folded levels twice during memory removal
pro-utkarshM Oct 23, 2026
fc6ea30
multikernel: prepare architecture state before emitting the boot mani…
pro-utkarshM Oct 4, 2026
8397f6c
multikernel: keep the physical CPU zero fallback for old host doorbells
pro-utkarshM Oct 4, 2026
4dbd5f3
Merge generic lifecycle safety for RISC-V pool validation
pro-utkarshM Nov 3, 2026
5546a73
riscv: cap multikernel direct-map leaves at subsection size
pro-utkarshM Oct 23, 2026
beaba2d
riscv: map hot-removed multikernel pool allocations with fallible tables
pro-utkarshM Oct 23, 2026
eb76d16
riscv: check online RAM when admitting multikernel pool mappings
pro-utkarshM Oct 23, 2026
57b43f8
Merge the manifest prerequisite for RISC-V lifecycle validation
pro-utkarshM Nov 3, 2026
d735bcd
Merge the host IPI fallback for RISC-V lifecycle validation
pro-utkarshM Nov 3, 2026
2f329b5
Merge the folded-level hot-remove repair for RISC-V validation
pro-utkarshM Nov 3, 2026
3bb5e23
riscv: add HSM lifecycle and immutable multikernel entry stub
pro-utkarshM Sep 27, 2026
989c57a
riscv: contain spawn shutdown and panic with local HART_STOP
pro-utkarshM Sep 27, 2026
d87954b
riscv: exclude incompatible multikernel boot configurations
pro-utkarshM Oct 6, 2026
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
86 changes: 48 additions & 38 deletions Documentation/multikernel/device-tree.rst
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ back the pool::
#address-cells = <2>;
#size-cells = <2>;
id = <0>;
memory-granule = <0x0 0x400000>;
resources {
cpus = <0x0 0x1 0x0 0x2 0x0 0x3>; /* every pool member */
cpus-available = <0x0 0x2 0x0 0x3>; /* the free subset */
Expand All @@ -91,16 +92,24 @@ back the pool::
devices { ... }; /* platform devices only */
};
aliases {
enp9s0 = "/pci@0/pci@3,0/pci@0,0";
enp9s0 = "/pci@0,9/pci@0,0";
};
pci@0 { ... }; /* see Devices below */
pci@0,9 { ... }; /* see Devices below */
};

``cpus`` lists every CPU the pool owns, including CPUs lent to instances;
``cpus-available`` lists the free ones. There is one ``memory@<base>`` node
per pool chunk in the standard memory node form. Free pool PCI devices
appear under their host bridge.

``memory-granule`` is the unit memory moves into or out of the kernel
reading the tree in: the base and size of a pool chunk, or of memory added
to or removed from the kernel at run time, are multiples of it. Every
kernel's own ``/sys/fs/multikernel/device_tree`` carries it, a spawn
kernel's included, and an instance tree does not, as it describes another
kernel. It covers whole MAX_PAGE_ORDER blocks, 4M on x86, as the buddy
allocator merges free pages across them.

The Instance Tree
=================

Expand All @@ -120,54 +129,55 @@ instance owns. The root is the instance, named by ``model``::
devices { ... }; /* platform devices only */
};
aliases {
enp9s0 = "/pci@0/pci@3,0/pci@0,0";
enp9s0 = "/pci@0,9/pci@0,0";
};
pci@0 { ... };
pci@0,9 { ... };
};

Devices
=======

PCI devices are described where the devicetree PCI bus binding puts them:
under the bus they sit on. One node per root bus the instance reaches,
then one node per bridge on the way down, then the device as a leaf::
under the bus they sit on. Each bus that holds a device of the instance is
a root bus of its own, with the instance's devices on it as leaves and
nothing else. The bridges above it are not described: they belong to the
kernel that writes the tree, which keeps driving them::

pci@0 {
pci@0,9 { /* domain 0, bus 9 */
compatible = "multikernel,pci-host-bridge";
device_type = "pci";
#address-cells = <3>;
#size-cells = <2>;
linux,pci-domain = <0>;
bus-range = <0x0 0xff>;
reg = <0x0 0xb0000000 0x0 0x10000000>; /* ECAM window, when known */
ranges = <0x01000000 0x0 0x0 0x0 0x0 0x0 0xcf8 /* I/O */
0x02000000 0x0 0x80000000 0x0 0x80000000 0x0 0x30000000
...>;
pci@3,0 { /* a bridge on the path */
device_type = "pci";
#address-cells = <3>;
#size-cells = <2>;
reg = <0x00001800 0 0 0 0>; /* bus 0, device 3, fn 0 */
bus-range = <0x9 0x9>;
pci@0,0 { /* the device */
reg = <0x00090000 0 0 0 0>; /* bus 9, device 0, fn 0 */
vendor-id = <0x1af4>;
device-id = <0x1041>;
};
bus-range = <0x9 0x9>;
reg = <0x0 0xb0900000 0x0 0x100000>; /* the bus's ECAM, when known */
ranges = <0x02000000 0x0 0xfe800000 0x0 0xfe800000 0x0 0x200000
0x43000000 0x0 0xfc800000 0x0 0xfc800000 0x0 0x200000>;
pci@0,0 { /* the device */
reg = <0x00090000 0 0 0 0>; /* bus 9, device 0, fn 0 */
vendor-id = <0x1af4>;
device-id = <0x1041>;
};
};

The unit address of a device or bridge is ``device,function`` in hex and
its ``reg`` encodes bus, device and function in the first cell as the
binding prescribes, so ``pci_set_of_node()`` finds it by devfn under its
bus. ``ranges`` uses the standard 7-cell PCI encoding. ``reg`` on a host
bridge is its ECAM window; a spawn kernel installs it so that any domain
and extended config space are reachable, and falls back to port ``0xCF8``
for domain 0 without one.

The path down comes from the bus structures of the kernel that writes the
tree, so a device that has been detached from that kernel is still placed
correctly.
Bus, device and function numbers are the real ones, so a device has the
same address in every kernel. The unit address of a device is
``device,function`` in hex and its ``reg`` encodes bus, device and function
in the first cell as the binding prescribes, so ``pci_set_of_node()`` finds
it by devfn under its bus. ``ranges`` uses the standard 7-cell PCI encoding
and holds the windows of the bridge above the bus, or of the host bridge
for a root bus, which cover the BARs of every device on it.

A PCI function handed to a running spawn comes with the same description
of its bus, and the spawn adds the nodes it would have booted with: the
device under its bus, and the bus as a root bus of its own when the
spawn has none.

``reg`` is the ECAM window of the bus, as in the generic ECAM host bridge
binding. A spawn kernel does not use it while the kernel that lent the
devices is alive: it reaches their config space through that kernel, over
the message ring, and goes to the window only once it has fenced that
kernel.

Platform devices stay under ``/resources/devices`` as nodes with
``device-type = "platform"`` and ``device-name`` or ``acpi-hid``.
Expand Down Expand Up @@ -216,11 +226,11 @@ everything else read the tree through the usual ``of_*`` helpers.
What a spawn does with its tree:

* creates a PCI root bus per ``multikernel,pci-host-bridge`` node, with
the node's bus range, windows and ECAM;
the node's bus range and windows, whose config space it asks the host
for;
* probes a PCI slot only when the bus's node has a child at that devfn,
which admits the bridges on the path and nothing else on the shared
fabric, and registers a platform device only when a
``/resources/devices`` node names it;
which admits nothing else on the shared fabric, and registers a
platform device only when a ``/resources/devices`` node names it;
* binds every bus and device to its node, so ``dev->of_node`` is set as on
any devicetree platform;
* names network devices from ``/aliases``.
Expand Down
3 changes: 3 additions & 0 deletions Documentation/multikernel/overlays.rst
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ kernel that manages a pool, its ``/resources`` node describes the pool::
#address-cells = <2>;
#size-cells = <2>;
id = <0>;
memory-granule = <0x0 0x400000>;
resources {
cpus = <...>; /* every pool member */
cpus-available = <...>; /* the free subset */
Expand All @@ -248,6 +249,8 @@ kernel that manages a pool, its ``/resources`` node describes the pool::
pci@0 { ... }; /* free pool PCI devices */
};

``memory-granule`` is what the base and size of a ``memory-add`` or
``memory-remove`` item for this kernel must be multiples of.
``cpus`` lists every CPU the pool owns, including CPUs currently lent to
instances; ``cpus-available`` lists only the free ones. There is one
``memory@<base>`` node per pool chunk, in the standard memory node form, and
Expand Down
61 changes: 61 additions & 0 deletions Documentation/multikernel/riscv-lifecycle.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
.. SPDX-License-Identifier: GPL-2.0

RISC-V lifecycle and entry cache maintenance
==========================================

The #23--#25 series requires SBI HSM and supervisor-mode rv64 multikernel
kernels. It does not provide the #26 Image loader, #27 boot-tree CPU/intc
description or #28 parent doorbell/panic-notification transport. Generic
controller serialization and confirmed-stop retirement are separate master
prerequisites. Force-stop is unsupported on RISC-V and must fail closed.

Both host and spawn must use kernels with ``CONFIG_BUILTIN_DTB=n`` and
``CONFIG_RISCV_BOOT_SPINWAIT=n``; Kconfig excludes multikernel otherwise.
A built-in DTB replaces the supplied manifest before spawn detection, leaving
host-wide reset setup enabled. Spinwait boot rejects physical hart IDs beyond
``NR_CPUS`` and can leave a hart waiting in Image memory instead of HART_STOP.
Ordered SBI HSM boot avoids that physical-ID bound. These checks constrain
kernel builds, not arbitrary foreign Images loaded by the host.

The host owns two adjacent control pages for the instance lifetime: a mutable
entry record followed by immutable entry code. Before each start, the host
copies the Image and writes the current entry, then publishes those stores
before HART_START. The copied stub executes fence.i, finds the preceding page
from its PC, reads the entry and jumps without modifying a0 (physical hartid)
or a1 (primary boot tree or secondary SBI boot data). The code uses neither an
embedded mutable entry immediate nor an absolute relocation target.

A fence.i at the start of a newly copied code page alone is insufficient: the
first instruction fetch can see an earlier occupant of that physical page.
Every assigned hart first runs mk_riscv_entry_fence_stop in immutable, reserved
host text, executes fence.i and HART_STOP. The host confirms STOPPED before
starting the copied stub. Linux pool entry also fences before HART_STOP. This
is a first-fetch priming handshake, not an assumption that a stopped hart can
service a remote-fence request. Host text must stay reserved and unchanged.

Using SBI's opaque argument for an entry record would put that record in a1;
an alternative must recover the boot-tree/secondary argument before entry and
still avoid fetching recycled code before a local fence.i. The adjacent-page
design preserves the firmware boot arguments directly. Secondary entry updates
the record through memremap, so a no-map control reservation need not be in the
spawn linear map. The child must reserve all host-owned control pages (#27).

On the modern foundation, a1 names the execution-time 256KB instance manifest,
not a separate load-time clone of the host DTB. Manifest and ring pages are
persistent host allocations outside the Image grant. #27 must emit assigned
hart/intc nodes, initrd/boot arguments and the required no-map reservations in
that boot tree. Reclaim is allowed only after every assigned/tracked hart is
confirmed stopped. A timeout, failed query or STOP_PENDING cannot authorize
reuse; a STOPPED observation does not cancel outstanding remote start work.

Requested and voluntary shutdown, reboot and panic stop local harts with HSM;
spawn reset must never reach SRST or legacy shutdown. With panic_timeout=0,
the spawn panic notifier halts immediately rather than leaving the panic CPU
in the generic infinite wait loop. With a nonzero timeout, the notifier returns
to the generic panic path: positive values delay restart, while negative values
restart without that delay. The spawn restart override stops locally in either
case; it must not reset the host. Parent notification is a separate #28 concern.
An unexpected HART_STOP return leaves a local wait loop, so the host must fail
confirmation and retain resources. Ring reset is not a remote-work retirement
protocol and does not supply #7/session guarantees. Matched revisions and fresh
QEMU/OpenSBI failure and replacement tests remain release gates.
3 changes: 3 additions & 0 deletions arch/riscv/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -1094,6 +1094,9 @@ config ARCH_SUPPORTS_MULTIKERNEL
depends on KEXEC_FILE
depends on HOTPLUG_CPU
depends on !RISCV_M_MODE
# Spawn identity requires the supplied DTB and ordered HSM boot.
depends on !BUILTIN_DTB
depends on !RISCV_BOOT_SPINWAIT

config ARCH_SUPPORTS_CRASH_DUMP
def_bool y
Expand Down
8 changes: 8 additions & 0 deletions arch/riscv/include/asm/cpu_ops_sbi.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@

extern const struct cpu_operations cpu_ops_sbi;

int sbi_hsm_hart_start(unsigned long hartid, unsigned long saddr,
unsigned long priv);

#ifdef CONFIG_HOTPLUG_CPU
int sbi_hsm_hart_stop(void);
int sbi_hsm_hart_get_status(unsigned long hartid);
#endif

/**
* struct sbi_hart_boot_data - Hart specific boot used during booting and
* cpu hotplug.
Expand Down
18 changes: 13 additions & 5 deletions arch/riscv/include/asm/multikernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,25 @@ static inline int arch_cpu_from_physical_id(u64 hartid)
*/
#define MK_CTRL_BLOCK_SIZE (SZ_64K + 2 * PAGE_SIZE)

/*
* Architecture-private spawn and park state is added with the SBI HSM
* and Image loader support. The compile-only skeleton intentionally has
* none.
*/
struct mk_riscv_spawn_context {
unsigned long image_entry;
};

/* Per-instance state, allocated from the control block on first spawn. */
struct mk_instance_arch {
struct mk_riscv_spawn_context *ctx;
phys_addr_t ctx_phys;
const void *stub;
phys_addr_t stub_phys;
};

struct mk_pool_arch {
};

extern char mk_riscv_entry_stub_start[];
extern char mk_riscv_entry_stub_end[];
extern char mk_riscv_entry_fence_stop[];

#endif /* !__ASSEMBLY__ */

#endif /* _ASM_RISCV_MULTIKERNEL_H */
70 changes: 63 additions & 7 deletions arch/riscv/kernel/cpu_ops_sbi.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*/

#include <linux/cacheflush.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/mm.h>
#include <linux/multikernel.h>
#include <linux/sched/task_stack.h>
#include <asm/cpu_ops.h>
#include <asm/cpu_ops_sbi.h>
Expand All @@ -23,45 +26,90 @@ const struct cpu_operations cpu_ops_sbi;
*/
static struct sbi_hart_boot_data boot_data[NR_CPUS];

static int sbi_hsm_hart_start(unsigned long hartid, unsigned long saddr,
unsigned long priv)
static int sbi_hsm_err_map_linux_errno(long err)
{
switch (err) {
case SBI_ERR_ALREADY_AVAILABLE:
case SBI_ERR_ALREADY_STARTED:
case SBI_ERR_ALREADY_STOPPED:
return -EALREADY;
case SBI_ERR_FAILURE:
return -EIO;
default:
return sbi_err_map_linux_errno(err);
}
}

int sbi_hsm_hart_start(unsigned long hartid, unsigned long saddr,
unsigned long priv)
{
struct sbiret ret;

ret = sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_START,
hartid, saddr, priv, 0, 0, 0);
if (ret.error)
return sbi_err_map_linux_errno(ret.error);
return sbi_hsm_err_map_linux_errno(ret.error);
else
return 0;
}

#ifdef CONFIG_HOTPLUG_CPU
static int sbi_hsm_hart_stop(void)
int sbi_hsm_hart_stop(void)
{
struct sbiret ret;

/* A stopped hart cannot receive the remote fence for its next entry. */
local_flush_icache_all();
ret = sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_STOP, 0, 0, 0, 0, 0, 0);

if (ret.error)
return sbi_err_map_linux_errno(ret.error);
return sbi_hsm_err_map_linux_errno(ret.error);
else
return 0;
}

static int sbi_hsm_hart_get_status(unsigned long hartid)
int sbi_hsm_hart_get_status(unsigned long hartid)
{
struct sbiret ret;

ret = sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_STATUS,
hartid, 0, 0, 0, 0, 0);
if (ret.error)
return sbi_err_map_linux_errno(ret.error);
return sbi_hsm_err_map_linux_errno(ret.error);
else
return ret.value;
}
#endif

#ifdef CONFIG_MULTIKERNEL
static int sbi_spawn_cpu_entry(unsigned long *boot_addr)
{
struct mk_riscv_spawn_context *ctx;
phys_addr_t stub_addr;

if (!mk_spawned())
return 0;

stub_addr = mk_manifest_entry_stub_phys();
if (stub_addr < PAGE_SIZE || !IS_ALIGNED(stub_addr, PAGE_SIZE)) {
pr_err_once("SBI: invalid multikernel entry stub address %pa\n",
&stub_addr);
return -EINVAL;
}

/* #27 reserves this host-owned data no-map; do not assume a linear map. */
ctx = memremap(stub_addr - PAGE_SIZE, PAGE_SIZE, MEMREMAP_WB);
if (!ctx)
return -ENOMEM;
WRITE_ONCE(ctx->image_entry, *boot_addr);
/* Publish the secondary entry before firmware can enter the stub. */
smp_wmb();
memunmap(ctx);
*boot_addr = stub_addr;
return 0;
}
#endif

static int sbi_cpu_start(unsigned int cpuid, struct task_struct *tidle)
{
unsigned long boot_addr = __pa_symbol(secondary_start_sbi);
Expand All @@ -73,6 +121,14 @@ static int sbi_cpu_start(unsigned int cpuid, struct task_struct *tidle)
smp_mb();
bdata->task_ptr = tidle;
bdata->stack_ptr = task_pt_regs(tidle);
#ifdef CONFIG_MULTIKERNEL
{
int ret = sbi_spawn_cpu_entry(&boot_addr);

if (ret)
return ret;
}
#endif
/* Make sure boot data is updated */
smp_mb();
hsm_data = __pa(bdata);
Expand Down
Loading