Skip to content

Commit

Permalink
x86_64+examples: add fs/gs save/restore and kernel interface
Browse files Browse the repository at this point in the history
  • Loading branch information
Qix- committed Feb 8, 2025
1 parent 24868af commit 9b158bc
Show file tree
Hide file tree
Showing 15 changed files with 282 additions and 5 deletions.
4 changes: 2 additions & 2 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ oro-ra-x86_64 = "check --quiet --message-format=json --keep-going --target ./oro
oro-ra-aarch64 = "check --quiet --message-format=json --keep-going --target ./oro-arch-aarch64/aarch64-unknown-oro.json --bin oro-kernel-aarch64 --bin oro-limine-aarch64 -Zunstable-options -Zbuild-std=core,compiler_builtins,alloc -Zbuild-std-features=compiler-builtins-mem"

# NOTE: Does not need the unstable flags / building std / etc.
oro-examples = "build --target=x86_64-unknown-none --target=aarch64-unknown-none -p example-noop -p example-spin -p example-std-noop -p example-std-noop-nightly -p example-std-spin -p example-hello-world -p example-root-vbuf-demo -p example-page-alloc"
oro-examples = "build --target=x86_64-unknown-none --target=aarch64-unknown-none -p example-noop -p example-spin -p example-std-noop -p example-std-noop-nightly -p example-std-spin -p example-hello-world -p example-root-vbuf-demo -p example-page-alloc -p example-x86_64-tls-base"

# NOTE(qix-): Temporary.
test-ports = "build --target=x86_64-unknown-none -p example-test-ports"
test-ports = "build --target=x86_64-unknown-none -p example-test-ports"
7 changes: 7 additions & 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 Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ members = [
"examples/no-std/root-vbuf-demo",
"examples/no-std/page-alloc",
"examples/no-std/test-ports", # NOTE(qix-): temporary
"examples/no-std/x86_64-tls-base",
"examples/std/noop",
"examples/std/noop-nightly",
"examples/std/spin",
Expand Down
17 changes: 17 additions & 0 deletions examples/no-std/x86_64-tls-base/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "example-x86_64-tls-base"
description = "x86_64 TLS base (FS/GS) interface example"
version = "0.0.0"
publish = false
edition = "2021"

build = "build.rs"

[dependencies.oro]
path = "../../../oro"
features = ["module", "panic_debug_out_v0"]

[build-dependencies.oro]
path = "../../../oro"
features = ["build"]
default-features = false
3 changes: 3 additions & 0 deletions examples/no-std/x86_64-tls-base/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
::oro::build();
}
70 changes: 70 additions & 0 deletions examples/no-std/x86_64-tls-base/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#![no_std]
#![no_main]

use oro::debug_out_v0_println as println;

#[cfg(not(target_arch = "x86_64"))]
#[no_mangle]
fn main() {
println!("This example only works on x86_64");
}

#[cfg(target_arch = "x86_64")]
#[no_mangle]
fn main() {
use core::arch::asm;

use oro::{id::iface::KERNEL_X86_64_TLS_BASE_V0, key, syscall_get, syscall_set};

static THE_ANSWER: u64 = 42;

println!("local answer: {THE_ANSWER}");

let fsbase_name: u64 = syscall_get!(
KERNEL_X86_64_TLS_BASE_V0,
KERNEL_X86_64_TLS_BASE_V0,
0,
key!("name"),
)
.expect("failed to get FS base name");

println!("fsbase name: {:?}", oro::Key(&fsbase_name));

let fsbase = syscall_get!(
KERNEL_X86_64_TLS_BASE_V0,
KERNEL_X86_64_TLS_BASE_V0,
0,
key!("base"),
)
.expect("failed to get initial FS base");

println!("initial FS base: {fsbase:#016x}");

syscall_set!(
KERNEL_X86_64_TLS_BASE_V0,
KERNEL_X86_64_TLS_BASE_V0,
0,
key!("base"),
&THE_ANSWER as *const _ as u64
)
.expect("failed to set FS base");

println!("set FS base to: {:#016x}", &THE_ANSWER as *const _ as u64);

let fsbase = syscall_get!(
KERNEL_X86_64_TLS_BASE_V0,
KERNEL_X86_64_TLS_BASE_V0,
0,
key!("base"),
)
.expect("failed to get final FS base");

println!("final FS base: {fsbase:#016x}");

let answer: u64;
unsafe {
asm!("mov rax, fs:[0]", out("rax") answer);
}

println!("read FS base: {answer}");
}
26 changes: 26 additions & 0 deletions oro-arch-x86_64/src/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,3 +209,29 @@ pub fn rflags() -> u64 {
}
rflags
}

/// Sets the FS base pointer MSR to the given `value`.
#[inline(always)]
pub fn set_fs_msr(value: u64) {
wrmsr(0xC000_0100, value);
}

