aboutsummaryrefslogtreecommitdiff
path: root/util/extensions/legacybios/kernel
diff options
context:
space:
mode:
authorStefan Reinauer <stepan@openbios.org>2003-09-18 14:16:08 +0000
committerStefan Reinauer <stepan@openbios.org>2003-09-18 14:16:08 +0000
commitdcdbdfb46e7075515fef5be386e14c42463f7a5e (patch)
treeca43f548ddcb695d4843fe8a69a55e68ba325ca8 /util/extensions/legacybios/kernel
parent59549598c08d5bdcee01bfb91dd9d147edf9fee7 (diff)
first shot of legacybios emulation.
does not work yet.. sorry :-( git-svn-id: svn://svn.coreboot.org/coreboot/trunk@1119 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'util/extensions/legacybios/kernel')
-rw-r--r--util/extensions/legacybios/kernel/Makefile22
-rw-r--r--util/extensions/legacybios/kernel/legacybios.c32
-rw-r--r--util/extensions/legacybios/kernel/lib.c170
-rw-r--r--util/extensions/legacybios/kernel/malloc.c35
-rw-r--r--util/extensions/legacybios/kernel/pcibios.c155
-rw-r--r--util/extensions/legacybios/kernel/x86glue.c137
6 files changed, 551 insertions, 0 deletions
diff --git a/util/extensions/legacybios/kernel/Makefile b/util/extensions/legacybios/kernel/Makefile
new file mode 100644
index 0000000000..a03dcd314e
--- /dev/null
+++ b/util/extensions/legacybios/kernel/Makefile
@@ -0,0 +1,22 @@
+# Makefile for the kernel
+#
+# Copyright (C) 2003 Stefan Reinauer
+#
+# See the file "COPYING" for further information about
+# the copyright and warranty status of this work.
+#
+
+OBJS_KERNEL = lib.o legacybios.o pcibios.o malloc.o x86glue.o
+INCLUDES := -I$(TOPDIR)/include -I$(BUILDDIR) -I $(TOPDIR)/arch/$(ARCH)/include -I$(TOPDIR)/arch/x86emu/include
+
+include $(TOPDIR)/Rules.make
+
+all: core $(OBJS_KERNEL)
+
+core:
+ echo -e "\nBuilding common core files for architecture $(ARCH)"
+
+# dependencies. these are so small that we write them manually.
+lib.o: types.h lib.c
+legacybios.o: config.h types.h legacybios.c
+
diff --git a/util/extensions/legacybios/kernel/legacybios.c b/util/extensions/legacybios/kernel/legacybios.c
new file mode 100644
index 0000000000..08579619ef
--- /dev/null
+++ b/util/extensions/legacybios/kernel/legacybios.c
@@ -0,0 +1,32 @@
+/* tag: legacybios environment, executable code
+ *
+ * Copyright (C) 2003 Stefan Reinauer
+ *
+ * See the file "COPYING" for further information about
+ * the copyright and warranty status of this work.
+ */
+
+#include "config.h"
+#include "types.h"
+
+void printk(const char *fmt, ...);
+void cls(void);
+#ifdef DEBUG_CONSOLE
+int uart_init(int port, unsigned long speed);
+#endif
+
+
+void legacybios(ucell romstart, ucell romend)
+{
+#ifdef DEBUG_CONSOLE
+ uart_init(SERIAL_PORT, SERIAL_SPEED);
+ /* Clear the screen. */
+ cls();
+#endif
+
+#ifdef DEBUG_BOOT
+ printk("LegacyBIOS started.\n");
+#endif
+
+ return;
+}
diff --git a/util/extensions/legacybios/kernel/lib.c b/util/extensions/legacybios/kernel/lib.c
new file mode 100644
index 0000000000..b0a3fbb0e7
--- /dev/null
+++ b/util/extensions/legacybios/kernel/lib.c
@@ -0,0 +1,170 @@
+/* lib.c
+ * tag: simple function library
+ *
+ * Copyright (C) 2003 Stefan Reinauer
+ *
+ * See the file "COPYING" for further information about
+ * the copyright and warranty status of this work.
+ */
+
+#include <stdarg.h>
+#include <string.h>
+#include "types.h"
+
+int putchar(int c);
+
+/* ****************************************************************** */
+
+/* Convert the integer D to a string and save the string in BUF. If
+ * BASE is equal to 'd', interpret that D is decimal, and if BASE is
+ * equal to 'x', interpret that D is hexadecimal.
+ */
+
+static void itoa(char *buf, int base, int d)
+{
+ char *p = buf;
+ char *p1, *p2;
+ unsigned long ud = d;
+ int divisor = 10;
+
+ /* If %d is specified and D is minus, put `-' in the head. */
+ if (base == 'd' && d < 0) {
+ *p++ = '-';
+ buf++;
+ ud = -d;
+ } else if (base == 'x')
+ divisor = 16;
+
+ /* Divide UD by DIVISOR until UD == 0. */
+ do {
+ int remainder = ud % divisor;
+
+ *p++ =
+ (remainder <
+ 10) ? remainder + '0' : remainder + 'a' - 10;
+ }
+ while (ud /= divisor);
+
+ /* Terminate BUF. */
+ *p = 0;
+
+ /* Reverse BUF. */
+ p1 = buf;
+ p2 = p - 1;
+ while (p1 < p2) {
+ char tmp = *p1;
+ *p1 = *p2;
+ *p2 = tmp;
+ p1++;
+ p2--;
+ }
+}
+
+/* Format a string and print it on the screen, just like the libc
+ * function printf.
+ */
+void printk(const char *format, ...)
+{
+ va_list ap;
+ int c, d;
+ char buf[20];
+
+ va_start(ap, format);
+ while ((c = *format++) != 0) {
+ char *p;
+ if (c != '%') {
+ putchar(c);
+ continue;
+ }
+
+ c = *format++;
+ switch (c) {
+ case 'd':
+ case 'u':
+ case 'x':
+ d = va_arg(ap, int);
+ itoa(buf, c, d);
+ p = buf;
+ goto string;
+ break;
+
+ case 's':
+ p = va_arg(ap, char *);
+ if (!p)
+ p = "(null)";
+
+ string:
+ while (*p)
+ putchar(*p++);
+ break;
+
+ default:
+ putchar(va_arg(ap, int));
+ break;
+ }
+ }
+ va_end(ap);
+}
+
+/* memset might be a macro or alike. Disable it to be sure */
+#undef memset
+
+void *memset(void *s, int c, size_t count)
+{
+ char *xs = (char *) s;
+ while (count--)
+ *xs++ = c;
+ return s;
+}
+
+void *memmove(void *dest, const void *src, size_t count)
+{
+ char *tmp, *s;
+ if (dest <= src) {
+ tmp = (char *) dest;
+ s = (char *) src;
+ while (count--)
+ *tmp++ = *s++;
+ } else {
+ tmp = (char *) dest + count;
+ s = (char *) src + count;
+ while (count--)
+ *--tmp = *--s;
+ }
+ return dest;
+}
+
+#ifdef DEBUG_GDB
+void *memcpy(void *dest, const void *src, size_t count)
+{
+ char *tmp = (char *) dest, *s = (char *) src;
+
+ while (count--)
+ *tmp++ = *s++;
+
+ return dest;
+}
+
+#undef strncmp
+int strncmp(const char *cs, const char *ct, size_t count)
+{
+ register signed char __res = 0;
+
+ while (count) {
+ if ((__res = *cs - *ct++) != 0 || !*cs++)
+ break;
+ count--;
+ }
+
+ return __res;
+}
+
+size_t strlen(const char *s)
+{
+ const char *sc;
+
+ for (sc = s; *sc != '\0'; ++sc)
+ /* nothing */ ;
+ return sc - s;
+}
+#endif
diff --git a/util/extensions/legacybios/kernel/malloc.c b/util/extensions/legacybios/kernel/malloc.c
new file mode 100644
index 0000000000..782b516222
--- /dev/null
+++ b/util/extensions/legacybios/kernel/malloc.c
@@ -0,0 +1,35 @@
+
+// 32k heap
+
+
+void printk(const char *fmt, ...);
+#define error printk
+
+static unsigned long free_mem_ptr = 0x20000; /* Start of heap */
+static unsigned long free_mem_end_ptr = 0x28000; /* End of heap */
+
+
+void *malloc(unsigned int size)
+{
+ void *p;
+
+ if (size < 0)
+ error("Error! malloc: Size < 0");
+ if (free_mem_ptr <= 0)
+ error("Error! malloc: Free_mem_ptr <= 0");
+
+ free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */
+
+ p = (void *) free_mem_ptr;
+ free_mem_ptr += size;
+
+ if (free_mem_ptr >= free_mem_end_ptr)
+ error("Error! malloc: Free_mem_ptr >= free_mem_end_ptr");
+
+ return p;
+}
+
+void free(void *where)
+{
+ /* Don't care */
+}
diff --git a/util/extensions/legacybios/kernel/pcibios.c b/util/extensions/legacybios/kernel/pcibios.c
new file mode 100644
index 0000000000..75024d3ddc
--- /dev/null
+++ b/util/extensions/legacybios/kernel/pcibios.c
@@ -0,0 +1,155 @@
+/*
+ * pcibios code from linuxbios
+ */
+
+#include <pci.h>
+#undef __KERNEL__
+#include <io.h>
+
+void printk(const char *fmt, ...);
+
+#define printk_debug printk
+#define printk_err printk
+
+enum {
+ CHECK = 0xb001,
+ FINDDEV = 0xb102,
+ READCONFBYTE = 0xb108,
+ READCONFWORD = 0xb109,
+ READCONFDWORD = 0xb10a,
+ WRITECONFBYTE = 0xb10b,
+ WRITECONFWORD = 0xb10c,
+ WRITECONFDWORD = 0xb10d
+};
+
+// errors go in AH. Just set these up so that word assigns
+// will work. KISS.
+enum {
+ PCIBIOS_NODEV = 0x8600,
+ PCIBIOS_BADREG = 0x8700
+};
+
+int
+pcibios(
+ unsigned long *pedi,
+ unsigned long *pesi,
+ unsigned long *pebp,
+ unsigned long *pesp,
+ unsigned long *pebx,
+ unsigned long *pedx,
+ unsigned long *pecx,
+ unsigned long *peax,
+ unsigned long *pflags
+ ) {
+ unsigned long edi = *pedi;
+ unsigned long esi = *pesi;
+ unsigned long ebp = *pebp;
+ unsigned long esp = *pesp;
+ unsigned long ebx = *pebx;
+ unsigned long edx = *pedx;
+ unsigned long ecx = *pecx;
+ unsigned long eax = *peax;
+ unsigned long flags = *pflags;
+ unsigned short func = (unsigned short) eax;
+ int retval = -1;
+ unsigned short devid, vendorid, devfn;
+ short devindex; /* Use short to get rid of gabage in upper half of 32-bit register */
+ unsigned char bus;
+ struct pci_dev *dev;
+
+ switch(func) {
+ case CHECK:
+ *pedx = 0x4350;
+ *pecx = 0x2049;
+ retval = 0;
+ break;
+ case FINDDEV:
+ {
+ devid = *pecx;
+ vendorid = *pedx;
+ devindex = *pesi;
+ dev = 0;
+ while ((dev = pci_find_device(vendorid, devid, dev))) {
+ if (devindex <= 0)
+ break;
+ devindex--;
+ }
+ if (dev) {
+ unsigned short busdevfn;
+ *peax = 0;
+ // busnum is an unsigned char;
+ // devfn is an int, so we mask it off.
+ busdevfn = (dev->bus << 8)
+ | (dev->devfn & 0xff);
+ printk_debug("0x%x: return 0x%x\n", func, busdevfn);
+ *pebx = busdevfn;
+ retval = 0;
+ } else {
+ *peax = PCIBIOS_NODEV;
+ retval = -1;
+ }
+ }
+ break;
+ case READCONFDWORD:
+ case READCONFWORD:
+ case READCONFBYTE:
+ case WRITECONFDWORD:
+ case WRITECONFWORD:
+ case WRITECONFBYTE:
+ {
+ unsigned int dword;
+ unsigned short word;
+ unsigned char byte;
+ unsigned char reg;
+
+ devfn = *pebx & 0xff;
+ bus = *pebx >> 8;
+ reg = *pedi;
+ dev = pci_find_slot(bus, devfn);
+ if (! dev) {
+ printk_debug("0x%x: BAD DEVICE bus %d devfn 0x%x\n", func, bus, devfn);
+ // idiots. the pcibios guys assumed you'd never pass a bad bus/devfn!
+ *peax = PCIBIOS_BADREG;
+ retval = -1;
+ }
+ switch(func) {
+ case READCONFBYTE:
+ retval = pci_read_config_byte(dev, reg, &byte);
+ *pecx = byte;
+ break;
+ case READCONFWORD:
+ retval = pci_read_config_word(dev, reg, &word);
+ *pecx = word;
+ break;
+ case READCONFDWORD:
+ retval = pci_read_config_dword(dev, reg, &dword);
+ *pecx = dword;
+ break;
+ case WRITECONFBYTE:
+ byte = *pecx;
+ retval = pci_write_config_byte(dev, reg, byte);
+ break;
+ case WRITECONFWORD:
+ word = *pecx;
+ retval = pci_write_config_word(dev, reg, word);
+ break;
+ case WRITECONFDWORD:
+ word = *pecx;
+ retval = pci_write_config_dword(dev, reg, dword);
+ break;
+ }
+
+ if (retval)
+ retval = PCIBIOS_BADREG;
+ printk_debug("0x%x: bus %d devfn 0x%x reg 0x%x val 0x%lx\n", func, bus, devfn, reg, *pecx);
+ *peax = 0;
+ retval = 0;
+ }
+ break;
+ default:
+ printk_err("UNSUPPORTED PCIBIOS FUNCTION 0x%x\n", func);
+ break;
+ }
+
+ return retval;
+}
diff --git a/util/extensions/legacybios/kernel/x86glue.c b/util/extensions/legacybios/kernel/x86glue.c
new file mode 100644
index 0000000000..4abbd98113
--- /dev/null
+++ b/util/extensions/legacybios/kernel/x86glue.c
@@ -0,0 +1,137 @@
+#include <types.h>
+#include <io.h>
+#include <x86emu.h>
+#include <x86glue.h>
+
+void printk(const char *fmt, ...);
+void x86emu_dump_xregs(void);
+void pci_init(void);
+
+int int10_handler(void);
+int int1a_handler(void);
+
+void pushw(u16 val);
+unsigned char biosmem[1024 * 1024];
+int verbose = 0;
+
+u8 x_inb(u16 port)
+{
+ return inb(port);
+}
+
+u16 x_inw(u16 port)
+{
+ return inw(port);
+}
+
+u32 x_inl(u16 port)
+{
+ return inb(port);
+}
+
+void x_outb(u16 port, u8 val)
+{
+ outb(port, val);
+}
+
+void x_outw(u16 port, u16 val)
+{
+ outb(port, val);
+}
+
+void x_outl(u16 port, u32 val)
+{
+ outb(port, val);
+}
+
+X86EMU_pioFuncs myfuncs = {
+ x_inb, x_inw, x_inl,
+ x_outb, x_outw, x_outl
+};
+
+void irq_multiplexer(int num)
+{
+ int ret = 0;
+ switch (num) {
+ case 0x10:
+ case 0x42:
+ case 0x6d:
+ ret = int10_handler();
+ break;
+ case 0x1a:
+ ret = int1a_handler();
+ break;
+ default:
+ break;
+ }
+
+ if (!ret) {
+ printk("int%x not implemented\n", num);
+ x86emu_dump_xregs();
+ }
+}
+
+ptr current = 0;
+int startrom(unsigned char *addr)
+{
+ X86EMU_intrFuncs intFuncs[256];
+ void X86EMU_setMemBase(void *base, size_t size);
+ int trace = 1;
+ int i;
+
+ int devfn=0x18; // FIXME
+ int size=64*1024; // FIXME
+ int initialcs=0xc000;
+ int initialip=0x0003;
+ int base=0xc0000;
+
+ X86EMU_setMemBase(biosmem, sizeof(biosmem));
+ X86EMU_setupPioFuncs(&myfuncs);
+ pci_init();
+ for (i = 0; i < 256; i++)
+ intFuncs[i] = irq_multiplexer;
+ X86EMU_setupIntrFuncs(intFuncs);
+
+
+ current->ax = devfn ? devfn : 0xff; // FIXME
+ /* above we need to search the device on the bus */
+
+ current->dx = 0x80;
+ // current->ip = 0;
+
+ for (i = 0; i < size; i++)
+ wrb(base + i, addr[i]);
+
+ /* cpu setup */
+ X86_AX = devfn ? devfn : 0xff;
+ X86_DX = 0x80;
+ X86_EIP = initialip;
+ X86_CS = initialcs;
+
+ /* Initialize stack and data segment */
+ X86_SS = 0x0030;
+ X86_DS = 0x0040;
+ X86_SP = 0xfffe;
+
+ /* 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);
+
+ X86_ES = 0x0000;
+
+ if (trace) {
+ printk("Switching to single step mode.\n");
+ X86EMU_trace_on();
+ }
+
+ X86EMU_exec();
+
+
+
+ return 0;
+}