From 82d56ef77c114ac0b375fef04cea3a50f10f1843 Mon Sep 17 00:00:00 2001 From: Louis Burda Date: Tue, 22 Nov 2022 15:03:02 +0100 Subject: Improved single stepping and added initial cpuid events --- test/.gitignore | 4 + test/access-detect_guest.c | 26 ++++ test/access-detect_host.c | 288 +++++++++++++++++++++++++++++++++++++++++++++ test/aes-detect_guest | Bin 1007048 -> 826488 bytes test/aes-detect_guest.c | 16 +++ test/sevstep.c | 33 ++++-- 6 files changed, 355 insertions(+), 12 deletions(-) create mode 100644 test/access-detect_guest.c create mode 100644 test/access-detect_host.c (limited to 'test') diff --git a/test/.gitignore b/test/.gitignore index c2e8d30..f54caf0 100755 --- a/test/.gitignore +++ b/test/.gitignore @@ -5,3 +5,7 @@ sev sev-es sev-snp sevstep +aes-detect_guest +aes-detect_host +access-detect_guest +access-detect_host diff --git a/test/access-detect_guest.c b/test/access-detect_guest.c new file mode 100644 index 0000000..442c88c --- /dev/null +++ b/test/access-detect_guest.c @@ -0,0 +1,26 @@ +#include "cachepc/uapi.h" + +#include +#include +#include +#include +#include + +int +main(int argc, const char **argv) +{ + void *buf; + + buf = NULL; + if (posix_memalign(&buf, L1_LINESIZE * L1_SETS, L1_LINESIZE * L1_SETS)) + err(1, "memalign"); + memset(buf, 0, L1_LINESIZE * L1_SETS); + + while (1) { + CPC_CPUID_SIGNAL(CPC_CPUID_START_TRACK, 0); + + *(uint8_t *)(buf + L1_LINESIZE * 5) += 1; + + CPC_CPUID_SIGNAL(CPC_CPUID_START_TRACK, 0); + } +} diff --git a/test/access-detect_host.c b/test/access-detect_host.c new file mode 100644 index 0000000..9ede56f --- /dev/null +++ b/test/access-detect_host.c @@ -0,0 +1,288 @@ +#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 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 == -1) 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 track_mode; + int ret, i; + + /* Get page fault info */ + ret = ioctl(kvm_dev, KVM_CPC_POLL_EVENT, &event); + if (!ret) { + if (event.type == CPC_EVENT_CPUID) { + printf("CPUID EVENT\n"); + if (event.cpuid.type == CPC_CPUID_START_TRACK) { + track_mode = KVM_PAGE_TRACK_ACCESS; + ret = ioctl(kvm_dev, KVM_CPC_TRACK_ALL, &track_mode); + if (ret) err(1, "ioctl TRACK_ALL"); + } else if (event.cpuid.type == CPC_CPUID_STOP_TRACK) { + track_mode = KVM_PAGE_TRACK_ACCESS; + ret = ioctl(kvm_dev, KVM_CPC_UNTRACK_ALL, &track_mode); + if (ret) err(1, "ioctl UNTRACK_ALL"); + } + return 0; + } else if (event.type != CPC_EVENT_TRACK) { + return 0; + } + + printf("EVENT\n"); + + ret = ioctl(kvm_dev, KVM_CPC_READ_COUNTS, counts); + if (ret == -1) err(1, "ioctl READ_COUNTS"); + + if (!baseline) { + printf("Event: inst:%llu data:%llu retired:%llu\n", + event.track.inst_fault_gfn, + event.track.data_fault_gfn, + event.track.retinst); + print_counts(counts); + printf("\n"); + } + + for (i = 0; i < 64; i++) { + if (counts[i] > 8) { + errx(1, "Invalid count for set %i (%llu)", + i, counts[i]); + } + } + + ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.track.id); + if (ret == -1) err(1, "ioctl ACK_EVENT"); + + faultcnt++; + } else if (errno != EAGAIN) { + perror("ioctl POLL_EVENT"); + return 1; + } + + 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; + + if (argc <= 1 || !atoi(argv[1])) { + printf("Specify qemu process to pin\n"); + return 0; + } + + kvm_dev = open("/dev/kvm", O_RDWR); + if (!kvm_dev) err(1, "open /dev/kvm"); + + setvbuf(stdout, NULL, _IONBF, 0); + + pid = atoi(argv[1]); + 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 == -1) err(1, "ioctl RESET_TRACKING"); + + /* Do data access stepping */ + arg = CPC_TRACK_DATA_ACCESS; + ret = ioctl(kvm_dev, KVM_CPC_TRACK_MODE, &arg); + if (ret == -1) err(1, "ioctl TRACK_MODE"); + + pin_process(0, SECONDARY_CORE, true); + printf("PINNED\n"); + + arg = false; + ret = ioctl(kvm_dev, KVM_CPC_SUB_BASELINE, &arg); + if (ret == -1) err(1, "ioctl SUB_BASELINE"); + + arg = true; + ret = ioctl(kvm_dev, KVM_CPC_MEASURE_BASELINE, &arg); + if (ret == -1) 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"); + + faultcnt = 0; + while (faultcnt < 100) { + if (monitor(true)) break; + } + + arg = KVM_PAGE_TRACK_ACCESS; + ret = ioctl(kvm_dev, KVM_CPC_UNTRACK_ALL, &arg); + if (ret) err(1, "ioctl TRACK_ALL"); + + do { + ret = ioctl(kvm_dev, KVM_CPC_POLL_EVENT, &event); + if (ret == -1 && errno != EAGAIN) + err(1, "ioctl POLL_EVENT"); + } while (ret == -1 && errno == EAGAIN); + + arg = false; + ret = ioctl(kvm_dev, KVM_CPC_MEASURE_BASELINE, &arg); + if (ret == -1) err(1, "ioctl MEASURE_BASELINE"); + + ret = ioctl(kvm_dev, KVM_CPC_READ_BASELINE, baseline); + if (ret == -1) 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 == -1) err(1, "ioctl SUB_BASELINE"); + + ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.track.id); + if (ret == -1) err(1, "ioctl ACK_EVENT"); + + faultcnt = 0; + while (faultcnt < 10) { + if (monitor(false)) break; + } +} + diff --git a/test/aes-detect_guest b/test/aes-detect_guest index de1ec2f..d482fd2 100755 Binary files a/test/aes-detect_guest and b/test/aes-detect_guest differ diff --git a/test/aes-detect_guest.c b/test/aes-detect_guest.c index 4012b74..80a6a64 100644 --- a/test/aes-detect_guest.c +++ b/test/aes-detect_guest.c @@ -30,8 +30,24 @@ main(int argc, const char **argv) { struct kcapi_handle *kcapi; uint8_t block[128]; + uint8_t *buf; size_t n; + buf = NULL; + if (posix_memalign((void *)&buf, L1_LINESIZE * L1_SETS, L1_LINESIZE * L1_SETS)) + err(1, "memalign"); + memset(buf, 0, L1_LINESIZE * L1_SETS); + + while (1) { + CPC_CPUID_SIGNAL(CPC_CPUID_START_TRACK, 0); + + buf[L1_LINESIZE * 5] += 1; + + CPC_CPUID_SIGNAL(CPC_CPUID_START_TRACK, 0); + } + + return 0; + kcapi = NULL; if (kcapi_cipher_init(&kcapi, "ecb(aes)", 0)) err(1, "kcapi init"); diff --git a/test/sevstep.c b/test/sevstep.c index 3307245..40130c5 100644 --- a/test/sevstep.c +++ b/test/sevstep.c @@ -481,7 +481,7 @@ int monitor(struct kvm *kvm, bool baseline) { static uint64_t rip_prev = 1; - struct cpc_track_event event; + struct cpc_event event; cpc_msrmt_t counts[64]; uint64_t rip; int ret, i; @@ -489,17 +489,24 @@ monitor(struct kvm *kvm, bool baseline) /* Get page fault info */ ret = ioctl(kvm_dev, KVM_CPC_POLL_EVENT, &event); if (!ret) { + if (event.type != CPC_EVENT_TRACK) + return 0; + ret = ioctl(kvm_dev, KVM_CPC_READ_COUNTS, counts); if (ret == -1) err(1, "ioctl READ_COUNTS"); rip = sev_dbg_rip(kvm->vmfd); if (!baseline && rip != rip_prev) { printf("Event: inst:%llu data:%llu retired:%llu rip:%lu\n", - event.inst_fault_gfn, event.data_fault_gfn, - event.retinst, rip); + event.track.inst_fault_gfn, + event.track.data_fault_gfn, + event.track.retinst, rip); print_counts(counts); printf("\n"); rip_prev = rip; + faultcnt++; + } else if (baseline) { + faultcnt++; } for (i = 0; i < 64; i++) { @@ -511,8 +518,6 @@ monitor(struct kvm *kvm, bool baseline) ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id); if (ret == -1) err(1, "ioctl ACK_EVENT"); - - faultcnt++; } else if (errno != EAGAIN) { perror("ioctl POLL_EVENT"); return 1; @@ -528,7 +533,7 @@ main(int argc, const char **argv) uint64_t track_mode; pid_t ppid, pid; uint32_t arg; - struct cpc_track_event event; + struct cpc_event event; cpc_msrmt_t baseline[64]; int ret, i; @@ -571,6 +576,14 @@ main(int argc, const char **argv) ret = ioctl(kvm_dev, KVM_CPC_TRACK_ALL, &track_mode); if (ret == -1) err(1, "ioctl TRACK_ALL"); + arg = false; + ret = ioctl(kvm_dev, KVM_CPC_SUB_BASELINE, &arg); + if (ret == -1) err(1, "ioctl SUB_BASELINE"); + + arg = true; + ret = ioctl(kvm_dev, KVM_CPC_MEASURE_BASELINE, &arg); + if (ret == -1) err(1, "ioctl MEASURE_BASELINE"); + ppid = getpid(); if ((pid = fork())) { if (pid < 0) err(1, "fork"); @@ -584,12 +597,8 @@ main(int argc, const char **argv) pin_process(0, SECONDARY_CORE, true); printf("PINNED\n"); - arg = true; - ret = ioctl(kvm_dev, KVM_CPC_MEASURE_BASELINE, &arg); - if (ret == -1) err(1, "ioctl MEASURE_BASELINE"); - faultcnt = 0; - while (faultcnt < 50) { + while (faultcnt < 300) { if (monitor(&kvm_with_access, true)) break; } @@ -626,7 +635,7 @@ main(int argc, const char **argv) if (ret == -1) err(1, "ioctl ACK_EVENT"); faultcnt = 0; - while (faultcnt < 50) { + while (faultcnt < 20) { if (monitor(&kvm_with_access, false)) break; } -- cgit v1.2.3-71-gd317