commit c308b0d3af8c052cd3dbe22143435917da6e7988
parent d4ac8d64359fcaf25a65196c83ba0a091f645a3b
Author: Louis Burda <quent.burda@gmail.com>
Date: Fri, 4 Nov 2022 14:56:50 +0100
Enable tracking data fault after instruction fetch
Diffstat:
6 files changed, 69 insertions(+), 58 deletions(-)
diff --git a/cachepc/cachepc.c b/cachepc/cachepc.c
@@ -1,9 +1,6 @@
#include "cachepc.h"
#include "uapi.h"
-#include "../../include/asm/apic.h"
-#include "../../include/asm/irq_vectors.h"
-
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/slab.h>
@@ -315,18 +312,10 @@ cachepc_update_baseline(void)
}
}
-void
-cachepc_apic_oneshot(uint32_t interval)
-{
- pr_warn("CachePCTest: Setting up APIC oneshot\n");
- native_apic_mem_write(APIC_LVTT, LOCAL_TIMER_VECTOR | APIC_LVT_TIMER_ONESHOT);
- native_apic_mem_write(APIC_TDCR, APIC_TDR_DIV_2);
- native_apic_mem_write(APIC_TMICT, interval);
-}
-
void __attribute__((optimize(1))) // prevent instruction reordering
cachepc_prime_vcall(uintptr_t ret, cacheline *cl)
{
+ cachepc_apic_oneshot(150);
cachepc_prime(cl);
asm volatile ("mov %0, %%rax; jmp *%%rax" : : "r"(ret) : "rax");
}
diff --git a/cachepc/cachepc.h b/cachepc/cachepc.h
@@ -3,6 +3,9 @@
#include "asm.h"
#include "uapi.h"
+#include "../../include/asm/apic.h"
+#include "../../include/asm/irq_vectors.h"
+
#define L1_CACHE 0
#define L2_CACHE 1
@@ -93,8 +96,6 @@ void cachepc_save_msrmts(cacheline *head);
void cachepc_print_msrmts(cacheline *head);
void cachepc_update_baseline(void);
-void cachepc_apic_oneshot(uint32_t interval);
-
void cachepc_prime_vcall(uintptr_t ret, cacheline *cl);
void cachepc_probe_vcall(uintptr_t ret, cacheline *cl);
@@ -113,6 +114,9 @@ static inline void cachepc_victim(void *p);
__attribute__((always_inline))
static inline uint64_t cachepc_read_pmc(uint64_t event);
+__attribute__((always_inline))
+static inline void cachepc_apic_oneshot(uint32_t interval);
+
extern cpc_msrmt_t *cachepc_msrmts;
extern size_t cachepc_msrmts_count;
@@ -124,8 +128,10 @@ extern uint64_t cachepc_retinst;
extern bool cachepc_single_step;
extern bool cachepc_track_single_step;
-extern uint64_t cachepc_last_fault_gfn;
-extern uint32_t cachepc_last_fault_err;
+extern bool cachepc_inst_fault_avail;
+extern uint64_t cachepc_inst_fault_gfn;
+extern bool cachepc_data_fault_avail;
+extern uint64_t cachepc_data_fault_gfn;
extern cache_ctx *cachepc_ctx;
extern cacheline *cachepc_ds;
@@ -271,3 +277,11 @@ cachepc_read_pmc(uint64_t event)
return res;
}
+
+void
+cachepc_apic_oneshot(uint32_t interval)
+{
+ native_apic_mem_write(APIC_LVTT, LOCAL_TIMER_VECTOR | APIC_LVT_TIMER_ONESHOT);
+ native_apic_mem_write(APIC_TDCR, APIC_TDR_DIV_2);
+ native_apic_mem_write(APIC_TMICT, interval);
+}
diff --git a/cachepc/kvm.c b/cachepc/kvm.c
@@ -27,12 +27,16 @@ EXPORT_SYMBOL(cachepc_retinst);
bool cachepc_single_step = false;
bool cachepc_track_single_step = false;
-uint64_t cachepc_last_fault_gfn;
-uint32_t cachepc_last_fault_err;
+bool cachepc_inst_fault_avail = false;
+uint64_t cachepc_inst_fault_gfn = 0;
+bool cachepc_data_fault_avail = false;
+uint64_t cachepc_data_fault_gfn = 0;
EXPORT_SYMBOL(cachepc_single_step);
EXPORT_SYMBOL(cachepc_track_single_step);
-EXPORT_SYMBOL(cachepc_last_fault_gfn);
-EXPORT_SYMBOL(cachepc_last_fault_err);
+EXPORT_SYMBOL(cachepc_inst_fault_avail);
+EXPORT_SYMBOL(cachepc_inst_fault_gfn);
+EXPORT_SYMBOL(cachepc_data_fault_avail);
+EXPORT_SYMBOL(cachepc_data_fault_gfn);
cache_ctx *cachepc_ctx = NULL;
cacheline *cachepc_ds = NULL;
@@ -671,6 +675,10 @@ cachepc_kvm_init(void)
cachepc_single_step = false;
cachepc_track_single_step = false;
+ cachepc_data_fault_avail = false;
+ cachepc_data_fault_gfn = 0;
+ cachepc_inst_fault_avail = false;
+ cachepc_inst_fault_gfn = 0;
cachepc_msrmts_count = L1_SETS;
cachepc_msrmts = kzalloc(cachepc_msrmts_count * sizeof(cpc_msrmt_t), GFP_KERNEL);
diff --git a/cachepc/mmu.c b/cachepc/mmu.c
@@ -6,40 +6,38 @@ static void
sevstep_uspt_page_fault_handle(struct kvm_vcpu *vcpu,
struct kvm_page_fault *fault)
{
- const int modes[] = {
- KVM_PAGE_TRACK_WRITE,
- KVM_PAGE_TRACK_ACCESS,
- KVM_PAGE_TRACK_EXEC
- };
- bool was_tracked;
int err;
- int i;
- pr_warn("CachePCTest: Page fault %llu\n", fault->gfn);
-
- was_tracked = false;
- for (i = 0; i < sizeof(modes) / sizeof(modes[0]); i++) {
- if (kvm_slot_page_track_is_active(vcpu->kvm,
- fault->slot, fault->gfn, modes[i])) {
- pr_warn("CachePCTest: Page attrs %i %i %i\n",
- fault->present, fault->write, fault->user);
- sevstep_untrack_single(vcpu, fault->gfn, modes[i]);
- if (!cachepc_track_single_step)
- sevstep_track_single(vcpu, fault->gfn, modes[i]);
- was_tracked = true;
- }
- }
+ if (kvm_slot_page_track_is_active(vcpu->kvm,
+ fault->slot, fault->gfn, KVM_PAGE_TRACK_ACCESS)) {
+ pr_warn("Sevstep: Tracked page fault (gfn:%llu err:%u)\n",
+ fault->gfn, fault->error_code);
+ //pr_warn("Sevstep: Tracked page fault attrs %i %i %i\n",
+ // fault->present, fault->write, fault->user);
+
+ sevstep_untrack_single(vcpu, fault->gfn, KVM_PAGE_TRACK_ACCESS);
- if (was_tracked) {
- pr_warn("Sevstep: Tracked page fault (gfn:%llu)", fault->gfn);
if (cachepc_track_single_step) {
- cachepc_last_fault_gfn = fault->gfn;
- cachepc_last_fault_err = fault->error_code;
- cachepc_single_step = true;
+ if (cachepc_single_step && cachepc_inst_fault_avail) {
+ /* faulted during single step => data address */
+ pr_warn("Sevstep: Got data fault gfn:%llu\n", fault->gfn);
+
+ BUG_ON(!cachepc_inst_fault_avail);
+ cachepc_data_fault_gfn = fault->gfn;
+ cachepc_data_fault_avail = true;
+ } else {
+ /* first fault from instruction fetch */
+ pr_warn("Sevstep: Got inst fault gfn:%llu\n", fault->gfn);
+
+ cachepc_inst_fault_gfn = fault->gfn;
+ cachepc_inst_fault_avail = true;
+ cachepc_data_fault_avail = false;
+ cachepc_single_step = true;
+ }
} else {
- err = sevstep_uspt_send_and_block(fault->gfn,
- fault->error_code);
- if (err) pr_warn("Sevstep: uspt_send_and_block failed (%d)\n", err);
+ sevstep_track_single(vcpu, fault->gfn, KVM_PAGE_TRACK_ACCESS);
+ if (sevstep_uspt_send_and_block(fault->gfn, 0))
+ pr_warn("Sevstep: uspt_send_and_block failed (%d)\n", err);
}
}
}
@@ -50,7 +48,7 @@ sevstep_spte_protect(u64 *sptep, bool pt_protect, enum kvm_page_track_mode mode)
u64 spte;
bool flush;
- pr_warn("Sevstep: spte_protect\n");
+ // pr_warn("Sevstep: spte_protect\n");
spte = *sptep;
if (!is_writable_pte(spte) && !(pt_protect && is_mmu_writable_spte(spte)))
@@ -85,7 +83,7 @@ sevstep_spte_protect(u64 *sptep, bool pt_protect, enum kvm_page_track_mode mode)
}
flush |= mmu_spte_update(sptep, spte);
- pr_warn("Sevstep: spte_protect flush:%i\n", flush);
+ // pr_warn("Sevstep: spte_protect flush:%i\n", flush);
return flush;
}
@@ -117,7 +115,7 @@ sevstep_kvm_mmu_slot_gfn_protect(struct kvm *kvm, struct kvm_memory_slot *slot,
protected = false;
- pr_warn("Sevstep: mmu_slot_gfn_protect gfn:%llu\n", gfn);
+ // pr_warn("Sevstep: mmu_slot_gfn_protect gfn:%llu\n", gfn);
if (kvm_memslots_have_rmaps(kvm)) {
for (i = min_level; i <= KVM_MAX_HUGEPAGE_LEVEL; ++i) {
@@ -128,10 +126,10 @@ sevstep_kvm_mmu_slot_gfn_protect(struct kvm *kvm, struct kvm_memory_slot *slot,
protected |= sevstep_tdp_protect_gfn(kvm,
slot, gfn, min_level, mode);
} else {
- pr_warn("CachePC: Tracking unsupported!\n");
+ pr_err("CachePC: Tracking unsupported!\n");
}
- return true;
+ return protected;
}
EXPORT_SYMBOL(sevstep_kvm_mmu_slot_gfn_protect);
diff --git a/cachepc/sevstep.c b/cachepc/sevstep.c
@@ -62,6 +62,8 @@ sevstep_track_single(struct kvm_vcpu *vcpu, gfn_t gfn,
srcu_read_unlock(&vcpu->kvm->srcu, idx);
+ if (!slot) pr_err("Sevstep: Failed to track gfn %llu\n", gfn);
+
return slot != NULL;
}
EXPORT_SYMBOL(sevstep_track_single);
@@ -84,6 +86,8 @@ sevstep_untrack_single(struct kvm_vcpu *vcpu, gfn_t gfn,
srcu_read_unlock(&vcpu->kvm->srcu, idx);
+ if (!slot) pr_err("Sevstep: Failed to untrack gfn %llu\n", gfn);
+
return slot != NULL;
}
EXPORT_SYMBOL(sevstep_untrack_single);
diff --git a/test/sevstep.c b/test/sevstep.c
@@ -30,8 +30,6 @@
#define ARRLEN(x) (sizeof(x) / sizeof((x)[0]))
#define MIN(a,b) ((a) > (b) ? (b) : (a))
-#define SAMPLE_COUNT 20
-
#define TARGET_CORE 2
#define SECONDARY_CORE 3
@@ -528,7 +526,7 @@ main(int argc, const char **argv)
if (ret == -1) err(1, "ioctl MEASURE_BASELINE");
faultcnt = 0;
- while (faultcnt < SAMPLE_COUNT) {
+ while (faultcnt < 20) {
if (monitor(&kvm_with_access)) break;
}
@@ -561,7 +559,7 @@ main(int argc, const char **argv)
if (ret == -1) err(1, "ioctl TRACK_SINGLE_STEP");
faultcnt = 0;
- while (faultcnt < SAMPLE_COUNT) {
+ while (faultcnt < 100) {
if (monitor(&kvm_with_access)) break;
}