@@ -1032,6 +1032,91 @@ mod tests {
10321032 hex:: encode ( vec ! [ byte; len] )
10331033 }
10341034
1035+ fn ovmf_footer_entry ( data : & [ u8 ] , guid : & [ u8 ; 16 ] ) -> Vec < u8 > {
1036+ let mut entry = data. to_vec ( ) ;
1037+ entry. extend_from_slice ( & ( ( data. len ( ) + OVMF_FOOTER_ENTRY_SIZE ) as u16 ) . to_le_bytes ( ) ) ;
1038+ entry. extend_from_slice ( guid) ;
1039+ entry
1040+ }
1041+
1042+ fn synthetic_snp_ovmf ( ) -> Vec < u8 > {
1043+ let mut ovmf = vec ! [ 0u8 ; 4096 ] ;
1044+ let meta_start = 512usize ;
1045+ ovmf[ meta_start..meta_start + 4 ] . copy_from_slice ( b"ASEV" ) ;
1046+ write_u32_le_at ( & mut ovmf, meta_start + 8 , 1 ) ;
1047+ write_u32_le_at ( & mut ovmf, meta_start + 12 , 4 ) ;
1048+ let sections = [
1049+ ( 0x1000u32 , 0x1000u32 , 1u32 ) ,
1050+ ( 0x2000u32 , 0x1000u32 , 2u32 ) ,
1051+ ( 0x3000u32 , 0x1000u32 , 3u32 ) ,
1052+ ( 0x4000u32 , 0x1000u32 , 0x10u32 ) ,
1053+ ] ;
1054+ for ( i, ( gpa, size, section_type) ) in sections. into_iter ( ) . enumerate ( ) {
1055+ let off = meta_start + 16 + i * 12 ;
1056+ write_u32_le_at ( & mut ovmf, off, gpa) ;
1057+ write_u32_le_at ( & mut ovmf, off + 4 , size) ;
1058+ write_u32_le_at ( & mut ovmf, off + 8 , section_type) ;
1059+ }
1060+
1061+ let mut table = Vec :: new ( ) ;
1062+ table. extend ( ovmf_footer_entry (
1063+ & 0x4000u32 . to_le_bytes ( ) ,
1064+ & GUID_SEV_HASH_TABLE_RV ,
1065+ ) ) ;
1066+ table. extend ( ovmf_footer_entry (
1067+ & 0xffff_fff0u32 . to_le_bytes ( ) ,
1068+ & GUID_SEV_ES_RESET_BLK ,
1069+ ) ) ;
1070+ table. extend ( ovmf_footer_entry (
1071+ & ( ( ovmf. len ( ) - meta_start) as u32 ) . to_le_bytes ( ) ,
1072+ & GUID_SEV_META_DATA ,
1073+ ) ) ;
1074+
1075+ let footer_off = ovmf. len ( ) - OVMF_RESET_VECTOR_TAIL_SIZE - OVMF_FOOTER_ENTRY_SIZE ;
1076+ let table_start = footer_off - table. len ( ) ;
1077+ ovmf[ table_start..footer_off] . copy_from_slice ( & table) ;
1078+ write_u16_le_at (
1079+ & mut ovmf,
1080+ footer_off,
1081+ ( table. len ( ) + OVMF_FOOTER_ENTRY_SIZE ) as u16 ,
1082+ ) ;
1083+ ovmf[ footer_off + 2 ..footer_off + OVMF_FOOTER_ENTRY_SIZE ]
1084+ . copy_from_slice ( & GUID_FOOTER_TABLE ) ;
1085+ ovmf
1086+ }
1087+
1088+ #[ test]
1089+ fn ovmf_parser_matches_synthetic_footer_metadata_vector ( ) {
1090+ let ovmf = synthetic_snp_ovmf ( ) ;
1091+ let info = OvmfInfo :: parse ( ovmf. clone ( ) ) . expect ( "synthetic ovmf parses" ) ;
1092+ assert_eq ! ( info. gpa, FOUR_GIB - ovmf. len( ) as u64 ) ;
1093+ assert_eq ! ( info. sev_hashes_table_gpa, 0x4000 ) ;
1094+ assert_eq ! ( info. sev_es_reset_eip, 0xffff_fff0 ) ;
1095+
1096+ let sections: Vec < ( u64 , u64 , SectionType ) > = info
1097+ . sections
1098+ . iter ( )
1099+ . map ( |s| ( s. gpa , s. size , s. section_type ) )
1100+ . collect ( ) ;
1101+ assert_eq ! (
1102+ sections,
1103+ vec![
1104+ ( 0x1000 , 0x1000 , SectionType :: SnpSecMemory ) ,
1105+ ( 0x2000 , 0x1000 , SectionType :: SnpSecrets ) ,
1106+ ( 0x3000 , 0x1000 , SectionType :: Cpuid ) ,
1107+ ( 0x4000 , 0x1000 , SectionType :: SnpKernelHashes ) ,
1108+ ]
1109+ ) ;
1110+
1111+ let mut gctx = Gctx :: new ( ) ;
1112+ gctx. update_normal_pages ( info. gpa , & info. data ) ;
1113+ assert_eq ! (
1114+ hex:: encode( gctx. ld) ,
1115+ "7c0f80f0a8d0ab1ee23fe763b255b8b210bb71113febcda60d76c00e84512f0cc141ffaa61be7bd22164736e85ec52d3" ,
1116+ "synthetic OVMF launch digest vector should not drift"
1117+ ) ;
1118+ }
1119+
10351120 fn valid_input ( ) -> MeasurementInput {
10361121 let rootfs_hash = hex_of ( 0x33 , 32 ) ;
10371122 MeasurementInput {
0 commit comments