Skip to content

Commit 9c0f15c

Browse files
committed
f
1 parent 0aad667 commit 9c0f15c

File tree

5 files changed

+73
-48
lines changed

5 files changed

+73
-48
lines changed

src/arch/aarch64/kernel/scheduler.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ impl TaskFrame for Task {
296296
if self.tls.is_none() {
297297
use crate::scheduler::task::tls::Tls;
298298

299-
self.tls = Tls::from_environment();
299+
self.tls = Tls::from_env();
300300
}
301301

302302
unsafe {

src/arch/riscv64/kernel/scheduler.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ use crate::arch::riscv64::kernel::processor::set_oneshot_timer;
99
use crate::arch::riscv64::mm::paging::{BasePageSize, PageSize, PageTableEntryFlags};
1010
use crate::mm::physicalmem::PHYSICAL_FREE_LIST;
1111
use crate::mm::virtualmem::KERNEL_FREE_LIST;
12-
#[cfg(not(feature = "common-os"))]
13-
use crate::scheduler::task::tls::Tls;
1412
use crate::scheduler::task::{Task, TaskFrame};
1513
use crate::{DEFAULT_STACK_SIZE, KERNEL_STACK_SIZE};
1614

@@ -317,7 +315,9 @@ impl TaskFrame for Task {
317315
// check is TLS is already allocated
318316
#[cfg(not(feature = "common-os"))]
319317
if self.tls.is_none() {
320-
self.tls = Tls::from_environment();
318+
use crate::scheduler::task::tls::Tls;
319+
320+
self.tls = Tls::from_env();
321321
}
322322

323323
unsafe {

src/arch/x86_64/kernel/scheduler.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ use crate::env;
1818
use crate::mm::physicalmem::PHYSICAL_FREE_LIST;
1919
use crate::mm::virtualmem::KERNEL_FREE_LIST;
2020
use crate::scheduler::PerCoreSchedulerExt;
21-
#[cfg(not(feature = "common-os"))]
22-
use crate::scheduler::task::tls::Tls;
2321
use crate::scheduler::task::{Task, TaskFrame};
2422

2523
#[repr(C, packed)]
@@ -289,7 +287,9 @@ impl TaskFrame for Task {
289287
// Check if TLS is allocated already and if the task uses thread-local storage.
290288
#[cfg(not(feature = "common-os"))]
291289
if self.tls.is_none() {
292-
self.tls = Tls::from_environment();
290+
use crate::scheduler::task::tls::Tls;
291+
292+
self.tls = Tls::from_env();
293293
}
294294

295295
unsafe {

src/scheduler/task/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#![allow(clippy::type_complexity)]
22

3-
pub mod tls;
3+
pub(crate) mod tls;
44

55
use alloc::collections::{LinkedList, VecDeque};
66
use alloc::rc::Rc;

src/scheduler/task/tls.rs

Lines changed: 65 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,57 @@
1-
//! Thread-local storage data structures
1+
//! Thread-local storage data structures.
22
//!
3-
//! See _ELF Handling For Thread-Local Storage_ [[tls]].
3+
//! See _ELF Handling For Thread-Local Storage_ [\[tls\]] for details.
44
//!
5-
//! - For `riscv`-specifics, see _Thread Local Storage - RISC-V ELF Specification - RISC-V ELF psABI Document_ [[riscv]].
5+
//! - For ARM specifics, see
6+
//! - _4 ADDENDUM: Thread Local Storage - Addenda to, and Errata in, the ABI for the Arm Architecture_ [\[riscv\]] and
7+
//! - _Speeding Up Thread-Local Storage Access in Dynamic Libraries in the ARM platform_ [\[paper-lk2006\]].
8+
//! - For RISC-V specifics, see
9+
//! - _Thread Local Storage - RISC-V ELF Specification - RISC-V ELF psABI Document_ [\[riscv\]].
10+
//! - For x86-64 specifics, see
11+
//! - _ELF x86-64-ABI psABI_ [\[x86-64 psABI\]] and
12+
//! - _Thread-Local Storage Descriptors for IA32 and AMD64/EM64T_ [\[RFC-TLSDESC-x86\]]
613
//!
7-
//! The dynamic thread vector (dtv) is currently unused.
8-
//!
9-
//! [[tls]]: https://akkadia.org/drepper/tls.pdf
10-
//! [[riscv]]: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/v1.0/riscv-elf.adoc#thread-local-storage
14+
//! [\[tls\]]: https://akkadia.org/drepper/tls.pdf
15+
//! [\[arm\]]: https://github.com/ARM-software/abi-aa/blob/2025Q1/addenda32/addenda32.rst#addendum-thread-local-storage
16+
//! [\[paper-lk2006\]]: https://www.fsfla.org/~lxoliva/writeups/TLS/paper-lk2006.pdf
17+
//! [\[riscv\]]: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/v1.0/riscv-elf.adoc#thread-local-storage
18+
//! [\[x86-64 psABI\]]: https://gitlab.com/x86-psABIs/x86-64-ABI/-/jobs/artifacts/master/raw/x86-64-ABI/abi.pdf?job=build
19+
//! [\[RFC-TLSDESC-x86\]]: https://www.fsfla.org/~lxoliva/writeups/TLS/RFC-TLSDESC-x86.txt
1120
1221
use core::alloc::Layout;
13-
use core::mem::MaybeUninit;
22+
use core::mem::{self, MaybeUninit};
1423
use core::{ptr, slice};
1524

1625
use hermit_entry::boot_info::TlsInfo;
1726

1827
use self::allocation::Allocation;
1928

29+
/// Thread-local storage data structures.
2030
pub struct Tls {
2131
_block: Allocation,
2232
thread_ptr: *mut (),
2333
}
2434

35+
/// Thread control block.
2536
#[repr(C)]
2637
struct Tcb {
27-
/// > For the implementation on GNU systems we can add one more requirement. The
28-
/// > address %gs:0 represents is actually the same as the thread pointer. I.e., the content of
29-
/// > the word addressed via %gs:0 is the address of the very same location.
30-
///
31-
/// [[tls]] Section 3.4.2: IA-32 specific
38+
/// Thread pointer.
3239
#[cfg(target_arch = "x86_64")]
3340
thread_ptr: *mut (),
3441

3542
/// Pointer to the dynamic thread vector (dtv).
3643
///
37-
/// Currently unused.
38-
dtv_ptr: *mut (),
44+
/// Currently not needed on Hermit.
45+
dtv: *mut (),
3946

40-
/// OS-specific TCB data.
47+
/// Implementation-defined TCB data.
4148
///
42-
/// Currently unused.
49+
/// Currently not used on Hermit.
4350
tcb_data: *mut (),
4451
}
4552

4653
impl Tls {
47-
pub fn new(tls_info: TlsInfo) -> Self {
54+
unsafe fn new(tls_info: TlsInfo) -> Self {
4855
let start = usize::try_from(tls_info.start).unwrap();
4956
let filesz = usize::try_from(tls_info.filesz).unwrap();
5057
let memsz = usize::try_from(tls_info.memsz).unwrap();
@@ -53,7 +60,6 @@ impl Tls {
5360
// Get TLS initialization image
5461
let tls_init_image = {
5562
let start = ptr::with_exposed_provenance(start);
56-
// SAFETY: We will have to trust the environment here.
5763
unsafe { slice::from_raw_parts(start, filesz) }
5864
};
5965

@@ -62,37 +68,53 @@ impl Tls {
6268
.unwrap()
6369
.pad_to_align();
6470

65-
let (tls_layout, data_offset, tcb_offset) =
71+
let (layout, tls_offset, tcb_offset) =
6672
if cfg!(any(target_arch = "aarch64", target_arch = "riscv64")) {
6773
// AArch64 and 64-bit RISC-V use TLS data structures variant I.
68-
// This means the TLS data comes after the TCB.
74+
75+
// Variant I does not guarantee more than 16 bytes of space for the TCB.
76+
assert_eq!(tcb_layout.size(), 16);
77+
78+
// Variant I requires the dtv pointer to be at the start of the TCB.
79+
assert_eq!(mem::offset_of!(Tcb, dtv), 0);
80+
81+
// In variant I, the TLS data comes after the TCB.
6982
let (tls_layout, data_offset) = tcb_layout.extend(data_layout).unwrap();
7083
(tls_layout.pad_to_align(), data_offset, 0)
7184
} else if cfg!(target_arch = "x86_64") {
7285
// x86-64 uses TLS data structures variant II.
73-
// This means the TCB comes after the TLS data.
86+
87+
// Variant II (on GNU systems) requires the thread pointer to be at the start of the TCB:
88+
// > For the implementation on GNU systems we can add one more requirement. The
89+
// > address %gs:0 represents is actually the same as the thread pointer. I.e., the content of
90+
// > the word addressed via %gs:0 is the address of the very same location.
91+
#[cfg(target_arch = "x86_64")]
92+
assert_eq!(mem::offset_of!(Tcb, thread_ptr), 0);
93+
94+
// In Variant II, the TCB comes after the TLS data.
7495
let (tls_layout, tcb_offset) = data_layout.extend(tcb_layout).unwrap();
7596
(tls_layout.pad_to_align(), 0, tcb_offset)
7697
} else {
7798
unimplemented!()
7899
};
79100

80-
let mut block = Allocation::new(tls_layout).unwrap();
101+
let mut block = Allocation::new(layout).unwrap();
81102

82-
// Initialize beginning of the TLS block with TLS initialization image
83-
block.as_mut_slice()[data_offset..][..tls_init_image.len()].copy_from_slice(tls_init_image);
103+
// Initialize the beginning of the TLS block with the TLS initialization image.
104+
block.as_mut_slice()[tls_offset..][..tls_init_image.len()].copy_from_slice(tls_init_image);
84105

85-
// Fill the rest of the block with zeros
86-
block.as_mut_slice()[data_offset..][tls_init_image.len()..data_layout.size()]
106+
// Fill the rest of the TLS block with zeros.
107+
block.as_mut_slice()[tls_offset..][tls_init_image.len()..data_layout.size()]
87108
.fill(MaybeUninit::new(0));
88109

89-
let thread_ptr = if cfg!(target_arch = "aarch64") {
110+
let thread_ptr = if cfg!(target_arch = "riscv64") {
111+
// On RISC-V, `tp` points to the address one past the end of the TCB.
112+
unsafe { block.as_mut_ptr().add(tls_offset).cast() }
113+
} else if cfg!(target_arch = "aarch64") {
114+
// For variant I, `tp` points to the start of the block.
90115
block.as_mut_ptr().cast()
91-
} else if cfg!(target_arch = "riscv64") {
92-
// > `tp` containing the address one past the end of the TCB.
93-
// [[riscv]]
94-
unsafe { block.as_mut_ptr().add(data_offset).cast() }
95116
} else if cfg!(target_arch = "x86_64") {
117+
// For variant II, `tp` points to the TCB after the TLS data.
96118
unsafe { block.as_mut_ptr().add(tcb_offset).cast() }
97119
} else {
98120
unimplemented!()
@@ -102,7 +124,7 @@ impl Tls {
102124
let tcb = Tcb {
103125
#[cfg(target_arch = "x86_64")]
104126
thread_ptr,
105-
dtv_ptr: ptr::null_mut(),
127+
dtv: ptr::null_mut(),
106128
tcb_data: ptr::null_mut(),
107129
};
108130
unsafe {
@@ -115,9 +137,10 @@ impl Tls {
115137
}
116138
}
117139

118-
pub fn from_environment() -> Option<Self> {
140+
pub fn from_env() -> Option<Self> {
119141
let tls_info = crate::env::boot_info().load_info.tls_info?;
120-
Some(Self::new(tls_info))
142+
let this = unsafe { Self::new(tls_info) };
143+
Some(this)
121144
}
122145

123146
pub fn thread_ptr(&self) -> *mut () {
@@ -137,20 +160,22 @@ mod allocation {
137160

138161
impl Allocation {
139162
pub fn new(layout: Layout) -> Option<Self> {
140-
let ptr = unsafe { ::alloc::alloc::alloc_zeroed(layout) };
163+
let ptr = unsafe { ::alloc::alloc::alloc(layout) };
164+
141165
if ptr.is_null() {
142166
return None;
143167
}
144-
Some(Self { ptr, layout })
145-
}
146168

147-
pub fn as_mut_slice(&mut self) -> &mut [MaybeUninit<u8>] {
148-
unsafe { slice::from_raw_parts_mut(self.ptr.cast(), self.layout.size()) }
169+
Some(Self { ptr, layout })
149170
}
150171

151172
pub fn as_mut_ptr(&self) -> *mut u8 {
152173
self.ptr
153174
}
175+
176+
pub fn as_mut_slice(&mut self) -> &mut [MaybeUninit<u8>] {
177+
unsafe { slice::from_raw_parts_mut(self.ptr.cast(), self.layout.size()) }
178+
}
154179
}
155180

156181
impl Drop for Allocation {

0 commit comments

Comments
 (0)