blob: a1d4c3d089275081f19177ebfda22a090962bfd1 [file] [log] [blame]
Serge Bazanskif055a7f2021-04-13 16:22:33 +02001# Copyright 2020 The Monogon Project Authors.
2#
3# SPDX-License-Identifier: Apache-2.0
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17"""
18Rules for building Linux kernel images.
19
20This currently performs the build in a fully unhermetic manner, using
Leopoldbc93c2b2023-01-14 13:12:23 +010021make/gcc/... from the sandbox sysroot, and is only slightly better than a genrule. This
Serge Bazanskif055a7f2021-04-13 16:22:33 +020022should be replaced by a hermetic build that at least uses rules_cc toolchain
23information, or even better, just uses cc_library targets.
24"""
25
Lorenz Brun6df40aa2025-05-22 15:35:44 +020026load("@rules_cc//cc:action_names.bzl", "C_COMPILE_ACTION_NAME")
27load("@rules_cc//cc:find_cc_toolchain.bzl", "CC_TOOLCHAIN_ATTRS", "find_cpp_toolchain", "use_cc_toolchain")
Tim Windelschmidtd4817492025-06-16 15:03:12 +020028load("@rules_cc//cc/common:cc_common.bzl", "cc_common")
Serge Bazanskif055a7f2021-04-13 16:22:33 +020029load("//build/utils:detect_root.bzl", "detect_root")
Tim Windelschmidt08054ca2025-04-04 01:11:56 +020030load("//osbase/build:def.bzl", "ignore_unused_configuration")
Serge Bazanskif055a7f2021-04-13 16:22:33 +020031
Serge Bazanskif9c82492024-09-16 16:50:39 +020032def _linux_image_impl_resources(_os, _ninputs):
33 """
34 Configures linux build resources.
35
36 See `resource_set` documentation in builtins.actions Bazel docs.
37 """
Tim Windelschmidt156248b2025-01-10 00:27:45 +010038
Serge Bazanskif9c82492024-09-16 16:50:39 +020039 # 16 threads seems about right - this fits well in both our build machines and
40 # development machines.
41 cpu = 16
Tim Windelschmidt156248b2025-01-10 00:27:45 +010042
Serge Bazanskif9c82492024-09-16 16:50:39 +020043 # In MB. Picked based on observing build in htop.
44 mb_per_cpu = 256
45 return {
Tim Windelschmidt156248b2025-01-10 00:27:45 +010046 "cpu": cpu,
47 "memory": cpu * mb_per_cpu,
48 "local_test": 0,
Serge Bazanskif9c82492024-09-16 16:50:39 +020049 }
Serge Bazanskif055a7f2021-04-13 16:22:33 +020050
Lorenz Brun6df40aa2025-05-22 15:35:44 +020051DISABLED_FEATURES = []
52
53# NOTE: Multicall tool is called as path/to/llvm clang to workaround bug in out-of-process execution where tool name is repeated and parsing breaks.
54
Serge Bazanskif055a7f2021-04-13 16:22:33 +020055def _linux_image_impl(ctx):
56 kernel_config = ctx.file.kernel_config
57 kernel_src = ctx.files.kernel_src
58 image_format = ctx.attr.image_format
59
Lorenz Brun6df40aa2025-05-22 15:35:44 +020060 # Root of the given Linux sources.
61 root = detect_root(ctx.attr.kernel_src)
62
63 # Figure out target CC toolchain
64 cc_toolchain = find_cpp_toolchain(ctx)
65 feature_configuration = cc_common.configure_features(
66 ctx = ctx,
67 cc_toolchain = cc_toolchain,
68 requested_features = ctx.features,
69 unsupported_features = DISABLED_FEATURES + ctx.disabled_features,
70 )
71 c_compiler_path = cc_common.get_tool_for_action(
72 feature_configuration = feature_configuration,
73 action_name = C_COMPILE_ACTION_NAME,
74 )
75
76 # Figure out Kbuild ARCH option
77 target_arch = None
78 compressed_image_name = None
79
80 if ctx.target_platform_has_constraint(ctx.attr._constraint_x86_64[platform_common.ConstraintValueInfo]):
81 target_arch = "x86"
82 compressed_image_name = "bzImage"
83
84 if ctx.target_platform_has_constraint(ctx.attr._constraint_aarch64[platform_common.ConstraintValueInfo]):
85 target_arch = "arm64"
86 compressed_image_name = "Image"
87
88 if ctx.target_platform_has_constraint(ctx.attr._constraint_riscv64[platform_common.ConstraintValueInfo]):
89 target_arch = "riscv"
90 compressed_image_name = "Image"
91
92 if not target_arch:
93 fail("Target platform does not match expected constraints: @platforms//cpu:x86_64, @platforms//cpu:aarch64, or @platforms//cpu:riscv64.")
94
Serge Bazanskif055a7f2021-04-13 16:22:33 +020095 # Tuple containing information about how to build and access the resulting
96 # image.
97 # The first element (target) is the make target to build, the second
Mateusz Zalega9a66b182021-12-22 20:33:12 +010098 # (image_source) is the resulting file to be copied and the last
99 # (image_name) is the name of the image that will be generated by this
Serge Bazanskif055a7f2021-04-13 16:22:33 +0200100 # rule.
Mateusz Zalega9a66b182021-12-22 20:33:12 +0100101 (target, image_source, image_name) = {
Tim Windelschmidt156248b2025-01-10 00:27:45 +0100102 "vmlinux": ("vmlinux modules", "vmlinux", "vmlinux"),
Lorenz Brun6df40aa2025-05-22 15:35:44 +0200103 "Image": ("all modules", "arch/" + target_arch + "/boot/" + compressed_image_name, "Image"),
Serge Bazanskif055a7f2021-04-13 16:22:33 +0200104 }[image_format]
105
Mateusz Zalega9a66b182021-12-22 20:33:12 +0100106 image = ctx.actions.declare_file(image_name)
107 modinfo = ctx.actions.declare_file("modules.builtin.modinfo")
Lorenz Brun6c454342023-06-01 12:23:38 +0200108 modules = ctx.actions.declare_directory("modules")
Serge Bazanskif055a7f2021-04-13 16:22:33 +0200109 ctx.actions.run_shell(
Tim Windelschmidt156248b2025-01-10 00:27:45 +0100110 outputs = [image, modinfo, modules],
Lorenz Brun6df40aa2025-05-22 15:35:44 +0200111 inputs = depset([kernel_config] + kernel_src, transitive = [cc_toolchain.all_files]),
Serge Bazanskif9c82492024-09-16 16:50:39 +0200112 resource_set = _linux_image_impl_resources,
Serge Bazanskif055a7f2021-04-13 16:22:33 +0200113 command = '''
114 kconfig=$1
115 target=$2
Mateusz Zalega9a66b182021-12-22 20:33:12 +0100116 image_source=$3
117 image=$4
Serge Bazanskif055a7f2021-04-13 16:22:33 +0200118 root=$5
Mateusz Zalega9a66b182021-12-22 20:33:12 +0100119 modinfo=$6
Lorenz Brun6c454342023-06-01 12:23:38 +0200120 modules=$7
Lorenz Brun6df40aa2025-05-22 15:35:44 +0200121 arch=$8
122 cc=$PWD/$9
Lorenz Brun6c454342023-06-01 12:23:38 +0200123
124 builddir=$(mktemp -d)
Serge Bazanskif055a7f2021-04-13 16:22:33 +0200125
126 mkdir ${root}/.bin
Lorenz Brun6c454342023-06-01 12:23:38 +0200127 cp ${kconfig} ${builddir}/.config
Lorenz Brun6df40aa2025-05-22 15:35:44 +0200128 (cd ${root} && make -j 16 KBUILD_OUTPUT="${builddir}" ARCH="${arch}" CC="${cc//clang/llvm} clang" LD="${cc//clang/ld.lld}" OBJCOPY="${cc//clang/llvm-objcopy}" OBJDUMP="${cc//clang/llvm-objdump}" AR="${cc//clang/llvm-ar}" NM="${cc//clang/llvm-nm}" STRIP="${cc//clang/llvm-strip}" READELF="${cc//clang/llvm-readelf}" olddefconfig ${target} >/dev/null)
Lorenz Brun6c454342023-06-01 12:23:38 +0200129 cp "${builddir}"/${image_source} ${image}
130 cp "${builddir}"/modules.builtin.modinfo ${modinfo}
131 # Not using modules_install as it tries to run depmod and friends
132 for f in $(find "${builddir}" -name '*.ko' -type f -printf "%P\n" ); do
133 install -D "${builddir}/$f" "${modules}/$f"
134 done
135 rm -Rf "$builddir"
Serge Bazanskif055a7f2021-04-13 16:22:33 +0200136 ''',
137 arguments = [
138 kernel_config.path,
139 target,
Mateusz Zalega9a66b182021-12-22 20:33:12 +0100140 image_source,
141 image.path,
Serge Bazanskif055a7f2021-04-13 16:22:33 +0200142 root,
Lorenz Brun6c454342023-06-01 12:23:38 +0200143 modinfo.path,
144 modules.path,
Lorenz Brun6df40aa2025-05-22 15:35:44 +0200145 target_arch,
146 c_compiler_path,
Serge Bazanskif055a7f2021-04-13 16:22:33 +0200147 ],
148 use_default_shell_env = True,
149 )
150
Mateusz Zalega9a66b182021-12-22 20:33:12 +0100151 return [
Tim Windelschmidt156248b2025-01-10 00:27:45 +0100152 DefaultInfo(
153 files = depset([image]),
154 runfiles = ctx.runfiles(files = [image]),
155 ),
156 OutputGroupInfo(
157 modinfo = depset([modinfo]),
158 modules = depset([modules]),
159 ),
Mateusz Zalega9a66b182021-12-22 20:33:12 +0100160 ]
Serge Bazanskif055a7f2021-04-13 16:22:33 +0200161
162linux_image = rule(
Tim Windelschmidt156248b2025-01-10 00:27:45 +0100163 doc = """
Serge Bazanskif055a7f2021-04-13 16:22:33 +0200164 Build Linux kernel image unhermetically in a given format.
Tim Windelschmidt156248b2025-01-10 00:27:45 +0100165 """,
Serge Bazanskif055a7f2021-04-13 16:22:33 +0200166 implementation = _linux_image_impl,
167 cfg = ignore_unused_configuration,
168 attrs = {
169 "kernel_config": attr.label(
Tim Windelschmidt156248b2025-01-10 00:27:45 +0100170 doc = """
Serge Bazanskif055a7f2021-04-13 16:22:33 +0200171 Linux kernel configuration file to build this kernel image with.
Tim Windelschmidt156248b2025-01-10 00:27:45 +0100172 """,
Serge Bazanskif055a7f2021-04-13 16:22:33 +0200173 allow_single_file = True,
Serge Bazanskif055a7f2021-04-13 16:22:33 +0200174 ),
175 "kernel_src": attr.label(
Tim Windelschmidt156248b2025-01-10 00:27:45 +0100176 doc = """
Serge Bazanskif055a7f2021-04-13 16:22:33 +0200177 Filegroup containing Linux kernel sources.
Tim Windelschmidt156248b2025-01-10 00:27:45 +0100178 """,
Serge Bazanskif055a7f2021-04-13 16:22:33 +0200179 default = "@linux//:all",
180 ),
181 "image_format": attr.string(
Tim Windelschmidt156248b2025-01-10 00:27:45 +0100182 doc = """
Lorenz Brun6df40aa2025-05-22 15:35:44 +0200183 Format of generated Linux image, one of 'vmlinux' or 'Image',
Tim Windelschmidt156248b2025-01-10 00:27:45 +0100184 """,
Serge Bazanskif055a7f2021-04-13 16:22:33 +0200185 values = [
Tim Windelschmidt156248b2025-01-10 00:27:45 +0100186 "vmlinux",
Lorenz Brun6df40aa2025-05-22 15:35:44 +0200187 "Image",
Serge Bazanskif055a7f2021-04-13 16:22:33 +0200188 ],
Lorenz Brun6df40aa2025-05-22 15:35:44 +0200189 default = "Image",
Serge Bazanskif055a7f2021-04-13 16:22:33 +0200190 ),
191 "_allowlist_function_transition": attr.label(
Tim Windelschmidt156248b2025-01-10 00:27:45 +0100192 default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
Serge Bazanskif055a7f2021-04-13 16:22:33 +0200193 ),
Lorenz Brun6df40aa2025-05-22 15:35:44 +0200194 # Bazel doesn't let you access the target platform directly, use these
195 "_constraint_x86_64": attr.label(
196 default = "@platforms//cpu:x86_64",
197 ),
198 "_constraint_aarch64": attr.label(
199 default = "@platforms//cpu:aarch64",
200 ),
201 "_constraint_riscv64": attr.label(
202 default = "@platforms//cpu:riscv64",
203 ),
204 } | CC_TOOLCHAIN_ATTRS,
205 toolchains = use_cc_toolchain(),
206 fragments = ["cpp"],
Serge Bazanskif055a7f2021-04-13 16:22:33 +0200207)