It's Pi all the way down...


In the previous post, we looked at why I’ve been working on pibootctl. But if you just want to use it, look no further! (Or, do go and read the fine manual if you prefer).

Installing it on your pi is pretty simple:

$ sudo add-apt-repository ppa:waveform/pibootctl
$ sudo apt install pibootctl

Side note: in future, this should be included by default on Ubuntu images, but for now it lives in my PPA.


The utility includes several sub-commands, but the first you ought to learn (or even guess) is “help”:

$ pibootctl help
usage: pibootctl [-h] [--version]
                 ls,remove,rm,rename,mv} ...

pibootctl is a tool for querying and modifying the boot configuration of
the Raspberry Pi.

optional arguments:
  -h, --help            show this help message and exit
  --version             show program's version number and exit

    help (?)            Displays help about the specified command or setting
    status (dump)       Output the current boot time configuration
    get                 Query the state of one or more boot settings
    set                 Change the state of one or more boot settings
    save                Store the current boot configuration for later use
    load                Replace the boot configuration with a saved one
    diff                Show the differences between boot configurations
    show (cat)          Show the specified stored configuration
    list (ls)           List the stored boot configurations
    remove (rm)         Remove a stored boot configuration
    rename (mv)         Rename a stored boot configuration

You can also ask this sub-command for help on any of the other sub-commands … including itself:

$ pibootctl help help
usage: pibootctl help [-h] [command-or-setting]

With no arguments, displays the list of pibootctl commands. If a command
name is given, displays the description and options for the named command.
If a setting name is given, displays the description and default value for
that setting.

positional arguments:
  command-or-setting  The name of the command or setting to output help for

optional arguments:
  -h, --help          show this help message and exit

If you fancy good old man-pages, there’s those too. One for the tool itself, and one for each sub-command. For example:

$ man pibootctl
$ man pibootctl help

These include some additional notes and examples which may be worth a look (they’re also included in the online manual).

First Steps

What about actual usage? The first thing you’ll probably want to do is look at the current state of your boot configuration. This is what Ubuntu 20.04’s looks like in pibootctl “out of the box”:

$ pibootctl status
│ Name                    │ Value                │
│ audio.enabled           │ on                   │
│ boot.devicetree.address │ 50331648 (0x3000000) │
│ boot.kernel.64bit       │ on                   │
│ boot.kernel.cmdline     │ 'cmdline.txt'        │
│ boot.kernel.filename    │ 'uboot_rpi_3.bin'    │
│ i2c.enabled             │ on                   │
│ serial.enabled          │ on                   │
│ spi.enabled             │ on                   │

Several things to note above:

Oooh, pretty!
The default output mode is designed to be human-readable and, if your locale includes “UTF-8” then unicode line-drawing characters will be used for tables.
You’re using arm64 on a Pi3?
Right now, yes. It was the first card and Pi combination that came to hand!
There’s not many settings there?
Yes, only modified settings are listed by default because otherwise there’s … a lot (and most of them you probably don’t care about). You can list all the settings with the --all option, but be warned there’s more than a page’s worth!
I don’t recognize those setting names!
Yes. This is probably going to be one of the more contentious decisions in the design of pibootctl. I could’ve stuck with the actual commands used in the Pi’s boot configuration, e.g. “dtparam=spi=on” or “uart_enable=1” or “disable_overscan=1”, but I didn’t. This probably needs justifying as it’s going to confuse anyone familiar with the existing settings (including me!)…

Setting Names

The names for settings in the Pi’s bootloader have grown more or less organically over time and occasionally change as new interfaces emerge (e.g. “display_rotate” being deprecated in favour of “display_lcd_rotate” and “display_hdmi_rotate”). Moreover, the settings are for use in a fairly low-level tool (the bootloader) so there’s a general preference for defaults to be “0”, hence the occasional setting with reverse setting logic (“disable_overscan=1”).

