add IDT and GDT initialization
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
use core::arch::asm;
|
||||
|
||||
#[repr(C, align(8))]
|
||||
struct Gdt {
|
||||
entries: [u64; 5],
|
||||
}
|
||||
|
||||
impl Gdt {
|
||||
pub const fn new() -> Self {
|
||||
Self { entries: [0; 5] }
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C, packed)]
|
||||
struct GdtPointer {
|
||||
limit: u16,
|
||||
base: u64,
|
||||
}
|
||||
|
||||
#[repr(C, packed)]
|
||||
struct TaskStateSegment {
|
||||
reserved_0: u32,
|
||||
privilege_stacks: [u64; 3],
|
||||
reserved_1: u64,
|
||||
interrupt_stacks: [u64; 7],
|
||||
reserved_2: u64,
|
||||
reserved_3: u16,
|
||||
iomap_base: u16,
|
||||
}
|
||||
|
||||
impl TaskStateSegment {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
reserved_0: 0,
|
||||
privilege_stacks: [0; 3],
|
||||
reserved_1: 0,
|
||||
interrupt_stacks: [0; 7],
|
||||
reserved_2: 0,
|
||||
reserved_3: 0,
|
||||
iomap_base: core::mem::size_of::<TaskStateSegment>() as u16,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 16 KiB
|
||||
const DOUBLE_FAULT_STACK_SIZE: usize = 16 * 1024;
|
||||
|
||||
pub(super) const KERNEL_CODE_SELECTOR: u16 = 1 * 8;
|
||||
pub(super) const KERNEL_DATA_SELECTOR: u16 = 2 * 8;
|
||||
pub(super) const TSS_SELECTOR: u16 = 3 * 8;
|
||||
|
||||
#[repr(align(16))]
|
||||
struct ExceptionStack([u8; DOUBLE_FAULT_STACK_SIZE]);
|
||||
|
||||
static mut GDT: Gdt = Gdt::new();
|
||||
static mut TSS: TaskStateSegment = TaskStateSegment::new();
|
||||
static mut DOUBLE_FAULT_STACK: ExceptionStack = ExceptionStack([0; DOUBLE_FAULT_STACK_SIZE]);
|
||||
|
||||
pub fn init() {
|
||||
const _: () = assert!(core::mem::size_of::<TaskStateSegment>() == 104);
|
||||
const _: () = assert!(core::mem::size_of::<GdtPointer>() == 10);
|
||||
|
||||
unsafe {
|
||||
let stack_bottom = core::ptr::addr_of_mut!(DOUBLE_FAULT_STACK) as u64;
|
||||
let stack_top = stack_bottom + DOUBLE_FAULT_STACK_SIZE as u64;
|
||||
|
||||
TSS.interrupt_stacks[0] = stack_top;
|
||||
|
||||
let [tss_low, tss_high] = tss_descriptor(core::ptr::addr_of!(TSS));
|
||||
|
||||
let gdt = Gdt {
|
||||
entries: [
|
||||
0,
|
||||
kernel_code_descriptor(),
|
||||
kernel_data_descriptor(),
|
||||
tss_low,
|
||||
tss_high,
|
||||
],
|
||||
};
|
||||
core::ptr::addr_of_mut!(GDT).write(gdt);
|
||||
|
||||
gdt_reload();
|
||||
}
|
||||
}
|
||||
|
||||
fn gdt_reload() {
|
||||
unsafe {
|
||||
asm!(
|
||||
"lgdt [{gdt_pointer}]",
|
||||
|
||||
"push {code_selector}",
|
||||
"lea rax, [rip + 2f]",
|
||||
"push rax",
|
||||
"retfq",
|
||||
"2:",
|
||||
|
||||
"mov ax, {data_selector}",
|
||||
"mov ds, ax",
|
||||
"mov es, ax",
|
||||
"mov fs, ax",
|
||||
"mov gs, ax",
|
||||
"mov ss, ax",
|
||||
|
||||
"mov ax, {tss_selector}",
|
||||
"ltr ax",
|
||||
|
||||
gdt_pointer = in(reg) &GdtPointer {
|
||||
limit: (core::mem::size_of::<Gdt>() - 1) as u16,
|
||||
base: core::ptr::addr_of!(GDT) as u64,
|
||||
},
|
||||
code_selector = const KERNEL_CODE_SELECTOR,
|
||||
data_selector = const KERNEL_DATA_SELECTOR,
|
||||
tss_selector = const TSS_SELECTOR,
|
||||
lateout("rax") _,
|
||||
options(preserves_flags)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const PRESENT: u64 = 1 << 47;
|
||||
const USER_DESCRIPTOR: u64 = 1 << 44;
|
||||
const EXECUTABLE: u64 = 1 << 43;
|
||||
const READ_WRITE: u64 = 1 << 41;
|
||||
const LONG_MODE: u64 = 1 << 53;
|
||||
|
||||
fn kernel_code_descriptor() -> u64 {
|
||||
PRESENT | USER_DESCRIPTOR | EXECUTABLE | READ_WRITE | LONG_MODE
|
||||
}
|
||||
|
||||
fn kernel_data_descriptor() -> u64 {
|
||||
PRESENT | USER_DESCRIPTOR | READ_WRITE
|
||||
}
|
||||
|
||||
fn tss_descriptor(tss: *const TaskStateSegment) -> [u64; 2] {
|
||||
let base = tss as u64;
|
||||
let limit = (core::mem::size_of::<TaskStateSegment>() - 1) as u64;
|
||||
|
||||
let low = (limit & 0xFFFF)
|
||||
| ((base & 0x00FF_FFFF) << 16)
|
||||
| (0x09 << 40)
|
||||
| (1 << 47)
|
||||
| (((limit >> 16) & 0x0F) << 48)
|
||||
| (((base >> 24) & 0xFF) << 56);
|
||||
|
||||
let high = base >> 32;
|
||||
[low, high]
|
||||
}
|
||||
Reference in New Issue
Block a user