For x86, building xen.efi requires gcc 4.5.x or above (4.6.x or newer
recommended, as 4.5.x was probably never really tested for this purpose)
and binutils 2.22 or newer. Additionally, the binutils build must be
configured to include support for the x86_64-pep emulation (i.e.
--enable-targets=x86_64-pep
or an option of equivalent
effect should be passed to the configure script).
For arm64, the PE/COFF header is open-coded in assembly, so no toolchain support for PE/COFF is required. Also, the PE/COFF header co-exists with the normal Image format, so a single binary may be booted as an Image file or as an EFI application. When booted as an EFI application, Xen requires a configuration file as described below unless a bootloader, such as GRUB, has loaded the modules and describes them in the device tree provided to Xen. If a bootloader provides a device tree containing modules then any configuration files are ignored, and the bootloader is responsible for populating all relevant device tree nodes. The property “xen,uefi-cfg-load” can be specified in the /chosen node to force Xen to load the configuration file even if multiboot modules are found.
Once built, make install-xen
will place the resulting
binary directly into the EFI boot partition, provided
EFI_VENDOR
is set in the environment (and
EFI_MOUNTPOINT
is overridden as needed, should the default
of /boot/efi
not match your system). When built with debug
info, the binary can be quite large. Setting
INSTALL_EFI_STRIP=1
in the environment will cause it to be
stripped of debug info in the process of installing.
INSTALL_EFI_STRIP
can also be set to any combination of
options suitable to pass to strip
, in case the default ones
don’t do. The xen.efi binary will also be installed in
/usr/lib64/efi/
, unless EFI_DIR
is set in the
environment to override this default. This binary will not be stripped
in the process.
The binary itself will require a configuration file (names with the
.efi
extension of the binary’s name replaced by
.cfg
, and - until an existing file is found - trailing name
components dropped at .
, -
, and _
separators will be tried) to be present in the same directory as the
binary. (To illustrate the name handling, a binary named
xen-4.2-unstable.efi
would try
xen-4.2-unstable.cfg
, xen-4.2.cfg
,
xen-4.cfg
, and xen.cfg
in order.) One can
override this with a command line option
(-cfg=<filename>
). This configuration file and EFI
commandline are only used for booting directly from EFI firmware, or
when using an EFI loader that does not support the multiboot2 protocol.
When booting using GRUB or another multiboot aware loader the EFI
commandline is ignored and all information is passed from the loader to
Xen using the multiboot protocol.
The configuration file consists of one or more sections headed by a
section name enclosed in square brackets, with individual values
specified in each section. A section named [global]
is
treated specially to allow certain settings to apply to all other
sections (or to provide defaults for certain settings in case individual
sections don’t specify them). This file (for now) needs to be of ASCII
type and not e.g. UTF-8 or UTF-16. A typical file would thus look like
this (#
serving as comment character):
**************************example begin******************************
[global]
default=sle11sp2
[sle11sp2]
options=console=vga,com1 com1=57600 loglvl=all noreboot
kernel=vmlinuz-3.0.31-0.4-xen [domain 0 command line options]
ramdisk=initrd-3.0.31-0.4-xen
**************************example end********************************
The individual values used here are:
###default=<name>
Specifies the section to use for booting, if none was specified on
the command line; only meaningful in the [global]
section.
This isn’t required; if absent, section headers will be ignored and for
each value looked for the first instance within the file will be
used.
###options=<text>
Specifies the options passed to the hypervisor, see Xen Hypervisor Command Line Options.
###kernel=<filename>[ <options>]
Specifies the Dom0 kernel binary and the options to pass to it.
The options should in general be the same as is used when booting
natively, e.g. including root=...
etc.
Check your bootloader (e.g. grub) configuration or
/proc/cmdline
for the native configuration.
###ramdisk=<filename>
Specifies a Linux-style initial RAM disk image to load.
Other values to specify are:
###video=gfx-<xres>[x<yres>[x<depth>]]
Specifies a video mode to select if available. In case of problems,
the -basevideo
command line option can be used to skip
altering video modes.
###xsm=<filename>
Specifies an XSM module to load.
###ucode=<filename>
Specifies a CPU microcode blob to load. (x86 only)
###dtb=<filename>
Specifies a device tree file to load. The platform firmware may provide a DTB in an EFI configuration table, so this field is optional in that case. A dtb specified in the configuration file will override a device tree provided in the EFI configuration table. (ARM only)
###chain=<filename>
Specifies an alternate configuration file to use in case the
specified section (and in particular its kernel=
setting)
can’t be found in the default (or specified) configuration file. This is
only meaningful in the [global] section and really not meant to be used
together with the -cfg=
command line option.
Filenames must be specified relative to the location of the EFI binary.
Extra options to be passed to Xen can also be specified on the
command line, following a --
separator option.
The “Unified” kernel image can be generated by adding additional sections to the Xen EFI executable with objcopy, similar to how systemd-boot uses the stub to add them to the Linux kernel
The sections for the xen configuration file, the dom0 kernel, dom0
initrd, XSM and CPU microcode should be added after the Xen
.pad
section, the ending address of which can be located
with:
objdump -h xen.efi \
| perl -ane '/\.pad/ && printf "0x%016x\n", hex($F[2]) + hex($F[3])'
For all the examples the .pad
section ended at
0xffff82d041000000. All the sections are optional (.config
,
.kernel
, .ramdisk
, .xsm
,
.ucode
(x86) and .dtb
(ARM)) and the order
does not matter. The virtual addresses do not need to be contiguous,
although they should not be overlapping and should all be greater than
the last virtual address of the hypervisor components.
objcopy \
--add-section .config=xen.cfg \
--change-section-vma .config=0xffff82d041000000
--add-section .ucode=ucode.bin \
--change-section-vma .ucode=0xffff82d041010000 \
--add-section .xsm=xsm.cfg \
--change-section-vma .xsm=0xffff82d041080000 \
--add-section .kernel=vmlinux \
--change-section-vma .kernel=0xffff82d041100000 \
--add-section .ramdisk=initrd.img \
--change-section-vma .ramdisk=0xffff82d042000000 \
xen.efi \
xen.unified.efi
The unified executable can be signed with sbsigntool to make it usable with UEFI secure boot:
sbsign \
--key signing.key \
--cert cert.pem \
--output xen.signed.efi \
xen.unified.efi
When booting using UEFI on ARM, it is possible to specify the Dom0 modules directly from the device tree without using the Xen configuration file, here an example:
chosen { #size-cells = <0x1>; #address-cells = <0x1>; xen,xen-bootargs = “[Xen boot arguments]”
module@1 {
compatible = "multiboot,kernel", "multiboot,module";
xen,uefi-binary = "vmlinuz-3.0.31-0.4-xen";
bootargs = "[domain 0 command line options]";
};
module@2 {
compatible = "multiboot,ramdisk", "multiboot,module";
xen,uefi-binary = "initrd-3.0.31-0.4-xen";
};
}
Dom0less feature is supported by ARM and it is possible to use it when Xen is started as an EFI application. The way to specify the domU domains is by Device Tree as specified in the dom0less documentation page under the “Device Tree configuration” section, but instead of declaring the reg property in the boot module, the user must specify the “xen,uefi-binary” property containing the name of the binary file that has to be loaded in memory. The UEFI stub will load the binary in memory and it will add the reg property accordingly.
An example here:
domU1 { #address-cells = <1>; #size-cells = <1>; compatible = “xen,domain”; memory = <0 0x20000>; cpus = <1>; vpl011;
module@1 {
compatible = "multiboot,kernel", "multiboot,module";
xen,uefi-binary = "vmlinuz-3.0.31-0.4-xen";
bootargs = "console=ttyAMA0";
};
module@2 {
compatible = "multiboot,ramdisk", "multiboot,module";
xen,uefi-binary = "initrd-3.0.31-0.4-xen";
};
module@3 {
compatible = "multiboot,device-tree", "multiboot,module";
xen,uefi-binary = "passthrough.dtb";
};
};
These are the different ways to boot a Xen system from UEFI:
This configuration can be started using the Xen configuration file in the example above.
This configuration needs the domU domain(s) specified in the /chosen node, examples of how to do that are provided by the documentation about dom0less and the example above shows how to use the “xen,uefi-binary” property to use the UEFI stub for module loading. When adding DomU modules to device tree, also add the property xen,uefi-cfg-load under chosen for Xen to load the Xen config file. Otherwise, Xen will skip the config file and rely on device tree alone. When using the Xen configuration file in conjunction with the device tree, you can specify the Xen boot arguments in the configuration file with the “options=” keyword or in the device tree with the “xen,xen-bootargs” property, but be aware that the Xen configuration file value has a precedence over the DT value.
Example 1 of how to boot a true dom0less configuration:
Xen configuration file: skipped.
Device tree:
chosen {
#size-cells = <0x1>;
#address-cells = <0x1>;
xen,xen-bootargs = "<Xen command line>"
domU1 {
#size-cells = <0x1>;
#address-cells = <0x1>;
compatible = "xen,domain";
cpus = <0x1>;
memory = <0x0 0xc0000>;
vpl011;
module@1 {
compatible = "multiboot,kernel", "multiboot,module";
xen,uefi-binary = "Image-domu1.bin";
bootargs = "console=ttyAMA0 root=/dev/ram0 rw";
};
};
domU2 {
#size-cells = <0x1>;
#address-cells = <0x1>;
compatible = "xen,domain";
cpus = <0x1>;
memory = <0x0 0x100000>;
vpl011;
module@2 {
compatible = "multiboot,kernel", "multiboot,module";
xen,uefi-binary = "Image-domu2.bin";
bootargs = "console=ttyAMA0 root=/dev/ram0 rw";
};
};
};
Example 2 of how to boot a true dom0less configuration:
Xen configuration file:
[global]
default=xen
[xen]
options=<Xen command line>
dtb=<optional DTB>
Device tree:
chosen {
#size-cells = <0x1>;
#address-cells = <0x1>;
xen,uefi-cfg-load;
domU1 {
#size-cells = <0x1>;
#address-cells = <0x1>;
compatible = "xen,domain";
cpus = <0x1>;
memory = <0x0 0xc0000>;
vpl011;
module@1 {
compatible = "multiboot,kernel", "multiboot,module";
xen,uefi-binary = "Image-domu1.bin";
bootargs = "console=ttyAMA0 root=/dev/ram0 rw";
};
};
domU2 {
#size-cells = <0x1>;
#address-cells = <0x1>;
compatible = "xen,domain";
cpus = <0x1>;
memory = <0x0 0x100000>;
vpl011;
module@2 {
compatible = "multiboot,kernel", "multiboot,module";
xen,uefi-binary = "Image-domu2.bin";
bootargs = "console=ttyAMA0 root=/dev/ram0 rw";
};
};
};
This configuration is a mix of the two configuration above, to boot this one the configuration file can be processed or the Dom0 modules can be read from the device tree.
Here the first example:
Xen configuration file:
[global]
default=xen
[xen]
options=<Xen command line>
kernel=vmlinuz-3.0.31-0.4-xen [domain 0 command line options]
ramdisk=initrd-3.0.31-0.4-xen
dtb=<optional DTB>
Device tree:
chosen {
#size-cells = <0x1>;
#address-cells = <0x1>;
xen,uefi-cfg-load;
domU1 {
#size-cells = <0x1>;
#address-cells = <0x1>;
compatible = "xen,domain";
cpus = <0x1>;
memory = <0x0 0xc0000>;
vpl011;
module@1 {
compatible = "multiboot,kernel", "multiboot,module";
xen,uefi-binary = "Image-domu1.bin";
bootargs = "console=ttyAMA0 root=/dev/ram0 rw";
};
};
};
Here the second example:
Device tree:
chosen {
#size-cells = <0x1>;
#address-cells = <0x1>;
xen,xen-bootargs = "[Xen boot arguments]"
module@1 {
compatible = "multiboot,kernel", "multiboot,module";
xen,uefi-binary = "vmlinuz-3.0.31-0.4-xen";
bootargs = "[domain 0 command line options]";
};
module@2 {
compatible = "multiboot,ramdisk", "multiboot,module";
xen,uefi-binary = "initrd-3.0.31-0.4-xen";
};
domU1 {
#size-cells = <0x1>;
#address-cells = <0x1>;
compatible = "xen,domain";
cpus = <0x1>;
memory = <0x0 0xc0000>;
vpl011;
module@1 {
compatible = "multiboot,kernel", "multiboot,module";
xen,uefi-binary = "Image-domu1.bin";
bootargs = "console=ttyAMA0 root=/dev/ram0 rw";
};
};
};