Each worker core sets up its own IPI receiver before going online (amd64 LAPIC + vector 0x22 with its own stub, aarch64 banked GIC SGI 0, riscv64 sie.SSIE); core 0 sends by ICR / GICD_SGIR / SBI IPI. Park lets exactly one interrupt in without a lost-wake window. Boot self-test: IPI round trips 3/3 and 'woke x3, IPIs x3' on all three ISAs; worker vCPU threads 0.0% on the host. 3-ISA acceptance clean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
80 lines
2.9 KiB
C
80 lines
2.9 KiB
C
/*
|
||
StarForth — Steady-State Virtual Machine Runtime
|
||
|
||
Copyright (c) 2023–2025 Robert A. James
|
||
All rights reserved.
|
||
|
||
This file is part of the StarForth project.
|
||
|
||
Licensed under the StarForth License, Version 1.0 (the "License");
|
||
you may not use this file except in compliance with the License.
|
||
*/
|
||
|
||
/**
|
||
* smp.h - The core table and secondary-core bring-up (FABRIC-3.10.8 MC-1).
|
||
*
|
||
* Core ids are dense and logical: core 0 is the boot core, whatever its
|
||
* hardware id; the others are numbered in enumeration order. The hardware
|
||
* id lives in the core's block (sk_percpu_t.hw_id) and never in a lock's
|
||
* owner word.
|
||
*
|
||
* MC-1: a secondary core comes up, reports, and parks -- interrupts masked,
|
||
* halted, every wake counted. It does no console, log or heap work.
|
||
*/
|
||
#ifndef STARKERNEL_SMP_H
|
||
#define STARKERNEL_SMP_H
|
||
|
||
#include <stdint.h>
|
||
#include "starkernel/percpu.h"
|
||
#include "uefi.h" /* BootInfo */
|
||
|
||
/* Enumerate the cores, bring each secondary up in turn and wait (bounded)
|
||
* for it to park. Boot core only, interrupts off; after the heartbeat
|
||
* init. Prints one line per core. */
|
||
void sk_smp_init(BootInfo *boot_info);
|
||
|
||
uint32_t sk_smp_core_count(void);
|
||
sk_percpu_t *sk_smp_core(uint32_t core_id);
|
||
|
||
/* The idle point: logs a parked core's wake count when it has changed.
|
||
* Call with no lock held. */
|
||
void sk_smp_report(void);
|
||
|
||
/* Where every secondary core's entry path lands, with its per-CPU register
|
||
* already set to `pc`. Never returns. */
|
||
void sk_smp_secondary_main(sk_percpu_t *pc) __attribute__((noreturn));
|
||
|
||
/* ---- per ISA (arch/<isa>/smp.c) ---------------------------------------- */
|
||
|
||
/* The cores this machine has, boot core included: fills hw_ids[0..cap) in
|
||
* enumeration order and returns the total (call with cap 0 to count). */
|
||
uint32_t arch_smp_enumerate(BootInfo *boot_info, uint64_t *hw_ids, uint32_t cap);
|
||
|
||
/* The boot core's own hardware id. */
|
||
uint64_t arch_smp_boot_hw_id(void);
|
||
|
||
/* Start the core `pc` describes on `stack_top`; returns 0 once the start
|
||
* sequence was issued (arrival is observed through pc->online). */
|
||
int arch_smp_start(BootInfo *boot_info, sk_percpu_t *pc, void *stack_top);
|
||
|
||
/* One park step: interrupts stay masked; returns when the core wakes. */
|
||
void arch_smp_park_once(void);
|
||
|
||
/* Once `pc` is online: what the ISA can say about how it arrived (the
|
||
* exception level, the privilege mode), as a short phrase for its line. */
|
||
const char *arch_smp_arrival(const sk_percpu_t *pc);
|
||
|
||
/* MC-3b. On the secondary core, before it reports online: set up its own
|
||
* interrupt receiver for the IPI only, and record in pc->ipi_target how
|
||
* to reach it. */
|
||
void arch_smp_secondary_init(sk_percpu_t *pc);
|
||
|
||
/* MC-3b. Send the wake IPI to the core `target` describes. */
|
||
void arch_smp_send_ipi(const sk_percpu_t *target);
|
||
|
||
/* MC-3b. Called by each ISA's interrupt handler when the IPI arrives: counts
|
||
* it in this core's block. The handler acknowledges it. */
|
||
void sk_smp_ipi_received(void);
|
||
|
||
#endif /* STARKERNEL_SMP_H */
|