diff options
Diffstat (limited to 'util/extensions/legacybios/kernel')
-rw-r--r-- | util/extensions/legacybios/kernel/Makefile | 22 | ||||
-rw-r--r-- | util/extensions/legacybios/kernel/legacybios.c | 32 | ||||
-rw-r--r-- | util/extensions/legacybios/kernel/lib.c | 170 | ||||
-rw-r--r-- | util/extensions/legacybios/kernel/malloc.c | 35 | ||||
-rw-r--r-- | util/extensions/legacybios/kernel/pcibios.c | 155 | ||||
-rw-r--r-- | util/extensions/legacybios/kernel/x86glue.c | 137 |
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; +} |