commit da9326a66bd534de38ab07dac96e8af051e94923
parent df90539b9e7ee75c206d5b77d4f1b94882d090c7
Author: Louis Burda <quent.burda@gmail.com>
Date: Thu, 2 Feb 2023 09:42:58 -0600
Add event batching and handling of instructions loads on page boundaries for CPC_TRACK_PAGES
Diffstat:
15 files changed, 117 insertions(+), 36 deletions(-)
diff --git a/Makefile b/Makefile
@@ -60,7 +60,7 @@ load:
prep:
sudo sh -c "echo 0 > /proc/sys/kernel/watchdog"
- sudo cpupower frequency-set -d 3.7GHz -u 3.7GHz
+ sudo cpupower frequency-set -g powersave
sudo bash -c "for f in /proc/irq/*/smp_affinity; do echo 1 > \$$f 2>/dev/null; done"
util/%: util/%.c $(UTIL_SRCS)
diff --git a/cachepc/cachepc.c b/cachepc/cachepc.c
@@ -217,6 +217,6 @@ cpc_apic_oneshot_run(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_1);
- native_apic_mem_write(APIC_TMICT, interval);
+ native_apic_mem_write(APIC_TMICT, interval / CPC_APIC_TIMER_SOFTDIV);
}
EXPORT_SYMBOL(cpc_apic_oneshot_run);
diff --git a/cachepc/cachepc.h b/cachepc/cachepc.h
@@ -37,8 +37,12 @@ struct cpc_fault {
};
struct cpc_track_pages {
+ bool prev_avail;
bool cur_avail;
+ bool next_avail;
+ uint64_t prev_gfn;
uint64_t cur_gfn;
+ uint64_t next_gfn;
uint64_t retinst;
bool in_step;
};
@@ -95,7 +99,7 @@ extern bool cpc_singlestep;
extern bool cpc_singlestep_reset;
extern bool cpc_long_step;
-extern bool cpc_apic_oneshot;
+extern volatile bool cpc_apic_oneshot;
extern uint32_t cpc_apic_timer;
extern uint32_t cpc_track_mode;
diff --git a/cachepc/const.h b/cachepc/const.h
@@ -21,4 +21,6 @@
#define CPC_CL_COUNT_OFFSET 16
#define CPC_APIC_TIMER_SOFTDIV 3
-#define CPC_APIC_TIMER_MIN (100 * CPC_APIC_TIMER_SOFTDIV)
+#define CPC_APIC_TIMER_MIN (50 * CPC_APIC_TIMER_SOFTDIV)
+
+#define CPC_EVENT_BATCH_MAX 1000
diff --git a/cachepc/event.c b/cachepc/event.c
@@ -33,7 +33,9 @@ EXPORT_SYMBOL(cpc_send_track_page_event);
void
cpc_events_init(void)
{
- cpc_eventbuf = NULL;
+ cpc_eventbuf = kzalloc(sizeof(struct cpc_event)
+ * CPC_EVENT_BATCH_MAX, GFP_KERNEL);
+ BUG_ON(!cpc_eventbuf);
cpc_eventbuf_len = 0;
cpc_event_batching = false;
rwlock_init(&cpc_event_lock);
@@ -70,7 +72,7 @@ cpc_send_event(struct cpc_event event)
}
if (cpc_event_batching) {
- if (cpc_eventbuf_len < CPC_EVENTBUF_CAP) {
+ if (cpc_eventbuf_len < CPC_EVENT_BATCH_MAX) {
event.id = 0;
memcpy(&cpc_eventbuf[cpc_eventbuf_len], &event,
sizeof(struct cpc_event));
@@ -238,10 +240,22 @@ cpc_ack_event_ioctl(void __user *arg_user)
}
int
-cpc_read_events_ioctl(void __user *arg_user)
+cpc_batch_events_ioctl(void __user *arg_user)
+{
+ uint32_t enable;
+
+ if (copy_from_user(&enable, arg_user, sizeof(enable)))
+ return -EFAULT;
+
+ cpc_event_batching = enable;
+
+ return 0;
+}
+
+int
+cpc_read_batch_ioctl(void __user *arg_user)
{
- struct cpc_batch_event batch;
- size_t n;
+ struct cpc_event_batch batch;
if (!arg_user) return -EINVAL;
@@ -256,11 +270,12 @@ cpc_read_events_ioctl(void __user *arg_user)
return -EAGAIN;
}
- n = cpc_eventbuf_len;
- if (batch.maxcnt < n)
- n = batch.maxcnt;
+ batch.cnt = cpc_eventbuf_len;
+ if (batch.maxcnt < batch.cnt)
+ batch.cnt = batch.maxcnt;
- if (copy_to_user(batch.buf, cpc_eventbuf, sizeof(struct cpc_event) * n)) {
+ if (copy_to_user(batch.buf, cpc_eventbuf,
+ sizeof(struct cpc_event) * batch.cnt)) {
write_unlock(&cpc_event_lock);
return -EFAULT;
}
diff --git a/cachepc/event.h b/cachepc/event.h
@@ -7,14 +7,12 @@
#include <linux/kvm_host.h>
#include <linux/types.h>
-#define CPC_EVENTBUF_CAP 5000
-
extern struct cpc_event *cpc_eventbuf;
extern size_t cpc_eventbuf_len;
extern bool cpc_event_batching;
-void cpc_event_init(void);
-void cpc_event_deinit(void);
+void cpc_events_init(void);
+void cpc_events_deinit(void);
void cpc_events_reset(void);
int cpc_send_guest_event(uint64_t type, uint64_t val);
@@ -27,4 +25,5 @@ bool cpc_event_is_done(void);
int cpc_poll_event_ioctl(void __user *arg_user);
int cpc_ack_event_ioctl(void __user *arg_user);
-int cpc_read_events_ioctl(void __user *arg_user);
+int cpc_batch_events_ioctl(void __user *arg_user);
+int cpc_read_batch_ioctl(void __user *arg_user);
diff --git a/cachepc/kvm.c b/cachepc/kvm.c
@@ -59,7 +59,7 @@ EXPORT_SYMBOL(cpc_singlestep);
EXPORT_SYMBOL(cpc_singlestep_reset);
EXPORT_SYMBOL(cpc_long_step);
-bool cpc_apic_oneshot = false;
+volatile bool cpc_apic_oneshot = false;
uint32_t cpc_apic_timer = 0;
EXPORT_SYMBOL(cpc_apic_oneshot);
EXPORT_SYMBOL(cpc_apic_timer);
@@ -624,8 +624,10 @@ cpc_kvm_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
return cpc_poll_event_ioctl(arg_user);
case KVM_CPC_ACK_EVENT:
return cpc_ack_event_ioctl(arg_user);
- case KVM_CPC_READ_EVENTS:
- return cpc_read_events_ioctl(arg_user);
+ case KVM_CPC_BATCH_EVENTS:
+ return cpc_batch_events_ioctl(arg_user);
+ case KVM_CPC_READ_BATCH:
+ return cpc_read_batch_ioctl(arg_user);
// case KVM_CPC_TRACK_PAGE:
// return cpc_track_page_ioctl(arg_user);
// case KVM_CPC_TRACK_RANGE_START:
@@ -700,7 +702,7 @@ cpc_kvm_init(void)
cpc_baseline = kzalloc(L1_SETS, GFP_KERNEL);
BUG_ON(!cpc_baseline);
- cpc_events_reset();
+ cpc_events_init();
ret = smp_call_function_single(CPC_ISOLCPU,
cpc_setup_test, NULL, true);
@@ -710,6 +712,8 @@ cpc_kvm_init(void)
void
cpc_kvm_exit(void)
{
+ cpc_events_deinit();
+
kfree(cpc_msrmts);
kfree(cpc_baseline);
diff --git a/cachepc/uapi.h b/cachepc/uapi.h
@@ -30,7 +30,8 @@
#define KVM_CPC_POLL_EVENT _IOWR(KVMIO, 0x40, struct cpc_event)
#define KVM_CPC_ACK_EVENT _IOWR(KVMIO, 0x41, __u64)
-#define KVM_CPC_READ_EVENTS _IOWR(KVMIO, 0x42, struct cpc_batch_event)
+#define KVM_CPC_BATCH_EVENTS _IOW(KVMIO, 0x42, __u32)
+#define KVM_CPC_READ_BATCH _IOWR(KVMIO, 0x43, struct cpc_event_batch)
#define KVM_CPC_VM_REQ_PAUSE _IO(KVMIO, 0x50)
@@ -93,7 +94,7 @@ struct cpc_guest_event {
__u64 val;
};
-struct cpc_batch_event {
+struct cpc_event_batch {
__u64 cnt;
__u64 maxcnt;
struct cpc_event *buf;
@@ -106,7 +107,6 @@ struct cpc_event {
struct cpc_track_step_event step;
struct cpc_track_page_event page;
struct cpc_guest_event guest;
- struct cpc_batch_event batch;
};
};
diff --git a/qemu/install.sh b/qemu/install.sh
@@ -5,7 +5,7 @@ set -ex
gitroot=$(git rev-parse --show-toplevel)
cd "$gitroot/qemu"
-DISK="debian11.qcow2"
+DISK="guest.qcow2"
DEBIANISO="debian-11.4.0-amd64-DVD-1.iso"
if [ ! -e "$DISK" ]; then
diff --git a/qemu/launch-victim.sh b/qemu/launch-victim.sh
@@ -10,15 +10,15 @@ if [ ! -e cmdline ]; then
exit 1
fi
-if [ ! -e debian11_encrypted.qcow2 ]; then
+if [ ! -e guest_encrypted.qcow2 ]; then
echo "Copying disk.."
- rsync -a --info=progress2 debian11.qcow2 debian11_encrypted.qcow2
+ rsync -a --info=progress2 guest.qcow2 guest_encrypted.qcow2
fi
sudo LIBVIRT_DEBUG=1 virsh net-start default 2>&1 | grep -i warning || true
sudo PREFIX=$gitroot/AMDSEV $gitroot/AMDSEV/launch-qemu.sh \
- -hda debian11_encrypted.qcow2 \
+ -hda guest_encrypted.qcow2 \
-console serial \
-vnc 1 \
-mem 2024 \
diff --git a/qemu/launch.sh b/qemu/launch.sh
@@ -8,7 +8,7 @@ cd "$gitroot/qemu"
sudo LIBVIRT_DEBUG=1 virsh net-start default 2>&1 | grep -i warning || true
sudo PREFIX=$gitroot/AMDSEV $gitroot/AMDSEV/launch-qemu.sh \
- -hda debian11.qcow2 \
+ -hda guest.qcow2 \
-console serial \
-vnc 1 \
-mem 2024 \
diff --git a/qemu/ssh.sh b/qemu/ssh.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+ssh -p 8000 test@localhost
diff --git a/test/kvm-pagestep.c b/test/kvm-pagestep.c
@@ -41,6 +41,13 @@ monitor(struct kvm *kvm, bool baseline)
return 1;
}
+void
+kill_child(void)
+{
+ printf("Killing vm..\n");
+ kill(child, SIGKILL);
+}
+
int
main(int argc, const char **argv)
{
@@ -96,6 +103,8 @@ main(int argc, const char **argv)
} else {
pin_process(0, SECONDARY_CORE, true);
+ atexit(kill_child);
+
ipc_wait_child(ipc);
printf("Monitor start\n");
diff --git a/test/kvm-pagestep_guest.S b/test/kvm-pagestep_guest.S
@@ -11,6 +11,17 @@ guest:
nop
.endr
+# instruction on page boundary test
+ nop
+.rept 2
+.rept L1_LINESIZE * L1_SETS - 2
+ nop
+.endr
+ cpuid # two byte instruction
+.endr
+# ---------------------------------
+
+# speculation on conditional jump test
mov $0x01, %bx
cmp $0x00, %bx
@@ -19,6 +30,7 @@ guest:
nop
.endr
skip:
+# -----------------------------------
jmp guest
diff --git a/test/qemu-pagestep.c b/test/qemu-pagestep.c
@@ -15,23 +15,48 @@
#include <stdio.h>
#include <stdlib.h>
+struct cpc_event *batch_buffer;
+
+void
+report(struct cpc_event *event)
+{
+ if (event->type == CPC_EVENT_TRACK_PAGE) {
+ printf("Page event: rip:%016llx prev:%08llx next:%08llx ret:%llu\n",
+ vm_get_rip(), event->page.inst_gfn_prev,
+ event->page.inst_gfn, event->page.retinst);
+ } else if (event->type == CPC_EVENT_GUEST) {
+ printf("Guest event: type:%u arg:%u\n",
+ event->guest.type, event->guest.val);
+ } else {
+ printf("Unexpected event type %i\n", event->type);
+ }
+ printf("\n");
+}
+
void
monitor(void)
{
struct cpc_event event;
+ struct cpc_event_batch batch;
+ size_t i;
int ret;
ret = ioctl(kvm_dev, KVM_CPC_POLL_EVENT, &event);
if (ret && errno == EAGAIN) return;
if (ret) err(1, "KVM_CPC_POLL_EVENT");
- if (event.type == CPC_EVENT_TRACK_PAGE) {
- printf("Event: rip:%016llx prev:%08llx next:%08llx ret:%llu\n",
- vm_get_rip(), event.page.inst_gfn_prev,
- event.page.inst_gfn, event.page.retinst);
- printf("\n");
+ if (event.type == CPC_EVENT_BATCH) {
+ batch.cnt = 0;
+ batch.maxcnt = CPC_EVENT_BATCH_MAX;
+ batch.buf = batch_buffer;
+
+ ret = ioctl(kvm_dev, KVM_CPC_READ_BATCH, &batch);
+ if (ret) err(1, "KVM_CPC_READ_BATCH");
+
+ for (i = 0; i < batch.cnt; i++)
+ report(&batch.buf[i]);
} else {
- printf("Unexpected event type %i\n", event.type);
+ report(&event);
}
ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id);
@@ -42,8 +67,12 @@ int
main(int argc, const char **argv)
{
struct cpc_track_cfg cfg;
+ uint32_t arg;
int ret;
+ batch_buffer = malloc(sizeof(struct cpc_event) * CPC_EVENT_BATCH_MAX);
+ if (!batch_buffer) err(1, "malloc");
+
setvbuf(stdout, NULL, _IONBF, 0);
kvm_setup_init();
@@ -53,6 +82,10 @@ main(int argc, const char **argv)
ret = ioctl(kvm_dev, KVM_CPC_RESET);
if (ret) err(1, "KVM_CPC_RESET");
+ arg = true;
+ ret = ioctl(kvm_dev, KVM_CPC_BATCH_EVENTS, &arg);
+ if (ret) err(1, "KVM_CPC_BATCH_EVENTS");
+
memset(&cfg, 0, sizeof(cfg));
cfg.mode = CPC_TRACK_PAGES;
ret = ioctl(kvm_dev, KVM_CPC_TRACK_MODE, &cfg);