//! Thread-local storage implementation. const builtin = @import("builtin"); const vmm = @import("vmm.zig"); const phys_memory = @import("phys.zig"); const kernel = @import("../kernel.zig"); const PAGE_SIZE = vmm.PAGE_SIZE; const log = kernel.debug.log; /// Thread-local storage layout variant used by this target platform. pub const TLS_VARIANT: enum { /// Variant I: /// /// [ TCB ] [ pad to p_align ] [ MODULE 0 ] [ MODULE 1 ] ... /// | | | /// | | | /// tp off1 off2 variant1, /// Variant II: /// /// ... [ MODULE 1 ] [ MODULE 0 ] [ TCB ] /// | | | /// | | | /// off2 off1 tp variant2, } = switch (builtin.cpu.arch) { .riscv64, .aarch64 => .variant1, // x86-64 uses variant 2 else => @panic("Unsupported CPU architecture"), }; extern var __tdata_start: u8; extern var __tdata_end: u8; extern var __tbss_start: u8; extern var __tbss_end: u8; /// Allocates a storage for one per-CPU TLS block, clones the TLS image /// (as described by .tbss/.tdata sections) and returns the result. pub fn load_kernel_tls_image() []u8 { // Assume .tbss follows .tdata const tdata_start = @intFromPtr(&__tdata_start); const tdata_end = @intFromPtr(&__tdata_end); const tdata_size = tdata_end - tdata_start; const tbss_start = @intFromPtr(&__tbss_start); const tbss_end = @intFromPtr(&__tbss_end); const tbss_size = tbss_end - tbss_start; const tdata_data = @as([*]u8, @ptrFromInt(tdata_start))[0..tdata_size]; switch (comptime TLS_VARIANT) { .variant1 => { const tls_size = tdata_size + tbss_size; const tls_page_count = (tls_size + PAGE_SIZE - 1) / PAGE_SIZE; // Variant I: TLS block 0 follows TP after a certain displacement const tls_address = phys_memory.alloc_pages(tls_page_count).?.virtualize(); const tls_data = @as([*]u8, @ptrFromInt(tls_address))[0..tls_size]; log.info("Allocated TLS @ {*}", .{tls_data}); @memcpy(tls_data[0..tdata_size], tdata_data); @memset(tls_data[tdata_size..], 0); return tls_data; }, .variant2 => @panic("TODO: TLS variant II"), } }