ax_cpu/arch/x86_64/
gdt.rs1use core::ptr::NonNull;
2
3use x86_64::{
4 PrivilegeLevel, VirtAddr,
5 instructions::tables::load_tss,
6 registers::segmentation::{CS, DS, ES, SS, Segment, SegmentSelector},
7 structures::{
8 gdt::{Descriptor, GlobalDescriptorTable},
9 tss::TaskStateSegment,
10 },
11};
12
13pub(super) const DOUBLE_FAULT_IST_INDEX: u16 = 0;
14
15pub struct TrapStorage {
17 pub tss: NonNull<TaskStateSegment>,
19 pub gdt: NonNull<GlobalDescriptorTable>,
21 pub double_fault_stack_top: ax_memory_addr::VirtAddr,
23}
24
25#[trait_ffi::def_extern_trait(mod_path = "boot")]
36pub unsafe trait TrapStorageProvider {
37 fn take() -> TrapStorage;
39}
40
41pub const KCODE64: SegmentSelector = SegmentSelector::new(1, PrivilegeLevel::Ring0);
43pub const KDATA: SegmentSelector = SegmentSelector::new(2, PrivilegeLevel::Ring0);
45pub const UDATA: SegmentSelector = SegmentSelector::new(3, PrivilegeLevel::Ring3);
47pub const UCODE64: SegmentSelector = SegmentSelector::new(4, PrivilegeLevel::Ring3);
49
50fn install_exception_stacks(tss: &mut TaskStateSegment, double_fault_stack_top: VirtAddr) {
51 tss.interrupt_stack_table[usize::from(DOUBLE_FAULT_IST_INDEX)] = double_fault_stack_top;
52}
53
54pub(super) fn init() {
57 let mut storage = trap_storage_provider::take();
58 let (gdt, tss): (
61 &'static mut GlobalDescriptorTable,
62 &'static mut TaskStateSegment,
63 ) = unsafe { (storage.gdt.as_mut(), storage.tss.as_mut()) };
64 install_exception_stacks(
65 tss,
66 VirtAddr::new(storage.double_fault_stack_top.as_usize() as u64),
67 );
68 assert_eq!(gdt.append(Descriptor::kernel_code_segment()), KCODE64);
69 assert_eq!(gdt.append(Descriptor::kernel_data_segment()), KDATA);
70 assert_eq!(gdt.append(Descriptor::user_data_segment()), UDATA);
71 assert_eq!(gdt.append(Descriptor::user_code_segment()), UCODE64);
72 let tss = gdt.append(Descriptor::tss_segment(&*tss));
73 gdt.load();
74 unsafe {
77 CS::set_reg(KCODE64);
78 DS::set_reg(KDATA);
79 ES::set_reg(KDATA);
80 SS::set_reg(KDATA);
81 load_tss(tss);
82 }
83}