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