void xf86ExecX86int10(xf86Int10InfoPtr pInt) { int sig = setup_int(pInt); if (sig < 0) return; if (int_handler(pInt)) { X86EMU_exec(); } finish_int(pInt, sig); }
//M defined in x86emu/regs.h int main(int argc, char* argv[]) { memset(&M, 0, sizeof(M)); memory = malloc(0x1000); M.mem_base = (unsigned long)memory; M.mem_size = 0x1000; memcpy(memory, _1234, sizeof(_1234)); X86EMU_exec(); printf("eax: %x", M.x86.gen.A.I32_reg.e_reg); 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__); }
// 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__); }