diff mbox

[U-Boot,RFC] efi: variable support

Message ID 20170624222918.29018-1-robdclark@gmail.com
State RFC
Delegated to: Alexander Graf
Headers show

Commit Message

Rob Clark June 24, 2017, 10:29 p.m. UTC
Mapping from EFI variables to grub variables.  Still almost as many
TODOs as lines of code, but just figured I'd send out an early version
for comments.

I was thinking of it as a useful way for u-boot to pass values to grub
(although grub is still missing a way for grub scripts to retrieve
UEFI variables).

The rough idea is to encode GUID + variable name plus "efi_" prefix
(to avoid unintended u-boot variables leaking into the UEFI world).
And then encode the type (and attributes?) in the string value of the
variable.  Ie. something like:

  setenv efi_8be4df6193ca11d2aa0d00e098032b8c_OsIndicationsSupported (u64)0

---
 cmd/bootefi.c                 |   3 +
 include/efi.h                 |  19 ++++
 include/efi_loader.h          |  10 ++
 lib/efi_loader/Makefile       |   1 +
 lib/efi_loader/efi_runtime.c  |  17 ++-
 lib/efi_loader/efi_util.h     |  79 ++++++++++++++
 lib/efi_loader/efi_variable.c | 235 ++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 360 insertions(+), 4 deletions(-)
 create mode 100644 lib/efi_loader/efi_util.h
 create mode 100644 lib/efi_loader/efi_variable.c

Comments

Heinrich Schuchardt June 25, 2017, 5:06 a.m. UTC | #1
On 06/25/2017 12:29 AM, Rob Clark wrote:
> Mapping from EFI variables to grub variables.  Still almost as many
> TODOs as lines of code, but just figured I'd send out an early version
> for comments.
> 
> I was thinking of it as a useful way for u-boot to pass values to grub
> (although grub is still missing a way for grub scripts to retrieve
> UEFI variables).
> 
> The rough idea is to encode GUID + variable name plus "efi_" prefix
> (to avoid unintended u-boot variables leaking into the UEFI world).
> And then encode the type (and attributes?) in the string value of the
> variable.  Ie. something like:
> 
>   setenv efi_8be4df6193ca11d2aa0d00e098032b8c_OsIndicationsSupported (u64)0

Hello Rob,

thank you for your effort for a first implementation of EFI variables.


The UEFI variable runtime services consists of the following functions:
GetVariable, GetNextVariableName, SetVariable, QueryVariableInfo.

SetVariable is meant to persistently store variables. The value has to
be maintained across reboots.

A variable consists of a variable name, a vendor GUID, an attribute
bitmask and the variable value.

SetVariable has to support appending to the value.

The UEFI spec also defines some global variables marked by the
EFI_GLOBAL_VARIABLE GUID.


Grub uses UEFI variables to store boot entries for GPT disks.

To do so it requires that the EFI runtime services are available after
Linux is booted.


So my conclusion is that it would be valuable to implement the EFI
variable services. This implementation has to include a persistent
store. The runtime service has to be available after Linux boot.

If we want to manipulate variables from U-Boot we would need two new
commands to set and get EFI variable names, GUIDs, attributes, and values.



Could you, please, provide your use case for manipulating EFI variables
from U-Boot.

One use case I could think of is to let Linux write the dtb name into an
EFI variable and let U-Boot read this EFI variable to decide which dtb
file to load.

Best regards

Heinrich Schuchardt
Rob Clark June 25, 2017, 12:12 p.m. UTC | #2
On Sun, Jun 25, 2017 at 1:06 AM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
> On 06/25/2017 12:29 AM, Rob Clark wrote:
>> Mapping from EFI variables to grub variables.  Still almost as many
>> TODOs as lines of code, but just figured I'd send out an early version
>> for comments.
>>
>> I was thinking of it as a useful way for u-boot to pass values to grub
>> (although grub is still missing a way for grub scripts to retrieve
>> UEFI variables).
>>
>> The rough idea is to encode GUID + variable name plus "efi_" prefix
>> (to avoid unintended u-boot variables leaking into the UEFI world).
>> And then encode the type (and attributes?) in the string value of the
>> variable.  Ie. something like:
>>
>>   setenv efi_8be4df6193ca11d2aa0d00e098032b8c_OsIndicationsSupported (u64)0
>
> Hello Rob,
>
> thank you for your effort for a first implementation of EFI variables.
>
>
> The UEFI variable runtime services consists of the following functions:
> GetVariable, GetNextVariableName, SetVariable, QueryVariableInfo.
>
> SetVariable is meant to persistently store variables. The value has to
> be maintained across reboots.
>
> A variable consists of a variable name, a vendor GUID, an attribute
> bitmask and the variable value.
>
> SetVariable has to support appending to the value.
>
> The UEFI spec also defines some global variables marked by the
> EFI_GLOBAL_VARIABLE GUID.
>
>
> Grub uses UEFI variables to store boot entries for GPT disks.
>
> To do so it requires that the EFI runtime services are available after
> Linux is booted.

This is somewhat more ambitious than what I had in mind, at least for
the first step or two.  By the time linux is loaded, most of u-boot
has disappeared from memory, so currently there is very little it can
provide as far as runtime services.  (I was thinking read-only access
to variables might be possible as a 2nd step.)

otoh, at least for systems that have 1+gb of RAM, u-boot is relatively
tiny, so a build option to keep all of u-boot in RAM after boot might
be a way to approach this.

> So my conclusion is that it would be valuable to implement the EFI
> variable services. This implementation has to include a persistent
> store. The runtime service has to be available after Linux boot.

It would be nice, and it'd make u-boots implementation
(approximation?) of EFI somewhat more complete, for sure.

> If we want to manipulate variables from U-Boot we would need two new
> commands to set and get EFI variable names, GUIDs, attributes, and values.

hmm.. the approach of encoding GUID in variable name and attributes as
part of the string value would mean normal getenv/setenv is all we
need.  This seemed like a more natural approach to me.

> Could you, please, provide your use case for manipulating EFI variables
> from U-Boot.
>
> One use case I could think of is to let Linux write the dtb name into an
> EFI variable and let U-Boot read this EFI variable to decide which dtb
> file to load.

I was kinda thinking in the opposite direction, for u-boot to expose
dtb name to grub.  Also it would be nice for debugging if initial
value of grub's debug env var could be read from EFI.  For both these
cases, read-only access and no runtime access would be sufficient.
And from an implementation standpoint, that seemed like a reasonable
first goal.

BR,
-R
Heinrich Schuchardt June 25, 2017, 5:16 p.m. UTC | #3
On 06/25/2017 02:12 PM, Rob Clark wrote:
> On Sun, Jun 25, 2017 at 1:06 AM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>> On 06/25/2017 12:29 AM, Rob Clark wrote:
>>> Mapping from EFI variables to grub variables.  Still almost as many
>>> TODOs as lines of code, but just figured I'd send out an early version
>>> for comments.
>>>
>>> I was thinking of it as a useful way for u-boot to pass values to grub
>>> (although grub is still missing a way for grub scripts to retrieve
>>> UEFI variables).
>>>
>>> The rough idea is to encode GUID + variable name plus "efi_" prefix
>>> (to avoid unintended u-boot variables leaking into the UEFI world).
>>> And then encode the type (and attributes?) in the string value of the
>>> variable.  Ie. something like:
>>>
>>>   setenv efi_8be4df6193ca11d2aa0d00e098032b8c_OsIndicationsSupported (u64)0
>>
>> Hello Rob,
>>
>> thank you for your effort for a first implementation of EFI variables.
>>
>>
>> The UEFI variable runtime services consists of the following functions:
>> GetVariable, GetNextVariableName, SetVariable, QueryVariableInfo.
>>
>> SetVariable is meant to persistently store variables. The value has to
>> be maintained across reboots.
>>
>> A variable consists of a variable name, a vendor GUID, an attribute
>> bitmask and the variable value.
>>
>> SetVariable has to support appending to the value.
>>
>> The UEFI spec also defines some global variables marked by the
>> EFI_GLOBAL_VARIABLE GUID.
>>
>>
>> Grub uses UEFI variables to store boot entries for GPT disks.
>>
>> To do so it requires that the EFI runtime services are available after
>> Linux is booted.
> 
> This is somewhat more ambitious than what I had in mind, at least for
> the first step or two.  By the time linux is loaded, most of u-boot
> has disappeared from memory, so currently there is very little it can
> provide as far as runtime services.  (I was thinking read-only access
> to variables might be possible as a 2nd step.)
> 
> otoh, at least for systems that have 1+gb of RAM, u-boot is relatively
> tiny, so a build option to keep all of u-boot in RAM after boot might
> be a way to approach this.
> 
>> So my conclusion is that it would be valuable to implement the EFI
>> variable services. This implementation has to include a persistent
>> store. The runtime service has to be available after Linux boot.
> 
> It would be nice, and it'd make u-boots implementation
> (approximation?) of EFI somewhat more complete, for sure.
> 
>> If we want to manipulate variables from U-Boot we would need two new
>> commands to set and get EFI variable names, GUIDs, attributes, and values.
> 
> hmm.. the approach of encoding GUID in variable name and attributes as
> part of the string value would mean normal getenv/setenv is all we
> need.  This seemed like a more natural approach to me.
> 
>> Could you, please, provide your use case for manipulating EFI variables
>> from U-Boot.
>>
>> One use case I could think of is to let Linux write the dtb name into an
>> EFI variable and let U-Boot read this EFI variable to decide which dtb
>> file to load.
> 
> I was kinda thinking in the opposite direction, for u-boot to expose
> dtb name to grub.

The dtb is passed to EFI in memory (2nd parameter of bootefi).
So why should grub need the dtb name?

Regards

Heinrich

