[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH] vmxassist-syslinux.patch
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 045bee6e1ebd tools/examples/xmexample.hvm --- a/tools/examples/xmexample.hvm Tue Mar 21 11:26:38 2006 +++ b/tools/examples/xmexample.hvm Tue Mar 21 10:22:35 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 045bee6e1ebd tools/firmware/vmxassist/machine.h --- a/tools/firmware/vmxassist/machine.h Tue Mar 21 11:26:38 2006 +++ b/tools/firmware/vmxassist/machine.h Tue Mar 21 10:22:35 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 045bee6e1ebd tools/firmware/vmxassist/util.c --- a/tools/firmware/vmxassist/util.c Tue Mar 21 11:26:38 2006 +++ b/tools/firmware/vmxassist/util.c Tue Mar 21 10:22:35 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 045bee6e1ebd tools/firmware/vmxassist/vm86.c --- a/tools/firmware/vmxassist/vm86.c Tue Mar 21 11:26:38 2006 +++ b/tools/firmware/vmxassist/vm86.c Tue Mar 21 10:22:35 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-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |