-
Notifications
You must be signed in to change notification settings - Fork 24
Expand file tree
/
Copy pathgdt.rs
More file actions
59 lines (53 loc) · 2.16 KB
/
Copy pathgdt.rs
File metadata and controls
59 lines (53 loc) · 2.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
use x86_64::{
instructions::tables::load_tss,
registers::segmentation::{Segment, SegmentSelector, CS},
structures::{
gdt::{Descriptor, GlobalDescriptorTable},
tss::TaskStateSegment,
},
PrivilegeLevel,
};
#[percpu::def_percpu]
#[unsafe(no_mangle)]
static TSS: TaskStateSegment = TaskStateSegment::new();
#[percpu::def_percpu]
static GDT: GlobalDescriptorTable = GlobalDescriptorTable::new();
/// Kernel code segment for 64-bit mode.
pub const KCODE64: SegmentSelector = SegmentSelector::new(1, PrivilegeLevel::Ring0);
/// Kernel data segment.
pub const KDATA: SegmentSelector = SegmentSelector::new(2, PrivilegeLevel::Ring0);
/// User data segment.
pub const UDATA: SegmentSelector = SegmentSelector::new(3, PrivilegeLevel::Ring3);
/// User code segment for 64-bit mode.
pub const UCODE64: SegmentSelector = SegmentSelector::new(4, PrivilegeLevel::Ring3);
/// Initializes the per-CPU TSS and GDT structures and loads them into the
/// current CPU.
pub(super) fn init() {
let gdt = unsafe { GDT.current_ref_mut_raw() };
assert_eq!(gdt.append(Descriptor::kernel_code_segment()), KCODE64);
assert_eq!(gdt.append(Descriptor::kernel_data_segment()), KDATA);
assert_eq!(gdt.append(Descriptor::user_data_segment()), UDATA);
assert_eq!(gdt.append(Descriptor::user_code_segment()), UCODE64);
let tss = gdt.append(Descriptor::tss_segment(unsafe { TSS.current_ref_raw() }));
gdt.load();
unsafe {
CS::set_reg(KCODE64);
load_tss(tss);
}
}
/// Returns the stack pointer for privilege level 0 (RSP0) of the current TSS.
#[cfg(feature = "uspace")]
pub(crate) fn read_tss_rsp0() -> memory_addr::VirtAddr {
let tss = unsafe { TSS.current_ref_raw() };
memory_addr::VirtAddr::from(tss.privilege_stack_table[0].as_u64() as usize)
}
/// Sets the stack pointer for privilege level 0 (RSP0) of the current TSS.
///
/// # Safety
///
/// Must be called after initialization and preemption is disabled.
#[cfg(feature = "uspace")]
pub(crate) unsafe fn write_tss_rsp0(rsp0: memory_addr::VirtAddr) {
let tss = unsafe { TSS.current_ref_mut_raw() };
tss.privilege_stack_table[0] = x86_64::VirtAddr::new_truncate(rsp0.as_usize() as u64);
}