519 lines
16 KiB
Rust
Raw Normal View History

2023-12-07 12:50:54 +02:00
//! x86-64 architecture implementation
use core::{
mem::size_of,
ops::{Deref, DerefMut},
ptr::null_mut,
sync::atomic::Ordering,
};
use ::acpi::{mcfg::Mcfg, AcpiTables, InterruptModel};
2023-07-29 19:31:56 +03:00
use abi::error::Error;
use alloc::boxed::Box;
2024-02-26 23:04:51 +02:00
use device_api::{interrupt::Irq, Device};
2023-08-05 16:32:12 +03:00
use git_version::git_version;
2024-10-27 12:35:46 +02:00
use kernel_arch_x86::{
cpuid::{self, CpuFeatures, EcxFeatures, EdxFeatures},
gdt,
};
2024-02-08 15:50:25 +02:00
use kernel_arch_x86_64::{
mem::{
init_fixed_tables,
2024-02-08 15:50:25 +02:00
table::{PageAttributes, PageEntry, PageTable, L1, L2, L3},
EarlyMapping, MEMORY_LIMIT, RAM_MAPPING_L1,
2024-02-08 15:50:25 +02:00
},
PerCpuData,
};
use kernel_fs::devfs::{self, BlockDeviceType};
use libk::{
arch::Cpu,
device::{
display::{
register_display_device, set_display_registration_callback, DisplayDeviceWrapper,
DriverFlags, PixelFormat,
},
register_external_interrupt_controller,
},
};
2024-02-14 14:45:18 +02:00
use libk_device::register_monotonic_timestamp_provider;
2024-02-05 12:59:23 +02:00
use libk_mm::{
2024-07-25 11:58:47 +03:00
address::{PhysicalAddress, Virtualize},
phys::{self, reserved::reserve_region, PhysicalMemoryRegion},
table::{EntryLevel, EntryLevelExt},
};
2024-02-05 12:59:23 +02:00
use libk_util::{sync::SpinFence, OneTimeInit};
use yboot_proto::{
v1::{self, AvailableMemoryRegion},
LoadProtocolV1,
};
use ygg_driver_pci::PciBusManager;
mod acpi;
mod apic;
mod boot;
mod exception;
mod smp;
mod syscall;
2023-07-28 14:26:39 +03:00
2023-07-29 21:11:15 +03:00
use crate::{
2024-12-02 10:19:48 +02:00
arch::x86::peripherals::{i8253::I8253, i8259::I8259, ps2::PS2, rtc::RTC, serial::ComPort},
debug::{self, LogLevel},
2023-07-29 21:11:15 +03:00
device::{
self,
display::{fb_console::FramebufferConsole, linear_fb::LinearFramebuffer},
},
fs::{Initrd, INITRD_DATA},
2023-07-29 21:11:15 +03:00
};
2023-07-28 14:26:39 +03:00
use self::{
2023-08-31 13:40:17 +03:00
acpi::{AcpiAllocator, AcpiHandlerImpl},
apic::{ioapic::IoApic, local::LocalApic},
boot::BootData,
};
2024-11-30 23:51:02 +02:00
use super::{x86::intrinsics, Platform};
2024-10-11 15:29:41 +03:00
/// Offset where legacy ISA IRQs are remapped
pub const ISA_IRQ_OFFSET: u32 = apic::ioapic::ISA_IRQ_OFFSET;
2023-08-05 16:32:12 +03:00
2023-12-07 12:50:54 +02:00
/// x86-64 architecture implementation
2023-07-29 21:11:15 +03:00
pub struct X86_64 {
boot_data: OneTimeInit<BootData>,
acpi: OneTimeInit<AcpiTables<AcpiHandlerImpl>>,
// Display
gop_framebuffer: OneTimeInit<LinearFramebuffer>,
fbconsole: OneTimeInit<FramebufferConsole>,
2023-07-29 21:11:15 +03:00
}
2023-07-28 14:26:39 +03:00
static SHUTDOWN_FENCE: SpinFence = SpinFence::new();
2023-12-07 12:50:54 +02:00
/// Global x86-64 architecture value
pub static PLATFORM: X86_64 = X86_64 {
boot_data: OneTimeInit::new(),
acpi: OneTimeInit::new(),
gop_framebuffer: OneTimeInit::new(),
fbconsole: OneTimeInit::new(),
};
impl Platform for X86_64 {
2023-07-29 19:31:56 +03:00
const KERNEL_VIRT_OFFSET: usize = 0xFFFFFF8000000000;
type L3 = kernel_arch_x86_64::mem::table::L3;
2023-09-15 00:02:14 +03:00
unsafe fn start_application_processors(&self) {
if let Some(acpi) = self.acpi.try_get() {
let Some(pinfo) = acpi
.platform_info_in(AcpiAllocator)
.ok()
.and_then(|p| p.processor_info)
else {
return;
};
smp::start_ap_cores(&pinfo);
}
}
}
impl X86_64 {
fn set_boot_data(&self, data: BootData) {
match data {
BootData::YBoot(data) => {
// Reserve the memory map
reserve_region(
"mmap",
PhysicalMemoryRegion {
base: PhysicalAddress::from_u64(data.memory_map.address),
size: data.memory_map.len as usize * size_of::<AvailableMemoryRegion>(),
},
);
// Reserve initrd, if not NULL
if data.initrd_address != 0 && data.initrd_size != 0 {
let aligned_start = data.initrd_address & !0xFFF;
let aligned_end = (data.initrd_address + data.initrd_size + 0xFFF) & !0xFFF;
reserve_region(
"initrd",
PhysicalMemoryRegion {
base: PhysicalAddress::from_u64(aligned_start),
size: (aligned_end - aligned_start) as usize,
},
);
}
}
}
2023-08-03 18:49:29 +03:00
self.boot_data.init(data);
2023-08-03 18:49:29 +03:00
}
2023-08-05 16:32:12 +03:00
fn map_physical_memory<I: Iterator<Item = PhysicalMemoryRegion> + Clone>(
it: I,
_memory_start: PhysicalAddress,
memory_end: PhysicalAddress,
) -> Result<(), Error> {
2024-07-25 11:58:47 +03:00
let end_l1i = memory_end
.into_usize()
.page_align_up::<L1>()
.page_index::<L1>();
if end_l1i > 512 {
2024-11-05 22:00:10 +02:00
panic!(
"Cannot handle {}GiB of RAM",
end_l1i * L1::SIZE / (1024 * 1024 * 1024)
);
}
2024-07-25 11:58:47 +03:00
MEMORY_LIMIT.store(memory_end.into_usize(), Ordering::Release);
// Check if 1GiB pages are supported
2024-10-12 20:43:16 +03:00
// TODO
// if PROCESSOR_FEATURES
// .get()
// .contains(ProcessorFeatures::PDPE1GB)
// {
// // Just map gigabytes of RAM
// for l1i in 0..end_l1i {
// // TODO NX
// unsafe {
// RAM_MAPPING_L1[l1i] = PageEntry::<L1>::block(
// PhysicalAddress::from_usize(l1i * L1::SIZE),
// PageAttributes::WRITABLE,
// );
// }
// }
// } else {
// Allocate the intermediate tables first
let l2_tables_start = phys::find_contiguous_region(it, end_l1i)
.expect("Could not allocate the memory for RAM mapping L2 tables");
reserve_region(
"ram-l2-tables",
PhysicalMemoryRegion {
base: l2_tables_start,
size: end_l1i * L3::SIZE,
},
);
2024-10-12 20:43:16 +03:00
// Fill in the tables
for l1i in 0..end_l1i {
let l2_phys_addr = l2_tables_start.add(l1i * L3::SIZE);
// Safety: ok, the mapping is done to the memory obtained from
// find_contiguous_region()
let mut l2_data = unsafe { EarlyMapping::<[PageEntry<L2>; 512]>::map(l2_phys_addr)? };
// Safety: ok, the slice comes from EarlyMapping of a page-aligned region
let l2 = unsafe { PageTable::from_raw_slice_mut(l2_data.deref_mut()) };
for l2i in 0..512 {
// TODO NX
l2[l2i] = PageEntry::<L2>::block(
PhysicalAddress::from_usize((l1i * L1::SIZE) | (l2i * L2::SIZE)),
PageAttributes::WRITABLE,
);
}
2024-10-12 20:43:16 +03:00
// Point the L1 entry to the L2 table
unsafe {
RAM_MAPPING_L1[l1i] = PageEntry::<L1>::table(l2_phys_addr, PageAttributes::WRITABLE)
};
2024-10-12 20:43:16 +03:00
intrinsics::flush_cpu_cache();
// The EarlyMapping is then dropped
}
2024-10-12 20:43:16 +03:00
// }
Ok(())
}
2023-09-15 23:23:20 +03:00
unsafe fn init_physical_memory_from_yboot(data: &LoadProtocolV1) -> Result<(), Error> {
let mmap = EarlyMapping::<AvailableMemoryRegion>::map_slice(
2024-07-25 11:58:47 +03:00
PhysicalAddress::from_u64(data.memory_map.address),
data.memory_map.len as usize,
2023-09-15 23:23:20 +03:00
)?;
phys::init_from_iter(
mmap.as_ref().iter().map(|reg| PhysicalMemoryRegion {
2024-07-25 11:58:47 +03:00
base: PhysicalAddress::from_u64(reg.start_address),
size: reg.page_count as usize * L3::SIZE,
}),
Self::map_physical_memory,
)
2023-08-05 16:32:12 +03:00
}
2023-07-28 14:26:39 +03:00
2023-09-15 23:23:20 +03:00
unsafe fn init_memory_management(&self) -> Result<(), Error> {
init_fixed_tables();
// Reserve lower 4MiB just in case
2023-07-30 16:40:30 +03:00
reserve_region(
"lowmem",
2023-07-30 16:40:30 +03:00
PhysicalMemoryRegion {
base: PhysicalAddress::ZERO,
size: 4 * 1024 * 1024,
2023-07-30 16:40:30 +03:00
},
);
match self.boot_data.get() {
2023-09-15 23:23:20 +03:00
&BootData::YBoot(data) => Self::init_physical_memory_from_yboot(data)?,
}
2023-09-15 23:23:20 +03:00
Ok(())
2023-08-05 16:32:12 +03:00
}
2023-09-15 23:23:20 +03:00
unsafe fn init_platform(&'static self, cpu_id: usize) -> Result<(), Error> {
2024-02-08 15:50:25 +02:00
let local_apic = Box::leak(Box::new(LocalApic::new()));
let tss_address = gdt::init();
2024-10-12 20:43:16 +03:00
let (have_features, will_features) = cpuid::setup_features(
CpuFeatures {
ecx: EcxFeatures::SSE3
| EcxFeatures::SSE4_1
| EcxFeatures::SSE4_2
| EcxFeatures::AVX,
edx: EdxFeatures::empty(),
},
CpuFeatures {
ecx: EcxFeatures::XSAVE,
edx: EdxFeatures::FXSR
| EdxFeatures::SSE
| EdxFeatures::PGE
| EdxFeatures::PSE
| EdxFeatures::FPU,
},
);
let will_features = will_features.expect("Could not initialize CPU features");
2024-02-08 15:50:25 +02:00
let cpu_data = PerCpuData {
this: null_mut(),
tss_address,
tmp_address: 0,
local_apic,
2024-10-12 20:43:16 +03:00
available_features: have_features,
enabled_features: will_features,
2024-02-08 15:50:25 +02:00
};
2024-10-12 20:43:16 +03:00
Cpu::init_local(Some(cpu_id as _), cpu_data);
2024-02-08 15:50:25 +02:00
syscall::init_syscall();
2023-08-05 16:32:12 +03:00
if cpu_id == 0 {
// Register the PCI drivers
// TODO make this implicit init
ygg_driver_pci::register_class_driver(
"NVMe Host Controller",
0x01,
Some(0x08),
Some(0x02),
ygg_driver_nvme::probe,
);
ygg_driver_pci::register_class_driver(
"AHCI SATA Controller",
0x01,
Some(0x06),
Some(0x01),
ygg_driver_ahci::probe,
);
2024-02-26 23:04:51 +02:00
ygg_driver_pci::register_class_driver(
"USB xHCI",
0x0C,
Some(0x03),
Some(0x30),
ygg_driver_usb_xhci::probe,
);
ygg_driver_pci::register_vendor_driver(
"Virtio PCI GPU Device",
0x1AF4,
0x1050,
ygg_driver_virtio_gpu::probe,
);
ygg_driver_pci::register_vendor_driver(
"Virtio PCI Network Device",
0x1AF4,
0x1000,
ygg_driver_virtio_net::probe,
);
match self.boot_data.get() {
&BootData::YBoot(data) => {
2024-07-25 11:58:47 +03:00
let start = PhysicalAddress::from_u64(data.initrd_address);
Self::init_initrd(start, start.add(data.initrd_size as usize));
}
}
2023-09-15 23:23:20 +03:00
self.init_acpi_from_boot_data()?;
2024-10-10 18:06:54 +03:00
I8259.disable();
2023-08-05 16:32:12 +03:00
2024-02-07 13:06:17 +02:00
let com1_3 = Box::leak(Box::new(ComPort::new(
0x3F8,
0x3E8,
Irq::External(ISA_IRQ_OFFSET + 4),
)));
debug::add_sink(com1_3.port_a(), LogLevel::Debug);
set_display_registration_callback(|device| {
log::info!("Display registered: {:?}", device.display_name());
let node = devfs::add_block_device(device, BlockDeviceType::Framebuffer);
if device
.driver_flags()
.contains(DriverFlags::REPLACES_BOOT_FRAMEBUFFER)
{
// Switch fbconsole to the new framebuffer
if let Some(fbconsole) = PLATFORM.fbconsole.try_get()
&& fbconsole.uses_boot_framebuffer()
{
if let Err(error) = fbconsole.set_display(device.deref()) {
log::error!("Couldn't set fb console display: {error:?}");
}
}
// Switch /dev/fb0 to the new node
if let Ok(node) = node {
devfs::set_node("fb0", node).ok();
}
}
});
2023-09-15 23:23:20 +03:00
self.init_framebuffer()?;
2023-08-22 10:00:56 +03:00
debug::init();
2024-11-30 23:51:02 +02:00
log::info!(
"Yggdrasil v{} ({})",
env!("CARGO_PKG_VERSION"),
git_version!()
);
2024-12-02 10:19:48 +02:00
RTC.init()?;
2024-10-10 18:06:54 +03:00
PS2.init()?;
if let Some(acpi) = self.acpi.try_get() {
2023-09-15 23:23:20 +03:00
self.init_platform_from_acpi(acpi)?;
}
2023-08-05 16:32:12 +03:00
2024-12-02 10:19:48 +02:00
register_monotonic_timestamp_provider(&I8253);
2024-10-10 18:06:54 +03:00
I8253.init_irq()?;
2024-12-02 10:19:48 +02:00
RTC.init_irq()?;
2023-12-28 10:37:35 +02:00
// ps2.connect(self.tty.get());
2024-10-11 15:29:41 +03:00
PS2.init_irq()?;
2023-08-05 16:32:12 +03:00
2024-10-10 18:06:54 +03:00
device::register_device(&PS2);
2023-08-05 16:32:12 +03:00
2023-09-15 23:23:20 +03:00
PciBusManager::setup_bus_devices()?;
}
2023-09-15 23:23:20 +03:00
Ok(())
}
2023-09-15 23:23:20 +03:00
unsafe fn init_acpi_from_boot_data(&self) -> Result<(), Error> {
match self.boot_data.get() {
&BootData::YBoot(data) => self.init_acpi_from_rsdp(data.rsdp_address as usize),
}
}
2023-09-15 23:23:20 +03:00
unsafe fn init_acpi_from_rsdp(&self, rsdp: usize) -> Result<(), Error> {
let acpi_tables = AcpiTables::from_rsdp(AcpiHandlerImpl, rsdp).map_err(|err| {
2024-11-30 23:51:02 +02:00
log::error!("Could not initialize ACPI tables: {:?}", err);
2023-09-15 23:23:20 +03:00
Error::InvalidArgument
})?;
self.acpi.init(acpi_tables);
2023-09-15 23:23:20 +03:00
Ok(())
}
2023-09-15 23:23:20 +03:00
unsafe fn init_platform_from_acpi(
&self,
acpi: &'static AcpiTables<AcpiHandlerImpl>,
) -> Result<(), Error> {
let platform_info = acpi.platform_info_in(AcpiAllocator).map_err(|err| {
2024-11-30 23:51:02 +02:00
log::error!("Could not get ACPI platform info: {:?}", err);
2023-09-15 23:23:20 +03:00
Error::InvalidArgument
})?;
let InterruptModel::Apic(apic_info) = platform_info.interrupt_model else {
panic!("The processor does not support APIC");
};
let ioapic = IoApic::from_acpi(&apic_info)?;
let ioapic = Box::leak(Box::new(ioapic));
register_external_interrupt_controller(ioapic);
2023-10-03 10:17:13 +03:00
// acpi::init_acpi(acpi).unwrap();
2023-09-15 00:02:14 +03:00
if let Ok(mcfg) = acpi.find_table::<Mcfg>() {
for entry in mcfg.entries() {
2023-09-15 23:23:20 +03:00
PciBusManager::add_segment_from_mcfg(entry)?;
2023-09-15 00:02:14 +03:00
}
}
2023-09-15 23:23:20 +03:00
Ok(())
}
2023-09-15 23:23:20 +03:00
unsafe fn init_framebuffer(&'static self) -> Result<(), Error> {
let display = match self.boot_data.get() {
&BootData::YBoot(data) => {
let info = &data.opt_framebuffer;
let format = match info.res_format {
v1::PIXEL_B8G8R8A8 => PixelFormat::B8G8R8A8,
v1::PIXEL_R8G8B8A8 => PixelFormat::R8G8B8A8,
// Fallback
_ => PixelFormat::R8G8B8A8,
};
let framebuffer = LinearFramebuffer::from_physical_bits(
PhysicalAddress::from_u64(info.res_address),
info.res_size as usize,
info.res_stride as usize,
info.res_width,
info.res_height,
format,
)?;
let framebuffer = self.gop_framebuffer.init(framebuffer);
Some(framebuffer)
}
};
2023-09-15 23:23:20 +03:00
let Some(display) = display else {
return Ok(());
};
// Register boot display
let display = Box::leak(Box::new(DisplayDeviceWrapper::new(display)));
register_display_device(display);
let fbconsole = self.fbconsole.init(FramebufferConsole::from_framebuffer(
(*display).deref(),
None,
true,
)?);
debug::add_sink(fbconsole, LogLevel::Info);
Ok(())
}
fn init_initrd(initrd_start: PhysicalAddress, initrd_end: PhysicalAddress) {
if initrd_start.is_zero() || initrd_end <= initrd_start {
2024-11-30 23:51:02 +02:00
log::info!("No initrd loaded");
return;
}
let start_aligned = initrd_start.page_align_down::<L3>();
let end_aligned = initrd_start.page_align_up::<L3>();
let data = unsafe {
core::slice::from_raw_parts(
start_aligned.virtualize() as *const u8,
initrd_end - initrd_start,
)
};
let initrd = Initrd {
phys_page_start: start_aligned,
phys_page_len: end_aligned - start_aligned,
data,
};
INITRD_DATA.init(initrd);
2023-08-05 16:32:12 +03:00
}
}