1414use core:: cmp:: Ordering ;
1515
1616use crate :: pi:: {
17- hob:: Hob ,
17+ hob:: { Hob , MEMORY_TYPE_INFO_HOB_GUID } ,
1818 serializable:: { Interval , format_guid, hex_format} ,
1919} ;
20- use alloc:: string:: String ;
20+ use alloc:: { string:: String , vec :: Vec } ;
2121use serde:: { Deserialize , Serialize } ;
2222
2323/// Serializable representation of the different HOB types.
@@ -50,6 +50,14 @@ pub enum HobSerDe {
5050 GuidExtension {
5151 name : String ,
5252 } ,
53+ /// Memory Type Information GUID Extension HOB (Name == `MEMORY_TYPE_INFO_HOB_GUID`).
54+ ///
55+ /// The HOB's data payload is parsed into an array of
56+ /// `(memory_type, number_of_pages)` entries up to (but not including)
57+ /// the sentinel entry whose `memory_type` is `>= EFI_MAX_MEMORY_TYPE`.
58+ MemoryTypeInformation {
59+ entries : Vec < MemoryTypeInfoEntrySerDe > ,
60+ } ,
5361 FirmwareVolume {
5462 #[ serde( with = "hex_format" ) ]
5563 base_address : u64 ,
@@ -62,6 +70,37 @@ pub enum HobSerDe {
6270 UnknownHob ,
6371}
6472
73+ /// Serializable representation of one `EFI_MEMORY_TYPE_INFORMATION` entry inside a Memory
74+ /// Type Information GUID Extension HOB.
75+ #[ derive( Serialize , Deserialize , Debug , Clone , Copy , PartialEq , Eq , PartialOrd , Ord ) ]
76+ pub struct MemoryTypeInfoEntrySerDe {
77+ /// `EFI_MEMORY_TYPE` value for this bin (e.g. `EfiRuntimeServicesData = 6`).
78+ pub memory_type : u32 ,
79+ /// Number of 4 KiB pages requested for this bin.
80+ pub number_of_pages : u32 ,
81+ }
82+
83+ /// Parses the data payload of a Memory Type Information GUID Extension HOB.
84+ ///
85+ /// Each entry is `(u32 memory_type, u32 number_of_pages)` in little-endian order. Parsing
86+ /// stops at (and excludes) the sentinel entry whose `memory_type` is `>= EFI_MAX_MEMORY_TYPE`.
87+ fn parse_memory_type_info_entries ( data : & [ u8 ] ) -> Vec < MemoryTypeInfoEntrySerDe > {
88+ const ENTRY_SIZE : usize = core:: mem:: size_of :: < MemoryTypeInfoEntrySerDe > ( ) ;
89+ let mut entries = Vec :: new ( ) ;
90+ for chunk in data. chunks_exact ( ENTRY_SIZE ) {
91+ let & [ m0, m1, m2, m3, p0, p1, p2, p3] = chunk else {
92+ continue ;
93+ } ;
94+ let memory_type = u32:: from_le_bytes ( [ m0, m1, m2, m3] ) ;
95+ let number_of_pages = u32:: from_le_bytes ( [ p0, p1, p2, p3] ) ;
96+ if ( memory_type as usize ) >= crate :: efi_types:: EFI_MAX_MEMORY_TYPE {
97+ break ;
98+ }
99+ entries. push ( MemoryTypeInfoEntrySerDe { memory_type, number_of_pages } ) ;
100+ }
101+ entries
102+ }
103+
65104/// Serializable representation of the memory allocation descriptor inside a Memory Allocation HOB.
66105#[ derive( Serialize , Deserialize , Debug , Clone , PartialEq , Eq , PartialOrd , Ord ) ]
67106pub struct MemAllocDescriptorSerDe {
@@ -188,7 +227,13 @@ impl From<&Hob<'_>> for HobSerDe {
188227 } ,
189228 attributes : resource_desc2. attributes ,
190229 } ,
191- Hob :: GuidHob ( guid_ext, _) => Self :: GuidExtension { name : format_guid ( & guid_ext. name ) } ,
230+ Hob :: GuidHob ( guid_ext, data) => {
231+ if guid_ext. name == MEMORY_TYPE_INFO_HOB_GUID . into_inner ( ) {
232+ Self :: MemoryTypeInformation { entries : parse_memory_type_info_entries ( data) }
233+ } else {
234+ Self :: GuidExtension { name : format_guid ( & guid_ext. name ) }
235+ }
236+ }
192237 Hob :: FirmwareVolume ( fv) => Self :: FirmwareVolume { base_address : fv. base_address , length : fv. length } ,
193238 Hob :: Cpu ( cpu) => {
194239 Self :: Cpu { size_of_memory_space : cpu. size_of_memory_space , size_of_io_space : cpu. size_of_io_space }
@@ -453,4 +498,43 @@ mod tests {
453498 assert ! ( json. contains( r#""size_of_memory_space": 0"# ) , "CPU memory space size incorrect" ) ;
454499 assert ! ( json. contains( r#""size_of_io_space": 0"# ) , "CPU IO space size incorrect" ) ;
455500 }
501+
502+ #[ test]
503+ fn test_memory_type_information_hob_serialization ( ) {
504+ // Two valid entries followed by a sentinel entry whose memory_type is >= EFI_MAX_MEMORY_TYPE.
505+ let mut data = Vec :: new ( ) ;
506+ data. extend_from_slice ( & 6_u32 . to_le_bytes ( ) ) ; // EfiRuntimeServicesData
507+ data. extend_from_slice ( & 100_u32 . to_le_bytes ( ) ) ;
508+ data. extend_from_slice ( & 9_u32 . to_le_bytes ( ) ) ; // EfiACPIReclaimMemory
509+ data. extend_from_slice ( & 200_u32 . to_le_bytes ( ) ) ;
510+ data. extend_from_slice ( & u32:: MAX . to_le_bytes ( ) ) ; // sentinel
511+ data. extend_from_slice ( & 999_u32 . to_le_bytes ( ) ) ; // ignored sentinel pages
512+
513+ let guid_hob = hob:: GuidHob {
514+ header : hob:: header:: Hob {
515+ r#type : hob:: GUID_EXTENSION ,
516+ length : ( size_of :: < hob:: GuidHob > ( ) + data. len ( ) ) as u16 ,
517+ reserved : 0 ,
518+ } ,
519+ name : MEMORY_TYPE_INFO_HOB_GUID ,
520+ } ;
521+
522+ let serde = HobSerDe :: from ( & Hob :: GuidHob ( & guid_hob, & data) ) ;
523+ let json = to_string_pretty ( & serde) . expect ( "Serialization failed" ) ;
524+
525+ let HobSerDe :: MemoryTypeInformation { entries } = serde else {
526+ panic ! ( "Expected MemoryTypeInformation variant" ) ;
527+ } ;
528+
529+ assert_eq ! (
530+ entries,
531+ alloc:: vec![
532+ MemoryTypeInfoEntrySerDe { memory_type: 6 , number_of_pages: 100 } ,
533+ MemoryTypeInfoEntrySerDe { memory_type: 9 , number_of_pages: 200 } ,
534+ ]
535+ ) ;
536+
537+ assert ! ( json. contains( r#""type": "memory_type_information""# ) , "Memory Type Information HOB missing" ) ;
538+ assert ! ( json. contains( r#""number_of_pages": 200"# ) , "Entry page count incorrect" ) ;
539+ }
456540}
0 commit comments