uefi-rs icon indicating copy to clipboard operation
uefi-rs copied to clipboard

How to convert value returned by `get_variable_boxed()` into a printable `str`?

Open felipebalbi opened this issue 2 years ago • 5 comments

Hi,

I'm experimenting with uefi-rs, specifically I want to read the BootOrder variable (and the accompanying Boot#### variables) and try to write a very minimal boot manager application. Reading the content of the variables is straightforward, but how can I convert the resulting &[u8] into something I can print to the screen?

felipebalbi avatar Aug 23 '23 01:08 felipebalbi

UEFI variables can hold arbitrary data, so there's no single optimal way to print them.

BootOrder is described in section 3.3:

The BootOrder variable contains an array of UINT16 ’s that make up an ordered list of the Boot#### options. The first element in the array is the value for the first logical boot option, the second element is the value for the second logical boot option, etc.

So for BootOrder, you should deserialize it as little-endian u16 values.

Boot#### contain EFI_LOAD_OPTION, which is described in section 3.1.3. That struct contains multiple dynamically-sized fields making it a bit more complicated. You'd deserialize it by reading a little-endian u32. then a u16, then read u16 chars until the null char is reached for the description field, then deserialize the packed DevicePaths, then treating the rest of the data as the OptionalData field.

I think we should add some code to uefi-rs to help with parsing and creating EFI_LOAD_OPTION data, but I don't think we have any such code yet.

nicholasbishop avatar Aug 23 '23 02:08 nicholasbishop

UEFI variables can hold arbitrary data, so there's no single optimal way to print them.

Right. They need to be parsed.

BootOrder is described in section 3.3:

The BootOrder variable contains an array of UINT16 ’s that make up an ordered list of the Boot#### options. The first element in the array is the value for the first logical boot option, the second element is the value for the second logical boot option, etc.

So for BootOrder, you should deserialize it as little-endian u16 values.

I got this far, yes.

Boot#### contain EFI_LOAD_OPTION, which is described in section 3.1.3. That struct contains multiple dynamically-sized fields making it a bit more complicated. You'd deserialize it by reading a little-endian u32. then a u16, then read u16 chars until the null char is reached for the description field, then deserialize the packed DevicePaths, then treating the rest of the data as the OptionalData field.

Heh, this I totally misunderstood. Thanks for the direct description. I'll try looking into this tomorrow.

I think we should add some code to uefi-rs to help with parsing and creating EFI_LOAD_OPTION data, but I don't think we have any such code yet.

Any suggestion where to put the code? A new module altogether? As part of a new EfiLoadOption type? Perhaps with a new EfiLoadOption::try_from() trait implementation? If possible, I'd like to contribute that code, but I'll probably need some rounds of review before the code is up to the project's standards.

Cheers

felipebalbi avatar Aug 23 '23 04:08 felipebalbi

Any suggestion where to put the code? A new module altogether? As part of a new EfiLoadOption type? Perhaps with a new EfiLoadOption::try_from() trait implementation? If possible, I'd like to contribute that code, but I'll probably need some rounds of review before the code is up to the project's standards.

That would be great! I'm thinking maybe a new struct LoadOption in uefi/src/data_types/load_option.rs. This would be a DST type, probably with a trailing [u8] field to contain the three DST fields.

A somewhat similar example that might help to review is the ACPI expanded device path node. The Expanded struct is defined here. Various accessor methods will be needed to get the private field data out of the DST field. (We also have a builder struct defined here for creating an Expanded node. A builder doesn't need to be part of the initial PR for this though, just a read-only struct would be a good place to start.) These structs are generated, so they look a little different from what you'll write, but should be useful as a reference.

nicholasbishop avatar Aug 24 '23 01:08 nicholasbishop

That would be great! I'm thinking maybe a new struct LoadOption in uefi/src/data_types/load_option.rs. This would be a DST type, probably with a trailing [u8] field to contain the three DST fields.

Perfect. I'll start working on that. Do you think it makes sense to add a LoadOption iterator? This would read and parse BootOrder and its next method would read the correct variable, produce the LoadOption struct and return it.

felipebalbi avatar Aug 24 '23 15:08 felipebalbi

I'm not sure about the iterator. It's possible that kind of logic might be too specific to the application using it, so even if we provided it, bootloaders might end up re-implementing their own more specific version. Another option would be to add such code as an example (under uefi-test-runner/examples) and then see if there's anything we feel confident is generic enough to pull out of it.

nicholasbishop avatar Aug 29 '23 19:08 nicholasbishop