From 024c8131bcd83d2ae11229f2332b59d31818f7fd Mon Sep 17 00:00:00 2001 From: bunnie Date: Sun, 21 Sep 2025 21:50:31 +0800 Subject: [PATCH] extend image builder to handle baking in statics --- tools/Cargo.toml | 1 + tools/src/bin/copy-object.rs | 44 +++++++++++++++++++++++++++++++++--- tools/src/elf.rs | 44 +++++++++++------------------------- 3 files changed, 55 insertions(+), 34 deletions(-) diff --git a/tools/Cargo.toml b/tools/Cargo.toml index 51db59bab..a669c48c5 100644 --- a/tools/Cargo.toml +++ b/tools/Cargo.toml @@ -26,6 +26,7 @@ pkcs8 = { version = "0.8.0", features = ["pem"] } base64 = "0.20.0" rand = "0.8.5" aes-gcm-siv = "0.11.1" +bao1x-api = { path = "../libs/bao1x-api" } [[bin]] name = "copy-object" diff --git a/tools/src/bin/copy-object.rs b/tools/src/bin/copy-object.rs index 78b157d37..ab2ac2e29 100644 --- a/tools/src/bin/copy-object.rs +++ b/tools/src/bin/copy-object.rs @@ -1,7 +1,7 @@ use std::env; use std::fs::File; use std::io::Write; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::process; use tools::elf; @@ -10,16 +10,34 @@ fn main() { env_logger::init(); let args: Vec = env::args().collect(); if args.len() < 2 { - println!("Usage: {} input.elf [output.bin]", args.get(0).unwrap_or(&"copy-object".to_owned())); + println!( + "Usage: {} input.elf [output.bin] [--bao1x]", + args.get(0).unwrap_or(&"copy-object".to_owned()) + ); return; } let input_filename = Path::new(args.get(1).unwrap()).to_path_buf(); - let output_filename = args.get(2).map(|x| Path::new(x).to_path_buf()).unwrap_or_else(|| { + + // Parse remaining arguments + let mut output_filename: Option = None; + let mut bao1x_flag = false; + + for arg in args.iter().skip(2) { + if arg == "--bao1x" { + bao1x_flag = true; + } else if output_filename.is_none() { + output_filename = Some(Path::new(arg).to_path_buf()); + } + } + + // Set default output filename if none provided + let output_filename = output_filename.unwrap_or_else(|| { let mut output_filename = input_filename.clone(); output_filename.set_extension("bin"); output_filename }); + if output_filename == input_filename { eprintln!("Input and output filename are the same: {}", output_filename.display()); eprintln!("Specify an output path, or change the suffix of your input file from \".bin\""); @@ -33,6 +51,26 @@ fn main() { eprintln!("Couldn't create output file {}: {}", output_filename.display(), e); process::exit(1); }); + if bao1x_flag { + let mut statics = bao1x_api::StaticsInRom { + jump_instruction: bao1x_api::JUMP_INSTRUCTION, + version: bao1x_api::STATICS_IN_ROM_VERSION, + valid_pokes: 0, + data_origin: 0, + data_size_bytes: 0, + poke_table: [(0u32, 0u32); 30], + }; + statics.data_origin = pd.data_offset; + statics.data_size_bytes = pd.clear_size; + statics.valid_pokes = pd.poke_table.len() as u16; + for (&entry, dest) in pd.poke_table.iter().zip(statics.poke_table.iter_mut()) { + *dest = entry; + } + f.write(statics.as_bytes()).unwrap_or_else(|e| { + eprintln!("Couldn't write data to {}: {}", output_filename.display(), e); + process::exit(1); + }); + } f.write_all(&pd.program).unwrap_or_else(|e| { eprintln!("Couldn't write data to {}: {}", output_filename.display(), e); process::exit(1); diff --git a/tools/src/elf.rs b/tools/src/elf.rs index 62a75ba67..0588df7b6 100644 --- a/tools/src/elf.rs +++ b/tools/src/elf.rs @@ -36,6 +36,13 @@ pub struct ProgramDescription { /// Size of .data section pub data_size: u32, + /// Poke table for data section; in (address, data) tuples. Addresses are in `u32` format + /// because we're packing them for a target that is 32-bits, which may be different from the host. + pub poke_table: Vec<(u32, u32)>, + + /// Size of region to be zero-ized by the loader + pub clear_size: u32, + /// Size of the .bss section pub bss_size: u32, @@ -156,6 +163,7 @@ pub fn process_program(b: &[u8], rom_only: bool) -> Result::new(); let mut size = 0; let mut data_offset = 0; @@ -328,42 +336,12 @@ pub fn process_program(b: &[u8], rom_only: bool) -> Result() == 0 { - const SPACING: &'static str = " "; - let mut non_zero_tuples = Vec::<(usize, u32)>::new(); for (i, chunk) in data_copy.chunks_exact(4).enumerate() { let word = u32::from_le_bytes(chunk.try_into().unwrap()); if word != 0 { - non_zero_tuples.push((i, word)); + poke_table.push((i as u32, word)); } } - println!("Code for loader/baremetal integration:\n"); - println!("// Define the .data region - bootstrap baremetal using these hard-coded parameters."); - println!("const DATA_ORIGIN: usize = 0x{:x};", data_offset); - println!( - "const DATA_SIZE_BYTES: usize = 0x{:x};", - // round up to the nearest u32 word. Includes .data, .bss, .stack, .heap - regions to be zero'd. - ((data_size + bss_size) as usize + size_of::() - 1) & !(size_of::() - 1) - ); - let mut init_str = String::new(); - init_str.push_str(&format!("const DATA_INIT: [(usize, u32); {}] = [\n", non_zero_tuples.len())); - for (offset, data) in non_zero_tuples { - init_str.push_str(&format!("{}(0x{:x}, 0x{:x}),\n", SPACING, offset, data)); - } - init_str.push_str(&format!("];")); - print!("{}", init_str); - let boilerplate = r#" -// Clear .data, .bss, .stack, .heap regions & setup .data values -unsafe { - let data_ptr = DATA_ORIGIN as *mut u32; - for i in 0..DATA_SIZE_BYTES / size_of::() { - data_ptr.add(i).write_volatile(0); - } - for (offset, data) in DATA_INIT { - data_ptr.add(offset).write_volatile(data); - } -} - "#; - println!("\n{}", boilerplate); } else { println!( "Data section is not word-aligned, check objdump in detail for how to initialize the section" @@ -377,6 +355,10 @@ unsafe { text_offset, text_size, bss_size, + // round up to the nearest u32 word. Includes .data, .bss, .stack, .heap - regions to be zero'd. + clear_size: (((data_size + bss_size) as usize + size_of::() - 1) & !(size_of::() - 1)) + as u32, + poke_table, }) }