>  Also it would be nice for debugging if initial
> value of grub's debug env var could be read from EFI.  For both these
> cases, read-only access and no runtime access would be sufficient.
> And from an implementation standpoint, that seemed like a reasonable
> first goal.
> 
> BR,
> -R
>
Rob Clark June 25, 2017, 7:06 p.m. UTC | #4
On Sun, Jun 25, 2017 at 1:16 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
> On 06/25/2017 02:12 PM, Rob Clark wrote:
>> On Sun, Jun 25, 2017 at 1:06 AM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>>> On 06/25/2017 12:29 AM, Rob Clark wrote:
>>>> Mapping from EFI variables to grub variables.  Still almost as many
>>>> TODOs as lines of code, but just figured I'd send out an early version
>>>> for comments.
>>>>
>>>> I was thinking of it as a useful way for u-boot to pass values to grub
>>>> (although grub is still missing a way for grub scripts to retrieve
>>>> UEFI variables).
>>>>
>>>> The rough idea is to encode GUID + variable name plus "efi_" prefix
>>>> (to avoid unintended u-boot variables leaking into the UEFI world).
>>>> And then encode the type (and attributes?) in the string value of the
>>>> variable.  Ie. something like:
>>>>
>>>>   setenv efi_8be4df6193ca11d2aa0d00e098032b8c_OsIndicationsSupported (u64)0
>>>
>>> Hello Rob,
>>>
>>> thank you for your effort for a first implementation of EFI variables.
>>>
>>>
>>> The UEFI variable runtime services consists of the following functions:
>>> GetVariable, GetNextVariableName, SetVariable, QueryVariableInfo.
>>>
>>> SetVariable is meant to persistently store variables. The value has to
>>> be maintained across reboots.
>>>
>>> A variable consists of a variable name, a vendor GUID, an attribute
>>> bitmask and the variable value.
>>>
>>> SetVariable has to support appending to the value.
>>>
>>> The UEFI spec also defines some global variables marked by the
>>> EFI_GLOBAL_VARIABLE GUID.
>>>
>>>
>>> Grub uses UEFI variables to store boot entries for GPT disks.
>>>
>>> To do so it requires that the EFI runtime services are available after
>>> Linux is booted.
>>
>> This is somewhat more ambitious than what I had in mind, at least for
>> the first step or two.  By the time linux is loaded, most of u-boot
>> has disappeared from memory, so currently there is very little it can
>> provide as far as runtime services.  (I was thinking read-only access
>> to variables might be possible as a 2nd step.)
>>
>> otoh, at least for systems that have 1+gb of RAM, u-boot is relatively
>> tiny, so a build option to keep all of u-boot in RAM after boot might
>> be a way to approach this.
>>
>>> So my conclusion is that it would be valuable to implement the EFI
>>> variable services. This implementation has to include a persistent
>>> store. The runtime service has to be available after Linux boot.
>>
>> It would be nice, and it'd make u-boots implementation
>> (approximation?) of EFI somewhat more complete, for sure.
>>
>>> If we want to manipulate variables from U-Boot we would need two new
>>> commands to set and get EFI variable names, GUIDs, attributes, and values.
>>
>> hmm.. the approach of encoding GUID in variable name and attributes as
>> part of the string value would mean normal getenv/setenv is all we
>> need.  This seemed like a more natural approach to me.
>>
>>> Could you, please, provide your use case for manipulating EFI variables
>>> from U-Boot.
>>>
>>> One use case I could think of is to let Linux write the dtb name into an
>>> EFI variable and let U-Boot read this EFI variable to decide which dtb
>>> file to load.
>>
>> I was kinda thinking in the opposite direction, for u-boot to expose
>> dtb name to grub.
>
> The dtb is passed to EFI in memory (2nd parameter of bootefi).
> So why should grub need the dtb name?
>

because I want to be able to update dtb w/ 'dnf upgrade' (or equiv cmd
for other distros).. the alternative seems to be figuring out how (via
distro u-boot script) to find the most recent dtb, or constantly
requiring users to upgrade their firmware.  Neither of which sounds
appealing.

(the whole idea of a single static dtb for a SoC is nice in theory
until you realize that complex SoC's like snapdragon are still pushing
the boundaries of what we have figured out how to model in dt)

BR,
-R
Heinrich Schuchardt June 25, 2017, 9:07 p.m. UTC | #5
On 06/25/2017 09:06 PM, Rob Clark wrote:
> On Sun, Jun 25, 2017 at 1:16 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>> On 06/25/2017 02:12 PM, Rob Clark wrote:
>>> On Sun, Jun 25, 2017 at 1:06 AM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>>>> On 06/25/2017 12:29 AM, Rob Clark wrote:
>>>>> Mapping from EFI variables to grub variables.  Still almost as many
>>>>> TODOs as lines of code, but just figured I'd send out an early version
>>>>> for comments.
>>>>>
>>>>> I was thinking of it as a useful way for u-boot to pass values to grub
>>>>> (although grub is still missing a way for grub scripts to retrieve
>>>>> UEFI variables).
>>>>>
>>>>> The rough idea is to encode GUID + variable name plus "efi_" prefix
>>>>> (to avoid unintended u-boot variables leaking into the UEFI world).
>>>>> And then encode the type (and attributes?) in the string value of the
>>>>> variable.  Ie. something like:
>>>>>
>>>>>   setenv efi_8be4df6193ca11d2aa0d00e098032b8c_OsIndicationsSupported (u64)0
>>>>
>>>> Hello Rob,
>>>>
>>>> thank you for your effort for a first implementation of EFI variables.
>>>>
>>>>
>>>> The UEFI variable runtime services consists of the following functions:
>>>> GetVariable, GetNextVariableName, SetVariable, QueryVariableInfo.
>>>>
>>>> SetVariable is meant to persistently store variables. The value has to
>>>> be maintained across reboots.
>>>>
>>>> A variable consists of a variable name, a vendor GUID, an attribute
>>>> bitmask and the variable value.
>>>>
>>>> SetVariable has to support appending to the value.
>>>>
>>>> The UEFI spec also defines some global variables marked by the
>>>> EFI_GLOBAL_VARIABLE GUID.
>>>>
>>>>
>>>> Grub uses UEFI variables to store boot entries for GPT disks.
>>>>
>>>> To do so it requires that the EFI runtime services are available after
>>>> Linux is booted.
>>>
>>> This is somewhat more ambitious than what I had in mind, at least for
>>> the first step or two.  By the time linux is loaded, most of u-boot
>>> has disappeared from memory, so currently there is very little it can
>>> provide as far as runtime services.  (I was thinking read-only access
>>> to variables might be possible as a 2nd step.)
>>>
>>> otoh, at least for systems that have 1+gb of RAM, u-boot is relatively
>>> tiny, so a build option to keep all of u-boot in RAM after boot might
>>> be a way to approach this.
>>>
>>>> So my conclusion is that it would be valuable to implement the EFI
>>>> variable services. This implementation has to include a persistent
>>>> store. The runtime service has to be available after Linux boot.
>>>
>>> It would be nice, and it'd make u-boots implementation
>>> (approximation?) of EFI somewhat more complete, for sure.
>>>
>>>> If we want to manipulate variables from U-Boot we would need two new
>>>> commands to set and get EFI variable names, GUIDs, attributes, and values.
>>>
>>> hmm.. the approach of encoding GUID in variable name and attributes as
>>> part of the string value would mean normal getenv/setenv is all we
>>> need.  This seemed like a more natural approach to me.
>>>
>>>> Could you, please, provide your use case for manipulating EFI variables
>>>> from U-Boot.
>>>>
>>>> One use case I could think of is to let Linux write the dtb name into an
>>>> EFI variable and let U-Boot read this EFI variable to decide which dtb
>>>> file to load.
>>>
>>> I was kinda thinking in the opposite direction, for u-boot to expose
>>> dtb name to grub.
>>
>> The dtb is passed to EFI in memory (2nd parameter of bootefi).
>> So why should grub need the dtb name?
>>
> 
> because I want to be able to update dtb w/ 'dnf upgrade' (or equiv cmd
> for other distros).. the alternative seems to be figuring out how (via
> distro u-boot script) to find the most recent dtb, or constantly
> requiring users to upgrade their firmware.  Neither of which sounds
> appealing.
> 
> (the whole idea of a single static dtb for a SoC is nice in theory
> until you realize that complex SoC's like snapdragon are still pushing
> the boundaries of what we have figured out how to model in dt)
> 
> BR,
> -R
> 

Have a look at Debian/Ubuntu package flash-kernel.

After installing a new kernel update-initramfs triggers flash-kernel.
flash-kernel looks up the value provided by file
/proc/device-tree/model
in a database file to find the correct dtb and installs it in /boot. It
further sets a symbolic link
/boot/dtb
to the dtb. So u-boot can simply load /boot/dtb and pass it to grub.

If static dtbs are not enough for your requirements look at device
overlay trees.

Best regards

Heinrich Schuchardt
Rob Clark June 25, 2017, 10:13 p.m. UTC | #6
On Sun, Jun 25, 2017 at 5:07 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
> On 06/25/2017 09:06 PM, Rob Clark wrote:
>> On Sun, Jun 25, 2017 at 1:16 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>>> On 06/25/2017 02:12 PM, Rob Clark wrote:
>>>> On Sun, Jun 25, 2017 at 1:06 AM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>>>>> On 06/25/2017 12:29 AM, Rob Clark wrote:
>>>>>> Mapping from EFI variables to grub variables.  Still almost as many
>>>>>> TODOs as lines of code, but just figured I'd send out an early version
>>>>>> for comments.
>>>>>>
>>>>>> I was thinking of it as a useful way for u-boot to pass values to grub
>>>>>> (although grub is still missing a way for grub scripts to retrieve
>>>>>> UEFI variables).
>>>>>>
>>>>>> The rough idea is to encode GUID + variable name plus "efi_" prefix
>>>>>> (to avoid unintended u-boot variables leaking into the UEFI world).
>>>>>> And then encode the type (and attributes?) in the string value of the
>>>>>> variable.  Ie. something like:
>>>>>>
>>>>>>   setenv efi_8be4df6193ca11d2aa0d00e098032b8c_OsIndicationsSupported (u64)0
>>>>>
>>>>> Hello Rob,
>>>>>
>>>>> thank you for your effort for a first implementation of EFI variables.
>>>>>
>>>>>
>>>>> The UEFI variable runtime services consists of the following functions:
>>>>> GetVariable, GetNextVariableName, SetVariable, QueryVariableInfo.
>>>>>
>>>>> SetVariable is meant to persistently store variables. The value has to
>>>>> be maintained across reboots.
>>>>>
>>>>> A variable consists of a variable name, a vendor GUID, an attribute
>>>>> bitmask and the variable value.
>>>>>
>>>>> SetVariable has to support appending to the value.
>>>>>
>>>>> The UEFI spec also defines some global variables marked by the
>>>>> EFI_GLOBAL_VARIABLE GUID.
>>>>>
>>>>>
>>>>> Grub uses UEFI variables to store boot entries for GPT disks.
>>>>>
>>>>> To do so it requires that the EFI runtime services are available after
>>>>> Linux is booted.
>>>>
>>>> This is somewhat more ambitious than what I had in mind, at least for
>>>> the first step or two.  By the time linux is loaded, most of u-boot
>>>> has disappeared from memory, so currently there is very little it can
>>>> provide as far as runtime services.  (I was thinking read-only access
>>>> to variables might be possible as a 2nd step.)
>>>>
>>>> otoh, at least for systems that have 1+gb of RAM, u-boot is relatively
>>>> tiny, so a build option to keep all of u-boot in RAM after boot might
>>>> be a way to approach this.
>>>>
>>>>> So my conclusion is that it would be valuable to implement the EFI
>>>>> variable services. This implementation has to include a persistent
>>>>> store. The runtime service has to be available after Linux boot.
>>>>
>>>> It would be nice, and it'd make u-boots implementation
>>>> (approximation?) of EFI somewhat more complete, for sure.
>>>>
>>>>> If we want to manipulate variables from U-Boot we would need two new
>>>>> commands to set and get EFI variable names, GUIDs, attributes, and values.
>>>>
>>>> hmm.. the approach of encoding GUID in variable name and attributes as
>>>> part of the string value would mean normal getenv/setenv is all we
>>>> need.  This seemed like a more natural approach to me.
>>>>
>>>>> Could you, please, provide your use case for manipulating EFI variables
>>>>> from U-Boot.
>>>>>
>>>>> One use case I could think of is to let Linux write the dtb name into an
>>>>> EFI variable and let U-Boot read this EFI variable to decide which dtb
>>>>> file to load.
>>>>
>>>> I was kinda thinking in the opposite direction, for u-boot to expose
>>>> dtb name to grub.
>>>
>>> The dtb is passed to EFI in memory (2nd parameter of bootefi).
>>> So why should grub need the dtb name?
>>>
>>
>> because I want to be able to update dtb w/ 'dnf upgrade' (or equiv cmd
>> for other distros).. the alternative seems to be figuring out how (via
>> distro u-boot script) to find the most recent dtb, or constantly
>> requiring users to upgrade their firmware.  Neither of which sounds
>> appealing.
>>
>> (the whole idea of a single static dtb for a SoC is nice in theory
>> until you realize that complex SoC's like snapdragon are still pushing
>> the boundaries of what we have figured out how to model in dt)
>>
>> BR,
>> -R
>>
>
> Have a look at Debian/Ubuntu package flash-kernel.
>
> After installing a new kernel update-initramfs triggers flash-kernel.
> flash-kernel looks up the value provided by file
> /proc/device-tree/model
> in a database file to find the correct dtb and installs it in /boot. It
> further sets a symbolic link
> /boot/dtb
> to the dtb. So u-boot can simply load /boot/dtb and pass it to grub.

