do {
desc = *pdesc;
- /* Segment present in memory? */
- if ( !(desc.b & _SEGMENT_P) )
- {
- fault_type = (seg != x86_seg_ss) ? TRAP_no_segment
- : TRAP_stack_error;
- goto unmap_and_fail;
- }
-
/* LDT descriptor is a system segment. All others are code/data. */
if ( (desc.b & (1u<<12)) == ((seg == x86_seg_ldtr) << 12) )
goto unmap_and_fail;
goto unmap_and_fail;
break;
}
+
+ /* Segment present in memory? */
+ if ( !(desc.b & _SEGMENT_P) )
+ {
+ fault_type = (seg != x86_seg_ss) ? TRAP_no_segment
+ : TRAP_stack_error;
+ goto unmap_and_fail;
+ }
} while ( !(desc.b & 0x100) && /* Ensure Accessed flag is set */
writable && /* except if we are to discard writes */
(cmpxchg(&pdesc->b, desc.b, desc.b | 0x100) != desc.b) );
if ( tr.attr.fields.g )
tr.limit = (tr.limit << 12) | 0xfffu;
- if ( !tr.attr.fields.p )
- {
- hvm_inject_hw_exception(TRAP_no_segment, tss_sel & 0xfff8);
- goto out;
- }
-
if ( tr.attr.fields.type != ((taskswitch_reason == TSW_iret) ? 0xb : 0x9) )
{
hvm_inject_hw_exception(
goto out;
}
+ if ( !tr.attr.fields.p )
+ {
+ hvm_inject_hw_exception(TRAP_no_segment, tss_sel & 0xfff8);
+ goto out;
+ }
+
if ( tr.limit < (sizeof(tss)-1) )
{
hvm_inject_hw_exception(TRAP_invalid_tss, tss_sel & 0xfff8);
struct { uint32_t a, b; } desc;
uint8_t dpl, rpl;
int cpl = get_cpl(ctxt, ops);
- uint32_t new_desc_b, a_flag = 0x100;
+ uint32_t a_flag = 0x100;
int rc, fault_type = EXC_GP;
if ( cpl < 0 )
&desc, sizeof(desc), ctxt)) )
return rc;
- /* Segment present in memory? */
- if ( !(desc.b & (1u<<15)) )
- {
- fault_type = seg != x86_seg_ss ? EXC_NP : EXC_SS;
- goto raise_exn;
- }
-
if ( !is_x86_user_segment(seg) )
{
/* System segments must have S flag == 0. */
/* Non-conforming segment: check RPL and DPL against CPL. */
: rpl > cpl || dpl != cpl )
goto raise_exn;
- /* 64-bit code segments (L bit set) must have D bit clear. */
- if ( in_longmode(ctxt, ops) &&
- (desc.b & (1 << 21)) && (desc.b & (1 << 22)) )
- goto raise_exn;
sel = (sel ^ rpl) | cpl;
break;
case x86_seg_ss:
/* LDT system segment? */
if ( (desc.b & (15u<<8)) != (2u<<8) )
goto raise_exn;
- goto skip_accessed_flag;
+ a_flag = 0;
+ break;
case x86_seg_tr:
/* Available TSS system segment? */
if ( (desc.b & (15u<<8)) != (9u<<8) )
break;
}
+ /* Segment present in memory? */
+ if ( !(desc.b & (1 << 15)) )
+ {
+ fault_type = seg != x86_seg_ss ? EXC_NP : EXC_SS;
+ goto raise_exn;
+ }
+
+ /* 64-bit code segments (L bit set) must have D bit clear. */
+ if ( seg == x86_seg_cs && in_longmode(ctxt, ops) &&
+ (desc.b & (1 << 21)) && (desc.b & (1 << 22)) )
+ goto raise_exn;
+
/* Ensure Accessed flag is set. */
- new_desc_b = desc.b | a_flag;
- if ( !(desc.b & a_flag) &&
- ((rc = ops->cmpxchg(
- x86_seg_none, desctab.base + (sel & 0xfff8) + 4,
- &desc.b, &new_desc_b, 4, ctxt)) != 0) )
- return rc;
+ if ( a_flag && !(desc.b & a_flag) )
+ {
+ uint32_t new_desc_b = desc.b | a_flag;
- /* Force the Accessed flag in our local copy. */
- desc.b |= a_flag;
+ if ( (rc = ops->cmpxchg(x86_seg_none, desctab.base + (sel & 0xfff8) + 4,
+ &desc.b, &new_desc_b, 4, ctxt)) != 0 )
+ return rc;
+
+ /* Force the Accessed flag in our local copy. */
+ desc.b = new_desc_b;
+ }
- skip_accessed_flag:
sreg->base = (((desc.b << 0) & 0xff000000u) |
((desc.b << 16) & 0x00ff0000u) |
((desc.a >> 16) & 0x0000ffffu));