Use x86 crate for definition of TSS and GDTR, WIP: loading TSS

This commit is contained in:
Jeremy Soller 2016-08-19 13:09:00 -06:00
parent 55a0154eac
commit 7aafc165ec
3 changed files with 74 additions and 103 deletions

View file

@ -1,6 +1,9 @@
//! Global descriptor table //! Global descriptor table
use core::mem; use core::mem;
use x86::dtables::{self, DescriptorTablePointer};
use x86::segmentation::{self, SegmentSelector};
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;
@ -9,110 +12,102 @@ pub const GDT_USER_CODE: usize = 3;
pub const GDT_USER_DATA: usize = 4; pub const GDT_USER_DATA: usize = 4;
pub const GDT_USER_TLS: usize = 5; pub const GDT_USER_TLS: usize = 5;
pub const GDT_TSS: usize = 6; pub const GDT_TSS: usize = 6;
pub const GDT_TSS_HIGH: usize = 7;
pub static mut GDTR: GdtDescriptor = GdtDescriptor { pub const GDT_A_PRESENT: u8 = 1 << 7;
size: 0, pub const GDT_A_RING_0: u8 = 0 << 5;
offset: 0 pub const GDT_A_RING_1: u8 = 1 << 5;
pub const GDT_A_RING_2: u8 = 2 << 5;
pub const GDT_A_RING_3: u8 = 3 << 5;
pub const GDT_A_SYSTEM: u8 = 1 << 4;
pub const GDT_A_EXECUTABLE: u8 = 1 << 3;
pub const GDT_A_CONFORMING: u8 = 1 << 2;
pub const GDT_A_PRIVILEGE: u8 = 1 << 1;
pub const GDT_A_DIRTY: u8 = 1;
pub const GDT_A_TSS_AVAIL: u8 = 0x9;
pub const GDT_A_TSS_BUSY: u8 = 0xB;
pub const GDT_F_PAGE_SIZE: u8 = 1 << 7;
pub const GDT_F_PROTECTED_MODE: u8 = 1 << 6;
pub const GDT_F_LONG_MODE: u8 = 1 << 5;
pub static mut GDTR: DescriptorTablePointer = DescriptorTablePointer {
limit: 0,
base: 0
}; };
pub static mut GDT: [GdtEntry; 5] = [GdtEntry::new(); 5]; pub static mut GDT: [GdtEntry; 8] = [
// 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),
// User code
GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_SYSTEM | GDT_A_EXECUTABLE | GDT_A_PRIVILEGE, GDT_F_LONG_MODE),
// User data
GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_LONG_MODE),
//TODO: User TLS
GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_LONG_MODE),
//TODO: TSS
GdtEntry::new(0, 0, 0 , 0),
// TSS must be 16 bytes long, twice the normal size
GdtEntry::new(0, 0, 0, 0),
];
pub static mut TSS: TaskStateSegment = TaskStateSegment {
reserved: 0,
rsp: [0; 3],
reserved2: 0,
ist: [0; 7],
reserved3: 0,
reserved4: 0,
iomap_base: 0xFFFF
};
pub unsafe fn init() { pub unsafe fn init() {
GDT[GDT_KERNEL_CODE].set_access(GDT_PRESENT | GDT_RING_0 | GDT_SYSTEM | GDT_EXECUTABLE | GDT_PRIVILEGE); GDTR.limit = (GDT.len() * mem::size_of::<GdtEntry>() - 1) as u16;
GDT[GDT_KERNEL_CODE].set_flags(GDT_LONG_MODE); GDTR.base = GDT.as_ptr() as u64;
GDT[GDT_KERNEL_DATA].set_access(GDT_PRESENT | GDT_RING_0 | GDT_SYSTEM | GDT_PRIVILEGE); GDT[GDT_TSS] = GdtEntry::new(&TSS as *const _ as u32, mem::size_of::<TaskStateSegment>() as u32, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_TSS_AVAIL, 0);
GDT[GDT_KERNEL_DATA].set_flags(GDT_LONG_MODE);
GDT[GDT_USER_CODE].set_access(GDT_PRESENT | GDT_RING_3 | GDT_SYSTEM | GDT_EXECUTABLE | GDT_PRIVILEGE);
GDT[GDT_USER_CODE].set_flags(GDT_LONG_MODE);
GDT[GDT_USER_DATA].set_access(GDT_PRESENT | GDT_RING_3 | GDT_SYSTEM | GDT_PRIVILEGE);
GDT[GDT_USER_DATA].set_flags(GDT_LONG_MODE);
GDTR.set_slice(&GDT);
init_ap(); init_ap();
} }
pub unsafe fn init_ap() { pub unsafe fn init_ap() {
GDTR.load(); dtables::lgdt(&GDTR);
}
bitflags! { segmentation::load_cs(SegmentSelector::new(GDT_KERNEL_CODE as u16));
pub flags GdtAccess: u8 { segmentation::load_ds(SegmentSelector::new(GDT_KERNEL_DATA as u16));
const GDT_PRESENT = 1 << 7, segmentation::load_es(SegmentSelector::new(GDT_KERNEL_DATA as u16));
const GDT_RING_0 = 0 << 5, segmentation::load_fs(SegmentSelector::new(GDT_KERNEL_DATA as u16));
const GDT_RING_1 = 1 << 5, segmentation::load_gs(SegmentSelector::new(GDT_KERNEL_DATA as u16));
const GDT_RING_2 = 2 << 5, segmentation::load_ss(SegmentSelector::new(GDT_KERNEL_DATA as u16));
const GDT_RING_3 = 3 << 5,
const GDT_SYSTEM = 1 << 4,
const GDT_EXECUTABLE = 1 << 3,
const GDT_CONFORMING = 1 << 2,
const GDT_PRIVILEGE = 1 << 1,
const GDT_DIRTY = 1,
}
}
bitflags! { //TODO: Seperate TSS for each processor task::load_ltr(SegmentSelector::new(GDT_TSS as u16));
pub flags GdtFlags: u8 {
const GDT_PAGE_SIZE = 1 << 7,
const GDT_PROTECTED_MODE = 1 << 6,
const GDT_LONG_MODE = 1 << 5
}
}
#[repr(packed)]
pub struct GdtDescriptor {
pub size: u16,
pub offset: u64
}
impl GdtDescriptor {
pub fn set_slice(&mut self, slice: &'static [GdtEntry]) {
self.size = (slice.len() * mem::size_of::<GdtEntry>() - 1) as u16;
self.offset = slice.as_ptr() as u64;
}
pub unsafe fn load(&self) {
asm!("lgdt [rax]" : : "{rax}"(self as *const _ as usize) : : "intel", "volatile");
}
} }
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
#[repr(packed)] #[repr(packed)]
pub struct GdtEntry { pub struct GdtEntry {
pub limitl: u16, pub limitl: u16,
pub basel: u16, pub offsetl: u16,
pub basem: u8, pub offsetm: u8,
pub access: u8, pub access: u8,
pub flags_limith: u8, pub flags_limith: u8,
pub baseh: u8 pub offseth: u8
} }
impl GdtEntry { impl GdtEntry {
pub const fn new() -> Self { pub const fn new(offset: u32, limit: u32, access: u8, flags: u8) -> Self {
GdtEntry { GdtEntry {
limitl: 0, limitl: limit as u16,
basel: 0, offsetl: offset as u16,
basem: 0, offsetm: (offset >> 16) as u8,
access: 0, access: access,
flags_limith: 0, flags_limith: flags & 0xF0 | ((limit >> 16) as u8) & 0x0F,
baseh: 0 offseth: (offset >> 24) as u8
} }
} }
pub fn set_offset(&mut self, offset: usize) {
self.basel = offset as u16;
self.basem = (offset >> 16) as u8;
self.baseh = (offset >> 24) as u8;
}
pub fn set_access(&mut self, access: GdtAccess) {
self.access = access.bits;
}
pub fn set_flags(&mut self, flags: GdtFlags) {
self.flags_limith = (self.flags_limith & 0xF) | flags.bits;
}
} }

View file

@ -95,7 +95,6 @@ macro_rules! interrupt_error {
push r11" push r11"
: : : : "intel", "volatile"); : : : : "intel", "volatile");
// Call inner rust function // Call inner rust function
inner(); inner();
@ -148,6 +147,3 @@ pub mod serial;
/// Initialization and start function /// Initialization and start function
pub mod start; pub mod start;
/// Task state segment
pub mod tss;

View file

@ -1,20 +0,0 @@
#[repr(packed)]
pub struct Tss {
pub reserved1: u32,
pub sp0: u64,
pub sp1: u64,
pub sp2: u64,
pub reserved2: u32,
pub reserved3: u32,
pub ist1: u64,
pub ist2: u64,
pub ist3: u64,
pub ist4: u64,
pub ist5: u64,
pub ist6: u64,
pub ist7: u64,
pub reserved4: u32,
pub reserved5: u32,
pub reserved6: u16,
pub iomap_base: u16,
}