allocate AP kernel/IST stacks at bring-up, not statically
Hoist max_cpus into danos (root.zig), raise it to 128, and stop reserving a static [max_cpus][16 KiB] IST array. Only the BSP's IST stack is static (needed before the allocator); each AP's is heap-allocated when it comes online. Shrinks the kernel from ~1.1 MB to ~139 KiB in ReleaseSmall.
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
//! once can't share one fault stack. So the TSS and its IST stack are per-core,
|
||||
//! indexed by CPU number; slot 0 is the BSP.
|
||||
|
||||
const danos = @import("danos");
|
||||
const gdt = @import("gdt.zig");
|
||||
|
||||
/// x86_64 TSS. `packed` because several 64-bit fields sit at 4-byte-unaligned
|
||||
@@ -34,24 +35,35 @@ const Tss = packed struct {
|
||||
/// The IST slot (1-based, as the IDT gate encodes it) used for critical faults.
|
||||
pub const double_fault_ist = 1;
|
||||
|
||||
const max_cpus = 64; // matches gdt.zig / the scheduler
|
||||
const ist_stack_size = 16 * 1024;
|
||||
const max_cpus = danos.max_cpus;
|
||||
pub const ist_stack_size = 16 * 1024;
|
||||
|
||||
/// One TSS per core, and one IST1 stack per core. Static, so they need no allocator
|
||||
/// and are always valid. (max_cpus × 16 KiB of BSS for the IST stacks.)
|
||||
/// One TSS per core (small — kept static). The IST stacks are 16 KiB each, so only
|
||||
/// the **BSP's** is static: it must exist before the frame allocator does, to catch a
|
||||
/// fault during early boot. Each **AP** gets a heap-allocated IST stack at bring-up
|
||||
/// (after the heap is up), the top of which the BSP records here before waking it —
|
||||
/// so we reserve big stacks only for cores that actually come online.
|
||||
var tss_table = [_]Tss{.{}} ** max_cpus;
|
||||
var ist_stacks: [max_cpus][ist_stack_size]u8 align(16) = undefined;
|
||||
var bsp_ist_stack: [ist_stack_size]u8 align(16) = undefined;
|
||||
var ap_ist_top = [_]usize{0} ** max_cpus; // per-AP IST stack top (0 = BSP / not set)
|
||||
|
||||
/// Loads the task register with the TSS selector. Defined in isr.s.
|
||||
extern fn load_tr(selector: u16) callconv(.c) void;
|
||||
|
||||
/// Set up core `cpu`'s TSS: point IST1 at that core's stack, install the TSS
|
||||
/// Record the top of the IST stack the kernel allocated for AP `cpu`. Called on the
|
||||
/// BSP before waking that core; read by the core's own `setupThisCpu`.
|
||||
pub fn setApIstStack(cpu: usize, top: usize) void {
|
||||
ap_ist_top[cpu] = top;
|
||||
}
|
||||
|
||||
/// Set up core `cpu`'s TSS: point IST1 at its stack (the BSP's static one for core 0,
|
||||
/// the allocated one recorded via `setApIstStack` for an AP), install the TSS
|
||||
/// descriptor into that core's GDT, and load it into the task register. Requires the
|
||||
/// core's GDT to already be loaded (gdt.loadOnThisCpu first).
|
||||
pub fn setupThisCpu(cpu: usize) void {
|
||||
const t = &tss_table[cpu];
|
||||
t.* = .{};
|
||||
t.ist1 = @intFromPtr(&ist_stacks[cpu]) + ist_stack_size; // stacks grow down
|
||||
t.ist1 = if (cpu == 0) @intFromPtr(&bsp_ist_stack) + ist_stack_size else ap_ist_top[cpu];
|
||||
t.iomap_base = @sizeOf(Tss); // == limit: no I/O permission bitmap
|
||||
gdt.setTssFor(cpu, @intFromPtr(t), @sizeOf(Tss) - 1);
|
||||
load_tr(gdt.tss_selector);
|
||||
|
||||
Reference in New Issue
Block a user