2023-08-01 11:09:56 +03:00
|
|
|
//! x86-64 architecture and platform implementation
|
2023-08-05 16:32:12 +03:00
|
|
|
use core::{ptr::NonNull, sync::atomic::Ordering};
|
2023-08-01 11:09:56 +03:00
|
|
|
|
2023-07-29 19:31:56 +03:00
|
|
|
use abi::error::Error;
|
2023-08-31 13:40:17 +03:00
|
|
|
use acpi_lib::{AcpiHandler, AcpiTables, HpetInfo, InterruptModel, PhysicalMapping};
|
2023-08-21 17:26:44 +03:00
|
|
|
use alloc::boxed::Box;
|
2023-08-05 16:32:12 +03:00
|
|
|
use cpu::Cpu;
|
2023-08-21 17:26:44 +03:00
|
|
|
use device_api::{
|
|
|
|
input::KeyboardProducer,
|
|
|
|
interrupt::{ExternalInterruptController, IpiDeliveryTarget, LocalInterruptController},
|
|
|
|
timer::MonotonicTimestampProviderDevice,
|
|
|
|
Device,
|
|
|
|
};
|
2023-08-05 16:32:12 +03:00
|
|
|
use git_version::git_version;
|
2023-08-21 17:26:44 +03:00
|
|
|
use kernel_util::util::OneTimeInit;
|
|
|
|
use yboot_proto::{AvailableRegion, IterableMemoryMap};
|
2023-07-28 14:26:39 +03:00
|
|
|
|
2023-07-29 21:11:15 +03:00
|
|
|
use crate::{
|
2023-08-05 16:32:12 +03:00
|
|
|
arch::x86_64::{
|
|
|
|
apic::local::LocalApic,
|
2023-08-21 17:26:44 +03:00
|
|
|
peripherals::serial::ComPort,
|
2023-08-05 16:32:12 +03:00
|
|
|
table::{init_fixed_tables, KERNEL_TABLES},
|
|
|
|
},
|
2023-08-07 09:53:47 +03:00
|
|
|
debug::{self, LogLevel},
|
2023-07-29 21:11:15 +03:00
|
|
|
device::{
|
2023-08-21 17:26:44 +03:00
|
|
|
self,
|
2023-08-22 10:00:56 +03:00
|
|
|
display::{console, fb_console::FramebufferConsole, linear_fb::LinearFramebuffer},
|
2023-08-21 17:26:44 +03:00
|
|
|
tty::combined::CombinedTerminal,
|
2023-08-01 11:09:56 +03:00
|
|
|
},
|
2023-08-02 19:53:54 +03:00
|
|
|
fs::{
|
|
|
|
devfs::{self, CharDeviceType},
|
2023-08-05 16:32:12 +03:00
|
|
|
Initrd, INITRD_DATA,
|
2023-08-02 19:53:54 +03:00
|
|
|
},
|
2023-08-01 11:09:56 +03:00
|
|
|
mem::{
|
2023-08-21 17:26:44 +03:00
|
|
|
phys::{self, reserved::reserve_region, PhysicalMemoryRegion},
|
2023-08-01 11:09:56 +03:00
|
|
|
ConvertAddress,
|
2023-07-29 21:11:15 +03:00
|
|
|
},
|
2023-08-31 13:40:17 +03:00
|
|
|
panic,
|
|
|
|
sync::SpinFence,
|
2023-08-21 17:26:44 +03:00
|
|
|
CPU_INIT_FENCE,
|
2023-07-29 21:11:15 +03:00
|
|
|
};
|
2023-07-28 14:26:39 +03:00
|
|
|
|
2023-08-01 11:09:56 +03:00
|
|
|
use self::{
|
2023-08-31 13:40:17 +03:00
|
|
|
acpi::{AcpiAllocator, AcpiHandlerImpl},
|
2023-08-21 17:26:44 +03:00
|
|
|
apic::ioapic::IoApic,
|
2023-08-31 09:21:24 +03:00
|
|
|
intrinsics::{IoPort, IoPortAccess},
|
2023-08-21 17:26:44 +03:00
|
|
|
peripherals::{hpet::Hpet, ps2::PS2Controller},
|
2023-08-05 16:32:12 +03:00
|
|
|
smp::CPU_COUNT,
|
2023-08-01 11:09:56 +03:00
|
|
|
};
|
|
|
|
|
2023-08-05 16:32:12 +03:00
|
|
|
use super::{Architecture, CpuMessage};
|
2023-07-28 14:26:39 +03:00
|
|
|
|
2023-07-30 16:40:30 +03:00
|
|
|
#[macro_use]
|
|
|
|
pub mod intrinsics;
|
|
|
|
|
2023-08-31 13:40:17 +03:00
|
|
|
pub mod acpi;
|
2023-08-01 11:09:56 +03:00
|
|
|
pub mod apic;
|
2023-07-29 19:31:56 +03:00
|
|
|
pub mod boot;
|
2023-08-01 18:05:10 +03:00
|
|
|
pub mod context;
|
2023-08-01 11:09:56 +03:00
|
|
|
pub mod cpu;
|
2023-08-01 18:05:10 +03:00
|
|
|
pub mod cpuid;
|
2023-07-30 16:40:30 +03:00
|
|
|
pub mod exception;
|
|
|
|
pub mod gdt;
|
2023-08-01 11:09:56 +03:00
|
|
|
pub mod peripherals;
|
|
|
|
pub mod registers;
|
2023-08-05 16:32:12 +03:00
|
|
|
pub mod smp;
|
2023-08-02 19:53:54 +03:00
|
|
|
pub mod syscall;
|
2023-07-29 19:31:56 +03:00
|
|
|
pub mod table;
|
2023-07-28 14:26:39 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
/// x86-64 interrupt number wrapper
|
|
|
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
|
|
|
pub enum IrqNumber {
|
|
|
|
/// Legacy (ISA) interrupt. Can have value in range 0..16.
|
|
|
|
Isa(u8),
|
|
|
|
/// Global system interrupt. Means an external interrupt for I/O APIC.
|
|
|
|
Gsi(u8),
|
|
|
|
}
|
2023-08-05 16:32:12 +03:00
|
|
|
|
2023-08-01 11:09:56 +03:00
|
|
|
/// Helper trait to provide abstract access to available memory regions
|
2023-07-30 16:40:30 +03:00
|
|
|
pub trait AbstractAvailableRegion {
|
2023-08-01 11:09:56 +03:00
|
|
|
/// Returns page-aligned physical start address of the region
|
2023-07-30 16:40:30 +03:00
|
|
|
fn start_address(&self) -> usize;
|
2023-08-01 11:09:56 +03:00
|
|
|
/// Returns the page count (rounded down) of this region
|
2023-07-30 16:40:30 +03:00
|
|
|
fn page_count(&self) -> usize;
|
|
|
|
}
|
|
|
|
|
2023-08-01 11:09:56 +03:00
|
|
|
/// Helper trait to provide abstract access to memory maps
|
2023-07-30 16:40:30 +03:00
|
|
|
pub trait AbstractMemoryMap<'a>: 'a {
|
2023-08-01 11:09:56 +03:00
|
|
|
/// Available memory region type contained within this memory map
|
2023-07-30 16:40:30 +03:00
|
|
|
type AvailableRegion: AbstractAvailableRegion;
|
2023-08-01 11:09:56 +03:00
|
|
|
/// Iterator type returned by [Self::iter]
|
2023-07-30 16:40:30 +03:00
|
|
|
type Iter: Iterator<Item = &'a Self::AvailableRegion> + Clone;
|
|
|
|
|
2023-08-01 11:09:56 +03:00
|
|
|
/// Returns the physical memory range which contains this memory map
|
2023-07-30 16:40:30 +03:00
|
|
|
fn reserved_range(&self) -> PhysicalMemoryRegion;
|
2023-08-01 11:09:56 +03:00
|
|
|
/// Returns an iterator over the available memory regions
|
2023-07-30 16:40:30 +03:00
|
|
|
fn iter(&self) -> Self::Iter;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: AvailableRegion> AbstractAvailableRegion for T {
|
|
|
|
fn start_address(&self) -> usize {
|
|
|
|
<T as AvailableRegion>::start_address(self)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn page_count(&self) -> usize {
|
|
|
|
<T as AvailableRegion>::page_count(self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, T: IterableMemoryMap<'a> + 'a> AbstractMemoryMap<'a> for T {
|
|
|
|
type AvailableRegion = T::Entry;
|
|
|
|
type Iter = T::Iter;
|
|
|
|
|
|
|
|
fn reserved_range(&self) -> PhysicalMemoryRegion {
|
|
|
|
PhysicalMemoryRegion {
|
|
|
|
base: self.data_physical_base(),
|
|
|
|
size: (self.data_size() + 0xFFF) & !0xFFF,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn iter(&self) -> Self::Iter {
|
|
|
|
<T as IterableMemoryMap>::iter_with_offset(self, X86_64::KERNEL_VIRT_OFFSET)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
/// Describes which kind of bootloader data was provided to the kernel
|
|
|
|
pub enum BootData {
|
|
|
|
/// [yboot_proto::LoadProtocolV1]
|
|
|
|
YBoot(&'static yboot_proto::LoadProtocolV1),
|
|
|
|
}
|
|
|
|
|
2023-08-01 11:09:56 +03:00
|
|
|
/// x86-64 architecture + platform implementation
|
2023-07-29 21:11:15 +03:00
|
|
|
pub struct X86_64 {
|
2023-08-21 17:26:44 +03:00
|
|
|
boot_data: OneTimeInit<BootData>,
|
|
|
|
acpi: OneTimeInit<AcpiTables<AcpiHandlerImpl>>,
|
2023-08-01 11:09:56 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
framebuffer: OneTimeInit<LinearFramebuffer>,
|
|
|
|
fb_console: OneTimeInit<FramebufferConsole>,
|
2023-08-02 19:53:54 +03:00
|
|
|
combined_terminal: OneTimeInit<CombinedTerminal>,
|
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
ioapic: OneTimeInit<IoApic>,
|
|
|
|
timer: OneTimeInit<Hpet>,
|
2023-07-29 21:11:15 +03:00
|
|
|
}
|
2023-07-28 14:26:39 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
/// x86-64 architecture implementation
|
|
|
|
pub static ARCHITECTURE: X86_64 = X86_64 {
|
|
|
|
boot_data: OneTimeInit::new(),
|
|
|
|
acpi: OneTimeInit::new(),
|
|
|
|
|
|
|
|
framebuffer: OneTimeInit::new(),
|
|
|
|
fb_console: OneTimeInit::new(),
|
|
|
|
combined_terminal: OneTimeInit::new(),
|
|
|
|
|
|
|
|
// Devices
|
|
|
|
ioapic: OneTimeInit::new(),
|
|
|
|
timer: OneTimeInit::new(),
|
|
|
|
};
|
|
|
|
|
2023-08-31 13:40:17 +03:00
|
|
|
static SHUTDOWN_FENCE: SpinFence = SpinFence::new();
|
|
|
|
|
2023-07-29 19:31:56 +03:00
|
|
|
impl Architecture for X86_64 {
|
|
|
|
const KERNEL_VIRT_OFFSET: usize = 0xFFFFFF8000000000;
|
2023-07-28 14:26:39 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
type IrqNumber = IrqNumber;
|
|
|
|
|
2023-07-29 19:31:56 +03:00
|
|
|
unsafe fn init_mmu(&self, bsp: bool) {
|
|
|
|
if bsp {
|
|
|
|
init_fixed_tables();
|
|
|
|
}
|
2023-07-28 14:26:39 +03:00
|
|
|
|
2023-07-29 19:31:56 +03:00
|
|
|
let cr3 = KERNEL_TABLES.physical_address();
|
|
|
|
core::arch::asm!("wbinvd; mov {0}, %cr3", in(reg) cr3, options(att_syntax));
|
|
|
|
}
|
2023-07-28 14:26:39 +03:00
|
|
|
|
2023-07-29 19:31:56 +03:00
|
|
|
unsafe fn set_interrupt_mask(mask: bool) {
|
2023-07-29 21:11:15 +03:00
|
|
|
if mask {
|
|
|
|
core::arch::asm!("cli");
|
|
|
|
} else {
|
|
|
|
core::arch::asm!("sti");
|
|
|
|
}
|
2023-07-29 19:31:56 +03:00
|
|
|
}
|
2023-07-28 14:26:39 +03:00
|
|
|
|
2023-07-29 19:31:56 +03:00
|
|
|
fn interrupt_mask() -> bool {
|
2023-07-29 21:11:15 +03:00
|
|
|
let mut flags: u64;
|
|
|
|
unsafe {
|
2023-08-01 18:05:10 +03:00
|
|
|
core::arch::asm!("pushfq; pop {0}", out(reg) flags, options(att_syntax));
|
2023-07-29 21:11:15 +03:00
|
|
|
}
|
|
|
|
// If IF is zero, interrupts are disabled (masked)
|
|
|
|
flags & (1 << 9) == 0
|
|
|
|
}
|
2023-08-05 16:32:12 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
fn wait_for_interrupt() {
|
|
|
|
unsafe {
|
|
|
|
core::arch::asm!("hlt");
|
|
|
|
}
|
2023-08-05 16:32:12 +03:00
|
|
|
}
|
2023-07-30 16:40:30 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
// CPU management
|
|
|
|
unsafe fn reset(&self) -> ! {
|
|
|
|
todo!()
|
|
|
|
}
|
2023-08-01 11:09:56 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
unsafe fn send_ipi(&self, target: IpiDeliveryTarget, msg: CpuMessage) -> Result<(), Error> {
|
|
|
|
if !CPU_INIT_FENCE.try_wait_all(1) {
|
|
|
|
// Don't send an IPI: SMP not initialized yet
|
|
|
|
return Ok(());
|
|
|
|
}
|
2023-08-03 18:49:29 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
let Some(local_apic) = Cpu::get_local().map(|cpu| cpu.local_apic()) else {
|
|
|
|
panic!("Local APIC has not been initialized yet");
|
|
|
|
};
|
2023-08-01 11:09:56 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
local_apic.send_ipi(target, msg)
|
|
|
|
}
|
2023-08-05 16:32:12 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
unsafe fn start_application_processors(&self) {
|
|
|
|
if let Some(acpi) = self.acpi.try_get() {
|
2023-08-31 13:40:17 +03:00
|
|
|
let Some(pinfo) = acpi
|
|
|
|
.platform_info_in(AcpiAllocator)
|
|
|
|
.ok()
|
|
|
|
.and_then(|p| p.processor_info)
|
|
|
|
else {
|
2023-08-21 17:26:44 +03:00
|
|
|
return;
|
2023-08-01 11:09:56 +03:00
|
|
|
};
|
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
smp::start_ap_cores(&pinfo);
|
|
|
|
}
|
|
|
|
}
|
2023-08-01 11:09:56 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
fn cpu_count() -> usize {
|
|
|
|
CPU_COUNT.load(Ordering::Acquire)
|
|
|
|
}
|
2023-08-02 19:53:54 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
// Memory
|
|
|
|
fn map_device_pages(&self, phys: usize, count: usize) -> Result<usize, Error> {
|
|
|
|
unsafe { KERNEL_TABLES.map_device_pages(phys, count) }
|
|
|
|
}
|
2023-08-02 19:53:54 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
// Devices
|
|
|
|
fn register_monotonic_timer(
|
|
|
|
&self,
|
|
|
|
_timer: &'static dyn device_api::timer::MonotonicTimestampProviderDevice,
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
todo!()
|
|
|
|
}
|
2023-08-01 11:09:56 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
fn register_local_interrupt_controller(
|
|
|
|
&self,
|
|
|
|
_intc: &'static dyn device_api::interrupt::LocalInterruptController<
|
|
|
|
IpiMessage = CpuMessage,
|
|
|
|
>,
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
todo!()
|
2023-07-29 21:11:15 +03:00
|
|
|
}
|
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
fn register_external_interrupt_controller(
|
|
|
|
&self,
|
|
|
|
_intc: &'static dyn device_api::interrupt::ExternalInterruptController<
|
|
|
|
IrqNumber = Self::IrqNumber,
|
|
|
|
>,
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
todo!()
|
|
|
|
}
|
2023-07-29 21:11:15 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
fn register_reset_device(
|
|
|
|
&self,
|
|
|
|
_reset: &'static dyn device_api::ResetDevice,
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
todo!()
|
|
|
|
}
|
2023-08-05 19:10:44 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
fn monotonic_timer(&'static self) -> &'static dyn MonotonicTimestampProviderDevice {
|
|
|
|
self.timer.get()
|
2023-07-29 21:11:15 +03:00
|
|
|
}
|
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
fn local_interrupt_controller(
|
|
|
|
&'static self,
|
|
|
|
) -> &'static dyn LocalInterruptController<IpiMessage = CpuMessage> {
|
|
|
|
todo!()
|
2023-07-29 21:11:15 +03:00
|
|
|
}
|
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
fn external_interrupt_controller(
|
|
|
|
&'static self,
|
|
|
|
) -> &'static dyn ExternalInterruptController<IrqNumber = Self::IrqNumber> {
|
|
|
|
self.ioapic.get()
|
2023-08-01 11:09:56 +03:00
|
|
|
}
|
2023-08-21 17:26:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
impl X86_64 {
|
|
|
|
fn set_boot_data(&self, boot_data: BootData) {
|
|
|
|
match &boot_data {
|
|
|
|
BootData::YBoot(data) => {
|
|
|
|
// Setup initrd
|
|
|
|
Self::init_initrd(
|
|
|
|
data.initrd_address as usize,
|
|
|
|
(data.initrd_address + data.initrd_size) as usize,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2023-08-03 18:49:29 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
self.boot_data.init(boot_data);
|
2023-08-03 18:49:29 +03:00
|
|
|
}
|
2023-08-05 16:32:12 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
fn init_initrd(initrd_start: usize, initrd_end: usize) {
|
|
|
|
if initrd_start == 0 || initrd_end <= initrd_start {
|
|
|
|
infoln!("No initrd loaded");
|
|
|
|
return;
|
2023-08-07 09:53:47 +03:00
|
|
|
}
|
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
let start_aligned = initrd_start & !0xFFF;
|
|
|
|
let end_aligned = initrd_end & !0xFFF;
|
|
|
|
|
|
|
|
let data = unsafe {
|
|
|
|
core::slice::from_raw_parts(
|
|
|
|
initrd_start.virtualize() as *const _,
|
|
|
|
initrd_end - initrd_start,
|
|
|
|
)
|
2023-08-05 16:32:12 +03:00
|
|
|
};
|
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
let initrd = Initrd {
|
|
|
|
phys_page_start: start_aligned,
|
|
|
|
phys_page_len: end_aligned - start_aligned,
|
|
|
|
data,
|
|
|
|
};
|
2023-08-05 16:32:12 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
INITRD_DATA.init(initrd);
|
2023-08-05 16:32:12 +03:00
|
|
|
}
|
2023-07-28 14:26:39 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
fn init_acpi_from_boot_data(&self) {
|
|
|
|
match *self.boot_data.get() {
|
|
|
|
BootData::YBoot(data) => {
|
|
|
|
self.init_acpi_from_rsdp(data.rsdp_address as usize);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn init_acpi_from_rsdp(&self, address: usize) {
|
|
|
|
let acpi_tables = unsafe { AcpiTables::from_rsdp(AcpiHandlerImpl, address).unwrap() };
|
|
|
|
self.acpi.init(acpi_tables);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe fn init_physical_memory(&self) -> Result<(), Error> {
|
2023-07-30 16:40:30 +03:00
|
|
|
// Reserve the lower 8MiB of memory
|
|
|
|
reserve_region(
|
|
|
|
"lower-memory",
|
|
|
|
PhysicalMemoryRegion {
|
|
|
|
base: 0,
|
|
|
|
size: 8 << 21,
|
|
|
|
},
|
|
|
|
);
|
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
// Reserve initrd
|
2023-08-02 19:53:54 +03:00
|
|
|
if let Some(initrd) = INITRD_DATA.try_get() {
|
|
|
|
reserve_region(
|
|
|
|
"initrd",
|
|
|
|
PhysicalMemoryRegion {
|
|
|
|
base: initrd.phys_page_start,
|
|
|
|
size: initrd.phys_page_len,
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
match *self.boot_data.get() {
|
|
|
|
BootData::YBoot(data) => {
|
|
|
|
let memory_map = &data.memory_map;
|
2023-08-01 11:09:56 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
reserve_region("memory-map", memory_map.reserved_range());
|
2023-08-01 11:09:56 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
phys::init_from_iter(IterableMemoryMap::iter(memory_map).map(|r| {
|
|
|
|
PhysicalMemoryRegion {
|
|
|
|
base: AbstractAvailableRegion::start_address(r),
|
|
|
|
size: AbstractAvailableRegion::page_count(r) * 0x1000,
|
|
|
|
}
|
|
|
|
}))
|
|
|
|
.expect("Failed to initialize the physical memory manager");
|
|
|
|
}
|
|
|
|
}
|
2023-08-01 11:09:56 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
Ok(())
|
2023-08-01 11:09:56 +03:00
|
|
|
}
|
2023-07-30 16:40:30 +03:00
|
|
|
|
2023-08-31 13:40:17 +03:00
|
|
|
unsafe fn init_platform_from_acpi(&self, acpi: &'static AcpiTables<AcpiHandlerImpl>) {
|
|
|
|
let platform_info = acpi.platform_info_in(AcpiAllocator).unwrap();
|
2023-08-02 19:53:54 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
let InterruptModel::Apic(apic_info) = platform_info.interrupt_model else {
|
|
|
|
panic!("Processor does not have an APIC");
|
|
|
|
};
|
2023-08-03 13:01:30 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
self.ioapic.init(IoApic::from_acpi(&apic_info).unwrap());
|
2023-08-05 16:32:12 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
let hpet = HpetInfo::new(acpi).unwrap();
|
|
|
|
self.timer.init(Hpet::from_acpi(&hpet).unwrap());
|
2023-08-31 13:40:17 +03:00
|
|
|
|
|
|
|
acpi::init_acpi(acpi).unwrap();
|
2023-08-05 16:32:12 +03:00
|
|
|
}
|
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
unsafe fn init_framebuffer(&'static self) {
|
|
|
|
match *self.boot_data.get() {
|
|
|
|
BootData::YBoot(data) => {
|
|
|
|
let fb = &data.opt_framebuffer;
|
|
|
|
self.framebuffer.init(
|
|
|
|
LinearFramebuffer::from_physical_bits(
|
|
|
|
fb.res_address as _,
|
|
|
|
fb.res_size as _,
|
|
|
|
fb.res_stride as _,
|
|
|
|
fb.res_width as _,
|
|
|
|
fb.res_height as _,
|
|
|
|
)
|
|
|
|
.unwrap(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2023-08-05 16:32:12 +03:00
|
|
|
|
2023-08-22 09:43:33 +03:00
|
|
|
self.fb_console
|
|
|
|
.init(FramebufferConsole::from_framebuffer(self.framebuffer.get(), None).unwrap());
|
2023-08-05 16:32:12 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
debug::add_sink(self.fb_console.get(), LogLevel::Info);
|
2023-08-05 16:32:12 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
// Add a terminal to the devfs
|
|
|
|
// TODO this is ugly
|
|
|
|
let combined_terminal = CombinedTerminal::new(self.fb_console.get());
|
|
|
|
self.combined_terminal.init(combined_terminal);
|
2023-08-05 16:32:12 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
devfs::add_char_device(self.combined_terminal.get(), CharDeviceType::TtyRegular).unwrap();
|
|
|
|
console::add_console_autoflush(self.fb_console.get());
|
2023-08-05 16:32:12 +03:00
|
|
|
}
|
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
unsafe fn init_platform(&'static self, cpu_id: usize) {
|
|
|
|
Cpu::init_local(LocalApic::new(), cpu_id as _);
|
2023-08-05 16:32:12 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
if cpu_id == 0 {
|
|
|
|
self.init_acpi_from_boot_data();
|
|
|
|
Self::disable_8259();
|
2023-08-05 16:32:12 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
// Initialize debug output as soon as possible
|
|
|
|
let com1_3 = Box::leak(Box::new(ComPort::new(0x3F8, 0x3E8, IrqNumber::Isa(4))));
|
|
|
|
debug::add_sink(com1_3.port_a(), LogLevel::Debug);
|
|
|
|
// devfs::add_char_device(com1_3.port_a(), CharDeviceType::TtySerial).unwrap();
|
|
|
|
|
|
|
|
self.init_framebuffer();
|
2023-08-22 10:00:56 +03:00
|
|
|
debug::init();
|
2023-08-21 17:26:44 +03:00
|
|
|
|
|
|
|
let ps2 = Box::leak(Box::new(PS2Controller::new(
|
|
|
|
IrqNumber::Isa(1),
|
|
|
|
IrqNumber::Isa(12),
|
|
|
|
0x64,
|
|
|
|
0x60,
|
|
|
|
)));
|
|
|
|
ps2.init().unwrap();
|
|
|
|
|
|
|
|
// Print some stuff now that the output is initialized
|
|
|
|
infoln!(
|
|
|
|
"Yggdrasil v{} ({})",
|
|
|
|
env!("CARGO_PKG_VERSION"),
|
|
|
|
git_version!()
|
|
|
|
);
|
|
|
|
infoln!("Initializing x86_64 platform");
|
2023-08-05 16:32:12 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
if let Some(acpi) = self.acpi.try_get() {
|
|
|
|
self.init_platform_from_acpi(acpi);
|
|
|
|
}
|
2023-08-05 16:32:12 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
// Enable IRQs for the devices
|
|
|
|
self.timer.get().init_irq().unwrap();
|
|
|
|
ps2.connect(self.combined_terminal.get());
|
|
|
|
ps2.init_irq().unwrap();
|
2023-08-05 16:32:12 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
device::register_device(self.ioapic.get());
|
|
|
|
device::register_device(self.timer.get());
|
|
|
|
device::register_device(ps2);
|
2023-08-05 16:32:12 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
infoln!("Device list:");
|
|
|
|
for device in device::manager_lock().devices() {
|
|
|
|
infoln!("* {}", device.display_name());
|
|
|
|
}
|
|
|
|
}
|
2023-08-05 16:32:12 +03:00
|
|
|
}
|
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
unsafe fn disable_8259() {
|
|
|
|
infoln!("Disabling i8259 PIC");
|
|
|
|
// TODO should I make a module for 8259 if I don't even use it?
|
2023-08-31 09:21:24 +03:00
|
|
|
let pic_master_cmd = IoPort::<u8>::new(0x20);
|
|
|
|
let pic_master_data = IoPort::<u8>::new(0x21);
|
|
|
|
let pic_slave_cmd = IoPort::<u8>::new(0xA0);
|
|
|
|
let pic_slave_data = IoPort::<u8>::new(0xA1);
|
2023-08-05 16:32:12 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
// Remap PIC IRQ vectors to 32..
|
|
|
|
pic_master_cmd.write(0x11);
|
|
|
|
pic_slave_cmd.write(0x11);
|
2023-08-05 16:32:12 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
pic_master_data.write(32);
|
|
|
|
pic_slave_data.write(32 + 8);
|
2023-08-05 16:32:12 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
pic_slave_data.write(0xFF);
|
|
|
|
pic_master_data.write(0xFF);
|
2023-08-05 16:32:12 +03:00
|
|
|
|
2023-08-21 17:26:44 +03:00
|
|
|
pic_master_cmd.write(0x20);
|
|
|
|
pic_slave_cmd.write(0x20);
|
2023-08-05 16:32:12 +03:00
|
|
|
}
|
2023-08-31 13:40:17 +03:00
|
|
|
|
|
|
|
unsafe fn handle_ipi(&self, msg: CpuMessage) {
|
|
|
|
match msg {
|
|
|
|
CpuMessage::Panic => panic::panic_secondary(),
|
|
|
|
CpuMessage::Shutdown => {
|
|
|
|
Self::set_interrupt_mask(true);
|
|
|
|
|
|
|
|
let id = Cpu::local_id();
|
|
|
|
infoln!("cpu{} shutdown", id);
|
|
|
|
SHUTDOWN_FENCE.signal();
|
|
|
|
|
|
|
|
loop {
|
|
|
|
Self::wait_for_interrupt();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-08-05 16:32:12 +03:00
|
|
|
}
|