but this doesn't work if you want to be able to (for example) unplug a
disk from device A and plug it in to device B, does it?

> If static dtbs are not enough for your requirements look at device
> overlay trees.

I do have some interest in overlays, mostly because currently the
firmware generates psuedo-random eth/wifi/bt MAC addrs based on some
board specific info (like emmc part serial #, for example).. which we
currently loose out from if not using the qcom specific lk->kernel
boot chain.  But I guess that is a bit of a different topic.

BR,
-R
Heinrich Schuchardt June 26, 2017, 6:20 p.m. UTC | #7
On 06/26/2017 12:13 AM, Rob Clark wrote:
>>> (the whole idea of a single static dtb for a SoC is nice in theory
>>> until you realize that complex SoC's like snapdragon are still pushing
>>> the boundaries of what we have figured out how to model in dt)
>>>
>>> BR,
>>> -R
>>>
>> Have a look at Debian/Ubuntu package flash-kernel.
>>
>> After installing a new kernel update-initramfs triggers flash-kernel.
>> flash-kernel looks up the value provided by file
>> /proc/device-tree/model
>> in a database file to find the correct dtb and installs it in /boot. It
>> further sets a symbolic link
>> /boot/dtb
>> to the dtb. So u-boot can simply load /boot/dtb and pass it to grub.
> but this doesn't work if you want to be able to (for example) unplug a
> disk from device A and plug it in to device B, does it?
> 
>> If static dtbs are not enough for your requirements look at device
>> overlay trees.
> I do have some interest in overlays, mostly because currently the
> firmware generates psuedo-random eth/wifi/bt MAC addrs based on some
> board specific info (like emmc part serial #, for example).. which we
> currently loose out from if not using the qcom specific lk->kernel
> boot chain.  But I guess that is a bit of a different topic.
> 
> BR,
> -R
> 

U-Boot can load device tree overlays. Here is what worked for me:

=> load mmc 0:1 0x01000000 dtb
29830 bytes read in 14 ms (2 MiB/s)
=> fdt addr 0x01000000 0x80000
=> load mmc 0:1 0x01080000 rtc.dtbo
529 bytes read in 8 ms (64.5 KiB/s)
=> fdt apply 0x01080000
=> load mmc 0:4 0x13000000 efi/debian/grubaa64.efi
reading efi/debian/grubaa64.efi
120832 bytes read in 7 ms (16.5 MiB/s)
=> bootefi 0x13000000 0x01000000

U-Boot must be configured with
CONFIG_OF_LIBFDT_OVERLAY
to support device tree overlays.

Best regards

Heinrich Schuchardt
Alexander Graf July 12, 2017, 12:57 p.m. UTC | #8
On 25.06.17 00:29, Rob Clark wrote:
> Mapping from EFI variables to grub variables.  Still almost as many
> TODOs as lines of code, but just figured I'd send out an early version
> for comments.
> 
> I was thinking of it as a useful way for u-boot to pass values to grub
> (although grub is still missing a way for grub scripts to retrieve
> UEFI variables).
> 
> The rough idea is to encode GUID + variable name plus "efi_" prefix
> (to avoid unintended u-boot variables leaking into the UEFI world).
> And then encode the type (and attributes?) in the string value of the
> variable.  Ie. something like:
> 
>    setenv efi_8be4df6193ca11d2aa0d00e098032b8c_OsIndicationsSupported (u64)0

That's a pretty nice idea altogether, I agree. I don't think the goal 
you have in mind is good though.

I don't really think we should ever allow grub to override the device 
tree files - unless for development purposes. The reason we are in the 
dt mess we are in today is because it's too easy. People associate 
device trees with kernels, not hardware. That's just plain wrong: device 
trees describe hardware, not Linux interfaces.

As for real variable support (for example to boot using a native EFI 
boot order), I think this approach can work. But before committing to a 
specific path to take, I'd like to see a full solution that allows us to 
maintain these variables consistently in runtime services too, as that's 
required for the boot order.

So far my thinking was that maybe we could push all u-boot variables 
into EL3. That way we could still call into the same space during Linux 
execution. However of course only if there is separate storage to put 
those variables into...


Alex
Rob Clark July 19, 2017, 4:38 p.m. UTC | #9
On Wed, Jul 12, 2017 at 8:57 AM, Alexander Graf <agraf@suse.de> wrote:
>
>
> On 25.06.17 00:29, Rob Clark wrote:
>>
>> Mapping from EFI variables to grub variables.  Still almost as many
>> TODOs as lines of code, but just figured I'd send out an early version
>> for comments.
>>
>> I was thinking of it as a useful way for u-boot to pass values to grub
>> (although grub is still missing a way for grub scripts to retrieve
>> UEFI variables).
>>
>> The rough idea is to encode GUID + variable name plus "efi_" prefix
>> (to avoid unintended u-boot variables leaking into the UEFI world).
>> And then encode the type (and attributes?) in the string value of the
>> variable.  Ie. something like:
>>
>>    setenv efi_8be4df6193ca11d2aa0d00e098032b8c_OsIndicationsSupported
>> (u64)0
>
>
> That's a pretty nice idea altogether, I agree. I don't think the goal you
> have in mind is good though.
>
> I don't really think we should ever allow grub to override the device tree
> files - unless for development purposes. The reason we are in the dt mess we
> are in today is because it's too easy. People associate device trees with
> kernels, not hardware. That's just plain wrong: device trees describe
> hardware, not Linux interfaces.

I kinda wish I could agree with you, but it breaks down quickly when
you start getting into more complex SoC's.  There is enough that we
simply haven't figured out how to model properly in dt.  5yrs from now
I might agree with you ;-)

It might mostly sorta work most of the time if u-boot finds the most
recent dtb (which at least in fedora would mean parsing all the
dtb-x.y.z directory names and figuring out which is newest)

and btw, as someone who works on kernel to the "development purposes"
is an important use-case to me..  and generally it isn't a good idea
to make kernel developer's boot process significantly different from
end users, or you'll just end up in a state where things constantly
work for developers and are broken for distros ;-)

> As for real variable support (for example to boot using a native EFI boot
> order), I think this approach can work. But before committing to a specific
> path to take, I'd like to see a full solution that allows us to maintain
> these variables consistently in runtime services too, as that's required for
> the boot order.

persisting variables, especially after we exit boot-services will
be... interesting.

Rough idea is move env_htab into __efi_runtime_data and some simple
accessors into __efi_runtime.  I think we'll need some board support
to saveenv after a variable is written.  It seems tricky depending on
where the variables are stored (ie. if they are on same eMMC that
linux thinks it owns).

In some cases it might make sense for u-boot to own eMMC (and hide it
from linux) and keep grub and rest of distro media on sd-card /
usb-disk / etc.  I'm not entirely sure how that would work from
kconfig option standpoint, and it would mean that we start adding
drivers and a bunch more in the efi_runtime section.  (And then how to
deal w/ dynamically allocated memory, etc)

BR,
-R

> So far my thinking was that maybe we could push all u-boot variables into
> EL3. That way we could still call into the same space during Linux
> execution. However of course only if there is separate storage to put those
> variables into...
>
>
> Alex
Alexander Graf July 25, 2017, 9:38 a.m. UTC | #10
On 19.07.17 18:38, Rob Clark wrote:
> On Wed, Jul 12, 2017 at 8:57 AM, Alexander Graf <agraf@suse.de> wrote:
>>
>>
>> On 25.06.17 00:29, Rob Clark wrote:
>>>
>>> Mapping from EFI variables to grub variables.  Still almost as many
>>> TODOs as lines of code, but just figured I'd send out an early version
>>> for comments.
>>>
>>> I was thinking of it as a useful way for u-boot to pass values to grub
>>> (although grub is still missing a way for grub scripts to retrieve
>>> UEFI variables).
>>>
>>> The rough idea is to encode GUID + variable name plus "efi_" prefix
>>> (to avoid unintended u-boot variables leaking into the UEFI world).
>>> And then encode the type (and attributes?) in the string value of the
>>> variable.  Ie. something like:
>>>
>>>     setenv efi_8be4df6193ca11d2aa0d00e098032b8c_OsIndicationsSupported
>>> (u64)0
>>
>>
>> That's a pretty nice idea altogether, I agree. I don't think the goal you
>> have in mind is good though.
>>
>> I don't really think we should ever allow grub to override the device tree
>> files - unless for development purposes. The reason we are in the dt mess we
>> are in today is because it's too easy. People associate device trees with
>> kernels, not hardware. That's just plain wrong: device trees describe
>> hardware, not Linux interfaces.
> 
> I kinda wish I could agree with you, but it breaks down quickly when
> you start getting into more complex SoC's.  There is enough that we
> simply haven't figured out how to model properly in dt.  5yrs from now
> I might agree with you ;-)

It's perfectly ok to mismodel things at first. Then the dt would simply 
contain the "old way" nodes as well as the "new way" ones.

Every time we find a case where this approach does not work, we need to 
ask ourselves why. And every time we should ideally find a solution so 
that next time we don't break backwards compatibility.

One good example for that is all of the clock framework mess we have 
today. As a result of that, Andre started to push that logic into ATF 
and made Linux just call into it. Conveniently that also fixes issues with

   a) partitioning hypervisors
   b) trustzone controlling devices in the same clock domain as linux

and I'm sure for other cases where we see it fail we will find solutions 
- at least if people care enough :).

> It might mostly sorta work most of the time if u-boot finds the most
> recent dtb (which at least in fedora would mean parsing all the
> dtb-x.y.z directory names and figuring out which is newest)

Well, the holy grail would be:

   ATF generates DT
   U-Boot uses that DT to configure itself
   U-Boot passes the same DT on to Linux

Of course you can cut the chain at any point. And we have to make sure 
that overrides are always easy enough.

> and btw, as someone who works on kernel to the "development purposes"
> is an important use-case to me..  and generally it isn't a good idea
> to make kernel developer's boot process significantly different from
> end users, or you'll just end up in a state where things constantly
> work for developers and are broken for distros ;-)

I agree :). We still want to have overriding mechanisms. And we do have 
them today. But the normal end user case should really not force them to 
have dtbs and kernels in lock-step.

Take a look at all the server platforms out there. They do work with dtb 
just fine and most of them managed to keep backwards compatibility 
working. The 2 cases I'm aware of really boiled down to "don't care" 
attitudes and thus would've been avoidable.

