x86: unify x86_64/i686 platform init

This commit is contained in:
Mark Poliakov 2024-12-10 16:55:27 +02:00
parent 0b2822cea1
commit 433094837d
11 changed files with 374 additions and 350 deletions

View File

@ -440,7 +440,7 @@ impl ConsoleState {
} }
} }
// Move cursor to position // Move cursor to position
b'f' => { b'f' if self.esc_args.len() >= 2 => {
let row = self.esc_args[0].clamp(1, self.buffer.height) - 1; let row = self.esc_args[0].clamp(1, self.buffer.height) - 1;
let col = self.esc_args[1].clamp(1, CONSOLE_ROW_LEN as u32) - 1; let col = self.esc_args[1].clamp(1, CONSOLE_ROW_LEN as u32) - 1;

View File

@ -69,7 +69,7 @@ impl<const STEPS: usize> TimerWheel<STEPS> {
} }
fn register_timeout(duration: Duration, waker: &Waker) { fn register_timeout(duration: Duration, waker: &Waker) {
let nticks = duration.as_millis().min(288).max(2) as u64; let nticks = duration.as_millis().clamp(2, 288) as u64;
if nticks < 32 { if nticks < 32 {
SHORT_TERM_SLEEPS.lock().wake_after(nticks, waker); SHORT_TERM_SLEEPS.lock().wake_after(nticks, waker);

View File

@ -3,6 +3,8 @@ use libk_mm::{
phys::PhysicalMemoryRegion, phys::PhysicalMemoryRegion,
}; };
use crate::arch::x86::InitrdSource;
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
#[repr(C)] #[repr(C)]
pub struct MultibootInfo { pub struct MultibootInfo {
@ -92,3 +94,13 @@ impl MultibootMemoryMapEntry {
self.ty == 1 self.ty == 1
} }
} }
impl InitrdSource for MultibootModuleEntry {
fn start(&self) -> PhysicalAddress {
PhysicalAddress::from_u32(self.mod_start)
}
fn end(&self) -> PhysicalAddress {
PhysicalAddress::from_u32(self.mod_end)
}
}

View File

@ -5,18 +5,15 @@ use abi::error::Error;
use alloc::sync::Arc; use alloc::sync::Arc;
use boot::multiboot::MultibootInfo; use boot::multiboot::MultibootInfo;
use device_api::{ use device_api::{
device::Device, interrupt::{IpiDeliveryTarget, IpiMessage},
interrupt::{IpiDeliveryTarget, IpiMessage, Irq},
ResetDevice, ResetDevice,
}; };
use git_version::git_version;
use kernel_arch::{Architecture, ArchitectureImpl}; use kernel_arch::{Architecture, ArchitectureImpl};
use kernel_arch_i686::{gdt, mem::table::L3, PerCpuData}; use kernel_arch_i686::{gdt, mem::table::L3, PerCpuData};
use kernel_arch_x86::cpuid::{self, CpuFeatures, EcxFeatures, EdxFeatures}; use kernel_arch_x86::cpuid::{self, CpuFeatures, EcxFeatures, EdxFeatures};
use libk::{ use libk::{
arch::Cpu, arch::Cpu,
debug::{self, LogLevel}, debug::{self, LogLevel},
devfs,
device::{ device::{
display::{ display::{
console::{add_console_autoflush, ConsoleWrapper}, console::{add_console_autoflush, ConsoleWrapper},
@ -28,55 +25,23 @@ use libk::{
vfs::{Terminal, TerminalInput}, vfs::{Terminal, TerminalInput},
}; };
use libk_mm::{ use libk_mm::{
address::{PhysicalAddress, Virtualize}, address::PhysicalAddress,
phys::{self, reserved::reserve_region, PhysicalMemoryRegion}, phys::{self, reserved::reserve_region, PhysicalMemoryRegion},
table::EntryLevelExt,
}; };
use libk_util::sync::IrqSafeSpinlock;
use peripherals::textfb::TextFramebuffer; use peripherals::textfb::TextFramebuffer;
use ygg_driver_pci::{LegacyPciAccess, PciBusManager};
use crate::arch::x86;
use super::Platform;
mod boot; mod boot;
pub mod exception; pub mod exception;
mod peripherals; mod peripherals;
use crate::{
arch::x86::{
intrinsics::IoPortAccess,
peripherals::{i8253::I8253, ps2::PS2Controller, rtc::Rtc},
ISA_IRQ_OFFSET,
},
fs::{Initrd, INITRD_DATA},
};
use super::{
x86::{
intrinsics::IoPort,
peripherals::{i8259::I8259, serial::ComPort},
},
Platform,
};
struct LegacyPciInner {
address: IoPort<u32>,
data: IoPort<u32>,
}
struct LegacyPci {
inner: IrqSafeSpinlock<LegacyPciInner>,
}
pub struct I686; pub struct I686;
static SWITCH_TO_GRAPHIC: AtomicBool = AtomicBool::new(false); static SWITCH_TO_GRAPHIC: AtomicBool = AtomicBool::new(false);
static PCI: LegacyPci = LegacyPci {
inner: IrqSafeSpinlock::new(LegacyPciInner {
address: IoPort::new(0xCF8),
data: IoPort::new(0xCFC),
}),
};
pub static PLATFORM: I686 = I686; pub static PLATFORM: I686 = I686;
impl Platform for I686 { impl Platform for I686 {
@ -101,32 +66,7 @@ impl Platform for I686 {
} }
impl I686 { impl I686 {
fn init_initrd(initrd_start: PhysicalAddress, initrd_end: PhysicalAddress) { unsafe fn init_memory_management(&self, multiboot_info: &MultibootInfo) -> Result<(), Error> {
if initrd_start.is_zero() || initrd_end <= initrd_start {
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);
}
unsafe fn init_platform(&'static self, multiboot_info: &MultibootInfo) -> Result<(), Error> {
reserve_region( reserve_region(
"lowmem", "lowmem",
PhysicalMemoryRegion { PhysicalMemoryRegion {
@ -138,34 +78,18 @@ impl I686 {
let modules = multiboot_info.modules(); let modules = multiboot_info.modules();
if !modules.is_empty() { if !modules.is_empty() {
let initrd = &modules[0]; let initrd = &modules[0];
let start = PhysicalAddress::from_u32(initrd.mod_start); x86::set_initrd(initrd, true);
let end = PhysicalAddress::from_u32(initrd.mod_end);
if initrd.mod_start < initrd.mod_end {
let size = initrd.mod_end - initrd.mod_start;
reserve_region(
"initrd",
PhysicalMemoryRegion {
base: start,
size: size as _,
},
);
}
Self::init_initrd(start, end);
} }
// Initialize physical memory // Initialize physical memory
phys::init_from_iter(multiboot_info.memory_map_iter(), |_, _, _| Ok(()))?; phys::init_from_iter(multiboot_info.memory_map_iter(), |_, _, _| Ok(()))?;
debug::init(); Ok(())
devfs::init(); }
let com1_3 = ComPort::setup(0x3F8, 0x3E8, Irq::External(ISA_IRQ_OFFSET + 4))?; unsafe fn init_cpu(&self) -> Result<(), Error> {
init_gdt();
unsafe { init_gdt() }; exception::init_exceptions();
unsafe { exception::init_exceptions() };
let (have_features, will_features) = cpuid::setup_features( let (have_features, will_features) = cpuid::setup_features(
CpuFeatures { CpuFeatures {
@ -185,38 +109,10 @@ impl I686 {
}; };
Cpu::init_local(Some(0), cpu_data); Cpu::init_local(Some(0), cpu_data);
runtime::init_task_queue(); Ok(())
}
// Register the PCI drivers
// TODO make this implicit init
// TODO AHCI hangs inside interrupt handler in i686
// ygg_driver_pci::register_class_driver(
// "AHCI SATA Controller",
// 0x01,
// Some(0x06),
// Some(0x01),
// ygg_driver_ahci::probe,
// );
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,
);
unsafe fn init_framebuffer(&self) -> Result<(), Error> {
DEVICE_REGISTRY.display.set_callback(|device, _| { DEVICE_REGISTRY.display.set_callback(|device, _| {
log::info!("Display registered: {:?}", device.display_name()); log::info!("Display registered: {:?}", device.display_name());
if device if device
@ -227,21 +123,6 @@ impl I686 {
} }
}); });
let i8259 = I8259::setup().expect("Could not initialize i8259 PIC");
let i8253 = I8253::setup().expect("Could not initialize i8253 Timer");
i8259.set_i8253(i8253);
if let Err(error) = PS2Controller::setup() {
log::error!("Could not initialize PS/2 Controller: {error:?}");
}
if let Err(error) = Rtc::setup() {
log::error!("RTC init error: {error:?}");
}
if let Err(error) = unsafe { com1_3.port_a().clone().init_irq() } {
log::error!("COM port IRQ init error: {error:?}");
}
// Setup text framebuffer // Setup text framebuffer
// TODO check if video mode is set from boot info // TODO check if video mode is set from boot info
let textfb = Arc::new(TextFramebuffer::new( let textfb = Arc::new(TextFramebuffer::new(
@ -254,7 +135,7 @@ impl I686 {
let textfb_console = Arc::new(Terminal::from_parts( let textfb_console = Arc::new(Terminal::from_parts(
Default::default(), Default::default(),
TerminalInput::with_capacity(256).unwrap(), TerminalInput::with_capacity(256)?,
ConsoleWrapper(textfb), ConsoleWrapper(textfb),
)); ));
let keyboard_input = ygg_driver_input::setup(); let keyboard_input = ygg_driver_input::setup();
@ -267,43 +148,27 @@ impl I686 {
.ok(); .ok();
DEVICE_REGISTRY.terminal.register(textfb_console).ok(); DEVICE_REGISTRY.terminal.register(textfb_console).ok();
log::info!(
"Yggdrasil v{} ({})",
env!("CARGO_PKG_VERSION"),
git_version!()
);
PciBusManager::add_legacy_segment(&PCI)?;
PciBusManager::setup_bus_devices()?;
Ok(()) Ok(())
} }
}
impl LegacyPciAccess for LegacyPci { unsafe fn init_platform(&'static self, multiboot_info: &MultibootInfo) -> Result<(), Error> {
fn write_u32(&self, bus: u8, slot: u8, func: u8, offset: u8, value: u32) { self.init_memory_management(multiboot_info)
assert_eq!(offset & 0x3, 0); .expect("Could not initialize memory management");
let inner = self.inner.lock();
inner.address.write(Self::addr(bus, slot, func, offset));
inner.data.write(value);
}
fn read_u32(&self, bus: u8, slot: u8, func: u8, offset: u8) -> u32 { self.init_cpu().expect("Could not initialize CPU");
assert_eq!(offset & 0x3, 0);
let inner = self.inner.lock();
inner.address.write(Self::addr(bus, slot, func, offset));
inner.data.read()
}
}
impl LegacyPci { x86::register_pci_drivers();
#[inline]
const fn addr(bus: u8, slot: u8, func: u8, offset: u8) -> u32 { let early = x86::init_platform_devices_early()?;
((bus as u32) << 16)
| ((slot as u32) << 11) if let Err(error) = self.init_framebuffer() {
| ((func as u32) << 8) log::error!("Could not initialize boot framebuffer: {error:?}");
| (offset as u32 & 0xFC) }
| (1 << 31)
x86::add_legacy_pci();
x86::init_platform_devices(early);
Ok(())
} }
} }

View File

@ -2,6 +2,22 @@
#![allow(missing_docs)] #![allow(missing_docs)]
use abi::error::Error;
use alloc::sync::Arc;
use device_api::{device::Device, interrupt::Irq};
use libk::{debug, devfs, task::runtime};
use libk_mm::{
address::{PhysicalAddress, Virtualize},
phys::{self, PhysicalMemoryRegion},
table::EntryLevelExt,
};
use peripherals::{i8253::I8253, i8259::I8259, ps2::PS2Controller, rtc::Rtc, serial::ComPort};
use ygg_driver_pci::PciBusManager;
use crate::fs::{Initrd, INITRD_DATA};
use super::L3;
#[cfg(any(target_arch = "x86_64", rust_analyzer))] #[cfg(any(target_arch = "x86_64", rust_analyzer))]
pub const ISA_IRQ_OFFSET: u32 = crate::arch::x86_64::ISA_IRQ_OFFSET; pub const ISA_IRQ_OFFSET: u32 = crate::arch::x86_64::ISA_IRQ_OFFSET;
@ -9,4 +25,156 @@ pub const ISA_IRQ_OFFSET: u32 = crate::arch::x86_64::ISA_IRQ_OFFSET;
pub const ISA_IRQ_OFFSET: u32 = 0; pub const ISA_IRQ_OFFSET: u32 = 0;
pub mod intrinsics; pub mod intrinsics;
mod pci;
pub mod peripherals; pub mod peripherals;
pub trait InitrdSource {
fn start(&self) -> PhysicalAddress;
fn end(&self) -> PhysicalAddress;
}
pub struct EarlyPlatformDevices {
pub com1_3: Arc<ComPort>,
pub i8259: Arc<I8259>,
}
// TODO move this to some sort of .init_array-style implicit thing
pub fn register_pci_drivers() {
// XXX: Only works with MSI-X, so no i686
#[cfg(any(target_arch = "x86_64", rust_analyzer))]
ygg_driver_pci::register_class_driver(
"NVMe Host Controller",
0x01,
Some(0x08),
Some(0x02),
ygg_driver_nvme::probe,
);
// XXX: i686 hangs in interrupt handler
#[cfg(any(target_arch = "x86_64", rust_analyzer))]
ygg_driver_pci::register_class_driver(
"AHCI Controller",
0x01,
Some(0x06),
Some(0x01),
ygg_driver_ahci::probe,
);
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,
);
}
// Initialize the bare minimum required to:
// * Allocate/manage interrupts
// * Print debug output
pub fn init_platform_devices_early() -> Result<EarlyPlatformDevices, Error> {
devfs::init();
debug::init();
// Initialize async executor queue
runtime::init_task_queue();
let com1_3 = ComPort::setup(0x3F8, 0x3E8, Irq::External(ISA_IRQ_OFFSET + 4))?;
let i8259 = I8259::setup().expect("Could not initialize i8259 PIC");
#[cfg(any(target_arch = "x86", rust_analyzer))]
{
use libk::device::register_external_interrupt_controller;
// No other interrupt handling options
unsafe { i8259.clone().init() }?;
register_external_interrupt_controller(i8259.clone());
}
#[cfg(any(target_arch = "x86_64", rust_analyzer))]
{
i8259.disable();
}
Ok(EarlyPlatformDevices { i8259, com1_3 })
}
pub fn add_legacy_pci() {
if let Err(error) = PciBusManager::add_legacy_segment(&pci::PCI) {
log::error!("Couldn't add legacy x86 PCI: {error:?}");
}
}
pub fn init_platform_devices(early: EarlyPlatformDevices) {
// TODO clocksource can be selected here
match I8253::setup() {
Ok(i8253) => {
early.i8259.set_i8253(i8253);
}
Err(error) => {
log::error!("Couldn't setup i8253: {error:?}");
}
}
if let Err(error) = PS2Controller::setup() {
log::error!("PS/2 controller init error: {error:?}");
}
if let Err(error) = Rtc::setup() {
log::error!("RTC init error: {error:?}");
}
if let Err(error) = unsafe { early.com1_3.port_a().clone().init_irq() } {
log::error!("COM port IRQ init error: {error:?}");
}
if let Err(error) = PciBusManager::setup_bus_devices() {
log::error!("PCI bus device setup error(s): {error:?}");
}
}
pub fn set_initrd(initrd: &impl InitrdSource, reserve: bool) {
let initrd_start = initrd.start();
let initrd_end = initrd.end();
if initrd_start.is_zero() || initrd_end <= initrd_start {
log::info!("No initrd loaded");
return;
}
let start_aligned = initrd_start.page_align_down::<L3>();
let end_aligned = initrd_end.page_align_up::<L3>();
let size = end_aligned - start_aligned;
if reserve {
phys::reserved::reserve_region(
"initrd",
PhysicalMemoryRegion {
base: start_aligned,
size,
},
);
}
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);
}

View File

@ -0,0 +1,49 @@
use libk_util::sync::IrqSafeSpinlock;
use ygg_driver_pci::LegacyPciAccess;
use crate::arch::x86::intrinsics::IoPortAccess;
use super::intrinsics::IoPort;
struct LegacyPciInner {
address: IoPort<u32>,
data: IoPort<u32>,
}
pub(super) struct LegacyPci {
inner: IrqSafeSpinlock<LegacyPciInner>,
}
pub(super) static PCI: LegacyPci = LegacyPci {
inner: IrqSafeSpinlock::new(LegacyPciInner {
address: IoPort::new(0xCF8),
data: IoPort::new(0xCFC),
}),
};
impl LegacyPciAccess for LegacyPci {
fn write_u32(&self, bus: u8, slot: u8, func: u8, offset: u8, value: u32) {
assert_eq!(offset & 0x3, 0);
let inner = self.inner.lock();
inner.address.write(Self::addr(bus, slot, func, offset));
inner.data.write(value);
}
fn read_u32(&self, bus: u8, slot: u8, func: u8, offset: u8) -> u32 {
assert_eq!(offset & 0x3, 0);
let inner = self.inner.lock();
inner.address.write(Self::addr(bus, slot, func, offset));
inner.data.read()
}
}
impl LegacyPci {
#[inline]
const fn addr(bus: u8, slot: u8, func: u8, offset: u8) -> u32 {
((bus as u32) << 16)
| ((slot as u32) << 11)
| ((func as u32) << 8)
| (offset as u32 & 0xFC)
| (1 << 31)
}
}

View File

@ -9,7 +9,6 @@ use device_api::{
IrqOptions, IrqOptions,
}, },
}; };
use libk::device::register_external_interrupt_controller;
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit}; use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
use crate::arch::x86::intrinsics::{IoPort, IoPortAccess}; use crate::arch::x86::intrinsics::{IoPort, IoPortAccess};
@ -124,8 +123,6 @@ impl I8259 {
pub fn setup() -> Result<Arc<Self>, Error> { pub fn setup() -> Result<Arc<Self>, Error> {
let this = Arc::new(Self::new()); let this = Arc::new(Self::new());
unsafe { this.clone().init() }?;
register_external_interrupt_controller(this.clone());
I8259.init(this.clone()); I8259.init(this.clone());
Ok(this) Ok(this)
} }
@ -134,9 +131,8 @@ impl I8259 {
self.i8253.init(i8253); self.i8253.init(i8253);
} }
pub fn disable() { pub fn disable(&self) {
let inner = Self::new_inner(); let inner = self.inner.lock();
log::info!("Disabling i8259 PIC"); log::info!("Disabling i8259 PIC");
// Remap PIC IRQ vectors to 32.. // Remap PIC IRQ vectors to 32..

View File

@ -54,7 +54,7 @@ impl Inner {
self.wait_for_update(); self.wait_for_update();
let mut last = self.try_read_time(); let mut last = self.try_read_time();
let time = loop { loop {
self.wait_for_update(); self.wait_for_update();
let now = self.try_read_time(); let now = self.try_read_time();
@ -62,9 +62,7 @@ impl Inner {
break now; break now;
} }
last = now; last = now;
}; }
time
} }
fn wait_for_update(&mut self) { fn wait_for_update(&mut self) {

View File

@ -3,7 +3,6 @@ use core::{arch::global_asm, sync::atomic::Ordering};
use kernel_arch_x86::registers::MSR_IA32_KERNEL_GS_BASE; use kernel_arch_x86::registers::MSR_IA32_KERNEL_GS_BASE;
use kernel_arch_x86_64::CPU_COUNT; use kernel_arch_x86_64::CPU_COUNT;
use libk::{devfs, task::runtime};
use tock_registers::interfaces::Writeable; use tock_registers::interfaces::Writeable;
use yboot_proto::{ use yboot_proto::{
v1::{FramebufferOption, MemoryMap}, v1::{FramebufferOption, MemoryMap},
@ -12,7 +11,7 @@ use yboot_proto::{
use crate::{kernel_main, kernel_secondary_main, mem::KERNEL_VIRT_OFFSET}; use crate::{kernel_main, kernel_secondary_main, mem::KERNEL_VIRT_OFFSET};
use super::{exception, syscall, PLATFORM}; use super::PLATFORM;
pub enum BootData { pub enum BootData {
YBoot(&'static LoadProtocolV1), YBoot(&'static LoadProtocolV1),
@ -79,23 +78,6 @@ extern "C" fn __x86_64_upper_entry() -> ! {
PLATFORM.set_boot_data(BootData::YBoot(&YBOOT_DATA)); PLATFORM.set_boot_data(BootData::YBoot(&YBOOT_DATA));
// Setup memory management: kernel virtual memory tables, physical page manager and heap
unsafe {
PLATFORM
.init_memory_management()
.expect("Could not initialize memory management");
}
unsafe {
exception::init_exceptions(0);
}
// Initialize async executor queue
runtime::init_task_queue();
devfs::init();
// Initializes: local CPU, platform devices (timers/serials/etc), debug output
unsafe { unsafe {
PLATFORM PLATFORM
.init_platform(0) .init_platform(0)
@ -113,13 +95,7 @@ pub extern "C" fn __x86_64_ap_entry() -> ! {
init_dummy_cpu(); init_dummy_cpu();
} }
// Still not initialized: GDT, IDT, CPU features, syscall, kernel_gs_base
unsafe { unsafe {
// Cpu::init_local(LocalApic::new(), cpu_id as u32);
syscall::init_syscall();
exception::init_exceptions(cpu_id);
PLATFORM PLATFORM
.init_platform(cpu_id) .init_platform(cpu_id)
.expect("Could not initialize the platform (AP)"); .expect("Could not initialize the platform (AP)");

View File

@ -6,8 +6,6 @@ use abi::error::Error;
use acpi::{AcpiAllocator, AcpiHandlerImpl}; use acpi::{AcpiAllocator, AcpiHandlerImpl};
use alloc::{boxed::Box, sync::Arc}; use alloc::{boxed::Box, sync::Arc};
use apic::{ioapic::IoApic, local::LocalApic}; use apic::{ioapic::IoApic, local::LocalApic};
use device_api::{device::Device, interrupt::Irq};
use git_version::git_version;
use kernel_arch_x86::{ use kernel_arch_x86::{
cpuid::{self, CpuFeatures, EcxFeatures, EdxFeatures}, cpuid::{self, CpuFeatures, EcxFeatures, EdxFeatures},
gdt, gdt,
@ -31,7 +29,7 @@ use libk::{
}, },
}; };
use libk_mm::{ use libk_mm::{
address::{PhysicalAddress, Virtualize}, address::PhysicalAddress,
phys::{self, reserved::reserve_region, PhysicalMemoryRegion}, phys::{self, reserved::reserve_region, PhysicalMemoryRegion},
table::{EntryLevel, EntryLevelExt}, table::{EntryLevel, EntryLevelExt},
}; };
@ -49,19 +47,12 @@ mod exception;
mod smp; mod smp;
mod syscall; mod syscall;
use crate::{ use crate::{arch::x86, device::display::linear_fb::LinearFramebuffer};
arch::x86::peripherals::{i8253::I8253, ps2::PS2Controller, rtc::Rtc},
device::display::linear_fb::LinearFramebuffer,
fs::{Initrd, INITRD_DATA},
};
use self::boot::BootData; use self::boot::BootData;
use super::{ use super::{
x86::{ x86::{intrinsics, InitrdSource},
intrinsics,
peripherals::{i8259::I8259, serial::ComPort},
},
Platform, Platform,
}; };
@ -251,8 +242,39 @@ impl X86_64 {
} }
unsafe fn init_platform(&'static self, cpu_id: usize) -> Result<(), Error> { unsafe fn init_platform(&'static self, cpu_id: usize) -> Result<(), Error> {
if cpu_id == 0 {
PLATFORM
.init_memory_management()
.expect("Could not initialize memory management");
}
self.init_local_cpu(cpu_id);
if cpu_id == 0 {
x86::register_pci_drivers();
self.setup_from_boot_data()?;
let early = x86::init_platform_devices_early()?;
if let Err(error) = self.init_framebuffer() {
log::error!("Could not initialize boot framebuffer: {error:?}");
}
if let Some(acpi) = self.acpi.try_get() {
self.init_platform_from_acpi(acpi)?;
}
x86::init_platform_devices(early);
}
Ok(())
}
unsafe fn init_local_cpu(&self, cpu_id: usize) {
let local_apic = Box::new(LocalApic::new()); let local_apic = Box::new(LocalApic::new());
let tss_address = gdt::init(); let tss_address = gdt::init();
exception::init_exceptions(cpu_id);
let (have_features, will_features) = cpuid::setup_features( let (have_features, will_features) = cpuid::setup_features(
CpuFeatures { CpuFeatures {
@ -285,119 +307,16 @@ impl X86_64 {
Cpu::init_local(Some(cpu_id as _), cpu_data); Cpu::init_local(Some(cpu_id as _), cpu_data);
syscall::init_syscall(); syscall::init_syscall();
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 Controller",
0x01,
Some(0x06),
Some(0x01),
ygg_driver_ahci::probe,
);
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) => {
let start = PhysicalAddress::from_u64(data.initrd_address);
Self::init_initrd(start, start.add(data.initrd_size as usize));
}
}
self.init_acpi_from_boot_data()?;
I8259::disable();
debug::init();
let com1_3 = ComPort::setup(0x3F8, 0x3E8, Irq::External(ISA_IRQ_OFFSET + 4))?;
// TODO register platform devices
DEVICE_REGISTRY.display.set_callback(|device, node| {
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.clone()) {
log::error!("Couldn't set fb console display: {error:?}");
}
}
// Switch /dev/fb0 to the new node
if let Some(node) = node {
devfs::set_node("fb0", node).ok();
}
}
});
self.init_framebuffer()?;
log::info!(
"Yggdrasil v{} ({})",
env!("CARGO_PKG_VERSION"),
git_version!()
);
// RTC.init()?;
if let Some(acpi) = self.acpi.try_get() {
self.init_platform_from_acpi(acpi)?;
}
if let Err(error) = I8253::setup() {
log::error!("Couldn't setup i8253: {error:?}");
}
if let Err(error) = PS2Controller::setup() {
log::error!("PS/2 controller init error: {error:?}");
}
if let Err(error) = Rtc::setup() {
log::error!("RTC init error: {error:?}");
}
if let Err(error) = unsafe { com1_3.port_a().clone().init_irq() } {
log::error!("COM port IRQ init error: {error:?}");
}
PciBusManager::setup_bus_devices()?;
}
Ok(())
} }
unsafe fn init_acpi_from_boot_data(&self) -> Result<(), Error> { unsafe fn setup_from_boot_data(&self) -> Result<(), Error> {
match self.boot_data.get() { match self.boot_data.get() {
&BootData::YBoot(data) => self.init_acpi_from_rsdp(data.rsdp_address as usize), &BootData::YBoot(data) => {
// Already reserved in set_boot_data()
x86::set_initrd(data, false);
self.init_acpi_from_rsdp(data.rsdp_address as usize)
}
} }
} }
@ -420,16 +339,19 @@ impl X86_64 {
})?; })?;
let InterruptModel::Apic(apic_info) = platform_info.interrupt_model else { let InterruptModel::Apic(apic_info) = platform_info.interrupt_model else {
panic!("The processor does not support APIC"); unreachable!("The processor does not support APIC");
}; };
let ioapic = IoApic::from_acpi(&apic_info)?; let ioapic = IoApic::from_acpi(&apic_info)?;
register_external_interrupt_controller(ioapic); register_external_interrupt_controller(ioapic);
// acpi::init_acpi(acpi).unwrap(); // acpi::init_acpi(acpi).unwrap();
if let Ok(mcfg) = acpi.find_table::<Mcfg>() { if let Ok(mcfg) = acpi.find_table::<Mcfg>() {
for entry in mcfg.entries() { for entry in mcfg.entries() {
PciBusManager::add_segment_from_mcfg(entry)?; if let Err(error) = PciBusManager::add_segment_from_mcfg(entry) {
log::error!("Could not add PCI bus segment: {error:?}");
}
} }
} }
@ -437,6 +359,29 @@ impl X86_64 {
} }
unsafe fn init_framebuffer(&'static self) -> Result<(), Error> { unsafe fn init_framebuffer(&'static self) -> Result<(), Error> {
DEVICE_REGISTRY.display.set_callback(|device, node| {
log::info!("Display registered: {:?}", device.display_name());
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.clone()) {
log::error!("Couldn't set fb console display: {error:?}");
}
}
// Switch /dev/fb0 to the new node
if let Some(node) = node {
devfs::set_node("fb0", node).ok();
}
}
});
let display = match self.boot_data.get() { let display = match self.boot_data.get() {
&BootData::YBoot(data) => { &BootData::YBoot(data) => {
let info = &data.opt_framebuffer; let info = &data.opt_framebuffer;
@ -465,9 +410,7 @@ impl X86_64 {
}; };
// Register boot display // Register boot display
// let display = Box::leak(Box::new(DisplayDeviceWrapper::new(display)));
DEVICE_REGISTRY.display.register(display.clone(), true)?; DEVICE_REGISTRY.display.register(display.clone(), true)?;
// register_display_device(display);
let fbconsole = self let fbconsole = self
.fbconsole .fbconsole
@ -482,28 +425,38 @@ impl X86_64 {
Ok(()) Ok(())
} }
fn init_initrd(initrd_start: PhysicalAddress, initrd_end: PhysicalAddress) { // fn init_initrd(initrd_start: PhysicalAddress, initrd_end: PhysicalAddress) {
if initrd_start.is_zero() || initrd_end <= initrd_start { // if initrd_start.is_zero() || initrd_end <= initrd_start {
log::info!("No initrd loaded"); // log::info!("No initrd loaded");
return; // return;
} // }
let start_aligned = initrd_start.page_align_down::<L3>(); // let start_aligned = initrd_start.page_align_down::<L3>();
let end_aligned = initrd_start.page_align_up::<L3>(); // let end_aligned = initrd_start.page_align_up::<L3>();
let data = unsafe { // let data = unsafe {
core::slice::from_raw_parts( // core::slice::from_raw_parts(
start_aligned.virtualize() as *const u8, // start_aligned.virtualize() as *const u8,
initrd_end - initrd_start, // initrd_end - initrd_start,
) // )
}; // };
let initrd = Initrd { // let initrd = Initrd {
phys_page_start: start_aligned, // phys_page_start: start_aligned,
phys_page_len: end_aligned - start_aligned, // phys_page_len: end_aligned - start_aligned,
data, // data,
}; // };
INITRD_DATA.init(initrd); // INITRD_DATA.init(initrd);
// }
}
impl InitrdSource for LoadProtocolV1 {
fn start(&self) -> PhysicalAddress {
PhysicalAddress::from_u64(self.initrd_address)
}
fn end(&self) -> PhysicalAddress {
PhysicalAddress::from_u64(self.initrd_address + self.initrd_size)
} }
} }

View File

@ -38,6 +38,7 @@
use alloc::borrow::ToOwned; use alloc::borrow::ToOwned;
use arch::Platform; use arch::Platform;
use fs::sysfs; use fs::sysfs;
use git_version::git_version;
use kernel_arch::{Architecture, ArchitectureImpl}; use kernel_arch::{Architecture, ArchitectureImpl};
use libk::{arch::Cpu, devfs}; use libk::{arch::Cpu, devfs};
use libk_util::sync::SpinFence; use libk_util::sync::SpinFence;
@ -87,6 +88,12 @@ pub fn kernel_secondary_main() -> ! {
/// * Basic debugging facilities /// * Basic debugging facilities
/// * Initrd /// * Initrd
pub fn kernel_main() -> ! { pub fn kernel_main() -> ! {
log::info!(
"Yggdrasil v{} ({})",
env!("CARGO_PKG_VERSION"),
git_version!()
);
libk::panic::set_handler(panic::panic_handler); libk::panic::set_handler(panic::panic_handler);
// Setup the sysfs // Setup the sysfs