[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] The following patch adds support to vmxassist for SYSLINUX/ISOLINUX. This



# HG changeset patch
# User kaf24@xxxxxxxxxxxxxxxxxxxx
# Node ID f9e9128420064c3b6c2e069ed4e40f6abd7413c3
# Parent  4dec7a81f8f5b279b62aede01f2b9fcad74cabd0
The following patch adds support to vmxassist for SYSLINUX/ISOLINUX. This
enables you to install SLES-10 as an unmodified guest.

Notice that at this time, vmxassist does not support the graphic bootstrap
loader (gfxboot), so be sure the set "stdvga=1" in your configuration file
to prevent gfxboot from kicking in (or hit SHIFT really fast).

Signed-Off-By: Leendert van Doorn <leendert@xxxxxxxxxxxxxx>

diff -r 4dec7a81f8f5 -r f9e912842006 tools/examples/xmexample.hvm
--- a/tools/examples/xmexample.hvm      Tue Mar 21 21:48:04 2006
+++ b/tools/examples/xmexample.hvm      Tue Mar 21 21:50:48 2006
@@ -129,6 +129,9 @@
 # no graphics, use serial port
 #nographic=0
 
+#----------------------------------------------------------------------------
+# enable stdvga, default = 0 (use cirrus logic device model)
+stdvga=0
 
 #-----------------------------------------------------------------------------
 #   serial port re-direct to pty deivce, /dev/pts/n 
diff -r 4dec7a81f8f5 -r f9e912842006 tools/firmware/vmxassist/machine.h
--- a/tools/firmware/vmxassist/machine.h        Tue Mar 21 21:48:04 2006
+++ b/tools/firmware/vmxassist/machine.h        Tue Mar 21 21:50:48 2006
@@ -37,10 +37,11 @@
 #define CR4_PVI                (1 << 1)
 #define CR4_PSE                (1 << 4)
 
+#define EFLAGS_ZF      (1 << 6)
 #define EFLAGS_TF      (1 << 8)
 #define EFLAGS_IF      (1 << 9)
 #define EFLAGS_DF      (1 << 10)
-#define EFLAGS_IOPL (3 << 12)
+#define EFLAGS_IOPL    (3 << 12)
 #define EFLAGS_VM      ((1 << 17) | EFLAGS_IOPL)
 #define EFLAGS_VIF     (1 << 19)
 #define EFLAGS_VIP     (1 << 20)
diff -r 4dec7a81f8f5 -r f9e912842006 tools/firmware/vmxassist/util.c
--- a/tools/firmware/vmxassist/util.c   Tue Mar 21 21:48:04 2006
+++ b/tools/firmware/vmxassist/util.c   Tue Mar 21 21:50:48 2006
@@ -48,7 +48,8 @@
                printf("trapno %8x errno  %8x\n", regs->trapno, regs->errno);
 
        printf("cr0    %8lx cr2    %8x cr3    %8lx cr4    %8lx\n",
-               oldctx.cr0, get_cr2(), oldctx.cr3, oldctx.cr4);
+               (long)oldctx.cr0, get_cr2(),
+               (long)oldctx.cr3, (long)oldctx.cr4);
 }
 
 #ifdef DEBUG
@@ -104,15 +105,25 @@
 }
 
 void
