commit 501c6bcf4513d40a53022dc93d4156402d43670b
parent 1fe8249bbc782d28185e0e893504e8ac3a1fcaec
Author: Louis Burda <quent.burda@gmail.com>
Date: Tue, 24 Jan 2023 01:43:18 +0100
Page track support (without speculation)
Diffstat:
4 files changed, 62 insertions(+), 97 deletions(-)
diff --git a/cachepc/cachepc.h b/cachepc/cachepc.h
@@ -65,6 +65,12 @@ struct cpc_fault {
struct list_head list;
};
+struct cpc_track_exec {
+ bool cur_avail;
+ uint64_t cur_gfn;
+ uint64_t retinst;
+};
+
static_assert(sizeof(struct cacheline) == L1_LINESIZE, "Bad cacheline struct");
static_assert(CPC_CL_NEXT_OFFSET == offsetof(struct cacheline, next));
static_assert(CPC_CL_PREV_OFFSET == offsetof(struct cacheline, prev));
@@ -128,9 +134,7 @@ extern uint64_t cachepc_rip;
extern uint64_t cachepc_rip_prev;
extern bool cachepc_rip_prev_set;
-extern uint64_t cachepc_inst_fault_gfn;
-extern uint32_t cachepc_inst_fault_err;
-extern uint64_t cachepc_inst_fault_retinst;
+extern struct cpc_track_exec cachepc_track_exec;
extern struct list_head cachepc_faults;
diff --git a/cachepc/kvm.c b/cachepc/kvm.c
@@ -71,12 +71,8 @@ EXPORT_SYMBOL(cachepc_track_end_gfn);
LIST_HEAD(cachepc_faults);
EXPORT_SYMBOL(cachepc_faults);
-uint64_t cachepc_inst_fault_gfn = 0;
-uint32_t cachepc_inst_fault_err = 0;
-uint64_t cachepc_inst_fault_retinst = 0;
-EXPORT_SYMBOL(cachepc_inst_fault_gfn);
-EXPORT_SYMBOL(cachepc_inst_fault_err);
-EXPORT_SYMBOL(cachepc_inst_fault_retinst);
+struct cpc_track_exec cachepc_track_exec;
+EXPORT_SYMBOL(cachepc_track_exec);
cache_ctx *cachepc_ctx = NULL;
cacheline *cachepc_ds = NULL;
@@ -290,6 +286,8 @@ cachepc_kvm_reset_ioctl(void __user *arg_user)
put_cpu();
+ cachepc_events_reset();
+
cachepc_kvm_reset_tracking_ioctl(NULL);
cachepc_kvm_reset_baseline_ioctl(NULL);
@@ -477,12 +475,11 @@ cachepc_kvm_reset_tracking_ioctl(void __user *arg_user)
cachepc_untrack_all(vcpu, KVM_PAGE_TRACK_ACCESS);
cachepc_untrack_all(vcpu, KVM_PAGE_TRACK_WRITE);
- cachepc_inst_fault_gfn = 0;
- cachepc_inst_fault_err = 0;
-
cachepc_track_start_gfn = 0;
cachepc_track_end_gfn = 0;
+ memset(&cachepc_track_exec, 0, sizeof(cachepc_track_exec));
+
cachepc_singlestep = false;
cachepc_singlestep_reset = false;
@@ -526,22 +523,22 @@ cachepc_kvm_track_mode_ioctl(void __user *arg_user)
case CPC_TRACK_FULL:
cachepc_track_all(vcpu, KVM_PAGE_TRACK_ACCESS);
cachepc_singlestep_reset = true;
- cachepc_track_mode = CPC_TRACK_FULL;
break;
case CPC_TRACK_EXEC:
cachepc_track_all(vcpu, KVM_PAGE_TRACK_EXEC);
cachepc_singlestep_reset = true;
- cachepc_track_mode = CPC_TRACK_EXEC;
break;
case CPC_TRACK_FAULT_NO_RUN:
cachepc_track_all(vcpu, KVM_PAGE_TRACK_ACCESS);
- cachepc_track_mode = CPC_TRACK_FAULT_NO_RUN;
break;
- default:
- cachepc_track_mode = CPC_TRACK_NONE;
+ case CPC_TRACK_NONE:
break;
+ default:
+ return -EINVAL;
}
+ cachepc_track_mode = mode;
+
return 0;
}
@@ -740,8 +737,7 @@ cachepc_kvm_init(void)
cachepc_apic_oneshot = false;
cachepc_apic_timer = 0;
- cachepc_inst_fault_gfn = 0;
- cachepc_inst_fault_err = 0;
+ memset(&cachepc_track_exec, 0, sizeof(cachepc_track_exec));
INIT_LIST_HEAD(&cachepc_faults);
diff --git a/test/kvm-pagestep.c b/test/kvm-pagestep.c
@@ -5,8 +5,8 @@
#include <sys/ioctl.h>
#include <sys/mman.h>
-#include <unistd.h>
#include <signal.h>
+#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <err.h>
@@ -21,11 +21,12 @@
extern uint8_t guest_start[];
extern uint8_t guest_stop[];
+static int child;
+
uint64_t
monitor(struct kvm *kvm, bool baseline)
{
struct cpc_event event;
- uint8_t counts[64];
int ret;
/* Get page fault info */
@@ -33,17 +34,12 @@ monitor(struct kvm *kvm, bool baseline)
if (ret && errno == EAGAIN) return 0;
if (ret) err(1, "ioctl KVM_CPC_POLL_EVENT");
- if (event.type != CPC_EVENT_TRACK_STEP)
+ if (event.type != CPC_EVENT_TRACK_PAGE)
errx(1, "unexpected event type %i", event.type);
- ret = ioctl(kvm_dev, KVM_CPC_READ_COUNTS, counts);
- if (ret) err(1, "ioctl KVM_CPC_READ_COUNTS");
-
- printf("Event: rip:%llu cnt:%llu inst:%llu data:%llu ret:%llu\n",
- vm_get_rip(kvm), event.step.fault_count,
- event.step.fault_gfns[0], event.step.fault_gfns[1],
- event.step.retinst);
- print_counts(counts);
+ printf("Event: rip:%08llx prev:%llu next:%llu ret:%llu\n",
+ vm_get_rip(kvm), event.page.inst_gfn_prev,
+ event.page.inst_gfn, event.page.retinst);
printf("\n");
ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id);
@@ -52,36 +48,48 @@ monitor(struct kvm *kvm, bool baseline)
return 1;
}
+void
+kill_child(void)
+{
+ kill(child, SIGKILL);
+}
+
int
main(int argc, const char **argv)
{
+ struct ipc *ipc;
struct kvm kvm;
- uint8_t baseline[L1_SETS];
- struct cpc_event event;
uint64_t eventcnt;
- pid_t ppid, pid;
uint32_t arg;
int ret;
- parse_vmtype(argc, argv);
+ 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);
- pin_process(0, TARGET_CORE, true);
-
kvm_setup_init();
- vm_init(&kvm, guest_start, guest_stop);
+ ipc = ipc_alloc();
+
+ child = fork();
+ if (child < 0) err(1, "fork");
- /* reset kernel module state */
- ret = ioctl(kvm_dev, KVM_CPC_RESET, NULL);
- if (ret < 0) err(1, "ioctl KVM_CPC_RESET");
+ if (child == 0) {
+ pin_process(0, TARGET_CORE, true);
- ppid = getpid();
- if ((pid = fork())) {
- if (pid < 0) err(1, "fork");
+ vm_init(&kvm, guest_start, guest_stop);
- sleep(1); /* give time for child to pin other core */
+ /* reset kernel module state */
+ ret = ioctl(kvm_dev, KVM_CPC_RESET, NULL);
+ if (ret < 0) err(1, "ioctl KVM_CPC_RESET");
+
+ ipc_signal_parent(ipc);
+ ipc_wait_parent(ipc);
printf("VM start\n");
@@ -94,72 +102,32 @@ main(int argc, const char **argv)
} while (kvm.run->exit_reason == KVM_EXIT_HLT);
printf("VM exit\n");
+
+ vm_deinit(&kvm);
} else {
pin_process(0, SECONDARY_CORE, true);
- /* capture baseline by just letting it fault over and over */
- arg = CPC_TRACK_EXEC;
- ret = ioctl(kvm_dev, KVM_CPC_TRACK_MODE, &arg);
- if (ret) err(1, "ioctl KVM_CPC_TRACK_MODE");
-
- printf("Monitor ready\n");
-
- /* 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, "ioctl KVM_CPC_VM_REQ_PAUSE");
+ atexit(kill_child);
- while (1) {
- ret = ioctl(kvm_dev, KVM_CPC_POLL_EVENT, &event);
- if (ret && errno == EAGAIN) continue;
- if (ret) err(1, "ioctl KVM_CPC_POLL_EVENT");
+ ipc_wait_child(ipc);
- if (event.type == CPC_EVENT_PAUSE) break;
+ printf("Monitor start\n");
- printf("Skipping non-pause event..\n");
- ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id);
- if (ret) err(1, "ioctl KVM_CPC_ACK_EVENT");
- }
-
- arg = false;
- ret = ioctl(kvm_dev, KVM_CPC_CALC_BASELINE, &arg);
- if (ret) err(1, "ioctl KVM_CPC_CALC_BASELINE");
-
- ret = ioctl(kvm_dev, KVM_CPC_READ_BASELINE, baseline);
- if (ret) err(1, "ioctl 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, "ioctl KMV_CPC_APPLY_BASELINE");
-
- /* single step and log all accessed pages */
- arg = CPC_TRACK_FULL;
+ arg = CPC_TRACK_EXEC;
ret = ioctl(kvm_dev, KVM_CPC_TRACK_MODE, &arg);
if (ret) err(1, "ioctl KVM_CPC_TRACK_MODE");
- ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id);
- if (ret) err(1, "ioctl KVM_CPC_ACK_EVENT");
+ ipc_signal_child(ipc);
eventcnt = 0;
while (eventcnt < 50) {
- eventcnt += monitor(&kvm, false);
+ eventcnt += monitor(&kvm, true);
}
- kill(ppid, SIGINT);
- exit(0);
+ printf("Monitor exit\n");
}
- vm_deinit(&kvm);
+ ipc_free(ipc);
kvm_setup_deinit();
}
diff --git a/test/kvm.c b/test/kvm.c
@@ -226,9 +226,6 @@ kvm_init_memory(struct kvm *kvm, size_t ramsize,
assert(code_stop - code_start <= kvm->memsize);
memcpy(kvm->mem, code_start, code_stop - code_start);
- printf("KVM Memory:\n");
- hexdump(code_start, code_stop - code_start);
-
memset(®ion, 0, sizeof(region));
region.slot = 0;
region.memory_size = kvm->memsize;