Skip to content

Commit

Permalink
limine+aarch64: add DeviceTree blob passing via boot protocol
Browse files Browse the repository at this point in the history
  • Loading branch information
Qix- committed Sep 6, 2024
1 parent 170753b commit 6e6440d
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 66 deletions.
5 changes: 3 additions & 2 deletions clippy.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
doc-valid-idents = [
"..",
"..", # Include the built-in valid idents list
"x86_64", "AArch64", "ARMv8",
"ANDing", "ORing",
"snake_case", "TitleCase",
"CONST_CASE"
"CONST_CASE",
"DeviceTree",
]
20 changes: 19 additions & 1 deletion oro-arch-aarch64/src/boot/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,41 @@
mod memory;
mod protocol;

use oro_boot_protocol::device_tree::DeviceTreeKind;
use oro_debug::dbg;

/// Boots the primary core on AArch64.
///
/// # Safety
/// Meant only to be called by the entry point.
/// Do not call this directly. It does not reset
/// the kernel or anything else magic like that.
///
/// # Panics
/// Panics if the DeviceTree blob is not provided.
pub unsafe fn boot_primary() -> ! {
crate::asm::disable_interrupts();

#[allow(unused_variables)] // XXX(qix-): Temporary for CI
let memory::PreparedMemory { pfa: _pfa, pat } = memory::prepare_memory();

// We now have a valid physical map; let's re-init
// any MMIO loggers with that offset.
#[cfg(debug_assertions)]
oro_debug::init_with_offset(pat.offset());

oro_debug::dbg!("is this thing on?");
// Get the devicetree blob.
let DeviceTreeKind::V0(dtb) = protocol::DTB_REQUEST
.response()
.expect("no DeviceTree blob response was provided")
else {
panic!("DeviceTree blob response was provided but was the wrong revision");
};

dbg!(
"got DeviceTree blob of {} bytes",
dtb.assume_init_ref().length
);

crate::asm::halt();
}
9 changes: 8 additions & 1 deletion oro-arch-aarch64/src/boot/protocol.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
//! Kernel boot protocol requests for the AArch64 architecture.

use oro_boot_protocol::MemoryMapRequest;
use oro_boot_protocol::{DeviceTreeRequest, MemoryMapRequest};

/// The memory map request.
///
/// Required.
#[used]
#[link_section = ".oro_boot"]
pub static MMAP_REQUEST: MemoryMapRequest = MemoryMapRequest::with_revision(0);

/// The DeviceTree blob request.
///
/// Required.
#[used]
#[link_section = ".oro_boot"]
pub static DTB_REQUEST: DeviceTreeRequest = DeviceTreeRequest::with_revision(0);
17 changes: 17 additions & 0 deletions oro-boot-protocol/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,23 @@ macros::oro_boot_protocol! {
}
}

/// Kernel request for the DeviceTree blob, if available.
///
/// If no DeviceTree blob is provided on architectures that
/// support it, some kernels may opt to use the ACPI configuration
/// instead (via the [`AcpiRequest`]).
///
/// Otherwise, if no DeviceTree blob is provided and no ACPI
/// configuration is provided, the kernel may panic.
b"ORO_DTRB" => DeviceTree {
0 => {
/// The physical address of the DeviceTree blob.
pub base: u64,
/// The length of the DeviceTree blob.
pub length: u64,
}
}

/// Kernel request for a list of modules to load and
/// place onto the root ring.
b"ORO_MODS" => Modules {
Expand Down
155 changes: 93 additions & 62 deletions oro-bootloader-limine/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ const KERNEL_STACK_PAGES: usize = 16;
/// as a module (but it can be).
const KERNEL_PATH: &CStr = limine::cstr!("/oro-kernel");

/// The path to where the DeviceTree blob is expected,
/// if provided. The bootloader does **not** expect it to be
/// listed as a module (but it can be).
const DTB_PATH: &CStr = limine::cstr!("/oro-device-tree.dtb");

/// Provides Limine with a base revision of the protocol
/// that this "kernel" (in Limine terms) expects.
#[used]
Expand All @@ -42,6 +47,7 @@ static REQ_MODULES: ModuleRequest = ModuleRequest::with_revision(1).with_interna
&InternalModule::new()
.with_path(KERNEL_PATH)
.with_flags(ModuleFlags::REQUIRED),
&InternalModule::new().with_path(DTB_PATH),
]);

