Next Generation WASM Microkernel Operating System
at trap_handler 119 lines 4.0 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::error::Error; 9use core::fmt::Formatter; 10use core::range::Range; 11use core::{fmt, slice}; 12use loader_api::LoaderConfig; 13use xmas_elf::program::{ProgramHeader, Type}; 14 15/// The inlined kernel 16static INLINED_KERNEL_BYTES: KernelBytes = KernelBytes(*include_bytes!(env!("KERNEL"))); 17/// Wrapper type for the inlined bytes to ensure proper alignment 18#[repr(C, align(4096))] 19struct KernelBytes(pub [u8; include_bytes!(env!("KERNEL")).len()]); 20 21/// The decompressed and parsed kernel ELF plus the embedded loader configuration data 22pub struct Kernel<'a> { 23 pub elf_file: xmas_elf::ElfFile<'a>, 24 pub _loader_config: &'a LoaderConfig, 25} 26 27impl Kernel<'static> { 28 pub fn from_static(phys_off: usize) -> crate::Result<Self> { 29 // Safety: The kernel elf file is inlined into the loader executable as part of the build setup 30 // which means we just need to parse it here. 31 let elf_file = xmas_elf::ElfFile::new(unsafe { 32 let base = phys_off 33 .checked_add(INLINED_KERNEL_BYTES.0.as_ptr().addr()) 34 .unwrap(); 35 36 slice::from_raw_parts(base as *mut u8, INLINED_KERNEL_BYTES.0.len()) 37 }) 38 .map_err(Error::Elf)?; 39 40 let loader_config = { 41 let section = elf_file 42 .find_section_by_name(".loader_config") 43 .expect("missing .loader_config section"); 44 let raw = section.raw_data(&elf_file); 45 46 let ptr: *const LoaderConfig = raw.as_ptr().cast(); 47 // Safety: kernel is inlined into the loader, so ptr is always valid 48 let cfg = unsafe { &*ptr }; 49 50 cfg.assert_valid(); 51 cfg 52 }; 53 54 Ok(Kernel { 55 elf_file, 56 _loader_config: loader_config, 57 }) 58 } 59} 60 61impl Kernel<'_> { 62 pub fn phys_range(&self) -> Range<usize> { 63 let fdt = INLINED_KERNEL_BYTES.0.as_ptr_range(); 64 Range::from(fdt.start as usize..fdt.end as usize) 65 } 66 67 /// Returns the size of the kernel in memory. 68 pub fn mem_size(&self) -> u64 { 69 let max_addr = self 70 .loadable_program_headers() 71 .map(|ph| ph.virtual_addr() + ph.mem_size()) 72 .max() 73 .unwrap_or(0); 74 75 let min_addr = self 76 .loadable_program_headers() 77 .map(|ph| ph.virtual_addr()) 78 .min() 79 .unwrap_or(0); 80 81 max_addr - min_addr 82 } 83 84 /// Returns the largest alignment of any loadable segment in the kernel and by extension 85 /// the overall alignment for the kernel. 86 pub fn max_align(&self) -> u64 { 87 let load_program_headers = self.loadable_program_headers(); 88 89 load_program_headers.map(|ph| ph.align()).max().unwrap_or(1) 90 } 91 92 fn loadable_program_headers(&self) -> impl Iterator<Item = ProgramHeader> + '_ { 93 self.elf_file 94 .program_iter() 95 .filter(|ph| ph.get_type().unwrap() == Type::Load) 96 } 97} 98 99impl fmt::Display for Kernel<'_> { 100 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 101 writeln!( 102 f, 103 "Idx Name Offset Vaddr Filesz Memsz" 104 )?; 105 106 for (idx, sec) in self.elf_file.section_iter().enumerate() { 107 writeln!( 108 f, 109 "{idx:>3} {name:<17} {offset:#08x} {vaddr:#016x} {filesz:#08x} {memsz:#08x}", 110 name = sec.get_name(&self.elf_file).unwrap_or(""), 111 offset = sec.offset(), 112 vaddr = sec.address(), 113 filesz = sec.entry_size(), 114 memsz = sec.size(), 115 )?; 116 } 117 Ok(()) 118 } 119}