diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 704fd6441a..deb1783848 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -2512,6 +2512,10 @@ bool_t hvm_virtual_to_linear_addr( */ addr = (uint32_t)(addr + reg->base); + /* Segment not valid for use (cooked meaning of .p)? */ + if ( !reg->attr.fields.p ) + goto out; + switch ( access_type ) { case hvm_access_read: @@ -2767,6 +2771,10 @@ static int hvm_load_segment_selector( hvm_get_segment_register( v, (sel & 4) ? x86_seg_ldtr : x86_seg_gdtr, &desctab); + /* Segment not valid for use (cooked meaning of .p)? */ + if ( !desctab.attr.fields.p ) + goto fail; + /* Check against descriptor table limit. */ if ( ((sel & 0xfff8) + 7) > desctab.limit ) goto fail; diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c index c9dbbea42f..98a037d4dc 100644 --- a/xen/arch/x86/hvm/svm/svm.c +++ b/xen/arch/x86/hvm/svm/svm.c @@ -627,6 +627,7 @@ static void svm_get_segment_register(struct vcpu *v, enum x86_segment seg, { case x86_seg_cs: memcpy(reg, &vmcb->cs, sizeof(*reg)); + reg->attr.fields.p = 1; reg->attr.fields.g = reg->limit > 0xFFFFF; break; case x86_seg_ds: @@ -660,13 +661,16 @@ static void svm_get_segment_register(struct vcpu *v, enum x86_segment seg, case x86_seg_tr: svm_sync_vmcb(v); memcpy(reg, &vmcb->tr, sizeof(*reg)); + reg->attr.fields.p = 1; reg->attr.fields.type |= 0x2; break; case x86_seg_gdtr: memcpy(reg, &vmcb->gdtr, sizeof(*reg)); + reg->attr.bytes = 0x80; break; case x86_seg_idtr: memcpy(reg, &vmcb->idtr, sizeof(*reg)); + reg->attr.bytes = 0x80; break; case x86_seg_ldtr: svm_sync_vmcb(v); diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index a18db28f6f..0a52624994 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -1035,10 +1035,12 @@ void vmx_get_segment_register(struct vcpu *v, enum x86_segment seg, reg->sel = sel; reg->limit = limit; - reg->attr.bytes = (attr & 0xff) | ((attr >> 4) & 0xf00); - /* Unusable flag is folded into Present flag. */ - if ( attr & (1u<<16) ) - reg->attr.fields.p = 0; + /* + * Fold VT-x representation into Xen's representation. The Present bit is + * unconditionally set to the inverse of unusable. + */ + reg->attr.bytes = + (!(attr & (1u << 16)) << 7) | (attr & 0x7f) | ((attr >> 4) & 0xf00); /* Adjust for virtual 8086 mode */ if ( v->arch.hvm_vmx.vmx_realmode && seg <= x86_seg_tr @@ -1118,11 +1120,11 @@ static void vmx_set_segment_register(struct vcpu *v, enum x86_segment seg, } } - attr = ((attr & 0xf00) << 4) | (attr & 0xff); - - /* Not-present must mean unusable. */ - if ( !reg->attr.fields.p ) - attr |= (1u << 16); + /* + * Unfold Xen representation into VT-x representation. The unusable bit + * is unconditionally set to the inverse of present. + */ + attr = (!(attr & (1u << 7)) << 16) | ((attr & 0xf00) << 4) | (attr & 0xff); /* VMX has strict consistency requirement for flag G. */ attr |= !!(limit >> 20) << 15; diff --git a/xen/arch/x86/x86_emulate/x86_emulate.c b/xen/arch/x86/x86_emulate/x86_emulate.c index 26214877c3..f9cdb63426 100644 --- a/xen/arch/x86/x86_emulate/x86_emulate.c +++ b/xen/arch/x86/x86_emulate/x86_emulate.c @@ -1367,6 +1367,10 @@ protmode_load_seg( &desctab, ctxt)) ) return rc; + /* Segment not valid for use (cooked meaning of .p)? */ + if ( !desctab.attr.fields.p ) + goto raise_exn; + /* Check against descriptor table limit. */ if ( ((sel & 0xfff8) + 7) > desctab.limit ) goto raise_exn;