>> As for real variable support (for example to boot using a native EFI boot
>> order), I think this approach can work. But before committing to a specific
>> path to take, I'd like to see a full solution that allows us to maintain
>> these variables consistently in runtime services too, as that's required for
>> the boot order.
> 
> persisting variables, especially after we exit boot-services will
> be... interesting.
> 
> Rough idea is move env_htab into __efi_runtime_data and some simple
> accessors into __efi_runtime.  I think we'll need some board support
> to saveenv after a variable is written.  It seems tricky depending on
> where the variables are stored (ie. if they are on same eMMC that
> linux thinks it owns).
> 
> In some cases it might make sense for u-boot to own eMMC (and hide it
> from linux) and keep grub and rest of distro media on sd-card /
> usb-disk / etc.  I'm not entirely sure how that would work from
> kconfig option standpoint, and it would mean that we start adding
> drivers and a bunch more in the efi_runtime section.  (And then how to
> deal w/ dynamically allocated memory, etc)

That's why I wanted to push these pieces into EL3, as there's no way 
anyone can make U-Boot drivers work properly with UEFI's dynamic 
relocation mess :).

So if you want a "full uefi env" enabled platform, you'd have to steal a 
storage device completely into the secure world and only drive it from 
there. U-Boot would only call into EL3 to access that device and handle 
its own environment though it. Both in the boot time as well as the 
runtime case.

It really gets tricky if you don't have any dedicated storage available. 
Then we would be able to expose variables in the boot time case, but not 
in the runtime one. And I'm not sure how hard that would confuse 
applications ...


Alex
Rob Clark July 25, 2017, 12:47 p.m. UTC | #11
On Tue, Jul 25, 2017 at 5:38 AM, Alexander Graf <agraf@suse.de> wrote:
>
>
> On 19.07.17 18:38, Rob Clark wrote:
>>
>> On Wed, Jul 12, 2017 at 8:57 AM, Alexander Graf <agraf@suse.de> wrote:
>>>
>>>
>>>
>>> On 25.06.17 00:29, Rob Clark wrote:
>>>>
>>>>
>>>> Mapping from EFI variables to grub variables.  Still almost as many
>>>> TODOs as lines of code, but just figured I'd send out an early version
>>>> for comments.
>>>>
>>>> I was thinking of it as a useful way for u-boot to pass values to grub
>>>> (although grub is still missing a way for grub scripts to retrieve
>>>> UEFI variables).
>>>>
>>>> The rough idea is to encode GUID + variable name plus "efi_" prefix
>>>> (to avoid unintended u-boot variables leaking into the UEFI world).
>>>> And then encode the type (and attributes?) in the string value of the
>>>> variable.  Ie. something like:
>>>>
>>>>     setenv efi_8be4df6193ca11d2aa0d00e098032b8c_OsIndicationsSupported
>>>> (u64)0
>>>
>>>
>>>
>>> That's a pretty nice idea altogether, I agree. I don't think the goal you
>>> have in mind is good though.
>>>
>>> I don't really think we should ever allow grub to override the device
>>> tree
>>> files - unless for development purposes. The reason we are in the dt mess
>>> we
>>> are in today is because it's too easy. People associate device trees with
>>> kernels, not hardware. That's just plain wrong: device trees describe
>>> hardware, not Linux interfaces.
>>
>>
>> I kinda wish I could agree with you, but it breaks down quickly when
>> you start getting into more complex SoC's.  There is enough that we
>> simply haven't figured out how to model properly in dt.  5yrs from now
>> I might agree with you ;-)
>
>
> It's perfectly ok to mismodel things at first. Then the dt would simply
> contain the "old way" nodes as well as the "new way" ones.

sometimes, easier said than done

> Every time we find a case where this approach does not work, we need to ask
> ourselves why. And every time we should ideally find a solution so that next
> time we don't break backwards compatibility.
>
> One good example for that is all of the clock framework mess we have today.
> As a result of that, Andre started to push that logic into ATF and made
> Linux just call into it. Conveniently that also fixes issues with
>
>   a) partitioning hypervisors
>   b) trustzone controlling devices in the same clock domain as linux

snapdragon has the same issue, but also some clks and regulators, etc,
are also used by various other cores on the SoC (dsp's, etc).. for
those resources, they actually manage via an "rpm" core (resource
power mgr, iirc).

tbh, I think just going the UEFI+ACPI route would, I think, make it
much easier for qcom to upstream their firehose of rather complex
SoC's by abstracting a lot of the complexity below linux.  But not my
call.

> and I'm sure for other cases where we see it fail we will find solutions -
> at least if people care enough :).

I agree.. it's just a big task.  Which is why I said earlier that I'll
agree with your position in 5 yrs ;-)

>> It might mostly sorta work most of the time if u-boot finds the most
>> recent dtb (which at least in fedora would mean parsing all the
>> dtb-x.y.z directory names and figuring out which is newest)
>
>
> Well, the holy grail would be:
>
>   ATF generates DT
>   U-Boot uses that DT to configure itself
>   U-Boot passes the same DT on to Linux
>
> Of course you can cut the chain at any point. And we have to make sure that
> overrides are always easy enough.
>
>> and btw, as someone who works on kernel to the "development purposes"
>> is an important use-case to me..  and generally it isn't a good idea
>> to make kernel developer's boot process significantly different from
>> end users, or you'll just end up in a state where things constantly
>> work for developers and are broken for distros ;-)
>
>
> I agree :). We still want to have overriding mechanisms. And we do have them
> today. But the normal end user case should really not force them to have
> dtbs and kernels in lock-step.
>
> Take a look at all the server platforms out there. They do work with dtb
> just fine and most of them managed to keep backwards compatibility working.
> The 2 cases I'm aware of really boiled down to "don't care" attitudes and
> thus would've been avoidable.

The idealistic approach that you want is fine for servers and a bunch
of other simple industrial SoCs out there.. simply because they are so
much less complex.  I don't think it is as much of a "don't care"
attitude (at least not all of the time).. as much as a whole different
level of complexity in the SoC.  Trying to say that this approach
works for something like am33xx so it ought to work for anyone is just
misunderstanding the scope of the problem.


>>> As for real variable support (for example to boot using a native EFI boot
>>> order), I think this approach can work. But before committing to a
>>> specific
>>> path to take, I'd like to see a full solution that allows us to maintain
>>> these variables consistently in runtime services too, as that's required
>>> for
>>> the boot order.
>>
>>
>> persisting variables, especially after we exit boot-services will
>> be... interesting.
>>
>> Rough idea is move env_htab into __efi_runtime_data and some simple
>> accessors into __efi_runtime.  I think we'll need some board support
>> to saveenv after a variable is written.  It seems tricky depending on
>> where the variables are stored (ie. if they are on same eMMC that
>> linux thinks it owns).
>>
>> In some cases it might make sense for u-boot to own eMMC (and hide it
>> from linux) and keep grub and rest of distro media on sd-card /
>> usb-disk / etc.  I'm not entirely sure how that would work from
>> kconfig option standpoint, and it would mean that we start adding
>> drivers and a bunch more in the efi_runtime section.  (And then how to
>> deal w/ dynamically allocated memory, etc)
>
>
> That's why I wanted to push these pieces into EL3, as there's no way anyone
> can make U-Boot drivers work properly with UEFI's dynamic relocation mess
> :).
>
> So if you want a "full uefi env" enabled platform, you'd have to steal a
> storage device completely into the secure world and only drive it from
> there. U-Boot would only call into EL3 to access that device and handle its
> own environment though it. Both in the boot time as well as the runtime
> case.
>
> It really gets tricky if you don't have any dedicated storage available.
> Then we would be able to expose variables in the boot time case, but not in
> the runtime one. And I'm not sure how hard that would confuse applications
> ...

I think for the immediate problem of making an installed OS partition
(as opposed to "live media") work, just having variables before we
exit runtime services is sufficient.  It means, for example, having to
edit efivars.txt instead of using grub2-reboot.. but ok, it's a pretty
big improvement over the current state.

Post runtime-services is definitely not part of the first patchset.

BR,
-R
Alexander Graf July 25, 2017, 2:25 p.m. UTC | #12
On 25.07.17 14:47, Rob Clark wrote:
> On Tue, Jul 25, 2017 at 5:38 AM, Alexander Graf <agraf@suse.de> wrote:
>>
>>
>> On 19.07.17 18:38, Rob Clark wrote:
>>>
>>> On Wed, Jul 12, 2017 at 8:57 AM, Alexander Graf <agraf@suse.de> wrote:
>>>>
>>>>
>>>>
>>>> On 25.06.17 00:29, Rob Clark wrote:
>>>>>
>>>>>
>>>>> Mapping from EFI variables to grub variables.  Still almost as many
>>>>> TODOs as lines of code, but just figured I'd send out an early version
>>>>> for comments.
>>>>>
>>>>> I was thinking of it as a useful way for u-boot to pass values to grub
>>>>> (although grub is still missing a way for grub scripts to retrieve
>>>>> UEFI variables).
>>>>>
>>>>> The rough idea is to encode GUID + variable name plus "efi_" prefix
>>>>> (to avoid unintended u-boot variables leaking into the UEFI world).
>>>>> And then encode the type (and attributes?) in the string value of the
>>>>> variable.  Ie. something like:
>>>>>
>>>>>      setenv efi_8be4df6193ca11d2aa0d00e098032b8c_OsIndicationsSupported
>>>>> (u64)0
>>>>
>>>>
>>>>
>>>> That's a pretty nice idea altogether, I agree. I don't think the goal you
>>>> have in mind is good though.
>>>>
>>>> I don't really think we should ever allow grub to override the device
>>>> tree
>>>> files - unless for development purposes. The reason we are in the dt mess
>>>> we
>>>> are in today is because it's too easy. People associate device trees with
>>>> kernels, not hardware. That's just plain wrong: device trees describe
>>>> hardware, not Linux interfaces.
>>>
>>>
>>> I kinda wish I could agree with you, but it breaks down quickly when
>>> you start getting into more complex SoC's.  There is enough that we
>>> simply haven't figured out how to model properly in dt.  5yrs from now
>>> I might agree with you ;-)
>>
>>
>> It's perfectly ok to mismodel things at first. Then the dt would simply
>> contain the "old way" nodes as well as the "new way" ones.
> 
> sometimes, easier said than done

Yes, I know :).

> 
>> Every time we find a case where this approach does not work, we need to ask
>> ourselves why. And every time we should ideally find a solution so that next
>> time we don't break backwards compatibility.
>>
>> One good example for that is all of the clock framework mess we have today.
>> As a result of that, Andre started to push that logic into ATF and made
>> Linux just call into it. Conveniently that also fixes issues with
>>
>>    a) partitioning hypervisors
>>    b) trustzone controlling devices in the same clock domain as linux
> 
> snapdragon has the same issue, but also some clks and regulators, etc,
> are also used by various other cores on the SoC (dsp's, etc).. for
> those resources, they actually manage via an "rpm" core (resource
> power mgr, iirc).
> 
> tbh, I think just going the UEFI+ACPI route would, I think, make it
> much easier for qcom to upstream their firehose of rather complex
> SoC's by abstracting a lot of the complexity below linux.  But not my
> call.
Well, the DT alternative to ACPI byte code are PSCI calls ;).

>> and I'm sure for other cases where we see it fail we will find solutions -
>> at least if people care enough :).
> 
> I agree.. it's just a big task.  Which is why I said earlier that I'll
> agree with your position in 5 yrs ;-)

So any time you come across such a situation, I'd love to hear back on 
why it was hard. I'm just afraid that if nobody attacks the problems 
that do arise, we will have the same statement again in 5 years :).

