miniOS
x86_64 hobby kernel with SMP, VFS, and POSIX process model
Loading...
Searching...
No Matches
SMP Boot and Per-CPU State

ACPI MADT parsing, AP boot sequence, and per-CPU cpu_t management. More...

Classes

struct  cpu_t

Macros

#define MAX_CPUS   8

Typedefs

typedef struct cpu_t cpu_t

Functions

static cpu_tcpu_local (void)
void cpu_enable_sse (void)
 Enable SSE/SSE2 on the calling CPU.
void per_cpu_init (uint32_t cpu_id)
 Initialise per-CPU GDT, TSS, IDT, and GS base for one CPU.
void acpi_find_madt (uint64_t mb_info_phys)
 Parse ACPI MADT and populate smp_lapic_ids[]/smp_cpu_count.
void smp_boot_aps (void)
 Send INIT-SIPI-SIPI sequence to all non-BSP CPUs.
void per_cpu_update_rsp0 (uint64_t rsp0)
 Update this CPU's TSS RSP0 and cpu_t.kstack_top.
void ap_barrier_checkin (void)
 Signal that this AP has completed its CPU init.
void smp_wait_for_aps (void)
 Block until all APs have checked in at the rendezvous barrier.
void lapic_timer_init_ap (void)
 Start LAPIC timer on the calling AP using the BSP-calibrated ICR.

Variables

uint32_t smp_cpu_count
uint8_t smp_lapic_ids [MAX_CPUS]
cpu_t g_cpus [MAX_CPUS]
volatile uint32_t smp_aps_ready

Detailed Description

ACPI MADT parsing, AP boot sequence, and per-CPU cpu_t management.

Declares cpu_t (the per-CPU state block accessed via GS.base), the global g_cpus[] array, and the public API for SMP initialisation: MADT parsing, AP boot, rendezvous barrier, and per-CPU TSS/GDT setup.

Macro Definition Documentation

◆ MAX_CPUS

#define MAX_CPUS   8

Typedef Documentation

◆ cpu_t

typedef struct cpu_t cpu_t

cpu_t - Per-CPU state block; GS.base on each CPU points to this struct.

The first field MUST be a self-pointer at offset 0 (gs:0) so cpu_local() works with a single mov %gs:0, %0 instruction regardless of cpu count. Fields at fixed GS offsets are used by assembly: current_thread at gs:56, kstack_top at gs:64, user_rsp_scratch at gs:72.

Function Documentation

◆ acpi_find_madt()

void acpi_find_madt ( uint64_t mb_info_phys)

Parse ACPI MADT and populate smp_lapic_ids[]/smp_cpu_count.

Parameters
mb_info_physPhysical address of the Multiboot 2 information structure (from RDI at boot).

Locates the RSDP via the Multiboot 2 ACPI tag (or EBDA/BIOS ROM scan fallback), prefers XSDT (RSDP revision >= 2) over RSDT to support memory above 4 GB, walks the SDT entries to find the MADT, then extracts all Processor Local APIC entries (type 0) into smp_lapic_ids[]. Index 0 is always the BSP.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ap_barrier_checkin()

void ap_barrier_checkin ( void )

Signal that this AP has completed its CPU init.

Atomically increments smp_aps_ready. Called by each AP after per_cpu_init() and lapic_timer_init_ap() succeed, immediately before entering the AP idle loop. The BSP polls smp_aps_ready in smp_wait_for_aps() until it reaches smp_cpu_count-1.

Here is the caller graph for this function:

◆ cpu_enable_sse()

void cpu_enable_sse ( void )

Enable SSE/SSE2 on the calling CPU.

Sets CR4.OSFXSR and CR4.OSXMMEXCPT, clears CR0.EM, sets CR0.MP, then executes FNINIT and LDMXCSR 0x1F80 to put the FPU and SSE unit in a known state. Must be called on every CPU (BSP in kernel_main, each AP in ap_entry) before any userspace SSE instruction executes.

Here is the caller graph for this function:

◆ cpu_local()

cpu_t * cpu_local ( void )
inlinestatic
Here is the caller graph for this function:

◆ lapic_timer_init_ap()

void lapic_timer_init_ap ( void )

Start LAPIC timer on the calling AP using the BSP-calibrated ICR.

Reads lapic_bsp_timer_icr (calibrated by the BSP) and writes it directly to LAPIC_TIMER_ICR, avoiding a second PIT calibration which would cause contention on smp_aps_ready. Sets LVT timer to periodic mode at LAPIC_TIMER_VECTOR. Must be called after LAPIC is software-enabled on AP.

Start LAPIC timer on the calling AP using the BSP-calibrated ICR.

Reads lapic_bsp_timer_icr (calibrated by the BSP) and writes it directly to LAPIC_TIMER_ICR, avoiding a second PIT calibration which would cause contention. Sets LVT timer to periodic mode at LAPIC_TIMER_VECTOR. Called from ap_entry() on each AP after LAPIC software-enable.

◆ per_cpu_init()

void per_cpu_init ( uint32_t cpu_id)

Initialise per-CPU GDT, TSS, IDT, and GS base for one CPU.

Parameters
cpu_idLogical CPU index (0 = BSP, 1..N-1 = APs).

Steps performed:

  1. Fills g_cpus[cpu_id].self, .cpu_id, .lapic_id.
  2. Allocates a 16 KiB kernel stack via kmalloc and stores base pointer.
  3. Copies the BSP GDT into a per-CPU buffer and patches in the CPU's TSS descriptor.
  4. Executes lgdt (per-CPU GDT), lidt (shared IDT), ltr (per-CPU TSS selector).
  5. Writes IA32_GS_BASE MSR to &g_cpus[cpu_id] so cpu_local() returns the correct struct.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ per_cpu_update_rsp0()

void per_cpu_update_rsp0 ( uint64_t rsp0)

Update this CPU's TSS RSP0 and cpu_t.kstack_top.

Parameters
rsp0New kernel stack top to install in TSS privileged_stack_table[0] and cpu_t.kstack_top (read by syscall_entry via gs:64).

Must be called whenever the running thread changes (in sched_schedule) and before the first ring-3 entry on any CPU, so that both interrupt- driven (iretq path) and SYSCALL-driven ring-3 to ring-0 transitions use the correct kernel stack for the new thread.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ smp_boot_aps()

void smp_boot_aps ( void )

Send INIT-SIPI-SIPI sequence to all non-BSP CPUs.

Iterates smp_lapic_ids[1..smp_cpu_count-1], sends INIT IPI, waits 10 ms, sends two SIPI IPIs 200 us apart with vector = TRAMP_BASE >> 12 (0x8). Each AP executes the 16-bit trampoline at physical 0x8000, transitions to 64-bit long mode, and calls ap_entry(). Requires lapic_init() to have run.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ smp_wait_for_aps()

void smp_wait_for_aps ( void )

Block until all APs have checked in at the rendezvous barrier.

Spins with PAUSE until smp_aps_ready == smp_cpu_count - 1. Must be called by the BSP after smp_boot_aps() and before the second call to sched_init() (which sets up per-CPU run queues). Guaranteed to return eventually because each AP calls ap_barrier_checkin() exactly once.

Here is the call graph for this function:
Here is the caller graph for this function:

Variable Documentation

◆ g_cpus

cpu_t g_cpus[MAX_CPUS]
extern

◆ smp_aps_ready

volatile uint32_t smp_aps_ready
extern

◆ smp_cpu_count

uint32_t smp_cpu_count
extern

◆ smp_lapic_ids

uint8_t smp_lapic_ids[MAX_CPUS]
extern