2024-02-05 13:44:21 +02:00
|
|
|
#![no_std]
|
2024-02-06 12:27:02 +02:00
|
|
|
#![feature(effects, strict_provenance)]
|
2024-02-05 13:44:21 +02:00
|
|
|
|
2024-02-08 15:50:25 +02:00
|
|
|
extern crate alloc;
|
|
|
|
|
|
|
|
use alloc::vec::Vec;
|
|
|
|
use device_api::interrupt::{LocalInterruptController, MessageInterruptController};
|
|
|
|
use kernel_arch_interface::{cpu::IpiQueue, util::OneTimeInit, Architecture};
|
|
|
|
use libk_mm_interface::address::PhysicalAddress;
|
|
|
|
use registers::MSR_IA32_KERNEL_GS_BASE;
|
|
|
|
use tock_registers::interfaces::Writeable;
|
2024-02-05 13:44:21 +02:00
|
|
|
|
2024-02-06 12:27:02 +02:00
|
|
|
pub mod mem;
|
|
|
|
pub mod registers;
|
|
|
|
|
2024-02-06 16:38:39 +02:00
|
|
|
pub use mem::{process::ProcessAddressSpaceImpl, KernelTableManagerImpl};
|
2024-02-06 12:27:02 +02:00
|
|
|
|
2024-02-05 13:44:21 +02:00
|
|
|
pub struct ArchitectureImpl;
|
|
|
|
|
2024-02-06 12:27:02 +02:00
|
|
|
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,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PerCpuData {
|
|
|
|
pub fn local_apic(&self) -> &'static dyn LocalApicInterface {
|
|
|
|
self.local_apic
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static IPI_QUEUES: OneTimeInit<Vec<IpiQueue<ArchitectureImpl>>> = OneTimeInit::new();
|
|
|
|
|
|
|
|
impl ArchitectureImpl {
|
|
|
|
fn local_cpu_data() -> Option<&'static mut PerCpuData> {
|
|
|
|
unsafe { (Self::local_cpu() as *mut PerCpuData).as_mut() }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-05 13:44:21 +02:00
|
|
|
impl Architecture for ArchitectureImpl {
|
2024-02-08 15:50:25 +02:00
|
|
|
type PerCpuData = PerCpuData;
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2024-02-05 13:44:21 +02:00
|
|
|
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
|
|
|
|
|
|
|
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-02-05 13:44:21 +02:00
|
|
|
}
|