tartan_kernel/arch/
x86_common.rsuse core::arch::naked_asm;
use core::mem::size_of;
use core::ptr::addr_of;
use memoffset::offset_of;
use paste::paste;
use tartan_arch::x86_common::interrupt::{
InterruptDescriptorTableRegister, InterruptVector,
};
use tartan_arch::x86_common::protection::{
DescriptorFlags, GateDescriptor, GateDescriptorFlags, GlobalDescriptorTableRegister,
LocalDescriptorTableRegister, SegmentDescriptor, SegmentDescriptorFlags, Selector,
SystemDescriptorType, TaskRegister,
};
use tartan_arch::x86_common::{ControlRegister0, ControlRegister4, FlagRegister};
#[cfg(target_arch = "x86")]
use tartan_arch::x86::protection::TaskStateSegmentHeader;
#[cfg(target_arch = "x86_64")]
use tartan_arch::x86_64::protection::TaskStateSegmentHeader;
static mut GLOBAL_DESCRIPTOR_TABLE: GlobalDescriptorTable = GlobalDescriptorTable {
null_segment: SegmentDescriptor::new(),
code_segment: SegmentDescriptor::new(),
data_segment: SegmentDescriptor::new(),
task_state_segment: SegmentDescriptor::new(),
};
static mut INTERRUPT_DESCRIPTOR_TABLE: InterruptDescriptorTable =
InterruptDescriptorTable { descriptors: [GateDescriptor::new(); 0xff] };
static mut TASK_STATE_SEGMENT: TaskStateSegmentHeader = TaskStateSegmentHeader::new();
struct GlobalDescriptorTable {
pub null_segment: SegmentDescriptor,
pub code_segment: SegmentDescriptor,
pub data_segment: SegmentDescriptor,
pub task_state_segment: SegmentDescriptor,
}
macro_rules! global_selector {
[$segment:ident] => {
{
let offset = offset_of!(GlobalDescriptorTable, $segment);
Selector::new(offset.try_into().unwrap(), 0, false)
}
}
}
struct InterruptDescriptorTable {
pub descriptors: [GateDescriptor; 0xff],
}
pub fn initialize_control_registers() {
let mut flags = FlagRegister::get();
assert!(!flags.virtual_8086_mode()); flags.set_interrupt_enabled(true); flags.set_io_privilege_level(0); flags.set_alignment_check_or_access_control(true); unsafe {
FlagRegister::set(flags);
}
let mut cr0 = ControlRegister0::get();
assert!(cr0.protected_mode()); cr0.set_cache_disabled(false); cr0.set_cache_not_write_through(false); cr0.set_alignment_check_mask(true); cr0.set_write_protect(true); cr0.set_native_fpu_error(true); cr0.set_fpu_emulation(true);
#[cfg(target_arch = "x86_64")]
{
assert!(cr0.paging()); }
unsafe {
ControlRegister0::set(cr0);
}
let mut cr4 = ControlRegister4::get();
cr4.set_virtual_8086_extensions(false); cr4.set_protected_virtual_interrupts(false); cr4.set_timestamp_disabled(true); cr4.set_debugging_extensions(true); cr4.set_page_size_extensions(false); cr4.set_machine_check_exception(true); cr4.set_global_pages(false); cr4.set_performance_counter(false); cr4.set_sse_and_fpu_save(false); cr4.set_simd_exceptions(false); cr4.set_restrict_user_mode_instructions(false); cr4.set_virtual_machine_extensions(false); cr4.set_safer_mode_extensions(false); cr4.set_extended_state_save(false); cr4.set_supervisor_execution_prevention(false); cr4.set_supervisor_access_prevention(false); cr4.set_control_flow_enforcement(false); #[cfg(target_arch = "x86_64")]
{
assert!(cr4.physical_address_extension()); cr4.set_five_level_paging(false); cr4.set_extended_base_registers(false); cr4.set_process_context_ids(false); cr4.set_user_protection_keys(false); cr4.set_supervisor_protection_keys(false); }
unsafe {
ControlRegister4::set(cr4);
}
#[cfg(target_arch = "x86_64")]
{
use tartan_arch::x86_64::ExtendedFeatureEnableRegister;
let mut efer = ExtendedFeatureEnableRegister::get();
assert!(efer.long_mode_active()); efer.set_syscall(true); efer.set_no_execute(true); unsafe {
ExtendedFeatureEnableRegister::set(efer);
}
}
}
pub fn initialize_segments() {
unsafe {
GLOBAL_DESCRIPTOR_TABLE.code_segment = make_code_descriptor();
GLOBAL_DESCRIPTOR_TABLE.data_segment = make_data_descriptor();
GLOBAL_DESCRIPTOR_TABLE.task_state_segment = make_task_state_descriptor();
}
let gdtr = GlobalDescriptorTableRegister {
address: addr_of!(GLOBAL_DESCRIPTOR_TABLE) as usize,
limit: (size_of::<GlobalDescriptorTable>() - 1).try_into().unwrap(),
};
unsafe {
GlobalDescriptorTableRegister::set_with_segments(
&gdtr,
global_selector!(code_segment),
global_selector!(data_segment),
)
}
unsafe {
TaskRegister::set(global_selector!(task_state_segment));
}
unsafe {
LocalDescriptorTableRegister::set(global_selector!(null_segment));
}
}
fn make_code_descriptor() -> SegmentDescriptor {
#![allow(clippy::field_reassign_with_default)] let mut flags = SegmentDescriptorFlags::default();
flags.set_present(true);
flags.set_granularity(true);
flags.set_is_application(true);
flags.set_is_code(true);
flags.set_code_readable(true);
#[cfg(target_arch = "x86")]
flags.set_application_mode_32(true);
#[cfg(target_arch = "x86_64")]
flags.set_code_mode_64(true);
let mut descriptor = SegmentDescriptor::default();
descriptor.flags = flags;
descriptor.set_limit(SegmentDescriptor::LIMIT_MAX);
descriptor
}
fn make_data_descriptor() -> SegmentDescriptor {
#![allow(clippy::field_reassign_with_default)] let mut flags = SegmentDescriptorFlags::default();
flags.set_present(true);
flags.set_granularity(true);
flags.set_is_application(true);
flags.set_is_code(false);
flags.set_data_writable(true);
#[cfg(target_arch = "x86")]
flags.set_application_mode_32(true);
let mut descriptor = SegmentDescriptor::default();
descriptor.flags = flags;
descriptor.set_limit(SegmentDescriptor::LIMIT_MAX);
descriptor
}
fn make_task_state_descriptor() -> SegmentDescriptor {
#![allow(clippy::field_reassign_with_default)] let mut flags = SegmentDescriptorFlags::default();
flags.set_present(true);
flags.set_is_application(false);
flags.set_system_type(SystemDescriptorType::TaskStateAvailable);
let mut descriptor = SegmentDescriptor::default();
descriptor.flags = flags;
descriptor.set_address(addr_of!(TASK_STATE_SEGMENT) as usize);
descriptor.set_limit((size_of::<TaskStateSegmentHeader>() - 1).try_into().unwrap());
descriptor
}
pub fn initialize_interrupts() {
macro_rules! forward_interrupt {
[$vector:literal] => {
paste! {
#[naked]
unsafe extern "C" fn [< forward_interrupt_ $vector >]() {
#[cfg(target_arch = "x86")]
naked_asm!(
"
push {}
call {}
",
const $vector,
sym handle_unknown_interrupt,
);
#[cfg(target_arch = "x86_64")]
naked_asm!(
"
mov rdi, {}
call {}
",
const $vector,
sym handle_unknown_interrupt,
);
}
unsafe {
INTERRUPT_DESCRIPTOR_TABLE.descriptors[$vector] =
make_interrupt_gate(
global_selector!(code_segment),
[< forward_interrupt_ $vector >],
);
}
}
}
}
forward_interrupt!(0);
forward_interrupt!(1);
forward_interrupt!(2);
forward_interrupt!(3);
forward_interrupt!(4);
forward_interrupt!(5);
forward_interrupt!(6);
forward_interrupt!(7);
forward_interrupt!(8);
forward_interrupt!(9);
forward_interrupt!(10);
forward_interrupt!(11);
forward_interrupt!(12);
forward_interrupt!(13);
forward_interrupt!(14);
forward_interrupt!(15);
forward_interrupt!(16);
forward_interrupt!(17);
forward_interrupt!(18);
forward_interrupt!(19);
forward_interrupt!(20);
forward_interrupt!(21);
forward_interrupt!(22);
forward_interrupt!(23);
forward_interrupt!(24);
forward_interrupt!(25);
forward_interrupt!(26);
forward_interrupt!(27);
forward_interrupt!(28);
forward_interrupt!(29);
forward_interrupt!(30);
forward_interrupt!(31);
let idtr = InterruptDescriptorTableRegister {
address: addr_of!(INTERRUPT_DESCRIPTOR_TABLE) as usize,
limit: (size_of::<InterruptDescriptorTable>() - 1).try_into().unwrap(),
};
unsafe { InterruptDescriptorTableRegister::set(&idtr) };
}
fn make_interrupt_gate(
code_segment: Selector,
handler: unsafe extern "C" fn(),
) -> GateDescriptor {
#![allow(clippy::field_reassign_with_default)] let mut flags = GateDescriptorFlags::default();
flags.set_present(true);
flags.set_is_application(false);
flags.set_system_type(SystemDescriptorType::InterruptGate);
let mut descriptor = GateDescriptor::default();
descriptor.flags = flags;
descriptor.set_selector(code_segment);
descriptor.set_entry_point_offset(handler as usize);
descriptor
}
fn handle_unknown_interrupt(vector: InterruptVector) {
panic!("Interrupt {:?}", vector);
}