aboutsummaryrefslogtreecommitdiff
path: root/util/x86emu/biosemu.c
diff options
context:
space:
mode:
authorStefan Reinauer <stepan@coresystems.de>2009-08-11 21:28:25 +0000
committerStefan Reinauer <stepan@openbios.org>2009-08-11 21:28:25 +0000
commit38cd29ebd7282333650cf11ed50c7f2fd4031e80 (patch)
tree61008ca7d9a8e4ad5e5237e5f7cbc982a8206c55 /util/x86emu/biosemu.c
parentb339e10f04869a3d8da31e7d52831c32c57302a2 (diff)
Don't pull in x86emu from a foreign directory anymore. This
produced numerous problems in the past, including the fact that x86emu doesn't work in v3 anymore even though it lives in the v3 repository. Since this is a cross-repository move, keeping the history in the v2 tree would make life hard for everone. So check the v3 repository for x86emu history since the merger. The his commit is based on an svn export of r1175 of the coreboot-v3 repository. Signed-off-by: Stefan Reinauer <stepan@coresystems.de> Acked-by: Patrick Georgi <patrick.georgi@coresystems.de> git-svn-id: svn://svn.coreboot.org/coreboot/trunk@4532 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'util/x86emu/biosemu.c')
-rw-r--r--util/x86emu/biosemu.c399
1 files changed, 399 insertions, 0 deletions
diff --git a/util/x86emu/biosemu.c b/util/x86emu/biosemu.c
new file mode 100644
index 0000000000..e91343603f
--- /dev/null
+++ b/util/x86emu/biosemu.c
@@ -0,0 +1,399 @@
+/*
+ * This software and ancillary information (herein called SOFTWARE )
+ * called LinuxBIOS is made available under the terms described
+ * here. The SOFTWARE has been approved for release with associated
+ * LA-CC Number 00-34 . Unless otherwise indicated, this SOFTWARE has
+ * been authored by an employee or employees of the University of
+ * California, operator of the Los Alamos National Laboratory under
+ * Contract No. W-7405-ENG-36 with the U.S. Department of Energy. The
+ * U.S. Government has rights to use, reproduce, and distribute this
+ * SOFTWARE. The public may copy, distribute, prepare derivative works
+ * and publicly display this SOFTWARE without charge, provided that this
+ * Notice and any statement of authorship are reproduced on all copies.
+ * Neither the Government nor the University makes any warranty, express
+ * or implied, or assumes any liability or responsibility for the use of
+ * this SOFTWARE. If SOFTWARE is modified to produce derivative works,
+ * such modified SOFTWARE should be clearly marked, so as not to confuse
+ * it with the version available from LANL.
+ */
+ /*
+ * This file is part of the coreboot project.
+ *
+ * (c) Copyright 2000, Ron Minnich, Advanced Computing Lab, LANL
+ * Copyright (C) 2009 coresystems GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifdef CONFIG_COREBOOT_V2
+#include <arch/io.h>
+#include <console/console.h>
+#else
+#include <io.h>
+#include <console.h>
+#endif
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+
+#include <x86emu/x86emu.h>
+
+#include "pcbios/pcibios.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);
+
+//
+void X86EMU_setMemBase(void *base, size_t size);
+
+/* 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);
+
+ return 1;
+}
+
+u8 x_inb(u16 port)
+{
+ u8 val;
+
+ val = inb(port);
+#ifdef CONFIG_DEBUG
+ if (port != 0x40)
+ printk("inb(0x%04x) = 0x%02x\n", port, val);
+#endif
+
+ return val;
+}
+
+u16 x_inw(u16 port)
+{
+ u16 val;
+
+ val = inw(port);
+
+#ifdef CONFIG_DEBUG
+ printk("inw(0x%04x) = 0x%04x\n", port, val);
+#endif
+ return val;
+}
+
+u32 x_inl(u16 port)
+{
+ u32 val;
+
+ val = inl(port);
+
+#ifdef CONFIG_DEBUG
+ printk("inl(0x%04x) = 0x%08x\n", port, val);
+#endif
+ return val;
+}
+
+void x_outb(u16 port, u8 val)
+{
+#ifdef CONFIG_DEBUG
+ if (port != 0x43)
+ printk("outb(0x%02x, 0x%04x)\n", val, port);
+#endif
+ outb(val, port);
+}
+
+void x_outw(u16 port, u16 val)
+{
+#ifdef CONFIG_DEBUG
+ printk("outw(0x%04x, 0x%04x)\n", val, port);
+#endif
+ outw(val, port);
+}
+
+void x_outl(u16 port, u32 val)
+{
+#ifdef CONFIG_DEBUG
+ printk("outl(0x%08x, 0x%04x)\n", val, port);
+#endif
+ 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("int%x vector at %x\n", num, getIntVect(num));
+
+ switch (num) {
+#ifndef _PC
+ case 0x10:
+ case 0x42:
+ case 0x6D:
+ if (getIntVect(num) == 0x0000) {
+ printk("uninitialized interrupt vector\n");
+ ret = 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();
+ ret = 1;
+ break;
+ case 0xe6:
+ //ret = intE6_handler();
+ ret = 0;
+ break;
+ default:
+ break;
+ }
+
+ if (!ret)
+ ret = run_bios_int(num);
+
+}
+
+#if 0
+#define SYS_BIOS 0xf0000
+/*
+ * here we are really paranoid about faking a "real"
+ * BIOS. Most of this information was pulled from
+ * dosemu.
+ */
+#if 0
+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;
+}
+#endif
+
+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(BIOS_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);
+}
+#endif
+
+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.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);
+
+#ifdef CONFIG_DEBUG
+ //X86EMU_trace_on();
+#endif
+
+ printk("entering emulator\n");
+ X86EMU_exec();
+ printk("exited emulator\n");
+
+#endif
+}