> 
>>> It might mostly sorta work most of the time if u-boot finds the most
>>> recent dtb (which at least in fedora would mean parsing all the
>>> dtb-x.y.z directory names and figuring out which is newest)
>>
>>
>> Well, the holy grail would be:
>>
>>    ATF generates DT
>>    U-Boot uses that DT to configure itself
>>    U-Boot passes the same DT on to Linux
>>
>> Of course you can cut the chain at any point. And we have to make sure that
>> overrides are always easy enough.
>>
>>> and btw, as someone who works on kernel to the "development purposes"
>>> is an important use-case to me..  and generally it isn't a good idea
>>> to make kernel developer's boot process significantly different from
>>> end users, or you'll just end up in a state where things constantly
>>> work for developers and are broken for distros ;-)
>>
>>
>> I agree :). We still want to have overriding mechanisms. And we do have them
>> today. But the normal end user case should really not force them to have
>> dtbs and kernels in lock-step.
>>
>> Take a look at all the server platforms out there. They do work with dtb
>> just fine and most of them managed to keep backwards compatibility working.
>> The 2 cases I'm aware of really boiled down to "don't care" attitudes and
>> thus would've been avoidable.
> 
> The idealistic approach that you want is fine for servers and a bunch
> of other simple industrial SoCs out there.. simply because they are so
> much less complex.  I don't think it is as much of a "don't care"
> attitude (at least not all of the time).. as much as a whole different
> level of complexity in the SoC.  Trying to say that this approach
> works for something like am33xx so it ought to work for anyone is just
> misunderstanding the scope of the problem.

Yes, as I mentioned above, I want to learn about all the cases where it 
went wrong, take a step back and figure out why it was impossible to 
stay compatible.

Maybe the end result of that will be to dispair and rip all my hair out. 
But maybe we will find ways to ease the pain next time :).

>>>> As for real variable support (for example to boot using a native EFI boot
>>>> order), I think this approach can work. But before committing to a
>>>> specific
>>>> path to take, I'd like to see a full solution that allows us to maintain
>>>> these variables consistently in runtime services too, as that's required
>>>> for
>>>> the boot order.
>>>
>>>
>>> persisting variables, especially after we exit boot-services will
>>> be... interesting.
>>>
>>> Rough idea is move env_htab into __efi_runtime_data and some simple
>>> accessors into __efi_runtime.  I think we'll need some board support
>>> to saveenv after a variable is written.  It seems tricky depending on
>>> where the variables are stored (ie. if they are on same eMMC that
>>> linux thinks it owns).
>>>
>>> In some cases it might make sense for u-boot to own eMMC (and hide it
>>> from linux) and keep grub and rest of distro media on sd-card /
>>> usb-disk / etc.  I'm not entirely sure how that would work from
>>> kconfig option standpoint, and it would mean that we start adding
>>> drivers and a bunch more in the efi_runtime section.  (And then how to
>>> deal w/ dynamically allocated memory, etc)
>>
>>
>> That's why I wanted to push these pieces into EL3, as there's no way anyone
>> can make U-Boot drivers work properly with UEFI's dynamic relocation mess
>> :).
>>
>> So if you want a "full uefi env" enabled platform, you'd have to steal a
>> storage device completely into the secure world and only drive it from
>> there. U-Boot would only call into EL3 to access that device and handle its
>> own environment though it. Both in the boot time as well as the runtime
>> case.
>>
>> It really gets tricky if you don't have any dedicated storage available.
>> Then we would be able to expose variables in the boot time case, but not in
>> the runtime one. And I'm not sure how hard that would confuse applications
>> ...
> 
> I think for the immediate problem of making an installed OS partition
> (as opposed to "live media") work, just having variables before we
> exit runtime services is sufficient.  It means, for example, having to
> edit efivars.txt instead of using grub2-reboot.. but ok, it's a pretty
> big improvement over the current state.

Well, it wouldn't be efivars but just the already existing bootenv which 
can also already be stored in .txt format on SD card ;).

Also, openSUSE has special support for non-efi-var booting. It detects 
that there is no efi var support and in that case simply installs grub 
with --removable --no-nvram. That way booting "just works" for the 
default case that basically everyone cares about.

> Post runtime-services is definitely not part of the first patchset.

So yeah, maybe this can work. I definitely don't want to expose any sort 
of fake RTS variable services, as that would break the logic above ;).


Alex
Rob Clark July 25, 2017, 3:47 p.m. UTC | #13
On Tue, Jul 25, 2017 at 10:25 AM, Alexander Graf <agraf@suse.de> wrote:
>
>
> On 25.07.17 14:47, Rob Clark wrote:
>>
>> On Tue, Jul 25, 2017 at 5:38 AM, Alexander Graf <agraf@suse.de> wrote:
>>>
>>> I agree :). We still want to have overriding mechanisms. And we do have
>>> them
>>> today. But the normal end user case should really not force them to have
>>> dtbs and kernels in lock-step.
>>>
>>> Take a look at all the server platforms out there. They do work with dtb
>>> just fine and most of them managed to keep backwards compatibility
>>> working.
>>> The 2 cases I'm aware of really boiled down to "don't care" attitudes and
>>> thus would've been avoidable.
>>
>>
>> The idealistic approach that you want is fine for servers and a bunch
>> of other simple industrial SoCs out there.. simply because they are so
>> much less complex.  I don't think it is as much of a "don't care"
>> attitude (at least not all of the time).. as much as a whole different
>> level of complexity in the SoC.  Trying to say that this approach
>> works for something like am33xx so it ought to work for anyone is just
>> misunderstanding the scope of the problem.
>
>
> Yes, as I mentioned above, I want to learn about all the cases where it went
> wrong, take a step back and figure out why it was impossible to stay
> compatible.
>
> Maybe the end result of that will be to dispair and rip all my hair out. But
> maybe we will find ways to ease the pain next time :).

I know recently on one board there were some issues because of the way
host and otg usb were muxed (I'm not sure the details, I'm not a usb
expert, nor do I have time to be), which at some point will require a
non-backwards compatible dt change.  In the past it took a while to
describe more complex display topologies with bridge chips.  There is
still the yet unanswered question of how to handle interconnect/NoC
bus scaling.  Probably other cases that don't come to mind offhand..
I know downstream kernel has a lot of tricks for power saving which we
haven't figured out how to do upstream yet.

>>
>> I think for the immediate problem of making an installed OS partition
>> (as opposed to "live media") work, just having variables before we
>> exit runtime services is sufficient.  It means, for example, having to
>> edit efivars.txt instead of using grub2-reboot.. but ok, it's a pretty
>> big improvement over the current state.
>
>
> Well, it wouldn't be efivars but just the already existing bootenv which can
> also already be stored in .txt format on SD card ;).
>
> Also, openSUSE has special support for non-efi-var booting. It detects that
> there is no efi var support and in that case simply installs grub with
> --removable --no-nvram. That way booting "just works" for the default case
> that basically everyone cares about.
>
>> Post runtime-services is definitely not part of the first patchset.
>
>
> So yeah, maybe this can work. I definitely don't want to expose any sort of
> fake RTS variable services, as that would break the logic above ;).
>

I don't think we have an choice if we want to have cross-distro
"firmware", since post-RTS variables aren't going to be possible on
all devices, I don't think.  Otherwise I would have just stuck with my
u-boot hack patch that loads \EFI\fedora\grubaa64.efi directly and not
bothered with all this work ;-)

Anyways, it wouldn't really break you.. it would just change the logic
above to not do the hack of installing as a live-media image that
thinks it owns the whole disk.  And then we could install multiple
distros on different partitions on the same disk (with the caveat of
having to edit efivars.txt to change boot-order... possibly we could
invent a u-boot script or bootorder.efi that shows a menu on screen if
you boot with some key held down, similar to what you get on x86).

BR,
-R
Alexander Graf July 25, 2017, 4:55 p.m. UTC | #14
On 25.07.17 17:47, Rob Clark wrote:
> On Tue, Jul 25, 2017 at 10:25 AM, Alexander Graf <agraf@suse.de> wrote:
>>
>>
>> On 25.07.17 14:47, Rob Clark wrote:
>>>
>>> On Tue, Jul 25, 2017 at 5:38 AM, Alexander Graf <agraf@suse.de> wrote:
>>>>
>>>> I agree :). We still want to have overriding mechanisms. And we do have
>>>> them
>>>> today. But the normal end user case should really not force them to have
>>>> dtbs and kernels in lock-step.
>>>>
>>>> Take a look at all the server platforms out there. They do work with dtb
>>>> just fine and most of them managed to keep backwards compatibility
>>>> working.
>>>> The 2 cases I'm aware of really boiled down to "don't care" attitudes and
>>>> thus would've been avoidable.
>>>
>>>
>>> The idealistic approach that you want is fine for servers and a bunch
>>> of other simple industrial SoCs out there.. simply because they are so
>>> much less complex.  I don't think it is as much of a "don't care"
>>> attitude (at least not all of the time).. as much as a whole different
>>> level of complexity in the SoC.  Trying to say that this approach
>>> works for something like am33xx so it ought to work for anyone is just
>>> misunderstanding the scope of the problem.
>>
>>
>> Yes, as I mentioned above, I want to learn about all the cases where it went
>> wrong, take a step back and figure out why it was impossible to stay
>> compatible.
>>
>> Maybe the end result of that will be to dispair and rip all my hair out. But
>> maybe we will find ways to ease the pain next time :).
> 
> I know recently on one board there were some issues because of the way
> host and otg usb were muxed (I'm not sure the details, I'm not a usb
> expert, nor do I have time to be), which at some point will require a
> non-backwards compatible dt change.  In the past it took a while to
> describe more complex display topologies with bridge chips.  There is
> still the yet unanswered question of how to handle interconnect/NoC
> bus scaling.  Probably other cases that don't come to mind offhand..
> I know downstream kernel has a lot of tricks for power saving which we
> haven't figured out how to do upstream yet.
> 
>>>
>>> I think for the immediate problem of making an installed OS partition
>>> (as opposed to "live media") work, just having variables before we
>>> exit runtime services is sufficient.  It means, for example, having to
>>> edit efivars.txt instead of using grub2-reboot.. but ok, it's a pretty
>>> big improvement over the current state.
>>
>>
>> Well, it wouldn't be efivars but just the already existing bootenv which can
>> also already be stored in .txt format on SD card ;).
>>
>> Also, openSUSE has special support for non-efi-var booting. It detects that
>> there is no efi var support and in that case simply installs grub with
>> --removable --no-nvram. That way booting "just works" for the default case
>> that basically everyone cares about.
>>
>>> Post runtime-services is definitely not part of the first patchset.
>>
>>
>> So yeah, maybe this can work. I definitely don't want to expose any sort of
>> fake RTS variable services, as that would break the logic above ;).
>>
> 
> I don't think we have an choice if we want to have cross-distro
> "firmware", since post-RTS variables aren't going to be possible on
> all devices, I don't think.  Otherwise I would have just stuck with my
> u-boot hack patch that loads \EFI\fedora\grubaa64.efi directly and not
> bothered with all this work ;-)
> 
> Anyways, it wouldn't really break you.. it would just change the logic
> above to not do the hack of installing as a live-media image that
> thinks it owns the whole disk.  And then we could install multiple
> distros on different partitions on the same disk (with the caveat of
> having to edit efivars.txt to change boot-order... possibly we could
> invent a u-boot script or bootorder.efi that shows a menu on screen if
> you boot with some key held down, similar to what you get on x86).

