| Lorenz Brun | 2f9f387 | 2021-09-29 19:48:08 +0200 | [diff] [blame] | 1 | """Rules for generating EFI unified kernel images. These are EFI-bootable PE/COFF files containing a stub loader, |
| 2 | a kernel, and optional commandline and initramfs in one file. |
| 3 | See https://systemd.io/BOOT_LOADER_SPECIFICATION/#type-2-efi-unified-kernel-images for more information. |
| 4 | """ |
| 5 | |
| Lorenz Brun | 163525e | 2025-05-22 15:30:14 +0200 | [diff] [blame] | 6 | load("@rules_cc//cc:action_names.bzl", "OBJ_COPY_ACTION_NAME") |
| 7 | load("@rules_cc//cc:find_cc_toolchain.bzl", "CC_TOOLCHAIN_ATTRS", "find_cpp_toolchain", "use_cc_toolchain") |
| 8 | load("//osbase/build:def.bzl", "build_static_transition") |
| Tim Windelschmidt | bed76d9 | 2025-02-18 03:04:14 +0100 | [diff] [blame] | 9 | load("//osbase/build/mkverity:def.bzl", "VerityInfo") |
| Lorenz Brun | 2f9f387 | 2021-09-29 19:48:08 +0200 | [diff] [blame] | 10 | |
| 11 | def _efi_unified_kernel_image_impl(ctx): |
| Mateusz Zalega | 8c2c771 | 2022-01-25 19:42:21 +0100 | [diff] [blame] | 12 | # Find the dependency paths to be passed to mkpayload. |
| 13 | deps = { |
| Lorenz Brun | f099c09 | 2022-02-24 17:22:26 +0100 | [diff] [blame] | 14 | "linux": ctx.file.kernel, |
| Lorenz Brun | f099c09 | 2022-02-24 17:22:26 +0100 | [diff] [blame] | 15 | "osrel": ctx.file.os_release, |
| 16 | "splash": ctx.file.splash, |
| 17 | "stub": ctx.file.stub, |
| Mateusz Zalega | 8c2c771 | 2022-01-25 19:42:21 +0100 | [diff] [blame] | 18 | } |
| Lorenz Brun | f099c09 | 2022-02-24 17:22:26 +0100 | [diff] [blame] | 19 | |
| Mateusz Zalega | 8c2c771 | 2022-01-25 19:42:21 +0100 | [diff] [blame] | 20 | # 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 Brun | 2f9f387 | 2021-09-29 19:48:08 +0200 | [diff] [blame] | 24 | ctx.actions.write( |
| Mateusz Zalega | 8c2c771 | 2022-01-25 19:42:21 +0100 | [diff] [blame] | 25 | output = cmdline, |
| Lorenz Brun | 2f9f387 | 2021-09-29 19:48:08 +0200 | [diff] [blame] | 26 | content = ctx.attr.cmdline, |
| 27 | ) |
| Mateusz Zalega | 8c2c771 | 2022-01-25 19:42:21 +0100 | [diff] [blame] | 28 | deps["cmdline"] = cmdline |
| Lorenz Brun | f099c09 | 2022-02-24 17:22:26 +0100 | [diff] [blame] | 29 | |
| Tim Windelschmidt | 156248b | 2025-01-10 00:27:45 +0100 | [diff] [blame] | 30 | # Get the dm-verity target table from VerityInfo provider. |
| Mateusz Zalega | 8c2c771 | 2022-01-25 19:42:21 +0100 | [diff] [blame] | 31 | if ctx.attr.verity: |
| Tim Windelschmidt | 156248b | 2025-01-10 00:27:45 +0100 | [diff] [blame] | 32 | deps["rootfs_dm_table"] = ctx.attr.verity[VerityInfo].table |
| Lorenz Brun | f099c09 | 2022-02-24 17:22:26 +0100 | [diff] [blame] | 33 | |
| Mateusz Zalega | 8c2c771 | 2022-01-25 19:42:21 +0100 | [diff] [blame] | 34 | # Format deps into command line arguments while keeping track of mkpayload |
| 35 | # runtime inputs. |
| Lorenz Brun | 2f9f387 | 2021-09-29 19:48:08 +0200 | [diff] [blame] | 36 | args = [] |
| Mateusz Zalega | 8c2c771 | 2022-01-25 19:42:21 +0100 | [diff] [blame] | 37 | inputs = [] |
| 38 | for name, file in deps.items(): |
| Lorenz Brun | f099c09 | 2022-02-24 17:22:26 +0100 | [diff] [blame] | 39 | if file: |
| 40 | args.append("-{}={}".format(name, file.path)) |
| 41 | inputs.append(file) |
| 42 | |
| Lorenz Brun | 304d42c | 2022-02-24 17:53:08 +0100 | [diff] [blame] | 43 | for file in ctx.files.initrd: |
| 44 | args.append("-initrd={}".format(file.path)) |
| 45 | inputs.append(file) |
| 46 | |
| Mateusz Zalega | 8c2c771 | 2022-01-25 19:42:21 +0100 | [diff] [blame] | 47 | # 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 Brun | f099c09 | 2022-02-24 17:22:26 +0100 | [diff] [blame] | 51 | |
| Mateusz Zalega | 8c2c771 | 2022-01-25 19:42:21 +0100 | [diff] [blame] | 52 | # 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 Brun | 163525e | 2025-05-22 15:30:14 +0200 | [diff] [blame] | 54 | 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 Zalega | 8c2c771 | 2022-01-25 19:42:21 +0100 | [diff] [blame] | 66 | args.append("-objcopy={}".format(objcopy)) |
| Lorenz Brun | f099c09 | 2022-02-24 17:22:26 +0100 | [diff] [blame] | 67 | |
| Mateusz Zalega | 8c2c771 | 2022-01-25 19:42:21 +0100 | [diff] [blame] | 68 | # Run mkpayload. |
| Lorenz Brun | 2f9f387 | 2021-09-29 19:48:08 +0200 | [diff] [blame] | 69 | ctx.actions.run( |
| Lorenz Brun | f099c09 | 2022-02-24 17:22:26 +0100 | [diff] [blame] | 70 | mnemonic = "GenEFIKernelImage", |
| Tim Windelschmidt | 83f0aa4 | 2024-12-09 20:34:33 +0100 | [diff] [blame] | 71 | progress_message = "Generating EFI unified kernel image: {}".format(image.short_path), |
| Lorenz Brun | 163525e | 2025-05-22 15:30:14 +0200 | [diff] [blame] | 72 | inputs = depset(inputs, transitive = [cc_toolchain.all_files]), |
| Lorenz Brun | f099c09 | 2022-02-24 17:22:26 +0100 | [diff] [blame] | 73 | outputs = [image], |
| 74 | executable = ctx.file._mkpayload, |
| 75 | arguments = args, |
| Lorenz Brun | 2f9f387 | 2021-09-29 19:48:08 +0200 | [diff] [blame] | 76 | ) |
| Lorenz Brun | f099c09 | 2022-02-24 17:22:26 +0100 | [diff] [blame] | 77 | |
| Mateusz Zalega | 8c2c771 | 2022-01-25 19:42:21 +0100 | [diff] [blame] | 78 | # Return the unified kernel image file. |
| 79 | return [DefaultInfo(files = depset([image]), runfiles = ctx.runfiles(files = [image]))] |
| Lorenz Brun | 2f9f387 | 2021-09-29 19:48:08 +0200 | [diff] [blame] | 80 | |
| 81 | efi_unified_kernel_image = rule( |
| Lorenz Brun | 163525e | 2025-05-22 15:30:14 +0200 | [diff] [blame] | 82 | cfg = build_static_transition, |
| Lorenz Brun | 2f9f387 | 2021-09-29 19:48:08 +0200 | [diff] [blame] | 83 | implementation = _efi_unified_kernel_image_impl, |
| 84 | attrs = { |
| 85 | "kernel": attr.label( |
| Lorenz Brun | 163525e | 2025-05-22 15:30:14 +0200 | [diff] [blame] | 86 | doc = "The Linux kernel executable Image. Needs to have EFI stub enabled.", |
| Lorenz Brun | 2f9f387 | 2021-09-29 19:48:08 +0200 | [diff] [blame] | 87 | mandatory = True, |
| 88 | allow_single_file = True, |
| 89 | ), |
| 90 | "cmdline": attr.string( |
| 91 | doc = "The kernel commandline to be embedded.", |
| 92 | ), |
| Lorenz Brun | 304d42c | 2022-02-24 17:53:08 +0100 | [diff] [blame] | 93 | "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 Brun | 2f9f387 | 2021-09-29 19:48:08 +0200 | [diff] [blame] | 114 | ), |
| 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 Brun | 2f9f387 | 2021-09-29 19:48:08 +0200 | [diff] [blame] | 130 | ), |
| Mateusz Zalega | 8c2c771 | 2022-01-25 19:42:21 +0100 | [diff] [blame] | 131 | "verity": attr.label( |
| 132 | doc = "The DeviceMapper Verity rootfs target table.", |
| 133 | allow_single_file = True, |
| Tim Windelschmidt | 156248b | 2025-01-10 00:27:45 +0100 | [diff] [blame] | 134 | providers = [DefaultInfo, VerityInfo], |
| Mateusz Zalega | 8c2c771 | 2022-01-25 19:42:21 +0100 | [diff] [blame] | 135 | ), |
| 136 | "_mkpayload": attr.label( |
| 137 | doc = "The mkpayload executable.", |
| Tim Windelschmidt | c2290c2 | 2024-08-15 19:56:00 +0200 | [diff] [blame] | 138 | default = "//osbase/build/mkpayload", |
| Mateusz Zalega | 8c2c771 | 2022-01-25 19:42:21 +0100 | [diff] [blame] | 139 | allow_single_file = True, |
| 140 | executable = True, |
| 141 | cfg = "exec", |
| 142 | ), |
| Lorenz Brun | 163525e | 2025-05-22 15:30:14 +0200 | [diff] [blame] | 143 | } | CC_TOOLCHAIN_ATTRS, |
| 144 | toolchains = use_cc_toolchain(), |
| 145 | fragments = ["cpp"], |
| Lorenz Brun | 2f9f387 | 2021-09-29 19:48:08 +0200 | [diff] [blame] | 146 | ) |