feat(build): Kconfig-based build configuration - #397
Draft
josecm wants to merge 9 commits into
Draft
Conversation
A goal named config or any other substring of a non-build target name would be silently classified as one, skipping the platform and configuration checks. Co-authored-by: Diogo Costa <diogoandreveigacosta@gmail.com> Signed-off-by: Jose Martins <josemartins90@gmail.com>
Each build instance carries its own .config, seeded by layering the platform defconfig and the VM config folder defconfig over Kconfig defaults, and synced by scripts/kconfig.py (kconfiglib) into a make fragment and a C header force-included in every compilation unit. menuconfig and listconfig operate per build instance and configuration options cannot be set on the command line. Signed-off-by: Jose Martins <josemartins90@gmail.com>
Signed-off-by: Jose Martins <josemartins90@gmail.com>
Signed-off-by: Jose Martins <josemartins90@gmail.com>
Signed-off-by: Jose Martins <josemartins90@gmail.com>
Signed-off-by: Jose Martins <josemartins90@gmail.com>
PLATFORM= and CONFIG= on the command line keep selecting the classic per-target build exactly as before, and the new classic defconfig target seeds its .config without building. Everything else operates on an output directory: explicit O=, or by default build/ with binaries in bin/. Output directories carry their own .config, seeded through the per-platform <platform>_defconfig targets, and the build takes the platform and the VM configuration (the new CONFIG_SRC option) from it. Mixing the two workflows in one invocation is rejected. make clean on the default output erases build/ and bin/ wholesale; an explicit O= directory only ever has its contents removed.
A classic PLATFORM=/CONFIG= seed writes a .pin Kconfig fragment into the build directory fixing both from that point on: the CONFIG_SRC option loses its prompt and takes the pinned value, the platform choice refuses changes in menuconfig, and out-of-band edits to either are rejected when the configuration is next resolved. Defconfig-seeded output directories stay unpinned, and reseeding replaces any pins.
CONFIG_REPO joins CONFIG_SRC in Kconfig, empty meaning the in-tree configs folder, and CONFIG_SRC accepts a configuration name resolved in that repository, a configuration folder, or a config.c path. Seeding records the name as given (plus the repository when explicit) instead of a resolved absolute path, keeping .config files portable; the config pin covers both values. Signed-off-by: Jose Martins <josemartins90@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR introduces a Kconfig-based configuration system for bao's build. It replaces scattered make variables and command-line
-Dmacros with a structured, validated configuration tree, while keeping the familiarmake PLATFORM=<plat> CONFIG=<config>entry point unchanged.How options split between config.c and Kconfig
The guiding rule is that Kconfig enables, config.c parameterizes. Kconfig decides what the hypervisor build contains: which features are compiled in at all, the platform identity and its hardware facts, and build tunables. config.c then parameterizes the features that are present, per VM or for the hypervisor itself: which VMs run, their images, memory regions, and device assignments, and each enabled feature's per-deployment settings. Cache coloring illustrates the split: it will become a Kconfig feature in a follow-up, meaning the coloring code is not compiled in when disabled; when enabled, the color assignments themselves stay exactly where they are today, per VM and for the hypervisor in config.c.
The two sides are deliberately coupled at compile time. When a feature is disabled in Kconfig, its fields are removed from the configuration structures rather than silently ignored, so a config.c that sets parameters for a disabled feature fails to build with a compiler error pointing at the offending line. This rule takes effect as features gain gating (see the follow-ups below).
Kconfig symbols fall into three groups:
IPCorIPI_MAX_EVENTS, including platform properties a platform may default but allow the user to override, such asMEM_NON_UNIFIED.ARCH,ARCH_SUB,ARCH_PROFILE, CPU count, GIC version,IRQC/IPIC, the memory protection model). They are visible in menuconfig for inspection but not editable, and a defconfig that tries to override one fails the configuration step. Where a platform genuinely offers a hardware choice the fact becomes a real choice: qemu riscv virt can select PLIC, APLIC, or AIA and the matching IPI mechanism.PLAT_HAS_*symbols that gate which user options are even offered, e.g. MMIO slave-side protection is only offered on platforms that declare support for it.Infrastructure
src/Kconfigsources the architecture trees (src/arch/*/Kconfig) and the platform registry (src/platform/Kconfig). Each platform contributes its identity and selects (Kconfig.plat) plus its fact defaults (Kconfig)..configlives per build instance atbuild/<plat>/<config>/.config, so different platform/config pairs never fight over a shared file.src/platform/<plat>/defconfig, when present), then an optional defconfig next to the VM configuration (configs/<config>/defconfig), then Kconfig defaults.PLATFORM=pins the platform choice.auto.conf, included by make and used to gate objects (core-objs-$(CONFIG_X)+=...), andautoconf.h, force-included into every compilation unit so code seesCONFIG_*macros without explicit includes.make PLATFORM=<plat> CONFIG=<config> menuconfigedits the build's configuration interactively;listconfigprints every option with its value and which layer decided it (default, platform, config, or modified by the user), plus the fixed facts.CONFIG_*variables cannot be overridden on the make command line; defconfigs and menuconfig are the only configuration inputs.The engine is kconfiglib driven by
scripts/kconfig.py, so configuring a build requires python3 with kconfiglib available; all constraints that the build itself depends on remain enforced in the Makefiles.Using it
Nothing changes for the common case:
make PLATFORM=<plat> CONFIG=<config>(optionally withCONFIG_REPO=for an external configuration repository) builds as before. The first build seeds the configuration automatically; later builds reuse it, and any change to.configregeneratesauto.conf/autoconf.hand rebuilds what depends on them.Kernel-style output directories are supported as an alternative workflow.
make O=<dir> <platform>_defconfigseeds<dir>/.configfor that platform, and passingCONFIG=to the defconfig target records the VM configuration source in theCONFIG_SRCoption. From then onmake O=<dir>alone builds there, taking both the platform and the VM configuration from the.config;O=is passed on each invocation (export it in the environment for stickiness). On a build,CONFIG=overrides the configured source for that invocation only, without touching the.config(each configuration keeps its own object tree inside the directory), whilePLATFORM=seeds an empty directory directly or must match the directory's configured platform.menuconfigandlistconfigtakeO=the same way, andmake O=<dir> menuconfigon an empty directory opens the full tree starting from defaults, platform choice included.cleanempties the directory but keeps its.config;distcleanerases the configuration as well.A configured build directory is pinned to its platform and VM configuration: seeding drops a small generated Kconfig fragment (
.pin) into it, after which the platform choice refuses changes in menuconfig,CONFIG_SRCloses its prompt and shows as a fixed value, and out-of-band edits to either are rejected the next time the configuration is resolved.CONFIG=remains the sanctioned per-invocation override, and reseeding through a<platform>_defconfigtarget (or deleting the fragment) replaces the pin.To inspect or change a build's configuration:
make PLATFORM=<plat> CONFIG=<config> menuconfigopens the interactive frontend on that build's.config(seeding it first if it does not exist yet).make PLATFORM=<plat> CONFIG=<config> listconfigprints every option with its type, value, default, and the layer that decided it, plus the platform-fixed facts..config); the next build reseeds from the defconfig layers.Where each piece is defined:
src/Kconfig: the root, sourcing the architecture, platform, and core trees.src/core/Kconfig: core feature options and tunables (IPC,MMIO_SLAVE_SIDE_PROT,IPI_MAX_EVENTS).src/arch/Kconfigandsrc/arch/<arch>/Kconfig: architecture selection and the architecture-owned facts (ARCH,ARCH_SUB,ARCH_PROFILE, memory protection model,CPU/GIC_VERSIONon armv8,IRQC/IPICon riscv).src/platform/Kconfig: the platform registry, declaring the platform choice and the platform-wide symbols (PLATFORM,MEM_NON_UNIFIED,PLAT_HAS_*).src/platform/<plat>/Kconfig.plat: the platform's entry in the platform choice and itsselects (Kconfig grammar requires choice entries in a separate file).src/platform/<plat>/Kconfig: the platform's fact values, given as defaults conditioned on the platform symbol, and its hardware choices where they exist (the qemu riscv interrupt controller selection above).src/platform/<plat>/defconfig: the platform's optional defconfig. A platform can ship one to preset any user-visible option for builds targeting it: default a feature off because it makes no sense on that hardware, preset a tunable to a value that fits its memory budget, or pick one side of a hardware choice as the recommended one. It is the base seeding layer, so everything it sets remains a user decision that a config defconfig or menuconfig can override, which is exactly what distinguishes it from a Kconfig fact: facts are fixed by the platform selection and cannot be touched, while platform defconfig entries are just that platform's starting point.listconfigattributes such values to the platform layer. No platform ships one in this PR because every current platform default is expressible as a Kconfig default, but the mechanism is in place.configs/<config>/defconfig: an optional defconfig next to the VM configuration'sconfig.c, for options a given deployment wants pinned (folder configurations only; single-file<config>.cconfigurations have no defconfig layer).build/<plat>/<config>/.config: the resolved working configuration of that build instance, plus the generatedauto.confandautoconf.hunderbuild/<plat>/<config>/config/.The layers superimpose in a fixed order at seeding time: the platform defconfig is applied first, the config-folder defconfig is applied on top of it and may override it, and every symbol neither mentions takes its Kconfig default (which the platform selection already specializes). The platform itself is always pinned by
PLATFORM=and cannot be changed by a defconfig. After seeding, the build's.configis authoritative: menuconfig edits land there, andlistconfigreports such values as modified. If a seed defconfig changes after a build was configured, the build warns that the defconfig is newer but never silently reseeds; removing the.configadopts the new defconfig.What is configurable in this PR, and what comes next
This PR moves the existing platform and architecture build facts into Kconfig (memory protection model, non-unified memory, physical interrupt handling, interrupt controller selection) and introduces the first core feature options:
MMIO_SLAVE_SIDE_PROT(bridged to the existingDEFINED()-based gating),IPI_MAX_EVENTS(now sizing the cpu message queue directly, replacing the-Doverride), andIPC, whose code gating lands in a follow-up.Two follow-ups are already prepared on branches stacked on this one, each to become its own PR:
CONFIG_REMIO): compiles remio fully out when disabled, including the hypercall dispatch, the VM init hooks, and the remio fields of the configuration structures.CONFIG_MEM_COLORING): MMU-only option that compiles the coloring module out and strips color fields and arguments from disabled builds, moving all coloring logic behind a singlecoloring.hboundary header.An open question for reviewers: which other build-time knobs should move into Kconfig? Existing
-Dmacros, debug and logging options, and per-architecture features are all candidates; input on what is missing from this first set is welcome.