ia64/xen-unstable

changeset 5180:da69cdf7fef2

bitkeeper revision 1.1571 (4296dbdcx0p8kMuQ9I0m0bHZ7K1BuQ)

[PATCH] [PATCH] More accurate address decoding for VMX string

This patch includes two patches. The major patch is the improved address
decoding for ins/outs instructions. In the previous version, segment
overrides were ignored which caused a lot of problems for parts of the
ROMBIOS code where they are used heavily. Address decoding has been
made slightly easier now that GUEST_LINEAR_ADDRESS is documented. We
still need to work around a bug in the current stepping and make sure
that in protected mode the selector is not null.

The second patch removes the ASSERT(cr3). cr3==0 is a perfectly legal
value and Xen should not crash when its read.

Signed-Off-By: Leendert van Doorn <leendert@watson.ibm.com>
author leendert@watson.ibm.com[kaf24]
date Fri May 27 08:35:40 2005 +0000 (2005-05-27)
parents 5fa5698914c1
children 3487ddf5b689
files xen/arch/x86/vmx.c
line diff
     1.1 --- a/xen/arch/x86/vmx.c	Fri May 27 08:35:25 2005 +0000
     1.2 +++ b/xen/arch/x86/vmx.c	Fri May 27 08:35:40 2005 +0000
     1.3 @@ -318,6 +318,55 @@ static void vmx_vmexit_do_invlpg(unsigne
     1.4      shadow_invlpg(ed, va);
     1.5  }
     1.6  
     1.7 +static int check_for_null_selector(unsigned long eip)
     1.8 +{
     1.9 +    unsigned char inst[MAX_INST_LEN];
    1.10 +    unsigned long sel;
    1.11 +    int i, inst_len;
    1.12 +    int inst_copy_from_guest(unsigned char *, unsigned long, int);
    1.13 +
    1.14 +    __vmread(INSTRUCTION_LEN, &inst_len);
    1.15 +    memset(inst, 0, MAX_INST_LEN);
    1.16 +    if (inst_copy_from_guest(inst, eip, inst_len) != inst_len) {
    1.17 +        printf("check_for_null_selector: get guest instruction failed\n");
    1.18 +        domain_crash_synchronous();
    1.19 +    }
    1.20 +
    1.21 +    for (i = 0; i < inst_len; i++) {
    1.22 +        switch (inst[i]) {
    1.23 +        case 0xf3: /* REPZ */
    1.24 +        case 0xf2: /* REPNZ */
    1.25 +        case 0xf0: /* LOCK */
    1.26 +        case 0x66: /* data32 */
    1.27 +        case 0x67: /* addr32 */
    1.28 +            continue;
    1.29 +        case 0x2e: /* CS */
    1.30 +            __vmread(GUEST_CS_SELECTOR, &sel);
    1.31 +            break;
    1.32 +        case 0x36: /* SS */
    1.33 +            __vmread(GUEST_SS_SELECTOR, &sel);
    1.34 +            break;
    1.35 +        case 0x26: /* ES */
    1.36 +            __vmread(GUEST_ES_SELECTOR, &sel);
    1.37 +            break;
    1.38 +        case 0x64: /* FS */
    1.39 +            __vmread(GUEST_FS_SELECTOR, &sel);
    1.40 +            break;
    1.41 +        case 0x65: /* GS */
    1.42 +            __vmread(GUEST_GS_SELECTOR, &sel);
    1.43 +            break;
    1.44 +        case 0x3e: /* DS */
    1.45 +            /* FALLTHROUGH */
    1.46 +        default:
    1.47 +            /* DS is the default */
    1.48 +            __vmread(GUEST_DS_SELECTOR, &sel);
    1.49 +        }
    1.50 +        return sel == 0 ? 1 : 0;
    1.51 +    }
    1.52 +
    1.53 +    return 0;
    1.54 +}
    1.55 +
    1.56  static void vmx_io_instruction(struct cpu_user_regs *regs, 
    1.57                     unsigned long exit_qualification, unsigned long inst_len) 
    1.58  {
    1.59 @@ -354,40 +403,44 @@ static void vmx_io_instruction(struct cp
    1.60          domain_crash_synchronous(); 
    1.61      }
    1.62      p = &vio->vp_ioreq;
    1.63 -    p->dir = test_bit(3, &exit_qualification);  
    1.64 +    p->dir = test_bit(3, &exit_qualification); /* direction */
    1.65  
    1.66      p->pdata_valid = 0;
    1.67      p->count = 1;
    1.68      p->size = (exit_qualification & 7) + 1;
    1.69  
    1.70 -    if (test_bit(4, &exit_qualification)) {
    1.71 -        p->df = (eflags & X86_EFLAGS_DF) ? 1 : 0;
    1.72 -        p->pdata_valid = 1;
    1.73 +    if (test_bit(4, &exit_qualification)) { /* string instruction */
    1.74 +	unsigned long laddr;
    1.75  
    1.76 -        if (vm86) {
    1.77 -            unsigned long seg;
    1.78 -            if (p->dir == IOREQ_WRITE) {
    1.79 -                __vmread(GUEST_DS_SELECTOR, &seg);
    1.80 -                p->u.pdata = (void *)
    1.81 -                        ((seg << 4) + (regs->esi & 0xFFFF));
    1.82 -            } else {
    1.83 -                __vmread(GUEST_ES_SELECTOR, &seg);
    1.84 -                p->u.pdata = (void *)
    1.85 -                        ((seg << 4) + (regs->edi & 0xFFFF));
    1.86 -            }
    1.87 -        } else {
    1.88 -               p->u.pdata = (void *) ((p->dir == IOREQ_WRITE) ?
    1.89 -                   regs->esi : regs->edi);
    1.90 +	__vmread(GUEST_LINEAR_ADDRESS, &laddr);
    1.91 +        /*
    1.92 +         * In protected mode, guest linear address is invalid if the
    1.93 +         * selector is null.
    1.94 +         */
    1.95 +        if (!vm86 && check_for_null_selector(eip)) {
    1.96 +            printf("String I/O with null selector (cs:eip=0x%lx:0x%lx)\n",
    1.97 +                cs, eip);
    1.98 +            laddr = (p->dir == IOREQ_WRITE) ? regs->esi : regs->edi;
    1.99          }
   1.100 -        p->u.pdata = (void *) gva_to_gpa(p->u.data);
   1.101 +        p->pdata_valid = 1;
   1.102 +        p->u.pdata = (void *) gva_to_gpa(laddr);
   1.103 +        p->df = (eflags & X86_EFLAGS_DF) ? 1 : 0;
   1.104  
   1.105 -        if (test_bit(5, &exit_qualification))
   1.106 +        if (test_bit(5, &exit_qualification)) /* "rep" prefix */
   1.107  	    p->count = vm86 ? regs->ecx & 0xFFFF : regs->ecx;
   1.108 +
   1.109 +        /*
   1.110 +         * Split up string I/O operations that cross page boundaries. Don't
   1.111 +         * advance %eip so that "rep insb" will restart at the next page.
   1.112 +         */
   1.113          if ((p->u.data & PAGE_MASK) != 
   1.114 -            ((p->u.data + p->count * p->size - 1) & PAGE_MASK)) {
   1.115 -            printk("stringio crosses page boundary!\n");
   1.116 +		((p->u.data + p->count * p->size - 1) & PAGE_MASK)) {
   1.117 +	    VMX_DBG_LOG(DBG_LEVEL_2,
   1.118 +		"String I/O crosses page boundary (cs:eip=0x%lx:0x%lx)\n",
   1.119 +		cs, eip);
   1.120              if (p->u.data & (p->size - 1)) {
   1.121 -                printk("Not aligned I/O!\n");
   1.122 +		printf("Unaligned string I/O operation (cs:eip=0x%lx:0x%lx)\n",
   1.123 +			cs, eip);
   1.124                  domain_crash_synchronous();     
   1.125              }
   1.126              p->count = (PAGE_SIZE - (p->u.data & ~PAGE_MASK)) / p->size;
   1.127 @@ -885,7 +938,6 @@ static void mov_from_cr(int cr, int gp, 
   1.128          __vmx_bug(regs);
   1.129  
   1.130      value = (unsigned long) d->arch.arch_vmx.cpu_cr3;
   1.131 -    ASSERT(value);
   1.132  
   1.133      switch (gp) {
   1.134          CASE_SET_REG(EAX, eax);