/// Sets the GS base pointer MSR to the given `value`.
#[inline(always)]
pub fn set_gs_msr(value: u64) {
wrmsr(0xC000_0101, value);
}

/// Gets the FS base pointer MSR.
#[inline(always)]
#[must_use]
pub fn get_fs_msr() -> u64 {
rdmsr(0xC000_0100)
}

/// Gets the GS base pointer MSR.
#[inline(always)]
#[must_use]
pub fn get_gs_msr() -> u64 {
rdmsr(0xC000_0101)
}
22 changes: 22 additions & 0 deletions oro-arch-x86_64/src/iface/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//! x86_64-specific kernel interfaces.
use oro_kernel::{iface::kernel::KernelInterface, table::Table};
use oro_mem::alloc::boxed::Box;

/// Registers the x86_64-specific kernel interfaces.
pub(crate) fn register_kernel_interfaces(table: &mut Table<Box<dyn KernelInterface<crate::Arch>>>) {
macro_rules! register_all {
($($id:ident => $iface_mod:literal $iface:ident),* $(,)?) => {
$({
#[path = $iface_mod]
mod ifacemod;

table.insert(::oro::id::iface::$id, Box::new(ifacemod::$iface));
})*
};
}

register_all! {
KERNEL_X86_64_TLS_BASE_V0 => "tls_base_v0.rs" TlsBaseV0,
}
}
74 changes: 74 additions & 0 deletions oro-arch-x86_64/src/iface/tls_base_v0.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
//! x86_64 TLS base pointer (FS/GS) interface.
//! Kernel interface for querying the ring's interfaces
//! based on the interface type.
use crate::Arch as A;
use oro::{key, syscall::Error as SysError};
use oro_kernel::{syscall::InterfaceResponse, tab::Tab, thread::Thread, iface::kernel::KernelInterface};

/// Version 0 of TLS base (FS/GS) kernel interface for x86_64.
#[repr(transparent)]
pub struct TlsBaseV0;

impl KernelInterface<A> for TlsBaseV0 {
fn get(&self, thread: &Tab<Thread<A>>, index: u64, key: u64) -> InterfaceResponse {
match key {
key!("name") => {
match index {
0 => InterfaceResponse::ok(key!("fs")),
1 => InterfaceResponse::ok(key!("gs")),
_ => InterfaceResponse::immediate(SysError::BadIndex, 0),
}
},
key!("base") => {
match index {
0 => {
debug_assert_eq!(crate::asm::get_fs_msr(), thread.with(|ctx| ctx.handle().fsbase));
InterfaceResponse::ok(crate::asm::get_fs_msr())
}
1 => {
debug_assert_eq!(crate::asm::get_gs_msr(), thread.with(|ctx| ctx.handle().gsbase));
InterfaceResponse::ok(crate::asm::get_gs_msr())
}
_ => InterfaceResponse::immediate(SysError::BadIndex, 0),
}
},
_ => InterfaceResponse::immediate(SysError::BadKey, 0),
}
}

fn set(
&self,
thread: &Tab<Thread<A>>,
index: u64,
key: u64,
value: u64,
) -> InterfaceResponse {
match key {
key!("name") => InterfaceResponse::immediate(SysError::ReadOnly, 0),
key!("base") => {
match index {
0 => {
// Set the FS base pointer. Will get picked up by the
// next context switch.
thread.with_mut(|ctx| {
ctx.handle_mut().fsbase = value;
});
},
1 => {
// Set the GS base pointer. Will get picked up by the
// next context switch.
thread.with_mut(|ctx| {
ctx.handle_mut().gsbase = value;
});
},
_ => return InterfaceResponse::immediate(SysError::BadIndex, 0),
}

InterfaceResponse::ok(0)
}
_ => InterfaceResponse::immediate(SysError::BadKey, 0),
}
}
}
8 changes: 8 additions & 0 deletions oro-arch-x86_64/src/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,10 @@ pub unsafe fn boot() -> ! {
(*kernel.handle().tss.get())
.rsp0
.write(AddressSpaceLayout::interrupt_stack().range().1 as u64 & !0xFFF);

crate::asm::set_fs_msr(ctx_lock.handle().fsbase);
crate::asm::set_gs_msr(ctx_lock.handle().gsbase);

(cr3, rsp, kernel_rsp_ptr, kernel_irq_rsp_ptr)
})
};
Expand All @@ -330,6 +334,10 @@ pub unsafe fn boot() -> ! {
(*kernel.handle().tss.get())
.rsp0
.write(AddressSpaceLayout::interrupt_stack().range().1 as u64 & !0xFFF);

crate::asm::set_fs_msr(ctx_lock.handle().fsbase);
crate::asm::set_gs_msr(ctx_lock.handle().gsbase);

(cr3, rsp, kernel_rsp_ptr, kernel_irq_rsp_ptr)
})
};
Expand Down
15 changes: 14 additions & 1 deletion oro-arch-x86_64/src/interrupt/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,12 @@ macro_rules! isr {
// If this is `None`, then the kernel is currently running.
// Otherwise it's a userspace task that we just jumped from.
if let Some(user_task) = scheduler_lock.current_thread().as_ref() {
user_task.with_mut(|t| t.handle_mut().irq_stack_ptr = irq_stack_ptr as usize);
user_task.with_mut(|t| {
let handle = t.handle_mut();
handle.irq_stack_ptr = irq_stack_ptr as usize;
handle.fsbase = $crate::asm::get_fs_msr();
handle.gsbase = $crate::asm::get_gs_msr();
});
drop(scheduler_lock);
Some(user_task.clone())
} else {
Expand Down Expand Up @@ -213,6 +218,10 @@ macro_rules! isr {
(*$kernel.handle().tss.get())
.rsp0
.write($crate::mem::address_space::AddressSpaceLayout::interrupt_stack().range().1 as u64 & !0xFFF);

$crate::asm::set_fs_msr(ctx_lock.handle().fsbase);
$crate::asm::set_gs_msr(ctx_lock.handle().gsbase);

(cr3, rsp)
})
};
Expand Down Expand Up @@ -240,6 +249,10 @@ macro_rules! isr {
(*$kernel.handle().tss.get())
.rsp0
.write($crate::mem::address_space::AddressSpaceLayout::interrupt_stack().range().1 as u64 & !0xFFF);

$crate::asm::set_fs_msr(ctx_lock.handle().fsbase);
$crate::asm::set_gs_msr(ctx_lock.handle().gsbase);

(cr3, rsp)
})
};
Expand Down
10 changes: 10 additions & 0 deletions oro-arch-x86_64/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,17 @@
// SAFETY(qix-): https://github.com/rust-lang/rust/issues/76560
#![expect(incomplete_features)]
#![feature(generic_const_exprs)]
// SAFETY(qix-): Needed to make the system call key checks work inline.
// SAFETY(qix-): https://github.com/rust-lang/rust/issues/76001
#![feature(inline_const_pat)]
#![cfg_attr(doc, feature(doc_cfg, doc_auto_cfg))]

