Files
dusk/src/arch/x86_64/gdt.rs
T
2026-08-28 10:14:39 -05:00

178 lines
4.4 KiB
Rust

use core::arch::asm;
use crate::memory::VirtualAddr;
#[repr(C, align(8))]
struct Gdt {
entries: [u64; 7],
}
impl Gdt {
pub const fn new() -> Self {
Self { entries: [0; 7] }
}
}
#[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 USER_CODE_SELECTOR: u16 = (3 * 8) | 3;
pub(super) const USER_DATA_SELECTOR: u16 = (4 * 8) | 3;
pub(super) const TSS_SELECTOR: u16 = 5 * 8;
#[repr(align(16))]
#[allow(dead_code)] // field 0 is read, rust just cant tell
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]);
const _: () = assert!(core::mem::size_of::<TaskStateSegment>() == 104);
const _: () = assert!(core::mem::size_of::<GdtPointer>() == 10);
pub fn init() {
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(),
user_code_descriptor(),
user_data_descriptor(),
tss_low,
tss_high,
],
};
core::ptr::addr_of_mut!(GDT).write(gdt);
gdt_reload();
}
}
pub fn set_kernel_stack(stack_top: VirtualAddr) {
unsafe {
TSS.privilege_stacks[0] = stack_top.as_usize() as u64;
}
}
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 CODE_DATA_DESCRIPTOR: u64 = 1 << 44;
const USER_PRIVILEGE: u64 = 3 << 45;
const EXECUTABLE: u64 = 1 << 43;
const READ_WRITE: u64 = 1 << 41;
const GRANULARITY: u64 = 1 << 55;
const SIZE: u64 = 1 << 54;
const LONG_MODE: u64 = 1 << 53;
fn kernel_code_descriptor() -> u64 {
PRESENT | CODE_DATA_DESCRIPTOR | EXECUTABLE | READ_WRITE | LONG_MODE | GRANULARITY
}
fn kernel_data_descriptor() -> u64 {
PRESENT | CODE_DATA_DESCRIPTOR | READ_WRITE | SIZE | GRANULARITY
}
fn user_code_descriptor() -> u64 {
PRESENT
| CODE_DATA_DESCRIPTOR
| USER_PRIVILEGE
| EXECUTABLE
| READ_WRITE
| LONG_MODE
| GRANULARITY
}
fn user_data_descriptor() -> u64 {
PRESENT | CODE_DATA_DESCRIPTOR | USER_PRIVILEGE | READ_WRITE | SIZE | GRANULARITY
}
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]
}