Skip to content

Commit 6d2bcb3

Browse files
authored
Merge pull request #96 from rust-osdev/elf-tls-sections
Add basic support for ELF thread local storage segments
2 parents f8ebd54 + fb926bc commit 6d2bcb3

File tree

3 files changed

+87
-8
lines changed

3 files changed

+87
-8
lines changed

Diff for: src/bootinfo/mod.rs

+44
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ pub struct BootInfo {
4242
/// can be safely accessed.
4343
#[cfg(feature = "map_physical_memory")]
4444
pub physical_memory_offset: u64,
45+
tls_template: TlsTemplate,
4546
_non_exhaustive: u8, // `()` is not FFI safe
4647
}
4748

@@ -51,18 +52,61 @@ impl BootInfo {
5152
#[doc(hidden)]
5253
pub fn new(
5354
memory_map: MemoryMap,
55+
tls_template: Option<TlsTemplate>,
5456
recursive_page_table_addr: u64,
5557
physical_memory_offset: u64,
5658
) -> Self {
59+
let tls_template = tls_template.unwrap_or(TlsTemplate {
60+
start_addr: 0,
61+
file_size: 0,
62+
mem_size: 0,
63+
});
5764
BootInfo {
5865
memory_map,
66+
tls_template,
5967
#[cfg(feature = "recursive_page_table")]
6068
recursive_page_table_addr,
6169
#[cfg(feature = "map_physical_memory")]
6270
physical_memory_offset,
6371
_non_exhaustive: 0,
6472
}
6573
}
74+
75+
/// Returns information about the thread local storage segment of the kernel.
76+
///
77+
/// Returns `None` if the kernel has no thread local storage segment.
78+
///
79+
/// (The reason this is a method instead of a normal field is that `Option`
80+
/// is not FFI-safe.)
81+
pub fn tls_template(&self) -> Option<TlsTemplate> {
82+
if self.tls_template.mem_size > 0 {
83+
Some(self.tls_template)
84+
} else {
85+
None
86+
}
87+
}
88+
}
89+
90+
/// Information about the thread local storage (TLS) template.
91+
///
92+
/// This template can be used to set up thread local storage for threads. For
93+
/// each thread, a new memory location of size `mem_size` must be initialized.
94+
/// Then the first `file_size` bytes of this template needs to be copied to the
95+
/// location. The additional `mem_size - file_size` bytes must be initialized with
96+
/// zero.
97+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
98+
#[repr(C)]
99+
pub struct TlsTemplate {
100+
/// The virtual start address of the thread local storage template.
101+
pub start_addr: u64,
102+
/// The number of data bytes in the template.
103+
///
104+
/// Corresponds to the length of the `.tdata` section.
105+
pub file_size: u64,
106+
/// The total number of bytes that the TLS segment should have in memory.
107+
///
108+
/// Corresponds to the combined length of the `.tdata` and `.tbss` sections.
109+
pub mem_size: u64,
66110
}
67111

68112
extern "C" {

Diff for: src/main.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ fn bootloader_main(
271271
};
272272

273273
// Map kernel segments.
274-
let stack_end = page_table::map_kernel(
274+
let kernel_memory_info = page_table::map_kernel(
275275
kernel_start.phys(),
276276
kernel_stack_address,
277277
KERNEL_STACK_SIZE,
@@ -324,6 +324,7 @@ fn bootloader_main(
324324
// Construct boot info structure.
325325
let mut boot_info = BootInfo::new(
326326
memory_map,
327+
kernel_memory_info.tls_segment,
327328
recursive_page_table_addr.as_u64(),
328329
physical_memory_offset,
329330
);
@@ -352,7 +353,7 @@ fn bootloader_main(
352353
sse::enable_sse();
353354

354355
let entry_point = VirtAddr::new(entry_point);
355-
unsafe { context_switch(boot_info_addr, entry_point, stack_end) };
356+
unsafe { context_switch(boot_info_addr, entry_point, kernel_memory_info.stack_end) };
356357
}
357358

358359
fn enable_nxe_bit() {

Diff for: src/page_table.rs

+40-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::frame_allocator::FrameAllocator;
22
use bootloader::bootinfo::MemoryRegionType;
3+
use bootloader::bootinfo::TlsTemplate;
34
use fixedvec::FixedVec;
45
use x86_64::structures::paging::mapper::{MapToError, MapperFlush, UnmapError};
56
use x86_64::structures::paging::{
@@ -9,16 +10,40 @@ use x86_64::structures::paging::{
910
use x86_64::{align_up, PhysAddr, VirtAddr};
1011
use xmas_elf::program::{self, ProgramHeader64};
1112

13+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14+
pub struct MemoryInfo {
15+
pub stack_end: VirtAddr,
16+
pub tls_segment: Option<TlsTemplate>,
17+
}
18+
19+
#[derive(Debug)]
20+
pub enum MapKernelError {
21+
Mapping(MapToError),
22+
MultipleTlsSegments,
23+
}
24+
25+
impl From<MapToError> for MapKernelError {
26+
fn from(e: MapToError) -> Self {
27+
MapKernelError::Mapping(e)
28+
}
29+
}
30+
1231
pub(crate) fn map_kernel(
1332
kernel_start: PhysAddr,
1433
stack_start: Page,
1534
stack_size: u64,
1635
segments: &FixedVec<ProgramHeader64>,
1736
page_table: &mut RecursivePageTable,
1837
frame_allocator: &mut FrameAllocator,
19-
) -> Result<VirtAddr, MapToError> {
38+
) -> Result<MemoryInfo, MapKernelError> {
39+
let mut tls_segment = None;
2040
for segment in segments {
21-
map_segment(segment, kernel_start, page_table, frame_allocator)?;
41+
let tls = map_segment(segment, kernel_start, page_table, frame_allocator)?;
42+
if let Some(tls) = tls {
43+
if tls_segment.replace(tls).is_some() {
44+
return Err(MapKernelError::MultipleTlsSegments);
45+
}
46+
}
2247
}
2348

2449
// Create a stack
@@ -35,15 +60,18 @@ pub(crate) fn map_kernel(
3560
unsafe { map_page(page, frame, flags, page_table, frame_allocator)? }.flush();
3661
}
3762

38-
Ok(stack_end.start_address())
63+
Ok(MemoryInfo {
64+
stack_end: stack_end.start_address(),
65+
tls_segment,
66+
})
3967
}
4068

4169
pub(crate) fn map_segment(
4270
segment: &ProgramHeader64,
4371
kernel_start: PhysAddr,
4472
page_table: &mut RecursivePageTable,
4573
frame_allocator: &mut FrameAllocator,
46-
) -> Result<(), MapToError> {
74+
) -> Result<Option<TlsTemplate>, MapToError> {
4775
let typ = segment.get_type().unwrap();
4876
match typ {
4977
program::Type::Load => {
@@ -160,10 +188,16 @@ pub(crate) fn map_segment(
160188
unsafe { addr.as_mut_ptr::<u8>().write(0) };
161189
}
162190
}
191+
192+
Ok(None)
163193
}
164-
_ => {}
194+
program::Type::Tls => Ok(Some(TlsTemplate {
195+
start_addr: segment.virtual_addr,
196+
mem_size: segment.mem_size,
197+
file_size: segment.file_size,
198+
})),
199+
_ => Ok(None),
165200
}
166-
Ok(())
167201
}
168202

169203
pub(crate) unsafe fn map_page<'a, S>(

0 commit comments

Comments
 (0)