Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
hawkw committed Nov 29, 2022
1 parent f1c1b03 commit dcd6c7c
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 88 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions hal-x86_64/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ hal-core = { path = "../hal-core" }
mycelium-util = { path = "../util" }
mycelium-trace = { path = "../trace" }
mycotest = { path = "../mycotest"}
pin-project = "1"
rand_core = { version = "0.6.4", default_features = false, optional = true }
raw-cpuid = "10.6.0"
tracing = { git = "https://github.com/tokio-rs/tracing", default_features = false, features = ["attributes"] }
Expand Down
2 changes: 2 additions & 0 deletions hal-x86_64/src/cpu/local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use mycelium_util::{fmt, sync::Lazy};

#[repr(C)]
#[derive(Debug)]
#[pin_project]
pub struct GsLocalData {
/// This *must* be the first field of the local data struct, because we read
/// from `gs:0x0` to get the local data's address.
Expand All @@ -19,6 +20,7 @@ pub struct GsLocalData {
processor: Processor,
/// Because this struct is self-referential, it may not be `Unpin`.
_must_pin: PhantomPinned,

/// Arbitrary user data.
///
// TODO(eliza): consider storing this in some kind of heap allocated tree
Expand Down
1 change: 1 addition & 0 deletions src/arch/x86_64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ mod framebuf;
pub mod interrupt;
mod oops;
pub mod pci;
mod segment;
pub use self::{
boot::ArchInfo,
oops::{oops, Oops},
Expand Down
90 changes: 2 additions & 88 deletions src/arch/x86_64/interrupt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,13 @@ use super::{oops, Oops};
use core::sync::atomic::{AtomicUsize, Ordering};
use hal_core::{interrupt, VAddr};
pub use hal_x86_64::interrupt::*;
use hal_x86_64::{
cpu::Ring,
segment::{self, Gdt},
task,
};
use hal_x86_64::{cpu::Ring, task};
use maitake::time;
use mycelium_util::{fmt, sync};

#[tracing::instrument]
pub fn enable_exceptions() {
init_gdt();
segmentation::init_gdt();
tracing::info!("GDT initialized!");

Controller::init::<InterruptHandlers>();
Expand All @@ -30,32 +26,6 @@ pub fn enable_hardware_interrupts(acpi: Option<&acpi::InterruptModel>) {
tracing::info!(granularity = ?TIMER_INTERVAL, "global timer initialized")
}

// TODO(eliza): put this somewhere good.
type StackFrame = [u8; 4096];

// chosen by fair dice roll, guaranteed to be random
const DOUBLE_FAULT_STACK_SIZE: usize = 8;

/// Stack used by ISRs during a double fault.
///
/// /!\ EXTREMELY SERIOUS WARNING: this has to be `static mut` or else it
/// will go in `.bss` and we'll all die or something.
static mut DOUBLE_FAULT_STACK: [StackFrame; DOUBLE_FAULT_STACK_SIZE] =
[[0; 4096]; DOUBLE_FAULT_STACK_SIZE];

static TSS: sync::Lazy<task::StateSegment> = sync::Lazy::new(|| {
tracing::trace!("initializing TSS..");
let mut tss = task::StateSegment::empty();
tss.interrupt_stacks[Idt::DOUBLE_FAULT_IST_OFFSET] = unsafe {
// safety: asdf
VAddr::of(&DOUBLE_FAULT_STACK).offset(DOUBLE_FAULT_STACK_SIZE as i32)
};
tracing::debug!(?tss, "TSS initialized");
tss
});

static GDT: sync::InitOnce<Gdt> = sync::InitOnce::uninitialized();

const TIMER_INTERVAL: time::Duration = time::Duration::from_millis(10);
pub(super) static TIMER: time::Timer = time::Timer::new(TIMER_INTERVAL);

Expand Down Expand Up @@ -112,62 +82,6 @@ impl hal_core::interrupt::Handlers<Registers> for InterruptHandlers {
}
}

#[inline]
#[tracing::instrument(level = tracing::Level::DEBUG)]
pub(super) fn init_gdt() {
tracing::trace!("initializing GDT...");
let mut gdt = Gdt::new();

// add one kernel code segment
let code_segment = segment::Descriptor::code().with_ring(Ring::Ring0);
let code_selector = gdt.add_segment(code_segment);
tracing::debug!(
descriptor = fmt::alt(code_segment),
selector = fmt::alt(code_selector),
"added code segment"
);

// add the TSS.

let tss = segment::SystemDescriptor::tss(&TSS);
let tss_selector = gdt.add_sys_segment(tss);
tracing::debug!(
tss.descriptor = fmt::alt(tss),
tss.selector = fmt::alt(tss_selector),
"added TSS"
);

// all done! long mode barely uses this thing lol.
GDT.init(gdt);

// load the GDT
let gdt = GDT.get();
tracing::debug!(GDT = ?gdt, "GDT initialized");
gdt.load();

tracing::trace!("GDT loaded");

// set new segment selectors
let code_selector = segment::Selector::current_cs();
tracing::trace!(code_selector = fmt::alt(code_selector));
unsafe {
// set the code segment selector
code_selector.set_cs();

// in protected mode and long mode, the code segment, stack segment,
// data segment, and extra segment must all have base address 0 and
// limit `2^64`, since actual segmentation is not used in those modes.
// therefore, we must zero the SS, DS, and ES registers.
segment::Selector::null().set_ss();
segment::Selector::null().set_ds();
segment::Selector::null().set_es();

task::StateSegment::load_tss(tss_selector);
}

tracing::debug!("segment selectors set");
}

mycotest::decl_test! {
fn interrupts_work() -> mycotest::TestResult {
let test_interrupt_fires = TEST_INTERRUPT_WAS_FIRED.load(Ordering::Acquire);
Expand Down
59 changes: 59 additions & 0 deletions src/arch/x86_64/segmentation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use hal_x86_64::segment::{self, Gdt};
use mycelium_util::spin::Mutex;

pub(super) static GDT: Mutex<Gdt<8>> = Mutex::new(Gdt::new());

#[tracing::instrument(level = tracing::Level::DEBUG)]
pub(super) fn init_gdt() {
tracing::trace!("initializing GDT...");
let mut gdt = GDT.lock();

// add one kernel code segment
let code_segment = segment::Descriptor::code().with_ring(Ring::Ring0);
let code_selector = gdt.add_segment(code_segment);
tracing::debug!(
descriptor = fmt::alt(code_segment),
selector = fmt::alt(code_selector),
"added code segment"
);

// add the TSS.

let tss = segment::SystemDescriptor::tss(&TSS);
let tss_selector = gdt.add_sys_segment(tss);
tracing::debug!(
tss.descriptor = fmt::alt(tss),
tss.selector = fmt::alt(tss_selector),
"added TSS"
);

// all done! long mode barely uses this thing lol.
GDT.init(gdt);

// load the GDT
let gdt = GDT.get();
tracing::debug!(GDT = ?gdt, "GDT initialized");
gdt.load();

tracing::trace!("GDT loaded");

// set new segment selectors
let code_selector = segment::Selector::current_cs();
tracing::trace!(code_selector = fmt::alt(code_selector));
unsafe {
// set the code segment selector
code_selector.set_cs();

// in protected mode and long mode, the code segment, stack segment,
// data segment, and extra segment must all have base address 0 and
// limit `2^64`, since actual segmentation is not used in those modes.
// therefore, we must zero the SS, DS, and ES registers.
segment::Selector::null().set_ss();
segment::Selector::null().set_ds();
segment::Selector::null().set_es();

task::StateSegment::load_tss(tss_selector);
}

tracing::debug!("segment selectors set");
}

0 comments on commit dcd6c7c

Please sign in to comment.