diff options
| author | Louis Burda <quent.burda@gmail.com> | 2023-02-03 11:59:43 -0600 |
|---|---|---|
| committer | Louis Burda <quent.burda@gmail.com> | 2023-02-03 11:59:43 -0600 |
| commit | 1715c9d6e1aa977b407081fb3164edbf1534fb5c (patch) | |
| tree | 1802d90d850164f2387098c238214641b75e86e9 /test/kvm-targetstep.c | |
| parent | 0c825583fc20f1b91c56e1aaf450d6a753d24658 (diff) | |
| download | cachepc-1715c9d6e1aa977b407081fb3164edbf1534fb5c.tar.gz cachepc-1715c9d6e1aa977b407081fb3164edbf1534fb5c.zip | |
Properly implement target gfn stepping
Diffstat (limited to 'test/kvm-targetstep.c')
| -rw-r--r-- | test/kvm-targetstep.c | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/test/kvm-targetstep.c b/test/kvm-targetstep.c new file mode 100644 index 0000000..f30563c --- /dev/null +++ b/test/kvm-targetstep.c @@ -0,0 +1,227 @@ +#include "test/kvm-eviction.h" +#include "test/kvm.h" +#include "test/util.h" +#include "cachepc/uapi.h" + +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <signal.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <err.h> +#include <string.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> + +static int child; +static struct cpc_event event; + +uint64_t +monitor(struct kvm *kvm, bool baseline) +{ + uint8_t counts[L1_SETS]; + int ret; + + ret = ioctl(kvm_dev, KVM_CPC_POLL_EVENT, &event); + if (ret && errno == EAGAIN) return 0; + if (ret) err(1, "KVM_CPC_POLL_EVENT"); + + if (!baseline && event.type == CPC_EVENT_GUEST + && event.guest.type == CPC_GUEST_STOP_TRACK) + return 2; + + if (event.type == CPC_EVENT_TRACK_STEP) { + ret = ioctl(kvm_dev, KVM_CPC_READ_COUNTS, counts); + if (ret) err(1, "KVM_CPC_READ_COUNTS"); + + printf("Event: rip:%08llx cnt:%llu inst:%08llx data:%08llx ret:%llu\n", + vm_get_rip(), event.step.fault_count, + event.step.fault_gfns[0], event.step.fault_gfns[1], + event.step.retinst); + print_counts(counts); + printf("\n"); + print_counts_raw(counts); + printf("\n"); + } + + ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id); + if (ret) err(1, "KVM_CPC_ACK_EVENT"); + + return 1; +} + +void +kill_child(void) +{ + printf("Killing vm..\n"); + kill(child, SIGKILL); +} + +int +main(int argc, const char **argv) +{ + struct ipc *ipc; + struct guest guest; + struct kvm kvm; + uint8_t baseline[L1_SETS]; + struct cpc_track_cfg cfg; + bool inst_gfn_avail; + uint64_t inst_gfn; + uint64_t eventcnt; + uint32_t arg; + int ret; + + vmtype = "kvm"; + if (argc > 1) vmtype = argv[1]; + if (strcmp(vmtype, "kvm") && strcmp(vmtype, "sev") + && strcmp(vmtype, "sev-es") + && strcmp(vmtype, "sev-snp")) + errx(1, "invalid vm mode: %s", vmtype); + + setvbuf(stdout, NULL, _IONBF, 0); + + kvm_setup_init(); + + ipc = ipc_alloc(); + + child = fork(); + if (child < 0) err(1, "fork"); + + if (child == 0) { + pin_process(0, TARGET_CORE, true); + + guest_init(&guest, "test/kvm-targetstep_guest"); + vm_init(&kvm, &guest); + guest_deinit(&guest); + + /* reset kernel module state */ + ret = ioctl(kvm_dev, KVM_CPC_RESET, NULL); + if (ret < 0) err(1, "KVM_CPC_RESET"); + + ipc_signal_parent(ipc); + ipc_wait_parent(ipc); + + printf("VM start\n"); + + do { + ret = ioctl(kvm.vcpufd, KVM_RUN, NULL); + if (ret < 0) err(1, "KVM_RUN"); + } while (kvm.run->exit_reason == KVM_EXIT_HLT); + + printf("VM exit\n"); + + vm_deinit(&kvm); + } else { + pin_process(0, SECONDARY_CORE, true); + + atexit(kill_child); + + ipc_wait_child(ipc); + + printf("Monitor start\n"); + + memset(&cfg, 0, sizeof(cfg)); + cfg.mode = CPC_TRACK_STEPS; + cfg.steps.with_data = true; + ret = ioctl(kvm_dev, KVM_CPC_TRACK_MODE, &cfg); + if (ret) err(1, "KVM_CPC_TRACK_MODE"); + + arg = true; + ret = ioctl(kvm_dev, KVM_CPC_CALC_BASELINE, &arg); + if (ret) err(1, "KVM_CPC_CALC_BASELINE"); + + ipc_signal_child(ipc); + + /* run vm while baseline is calculated */ + eventcnt = 0; + while (eventcnt < 50) { + eventcnt += monitor(&kvm, true); + } + + ret = ioctl(kvm_dev, KVM_CPC_VM_REQ_PAUSE); + if (ret) err(1, "KVM_CPC_VM_REQ_PAUSE"); + + while (1) { + ret = ioctl(kvm_dev, KVM_CPC_POLL_EVENT, &event); + if (ret && errno == EAGAIN) continue; + if (ret) err(1, "KVM_CPC_POLL_EVENT"); + + if (event.type == CPC_EVENT_PAUSE) break; + + ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id); + if (ret) err(1, "KVM_CPC_ACK_EVENT"); + } + + arg = false; + ret = ioctl(kvm_dev, KVM_CPC_CALC_BASELINE, &arg); + if (ret) err(1, "KVM_CPC_CALC_BASELINE"); + + ret = ioctl(kvm_dev, KVM_CPC_READ_BASELINE, baseline); + if (ret) err(1, "KVM_CPC_READ_BASELINE"); + + printf("\nBaseline:\n"); + print_counts(baseline); + printf("\n"); + print_counts_raw(baseline); + printf("\n\n"); + + arg = true; + ret = ioctl(kvm_dev, KVM_CPC_APPLY_BASELINE, &arg); + if (ret) err(1, "KMV_CPC_APPLY_BASELINE"); + + memset(&cfg, 0, sizeof(cfg)); + cfg.mode = CPC_TRACK_PAGES; + ret = ioctl(kvm_dev, KVM_CPC_TRACK_MODE, &cfg); + if (ret) err(1, "KVM_CPC_TRACK_MODE"); + + ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id); + if (ret) err(1, "KVM_CPC_ACK_EVENT"); + + /* wait for CPC_GUEST_START_TRACK */ + + inst_gfn_avail = false; + while (1) { + ret = ioctl(kvm_dev, KVM_CPC_POLL_EVENT, &event); + if (ret && errno == EAGAIN) continue; + if (ret) err(1, "KVM_CPC_POLL_EVENT"); + + if (inst_gfn_avail && event.type == CPC_EVENT_GUEST + && event.guest.type == CPC_GUEST_START_TRACK) + break; + + if (event.type == CPC_EVENT_TRACK_PAGE) { + inst_gfn = event.page.inst_gfn; + inst_gfn_avail = true; + } + + ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id); + if (ret) err(1, "KVM_CPC_ACK_EVENT"); + } + + /* start step tracking for target gfn */ + + printf("Target GFN: %08llx\n", inst_gfn); + + memset(&cfg, 0, sizeof(cfg)); + cfg.mode = CPC_TRACK_STEPS; + cfg.steps.target_gfn = inst_gfn; + cfg.steps.use_target = true; + cfg.steps.with_data = true; + ret = ioctl(kvm_dev, KVM_CPC_TRACK_MODE, &cfg); + if (ret) err(1, "KVM_CPC_TRACK_MODE"); + + ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id); + if (ret) err(1, "KVM_CPC_ACK_EVENT"); + + while (monitor(&kvm, false) != 2); + + printf("Monitor exit\n"); + } + + ipc_free(ipc); + + kvm_setup_deinit(); +} + |
