// 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 { 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], 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::() / 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) }; } }