Thread local TSS
This commit is contained in:
		
							parent
							
								
									5b9c821ff5
								
							
						
					
					
						commit
						3eca1e3451
					
				
					 2 changed files with 55 additions and 13 deletions
				
			
		| 
						 | 
					@ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue