Skip to content
This repository was archived by the owner on Mar 20, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 76 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ edition = "2018"

[dependencies]
volatile = "0.2.6"
spin = "0.5.2"
spin = "0.9.8"
pc-keyboard = "0.5.0"
heapless = "0.6.1"
acpi = "5.0.0"
aml = "0.16.4"
linked_list_allocator = "0.9.0"

[target.'cfg(target_arch = "x86_64")'.dependencies]
Expand Down
177 changes: 177 additions & 0 deletions src/kernel/acpi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
use crate::print;

use acpi::platform::{Processor, ProcessorState};
use acpi::{AcpiHandler, AcpiTables, PhysicalMapping};
use alloc::boxed::Box;
use aml::value::AmlValue;
use aml::{AmlContext, AmlName, DebugVerbosity, Handler};
use core::ptr::NonNull;
use x86_64::instructions::port::Port;
use x86_64::PhysAddr;

use super::memory;

static mut PM1A_CNT_BLK: u32 = 0;
static mut SLP_TYPA: u16 = 0;
static SLP_LEN: u16 = 1 << 13;

pub fn init() {
let res = unsafe { AcpiTables::search_for_rsdp_bios(MorosAcpiHandler) };
match res {
Ok(acpi) => {
if let Ok(info) = acpi.platform_info() {
if let Some(info) = info.processor_info {
log_cpu(&info.boot_processor);
for processor in info.application_processors.iter() {
log_cpu(&processor);
}
}
}
if let Ok(fadt) = acpi.find_table::<acpi::fadt::Fadt>() {
if let Ok(block) = fadt.pm1a_control_block() {
unsafe {
PM1A_CNT_BLK = block.address as u32;
}
}
}
if let Ok(dsdt) = acpi.dsdt() {
let phys_addr = PhysAddr::new(dsdt.address as u64);
let virt_addr = memory::phys_to_virt(phys_addr);
let ptr = virt_addr.as_ptr();
let table = unsafe { core::slice::from_raw_parts(ptr, dsdt.length as usize) };
let handler = Box::new(MorosAmlHandler);
let mut aml = AmlContext::new(handler, DebugVerbosity::None);
if aml.parse_table(table).is_ok() {
let name = AmlName::from_str("\\_S5").unwrap();
let res = aml.namespace.get_by_path(&name);
if let Ok(AmlValue::Package(s5)) = res {
if let AmlValue::Integer(value) = s5[0] {
unsafe {
SLP_TYPA = value as u16;
}
}
}
} else {
print!("ACPI: Could not parse AML in DSDT");
// FIXME: AML parsing works on QEMU and Bochs but not
// on VirtualBox at the moment, so we use the following
// hardcoded value:
unsafe {
SLP_TYPA = (5 & 7) << 10;
}
}
} else {
print!("ACPI: Could not find DSDT in BIOS");
}
}
Err(_e) => {
print!("ACPI: Could not find RDSP in BIOS");
}
};
}

pub fn shutdown() {
print!("ACPI Shutdown");
unsafe {
let mut port: Port<u16> = Port::new(PM1A_CNT_BLK as u16);
port.write(SLP_TYPA | SLP_LEN);
}
}

#[derive(Clone)]
pub struct MorosAcpiHandler;

impl AcpiHandler for MorosAcpiHandler {
unsafe fn map_physical_region<T>(&self, addr: usize, size: usize) -> PhysicalMapping<Self, T> {
let phys_addr = PhysAddr::new(addr as u64);
let virt_addr = memory::phys_to_virt(phys_addr);
let ptr = NonNull::new(virt_addr.as_mut_ptr()).unwrap();
PhysicalMapping::new(addr, ptr, size, size, Self)
}

fn unmap_physical_region<T>(_region: &PhysicalMapping<Self, T>) {}
}

struct MorosAmlHandler;

