[patina::pi::hob] Adjust hob misc design - #1752
Conversation
⌛ QEMU Validation PendingQEMU validation is pending on successful CI completion.
This comment was automatically generated by the Patina QEMU PR Validation workflow. |
|
Original bug, #1748 |
| Hob::ResourceDescriptorV2(hob) => *hob = Box::leak(Box::new(ResourceDescriptorV2::clone(hob))), | ||
| Hob::Misc(_) => (), // Data is owned in Misc (nothing to move), | ||
| Hob::EndOfHobList(_) => { | ||
| unreachable!("EndOfHobList Shoul not in list.") |
There was a problem hiding this comment.
This unreachable!() is a runtime panic; a comment indicating why this can't be reached would be nice. If it can be reached based on invalid input (e.g. a weirdly formatted hoblist or something), consider changing it to a debug_assert!() to avoid runtime panic based on input we don't control.
There was a problem hiding this comment.
I don't think unreachable!() is appropriate here. The code is reachable given a malformed HOB list. It falls more into input validation than a logically unreachable case that macro is designed for. Regardless of anything else, I think that should be avoided. debug_assert!() is reasonable to catch the error in debug builds.
There was a problem hiding this comment.
I used unreachable!() because I think the relocate_hobs() fn itself is questionable. I intend to remove the fn.
Q1
For release build, should we relocate these HOBs as well?
Q2
BTW, for the only consumer of relocate_hobs() in patina_dxe_core/src/lib.rs, I think relocate_hobs() is unnecessary.
Given that we redeclare the hob_list on relocated_hob_list.
patina/patina_dxe_core/src/lib.rs
Lines 452 to 455 in e15d0a4
patina/patina_dxe_core/src/lib.rs
Lines 447 to 448 in e15d0a4
Minor
Why should we copy the HOB from pre-DXE physical_hob_list to relocated_hob_list?
We have three copys now
- The original
physical_hob_list - The dxe managed
relocated_hob_list - The rust used (partial)
hob_list
There was a problem hiding this comment.
We need both copies of the HOB list. The hob list as passed in to Patina does not live in allocated memory. It must be relocated before all memory is discovered because it is in free memory. We have one copy of the full HOB list for C drivers to consume in the PI spec format. However, this is not a great format for Rust. So, we use a native Rust format that is good for Rust code to consume and provides a safer abstraction.
There was a problem hiding this comment.
As mentioned, we need both. I think this is also getting into scope creep.
| Hob::ResourceDescriptorV2(hob) => *hob = Box::leak(Box::new(ResourceDescriptorV2::clone(hob))), | ||
| Hob::Misc(_) => (), // Data is owned in Misc (nothing to move), | ||
| Hob::EndOfHobList(_) => { | ||
| unreachable!("EndOfHobList Shoul not in list.") |
There was a problem hiding this comment.
I don't think unreachable!() is appropriate here. The code is reachable given a malformed HOB list. It falls more into input validation than a logically unreachable case that macro is designed for. Regardless of anything else, I think that should be avoided. debug_assert!() is reasonable to catch the error in debug builds.
| fn test_gen_memory_pool() { | ||
| let buffer = gen_memory_pool(); | ||
| assert_eq!(buffer.len(), 0x18); | ||
| let header = unsafe { &*(buffer.as_ptr() as *const hob::GenericHob) }; |
There was a problem hiding this comment.
Please add a safety comment before this unsafe block. Also, I think you should use read_unaligned() here gen_memory_pool() is just an array on the stack which is not guaranteed to by 8-byte aligned.
| /// - MEMORY_POOL | ||
| /// - UNUSED | ||
| /// - LOAD_PEIM_UNUSED | ||
| Misc(&'a GenericHob), |
There was a problem hiding this comment.
There may have been conversation around this, so let me know if so, but If I'm understanding correctly, the Misc hob is incredibly close to the GuidHob. Due to this, I'm not a fan of the fact that we just give the user the header, and it is up to the caller to unsafe-ly extract any bytes after the header if the length exceeds the length of a header. I also don't think we should be using GenericHob. In my opinion it should just be a HobHeader.
I personally think it makes more sense for this enum variable to be below, where our code takes on the burden of extracting the bytes after the header:
Misc(&'a Hobheader, &'a [u8])| } | ||
| END_OF_HOB_LIST => return None, | ||
| hob_type => Hob::Misc(hob_type), | ||
| MEMORY_POOL | LOAD_PEIM_UNUSED | UNUSED => { |
There was a problem hiding this comment.
Here we would do something similar to GUID_EXTENSION and call the slice::from_raw_parts(data_ptr, data_len for the user.
| /// | ||
| #[repr(C)] | ||
| #[derive(Debug)] | ||
| pub struct GenericHob { |
There was a problem hiding this comment.
I don't see a need for GenericHob. It feels like we should just use the HobHeader directly - via the usage I described above.
Description
Refactor the
Hob::Miscdesign.Introduce
hob::GenericHobto hold the HOB generic header forHob::Misc.Per the PI spec, HOB is an open design, and all HOBs share a common header. Binding to a generic header is more intuitive than using a heterogeneous integer representation.
Bug Fix:
Introduce
hob::EndOfHobListfor unit tests, this is the correct struct for end-of-hob per PI Spec.Correct related unit tests to use
hob::EndOfHobListCode Enhancement:
Add
align(8)forhob::HobHeader. This is optional for consumers, but following PI Spec is not a bad choice.How This Was Tested
Pass
cargo make testIntegration Instructions
N/A