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 | |
| 6 | load("//build/toolchain/llvm-efi:transition.bzl", "build_efi_transition") |
Mateusz Zalega | 8c2c771 | 2022-01-25 19:42:21 +0100 | [diff] [blame] | 7 | load("//metropolis/node/build:def.bzl", "VerityConfig") |
Lorenz Brun | 2f9f387 | 2021-09-29 19:48:08 +0200 | [diff] [blame] | 8 | |
| 9 | def _efi_unified_kernel_image_impl(ctx): |
Mateusz Zalega | 8c2c771 | 2022-01-25 19:42:21 +0100 | [diff] [blame] | 10 | # Find the dependency paths to be passed to mkpayload. |
| 11 | deps = { |
Lorenz Brun | f099c09 | 2022-02-24 17:22:26 +0100 | [diff] [blame] | 12 | "linux": ctx.file.kernel, |
Lorenz Brun | f099c09 | 2022-02-24 17:22:26 +0100 | [diff] [blame] | 13 | "osrel": ctx.file.os_release, |
| 14 | "splash": ctx.file.splash, |
| 15 | "stub": ctx.file.stub, |
Mateusz Zalega | 8c2c771 | 2022-01-25 19:42:21 +0100 | [diff] [blame] | 16 | } |
Lorenz Brun | f099c09 | 2022-02-24 17:22:26 +0100 | [diff] [blame] | 17 | |
Mateusz Zalega | 8c2c771 | 2022-01-25 19:42:21 +0100 | [diff] [blame] | 18 | # Since cmdline is a string attribute, put it into a file, then append |
| 19 | # that file to deps. |
| 20 | if ctx.attr.cmdline and ctx.attr.cmdline != "": |
| 21 | cmdline = ctx.actions.declare_file("cmdline") |
Lorenz Brun | 2f9f387 | 2021-09-29 19:48:08 +0200 | [diff] [blame] | 22 | ctx.actions.write( |
Mateusz Zalega | 8c2c771 | 2022-01-25 19:42:21 +0100 | [diff] [blame] | 23 | output = cmdline, |
Lorenz Brun | 2f9f387 | 2021-09-29 19:48:08 +0200 | [diff] [blame] | 24 | content = ctx.attr.cmdline, |
| 25 | ) |
Mateusz Zalega | 8c2c771 | 2022-01-25 19:42:21 +0100 | [diff] [blame] | 26 | deps["cmdline"] = cmdline |
Lorenz Brun | f099c09 | 2022-02-24 17:22:26 +0100 | [diff] [blame] | 27 | |
Mateusz Zalega | 8c2c771 | 2022-01-25 19:42:21 +0100 | [diff] [blame] | 28 | # Get the dm-verity target table from VerityConfig provider. |
| 29 | if ctx.attr.verity: |
Lorenz Brun | f099c09 | 2022-02-24 17:22:26 +0100 | [diff] [blame] | 30 | deps["rootfs_dm_table"] = ctx.attr.verity[VerityConfig].table |
| 31 | |
Mateusz Zalega | 8c2c771 | 2022-01-25 19:42:21 +0100 | [diff] [blame] | 32 | # Format deps into command line arguments while keeping track of mkpayload |
| 33 | # runtime inputs. |
Lorenz Brun | 2f9f387 | 2021-09-29 19:48:08 +0200 | [diff] [blame] | 34 | args = [] |
Mateusz Zalega | 8c2c771 | 2022-01-25 19:42:21 +0100 | [diff] [blame] | 35 | inputs = [] |
| 36 | for name, file in deps.items(): |
Lorenz Brun | f099c09 | 2022-02-24 17:22:26 +0100 | [diff] [blame] | 37 | if file: |
| 38 | args.append("-{}={}".format(name, file.path)) |
| 39 | inputs.append(file) |
| 40 | |
Lorenz Brun | 304d42c | 2022-02-24 17:53:08 +0100 | [diff] [blame] | 41 | for file in ctx.files.initrd: |
| 42 | args.append("-initrd={}".format(file.path)) |
| 43 | inputs.append(file) |
| 44 | |
Mateusz Zalega | 8c2c771 | 2022-01-25 19:42:21 +0100 | [diff] [blame] | 45 | # Append the output parameter separately, as it doesn't belong with the |
| 46 | # runtime inputs. |
| 47 | image = ctx.actions.declare_file(ctx.attr.name + ".efi") |
| 48 | args.append("-output={}".format(image.path)) |
Lorenz Brun | f099c09 | 2022-02-24 17:22:26 +0100 | [diff] [blame] | 49 | |
Mateusz Zalega | 8c2c771 | 2022-01-25 19:42:21 +0100 | [diff] [blame] | 50 | # Append the objcopy parameter separately, as it's not of File type, and |
| 51 | # it does not constitute an input, since it's part of the toolchain. |
Leopold | bc93c2b | 2023-01-14 13:12:23 +0100 | [diff] [blame] | 52 | objcopy = ctx.toolchains["@bazel_tools//tools/cpp:toolchain_type"].cc.objcopy_executable |
Mateusz Zalega | 8c2c771 | 2022-01-25 19:42:21 +0100 | [diff] [blame] | 53 | args.append("-objcopy={}".format(objcopy)) |
Lorenz Brun | f099c09 | 2022-02-24 17:22:26 +0100 | [diff] [blame] | 54 | |
Mateusz Zalega | 8c2c771 | 2022-01-25 19:42:21 +0100 | [diff] [blame] | 55 | # Run mkpayload. |
Lorenz Brun | 2f9f387 | 2021-09-29 19:48:08 +0200 | [diff] [blame] | 56 | ctx.actions.run( |
Lorenz Brun | f099c09 | 2022-02-24 17:22:26 +0100 | [diff] [blame] | 57 | mnemonic = "GenEFIKernelImage", |
| 58 | progress_message = "Generating EFI unified kernel image", |
| 59 | inputs = inputs, |
| 60 | outputs = [image], |
| 61 | executable = ctx.file._mkpayload, |
| 62 | arguments = args, |
Lorenz Brun | 2f9f387 | 2021-09-29 19:48:08 +0200 | [diff] [blame] | 63 | ) |
Lorenz Brun | f099c09 | 2022-02-24 17:22:26 +0100 | [diff] [blame] | 64 | |
Mateusz Zalega | 8c2c771 | 2022-01-25 19:42:21 +0100 | [diff] [blame] | 65 | # Return the unified kernel image file. |
| 66 | return [DefaultInfo(files = depset([image]), runfiles = ctx.runfiles(files = [image]))] |
Lorenz Brun | 2f9f387 | 2021-09-29 19:48:08 +0200 | [diff] [blame] | 67 | |
| 68 | efi_unified_kernel_image = rule( |
| 69 | implementation = _efi_unified_kernel_image_impl, |
| 70 | attrs = { |
| 71 | "kernel": attr.label( |
| 72 | doc = "The Linux kernel executable bzImage. Needs to have EFI handover and EFI stub enabled.", |
| 73 | mandatory = True, |
| 74 | allow_single_file = True, |
| 75 | ), |
| 76 | "cmdline": attr.string( |
| 77 | doc = "The kernel commandline to be embedded.", |
| 78 | ), |
Lorenz Brun | 304d42c | 2022-02-24 17:53:08 +0100 | [diff] [blame] | 79 | "initrd": attr.label_list( |
| 80 | doc = """ |
| 81 | List of payloads to concatenate and supply as the initrd parameter to Linux when it boots. |
| 82 | The name stems from the time Linux booted from an initial ram disk (initrd), but it's now |
| 83 | a catch-all for a bunch of different larger payload for early Linux initialization. |
| 84 | |
| 85 | In Linux 5.15 this can first contain an arbitrary amount of uncompressed cpio archives |
| 86 | with directories being optional which is accessed by earlycpio. This is used for both |
| 87 | early microcode loading and ACPI table overrides. This can then be followed by an arbitrary |
| 88 | amount of compressed cpio archives (even with different compression methods) which will |
| 89 | together make up the initramfs. The initramfs is only booted into if it contains either |
| 90 | /init or whatever file is specified as init= in cmdline. Technically depending on kernel |
| 91 | flags you might be able to supply an actual initrd, i.e. an image of a disk loaded into |
| 92 | RAM, but that has been deprecated for nearly 2 decades and should really not be used. |
| 93 | |
| 94 | For kernels designed to run on physical machines this should at least contain microcode, |
| 95 | optionally followed by a compressed initramfs. For kernels only used in virtualized |
| 96 | setups the microcode can be left out and if no initramfs is needed this option can |
| 97 | be omitted completely. |
| 98 | """, |
| 99 | allow_files = True, |
Lorenz Brun | 2f9f387 | 2021-09-29 19:48:08 +0200 | [diff] [blame] | 100 | ), |
| 101 | "os_release": attr.label( |
| 102 | doc = """ |
| 103 | The os-release file identifying the operating system. |
| 104 | See https://www.freedesktop.org/software/systemd/man/os-release.html for format. |
| 105 | """, |
| 106 | allow_single_file = True, |
| 107 | ), |
| 108 | "splash": attr.label( |
| 109 | doc = "An image in BMP format which will be displayed as a splash screen until the kernel takes over.", |
| 110 | allow_single_file = True, |
| 111 | ), |
| 112 | "stub": attr.label( |
| 113 | doc = "The stub executable itself as a PE/COFF executable.", |
| 114 | default = "@efistub//:efistub", |
| 115 | allow_single_file = True, |
| 116 | executable = True, |
| 117 | cfg = build_efi_transition, |
| 118 | ), |
Mateusz Zalega | 8c2c771 | 2022-01-25 19:42:21 +0100 | [diff] [blame] | 119 | "verity": attr.label( |
| 120 | doc = "The DeviceMapper Verity rootfs target table.", |
| 121 | allow_single_file = True, |
| 122 | providers = [DefaultInfo, VerityConfig], |
| 123 | ), |
| 124 | "_mkpayload": attr.label( |
| 125 | doc = "The mkpayload executable.", |
| 126 | default = "//metropolis/node/build/mkpayload", |
| 127 | allow_single_file = True, |
| 128 | executable = True, |
| 129 | cfg = "exec", |
| 130 | ), |
Lorenz Brun | 2f9f387 | 2021-09-29 19:48:08 +0200 | [diff] [blame] | 131 | # Allow for transitions to be attached to this rule. |
| 132 | "_whitelist_function_transition": attr.label( |
| 133 | default = "@bazel_tools//tools/whitelists/function_transition_whitelist", |
| 134 | ), |
| 135 | }, |
Leopold | bc93c2b | 2023-01-14 13:12:23 +0100 | [diff] [blame] | 136 | toolchains = [ |
| 137 | "@bazel_tools//tools/cpp:toolchain_type" |
| 138 | ], |
Lorenz Brun | 2f9f387 | 2021-09-29 19:48:08 +0200 | [diff] [blame] | 139 | ) |