示例#1
0
文件: biosemu.c 项目: jaanek/coreboot
/* main entry into YABEL biosemu, arguments are:
 * *biosmem = pointer to virtual memory
 * biosmem_size = size of the virtual memory
 * *dev = pointer to the device to be initialised
 * rom_addr = address of the OptionROM to be executed, if this is = 0, YABEL
 * 	will look for an ExpansionROM BAR and use the code from there.
 */
u32
biosemu(u8 *biosmem, u32 biosmem_size, struct device * dev, unsigned long rom_addr)
{
	u8 *rom_image;
	int i = 0;
#if CONFIG_X86EMU_DEBUG
	debug_flags = 0;
#if defined(CONFIG_X86EMU_DEBUG_JMP) && CONFIG_X86EMU_DEBUG_JMP
	debug_flags |= DEBUG_JMP;
#endif
#if defined(CONFIG_X86EMU_DEBUG_TRACE) && CONFIG_X86EMU_DEBUG_TRACE
	debug_flags |= DEBUG_TRACE_X86EMU;
#endif
#if defined(CONFIG_X86EMU_DEBUG_PNP) && CONFIG_X86EMU_DEBUG_PNP
	debug_flags |= DEBUG_PNP;
#endif
#if defined(CONFIG_X86EMU_DEBUG_DISK) && CONFIG_X86EMU_DEBUG_DISK
	debug_flags |= DEBUG_DISK;
#endif
#if defined(CONFIG_X86EMU_DEBUG_PMM) && CONFIG_X86EMU_DEBUG_PMM
	debug_flags |= DEBUG_PMM;
#endif
#if defined(CONFIG_X86EMU_DEBUG_VBE) && CONFIG_X86EMU_DEBUG_VBE
	debug_flags |= DEBUG_VBE;
#endif
#if defined(CONFIG_X86EMU_DEBUG_INT10) && CONFIG_X86EMU_DEBUG_INT10
	debug_flags |= DEBUG_PRINT_INT10;
#endif
#if defined(CONFIG_X86EMU_DEBUG_INTERRUPTS) && CONFIG_X86EMU_DEBUG_INTERRUPTS
	debug_flags |= DEBUG_INTR;
#endif
#if defined(CONFIG_X86EMU_DEBUG_CHECK_VMEM_ACCESS) && CONFIG_X86EMU_DEBUG_CHECK_VMEM_ACCESS
	debug_flags |= DEBUG_CHECK_VMEM_ACCESS;
#endif
#if defined(CONFIG_X86EMU_DEBUG_MEM) && CONFIG_X86EMU_DEBUG_MEM
	debug_flags |= DEBUG_MEM;
#endif
#if defined(CONFIG_X86EMU_DEBUG_IO) && CONFIG_X86EMU_DEBUG_IO
	debug_flags |= DEBUG_IO;
#endif

#endif
	if (biosmem_size < MIN_REQUIRED_VMEM_SIZE) {
		printf("Error: Not enough virtual memory: %x, required: %x!\n",
		       biosmem_size, MIN_REQUIRED_VMEM_SIZE);
		return -1;
	}
	if (biosemu_dev_init(dev) != 0) {
		printf("Error initializing device!\n");
		return -1;
	}
	if (biosemu_dev_check_exprom(rom_addr) != 0) {
		printf("Error: Device Expansion ROM invalid!\n");
		return -1;
	}
	rom_image = (u8 *) bios_device.img_addr;
	DEBUG_PRINTF("executing rom_image from %p\n", rom_image);
	DEBUG_PRINTF("biosmem at %p\n", biosmem);

	DEBUG_PRINTF("Image Size: %d\n", bios_device.img_size);

	// in case we jump somewhere unexpected, or execution is finished,
	// fill the biosmem with hlt instructions (0xf4)
	// But we have to be careful: If biosmem is 0x00000000 we're running
	// in the lower 1MB and we must not wipe memory like that.
	if (biosmem) {
		DEBUG_PRINTF("Clearing biosmem\n");
		memset(biosmem, 0xf4, biosmem_size);
	}

	X86EMU_setMemBase(biosmem, biosmem_size);

	DEBUG_PRINTF("membase set: %08x, size: %08x\n", (int) M.mem_base,
		     (int) M.mem_size);

	// copy expansion ROM image to segment OPTION_ROM_CODE_SEGMENT
	// NOTE: this sometimes fails, some bytes are 0x00... so we compare
	// after copying and do some retries...
	u8 *mem_img = biosmem + (OPTION_ROM_CODE_SEGMENT << 4);
	u8 copy_count = 0;
	u8 cmp_result = 0;
	do {
#if 0
		set_ci();
		memcpy(mem_img, rom_image, len);
		clr_ci();
#else
		// memcpy fails... try copy byte-by-byte with set/clr_ci
		u8 c;
		for (i = 0; i < bios_device.img_size; i++) {
			set_ci();
			c = *(rom_image + i);
			if (c != *(rom_image + i)) {
				clr_ci();
				printf("Copy failed at: %x/%x\n", i,
				       bios_device.img_size);
				printf("rom_image(%x): %x, mem_img(%x): %x\n",
				       i, *(rom_image + i), i, *(mem_img + i));
				break;
			}
			clr_ci();
			*(mem_img + i) = c;
		}
#endif
		copy_count++;
		set_ci();
		cmp_result = memcmp(mem_img, rom_image, bios_device.img_size);
		clr_ci();
	}
	while ((copy_count < 5) && (cmp_result != 0));
	if (cmp_result != 0) {
		printf
		    ("\nCopying Expansion ROM Image to Memory failed after %d retries! (%x)\n",
		     copy_count, cmp_result);
		dump(rom_image, 0x20);
		dump(mem_img, 0x20);
		return 0;
	}
	// setup default Interrupt Vectors
	// some expansion ROMs seem to check for these addresses..
	// each handler is only an IRET (0xCF) instruction
	// ROM BIOS Int 10 Handler F000:F065
	my_wrl(0x10 * 4, 0xf000f065);
	my_wrb(0x000ff065, 0xcf);
	// ROM BIOS Int 11 Handler F000:F84D
	my_wrl(0x11 * 4, 0xf000f84d);
	my_wrb(0x000ff84d, 0xcf);
	// ROM BIOS Int 12 Handler F000:F841
	my_wrl(0x12 * 4, 0xf000f841);
	my_wrb(0x000ff841, 0xcf);
	// ROM BIOS Int 13 Handler F000:EC59
	my_wrl(0x13 * 4, 0xf000ec59);
	my_wrb(0x000fec59, 0xcf);
	// ROM BIOS Int 14 Handler F000:E739
	my_wrl(0x14 * 4, 0xf000e739);
	my_wrb(0x000fe739, 0xcf);
	// ROM BIOS Int 15 Handler F000:F859
	my_wrl(0x15 * 4, 0xf000f859);
	my_wrb(0x000ff859, 0xcf);
	// ROM BIOS Int 16 Handler F000:E82E
	my_wrl(0x16 * 4, 0xf000e82e);
	my_wrb(0x000fe82e, 0xcf);
	// ROM BIOS Int 17 Handler F000:EFD2
	my_wrl(0x17 * 4, 0xf000efd2);
	my_wrb(0x000fefd2, 0xcf);
	// ROM BIOS Int 1A Handler F000:FE6E
	my_wrl(0x1a * 4, 0xf000fe6e);
	my_wrb(0x000ffe6e, 0xcf);

	// setup BIOS Data Area (0000:04xx, or 0040:00xx)
	// we currently 0 this area, meaning "we dont have
	// any hardware" :-) no serial/parallel ports, floppys, ...
	memset(biosmem + 0x400, 0x0, 0x100);

	// at offset 13h in BDA is the memory size in kbytes
	my_wrw(0x413, biosmem_size / 1024);
	// at offset 0eh in BDA is the segment of the Extended BIOS Data Area
	// see setup further down
	my_wrw(0x40e, INITIAL_EBDA_SEGMENT);
	// TODO: setup BDA Video Data ( offset 49h-66h)
	// e.g. to store video mode, cursor position, ...
	// in int10 (done) handler and VBE Functions

	// TODO: setup BDA Fixed Disk Data
	// 74h: Fixed Disk Last Operation Status
	// 75h: Fixed Disk Number of Disk Drives

	// TODO: check BDA for further needed data...

	//setup Extended BIOS Data Area
	//we currently 0 this area
	memset(biosmem + (INITIAL_EBDA_SEGMENT << 4), 0, INITIAL_EBDA_SIZE);
	// at offset 0h in EBDA is the size of the EBDA in KB
	my_wrw((INITIAL_EBDA_SEGMENT << 4) + 0x0, INITIAL_EBDA_SIZE / 1024);
	//TODO: check for further needed EBDA data...

	// setup  original ROM BIOS Area (F000:xxxx)
	const char *date = "06/11/99";
	for (i = 0; date[i]; i++)
		my_wrb(0xffff5 + i, date[i]);
	// set up eisa ident string
	const char *ident = "PCI_ISA";
	for (i = 0; ident[i]; i++)
		my_wrb(0xfffd9 + i, ident[i]);

	// write system model id for IBM-AT
	// according to "Ralf Browns Interrupt List" Int15 AH=C0 Table 515,
	// model FC is the original AT and also used in all DOSEMU Versions.
	my_wrb(0xFFFFE, 0xfc);

	//setup interrupt handler
	X86EMU_intrFuncs intrFuncs[256];
	for (i = 0; i < 256; i++)
		intrFuncs[i] = handleInterrupt;
	X86EMU_setupIntrFuncs(intrFuncs);
	X86EMU_setupPioFuncs(&my_pio_funcs);
	X86EMU_setupMemFuncs(&my_mem_funcs);

	//setup PMM struct in BIOS_DATA_SEGMENT, offset 0x0
	u8 pmm_length = pmm_setup(BIOS_DATA_SEGMENT, 0x0);
	if (pmm_length <= 0) {
		printf ("\nYABEL: Warning: PMM Area could not be setup. PMM not available (%x)\n",
		     pmm_length);
		return 0;
	} else {
		CHECK_DBG(DEBUG_PMM) {
			/* test the PMM */
			pmm_test();
			/* and clean it again by calling pmm_setup... */
			pmm_length = pmm_setup(BIOS_DATA_SEGMENT, 0x0);
		}
	}
	// setup the CPU
	M.x86.R_AH = bios_device.bus;
	M.x86.R_AL = bios_device.devfn;
	M.x86.R_DX = 0x80;
	M.x86.R_EIP = 3;
	M.x86.R_CS = OPTION_ROM_CODE_SEGMENT;

	// Initialize stack and data segment
	M.x86.R_SS = STACK_SEGMENT;
	M.x86.R_SP = STACK_START_OFFSET;
	M.x86.R_DS = DATA_SEGMENT;

	// push a HLT instruction and a pointer to it onto the stack
	// any return will pop the pointer and jump to the HLT, thus
	// exiting (more or less) cleanly
	push_word(0xf4f4);	// F4=HLT
	push_word(M.x86.R_SS);
	push_word(M.x86.R_SP + 2);

	CHECK_DBG(DEBUG_TRACE_X86EMU) {
		X86EMU_trace_on();
#if 0
	} else {
示例#2
0
// handle int10 (VGA BIOS Interrupt)
static void
handleInt10(void)
{
	// the data for INT10 is stored in BDA (0000:0400h) offset 49h-66h
	// function number in AH
	//DEBUG_PRINTF_CS_IP("%s:\n", __func__);
	//x86emu_dump_xregs();
	//if ((M.x86.R_IP == 0x32c2) && (M.x86.R_SI == 0x1ce2)){
	//X86EMU_trace_on();
	//M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
	//}
	switch (M.x86.R_AH) {
	case 0x00:
		// set video mode
		// BDA offset 49h is current video mode
		my_wrb(0x449, M.x86.R_AL);
		if (M.x86.R_AL > 7)
			M.x86.R_AL = 0x20;
		else if (M.x86.R_AL == 6)
			M.x86.R_AL = 0x3f;
		else
			M.x86.R_AL = 0x30;
		break;
	case 0x01:
		// set cursor shape
		// ignore
		break;
	case 0x02:
		// set cursor position
		// BH: pagenumber, DX: cursor_pos (DH:row, DL:col)
		// BDA offset 50h-60h are 8 cursor position words for
		// eight possible video pages
		my_wrw(0x450 + (M.x86.R_BH * 2), M.x86.R_DX);
		break;
	case 0x03:
		//get cursor position
		// BH: pagenumber
		// BDA offset 50h-60h are 8 cursor position words for
		// eight possible video pages
		M.x86.R_AX = 0;
		M.x86.R_CH = 0;	// start scan line ???
		M.x86.R_CL = 0;	// end scan line ???
		M.x86.R_DX = my_rdw(0x450 + (M.x86.R_BH * 2));
		break;
	case 0x05:
		// set active page
		// BDA offset 62h is current page number
		my_wrb(0x462, M.x86.R_AL);
		break;
	case 0x06:
		//scroll up windows
		break;
	case 0x07:
		//scroll down windows
		break;
	case 0x08:
		//read character and attribute at position
		M.x86.R_AH = 0x07;	// white-on-black
		M.x86.R_AL = 0x20;	// a space...
		break;
	case 0x09:
		// write character and attribute
		//AL: char, BH: page number, BL: attribute, CX: number of times to write
		//BDA offset 62h is current page number
		CHECK_DBG(DEBUG_PRINT_INT10) {
			u32 i = 0;
			if (M.x86.R_BH == my_rdb(0x462)) {
				for (i = 0; i < M.x86.R_CX; i++)
					printf("%c", M.x86.R_AL);
			}
		}
		break;
	case 0x0a:
		// write character
		//AL: char, BH: page number, BL: attribute, CX: number of times to write
		//BDA offset 62h is current page number
		CHECK_DBG(DEBUG_PRINT_INT10) {
			u32 i = 0;
			if (M.x86.R_BH == my_rdb(0x462)) {
				for (i = 0; i < M.x86.R_CX; i++)
					printf("%c", M.x86.R_AL);
			}
		}
		break;
	case 0x0e:
		// teletype output: write character and advance cursor...
		//AL: char, BH: page number, BL: attribute
		//BDA offset 62h is current page number
		CHECK_DBG(DEBUG_PRINT_INT10) {
			// we ignore the pagenumber on this call...
			//if (M.x86.R_BH == my_rdb(0x462))
			{
				printf("%c", M.x86.R_AL);
				// for debugging, to read all lines
				//if (M.x86.R_AL == 0xd) // carriage return
				//      printf("\n");
			}
		}
		break;
	case 0x0f:
		// get video mode
		// BDA offset 49h is current video mode
		// BDA offset 62h is current page number
		// BDA offset 4ah is columns on screen
		M.x86.R_AH = 80;	//number of character columns... we hardcode it to 80
		M.x86.R_AL = my_rdb(0x449);
		M.x86.R_BH = my_rdb(0x462);
		break;
	default:
		printf("%s(): unknown function (%x) for int10 handler.\n",
		       __func__, M.x86.R_AH);
		DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n",
				  M.x86.R_AX, M.x86.R_BX, M.x86.R_CX,
				  M.x86.R_DX);
		HALT_SYS();
		break;
	}
}