diff options
| author | summivox <summivox@gmail.com> | 2023-08-20 23:13:59 -0700 |
|---|---|---|
| committer | Ian McIntyre <ianpmcintyre@gmail.com> | 2023-09-08 19:18:34 -0400 |
| commit | c6d3bcfb11800c58339037be58fa9935f816f1bb (patch) | |
| tree | 4e8b0d6cdae543e0443f4a8d4cf969f4def7a1f3 /tests | |
| parent | e1fddd5b3b678c43ee59835d7b57bbc063a22d28 (diff) | |
Add optional DCD section in linker script
Users can define their device configuration data (DCD), and place the
data in the .dcd section. If the .dcd section has content, the entry in
the IVT points at the user's DCD. This plays well with imxrt-dcd.
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/inspect_elf.rs | 158 |
1 files changed, 143 insertions, 15 deletions
diff --git a/tests/inspect_elf.rs b/tests/inspect_elf.rs index c45260d..fa2c11d 100644 --- a/tests/inspect_elf.rs +++ b/tests/inspect_elf.rs @@ -12,7 +12,7 @@ type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>; /// Build an example, returning a path to the ELF. fn cargo_build(board: &str) -> Result<PathBuf> { - Command::new("cargo") + let status = Command::new("cargo") .arg("build") .arg("--example=blink-rtic") .arg(format!("--features=board/{},board/rtic", board)) @@ -22,6 +22,15 @@ fn cargo_build(board: &str) -> Result<PathBuf> { .spawn()? .wait()?; + // TODO(summivox): `ExitStatus::exit_ok()` stabilization (can be chained after the `.wait()?) + if !status.success() { + return Err(format!( + "Building board '{}' failed: process returned {:?}", + board, status, + ) + .into()); + } + let path = PathBuf::from(format!( "target/{}/thumbv7em-none-eabihf/debug/examples/blink-rtic", board @@ -31,11 +40,23 @@ fn cargo_build(board: &str) -> Result<PathBuf> { struct ImxrtBinary<'a> { elf: &'a Elf<'a>, + contents: &'a [u8], +} + +/// Image vector table. +/// +/// Not to be confused with the ARM vector table. See the linker +/// script for more information. +struct Ivt { + magic_header: u32, + interrupt_vector_table: u32, + device_configuration_data: u32, + boot_data: u32, } impl<'a> ImxrtBinary<'a> { - fn new(elf: &'a Elf<'a>) -> Self { - Self { elf } + fn new(elf: &'a Elf<'a>, contents: &'a [u8]) -> Self { + Self { elf, contents } } fn symbol(&self, symbol_name: &str) -> Option<goblin::elf::Sym> { @@ -47,6 +68,10 @@ impl<'a> ImxrtBinary<'a> { .map(|(sym, _)| sym) } + fn symbol_value(&self, symbol_name: &str) -> Option<u64> { + self.symbol(symbol_name).map(|sym| sym.st_value) + } + fn fcb(&self) -> Result<Fcb> { self.symbol("FLEXSPI_CONFIGURATION_BLOCK") .map(|sym| Fcb { @@ -58,13 +83,35 @@ impl<'a> ImxrtBinary<'a> { }) } + fn read_u32(&self, offset: usize) -> u32 { + u32::from_le_bytes(self.contents[offset..offset + 4].try_into().unwrap()) + } + + fn ivt(&self) -> Result<Ivt> { + let ivt_at_runtime = self + .symbol_value("__ivt") + .ok_or_else(|| String::from("Could not find __ivt symbol"))?; + let (boot_section_offset, boot_section_at_runtime) = self + .section_header(".boot") + .map(|sec| (sec.sh_offset, sec.sh_addr)) + .ok_or_else(|| String::from("Could not find '.boot' section"))?; + let ivt_offset = + (boot_section_offset + (ivt_at_runtime - boot_section_at_runtime)) as usize; + Ok(Ivt { + magic_header: self.read_u32(ivt_offset), + interrupt_vector_table: self.read_u32(ivt_offset + 4), + device_configuration_data: self.read_u32(ivt_offset + 12), + boot_data: self.read_u32(ivt_offset + 16), + }) + } + fn flexram_config(&self) -> Result<u64> { self.symbol("__flexram_config") .map(|sym| sym.st_value) .ok_or_else(|| String::from("Could not find FlexRAM configuration in program").into()) } - fn section(&self, section_name: &str) -> Result<Section> { + fn section_header(&self, section_name: &str) -> Option<&goblin::elf::SectionHeader> { self.elf .section_headers .iter() @@ -75,7 +122,12 @@ impl<'a> ImxrtBinary<'a> { .map(|name| (sec, name)) }) .find(|(_, name)| section_name == *name) - .map(|(sec, _)| Section { + .map(|(sec, _)| sec) + } + + fn section(&self, section_name: &str) -> Result<Section> { + self.section_header(section_name) + .map(|sec| Section { address: sec.sh_addr, size: sec.sh_size, }) @@ -121,7 +173,11 @@ fn imxrt1010evk() { let contents = fs::read(path).expect("Could not read ELF file"); let elf = Elf::parse(&contents).expect("Could not parse ELF"); - let binary = ImxrtBinary::new(&elf); + let binary = ImxrtBinary::new(&elf, &contents); + assert_eq!( + binary.symbol_value("__dcd_start"), + binary.symbol_value("__dcd_end") + ); assert_eq!( Fcb { address: 0x6000_0400, @@ -131,6 +187,15 @@ fn imxrt1010evk() { ); assert_eq!(binary.flexram_config().unwrap(), 0b11_10_0101); + let ivt = binary.ivt().unwrap(); + assert_eq!(ivt.magic_header, 0x402000D1); + assert_eq!(ivt.interrupt_vector_table, 0x6000_2000); + assert_eq!(ivt.device_configuration_data, 0); + assert_eq!( + ivt.boot_data as u64, + binary.symbol_value("__ivt").unwrap() + 32 + ); + let stack = binary.section(".stack").unwrap(); assert_eq!( Section { @@ -218,14 +283,7 @@ fn imxrt1010evk() { assert_eq!(binary.section_lma(&heap), heap.address, "Heap is NOLOAD"); } -#[test] -#[ignore = "building an example can take time"] -fn teensy4() { - let path = cargo_build("teensy4").expect("Unable to build example"); - let contents = fs::read(path).expect("Could not read ELF file"); - let elf = Elf::parse(&contents).expect("Could not parse ELF"); - - let binary = ImxrtBinary::new(&elf); +fn baseline_teensy4(binary: &ImxrtBinary, dcd_at_runtime: u32) { assert_eq!( Fcb { address: 0x6000_0000, @@ -238,6 +296,15 @@ fn teensy4() { 0b11111111_101010101010101010101010 ); + let ivt = binary.ivt().unwrap(); + assert_eq!(ivt.magic_header, 0x402000D1); + assert_eq!(ivt.interrupt_vector_table, 0x6000_2000); + assert_eq!(ivt.device_configuration_data, dcd_at_runtime); + assert_eq!( + ivt.boot_data as u64, + binary.symbol_value("__ivt").unwrap() + 32 + ); + let stack = binary.section(".stack").unwrap(); assert_eq!( Section { @@ -337,12 +404,64 @@ fn teensy4() { #[test] #[ignore = "building an example can take time"] +fn teensy4() { + let path = cargo_build("teensy4").expect("Unable to build example"); + let contents = fs::read(path).expect("Could not read ELF file"); + let elf = Elf::parse(&contents).expect("Could not parse ELF"); + + let binary = ImxrtBinary::new(&elf, &contents); + assert!(binary.symbol("DEVICE_CONFIGURATION_DATA").is_none()); + assert_eq!( + binary.symbol_value("__dcd_start"), + binary.symbol_value("__dcd_end") + ); + assert_eq!(binary.symbol_value("__dcd"), Some(0)); + baseline_teensy4(&binary, 0); +} + +#[test] +#[ignore = "building an example can take time"] +fn teensy4_fake_dcd() { + let path = cargo_build("__dcd").expect("Unable to build example"); + let contents = fs::read(path).expect("Could not read ELF file"); + let elf = Elf::parse(&contents).expect("Could not parse ELF"); + + let binary = ImxrtBinary::new(&elf, &contents); + let dcd = binary.symbol("DEVICE_CONFIGURATION_DATA").unwrap(); + let dcd_start = binary.symbol_value("__dcd_start").unwrap(); + assert_eq!( + Some(dcd_start + dcd.st_size), + binary.symbol_value("__dcd_end"), + ); + assert_eq!( + binary.symbol_value("__dcd"), + binary.symbol_value("__dcd_start"), + ); + assert_eq!(dcd.st_size % 4, 0); + baseline_teensy4(&binary, dcd_start as u32); +} + +#[test] +#[ignore = "building an example can take time"] +fn teensy4_fake_dcd_missize_fail() { + cargo_build("__dcd_missize").expect_err("Build should fail for missized DCD section."); + eprintln!(); + eprintln!("NOTE: Linker failures above are intentional --- this test has succeeded."); +} + +#[test] +#[ignore = "building an example can take time"] fn imxrt1170evk_cm7() { let path = cargo_build("imxrt1170evk-cm7").expect("Unable to build example"); let contents = fs::read(path).expect("Could not read ELF file"); let elf = Elf::parse(&contents).expect("Could not parse ELF"); - let binary = ImxrtBinary::new(&elf); + let binary = ImxrtBinary::new(&elf, &contents); + assert_eq!( + binary.symbol_value("__dcd_start"), + binary.symbol_value("__dcd_end") + ); + assert_eq!(binary.symbol_value("__dcd"), Some(0)); assert_eq!( Fcb { address: 0x3000_0400, @@ -355,6 +474,15 @@ fn imxrt1170evk_cm7() { 0b1111111111111111_1010101010101010 ); + let ivt = binary.ivt().unwrap(); + assert_eq!(ivt.magic_header, 0x402000D1); + assert_eq!(ivt.interrupt_vector_table, 0x3000_2000); + assert_eq!(ivt.device_configuration_data, 0); + assert_eq!( + ivt.boot_data as u64, + binary.symbol_value("__ivt").unwrap() + 32 + ); + let stack = binary.section(".stack").unwrap(); assert_eq!( Section { |
