diff --git a/system/kernel/architecture/x86_64/cpu.zig b/system/kernel/architecture/x86_64/cpu.zig index 3524b21..9bbd7a9 100644 --- a/system/kernel/architecture/x86_64/cpu.zig +++ b/system/kernel/architecture/x86_64/cpu.zig @@ -306,10 +306,12 @@ pub fn cpuLocal() usize { const ia32_fs_base = 0xC000_0100; -/// Set the FS-segment base — the x86_64 thread pointer for user-space TLS. The kernel -/// never touches FS, so this only affects the user task that runs next; the scheduler -/// restores it per task across context switches (docs/threading-plan.md M10). -pub fn setFsBase(base: u64) void { +/// Set the user-space TLS **thread pointer** — the arch-neutral name the generic scheduler +/// calls (`architecture.setThreadPointer`). On x86_64 that is the FS-segment base +/// (`IA32_FS_BASE`); an aarch64 port implements the same call against `TPIDR_EL0`. The +/// kernel never touches FS, so this only affects the user task that runs next, which the +/// scheduler restores per task across context switches (docs/threading-plan.md M10). +pub fn setThreadPointer(base: u64) void { io.wrmsr(ia32_fs_base, base); } diff --git a/system/kernel/scheduler.zig b/system/kernel/scheduler.zig index 4cdba5a..44d751f 100644 --- a/system/kernel/scheduler.zig +++ b/system/kernel/scheduler.zig @@ -81,18 +81,19 @@ pub const Task = struct { aspace: u64 = 0, user_ip: u64 = 0, // user-mode entry point (user task only) user_sp: u64 = 0, // user-mode stack pointer (user task only) - user_arg: u64 = 0, // value delivered in the user's rdi at first entry: 0 for a - // process (its _start ignores it), the closure pointer for a thread (docs/threading.md) + user_arg: u64 = 0, // value delivered in the user's first argument register at first entry + // (rdi on x86_64, via architecture.jumpToUserArg): 0 for a process (its _start ignores + // it), the closure pointer for a thread (docs/threading.md) // The user address this task is blocked on in futex_wait (0 = not futex-waiting). // Cleared to 0 by futexWakeLocked as the "woken, not timed out" signal (docs/threading.md). futex_addr: u64 = 0, // The task id this task is blocked in `thread_join` on (0 = not joining). Woken by // `wakeJoinersLocked` when that task exits (docs/threading-plan.md M9). join_target: u32 = 0, - // The FS-base (x86_64 thread pointer) for this task's user-space TLS — 0 until the - // task sets it via `set_thread_pointer`. Restored on every context switch to this task - // (docs/threading-plan.md M10). - fs_base: u64 = 0, + // This task's user-space TLS thread pointer — 0 until set via `set_thread_pointer`. + // Architecture-neutral: the arch layer maps it to the FS base on x86_64, `TPIDR_EL0` on + // aarch64. Restored on every context switch to this task (docs/threading-plan.md M10). + thread_pointer: u64 = 0, // The mmap / MMIO grant-arena cursors moved from Task to the per-address-space object // (`AspaceRef`, below) so threads sharing one address space hand out disjoint grants // — see aspaceMmapNextPtr / aspaceDeviceMapNextPtr (docs/threading-plan.md M7). @@ -288,7 +289,7 @@ pub const PerCpu = struct { index: u32 = 0, // dense 0-based core index online: bool = false, // has this core finished bring-up? loaded_aspace: u64 = 0, // the address-space root currently loaded on this core - loaded_fs_base: u64 = 0, // the FS base currently loaded on this core (docs/threading-plan.md M10) + loaded_thread_pointer: u64 = 0, // the TLS thread pointer currently loaded on this core (docs/threading-plan.md M10) // Tasks pinned to this core (affinity == index), per priority level + bitmap. pinned_head: [number_priorities]?*Task = .{null} ** number_priorities, pinned_tail: [number_priorities]?*Task = .{null} ** number_priorities, @@ -573,11 +574,11 @@ fn switchTo(pc: *PerCpu, save_sp: *usize, next: *Task) void { architecture.loadPageTable(want); pc.loaded_aspace = want; } - // Restore the next task's user TLS thread pointer (FS base) — only on change, the same + // Restore the next task's user TLS thread pointer — only on change, the same // conditional-load discipline as CR3 above (docs/threading-plan.md M10). - if (next.fs_base != pc.loaded_fs_base) { - architecture.setFsBase(next.fs_base); - pc.loaded_fs_base = next.fs_base; + if (next.thread_pointer != pc.loaded_thread_pointer) { + architecture.setThreadPointer(next.thread_pointer); + pc.loaded_thread_pointer = next.thread_pointer; } architecture.switchContext(save_sp, next.sp); // Resumed now (switchContext returned into our own switchTo frame). Re-fetch the core @@ -678,14 +679,13 @@ pub fn joinThreadLocked(tid: u32) void { } } -/// Set the calling task's user TLS thread pointer (FS base) and load it now. Persisted on -/// the Task so context switches restore it (docs/threading-plan.md M10). Caller holds the -/// kernel lock. +/// Set the calling task's user TLS thread pointer and load it now. Persisted on the Task so +/// context switches restore it (docs/threading-plan.md M10). Caller holds the kernel lock. pub fn setThreadPointerLocked(addr: u64) void { const pc = thisCpu(); - pc.current.fs_base = addr; - architecture.setFsBase(addr); - pc.loaded_fs_base = addr; + pc.current.thread_pointer = addr; + architecture.setThreadPointer(addr); + pc.loaded_thread_pointer = addr; } /// Wake every task blocked in `thread_join` on `tid` — called from the exit paths once the