Create a VM from a complete ELF-64 image by mapping every `PT_LOAD` segment.
(bytes: &[u8])
| 48 | /// This snapshot with both bulk images dropped (RAM and framebuffer planes). |
| 49 | pub fn without_bulk(&self) -> Self { |
| 50 | Self { |
| 51 | cpu: self.cpu.clone(), |
| 52 | devices: self.devices.without_fb(), |
| 53 | ram: Vec::new(), |
| 54 | } |
| 55 | } |
| 56 | |
| 57 | /// This snapshot with both bulk images reattached, ready for |
| 58 | /// [`VirtualMachine::restore`]. |
| 59 | pub fn with_bulk(&self, ram: Vec<u8>, fb: &[u8]) -> Self { |
| 60 | let mut devices = self.devices.clone(); |
| 61 | devices.load_fb_image(fb); |
| 62 | Self { |
| 63 | cpu: self.cpu.clone(), |
| 64 | devices, |
| 65 | ram, |
| 66 | } |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | // --- Constructors --- |
| 71 | |
| 72 | impl VirtualMachine { |
| 73 | /// Create a VM from raw assembled output by exporting it to ELF and loading that image. |
| 74 | pub fn new(assembled: &AssembledOutput) -> Self { |
| 75 | let elf = assembled.to_elf(ELF_LOAD_BASE); |
| 76 | Self::from_elf(&elf).unwrap_or_else(|e| panic!("failed to load assembled ELF: {e}")) |
| 77 | } |
| 78 | |
| 79 | /// Loads the kernel ELF at `RAM_BASE` but resets the CPU to `ROM_BASE`, so the |
| 80 | /// ROM stub sets up PMP and delegation before `mret`ing into S-mode. |
| 81 | pub fn new_kernel(assembled: &AssembledOutput) -> Self { |
| 82 | let elf = assembled.to_elf_with_entry(ELF_LOAD_BASE, "_kernel_start"); |
| 83 | let mut vm = |
| 84 | Self::from_elf(&elf).unwrap_or_else(|e| panic!("failed to load kernel ELF: {e}")); |
| 85 | let entry = vm.cpu.peek_pc(); // ELF entry point (_kernel_start) resolved by from_elf |
| 86 | vm.cpu.reset_pc(crate::rom::ROM_BASE); |
| 87 | vm.cpu.set_boot_entry(entry); // a0 = _kernel_start; ROM _start does `csrw mepc, a0` |
| 88 | vm |
| 89 | } |
| 90 | |
| 91 | /// Create a VM from a complete ELF-64 image by mapping every `PT_LOAD` segment. |
| 92 | pub fn from_elf(bytes: &[u8]) -> Result<Self, VmError> { |
| 93 | let elf = ParsedElf::parse(bytes)?; |
| 94 | |
| 95 | let rom_image = crate::rom::generate_rom_image(); |
| 96 | let mut bus = SystemBus::new(rom_image); |
| 97 | |
| 98 | let image_base = elf |
| 99 | .load_segments |
| 100 | .iter() |
| 101 | .map(|segment| segment.vaddr) |
| 102 | .min() |
| 103 | .unwrap_or(RAM_BASE); |
| 104 | |
| 105 | let mut highest_mapped = RAM_BASE; |
| 106 | for segment in &elf.load_segments { |
nothing calls this directly
no test coverage detected