mod common; use common::*; use turkos_bootinfo::{BootInfoHandoffError, BootInfoHeaderError, BootInfoPointerError}; use turkos_os_runtime::boot_contract::*; #[test] fn os_boot_contract_origin_positive() { for mib in [256, 512, 1024] { let dtb = fixture(mib); let info = encode(header(mib)); let direct = resolve( registers(mib, false), located(dtb_address(mib), &dtb), None, image(), ) .unwrap(); let uefi = resolve( registers(mib, true), located(dtb_address(mib), &dtb), Some(located(INFO_ADDRESS, &info)), image(), ) .unwrap(); assert_eq!(direct.origin, BootOrigin::DirectImage); assert_eq!(uefi.origin, BootOrigin::UefiBootInfoV1); assert_eq!(direct.ram, uefi.ram); assert_eq!( direct.ram, PhysicalRange::new(RAM_START, mib * 1024 * 1024).unwrap() ); assert_eq!(direct.dtb, uefi.dtb); assert_eq!(direct.dtb.bytes(), dtb.len() as u64); assert_eq!(direct.uart_base, 0x0900_0000); assert_eq!(direct.uart_base, uefi.uart_base); assert_eq!(direct.boot_info, None); assert_eq!(uefi.boot_info, Some(header(mib))); assert_ne!(direct.origin.tag(), uefi.origin.tag()); eprintln!("K603 profile={mib}MiB direct-image/uefi-bootinfo-v1 RAM=equal; host-only"); // No allocator or global state participates; repeating is deterministic. assert_eq!( resolve( registers(mib, false), located(dtb_address(mib), &dtb), None, image() ) .unwrap() .ram, direct.ram ); } } #[test] fn origin_positive_adjacent_image_and_dtb_do_not_overlap() { let dtb = fixture(256); let end = dtb_address(256); let adjacent = PhysicalRange::new(end - 4096, 4096).unwrap(); let boot = resolve(registers(256, false), located(end, &dtb), None, adjacent).unwrap(); assert_eq!(boot.dtb.start(), adjacent.end()); } #[test] fn origin_positive_result_owns_header_metadata() { let dtb = fixture(512); let mut info = encode(header(512)); let boot = resolve( registers(512, true), located(dtb_address(512), &dtb), Some(located(INFO_ADDRESS, &info)), image(), ) .unwrap(); info.fill(0xa5); assert_eq!(boot.boot_info, Some(header(512))); // Only metadata is owned; this is NOT a firmware map-copy/ownership test. } #[test] fn origin_positive_mapped_slice_can_contain_bytes_after_dtb() { let mut dtb = fixture(512); let size = dtb.len(); dtb.extend([0xa5; 64]); let boot = resolve( registers(512, false), located(dtb_address(512), &dtb), None, image(), ) .unwrap(); assert_eq!(boot.dtb.bytes(), size as u64); } #[test] fn os_boot_contract_origin_negative() { // The roadmap's specific counterexample: DTB bytes at the claimed x1 // address must not become a BootInfo, even when both refer to equal RAM. let dtb = fixture(512); let before = dtb.clone(); assert_eq!( resolve( registers(512, true), located(dtb_address(512), &dtb), Some(located(INFO_ADDRESS, &dtb)), image() ) .unwrap_err(), BootError::Header(BootInfoHeaderError::Magic) ); assert_eq!(dtb, before); assert_eq!( resolve( registers(512, false), located(dtb_address(512), &dtb), None, image() ) .unwrap() .origin, BootOrigin::DirectImage ); } #[test] fn origin_negative_zero_x1_with_payload_is_not_silently_direct() { let dtb = fixture(256); let info = encode(header(256)); assert_eq!( resolve( registers(256, false), located(dtb_address(256), &dtb), Some(located(INFO_ADDRESS, &info)), image() ) .unwrap_err(), BootError::UnexpectedBootInfo ); } #[test] fn origin_negative_nonzero_x1_without_payload_is_not_silently_direct() { let dtb = fixture(256); assert_eq!( resolve( registers(256, true), located(dtb_address(256), &dtb), None, image() ) .unwrap_err(), BootError::MissingBootInfo ); } #[test] fn origin_negative_all_truncated_header_lengths_are_rejected() { let dtb = fixture(512); let bytes = encode(header(512)); for length in 1..72 { assert_eq!( resolve( registers(512, true), located(dtb_address(512), &dtb), Some(located(INFO_ADDRESS, &bytes[..length])), image() ) .unwrap_err(), BootError::HeaderTruncated ); } assert!(matches!( LocatedBytes::new(INFO_ADDRESS, &[]), Err(RangeError::Empty) )); } #[test] fn origin_negative_version_size_magic_have_explicit_errors() { let dtb = fixture(256); for (offset, value, expected) in [ (0, 0, BootInfoHeaderError::Magic), (8, 255, BootInfoHeaderError::Version), (12, 71, BootInfoHeaderError::Size), ] { let mut bytes = encode(header(256)); let before_dtb = dtb.clone(); bytes[offset] = value; let before_header = bytes.clone(); assert_eq!( resolve( registers(256, true), located(dtb_address(256), &dtb), Some(located(INFO_ADDRESS, &bytes)), image() ) .unwrap_err(), BootError::Header(expected) ); assert_eq!(bytes, before_header); assert_eq!(dtb, before_dtb); } } #[test] fn origin_negative_wrong_address_labels_are_rejected() { let dtb = fixture(512); let info = encode(header(512)); assert_eq!( resolve( registers(512, true), located(dtb_address(512), &dtb), Some(located(INFO_ADDRESS + 8, &info)), image() ) .unwrap_err(), BootError::BootInfoAddressMismatch ); assert_eq!( resolve( registers(512, false), located(dtb_address(512) + 4, &dtb), None, image() ) .unwrap_err(), BootError::DtbAddressMismatch ); } #[test] fn origin_negative_bad_register_pointers_are_rejected() { let dtb = fixture(256); let bytes = encode(header(256)); for addr in [0, dtb_address(256) + 1] { let mut reg = registers(256, false); reg.dtb_address = addr; assert_eq!( resolve(reg, located(addr, &dtb), None, image()).unwrap_err(), BootError::DtbPointer ); } let mut reg = registers(256, true); reg.boot_info_address += 1; assert_eq!( resolve( reg, located(dtb_address(256), &dtb), Some(located(reg.boot_info_address, &bytes)), image() ) .unwrap_err(), BootError::BootInfoPointer(BootInfoPointerError::Unaligned) ); reg.boot_info_address = u64::MAX - 7; assert_eq!( resolve(reg, located(dtb_address(256), &dtb), None, image()).unwrap_err(), BootError::BootInfoPointer(BootInfoPointerError::AddressOverflow) ); } #[test] fn origin_negative_bootinfo_in_dtb_position_is_rejected() { let bytes = encode(header(512)); assert_eq!( resolve( registers(512, false), located(dtb_address(512), &bytes), None, image() ) .unwrap_err(), BootError::Dtb(turkos_kernel::dtb::Error::Invalid) ); } #[test] fn origin_negative_truncated_and_corrupt_dtb_are_rejected() { let dtb = fixture(512); for length in [1, 39, dtb.len() - 1] { assert_eq!( resolve( registers(512, false), located(dtb_address(512), &dtb[..length]), None, image() ) .unwrap_err(), BootError::Dtb(turkos_kernel::dtb::Error::Invalid) ); } let mut corrupt = dtb.clone(); corrupt[0] = 0; assert_eq!( resolve( registers(512, false), located(dtb_address(512), &corrupt), None, image() ) .unwrap_err(), BootError::Dtb(turkos_kernel::dtb::Error::Invalid) ); } #[test] fn origin_negative_image_dtb_overlap_is_rejected_on_both_paths() { let dtb = fixture(256); let info = encode(header(256)); let overlap = PhysicalRange::new(dtb_address(256) - 4, 8).unwrap(); for uefi in [false, true] { assert_eq!( resolve( registers(256, uefi), located(dtb_address(256), &dtb), uefi.then(|| located(INFO_ADDRESS, &info)), overlap ) .unwrap_err(), BootError::ImageDtbOverlap ); } } #[test] fn origin_negative_image_and_dtb_outside_ram_are_rejected() { let dtb = fixture(256); for outside in [ PhysicalRange::new(RAM_START - 4, 8).unwrap(), PhysicalRange::new(RAM_START + 256 * 1024 * 1024 - 4, 8).unwrap(), ] { assert_eq!( resolve( registers(256, false), located(dtb_address(256), &dtb), None, outside ) .unwrap_err(), BootError::ImageOutsideRam ); } let reg = EntryRegisters { dtb_address: RAM_START + 256 * 1024 * 1024 - 4, boot_info_address: 0, }; assert_eq!( resolve(reg, located(reg.dtb_address, &dtb), None, image()).unwrap_err(), BootError::DtbOutsideRam ); } #[test] fn origin_negative_payload_aliasing_dtb_is_rejected() { let dtb = fixture(512); let mut info = header(512); let reg = EntryRegisters { dtb_address: dtb_address(512), boot_info_address: dtb_address(512), }; // A forged physical label can carry valid header bytes. Numeric bounds // still reject the overlap; slice readability is not physical ownership. info.dtb_phys_addr = reg.dtb_address; let bytes = encode(info); assert_eq!( resolve( reg, located(reg.dtb_address, &dtb), Some(located(reg.boot_info_address, &bytes)), image() ) .unwrap_err(), BootError::Handoff(BootInfoHandoffError::Overlap) ); } #[test] fn origin_negative_map_overflow_and_unknown_flags_never_fall_back() { let dtb = fixture(512); for (info, expected) in [ ( turkos_bootinfo::BootInfoV1 { memory_map_ptr: u64::MAX - 7, ..header(512) }, BootInfoHandoffError::Map, ), ( turkos_bootinfo::BootInfoV1 { flags: 1, ..header(512) }, BootInfoHandoffError::Fields, ), ] { let bytes = encode(info); assert_eq!( resolve( registers(512, true), located(dtb_address(512), &dtb), Some(located(INFO_ADDRESS, &bytes)), image() ) .unwrap_err(), BootError::Handoff(expected) ); } } #[test] fn origin_negative_checked_range_rejects_empty_overflow() { assert_eq!(PhysicalRange::new(1, 0), Err(RangeError::Empty)); assert_eq!(PhysicalRange::new(u64::MAX, 1), Err(RangeError::Overflow)); assert!(matches!( LocatedBytes::new(u64::MAX, &[1]), Err(RangeError::Overflow) )); assert_eq!(PhysicalRange::new(u64::MAX - 1, 1).unwrap().end(), u64::MAX); }