/// Requests that Limine performs a Higher Half Direct Map (HHDM)
Expand Down Expand Up @@ -116,77 +122,102 @@ pub unsafe fn init() -> ! {
let hhdm_offset = hhdm_response.offset();

(|| {
Err(oro_boot::OroBootstrapper::bootstrap(
hhdm_offset,
KERNEL_STACK_PAGES,
{
use oro_boot_protocol::{MemoryMapEntry, MemoryMapEntryType};

let mmap_response = get_response!(REQ_MMAP, "memory mapping");
Err({
let bs = oro_boot::OroBootstrapper::bootstrap(
hhdm_offset,
KERNEL_STACK_PAGES,
{
use oro_boot_protocol::{MemoryMapEntry, MemoryMapEntryType};

let mmap_response = get_response!(REQ_MMAP, "memory mapping");

mmap_response.entries().iter().map(|region| {
MemoryMapEntry {
next: 0,
base: region.base,
length: region.length,
ty: match region.entry_type {
EntryType::USABLE | EntryType::BOOTLOADER_RECLAIMABLE => {
MemoryMapEntryType::Usable
}
EntryType::KERNEL_AND_MODULES => MemoryMapEntryType::Modules,
EntryType::BAD_MEMORY => MemoryMapEntryType::Bad,
_ => MemoryMapEntryType::Unknown,
},
used: {
let used = if region.entry_type == EntryType::BOOTLOADER_RECLAIMABLE
{
region.length
} else {
0
};

// On x86/x86_64, the first 1MiB of memory is reserved and must not be used.
// We have to set this to at least however many bytes are in the first MiB.
#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
let used = if region.base < MIB1 {
let end = region.base + region.length;
let end_mib = end.min(MIB1);
used.max(end_mib - region.base)
} else {
used
};

mmap_response.entries().iter().map(|region| {
MemoryMapEntry {
next: 0,
base: region.base,
length: region.length,
ty: match region.entry_type {
EntryType::USABLE | EntryType::BOOTLOADER_RECLAIMABLE => {
MemoryMapEntryType::Usable
}
EntryType::KERNEL_AND_MODULES => MemoryMapEntryType::Modules,
EntryType::BAD_MEMORY => MemoryMapEntryType::Bad,
_ => MemoryMapEntryType::Unknown,
},
used: {
let used = if region.entry_type == EntryType::BOOTLOADER_RECLAIMABLE {
region.length
} else {
0
};

// On x86/x86_64, the first 1MiB of memory is reserved and must not be used.
// We have to set this to at least however many bytes are in the first MiB.
#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
let used = if region.base < MIB1 {
let end = region.base + region.length;
let end_mib = end.min(MIB1);
used.max(end_mib - region.base)
} else {
used
};

used
},
},
}
})
},
{
use oro_boot_protocol::Module;

let module_response = get_response!(REQ_MODULES, "module listing");
let kernel_module = module_response
.modules()
.iter()
.find(|module| module.path() == KERNEL_PATH.to_bytes());

let Some(kernel_module) = kernel_module else {
panic!("failed to find kernel module: {KERNEL_PATH:?}");
};

Module {
// Expects a physical address but the Limine system gives us
// a virtual address. We have to un-translate it.
base: u64::try_from(kernel_module.addr() as usize).unwrap() - hhdm_offset,
length: kernel_module.size(),
next: 0,
}
},
)?;

let bs = if let Some(rsdp) = REQ_RSDP.get_response() {
bs.send(oro_boot_protocol::acpi::AcpiDataV0 {
rsdp: rsdp.address() as u64 - hhdm_offset,
})
},
{
use oro_boot_protocol::Module;
} else {
bs
};

let module_response = get_response!(REQ_MODULES, "module listing");
let kernel_module = module_response
let bs = if let Some(modules) = REQ_MODULES.get_response() {
if let Some(dtb_module) = modules
.modules()
.iter()
.find(|module| module.path() == KERNEL_PATH.to_bytes());

let Some(kernel_module) = kernel_module else {
panic!("failed to find kernel module: {KERNEL_PATH:?}");
};

Module {
// Expects a physical address but the Limine system gives us
// a virtual address. We have to un-translate it.
base: u64::try_from(kernel_module.addr() as usize).unwrap() - hhdm_offset,
length: kernel_module.size(),
next: 0,
.find(|module| module.path() == DTB_PATH.to_bytes())
{
bs.send(oro_boot_protocol::device_tree::DeviceTreeDataV0 {
base: u64::try_from(dtb_module.addr() as usize).unwrap() - hhdm_offset,
length: dtb_module.size(),
})
} else {
bs
}
},
)?
.send(oro_boot_protocol::acpi::AcpiDataV0 {
rsdp: get_response!(REQ_RSDP, "rsdp pointer").address() as u64 - hhdm_offset,
} else {
bs
};

bs.boot_to_kernel().unwrap_err()
})
.boot_to_kernel()
.unwrap_err())
})()
.unwrap()
}
Expand Down

0 comments on commit 6e6440d

Please sign in to comment.