Skip to content

feat(usermode): usermode code execution, usermode GDT segments #81

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 7 additions & 37 deletions src/fzboot/irq/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ use crate::{
x86::{
apic::local_apic::InterruptVector,
descriptors::{
gdt::SegmentSelector,
gdt::KERNEL_CODE_SELECTOR,
idt::{GateDescriptor, GateType, InterruptDescriptorTable},
},
int::{disable_interrupts, enable_interrupts, interrupts_disabled},
Expand Down Expand Up @@ -166,12 +166,7 @@ impl<A: MemoryAddress> InterruptManager<A> {
.with_dpl(PrivilegeLevel::Ring0)
.with_offset(handler_ptr)
.with_present(true)
.with_segment_selector(
SegmentSelector::gdt_selector()
.with_index(0x10)
.expect("invalid segment selector while registering static handler")
.with_rpl(PrivilegeLevel::Ring0),
)
.with_segment_selector(*KERNEL_CODE_SELECTOR)
} else {
let handler_ptr = PhyAddr::new(
u64::try_from(default_handler_ptr as usize).expect("invalid handler pointer"),
Expand All @@ -181,12 +176,7 @@ impl<A: MemoryAddress> InterruptManager<A> {
.with_dpl(PrivilegeLevel::Ring0)
.with_offset(handler_ptr)
.with_present(true)
.with_segment_selector(
SegmentSelector::gdt_selector()
.with_index(0x10)
.expect("invalid segment selector while registering static handler")
.with_rpl(PrivilegeLevel::Ring0),
)
.with_segment_selector(*KERNEL_CODE_SELECTOR)
};

// Setup default handlers for every interrupt vector when first loading the table.
Expand Down Expand Up @@ -309,12 +299,7 @@ impl<A: MemoryAddress> InterruptManager<A> {
.with_dpl(PrivilegeLevel::Ring0)
.with_offset(handler_ptr)
.with_present(true)
.with_segment_selector(
SegmentSelector::gdt_selector()
.with_index(0x10)
.expect("invalid segment selector while registering static handler")
.with_rpl(PrivilegeLevel::Ring0),
)
.with_segment_selector(*KERNEL_CODE_SELECTOR)
} else {
let handler_ptr = PhyAddr::new(
u64::try_from(runtime_entry_ptr as usize).expect("invalid handler pointer"),
Expand All @@ -324,12 +309,7 @@ impl<A: MemoryAddress> InterruptManager<A> {
.with_dpl(PrivilegeLevel::Ring0)
.with_offset(handler_ptr)
.with_present(true)
.with_segment_selector(
SegmentSelector::gdt_selector()
.with_index(0x10)
.expect("invalid segment selector while registering static handler")
.with_rpl(PrivilegeLevel::Ring0),
)
.with_segment_selector(*KERNEL_CODE_SELECTOR)
};

self.idt
Expand Down Expand Up @@ -400,12 +380,7 @@ impl<A: MemoryAddress> InterruptManager<A> {
.with_dpl(PrivilegeLevel::Ring0)
.with_offset(handler_ptr)
.with_present(true)
.with_segment_selector(
SegmentSelector::gdt_selector()
.with_index(0x10)
.expect("invalid segment selector while registering static handler")
.with_rpl(PrivilegeLevel::Ring0),
)
.with_segment_selector(*KERNEL_CODE_SELECTOR)
} else {
let handler_ptr =
PhyAddr::new(u64::try_from(handler as usize).expect("invalid handler pointer"));
Expand All @@ -414,12 +389,7 @@ impl<A: MemoryAddress> InterruptManager<A> {
.with_dpl(PrivilegeLevel::Ring0)
.with_offset(handler_ptr)
.with_present(true)
.with_segment_selector(
SegmentSelector::gdt_selector()
.with_index(0x10)
.expect("invalid segment selector while registering static handler")
.with_rpl(PrivilegeLevel::Ring0),
)
.with_segment_selector(*KERNEL_CODE_SELECTOR)
};

self.idt
Expand Down
71 changes: 70 additions & 1 deletion src/fzboot/irq/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use core::arch::asm;

use crate::io::outb;
use crate::io::IOPort;
use crate::mem::VirtAddr;
Expand All @@ -15,7 +17,7 @@ pub mod handlers;
///
/// Interrupt handlers receive this structure as their first argument.
#[repr(C)]
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, Default)]
pub struct InterruptStackFrame {
/// Saved content of the `RIP` (_instruction pointer_ register) prior to the interrupt.
pub(crate) rip: VirtAddr,
Expand All @@ -36,6 +38,73 @@ pub struct InterruptStackFrame {
pub(crate) registers: GeneralPurposeRegisters,
}

impl InterruptStackFrame {
/// Performs an `iret`.
///
/// Restores the previous execution context using the value defined in the structure.
///
/// Used to return to original execution context after an interrupt was processed.
/// Can also be used to change the current privilege level (`CPL`) of the CPU.
pub unsafe fn iret(&self) {
#[cfg(target_arch = "x86_64")]
unsafe {
asm!("push {0:r}",
"push {1:r}",
"push {2:r}",
"push {3:r}",
"push {4:r}",
"iretq",
in(reg) self.stack_segment,
in(reg) u64::from(self.stack_ptr),
in(reg) self.rflags,
in(reg) self.cs,
in(reg) u64::from(self.rip),
options(noreturn)
)
}
}

/// Performs an `iret`, preserving the current value of `RFLAGS` (and of the stack pointer, if `stack_ptr_override` is set to false).
///
/// Restores the previous execution context using the value defined in the structure.
///
/// Used to return to original execution context after an interrupt was processed.
/// Can also be used to change the current privilege level (`CPL`) of the CPU.
pub unsafe fn iret_preserve_flags(&self, stack_ptr_override: bool) -> ! {
// emulates a fake InterruptStackFrame with data and code segment selector set to `CPL` = 3
#[cfg(target_arch = "x86_64")]
unsafe {
if !stack_ptr_override {
asm!("push {0:r}",
"push rsp",
"pushfq",
"push {1:r}",
"push {2:r}",
"iretq",
in(reg) self.stack_segment,
in(reg) self.cs,
in(reg) u64::from(self.rip),
options(noreturn)
)
} else {
asm!("push {0:r}",
"push {1:r}",
"pushfq",
"push {2:r}",
"push {3:r}",
"iretq",
in(reg) self.stack_segment,
in(reg) u64::from(self.stack_ptr),
in(reg) self.cs,
in(reg) u64::from(self.rip),
options(noreturn))
}
}

unreachable!()
}
}

/// Content of the _Exception Stack Frame_, set up by the CPU when an exception that defines an error code
/// is raised.
///
Expand Down
4 changes: 2 additions & 2 deletions src/fzboot/kernel/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use fzboot::{
},
video,
x86::{
descriptors::gdt::{long_init_gdt, LONG_GDT_ADDR},
descriptors::gdt::{kernel_init_gdt, LONG_GDT_ADDR},
int::enable_interrupts,
paging::{
get_memory_mapper, init_global_mapper,
Expand Down Expand Up @@ -93,7 +93,7 @@ unsafe fn mem_init(mb_information: &mb_information::MultibootInformation) {
.as_mut_ptr(),
);

long_init_gdt(
kernel_init_gdt(
PhysicalMemoryMapping::KERNEL_DEFAULT_MAPPING.convert(PhyAddr::new(LONG_GDT_ADDR)),
);

Expand Down
2 changes: 1 addition & 1 deletion src/mem/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ impl TryFrom<Alignment> for u64 {
}
}

#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)]
pub struct VirtAddr(u64);

impl VirtAddr {
Expand Down
Loading
Loading