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:
22
util/extensions/legacybios/kernel/Makefile
Normal file
22
util/extensions/legacybios/kernel/Makefile
Normal 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
|
||||
|
32
util/extensions/legacybios/kernel/legacybios.c
Normal file
32
util/extensions/legacybios/kernel/legacybios.c
Normal 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;
|
||||
}
|
170
util/extensions/legacybios/kernel/lib.c
Normal file
170
util/extensions/legacybios/kernel/lib.c
Normal 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
|
35
util/extensions/legacybios/kernel/malloc.c
Normal file
35
util/extensions/legacybios/kernel/malloc.c
Normal 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 */
|
||||
}
|
155
util/extensions/legacybios/kernel/pcibios.c
Normal file
155
util/extensions/legacybios/kernel/pcibios.c
Normal 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;
|
||||
}
|
137
util/extensions/legacybios/kernel/x86glue.c
Normal file
137
util/extensions/legacybios/kernel/x86glue.c
Normal 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;
|
||||
}
|
Reference in New Issue
Block a user