From 438ce4c58ecb0943a94e8844120b51913dfe39f3 Mon Sep 17 00:00:00 2001 From: KeksNino Date: Thu, 30 Jul 2026 01:02:17 +0200 Subject: [PATCH] massive restructure --- .gitignore | 8 + README.md | 3 + flake.lock | 463 ++++++++++++ flake.nix | 88 +++ hosts/desktop/configuration.nix | 266 +++++++ hosts/desktop/hardware-configuration.nix | 68 ++ hosts/desktop/home-manager/home.nix | 191 +++++ hosts/desktop/home-manager/mpd.nix | 225 ++++++ hosts/desktop/packages.nix | 69 ++ hosts/music-server/configuration.nix | 87 +++ hosts/music-server/hardware-configuration.nix | 61 ++ hosts/music-server/home-manager/beets.nix | 52 ++ hosts/music-server/home-manager/home.nix | 61 ++ hosts/music-server/packages.nix | 30 + modules/common.nix | 9 + modules/desktop/xremap.nix | 37 + modules/scripts.nix | 25 + modules/server/default.nix | 11 + modules/server/navidrome.nix | 20 + modules/server/nfs.nix | 15 + modules/server/services.nix | 31 + modules/server/slskd.nix | 118 ++++ modules/server/smb.nix | 24 + modules/server/zfs.nix | 39 ++ pkgs/cpuid-fault-emulation/default.nix | 28 + pkgs/cpuid-fault-emulation/source/Makefile | 23 + pkgs/cpuid-fault-emulation/source/dkms.conf | 7 + .../source/inc/host_state.h | 101 +++ .../source/inc/vmcb_layout.h | 574 +++++++++++++++ .../source/src/capture_context.S | 40 ++ .../source/src/cpuid_fault_emulation.c | 663 ++++++++++++++++++ .../cpuid-fault-emulation/source/src/run_vm.S | 121 ++++ 32 files changed, 3558 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 hosts/desktop/configuration.nix create mode 100644 hosts/desktop/hardware-configuration.nix create mode 100644 hosts/desktop/home-manager/home.nix create mode 100644 hosts/desktop/home-manager/mpd.nix create mode 100644 hosts/desktop/packages.nix create mode 100644 hosts/music-server/configuration.nix create mode 100644 hosts/music-server/hardware-configuration.nix create mode 100644 hosts/music-server/home-manager/beets.nix create mode 100644 hosts/music-server/home-manager/home.nix create mode 100644 hosts/music-server/packages.nix create mode 100644 modules/common.nix create mode 100644 modules/desktop/xremap.nix create mode 100644 modules/scripts.nix create mode 100644 modules/server/default.nix create mode 100644 modules/server/navidrome.nix create mode 100644 modules/server/nfs.nix create mode 100644 modules/server/services.nix create mode 100644 modules/server/slskd.nix create mode 100644 modules/server/smb.nix create mode 100644 modules/server/zfs.nix create mode 100644 pkgs/cpuid-fault-emulation/default.nix create mode 100644 pkgs/cpuid-fault-emulation/source/Makefile create mode 100644 pkgs/cpuid-fault-emulation/source/dkms.conf create mode 100644 pkgs/cpuid-fault-emulation/source/inc/host_state.h create mode 100644 pkgs/cpuid-fault-emulation/source/inc/vmcb_layout.h create mode 100644 pkgs/cpuid-fault-emulation/source/src/capture_context.S create mode 100644 pkgs/cpuid-fault-emulation/source/src/cpuid_fault_emulation.c create mode 100644 pkgs/cpuid-fault-emulation/source/src/run_vm.S diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3cb44c3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +# ---> Nix +# Ignore build outputs from performing a nix-build or `nix build` command +result +result-* + +# Ignore automatically generated direnv output +.direnv + diff --git a/README.md b/README.md new file mode 100644 index 0000000..6b61a8e --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# nixos-conf + +my nixos config \ No newline at end of file diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..e9974aa --- /dev/null +++ b/flake.lock @@ -0,0 +1,463 @@ +{ + "nodes": { + "bcdl-free": { + "inputs": { + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1785350661, + "narHash": "sha256-IEFWX9+OQkvYry8ODdVmRZkD8K0WiPVLRAo/GItzBJs=", + "ref": "refs/heads/main", + "rev": "8b9fa0ef8047861ca1b8959afdf8079b39a64d53", + "revCount": 74, + "type": "git", + "url": "https://git.pizzasucht.net/KeksNino/free-bandcamp-downloader" + }, + "original": { + "type": "git", + "url": "https://git.pizzasucht.net/KeksNino/free-bandcamp-downloader" + } + }, + "crane": { + "locked": { + "lastModified": 1766774972, + "narHash": "sha256-8qxEFpj4dVmIuPn9j9z6NTbU+hrcGjBOvaxTzre5HmM=", + "owner": "ipetkov", + "repo": "crane", + "rev": "01bc1d404a51a0a07e9d8759cd50a7903e218c82", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1765835352, + "narHash": "sha256-XswHlK/Qtjasvhd1nOa1e8MgZ8GS//jBoTqWtrS1Giw=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "a34fae9c08a15ad73f295041fec82323541400a9", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "gsr-ui": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1785085647, + "narHash": "sha256-VerKUIpQHGnXgpmRXzh767X0BJNjpACWdVp391t8n1s=", + "owner": "rPlakama", + "repo": "gsr-ui-nix", + "rev": "1f9a46bcdde0e805ced86a0e995f1449f8f7a12f", + "type": "github" + }, + "original": { + "owner": "rPlakama", + "repo": "gsr-ui-nix", + "type": "github" + } + }, + "home-manager": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1785306346, + "narHash": "sha256-DScBkW0fOgpGPK2trNoX3ryLTlaC14+gglFo/BhGJ4g=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "e705714e918c3b11affcdd15db2cbe3a070420a0", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "home-manager", + "type": "github" + } + }, + "home-manager_2": { + "inputs": { + "nixpkgs": [ + "zen-browser", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1783963347, + "narHash": "sha256-r376E2XpakiXwModDHIxlvB6qLq4iFVEq730vxOO4JY=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "a45a7c451455a51ae740ec3bce4024b312809c29", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "home-manager", + "type": "github" + } + }, + "millennium": { + "inputs": { + "millennium-src": "millennium-src", + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "dir": "packages/nix", + "lastModified": 1785163789, + "narHash": "sha256-nHTGaYBPKqOY4SPTqRJNX8MfV/GuIjgPCUxDHHeinGc=", + "owner": "SteamClientHomebrew", + "repo": "Millennium", + "rev": "1375ceda332171907e64e9a9324f9a869f715d6c", + "type": "github" + }, + "original": { + "dir": "packages/nix", + "owner": "SteamClientHomebrew", + "repo": "Millennium", + "type": "github" + } + }, + "millennium-src": { + "flake": false, + "locked": { + "lastModified": 1783268941, + "narHash": "sha256-MJLJ0I48HXgfOpISTAbDMYMUdWj9A6M+jGQz4uAvwyw=", + "owner": "SteamClientHomebrew", + "repo": "Millennium", + "rev": "f37f05bdbd4727d873a1ad83ce72d062ef9a0c48", + "type": "github" + }, + "original": { + "owner": "SteamClientHomebrew", + "repo": "Millennium", + "rev": "f37f05bdbd4727d873a1ad83ce72d062ef9a0c48", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1785350410, + "narHash": "sha256-wXYrsdit8Z54aOAUf7/83LDhkY9+RgSuFBO/rFJeHb8=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "00d4d9bc4d406965d1e0081300dd8c854fd4ba11", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-lib": { + "locked": { + "lastModified": 1765674936, + "narHash": "sha256-k00uTP4JNfmejrCLJOwdObYC9jHRrr/5M/a/8L2EIdo=", + "owner": "nix-community", + "repo": "nixpkgs.lib", + "rev": "2075416fcb47225d9b68ac469a5c4801a9c4dd85", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixpkgs.lib", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1781577229, + "narHash": "sha256-lrp67w8AulE9Ks53n27I45ADSzbOCn4H+CNW1Ck8B+8=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "567a49d1913ce81ac6e9582e3553dd90a955875f", + "type": "github" + }, + "original": { + "owner": "nixos", + "repo": "nixpkgs", + "rev": "567a49d1913ce81ac6e9582e3553dd90a955875f", + "type": "github" + } + }, + "nixpkgs_3": { + "locked": { + "lastModified": 1785332987, + "narHash": "sha256-Eiw4ie++bC7tDWyBEZmcbEeKv1xv0UAihkVTjD4C5VM=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "97478ef76c1f4c40b12fd4a42c1feba41e60650d", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_4": { + "locked": { + "lastModified": 1767026758, + "narHash": "sha256-7fsac/f7nh/VaKJ/qm3I338+wAJa/3J57cOGpXi0Sbg=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "346dd96ad74dc4457a9db9de4f4f57dab2e5731d", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_5": { + "locked": { + "lastModified": 1783279667, + "narHash": "sha256-/NAkDSsve+GNM0Bt6tleJdCGfsTlK89nPjkVOzZMo0s=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "f205b5574fd0cb7da5b702a2da51507b7f4fdd1b", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_6": { + "locked": { + "lastModified": 1784007870, + "narHash": "sha256-djcLt/JJphyNt4eDY9XTly+/WbCK5lqWq9lSgCmJkkQ=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "18b9261cb3294b6d2a06d03f96872827b8fe2698", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "bcdl-free": "bcdl-free", + "gsr-ui": "gsr-ui", + "home-manager": "home-manager", + "millennium": "millennium", + "nixpkgs": "nixpkgs_3", + "sls-steam": "sls-steam", + "xremap-flake": "xremap-flake", + "yazi": "yazi", + "zen-browser": "zen-browser" + } + }, + "rust-overlay": { + "inputs": { + "nixpkgs": [ + "yazi", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1783320166, + "narHash": "sha256-l7C/OsjcnWDOk2K3ssj+SBduwL67LashjBqis9+t468=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "20ee15370c9256669d66968b89ee20a4b0a4e673", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "sls-steam": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1785275929, + "narHash": "sha256-3IbhTuHEqh2tokPGNKnv6x0HcsjOu3hk1MbLYRtzyRQ=", + "owner": "AceSLS", + "repo": "SLSsteam", + "rev": "1906382a482f35b2bc9b124f3849538ab432e4f3", + "type": "github" + }, + "original": { + "owner": "AceSLS", + "repo": "SLSsteam", + "type": "github" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "xremap": { + "flake": false, + "locked": { + "lastModified": 1782465938, + "narHash": "sha256-BgRp0y5bkmMwRCdIKHrXIbv6Kl7Hn9IphburN7i7sE8=", + "owner": "k0kubun", + "repo": "xremap", + "rev": "6d1d06436ecd54002257029bc26a22ef058d4b63", + "type": "github" + }, + "original": { + "owner": "k0kubun", + "ref": "v0.15.9", + "repo": "xremap", + "type": "github" + } + }, + "xremap-flake": { + "inputs": { + "crane": "crane", + "flake-parts": "flake-parts", + "nixpkgs": "nixpkgs_4", + "xremap": "xremap" + }, + "locked": { + "lastModified": 1782757039, + "narHash": "sha256-4CuFwWsQxoNY4Cxz4+GVEmRrMTR5dUOTKN2eNk1KiEI=", + "owner": "xremap", + "repo": "nix-flake", + "rev": "7f161bede2961279dfde194add6aa53d80a9d26d", + "type": "github" + }, + "original": { + "owner": "xremap", + "repo": "nix-flake", + "type": "github" + } + }, + "yazi": { + "inputs": { + "flake-utils": "flake-utils_2", + "nixpkgs": "nixpkgs_5", + "rust-overlay": "rust-overlay" + }, + "locked": { + "lastModified": 1785301727, + "narHash": "sha256-Z9g04KWv8aEowWW+QIiADE6ct36oIZmrykTzEh5sQ4M=", + "owner": "sxyazi", + "repo": "yazi", + "rev": "319f90e0eab185a231eef5562215ba322e320286", + "type": "github" + }, + "original": { + "owner": "sxyazi", + "repo": "yazi", + "type": "github" + } + }, + "zen-browser": { + "inputs": { + "home-manager": "home-manager_2", + "nixpkgs": "nixpkgs_6" + }, + "locked": { + "lastModified": 1785224333, + "narHash": "sha256-8DNJUVM10ktK02V9ZIV064CH+fuPF272VCAZBn6arig=", + "owner": "0xc000022070", + "repo": "zen-browser-flake", + "rev": "5f1a4be4d280e1ae06d61a75775a234b1714da3f", + "type": "github" + }, + "original": { + "owner": "0xc000022070", + "repo": "zen-browser-flake", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..ebeb050 --- /dev/null +++ b/flake.nix @@ -0,0 +1,88 @@ +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs"; + home-manager = { + url = "github:nix-community/home-manager"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + sls-steam = { + url = "github:AceSLS/SLSsteam"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + zen-browser.url = "github:0xc000022070/zen-browser-flake"; + xremap-flake.url = "github:xremap/nix-flake"; + yazi.url = "github:sxyazi/yazi"; + millennium.url = "github:SteamClientHomebrew/Millennium?dir=packages/nix"; + gsr-ui = { + url = "github:rPlakama/gsr-ui-nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + bcdl-free.url = "git+https://git.pizzasucht.net/KeksNino/free-bandcamp-downloader"; + }; + + outputs = + { + nixpkgs, + home-manager, + zen-browser, + xremap-flake, + sls-steam, + yazi, + millennium, + gsr-ui, + bcdl-free, + ... + }@inputs: + let + system = "x86_64-linux"; + in + { + nixosConfigurations.desktop = nixpkgs.lib.nixosSystem { + specialArgs = { + inherit + sls-steam + bcdl-free + xremap-flake + system + ; + }; + modules = [ + ./hosts/desktop/configuration.nix + ./hosts/desktop/hardware-configuration.nix + ./modules/common.nix + home-manager.nixosModules.home-manager + gsr-ui.nixosModules.default + { + nixpkgs.overlays = [ + yazi.overlays.default + millennium.overlays.default + ]; + + home-manager.users.user = import ./hosts/desktop/home-manager/home.nix; + + home-manager.extraSpecialArgs = { + inherit zen-browser; + }; + + programs.gpu-screen-recorder = { + package = gsr-ui.packages.${system}.gpu-screen-recorder; + enable = true; + ui.enable = true; + }; + } + ]; + }; + nixosConfigurations.music-server = nixpkgs.lib.nixosSystem { + specialArgs = { inherit inputs bcdl-free system; }; + modules = [ + ./hosts/music-server/configuration.nix + ./hosts/music-server/hardware-configuration.nix + ./modules/common.nix + home-manager.nixosModules.home-manager + { + home-manager.users.user = import ./hosts/music-server/home-manager/home.nix; + } + ]; + }; + }; +} diff --git a/hosts/desktop/configuration.nix b/hosts/desktop/configuration.nix new file mode 100644 index 0000000..45f59ac --- /dev/null +++ b/hosts/desktop/configuration.nix @@ -0,0 +1,266 @@ +{ + pkgs, + sls-steam, + options, + config, + ... +}: +let + cpuid-fault-emulation = pkgs.callPackage ../../pkgs/cpuid-fault-emulation { + kernel = config.boot.kernelPackages.kernel; + }; +in + +{ + imports = [ + ./hardware-configuration.nix + ./packages.nix + ../../modules/scripts.nix + ../../modules/desktop/xremap.nix + ]; + + # DISKS + fileSystems."/media/gamedisk4" = { + device = "/dev/disk/by-uuid/D290EB87C8A1E82A"; + fsType = "ntfs3"; + options = [ + "uid=1000" + "gid=100" + "rw" + "user" + "exec" + "umask=000" + "nofail" + ]; + }; + + fileSystems."/media/gamedisk" = { + device = "/dev/disk/by-uuid/5C7C14707C1446E4"; + fsType = "ntfs3"; + options = [ + "uid=1000" + "gid=100" + "rw" + "user" + "exec" + "umask=000" + "nofail" + ]; + }; + + fileSystems."/media/gamedisk2" = { + device = "/dev/disk/by-uuid/945A7421DAD8A3CE"; + fsType = "ntfs3"; + options = [ + "uid=1000" + "gid=100" + "rw" + "user" + "exec" + "umask=000" + "nofail" + ]; + }; + + nix.settings.experimental-features = [ + "nix-command" + "flakes" + ]; + + boot.kernelParams = [ + "iomem=relaxed" + "iommu=pt" + "amd_iommu=on" + "kvm.ignore_msrs=1" + "mitigations=off" + "amdgpu.ppfeaturemask=0xffffffff" + "clearcpuid=umip" + ]; + + xdg = { + mime.defaultApplications = { + "inode/directory" = [ "nemo.desktop" ]; + "application/x-gnome-saved-search" = [ "nemo.desktop" ]; + }; + }; + + hardware.graphics.enable = true; + hardware.graphics.enable32Bit = true; + services.hardware.openrgb.enable = true; + + # Bootloader. + boot.loader.grub.enable = true; + boot.loader.grub.device = "nodev"; + boot.loader.grub.efiSupport = true; + boot.extraModulePackages = [ cpuid-fault-emulation ]; + + environment.systemPackages = [ + (pkgs.writeShellScriptBin "enable-hypervisor" '' + sudo modprobe -r kvm_amd kvm + sudo modprobe cpuid_fault_emulation + '') + (pkgs.writeShellScriptBin "disable-hypervisor" '' + sudo modprobe -r cpuid_fault_emulation + sudo modprobe kvm_amd kvm + '') + ]; + + networking.hostName = "nixos-desktop"; + networking.firewall.enable = false; + networking.networkmanager.enable = true; + + # Set your time zone. + time.timeZone = "Europe/Berlin"; + + # Select internationalisation properties. + i18n.defaultLocale = "en_US.UTF-8"; + + i18n.extraLocaleSettings = { + LC_ADDRESS = "de_DE.UTF-8"; + LC_IDENTIFICATION = "de_DE.UTF-8"; + LC_MEASUREMENT = "de_DE.UTF-8"; + LC_MONETARY = "de_DE.UTF-8"; + LC_NAME = "de_DE.UTF-8"; + LC_NUMERIC = "de_DE.UTF-8"; + LC_PAPER = "de_DE.UTF-8"; + LC_TELEPHONE = "de_DE.UTF-8"; + LC_TIME = "de_DE.UTF-8"; + }; + + console.keyMap = "de"; + + programs.fish.enable = true; + users.users.user = { + isNormalUser = true; + description = "user"; + uid = 1000; + extraGroups = [ + "networkmanager" + "wheel" + "docker" + ]; + shell = pkgs.fish; + }; + + nixpkgs.config.allowUnfree = true; + + programs.niri.enable = true; + programs.hyprland = { + enable = true; + xwayland.enable = true; + }; + + # environment.loginShellInit = '' + # if [ "$(tty)" = "/dev/tty1" ] && [ -z "$WAYLAND_DISPLAY" ]; then + # exec start-hyprland + # fi + # ''; + + # NFS / MPD + fileSystems."/media/music" = { + device = "192.168.132.149:/media/music"; + fsType = "nfs4"; + }; + boot.supportedFilesystems = [ "nfs4" ]; + + qt = { + enable = true; + platformTheme = "qt5ct"; + style = "breeze"; + }; + + virtualisation.docker.enable = true; + services.gvfs.enable = true; + services.goxlr-utility.enable = true; + services.lact.enable = true; + services.rsync.enable = true; + programs.kdeconnect.enable = true; + programs.neovim.enable = true; + programs.tmux.enable = true; + programs.bat.enable = true; + programs.nh.enable = true; + programs.git = { + enable = true; + config = { + signing = { + key = "51AE8C6E80E6AF3BDFBE2BF804B31D181764898D"; + signByDefault = true; + }; + user = { + name = "KeksNino"; + email = "KeksNino@proton.me"; + }; + init = { + defaultBranch = "main"; + }; + push = { + autoSetupRemote = true; + }; + commit = { + gpgsign = true; + }; + tag = { + gpgsign = true; + }; + }; + }; + programs.gnupg.agent = { + enable = true; + pinentryPackage = pkgs.pinentry-curses; + }; + + programs.steam = { + enable = true; + package = pkgs.millennium-steam.override { + extraEnv = { + LD_AUDIT = "${sls-steam.packages.${pkgs.stdenv.hostPlatform.system}.sls-steam}/library-inject.so:${ + sls-steam.packages.${pkgs.stdenv.hostPlatform.system}.sls-steam + }/SLSsteam.so"; + }; + }; + }; + + programs.nix-ld = { + enable = true; + libraries = + options.programs.nix-ld.libraries.default + ++ (with pkgs; [ + dbus # libdbus-1.so.3 + fontconfig # libfontconfig.so.1 + freetype # libfreetype.so.6 + glib # libglib-2.0.so.0 + libGL # libGL.so.1 + libxkbcommon # libxkbcommon.so.0 + libx11 # libX11.so.6 + wayland + ]); + }; + + services.pipewire = { + enable = true; + alsa.enable = true; + pulse.enable = true; + jack.enable = true; + }; + + security.pam.loginLimits = [ + { + domain = "@users"; + item = "rtprio"; + type = "-"; + value = "95"; + } + { + domain = "@users"; + item = "memlock"; + type = "-"; + value = "unlimited"; + } + ]; + + security.rtkit.enable = true; + + system.stateVersion = "24.11"; + system.autoUpgrade.enable = false; + system.autoUpgrade.allowReboot = true; +} diff --git a/hosts/desktop/hardware-configuration.nix b/hosts/desktop/hardware-configuration.nix new file mode 100644 index 0000000..44aec8b --- /dev/null +++ b/hosts/desktop/hardware-configuration.nix @@ -0,0 +1,68 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ + config, + lib, + pkgs, + modulesPath, + ... +}: + +{ + imports = [ + (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = [ + "xhci_pci" + "ahci" + "usbhid" + "usb_storage" + "sd_mod" + ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-amd" ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = { + device = "/dev/disk/by-uuid/ddabcce9-86a5-4dd8-84f1-3afa99a83752"; + fsType = "ext4"; + }; + + fileSystems."/boot" = { + device = "/dev/disk/by-uuid/16F5-2D1A"; + fsType = "vfat"; + options = [ + "fmask=0077" + "dmask=0077" + ]; + }; + + fileSystems."/media/gamedisk4" = { + device = "/dev/disk/by-uuid/D290EB87C8A1E82A"; + fsType = "ntfs3"; + }; + + fileSystems."/media/music" = { + device = "192.168.132.149:/media/music"; + fsType = "nfs4"; + }; + + fileSystems."/media/arch" = { + device = "/dev/disk/by-uuid/8873d98f-c461-4d34-8867-f4ebd5c205d2"; + fsType = "ext4"; + }; + + fileSystems."/media/gamedisk" = { + device = "/dev/disk/by-uuid/5C7C14707C1446E4"; + fsType = "ntfs3"; + }; + + swapDevices = [ + { device = "/dev/disk/by-uuid/5949c73f-30eb-4956-9e93-70301c88fad8"; } + ]; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/hosts/desktop/home-manager/home.nix b/hosts/desktop/home-manager/home.nix new file mode 100644 index 0000000..6def3e2 --- /dev/null +++ b/hosts/desktop/home-manager/home.nix @@ -0,0 +1,191 @@ +{ + pkgs, + config, + zen-browser, + ... +}: +{ + imports = [ + ./mpd.nix + zen-browser.homeModules.beta + ]; + + home.username = "user"; + home.homeDirectory = "/home/user"; + + xdg.userDirs = { + enable = true; + createDirectories = false; + extraConfig = { + SCREENSHOTS = "${config.home.homeDirectory}/Pictures/Screenshots"; + }; + }; + + xdg.mimeApps = { + enable = true; + defaultApplications = { + "inode/directory" = [ "nemo.desktop" ]; + "image/*" = [ "imv-dir.desktop" ]; + "image/gif" = [ "imv-dir.desktop" ]; + "image/jpeg" = [ "imv-dir.desktop" ]; + "image/png" = [ "imv-dir.desktop" ]; + "image/webp" = [ "imv-dir.desktop" ]; + }; + }; + + dconf = { + settings = { + "org/cinnamon/desktop/applications/terminal" = { + exec = "kitty"; + # exec-arg = ""; # argument + }; + }; + }; + + home.pointerCursor = { + enable = true; + gtk.enable = true; + package = pkgs.adwaita-icon-theme; + name = "Adwaita"; + size = 20; + }; + + programs.zen-browser = { + enable = true; + setAsDefaultBrowser = true; + }; + + programs.yazi.enable = true; + programs.yazi.enableFishIntegration = true; + + programs.fzf.enable = true; + programs.fzf.enableFishIntegration = true; + + programs.eza = { + enable = true; + enableFishIntegration = true; + git = true; + icons = "always"; + extraOptions = [ + "-1" + ]; + }; + + programs.pywal = { + enable = true; + package = pkgs.pywal16; + }; + + programs.lazygit.enable = true; + programs.lazygit.enableFishIntegration = true; + + programs.rbw = { + enable = true; + settings = { + pinentry = pkgs.pinentry-curses; + email = "KeksNino@proton.me"; + base_url = "https://vw.pizzasucht.net"; + }; + }; + + programs.distrobox.enable = true; + services.podman.enable = true; + + programs.rofi.enable = true; + programs.rofi.plugins = [ pkgs.rofi-calc ]; + + services.polkit-gnome.enable = true; + services.cliphist.enable = true; + programs.btop.enable = true; + services.udiskie.enable = true; + programs.cava.enable = true; + programs.equibop.enable = true; + services.awww.enable = true; + services.mpdris2.enable = true; + programs.fastfetch.enable = true; + programs.prismlauncher.enable = true; + programs.fd.enable = true; + programs.uv.enable = true; + programs.satty.enable = true; + programs.mpvpaper.enable = true; + programs.obsidian.enable = true; + programs.gcc.enable = true; + programs.mpv.enable = true; + programs.imv.enable = true; + programs.aria2.enable = true; + programs.qutebrowser = { + enable = true; + settings = { + colors.webpage.preferred_color_scheme = "dark"; + auto_save.session = true; + scrolling.smooth = true; + content.autoplay = false; + content.blocking.method = "both"; + url.default_page = "https://priv.au"; + }; + extraConfig = '' + c.qt.args = ["disable-features=AcceleratedVideoDecodeLinuxGL"] + ''; + keyBindings = { + normal = { + "M" = "hint links spawn mpv {hint-url}"; + }; + }; + searchEngines = { + DEFAULT = "https://priv.au/search?q={}"; + }; + }; + + home.sessionPath = [ + "${config.home.homeDirectory}/.local/bin" + ]; + + home.sessionVariables = { + EDITOR = "nvim"; + }; + + programs.fish = { + enable = true; + interactiveShellInit = '' + nitch + set -g fish_key_bindings fish_hybrid_key_bindings + set fish_greeting + ''; + shellAliases = { + ls = "eza -al --no-time --no-user --no-permissions --no-filesize"; + ll = "eza -la"; + cat = "bat"; + cd = "z"; + cp = "cp -v"; + ff = "fastfetch"; + grep = "grep -i"; + hyprland = "start-hyprland"; + mv = "mv -v"; + n = "nvim"; + py = "uv run"; + r = "rsync -avh --info=progress2"; + rm = "gomi"; + ssh = "kitty +kitten ssh"; + nd = "nix develop"; + }; + }; + + programs.zoxide.enable = true; + programs.zoxide.enableFishIntegration = true; + + home.file.".local/share/Steam/steam.cfg".text = '' + BootStrapperInhibitAll=enable + BootStrapperForceSelfUpdate=disable + ''; + + gtk = { + enable = true; + # theme = { + # name = "Materia-dark-compact"; + # package = pkgs.materia-theme-transparent; + # }; + colorScheme = "dark"; + }; + + home.stateVersion = "26.05"; +} diff --git a/hosts/desktop/home-manager/mpd.nix b/hosts/desktop/home-manager/mpd.nix new file mode 100644 index 0000000..fd404f4 --- /dev/null +++ b/hosts/desktop/home-manager/mpd.nix @@ -0,0 +1,225 @@ +{ + services.mpd = { + enable = true; + musicDirectory = "/home/user/Music"; + playlistDirectory = "/home/user/Music/Playlists"; + dbFile = "/home/user/.config/mpd/database"; + # log_file = "~/.config/mpd/log"; + extraConfig = '' + save_absolute_paths_in_playlists "yes" + metadata_to_use "+comment" + audio_output { + type "pipewire" + name "Pipewire Sound Server" + } + audio_output { + type "fifo" + name "my_fifo" + path "/tmp/mpd.fifo" + format "44100:16:2" + } + auto_update "yes" + ''; + network.listenAddress = "/home/user/.config/mpd/socket"; + }; + + services.mpdscribble = { + enable = true; + endpoints = { + "last.fm" = { + passwordFile = "/home/user/lastfm_password"; + username = "KeksNino"; + }; + }; + }; + + programs.rmpc.enable = true; + programs.rmpc.config = '' + #![enable(implicit_some)] + #![enable(unwrap_newtypes)] + #![enable(unwrap_variant_newtypes)] + ( + address: "/home/user/.config/mpd/socket", + password: None, + theme: Some("default"), + cache_dir: Some("/home/user/Music/rmpc"), + on_song_change: None, + volume_step: 5, + max_fps: 60, + scrolloff: 0, + wrap_navigation: false, + enable_mouse: true, + enable_config_hot_reload: true, + status_update_interval_ms: 1000, + rewind_to_start_sec: None, + reflect_changes_to_playlist: false, + select_current_song_on_change: false, + browser_song_sort: [Track, Disc, Artist, Title], + directories_sort: SortFormat(group_by_type: true, reverse: false), + album_art: ( + method: Kitty, + max_size_px: (width: 1200, height: 1200), + disabled_protocols: ["http://", "https://"], + vertical_align: Center, + horizontal_align: Center, + ), + keybinds: ( + global: { + ":": CommandMode, + ",": VolumeDown, + "s": Stop, + ".": VolumeUp, + "": NextTab, + "": PreviousTab, + "1": SwitchToTab("Queue"), + "2": SwitchToTab("Files"), + "3": SwitchToTab("Playlists"), + "4": SwitchToTab("Artists"), + "5": SwitchToTab("Albums"), + "6": SwitchToTab("Search"), + //"7": SwitchToTab("Album Artists"), + "q": Quit, + ">": NextTrack, + "p": TogglePause, + "<": PreviousTrack, + "f": SeekForward, + "z": ToggleRepeat, + "x": ToggleRandom, + "c": ToggleConsume, + "v": ToggleSingle, + "b": SeekBack, + "~": ShowHelp, + "u": Update, + "U": Rescan, + "I": ShowCurrentSongInfo, + "O": ShowOutputs, + "P": ShowDecoders, + "R": AddRandom, + "": ExternalCommand(command: ["/home/user/.scripts/check-playlist.sh"], description: "Check if selected song is already in a playlist"), + }, + navigation: { + "k": Up, + "j": Down, + "h": Left, + "l": Right, + "": Up, + "": Down, + "": Left, + "": Right, + "": PaneUp, + "": PaneDown, + "": PaneLeft, + "": PaneRight, + "": UpHalf, + "N": PreviousResult, + "a": Add, + "A": AddAll, + "r": Rename, + "n": NextResult, + "g": Top, + "": Select, + "": InvertSelection, + "G": Bottom, + "": Confirm, + "i": FocusInput, + "J": MoveDown, + "": DownHalf, + "/": EnterSearch, + "": Close, + "": Close, + "K": MoveUp, + "D": Delete, + "B": ShowInfo, + }, + queue: { + "D": DeleteAll, + "": Play, + "": Save, + "a": AddToPlaylist, + "d": Delete, + "C": JumpToCurrent, + "X": Shuffle, + }, + ), + search: ( + case_sensitive: false, + mode: Contains, + tags: [ + (value: "any", label: "Any Tag"), + (value: "artist", label: "Artist"), + (value: "album", label: "Album"), + (value: "albumartist", label: "Album Artist"), + (value: "title", label: "Title"), + (value: "filename", label: "Filename"), + (value: "genre", label: "Genre"), + ], + ), + artists: ( + album_display_mode: SplitByDate, + album_sort_by: Date, + ), + cava: ( + framerate: 60, + autosens: true, + sensitivity: 110, // default 100 + lower_cutoff_freq: 50, // not passed to cava if not provided + higher_cutoff_freq: 10000, // not passed to cava if not provided + input: ( + method: Fifo, + source: "/tmp/mpd.fifo", + sample_rate: 44100, + channels: 2, + sample_bits: 16, + ), + smoothing: ( + noise_reduction: 77, + monstercat: true, + waves: false, + ), + eq: [] + ), + tabs: [ + ( + name: "Queue", + pane: Split( + direction: Horizontal, + panes: [ + (size: "40%", pane: Pane(AlbumArt)), + (size: "60%", pane: Split( + direction: Vertical, + panes: [ + (size: "95%", pane: Pane(Queue)), + (size: "30%", pane: Pane(Cava)), + ], + )), + ], + ), + ), + ( + name: "Files", + pane: Pane(Directories), + ), + ( + name: "Playlists", + pane: Pane(Playlists), + ), + ( + name: "Artists", + pane: Pane(Artists), + ), + ( + name: "Albums", + pane: Pane(Albums), + ), + ( + name: "Search", + pane: Pane(Search), + ), + //( + // name: "Album Artists", + // pane: Pane(AlbumArtists), + //), + ], + ) + ''; +} diff --git a/hosts/desktop/packages.nix b/hosts/desktop/packages.nix new file mode 100644 index 0000000..13410f5 --- /dev/null +++ b/hosts/desktop/packages.nix @@ -0,0 +1,69 @@ +{ pkgs, ... }: { + + environment.systemPackages = with pkgs; [ + wget + kitty + gdu + jamesdsp + grimblast + nitch + wl-clipboard + unzip + _7zz + tree-sitter + nodejs + nixfmt + decibels + nwg-look + mpc + python3 + basedpyright + waypaper + renoise + pwvucontrol + lsof + picard + exiftool + tlrc + libnotify + trash-cli + spek + ffmpeg + # wine + ripgrep + nemo-with-extensions + papirus-icon-theme + rust-analyzer + scdl + motrix-next + onefetch + smartmontools + qpwgraph + pipewire.jack + sysz + gomi + noctalia-shell + discordchatexporter-desktop + act + ayugram-desktop + playerctl + musicpresence + nixd + libsForQt5.qt5ct + qt6Packages.qt6ct + kdePackages.breeze + kdePackages.breeze.qt5 + gnumake + samrewritten + gale + losslesscut + tree + stow + ]; + + fonts.packages = with pkgs; [ + nerd-fonts.caskaydia-mono + nerd-fonts.symbols-only + nerd-fonts.jetbrains-mono + ]; +} diff --git a/hosts/music-server/configuration.nix b/hosts/music-server/configuration.nix new file mode 100644 index 0000000..5b3de55 --- /dev/null +++ b/hosts/music-server/configuration.nix @@ -0,0 +1,87 @@ +{ + pkgs, + ... +}: + +{ + imports = [ + ./hardware-configuration.nix + ./packages.nix + ../../modules/server + ]; + + nix.settings.experimental-features = [ + "nix-command" + "flakes" + ]; + + fileSystems."/media/music" = { + device = "/dev/disk/by-uuid/8e6ae06e-a4b5-4ac8-ad15-cb288b14715f"; + fsType = "ext4"; + }; + + fileSystems."/home/user/backup" = { + device = "/dev/disk/by-uuid/db7d96f1-5c72-42dc-abc1-00de9b73f017"; + fsType = "ext4"; + }; + + networking.hostId = "6054e036"; + networking.hostName = "nixos-music"; + networking.networkmanager.enable = true; + networking.firewall.enable = false; + + time.timeZone = "Europe/Berlin"; + + i18n.defaultLocale = "en_US.UTF-8"; + console = { + font = "Lat2-Terminus16"; + keyMap = "de"; + }; + + programs.fish.enable = true; + users.users.user = { + isNormalUser = true; + description = "user"; + uid = 1000; + extraGroups = [ + "networkmanager" + "wheel" + "docker" + ]; + shell = pkgs.fish; + }; + + services.tailscale.enable = true; + services.rsync.enable = true; + programs.nix-ld.enable = true; + programs.nh.enable = true; + programs.neovim.enable = true; + programs.tmux.enable = true; + programs.bat.enable = true; + programs.git = { + enable = true; + config = { + user = { + name = "KeksNino"; + email = "KeksNino@proton.me"; + }; + init = { + defaultBranch = "main"; + }; + push = { + autoSetupRemote = true; + }; + }; + }; + + services.openssh = { + enable = true; + openFirewall = true; + settings = { + PasswordAuthentication = false; + PermitRootLogin = "no"; + }; + }; + + system.stateVersion = "26.05"; +} diff --git a/hosts/music-server/hardware-configuration.nix b/hosts/music-server/hardware-configuration.nix new file mode 100644 index 0000000..4f0d529 --- /dev/null +++ b/hosts/music-server/hardware-configuration.nix @@ -0,0 +1,61 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ + config, + lib, + pkgs, + modulesPath, + ... +}: + +{ + imports = [ + (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = [ + "xhci_pci" + "ahci" + "usb_storage" + "uas" + "sd_mod" + ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-intel" ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = { + device = "zpool/root"; + fsType = "zfs"; + }; + + fileSystems."/var" = { + device = "zpool/var"; + fsType = "zfs"; + }; + + fileSystems."/nix" = { + device = "zpool/nix"; + fsType = "zfs"; + }; + + fileSystems."/home" = { + device = "zpool/home"; + fsType = "zfs"; + }; + + fileSystems."/boot" = { + device = "/dev/disk/by-uuid/FCFD-4472"; + fsType = "vfat"; + options = [ + "fmask=0022" + "dmask=0022" + ]; + }; + + swapDevices = [ ]; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/hosts/music-server/home-manager/beets.nix b/hosts/music-server/home-manager/beets.nix new file mode 100644 index 0000000..1ed2393 --- /dev/null +++ b/hosts/music-server/home-manager/beets.nix @@ -0,0 +1,52 @@ +{ + programs.beets.enable = true; + + # programs.beets.package = pkgs.beets.override { + # pluginOverrides = { + # filetote = { + # enable = true; + # }; + # }; + # }; + + programs.beets.settings = { + directory = "/home/user/Music/Tracks"; + + plugins = [ + "fetchart" + "badfiles" + "edit" + "fish" + "hook" + ]; + + import = { + copy = false; + move = true; + autotag = false; + write = true; + }; + + paths = { + default = "$albumartist/$album/$track. $artist - $title"; + }; + + fetchart = { + auto = true; + sources = [ "filesystem" ]; + }; + + badfiles = { + check_on_import = true; + }; + + hook = { + hooks = [ + { + event = "item_imported"; + command = "echo test"; + } + ]; + }; + }; +} diff --git a/hosts/music-server/home-manager/home.nix b/hosts/music-server/home-manager/home.nix new file mode 100644 index 0000000..89a5fcc --- /dev/null +++ b/hosts/music-server/home-manager/home.nix @@ -0,0 +1,61 @@ +{ pkgs, config, ... }: +{ + imports = [ + ./beets.nix + ]; + + home.username = "user"; + home.homeDirectory = "/home/user"; + + programs.yazi.enable = true; + programs.yazi.enableFishIntegration = true; + + programs.fzf.enable = true; + programs.fzf.enableFishIntegration = true; + + programs.zoxide.enable = true; + programs.zoxide.enableFishIntegration = true; + + programs.gcc.enable = true; + + programs.eza = { + enable = true; + enableFishIntegration = true; + git = true; + icons = "always"; + extraOptions = [ + "-1" + ]; + }; + + programs.btop.enable = true; + programs.fastfetch.enable = true; + programs.fd.enable = true; + + home.sessionVariables = { + EDITOR = "nvim"; + }; + + programs.fish = { + enable = true; + interactiveShellInit = '' + set -g fish_key_bindings fish_hybrid_key_bindings + set fish_greeting + ''; + shellAliases = { + ls = "eza -al --no-time --no-user --no-permissions --no-filesize"; + ll = "eza -la"; + cat = "bat"; + cd = "z"; + cp = "cp -v"; + ff = "fastfetch"; + grep = "grep -i"; + mv = "mv -v"; + n = "nvim"; + r = "rsync -avh --info=progress2"; + rm = "gomi"; + }; + }; + + home.stateVersion = "26.05"; +} diff --git a/hosts/music-server/packages.nix b/hosts/music-server/packages.nix new file mode 100644 index 0000000..962412d --- /dev/null +++ b/hosts/music-server/packages.nix @@ -0,0 +1,30 @@ +{ pkgs, ... }: { + + environment.systemPackages = ( + with pkgs; + [ + wget + nixfmt + tree-sitter + lsof + exiftool + trash-cli + ffmpeg + unzip + scdl + aria2 + nodejs + gomi + bun + croc + mp3val + flac + (python314.withPackages ( + ps: with ps; [ + requests + python-dotenv + ] + )) + ] + ); +} diff --git a/modules/common.nix b/modules/common.nix new file mode 100644 index 0000000..0b6e13f --- /dev/null +++ b/modules/common.nix @@ -0,0 +1,9 @@ +{ system, bcdl-free, ... }: +{ + environment.systemPackages = [ bcdl-free.packages.${system}.default ]; + + home-manager.useGlobalPkgs = true; + home-manager.useUserPackages = true; + + home-manager.backupFileExtension = "backup"; +} diff --git a/modules/desktop/xremap.nix b/modules/desktop/xremap.nix new file mode 100644 index 0000000..4cca033 --- /dev/null +++ b/modules/desktop/xremap.nix @@ -0,0 +1,37 @@ +{ xremap-flake, ... }: +{ + imports = [ + xremap-flake.nixosModules.default + ]; + + services.xremap.enable = true; + services.xremap.withHypr = true; + + services.xremap.config.modmap = [ + { + name = "Global"; + remap = { + "CapsLock" = "Esc"; + }; + } + ]; + + services.xremap.config.keymap = [ + { + name = "curly braces"; + remap = { + "KEY_SEMICOLON" = "RIGHTALT-KEY_7"; + }; # ä -> } + remap = { + "KEY_APOSTROPHE" = "RIGHTALT-KEY_0"; + }; # ö -> { + remap = { + "RIGHTALT-KEY_A" = "KEY_APOSTROPHE"; + }; # altgr + a -> ä + remap = { + "RIGHTALT-KEY_W" = "KEY_SEMICOLON"; + }; # altgr + w -> ö + } + ]; + +} diff --git a/modules/scripts.nix b/modules/scripts.nix new file mode 100644 index 0000000..90c91a9 --- /dev/null +++ b/modules/scripts.nix @@ -0,0 +1,25 @@ +{ pkgs, ... }: +{ + environment.systemPackages = [ + (pkgs.writeShellScriptBin "scan" '' + find . -type f \( -iname "*.mp3" -o -iname "*.flac" -o -iname "*.m4a" -o -iname "*.ogg" -o -iname "*.wav" -o -iname "*.aiff" \) -print0 | + xargs -0 -P"$(nproc)" -I{} bash -c ' + if ffprobe -v quiet -show_entries format_tags \ + -of default=nw=1:nk=1 "$1" 2>/dev/null | + grep -q -E "Visit https?://[^ ]+"; then + echo "Match found in: $1" + fi + ' _ {} | sort + '') + (pkgs.writeShellScriptBin "2scan" '' + find . -type f \( -iname "*.mp3" -o -iname "*.flac" -o -iname "*.m4a" -o -iname "*.ogg" -o -iname "*.wav" -o -iname "*.aiff" \) -print0 | + xargs -0 -P"$(nproc)" -I{} sh -c ' + if ! ffprobe -v quiet -show_entries format_tags \ + -of default=nw=1:nk=1 "$1" 2>/dev/null | + grep -q -E "Visit https?://[^ ]+"; then + echo "Match found in: $1" + fi + ' _ {} + '') + ]; +} diff --git a/modules/server/default.nix b/modules/server/default.nix new file mode 100644 index 0000000..033b436 --- /dev/null +++ b/modules/server/default.nix @@ -0,0 +1,11 @@ +{ + imports = [ + ./slskd.nix + ./navidrome.nix + ./nfs.nix + ./services.nix + ./smb.nix + ./zfs.nix + ../scripts.nix + ]; +} diff --git a/modules/server/navidrome.nix b/modules/server/navidrome.nix new file mode 100644 index 0000000..a70f05a --- /dev/null +++ b/modules/server/navidrome.nix @@ -0,0 +1,20 @@ +{ lib, ... }: + +{ + services.navidrome = { + enable = true; + user = "user"; + settings = { + MusicFolder = "/home/user/Music"; + PlaylistsPath = "Playlists"; + Address = "0.0.0.0"; + ScanSchedule = "@every 24h"; + EnableInsightsCollector = false; + Scanner.PurgeMissing = "always"; + }; + }; + + systemd.services.navidrome.serviceConfig = { + ProtectHome = lib.mkForce false; + }; +} diff --git a/modules/server/nfs.nix b/modules/server/nfs.nix new file mode 100644 index 0000000..ab9712c --- /dev/null +++ b/modules/server/nfs.nix @@ -0,0 +1,15 @@ +{ + services.nfs.server = { + enable = true; + exports = { + "/media/music" = { + "192.168.132.0/24" = [ + "rw" + "async" + "no_subtree_check" + "fsid=1" + ]; + }; + }; + }; +} diff --git a/modules/server/services.nix b/modules/server/services.nix new file mode 100644 index 0000000..eeb0bf3 --- /dev/null +++ b/modules/server/services.nix @@ -0,0 +1,31 @@ +{ pkgs, ... }: + +{ + systemd.timers."bc-wishlist-scraper" = { + wantedBy = [ "timers.target" ]; + timerConfig = { + OnCalendar = "daily"; + Unit = "bc-wishlist-scraper.service"; + }; + }; + + systemd.services."bc-wishlist-scraper" = { + script = '' + ${pkgs.bash}/bin/bash /home/user/bc-wishlist-scraper/run.sh + ''; + }; + + systemd.user.timers."scdl" = { + wantedBy = [ "timers.target" ]; + timerConfig = { + OnCalendar = "daily"; + Unit = "scdl.service"; + }; + }; + + systemd.user.services."scdl" = { + script = '' + cd ~/Music/scdl && ${pkgs.scdl}/bin/scdl me -f -c --download-archive archive.txt + ''; + }; +} diff --git a/modules/server/slskd.nix b/modules/server/slskd.nix new file mode 100644 index 0000000..a99f2df --- /dev/null +++ b/modules/server/slskd.nix @@ -0,0 +1,118 @@ +{ pkgs, ... }: + +{ + services.slskd = { + enable = true; + environmentFile = /home/user/slskd_secrets; + user = "user"; + settings = { + remote_configuration = true; + remote_file_management = true; + directories = { + downloads = "/media/music/Soulseek"; + }; + shares = { + directories = [ + "/media/music/Tracks" + "/media/music/Tracks2" + "/media/music/samples" + ]; + }; + rooms = [ + "Rare Music" + "nicotine" + "! ! LGBTQ+ ! !" + "lossless" + "Linux" + "Breakcore" + "Jungle" + ]; + transfers = { + upload = { + speed_limit = 3700; + }; + groups = { + blacklisted = { + members = [ + "relay" + "smbd" + ]; + }; + user_defined = { + my_buddies = { + upload = { + priority = 1; + strategy = "firstinfirstout"; + slots = 1000; + }; + members = [ + "noamifur" + "mesityl" + "diphenhydramine" + "monfi" + ]; + }; + }; + }; + }; + soulseek = { + description = '' + Fuck DRM. Fuck Spotify + Discord: keksnino + https://www.last.fm/user/KeksNino + ''; + listen_port = 32895; + }; + feature = { + swagger = true; + }; + integrations = { + webhooks = { + discord_relay = { + call = { + url = "http://localhost:5001/slskd_webhook"; + }; + on = [ "UploadFileComplete" ]; + timeout = 5000; + retry = { + attempts = 3; + }; + }; + }; + }; + retention = { + files = { + incomplete = 20160; + }; + }; + }; + }; + + systemd.user.services.slskd-speed = { + enable = true; + description = "Soulseek True Speed Shower"; + after = [ "network-online.target" ]; + wants = [ "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "simple"; + Environment = "PYTHONUNBUFFERED=1"; + Restart = "on-failure"; + RestartSec = 30; + StandardOutput = "journal"; + StandardError = "journal"; + EnvironmentFile = "/home/user/slskd_secrets"; + ExecStart = '' + ${pkgs.python3}/bin/python3 /home/user/slskd-speed.py \ + -u "$SLSKD_SLSK_USERNAME" \ + -p "$SLSKD_SLSK_PASSWORD" \ + -s 30mbit/s \ + --slskd-url http://localhost:5030 \ + --slskd-key "$SLSKD_API_KEY" \ + --loop \ + --poll-interval 30 \ + --interval 900 + ''; + }; + }; +} diff --git a/modules/server/smb.nix b/modules/server/smb.nix new file mode 100644 index 0000000..0a1d94b --- /dev/null +++ b/modules/server/smb.nix @@ -0,0 +1,24 @@ +{ + services.samba = { + enable = true; + openFirewall = true; + settings = { + global = { + "workgroup" = "WORKGROUP"; + "server string" = "smbnix"; + "security" = "user"; + "interfaces" = "lo eno1 tailscale0"; + "hosts allow" = "192.168.132.0/24 100.64.0.0/10 127.0.0.1 localhost"; + "hosts deny" = "0.0.0.0/0"; + "guest account" = "nobody"; + }; + "Music" = { + "path" = "/media/music"; + "browseable" = "yes"; + "read only" = "no"; + "guest ok" = "no"; + "valid users" = "user"; + }; + }; + }; +} diff --git a/modules/server/zfs.nix b/modules/server/zfs.nix new file mode 100644 index 0000000..cca2052 --- /dev/null +++ b/modules/server/zfs.nix @@ -0,0 +1,39 @@ +{ + boot.loader.grub = { + enable = true; + zfsSupport = true; + efiSupport = true; + efiInstallAsRemovable = true; + mirroredBoots = [ + { + devices = [ "nodev" ]; + path = "/boot"; + } + ]; + }; + + fileSystems."/" = { + device = "zpool/root"; + fsType = "zfs"; + }; + fileSystems."/nix" = { + device = "zpool/nix"; + fsType = "zfs"; + }; + fileSystems."/var" = { + device = "zpool/var"; + fsType = "zfs"; + }; + fileSystems."/home" = { + device = "zpool/home"; + fsType = "zfs"; + }; + fileSystems."/boot" = { + device = "/dev/disk/by-uuid/FCFD-4472"; + fsType = "vfat"; + }; + boot.zfs.forceImportRoot = false; + services.zfs.autoScrub.enable = true; + + swapDevices = [ ]; +} diff --git a/pkgs/cpuid-fault-emulation/default.nix b/pkgs/cpuid-fault-emulation/default.nix new file mode 100644 index 0000000..f98194e --- /dev/null +++ b/pkgs/cpuid-fault-emulation/default.nix @@ -0,0 +1,28 @@ +{ stdenv, kernel }: + +stdenv.mkDerivation { + pname = "cpuid_fault_emulation"; + version = "0.1"; + + src = ./source; + + nativeBuildInputs = kernel.moduleBuildDependencies; + hardeningDisable = [ + "pic" + "format" + ]; + + # Patch the hardcoded host paths to point into the Nix store + postPatch = '' + substituteInPlace Makefile \ + --replace '/lib/modules/$(KERNEL)/build' '${kernel.dev}/lib/modules/${kernel.modDirVersion}/build' \ + --replace '$(shell uname -r)' '${kernel.modDirVersion}' + ''; + + installPhase = '' + install -D cpuid_fault_emulation.ko \ + $out/lib/modules/${kernel.modDirVersion}/extra/cpuid_fault_emulation.ko + ''; + + meta.platforms = [ "x86_64-linux" ]; +} diff --git a/pkgs/cpuid-fault-emulation/source/Makefile b/pkgs/cpuid-fault-emulation/source/Makefile new file mode 100644 index 0000000..c63d31a --- /dev/null +++ b/pkgs/cpuid-fault-emulation/source/Makefile @@ -0,0 +1,23 @@ +obj-m += cpuid_fault_emulation.o +cpuid_fault_emulation-y := src/cpuid_fault_emulation.o src/capture_context.o src/run_vm.o + +PWD := $(CURDIR) +ccflags-y += -I$(src)/inc +asflags-y += -I$(src)/inc + + +NOCLANG := CONFIG_CLANG_VERSION=0 + +KERNEL := $(if $(KERNEL),$(KERNEL),$(shell uname -r)) + +ifneq ($(shell grep "CONFIG_CLANG_VERSION" /lib/modules/$(KERNEL)/build/.config), $(NOCLANG)) + LLVM := LLVM=1 +endif + + +all: + echo $(MAKE) $(LLVM) -C /lib/modules/$(KERNEL)/build M=$(PWD) modules + $(MAKE) $(LLVM) -C /lib/modules/$(KERNEL)/build M=$(PWD) modules + +clean: + $(MAKE) -C /lib/modules/$(KERNEL)/build M=$(PWD) clean diff --git a/pkgs/cpuid-fault-emulation/source/dkms.conf b/pkgs/cpuid-fault-emulation/source/dkms.conf new file mode 100644 index 0000000..3e7b733 --- /dev/null +++ b/pkgs/cpuid-fault-emulation/source/dkms.conf @@ -0,0 +1,7 @@ +PACKAGE_NAME="cpuid_fault_emulation" +PACKAGE_VERSION="0.1" + +BUILT_MODULE_NAME="cpuid_fault_emulation" +BUILT_MODULE_NAME="cpuid_fault_emulation" +DEST_MODULE_LOCATION="/updates" +AUTOINSTALL="yes" diff --git a/pkgs/cpuid-fault-emulation/source/inc/host_state.h b/pkgs/cpuid-fault-emulation/source/inc/host_state.h new file mode 100644 index 0000000..40fb9db --- /dev/null +++ b/pkgs/cpuid-fault-emulation/source/inc/host_state.h @@ -0,0 +1,101 @@ +#ifndef HOST_STATE_H +#define HOST_STATE_H + + +#define GUEST_RAX_OFFSET 0x00 +#define GUEST_RBX_OFFSET 0x08 +#define GUEST_RCX_OFFSET 0x10 +#define GUEST_RDX_OFFSET 0x18 +#define GUEST_RSI_OFFSET 0x20 +#define GUEST_RDI_OFFSET 0x28 +#define GUEST_RSP_OFFSET 0x30 +#define GUEST_RBP_OFFSET 0x38 +#define GUEST_R8_OFFSET 0x40 +#define GUEST_R9_OFFSET 0x48 +#define GUEST_R10_OFFSET 0x50 +#define GUEST_R11_OFFSET 0x58 +#define GUEST_R12_OFFSET 0x60 +#define GUEST_R13_OFFSET 0x68 +#define GUEST_R14_OFFSET 0x70 +#define GUEST_R15_OFFSET 0x78 +#define GUEST_RIP_OFFSET 0x80 +#define GUEST_RFLAGS_OFFSET 0x88 + +#define HOST_STACK_OFFSET 0x000 +#define HOST_STACK_SIZE 0x1000 +#define HOST_VMCB_OFFSET 0x1000 +#define HOST_HOST_VMCB_OFFSET 0x2000 +#define HOST_HOST_SAVE_OFFSET 0x3000 +#define HOST_VMCB_PA_OFFSET 0x4000 +#define HOST_HOST_VMCB_PA_OFFSET 0x4008 +#define HOST_REGISTER_OFFSET 0x4010 + +#ifndef __ASSEMBLER__ +#include "vmcb_layout.h" + +struct GuestRegisters { + u64 rax; + u64 rbx; + u64 rcx; + u64 rdx; + u64 rsi; + u64 rdi; + u64 rsp; + u64 rbp; + u64 r8; + u64 r9; + u64 r10; + u64 r11; + u64 r12; + u64 r13; + u64 r14; + u64 r15; +} __attribute__((packed)); + +static_assert(GUEST_RAX_OFFSET == offsetof(struct GuestRegisters, rax)); +static_assert(GUEST_RBX_OFFSET == offsetof(struct GuestRegisters, rbx)); +static_assert(GUEST_RCX_OFFSET == offsetof(struct GuestRegisters, rcx)); +static_assert(GUEST_RDX_OFFSET == offsetof(struct GuestRegisters, rdx)); +static_assert(GUEST_RSI_OFFSET == offsetof(struct GuestRegisters, rsi)); +static_assert(GUEST_RDI_OFFSET == offsetof(struct GuestRegisters, rdi)); +static_assert(GUEST_RSP_OFFSET == offsetof(struct GuestRegisters, rsp)); +static_assert(GUEST_RBP_OFFSET == offsetof(struct GuestRegisters, rbp)); +static_assert(GUEST_R8_OFFSET == offsetof(struct GuestRegisters, r8)); +static_assert(GUEST_R9_OFFSET == offsetof(struct GuestRegisters, r9)); +static_assert(GUEST_R10_OFFSET == offsetof(struct GuestRegisters, r10)); +static_assert(GUEST_R11_OFFSET == offsetof(struct GuestRegisters, r11)); +static_assert(GUEST_R12_OFFSET == offsetof(struct GuestRegisters, r12)); +static_assert(GUEST_R13_OFFSET == offsetof(struct GuestRegisters, r13)); +static_assert(GUEST_R14_OFFSET == offsetof(struct GuestRegisters, r14)); +static_assert(GUEST_R15_OFFSET == offsetof(struct GuestRegisters, r15)); + +struct InitialContext { + struct GuestRegisters regs; + u64 rip; + u64 rflags; +} __attribute__((packed)); +static_assert(GUEST_RIP_OFFSET == offsetof(struct InitialContext, rip)); +static_assert(GUEST_RFLAGS_OFFSET == offsetof(struct InitialContext, rflags)); + +struct ProcessorStatus { + u8 host_stack[HOST_STACK_SIZE]; + struct VMCB vmcb; + struct VMCB host_vmcb; + u8 host_save[0x1000]; + u64 vmcb_pa; + u64 host_vmcb_pa; + struct GuestRegisters guest_registers; + void* page_ptr; + u64 prev_hsave_pa; + bool cpuid_fault; +} __attribute__((packed)); +static_assert(offsetof(struct ProcessorStatus, host_stack) == HOST_STACK_OFFSET); +static_assert(offsetof(struct ProcessorStatus, vmcb) == HOST_VMCB_OFFSET); +static_assert(offsetof(struct ProcessorStatus, host_vmcb) == HOST_HOST_VMCB_OFFSET); +static_assert(offsetof(struct ProcessorStatus, host_save) == HOST_HOST_SAVE_OFFSET); +static_assert(offsetof(struct ProcessorStatus, vmcb_pa) == HOST_VMCB_PA_OFFSET); +static_assert(offsetof(struct ProcessorStatus, host_vmcb_pa) == HOST_HOST_VMCB_PA_OFFSET); +static_assert(offsetof(struct ProcessorStatus, guest_registers) == HOST_REGISTER_OFFSET); +#endif +#endif + diff --git a/pkgs/cpuid-fault-emulation/source/inc/vmcb_layout.h b/pkgs/cpuid-fault-emulation/source/inc/vmcb_layout.h new file mode 100644 index 0000000..f171f77 --- /dev/null +++ b/pkgs/cpuid-fault-emulation/source/inc/vmcb_layout.h @@ -0,0 +1,574 @@ +#ifndef VMCB_LAYOUT_H +#define VMCB_LAYOUT_H +#include + +struct InterceptVector0 { + u32 read_cr0 : 1; + u32 read_cr1 : 1; + u32 read_cr2 : 1; + u32 read_cr3 : 1; + u32 read_cr4 : 1; + u32 read_cr5 : 1; + u32 read_cr6 : 1; + u32 read_cr7 : 1; + u32 read_cr8 : 1; + u32 read_cr9 : 1; + u32 read_cr10 : 1; + u32 read_cr11 : 1; + u32 read_cr12 : 1; + u32 read_cr13 : 1; + u32 read_cr14 : 1; + u32 read_cr15 : 1; + u32 write_cr0 : 1; + u32 write_cr1 : 1; + u32 write_cr2 : 1; + u32 write_cr3 : 1; + u32 write_cr4 : 1; + u32 write_cr5 : 1; + u32 write_cr6 : 1; + u32 write_cr7 : 1; + u32 write_cr8 : 1; + u32 write_cr9 : 1; + u32 write_cr10 : 1; + u32 write_cr11 : 1; + u32 write_cr12 : 1; + u32 write_cr13 : 1; + u32 write_cr14 : 1; + u32 write_cr15 : 1; +} __attribute__((packed)); +static_assert(sizeof(struct InterceptVector0) == 4); + +struct InterceptVector1 { + u32 read_dr0 : 1; + u32 read_dr1 : 1; + u32 read_dr2 : 1; + u32 read_dr3 : 1; + u32 read_dr4 : 1; + u32 read_dr5 : 1; + u32 read_dr6 : 1; + u32 read_dr7 : 1; + u32 read_dr8 : 1; + u32 read_dr9 : 1; + u32 read_dr10 : 1; + u32 read_dr11 : 1; + u32 read_dr12 : 1; + u32 read_dr13 : 1; + u32 read_dr14 : 1; + u32 read_dr15 : 1; + u32 write_dr0 : 1; + u32 write_dr1 : 1; + u32 write_dr2 : 1; + u32 write_dr3 : 1; + u32 write_dr4 : 1; + u32 write_dr5 : 1; + u32 write_dr6 : 1; + u32 write_dr7 : 1; + u32 write_dr8 : 1; + u32 write_dr9 : 1; + u32 write_dr10 : 1; + u32 write_dr11 : 1; + u32 write_dr12 : 1; + u32 write_dr13 : 1; + u32 write_dr14 : 1; + u32 write_dr15 : 1; +} __attribute__((packed)); +static_assert(sizeof(struct InterceptVector1) == 4); + +struct InterceptVector2 { + u32 exception_vector0 : 1; + u32 exception_vector1 : 1; + u32 exception_vector2 : 1; + u32 exception_vector3 : 1; + u32 exception_vector4 : 1; + u32 exception_vector5 : 1; + u32 exception_vector6 : 1; + u32 exception_vector7 : 1; + u32 exception_vector8 : 1; + u32 exception_vector9 : 1; + u32 exception_vector10 : 1; + u32 exception_vector11 : 1; + u32 exception_vector12 : 1; + u32 exception_vector13 : 1; + u32 exception_vector14 : 1; + u32 exception_vector15 : 1; + u32 exception_vector16 : 1; + u32 exception_vector17 : 1; + u32 exception_vector18 : 1; + u32 exception_vector19 : 1; + u32 exception_vector20 : 1; + u32 exception_vector21 : 1; + u32 exception_vector22 : 1; + u32 exception_vector23 : 1; + u32 exception_vector24 : 1; + u32 exception_vector25 : 1; + u32 exception_vector26 : 1; + u32 exception_vector27 : 1; + u32 exception_vector28 : 1; + u32 exception_vector29 : 1; + u32 exception_vector30 : 1; + u32 exception_vector31 : 1; +} __attribute__((packed)); +static_assert(sizeof(struct InterceptVector2) == 4); + +struct InterceptVector3 { + u32 intr : 1; + u32 nmi : 1; + u32 smi : 1; + u32 init : 1; + u32 vintr : 1; + u32 cr0_writes : 1; + u32 idtr_read : 1; + u32 gdtr_read : 1; + u32 ldtr_read : 1; + u32 tr_read : 1; + u32 idtr_write : 1; + u32 gdtr_write : 1; + u32 ldtr_write : 1; + u32 tr_write : 1; + u32 rdtsc_inst : 1; + u32 rdpmc_inst : 1; + u32 pushf_inst : 1; + u32 popf_inst : 1; + u32 cpuid_inst : 1; + u32 rsm_inst : 1; + u32 iret_inst : 1; + u32 intn_inst : 1; + u32 invd_inst : 1; + u32 pause_inst : 1; + u32 hlt_inst : 1; + u32 invlpg_inst : 1; + u32 invlpga_inst : 1; + u32 ioio_prot : 1; + u32 msr_prot : 1; + u32 task_switches : 1; + u32 ferr_freeze : 1; + u32 shutdown : 1; +} __attribute__((packed)); +static_assert(sizeof(struct InterceptVector3) == 4); + +struct InterceptVector4 { + u32 vmrun_inst : 1; + u32 vmcall_inst : 1; + u32 vmload_inst : 1; + u32 vmsave_inst : 1; + u32 stgi_inst : 1; + u32 clgi_inst : 1; + u32 skinit_inst : 1; + u32 rdtscp_inst : 1; + u32 icebp_inst : 1; + u32 wbinvd_inst : 1; + u32 monitor_inst : 1; + u32 mwait_inst_uncond : 1; + u32 mwait_inst_armed : 1; + u32 xsetbv_inst : 1; + u32 rdpru_inst : 1; + u32 efer_write : 1; + u32 write_cr0_after : 1; + u32 write_cr1_after : 1; + u32 write_cr2_after : 1; + u32 write_cr3_after : 1; + u32 write_cr4_after : 1; + u32 write_cr5_after : 1; + u32 write_cr6_after : 1; + u32 write_cr7_after : 1; + u32 write_cr8_after : 1; + u32 write_cr9_after : 1; + u32 write_cr10_after : 1; + u32 write_cr11_after : 1; + u32 write_cr12_after : 1; + u32 write_cr13_after : 1; + u32 write_cr14_after : 1; + u32 write_cr15_after : 1; +} __attribute__((packed)); +static_assert(sizeof(struct InterceptVector4) == 4); + +struct InterceptVector5 { + u32 invlpgb_inst_all : 1; + u32 invlpgb_inst_ill : 1; + u32 invpcid_inst : 1; + u32 mcommit_inst : 1; + u32 tlbsync_inst : 1; + u32 bus_lock_op : 1; + u32 hlt_inst_npen : 1; + u32 reserved : 25; +} __attribute__((packed)); +static_assert(sizeof(struct InterceptVector5) == 4); + +struct TLBControl { + u32 tlb_control : 8; + u32 allow_larger_rap : 1; + u32 clear_rap : 1; + u32 reserved : 22; +} __attribute__((packed)); +static_assert(sizeof(struct TLBControl) == 4); + +struct VirtualInterruptControl { + u64 v_tpr : 4; + u64 v_tpr_mbz : 4; + u64 v_irq : 1; + u64 v_gif : 1; + u64 reserved_0 : 1; + u64 v_nmi : 1; + u64 v_nmi_mask : 1; + u64 reserved_1 : 3; + u64 v_intr_prio : 4; + u64 v_ign_tpr : 1; + u64 reserved_2 : 3; + u64 v_intr_masking : 1; + u64 v_gif_enable : 1; + u64 v_nmi_enable : 1; + u64 reserved_3 : 3; + u64 x2avic_enable : 1; + u64 avic_enable : 1; + u64 v_intr_vector : 8; + u64 reserved_4 : 24; +} __attribute__((packed)); +static_assert(sizeof(struct VirtualInterruptControl) == 8); + +struct InterruptShadow { + u64 interrupt_shadow : 1; + u64 guest_interrupt_mask : 1; + u64 reserved : 62; +} __attribute__((packed)); +static_assert(sizeof(struct InterruptShadow) == 8); + +struct VirtualizationControl0 { + u64 np_enable : 1; + u64 sev_enable : 1; + u64 sev_es : 1; + u64 guest_mode_execute_trap : 1; + u64 ssscheck_en : 1; + u64 virtual_transparent_encryption : 1; + u64 read_only_guest_page_tables : 1; + u64 invlpg_tlbsync_enable : 1; + u64 reserved : 56; +} __attribute__((packed)); +static_assert(sizeof(struct VirtualizationControl0) == 8); + +struct AVICAPICBar { + u64 avic_apic_bar : 52; + u64 reserved : 12; +} __attribute__((packed)); +static_assert(sizeof(struct AVICAPICBar) == 8); + +struct VirtualizationControl1 { + u64 lbr_virtualization_enable : 1; + u64 vmsave_vmload_virtualization_enable : 1; + u64 ibs_virtualization_enable : 1; + u64 pmc_virtualization_enable : 1; + u64 ignored : 60; +} __attribute__((packed)); +static_assert(sizeof(struct VirtualizationControl1) == 8); + +struct GuestInstruction { + u8 bytes_fetched; + u8 guest_instruction[0xF]; +} __attribute__((packed)); +static_assert(sizeof(struct GuestInstruction) == 0x10); + +struct AVICAPICBackingPage { + u64 avic_apic_backing_page_pointer : 52; + u64 reserved : 12; +} __attribute__((packed)); +static_assert(sizeof(struct AVICAPICBackingPage) == 8); + +struct AVICLogicalTablePointer { + u64 reserved_0 : 12; + u64 avic_logical_table_pointer : 40; + u64 reserved_1 : 12; +} __attribute__((packed)); +static_assert(sizeof(struct AVICLogicalTablePointer) == 8); + +struct AVICPhysicalTablePointer { + u64 avic_physical_max_index : 12; + u64 avic_physical_table_pointer : 40; + u64 reserved_0 : 12; +} __attribute__((packed)); +static_assert(sizeof(struct AVICPhysicalTablePointer) == 8); + +struct VMSAPointer { + u64 reserved_0 : 12; + u64 vmsa_pointer : 40; + u64 reserved_1 : 12; +} __attribute__((packed)); +static_assert(sizeof(struct VMSAPointer) == 8); + +struct AllowedSEVFeatures { + u64 allowed_sev_features_mask : 62; + u64 reserved_0 : 1; + u64 allowed_sev_features_en : 1; +} __attribute__((packed)); +static_assert(sizeof(struct AllowedSEVFeatures) == 8); + +struct RequestedIRR { + u64 irr[4]; +} __attribute__((packed)); +static_assert(sizeof(struct RequestedIRR) == 0x20); + +struct VMCBControlArea { + struct InterceptVector0 intercept_vector0; + struct InterceptVector1 intercept_vector1; + struct InterceptVector2 intercept_vector2; + struct InterceptVector3 intercept_vector3; + struct InterceptVector4 intercept_vector4; + struct InterceptVector5 intercept_vector5; + u8 reserved_0[0x24]; + u16 pause_filter_threshold; + u16 pause_filter_count; + u64 iopm_base_pa; + u64 msrpm_base_pa; + u64 tsc_offset; + u32 guest_asid; + struct TLBControl tlb_control; + struct VirtualInterruptControl v_intr; + struct InterruptShadow interrupt_shadow; + u64 exitcode; + u64 exitinfo1; + u64 exitinfo2; + u64 exitintinfo; + struct VirtualizationControl0 virtualization_control0; + struct AVICAPICBar avic_apic_bar; + u64 guest_ghcb_pa; + u64 eventinj; + u64 h_cr3; + struct VirtualizationControl1 virtualization_control1; + u32 vmcb_clean_bits; + u8 reserved_1[0x4]; + u64 nrip; + struct GuestInstruction guest_instruction; + struct AVICAPICBackingPage avicapic_backing_page; + u8 reserved_2[0x8]; + struct AVICLogicalTablePointer avic_logical_table; + struct AVICPhysicalTablePointer avic_physical_table; + u8 reserved_3[0x08]; + struct VMSAPointer vmsa_pointer; + u64 vmgexit_rax; + u8 vmgexit_cpl; + u8 reserved_4[0x07]; + u16 bus_lock_threshold_counter; + u8 reserved_5[0x12]; + u32 update_irr; + struct AllowedSEVFeatures allowed_sev_features; + u64 guest_sev_features; + u8 reserved_6[0x8]; + struct RequestedIRR requested_irr; + u8 reserved_7[0x270]; + u8 host_reserved[0x20]; +} __attribute__((packed)); + +static_assert(offsetof(struct VMCBControlArea, intercept_vector0) == 0x000); +static_assert(offsetof(struct VMCBControlArea, intercept_vector1) == 0x004); +static_assert(offsetof(struct VMCBControlArea, intercept_vector2) == 0x008); +static_assert(offsetof(struct VMCBControlArea, intercept_vector3) == 0x00C); +static_assert(offsetof(struct VMCBControlArea, intercept_vector4) == 0x010); +static_assert(offsetof(struct VMCBControlArea, intercept_vector5) == 0x014); +static_assert(offsetof(struct VMCBControlArea, pause_filter_threshold) == 0x03C); +static_assert(offsetof(struct VMCBControlArea, pause_filter_count) == 0x03E); +static_assert(offsetof(struct VMCBControlArea, intercept_vector5) == 0x014); +static_assert(offsetof(struct VMCBControlArea, iopm_base_pa) == 0x040); +static_assert(offsetof(struct VMCBControlArea, msrpm_base_pa) == 0x048); +static_assert(offsetof(struct VMCBControlArea, tsc_offset) == 0x050); +static_assert(offsetof(struct VMCBControlArea, guest_asid) == 0x058); +static_assert(offsetof(struct VMCBControlArea, tlb_control) == 0x05C); +static_assert(offsetof(struct VMCBControlArea, v_intr) == 0x060); +static_assert(offsetof(struct VMCBControlArea, interrupt_shadow) == 0x068); +static_assert(offsetof(struct VMCBControlArea, exitcode) == 0x070); +static_assert(offsetof(struct VMCBControlArea, exitinfo1) == 0x078); +static_assert(offsetof(struct VMCBControlArea, exitinfo2) == 0x080); +static_assert(offsetof(struct VMCBControlArea, exitintinfo) == 0x088); +static_assert(offsetof(struct VMCBControlArea, virtualization_control0) == 0x090); +static_assert(offsetof(struct VMCBControlArea, avic_apic_bar) == 0x098); +static_assert(offsetof(struct VMCBControlArea, guest_ghcb_pa) == 0x0A0); +static_assert(offsetof(struct VMCBControlArea, eventinj) == 0x0A8); +static_assert(offsetof(struct VMCBControlArea, h_cr3) == 0x0B0); +static_assert(offsetof(struct VMCBControlArea, virtualization_control1) == 0x0B8); +static_assert(offsetof(struct VMCBControlArea, vmcb_clean_bits) == 0x0C0); +static_assert(offsetof(struct VMCBControlArea, nrip) == 0x0C8); +static_assert(offsetof(struct VMCBControlArea, guest_instruction) == 0x0D0); +static_assert(offsetof(struct VMCBControlArea, avicapic_backing_page) == 0x0E0); +static_assert(offsetof(struct VMCBControlArea, avic_logical_table) == 0x0F0); +static_assert(offsetof(struct VMCBControlArea, avic_physical_table) == 0x0F8); +static_assert(offsetof(struct VMCBControlArea, vmsa_pointer) == 0x108); +static_assert(offsetof(struct VMCBControlArea, vmgexit_rax) == 0x110); +static_assert(offsetof(struct VMCBControlArea, vmgexit_cpl) == 0x118); +static_assert(offsetof(struct VMCBControlArea, bus_lock_threshold_counter) == 0x120); +static_assert(offsetof(struct VMCBControlArea, update_irr) == 0x134); +static_assert(offsetof(struct VMCBControlArea, allowed_sev_features) == 0x138); +static_assert(offsetof(struct VMCBControlArea, guest_sev_features) == 0x140); +static_assert(offsetof(struct VMCBControlArea, requested_irr) == 0x150); +static_assert(offsetof(struct VMCBControlArea, host_reserved) == 0x3E0); +static_assert(sizeof(struct VMCBControlArea) == 0x400); + +struct SegmentDescriptor { + u16 selector; + u16 attrib; + u32 limit; + u64 base; +} __attribute__((packed)); + +static_assert(offsetof(struct SegmentDescriptor, selector) == 0); +static_assert(offsetof(struct SegmentDescriptor, attrib) == 2); +static_assert(offsetof(struct SegmentDescriptor, limit) == 4); +static_assert(offsetof(struct SegmentDescriptor, base) == 8); +static_assert(sizeof(struct SegmentDescriptor) == 0x10); + +struct LBRSTACK { + u8 lbr_stack_from_to[256]; +} __attribute__((packed)); +static_assert(sizeof(struct LBRSTACK) == 0x100); + +struct VMCBStateSaveArea { + struct SegmentDescriptor es; + struct SegmentDescriptor cs; + struct SegmentDescriptor ss; + struct SegmentDescriptor ds; + struct SegmentDescriptor fs; + struct SegmentDescriptor gs; + struct SegmentDescriptor gdtr; + struct SegmentDescriptor ldtr; + struct SegmentDescriptor idtr; + struct SegmentDescriptor tr; + u8 reserved_0[0x2B]; + u8 cpl; + u8 reserved_1[0x4]; + u64 efer; + u8 reserved_2[0x8]; + u64 perf_ctl0; + u64 perf_ctr0; + u64 perf_ctl1; + u64 perf_ctr1; + u64 perf_ctl2; + u64 perf_ctr2; + u64 perf_ctl3; + u64 perf_ctr3; + u64 perf_ctl4; + u64 perf_ctr4; + u64 perf_ctl5; + u64 perf_ctr5; + u8 reserved_3[0x8]; + u64 cr4; + u64 cr3; + u64 cr0; + u64 dr7; + u64 dr6; + u64 rflags; + u64 rip; + u8 reserved_4[0x40]; + u64 instr_retired_ctr; + u64 perf_ctr_global_sts; + u64 perf_ctr_global_ctl; + u64 rsp; + u64 s_cet; + u64 ssp; + u64 isst_addr; + u64 rax; + u64 star; + u64 lstar; + u64 cstar; + u64 sfmask; + u64 kernel_gs_base; + u64 sysenter_cs; + u64 sysenter_esp; + u64 sysenter_eip; + u64 cr2; + u8 reserved_5[0x20]; + u64 g_pat; + u64 dbgctl; + u64 br_from; + u64 br_to; + u64 lastexcpfrom; + u64 lastexcpto; + u64 dbgextnctl; + u8 reserved_6[0x40]; + u64 spec_ctrl; + u8 reserved_7[0x388]; + struct LBRSTACK lbr_stack_from_to; + u64 lbr_select; + u64 ibs_fetch_ctl; + u64 ibs_fetch_linaddr; + u64 ibs_op_ctl; + u64 ibs_op_rip; + u64 ibs_op_data; + u64 ibs_op_data2; + u64 ibs_op_data3; + u64 ibs_dc_linaddr; + u64 bp_ibstgt_rip; + u64 ic_ibs_extd_ctl; + u8 reserved_9[0x38]; +} __attribute__((packed)); +static_assert(offsetof(struct VMCBStateSaveArea, es) == 0x000); +static_assert(offsetof(struct VMCBStateSaveArea, cs) == 0x010); +static_assert(offsetof(struct VMCBStateSaveArea, ss) == 0x020); +static_assert(offsetof(struct VMCBStateSaveArea, ds) == 0x030); +static_assert(offsetof(struct VMCBStateSaveArea, fs) == 0x040); +static_assert(offsetof(struct VMCBStateSaveArea, gs) == 0x050); +static_assert(offsetof(struct VMCBStateSaveArea, gdtr) == 0x060); +static_assert(offsetof(struct VMCBStateSaveArea, ldtr) == 0x070); +static_assert(offsetof(struct VMCBStateSaveArea, idtr) == 0x080); +static_assert(offsetof(struct VMCBStateSaveArea, tr) == 0x090); +static_assert(offsetof(struct VMCBStateSaveArea, cpl) == 0x0CB); +static_assert(offsetof(struct VMCBStateSaveArea, efer) == 0x0D0); +static_assert(offsetof(struct VMCBStateSaveArea, perf_ctl0) == 0x0E0); +static_assert(offsetof(struct VMCBStateSaveArea, perf_ctr0) == 0x0E8); +static_assert(offsetof(struct VMCBStateSaveArea, perf_ctl1) == 0x0F0); +static_assert(offsetof(struct VMCBStateSaveArea, perf_ctr1) == 0x0F8); +static_assert(offsetof(struct VMCBStateSaveArea, perf_ctl2) == 0x100); +static_assert(offsetof(struct VMCBStateSaveArea, perf_ctr2) == 0x108); +static_assert(offsetof(struct VMCBStateSaveArea, perf_ctl3) == 0x110); +static_assert(offsetof(struct VMCBStateSaveArea, perf_ctr3) == 0x118); +static_assert(offsetof(struct VMCBStateSaveArea, perf_ctl4) == 0x120); +static_assert(offsetof(struct VMCBStateSaveArea, perf_ctr4) == 0x128); +static_assert(offsetof(struct VMCBStateSaveArea, perf_ctl5) == 0x130); +static_assert(offsetof(struct VMCBStateSaveArea, perf_ctr5) == 0x138); +static_assert(offsetof(struct VMCBStateSaveArea, cr4) == 0x148); +static_assert(offsetof(struct VMCBStateSaveArea, cr3) == 0x150); +static_assert(offsetof(struct VMCBStateSaveArea, cr0) == 0x158); +static_assert(offsetof(struct VMCBStateSaveArea, dr7) == 0x160); +static_assert(offsetof(struct VMCBStateSaveArea, dr6) == 0x168); +static_assert(offsetof(struct VMCBStateSaveArea, rflags) == 0x170); +static_assert(offsetof(struct VMCBStateSaveArea, rip) == 0x178); +static_assert(offsetof(struct VMCBStateSaveArea, instr_retired_ctr) == 0x1C0); +static_assert(offsetof(struct VMCBStateSaveArea, perf_ctr_global_sts) == 0x1C8); +static_assert(offsetof(struct VMCBStateSaveArea, perf_ctr_global_ctl) == 0x1D0); +static_assert(offsetof(struct VMCBStateSaveArea, rsp) == 0x1D8); +static_assert(offsetof(struct VMCBStateSaveArea, rax) == 0x1F8); +static_assert(offsetof(struct VMCBStateSaveArea, star) == 0x200); +static_assert(offsetof(struct VMCBStateSaveArea, lstar) == 0x208); +static_assert(offsetof(struct VMCBStateSaveArea, cstar) == 0x210); +static_assert(offsetof(struct VMCBStateSaveArea, sfmask) == 0x218); +static_assert(offsetof(struct VMCBStateSaveArea, kernel_gs_base) == 0x220); +static_assert(offsetof(struct VMCBStateSaveArea, sysenter_cs) == 0x228); +static_assert(offsetof(struct VMCBStateSaveArea, sysenter_esp) == 0x230); +static_assert(offsetof(struct VMCBStateSaveArea, sysenter_eip) == 0x238); +static_assert(offsetof(struct VMCBStateSaveArea, cr2) == 0x240); +static_assert(offsetof(struct VMCBStateSaveArea, g_pat) == 0x268); +static_assert(offsetof(struct VMCBStateSaveArea, dbgctl) == 0x270); +static_assert(offsetof(struct VMCBStateSaveArea, br_from) == 0x278); +static_assert(offsetof(struct VMCBStateSaveArea, br_to) == 0x280); +static_assert(offsetof(struct VMCBStateSaveArea, lastexcpfrom) == 0x288); +static_assert(offsetof(struct VMCBStateSaveArea, lastexcpto) == 0x290); +static_assert(offsetof(struct VMCBStateSaveArea, dbgextnctl) == 0x298); +static_assert(offsetof(struct VMCBStateSaveArea, spec_ctrl) == 0x2E0); +static_assert(offsetof(struct VMCBStateSaveArea, lbr_stack_from_to) == 0x670); +static_assert(offsetof(struct VMCBStateSaveArea, lbr_select) == 0x770); +static_assert(offsetof(struct VMCBStateSaveArea, ibs_fetch_ctl) == 0x778); +static_assert(offsetof(struct VMCBStateSaveArea, ibs_fetch_linaddr) == 0x780); +static_assert(offsetof(struct VMCBStateSaveArea, ibs_op_ctl) == 0x788); +static_assert(offsetof(struct VMCBStateSaveArea, ibs_op_rip) == 0x790); +static_assert(offsetof(struct VMCBStateSaveArea, ibs_op_data) == 0x798); +static_assert(offsetof(struct VMCBStateSaveArea, ibs_op_data2) == 0x7A0); +static_assert(offsetof(struct VMCBStateSaveArea, ibs_op_data3) == 0x7A8); +static_assert(offsetof(struct VMCBStateSaveArea, ibs_dc_linaddr) == 0x7B0); +static_assert(offsetof(struct VMCBStateSaveArea, bp_ibstgt_rip) == 0x7B8); +static_assert(offsetof(struct VMCBStateSaveArea, ic_ibs_extd_ctl) == 0x7C0); +static_assert(sizeof(struct VMCBStateSaveArea) == 0x800); + +struct VMCB { + struct VMCBControlArea control_area; + struct VMCBStateSaveArea state_area; + u8 reserved_0 [0x400]; +} __attribute__((packed)); +static_assert(offsetof(struct VMCB, control_area) == 0x000); +static_assert(offsetof(struct VMCB, state_area) == 0x400); +static_assert(sizeof(struct VMCB) == 0x1000); +#endif diff --git a/pkgs/cpuid-fault-emulation/source/src/capture_context.S b/pkgs/cpuid-fault-emulation/source/src/capture_context.S new file mode 100644 index 0000000..84061d6 --- /dev/null +++ b/pkgs/cpuid-fault-emulation/source/src/capture_context.S @@ -0,0 +1,40 @@ +#include +#include +#include + +#define save_to_offset(val, REG) movq val , GUEST_ ## REG ## _OFFSET (% _ASM_ARG1 ) +SYM_FUNC_START(capture_context) +#ifdef ENDBR + ENDBR +#endif + save_to_offset($0, RAX) /* save 0 for guest rax */ + save_to_offset(%rbx, RBX) + save_to_offset(%rcx, RCX) + save_to_offset(%rdx, RDX) + save_to_offset(%rsi, RSI) + save_to_offset(%rdi, RDI) + save_to_offset(%rbp, RBP) + + leaq 8(%rsp),%rax /* rsp after ret */ + save_to_offset(%rax, RSP) + + save_to_offset(%r8, R8) + save_to_offset(%r9, R9) + save_to_offset(%r10, R10) + save_to_offset(%r11, R11) + save_to_offset(%r12, R12) + save_to_offset(%r13, R13) + save_to_offset(%r14, R14) + save_to_offset(%r15, R15) + + movq (%rsp), %rax /* return addr*/ + save_to_offset(%rax, RIP) + + pushfq + popq %rax /* rflags */ + save_to_offset(%rax, RFLAGS) + + mov $1, %rax; + RET + +SYM_FUNC_END(capture_context) diff --git a/pkgs/cpuid-fault-emulation/source/src/cpuid_fault_emulation.c b/pkgs/cpuid-fault-emulation/source/src/cpuid_fault_emulation.c new file mode 100644 index 0000000..e7f3655 --- /dev/null +++ b/pkgs/cpuid-fault-emulation/source/src/cpuid_fault_emulation.c @@ -0,0 +1,663 @@ +#include /* Needed for the macros */ +#include /* Needed by all modules */ +#include /* Needed for pr_info() */ +#include /* for memset() and memcpy() */ +#include +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 11, 0) + #include +#else + #include +#endif +#include + +#include +#include +#include +#include + +#include +#include + +#define MSR_PM_BASE1 0x00000000 +#define MSR_PM_BASE2 0xc0000000 +#define MSR_PM_BASE3 0xc0010000 +#define SVM_MSR_VM_HSAVE_PA 0xc0010117 + +#define UNLOAD_HV_MAGIC 0x40067420 + +#define SVM_SUPPORT_LEAF 0x80000001 +#define SVM_SUPPORT_BIT 2 + +#define SVM_MSR_VM_CR 0xc0010114 +#define VM_CR_SVMDIS_BIT 4 + +#define VMEXIT_CPUID 0x72 +#define VMEXIT_MSRPROT 0x7C + +/* VECTOR 8 bits = 0x0D (GP) */ +/* TYPE 3 bits = 0x3 (Fault) */ +/* EV 1 bit = 0x1 (Error Code Valid) */ +/* reserved 19 bits */ +/* V 1 bit = 0x1 (Valid) */ +/* ERRORCODE 32 bits = 0x0 */ +#define GP0_EVENTINJ (0x0D | (0x3 << 8) | (0x1 << 11) | (0x1 << 31)) + + +#ifndef page_to_phys +#define page_to_phys(page) PFN_PHYS(page_to_pfn(page)) +#endif + +/* The hypervisor doesn't handle nested virtualization, so attempting to + * virtualize a kernel currently using virtualization features will probably + * result in an immediate crash. If you know better you can tell the module + * to attempt the virtualization anyway */ +static int ignore_svm_enabled = 0; +module_param(ignore_svm_enabled, int, 0); + +static struct { + struct page* msrpm_page; + u64 msrpm_pa; + bool prev_cpuid_fault_cap; + bool prev_svm_enabled; +} shared_data; + + +inline static void vmsave(u64 vmcb_pa) { + asm volatile ("vmsave" : : "a" (vmcb_pa) : "memory"); +} + +inline static void vmload(u64 vmcb_pa) { + asm volatile ("vmload" : : "a" (vmcb_pa) : "memory"); +} + +inline static void do_cpuid(u32* eax, u32* ebx, u32* ecx, u32* edx) { + asm volatile ("cpuid" + : "+a"(*eax), "=b"(*ebx), "+c"(*ecx), "=d"(*edx) + : + : "memory"); +} + +inline static void do_cpuid_leaf(u32 leaf, u32* eax, u32* ebx, + u32* ecx, u32* edx) { + asm volatile ("cpuid" + : "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx) + : "a"(leaf) + : "memory"); +} + +inline static void do_wrmsr(u32 msr, u64 val) { + asm volatile ("wrmsr" : : "c"(msr), "a"((u32)val), "d" ((u32)(val >> 32)) : "memory"); +} + +inline static u64 do_rdmsr(u32 msr) { + u32 low, high; + asm volatile ("rdmsr" : "=a"(low), "=d" (high) : "c"(msr)); + return low | ((u64)high) << 32; +} + +/* Raw writes and reads for cr registers. The kernel has it's own safer + * versions, however, all the writes we do should use values provided by the + * kernel, so these consistent raw versions are cleaner to use. */ +#define define_cr_ops(cr) \ +inline static u64 do_read_ ## cr (void) {\ + u64 val; \ + asm volatile ("movq %%" #cr ", %0" : "=r" (val) : :); \ + return val; \ +} \ +inline static void do_write_ ## cr (u64 val) {\ + asm volatile ("movq %0, %%" #cr : :"r" (val) :); \ +} +define_cr_ops(cr0); +define_cr_ops(cr2); +define_cr_ops(cr3); +define_cr_ops(cr4); + +/* Checks the relevant CPUID bits and MSR registers to determine SVM support + * since the hypervisor doesn't use features like NPT or decode assists, + * very few checks are needed */ +static bool check_svm_support(void) { + u32 eax, ebx, ecx, edx; + + /* check for "AuthenticAMD" on leaf 0 */ + do_cpuid_leaf(0, &eax, &ebx, &ecx, &edx); + if (!(ebx == 'htuA' && edx == 'itne' && ecx == 'DMAc')) + return false; + + /* check for SVM support */ + do_cpuid_leaf(SVM_SUPPORT_LEAF, &eax, &ebx, &ecx, &edx); + if (!(ecx & (1U << SVM_SUPPORT_BIT))) + return false; + + /* check if SVM is disabled by the BIOS */ + if (do_rdmsr(SVM_MSR_VM_CR) & BIT_ULL(VM_CR_SVMDIS_BIT)) + return false; + + return true; +} + +/* capture_context saves all GPR's, as well as RIP and RFLAGS as they are at + * it's return, except for RAX, which is saved as 0, but returned as 1 */ +noinline_for_stack u64 capture_context(struct InitialContext* registers); + +/* run_vm repeatedly runs the VMRUN instruction, effectively continuing to + * run the guest (the OS), when an intercepted event happens, it calls the + * handle_vm_exit function with the current state of the guest. If the call + * returns a non-zero value it begins the process of devirtualizing the + * processor */ +__attribute__((noreturn)) void run_vm(struct ProcessorStatus* status); + +/* called when the guest would execute a CPUID instruction*/ +static u64 handle_cpuid(struct ProcessorStatus* status) { + u32 eax = status->guest_registers.rax; + u32 ebx; + u32 ecx = status->guest_registers.rcx; + u32 edx; + if(status->vmcb.state_area.cpl == 0) { + switch (eax) { + case UNLOAD_HV_MAGIC: + status->vmcb.state_area.rip += 2; + return 1; /* tell the hypervisor to devirtualize the processor */ + } + } else { + if(status->cpuid_fault) { /* if CPUID should fault */ + status->vmcb.control_area.eventinj = GP0_EVENTINJ; /* inject GP */ + return 0; + } + } + /* otherwise, run CPUID and increase RIP */ + do_cpuid(&eax, &ebx, &ecx, &edx); + status->guest_registers.rax = eax; + status->guest_registers.rbx = ebx; + status->guest_registers.rcx = ecx; + status->guest_registers.rdx = edx; + status->vmcb.state_area.rip += 2; + return 0; +} + +/* called when the guest would execute a read or write to a protected MSR */ +static u64 handle_msr(struct ProcessorStatus* status) { + /* the msr the guest is trying to access */ + u32 msr = status->guest_registers.rcx; + + bool write_access = (status->vmcb.control_area.exitinfo1 != 0); + /* to emulate cpuid_fault, writes and reads to the corresponding MSR are + * intercepted */ + if (write_access) { + u64 value = (status->guest_registers.rdx << 32) | + (u32)status->guest_registers.rax; +#ifdef MSR_K7_HWCR_CPUID_USER_DIS_BIT + /* If the MSR to enable / disable cpuid_fault is being written to */ + if(msr == MSR_K7_HWCR) { + /* update whether the hypervisor should inject a fault on CPUID */ + status->cpuid_fault = value & BIT_ULL(MSR_K7_HWCR_CPUID_USER_DIS_BIT); + /* write the value to the register, with the cpuid_fault bit clear */ + do_wrmsr(msr, value & ~BIT_ULL(MSR_K7_HWCR_CPUID_USER_DIS_BIT)); + } +#else + /* Older kernels will attempt to enable cpuid_fault using the intel + * MSR */ + if(msr == MSR_MISC_FEATURES_ENABLES) { + status->cpuid_fault = value & MSR_MISC_FEATURES_ENABLES_CPUID_FAULT; + } +#endif + else { + /* If we don't care about the MSR, do the write directly */ + do_wrmsr(msr, value); + } + } else { + u64 value; +#ifdef MSR_K7_HWCR_CPUID_USER_DIS_BIT + /* If the MSR to enable / disable cpuid_fault is being read */ + if(msr == MSR_K7_HWCR) { + value = do_rdmsr(msr); + /* reflect the current cpuid_fault status to the guest */ + if(status->cpuid_fault) + value |= BIT_ULL(MSR_K7_HWCR_CPUID_USER_DIS_BIT); + } +#else + /* Older kernels will attempt to enable cpuid_faulting using the intel + * MSR */ + if(msr == MSR_MISC_FEATURES_ENABLES) { + value = 0; + if(status->cpuid_fault) + value |= MSR_MISC_FEATURES_ENABLES_CPUID_FAULT; + } +#endif + else { + /* If we don't care about the MSR, do the read directly */ + value = do_rdmsr(msr); + } + status->guest_registers.rax = (u32)value; + status->guest_registers.rdx = (u32)(value >> 32); + } + status->vmcb.state_area.rip += 2; + return 0; +} + +/* consistent functions to write segment selectors */ +#define define_sel_ops(sel) \ +inline static u64 read_ ## sel ## _sel(void) {\ + u16 sel; \ + asm volatile ("movw %%" #sel ", %0" : "=r" (sel) : :); \ + return sel; \ +} \ +inline static void write_ ## sel ## _sel(u16 sel) {\ + asm volatile ("movw %0, %%" #sel : :"r" (sel) :); \ +} +define_sel_ops(ds); +define_sel_ops(es); +define_sel_ops(ss); +inline static u64 read_cs_sel(void) { + u16 cs; + asm volatile("movw %%cs, %0" : "=r"(cs) : :); + return cs; +} +/* a direct move into cs is not a valid instruction, so the value is written + * via a far jump */ +inline static void write_cs_sel(u16 cs) { + asm volatile("movzwq %0,%%rax\n\t" + "pushq %%rax\n\t" + "leaq curr_ip(%%rip),%%rax\n\t" + "pushq %%rax\n\t" + "lretq\n\t" + "curr_ip:": : "r"(cs) : "rax"); +}; + +/* To end the virtualization the host needs to put itself the guest was just + * in, this effectively does the opposite to setup_guest_state */ +static void restore_host_state(struct ProcessorStatus* status) { + struct VMCB* guest_vmcb = &status->vmcb; + struct desc_ptr gdt_ptr; + struct desc_ptr idt_ptr; + /* Load other state that might have changed */ + vmload(status->vmcb_pa); + + /* Restore the hsave address before the processor was virtualized */ + do_wrmsr(SVM_MSR_VM_HSAVE_PA, status->prev_hsave_pa); + + do_wrmsr(MSR_EFER, guest_vmcb->state_area.efer); + + idt_ptr.address = guest_vmcb->state_area.idtr.base; + idt_ptr.size = guest_vmcb->state_area.idtr.limit; + gdt_ptr.address = guest_vmcb->state_area.gdtr.base; + gdt_ptr.size = guest_vmcb->state_area.gdtr.limit; + + /* Restore gdt and idt. Done for correctness */ + native_load_gdt(&gdt_ptr); + native_load_idt(&idt_ptr); + + /* Load segment selectors from the guest. Also for correctness */ + write_es_sel(guest_vmcb->state_area.es.selector); + write_ss_sel(guest_vmcb->state_area.ss.selector); + write_ds_sel(guest_vmcb->state_area.ds.selector); + write_cs_sel(guest_vmcb->state_area.cs.selector); + + /* run_vm will resume running the OS by setting this rip and rsp */ + status->guest_registers.rax = guest_vmcb->state_area.rip; + status->guest_registers.rsp = guest_vmcb->state_area.rsp; + + /* will be used by the OS to cleanup the per processor data */ + status->guest_registers.rbx = (u64)status; +} + +/* Everytime an intercepted instruction is excecuted (currently only + * wrmsr/rdmsr to the cpuid_fault register, cpuid and runvm (required by + * the processor)), the guest's state is saved and the hypervisor calls + * this function */ +u64 handle_vm_exit(struct ProcessorStatus* status) { + status->guest_registers.rsp = status->vmcb.state_area.rsp; + status->guest_registers.rax = status->vmcb.state_area.rax; + + u64 exitcode = status->vmcb.control_area.exitcode; + u64 result = 0; + switch(exitcode) { + case VMEXIT_CPUID: + result = handle_cpuid(status); + break; + case VMEXIT_MSRPROT: + result = handle_msr(status); + break; + } + if(result) { /* begin the devirtualization process */ + restore_host_state(status); + } + status->vmcb.state_area.rsp = status->guest_registers.rsp; + status->vmcb.state_area.rax = status->guest_registers.rax; + return result; /* tell run_vm if it should keep running the guest */ +} + +/* Used to initialize the segment registers (cs, ds, es, ss) in the VMCB */ +static void set_descriptor_from_gdt(struct desc_ptr* gdtr, u16 selector, + struct SegmentDescriptor* desc) { + desc->selector = selector; + + u64 idx = selector & ~0b111; /* Mask out the TI and RPL bits */ + + if(!idx) { + desc->attrib = 0; + desc->limit = 0; + desc->base = 0; + return; + } + + /* Read the 8 bytes of the descriptor from the gdt, there's also 16-byte + * descriptors (e.g. TSS, LDT), but the function is not used for them, so + * they're not handled */ + u64 raw = *(u64*) (gdtr->address + idx); + + /* Concatenate the attribute bits */ + desc->attrib = ((raw & (0xFFL << 40)) >> 40) | + ((raw & (0xFL << 52)) >> 44); + /* Concatenate the limit bits */ + desc->limit = (raw & 0xFFFF) | ((raw & (0xFL << 48)) >> 32); + /* If the granularity is 4kb, store the effective limit */ + if(raw & (0x1L << 55)) desc->limit = (desc->limit << 12) | 0xFFFL; + /* Concatenate the base address bits */ + desc->base = ((raw & (0xFFFFL << 16)) >> 16) | + ((raw & (0xFFL << 32)) >> 16) | + ((raw & (0xFFL << 56)) >> 32); +} + +/* This setups all of the state needed to run a vm with the current status + * of the processor */ +static void setup_guest_state(struct page* host_status_page, + struct InitialContext* initial_context) { + u64 host_status_pa = page_to_phys(host_status_page); + u64 guest_vmcb_pa = host_status_pa + HOST_VMCB_OFFSET; + u64 host_vmcb_pa = host_status_pa + HOST_HOST_VMCB_OFFSET; + u64 host_save_pa = host_status_pa + HOST_HOST_SAVE_OFFSET; + + struct ProcessorStatus* host_status = page_address(host_status_page); + host_status->vmcb_pa = guest_vmcb_pa; + host_status->host_vmcb_pa = host_vmcb_pa; + + /* used to cleanup after the processor is devirtualized */ + host_status->page_ptr = host_status_page; + + host_status->guest_registers = initial_context->regs; + struct VMCB* guest_vmcb = &host_status->vmcb; + + struct desc_ptr gdt_ptr; + struct desc_ptr idt_ptr; + + native_store_gdt(&gdt_ptr); + store_idt(&idt_ptr); + + /* intercept MSRs defined by MSR prot */ + guest_vmcb->control_area.intercept_vector3.msr_prot = 1; + guest_vmcb->control_area.msrpm_base_pa = shared_data.msrpm_pa; + + /* intercept the CPUID instruction */ + guest_vmcb->control_area.intercept_vector3.cpuid_inst = 1; + + /* intercept the VMRUN instruction (required to run VMRUN) */ + guest_vmcb->control_area.intercept_vector4.vmrun_inst = 1; + + /* the guest uses it's own address space, 1 is the safest value to use */ + guest_vmcb->control_area.guest_asid = 1; + + u32 eax, ebx, ecx, edx; + do_cpuid_leaf(0x80000008, &eax, &ebx, &ecx, &edx); + if(ebx & (1 << 3)) { + do_cpuid_leaf(0x8000000a, &eax, &ebx, &ecx, &edx); + if(edx & (1 << 24)) { + guest_vmcb->control_area.virtualization_control0.invlpg_tlbsync_enable = 1; + } + } + + guest_vmcb->state_area.gdtr.base = gdt_ptr.address; + guest_vmcb->state_area.gdtr.limit = gdt_ptr.size; + guest_vmcb->state_area.idtr.base = idt_ptr.address; + guest_vmcb->state_area.idtr.limit = idt_ptr.size; + + u16 cs_selector = read_cs_sel(); + set_descriptor_from_gdt(&gdt_ptr, cs_selector, + &guest_vmcb->state_area.cs); + u16 ds_selector = read_ds_sel(); + set_descriptor_from_gdt(&gdt_ptr, ds_selector, + &guest_vmcb->state_area.ds); + u16 es_selector = read_es_sel(); + set_descriptor_from_gdt(&gdt_ptr, es_selector, + &guest_vmcb->state_area.es); + u16 ss_selector = read_ss_sel(); + set_descriptor_from_gdt(&gdt_ptr, ss_selector, + &guest_vmcb->state_area.ss); + + guest_vmcb->state_area.efer = do_rdmsr(MSR_EFER); + guest_vmcb->state_area.cr0 = do_read_cr0(); + guest_vmcb->state_area.cr2 = do_read_cr2(); + guest_vmcb->state_area.cr3 = do_read_cr3(); + guest_vmcb->state_area.cr4 = do_read_cr4(); + + guest_vmcb->state_area.rflags = initial_context->rflags; + guest_vmcb->state_area.rsp = initial_context->regs.rsp; + guest_vmcb->state_area.rip = initial_context->rip; + guest_vmcb->state_area.rax = initial_context->regs.rax; + + vmsave(guest_vmcb_pa); + + /* Save the hsave address before the hypervisor is loaded */ + /* (If the kvm_amd kernel module is loaded, this value will already be + * setup and changing it and trying to run a kvm vm will crash the OS) */ + host_status->prev_hsave_pa = do_rdmsr(SVM_MSR_VM_HSAVE_PA); + do_wrmsr(SVM_MSR_VM_HSAVE_PA, host_save_pa); + + /* save another copy of the host state, used to provide a more consistent + * host state at vmexit */ + vmsave(host_vmcb_pa); +} + +static int virtualize_processor(void* processor_number) { + struct page* host_status_page; + int order = get_order(sizeof(struct ProcessorStatus)); + host_status_page = alloc_pages(GFP_KERNEL, order); + if (!host_status_page) + goto host_status_page_failed; + + unsigned long flags; + get_cpu(); + local_irq_save(flags); + + memset(page_address(host_status_page), 0, PAGE_SIZE * (1 << order)); + + struct InitialContext context; + + + /* Capture the context to be used to initialize the guest, since it + * returns 1 but the stored state has 0 as it's return, when the guest + * starts execution at the stored state it will not enter into the if. + * */ + if(capture_context(&context)) { + + do_wrmsr(MSR_EFER, do_rdmsr(MSR_EFER) | EFER_SVME); /* Enable SVME */ + + setup_guest_state(host_status_page, &context); + struct ProcessorStatus* host_status = page_address(host_status_page); + + /* Kinda ugly, effectively sets a CR3 for the host that will + * always be safe to access the hypervisor's code from + * */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 9, 0) + leave_mm(); +#else + leave_mm(smp_processor_id()); +#endif + run_vm(host_status); + BUG(); + } + + /* Only the guest should run this code */ + put_cpu(); + + pr_info("Processor %d virtualized\n", (u32)(u64)processor_number); + return 0; +host_status_page_failed: + local_irq_restore(flags); + put_cpu(); + + return -ENOMEM; +} + +static int check_svm_on_cpu(void*) { + return do_rdmsr(MSR_EFER) & EFER_SVME; +} + +static bool check_svm_status(void) { + u32 svm_enabled = 0; + cpus_read_lock(); + u32 cpu; + for_each_online_cpu(cpu) { + svm_enabled |= smp_call_on_cpu(cpu, check_svm_on_cpu, NULL, true); + } + cpus_read_unlock(); + return svm_enabled; +} + + +static int devirtualize_processor(void* processor_number) { + int order = get_order(sizeof(struct ProcessorStatus)); + unsigned long flags; + get_cpu(); + local_irq_save(flags); + + u64 rax = UNLOAD_HV_MAGIC; + u64 rbx, rcx, rdx; + asm volatile("cpuid":"+a"(rax),"=b"(rbx),"=c"(rcx),"=d"(rdx)::"memory"); + struct ProcessorStatus* status = NULL; + + if(rax != UNLOAD_HV_MAGIC) { + status = (struct ProcessorStatus*)rbx; + struct VMCB* guest_vmcb = &status->vmcb; + + do_write_cr3(guest_vmcb->state_area.cr3); + do_write_cr4(guest_vmcb->state_area.cr4); + do_write_cr2(guest_vmcb->state_area.cr2); + do_write_cr0(guest_vmcb->state_area.cr0); + } + + if(!shared_data.prev_svm_enabled) + do_wrmsr(MSR_EFER, do_rdmsr(MSR_EFER) & ~EFER_SVME); + + local_irq_restore(flags); + put_cpu(); + if(status)__free_pages(status->page_ptr, order); + + + pr_info("Processor %d devirtualized\n", (u32)(u64)processor_number); + return 0; +} + +/* called when a Power Management (e.g. suspend) event is about to happen */ +static int handle_pm_notification(struct notifier_block* nb, unsigned long action, void *data) { + + if(action == PM_HIBERNATION_PREPARE || action == PM_SUSPEND_PREPARE) { + /* on suspend or hibernation svm is disabled, so + * all processors need to be devirtualized */ + cpus_read_lock(); + u32 cpu; + for_each_online_cpu(cpu) { + smp_call_on_cpu(cpu, devirtualize_processor, (void*)(u64)cpu, true); + } + cpus_read_unlock(); + /* return the cpuid_fault bit capability to it's previous value */ + if(!shared_data.prev_cpuid_fault_cap) + clear_bit(X86_FEATURE_CPUID_FAULT, + (unsigned long *)(boot_cpu_data.x86_capability)); + } + if(action == PM_POST_HIBERNATION || action == PM_POST_SUSPEND) { + /* revirtualize all processors after suspend or hibernation */ + cpus_read_lock(); + u32 cpu; + for_each_online_cpu(cpu) { + smp_call_on_cpu(cpu, virtualize_processor, (void*)(u64)cpu, true); + } + cpus_read_unlock(); + shared_data.prev_cpuid_fault_cap = test_bit(X86_FEATURE_CPUID_FAULT, + (unsigned long *)(boot_cpu_data.x86_capability)); + set_bit(X86_FEATURE_CPUID_FAULT, + (unsigned long *)(boot_cpu_data.x86_capability)); + } + return 0; +} + +static struct notifier_block pm_notifier = { + .notifier_call = handle_pm_notification +}; + +static int __init init_emulation(void) { + if (!check_svm_support()) { + pr_info("Processor not supported\n"); + return -ENODEV; + } + shared_data.prev_svm_enabled = check_svm_status(); + + if(shared_data.prev_svm_enabled && !ignore_svm_enabled) { + pr_info("SVM already enabled\n"); + return -ENODEV; + } + + shared_data.msrpm_page = alloc_pages(GFP_KERNEL, 1); + if (!shared_data.msrpm_page) + goto msrpm_failed; + shared_data.msrpm_pa = page_to_phys(shared_data.msrpm_page); + + memset(page_address(shared_data.msrpm_page), 0, 0x2000); + unsigned char* section_1_start = (unsigned char*) + page_address(shared_data.msrpm_page); + unsigned char* section_3_start = (unsigned char*) + page_address(shared_data.msrpm_page) + 0x1000; + +#ifdef MSR_K7_HWCR_CPUID_USER_DIS_BIT + set_bit((MSR_K7_HWCR - MSR_PM_BASE3) * 2, + (unsigned long*) section_3_start); + set_bit((MSR_K7_HWCR - MSR_PM_BASE3) * 2 + 1, + (unsigned long*) section_3_start); +#else /* on older kernels intercept the intel register instead */ + set_bit((MSR_MISC_FEATURES_ENABLES - MSR_PM_BASE1) * 2, + (unsigned long*) section_1_start); + set_bit((MSR_MISC_FEATURES_ENABLES - MSR_PM_BASE1) * 2 + 1, + (unsigned long*) section_1_start); +#endif + + cpus_read_lock(); + u32 cpu; + for_each_online_cpu(cpu) { + smp_call_on_cpu(cpu, virtualize_processor, (void*)(u64)cpu, true); + } + cpus_read_unlock(); + shared_data.prev_cpuid_fault_cap = test_bit(X86_FEATURE_CPUID_FAULT, + (unsigned long *)(boot_cpu_data.x86_capability)); + set_bit(X86_FEATURE_CPUID_FAULT, + (unsigned long *)(boot_cpu_data.x86_capability)); + + register_pm_notifier(&pm_notifier); + + return 0; + +msrpm_failed: + return -ENOMEM; +} + +static void __exit deinit_emulation(void) { + unregister_pm_notifier(&pm_notifier); + if(!shared_data.prev_cpuid_fault_cap) + clear_bit(X86_FEATURE_CPUID_FAULT, + (unsigned long *)(boot_cpu_data.x86_capability)); + cpus_read_lock(); + u32 cpu; + for_each_online_cpu(cpu) { + smp_call_on_cpu(cpu, devirtualize_processor, (void*)(u64)cpu, true); + } + + cpus_read_unlock(); + if (shared_data.msrpm_page) + __free_pages(shared_data.msrpm_page, 1); +} + + + +module_init(init_emulation); +module_exit(deinit_emulation); + +MODULE_LICENSE("GPL"); diff --git a/pkgs/cpuid-fault-emulation/source/src/run_vm.S b/pkgs/cpuid-fault-emulation/source/src/run_vm.S new file mode 100644 index 0000000..1fea9ef --- /dev/null +++ b/pkgs/cpuid-fault-emulation/source/src/run_vm.S @@ -0,0 +1,121 @@ +#include +#include +#include + +#define save_to_offset_from(val, off, from) movq val, off -(HOST_STACK_OFFSET + HOST_STACK_SIZE) (from) +#define mov_from_offset_from(off, reg, from) movq off -(HOST_STACK_OFFSET + HOST_STACK_SIZE) (from), reg +#define save_to_offset(val, off) save_to_offset_from(val, off, %rsp) +#define mov_from_offset(off, reg) mov_from_offset_from(off, reg, %rsp) +#define save_to_reg_from(val, REG, from) save_to_offset_from(val, HOST_REGISTER_OFFSET + GUEST_ ## REG ## _OFFSET, from) +#define mov_from_reg_from(REG, reg, from) mov_from_offset_from(HOST_REGISTER_OFFSET + GUEST_ ## REG ## _OFFSET, reg, from) +#define save_to_reg(val, REG) save_to_reg_from(val, REG, %rsp) +#define mov_from_reg(REG, reg) mov_from_reg_from(REG, reg, %rsp) +SYM_CODE_START(run_vm) +#ifdef ENDBR + ENDBR +#endif + leaq HOST_STACK_OFFSET + HOST_STACK_SIZE(%_ASM_ARG1), %rsp + +vmloop: + mov_from_offset(HOST_HOST_VMCB_PA_OFFSET, %rax) + vmsave + + mov_from_offset(HOST_VMCB_PA_OFFSET, %rax) + vmload + + mov_from_reg(RBX, %rbx) + mov_from_reg(RCX, %rcx) + mov_from_reg(RDX, %rdx) + mov_from_reg(RSI, %rsi) + mov_from_reg(RDI, %rdi) + mov_from_reg(RBP, %rbp) + + mov_from_reg(R8, %r8) + mov_from_reg(R9, %r9) + mov_from_reg(R10, %r10) + mov_from_reg(R11, %r11) + mov_from_reg(R12, %r12) + mov_from_reg(R13, %r13) + mov_from_reg(R14, %r14) + mov_from_reg(R15, %r15) + + vmrun + + vmsave + + mov_from_offset(HOST_HOST_VMCB_PA_OFFSET, %rax) + vmload + + save_to_reg(%rbx, RBX) + save_to_reg(%rcx, RCX) + save_to_reg(%rdx, RDX) + save_to_reg(%rsi, RSI) + save_to_reg(%rdi, RDI) + save_to_reg(%rbp, RBP) + + save_to_reg(%r8, R8) + save_to_reg(%r9, R9) + save_to_reg(%r10, R10) + save_to_reg(%r11, R11) + save_to_reg(%r12, R12) + save_to_reg(%r13, R13) + save_to_reg(%r14, R14) + save_to_reg(%r15, R15) + + leaq -HOST_STACK_SIZE(%rsp), %_ASM_ARG1 + + /* Save volatile XMM registers */ + sub $0x80, %rsp + movaps %xmm0, 0x20(%rsp) + movaps %xmm1, 0x30(%rsp) + movaps %xmm2, 0x40(%rsp) + movaps %xmm3, 0x50(%rsp) + movaps %xmm4, 0x60(%rsp) + movaps %xmm5, 0x70(%rsp) + + sub $0x8, %rsp + call handle_vm_exit + add $0x8, %rsp + + /* Restore volatile XMM registers */ + movaps 0x70(%rsp), %xmm5 + movaps 0x60(%rsp), %xmm4 + movaps 0x50(%rsp), %xmm3 + movaps 0x40(%rsp), %xmm2 + movaps 0x30(%rsp), %xmm1 + movaps 0x20(%rsp), %xmm0 + add $0x80, %rsp + + test %rax, %rax + + jz vmloop + + mov_from_reg(RBX, %rbx) /* now holds rflags */ + pushq %rbx + popfq + leaq (%rsp), %rax; + mov_from_reg(RBX, %rbx) + mov_from_reg(RCX, %rcx) + mov_from_reg(RDX, %rdx) + mov_from_reg(RSI, %rsi) + mov_from_reg(RDI, %rdi) + mov_from_reg(RBP, %rbp) + + mov_from_reg(R8, %r8) + mov_from_reg(R9, %r9) + mov_from_reg(R10, %r10) + mov_from_reg(R11, %r11) + mov_from_reg(R12, %r12) + mov_from_reg(R13, %r13) + mov_from_reg(R14, %r14) + mov_from_reg(R15, %r15) + + mov_from_reg(RSP, %rsp) + mov_from_reg_from(RAX, %rax, %rax) /* now holds rip */ + + stgi + pushq %rax + RET + + +SYM_CODE_END(run_vm)