No, we either implement real EFI vars to Linux or none at all, but I 
don't want to see us reinvent random non-UEFI standard ways of doing 
what people expect it to do.

So while yes, before exit_boot_services I think we can expose efi 
variables, I definitely don't want to see anything "fake" or "different 
from standard UEFI" within Linux. And that only works with dedicated (or 
virtualized) storage.

I can understand that it feels appealing to only have a small hack in 
Linux to get the full UEFI greatness, but I really believe we should 
either stick to the spec or not expose functionality at all. Anything in 
between will result in terrible divergence, breakage and means we're 
still not compliant - which goes against the whole idea.

Of course if instead you're interested to change the UEFI spec to 
standardize an alternative mechanism for variable storage, I'm all ears :).


Alex
Rob Clark July 25, 2017, 5:23 p.m. UTC | #15
On Tue, Jul 25, 2017 at 12:55 PM, Alexander Graf <agraf@suse.de> wrote:
>
>
> On 25.07.17 17:47, Rob Clark wrote:
>>
>> On Tue, Jul 25, 2017 at 10:25 AM, Alexander Graf <agraf@suse.de> wrote:
>>>
>>>
>>>
>>> On 25.07.17 14:47, Rob Clark wrote:
>>>>
>>>>
>>>> On Tue, Jul 25, 2017 at 5:38 AM, Alexander Graf <agraf@suse.de> wrote:
>>>>>
>>>>>
>>>>> I agree :). We still want to have overriding mechanisms. And we do have
>>>>> them
>>>>> today. But the normal end user case should really not force them to
>>>>> have
>>>>> dtbs and kernels in lock-step.
>>>>>
>>>>> Take a look at all the server platforms out there. They do work with
>>>>> dtb
>>>>> just fine and most of them managed to keep backwards compatibility
>>>>> working.
>>>>> The 2 cases I'm aware of really boiled down to "don't care" attitudes
>>>>> and
>>>>> thus would've been avoidable.
>>>>
>>>>
>>>>
>>>> The idealistic approach that you want is fine for servers and a bunch
>>>> of other simple industrial SoCs out there.. simply because they are so
>>>> much less complex.  I don't think it is as much of a "don't care"
>>>> attitude (at least not all of the time).. as much as a whole different
>>>> level of complexity in the SoC.  Trying to say that this approach
>>>> works for something like am33xx so it ought to work for anyone is just
>>>> misunderstanding the scope of the problem.
>>>
>>>
>>>
>>> Yes, as I mentioned above, I want to learn about all the cases where it
>>> went
>>> wrong, take a step back and figure out why it was impossible to stay
>>> compatible.
>>>
>>> Maybe the end result of that will be to dispair and rip all my hair out.
>>> But
>>> maybe we will find ways to ease the pain next time :).
>>
>>
>> I know recently on one board there were some issues because of the way
>> host and otg usb were muxed (I'm not sure the details, I'm not a usb
>> expert, nor do I have time to be), which at some point will require a
>> non-backwards compatible dt change.  In the past it took a while to
>> describe more complex display topologies with bridge chips.  There is
>> still the yet unanswered question of how to handle interconnect/NoC
>> bus scaling.  Probably other cases that don't come to mind offhand..
>> I know downstream kernel has a lot of tricks for power saving which we
>> haven't figured out how to do upstream yet.
>>
>>>>
>>>> I think for the immediate problem of making an installed OS partition
>>>> (as opposed to "live media") work, just having variables before we
>>>> exit runtime services is sufficient.  It means, for example, having to
>>>> edit efivars.txt instead of using grub2-reboot.. but ok, it's a pretty
>>>> big improvement over the current state.
>>>
>>>
>>>
>>> Well, it wouldn't be efivars but just the already existing bootenv which
>>> can
>>> also already be stored in .txt format on SD card ;).
>>>
>>> Also, openSUSE has special support for non-efi-var booting. It detects
>>> that
>>> there is no efi var support and in that case simply installs grub with
>>> --removable --no-nvram. That way booting "just works" for the default
>>> case
>>> that basically everyone cares about.
>>>
>>>> Post runtime-services is definitely not part of the first patchset.
>>>
>>>
>>>
>>> So yeah, maybe this can work. I definitely don't want to expose any sort
>>> of
>>> fake RTS variable services, as that would break the logic above ;).
>>>
>>
>> I don't think we have an choice if we want to have cross-distro
>> "firmware", since post-RTS variables aren't going to be possible on
>> all devices, I don't think.  Otherwise I would have just stuck with my
>> u-boot hack patch that loads \EFI\fedora\grubaa64.efi directly and not
>> bothered with all this work ;-)
>>
>> Anyways, it wouldn't really break you.. it would just change the logic
>> above to not do the hack of installing as a live-media image that
>> thinks it owns the whole disk.  And then we could install multiple
>> distros on different partitions on the same disk (with the caveat of
>> having to edit efivars.txt to change boot-order... possibly we could
>> invent a u-boot script or bootorder.efi that shows a menu on screen if
>> you boot with some key held down, similar to what you get on x86).
>
>
> No, we either implement real EFI vars to Linux or none at all, but I don't
> want to see us reinvent random non-UEFI standard ways of doing what people
> expect it to do.
>
> So while yes, before exit_boot_services I think we can expose efi variables,
> I definitely don't want to see anything "fake" or "different from standard
> UEFI" within Linux. And that only works with dedicated (or virtualized)
> storage.

I wasn't planning to expose efi vars to linux (or anything post EBS).
My rough plan was to persist all the env vars that start with efi_ in
EBS while we still have u-boot drivers, to make them available on next
boot, but *only* to shim/fallback/grub.. not post-EBS.

Like I said earlier, on devices without a proper way to do efi vars,
you have to 'sudo vim /boot/efi/efivars.txt' instead of 'grub2-reboot
2', etc.

BR,
-R

> I can understand that it feels appealing to only have a small hack in Linux
> to get the full UEFI greatness, but I really believe we should either stick
> to the spec or not expose functionality at all. Anything in between will
> result in terrible divergence, breakage and means we're still not compliant
> - which goes against the whole idea.
>
> Of course if instead you're interested to change the UEFI spec to
> standardize an alternative mechanism for variable storage, I'm all ears :).
>
>
> Alex
Alexander Graf July 25, 2017, 5:29 p.m. UTC | #16
> Am 25.07.2017 um 19:23 schrieb Rob Clark <robdclark@gmail.com>:
> 
>> On Tue, Jul 25, 2017 at 12:55 PM, Alexander Graf <agraf@suse.de> wrote:
>> 
>> 
>>> On 25.07.17 17:47, Rob Clark wrote:
>>> 
>>>> On Tue, Jul 25, 2017 at 10:25 AM, Alexander Graf <agraf@suse.de> wrote:
>>>> 
>>>> 
>>>> 
>>>>> On 25.07.17 14:47, Rob Clark wrote:
>>>>> 
>>>>> 
>>>>>> On Tue, Jul 25, 2017 at 5:38 AM, Alexander Graf <agraf@suse.de> wrote:
>>>>>> 
>>>>>> 
>>>>>> I agree :). We still want to have overriding mechanisms. And we do have
>>>>>> them
>>>>>> today. But the normal end user case should really not force them to
>>>>>> have
>>>>>> dtbs and kernels in lock-step.
>>>>>> 
>>>>>> Take a look at all the server platforms out there. They do work with
>>>>>> dtb
>>>>>> just fine and most of them managed to keep backwards compatibility
>>>>>> working.
>>>>>> The 2 cases I'm aware of really boiled down to "don't care" attitudes
>>>>>> and
>>>>>> thus would've been avoidable.
>>>>> 
>>>>> 
>>>>> 
>>>>> The idealistic approach that you want is fine for servers and a bunch
>>>>> of other simple industrial SoCs out there.. simply because they are so
>>>>> much less complex.  I don't think it is as much of a "don't care"
>>>>> attitude (at least not all of the time).. as much as a whole different
>>>>> level of complexity in the SoC.  Trying to say that this approach
>>>>> works for something like am33xx so it ought to work for anyone is just
>>>>> misunderstanding the scope of the problem.
>>>> 
>>>> 
>>>> 
>>>> Yes, as I mentioned above, I want to learn about all the cases where it
>>>> went
>>>> wrong, take a step back and figure out why it was impossible to stay
>>>> compatible.
>>>> 
>>>> Maybe the end result of that will be to dispair and rip all my hair out.
>>>> But
>>>> maybe we will find ways to ease the pain next time :).
>>> 
>>> 
>>> I know recently on one board there were some issues because of the way
>>> host and otg usb were muxed (I'm not sure the details, I'm not a usb
>>> expert, nor do I have time to be), which at some point will require a
>>> non-backwards compatible dt change.  In the past it took a while to
>>> describe more complex display topologies with bridge chips.  There is
>>> still the yet unanswered question of how to handle interconnect/NoC
>>> bus scaling.  Probably other cases that don't come to mind offhand..
>>> I know downstream kernel has a lot of tricks for power saving which we
>>> haven't figured out how to do upstream yet.
>>> 
>>>>> 
>>>>> I think for the immediate problem of making an installed OS partition
>>>>> (as opposed to "live media") work, just having variables before we
>>>>> exit runtime services is sufficient.  It means, for example, having to
>>>>> edit efivars.txt instead of using grub2-reboot.. but ok, it's a pretty
>>>>> big improvement over the current state.
>>>> 
>>>> 
>>>> 
>>>> Well, it wouldn't be efivars but just the already existing bootenv which
>>>> can
>>>> also already be stored in .txt format on SD card ;).
>>>> 
>>>> Also, openSUSE has special support for non-efi-var booting. It detects
>>>> that
>>>> there is no efi var support and in that case simply installs grub with
>>>> --removable --no-nvram. That way booting "just works" for the default
>>>> case
>>>> that basically everyone cares about.
>>>> 
>>>>> Post runtime-services is definitely not part of the first patchset.
>>>> 
>>>> 
>>>> 
>>>> So yeah, maybe this can work. I definitely don't want to expose any sort
>>>> of
>>>> fake RTS variable services, as that would break the logic above ;).
>>>> 
>>> 
>>> I don't think we have an choice if we want to have cross-distro
>>> "firmware", since post-RTS variables aren't going to be possible on
>>> all devices, I don't think.  Otherwise I would have just stuck with my
>>> u-boot hack patch that loads \EFI\fedora\grubaa64.efi directly and not
>>> bothered with all this work ;-)
>>> 
>>> Anyways, it wouldn't really break you.. it would just change the logic
>>> above to not do the hack of installing as a live-media image that
>>> thinks it owns the whole disk.  And then we could install multiple
>>> distros on different partitions on the same disk (with the caveat of
>>> having to edit efivars.txt to change boot-order... possibly we could
>>> invent a u-boot script or bootorder.efi that shows a menu on screen if
>>> you boot with some key held down, similar to what you get on x86).
>> 
>> 
>> No, we either implement real EFI vars to Linux or none at all, but I don't
>> want to see us reinvent random non-UEFI standard ways of doing what people
>> expect it to do.
>> 
>> So while yes, before exit_boot_services I think we can expose efi variables,
>> I definitely don't want to see anything "fake" or "different from standard
>> UEFI" within Linux. And that only works with dedicated (or virtualized)
>> storage.
> 
> I wasn't planning to expose efi vars to linux (or anything post EBS).
> My rough plan was to persist all the env vars that start with efi_ in
> EBS while we still have u-boot drivers, to make them available on next
> boot, but *only* to shim/fallback/grub.. not post-EBS.
> 
> Like I said earlier, on devices without a proper way to do efi vars,
> you have to 'sudo vim /boot/efi/efivars.txt'

