Skip to content

Commit

Permalink
kernel+common+x86_64+aarch64: add and transfer boot config
Browse files Browse the repository at this point in the history
  • Loading branch information
Qix- committed Jul 29, 2024
1 parent afa9768 commit 731bfe6
Show file tree
Hide file tree
Showing 16 changed files with 314 additions and 21 deletions.
8 changes: 6 additions & 2 deletions oro-arch-aarch64/src/arch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,11 @@ unsafe impl Arch for Aarch64 {
}
}

unsafe fn transfer(entry: usize, transfer_token: Self::TransferToken) -> ! {
crate::xfer::transfer(entry, &transfer_token);
unsafe fn transfer(
entry: usize,
transfer_token: Self::TransferToken,
boot_config_virt: usize,
) -> ! {
crate::xfer::transfer(entry, &transfer_token, boot_config_virt);
}
}
40 changes: 40 additions & 0 deletions oro-arch-aarch64/src/mem/address_space.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ pub struct AddressSpaceHandle {
pub struct AddressSpaceLayout;

impl AddressSpaceLayout {
/// The index for the kernel boot protocol.
pub const BOOT_INFO_IDX: usize = 302;
/// The direct map range
pub const DIRECT_MAP_IDX: (usize, usize) = (258, 300);
/// The kernel executable range, shared by the RX, RO, and RW segments.
Expand Down Expand Up @@ -356,4 +358,42 @@ unsafe impl AddressSpace for AddressSpaceLayout {

&DESCRIPTOR
}

fn boot_info() -> Self::SupervisorSegment {
#[allow(clippy::missing_docs_in_private_items)]
static DESCRIPTOR: Segment = unsafe {
Segment {
valid_range: (
AddressSpaceLayout::BOOT_INFO_IDX,
AddressSpaceLayout::BOOT_INFO_IDX,
),
l0_template: L0PageTableDescriptor::new()
.with_valid()
.with_table_access_permissions(PageTableEntryTableAccessPerm::KernelOnly)
.with_user_no_exec()
.with_kernel_no_exec(),
l1_table_template: L1PageTableDescriptor::new()
.with_valid()
.with_table_access_permissions(PageTableEntryTableAccessPerm::KernelOnly)
.with_user_no_exec()
.with_kernel_no_exec(),
l2_table_template: L2PageTableDescriptor::new()
.with_valid()
.with_table_access_permissions(PageTableEntryTableAccessPerm::KernelOnly)
.with_user_no_exec()
.with_kernel_no_exec(),
l3_template: L3PageTableBlockDescriptor::new()
.with_valid()
.with_block_access_permissions(
PageTableEntryBlockAccessPerm::KernelROUserNoAccess,
)
.with_user_no_exec()
.with_kernel_no_exec()
.with_not_secure()
.with_mair_index(MairEntry::KernelRo.index() as u64),
}
};

&DESCRIPTOR
}
}
10 changes: 5 additions & 5 deletions oro-arch-aarch64/src/xfer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ where
///
/// # Safety
/// Only to be called ONCE per core, and only by the [`oro_common::Arch`] implementation.
pub unsafe fn transfer(entry: usize, transfer_token: &TransferToken) -> ! {
pub unsafe fn transfer(entry: usize, transfer_token: &TransferToken, boot_config_virt: usize) -> ! {
let page_table_phys: u64 = transfer_token.ttbr1_page_table_phys;
let stack_addr: usize = transfer_token.stack_ptr;
let mair_value: u64 = MairEntry::build_mair().into();
Expand Down Expand Up @@ -160,8 +160,6 @@ pub unsafe fn transfer(entry: usize, transfer_token: &TransferToken) -> ! {
);

// Populate registers and jump to stubs
// SAFETY(qix-): `x9` is used by the transfer stubs as a temporary register.
// SAFETY(qix-): Do not use it for transferring values.
asm!(
"isb",
"br x4",
Expand All @@ -173,7 +171,8 @@ pub unsafe fn transfer(entry: usize, transfer_token: &TransferToken) -> ! {
in("x5") tcr_el1_raw,
in("x6") core_id,
in("x7") core_is_primary,
// SAFETY(qix-): Do not use `x9` for transferring values.
// SAFETY(qix-): Do not use `x8` or `x9` for transferring values.
in("x10") boot_config_virt,
options(noreturn)
);
}
Expand Down Expand Up @@ -231,12 +230,13 @@ unsafe extern "C" fn transfer_stubs() -> ! {
/// entry points in the kernel. DO NOT USE THIS MACRO IN PRE-BOOT ENVIRONMENTS.
#[macro_export]
macro_rules! transfer_params {
($core_id:path, $core_is_primary:path) => {{
($core_id:path, $core_is_primary:path, $boot_config_virt:path) => {{
::oro_common::assert_unsafe!();
::core::arch::asm!(
"",
out("x6") $core_id,
out("x7") $core_is_primary,
out("x10") $boot_config_virt,
options(nostack, nomem),
);
}};
Expand Down
8 changes: 6 additions & 2 deletions oro-arch-x86_64/src/arch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,8 +250,12 @@ unsafe impl Arch for X86_64 {
}
}

unsafe fn transfer(entry: usize, transfer_token: Self::TransferToken) -> ! {
crate::xfer::transfer(entry, &transfer_token)
unsafe fn transfer(
entry: usize,
transfer_token: Self::TransferToken,
boot_config_virt: usize,
) -> ! {
crate::xfer::transfer(entry, &transfer_token, boot_config_virt)
}

#[inline(always)]
Expand Down
20 changes: 20 additions & 0 deletions oro-arch-x86_64/src/mem/address_space.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ impl MapperHandle for AddressSpaceHandle {
pub struct AddressSpaceLayout;

impl AddressSpaceLayout {
/// The index for the kernel boot protocol.
pub const BOOT_INFO_IDX: usize = 302;
/// The direct map range
pub const DIRECT_MAP_IDX: (usize, usize) = (258, 300);
/// The kernel executable range, shared by the RX, RO, and RW segments.
Expand Down Expand Up @@ -198,4 +200,22 @@ unsafe impl AddressSpace for AddressSpaceLayout {

&DESCRIPTOR
}

fn boot_info() -> Self::SupervisorSegment {
#[allow(clippy::missing_docs_in_private_items)]
const DESCRIPTOR: AddressSegment = AddressSegment {
valid_range: (
AddressSpaceLayout::BOOT_INFO_IDX,
AddressSpaceLayout::BOOT_INFO_IDX,
),
entry_template: PageTableEntry::new()
.with_global()
.with_present()
.with_no_exec()
.with_writable()
.with_write_through(),
};

&DESCRIPTOR
}
}
6 changes: 4 additions & 2 deletions oro-arch-x86_64/src/xfer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ pub fn target_address() -> usize {
///
/// # Safety
/// Only to be called ONCE per core, and only by the [`oro_common::Arch`] implementation.
pub unsafe fn transfer(entry: usize, transfer_token: &TransferToken) -> ! {
pub unsafe fn transfer(entry: usize, transfer_token: &TransferToken, boot_config_virt: usize) -> ! {
let page_table_phys: u64 = transfer_token.page_table_phys;
let stack_addr: usize = transfer_token.stack_ptr;
let stubs_addr: usize = crate::xfer::target_address();
Expand All @@ -55,6 +55,7 @@ pub unsafe fn transfer(entry: usize, transfer_token: &TransferToken) -> ! {
in("r12") stubs_addr,
in("r13") core_id,
in("r14") core_is_primary,
in("r15") boot_config_virt,
options(noreturn)
);
}
Expand Down Expand Up @@ -94,12 +95,13 @@ unsafe extern "C" fn transfer_stubs() -> ! {
/// entry points in the kernel. DO NOT USE THIS MACRO IN PRE-BOOT ENVIRONMENTS.
#[macro_export]
macro_rules! transfer_params {
($core_id:path, $core_is_primary:path) => {{
($core_id:path, $core_is_primary:path, $boot_config_virt:path) => {{
::oro_common::assert_unsafe!();
::core::arch::asm!(
"",
out("r13") $core_id,
out("r14") $core_is_primary,
out("r15") $boot_config_virt,
options(nostack, nomem),
);
}};
Expand Down
16 changes: 15 additions & 1 deletion oro-common/src/arch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,22 @@ pub unsafe trait Arch {
/// Implementations MUST NOT affect ANY resources that are not
/// local to the CPU core being prepared.
///
/// The boot config virtual address MUST NOT be zero, and MUST be
/// a valid, readable readable address (as specified by
/// [`crate::mem::AddressSpace::boot_info()`]) mapped into the
/// kernel's eventual address space, whereby a cast to a pointer to
/// [`crate::boot::BootConfig`] is valid and dereferenceable without
/// invoking undefined behavior.
///
/// Implementations MUST NOT derefence the boot config virtual address
/// as it is not valid in the pre-boot memory map.
///
/// This method **must not panic**.
unsafe fn transfer(entry: usize, transfer_token: Self::TransferToken) -> !;
unsafe fn transfer(
entry: usize,
transfer_token: Self::TransferToken,
boot_config_virt: usize,
) -> !;

/// Cleans up resources after the transfer has been completed.
/// Execution is now in the kernel; all architecture-specific
Expand Down
1 change: 1 addition & 0 deletions oro-common/src/boot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
//! Note that no core-specific information is provided here, as
//! that is handled by passing information to the kernel via
//! architecture-specific transfer stubs.
#![allow(rustdoc::private_intra_doc_links)]

use crate::ser2mem::Ser2Mem;

Expand Down
39 changes: 35 additions & 4 deletions oro-common/src/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use crate::{
AddressSegment, AddressSpace, FiloPageFrameAllocator, MemoryRegion, MemoryRegionType,
PageFrameAllocate, PageFrameFree, PhysicalAddressTranslator,
},
ser2mem::Serialize,
sync::{SpinBarrier, UnfairSpinlock},
util::{assertions, proxy::Proxy},
Arch,
Expand Down Expand Up @@ -292,6 +293,10 @@ where
// Finally, for good measure, make sure that we barrier here so we're all on the same page.
wait_for_all_cores!(config);

// Create a spot where the boot config virtual address can be stored for passing to
// the kernel during transfer.
let boot_config_shared_virt = UnfairSpinlock::<A, usize>::new(0x0);

// Next, we create the supervisor mapper. This has two steps, as the value returned
// is going to be different for every core.
//
Expand Down Expand Up @@ -467,12 +472,31 @@ where
);

// Write the boot config.
// TODO(qix-)
#[allow(clippy::no_effect_underscore_binding)]
let _boot_config = <BootConfig as crate::ser2mem::Proxy>::Proxy {
let boot_config = <BootConfig as crate::ser2mem::Proxy>::Proxy {
core_count: *num_instances,
};

// FIXME(qix-): The strange types here are required to work around a
// FIXME(qix-): bug in rustc (rust-lang/rust#121613)
let pfa_mut = &mut *pfa;
let mut serializer = crate::mem::PfaSerializer::<_, _, <A as Arch>::AddressSpace>::new(
pfa_mut,
physical_address_translator,
&kernel_mapper,
);

let boot_config_target_virt = boot_config
.serialize(&mut serializer)
.expect("failed to serialize boot config");
(*boot_config_shared_virt.lock()) =
::core::ptr::from_ref(boot_config_target_virt) as usize;

dbg!(
A,
"boot_to_kernel",
"boot config serialized to kernel memory"
);

// Store the kernel address space handle and entry point for cloning later.
KERNEL_ADDRESS_SPACE = Proxy::from(kernel_mapper);
KERNEL_ENTRY_POINT = kernel_elf.entry_point();
Expand Down Expand Up @@ -551,6 +575,13 @@ where
dbg!(A, "boot_to_kernel", "all {} core(s) online", num_instances);
}

// Make sure we got the boot config virtual address.
let boot_config_shared_virt = *boot_config_shared_virt.lock();
assert_ne!(
boot_config_shared_virt, 0,
"boot config virtual address not set"
);

// Inform the architecture we are about to jump to the kernel.
// This allows for any architecture-specific, **potentially destructive**
// operations to be performed before the kernel is entered.
Expand Down Expand Up @@ -582,7 +613,7 @@ where
wait_for_all_cores!(config);

// Finally, jump to the kernel entry point.
A::transfer(KERNEL_ENTRY_POINT, transfer_token)
A::transfer(KERNEL_ENTRY_POINT, transfer_token, boot_config_shared_virt)
}

/// Provides the types used by the primary core configuration values
Expand Down
1 change: 1 addition & 0 deletions oro-common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,6 @@ pub(crate) mod util;

pub use self::{
arch::Arch,
boot::BootConfig,
init::{boot_to_kernel, ModuleDef, PrebootConfig, PrebootPrimaryConfig},
};
8 changes: 8 additions & 0 deletions oro-common/src/mem/mapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,14 @@ pub unsafe trait AddressSpace {
///
/// Must **not** overlap with any other segment.
fn direct_map() -> Self::SupervisorSegment;

/// Returns the layout descriptor for the boot protocol information.
///
/// This must be read-only, non-user accessible, and is
/// **not** executable.
///
/// Must **not** overlap with any other segment.
fn boot_info() -> Self::SupervisorSegment;
}

/// An address space segment descriptor. Segments are architecture specified
Expand Down
2 changes: 2 additions & 0 deletions oro-common/src/mem/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
mod mapper;
mod pfa;
mod region;
mod ser2mem;
mod translate;

pub(crate) use self::ser2mem::PfaSerializer;
pub use self::{
mapper::{AddressSegment, AddressSpace, MapError, UnmapError},
pfa::{
Expand Down
Loading

0 comments on commit 731bfe6

Please sign in to comment.