ia64/xen-unstable

changeset 13404:7ad205a162a8

x86: properly handle LOCK prefix in privileged PV opcode emulation

- include LOCK prefix presence in calculation of which CR/DR is being
targeted by moves to/from these registers
- fail any other opcodes when beingused with lock prefix

Signed-off-by: Jan Beulich <jbeulich@novell.com>
author kfraser@localhost.localdomain
date Fri Jan 12 14:38:30 2007 +0000 (2007-01-12)
parents 3f419d160647
children c6cea93d3cd9
files xen/arch/x86/traps.c
line diff
     1.1 --- a/xen/arch/x86/traps.c	Fri Jan 12 14:33:36 2007 +0000
     1.2 +++ b/xen/arch/x86/traps.c	Fri Jan 12 14:38:30 2007 +0000
     1.3 @@ -1121,7 +1121,7 @@ static int emulate_privileged_op(struct 
     1.4  {
     1.5      struct vcpu *v = current;
     1.6      unsigned long *reg, eip = regs->eip, res;
     1.7 -    u8 opcode, modrm_reg = 0, modrm_rm = 0, rep_prefix = 0, rex = 0;
     1.8 +    u8 opcode, modrm_reg = 0, modrm_rm = 0, rep_prefix = 0, lock = 0, rex = 0;
     1.9      enum { lm_seg_none, lm_seg_fs, lm_seg_gs } lm_ovr = lm_seg_none;
    1.10      unsigned int port, i, data_sel, ar, data, rc;
    1.11      unsigned int op_bytes, op_default, ad_bytes, ad_default;
    1.12 @@ -1184,6 +1184,7 @@ static int emulate_privileged_op(struct 
    1.13              data_sel = regs->ss;
    1.14              continue;
    1.15          case 0xf0: /* LOCK */
    1.16 +            lock = 1;
    1.17              continue;
    1.18          case 0xf2: /* REPNE/REPNZ */
    1.19          case 0xf3: /* REP/REPE/REPZ */
    1.20 @@ -1210,6 +1211,9 @@ static int emulate_privileged_op(struct 
    1.21      if ( opcode == 0x0f )
    1.22          goto twobyte_opcode;
    1.23      
    1.24 +    if ( lock )
    1.25 +        goto fail;
    1.26 +
    1.27      /* Input/Output String instructions. */
    1.28      if ( (opcode >= 0x6c) && (opcode <= 0x6f) )
    1.29      {
    1.30 @@ -1472,6 +1476,8 @@ static int emulate_privileged_op(struct 
    1.31  
    1.32      /* Privileged (ring 0) instructions. */
    1.33      opcode = insn_fetch(u8, code_base, eip, code_limit);
    1.34 +    if ( lock && (opcode & ~3) != 0x20 )
    1.35 +        goto fail;
    1.36      switch ( opcode )
    1.37      {
    1.38      case 0x06: /* CLTS */
    1.39 @@ -1490,7 +1496,7 @@ static int emulate_privileged_op(struct 
    1.40  
    1.41      case 0x20: /* MOV CR?,<reg> */
    1.42          opcode = insn_fetch(u8, code_base, eip, code_limit);
    1.43 -        modrm_reg |= (opcode >> 3) & 7;
    1.44 +        modrm_reg += ((opcode >> 3) & 7) + (lock << 3);
    1.45          modrm_rm  |= (opcode >> 0) & 7;
    1.46          reg = decode_register(modrm_rm, regs, 0);
    1.47          switch ( modrm_reg )
    1.48 @@ -1530,7 +1536,7 @@ static int emulate_privileged_op(struct 
    1.49  
    1.50      case 0x21: /* MOV DR?,<reg> */
    1.51          opcode = insn_fetch(u8, code_base, eip, code_limit);
    1.52 -        modrm_reg |= (opcode >> 3) & 7;
    1.53 +        modrm_reg += ((opcode >> 3) & 7) + (lock << 3);
    1.54          modrm_rm  |= (opcode >> 0) & 7;
    1.55          reg = decode_register(modrm_rm, regs, 0);
    1.56          if ( (res = do_get_debugreg(modrm_reg)) > (unsigned long)-256 )
    1.57 @@ -1540,7 +1546,7 @@ static int emulate_privileged_op(struct 
    1.58  
    1.59      case 0x22: /* MOV <reg>,CR? */
    1.60          opcode = insn_fetch(u8, code_base, eip, code_limit);
    1.61 -        modrm_reg |= (opcode >> 3) & 7;
    1.62 +        modrm_reg += ((opcode >> 3) & 7) + (lock << 3);
    1.63          modrm_rm  |= (opcode >> 0) & 7;
    1.64          reg = decode_register(modrm_rm, regs, 0);
    1.65          switch ( modrm_reg )
    1.66 @@ -1588,7 +1594,7 @@ static int emulate_privileged_op(struct 
    1.67  
    1.68      case 0x23: /* MOV <reg>,DR? */
    1.69          opcode = insn_fetch(u8, code_base, eip, code_limit);
    1.70 -        modrm_reg |= (opcode >> 3) & 7;
    1.71 +        modrm_reg += ((opcode >> 3) & 7) + (lock << 3);
    1.72          modrm_rm  |= (opcode >> 0) & 7;
    1.73          reg = decode_register(modrm_rm, regs, 0);
    1.74          if ( do_set_debugreg(modrm_reg, *reg) != 0 )