summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLouis Burda <quent.burda@gmail.com>2023-02-06 11:30:27 -0600
committerLouis Burda <quent.burda@gmail.com>2023-02-06 11:30:27 -0600
commit8d018c17170a3b623f48de5282955b817a6284f3 (patch)
tree70c44cfe471771ef2a42933118846c6ab869df11
parent4dd9fe04e1399e8629ab2a98b54db6a7dcdb0076 (diff)
downloadcachepc-8d018c17170a3b623f48de5282955b817a6284f3.tar.gz
cachepc-8d018c17170a3b623f48de5282955b817a6284f3.zip
qemu-targetstep: Attempt to track guest process gfn when running in userspace
Seems like single-stepping the guest with LAPIC influences the guest scheduler behaviour, since just a single step inside the target gfn (to determine if its running in userspace), is enough to for us to never reach the GUEST_STOP_TRACK event. FWICT the single-stepping is not frequent and does not take long enough to justify never reaching the stop event.
-rwxr-xr-xMakefile2
-rw-r--r--cachepc/cachepc.h9
-rw-r--r--cachepc/const.h1
-rw-r--r--cachepc/event.c5
-rw-r--r--cachepc/event.h3
-rw-r--r--cachepc/kvm.c9
-rw-r--r--cachepc/macro.S1
-rw-r--r--cachepc/uapi.h3
m---------linux0
-rwxr-xr-xtest/.gitignore4
-rw-r--r--test/qemu-targetstep.c (renamed from test/qemu-eviction.c)28
-rw-r--r--test/qemu-targetstep_guest.c (renamed from test/qemu-eviction_guest.c)7
12 files changed, 60 insertions, 12 deletions
diff --git a/Makefile b/Makefile
index fe4b337..9590b92 100755
--- a/Makefile
+++ b/Makefile
@@ -11,7 +11,7 @@ BINS += test/kvm-step test/kvm-step_guest
BINS += test/kvm-targetstep test/kvm-targetstep_guest
BINS += test/kvm-pagestep test/kvm-pagestep_guest
BINS += test/qemu-pagestep
-BINS += test/qemu-eviction test/qemu-eviction_guest
+BINS += test/qemu-targetstep test/qemu-targetstep_guest
# BINS += test/qemu-aes_guest test/qemu-aes
BINS += util/loglevel util/reset util/mainpfn
diff --git a/cachepc/cachepc.h b/cachepc/cachepc.h
index 21e136b..71ac49f 100644
--- a/cachepc/cachepc.h
+++ b/cachepc/cachepc.h
@@ -44,21 +44,29 @@ struct cpc_fault {
struct cpc_track_pages {
bool singlestep_resolve;
uint64_t retinst;
+ uint64_t retinst_user;
bool in_step;
bool prev_avail;
uint64_t prev_gfn;
+ uint16_t prev_err;
+
bool cur_avail;
uint64_t cur_gfn;
+ uint16_t cur_err;
+
bool next_avail;
uint64_t next_gfn;
+ uint16_t next_err;
};
struct cpc_track_steps {
bool with_data;
bool use_target;
+ bool target_user;
uint64_t target_gfn;
bool stepping;
+ bool in_target;
bool use_filter;
};
@@ -118,6 +126,7 @@ extern uint64_t cpc_track_start_gfn;
extern uint64_t cpc_track_end_gfn;
extern uint64_t cpc_retinst;
+extern uint64_t cpc_retinst_user;
extern uint64_t cpc_retinst_prev;
extern uint64_t cpc_rip;
diff --git a/cachepc/const.h b/cachepc/const.h
index b5deb53..633805e 100644
--- a/cachepc/const.h
+++ b/cachepc/const.h
@@ -10,6 +10,7 @@
#define CPC_L1MISS_PMC 0
#define CPC_RETINST_PMC 1
+#define CPC_RETINST_USER_PMC 2
#define CPC_VMSA_MAGIC_ADDR ((void *) 0xC0FFEE)
diff --git a/cachepc/event.c b/cachepc/event.c
index d863790..b85c2fc 100644
--- a/cachepc/event.c
+++ b/cachepc/event.c
@@ -158,14 +158,17 @@ cpc_send_track_step_event(struct list_head *list)
}
int
-cpc_send_track_page_event(uint64_t gfn_prev, uint64_t gfn, uint64_t retinst)
+cpc_send_track_page_event(uint64_t gfn_prev, uint64_t gfn, uint16_t err,
+ uint64_t retinst, uint64_t retinst_user)
{
struct cpc_event event = { 0 };
event.type = CPC_EVENT_TRACK_PAGE;
event.page.inst_gfn_prev = gfn_prev;
event.page.inst_gfn = gfn;
+ event.page.fault_err = err;
event.page.retinst = retinst;
+ event.page.retinst_user = retinst_user;
return cpc_send_event(event);
}
diff --git a/cachepc/event.h b/cachepc/event.h
index 1464f75..bd923a2 100644
--- a/cachepc/event.h
+++ b/cachepc/event.h
@@ -19,7 +19,8 @@ int cpc_send_guest_event(uint64_t type, uint64_t val);
int cpc_send_pause_event(void);
int cpc_send_track_step_event(struct list_head *list);
int cpc_send_track_step_event_single(uint64_t gfn, uint32_t err, uint64_t retinst);
-int cpc_send_track_page_event(uint64_t gfn_prev, uint64_t gfn, uint64_t retinst);
+int cpc_send_track_page_event(uint64_t gfn_prev, uint64_t gfn, uint16_t err,
+ uint64_t retinst, uint64_t retinst_user);
bool cpc_event_is_done(void);
diff --git a/cachepc/kvm.c b/cachepc/kvm.c
index d2bb5f7..4358a3f 100644
--- a/cachepc/kvm.c
+++ b/cachepc/kvm.c
@@ -41,8 +41,10 @@ bool cpc_prime_probe = false;
EXPORT_SYMBOL(cpc_prime_probe);
uint64_t cpc_retinst = 0;
+uint64_t cpc_retinst_user = 0;
uint64_t cpc_retinst_prev = 0;
EXPORT_SYMBOL(cpc_retinst);
+EXPORT_SYMBOL(cpc_retinst_user);
EXPORT_SYMBOL(cpc_retinst_prev);
uint64_t cpc_rip = 0;
@@ -244,6 +246,10 @@ cpc_pmc_setup(void *p)
/* retired instructions in guest */
cpc_init_pmc(CPC_RETINST_PMC, 0xC0, 0x00,
PMC_GUEST, PMC_KERNEL | PMC_USER);
+
+ /* retired instructions in guest userspace */
+ cpc_init_pmc(CPC_RETINST_USER_PMC, 0xC0, 0x00,
+ PMC_GUEST, PMC_USER);
}
void
@@ -510,9 +516,11 @@ cpc_track_mode_ioctl(void __user *arg_user)
break;
case CPC_TRACK_STEPS:
cpc_track_steps.use_target = cfg.steps.use_target;
+ cpc_track_steps.target_user = cfg.steps.target_user;
cpc_track_steps.target_gfn = cfg.steps.target_gfn;
cpc_track_steps.with_data = cfg.steps.with_data;
cpc_track_steps.use_filter = cfg.steps.use_filter;
+ cpc_track_steps.in_target = false;
if (!cpc_track_steps.use_target
&& cpc_track_steps.with_data) {
cpc_track_all(vcpu, KVM_PAGE_TRACK_ACCESS);
@@ -705,6 +713,7 @@ cpc_kvm_init(void)
cpc_ds_ul = NULL;
cpc_retinst = 0;
+ cpc_retinst_user = 0;
cpc_long_step = false;
cpc_singlestep = false;
cpc_singlestep_reset = false;
diff --git a/cachepc/macro.S b/cachepc/macro.S
index 53332a4..249f805 100644
--- a/cachepc/macro.S
+++ b/cachepc/macro.S
@@ -4,6 +4,7 @@
.macro barrier
mfence # finish load and stores
lfence # prevent reordering
+ rdtsc # prevent reordering
.endm
# clobbers rax, rbx, rcx, rdx, (out)
diff --git a/cachepc/uapi.h b/cachepc/uapi.h
index e3665a3..f04b9d8 100644
--- a/cachepc/uapi.h
+++ b/cachepc/uapi.h
@@ -63,6 +63,7 @@ struct cpc_track_cfg {
union {
struct {
__u64 target_gfn;
+ __u8 target_user;
__u8 use_target;
__u8 use_filter;
__u8 with_data;
@@ -84,7 +85,9 @@ struct cpc_track_step_event {
struct cpc_track_page_event {
__u64 inst_gfn_prev;
__u64 inst_gfn;
+ __u16 fault_err;
__u64 retinst;
+ __u64 retinst_user;
};
struct cpc_guest_event {
diff --git a/linux b/linux
-Subproject c017dafb1efb1e28b9f5b3500bf5f87e451709d
+Subproject dc737cafcbc0d030d797b66a45ccf9fe92d0970
diff --git a/test/.gitignore b/test/.gitignore
index cea8b5a..9c69377 100755
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -7,10 +7,10 @@ kvm-step
kvm-step_guest
kvm-pagestep
kvm-pagestep_guest
-qemu-eviction
-qemu-eviction_guest
qemu-pagestep
qemu-aes
qemu-aes_guest
qemu-poc
qemu-poc_guest
+qemu-targetstep
+qemu-targetstep_guest
diff --git a/test/qemu-eviction.c b/test/qemu-targetstep.c
index 2392472..a7345a3 100644
--- a/test/qemu-eviction.c
+++ b/test/qemu-targetstep.c
@@ -17,6 +17,7 @@
static struct cpc_event event;
static struct cpc_event_batch batch;
+static uint64_t last_user_inst_gfn;
int
monitor(bool baseline)
@@ -30,7 +31,7 @@ monitor(bool baseline)
switch (event.type) {
case CPC_EVENT_GUEST:
- printf("Guest event: %i\n", event.guest.type);
+ printf("Guest %s\n", !event.guest.type ? "start" : "stop");
if (event.guest.type == CPC_GUEST_STOP_TRACK)
return 2;
break;
@@ -71,7 +72,14 @@ read_batch(void)
if (batch.buf[i].type != CPC_EVENT_TRACK_PAGE)
continue;
- printf("GFN %08llx\n", batch.buf[i].page.inst_gfn);
+ if (batch.buf[i].page.retinst_user > 0) {
+ printf("GFN %08llx %04x %4llu %4llu\n",
+ batch.buf[i].page.inst_gfn,
+ batch.buf[i].page.fault_err,
+ batch.buf[i].page.retinst,
+ batch.buf[i].page.retinst_user);
+ last_user_inst_gfn = batch.buf[i].page.inst_gfn;
+ }
}
}
@@ -185,8 +193,12 @@ main(int argc, const char **argv)
ret = ioctl(kvm_dev, KVM_CPC_POLL_EVENT, &event);
if (ret && errno == EAGAIN) continue;
if (ret) err(1, "KVM_CPC_POLL_EVENT");
-
- printf("EVENT %i\n", event.type);
+
+ if (event.type == CPC_EVENT_GUEST) {
+ read_batch();
+ printf("Guest %s\n",
+ !event.guest.type ? "start" : "stop");
+ }
if (event.type == CPC_EVENT_GUEST
&& event.guest.type == CPC_GUEST_START_TRACK) {
@@ -207,17 +219,21 @@ main(int argc, const char **argv)
if (!batch.cnt) errx(1, "empty batch buffer");
memset(&cfg, 0, sizeof(cfg));
cfg.mode = CPC_TRACK_STEPS;
- cfg.steps.target_gfn = batch.buf[batch.cnt - 3].page.inst_gfn;
+ cfg.steps.target_gfn = last_user_inst_gfn;
+ cfg.steps.target_user = true;
cfg.steps.use_target = true;
cfg.steps.use_filter = true;
- cfg.steps.with_data = 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");
+ printf("Target GFN: %08llx\n", cfg.steps.target_gfn);
+
while (monitor(false) != 2);
+ read_batch();
signal(SIGINT, NULL);
diff --git a/test/qemu-eviction_guest.c b/test/qemu-targetstep_guest.c
index 086fee5..9ef36e1 100644
--- a/test/qemu-eviction_guest.c
+++ b/test/qemu-targetstep_guest.c
@@ -2,6 +2,7 @@
#include <sys/time.h>
#include <sys/resource.h>
+#include <errno.h>
#include <err.h>
#include <unistd.h>
#include <stdint.h>
@@ -13,13 +14,17 @@ int
main(int argc, const char **argv)
{
void *buf;
+ int ret;
buf = NULL;
if (posix_memalign(&buf, L1_LINESIZE * L1_SETS, L1_LINESIZE * L1_SETS))
err(1, "memalign");
memset(buf, 0, L1_LINESIZE * L1_SETS);
- setpriority(PRIO_PROCESS, 0, -20);
+ errno = 0;
+ ret = setpriority(PRIO_PROCESS, 0, -20);
+ if (errno) err(1, "setpriority");
+ printf("NICE %i\n", ret);
while (1) {
printf("LOOP\n");