From 65daf1cb353f4ba5e2f08ccbce6b0d5220b0099a Mon Sep 17 00:00:00 2001 From: Louis Burda Date: Tue, 24 Jan 2023 16:17:45 +0100 Subject: Create flat binaries to support more complex guests --- Makefile | 31 ++- README | 2 +- cachepc/kvm.c | 1 - linux | 2 +- test/.gitignore | 8 + test/guest.lds | 13 + test/kvm-eviction-with_guest.S | 14 + test/kvm-eviction-without_guest.S | 12 + test/kvm-eviction.c | 15 +- test/kvm-eviction_guest.S | 26 -- test/kvm-pagestep.c | 8 +- test/kvm-pagestep_guest.S | 21 +- test/kvm-step.c | 8 +- test/kvm-step_guest.S | 28 +- test/kvm.c | 78 ++++-- test/kvm.h | 25 +- test/qemu-aes.c | 527 ++++++++++++++++++++++++++++++++++++++ test/qemu-aes_host.c | 527 -------------------------------------- test/qemu-eviction.c | 362 ++++++++++++++++++++++++++ test/qemu-eviction_host.c | 361 -------------------------- test/util.c | 1 + util/disasm | 4 +- 22 files changed, 1064 insertions(+), 1010 deletions(-) create mode 100644 test/guest.lds create mode 100644 test/kvm-eviction-with_guest.S create mode 100644 test/kvm-eviction-without_guest.S delete mode 100644 test/kvm-eviction_guest.S create mode 100644 test/qemu-aes.c delete mode 100644 test/qemu-aes_host.c create mode 100644 test/qemu-eviction.c delete mode 100644 test/qemu-eviction_host.c diff --git a/Makefile b/Makefile index 76da9c0..4e15d6f 100755 --- a/Makefile +++ b/Makefile @@ -6,9 +6,11 @@ JOBS ?= $(CORES) PWD := $(shell pwd) BINS = test/eviction test/kvm-eviction -BINS += test/kvm-step test/kvm-pagestep -# BINS += test/qemu-eviction_guest test/qemu-eviction_host -# BINS += test/qemu-aes_guest test/qemu-aes_host +BINS += test/kvm-eviction-with_guest test/kvm-eviction-without_guest +BINS += test/kvm-step test/kvm-step_guest +BINS += test/kvm-pagestep test/kvm-pagestep_guest +#BINS += test/qemu-eviction_guest test/qemu-eviction +# BINS += test/qemu-aes_guest test/qemu-aes BINS += util/debug util/reset CFLAGS = -I . -I linux/usr/include @@ -17,7 +19,8 @@ CFLAGS += -fsanitize=address LDLIBS = -lpthread -CACHEPC_UAPI = cachepc/uapi.h cachepc/const.h +TEST_SRCS = test/util.c test/util.h test/kvm.c test/kvm.h +TEST_SRCS += cachepc/uapi.h cachepc/const.h all: build $(BINS) @@ -57,19 +60,25 @@ prep: util/%: util/%.c $(CACHEPC_UAPI) -test/eviction: test/eviction.c test/util.c $(CACHEPC_UAPI) +test/%.o: test/%.c + $(CC) -c -o $@ $^ $(CFLAGS) + +test/%.o: test/%.S + $(CC) -c -o $@ $^ $(CFLAGS) + +test/%_guest: test/%_guest.o test/guest.lds + $(LD) -Ttest/guest.lds -o $@ $< + +test/eviction: test/eviction.c test/util.c $(TEST_SRCS) $(CC) -o $@ $(filter %.c,$^) $(filter %.S,$^) $(CFLAGS) $(LDLIBS) -test/kvm-eviction: test/kvm-eviction.c test/kvm-eviction_guest.S test/util.c \ - test/util.h test/kvm.c test/kvm.h test/kvm-eviction.h $(CACHEPC_UAPI) +test/kvm-eviction: test/kvm-eviction.c test/kvm-eviction.h $(TEST_SRCS) $(CC) -o $@ $(filter %.c,$^) $(filter %.S,$^) $(CFLAGS) $(LDLIBS) -test/kvm-step: test/kvm-step.c test/kvm-step_guest.S \ - test/util.c test/util.h test/kvm.c test/kvm.h $(CACHEPC_UAPI) +test/kvm-step: test/kvm-step.c $(TEST_SRCS) $(CC) -o $@ $(filter %.c,$^) $(filter %.S,$^) $(CFLAGS) $(LDLIBS) -test/kvm-pagestep: test/kvm-pagestep.c test/kvm-pagestep_guest.S \ - test/util.c test/util.h test/kvm.c test/kvm.h $(CACHEPC_UAPI) +test/kvm-pagestep: test/kvm-pagestep.c $(TEST_SRCS) $(CC) -o $@ $(filter %.c,$^) $(filter %.S,$^) $(CFLAGS) $(LDLIBS) .PHONY: all clean host build load prep diff --git a/README b/README index ee74746..1b87962 100644 --- a/README +++ b/README @@ -1,7 +1,7 @@ CachePC ======= -This repository contains proof-of-concept code for a novel cache side-channel +This repository contains proof-of-concept code for a cache side-channel attack dubbed PRIME+COUNT that we demonstrate can be used to circumvent AMD's latest secure virtualization solution SEV-SNP to access sensitive guest information. diff --git a/cachepc/kvm.c b/cachepc/kvm.c index 3809737..559388f 100644 --- a/cachepc/kvm.c +++ b/cachepc/kvm.c @@ -513,7 +513,6 @@ cachepc_kvm_track_mode_ioctl(void __user *arg_user) cachepc_untrack_all(vcpu, KVM_PAGE_TRACK_ACCESS); cachepc_untrack_all(vcpu, KVM_PAGE_TRACK_WRITE); - cachepc_apic_timer = 0; cachepc_apic_oneshot = false; cachepc_singlestep = false; cachepc_singlestep_reset = false; diff --git a/linux b/linux index abccf24..fa82176 160000 --- a/linux +++ b/linux @@ -1 +1 @@ -Subproject commit abccf24ec694dd3d9196b8c03b9c1f0b3f2575ae +Subproject commit fa821762ad7ed234d85318f150bb11ce9a3e2c75 diff --git a/test/.gitignore b/test/.gitignore index 2549182..ad9a84a 100755 --- a/test/.gitignore +++ b/test/.gitignore @@ -1,7 +1,15 @@ +*.o eviction kvm-eviction +kvm-eviction-with_guest +kvm-eviction-without_guest kvm-step +kvm-step_guest kvm-pagestep +kvm-pagestep_guest qemu-eviction +qemu-eviction_guest qemu-aes +qemu-aes_guest qemu-poc +qemu-poc_guest diff --git a/test/guest.lds b/test/guest.lds new file mode 100644 index 0000000..bced66e --- /dev/null +++ b/test/guest.lds @@ -0,0 +1,13 @@ +OUTPUT_FORMAT(binary) + +SECTIONS +{ + .text : { + . = 0; + *(.text) + } + + .data : { + *(.data) + } +} diff --git a/test/kvm-eviction-with_guest.S b/test/kvm-eviction-with_guest.S new file mode 100644 index 0000000..08b365c --- /dev/null +++ b/test/kvm-eviction-with_guest.S @@ -0,0 +1,14 @@ +#include "test/kvm-eviction.h" +#include "cachepc/const.h" + +.text +.align(16) +.code16gcc + +guest: + mov $(L1_LINESIZE * (L1_SETS + TARGET_SET)), %bx + movb (%bx), %bl + hlt + + jmp guest + diff --git a/test/kvm-eviction-without_guest.S b/test/kvm-eviction-without_guest.S new file mode 100644 index 0000000..896a933 --- /dev/null +++ b/test/kvm-eviction-without_guest.S @@ -0,0 +1,12 @@ +#include "test/kvm-eviction.h" +#include "cachepc/const.h" + +.text +.align(16) +.code16gcc + +guest: + hlt + + jmp guest + diff --git a/test/kvm-eviction.c b/test/kvm-eviction.c index 5347f35..cc1fbe3 100644 --- a/test/kvm-eviction.c +++ b/test/kvm-eviction.c @@ -18,11 +18,6 @@ #define TARGET_CORE 2 #define SECONDARY_CORE 3 -extern uint8_t guest_with_start[]; -extern uint8_t guest_with_stop[]; -extern uint8_t guest_without_start[]; -extern uint8_t guest_without_stop[]; - void collect(struct kvm *kvm, uint8_t *counts) { @@ -47,6 +42,7 @@ int main(int argc, const char **argv) { struct kvm vms[2]; + struct guest guests[2]; uint8_t counts[2][SAMPLE_COUNT][L1_SETS]; uint8_t baseline[L1_SETS]; int i, k, ret; @@ -64,8 +60,13 @@ main(int argc, const char **argv) kvm_setup_init(); - vm_init(&vms[WITH], guest_with_start, guest_with_stop); - vm_init(&vms[WITHOUT], guest_without_start, guest_without_stop); + guest_init(&guests[WITH], "test/kvm-eviction-with_guest"); + vm_init(&vms[WITH], &guests[WITH]); + guest_deinit(&guests[WITH]); + + guest_init(&guests[WITHOUT], "test/kvm-eviction-without_guest"); + vm_init(&vms[WITHOUT], &guests[WITHOUT]); + guest_deinit(&guests[WITHOUT]); /* reset kernel module state */ ret = ioctl(kvm_dev, KVM_CPC_RESET); diff --git a/test/kvm-eviction_guest.S b/test/kvm-eviction_guest.S deleted file mode 100644 index 16a07a5..0000000 --- a/test/kvm-eviction_guest.S +++ /dev/null @@ -1,26 +0,0 @@ -#include "test/kvm-eviction.h" -#include "cachepc/const.h" - -.global guest_with_start -.global guest_with_stop - -.global guest_without_start -.global guest_without_stop - -.align(16) -.code16gcc - -guest_with_start: - mov $(L1_LINESIZE * (L1_SETS + TARGET_SET)), %bx - movb (%bx), %bl - hlt - - mov $0x00, %ax - jmp *%ax -guest_with_stop: - -guest_without_start: - hlt - mov $0x00, %ax - jmp *%ax -guest_without_stop: diff --git a/test/kvm-pagestep.c b/test/kvm-pagestep.c index e04429b..5f9d025 100644 --- a/test/kvm-pagestep.c +++ b/test/kvm-pagestep.c @@ -18,9 +18,6 @@ #define TARGET_CORE 2 #define SECONDARY_CORE 3 -extern uint8_t guest_start[]; -extern uint8_t guest_stop[]; - static int child; uint64_t @@ -58,6 +55,7 @@ int main(int argc, const char **argv) { struct ipc *ipc; + struct guest guest; struct kvm kvm; uint64_t eventcnt; uint32_t arg; @@ -82,7 +80,9 @@ main(int argc, const char **argv) if (child == 0) { pin_process(0, TARGET_CORE, true); - vm_init(&kvm, guest_start, guest_stop); + guest_init(&guest, "test/kvm-pagestep_guest"); + vm_init(&kvm, &guest); + guest_deinit(&guest); /* reset kernel module state */ ret = ioctl(kvm_dev, KVM_CPC_RESET, NULL); diff --git a/test/kvm-pagestep_guest.S b/test/kvm-pagestep_guest.S index a936d2d..b40d230 100644 --- a/test/kvm-pagestep_guest.S +++ b/test/kvm-pagestep_guest.S @@ -2,28 +2,23 @@ #define TARGET_SET 15 -.global guest_start -.global guest_stop - +.text .align(16) .code16gcc -guest_start: +guest: .rept L1_SIZE - nop + nop .endr - mov $0x01, %bx - cmp $0x00, %bx + mov $0x01, %bx + cmp $0x00, %bx - # NOTE: this needs to be a relative jmp - je skip + je skip .rept L1_LINESIZE * L1_SETS * 2 - nop + nop .endr skip: - mov $0x00, %ax - jmp *%ax -guest_stop: + jmp guest diff --git a/test/kvm-step.c b/test/kvm-step.c index e3df5d2..ce715d2 100644 --- a/test/kvm-step.c +++ b/test/kvm-step.c @@ -18,9 +18,6 @@ #define TARGET_CORE 2 #define SECONDARY_CORE 3 -extern uint8_t guest_start[]; -extern uint8_t guest_stop[]; - static int child; uint64_t @@ -64,6 +61,7 @@ int main(int argc, const char **argv) { struct ipc *ipc; + struct guest guest; struct kvm kvm; uint8_t baseline[L1_SETS]; struct cpc_event event; @@ -90,7 +88,9 @@ main(int argc, const char **argv) if (child == 0) { pin_process(0, TARGET_CORE, true); - vm_init(&kvm, guest_start, guest_stop); + guest_init(&guest, "test/kvm-step_guest"); + vm_init(&kvm, &guest); + guest_deinit(&guest); /* reset kernel module state */ ret = ioctl(kvm_dev, KVM_CPC_RESET, NULL); diff --git a/test/kvm-step_guest.S b/test/kvm-step_guest.S index 3d1b0e7..dcc8ff3 100644 --- a/test/kvm-step_guest.S +++ b/test/kvm-step_guest.S @@ -2,26 +2,22 @@ #define TARGET_SET 15 -.global guest_start -.global guest_stop - +.text .align(16) .code16gcc -guest_start: - mov $(L1_LINESIZE * (L1_SETS + 11)), %bx - movb (%bx), %bl - hlt +guest: + mov $(L1_LINESIZE * (L1_SETS + 11)), %bx + movb (%bx), %bl + hlt - mov $(L1_LINESIZE * (L1_SETS + 13)), %bx - movb (%bx), %bl - hlt + mov $(L1_LINESIZE * (L1_SETS + 13)), %bx + movb (%bx), %bl + hlt - mov $(L1_LINESIZE * (L1_SETS + 15)), %bx - movb (%bx), %bl - hlt + mov $(L1_LINESIZE * (L1_SETS + 15)), %bx + movb (%bx), %bl + hlt - mov $0x00, %ax - jmp *%ax -guest_stop: + jmp guest diff --git a/test/kvm.c b/test/kvm.c index 34f732c..b2b28fe 100644 --- a/test/kvm.c +++ b/test/kvm.c @@ -203,6 +203,35 @@ snp_dbg_decrypt_rip(int vmfd) return rip; } +void +guest_init(struct guest *guest, const char *filename) +{ + FILE *f; + + f = fopen(filename, "r"); + if (!f) err(1, "fopen"); + + fseek(f, 0, SEEK_END); + guest->code_size = ftell(f); + fseek(f, 0, SEEK_SET); + + guest->code = malloc(guest->code_size); + if (!guest->code) err(1, "malloc"); + + if (!fread(guest->code, guest->code_size, 1, f)) + errx(1, "read guest"); + + guest->mem_size = 0; + + fclose(f); +} + +void +guest_deinit(struct guest *guest) +{ + free(guest->code); +} + void kvm_create_vm(struct kvm *kvm) { @@ -211,20 +240,19 @@ kvm_create_vm(struct kvm *kvm) } void -kvm_init_memory(struct kvm *kvm, size_t ramsize, - void *code_start, void *code_stop) +kvm_init_memory(struct kvm *kvm, size_t mem_size, void *code, size_t code_size) { struct kvm_userspace_memory_region region; int ret; - kvm->memsize = ramsize; + kvm->memsize = mem_size; kvm->mem = mmap(NULL, kvm->memsize, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); if (!kvm->mem) err(1, "mmap kvm->mem"); /* nop slide oob to detect errors quickly */ memset(kvm->mem, 0x90, kvm->memsize); - assert(code_stop - code_start <= kvm->memsize); - memcpy(kvm->mem, code_start, code_stop - code_start); + assert(code_size <= kvm->memsize); + memcpy(kvm->mem, code, code_size); memset(®ion, 0, sizeof(region)); region.slot = 0; @@ -279,12 +307,11 @@ kvm_init_regs(struct kvm *kvm) } void -kvm_init(struct kvm *kvm, size_t ramsize, - void *code_start, void *code_stop) +kvm_init(struct kvm *kvm, struct guest *guest) { kvm_create_vm(kvm); - kvm_init_memory(kvm, ramsize, code_start, code_stop); + kvm_init_memory(kvm, guest->mem_size, guest->code, guest->code_size); kvm_create_vcpu(kvm); @@ -292,8 +319,7 @@ kvm_init(struct kvm *kvm, size_t ramsize, } void -sev_kvm_init(struct kvm *kvm, size_t ramsize, - void *code_start, void *code_stop) +sev_kvm_init(struct kvm *kvm, struct guest *guest) { struct kvm_sev_launch_update_data update; struct kvm_sev_launch_start start; @@ -301,7 +327,7 @@ sev_kvm_init(struct kvm *kvm, size_t ramsize, kvm_create_vm(kvm); - kvm_init_memory(kvm, ramsize, code_start, code_stop); + kvm_init_memory(kvm, guest->mem_size, guest->code, guest->code_size); /* Enable SEV for vm */ ret = sev_ioctl(kvm->vmfd, KVM_SEV_INIT, NULL, &fwerr); @@ -323,7 +349,7 @@ sev_kvm_init(struct kvm *kvm, size_t ramsize, /* Prepare the vm memory (by encrypting it) */ memset(&update, 0, sizeof(update)); update.uaddr = (uintptr_t) kvm->mem; - update.len = ramsize; + update.len = kvm->memsize; 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)); @@ -342,8 +368,7 @@ sev_kvm_init(struct kvm *kvm, size_t ramsize, } void -sev_es_kvm_init(struct kvm *kvm, size_t ramsize, - void *code_start, void *code_stop) +sev_es_kvm_init(struct kvm *kvm, struct guest *guest) { struct kvm_sev_launch_update_data update; struct kvm_sev_launch_start start; @@ -351,7 +376,7 @@ sev_es_kvm_init(struct kvm *kvm, size_t ramsize, kvm_create_vm(kvm); - kvm_init_memory(kvm, ramsize, code_start, code_stop); + kvm_init_memory(kvm, guest->mem_size, guest->code, guest->code_size); /* Enable SEV for vm */ ret = sev_ioctl(kvm->vmfd, KVM_SEV_ES_INIT, NULL, &fwerr); @@ -373,7 +398,7 @@ sev_es_kvm_init(struct kvm *kvm, size_t ramsize, /* Prepare the vm memory (by encrypting it) */ memset(&update, 0, sizeof(update)); update.uaddr = (uintptr_t) kvm->mem; - update.len = ramsize; + update.len = kvm->memsize; 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)); @@ -397,8 +422,7 @@ sev_es_kvm_init(struct kvm *kvm, size_t ramsize, } void -sev_snp_kvm_init(struct kvm *kvm, size_t ramsize, - void *code_start, void *code_stop) +sev_snp_kvm_init(struct kvm *kvm, struct guest *guest) { struct kvm_sev_snp_launch_update update; struct kvm_sev_snp_launch_start start; @@ -409,7 +433,7 @@ sev_snp_kvm_init(struct kvm *kvm, size_t ramsize, kvm_create_vm(kvm); - kvm_init_memory(kvm, ramsize, code_start, code_stop); + kvm_init_memory(kvm, guest->mem_size, guest->code, guest->code_size); /* Enable SEV for vm */ memset(&init, 0, sizeof(init)); @@ -440,7 +464,7 @@ sev_snp_kvm_init(struct kvm *kvm, size_t ramsize, /* Prepare the vm memory */ memset(&update, 0, sizeof(update)); update.uaddr = (uintptr_t) kvm->mem; - update.len = ramsize; + update.len = kvm->memsize; update.start_gfn = 0; update.page_type = KVM_SEV_SNP_PAGE_TYPE_NORMAL; ret = sev_ioctl(kvm->vmfd, KVM_SEV_SNP_LAUNCH_UPDATE, &update, &fwerr); @@ -495,19 +519,19 @@ vm_get_rip(struct kvm *kvm) } void -vm_init(struct kvm *kvm, void *code_start, void *code_end) +vm_init(struct kvm *kvm, struct guest *guest) { - size_t ramsize; + if (!guest->mem_size) + guest->mem_size = L1_SIZE * 2; - ramsize = L1_SIZE * 2; if (!strcmp(vmtype, "kvm")) { - kvm_init(kvm, ramsize, code_start, code_end); + kvm_init(kvm, guest); } else if (!strcmp(vmtype, "sev")) { - sev_kvm_init(kvm, ramsize, code_start, code_end); + sev_kvm_init(kvm, guest); } else if (!strcmp(vmtype, "sev-es")) { - sev_es_kvm_init(kvm, ramsize, code_start, code_end); + sev_es_kvm_init(kvm, guest); } else if (!strcmp(vmtype, "sev-snp")) { - sev_snp_kvm_init(kvm, ramsize, code_start, code_end); + sev_snp_kvm_init(kvm, guest); } else { errx(1, "invalid version"); } diff --git a/test/kvm.h b/test/kvm.h index ffa2df9..58e164e 100644 --- a/test/kvm.h +++ b/test/kvm.h @@ -1,5 +1,7 @@ #pragma once +#include "util.h" + #include #include @@ -22,6 +24,12 @@ struct kvm { struct kvm_run *run; }; +struct guest { + void *code; + size_t code_size; + size_t mem_size; +}; + const char *sev_fwerr_str(int code); const char *sev_gstate_str(int code); @@ -33,19 +41,18 @@ uint64_t sev_dbg_decrypt_rip(int vmfd); void snp_dbg_decrypt(int vmfd, void *src, void *dst, size_t size); uint64_t snp_dbg_decrypt_rip(int vmfd); -void kvm_init(struct kvm *kvm, size_t ramsize, - void *code_start, void *code_stop); -void sev_kvm_init(struct kvm *kvm, size_t ramsize, - void *code_start, void *code_stop); -void sev_es_kvm_init(struct kvm *kvm, size_t ramsize, - void *code_start, void *code_stop); -void sev_snp_kvm_init(struct kvm *kvm, size_t ramsize, - void *code_start, void *code_stop); +void guest_init(struct guest *guest, const char *filename); +void guest_deinit(struct guest *guest); + +void kvm_init(struct kvm *kvm, struct guest *guest); +void sev_kvm_init(struct kvm *kvm, struct guest *guest); +void sev_es_kvm_init(struct kvm *kvm, struct guest *guest); +void sev_snp_kvm_init(struct kvm *kvm, struct guest *guest); void kvm_deinit(struct kvm *kvm); void parse_vmtype(int argc, const char **argv); uint64_t vm_get_rip(struct kvm *kvm); -void vm_init(struct kvm *kvm, void *code_start, void *code_end); +void vm_init(struct kvm *kvm, struct guest *guest); void vm_deinit(struct kvm *kvm); void kvm_setup_init(void); diff --git a/test/qemu-aes.c b/test/qemu-aes.c new file mode 100644 index 0000000..0e6dff6 --- /dev/null +++ b/test/qemu-aes.c @@ -0,0 +1,527 @@ +#define _GNU_SOURCE + +#include "cachepc/uapi.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ARRLEN(x) (sizeof(x) / sizeof((x)[0])) +#define MIN(a,b) ((a) > (b) ? (b) : (a)) + +#define SAMPLE_COUNT 100 + +#define TARGET_CORE 2 +#define SECONDARY_CORE 3 + +#define TARGET_CACHE_LINESIZE 64 +#define TARGET_SET 15 + +struct kvm { + int vmfd, vcpufd; + void *mem; + size_t memsize; + struct kvm_run *run; +}; + +/* start and end for guest assembly */ +extern uint8_t __start_guest_with[]; +extern uint8_t __stop_guest_with[]; + +/* ioctl dev fds */ +static int kvm_dev, sev_dev, kvm_dev; +static int faultcnt; + +enum { + GSTATE_UNINIT, + GSTATE_LUPDATE, + GSTATE_LSECRET, + GSTATE_RUNNING, + GSTATE_SUPDATE, + GSTATE_RUPDATE, + GSTATE_SENT +}; + +const char *sev_fwerr_strs[] = { + "Success", + "Platform state is invalid", + "Guest state is invalid", + "Platform configuration is invalid", + "Buffer too small", + "Platform is already owned", + "Certificate is invalid", + "Policy is not allowed", + "Guest is not active", + "Invalid address", + "Bad signature", + "Bad measurement", + "Asid is already owned", + "Invalid ASID", + "WBINVD is required", + "DF_FLUSH is required", + "Guest handle is invalid", + "Invalid command", + "Guest is active", + "Hardware error", + "Hardware unsafe", + "Feature not supported", + "Invalid parameter", + "Out of resources", + "Integrity checks failed" +}; + +const char *sev_gstate_strs[] = { + "UNINIT", + "LUPDATE", + "LSECRET", + "RUNNING", + "SUPDATE", + "RUPDATE", + "SEND" +}; + +void +hexdump(void *data, int len) +{ + int i; + + for (i = 0; i < len; i++) { + if (i % 16 == 0 && i) + printf("\n"); + printf("%02X ", *(uint8_t *)(data + i)); + } + printf("\n"); +} + +__attribute__((section("guest_with"))) void +vm_guest_with(void) +{ + asm volatile("hlt"); + while (1) { + asm volatile("mov (%[v]), %%bl" + : : [v] "r" (TARGET_CACHE_LINESIZE * TARGET_SET)); + } +} + +bool +pin_process(pid_t pid, int cpu, bool assert) +{ + cpu_set_t cpuset; + int ret; + + CPU_ZERO(&cpuset); + CPU_SET(cpu, &cpuset); + ret = sched_setaffinity(pid, sizeof(cpu_set_t), &cpuset); + if (ret < 0) { + if (assert) err(1, "sched_setaffinity"); + return false; + } + + return true; +} + +int +read_stat_core(pid_t pid) +{ + char path[256]; + char line[2048]; + FILE *file; + char *p; + int i, cpu; + + snprintf(path, sizeof(path), "/proc/%u/stat", pid); + file = fopen(path, "r"); + if (!file) return -1; + + if (!fgets(line, sizeof(line), file)) + err(1, "read stat"); + + p = line; + for (i = 0; i < 38 && (p = strchr(p, ' ')); i++) + p += 1; + + if (!p) errx(1, "stat format"); + cpu = atoi(p); + + fclose(file); + + return cpu; +} + +const char * +sev_fwerr_str(int code) +{ + if (code < 0 || code >= ARRLEN(sev_fwerr_strs)) + return "Unknown error"; + + return sev_fwerr_strs[code]; +} + +const char * +sev_gstate_str(int code) +{ + if (code < 0 || code >= ARRLEN(sev_gstate_strs)) + return "Unknown gstate"; + + return sev_gstate_strs[code]; +} + +int +sev_ioctl(int vmfd, int cmd, void *data, int *error) +{ + struct kvm_sev_cmd input; + int ret; + + memset(&input, 0, sizeof(input)); + input.id = cmd; + input.sev_fd = sev_dev; + input.data = (uintptr_t) data; + + ret = ioctl(vmfd, KVM_MEMORY_ENCRYPT_OP, &input); + if (error) *error = input.error; + + return ret; +} + +uint8_t * +sev_get_measure(int vmfd) +{ + struct kvm_sev_launch_measure msrmt; + int ret, fwerr; + uint8_t *data; + + memset(&msrmt, 0, sizeof(msrmt)); + ret = sev_ioctl(vmfd, KVM_SEV_LAUNCH_MEASURE, &msrmt, &fwerr); + if (ret < 0 && fwerr != SEV_RET_INVALID_LEN) + errx(1, "LAUNCH_MEASURE: (%s) %s", strerror(errno), sev_fwerr_str(fwerr)); + + data = malloc(msrmt.len); + msrmt.uaddr = (uintptr_t) data; + + ret = sev_ioctl(vmfd, KVM_SEV_LAUNCH_MEASURE, &msrmt, &fwerr); + if (ret < 0) + errx(1, "LAUNCH_MEASURE: (%s) %s", strerror(errno), sev_fwerr_str(fwerr)); + + return data; +} + +uint8_t +sev_guest_state(int vmfd, uint32_t handle) +{ + struct kvm_sev_guest_status status; + int ret, fwerr; + + 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)); + } + + return status.state; +} + +void +sev_dbg_encrypt(int vmfd, void *dst, void *src, size_t size) +{ + struct kvm_sev_dbg enc; + int ret, fwerr; + + enc.src_uaddr = (uintptr_t) src; + 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", + strerror(errno), sev_fwerr_str(fwerr)); +} + +void +sev_dbg_decrypt(int vmfd, void *dst, void *src, size_t size) +{ + struct kvm_sev_dbg enc; + int ret, fwerr; + + enc.src_uaddr = (uintptr_t) src; + 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", + strerror(errno), sev_fwerr_str(fwerr)); +} + +void +sev_kvm_init(struct kvm *kvm, size_t ramsize, void *code_start, void *code_stop) +{ + // REF: https://www.amd.com/system/files/TechDocs/55766_SEV-KM_API_Specification.pdf + struct kvm_sev_launch_update_data update; + struct kvm_sev_launch_start start; + struct kvm_userspace_memory_region region; + struct kvm_regs regs; + struct kvm_sregs sregs; + uint8_t *msrmt; + int ret, fwerr; + + /* 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 < 0) err(1, "KVM_SET_USER_MEMORY_REGION"); + + /* Enable SEV for vm */ + ret = sev_ioctl(kvm->vmfd, KVM_SEV_ES_INIT, NULL, &fwerr); + if (ret < 0) 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 < 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"); + sregs.cs.base = 0; + sregs.cs.selector = 0; + ret = ioctl(kvm->vcpufd, KVM_SET_SREGS, &sregs); + if (ret < 0) 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; + ret = ioctl(kvm->vcpufd, KVM_SET_REGS, ®s); + if (ret < 0) err(1, "KVM_SET_REGS"); + + /* 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 < 0) 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 < 0) 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 < 0) errx(1, "KVM_SEV_LAUNCH_UPDATE_VMSA: (%s) %s", + strerror(errno), sev_fwerr_str(fwerr)); + + /* Collect a measurement (necessary) */ + msrmt = sev_get_measure(kvm->vmfd); + free(msrmt); + + /* 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)); + ret = sev_guest_state(kvm->vmfd, start.handle); + if (ret != GSTATE_RUNNING) + errx(1, "Bad guest state: %s", sev_gstate_str(fwerr)); +} + +void +sev_kvm_deinit(struct kvm *kvm) +{ + close(kvm->vmfd); + close(kvm->vcpufd); + munmap(kvm->mem, kvm->memsize); +} + +uint16_t * +read_counts() +{ + uint16_t *counts; + int ret; + + counts = malloc(64 * sizeof(uint16_t)); + if (!counts) err(1, "malloc"); + ret = ioctl(kvm_dev, KVM_CPC_READ_COUNTS, counts); + if (ret == -1) err(1, "ioctl READ_COUNTS"); + + return counts; +} + +void +print_counts(uint16_t *counts) +{ + int i; + + for (i = 0; i < 64; i++) { + if (i % 16 == 0 && i) + printf("\n"); + if (counts[i] == 1) + printf("\x1b[38;5;88m"); + else if (counts[i] > 1) + printf("\x1b[38;5;196m"); + printf("%2i ", i); + if (counts[i] > 0) + printf("\x1b[0m"); + } + printf("\n Target Set %i Count: %hu\n", TARGET_SET, counts[TARGET_SET]); + printf("\n"); +} + +void +runonce(struct kvm *kvm) +{ + struct kvm_regs regs; + int ret; + + ret = ioctl(kvm->vcpufd, KVM_RUN, NULL); + if (ret < 0) err(1, "KVM_RUN"); + printf("VMEXIT\n"); + + 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"); + errx(1, "KVM_EXTI_MMIO: Victim %s at 0x%08llx: rip=0x%08llx\n", + kvm->run->mmio.is_write ? "write" : "read", + kvm->run->mmio.phys_addr, regs.rip); + } else if (kvm->run->exit_reason != KVM_EXIT_HLT) { + errx(1, "KVM died: %i\n", kvm->run->exit_reason); + } +} + +int +monitor(void) +{ + struct cpc_event event; + int ret; + + /* Get page fault info */ + ret = ioctl(kvm_dev, KVM_CPC_POLL_EVENT, &event); + if (!ret) { + printf("Got page fault! %llu retired insts\n", + event.step.retinst); + faultcnt++; + + printf("Acking event %llu\n", event.id); + ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id); + if (ret == -1) err(1, "ioctl ACK_EVENT"); + } else if (errno != EAGAIN) { + perror("ioctl POLL_EVENT"); + return 1; + } + + return 0; +} + +int +main(int argc, const char **argv) +{ + struct kvm kvm_with_access; + uint64_t track_mode; + pid_t ppid, pid; + int ret; + + setvbuf(stdout, NULL, _IONBF, 0); + + pin_process(0, TARGET_CORE, true); + + sev_dev = open("/dev/sev", O_RDWR | O_CLOEXEC); + if (sev_dev < 0) err(1, "open /dev/sev"); + + kvm_dev = open("/dev/kvm", O_RDWR | O_CLOEXEC); + if (kvm_dev < 0) err(1, "open /dev/kvm"); + + /* 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 != 12) errx(1, "KVM_GET_API_VERSION %d, expected 12", ret); + + /* Setup needed performance counters */ + ret = ioctl(kvm_dev, KVM_CPC_SETUP_PMC, NULL); + if (ret < 0) err(1, "ioctl SETUP_PMC"); + + sev_kvm_init(&kvm_with_access, 64 * 64 * 8 * 2, + __start_guest_with, __stop_guest_with); + + /* One run to skip stack setup */ + ioctl(kvm_with_access.vcpufd, KVM_RUN, NULL); + + /* Page tracking init needs to happen after kvm + * init so main_kvm is set.. */ + + /* Reset previous tracking */ + ret = ioctl(kvm_dev, KVM_CPC_RESET_TRACKING, NULL); + if (ret == -1) err(1, "ioctl RESET_TRACKING"); + + /* Init page tracking */ + track_mode = KVM_PAGE_TRACK_ACCESS; + ret = ioctl(kvm_dev, KVM_CPC_TRACK_ALL, &track_mode); + if (ret == -1) err(1, "ioctl TRACK_ALL"); + + ppid = getpid(); + if ((pid = fork())) { + if (pid < 0) err(1, "fork"); + runonce(&kvm_with_access); + } else { + pin_process(0, SECONDARY_CORE, true); + faultcnt = 0; + while (faultcnt < SAMPLE_COUNT) { + if (monitor()) break; + } + kill(ppid, SIGTERM); + exit(0); + } + + sev_kvm_deinit(&kvm_with_access); + + close(kvm_dev); + close(sev_dev); +} + diff --git a/test/qemu-aes_host.c b/test/qemu-aes_host.c deleted file mode 100644 index 0e6dff6..0000000 --- a/test/qemu-aes_host.c +++ /dev/null @@ -1,527 +0,0 @@ -#define _GNU_SOURCE - -#include "cachepc/uapi.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define ARRLEN(x) (sizeof(x) / sizeof((x)[0])) -#define MIN(a,b) ((a) > (b) ? (b) : (a)) - -#define SAMPLE_COUNT 100 - -#define TARGET_CORE 2 -#define SECONDARY_CORE 3 - -#define TARGET_CACHE_LINESIZE 64 -#define TARGET_SET 15 - -struct kvm { - int vmfd, vcpufd; - void *mem; - size_t memsize; - struct kvm_run *run; -}; - -/* start and end for guest assembly */ -extern uint8_t __start_guest_with[]; -extern uint8_t __stop_guest_with[]; - -/* ioctl dev fds */ -static int kvm_dev, sev_dev, kvm_dev; -static int faultcnt; - -enum { - GSTATE_UNINIT, - GSTATE_LUPDATE, - GSTATE_LSECRET, - GSTATE_RUNNING, - GSTATE_SUPDATE, - GSTATE_RUPDATE, - GSTATE_SENT -}; - -const char *sev_fwerr_strs[] = { - "Success", - "Platform state is invalid", - "Guest state is invalid", - "Platform configuration is invalid", - "Buffer too small", - "Platform is already owned", - "Certificate is invalid", - "Policy is not allowed", - "Guest is not active", - "Invalid address", - "Bad signature", - "Bad measurement", - "Asid is already owned", - "Invalid ASID", - "WBINVD is required", - "DF_FLUSH is required", - "Guest handle is invalid", - "Invalid command", - "Guest is active", - "Hardware error", - "Hardware unsafe", - "Feature not supported", - "Invalid parameter", - "Out of resources", - "Integrity checks failed" -}; - -const char *sev_gstate_strs[] = { - "UNINIT", - "LUPDATE", - "LSECRET", - "RUNNING", - "SUPDATE", - "RUPDATE", - "SEND" -}; - -void -hexdump(void *data, int len) -{ - int i; - - for (i = 0; i < len; i++) { - if (i % 16 == 0 && i) - printf("\n"); - printf("%02X ", *(uint8_t *)(data + i)); - } - printf("\n"); -} - -__attribute__((section("guest_with"))) void -vm_guest_with(void) -{ - asm volatile("hlt"); - while (1) { - asm volatile("mov (%[v]), %%bl" - : : [v] "r" (TARGET_CACHE_LINESIZE * TARGET_SET)); - } -} - -bool -pin_process(pid_t pid, int cpu, bool assert) -{ - cpu_set_t cpuset; - int ret; - - CPU_ZERO(&cpuset); - CPU_SET(cpu, &cpuset); - ret = sched_setaffinity(pid, sizeof(cpu_set_t), &cpuset); - if (ret < 0) { - if (assert) err(1, "sched_setaffinity"); - return false; - } - - return true; -} - -int -read_stat_core(pid_t pid) -{ - char path[256]; - char line[2048]; - FILE *file; - char *p; - int i, cpu; - - snprintf(path, sizeof(path), "/proc/%u/stat", pid); - file = fopen(path, "r"); - if (!file) return -1; - - if (!fgets(line, sizeof(line), file)) - err(1, "read stat"); - - p = line; - for (i = 0; i < 38 && (p = strchr(p, ' ')); i++) - p += 1; - - if (!p) errx(1, "stat format"); - cpu = atoi(p); - - fclose(file); - - return cpu; -} - -const char * -sev_fwerr_str(int code) -{ - if (code < 0 || code >= ARRLEN(sev_fwerr_strs)) - return "Unknown error"; - - return sev_fwerr_strs[code]; -} - -const char * -sev_gstate_str(int code) -{ - if (code < 0 || code >= ARRLEN(sev_gstate_strs)) - return "Unknown gstate"; - - return sev_gstate_strs[code]; -} - -int -sev_ioctl(int vmfd, int cmd, void *data, int *error) -{ - struct kvm_sev_cmd input; - int ret; - - memset(&input, 0, sizeof(input)); - input.id = cmd; - input.sev_fd = sev_dev; - input.data = (uintptr_t) data; - - ret = ioctl(vmfd, KVM_MEMORY_ENCRYPT_OP, &input); - if (error) *error = input.error; - - return ret; -} - -uint8_t * -sev_get_measure(int vmfd) -{ - struct kvm_sev_launch_measure msrmt; - int ret, fwerr; - uint8_t *data; - - memset(&msrmt, 0, sizeof(msrmt)); - ret = sev_ioctl(vmfd, KVM_SEV_LAUNCH_MEASURE, &msrmt, &fwerr); - if (ret < 0 && fwerr != SEV_RET_INVALID_LEN) - errx(1, "LAUNCH_MEASURE: (%s) %s", strerror(errno), sev_fwerr_str(fwerr)); - - data = malloc(msrmt.len); - msrmt.uaddr = (uintptr_t) data; - - ret = sev_ioctl(vmfd, KVM_SEV_LAUNCH_MEASURE, &msrmt, &fwerr); - if (ret < 0) - errx(1, "LAUNCH_MEASURE: (%s) %s", strerror(errno), sev_fwerr_str(fwerr)); - - return data; -} - -uint8_t -sev_guest_state(int vmfd, uint32_t handle) -{ - struct kvm_sev_guest_status status; - int ret, fwerr; - - 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)); - } - - return status.state; -} - -void -sev_dbg_encrypt(int vmfd, void *dst, void *src, size_t size) -{ - struct kvm_sev_dbg enc; - int ret, fwerr; - - enc.src_uaddr = (uintptr_t) src; - 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", - strerror(errno), sev_fwerr_str(fwerr)); -} - -void -sev_dbg_decrypt(int vmfd, void *dst, void *src, size_t size) -{ - struct kvm_sev_dbg enc; - int ret, fwerr; - - enc.src_uaddr = (uintptr_t) src; - 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", - strerror(errno), sev_fwerr_str(fwerr)); -} - -void -sev_kvm_init(struct kvm *kvm, size_t ramsize, void *code_start, void *code_stop) -{ - // REF: https://www.amd.com/system/files/TechDocs/55766_SEV-KM_API_Specification.pdf - struct kvm_sev_launch_update_data update; - struct kvm_sev_launch_start start; - struct kvm_userspace_memory_region region; - struct kvm_regs regs; - struct kvm_sregs sregs; - uint8_t *msrmt; - int ret, fwerr; - - /* 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 < 0) err(1, "KVM_SET_USER_MEMORY_REGION"); - - /* Enable SEV for vm */ - ret = sev_ioctl(kvm->vmfd, KVM_SEV_ES_INIT, NULL, &fwerr); - if (ret < 0) 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 < 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"); - sregs.cs.base = 0; - sregs.cs.selector = 0; - ret = ioctl(kvm->vcpufd, KVM_SET_SREGS, &sregs); - if (ret < 0) 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; - ret = ioctl(kvm->vcpufd, KVM_SET_REGS, ®s); - if (ret < 0) err(1, "KVM_SET_REGS"); - - /* 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 < 0) 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 < 0) 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 < 0) errx(1, "KVM_SEV_LAUNCH_UPDATE_VMSA: (%s) %s", - strerror(errno), sev_fwerr_str(fwerr)); - - /* Collect a measurement (necessary) */ - msrmt = sev_get_measure(kvm->vmfd); - free(msrmt); - - /* 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)); - ret = sev_guest_state(kvm->vmfd, start.handle); - if (ret != GSTATE_RUNNING) - errx(1, "Bad guest state: %s", sev_gstate_str(fwerr)); -} - -void -sev_kvm_deinit(struct kvm *kvm) -{ - close(kvm->vmfd); - close(kvm->vcpufd); - munmap(kvm->mem, kvm->memsize); -} - -uint16_t * -read_counts() -{ - uint16_t *counts; - int ret; - - counts = malloc(64 * sizeof(uint16_t)); - if (!counts) err(1, "malloc"); - ret = ioctl(kvm_dev, KVM_CPC_READ_COUNTS, counts); - if (ret == -1) err(1, "ioctl READ_COUNTS"); - - return counts; -} - -void -print_counts(uint16_t *counts) -{ - int i; - - for (i = 0; i < 64; i++) { - if (i % 16 == 0 && i) - printf("\n"); - if (counts[i] == 1) - printf("\x1b[38;5;88m"); - else if (counts[i] > 1) - printf("\x1b[38;5;196m"); - printf("%2i ", i); - if (counts[i] > 0) - printf("\x1b[0m"); - } - printf("\n Target Set %i Count: %hu\n", TARGET_SET, counts[TARGET_SET]); - printf("\n"); -} - -void -runonce(struct kvm *kvm) -{ - struct kvm_regs regs; - int ret; - - ret = ioctl(kvm->vcpufd, KVM_RUN, NULL); - if (ret < 0) err(1, "KVM_RUN"); - printf("VMEXIT\n"); - - 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"); - errx(1, "KVM_EXTI_MMIO: Victim %s at 0x%08llx: rip=0x%08llx\n", - kvm->run->mmio.is_write ? "write" : "read", - kvm->run->mmio.phys_addr, regs.rip); - } else if (kvm->run->exit_reason != KVM_EXIT_HLT) { - errx(1, "KVM died: %i\n", kvm->run->exit_reason); - } -} - -int -monitor(void) -{ - struct cpc_event event; - int ret; - - /* Get page fault info */ - ret = ioctl(kvm_dev, KVM_CPC_POLL_EVENT, &event); - if (!ret) { - printf("Got page fault! %llu retired insts\n", - event.step.retinst); - faultcnt++; - - printf("Acking event %llu\n", event.id); - ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id); - if (ret == -1) err(1, "ioctl ACK_EVENT"); - } else if (errno != EAGAIN) { - perror("ioctl POLL_EVENT"); - return 1; - } - - return 0; -} - -int -main(int argc, const char **argv) -{ - struct kvm kvm_with_access; - uint64_t track_mode; - pid_t ppid, pid; - int ret; - - setvbuf(stdout, NULL, _IONBF, 0); - - pin_process(0, TARGET_CORE, true); - - sev_dev = open("/dev/sev", O_RDWR | O_CLOEXEC); - if (sev_dev < 0) err(1, "open /dev/sev"); - - kvm_dev = open("/dev/kvm", O_RDWR | O_CLOEXEC); - if (kvm_dev < 0) err(1, "open /dev/kvm"); - - /* 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 != 12) errx(1, "KVM_GET_API_VERSION %d, expected 12", ret); - - /* Setup needed performance counters */ - ret = ioctl(kvm_dev, KVM_CPC_SETUP_PMC, NULL); - if (ret < 0) err(1, "ioctl SETUP_PMC"); - - sev_kvm_init(&kvm_with_access, 64 * 64 * 8 * 2, - __start_guest_with, __stop_guest_with); - - /* One run to skip stack setup */ - ioctl(kvm_with_access.vcpufd, KVM_RUN, NULL); - - /* Page tracking init needs to happen after kvm - * init so main_kvm is set.. */ - - /* Reset previous tracking */ - ret = ioctl(kvm_dev, KVM_CPC_RESET_TRACKING, NULL); - if (ret == -1) err(1, "ioctl RESET_TRACKING"); - - /* Init page tracking */ - track_mode = KVM_PAGE_TRACK_ACCESS; - ret = ioctl(kvm_dev, KVM_CPC_TRACK_ALL, &track_mode); - if (ret == -1) err(1, "ioctl TRACK_ALL"); - - ppid = getpid(); - if ((pid = fork())) { - if (pid < 0) err(1, "fork"); - runonce(&kvm_with_access); - } else { - pin_process(0, SECONDARY_CORE, true); - faultcnt = 0; - while (faultcnt < SAMPLE_COUNT) { - if (monitor()) break; - } - kill(ppid, SIGTERM); - exit(0); - } - - sev_kvm_deinit(&kvm_with_access); - - close(kvm_dev); - close(sev_dev); -} - diff --git a/test/qemu-eviction.c b/test/qemu-eviction.c new file mode 100644 index 0000000..2761d8c --- /dev/null +++ b/test/qemu-eviction.c @@ -0,0 +1,362 @@ +#define _GNU_SOURCE + +#include "cachepc/uapi.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ARRLEN(x) (sizeof(x) / sizeof((x)[0])) +#define MIN(a,b) ((a) > (b) ? (b) : (a)) + +#define TARGET_CORE 2 +#define SECONDARY_CORE 3 + +#define TARGET_SET 15 + +/* ioctl dev fds */ +static int kvm_dev; +static int faultcnt; + +void +hexdump(void *data, int len) +{ + int i; + + for (i = 0; i < len; i++) { + if (i % 16 == 0 && i) + printf("\n"); + printf("%02X ", *(uint8_t *)(data + i)); + } + printf("\n"); +} + +bool +pin_process(pid_t pid, int cpu, bool assert) +{ + cpu_set_t cpuset; + int ret; + + CPU_ZERO(&cpuset); + CPU_SET(cpu, &cpuset); + ret = sched_setaffinity(pid, sizeof(cpu_set_t), &cpuset); + if (ret < 0) { + if (assert) err(1, "sched_setaffinity"); + return false; + } + + return true; +} + +cpc_msrmt_t * +read_counts() +{ + cpc_msrmt_t *counts; + int i, ret; + + counts = malloc(L1_SETS * sizeof(cpc_msrmt_t)); + if (!counts) err(1, "malloc"); + + ret = ioctl(kvm_dev, KVM_CPC_READ_COUNTS, counts); + if (ret) err(1, "ioctl READ_COUNTS"); + + for (i = 0; i < L1_SETS; i++) { + if (counts[i] > 8) + errx(1, "Invalid counts set %i", i); + } + + return counts; +} + +void +print_counts(cpc_msrmt_t *counts) +{ + int i; + + for (i = 0; i < 64; i++) { + if (i % 16 == 0 && i) + printf("\n"); + if (counts[i] == 1) + printf("\x1b[38;5;88m"); + else if (counts[i] > 1) + printf("\x1b[38;5;196m"); + printf("%2i ", i); + if (counts[i] > 0) + printf("\x1b[0m"); + } + printf("\n"); +} + +void +print_counts_raw(cpc_msrmt_t *counts) +{ + int i; + + for (i = 0; i < 64; i++) { + if (i % 16 == 0 && i) + printf("\n"); + if (counts[i] == 1) + printf("\x1b[38;5;88m"); + else if (counts[i] > 1) + printf("\x1b[38;5;196m"); + printf("%02X ", (uint8_t) counts[i]); + if (counts[i] > 0) + printf("\x1b[0m"); + } + printf("\n"); +} + +int +monitor(bool baseline) +{ + struct cpc_event event; + cpc_msrmt_t counts[64]; + uint64_t inst_fault_gfn; + uint64_t read_fault_gfn; + uint64_t arg; + int ret, i; + + /* Get page fault info */ + ret = ioctl(kvm_dev, KVM_CPC_POLL_EVENT, &event); + if (ret) { + if (errno == EAGAIN) + return 0; + perror("ioctl POLL_EVENT"); + return 1; + } + + if (event.type == CPC_EVENT_CPUID) { + printf("CPUID EVENT\n"); + if (event.guest.type == CPC_GUEST_START_TRACK) { + ret = ioctl(kvm_dev, KVM_CPC_TRACK_EXEC_CUR, &inst_fault_gfn); + if (ret) err(1, "ioctl TRACK_EXEC_CUR"); + + printf("CPUID INST PAGE: %lu\n", inst_fault_gfn); + + arg = inst_fault_gfn; + ret = ioctl(kvm_dev, KVM_CPC_TRACK_RANGE_START, &arg); + if (ret) err(1, "ioctl TRACK_RANGE_START"); + + arg = inst_fault_gfn+8; + ret = ioctl(kvm_dev, KVM_CPC_TRACK_RANGE_END, &arg); + if (ret) err(1, "ioctl TRACK_RANGE_END"); + } else if (event.guest.type == CPC_GUEST_STOP_TRACK) { + arg = 0; + ret = ioctl(kvm_dev, KVM_CPC_TRACK_RANGE_START, &arg); + if (ret) err(1, "ioctl TRACK_RANGE_START"); + + arg = 0; + ret = ioctl(kvm_dev, KVM_CPC_TRACK_RANGE_END, &arg); + if (ret) err(1, "ioctl TRACK_RANGE_END"); + } + + faultcnt++; + } else if (event.type == CPC_EVENT_TRACK_STEP) { + printf("STEP EVENT\n"); + + ret = ioctl(kvm_dev, KVM_CPC_READ_COUNTS, counts); + if (ret) err(1, "ioctl READ_COUNTS"); + + inst_fault_gfn = 0; + read_fault_gfn = 0; + for (i = 0; i < event.step.fault_count; i++) { + if ((event.step.fault_errs[i] & 0b11111) == 0b10100) + inst_fault_gfn = event.step.fault_gfns[i]; + else if ((event.step.fault_errs[i] & 0b00110) == 0b00100) + read_fault_gfn = event.step.fault_gfns[i]; + } + + if (!baseline) { + printf("Event: cnt:%llu inst:%lu data:%lu retired:%llu\n", + event.step.fault_count, inst_fault_gfn, + read_fault_gfn, event.step.retinst); + print_counts(counts); + printf("\n"); + } + + for (i = 0; i < 64; i++) { + if (counts[i] > 8) { + warnx("Invalid count for set %i (%llu)", + i, counts[i]); + counts[i] = 8; + } + } + + if (baseline) faultcnt++; + } else if (event.type == CPC_EVENT_TRACK_PAGE) { + printf("PAGE EVENT\n"); + + printf("Event: prev:%llu new:%llu retired:%llu\n", + event.page.inst_gfn_prev, event.page.inst_gfn, + event.page.retinst); + } + + ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id); + if (ret) err(1, "ioctl ACK_EVENT"); + + return 0; +} + +int +pgrep(const char *bin) +{ + char path[PATH_MAX]; + char buf[PATH_MAX]; + char *cmp; + struct dirent *ent; + FILE *f; + DIR *dir; + + dir = opendir("/proc"); + if (!dir) err(1, "opendir"); + + while ((ent = readdir(dir))) { + snprintf(path, sizeof(path), "/proc/%s/cmdline", ent->d_name); + f = fopen(path, "rb"); + if (!f) continue; + memset(buf, 0, sizeof(buf)); + fread(buf, 1, sizeof(buf), f); + if ((cmp = strrchr(buf, '/'))) + cmp += 1; + else + cmp = buf; + if (!strcmp(cmp, bin)) + return atoi(ent->d_name); + fclose(f); + } + + closedir(dir); + + return 0; +} + +int +main(int argc, const char **argv) +{ + pid_t pid; + uint32_t arg; + struct cpc_event event; + cpc_msrmt_t baseline[64]; + int ret, i; + + kvm_setup_init(); + + setvbuf(stdout, NULL, _IONBF, 0); + + pid = pgrep("qemu-system-x86_64"); + if (!pid) errx(1, "Failed to find qemu instance"); + printf("PID %i\n", pid); + + pin_process(pid, TARGET_CORE, true); + pin_process(0, TARGET_CORE, true); + + /* Setup needed performance counters */ + ret = ioctl(kvm_dev, KVM_CPC_SETUP_PMC, NULL); + if (ret < 0) err(1, "ioctl SETUP_PMC"); + + /* Reset previous tracking */ + ret = ioctl(kvm_dev, KVM_CPC_RESET_TRACKING, NULL); + if (ret) err(1, "ioctl RESET_TRACKING"); + + pin_process(0, SECONDARY_CORE, true); + printf("PINNED\n"); + + // arg = false; + // ret = ioctl(kvm_dev, KVM_CPC_SUB_BASELINE, &arg); + // if (ret) err(1, "ioctl SUB_BASELINE"); + + // arg = true; + // ret = ioctl(kvm_dev, KVM_CPC_MEASURE_BASELINE, &arg); + // if (ret) err(1, "ioctl MEASURE_BASELINE"); + + // arg = KVM_PAGE_TRACK_ACCESS; + // ret = ioctl(kvm_dev, KVM_CPC_TRACK_ALL, &arg); + // if (ret) err(1, "ioctl TRACK_ALL"); + + // arg = CPC_TRACK_DATA_ACCESS; + // ret = ioctl(kvm_dev, KVM_CPC_TRACK_MODE, &arg); + // if (ret) err(1, "ioctl TRACK_MODE"); + + // faultcnt = 0; + // while (faultcnt < 100) { + // if (monitor(true)) break; + // } + + // do { + // ret = ioctl(kvm_dev, KVM_CPC_POLL_EVENT, &event); + // if (ret && errno != EAGAIN) + // err(1, "ioctl POLL_EVENT"); + // } while (ret && errno == EAGAIN); + + // arg = KVM_PAGE_TRACK_ACCESS; + // ret = ioctl(kvm_dev, KVM_CPC_UNTRACK_ALL, &arg); + // if (ret) err(1, "ioctl UNTRACK_ALL"); + + arg = CPC_TRACK_EXEC; + ret = ioctl(kvm_dev, KVM_CPC_TRACK_MODE, &arg); + if (ret) err(1, "ioctl TRACK_MODE"); + + arg = KVM_PAGE_TRACK_EXEC; + ret = ioctl(kvm_dev, KVM_CPC_TRACK_ALL, &arg); + if (ret) err(1, "ioctl TRACK_ALL"); + + // arg = false; + // ret = ioctl(kvm_dev, KVM_CPC_MEASURE_BASELINE, &arg); + // if (ret) err(1, "ioctl MEASURE_BASELINE"); + + // ret = ioctl(kvm_dev, KVM_CPC_READ_BASELINE, baseline); + // if (ret) err(1, "ioctl READ_BASELINE"); + + // printf("\n>>> BASELINE:\n"); + // print_counts(baseline); + // printf("\n"); + // print_counts_raw(baseline); + // printf("\n"); + + // /* Check baseline for saturated sets */ + // for (i = 0; i < 64; i++) { + // if (baseline[i] >= 8) + // errx(1, "!!! Baseline set %i full\n", i); + // } + + // arg = true; + // ret = ioctl(kvm_dev, KVM_CPC_SUB_BASELINE, &arg); + // if (ret) err(1, "ioctl SUB_BASELINE"); + + // ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id); + // if (ret) err(1, "ioctl ACK_EVENT"); + + faultcnt = 0; + while (faultcnt < 10) { + if (monitor(false)) break; + } + + arg = KVM_PAGE_TRACK_EXEC; + ret = ioctl(kvm_dev, KVM_CPC_UNTRACK_ALL, &arg); + if (ret) err(1, "ioctl UNTRACK_ALL"); + + kvm_setup_deinit(); +} + diff --git a/test/qemu-eviction_host.c b/test/qemu-eviction_host.c deleted file mode 100644 index 87a5edd..0000000 --- a/test/qemu-eviction_host.c +++ /dev/null @@ -1,361 +0,0 @@ -#define _GNU_SOURCE - -#include "cachepc/uapi.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define ARRLEN(x) (sizeof(x) / sizeof((x)[0])) -#define MIN(a,b) ((a) > (b) ? (b) : (a)) - -#define TARGET_CORE 2 -#define SECONDARY_CORE 3 - -#define TARGET_SET 15 - -/* ioctl dev fds */ -static int kvm_dev; -static int faultcnt; - -void -hexdump(void *data, int len) -{ - int i; - - for (i = 0; i < len; i++) { - if (i % 16 == 0 && i) - printf("\n"); - printf("%02X ", *(uint8_t *)(data + i)); - } - printf("\n"); -} - -bool -pin_process(pid_t pid, int cpu, bool assert) -{ - cpu_set_t cpuset; - int ret; - - CPU_ZERO(&cpuset); - CPU_SET(cpu, &cpuset); - ret = sched_setaffinity(pid, sizeof(cpu_set_t), &cpuset); - if (ret < 0) { - if (assert) err(1, "sched_setaffinity"); - return false; - } - - return true; -} - -cpc_msrmt_t * -read_counts() -{ - cpc_msrmt_t *counts; - int i, ret; - - counts = malloc(L1_SETS * sizeof(cpc_msrmt_t)); - if (!counts) err(1, "malloc"); - - ret = ioctl(kvm_dev, KVM_CPC_READ_COUNTS, counts); - if (ret) err(1, "ioctl READ_COUNTS"); - - for (i = 0; i < L1_SETS; i++) { - if (counts[i] > 8) - errx(1, "Invalid counts set %i", i); - } - - return counts; -} - -void -print_counts(cpc_msrmt_t *counts) -{ - int i; - - for (i = 0; i < 64; i++) { - if (i % 16 == 0 && i) - printf("\n"); - if (counts[i] == 1) - printf("\x1b[38;5;88m"); - else if (counts[i] > 1) - printf("\x1b[38;5;196m"); - printf("%2i ", i); - if (counts[i] > 0) - printf("\x1b[0m"); - } - printf("\n"); -} - -void -print_counts_raw(cpc_msrmt_t *counts) -{ - int i; - - for (i = 0; i < 64; i++) { - if (i % 16 == 0 && i) - printf("\n"); - if (counts[i] == 1) - printf("\x1b[38;5;88m"); - else if (counts[i] > 1) - printf("\x1b[38;5;196m"); - printf("%02X ", (uint8_t) counts[i]); - if (counts[i] > 0) - printf("\x1b[0m"); - } - printf("\n"); -} - -int -monitor(bool baseline) -{ - struct cpc_event event; - cpc_msrmt_t counts[64]; - uint64_t inst_fault_gfn; - uint64_t read_fault_gfn; - uint64_t arg; - int ret, i; - - /* Get page fault info */ - ret = ioctl(kvm_dev, KVM_CPC_POLL_EVENT, &event); - if (ret) { - if (errno == EAGAIN) - return 0; - perror("ioctl POLL_EVENT"); - return 1; - } - - if (event.type == CPC_EVENT_CPUID) { - printf("CPUID EVENT\n"); - if (event.guest.type == CPC_GUEST_START_TRACK) { - ret = ioctl(kvm_dev, KVM_CPC_TRACK_EXEC_CUR, &inst_fault_gfn); - if (ret) err(1, "ioctl TRACK_EXEC_CUR"); - - printf("CPUID INST PAGE: %lu\n", inst_fault_gfn); - - arg = inst_fault_gfn; - ret = ioctl(kvm_dev, KVM_CPC_TRACK_RANGE_START, &arg); - if (ret) err(1, "ioctl TRACK_RANGE_START"); - - arg = inst_fault_gfn+8; - ret = ioctl(kvm_dev, KVM_CPC_TRACK_RANGE_END, &arg); - if (ret) err(1, "ioctl TRACK_RANGE_END"); - } else if (event.guest.type == CPC_GUEST_STOP_TRACK) { - arg = 0; - ret = ioctl(kvm_dev, KVM_CPC_TRACK_RANGE_START, &arg); - if (ret) err(1, "ioctl TRACK_RANGE_START"); - - arg = 0; - ret = ioctl(kvm_dev, KVM_CPC_TRACK_RANGE_END, &arg); - if (ret) err(1, "ioctl TRACK_RANGE_END"); - } - - faultcnt++; - } else if (event.type == CPC_EVENT_TRACK_STEP) { - printf("STEP EVENT\n"); - - ret = ioctl(kvm_dev, KVM_CPC_READ_COUNTS, counts); - if (ret) err(1, "ioctl READ_COUNTS"); - - inst_fault_gfn = 0; - read_fault_gfn = 0; - for (i = 0; i < event.step.fault_count; i++) { - if ((event.step.fault_errs[i] & 0b11111) == 0b10100) - inst_fault_gfn = event.step.fault_gfns[i]; - else if ((event.step.fault_errs[i] & 0b00110) == 0b00100) - read_fault_gfn = event.step.fault_gfns[i]; - } - - if (!baseline) { - printf("Event: cnt:%llu inst:%lu data:%lu retired:%llu\n", - event.step.fault_count, inst_fault_gfn, - read_fault_gfn, event.step.retinst); - print_counts(counts); - printf("\n"); - } - - for (i = 0; i < 64; i++) { - if (counts[i] > 8) { - warnx("Invalid count for set %i (%llu)", - i, counts[i]); - counts[i] = 8; - } - } - - if (baseline) faultcnt++; - } else if (event.type == CPC_EVENT_TRACK_PAGE) { - printf("PAGE EVENT\n"); - - printf("Event: prev:%llu new:%llu retired:%llu\n", - event.page.inst_gfn_prev, event.page.inst_gfn, - event.page.retinst); - } - - ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id); - if (ret) err(1, "ioctl ACK_EVENT"); - - return 0; -} - -int -pgrep(const char *bin) -{ - char path[PATH_MAX]; - char buf[PATH_MAX]; - char *cmp; - struct dirent *ent; - FILE *f; - DIR *dir; - - dir = opendir("/proc"); - if (!dir) err(1, "opendir"); - - while ((ent = readdir(dir))) { - snprintf(path, sizeof(path), "/proc/%s/cmdline", ent->d_name); - f = fopen(path, "rb"); - if (!f) continue; - memset(buf, 0, sizeof(buf)); - fread(buf, 1, sizeof(buf), f); - if ((cmp = strrchr(buf, '/'))) - cmp += 1; - else - cmp = buf; - if (!strcmp(cmp, bin)) - return atoi(ent->d_name); - fclose(f); - } - - closedir(dir); - - return 0; -} - -int -main(int argc, const char **argv) -{ - pid_t pid; - uint32_t arg; - struct cpc_event event; - cpc_msrmt_t baseline[64]; - int ret, i; - - kvm_dev = open("/dev/kvm", O_RDWR); - if (!kvm_dev) err(1, "open /dev/kvm"); - - setvbuf(stdout, NULL, _IONBF, 0); - - pid = pgrep("qemu-system-x86_64"); - if (!pid) errx(1, "Failed to find qemu instance"); - printf("PID %i\n", pid); - - pin_process(pid, TARGET_CORE, true); - pin_process(0, TARGET_CORE, true); - - /* Setup needed performance counters */ - ret = ioctl(kvm_dev, KVM_CPC_SETUP_PMC, NULL); - if (ret < 0) err(1, "ioctl SETUP_PMC"); - - /* Reset previous tracking */ - ret = ioctl(kvm_dev, KVM_CPC_RESET_TRACKING, NULL); - if (ret) err(1, "ioctl RESET_TRACKING"); - - pin_process(0, SECONDARY_CORE, true); - printf("PINNED\n"); - - // arg = false; - // ret = ioctl(kvm_dev, KVM_CPC_SUB_BASELINE, &arg); - // if (ret) err(1, "ioctl SUB_BASELINE"); - - // arg = true; - // ret = ioctl(kvm_dev, KVM_CPC_MEASURE_BASELINE, &arg); - // if (ret) err(1, "ioctl MEASURE_BASELINE"); - - // arg = KVM_PAGE_TRACK_ACCESS; - // ret = ioctl(kvm_dev, KVM_CPC_TRACK_ALL, &arg); - // if (ret) err(1, "ioctl TRACK_ALL"); - - // arg = CPC_TRACK_DATA_ACCESS; - // ret = ioctl(kvm_dev, KVM_CPC_TRACK_MODE, &arg); - // if (ret) err(1, "ioctl TRACK_MODE"); - - // faultcnt = 0; - // while (faultcnt < 100) { - // if (monitor(true)) break; - // } - - // do { - // ret = ioctl(kvm_dev, KVM_CPC_POLL_EVENT, &event); - // if (ret && errno != EAGAIN) - // err(1, "ioctl POLL_EVENT"); - // } while (ret && errno == EAGAIN); - - // arg = KVM_PAGE_TRACK_ACCESS; - // ret = ioctl(kvm_dev, KVM_CPC_UNTRACK_ALL, &arg); - // if (ret) err(1, "ioctl UNTRACK_ALL"); - - arg = CPC_TRACK_EXEC; - ret = ioctl(kvm_dev, KVM_CPC_TRACK_MODE, &arg); - if (ret) err(1, "ioctl TRACK_MODE"); - - arg = KVM_PAGE_TRACK_EXEC; - ret = ioctl(kvm_dev, KVM_CPC_TRACK_ALL, &arg); - if (ret) err(1, "ioctl TRACK_ALL"); - - // arg = false; - // ret = ioctl(kvm_dev, KVM_CPC_MEASURE_BASELINE, &arg); - // if (ret) err(1, "ioctl MEASURE_BASELINE"); - - // ret = ioctl(kvm_dev, KVM_CPC_READ_BASELINE, baseline); - // if (ret) err(1, "ioctl READ_BASELINE"); - - // printf("\n>>> BASELINE:\n"); - // print_counts(baseline); - // printf("\n"); - // print_counts_raw(baseline); - // printf("\n"); - - // /* Check baseline for saturated sets */ - // for (i = 0; i < 64; i++) { - // if (baseline[i] >= 8) - // errx(1, "!!! Baseline set %i full\n", i); - // } - - // arg = true; - // ret = ioctl(kvm_dev, KVM_CPC_SUB_BASELINE, &arg); - // if (ret) err(1, "ioctl SUB_BASELINE"); - - // ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id); - // if (ret) err(1, "ioctl ACK_EVENT"); - - faultcnt = 0; - while (faultcnt < 10) { - if (monitor(false)) break; - } - - arg = KVM_PAGE_TRACK_EXEC; - ret = ioctl(kvm_dev, KVM_CPC_UNTRACK_ALL, &arg); - if (ret) err(1, "ioctl UNTRACK_ALL"); -} - diff --git a/test/util.c b/test/util.c index 6fc38d2..8b27578 100644 --- a/test/util.c +++ b/test/util.c @@ -192,3 +192,4 @@ ipc_wait_parent(struct ipc *ipc) ipc->has_sig_parent = false; pthread_mutex_unlock(&ipc->lock); } + diff --git a/util/disasm b/util/disasm index d8247e1..99b2d21 100755 --- a/util/disasm +++ b/util/disasm @@ -1,12 +1,12 @@ #!/bin/sh if [ $# -lt 2 ]; then - echo "Usage: guest_asm FILE FUNC (guest)" + echo "Usage: guest_asm FILE FUNC" exit 1 fi ARCH="i386" -if [ "$3" = "guest" ]; then +if [ "$2" = "guest" ]; then ARCH="i8086" fi -- cgit v1.2.3-71-gd317