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,22 @@ if (in) { vis->seg_name = VM_REG_GUEST_ES; } else { - /* The segment field has standard encoding */ - s = (info1 >> 10) & 0x7; + /* + * The effective segment number in EXITINFO1[12:10] is populated + * only if the processor has the DecodeAssist capability. + * + * XXX this is not specified explicitly in APMv2 but can be + * verified empirically. + */ + 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); } @@ -798,16 +854,6 @@ info1 = ctrl->exitinfo1; inout_string = info1 & BIT(2) ? 1 : 0; - /* - * The effective segment number in EXITINFO1[12:10] is populated - * only if the processor has the DecodeAssist capability. - * - * XXX this is not specified explicitly in APMv2 but can be verified - * empirically. - */ - if (inout_string && !decode_assist()) - return (UNHANDLED); - vmexit->exitcode = VM_EXITCODE_INOUT; vmexit->u.inout.in = (info1 & BIT(0)) ? 1 : 0; vmexit->u.inout.string = inout_string;