]> git.ipfire.org Git - thirdparty/mkosi.git/commitdiff
Build initrd if Bootable=auto
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Fri, 15 Dec 2023 13:20:49 +0000 (14:20 +0100)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Sat, 16 Dec 2023 17:13:47 +0000 (18:13 +0100)
If building a bootable image is not explicitly disabled and we
don't split out an initrd from a UKI because the dependencies are
not installed or we're on the wrong architecture, let's still build
an initrd so that booting with qemu direct kernel boot still works.

mkosi/__init__.py
mkosi/util.py

index 6e714681ea6f6e913ea47cfbf454d3d425335c48..277aa275760adbe8b1e56d1cd39e62a51bcbfcac 100644 (file)
@@ -4,6 +4,7 @@ import contextlib
 import dataclasses
 import datetime
 import hashlib
+import io
 import itertools
 import json
 import logging
@@ -76,6 +77,7 @@ from mkosi.util import (
     read_env_file,
     read_os_release,
     resource_path,
+    round_up,
     scopedenv,
     try_import,
     umask,
@@ -1412,6 +1414,25 @@ def build_kernel_modules_initrd(state: MkosiState, kver: str) -> Path:
     return kmods
 
 
+def join_initrds(initrds: Sequence[Path], output: Path) -> Path:
+    assert initrds
+
+    if len(initrds) == 1:
+        copy_tree(initrds[0], output)
+        return output
+
+    seq = io.BytesIO()
+    for p in initrds:
+        initrd = p.read_bytes()
+        n = len(initrd)
+        padding = b'\0' * (round_up(n, 4) - n)  # pad to 32 bit alignment
+        seq.write(initrd)
+        seq.write(padding)
+
+    output.write_bytes(seq.getbuffer())
+    return output
+
+
 def python_binary(config: MkosiConfig) -> str:
     # If there's no tools tree, prefer the interpreter from MKOSI_INTERPRETER. If there is a tools
     # tree, just use the default python3 interpreter.
@@ -1692,6 +1713,27 @@ def copy_vmlinuz(state: MkosiState) -> None:
         break
 
 
+def copy_initrd(state: MkosiState) -> None:
+    if (state.staging / state.config.output_split_initrd).exists():
+        return
+
+    if state.config.bootable == ConfigFeature.disabled:
+        return
+
+    if state.config.output_format not in (OutputFormat.disk, OutputFormat.directory):
+        return
+
+    for kver, _ in gen_kernel_images(state):
+        microcode = build_microcode_initrd(state)
+        initrds = [microcode] if microcode else []
+        initrds += state.config.initrds or [build_initrd(state)]
+        if state.config.kernel_modules_initrd:
+            kver = next(gen_kernel_images(state))[0]
+            initrds += [build_kernel_modules_initrd(state, kver)]
+        join_initrds(initrds, state.staging / state.config.output_split_initrd)
+        break
+
+
 def hash_file(of: TextIO, path: Path) -> None:
     bs = 16 * 1024**2
     h = hashlib.sha256()
@@ -2565,6 +2607,7 @@ def build_image(args: MkosiArgs, config: MkosiConfig) -> None:
             make_disk(state, split=True, msg="Extracting partitions")
 
         copy_vmlinuz(state)
+        copy_initrd(state)
 
         if state.config.output_format == OutputFormat.tar:
             make_tar(state.root, state.staging / state.config.output_with_format)
index e478e1b95ea5d6c59b040e05ed7769e191948873..f932e52763ee1b9bc2ee248934a6eafa38314583 100644 (file)
@@ -194,3 +194,7 @@ def resource_path(mod: ModuleType) -> Iterator[Path]:
     t = importlib.resources.files(mod)
     with importlib.resources.as_file(t) as p:
         yield p
+
+
+def round_up(x: int, blocksize: int = 4096) -> int:
+    return (x + blocksize - 1) // blocksize * blocksize