2016-08-15 22:34:20 +02:00
|
|
|
//! Global descriptor table
|
|
|
|
|
|
|
|
use core::mem;
|
|
|
|
|
2016-08-14 02:58:31 +02:00
|
|
|
pub const GDT_NULL: usize = 0;
|
|
|
|
pub const GDT_KERNEL_CODE: usize = 1;
|
|
|
|
pub const GDT_KERNEL_DATA: usize = 2;
|
|
|
|
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;
|
|
|
|
|
2016-08-15 22:34:20 +02:00
|
|
|
pub static mut GDTR: GdtDescriptor = GdtDescriptor {
|
|
|
|
size: 0,
|
|
|
|
offset: 0
|
|
|
|
};
|
|
|
|
|
|
|
|
pub static mut GDT: [GdtEntry; 5] = [GdtEntry::new(); 5];
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
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);
|
2016-08-17 23:47:54 +02:00
|
|
|
|
|
|
|
init_ap();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn init_ap() {
|
2016-08-15 22:34:20 +02:00
|
|
|
GDTR.load();
|
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bitflags! {
|
|
|
|
pub flags GdtFlags: u8 {
|
|
|
|
const GDT_PAGE_SIZE = 1 << 7,
|
|
|
|
const GDT_PROTECTED_MODE = 1 << 6,
|
|
|
|
const GDT_LONG_MODE = 1 << 5
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-14 02:58:31 +02:00
|
|
|
#[repr(packed)]
|
|
|
|
pub struct GdtDescriptor {
|
|
|
|
pub size: u16,
|
2016-08-15 22:34:20 +02:00
|
|
|
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");
|
|
|
|
}
|
2016-08-14 02:58:31 +02:00
|
|
|
}
|
|
|
|
|
2016-08-15 22:34:20 +02:00
|
|
|
#[derive(Copy, Clone, Debug)]
|
2016-08-14 02:58:31 +02:00
|
|
|
#[repr(packed)]
|
|
|
|
pub struct GdtEntry {
|
|
|
|
pub limitl: u16,
|
|
|
|
pub basel: u16,
|
|
|
|
pub basem: u8,
|
2016-08-15 22:34:20 +02:00
|
|
|
pub access: u8,
|
2016-08-14 02:58:31 +02:00
|
|
|
pub flags_limith: u8,
|
|
|
|
pub baseh: u8
|
|
|
|
}
|
|
|
|
|
|
|
|
impl GdtEntry {
|
2016-08-15 22:34:20 +02:00
|
|
|
pub const fn new() -> Self {
|
|
|
|
GdtEntry {
|
|
|
|
limitl: 0,
|
|
|
|
basel: 0,
|
|
|
|
basem: 0,
|
|
|
|
access: 0,
|
|
|
|
flags_limith: 0,
|
|
|
|
baseh: 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2016-08-14 02:58:31 +02:00
|
|
|
}
|
|
|
|
}
|