blob: 925d682c58d87d2f2818f4efa4fbd96df719ae90 [file] [log] [blame]
Lorenz Brun2f9f3872021-09-29 19:48:08 +02001"""Rules for generating EFI unified kernel images. These are EFI-bootable PE/COFF files containing a stub loader,
2a kernel, and optional commandline and initramfs in one file.
3See https://systemd.io/BOOT_LOADER_SPECIFICATION/#type-2-efi-unified-kernel-images for more information.
4"""
5
Lorenz Brun163525e2025-05-22 15:30:14 +02006load("@rules_cc//cc:action_names.bzl", "OBJ_COPY_ACTION_NAME")
7load("@rules_cc//cc:find_cc_toolchain.bzl", "CC_TOOLCHAIN_ATTRS", "find_cpp_toolchain", "use_cc_toolchain")
8load("//osbase/build:def.bzl", "build_static_transition")
Tim Windelschmidtbed76d92025-02-18 03:04:14 +01009load("//osbase/build/mkverity:def.bzl", "VerityInfo")
Lorenz Brun2f9f3872021-09-29 19:48:08 +020010
11def _efi_unified_kernel_image_impl(ctx):
Mateusz Zalega8c2c7712022-01-25 19:42:21 +010012 # Find the dependency paths to be passed to mkpayload.
13 deps = {
Lorenz Brunf099c092022-02-24 17:22:26 +010014 "linux": ctx.file.kernel,
Lorenz Brunf099c092022-02-24 17:22:26 +010015 "osrel": ctx.file.os_release,
16 "splash": ctx.file.splash,
17 "stub": ctx.file.stub,
Mateusz Zalega8c2c7712022-01-25 19:42:21 +010018 }
Lorenz Brunf099c092022-02-24 17:22:26 +010019
Mateusz Zalega8c2c7712022-01-25 19:42:21 +010020 # Since cmdline is a string attribute, put it into a file, then append
21 # that file to deps.
22 if ctx.attr.cmdline and ctx.attr.cmdline != "":
23 cmdline = ctx.actions.declare_file("cmdline")
Lorenz Brun2f9f3872021-09-29 19:48:08 +020024 ctx.actions.write(
Mateusz Zalega8c2c7712022-01-25 19:42:21 +010025 output = cmdline,
Lorenz Brun2f9f3872021-09-29 19:48:08 +020026 content = ctx.attr.cmdline,
27 )
Mateusz Zalega8c2c7712022-01-25 19:42:21 +010028 deps["cmdline"] = cmdline
Lorenz Brunf099c092022-02-24 17:22:26 +010029
Tim Windelschmidt156248b2025-01-10 00:27:45 +010030 # Get the dm-verity target table from VerityInfo provider.
Mateusz Zalega8c2c7712022-01-25 19:42:21 +010031 if ctx.attr.verity:
Tim Windelschmidt156248b2025-01-10 00:27:45 +010032 deps["rootfs_dm_table"] = ctx.attr.verity[VerityInfo].table
Lorenz Brunf099c092022-02-24 17:22:26 +010033
Mateusz Zalega8c2c7712022-01-25 19:42:21 +010034 # Format deps into command line arguments while keeping track of mkpayload
35 # runtime inputs.
Lorenz Brun2f9f3872021-09-29 19:48:08 +020036 args = []
Mateusz Zalega8c2c7712022-01-25 19:42:21 +010037 inputs = []
38 for name, file in deps.items():
Lorenz Brunf099c092022-02-24 17:22:26 +010039 if file:
40 args.append("-{}={}".format(name, file.path))
41 inputs.append(file)
42
Lorenz Brun304d42c2022-02-24 17:53:08 +010043 for file in ctx.files.initrd:
44 args.append("-initrd={}".format(file.path))
45 inputs.append(file)
46
Mateusz Zalega8c2c7712022-01-25 19:42:21 +010047 # Append the output parameter separately, as it doesn't belong with the
48 # runtime inputs.
49 image = ctx.actions.declare_file(ctx.attr.name + ".efi")
50 args.append("-output={}".format(image.path))
Lorenz Brunf099c092022-02-24 17:22:26 +010051
Mateusz Zalega8c2c7712022-01-25 19:42:21 +010052 # Append the objcopy parameter separately, as it's not of File type, and
53 # it does not constitute an input, since it's part of the toolchain.
Lorenz Brun163525e2025-05-22 15:30:14 +020054 cc_toolchain = find_cpp_toolchain(ctx)
55 feature_configuration = cc_common.configure_features(
56 ctx = ctx,
57 cc_toolchain = cc_toolchain,
58 requested_features = ctx.features,
59 unsupported_features = ctx.disabled_features,
60 )
61 objcopy = cc_common.get_tool_for_action(
62 feature_configuration = feature_configuration,
63 action_name = OBJ_COPY_ACTION_NAME,
64 )
65
Mateusz Zalega8c2c7712022-01-25 19:42:21 +010066 args.append("-objcopy={}".format(objcopy))
Lorenz Brunf099c092022-02-24 17:22:26 +010067
Mateusz Zalega8c2c7712022-01-25 19:42:21 +010068 # Run mkpayload.
Lorenz Brun2f9f3872021-09-29 19:48:08 +020069 ctx.actions.run(
Lorenz Brunf099c092022-02-24 17:22:26 +010070 mnemonic = "GenEFIKernelImage",
Tim Windelschmidt83f0aa42024-12-09 20:34:33 +010071 progress_message = "Generating EFI unified kernel image: {}".format(image.short_path),
Lorenz Brun163525e2025-05-22 15:30:14 +020072 inputs = depset(inputs, transitive = [cc_toolchain.all_files]),
Lorenz Brunf099c092022-02-24 17:22:26 +010073 outputs = [image],
74 executable = ctx.file._mkpayload,
75 arguments = args,
Lorenz Brun2f9f3872021-09-29 19:48:08 +020076 )
Lorenz Brunf099c092022-02-24 17:22:26 +010077
Mateusz Zalega8c2c7712022-01-25 19:42:21 +010078 # Return the unified kernel image file.
79 return [DefaultInfo(files = depset([image]), runfiles = ctx.runfiles(files = [image]))]
Lorenz Brun2f9f3872021-09-29 19:48:08 +020080
81efi_unified_kernel_image = rule(
Lorenz Brun163525e2025-05-22 15:30:14 +020082 cfg = build_static_transition,
Lorenz Brun2f9f3872021-09-29 19:48:08 +020083 implementation = _efi_unified_kernel_image_impl,
84 attrs = {
85 "kernel": attr.label(
Lorenz Brun163525e2025-05-22 15:30:14 +020086 doc = "The Linux kernel executable Image. Needs to have EFI stub enabled.",
Lorenz Brun2f9f3872021-09-29 19:48:08 +020087 mandatory = True,
88 allow_single_file = True,
89 ),
90 "cmdline": attr.string(
91 doc = "The kernel commandline to be embedded.",
92 ),
Lorenz Brun304d42c2022-02-24 17:53:08 +010093 "initrd": attr.label_list(
94 doc = """
95 List of payloads to concatenate and supply as the initrd parameter to Linux when it boots.
96 The name stems from the time Linux booted from an initial ram disk (initrd), but it's now
97 a catch-all for a bunch of different larger payload for early Linux initialization.
98
99 In Linux 5.15 this can first contain an arbitrary amount of uncompressed cpio archives
100 with directories being optional which is accessed by earlycpio. This is used for both
101 early microcode loading and ACPI table overrides. This can then be followed by an arbitrary
102 amount of compressed cpio archives (even with different compression methods) which will
103 together make up the initramfs. The initramfs is only booted into if it contains either
104 /init or whatever file is specified as init= in cmdline. Technically depending on kernel
105 flags you might be able to supply an actual initrd, i.e. an image of a disk loaded into
106 RAM, but that has been deprecated for nearly 2 decades and should really not be used.
107
108 For kernels designed to run on physical machines this should at least contain microcode,
109 optionally followed by a compressed initramfs. For kernels only used in virtualized
110 setups the microcode can be left out and if no initramfs is needed this option can
111 be omitted completely.
112 """,
113 allow_files = True,
Lorenz Brun2f9f3872021-09-29 19:48:08 +0200114 ),
115 "os_release": attr.label(
116 doc = """
117 The os-release file identifying the operating system.
118 See https://www.freedesktop.org/software/systemd/man/os-release.html for format.
119 """,
120 allow_single_file = True,
121 ),
122 "splash": attr.label(
123 doc = "An image in BMP format which will be displayed as a splash screen until the kernel takes over.",
124 allow_single_file = True,
125 ),
126 "stub": attr.label(
127 doc = "The stub executable itself as a PE/COFF executable.",
128 default = "@efistub//:efistub",
129 allow_single_file = True,
Lorenz Brun2f9f3872021-09-29 19:48:08 +0200130 ),
Mateusz Zalega8c2c7712022-01-25 19:42:21 +0100131 "verity": attr.label(
132 doc = "The DeviceMapper Verity rootfs target table.",
133 allow_single_file = True,
Tim Windelschmidt156248b2025-01-10 00:27:45 +0100134 providers = [DefaultInfo, VerityInfo],
Mateusz Zalega8c2c7712022-01-25 19:42:21 +0100135 ),
136 "_mkpayload": attr.label(
137 doc = "The mkpayload executable.",
Tim Windelschmidtc2290c22024-08-15 19:56:00 +0200138 default = "//osbase/build/mkpayload",
Mateusz Zalega8c2c7712022-01-25 19:42:21 +0100139 allow_single_file = True,
140 executable = True,
141 cfg = "exec",
142 ),
Lorenz Brun163525e2025-05-22 15:30:14 +0200143 } | CC_TOOLCHAIN_ATTRS,
144 toolchains = use_cc_toolchain(),
145 fragments = ["cpp"],
Lorenz Brun2f9f3872021-09-29 19:48:08 +0200146)