| # SPDX-License-Identifier: GPL-2.0-or-later | |
| """Defines helper functions for creating debug and staging build configs.""" | |
| load("@bazel_skylib//lib:paths.bzl", "paths") | |
| load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo") | |
| load("//build/kernel/kleaf:hermetic_tools.bzl", "hermetic_toolchain") | |
| load( | |
| "//build/kernel/kleaf:kernel.bzl", | |
| "kernel_build_config", | |
| "kernel_module", | |
| ) | |
| def _extracted_system_dlkm(ctx): | |
| hermetic_tools = hermetic_toolchain.get(ctx) | |
| inputs = [] | |
| system_dlkm_archive = None | |
| for f in ctx.files.images: | |
| if f.basename == "system_dlkm_staging_archive.tar.gz": | |
| inputs.append(f) | |
| system_dlkm_archive = f | |
| break | |
| outs = [] | |
| for m in ctx.attr.gki_modules: | |
| outs.append(ctx.actions.declare_file(m)) | |
| common_outs = outs[0].dirname | |
| intermediates_dir = paths.join( | |
| ctx.bin_dir.path, | |
| paths.dirname(ctx.build_file_path), | |
| ctx.attr.name + "_intermediates", | |
| ) | |
| command = hermetic_tools.setup | |
| command += """ | |
| # Extract GKI modules | |
| mkdir -p {intermediates_dir} | |
| tar xf {system_dlkm_archive} -C {intermediates_dir} | |
| find {intermediates_dir} -name '*.ko' -exec cp -t {common_outs} {{}} \\+ | |
| # Verify the outputs. We don't care if there are more modules extracted | |
| # than used. For example, we don't use zram.ko. | |
| all_modules=({all_modules}) | |
| for m in "${{all_modules[@]}}"; do | |
| if ! [[ -f "{common_outs}/${{m}}" ]]; then | |
| echo "${{m}} is missing from $(basename {system_dlkm_archive})" >&2 | |
| exit 1 | |
| fi | |
| done | |
| """.format( | |
| all_modules = " ".join([m.basename for m in outs]), | |
| common_outs = common_outs, | |
| system_dlkm_archive = system_dlkm_archive.path, | |
| intermediates_dir = intermediates_dir, | |
| ) | |
| ctx.actions.run_shell( | |
| mnemonic = "ExtractedSystemDlkm", | |
| inputs = inputs, | |
| outputs = outs, | |
| tools = hermetic_tools.deps, | |
| progress_message = "Extracting GKI modules", | |
| command = command, | |
| ) | |
| return [DefaultInfo(files = depset(outs))] | |
| extracted_system_dlkm = rule( | |
| doc = """Extracts the system_dlkm archive so that they can be copied to the dist_dir""", | |
| implementation = _extracted_system_dlkm, | |
| attrs = { | |
| "images": attr.label( | |
| doc = "The kernel_images target that contains the system_dlkm archive.", | |
| allow_files = True, | |
| mandatory = True, | |
| ), | |
| "gki_modules": attr.string_list( | |
| doc = "A list of GKI modules", | |
| allow_empty = False, | |
| mandatory = True, | |
| ), | |
| }, | |
| toolchains = [hermetic_toolchain.type], | |
| ) | |
| def _set_gki_kernel_dir_impl(ctx): | |
| output = ctx.actions.declare_file(ctx.label.name) | |
| output_cmd = "" | |
| if not ctx.attr.device_config_dir: | |
| output_cmd = "KERNEL_DIR={gki_kernel_dir}\n".format( | |
| gki_kernel_dir = str(ctx.attr.gki_kernel_dir[BuildSettingInfo].value), | |
| ) | |
| else: | |
| output_cmd = """ | |
| KERNEL_DIR="{device_config_dir}" | |
| GKI_KERNEL_DIR="{gki_kernel_dir}" | |
| """.format( | |
| device_config_dir = ctx.attr.device_config_dir, | |
| gki_kernel_dir = str(ctx.attr.gki_kernel_dir[BuildSettingInfo].value), | |
| ) | |
| if ctx.file.gki_build_config_fragment: | |
| output_cmd += "GKI_BUILD_CONFIG_FRAGMENT={}\n".format(ctx.file.gki_build_config_fragment.path) | |
| ctx.actions.write( | |
| output = output, | |
| content = output_cmd, | |
| ) | |
| return DefaultInfo(files = depset([output])) | |
| set_gki_kernel_dir = rule( | |
| doc = """Creates a build config fragment file that defines the kernel | |
| directories and GKI_BUILD_CONFIG_FRAGMENT (if set). | |
| """, | |
| implementation = _set_gki_kernel_dir_impl, | |
| attrs = { | |
| "device_config_dir": attr.string( | |
| doc = "path to the device build config", | |
| mandatory = False, | |
| ), | |
| "gki_kernel_dir": attr.label( | |
| doc = "string_flag that contains the path to the GKI kernel source", | |
| mandatory = True, | |
| ), | |
| "gki_build_config_fragment": attr.label( | |
| doc = "file used as the debug build config fragment", | |
| allow_single_file = True, | |
| mandatory = False, | |
| ), | |
| }, | |
| ) | |
| def create_device_build_config(name, base_build_config, device_name, debug_fragment, gki_staging_fragment): | |
| """Generates device and kernel build configs using the build config fragments. | |
| Defines these targets: | |
| - `{name}` | |
| - `{name}.gki` | |
| Args: | |
| name: name of the main `kernel_build_config` target. | |
| base_build_config: the device build config. | |
| device_name: name of the device. | |
| debug_fragment: the GKI_BUILD_CONFIG_FRAGMENT used to enable debug configs. | |
| gki_staging_fragment: the staging kernel's build config fragment which is | |
| concatenated with the base build configs. | |
| """ | |
| set_gki_kernel_dir( | |
| name = "{}.gen".format(name), | |
| device_config_dir = "private/devices/google/{}".format(device_name), | |
| gki_kernel_dir = "//private/google-modules/soc/gs:gki_kernel_dir", | |
| gki_build_config_fragment = debug_fragment, | |
| ) | |
| set_gki_kernel_dir( | |
| name = "{}.gki.gen".format(name), | |
| gki_kernel_dir = "//private/google-modules/soc/gs:gki_kernel_dir", | |
| gki_build_config_fragment = debug_fragment, | |
| ) | |
| kernel_build_config( | |
| name = name, | |
| srcs = [ | |
| # do not sort | |
| ":{}.gen".format(name), | |
| base_build_config, | |
| ] + ([gki_staging_fragment] if gki_staging_fragment else []), | |
| ) | |
| kernel_build_config( | |
| name = "{}.gki".format(name), | |
| srcs = [ | |
| # do not sort | |
| ":{}.gki.gen".format(name), | |
| ] + select({ | |
| "//private/google-modules/soc/gs:gki_aosp": ["//aosp:build.config.gki.aarch64"], | |
| "//private/google-modules/soc/gs:gki_aosp_staging": ["//aosp-staging:build.config.gki.aarch64"], | |
| }) + ([gki_staging_fragment] if gki_staging_fragment else []), | |
| ) | |
| def device_build_configs( | |
| name, | |
| base_build_config, | |
| device_name, | |
| gki_staging_fragment = None): | |
| """Creates the full set of debug configs for a pixel device. | |
| Defines these targets for each debug config: | |
| - `{name}.{debug_name}` | |
| - `{name}.{debug_name}.gki` | |
| Args: | |
| name: name of the base `kernel_build_config` target | |
| base_build_config: the device build config | |
| device_name: name of the device | |
| gki_staging_fragment: the staging kernel's build config fragment | |
| """ | |
| debug_types = [ | |
| "blktest", | |
| "debug_api", | |
| "debug_kmemleak", | |
| "debug_locking", | |
| "debug_memory", | |
| "debug_memory_accounting", | |
| "kasan", | |
| "khwasan", | |
| ] | |
| debug_configs_mapping = {} | |
| debug_gki_configs_mapping = {} | |
| for debug_name in debug_types: | |
| create_device_build_config( | |
| name = "{name}.{debug_name}".format(name = name, debug_name = debug_name), | |
| base_build_config = base_build_config, | |
| device_name = device_name, | |
| debug_fragment = "//private/google-modules/soc/gs:build.config.slider.{}".format(debug_name), | |
| gki_staging_fragment = gki_staging_fragment, | |
| ) | |
| debug_configs_mapping["//private/google-modules/soc/gs:{}".format(debug_name)] = \ | |
| ["//private/devices/google/{device}:{name}.{debug_name}".format( | |
| name = name, | |
| device = device_name, | |
| debug_name = debug_name, | |
| )] | |
| debug_gki_configs_mapping["//private/google-modules/soc/gs:{}".format(debug_name)] = \ | |
| ["//private/devices/google/{device}:{name}.{debug_name}.gki".format( | |
| name = name, | |
| device = device_name, | |
| debug_name = debug_name, | |
| )] | |
| create_device_build_config( | |
| name = "{}_mod".format(name), | |
| base_build_config = base_build_config, | |
| device_name = device_name, | |
| debug_fragment = None, | |
| gki_staging_fragment = gki_staging_fragment, | |
| ) | |
| debug_configs_mapping["//conditions:default"] = \ | |
| [":{name}_mod".format(name = name)] | |
| debug_gki_configs_mapping["//conditions:default"] = \ | |
| [":{name}_mod.gki".format(name = name)] | |
| native.filegroup( | |
| name = "device_build_config", | |
| srcs = select(debug_configs_mapping), | |
| ) | |
| native.filegroup( | |
| name = "gki_build_config", | |
| srcs = select(debug_gki_configs_mapping), | |
| ) | |
| def lto_dependant_kernel_module( | |
| name, | |
| outs, | |
| lto_outs, | |
| srcs = None, | |
| kernel_build = None, | |
| makefile = None, | |
| deps = None, | |
| **kwargs): | |
| """Wrapper over kernel_module to conditionally modify outs when LTO is set differently. | |
| Args: | |
| name: name of the module | |
| outs: See kernel_module.outs | |
| lto_outs: Like outs, but only appended to outs when LTO is not set to none | |
| kernel_build: See kernel_module.kernel_build | |
| makefile: See kernel_module.makefile | |
| deps: See kernel_module.deps | |
| **kwargs: common kwargs for all rules | |
| """ | |
| kwargs_with_private_visibility = dict( | |
| kwargs, | |
| visibility = ["//visibility:private"], | |
| ) | |
| kernel_module( | |
| name = name + "_internal", | |
| srcs = srcs, | |
| outs = outs + lto_outs, | |
| kernel_build = kernel_build, | |
| makefile = makefile, | |
| deps = deps, | |
| **kwargs_with_private_visibility | |
| ) | |
| kernel_module( | |
| name = name + "_lto_none", | |
| srcs = srcs, | |
| outs = outs, | |
| kernel_build = kernel_build, | |
| makefile = makefile, | |
| deps = deps, | |
| **kwargs_with_private_visibility | |
| ) | |
| native.alias( | |
| name = name, | |
| actual = select({ | |
| "//private/google-modules/soc/gs:lto_none": name + "_lto_none", | |
| "//conditions:default": name + "_internal", | |
| }), | |
| **kwargs | |
| ) |