There shouldn't be efivars - the efi variables should get persisted through saveenv.

> instead of 'grub2-reboot
> 2', etc.

Yup, and that much sounds reasonable to me :). We have to be very careful to not create a special, parallel UEFI world with this though ;).

As an example: I can imagine that once this works, someone will send patches to grub to modify env.txt if it finds a u-boot uefi implementation. And then we by accident created a parallel universe where uefi lost its unification :/.


Alex
Rob Clark July 25, 2017, 5:42 p.m. UTC | #17
On Tue, Jul 25, 2017 at 1:29 PM, Alexander Graf <agraf@suse.de> wrote:
>
>
>> Am 25.07.2017 um 19:23 schrieb Rob Clark <robdclark@gmail.com>:
>>
>>> On Tue, Jul 25, 2017 at 12:55 PM, Alexander Graf <agraf@suse.de> wrote:
>>>
>>>
>>>> On 25.07.17 17:47, Rob Clark wrote:
>>>>
>>>>> On Tue, Jul 25, 2017 at 10:25 AM, Alexander Graf <agraf@suse.de> wrote:
>>>>>
>>>>>
>>>>>
>>>>>> On 25.07.17 14:47, Rob Clark wrote:
>>>>>>
>>>>>>
>>>>>>> On Tue, Jul 25, 2017 at 5:38 AM, Alexander Graf <agraf@suse.de> wrote:
>>>>>>>
>>>>>>>
>>>>>>> I agree :). We still want to have overriding mechanisms. And we do have
>>>>>>> them
>>>>>>> today. But the normal end user case should really not force them to
>>>>>>> have
>>>>>>> dtbs and kernels in lock-step.
>>>>>>>
>>>>>>> Take a look at all the server platforms out there. They do work with
>>>>>>> dtb
>>>>>>> just fine and most of them managed to keep backwards compatibility
>>>>>>> working.
>>>>>>> The 2 cases I'm aware of really boiled down to "don't care" attitudes
>>>>>>> and
>>>>>>> thus would've been avoidable.
>>>>>>
>>>>>>
>>>>>>
>>>>>> The idealistic approach that you want is fine for servers and a bunch
>>>>>> of other simple industrial SoCs out there.. simply because they are so
>>>>>> much less complex.  I don't think it is as much of a "don't care"
>>>>>> attitude (at least not all of the time).. as much as a whole different
>>>>>> level of complexity in the SoC.  Trying to say that this approach
>>>>>> works for something like am33xx so it ought to work for anyone is just
>>>>>> misunderstanding the scope of the problem.
>>>>>
>>>>>
>>>>>
>>>>> Yes, as I mentioned above, I want to learn about all the cases where it
>>>>> went
>>>>> wrong, take a step back and figure out why it was impossible to stay
>>>>> compatible.
>>>>>
>>>>> Maybe the end result of that will be to dispair and rip all my hair out.
>>>>> But
>>>>> maybe we will find ways to ease the pain next time :).
>>>>
>>>>
>>>> I know recently on one board there were some issues because of the way
>>>> host and otg usb were muxed (I'm not sure the details, I'm not a usb
>>>> expert, nor do I have time to be), which at some point will require a
>>>> non-backwards compatible dt change.  In the past it took a while to
>>>> describe more complex display topologies with bridge chips.  There is
>>>> still the yet unanswered question of how to handle interconnect/NoC
>>>> bus scaling.  Probably other cases that don't come to mind offhand..
>>>> I know downstream kernel has a lot of tricks for power saving which we
>>>> haven't figured out how to do upstream yet.
>>>>
>>>>>>
>>>>>> I think for the immediate problem of making an installed OS partition
>>>>>> (as opposed to "live media") work, just having variables before we
>>>>>> exit runtime services is sufficient.  It means, for example, having to
>>>>>> edit efivars.txt instead of using grub2-reboot.. but ok, it's a pretty
>>>>>> big improvement over the current state.
>>>>>
>>>>>
>>>>>
>>>>> Well, it wouldn't be efivars but just the already existing bootenv which
>>>>> can
>>>>> also already be stored in .txt format on SD card ;).
>>>>>
>>>>> Also, openSUSE has special support for non-efi-var booting. It detects
>>>>> that
>>>>> there is no efi var support and in that case simply installs grub with
>>>>> --removable --no-nvram. That way booting "just works" for the default
>>>>> case
>>>>> that basically everyone cares about.
>>>>>
>>>>>> Post runtime-services is definitely not part of the first patchset.
>>>>>
>>>>>
>>>>>
>>>>> So yeah, maybe this can work. I definitely don't want to expose any sort
>>>>> of
>>>>> fake RTS variable services, as that would break the logic above ;).
>>>>>
>>>>
>>>> I don't think we have an choice if we want to have cross-distro
>>>> "firmware", since post-RTS variables aren't going to be possible on
>>>> all devices, I don't think.  Otherwise I would have just stuck with my
>>>> u-boot hack patch that loads \EFI\fedora\grubaa64.efi directly and not
>>>> bothered with all this work ;-)
>>>>
>>>> Anyways, it wouldn't really break you.. it would just change the logic
>>>> above to not do the hack of installing as a live-media image that
>>>> thinks it owns the whole disk.  And then we could install multiple
>>>> distros on different partitions on the same disk (with the caveat of
>>>> having to edit efivars.txt to change boot-order... possibly we could
>>>> invent a u-boot script or bootorder.efi that shows a menu on screen if
>>>> you boot with some key held down, similar to what you get on x86).
>>>
>>>
>>> No, we either implement real EFI vars to Linux or none at all, but I don't
>>> want to see us reinvent random non-UEFI standard ways of doing what people
>>> expect it to do.
>>>
>>> So while yes, before exit_boot_services I think we can expose efi variables,
>>> I definitely don't want to see anything "fake" or "different from standard
>>> UEFI" within Linux. And that only works with dedicated (or virtualized)
>>> storage.
>>
>> I wasn't planning to expose efi vars to linux (or anything post EBS).
>> My rough plan was to persist all the env vars that start with efi_ in
>> EBS while we still have u-boot drivers, to make them available on next
>> boot, but *only* to shim/fallback/grub.. not post-EBS.
>>
>> Like I said earlier, on devices without a proper way to do efi vars,
>> you have to 'sudo vim /boot/efi/efivars.txt'
>
> There shouldn't be efivars - the efi variables should get persisted through saveenv.

hmm, possibly.. that would be simpler.. I had mainly wanted to
separate efi and u-boot state, but I think I could go either way on
that.

>> instead of 'grub2-reboot
>> 2', etc.
>
> Yup, and that much sounds reasonable to me :). We have to be very careful to not create a special, parallel UEFI world with this though ;).
>

btw, I realized I think some of the confusion was my fault.. I
probably had previously mentioned the possible 2nd step of moving some
of env block into efi_runtime section to make read-only efi variables
available to linux.. but without mentioning that I have no immediate
plans to actually implement that (and I can't really think of a reason
that would be useful).  (If there *was* a use-case for that, I think
the opensuse installer could detect that by trying to *write* an efi
var, I guess.. but really my main interest right now is to have efi
vars for pre-EBS).

> As an example: I can imagine that once this works, someone will send patches to grub to modify env.txt if it finds a u-boot uefi implementation. And then we by accident created a parallel universe where uefi lost its unification :/.
>

grub is pre-EBS so it can just use the normal UEFI interfaces.  If you
do see such a patch, pls NAK it ;-)

BR,
-R
diff mbox

Patch

diff --git a/cmd/bootefi.c b/cmd/bootefi.c
index 4f11682..56f6bc4 100644
--- a/cmd/bootefi.c
+++ b/cmd/bootefi.c
@@ -300,6 +300,9 @@  static unsigned long do_bootefi_exec(void *efi, void *fdt)
 	efi_reset_system_init();
 	efi_get_time_init();
 
+	/* we don't support much: */
+	setenv("efi_61dfe48bca93d211aa0d00e098032b8c_OsIndicationsSupported", "(u64)0");
+
 	/* Call our payload! */
 	debug("%s:%d Jumping to 0x%lx\n", __func__, __LINE__, (long)entry);
 
diff --git a/include/efi.h b/include/efi.h
index 3d58780..f819c5b 100644
--- a/include/efi.h
+++ b/include/efi.h
@@ -294,6 +294,25 @@  extern char image_base[];
 /* Start and end of U-Boot image (for payload) */
 extern char _binary_u_boot_bin_start[], _binary_u_boot_bin_end[];
 
+/*
+ * Variable Attributes
+ */
+#define EFI_VARIABLE_NON_VOLATILE       0x0000000000000001
+#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002
+#define EFI_VARIABLE_RUNTIME_ACCESS     0x0000000000000004
+#define EFI_VARIABLE_HARDWARE_ERROR_RECORD 0x0000000000000008
+#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x0000000000000010
+#define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x0000000000000020
+#define EFI_VARIABLE_APPEND_WRITE	0x0000000000000040
+
+#define EFI_VARIABLE_MASK 	(EFI_VARIABLE_NON_VOLATILE | \
+				EFI_VARIABLE_BOOTSERVICE_ACCESS | \
+				EFI_VARIABLE_RUNTIME_ACCESS | \
+				EFI_VARIABLE_HARDWARE_ERROR_RECORD | \
+				EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | \
+				EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | \
+				EFI_VARIABLE_APPEND_WRITE)
+
 /**
  * efi_get_sys_table() - Get access to the main EFI system table
  *
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 99619f5..812ec10 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -176,6 +176,16 @@  efi_status_t __efi_runtime EFIAPI efi_get_time(
 			struct efi_time_cap *capabilities);
 void efi_get_time_init(void);
 
+efi_status_t EFIAPI efi_get_variable(s16 *variable_name,
+		efi_guid_t *vendor, u32 *attributes,
+		unsigned long *data_size, void *data);
+efi_status_t EFIAPI efi_get_next_variable(
+		unsigned long *variable_name_size,
+		s16 *variable_name, efi_guid_t *vendor);
+efi_status_t EFIAPI efi_set_variable(s16 *variable_name,
+		efi_guid_t *vendor, u32 attributes,
+		unsigned long data_size, void *data);
+
 #else /* defined(EFI_LOADER) && !defined(CONFIG_SPL_BUILD) */
 
 /* Without CONFIG_EFI_LOADER we don't have a runtime section, stub it out */
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
index 3c230ac..9c67367 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -16,6 +16,7 @@  always := $(efiprogs-y)
 obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o
 obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o
 obj-y += efi_memory.o
+obj-y += efi_variable.o
 obj-$(CONFIG_LCD) += efi_gop.o
 obj-$(CONFIG_DM_VIDEO) += efi_gop.o
 obj-$(CONFIG_PARTITIONS) += efi_disk.o
diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c
index dd52755..7615090 100644
--- a/lib/efi_loader/efi_runtime.c
+++ b/lib/efi_loader/efi_runtime.c
@@ -184,7 +184,16 @@  static const struct efi_runtime_detach_list_struct efi_runtime_detach_list[] = {
 		/* Clean up system table */
 		.ptr = &systab.boottime,
 		.patchto = NULL,
-	},
+	}, {
+		.ptr = &efi_runtime_services.get_variable,
+		.patchto = &efi_device_error,
+	}, {
+		.ptr = &efi_runtime_services.get_next_variable,
+		.patchto = &efi_device_error,
+	}, {
+		.ptr = &efi_runtime_services.set_variable,
+		.patchto = &efi_device_error,
+	}
 };
 
 static bool efi_runtime_tobedetached(void *p)
