asyncpf.c 2.6 KB

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