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 "libcflat.h" 26 #include <stdint.h> 27 28 #define KVM_PV_REASON_PAGE_NOT_PRESENT 1 29 #define KVM_PV_REASON_PAGE_READY 2 30 31 #define MSR_KVM_ASYNC_PF_EN 0x4b564d02 32 33 #define KVM_ASYNC_PF_ENABLED (1 << 0) 34 #define KVM_ASYNC_PF_SEND_ALWAYS (1 << 1) 35 36 volatile uint32_t apf_reason __attribute__((aligned(64))); 37 char *buf; 38 volatile uint64_t i; 39 volatile uint64_t phys; 40 bool fail; 41 42 static inline uint32_t get_apf_reason(void) 43 { 44 uint32_t r = apf_reason; 45 apf_reason = 0; 46 return r; 47 } 48 49 static void pf_isr(struct ex_regs *r) 50 { 51 void* virt = (void*)((ulong)(buf+i) & ~(PAGE_SIZE-1)); 52 uint32_t reason = get_apf_reason(); 53 54 switch (reason) { 55 case 0: 56 printf("unexpected #PF at %p\n", read_cr2()); 57 fail = true; 58 break; 59 case KVM_PV_REASON_PAGE_NOT_PRESENT: 60 phys = virt_to_phys_cr3(virt); 61 install_pte(phys_to_virt(read_cr3()), 1, virt, phys, 0); 62 write_cr3(read_cr3()); 63 printf("Got not present #PF token %x virt addr %p phys addr %p\n", read_cr2(), virt, phys); 64 while(phys) { 65 safe_halt(); /* enables irq */ 66 irq_disable(); 67 } 68 break; 69 case KVM_PV_REASON_PAGE_READY: 70 printf("Got present #PF token %x\n", read_cr2()); 71 if ((uint32_t)read_cr2() == ~0) 72 break; 73 install_pte(phys_to_virt(read_cr3()), 1, virt, phys | PTE_PRESENT | PTE_WRITE, 0); 74 write_cr3(read_cr3()); 75 phys = 0; 76 break; 77 default: 78 printf("unexpected async pf reason %d\n", reason); 79 fail = true; 80 break; 81 } 82 } 83 84 #define MEM 1ull*1024*1024*1024 85 86 int main(int ac, char **av) 87 { 88 int loop = 2; 89 90 setup_vm(); 91 setup_idt(); 92 printf("install handler\n"); 93 handle_exception(14, pf_isr); 94 apf_reason = 0; 95 printf("enable async pf\n"); 96 wrmsr(MSR_KVM_ASYNC_PF_EN, virt_to_phys((void*)&apf_reason) | 97 KVM_ASYNC_PF_SEND_ALWAYS | KVM_ASYNC_PF_ENABLED); 98 printf("alloc memory\n"); 99 buf = vmalloc(MEM); 100 irq_enable(); 101 while(loop--) { 102 printf("start loop\n"); 103 /* access a lot of memory to make host swap it out */ 104 for (i=0; i < MEM; i+=4096) 105 buf[i] = 1; 106 printf("end loop\n"); 107 } 108 irq_disable(); 109 110 printf("%s\n", fail ? "FAIL" : "PASS"); 111 return fail; 112 } 113