Note
See FdtBusPkg Documentation Style and Terms Definitions first.
This is on top of the regular Tiano requirements covered elsewhere.
- cmake (for Uncrustify)
- device-tree-compiler (for the regression test device tree)
Uncrustify is a code beautifier used to format code into the accepted Tiano style.
Here are some simple steps to build and install Uncrustify:
$ git clone https://[email protected]/projectmu/Uncrustify/_git/Uncrustify
$ cd Uncrustify
$ mkdir build
$ cd build
$ cmake ..
$ cmake -build .
$ sudo make install
Here's a useful command to run the styler on all C headers and sources under the current directly.
$ git ls-files *.h *.c | uncrustify -c $WORKSPACE/.pytool/Plugin/UncrustifyCheck/uncrustify.cfg -F - --replace --no-backup --if-changed
Also see https://github.com/tianocore/tianocore.github.io/wiki/EDK-II-Code-Formatting.
Configuring a development environment is easy:
$ git clone https://github.com/tianocore/edk2.git
$ cd edk2
$ git submodule add https://github.com/intel/FdtBusPkg
$ git submodule update --init --recursive
$ . edksetup.sh
$ python3 BaseTools/Scripts/SetupGit.py
$ git am FdtBusPkg/Docs/edk2-patches/*
$ pushd FdtBusPkg
$ python3 ../BaseTools/Scripts/SetupGit.py
$ popd
$ make -C BaseTools
Once the environment is set up, to build all of the components (outside of a firmware build):
$ export GCC_RISCV64_PREFIX=... (if you are on a non-RISCV64 system)
$ build -a RISCV64 -t GCC5 -p FdtBusPkg/FdtBusPkg.dsc -b DEBUG
To build RISC-V OVMF firmware enabled with FdtBusPkg components:
$ git am FdtBusPkg/Docs/ovmf-patches/*
$ export GCC_RISCV64_PREFIX=... (if you are on a non-RISCV64 system)
$ build -a RISCV64 -p OvmfPkg/RiscVVirt/RiscVVirtQemu.dsc -t GCC -b DEBUG
- Keep the docs in sync with any patches and changes to DtIo.h.
- Keeps the test applications in sync with any patches and changes to DtIo.h.
- New functionality must be checked in along with the relevant regression test (in the same commit).
- Use Tiano coding style (run edk2 uncrustify).
- Regression tests should avoid unnecessary logging and test conditionals.
ASSERT
is your friend. - Checking in regression tests means checking in TestDt.dts and TestDt.dtbi changes.
- When adding new components, don't forget to add them to FdtBusPkg.dsc and test the build.
- When adding new test applications, don't forget to add them to FdtBusPkgApps.dsc and test the build.
A debug build of FdtBusDxe comes with a regression test suite. This runs automatically and will crash the firmware on failure. You don't need to take any special steps.
To build test apps:
$ export GCC_RISCV64_PREFIX=... (if you are on a non-RISCV64 system)
$ build -a RISCV64 -t GCC5 -p FdtBusPkg/FdtBusPkgApps.dsc -b DEBUG
Dumps EFI_DT_IO_PROTOCOL
info for a DT controller.
Shell> FS0:\DtInfo controller
controller
: a hexEFI_HANDLE
, a hex device handle index (fromdevtree
), an alias or absolute DT path.
Note
A lookup by path will connect any missing drivers and enumerate missing devices along the path.
Caution
The unit address portion of the DT path may not be omitted under any circumstances. Passing "/soc/pci@30000000" is okay but "/soc/pci" is not. This is a restriction in the current implementation and a difference in behavior, when compared to the Devicetree Specification, Section 2.2.3.
Shell> FS0:\DtInfo 17F44B918
Shell> FS0:\DtInfo 99
Shell> FS0:\DtInfo soc/pci@30000000
Shell> FS0:\DtInfo /soc/pci@30000000
Here's an example of output:
ComponentName: 'DT(serial@10000000)'
Name: 'serial@10000000'
DeviceType: '[NONE]'
DeviceStatus: 'OKAY'
AddressCells: '2'
SizeCells: '2'
ChildAddressCells: '0'
ChildSizeCells: '0'
IsDmaCoherent: 'no'
ParentDevice: '17F447E18'
Compatible: 'ns16550a'
Reg: #0 10000000(100) MemoryMappedIo UC
Dumps a property value for a DT controller.
Shell> FS0:\DtProp controller property [parse string]
controller
: a hexEFI_HANDLE
, a hex device handle index (fromdevtree
), an alias or absolute DT path. Just like DtInfo.efi.property
: property name to dump.parse string
: commands to parse the property data.
If the optional parse string
is not provided, the tool performs
a hex dump of the property
data.
The parse string
, when provided, contains single-character commands to
parse the property
data. This enables parsing complex and arbitrary
formats.
Command | Parse Type |
---|---|
1 |
EFI_DT_VALUE_U32 |
2 |
EFI_DT_VALUE_U64 |
4 |
EFI_DT_VALUE_U128 |
b |
EFI_DT_VALUE_BUS_ADDRESS |
B |
EFI_DT_VALUE_CHILD_BUS_ADDRESS |
z |
EFI_DT_VALUE_SIZE |
Z |
EFI_DT_VALUE_CHILD_SIZE |
r |
EFI_DT_VALUE_REG |
R |
EFI_DT_VALUE_RANGE |
s |
EFI_DT_VALUE_STRING |
d |
EFI_DT_VALUE_DEVICE |
Hex dump of a property:
Shell> FS0:\DtProp /soc/pci@30000000 compatible
Dumping 22 bytes of 'compatible':
00000000: 70 63 69 2D 68 6F 73 74-2D 65 63 61 6D 2D 67 65 *pci-host-ecam-ge*
00000010: 6E 65 72 69 63 00 *neric.*
An empty property:
Shell> FS0:\DtProp /soc/pci@30000000 dma-coherent
Property 'dma-coherent' exists but is EMPTY
Formatting property data using the parse string parameter:
Shell> FS0:\DtProp /soc/pci@30000000 reg 1111
Parsing 'reg' with command string '1111':
00000000: 0x0
00000004: 0x30000000
00000008: 0x0
0000000C: 0x10000000
Shell> FS0:\DtProp /soc/pci@30000000 reg bz
Parsing 'reg' with command string 'bz':
00000000: 30000000
00000008: 10000000
Shell> FS0:\DtProp /soc/pci@30000000 reg r
Parsing 'reg' with command string 'r':
00000000: 30000000(10000000) MemoryMappedIo UC
Shell> FS0:\DtProp /soc/pci@30000000 ranges RRR
Parsing 'ranges' with command string 'RRR':
00000000: 0x10000000000000000000000(10000)->0x3000000 MemoryMappedIo UC
0000001C: 0x20000000000000040000000(40000000)->0x40000000 MemoryMappedIo UC
00000038: 0x30000000000000400000000(400000000)->0x400000000 MemoryMappedIo UC
Shell> FS0:\DtProp sample-bus/sample-device@1337 reg r
Parsing 'reg' with command string 'r':
00000000: 1337(100) via DT(sample-bus)
The first column in the output is the offset of the parsed element within the property data.
Reads and writes DT controller register regions.
Shell> FS0:\DtReg [-i reg index|name] [-n count] [-w access width] controller offset [set value]
-i
: reg index or name. When not provided, the first (index 0) region is used.-n
: number of reads or writes to perform. When not provided, 1 is used.-w
: access width (1, 2, 4 or 8). When not provded, 1 is used.controller
: a hexEFI_HANDLE
, a hex device handle index (fromdevtree
), an alias or absolute DT path. Just like DtInfo.efi.offset
: a region offset (decimal or hex).set value
: when provided, the value to write to register region.
If the optional set value
parameter is not provided, the tool reads
from a register region. If the set value
parameter is provided, to
tool writes to a register region. The accesses begin at the specified
offset
, with the address incrementing count
times.
4 reads of 8 bytes each at offset 8:
FS0:\> DtReg -n 4 -w 8 /sample-bus/sample-device@1337 8
Dumping 32 bytes at offset 0x8 of reg via DT(sample-bus) 0x1337(100):
00000008: 8888888888888808
00000010: 8888888888888810
00000018: 8888888888888818
00000020: 8888888888888820
Write 1 byte at offset 0:
Shell> FS0:\DtReg soc/serial@10000000 0 41
Tool for dumping BAR info for PCI devices or a specific PCI device.
This might seem a strange tool to have in FdtBusPkg, but it is very useful in diagnosing PciHostBridgeFdtDxe, as it shows BARs and both bus- and CPU-side addresses.
Shell> FS0:\pciinfo.EFI seg bus dev func
Shell> FS0:\pciinfo.EFI handle
Shell> FS0:\pciinfo.EFI [-v]
seg
: a hex segment number.bus
: a hex bus number.dev
: a hex device number.func
: a hex function number.handle
: a hexEFI_HANDLE
, a hex device handle index (fromdevtree
).-v
: verbose, dumping info for all PCI devices when a device is not specified.
Dump info about a given handle index (from devtree
output):
Shell> PciInfo bd
[BD] 0000:00:03.00 info:
-------------------------
Vendor: 1AF4 Device: 1000
Supported: IO MEM BM ED ER DAC
Current: IO MEM BM
ROMs:
+0x00000000: BIOS (0x0000) image (0x10E00 bytes)
+0x00010E00: UEFI (0x8664) image (0x16600 bytes)
+0x00010E00: Subsystem: 0xB
+0x00010E00: InitializationSize: 0x16600 (bytes)
+0x00010E00: EfiImageHeaderOffset: 0x38
+0x00010E00: Compressed: yes
BAR0: IO CPU 0x0000000003000000 -> PCI 0x0000000000000000 (0x20)
BAR1: MEM32 CPU 0x0000000040044000 -> PCI 0x0000000040044000 (0x1000)
That is, what if FdtBusDxe.efi is not part of my firmware?
Put FdtBusDxe.efi on removable media and use the load
Shell command:
Shell> fs0:
Shell> load FdtBusDxe.efi
Use the drivers
Shell command.
Shell> drivers
T D
D Y C I
R P F A
V VERSION E G G #D #C DRIVER NAME IMAGE NAME
== ======== = = = == == =================================== ==========
...
27 0000000A B - - 28 19 Devicetree Bus Driver FdtBusDxe
The driver will load if it is not able to locate the Devicetree blob via FDT HOB, but the driver was built with regression test support.
Use the devtree
Shell command.
Shell> devtree
...
Ctrl[28] DT(DtRoot)
...
Ctrl[29] DT(DtTestRoot)
Ctrl[4B] DT(aliases)
Ctrl[4C] DT(G0)
Ctrl[4D] DT(G1)
Ctrl[4E] DT(G2)
The DT(DtTestRoot)
device will be present if FdtBusDxe was build with regression testing support (i.e. if it were a DEBUG build).
Yes.
Caution
If your console device is a DT controller, this will disconnect it too.
Note
If you run reconnect -r
, the devtree
output from the Shell will be
stale. Simply exit the Shell and run it again.
Not today.
Using devtree
and dh
tools.
First, look at devtree
and note the device handle index and
component name. If component name is Legacy-Managed Device
, then the
DT controller is managed by a legacy driver. That is, it is managed by
code that doesn't conform to the UEFI Driver Mode. See the
documentation on device drivers for more info.
Shell> devtree
...
Ctrl[28] DT(DtRoot)
Ctrl[2A] Legacy-Managed Device
Ctrl[2B] DT(soc)
Ctrl[2C] Legacy-Managed Device
Ctrl[97] DT(pmu)
Ctrl[98] DT(rtc@101000)
Ctrl[99] 16550 UART Device
Ctrl[A5] FDT Serial Port #0
Ctrl[A6] PC-ANSI Serial Console
Ctrl[6E] Primary Console Input Device
Ctrl[6F] Primary Console Output Device
Ctrl[70] Primary Standard Error Device
If a device has a component name of the form DT(...)
, then it is
either not managed by any driver or is managed by FdtBusDxe itself.
In general, this is where the dh
tool helps.
In the following example, we see DT(soc)
is managed by FdtBusDxe,
which makes sense as it is a simple-bus container device:
2B: DevicePath(..-1EE3-425E3650A29B,736F6300)) 5CE5A2B0-2838-3C35-1EE3-425E3650A29B
Controller Name : DT(soc)
Device Path : VenHw(5CE5A2B0-2838-3C35-1EE3-425E3650A29B,4474526F6F7400)/VenHw(5CE5A2B0-2838-3C35-1EE3-425E3650A29B,736F6300)
Controller Type : BUS
Configuration : NO
Diagnostics : NO
Managed by :
Drv[27] : Devicetree Bus Driver
Parent Controllers :
Parent[28] : DT(DtRoot)
Child Controllers :
Child[2C] : Legacy-Managed Device
Child[97] : DT(pmu)
Child[98] : DT(rtc@101000)
Child[99] : 16550 UART Device
Child[9A] : DT(test@100000)
Child[9B] : DT(virtio_mmio@10008000)
Child[9C] : DT(virtio_mmio@10007000)
Child[9D] : DT(virtio_mmio@10006000)
Child[9E] : DT(virtio_mmio@10005000)
Child[9F] : DT(virtio_mmio@10004000)
Child[A0] : DT(virtio_mmio@10003000)
Child[A1] : DT(virtio_mmio@10002000)
Child[A2] : DT(virtio_mmio@10001000)
Child[A3] : DT(plic@c000000)
Child[A4] : DT(clint@2000000)
Here we see that DT(rtc@101000)
is not managed by a UEFI Driver
Model-compliant device driver. Most likely, it is not used by any
driver (at least one following the documentation on device
drivers):
98: 5CE5A2B0-2838-3C35-1EE3-425E3650A29B DevicePath(..A29B,7274634031303130303000))
Controller Name : DT(rtc@101000)
Device Path : VenHw(5CE5A2B0-2838-3C35-1EE3-425E3650A29B,4474526F6F7400)/VenHw(5CE5A2B0-2838-3C35-1EE3-425E3650A29B,736F6300)/VenHw(5CE5A2B0-2838-3C35-1EE3-425E3650A29B,7274634031303130303000)
Controller Type : DEVICE
Configuration : NO
Diagnostics : NO
Managed by : <None>
Parent Controllers :
Parent[2B] : DT(soc)
Child Controllers : <None>
Here we see that the device with handle index 99
is managed by a 16550 UART Driver
. The component name is not in the form DT(...)
,
because the UART driver provides its own component naming for the devices
it manages.
Shell> dh -d 99
99: 5CE5A2B0-2838-3C35-1EE3-425E3650A29B DevicePath(..269616C40313030303030303000))
Controller Name : 16550 UART Device
Device Path : VenHw(5CE5A2B0-2838-3C35-1EE3-425E3650A29B,4474526F6F7400)/VenHw(5CE5A2B0-2838-3C35-1EE3-425E3650A29B,736F6300)/VenHw(5CE5A2B0-2838-3C35-1EE3-425E3650A29B,73657269616C40313030303030303000)
Controller Type : BUS
Configuration : NO
Diagnostics : NO
Managed by :
Drv[73] : 16550 UART Driver
Parent Controllers :
Parent[2B] : DT(soc)
Child Controllers :
Child[A5] : FDT Serial Port #0
The DtInfo.efi tool will list more info about this device handle, including the FdtBusDxe component name:
Shell> FS0:\DtInfo 99
ComponentName: 'DT(serial@10000000)'
Name: 'serial@10000000'
...