On 12/12/20 12:29 AM, Heinrich Schuchardt wrote:
Dear all,

we have discussed that a protocol is needed to fix-up device trees
loaded by GRUB or other boot managers.

In the U-Boot code we have actually the following actions for
device-trees:

* load the device-tree to memory
* copy the device-tree to an allocated memory region which
   has 12 KiB free space for device-tree fix-ups
* do the actual fix-ups, i.e. add new nodes or change properties
* reserve memory according to the /reserved-memory node and the
   memory reservation block as EfiBootServicesData or as
   EfiReservedMemoryType for no-map regions
* install the device-tree as configuration table

So I think the usage of a DT fix-up protocol could take the following
steps:

* GRUB loads the device-tree allocating sufficient memory for fix-ups
* GRUB calls the protocol a fist time to add extra nodes and properties
* GRUB applies its own device-tree fix-ups
* GRUB calls the protocol a second time which
   - reserves memory according to the /reserved-memory node
   - installs the device-tree as configuration table

One could join both service calls if GRUB applies its own fix-ups first.
But maybe GRUB wants to analyze U-Boot's fix-ups before committing its
own ones.

So lets define a bit-field to pass to the fix-up protocol:

/* Add nodes and update properties */
#define EFI_DT_APPLY_FIXUPS    0x00000001
/*
  * Reserve memory according to the /reserved-memory node
  * and the memory reservation block
  */
#define EFI_DT_RESERVE_MEMORY  0x00000002
/* Install the device-tree as configuration table */
#define EFI_DT_INSTALL_TABLE   0x00000004

Here is the rest of the proposed protocol definition:

#define EFI_DT_FIXUP_PROTOCOL_GUID \
  { 0xe617d64c, 0xfe08, 0x46da, \
  { 0xf4, 0xdc, 0xbb, 0xd5, 0x87, 0x0c, 0x73, 0x00 } }

typedef struct _EFI_DT_FIXUP_PROTOCOL {
EFI_DT_FIXUP fixup;
} EFI_DT_FIXUP_PROTOCOL;

typedef EFI_STATUS
(EFIAPI *EFI_DT_FIXUP) (
     IN EFI_DT_FIXUP_PROTOCOL *This,
     IN VOID                  *Fdt,
     IN OUT UINTN             *BufferSize,
     IN UINT32                Flags,
     );

This:       Pointer to the protocol
Fdt:        Buffer with the device-tree. This shall be memory
             of type EfiACPIReclaimMemory if Flags contains
             EFI_DT_INSTALL_TABLE.
BufferSize: Pointer to the size of the buffer including
             trailing unused bytes for fix-ups.
             If the buffer size is too small,
             the required buffer size is returned.
Flags:      Bitmap containing at least one of the values
             EFI_DT_APPLY_FIXUPS, EFI_DT_RESERVE_MEMORY,
             EFI_DT_INSTALL_TABLE. Indicates the actions
             to be applied to the device-tree.

The selected actions indicated in Flags are applied in the
sequence:

* Add nodes and update properties.
* Reserve memory according to the /reserved-memory node
   and the memory reservation block
* Install the device-tree as configuration table

Memory is reserved as EfiBootServicesData if the reservation does not
carry the no-map property and as EfiReservedMemoryType if it is marked
as no-map.

If *BufferSize exceeds the value of the totalsize field header of
device-tree header upon entry to the service, the totalsize field is set
to *BufferSize.

Return values:

EFI_INVALID_PARAMETER - This is NULL or does not point to a valid
                         EFI_DT_FIXUP_PROTOCOL implementation.
EFI_INVALID_PARAMETER - Fdt or BufferSize is NULL
EFI_INVALID_PARAMETER - *Fdt is not a valid device-tree
                         (e.g. incorrect value of magic)
EFI_INVALID_PARAMETER - Invalid value of Flags (zero or unknown bit)
EFI_BUFFER_TOO_SMALL  - The buffer is too small to apply the fix-ups.
EFI_SUCCESS           - All steps succeeded

If EFI_BUFFER_TOO_SMALL is returned, the device-tree is unmodified
and *BufferSize is updated with the required buffer size for the
provided device-tree.

The required buffer size when called with EFI_DT_APPLY_FIXUPS should
enforce at least 4 KiB unused space for additional fix-ups by the
operating system or the caller. The available space in the device-tree
shall be determined using the device-tree header fields:

     Available = header->totalsize
               - header->off_dt_strings
               - header->size_dt_strings;

(The strings block is always last in the flattened device-tree. There
might be more space between blocks but not all device-tree libraries can
use it.)

The required buffer size when called without EFI_DT_APPLY_FIXUPS shall
be the value of the totalsize field of the flattened device tree header.

If any other error code is returned, the state of the device-tree is
undefined. The caller should discard the buffer content.

The extent to which the validity of the device-tree is checked is
implementation dependent. But a buffer without the correct value of the
magic field of the flattened device tree header should always be rejected.

The protocol implementation is not required to check if the device-tree
is in memory of type EfiACPIReclaimMemory.

Looking forward to your feedback.


I have created a git repository for the spec:

    https://github.com/U-Boot-EFI/EFI_DT_FIXUP_PROTOCOL

We can discuss it via issues or pull requests.

Next step will be implementing this in a U-Boot fork.

Best regards

Heinrich
_______________________________________________
boot-architecture mailing list
[email protected]
https://lists.linaro.org/mailman/listinfo/boot-architecture

Reply via email to