use turkos_bootinfo::BootInfoV1; use turkos_os_runtime::boot_contract::{EntryRegisters, LocatedBytes, PhysicalRange}; pub const RAM_START: u64 = 0x4000_0000; pub const IMAGE_START: u64 = 0x4008_0000; pub const IMAGE_BYTES: u64 = 0x30_000; pub const INFO_ADDRESS: u64 = 0x4040_0000; pub const MAP_ADDRESS: u64 = 0x4050_0000; pub fn image() -> PhysicalRange { PhysicalRange::new(IMAGE_START, IMAGE_BYTES).unwrap() } pub fn dtb_address(mib: u64) -> u64 { RAM_START + mib * 1024 * 1024 - 2 * 1024 * 1024 } pub fn located(address: u64, bytes: &[u8]) -> LocatedBytes<'_> { LocatedBytes::new(address, bytes).unwrap() } pub fn registers(mib: u64, uefi: bool) -> EntryRegisters { EntryRegisters { dtb_address: dtb_address(mib), boot_info_address: if uefi { INFO_ADDRESS } else { 0 }, } } pub fn header(mib: u64) -> BootInfoV1 { BootInfoV1 { memory_map_ptr: MAP_ADDRESS, memory_map_bytes: 48, descriptor_bytes: 48, descriptor_version: 1, kernel_phys_start: IMAGE_START, kernel_file_bytes: 0x20_000, dtb_phys_addr: dtb_address(mib), ..BootInfoV1::empty() } } pub fn encode(info: BootInfoV1) -> Vec { let mut out = Vec::from(info.magic); out.extend(info.version.to_le_bytes()); out.extend(info.struct_bytes.to_le_bytes()); out.extend(info.memory_map_ptr.to_le_bytes()); out.extend(info.memory_map_bytes.to_le_bytes()); out.extend(info.descriptor_bytes.to_le_bytes()); out.extend(info.descriptor_version.to_le_bytes()); out.extend(info.kernel_phys_start.to_le_bytes()); out.extend(info.kernel_file_bytes.to_le_bytes()); out.extend(info.dtb_phys_addr.to_le_bytes()); out.extend(info.flags.to_le_bytes()); assert_eq!(out.len(), 72); out } fn word(out: &mut Vec, value: u32) { out.extend(value.to_be_bytes()); } fn node(out: &mut Vec, name: &[u8]) { word(out, 1); out.extend(name); out.resize(out.len().next_multiple_of(4), 0); } fn property(out: &mut Vec, name_offset: u32, bytes: &[u8]) { word(out, 3); word(out, bytes.len() as u32); word(out, name_offset); out.extend(bytes); out.resize(out.len().next_multiple_of(4), 0); } /// Minimal valid QEMU-style FDT v17, not a canned Hardware mock. The existing /// kernel parser really reads the memory/PL011 properties and reservation table. pub fn fixture(mib: u64) -> Vec { let strings = b"#address-cells\0#size-cells\0reg\0device_type\0compatible\0"; let mut tree = Vec::new(); node(&mut tree, b"\0"); property(&mut tree, 0, &2u32.to_be_bytes()); property(&mut tree, 15, &2u32.to_be_bytes()); node(&mut tree, b"memory@40000000\0"); let memory = [RAM_START.to_be_bytes(), (mib * 1024 * 1024).to_be_bytes()].concat(); property(&mut tree, 27, &memory); property(&mut tree, 31, b"memory\0"); word(&mut tree, 2); node(&mut tree, b"pl011@9000000\0"); let uart = [0x0900_0000u64.to_be_bytes(), 0x1000u64.to_be_bytes()].concat(); property(&mut tree, 27, &uart); property(&mut tree, 43, b"arm,pl011\0arm,primecell\0"); word(&mut tree, 2); word(&mut tree, 2); word(&mut tree, 9); let strings_offset = 56 + tree.len(); let mut blob = Vec::new(); for value in [ 0xd00d_feed, (strings_offset + strings.len()) as u32, 56, strings_offset as u32, 40, 17, 16, 0, strings.len() as u32, tree.len() as u32, ] { word(&mut blob, value); } blob.extend([0; 16]); blob.extend(tree); blob.extend(strings); blob }