Conversation
There was a problem hiding this comment.
This is working as intended for me, but there are a few issues:
After editing .config (which is what menuconfig does), make O=dir prints "Compiling generator .../config//config_defs_gen" followed by "undefined reference to config" from the host linker. The build then restarts and finishes correctly, so exit status is 0, but the output looks broken.
The CONFIG_SRC help in src/Kconfig:13 and the pinned-configuration error at scripts/kconfig.py:139 both say to "pass CONFIG= to override it for a build", but CONFIG= combined with O= is an explicit error and CONFIG= alone switches to the classic build. The comment at Makefile:213 says CONFIG= "additionally records the VM configuration source" for a defconfig target, but that combination is also rejected.
The RISC-V IRQC choice offers AIA and PLIC only. arch.mk and the CI matrix also support APLIC.
IPC options although present does not affect the compiled code.
Regarding the git history, I'd probably squash 6318f37 9ef0b65 22a33ec and 7297bb0
I also would squash 15f2954, 15f2954 and 0aeabb1 with 7cbb295
Also the CI should be updated with the Kconfig lib before this accepted
edit: I've added it here bao-project/bao-ci#95
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>
Signed-off-by: Jose Martins <josemartins90@gmail.com>
Each build 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. Configuration options cannot be set on the command line; menuconfig and listconfig edit and inspect a build's configuration. PLATFORM= and CONFIG= on the command line keep selecting the classic per-target build exactly as before, and the classic defconfig target seeds its .config without building. A classic build directory is pinned to its platform and configuration through a generated Kconfig fragment, so menuconfig cannot switch them and out-of-band edits are rejected. Everything else operates on a kernel-style output directory: explicit O=, or by default build/ with binaries in bin/. Output directories are seeded, unpinned, through the per-platform <platform>_defconfig targets, and take the platform and the VM configuration from their .config. The CONFIG_SRC option names the VM configuration (a name looked up in the CONFIG_REPO repository, empty meaning the in-tree configs folder, a configuration folder, or a config.c path). Mixing the two workflows in one invocation is rejected. Signed-off-by: Jose Martins <josemartins90@gmail.com>
Platform and architecture facts (architecture, profile, cpu, GIC version, interrupt and IPI controllers, memory protection model, non-unified memory, physical-interrupts-only) are resolved from the platform selection instead of per-platform makefiles, and the build macros derived from them are bridged from Kconfig. Facts cannot be overridden on the command line; where hardware genuinely offers a choice, as the qemu RISC-V virt interrupt and IPI controllers and the FVP GIC version, it is a Kconfig choice. The Arm and RISC-V CI workflows select their variants through a defconfig accordingly. The core feature menu starts with MMIO slave-side protection, offered only on platforms that support it, and the IPI queue depth tunable, which now sizes the per-cpu message queue. Signed-off-by: Jose Martins <josemartins90@gmail.com>
|
@DavidMCerdeira I think all your concerns were addressed. |
|
Great! |
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.