123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109 |
- #include "x86/msr.h"
- #include "x86/processor.h"
- #include "x86/apic-defs.h"
- #include "x86/apic.h"
- #include "x86/desc.h"
- #include "x86/isr.h"
- #include "x86/vm.h"
- #include "libcflat.h"
- #include <stdint.h>
- #define KVM_PV_REASON_PAGE_NOT_PRESENT 1
- #define KVM_PV_REASON_PAGE_READY 2
- #define MSR_KVM_ASYNC_PF_EN 0x4b564d02
- #define KVM_ASYNC_PF_ENABLED (1 << 0)
- #define KVM_ASYNC_PF_SEND_ALWAYS (1 << 1)
- volatile uint32_t apf_reason __attribute__((aligned(64)));
- char *buf;
- volatile uint64_t i;
- volatile uint64_t phys;
- static inline uint32_t get_apf_reason(void)
- {
- uint32_t r = apf_reason;
- apf_reason = 0;
- return r;
- }
- static void pf_isr(struct ex_regs *r)
- {
- void* virt = (void*)((ulong)(buf+i) & ~(PAGE_SIZE-1));
- uint32_t reason = get_apf_reason();
- switch (reason) {
- case 0:
- report("unexpected #PF at %#lx", false, read_cr2());
- break;
- case KVM_PV_REASON_PAGE_NOT_PRESENT:
- phys = virt_to_phys_cr3(virt);
- install_pte(phys_to_virt(read_cr3()), 1, virt, phys, 0);
- write_cr3(read_cr3());
- report("Got not present #PF token %lx virt addr %p phys addr %#" PRIx64,
- true, read_cr2(), virt, phys);
- while(phys) {
- safe_halt();
- irq_disable();
- }
- break;
- case KVM_PV_REASON_PAGE_READY:
- report("Got present #PF token %lx", true, read_cr2());
- if ((uint32_t)read_cr2() == ~0)
- break;
- install_pte(phys_to_virt(read_cr3()), 1, virt, phys | PT_PRESENT_MASK | PT_WRITABLE_MASK, 0);
- write_cr3(read_cr3());
- phys = 0;
- break;
- default:
- report("unexpected async pf reason %d", false, reason);
- break;
- }
- }
- #define MEM 1ull*1024*1024*1024
- int main(int ac, char **av)
- {
- int loop = 2;
- setup_vm();
- setup_idt();
- printf("install handler\n");
- handle_exception(14, pf_isr);
- apf_reason = 0;
- printf("enable async pf\n");
- wrmsr(MSR_KVM_ASYNC_PF_EN, virt_to_phys((void*)&apf_reason) |
- KVM_ASYNC_PF_SEND_ALWAYS | KVM_ASYNC_PF_ENABLED);
- printf("alloc memory\n");
- buf = vmalloc(MEM);
- irq_enable();
- while(loop--) {
- printf("start loop\n");
-
- for (i=0; i < MEM; i+=4096)
- buf[i] = 1;
- printf("end loop\n");
- }
- irq_disable();
- return report_summary();
- }
|