kvm-targetstep.c (5030B)
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 int child; 19static struct cpc_event event; 20 21uint64_t 22monitor(struct kvm *kvm, bool baseline) 23{ 24 uint8_t counts[L1_SETS]; 25 int ret; 26 27 ret = ioctl(kvm_dev, KVM_CPC_POLL_EVENT, &event); 28 if (ret && errno == EAGAIN) return 0; 29 if (ret) err(1, "KVM_CPC_POLL_EVENT"); 30 31 if (!baseline && event.type == CPC_EVENT_GUEST 32 && event.guest.type == CPC_GUEST_STOP_TRACK) 33 return 2; 34 35 if (event.type == CPC_EVENT_TRACK_STEP) { 36 ret = ioctl(kvm_dev, KVM_CPC_READ_COUNTS, counts); 37 if (ret) err(1, "KVM_CPC_READ_COUNTS"); 38 39 printf("Event: rip:%08llx cnt:%llu inst:%08llx data:%08llx ret:%llu\n", 40 vm_get_rip(), event.step.fault_count, 41 event.step.fault_gfns[0], event.step.fault_gfns[1], 42 event.step.retinst); 43 print_counts(counts); 44 printf("\n"); 45 print_counts_raw(counts); 46 printf("\n"); 47 } 48 49 ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id); 50 if (ret) err(1, "KVM_CPC_ACK_EVENT"); 51 52 return 1; 53} 54 55void 56deinit(void) 57{ 58 ioctl(kvm_dev, KVM_CPC_DEINIT); 59 60 kill(child, SIGKILL); 61 62 kvm_setup_deinit(); 63} 64 65int 66main(int argc, const char **argv) 67{ 68 struct ipc *ipc; 69 struct guest guest; 70 struct kvm kvm; 71 uint8_t baseline[L1_SETS]; 72 struct cpc_track_cfg cfg; 73 bool inst_gfn_avail; 74 uint64_t inst_gfn; 75 uint64_t eventcnt; 76 uint32_t arg; 77 int ret; 78 79 setvbuf(stdout, NULL, _IONBF, 0); 80 81 parse_vmtype(argc, argv); 82 83 kvm_setup_init(); 84 85 ipc = ipc_alloc(); 86 87 child = fork(); 88 if (child < 0) err(1, "fork"); 89 90 if (child == 0) { 91 pin_process(0, TARGET_CORE, true); 92 93 guest_init(&guest, "test/kvm-targetstep_guest"); 94 vm_init(&kvm, &guest); 95 guest_deinit(&guest); 96 97 /* reset kernel module state */ 98 ret = ioctl(kvm_dev, KVM_CPC_RESET, NULL); 99 if (ret < 0) err(1, "KVM_CPC_RESET"); 100 101 ipc_signal_parent(ipc); 102 ipc_wait_parent(ipc); 103 104 printf("VM start\n"); 105 106 do { 107 ret = ioctl(kvm.vcpufd, KVM_RUN, NULL); 108 if (ret < 0) err(1, "KVM_RUN"); 109 } while (kvm.run->exit_reason == KVM_EXIT_HLT); 110 111 printf("VM exit\n"); 112 113 vm_deinit(&kvm); 114 115 ipc_free(ipc); 116 kvm_setup_deinit(); 117 } else { 118 pin_process(0, SECONDARY_CORE, true); 119 120 atexit(deinit); 121 122 ipc_wait_child(ipc); 123 124 printf("Monitor start\n"); 125 126 memset(&cfg, 0, sizeof(cfg)); 127 cfg.mode = CPC_TRACK_STEPS; 128 cfg.steps.with_data = true; 129 ret = ioctl(kvm_dev, KVM_CPC_TRACK_MODE, &cfg); 130 if (ret) err(1, "KVM_CPC_TRACK_MODE"); 131 132 arg = true; 133 ret = ioctl(kvm_dev, KVM_CPC_CALC_BASELINE, &arg); 134 if (ret) err(1, "KVM_CPC_CALC_BASELINE"); 135 136 ipc_signal_child(ipc); 137 138 /* run vm while baseline is calculated */ 139 eventcnt = 0; 140 while (eventcnt < 50) { 141 eventcnt += monitor(&kvm, true); 142 } 143 144 ret = ioctl(kvm_dev, KVM_CPC_VM_REQ_PAUSE); 145 if (ret) err(1, "KVM_CPC_VM_REQ_PAUSE"); 146 147 while (1) { 148 ret = ioctl(kvm_dev, KVM_CPC_POLL_EVENT, &event); 149 if (ret && errno == EAGAIN) continue; 150 if (ret) err(1, "KVM_CPC_POLL_EVENT"); 151 152 if (event.type == CPC_EVENT_PAUSE) break; 153 154 ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id); 155 if (ret) err(1, "KVM_CPC_ACK_EVENT"); 156 } 157 158 arg = false; 159 ret = ioctl(kvm_dev, KVM_CPC_CALC_BASELINE, &arg); 160 if (ret) err(1, "KVM_CPC_CALC_BASELINE"); 161 162 ret = ioctl(kvm_dev, KVM_CPC_READ_BASELINE, baseline); 163 if (ret) err(1, "KVM_CPC_READ_BASELINE"); 164 165 printf("\nBaseline:\n"); 166 print_counts(baseline); 167 printf("\n"); 168 print_counts_raw(baseline); 169 printf("\n\n"); 170 171 arg = true; 172 ret = ioctl(kvm_dev, KVM_CPC_APPLY_BASELINE, &arg); 173 if (ret) err(1, "KMV_CPC_APPLY_BASELINE"); 174 175 memset(&cfg, 0, sizeof(cfg)); 176 cfg.mode = CPC_TRACK_PAGES; 177 ret = ioctl(kvm_dev, KVM_CPC_TRACK_MODE, &cfg); 178 if (ret) err(1, "KVM_CPC_TRACK_MODE"); 179 180 ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id); 181 if (ret) err(1, "KVM_CPC_ACK_EVENT"); 182 183 /* wait for CPC_GUEST_START_TRACK */ 184 185 inst_gfn_avail = false; 186 while (1) { 187 ret = ioctl(kvm_dev, KVM_CPC_POLL_EVENT, &event); 188 if (ret && errno == EAGAIN) continue; 189 if (ret) err(1, "KVM_CPC_POLL_EVENT"); 190 191 if (inst_gfn_avail && event.type == CPC_EVENT_GUEST 192 && event.guest.type == CPC_GUEST_START_TRACK) 193 break; 194 195 if (event.type == CPC_EVENT_TRACK_PAGE) { 196 inst_gfn = event.page.inst_gfn; 197 inst_gfn_avail = true; 198 } 199 200 ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id); 201 if (ret) err(1, "KVM_CPC_ACK_EVENT"); 202 } 203 204 /* start step tracking for target gfn */ 205 206 printf("Target GFN: %08llx\n", inst_gfn); 207 208 memset(&cfg, 0, sizeof(cfg)); 209 cfg.mode = CPC_TRACK_STEPS; 210 cfg.steps.target_gfn = inst_gfn; 211 cfg.steps.use_target = true; 212 cfg.steps.with_data = true; 213 ret = ioctl(kvm_dev, KVM_CPC_TRACK_MODE, &cfg); 214 if (ret) err(1, "KVM_CPC_TRACK_MODE"); 215 216 ret = ioctl(kvm_dev, KVM_CPC_ACK_EVENT, &event.id); 217 if (ret) err(1, "KVM_CPC_ACK_EVENT"); 218 219 while (monitor(&kvm, false) != 2); 220 221 printf("Monitor exit\n"); 222 223 ipc_free(ipc); 224 } 225} 226