impl Handler for MorosAmlHandler {
fn read_u8(&self, address: usize) -> u8 {
read_addr::<u8>(address)
}
fn read_u16(&self, address: usize) -> u16 {
read_addr::<u16>(address)
}
fn read_u32(&self, address: usize) -> u32 {
read_addr::<u32>(address)
}
fn read_u64(&self, address: usize) -> u64 {
read_addr::<u64>(address)
}

fn write_u8(&mut self, _: usize, _: u8) {
unimplemented!()
}
fn write_u16(&mut self, _: usize, _: u16) {
unimplemented!()
}
fn write_u32(&mut self, _: usize, _: u32) {
unimplemented!()
}
fn write_u64(&mut self, _: usize, _: u64) {
unimplemented!()
}
fn read_io_u8(&self, _: u16) -> u8 {
unimplemented!()
}
fn read_io_u16(&self, _: u16) -> u16 {
unimplemented!()
}
fn read_io_u32(&self, _: u16) -> u32 {
unimplemented!()
}
fn write_io_u8(&self, _: u16, _: u8) {
unimplemented!()
}
fn write_io_u16(&self, _: u16, _: u16) {
unimplemented!()
}
fn write_io_u32(&self, _: u16, _: u32) {
unimplemented!()
}
fn read_pci_u8(&self, _: u16, _: u8, _: u8, _: u8, _: u16) -> u8 {
unimplemented!()
}
fn read_pci_u16(&self, _: u16, _: u8, _: u8, _: u8, _: u16) -> u16 {
unimplemented!()
}
fn read_pci_u32(&self, _: u16, _: u8, _: u8, _: u8, _: u16) -> u32 {
unimplemented!()
}
fn write_pci_u8(&self, _: u16, _: u8, _: u8, _: u8, _: u16, _: u8) {
unimplemented!()
}
fn write_pci_u16(&self, _: u16, _: u8, _: u8, _: u8, _: u16, _: u16) {
unimplemented!()
}
fn write_pci_u32(&self, _: u16, _: u8, _: u8, _: u8, _: u16, _: u32) {
unimplemented!()
}
}

fn read_addr<T>(addr: usize) -> T
where
T: Copy,
{
let virtual_address = memory::phys_to_virt(PhysAddr::new(addr as u64));
unsafe { *virtual_address.as_ptr::<T>() }
}

fn log_cpu(processor: &Processor) {
let kind = if processor.is_ap { "AP" } else { "BP" };
let state = match processor.state {
ProcessorState::Disabled => "disabled",
ProcessorState::Running => "running",
ProcessorState::WaitingForSipi => "waiting",
};
print!("CPU {}:{} {}", kind, processor.processor_uid, state);
}
17 changes: 13 additions & 4 deletions src/kernel/memory.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
use bootloader::bootinfo::{MemoryMap, MemoryRegionType};
use spin::Once;
use x86_64::structures::paging::OffsetPageTable;
use x86_64::{
structures::paging::{FrameAllocator, Mapper, Page, PageTable, PhysFrame, Size4KiB},
PhysAddr, VirtAddr,
};

pub static PHYS_MEM_OFFSET: Once<u64> = Once::new();

pub fn phys_mem_offset() -> u64 {
unsafe { *PHYS_MEM_OFFSET.get_unchecked() }
}

pub fn phys_to_virt(addr: PhysAddr) -> VirtAddr {
VirtAddr::new(addr.as_u64() + phys_mem_offset())
}

/// A FrameAllocator that returns usable frames from the bootloader's memory map.
pub struct BootInfoFrameAllocator {
memory_map: &'static MemoryMap,
Expand All @@ -27,11 +38,9 @@ impl BootInfoFrameAllocator {
/// Returns an iterator over the usable frames specified in the memory map.
fn usable_frames(&self) -> impl Iterator<Item = PhysFrame> {
let regions = self.memory_map.iter();
let usable_regions = regions
.filter(|r| r.region_type == MemoryRegionType::Usable);
let usable_regions = regions.filter(|r| r.region_type == MemoryRegionType::Usable);

let addr_ranges = usable_regions
.map(|r| r.range.start_addr()..r.range.end_addr());
let addr_ranges = usable_regions.map(|r| r.range.start_addr()..r.range.end_addr());

let frame_addresses = addr_ranges.flat_map(|r| r.step_by(4096));

Expand Down
1 change: 1 addition & 0 deletions src/kernel/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod acpi;
pub mod allocator;
pub mod clock;
pub mod debug;
Expand Down
Loading