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.
Best regards
Heinrich
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@lists.linaro.org