update
This commit is contained in:
@@ -2,8 +2,14 @@
|
|||||||
pkgs,
|
pkgs,
|
||||||
sls-steam,
|
sls-steam,
|
||||||
options,
|
options,
|
||||||
|
config,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
|
let
|
||||||
|
cpuid-fault-emulation = pkgs.callPackage ./pkgs/cpuid-fault-emulation {
|
||||||
|
kernel = config.boot.kernelPackages.kernel;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
@@ -66,6 +72,7 @@
|
|||||||
"kvm.ignore_msrs=1"
|
"kvm.ignore_msrs=1"
|
||||||
"mitigations=off"
|
"mitigations=off"
|
||||||
"amdgpu.ppfeaturemask=0xffffffff"
|
"amdgpu.ppfeaturemask=0xffffffff"
|
||||||
|
"clearcpuid=umip"
|
||||||
];
|
];
|
||||||
|
|
||||||
xdg = {
|
xdg = {
|
||||||
@@ -83,6 +90,18 @@
|
|||||||
boot.loader.grub.enable = true;
|
boot.loader.grub.enable = true;
|
||||||
boot.loader.grub.device = "nodev";
|
boot.loader.grub.device = "nodev";
|
||||||
boot.loader.grub.efiSupport = true;
|
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"; # Define your hostname.
|
networking.hostName = "nixos"; # Define your hostname.
|
||||||
networking.firewall.enable = false;
|
networking.firewall.enable = false;
|
||||||
|
|||||||
Generated
+27
-27
@@ -18,11 +18,11 @@
|
|||||||
"dank-qml-common": {
|
"dank-qml-common": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1784647395,
|
"lastModified": 1784935106,
|
||||||
"narHash": "sha256-kcLSJC8XBzmWoSBc90Zn81qrNsqWMkwQ1m/zZixOw30=",
|
"narHash": "sha256-aVgOBRynme6XNKYCZlf/oCjPDZFwddyUQPRRkEupC3c=",
|
||||||
"owner": "AvengeMedia",
|
"owner": "AvengeMedia",
|
||||||
"repo": "dank-qml-common",
|
"repo": "dank-qml-common",
|
||||||
"rev": "1919595f0dde4f5bf5ac0baa1902ff6d070971d5",
|
"rev": "a172b39841d8f42bac46ac133b76cade1fae91b4",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -40,11 +40,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1784816066,
|
"lastModified": 1784936204,
|
||||||
"narHash": "sha256-j2jJmxgkcZemmusvQysK+bN/dDhvqYD//IPmcVsfhR0=",
|
"narHash": "sha256-XNbDvIaPzqqIpgJynqSADAj7Yf8KlGJTo5S/fQJUBxs=",
|
||||||
"owner": "AvengeMedia",
|
"owner": "AvengeMedia",
|
||||||
"repo": "DankMaterialShell",
|
"repo": "DankMaterialShell",
|
||||||
"rev": "d818067bee842e432fc8ffd94bf3d0801d190c7f",
|
"rev": "8bb7396362357650a80dcc8d81407095c91c7dcf",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -131,11 +131,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1784064149,
|
"lastModified": 1784926331,
|
||||||
"narHash": "sha256-yJ+YH7ZjNTnU33wnNRs21dGILG+5Ewt2s+B4OAi8SOU=",
|
"narHash": "sha256-EiyJny6oq41fes/x+vWmmzlbjZxwy+8TtbaQqKXyRgY=",
|
||||||
"owner": "rPlakama",
|
"owner": "rPlakama",
|
||||||
"repo": "gsr-ui-nix",
|
"repo": "gsr-ui-nix",
|
||||||
"rev": "42838d89e48b5c32bcf0e6a670e5daaa084229dc",
|
"rev": "e463d47ca8724de7a83c394d9e323c6d9c449508",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -151,11 +151,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1784789275,
|
"lastModified": 1784913159,
|
||||||
"narHash": "sha256-cgRTWuG+u1tBPhm01JrId2k0Bni09phVJ1Q0BZlRd7M=",
|
"narHash": "sha256-JWq0BfjO4ktpH5USfQNQzdvHpIDT8fSKD5K7LvdMRFs=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"rev": "3b0e6bbd65869af1beadf5963a99befc179d209f",
|
"rev": "079a3b5d1aa6a719920a51316253b7d6dd22738d",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -192,11 +192,11 @@
|
|||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"dir": "packages/nix",
|
"dir": "packages/nix",
|
||||||
"lastModified": 1784048235,
|
"lastModified": 1784860807,
|
||||||
"narHash": "sha256-ar1xg5HFbz6XJ/BAOo37ewfnMcsLHj0/088soIvXKIo=",
|
"narHash": "sha256-nznQFS9H8er9bTwxKG4LSa2D0lGsxIPUqDuWa1rbJkA=",
|
||||||
"owner": "SteamClientHomebrew",
|
"owner": "SteamClientHomebrew",
|
||||||
"repo": "Millennium",
|
"repo": "Millennium",
|
||||||
"rev": "df5a3572fd2366b4aa689abd655ee48296ba1afd",
|
"rev": "266e41ea8924c41e51145ae986a9bdf68f9415d9",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -256,11 +256,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs_2": {
|
"nixpkgs_2": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1784819053,
|
"lastModified": 1784992771,
|
||||||
"narHash": "sha256-LjxwsNf8fZonvODqPaR6vzAN43ShWji4GaOVUMBv94w=",
|
"narHash": "sha256-xEE5I69+WNqcs7Z0v5D9xwcHYRbvC8k/fKBmlUBdCp4=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "d0f7f5759c3c0ef348c999a0b96eb03071a53f48",
|
"rev": "37bfb33419c6e367e8bb6f44041eaecf953b5236",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -324,11 +324,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1784819646,
|
"lastModified": 1784993591,
|
||||||
"narHash": "sha256-q7etFrDCAZkGwHQDazozduWrxHc9AazJcBNVTBAM94g=",
|
"narHash": "sha256-4/evHMKmkO482OWfvaPk4uwyvUJxrJWcxXhNHqMQbDU=",
|
||||||
"owner": "noctalia-dev",
|
"owner": "noctalia-dev",
|
||||||
"repo": "noctalia",
|
"repo": "noctalia",
|
||||||
"rev": "6008a66739beb43f8d1509bda459ab5c6e59073f",
|
"rev": "62975eea9ea64171c35382d904c7564cd3d4077b",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -467,11 +467,11 @@
|
|||||||
"rust-overlay": "rust-overlay"
|
"rust-overlay": "rust-overlay"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1784743179,
|
"lastModified": 1784975066,
|
||||||
"narHash": "sha256-zEFky4d+WKVfbWVzcGkECsQgwW0XZWilGA5VQpgtFek=",
|
"narHash": "sha256-EoSjKF8AMBbtupTmen2n+CEJnWVW2ynSYIMNHYTTT2s=",
|
||||||
"owner": "sxyazi",
|
"owner": "sxyazi",
|
||||||
"repo": "yazi",
|
"repo": "yazi",
|
||||||
"rev": "58f1013348c969538352e3105f58e8d8e870a092",
|
"rev": "533d1aa3fbb9b388745c72d34d377ff8e8326d84",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -486,11 +486,11 @@
|
|||||||
"nixpkgs": "nixpkgs_5"
|
"nixpkgs": "nixpkgs_5"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1784586513,
|
"lastModified": 1784985989,
|
||||||
"narHash": "sha256-ewIv3xH9bQK7uMkU3xK6NWFEW5oIuAtIny8ifJwcY/E=",
|
"narHash": "sha256-Mz4G81HXJlUtHoJtA31D+Ob7uma2BX7E/y7F9QazuFc=",
|
||||||
"owner": "0xc000022070",
|
"owner": "0xc000022070",
|
||||||
"repo": "zen-browser-flake",
|
"repo": "zen-browser-flake",
|
||||||
"rev": "0ea161e9ac257510acabfb6e9dbf13630298760d",
|
"rev": "a8f9b6d014c9cfe0615dccb2bc7808713f6e62c2",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
home.username = "user";
|
home.username = "user";
|
||||||
home.homeDirectory = "/home/user";
|
home.homeDirectory = "/home/user";
|
||||||
|
|
||||||
xdg.userDirs = {
|
xdg.userDirs = {
|
||||||
enable = true;
|
enable = true;
|
||||||
createDirectories = false;
|
createDirectories = false;
|
||||||
@@ -23,6 +24,23 @@
|
|||||||
SCREENSHOTS = "${config.home.homeDirectory}/Pictures/Screenshots";
|
SCREENSHOTS = "${config.home.homeDirectory}/Pictures/Screenshots";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
xdg.mimeApps = {
|
||||||
|
enable = true;
|
||||||
|
defaultApplications = {
|
||||||
|
"inode/directory" = [ "nemo.desktop" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
dconf = {
|
||||||
|
settings = {
|
||||||
|
"org/cinnamon/desktop/applications/terminal" = {
|
||||||
|
exec = "kitty";
|
||||||
|
# exec-arg = ""; # argument
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
home.pointerCursor = {
|
home.pointerCursor = {
|
||||||
enable = true;
|
enable = true;
|
||||||
gtk.enable = true;
|
gtk.enable = true;
|
||||||
|
|||||||
+9
-3
@@ -24,18 +24,16 @@
|
|||||||
pwvucontrol
|
pwvucontrol
|
||||||
lsof
|
lsof
|
||||||
picard
|
picard
|
||||||
klassy
|
|
||||||
exiftool
|
exiftool
|
||||||
tlrc
|
tlrc
|
||||||
libnotify
|
libnotify
|
||||||
trash-cli
|
trash-cli
|
||||||
nicotine-plus
|
|
||||||
spek
|
spek
|
||||||
ffmpeg
|
ffmpeg
|
||||||
vlc
|
vlc
|
||||||
# wine
|
# wine
|
||||||
ripgrep
|
ripgrep
|
||||||
nemo
|
nemo-with-extensions
|
||||||
unrar
|
unrar
|
||||||
papirus-icon-theme
|
papirus-icon-theme
|
||||||
rust-analyzer
|
rust-analyzer
|
||||||
@@ -55,6 +53,14 @@
|
|||||||
playerctl
|
playerctl
|
||||||
musicpresence
|
musicpresence
|
||||||
nixd
|
nixd
|
||||||
|
libsForQt5.qt5ct
|
||||||
|
qt6Packages.qt6ct
|
||||||
|
kdePackages.breeze
|
||||||
|
kdePackages.breeze.qt5
|
||||||
|
hexchat
|
||||||
|
gnumake
|
||||||
|
samrewritten
|
||||||
|
gale
|
||||||
];
|
];
|
||||||
|
|
||||||
fonts.packages = with pkgs; [
|
fonts.packages = with pkgs; [
|
||||||
|
|||||||
@@ -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" ];
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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"
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -0,0 +1,574 @@
|
|||||||
|
#ifndef VMCB_LAYOUT_H
|
||||||
|
#define VMCB_LAYOUT_H
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
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
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
#include <linux/linkage.h>
|
||||||
|
#include <asm/asm.h>
|
||||||
|
#include <host_state.h>
|
||||||
|
|
||||||
|
#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)
|
||||||
@@ -0,0 +1,663 @@
|
|||||||
|
#include <linux/init.h> /* Needed for the macros */
|
||||||
|
#include <linux/module.h> /* Needed by all modules */
|
||||||
|
#include <linux/printk.h> /* Needed for pr_info() */
|
||||||
|
#include <linux/string.h> /* for memset() and memcpy() */
|
||||||
|
#include <linux/bits.h>
|
||||||
|
#include <linux/version.h>
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 11, 0)
|
||||||
|
#include <linux/cpuhplock.h>
|
||||||
|
#else
|
||||||
|
#include <linux/cpu.h>
|
||||||
|
#endif
|
||||||
|
#include <linux/suspend.h>
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <asm/desc.h>
|
||||||
|
#include <asm/msr.h>
|
||||||
|
#include <linux/mm.h>
|
||||||
|
|
||||||
|
#include <host_state.h>
|
||||||
|
#include <vmcb_layout.h>
|
||||||
|
|
||||||
|
#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");
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
#include <linux/linkage.h>
|
||||||
|
#include <asm/asm.h>
|
||||||
|
#include <host_state.h>
|
||||||
|
|
||||||
|
#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)
|
||||||
Reference in New Issue
Block a user