from mkosi.installer import clean_package_manager_metadata
from mkosi.installer.pacman import Pacman
from mkosi.installer.zypper import Zypper
-from mkosi.kmod import gen_required_kernel_modules, is_valid_kdir, loaded_modules, process_kernel_modules
+from mkosi.kmod import (
+ filter_devicetrees,
+ gen_required_kernel_modules,
+ is_valid_kdir,
+ loaded_modules,
+ process_kernel_modules,
+)
from mkosi.log import ARG_DEBUG, complete_step, die, log_notice, log_step
from mkosi.manifest import Manifest
from mkosi.mounts import (
return kmods
-def find_devicetree(context: Context, kver: str) -> Path:
- assert context.config.devicetree
-
- for d in (
- context.root / f"usr/lib/firmware/{kver}/device-tree",
- context.root / f"usr/lib/linux-image-{kver}",
- context.root / f"usr/lib/modules/{kver}/dtb",
- ):
- dtb = d / context.config.devicetree
- if dtb.exists():
- return dtb
-
- die(f"Requested devicetree {context.config.devicetree} not found")
-
-
def want_signed_pcrs(config: Config) -> bool:
return config.sign_expected_pcr == ConfigFeature.enabled or (
config.sign_expected_pcr == ConfigFeature.auto
*flatten(["--ro-bind", os.fspath(profile), os.fspath(workdir(profile))] for profile in profiles),
] # fmt: skip
- if context.config.devicetree:
- dtb = find_devicetree(context, kver)
- arguments += ["--devicetree", workdir(dtb)]
- options += ["--ro-bind", dtb, workdir(dtb)]
+ if context.config.devicetrees:
+ dtbs = filter_devicetrees(context.root, kver, include=context.config.devicetrees)
+ switch = "--devicetree" if len(dtbs) == 1 else "--devicetree-auto"
+ for dtb_rel in dtbs:
+ dtb = context.root / dtb_rel
+ arguments += [switch, workdir(dtb)]
+ options += ["--ro-bind", dtb, workdir(dtb)]
if context.config.splash:
splash = context.root / os.fspath(context.config.splash).lstrip("/")
entry.parent.mkdir(parents=True, exist_ok=True)
dtb = None
- if context.config.devicetree:
- dtb = dst / context.config.devicetree
+ source_dtb = None
+ if context.config.devicetrees:
+ dtbs = filter_devicetrees(context.root, kver, include=context.config.devicetrees)
+ if len(dtbs) != 1:
+ die(
+ "Type 1 boot entries support only single devicetree, use UKI builds for multiple devicetrees"
+ )
+
+ source_dtb = context.root / dtbs[0]
+ dtb = dst / dtbs[0].relative_to(f"usr/lib/modules/{kver}/dtb")
with umask(~0o700):
dtb.parent.mkdir(parents=True, exist_ok=True)
Path(shutil.copy2(initrd, dst.parent / initrd.name)) for initrd in microcode + initrds
] + [Path(shutil.copy2(kmods, dst / "kernel-modules.initrd"))]
- if dtb:
- shutil.copy2(find_devicetree(context, kver), dtb)
+ if dtb and source_dtb:
+ shutil.copy2(source_dtb, dtb)
with entry.open("w") as f:
f.write(
initrd_packages: list[str]
initrd_volatile_packages: list[str]
microcode_host: bool
- devicetree: Optional[str]
+ devicetrees: list[str]
splash: Optional[Path]
kernel_command_line: list[str]
kernel_modules_include: list[str]
help="Packages to install in the initrd that are not cached",
),
ConfigSetting(
- dest="devicetree",
+ dest="devicetrees",
section="Content",
- parse=config_parse_string,
- help="Devicetree to be used by the booting kernel",
+ parse=config_make_list_parser(delimiter=","),
+ help="Devicetree(s) to be used by the booting kernel",
+ compat_names=("Devicetree",),
),
ConfigSetting(
dest="splash",
Initrd Profiles: {line_join_list(config.initrd_profiles)}
Initrd Packages: {line_join_list(config.initrd_packages)}
Initrd Volatile Packages: {line_join_list(config.initrd_volatile_packages)}
- Devicetree: {none_to_none(config.devicetree)}
+ Devicetrees: {line_join_list(config.devicetrees)}
Splash: {none_to_none(config.splash)}
Kernel Command Line: {line_join_list(config.kernel_command_line)}
Kernel Modules: {line_join_list(config.kernel_modules_include)}
# check that kdir contains more than just updates
return dircontent != [kdir / "updates"]
+
+
+def filter_devicetrees(
+ root: Path,
+ kver: str,
+ *,
+ include: Iterable[str],
+) -> list[Path]:
+ if not include:
+ return []
+
+ logging.debug(f"Devicetrees include: {' '.join(include)}")
+
+ # Search standard DTB locations
+ dtb_dirs = [
+ Path("usr/lib/firmware") / kver / "device-tree",
+ Path(f"usr/lib/linux-image-{kver}"),
+ Path("usr/lib/modules") / kver / "dtb",
+ ]
+
+ matched_dtbs = []
+ globs = list(include)
+
+ with chdir(root):
+ for dtb_dir in dtb_dirs:
+ all_dtbs = [p for p in dtb_dir.rglob("*.dtb") if p.is_file() or p.is_symlink()]
+ logging.debug(f"Found {len(all_dtbs)} DTB files in {dtb_dir}")
+
+ for dtb in all_dtbs:
+ rel_path = os.fspath(dtb.relative_to(dtb_dir))
+ if globs_match_filename(rel_path, globs):
+ logging.debug(f"Matched DTB: {rel_path} in {dtb_dir}")
+ matched_dtbs.append(dtb)
+
+ if not matched_dtbs:
+ logging.warning(f"Devicetrees patterns '{globs}' matched 0 files")
+ else:
+ logging.debug(f"Including {len(matched_dtbs)} devicetree files")
+
+ return sorted(matched_dtbs)
: Similar to `VolatilePackages=`, except it applies to the default
initrd.
-`Devicetree=`, `--devicetree=`
-: When set, specifies a Devicetree blob to be used by the booting system,
- instead of the one provided by firmware. **mkosi** will search for the
- specified file relative to common paths where Linux distributions install
- Devicetree files. It should typically have the format `<vendor>/<board>.dtb`.
+`Devicetrees=`, `--devicetrees=`
+: Comma-separated list of devicetree patterns for automatic hardware-based selection.
+ Patterns are glob expressions. **mkosi** searches for devicetree files in standard
+ locations relative to `/usr/lib/modules/<kver>/dtb/`, `/usr/lib/firmware/<kver>/device-tree/`,
+ and `/usr/lib/linux-image-<kver>/`.
+
+ For UKI builds, multiple matches enable automatic hardware-based selection using
+ the `.dtbauto` sections. Type 1 boot entries require exactly one match.
+
+ Example: `Devicetrees=rockchip/*,imx.*` would include all Rockchip devicetrees
+ and any IMX devicetrees.
`Splash=`, `--splash=`
: When set, the boot splash for any unified kernel image built by **mkosi** will
"Dependencies": [
"dep1"
],
- "Devicetree": "freescale/imx8mm-verdin-nonwifi-dev.dtb",
+ "Devicetrees": [
+ "freescale/imx8mm-verdin-nonwifi-dev.dtb"
+ ],
"Distribution": "fedora",
"Drives": [
{
make_initrd=False,
manifest_format=[ManifestFormat.json, ManifestFormat.changelog],
microcode_host=True,
- devicetree="freescale/imx8mm-verdin-nonwifi-dev.dtb",
+ devicetrees=["freescale/imx8mm-verdin-nonwifi-dev.dtb"],
minimum_version="123",
mirror=None,
nspawn_settings=None,