blob: 51f2ff1960e346ff9bfbdbe5135a2eb21402c33b [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")
Tim Windelschmidtd4817492025-06-16 15:03:12 +02008load("@rules_cc//cc/common:cc_common.bzl", "cc_common")
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(
82 implementation = _efi_unified_kernel_image_impl,
83 attrs = {
84 "kernel": attr.label(
Lorenz Brun163525e2025-05-22 15:30:14 +020085 doc = "The Linux kernel executable Image. Needs to have EFI stub enabled.",
Lorenz Brun2f9f3872021-09-29 19:48:08 +020086 mandatory = True,
87 allow_single_file = True,
88 ),
89 "cmdline": attr.string(
90 doc = "The kernel commandline to be embedded.",
91 ),
Lorenz Brun304d42c2022-02-24 17:53:08 +010092 "initrd": attr.label_list(
93 doc = """
94 List of payloads to concatenate and supply as the initrd parameter to Linux when it boots.
95 The name stems from the time Linux booted from an initial ram disk (initrd), but it's now
96 a catch-all for a bunch of different larger payload for early Linux initialization.
97
98 In Linux 5.15 this can first contain an arbitrary amount of uncompressed cpio archives
99 with directories being optional which is accessed by earlycpio. This is used for both
100 early microcode loading and ACPI table overrides. This can then be followed by an arbitrary
101 amount of compressed cpio archives (even with different compression methods) which will
102 together make up the initramfs. The initramfs is only booted into if it contains either
103 /init or whatever file is specified as init= in cmdline. Technically depending on kernel
104 flags you might be able to supply an actual initrd, i.e. an image of a disk loaded into
105 RAM, but that has been deprecated for nearly 2 decades and should really not be used.
106
107 For kernels designed to run on physical machines this should at least contain microcode,
108 optionally followed by a compressed initramfs. For kernels only used in virtualized
109 setups the microcode can be left out and if no initramfs is needed this option can
110 be omitted completely.
111 """,
112 allow_files = True,
Lorenz Brun2f9f3872021-09-29 19:48:08 +0200113 ),
114 "os_release": attr.label(
115 doc = """
116 The os-release file identifying the operating system.
117 See https://www.freedesktop.org/software/systemd/man/os-release.html for format.
118 """,
119 allow_single_file = True,
120 ),
121 "splash": attr.label(
122 doc = "An image in BMP format which will be displayed as a splash screen until the kernel takes over.",
123 allow_single_file = True,
124 ),
125 "stub": attr.label(
126 doc = "The stub executable itself as a PE/COFF executable.",
127 default = "@efistub//:efistub",
128 allow_single_file = True,
Lorenz Brun2f9f3872021-09-29 19:48:08 +0200129 ),
Mateusz Zalega8c2c7712022-01-25 19:42:21 +0100130 "verity": attr.label(
131 doc = "The DeviceMapper Verity rootfs target table.",
132 allow_single_file = True,
Tim Windelschmidt156248b2025-01-10 00:27:45 +0100133 providers = [DefaultInfo, VerityInfo],
Mateusz Zalega8c2c7712022-01-25 19:42:21 +0100134 ),
135 "_mkpayload": attr.label(
136 doc = "The mkpayload executable.",
Tim Windelschmidtc2290c22024-08-15 19:56:00 +0200137 default = "//osbase/build/mkpayload",
Mateusz Zalega8c2c7712022-01-25 19:42:21 +0100138 allow_single_file = True,
139 executable = True,
140 cfg = "exec",
141 ),
Lorenz Brun163525e2025-05-22 15:30:14 +0200142 } | CC_TOOLCHAIN_ATTRS,
143 toolchains = use_cc_toolchain(),
144 fragments = ["cpp"],
Lorenz Brun2f9f3872021-09-29 19:48:08 +0200145)