// VBE Function 02h static u8 vbe_set_mode(vbe_mode_info_t * mode_info) { vbe_prepare(); // call VBE function 02h (Set VBE Mode Function) M.x86.R_EAX = 0x4f02; M.x86.R_BX = mode_info->video_mode; M.x86.R_BX |= 0x4000; // set bit 14 to request linear framebuffer mode M.x86.R_BX &= 0x7FFF; // clear bit 15 to request clearing of framebuffer DEBUG_PRINTF_VBE("%s: setting mode: 0x%04x\n", __func__, M.x86.R_BX); // enable trace CHECK_DBG(DEBUG_TRACE_X86EMU) { X86EMU_trace_on(); } // run VESA Interrupt runInt10(); if (M.x86.R_AL != 0x4f) { DEBUG_PRINTF_VBE ("%s: VBE Set Mode Function NOT supported! AL=%x\n", __func__, M.x86.R_AL); return -1; } if (M.x86.R_AH != 0x0) { DEBUG_PRINTF_VBE ("%s: mode: %x VBE Set Mode Function Return Code NOT OK! AH=%x\n", __func__, mode_info->video_mode, M.x86.R_AH); return M.x86.R_AH; } return 0; }
//VBE Function 08h static u8 vbe_set_palette_format(u8 format) { vbe_prepare(); // call VBE function 09h (Set/Get Palette Data Function) M.x86.R_EAX = 0x4f08; M.x86.R_BL = 0x00; // set format M.x86.R_BH = format; DEBUG_PRINTF_VBE("%s: setting palette format: %d\n", __func__, format); // enable trace CHECK_DBG(DEBUG_TRACE_X86EMU) { X86EMU_trace_on(); } // run VESA Interrupt runInt10(); if (M.x86.R_AL != 0x4f) { DEBUG_PRINTF_VBE ("%s: VBE Set Palette Format Function NOT supported! AL=%x\n", __func__, M.x86.R_AL); return -1; } if (M.x86.R_AH != 0x0) { DEBUG_PRINTF_VBE ("%s: VBE Set Palette Format Function Return Code NOT OK! AH=%x\n", __func__, M.x86.R_AH); return M.x86.R_AH; } return 0; }
static u8 vbe_get_color(u16 color_number, u32 * color_value) { vbe_prepare(); // call VBE function 09h (Set/Get Palette Data Function) M.x86.R_EAX = 0x4f09; M.x86.R_BL = 0x00; // get color M.x86.R_CX = 0x01; // get only one entry M.x86.R_DX = color_number; // ES:DI is address where color_value is stored, we store it at 2000:0000 M.x86.R_ES = 0x2000; M.x86.R_DI = 0x0; // enable trace CHECK_DBG(DEBUG_TRACE_X86EMU) { X86EMU_trace_on(); } // run VESA Interrupt runInt10(); if (M.x86.R_AL != 0x4f) { DEBUG_PRINTF_VBE ("%s: VBE Set Palette Function NOT supported! AL=%x\n", __func__, M.x86.R_AL); return -1; } if (M.x86.R_AH != 0x0) { DEBUG_PRINTF_VBE ("%s: VBE Set Palette Function Return Code NOT OK! AH=%x\n", __func__, M.x86.R_AH); return M.x86.R_AH; } // read color value from ES:DI *color_value = in32le(biosmem + (M.x86.R_ES << 4) + M.x86.R_DI); DEBUG_PRINTF_VBE("%s: getting color #%x --> 0x%04x\n", __func__, color_number, *color_value); return 0; }
// VBE Function 01h static u8 vbe_get_mode_info(vbe_mode_info_t * mode_info) { vbe_prepare(); // call VBE function 01h (Return VBE Mode Info Function) M.x86.R_EAX = 0x4f01; M.x86.R_CX = mode_info->video_mode; // enable trace CHECK_DBG(DEBUG_TRACE_X86EMU) { X86EMU_trace_on(); } // run VESA Interrupt runInt10(); if (M.x86.R_AL != 0x4f) { DEBUG_PRINTF_VBE ("%s: VBE Return Mode Info Function NOT supported! AL=%x\n", __func__, M.x86.R_AL); return -1; } if (M.x86.R_AH != 0x0) { DEBUG_PRINTF_VBE ("%s: VBE Return Mode Info (mode: %04x) Function Return Code NOT OK! AH=%02x\n", __func__, mode_info->video_mode, M.x86.R_AH); return M.x86.R_AH; } //pointer to mode_info_block is in ES:DI memcpy(mode_info->mode_info_block, biosmem + ((M.x86.R_ES << 4) + M.x86.R_DI), sizeof(mode_info->mode_info_block)); mode_info_valid = 1; //printf("Mode Info Dump:"); //dump(mode_info_block, 64); return 0; }
// prepare and execute Interrupt 13 (Disk Interrupt) void runInt13(void) { // Initialize stack and data segment M.x86.R_SS = STACK_SEGMENT; M.x86.R_DS = DATA_SEGMENT; M.x86.R_SP = STACK_START_OFFSET; // 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); // setupInt will push the current CS and IP to the stack to return to it, // but we want to halt, so set CS:IP to the HLT instruction we just pushed // to the stack M.x86.R_CS = M.x86.R_SS; M.x86.R_IP = M.x86.R_SP; CHECK_DBG(DEBUG_TRACE_X86EMU) { X86EMU_trace_on(); } CHECK_DBG(DEBUG_JMP) { M.x86.debug |= DEBUG_TRACEJMP_REGS_F; M.x86.debug |= DEBUG_TRACEJMP_REGS_F; M.x86.debug |= DEBUG_TRACECALL_F; M.x86.debug |= DEBUG_TRACECALL_REGS_F; } setupInt(0x13); DEBUG_PRINTF_INTR("%s(): starting execution of INT13...\n", __func__); X86EMU_exec(); DEBUG_PRINTF_INTR("%s(): execution finished\n", __func__); }
// VBE Function 00h static u8 vbe_info(vbe_info_t * info) { vbe_prepare(); // call VBE function 00h (Info Function) M.x86.R_EAX = 0x4f00; // enable trace CHECK_DBG(DEBUG_TRACE_X86EMU) { X86EMU_trace_on(); } // run VESA Interrupt runInt10(); if (M.x86.R_AL != 0x4f) { DEBUG_PRINTF_VBE("%s: VBE Info Function NOT supported! AL=%x\n", __func__, M.x86.R_AL); return -1; } if (M.x86.R_AH != 0x0) { DEBUG_PRINTF_VBE ("%s: VBE Info Function Return Code NOT OK! AH=%x\n", __func__, M.x86.R_AH); return M.x86.R_AH; } //printf("VBE Info Dump:"); //dump(vbe_info_buffer, 64); //offset 0: signature info->signature[0] = vbe_info_buffer[0]; info->signature[1] = vbe_info_buffer[1]; info->signature[2] = vbe_info_buffer[2]; info->signature[3] = vbe_info_buffer[3]; // offset 4: 16bit le containing VbeVersion info->version = in16le(vbe_info_buffer + 4); // offset 6: 32bit le containing segment:offset of OEM String in virtual Mem. info->oem_string_ptr = biosmem + ((in16le(vbe_info_buffer + 8) << 4) + in16le(vbe_info_buffer + 6)); // offset 10: 32bit le capabilities info->capabilities = in32le(vbe_info_buffer + 10); // offset 14: 32 bit le containing segment:offset of supported video mode table u16 *video_mode_ptr; video_mode_ptr = (u16 *) (biosmem + ((in16le(vbe_info_buffer + 16) << 4) + in16le(vbe_info_buffer + 14))); u32 i = 0; do { info->video_mode_list[i] = in16le(video_mode_ptr + i); i++; } while ((i < (sizeof(info->video_mode_list) / sizeof(info->video_mode_list[0]))) && (info->video_mode_list[i - 1] != 0xFFFF)); //offset 18: 16bit le total memory in 64KB blocks info->total_memory = in16le(vbe_info_buffer + 18); return 0; }
// VBE Function 15h static u8 vbe_get_ddc_info(vbe_ddc_info_t * ddc_info) { vbe_prepare(); // call VBE function 15h (DDC Info Function) M.x86.R_EAX = 0x4f15; M.x86.R_BL = 0x00; // get DDC Info M.x86.R_CX = ddc_info->port_number; M.x86.R_ES = 0x0; M.x86.R_DI = 0x0; // enable trace CHECK_DBG(DEBUG_TRACE_X86EMU) { X86EMU_trace_on(); } // run VESA Interrupt runInt10(); if (M.x86.R_AL != 0x4f) { DEBUG_PRINTF_VBE ("%s: VBE Get DDC Info Function NOT supported! AL=%x\n", __func__, M.x86.R_AL); return -1; } if (M.x86.R_AH != 0x0) { DEBUG_PRINTF_VBE ("%s: port: %x VBE Get DDC Info Function Return Code NOT OK! AH=%x\n", __func__, ddc_info->port_number, M.x86.R_AH); return M.x86.R_AH; } // BH = approx. time in seconds to transfer one EDID block ddc_info->edid_transfer_time = M.x86.R_BH; // BL = DDC Level ddc_info->ddc_level = M.x86.R_BL; vbe_prepare(); // call VBE function 15h (DDC Info Function) M.x86.R_EAX = 0x4f15; M.x86.R_BL = 0x01; // read EDID M.x86.R_CX = ddc_info->port_number; M.x86.R_DX = 0x0; // block number // ES:DI is address where EDID is stored, we store it at 2000:0000 M.x86.R_ES = 0x2000; M.x86.R_DI = 0x0; // enable trace CHECK_DBG(DEBUG_TRACE_X86EMU) { X86EMU_trace_on(); } // run VESA Interrupt runInt10(); if (M.x86.R_AL != 0x4f) { DEBUG_PRINTF_VBE ("%s: VBE Read EDID Function NOT supported! AL=%x\n", __func__, M.x86.R_AL); return -1; } if (M.x86.R_AH != 0x0) { DEBUG_PRINTF_VBE ("%s: port: %x VBE Read EDID Function Return Code NOT OK! AH=%x\n", __func__, ddc_info->port_number, M.x86.R_AH); return M.x86.R_AH; } memcpy(ddc_info->edid_block_zero, biosmem + (M.x86.R_ES << 4) + M.x86.R_DI, sizeof(ddc_info->edid_block_zero)); return 0; }
/* 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 {
int vga_bios_init(void) { struct pci_device *pdev; unsigned long romsize = 0; unsigned long romaddress = 0; unsigned char magic[2]; unsigned short ppcidata; /* pointer to pci data structure */ unsigned char pcisig[4]; /* signature of pci data structure */ unsigned char codetype; /* unsigned int vesa_mode = 0;*/ int XGIZ9_ROM = 0; if (vga_dev != NULL) { pdev = vga_dev; printf("Found VGA device: vendor=0x%04x, device=0x%04x\n", PCI_VENDOR(pdev->pa.pa_id),pdev->pa.pa_device); if (PCI_VENDOR(pdev->pa.pa_id) == 0x1002 && pdev->pa.pa_device == 0x4750) BE_wrw(0xc015e,0x4750); if (PCI_VENDOR((pdev->pa.pa_id) == 0x102b)) { printf("skipping matrox cards\n"); return -1; } pci_read_config_dword(pdev,0x30,(int*)&romaddress); romaddress &= (~1); /* enable rom address decode */ pci_write_config_dword(pdev,0x30,romaddress|1); if (romaddress == 0) { printf("No rom address assigned,skipped\n"); return -1; } #ifdef BONITOEL romaddress |= 0x10000000; #endif printf("Rom mapped to %lx\n",romaddress); magic[0] = readb(romaddress); magic[1] = readb(romaddress + 1); if (magic[0]==0x55 && magic[1]==0xaa) { printf("VGA bios found\n"); /* rom size is stored at offset 2,in 512 byte unit*/ romsize = (readb(romaddress + 2)) * 512; printf("rom size is %ldk\n",romsize/1024); ppcidata = readw(romaddress + 0x18); printf("PCI data structure at offset %x\n",ppcidata); pcisig[0] = readb(romaddress + ppcidata); pcisig[1] = readb(romaddress + ppcidata + 1); pcisig[2] = readb(romaddress + ppcidata + 2); pcisig[3] = readb(romaddress + ppcidata + 3); if (pcisig[0]!='P' || pcisig[1]!='C' || pcisig[2]!='I' || pcisig[3]!='R') { printf("PCIR expected,read %c%c%c%c\n", pcisig[0],pcisig[1],pcisig[2],pcisig[3]); printf("Invalid pci signature found,give up\n"); return -1; } codetype = readb(romaddress + ppcidata + 0x14); if (codetype != 0) { printf("Not x86 code in rom,give up\n"); return -1; } } else { #ifdef HAVE_XGIZ9_ROM romaddress = z9sl10810_rom_data; XGIZ9_ROM = 1; romsize = (readb(romaddress + 2)) * 512; #else printf("No valid bios found,magic=%x%x\n",magic[0],magic[1]); return -1; #endif } memset(VGAInfo,0,sizeof(BE_VGAInfo)); VGAInfo[0].pciInfo = pdev; VGAInfo[0].BIOSImage = (void*)malloc(romsize); if (VGAInfo[0].BIOSImage == NULL) { printf("Error alloc memory for vgabios\n"); return -1; } VGAInfo[0].BIOSImageLen = romsize; if (XGIZ9_ROM == 1) memcpy(VGAInfo[0].BIOSImage,(char*)romaddress,romsize); else memcpy(VGAInfo[0].BIOSImage,(char*)(0xa0000000|romaddress),romsize); BE_init(debugFlags,65536,&VGAInfo[0]); regs.h.ah = pdev->pa.pa_bus; regs.h.al = (pdev->pa.pa_device<<3)|(pdev->pa.pa_function&0x7); // Execute the BIOS POST code #ifdef DEBUG_EMU_VGA X86EMU_trace_on(); #endif BE_callRealMode(0xC000,0x0003,®s,&sregs); #if 0 { RMREGS in; RMREGS out; in.e.eax = 0x0003; BE_int86(0x10,&in,&out); } #endif if (XGIZ9_ROM == 0) { //BE_exit(); pci_read_config_dword(pdev,0x30,(int*)&romaddress); /* disable rom address decode */ pci_write_config_dword(pdev,0x30,romaddress & ~1); } printf("vgabios_init: Emulation done\n"); vga_available = 1; return 1; } else{ printf("No VGA PCI device available\n"); return -1; } }
// handle int1a (PCI BIOS Interrupt) static void handleInt1a(void) { // function number in AX u8 bus, devfn, offs; struct device* dev; switch (M.x86.R_AX) { case 0xb101: // Installation check CLEAR_FLAG(F_CF); // clear CF M.x86.R_EDX = 0x20494350; // " ICP" endian swapped "PCI " M.x86.R_AL = 0x1; // Config Space Mechanism 1 supported M.x86.R_BX = 0x0210; // PCI Interface Level Version 2.10 M.x86.R_CL = 0xff; // number of last PCI Bus in system TODO: check! break; case 0xb102: // Find PCI Device // device_id in CX, vendor_id in DX // device index in SI (i.e. if multiple devices with same vendor/device id // are connected). We currently only support device index 0 // DEBUG_PRINTF_INTR("%s(): function: %x: PCI Find Device\n", __func__, M.x86.R_AX); /* FixME: support SI != 0 */ #if CONFIG_YABEL_PCI_ACCESS_OTHER_DEVICES dev = dev_find_device(M.x86.R_DX, M.x86.R_CX, 0); if (dev != 0) { DEBUG_PRINTF_INTR ("%s(): function %x: PCI Find Device --> 0x%04x\n", __func__, M.x86.R_AX, M.x86.R_BX); M.x86.R_BH = dev->bus->secondary; M.x86.R_BL = dev->path.pci.devfn; M.x86.R_AH = 0x00; // return code: success CLEAR_FLAG(F_CF); #else // only allow the device to find itself... if ((M.x86.R_CX == bios_device.pci_device_id) && (M.x86.R_DX == bios_device.pci_vendor_id) // device index must be 0 && (M.x86.R_SI == 0)) { CLEAR_FLAG(F_CF); M.x86.R_AH = 0x00; // return code: success M.x86.R_BH = bios_device.bus; M.x86.R_BL = bios_device.devfn; #endif } else { DEBUG_PRINTF_INTR ("%s(): function %x: invalid device/vendor/device index! (%04x/%04x/%02x expected: %04x/%04x/00) \n", __func__, M.x86.R_AX, M.x86.R_CX, M.x86.R_DX, M.x86.R_SI, bios_device.pci_device_id, bios_device.pci_vendor_id); SET_FLAG(F_CF); M.x86.R_AH = 0x86; // return code: device not found } break; case 0xb108: //read configuration byte case 0xb109: //read configuration word case 0xb10a: //read configuration dword bus = M.x86.R_BH; devfn = M.x86.R_BL; offs = M.x86.R_DI; DEBUG_PRINTF_INTR("%s(): function: %x: PCI Config Read from device: bus: %02x, devfn: %02x, offset: %02x\n", __func__, M.x86.R_AX, bus, devfn, offs); #if CONFIG_YABEL_PCI_ACCESS_OTHER_DEVICES dev = dev_find_slot(bus, devfn); DEBUG_PRINTF_INTR("%s(): function: %x: dev_find_slot() returned: %s\n", __func__, M.x86.R_AX, dev_path(dev)); if (dev == 0) { // fail accesses to non-existent devices... #else dev = bios_device.dev; if ((bus != bios_device.bus) || (devfn != bios_device.devfn)) { // fail accesses to any device but ours... #endif printf ("%s(): Config read access invalid device! bus: %02x (%02x), devfn: %02x (%02x), offs: %02x\n", __func__, bus, bios_device.bus, devfn, bios_device.devfn, offs); SET_FLAG(F_CF); M.x86.R_AH = 0x87; //return code: bad pci register HALT_SYS(); return; } else { switch (M.x86.R_AX) { case 0xb108: M.x86.R_CL = #if CONFIG_PCI_OPTION_ROM_RUN_YABEL pci_read_config8(dev, offs); #else (u8) rtas_pci_config_read(bios_device. puid, 1, bus, devfn, offs); #endif DEBUG_PRINTF_INTR ("%s(): function %x: PCI Config Read @%02x --> 0x%02x\n", __func__, M.x86.R_AX, offs, M.x86.R_CL); break; case 0xb109: M.x86.R_CX = #if CONFIG_PCI_OPTION_ROM_RUN_YABEL pci_read_config16(dev, offs); #else (u16) rtas_pci_config_read(bios_device. puid, 2, bus, devfn, offs); #endif DEBUG_PRINTF_INTR ("%s(): function %x: PCI Config Read @%02x --> 0x%04x\n", __func__, M.x86.R_AX, offs, M.x86.R_CX); break; case 0xb10a: M.x86.R_ECX = #if CONFIG_PCI_OPTION_ROM_RUN_YABEL pci_read_config32(dev, offs); #else (u32) rtas_pci_config_read(bios_device. puid, 4, bus, devfn, offs); #endif DEBUG_PRINTF_INTR ("%s(): function %x: PCI Config Read @%02x --> 0x%08x\n", __func__, M.x86.R_AX, offs, M.x86.R_ECX); break; } CLEAR_FLAG(F_CF); M.x86.R_AH = 0x0; // return code: success } break; case 0xb10b: //write configuration byte case 0xb10c: //write configuration word case 0xb10d: //write configuration dword bus = M.x86.R_BH; devfn = M.x86.R_BL; offs = M.x86.R_DI; if ((bus != bios_device.bus) || (devfn != bios_device.devfn)) { // fail accesses to any device but ours... printf ("%s(): Config read access invalid! bus: %x (%x), devfn: %x (%x), offs: %x\n", __func__, bus, bios_device.bus, devfn, bios_device.devfn, offs); SET_FLAG(F_CF); M.x86.R_AH = 0x87; //return code: bad pci register HALT_SYS(); return; } else { switch (M.x86.R_AX) { case 0xb10b: #if CONFIG_PCI_OPTION_ROM_RUN_YABEL pci_write_config8(bios_device.dev, offs, M.x86.R_CL); #else rtas_pci_config_write(bios_device.puid, 1, bus, devfn, offs, M.x86.R_CL); #endif DEBUG_PRINTF_INTR ("%s(): function %x: PCI Config Write @%02x <-- 0x%02x\n", __func__, M.x86.R_AX, offs, M.x86.R_CL); break; case 0xb10c: #if CONFIG_PCI_OPTION_ROM_RUN_YABEL pci_write_config16(bios_device.dev, offs, M.x86.R_CX); #else rtas_pci_config_write(bios_device.puid, 2, bus, devfn, offs, M.x86.R_CX); #endif DEBUG_PRINTF_INTR ("%s(): function %x: PCI Config Write @%02x <-- 0x%04x\n", __func__, M.x86.R_AX, offs, M.x86.R_CX); break; case 0xb10d: #if CONFIG_PCI_OPTION_ROM_RUN_YABEL pci_write_config32(bios_device.dev, offs, M.x86.R_ECX); #else rtas_pci_config_write(bios_device.puid, 4, bus, devfn, offs, M.x86.R_ECX); #endif DEBUG_PRINTF_INTR ("%s(): function %x: PCI Config Write @%02x <-- 0x%08x\n", __func__, M.x86.R_AX, offs, M.x86.R_ECX); break; } CLEAR_FLAG(F_CF); M.x86.R_AH = 0x0; // return code: success } break; default: printf("%s(): unknown function (%x) for int1a handler.\n", __func__, M.x86.R_AX); 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; } } // main Interrupt Handler routine, should be registered as x86emu interrupt handler void handleInterrupt(int intNum) { u8 int_handled = 0; #ifndef DEBUG_PRINT_INT10 // this printf makes output by int 10 unreadable... // so we only enable it, if int10 print is disabled DEBUG_PRINTF_INTR("%s(%x)\n", __func__, intNum); #endif /* check wether this interrupt has a function pointer set in yabel_intFuncArray and run that */ if (yabel_intFuncArray[intNum]) { DEBUG_PRINTF_INTR("%s(%x) intHandler overridden, calling it...\n", __func__, intNum); int_handled = (*yabel_intFuncArray[intNum])(); } else { switch (intNum) { case 0x10: //BIOS video interrupt case 0x42: // INT 10h relocated by EGA/VGA BIOS case 0x6d: // INT 10h relocated by VGA BIOS // get interrupt vector from IDT (4 bytes per Interrupt starting at address 0 if ((my_rdl(intNum * 4) == 0xF000F065) || //F000:F065 is default BIOS interrupt handler address (my_rdl(intNum * 4) == 0xF4F4F4F4)) //invalid { #if 0 // ignore interrupt... DEBUG_PRINTF_INTR ("%s(%x): invalid interrupt Vector (%08x) found, interrupt ignored...\n", __func__, intNum, my_rdl(intNum * 4)); 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(); #endif handleInt10(); int_handled = 1; } break; case 0x16: // Keyboard BIOS Interrupt handleInt16(); int_handled = 1; break; case 0x1a: // PCI BIOS Interrupt handleInt1a(); int_handled = 1; break; case PMM_INT_NUM: /* The self-defined PMM INT number, this is called by * the code in PMM struct, and it is handled by * pmm_handleInt() */ pmm_handleInt(); int_handled = 1; break; default: printf("Interrupt %#x (Vector: %x) not implemented\n", intNum, my_rdl(intNum * 4)); 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); int_handled = 1; HALT_SYS(); break; } } // if we did not handle the interrupt, jump to the interrupt vector... if (!int_handled) { setupInt(intNum); } } // prepare and execute Interrupt 10 (VGA Interrupt) void runInt10(void) { // Initialize stack and data segment M.x86.R_SS = STACK_SEGMENT; M.x86.R_DS = DATA_SEGMENT; M.x86.R_SP = STACK_START_OFFSET; // 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); // setupInt will push the current CS and IP to the stack to return to it, // but we want to halt, so set CS:IP to the HLT instruction we just pushed // to the stack M.x86.R_CS = M.x86.R_SS; M.x86.R_IP = M.x86.R_SP; // + 4; CHECK_DBG(DEBUG_TRACE_X86EMU) { X86EMU_trace_on(); } CHECK_DBG(DEBUG_JMP) { M.x86.debug |= DEBUG_TRACEJMP_REGS_F; M.x86.debug |= DEBUG_TRACEJMP_REGS_F; M.x86.debug |= DEBUG_TRACECALL_F; M.x86.debug |= DEBUG_TRACECALL_REGS_F; } setupInt(0x10); DEBUG_PRINTF_INTR("%s(): starting execution of INT10...\n", __func__); X86EMU_exec(); DEBUG_PRINTF_INTR("%s(): execution finished\n", __func__); }