Verified Commit 1dfe98ef authored by Jeremy Soller's avatar Jeremy Soller
Browse files

Use ACPI for aarch64

parent 5baae1cc
......@@ -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;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment