diff options
-rw-r--r-- | sys/amd64/include/vmm.h | 1 | ||||
-rw-r--r-- | sys/amd64/include/vmm_instruction_emul.h | 6 | ||||
-rw-r--r-- | sys/amd64/vmm/intel/vmx.c | 1 | ||||
-rw-r--r-- | sys/amd64/vmm/vmm_instruction_emul.c | 70 | ||||
-rw-r--r-- | sys/amd64/vmm/vmm_ioport.c | 16 | ||||
-rw-r--r-- | usr.sbin/bhyve/inout.c | 27 |
6 files changed, 53 insertions, 68 deletions
diff --git a/sys/amd64/include/vmm.h b/sys/amd64/include/vmm.h index 28e2808e89b7..b30e42e743b2 100644 --- a/sys/amd64/include/vmm.h +++ b/sys/amd64/include/vmm.h @@ -426,7 +426,6 @@ struct vm_inout_str { int addrsize; enum vm_reg_name seg_name; struct seg_desc seg_desc; - uint64_t gla; /* may be set to VIE_INVALID_GLA */ }; struct vm_exit { diff --git a/sys/amd64/include/vmm_instruction_emul.h b/sys/amd64/include/vmm_instruction_emul.h index 1703feb20ddc..5e6862b4ca84 100644 --- a/sys/amd64/include/vmm_instruction_emul.h +++ b/sys/amd64/include/vmm_instruction_emul.h @@ -67,6 +67,9 @@ int vie_canonical_check(enum vm_cpu_mode cpu_mode, uint64_t gla); uint64_t vie_size2mask(int size); +int vie_calculate_gla(enum vm_cpu_mode cpu_mode, int addrsize, + enum vm_reg_name seg, struct seg_desc *desc, uint64_t off, uint64_t *gla); + #ifdef _KERNEL /* * APIs to fetch and decode the instruction from nested page fault handler. @@ -89,9 +92,6 @@ int vmm_gla2gpa(struct vm *vm, int vcpuid, struct vm_guest_paging *paging, void vie_init(struct vie *vie); -uint64_t vie_segbase(enum vm_reg_name segment, enum vm_cpu_mode cpu_mode, - const struct seg_desc *desc); - /* * Decode the instruction fetched into 'vie' so it can be emulated. * diff --git a/sys/amd64/vmm/intel/vmx.c b/sys/amd64/vmm/intel/vmx.c index 8efb667a1f79..1509931172b4 100644 --- a/sys/amd64/vmm/intel/vmx.c +++ b/sys/amd64/vmm/intel/vmx.c @@ -2012,7 +2012,6 @@ vmx_exit_process(struct vmx *vmx, int vcpu, struct vm_exit *vmexit) vis->count = inout_str_count(vmx, vcpu, vis->inout.rep); vis->addrsize = inout_str_addrsize(inst_info); inout_str_seginfo(vmx, vcpu, inst_info, in, vis); - vis->gla = vmcs_gla(); } break; case EXIT_REASON_CPUID: diff --git a/sys/amd64/vmm/vmm_instruction_emul.c b/sys/amd64/vmm/vmm_instruction_emul.c index 0f520d71b47a..8d4f5400ec11 100644 --- a/sys/amd64/vmm/vmm_instruction_emul.c +++ b/sys/amd64/vmm/vmm_instruction_emul.c @@ -607,6 +607,38 @@ vie_size2mask(int size) return (size2mask[size]); } +int +vie_calculate_gla(enum vm_cpu_mode cpu_mode, int addrsize, enum vm_reg_name seg, + struct seg_desc *desc, uint64_t offset, uint64_t *gla) +{ + uint64_t segbase; + int glasize; + + KASSERT(seg >= VM_REG_GUEST_ES && seg <= VM_REG_GUEST_GS, + ("%s: invalid segment %d", __func__, seg)); + + glasize = (cpu_mode == CPU_MODE_64BIT) ? 8 : 4; + + /* + * In 64-bit mode all segments except %fs and %gs have a segment + * base address of 0. + */ + if (cpu_mode == CPU_MODE_64BIT && seg != VM_REG_GUEST_FS && + seg != VM_REG_GUEST_GS) { + segbase = 0; + } else { + segbase = desc->base; + } + + /* + * Truncate 'offset' to the effective address size before adding + * it to the segment base. + */ + offset &= vie_size2mask(addrsize); + *gla = (segbase + offset) & vie_size2mask(glasize); + return (0); +} + #ifdef _KERNEL void vie_init(struct vie *vie) @@ -1271,42 +1303,4 @@ vmm_decode_instruction(struct vm *vm, int cpuid, uint64_t gla, return (0); } - -uint64_t -vie_segbase(enum vm_reg_name seg, enum vm_cpu_mode cpu_mode, - const struct seg_desc *desc) -{ - int basesize; - - basesize = 4; /* default segment width in bytes */ - - switch (seg) { - case VM_REG_GUEST_ES: - case VM_REG_GUEST_CS: - case VM_REG_GUEST_SS: - case VM_REG_GUEST_DS: - if (cpu_mode == CPU_MODE_64BIT) { - /* - * Segments having an implicit base address of 0 - * in 64-bit mode. - */ - return (0); - } - break; - case VM_REG_GUEST_FS: - case VM_REG_GUEST_GS: - if (cpu_mode == CPU_MODE_64BIT) { - /* - * In 64-bit mode the FS and GS base address is 8 bytes - * wide. - */ - basesize = 8; - } - break; - default: - panic("%s: invalid segment register %d", __func__, seg); - } - - return (desc->base & size2mask[basesize]); -} #endif /* _KERNEL */ diff --git a/sys/amd64/vmm/vmm_ioport.c b/sys/amd64/vmm/vmm_ioport.c index 96f2418a72b4..c4626251fd64 100644 --- a/sys/amd64/vmm/vmm_ioport.c +++ b/sys/amd64/vmm/vmm_ioport.c @@ -144,7 +144,6 @@ static int emulate_inout_str(struct vm *vm, int vcpuid, struct vm_exit *vmexit, bool *retu) { struct vm_inout_str *vis; - uint64_t gla, index, segbase; int in; vis = &vmexit->u.inout_str; @@ -182,21 +181,6 @@ emulate_inout_str(struct vm *vm, int vcpuid, struct vm_exit *vmexit, bool *retu) return (EINVAL); } - segbase = vie_segbase(vis->seg_name, vis->paging.cpu_mode, - &vis->seg_desc); - index = vis->index & vie_size2mask(vis->addrsize); - gla = segbase + index; - - /* - * Verify that the computed linear address matches with the one - * provided by hardware. - */ - if (vis->gla != VIE_INVALID_GLA) { - KASSERT(gla == vis->gla, ("%s: gla mismatch " - "%#lx/%#lx", __func__, gla, vis->gla)); - } - vis->gla = gla; - *retu = true; return (0); /* Return to userspace to finish emulation */ } diff --git a/usr.sbin/bhyve/inout.c b/usr.sbin/bhyve/inout.c index 9df3ab47420a..7b22b46baffe 100644 --- a/usr.sbin/bhyve/inout.c +++ b/usr.sbin/bhyve/inout.c @@ -147,15 +147,25 @@ emulate_inout(struct vmctx *ctx, int vcpu, struct vm_exit *vmexit, int strict) /* Count register */ count = vis->count & vie_size2mask(addrsize); - if (vie_alignment_check(vis->paging.cpl, bytes, vis->cr0, - vis->rflags, vis->gla)) { - error = vm_inject_exception2(ctx, vcpu, IDT_AC, 0); - assert(error == 0); - return (INOUT_RESTART); - } - - gla = vis->gla; while (count) { + if (vie_calculate_gla(vis->paging.cpu_mode, + vis->addrsize, vis->seg_name, &vis->seg_desc, + index, &gla)) { + error = vm_inject_exception2(ctx, vcpu, + IDT_GP, 0); + assert(error == 0); + return (INOUT_RESTART); + } + + if (vie_alignment_check(vis->paging.cpl, bytes, + vis->cr0, vis->rflags, gla)) { + error = vm_inject_exception2(ctx, vcpu, + IDT_AC, 0); + assert(error == 0); + return (INOUT_RESTART); + } + + val = 0; if (!in) { error = vm_copyin(ctx, vcpu, &vis->paging, @@ -190,7 +200,6 @@ emulate_inout(struct vmctx *ctx, int vcpu, struct vm_exit *vmexit, int strict) index += bytes; count--; - gla += bytes; } /* Update index register */ |