⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vm86.c

📁 xen 3.2.2 源码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * 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 + -