loader.rs 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. use elf_rs::{ElfFile, ProgramHeaderEntry, ProgramType};
  2. use multiboot2::{
  3. BootLoaderNameTag, CommandLineTag, MemoryArea, MemoryAreaType, MemoryMapTag,
  4. ModuleTag,
  5. };
  6. /// Loads the first module into memory. Assumes that the module is a ELF file.
  7. /// The handoff is performed according to the Multiboot2 spec.
  8. pub fn load_module(mut modules: multiboot::information::ModuleIter) -> ! {
  9. // Load the ELF from the Multiboot1 boot module.
  10. let elf_mod = modules.next().expect("Should have payload");
  11. let elf_bytes = unsafe {
  12. core::slice::from_raw_parts(
  13. elf_mod.start as *const u64 as *const u8,
  14. (elf_mod.end - elf_mod.start) as usize,
  15. )
  16. };
  17. let elf = elf_rs::Elf32::from_bytes(elf_bytes).expect("Should be valid ELF");
  18. // Check if a header is present.
  19. {
  20. let hdr = multiboot2_header::Multiboot2Header::find_header(elf_bytes)
  21. .unwrap()
  22. .expect("Should have Multiboot2 header");
  23. let hdr =
  24. unsafe { multiboot2_header::Multiboot2Header::load(hdr.0.as_ptr().cast()) }.unwrap();
  25. log::info!("Multiboot2 header:\n{hdr:#?}");
  26. }
  27. // Map the load segments into memory (at their corresponding link).
  28. {
  29. let elf = elf_rs::Elf32::from_bytes(elf_bytes).expect("Should be valid ELF");
  30. elf.program_header_iter()
  31. .filter(|ph| ph.ph_type() == ProgramType::LOAD)
  32. .for_each(|ph| {
  33. map_memory(ph);
  34. });
  35. }
  36. // Currently, the MBI is not enriched with "real" information as requested.
  37. // Subject here is not to write a feature-complete bootloader but to test
  38. // that the basic data structures are usable.
  39. // build MBI
  40. let mbi = multiboot2::builder::InformationBuilder::new()
  41. .bootloader_name_tag(BootLoaderNameTag::new("mb2_integrationtest_chainloader"))
  42. .command_line_tag(CommandLineTag::new("chainloaded YEAH"))
  43. // random non-sense memory map
  44. .memory_map_tag(MemoryMapTag::new(&[MemoryArea::new(
  45. 0,
  46. 0xffffffff,
  47. MemoryAreaType::Reserved,
  48. )]))
  49. .add_module_tag(ModuleTag::new(
  50. elf_mod.start as u32,
  51. elf_mod.end as u32,
  52. elf_mod.string.unwrap(),
  53. ))
  54. .build();
  55. log::info!(
  56. "Handing over to ELF: {}",
  57. elf_mod.string.unwrap_or("<unknown>")
  58. );
  59. // handoff
  60. unsafe {
  61. core::arch::asm!(
  62. "jmp *%ecx",
  63. in("eax") multiboot2::MAGIC,
  64. in("ebx") mbi.as_ptr() as u32,
  65. in("ecx") elf.entry_point() as u32,
  66. options(noreturn, att_syntax));
  67. }
  68. }
  69. /// Blindly copies the LOAD segment content at its desired address in physical
  70. /// address space. The loader assumes that the addresses to not clash with the
  71. /// loader (or anything else).
  72. fn map_memory(ph: ProgramHeaderEntry) {
  73. log::debug!("Mapping LOAD segment {ph:#?}");
  74. let dest_ptr = ph.vaddr() as *mut u8;
  75. let content = ph.content().expect("Should have content");
  76. unsafe { core::ptr::copy(content.as_ptr(), dest_ptr, content.len()) };
  77. let dest_ptr = unsafe { dest_ptr.add(ph.filesz() as usize) };
  78. // Zero .bss memory
  79. for _ in 0..(ph.memsz() - ph.filesz()) {
  80. unsafe {
  81. core::ptr::write(dest_ptr, 0);
  82. }
  83. }
  84. }