Thread local TSS
This commit is contained in:
parent
5b9c821ff5
commit
3eca1e3451
|
@ -3,7 +3,7 @@
|
||||||
use core::mem;
|
use core::mem;
|
||||||
use x86::dtables::{self, DescriptorTablePointer};
|
use x86::dtables::{self, DescriptorTablePointer};
|
||||||
use x86::segmentation::{self, SegmentSelector};
|
use x86::segmentation::{self, SegmentSelector};
|
||||||
use x86::task::TaskStateSegment;
|
use x86::task::{self, TaskStateSegment};
|
||||||
|
|
||||||
pub const GDT_NULL: usize = 0;
|
pub const GDT_NULL: usize = 0;
|
||||||
pub const GDT_KERNEL_CODE: usize = 1;
|
pub const GDT_KERNEL_CODE: usize = 1;
|
||||||
|
@ -33,11 +33,29 @@ pub const GDT_F_PAGE_SIZE: u8 = 1 << 7;
|
||||||
pub const GDT_F_PROTECTED_MODE: u8 = 1 << 6;
|
pub const GDT_F_PROTECTED_MODE: u8 = 1 << 6;
|
||||||
pub const GDT_F_LONG_MODE: u8 = 1 << 5;
|
pub const GDT_F_LONG_MODE: u8 = 1 << 5;
|
||||||
|
|
||||||
|
static mut INIT_GDTR: DescriptorTablePointer = DescriptorTablePointer {
|
||||||
|
limit: 0,
|
||||||
|
base: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
static mut INIT_GDT: [GdtEntry; 4] = [
|
||||||
|
// Null
|
||||||
|
GdtEntry::new(0, 0, 0, 0),
|
||||||
|
// Kernel code
|
||||||
|
GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_EXECUTABLE | GDT_A_PRIVILEGE, GDT_F_LONG_MODE),
|
||||||
|
// Kernel data
|
||||||
|
GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_LONG_MODE),
|
||||||
|
// Kernel TLS
|
||||||
|
GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_LONG_MODE)
|
||||||
|
];
|
||||||
|
|
||||||
|
#[thread_local]
|
||||||
pub static mut GDTR: DescriptorTablePointer = DescriptorTablePointer {
|
pub static mut GDTR: DescriptorTablePointer = DescriptorTablePointer {
|
||||||
limit: 0,
|
limit: 0,
|
||||||
base: 0
|
base: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[thread_local]
|
||||||
pub static mut GDT: [GdtEntry; 9] = [
|
pub static mut GDT: [GdtEntry; 9] = [
|
||||||
// Null
|
// Null
|
||||||
GdtEntry::new(0, 0, 0, 0),
|
GdtEntry::new(0, 0, 0, 0),
|
||||||
|
@ -53,12 +71,13 @@ pub static mut GDT: [GdtEntry; 9] = [
|
||||||
GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_LONG_MODE),
|
GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_LONG_MODE),
|
||||||
//TODO: User TLS
|
//TODO: User TLS
|
||||||
GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_LONG_MODE),
|
GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_LONG_MODE),
|
||||||
//TODO: TSS
|
// TSS
|
||||||
GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_TSS_AVAIL, 0),
|
GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_TSS_AVAIL, 0),
|
||||||
// TSS must be 16 bytes long, twice the normal size
|
// TSS must be 16 bytes long, twice the normal size
|
||||||
GdtEntry::new(0, 0, 0, 0),
|
GdtEntry::new(0, 0, 0, 0),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
#[thread_local]
|
||||||
pub static mut TSS: TaskStateSegment = TaskStateSegment {
|
pub static mut TSS: TaskStateSegment = TaskStateSegment {
|
||||||
reserved: 0,
|
reserved: 0,
|
||||||
rsp: [0; 3],
|
rsp: [0; 3],
|
||||||
|
@ -69,20 +88,24 @@ pub static mut TSS: TaskStateSegment = TaskStateSegment {
|
||||||
iomap_base: 0xFFFF
|
iomap_base: 0xFFFF
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Initialize GDT on the BSP
|
||||||
pub unsafe fn init(tcb_offset: usize) {
|
pub unsafe fn init(tcb_offset: usize) {
|
||||||
GDTR.limit = (GDT.len() * mem::size_of::<GdtEntry>() - 1) as u16;
|
// Setup the initial GDT with TLS, so we can setup the TLS GDT (a little confusing)
|
||||||
GDTR.base = GDT.as_ptr() as u64;
|
// This means that each CPU will have its own GDT, but we only need to define it once as a thread local
|
||||||
|
INIT_GDTR.limit = (INIT_GDT.len() * mem::size_of::<GdtEntry>() - 1) as u16;
|
||||||
|
INIT_GDTR.base = INIT_GDT.as_ptr() as u64;
|
||||||
|
|
||||||
GDT[GDT_KERNEL_TLS].set_offset(tcb_offset as u32);
|
// Set the TLS segment to the offset of the Thread Control Block
|
||||||
|
INIT_GDT[GDT_KERNEL_TLS].set_offset(tcb_offset as u32);
|
||||||
|
|
||||||
GDT[GDT_TSS].set_offset(&TSS as *const _ as u32);
|
// Run the AP GDT initialization, which does the rest
|
||||||
GDT[GDT_TSS].set_limit(mem::size_of::<TaskStateSegment>() as u32);
|
init_ap(tcb_offset);
|
||||||
|
|
||||||
init_ap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn init_ap() {
|
/// Initialize GDT for an AP
|
||||||
dtables::lgdt(&GDTR);
|
pub unsafe fn init_ap(tcb_offset: usize) {
|
||||||
|
// Load the initial GDT, before we have access to thread locals
|
||||||
|
dtables::lgdt(&INIT_GDTR);
|
||||||
|
|
||||||
segmentation::load_cs(SegmentSelector::new(GDT_KERNEL_CODE as u16));
|
segmentation::load_cs(SegmentSelector::new(GDT_KERNEL_CODE as u16));
|
||||||
segmentation::load_ds(SegmentSelector::new(GDT_KERNEL_DATA as u16));
|
segmentation::load_ds(SegmentSelector::new(GDT_KERNEL_DATA as u16));
|
||||||
|
@ -91,7 +114,21 @@ pub unsafe fn init_ap() {
|
||||||
segmentation::load_gs(SegmentSelector::new(GDT_KERNEL_DATA as u16));
|
segmentation::load_gs(SegmentSelector::new(GDT_KERNEL_DATA as u16));
|
||||||
segmentation::load_ss(SegmentSelector::new(GDT_KERNEL_DATA as u16));
|
segmentation::load_ss(SegmentSelector::new(GDT_KERNEL_DATA as u16));
|
||||||
|
|
||||||
//TODO: Seperate TSS for each processor task::load_ltr(SegmentSelector::new(GDT_TSS as u16));
|
// Now that we have access to thread locals, setup the AP's individual GDT
|
||||||
|
GDTR.limit = (GDT.len() * mem::size_of::<GdtEntry>() - 1) as u16;
|
||||||
|
GDTR.base = GDT.as_ptr() as u64;
|
||||||
|
|
||||||
|
GDT[GDT_KERNEL_TLS].set_offset(tcb_offset as u32);
|
||||||
|
|
||||||
|
// We can now access our TSS, which is a thread local
|
||||||
|
GDT[GDT_TSS].set_offset(&TSS as *const _ as u32);
|
||||||
|
GDT[GDT_TSS].set_limit(mem::size_of::<TaskStateSegment>() as u32);
|
||||||
|
|
||||||
|
// Load the new GDT, which is correctly located in thread local storage
|
||||||
|
dtables::lgdt(&GDTR);
|
||||||
|
|
||||||
|
// Load the task register
|
||||||
|
task::load_ltr(SegmentSelector::new(GDT_TSS as u16));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
|
|
@ -134,6 +134,11 @@ pub unsafe extern fn kstart() -> ! {
|
||||||
/// Entry to rust for an AP
|
/// Entry to rust for an AP
|
||||||
pub unsafe extern fn kstart_ap(stack_start: usize, stack_end: usize) -> ! {
|
pub unsafe extern fn kstart_ap(stack_start: usize, stack_end: usize) -> ! {
|
||||||
{
|
{
|
||||||
|
extern {
|
||||||
|
/// The end of the tbss.
|
||||||
|
static mut __tbss_end: u8;
|
||||||
|
}
|
||||||
|
|
||||||
assert_eq!(BSS_TEST_ZERO, 0);
|
assert_eq!(BSS_TEST_ZERO, 0);
|
||||||
assert_eq!(DATA_TEST_NONZERO, 0xFFFFFFFFFFFFFFFF);
|
assert_eq!(DATA_TEST_NONZERO, 0xFFFFFFFFFFFFFFFF);
|
||||||
|
|
||||||
|
@ -141,7 +146,7 @@ pub unsafe extern fn kstart_ap(stack_start: usize, stack_end: usize) -> ! {
|
||||||
let mut active_table = paging::init(stack_start, stack_end);
|
let mut active_table = paging::init(stack_start, stack_end);
|
||||||
|
|
||||||
// Set up GDT for AP
|
// Set up GDT for AP
|
||||||
gdt::init_ap();
|
gdt::init_ap((&__tbss_end as *const u8 as *const usize).offset(-1) as usize);
|
||||||
|
|
||||||
// Set up IDT for AP
|
// Set up IDT for AP
|
||||||
idt::init();
|
idt::init();
|
||||||
|
|
Loading…
Reference in a new issue