Next Generation WASM Microkernel Operating System
at trap_handler 120 lines 4.3 kB view raw
1// Copyright 2025 Jonas Kruckenberg 2// 3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or 4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or 5// http://opensource.org/licenses/MIT>, at your option. This file may not be 6// copied, modified, or distributed except according to those terms. 7 8use crate::arch; 9use crate::frame_alloc::FrameAllocator; 10use core::alloc::Layout; 11use core::mem::MaybeUninit; 12use core::range::Range; 13use core::slice; 14use loader_api::{BootInfo, MemoryRegion, MemoryRegionKind, MemoryRegions, TlsTemplate}; 15 16#[expect(clippy::too_many_arguments, reason = "")] 17pub fn prepare_boot_info( 18 mut frame_alloc: FrameAllocator, 19 physical_address_offset: usize, 20 physical_memory_map: Range<usize>, 21 kernel_virt: Range<usize>, 22 maybe_tls_template: Option<TlsTemplate>, 23 loader_phys: Range<usize>, 24 kernel_phys: Range<usize>, 25 fdt_phys: Range<usize>, 26 hart_mask: usize, 27 rng_seed: [u8; 32], 28) -> crate::Result<*mut BootInfo> { 29 let frame = frame_alloc.allocate_contiguous_zeroed( 30 Layout::from_size_align(arch::PAGE_SIZE, arch::PAGE_SIZE).unwrap(), 31 arch::KERNEL_ASPACE_BASE, 32 )?; 33 let page = physical_address_offset.checked_add(frame).unwrap(); 34 35 let memory_regions = 36 init_boot_info_memory_regions(page, frame_alloc, fdt_phys, loader_phys, kernel_phys); 37 38 let mut boot_info = BootInfo::new(memory_regions); 39 boot_info.physical_address_offset = physical_address_offset; 40 boot_info.physical_memory_map = physical_memory_map; 41 boot_info.tls_template = maybe_tls_template; 42 boot_info.kernel_virt = kernel_virt; 43 boot_info.kernel_phys = kernel_phys; 44 boot_info.cpu_mask = hart_mask; 45 boot_info.rng_seed = rng_seed; 46 47 let boot_info_ptr = page as *mut BootInfo; 48 // Safety: we just allocated the boot info frame 49 unsafe { boot_info_ptr.write(boot_info) } 50 51 Ok(boot_info_ptr) 52} 53 54fn init_boot_info_memory_regions( 55 page: usize, 56 frame_alloc: FrameAllocator, 57 fdt_phys: Range<usize>, 58 loader_phys: Range<usize>, 59 kernel_phys: Range<usize>, 60) -> MemoryRegions { 61 // Safety: we just allocated a whole frame for the boot info 62 let regions: &mut [MaybeUninit<MemoryRegion>] = unsafe { 63 let base = page.checked_add(size_of::<BootInfo>()).unwrap(); 64 let len = (arch::PAGE_SIZE - size_of::<BootInfo>()) / size_of::<MemoryRegion>(); 65 66 slice::from_raw_parts_mut(base as *mut MaybeUninit<MemoryRegion>, len) 67 }; 68 69 let mut len = 0; 70 let mut push_region = |region: MemoryRegion| { 71 debug_assert!(!region.range.is_empty()); 72 regions[len].write(region); 73 len += 1; 74 }; 75 76 // Report the memory we consumed during startup as used. 77 for used_region in frame_alloc.used_regions() { 78 push_region(MemoryRegion { 79 range: used_region, 80 kind: MemoryRegionKind::Loader, 81 }); 82 } 83 84 // Report the free regions as usable. 85 for free_region in frame_alloc.free_regions() { 86 push_region(MemoryRegion { 87 range: free_region, 88 kind: MemoryRegionKind::Usable, 89 }); 90 } 91 92 // Most of the memory occupied by the loader is not needed once the kernel is running, 93 // but the kernel itself lies somewhere in the loader memory. 94 // 95 // We can still mark the range before and after the kernel as usable. 96 push_region(MemoryRegion { 97 range: Range::from(loader_phys.start..kernel_phys.start), 98 kind: MemoryRegionKind::Usable, 99 }); 100 push_region(MemoryRegion { 101 range: Range::from(kernel_phys.end..loader_phys.end), 102 kind: MemoryRegionKind::Usable, 103 }); 104 105 // Report the flattened device tree as a separate region. 106 push_region(MemoryRegion { 107 range: fdt_phys, 108 kind: MemoryRegionKind::FDT, 109 }); 110 111 // Truncate the slice to include only initialized elements 112 // Safety: closure above ensures the slice up to len is valid 113 let regions = unsafe { regions[0..len].assume_init_mut() }; 114 115 // Sort the memory regions by start address, we do this now in the loader 116 // because the BootInfo struct will be passed as a read-only static reference to the kernel. 117 regions.sort_unstable_by_key(|region| region.range.start); 118 119 MemoryRegions::from(regions) 120}