qemu-targetstep.c (5678B)
1#include "test/kvm-eviction.h" 2#include "test/kvm.h" 3#include "test/util.h" 4#include "cachepc/uapi.h" 5 6#include <sys/ioctl.h> 7#include <sys/mman.h> 8#include <signal.h> 9#include <unistd.h> 10#include <fcntl.h> 11#include <errno.h> 12#include <err.h> 13#include <string.h> 14#include <stdbool.h> 15#include <stdio.h> 16#include <stdlib.h> 17 18static struct cpc_event event; 19static struct cpc_event_batch batch; 20static uint64_t last_user_inst_gfn; 21 22int 23monitor(bool baseline) 24{ 25 uint8_t counts[L1_SETS]; 26 int ret; 27 28 ret = ioctl(kvm_dev, KVM_CPC_POLL_EVENT, &event); 29 if (ret && errno == EAGAIN) return 0; 30 if (ret) err(1, "KVM_CPC_POLL_EVENT"); 31 32 switch (event.type) { 33 case CPC_EVENT_GUEST: 34 printf("Guest %s\n", !event.guest.type ? "start" : "stop"); 35 if (event.guest.type == CPC_GUEST_STOP_TRACK) 36 return 2; 37 break; 38 case CPC_EVENT_TRACK_STEP: 39 ret = ioctl(kvm_dev, KVM_CPC_READ_COUNTS, counts); 40 if (ret) err(1, "KVM_CPC_READ_COUNTS"); 41 42 printf("Event: rip:%016llx cnt:%llu " 43 "inst:%08llx ret:%llu\n", 44 vm_get_rip(), event.step.fault_count, 45 event.step.inst_gfn, event.step.retinst); 46 print_counts(counts); 47 printf("\n"); 48 print_counts_raw(counts); 49 printf("\n"); 50 break; 51 default: 52 errx(1, "unexpected event type %i", event.type); 53 } 54 55 ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id); 56 if (ret) err(1, "KVM_CPC_ACK_EVENT"); 57 58 return 1; 59} 60 61void 62read_batch(void) 63{ 64 uint32_t i; 65 int ret; 66 67 ret = ioctl(kvm_dev, KVM_CPC_READ_BATCH, &batch); 68 if (ret && errno == EAGAIN) return; 69 if (ret && errno != EAGAIN) err(1, "KVM_CPC_READ_BATCH"); 70 71 for (i = 0; i < batch.cnt; i++) { 72 if (batch.buf[i].type != CPC_EVENT_TRACK_PAGE) 73 continue; 74 75 if (batch.buf[i].page.retinst_user > 0) { 76 printf("GFN %08llx %04x %4llu %4llu\n", 77 batch.buf[i].page.inst_gfn, 78 batch.buf[i].page.fault_err, 79 batch.buf[i].page.retinst, 80 batch.buf[i].page.retinst_user); 81 last_user_inst_gfn = batch.buf[i].page.inst_gfn; 82 } 83 } 84} 85 86void 87reset(int sig) 88{ 89 int ret; 90 91 ret = ioctl(kvm_dev, KVM_CPC_RESET); 92 if (ret) err(1, "KVM_CPC_RESET"); 93 94 exit(1); 95} 96 97int 98main(int argc, const char **argv) 99{ 100 uint8_t baseline[L1_SETS]; 101 struct cpc_track_cfg cfg; 102 bool first_guest_event; 103 uint32_t eventcnt; 104 uint32_t arg; 105 int ret; 106 107 pin_process(0, SECONDARY_CORE, true); 108 109 setvbuf(stdout, NULL, _IONBF, 0); 110 111 kvm_setup_init(); 112 113 ret = ioctl(kvm_dev, KVM_CPC_RESET); 114 if (ret) err(1, "KVM_CPC_RESET"); 115 116 signal(SIGINT, reset); 117 118 arg = true; 119 ret = ioctl(kvm_dev, KVM_CPC_CALC_BASELINE, &arg); 120 if (ret) err(1, "KVM_CPC_CALC_BASELINE"); 121 122 memset(&cfg, 0, sizeof(cfg)); 123 cfg.mode = CPC_TRACK_STEPS; 124 cfg.steps.with_data = true; 125 cfg.steps.use_filter = true; 126 ret = ioctl(kvm_dev, KVM_CPC_TRACK_MODE, &cfg); 127 if (ret) err(1, "KVM_CPC_RESET"); 128 129 eventcnt = 0; 130 while (eventcnt < 50) { 131 eventcnt += monitor(true); 132 } 133 134 ret = ioctl(kvm_dev, KVM_CPC_VM_REQ_PAUSE); 135 if (ret) err(1, "KVM_CPC_VM_REQ_PAUSE"); 136 137 while (1) { 138 ret = ioctl(kvm_dev, KVM_CPC_POLL_EVENT, &event); 139 if (ret && errno == EAGAIN) continue; 140 if (ret) err(1, "KVM_CPC_POLL_EVENT"); 141 142 if (event.type == CPC_EVENT_PAUSE) break; 143 144 ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id); 145 if (ret) err(1, "KVM_CPC_ACK_EVENT"); 146 } 147 148 arg = false; 149 ret = ioctl(kvm_dev, KVM_CPC_CALC_BASELINE, &arg); 150 if (ret) err(1, "KVM_CPC_CALC_BASELINE"); 151 152 arg = true; 153 ret = ioctl(kvm_dev, KVM_CPC_APPLY_BASELINE, &arg); 154 if (ret) err(1, "KVM_CPC_APPLY_BASELINE"); 155 156 ret = ioctl(kvm_dev, KVM_CPC_READ_BASELINE, baseline); 157 if (ret) err(1, "KVM_CPC_READ_BASELINE"); 158 159 printf("\nBaseline:\n"); 160 print_counts(baseline); 161 printf("\n"); 162 print_counts_raw(baseline); 163 printf("\n\n"); 164 165 memset(&cfg, 0, sizeof(&cfg)); 166 cfg.mode = CPC_TRACK_NONE; 167 ret = ioctl(kvm_dev, KVM_CPC_TRACK_MODE, &cfg); 168 if (ret) err(1, "KVM_CPC_TRACK_MODE"); 169 170 ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id); 171 if (ret) err(1, "KVM_CPC_ACK_EVENT"); 172 173 /* wait until guest program is run */ 174 printf("Press enter to continue..\n"); 175 getchar(); 176 177 arg = true; 178 ret = ioctl(kvm_dev, KVM_CPC_BATCH_EVENTS, &arg); 179 if (ret) err(1, "KVM_CPC_BATCH_EVENTS"); 180 181 memset(&cfg, 0, sizeof(cfg)); 182 cfg.mode = CPC_TRACK_PAGES; 183 ret = ioctl(kvm_dev, KVM_CPC_TRACK_MODE, &cfg); 184 if (ret) err(1, "KVM_CPC_TRACK_MODE"); 185 186 batch.cnt = 0; 187 batch.maxcnt = CPC_EVENT_BATCH_MAX; 188 batch.buf = malloc(sizeof(struct cpc_event) * batch.maxcnt); 189 if (!batch.buf) err(1, "malloc"); 190 191 first_guest_event = true; 192 while (1) { 193 ret = ioctl(kvm_dev, KVM_CPC_POLL_EVENT, &event); 194 if (ret && errno == EAGAIN) continue; 195 if (ret) err(1, "KVM_CPC_POLL_EVENT"); 196 197 if (event.type == CPC_EVENT_GUEST) { 198 read_batch(); 199 printf("Guest %s\n", 200 !event.guest.type ? "start" : "stop"); 201 } 202 203 if (event.type == CPC_EVENT_GUEST 204 && event.guest.type == CPC_GUEST_START_TRACK) { 205 if (!first_guest_event) 206 break; 207 first_guest_event = false; 208 } 209 210 if (event.type == CPC_EVENT_BATCH) 211 read_batch(); 212 213 ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id); 214 if (ret) err(1, "KVM_CPC_ACK_EVENT"); 215 } 216 217 read_batch(); 218 219 if (!batch.cnt) errx(1, "empty batch buffer"); 220 memset(&cfg, 0, sizeof(cfg)); 221 cfg.mode = CPC_TRACK_STEPS; 222 cfg.steps.target_gfn = last_user_inst_gfn; 223 cfg.steps.target_user = true; 224 cfg.steps.use_target = true; 225 cfg.steps.use_filter = true; 226 //cfg.steps.with_data = true; 227 ret = ioctl(kvm_dev, KVM_CPC_TRACK_MODE, &cfg); 228 if (ret) err(1, "KVM_CPC_TRACK_MODE"); 229 230 ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id); 231 if (ret) err(1, "KVM_CPC_ACK_EVENT"); 232 233 printf("Target GFN: %08llx\n", cfg.steps.target_gfn); 234 235 while (monitor(false) != 2); 236 read_batch(); 237 238 signal(SIGINT, NULL); 239 240 ret = ioctl(kvm_dev, KVM_CPC_RESET); 241 if (ret) err(1, "KVM_CPC_RESET"); 242 243 free(batch.buf); 244 245 kvm_setup_deinit(); 246} 247