blob: 69221883f878f2b4296fc4ce68245dca47bc837d [file] [edit]
# Copyright 2026 The Fuchsia Authors
#
# Use of this source code is governed by a MIT-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/MIT
import("//build/config/clang/clang_prefix.gni")
import("//build/config/compiler_config.gni")
import("//build/config/current_target_tuple.gni")
import("//build/config/linker.gni")
import("//build/rust/config.gni")
import("//build/toolchain/rbe.gni")
import("//build/toolchain/variant.gni")
import("//build/toolchain/zircon/gcc.gni")
import("//build/zircon/zircon_cpu.gni")
import("//zircon/kernel/params.gni")
assert(
is_kernel,
"kernel switches should only be evaluated by kernel switchsets, not $current_toolchain")
declare_args() {
# Enable stacktrace and statistics aggregation for each malloc and free.
# `/boot/kernel/i/memory-profile/d/heap.bin` contains the binary data.
# Use `ffx profile heapdump snapshot --kernel` to produce a symbolized
# memory profile.
kernel_memory_profiler = false
}
# For any standalone static binary.
compiler_config("standalone") {
compiler_configs = [ ":static-pic-link" ]
if (toolchain_environment == "kernel") {
rust_target_edits = [
{
key = "pre-link-objects"
action = "unset"
},
]
if (linker == "lld") {
rust_linker = "$rebased_clang_prefix/lld"
rust_linker_flavor = "gnu-lld"
} else {
assert(linker == "")
rust_linker =
rebase_path("$gcc_tool_dir/$clang_cpu-elf-ld", root_build_dir)
rust_linker_flavor = "gnu"
pre_link_edits = []
post_link_edits = []
foreach(flavor,
[
"gnu",
"gnu-lld",
]) {
pre_link_edits += [
{
key = flavor
action = "erase"
value = [
"-z",
"rodynamic",
]
},
{
key = flavor
action = "erase"
value = [
"-z",
"separate-loadable-segments",
]
},
{
key = flavor
action = "erase"
value = [
"-z",
"rel",
]
},
{
key = flavor
action = "erase"
value = [ "--pack-dyn-relocs=relr" ]
},
{
key = flavor
action = "extend"
value = [
"-z",
"pack-relative-relocs",
]
},
{
key = flavor
action = "extend"
value = [ "--start-group" ]
},
]
if (is_gcc && current_cpu == "arm64") {
pre_link_edits += [
{
key = flavor
action = "erase"
value = [ "--execute-only" ]
},
{
key = flavor
action = "erase"
value = [
"-z",
"--fix-cortex-a53-843419",
]
},
]
}
post_link_edits += [
{
key = flavor
action = "set"
value = [ "--end-group" ]
},
]
}
rust_target_edits += [
{
key = "pre-link-args"
action = "edit"
value = pre_link_edits
},
{
key = "post-link-args"
action = "edit"
value = post_link_edits
},
]
}
if (rust_rbe_enable) {
rustflags = [ "--remote-inputs=$rust_linker" ]
}
rust_target_edits += [
{
key = "linker"
action = "set"
value = rust_linker
},
{
key = "linker-flavor"
action = "set"
value = rust_linker_flavor
},
]
}
c_family_flags = [ "-ffreestanding" ]
configs = [
"//build/config:no_exceptions",
":debug-only-unwind-tables",
":kernel-heap-alignment",
]
}
# These flags say that all function and variable references will be statically
# resolved at link time, so PIC generation will never use GOT indirection.
compiler_config("static-pic-link") {
ldflags = [
"-nostdlib",
"-static",
]
inputs = [ "//zircon/kernel/include/hidden.h" ]
cflags = [
"-include",
rebase_path(inputs[0], root_build_dir),
]
if (is_gcc && current_os == "fuchsia") {
c_family_flags = [ "-fpie" ]
}
rustflags = []
if (toolchain_environment == "kernel") {
rust_target_edits = [
{
key = "no-default-libraries"
action = "set"
value = true
},
{
key = "direct-access-external-data"
action = "set"
value = true
},
{
key = "default-visibility"
action = "set"
value = "hidden"
},
{
key = "relocation-model"
action = "set"
value = "pie"
},
]
} else {
rustflags += [
# TODO(https://fxbug.dev/532132064): Set the relocation-model=pie for
# Rust, as without this setting the Rust core library will not build
# correctly w/ direct-access-external-data, whenever ThinLTO is used,
# thus resulting in unnecessary GOT slots. Note that due to
# `codegen-units > 1`, crates may be split and ThinLTO'd together back
# together, even in non-LTO enabled builds. Note that this option is also
# in the rust_target_edits above, and these should be added or removed
# together.
"-Crelocation-model=pie",
"-Cdefault-linker-libraries=no",
"-Zdefault-visibility=hidden",
"-Zdirect-access-external-data=yes",
]
}
}
# These flags say that we want complete DWARF CFI at every instruction in
# .debug_frame, but never any .eh_frame data.
config("debug-only-unwind-tables") {
# We want `.debug_frame` for the kernel (https://fxbug.dev/42104841). And we
# still want asynchronous unwind tables. Alas there's (currently) no way to
# achieve this with our GCC. At the moment we compile with
# `-fno-omit-frame-pointer`, which is good because we link with
# `--gc-sections`, which means `.eh_frame` gets discarded so GCC-built
# kernels don't have any unwind info (except for assembly)!
cflags = [ "-fno-unwind-tables" ]
# Always feed assembler code the `.cfi_sections` directive to
# populate only `.debug_frame` and not `.eh_frame`.
asmflags = [
"-include",
rebase_path("//zircon/kernel/debug-frame.S", root_build_dir),
]
rustflags = [ "-Cforce-unwind-tables=no" ]
}
# These flags say that the standard ABIs for heap allocation generated by the
# compiler should be understood to provide only 8-byte alignment for the
# allocation signatures that don't request a specific minimum alignment.
#
# TODO(https://fxbug.dev/507570739): In Rust this may be plumbed somehow in
# source code providing default allocator traits, but the details need to be
# figured out.
config("kernel-heap-alignment") {
cflags_cc = [
# Underlying kernel heap only has default alignment of 8 bytes, so pass
# this to the compiler as the default new alignment.
"-faligned-new=8",
]
}
config("headers") {
include_dirs = [
"//zircon/kernel/include",
"//zircon/kernel/lib/libc/include",
]
# This is in public_configs of libc:headers, so we need it explicitly here
# to match up with the include_dirs here that replicates what a proper dep
# on libc:headers would yield.
configs = [ "//zircon/kernel/lib/libc:headers.after" ]
}
# These are needed both in kernel sources (pervasively) and in the linker
# scripts.
kernel_defines = [ "SMP_MAX_CPUS=$smp_max_cpus" ]
config("instrumented-stack-size") {
# Note: Using this extra variable to capture whether the stack size should be
# increased or not, is due to GN's limitation on treating unevaluated parts of
# an expression as unused (e.g. a || b, would flag `b` as unused if `a` is
# true).
increase_stack_size = false
# Lockdep enabled.
if (enable_lock_dep || enable_lock_dep_metadata_only ||
scheduler_lock_spin_tracing_enabled || lock_name_tracing_enabled) {
increase_stack_size = true
}
# Variant considered instrumentation.
if (toolchain_variant.tags + [ "instrumented" ] - [ "instrumented" ] !=
toolchain_variant.tags) {
increase_stack_size = true
}
if (increase_stack_size) {
defines = [ "CUSTOM_DEFAULT_STACK_SIZE=16384" ]
}
}
# This is the "top" compiler_config(). Its $compiler_configs must reach all
# other compiler_config()s that could be reached in any way as normal config()s
# in this toolchain. It's paired with //zircon/kernel/lib/rust:kernel-target
# to roll up the compiler_config() instructions for the custom Rust target.
compiler_config("abi") {
compiler_configs = [
"//zircon/kernel/arch/$zircon_cpu:abi",
":standalone",
]
}
# These are referenced because :abi is listed in the toolchain definition.
group("abi_deps") {
}
group("abi_executable_deps") {
}
group("abi_link_deps") {
}
group("abi_source_deps") {
}
# This is the top config for all kernel code (after :abi).
variant("kernel_config") {
configs = [
":jtrace_config",
":lock_dep",
":scheduler",
":persistent_ram_config",
":kernel_memory_profiler",
":warnings",
"//zircon/kernel/arch/$zircon_cpu:kernel",
"//build/config:no-finite-loops",
"//build/config:zero-call-used-regs",
# include/lib/counters.h and kernel.ld depend on -fdata-sections.
"//build/config/zircon:data_sections",
# Provides checks for maximum supported kernel sizes.
":kernel_image_max_size",
# Overrides default stack size for instrumented builds.
":instrumented-stack-size",
]
# TODO(https://fxbug.dev/42101573): This dependency is conditional because when built
# with GCC the kernel uses function scoped statics requiring dynamic
# initialization. Once https://fxbug.dev/42101573 is fixed, this dependency can be
# removed.
if (is_gcc) {
# Don't emit extra code making static initializers thread-safe.
configs += [ "//build/config/zircon:no_threadsafe_statics" ]
}
# Always enable frame pointers in the kernel so there are panic
# backtraces and such.
# TODO(mcgrathr): Consider either removing this so there's a
# no-frame-pointers option, or removing the kernel's support for
# !WITH_FRAME_POINTERS if it will never be used.
configs += [ "//build/config:frame_pointers" ]
defines = kernel_defines + kernel_extra_defines
defines += [
"_KERNEL",
"LK",
"ZIRCON_TOOLCHAIN",
"DEBUG_PRINT_LEVEL=$kernel_debug_print_level",
"VM_TRACING_LEVEL=$vm_tracing_level",
"FUTEX_BLOCK_TRACING_ENABLED=$futex_block_tracing_enabled",
"LOCK_NAME_TRACING_ENABLED=$lock_name_tracing_enabled",
"EXPERIMENTAL_THREAD_SAMPLER_ENABLED=$experimental_thread_sampler_enabled",
"EXPERIMENTAL_CHANNEL_CALL_PROPAGATION_ENABLED=$experimental_channel_call_propagation_enabled",
"EXPERIMENTAL_FORCE_NEW_WAKEUP_ACCOUNTING=$experimental_force_enable_new_wakeup_accounting",
"EXPERIMENTAL_CONTINUOUS_PER_VMO_ATTRIBUTION_ENABLED=$experimental_continuous_per_vmo_attribution_enabled",
"CHANNEL_MESSAGE_BODY_TRACING_ENABLED=$channel_message_body_tracing_enabled",
]
if (kernel_no_userabi) {
defines += [ "KERNEL_NO_USERABI" ]
}
}
# Each switchset is expected to include one of these.
foreach(level,
[
0,
1,
2,
]) {
variant("lk_debug_level_${level}") {
defines = [ "LK_DEBUGLEVEL=$level" ]
rustflags = [ "--cfg=lk_debuglevel=\"${level}\"" ]
if (level > 0) {
rustflags += [ "--cfg=console_enabled" ]
}
}
}
config("warnings") {
cflags = [
"-Wformat=2",
"-Wmissing-declarations",
"-Wvla",
]
# GCC supports `-Wformat-signedness` but Clang currently does not.
if (is_gcc) {
cflags += [ "-Wformat-signedness" ]
}
# TODO(https://fxbug.dev/42159114): Eventually enable -Wshadow for GCC. It's currently
# disabled because GCC is more aggressive than Clang.
if (!is_gcc) {
cflags += [ "-Wshadow" ]
}
cflags_c = [ "-Wmissing-prototypes" ]
}
config("lock_dep") {
visibility = [ ":*" ]
defines = []
if (enable_lock_dep) {
defines += [
"WITH_LOCK_DEP=1",
"LOCK_DEP_ENABLED_FEATURE_LEVEL=2",
]
} else if (enable_lock_dep_metadata_only ||
scheduler_lock_spin_tracing_enabled || lock_name_tracing_enabled) {
defines += [
"WITH_LOCK_DEP=1",
"LOCK_DEP_ENABLED_FEATURE_LEVEL=1",
]
}
if (enable_lock_dep_tests) {
defines += [ "WITH_LOCK_DEP_TESTS=1" ]
}
}
config("scheduler") {
visibility = [ ":*" ]
defines = [
"SCHEDULER_TRACING_LEVEL=$scheduler_tracing_level",
"SCHEDULER_QUEUE_TRACING_ENABLED=$scheduler_queue_tracing_enabled",
"SCHEDULER_EXTRA_INVARIANT_VALIDATION=$scheduler_extra_invariant_validation",
"SCHEDULER_LOCK_SPIN_TRACING_COMPRESSED=$scheduler_lock_spin_tracing_compressed",
"SCHEDULER_LOCK_SPIN_TRACING_ENABLED=$scheduler_lock_spin_tracing_enabled",
"WAIT_QUEUE_DEPTH_TRACING_ENABLED=$wait_queue_depth_tracing_enabled",
]
}
config("persistent_ram_config") {
visibility = [ ":*" ]
defines = [ "PERSISTENT_RAM_ALLOCATION_GRANULARITY=$persistent_ram_allocation_granularity" ]
}
# In architectures where it is necessary, determined the number of boot pages to
# be preallocated from BSS to map the kernel in the higher address space for
# enabling the MMU when booting. See `start.S` of the relevant architectures for
# more information.
config("kernel_image_max_size") {
if (target_cpu == "arm64" || target_cpu == "riscv64") {
if (toolchain_variant.tags + [ "coverage" ] - [ "coverage" ] !=
toolchain_variant.tags) {
# 25 MB upperbound for coverage builds.
kernel_image_max_size = 26214400
} else {
# 14 MB upperbound for non coverage builds.
kernel_image_max_size = 14680064
}
} else if (target_cpu == "x64") {
# x64 hard coded to support up to 64 MB.
kernel_image_max_size = 67108864
}
visibility = [
":*",
"//zircon/kernel/phys:*",
]
defines = [ "KERNEL_IMAGE_MAX_SIZE=$kernel_image_max_size" ]
}
config("kernel_memory_profiler") {
visibility = [ ":*" ]
defines = [ "KERNEL_MEMORY_PROFILER=$kernel_memory_profiler" ]
}
config("jtrace_config") {
visibility = [ ":*" ]
if (jtrace_enabled == false) {
defines = [ "JTRACE_TARGET_BUFFER_SIZE=0" ]
} else {
if (jtrace_target_buffer_size == "auto") {
if (jtrace_enabled == "persistent") {
jtrace_target_buffer_size = 4096
} else {
jtrace_target_buffer_size = 32768
}
}
if (jtrace_use_large_entries == "auto") {
if (jtrace_enabled == "persistent") {
jtrace_use_large_entries = false
} else {
jtrace_use_large_entries = true
}
}
defines = [
"JTRACE_TARGET_BUFFER_SIZE=$jtrace_target_buffer_size",
"JTRACE_LAST_ENTRY_STORAGE=$jtrace_last_entry_storage",
"JTRACE_USE_LARGE_ENTRIES=$jtrace_use_large_entries",
"JTRACE_USE_MONO_TIMESTAMPS=$jtrace_use_mono_timestamps",
]
if (jtrace_enabled == "persistent") {
defines += [ "JTRACE_IS_PERSISTENT=true" ]
} else {
defines += [ "JTRACE_IS_PERSISTENT=false" ]
}
}
}
# See kernel.ld where KERNEL_GOT_TOLERANCE is used.
if (current_cpu == "arm64" && is_gcc) {
# Each slot is 8 bytes. The first two special slots are always there if
# .got is there at all, per psABI. GNU (BFD) ld seems to emit two more
# unused slots with no associated relocs to explain their existence.
got_tolerance = 32
} else {
got_tolerance = 0
}
# This is implicitly added last to configs in kernel_executable().
compiler_config("kernel_executable.config") {
visibility = [ "//zircon/kernel/bin/*" ]
inputs = [ "//zircon/kernel/kernel.ld" ]
linker_flags = [ "-T" + rebase_path(inputs[0], root_build_dir) ]
# TODO(https://fxbug.dev/379891035): There is still kASan-related start.S
# bootstrap logic for x86 not yet moved into physboot.
if (current_cpu != "x64") {
# PhysbootHandoff is the entrypoint symbol.
linker_flags += [ "--defsym=PhysbootHandoff=lk_main" ]
}
assignments = kernel_defines + [
"KERNEL_GOT_TOLERANCE=$got_tolerance",
# This symbol is used by gdb python to know the base of the
# kernel module
#
# TODO(https://fxbug.dev/42164859): This is now identically
# zero; investigate its need.
"KERNEL_BASE_ADDRESS=0",
]
foreach(assignment, assignments) {
linker_flags += [ "-defsym=$assignment" ]
}
configs = [
"//build/config/zircon:static-pie-compile",
"//build/config/zircon:static-pie-link",
]
}
# Enables unit tests in both the C++ and Rust parts of the kernel.
variant("unit-tests-enabled") {
defines = [ "UNITTESTS_ENABLED" ]
rustflags = [
"--cfg",
"ktest",
]
}