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,55 @@ return (val); } +static int +decode_segment(struct svm_vcpu *svcpu, int *segment) +{ + 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 the segment override prefix to a 16-bit register number. + */ + switch (vie.inst[0]) { + case 0x26: + *segment = 0; + break; + case 0x2E: + *segment = 1; + break; + case 0x36: + *segment = 2; + break; + case 0x3E: + *segment = 3; + break; + case 0x64: + *segment = 4; + break; + case 0x65: + *segment = 5; + break; + default: + err = -1; + break; + } + + return (err); +} + static void svm_inout_str_seginfo(struct svm_vcpu *vcpu, int64_t info1, int in, struct vm_inout_str *vis) @@ -736,8 +785,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()) { + error = decode_segment(vcpu, &s); + if (error) + panic("%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 +861,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;