| 1320 | } |
| 1321 | |
| 1322 | static int |
| 1323 | svm_vmexit(struct svm_softc *svm_sc, int vcpu, struct vm_exit *vmexit) |
| 1324 | { |
| 1325 | struct vmcb *vmcb; |
| 1326 | struct vmcb_state *state; |
| 1327 | struct vmcb_ctrl *ctrl; |
| 1328 | struct svm_regctx *ctx; |
| 1329 | uint64_t code, info1, info2, val; |
| 1330 | uint32_t eax, ecx, edx; |
| 1331 | int error, errcode_valid, handled, idtvec, reflect; |
| 1332 | bool retu; |
| 1333 | |
| 1334 | ctx = svm_get_guest_regctx(svm_sc, vcpu); |
| 1335 | vmcb = svm_get_vmcb(svm_sc, vcpu); |
| 1336 | state = &vmcb->state; |
| 1337 | ctrl = &vmcb->ctrl; |
| 1338 | |
| 1339 | handled = 0; |
| 1340 | code = ctrl->exitcode; |
| 1341 | info1 = ctrl->exitinfo1; |
| 1342 | info2 = ctrl->exitinfo2; |
| 1343 | |
| 1344 | vmexit->exitcode = VM_EXITCODE_BOGUS; |
| 1345 | vmexit->rip = state->rip; |
| 1346 | vmexit->inst_length = nrip_valid(code) ? ctrl->nrip - state->rip : 0; |
| 1347 | |
| 1348 | vmm_stat_incr(svm_sc->vm, vcpu, VMEXIT_COUNT, 1); |
| 1349 | |
| 1350 | /* |
| 1351 | * #VMEXIT(INVALID) needs to be handled early because the VMCB is |
| 1352 | * in an inconsistent state and can trigger assertions that would |
| 1353 | * never happen otherwise. |
| 1354 | */ |
| 1355 | if (code == VMCB_EXIT_INVALID) { |
| 1356 | vm_exit_svm(vmexit, code, info1, info2); |
| 1357 | return (0); |
| 1358 | } |
| 1359 | |
| 1360 | KASSERT((ctrl->eventinj & VMCB_EVENTINJ_VALID) == 0, ("%s: event " |
| 1361 | "injection valid bit is set %#lx", __func__, ctrl->eventinj)); |
| 1362 | |
| 1363 | KASSERT(vmexit->inst_length >= 0 && vmexit->inst_length <= 15, |
| 1364 | ("invalid inst_length %d: code (%#lx), info1 (%#lx), info2 (%#lx)", |
| 1365 | vmexit->inst_length, code, info1, info2)); |
| 1366 | |
| 1367 | svm_update_virqinfo(svm_sc, vcpu); |
| 1368 | svm_save_intinfo(svm_sc, vcpu); |
| 1369 | |
| 1370 | switch (code) { |
| 1371 | case VMCB_EXIT_IRET: |
| 1372 | /* |
| 1373 | * Restart execution at "iret" but with the intercept cleared. |
| 1374 | */ |
| 1375 | vmexit->inst_length = 0; |
| 1376 | clear_nmi_blocking(svm_sc, vcpu); |
| 1377 | handled = 1; |
| 1378 | break; |
| 1379 | case VMCB_EXIT_VINTR: /* interrupt window exiting */ |
no test coverage detected