81 lines
2.7 KiB
Rust
81 lines
2.7 KiB
Rust
// Boot-time userspace setup: init's BootInfo page.
|
|
|
|
use crate::hw::uart::Uart;
|
|
use types::address::VirtualAddress;
|
|
use types::bootinfo::{BOOT_INFO_VA, BootDevice, BootInfo, MAGIC, MAX_BOOT_DEVICES, NO_SLOT};
|
|
use types::id::ProcessId;
|
|
use types::mapping::PagePerms;
|
|
|
|
fn kern() -> &'static mut kernel::Kernel<crate::platform::RiscVPlatform> {
|
|
unsafe { &mut *crate::kernel_ptr() }
|
|
}
|
|
|
|
/// Tells init, in a read-only page at BOOT_INFO_VA, which of its slots hold
|
|
/// each board device's capabilities.
|
|
pub(crate) fn boot_info(
|
|
uart: &Uart,
|
|
init: ProcessId,
|
|
board: &[kernel::BoardDevice],
|
|
kinds: &[u64],
|
|
placed: &[Option<kernel::BoardCaps>],
|
|
boot_caps: kernel::BootCaps,
|
|
) {
|
|
let empty = BootDevice {
|
|
kind: 0,
|
|
phys_base: 0,
|
|
pages: 0,
|
|
irq: 0,
|
|
region_slot: NO_SLOT,
|
|
irq_slot: NO_SLOT,
|
|
};
|
|
let mut info = BootInfo {
|
|
magic: MAGIC,
|
|
device_count: 0,
|
|
system_control_slot: boot_caps.system_control.value() as u64,
|
|
console_slot: boot_caps.console.value() as u64,
|
|
devices: [empty; MAX_BOOT_DEVICES],
|
|
};
|
|
for (((d, kind), caps), out) in board
|
|
.iter()
|
|
.zip(kinds)
|
|
.zip(placed)
|
|
.zip(info.devices.iter_mut())
|
|
{
|
|
let Some(caps) = caps else { continue };
|
|
*out = BootDevice {
|
|
kind: *kind,
|
|
phys_base: d.base.raw() as u64,
|
|
pages: d.pages.value() as u64,
|
|
irq: d.irq.map_or(0, |i| i.raw() as u64),
|
|
region_slot: caps.region.value() as u64,
|
|
irq_slot: caps.irq.map_or(NO_SLOT, |s| s.value() as u64),
|
|
};
|
|
info.device_count += 1;
|
|
}
|
|
// SAFETY: BootInfo is repr(C) and made only of u64s.
|
|
let words = unsafe {
|
|
core::slice::from_raw_parts(
|
|
&info as *const BootInfo as *const u64,
|
|
core::mem::size_of::<BootInfo>() / 8,
|
|
)
|
|
};
|
|
write_page(uart, init, BOOT_INFO_VA, words);
|
|
}
|
|
|
|
/// Writes `words` into a fresh read-only page mapped at `va` in `pid`.
|
|
fn write_page(uart: &Uart, pid: ProcessId, va: usize, words: &[u64]) {
|
|
let va = VirtualAddress::from_raw(va);
|
|
kern()
|
|
.map_fresh_range(pid, va, 1, PagePerms::ReadOnly)
|
|
.unwrap_or_else(|_| crate::halt(uart, "boot info page failed"));
|
|
let pa = kern()
|
|
.user_page_frame(pid, va)
|
|
.unwrap_or_else(|| crate::halt(uart, "boot info page vanished"));
|
|
let page = crate::mmu::phys_to_virt(pa.raw()) as *mut u64;
|
|
for (i, &w) in words.iter().take(crate::mmu::PAGE_SIZE / 8).enumerate() {
|
|
// SAFETY: `pa` is a pool frame just mapped for `pid`, reachable at
|
|
// `phys_to_virt`, and at most one page is written.
|
|
unsafe { core::ptr::write_volatile(page.add(i), w) };
|
|
}
|
|
}
|