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