pub mod asm;
pub mod boot;
pub mod core_local;
pub mod cpuid;
pub mod gdt;
pub mod iface;
pub mod instance;
pub mod interrupt;
pub mod lapic;
Expand All @@ -81,6 +85,8 @@ pub mod tss;
pub(crate) mod init;

use oro_elf::{ElfClass, ElfEndianness, ElfMachine};
use oro_kernel::{iface::kernel::KernelInterface, table::Table};
use oro_mem::alloc::boxed::Box;

/// The ELF class of the x86_64 architecture.
pub const ELF_CLASS: ElfClass = ElfClass::Class64;
Expand All @@ -103,6 +109,10 @@ impl oro_kernel::arch::Arch for Arch {
// NOTE(qix-): This might be too strong for what we need.
asm::strong_memory_barrier();
}

fn register_kernel_interfaces(table: &mut Table<Box<dyn KernelInterface<Self>>>) {
iface::register_kernel_interfaces(table);
}
}

/// Type alias for the Oro kernel core-local instance type.
Expand Down
15 changes: 14 additions & 1 deletion oro-arch-x86_64/src/syscall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,12 @@ unsafe extern "C" fn syscall_enter_noncompat_rust() -> ! {
unreachable!();
};

current_thread.with_mut(|t| t.handle_mut().irq_stack_ptr = stack_ptr);
current_thread.with_mut(|t| {
let handle = t.handle_mut();
handle.irq_stack_ptr = stack_ptr;
handle.fsbase = crate::asm::get_fs_msr();
handle.gsbase = crate::asm::get_gs_msr();
});

let switch = scheduler.event_system_call(&syscall_request);

Expand All @@ -149,6 +154,10 @@ unsafe extern "C" fn syscall_enter_noncompat_rust() -> ! {
(*kernel.handle().tss.get())
.rsp0
.write(AddressSpaceLayout::interrupt_stack().range().1 as u64 & !0xFFF);

crate::asm::set_fs_msr(ctx_lock.handle().fsbase);
crate::asm::set_gs_msr(ctx_lock.handle().gsbase);

(cr3, rsp)
})
};
Expand All @@ -172,6 +181,10 @@ unsafe extern "C" fn syscall_enter_noncompat_rust() -> ! {
(*kernel.handle().tss.get())
.rsp0
.write(AddressSpaceLayout::interrupt_stack().range().1 as u64 & !0xFFF);

crate::asm::set_fs_msr(ctx_lock.handle().fsbase);
crate::asm::set_gs_msr(ctx_lock.handle().gsbase);

(cr3, rsp)
})
};
Expand Down
Loading

0 comments on commit 9b158bc

Please sign in to comment.