📄 vm86.c
字号:
/* * vm86.c: A vm86 emulator. The main purpose of this emulator is to do as * little work as possible. * * Leendert van Doorn, leendert@watson.ibm.com * 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, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place - Suite 330, Boston, MA 02111-1307 USA. */#include "vm86.h"#include "util.h"#include "machine.h"#define HIGHMEM (1 << 20) /* 1MB */#define MASK16(v) ((v) & 0xFFFF)#define DATA32 0x0001#define ADDR32 0x0002#define SEG_CS 0x0004#define SEG_DS 0x0008#define SEG_ES 0x0010#define SEG_SS 0x0020#define SEG_FS 0x0040#define SEG_GS 0x0080#define REP 0x0100static unsigned prev_eip = 0;enum vm86_mode mode = 0;static struct regs saved_rm_regs;#ifdef DEBUGint traceset = 0;char *states[] = { "<VM86_REAL>", "<VM86_REAL_TO_PROTECTED>", "<VM86_PROTECTED_TO_REAL>", "<VM86_PROTECTED>"};static char *rnames[] = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di" };#endif /* DEBUG */#define PDE_PS (1 << 7)#define PT_ENTRY_PRESENT 0x1/* We only support access to <=4G physical memory due to 1:1 mapping */static uint64_tguest_linear_to_phys(uint32_t base){ uint32_t gcr3 = oldctx.cr3; uint64_t l2_mfn; uint64_t l1_mfn; uint64_t l0_mfn; if (!(oldctx.cr0 & CR0_PG)) return base; if (!(oldctx.cr4 & CR4_PAE)) { l1_mfn = ((uint32_t *)(long)gcr3)[(base >> 22) & 0x3ff]; if (!(l1_mfn & PT_ENTRY_PRESENT)) panic("l2 entry not present\n"); if ((oldctx.cr4 & CR4_PSE) && (l1_mfn & PDE_PS)) { l0_mfn = l1_mfn & 0xffc00000; return l0_mfn + (base & 0x3fffff); } l1_mfn &= 0xfffff000; l0_mfn = ((uint32_t *)(long)l1_mfn)[(base >> 12) & 0x3ff]; if (!(l0_mfn & PT_ENTRY_PRESENT)) panic("l1 entry not present\n"); l0_mfn &= 0xfffff000; return l0_mfn + (base & 0xfff); } else { l2_mfn = ((uint64_t *)(long)gcr3)[(base >> 30) & 0x3]; if (!(l2_mfn & PT_ENTRY_PRESENT)) panic("l3 entry not present\n"); l2_mfn &= 0xffffff000ULL; if (l2_mfn & 0xf00000000ULL) { printf("l2 page above 4G\n"); cpuid_addr_value(l2_mfn + 8 * ((base >> 21) & 0x1ff), &l1_mfn); } else l1_mfn = ((uint64_t *)(long)l2_mfn)[(base >> 21) & 0x1ff]; if (!(l1_mfn & PT_ENTRY_PRESENT)) panic("l2 entry not present\n"); if (l1_mfn & PDE_PS) { /* CR4.PSE is ignored in PAE mode */ l0_mfn = l1_mfn & 0xfffe00000ULL; return l0_mfn + (base & 0x1fffff); } l1_mfn &= 0xffffff000ULL; if (l1_mfn & 0xf00000000ULL) { printf("l1 page above 4G\n"); cpuid_addr_value(l1_mfn + 8 * ((base >> 12) & 0x1ff), &l0_mfn); } else l0_mfn = ((uint64_t *)(long)l1_mfn)[(base >> 12) & 0x1ff]; if (!(l0_mfn & PT_ENTRY_PRESENT)) panic("l1 entry not present\n"); l0_mfn &= 0xffffff000ULL; return l0_mfn + (base & 0xfff); }}static unsignedaddress(struct regs *regs, unsigned seg, unsigned off){ uint64_t gdt_phys_base; unsigned long long entry; unsigned seg_base, seg_limit; unsigned entry_low, entry_high; if (seg == 0) { if (mode == VM86_REAL || mode == VM86_REAL_TO_PROTECTED) return off; else panic("segment is zero, but not in real mode!\n"); } if (mode == VM86_REAL || seg > oldctx.gdtr_limit || (mode == VM86_REAL_TO_PROTECTED && regs->cs == seg)) return ((seg & 0xFFFF) << 4) + off; gdt_phys_base = guest_linear_to_phys(oldctx.gdtr_base); if (gdt_phys_base != (uint32_t)gdt_phys_base) { printf("gdt base address above 4G\n"); cpuid_addr_value(gdt_phys_base + 8 * (seg >> 3), &entry); } else entry = ((unsigned long long *)(long)gdt_phys_base)[seg >> 3]; entry_high = entry >> 32; entry_low = entry & 0xFFFFFFFF; seg_base = (entry_high & 0xFF000000) | ((entry >> 16) & 0xFFFFFF); seg_limit = (entry_high & 0xF0000) | (entry_low & 0xFFFF); if (entry_high & 0x8000 && ((entry_high & 0x800000 && off >> 12 <= seg_limit) || (!(entry_high & 0x800000) && off <= seg_limit))) return seg_base + off; panic("should never reach here in function address():\n\t" "entry=0x%08x%08x, mode=%d, seg=0x%08x, offset=0x%08x\n", entry_high, entry_low, mode, seg, off); return 0;}#ifdef DEBUGvoidtrace(struct regs *regs, int adjust, char *fmt, ...){ unsigned off = regs->eip - adjust; va_list ap; if ((traceset & (1 << mode)) && (mode == VM86_REAL_TO_PROTECTED || mode == VM86_REAL)) { /* 16-bit, seg:off addressing */ unsigned addr = address(regs, regs->cs, off); printf("0x%08x: 0x%x:0x%04x ", addr, regs->cs, off); printf("(%d) ", mode); va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); printf("\n"); } if ((traceset & (1 << mode)) && (mode == VM86_PROTECTED_TO_REAL || mode == VM86_PROTECTED)) { /* 16-bit, gdt addressing */ unsigned addr = address(regs, regs->cs, off); printf("0x%08x: 0x%x:0x%08x ", addr, regs->cs, off); printf("(%d) ", mode); va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); printf("\n"); }}#endif /* DEBUG */static inline unsignedread32(unsigned addr){ return *(unsigned long *) addr;}static inline unsignedread16(unsigned addr){ return *(unsigned short *) addr;}static inline unsignedread8(unsigned addr){ return *(unsigned char *) addr;}static inline voidwrite32(unsigned addr, unsigned value){ *(unsigned long *) addr = value;}static inline voidwrite16(unsigned addr, unsigned value){ *(unsigned short *) addr = value;}static inline voidwrite8(unsigned addr, unsigned value){ *(unsigned char *) addr = value;}static inline voidpush32(struct regs *regs, unsigned value){ regs->uesp -= 4; write32(address(regs, regs->uss, MASK16(regs->uesp)), value);}static inline voidpush16(struct regs *regs, unsigned value){ regs->uesp -= 2; write16(address(regs, regs->uss, MASK16(regs->uesp)), value);}static inline unsignedpop32(struct regs *regs){ unsigned value = read32(address(regs, regs->uss, MASK16(regs->uesp))); regs->uesp += 4; return value;}static inline unsignedpop16(struct regs *regs){ unsigned value = read16(address(regs, regs->uss, MASK16(regs->uesp))); regs->uesp += 2; return value;}static inline unsignedfetch32(struct regs *regs){ unsigned addr = address(regs, regs->cs, MASK16(regs->eip)); regs->eip += 4; return read32(addr);}static inline unsignedfetch16(struct regs *regs){ unsigned addr = address(regs, regs->cs, MASK16(regs->eip)); regs->eip += 2; return read16(addr);}static inline unsignedfetch8(struct regs *regs){ unsigned addr = address(regs, regs->cs, MASK16(regs->eip)); regs->eip++; return read8(addr);}static unsignedgetreg32(struct regs *regs, int r){ switch (r & 7) { case 0: return regs->eax; case 1: return regs->ecx; case 2: return regs->edx; case 3: return regs->ebx; case 4: return regs->uesp; case 5: return regs->ebp; case 6: return regs->esi; case 7: return regs->edi; } return ~0;}static unsignedgetreg16(struct regs *regs, int r){ return MASK16(getreg32(regs, r));}static unsignedgetreg8(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->eax >> 8) & 0xFF; /* ah */ case 5: return (regs->ecx >> 8) & 0xFF; /* ch */ case 6: return (regs->edx >> 8) & 0xFF; /* dh */ case 7: return (regs->ebx >> 8) & 0xFF; /* bh */ } return ~0;}static voidsetreg32(struct regs *regs, int r, unsigned v){ switch (r & 7) { case 0: regs->eax = v; break; case 1: regs->ecx = v; break; case 2: regs->edx = v; break; case 3: regs->ebx = v; break; case 4: regs->uesp = v; break; case 5: regs->ebp = v; break; case 6: regs->esi = v; break; case 7: regs->edi = v; break; }}static voidsetreg16(struct regs *regs, int r, unsigned v){ setreg32(regs, r, (getreg32(regs, r) & ~0xFFFF) | MASK16(v));}static voidsetreg8(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->eax = (regs->eax & ~0xFF00) | (v << 8); break; case 5: regs->ecx = (regs->ecx & ~0xFF00) | (v << 8); break; case 6: regs->edx = (regs->edx & ~0xFF00) | (v << 8); break; case 7: regs->ebx = (regs->ebx & ~0xFF00) | (v << 8); break; }}static unsignedsegment(unsigned prefix, struct regs *regs, unsigned seg){ if (prefix & SEG_ES) seg = regs->ves; if (prefix & SEG_DS) seg = regs->vds; if (prefix & SEG_CS) seg = regs->cs; if (prefix & SEG_SS) seg = regs->uss; if (prefix & SEG_FS) seg = regs->vfs; if (prefix & SEG_GS) seg = regs->vgs; return seg;}static unsignedsib(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 */static unsignedoperand(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)) { case 0: switch (modrm & 7) { case 0: return address(regs, seg, regs->eax); 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: 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); } break; case 1: case 2: if ((modrm & 7) != 4) { if (mod == 1) disp = (char) fetch8(regs); else disp = (int) fetch32(regs); } switch (modrm & 7) { case 0: return address(regs, seg, regs->eax + disp); 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: 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 getreg32(regs, modrm); } } else { /* 16-bit addressing */ switch ((mod = (modrm >> 6) & 3)) { case 0: switch (modrm & 7) { case 0: return address(regs, seg, MASK16(regs->ebx) + MASK16(regs->esi)); case 1: return address(regs, seg, MASK16(regs->ebx) + MASK16(regs->edi)); case 2: return address(regs, seg, MASK16(regs->ebp) + MASK16(regs->esi)); case 3: return address(regs, seg, MASK16(regs->ebp) + MASK16(regs->edi)); case 4: return address(regs, seg, MASK16(regs->esi)); case 5: return address(regs, seg, MASK16(regs->edi)); case 6: return address(regs, seg, fetch16(regs)); case 7: return address(regs, seg, MASK16(regs->ebx)); } break; case 1: case 2: if (mod == 1) disp = (char) fetch8(regs); else disp = (int) fetch16(regs); switch (modrm & 7) { case 0: return address(regs, seg, MASK16(regs->ebx) + MASK16(regs->esi) + disp); case 1: return address(regs, seg, MASK16(regs->ebx) + MASK16(regs->edi) + disp); case 2: return address(regs, seg, MASK16(regs->ebp) + MASK16(regs->esi) + disp); case 3: return address(regs, seg, MASK16(regs->ebp) + MASK16(regs->edi) + disp); case 4: return address(regs, seg, MASK16(regs->esi) + disp); case 5: return address(regs, seg, MASK16(regs->edi) + disp);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -