1 #include "vmx.h" 2 #include "msr.h" 3 #include "processor.h" 4 #include "vm.h" 5 6 u64 ia32_pat; 7 u64 ia32_efer; 8 9 static inline void vmcall() 10 { 11 asm volatile("vmcall"); 12 } 13 14 void basic_init() 15 { 16 } 17 18 void basic_guest_main() 19 { 20 /* Here is a basic guest_main, print Hello World */ 21 printf("\tHello World, this is null_guest_main!\n"); 22 } 23 24 int basic_exit_handler() 25 { 26 u64 guest_rip; 27 ulong reason; 28 29 guest_rip = vmcs_read(GUEST_RIP); 30 reason = vmcs_read(EXI_REASON) & 0xff; 31 32 switch (reason) { 33 case VMX_VMCALL: 34 print_vmexit_info(); 35 vmcs_write(GUEST_RIP, guest_rip + 3); 36 return VMX_TEST_RESUME; 37 default: 38 break; 39 } 40 printf("ERROR : Unhandled vmx exit.\n"); 41 print_vmexit_info(); 42 return VMX_TEST_EXIT; 43 } 44 45 void basic_syscall_handler(u64 syscall_no) 46 { 47 } 48 49 void vmenter_main() 50 { 51 u64 rax; 52 u64 rsp, resume_rsp; 53 54 report("test vmlaunch", 1); 55 56 asm volatile( 57 "mov %%rsp, %0\n\t" 58 "mov %3, %%rax\n\t" 59 "vmcall\n\t" 60 "mov %%rax, %1\n\t" 61 "mov %%rsp, %2\n\t" 62 : "=r"(rsp), "=r"(rax), "=r"(resume_rsp) 63 : "g"(0xABCD)); 64 report("test vmresume", (rax == 0xFFFF) && (rsp == resume_rsp)); 65 } 66 67 int vmenter_exit_handler() 68 { 69 u64 guest_rip; 70 ulong reason; 71 72 guest_rip = vmcs_read(GUEST_RIP); 73 reason = vmcs_read(EXI_REASON) & 0xff; 74 switch (reason) { 75 case VMX_VMCALL: 76 if (regs.rax != 0xABCD) { 77 report("test vmresume", 0); 78 return VMX_TEST_VMEXIT; 79 } 80 regs.rax = 0xFFFF; 81 vmcs_write(GUEST_RIP, guest_rip + 3); 82 return VMX_TEST_RESUME; 83 default: 84 report("test vmresume", 0); 85 print_vmexit_info(); 86 } 87 return VMX_TEST_VMEXIT; 88 } 89 90 void msr_bmp_init() 91 { 92 void *msr_bitmap; 93 u32 ctrl_cpu0; 94 95 msr_bitmap = alloc_page(); 96 memset(msr_bitmap, 0x0, PAGE_SIZE); 97 ctrl_cpu0 = vmcs_read(CPU_EXEC_CTRL0); 98 ctrl_cpu0 |= CPU_MSR_BITMAP; 99 vmcs_write(CPU_EXEC_CTRL0, ctrl_cpu0); 100 vmcs_write(MSR_BITMAP, (u64)msr_bitmap); 101 } 102 103 static void test_ctrl_pat_init() 104 { 105 u64 ctrl_ent; 106 u64 ctrl_exi; 107 108 msr_bmp_init(); 109 ctrl_ent = vmcs_read(ENT_CONTROLS); 110 ctrl_exi = vmcs_read(EXI_CONTROLS); 111 vmcs_write(ENT_CONTROLS, ctrl_ent | ENT_LOAD_PAT); 112 vmcs_write(EXI_CONTROLS, ctrl_exi | (EXI_SAVE_PAT | EXI_LOAD_PAT)); 113 ia32_pat = rdmsr(MSR_IA32_CR_PAT); 114 vmcs_write(GUEST_PAT, 0x0); 115 vmcs_write(HOST_PAT, ia32_pat); 116 } 117 118 static void test_ctrl_pat_main() 119 { 120 u64 guest_ia32_pat; 121 122 guest_ia32_pat = rdmsr(MSR_IA32_CR_PAT); 123 if (!(ctrl_enter_rev.clr & ENT_LOAD_PAT)) 124 printf("\tENT_LOAD_PAT is not supported.\n"); 125 else { 126 if (guest_ia32_pat != 0) { 127 report("Entry load PAT", 0); 128 return; 129 } 130 } 131 wrmsr(MSR_IA32_CR_PAT, 0x6); 132 vmcall(); 133 guest_ia32_pat = rdmsr(MSR_IA32_CR_PAT); 134 if (ctrl_enter_rev.clr & ENT_LOAD_PAT) { 135 if (guest_ia32_pat != ia32_pat) { 136 report("Entry load PAT", 0); 137 return; 138 } 139 report("Entry load PAT", 1); 140 } 141 } 142 143 static int test_ctrl_pat_exit_handler() 144 { 145 u64 guest_rip; 146 ulong reason; 147 u64 guest_pat; 148 149 guest_rip = vmcs_read(GUEST_RIP); 150 reason = vmcs_read(EXI_REASON) & 0xff; 151 switch (reason) { 152 case VMX_VMCALL: 153 guest_pat = vmcs_read(GUEST_PAT); 154 if (!(ctrl_exit_rev.clr & EXI_SAVE_PAT)) { 155 printf("\tEXI_SAVE_PAT is not supported\n"); 156 vmcs_write(GUEST_PAT, 0x6); 157 } else { 158 if (guest_pat == 0x6) 159 report("Exit save PAT", 1); 160 else 161 report("Exit save PAT", 0); 162 } 163 if (!(ctrl_exit_rev.clr & EXI_LOAD_PAT)) 164 printf("\tEXI_LOAD_PAT is not supported\n"); 165 else { 166 if (rdmsr(MSR_IA32_CR_PAT) == ia32_pat) 167 report("Exit load PAT", 1); 168 else 169 report("Exit load PAT", 0); 170 } 171 vmcs_write(GUEST_PAT, ia32_pat); 172 vmcs_write(GUEST_RIP, guest_rip + 3); 173 return VMX_TEST_RESUME; 174 default: 175 printf("ERROR : Undefined exit reason, reason = %d.\n", reason); 176 break; 177 } 178 return VMX_TEST_VMEXIT; 179 } 180 181 static void test_ctrl_efer_init() 182 { 183 u64 ctrl_ent; 184 u64 ctrl_exi; 185 186 msr_bmp_init(); 187 ctrl_ent = vmcs_read(ENT_CONTROLS) | ENT_LOAD_EFER; 188 ctrl_exi = vmcs_read(EXI_CONTROLS) | EXI_SAVE_EFER | EXI_LOAD_EFER; 189 vmcs_write(ENT_CONTROLS, ctrl_ent & ctrl_enter_rev.clr); 190 vmcs_write(EXI_CONTROLS, ctrl_exi & ctrl_exit_rev.clr); 191 ia32_efer = rdmsr(MSR_EFER); 192 vmcs_write(GUEST_EFER, ia32_efer ^ EFER_NX); 193 vmcs_write(HOST_EFER, ia32_efer ^ EFER_NX); 194 } 195 196 static void test_ctrl_efer_main() 197 { 198 u64 guest_ia32_efer; 199 200 guest_ia32_efer = rdmsr(MSR_EFER); 201 if (!(ctrl_enter_rev.clr & ENT_LOAD_EFER)) 202 printf("\tENT_LOAD_EFER is not supported.\n"); 203 else { 204 if (guest_ia32_efer != (ia32_efer ^ EFER_NX)) { 205 report("Entry load EFER", 0); 206 return; 207 } 208 } 209 wrmsr(MSR_EFER, ia32_efer); 210 vmcall(); 211 guest_ia32_efer = rdmsr(MSR_EFER); 212 if (ctrl_enter_rev.clr & ENT_LOAD_EFER) { 213 if (guest_ia32_efer != ia32_efer) { 214 report("Entry load EFER", 0); 215 return; 216 } 217 report("Entry load EFER", 1); 218 } 219 } 220 221 static int test_ctrl_efer_exit_handler() 222 { 223 u64 guest_rip; 224 ulong reason; 225 u64 guest_efer; 226 227 guest_rip = vmcs_read(GUEST_RIP); 228 reason = vmcs_read(EXI_REASON) & 0xff; 229 switch (reason) { 230 case VMX_VMCALL: 231 guest_efer = vmcs_read(GUEST_EFER); 232 if (!(ctrl_exit_rev.clr & EXI_SAVE_EFER)) { 233 printf("\tEXI_SAVE_EFER is not supported\n"); 234 vmcs_write(GUEST_EFER, ia32_efer); 235 } else { 236 if (guest_efer == ia32_efer) 237 report("Exit save EFER", 1); 238 else 239 report("Exit save EFER", 0); 240 } 241 if (!(ctrl_exit_rev.clr & EXI_LOAD_EFER)) { 242 printf("\tEXI_LOAD_EFER is not supported\n"); 243 wrmsr(MSR_EFER, ia32_efer ^ EFER_NX); 244 } else { 245 if (rdmsr(MSR_EFER) == (ia32_efer ^ EFER_NX)) 246 report("Exit load EFER", 1); 247 else 248 report("Exit load EFER", 0); 249 } 250 vmcs_write(GUEST_PAT, ia32_efer); 251 vmcs_write(GUEST_RIP, guest_rip + 3); 252 return VMX_TEST_RESUME; 253 default: 254 printf("ERROR : Undefined exit reason, reason = %d.\n", reason); 255 break; 256 } 257 return VMX_TEST_VMEXIT; 258 } 259 260 /* name/init/guest_main/exit_handler/syscall_handler/guest_regs 261 basic_* just implement some basic functions */ 262 struct vmx_test vmx_tests[] = { 263 { "null", basic_init, basic_guest_main, basic_exit_handler, 264 basic_syscall_handler, {0} }, 265 { "vmenter", basic_init, vmenter_main, vmenter_exit_handler, 266 basic_syscall_handler, {0} }, 267 { "control field PAT", test_ctrl_pat_init, test_ctrl_pat_main, 268 test_ctrl_pat_exit_handler, basic_syscall_handler, {0} }, 269 { "control field EFER", test_ctrl_efer_init, test_ctrl_efer_main, 270 test_ctrl_efer_exit_handler, basic_syscall_handler, {0} }, 271 { NULL, NULL, NULL, NULL, NULL, {0} }, 272 }; 273