Use x86 crate for definition of TSS and GDTR, WIP: loading TSS
This commit is contained in:
parent
55a0154eac
commit
7aafc165ec
|
@ -1,6 +1,9 @@
|
|||
//! Global descriptor table
|
||||
|
||||
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_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_TLS: usize = 5;
|
||||
pub const GDT_TSS: usize = 6;
|
||||
pub const GDT_TSS_HIGH: usize = 7;
|
||||
|
||||
pub static mut GDTR: GdtDescriptor = GdtDescriptor {
|
||||
size: 0,
|
||||
offset: 0
|
||||
pub const GDT_A_PRESENT: u8 = 1 << 7;
|
||||
pub const GDT_A_RING_0: u8 = 0 << 5;
|
||||
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() {
|
||||
GDT[GDT_KERNEL_CODE].set_access(GDT_PRESENT | GDT_RING_0 | GDT_SYSTEM | GDT_EXECUTABLE | GDT_PRIVILEGE);
|
||||
GDT[GDT_KERNEL_CODE].set_flags(GDT_LONG_MODE);
|
||||
GDTR.limit = (GDT.len() * mem::size_of::<GdtEntry>() - 1) as u16;
|
||||
GDTR.base = GDT.as_ptr() as u64;
|
||||
|
||||
GDT[GDT_KERNEL_DATA].set_access(GDT_PRESENT | GDT_RING_0 | GDT_SYSTEM | GDT_PRIVILEGE);
|
||||
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);
|
||||
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);
|
||||
|
||||
init_ap();
|
||||
}
|
||||
|
||||
pub unsafe fn init_ap() {
|
||||
GDTR.load();
|
||||
}
|
||||
dtables::lgdt(&GDTR);
|
||||
|
||||
bitflags! {
|
||||
pub flags GdtAccess: u8 {
|
||||
const GDT_PRESENT = 1 << 7,
|
||||
const GDT_RING_0 = 0 << 5,
|
||||
const GDT_RING_1 = 1 << 5,
|
||||
const GDT_RING_2 = 2 << 5,
|
||||
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,
|
||||
}
|
||||
}
|
||||
segmentation::load_cs(SegmentSelector::new(GDT_KERNEL_CODE as u16));
|
||||
segmentation::load_ds(SegmentSelector::new(GDT_KERNEL_DATA as u16));
|
||||
segmentation::load_es(SegmentSelector::new(GDT_KERNEL_DATA as u16));
|
||||
segmentation::load_fs(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));
|
||||
|
||||
bitflags! {
|
||||
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");
|
||||
}
|
||||
//TODO: Seperate TSS for each processor task::load_ltr(SegmentSelector::new(GDT_TSS as u16));
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(packed)]
|
||||
pub struct GdtEntry {
|
||||
pub limitl: u16,
|
||||
pub basel: u16,
|
||||
pub basem: u8,
|
||||
pub offsetl: u16,
|
||||
pub offsetm: u8,
|
||||
pub access: u8,
|
||||
pub flags_limith: u8,
|
||||
pub baseh: u8
|
||||
pub offseth: u8
|
||||
}
|
||||
|
||||
impl GdtEntry {
|
||||
pub const fn new() -> Self {
|
||||
pub const fn new(offset: u32, limit: u32, access: u8, flags: u8) -> Self {
|
||||
GdtEntry {
|
||||
limitl: 0,
|
||||
basel: 0,
|
||||
basem: 0,
|
||||
access: 0,
|
||||
flags_limith: 0,
|
||||
baseh: 0
|
||||
limitl: limit as u16,
|
||||
offsetl: offset as u16,
|
||||
offsetm: (offset >> 16) as u8,
|
||||
access: access,
|
||||
flags_limith: flags & 0xF0 | ((limit >> 16) as u8) & 0x0F,
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,7 +95,6 @@ macro_rules! interrupt_error {
|
|||
push r11"
|
||||
: : : : "intel", "volatile");
|
||||
|
||||
|
||||
// Call inner rust function
|
||||
inner();
|
||||
|
||||
|
@ -148,6 +147,3 @@ pub mod serial;
|
|||
|
||||
/// Initialization and start function
|
||||
pub mod start;
|
||||
|
||||
/// Task state segment
|
||||
pub mod tss;
|
||||
|
|
|
@ -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,
|
||||
}
|
Loading…
Reference in a new issue