Skip to content
Snippets Groups Projects
Verified Commit 1dfe98ef authored by Jeremy Soller's avatar Jeremy Soller
Browse files

Use ACPI for aarch64

parent 5baae1cc
No related branches found
No related tags found
No related merge requests found
......@@ -51,7 +51,7 @@ $(BUILD)/harddrive.bin: $(BUILD)/esp.bin $(BUILD)/filesystem.bin
mv $@.partial $@
$(BUILD)/firmware.rom:
wget https://releases.linaro.org/components/kernel/uefi-linaro/latest/release/qemu64/QEMU_EFI.fd -O $@
cp /usr/share/AAVMF/AAVMF_CODE.fd $@
qemu: $(BUILD)/harddrive.bin $(BUILD)/firmware.rom
$(QEMU) \
......@@ -61,6 +61,7 @@ qemu: $(BUILD)/harddrive.bin $(BUILD)/firmware.rom
-chardev stdio,id=debug,signal=off,mux=on \
-serial chardev:debug \
-mon chardev=debug \
-device virtio-gpu-pci \
-machine virt \
-net none \
-cpu max \
......
use std::vec::Vec;
use uefi::guid::GuidKind;
pub(crate) static mut RSDPS_AREA: Option<Vec<u8>> = None;
struct Invalid;
fn validate_rsdp(address: usize, v2: bool) -> core::result::Result<usize, Invalid> {
#[repr(packed)]
#[derive(Clone, Copy, Debug)]
struct Rsdp {
signature: [u8; 8], // b"RSD PTR "
chksum: u8,
oem_id: [u8; 6],
revision: u8,
rsdt_addr: u32,
// the following fields are only available for ACPI 2.0, and are reserved otherwise
length: u32,
xsdt_addr: u64,
extended_chksum: u8,
_rsvd: [u8; 3],
}
// paging is not enabled at this stage; we can just read the physical address here.
let rsdp_bytes = unsafe { core::slice::from_raw_parts(address as *const u8, core::mem::size_of::<Rsdp>()) };
let rsdp = unsafe { (rsdp_bytes.as_ptr() as *const Rsdp).as_ref::<'static>().unwrap() };
log::debug!("RSDP: {:?}", rsdp);
if rsdp.signature != *b"RSD PTR " {
return Err(Invalid);
}
let mut base_sum = 0u8;
for base_byte in &rsdp_bytes[..20] {
base_sum = base_sum.wrapping_add(*base_byte);
}
if base_sum != 0 {
return Err(Invalid);
}
if rsdp.revision == 2 {
let mut extended_sum = 0u8;
for byte in rsdp_bytes {
extended_sum = extended_sum.wrapping_add(*byte);
}
if extended_sum != 0 {
return Err(Invalid);
}
}
let length = if rsdp.revision == 2 { rsdp.length as usize } else { core::mem::size_of::<Rsdp>() };
Ok(length)
}
pub(crate) fn find_acpi_table_pointers() {
let rsdps_area = unsafe {
RSDPS_AREA = Some(Vec::new());
RSDPS_AREA.as_mut().unwrap()
};
let cfg_tables = std::system_table().config_tables();
for (address, v2) in cfg_tables.iter().find_map(|cfg_table| {
if cfg_table.VendorGuid.kind() == GuidKind::Acpi {
Some((cfg_table.VendorTable, false))
} else if cfg_table.VendorGuid.kind() == GuidKind::Acpi2 {
Some((cfg_table.VendorTable, true))
} else {
None
}
}) {
match validate_rsdp(address, v2) {
Ok(length) => {
let align = 8;
rsdps_area.extend(&u32::to_ne_bytes(length as u32));
rsdps_area.extend(unsafe { core::slice::from_raw_parts(address as *const u8, length) });
rsdps_area.resize(((rsdps_area.len() + (align - 1)) / align) * align, 0u8);
}
Err(_) => log::warn!("Found RSDP that was not valid at {:p}", address as *const u8),
}
}
}
use core::{mem, ptr};
use uefi::guid::Guid;
use uefi::status::{Error, Result};
use std::vec::Vec;
use uefi::status::Result;
use crate::{
KernelArgs,
......@@ -9,6 +9,11 @@ use crate::{
use super::super::{
OsEfi,
exit_boot_services,
acpi::{
RSDPS_AREA,
find_acpi_table_pointers,
},
};
use self::memory_map::memory_map;
......@@ -19,37 +24,11 @@ mod paging;
static PHYS_OFFSET: u64 = 0xFFFF800000000000;
static mut DTB_PHYSICAL: u64 = 0;
#[no_mangle]
pub extern "C" fn __chkstk() {
//TODO
}
unsafe fn exit_boot_services(key: usize) {
let handle = std::handle();
let uefi = std::system_table();
let _ = (uefi.BootServices.ExitBootServices)(handle, key);
}
static DTB_GUID: Guid = Guid(0xb1b621d5, 0xf19c, 0x41a5, [0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0]);
fn find_dtb() -> Result<()> {
let cfg_tables = std::system_table().config_tables();
for cfg_table in cfg_tables.iter() {
if cfg_table.VendorGuid == DTB_GUID {
unsafe {
DTB_PHYSICAL = cfg_table.VendorTable as u64;
println!("DTB: {:X}", DTB_PHYSICAL);
}
return Ok(());
}
}
println!("Failed to find DTB");
Err(Error::NotFound)
}
unsafe extern "C" fn kernel_entry(
page_phys: usize,
stack: u64,
......@@ -60,27 +39,37 @@ unsafe extern "C" fn kernel_entry(
let key = memory_map();
exit_boot_services(key);
// Enable paging
// Disable interrupts
asm!("msr daifset, #2");
// Enable paging
paging();
//TODO: Set stack
// Call kernel entry
let entry_fn: extern "C" fn(dtb: u64) -> ! = mem::transmute(func);
entry_fn(DTB_PHYSICAL);
let entry_fn: extern "C" fn(*const KernelArgs) -> ! = mem::transmute(func);
entry_fn(args);
}
pub fn main() -> Result<()> {
LOGGER.init();
find_dtb()?;
//TODO: support this in addition to ACPI?
// let dtb = find_dtb()?;
find_acpi_table_pointers();
let mut os = OsEfi {
st: std::system_table(),
};
let (page_phys, args) = crate::main(&mut os);
let (page_phys, mut args) = crate::main(&mut os);
unsafe {
args.acpi_rsdps_base = RSDPS_AREA.as_ref().map(Vec::as_ptr).unwrap_or(core::ptr::null()) as usize as u64 + PHYS_OFFSET;
args.acpi_rsdps_size = RSDPS_AREA.as_ref().map(Vec::len).unwrap_or(0) as u64;
kernel_entry(
page_phys,
args.stack_base + args.stack_size + PHYS_OFFSET,
......
use core::{
mem,
ptr
};
use std::{
vec::Vec,
};
use uefi::{
guid::GuidKind,
status::Result,
};
use core::{mem, ptr};
use std::vec::Vec;
use uefi::status::Result;
use crate::{
KernelArgs,
......@@ -17,6 +9,11 @@ use crate::{
use super::super::{
OsEfi,
exit_boot_services,
acpi::{
RSDPS_AREA,
find_acpi_table_pointers,
},
};
use self::memory_map::memory_map;
......@@ -27,96 +24,6 @@ mod paging;
static PHYS_OFFSET: u64 = 0xFFFF800000000000;
static mut RSDPS_AREA: Option<Vec<u8>> = None;
unsafe fn exit_boot_services(key: usize) {
let handle = std::handle();
let uefi = std::system_table();
let _ = (uefi.BootServices.ExitBootServices)(handle, key);
}
struct Invalid;
fn validate_rsdp(address: usize, v2: bool) -> core::result::Result<usize, Invalid> {
#[repr(packed)]
#[derive(Clone, Copy, Debug)]
struct Rsdp {
signature: [u8; 8], // b"RSD PTR "
chksum: u8,
oem_id: [u8; 6],
revision: u8,
rsdt_addr: u32,
// the following fields are only available for ACPI 2.0, and are reserved otherwise
length: u32,
xsdt_addr: u64,
extended_chksum: u8,
_rsvd: [u8; 3],
}
// paging is not enabled at this stage; we can just read the physical address here.
let rsdp_bytes = unsafe { core::slice::from_raw_parts(address as *const u8, core::mem::size_of::<Rsdp>()) };
let rsdp = unsafe { (rsdp_bytes.as_ptr() as *const Rsdp).as_ref::<'static>().unwrap() };
log::debug!("RSDP: {:?}", rsdp);
if rsdp.signature != *b"RSD PTR " {
return Err(Invalid);
}
let mut base_sum = 0u8;
for base_byte in &rsdp_bytes[..20] {
base_sum = base_sum.wrapping_add(*base_byte);
}
if base_sum != 0 {
return Err(Invalid);
}
if rsdp.revision == 2 {
let mut extended_sum = 0u8;
for byte in rsdp_bytes {
extended_sum = extended_sum.wrapping_add(*byte);
}
if extended_sum != 0 {
return Err(Invalid);
}
}
let length = if rsdp.revision == 2 { rsdp.length as usize } else { core::mem::size_of::<Rsdp>() };
Ok(length)
}
fn find_acpi_table_pointers() {
let rsdps_area = unsafe {
RSDPS_AREA = Some(Vec::new());
RSDPS_AREA.as_mut().unwrap()
};
let cfg_tables = std::system_table().config_tables();
for (address, v2) in cfg_tables.iter().find_map(|cfg_table| {
if cfg_table.VendorGuid.kind() == GuidKind::Acpi {
Some((cfg_table.VendorTable, false))
} else if cfg_table.VendorGuid.kind() == GuidKind::Acpi2 {
Some((cfg_table.VendorTable, true))
} else {
None
}
}) {
match validate_rsdp(address, v2) {
Ok(length) => {
let align = 8;
rsdps_area.extend(&u32::to_ne_bytes(length as u32));
rsdps_area.extend(unsafe { core::slice::from_raw_parts(address as *const u8, length) });
rsdps_area.resize(((rsdps_area.len() + (align - 1)) / align) * align, 0u8);
}
Err(_) => log::warn!("Found RSDP that was not valid at {:p}", address as *const u8),
}
}
}
unsafe extern "C" fn kernel_entry(
page_phys: usize,
stack: u64,
......@@ -137,7 +44,7 @@ unsafe extern "C" fn kernel_entry(
llvm_asm!("mov rsp, $0" : : "r"(stack) : "memory" : "intel", "volatile");
// Call kernel entry
let entry_fn: extern "sysv64" fn(args_ptr: *const KernelArgs) -> ! = mem::transmute(func);
let entry_fn: extern "sysv64" fn(*const KernelArgs) -> ! = mem::transmute(func);
entry_fn(args);
}
......
use uefi::guid::Guid;
use uefi::status::{Error, Result};
static DTB_GUID: Guid = Guid(0xb1b621d5, 0xf19c, 0x41a5, [0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0]);
pub(crate) fn find_dtb() -> Result<u64> {
let cfg_tables = std::system_table().config_tables();
for cfg_table in cfg_tables.iter() {
if cfg_table.VendorGuid == DTB_GUID {
let addr = cfg_table.VendorTable as u64;
println!("DTB: {:X}", addr);
return Ok(addr);
}
}
println!("Failed to find DTB");
Err(Error::NotFound)
}
......@@ -27,19 +27,14 @@ use self::{
video_mode::VideoModeIter,
};
mod acpi;
mod arch;
mod disk;
mod display;
mod dtb;
mod memory_map;
mod video_mode;
fn status_to_result(status: Status) -> Result<usize> {
match status.branch() {
ControlFlow::Continue(ok) => Ok(ok),
ControlFlow::Break(err) => Err(err),
}
}
pub struct OsEfi {
st: &'static SystemTable,
}
......@@ -207,6 +202,20 @@ impl Os<
}
}
unsafe fn exit_boot_services(key: usize) {
let handle = std::handle();
let uefi = std::system_table();
let _ = (uefi.BootServices.ExitBootServices)(handle, key);
}
fn status_to_result(status: Status) -> Result<usize> {
match status.branch() {
ControlFlow::Continue(ok) => Ok(ok),
ControlFlow::Break(err) => Err(err),
}
}
fn set_max_mode(output: &uefi::text::TextOutput) -> Result<()> {
let mut max_i = None;
let mut max_w = 0;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment