Files
zing/src/mem/tls.zig
T

70 lines
2.3 KiB
Zig

//! 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"),
}
}