-dump_dtr(unsigned long base, unsigned long limit)
+dump_dtr(unsigned long addr, unsigned long size)
 {
        unsigned long long entry;
+       unsigned long base, limit;
        int i;
 
-       for (i = 0; i < limit; i += 8) {
-               entry = ((unsigned long long *) base)[i >> 3];
-               printf("[0x%x] = 0x%08x%08x\n", i,
-                       (unsigned)(entry >> 32), (unsigned)(entry));
+       for (i = 0; i < size; i += 8) {
+               entry = ((unsigned long long *) addr)[i >> 3];
+               base = (((entry >> (56-24)) & 0xFF000000) |
+                       ((entry >> (32-16)) & 0x00FF0000) |
+                       ((entry >> (   16)) & 0x0000FFFF));
+               limit = (((entry >> (48-16)) & 0x000F0000) |
+                        ((entry           ) & 0x0000FFFF));
+               if (entry & (1ULL << (23+32))) /* G */
+                       limit = (limit << 12) | 0xFFF;
+
+               printf("[0x%x] = 0x%08x%08x, base 0x%lx, limit 0x%lx\n", i,
+                       (unsigned)(entry >> 32), (unsigned)(entry),
+                       base, limit);
        }
 }
 
@@ -120,18 +131,19 @@
 dump_vmx_context(struct vmx_assist_context *c)
 {
        printf("eip 0x%lx, esp 0x%lx, eflags 0x%lx\n",
-               c->eip, c->esp, c->eflags);
-
-       printf("cr0 0x%lx, cr3 0x%lx, cr4 0x%lx\n", c->cr0, c->cr3, c->cr4);
+               (long) c->eip, (long) c->esp, (long) c->eflags);
+
+       printf("cr0 0x%lx, cr3 0x%lx, cr4 0x%lx\n",
+               (long)c->cr0, (long)c->cr3, (long)c->cr4);
 
        printf("idtr: limit 0x%lx, base 0x%lx\n",
-               c->idtr_limit, c->idtr_base);
+               (long)c->idtr_limit, (long)c->idtr_base);
 
        printf("gdtr: limit 0x%lx, base 0x%lx\n",
-               c->gdtr_limit, c->gdtr_base);
+               (long)c->gdtr_limit, (long)c->gdtr_base);
 
        printf("cs: sel 0x%lx, limit 0x%lx, base 0x%lx\n",
-               c->cs_sel, c->cs_limit, c->cs_base);
+               (long)c->cs_sel, (long)c->cs_limit, (long)c->cs_base);
        printf("\ttype %d, s %d, dpl %d, p %d, avl %d, ops %d, g %d, nul %d\n",
                c->cs_arbytes.fields.seg_type,
                c->cs_arbytes.fields.s,
@@ -143,7 +155,7 @@
                c->cs_arbytes.fields.null_bit);
 
        printf("ds: sel 0x%lx, limit 0x%lx, base 0x%lx\n",
-               c->ds_sel, c->ds_limit, c->ds_base);
+               (long)c->ds_sel, (long)c->ds_limit, (long)c->ds_base);
        printf("\ttype %d, s %d, dpl %d, p %d, avl %d, ops %d, g %d, nul %d\n",
                c->ds_arbytes.fields.seg_type,
                c->ds_arbytes.fields.s,
@@ -155,7 +167,7 @@
                c->ds_arbytes.fields.null_bit);
 
        printf("es: sel 0x%lx, limit 0x%lx, base 0x%lx\n",
-               c->es_sel, c->es_limit, c->es_base);
+               (long)c->es_sel, (long)c->es_limit, (long)c->es_base);
        printf("\ttype %d, s %d, dpl %d, p %d, avl %d, ops %d, g %d, nul %d\n",
                c->es_arbytes.fields.seg_type,
                c->es_arbytes.fields.s,
@@ -167,7 +179,7 @@
                c->es_arbytes.fields.null_bit);
 
        printf("ss: sel 0x%lx, limit 0x%lx, base 0x%lx\n",
-               c->ss_sel, c->ss_limit, c->ss_base);
+               (long)c->ss_sel, (long)c->ss_limit, (long)c->ss_base);
        printf("\ttype %d, s %d, dpl %d, p %d, avl %d, ops %d, g %d, nul %d\n",
                c->ss_arbytes.fields.seg_type,
                c->ss_arbytes.fields.s,
@@ -179,7 +191,7 @@
                c->ss_arbytes.fields.null_bit);
 
        printf("fs: sel 0x%lx, limit 0x%lx, base 0x%lx\n",
-               c->fs_sel, c->fs_limit, c->fs_base);
+               (long)c->fs_sel, (long)c->fs_limit, (long)c->fs_base);
        printf("\ttype %d, s %d, dpl %d, p %d, avl %d, ops %d, g %d, nul %d\n",
                c->fs_arbytes.fields.seg_type,
                c->fs_arbytes.fields.s,
@@ -191,7 +203,7 @@
                c->fs_arbytes.fields.null_bit);
 
        printf("gs: sel 0x%lx, limit 0x%lx, base 0x%lx\n",
-               c->gs_sel, c->gs_limit, c->gs_base);
+               (long)c->gs_sel, (long)c->gs_limit, (long)c->gs_base);
        printf("\ttype %d, s %d, dpl %d, p %d, avl %d, ops %d, g %d, nul %d\n",
                c->gs_arbytes.fields.seg_type,
                c->gs_arbytes.fields.s,
@@ -203,7 +215,7 @@
                c->gs_arbytes.fields.null_bit);
 
        printf("tr: sel 0x%lx, limit 0x%lx, base 0x%lx\n",
-               c->tr_sel, c->tr_limit, c->tr_base);
+               (long)c->tr_sel, (long)c->tr_limit, (long)c->tr_base);
        printf("\ttype %d, s %d, dpl %d, p %d, avl %d, ops %d, g %d, nul %d\n",
                c->tr_arbytes.fields.seg_type,
                c->tr_arbytes.fields.s,
@@ -215,7 +227,7 @@
                c->tr_arbytes.fields.null_bit);
 
        printf("ldtr: sel 0x%lx, limit 0x%lx, base 0x%lx\n",
-               c->ldtr_sel, c->ldtr_limit, c->ldtr_base);
+               (long)c->ldtr_sel, (long)c->ldtr_limit, (long)c->ldtr_base);
        printf("\ttype %d, s %d, dpl %d, p %d, avl %d, ops %d, g %d, nul %d\n",
                c->ldtr_arbytes.fields.seg_type,
                c->ldtr_arbytes.fields.s,
@@ -226,7 +238,8 @@
                c->ldtr_arbytes.fields.g,
                c->ldtr_arbytes.fields.null_bit);
 
-       printf("GDTR <0x%lx,0x%lx>:\n", c->gdtr_base,  c->gdtr_limit);
+       printf("GDTR <0x%lx,0x%lx>:\n",
+               (long)c->gdtr_base, (long)c->gdtr_limit);
        dump_dtr(c->gdtr_base, c->gdtr_limit);
 }
 #endif /* DEBUG */
diff -r 4dec7a81f8f5 -r f9e912842006 tools/firmware/vmxassist/vm86.c
--- a/tools/firmware/vmxassist/vm86.c   Tue Mar 21 21:48:04 2006
+++ b/tools/firmware/vmxassist/vm86.c   Tue Mar 21 21:50:48 2006
@@ -3,7 +3,7 @@
  * little work as possible. 
  *
  * Leendert van Doorn, leendert@xxxxxxxxxxxxxx
- * Copyright (c) 2005, International Business Machines Corporation.
+ * Copyright (c) 2005-2006, International Business Machines Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -35,7 +35,7 @@
 #define        SEG_GS          0x0080
 
 unsigned prev_eip = 0;
-enum vm86_mode mode;
+enum vm86_mode mode = 0;
 
 #ifdef DEBUG
 int traceset = 0;
@@ -46,8 +46,9 @@
        "<VM86_PROTECTED_TO_REAL>",
        "<VM86_PROTECTED>"
 };
+
+static char *rnames[] = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di" };
 #endif /* DEBUG */
-
 
 unsigned
 address(struct regs *regs, unsigned seg, unsigned off)
@@ -55,15 +56,11 @@
        unsigned long long entry;
        unsigned addr;
 
-       /* real mode: segment is part of the address */
-       if (mode == VM86_REAL || mode == VM86_REAL_TO_PROTECTED)
+       if (seg == 0)
+               return off;
+
+       if (seg > oldctx.gdtr_limit)
                return ((seg & 0xFFFF) << 4) + off;
-
-       /* protected mode: use seg as index into gdt */
-       if (seg > oldctx.gdtr_limit) {
-               printf("address: Invalid segment descriptor (0x%x)\n", seg);
-               return 0;
-       }
 
        entry = ((unsigned long long *) oldctx.gdtr_base)[seg >> 3];
        addr = (((entry >> (56-24)) & 0xFF000000) |
@@ -198,7 +195,7 @@
 }
 
 unsigned
