aboutsummaryrefslogtreecommitdiffstats
path: root/executor
diff options
context:
space:
mode:
authorAlexander Potapenko <glider@google.com>2025-07-23 13:57:42 +0200
committerAlexander Potapenko <glider@google.com>2025-07-24 12:46:04 +0000
commitc76c0ee772387ce764344e75570062c4219bf495 (patch)
treed3531688dc37e6c06fbc89cf3fa557de86ba151a /executor
parent925dbff34225cb5d2677b079aa2db86719ec10fc (diff)
executor: sys/linux/dev_kvm_amd64.txt: implement rdmsr/wrmsr
Let SYZOS execute RDMSR and WRMSR on x86.
Diffstat (limited to 'executor')
-rw-r--r--executor/common_kvm_amd64_syzos.h54
1 files changed, 54 insertions, 0 deletions
diff --git a/executor/common_kvm_amd64_syzos.h b/executor/common_kvm_amd64_syzos.h
index 64f50dfcd..22c00b501 100644
--- a/executor/common_kvm_amd64_syzos.h
+++ b/executor/common_kvm_amd64_syzos.h
@@ -26,6 +26,8 @@ typedef enum {
SYZOS_API_UEXIT = 0,
SYZOS_API_CODE = 10,
SYZOS_API_CPUID = 20,
+ SYZOS_API_WRMSR = 30,
+ SYZOS_API_RDMSR = 50,
SYZOS_API_STOP, // Must be the last one
} syzos_api_id;
@@ -50,9 +52,21 @@ struct api_call_cpuid {
uint32 ecx;
};
+struct api_call_1 {
+ struct api_call_header header;
+ uint64 arg;
+};
+
+struct api_call_2 {
+ struct api_call_header header;
+ uint64 args[2];
+};
+
static void guest_uexit(uint64 exit_code);
static void guest_execute_code(uint8* insns, uint64 size);
static void guest_cpuid(uint32 eax, uint32 ecx);
+static void guest_wrmsr(uint64 reg, uint64 val);
+static void guest_rdmsr(uint64 reg);
typedef enum {
UEXIT_END = (uint64)-1,
@@ -90,6 +104,16 @@ guest_main(uint64 size, uint64 cpu)
guest_cpuid(ccmd->eax, ccmd->ecx);
break;
}
+ case SYZOS_API_WRMSR: {
+ struct api_call_2* ccmd = (struct api_call_2*)cmd;
+ guest_wrmsr(ccmd->args[0], ccmd->args[1]);
+ break;
+ }
+ case SYZOS_API_RDMSR: {
+ struct api_call_1* ccmd = (struct api_call_1*)cmd;
+ guest_rdmsr(ccmd->arg);
+ break;
+ }
}
addr += cmd->size;
size -= cmd->size;
@@ -120,3 +144,33 @@ GUEST_CODE static noinline void guest_cpuid(uint32 eax, uint32 ecx)
: "a"(eax), "c"(ecx)
: "rbx", "rdx");
}
+
+// Write val into an MSR register reg.
+GUEST_CODE static noinline void guest_wrmsr(uint64 reg, uint64 val)
+{
+ // The wrmsr instruction takes its arguments in specific registers:
+ // edx:eax contains the 64-bit value to write, ecx contains the MSR address.
+ asm volatile(
+ "wrmsr"
+ :
+ : "c"(reg),
+ "a"((uint32)val),
+ "d"((uint32)(val >> 32))
+ : "memory");
+}
+
+// Read an MSR register, ignore the result.
+GUEST_CODE static noinline void guest_rdmsr(uint64 reg)
+{
+ uint32 low = 0, high = 0;
+ // The rdmsr instruction takes the MSR address in ecx.
+ // It puts the lower 32 bits of the MSR value into eax, and the upper.
+ // 32 bits of the MSR value into edx.
+ asm volatile(
+ "rdmsr"
+ : "=a"(low),
+ "=d"(high)
+ : "c"(reg)
+ : // No explicit clobbers.
+ );
+}