[U-Boot] [RFC] Device model for block devices - integration with EFI subsystem

Heinrich Schuchardt xypron.glpk at gmx.de
Fri Jan 11 17:54:14 UTC 2019


# Motivation

At different times we have noted that in U-Boot device model and the EFI
subsystem we have parallel structures. The most recent being Takahiro's
patch series [1].

Before adding any more dependencies I think we should develop a sound
architectural vision. We should end up with a design specification on
which we can base our future development.

This year hopefully all block devices will be eliminated in U-Boot that
are not following the device model. This gives us the chance to clean up
our code base.

Topics of this mail are:

- how devices and drivers are modeled in EFI
- how devices and drivers are modeled in U-Boot
- how both are related
- the state of block devices and drivers in U-Boot
- first thoughts on joining the two worlds

# Devices and drivers in EFI

An overview of devices and drivers in EFI is given in doc/README.uefi.

A device is represented by a handle (struct efi_obj *) exposing the
device path protocol. This device path protocol is a sequence of device
path nodes. The device tree is modeled via the device path protocol.

A driver (also called controller) is represented by a handle exposing
the EFI_DRIVER_BINDING_PROTOCOL.

Drivers are attached to a device by calling the ConnectController
service. Drivers are removed from a device by calling the
DisconnectController service.

The ConnectController service iterates over all handles exposing the
driver binding protocol and calls the Supported() method of the
protocol. For each driver supporting the device it calls the Start()
method of the protocol.

The driver now installs its own protocol on the device handle with its
own handle referenced as the controller and setting an attribute
indicating if it is binding exclusively (no other driver may be
connected to the device).

The driver may create additional handles representing sub-devices in the
StartService. The ConnectController service can recursively bind drivers
to these.

The DisconnectController service iterates of all protocols on the device
handle which are marked as being controlled by a driver and calls the
Stop() method of the driver binding protocol.

The driver now uninstalls its protocol.

There can be handles that are neither drivers nor devices.

Devices may be created by the sub-system without any pre-existing U-Boot
device, e.g. an iSCSI drive may be set up as a handle exposing the
EFI_BLOCK_IO_PROTOCOL, or a VPN tunnel may  be created as a virtual
network interface with the EFI_SIMPLE_NETWORK_PROTOCOL installed.

# Devices and drivers in U-Boot

doc/driver-model/README.txt has an overview.

A driver has a U_BLOCK_DRIVER entry linking it to a uclass. In the ops
pointer U_BLOCK_DRIVER it exposes the available operations.

A uclass represents a group of drivers exposing the same interface.

A device is represented by a udevice structure. It has a pointer to its
uclass. It is connected to a driver by calling the bind() function of
its uclass and can be disconnected by calling the unbind() function of
the uclass. All devices have a parent device except for the top level
device. These relationships make up the device tree.

Some devices to be created are defined in the device tree. Other devices
are detected by scanning hardware buses.

New devices may be found at runtime, e.g. when a USB device is connected.

# Relationship between EFI and U-Boot devices

ConnectController in EFI is the equivalent to bind(),
ofdata_to_platdata(), and probe() in U-Boot.

DisconnectController in EFI is the equivalent to unbind() in U-Boot.

We have discovered a single case where objects are devices in EFI but
not in U-Boot. EFI partitions are block io devices where the disk is the
parent. A block device exposes the EFI_BLOCK_IO_PROTOCOL. If the
partition is formatted the EFI device additionally exposes the
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL.

In U-Boot partitions and file systems are not following the device model.

We have devices in U-Boot where there is no protocol existing in EFI to
access it. We could represent them in EFI as a handle with a device path
protocol.

As described above the EFI subsystem may create (virtual) devices. For
block io devices we have integrated the two worlds. When
ConnectController is called for a block io device we create a U-Boot
block device marked as being of type UCLASS_EFI. The unbinding of the
driver is not yet implemented.

# How we can tie the worlds together

Every device in the EFI world should have an equivalent in the U-Boot
world. This requires modeling partitions as U-Boot devices.

Every U-Boot device relevant for EFI and all its ancestors should have
an EFI handle with the EFI_DEVICE_PATH_PROTOCOL installed.

For convenient look up a pointer to the device in the EFI handle (struct
efi_obj) would be helpful.

When trying to join the EFI and the U-Boot driver model the best
abstraction level would be uclasses having EFI handles exposing the
EFI_DRIVER_BINDING_PROTOCOL.

EFI handles should be created when bind() is called for the U-Boot device.

Block devices seem to be the best starting point for the exercise.

[1] [PATCH v2 0/3] efi_loader: add removable device support
    https://lists.denx.de/pipermail/u-boot/2018-November/347491.html


More information about the U-Boot mailing list