186 lines
4.7 KiB
Rust
Raw Normal View History

#![no_std]
2024-03-13 01:54:00 +02:00
#![allow(clippy::new_without_default)]
2024-07-25 11:58:47 +03:00
#![feature(strict_provenance, asm_const, naked_functions, trait_upcasting)]
2024-02-08 15:50:25 +02:00
extern crate alloc;
use core::{
ops::DerefMut,
sync::atomic::{AtomicUsize, Ordering},
};
2024-02-08 15:50:25 +02:00
use alloc::vec::Vec;
use device_api::interrupt::{LocalInterruptController, MessageInterruptController};
use kernel_arch_interface::{
cpu::{CpuImpl, IpiQueue},
task::Scheduler,
util::OneTimeInit,
Architecture,
};
2024-10-12 20:43:16 +03:00
use kernel_arch_x86::{cpuid::CpuFeatures, registers::MSR_IA32_KERNEL_GS_BASE};
2024-02-08 15:50:25 +02:00
use libk_mm_interface::address::PhysicalAddress;
use tock_registers::interfaces::Writeable;
pub mod context;
pub mod mem;
pub use context::TaskContextImpl;
pub use mem::{process::ProcessAddressSpaceImpl, KernelTableManagerImpl};
pub struct ArchitectureImpl;
pub const KERNEL_VIRT_OFFSET: usize = 0xFFFFFF8000000000;
2024-02-08 15:50:25 +02:00
pub trait LocalApicInterface: LocalInterruptController + MessageInterruptController {
/// Performs an application processor startup sequence.
///
/// # Safety
///
/// Unsafe: only meant to be called by the BSP during SMP init.
unsafe fn wakeup_cpu(&self, apic_id: u32, bootstrap_code: PhysicalAddress);
/// Signals local APIC that we've handled the IRQ
fn clear_interrupt(&self);
}
#[repr(C, align(0x10))]
pub struct PerCpuData {
// 0x00
pub this: *mut Self,
// 0x08, used in assembly
pub tss_address: usize,
// 0x10, used in assembly
pub tmp_address: usize,
pub local_apic: &'static dyn LocalApicInterface,
2024-10-12 20:43:16 +03:00
pub available_features: CpuFeatures,
pub enabled_features: CpuFeatures,
2024-02-08 15:50:25 +02:00
}
impl PerCpuData {
pub fn local_apic(&self) -> &'static dyn LocalApicInterface {
self.local_apic
}
}
static IPI_QUEUES: OneTimeInit<Vec<IpiQueue<ArchitectureImpl>>> = OneTimeInit::new();
pub static CPU_COUNT: AtomicUsize = AtomicUsize::new(1);
2024-02-08 15:50:25 +02:00
#[naked]
extern "C" fn idle_task(_: usize) -> ! {
unsafe {
core::arch::asm!(
r#"
1:
nop
jmp 1b
"#,
options(noreturn, att_syntax)
);
}
}
2024-02-08 15:50:25 +02:00
impl ArchitectureImpl {
fn local_cpu_data() -> Option<&'static mut PerCpuData> {
unsafe { (Self::local_cpu() as *mut PerCpuData).as_mut() }
}
}
impl Architecture for ArchitectureImpl {
2024-02-08 15:50:25 +02:00
type PerCpuData = PerCpuData;
2024-10-12 20:43:16 +03:00
type CpuFeatures = CpuFeatures;
2024-02-08 15:50:25 +02:00
unsafe fn set_local_cpu(cpu: *mut ()) {
MSR_IA32_KERNEL_GS_BASE.set(cpu as u64);
core::arch::asm!("wbinvd; swapgs");
}
fn local_cpu() -> *mut () {
let mut addr: u64;
unsafe {
core::arch::asm!("movq %gs:(0), {0}", out(reg) addr, options(att_syntax));
}
addr as _
}
unsafe fn init_ipi_queues(queues: Vec<IpiQueue<Self>>) {
IPI_QUEUES.init(queues);
}
unsafe fn init_local_cpu<S: Scheduler + 'static>(id: Option<u32>, data: Self::PerCpuData) {
use alloc::boxed::Box;
let cpu = Box::leak(Box::new(CpuImpl::<Self, S>::new(
id.expect("x86_64 required manual CPU ID set"),
data,
)));
cpu.this = cpu.deref_mut();
cpu.set_local();
}
fn idle_task() -> extern "C" fn(usize) -> ! {
idle_task
}
fn cpu_count() -> usize {
CPU_COUNT.load(Ordering::Acquire)
}
2024-02-26 23:04:51 +02:00
fn cpu_index<S: Scheduler + 'static>() -> u32 {
CpuImpl::<Self, S>::local().id()
}
fn interrupt_mask() -> bool {
let mut flags: u64;
unsafe {
core::arch::asm!("pushfq; pop {0}", out(reg) flags, options(att_syntax));
}
// If IF is zero, interrupts are disabled (masked)
flags & (1 << 9) == 0
}
unsafe fn set_interrupt_mask(mask: bool) -> bool {
let old = Self::interrupt_mask();
if mask {
core::arch::asm!("cli");
} else {
core::arch::asm!("sti");
}
old
}
#[inline]
fn wait_for_interrupt() {
unsafe {
core::arch::asm!("hlt");
}
}
2024-02-08 15:50:25 +02:00
2024-10-11 15:44:14 +03:00
fn halt() -> ! {
loop {
unsafe {
core::arch::asm!("cli; hlt");
}
}
}
2024-02-08 15:50:25 +02:00
fn local_interrupt_controller() -> &'static dyn LocalInterruptController {
let local = Self::local_cpu_data().unwrap();
local.local_apic
}
fn message_interrupt_controller() -> &'static dyn MessageInterruptController {
let local = Self::local_cpu_data().unwrap();
local.local_apic
}
2024-10-12 20:43:16 +03:00
fn cpu_enabled_features<S: Scheduler>(cpu: &CpuImpl<Self, S>) -> Option<&Self::CpuFeatures> {
Some(&cpu.enabled_features)
}
fn cpu_available_features<S: Scheduler>(cpu: &CpuImpl<Self, S>) -> Option<&Self::CpuFeatures> {
Some(&cpu.available_features)
}
}