Successfully entered setup rust entrypoint

This commit is contained in:
Zhang Junyang
2023-10-23 09:53:55 +08:00
committed by Tate, Hongliang Tian
parent 922fbd0c91
commit 052fc795a5
5 changed files with 68 additions and 33 deletions

1
Cargo.lock generated
View File

@ -647,6 +647,7 @@ dependencies = [
"volatile",
"x86",
"x86_64",
"xmas-elf",
]
[[package]]

View File

@ -58,7 +58,6 @@ export
# Toolchain variables that are used when building the Linux setup header
export CARGO := cargo
export OBJCOPY := objcopy
.PHONY: all setup build tools run test docs check clean

View File

@ -30,5 +30,8 @@ aml = "0.16.3"
multiboot2 = "0.16.0"
rsdp = "2.0.0"
[build-dependencies]
xmas-elf = "0.8.0"
[features]
intel_tdx = ["dep:tdx-guest"]

View File

@ -1,14 +1,26 @@
use std::{error::Error, io::Write, path::PathBuf};
use std::{
error::Error,
io::{Seek, Write},
path::{Path, PathBuf},
};
use xmas_elf::program::{ProgramHeader, SegmentData};
const SETUP32_LMA: usize = 0x100000;
fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
build_linux_setup_header()?;
let source_dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap());
build_linux_setup_header(&source_dir, &out_dir)?;
copy_to_raw_binary(&out_dir)?;
Ok(())
}
fn build_linux_setup_header() -> Result<(), Box<dyn Error + Send + Sync>> {
// Build the setup header to raw binary.
let source_dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap());
fn build_linux_setup_header(
source_dir: &Path,
out_dir: &Path,
) -> Result<(), Box<dyn Error + Send + Sync>> {
// Build the setup header to ELF.
let setup_crate_dir = source_dir
.join("src")
.join("arch")
@ -26,12 +38,17 @@ fn build_linux_setup_header() -> Result<(), Box<dyn Error + Send + Sync>> {
let cargo = std::env::var("CARGO").unwrap();
let mut cmd = std::process::Command::new(cargo);
cmd.arg("install").arg("jinux-frame-x86-boot-setup");
cmd.arg("--debug");
cmd.arg("--locked");
cmd.arg("--path").arg(setup_crate_dir.to_str().unwrap());
cmd.arg("--target").arg(target_json.as_os_str());
cmd.arg("-Zbuild-std=core,compiler_builtins");
cmd.arg("-Zbuild-std-features=compiler-builtins-mem");
// Specify the installation root.
cmd.arg("--root").arg(out_dir.as_os_str());
// 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.env_remove("RUSTFLAGS");
cmd.env_remove("CARGO_ENCODED_RUSTFLAGS");
let output = cmd.output()?;
@ -45,31 +62,46 @@ fn build_linux_setup_header() -> Result<(), Box<dyn Error + Send + Sync>> {
.into());
}
Ok(())
}
/// We need a binary which satisfies `LMA == File_Offset`, 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
/// dump of the kernel setup header when it's loaded by the bootloader.
fn copy_to_raw_binary(out_dir: &Path) -> Result<(), Box<dyn Error + Send + Sync>> {
// Strip the elf header to get the raw header.
let elf_path = out_dir.join("bin").join("jinux-frame-x86-boot-setup");
let bin_path = out_dir.join("bin").join("jinux-frame-x86-boot-setup.bin");
let objcopy = std::env::var("OBJCOPY").unwrap();
let mut cmd = std::process::Command::new(objcopy);
cmd.arg("-O").arg("binary");
cmd.arg("-j").arg(".header");
cmd.arg("-j").arg(".text");
cmd.arg("-j").arg(".rodata");
cmd.arg("-j").arg(".data");
cmd.arg("-j").arg(".bss");
cmd.arg("-j").arg(".eh_frame");
cmd.arg("-j").arg(".eh_frame_hdr");
cmd.arg(elf_path.to_str().unwrap());
cmd.arg(bin_path.to_str().unwrap());
let output = cmd.output()?;
if !output.status.success() {
std::io::stdout().write_all(&output.stdout).unwrap();
std::io::stderr().write_all(&output.stderr).unwrap();
return Err(format!(
"Failed to strip linux boot header:\n\tcommand `{:?}`\n\treturned {}",
cmd, output.status
)
.into());
let elf_file = std::fs::read(elf_path)?;
let elf = xmas_elf::ElfFile::new(&elf_file)?;
let bin_file = std::fs::File::create(bin_path)?;
let mut bin_writer = std::io::BufWriter::new(bin_file);
for ph in elf.program_iter() {
let ProgramHeader::Ph32(program) = ph else {
return Err("Unexpected program header type".into());
};
if program.get_type().unwrap() == xmas_elf::program::Type::Load {
let dest_file_offset = program.virtual_addr as usize - SETUP32_LMA;
bin_writer.seek(std::io::SeekFrom::End(0))?;
let cur_file_offset = bin_writer.stream_position().unwrap() as usize;
if cur_file_offset < dest_file_offset {
let padding = vec![0; dest_file_offset - cur_file_offset];
bin_writer.write_all(&padding)?;
} else {
bin_writer.seek(std::io::SeekFrom::Start(dest_file_offset as u64))?;
}
let SegmentData::Undefined(header_data) = program.get_data(&elf).unwrap() else {
return Err("Unexpected segment data type".into());
};
bin_writer.write_all(header_data)?;
}
}
Ok(())
}

View File

@ -16,7 +16,7 @@
.code16
.org 0x01f1
hdr:
hdr_start:
SETUP_SECTS = 4
setup_sects: .byte SETUP_SECTS
root_flags: .word 1
@ -26,7 +26,7 @@ vid_mode: .word 0xfffd
root_dev: .word 0
boot_flag: .word 0xAA55
jump: .byte 0xeb
jump_addr: .byte start_of_setup32-jump_addr
jump_addr: .byte hdr_end-jump_addr
magic: .ascii "HdrS"
.word 0x020f
realmode_swtch: .word 0, 0
@ -58,12 +58,12 @@ pref_address: .quad 0
init_size: .long 0xabababab # at 0x260/4, to be filled by the runner
handover_offset: .long 0
kernel_info_offset: .long 0
hdr_end:
// End of header.
// 32-bit setup code starts here.
// 32-bit setup code starts here, and will be loaded at code32_start (0x100000).
.code32
start_of_setup32:
.org 0x200 * (SETUP_SECTS + 1)
start_of_setup32:
.extern _rust_setup_entry
jmp _rust_setup_entry