Skip to content

[patina::pi::hob] Adjust hob misc design - #1752

Open
yangrongwei wants to merge 6 commits into
OpenDevicePartnership:mainfrom
uefi-lab:adjust_hob_misc_design
Open

[patina::pi::hob] Adjust hob misc design#1752
yangrongwei wants to merge 6 commits into
OpenDevicePartnership:mainfrom
uefi-lab:adjust_hob_misc_design

Conversation

@yangrongwei

@yangrongwei yangrongwei commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Description

Refactor the Hob::Misc design.

Introduce hob::GenericHob to hold the HOB generic header for Hob::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::EndOfHobList for unit tests, this is the correct struct for end-of-hob per PI Spec.
Correct related unit tests to use hob::EndOfHobList

Code Enhancement:
Add align(8) for hob::HobHeader. This is optional for consumers, but following PI Spec is not a bad choice.

  • Impacts functionality?
  • Impacts security?
  • Breaking change?
  • Includes tests?
  • Includes documentation?

How This Was Tested

Pass cargo make test

Integration Instructions

N/A

@patina-automation

Copy link
Copy Markdown
Contributor

⌛ QEMU Validation Pending

QEMU validation is pending on successful CI completion.

Note: Any previous results are available in this comment's edit history.

This comment was automatically generated by the Patina QEMU PR Validation workflow.

@github-actions github-actions Bot added impact:non-functional Does not have a functional impact impact:testing Affects testing labels Aug 21, 2026
@yangrongwei

Copy link
Copy Markdown
Contributor Author

Original bug, #1748

@os-d os-d linked an issue Aug 21, 2026 that may be closed by this pull request
1 task
@os-d
os-d self-requested a review August 21, 2026 17:34
Comment thread sdk/patina/src/pi/hob/hob_list.rs Outdated
Comment thread sdk/patina/src/pi/hob/hob_list.rs Outdated
Comment thread sdk/patina/src/pi/hob/hob_list.rs Outdated
Comment thread sdk/patina/src/pi/hob.rs Outdated
Comment thread sdk/patina/src/pi/hob/hob_list.rs Outdated
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.")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

// we have to relocate HOBs after memory services are initialized as we are going to allocate memory and
// the initial free memory may not be enough to contain the HOB list. We need to relocate the HOBs because
// the initial HOB list is not in mapped memory as passed from pre-DXE.
hob_list.relocate_hobs();

// Leak a DXE allocated PI HOB list so it is available throughout the DXE phase.
let relocated_hob_list = Box::leak(pi_hob_slice.to_vec().into_boxed_slice()).as_mut_ptr().cast::<c_void>();

Minor

Why should we copy the HOB from pre-DXE physical_hob_list to relocated_hob_list?

We have three copys now

  1. The original physical_hob_list
  2. The dxe managed relocated_hob_list
  3. The rust used (partial) hob_list

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned, we need both. I think this is also getting into scope creep.

Comment thread sdk/patina/src/pi/hob/hob_list.rs Outdated
Comment thread sdk/patina/src/pi/hob.rs Outdated
Comment thread sdk/patina/src/pi/hob.rs Outdated
Comment thread sdk/patina/src/pi/hob.rs Outdated
Comment thread sdk/patina/src/pi/hob/hob_list.rs Outdated
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.")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread sdk/patina/src/pi/hob.rs Outdated
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) };

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will follow

Comment thread sdk/patina/src/pi/hob.rs Outdated
Comment thread sdk/patina/src/pi/hob.rs Outdated
Comment thread sdk/patina/src/pi/hob.rs Outdated
Comment thread sdk/patina/src/pi/hob.rs Outdated
@github-actions github-actions Bot added the type:documentation Improvements or additions to documentation label Aug 28, 2026
Comment thread sdk/patina/src/pi/hob.rs
/// - MEMORY_POOL
/// - UNUSED
/// - LOAD_PEIM_UNUSED
Misc(&'a GenericHob),

@Javagedes Javagedes Aug 31, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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])

Comment thread sdk/patina/src/pi/hob.rs
}
END_OF_HOB_LIST => return None,
hob_type => Hob::Misc(hob_type),
MEMORY_POOL | LOAD_PEIM_UNUSED | UNUSED => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we would do something similar to GUID_EXTENSION and call the slice::from_raw_parts(data_ptr, data_len for the user.

Comment thread sdk/patina/src/pi/hob.rs
///
#[repr(C)]
#[derive(Debug)]
pub struct GenericHob {

@Javagedes Javagedes Aug 31, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see a need for GenericHob. It feels like we should just use the HobHeader directly - via the usage I described above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

impact:non-functional Does not have a functional impact impact:testing Affects testing type:documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Question for patina::pi::hob::Hob

5 participants