This tool builds flash images for AMD Zen systems.
We use the cargo xtask
for building.
You will need to have either the LLVM ld.lld
or GNU linkers
installed in order to build. If you are building on illumos,
GNU ld
is installed as gld
; set LD=gld
before running
cargo xtask
if you get errors from build.rs
.
Select a configuration file for the system and firmware version
that you are using, e.g., etc/milan-gimlet-b-1.0.0.a.efs.json5
and customize it according to your application if necessary.
To build an image for a Milan-based Gimlet, run the following,
specifying the make
variable PAYLOAD
to point to the reset
image payload you want in the result:
cargo xtask gen \
--payload /path/to/phbl \
--amd-firmware /path/to/amd-firmware/blobs \
--app apps/milan-gimlet-b-1.0.0.a.toml \
--image out/milan-gimlet-b-1.0.0.a.img
This will create an image file in the out/
subdirectory of
the current directory, with the name that you specified, e.g.,
milan-gimlet-b-1.0.0.a.img
, with the production phbl
loader as the payload.
To use the development loader, one may run:
cargo xtask gen \
--payload /path/to/bldb/target/x86_64-oxide-none-elf/release/bldb \
--amd-firmware /path/to/amd-firmware/blobs \
--app apps/turin-ruby-1.0.0.3-p1.toml \
--image out/turin-ruby-1.0.0.3-p1-bldb.img
Alternatively, one may run cargo run
directory, and not use
the xtask
wrapper. For example:
cargo run -- \
-B /path/to/amd-firmware/GN/1.0.0.a \
-c etc/milan-gimlet-b-1.0.0.a.efs.json5 \
-r /path/to/target/x86_64-oxide-none-elf/release/bldb \
-o milan-gimlet-b-1.0.0.a.img
Here, the following are given as arguments:
/path/to/amd-firmware/GN/1.0.0.a
is in the search path for blobs,- The configuration file used is
etc/milan-gimlet-b-1.0.0.a.efs.json5
, - The reset image is
bldb
. Note that there are restrictions on the contents of the ELF file given to the image builder.amd-host-image-builder
extracts the segments that need to be in the reset image from the ELF file and stores them into the appropriate flash entries. Those entries will automatically be created and should not be specified in the JSON configuration file. - The output file name is given as
milan-gimlet-b-1.0.0.a.img
.
amd-host-image-builder
will incorporate a number of
(necessary) blobs named in the configuration file. These blobs
are located by searching directories specified via the -B <directory>
option, which can be given multiple times. If a
blob is named by an absolute path in the configuration file,
then that will be used. Otherwise, the directories will be
searched in the order they were specified.
The resulting image will be in milan-gimlet-b-1.0.0.a.img
and
can be flashed using
humility qspi or
a hardware flasher (CH341A etc).
The PSP will print debug messages to the serial port that can be configured in the settings below, see PSP configuration.
The configuration file syntax is JSON5.
The configuration file contents specify:
- Processor generation,
- PSP directory contents,
- BHD directory contents,
See the subsections below for more details.
Running cargo xtask schema
builds the schema and stores it
into /out/efs.schema.json
.
We recommend using an editor that can match the document against
a schema when editing the configuration. For example, IntelliJ
IDEA is known to work by setting a mapping between the file
suffix .efs.json5
and the file efs.schema.json
in JSON Schema Mappings
in its global settings.
Each directory has any number of entries. Each entry has a
source
and a target
field.
The source
field specifies how to construct the payload
data for that entry. Possible fields in source
are:
Value
and an immediate value to useApcbJson
and the inline configuration for the PSPBlobFile
and the name of a file to load and use as payload
Use the target
field to specify where in the flash to put the
result. The only mandatory field is type
to specify the
corresponding entry kind.
The PSP can be configured using one or multiple entries in the
Bhd directory with the type ApcbBackup
and/or Apcb
. For
now, it is recommended to have exactly one entry of type
ApcbBackup
, and to store it into sub_program
1. Note that
sub_program
an optional field in the target
that defaults to
0.
We represent the PSP configuration as JSON5, too. The format is very close to the actual APCB, with some reserved fields hidden if they are empty anyway. The checksum will automatically be updated by amd-host-image-builder and doesn't need to be manually updated.
For extra possible entries that you can add to the Apcb, be sure to validate against the JSON schema.
The Apcb contains (about 3) groups. Each group contains several
dozen entries. Each entry is either a "struct" or a "tokens"
entry. Struct entries are denoted by the keyword Struct
, and
are an older mechanism. AMD is in the process of replacing them
with tokens entries, denoted by tokens
. Settings should be
made using tokens
entries, not Struct
entries, if possible.
For example, there's an entry ErrorOutControl
which you can
use to configure PSP error messages, and ConsoleOutControl
which you can use to configure early PSP messages. You can
configure target and verbosity.
Under tokens
, there's are tokens to configure later PSP
messages. For example, the token AblSerialBaudRate
configures
the baud rate of the UART, FchConsoleOutMode
to set whether
PSP prints to a UART or not (0), FchConsoleOutSerialPort
to
set which UART to use (SuperIo
, Uart0Mmio
, or Uart1Mmio
;
supposedly moved to FchConsoleMode
in Milan.
This tool generates its output such that, when the PSP loads the reset image into memory, it is laid out as specified in the source ELF file. Execution will start at the ELF entry point.
When the system starts, the PSP holds the x86 cores in reset while loading the image. Eventually, it starts the x86 "boot" CPU (called the "Boot Support Core", "Bootstrap Core", or BSC in AMD's documentation) in 16-bit real mode. That CPU will start executing 16 Byte below the end of the aligned 16-bit real-mode segment at the end of the reset image. Thus, the ELF entry point must contain valid 16-bit real-mode code exactly 16 bytes from the end of the last segment in the file.
Also, the ELF file needs to be linked in a way that it actually specifies physical addresses: there is no MMU configured, let alone enabled, when execution starts at the reset vector.
The ELF file must also expose three symbols:
__sloader
marking the start of the reset image__eloader
marking the end of the reset image_BL_SPACE
giving the amount of memory required for the image, in bytes.
The values of those special symbols are validated by
amd-host-image-builder
, which will fail if they do not
match a set of hardcoded criteria. See the tool's source
code for the exact rules.
For the special case of facilitating bring-up work, it is also possible to specify a non-ELF file that is interpreted basically as a blob. In that case, it will be loaded into RAM such that it ends at address 0x8000_0000. Validation checks are not performed in this case. Further, we make no claims of stability for this feature and reserve the right to change or remove it at any point--you are on your own.
Firmware blobs come from AMD, and we do not redistribute them
here. However, the dump
subcommand of this tool can extract
them from an existing image. If you have, say, a ROM image with
AGESA for your board, you can use this to extract the blobs that
are embedded with that image, and then use those with
amd-host-image-builder
to build your own image with a
different payload.
AMD host image builder uses the Mozilla Public License, 2.0.