diff options
Diffstat (limited to 'nixos/modules/virtualisation/qemu-vm.nix')
-rw-r--r-- | nixos/modules/virtualisation/qemu-vm.nix | 67 |
1 files changed, 66 insertions, 1 deletions
diff --git a/nixos/modules/virtualisation/qemu-vm.nix b/nixos/modules/virtualisation/qemu-vm.nix index 737a935711ae..55d23b6fb8b5 100644 --- a/nixos/modules/virtualisation/qemu-vm.nix +++ b/nixos/modules/virtualisation/qemu-vm.nix @@ -198,6 +198,39 @@ let fi ''} + ${lib.optionalString cfg.tpm.enable '' + NIX_SWTPM_DIR=$(readlink -f "''${NIX_SWTPM_DIR:-${config.system.name}-swtpm}") + mkdir -p "$NIX_SWTPM_DIR" + ${lib.getExe cfg.tpm.package} \ + socket \ + --tpmstate dir="$NIX_SWTPM_DIR" \ + --ctrl type=unixio,path="$NIX_SWTPM_DIR"/socket,terminate \ + --pid file="$NIX_SWTPM_DIR"/pid --daemon \ + --tpm2 \ + --log file="$NIX_SWTPM_DIR"/stdout,level=6 + + # Enable `fdflags` builtin in Bash + # We will need it to perform surgical modification of the file descriptor + # passed in the coprocess to remove `FD_CLOEXEC`, i.e. close the file descriptor + # on exec. + # If let alone, it will trigger the coprocess to read EOF when QEMU is `exec` + # at the end of this script. To work around that, we will just clear + # the `FD_CLOEXEC` bits as a first step. + enable -f ${hostPkgs.bash}/lib/bash/fdflags fdflags + # leave a dangling subprocess because the swtpm ctrl socket has + # "terminate" when the last connection disconnects, it stops swtpm. + # When qemu stops, or if the main shell process ends, the coproc will + # get signaled by virtue of the pipe between main and coproc ending. + # Which in turns triggers a socat connect-disconnect to swtpm which + # will stop it. + coproc waitingswtpm { + read || : + echo "" | ${lib.getExe hostPkgs.socat} STDIO UNIX-CONNECT:"$NIX_SWTPM_DIR"/socket + } + # Clear `FD_CLOEXEC` on the coprocess' file descriptor stdin. + fdflags -s-cloexec ''${waitingswtpm[1]} + ''} + cd "$TMPDIR" ${lib.optionalString (cfg.emptyDiskImages != []) "idx=0"} @@ -863,6 +896,32 @@ in }; }; + virtualisation.tpm = { + enable = mkEnableOption "a TPM device in the virtual machine with a driver, using swtpm."; + + package = mkPackageOptionMD cfg.host.pkgs "swtpm" { }; + + deviceModel = mkOption { + type = types.str; + default = ({ + "i686-linux" = "tpm-tis"; + "x86_64-linux" = "tpm-tis"; + "ppc64-linux" = "tpm-spapr"; + "armv7-linux" = "tpm-tis-device"; + "aarch64-linux" = "tpm-tis-device"; + }.${pkgs.hostPlatform.system} or (throw "Unsupported system for TPM2 emulation in QEMU")); + defaultText = '' + Based on the guest platform Linux system: + + - `tpm-tis` for (i686, x86_64) + - `tpm-spapr` for ppc64 + - `tpm-tis-device` for (armv7, aarch64) + ''; + example = "tpm-tis-device"; + description = lib.mdDoc "QEMU device model for the TPM, uses the appropriate default based on th guest platform system and the package passed."; + }; + }; + virtualisation.useDefaultFilesystems = mkOption { type = types.bool; @@ -1028,7 +1087,8 @@ in boot.initrd.availableKernelModules = optional cfg.writableStore "overlay" - ++ optional (cfg.qemu.diskInterface == "scsi") "sym53c8xx"; + ++ optional (cfg.qemu.diskInterface == "scsi") "sym53c8xx" + ++ optional (cfg.tpm.enable) "tpm_tis"; virtualisation.additionalPaths = [ config.system.build.toplevel ]; @@ -1099,6 +1159,11 @@ in (mkIf (!cfg.graphics) [ "-nographic" ]) + (mkIf (cfg.tpm.enable) [ + "-chardev socket,id=chrtpm,path=\"$NIX_SWTPM_DIR\"/socket" + "-tpmdev emulator,id=tpm_dev_0,chardev=chrtpm" + "-device ${cfg.tpm.deviceModel},tpmdev=tpm_dev_0" + ]) ]; virtualisation.qemu.drives = mkMerge [ |