@@ -382,9 +391,9 @@  struct efi_runtime_services __efi_runtime_data efi_runtime_services = {
 	.set_wakeup_time = (void *)&efi_unimplemented,
 	.set_virtual_address_map = &efi_set_virtual_address_map,
 	.convert_pointer = (void *)&efi_invalid_parameter,
-	.get_variable = (void *)&efi_device_error,
-	.get_next_variable = (void *)&efi_device_error,
-	.set_variable = (void *)&efi_device_error,
+	.get_variable = efi_get_variable,
+	.get_next_variable = efi_get_next_variable,
+	.set_variable = efi_set_variable,
 	.get_next_high_mono_count = (void *)&efi_device_error,
 	.reset_system = &efi_reset_system_boottime,
 };
diff --git a/lib/efi_loader/efi_util.h b/lib/efi_loader/efi_util.h
new file mode 100644
index 0000000..a566e81
--- /dev/null
+++ b/lib/efi_loader/efi_util.h
@@ -0,0 +1,79 @@ 
+/*
+ *  EFI utils
+ *
+ *  Copyright (c) 2017 Rob Clark
+ *
+ *  SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __EFI_UTIL_H_
+#define __EFI_UTIL_H_
+
+/*
+ * utf8/utf16 conversion lifted from grub
+ */
+
+static inline int
+utf16_strlen(uint16_t *in)
+{
+  int i;
+  for (i = 0; in[i]; i++);
+  return i;
+}
+
+/* Convert UTF-16 to UTF-8.  */
+static inline uint8_t *
+utf16_to_utf8(uint8_t *dest, const uint16_t *src, size_t size)
+{
+	uint32_t code_high = 0;
+
+	while (size--) {
+		uint32_t code = *src++;
+
+		if (code_high) {
+			if (code >= 0xDC00 && code <= 0xDFFF) {
+				/* Surrogate pair.  */
+				code = ((code_high - 0xD800) << 10) + (code - 0xDC00) + 0x10000;
+
+				*dest++ = (code >> 18) | 0xF0;
+				*dest++ = ((code >> 12) & 0x3F) | 0x80;
+				*dest++ = ((code >> 6) & 0x3F) | 0x80;
+				*dest++ = (code & 0x3F) | 0x80;
+			} else {
+				/* Error...  */
+				*dest++ = '?';
+				/* *src may be valid. Don't eat it.  */
+				src--;
+			}
+
+			code_high = 0;
+		} else {
+			if (code <= 0x007F) {
+				*dest++ = code;
+			} else if (code <= 0x07FF) {
+				*dest++ = (code >> 6) | 0xC0;
+				*dest++ = (code & 0x3F) | 0x80;
+			} else if (code >= 0xD800 && code <= 0xDBFF) {
+				code_high = code;
+				continue;
+			} else if (code >= 0xDC00 && code <= 0xDFFF) {
+				/* Error... */
+				*dest++ = '?';
+			} else if (code < 0x10000) {
+				*dest++ = (code >> 12) | 0xE0;
+				*dest++ = ((code >> 6) & 0x3F) | 0x80;
+				*dest++ = (code & 0x3F) | 0x80;
+			} else {
+				*dest++ = (code >> 18) | 0xF0;
+				*dest++ = ((code >> 12) & 0x3F) | 0x80;
+				*dest++ = ((code >> 6) & 0x3F) | 0x80;
+				*dest++ = (code & 0x3F) | 0x80;
+			}
+		}
+	}
+
+	return dest;
+}
+
+
+#endif /* __EFI_UTIL_H_ */
diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c
new file mode 100644
index 0000000..5343f49
--- /dev/null
+++ b/lib/efi_loader/efi_variable.c
@@ -0,0 +1,235 @@ 
+/*
+ *  EFI utils
+ *
+ *  Copyright (c) 2017 Rob Clark
+ *
+ *  SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <efi_loader.h>
+#include "efi_util.h"
+
+
+/* Mapping between EFI variables and u-boot variables:
+ *
+ *   efi_$guid_$varname = (type)value
+ *
+ * For example:
+ *
+ *   efi_8be4df6193ca11d2aa0d00e098032b8c_OsIndicationsSupported=
+ *      "(u64)0"
+ *   efi_f3cc021b90a3486683fbe8b6461fc2f2_fdtpath=
+ *      "(string)qcom/apq8016-sbc.dtb"
+ *
+ * Possible types:
+ *
+ *   + string - raw string (TODO automatically converted to utf16?)
+ *   + u64 - hex string encoding 64b value
+ *
+ * TODO add other types as needed.
+ *
+ * TODO we could include attributes in the value string, ie. something
+ * like "(ro,boot)(string)qcom/apq8016-sbc.dtb"
+ *
+ * TODO we could at least provide read-only access to ->get_variable()
+ * and friends by snapshot'ing the variables at detach time and having
+ * alternate versions of ->get_variable() and ->get_next_variable()
+ * in efi_runtime section.
+ */
+
+#define MAX_VAR_NAME 31
+#define MAX_NATIVE_VAR_NAME (strlen("efi_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_") + MAX_VAR_NAME)
+
+static int hex(unsigned char ch)
+{
+	if (ch >= 'a' && ch <= 'f')
+		return ch-'a'+10;
+	if (ch >= '0' && ch <= '9')
+		return ch-'0';
+	if (ch >= 'A' && ch <= 'F')
+		return ch-'A'+10;
+	return -1;
+}
+
+static const char * hex2mem(u8 *mem, const char *hexstr, int count)
+{
+	memset(mem, 0, count/2);
+
+	do {
+		int nibble;
+
+		*mem = 0;
+
+		if (!count || !*hexstr)
+			break;
+
+		nibble = hex(*hexstr);
+		if (nibble < 0)
+			break;
+
+		*mem = nibble;
+		count--;
+		hexstr++;
+
+		if (!count || !*hexstr)
+			break;
+
+		nibble = hex(*hexstr);
+		if (nibble < 0)
+			break;
+
+		*mem = (*mem << 4) | nibble;
+		count--;
+		hexstr++;
+		mem++;
+
+	} while (1);
+
+	if (*hexstr)
+		return hexstr;
+
+	return NULL;
+}
+
+static char * mem2hex(char *hexstr, const u8 *mem, int count)
+{
+	static const char hexchars[] = "0123456789abcdef";
+
+	while (count-- > 0) {
+		u8 ch = *mem++;
+		*hexstr++ = hexchars[ch >> 4];
+		*hexstr++ = hexchars[ch & 0xf];
+	}
+
+	return hexstr;
+}
+
+/* TODO this ends up byte-swapping the GUID compared to what one might
+ * expect, so:
+ *
+ *   efi_61dfe48bca93d211aa0d00e098032b8c_OsIndicationsSupported
+ *
+ * instead of
+ *
+ *   efi_8be4df6193ca11d2aa0d00e098032b8c_OsIndicationsSupported
+ *
+ * possibly make logic smarter in converting efi<->native
+ */
+
+static efi_status_t efi_to_native(char *native, s16 *variable_name,
+		efi_guid_t *vendor)
+{
+	size_t len;
+
+	len = utf16_strlen((u16 *)variable_name);
+	if (len >= MAX_VAR_NAME)
+		return EFI_DEVICE_ERROR;
+
+	native += sprintf(native, "efi_");
+	native  = mem2hex(native, vendor->b, sizeof(vendor->b));
+	native += sprintf(native, "_");
+	native  = (char *)utf16_to_utf8((u8 *)native, (u16 *)variable_name, len);
+	*native = '\0';
+
+	return EFI_SUCCESS;
+}
+
+
+static const char * prefix(const char *str, const char *prefix)
+{
+	while (*str && *prefix) {
+		if (*str != *prefix)
+			break;
+		str++;
+		prefix++;
+	}
+
+	if (*prefix)
+		return NULL;
+
+	return str;
+}
+
+
+/* http://wiki.phoenix.com/wiki/index.php/EFI_RUNTIME_SERVICES#GetVariable.28.29 */
+efi_status_t EFIAPI efi_get_variable(s16 *variable_name,
+		efi_guid_t *vendor, u32 *attributes,
+		unsigned long *data_size, void *data)
+{
+	char native_name[MAX_NATIVE_VAR_NAME + 1];
+	efi_status_t ret;
+	unsigned long in_size;
+	const char *val, *s;
+
+	EFI_ENTRY("%p %p %p %p %p", variable_name, vendor, attributes,
+			data_size, data);
+
+	if (!variable_name || !vendor || !data_size)
+		return EFI_EXIT(EFI_INVALID_PARAMETER);
+
+	ret = efi_to_native(native_name, variable_name, vendor);
+	if (ret)
+		return EFI_EXIT(ret);
+
+	debug("%s: get '%s'\n", __func__, native_name);
+
+	val = getenv(native_name);
+	if (!val)
+		return EFI_EXIT(EFI_NOT_FOUND);
+
+	in_size = *data_size;
+
+	if ((s = prefix(val, "(u64)"))) {
+		*data_size = sizeof(u64);
+
+		if (in_size < sizeof(u64))
+			return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
+
+		if (!data)
+			return EFI_EXIT(EFI_INVALID_PARAMETER);
+
+		if (hex2mem(data, s, 16))
+			return EFI_EXIT(EFI_DEVICE_ERROR);
+
+		debug("%s: got value: %llu\n", __func__, *(u64 *)data);
+	} else if ((s = prefix(val, "(string)"))) {
+		/* TODO should string's be converted to utf16?  Or maybe if
+		 * string isn't really a thing in efi, this should be (utf8)
+		 * (and (utf16)?) and (raw%d), with the former being (in the
+		 * land of u-boot) ascii strings converted to utf8/utf16 and
+		 * the latter just being an arbitrary hex encoded value??
+		 */
+		return EFI_EXIT(EFI_DEVICE_ERROR);
+	} else {
+		debug("%s: invalid value: '%s'\n", __func__, val);
+		return EFI_EXIT(EFI_DEVICE_ERROR);
+	}
+	// TODO other types?
+
+	// TODO support attributes
+	if (attributes)
+		*attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS;
+
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+/* http://wiki.phoenix.com/wiki/index.php/EFI_RUNTIME_SERVICES#GetNextVariableName.28.29 */
+efi_status_t EFIAPI efi_get_next_variable(
+		unsigned long *variable_name_size,
+		s16 *variable_name, efi_guid_t *vendor)
+{
+	EFI_ENTRY("%p %p %p", variable_name_size, variable_name, vendor);
+
+	return EFI_EXIT(EFI_DEVICE_ERROR);
+}
+
+/* http://wiki.phoenix.com/wiki/index.php/EFI_RUNTIME_SERVICES#SetVariable.28.29 */
+efi_status_t EFIAPI efi_set_variable(s16 *variable_name,
+		efi_guid_t *vendor, u32 attributes,
+		unsigned long data_size, void *data)
+{
+	EFI_ENTRY("%p %p %x %lu %p", variable_name, vendor, attributes,
+			data_size, data);
+
+	return EFI_EXIT(EFI_DEVICE_ERROR);
+}