mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-15 16:26:48 +00:00
Style improvements on the boot code
This commit is contained in:
parent
501894652f
commit
11ff35d34e
@ -1,7 +1,6 @@
|
||||
//! The Linux 64-bit Boot Protocol supporting module.
|
||||
//!
|
||||
|
||||
extern crate linux_boot_params;
|
||||
use linux_boot_params::{BootParams, E820Type, LINUX_BOOT_HEADER_MAGIC};
|
||||
|
||||
use crate::boot::{
|
||||
@ -138,7 +137,7 @@ fn init_memory_regions(memory_regions: &'static Once<Vec<MemoryRegion>>) {
|
||||
memory_regions.call_once(|| non_overlapping_regions_from(regions.as_ref()));
|
||||
}
|
||||
|
||||
/// The entry point of of the Rust code portion of Asterinas.
|
||||
/// The entry point of the Rust code portion of Asterinas.
|
||||
#[no_mangle]
|
||||
unsafe extern "sysv64" fn __linux_boot(params_ptr: *const BootParams) -> ! {
|
||||
let params = *params_ptr;
|
||||
|
@ -24,11 +24,98 @@ use xmas_elf::program::SegmentData;
|
||||
|
||||
use mapping::{SetupFileOffset, SetupVA};
|
||||
|
||||
/// The type of the bzImage that we are building through `make_bzimage`.
|
||||
///
|
||||
/// Currently, Legacy32 and Efi64 are mutually exclusive.
|
||||
pub enum BzImageType {
|
||||
Legacy32,
|
||||
Efi64,
|
||||
}
|
||||
|
||||
/// Making a bzImage given the kernel ELF and setup source.
|
||||
///
|
||||
/// Explanations for the arguments:
|
||||
/// - `target_image_path`: The path to the target bzImage.
|
||||
/// - `image_type`: The type of the bzImage that we are building.
|
||||
/// - `kernel_path`: The path to the kernel ELF.
|
||||
/// - `setup_src`: The path to the setup crate.
|
||||
/// - `setup_tmp_out_dir`: The path to the temporary output directory for the setup binary.
|
||||
pub fn make_bzimage(
|
||||
target_image_path: &Path,
|
||||
image_type: BzImageType,
|
||||
kernel_path: &Path,
|
||||
setup_src: &Path,
|
||||
setup_tmp_out_dir: &Path,
|
||||
) {
|
||||
let setup = match image_type {
|
||||
BzImageType::Legacy32 => {
|
||||
let arch = setup_src
|
||||
.join("x86_64-i386_pm-none.json")
|
||||
.canonicalize()
|
||||
.unwrap();
|
||||
build_setup_with_arch(setup_src, setup_tmp_out_dir, &SetupBuildArch::Other(arch))
|
||||
}
|
||||
BzImageType::Efi64 => {
|
||||
build_setup_with_arch(setup_src, setup_tmp_out_dir, &SetupBuildArch::X86_64)
|
||||
}
|
||||
};
|
||||
|
||||
let mut setup_elf = Vec::new();
|
||||
File::open(setup)
|
||||
.unwrap()
|
||||
.read_to_end(&mut setup_elf)
|
||||
.unwrap();
|
||||
let mut setup = to_flat_binary(&setup_elf);
|
||||
// Pad the header with 8-byte alignment.
|
||||
setup.resize((setup.len() + 7) & !7, 0x00);
|
||||
|
||||
let mut kernel = Vec::new();
|
||||
File::open(kernel_path)
|
||||
.unwrap()
|
||||
.read_to_end(&mut kernel)
|
||||
.unwrap();
|
||||
let payload = kernel;
|
||||
|
||||
let setup_len = setup.len();
|
||||
let payload_len = payload.len();
|
||||
let payload_offset = SetupFileOffset::from(setup_len);
|
||||
fill_legacy_header_fields(&mut setup, payload_len, setup_len, payload_offset.into());
|
||||
|
||||
let mut kernel_image = File::create(target_image_path).unwrap();
|
||||
kernel_image.write_all(&setup).unwrap();
|
||||
kernel_image.write_all(&payload).unwrap();
|
||||
|
||||
let image_size = setup_len + payload_len;
|
||||
|
||||
if matches!(image_type, BzImageType::Efi64) {
|
||||
// Write the PE/COFF header to the start of the file.
|
||||
// Since the Linux boot header starts at 0x1f1, we can write the PE/COFF header directly to the
|
||||
// start of the file without overwriting the Linux boot header.
|
||||
let pe_header = pe_header::make_pe_coff_header(&setup_elf, image_size);
|
||||
assert!(
|
||||
pe_header.header_at_zero.len() <= 0x1f1,
|
||||
"PE/COFF header is too large"
|
||||
);
|
||||
|
||||
kernel_image.seek(SeekFrom::Start(0)).unwrap();
|
||||
kernel_image.write_all(&pe_header.header_at_zero).unwrap();
|
||||
kernel_image
|
||||
.seek(SeekFrom::Start(usize::from(pe_header.relocs.0) as u64))
|
||||
.unwrap();
|
||||
kernel_image.write_all(&pe_header.relocs.1).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
enum SetupBuildArch {
|
||||
X86_64,
|
||||
Other(PathBuf),
|
||||
}
|
||||
|
||||
/// We need a flat binary which satisfies PA delta == File offset delta,
|
||||
/// and objcopy does not satisfy us well, so we should parse the ELF and
|
||||
/// do our own objcopy job.
|
||||
///
|
||||
/// Interstingly, the resulting binary should be the same as the memory
|
||||
/// Interestingly, the resulting binary should be the same as the memory
|
||||
/// dump of the kernel setup header when it's loaded by the bootloader.
|
||||
fn to_flat_binary(elf_file: &[u8]) -> Vec<u8> {
|
||||
let elf = xmas_elf::ElfFile::new(&elf_file).unwrap();
|
||||
@ -54,7 +141,7 @@ fn to_flat_binary(elf_file: &[u8]) -> Vec<u8> {
|
||||
bin
|
||||
}
|
||||
|
||||
/// This function sould be used when generating the Linux x86 Boot setup header.
|
||||
/// This function should be used when generating the Linux x86 Boot setup header.
|
||||
/// Some fields in the Linux x86 Boot setup header should be filled after assembled.
|
||||
/// And the filled fields must have the bytes with values of 0xAB. See
|
||||
/// `framework/aster-frame/src/arch/x86/boot/linux_boot/setup/src/header.S` for more
|
||||
@ -95,91 +182,14 @@ fn fill_legacy_header_fields(
|
||||
);
|
||||
}
|
||||
|
||||
/// The type of the bzImage that we are building through `make_bzimage`.
|
||||
///
|
||||
/// Currently, Legacy32 and Efi64 are mutually exclusive.
|
||||
pub enum BzImageType {
|
||||
Legacy32,
|
||||
Efi64,
|
||||
}
|
||||
|
||||
pub fn make_bzimage(
|
||||
image_path: &Path,
|
||||
kernel_path: &Path,
|
||||
image_type: BzImageType,
|
||||
setup_src: &Path,
|
||||
setup_out: &Path,
|
||||
) {
|
||||
let setup = match image_type {
|
||||
BzImageType::Legacy32 => {
|
||||
let arch = setup_src
|
||||
.join("x86_64-i386_pm-none.json")
|
||||
.canonicalize()
|
||||
.unwrap();
|
||||
build_setup_with_arch(setup_src, setup_out, &SetupBuildArch::Other(arch))
|
||||
}
|
||||
BzImageType::Efi64 => build_setup_with_arch(setup_src, setup_out, &SetupBuildArch::X86_64),
|
||||
};
|
||||
|
||||
let mut setup_elf = Vec::new();
|
||||
File::open(setup)
|
||||
.unwrap()
|
||||
.read_to_end(&mut setup_elf)
|
||||
.unwrap();
|
||||
let mut setup = to_flat_binary(&setup_elf);
|
||||
// Pad the header with 8-byte alignment.
|
||||
setup.resize((setup.len() + 7) & !7, 0x00);
|
||||
|
||||
let mut kernel = Vec::new();
|
||||
File::open(kernel_path)
|
||||
.unwrap()
|
||||
.read_to_end(&mut kernel)
|
||||
.unwrap();
|
||||
let payload = kernel;
|
||||
|
||||
let setup_len = setup.len();
|
||||
let payload_len = payload.len();
|
||||
let payload_offset = SetupFileOffset::from(setup_len);
|
||||
fill_legacy_header_fields(&mut setup, payload_len, setup_len, payload_offset.into());
|
||||
|
||||
let mut kernel_image = File::create(image_path).unwrap();
|
||||
kernel_image.write_all(&setup).unwrap();
|
||||
kernel_image.write_all(&payload).unwrap();
|
||||
|
||||
let image_size = setup_len + payload_len;
|
||||
|
||||
if matches!(image_type, BzImageType::Efi64) {
|
||||
// Write the PE/COFF header to the start of the file.
|
||||
// Since the Linux boot header starts at 0x1f1, we can write the PE/COFF header directly to the
|
||||
// start of the file without overwriting the Linux boot header.
|
||||
let pe_header = pe_header::make_pe_coff_header(&setup_elf, image_size);
|
||||
assert!(
|
||||
pe_header.header_at_zero.len() <= 0x1f1,
|
||||
"PE/COFF header is too large"
|
||||
);
|
||||
|
||||
kernel_image.seek(SeekFrom::Start(0)).unwrap();
|
||||
kernel_image.write_all(&pe_header.header_at_zero).unwrap();
|
||||
kernel_image
|
||||
.seek(SeekFrom::Start(usize::from(pe_header.relocs.0) as u64))
|
||||
.unwrap();
|
||||
kernel_image.write_all(&pe_header.relocs.1).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
enum SetupBuildArch {
|
||||
X86_64,
|
||||
Other(PathBuf),
|
||||
}
|
||||
|
||||
/// Build the setup binary.
|
||||
///
|
||||
/// It will return the path to the built setup binary.
|
||||
fn build_setup_with_arch(source_dir: &Path, out_dir: &Path, arch: &SetupBuildArch) -> PathBuf {
|
||||
if !out_dir.exists() {
|
||||
std::fs::create_dir_all(&out_dir).unwrap();
|
||||
fn build_setup_with_arch(source_dir: &Path, tmp_out_dir: &Path, arch: &SetupBuildArch) -> PathBuf {
|
||||
if !tmp_out_dir.exists() {
|
||||
std::fs::create_dir_all(&tmp_out_dir).unwrap();
|
||||
}
|
||||
let out_dir = std::fs::canonicalize(out_dir).unwrap();
|
||||
let tmp_out_dir = std::fs::canonicalize(tmp_out_dir).unwrap();
|
||||
|
||||
// Relocations are fewer in release mode. That's why the release mode is more stable than
|
||||
// the debug mode.
|
||||
@ -201,7 +211,7 @@ fn build_setup_with_arch(source_dir: &Path, out_dir: &Path, arch: &SetupBuildArc
|
||||
cmd.arg("-Zbuild-std-features=compiler-builtins-mem");
|
||||
// Specify the build target directory to avoid cargo running
|
||||
// into a deadlock reading the workspace files.
|
||||
cmd.arg("--target-dir").arg(out_dir.as_os_str());
|
||||
cmd.arg("--target-dir").arg(tmp_out_dir.as_os_str());
|
||||
cmd.env_remove("RUSTFLAGS");
|
||||
cmd.env_remove("CARGO_ENCODED_RUSTFLAGS");
|
||||
|
||||
@ -220,7 +230,7 @@ fn build_setup_with_arch(source_dir: &Path, out_dir: &Path, arch: &SetupBuildArc
|
||||
SetupBuildArch::Other(path) => path.file_stem().unwrap().to_str().unwrap(),
|
||||
};
|
||||
|
||||
let setup_artifact = out_dir
|
||||
let setup_artifact = tmp_out_dir
|
||||
.join(arch_name)
|
||||
.join(profile)
|
||||
.join("linux-bzimage-setup");
|
||||
|
@ -1,17 +1,5 @@
|
||||
use xmas_elf::program::{ProgramHeader, SegmentData};
|
||||
|
||||
/// TODO: remove this and use copy_from_slice instead
|
||||
///
|
||||
/// We use a custom memcpy because the standard library's compiler's builtin memcpy
|
||||
/// fails for some unknown reason.
|
||||
unsafe fn memcpy(dst: *mut u8, src: *const u8, size: usize) {
|
||||
let mut i = 0;
|
||||
while i < size {
|
||||
*dst.add(i) = *src.add(i);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Load the kernel ELF payload to memory.
|
||||
pub fn load_elf(file: &[u8]) {
|
||||
let elf = xmas_elf::ElfFile::new(file).unwrap();
|
||||
@ -62,3 +50,16 @@ fn load_segment(file: &xmas_elf::ElfFile, program: &xmas_elf::program::ProgramHe
|
||||
let zero_slice = &mut dst_slice[program.file_size as usize..];
|
||||
zero_slice.fill(0);
|
||||
}
|
||||
|
||||
/// TODO: remove this and use copy_from_slice instead
|
||||
///
|
||||
/// We use a custom memcpy because the standard library's compiler's builtin memcpy
|
||||
/// fails for some unknown reason. Sometimes that will result in "Unknown OPCode"
|
||||
/// machine error.
|
||||
unsafe fn memcpy(dst: *mut u8, src: *const u8, size: usize) {
|
||||
let mut i = 0;
|
||||
while i < size {
|
||||
*dst.add(i) = *src.add(i);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
@ -74,12 +74,12 @@ pub const GRUB_PREFIX_EFI_AND_LEGACY: &str = "/usr/local/grub";
|
||||
pub const GRUB_VERSION: &str = "x86_64-efi";
|
||||
|
||||
pub fn create_bootdev_image(
|
||||
aster_path: PathBuf,
|
||||
kernel_elf_path: PathBuf,
|
||||
initramfs_path: PathBuf,
|
||||
grub_cfg: String,
|
||||
protocol: BootProtocol,
|
||||
) -> PathBuf {
|
||||
let target_dir = aster_path.parent().unwrap();
|
||||
let target_dir = kernel_elf_path.parent().unwrap();
|
||||
let iso_root = target_dir.join("iso_root");
|
||||
|
||||
// Clear or make the iso dir.
|
||||
@ -102,24 +102,24 @@ pub fn create_bootdev_image(
|
||||
BootProtocol::LinuxEfiHandover64 => BzImageType::Efi64,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let wrapper_src = Path::new("framework/libs/linux-bzimage/setup");
|
||||
let wrapper_out = Path::new("target/linux-bzimage-setup");
|
||||
let setup_src = Path::new("framework/libs/linux-bzimage/setup");
|
||||
let setup_out_dir = Path::new("target/linux-bzimage-setup");
|
||||
// Make the `bzImage`-compatible kernel image and place it in the boot directory.
|
||||
let target_path = iso_root.join("boot").join("asterinaz");
|
||||
println!("[aster-runner] Building bzImage.");
|
||||
make_bzimage(
|
||||
&target_path,
|
||||
&aster_path.as_path(),
|
||||
image_type,
|
||||
&wrapper_src,
|
||||
&wrapper_out,
|
||||
&kernel_elf_path.as_path(),
|
||||
&setup_src,
|
||||
&setup_out_dir,
|
||||
);
|
||||
target_path
|
||||
}
|
||||
BootProtocol::Multiboot | BootProtocol::Multiboot2 => {
|
||||
// Copy the kernel image to the boot directory.
|
||||
let target_path = iso_root.join("boot").join("atserinas");
|
||||
fs::copy(&aster_path, &target_path).unwrap();
|
||||
fs::copy(&kernel_elf_path, &target_path).unwrap();
|
||||
target_path
|
||||
}
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user