linux_bzimage_builder/
lib.rs1pub mod encoder;
17mod mapping;
18mod pe_header;
19
20use std::{
21 fs::File,
22 io::{Read, Seek, SeekFrom, Write},
23 path::Path,
24};
25
26use align_ext::AlignExt;
27pub use encoder::{encode_kernel, PayloadEncoding};
28use mapping::{SetupFileOffset, SetupVA};
29use xmas_elf::{program::SegmentData, sections::SectionData};
30
31pub enum BzImageType {
35 Legacy32,
36 Efi64,
37}
38
39pub fn make_bzimage(target_image_path: &Path, image_type: BzImageType, setup_elf_path: &Path) {
47 let mut setup_elf = Vec::new();
48 File::open(setup_elf_path)
49 .unwrap()
50 .read_to_end(&mut setup_elf)
51 .unwrap();
52 let mut setup = to_flat_binary(&setup_elf);
53 setup.resize(setup.len().align_up(pe_header::SECTION_ALIGNMENT), 0x00);
55
56 let mut kernel_image = File::create(target_image_path).unwrap();
57 kernel_image.write_all(&setup).unwrap();
58
59 if matches!(image_type, BzImageType::Efi64) {
60 assert_elf64_reloc_supported(&setup_elf);
61
62 let pe_header = pe_header::make_pe_coff_header(&setup_elf);
66 assert!(pe_header.len() <= 0x1f1, "PE/COFF header is too large");
67
68 kernel_image.seek(SeekFrom::Start(0)).unwrap();
69 kernel_image.write_all(&pe_header).unwrap();
70 }
71}
72
73pub fn legacy32_rust_target_json() -> &'static str {
75 include_str!("x86_64-i386_pm-none.json")
76}
77
78fn to_flat_binary(elf_file: &[u8]) -> Vec<u8> {
85 let elf = xmas_elf::ElfFile::new(elf_file).unwrap();
86 let mut bin = Vec::<u8>::new();
87
88 for program in elf.program_iter() {
89 if program.get_type().unwrap() == xmas_elf::program::Type::Load {
90 let SegmentData::Undefined(header_data) = program.get_data(&elf).unwrap() else {
91 panic!("Unexpected segment data type");
92 };
93 let dst_file_offset = usize::from(SetupFileOffset::from(SetupVA::from(
94 program.virtual_addr() as usize,
95 )));
96
97 let mem_length = program.mem_size() as usize;
100 if bin.len() < dst_file_offset + mem_length {
101 bin.resize(dst_file_offset + mem_length, 0);
102 }
103
104 let file_length = program.file_size() as usize;
106 let dest_slice = bin[dst_file_offset..dst_file_offset + file_length].as_mut();
107 dest_slice.copy_from_slice(header_data);
108 }
109 }
110
111 bin
112}
113
114fn assert_elf64_reloc_supported(elf_file: &[u8]) {
115 const R_X86_64_RELATIVE: u32 = 8;
116
117 let elf = xmas_elf::ElfFile::new(elf_file).unwrap();
118
119 let SectionData::Rela64(rela64) = elf
120 .find_section_by_name(".rela")
121 .unwrap()
122 .get_data(&elf)
123 .unwrap()
124 else {
125 panic!("the ELF64 relocation data is not of the correct type");
126 };
127
128 rela64.iter().for_each(|r| {
129 assert_eq!(
130 r.get_type(),
131 R_X86_64_RELATIVE,
132 "the ELF64 relocation type is not supported"
133 )
134 });
135}