| 364 | } |
| 365 | |
| 366 | int |
| 367 | vmcb_setdesc(void *arg, int vcpu, int reg, struct seg_desc *desc) |
| 368 | { |
| 369 | struct vmcb *vmcb; |
| 370 | struct svm_softc *sc; |
| 371 | struct vmcb_segment *seg; |
| 372 | uint16_t attrib; |
| 373 | |
| 374 | sc = arg; |
| 375 | vmcb = svm_get_vmcb(sc, vcpu); |
| 376 | |
| 377 | seg = vmcb_segptr(vmcb, reg); |
| 378 | KASSERT(seg != NULL, ("%s: invalid segment descriptor %d", |
| 379 | __func__, reg)); |
| 380 | |
| 381 | seg->base = desc->base; |
| 382 | seg->limit = desc->limit; |
| 383 | if (reg != VM_REG_GUEST_GDTR && reg != VM_REG_GUEST_IDTR) { |
| 384 | /* |
| 385 | * Map seg_desc access to VMCB attribute format. |
| 386 | * |
| 387 | * SVM uses the 'P' bit in the segment attributes to indicate a |
| 388 | * NULL segment so clear it if the segment is marked unusable. |
| 389 | */ |
| 390 | attrib = ((desc->access & 0xF000) >> 4) | (desc->access & 0xFF); |
| 391 | if (SEG_DESC_UNUSABLE(desc->access)) { |
| 392 | attrib &= ~0x80; |
| 393 | } |
| 394 | seg->attrib = attrib; |
| 395 | } |
| 396 | |
| 397 | VCPU_CTR4(sc->vm, vcpu, "Setting desc %d: base (%#lx), limit (%#x), " |
| 398 | "attrib (%#x)", reg, seg->base, seg->limit, seg->attrib); |
| 399 | |
| 400 | switch (reg) { |
| 401 | case VM_REG_GUEST_CS: |
| 402 | case VM_REG_GUEST_DS: |
| 403 | case VM_REG_GUEST_ES: |
| 404 | case VM_REG_GUEST_SS: |
| 405 | svm_set_dirty(sc, vcpu, VMCB_CACHE_SEG); |
| 406 | break; |
| 407 | case VM_REG_GUEST_GDTR: |
| 408 | case VM_REG_GUEST_IDTR: |
| 409 | svm_set_dirty(sc, vcpu, VMCB_CACHE_DT); |
| 410 | break; |
| 411 | default: |
| 412 | break; |
| 413 | } |
| 414 | |
| 415 | return (0); |
| 416 | } |
| 417 | |
| 418 | int |
| 419 | vmcb_getdesc(void *arg, int vcpu, int reg, struct seg_desc *desc) |
no test coverage detected