ia64/xen-unstable

changeset 10080:632ad28f2fd7

SVM patch to cleanup IOIO handling, do not use "real" mode but rather
the correct "bitness".

Signed-off-by: Tom Woller <thomas.woller@amd.com>
Signed-off-by: Mats Petersson <mats.petersson@amd.com>
author kaf24@firebug.cl.cam.ac.uk
date Wed May 17 23:50:23 2006 +0100 (2006-05-17)
parents 81ab21f76a6f
children 3d85f350a66a
files xen/arch/x86/hvm/svm/svm.c
line diff
     1.1 --- a/xen/arch/x86/hvm/svm/svm.c	Wed May 17 23:47:19 2006 +0100
     1.2 +++ b/xen/arch/x86/hvm/svm/svm.c	Wed May 17 23:50:23 2006 +0100
     1.3 @@ -1118,19 +1118,17 @@ static void svm_dr_access (struct vcpu *
     1.4  }
     1.5  
     1.6  
     1.7 -static unsigned int check_for_null_selector(struct vmcb_struct *vmcb, 
     1.8 -        unsigned int dir, unsigned long *base, unsigned int real)
     1.9 -
    1.10 +static void svm_get_prefix_info(struct vmcb_struct *vmcb, 
    1.11 +		unsigned int dir, segment_selector_t **seg, unsigned int *asize)
    1.12  {
    1.13      unsigned char inst[MAX_INST_LEN];
    1.14 -    segment_selector_t seg;
    1.15      int i;
    1.16  
    1.17      memset(inst, 0, MAX_INST_LEN);
    1.18      if (inst_copy_from_guest(inst, svm_rip2pointer(vmcb), sizeof(inst)) 
    1.19              != MAX_INST_LEN) 
    1.20      {
    1.21 -        printk("check_for_null_selector: get guest instruction failed\n");
    1.22 +        printk("%s: get guest instruction failed\n", __func__);
    1.23          domain_crash_synchronous();
    1.24      }
    1.25  
    1.26 @@ -1142,7 +1140,6 @@ static unsigned int check_for_null_selec
    1.27          case 0xf2: /* REPNZ */
    1.28          case 0xf0: /* LOCK */
    1.29          case 0x66: /* data32 */
    1.30 -        case 0x67: /* addr32 */
    1.31  #if __x86_64__
    1.32              /* REX prefixes */
    1.33          case 0x40:
    1.34 @@ -1164,79 +1161,127 @@ static unsigned int check_for_null_selec
    1.35          case 0x4f:
    1.36  #endif
    1.37              continue;
    1.38 +        case 0x67: /* addr32 */
    1.39 +            *asize ^= 48;        /* Switch 16/32 bits */
    1.40 +            continue;
    1.41          case 0x2e: /* CS */
    1.42 -            seg = vmcb->cs;
    1.43 -            break;
    1.44 +            *seg = &vmcb->cs;
    1.45 +            continue;
    1.46          case 0x36: /* SS */
    1.47 -            seg = vmcb->ss;
    1.48 -            break;
    1.49 +            *seg = &vmcb->ss;
    1.50 +            continue;
    1.51          case 0x26: /* ES */
    1.52 -            seg = vmcb->es;
    1.53 -            break;
    1.54 +            *seg = &vmcb->es;
    1.55 +            continue;
    1.56          case 0x64: /* FS */
    1.57 -            seg = vmcb->fs;
    1.58 -            break;
    1.59 +            *seg = &vmcb->fs;
    1.60 +            continue;
    1.61          case 0x65: /* GS */
    1.62 -            seg = vmcb->gs;
    1.63 -            break;
    1.64 +            *seg = &vmcb->gs;
    1.65 +            continue;
    1.66          case 0x3e: /* DS */
    1.67 -            /* FALLTHROUGH */
    1.68 -            seg = vmcb->ds;
    1.69 -            break;
    1.70 +            *seg = &vmcb->ds;
    1.71 +            continue;
    1.72          default:
    1.73 -            if (dir == IOREQ_READ) /* IN/INS instruction? */
    1.74 -                seg = vmcb->es;
    1.75 -            else
    1.76 -                seg = vmcb->ds;
    1.77 +            break;
    1.78          }
    1.79 -        
    1.80 -        if (base)
    1.81 -            *base = seg.base;
    1.82 -
    1.83 -        return seg.attributes.fields.p;
    1.84 +        return;
    1.85      }
    1.86 -
    1.87 -    ASSERT(0);
    1.88 -    return 0;
    1.89  }
    1.90  
    1.91  
    1.92  /* Get the address of INS/OUTS instruction */
    1.93 -static inline unsigned long svm_get_io_address(struct vmcb_struct *vmcb, 
    1.94 -        struct cpu_user_regs *regs, unsigned int dir, unsigned int real)
    1.95 +static inline int svm_get_io_address(struct vmcb_struct *vmcb, 
    1.96 +		struct cpu_user_regs *regs, unsigned int dir, 
    1.97 +        unsigned long *count, unsigned long *addr)
    1.98  {
    1.99 -    unsigned long addr = 0;
   1.100 -    unsigned long base = 0;
   1.101 -
   1.102 -    check_for_null_selector(vmcb, dir, &base, real);
   1.103 +    unsigned long        reg;
   1.104 +    unsigned int         asize = 0;
   1.105 +    unsigned int         isize;
   1.106 +    int                  long_mode;
   1.107 +    ioio_info_t          info;
   1.108 +    segment_selector_t  *seg = NULL;
   1.109 +
   1.110 +    info.bytes = vmcb->exitinfo1;
   1.111 +
   1.112 +    /* If we're in long mode, we shouldn't check the segment presence and limit */
   1.113 +    long_mode = vmcb->cs.attributes.fields.l && vmcb->efer & EFER_LMA;
   1.114 +
   1.115 +    /* d field of cs.attributes is 1 for 32-bit, 0 for 16 or 64 bit. 
   1.116 +     * l field combined with EFER_LMA -> longmode says whether it's 16 or 64 bit. 
   1.117 +     */
   1.118 +    asize = (long_mode)?64:((vmcb->cs.attributes.fields.db)?32:16);
   1.119 +
   1.120 +
   1.121 +    /* The ins/outs instructions are single byte, so if we have got more 
   1.122 +     * than one byte (+ maybe rep-prefix), we have some prefix so we need 
   1.123 +     * to figure out what it is...
   1.124 +     */
   1.125 +    isize = vmcb->exitinfo2 - vmcb->rip;
   1.126 +
   1.127 +    if (info.fields.rep)
   1.128 +        isize --;
   1.129 +
   1.130 +    if (isize > 1) 
   1.131 +    {
   1.132 +        svm_get_prefix_info(vmcb, dir, &seg, &asize);
   1.133 +    }
   1.134 +
   1.135 +    ASSERT(dir == IOREQ_READ || dir == IOREQ_WRITE);
   1.136  
   1.137      if (dir == IOREQ_WRITE)
   1.138      {
   1.139 -        if (real)
   1.140 -            addr = (regs->esi & 0xFFFF) + base;
   1.141 -        else
   1.142 -            addr = regs->esi + base;
   1.143 +        reg = regs->esi;
   1.144 +        if (!seg)               /* If no prefix, used DS. */
   1.145 +            seg = &vmcb->ds;
   1.146      }
   1.147      else
   1.148      {
   1.149 -        if (real)
   1.150 -            addr = (regs->edi & 0xFFFF) + base;
   1.151 -        else
   1.152 -            addr = regs->edi + base;
   1.153 +        reg = regs->edi;
   1.154 +        seg = &vmcb->es;        /* Note: This is ALWAYS ES. */
   1.155      }
   1.156  
   1.157 -    return addr;
   1.158 +    /* If the segment isn't present, give GP fault! */
   1.159 +    if (!long_mode && !seg->attributes.fields.p) 
   1.160 +    {
   1.161 +        svm_inject_exception(vmcb, TRAP_gp_fault, 1, seg->sel);
   1.162 +        return 0;
   1.163 +    }
   1.164 +
   1.165 +    if (asize == 16) 
   1.166 +    {
   1.167 +        *addr = (reg & 0xFFFF);
   1.168 +        *count = regs->ecx & 0xffff;
   1.169 +    }
   1.170 +    else
   1.171 +    {
   1.172 +        *addr = reg;
   1.173 +        *count = regs->ecx;
   1.174 +    }
   1.175 +
   1.176 +    if (!long_mode) {
   1.177 +        if (*addr > seg->limit) 
   1.178 +        {
   1.179 +            svm_inject_exception(vmcb, TRAP_gp_fault, 1, seg->sel);
   1.180 +            return 0;
   1.181 +        } 
   1.182 +        else 
   1.183 +        {
   1.184 +            *addr += seg->base;
   1.185 +        }
   1.186 +    }
   1.187 +    
   1.188 +
   1.189 +    return 1;
   1.190  }
   1.191  
   1.192  
   1.193  static void svm_io_instruction(struct vcpu *v, struct cpu_user_regs *regs) 
   1.194  {
   1.195      struct mmio_op *mmio_opp;
   1.196 -    unsigned long eip, cs, eflags, cr0;
   1.197 -    unsigned long port;
   1.198 -    unsigned int real, size, dir;
   1.199 +    unsigned int port;
   1.200 +    unsigned int size, dir;
   1.201      ioio_info_t info;
   1.202 -
   1.203      struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
   1.204  
   1.205      ASSERT(vmcb);
   1.206 @@ -1244,10 +1289,6 @@ static void svm_io_instruction(struct vc
   1.207      mmio_opp->instr = INSTR_PIO;
   1.208      mmio_opp->flags = 0;
   1.209  
   1.210 -    eip = vmcb->rip;
   1.211 -    cs =  vmcb->cs.sel;
   1.212 -    eflags = vmcb->rflags;
   1.213 -
   1.214      info.bytes = vmcb->exitinfo1;
   1.215  
   1.216      port = info.fields.port; /* port used to be addr */
   1.217 @@ -1259,27 +1300,33 @@ static void svm_io_instruction(struct vc
   1.218      else 
   1.219          size = 1;
   1.220  
   1.221 -    cr0 = vmcb->cr0;
   1.222 -    real = (eflags & X86_EFLAGS_VM) || !(cr0 & X86_CR0_PE);
   1.223 -
   1.224      HVM_DBG_LOG(DBG_LEVEL_IO, 
   1.225 -                "svm_io_instruction: port 0x%lx real %d, eip=%lx:%lx, "
   1.226 +                "svm_io_instruction: port 0x%x eip=%lx:%lx, "
   1.227                  "exit_qualification = %lx",
   1.228 -                (unsigned long) port, real, cs, eip, (unsigned long)info.bytes);
   1.229 +                port, vmcb->cs.sel, vmcb->rip, (unsigned long)info.bytes);
   1.230      /* string instruction */
   1.231      if (info.fields.str)
   1.232      { 
   1.233 -        unsigned long addr, count = 1;
   1.234 +        unsigned long addr, count;
   1.235          int sign = regs->eflags & EF_DF ? -1 : 1;
   1.236  
   1.237 -        /* Need the original rip, here. */
   1.238 -        addr = svm_get_io_address(vmcb, regs, dir, real);
   1.239 +        if (!svm_get_io_address(vmcb, regs, dir, &count, &addr)) 
   1.240 +        {
   1.241 +            /* We failed to get a valid address, so don't do the IO operation - 
   1.242 +             * it would just get worse if we do! Hopefully the guest is handing
   1.243 +             * gp-faults... 
   1.244 +             */
   1.245 +            return;
   1.246 +        }
   1.247  
   1.248          /* "rep" prefix */
   1.249          if (info.fields.rep) 
   1.250          {
   1.251              mmio_opp->flags |= REPZ;
   1.252 -            count = real ? regs->ecx & 0xFFFF : regs->ecx;
   1.253 +        }
   1.254 +        else 
   1.255 +        {
   1.256 +            count = 1;
   1.257          }
   1.258  
   1.259          /*