1 /* 2 * Async PF test. For the test to actually do anything it needs to be started 3 * in memory cgroup with 512M of memory and with more then 1G memory provided 4 * to the guest. 5 * 6 * To create cgroup do as root: 7 * mkdir /dev/cgroup 8 * mount -t cgroup none -omemory /dev/cgroup 9 * chmod a+rxw /dev/cgroup/ 10 * 11 * From a shell you will start qemu from: 12 * mkdir /dev/cgroup/1 13 * echo $$ > /dev/cgroup/1/tasks 14 * echo 512M > /dev/cgroup/1/memory.limit_in_bytes 15 * 16 */ 17 #include "x86/msr.h" 18 #include "x86/processor.h" 19 #include "x86/apic-defs.h" 20 #include "x86/apic.h" 21 #include "x86/desc.h" 22 #include "x86/isr.h" 23 #include "x86/vm.h" 24 25 #include "asm/page.h" 26 #include "alloc.h" 27 #include "libcflat.h" 28 #include "vmalloc.h" 29 #include <stdint.h> 30 31 #define KVM_PV_REASON_PAGE_NOT_PRESENT 1 32 #define KVM_PV_REASON_PAGE_READY 2 33 34 #define MSR_KVM_ASYNC_PF_EN 0x4b564d02 35 36 #define KVM_ASYNC_PF_ENABLED (1 << 0) 37 #define KVM_ASYNC_PF_SEND_ALWAYS (1 << 1) 38 39 volatile uint32_t apf_reason __attribute__((aligned(64))); 40 char *buf; 41 volatile uint64_t i; 42 volatile uint64_t phys; 43 44 static inline uint32_t get_apf_reason(void) 45 { 46 uint32_t r = apf_reason; 47 apf_reason = 0; 48 return r; 49 } 50 51 static void pf_isr(struct ex_regs *r) 52 { 53 void* virt = (void*)((ulong)(buf+i) & ~(PAGE_SIZE-1)); 54 uint32_t reason = get_apf_reason(); 55 56 switch (reason) { 57 case 0: 58 report(false, "unexpected #PF at %#lx", read_cr2()); 59 break; 60 case KVM_PV_REASON_PAGE_NOT_PRESENT: 61 phys = virt_to_pte_phys(phys_to_virt(read_cr3()), virt); 62 install_pte(phys_to_virt(read_cr3()), 1, virt, phys, 0); 63 write_cr3(read_cr3()); 64 report(true, 65 "Got not present #PF token %lx virt addr %p phys addr %#" PRIx64, 66 read_cr2(), virt, phys); 67 while(phys) { 68 safe_halt(); /* enables irq */ 69 irq_disable(); 70 } 71 break; 72 case KVM_PV_REASON_PAGE_READY: 73 report(true, "Got present #PF token %lx", read_cr2()); 74 if ((uint32_t)read_cr2() == ~0) 75 break; 76 install_pte(phys_to_virt(read_cr3()), 1, virt, phys | PT_PRESENT_MASK | PT_WRITABLE_MASK, 0); 77 write_cr3(read_cr3()); 78 phys = 0; 79 break; 80 default: 81 report(false, "unexpected async pf reason %" PRId32, reason); 82 break; 83 } 84 } 85 86 #define MEM 1ull*1024*1024*1024 87 88 int main(int ac, char **av) 89 { 90 int loop = 2; 91 92 setup_vm(); 93 printf("install handler\n"); 94 handle_exception(14, pf_isr); 95 apf_reason = 0; 96 printf("enable async pf\n"); 97 wrmsr(MSR_KVM_ASYNC_PF_EN, virt_to_phys((void*)&apf_reason) | 98 KVM_ASYNC_PF_SEND_ALWAYS | KVM_ASYNC_PF_ENABLED); 99 printf("alloc memory\n"); 100 buf = malloc(MEM); 101 irq_enable(); 102 while(loop--) { 103 printf("start loop\n"); 104 /* access a lot of memory to make host swap it out */ 105 for (i=0; i < MEM; i+=4096) 106 buf[i] = 1; 107 printf("end loop\n"); 108 } 109 irq_disable(); 110 111 return report_summary(); 112 } 113