The lack of a common naming standard (while understandable) does make it tricky to query groups of settings common to an area. For example, how would you query all the video related settings (remembering that “disable_overscan” setting)? However, if a naming scheme is imposed on the settings, it becomes easy:

ubuntu@pitest:~$ pibootctl status --all video.*
│ Name                         │ Modified │ Value                          │
│ video.cec.enabled            │          │ on                             │
│ video.cec.init               │          │ on                             │
│               │          │ 'Raspberry Pi'                 │
│ video.dispmanx.offline       │          │ off                            │
│ video.dpi.clock              │          │ off                            │
│ video.dpi.enabled            │          │ off                            │
│ video.dpi.format             │          │ 1 (9-bit RGB666; unsupported)  │
│              │          │ 0 (auto from EDID)             │
│ video.dpi.hsync.disabled     │          │ off                            │
│ video.dpi.hsync.phase        │          │ off                            │
│ video.dpi.hsync.polarity     │          │ off                            │

The usual “*” and “?” wildcards can be used in the setting pattern. In the above output it’s worth noting that explanatory text is included for certain setting values (e.g. “auto from EDID” for “”). A more minimal example is all the settings for the TV output:

ubuntu@pitest:~$ pibootctl status --all*
│ Name                │ Modified │ Value    │
│     │          │ 1 (4:3)  │
│ │          │ on       │
│    │          │ on       │
│       │          │ 0 (NTSC) │

This scheme also means that simple sorting by name groups related settings together in the output. However, as mentioned above it is going to confuse anyone who’s familiar with the underlying setting names. To try and mitigate this a bit, the help output for all settings includes the underlying command name (or overlay and parameter name as appropriate), and the “help” command itself will also accept such names:

$ pibootctl help disable_overscan
      Name: video.overscan.enabled
   Default: on
Command(s): disable_overscan

When enabled (the default), if a group 1 (CEA) HDMI mode is selected
(automatically or otherwise), the display output will include black borders
to align the edges of the output with a typical TV display.

There are cases where an underlying command is represented (or affected by) several settings (and vice versa). In this case, asking for help on such a setting will tell you the names of all settings that can affect it:

$ pibootctl help start_file
start_file is affected by the following settings:



We’ve seen the pretty-printed output of multiple settings above. What about retrieving an individual setting for scripting purposes? The “get” command is used for this (there’s very little point using this command outside a script):

$ pibootctl get serial.enabled

While this is simple enough, it’s not very efficient when it comes to obtaining the value of lots of settings. To accommodate usage from scripts, the majority of commands in pibootctl (including “get” and “status”) accept the --json, --yaml, or --shell switches to produce output in JSON, YAML, or a shell-compatible style respectively:

$ pibootctl status --json --all "video.hdmi*"
{"video.hdmi.edid.override": false, "": false,
"video.hdmi.4kp60": false, "video.hdmi.edid.ignore": false,
"video.hdmi.edid.contenttype": 0, "video.hdmi0.edid.filename": "edid.dat",
"video.hdmi.edid.parse": true, "video.hdmi0.enabled": null,
"video.hdmi.edid.3d": false, "": null,
"video.hdmi0.boost": 5, "": 0, "video.hdmi0.timings": [],
"video.hdmi.powersave": false, "video.hdmi0.mode": 0,
"video.hdmi0.mode.force": false, "video.hdmi0.encoding": 0,
"": 0, "video.hdmi0.rotate": 0, "video.hdmi0.flip": 0,
"video.hdmi1.boost": 5, "video.hdmi1.enabled": null, "":
null, "video.hdmi1.edid.filename": "edid.dat", "video.hdmi1.timings": [],
"": 0, "video.hdmi1.mode": 0, "video.hdmi1.mode.force":
false, "video.hdmi1.encoding": 0, "": 0,
"video.hdmi1.rotate": 0, "video.hdmi1.flip": 0}
$ pibootctl get --json serial.enabled


That’s enough for this post; next time we’ll have a look at how pibootctl modifies the boot configuration, and the steps it takes to try and do so safely!