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

📄 vm86.c

📁 xen 3.2.2 源码
💻 C
📖 第 1 页 / 共 4 页
字号:
			setreg32(regs, r, result);			TRACE((regs, regs->eip - eip,				"addl *0x%x, %%e%s", addr, rnames[r]));		} else {			val1 = getreg16(regs, r);			val2 = read16(addr);			result = val1 + val2;			setreg16(regs, r, result);			TRACE((regs, regs->eip - eip,				"addw *0x%x, %%%s", addr, rnames[r]));		}		break;	}	if (opc == 0x00)		hi_bit = (1<<7);	else		hi_bit = (prefix & DATA32) ? (1<<31) : (1<<15);	set_eflags_add(hi_bit, val1, val2, result, regs);	return 1;}/* * We need to handle pop opcodes that address memory beyond the 64KB * segment limit that VM8086 mode enforces. */static intpop(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;}static intmov_to_seg(struct regs *regs, unsigned prefix, unsigned opc){	unsigned modrm = fetch8(regs);	/*	 * Emulate segment loads in:	 * 1) real->protected mode.	 * 2) protected->real mode.	 */	if (mode != VM86_REAL_TO_PROTECTED &&	    mode != VM86_PROTECTED_TO_REAL)		return 0;	/* Register source only. */	if ((modrm & 0xC0) != 0xC0)		goto fail;	switch ((modrm & 0x38) >> 3) {	case 0: /* es */		regs->ves = getreg16(regs, modrm);		if (mode == VM86_PROTECTED_TO_REAL)			return 1;		saved_rm_regs.ves = 0;		oldctx.es_sel = regs->ves;		return 1;	/* case 1: cs */	case 2: /* ss */		regs->uss = getreg16(regs, modrm);		if (mode == VM86_PROTECTED_TO_REAL)			return 1;		saved_rm_regs.uss = 0;		oldctx.ss_sel = regs->uss;		return 1;	case 3: /* ds */		regs->vds = getreg16(regs, modrm);		if (mode == VM86_PROTECTED_TO_REAL)			return 1;		saved_rm_regs.vds = 0;		oldctx.ds_sel = regs->vds;		return 1;	case 4: /* fs */		regs->vfs = getreg16(regs, modrm);		if (mode == VM86_PROTECTED_TO_REAL)			return 1;		saved_rm_regs.vfs = 0;		oldctx.fs_sel = regs->vfs;		return 1;	case 5: /* gs */		regs->vgs = getreg16(regs, modrm);		if (mode == VM86_PROTECTED_TO_REAL)			return 1;		saved_rm_regs.vgs = 0;		oldctx.gs_sel = regs->vgs;		return 1;	} fail:	printf("%s:%d: missed opcode %02x %02x\n",		   __FUNCTION__, __LINE__, opc, modrm);	return 0;}/* * Emulate a segment load in protected mode */static intload_seg(unsigned long sel, uint32_t *base, uint32_t *limit, union vmcs_arbytes *arbytes){	uint64_t gdt_phys_base;	unsigned long long entry;	/* protected mode: use seg as index into gdt */	if (sel > oldctx.gdtr_limit)		return 0;	if (sel == 0) {		arbytes->fields.null_bit = 1;		return 1;	}	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 * (sel >> 3), &entry);	} else		entry = ((unsigned long long *)(long)gdt_phys_base)[sel >> 3];	/* Check the P bit first */	if (!((entry >> (15+32)) & 0x1) && sel != 0)		return 0;	*base =  (((entry >> (56-24)) & 0xFF000000) |		  ((entry >> (32-16)) & 0x00FF0000) |		  ((entry >> (   16)) & 0x0000FFFF));	*limit = (((entry >> (48-16)) & 0x000F0000) |		  (entry & 0x0000FFFF));	arbytes->bytes = 0;	arbytes->fields.seg_type = (entry >> (8+32)) & 0xF; /* TYPE */	arbytes->fields.s = (entry >> (12+32)) & 0x1; /* S */	if (arbytes->fields.s)		arbytes->fields.seg_type |= 1; /* accessed */	arbytes->fields.dpl = (entry >> (13+32)) & 0x3; /* DPL */	arbytes->fields.p = (entry >> (15+32)) & 0x1; /* P */	arbytes->fields.avl = (entry >> (20+32)) & 0x1; /* AVL */	arbytes->fields.default_ops_size = (entry >> (22+32)) & 0x1; /* D */	if (entry & (1ULL << (23+32))) { /* G */		arbytes->fields.g = 1;		*limit = (*limit << 12) | 0xFFF;	}	return 1;}/* * Emulate a protected mode segment load, falling back to clearing it if * the descriptor was invalid. */static voidload_or_clear_seg(unsigned long sel, uint32_t *base, uint32_t *limit, union vmcs_arbytes *arbytes){	if (!load_seg(sel, base, limit, arbytes))		load_seg(0, base, limit, arbytes);}static unsigned char rm_irqbase[2];/* * Transition to protected mode */static voidprotected_mode(struct regs *regs){	extern char stack_top[];	oldctx.rm_irqbase[0] = rm_irqbase[0];	oldctx.rm_irqbase[1] = rm_irqbase[1];	regs->eflags &= ~(EFLAGS_TF|EFLAGS_VM);	oldctx.eip = regs->eip;	oldctx.esp = regs->uesp;	oldctx.eflags = regs->eflags;	/* reload all segment registers */	if (!load_seg(regs->cs, &oldctx.cs_base,				&oldctx.cs_limit, &oldctx.cs_arbytes))		panic("Invalid %%cs=0x%x for protected mode\n", regs->cs);	oldctx.cs_sel = regs->cs;	load_or_clear_seg(oldctx.es_sel, &oldctx.es_base,			  &oldctx.es_limit, &oldctx.es_arbytes);	load_or_clear_seg(oldctx.ss_sel, &oldctx.ss_base,			  &oldctx.ss_limit, &oldctx.ss_arbytes);	load_or_clear_seg(oldctx.ds_sel, &oldctx.ds_base,			  &oldctx.ds_limit, &oldctx.ds_arbytes);	load_or_clear_seg(oldctx.fs_sel, &oldctx.fs_base,			  &oldctx.fs_limit, &oldctx.fs_arbytes);	load_or_clear_seg(oldctx.gs_sel, &oldctx.gs_base,			  &oldctx.gs_limit, &oldctx.gs_arbytes);	/* initialize jump environment to warp back to protected mode */	regs->uss = DATA_SELECTOR;	regs->uesp = (unsigned long)stack_top;	regs->cs = CODE_SELECTOR;	regs->eip = (unsigned long)switch_to_protected_mode;	/* this should get us into 32-bit mode */}/* * Start real-mode emulation */static voidreal_mode(struct regs *regs){	regs->eflags |= EFLAGS_VM | 0x02;	/*	 * When we transition from protected to real-mode and we	 * have not reloaded the segment descriptors yet, they are	 * interpreted as if they were in protect mode.	 * We emulate this behavior by assuming that these memory	 * reference are below 1MB and set %ss, %ds, %es accordingly.	 */	if (regs->uss != 0) {		if (regs->uss >= HIGHMEM)			panic("%%ss 0x%lx higher than 1MB", regs->uss);		regs->uss = address(regs, regs->uss, 0) >> 4;	} else {		regs->uss = saved_rm_regs.uss;	}	if (regs->vds != 0) {		if (regs->vds >= HIGHMEM)			panic("%%ds 0x%lx higher than 1MB", regs->vds);		regs->vds = address(regs, regs->vds, 0) >> 4;	} else {		regs->vds = saved_rm_regs.vds;	}	if (regs->ves != 0) {		if (regs->ves >= HIGHMEM)			panic("%%es 0x%lx higher than 1MB", regs->ves);		regs->ves = address(regs, regs->ves, 0) >> 4;	} else {		regs->ves = saved_rm_regs.ves;	}	/* this should get us into 16-bit mode */}/* * 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. */voidset_mode(struct regs *regs, enum vm86_mode newmode){	switch (newmode) {	case VM86_REAL:		if (mode == VM86_PROTECTED_TO_REAL ||		    mode == VM86_REAL_TO_PROTECTED) {			regs->eflags &= ~EFLAGS_TF;			real_mode(regs);		} else if (mode != VM86_REAL)			panic("unexpected real mode transition");		break;	case VM86_REAL_TO_PROTECTED:		if (mode == VM86_REAL) {			regs->eflags |= EFLAGS_TF;			saved_rm_regs.vds = regs->vds;			saved_rm_regs.ves = regs->ves;			saved_rm_regs.vfs = regs->vfs;			saved_rm_regs.vgs = regs->vgs;			saved_rm_regs.uss = regs->uss;			oldctx.ds_sel = 0;			oldctx.es_sel = 0;			oldctx.fs_sel = 0;			oldctx.gs_sel = 0;			oldctx.ss_sel = 0;		} else if (mode != VM86_REAL_TO_PROTECTED)			panic("unexpected real-to-protected mode transition");		break;	case VM86_PROTECTED_TO_REAL:		if (mode != VM86_PROTECTED)			panic("unexpected protected-to-real mode transition");		break;	case VM86_PROTECTED:		if (mode != VM86_REAL_TO_PROTECTED)			panic("unexpected protected mode transition");		protected_mode(regs);		break;	}	mode = newmode;	if (mode != VM86_PROTECTED)		TRACE((regs, 0, states[mode]));}static voidjmpl(struct regs *regs, int prefix){	unsigned n = regs->eip;	unsigned cs, eip;	eip = (prefix & DATA32) ? fetch32(regs) : fetch16(regs);	cs = fetch16(regs);	TRACE((regs, (regs->eip - n) + 1, "jmpl 0x%x:0x%x", cs, eip));	regs->cs = cs;	regs->eip = eip;	if (mode == VM86_REAL_TO_PROTECTED)		/* jump to protected mode */		set_mode(regs, VM86_PROTECTED);	else if (mode == VM86_PROTECTED_TO_REAL)	/* jump to real mode */		set_mode(regs, VM86_REAL);	else		panic("jmpl");}static voidjmpl_indirect(struct regs *regs, int prefix, unsigned modrm){	unsigned n = regs->eip;	unsigned cs, eip;	unsigned addr;	addr = operand(prefix, regs, modrm);	eip = (prefix & DATA32) ? read32(addr) : read16(addr);	addr += (prefix & DATA32) ? 4 : 2;	cs = read16(addr);	TRACE((regs, (regs->eip - n) + 1, "jmpl 0x%x:0x%x", cs, eip));	regs->cs = cs;	regs->eip = eip;	if (mode == VM86_REAL_TO_PROTECTED)		/* jump to protected mode */		set_mode(regs, VM86_PROTECTED);	else if (mode == VM86_PROTECTED_TO_REAL)	/* jump to real mode */		set_mode(regs, VM86_REAL);	else		panic("jmpl");}static voidretl(struct regs *regs, int prefix){	unsigned cs, eip;	if (prefix & DATA32) {		eip = pop32(regs);		cs = MASK16(pop32(regs));	} else {		eip = pop16(regs);		cs = pop16(regs);	}	TRACE((regs, 1, "retl (to 0x%x:0x%x)", cs, eip));	regs->cs = cs;	regs->eip = eip;	if (mode == VM86_REAL_TO_PROTECTED)		/* jump to protected mode */		set_mode(regs, VM86_PROTECTED);	else if (mode == VM86_PROTECTED_TO_REAL)	/* jump to real mode */		set_mode(regs, VM86_REAL);	else		panic("retl");}static voidinterrupt(struct regs *regs, int n){	TRACE((regs, 0, "external interrupt %d", n));	push16(regs, regs->eflags);	push16(regs, regs->cs);	push16(regs, regs->eip);	regs->eflags &= ~EFLAGS_IF;	regs->eip = read16(address(regs, 0, n * 4));	regs->cs = read16(address(regs, 0, n * 4 + 2));}/* * Most port I/O operations are passed unmodified. We do have to be * careful and make sure the emulated program isn't remapping the * interrupt vectors. The following simple state machine catches * these attempts and rewrites them. */static intoutbyte(struct regs *regs, unsigned prefix, unsigned opc){	static char icw2[2] = { 0 };	int al, port;	switch (opc) {	case 0xE6: /* outb port, al */		port = fetch8(regs);		break;	case 0xEE: /* outb (%dx), al */		port = MASK16(regs->edx);		break;	default:		return 0;	}	al = regs->eax & 0xFF;	switch (port) {	case PIC_MASTER + PIC_CMD:		if (al & (1 << 4)) /* A0=0,D4=1 -> ICW1 */			icw2[0] = 1;		break;	case PIC_MASTER + PIC_IMR:		if (icw2[0]) {			icw2[0] = 0;			printf("Remapping master: ICW2 0x%x -> 0x%x\n",				al, NR_EXCEPTION_HANDLER);			rm_irqbase[0] = al;			al = NR_EXCEPTION_HANDLER;		}		break;	case PIC_SLAVE  + PIC_CMD:		if (al & (1 << 4)) /* A0=0,D4=1 -> ICW1 */			icw2[1] = 1;		break;	case PIC_SLAVE  + PIC_IMR:		if (icw2[1]) {			icw2[1] = 0;			printf("Remapping slave: ICW2 0x%x -> 0x%x\n",				al, NR_EXCEPTION_HANDLER+8);			rm_irqbase[1] = al;			al = NR_EXCEPTION_HANDLER+8;		}		break;	}	outb(port, al);	return 1;}static intinbyte(struct regs *regs, unsigned prefix, unsigned opc){	int port;	switch (opc) {	case 0xE4: /* inb al, port */		port = fetch8(regs);		break;	case 0xEC: /* inb al, (%dx) */		port = MASK16(regs->edx);		break;	default:		return 0;	}	regs->eax = (regs->eax & ~0xFF) | inb(port);	return 1;}static voidpushrm(struct regs *regs, int prefix, unsigned modrm){	unsigned n = regs->eip;	unsigned addr;	unsigned data;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -