summaryrefslogtreecommitdiff
path: root/src/devices/emulator/biosemu.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/emulator/biosemu.c')
-rw-r--r--src/devices/emulator/biosemu.c335
1 files changed, 335 insertions, 0 deletions
diff --git a/src/devices/emulator/biosemu.c b/src/devices/emulator/biosemu.c
new file mode 100644
index 0000000000..02884035a5
--- /dev/null
+++ b/src/devices/emulator/biosemu.c
@@ -0,0 +1,335 @@
+#include <arch/io.h>
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+
+#include <x86emu/x86emu.h>
+
+#define MEM_WB(where, what) wrb(where, what)
+#define MEM_WW(where, what) wrw(where, what)
+#define MEM_WL(where, what) wrl(where, what)
+
+#define MEM_RB(where) rdb(where)
+#define MEM_RW(where) rdw(where)
+#define MEM_RL(where) rdl(where)
+
+u8 x_inb(u16 port);
+u16 x_inw(u16 port);
+void x_outb(u16 port, u8 val);
+void x_outw(u16 port, u16 val);
+u32 x_inl(u16 port);
+void x_outl(u16 port, u32 val);
+
+/* general software interrupt handler */
+u32 getIntVect(int num)
+{
+ return MEM_RW(num << 2) + (MEM_RW((num << 2) + 2) << 4);
+}
+
+/* FixME: There is already a push_word() in the emulator */
+void pushw(u16 val)
+{
+ X86_ESP -= 2;
+ MEM_WW(((u32) X86_SS << 4) + X86_SP, val);
+}
+
+int run_bios_int(int num)
+{
+ u32 eflags;
+
+ eflags = X86_EFLAGS;
+ pushw(eflags);
+ pushw(X86_CS);
+ pushw(X86_IP);
+ X86_CS = MEM_RW((num << 2) + 2);
+ X86_IP = MEM_RW(num << 2);
+
+ printk_debug("%s: INT %x CS:IP = %x:%x\n", __FUNCTION__,
+ num, MEM_RW((num << 2) + 2), MEM_RW(num << 2));
+
+ return 1;
+}
+
+u8 x_inb(u16 port)
+{
+ u8 val;
+
+ val = inb(port);
+
+ if (port != 0x40)
+ printk_debug("inb(0x%04x) = 0x%02x\n", port, val);
+
+ return val;
+}
+
+u16 x_inw(u16 port)
+{
+ u16 val;
+
+ val = inw(port);
+
+ printk_debug("inw(0x%04x) = 0x%04x\n", port, val);
+ return val;
+}
+
+u32 x_inl(u16 port)
+{
+ u32 val;
+
+ val = inl(port);
+
+ printk_debug("inl(0x%04x) = 0x%08x\n", port, val);
+ return val;
+}
+
+void x_outb(u16 port, u8 val)
+{
+ if (port != 0x43)
+ printk_debug("outb(0x%02x, 0x%04x)\n", val, port);
+ outb(val, port);
+}
+
+void x_outw(u16 port, u16 val)
+{
+ printk_debug("outw(0x%04x, 0x%04x)\n", val, port);
+ outw(val, port);
+}
+
+void x_outl(u16 port, u32 val)
+{
+ printk_debug("outl(0x%08x, 0x%04x)\n", val, port);
+ outl(val, port);
+}
+
+X86EMU_pioFuncs myfuncs = {
+ x_inb, x_inw, x_inl,
+ x_outb, x_outw, x_outl
+};
+
+
+
+/* Interrupt multiplexer */
+
+void do_int(int num)
+{
+ int ret = 0;
+
+ printk_debug("int%x vector at %x\n", num, getIntVect(num));
+
+ switch (num) {
+#ifndef _PC
+ case 0x10:
+ case 0x42:
+ case 0x6D:
+ if (getIntVect(num) == 0x0000) {
+ printk_debug("un-inited int vector\n");
+ return 1;
+ }
+ if (getIntVect(num) == 0xFF065) {
+ //ret = int42_handler();
+ ret = 1;
+ }
+ break;
+#endif
+ case 0x15:
+ //ret = int15_handler();
+ ret = 1;
+ break;
+ case 0x16:
+ //ret = int16_handler();
+ ret = 0;
+ break;
+ case 0x1A:
+ ret = pcibios_handler();
+ break;
+ case 0xe6:
+ //ret = intE6_handler();
+ ret = 0;
+ break;
+ default:
+ break;
+ }
+
+ if (!ret)
+ ret = run_bios_int(num);
+
+ if (!ret) {
+ printk_debug("\nint%x: not implemented\n", num);
+ x86emu_dump_xregs();
+ }
+}
+#define SYS_BIOS 0xf0000
+/*
+ * here we are really paranoid about faking a "real"
+ * BIOS. Most of this information was pulled from
+ * dosemu.
+ */
+void setup_int_vect(void)
+{
+ int i;
+
+ /* let the int vects point to the SYS_BIOS seg */
+ for (i = 0; i < 0x80; i++) {
+ MEM_WW(i << 2, 0);
+ MEM_WW((i << 2) + 2, SYS_BIOS >> 4);
+ }
+
+ reset_int_vect();
+
+ /* font tables default location (int 1F) */
+ MEM_WW(0x1f << 2, 0xfa6e);
+ /* int 11 default location (Get Equipment Configuration) */
+ MEM_WW(0x11 << 2, 0xf84d);
+ /* int 12 default location (Get Conventional Memory Size) */
+ MEM_WW(0x12 << 2, 0xf841);
+ /* int 15 default location (I/O System Extensions) */
+ MEM_WW(0x15 << 2, 0xf859);
+ /* int 1A default location (RTC, PCI and others) */
+ MEM_WW(0x1a << 2, 0xff6e);
+ /* int 05 default location (Bound Exceeded) */
+ MEM_WW(0x05 << 2, 0xff54);
+ /* int 08 default location (Double Fault) */
+ MEM_WW(0x08 << 2, 0xfea5);
+ /* int 13 default location (Disk) */
+ MEM_WW(0x13 << 2, 0xec59);
+ /* int 0E default location (Page Fault) */
+ MEM_WW(0x0e << 2, 0xef57);
+ /* int 17 default location (Parallel Port) */
+ MEM_WW(0x17 << 2, 0xefd2);
+ /* fdd table default location (int 1e) */
+ MEM_WW(0x1e << 2, 0xefc7);
+
+ /* Set Equipment flag to VGA */
+ i = MEM_RB(0x0410) & 0xCF;
+ MEM_WB(0x0410, i);
+ /* XXX Perhaps setup more of the BDA here. See also int42(0x00). */
+}
+
+int setup_system_bios(void *base_addr)
+{
+ char *base = (char *) base_addr;
+
+ /*
+ * we trap the "industry standard entry points" to the BIOS
+ * and all other locations by filling them with "hlt"
+ * TODO: implement hlt-handler for these
+ */
+ memset(base, 0xf4, 0x10000);
+
+ /* set bios date */
+ //strcpy(base + 0x0FFF5, "06/11/99");
+ /* set up eisa ident string */
+ //strcpy(base + 0x0FFD9, "PCI_ISA");
+ /* write system model id for IBM-AT */
+ //*((unsigned char *) (base + 0x0FFFE)) = 0xfc;
+
+ return 1;
+}
+
+void reset_int_vect(void)
+{
+ /*
+ * This table is normally located at 0xF000:0xF0A4. However, int 0x42,
+ * function 0 (Mode Set) expects it (or a copy) somewhere in the bottom
+ * 64kB. Note that because this data doesn't survive POST, int 0x42 should
+ * only be used during EGA/VGA BIOS initialisation.
+ */
+ static const u8 VideoParms[] = {
+ /* Timing for modes 0x00 & 0x01 */
+ 0x38, 0x28, 0x2d, 0x0a, 0x1f, 0x06, 0x19, 0x1c,
+ 0x02, 0x07, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00,
+ /* Timing for modes 0x02 & 0x03 */
+ 0x71, 0x50, 0x5a, 0x0a, 0x1f, 0x06, 0x19, 0x1c,
+ 0x02, 0x07, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00,
+ /* Timing for modes 0x04, 0x05 & 0x06 */
+ 0x38, 0x28, 0x2d, 0x0a, 0x7f, 0x06, 0x64, 0x70,
+ 0x02, 0x01, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00,
+ /* Timing for mode 0x07 */
+ 0x61, 0x50, 0x52, 0x0f, 0x19, 0x06, 0x19, 0x19,
+ 0x02, 0x0d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ /* Display page lengths in little endian order */
+ 0x00, 0x08, /* Modes 0x00 and 0x01 */
+ 0x00, 0x10, /* Modes 0x02 and 0x03 */
+ 0x00, 0x40, /* Modes 0x04 and 0x05 */
+ 0x00, 0x40, /* Modes 0x06 and 0x07 */
+ /* Number of columns for each mode */
+ 40, 40, 80, 80, 40, 40, 80, 80,
+ /* CGA Mode register value for each mode */
+ 0x2c, 0x28, 0x2d, 0x29, 0x2a, 0x2e, 0x1e, 0x29,
+ /* Padding */
+ 0x00, 0x00, 0x00, 0x00
+ };
+ int i;
+
+ for (i = 0; i < sizeof(VideoParms); i++)
+ MEM_WB(i + (0x1000 - sizeof(VideoParms)), VideoParms[i]);
+ MEM_WW(0x1d << 2, 0x1000 - sizeof(VideoParms));
+ MEM_WW((0x1d << 2) + 2, 0);
+
+ printk_debug("SETUP INT\n");
+ MEM_WW(0x10 << 2, 0xf065);
+ MEM_WW((0x10 << 2) + 2, SYS_BIOS >> 4);
+ MEM_WW(0x42 << 2, 0xf065);
+ MEM_WW((0x42 << 2) + 2, SYS_BIOS >> 4);
+ MEM_WW(0x6D << 2, 0xf065);
+ MEM_WW((0x6D << 2) + 2, SYS_BIOS >> 4);
+}
+
+void run_bios(struct device * dev, unsigned long addr)
+{
+#if 1
+ int i;
+ unsigned short initialcs = (addr & 0xF0000) >> 4;
+ unsigned short initialip = (addr + 3) & 0xFFFF;
+ unsigned short devfn = dev->bus->secondary << 8 | dev->path.u.pci.devfn;
+ X86EMU_intrFuncs intFuncs[256];
+
+ X86EMU_setMemBase(0, 0x100000);
+ X86EMU_setupPioFuncs(&myfuncs);
+ for (i = 0; i < 256; i++)
+ intFuncs[i] = do_int;
+ X86EMU_setupIntrFuncs(intFuncs);
+
+ {
+ char *date = "01/01/99";
+ for (i = 0; date[i]; i++)
+ wrb(0xffff5 + i, date[i]);
+ wrb(0xffff7, '/');
+ wrb(0xffffa, '/');
+ }
+
+ {
+ /* FixME: move PIT init to its own file */
+ outb(0x36, 0x43);
+ outb(0x00, 0x40);
+ outb(0x00, 0x40);
+ }
+ //setup_int_vect();
+
+ /* cpu setup */
+ X86_AX = devfn ? devfn : 0xff;
+ X86_DX = 0x80;
+ X86_EIP = initialip;
+ X86_CS = initialcs;
+
+ /* Initialize stack and data segment */
+ X86_SS = initialcs;
+ X86_SP = 0xfffe;
+ X86_DS = 0x0040;
+ X86_ES = 0x0000;
+
+ /* We need a sane way to return from bios
+ * execution. A hlt instruction and a pointer
+ * to it, both kept on the stack, will do.
+ */
+ pushw(0xf4f4); /* hlt; hlt */
+ pushw(X86_SS);
+ pushw(X86_SP + 2);
+
+ //X86EMU_trace_on();
+
+ X86EMU_exec();
+#endif
+}