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
This commit is contained in:
Stefan Reinauer
2003-09-18 14:16:08 +00:00
parent 59549598c0
commit dcdbdfb46e
51 changed files with 27688 additions and 0 deletions

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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 */
}

View File

@@ -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;
}

View File

@@ -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;
}