diff --git a/sys/amd64/vmm/amd/svm.c b/sys/amd64/vmm/amd/svm.c --- a/sys/amd64/vmm/amd/svm.c +++ b/sys/amd64/vmm/amd/svm.c @@ -727,6 +727,48 @@ return (val); } +static int +decode_segment(struct svm_vcpu *svcpu) +{ + struct vm_guest_paging *paging; + struct vie vie; + struct vm_exit *vme; + uint64_t cs_base; + int err; + int fault; + + vme = vm_exitinfo(svcpu->vcpu); + paging = &vme->u.inst_emul.paging; + cs_base = vme->u.inst_emul.cs_base; + + err = vmm_fetch_instruction(svcpu->vcpu, paging, vme->rip + cs_base, + VIE_INST_SIZE, &vie, &fault); + if (err || fault) + return (err); + + /* + * convert segment override prefix to 16bit Register number + */ + switch (vie.inst[0]) { + case 0x26: + return (0); + case 0x2E: + return (1); + case 0x36: + return (2); + case 0x3E: + return (3); + case 0x64: + return (4); + case 0x65: + return (5); + default: + err = -1; + } + + return (err); +} + static void svm_inout_str_seginfo(struct svm_vcpu *vcpu, int64_t info1, int in, struct vm_inout_str *vis) @@ -736,8 +778,15 @@ if (in) { vis->seg_name = VM_REG_GUEST_ES; } else { - /* The segment field has standard encoding */ - s = (info1 >> 10) & 0x7; + if (!decode_assist()) { + s = decode_segment(vcpu); + KASSERT(s >= 0, + ("%s: decode_segment error %d, error", __func__, + error)); + } else { + /* The segment field has standard encoding */ + s = (info1 >> 10) & 0x7; + } vis->seg_name = vm_segment_name(s); } @@ -805,7 +854,7 @@ * XXX this is not specified explicitly in APMv2 but can be verified * empirically. */ - if (inout_string && !decode_assist()) + if (inout_string) return (UNHANDLED); vmexit->exitcode = VM_EXITCODE_INOUT;