-getreg(struct regs *regs, int r)
+getreg32(struct regs *regs, int r)
 {
        switch (r & 7) {
        case 0: return regs->eax;
@@ -213,8 +210,30 @@
        return ~0;
 }
 
+unsigned
+getreg16(struct regs *regs, int r)
+{
+       return MASK16(getreg32(regs, r));
+}
+
+unsigned
+getreg8(struct regs *regs, int r)
+{
+       switch (r & 7) {
+       case 0: return regs->eax & 0xFF; /* al */
+       case 1: return regs->ecx & 0xFF; /* cl */
+       case 2: return regs->edx & 0xFF; /* dl */
+       case 3: return regs->ebx & 0xFF; /* bl */
+       case 4: return (regs->esp >> 8) & 0xFF; /* ah */
+       case 5: return (regs->ebp >> 8) & 0xFF; /* ch */
+       case 6: return (regs->esi >> 8) & 0xFF; /* dh */
+       case 7: return (regs->edi >> 8) & 0xFF; /* bh */
+       }
+       return ~0;
+}
+
 void
-setreg(struct regs *regs, int r, unsigned v)
+setreg32(struct regs *regs, int r, unsigned v)
 {
        switch (r & 7) {
        case 0: regs->eax = v; break;
@@ -228,15 +247,31 @@
        }
 }
 
-/*
- * Operand (modrm) decode
- */
+void
+setreg16(struct regs *regs, int r, unsigned v)
+{
+       setreg32(regs, r, (getreg32(regs, r) & ~0xFFFF) | MASK16(v));
+}
+
+void
+setreg8(struct regs *regs, int r, unsigned v)
+{
+       v &= 0xFF;
+       switch (r & 7) {
+       case 0: regs->eax = (regs->eax & ~0xFF) | v; break;
+       case 1: regs->ecx = (regs->ecx & ~0xFF) | v; break;
+       case 2: regs->edx = (regs->edx & ~0xFF) | v; break;
+       case 3: regs->ebx = (regs->ebx & ~0xFF) | v; break;
+       case 4: regs->esp = (regs->esp & ~0xFF00) | (v << 8); break;
+       case 5: regs->ebp = (regs->ebp & ~0xFF00) | (v << 8); break;
+       case 6: regs->esi = (regs->esi & ~0xFF00) | (v << 8); break;
+       case 7: regs->edi = (regs->edi & ~0xFF00) | (v << 8); break;
+       }
+}
+
 unsigned
-operand(unsigned prefix, struct regs *regs, unsigned modrm)
-{
-       int mod, disp = 0, seg;
-
-       seg = regs->vds;
+segment(unsigned prefix, struct regs *regs, unsigned seg)
+{
        if (prefix & SEG_ES)
                seg = regs->ves;
        if (prefix & SEG_DS)
@@ -249,6 +284,47 @@
                seg = regs->fs;
        if (prefix & SEG_GS)
                seg = regs->gs;
+       return seg;
+}
+
+unsigned
+sib(struct regs *regs, int mod, unsigned byte)
+{
+       unsigned scale = (byte >> 6) & 3;
+       int index = (byte >> 3) & 7;
+       int base = byte & 7;
+       unsigned addr = 0;
+
+       switch (mod) {
+       case 0:
+               if (base == 5)
+                       addr = fetch32(regs);
+               else
+                       addr = getreg32(regs, base);
+               break;
+       case 1:
+               addr = getreg32(regs, base) + (char) fetch8(regs);
+               break;
+       case 2:
+               addr = getreg32(regs, base) + fetch32(regs);
+               break;
+       }
+
+       if (index != 4)
+               addr += getreg32(regs, index) << scale;
+
+       return addr;
+}
+
+/*
+ * Operand (modrm) decode
+ */
+unsigned
+operand(unsigned prefix, struct regs *regs, unsigned modrm)
+{
+       int mod, disp = 0, seg;
+
+       seg = segment(prefix, regs, regs->vds);
 
        if (prefix & ADDR32) { /* 32-bit addressing */
                switch ((mod = (modrm >> 6) & 3)) {
@@ -258,7 +334,8 @@
                        case 1: return address(regs, seg, regs->ecx);
                        case 2: return address(regs, seg, regs->edx);
                        case 3: return address(regs, seg, regs->ebx);
-                       case 4: panic("No SIB decode (yet)");
+                       case 4: return address(regs, seg,
+                                              sib(regs, mod, fetch8(regs)));
                        case 5: return address(regs, seg, fetch32(regs));
                        case 6: return address(regs, seg, regs->esi);
                        case 7: return address(regs, seg, regs->edi);
@@ -277,14 +354,15 @@
                        case 1: return address(regs, seg, regs->ecx + disp);
                        case 2: return address(regs, seg, regs->edx + disp);
                        case 3: return address(regs, seg, regs->ebx + disp);
-                       case 4: panic("No SIB decode (yet)");
+                       case 4: return address(regs, seg,
+                                              sib(regs, mod, fetch8(regs)));
                        case 5: return address(regs, seg, regs->ebp + disp);
                        case 6: return address(regs, seg, regs->esi + disp);
                        case 7: return address(regs, seg, regs->edi + disp);
                        }
                        break;
                case 3:
-                       return getreg(regs, modrm);
+                       return getreg32(regs, modrm);
                }
        } else { /* 16-bit addressing */
                switch ((mod = (modrm >> 6) & 3)) {
@@ -330,7 +408,7 @@
                        }
                        break;
                case 3:
-                       return MASK16(getreg(regs, modrm));
+                       return getreg16(regs, modrm);
                }
        }
 
@@ -400,6 +478,72 @@
 }
 
 /*
+ * We need to handle moves that address memory beyond the 64KB segment
+ * limit that VM8086 mode enforces.
+ */
+int
+movr(struct regs *regs, unsigned prefix, unsigned opc)
+{
+       unsigned eip = regs->eip - 1;
+       unsigned modrm = fetch8(regs);
+       unsigned addr = operand(prefix, regs, modrm);
+       unsigned val, r = (modrm >> 3) & 7;
+
+       if ((modrm & 0xC0) == 0xC0) /* no registers */
+               return 0;
+
+       switch (opc) {
+       case 0x88: /* addr32 mov r8, r/m8 */
+               val = getreg8(regs, r);
+               TRACE((regs, regs->eip - eip,
+                       "movb %%e%s, *0x%x", rnames[r], addr));
+               write8(addr, val);
+               break;
+
+       case 0x8A: /* addr32 mov r/m8, r8 */
+               TRACE((regs, regs->eip - eip,
+                       "movb *0x%x, %%%s", addr, rnames[r]));
+               setreg8(regs, r, read8(addr));
+               break;
+
+       case 0x89: /* addr32 mov r16, r/m16 */
+               val = getreg32(regs, r);
+               if (prefix & DATA32) {
+                       TRACE((regs, regs->eip - eip,
+                               "movl %%e%s, *0x%x", rnames[r], addr));
+                       write32(addr, val);
+               } else {
+                       TRACE((regs, regs->eip - eip,
+                               "movw %%%s, *0x%x", rnames[r], addr));
+                       write16(addr, MASK16(val));
+               }
+               break;
+
+       case 0x8B: /* addr32 mov r/m16, r16 */
+               if (prefix & DATA32) {
+                       TRACE((regs, regs->eip - eip,
+                               "movl *0x%x, %%e%s", addr, rnames[r]));
+                       setreg32(regs, r, read32(addr));
+               } else {
+                       TRACE((regs, regs->eip - eip,
+                               "movw *0x%x, %%%s", addr, rnames[r]));
+                       setreg16(regs, r, read16(addr));
+               }
+               break;
+
+       case 0xC6: /* addr32 movb $imm, r/m8 */
+               if ((modrm >> 3) & 7)
+                       return 0;
+               val = fetch8(regs);
+               write8(addr, val);
+               TRACE((regs, regs->eip - eip, "movb $0x%x, *0x%x",
+                                                       val, addr));
+               break;
+       }
+       return 1;
+}
+
+/*
  * Move to and from a control register.
  */
 int
