commit b8f40e776af1a82116a44ce8fac34f343194f033
parent bca09eea299f162a27be3f6a59160afe86c8d525
Author: Louis Burda <quent.burda@gmail.com>
Date: Wed, 11 Jan 2023 18:56:23 +0100
Fix kvm-eviction kvm & sev support
Diffstat:
9 files changed, 283 insertions(+), 148 deletions(-)
diff --git a/Makefile b/Makefile
@@ -2,6 +2,7 @@ LINUX ?= linux
CORES ?= $(shell ls /dev/cpu | wc -l)
LOAD ?= $(CORES)
JOBS ?= $(CORES)
+
PWD := $(shell pwd)
BINS = test/eviction test/kvm-eviction # test/kvm-execstep
@@ -9,7 +10,11 @@ BINS = test/eviction test/kvm-eviction # test/kvm-execstep
# BINS += test/qemu-aes_guest test/qemu-aes_host
BINS += util/svme util/debug util/reset
-CFLAGS = -I . -I linux/usr/include -I test -Wunused-variable -Wunknown-pragmas
+CFLAGS = -I . -I linux/usr/include -I test
+CFLAGS += -g -Wunused-variable -Wunknown-pragmas
+CFLAGS += -fsanitize=address
+
+CACHEPC_UAPI = cachepc/uapi.h cachepc/const.h
all: build $(BINS)
@@ -22,7 +27,7 @@ $(LINUX)/arch/x86/kvm/cachepc:
ln -sf $(PWD)/cachepc $@
host:
- # generate host kernel and Module.symvers for depmod
+ # build host kernel and Module.symvers for depmod
cp extra/.config linux/.config
git -C $(LINUX) add .
git -C $(LINUX) stash
@@ -50,10 +55,12 @@ freq:
update:
git -C $(LINUX) diff 0aaa1e599bee256b3b15643bbb95e80ce7aa9be5 -G. > patch.diff
-test/%: test/%.c cachepc/uapi.h
- clang -o $@ $< $(CFLAGS) -fsanitize=address
+util/%: util/%.c $(CACHEPC_UAPI)
+
+test/%: test/%.c $(CACHEPC_UAPI)
-util/%: util/%.c cachepc/uapi.h
- clang -o $@ $< $(CFLAGS) -fsanitize=address
+test/kvm-eviction: test/kvm-eviction.c test/kvm-eviction_guest.S \
+ test/kvm-eviction.h $(CACHEPC_UAPI)
+ $(CC) -o $@ test/kvm-eviction.c test/kvm-eviction_guest.S $(CFLAGS)
.PHONY: all clean host build load freq update
diff --git a/cachepc/const.h b/cachepc/const.h
@@ -0,0 +1,22 @@
+#pragma once
+
+#define CPC_ISOLCPU 2
+
+#define CPC_L1MISS_PMC 0
+#define CPC_RETINST_PMC 1
+
+#define L1_ASSOC 8
+#define L1_LINESIZE 64
+#define L1_SETS 64
+#define L1_SIZE (L1_SETS * L1_ASSOC * L1_LINESIZE)
+
+#define L2_ASSOC 8
+#define L2_LINESIZE 64
+#define L2_SETS 1024
+#define L2_SIZE (L2_SETS * L2_ASSOC * L2_LINESIZE)
+
+#define CPC_VMSA_MAGIC_ADDR ((void *) 0xC0FFEE)
+
+#define KVM_HC_CPC_VMMCALL_SIGNAL 0xEE01
+#define KVM_HC_CPC_VMMCALL_EXIT 0xEE02
+
diff --git a/cachepc/kvm.c b/cachepc/kvm.c
@@ -190,9 +190,9 @@ cachepc_kvm_stream_hwpf_test(void *p)
asm volatile ("mov (%0), %%rbx" : : "r"(lines + 4) : "rbx");
asm volatile ("mov (%0), %%rbx" : : "r"(lines + 5) : "rbx");
asm volatile ("mov (%0), %%rbx" : : "r"(lines + 6) : "rbx");
- asm volatile ("mov (%0), %%rbx" : : "r"(lines + 0) : "rbx");
- asm volatile ("mov (%0), %%rbx" : : "r"(lines + 1) : "rbx");
- asm volatile ("mov (%0), %%rbx" : : "r"(lines + 2) : "rbx");
+ asm volatile ("mov (%0), %%rbx" : : "r"(lines + 7) : "rbx");
+ asm volatile ("mov (%0), %%rbx" : : "r"(lines + 8) : "rbx");
+ asm volatile ("mov (%0), %%rbx" : : "r"(lines + 9) : "rbx");
count += cachepc_read_pmc(CPC_L1MISS_PMC);
CPC_WARN("HWPF test done (%u vs. %u => %s)\n",
diff --git a/cachepc/uapi.h b/cachepc/uapi.h
@@ -1,28 +1,11 @@
#pragma once
+#include "const.h"
+
#include <linux/kvm.h>
#include <linux/types.h>
#include <linux/ioctl.h>
-#define CPC_ISOLCPU 2
-
-#define CPC_L1MISS_PMC 0
-#define CPC_RETINST_PMC 1
-
-#define L1_ASSOC 8
-#define L1_LINESIZE 64
-#define L1_SETS 64
-#define L1_SIZE (L1_SETS * L1_ASSOC * L1_LINESIZE)
-
-#define L2_ASSOC 8
-#define L2_LINESIZE 64
-#define L2_SETS 1024
-#define L2_SIZE (L2_SETS * L2_ASSOC * L2_LINESIZE)
-
-#define CPC_VMSA_MAGIC_ADDR ((void *) 0xC0FFEE)
-
-#define KVM_HC_CPC_VMMCALL_SIGNAL 0xC0FFEE00
-#define KVM_HC_CPC_VMMCALL_EXIT 0xC0FFEE01
#define CPC_DO_VMMCALL(action, type, val) \
asm volatile("vmmcall" : : "a" (KVM_HC_CPC_VMMCALL_ ## action), \
"b"(type), "c" (val) : "rdx")
diff --git a/test/eviction.c b/test/eviction.c
@@ -21,6 +21,8 @@ main(int argc, const char **argv)
set = 48;
if (argc > 1) set = atoi(argv[1]);
+ if (set >= L1_SETS)
+ errx(1, "set out-of-bounds");
ret = ioctl(fd, KVM_CPC_TEST_EVICTION, &set);
if (ret == -1) err(1, "ioctl KVM_CPC_TEST_EVICTION");
diff --git a/test/kvm-eviction.c b/test/kvm-eviction.c
@@ -1,5 +1,6 @@
#define _GNU_SOURCE
+#include "kvm-eviction.h"
#include "cachepc/uapi.h"
#include <linux/psp-sev.h>
@@ -35,8 +36,6 @@
#define TARGET_CORE 2
#define SECONDARY_CORE 3
-#define TARGET_SET 15
-
enum {
WITH,
WITHOUT
@@ -50,10 +49,10 @@ struct kvm {
};
/* start and end for guest assembly */
-extern uint8_t __start_guest_with[];
-extern uint8_t __stop_guest_with[];
-extern uint8_t __start_guest_without[];
-extern uint8_t __stop_guest_without[];
+extern uint8_t start_guest_with[];
+extern uint8_t stop_guest_with[];
+extern uint8_t start_guest_without[];
+extern uint8_t stop_guest_without[];
static const char *vmtype;
@@ -120,24 +119,6 @@ hexdump(void *data, int len)
printf("\n");
}
-__attribute__((section("guest_with"))) void
-vm_guest_with(void)
-{
- while (1) {
- asm volatile("mov (%[v]), %%bl"
- : : [v] "r" (L1_LINESIZE * TARGET_SET));
- CPC_DO_VMMCALL(EXIT, 0, 0);
- }
-}
-
-__attribute__((section("guest_without"))) void
-vm_guest_without(void)
-{
- while (1) {
- CPC_DO_VMMCALL(EXIT, 0, 0);
- }
-}
-
bool
pin_process(pid_t pid, int cpu, bool assert)
{
@@ -147,7 +128,7 @@ pin_process(pid_t pid, int cpu, bool assert)
CPU_ZERO(&cpuset);
CPU_SET(cpu, &cpuset);
ret = sched_setaffinity(pid, sizeof(cpu_set_t), &cpuset);
- if (ret < 0) {
+ if (ret == -1) {
if (assert) err(1, "sched_setaffinity");
return false;
}
@@ -227,7 +208,7 @@ sev_get_measure(int vmfd)
memset(&msrmt, 0, sizeof(msrmt));
ret = sev_ioctl(vmfd, KVM_SEV_LAUNCH_MEASURE, &msrmt, &fwerr);
- if (ret < 0 && fwerr != SEV_RET_INVALID_LEN)
+ if (ret == -1 && fwerr != SEV_RET_INVALID_LEN)
errx(1, "KVM_SEV_LAUNCH_MEASURE: (%s) %s",
strerror(errno), sev_fwerr_str(fwerr));
@@ -235,9 +216,8 @@ sev_get_measure(int vmfd)
msrmt.uaddr = (uintptr_t) data;
ret = sev_ioctl(vmfd, KVM_SEV_LAUNCH_MEASURE, &msrmt, &fwerr);
- if (ret < 0)
- errx(1, "KVM_SEV_LAUNCH_MEASURE: (%s) %s",
- strerror(errno), sev_fwerr_str(fwerr));
+ if (ret == -1) errx(1, "KVM_SEV_LAUNCH_MEASURE: (%s) %s",
+ strerror(errno), sev_fwerr_str(fwerr));
free(data);
}
@@ -250,10 +230,8 @@ sev_guest_state(int vmfd, uint32_t handle)
status.handle = handle;
ret = sev_ioctl(vmfd, KVM_SEV_GUEST_STATUS, &status, &fwerr);
- if (ret < 0) {
- errx(1, "KVM_SEV_GUEST_STATUS: (%s) %s",
- strerror(errno), sev_fwerr_str(fwerr));
- }
+ if (ret == -1) errx(1, "KVM_SEV_GUEST_STATUS: (%s) %s",
+ strerror(errno), sev_fwerr_str(fwerr));
return status.state;
}
@@ -268,7 +246,7 @@ sev_debug_encrypt(int vmfd, void *src, void *dst, size_t size)
enc.dst_uaddr = (uintptr_t) dst;
enc.len = size;
ret = sev_ioctl(vmfd, KVM_SEV_DBG_ENCRYPT, &enc, &fwerr);
- if (ret < 0) errx(1, "KVM_SEV_DBG_ENCRYPT: (%s) %s",
+ if (ret == -1) errx(1, "KVM_SEV_DBG_ENCRYPT: (%s) %s",
strerror(errno), sev_fwerr_str(fwerr));
}
@@ -282,7 +260,7 @@ sev_debug_decrypt(int vmfd, void *src, void *dst, size_t size)
enc.dst_uaddr = (uintptr_t) dst;
enc.len = size;
ret = sev_ioctl(vmfd, KVM_SEV_DBG_DECRYPT, &enc, &fwerr);
- if (ret < 0) errx(1, "KVM_SEV_DBG_DECRYPT: (%s) %s",
+ if (ret == -1) errx(1, "KVM_SEV_DBG_DECRYPT: (%s) %s",
strerror(errno), sev_fwerr_str(fwerr));
}
@@ -314,31 +292,38 @@ kvm_init(struct kvm *kvm, size_t ramsize,
region.guest_phys_addr = 0x0000;
region.userspace_addr = (uintptr_t) kvm->mem;
ret = ioctl(kvm->vmfd, KVM_SET_USER_MEMORY_REGION, ®ion);
- if (ret < 0) err(1, "KVM_SET_USER_MEMORY_REGION");
+ if (ret == -1) err(1, "KVM_SET_USER_MEMORY_REGION");
/* Create virtual cpu core */
kvm->vcpufd = ioctl(kvm->vmfd, KVM_CREATE_VCPU, 0);
if (kvm->vcpufd < 0) err(1, "KVM_CREATE_VCPU");
+ /* Map the shared kvm_run structure and following data */
+ ret = ioctl(kvm_dev, KVM_GET_VCPU_MMAP_SIZE, NULL);
+ if (ret == -1) err(1, "KVM_GET_VCPU_MMAP_SIZE");
+ if (ret < sizeof(struct kvm_run))
+ errx(1, "KVM_GET_VCPU_MMAP_SIZE too small");
+ kvm->run = mmap(NULL, ret, PROT_READ | PROT_WRITE,
+ MAP_SHARED, kvm->vcpufd, 0);
+ if (!kvm->run) err(1, "mmap vcpu");
+
/* Initialize segment regs */
memset(&sregs, 0, sizeof(sregs));
ret = ioctl(kvm->vcpufd, KVM_GET_SREGS, &sregs);
- if (ret < 0) err(1, "KVM_GET_SREGS");
+ if (ret == -1) err(1, "KVM_GET_SREGS");
sregs.cs.base = 0;
sregs.cs.selector = 0;
ret = ioctl(kvm->vcpufd, KVM_SET_SREGS, &sregs);
- if (ret < 0) err(1, "KVM_SET_SREGS");
+ if (ret == -1) err(1, "KVM_SET_SREGS");
/* Initialize rest of registers */
memset(®s, 0, sizeof(regs));
- regs.rip = 0x0;
+ regs.rip = 0;
regs.rsp = kvm->memsize - 8;
regs.rbp = kvm->memsize - 8;
- regs.rax = 0;
- regs.rdx = 0;
regs.rflags = 0x2;
ret = ioctl(kvm->vcpufd, KVM_SET_REGS, ®s);
- if (ret < 0) err(1, "KVM_SET_REGS");
+ if (ret == -1) err(1, "KVM_SET_REGS");
}
void
@@ -368,22 +353,53 @@ sev_kvm_init(struct kvm *kvm, size_t ramsize,
memset(®ion, 0, sizeof(region));
region.slot = 0;
region.memory_size = kvm->memsize;
- region.guest_phys_addr = 0x0000;
+ region.guest_phys_addr = 0;
region.userspace_addr = (uintptr_t) kvm->mem;
ret = ioctl(kvm->vmfd, KVM_SET_USER_MEMORY_REGION, ®ion);
- if (ret < 0) err(1, "KVM_SET_USER_MEMORY_REGION");
+ if (ret == -1) err(1, "KVM_SET_USER_MEMORY_REGION");
/* Enable SEV for vm */
ret = sev_ioctl(kvm->vmfd, KVM_SEV_INIT, NULL, &fwerr);
- if (ret < 0) errx(1, "KVM_SEV_INIT: (%s) %s",
+ if (ret == -1) errx(1, "KVM_SEV_INIT: (%s) %s",
strerror(errno), sev_fwerr_str(fwerr));
+ /* Create virtual cpu core */
+ kvm->vcpufd = ioctl(kvm->vmfd, KVM_CREATE_VCPU, 0);
+ if (kvm->vcpufd < 0) err(1, "KVM_CREATE_VCPU");
+
+ /* Map the shared kvm_run structure and following data */
+ ret = ioctl(kvm_dev, KVM_GET_VCPU_MMAP_SIZE, NULL);
+ if (ret == -1) err(1, "KVM_GET_VCPU_MMAP_SIZE");
+ if (ret < sizeof(struct kvm_run))
+ errx(1, "KVM_GET_VCPU_MMAP_SIZE too small");
+ kvm->run = mmap(NULL, ret, PROT_READ | PROT_WRITE,
+ MAP_SHARED, kvm->vcpufd, 0);
+ if (!kvm->run) err(1, "mmap vcpu");
+
+ /* Initialize segment regs */
+ memset(&sregs, 0, sizeof(sregs));
+ ret = ioctl(kvm->vcpufd, KVM_GET_SREGS, &sregs);
+ if (ret == -1) err(1, "KVM_GET_SREGS");
+ sregs.cs.base = 0;
+ sregs.cs.selector = 0;
+ ret = ioctl(kvm->vcpufd, KVM_SET_SREGS, &sregs);
+ if (ret == -1) err(1, "KVM_SET_SREGS");
+
+ /* Initialize rest of registers */
+ memset(®s, 0, sizeof(regs));
+ regs.rip = 0;
+ regs.rsp = kvm->memsize - 8;
+ regs.rbp = kvm->memsize - 8;
+ regs.rflags = 0x2;
+ ret = ioctl(kvm->vcpufd, KVM_SET_REGS, ®s);
+ if (ret == -1) err(1, "KVM_SET_REGS");
+
/* Generate encryption keys and set policy */
memset(&start, 0, sizeof(start));
start.handle = 0;
start.policy = 0;
ret = sev_ioctl(kvm->vmfd, KVM_SEV_LAUNCH_START, &start, &fwerr);
- if (ret < 0) errx(1, "KVM_SEV_LAUNCH_START: (%s) %s",
+ if (ret == -1) errx(1, "KVM_SEV_LAUNCH_START: (%s) %s",
strerror(errno), sev_fwerr_str(fwerr));
/* Prepare the vm memory (by encrypting it) */
@@ -391,7 +407,7 @@ sev_kvm_init(struct kvm *kvm, size_t ramsize,
update.uaddr = (uintptr_t) kvm->mem;
update.len = ramsize;
ret = sev_ioctl(kvm->vmfd, KVM_SEV_LAUNCH_UPDATE_DATA, &update, &fwerr);
- if (ret < 0) errx(1, "KVM_SEV_LAUNCH_UPDATE_DATA: (%s) %s",
+ if (ret == -1) errx(1, "KVM_SEV_LAUNCH_UPDATE_DATA: (%s) %s",
strerror(errno), sev_fwerr_str(fwerr));
/* Collect a measurement (necessary) */
@@ -399,19 +415,60 @@ sev_kvm_init(struct kvm *kvm, size_t ramsize,
/* Finalize launch process */
ret = sev_ioctl(kvm->vmfd, KVM_SEV_LAUNCH_FINISH, 0, &fwerr);
- if (ret < 0) errx(1, "KVM_SEV_LAUNCH_FINISH: (%s) %s",
- strerror(errno), sev_fwerr_str(fwerr));
+ if (ret == -1) errx(1, "KVM_SEV_LAUNCH_FINISH: (%s) %s",
+ strerror(errno), sev_fwerr_str(fwerr));
+
ret = sev_guest_state(kvm->vmfd, start.handle);
if (ret != GSTATE_RUNNING)
errx(1, "Bad guest state: %s", sev_gstate_str(fwerr));
+}
- /* Create virtual cpu core */
+void
+sev_es_kvm_init(struct kvm *kvm, size_t ramsize,
+ void *code_start, void *code_stop)
+{
+ struct kvm_sev_launch_update_data update;
+ struct kvm_sev_launch_start start;
+ struct kvm_userspace_memory_region region;
+ struct kvm_sev_dbg dec;
+ struct kvm_regs regs;
+ struct kvm_sregs sregs;
+ int ret, fwerr;
+ void *buf;
+
+ /* Create a kvm instance */
+ kvm->vmfd = ioctl(kvm_dev, KVM_CREATE_VM, 0);
+ if (kvm->vmfd < 0) err(1, "KVM_CREATE_VM");
+
+ /* Allocate guest memory */
+ kvm->memsize = ramsize;
+ kvm->mem = mmap(NULL, kvm->memsize, PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+ if (!kvm->mem) err(1, "Allocating guest memory");
+ assert(code_stop - code_start <= kvm->memsize);
+ memcpy(kvm->mem, code_start, code_stop - code_start);
+
+ /* Map it into the vm */
+ memset(®ion, 0, sizeof(region));
+ region.slot = 0;
+ region.memory_size = kvm->memsize;
+ region.guest_phys_addr = 0;
+ region.userspace_addr = (uintptr_t) kvm->mem;
+ ret = ioctl(kvm->vmfd, KVM_SET_USER_MEMORY_REGION, ®ion);
+ if (ret == -1) err(1, "KVM_SET_USER_MEMORY_REGION");
+
+ /* Enable SEV-ES for vm */
+ ret = sev_ioctl(kvm->vmfd, KVM_SEV_ES_INIT, NULL, &fwerr);
+ if (ret == -1) errx(1, "KVM_SEV_ES_INIT: (%s) %s",
+ strerror(errno), sev_fwerr_str(fwerr));
+
+ /* Create virtual cpu */
kvm->vcpufd = ioctl(kvm->vmfd, KVM_CREATE_VCPU, 0);
if (kvm->vcpufd < 0) err(1, "KVM_CREATE_VCPU");
/* Map the shared kvm_run structure and following data */
ret = ioctl(kvm_dev, KVM_GET_VCPU_MMAP_SIZE, NULL);
- if (ret < 0) err(1, "KVM_GET_VCPU_MMAP_SIZE");
+ if (ret == -1) err(1, "KVM_GET_VCPU_MMAP_SIZE");
if (ret < sizeof(struct kvm_run))
errx(1, "KVM_GET_VCPU_MMAP_SIZE too small");
kvm->run = mmap(NULL, ret, PROT_READ | PROT_WRITE,
@@ -421,29 +478,62 @@ sev_kvm_init(struct kvm *kvm, size_t ramsize,
/* Initialize segment regs */
memset(&sregs, 0, sizeof(sregs));
ret = ioctl(kvm->vcpufd, KVM_GET_SREGS, &sregs);
- if (ret < 0) err(1, "KVM_GET_SREGS");
+ if (ret == -1) err(1, "KVM_GET_SREGS");
sregs.cs.base = 0;
sregs.cs.selector = 0;
ret = ioctl(kvm->vcpufd, KVM_SET_SREGS, &sregs);
- if (ret < 0) err(1, "KVM_SET_SREGS");
+ if (ret == -1) err(1, "KVM_SET_SREGS");
/* Initialize rest of registers */
memset(®s, 0, sizeof(regs));
- regs.rip = 0x0;
+ regs.rip = 0;
regs.rsp = kvm->memsize - 8;
regs.rbp = kvm->memsize - 8;
- regs.rax = 0;
- regs.rdx = 0;
- regs.rflags = 0x2;
ret = ioctl(kvm->vcpufd, KVM_SET_REGS, ®s);
- if (ret < 0) err(1, "KVM_SET_REGS");
-}
+ if (ret == -1) err(1, "KVM_SET_REGS");
-void
-sev_es_kvm_init(struct kvm *kvm, size_t ramsize,
- void *code_start, void *code_stop)
-{
- errx(1, "Not implemented");
+ /* Generate encryption keys and set policy */
+ memset(&start, 0, sizeof(start));
+ start.handle = 0;
+ start.policy = 1 << 2; /* require ES */
+ ret = sev_ioctl(kvm->vmfd, KVM_SEV_LAUNCH_START, &start, &fwerr);
+ if (ret == -1) errx(1, "KVM_SEV_LAUNCH_START: (%s) %s",
+ strerror(errno), sev_fwerr_str(fwerr));
+
+ /* Prepare the vm memory (by encrypting it) */
+ memset(&update, 0, sizeof(update));
+ update.uaddr = (uintptr_t) kvm->mem;
+ update.len = ramsize;
+ ret = sev_ioctl(kvm->vmfd, KVM_SEV_LAUNCH_UPDATE_DATA, &update, &fwerr);
+ if (ret == -1) errx(1, "KVM_SEV_LAUNCH_UPDATE_DATA: (%s) %s",
+ strerror(errno), sev_fwerr_str(fwerr));
+
+ /* Prepare the vm save area */
+ ret = sev_ioctl(kvm->vmfd, KVM_SEV_LAUNCH_UPDATE_VMSA, NULL, &fwerr);
+ if (ret == -1) errx(1, "KVM_SEV_LAUNCH_UPDATE_VMSA: (%s) %s",
+ strerror(errno), sev_fwerr_str(fwerr));
+
+ /* Collect a measurement (necessary) */
+ sev_get_measure(kvm->vmfd);
+
+ /* Finalize launch process */
+ ret = sev_ioctl(kvm->vmfd, KVM_SEV_LAUNCH_FINISH, 0, &fwerr);
+ if (ret == -1) errx(1, "KVM_SEV_LAUNCH_FINISH: (%s) %s",
+ strerror(errno), sev_fwerr_str(fwerr));
+ ret = sev_guest_state(kvm->vmfd, start.handle);
+ if (ret != GSTATE_RUNNING)
+ errx(1, "Bad guest state: %s", sev_gstate_str(fwerr));
+
+ /* Validate code was encrypted correctly */
+ buf = malloc(ramsize);
+ dec.src_uaddr = (uint64_t) kvm->mem;
+ dec.dst_uaddr = (uint64_t) buf;
+ dec.len = ramsize;
+ ret = sev_ioctl(kvm->vmfd, KVM_SEV_DBG_DECRYPT, &dec, &fwerr);
+ if (ret == -1) errx(1, "KVM_SEV_DBG_DECRYPT: (%s) %s",
+ strerror(errno), sev_fwerr_str(fwerr));
+ if (memcmp(buf, code_start, code_stop - code_start))
+ errx(1, "VM ram not encrypted correctly");
}
void
@@ -506,16 +596,16 @@ collect(struct kvm *kvm, uint8_t *counts)
/* run vm twice, use count without initial stack setup */
ret = ioctl(kvm->vcpufd, KVM_RUN, NULL);
- if (ret < 0) err(1, "KVM_RUN");
+ if (ret == -1) err(1, "KVM_RUN");
if (kvm->run->exit_reason == KVM_EXIT_MMIO) {
memset(®s, 0, sizeof(regs));
ret = ioctl(kvm->vcpufd, KVM_GET_REGS, ®s);
- if (ret < 0) err(1, "KVM_GET_REGS");
+ if (ret == -1) err(1, "KVM_GET_REGS");
errx(1, "Victim access OOB: %llu %08llx => %02X\n",
kvm->run->mmio.phys_addr, regs.rip,
((uint8_t *)kvm->mem)[regs.rip]);
- } else if (kvm->run->exit_reason != KVM_EXIT_IO) {
+ } else if (kvm->run->exit_reason != KVM_EXIT_HYPERCALL) {
errx(1, "KVM died: %i\n", kvm->run->exit_reason);
}
@@ -527,9 +617,8 @@ int
main(int argc, const char **argv)
{
struct kvm vms[2];
- uint8_t counts[2][SAMPLE_COUNT][64];
- uint8_t baseline[64];
- uint32_t calc;
+ uint8_t counts[2][SAMPLE_COUNT][L1_SETS];
+ uint8_t baseline[L1_SETS];
int i, k, ret;
vmtype = "kvm";
@@ -537,7 +626,7 @@ main(int argc, const char **argv)
if (strcmp(vmtype, "kvm") && strcmp(vmtype, "sev")
&& strcmp(vmtype, "sev-es")
&& strcmp(vmtype, "sev-snp"))
- errx(1, "invalid version: %s", vmtype);
+ errx(1, "invalid vm mode: %s", vmtype);
setvbuf(stdout, NULL, _IONBF, 0);
@@ -551,57 +640,63 @@ main(int argc, const char **argv)
/* Make sure we have the stable version of the API */
ret = ioctl(kvm_dev, KVM_GET_API_VERSION, NULL);
- if (ret < 0) err(1, "KVM_GET_API_VERSION");
+ if (ret == -1) err(1, "KVM_GET_API_VERSION");
if (ret != 12) errx(1, "KVM_GET_API_VERSION %d, expected 12", ret);
/* Reset kernel module state */
ret = ioctl(kvm_dev, KVM_CPC_RESET);
- if (ret < 0) err(1, "ioctl KVM_CPC_RESET");
-
- vm_init(&vms[WITH], 64 * 64 * 8 * 2,
- __start_guest_with, __stop_guest_with);
- vm_init(&vms[WITHOUT], 64 * 64 * 8 * 2,
- __start_guest_without, __stop_guest_without);
+ if (ret == -1) err(1, "ioctl KVM_CPC_RESET");
- calc = true;
- ret = ioctl(kvm_dev, KVM_CPC_CALC_BASELINE, &calc);
- if (ret == -1) err(1, "ioctl KVM_CPC_CALC_BASELINE");
+ vm_init(&vms[WITH], 2 * L1_SIZE,
+ start_guest_with, stop_guest_with);
+ vm_init(&vms[WITHOUT], 2 * L1_SIZE,
+ start_guest_without, stop_guest_without);
for (i = 0; i < SAMPLE_COUNT; i++) {
collect(&vms[WITH], counts[WITH][i]);
collect(&vms[WITHOUT], counts[WITHOUT][i]);
}
- calc = false;
- ret = ioctl(kvm_dev, KVM_CPC_CALC_BASELINE, &calc);
- if (ret == -1) err(1, "ioctl KVM_CPC_CALC_BASELINE");
-
- ret = ioctl(kvm_dev, KVM_CPC_READ_BASELINE, baseline);
- if (ret == -1) err(1, "ioctl KVM_CPC_READ_BASELINE");
+ memset(baseline, 0xff, L1_SETS);
+ for (i = 0; i < SAMPLE_COUNT; i++) {
+ for (k = 0; k < L1_SETS; k++) {
+ if (counts[WITH][i][k] < baseline[k])
+ baseline[k] = counts[WITH][i][k];
+ if (counts[WITHOUT][i][k] < baseline[k])
+ baseline[k] = counts[WITHOUT][i][k];
+ }
+ }
for (i = 0; i < SAMPLE_COUNT; i++) {
- printf("Evictions with access:\n");
+ for (k = 0; k < L1_SETS; k++) {
+ counts[WITH][i][k] -= baseline[k];
+ counts[WITHOUT][i][k] -= baseline[k];
+ }
+
+ printf("=== Sample %2i ===\n\n", i);
+
+ printf("With eviction:\n");
print_counts(counts[WITH][i]);
- printf("Evictions without access:\n");
+ printf("Without eviction:\n");
print_counts(counts[WITHOUT][i]);
+ }
- for (k = 0; k < 64; k++) {
- if (counts[WITH][i][k] >= 8)
- warnx("with: Count OOB (%i, %i)", i, k);
- if (baseline[k] > counts[WITH][i][k])
- warnx("with: Baseline oob (%i, %i)", i, k);
- counts[WITH][i][k] -= baseline[k];
-
- if (counts[WITHOUT][i][k] >= 8)
- warnx("without: Count OOB (%i, %i)", i, k);
- if (baseline[k] > counts[WITHOUT][i][k])
- warnx("without: Baseline OOB (%i, %i)", i, k);
- counts[WITHOUT][i][k] -= baseline[k];
+ for (i = 0; i < SAMPLE_COUNT; i++) {
+ for (k = 0; k < L1_SETS; k++) {
+ if (counts[WITH][i][k] + baseline[k] >= L1_ASSOC)
+ warnx("sample %i: With count OOB for set %i (=%i)",
+ i, k, counts[WITH][i][k] + baseline[k]);
+
+ if (counts[WITHOUT][i][k] + baseline[k] >= L1_ASSOC)
+ warnx("sample %i: Without count OOB for set %i (=%i)",
+ i, k, counts[WITHOUT][i][k] + baseline[k]);
}
if (!counts[WITH][i][TARGET_SET])
- warnx("with: Missing eviction in target set");
+ warnx("sample %i: Missing eviction in target set %i (=%i,%i)",
+ i, TARGET_SET, counts[WITH][i][TARGET_SET],
+ counts[WITH][i][TARGET_SET] + baseline[i]);
}
vm_deinit(&vms[WITH]);
diff --git a/test/kvm-eviction.h b/test/kvm-eviction.h
@@ -0,0 +1,3 @@
+#pragma once
+
+#define TARGET_SET 15
diff --git a/test/kvm-eviction_guest.S b/test/kvm-eviction_guest.S
@@ -0,0 +1,24 @@
+#include "kvm-eviction.h"
+#include "cachepc/const.h"
+
+#define TARGET_SET 15
+
+.global start_guest_with
+.global stop_guest_with
+
+.global start_guest_without
+.global stop_guest_without
+
+start_guest_with:
+ mov $(L1_LINESIZE * TARGET_SET), %rbx
+ mov (%rbx), %bl
+ mov $KVM_HC_CPC_VMMCALL_EXIT, %rax
+ vmmcall
+ jmp start_guest_with
+stop_guest_with:
+
+start_guest_without:
+ mov $KVM_HC_CPC_VMMCALL_EXIT, %rax
+ vmmcall
+ jmp start_guest_without
+stop_guest_without:
diff --git a/test/sev-es.c b/test/sev-es.c
@@ -399,13 +399,13 @@ sev_kvm_deinit(struct kvm *kvm)
munmap(kvm->mem, kvm->memsize);
}
-cpc_msrmt_t *
+uint8_t *
read_counts()
{
- cpc_msrmt_t *counts;
+ uint8_t *counts;
int ret;
- counts = malloc(64 * sizeof(cpc_msrmt_t));
+ counts = malloc(64);
if (!counts) err(1, "malloc");
ret = ioctl(kvm_dev, KVM_CPC_READ_COUNTS, counts);
if (ret == -1) err(1, "ioctl READ_COUNTS");
@@ -414,7 +414,7 @@ read_counts()
}
void
-print_counts(cpc_msrmt_t *counts)
+print_counts(uint8_t *counts)
{
int i;
@@ -429,11 +429,11 @@ print_counts(cpc_msrmt_t *counts)
if (counts[i] > 0)
printf("\x1b[0m");
}
- printf("\n Target Set %i Count: %llu\n", TARGET_SET, counts[TARGET_SET]);
+ printf("\n Target Set %i Count: %u\n", TARGET_SET, counts[TARGET_SET]);
printf("\n");
}
-cpc_msrmt_t *
+uint8_t *
collect(struct kvm *kvm)
{
struct kvm_regs regs;
@@ -459,10 +459,10 @@ collect(struct kvm *kvm)
int
main(int argc, const char **argv)
{
- cpc_msrmt_t without_access[SAMPLE_COUNT][64];
- cpc_msrmt_t with_access[SAMPLE_COUNT][64];
+ uint8_t without_access[SAMPLE_COUNT][64];
+ uint8_t with_access[SAMPLE_COUNT][64];
struct kvm kvm_without_access, kvm_with_access;
- cpc_msrmt_t *counts, *baseline;
+ uint8_t *counts, *baseline;
uint32_t arg, measure;
int i, k, ret;
@@ -482,11 +482,10 @@ main(int argc, const char **argv)
if (ret != 12) errx(1, "KVM_GET_API_VERSION %d, expected 12", ret);
/* init L1 miss counter for host kernel */
- arg = 0x002264D8;
- ret = ioctl(kvm_dev, KVM_CPC_INIT_PMC, &arg);
- if (ret < 0) err(1, "ioctl INIT_PMC");
+ ret = ioctl(kvm_dev, KVM_CPC_RESET);
+ if (ret < 0) err(1, "ioctl KVM_CPC_RESET");
- baseline = calloc(sizeof(cpc_msrmt_t), 64);
+ baseline = malloc(64);
if (!baseline) err(1, "calloc");
sev_kvm_init(&kvm_with_access, 64 * 64 * 8 * 2, __start_guest_with, __stop_guest_with);
@@ -497,21 +496,21 @@ main(int argc, const char **argv)
ioctl(kvm_without_access.vcpufd, KVM_RUN, NULL);
measure = true;
- ret = ioctl(kvm_dev, KVM_CPC_MEASURE_BASELINE, &measure);
+ ret = ioctl(kvm_dev, KVM_CPC_CALC_BASELINE, &measure);
if (ret == -1) err(1, "ioctl MEASURE_BASELINE");
for (i = 0; i < SAMPLE_COUNT; i++) {
counts = collect(&kvm_without_access);
- memcpy(without_access[i], counts, 64 * sizeof(cpc_msrmt_t));
+ memcpy(without_access[i], counts, 64);
free(counts);
counts = collect(&kvm_with_access);
- memcpy(with_access[i], counts, 64 * sizeof(cpc_msrmt_t));
+ memcpy(with_access[i], counts, 64);
free(counts);
}
measure = false;
- ret = ioctl(kvm_dev, KVM_CPC_MEASURE_BASELINE, &measure);
+ ret = ioctl(kvm_dev, KVM_CPC_CALC_BASELINE, &measure);
if (ret == -1) err(1, "ioctl MEASURE_BASELINE");
ret = ioctl(kvm_dev, KVM_CPC_READ_BASELINE, baseline);
@@ -527,7 +526,7 @@ main(int argc, const char **argv)
printf("Evictions with access:\n");
print_counts(with_access[i]);
- printf("Evictions without access:\n");
+ printf("Evictions withoCALCt access:\n");
print_counts(without_access[i]);
}