blob: 8cc068f20d38227e156c92876b928c4ffd33140f [file] [log] [blame]
"""Rules for generating EFI unified kernel images. These are EFI-bootable PE/COFF files containing a stub loader,
a kernel, and optional commandline and initramfs in one file.
See https://systemd.io/BOOT_LOADER_SPECIFICATION/#type-2-efi-unified-kernel-images for more information.
"""
load("//build/toolchain/llvm-efi:transition.bzl", "build_efi_transition")
load("//metropolis/node/build:def.bzl", "VerityConfig")
def _efi_unified_kernel_image_impl(ctx):
# Find the dependency paths to be passed to mkpayload.
deps = {
"linux": ctx.file.kernel,
"osrel": ctx.file.os_release,
"splash": ctx.file.splash,
"stub": ctx.file.stub,
}
# Since cmdline is a string attribute, put it into a file, then append
# that file to deps.
if ctx.attr.cmdline and ctx.attr.cmdline != "":
cmdline = ctx.actions.declare_file("cmdline")
ctx.actions.write(
output = cmdline,
content = ctx.attr.cmdline,
)
deps["cmdline"] = cmdline
# Get the dm-verity target table from VerityConfig provider.
if ctx.attr.verity:
deps["rootfs_dm_table"] = ctx.attr.verity[VerityConfig].table
# Format deps into command line arguments while keeping track of mkpayload
# runtime inputs.
args = []
inputs = []
for name, file in deps.items():
if file:
args.append("-{}={}".format(name, file.path))
inputs.append(file)
for file in ctx.files.initrd:
args.append("-initrd={}".format(file.path))
inputs.append(file)
# Append the output parameter separately, as it doesn't belong with the
# runtime inputs.
image = ctx.actions.declare_file(ctx.attr.name + ".efi")
args.append("-output={}".format(image.path))
# Append the objcopy parameter separately, as it's not of File type, and
# it does not constitute an input, since it's part of the toolchain.
objcopy = ctx.toolchains["@bazel_tools//tools/cpp:toolchain_type"].cc.objcopy_executable
args.append("-objcopy={}".format(objcopy))
# Run mkpayload.
ctx.actions.run(
mnemonic = "GenEFIKernelImage",
progress_message = "Generating EFI unified kernel image",
inputs = inputs,
outputs = [image],
executable = ctx.file._mkpayload,
arguments = args,
)
# Return the unified kernel image file.
return [DefaultInfo(files = depset([image]), runfiles = ctx.runfiles(files = [image]))]
efi_unified_kernel_image = rule(
implementation = _efi_unified_kernel_image_impl,
attrs = {
"kernel": attr.label(
doc = "The Linux kernel executable bzImage. Needs to have EFI handover and EFI stub enabled.",
mandatory = True,
allow_single_file = True,
),
"cmdline": attr.string(
doc = "The kernel commandline to be embedded.",
),
"initrd": attr.label_list(
doc = """
List of payloads to concatenate and supply as the initrd parameter to Linux when it boots.
The name stems from the time Linux booted from an initial ram disk (initrd), but it's now
a catch-all for a bunch of different larger payload for early Linux initialization.
In Linux 5.15 this can first contain an arbitrary amount of uncompressed cpio archives
with directories being optional which is accessed by earlycpio. This is used for both
early microcode loading and ACPI table overrides. This can then be followed by an arbitrary
amount of compressed cpio archives (even with different compression methods) which will
together make up the initramfs. The initramfs is only booted into if it contains either
/init or whatever file is specified as init= in cmdline. Technically depending on kernel
flags you might be able to supply an actual initrd, i.e. an image of a disk loaded into
RAM, but that has been deprecated for nearly 2 decades and should really not be used.
For kernels designed to run on physical machines this should at least contain microcode,
optionally followed by a compressed initramfs. For kernels only used in virtualized
setups the microcode can be left out and if no initramfs is needed this option can
be omitted completely.
""",
allow_files = True,
),
"os_release": attr.label(
doc = """
The os-release file identifying the operating system.
See https://www.freedesktop.org/software/systemd/man/os-release.html for format.
""",
allow_single_file = True,
),
"splash": attr.label(
doc = "An image in BMP format which will be displayed as a splash screen until the kernel takes over.",
allow_single_file = True,
),
"stub": attr.label(
doc = "The stub executable itself as a PE/COFF executable.",
default = "@efistub//:efistub",
allow_single_file = True,
executable = True,
cfg = build_efi_transition,
),
"verity": attr.label(
doc = "The DeviceMapper Verity rootfs target table.",
allow_single_file = True,
providers = [DefaultInfo, VerityConfig],
),
"_mkpayload": attr.label(
doc = "The mkpayload executable.",
default = "//metropolis/node/build/mkpayload",
allow_single_file = True,
executable = True,
cfg = "exec",
),
# Allow for transitions to be attached to this rule.
"_whitelist_function_transition": attr.label(
default = "@bazel_tools//tools/whitelists/function_transition_whitelist",
),
},
toolchains = [
"@bazel_tools//tools/cpp:toolchain_type"
],
)