@@ -418,21 +562,21 @@
                switch (cr) {
                case 0:
 #ifndef TEST
-                       setreg(regs, modrm,
+                       setreg32(regs, modrm,
                                oldctx.cr0 & ~(CR0_PE | CR0_NE));
 #else
-                       setreg(regs, modrm,
+                       setreg32(regs, modrm,
                                oldctx.cr0 & ~(CR0_PE | CR0_NE | CR0_PG));
 #endif
                        break;
                case 2:
-                       setreg(regs, modrm, get_cr2());
+                       setreg32(regs, modrm, get_cr2());
                        break;
                case 3:
-                       setreg(regs, modrm, oldctx.cr3);
+                       setreg32(regs, modrm, oldctx.cr3);
                        break;
                case 4:
-                       setreg(regs, modrm, oldctx.cr4);
+                       setreg32(regs, modrm, oldctx.cr4);
                        break;
                }
                break;
@@ -440,22 +584,135 @@
                TRACE((regs, regs->eip - eip, "movl %%eax, %%cr%d", cr));
                switch (cr) {
                case 0:
-                       oldctx.cr0 = getreg(regs, modrm) | (CR0_PE | CR0_NE);
+                       oldctx.cr0 = getreg32(regs, modrm) | (CR0_PE | CR0_NE);
 #ifdef TEST
                        oldctx.cr0 |= CR0_PG;
 #endif
-                       if (getreg(regs, modrm) & CR0_PE)
+                       if (getreg32(regs, modrm) & CR0_PE)
                                set_mode(regs, VM86_REAL_TO_PROTECTED);
-
+                       else
+                               set_mode(regs, VM86_REAL);
                        break;
                case 3:
-                       oldctx.cr3 = getreg(regs, modrm);
+                       oldctx.cr3 = getreg32(regs, modrm);
                        break;
                case 4:
-                       oldctx.cr4 = getreg(regs, modrm);
+                       oldctx.cr4 = getreg32(regs, modrm);
                        break;
                }
                break;
+       }
+
+       return 1;
+}
+
+static inline void set_eflags_ZF(unsigned mask, unsigned v1, struct regs *regs)
+{
+       if ((v1 & mask) == 0)
+               regs->eflags |= EFLAGS_ZF;
+       else
+               regs->eflags &= ~EFLAGS_ZF;
+}
+
+/*
+ * We need to handle cmp opcodes that address memory beyond the 64KB
+ * segment limit that VM8086 mode enforces.
+ */
+int
+cmp(struct regs *regs, unsigned prefix, unsigned opc)
+{
+       unsigned eip = regs->eip - 1;
+       unsigned modrm = fetch8(regs);
+       unsigned addr = operand(prefix, regs, modrm);
+       unsigned diff, val, r = (modrm >> 3) & 7;
+
+       if ((modrm & 0xC0) == 0xC0) /* no registers */
+               return 0;
+
+       switch (opc) {
+       case 0x39: /* addr32 cmp r16, r/m16 */
+               val = getreg32(regs, r);
+               if (prefix & DATA32) {
+                       diff = read32(addr) - val;
+                       set_eflags_ZF(~0, diff, regs);
+
+                       TRACE((regs, regs->eip - eip,
+                               "cmp %%e%s, *0x%x (0x%x)",
+                               rnames[r], addr, diff));
+               } else {
+                       diff = read16(addr) - val;
+                       set_eflags_ZF(0xFFFF, diff, regs);
+
+                       TRACE((regs, regs->eip - eip,
+                               "cmp %%%s, *0x%x (0x%x)",
+                               rnames[r], addr, diff));
+               }
+               break;
+
+       /* other cmp opcodes ... */
+       }
+       return 1;
+}
+
+/*
+ * We need to handle test opcodes that address memory beyond the 64KB
+ * segment limit that VM8086 mode enforces.
+ */
+int
+test(struct regs *regs, unsigned prefix, unsigned opc)
+{
+       unsigned eip = regs->eip - 1;
+       unsigned modrm = fetch8(regs);
+       unsigned addr = operand(prefix, regs, modrm);
+       unsigned val, diff;
+
+       if ((modrm & 0xC0) == 0xC0) /* no registers */
+               return 0;
+
+       switch (opc) {
+       case 0xF6: /* testb $imm, r/m8 */
+               if ((modrm >> 3) & 7)
+                       return 0;
+               val = fetch8(regs);
+               diff = read8(addr) & val;
+               set_eflags_ZF(0xFF, diff, regs);
+
+               TRACE((regs, regs->eip - eip, "testb $0x%x, *0x%x (0x%x)",
+                                                       val, addr, diff));
+               break;
+
+       /* other test opcodes ... */
+       }
+
+       return 1;
+}
+
+/*
+ * We need to handle pop opcodes that address memory beyond the 64KB
+ * segment limit that VM8086 mode enforces.
+ */
+int
+pop(struct regs *regs, unsigned prefix, unsigned opc)
+{
+       unsigned eip = regs->eip - 1;
+       unsigned modrm = fetch8(regs);
+       unsigned addr = operand(prefix, regs, modrm);
+
+       if ((modrm & 0xC0) == 0xC0) /* no registers */
+               return 0;
+
+       switch (opc) {
+       case 0x8F: /* pop r/m16 */
+               if ((modrm >> 3) & 7)
+                       return 0;
+               if (prefix & DATA32)
+                       write32(addr, pop32(regs));
+               else
+                       write16(addr, pop16(regs));
+               TRACE((regs, regs->eip - eip, "pop *0x%x", addr));
+               break;
+
+       /* other pop opcodes ... */
        }
 
        return 1;
@@ -473,17 +730,16 @@
        if (sel > oldctx.gdtr_limit)
                return 0;
 
-    if (sel == 0) {
-        arbytes->fields.null_bit = 1;
-        return 1;
-    }
+       if (sel == 0) {
+               arbytes->fields.null_bit = 1;
+               return 1;
+       }
 
        entry =  ((unsigned long long *) oldctx.gdtr_base)[sel >> 3];
 
-    /* Check the P bit fisrt*/
-    if (!((entry >> (15+32)) & 0x1) && sel != 0) {
-        return 0;
-    }
+       /* Check the P bit first */
+       if (!((entry >> (15+32)) & 0x1) && sel != 0)
+               return 0;
 
        *base =  (((entry >> (56-24)) & 0xFF000000) |
                  ((entry >> (32-16)) & 0x00FF0000) |
@@ -530,42 +786,47 @@
        if (load_seg(regs->ves, &oldctx.es_base,
                                &oldctx.es_limit, &oldctx.es_arbytes))
                oldctx.es_sel = regs->ves;
-    else {
-        load_seg(0, &oldctx.es_base,&oldctx.es_limit, &oldctx.es_arbytes);
-        oldctx.es_sel = 0;
-    }
+       else {
+               load_seg(0, &oldctx.es_base,
+                           &oldctx.es_limit, &oldctx.es_arbytes);
+               oldctx.es_sel = 0;
+       }
 
        if (load_seg(regs->uss, &oldctx.ss_base,
                                &oldctx.ss_limit, &oldctx.ss_arbytes))
                oldctx.ss_sel = regs->uss;
-    else {
-        load_seg(0, &oldctx.ss_base, &oldctx.ss_limit, &oldctx.ss_arbytes);
-        oldctx.ss_sel = 0;
-    }
+       else {
+               load_seg(0, &oldctx.ss_base,
+                           &oldctx.ss_limit, &oldctx.ss_arbytes);
+               oldctx.ss_sel = 0;
+       }
 
        if (load_seg(regs->vds, &oldctx.ds_base,
                                &oldctx.ds_limit, &oldctx.ds_arbytes))
                oldctx.ds_sel = regs->vds;
-    else {
-        load_seg(0, &oldctx.ds_base, &oldctx.ds_limit, &oldctx.ds_arbytes);
-        oldctx.ds_sel = 0;
-    }
+       else {
+               load_seg(0, &oldctx.ds_base,
+                           &oldctx.ds_limit, &oldctx.ds_arbytes);
+               oldctx.ds_sel = 0;
+       }
 
        if (load_seg(regs->vfs, &oldctx.fs_base,
                                &oldctx.fs_limit, &oldctx.fs_arbytes))
                oldctx.fs_sel = regs->vfs;
-    else {
-        load_seg(0, &oldctx.fs_base, &oldctx.fs_limit, &oldctx.fs_arbytes);
-        oldctx.fs_sel = 0;
-    }
+       else {
+               load_seg(0, &oldctx.fs_base,
+                           &oldctx.fs_limit, &oldctx.fs_arbytes);
+               oldctx.fs_sel = 0;
+       }
 
        if (load_seg(regs->vgs, &oldctx.gs_base,
                                &oldctx.gs_limit, &oldctx.gs_arbytes))
                oldctx.gs_sel = regs->vgs;
-    else {
-        load_seg(0, &oldctx.gs_base, &oldctx.gs_limit, &oldctx.gs_arbytes);
-        oldctx.gs_sel = 0;
-    }
+       else {
+               load_seg(0, &oldctx.gs_base,
+                           &oldctx.gs_limit, &oldctx.gs_arbytes);
+               oldctx.gs_sel = 0;
+       }
 
        /* initialize jump environment to warp back to protected mode */
        regs->cs = CODE_SELECTOR;
@@ -618,22 +879,24 @@
 
 /*
  * This is the smarts of the emulator and handles the mode transitions. The
- * emulator handles 4 different modes. 1) VM86_REAL: emulated real-mode, Just
- * handle those instructions that are not supported under VM8086.
- * 2) VM86_REAL_TO_PROTECTED: going from real-mode to protected mode. In this
- * we single step through the instructions until we reload the new %cs (some
- * OSes do a lot of computations before reloading %cs). 2) 
VM86_PROTECTED_TO_REAL
- * when we are going from protected to real mode. In this case we emulate the
- * instructions by hand. Finally, 4) VM86_PROTECTED when we transitioned to
- * protected mode and we should abandon the emulator. No instructions are
- * emulated when in VM86_PROTECTED mode.
+ * emulator handles 4 different modes. 1) VM86_REAL: emulated real-mode,
+ * Just handle those instructions that are not supported under VM8086.
+ * 2) VM86_REAL_TO_PROTECTED: going from real-mode to protected mode. In
+ * this we single step through the instructions until we reload the
+ * new %cs (some OSes do a lot of computations before reloading %cs). 2)
+ * VM86_PROTECTED_TO_REAL when we are going from protected to real mode. In
+ * this case we emulate the instructions by hand. Finally, 4) VM86_PROTECTED
+ * when we transitioned to protected mode and we should abandon the
+ * emulator. No instructions are emulated when in VM86_PROTECTED mode.
  */
 void
 set_mode(struct regs *regs, enum vm86_mode newmode)
 {
        switch (newmode) {
        case VM86_REAL:
-               if (mode == VM86_PROTECTED_TO_REAL) {
+               if ((mode == VM86_PROTECTED_TO_REAL) ||
+                   (mode == VM86_REAL_TO_PROTECTED)) {
+                       regs->eflags &= ~EFLAGS_TF;
                        real_mode(regs);
                        break;
                } else if (mode == VM86_REAL) {
@@ -653,10 +916,11 @@
                break;
 
        case VM86_PROTECTED_TO_REAL:
-               if (mode == VM86_PROTECTED)
-                       break;
-               else
+               if (mode == VM86_PROTECTED) {
+                       break;
+               } else
                        panic("unexpected protected-to-real mode transition");
+               break;
 
        case VM86_PROTECTED:
                if (mode == VM86_REAL_TO_PROTECTED) {
@@ -887,6 +1151,16 @@
                        prefix |= SEG_SS;
                        continue;
 
+               case 0x39: /* addr32 cmp r16, r/m16 */
+               case 0x3B: /* addr32 cmp r/m16, r16 */
+                       if (mode != VM86_REAL && mode != VM86_REAL_TO_PROTECTED)
+                               goto invalid;
+                        if ((prefix & ADDR32) == 0)
+                                goto invalid;
+                        if (!cmp(regs, prefix, opc))
+                                goto invalid;
+                        return OPC_EMULATED;
+
                case 0x3E:
                        TRACE((regs, regs->eip - eip, "%%ds:"));
                        prefix |= SEG_DS;
@@ -911,6 +1185,33 @@
                        TRACE((regs, regs->eip - eip, "addr32"));
                        prefix |= ADDR32;
                        continue;
+
+               case 0x88: /* addr32 mov r8, r/m8 */
+               case 0x8A: /* addr32 mov r/m8, r8 */
+                       if (mode != VM86_REAL && mode != VM86_REAL_TO_PROTECTED)
+                               goto invalid;
+                        if ((prefix & ADDR32) == 0)
+                                goto invalid;
+                        if (!movr(regs, prefix, opc))
+                                goto invalid;
+                        return OPC_EMULATED;
+
+               case 0x89: /* addr32 mov r16, r/m16 */
+               case 0x8B: /* addr32 mov r/m16, r16 */
+                       if (mode != VM86_REAL && mode != VM86_REAL_TO_PROTECTED)
+                               goto invalid;
+                        if ((prefix & ADDR32) == 0)
+                                goto invalid;
+                        if (!movr(regs, prefix, opc))
+                                goto invalid;
+                        return OPC_EMULATED;
+
+               case 0x8F: /* addr32 pop r/m16 */
+                        if ((prefix & ADDR32) == 0)
+                                goto invalid;
+                        if (!pop(regs, prefix, opc))
+                                goto invalid;
+                        return OPC_EMULATED;
 
                case 0x90: /* nop */
                        TRACE((regs, regs->eip - eip, "nop"));
@@ -924,7 +1225,7 @@
                                push16(regs, regs->eflags & ~EFLAGS_VM);
                        return OPC_EMULATED;
 
-               case 0x9D:      /* popf */
+               case 0x9D: /* popf */
                        TRACE((regs, regs->eip - eip, "popf"));
                        if (prefix & DATA32)
                                regs->eflags = pop32(regs);
@@ -934,7 +1235,14 @@
                        regs->eflags |= EFLAGS_VM;
                        return OPC_EMULATED;
 
-               case 0xCB:      /* retl */
+               case 0xC6: /* addr32 movb $imm, r/m8 */
+                        if ((prefix & ADDR32) == 0)
+                                goto invalid;
+                        if (!movr(regs, prefix, opc))
+                                goto invalid;
+                       return OPC_EMULATED;
+
+               case 0xCB: /* retl */
                        if ((mode == VM86_REAL_TO_PROTECTED) ||
                            (mode == VM86_PROTECTED_TO_REAL)) {
                                retl(regs, prefix);
@@ -942,12 +1250,12 @@
                        }
                        goto invalid;
 
-               case 0xCD:      /* int $n */
+               case 0xCD: /* int $n */
                        TRACE((regs, regs->eip - eip, "int"));
                        interrupt(regs, fetch8(regs));
                        return OPC_EMULATED;
 
-               case 0xCF:      /* iret */
+               case 0xCF: /* iret */
                        if (prefix & DATA32) {
                                TRACE((regs, regs->eip - eip, "data32 iretd"));
                                regs->eip = pop32(regs);
@@ -962,17 +1270,17 @@
                        }
                        return OPC_EMULATED;
 
-               case 0xE4:      /* inb al, port */
+               case 0xE4: /* inb al, port */
                        if (!inbyte(regs, prefix, opc))
                                goto invalid;
                        return OPC_EMULATED;
 
-               case 0xE6:      /* outb port, al */
+               case 0xE6: /* outb port, al */
                        if (!outbyte(regs, prefix, opc))
                                goto invalid;
                        return OPC_EMULATED;
 
-               case 0xEA:      /* jmpl */
+               case 0xEA: /* jmpl */
                        if ((mode == VM86_REAL_TO_PROTECTED) ||
                            (mode == VM86_PROTECTED_TO_REAL)) {
                                jmpl(regs, prefix);
@@ -980,7 +1288,7 @@
                        }
                        goto invalid;
 
-               case 0xEB:      /* short jump */
+               case 0xEB: /* short jump */
                        if ((mode == VM86_REAL_TO_PROTECTED) ||
                            (mode == VM86_PROTECTED_TO_REAL)) {
                                disp = (char) fetch8(regs);
@@ -990,26 +1298,33 @@
                        }
                        goto invalid;
 
-               case 0xEC:      /* inb al, (%dx) */
+               case 0xEC: /* inb al, (%dx) */
                        if (!inbyte(regs, prefix, opc))
                                goto invalid;
                        return OPC_EMULATED;
 
-               case 0xEE:      /* outb (%dx), al */
+               case 0xEE: /* outb (%dx), al */
                        if (!outbyte(regs, prefix, opc))
                                goto invalid;
                        return OPC_EMULATED;
 
-               case 0xF0:      /* lock */
+               case 0xF0: /* lock */
                        TRACE((regs, regs->eip - eip, "lock"));
                        continue;
 
-               case 0xFA:      /* cli */
+               case 0xF6: /* addr32 testb $imm, r/m8 */
+                        if ((prefix & ADDR32) == 0)
+                                goto invalid;
+                        if (!test(regs, prefix, opc))
+                                goto invalid;
+                       return OPC_EMULATED;
+
+               case 0xFA: /* cli */
                        TRACE((regs, regs->eip - eip, "cli"));
                        regs->eflags &= ~EFLAGS_IF;
                        return OPC_EMULATED;
 
-               case 0xFB:      /* sti */
+               case 0xFB: /* sti */
                        TRACE((regs, regs->eip - eip, "sti"));
                        regs->eflags |= EFLAGS_IF;
                        return OPC_EMULATED;
@@ -1021,6 +1336,7 @@
 
 invalid:
        regs->eip = eip;
+       TRACE((regs, regs->eip - eip, "opc 0x%x", opc));
        return OPC_INVALID;
 }
 
@@ -1087,4 +1403,3 @@
                halt();
        }
 }
-

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.