summaryrefslogtreecommitdiffstats
path: root/test/access-detect_host.c
diff options
context:
space:
mode:
authorLouis Burda <quent.burda@gmail.com>2022-11-22 15:03:02 +0100
committerLouis Burda <quent.burda@gmail.com>2022-11-22 15:03:02 +0100
commit82d56ef77c114ac0b375fef04cea3a50f10f1843 (patch)
tree397acfbcb5f1c2584a03f6201d95120d6f299361 /test/access-detect_host.c
parentafe49b52f6b2ac52efe8e610e64ee07c7c2efef4 (diff)
downloadcachepc-82d56ef77c114ac0b375fef04cea3a50f10f1843.tar.gz
cachepc-82d56ef77c114ac0b375fef04cea3a50f10f1843.zip
Improved single stepping and added initial cpuid events
Diffstat (limited to 'test/access-detect_host.c')
-rw-r--r--test/access-detect_host.c288
1 files changed, 288 insertions, 0 deletions
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 <linux/psp-sev.h>
+#include <linux/kvm.h>
+#include <sys/syscall.h>
+#include <sys/ioctl.h>
+#include <sys/user.h>
+#include <sys/wait.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <signal.h>
+#include <dirent.h>
+#include <assert.h>
+#include <errno.h>
+#include <err.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#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;
+ }
+}
+