direct-io.hg

changeset 14670:d3b1341d83db

svm: Improve emulation of SMSW instruction for memory operands.
From: Trolle Selander <trolle.selander@gmail.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
author Keir Fraser <keir@xensource.com>
date Fri Mar 30 17:13:50 2007 +0100 (2007-03-30)
parents 3c0d15279dc7
children a02b39eaba58
files xen/arch/x86/hvm/svm/svm.c
line diff
     1.1 --- a/xen/arch/x86/hvm/svm/svm.c	Fri Mar 30 17:02:46 2007 +0100
     1.2 +++ b/xen/arch/x86/hvm/svm/svm.c	Fri Mar 30 17:13:50 2007 +0100
     1.3 @@ -1866,11 +1866,13 @@ static int svm_cr_access(struct vcpu *v,
     1.4  {
     1.5      struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
     1.6      int inst_len = 0;
     1.7 -    int index;
     1.8 -    unsigned int gpreg;
     1.9 -    unsigned long value;
    1.10 +    int index,addr_size,i;
    1.11 +    unsigned int gpreg,offset;
    1.12 +    unsigned long value,addr;
    1.13      u8 buffer[MAX_INST_LEN];   
    1.14      u8 prefix = 0;
    1.15 +    u8 modrm;
    1.16 +    enum x86_segment seg;
    1.17      int result = 1;
    1.18      enum instruction_index list_a[] = {INSTR_MOV2CR, INSTR_CLTS, INSTR_LMSW};
    1.19      enum instruction_index list_b[] = {INSTR_MOVCR2, INSTR_SMSW};
    1.20 @@ -1931,9 +1933,59 @@ static int svm_cr_access(struct vcpu *v,
    1.21          break;
    1.22  
    1.23      case INSTR_SMSW:
    1.24 -        value = v->arch.hvm_svm.cpu_shadow_cr0;
    1.25 -        gpreg = decode_src_reg(prefix, buffer[index+2]);
    1.26 -        set_reg(gpreg, value, regs, vmcb);
    1.27 +        value = v->arch.hvm_svm.cpu_shadow_cr0 & 0xFFFF;
    1.28 +        modrm = buffer[index+2];
    1.29 +        addr_size = svm_guest_x86_mode( v );
    1.30 +        if ( likely((modrm & 0xC0) >> 6 == 3) )
    1.31 +        {
    1.32 +            gpreg = decode_src_reg(prefix, modrm);
    1.33 +            set_reg(gpreg, value, regs, vmcb);
    1.34 +        }
    1.35 +        /*
    1.36 +         * For now, only implement decode of the offset mode, since that's the
    1.37 +         * only mode observed in a real-world OS. This code is also making the
    1.38 +         * assumption that we'll never hit this code in long mode.
    1.39 +         */
    1.40 +        else if ( (modrm == 0x26) || (modrm == 0x25) )
    1.41 +        {   
    1.42 +            seg = x86_seg_ds;
    1.43 +            i = index;
    1.44 +            /* Segment or address size overrides? */
    1.45 +            while ( i-- )
    1.46 +            {
    1.47 +                switch ( buffer[i] )
    1.48 +                {
    1.49 +                   case 0x26: seg = x86_seg_es; break;
    1.50 +                   case 0x2e: seg = x86_seg_cs; break;
    1.51 +                   case 0x36: seg = x86_seg_ss; break;
    1.52 +                   case 0x64: seg = x86_seg_fs; break;
    1.53 +                   case 0x65: seg = x86_seg_gs; break;
    1.54 +                   case 0x67: addr_size ^= 6;   break;
    1.55 +                }
    1.56 +            }
    1.57 +            /* Bail unless this really is a seg_base + offset case */
    1.58 +            if ( ((modrm == 0x26) && (addr_size == 4)) ||
    1.59 +                 ((modrm == 0x25) && (addr_size == 2)) )
    1.60 +            {
    1.61 +                gdprintk(XENLOG_ERR, "SMSW emulation at guest address: "
    1.62 +                         "%lx failed due to unhandled addressing mode."
    1.63 +                         "ModRM byte was: %x \n", svm_rip2pointer(v), modrm);
    1.64 +                domain_crash(v->domain);
    1.65 +            }
    1.66 +            inst_len += addr_size;
    1.67 +            offset = *(( unsigned int *) ( void *) &buffer[index + 3]);
    1.68 +            offset = ( addr_size == 4 ) ? offset : ( offset & 0xFFFF );
    1.69 +            addr = hvm_get_segment_base(v, seg);
    1.70 +            addr += offset;
    1.71 +            hvm_copy_to_guest_virt(addr,&value,2);
    1.72 +        }
    1.73 +        else
    1.74 +        {
    1.75 +           gdprintk(XENLOG_ERR, "SMSW emulation at guest address: %lx "
    1.76 +                    "failed due to unhandled addressing mode!"
    1.77 +                    "ModRM byte was: %x \n", svm_rip2pointer(v), modrm);
    1.78 +           domain_crash(v->domain);
    1.79 +        }
    1.80          break;
    1.81  
    1.82      default: