- Initial checkin of the freebios2 tree


git-svn-id: svn://svn.coreboot.org/coreboot/trunk@784 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
diff --git a/src/arch/i386/boot/boot.c b/src/arch/i386/boot/boot.c
new file mode 100644
index 0000000..84c71da
--- /dev/null
+++ b/src/arch/i386/boot/boot.c
@@ -0,0 +1,182 @@
+#include <console/console.h>
+#include <ip_checksum.h>
+#include <boot/elf.h>
+#include <boot/elf_boot.h>
+#include <string.h>
+
+
+#ifndef CMD_LINE
+#define CMD_LINE ""
+#endif
+
+
+
+#define UPSZ(X) ((sizeof(X) + 3) &~3)
+
+static struct {
+	Elf_Bhdr hdr;
+	Elf_Nhdr ft_hdr;
+	unsigned char ft_desc[UPSZ(FIRMWARE_TYPE)];
+	Elf_Nhdr bl_hdr;
+	unsigned char bl_desc[UPSZ(BOOTLOADER)];
+	Elf_Nhdr blv_hdr;
+	unsigned char blv_desc[UPSZ(BOOTLOADER_VERSION)];
+	Elf_Nhdr cmd_hdr;
+	unsigned char cmd_desc[UPSZ(CMD_LINE)];
+} elf_boot_notes = {
+	.hdr = {
+		.b_signature = 0x0E1FB007,
+		.b_size = sizeof(elf_boot_notes),
+		.b_checksum = 0,
+		.b_records = 4,
+	},
+	.ft_hdr = {
+		.n_namesz = 0,
+		.n_descsz = sizeof(FIRMWARE_TYPE),
+		.n_type = EBN_FIRMWARE_TYPE,
+	},
+	.ft_desc = FIRMWARE_TYPE,
+	.bl_hdr = {
+		.n_namesz = 0,
+		.n_descsz = sizeof(BOOTLOADER),
+		.n_type = EBN_BOOTLOADER_NAME,
+	},
+	.bl_desc = BOOTLOADER,
+	.blv_hdr = {
+		.n_namesz = 0,
+		.n_descsz = sizeof(BOOTLOADER_VERSION),
+		.n_type = EBN_BOOTLOADER_VERSION,
+	},
+	.blv_desc = BOOTLOADER_VERSION,
+	.cmd_hdr = {
+		.n_namesz = 0,
+		.n_descsz = sizeof(CMD_LINE),
+		.n_type = EBN_COMMAND_LINE,
+	},
+	.cmd_desc = CMD_LINE,
+};
+
+
+int elf_check_arch(Elf_ehdr *ehdr)
+{
+	return (
+		((ehdr->e_machine == EM_386) ||	(ehdr->e_machine == EM_486)) &&
+		(ehdr->e_ident[EI_CLASS] == ELFCLASS32) &&
+		(ehdr->e_ident[EI_DATA] == ELFDATA2LSB) 
+		);
+	
+}
+
+void jmp_to_elf_entry(void *entry, unsigned long buffer)
+{
+	extern unsigned char _ram_seg, _eram_seg;
+	unsigned long lb_start, lb_size;
+	unsigned long adjust, adjusted_boot_notes;
+	unsigned long type;
+
+	elf_boot_notes.hdr.b_checksum = 
+		compute_ip_checksum(&elf_boot_notes, sizeof(elf_boot_notes));
+
+	type = 0x0E1FB007;
+	lb_start = (unsigned long)&_ram_seg;
+	lb_size = (unsigned long)(&_eram_seg - &_ram_seg);
+	adjust = buffer + lb_size - lb_start;
+
+	adjusted_boot_notes = (unsigned long)&elf_boot_notes;
+	adjusted_boot_notes += adjust; 
+
+	printk_spew("entry    = 0x%08lx\n", (unsigned long)entry);
+	printk_spew("lb_start = 0x%08lx\n", lb_start);
+	printk_spew("lb_size  = 0x%08lx\n", lb_size);
+	printk_spew("adjust   = 0x%08lx\n", adjust);
+	printk_spew("buffer   = 0x%08lx\n", buffer);
+	printk_spew("     elf_boot_notes = 0x%08lx\n", (unsigned long)&elf_boot_notes);
+	printk_spew("adjusted_boot_notes = 0x%08lx\n", adjusted_boot_notes);
+	
+	/* Jump to kernel */
+	__asm__ __volatile__(
+		"	cld	\n\t"
+		/* Save the callee save registers... */
+		"	pushl	%%esi\n\t"
+		"	pushl	%%edi\n\t"
+		"	pushl	%%ebx\n\t"
+		/* Save the parameters I was passed */
+		"	pushl	$0\n\t" /* 20 adjust */
+	        "	pushl	%0\n\t" /* 16 lb_start */
+		"	pushl	%1\n\t" /* 12 buffer */
+		"	pushl	%2\n\t" /*  8 lb_size */
+		"	pushl	%3\n\t" /*  4 entry */
+		"	pushl	%4\n\t" /*  0 elf_boot_notes */
+		/* Compute the adjustment */
+		"	xorl	%%eax, %%eax\n\t"
+		"	subl	16(%%esp), %%eax\n\t"
+		"	addl	12(%%esp), %%eax\n\t"
+		"	addl	 8(%%esp), %%eax\n\t"
+		"	movl	%%eax, 20(%%esp)\n\t"
+		/* Place a copy of linuxBIOS in it's new location */
+		/* Move ``longs'' the linuxBIOS size is 4 byte aligned */
+		"	movl	12(%%esp), %%edi\n\t"
+		"	addl	 8(%%esp), %%edi\n\t"
+		"	movl	16(%%esp), %%esi\n\t"
+		"	movl	 8(%%esp), %%ecx\n\n"
+		"	shrl	$2, %%ecx\n\t"
+		"	rep	movsl\n\t"
+
+		/* Adjust the stack pointer to point into the new linuxBIOS image */
+		"	addl	20(%%esp), %%esp\n\t"
+		/* Adjust the instruction pointer to point into the new linuxBIOS image */
+		"	movl	$1f, %%eax\n\t"
+		"	addl	20(%%esp), %%eax\n\t"
+		"	jmp	*%%eax\n\t"
+		"1:	\n\t"
+
+		/* Copy the linuxBIOS bounce buffer over linuxBIOS */
+		/* Move ``longs'' the linuxBIOS size is 4 byte aligned */
+		"	movl	16(%%esp), %%edi\n\t"
+		"	movl	12(%%esp), %%esi\n\t"
+		"	movl	 8(%%esp), %%ecx\n\t"
+		"	shrl	$2, %%ecx\n\t"
+		"	rep	movsl\n\t"
+
+		/* Now jump to the loaded image */
+		"	movl	$0x0E1FB007, %%eax\n\t"
+		"	movl	 0(%%esp), %%ebx\n\t"
+		"	call	*4(%%esp)\n\t"
+
+		/* The loaded image returned? */
+		"	cli	\n\t"
+		"	cld	\n\t"
+
+		/* Copy the saved copy of linuxBIOS where linuxBIOS runs */
+		/* Move ``longs'' the linuxBIOS size is 4 byte aligned */
+		"	movl	16(%%esp), %%edi\n\t"
+		"	movl	12(%%esp), %%esi\n\t"
+		"	addl	 8(%%esp), %%esi\n\t"
+		"	movl	 8(%%esp), %%ecx\n\t"
+		"	shrl	$2, %%ecx\n\t"
+		"	rep	movsl\n\t"
+
+		/* Adjust the stack pointer to point into the old linuxBIOS image */
+		"	subl	20(%%esp), %%esp\n\t"
+
+		/* Adjust the instruction pointer to point into the old linuxBIOS image */
+		"	movl	$1f, %%eax\n\t"
+		"	subl	20(%%esp), %%eax\n\t"
+		"	jmp	*%%eax\n\t"
+		"1:	\n\t"
+
+		/* Drop the parameters I was passed */
+		"	addl	$24, %%esp\n\t"
+
+		/* Restore the callee save registers */
+		"	popl	%%ebx\n\t"
+		"	popl	%%edi\n\t"
+		"	popl	%%esi\n\t"
+
+		:: 
+		"g" (lb_start), "g" (buffer), "g" (lb_size),
+		"g" (entry), "g"(adjusted_boot_notes)
+		);
+}
+
+
diff --git a/src/arch/i386/boot/linuxbios_table.c b/src/arch/i386/boot/linuxbios_table.c
new file mode 100644
index 0000000..1925f2d
--- /dev/null
+++ b/src/arch/i386/boot/linuxbios_table.c
@@ -0,0 +1,281 @@
+#include <console/console.h>
+#include <mem.h>
+#include <ip_checksum.h>
+#include <boot/linuxbios_tables.h>
+#include "linuxbios_table.h"
+#include <string.h>
+#include <version.h>
+
+
+struct lb_header *lb_table_init(unsigned long addr)
+{
+	struct lb_header *header;
+
+	/* 16 byte align the address */
+	addr += 15;
+	addr &= ~15;
+
+	header = (void *)addr;
+	header->signature[0] = 'L';
+	header->signature[1] = 'B';
+	header->signature[2] = 'I';
+	header->signature[3] = 'O';
+	header->header_bytes = sizeof(*header);
+	header->header_checksum = 0;
+	header->table_bytes = 0;
+	header->table_checksum = 0;
+	header->table_entries = 0;
+	return header;
+}
+
+struct lb_record *lb_first_record(struct lb_header *header)
+{
+	struct lb_record *rec;
+	rec = (void *)(((char *)header) + sizeof(*header));
+	return rec;
+}
+
+struct lb_record *lb_last_record(struct lb_header *header)
+{
+	struct lb_record *rec;
+	rec = (void *)(((char *)header) + sizeof(*header) + header->table_bytes);
+	return rec;
+}
+
+struct lb_record *lb_next_record(struct lb_record *rec)
+{
+	rec = (void *)(((char *)rec) + rec->size);	
+	return rec;
+}
+
+struct lb_record *lb_new_record(struct lb_header *header)
+{
+	struct lb_record *rec;
+	rec = lb_last_record(header);
+	if (header->table_entries) {
+		header->table_bytes += rec->size;
+	}
+	rec = lb_last_record(header);
+	header->table_entries++;
+	rec->tag = LB_TAG_UNUSED;
+	rec->size = sizeof(*rec);
+	return rec;
+}
+
+
+struct lb_memory *lb_memory(struct lb_header *header)
+{
+	struct lb_record *rec;
+	struct lb_memory *mem;
+	rec = lb_new_record(header);
+	mem = (struct lb_memory *)rec;
+	mem->tag = LB_TAG_MEMORY;
+	mem->size = sizeof(*mem);
+	return mem;
+}
+
+struct lb_mainboard *lb_mainboard(struct lb_header *header)
+{
+	struct lb_record *rec;
+	struct lb_mainboard *mainboard;
+	rec = lb_new_record(header);
+	mainboard = (struct lb_mainboard *)rec;
+	mainboard->tag = LB_TAG_MAINBOARD;
+
+	mainboard->size = (sizeof(*mainboard) +
+		strlen(mainboard_vendor) + 1 + 
+		strlen(mainboard_part_number) + 1 +
+		3) & ~3;
+
+	mainboard->vendor_idx = 0;
+	mainboard->part_number_idx = strlen(mainboard_vendor) + 1;
+
+	memcpy(mainboard->strings + mainboard->vendor_idx,
+		mainboard_vendor,      strlen(mainboard_vendor) + 1);
+	memcpy(mainboard->strings + mainboard->part_number_idx,
+		mainboard_part_number, strlen(mainboard_part_number) + 1);
+
+	return mainboard;
+}
+
+void lb_strings(struct lb_header *header)
+{
+	static const struct {
+		uint32_t tag;
+		const uint8_t *string;
+	} strings[] = {
+		{ LB_TAG_VERSION,        linuxbios_version,        },
+		{ LB_TAG_EXTRA_VERSION,  linuxbios_extra_version,  },
+		{ LB_TAG_BUILD,          linuxbios_build,          },
+		{ LB_TAG_COMPILE_TIME,   linuxbios_compile_time,   },
+		{ LB_TAG_COMPILE_BY,     linuxbios_compile_by,     },
+		{ LB_TAG_COMPILE_HOST,   linuxbios_compile_host,   },
+		{ LB_TAG_COMPILE_DOMAIN, linuxbios_compile_domain, },
+		{ LB_TAG_COMPILER,       linuxbios_compiler,       },
+		{ LB_TAG_LINKER,         linuxbios_linker,         },
+		{ LB_TAG_ASSEMBLER,      linuxbios_assembler,      },
+	};
+	int i;
+	for(i = 0; i < sizeof(strings)/sizeof(strings[0]); i++) {
+		struct lb_string *rec;
+		size_t len;
+		rec = (struct lb_string *)lb_new_record(header);
+		len = strlen(strings[i].string);
+		rec->tag = strings[i].tag;
+		rec->size = (sizeof(*rec) + len + 1 + 3) & ~3;
+		memcpy(rec->string, strings[i].string, len+1);
+	}
+
+}
+
+/* Some version of gcc have problems with 64 bit types so
+ * take an unsigned long instead of a uint64_t for now.
+ */
+void lb_memory_range(struct lb_memory *mem,
+	uint32_t type, unsigned long start, unsigned long size)
+{
+	int entries;
+	entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
+	mem->map[entries].start = start;
+	mem->map[entries].size = size;
+	mem->map[entries].type = type;
+	mem->size += sizeof(mem->map[0]);
+}
+
+static void lb_memory_rangek(struct lb_memory *mem,
+	uint32_t type, unsigned long startk, unsigned long endk)
+{
+	int entries;
+	entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
+	mem->map[entries].start = startk;
+	mem->map[entries].start <<= 10;
+	mem->map[entries].size = endk - startk;
+	mem->map[entries].size <<= 10;
+	mem->map[entries].type = type;
+	mem->size += sizeof(mem->map[0]);
+}
+
+static void lb_reserve_table_memory(struct lb_header *head)
+{
+	struct lb_record *last_rec;
+	struct lb_memory *mem;
+	uint64_t start;
+	uint64_t end;
+	int i, entries;
+
+	last_rec = lb_last_record(head);
+	mem = get_lb_mem();
+	start = (unsigned long)head;
+	end = (unsigned long)last_rec;
+	entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
+	/* Resize the right two memory areas so this table is in
+	 * a reserved area of memory.  Everything has been carefully
+	 * setup so that is all we need to do.
+	 */
+	for(i = 0; i < entries; i++ ) {
+		uint64_t map_start = mem->map[i].start;
+		uint64_t map_end = map_start + mem->map[i].size;
+		/* Does this area need to be expanded? */
+		if (map_end == start) {
+			mem->map[i].size = end - map_start;
+		}
+		/* Does this area need to be contracted? */
+		else if (map_start == start) {
+			mem->map[i].start = end;
+			mem->map[i].size = map_end - end;
+		}
+	}
+}
+
+
+unsigned long lb_table_fini(struct lb_header *head)
+{
+	struct lb_record *rec, *first_rec;
+	rec = lb_last_record(head);
+	if (head->table_entries) {
+		head->table_bytes += rec->size;
+	}
+	lb_reserve_table_memory(head);
+	first_rec = lb_first_record(head);
+	head->table_checksum = compute_ip_checksum(first_rec, head->table_bytes);
+	head->header_checksum = 0;
+	head->header_checksum = compute_ip_checksum(head, sizeof(*head));
+	printk_debug("Wrote linuxbios table at: %p - %p  checksum %lx\n",
+		head, rec, head->table_checksum);
+	return (unsigned long)rec;
+}
+
+
+/* Routines to extract part so the linuxBIOS table or 
+ * information from the linuxBIOS table after we have written it.
+ * Currently get_lb_mem relies on a global we can change the
+ * implementaiton.
+ */
+static struct lb_memory *mem_ranges = 0;
+struct lb_memory *get_lb_mem(void)
+{
+	return mem_ranges;
+}
+
+unsigned long write_linuxbios_table( 
+	unsigned long *processor_map, 
+	struct mem_range *ram,
+	unsigned long low_table_start, unsigned long low_table_end,
+	unsigned long rom_table_startk, unsigned long rom_table_endk)
+{
+	unsigned long table_size;
+	struct mem_range *ramp;
+	struct lb_header *head;
+	struct lb_memory *mem;
+	struct lb_record *rec_dest, *rec_src;
+
+	head = lb_table_init(low_table_end);
+	low_table_end = (unsigned long)head;
+#if HAVE_OPTION_TABLE == 1
+	/* Write the option config table... */
+	rec_dest = lb_new_record(head);
+	rec_src = (struct lb_record *)&option_table;
+	memcpy(rec_dest,  rec_src, rec_src->size);
+#endif	
+	mem = lb_memory(head);
+	mem_ranges = mem;
+	/* I assume there is always ram at address 0 */
+	/* Reserve our tables in low memory */
+	table_size = (low_table_end - low_table_start);
+	lb_memory_range(mem, LB_MEM_TABLE, 0, table_size);
+	lb_memory_range(mem, LB_MEM_RAM, table_size, (ram[0].sizek << 10) - table_size);
+	/* Reserving pci memory mapped  space will keep the kernel from booting seeing
+	 * any pci resources.
+	 */
+	for(ramp = &ram[1]; ramp->sizek; ramp++) {
+		unsigned long startk, endk;
+		startk = ramp->basek;
+		endk = startk + ramp->sizek;
+		if ((startk < rom_table_startk) && (endk > rom_table_startk)) {
+			lb_memory_rangek(mem, LB_MEM_RAM, startk, rom_table_startk);
+			startk = rom_table_startk;
+		}
+		if ((startk == rom_table_startk) && (endk > startk)) {
+			unsigned long tend;
+			tend = rom_table_endk;
+			if (tend > endk) {
+				tend = endk;
+			}
+			lb_memory_rangek(mem, LB_MEM_TABLE, rom_table_startk, tend);
+			startk = tend;
+		}
+		if (endk > startk) {
+			lb_memory_rangek(mem, LB_MEM_RAM, startk, endk);
+		}
+	}
+
+	/* Record our motheboard */
+	lb_mainboard(head);
+	/* Record our various random string information */
+	lb_strings(head);
+
+	low_table_end = lb_table_fini(head);
+
+	/* Remember where my valid memory ranges are */
+	return low_table_end;
+}
diff --git a/src/arch/i386/boot/linuxbios_table.h b/src/arch/i386/boot/linuxbios_table.h
new file mode 100644
index 0000000..42c0a07
--- /dev/null
+++ b/src/arch/i386/boot/linuxbios_table.h
@@ -0,0 +1,33 @@
+#ifndef LINUXBIOS_TABLE_H
+#define LINUXBIOS_TABLE_H
+
+#include <boot/linuxbios_tables.h>
+
+struct mem_range;
+
+/* This file holds function prototypes for building the linuxbios table. */
+unsigned long write_linuxbios_table(
+	unsigned long *processor_map, 
+	struct mem_range *ram,
+	unsigned long low_table_start, unsigned long low_table_end,
+	unsigned long rom_table_start, unsigned long rom_table_end);
+
+struct lb_header *lb_table_init(unsigned long addr);
+struct lb_record *lb_first_record(struct lb_header *header);
+struct lb_record *lb_last_record(struct lb_header *header);
+struct lb_record *lb_next_record(struct lb_record *rec);
+struct lb_record *lb_new_record(struct lb_header *header);
+struct lb_memory *lb_memory(struct lb_header *header);
+void lb_memory_range(struct lb_memory *mem, 
+	uint32_t type, unsigned long startk, unsigned long sizek);
+struct lb_mainboard *lb_mainboard(struct lb_header *header);
+unsigned long lb_table_fini(struct lb_header *header);
+
+/* Routines to extract part so the linuxBIOS table or information
+ * from the linuxBIOS table.
+ */
+struct lb_memory *get_lb_mem(void);
+
+extern struct cmos_option_table option_table;
+
+#endif /* LINUXBIOS_TABLE_H */
diff --git a/src/arch/i386/boot/pirq_routing.c b/src/arch/i386/boot/pirq_routing.c
new file mode 100644
index 0000000..a7325c4
--- /dev/null
+++ b/src/arch/i386/boot/pirq_routing.c
@@ -0,0 +1,93 @@
+#include <console/console.h>
+#include <arch/pirq_routing.h>
+#include <string.h>
+
+#ifdef DEBUG
+void check_pirq_routing_table(void)
+{
+	const u8 *addr;
+	const struct irq_routing_table *rt;
+	int i;
+	u8 sum;
+
+	printk_info("Checking IRQ routing tables...\n");
+
+#ifdef(IRQ_SLOT_COUNT)
+	if (sizeof(intel_irq_routing_table) != intel_irq_routing_table.size) {
+		printk_warning("Inconsistent IRQ routing table size\n");
+	}
+#endif
+
+	rt = &intel_irq_routing_table;
+	addr = (u8 *)rt;
+
+	sum = 0;
+	for (i = 0; i < rt->size; i++)
+		sum += addr[i];
+
+	printk_debug("%s:%6d:%s() - irq_routing_table located at: 0x%p\n",
+	    __FILE__, __LINE__, __FUNCTION__, addr);
+
+	sum = (unsigned char)(rt->checksum-sum);
+
+	if (sum != rt->checksum) {
+		printk_warning("%s:%6d:%s() - "
+		       "checksum is: 0x%02x but should be: 0x%02x\n",
+		       __FILE__, __LINE__, __FUNCTION__, rt->checksum, sum);
+	}
+
+	if (rt->signature != PIRQ_SIGNATURE || rt->version != PIRQ_VERSION ||
+	    rt->size % 16 || rt->size < sizeof(struct irq_routing_table)) {
+		printk_warning("%s:%6d:%s() - "
+		       "Interrupt Routing Table not valid\n",
+		       __FILE__, __LINE__, __FUNCTION__);
+		return;
+	}
+
+	sum = 0;
+	for (i=0; i<rt->size; i++)
+		sum += addr[i];
+
+	if (sum) {
+		printk_warning("%s:%6d:%s() - "
+		       "checksum error in irq routing table\n",
+		       __FILE__, __LINE__, __FUNCTION__);
+	}
+
+	printk_info("done.\n");
+}
+
+int verify_copy_pirq_routing_table(unsigned long addr)
+{
+	int i;
+	u8 *rt_orig, *rt_curr;
+
+	rt_curr = (u8*)addr;
+	rt_orig = (u8*)&intel_irq_routing_table;
+	printk_info("Verifing priq routing tables copy at 0x%x...", addr);
+	for (i = 0; i < intel_irq_routing_table.size; i++) {
+		if (*(rt_curr + i) != *(rt_orig + i)) {
+			printk_info("failed\n");
+			return -1;
+		}
+	}
+	printk_info("succeed\n");
+	return 0;
+}
+#else
+#define verify_copy_pirq_routing_table(addr)
+#endif
+
+unsigned long copy_pirq_routing_table(unsigned long addr)
+{
+	/* Align the table to be 16 byte aligned. */
+	addr += 15;
+	addr &= ~15;
+
+	/* This table must be betweeen 0xf0000 & 0x100000 */
+	printk_info("Copying IRQ routing tables to 0x%x...", addr);
+	memcpy((void *)addr, &intel_irq_routing_table, intel_irq_routing_table.size);
+	printk_info("done.\n");
+	verify_copy_pirq_routing_table(addr);
+	return addr + intel_irq_routing_table.size;
+}
diff --git a/src/arch/i386/boot/tables.c b/src/arch/i386/boot/tables.c
new file mode 100644
index 0000000..07579fe
--- /dev/null
+++ b/src/arch/i386/boot/tables.c
@@ -0,0 +1,69 @@
+#include <console/console.h>
+#include <mem.h>
+#include <cpu/cpu.h>
+#include <boot/tables.h>
+#include <boot/linuxbios_tables.h>
+#include <arch/pirq_routing.h>
+#include <arch/smp/mpspec.h>
+#include "linuxbios_table.h"
+
+#if CONFIG_SMP && CONFIG_MAX_PHYSICAL_CPUS && (CONFIG_MAX_PHYSICAL_CPUS < CONFIG_MAX_CPUS)
+static void remove_logical_cpus(unsigned long *processor_map)
+{
+	/* To turn off hyperthreading just remove the logical
+	 * cpus from the processor map.
+	 */
+	int disable_logical_cpus = !CONFIG_LOGICAL_CPUS;
+	if (get_option(&disable_logical_cpus,"hyper_threading")) {
+		disable_logical_cpus = !CONFIG_LOGICAL_CPUS;
+	}
+	if (disable_logical_cpus) {
+		/* disable logical cpus */
+		int cnt;
+		for(cnt=MAX_PHYSICAL_CPUS;cnt<MAX_CPUS;cnt++)
+			processor_map[cnt]=0;
+		printk_debug("logical cpus disabled\n");
+	}
+}
+#else
+
+#define remove_logical_cpus(processor_map) do {} while(0) 
+
+#endif /* CONFIG_SMP && CONFIG_MAX_PHYSICAL_CPUS */
+
+struct lb_memory *write_tables(struct mem_range *mem, unsigned long *processor_map)
+{
+	unsigned long low_table_start, low_table_end;
+	unsigned long rom_table_start, rom_table_end;
+
+	rom_table_start = 0xf0000;
+	rom_table_end =   0xf0000;
+	/* Start low addr at 16 bytes instead of 0 because of a buglet
+	 * in the generic linux unzip code, as it tests for the a20 line.
+	 */
+	low_table_start = 0;
+	low_table_end = 16;
+
+	post_code(0x9a);
+	check_pirq_routing_table();
+	/* This table must be betweeen 0xf0000 & 0x100000 */
+	rom_table_end = copy_pirq_routing_table(rom_table_end);
+	rom_table_end = (rom_table_end + 1023) & ~1023;
+
+	/* copy the smp block to address 0 */
+	post_code(0x96);
+	/* The smp table must be in 0-1K, 639K-640K, or 960K-1M */
+	remove_logical_cpus(processor_map);
+	low_table_end = write_smp_table(low_table_end, processor_map);
+
+	/* Don't write anything in the traditional x86 BIOS data segment */
+	if (low_table_end < 0x500) {
+		low_table_end = 0x500;
+	}
+	/* The linuxbios table must be in 0-4K or 960K-1M */
+	write_linuxbios_table(processor_map, mem,
+			      low_table_start, low_table_end,
+			      rom_table_start >> 10, rom_table_end >> 10);
+
+	return get_lb_mem();
+}
diff --git a/src/arch/i386/include/arch/asm.h b/src/arch/i386/include/arch/asm.h
new file mode 100644
index 0000000..ea63e2d
--- /dev/null
+++ b/src/arch/i386/include/arch/asm.h
@@ -0,0 +1,30 @@
+#ifndef ASM_H
+#define	ASM_H
+
+#define ASSEMBLER
+
+/*
+ * Bootstrap code for the STPC Consumer
+ * Copyright (c) 1999 by Net Insight AB. All Rights Reserved.
+ *
+ * $Id$
+ *
+ */
+
+#define	I386_ALIGN_TEXT	0
+#define	I386_ALIGN_DATA	0
+
+/*
+ *	XXX
+ */
+#ifdef __ELF__
+#define	EXT(x)		x
+#else
+#define	EXT(x)		_ ## x
+#endif
+
+#define	STATIC(x)	.align I386_ALIGN_TEXT; EXT(x): 
+#define	GLOBAL(x)	.globl EXT(x); STATIC(x)
+#define	ENTRY(x)	.text; GLOBAL(x)
+
+#endif /* ASM_H */
diff --git a/src/arch/i386/include/arch/boot/boot.h b/src/arch/i386/include/arch/boot/boot.h
new file mode 100644
index 0000000..3ff51c3
--- /dev/null
+++ b/src/arch/i386/include/arch/boot/boot.h
@@ -0,0 +1,8 @@
+#ifndef ASM_I386_BOOT_H
+#define ASM_I386_BOOT_H
+
+#define ELF_CLASS	ELFCLASS32
+#define ELF_DATA	ELFDATA2LSB
+#define ELF_ARCH	EM_386
+
+#endif /* ASM_I386_BOOT_H */
diff --git a/src/arch/i386/include/arch/intel.h b/src/arch/i386/include/arch/intel.h
new file mode 100644
index 0000000..df6604e
--- /dev/null
+++ b/src/arch/i386/include/arch/intel.h
@@ -0,0 +1,369 @@
+/*
+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.
+ */
+/* Copyright 2000, Ron Minnich, Advanced Computing Lab, LANL
+ * rminnich@lanl.gov
+ */
+
+
+#ifndef ROM_INTEL_H
+#define	ROM_INTEL_H
+
+/*
+ * Bootstrap code for the Intel
+ *
+ * $Id$
+ *
+ */
+
+/* 
+ *	Config registers. 
+ */
+/* yeah, yeah, I know these are macros, which is bad. Don't forget: 
+ * we have almost no assembly, so I am not worrying just yet about this. 
+ * we'll fix it someday if we care. My guess is we won't.
+ */
+
+/* well we want functions. But first we want to see it work at all. */
+#undef FUNCTIONS
+#ifndef FUNCTIONS
+
+
+#define RET_LABEL(label)	\
+	jmp label##_done
+
+#define CALL_LABEL(label)	\
+	jmp label		;\
+label##_done:
+
+#define CALLSP(func) \
+	lea	0f, %esp	; \
+	jmp func		; \
+0:
+
+#define RETSP \
+	jmp *%esp
+
+
+#define DELAY(x) mov x, %ecx ;\
+        1: loop 1b ;\
+
+
+	/*
+	 * Macro:	PCI_WRITE_CONFIG_BYTE
+	 * Arguments:	%eax address to write to (includes bus, device, function, &offset)
+	 *              %dl byte to write
+	 *
+	 * Results:	none
+	 *
+	 * Trashed:	%eax, %edx
+	 * Effects:	writes a single byte to pci config space
+	 *
+	 * Notes:	This routine is optimized for minimal register usage.
+	 *              And the tricks it does cannot scale beyond writing a single byte.
+	 *               
+	 *              What it does is almost simple.
+	 *              It preserves %eax (baring special bits) until it is written
+	 *              out to the appropriate port.  And hides the data byte
+	 *              in the high half of edx.
+	 *
+	 *              In %edx[3] it stores the byte to write.
+	 *              In %edx[2] it stores the lower three bits of the address.
+	 */
+
+
+#define PCI_WRITE_CONFIG_BYTE \
+	shll $8,   %edx		; \
+	movb %al,  %dl		; \
+	andb $0x3, %dl		; \
+	shll $16,  %edx		; \
+	\
+	orl  $0x80000000, %eax	; \
+	andl $0xfffffffc, %eax	; \
+	movw $0xcf8, %dx	; \
+	outl %eax,  %dx		; \
+	\
+	shrl $16,  %edx		; \
+	movb %dh,  %al		; \
+	movb $0,   %dh		; \
+	addl $0xcfc, %edx	; \
+	outb %al,  %dx
+
+
+	/*
+	 * Macro:	PCI_WRITE_CONFIG_WORD
+	 * Arguments:	%eax address to write to (includes bus, device, function, &offset)
+	 *              %ecx word to write
+	 *
+	 * Results:	none
+	 *
+	 * Trashed:	%eax, %edx
+	 * Preserved:   %ecx
+	 * Effects:	writes a single byte to pci config space
+	 *
+	 * Notes:	This routine is optimized for minimal register usage.
+	 *               
+	 *              What it does is almost simple.
+	 *              It preserves %eax (baring special bits) until it is written
+	 *              out to the appropriate port.  And hides the least significant
+	 *              bits of the address in the high half of edx.
+	 *
+	 *              In %edx[2] it stores the lower three bits of the address.
+	 */
+
+
+#define PCI_WRITE_CONFIG_WORD \
+	movb %al,  %dl		; \
+	andl $0x3, %edx		; \
+	shll $16,  %edx		; \
+	\
+	orl  $0x80000000, %eax	; \
+	andl $0xfffffffc, %eax	; \
+	movw $0xcf8, %dx	; \
+	outl %eax,  %dx		; \
+	\
+	shrl $16,  %edx		; \
+	movl %ecx, %eax		; \
+	addl $0xcfc, %edx	; \
+	outw %ax,  %dx
+
+
+
+	/*
+	 * Macro:	PCI_WRITE_CONFIG_DWORD
+	 * Arguments:	%eax address to write to (includes bus, device, function, &offset)
+	 *              %ecx dword to write
+	 *
+	 * Results:	none
+	 *
+	 * Trashed:	%eax, %edx
+	 * Preserved:   %ecx
+	 * Effects:	writes a single byte to pci config space
+	 *
+	 * Notes:	This routine is optimized for minimal register usage.
+	 *               
+	 *              What it does is almost simple.
+	 *              It preserves %eax (baring special bits) until it is written
+	 *              out to the appropriate port.  And hides the least significant
+	 *              bits of the address in the high half of edx.
+	 *
+	 *              In %edx[2] it stores the lower three bits of the address.
+	 */
+
+
+#define PCI_WRITE_CONFIG_DWORD \
+	movb %al,  %dl		; \
+	andl $0x3, %edx		; \
+	shll $16,  %edx		; \
+	\
+	orl  $0x80000000, %eax	; \
+	andl $0xfffffffc, %eax	; \
+	movw $0xcf8, %dx	; \
+	outl %eax,  %dx		; \
+	\
+	shrl $16,  %edx		; \
+	movl %ecx, %eax		; \
+	addl $0xcfc, %edx	; \
+	outl %eax,  %dx
+
+
+
+	
+	/*
+	 * Macro:	PCI_READ_CONFIG_BYTE
+	 * Arguments:	%eax address to read from (includes bus, device, function, &offset)
+	 *
+	 * Results:	%al Byte read
+	 *
+	 * Trashed:	%eax, %edx
+	 * Effects:	reads a single byte from pci config space
+	 *
+	 * Notes:	This routine is optimized for minimal register usage.
+	 *               
+	 *              What it does is almost simple.
+	 *              It preserves %eax (baring special bits) until it is written
+	 *              out to the appropriate port.  And hides the least significant
+	 *              bits of the address in the high half of edx.
+	 *
+	 *              In %edx[2] it stores the lower three bits of the address.
+	 */
+
+
+#define PCI_READ_CONFIG_BYTE \
+	movb %al,  %dl		; \
+	andl $0x3, %edx		; \
+	shll $16,  %edx		; \
+	\
+	orl  $0x80000000, %eax	; \
+	andl $0xfffffffc, %eax	; \
+	movw $0xcf8, %dx	; \
+	outl %eax,  %dx		; \
+	\
+	shrl $16,  %edx		; \
+	addl $0xcfc, %edx	; \
+	inb  %dx,  %al
+
+
+
+	/*
+	 * Macro:	PCI_READ_CONFIG_WORD
+	 * Arguments:	%eax address to read from (includes bus, device, function, &offset)
+	 *
+	 * Results:	%ax word read
+	 *
+	 * Trashed:	%eax, %edx
+	 * Effects:	reads a 2 bytes from pci config space
+	 *
+	 * Notes:	This routine is optimized for minimal register usage.
+	 *               
+	 *              What it does is almost simple.
+	 *              It preserves %eax (baring special bits) until it is written
+	 *              out to the appropriate port.  And hides the least significant
+	 *              bits of the address in the high half of edx.
+	 *
+	 *              In %edx[2] it stores the lower three bits of the address.
+	 */
+
+
+#define PCI_READ_CONFIG_WORD \
+	movb %al,  %dl		; \
+	andl $0x3, %edx		; \
+	shll $16,  %edx		; \
+	\
+	orl  $0x80000000, %eax	; \
+	andl $0xfffffffc, %eax	; \
+	movw $0xcf8, %dx	; \
+	outl %eax,  %dx		; \
+	\
+	shrl $16,  %edx		; \
+	addl $0xcfc, %edx	; \
+	inw  %dx,  %ax
+
+
+
+	/*
+	 * Macro:	PCI_READ_CONFIG_DWORD
+	 * Arguments:	%eax address to read from (includes bus, device, function, &offset)
+	 *
+	 * Results:	%eax
+	 *
+	 * Trashed:	%edx
+	 * Effects:	reads 4 bytes from pci config space
+	 *
+	 * Notes:	This routine is optimized for minimal register usage.
+	 *               
+	 *              What it does is almost simple.
+	 *              It preserves %eax (baring special bits) until it is written
+	 *              out to the appropriate port.  And hides the least significant
+	 *              bits of the address in the high half of edx.
+	 *
+	 *              In %edx[2] it stores the lower three bits of the address.
+	 */
+
+
+#define PCI_READ_CONFIG_DWORD \
+	movb %al,  %dl		; \
+	andl $0x3, %edx		; \
+	shll $16,  %edx		; \
+	\
+	orl  $0x80000000, %eax	; \
+	andl $0xfffffffc, %eax	; \
+	movw $0xcf8, %dx	; \
+	outl %eax,  %dx		; \
+	\
+	shrl $16,  %edx		; \
+	addl $0xcfc, %edx	; \
+	inl  %dx,  %eax
+
+
+
+
+#define CS_READ(which)  \
+                 mov  $0x80000000,%eax ; \
+                 mov  which,%ax ; \
+                 and  $0xfc,%al            /* clear bits 1-0 */ ; \
+                 mov  $0xcf8,%dx           /* port 0xcf8 ?*/ ; \
+                 outl  %eax,%dx             /* open up CS config */ ; \
+                 add  $0x4,%dl             /* 0xcfc data port 0 */ ; \
+                 mov  which,%al ; \
+                 and  $0x3,%al             /* only bits 1-0 */ ; \
+                 add  %al,%dl ; \
+                 inb   %dx,%al              /* read  */ ; \
+
+
+#define CS_WRITE(which, data)  \
+                 mov  $0x80000000,%eax       /* 32bit word with bit 31 set */ ; \
+                 mov  which,%ax             /* put the reg# in the low part */ ; \
+                 and  $0xfc,%al             /* dword align the reg# */ ; \
+                 mov  $0xcf8,%dx            /* enable port  */ ; \
+                 outl  %eax,%dx ; \
+                 add  $0x4,%dl             /* 1st data port */ ; \
+                 mov  which,%ax             /* register# */ ; \
+                 and  $0x3,%ax ; \
+                 add  %al,%dl ; \
+		 mov  data, %al ; \
+                 outb  %al,%dx                /* write to reg */ 
+
+#define REGBIS(which, bis) \
+	CS_READ(which) ;\
+	movb bis, %cl ;\
+	orb %al, %cl ;\
+	CS_WRITE(which, %cl)
+
+#define REGBIC(which, bic) \
+	CS_READ(which) ;\
+	movb bic, %cl ;\
+	notb %cl ;\
+	andb %al, %cl ;\
+	CS_WRITE(which, %cl)
+
+
+/* macro to BIC and BIS a reg. calls read a reg,
+ * does a BIC and then a BIS on it.
+ * to clear no bits, make BIC 0.
+ * to set no bits, make BIS 0
+ */
+#define REGBICBIS(which, bic, bis) \
+	CS_READ(which) ;\
+	movb bic, %cl ;\
+	notb %cl ;\
+	andb %cl, %al ;\
+	movb bis, %cl ;\
+	orb %al, %cl ;\
+	CS_WRITE(which, %cl)
+
+#else
+NO FUNCTIONS YET!
+#endif
+
+
+
+/* originally this macro was from STPC BIOS */
+#define	intel_chip_post_macro(value)			 \
+	movb	$value, %al				; \
+	outb	%al, $0x80
+
+#define INTEL_PDATA_MAGIC 0xdeadbeef
+
+/* SLOW_DOWN_IO is a delay we can use that is roughly cpu neutral,
+ * and can be used before memory or timer chips come up.
+ * Since this hits the isa bus it's roughly
+ */
+#define SLOW_DOWN_IO inb $0x80, %al
+
+#endif /* ROM_INTEL_H */
diff --git a/src/arch/i386/include/arch/io.h b/src/arch/i386/include/arch/io.h
new file mode 100644
index 0000000..bcba9a9
--- /dev/null
+++ b/src/arch/i386/include/arch/io.h
@@ -0,0 +1,76 @@
+#ifndef _ASM_IO_H
+#define _ASM_IO_H
+
+/*
+ * This file contains the definitions for the x86 IO instructions
+ * inb/inw/inl/outb/outw/outl and the "string versions" of the same
+ * (insb/insw/insl/outsb/outsw/outsl).
+ *
+ * This file is not meant to be obfuscating: it's just complicated
+ * to (a) handle it all in a way that makes gcc able to optimize it
+ * as well as possible and (b) trying to avoid writing the same thing
+ * over and over again with slight variations and possibly making a
+ * mistake somewhere.
+ */
+
+ /*
+  *  Bit simplified and optimized by Jan Hubicka
+  *  Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999.
+  */
+
+/*
+ * Talk about misusing macros..
+ */
+#define __OUT1(s,x) \
+extern inline void out##s(unsigned x value, unsigned short port) {
+
+#define __OUT2(s,s1,s2) \
+__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
+
+#define __OUT(s,s1,x) \
+__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } 
+
+#define __IN1(s) \
+extern inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
+
+#define __IN2(s,s1,s2) \
+__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
+
+#define __IN(s,s1,i...) \
+__IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } 
+
+#define __INS(s) \
+extern inline void ins##s(unsigned short port, void * addr, unsigned long count) \
+{ __asm__ __volatile__ ("cld ; rep ; ins" #s \
+: "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
+
+#define __OUTS(s) \
+extern inline void outs##s(unsigned short port, const void * addr, unsigned long count) \
+{ __asm__ __volatile__ ("cld ; rep ; outs" #s \
+: "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
+
+#define RETURN_TYPE unsigned char
+__IN(b,"")
+#undef RETURN_TYPE
+#define RETURN_TYPE unsigned short
+__IN(w,"")
+#undef RETURN_TYPE
+#define RETURN_TYPE unsigned int
+__IN(l,"")
+#undef RETURN_TYPE
+
+__OUT(b,"b",char)
+__OUT(w,"w",short)
+__OUT(l,,int)
+
+__INS(b)
+__INS(w)
+__INS(l)
+
+__OUTS(b)
+__OUTS(w)
+__OUTS(l)
+
+
+#endif
+
diff --git a/src/arch/i386/include/arch/pciconf.h b/src/arch/i386/include/arch/pciconf.h
new file mode 100644
index 0000000..8695ee2
--- /dev/null
+++ b/src/arch/i386/include/arch/pciconf.h
@@ -0,0 +1,9 @@
+#ifndef PCI_CONF_REG_INDEX
+
+// These are defined in the PCI spec, and hence are theoretically
+// inclusive of ANYTHING that uses a PCI bus. 
+#define	PCI_CONF_REG_INDEX	0xcf8
+#define	PCI_CONF_REG_DATA	0xcfc
+#define CONFIG_ADDR(bus,devfn,where) (((bus) << 16) | ((devfn) << 8) | (where))
+
+#endif
diff --git a/src/arch/i386/include/arch/pirq_routing.h b/src/arch/i386/include/arch/pirq_routing.h
new file mode 100644
index 0000000..215c4e5
--- /dev/null
+++ b/src/arch/i386/include/arch/pirq_routing.h
@@ -0,0 +1,54 @@
+#ifndef ARCH_PIRQ_ROUTING_H
+#define ARCH_PIRQ_ROUTING_H
+
+#include <stdint.h>
+
+#define PIRQ_SIGNATURE	(('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24))
+#define PIRQ_VERSION 0x0100
+
+struct irq_info {
+	uint8_t bus, devfn;			/* Bus, device and function */
+	struct {
+		uint8_t link;			/* IRQ line ID, chipset dependent, 0=not routed */
+		uint16_t bitmap;		/* Available IRQs */
+	} __attribute__((packed)) irq[4];
+	uint8_t slot;				/* Slot number, 0=onboard */
+	uint8_t rfu;
+} __attribute__((packed));
+
+#if defined(IRQ_SLOT_COUNT)
+#define IRQ_SLOTS_COUNT IRQ_SLOT_COUNT
+#elif (__GNUC__ < 3)
+#define IRQ_SLOTS_COUNT 1
+#else
+#define IRQ_SLOTS_COUNT
+#endif
+
+struct irq_routing_table {
+	uint32_t signature;			/* PIRQ_SIGNATURE should be here */
+	uint16_t version;			/* PIRQ_VERSION */
+	uint16_t size;				/* Table size in bytes */
+	uint8_t  rtr_bus, rtr_devfn;		/* Where the interrupt router lies */
+	uint16_t exclusive_irqs;		/* IRQs devoted exclusively to PCI usage */
+	uint16_t rtr_vendor, rtr_device;	/* Vendor and device ID of interrupt router */
+	uint32_t miniport_data;			/* Crap */
+	uint8_t  rfu[11];
+	uint8_t  checksum;			/* Modulo 256 checksum must give zero */
+	struct irq_info slots[IRQ_SLOTS_COUNT];
+} __attribute__((packed));
+
+extern const struct irq_routing_table intel_irq_routing_table;
+
+#if defined(DEBUG) && defined(HAVE_PIRQ_TABLE)
+void check_pirq_routing_table(void);
+#else
+#define check_pirq_routing_table() do {} while(0)
+#endif
+
+#if defined(HAVE_PIRQ_TABLE)
+unsigned long copy_pirq_routing_table(unsigned long start);
+#else
+#define copy_pirq_routing_table(start) (start)
+#endif
+
+#endif /* ARCH_PIRQ_ROUTING_H */
diff --git a/src/arch/i386/include/arch/rom_segs.h b/src/arch/i386/include/arch/rom_segs.h
new file mode 100644
index 0000000..b51a805
--- /dev/null
+++ b/src/arch/i386/include/arch/rom_segs.h
@@ -0,0 +1,10 @@
+#ifndef ROM_SEGS_H
+#define ROM_SEGS_H
+
+#define ROM_CODE_SEG 0x08
+#define ROM_DATA_SEG 0x10
+
+#define CACHE_RAM_CODE_SEG 0x18
+#define CACHE_RAM_DATA_SEG 0x20
+
+#endif /* ROM_SEGS_H */
diff --git a/src/arch/i386/include/arch/romcc_io.h b/src/arch/i386/include/arch/romcc_io.h
new file mode 100644
index 0000000..02cc272
--- /dev/null
+++ b/src/arch/i386/include/arch/romcc_io.h
@@ -0,0 +1,84 @@
+static void outb(unsigned char value, unsigned short port)
+{
+	__builtin_outb(value, port);
+}
+
+static void outw(unsigned short value, unsigned short port)
+{
+	__builtin_outw(value, port);
+}
+
+static void outl(unsigned int value, unsigned short port)
+{
+	__builtin_outl(value, port);
+}
+
+
+static unsigned char inb(unsigned short port)
+{
+	return __builtin_inb(port);
+}
+
+
+static unsigned char inw(unsigned short port)
+{
+	return __builtin_inw(port);
+}
+
+static unsigned char inl(unsigned short port)
+{
+	return __builtin_inl(port);
+}
+
+static void hlt(void)
+{
+	__builtin_hlt();
+}
+
+static unsigned int config_cmd(unsigned char bus, unsigned devfn, unsigned where)
+{
+	return 0x80000000 | (bus << 16) | (devfn << 8) | (where & ~3);
+}
+
+static unsigned char pcibios_read_config_byte(
+	unsigned char bus, unsigned devfn, unsigned where)
+{
+	outl(config_cmd(bus, devfn, where), 0xCF8);
+	return inb(0xCFC + (where & 3));
+}
+
+static unsigned short pcibios_read_config_word(
+	unsigned char bus, unsigned devfn, unsigned where)
+{
+	outl(config_cmd(bus, devfn, where), 0xCF8);
+	return inw(0xCFC + (where & 2));
+}
+
+static unsigned int pcibios_read_config_dword(
+	unsigned char bus, unsigned devfn, unsigned where)
+{
+	outl(config_cmd(bus, devfn, where), 0xCF8);
+	return inl(0xCFC);
+}
+
+
+static void pcibios_write_config_byte(
+	unsigned char bus, unsigned devfn, unsigned where, unsigned char value)
+{
+	outl(config_cmd(bus, devfn, where), 0xCF8);
+	outb(value, 0xCFC + (where & 3));
+}
+
+static void pcibios_write_config_word(
+	unsigned char bus, unsigned devfn, unsigned where, unsigned short value)
+{
+	outl(config_cmd(bus, devfn, where), 0xCF8);
+	outw(value, 0xCFC + (where & 2));
+}
+
+static void pcibios_write_config_dword(
+	unsigned char bus, unsigned devfn, unsigned where, unsigned int value)
+{
+	outl(config_cmd(bus, devfn, where), 0xCF8);
+	outl(value, 0xCFC);
+}
diff --git a/src/arch/i386/include/arch/smp/mpspec.h b/src/arch/i386/include/arch/smp/mpspec.h
new file mode 100644
index 0000000..305276e
--- /dev/null
+++ b/src/arch/i386/include/arch/smp/mpspec.h
@@ -0,0 +1,282 @@
+#ifndef __ASM_MPSPEC_H
+#define __ASM_MPSPEC_H
+
+#ifdef HAVE_MP_TABLE
+
+/*
+ * Structure definitions for SMP machines following the
+ * Intel Multiprocessing Specification 1.1 and 1.4.
+ */
+
+/*
+ * This tag identifies where the SMP configuration
+ * information is. 
+ */
+ 
+#define SMP_MAGIC_IDENT	(('_'<<24)|('P'<<16)|('M'<<8)|'_')
+
+/*
+ * a maximum of 16 APICs with the current APIC ID architecture.
+ */
+#define MAX_APICS 16
+
+
+#define SMP_FLOATING_TABLE_LEN sizeof(struct intel_mp_floating)
+
+struct intel_mp_floating
+{
+	char mpf_signature[4];		/* "_MP_" 			*/
+	unsigned long mpf_physptr;	/* Configuration table address	*/
+	unsigned char mpf_length;	/* Our length (paragraphs)	*/
+	unsigned char mpf_specification;/* Specification version	*/
+	unsigned char mpf_checksum;	/* Checksum (makes sum 0)	*/
+	unsigned char mpf_feature1;	/* Standard or configuration ? 	*/
+	unsigned char mpf_feature2;	/* Bit7 set for IMCR|PIC	*/
+	unsigned char mpf_feature3;	/* Unused (0)			*/
+	unsigned char mpf_feature4;	/* Unused (0)			*/
+	unsigned char mpf_feature5;	/* Unused (0)			*/
+};
+
+struct mp_config_table
+{
+	char mpc_signature[4];
+#define MPC_SIGNATURE "PCMP"
+	unsigned short mpc_length;	/* Size of table */
+	char  mpc_spec;			/* 0x01 */
+	char  mpc_checksum;
+	char  mpc_oem[8];
+	char  mpc_productid[12];
+	unsigned long mpc_oemptr;	/* 0 if not present */
+	unsigned short mpc_oemsize;	/* 0 if not present */
+	unsigned short mpc_entry_count;
+	unsigned long mpc_lapic;	/* APIC address */
+	unsigned short mpe_length;	/* Extended Table size */
+	unsigned char mpe_checksum;	/* Extended Table checksum */
+	unsigned char reserved;
+};
+
+/* Followed by entries */
+
+#define	MP_PROCESSOR	0
+#define	MP_BUS		1
+#define	MP_IOAPIC	2
+#define	MP_INTSRC	3
+#define	MP_LINTSRC	4
+
+struct mpc_config_processor
+{
+	unsigned char mpc_type;
+	unsigned char mpc_apicid;	/* Local APIC number */
+	unsigned char mpc_apicver;	/* Its versions */
+	unsigned char mpc_cpuflag;
+#define MPC_CPU_ENABLED		1	/* Processor is available */
+#define MPC_CPU_BOOTPROCESSOR	2	/* Processor is the BP */
+	unsigned long mpc_cpufeature;		
+#define MPC_CPU_STEPPING_MASK 0x0F
+#define MPC_CPU_MODEL_MASK	0xF0
+#define MPC_CPU_FAMILY_MASK	0xF00
+	unsigned long mpc_featureflag;	/* CPUID feature value */
+	unsigned long mpc_reserved[2];
+};
+
+struct mpc_config_bus
+{
+	unsigned char mpc_type;
+	unsigned char mpc_busid;
+	unsigned char mpc_bustype[6] __attribute((packed));
+};
+
+#define BUSTYPE_EISA	"EISA"
+#define BUSTYPE_ISA	"ISA"
+#define BUSTYPE_INTERN	"INTERN"	/* Internal BUS */
+#define BUSTYPE_MCA	"MCA"
+#define BUSTYPE_VL	"VL"		/* Local bus */
+#define BUSTYPE_PCI	"PCI"
+#define BUSTYPE_PCMCIA	"PCMCIA"
+
+struct mpc_config_ioapic
+{
+	unsigned char mpc_type;
+	unsigned char mpc_apicid;
+	unsigned char mpc_apicver;
+	unsigned char mpc_flags;
+#define MPC_APIC_USABLE		0x01
+	unsigned long mpc_apicaddr;
+};
+
+struct mpc_config_intsrc
+{
+	unsigned char mpc_type;
+	unsigned char mpc_irqtype;
+	unsigned short mpc_irqflag;
+	unsigned char mpc_srcbus;
+	unsigned char mpc_srcbusirq;
+	unsigned char mpc_dstapic;
+	unsigned char mpc_dstirq;
+};
+
+enum mp_irq_source_types {
+	mp_INT = 0,
+	mp_NMI = 1,
+	mp_SMI = 2,
+	mp_ExtINT = 3
+};
+
+#define MP_IRQ_POLARITY_DEFAULT	0x0
+#define MP_IRQ_POLARITY_HIGH	0x1
+#define MP_IRQ_POLARITY_LOW	0x3
+#define MP_IRQ_POLARITY_MASK    0x3
+#define MP_IRQ_TRIGGER_DEFAULT	0x0
+#define MP_IRQ_TRIGGER_EDGE	0x4
+#define MP_IRQ_TRIGGER_LEVEL	0xc
+#define MP_IRQ_TRIGGER_MASK     0xc
+
+
+struct mpc_config_lintsrc
+{
+	unsigned char mpc_type;
+	unsigned char mpc_irqtype;
+	unsigned short mpc_irqflag;
+	unsigned char mpc_srcbusid;
+	unsigned char mpc_srcbusirq;
+	unsigned char mpc_destapic;	
+#define MP_APIC_ALL	0xFF
+	unsigned char mpc_destapiclint;
+};
+
+/*
+ *	Default configurations
+ *
+ *	1	2 CPU ISA 82489DX
+ *	2	2 CPU EISA 82489DX neither IRQ 0 timer nor IRQ 13 DMA chaining
+ *	3	2 CPU EISA 82489DX
+ *	4	2 CPU MCA 82489DX
+ *	5	2 CPU ISA+PCI
+ *	6	2 CPU EISA+PCI
+ *	7	2 CPU MCA+PCI
+ */
+
+#define MAX_IRQ_SOURCES 128
+#define MAX_MP_BUSSES 32
+enum mp_bustype {
+	MP_BUS_ISA,
+	MP_BUS_EISA,
+	MP_BUS_PCI,
+	MP_BUS_MCA
+};
+
+/* Followed by entries */
+
+#define	MPE_SYSTEM_ADDRESS_SPACE	0x80
+#define	MPE_BUS_HIERARCHY		0x81
+#define	MPE_COMPATIBILITY_ADDRESS_SPACE	0x82
+
+struct mp_exten_config {
+	unsigned char mpe_type;
+	unsigned char mpe_length;
+};
+
+typedef struct mp_exten_config *mpe_t;
+
+struct mp_exten_system_address_space {
+	unsigned char mpe_type;
+	unsigned char mpe_length;
+	unsigned char mpe_busid;
+	unsigned char mpe_address_type;
+#define ADDRESS_TYPE_IO       0
+#define ADDRESS_TYPE_MEM      1
+#define ADDRESS_TYPE_PREFETCH 2
+	unsigned int  mpe_address_base_low;
+	unsigned int  mpe_address_base_high;
+	unsigned int  mpe_address_length_low;
+	unsigned int  mpe_address_length_high;
+};
+
+struct mp_exten_bus_hierarchy {
+	unsigned char mpe_type;
+	unsigned char mpe_length;
+	unsigned char mpe_busid;
+	unsigned char mpe_bus_info;
+#define BUS_SUBTRACTIVE_DECODE 1
+	unsigned char mpe_parent_busid;
+	unsigned char reserved[3];
+};
+
+struct mp_exten_compatibility_address_space {
+	unsigned char mpe_type;
+	unsigned char mpe_length;
+	unsigned char mpe_busid;
+	unsigned char mpe_address_modifier;
+#define ADDRESS_RANGE_SUBTRACT 1
+#define ADDRESS_RANGE_ADD      0
+	unsigned int  mpe_range_list;
+#define RANGE_LIST_IO_ISA	0	
+	/* X100 - X3FF
+	 * X500 - X7FF
+	 * X900 - XBFF
+	 * XD00 - XFFF
+	 */
+#define RANGE_LIST_IO_VGA	1
+	/* X3B0 - X3BB
+	 * X3C0 - X3DF
+	 * X7B0 - X7BB
+	 * X7C0 - X7DF
+	 * XBB0 - XBBB
+	 * XBC0 - XBDF
+	 * XFB0 - XFBB
+	 * XFC0 - XCDF
+	 */
+};
+
+/* Default local apic addr */
+#define LAPIC_ADDR 0xFEE00000
+
+void *smp_next_mpc_entry(struct mp_config_table *mc);
+void *smp_next_mpe_entry(struct mp_config_table *mc);
+
+void smp_write_processor(struct mp_config_table *mc,
+	unsigned char apicid, unsigned char apicver,
+	unsigned char cpuflag, unsigned int cpufeature,
+	unsigned int featureflag);
+void smp_write_processors(struct mp_config_table *mc, 
+	unsigned long *processor_map);
+void smp_write_bus(struct mp_config_table *mc,
+	unsigned char id, unsigned char *bustype);
+void smp_write_ioapic(struct mp_config_table *mc,
+	unsigned char id, unsigned char ver, 
+	unsigned long apicaddr);
+void smp_write_intsrc(struct mp_config_table *mc,
+	unsigned char irqtype, unsigned short irqflag,
+	unsigned char srcbus, unsigned char srcbusirq,
+	unsigned char dstapic, unsigned char dstirq);
+void smp_write_lintsrc(struct mp_config_table *mc,
+	unsigned char irqtype, unsigned short irqflag,
+	unsigned char srcbusid, unsigned char srcbusirq,
+	unsigned char destapic, unsigned char destapiclint);
+void smp_write_address_space(struct mp_config_table *mc,
+	unsigned char busid, unsigned char address_type,
+	unsigned int address_base_low, unsigned int address_base_high,
+	unsigned int address_length_low, unsigned int address_length_high);
+void smp_write_bus_hierarchy(struct mp_config_table *mc,
+	unsigned char busid, unsigned char bus_info,
+	unsigned char parent_busid);
+void smp_write_compatibility_address_space(struct mp_config_table *mc,
+	unsigned char busid, unsigned char address_modifier,
+	unsigned int range_list);
+unsigned char smp_compute_checksum(void *v, int len);
+void *smp_write_floating_table(unsigned long addr);
+unsigned long write_smp_table(unsigned long addr, unsigned long *processor_map);
+
+/* A table (per mainboard) listing the initial apicid of each cpu. */
+extern unsigned long initial_apicid[MAX_CPUS];
+
+#else /* HAVE_MP_TABLE */
+static inline 
+unsigned long write_smp_table(unsigned long addr, unsigned long *processor_map)
+{
+	return addr;
+}
+#endif /* HAVE_MP_TABLE */
+
+#endif
+
diff --git a/src/arch/i386/include/bitops.h b/src/arch/i386/include/bitops.h
new file mode 100644
index 0000000..fae2045
--- /dev/null
+++ b/src/arch/i386/include/bitops.h
@@ -0,0 +1,20 @@
+#ifndef I386_BITOPS_H
+#define I386_BITOPS_H
+
+/**
+ * log2 - Find the truncated log base 2 of x
+ */
+
+static inline unsigned long log2(unsigned long x)
+{
+	unsigned long r = 0;
+	__asm__(
+		"bsrl %1, %0\n\t"
+		"jnz 1f\n\t"
+		"movl $-1, %0\n\t"
+		"1:\n\t"
+		: "=r" (r) : "r" (x));
+	return r;
+		
+}
+#endif /* I386_BITOPS_H */
diff --git a/src/arch/i386/include/stddef.h b/src/arch/i386/include/stddef.h
new file mode 100644
index 0000000..4bf6b0a
--- /dev/null
+++ b/src/arch/i386/include/stddef.h
@@ -0,0 +1,15 @@
+#ifndef I386_STDDEF_H
+#define I386_STDDEF_H
+
+typedef long ptrdiff_t;
+typedef unsigned long size_t;
+typedef long ssize_t;
+
+typedef int wchar_t;
+typedef unsigned int wint_t;
+
+#define NULL 0
+
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+#endif /* I386_STDDEF_H */
diff --git a/src/arch/i386/include/stdint.h b/src/arch/i386/include/stdint.h
new file mode 100644
index 0000000..58d7519
--- /dev/null
+++ b/src/arch/i386/include/stdint.h
@@ -0,0 +1,52 @@
+#ifndef I386_STDINT_H
+#define I386_STDINT_H
+
+/* Exact integral types */
+typedef unsigned char      uint8_t;
+typedef signed char        int8_t; 
+
+typedef unsigned short     uint16_t;
+typedef signed short       int16_t;
+
+typedef unsigned int       uint32_t;
+typedef signed int         int32_t;
+
+typedef unsigned long long uint64_t;
+typedef signed long long   int64_t;
+
+/* Small types */
+typedef unsigned char      uint_least8_t;
+typedef signed char        int_least8_t; 
+
+typedef unsigned short     uint_least16_t;
+typedef signed short       int_least16_t;
+
+typedef unsigned int       uint_least32_t;
+typedef signed int         int_least32_t;
+
+typedef unsigned long long uint_least64_t;
+typedef signed long long   int_least64_t;
+
+/* Fast Types */
+typedef unsigned char      uint_fast8_t;
+typedef signed char        int_fast8_t; 
+
+typedef unsigned int       uint_fast16_t;
+typedef signed int         int_fast16_t;
+
+typedef unsigned int       uint_fast32_t;
+typedef signed int         int_fast32_t;
+
+typedef unsigned long long uint_fast64_t;
+typedef signed long long   int_fast64_t;
+
+/* Types for `void *' pointers.  */
+typedef int                intptr_t;
+typedef unsigned int       uintptr_t;
+
+/* Largest integral types */
+typedef long long int      intmax_t;
+typedef unsigned long long uintmax_t;
+
+
+#endif /* I386_STDINT_H */
diff --git a/src/arch/i386/lib/c_start.S b/src/arch/i386/lib/c_start.S
new file mode 100644
index 0000000..f5ca338
--- /dev/null
+++ b/src/arch/i386/lib/c_start.S
@@ -0,0 +1,135 @@
+#include <arch/asm.h>
+#include <arch/intel.h>
+#ifdef SMP
+#include <cpu/p6/apic.h>
+#endif
+	.section ".text"
+	.code32
+	.globl _start
+_start:
+	cli
+	lgdt	%cs:gdtaddr
+	ljmp	$0x10, $1f
+1:	movl	$0x18, %eax
+	movl	%eax, %ds
+	movl	%eax, %es
+	movl	%eax, %ss
+	movl	%eax, %fs
+	movl	%eax, %gs
+
+	intel_chip_post_macro(0x13)		/* post 12 */
+
+	/** clear stack */
+	leal	EXT(_stack), %edi
+	movl	$EXT(_estack), %ecx
+	subl	%edi, %ecx
+	xorl	%eax, %eax
+	rep
+	stosb
+
+	/** clear bss */
+	leal	EXT(_bss), %edi
+	movl	$EXT(_ebss), %ecx
+	subl	%edi, %ecx
+	jz	.Lnobss
+	xorl	%eax, %eax
+	rep
+	stosb
+.Lnobss:
+
+	/* set new stack */
+	movl	$_estack, %esp
+#ifdef SMP
+	/* Get the cpu id */
+	movl	$APIC_DEFAULT_BASE, %edi
+	movl	APIC_ID(%edi), %eax
+	shrl	$24, %eax
+
+	/* Get the cpu index (MAX_CPUS on error) */
+	movl	$-4, %ebx
+1:	addl	$4, %ebx
+	cmpl	$(MAX_CPUS << 2), %ebx
+	je	2
+	cmpl	%eax, EXT(initial_apicid)(%ebx)
+	jne	1b
+2:	shrl	$2, %ebx
+
+	/* Now compute the appropriate stack */
+	movl	%ebx, %eax
+	movl	$STACK_SIZE, %ebx
+	mull	%ebx
+	subl	%eax, %esp
+#endif
+
+	/* push the boot_complete flag */
+	pushl	%ebp
+
+	/* Save the stack location */
+	movl	%esp, %ebp
+
+	/*
+	 *	Now we are finished. Memory is up, data is copied and
+	 *	bss is cleared.   Now we call the main routine and
+	 *	let it do the rest.
+	 */ 
+	intel_chip_post_macro(0xfe)	/* post fe */
+
+	/* Resort the stack location */
+	movl	%ebp, %esp
+	
+	/* The boot_complete flag has already been pushed */
+	call	EXT(hardwaremain)
+	/*NOTREACHED*/
+.Lhlt:
+	intel_chip_post_macro(0xee)	/* post fe */
+	hlt
+	jmp	.Lhlt
+
+
+	.globl gdt, gdt_end, gdt_limit
+
+gdt_limit = gdt_end - gdt - 1 /* compute the table limit */
+gdtaddr:
+	.word	gdt_limit
+	.long	gdt                /* we know the offset */
+
+gdt:
+// selgdt 0
+	.word	0x0000, 0x0000		/* dummy */
+	.byte	0x00, 0x00, 0x00, 0x00
+
+// selgdt 8
+	.word	0x0000, 0x0000		/* dummy */
+	.byte	0x00, 0x00, 0x00, 0x00
+
+// selgdt 0x10 
+/* flat code segment */
+	.word	0xffff, 0x0000		
+	.byte	0x00, 0x9b, 0xcf, 0x00	
+	
+//selgdt 0x18
+/* flat data segment */
+	.word	0xffff, 0x0000		
+	.byte	0x00, 0x93, 0xcf, 0x00	
+
+//selgdt 0x20
+	.word	0x0000, 0x0000		/* dummy */
+	.byte	0x00, 0x00, 0x00, 0x00
+
+#if defined(CONFIG_VGABIOS) && (CONFIG_VGABIOS == 1)
+	// from monty:
+	/* 0x00009a00,0000ffffULL,   20h: 16-bit 64k code at 0x00000000 */
+        /* 0x00009200,0000ffffULL    28h: 16-bit 64k data at 0x00000000 */
+// selgdt 0x28
+/*16-bit 64k code at 0x00000000 */
+	.word 0xffff, 0x0000
+	.byte 0, 0x9a, 0, 0
+
+// selgdt 0x30
+/*16-bit 64k data at 0x00000000 */
+	.word 0xffff, 0x0000
+	.byte 0, 0x92, 0, 0
+#endif // defined(CONFIG_VGABIOS) && (CONFIG_VGABIOS == 1)
+gdt_end:
+
+.code32
diff --git a/src/arch/i386/lib/console.c b/src/arch/i386/lib/console.c
new file mode 100644
index 0000000..8c8eccd
--- /dev/null
+++ b/src/arch/i386/lib/console.c
@@ -0,0 +1,119 @@
+#include <console/loglevel.h>
+
+static void __console_tx_byte(unsigned char byte)
+{
+	uart_tx_byte(byte);
+}
+
+static void __console_tx_nibble(unsigned nibble)
+{
+	unsigned char digit;
+	digit = nibble + '0';
+	if (digit > '9') {
+		digit += 39;
+	}
+	__console_tx_byte(digit);
+}
+
+static void __console_tx_char(int loglevel, unsigned char byte)
+{
+	if (ASM_CONSOLE_LOGLEVEL > loglevel) {
+		uart_tx_byte(byte);
+	}
+}
+
+static void __console_tx_hex8(int loglevel, unsigned char byte)
+{
+	if (ASM_CONSOLE_LOGLEVEL > loglevel) {
+		__console_tx_nibble(byte >> 4U);
+		__console_tx_nibble(byte & 0x0fU);
+	}
+}
+
+static void __console_tx_hex32(int loglevel, unsigned int value)
+{
+	if (ASM_CONSOLE_LOGLEVEL > loglevel) {
+		__console_tx_nibble((value >> 28U) & 0x0fU);
+		__console_tx_nibble((value >> 24U) & 0x0fU);
+		__console_tx_nibble((value >> 20U) & 0x0fU);
+		__console_tx_nibble((value >> 16U) & 0x0fU);
+		__console_tx_nibble((value >> 12U) & 0x0fU);
+		__console_tx_nibble((value >>  8U) & 0x0fU);
+		__console_tx_nibble((value >>  4U) & 0x0fU);
+		__console_tx_nibble(value & 0x0fU);
+	}
+}
+
+static void __console_tx_string(int loglevel, const char *str)
+{
+	if (ASM_CONSOLE_LOGLEVEL > loglevel) {
+		unsigned char ch;
+		while((ch = *str++) != '\0') {
+			__console_tx_byte(ch);
+		}
+	}
+}
+
+static void print_emerg_char(unsigned char byte) { __console_tx_char(BIOS_EMERG, byte); }
+static void print_emerg_hex8(unsigned char value){ __console_tx_hex8(BIOS_EMERG, value); }
+static void print_emerg_hex32(unsigned int value) { __console_tx_hex32(BIOS_EMERG, value); }
+static void print_emerg(const char *str) { __console_tx_string(BIOS_EMERG, str); }
+
+static void print_alert_char(unsigned char byte) { __console_tx_char(BIOS_ALERT, byte); }
+static void print_alert_hex8(unsigned char value) { __console_tx_hex8(BIOS_ALERT, value); }
+static void print_alert_hex32(unsigned int value) { __console_tx_hex32(BIOS_ALERT, value); }
+static void print_alert(const char *str) { __console_tx_string(BIOS_ALERT, str); }
+
+static void print_crit_char(unsigned char byte) { __console_tx_char(BIOS_CRIT, byte); }
+static void print_crit_hex8(unsigned char value) { __console_tx_hex8(BIOS_CRIT, value); }
+static void print_crit_hex32(unsigned int value) { __console_tx_hex32(BIOS_CRIT, value); }
+static void print_crit(const char *str) { __console_tx_string(BIOS_CRIT, str); }
+
+static void print_err_char(unsigned char byte) { __console_tx_char(BIOS_ERR, byte); }
+static void print_err_hex8(unsigned char value) { __console_tx_hex8(BIOS_ERR, value); }
+static void print_err_hex32(unsigned int value) { __console_tx_hex32(BIOS_ERR, value); }
+static void print_err(const char *str) { __console_tx_string(BIOS_ERR, str); }
+
+static void print_warning_char(unsigned char byte) { __console_tx_char(BIOS_WARNING, byte); }
+static void print_warning_hex8(unsigned char value) { __console_tx_hex8(BIOS_WARNING, value); }
+static void print_warning_hex32(unsigned int value) { __console_tx_hex32(BIOS_WARNING, value); }
+static void print_warning(const char *str) { __console_tx_string(BIOS_WARNING, str); }
+
+static void print_notice_char(unsigned char byte) { __console_tx_char(BIOS_NOTICE, byte); }
+static void print_notice_hex8(unsigned char value) { __console_tx_hex8(BIOS_NOTICE, value); }
+static void print_notice_hex32(unsigned int value) { __console_tx_hex32(BIOS_NOTICE, value); }
+static void print_notice(const char *str) { __console_tx_string(BIOS_NOTICE, str); }
+
+static void print_info_char(unsigned char byte) { __console_tx_char(BIOS_INFO, byte); }
+static void print_info_hex8(unsigned char value) { __console_tx_hex8(BIOS_INFO, value); }
+static void print_info_hex32(unsigned int value) { __console_tx_hex32(BIOS_INFO, value); }
+static void print_info(const char *str) { __console_tx_string(BIOS_INFO, str); }
+
+static void print_debug_char(unsigned char byte) { __console_tx_char(BIOS_DEBUG, byte); }
+static void print_debug_hex8(unsigned char value) { __console_tx_hex8(BIOS_DEBUG, value); }
+static void print_debug_hex32(unsigned int value) { __console_tx_hex32(BIOS_DEBUG, value); }
+static void print_debug(const char *str) { __console_tx_string(BIOS_DEBUG, str); }
+
+static void print_spew_char(unsigned char byte) { __console_tx_char(BIOS_SPEW, byte); }
+static void print_spew_hex8(unsigned char value) { __console_tx_hex8(BIOS_SPEW, value); }
+static void print_spew_hex32(unsigned int value) { __console_tx_hex32(BIOS_SPEW, value); }
+static void print_spew(const char *str) { __console_tx_string(BIOS_SPEW, str); }
+
+#define __STR(X) #X
+#define STR(X) __STR(X)
+
+#ifndef LINUXBIOS_EXTRA_VERSION
+#define LINUXBIOS_EXTRA_VERSION
+#endif
+
+static void console_init(void)
+{
+	static const char console_test[] = 
+		"\r\n\r\nLinuxBIOS-"
+		STR(LINUXBIOS_VERSION)
+		STR(LINUXBIOS_EXTRA_VERSION)
+		" "
+		STR(LINUXBIOS_BUILD)
+		" starting...\r\n";
+	print_info(console_test);
+}
diff --git a/src/arch/i386/lib/console.inc b/src/arch/i386/lib/console.inc
new file mode 100644
index 0000000..3d6b01b
--- /dev/null
+++ b/src/arch/i386/lib/console.inc
@@ -0,0 +1,527 @@
+#include <console/loglevel.h>
+
+jmp	console0
+
+#define __STR(X) #X
+#define STR(X) __STR(X)
+
+#ifndef  LINUXBIOS_EXTRA_VERSION
+#define LINUXBIOS_EXTRA_VERSION
+#endif
+
+console_test:
+	.ascii	"\r\n\r\nLinuxBIOS-"
+	.ascii	STR(LINUXBIOS_VERSION)
+	.ascii	STR(LINUXBIOS_EXTRA_VERSION)
+	.ascii	" "
+	.ascii	STR(LINUXBIOS_BUILD)
+	.asciz	" starting...\r\n"
+
+#undef STR
+	/* uses:	ax, dx */
+#if CONFIG_CONSOLE_SERIAL8250
+#define __CONSOLE_INLINE_TX_AL TTYS0_TX_AL
+#else
+#define __CONSOLE_INLINE_TX_AL
+#endif
+
+	/* uses:	esp, ax, dx */
+#define __CONSOLE_TX_CHAR(byte)	\
+	mov	byte, %al	; \
+	CALLSP(console_tx_al)
+
+	/* uses:	 ax, dx */
+#define __CONSOLE_INLINE_TX_CHAR(byte)	\
+	mov	byte, %al	; \
+	__CONSOLE_INLINE_TX_AL
+
+	/* uses:	esp, ax, edx */
+#define __CONSOLE_TX_HEX8(byte)	\
+	mov	byte, %al	; \
+	CALLSP(console_tx_hex8)
+
+	/* uses:	 byte, ax, dx */
+#define __CONSOLE_INLINE_TX_HEX8(byte)	\
+	movb	byte, %dl	; \
+	shll	$16, %edx	; \
+	shr	$4, %al		; \
+	add	$'0', %al	; \
+	cmp	$'9', %al	; \
+	jle	9f		; \
+	add	$39, %al	; \
+9:				; \
+	__CONSOLE_INLINE_TX_AL	; \
+	shrl	$16, %edx	; \
+	movb	%dl, %al	; \
+	and	$0x0f, %al	; \
+	add	$'0', %al	; \
+	cmp	$'9', %al	; \
+	jle	9f		; \
+	add	$39, %al	; \
+9:				; \
+	__CONSOLE_INLINE_TX_AL
+
+	/* uses:	esp, eax, ebx, dx */
+#define __CONSOLE_TX_HEX32(lword)	\
+	mov	lword, %eax	; \
+	CALLSP(console_tx_hex32)
+
+	/* uses:	eax, lword, dx */
+#define __CONSOLE_INLINE_TX_HEX32(lword)	\
+	mov	lword, %eax	; \
+	shr	$28, %eax	; \
+	add	$'0', %al	; \
+	cmp	$'9', %al	; \
+	jle	9f		; \
+	add	$39, %al	; \
+9:				; \
+	__CONSOLE_INLINE_TX_AL		; \
+				; \
+	mov	lword, %eax	; \
+	shr	$24, %eax	; \
+	and	$0x0f, %al	; \
+	add	$'0', %al	; \
+	cmp	$'9', %al	; \
+	jle	9f		; \
+	add	$39, %al	; \
+9:				; \
+	__CONSOLE_INLINE_TX_AL		; \
+				; \
+	mov	lword, %eax	; \
+	shr	$20, %eax	; \
+	and	$0x0f, %al	; \
+	add	$'0', %al	; \
+	cmp	$'9', %al	; \
+	jle	9f		; \
+	add	$39, %al	; \
+9:				; \
+	__CONSOLE_INLINE_TX_AL		; \
+				; \
+	mov	lword, %eax	; \
+	shr	$16, %eax	; \
+	and	$0x0f, %al	; \
+	add	$'0', %al	; \
+	cmp	$'9', %al	; \
+	jle	9f		; \
+	add	$39, %al	; \
+9:				; \
+	__CONSOLE_INLINE_TX_AL		; \
+				; \
+	mov	lword, %eax	; \
+	shr	$12, %eax	; \
+	and	$0x0f, %al	; \
+	add	$'0', %al	; \
+	cmp	$'9', %al	; \
+	jle	9f		; \
+	add	$39, %al	; \
+9:				; \
+	__CONSOLE_INLINE_TX_AL		; \
+				; \
+	mov	lword, %eax	; \
+	shr	$8, %eax	; \
+	and	$0x0f, %al	; \
+	add	$'0', %al	; \
+	cmp	$'9', %al	; \
+	jle	9f		; \
+	add	$39, %al	; \
+9:				; \
+	__CONSOLE_INLINE_TX_AL		; \
+				; \
+	mov	lword, %eax	; \
+	shr	$4, %eax	; \
+	and	$0x0f, %al	; \
+	add	$'0', %al	; \
+	cmp	$'9', %al	; \
+	jle	9f		; \
+	add	$39, %al	; \
+9:				; \
+	__CONSOLE_INLINE_TX_AL		; \
+				; \
+	mov	lword, %eax	; \
+	and	$0x0f, %al	; \
+	add	$'0', %al	; \
+	cmp	$'9', %al	; \
+	jle	9f		; \
+	add	$39, %al	; \
+9:				; \
+	__CONSOLE_INLINE_TX_AL
+
+
+	/* uses:	 esp, ebx, ax, dx */
+#define __CONSOLE_TX_STRING(string)	\
+	mov	string, %ebx	; \
+	CALLSP(console_tx_string)
+
+	/* uses:	 ebx, ax, dx */
+#define __CONSOLE_INLINE_TX_STRING(string)	\
+	movl	string, %ebx	; \
+10:	movb	(%ebx), %al	; \
+	incl	%ebx		; \
+	testb	%al, %al	; \
+	jz	11f		; \
+	__CONSOLE_INLINE_TX_AL	; \
+	jmp	10b		; \
+11:	
+
+
+#define CONSOLE_EMERG_TX_CHAR(byte)            __CONSOLE_TX_CHAR(byte)
+#define CONSOLE_EMERG_INLINE_TX_CHAR(byte)     __CONSOLE_INLINE_TX_CHAR(byte)
+#define CONSOLE_EMERG_TX_HEX8(byte)            __CONSOLE_TX_HEX8(byte)
+#define CONSOLE_EMERG_INLINE_TX_HEX8(byte)     __CONSOLE_INLINE_TX_HEX8(byte)
+#define CONSOLE_EMERG_TX_HEX32(lword)          __CONSOLE_TX_HEX32(lword)
+#define CONSOLE_EMERG_INLINE_TX_HEX32(lword)   __CONSOLE_INLINE_TX_HEX32(lword)
+#define CONSOLE_EMERG_TX_STRING(string)        __CONSOLE_TX_STRING(string)
+#define CONSOLE_EMERG_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string)
+
+#define CONSOLE_ALERT_TX_CHAR(byte)            __CONSOLE_TX_CHAR(byte)
+#define CONSOLE_ALERT_INLINE_TX_CHAR(byte)     __CONSOLE_INLINE_TX_CHAR(byte)
+#define CONSOLE_ALERT_TX_HEX8(byte)            __CONSOLE_TX_HEX8(byte)
+#define CONSOLE_ALERT_INLINE_TX_HEX8(byte)     __CONSOLE_INLINE_TX_HEX8(byte)
+#define CONSOLE_ALERT_TX_HEX32(lword)          __CONSOLE_TX_HEX32(lword)
+#define CONSOLE_ALERT_INLINE_TX_HEX32(lword)   __CONSOLE_INLINE_TX_HEX32(lword)
+#define CONSOLE_ALERT_TX_STRING(string)        __CONSOLE_TX_STRING(string)
+#define CONSOLE_ALERT_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string)
+
+#define CONSOLE_CRIT_TX_CHAR(byte)            __CONSOLE_TX_CHAR(byte)
+#define CONSOLE_CRIT_INLINE_TX_CHAR(byte)     __CONSOLE_INLINE_TX_CHAR(byte)
+#define CONSOLE_CRIT_TX_HEX8(byte)            __CONSOLE_TX_HEX8(byte)
+#define CONSOLE_CRIT_INLINE_TX_HEX8(byte)     __CONSOLE_INLINE_TX_HEX8(byte)
+#define CONSOLE_CRIT_TX_HEX32(lword)          __CONSOLE_TX_HEX32(lword)
+#define CONSOLE_CRIT_INLINE_TX_HEX32(lword)   __CONSOLE_INLINE_TX_HEX32(lword)
+#define CONSOLE_CRIT_TX_STRING(string)        __CONSOLE_TX_STRING(string)
+#define CONSOLE_CRIT_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string)
+
+#define CONSOLE_ERR_TX_CHAR(byte)            __CONSOLE_TX_CHAR(byte)
+#define CONSOLE_ERR_INLINE_TX_CHAR(byte)     __CONSOLE_INLINE_TX_CHAR(byte)
+#define CONSOLE_ERR_TX_HEX8(byte)            __CONSOLE_TX_HEX8(byte)
+#define CONSOLE_ERR_INLINE_TX_HEX8(byte)     __CONSOLE_INLINE_TX_HEX8(byte)
+#define CONSOLE_ERR_TX_HEX32(lword)          __CONSOLE_TX_HEX32(lword)
+#define CONSOLE_ERR_INLINE_TX_HEX32(lword)   __CONSOLE_INLINE_TX_HEX32(lword)
+#define CONSOLE_ERR_TX_STRING(string)        __CONSOLE_TX_STRING(string)
+#define CONSOLE_ERR_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string)
+
+#define CONSOLE_WARNING_TX_CHAR(byte)            __CONSOLE_TX_CHAR(byte)
+#define CONSOLE_WARNING_INLINE_TX_CHAR(byte)     __CONSOLE_INLINE_TX_CHAR(byte)
+#define CONSOLE_WARNING_TX_HEX8(byte)            __CONSOLE_TX_HEX8(byte)
+#define CONSOLE_WARNING_INLINE_TX_HEX8(byte)     __CONSOLE_INLINE_TX_HEX8(byte)
+#define CONSOLE_WARNING_TX_HEX32(lword)          __CONSOLE_TX_HEX32(lword)
+#define CONSOLE_WARNING_INLINE_TX_HEX32(lword)   __CONSOLE_INLINE_TX_HEX32(lword)
+#define CONSOLE_WARNING_TX_STRING(string)        __CONSOLE_TX_STRING(string)
+#define CONSOLE_WARNING_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string)
+
+#define CONSOLE_NOTICE_TX_CHAR(byte)            __CONSOLE_TX_CHAR(byte)
+#define CONSOLE_NOTICE_INLINE_TX_CHAR(byte)     __CONSOLE_INLINE_TX_CHAR(byte)
+#define CONSOLE_NOTICE_TX_HEX8(byte)            __CONSOLE_TX_HEX8(byte)
+#define CONSOLE_NOTICE_INLINE_TX_HEX8(byte)     __CONSOLE_INLINE_TX_HEX8(byte)
+#define CONSOLE_NOTICE_TX_HEX32(lword)          __CONSOLE_TX_HEX32(lword)
+#define CONSOLE_NOTICE_INLINE_TX_HEX32(lword)   __CONSOLE_INLINE_TX_HEX32(lword)
+#define CONSOLE_NOTICE_TX_STRING(string)        __CONSOLE_TX_STRING(string)
+#define CONSOLE_NOTICE_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string)
+
+#define CONSOLE_INFO_TX_CHAR(byte)            __CONSOLE_TX_CHAR(byte)
+#define CONSOLE_INFO_INLINE_TX_CHAR(byte)     __CONSOLE_INLINE_TX_CHAR(byte)
+#define CONSOLE_INFO_TX_HEX8(byte)            __CONSOLE_TX_HEX8(byte)
+#define CONSOLE_INFO_INLINE_TX_HEX8(byte)     __CONSOLE_INLINE_TX_HEX8(byte)
+#define CONSOLE_INFO_TX_HEX32(lword)          __CONSOLE_TX_HEX32(lword)
+#define CONSOLE_INFO_INLINE_TX_HEX32(lword)   __CONSOLE_INLINE_TX_HEX32(lword)
+#define CONSOLE_INFO_TX_STRING(string)        __CONSOLE_TX_STRING(string)
+#define CONSOLE_INFO_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string)
+
+#define CONSOLE_DEBUG_TX_CHAR(byte)            __CONSOLE_TX_CHAR(byte)
+#define CONSOLE_DEBUG_INLINE_TX_CHAR(byte)     __CONSOLE_INLINE_TX_CHAR(byte)
+#define CONSOLE_DEBUG_TX_HEX8(byte)            __CONSOLE_TX_HEX8(byte)
+#define CONSOLE_DEBUG_INLINE_TX_HEX8(byte)     __CONSOLE_INLINE_TX_HEX8(byte)
+#define CONSOLE_DEBUG_TX_HEX32(lword)          __CONSOLE_TX_HEX32(lword)
+#define CONSOLE_DEBUG_INLINE_TX_HEX32(lword)   __CONSOLE_INLINE_TX_HEX32(lword)
+#define CONSOLE_DEBUG_TX_STRING(string)        __CONSOLE_TX_STRING(string)
+#define CONSOLE_DEBUG_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string)
+
+#define CONSOLE_SPEW_TX_CHAR(byte)            __CONSOLE_TX_CHAR(byte)
+#define CONSOLE_SPEW_INLINE_TX_CHAR(byte)     __CONSOLE_INLINE_TX_CHAR(byte)
+#define CONSOLE_SPEW_TX_HEX8(byte)            __CONSOLE_TX_HEX8(byte)
+#define CONSOLE_SPEW_INLINE_TX_HEX8(byte)     __CONSOLE_INLINE_TX_HEX8(byte)
+#define CONSOLE_SPEW_TX_HEX32(lword)          __CONSOLE_TX_HEX32(lword)
+#define CONSOLE_SPEW_INLINE_TX_HEX32(lword)   __CONSOLE_INLINE_TX_HEX32(lword)
+#define CONSOLE_SPEW_TX_STRING(string)        __CONSOLE_TX_STRING(string)
+#define CONSOLE_SPEW_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string)
+
+#if ASM_CONSOLE_LOGLEVEL <= BIOS_EMERG
+#undef  CONSOLE_EMERG_TX_CHAR
+#undef  CONSOLE_EMERG_INLINE_TX_CHAR
+#undef  CONSOLE_EMERG_TX_HEX8
+#undef  CONSOLE_EMERG_INLINE_TX_HEX8
+#undef  CONSOLE_EMERG_TX_HEX32
+#undef  CONSOLE_EMERG_INLINE_TX_HEX32
+#undef  CONSOLE_EMERG_TX_STRING
+#undef  CONSOLE_EMERG_INLINE_TX_STRING
+#define CONSOLE_EMERG_TX_CHAR(byte)            
+#define CONSOLE_EMERG_INLINE_TX_CHAR(byte)     
+#define CONSOLE_EMERG_TX_HEX8(byte)            
+#define CONSOLE_EMERG_INLINE_TX_HEX8(byte)     
+#define CONSOLE_EMERG_TX_HEX32(lword)          
+#define CONSOLE_EMERG_INLINE_TX_HEX32(lword)   
+#define CONSOLE_EMERG_TX_STRING(string)        
+#define CONSOLE_EMERG_INLINE_TX_STRING(string) 
+#endif
+
+
+#if ASM_CONSOLE_LOGLEVEL <= BIOS_ALERT
+#undef  CONSOLE_ALERT_TX_CHAR
+#undef  CONSOLE_ALERT_INLINE_TX_CHAR
+#undef  CONSOLE_ALERT_TX_HEX8
+#undef  CONSOLE_ALERT_INLINE_TX_HEX8
+#undef  CONSOLE_ALERT_TX_HEX32
+#undef  CONSOLE_ALERT_INLINE_TX_HEX32
+#undef  CONSOLE_ALERT_TX_STRING
+#undef  CONSOLE_ALERT_INLINE_TX_STRING
+#define CONSOLE_ALERT_TX_CHAR(byte)            
+#define CONSOLE_ALERT_INLINE_TX_CHAR(byte)     
+#define CONSOLE_ALERT_TX_HEX8(byte)            
+#define CONSOLE_ALERT_INLINE_TX_HEX8(byte)     
+#define CONSOLE_ALERT_TX_HEX32(lword)          
+#define CONSOLE_ALERT_INLINE_TX_HEX32(lword)   
+#define CONSOLE_ALERT_TX_STRING(string)        
+#define CONSOLE_ALERT_INLINE_TX_STRING(string) 
+#endif
+
+#if ASM_CONSOLE_LOGLEVEL <= BIOS_CRIT
+#undef  CONSOLE_CRIT_TX_CHAR
+#undef  CONSOLE_CRIT_INLINE_TX_CHAR
+#undef  CONSOLE_CRIT_TX_HEX8
+#undef  CONSOLE_CRIT_INLINE_TX_HEX8
+#undef  CONSOLE_CRIT_TX_HEX32
+#undef  CONSOLE_CRIT_INLINE_TX_HEX32
+#undef  CONSOLE_CRIT_TX_STRING
+#undef  CONSOLE_CRIT_INLINE_TX_STRING
+#define CONSOLE_CRIT_TX_CHAR(byte)            
+#define CONSOLE_CRIT_INLINE_TX_CHAR(byte)     
+#define CONSOLE_CRIT_TX_HEX8(byte)            
+#define CONSOLE_CRIT_INLINE_TX_HEX8(byte)     
+#define CONSOLE_CRIT_TX_HEX32(lword)          
+#define CONSOLE_CRIT_INLINE_TX_HEX32(lword)   
+#define CONSOLE_CRIT_TX_STRING(string)        
+#define CONSOLE_CRIT_INLINE_TX_STRING(string) 
+#endif
+
+#if ASM_CONSOLE_LOGLEVEL <= BIOS_ERR
+#undef  CONSOLE_ERR_TX_CHAR
+#undef  CONSOLE_ERR_INLINE_TX_CHAR
+#undef  CONSOLE_ERR_TX_HEX8
+#undef  CONSOLE_ERR_INLINE_TX_HEX8
+#undef  CONSOLE_ERR_TX_HEX32
+#undef  CONSOLE_ERR_INLINE_TX_HEX32
+#undef  CONSOLE_ERR_TX_STRING
+#undef  CONSOLE_ERR_INLINE_TX_STRING
+#define CONSOLE_ERR_TX_CHAR(byte)            
+#define CONSOLE_ERR_INLINE_TX_CHAR(byte)     
+#define CONSOLE_ERR_TX_HEX8(byte)            
+#define CONSOLE_ERR_INLINE_TX_HEX8(byte)     
+#define CONSOLE_ERR_TX_HEX32(lword)          
+#define CONSOLE_ERR_INLINE_TX_HEX32(lword)   
+#define CONSOLE_ERR_TX_STRING(string)        
+#define CONSOLE_ERR_INLINE_TX_STRING(string) 
+#endif
+
+#if ASM_CONSOLE_LOGLEVEL <= BIOS_WARNING
+#undef  CONSOLE_WARNING_TX_CHAR
+#undef  CONSOLE_WARNING_INLINE_TX_CHAR
+#undef  CONSOLE_WARNING_TX_HEX8
+#undef  CONSOLE_WARNING_INLINE_TX_HEX8
+#undef  CONSOLE_WARNING_TX_HEX32
+#undef  CONSOLE_WARNING_INLINE_TX_HEX32
+#undef  CONSOLE_WARNING_TX_STRING
+#undef  CONSOLE_WARNING_INLINE_TX_STRING
+#define CONSOLE_WARNING_TX_CHAR(byte)            
+#define CONSOLE_WARNING_INLINE_TX_CHAR(byte)     
+#define CONSOLE_WARNING_TX_HEX8(byte)            
+#define CONSOLE_WARNING_INLINE_TX_HEX8(byte)     
+#define CONSOLE_WARNING_TX_HEX32(lword)          
+#define CONSOLE_WARNING_INLINE_TX_HEX32(lword)   
+#define CONSOLE_WARNING_TX_STRING(string)        
+#define CONSOLE_WARNING_INLINE_TX_STRING(string) 
+#endif
+
+#if ASM_CONSOLE_LOGLEVEL <= BIOS_NOTICE
+#undef  CONSOLE_NOTICE_TX_CHAR
+#undef  CONSOLE_NOTICE_INLINE_TX_CHAR
+#undef  CONSOLE_NOTICE_TX_HEX8
+#undef  CONSOLE_NOTICE_INLINE_TX_HEX8
+#undef  CONSOLE_NOTICE_TX_HEX32
+#undef  CONSOLE_NOTICE_INLINE_TX_HEX32
+#undef  CONSOLE_NOTICE_TX_STRING
+#undef  CONSOLE_NOTICE_INLINE_TX_STRING
+#define CONSOLE_NOTICE_TX_CHAR(byte)            
+#define CONSOLE_NOTICE_INLINE_TX_CHAR(byte)     
+#define CONSOLE_NOTICE_TX_HEX8(byte)            
+#define CONSOLE_NOTICE_INLINE_TX_HEX8(byte)     
+#define CONSOLE_NOTICE_TX_HEX32(lword)          
+#define CONSOLE_NOTICE_INLINE_TX_HEX32(lword)   
+#define CONSOLE_NOTICE_TX_STRING(string)        
+#define CONSOLE_NOTICE_INLINE_TX_STRING(string) 
+#endif
+
+#if ASM_CONSOLE_LOGLEVEL <= BIOS_INFO
+#undef  CONSOLE_INFO_TX_CHAR
+#undef  CONSOLE_INFO_INLINE_TX_CHAR
+#undef  CONSOLE_INFO_TX_HEX8
+#undef  CONSOLE_INFO_INLINE_TX_HEX8
+#undef  CONSOLE_INFO_TX_HEX32
+#undef  CONSOLE_INFO_INLINE_TX_HEX32
+#undef  CONSOLE_INFO_TX_STRING
+#undef  CONSOLE_INFO_INLINE_TX_STRING
+#define CONSOLE_INFO_TX_CHAR(byte)            
+#define CONSOLE_INFO_INLINE_TX_CHAR(byte)     
+#define CONSOLE_INFO_TX_HEX8(byte)            
+#define CONSOLE_INFO_INLINE_TX_HEX8(byte)     
+#define CONSOLE_INFO_TX_HEX32(lword)          
+#define CONSOLE_INFO_INLINE_TX_HEX32(lword)   
+#define CONSOLE_INFO_TX_STRING(string)        
+#define CONSOLE_INFO_INLINE_TX_STRING(string) 
+#endif
+
+#if ASM_CONSOLE_LOGLEVEL <= BIOS_DEBUG
+#undef  CONSOLE_DEBUG_TX_CHAR
+#undef  CONSOLE_DEBUG_INLINE_TX_CHAR
+#undef  CONSOLE_DEBUG_TX_HEX8
+#undef  CONSOLE_DEBUG_INLINE_TX_HEX8
+#undef  CONSOLE_DEBUG_TX_HEX32
+#undef  CONSOLE_DEBUG_INLINE_TX_HEX32
+#undef  CONSOLE_DEBUG_TX_STRING
+#undef  CONSOLE_DEBUG_INLINE_TX_STRING
+#define CONSOLE_DEBUG_TX_CHAR(byte)            
+#define CONSOLE_DEBUG_INLINE_TX_CHAR(byte)     
+#define CONSOLE_DEBUG_TX_HEX8(byte)            
+#define CONSOLE_DEBUG_INLINE_TX_HEX8(byte)     
+#define CONSOLE_DEBUG_TX_HEX32(lword)          
+#define CONSOLE_DEBUG_INLINE_TX_HEX32(lword)   
+#define CONSOLE_DEBUG_TX_STRING(string)        
+#define CONSOLE_DEBUG_INLINE_TX_STRING(string) 
+#endif
+
+#if ASM_CONSOLE_LOGLEVEL <= BIOS_SPEW
+#undef  CONSOLE_SPEW_TX_CHAR
+#undef  CONSOLE_SPEW_INLINE_TX_CHAR
+#undef  CONSOLE_SPEW_TX_HEX8
+#undef  CONSOLE_SPEW_INLINE_TX_HEX8
+#undef  CONSOLE_SPEW_TX_HEX32
+#undef  CONSOLE_SPEW_INLINE_TX_HEX32
+#undef  CONSOLE_SPEW_TX_STRING
+#undef  CONSOLE_SPEW_INLINE_TX_STRING
+#define CONSOLE_SPEW_TX_CHAR(byte)            
+#define CONSOLE_SPEW_INLINE_TX_CHAR(byte)     
+#define CONSOLE_SPEW_TX_HEX8(byte)            
+#define CONSOLE_SPEW_INLINE_TX_HEX8(byte)     
+#define CONSOLE_SPEW_TX_HEX32(lword)          
+#define CONSOLE_SPEW_INLINE_TX_HEX32(lword)   
+#define CONSOLE_SPEW_TX_STRING(string)        
+#define CONSOLE_SPEW_INLINE_TX_STRING(string) 
+#endif
+
+
+	/* uses:	esp, ax, dx */
+console_tx_al:	
+	__CONSOLE_INLINE_TX_AL
+	RETSP
+
+	/* uses:	 esp, ax, edx */
+console_tx_hex8:
+	__CONSOLE_INLINE_TX_HEX8(%al)
+	RETSP
+
+
+	/* uses:	 esp, ebx, eax, dx */
+console_tx_hex32:
+	mov	%eax, %ebx
+	shr	$28, %eax
+	add	$'0', %al
+	cmp	$'9', %al
+	jle	9f
+	add	$39, %al
+9:
+	__CONSOLE_INLINE_TX_AL
+
+	mov	%ebx, %eax
+	shr	$24, %eax
+	and	$0x0f, %al
+	add	$'0', %al
+	cmp	$'9', %al
+	jle	9f
+	add	$39, %al
+9:
+	__CONSOLE_INLINE_TX_AL
+
+	mov	%ebx, %eax
+	shr	$20, %eax
+	and	$0x0f, %al
+	add	$'0', %al
+	cmp	$'9', %al
+	jle	9f
+	add	$39, %al
+9:
+	__CONSOLE_INLINE_TX_AL
+
+	mov	%ebx, %eax
+	shr	$16, %eax
+	and	$0x0f, %al
+	add	$'0', %al
+	cmp	$'9', %al
+	jle	9f
+	add	$39, %al
+9:
+	__CONSOLE_INLINE_TX_AL
+
+	mov	%ebx, %eax
+	shr	$12, %eax
+	and	$0x0f, %al
+	add	$'0', %al
+	cmp	$'9', %al
+	jle	9f
+	add	$39, %al
+9:
+	__CONSOLE_INLINE_TX_AL
+
+	mov	%ebx, %eax
+	shr	$8, %eax
+	and	$0x0f, %al
+	add	$'0', %al
+	cmp	$'9', %al
+	jle	9f
+	add	$39, %al
+9:
+	__CONSOLE_INLINE_TX_AL
+
+	mov	%ebx, %eax
+	shr	$4, %eax
+	and	$0x0f, %al
+	add	$'0', %al
+	cmp	$'9', %al
+	jle	9f
+	add	$39, %al
+9:
+	__CONSOLE_INLINE_TX_AL
+
+	mov	%ebx, %eax
+	and	$0x0f, %al
+	add	$'0', %al
+	cmp	$'9', %al
+	jle	9f
+	add	$39, %al
+9:
+	__CONSOLE_INLINE_TX_AL
+	RETSP
+
+	/* Uses esp, ebx, ax, dx  */
+
+console_tx_string:
+	mov	(%ebx), %al
+	inc	%ebx
+	cmp	$0, %al
+	jne	9f
+	RETSP
+9:	
+	__CONSOLE_INLINE_TX_AL
+	jmp	console_tx_string
+
+console0:
+	CONSOLE_INFO_TX_STRING($console_test)
+
diff --git a/src/arch/i386/lib/cpu.c b/src/arch/i386/lib/cpu.c
new file mode 100644
index 0000000..3e27e7a
--- /dev/null
+++ b/src/arch/i386/lib/cpu.c
@@ -0,0 +1,139 @@
+#include <console/console.h>
+#include <cpu/cpu.h>
+#include <mem.h>
+#include <arch/io.h>
+#include <string.h>
+#include <cpu/cpufixup.h>
+#include <smp/start_stop.h>
+#include <cpu/cpufixup.h>
+#include <cpu/p6/mtrr.h>
+#include <cpu/p6/msr.h>
+#include <cpu/p6/apic.h>
+#include <cpu/p5/cpuid.h>
+#if 0
+#include <cpu/l2_cache.h>
+#endif
+
+#if CONFIG_SMP || CONFIG_IOAPIC
+#define APIC 1
+#endif
+
+static void cache_on(struct mem_range *mem)
+{
+	post_code(0x60);
+	printk_info("Enabling cache...");
+
+
+	/* we need an #ifdef i586 here at some point ... */
+	__asm__ __volatile__("mov %cr0, %eax\n\t"
+			     "and $0x9fffffff,%eax\n\t"
+			     "mov %eax, %cr0\n\t");
+	/* turns out cache isn't really on until you set MTRR registers on 
+	 * 686 and later. 
+	 * NOTHING FANCY. Linux does a much better job anyway. 
+	 * so absolute minimum needed to get it going. 
+	 */
+	/* OK, linux it turns out does nothing. We have to do it ... */
+#if defined(i686) 
+	// totalram here is in linux sizing, i.e. units of KB. 
+	// set_mtrr is responsible for getting it into the right units!
+	setup_mtrrs(mem);
+#endif
+
+	post_code(0x6A);
+	printk_info("done.\n");
+}
+
+static void interrupts_on()
+{
+	/* this is so interrupts work. This is very limited scope -- 
+	 * linux will do better later, we hope ...
+	 */
+	/* this is the first way we learned to do it. It fails on real SMP 
+	 * stuff. So we have to do things differently ... 
+	 * see the Intel mp1.4 spec, page A-3
+	 */
+
+#if defined(APIC)
+	/* Only Pentium Pro and later have those MSR stuff */
+	unsigned long low, high;
+
+	printk_info("Setting up local apic...");
+
+	/* Enable the local apic */
+	rdmsr(APIC_BASE_MSR, low, high);
+	low |= APIC_BASE_MSR_ENABLE;
+	low &= ~APIC_BASE_MSR_ADDR_MASK;
+	low |= APIC_DEFAULT_BASE;
+	wrmsr(APIC_BASE_MSR, low, high);
+
+
+	/* Put the local apic in virtual wire mode */
+	apic_write_around(APIC_SPIV, 
+		(apic_read_around(APIC_SPIV) & ~(APIC_VECTOR_MASK))
+		| APIC_SPIV_ENABLE);
+	apic_write_around(APIC_LVT0, 
+		(apic_read_around(APIC_LVT0) & 
+			~(APIC_LVT_MASKED | APIC_LVT_LEVEL_TRIGGER | 
+				APIC_LVT_REMOTE_IRR | APIC_INPUT_POLARITY | 
+				APIC_SEND_PENDING |APIC_LVT_RESERVED_1 |
+				APIC_DELIVERY_MODE_MASK))
+		| (APIC_LVT_REMOTE_IRR |APIC_SEND_PENDING | 
+			APIC_DELIVERY_MODE_EXTINT)
+		);
+	apic_write_around(APIC_LVT1, 
+		(apic_read_around(APIC_LVT1) & 
+			~(APIC_LVT_MASKED | APIC_LVT_LEVEL_TRIGGER | 
+				APIC_LVT_REMOTE_IRR | APIC_INPUT_POLARITY | 
+				APIC_SEND_PENDING |APIC_LVT_RESERVED_1 |
+				APIC_DELIVERY_MODE_MASK))
+		| (APIC_LVT_REMOTE_IRR |APIC_SEND_PENDING | 
+			APIC_DELIVERY_MODE_NMI)
+		);
+#else /* APIC */
+#ifdef i686
+	/* Only Pentium Pro and later have those MSR stuff */
+	unsigned long low, high;
+
+	printk_info("Disabling local apic...");
+
+	rdmsr(APIC_BASE_MSR, low, high);
+	low &= ~APIC_BASE_MSR_ENABLE;
+	wrmsr(APIC_BASE_MSR, low, high);
+#endif /* i686 */
+#endif /* APIC */
+	printk_info("done.\n");
+	post_code(0x9b);
+}
+
+unsigned long cpu_initialize(struct mem_range *mem)
+{
+	/* Because we busy wait at the printk spinlock.
+	 * It is important to keep the number of printed messages
+	 * from secondary cpus to a minimum, when debugging is
+	 * disabled.
+	 */
+	unsigned long processor_id = this_processors_id();
+	printk_notice("Initializing CPU #%d\n", processor_id);
+	
+	/* some cpus need a fixup done. This is the hook for doing that. */
+	cpufixup(mem);
+
+	/* Turn on caching if we haven't already */
+	cache_on(mem);
+
+	display_cpuid();
+	mtrr_check();
+
+#if 0
+	/* now that everything is really up, enable the l2 cache if desired. 
+	 * The enable can wait until this point, because linuxbios and it's
+	 * data areas are tiny, easily fitting into the L1 cache. 
+	 */
+	configure_l2_cache();
+#endif
+	interrupts_on();
+	printk_info("CPU #%d Initialized\n", processor_id);
+	return processor_id;
+}
+
diff --git a/src/arch/i386/lib/cpu_reset.inc b/src/arch/i386/lib/cpu_reset.inc
new file mode 100644
index 0000000..c7c05e2
--- /dev/null
+++ b/src/arch/i386/lib/cpu_reset.inc
@@ -0,0 +1,9 @@
+jmp cpu_reset_out
+
+__cpu_reset:
+	movl	$0xffffffff, %ebp
+	jmp	__main
+
+cpu_reset_out:
+
+
diff --git a/src/arch/i386/lib/failover.lds b/src/arch/i386/lib/failover.lds
new file mode 100644
index 0000000..c9cf729
--- /dev/null
+++ b/src/arch/i386/lib/failover.lds
@@ -0,0 +1 @@
+	__normal_image = (ZKERNEL_START & 0xfffffff0) - 8;
diff --git a/src/arch/i386/lib/id.inc b/src/arch/i386/lib/id.inc
new file mode 100644
index 0000000..f28e23a
--- /dev/null
+++ b/src/arch/i386/lib/id.inc
@@ -0,0 +1,21 @@
+	.section ".id", "a", @progbits
+
+#define __STR(X) #X
+#define STR(X) __STR(X)
+
+	.globl __id_start
+__id_start:
+vendor:	
+	.asciz STR(MAINBOARD_VENDOR)
+part:		
+	.asciz STR(MAINBOARD_PART_NUMBER)
+.long __id_end + 0x10 - vendor  /* Reverse offset to the vendor id */
+.long __id_end + 0x10 - part    /* Reverse offset to the part number */
+.long PAYLOAD_SIZE + ROM_IMAGE_SIZE  /* Size of this romimage */
+	.globl __id_end
+
+#undef __STR
+#undef STR
+
+__id_end:
+.previous
diff --git a/src/arch/i386/lib/id.lds b/src/arch/i386/lib/id.lds
new file mode 100644
index 0000000..ccdf700
--- /dev/null
+++ b/src/arch/i386/lib/id.lds
@@ -0,0 +1,6 @@
+SECTIONS {
+	. = (_ROMBASE + ROM_IMAGE_SIZE - 0x10) - (__id_end - __id_start);
+	.id (.): {
+		*(.id)
+	}
+}
diff --git a/src/arch/i386/lib/noop_failover.inc b/src/arch/i386/lib/noop_failover.inc
new file mode 100644
index 0000000..70c10b0
--- /dev/null
+++ b/src/arch/i386/lib/noop_failover.inc
@@ -0,0 +1,9 @@
+/* Step 1:  Test for cpu reset
+ *     That is, did I just boot or is this a later boot since power on.
+ *     The result of this test in %al
+ *     %al == 1 -- We are rebooting
+ *     %al == 0 -- This is the initial boot
+ *
+ */
+	testb	%al, %al
+	jnz	__cpu_reset
diff --git a/src/arch/i386/lib/pci_ops.c b/src/arch/i386/lib/pci_ops.c
new file mode 100644
index 0000000..80921bf
--- /dev/null
+++ b/src/arch/i386/lib/pci_ops.c
@@ -0,0 +1,281 @@
+#include <console/console.h>
+#include <arch/io.h>
+#include <arch/pciconf.h>
+#include <pci.h>
+#include <pci_ids.h>
+#include <pci_ops.h>
+
+static const struct pci_ops *conf;
+struct pci_ops {
+	int (*read_byte) (uint8_t bus, int devfn, int where, uint8_t * val);
+	int (*read_word) (uint8_t bus, int devfn, int where, uint16_t * val);
+	int (*read_dword) (uint8_t bus, int devfn, int where, uint32_t * val);
+	int (*write_byte) (uint8_t bus, int devfn, int where, uint8_t val);
+	int (*write_word) (uint8_t bus, int devfn, int where, uint16_t val);
+	int (*write_dword) (uint8_t bus, int devfn, int where, uint32_t val);
+};
+
+/*
+ * Direct access to PCI hardware...
+ */
+
+
+/*
+ * Functions for accessing PCI configuration space with type 1 accesses
+ */
+
+#define CONFIG_CMD(bus,devfn, where)   (0x80000000 | (bus << 16) | (devfn << 8) | (where & ~3))
+
+static int pci_conf1_read_config_byte(unsigned char bus, int devfn, int where, uint8_t * value)
+{
+	outl(CONFIG_CMD(bus, devfn, where), 0xCF8);
+	*value = inb(0xCFC + (where & 3));
+	return 0;
+}
+
+static int pci_conf1_read_config_word(unsigned char bus, int devfn, int where, uint16_t * value)
+{
+	outl(CONFIG_CMD(bus, devfn, where), 0xCF8);
+	*value = inw(0xCFC + (where & 2));
+	return 0;
+}
+
+static int pci_conf1_read_config_dword(unsigned char bus, int devfn, int where, uint32_t * value)
+{
+	outl(CONFIG_CMD(bus, devfn, where), 0xCF8);
+	*value = inl(0xCFC);
+	return 0;
+}
+
+static int pci_conf1_write_config_byte(unsigned char bus, int devfn, int where, uint8_t value)
+{
+	outl(CONFIG_CMD(bus, devfn, where), 0xCF8);
+	outb(value, 0xCFC + (where & 3));
+	return 0;
+}
+
+static int pci_conf1_write_config_word(unsigned char bus, int devfn, int where, uint16_t value)
+{
+	outl(CONFIG_CMD(bus, devfn, where), 0xCF8);
+	outw(value, 0xCFC + (where & 2));
+	return 0;
+}
+
+static int pci_conf1_write_config_dword(unsigned char bus, int devfn, int where, uint32_t value)
+{
+	outl(CONFIG_CMD(bus, devfn, where), 0xCF8);
+	outl(value, 0xCFC);
+	return 0;
+}
+
+#undef CONFIG_CMD
+
+static const struct pci_ops pci_direct_conf1 =
+{
+	pci_conf1_read_config_byte,
+	pci_conf1_read_config_word,
+	pci_conf1_read_config_dword,
+	pci_conf1_write_config_byte,
+	pci_conf1_write_config_word,
+	pci_conf1_write_config_dword
+};
+
+/*
+ * Functions for accessing PCI configuration space with type 2 accesses
+ */
+
+#define IOADDR(devfn, where)	((0xC000 | ((devfn & 0x78) << 5)) + where)
+#define FUNC(devfn)		(((devfn & 7) << 1) | 0xf0)
+#define SET(bus,devfn)		if (devfn & 0x80) return -1;outb(FUNC(devfn), 0xCF8); outb(bus, 0xCFA);
+
+static int pci_conf2_read_config_byte(unsigned char bus, int devfn, int where, uint8_t * value)
+{
+	SET(bus, devfn);
+	*value = inb(IOADDR(devfn, where));
+	outb(0, 0xCF8);
+	return 0;
+}
+
+static int pci_conf2_read_config_word(unsigned char bus, int devfn, int where, uint16_t * value)
+{
+	SET(bus, devfn);
+	*value = inw(IOADDR(devfn, where));
+	outb(0, 0xCF8);
+	return 0;
+}
+
+static int pci_conf2_read_config_dword(unsigned char bus, int devfn, int where, uint32_t * value)
+{
+	SET(bus, devfn);
+	*value = inl(IOADDR(devfn, where));
+	outb(0, 0xCF8);
+	return 0;
+}
+
+static int pci_conf2_write_config_byte(unsigned char bus, int devfn, int where, uint8_t value)
+{
+	SET(bus, devfn);
+	outb(value, IOADDR(devfn, where));
+	outb(0, 0xCF8);
+	return 0;
+}
+
+static int pci_conf2_write_config_word(unsigned char bus, int devfn, int where, uint16_t value)
+{
+	SET(bus, devfn);
+	outw(value, IOADDR(devfn, where));
+	outb(0, 0xCF8);
+	return 0;
+}
+
+static int pci_conf2_write_config_dword(unsigned char bus, int devfn, int where, uint32_t value)
+{
+	SET(bus, devfn);
+	outl(value, IOADDR(devfn, where));
+	outb(0, 0xCF8);
+	return 0;
+}
+
+#undef SET
+#undef IOADDR
+#undef FUNC
+
+static const struct pci_ops pci_direct_conf2 =
+{
+	pci_conf2_read_config_byte,
+	pci_conf2_read_config_word,
+	pci_conf2_read_config_dword,
+	pci_conf2_write_config_byte,
+	pci_conf2_write_config_word,
+	pci_conf2_write_config_dword
+};
+
+/*
+ * Before we decide to use direct hardware access mechanisms, we try to do some
+ * trivial checks to ensure it at least _seems_ to be working -- we just test
+ * whether bus 00 contains a host bridge (this is similar to checking
+ * techniques used in XFree86, but ours should be more reliable since we
+ * attempt to make use of direct access hints provided by the PCI BIOS).
+ *
+ * This should be close to trivial, but it isn't, because there are buggy
+ * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID.
+ */
+static int pci_sanity_check(const struct pci_ops *o)
+{
+	uint16_t x;
+	uint8_t bus;
+	int devfn;
+#define PCI_CLASS_BRIDGE_HOST		0x0600
+#define PCI_CLASS_DISPLAY_VGA		0x0300
+#define PCI_VENDOR_ID_COMPAQ		0x0e11
+#define PCI_VENDOR_ID_INTEL		0x8086
+#define PCI_VENDOR_ID_MOTOROLA		0x1057
+
+	for (bus = 0, devfn = 0; devfn < 0x100; devfn++)
+		if ((!o->read_word(bus, devfn, PCI_CLASS_DEVICE, &x) &&
+		     (x == PCI_CLASS_BRIDGE_HOST || x == PCI_CLASS_DISPLAY_VGA)) ||
+		    (!o->read_word(bus, devfn, PCI_VENDOR_ID, &x) &&
+		     (x == PCI_VENDOR_ID_INTEL || x == PCI_VENDOR_ID_COMPAQ || x == PCI_VENDOR_ID_MOTOROLA)))
+			return 1;
+	printk_err("PCI: Sanity check failed\n");
+	return 0;
+}
+
+static const struct pci_ops *pci_check_direct(void)
+{
+	unsigned int tmp;
+
+	/*
+	 * Check if configuration type 1 works.
+	 */
+	{
+		outb(0x01, 0xCFB);
+		tmp = inl(0xCF8);
+		outl(0x80000000, 0xCF8);
+		if (inl(0xCF8) == 0x80000000 &&
+		    pci_sanity_check(&pci_direct_conf1)) {
+			outl(tmp, 0xCF8);
+			printk_debug("PCI: Using configuration type 1\n");
+			return &pci_direct_conf1;
+		}
+		outl(tmp, 0xCF8);
+	}
+
+	/*
+	 * Check if configuration type 2 works.
+	 */
+	{
+		outb(0x00, 0xCFB);
+		outb(0x00, 0xCF8);
+		outb(0x00, 0xCFA);
+		if (inb(0xCF8) == 0x00 && inb(0xCFA) == 0x00 &&
+		    pci_sanity_check(&pci_direct_conf2)) {
+			printk_debug("PCI: Using configuration type 2\n");
+			return &pci_direct_conf2;
+		}
+	}
+
+	printk_debug("pci_check_direct failed\n");
+    
+	return 0;
+}
+
+int pci_read_config_byte(struct device *dev, uint8_t where, uint8_t * val)
+{
+	int res; 
+	res = conf->read_byte(dev->bus->secondary, dev->devfn, where, val);
+	printk_spew("Read config byte bus %d,devfn 0x%x,reg 0x%x,val 0x%x,res 0x%x\n",
+		    dev->bus->secondary, dev->devfn, where, *val, res);
+	return res;
+
+
+}
+
+int pci_read_config_word(struct device *dev, uint8_t where, uint16_t * val)
+{
+	int res; 
+	res = conf->read_word(dev->bus->secondary, dev->devfn, where, val);
+	printk_spew( "Read config word bus %d,devfn 0x%x,reg 0x%x,val 0x%x,res 0x%x\n",
+		     dev->bus->secondary, dev->devfn, where, *val, res);
+	return res;
+}
+
+int pci_read_config_dword(struct device *dev, uint8_t where, uint32_t * val)
+{
+	int res; 
+	res = conf->read_dword(dev->bus->secondary, dev->devfn, where, val);
+	printk_spew( "Read config dword bus %d,devfn 0x%x,reg 0x%x,val 0x%x,res 0x%x\n",
+		     dev->bus->secondary, dev->devfn, where, *val, res);
+	return res;
+}
+
+int pci_write_config_byte(struct device *dev, uint8_t where, uint8_t val)
+{
+	printk_spew( "Write config byte bus %d, devfn 0x%x, reg 0x%x, val 0x%x\n",
+		     dev->bus->secondary, dev->devfn, where, val);
+	return conf->write_byte(dev->bus->secondary, dev->devfn, where, val);
+}
+
+int pci_write_config_word(struct device *dev, uint8_t where, uint16_t val)
+{
+	printk_spew( "Write config word bus %d, devfn 0x%x, reg 0x%x, val 0x%x\n",
+		     dev->bus->secondary, dev->devfn, where, val);
+	return conf->write_word(dev->bus->secondary, dev->devfn, where, val);
+}
+
+int pci_write_config_dword(struct device *dev, uint8_t where, uint32_t val)
+{
+	printk_spew( "Write config dword bus %d, devfn 0x%x, reg 0x%x, val 0x%x\n",
+		     dev->bus->secondary, dev->devfn, where, val);
+	return conf->write_dword(dev->bus->secondary, dev->devfn, where, val);
+}
+
+/** Set the method to be used for PCI, type I or type II
+ */
+void pci_set_method(void)
+{
+	conf = &pci_direct_conf1;
+	conf = pci_check_direct();
+}
+
+
diff --git a/src/arch/i386/smp/mpspec.c b/src/arch/i386/smp/mpspec.c
new file mode 100644
index 0000000..3bb5fa1
--- /dev/null
+++ b/src/arch/i386/smp/mpspec.c
@@ -0,0 +1,245 @@
+#include <console/console.h>
+#include <cpu/cpu.h>
+#include <smp/start_stop.h>
+#include <arch/smp/mpspec.h>
+#include <string.h>
+#include <cpu/p5/cpuid.h>
+#include <cpu/p6/apic.h>
+
+unsigned char smp_compute_checksum(void *v, int len)
+{
+	unsigned char *bytes;
+	unsigned char checksum;
+	int i;
+	bytes = v;
+	checksum = 0;
+	for(i = 0; i < len; i++) {
+		checksum -= bytes[i];
+	}
+	return checksum;
+}
+
+void *smp_write_floating_table(unsigned long addr)
+{
+	struct intel_mp_floating *mf;
+	void *v;
+	
+	/* 16 byte align the table address */
+	addr += 15;
+	addr &= ~15;
+	v = (void *)addr;
+
+	mf = v;
+	mf->mpf_signature[0] = '_';
+	mf->mpf_signature[1] = 'M';
+	mf->mpf_signature[2] = 'P';
+	mf->mpf_signature[3] = '_';
+	mf->mpf_physptr = (unsigned long)(((char *)v) + SMP_FLOATING_TABLE_LEN);
+	mf->mpf_length = 1;
+	mf->mpf_specification = 4;
+	mf->mpf_checksum = 0;
+	mf->mpf_feature1 = 0;
+	mf->mpf_feature2 = 0;
+	mf->mpf_feature3 = 0;
+	mf->mpf_feature4 = 0;
+	mf->mpf_feature5 = 0;
+	mf->mpf_checksum = smp_compute_checksum(mf, mf->mpf_length*16);
+	return v;
+}
+
+void *smp_next_mpc_entry(struct mp_config_table *mc)
+{
+	void *v;
+	v = (void *)(((char *)mc) + mc->mpc_length);
+	return v;
+}
+static void smp_add_mpc_entry(struct mp_config_table *mc, unsigned length)
+{
+	mc->mpc_length += length;
+	mc->mpc_entry_count++;
+}
+
+void *smp_next_mpe_entry(struct mp_config_table *mc)
+{
+	void *v;
+	v = (void *)(((char *)mc) + mc->mpc_length + mc->mpe_length);
+	return v;
+}
+static void smp_add_mpe_entry(struct mp_config_table *mc, mpe_t mpe)
+{
+	mc->mpe_length += mpe->mpe_length;
+}
+
+void smp_write_processor(struct mp_config_table *mc,
+	unsigned char apicid, unsigned char apicver,
+	unsigned char cpuflag, unsigned int cpufeature,
+	unsigned int featureflag)
+{
+	struct mpc_config_processor *mpc;
+	mpc = smp_next_mpc_entry(mc);
+	memset(mpc, '\0', sizeof(*mpc));
+	mpc->mpc_type = MP_PROCESSOR;
+	mpc->mpc_apicid = apicid;
+	mpc->mpc_apicver = apicver;
+	mpc->mpc_cpuflag = cpuflag;
+	mpc->mpc_cpufeature = cpufeature;
+	mpc->mpc_featureflag = featureflag;
+	smp_add_mpc_entry(mc, sizeof(*mpc));
+}
+
+/* If we assume a symmetric processor configuration we can
+ * get all of the information we need to write the processor
+ * entry from the bootstrap processor.
+ * Plus I don't think linux really even cares.
+ * Having the proper apicid's in the table so the non-bootstrap
+ *  processors can be woken up should be enough.
+ */
+void smp_write_processors(struct mp_config_table *mc, 
+			unsigned long *processor_map)
+{
+	int i;
+	int processor_id;
+	unsigned apic_version;
+	unsigned cpu_features;
+	unsigned cpu_feature_flags;
+	int eax, ebx, ecx, edx;
+	processor_id = this_processors_id();
+	apic_version = apic_read(APIC_LVR) & 0xff;
+	cpuid(1, &eax, &ebx, &ecx, &edx);
+	cpu_features = eax;
+	cpu_feature_flags = edx;
+	for(i = 0; i < MAX_CPUS; i++) {
+		unsigned long cpu_apicid = initial_apicid[i];
+		unsigned long cpu_flag;
+		if(initial_apicid[i]==-1)
+			continue;
+		cpu_flag = MPC_CPU_ENABLED
+		if (processor_map[i] & CPU_BOOTPROCESSOR) {
+			cpu_flag |= MPC_CPU_BOOTPROCESSOR;
+		}
+		smp_write_processor(mc, cpu_apicid, apic_version,
+			cpu_flag, cpu_features, cpu_feature_flags
+		);
+	
+	}
+}
+
+void smp_write_bus(struct mp_config_table *mc,
+	unsigned char id, unsigned char *bustype)
+{
+	struct mpc_config_bus *mpc;
+	mpc = smp_next_mpc_entry(mc);
+	memset(mpc, '\0', sizeof(*mpc));
+	mpc->mpc_type = MP_BUS;
+	mpc->mpc_busid = id;
+	memcpy(mpc->mpc_bustype, bustype, sizeof(mpc->mpc_bustype));
+	smp_add_mpc_entry(mc, sizeof(*mpc));
+}
+
+void smp_write_ioapic(struct mp_config_table *mc,
+	unsigned char id, unsigned char ver, 
+	unsigned long apicaddr)
+{
+	struct mpc_config_ioapic *mpc;
+	mpc = smp_next_mpc_entry(mc);
+	memset(mpc, '\0', sizeof(*mpc));
+	mpc->mpc_type = MP_IOAPIC;
+	mpc->mpc_apicid = id;
+	mpc->mpc_apicver = ver;
+	mpc->mpc_flags = MPC_APIC_USABLE;
+	mpc->mpc_apicaddr = apicaddr;
+	smp_add_mpc_entry(mc, sizeof(*mpc));
+}
+
+void smp_write_intsrc(struct mp_config_table *mc,
+	unsigned char irqtype, unsigned short irqflag,
+	unsigned char srcbus, unsigned char srcbusirq,
+	unsigned char dstapic, unsigned char dstirq)
+{
+	struct mpc_config_intsrc *mpc;
+	mpc = smp_next_mpc_entry(mc);
+	memset(mpc, '\0', sizeof(*mpc));
+	mpc->mpc_type = MP_INTSRC;
+	mpc->mpc_irqtype = irqtype;
+	mpc->mpc_irqflag = irqflag;
+	mpc->mpc_srcbus = srcbus;
+	mpc->mpc_srcbusirq = srcbusirq;
+	mpc->mpc_dstapic = dstapic;
+	mpc->mpc_dstirq = dstirq;
+	smp_add_mpc_entry(mc, sizeof(*mpc));
+#if CONFIG_DEBUG_MPTABLE == 1
+	printk_info("add intsrc srcbus 0x%x srcbusirq 0x%x, dstapic 0x%x, dstirq 0x%x\n",
+				srcbus, srcbusirq, dstapic, dstirq);
+	hexdump(__FUNCTION__, mpc, sizeof(*mpc));
+#endif
+}
+
+
+void smp_write_lintsrc(struct mp_config_table *mc,
+	unsigned char irqtype, unsigned short irqflag,
+	unsigned char srcbusid, unsigned char srcbusirq,
+	unsigned char destapic, unsigned char destapiclint)
+{
+	struct mpc_config_lintsrc *mpc;
+	mpc = smp_next_mpc_entry(mc);
+	memset(mpc, '\0', sizeof(*mpc));
+	mpc->mpc_type = MP_LINTSRC;
+	mpc->mpc_irqtype = irqtype;
+	mpc->mpc_irqflag = irqflag;
+	mpc->mpc_srcbusid = srcbusid;
+	mpc->mpc_srcbusirq = srcbusirq;
+	mpc->mpc_destapic = destapic;
+	mpc->mpc_destapiclint = destapiclint;
+	smp_add_mpc_entry(mc, sizeof(*mpc));
+}
+
+void smp_write_address_space(struct mp_config_table *mc,
+	unsigned char busid, unsigned char address_type,
+	unsigned int address_base_low, unsigned int address_base_high,
+	unsigned int address_length_low, unsigned int address_length_high)
+{
+	struct mp_exten_system_address_space *mpe;
+	mpe = smp_next_mpe_entry(mc);
+	memset(mpe, '\0', sizeof(*mpe));
+	mpe->mpe_type = MPE_SYSTEM_ADDRESS_SPACE;
+	mpe->mpe_length = sizeof(*mpe);
+	mpe->mpe_busid = busid;
+	mpe->mpe_address_type = address_type;
+	mpe->mpe_address_base_low  = address_base_low;
+	mpe->mpe_address_base_high = address_base_high;
+	mpe->mpe_address_length_low  = address_length_low;
+	mpe->mpe_address_length_high = address_length_high;
+	smp_add_mpe_entry(mc, (mpe_t)mpe);
+}
+
+
+void smp_write_bus_hierarchy(struct mp_config_table *mc,
+	unsigned char busid, unsigned char bus_info,
+	unsigned char parent_busid)
+{
+	struct mp_exten_bus_hierarchy *mpe;
+	mpe = smp_next_mpe_entry(mc);
+	memset(mpe, '\0', sizeof(*mpe));
+	mpe->mpe_type = MPE_BUS_HIERARCHY;
+	mpe->mpe_length = sizeof(*mpe);
+	mpe->mpe_busid = busid;
+	mpe->mpe_bus_info = bus_info;
+	mpe->mpe_parent_busid = parent_busid;
+	smp_add_mpe_entry(mc, (mpe_t)mpe);
+}
+
+void smp_write_compatibility_address_space(struct mp_config_table *mc,
+	unsigned char busid, unsigned char address_modifier,
+	unsigned int range_list)
+{
+	struct mp_exten_compatibility_address_space *mpe;
+	mpe = smp_next_mpe_entry(mc);
+	memset(mpe, '\0', sizeof(*mpe));
+	mpe->mpe_type = MPE_COMPATIBILITY_ADDRESS_SPACE;
+	mpe->mpe_length = sizeof(*mpe);
+	mpe->mpe_busid = busid;
+	mpe->mpe_address_modifier = address_modifier;
+	mpe->mpe_range_list = range_list;
+	smp_add_mpe_entry(mc, (mpe_t)mpe);
+}
+
diff --git a/src/boot/elfboot.c b/src/boot/elfboot.c
new file mode 100644
index 0000000..da0e909
--- /dev/null
+++ b/src/boot/elfboot.c
@@ -0,0 +1,663 @@
+#include <console/console.h>
+#include <part/fallback_boot.h>
+#include <boot/elf.h>
+#include <boot/elf_boot.h>
+#include <boot/linuxbios_tables.h>
+#include <ip_checksum.h>
+#include <stream/read_bytes.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Maximum physical address we can use for the linuxBIOS bounce buffer.
+ */
+#ifndef MAX_ADDR
+#define MAX_ADDR -1UL
+#endif
+
+extern unsigned char _ram_seg;
+extern unsigned char _eram_seg;
+
+struct segment {
+	struct segment *next;
+	struct segment *prev;
+	struct segment *phdr_next;
+	struct segment *phdr_prev;
+	unsigned long s_addr;
+	unsigned long s_memsz;
+	unsigned long s_offset;
+	unsigned long s_filesz;
+};
+
+struct verify_callback {
+	struct verify_callback *next;
+	int (*callback)(struct verify_callback *vcb, 
+		Elf_ehdr *ehdr, Elf_phdr *phdr, struct segment *head);
+	unsigned long desc_offset;
+	unsigned long desc_addr;
+};
+
+struct ip_checksum_vcb {
+	struct verify_callback data;
+	unsigned short ip_checksum;
+};
+
+int verify_ip_checksum(
+	struct verify_callback *vcb, 
+	Elf_ehdr *ehdr, Elf_phdr *phdr, struct segment *head)
+{
+	struct ip_checksum_vcb *cb;
+	struct segment *ptr;
+	unsigned long bytes;
+	unsigned long checksum;
+	unsigned char buff[2], *n_desc;
+	cb = (struct ip_checksum_vcb *)vcb;
+	/* zero the checksum so it's value won't
+	 * get in the way of verifying the checksum.
+	 */
+	n_desc = 0;
+	if (vcb->desc_addr) {
+		n_desc = (unsigned char *)(vcb->desc_addr);
+		memcpy(buff, n_desc, 2);
+		memset(n_desc, 0, 2);
+	}
+	bytes = 0;
+	checksum = compute_ip_checksum(ehdr, sizeof(*ehdr));
+	bytes += sizeof(*ehdr);
+	checksum = add_ip_checksums(bytes, checksum, 
+		compute_ip_checksum(phdr, ehdr->e_phnum*sizeof(*phdr)));
+	bytes += ehdr->e_phnum*sizeof(*phdr);
+	for(ptr = head->phdr_next; ptr != head; ptr = ptr->phdr_next) {
+		checksum = add_ip_checksums(bytes, checksum,
+			compute_ip_checksum((void *)ptr->s_addr, ptr->s_memsz));
+		bytes += ptr->s_memsz;
+	}
+	if (n_desc != 0) {
+		memcpy(n_desc, buff, 2);
+	}
+	if (checksum != cb->ip_checksum) {
+		printk_err("Image checksum: %04x != computed checksum: %04x\n",
+			cb->ip_checksum, checksum);
+	}
+	return checksum == cb->ip_checksum;
+}
+
+/* The problem:  
+ * Static executables all want to share the same addresses
+ * in memory because only a few addresses are reliably present on
+ * a machine, and implementing general relocation is hard.
+ *
+ * The solution:
+ * - Allocate a buffer twice the size of the linuxBIOS image.
+ * - Anything that would overwrite linuxBIOS copy into the lower half of
+ *   the buffer. 
+ * - After loading an ELF image copy linuxBIOS to the upper half of the
+ *   buffer.
+ * - Then jump to the loaded image.
+ * 
+ * Benefits:
+ * - Nearly arbitrary standalone executables can be loaded.
+ * - LinuxBIOS is preserved, so it can be returned to.
+ * - The implementation is still relatively simple,
+ *   and much simpler then the general case implemented in kexec.
+ * 
+ */
+
+static unsigned long get_bounce_buffer(struct lb_memory *mem)
+{
+	unsigned long lb_size;
+	unsigned long mem_entries;
+	unsigned long buffer;
+	int i;
+	lb_size = (unsigned long)(&_eram_seg - &_ram_seg);
+	/* Double linuxBIOS size so I have somewhere to place a copy to return to */
+	lb_size = lb_size + lb_size;
+	mem_entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
+	buffer = 0;
+	for(i = 0; i < mem_entries; i++) {
+		unsigned long mstart, mend;
+		unsigned long msize;
+		unsigned long tbuffer;
+		if (mem->map[i].type != LB_MEM_RAM)
+			continue;
+		if (mem->map[i].start > MAX_ADDR)
+			continue;
+		if (mem->map[i].size < lb_size)
+			continue;
+		mstart = mem->map[i].start;
+		msize = MAX_ADDR - mstart +1;
+		if (msize > mem->map[i].size)
+			msize = mem->map[i].size;
+		mend = mstart + msize;
+		tbuffer = mend - lb_size;
+		if (tbuffer < buffer) 
+			continue;
+		buffer = tbuffer;
+	}
+	return buffer;
+}
+
+
+static struct verify_callback *process_elf_notes(
+	unsigned char *header, 
+	unsigned long offset, unsigned long length)
+{
+	struct verify_callback *cb_chain;
+	unsigned char *note, *end;
+	char *program, *version;
+
+	cb_chain = 0;
+	note = header + offset;
+	end = note + length;
+	program = version = 0;
+	while(note < end) {
+		Elf_Nhdr *hdr;
+		unsigned char *n_name, *n_desc, *next;
+		hdr = (Elf_Nhdr *)note;
+		n_name = note + sizeof(*hdr);
+		n_desc = n_name + ((hdr->n_namesz + 3) & ~3);
+		next = n_desc + ((hdr->n_descsz + 3) & ~3);
+		if (next > end) {
+			break;
+		}
+		if ((hdr->n_namesz == sizeof(ELF_NOTE_BOOT)) && 
+			(memcmp(n_name, ELF_NOTE_BOOT, sizeof(ELF_NOTE_BOOT)) == 0)) {
+			switch(hdr->n_type) {
+			case EIN_PROGRAM_NAME:
+				if (n_desc[hdr->n_descsz -1] == 0) {
+					program = n_desc;
+				}
+				break;
+			case EIN_PROGRAM_VERSION:
+				if (n_desc[hdr->n_descsz -1] == 0) {
+					version = n_desc;
+				}
+				break;
+			case EIN_PROGRAM_CHECKSUM:
+			{
+				struct ip_checksum_vcb *cb;
+				cb = malloc(sizeof(*cb));
+				cb->ip_checksum = *((uint16_t *)n_desc);
+				cb->data.callback = verify_ip_checksum;
+				cb->data.next = cb_chain;
+				cb->data.desc_offset = n_desc - header;
+				cb_chain = &cb->data;
+				break;
+			}
+			}
+		}
+		printk_spew("n_type: %08x n_name(%d): %-*.*s n_desc(%d): %-*.*s\n", 
+			hdr->n_type,
+			hdr->n_namesz, hdr->n_namesz, hdr->n_namesz, n_name,
+			hdr->n_descsz,hdr->n_descsz, hdr->n_descsz, n_desc);
+		note = next;
+	}
+	if (program && version) {
+		printk_info("Loading %s version: %s\n",
+			program, version);
+	}
+	return cb_chain;
+}
+
+static int valid_area(struct lb_memory *mem, unsigned long buffer,
+	unsigned long start, unsigned long len)
+{
+	/* Check through all of the memory segments and ensure
+	 * the segment that was passed in is completely contained
+	 * in RAM.
+	 */
+	int i;
+	unsigned long end = start + len;
+	unsigned long mem_entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
+
+	/* See if I conflict with the bounce buffer */
+	if (end >= buffer) {
+		return 0;
+	}
+
+	/* Walk through the table of valid memory ranges and see if I
+	 * have a match.
+	 */
+	for(i = 0; i < mem_entries; i++) {
+		uint64_t mstart, mend;
+		uint32_t mtype;
+		mtype = mem->map[i].type;
+		mstart = mem->map[i].start;
+		mend = mstart + mem->map[i].size;
+		if ((mtype == LB_MEM_RAM) && (start < mend) && (end > mstart)) {
+			break;
+		}
+	}
+	if (i == mem_entries) {
+		printk_err("No matching ram area found for range:\n");
+		printk_err("  [0x%016lx, 0x%016lx)\n", start, end);
+		printk_err("Ram areas\n");
+		for(i = 0; i < mem_entries; i++) {
+			uint64_t mstart, mend;
+			uint32_t mtype;
+			mtype = mem->map[i].type;
+			mstart = mem->map[i].start;
+			mend = mstart + mem->map[i].size;
+			printk_err("  [0x%016lx, 0x%016lx) %s\n",
+				(unsigned long)mstart, 
+				(unsigned long)mend, 
+				(mtype == LB_MEM_RAM)?"RAM":"Reserved");
+			
+		}
+		return 0;
+	}
+	return 1;
+}
+
+static void relocate_segment(unsigned long buffer, struct segment *seg)
+{
+	/* Modify all segments that want to load onto linuxBIOS
+	 * to load onto the bounce buffer instead.
+	 */
+	unsigned long lb_start = (unsigned long)&_ram_seg;
+	unsigned long lb_end = (unsigned long)&_eram_seg;
+	unsigned long start, middle, end;
+
+	printk_spew("lb: [0x%016lx, 0x%016lx)\n", 
+		lb_start, lb_end);
+
+	start = seg->s_addr;
+	middle = start + seg->s_filesz;
+	end = start + seg->s_memsz;
+	/* I don't conflict with linuxBIOS so get out of here */
+	if ((end <= lb_start) || (start >= lb_end))
+		return;
+
+	printk_spew("segment: [0x%016lx, 0x%016lx, 0x%016lx)\n", 
+		start, middle, end);
+
+	/* Slice off a piece at the beginning
+	 * that doesn't conflict with linuxBIOS.
+	 */
+	if (start < lb_start) {
+		struct segment *new;
+		unsigned long len = lb_start - start;
+		new = malloc(sizeof(*new));
+		*new = *seg;
+		new->s_memsz = len;
+		seg->s_memsz -= len;
+		seg->s_addr += len;
+		seg->s_offset += len;
+		if (seg->s_filesz > len) {
+			new->s_filesz = len;
+			seg->s_filesz -= len;
+		} else {
+			seg->s_filesz = 0;
+		}
+
+		/* Order by stream offset */
+		new->next = seg;
+		new->prev = seg->prev;
+		seg->prev->next = new;
+		seg->prev = new;
+		/* Order by original program header order */
+		new->phdr_next = seg;
+		new->phdr_prev = seg->phdr_prev;
+		seg->phdr_prev->phdr_next = new;
+		seg->phdr_prev = new;
+
+		/* compute the new value of start */
+		start = seg->s_addr;
+		
+		printk_spew("   early: [0x%016lx, 0x%016lx, 0x%016lx)\n", 
+			new->s_addr, 
+			new->s_addr + new->s_filesz,
+			new->s_addr + new->s_memsz);
+	}
+	
+	/* Slice off a piece at the end 
+	 * that doesn't conflict with linuxBIOS 
+	 */
+	if (end > lb_end) {
+		unsigned long len = lb_end - start;
+		struct segment *new;
+		new = malloc(sizeof(*new));
+		*new = *seg;
+		seg->s_memsz = len;
+		new->s_memsz -= len;
+		new->s_addr += len;
+		new->s_offset += len;
+		if (seg->s_filesz > len) {
+			seg->s_filesz = len;
+			new->s_filesz -= len;
+		} else {
+			new->s_filesz = 0;
+		}
+		/* Order by stream offset */
+		new->next = seg->next;
+		new->prev = seg;
+		seg->next->prev = new;
+		seg->next = new;
+		/* Order by original program header order */
+		new->phdr_next = seg->phdr_next;
+		new->phdr_prev = seg;
+		seg->phdr_next->phdr_prev = new;
+		seg->phdr_next = new;
+
+		/* compute the new value of end */
+		end = start + len;
+		
+		printk_spew("   late: [0x%016lx, 0x%016lx, 0x%016lx)\n", 
+			new->s_addr, 
+			new->s_addr + new->s_filesz,
+			new->s_addr + new->s_memsz);
+		
+	}
+	/* Now retarget this segment onto the bounce buffer */
+	seg->s_addr = buffer + (seg->s_addr - lb_start);
+
+	printk_spew(" bounce: [0x%016lx, 0x%016lx, 0x%016lx)\n", 
+		seg->s_addr, 
+		seg->s_addr + seg->s_filesz, 
+		seg->s_addr + seg->s_memsz);
+}
+
+
+static int build_elf_segment_list(
+	struct segment *head, 
+	unsigned long bounce_buffer, struct lb_memory *mem,
+	Elf_phdr *phdr, int headers)
+{
+	struct segment *ptr;
+	int i;
+	memset(head, 0, sizeof(*head));
+	head->next = head->prev = head;
+	for(i = 0; i < headers; i++) {
+		struct segment *new;
+		/* Ignore data that I don't need to handle */
+		if (phdr[i].p_type != PT_LOAD) {
+			printk_debug("Dropping non PT_LOAD segment\n");
+			continue;
+		}
+		if (phdr[i].p_memsz == 0) {
+			printk_debug("Dropping empty segment\n");
+			continue;
+		}
+		new = malloc(sizeof(*new));
+		new->s_addr = phdr[i].p_paddr;
+		new->s_memsz = phdr[i].p_memsz;
+		new->s_offset = phdr[i].p_offset;
+		new->s_filesz = phdr[i].p_filesz;
+		printk_debug("New segment addr 0x%lx size 0x%lx offset 0x%lx filesize 0x%lx\n",
+			new->s_addr, new->s_memsz, new->s_offset, new->s_filesz);
+		/* Clean up the values */
+		if (new->s_filesz > new->s_memsz)  {
+			new->s_filesz = new->s_memsz;
+		}
+		printk_debug("(cleaned up) New segment addr 0x%lx size 0x%lx offset 0x%lx filesize 0x%lx\n",
+			new->s_addr, new->s_memsz, new->s_offset, new->s_filesz);
+		for(ptr = head->next; ptr != head; ptr = ptr->next) {
+			if (new->s_offset < ptr->s_offset)
+				break;
+		}
+		/* Order by stream offset */
+		new->next = ptr;
+		new->prev = ptr->prev;
+		ptr->prev->next = new;
+		ptr->prev = new;
+		/* Order by original program header order */
+		new->phdr_next = head;
+		new->phdr_prev = head->phdr_prev;
+		head->phdr_prev->phdr_next  = new;
+		head->phdr_prev = new;
+
+		/* Verify the memory addresses in the segment are valid */
+		if (!valid_area(mem, bounce_buffer, new->s_addr, new->s_memsz)) 
+			goto out;
+
+		/* Modify the segment to load onto the bounce_buffer if necessary.
+		 */
+		relocate_segment(bounce_buffer, new);
+	}
+	return 1;
+ out:
+	return 0;
+}
+
+static int load_elf_segments(
+	struct segment *head, unsigned char *header, unsigned long header_size)
+{
+	unsigned long offset;
+	struct segment *ptr;
+	
+	offset = 0;
+	for(ptr = head->next; ptr != head; ptr = ptr->next) {
+		unsigned long start_offset;
+		unsigned long skip_bytes, read_bytes;
+		unsigned char *dest, *middle, *end;
+		byte_offset_t result;
+		printk_debug("Loading Segment: addr: 0x%016lx memsz: 0x%016lx filesz: 0x%016lx\n",
+			ptr->s_addr, ptr->s_memsz, ptr->s_filesz);
+		
+		/* Compute the boundaries of the segment */
+		dest = (unsigned char *)(ptr->s_addr);
+		end = dest + ptr->s_memsz;
+		middle = dest + ptr->s_filesz;
+		start_offset = ptr->s_offset;
+		
+		printk_spew("[ 0x%016lx, %016lx, 0x%016lx) <- %016lx\n",
+			(unsigned long)dest,
+			(unsigned long)middle,
+			(unsigned long)end,
+			(unsigned long)start_offset);
+		
+		/* Skip intial buffer unused bytes */
+		if (offset < header_size) {
+			if (start_offset < header_size) {
+				offset = start_offset;
+			} else {
+				offset = header_size;
+			}
+		}
+		
+		/* Skip the unused bytes */
+		skip_bytes = start_offset - offset;
+		if (skip_bytes && 
+			((result = stream_skip(skip_bytes)) != skip_bytes)) {
+			printk_err("ERROR: Skip of %ld bytes skiped %ld bytes\n",
+				skip_bytes, result);
+			goto out;
+		}
+		offset = start_offset;
+		
+		/* Copy data from the initial buffer */
+		if (offset < header_size) {
+			size_t len;
+			if ((ptr->s_filesz + start_offset) > header_size) {
+				len = header_size - start_offset;
+			}
+			else {
+				len = ptr->s_filesz;
+			}
+			memcpy(dest, &header[start_offset], len);
+			dest += len;
+		}
+		
+		/* Read the segment into memory */
+		read_bytes = middle - dest;
+		if (read_bytes && 
+			((result = stream_read(dest, read_bytes)) != read_bytes)) {
+			printk_err("ERROR: Read of %ld bytes read %ld bytes...\n",
+				read_bytes, result);
+			goto out;
+		}
+		offset += ptr->s_filesz;
+		
+		/* Zero the extra bytes between middle & end */
+		if (middle < end) {
+			printk_debug("Clearing Segment: addr: 0x%016lx memsz: 0x%016lx\n",
+				(unsigned long)middle, end - middle);
+			
+			/* Zero the extra bytes */
+			memset(middle, 0, end - middle);
+		}
+	}
+	return 1;
+ out:
+	return 0;
+}
+
+static int verify_loaded_image(
+	struct verify_callback *vcb,
+	Elf_ehdr *ehdr, Elf_phdr *phdr,
+	struct segment *head
+	)
+{
+	struct segment *ptr;
+	int ok;
+	ok = 1;
+	for(; ok && vcb ; vcb = vcb->next) {
+		/* Find where the note is loaded */
+		/* The whole note must be loaded intact
+		 * so an address of 0 for the descriptor is impossible
+		 */
+		vcb->desc_addr = 0; 
+		for(ptr = head->next; ptr != head; ptr = ptr->next) {
+			unsigned long desc_addr;
+			desc_addr = ptr->s_addr + vcb->desc_offset - ptr->s_offset;
+			if ((desc_addr >= ptr->s_addr) &&
+				(desc_addr < (ptr->s_addr + ptr->s_filesz))) {
+				vcb->desc_addr = desc_addr;
+			}
+		}
+		ok = vcb->callback(vcb, ehdr, phdr, head);
+	}
+	return ok;
+}
+
+int elfload(struct lb_memory *mem,
+	unsigned char *header, unsigned long header_size)
+{
+	Elf_ehdr *ehdr;
+	Elf_phdr *phdr;
+	void *entry;
+	struct segment head;
+	struct verify_callback *cb_chain;
+	unsigned long bounce_buffer;
+
+	/* Find a bounce buffer so I can load to linuxBIOS's current location */
+	bounce_buffer = get_bounce_buffer(mem);
+	if (!bounce_buffer) {
+		printk_err("Could not find a bounce buffer...\n");
+		goto out;
+	}
+
+	ehdr = (Elf_ehdr *)header;
+	entry = (void *)(ehdr->e_entry);
+	phdr = (Elf_phdr *)(&header[ehdr->e_phoff]);
+
+	/* Digest elf note information... */
+	cb_chain = 0;
+	if ((phdr[0].p_type == PT_NOTE) && 
+		((phdr[0].p_offset + phdr[0].p_filesz) < header_size)) {
+		cb_chain = process_elf_notes(header,
+			phdr[0].p_offset, phdr[0].p_filesz);
+	}
+
+	/* Preprocess the elf segments */
+	if (!build_elf_segment_list(&head, 
+		bounce_buffer, mem, phdr, ehdr->e_phnum))
+		goto out;
+
+	/* Load the segments */
+	if (!load_elf_segments(&head, header, header_size))
+		goto out;
+
+	printk_spew("Loaded segments\n");
+	/* Verify the loaded image */
+	if (!verify_loaded_image(cb_chain, ehdr, phdr, &head)) 
+		goto out;
+
+	printk_spew("verified segments\n");
+	/* Shutdown the stream device */
+	stream_fini();
+	
+	printk_spew("closed down stream\n");
+	/* Reset to booting from this image as late as possible */
+	boot_successful();
+
+	printk_debug("Jumping to boot code at 0x%x\n", entry);
+	post_code(0xfe);
+
+	/* Jump to kernel */
+	jmp_to_elf_entry(entry, bounce_buffer);
+	return 1;
+
+ out:
+	return 0;
+}
+
+int elfboot(struct lb_memory *mem)
+{
+	Elf_ehdr *ehdr;
+	static unsigned char header[ELF_HEAD_SIZE];
+	int header_offset;
+	int i, result;
+
+	result = 0;
+	printk_info("\n");
+	printk_info("Welcome to %s, the open sourced starter.\n", BOOTLOADER);
+	printk_info("January 2002, Eric Biederman.\n");
+	printk_info("Version %s\n", BOOTLOADER_VERSION);
+	printk_info("\n");
+	post_code(0xf8);
+
+	if (stream_init() < 0) {
+		printk_err("Could not initialize driver...\n");
+		goto out;
+	}
+
+	/* Read in the initial ELF_HEAD_SIZE bytes */
+	if (stream_read(header, ELF_HEAD_SIZE) != ELF_HEAD_SIZE) {
+		printk_err("Read failed...\n");
+		goto out;
+	}
+	/* Scan for an elf header */
+	header_offset = -1;
+	for(i = 0; i < ELF_HEAD_SIZE - (sizeof(Elf_ehdr) + sizeof(Elf_phdr)); i+=16) {
+		ehdr = (Elf_ehdr *)(&header[i]);
+		if (memcmp(ehdr->e_ident, ELFMAG, 4) != 0) {
+			printk_spew("NO header at %d\n", i);
+			continue;
+		}
+		printk_debug("Found ELF candiate at offset %d\n", i);
+		/* Sanity check the elf header */
+		if ((ehdr->e_type == ET_EXEC) &&
+			elf_check_arch(ehdr) &&
+			(ehdr->e_ident[EI_VERSION] == EV_CURRENT) &&
+			(ehdr->e_version == EV_CURRENT) &&
+			(ehdr->e_ehsize == sizeof(Elf_ehdr)) &&
+			(ehdr->e_phentsize = sizeof(Elf_phdr)) &&
+			(ehdr->e_phoff < (ELF_HEAD_SIZE - i)) &&
+			((ehdr->e_phoff + (ehdr->e_phentsize * ehdr->e_phnum)) <= 
+				(ELF_HEAD_SIZE - i))) {
+			header_offset = i;
+			break;
+		}
+		ehdr = 0;
+	}
+	printk_spew("header_offset is %d\n", header_offset);
+	if (header_offset == -1) {
+		goto out;
+	}
+
+	printk_spew("Try to load at offset 0x%x\n", header_offset);
+	result = elfload(mem, 
+		header + header_offset , ELF_HEAD_SIZE - header_offset);
+ out:
+	if (!result) {
+		/* Shutdown the stream device */
+		stream_fini();
+
+		printk_err("Cannot Load ELF Image\n");
+
+		post_code(0xff);
+	}
+	return 0;
+
+}
diff --git a/src/boot/hardwaremain.c b/src/boot/hardwaremain.c
new file mode 100644
index 0000000..3507f88
--- /dev/null
+++ b/src/boot/hardwaremain.c
@@ -0,0 +1,216 @@
+/*
+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.
+ */
+/* Copyright 2000, Ron Minnich, Advanced Computing Lab, LANL
+ * rminnich@lanl.gov
+ */
+
+
+/*
+ * C Bootstrap code for the LinuxBIOS
+ */
+
+
+#include <console/console.h>
+#include <cpu/cpu.h>
+#include <mem.h>
+#include <version.h>
+#include <smp/start_stop.h>
+#include <boot/tables.h>
+#include <part/sizeram.h>
+#include <device.h>
+#include <pci.h>
+#if 0
+#include <part/mainboard.h>
+#endif
+#if 0
+#include <part/hard_reset.h>
+#endif
+#include <smp/atomic.h>
+#include <boot/elf.h>
+
+
+#ifndef CONFIG_MAX_PHYSICAL_CPUS
+#define CONFIG_MAX_PHYSICAL_CPUS CONFIG_MAX_CPUS
+#endif
+
+/* The processor map. 
+ * Now that SMP is in linuxbios, and Linux counts on us
+ * giving accurate information about processors, we need a map
+ * of what processors are out there. This could be a bit mask, 
+ * but we will be optimistic and hope we someday run on 
+ * REALLY BIG SMPs. Also we may need more than one bit of 
+ * info per processor at some point. I hope we don't need 
+ * anything more complex than an int.
+ */
+static unsigned long processor_map[MAX_CPUS];
+
+static struct mem_range *get_ramsize(void)
+{
+	struct mem_range *mem = 0;
+	if (!mem) {
+		mem = sizeram();
+	}
+	if (!mem) {
+		printk_err("No memory size information!\n");
+		for(;;);
+	}
+	return mem;
+}
+
+
+#if SMP == 1
+/* Number of cpus that are currently running in linuxbios */
+static atomic_t active_cpus = ATOMIC_INIT(1);
+
+void secondary_cpu_init(void)
+{
+	struct mem_range *mem;
+	unsigned long id;
+	int index;
+
+	atomic_inc(&active_cpus);
+	printk_debug(__FUNCTION__ "\n");
+	mem = get_ramsize();
+	id = cpu_initialize(mem);
+	index = processor_index(id);
+	printk_debug(__FUNCTION__ "  %d/%u\n", index, id);
+	processor_map[index] = CPU_ENABLED;
+	atomic_dec(&active_cpus);
+	stop_cpu(id);
+}
+
+static void wait_for_other_cpus(void)
+{
+	int old_active_count, active_count;
+	int i;
+	old_active_count = 1;
+
+	active_count = atomic_read(&active_cpus);
+	while(active_count > 1) {
+		if (active_count != old_active_count) {
+			printk_info("Waiting for %d CPUS to stop\n", active_count);
+			old_active_count = active_count;
+		}
+		active_count = atomic_read(&active_cpus);
+	}
+	for(i = 0; i < MAX_CPUS; i++) {
+		if (!(processor_map[i] & CPU_ENABLED)) {
+			printk_err("CPU %d/%u did not initialize!\n",
+				i, initial_apicid[i]);
+			processor_map[i] = 0;
+			mainboard_cpu_fixup(i);
+		}
+	}
+	printk_debug("All AP CPUs stopped\n");
+}
+
+#else /* SMP */
+#define wait_for_other_cpus() do {} while(0)
+#endif /* SMP */
+
+void hardwaremain(int boot_complete)
+{
+	/* Processor ID of the BOOT cpu (i.e. the one running this code) */
+	unsigned long boot_cpu;
+	int boot_index;
+
+	/* the order here is a bit tricky. We don't want to do much of 
+	 * anything that uses config registers until after PciAllocateResources
+	 * since that function also figures out what kind of config strategy
+	 * to use (type 1 or type 2). 
+	 * so we turn on cache, then worry about PCI setup, then do other 
+	 * things, so that the other work can use the PciRead* and PciWrite*
+	 * functions. 
+	 */
+	struct mem_range *mem, *tmem;
+	struct lb_memory *lb_mem;
+	unsigned long totalmem;
+
+	post_code(0x80);
+	/* displayinit MUST PRECEDE ALL PRINTK! */
+	console_init();
+	
+	post_code(0x39);
+	printk_notice("LinuxBIOS-%s%s %s %s...\n", 
+		linuxbios_version, linuxbios_extra_version, linuxbios_build,
+		(boot_complete)?"rebooting":"booting");
+
+	post_code(0x40);
+
+#if 0
+	/* If we have already booted attempt a hard reboot */
+	if (boot_complete) {
+		hard_reset();
+	}
+#endif
+#if 1
+
+	// pick how to scan the bus. This is first so we can get at memory size.
+	printk_info("Finding PCI configuration type.\n");
+	pci_set_method();
+	post_code(0x5f);
+#if 0
+	enumerate_static_devices();
+#endif
+	dev_enumerate();
+	post_code(0x66);
+	// Now do the real bus
+	// we round the total ram up a lot for thing like the SISFB, which 
+	// shares high memory with the CPU. 
+	dev_configure();
+	post_code(0x88);
+
+	dev_enable();
+	dev_initialize();
+	post_code(0x89);
+#endif
+
+	mem = get_ramsize();
+	post_code(0x70);
+	totalmem = 0;
+	for(tmem = mem; tmem->sizek; tmem++) {
+		totalmem += tmem->sizek;
+	}
+	printk_info("totalram: %ldM\n", 
+		(totalmem + 512) >> 10); /* Round to the nearest meg */
+
+	/* Fully initialize the cpu before configuring the bus */
+	boot_cpu = cpu_initialize(mem);
+	boot_index = processor_index(boot_cpu);
+	printk_spew("BOOT CPU is %d\n", boot_cpu);
+	processor_map[boot_index] = CPU_BOOTPROCESSOR|CPU_ENABLED;
+
+	/* Now start the other cpus initializing 
+	 * The sooner they start the sooner they stop.
+	 */
+	post_code(0x75);
+	startup_other_cpus(processor_map);
+	post_code(0x77);
+
+	/* make certain we are the only cpu running in linuxBIOS */
+	wait_for_other_cpus();
+
+	/* Now that we have collected all of our information
+	 * write our configuration tables.
+	 */
+	lb_mem = write_tables(mem, processor_map);
+
+	elfboot(lb_mem);
+}
+
diff --git a/src/config/LinuxBIOSDoc.config b/src/config/LinuxBIOSDoc.config
new file mode 100755
index 0000000..557b952
--- /dev/null
+++ b/src/config/LinuxBIOSDoc.config
@@ -0,0 +1,691 @@
+# Doxyfile 1.2.1
+
+# This file describes the settings to be used by doxygen for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# General configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
+# by quotes) that should identify the project. 
+
+PROJECT_NAME           = "LinuxBIOS"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. 
+# This could be handy for archiving the generated documentation or 
+# if some version control system is used.
+
+PROJECT_NUMBER         = 
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
+# base path where the generated documentation will be put. 
+# If a relative path is entered, it will be relative to the location 
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = .
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all 
+# documentation generated by doxygen is written. Doxygen will use this 
+# information to generate all constant output in the proper language. 
+# The default language is English, other supported languages are: 
+# Dutch, French, Italian, Czech, Swedish, German, Finnish, Japanese, 
+# Spanish, Russian, Croatian, Polish, and Portuguese.
+
+OUTPUT_LANGUAGE        = English
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 
+# documentation are documented, even if no documentation was available. 
+# Private class members and static file members will be hidden unless 
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES 
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
+# will be included in the documentation. 
+
+EXTRACT_PRIVATE        = YES
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file 
+# will be included in the documentation. 
+
+EXTRACT_STATIC         = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
+# undocumented members of documented classes, files or namespaces. 
+# If set to NO (the default) these members will be included in the 
+# various overviews, but no documentation section is generated. 
+# This option has no effect if EXTRACT_ALL is enabled. 
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 
+# undocumented classes that are normally visible in the class hierarchy. 
+# If set to NO (the default) these class will be included in the various 
+# overviews. This option has no effect if EXTRACT_ALL is enabled. 
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
+# include brief member descriptions after the members that are listed in 
+# the file and class documentation (similar to JavaDoc). 
+# Set to NO to disable this. 
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 
+# the brief description of a member or function before the detailed description. 
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 
+# brief descriptions will be completely suppressed. 
+
+REPEAT_BRIEF           = YES
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 
+# Doxygen will generate a detailed section even if there is only a brief 
+# description. 
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 
+# path before files name in the file list and in the header files. If set 
+# to NO the shortest path that makes the file name unique will be used. 
+
+FULL_PATH_NAMES        = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 
+# can be used to strip a user defined part of the path. Stripping is 
+# only done if one of the specified strings matches the left-hand part of 
+# the path. It is allowed to use relative paths in the argument list.
+
+STRIP_FROM_PATH        = 
+
+# The INTERNAL_DOCS tag determines if documentation 
+# that is typed after a \internal command is included. If the tag is set 
+# to NO (the default) then the documentation will be excluded. 
+# Set it to YES to include the internal documentation. 
+
+INTERNAL_DOCS          = NO
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
+# generate a class diagram (in Html and LaTeX) for classes with base or 
+# super classes. Setting the tag to NO turns the diagrams off. 
+
+CLASS_DIAGRAMS         = YES
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will 
+# be generated. Documented entities will be cross-referenced with these sources. 
+
+SOURCE_BROWSER         = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body 
+# of functions and classes directly in the documentation. 
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
+# doxygen to hide any special comment blocks from generated source code 
+# fragments. Normal C and C++ comments will always remain visible. 
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the CASE_SENSE_NAMES tag is set to NO (the default) then Doxygen 
+# will only generate file names in lower case letters. If set to 
+# YES upper case letters are also allowed. This is useful if you have 
+# classes or files whose names only differ in case and if your file system 
+# supports case sensitive file names. 
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
+# will show members with their full class and namespace scopes in the 
+# documentation. If set to YES the scope will be hidden. 
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
+# will generate a verbatim copy of the header file for each class for 
+# which an include is specified. Set to NO to disable this. 
+
+VERBATIM_HEADERS       = YES
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
+# will put list of the files that are included by a file in the documentation 
+# of that file. 
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES (the default) then Doxygen 
+# will interpret the first line (until the first dot) of a JavaDoc-style 
+# comment as the brief description. If set to NO, the Javadoc-style will 
+# behave just like the Qt-style comments. 
+
+JAVADOC_AUTOBRIEF      = YES
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
+# member inherits the documentation from any documented member that it 
+# reimplements. 
+
+INHERIT_DOCS           = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
+# is inserted in the documentation for inline members. 
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 
+# will sort the (detailed) documentation of file and class members 
+# alphabetically by member name. If set to NO the members will appear in 
+# declaration order. 
+
+SORT_MEMBER_DOCS       = YES
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
+# Doxygen uses this value to replace tabs by spaces in code fragments. 
+
+TAB_SIZE               = 8
+
+# The ENABLE_SECTIONS tag can be used to enable conditional 
+# documentation sections, marked by \if sectionname ... \endif. 
+
+ENABLED_SECTIONS       = 
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or 
+# disable (NO) the todo list. This list is created by putting \todo 
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or 
+# disable (NO) the test list. This list is created by putting \test 
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated 
+# by doxygen. Possible values are YES and NO. If left blank NO is used. 
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are 
+# generated by doxygen. Possible values are YES and NO. If left blank 
+# NO is used. 
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will 
+# automatically be disabled. 
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that 
+# doxygen can produce. The string should contain the $file, $line, and $text 
+# tags, which will be replaced by the file and line number from which the 
+# warning originated and the warning text. 
+
+WARN_FORMAT            = "$file:$line: $text"
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain 
+# documented source files. You may enter file names like "myfile.cpp" or 
+# directories like "/usr/src/myproject". Separate the files or directories 
+# with spaces. 
+
+# INPUT                  = ../src
+
+# If the value of the INPUT tag contains directories, you can use the 
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank all files are included. 
+
+# FILE_PATTERNS          = *.c *.h *.S
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories 
+# should be searched for input files as well. Possible values are YES and NO. 
+# If left blank NO is used. 
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should 
+# excluded from the INPUT source files. This way you can easily exclude a 
+# subdirectory from a directory tree whose root is specified with the INPUT tag. 
+
+EXCLUDE                = 
+
+# If the value of the INPUT tag contains directories, you can use the 
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 
+# certain files from those directories. 
+
+EXCLUDE_PATTERNS       = 
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or 
+# directories that contain example code fragments that are included (see 
+# the \include command). 
+
+EXAMPLE_PATH           = 
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the 
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank all files are included. 
+
+EXAMPLE_PATTERNS       = 
+
+# The IMAGE_PATH tag can be used to specify one or more files or 
+# directories that contain image that are included in the documentation (see 
+# the \image command). 
+
+IMAGE_PATH             = 
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should 
+# invoke to filter for each input file. Doxygen will invoke the filter program 
+# by executing (via popen()) the command <filter> <input-file>, where <filter> 
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an 
+# input file. Doxygen will then use the output that the filter program writes 
+# to standard output. 
+
+INPUT_FILTER           = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 
+# of all compounds will be generated. Enable this if the project 
+# contains a lot of classes, structs, unions or interfaces. 
+
+ALPHABETICAL_INDEX     = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 
+# in which this list will be split (can be a number in the range [1..20]) 
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all 
+# classes will be put under the same header in the alphabetical index. 
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that 
+# should be ignored while generating the index headers. 
+
+IGNORE_PREFIX          = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
+# generate HTML output. 
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `html' will be used as the default path. 
+
+HTML_OUTPUT            = html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard header.
+
+HTML_HEADER            = 
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard footer.
+
+HTML_FOOTER            = 
+
+# The HTML_STYLESHEET tag can be used to specify a user defined cascading 
+# style sheet that is used by each HTML page. It can be used to 
+# fine-tune the look of the HTML output. If the tag is left blank doxygen 
+# will generate a default style sheet 
+
+HTML_STYLESHEET        = 
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 
+# files or namespaces will be aligned in HTML using tables. If set to 
+# NO a bullet list will be used. 
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files 
+# will be generated that can be used as input for tools like the 
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) 
+# of the generated HTML documentation. 
+
+GENERATE_HTMLHELP      = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at 
+# top of each HTML page. The value NO (the default) enables the index and 
+# the value YES disables it. 
+
+DISABLE_INDEX          = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
+# generate Latex output. 
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `latex' will be used as the default path. 
+
+LATEX_OUTPUT           = latex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 
+# LaTeX documents. This may be useful for small projects and may help to 
+# save some trees in general. 
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used 
+# by the printer. Possible values are: a4, a4wide, letter, legal and 
+# executive. If left blank a4wide will be used. 
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
+# packages that should be included in the LaTeX output. 
+
+EXTRA_PACKAGES         = 
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for 
+# the generated latex document. The header should contain everything until 
+# the first chapter. If it is left blank doxygen will generate a 
+# standard header. Notice: only use this tag if you know what you are doing! 
+
+LATEX_HEADER           = 
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will 
+# contain links (just like the HTML output) instead of page references 
+# This makes the output suitable for online browsing using a pdf viewer. 
+
+PDF_HYPERLINKS         = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
+# plain latex in the generated Makefile. Set this option to YES to get a 
+# higher quality PDF documentation. 
+
+USE_PDFLATEX           = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 
+# command to the generated LaTeX files. This will instruct LaTeX to keep 
+# running if errors occur, instead of asking the user for help. 
+# This option is also used when generating formulas in HTML. 
+
+LATEX_BATCHMODE        = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 
+# The RTF output is optimised for Word 97 and may not look very pretty with 
+# other RTF readers or editors.
+
+GENERATE_RTF           = YES
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `rtf' will be used as the default path. 
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact 
+# RTF documents. This may be useful for small projects and may help to 
+# save some trees in general. 
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 
+# will contain hyperlink fields. The RTF file will 
+# contain links (just like the HTML output) instead of page references. 
+# This makes the output suitable for online browsing using a WORD or other. 
+# programs which support those fields. 
+# Note: wordpad (write) and others do not support links. 
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's 
+# config file, i.e. a series of assigments. You only have to provide 
+# replacements, missing definitions are set to their default value. 
+
+RTF_STYLESHEET_FILE    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
+# generate man pages 
+
+GENERATE_MAN           = YES
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `man' will be used as the default path. 
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to 
+# the generated man pages (default is the subroutine's section .3) 
+
+MAN_EXTENSION          = .3
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will 
+# generate an XML file that captures the structure of 
+# the code including all documentation. Warning: This feature 
+# is still experimental and very incomplete.
+
+GENERATE_XML           = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
+# evaluate all C-preprocessor directives found in the sources and include 
+# files. 
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 
+# names in the source code. If set to NO (the default) only conditional 
+# compilation will be performed. Macro expansion can be done in a controlled 
+# way by setting EXPAND_ONLY_PREDEF to YES. 
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
+# then the macro expansion is limited to the macros specified with the 
+# PREDEFINED and EXPAND_AS_PREDEFINED tags. 
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
+# in the INCLUDE_PATH (see below) will be search if a #include is found. 
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that 
+# contain include files that are not input files but should be processed by 
+# the preprocessor. 
+
+INCLUDE_PATH           = 
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
+# patterns (like *.h and *.hpp) to filter out the header-files in the 
+# directories. If left blank, the patterns specified with FILE_PATTERNS will 
+# be used. 
+
+INCLUDE_FILE_PATTERNS  = 
+
+# The PREDEFINED tag can be used to specify one or more macro names that 
+# are defined before the preprocessor is started (similar to the -D option of 
+# gcc). The argument of the tag is a list of macros of the form: name 
+# or name=definition (no spaces). If the definition and the = are 
+# omitted =1 is assumed. 
+
+PREDEFINED             = 
+
+# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then 
+# this tag can be used to specify a list of macro names that should be expanded. 
+# The macro definition that is found in the sources will be used. 
+# Use the PREDEFINED tag if you want to use a different macro definition. 
+
+EXPAND_AS_DEFINED      = 
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to external references   
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tagfiles. 
+
+TAGFILES               = 
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create 
+# a tag file that is based on the input files it reads. 
+
+GENERATE_TAGFILE       = 
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed 
+# in the class index. If set to NO only the inherited external classes 
+# will be listed. 
+
+ALLEXTERNALS           = NO
+
+# The PERL_PATH should be the absolute path and name of the perl script 
+# interpreter (i.e. the result of `which perl'). 
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 
+# available from the path. This tool is part of Graphviz, a graph visualization 
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section 
+# have no effect if this option is set to NO (the default) 
+
+HAVE_DOT               = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect inheritance relations. Setting this tag to YES will force the 
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect implementation dependencies (inheritance, containment, and 
+# class references variables) of the class with other documented classes. 
+
+COLLABORATION_GRAPH    = YES
+
+# If the ENABLE_PREPROCESSING, INCLUDE_GRAPH, and HAVE_DOT tags are set to 
+# YES then doxygen will generate a graph for each documented file showing 
+# the direct and indirect include dependencies of the file with other 
+# documented files. 
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, INCLUDED_BY_GRAPH, and HAVE_DOT tags are set to 
+# YES then doxygen will generate a graph for each documented header file showing 
+# the documented files that directly or indirectly include this file 
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
+# will graphical hierarchy of all classes instead of a textual one. 
+
+GRAPHICAL_HIERARCHY    = YES
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be 
+# found. If left blank, it is assumed the dot tool can be found on the path. 
+
+DOT_PATH               = 
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width 
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than 
+# this value, doxygen will try to truncate the graph, so that it fits within 
+# the specified constraint. Beware that most browsers cannot cope with very 
+# large images. 
+
+MAX_DOT_GRAPH_WIDTH    = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height 
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than 
+# this value, doxygen will try to truncate the graph, so that it fits within 
+# the specified constraint. Beware that most browsers cannot cope with very 
+# large images. 
+
+MAX_DOT_GRAPH_HEIGHT   = 1024
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to the search engine   
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be 
+# used. If set to NO the values of all tags below this one will be ignored. 
+
+SEARCHENGINE           = NO
+
+# The CGI_NAME tag should be the name of the CGI script that 
+# starts the search engine (doxysearch) with the correct parameters. 
+# A script with this name will be generated by doxygen. 
+
+CGI_NAME               = search.cgi
+
+# The CGI_URL tag should be the absolute URL to the directory where the 
+# cgi binaries are located. See the documentation of your http daemon for 
+# details. 
+
+CGI_URL                = 
+
+# The DOC_URL tag should be the absolute URL to the directory where the 
+# documentation is located. If left blank the absolute path to the 
+# documentation, with file:// prepended to it, will be used. 
+
+DOC_URL                = 
+
+# The DOC_ABSPATH tag should be the absolute path to the directory where the 
+# documentation is located. If left blank the directory on the local machine 
+# will be used. 
+
+DOC_ABSPATH            = 
+
+# The BIN_ABSPATH tag must point to the directory where the doxysearch binary 
+# is installed. 
+
+BIN_ABSPATH            = /usr/local/bin/
+
+# The EXT_DOC_PATHS tag can be used to specify one or more paths to 
+# documentation generated for other projects. This allows doxysearch to search 
+# the documentation for these projects as well. 
+
+EXT_DOC_PATHS          = 
diff --git a/src/config/doxyscript.base b/src/config/doxyscript.base
new file mode 100755
index 0000000..557b952
--- /dev/null
+++ b/src/config/doxyscript.base
@@ -0,0 +1,691 @@
+# Doxyfile 1.2.1
+
+# This file describes the settings to be used by doxygen for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# General configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
+# by quotes) that should identify the project. 
+
+PROJECT_NAME           = "LinuxBIOS"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. 
+# This could be handy for archiving the generated documentation or 
+# if some version control system is used.
+
+PROJECT_NUMBER         = 
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
+# base path where the generated documentation will be put. 
+# If a relative path is entered, it will be relative to the location 
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = .
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all 
+# documentation generated by doxygen is written. Doxygen will use this 
+# information to generate all constant output in the proper language. 
+# The default language is English, other supported languages are: 
+# Dutch, French, Italian, Czech, Swedish, German, Finnish, Japanese, 
+# Spanish, Russian, Croatian, Polish, and Portuguese.
+
+OUTPUT_LANGUAGE        = English
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 
+# documentation are documented, even if no documentation was available. 
+# Private class members and static file members will be hidden unless 
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES 
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
+# will be included in the documentation. 
+
+EXTRACT_PRIVATE        = YES
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file 
+# will be included in the documentation. 
+
+EXTRACT_STATIC         = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
+# undocumented members of documented classes, files or namespaces. 
+# If set to NO (the default) these members will be included in the 
+# various overviews, but no documentation section is generated. 
+# This option has no effect if EXTRACT_ALL is enabled. 
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 
+# undocumented classes that are normally visible in the class hierarchy. 
+# If set to NO (the default) these class will be included in the various 
+# overviews. This option has no effect if EXTRACT_ALL is enabled. 
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
+# include brief member descriptions after the members that are listed in 
+# the file and class documentation (similar to JavaDoc). 
+# Set to NO to disable this. 
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 
+# the brief description of a member or function before the detailed description. 
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 
+# brief descriptions will be completely suppressed. 
+
+REPEAT_BRIEF           = YES
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 
+# Doxygen will generate a detailed section even if there is only a brief 
+# description. 
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 
+# path before files name in the file list and in the header files. If set 
+# to NO the shortest path that makes the file name unique will be used. 
+
+FULL_PATH_NAMES        = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 
+# can be used to strip a user defined part of the path. Stripping is 
+# only done if one of the specified strings matches the left-hand part of 
+# the path. It is allowed to use relative paths in the argument list.
+
+STRIP_FROM_PATH        = 
+
+# The INTERNAL_DOCS tag determines if documentation 
+# that is typed after a \internal command is included. If the tag is set 
+# to NO (the default) then the documentation will be excluded. 
+# Set it to YES to include the internal documentation. 
+
+INTERNAL_DOCS          = NO
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
+# generate a class diagram (in Html and LaTeX) for classes with base or 
+# super classes. Setting the tag to NO turns the diagrams off. 
+
+CLASS_DIAGRAMS         = YES
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will 
+# be generated. Documented entities will be cross-referenced with these sources. 
+
+SOURCE_BROWSER         = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body 
+# of functions and classes directly in the documentation. 
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
+# doxygen to hide any special comment blocks from generated source code 
+# fragments. Normal C and C++ comments will always remain visible. 
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the CASE_SENSE_NAMES tag is set to NO (the default) then Doxygen 
+# will only generate file names in lower case letters. If set to 
+# YES upper case letters are also allowed. This is useful if you have 
+# classes or files whose names only differ in case and if your file system 
+# supports case sensitive file names. 
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
+# will show members with their full class and namespace scopes in the 
+# documentation. If set to YES the scope will be hidden. 
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
+# will generate a verbatim copy of the header file for each class for 
+# which an include is specified. Set to NO to disable this. 
+
+VERBATIM_HEADERS       = YES
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
+# will put list of the files that are included by a file in the documentation 
+# of that file. 
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES (the default) then Doxygen 
+# will interpret the first line (until the first dot) of a JavaDoc-style 
+# comment as the brief description. If set to NO, the Javadoc-style will 
+# behave just like the Qt-style comments. 
+
+JAVADOC_AUTOBRIEF      = YES
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
+# member inherits the documentation from any documented member that it 
+# reimplements. 
+
+INHERIT_DOCS           = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
+# is inserted in the documentation for inline members. 
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 
+# will sort the (detailed) documentation of file and class members 
+# alphabetically by member name. If set to NO the members will appear in 
+# declaration order. 
+
+SORT_MEMBER_DOCS       = YES
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
+# Doxygen uses this value to replace tabs by spaces in code fragments. 
+
+TAB_SIZE               = 8
+
+# The ENABLE_SECTIONS tag can be used to enable conditional 
+# documentation sections, marked by \if sectionname ... \endif. 
+
+ENABLED_SECTIONS       = 
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or 
+# disable (NO) the todo list. This list is created by putting \todo 
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or 
+# disable (NO) the test list. This list is created by putting \test 
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated 
+# by doxygen. Possible values are YES and NO. If left blank NO is used. 
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are 
+# generated by doxygen. Possible values are YES and NO. If left blank 
+# NO is used. 
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will 
+# automatically be disabled. 
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that 
+# doxygen can produce. The string should contain the $file, $line, and $text 
+# tags, which will be replaced by the file and line number from which the 
+# warning originated and the warning text. 
+
+WARN_FORMAT            = "$file:$line: $text"
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain 
+# documented source files. You may enter file names like "myfile.cpp" or 
+# directories like "/usr/src/myproject". Separate the files or directories 
+# with spaces. 
+
+# INPUT                  = ../src
+
+# If the value of the INPUT tag contains directories, you can use the 
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank all files are included. 
+
+# FILE_PATTERNS          = *.c *.h *.S
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories 
+# should be searched for input files as well. Possible values are YES and NO. 
+# If left blank NO is used. 
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should 
+# excluded from the INPUT source files. This way you can easily exclude a 
+# subdirectory from a directory tree whose root is specified with the INPUT tag. 
+
+EXCLUDE                = 
+
+# If the value of the INPUT tag contains directories, you can use the 
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 
+# certain files from those directories. 
+
+EXCLUDE_PATTERNS       = 
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or 
+# directories that contain example code fragments that are included (see 
+# the \include command). 
+
+EXAMPLE_PATH           = 
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the 
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank all files are included. 
+
+EXAMPLE_PATTERNS       = 
+
+# The IMAGE_PATH tag can be used to specify one or more files or 
+# directories that contain image that are included in the documentation (see 
+# the \image command). 
+
+IMAGE_PATH             = 
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should 
+# invoke to filter for each input file. Doxygen will invoke the filter program 
+# by executing (via popen()) the command <filter> <input-file>, where <filter> 
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an 
+# input file. Doxygen will then use the output that the filter program writes 
+# to standard output. 
+
+INPUT_FILTER           = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 
+# of all compounds will be generated. Enable this if the project 
+# contains a lot of classes, structs, unions or interfaces. 
+
+ALPHABETICAL_INDEX     = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 
+# in which this list will be split (can be a number in the range [1..20]) 
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all 
+# classes will be put under the same header in the alphabetical index. 
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that 
+# should be ignored while generating the index headers. 
+
+IGNORE_PREFIX          = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
+# generate HTML output. 
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `html' will be used as the default path. 
+
+HTML_OUTPUT            = html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard header.
+
+HTML_HEADER            = 
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard footer.
+
+HTML_FOOTER            = 
+
+# The HTML_STYLESHEET tag can be used to specify a user defined cascading 
+# style sheet that is used by each HTML page. It can be used to 
+# fine-tune the look of the HTML output. If the tag is left blank doxygen 
+# will generate a default style sheet 
+
+HTML_STYLESHEET        = 
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 
+# files or namespaces will be aligned in HTML using tables. If set to 
+# NO a bullet list will be used. 
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files 
+# will be generated that can be used as input for tools like the 
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) 
+# of the generated HTML documentation. 
+
+GENERATE_HTMLHELP      = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at 
+# top of each HTML page. The value NO (the default) enables the index and 
+# the value YES disables it. 
+
+DISABLE_INDEX          = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
+# generate Latex output. 
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `latex' will be used as the default path. 
+
+LATEX_OUTPUT           = latex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 
+# LaTeX documents. This may be useful for small projects and may help to 
+# save some trees in general. 
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used 
+# by the printer. Possible values are: a4, a4wide, letter, legal and 
+# executive. If left blank a4wide will be used. 
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
+# packages that should be included in the LaTeX output. 
+
+EXTRA_PACKAGES         = 
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for 
+# the generated latex document. The header should contain everything until 
+# the first chapter. If it is left blank doxygen will generate a 
+# standard header. Notice: only use this tag if you know what you are doing! 
+
+LATEX_HEADER           = 
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will 
+# contain links (just like the HTML output) instead of page references 
+# This makes the output suitable for online browsing using a pdf viewer. 
+
+PDF_HYPERLINKS         = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
+# plain latex in the generated Makefile. Set this option to YES to get a 
+# higher quality PDF documentation. 
+
+USE_PDFLATEX           = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 
+# command to the generated LaTeX files. This will instruct LaTeX to keep 
+# running if errors occur, instead of asking the user for help. 
+# This option is also used when generating formulas in HTML. 
+
+LATEX_BATCHMODE        = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 
+# The RTF output is optimised for Word 97 and may not look very pretty with 
+# other RTF readers or editors.
+
+GENERATE_RTF           = YES
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `rtf' will be used as the default path. 
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact 
+# RTF documents. This may be useful for small projects and may help to 
+# save some trees in general. 
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 
+# will contain hyperlink fields. The RTF file will 
+# contain links (just like the HTML output) instead of page references. 
+# This makes the output suitable for online browsing using a WORD or other. 
+# programs which support those fields. 
+# Note: wordpad (write) and others do not support links. 
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's 
+# config file, i.e. a series of assigments. You only have to provide 
+# replacements, missing definitions are set to their default value. 
+
+RTF_STYLESHEET_FILE    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
+# generate man pages 
+
+GENERATE_MAN           = YES
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `man' will be used as the default path. 
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to 
+# the generated man pages (default is the subroutine's section .3) 
+
+MAN_EXTENSION          = .3
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will 
+# generate an XML file that captures the structure of 
+# the code including all documentation. Warning: This feature 
+# is still experimental and very incomplete.
+
+GENERATE_XML           = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
+# evaluate all C-preprocessor directives found in the sources and include 
+# files. 
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 
+# names in the source code. If set to NO (the default) only conditional 
+# compilation will be performed. Macro expansion can be done in a controlled 
+# way by setting EXPAND_ONLY_PREDEF to YES. 
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
+# then the macro expansion is limited to the macros specified with the 
+# PREDEFINED and EXPAND_AS_PREDEFINED tags. 
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
+# in the INCLUDE_PATH (see below) will be search if a #include is found. 
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that 
+# contain include files that are not input files but should be processed by 
+# the preprocessor. 
+
+INCLUDE_PATH           = 
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
+# patterns (like *.h and *.hpp) to filter out the header-files in the 
+# directories. If left blank, the patterns specified with FILE_PATTERNS will 
+# be used. 
+
+INCLUDE_FILE_PATTERNS  = 
+
+# The PREDEFINED tag can be used to specify one or more macro names that 
+# are defined before the preprocessor is started (similar to the -D option of 
+# gcc). The argument of the tag is a list of macros of the form: name 
+# or name=definition (no spaces). If the definition and the = are 
+# omitted =1 is assumed. 
+
+PREDEFINED             = 
+
+# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then 
+# this tag can be used to specify a list of macro names that should be expanded. 
+# The macro definition that is found in the sources will be used. 
+# Use the PREDEFINED tag if you want to use a different macro definition. 
+
+EXPAND_AS_DEFINED      = 
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to external references   
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tagfiles. 
+
+TAGFILES               = 
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create 
+# a tag file that is based on the input files it reads. 
+
+GENERATE_TAGFILE       = 
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed 
+# in the class index. If set to NO only the inherited external classes 
+# will be listed. 
+
+ALLEXTERNALS           = NO
+
+# The PERL_PATH should be the absolute path and name of the perl script 
+# interpreter (i.e. the result of `which perl'). 
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 
+# available from the path. This tool is part of Graphviz, a graph visualization 
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section 
+# have no effect if this option is set to NO (the default) 
+
+HAVE_DOT               = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect inheritance relations. Setting this tag to YES will force the 
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect implementation dependencies (inheritance, containment, and 
+# class references variables) of the class with other documented classes. 
+
+COLLABORATION_GRAPH    = YES
+
+# If the ENABLE_PREPROCESSING, INCLUDE_GRAPH, and HAVE_DOT tags are set to 
+# YES then doxygen will generate a graph for each documented file showing 
+# the direct and indirect include dependencies of the file with other 
+# documented files. 
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, INCLUDED_BY_GRAPH, and HAVE_DOT tags are set to 
+# YES then doxygen will generate a graph for each documented header file showing 
+# the documented files that directly or indirectly include this file 
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
+# will graphical hierarchy of all classes instead of a textual one. 
+
+GRAPHICAL_HIERARCHY    = YES
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be 
+# found. If left blank, it is assumed the dot tool can be found on the path. 
+
+DOT_PATH               = 
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width 
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than 
+# this value, doxygen will try to truncate the graph, so that it fits within 
+# the specified constraint. Beware that most browsers cannot cope with very 
+# large images. 
+
+MAX_DOT_GRAPH_WIDTH    = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height 
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than 
+# this value, doxygen will try to truncate the graph, so that it fits within 
+# the specified constraint. Beware that most browsers cannot cope with very 
+# large images. 
+
+MAX_DOT_GRAPH_HEIGHT   = 1024
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to the search engine   
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be 
+# used. If set to NO the values of all tags below this one will be ignored. 
+
+SEARCHENGINE           = NO
+
+# The CGI_NAME tag should be the name of the CGI script that 
+# starts the search engine (doxysearch) with the correct parameters. 
+# A script with this name will be generated by doxygen. 
+
+CGI_NAME               = search.cgi
+
+# The CGI_URL tag should be the absolute URL to the directory where the 
+# cgi binaries are located. See the documentation of your http daemon for 
+# details. 
+
+CGI_URL                = 
+
+# The DOC_URL tag should be the absolute URL to the directory where the 
+# documentation is located. If left blank the absolute path to the 
+# documentation, with file:// prepended to it, will be used. 
+
+DOC_URL                = 
+
+# The DOC_ABSPATH tag should be the absolute path to the directory where the 
+# documentation is located. If left blank the directory on the local machine 
+# will be used. 
+
+DOC_ABSPATH            = 
+
+# The BIN_ABSPATH tag must point to the directory where the doxysearch binary 
+# is installed. 
+
+BIN_ABSPATH            = /usr/local/bin/
+
+# The EXT_DOC_PATHS tag can be used to specify one or more paths to 
+# documentation generated for other projects. This allows doxysearch to search 
+# the documentation for these projects as well. 
+
+EXT_DOC_PATHS          = 
diff --git a/src/config/linuxbios_c.ld b/src/config/linuxbios_c.ld
new file mode 100644
index 0000000..187a99a
--- /dev/null
+++ b/src/config/linuxbios_c.ld
@@ -0,0 +1,112 @@
+/*
+ *	Memory map:
+ *
+ *	_RAMBASE		
+ *				: data segment
+ *				: bss segment
+ *				: heap
+ *				: stack
+ */
+/*
+ * Bootstrap code for the STPC Consumer
+ * Copyright (c) 1999 by Net Insight AB. All Rights Reserved.
+ *
+ * $Id$
+ *
+ */
+
+/*
+ *	Written by Johan Rydberg, based on work by Daniel Kahlin.
+ *      Rewritten by Eric Biederman
+ */
+/*
+ *	We use ELF as output format. So that we can
+ *	debug the code in some form. 
+ */
+INCLUDE ldoptions
+
+ENTRY(_start)
+
+SECTIONS
+{
+	. = _RAMBASE;
+	/*
+	 * First we place the code and read only data (typically const declared).
+	 * This get placed in rom.
+	 */
+	.text : {
+		_text = .;
+		*(.text);
+		*(.text.*);
+		. = ALIGN(16);
+		_etext = .;
+	}
+	.rodata : {
+		_rodata = .;
+		. = ALIGN(4);
+		console_drivers = .;
+		*(.rodata.console_drivers)
+		econsole_drivers = . ;
+		. = ALIGN(4);
+		pci_drivers = . ;
+		*(.rodata.pci_drivers)
+		epci_drivers = . ;
+		*(.rodata)
+		*(.rodata.*)
+		/*
+		 * kevinh/Ispiri - Added an align, because the objcopy tool
+		 * incorrectly converts sections that are not long word aligned.
+		 * This breaksthe linuxbios.strip target.
+		 */
+		 . = ALIGN(4);
+
+		_erodata = .;
+	}	
+	/*
+	 * After the code we place initialized data (typically initialized
+	 * global variables). This gets copied into ram by startup code.
+	 * __data_start and __data_end shows where in ram this should be placed,
+	 * whereas __data_loadstart and __data_loadend shows where in rom to
+	 * copy from.
+	 */
+	.data : {
+		_data = .;
+		*(.data)
+		_edata = .;
+	}
+	/*
+	 * bss does not contain data, it is just a space that should be zero
+	 * initialized on startup. (typically uninitialized global variables)
+	 * crt0.S fills between _bss and _ebss with zeroes.
+	 */
+	_bss = .;
+	.bss . : {
+		*(.bss)
+		*(.sbss)
+		*(COMMON)
+	}
+	_ebss = .;
+	_end = .;
+	_stack = .;
+	.stack . : {
+		/* Reserve a stack for each possible cpu, +1 extra */
+		. = ((MAX_CPUS * STACK_SIZE) + STACK_SIZE) ; 
+	}
+	_estack = .;
+	_heap = .;
+	.heap . : {
+		/* Reserve 256K for the heap */
+		. = HEAP_SIZE ;
+		. = ALIGN(4);
+	}
+	_eheap = .;
+	/* The ram segment
+ 	 * This is all address of the memory resident copy of linuxBIOS.
+	 */
+	_ram_seg = _text;
+	_eram_seg = _eheap;
+	/DISCARD/ : {
+		*(.comment)
+		*(.note)
+	}
+}
diff --git a/src/console/console.c b/src/console/console.c
new file mode 100644
index 0000000..458fbb8
--- /dev/null
+++ b/src/console/console.c
@@ -0,0 +1,75 @@
+/*
+ * Bootstrap code for the INTEL 
+ * $Id$
+ *
+ */
+
+#include <arch/io.h>
+#include <console/console.h>
+#include <string.h>
+#include <pc80/mc146818rtc.h>
+
+
+static int initialized;
+
+/* initialize the console */
+void console_init(void)
+{
+	struct console_driver *driver;
+	if(get_option(&console_loglevel, "debug_level"))
+		console_loglevel=DEFAULT_CONSOLE_LOGLEVEL;
+
+	for(driver = console_drivers; driver < econsole_drivers; driver++) {
+		if (!driver->init)
+			continue;
+		driver->init();
+	}
+	initialized = 1;
+}
+
+static void __console_tx_byte(unsigned char byte)
+{
+	struct console_driver *driver;
+	for(driver = console_drivers; driver < econsole_drivers; driver++) {
+		driver->tx_byte(byte);
+	}
+}
+
+void console_tx_flush(void)
+{
+	struct console_driver *driver;
+	for(driver = console_drivers; driver < econsole_drivers; driver++) {
+		if (!driver->tx_flush) 
+			continue;
+		driver->tx_flush();
+	}
+}
+
+void console_tx_byte(unsigned char byte)
+{
+	if (!initialized)
+		return;
+	if (byte == '\n')
+		__console_tx_byte('\r');
+	__console_tx_byte(byte);
+}
+
+/*
+ *    Write POST information
+ */
+void post_code(uint8_t value)
+{
+#ifdef CONFIG_SERIAL_POST
+	printk_info("POST: 0x%02x\n", value);
+#elsif !define(NO_POST)
+	outb(value, 0x80);
+#endif
+}
+
+/* Report a fatal error */
+void die(char *msg)
+{
+	printk_emerg("%s", msg);
+	post_code(0xff);
+	while (1);		/* Halt */
+}
diff --git a/src/console/logbuf_console.c b/src/console/logbuf_console.c
new file mode 100644
index 0000000..e605ae5
--- /dev/null
+++ b/src/console/logbuf_console.c
@@ -0,0 +1,19 @@
+#include <console/console.h>
+
+#define LOGBUF_SIZE  1024
+
+// KEEP THIS GLOBAL. 
+// I need the address so I can watch it with the ARIUM hardware. RGM.
+char logbuf[LOGBUF_SIZE];
+int logbuf_offset = 0;
+
+static void logbuf_tx_byte(unsigned char byte)
+{
+	logbuf[logbuf_offset] = byte;
+	logbuf_offset = (logbuf_offset +1) % LOGBUF_SIZE;
+}
+
+static struct console_driver __console = {
+	.init    = 0,
+	.tx_byte = logbuf_tx_byte,
+};}
diff --git a/src/console/printk.c b/src/console/printk.c
new file mode 100644
index 0000000..67b0d4e
--- /dev/null
+++ b/src/console/printk.c
@@ -0,0 +1,56 @@
+/*
+ *  blantantly copied from linux/kernel/printk.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id$";
+#endif
+
+//typedef void * va_list;
+
+#include <stdarg.h>
+#include <smp/spinlock.h>
+#include <console/console.h>
+
+/* printk's without a loglevel use this.. */
+#define DEFAULT_MESSAGE_LOGLEVEL 4 /* BIOS_WARNING */
+
+/* We show everything that is MORE important than this.. */
+#define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */
+
+/* Keep together for sysctl support */
+
+int console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
+int default_message_loglevel = DEFAULT_MESSAGE_LOGLEVEL;
+int minimum_console_loglevel = MINIMUM_CONSOLE_LOGLEVEL;
+int default_console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
+
+void display(char*);
+extern int vtxprintf(void (*)(unsigned char), const char *, va_list);
+
+spinlock_t console_lock = SPIN_LOCK_UNLOCKED;
+
+int do_printk(int msg_level, const char *fmt, ...)
+{
+	va_list args;
+	int i;
+
+	if (msg_level >= console_loglevel) {
+		return 0;
+	}
+
+	spin_lock(&console_lock);
+
+	va_start(args, fmt);
+	i = vtxprintf(console_tx_byte, fmt, args);
+	va_end(args);
+
+	console_tx_flush();
+
+	spin_unlock(&console_lock);
+
+	return i;
+}
diff --git a/src/console/uart8250_console.c b/src/console/uart8250_console.c
new file mode 100644
index 0000000..6eeeb6a
--- /dev/null
+++ b/src/console/uart8250_console.c
@@ -0,0 +1,49 @@
+#include <console/console.h>
+#include <uart8250.h>
+#include <pc80/mc146818rtc.h>
+
+/* Base Address */
+#ifndef TTYS0_BASE
+#define TTYS0_BASE 0x3f8
+#endif
+
+#ifndef TTYS0_BAUD
+#define TTYS0_BAUD 115200
+#endif
+
+#if ((115200%TTYS0_BAUD) != 0)
+#error Bad ttys0 baud rate
+#endif
+
+#define TTYS0_DIV	(115200/TTYS0_BAUD)
+
+/* Line Control Settings */
+#ifndef TTYS0_LCS
+/* Set 8bit, 1 stop bit, no parity */
+#define TTYS0_LCS	0x3
+#endif
+
+#define UART_LCS	TTYS0_LCS
+
+void ttyS0_init(void)
+{
+	static unsigned char div[8]={1,2,3,6,12,24,48,96};
+	int b_index=0;
+	unsigned int divisor=TTYS0_DIV;
+
+	if(get_option(&b_index,"baud_rate")==0) {
+		divisor=div[b_index];
+	}
+	uart8250_init(TTYS0_BASE, divisor, TTYS0_LCS);
+}
+
+void ttyS0_tx_byte(unsigned char data) 
+{
+	uart8250_tx_byte(TTYS0_BASE, data);
+}
+
+static struct console_driver uart8250_console __console = {
+	.init    = ttyS0_init,
+	.tx_byte = ttyS0_tx_byte,
+};
+
diff --git a/src/console/vga_console.c b/src/console/vga_console.c
new file mode 100644
index 0000000..ffd6699
--- /dev/null
+++ b/src/console/vga_console.c
@@ -0,0 +1,100 @@
+/*
+ *
+ * modified from original freebios code
+ * by Steve M. Gehlbach <steve@kesa.com>
+ *
+ */
+
+#include <arch/io.h>
+#include <string.h>
+#include <pc80/vga.h>
+#include <console/console.h>
+
+void beep(int ms);
+
+static char *vidmem;		/* The video buffer, should be replaced by symbol in ldscript.ld */
+int vga_line, vga_col;
+
+#define VIDBUFFER 0xB8000;
+
+static void memsetw(void *s, int c, unsigned int n)
+{
+	int i;
+	 u16 *ss = (u16 *) s;
+
+	for (i = 0; i < n; i++) {
+		ss[i] = ( u16 ) c;
+	}
+}
+
+static void vga_init(void)
+{
+
+	// these are globals
+	vga_line = 0;
+	vga_col = 0;
+	vidmem = (unsigned char *) VIDBUFFER;
+	
+	// mainboard or chip specific init routines
+	// also loads font
+	vga_hardware_fixup();
+	
+	// set attributes, char for entire screen
+	// font should be previously loaded in 
+	// device specific code (vga_hardware_fixup)
+	 memsetw(vidmem, VGA_ATTR_CLR_WHT, 2*1024); //
+}
+
+static void vga_scroll(void)
+{
+	int i;
+
+	memcpy(vidmem, vidmem + COLS * 2, (LINES - 1) * COLS * 2);
+	for (i = (LINES - 1) * COLS * 2; i < LINES * COLS * 2; i += 2)
+		vidmem[i] = ' ';
+}
+
+static void vga_tx_byte(unsigned char byte)
+{
+	if (byte == '\n') {
+		vga_line++;
+		vga_col = 0;
+
+	} else if (byte == '\r') {
+		vga_col = 0;
+
+	} else if (byte == '\b') {
+		vga_col--;
+
+	} else if (byte == '\t') {
+		vga_col += 4;
+
+	} else if (byte == '\a') {
+		//beep
+		beep(500);
+
+	} else {
+		vidmem[((vga_col + (vga_line *COLS)) * 2)] = byte;
+		vidmem[((vga_col + (vga_line *COLS)) * 2) +1] = VGA_ATTR_CLR_WHT;
+		vga_col++;
+	}
+	if (vga_col < 0) {
+		vga_col = 0;
+	}
+	if (vga_col >= COLS) {
+		vga_line++;
+		vga_col = 0;
+	}
+	if (vga_line >= LINES) {
+		vga_scroll();
+		vga_line--;
+	}
+	// move the cursor
+	write_crtc((vga_col + (vga_line *COLS)) >> 8, CRTC_CURSOR_HI);
+	write_crtc((vga_col + (vga_line *COLS)) & 0x0ff, CRTC_CURSOR_LO);
+}
+
+struct console_driver {
+	.init    = vga_init,
+	.tx_byte = vga_tx_byte,
+};
diff --git a/src/console/vsprintf.c b/src/console/vsprintf.c
new file mode 100644
index 0000000..b1310c6
--- /dev/null
+++ b/src/console/vsprintf.c
@@ -0,0 +1,352 @@
+/*
+ *  linux/lib/vsprintf.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
+/*
+ * Wirzenius wrote this portably, Torvalds fucked it up :-)
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id$";
+#endif
+
+#include <stdarg.h>
+#include <string.h>
+
+/* haha, don't need ctype.c */
+#define isdigit(c)	((c) >= '0' && (c) <= '9')
+#define is_digit isdigit
+#define isxdigit(c)	(((c) >= '0' && (c) <= '9') || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F'))
+#define islower(c)	((c) >= 'a' && (c) <= 'z')
+#define toupper(c) __toupper(c)
+
+static inline unsigned char __toupper(unsigned char c)
+{
+        if (islower(c))
+                c -= 'a'-'A';
+        return c;
+}
+
+
+unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
+{
+	unsigned long result = 0,value;
+
+	if (!base) {
+		base = 10;
+		if (*cp == '0') {
+			base = 8;
+			cp++;
+			if ((*cp == 'x') && isxdigit(cp[1])) {
+				cp++;
+				base = 16;
+			}
+		}
+	}
+	while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
+	    ? toupper(*cp) : *cp)-'A'+10) < base) {
+		result = result*base + value;
+		cp++;
+	}
+	if (endp)
+		*endp = (char *)cp;
+	return result;
+}
+
+long simple_strtol(const char *cp,char **endp,unsigned int base)
+{
+	if(*cp=='-')
+		return -simple_strtoul(cp+1,endp,base);
+	return simple_strtoul(cp,endp,base);
+}
+
+
+static int skip_atoi(const char **s)
+{
+	int i=0;
+
+	while (is_digit(**s))
+		i = i*10 + *((*s)++) - '0';
+	return i;
+}
+
+#define ZEROPAD	1		/* pad with zero */
+#define SIGN	2		/* unsigned/signed long */
+#define PLUS	4		/* show plus */
+#define SPACE	8		/* space if plus */
+#define LEFT	16		/* left justified */
+#define SPECIAL	32		/* 0x */
+#define LARGE	64		/* use 'ABCDEF' instead of 'abcdef' */
+
+#define do_div(n,base) ({ \
+int __res; \
+__res = ((unsigned long) n) % (unsigned) base; \
+n = ((unsigned long) n) / (unsigned) base; \
+__res; })
+
+static int number(void (*tx_byte)(unsigned char byte), long num, int base, int size, int precision
+	,int type)
+{
+	char c,sign,tmp[66];
+	const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
+	int i;
+	int count = 0;
+
+	if (type & LARGE)
+		digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+	if (type & LEFT)
+		type &= ~ZEROPAD;
+	if (base < 2 || base > 36)
+		return 0;
+	c = (type & ZEROPAD) ? '0' : ' ';
+	sign = 0;
+	if (type & SIGN) {
+		if (num < 0) {
+			sign = '-';
+			num = -num;
+			size--;
+		} else if (type & PLUS) {
+			sign = '+';
+			size--;
+		} else if (type & SPACE) {
+			sign = ' ';
+			size--;
+		}
+	}
+	if (type & SPECIAL) {
+		if (base == 16)
+			size -= 2;
+		else if (base == 8)
+			size--;
+	}
+	i = 0;
+	if (num == 0)
+		tmp[i++]='0';
+	else while (num != 0)
+		tmp[i++] = digits[do_div(num,base)];
+	if (i > precision)
+		precision = i;
+	size -= precision;
+	if (!(type&(ZEROPAD+LEFT)))
+		while(size-->0)
+			tx_byte(' '), count++;
+	if (sign)
+		tx_byte(sign), count++;
+	if (type & SPECIAL) {
+		if (base==8)
+			tx_byte('0'), count++;
+		else if (base==16) {
+			tx_byte('0'), count++;
+			tx_byte(digits[33]), count++;
+		}
+	}
+	if (!(type & LEFT))
+		while (size-- > 0)
+			tx_byte(c), count++;
+	while (i < precision--)
+		tx_byte('0'), count++;
+	while (i-- > 0)
+		tx_byte(tmp[i]), count++;
+	while (size-- > 0)
+		tx_byte(' '), count++;
+	return count;
+}
+
+
+int vtxprintf(void (*tx_byte)(unsigned char byte), const char *fmt, va_list args)
+{
+	int len;
+	unsigned long num;
+	int i, base;
+	const char *s;
+
+	int flags;		/* flags to number() */
+
+	int field_width;	/* width of output field */
+	int precision;		/* min. # of digits for integers; max
+				   number of chars for from string */
+	int qualifier;		/* 'h', 'l', or 'L' for integer fields */
+	
+	int count;
+
+	for (count=0; *fmt ; ++fmt) {
+		if (*fmt != '%') {
+			tx_byte(*fmt), count++;
+			continue;
+		}
+			
+		/* process flags */
+		flags = 0;
+		repeat:
+			++fmt;		/* this also skips first '%' */
+			switch (*fmt) {
+				case '-': flags |= LEFT; goto repeat;
+				case '+': flags |= PLUS; goto repeat;
+				case ' ': flags |= SPACE; goto repeat;
+				case '#': flags |= SPECIAL; goto repeat;
+				case '0': flags |= ZEROPAD; goto repeat;
+				}
+		
+		/* get field width */
+		field_width = -1;
+		if (is_digit(*fmt))
+			field_width = skip_atoi(&fmt);
+		else if (*fmt == '*') {
+			++fmt;
+			/* it's the next argument */
+			field_width = va_arg(args, int);
+			if (field_width < 0) {
+				field_width = -field_width;
+				flags |= LEFT;
+			}
+		}
+
+		/* get the precision */
+		precision = -1;
+		if (*fmt == '.') {
+			++fmt;	
+			if (is_digit(*fmt))
+				precision = skip_atoi(&fmt);
+			else if (*fmt == '*') {
+				++fmt;
+				/* it's the next argument */
+				precision = va_arg(args, int);
+			}
+			if (precision < 0)
+				precision = 0;
+		}
+
+		/* get the conversion qualifier */
+		qualifier = -1;
+		if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
+			qualifier = *fmt;
+			++fmt;
+		}
+
+		/* default base */
+		base = 10;
+
+		switch (*fmt) {
+		case 'c':
+			if (!(flags & LEFT))
+				while (--field_width > 0)
+					tx_byte(' '), count++;
+			tx_byte((unsigned char) va_arg(args, int)), count++;
+			while (--field_width > 0)
+				tx_byte(' '), count++;
+			continue;
+
+		case 's':
+			s = va_arg(args, char *);
+			if (!s)
+				s = "<NULL>";
+
+			len = strnlen(s, precision);
+
+			if (!(flags & LEFT))
+				while (len < field_width--)
+					tx_byte(' '), count++;
+			for (i = 0; i < len; ++i)
+				tx_byte(*s++), count++;
+			while (len < field_width--)
+				tx_byte(' '), count++;
+			continue;
+
+		case 'p':
+			if (field_width == -1) {
+				field_width = 2*sizeof(void *);
+				flags |= ZEROPAD;
+			}
+			count += number(tx_byte,
+				(unsigned long) va_arg(args, void *), 16,
+				field_width, precision, flags);
+			continue;
+
+
+		case 'n':
+			if (qualifier == 'l') {
+				long * ip = va_arg(args, long *);
+				*ip = count;
+			} else {
+				int * ip = va_arg(args, int *);
+				*ip = count;
+			}
+			continue;
+
+		case '%':
+			tx_byte('%'), count++;
+			continue;
+
+		/* integer number formats - set up the flags and "break" */
+		case 'o':
+			base = 8;
+			break;
+
+		case 'X':
+			flags |= LARGE;
+		case 'x':
+			base = 16;
+			break;
+
+		case 'd':
+		case 'i':
+			flags |= SIGN;
+		case 'u':
+			break;
+
+		default:
+			tx_byte('%'), count++;
+			if (*fmt)
+				tx_byte(*fmt), count++;
+			else
+				--fmt;
+			continue;
+		}
+		if (qualifier == 'l')
+			num = va_arg(args, unsigned long);
+		else if (qualifier == 'h') {
+			num = (unsigned short) va_arg(args, int);
+			if (flags & SIGN)
+				num = (short) num;
+		} else if (flags & SIGN)
+			num = va_arg(args, int);
+		else
+			num = va_arg(args, unsigned int);
+		count += number(tx_byte, num, base, field_width, precision, flags);
+	}
+	return count;
+}
+
+/* FIXME this global makes vsprintf non-reentrant
+ */
+static char *str_buf;
+static void str_tx_byte(unsigned char byte)
+{
+	*str_buf = byte;
+	str_buf++;
+}
+
+int vsprintf(char * buf, const char *fmt, va_list args)
+{
+	int i;
+	str_buf = buf;
+	i = vtxprintf(str_tx_byte, fmt, args);
+	/* maeder/Ispiri -- The null termination was missing a deference */
+	/*                  and was just zeroing out the pointer instead */
+	*str_buf = '\0';
+	return i;
+}
+
+int sprintf(char * buf, const char *fmt, ...)
+{
+	va_list args;
+	int i;
+
+	va_start(args, fmt);
+	i=vsprintf(buf,fmt,args);
+	va_end(args);
+	return i;
+}
diff --git a/src/cpu/i386/entry16.inc b/src/cpu/i386/entry16.inc
new file mode 100644
index 0000000..c357504
--- /dev/null
+++ b/src/cpu/i386/entry16.inc
@@ -0,0 +1,112 @@
+/*
+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.
+ */
+/* Copyright 2000, Ron Minnich, Advanced Computing Lab, LANL
+ * rminnich@lanl.gov
+ */
+
+
+/** Start code to put an i386 or later processor into 32-bit 
+ * protected mode. 
+ */
+
+/* .section ".rom.text" */
+#include <arch/rom_segs.h>
+.code16
+.globl	EXT(_start)
+.type EXT(_start), @function
+
+EXT(_start): 
+	cli
+
+/* thanks to kmliu@sis.tw.com for this TBL fix ... */
+/**/
+/* IMMEDIATELY invalidate the translation lookaside buffer before executing*/
+/* any further code.  Even though paging is disabled we could still get*/
+/*false address translations due to the TLB if we didn't invalidate it.*/
+/**/
+	xorl	%eax, %eax
+	movl	%eax, %cr3    /* Invalidate TLB*/
+
+	/* invalidate the cache */
+	invd 
+
+	/* Note: gas handles memory addresses in 16 bit code very poorly.
+	 * In particular it doesn't appear to have a directive allowing you
+	 * associate a section or even an absolute offset with a segment register.
+	 *
+	 * This means that anything except cs:ip relative offsets are
+	 * a real pain in 16 bit mode.  And explains why it is almost
+	 * imposible to get gas to do lgdt correctly.
+	 *
+	 * One way to work around this is to have the linker do the
+	 * math instead of the assembler.  This solves the very
+	 * pratical problem of being able to write code that can
+	 * be relocated.
+	 *
+	 * An lgdt call before we have memory enabled cannot be 
+	 * position independent, as we cannot execute a call
+	 * instruction to get our current instruction pointer.
+	 * So while this code is relocateable it isn't arbitrarily
+	 * relocatable.
+	 *
+	 * The criteria for relocation have been relaxed to their 
+	 * utmost, so that we can use the same code for both
+	 * our initial entry point and startup of the second cpu.
+	 * The code assumes when executing at _start that:
+	 * (((cs & 0xfff) == 0) and (ip == _start & 0xffff))
+	 * or
+	 * ((cs == anything) and (ip == 0)).
+	 *
+	 * The restrictions in reset16.inc mean that _start initially
+	 * must be loaded at or above 0xffff0000 or below 0x100000.
+	 *
+	 * The linker scripts computs gdtptr16_offset by simply returning
+	 * the low 16 bits.  This means that the intial segment used
+	 * when start is called must be 64K aligned.  This should not
+	 * restrict the address as the ip address can be anything.
+	 */
+
+	movw	%cs, %ax
+	shlw	$4, %ax
+	movw	$EXT(gdtptr16_offset), %bx
+	subw	%ax, %bx
+	data32  lgdt %cs:(%bx)
+
+	movl	%cr0, %eax
+	andl	$0x7FFAFFD1, %eax /* PG,AM,WP,NE,TS,EM,MP = 0 */
+	orl	$0x60000001, %eax /* CD, NW, PE = 1 */
+	movl	%eax, %cr0
+
+	/* Now that we are in protected mode jump to a 32 bit code segment. */
+	data32	ljmp	$ROM_CODE_SEG, $__protected_start
+
+/** The gdt has a 4 Gb code segment at 0x10, and a 4 GB data segment
+ * at 0x18; these are Linux-compatible. 
+ */
+
+.align	4
+.globl EXT(gdtptr16)
+EXT(gdtptr16):
+	.word	gdt_end - gdt -1 /* compute the table limit */
+	.long	gdt		 /* we know the offset */
+
+.globl EXT(_estart)
+EXT(_estart):
+	.code32
+
diff --git a/src/cpu/i386/entry16.lds b/src/cpu/i386/entry16.lds
new file mode 100644
index 0000000..db37e66
--- /dev/null
+++ b/src/cpu/i386/entry16.lds
@@ -0,0 +1,2 @@
+	gdtptr16_offset = gdtptr16 & 0xffff;
+	_start_offset = _start & 0xffff;
diff --git a/src/cpu/i386/entry32.inc b/src/cpu/i386/entry32.inc
new file mode 100644
index 0000000..8ccd638
--- /dev/null
+++ b/src/cpu/i386/entry32.inc
@@ -0,0 +1,55 @@
+/* For starting linuxBIOS in protected mode */
+
+#include <arch/rom_segs.h>
+
+/* 	.section ".rom.text" */
+	.code32
+
+	.align	4
+.globl EXT(gdtptr)
+
+gdt:
+EXT(gdtptr):
+	.word	gdt_end - gdt -1 /* compute the table limit */
+	.long	gdt		 /* we know the offset */
+	.word	0
+
+/* flat code segment */
+	.word	0xffff, 0x0000		
+	.byte	0x00, 0x9b, 0xcf, 0x00	
+	
+/* flat data segment */
+	.word	0xffff, 0x0000		
+	.byte	0x00, 0x93, 0xcf, 0x00	
+
+gdt_end:
+	
+
+/*
+ *	When we come here we are in protected mode. We expand 
+ *	the stack and copies the data segment from ROM to the
+ *	memory.
+ *
+ *	After that, we call the chipset bootstrap routine that
+ *	does what is left of the chipset initialization. 
+ *
+ *	NOTE aligned to 4 so that we are sure that the prefetch
+ *	cache will be reloaded.
+ */
+	.align	4
+.globl EXT(protected_start)
+EXT(protected_start):
+
+	lgdt	%cs:gdtptr
+	ljmp	$ROM_CODE_SEG, $__protected_start
+	
+__protected_start:
+	intel_chip_post_macro(0x10)	/* post 10 */
+
+	movw	$ROM_DATA_SEG, %ax
+	movw	%ax, %ds
+	movw	%ax, %es
+	movw	%ax, %ss
+	movw	%ax, %fs
+	movw	%ax, %gs
+
diff --git a/src/cpu/i386/entry32.lds b/src/cpu/i386/entry32.lds
new file mode 100644
index 0000000..37a75ba
--- /dev/null
+++ b/src/cpu/i386/entry32.lds
@@ -0,0 +1,14 @@
+/*
+	_cache_ram_seg_base = DEFINED(CACHE_RAM_BASE)? CACHE_RAM_BASE - _rodata : 0;
+	_cache_ram_seg_base_low    = (_cache_ram_seg_base) & 0xffff;
+	_cache_ram_seg_base_middle = (_cache_ram_seg_base >> 16) & 0xff;
+	_cache_ram_seg_base_high   = (_cache_ram_seg_base >> 24) & 0xff;
+
+	_rom_code_seg_base =  _ltext - _text;
+	_rom_code_seg_base_low    = (_rom_code_seg_base) & 0xffff;
+	_rom_code_seg_base_middle = (_rom_code_seg_base >> 16) & 0xff;
+	_rom_code_seg_base_high   = (_rom_code_seg_base >> 24) & 0xff;
+*/
+
+
+
diff --git a/src/cpu/i386/reset16.inc b/src/cpu/i386/reset16.inc
new file mode 100644
index 0000000..7c911d9
--- /dev/null
+++ b/src/cpu/i386/reset16.inc
@@ -0,0 +1,27 @@
+	.section ".reset"
+	.code16
+.globl	EXT(reset_vector)
+EXT(reset_vector):
+#if _ROMBASE >= 0xffff0000
+	/* Hmm.
+	 * _start_offset is the low 16 bits of _start.
+	 * Theoretically we should have problems but it compiles
+	 * and links properly with binutils 2.9.5 & 2.10.90
+	 * This is probably a case that needs fixing in binutils.
+	 * And then we can just use _start.
+	 * We also need something like the assume directive in
+	 * other assemblers to tell it where the segment registers
+	 * are pointing in memory right now.
+	 */
+	jmp	EXT(_start_offset)
+#elif (_ROMBASE < 0x100000)
+	ljmp	$((_ROMBASE & 0xf0000)>>4),$EXT(_start_offset);
+#else
+#error	_ROMBASE is an unsupported value
+#endif
+
+	. = 0x8;
+	.code32
+	jmp	EXT(protected_start)
+
+	.previous
diff --git a/src/cpu/i386/reset16.lds b/src/cpu/i386/reset16.lds
new file mode 100644
index 0000000..80f2fc0
--- /dev/null
+++ b/src/cpu/i386/reset16.lds
@@ -0,0 +1,14 @@
+/*
+ *      _ROMTOP                 : The top of the rom used where we
+ *				  need to put the reset vector.
+ */
+
+SECTIONS {
+	_ROMTOP = (_ROMBASE >= 0xffff0000)? 0xfffffff0 : 0xffff0;
+	. = _ROMTOP;
+	.reset . : {
+		*(.reset)
+		. = 15 ;
+		BYTE(0x00);
+	} 
+}
diff --git a/src/cpu/i386/reset32.inc b/src/cpu/i386/reset32.inc
new file mode 100644
index 0000000..ec743b7
--- /dev/null
+++ b/src/cpu/i386/reset32.inc
@@ -0,0 +1,10 @@
+	.section ".reset"
+	.code16
+.globl	EXT(reset_vector)
+EXT(reset_vector):
+
+	. = 0x8;
+	.code32
+	jmp	EXT(protected_start)
+
+	.previous
diff --git a/src/cpu/i386/reset32.lds b/src/cpu/i386/reset32.lds
new file mode 100644
index 0000000..fa6db86
--- /dev/null
+++ b/src/cpu/i386/reset32.lds
@@ -0,0 +1,14 @@
+/*
+ *      _ROMTOP                 : The top of the rom used where we
+ *				  need to put the reset vector.
+ */
+
+SECTIONS {
+	_ROMTOP = _ROMBASE + ROM_IMAGE_SIZE - 0x10;
+	. = _ROMTOP;
+	.reset (.): {
+		*(.reset)
+		. = 15 ;
+		BYTE(0x00);
+	} 
+}
diff --git a/src/cpu/k8/cpufixup.c b/src/cpu/k8/cpufixup.c
new file mode 100644
index 0000000..9f306d1
--- /dev/null
+++ b/src/cpu/k8/cpufixup.c
@@ -0,0 +1,59 @@
+/* Needed so the AMD K8 runs correctly.  */
+#include <console/console.h>
+#include <mem.h>
+#include <cpu/p6/msr.h>
+
+#define TOP_MEM    0xc001001A
+#define TOP_MEM2   0xc001001D
+#define IORR_FIRST 0xC0010016
+#define IORR_LAST  0xC0010019
+#define SYSCFG     0xC0010010
+
+#define MTRRVARDRAMEN (1 << 20)
+
+void k8_cpufixup(struct mem_range *mem)
+{
+	unsigned long lo = 0, hi = 0, i;
+	unsigned long ram_megabytes;
+
+	/* For now no Athlon board has significant holes in it's
+	 * address space so just find the last memory region
+	 * and compute the end of memory from that.
+	 */
+	for(i = 0; mem[i].sizek; i++)
+		;
+	if (i == 0) 
+		return;
+	ram_megabytes = (mem[i-1].basek + mem[i-1].sizek) *1024;
+		
+
+	// 8 MB alignment please
+	ram_megabytes += 0x7fffff;
+	ram_megabytes &= (~0x7fffff);
+
+	// set top_mem registers to ram size
+	printk_spew("Setting top_mem to 0x%x\n", ram_megabytes);
+	rdmsr(TOP_MEM, lo, hi);
+	printk_spew("TOPMEM was 0x%02x:0x%02x\n", hi, lo);
+	hi = 0;
+	lo = ram_megabytes;
+	wrmsr(TOP_MEM, lo, hi);
+
+	// I am setting this even though I won't enable it
+	wrmsr(TOP_MEM2, lo, hi);
+
+	/* zero the IORR's before we enable to prevent
+	 * undefined side effects
+	 */
+	lo = hi = 0;
+	for (i = IORR_FIRST; i <= IORR_LAST; i++)
+		wrmsr(i, lo, hi);
+
+	rdmsr(SYSCFG, lo, hi);
+	printk_spew("SYSCFG was 0x%x:0x%x\n", hi, lo);
+	lo |= MTRRVARDRAMEN;
+	wrmsr(SYSCFG, lo, hi);
+	rdmsr(SYSCFG, lo, hi);
+	printk_spew("SYSCFG IS NOW 0x%x:0x%x\n", hi, lo);
+}
+
diff --git a/src/cpu/k8/earlymtrr.inc b/src/cpu/k8/earlymtrr.inc
new file mode 100644
index 0000000..7cd8443
--- /dev/null
+++ b/src/cpu/k8/earlymtrr.inc
@@ -0,0 +1,99 @@
+#include <cpu/k8/mtrr.h>
+
+/* The fixed and variable MTRRs are powered-up with random values, clear them to
+ * MTRR_TYPE_UNCACHABLE for safty reason 
+ */
+
+earlymtrr_start:
+	xorl	%eax, %eax			# clear %eax and %edx
+	xorl	%edx, %edx			#
+	movl	$fixed_mtrr_msr, %esi
+
+clear_fixed_var_mtrr:
+	lodsl	(%esi), %eax
+	testl	%eax, %eax
+	jz	clear_fixed_var_mtrr_out
+
+	movl	%eax, %ecx
+	xorl	%eax, %eax
+	wrmsr
+
+	jmp	clear_fixed_var_mtrr
+clear_fixed_var_mtrr_out:
+
+/* enable memory access for 0 - 8MB using top_mem */
+	movl	$TOP_MEM, %ecx
+	xorl	%edx, %edx
+	movl	$0x0800000, %eax
+	wrmsr
+
+set_var_mtrr:
+	/* enable caching for 0 - 128MB using variable mtrr */
+	movl	$0x200, %ecx
+	rdmsr
+	andl	$0xfffffff0, %edx
+	orl	$0x00000000, %edx
+	andl	$0x00000f00, %eax
+	orl	$0x00000006, %eax
+	wrmsr
+
+	movl	$0x201, %ecx
+	rdmsr
+	andl	$0xfffffff0, %edx
+	orl	$0x0000000f, %edx
+	andl	$0x000007ff, %eax
+	orl	$0xf0000800, %eax
+	wrmsr
+
+#if defined(XIP_ROM_SIZE) && defined(XIP_ROM_BASE)
+	/* enable write protect caching so we can do execute in place
+	 * on the flash rom.
+	 */
+	movl	$0x202, %ecx
+	xorl	%edx, %edx
+	movl	$(XIP_ROM_BASE | 0x005), %eax
+	wrmsr	
+
+	movl	$0x203, %ecx
+	movl	$0x0000000f, %edx
+	movl	$(~(XIP_ROM_SIZE - 1) | 0x800), %eax
+	wrmsr
+#endif /* XIP_ROM_SIZE && XIP_ROM_BASE */
+
+enable_mtrr:	
+	/* Set the default memory type and enable fixed and variable MTRRs */
+	movl	$0x2ff, %ecx
+	xorl	%edx, %edx
+	/* Enable Variable MTRRs */
+	movl	$0x00000800, %eax
+	wrmsr
+
+	/* Enable the MTRRs in SYSCFG */
+	movl	$SYSCFG_MSR, %ecx
+	rdmsr
+	orl	$(SYSCFG_MSR_MtrrVarDramEn), %eax
+	wrmsr
+
+	/* enable cache */
+	movl	%cr0, %eax
+	andl	$0x9fffffff,%eax
+	movl	%eax, %cr0
+
+	jmp	earlymtrr_end
+
+fixed_mtrr_msr:	
+	.long	0x250, 0x258, 0x259
+	.long	0x268, 0x269, 0x26A
+	.long	0x26B, 0x26C, 0x26D
+	.long	0x26E, 0x26F
+var_mtrr_msr:
+	.long	0x200, 0x201, 0x202, 0x203
+	.long	0x204, 0x205, 0x206, 0x207
+	.long	0x208, 0x209, 0x20A, 0x20B
+	.long	0x20C, 0x20D, 0x20E, 0x20F
+var_iorr_msr:
+	.long	0xC0010016, 0xC0010017, 0xC0010018, 0xC0010019
+mem_top:
+	.long	0xC001001A, 0xC001001D
+	.long	0x000 /* NULL, end of table */
+earlymtrr_end:
diff --git a/src/cpu/p5/cpuid.c b/src/cpu/p5/cpuid.c
new file mode 100644
index 0000000..d90cc2c
--- /dev/null
+++ b/src/cpu/p5/cpuid.c
@@ -0,0 +1,222 @@
+#ifndef lint
+static char rcsid[] = "$Id$";
+#endif
+
+#include <console/console.h>
+#include <cpu/p5/cpuid.h>
+#ifdef i586
+#include <cpu/p6/msr.h>
+#endif
+
+
+int mtrr_check(void)
+{
+#ifdef i686
+	/* Only Pentium Pro and later have MTRR */
+	unsigned long low, high;
+
+	printk_debug("\nMTRR check\n");
+
+	rdmsr(0x2ff, low, high);
+	low = low >> 10;
+
+	printk_debug("Fixed MTRRs   : ");
+	if (low & 0x01)
+		printk_debug("Enabled\n");
+	else
+		printk_debug("Disabled\n");
+
+	printk_debug("Variable MTRRs: ");
+	if (low & 0x02)
+		printk_debug("Enabled\n");
+	else
+		printk_debug("Disabled\n");
+
+	printk_debug("\n");
+
+	post_code(0x93);
+	return ((int) low);
+#else /* !i686 */
+	return 0;
+#endif /* i686 */
+}
+
+void display_cpuid(void)
+{
+	int op, eax, ebx, ecx, edx;
+	int max_op;
+
+	max_op = 0;
+
+	printk_debug("\n");
+
+	for (op = 0; op <= max_op; op++) {
+		cpuid(op, &eax, &ebx, &ecx, &edx);
+
+		if (0 == op) {
+			max_op = eax;
+			printk_debug("Max cpuid index    : %d\n", eax);
+			printk_debug("Vendor ID          : "
+			    "%c%c%c%c%c%c%c%c%c%c%c%c\n",
+			    ebx, ebx >> 8, ebx >> 16, ebx >> 24, edx,
+			    edx >> 8, edx >> 16, edx >> 24, ecx, ecx >> 8,
+			    ecx >> 16, ecx >> 24);
+		} else if (1 == op) {
+			printk_debug("Processor Type     : 0x%02x\n",
+			    (eax >> 12) & 0x03);
+			printk_debug("Processor Family   : 0x%02x\n",
+			    (eax >> 8) & 0x0f);
+			printk_debug("Processor Model    : 0x%02x\n",
+			    (eax >> 4) & 0x0f);
+			printk_debug("Processor Mask     : 0x%02x\n",
+			    (ecx >> 0) & 0x0f);
+			printk_debug("Processor Stepping : 0x%02x\n",
+			    (eax >> 0) & 0x0f);
+			printk_debug("Feature flags      : 0x%08x\n", edx);
+		} else if (2 == op) {
+			int desc[4];
+			int ii;
+			int _desc;
+
+			printk_debug("\n");
+
+			printk_debug("Cache/TLB descriptor values: %d "
+			    "reads required\n", eax & 0xff);
+
+			desc[0] = eax;
+			desc[1] = ebx;
+			desc[2] = ecx;
+			desc[3] = edx;
+
+			for (ii = 1; ii < 16; ii++) {
+				if (desc[ii >> 2] & 0x80000000) {
+					printk_debug("reserved descriptor\n");
+					continue;
+				}
+
+				_desc =
+				    ((desc[ii >> 2]) >> ((ii & 0x3) << 3))
+				    & 0xff;
+				printk_debug("Desc 0x%02x : ", _desc);
+
+				switch (_desc) {
+				case 0x00:
+					printk_debug("null\n");
+					break;
+
+				case 0x01:
+					printk_debug("Instr TLB: "
+					    "4KB pages, "
+					    "4-way set assoc, "
+					    "32 entries\n");
+					break;
+
+				case 0x02:
+					printk_debug("Instr TLB: "
+					    "4MB pages, "
+					    "fully assoc, " "2 entries\n");
+					break;
+
+				case 0x03:
+					printk_debug("Data TLB: "
+					    "4KB pages, "
+					    "4-way set assoc, "
+					    "64 entries\n");
+					break;
+
+				case 0x04:
+					printk_debug("Data TLB: "
+					    "4MB pages, "
+					    "4-way set assoc, "
+					    "8 entries\n");
+					break;
+
+				case 0x06:
+					printk_debug("Inst cache: "
+					    "8K bytes, "
+					    "4-way set assoc, "
+					    "32 byte line size\n");
+					break;
+
+				case 0x08:
+					printk_debug("Inst cache: "
+					    "16K bytes, "
+					    "4-way set assoc, "
+					    "32 byte line size\n");
+					break;
+
+				case 0x0a:
+					printk_debug("Data cache: "
+					    "8K bytes, "
+					    "2-way set assoc, "
+					    "32 byte line size\n");
+					break;
+
+				case 0x0c:
+					printk_debug("Data cache: "
+					    "16K bytes, "
+					    "2-way or 4-way set assoc, "
+					    "32 byte line size\n");
+					break;
+
+				case 0x40:
+					printk_debug("No L2 cache\n");
+					break;
+
+				case 0x41:
+					printk_debug("L2 Unified cache: "
+					    "128K bytes, "
+					    "4-way set assoc, "
+					    "32 byte line size\n");
+					break;
+
+				case 0x42:
+					printk_debug("L2 Unified cache: "
+					    "256K bytes, "
+					    "4-way set assoc, "
+					    "32 byte line size\n");
+					break;
+
+				case 0x43:
+					printk_debug("L2 Unified cache: "
+					    "512K bytes, "
+					    "4-way set assoc, "
+					    "32 byte line size\n");
+					break;
+
+				case 0x44:
+					printk_debug("L2 Unified cache: "
+					    "1M byte, "
+					    "4-way set assoc, "
+					    "32 byte line size\n");
+					break;
+
+				case 0x45:
+					printk_debug("L2 Unified cache: "
+					    "2M byte, "
+					    "4-way set assoc, "
+					    "32 byte line size\n");
+					break;
+
+				case 0x82:
+					printk_debug("L2 Unified cache: "
+					    "256K bytes, "
+					    "8-way set assoc, "
+					    "32 byte line size\n");
+					break;
+
+				default:
+					printk_debug("UNKNOWN\n");
+				}
+			}
+			printk_debug("\n");
+		} else {
+			printk_debug("op: 0x%02x  eax:0x%08x  "
+			    "ebx:0x%08x  ecx:0x%08x  edx:0x%08x\n",
+			    op, eax, ebx, ecx, edx);
+		}
+	}
+
+	printk_debug("\n");
+	post_code(0x92);
+}
diff --git a/src/cpu/p6/mtrr.c b/src/cpu/p6/mtrr.c
new file mode 100644
index 0000000..b88e174
--- /dev/null
+++ b/src/cpu/p6/mtrr.c
@@ -0,0 +1,356 @@
+/*
+ * intel_mtrr.c: setting MTRR to decent values for cache initialization on P6
+ *
+ * Derived from intel_set_mtrr in intel_subr.c and mtrr.c in linux kernel
+ *
+ * Copyright 2000 Silicon Integrated System Corporation
+ *
+ *	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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * Reference: Intel Architecture Software Developer's Manual, Volume 3: System Programming
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id$";
+#endif
+
+#include <console/console.h>
+#include <mem.h>
+#include <cpu/p6/msr.h>
+#include <cpu/p6/mtrr.h>
+#include <cpu/k7/mtrr.h>
+
+#define arraysize(x)   (sizeof(x)/sizeof((x)[0]))
+
+static unsigned int mtrr_msr[] = {
+	MTRRfix64K_00000_MSR, MTRRfix16K_80000_MSR, MTRRfix16K_A0000_MSR,
+	MTRRfix4K_C0000_MSR, MTRRfix4K_C8000_MSR, MTRRfix4K_D0000_MSR, MTRRfix4K_D8000_MSR,
+	MTRRfix4K_E0000_MSR, MTRRfix4K_E8000_MSR, MTRRfix4K_F0000_MSR, MTRRfix4K_F8000_MSR,
+};
+
+
+static void intel_enable_fixed_mtrr(void)
+{
+	unsigned long low, high;
+
+	rdmsr(MTRRdefType_MSR, low, high);
+	low |= 0xc00;
+	wrmsr(MTRRdefType_MSR, low, high);
+}
+
+static void intel_enable_var_mtrr(void)
+{
+	unsigned long low, high;
+
+	rdmsr(MTRRdefType_MSR, low, high);
+	low |= 0x800;
+	wrmsr(MTRRdefType_MSR, low, high);
+}
+
+static inline void disable_cache(void)
+{
+	unsigned int tmp;
+	/* Disable cache */
+	/* Write back the cache and flush TLB */
+	asm volatile (
+		"movl  %%cr0, %0\n\t"
+		"orl  $0x40000000, %0\n\t"
+		"wbinvd\n\t"
+		"movl  %0, %%cr0\n\t"
+		"wbinvd\n\t"
+		:"=r" (tmp)
+		::"memory");
+}
+
+static inline void enable_cache(void)
+{
+	unsigned int tmp;
+	// turn cache back on. 
+	asm volatile (
+		"movl  %%cr0, %0\n\t"
+		"andl  $0x9fffffff, %0\n\t"
+		"movl  %0, %%cr0\n\t"
+		:"=r" (tmp)
+		::"memory");
+}
+
+/* setting variable mtrr, comes from linux kernel source */
+static void intel_set_var_mtrr(unsigned int reg, unsigned long basek, unsigned long sizek, unsigned char type)
+{
+	unsigned long base_high, base_low;
+	unsigned long  mask_high, mask_low;
+
+	base_high = basek >> 22;
+	base_low  = basek << 10;
+
+	if (sizek < 4*1024*1024) {
+		mask_high = 0x0F;
+		mask_low = ~((sizek << 10) -1);
+	}
+	else {
+		mask_high = 0x0F & (~((sizek >> 22) -1));
+		mask_low = 0;
+	}
+
+	if (reg >= 8)
+		return;
+
+	// it is recommended that we disable and enable cache when we 
+	// do this. 
+	disable_cache();
+	if (sizek == 0) {
+		/* The invalid bit is kept in the mask, so we simply clear the
+		   relevant mask register to disable a range. */
+		wrmsr (MTRRphysMask_MSR (reg), 0, 0);
+	} else {
+		/* Bit 32-35 of MTRRphysMask should be set to 1 */
+		wrmsr (MTRRphysBase_MSR(reg), base_low | type, base_high);
+		wrmsr (MTRRphysMask_MSR(reg), mask_low | 0x800, mask_high);
+	}
+	enable_cache();
+}
+
+/* setting variable mtrr, comes from linux kernel source */
+void set_var_mtrr(unsigned int reg, unsigned long base, unsigned long size, unsigned char type)
+{
+	unsigned int tmp;
+
+	if (reg >= 8)
+		return;
+
+	// it is recommended that we disable and enable cache when we 
+	// do this. 
+	disable_cache();
+	if (size == 0) {
+		/* The invalid bit is kept in the mask, so we simply clear the
+		   relevant mask register to disable a range. */
+		wrmsr (MTRRphysMask_MSR (reg), 0, 0);
+	} else {
+		/* Bit 32-35 of MTRRphysMask should be set to 1 */
+		wrmsr (MTRRphysBase_MSR (reg), base | type, 0);
+		wrmsr (MTRRphysMask_MSR (reg), ~(size - 1) | 0x800, 0x0F);
+	}
+
+	// turn cache back on. 
+	enable_cache();
+}
+
+/* fms: find most sigificant bit set, stolen from Linux Kernel Source. */
+static inline unsigned int fms(unsigned int x)
+{
+	int r;
+
+	__asm__("bsrl %1,%0\n\t"
+	        "jnz 1f\n\t"
+	        "movl $0,%0\n"
+	        "1:" : "=r" (r) : "g" (x));
+	return r;
+}
+
+/* fms: find least sigificant bit set */
+static inline unsigned int fls(unsigned int x)
+{
+	int r;
+
+	__asm__("bsfl %1,%0\n\t"
+	        "jnz 1f\n\t"
+	        "movl $32,%0\n"
+	        "1:" : "=r" (r) : "g" (x));
+	return r;
+}
+
+/* setting up variable and fixed mtrr
+ *
+ * From Intel Vol. III Section 9.12.4, the Range Size and Base Alignment has some kind of requirement:
+ *	1. The range size must be 2^N byte for N >= 12 (i.e 4KB minimum).
+ *	2. The base address must be 2^N aligned, where the N here is equal to the N in previous
+ *	   requirement. So a 8K range must be 8K aligned not 4K aligned.
+ *
+ * These requirement is meet by "decompositing" the ramsize into Sum(Cn * 2^n, n = [0..N], Cn = [0, 1]).
+ * For Cm = 1, there is a WB range of 2^m size at base address Sum(Cm * 2^m, m = [N..n]).
+ * A 124MB (128MB - 4MB SMA) example:
+ * 	ramsize = 124MB == 64MB (at 0MB) + 32MB (at 64MB) + 16MB (at 96MB ) + 8MB (at 112MB) + 4MB (120MB).
+ * But this wastes a lot of MTRR registers so we use another more "aggresive" way with Uncacheable Regions.
+ *
+ * In the Uncacheable Region scheme, we try to cover the whole ramsize by one WB region as possible,
+ * If (an only if) this can not be done we will try to decomposite the ramesize, the mathematical formula
+ * whould be ramsize = Sum(Cn * 2^n, n = [0..N], Cn = [-1, 0, 1]). For Cn = -1, a Uncachable Region is used.
+ * The same 124MB example:
+ * 	ramsize = 124MB == 128MB WB (at 0MB) + 4MB UC (at 124MB)
+ * or a 156MB (128MB + 32MB - 4MB SMA) example:
+ *	ramsize = 156MB == 128MB WB (at 0MB) + 32MB WB (at 128MB) + 4MB UC (at 156MB)
+ */
+/* 2 MTRRS are reserved for the operating system */
+#define BIOS_MTRRS 6
+#define OS_MTRRS   2
+#define MTRRS        (BIOS_MTRRS + OS_MTRRS)
+
+
+static void set_fixed_mtrrs(unsigned int first, unsigned int last, unsigned char type)
+{
+	unsigned int i;
+	unsigned int fixed_msr = NUM_FIXED_RANGES >> 3;
+	unsigned long low, high;
+	low = high = 0; /* Shut up gcc */
+	for(i = first; i < last; i++) {
+		/* When I switch to a new msr read it in */
+		if (fixed_msr != i >> 3) {
+			/* But first write out the old msr */
+			if (fixed_msr < (NUM_FIXED_RANGES >> 3)) {
+				disable_cache();
+				wrmsr(mtrr_msr[fixed_msr], low, high);
+				enable_cache();
+			}
+			fixed_msr = i>>3;
+			rdmsr(mtrr_msr[fixed_msr], low, high);
+		}
+		if ((i & 7) < 4) {
+			low &= ~(0xff << ((i&3)*8));
+			low |= type << ((i&3)*8);
+		} else {
+			high &= ~(0xff << ((i&3)*8));
+			high |= type << ((i&3)*8);
+		}
+	}
+	/* Write out the final msr */
+	if (fixed_msr < (NUM_FIXED_RANGES >> 3)) {
+		disable_cache();
+		wrmsr(mtrr_msr[fixed_msr], low, high);
+		enable_cache();
+	}
+}
+
+static unsigned fixed_mtrr_index(unsigned long addrk)
+{
+	unsigned index;
+	index = (addrk - 0) >> 6;
+	if (index >= 8) {
+		index = ((addrk - 8*64) >> 4) + 8;
+	}
+	if (index >= 24) {
+		index = ((addrk - (8*64 + 16*16)) >> 2) + 24;
+	}
+	if (index > NUM_FIXED_RANGES) {
+		index = NUM_FIXED_RANGES;
+	}
+	return index;
+}
+
+static unsigned int range_to_mtrr(unsigned int reg, 
+	unsigned long range_startk, unsigned long range_sizek,
+	unsigned long next_range_startk)
+{
+	if (!range_sizek || (reg >= BIOS_MTRRS)) {
+		return reg;
+	}
+	while(range_sizek) {
+		unsigned long max_align, align;
+		unsigned long sizek;
+		/* Compute the maximum size I can make a range */
+		max_align = fls(range_startk);
+		align = fms(range_sizek); 
+		if (align > max_align) {
+			align = max_align;
+		}
+		sizek = 1 << align;
+		printk_debug("Setting variable MTRR %d, base: %4dMB, range: %4dMB, type WB\n",
+			reg, range_startk >>10, sizek >> 10);
+		intel_set_var_mtrr(reg++, range_startk, sizek, MTRR_TYPE_WRBACK);
+		range_startk += sizek;
+		range_sizek -= sizek;
+		if (reg >= BIOS_MTRRS)
+			break;
+	}
+	return reg;
+}
+
+void setup_mtrrs(struct mem_range *mem)
+{
+	/* Try this the simple way of incrementally adding together
+	 * mtrrs.  If this doesn't work out we can get smart again 
+	 * and clear out the mtrrs.
+	 */
+	struct mem_range *memp;
+	unsigned long range_startk, range_sizek;
+	unsigned int reg;
+
+	printk_debug("\n");
+	/* Initialized the fixed_mtrrs to uncached */
+	printk_debug("Setting fixed MTRRs(%d-%d) type: UC\n", 
+		0, NUM_FIXED_RANGES);
+	set_fixed_mtrrs(0, NUM_FIXED_RANGES, MTRR_TYPE_UNCACHABLE);
+
+	/* Now see which of the fixed mtrrs cover ram.
+	 */
+	for(memp = mem; memp->sizek; memp++) {
+		unsigned int start_mtrr;
+		unsigned int last_mtrr;
+		start_mtrr = fixed_mtrr_index(memp->basek);
+		last_mtrr = fixed_mtrr_index(memp->basek + memp->sizek);
+		if (start_mtrr >= NUM_FIXED_RANGES) {
+			break;
+		}
+		printk_debug("Setting fixed MTRRs(%d-%d) type: WB\n",
+			start_mtrr, last_mtrr);
+		set_fixed_mtrrs(start_mtrr, last_mtrr, MTRR_TYPE_WRBACK);
+	}
+	printk_debug("DONE fixed MTRRs\n");
+	/* Cache as many memory areas as possible */
+	/* FIXME is there an algorithm for computing the optimal set of mtrrs? 
+	 * In some cases it is definitely possible to do better.
+	 */
+	range_startk = 0;
+	range_sizek = 0;
+	reg = 0;
+	for (memp = mem; memp->sizek; memp++) {
+		/* See if I can merge with the last range 
+		 * Either I am below 1M and the fixed mtrrs handle it, or
+		 * the ranges touch.
+		 */
+		if ((memp->basek <= 1024) || (range_startk + range_sizek == memp->basek)) {
+			unsigned long endk = memp->basek + memp->sizek;
+			range_sizek = endk - range_startk;
+			continue;
+		}
+		/* Write the range mtrrs */
+		if (range_sizek != 0) {
+			reg = range_to_mtrr(reg, range_startk, range_sizek, memp->basek);
+			range_startk = 0;
+			range_sizek = 0;
+			if (reg >= BIOS_MTRRS)
+				break;
+		}
+		/* Allocate an msr */
+		range_startk = memp->basek;
+		range_sizek = memp->sizek;
+	}
+	/* Write the last range */
+	reg = range_to_mtrr(reg, range_startk, range_sizek, 0);
+	printk_debug("DONE variable MTRRs\n");
+	printk_debug("Clear out the extra MTRR's\n");
+	/* Clear out the extra MTRR's */
+	while(reg < MTRRS) {
+		intel_set_var_mtrr(reg++, 0, 0, 0);
+	}
+	/* enable fixed MTRR */
+	printk_debug("call intel_enable_fixed_mtrr()\n");
+	intel_enable_fixed_mtrr();
+	printk_debug("call intel_enable_var_mtrr()\n");
+	intel_enable_var_mtrr();
+	printk_debug("Leave %s\n", __FUNCTION__);
+}
diff --git a/src/devices/device.c b/src/devices/device.c
new file mode 100644
index 0000000..ffc7253
--- /dev/null
+++ b/src/devices/device.c
@@ -0,0 +1,423 @@
+/*
+ *      (c) 1999--2000 Martin Mares <mj@suse.cz>
+ *      (c) 2003 Eric Biederman <ebiederm@xmission.com>
+ */
+/* lots of mods by ron minnich (rminnich@lanl.gov), with 
+ * the final architecture guidance from Tom Merritt (tjm@codegen.com)
+ * In particular, we changed from the one-pass original version to 
+ * Tom's recommended multiple-pass version. I wasn't sure about doing 
+ * it with multiple passes, until I actually started doing it and saw
+ * the wisdom of Tom's recommendations ...
+ *
+ * Lots of cleanups by Eric Biederman to handle bridges, and to
+ * handle resource allocation for non-pci devices.
+ */
+
+#include <console/console.h>
+#include <bitops.h>
+#include <device.h>
+#include <arch/io.h>
+#include <pci.h>
+
+/**
+ * This is the root of the device tree. A PCI tree always has 
+ * one bus, bus 0. Bus 0 contains devices and bridges. 
+ */
+struct device dev_root;
+/* Linked list of ALL devices */
+struct device *all_devices = 0;
+/* pointer to the last device */
+static struct device **last_dev_p = &all_devices;
+
+#define DEVICE_MEM_HIGH  0xFEC00000UL /* Reserve 20M for the system */
+#define DEVICE_IO_START 0x1000
+
+
+unsigned long device_memory_base;
+
+
+/* Append a new device to the global device chain.
+ * The chain is used to find devices once everything is set up.
+ */
+void append_device(struct device *dev)
+{
+	*last_dev_p = dev;
+	last_dev_p = &dev->next;
+}
+
+
+/** round a number to an alignment. 
+ * @param val the starting value
+ * @param roundup Alignment as a power of two
+ * @returns rounded up number
+ */
+static unsigned long round(unsigned long val, unsigned long roundup)
+{
+	/* ROUNDUP MUST BE A POWER OF TWO. */
+	unsigned long inverse;
+	inverse = ~(roundup - 1);
+	val += (roundup - 1);
+	val &= inverse;
+	return val;
+}
+
+static unsigned long round_down(unsigned long val, unsigned long round_down)
+{
+	/* ROUND_DOWN MUST BE A POWER OF TWO. */
+	unsigned long inverse;
+	inverse = ~(round_down - 1);
+	val &= inverse;
+	return val;
+}
+
+
+/** Read the resources on all devices of a given bus.
+ * @param bus bus to read the resources on.
+ */
+static void read_resources(struct device *bus)
+{
+	struct device *curdev;
+
+	
+	/* Walk through all of the devices and find which resources they need. */
+	for(curdev = bus->children; curdev; curdev = curdev->sibling) {
+		if (curdev->resources > 0) {
+			continue;
+		}
+		curdev->ops->read_resources(curdev);
+	}
+}
+
+static struct device *largest_resource(struct device *bus, struct resource **result_res,
+	unsigned long type_mask, unsigned long type)
+{
+	struct device *curdev;
+	struct device *result_dev = 0;
+	struct resource *last = *result_res;
+	struct resource *result = 0;
+	int seen_last = 0;
+	for(curdev = bus->children; curdev; curdev = curdev->sibling) {
+		int i;
+		for(i = 0; i < curdev->resources; i++) {
+			struct resource *resource = &curdev->resource[i];
+			/* If it isn't the right kind of resource ignore it */
+			if ((resource->flags & type_mask) != type) {
+				continue;
+			}
+			/* Be certain to pick the successor to last */
+			if (resource == last) {
+				seen_last = 1;
+				continue;
+			}
+			if (last && (
+				(last->align < resource->align) ||
+				((last->align == resource->align) &&
+					(last->size < resource->size)) ||
+				((last->align == resource->align) &&
+					(last->size == resource->size) &&
+					(!seen_last)))) {
+				continue;
+			}
+			if (!result || 
+				(result->align < resource->align) ||
+				((result->align == resource->align) &&
+					(result->size < resource->size))) {
+				result_dev = curdev;
+				result = resource;
+			}
+		}
+	}
+	*result_res = result;
+	return result_dev;
+}
+
+/* Compute allocate resources is the guts of the resource allocator.
+ * 
+ * The problem.
+ *  - Allocate resources locations for every device.
+ *  - Don't overlap, and follow the rules of bridges.
+ *  - Don't overlap with resources in fixed locations.
+ *  - Be efficient so we don't have ugly strategies.
+ *
+ * The strategy.
+ * - Devices that have fixed addresses are the minority so don't
+ *   worry about them too much.  Instead only use part of the address
+ *   space for devices with programmable addresses.  This easily handles
+ *   everything except bridges.
+ *
+ * - PCI devices are required to have thier sizes and their alignments
+ *   equal.  In this case an optimal solution to the packing problem
+ *   exists.  Allocate all devices from highest alignment to least
+ *   alignment or vice versa.  Use this.
+ *
+ * - So we can handle more than PCI run two allocation passes on
+ *   bridges.  The first to see how large the resources are behind
+ *   the bridge, and what their alignment requirements are.  The
+ *   second to assign a safe address to the devices behind the
+ *   bridge.  This allows me to treat a bridge as just a device with 
+ *   a couple of resources, and not need to special case it in the
+ *   allocator.  Also this allows handling of other types of bridges.
+ *
+ */
+
+void compute_allocate_resource(
+	struct device *bus,
+	struct resource *bridge,
+	unsigned long type_mask,
+	unsigned long type)
+{
+	struct device *dev;
+	struct resource *resource;
+	unsigned long base;
+	unsigned long align, min_align;
+	min_align = 0;
+	base = bridge->base;
+
+	/* We want different minimum alignments for different kinds of
+	 * resources.  These minimums are not device type specific
+	 * but resource type specific.
+	 */
+	if (bridge->flags & IORESOURCE_IO) {
+		min_align = log2(DEVICE_IO_ALIGN);
+	}
+	if (bridge->flags & IORESOURCE_MEM) {
+		min_align = log2(DEVICE_MEM_ALIGN);
+	}
+
+	printk_spew("DEV: %02x:%02x.%01x compute_allocate_%s: base: %08lx size: %08lx align: %d gran: %d\n", 
+		bus->bus->secondary,
+		PCI_SLOT(bus->devfn), PCI_FUNC(bus->devfn),
+		(bridge->flags & IORESOURCE_IO)? "io":
+		(bridge->flags & IORESOURCE_PREFETCH)? "prefmem" : "mem",
+		base, bridge->size, bridge->align, bridge->gran);
+
+	/* Make certain I have read in all of the resources */
+	read_resources(bus);
+
+	/* Remember I haven't found anything yet. */
+	resource = 0;
+
+	/* Walk through all the devices on the current bus and compute the addresses */
+	while((dev = largest_resource(bus, &resource, type_mask, type))) {
+		unsigned long size;
+		/* Do NOT I repeat do not ignore resources which have zero size.
+		 * If they need to be ignored dev->read_resources should not even
+		 * return them.   Some resources must be set even when they have
+		 * no size.  PCI bridge resources are a good example of this.
+		 */
+
+		/* Propogate the resource alignment to the bridge register  */
+		if (resource->align > bridge->align) {
+			bridge->align = resource->align;
+		}
+
+		/* Make certain we are dealing with a good minimum size */
+		size = resource->size;
+		align = resource->align;
+		if (align < min_align) {
+			align = min_align;
+		}
+		if (resource->flags & IORESOURCE_IO) {
+			/* Don't allow potential aliases over the
+			 * legacy pci expansion card addresses.
+			 */
+			if ((base > 0x3ff) && ((base & 0x300) != 0)) {
+				base = (base & ~0x3ff) + 0x400;
+			}
+			/* Don't allow allocations in the VGA IO range.
+			 * PCI has special cases for that.
+			 */
+			else if ((base >= 0x3b0) && (base <= 0x3df)) {
+				base = 0x3e0;
+			}
+		}
+		if (((round(base, 1UL << align) + size) -1) <= resource->limit) {
+			/* base must be aligned to size */
+			base = round(base, 1UL << align);
+			resource->base = base;
+			resource->flags |= IORESOURCE_SET;
+			base += size;
+			
+			printk_spew(
+				"DEV: %02x:%02x.%01x %02x *  [0x%08lx - 0x%08lx] %s\n",
+				dev->bus->secondary, 
+				PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), 
+				resource->index, 
+				resource->base, resource->base + resource->size -1,
+				(resource->flags & IORESOURCE_IO)? "io":
+				(resource->flags & IORESOURCE_PREFETCH)? "prefmem": "mem");
+		}
+
+	}
+	/* A pci bridge resource does not need to be a power
+	 * of two size, but it does have a minimum granularity.
+	 * Round the size up to that minimum granularity so we
+	 * know not to place something else at an address postitively
+	 * decoded by the bridge.
+	 */
+	bridge->size = round(base, 1UL << bridge->gran) - bridge->base;
+
+	printk_spew("DEV: %02x:%02x.%01x compute_allocate_%s: base: %08lx size: %08lx align: %d gran: %d done\n", 
+		bus->bus->secondary,
+		PCI_SLOT(bus->devfn), PCI_FUNC(bus->devfn),
+		(bridge->flags & IORESOURCE_IO)? "io":
+		(bridge->flags & IORESOURCE_PREFETCH)? "prefmem" : "mem",
+		base, bridge->size, bridge->align, bridge->gran);
+
+
+}
+
+static void allocate_vga_resource(void)
+{
+	/* FIXME handle the VGA pallette snooping */
+	struct device *dev, *vga, *bus;
+	bus = vga = 0;
+	for(dev = all_devices; dev; dev = dev->next) {
+		uint32_t class_revision;
+		pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_revision);
+		if (((class_revision >> 24) == 0x03) && 
+		    ((class_revision >> 16) != 0x380)) {
+			if (!vga) {
+				printk_debug("Allocating VGA resource\n");
+				vga = dev;
+			}
+			if (vga == dev) {
+				/* All legacy VGA cards have MEM & I/O space registers */
+				dev->command |= PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
+			} else {
+				/* It isn't safe to enable other VGA cards */
+				dev->command &= ~(PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
+			}
+		}
+	}
+	if (vga) {
+		bus = vga->bus;
+	}
+	/* Now walk up the bridges setting the VGA enable */
+	while(bus) {
+		uint16_t ctrl;
+		pci_read_config_word(bus, PCI_BRIDGE_CONTROL, &ctrl);
+		ctrl |= PCI_BRIDGE_CTL_VGA;
+		pci_write_config_word(bus, PCI_BRIDGE_CONTROL, ctrl);
+		bus = (bus == bus->bus)? 0 : bus->bus;
+	} 
+}
+
+
+/** Assign the computed resources to the bridges and devices on the bus.
+ * Recurse to any bridges found on this bus first. Then do the devices
+ * on this bus. 
+ * @param bus Pointer to the structure for this bus
+ */ 
+void assign_resources(struct device *bus)
+{
+	struct device *curdev;
+
+	printk_debug("ASSIGN RESOURCES, bus %d\n", bus->secondary);
+
+	for (curdev = bus->children; curdev; curdev = curdev->sibling) {
+		curdev->ops->set_resources(curdev);
+	}
+	printk_debug("ASSIGNED RESOURCES, bus %d\n", bus->secondary);
+}
+
+static void enable_resources(struct device *bus)
+{
+	struct device *curdev;
+
+	/* Walk through the chain of all pci devices and enable them.
+	 * This is effectively a breadth first traversal so we should
+	 * not have enalbing ordering problems.
+	 */
+	for (curdev = all_devices; curdev; curdev = curdev->next) {
+		uint16_t command;
+		pci_read_config_word(curdev, PCI_COMMAND, &command);
+		command |= curdev->command;
+		printk_debug("DEV: %02x:%02x.%01x cmd <- %02x\n",
+			curdev->bus->secondary,
+			PCI_SLOT(curdev->devfn), PCI_FUNC(curdev->devfn),
+			command);
+		pci_write_config_word(curdev, PCI_COMMAND, command);
+	}
+}
+
+/** Enumerate the resources on the PCI by calling pci_init
+ */
+void dev_enumerate(void)
+{
+	struct device *root;
+	printk_info("Enumerating buses...");
+	root = &dev_root;
+	if (!root->ops) {
+		root->ops = &default_pci_ops_root;
+	}
+	root->subordinate = root->ops->scan_bus(root, 0);
+	printk_info("done\n");
+}
+
+/** Starting at the root, compute what resources are needed and allocate them. 
+ * I/O starts at PCI_IO_START. Since the assignment is hierarchical we
+ * set the values into the dev_root struct. 
+ */
+void dev_configure(void)
+{
+	struct device *root = &dev_root;
+	printk_info("Allocating resources...");
+	printk_debug("\n");
+
+
+	root->ops->read_resources(root);
+
+	/* Make certain the io devices are allocated somewhere
+	 * safe.
+	 */
+	root->resource[0].base = DEVICE_IO_START;
+	root->resource[0].flags |= IORESOURCE_SET;
+	/* Now reallocate the pci resources memory with the
+	 * highest addresses I can manage.
+	 */
+	root->resource[1].base = 
+		round_down(DEVICE_MEM_HIGH - root->resource[1].size,
+			1UL << root->resource[1].align);
+	device_memory_base = root->resource[1].base;
+	root->resource[1].flags |= IORESOURCE_SET;
+	// now just set things into registers ... we hope ...
+	root->ops->set_resources(root);
+
+	allocate_vga_resource();
+
+	printk_info("done.\n");
+}
+
+/** Starting at the root, walk the tree and enable all devices/bridges. 
+ * What really happens is computed COMMAND bits get set in register 4
+ */
+void dev_enable(void)
+{
+	printk_info("Enabling resourcess...");
+
+	/* now enable everything. */
+	enable_resources(&dev_root);
+	printk_info("done.\n");
+}
+
+/** Starting at the root, walk the tree and call a driver to
+ *  do device specific setup.
+ */
+void dev_initialize(void)
+{
+	struct device *dev;
+
+	printk_info("Initializing devices...\n");
+	for (dev = all_devices; dev; dev = dev->next) {
+		if (dev->ops->init) {
+			printk_debug("PCI: %02x:%02x.%01x init\n",
+				dev->bus->secondary,
+				PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+			dev->ops->init(dev);
+		}
+	}
+	printk_info("Devices initialized\n");
+}
+
+
diff --git a/src/devices/device_util.c b/src/devices/device_util.c
new file mode 100644
index 0000000..fdaa20d
--- /dev/null
+++ b/src/devices/device_util.c
@@ -0,0 +1,56 @@
+#include <console/console.h>
+#include <device.h>
+
+/**
+ * Given a bus and a devfn number, find the device structure
+ * @param bus The bus number
+ * @param devfn a device/function number
+ * @return pointer to the device structure
+ */
+struct device *dev_find_slot(unsigned int bus, unsigned int devfn)
+{
+	struct device *dev;
+
+	for (dev = all_devices; dev; dev = dev->next)
+		if (dev->bus->secondary == bus && dev->devfn == devfn)
+			break;
+	return dev;
+}
+
+/** Find a device of a given vendor and type
+ * @param vendor Vendor ID (e.g. 0x8086 for Intel)
+ * @param device Device ID
+ * @param from Pointer to the device structure, used as a starting point
+ *        in the linked list of all_devices, which can be 0 to start at the 
+ *        head of the list (i.e. all_devices)
+ * @return Pointer to the device struct 
+ */
+struct device *dev_find_device(unsigned int vendor, unsigned int device, struct device *from)
+{
+	if (!from)
+		from = all_devices;
+	else
+		from = from->next;
+	while (from && (from->vendor != vendor || from->device != device))
+		from = from->next;
+	return from;
+}
+
+/** Find a device of a given class
+ * @param class Class of the device
+ * @param from Pointer to the device structure, used as a starting point
+ *        in the linked list of all_devices, which can be 0 to start at the 
+ *        head of the list (i.e. all_devices)
+ * @return Pointer to the device struct 
+ */
+struct device *dev_find_class(unsigned int class, struct device *from)
+{
+	if (!from)
+		from = all_devices;
+	else
+		from = from->next;
+	while (from && from->class != class)
+		from = from->next;
+	return from;
+}
+
diff --git a/src/devices/pci_device.c b/src/devices/pci_device.c
new file mode 100644
index 0000000..2b309a9
--- /dev/null
+++ b/src/devices/pci_device.c
@@ -0,0 +1,670 @@
+/*
+ *      PCI Bus Services, see include/linux/pci.h for further explanation.
+ *
+ *      Copyright 1993 -- 1997 Drew Eckhardt, Frederic Potter,
+ *      David Mosberger-Tang
+ *
+ *      Copyright 1997 -- 1999 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *	
+ *	Copyright 2003 -- Eric Biederman <ebiederman@lnxi.com>
+ */
+
+#include <console/console.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <bitops.h>
+#include <pci.h>
+#include <pci_ids.h>
+#include <string.h>
+
+static unsigned int pci_scan_bridge(struct device *bus, unsigned int max);
+
+/** Given a device and register, read the size of the BAR for that register. 
+ * @param dev       Pointer to the device structure
+ * @param resource  Pointer to the resource structure
+ * @param index     Address of the pci configuration register
+ */
+static void pci_get_resource(struct device *dev, struct resource *resource, unsigned long index)
+{
+	uint32_t addr, size, base;
+	unsigned long type;
+
+	/* Initialize the resources to nothing */
+	resource->base = 0;
+	resource->size = 0;
+	resource->align = 0;
+	resource->gran = 0;
+	resource->limit = 0;
+	resource->flags = 0;
+	resource->index = index;
+
+	pci_read_config_dword(dev, index, &addr);
+	if (addr == 0xffffffffUL)
+		return;
+
+	/* FIXME: more consideration for 64-bit PCI devices,
+	 * we currently detect their size but otherwise
+	 * treat them as 32-bit resources
+	 */
+	/* get the size */
+	pci_write_config_dword(dev, index, ~0);
+	pci_read_config_dword(dev,  index, &size);
+
+	/* get the minimum value the bar can be set to */
+	pci_write_config_dword(dev, index, 0);
+	pci_read_config_dword(dev, index, &base);
+
+	/* restore addr */
+	pci_write_config_dword(dev, index, addr);
+
+	/*
+	 * some broken hardware has read-only registers that do not 
+	 * really size correctly. You can tell this if addr == size
+	 * Example: the acer m7229 has BARs 1-4 normally read-only. 
+	 * so BAR1 at offset 0x10 reads 0x1f1. If you size that register
+	 * by writing 0xffffffff to it, it will read back as 0x1f1 -- a 
+	 * violation of the spec. 
+	 * We catch this case and ignore it by settting size and type to 0.
+	 * This incidentally catches the common case where registers 
+	 * read back as 0 for both address and size. 
+	 */
+	if ((addr == size) && (addr == base)) {
+		if (size != 0) {
+			printk_debug(
+				"PCI: %02x:%02x.%01x register %02x(%08x), read-only ignoring it\n",
+				dev->bus->secondary,
+				PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), 
+				index, addr);
+		}
+		resource->flags = 0;
+	}
+	/* Now compute the actual size, See PCI Spec 6.2.5.1 ...  */
+	else if (size & PCI_BASE_ADDRESS_SPACE_IO) {
+		type = size & (~PCI_BASE_ADDRESS_IO_MASK);
+		/* BUG! Top 16 bits can be zero (or not) 
+		 * So set them to 0xffff so they go away ...
+		 */
+		resource->size = (~((size | 0xffff0000) & PCI_BASE_ADDRESS_IO_MASK)) +1;
+		resource->align = log2(resource->size);
+		resource->gran = resource->align;
+		resource->flags = IORESOURCE_IO;
+		resource->limit = 0xffff;
+	} 
+	else {
+		/* A Memory mapped base address */
+		type = size & (~PCI_BASE_ADDRESS_MEM_MASK);
+		resource->size = (~(size &PCI_BASE_ADDRESS_MEM_MASK)) +1;
+		resource->align = log2(resource->size);
+		resource->gran = resource->align;
+		resource->flags = IORESOURCE_MEM;
+		if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) {
+			resource->flags |= IORESOURCE_PREFETCH;
+		}
+		type &= PCI_BASE_ADDRESS_MEM_TYPE_MASK;
+		if (type == PCI_BASE_ADDRESS_MEM_TYPE_32) {
+			/* 32bit limit */
+			resource->limit = 0xffffffffUL;
+		}
+		else if (type == PCI_BASE_ADDRESS_MEM_TYPE_1M) {
+			/* 1MB limit */
+			resource->limit = 0x000fffffUL;
+		}
+		else if (type == PCI_BASE_ADDRESS_MEM_TYPE_64) {
+			unsigned long index_hi;
+			/* 64bit limit 
+			 * For now just treat this as a 32bit limit
+			 */
+			index_hi = index + 4;
+			resource->limit = 0xffffffffUL;
+			resource->flags |= IORESOURCE_PCI64;
+			pci_read_config_dword( dev, index_hi, &addr);
+			/* get the extended size */
+			pci_write_config_dword(dev, index_hi, 0xffffffffUL);
+			pci_read_config_dword( dev, index_hi, &size);
+
+			/* get the minimum value the bar can be set to */
+			pci_write_config_dword(dev, index_hi, 0);
+			pci_read_config_dword(dev,  index_hi, &base);
+
+			/* restore addr */
+			pci_write_config_dword(dev, index_hi, addr);
+			
+			if ((size == 0xffffffff) && (base == 0)) {
+				/* Clear the top half of the bar */
+				pci_write_config_dword(dev, index_hi, 0);
+			}
+			else {
+				printk_err("PCI: %02x:%02x.%01x Unable to handle 64-bit address\n",
+					dev->bus->secondary, 
+					PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+				resource->flags = IORESOURCE_PCI64;
+			}
+		} 
+		else {
+			/* Invalid value */
+			resource->flags = 0;
+		}
+	}
+	/* dev->size holds the flags... */
+	return;
+}
+
+/** Read the base address registers for a given device. 
+ * @param dev Pointer to the dev structure
+ * @param howmany How many registers to read (6 for device, 2 for bridge)
+ */
+static void pci_read_bases(struct device *dev, unsigned int howmany)
+{
+	unsigned int reg;
+	unsigned long index;
+
+	reg = dev->resources;
+	for(index = PCI_BASE_ADDRESS_0; 
+	    (reg < MAX_RESOURCES) && (index < PCI_BASE_ADDRESS_0 + (howmany << 2)); ) {
+		struct resource *resource;
+		resource = &dev->resource[reg];
+		pci_get_resource(dev, resource, index);
+		reg += (resource->flags & (IORESOURCE_IO | IORESOURCE_MEM))? 1:0;
+		index += (resource->flags & IORESOURCE_PCI64)?8:4;
+	}
+	dev->resources = reg;
+}
+
+
+static void pci_bridge_read_bases(struct device *dev)
+{
+	unsigned int reg = dev->resources;
+
+	/* FIXME handle bridges without some of the optional resources */
+
+	/* Initialize the io space constraints on the current bus */
+	dev->resource[reg].base  = 0;
+	dev->resource[reg].size  = 0;
+	dev->resource[reg].align = log2(PCI_IO_BRIDGE_ALIGN);
+	dev->resource[reg].gran  = log2(PCI_IO_BRIDGE_ALIGN);
+	dev->resource[reg].limit = 0xffffUL;
+	dev->resource[reg].flags = IORESOURCE_IO | IORESOURCE_PCI_BRIDGE;
+	dev->resource[reg].index = PCI_IO_BASE;
+	compute_allocate_resource(dev, &dev->resource[reg],
+		IORESOURCE_IO, IORESOURCE_IO);
+	reg++;
+
+	/* Initiliaze the prefetchable memory constraints on the current bus */
+	dev->resource[reg].base = 0;
+	dev->resource[reg].size = 0;
+	dev->resource[reg].align = log2(PCI_MEM_BRIDGE_ALIGN);
+	dev->resource[reg].gran  = log2(PCI_MEM_BRIDGE_ALIGN);
+	dev->resource[reg].limit = 0xffffffffUL;
+	dev->resource[reg].flags = IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_PCI_BRIDGE;
+	dev->resource[reg].index = PCI_PREF_MEMORY_BASE;
+	compute_allocate_resource(dev, &dev->resource[reg],
+		IORESOURCE_MEM | IORESOURCE_PREFETCH, 
+		IORESOURCE_MEM | IORESOURCE_PREFETCH);
+	reg++;
+
+	/* Initialize the memory resources on the current bus */
+	dev->resource[reg].base = 0;
+	dev->resource[reg].size = 0;
+	dev->resource[reg].align = log2(PCI_MEM_BRIDGE_ALIGN);
+	dev->resource[reg].gran  = log2(PCI_MEM_BRIDGE_ALIGN);
+	dev->resource[reg].limit = 0xffffffffUL;
+	dev->resource[reg].flags = IORESOURCE_MEM | IORESOURCE_PCI_BRIDGE;
+	dev->resource[reg].index = PCI_MEMORY_BASE;
+	compute_allocate_resource(dev, &dev->resource[reg],
+		IORESOURCE_MEM | IORESOURCE_PREFETCH, 
+		IORESOURCE_MEM);
+	reg++;
+
+	dev->resources = reg;
+}
+
+
+static void pci_dev_read_resources(struct device *dev)
+{
+	uint32_t addr;
+	dev->resources = 0;
+	memset(&dev->resource[0], 0, sizeof(dev->resource));
+	pci_read_bases(dev, 6);
+	pci_read_config_dword(dev, PCI_ROM_ADDRESS, &addr);
+	dev->rom_address = (addr == 0xffffffff)? 0 : addr;
+}
+
+static void pci_bus_read_resources(struct device *dev)
+{
+	uint32_t addr;
+	dev->resources = 0;
+	memset(&dev->resource[0], 0, sizeof(dev->resource));
+	pci_bridge_read_bases(dev);
+	pci_read_bases(dev, 2);
+	
+	pci_read_config_dword(dev, PCI_ROM_ADDRESS1, &addr);
+	dev->rom_address = (addr == 0xffffffff)? 0 : addr;
+
+}
+
+
+static void pci_set_resource(struct device *dev, struct resource *resource)
+{
+	unsigned long base, limit;
+	unsigned long bridge_align = PCI_MEM_BRIDGE_ALIGN;
+	unsigned char buf[10];
+	
+	/* Make certain the resource has actually been set */
+	if (!(resource->flags & IORESOURCE_SET)) {
+#if 1
+		printk_err("ERROR: %02x:%02x.%01x %02x not allocated\n",
+			dev->bus->secondary,
+			PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), 
+			resource->index);
+#endif
+		return;
+	}
+
+	/* Only handle PCI memory and IO resources for now */
+	if (!(resource->flags & (IORESOURCE_MEM |IORESOURCE_IO)))
+		return;
+	
+	if (resource->flags & IORESOURCE_MEM) {
+		dev->command |= PCI_COMMAND_MEMORY;
+		bridge_align = PCI_MEM_BRIDGE_ALIGN;
+	}
+	if (resource->flags & IORESOURCE_IO) {
+		dev->command |= PCI_COMMAND_IO;
+		bridge_align = PCI_IO_BRIDGE_ALIGN;
+	}
+	if (resource->flags & IORESOURCE_PCI_BRIDGE) {
+		dev->command |= PCI_COMMAND_MASTER;
+	}
+	/* Get the base address */
+	base = resource->base;
+	
+	/* Get the limit (rounded up) */
+	limit = base + ((resource->size + bridge_align - 1UL) & ~(bridge_align -1)) -1UL;
+	
+	if (!(resource->flags & IORESOURCE_PCI_BRIDGE)) {
+		/*
+		 * some chipsets allow us to set/clear the IO bit. 
+		 * (e.g. VIA 82c686a.) So set it to be safe)
+		 */
+		limit = base + resource->size -1;
+		if (resource->flags & IORESOURCE_IO) {
+			base |= PCI_BASE_ADDRESS_SPACE_IO;
+		}
+		pci_write_config_dword(dev, resource->index, base & 0xffffffff);
+		if (resource->flags & IORESOURCE_PCI64) {
+			/* FIXME handle real 64bit base addresses */
+			pci_write_config_dword(dev, resource->index + 4, 0);
+		}
+	}
+	else if (resource->index == PCI_IO_BASE) {
+		/* set the IO ranges
+		 * WARNING: we don't really do 32-bit addressing for IO yet! 
+		 */
+		compute_allocate_resource(dev, resource, 
+			IORESOURCE_IO, IORESOURCE_IO);
+		pci_write_config_byte(dev, PCI_IO_BASE,  base >> 8);
+		pci_write_config_byte(dev, PCI_IO_LIMIT, limit >> 8);
+	}
+	else if (resource->index == PCI_MEMORY_BASE) {
+		/* set the memory range
+		 */
+		compute_allocate_resource(dev, resource,
+			IORESOURCE_MEM | IORESOURCE_PREFETCH, 
+			IORESOURCE_MEM);
+		pci_write_config_word(dev, PCI_MEMORY_BASE, base >> 16);
+		pci_write_config_word(dev, PCI_MEMORY_LIMIT, limit >> 16);
+	}
+	else if (resource->index == PCI_PREF_MEMORY_BASE) {
+		/* set the prefetchable memory range
+		 * WARNING: we don't really do 64-bit addressing for prefetchable memory yet!
+		 */
+		compute_allocate_resource(dev, resource,
+			IORESOURCE_MEM | IORESOURCE_PREFETCH, 
+			IORESOURCE_MEM | IORESOURCE_PREFETCH);
+		pci_write_config_word(dev, PCI_PREF_MEMORY_BASE,  base >> 16);
+		pci_write_config_word(dev, PCI_PREF_MEMORY_LIMIT, limit >> 16);
+	}
+	else {
+		printk_err("ERROR: invalid resource->index %x\n",
+			resource->index);
+	}
+	buf[0] = '\0';
+	if (resource->flags & IORESOURCE_PCI_BRIDGE) {
+		sprintf(buf, "bus %d ", dev->secondary);
+	}
+	
+	printk_debug(
+		"PCI: %02x:%02x.%01x %02x <- [0x%08lx - 0x%08lx] %s%s\n",
+		dev->bus->secondary, 
+		PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), 
+		resource->index, 
+		resource->base, limit,
+		buf,
+		(resource->flags & IORESOURCE_IO)? "io":
+		(resource->flags & IORESOURCE_PREFETCH)? "prefmem": "mem");
+	return;
+}
+
+static void pci_dev_set_resources(struct device *dev)
+{
+	struct resource *resource, *last;
+	uint8_t line;
+
+	last = &dev->resource[dev->resources];
+
+	for(resource = &dev->resource[0]; resource < last; resource++) {
+		pci_set_resource(dev, resource);
+	}
+	if (dev->children) {
+		assign_resources(dev);
+	}
+
+	/* set a default latency timer */
+	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40);
+
+	/* set a default secondary latency timer */
+	if ((dev->hdr_type & 0x7f) == PCI_HEADER_TYPE_BRIDGE) {
+		pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 0x40);
+	}
+
+	/* zero the irq settings */
+	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &line);
+	if (line) {
+		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 0);
+	}
+	/* set the cache line size, so far 64 bytes is good for everyone */
+	pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 64 >> 2);
+}
+
+struct device_operations default_pci_ops_dev = {
+	.read_resources = pci_dev_read_resources,
+	.set_resources = pci_dev_set_resources,
+	.init = 0,
+	.scan_bus = 0,
+};
+struct device_operations default_pci_ops_bus = {
+	.read_resources = pci_bus_read_resources,
+	.set_resources = pci_dev_set_resources,
+	.init = 0,
+	.scan_bus = pci_scan_bridge,
+};
+static void set_pci_ops(struct device *dev)
+{
+	struct pci_driver *driver;
+	if (dev->ops) {
+		return;
+	}
+	/* Look through the list of setup drivers and find one for
+	 * this pci device 
+	 */
+	for(driver = &pci_drivers[0]; driver != &epci_drivers[0]; driver++) {
+		if ((driver->vendor == dev->vendor) &&
+			(driver->device = dev->device)) {
+			dev->ops = driver->ops;
+			break;
+		}
+	}
+	/* If I don't have a specific driver use the default operations */
+	switch(dev->hdr_type & 0x7f) {	/* header type */
+	case PCI_HEADER_TYPE_NORMAL:	/* standard header */
+		if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)
+			goto bad;
+		dev->ops = &default_pci_ops_dev;
+		break;
+	case PCI_HEADER_TYPE_BRIDGE:
+		if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
+			goto bad;
+		dev->ops = &default_pci_ops_bus;
+		break;
+	default:
+	bad:
+		printk_err("PCI: %02x:%02x.%01x [%04x/%04x/%06x] has unknown header "
+			"type %02x, ignoring.\n",
+			dev->bus->secondary, 
+			PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), 
+			dev->vendor, dev->device, 
+			dev->class >> 8, dev->hdr_type);
+	}
+	return;
+}
+
+/**
+ * Given a bus and a devfn number, find the device structure
+ * @param bus The bus structure
+ * @param devfn a device/function number
+ * @return pointer to the device structure
+ */
+static struct device *pci_scan_get_dev(struct device **list, unsigned int devfn)
+{
+	struct device *dev = 0;
+	for(; *list; list = &(*list)->sibling) {
+		if ((*list)->devfn == devfn) {
+			/* Unlink from the list */
+			dev = *list;
+			*list = (*list)->sibling;
+			dev->sibling = 0;
+			break;
+		}
+	}
+	return dev;
+}
+
+
+/** Scan the pci bus devices and bridges.
+ * @param pci_bus pointer to the bus structure
+ * @param max current bus number
+ * @return The maximum bus number found, after scanning all subordinate busses
+ */
+unsigned int pci_scan_bus(struct device *bus, unsigned int max)
+{
+	unsigned int devfn;
+	struct device *dev, **bus_last;
+	struct device *old_devices;
+	struct device *child;
+
+	printk_debug("PCI: pci_scan_bus for bus %d\n", bus->secondary);
+
+	old_devices = bus->children;
+	bus->children = 0;
+	bus_last = &bus->children;
+
+	post_code(0x24);
+	
+
+	/* probe all devices on this bus with some optimization for non-existance and 
+	   single funcion devices */
+	for (devfn = 0; devfn < 0xff; devfn++) {
+		struct device dummy;
+		uint32_t id, class;
+		uint8_t cmd, tmp, hdr_type;
+
+		/* First thing setup the device structure */
+		dev = pci_scan_get_dev(&old_devices, devfn);
+	
+		dummy.bus = bus;
+		dummy.devfn = devfn;
+		pci_read_config_dword(&dummy, PCI_VENDOR_ID, &id);
+		/* some broken boards return 0 if a slot is empty: */
+		if (!dev &&
+			(id == 0xffffffff || id == 0x00000000 || 
+			 id == 0x0000ffff || id == 0xffff0000)) {
+			printk_spew("PCI: devfn 0x%x, bad id 0x%x\n", devfn, id);
+			if (PCI_FUNC(devfn) == 0x00) {
+				/* if this is a function 0 device and it is not present,
+				   skip to next device */
+				devfn += 0x07;
+			}
+			/* multi function device, skip to next function */
+			continue;
+		}
+		pci_read_config_byte(&dummy, PCI_HEADER_TYPE, &hdr_type);
+		pci_read_config_dword(&dummy, PCI_CLASS_REVISION, &class);
+
+		if (!dev) {
+			if ((dev = malloc(sizeof(*dev))) == 0) {
+				printk_err("PCI: out of memory.\n");
+				continue;
+			}
+			memset(dev, 0, sizeof(*dev));
+		}
+
+		dev->bus = bus;
+		dev->devfn = devfn;
+		dev->vendor = id & 0xffff;
+		dev->device = (id >> 16) & 0xffff;
+		dev->hdr_type = hdr_type;
+		/* class code, the upper 3 bytes of PCI_CLASS_REVISION */
+		dev->class = class >> 8;
+
+		/* non-destructively determine if device can be a master: */
+		pci_read_config_byte(dev, PCI_COMMAND, &cmd);
+		pci_write_config_byte(dev, PCI_COMMAND, cmd | PCI_COMMAND_MASTER);
+		pci_read_config_byte(dev, PCI_COMMAND, &tmp);
+
+		dev->master = ((tmp & PCI_COMMAND_MASTER) != 0);
+		pci_write_config_byte(dev, PCI_COMMAND, cmd);
+
+		/* Look at the vendor and device id, or at least the 
+		 * header type and class and figure out which set of configuration
+		 * methods to use.
+		 */
+		set_pci_ops(dev);
+		/* Kill the device if we don't have some pci operations for it */
+		if (!dev->ops) {
+			free(dev);
+			continue;
+		}
+		printk_debug("PCI: %02x:%02x.%01x [%04x/%04x]\n", 
+			bus->secondary, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), 
+			dev->vendor, dev->device);
+
+		/* Put it into the global device chain. */
+		append_device(dev);
+
+		/* Now insert it into the list of devices held by the parent bus. */
+		*bus_last = dev;
+		bus_last = &dev->sibling;
+
+		if (PCI_FUNC(devfn) == 0x00 && (hdr_type & 0x80) != 0x80) {
+			/* if this is not a multi function device, don't waste time probe
+			   another function. Skip to next device. */
+			devfn += 0x07;
+		}
+	}
+	post_code(0x25);
+
+	for(child = bus->children; child; child = child->sibling) {
+		if (!child->ops->scan_bus)
+			continue;
+		max = child->ops->scan_bus(child, max);
+		
+	}
+	/*
+	 * We've scanned the bus and so we know all about what's on
+	 * the other side of any bridges that may be on this bus plus
+	 * any devices.
+	 *
+	 * Return how far we've got finding sub-buses.
+	 */
+	printk_debug("PCI: pci_scan_bus returning with max=%02x\n", max);
+	post_code(0x55);
+	return max;
+}
+
+/** Scan the bus, first for bridges and next for devices. 
+ * @param pci_bus pointer to the bus structure
+ * @return The maximum bus number found, after scanning all subordinate busses
+ */
+static unsigned int pci_scan_bridge(struct device *bus, unsigned int max)
+{
+	uint32_t buses;
+	uint16_t cr;
+	/* Set up the primary, secondary and subordinate bus numbers. We have
+	 * no idea how many buses are behind this bridge yet, so we set the
+	 * subordinate bus number to 0xff for the moment 
+	 */
+	bus->secondary = ++max;
+	bus->subordinate = 0xff;
+	
+	/* Clear all status bits and turn off memory, I/O and master enables. */
+	pci_read_config_word(bus, PCI_COMMAND, &cr);
+	pci_write_config_word(bus, PCI_COMMAND, 0x0000);
+	pci_write_config_word(bus, PCI_STATUS, 0xffff);
+
+	/*
+	 * Read the existing primary/secondary/subordinate bus
+	 * number configuration.
+	 */
+	pci_read_config_dword(bus, PCI_PRIMARY_BUS, &buses);
+
+	/* Configure the bus numbers for this bridge: the configuration
+	 * transactions will not be propagated by the bridge if it is not
+	 * correctly configured 
+	 */
+	buses &= 0xff000000;
+	buses |= (((unsigned int) (bus->bus->secondary) << 0) |
+		((unsigned int) (bus->secondary) << 8) |
+		((unsigned int) (bus->subordinate) << 16));
+	pci_write_config_dword(bus, PCI_PRIMARY_BUS, buses);
+	
+	/* Now we can scan all subordinate buses i.e. the bus hehind the bridge */
+	max = pci_scan_bus(bus, max);
+	
+	/* We know the number of buses behind this bridge. Set the subordinate
+	 *  bus number to its real value 
+	 */
+	bus->subordinate = max;
+	buses = (buses & 0xff00ffff) |
+		((unsigned int) (bus->subordinate) << 16);
+	pci_write_config_dword(bus, PCI_PRIMARY_BUS, buses);
+	pci_write_config_word(bus, PCI_COMMAND, cr);
+		
+	return max;
+}
+
+
+static void pci_root_read_resources(struct device *bus)
+{
+	int res = 0;
+	/* Initialize the system wide io space constraints */
+	bus->resource[res].base  = 0x400;
+	bus->resource[res].size  = 0;
+	bus->resource[res].align = 0;
+	bus->resource[res].gran  = 0;
+	bus->resource[res].limit = 0xffffUL;
+	bus->resource[res].flags = IORESOURCE_IO;
+	bus->resource[res].index = PCI_IO_BASE;
+	compute_allocate_resource(bus, &bus->resource[res], 
+		IORESOURCE_IO, IORESOURCE_IO);
+	res++;
+
+	/* Initialize the system wide memory resources constraints */
+	bus->resource[res].base  = 0;
+	bus->resource[res].size  = 0;
+	bus->resource[res].align = 0;
+	bus->resource[res].gran  = 0;
+	bus->resource[res].limit = 0xffffffffUL;
+	bus->resource[res].flags = IORESOURCE_MEM;
+	bus->resource[res].index = PCI_MEMORY_BASE;
+	compute_allocate_resource(bus, &bus->resource[res], 
+		IORESOURCE_MEM, IORESOURCE_MEM);
+	res++;
+
+	bus->resources = res;
+}
+static void pci_root_set_resources(struct device *bus)
+{
+	compute_allocate_resource(bus,
+		&bus->resource[0], IORESOURCE_IO, IORESOURCE_IO);
+	compute_allocate_resource(bus, 
+		&bus->resource[1], IORESOURCE_MEM, IORESOURCE_MEM);
+	assign_resources(bus);
+}
+
+struct device_operations default_pci_ops_root = {
+	.read_resources = pci_root_read_resources,
+	.set_resources = pci_root_set_resources,
+	.init = 0,
+	.scan_bus = pci_scan_bus,
+};
+
diff --git a/src/include/boot/elf.h b/src/include/boot/elf.h
new file mode 100644
index 0000000..3503388
--- /dev/null
+++ b/src/include/boot/elf.h
@@ -0,0 +1,401 @@
+#ifndef ELF_H
+#define	ELF_H
+
+/* Standard ELF types.  */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <arch/boot/boot.h>
+
+/* Type for a 16-bit quantity.  */
+typedef uint16_t Elf32_Half;
+typedef uint16_t Elf64_Half;
+
+/* Types for signed and unsigned 32-bit quantities.  */
+typedef uint32_t Elf32_Word;
+typedef	int32_t  Elf32_Sword;
+typedef uint32_t Elf64_Word;
+typedef	int32_t  Elf64_Sword;
+
+/* Types for signed and unsigned 64-bit quantities.  */
+typedef uint64_t Elf32_Xword;
+typedef	int64_t  Elf32_Sxword;
+typedef uint64_t Elf64_Xword;
+typedef	int64_t  Elf64_Sxword;
+
+/* Type of addresses.  */
+typedef uint32_t Elf32_Addr;
+typedef uint64_t Elf64_Addr;
+
+/* Type of file offsets.  */
+typedef uint32_t Elf32_Off;
+typedef uint64_t Elf64_Off;
+
+/* Type for section indices, which are 16-bit quantities.  */
+typedef uint16_t Elf32_Section;
+typedef uint16_t Elf64_Section;
+
+/* Type of symbol indices.  */
+typedef uint32_t Elf32_Symndx;
+typedef uint64_t Elf64_Symndx;
+
+
+/* The ELF file header.  This appears at the start of every ELF file.  */
+
+#define EI_NIDENT (16)
+
+typedef struct
+{
+  unsigned char	e_ident[EI_NIDENT];	/* Magic number and other info */
+  Elf32_Half	e_type;			/* Object file type */
+  Elf32_Half	e_machine;		/* Architecture */
+  Elf32_Word	e_version;		/* Object file version */
+  Elf32_Addr	e_entry;		/* Entry point virtual address */
+  Elf32_Off	e_phoff;		/* Program header table file offset */
+  Elf32_Off	e_shoff;		/* Section header table file offset */
+  Elf32_Word	e_flags;		/* Processor-specific flags */
+  Elf32_Half	e_ehsize;		/* ELF header size in bytes */
+  Elf32_Half	e_phentsize;		/* Program header table entry size */
+  Elf32_Half	e_phnum;		/* Program header table entry count */
+  Elf32_Half	e_shentsize;		/* Section header table entry size */
+  Elf32_Half	e_shnum;		/* Section header table entry count */
+  Elf32_Half	e_shstrndx;		/* Section header string table index */
+} Elf32_Ehdr;
+
+typedef struct
+{
+  unsigned char	e_ident[EI_NIDENT];	/* Magic number and other info */
+  Elf64_Half	e_type;			/* Object file type */
+  Elf64_Half	e_machine;		/* Architecture */
+  Elf64_Word	e_version;		/* Object file version */
+  Elf64_Addr	e_entry;		/* Entry point virtual address */
+  Elf64_Off	e_phoff;		/* Program header table file offset */
+  Elf64_Off	e_shoff;		/* Section header table file offset */
+  Elf64_Word	e_flags;		/* Processor-specific flags */
+  Elf64_Half	e_ehsize;		/* ELF header size in bytes */
+  Elf64_Half	e_phentsize;		/* Program header table entry size */
+  Elf64_Half	e_phnum;		/* Program header table entry count */
+  Elf64_Half	e_shentsize;		/* Section header table entry size */
+  Elf64_Half	e_shnum;		/* Section header table entry count */
+  Elf64_Half	e_shstrndx;		/* Section header string table index */
+} Elf64_Ehdr;
+
+/* Fields in the e_ident array.  The EI_* macros are indices into the
+   array.  The macros under each EI_* macro are the values the byte
+   may have.  */
+
+#define EI_MAG0		0		/* File identification byte 0 index */
+#define ELFMAG0		0x7f		/* Magic number byte 0 */
+
+#define EI_MAG1		1		/* File identification byte 1 index */
+#define ELFMAG1		'E'		/* Magic number byte 1 */
+
+#define EI_MAG2		2		/* File identification byte 2 index */
+#define ELFMAG2		'L'		/* Magic number byte 2 */
+
+#define EI_MAG3		3		/* File identification byte 3 index */
+#define ELFMAG3		'F'		/* Magic number byte 3 */
+
+/* Conglomeration of the identification bytes, for easy testing as a word.  */
+#define	ELFMAG		"\177ELF"
+#define	SELFMAG		4
+
+#define EI_CLASS	4		/* File class byte index */
+#define ELFCLASSNONE	0		/* Invalid class */
+#define ELFCLASS32	1		/* 32-bit objects */
+#define ELFCLASS64	2		/* 64-bit objects */
+#define ELFCLASSNUM	3
+
+#define EI_DATA		5		/* Data encoding byte index */
+#define ELFDATANONE	0		/* Invalid data encoding */
+#define ELFDATA2LSB	1		/* 2's complement, little endian */
+#define ELFDATA2MSB	2		/* 2's complement, big endian */
+#define ELFDATANUM	3
+
+#define EI_VERSION	6		/* File version byte index */
+					/* Value must be EV_CURRENT */
+
+#define EI_OSABI	7		/* OS ABI identification */
+#define ELFOSABI_SYSV		0	/* UNIX System V ABI */
+#define ELFOSABI_HPUX		1	/* HP-UX */
+#define ELFOSABI_ARM		97	/* ARM */
+#define ELFOSABI_STANDALONE	255	/* Standalone (embedded) application */
+
+#define EI_ABIVERSION	8		/* ABI version */
+
+#define EI_PAD		9		/* Byte index of padding bytes */
+
+/* Legal values for e_type (object file type).  */
+
+#define ET_NONE		0		/* No file type */
+#define ET_REL		1		/* Relocatable file */
+#define ET_EXEC		2		/* Executable file */
+#define ET_DYN		3		/* Shared object file */
+#define ET_CORE		4		/* Core file */
+#define	ET_NUM		5		/* Number of defined types */
+#define ET_LOPROC	0xff00		/* Processor-specific */
+#define ET_HIPROC	0xffff		/* Processor-specific */
+
+/* Legal values for e_machine (architecture).  */
+
+#define EM_NONE		 0		/* No machine */
+#define EM_M32		 1		/* AT&T WE 32100 */
+#define EM_SPARC	 2		/* SUN SPARC */
+#define EM_386		 3		/* Intel 80386 */
+#define EM_68K		 4		/* Motorola m68k family */
+#define EM_88K		 5		/* Motorola m88k family */
+#define EM_486		 6		/* Intel 80486 */
+#define EM_860		 7		/* Intel 80860 */
+#define EM_MIPS		 8		/* MIPS R3000 big-endian */
+#define EM_S370		 9		/* Amdahl */
+#define EM_MIPS_RS4_BE	10		/* MIPS R4000 big-endian */
+#define EM_RS6000	11		/* RS6000 */
+
+#define EM_PARISC	15		/* HPPA */
+#define EM_nCUBE	16		/* nCUBE */
+#define EM_VPP500	17		/* Fujitsu VPP500 */
+#define EM_SPARC32PLUS	18		/* Sun's "v8plus" */
+#define EM_960		19		/* Intel 80960 */
+#define EM_PPC		20		/* PowerPC */
+
+#define EM_V800		36		/* NEC V800 series */
+#define EM_FR20		37		/* Fujitsu FR20 */
+#define EM_RH32		38		/* TRW RH32 */
+#define EM_MMA		39		/* Fujitsu MMA */
+#define EM_ARM		40		/* ARM */
+#define EM_FAKE_ALPHA	41		/* Digital Alpha */
+#define EM_SH		42		/* Hitachi SH */
+#define EM_SPARCV9	43		/* SPARC v9 64-bit */
+#define EM_TRICORE	44		/* Siemens Tricore */
+#define EM_ARC		45		/* Argonaut RISC Core */
+#define EM_H8_300	46		/* Hitachi H8/300 */
+#define EM_H8_300H	47		/* Hitachi H8/300H */
+#define EM_H8S		48		/* Hitachi H8S */
+#define EM_H8_500	49		/* Hitachi H8/500 */
+#define EM_IA_64	50		/* Intel Merced */
+#define EM_MIPS_X	51		/* Stanford MIPS-X */
+#define EM_COLDFIRE	52		/* Motorola Coldfire */
+#define EM_68HC12	53		/* Motorola M68HC12 */
+#define EM_NUM		54
+
+/* If it is necessary to assign new unofficial EM_* values, please
+   pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the
+   chances of collision with official or non-GNU unofficial values.  */
+
+#define EM_ALPHA	0x9026
+
+/* Legal values for e_version (version).  */
+
+#define EV_NONE		0		/* Invalid ELF version */
+#define EV_CURRENT	1		/* Current version */
+#define EV_NUM		2
+
+
+/* Program segment header.  */
+
+typedef struct
+{
+  Elf32_Word	p_type;			/* Segment type */
+  Elf32_Off	p_offset;		/* Segment file offset */
+  Elf32_Addr	p_vaddr;		/* Segment virtual address */
+  Elf32_Addr	p_paddr;		/* Segment physical address */
+  Elf32_Word	p_filesz;		/* Segment size in file */
+  Elf32_Word	p_memsz;		/* Segment size in memory */
+  Elf32_Word	p_flags;		/* Segment flags */
+  Elf32_Word	p_align;		/* Segment alignment */
+} Elf32_Phdr;
+
+typedef struct
+{
+  Elf64_Word	p_type;			/* Segment type */
+  Elf64_Word	p_flags;		/* Segment flags */
+  Elf64_Off	p_offset;		/* Segment file offset */
+  Elf64_Addr	p_vaddr;		/* Segment virtual address */
+  Elf64_Addr	p_paddr;		/* Segment physical address */
+  Elf64_Xword	p_filesz;		/* Segment size in file */
+  Elf64_Xword	p_memsz;		/* Segment size in memory */
+  Elf64_Xword	p_align;		/* Segment alignment */
+} Elf64_Phdr;
+
+/* Legal values for p_type (segment type).  */
+
+#define	PT_NULL		0		/* Program header table entry unused */
+#define PT_LOAD		1		/* Loadable program segment */
+#define PT_DYNAMIC	2		/* Dynamic linking information */
+#define PT_INTERP	3		/* Program interpreter */
+#define PT_NOTE		4		/* Auxiliary information */
+#define PT_SHLIB	5		/* Reserved */
+#define PT_PHDR		6		/* Entry for header table itself */
+#define	PT_NUM		7		/* Number of defined types.  */
+#define PT_LOOS		0x60000000	/* Start of OS-specific */
+#define PT_HIOS		0x6fffffff	/* End of OS-specific */
+#define PT_LOPROC	0x70000000	/* Start of processor-specific */
+#define PT_HIPROC	0x7fffffff	/* End of processor-specific */
+
+/* Legal values for p_flags (segment flags).  */
+
+#define PF_X		(1 << 0)	/* Segment is executable */
+#define PF_W		(1 << 1)	/* Segment is writable */
+#define PF_R		(1 << 2)	/* Segment is readable */
+#define PF_MASKPROC	0xf0000000	/* Processor-specific */
+
+
+/* Note section contents.  Each entry in the note section begins with
+   a header of a fixed form.  */
+
+typedef struct
+{
+  Elf32_Word n_namesz;			/* Length of the note's name.  */
+  Elf32_Word n_descsz;			/* Length of the note's descriptor.  */
+  Elf32_Word n_type;			/* Type of the note.  */
+} Elf32_Nhdr;
+
+typedef struct
+{
+  Elf64_Word n_namesz;			/* Length of the note's name.  */
+  Elf64_Word n_descsz;			/* Length of the note's descriptor.  */
+  Elf64_Word n_type;			/* Type of the note.  */
+} Elf64_Nhdr;
+
+/* Known names of notes.  */
+
+/* Solaris entries in the note section have this name.  */
+#define ELF_NOTE_SOLARIS	"SUNW Solaris"
+
+/* Note entries for GNU systems have this name.  */
+#define ELF_NOTE_GNU		"GNU"
+
+
+/* Defined types of notes for Solaris.  */
+
+/* Value of descriptor (one word) is desired pagesize for the binary.  */
+#define ELF_NOTE_PAGESIZE_HINT	1
+
+
+/* Defined note types for GNU systems.  */
+
+/* ABI information.  The descriptor consists of words:
+   word 0: OS descriptor
+   word 1: major version of the ABI
+   word 2: minor version of the ABI
+   word 3: subminor version of the ABI
+*/
+#define ELF_NOTE_ABI		1
+
+/* Known OSes.  These value can appear in word 0 of an ELF_NOTE_ABI
+   note section entry.  */
+#define ELF_NOTE_OS_LINUX	0
+#define ELF_NOTE_OS_GNU		1
+#define ELF_NOTE_OS_SOLARIS2	2
+
+
+/* Motorola 68k specific definitions.  */
+
+/* Intel 80386 specific definitions.  */
+
+/* SUN SPARC specific definitions.  */
+
+/* Values for Elf64_Ehdr.e_flags.  */
+
+#define EF_SPARCV9_MM		3
+#define EF_SPARCV9_TSO		0
+#define EF_SPARCV9_PSO		1
+#define EF_SPARCV9_RMO		2
+#define EF_SPARC_EXT_MASK	0xFFFF00
+#define EF_SPARC_SUN_US1	0x000200
+#define EF_SPARC_HAL_R1		0x000400
+
+/* MIPS R3000 specific definitions.  */
+
+/* Legal values for e_flags field of Elf32_Ehdr.  */
+
+#define EF_MIPS_NOREORDER   1		/* A .noreorder directive was used */
+#define EF_MIPS_PIC	    2		/* Contains PIC code */
+#define EF_MIPS_CPIC	    4		/* Uses PIC calling sequence */
+#define EF_MIPS_XGOT	    8
+#define EF_MIPS_64BIT_WHIRL 16
+#define EF_MIPS_ABI2	    32
+#define EF_MIPS_ABI_ON32    64
+#define EF_MIPS_ARCH	    0xf0000000	/* MIPS architecture level */
+
+/* Legal values for MIPS architecture level.  */
+
+#define EF_MIPS_ARCH_1	    0x00000000	/* -mips1 code.  */
+#define EF_MIPS_ARCH_2	    0x10000000	/* -mips2 code.  */
+#define EF_MIPS_ARCH_3	    0x20000000	/* -mips3 code.  */
+#define EF_MIPS_ARCH_4	    0x30000000	/* -mips4 code.  */
+#define EF_MIPS_ARCH_5	    0x40000000	/* -mips5 code.  */
+
+/* Legal values for p_type field of Elf32_Phdr.  */
+
+#define PT_MIPS_REGINFO	0x70000000	/* Register usage information */
+#define PT_MIPS_RTPROC  0x70000001	/* Runtime procedure table. */
+#define PT_MIPS_OPTIONS 0x70000002
+
+/* Special program header types.  */
+
+#define PF_MIPS_LOCAL	0x10000000
+
+
+/* HPPA specific definitions.  */
+
+/* Legal values for e_flags field of Elf32_Ehdr.  */
+
+#define EF_PARISC_TRAPNL	1	/* Trap nil pointer dereference.  */
+#define EF_PARISC_EXT		2	/* Program uses arch. extensions.  */
+#define EF_PARISC_ARCH		0xffff0000 /* Architecture version.  */
+/* Defined values are:
+				0x020b	PA-RISC 1.0 big-endian
+				0x0210	PA-RISC 1.1 big-endian
+				0x028b	PA-RISC 1.0 little-endian
+				0x0290	PA-RISC 1.1 little-endian
+*/
+
+
+/* Alpha specific definitions.  */
+
+/* Legal values for e_flags field of Elf64_Ehdr.  */
+
+#define EF_ALPHA_32BIT		1	/* All addresses must be < 2GB.  */
+#define EF_ALPHA_CANRELAX	2	/* Relocations for relaxing exist.  */
+
+
+/* PowerPC specific declarations */
+
+/* ARM specific declarations */
+
+/* Processor specific flags for the ELF header e_flags field.  */
+#define EF_ARM_RELEXEC     0x01
+#define EF_ARM_HASENTRY    0x02
+#define EF_ARM_INTERWORK   0x04
+#define EF_ARM_APCS_26     0x08
+#define EF_ARM_APCS_FLOAT  0x10
+#define EF_ARM_PIC         0x20
+#define EF_ALIGN8          0x40		/* 8-bit structure alignment is in use */
+#define EF_NEW_ABI         0x80
+#define EF_OLD_ABI         0x100
+
+/* ARM-specific program header flags */
+#define PF_ARM_SB          0x10000000   /* Segment contains the location
+					   addressed by the static base */
+
+#if ELF_CLASS == ELFCLASS32
+typedef Elf32_Ehdr Elf_ehdr;
+typedef Elf32_Phdr Elf_phdr;
+#endif
+
+#if ELF_CLASS == ELFCLASS64
+typedef Elf64_Ehdr Elf_ehdr;
+typedef Elf64_Phdr Elf_phdr;
+#endif
+
+extern int elf_check_arch(Elf_ehdr *ehdr);
+extern void jmp_to_elf_entry(void *entry, unsigned long buffer);
+struct lb_memory;
+extern int elfboot(struct lb_memory *mem);
+
+#define FIRMWARE_TYPE "LinuxBIOS"
+#define BOOTLOADER "elfboot"
+#define BOOTLOADER_VERSION "1.3"
+
+#endif	/* elf.h */
diff --git a/src/include/boot/elf_boot.h b/src/include/boot/elf_boot.h
new file mode 100644
index 0000000..ee6750d
--- /dev/null
+++ b/src/include/boot/elf_boot.h
@@ -0,0 +1,89 @@
+#ifndef ELF_BOOT_H 
+#define ELF_BOOT_H 
+
+#include <stdint.h>
+
+/* This defines the structure of a table of parameters useful for ELF
+ * bootable images.  These parameters are all passed and generated
+ * by the bootloader to the booted image.  For simplicity and
+ * consistency the Elf Note format is reused.
+ *
+ * All of the information must be Position Independent Data.
+ * That is it must be safe to relocate the whole ELF boot parameter
+ * block without changing the meaning or correctnes of the data.
+ * Additionally it must be safe to permute the order of the ELF notes
+ * to any possible permutation without changing the meaning or correctness
+ * of the data.
+ *
+ */
+
+#define ELF_HEAD_SIZE		(8*1024)
+#define ELF_BOOT_MAGIC		0x0E1FB007
+
+typedef uint16_t Elf_Half;
+typedef uint32_t Elf_Word;
+typedef uint64_t Elf_Xword;
+
+typedef struct
+{
+	Elf_Word b_signature; /* "0x0E1FB007" */
+	Elf_Word b_size;
+	Elf_Half b_checksum;
+	Elf_Half b_records;
+} Elf_Bhdr;
+
+typedef struct 
+{
+	Elf_Word n_namesz;		/* Length of the note's name.  */
+	Elf_Word n_descsz;		/* Length of the note's descriptor.  */
+	Elf_Word n_type;		/* Type of the note.  */
+} Elf_Nhdr;
+
+
+/* For standard notes n_namesz must be zero */
+/* All of the following standard note types provide a single null
+ * terminated string in the descriptor.
+ */
+#define EBN_FIRMWARE_TYPE	0x00000001
+/* On platforms that support multiple classes of firmware this field
+ * specifies the class of firmware you are loaded under.
+ */
+#define EBN_BOOTLOADER_NAME	0x00000002
+/* This specifies just the name of the bootloader for easy comparison */
+#define EBN_BOOTLOADER_VERSION	0x00000003
+/* This specifies the version of the bootlader */
+#define EBN_COMMAND_LINE	0x00000004
+/* This specifies a command line that can be set by user interaction,
+ * and is provided as a free form string to the loaded image.
+ */
+
+
+/* Standardized Elf image notes for booting... The name for all of these is ELFBoot */
+
+#define ELF_NOTE_BOOT		"ELFBoot"
+
+#define EIN_PROGRAM_NAME	0x00000001
+/* The program in this ELF file */
+#define EIN_PROGRAM_VERSION	0x00000002
+/* The version of the program in this ELF file */
+#define EIN_PROGRAM_CHECKSUM	0x00000003
+/* ip style checksum of the memory image. */
+
+
+/* Linux image notes for booting... The name for all of these is Linux */
+
+#define LINUX_NOTE_BOOT		"Linux"
+
+#define LIN_COMMAND_LINE	0x00000001
+/* The command line to pass to the loaded kernel. */
+#define LIN_ROOT_DEV		0x00000002
+/* The root dev to pass to the loaded kernel. */
+#define LIN_RAMDISK_FLAGS	0x00000003
+/* Various old ramdisk flags */
+#define LIN_INITRD_START	0x00000004
+/* Start of the ramdisk in bytes */
+#define LIN_INITRD_SIZE		0x00000005
+/* Size of the ramdisk in bytes */
+
+
+#endif /* ELF_BOOT_H */
diff --git a/src/include/boot/linuxbios_tables.h b/src/include/boot/linuxbios_tables.h
new file mode 100644
index 0000000..5f37993
--- /dev/null
+++ b/src/include/boot/linuxbios_tables.h
@@ -0,0 +1,183 @@
+#ifndef LINUXBIOS_TABLES_H
+#define LINUXBIOS_TABLES_H
+
+#include <stdint.h>
+
+/* The linuxbios table information is for conveying information
+ * from the firmware to the loaded OS image.  Primarily this
+ * is expected to be information that cannot be discovered by
+ * other means, such as quering the hardware directly.
+ *
+ * All of the information should be Position Independent Data.  
+ * That is it should be safe to relocated any of the information
+ * without it's meaning/correctnes changing.   For table that
+ * can reasonably be used on multiple architectures the data
+ * size should be fixed.  This should ease the transition between
+ * 32 bit and 64 bit architectures etc.
+ *
+ * The completeness test for the information in this table is:
+ * - Can all of the hardware be detected?
+ * - Are the per motherboard constants available?
+ * - Is there enough to allow a kernel to run that was written before
+ *   a particular motherboard is constructed? (Assuming the kernel
+ *   has drivers for all of the hardware but it does not have
+ *   assumptions on how the hardware is connected together).
+ *
+ * With this test it should be straight forward to determine if a
+ * table entry is required or not.  This should remove much of the
+ * long term compatibility burden as table entries which are
+ * irrelevant or have been replaced by better alternatives may be
+ * dropped.  Of course it is polite and expidite to include extra
+ * table entries and be backwards compatible, but it is not required.
+ */
+
+
+struct lb_header
+{
+	uint8_t  signature[4]; /* LBIO */
+	uint32_t header_bytes;
+	uint32_t header_checksum;
+	uint32_t table_bytes;
+	uint32_t table_checksum;
+	uint32_t table_entries;
+};
+
+/* Every entry in the boot enviroment list will correspond to a boot
+ * info record.  Encoding both type and size.  The type is obviously
+ * so you can tell what it is.  The size allows you to skip that
+ * boot enviroment record if you don't know what it easy.  This allows
+ * forward compatibility with records not yet defined.
+ */
+struct lb_record {
+	uint32_t tag;		/* tag ID */
+	uint32_t size;		/* size of record (in bytes) */
+};
+
+#define LB_TAG_UNUSED	0x0000
+
+#define LB_TAG_MEMORY	0x0001
+
+struct lb_memory_range {
+	uint64_t start;
+	uint64_t size;
+	uint32_t type;
+#define LB_MEM_RAM       1	/* Memory anyone can use */
+#define LB_MEM_RESERVED  2	/* Don't use this memory region */
+#define LB_MEM_TABLE     16	/* Ram configuration tables are kept in */
+	
+};
+
+struct lb_memory {
+	uint32_t tag;
+	uint32_t size;
+	struct lb_memory_range map[0];
+};
+
+#define LB_TAG_HWRPB	0x0002
+struct lb_hwrpb {
+	uint32_t tag;
+	uint32_t size;
+	uint64_t hwrpb;
+};
+
+#define LB_TAG_MAINBOARD	0x0003
+struct lb_mainboard {
+	uint32_t tag;
+	uint32_t size;
+	uint8_t  vendor_idx;
+	uint8_t  part_number_idx;
+	uint8_t  strings[0];
+};
+
+#define LB_TAG_VERSION		0x0004
+#define LB_TAG_EXTRA_VERSION	0x0005
+#define LB_TAG_BUILD		0x0006
+#define LB_TAG_COMPILE_TIME	0x0007
+#define LB_TAG_COMPILE_BY	0x0008
+#define LB_TAG_COMPILE_HOST	0x0009
+#define LB_TAG_COMPILE_DOMAIN	0x000a
+#define LB_TAG_COMPILER		0x000b
+#define LB_TAG_LINKER		0x000c
+#define LB_TAG_ASSEMBLER	0x000d
+struct lb_string {
+	uint32_t tag;
+	uint32_t size;
+	uint8_t  string[0];
+};
+
+/* The following structures are for the cmos definitions table */
+#define LB_TAG_CMOS_OPTION_TABLE 200
+/* cmos header record */
+struct cmos_option_table {
+	uint32_t tag;               /* CMOS definitions table type */
+	uint32_t size;               /* size of the entire table */
+	uint32_t header_length;      /* length of header */
+};
+
+/* cmos entry record
+        This record is variable length.  The name field may be
+        shorter than CMOS_MAX_NAME_LENGTH. The entry may start
+        anywhere in the byte, but can not span bytes unless it
+        starts at the beginning of the byte and the length is
+        fills complete bytes.
+*/
+#define LB_TAG_OPTION 201
+struct cmos_entries {
+	uint32_t tag;                /* entry type */
+	uint32_t size;               /* length of this record */
+	uint32_t bit;                /* starting bit from start of image */
+	uint32_t length;             /* length of field in bits */
+	uint32_t config;             /* e=enumeration, h=hex, r=reserved */
+	uint32_t config_id;          /* a number linking to an enumeration record */
+#define CMOS_MAX_NAME_LENGTH 32
+	uint8_t name[CMOS_MAX_NAME_LENGTH]; /* name of entry in ascii, 
+					       variable length int aligned */
+};
+
+
+/* cmos enumerations record
+        This record is variable length.  The text field may be
+        shorter than CMOS_MAX_TEXT_LENGTH.
+*/
+#define LB_TAG_OPTION_ENUM 202
+struct cmos_enums {
+	uint32_t tag;		     /* enumeration type */
+	uint32_t size; 		     /* length of this record */
+	uint32_t config_id;          /* a number identifying the config id */
+	uint32_t value;              /* the value associated with the text */
+#define CMOS_MAX_TEXT_LENGTH 32
+	uint8_t text[CMOS_MAX_TEXT_LENGTH]; /* enum description in ascii, 
+						variable length int aligned */
+};
+
+/* cmos defaults record
+        This record contains default settings for the cmos ram.
+*/
+#define LB_TAG_OPTION_DEFAULTS 203
+struct cmos_defaults {
+	uint32_t tag;                /* default type */
+	uint32_t size;               /* length of this record */
+	uint32_t name_length;        /* length of the following name field */
+	uint8_t name[CMOS_MAX_NAME_LENGTH]; /* name identifying the default */
+#define CMOS_IMAGE_BUFFER_SIZE 128
+	uint8_t default_set[CMOS_IMAGE_BUFFER_SIZE]; /* default settings */
+};
+
+#define LB_TAG_OPTION_CHECKSUM 204
+struct	cmos_checksum {
+	uint32_t tag;
+	uint32_t size;
+	/* In practice everything is byte aligned, but things are measured
+	 * in bits to be consistent.
+	 */
+	uint32_t range_start;	/* First bit that is checksummed (byte aligned) */
+	uint32_t range_end;	/* Last bit that is checksummed (byte aligned) */
+	uint32_t location;	/* First bit of the checksum (byte aligned) */
+	uint32_t type;		/* Checksum algorithm that is used */
+#define CHECKSUM_NONE	0
+#define CHECKSUM_PCBIOS	1
+};
+
+
+
+#endif /* LINUXBIOS_TABLES_H */
diff --git a/src/include/boot/tables.h b/src/include/boot/tables.h
new file mode 100644
index 0000000..618c32e
--- /dev/null
+++ b/src/include/boot/tables.h
@@ -0,0 +1,9 @@
+#ifndef BOOT_TABLES_H
+#define BOOT_TABLES_H
+
+#include <mem.h>
+#include <boot/linuxbios_tables.h>
+
+struct lb_memory *write_tables(struct mem_range *mem, unsigned long *processor_map);
+
+#endif /* BOOT_TABLES_H */
diff --git a/src/include/console/console.h b/src/include/console/console.h
new file mode 100644
index 0000000..57ba9da
--- /dev/null
+++ b/src/include/console/console.h
@@ -0,0 +1,76 @@
+#ifndef CONSOLE_CONSOLE_H_
+#define CONSOLE_CONSOLE_H_
+
+#include <stdint.h>
+#include <console/loglevel.h>
+
+void console_init(void);
+void console_tx_byte(unsigned char byte);
+void console_tx_flush(void);
+void post_code(uint8_t value);
+void die(char *msg);
+
+struct console_driver {
+	void (*init)(void);
+	void (*tx_byte)(unsigned char byte);
+	void (*tx_flush)(void);
+};
+
+#define __console	__attribute__((unused, __section__ (".rodata.console_drivers")))
+
+/* Defined by the linker... */
+extern struct console_driver console_drivers[];
+extern struct console_driver econsole_drivers[];
+
+extern int console_loglevel;
+int do_printk(int msg_level, const char *fmt, ...);
+
+#define printk_emerg(fmt, arg...)   do_printk(BIOS_EMERG   ,fmt, ##arg)
+#define printk_alert(fmt, arg...)   do_printk(BIOS_ALERT   ,fmt, ##arg)
+#define printk_crit(fmt, arg...)    do_printk(BIOS_CRIT    ,fmt, ##arg)
+#define printk_err(fmt, arg...)     do_printk(BIOS_ERR     ,fmt, ##arg)
+#define printk_warning(fmt, arg...) do_printk(BIOS_WARNING ,fmt, ##arg)
+#define printk_notice(fmt, arg...)  do_printk(BIOS_NOTICE  ,fmt, ##arg)
+#define printk_info(fmt, arg...)    do_printk(BIOS_INFO    ,fmt, ##arg)
+#define printk_debug(fmt, arg...)   do_printk(BIOS_DEBUG   ,fmt, ##arg)
+#define printk_spew(fmt, arg...)    do_printk(BIOS_SPEW    ,fmt, ##arg)
+
+#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_EMERG
+#undef  printk_emerg
+#define printk_emerg(fmt, arg...)   do {} while(0)
+#endif
+#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_ALERT
+#undef  printk_alert
+#define printk_alart(fmt, arg...)   do {} while(0)
+#endif
+#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_CRIT
+#undef  printk_crit
+#define printk_crit(fmt, arg...)    do {} while(0)
+#endif
+#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_ERR
+#undef  printk_err
+#define printk_err(fmt, arg...)     do {} while(0)
+#endif
+#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_WARNING
+#undef  printk_warning
+#define printk_warning(fmt, arg...) do {} while(0)
+#endif
+#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_NOTICE
+#undef  printk_notice
+#define printk_notice(fmt, arg...)  do {} while(0)
+#endif
+#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_INFO
+#undef  printk_info
+#define printk_info(fmt, arg...)    do {} while(0)
+#endif
+#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_DEBUG
+#undef  printk_debug
+#define printk_debug(fmt, arg...)   do {} while(0)
+#endif
+#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_SPEW
+#undef  printk_spew
+#define printk_spew(fmt, arg...)    do {} while(0)
+#endif
+
+
+#endif /* CONSOLE_CONSOLE_H_ */
diff --git a/src/include/console/loglevel.h b/src/include/console/loglevel.h
new file mode 100644
index 0000000..a191b30
--- /dev/null
+++ b/src/include/console/loglevel.h
@@ -0,0 +1,30 @@
+#ifndef LOGLEVEL_H
+#define LOGLEVEL_H
+
+/* Safe for inclusion in assembly */
+
+#ifndef MAXIMUM_CONSOLE_LOGLEVEL
+#define MAXIMUM_CONSOLE_LOGLEVEL 8
+#endif
+
+#ifndef DEFAULT_CONSOLE_LOGLEVEL
+#define DEFAULT_CONSOLE_LOGLEVEL 8 /* anything MORE serious than BIOS_SPEW */
+#endif
+
+#if (DEFAULT_CONSOLE_LOGLEVEL <= MAXIMUM_CONSOLE_LOGLEVEL)
+#define ASM_CONSOLE_LOGLEVEL DEFAULT_CONSOLE_LOGLEVEL
+#else
+#define ASM_CONSOLE_LOGLEVEL MAXIMUM_CONSOLE_LOGLEVEL
+#endif
+
+#define BIOS_EMERG      0   /* system is unusable                   */
+#define BIOS_ALERT      1   /* action must be taken immediately     */
+#define BIOS_CRIT       2   /* critical conditions                  */
+#define BIOS_ERR        3   /* error conditions                     */
+#define BIOS_WARNING    4   /* warning conditions                   */
+#define BIOS_NOTICE     5   /* normal but significant condition     */
+#define BIOS_INFO       6   /* informational                        */
+#define BIOS_DEBUG      7   /* debug-level messages                 */
+#define BIOS_SPEW       8   /* Way too many details                 */
+
+#endif /* LOGLEVEL_H */
diff --git a/src/include/cpu/cpu.h b/src/include/cpu/cpu.h
new file mode 100644
index 0000000..208dab0
--- /dev/null
+++ b/src/include/cpu/cpu.h
@@ -0,0 +1,11 @@
+#ifndef CPU_CPU_H
+#define CPU_CPU_H
+
+#include <mem.h>
+
+unsigned long cpu_initialize(struct mem_range *mem);
+#define CPU_ENABLED		1	/* Processor is available */
+#define CPU_BOOTPROCESSOR	2	/* Processor is the BP */
+
+
+#endif /* CPU_CPU_H */
diff --git a/src/include/cpu/cpufixup.h b/src/include/cpu/cpufixup.h
new file mode 100644
index 0000000..b23afa5
--- /dev/null
+++ b/src/include/cpu/cpufixup.h
@@ -0,0 +1,24 @@
+#ifndef CPU_CPUFIXUP_H
+#define CPU_CPUFIXUP_H
+
+struct mem_range;
+
+#include <cpu/k8/cpufixup.h>
+#include <cpu/k7/cpufixup.h>
+#include <cpu/p6/cpufixup.h>
+
+#if CPU_FIXUP == 1 
+#  if defined(k8)
+#    define cpufixup(mem) k8_cpufixup(mem)
+#  elif defined(k7)
+#    define cpufixup(mem) k7_cpufixup(mem)
+#  elif defined(i786)
+#    define cpufixup(mem) i786_cpufixup(mem)
+#  elif defined(i686)
+#    define cpufixup(mem) p6_cpufixup(mem)
+#  endif
+#else
+#  define cpufixup(mem) do {} while(0)
+#endif
+
+#endif /* CPU_CPUFIXUP_H */
diff --git a/src/include/cpu/k7/cpufixup.h b/src/include/cpu/k7/cpufixup.h
new file mode 100644
index 0000000..0e3db3d
--- /dev/null
+++ b/src/include/cpu/k7/cpufixup.h
@@ -0,0 +1,6 @@
+#ifndef CPU_K7_CPUFIXUP_H
+#define CPU_K7_CPUFIXUP_H
+
+void k7_cpufixup(struct mem_range *mem);
+
+#endif /* CPU_K7_CPUFIXUP_H */
diff --git a/src/include/cpu/k7/mtrr.h b/src/include/cpu/k7/mtrr.h
new file mode 100644
index 0000000..ea376da
--- /dev/null
+++ b/src/include/cpu/k7/mtrr.h
@@ -0,0 +1,42 @@
+#ifndef CPU_K7_MTRR_H
+#define CPU_K7_MTRR_H
+
+#include <cpu/p6/mtrr.h>
+
+#define IORR_FIRST 0xC0010016
+#define IORR_LAST  0xC0010019
+#define SYSCFG     0xC0010010
+
+#define MTRR_READ_MEM			(1 << 4)
+#define MTRR_WRITE_MEM			(1 << 3)
+
+#define SYSCFG_MSR			0xC0010010
+#define SYSCFG_MSR_EvictEn		(1 << 22)
+#define SYSCFG_MSR_TOM2En		(1 << 21)
+#define SYSCFG_MSR_MtrrVarDramEn	(1 << 20)
+#define SYSCFG_MSR_MtrrFixDramModEn	(1 << 19)
+#define SYSCFG_MSR_MtrrFixDramEn	(1 << 18)
+#define SYSCFG_MSR_UcLockEn		(1 << 17)
+#define SYSCFG_MSR_ChxToDirtyDis	(1 << 16)
+#define SYSCFG_MSR_SysEccEn		(1 << 15)
+#define SYSCFG_MSR_RdBlkL2WayEn		(1 << 14)
+#define SYSCFG_MSR_SysFillValIsD1	(1 << 13)
+#define SYSCFG_MSR_IcInclusive		(1 << 12)
+#define SYSCFG_MSR_ClVicBlkEn		(1 << 11)
+#define SYSCFG_MSR_SetDirtyEnO		(1 << 10)
+#define SYSCFG_MSR_SetDirtyEnS		(1 <<  9)
+#define SYSCFG_MSR_SetDirtyEnE		(1 <<  8)
+#define SYSCFG_MSR_SysVicLimitMask	((1 << 8) - (1 << 5))
+#define SYSCFG_MSR_SysAckLimitMask	((1 << 5) - (1 << 0))
+
+
+
+#define IORR0_BASE			0xC0010016
+#define IORR0_MASK			0xC0010017
+#define IORR1_BASE			0xC0010018
+#define IORR1_MASK			0xC0010019
+#define TOP_MEM				0xC001001A
+#define TOP_MEM2			0xC001001D
+#define HWCR_MSR			0xC0010015
+
+#endif /* CPU_K7_MTRR_H */
diff --git a/src/include/cpu/k8/cpufixup.h b/src/include/cpu/k8/cpufixup.h
new file mode 100644
index 0000000..9500ec2
--- /dev/null
+++ b/src/include/cpu/k8/cpufixup.h
@@ -0,0 +1,6 @@
+#ifndef CPU_K8_CPUFIXUP_H
+#define CPU_K8_CPUFIXUP_H
+
+void k8_cpufixup(struct mem_range *mem);
+
+#endif /* CPU_K8_CPUFIXUP_H */
diff --git a/src/include/cpu/k8/mtrr.h b/src/include/cpu/k8/mtrr.h
new file mode 100644
index 0000000..ce9e6d4
--- /dev/null
+++ b/src/include/cpu/k8/mtrr.h
@@ -0,0 +1,45 @@
+#ifndef CPU_K8_MTRR_H
+#define CPU_K8_MTRR_H
+
+#include <cpu/k7/mtrr.h>
+
+#if 0
+#define IORR_FIRST 0xC0010016
+#define IORR_LAST  0xC0010019
+#define SYSCFG     0xC0010010
+
+#define MTRR_READ_MEM			(1 << 4)
+#define MTRR_WRITE_MEM			(1 << 3)
+
+#define SYSCFG_MSR			0xC0010010
+#define SYSCFG_MSR_EvictEn		(1 << 22)
+#define SYSCFG_MSR_TOM2En		(1 << 21)
+#define SYSCFG_MSR_MtrrVarDramEn	(1 << 20)
+#define SYSCFG_MSR_MtrrFixDramModEn	(1 << 19)
+#define SYSCFG_MSR_MtrrFixDramEn	(1 << 18)
+#define SYSCFG_MSR_UcLockEn		(1 << 17)
+#define SYSCFG_MSR_ChxToDirtyDis	(1 << 16)
+#define SYSCFG_MSR_SysEccEn		(1 << 15)
+#define SYSCFG_MSR_RdBlkL2WayEn		(1 << 14)
+#define SYSCFG_MSR_SysFillValIsD1	(1 << 13)
+#define SYSCFG_MSR_IcInclusive		(1 << 12)
+#define SYSCFG_MSR_ClVicBlkEn		(1 << 11)
+#define SYSCFG_MSR_SetDirtyEnO		(1 << 10)
+#define SYSCFG_MSR_SetDirtyEnS		(1 <<  9)
+#define SYSCFG_MSR_SetDirtyEnE		(1 <<  8)
+#define SYSCFG_MSR_SysVicLimitMask	((1 << 8) - (1 << 5))
+#define SYSCFG_MSR_SysAckLimitMask	((1 << 5) - (1 << 0))
+
+
+
+#define IORR0_BASE			0xC0010016
+#define IORR0_MASK			0xC0010017
+#define IORR1_BASE			0xC0010018
+#define IORR1_MASK			0xC0010019
+#define TOP_MEM				0xC001001A
+#define TOP_MEM2			0xC001001D
+#define HWCR_MSR			0xC0010015
+
+#endif
+
+#endif /* CPU_K8_MTRR_H */
diff --git a/src/include/cpu/p5/cpuid.h b/src/include/cpu/p5/cpuid.h
new file mode 100644
index 0000000..b8ffc88
--- /dev/null
+++ b/src/include/cpu/p5/cpuid.h
@@ -0,0 +1,25 @@
+#ifndef CPU_P5_CPUID_H
+#define CPU_P5_CPUID_H
+
+int mtrr_check(void);
+void display_cpuid(void);
+
+/*
+ *      Generic CPUID function. copied from Linux kernel headers
+ */
+
+static inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx)
+{
+        __asm__("pushl %%ebx\n\t"
+		"cpuid\n\t"
+		"movl	%%ebx, %%esi\n\t"
+		"popl	%%ebx\n\t"
+                : "=a" (*eax),
+                  "=S" (*ebx),
+                  "=c" (*ecx),
+                  "=d" (*edx)
+                : "a" (op)
+                : "cc");
+}
+
+#endif /* CPU_P5_CPUID_H */
diff --git a/src/include/cpu/p6/apic.h b/src/include/cpu/p6/apic.h
new file mode 100644
index 0000000..b91cdb2
--- /dev/null
+++ b/src/include/cpu/p6/apic.h
@@ -0,0 +1,175 @@
+#ifndef APIC_H
+#define APIC_H
+
+#define APIC_BASE_MSR 0x1B
+#define APIC_BASE_MSR_BOOTSTRAP_PROCESSOR (1 << 8)
+#define APIC_BASE_MSR_ENABLE (1 << 11)
+#define APIC_BASE_MSR_ADDR_MASK 0xFFFFF000
+
+#define APIC_DEFAULT_BASE 0xfee00000
+
+#define APIC_ID		0x020
+#define APIC_LVR	0x030
+#define APIC_ARBID	0x090
+#define	APIC_RRR	0x0C0
+#define APIC_SVR	0x0f0
+#define APIC_SPIV	0x0f0
+#define 	APIC_SPIV_ENABLE  0x100
+#define APIC_ESR	0x280
+#define		APIC_ESR_SEND_CS	0x00001
+#define		APIC_ESR_RECV_CS	0x00002
+#define		APIC_ESR_SEND_ACC	0x00004
+#define		APIC_ESR_RECV_ACC	0x00008
+#define		APIC_ESR_SENDILL	0x00020
+#define		APIC_ESR_RECVILL	0x00040
+#define		APIC_ESR_ILLREGA	0x00080
+#define APIC_ICR 	0x300
+#define		APIC_DEST_SELF		0x40000
+#define		APIC_DEST_ALLINC	0x80000
+#define		APIC_DEST_ALLBUT	0xC0000
+#define		APIC_ICR_RR_MASK	0x30000
+#define		APIC_ICR_RR_INVALID	0x00000
+#define		APIC_ICR_RR_INPROG	0x10000
+#define		APIC_ICR_RR_VALID	0x20000
+#define		APIC_INT_LEVELTRIG	0x08000
+#define		APIC_INT_ASSERT		0x04000
+#define		APIC_ICR_BUSY		0x01000
+#define		APIC_DEST_LOGICAL	0x00800
+#define		APIC_DM_FIXED		0x00000
+#define		APIC_DM_LOWEST		0x00100
+#define		APIC_DM_SMI		0x00200
+#define		APIC_DM_REMRD		0x00300
+#define		APIC_DM_NMI		0x00400
+#define		APIC_DM_INIT		0x00500
+#define		APIC_DM_STARTUP		0x00600
+#define		APIC_DM_EXTINT		0x00700
+#define		APIC_VECTOR_MASK	0x000FF
+#define APIC_ICR2	0x310
+#define		GET_APIC_DEST_FIELD(x)	(((x)>>24)&0xFF)
+#define		SET_APIC_DEST_FIELD(x)	((x)<<24)
+#define APIC_LVTT	0x320
+#define APIC_LVTPC	0x340
+#define APIC_LVT0	0x350
+#define		APIC_LVT_TIMER_BASE_MASK	(0x3<<18)
+#define		GET_APIC_TIMER_BASE(x)		(((x)>>18)&0x3)
+#define		SET_APIC_TIMER_BASE(x)		(((x)<<18))
+#define		APIC_TIMER_BASE_CLKIN		0x0
+#define		APIC_TIMER_BASE_TMBASE		0x1
+#define		APIC_TIMER_BASE_DIV		0x2
+#define		APIC_LVT_TIMER_PERIODIC		(1<<17)
+#define		APIC_LVT_MASKED			(1<<16)
+#define		APIC_LVT_LEVEL_TRIGGER		(1<<15)
+#define		APIC_LVT_REMOTE_IRR		(1<<14)
+#define		APIC_INPUT_POLARITY		(1<<13)
+#define		APIC_SEND_PENDING		(1<<12)
+#define		APIC_LVT_RESERVED_1		(1<<11)
+#define		APIC_DELIVERY_MODE_MASK		(7<<8)
+#define		APIC_DELIVERY_MODE_FIXED	(0<<8)
+#define		APIC_DELIVERY_MODE_NMI		(4<<8)
+#define		APIC_DELIVERY_MODE_EXTINT	(7<<8)
+#define		GET_APIC_DELIVERY_MODE(x)	(((x)>>8)&0x7)
+#define		SET_APIC_DELIVERY_MODE(x,y)	(((x)&~0x700)|((y)<<8))
+#define			APIC_MODE_FIXED		0x0
+#define			APIC_MODE_NMI		0x4
+#define			APIC_MODE_EXINT		0x7
+#define APIC_LVT1	0x360
+#define APIC_LVTERR	0x370
+
+
+#if !defined(ASSEMBLY)
+
+#include <console/console.h>
+
+
+#define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
+
+struct __xchg_dummy { unsigned long a[100]; };
+#define __xg(x) ((struct __xchg_dummy *)(x))
+
+/*
+ * Note: no "lock" prefix even on SMP: xchg always implies lock anyway
+ * Note 2: xchg has side effect, so that attribute volatile is necessary,
+ *	  but generally the primitive is invalid, *ptr is output argument. --ANK
+ */
+static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
+{
+	switch (size) {
+		case 1:
+			__asm__ __volatile__("xchgb %b0,%1"
+				:"=q" (x)
+				:"m" (*__xg(ptr)), "0" (x)
+				:"memory");
+			break;
+		case 2:
+			__asm__ __volatile__("xchgw %w0,%1"
+				:"=r" (x)
+				:"m" (*__xg(ptr)), "0" (x)
+				:"memory");
+			break;
+		case 4:
+			__asm__ __volatile__("xchgl %0,%1"
+				:"=r" (x)
+				:"m" (*__xg(ptr)), "0" (x)
+				:"memory");
+			break;
+	}
+	return x;
+}
+
+
+static inline unsigned long apic_read(unsigned long reg)
+{
+	return *((volatile unsigned long *)(APIC_DEFAULT_BASE+reg));
+}
+
+extern inline void apic_write_atomic(unsigned long reg, unsigned long v)
+{
+	xchg((volatile unsigned long *)(APIC_DEFAULT_BASE+reg), v);
+}
+
+static inline void apic_write(unsigned long reg, unsigned long v)
+{
+	*((volatile unsigned long *)(APIC_DEFAULT_BASE+reg)) = v;
+}
+
+static inline void apic_wait_icr_idle(void)
+{
+	do { } while ( apic_read( APIC_ICR ) & APIC_ICR_BUSY );
+}
+
+#ifdef CONFIG_X86_GOOD_APIC
+# define FORCE_READ_AROUND_WRITE 0
+# define apic_read_around(x) apic_read(x)
+# define apic_write_around(x,y) apic_write((x),(y))
+#else
+# define FORCE_READ_AROUND_WRITE 1
+# define apic_read_around(x) apic_read(x)
+# define apic_write_around(x,y) apic_write_atomic((x),(y))
+#endif
+
+static inline int apic_remote_read(int apicid, int reg, unsigned long *pvalue)
+{
+	int timeout;
+	unsigned long status;
+	int result;
+	apic_wait_icr_idle();
+	apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
+	apic_write_around(APIC_ICR, APIC_DM_REMRD | (reg >> 4));
+	timeout = 0;
+	do {
+#if 0
+		udelay(100);
+#endif
+		status = apic_read(APIC_ICR) & APIC_ICR_RR_MASK;
+	} while (status == APIC_ICR_RR_INPROG && timeout++ < 1000);
+
+	result = -1;
+	if (status == APIC_ICR_RR_VALID) {
+		*pvalue = apic_read(APIC_RRR);
+		result = 0;
+	}
+	return result;
+}
+#endif /* ASSEMBLY */
+
+#endif /* APIC_H */
diff --git a/src/include/cpu/p6/cpufixup.h b/src/include/cpu/p6/cpufixup.h
new file mode 100644
index 0000000..9b0f2fa
--- /dev/null
+++ b/src/include/cpu/p6/cpufixup.h
@@ -0,0 +1,6 @@
+#ifndef CPU_P6_CPUFIXUP_H
+#define CPU_P6_CPUFIXUP_H
+
+void p6_cpufixup(struct mem_range *mem);
+
+#endif /* CPU_P6_CPUFIXUP_H */
diff --git a/src/include/cpu/p6/msr.h b/src/include/cpu/p6/msr.h
new file mode 100644
index 0000000..4977b02
--- /dev/null
+++ b/src/include/cpu/p6/msr.h
@@ -0,0 +1,33 @@
+#ifndef CPU_P6_MSR_H
+#define CPU_P6_MSR_H
+
+/*
+ * Access to machine-specific registers (available on 586 and better only)
+ * Note: the rd* operations modify the parameters directly (without using
+ * pointer indirection), this allows gcc to optimize better
+ */
+
+#define rdmsr(msr,val1,val2) \
+       __asm__ __volatile__("rdmsr" \
+			    : "=a" (val1), "=d" (val2) \
+			    : "c" (msr))
+
+#define wrmsr(msr,val1,val2) \
+     __asm__ __volatile__("wrmsr" \
+			  : /* no outputs */ \
+			  : "c" (msr), "a" (val1), "d" (val2))
+
+#define rdtsc(low,high) \
+     __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
+
+#define rdtscl(low) \
+     __asm__ __volatile__ ("rdtsc" : "=a" (low) : : "edx")
+
+#define rdtscll(val) \
+     __asm__ __volatile__ ("rdtsc" : "=A" (val))
+
+#define rdpmc(counter,low,high) \
+     __asm__ __volatile__("rdpmc" \
+			  : "=a" (low), "=d" (high) \
+			  : "c" (counter))
+#endif /* CPU_P6_MSR_H */
diff --git a/src/include/cpu/p6/mtrr.h b/src/include/cpu/p6/mtrr.h
new file mode 100644
index 0000000..16af10b
--- /dev/null
+++ b/src/include/cpu/p6/mtrr.h
@@ -0,0 +1,44 @@
+#ifndef __LINUXBIOS_CPU_P6_MTRR_H
+#define __LINUXBIOS_CPU_P6_MTRR_H
+
+/*  These are the region types  */
+#define MTRR_TYPE_UNCACHABLE 0
+#define MTRR_TYPE_WRCOMB     1
+/*#define MTRR_TYPE_         2*/
+/*#define MTRR_TYPE_         3*/
+#define MTRR_TYPE_WRTHROUGH  4
+#define MTRR_TYPE_WRPROT     5
+#define MTRR_TYPE_WRBACK     6
+#define MTRR_NUM_TYPES       7
+
+#define MTRRcap_MSR     0x0fe
+#define MTRRdefType_MSR 0x2ff
+
+#define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg))
+#define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1)
+
+#define NUM_FIXED_RANGES 88
+#define MTRRfix64K_00000_MSR 0x250
+#define MTRRfix16K_80000_MSR 0x258
+#define MTRRfix16K_A0000_MSR 0x259
+#define MTRRfix4K_C0000_MSR 0x268
+#define MTRRfix4K_C8000_MSR 0x269
+#define MTRRfix4K_D0000_MSR 0x26a
+#define MTRRfix4K_D8000_MSR 0x26b
+#define MTRRfix4K_E0000_MSR 0x26c
+#define MTRRfix4K_E8000_MSR 0x26d
+#define MTRRfix4K_F0000_MSR 0x26e
+#define MTRRfix4K_F8000_MSR 0x26f
+
+
+#if !defined(ASSEMBLY)
+
+void set_var_mtrr(unsigned int reg, unsigned long base, unsigned long size, unsigned char type);
+#if defined(INTEL_PPRO_MTRR) 
+struct mem_range;
+void setup_mtrrs(struct mem_range *mem);
+#endif
+
+#endif /* ASSEMBLY */
+
+#endif /* __LINUXBIOS_CPU_P6_MTRR_H */
diff --git a/src/include/delay.h b/src/include/delay.h
new file mode 100644
index 0000000..bffb719
--- /dev/null
+++ b/src/include/delay.h
@@ -0,0 +1,8 @@
+#ifndef DELAY_H
+#define DELAY_H
+
+void udelay(int usecs);
+void mdelay(int msecs);
+void delay(int secs);
+
+#endif /* DELAY_H */
diff --git a/src/include/ip_checksum.h b/src/include/ip_checksum.h
new file mode 100644
index 0000000..c2cb938
--- /dev/null
+++ b/src/include/ip_checksum.h
@@ -0,0 +1,7 @@
+#ifndef IP_CHECKSUM_H
+#define IP_CHECKSUM_H
+
+unsigned long compute_ip_checksum(void *addr, unsigned long length);
+unsigned long add_ip_checksums(unsigned long offset, unsigned long sum, unsigned long new);
+
+#endif /* IP_CHECKSUM_H */
diff --git a/src/include/mem.h b/src/include/mem.h
new file mode 100644
index 0000000..e8f633b
--- /dev/null
+++ b/src/include/mem.h
@@ -0,0 +1,13 @@
+#ifndef MEM_H
+#define MEM_H
+
+struct mem_range {
+	unsigned long basek;
+	unsigned long sizek;
+};
+
+/* mem_range arrays are non-overlapping, in ascending order and null terminated */
+
+struct mem_range *sizeram(void);
+
+#endif /* MEM_H */
diff --git a/src/include/part/fallback_boot.h b/src/include/part/fallback_boot.h
new file mode 100644
index 0000000..1eb2f7b
--- /dev/null
+++ b/src/include/part/fallback_boot.h
@@ -0,0 +1,16 @@
+#ifndef PART_FALLBACK_BOOT_H
+#define PART_FALLBACK_BOOT_H
+
+#ifndef ASSEMBLY
+
+#if HAVE_FALLBACK_BOOT
+void boot_successful(void);
+#else
+#define boot_successful()
+#endif
+
+#endif /* ASSEMBLY */
+
+#define RTC_BOOT_BYTE	48
+
+#endif /* PART_FALLBACK_BOOT_H */
diff --git a/src/include/part/sizeram.h b/src/include/part/sizeram.h
new file mode 100644
index 0000000..50a44f3
--- /dev/null
+++ b/src/include/part/sizeram.h
@@ -0,0 +1,7 @@
+#ifndef PART_SIZERAM_H
+#define PART_SIZERAM_H
+
+struct mem_rang;
+struct mem_range *sizeram(void);
+
+#endif /* PART_SIZERAM_H */
diff --git a/src/include/pc80/mc146818rtc.h b/src/include/pc80/mc146818rtc.h
new file mode 100644
index 0000000..1daf39a
--- /dev/null
+++ b/src/include/pc80/mc146818rtc.h
@@ -0,0 +1,110 @@
+#ifndef PC80_MC146818RTC_H
+#define PC80_MC146818RTC_H
+
+#ifndef RTC_BASE_PORT
+#define RTC_BASE_PORT 0x70
+#endif
+
+#define RTC_PORT(x)	(RTC_BASE_PORT + (x))
+
+/* On PCs, the checksum is built only over bytes 16..45 */
+#define PC_CKS_RANGE_START	16
+#define PC_CKS_RANGE_END	45
+#define PC_CKS_LOC		46
+
+
+/* Linux bios checksum is built only over bytes 49..125 */
+#define LB_CKS_RANGE_START	49
+#define LB_CKS_RANGE_END	125
+#define LB_CKS_LOC		126
+
+
+/* control registers - Moto names
+ */
+#define RTC_REG_A		10
+#define RTC_REG_B		11
+#define RTC_REG_C		12
+#define RTC_REG_D		13
+
+
+/**********************************************************************
+ * register details
+ **********************************************************************/
+#define RTC_FREQ_SELECT	RTC_REG_A
+
+/* update-in-progress  - set to "1" 244 microsecs before RTC goes off the bus,
+ * reset after update (may take 1.984ms @ 32768Hz RefClock) is complete,
+ * totalling to a max high interval of 2.228 ms.
+ */
+# define RTC_UIP		0x80
+# define RTC_DIV_CTL		0x70
+   /* divider control: refclock values 4.194 / 1.049 MHz / 32.768 kHz */
+#  define RTC_REF_CLCK_4MHZ	0x00
+#  define RTC_REF_CLCK_1MHZ	0x10
+#  define RTC_REF_CLCK_32KHZ	0x20
+   /* 2 values for divider stage reset, others for "testing purposes only" */
+#  define RTC_DIV_RESET1	0x60
+#  define RTC_DIV_RESET2	0x70
+  /* Periodic intr. / Square wave rate select. 0=none, 1=32.8kHz,... 15=2Hz */
+# define RTC_RATE_SELECT 	0x0F
+#  define RTC_RATE_NONE		0x00
+#  define RTC_RATE_32786HZ	0x01
+#  define RTC_RATE_16384HZ	0x02
+#  define RTC_RATE_8192HZ	0x03
+#  define RTC_RATE_4096HZ	0x04
+#  define RTC_RATE_2048HZ	0x05
+#  define RTC_RATE_1024HZ	0x06
+#  define RTC_RATE_512HZ	0x07
+#  define RTC_RATE_256HZ	0x08
+#  define RTC_RATE_128HZ	0x09
+#  define RTC_RATE_64HZ		0x0a
+#  define RTC_RATE_32HZ		0x0b
+#  define RTC_RATE_16HZ		0x0c
+#  define RTC_RATE_8HZ		0x0d
+#  define RTC_RATE_4HZ		0x0e
+#  define RTC_RATE_2HZ		0x0f
+
+/**********************************************************************/
+#define RTC_CONTROL	RTC_REG_B
+# define RTC_SET 0x80		/* disable updates for clock setting */
+# define RTC_PIE 0x40		/* periodic interrupt enable */
+# define RTC_AIE 0x20		/* alarm interrupt enable */
+# define RTC_UIE 0x10		/* update-finished interrupt enable */
+# define RTC_SQWE 0x08		/* enable square-wave output */
+# define RTC_DM_BINARY 0x04	/* all time/date values are BCD if clear */
+# define RTC_24H 0x02		/* 24 hour mode - else hours bit 7 means pm */
+# define RTC_DST_EN 0x01	/* auto switch DST - works f. USA only */
+
+/**********************************************************************/
+#define RTC_INTR_FLAGS	RTC_REG_C
+/* caution - cleared by read */
+# define RTC_IRQF 0x80		/* any of the following 3 is active */
+# define RTC_PF 0x40
+# define RTC_AF 0x20
+# define RTC_UF 0x10
+
+/**********************************************************************/
+#define RTC_VALID	RTC_REG_D
+# define RTC_VRT 0x80		/* valid RAM and time */
+/**********************************************************************/
+
+
+/* On PCs, the checksum is built only over bytes 16..45 */
+#define PC_CKS_RANGE_START	16
+#define PC_CKS_RANGE_END	45
+#define PC_CKS_LOC		46
+
+#define LB_CKS_RANGE_START	49
+#define LB_CKS_RANGE_END	125
+#define LB_CKS_LOC		126
+
+#if !defined(ASSEMBLY)
+void rtc_init(int invalid);
+#if USE_OPTION_TABLE == 1
+int get_option(void *dest, char *name);
+#else
+#define get_option(dest, name) (-2)
+#endif
+#endif
+
+#endif /*  PC80_MC146818RTC_H */
diff --git a/src/include/smp/atomic.h b/src/include/smp/atomic.h
new file mode 100644
index 0000000..b36e0e2
--- /dev/null
+++ b/src/include/smp/atomic.h
@@ -0,0 +1,53 @@
+#ifndef SMP_ATOMIC_H
+#define SMP_ATOMIC_H
+
+#ifdef SMP
+#include <arch/smp/atomic.h>
+#else
+
+typedef struct { int counter; } atomic_t;
+#define ATOMIC_INIT(i) { (i) }
+
+/**
+ * atomic_read - read atomic variable
+ * @v: pointer of type atomic_t
+ * 
+ * Atomically reads the value of @v.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */ 
+#define atomic_read(v)		((v)->counter)
+
+/**
+ * atomic_set - set atomic variable
+ * @v: pointer of type atomic_t
+ * @i: required value
+ * 
+ * Atomically sets the value of @v to @i.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */ 
+#define atomic_set(v,i)		(((v)->counter) = (i))
+
+
+/**
+ * atomic_inc - increment atomic variable
+ * @v: pointer of type atomic_t
+ * 
+ * Atomically increments @v by 1.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */ 
+#define atomic_inc(v)	(((v)->counter)++)
+
+
+/**
+ * atomic_dec - decrement atomic variable
+ * @v: pointer of type atomic_t
+ * 
+ * Atomically decrements @v by 1.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */ 
+#define atomic_dec(v)	(((v)->counter)--)
+
+
+#endif /* SMP */
+
+#endif /* SMP_ATOMIC_H */
diff --git a/src/include/smp/spinlock.h b/src/include/smp/spinlock.h
new file mode 100644
index 0000000..9e0f8af
--- /dev/null
+++ b/src/include/smp/spinlock.h
@@ -0,0 +1,24 @@
+#ifndef SMP_SPINLOCK_H
+#define SMP_SPINLOCK_H
+
+#ifdef SMP
+#include <arch/smp/spinlock.h>
+#else /* !SMP */
+
+/* Most GCC versions have a nasty bug with empty initializers */
+#if (__GNUC__ > 2) 
+typedef struct { } spinlock_t;
+#define SPIN_LOCK_UNLOCKED (spinlock_t) { }
+#else
+typedef struct { int gcc_is_buggy; } spinlock_t;
+#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
+#endif
+
+#define barrier()		do {} while(0)
+#define spin_is_locked(lock)	0
+#define spin_unlock_wait(lock)	do {} while(0)
+#define spin_lock(lock)		do {} while(0)
+#define spin_unlock(lock)	do {} while(0)
+#endif
+
+#endif /* SMP_SPINLOCK_H */
diff --git a/src/include/smp/start_stop.h b/src/include/smp/start_stop.h
new file mode 100644
index 0000000..c0eebd0
--- /dev/null
+++ b/src/include/smp/start_stop.h
@@ -0,0 +1,17 @@
+#ifndef SMP_START_STOP_H
+#define SMP_START_STOP_H
+
+#if SMP == 1
+#include <smp/atomic.h>
+unsigned long this_processors_id(void);
+int processor_index(unsigned long processor_id);
+void stop_cpu(unsigned long processor_id);
+int start_cpu(unsigned long processor_id);
+void startup_other_cpus(unsigned long *processor_map);
+#else
+#define this_processors_id()	0
+#define startup_other_cpus(p)	do {} while(0)
+#define processor_index(p) 0
+#endif
+
+#endif /* SMP_START_STOP_H */
diff --git a/src/include/stdlib.h b/src/include/stdlib.h
new file mode 100644
index 0000000..eb67d20
--- /dev/null
+++ b/src/include/stdlib.h
@@ -0,0 +1,14 @@
+#ifndef STDLIB_H
+#define STDLIB_H
+
+#include <stddef.h>
+
+extern void *malloc(size_t size);
+void free(void *ptr);
+
+/* Extensions to malloc... */
+typedef size_t malloc_mark_t;
+void malloc_mark(malloc_mark_t *place);
+void malloc_release(malloc_mark_t *place);
+
+#endif /* STDLIB_H */
diff --git a/src/include/stream/read_bytes.h b/src/include/stream/read_bytes.h
new file mode 100644
index 0000000..dd3ef04
--- /dev/null
+++ b/src/include/stream/read_bytes.h
@@ -0,0 +1,13 @@
+#ifndef STREAM_READ_BYTES_H
+#define STREAM_READ_BYTES_H
+
+#include <stdint.h>
+
+typedef long byte_offset_t;
+
+extern int stream_init(void);
+extern byte_offset_t stream_read(void *vdest, byte_offset_t count);
+extern byte_offset_t stream_skip(byte_offset_t count);
+extern void stream_fini(void);
+
+#endif /* STREAM_READ_BYTES_H */
diff --git a/src/include/string.h b/src/include/string.h
new file mode 100644
index 0000000..cf9bbb1
--- /dev/null
+++ b/src/include/string.h
@@ -0,0 +1,36 @@
+#ifndef STRING_H
+#define STRING_H
+
+#include <stddef.h>
+
+// yes, linux has fancy ones. We don't care. This stuff gets used 
+// hardly at all. And the pain of including those files is just too high.
+
+//extern inline void strcpy(char *dst, char *src) {while (*src) *dst++ = *src++;}
+
+//extern inline int strlen(char *src) { int i = 0; while (*src++) i++; return i;}
+
+static inline size_t strnlen(const char *src, size_t max) 
+{ 
+	size_t i = 0;
+	while((*src++) && (i < max)) {
+		i++;
+	}
+	return i;
+}
+
+static inline size_t strlen(const char *src)
+{
+	size_t i = 0;
+	while(*src++) {
+		i++;
+	}
+	return i;
+}
+
+extern void *memcpy(void *dest, const void *src, size_t n);
+extern void *memset(void *s, int c, size_t n);
+extern int memcmp(const void *s1, const void *s2, size_t n);
+
+extern int sprintf(char * buf, const char *fmt, ...);
+#endif /* STRING_H */
diff --git a/src/include/uart8250.h b/src/include/uart8250.h
new file mode 100644
index 0000000..ae45615
--- /dev/null
+++ b/src/include/uart8250.h
@@ -0,0 +1,7 @@
+#ifndef UART8250_H
+#define UART8250_H
+
+void uart8250_tx_byte(unsigned base_port, unsigned char data);
+void uart8250_init(unsigned base_port, unsigned divisor, unsigned lcs);
+
+#endif /* UART8250_H */
diff --git a/src/include/version.h b/src/include/version.h
new file mode 100644
index 0000000..223b9a3
--- /dev/null
+++ b/src/include/version.h
@@ -0,0 +1,22 @@
+#ifndef VERSION_H
+#define VERSION_H
+
+/* Motherboard Information */
+extern const char mainboard_vendor[];
+extern const char mainboard_part_number[];
+
+/* LinuxBIOS Version */
+extern const char linuxbios_version[];
+extern const char linuxbios_extra_version[];
+extern const char linuxbios_build[];
+
+/* When LinuxBIOS was compiled */
+extern const char linuxbios_compile_time[];
+extern const char linuxbios_compile_by[];
+extern const char linuxbios_compile_host[];
+extern const char linuxbios_compile_domain[];
+extern const char linuxbios_compiler[];
+extern const char linuxbios_linker[];
+extern const char linuxbios_assembler[];
+
+#endif /* VERSION_H */
diff --git a/src/lib/clog2.c b/src/lib/clog2.c
new file mode 100644
index 0000000..092b49c
--- /dev/null
+++ b/src/lib/clog2.c
@@ -0,0 +1,18 @@
+#include <console/console.h>
+
+unsigned long log2(unsigned long x)
+{
+        // assume 8 bits per byte.
+        unsigned long i = 1 << (sizeof(x)*8 - 1);
+        unsigned long pow = sizeof(x) * 8 - 1;
+
+        if (! x) {
+                printk_warning("%s called with invalid parameter of 0\n",
+			__FUNCTION__);
+                return -1;
+        }
+        for(; i > x; i >>= 1, pow--)
+                ;
+
+        return pow;
+}
diff --git a/src/lib/compute_ip_checksum.c b/src/lib/compute_ip_checksum.c
new file mode 100644
index 0000000..0b8eb90
--- /dev/null
+++ b/src/lib/compute_ip_checksum.c
@@ -0,0 +1,53 @@
+#include <stdint.h>
+#include <ip_checksum.h>
+
+unsigned long compute_ip_checksum(void *addr, unsigned long length)
+{
+	uint8_t *ptr;
+	volatile union {
+		uint8_t  byte[2];
+		uint16_t word;
+	} value;
+	unsigned long sum;
+	unsigned long i;
+	/* In the most straight forward way possible,
+	 * compute an ip style checksum.
+	 */
+	sum = 0;
+	ptr = addr;
+	for(i = 0; i < length; i++) {
+		unsigned long value;
+		value = ptr[i];
+		if (i & 1) {
+			value <<= 8;
+		}
+		/* Add the new value */
+		sum += value;
+		/* Wrap around the carry */
+		if (sum > 0xFFFF) {
+			sum = (sum + (sum >> 16)) & 0xFFFF;
+		}
+	}
+	value.byte[0] = sum & 0xff;
+	value.byte[1] = (sum >> 8) & 0xff;
+	return (~value.word) & 0xFFFF;
+}
+
+unsigned long add_ip_checksums(unsigned long offset, unsigned long sum, unsigned long new)
+{
+	unsigned long checksum;
+	sum = ~sum & 0xFFFF;
+	new = ~new & 0xFFFF;
+	if (offset & 1) {
+		/* byte swap the sum if it came from an odd offset 
+		 * since the computation is endian independant this
+		 * works.
+		 */
+		new = ((new >> 8) & 0xff) | ((new << 8) & 0xff00);
+	}
+	checksum = sum + new;
+	if (checksum > 0xFFFF) {
+		checksum -= 0xFFFF;
+	}
+	return (~checksum) & 0xFFFF;
+}
diff --git a/src/lib/delay.c b/src/lib/delay.c
new file mode 100644
index 0000000..af5f786
--- /dev/null
+++ b/src/lib/delay.c
@@ -0,0 +1,15 @@
+#include <delay.h>
+void mdelay(int msecs)
+{
+	int i;
+	for(i = 0; i < msecs; i++) {
+		udelay(1000);
+	}
+}
+void delay(int secs)
+{
+	int i;
+	for(i = 0; i < secs; i++) {
+		mdelay(1000);
+	}
+}
diff --git a/src/lib/fallback_boot.c b/src/lib/fallback_boot.c
new file mode 100644
index 0000000..1bddd0a
--- /dev/null
+++ b/src/lib/fallback_boot.c
@@ -0,0 +1,25 @@
+#include <console/console.h>
+#include <part/fallback_boot.h>
+#include <pc80/mc146818rtc.h>
+#include <arch/io.h>
+
+void boot_successful(void)
+{
+	/* Remember I succesfully booted by setting
+	 * the initial boot direction
+	 * to the direction that I booted.
+	 */
+	unsigned char index, byte;
+	index = inb(RTC_PORT(0)) & 0x80;
+	index |= RTC_BOOT_BYTE;
+	outb(index, RTC_PORT(0));
+
+	byte = inb(RTC_PORT(1));
+	byte &= 0xfe;
+	byte |= (byte & 2) >> 1;
+
+	/* If we are in normal mode set the boot count to 0 */
+	if(byte & 1)
+		byte &= 0x0f;
+	outb(byte, RTC_PORT(1));
+}
diff --git a/src/lib/malloc.c b/src/lib/malloc.c
new file mode 100644
index 0000000..bd403e47e
--- /dev/null
+++ b/src/lib/malloc.c
@@ -0,0 +1,52 @@
+#include <stdlib.h>
+#include <console/console.h>
+
+#if 0
+#define MALLOCDBG(x)
+#else
+#define MALLOCDBG(x) printk_spew x
+#endif
+extern unsigned char _heap, _eheap;
+static size_t free_mem_ptr = (size_t)&_heap;		/* Start of heap */
+static size_t free_mem_end_ptr = (size_t)&_eheap;	/* End of heap */
+
+
+void malloc_mark(malloc_mark_t *place)
+{
+	*place = free_mem_ptr;
+	printk_spew("malloc_mark 0x%08lx\n", (unsigned long)free_mem_ptr);
+}
+
+void malloc_release(malloc_mark_t *ptr)
+{
+	free_mem_ptr = *ptr;
+	printk_spew("malloc_release 0x%08lx\n", (unsigned long)free_mem_ptr);
+}
+
+void *malloc(size_t size)
+{
+	void *p;
+
+	MALLOCDBG(("%s Enter, size %d, free_mem_ptr %p\n", __FUNCTION__, size, free_mem_ptr));
+	if (size < 0)
+		die("Error! malloc: Size < 0");
+	if (free_mem_ptr <= 0)
+		die("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)
+		die("Error! malloc: Free_mem_ptr >= free_mem_end_ptr");
+
+	MALLOCDBG(("malloc 0x%08lx\n", (unsigned long)p));
+
+	return p;
+}
+
+void free(void *where)
+{
+	/* Don't care */
+}
diff --git a/src/lib/memcmp.c b/src/lib/memcmp.c
new file mode 100644
index 0000000..46f13a4
--- /dev/null
+++ b/src/lib/memcmp.c
@@ -0,0 +1,17 @@
+#include <string.h>
+
+int memcmp(const void *src1, const void *src2, size_t bytes)
+{
+	const unsigned char *s1, *s2;
+	int result;
+	s1 = src1;
+	s2 = src2;
+	result = 0;
+	while((bytes > 0) && (result == 0)) {
+		result = *s1 - *s2;
+		bytes--;
+		s1++;
+		s2++;
+	}
+	return result;
+}
diff --git a/src/lib/memcpy.c b/src/lib/memcpy.c
new file mode 100644
index 0000000..ad8e8bd
--- /dev/null
+++ b/src/lib/memcpy.c
@@ -0,0 +1,11 @@
+#include <string.h>
+void *memcpy(void *__dest, __const void *__src, size_t __n)
+{
+	int i;
+	char *d = (char *) __dest, *s = (char *) __src;
+
+	for (i = 0; i < __n; i++)
+		d[i] = s[i];
+
+	return __dest;
+}
diff --git a/src/lib/memset.c b/src/lib/memset.c
new file mode 100644
index 0000000..c1bb4f8
--- /dev/null
+++ b/src/lib/memset.c
@@ -0,0 +1,12 @@
+#include <string.h>
+
+void *memset(void *s, int c, size_t n)
+{
+	int i;
+	char *ss = (char *) s;
+
+	for (i = 0; i < n; i++)
+		ss[i] = c;
+
+	return s;
+}
diff --git a/src/lib/uart8250.c b/src/lib/uart8250.c
new file mode 100644
index 0000000..778919b
--- /dev/null
+++ b/src/lib/uart8250.c
@@ -0,0 +1,64 @@
+#ifndef lint
+static char rcsid[] = "$Id$";
+#endif
+
+/* Should support 8250, 16450, 16550, 16550A type uarts */
+#include <arch/io.h>
+#include <uart8250.h>
+
+/* Data */
+#define UART_RBR 0x00
+#define UART_TBR 0x00
+
+/* Control */
+#define UART_IER 0x01
+#define UART_IIR 0x02
+#define UART_FCR 0x02
+#define UART_LCR 0x03
+#define UART_MCR 0x04
+#define UART_DLL 0x00
+#define UART_DLM 0x01
+
+/* Status */
+#define UART_LSR 0x05
+#define UART_MSR 0x06
+#define UART_SCR 0x07
+
+static inline int uart8250_can_tx_byte(unsigned base_port)
+{
+	return inb(base_port + UART_LSR) & 0x20;
+}
+
+static inline void uart8250_wait_to_tx_byte(unsigned base_port)
+{
+	while(!uart8250_can_tx_byte(base_port))
+		;
+}
+
+static inline void uart8250_wait_until_sent(unsigned base_port)
+{
+	while(!(inb(base_port + UART_LSR) & 0x40)) 
+		;
+}
+
+void uart8250_tx_byte(unsigned base_port, unsigned char data)
+{
+	uart8250_wait_to_tx_byte(base_port);
+	outb(data, base_port + UART_TBR);
+	/* Make certain the data clears the fifos */
+	uart8250_wait_until_sent(base_port);
+}
+
+void uart8250_init(unsigned base_port, unsigned divisor, unsigned lcs)
+{
+	lcs &= 0x7f;
+	/* disable interrupts */
+	outb(0x0, base_port + UART_IER);
+	/* enable fifo's */
+	outb(0x01, base_port + UART_FCR);
+	/* Set Baud Rate Divisor to 12 ==> 115200 Baud */
+	outb(0x80 | lcs, base_port + UART_LCR);
+	outb(divisor & 0xFF,   base_port + UART_DLL);
+	outb((divisor >> 8) & 0xFF,    base_port + UART_DLM);
+	outb(lcs, base_port + UART_LCR);
+}
diff --git a/src/lib/version.c b/src/lib/version.c
new file mode 100644
index 0000000..73d52ca
--- /dev/null
+++ b/src/lib/version.c
@@ -0,0 +1,62 @@
+#include <version.h>
+
+#define __STR(X) #X
+#define STR(X) __STR(X)
+
+#ifndef MAINBOARD_VENDOR
+#error MAINBOARD_VENDOR not defined
+#endif
+#ifndef MAINBOARD_PART_NUMBER
+#error  MAINBOARD_PART_NUMBER not defined
+#endif
+
+#ifndef LINUXBIOS_VERSION
+#error  LINUXBIOS_VERSION not defined
+#endif
+#ifndef LINUXBIOS_BUILD
+#error  LINUXBIOS_BUILD not defined
+#endif
+
+#ifndef LINUXBIOS_COMPILE_TIME
+#error  LINUXBIOS_COMPILE_TIME not defined
+#endif
+#ifndef LINUXBIOS_COMPILE_BY
+#error  LINUXBIOS_COMPILE_BY not defined
+#endif
+#ifndef LINUXBIOS_COMPILE_HOST
+#error  LINUXBIOS_COMPILE_HOST not defined
+#endif
+
+#ifndef LINUXBIOS_COMPILER
+#error  LINUXBIOS_COMPILER not defined
+#endif
+#ifndef LINUXBIOS_LINKER
+#error  LINUXBIOS_LINKER not defined
+#endif
+#ifndef LINUXBIOS_ASSEMBLER
+#error  LINUXBIOS_ASSEMBLER not defined
+#endif
+
+
+#ifndef  LINUXBIOS_EXTRA_VERSION
+#define LINUXBIOS_EXTRA_VERSION
+#endif
+
+const char mainboard_vendor[] = STR(MAINBOARD_VENDOR);
+const char mainboard_part_number[] = STR(MAINBOARD_PART_NUMBER);
+
+const char linuxbios_version[] = STR(LINUXBIOS_VERSION);
+const char linuxbios_extra_version[] = STR(LINUXBIOS_EXTRA_VERSION);
+const char linuxbios_build[] = STR(LINUXBIOS_BUILD);
+
+const char linuxbios_compile_time[]   = STR(LINUXBIOS_COMPILE_TIME);
+const char linuxbios_compile_by[]     = STR(LINUXBIOS_COMPILE_BY);
+const char linuxbios_compile_host[]   = STR(LINUXBIOS_COMPILE_HOST);
+const char linuxbios_compile_domain[] = STR(LINUXBIOS_COMPILE_DOMAIN);
+const char linuxbios_compiler[]       = STR(LINUXBIOS_COMPILER);
+const char linuxbios_linker[]         = STR(LINUXBIOS_LINKER);
+const char linuxbios_assembler[]      = STR(LINUXBIOS_ASSEMBLER);
+
+
+
+
diff --git a/src/mainboard/amd/solo/auto.c b/src/mainboard/amd/solo/auto.c
new file mode 100644
index 0000000..bc549fa
--- /dev/null
+++ b/src/mainboard/amd/solo/auto.c
@@ -0,0 +1,1070 @@
+#define ASSEMBLY 1
+#include "arch/romcc_io.h"
+#include "pc80/serial.c"
+#include "arch/i386/lib/console.c"
+#include "ram/ramtest.c"
+
+
+static void sdram_set_registers(void)
+{
+	static const unsigned int register_values[] = {
+	/* Routing Table Node i 
+	 * F0:0x40 i = 0, 
+	 * F0:0x44 i = 1,
+	 * F0:0x48 i = 2, 
+	 * F0:0x4c i = 3,
+	 * F0:0x50 i = 4, 
+	 * F0:0x54 i = 5,
+	 * F0:0x58 i = 6, 
+	 * F0:0x5c i = 7
+	 * [ 0: 3] Request Route
+	 *     [0] Route to this node
+	 *     [1] Route to Link 0
+	 *     [2] Route to Link 1
+	 *     [3] Route to Link 2
+	 * [11: 8] Response Route
+	 *     [0] Route to this node
+	 *     [1] Route to Link 0
+	 *     [2] Route to Link 1
+	 *     [3] Route to Link 2
+	 * [19:16] Broadcast route
+	 *     [0] Route to this node
+	 *     [1] Route to Link 0
+	 *     [2] Route to Link 1
+	 *     [3] Route to Link 2
+	 */
+	0xc040, 0xfff0f0f0, 0x00010101,
+	0xc044, 0xfff0f0f0, 0x00010101,
+	0xc048, 0xfff0f0f0, 0x00010101,
+	0xc04c, 0xfff0f0f0, 0x00010101,
+	0xc050, 0xfff0f0f0, 0x00010101,
+	0xc054, 0xfff0f0f0, 0x00010101,
+	0xc058, 0xfff0f0f0, 0x00010101,
+	0xc05c, 0xfff0f0f0, 0x00010101,
+
+	/* Hypetransport Transaction Control Register 
+	 * F0:0x68
+	 * [ 0: 0] Disable read byte probe
+	 *         0 = Probes issues
+	 *         1 = Probes not issued
+	 * [ 1: 1] Disable Read Doubleword probe
+	 *         0 = Probes issued
+	 *         1 = Probes not issued
+	 * [ 2: 2] Disable write byte probes
+	 *         0 = Probes issued
+	 *         1 = Probes not issued
+	 * [ 3: 3] Disalbe Write Doubleword Probes
+	 *         0 = Probes issued
+	 *         1 = Probes not issued.
+	 * [ 4: 4] Disable Memroy Controller Target Start
+	 *         0 = TgtStart packets are generated
+	 *         1 = TgtStart packets are not generated.
+	 * [ 5: 5] CPU1 Enable
+	 *         0 = Second CPU disabled or not present
+	 *         1 = Second CPU enabled.
+	 * [ 6: 6] CPU Request PassPW
+	 *         0 = CPU requests do not pass posted writes
+	 *         1 = CPU requests pass posted writes.
+	 * [ 7: 7] CPU read Respons PassPW
+	 *         0 = CPU Responses do not pass posted writes
+	 *         1 = CPU responses pass posted writes.
+	 * [ 8: 8] Disable Probe Memory Cancel
+	 *         0 = Probes may generate MemCancels
+	 *         1 = Probes may not generate MemCancels
+	 * [ 9: 9] Disable Remote Probe Memory Cancel.
+	 *         0 = Probes hitting dirty blocks generate memory cancel packets
+	 *         1 = Only probed caches on the same node as the memory controller
+	 *              generate cancel packets.
+	 * [10:10] Disable Fill Probe
+	 *         0 = Probes issued for cache fills
+	 *         1 = Probes not issued for cache fills.
+	 * [11:11] Response PassPw
+	 *         0 = Downstream response PassPW based on original request
+	 *         1 = Downstream response PassPW set to 1
+	 * [12:12] Change ISOC to Ordered
+	 *         0 = Bit 1 of coherent HT RdSz/WrSz command used for iosynchronous prioritization
+	 *         1 = Bit 1 of coherent HT RdSz/WrSz command used for ordering.
+	 * [14:13] Buffer Release Priority select 
+	 *         00 = 64
+	 *         01 = 16
+	 *         10 = 8
+	 *         11 = 2
+	 * [15:15] Limit Coherent HT Configuration Space Range
+	 *         0 = No coherent HT configuration space restrictions
+	 *         1 = Limit coherent HT configuration space based on node count
+	 * [16:16] Local Interrupt Conversion Enable.
+	 *         0 = ExtInt/NMI interrups unaffected.
+	 *         1 = ExtInt/NMI broadcat interrupts converted to LINT0/1
+	 * [17:17] APIC Extended Broadcast Enable.
+	 *         0 = APIC broadcast is 0F
+	 *         1 = APIC broadcast is FF
+	 * [18:18] APIC Extended ID Enable
+	 *         0 = APIC ID is 4 bits.
+	 *         1 = APIC ID is 8 bits.
+	 * [19:19] APIC Extended Spurious Vector Enable
+	 *         0 = Lower 4 bits of spurious vector are read-only 1111
+	 *         1 = Lower 4 bits of spurious vecotr are writeable.
+	 * [20:20] Sequence ID Source Node Enable
+	 *         0 = Normal operation
+	 *         1 = Keep SeqID on routed packets for debugging.
+	 * [22:21] Downstream non-posted request limit
+	 *         00 = No limit
+	 *         01 = Limited to 1
+	 *         10 = Limited to 4
+	 *         11 = Limited to 8
+	 * [23:23] RESERVED
+	 * [25:24] Medium-Priority Bypass Count
+	 *         - Maximum # of times a medium priority access can pass a low
+	 *           priority access before Medium-Priority mode is disabled for one access.
+	 * [27:26] High-Priority Bypass Count
+	 *         - Maximum # of times a high prioirty access can pass a medium or low
+	 *           priority access before High-prioirty mode is disabled for one access.
+	 * [28:28] Enable High Priority CPU Reads
+	 *         0 = Cpu reads are medium prioirty
+	 *         1 = Cpu reads are high prioirty
+	 * [29:29] Disable Low Priority Writes
+	 *         0 = Non-isochronous writes are low priority
+	 *         1 = Non-isochronous writes are medium prioirty
+	 * [30:30] Disable High Priority Isochronous writes
+	 *         0 = Isochronous writes are high priority
+	 *         1 = Isochronous writes are medium priority
+	 * [31:31] Disable Medium Priority Isochronous writes
+	 *         0 = Isochronous writes are medium are high
+	 *         1 = With bit 30 set makes Isochrouns writes low priority.
+	 */
+	0xc068, 0x00800000, 0x0f00840f,
+	/* HT Initialization Control Register
+	 * F0:0x68
+	 * [ 0: 0] Routing Table Disable
+	 *         0 = Packets are routed according to routing tables
+	 *         1 = Packets are routed according to the default link field
+	 * [ 1: 1] Request Disable (BSP should clear this)
+	 *         0 = Request packets may be generated
+	 *         1 = Request packets may not be generated.
+	 * [ 3: 2] Default Link (Read-only)
+	 *         00 = LDT0
+	 *         01 = LDT1
+	 *         10 = LDT2
+	 *         11 = CPU on same node
+	 * [ 4: 4] Cold Reset
+	 *         - Scratch bit cleared by a cold reset
+	 * [ 5: 5] BIOS Reset Detect
+	 *         - Scratch bit cleared by a cold reset
+	 * [ 6: 6] INIT Detect
+	 *         - Scratch bit cleared by a warm or cold reset not by an INIT
+	 *
+	 */
+	0xc06C, 0xffffff8c, 0x00000000,
+	/* LDTi Capabilities Registers
+	 * F0:0x80 i = 0,
+	 * F0:0xA0 i = 1,
+	 * F0:0xC0 i = 2,
+	 */
+	/* LDTi Link Control Registrs
+	 * F0:0x84 i = 0,
+	 * F0:0xA4 i = 1,
+	 * F0:0xC4 i = 2,
+	 * [ 1: 1] CRC Flood Enable
+	 *         0 = Do not generate sync packets on CRC error
+	 *         1 = Generate sync packets on CRC error
+	 * [ 2: 2] CRC Start Test (Read-Only)
+	 * [ 3: 3] CRC Force Frame Error
+	 *         0 = Do not generate bad CRC
+	 *         1 = Generate bad CRC
+	 * [ 4: 4] Link Failure
+	 *         0 = No link failure detected
+	 *         1 = Link failure detected
+	 * [ 5: 5] Initialization Complete
+	 *         0 = Initialization not complete
+	 *         1 = Initialization complete
+	 * [ 6: 6] Receiver off
+	 *         0 = Recevier on
+	 *         1 = Receiver off
+	 * [ 7: 7] Transmitter Off
+	 *         0 = Transmitter on
+	 *         1 = Transmitter off
+	 * [ 9: 8] CRC_Error
+	 *         00 = No error
+	 *         [0] = 1 Error on byte lane 0
+	 *         [1] = 1 Error on byte lane 1
+	 * [12:12] Isochrnous Enable  (Read-Only)
+	 * [13:13] HT Stop Tristate Enable
+	 *         0 = Driven during an LDTSTOP_L
+	 *         1 = Tristated during and LDTSTOP_L
+	 * [14:14] Extended CTL Time 
+	 *         0 = CTL is asserted for 16 bit times during link initialization
+	 *         1 = CTL is asserted for 50us during link initialization
+	 * [18:16] Max Link Width In (Read-Only?)
+	 *         000 = 8 bit link
+	 *         001 = 16bit link
+	 * [19:19] Doubleword Flow Control in (Read-Only)
+	 *         0 = This link does not support doubleword flow control
+	 *         1 = This link supports doubleword flow control
+	 * [22:20] Max Link Width Out (Read-Only?)
+	 *         000 = 8 bit link
+	 *         001 = 16bit link
+	 * [23:23] Doubleworld Flow Control out (Read-Only)
+	 *         0 = This link does not support doubleword flow control
+	 *         1 = This link supports doubleworkd flow control
+	 * [26:24] Link Width In
+	 *         000 = Use 8 bits
+	 *         001 = Use 16 bits
+	 *         010 = reserved
+	 *         011 = Use 32 bits
+	 *         100 = Use 2 bits
+	 *         101 = Use 4 bits
+	 *         110 = reserved
+	 *         111 = Link physically not connected
+	 * [27:27] Doubleword Flow Control In Enable
+	 *         0 = Doubleword flow control disabled
+	 *         1 = Doubleword flow control enabled (Not currently supported)
+	 * [30:28] Link Width Out
+	 *         000 = Use 8 bits
+	 *         001 = Use 16 bits
+	 *         010 = reserved
+	 *         011 = Use 32 bits
+	 *         100 = Use 2 bits
+	 *         101 = Use 4 bits
+	 *         110 = reserved
+	 *         111 = Link physically not connected
+	 * [31:31] Doubleworld Flow Control Out Enable
+	 *         0 = Doubleworld flow control disabled
+	 *         1 = Doubleword flow control enabled (Not currently supported)
+	 */
+	0xc084, 0x00009c05, 0x11110020,
+	/* LDTi Frequency/Revision Registers
+	 * F0:0x88 i = 0,
+	 * F0:0xA8 i = 1,
+	 * F0:0xC8 i = 2,
+	 * [ 4: 0] Minor Revision
+	 *         Contains the HT Minor revision
+	 * [ 7: 5] Major Revision
+	 *         Contains the HT Major revision
+	 * [11: 8] Link Frequency  (Takes effect the next time the link is reconnected)
+	 *         0000 = 200Mhz
+	 *         0001 = reserved
+	 *         0010 = 400Mhz
+	 *         0011 = reserved
+	 *         0100 = 600Mhz
+	 *         0101 = 800Mhz
+	 *         0110 = 1000Mhz
+	 *         0111 = reserved
+	 *         1000 = reserved
+	 *         1001 = reserved
+	 *         1010 = reserved
+	 *         1011 = reserved
+	 *         1100 = reserved
+	 *         1101 = reserved
+	 *         1110 = reserved
+	 *         1111 = 100 Mhz
+	 * [15:12] Error (Not currently Implemented)
+	 * [31:16] Indicates the frequency capabilities of the link
+	 *         [16] = 1 encoding 0000 of freq supported
+	 *         [17] = 1 encoding 0001 of freq supported
+	 *         [18] = 1 encoding 0010 of freq supported
+	 *         [19] = 1 encoding 0011 of freq supported
+	 *         [20] = 1 encoding 0100 of freq supported
+	 *         [21] = 1 encoding 0101 of freq supported
+	 *         [22] = 1 encoding 0110 of freq supported
+	 *         [23] = 1 encoding 0111 of freq supported
+	 *         [24] = 1 encoding 1000 of freq supported
+	 *         [25] = 1 encoding 1001 of freq supported
+	 *         [26] = 1 encoding 1010 of freq supported
+	 *         [27] = 1 encoding 1011 of freq supported
+	 *         [28] = 1 encoding 1100 of freq supported
+	 *         [29] = 1 encoding 1101 of freq supported
+	 *         [30] = 1 encoding 1110 of freq supported
+	 *         [31] = 1 encoding 1111 of freq supported
+	 */
+	0xC088, 0xfffff0ff, 0x00000200,
+	/* LDTi Feature Capability
+	 * F0:0x8C i = 0,
+	 * F0:0xAC i = 1,
+	 * F0:0xCC i = 2,
+	 */
+	/* LDTi Buffer Count Registers
+	 * F0:0x90 i = 0,
+	 * F0:0xB0 i = 1,
+	 * F0:0xD0 i = 2,
+	 */
+	/* LDTi Bus Number Registers
+	 * F0:0x94 i = 0,
+	 * F0:0xB4 i = 1,
+	 * F0:0xD4 i = 2,
+	 * For NonCoherent HT specifies the bus number downstream (behind the host bridge)
+	 * [ 0: 7] Primary Bus Number
+	 * [15: 8] Secondary Bus Number
+	 * [23:15] Subordiante Bus Number
+	 * [31:24] reserved
+	 */
+	0xC094, 0xff000000, 0x00ff0000,
+	/* LDTi Type Registers
+	 * F0:0x98 i = 0,
+	 * F0:0xB8 i = 1,
+	 * F0:0xD8 i = 2,
+	 */
+	/* Careful set limit registers before base registers which contain the enables */
+	/* DRAM Limit i Registers
+	 * F1:0x44 i = 0
+	 * F1:0x4C i = 1
+	 * F1:0x54 i = 2
+	 * F1:0x5C i = 3
+	 * F1:0x64 i = 4
+	 * F1:0x6C i = 5
+	 * F1:0x74 i = 6
+	 * F1:0x7C i = 7
+	 * [ 2: 0] Destination Node ID
+	 *         000 = Node 0
+	 *         001 = Node 1
+	 *         010 = Node 2
+	 *         011 = Node 3
+	 *         100 = Node 4
+	 *         101 = Node 5
+	 *         110 = Node 6
+	 *         111 = Node 7
+	 * [ 7: 3] Reserved
+	 * [10: 8] Interleave select
+	 *         specifies the values of A[14:12] to use with interleave enable.
+	 * [15:11] Reserved
+	 * [31:16] DRAM Limit Address i Bits 39-24
+	 *         This field defines the upper address bits of a 40 bit  address
+	 *         that define the end of the DRAM region.
+	 */
+	0xC144, 0x0000f8f8, 0x003f0000,
+	0xC148, 0x0000f8f8, 0x00000001,
+	0xC154, 0x0000f8f8, 0x00000002,
+	0xC158, 0x0000f8f8, 0x00000003,
+	0xC164, 0x0000f8f8, 0x00000004,
+	0xC168, 0x0000f8f8, 0x00000005,
+	0xC174, 0x0000f8f8, 0x00000006,
+	0xC178, 0x0000f8f8, 0x00000007,
+	/* DRAM Base i Registers
+	 * F1:0x40 i = 0
+	 * F1:0x48 i = 1
+	 * F1:0x50 i = 2
+	 * F1:0x58 i = 3
+	 * F1:0x60 i = 4
+	 * F1:0x68 i = 5
+	 * F1:0x70 i = 6
+	 * F1:0x78 i = 7
+	 * [ 0: 0] Read Enable
+	 *         0 = Reads Disabled
+	 *         1 = Reads Enabled
+	 * [ 1: 1] Write Enable
+	 *         0 = Writes Disabled
+	 *         1 = Writes Enabled
+	 * [ 7: 2] Reserved
+	 * [10: 8] Interleave Enable
+	 *         000 = No interleave
+	 *         001 = Interleave on A[12] (2 nodes)
+	 *         010 = reserved
+	 *         011 = Interleave on A[12] and A[14] (4 nodes)
+	 *         100 = reserved
+	 *         101 = reserved
+	 *         110 = reserved
+	 *         111 = Interleve on A[12] and A[13] and A[14] (8 nodes)
+	 * [15:11] Reserved
+	 * [13:16] DRAM Base Address i Bits 39-24
+	 *         This field defines the upper address bits of a 40-bit address
+	 *         that define the start of the DRAM region.
+	 */
+	0xC140, 0x0000f8fc, 0x00000003,
+	0xC148, 0x0000f8fc, 0x00400000,
+	0xC150, 0x0000f8fc, 0x00400000,
+	0xC158, 0x0000f8fc, 0x00400000,
+	0xC160, 0x0000f8fc, 0x00400000,
+	0xC168, 0x0000f8fc, 0x00400000,
+	0xC170, 0x0000f8fc, 0x00400000,
+	0xC178, 0x0000f8fc, 0x00400000,
+
+	/* Memory-Mapped I/O Limit i Registers
+	 * F1:0x84 i = 0
+	 * F1:0x8C i = 1
+	 * F1:0x94 i = 2
+	 * F1:0x9C i = 3
+	 * F1:0xA4 i = 4
+	 * F1:0xAC i = 5
+	 * F1:0xB4 i = 6
+	 * F1:0xBC i = 7
+	 * [ 2: 0] Destination Node ID
+	 *         000 = Node 0
+	 *         001 = Node 1
+	 *         010 = Node 2
+	 *         011 = Node 3
+	 *         100 = Node 4
+	 *         101 = Node 5
+	 *         110 = Node 6
+	 *         111 = Node 7
+	 * [ 3: 3] Reserved
+	 * [ 5: 4] Destination Link ID
+	 *         00 = Link 0
+	 *         01 = Link 1
+	 *         10 = Link 2
+	 *         11 = Reserved
+	 * [ 6: 6] Reserved
+	 * [ 7: 7] Non-Posted
+	 *         0 = CPU writes may be posted
+	 *         1 = CPU writes must be non-posted
+	 * [31: 8] Memory-Mapped I/O Limit Address i (39-16)
+	 *         This field defines the upp adddress bits of a 40-bit address that
+	 *         defines the end of a memory-mapped I/O region n
+	 */
+	0xC184, 0x00000048, 0x00e1ff00,
+	0xC18C, 0x00000048, 0x00dfff00,
+	0xC194, 0x00000048, 0x00e3ff00,
+	0xC19C, 0x00000048, 0x00000000,
+	0xC1A4, 0x00000048, 0x00000000,
+	0xC1AC, 0x00000048, 0x00000000,
+	0xC1B4, 0x00000048, 0x00000b00,
+
+
+	/* Memory-Mapped I/O Base i Registers
+	 * F1:0x80 i = 0
+	 * F1:0x88 i = 1
+	 * F1:0x90 i = 2
+	 * F1:0x98 i = 3
+	 * F1:0xA0 i = 4
+	 * F1:0xA8 i = 5
+	 * F1:0xB0 i = 6
+	 * F1:0xB8 i = 7
+	 * [ 0: 0] Read Enable
+	 *         0 = Reads disabled
+	 *         1 = Reads Enabled
+	 * [ 1: 1] Write Enable
+	 *         0 = Writes disabled
+	 *         1 = Writes Enabled
+	 * [ 2: 2] Cpu Disable
+	 *         0 = Cpu can use this I/O range
+	 *         1 = Cpu requests do not use this I/O range
+	 * [ 3: 3] Lock
+	 *         0 = base/limit registers i are read/write
+	 *         1 = base/limit registers i are read-only
+	 * [ 7: 4] Reserved
+	 * [31: 8] Memory-Mapped I/O Base Address i (39-16)
+	 *         This field defines the upper address bits of a 40bit address 
+	 *         that defines the start of memory-mapped I/O region i
+	 */
+	0xC1BC, 0x00000048, 0x00fe0b00,
+	0xC180, 0x000000f0, 0x00e00003,
+	0xC188, 0x000000f0, 0x00d80003,
+	0xC190, 0x000000f0, 0x00e20003,
+	0xC198, 0x000000f0, 0x00000000,
+	0xC1A0, 0x000000f0, 0x00000000,
+	0xC1A8, 0x000000f0, 0x00000000,
+	0xC1B0, 0x000000f0, 0x0000a003,
+	0xC1B8, 0x000000f0, 0x00400003,
+
+	/* PCI I/O Limit i Registers
+	 * F1:0xC4 i = 0
+	 * F1:0xCC i = 1
+	 * F1:0xD4 i = 2
+	 * F1:0xDC i = 3
+	 * [ 2: 0] Destination Node ID
+	 *         000 = Node 0
+	 *         001 = Node 1
+	 *         010 = Node 2
+	 *         011 = Node 3
+	 *         100 = Node 4
+	 *         101 = Node 5
+	 *         110 = Node 6
+	 *         111 = Node 7
+	 * [ 3: 3] Reserved
+	 * [ 5: 4] Destination Link ID
+	 *         00 = Link 0
+	 *         01 = Link 1
+	 *         10 = Link 2
+	 *         11 = reserved
+	 * [11: 6] Reserved
+	 * [24:12] PCI I/O Limit Address i
+	 *         This field defines the end of PCI I/O region n
+	 * [31:25] Reserved
+	 */
+	0xC1C4, 0xFE000FC8, 0x0000d000,
+	0xC1CC, 0xFE000FC8, 0x000ff000,
+	0xC1D4, 0xFE000FC8, 0x00000000,
+	0xC1DC, 0xFE000FC8, 0x00000000,
+
+	/* PCI I/O Base i Registers
+	 * F1:0xC0 i = 0
+	 * F1:0xC8 i = 1
+	 * F1:0xD0 i = 2
+	 * F1:0xD8 i = 3
+	 * [ 0: 0] Read Enable
+	 *         0 = Reads Disabled
+	 *         1 = Reads Enabled
+	 * [ 1: 1] Write Enable
+	 *         0 = Writes Disabled
+	 *         1 = Writes Enabled
+	 * [ 3: 2] Reserved
+	 * [ 4: 4] VGA Enable
+	 *         0 = VGA matches Disabled
+	 *         1 = matches all address < 64K and where A[9:0] is in the 
+	 *             range 3B0-3BB or 3C0-3DF independen of the base & limit registers
+	 * [ 5: 5] ISA Enable
+	 *         0 = ISA matches Disabled
+	 *         1 = Blocks address < 64K and in the last 768 bytes of eack 1K block
+	 *             from matching agains this base/limit pair
+	 * [11: 6] Reserved
+	 * [24:12] PCI I/O Base i
+	 *         This field defines the start of PCI I/O region n 
+	 * [31:25] Reserved
+	 */
+	0xC1C0, 0xFE000FCC, 0x0000d003,
+	0xC1C8, 0xFE000FCC, 0x00001013,
+	0xC1D0, 0xFE000FCC, 0x00000000,
+	0xC1D8, 0xFE000FCC, 0x00000000,
+
+	/* Config Base and Limit i Registers
+	 * F1:0xE0 i = 0
+	 * F1:0xE4 i = 1
+	 * F1:0xE8 i = 2
+	 * F1:0xEC i = 3
+	 * [ 0: 0] Read Enable
+	 *         0 = Reads Disabled
+	 *         1 = Reads Enabled
+	 * [ 1: 1] Write Enable
+	 *         0 = Writes Disabled
+	 *         1 = Writes Enabled
+	 * [ 2: 2] Device Number Compare Enable
+	 *         0 = The ranges are based on bus number
+	 *         1 = The ranges are ranges of devices on bus 0
+	 * [ 3: 3] Reserved
+	 * [ 6: 4] Destination Node
+	 *         000 = Node 0
+	 *         001 = Node 1
+	 *         010 = Node 2
+	 *         011 = Node 3
+	 *         100 = Node 4
+	 *         101 = Node 5
+	 *         110 = Node 6
+	 *         111 = Node 7
+	 * [ 7: 7] Reserved
+	 * [ 9: 8] Destination Link
+	 *         00 = Link 0
+	 *         01 = Link 1
+	 *         10 = Link 2
+	 *         11 - Reserved
+	 * [15:10] Reserved
+	 * [23:16] Bus Number Base i
+	 *         This field defines the lowest bus number in configuration region i
+	 * [31:24] Bus Number Limit i
+	 *         This field defines the highest bus number in configuration regin i
+	 */
+	0xC1E0, 0x0000FC88, 0xff000003,
+	0xC1E4, 0x0000FC88, 0x00000000,
+	0xC1E8, 0x0000FC88, 0x00000000,
+	0xC1EC, 0x0000FC88, 0x00000000,
+
+	/* DRAM CS Base Address i Registers
+	 * F2:0x40 i = 0
+	 * F2:0x44 i = 1
+	 * F2:0x48 i = 2
+	 * F2:0x4C i = 3
+	 * F2:0x50 i = 4
+	 * F2:0x54 i = 5
+	 * F2:0x58 i = 6
+	 * F2:0x5C i = 7
+	 * [ 0: 0] Chip-Select Bank Enable
+	 *         0 = Bank Disabled
+	 *         1 = Bank Enabled
+	 * [ 8: 1] Reserved
+	 * [15: 9] Base Address (19-13)
+	 *         An optimization used when all DIMM are the same size...
+	 * [20:16] Reserved
+	 * [31:21] Base Address (35-25)
+	 *         This field defines the top 11 addresses bit of a 40-bit
+	 *         address that define the memory address space.  These
+	 *         bits decode 32-MByte blocks of memory.
+	 */
+	0xC240, 0x001f01fe, 0x00000001,
+	0xC244, 0x001f01fe, 0x01000001,
+	0xC248, 0x001f01fe, 0x02000001,
+	0xC24C, 0x001f01fe, 0x03000001,
+	0xC250, 0x001f01fe, 0x00000000,
+	0xC254, 0x001f01fe, 0x00000000,
+	0xC258, 0x001f01fe, 0x00000000,
+	0xC25C, 0x001f01fe, 0x00000000,
+	/* DRAM CS Mask Address i Registers
+	 * F2:0x60 i = 0
+	 * F2:0x64 i = 1
+	 * F2:0x68 i = 2
+	 * F2:0x6C i = 3
+	 * F2:0x70 i = 4
+	 * F2:0x74 i = 5
+	 * F2:0x78 i = 6
+	 * F2:0x7C i = 7
+	 * Select bits to exclude from comparison with the DRAM Base address register.
+	 * [ 8: 0] Reserved
+	 * [15: 9] Address Mask (19-13)
+	 *         Address to be excluded from the optimized case
+	 * [20:16] Reserved
+	 * [29:21] Address Mask (33-25)
+	 *         The bits with an address mask of 1 are excluded from address comparison
+	 * [31:30] Reserved
+	 * 
+	 */
+	0xC260, 0xC01f01ff, 0x00e0fe00,
+	0xC264, 0xC01f01ff, 0x00e0fe00,
+	0xC268, 0xC01f01ff, 0x00e0fe00,
+	0xC26C, 0xC01f01ff, 0x00e0fe00,
+	0xC270, 0xC01f01ff, 0x00000000,
+	0xC274, 0xC01f01ff, 0x00000000,
+	0xC278, 0xC01f01ff, 0x00000000,
+	0xC27C, 0xC01f01ff, 0x00000000,
+	/* DRAM Bank Address Mapping Register
+	 * F2:0x80
+	 * Specify the memory module size
+	 * [ 2: 0] CS1/0 
+	 * [ 6: 4] CS3/2
+	 * [10: 8] CS5/4
+	 * [14:12] CS7/6
+	 *         000 = 32Mbyte  (Rows = 12 & Col =  8)
+	 *         001 = 64Mbyte  (Rows = 12 & Col =  9)
+	 *         010 = 128Mbyte (Rows = 13 & Col =  9)|(Rows = 12 & Col = 10)
+	 *         011 = 256Mbyte (Rows = 13 & Col = 10)|(Rows = 12 & Col = 11)
+	 *         100 = 512Mbyte (Rows = 13 & Col = 11)|(Rows = 14 & Col = 10)
+	 *         101 = 1Gbyte   (Rows = 14 & Col = 11)|(Rows = 13 & Col = 12)
+	 *         110 = 2Gbyte   (Rows = 14 & Col = 12)
+	 *         111 = reserved 
+	 * [ 3: 3] Reserved
+	 * [ 7: 7] Reserved
+	 * [11:11] Reserved
+	 * [31:15]
+	 */
+	0xC280, 0xffff8888, 0x00000033,
+	/* DRAM Timing Low Register
+	 * F2:0x88
+	 * [ 2: 0] Tcl (Cas# Latency, Cas# to read-data-valid)
+	 *         000 = reserved
+	 *         001 = CL 2
+	 *         010 = CL 3
+	 *         011 = reserved
+	 *         100 = reserved
+	 *         101 = CL 2.5
+	 *         110 = reserved
+	 *         111 = reserved
+	 * [ 3: 3] Reserved
+	 * [ 7: 4] Trc (Row Cycle Time, Ras#-active to Ras#-active/bank auto refresh)
+	 *         0000 =  7 bus clocks
+	 *         0001 =  8 bus clocks
+	 *         ...
+	 *         1110 = 21 bus clocks
+	 *         1111 = 22 bus clocks
+	 * [11: 8] Trfc (Row refresh Cycle time, Auto-refresh-active to RAS#-active or RAS#auto-refresh)
+	 *         0000 = 9 bus clocks
+	 *         0010 = 10 bus clocks
+	 *         ....
+	 *         1110 = 23 bus clocks
+	 *         1111 = 24 bus clocks
+	 * [14:12] Trcd (Ras#-active to Case#-read/write Delay)
+	 *         000 = reserved
+	 *         001 = reserved
+	 *         010 = 2 bus clocks
+	 *         011 = 3 bus clocks
+	 *         100 = 4 bus clocks
+	 *         101 = 5 bus clocks
+	 *         110 = 6 bus clocks
+	 *         111 = reserved
+	 * [15:15] Reserved
+	 * [18:16] Trrd (Ras# to Ras# Delay)
+	 *         000 = reserved
+	 *         001 = reserved
+	 *         010 = 2 bus clocks
+	 *         011 = 3 bus clocks
+	 *         100 = 4 bus clocks
+	 *         101 = reserved
+	 *         110 = reserved
+	 *         111 = reserved
+	 * [19:19] Reserved
+	 * [23:20] Tras (Minmum Ras# Active Time)
+	 *         0000 to 0100 = reserved
+	 *         0101 = 5 bus clocks
+	 *         ...
+	 *         1111 = 15 bus clocks
+	 * [26:24] Trp (Row Precharge Time)
+	 *         000 = reserved
+	 *         001 = reserved
+	 *         010 = 2 bus clocks
+	 *         011 = 3 bus clocks
+	 *         100 = 4 bus clocks
+	 *         101 = 5 bus clocks
+	 *         110 = 6 bus clocks
+	 *         111 = reserved
+	 * [27:27] Reserved
+	 * [28:28] Twr (Write Recovery Time)
+	 *         0 = 2 bus clocks
+	 *         1 = 3 bus clocks
+	 * [31:29] Reserved
+	 */
+	0xC288, 0xe8088008, 0x03623125,
+	/* DRAM Timing High Register
+	 * F2:0x8C
+	 * [ 0: 0] Twtr (Write to Read Delay)
+	 *         0 = 1 bus Clocks
+	 *         1 = 2 bus Clocks
+	 * [ 3: 1] Reserved
+	 * [ 6: 4] Trwf (Read to Write Delay)
+	 *         000 = 1 bus clocks
+	 *         001 = 2 bus clocks
+	 *         010 = 3 bus clocks
+	 *         011 = 4 bus clocks
+	 *         100 = 5 bus clocks
+	 *         101 = 6 bus clocks
+	 *         110 = reserved
+	 *         111 = reserved
+	 * [ 7: 7] Reserved
+	 * [12: 8] Tref (Refresh Rate)
+	 *         00000 = 100Mhz 4K rows
+	 *         00001 = 133Mhz 4K rows
+	 *         00010 = 166Mhz 4K rows
+	 *         01000 = 100Mhz 8K/16K rows
+	 *         01001 = 133Mhz 8K/16K rows
+	 *         01010 = 166Mhz 8K/16K rows
+	 * [19:13] Reserved
+	 * [22:20] Twcl (Write CAS Latency)
+	 *         000 = 1 Mem clock after CAS# (Unbuffered Dimms)
+	 *         001 = 2 Mem clocks after CAS# (Registered Dimms)
+	 * [31:23] Reserved
+	 */
+	0xC28c, 0xff8fe08e, 0x00000930,
+
+	/* DRAM Config Low Register
+	 * F2:0x90
+	 * [ 0: 0] DLL Disable
+	 *         0 = Enabled
+	 *         1 = Disabled
+	 * [ 1: 1] D_DRV
+	 *         0 = Normal Drive
+	 *         1 = Weak Drive
+	 * [ 2: 2] QFC_EN
+	 *         0 = Disabled
+	 *         1 = Enabled
+	 * [ 3: 3] Disable DQS Hystersis  (FIXME handle this one carefully)
+	 *         0 = Enable DQS input filter 
+	 *         1 = Disable DQS input filtering 
+	 * [ 7: 4] Reserved
+	 * [ 8: 8] DRAM_Init
+	 *         0 = Initialization done or not yet started.
+	 *         1 = Initiate DRAM intialization sequence
+	 * [ 9: 9] SO-Dimm Enable
+	 *         0 = Do nothing
+	 *         1 = SO-Dimms present
+	 * [10:10] DramEnable
+	 *         0 = DRAM not enabled
+	 *         1 = DRAM initialized and enabled
+	 * [11:11] Memory Clear Status
+	 *         0 = Memory Clear function has not completed
+	 *         1 = Memory Clear function has completed
+	 * [12:12] Exit Self-Refresh
+	 *         0 = Exit from self-refresh done or not yet started
+	 *         1 = DRAM exiting from self refresh
+	 * [13:13] Self-Refresh Status
+	 *         0 = Normal Operation
+	 *         1 = Self-refresh mode active
+	 * [15:14] Read/Write Queue Bypass Count
+	 *         00 = 2
+	 *         01 = 4
+	 *         10 = 8
+	 *         11 = 16
+	 * [16:16] 128-bit/64-Bit
+	 *         0 = 64bit Interface to DRAM
+	 *         1 = 128bit Interface to DRAM
+	 * [17:17] DIMM ECC Enable
+	 *         0 = Some DIMMs do not have ECC
+	 *         1 = ALL DIMMS have ECC bits
+	 * [18:18] UnBuffered DIMMs
+	 *         0 = Buffered DIMMS
+	 *         1 = Unbuffered DIMMS
+	 * [19:19] Enable 32-Byte Granularity
+	 *         0 = Optimize for 64byte bursts
+	 *         1 = Optimize for 32byte bursts
+	 * [20:20] DIMM 0 is x4
+	 * [21:21] DIMM 1 is x4
+	 * [22:22] DIMM 2 is x4
+	 * [23:23] DIMM 3 is x4
+	 *         0 = DIMM is not x4
+	 *         1 = x4 DIMM present
+	 * [24:24] Disable DRAM Receivers
+	 *         0 = Receivers enabled
+	 *         1 = Receivers disabled
+	 * [27:25] Bypass Max
+	 *         000 = Arbiters chois is always respected
+	 *         001 = Oldest entry in DCQ can be bypassed 1 time
+	 *         010 = Oldest entry in DCQ can be bypassed 2 times
+	 *         011 = Oldest entry in DCQ can be bypassed 3 times
+	 *         100 = Oldest entry in DCQ can be bypassed 4 times
+	 *         101 = Oldest entry in DCQ can be bypassed 5 times
+	 *         110 = Oldest entry in DCQ can be bypassed 6 times
+	 *         111 = Oldest entry in DCQ can be bypassed 7 times
+	 * [31:28] Reserved
+	 */
+	0xC290, 0xf0000000, 
+	(4 << 25)|(0 << 24)| 
+	(0 << 23)|(0 << 22)|(0 << 21)|(0 << 20)| 
+	(1 << 19)|(1 << 18)|(0 << 17)|(0 << 16)| 
+	(2 << 14)|(0 << 13)|(0 << 12)| 
+	(0 << 11)|(0 << 10)|(0 << 9)|(0 << 8)| 
+	(0 << 3) |(0 << 1) |(0 << 0),
+	/* DRAM Config High Register
+	 * F2:0x94
+	 * [ 0: 3] Maximum Asynchronous Latency
+	 *         0000 = 0 ns
+	 *         ...
+	 *         1111 = 15 ns
+	 * [ 7: 4] Reserved
+	 * [11: 8] Read Preamble
+	 *         0000 = 2.0 ns
+	 *         0001 = 2.5 ns
+	 *         0010 = 3.0 ns
+	 *         0011 = 3.5 ns
+	 *         0100 = 4.0 ns
+	 *         0101 = 4.5 ns
+	 *         0110 = 5.0 ns
+	 *         0111 = 5.5 ns
+	 *         1000 = 6.0 ns
+	 *         1001 = 6.5 ns
+	 *         1010 = 7.0 ns
+	 *         1011 = 7.5 ns
+	 *         1100 = 8.0 ns
+	 *         1101 = 8.5 ns
+	 *         1110 = 9.0 ns
+	 *         1111 = 9.5 ns
+	 * [15:12] Reserved
+	 * [18:16] Idle Cycle Limit
+	 *         000 = 0 cycles
+	 *         001 = 4 cycles
+	 *         010 = 8 cycles
+	 *         011 = 16 cycles
+	 *         100 = 32 cycles
+	 *         101 = 64 cycles
+	 *         110 = 128 cycles
+	 *         111 = 256 cycles
+	 * [19:19] Dynamic Idle Cycle Center Enable
+	 *         0 = Use Idle Cycle Limit
+	 *         1 = Generate a dynamic Idle cycle limit
+	 * [22:20] DRAM MEMCLK Frequency
+	 *         000 = 100Mhz
+	 *         001 = reserved
+	 *         010 = 133Mhz
+	 *         011 = reserved
+	 *         100 = reserved
+	 *         101 = 166Mhz
+	 *         110 = reserved
+	 *         111 = reserved
+	 * [24:23] Reserved
+	 * [25:25] Memory Clock Ratio Valid (FIXME carefully enable memclk)
+	 *         0 = Disable MemClks
+	 *         1 = Enable MemClks
+	 * [26:26] Memory Clock 0 Enable
+	 *         0 = Disabled
+	 *         1 = Enabled
+	 * [27:27] Memory Clock 1 Enable
+	 *         0 = Disabled
+	 *         1 = Enabled
+	 * [28:28] Memory Clock 2 Enable
+	 *         0 = Disabled
+	 *         1 = Enabled
+	 * [29:29] Memory Clock 3 Enable
+	 *         0 = Disabled
+	 *         1 = Enabled
+	 * [31:30] Reserved
+	 */
+	0xC294, 0xc180f0f0, 0x0e2b0a05,
+	/* DRAM Delay Line Register
+	 * F2:0x98
+	 * Adjust the skew of the input DQS strobe relative to DATA
+	 * [15: 0] Reserved
+	 * [23:16] Delay Line Adjust
+	 *         Adjusts the DLL derived PDL delay by one or more delay stages
+	 *         in either the faster or slower direction.
+	 * [24:24} Adjust Slower
+	 *         0 = Do Nothing
+	 *         1 = Adj is used to increase the PDL delay
+	 * [25:25] Adjust Faster
+	 *         0 = Do Nothing
+	 *         1 = Adj is used to decrease the PDL delay
+	 * [31:26] Reserved
+	 */
+	0xC298, 0xfc00ffff, 0x00000000,
+	/* DRAM Scrub Control Register
+	 * F3:0x58
+	 * [ 4: 0] DRAM Scrube Rate
+	 * [ 7: 5] reserved
+	 * [12: 8] L2 Scrub Rate
+	 * [15:13] reserved
+	 * [20:16] Dcache Scrub
+	 * [31:21] reserved
+	 *         Scrub Rates
+	 *         00000 = Do not scrub
+	 *         00001 =  40.00 ns
+	 *         00010 =  80.00 ns
+	 *         00011 = 160.00 ns
+	 *         00100 = 320.00 ns
+	 *         00101 = 640.00 ns
+	 *         00110 =   1.28 us
+	 *         00111 =   2.56 us
+	 *         01000 =   5.12 us
+	 *         01001 =  10.20 us
+	 *         01011 =  41.00 us
+	 *         01100 =  81.90 us
+	 *         01101 = 163.80 us
+	 *         01110 = 327.70 us
+	 *         01111 = 655.40 us
+	 *         10000 =   1.31 ms
+	 *         10001 =   2.62 ms
+	 *         10010 =   5.24 ms
+	 *         10011 =  10.49 ms
+	 *         10100 =  20.97 ms
+	 *         10101 =  42.00 ms
+	 *         10110 =  84.00 ms
+	 *         All Others = Reserved
+	 */
+	0xC358, 0xffe0e0e0, 0x00000000,
+	/* DRAM Scrub Address Low Register
+	 * F3:0x5C
+	 * [ 0: 0] DRAM Scrubber Redirect Enable
+	 *         0 = Do nothing
+	 *         1 = Scrubber Corrects errors found in normal operation
+	 * [ 5: 1] Reserved
+	 * [31: 6] DRAM Scrub Address 31-6
+	 */
+	0xC35C, 0x0000003e, 0x00000000,
+	/* DRAM Scrub Address High Register
+	 * F3:0x60
+	 * [ 7: 0] DRAM Scrubb Address 39-32
+	 * [31: 8] Reserved
+	 */
+	0xC360, 0xffffff00, 0x00000000,
+	};
+	int i;
+	int max;
+	print_debug("setting up northbridge registers\r\n");
+	max = sizeof(register_values)/sizeof(register_values[0]);
+	for(i = 0; i < max; i += 3) {
+		unsigned long reg;
+#if 0
+		print_debug_hex32(register_values[i]);
+		print_debug(" <-");
+		print_debug_hex32(register_values[i+2]);
+		print_debug("\r\n");
+#endif
+		reg = pcibios_read_config_dword(
+			0, register_values[i] >> 8, register_values[i] & 0xff);
+		reg &= register_values[i+1];
+		reg |= register_values[i+2] & ~register_values[i+1];
+		pcibios_write_config_dword(
+			0, register_values[i] >> 8, register_values[i] & 0xff, reg);
+	}
+	print_debug("setting up northbridge registers done. hurray!\r\n");
+}
+
+#define PCI_DEVFN(slot,func)	((((slot) & 0x1f) << 3) | ((func) & 0x07))
+
+#define DRAM_CONFIG_LOW 0x90
+#define  DCL_DLL_Disable   (1<<0)
+#define  DCL_D_DRV         (1<<1)
+#define  DCL_QFC_EN        (1<<2)
+#define  DCL_DisDqsHys     (1<<3)
+#define  DCL_DramInit      (1<<8)
+#define  DCL_DramEnable    (1<<10)
+#define  DCL_MemClrStatus  (1<<11)
+#define  DCL_DimmEcEn      (1<<17)
+
+static void sdram_set_spd_registers(void) 
+{
+	unsigned long dcl;
+	dcl = pcibios_read_config_dword(0, PCI_DEVFN(0x18,2), DRAM_CONFIG_LOW);
+	/* Until I know what is going on disable ECC support */
+	dcl &= ~DCL_DimmEcEn;
+	pcibios_write_config_dword(0, PCI_DEVFN(0x18,2), DRAM_CONFIG_LOW, dcl);
+}
+
+#define TIMEOUT_LOOPS 300000
+static void sdram_enable(void)
+{
+	unsigned long dcl;
+
+	/* Toggle DisDqsHys to get it working */
+	dcl = pcibios_read_config_dword(0, PCI_DEVFN(0x18,2), DRAM_CONFIG_LOW);
+	print_debug("dcl: ");
+	print_debug_hex32(dcl);
+	print_debug("\r\n");
+	dcl |= DCL_DisDqsHys;
+	pcibios_write_config_dword(0, PCI_DEVFN(0x18, 2), DRAM_CONFIG_LOW, dcl);
+	dcl &= ~DCL_DisDqsHys;
+	dcl &= ~DCL_DLL_Disable;
+	dcl &= ~DCL_D_DRV;
+	dcl &= ~DCL_QFC_EN;
+	dcl |= DCL_DramInit;
+	pcibios_write_config_dword(0, PCI_DEVFN(0x18, 2), DRAM_CONFIG_LOW, dcl);
+	
+	print_debug("Initializing memory: ");
+	int loops = 0;
+	do {
+		dcl = pcibios_read_config_dword(0, PCI_DEVFN(0x18, 2), DRAM_CONFIG_LOW);
+		loops += 1;
+		if ((loops & 1023) == 0) {
+			print_debug(" ");
+			print_debug_hex32(loops);
+		}
+	} while(((dcl & DCL_DramInit) != 0) && (loops < TIMEOUT_LOOPS));
+	if (loops >= TIMEOUT_LOOPS) {
+		print_debug(" failed\r\n");
+	} else {
+		print_debug(" done\r\n");
+	}
+
+#if 0
+	print_debug("Clearing memory: ");
+	loops = 0;
+	do {
+		dcl = pcibios_read_config_dword(0, PCI_DEVFN(0x18, 2), DRAM_CONFIG_LOW);
+		loops += 1;
+		if ((loops & 1023) == 0) {
+			print_debug(" ");
+			print_debug_hex32(loops);
+		}
+	} while(((dcl & DCL_MemClrStatus) == 0) && (loops < TIMEOUT_LOOPS));
+	if (loops >= TIMEOUT_LOOPS) {
+		print_debug("failed\r\n");
+	} else {
+		print_debug("done\r\n");
+	}
+#endif
+}
+
+static void sdram_first_normal_reference(void) {}
+static void sdram_enable_refresh(void) {}
+static void sdram_special_finishup(void) {}
+
+static int sdram_enabled(void)
+{
+	unsigned long dcl;
+	int enabled;
+	dcl = pcibios_read_config_dword(0, PCI_DEVFN(0x18, 2), DRAM_CONFIG_LOW);
+	enabled = !!(dcl & DCL_DramEnable);
+	if (enabled) {
+		print_debug("DRAM already enabled.");
+	}
+	return enabled;
+}
+
+
+#include "sdram/generic_sdram.c"
+
+static void main(void)
+{
+	uart_init();
+	console_init();
+	if (!sdram_enabled()) {
+		sdram_initialize();
+#if 0
+		ram_fill(  0x00100000, 0x00180000);
+		ram_verify(0x00100000, 0x00180000);
+#endif
+#if 1
+		ram_fill(  0x00000000, 0x00001000);
+		ram_verify(0x00000000, 0x00001000);
+#endif
+	}
+}
diff --git a/src/mainboard/amd/solo/cmos.layout b/src/mainboard/amd/solo/cmos.layout
new file mode 100644
index 0000000..5ba4c03
--- /dev/null
+++ b/src/mainboard/amd/solo/cmos.layout
@@ -0,0 +1,74 @@
+entries
+
+#start-bit length  config config-ID    name
+#0            8       r       0        seconds
+#8            8       r       0        alarm_seconds
+#16           8       r       0        minutes
+#24           8       r       0        alarm_minutes
+#32           8       r       0        hours
+#40           8       r       0        alarm_hours
+#48           8       r       0        day_of_week
+#56           8       r       0        day_of_month
+#64           8       r       0        month
+#72           8       r       0        year
+#80           4       r       0        rate_select
+#84           3       r       0        REF_Clock
+#87           1       r       0        UIP
+#88           1       r       0        auto_switch_DST
+#89           1       r       0        24_hour_mode
+#90           1       r       0        binary_values_enable
+#91           1       r       0        square-wave_out_enable
+#92           1       r       0        update_finished_enable
+#93           1       r       0        alarm_interrupt_enable
+#94           1       r       0        periodic_interrupt_enable
+#95           1       r       0        disable_clock_updates
+#96         288       r       0        temporary_filler
+0          384       r       0        reserved_memory
+384          1       e       4        boot_option
+385          1       e       4        last_boot
+386          1       e       1        ECC_memory
+388          4       r       0        reboot_bits
+392          3       e       5        baud_rate
+400          1       e       1        power_on_after_fail
+412          4       e       6        debug_level
+416          4       e       7        boot_first
+420          4       e       7        boot_second
+424          4       e       7        boot_third
+428          4       h       0        boot_index
+432	     8       h       0        boot_countdown
+1008         16      h       0        check_sum
+
+enumerations
+
+#ID value   text
+1     0     Disable
+1     1     Enable
+2     0     Enable
+2     1     Disable
+4     0     Fallback
+4     1     Normal
+5     0     115200
+5     1     57600
+5     2     38400
+5     3     19200
+5     4     9600
+5     5     4800
+5     6     2400
+5     7     1200
+6     6     Notice
+6     7     Info
+6     8     Debug
+6     9     Spew
+7     0     Network
+7     1     HDD
+7     2     Floppy
+7     8     Fallback_Network
+7     9     Fallback_HDD
+7     10    Fallback_Floppy
+#7     3     ROM
+
+checksums
+
+checksum 392 1007 1008
+
+
diff --git a/src/mainboard/amd/solo/mainboard.c b/src/mainboard/amd/solo/mainboard.c
new file mode 100644
index 0000000..b8b8d6c
--- /dev/null
+++ b/src/mainboard/amd/solo/mainboard.c
@@ -0,0 +1,25 @@
+#if 0
+#include <printk.h>
+#endif
+
+void
+mainboard_fixup(void)
+{
+}
+
+void
+final_mainboard_fixup(void)
+{
+#if 0
+//	void final_southbridge_fixup(void);
+//	void final_superio_fixup(void);
+
+	printk_info("AMD Solo initializing...");
+
+//	final_southbridge_fixup();
+
+//#ifndef USE_NEW_SUPERIO_INTERFACE
+//final_superio_fixup();
+//#endif
+#endif
+}
diff --git a/src/northbridge/amd/amdk8/northbridge.c b/src/northbridge/amd/amdk8/northbridge.c
new file mode 100644
index 0000000..1ba87bd
--- /dev/null
+++ b/src/northbridge/amd/amdk8/northbridge.c
@@ -0,0 +1,22 @@
+#include <arch/io.h>
+#include <stdint.h>
+#include <mem.h>
+#include <part/sizeram.h>
+
+struct mem_range *sizeram(void)
+{
+	static struct mem_range mem[3];
+	uint32_t size;
+	/* Convert size in bytes to size in K */
+	/* FIXME  hardcoded for now */
+	size = 512*1024;
+
+	mem[0].basek = 0;
+	mem[0].sizek = 640;
+	mem[1].basek = 1024;
+	mem[1].sizek = size - mem[1].basek;
+	mem[2].basek = 0;
+	mem[2].sizek = 0;
+	return mem;
+}
+
diff --git a/src/pc80/mc146818rtc.c b/src/pc80/mc146818rtc.c
new file mode 100644
index 0000000..b77653c
--- /dev/null
+++ b/src/pc80/mc146818rtc.c
@@ -0,0 +1,249 @@
+#include <console/console.h>
+#include <arch/io.h>
+#include <pc80/mc146818rtc.h>
+#include <boot/linuxbios_tables.h>
+#include <string.h>
+
+#define CMOS_READ(addr) ({ \
+outb((addr),RTC_PORT(0)); \
+inb(RTC_PORT(1)); \
+})
+
+#define CMOS_WRITE(val, addr) ({ \
+outb((addr),RTC_PORT(0)); \
+outb((val),RTC_PORT(1)); \
+})
+
+/* control registers - Moto names
+ */
+#define RTC_REG_A		10
+#define RTC_REG_B		11
+#define RTC_REG_C		12
+#define RTC_REG_D		13
+
+
+/**********************************************************************
+ * register details
+ **********************************************************************/
+#define RTC_FREQ_SELECT	RTC_REG_A
+
+/* update-in-progress  - set to "1" 244 microsecs before RTC goes off the bus,
+ * reset after update (may take 1.984ms @ 32768Hz RefClock) is complete,
+ * totalling to a max high interval of 2.228 ms.
+ */
+# define RTC_UIP		0x80
+# define RTC_DIV_CTL		0x70
+   /* divider control: refclock values 4.194 / 1.049 MHz / 32.768 kHz */
+#  define RTC_REF_CLCK_4MHZ	0x00
+#  define RTC_REF_CLCK_1MHZ	0x10
+#  define RTC_REF_CLCK_32KHZ	0x20
+   /* 2 values for divider stage reset, others for "testing purposes only" */
+#  define RTC_DIV_RESET1	0x60
+#  define RTC_DIV_RESET2	0x70
+  /* Periodic intr. / Square wave rate select. 0=none, 1=32.8kHz,... 15=2Hz */
+# define RTC_RATE_SELECT 	0x0F
+#  define RTC_RATE_NONE		0x00
+#  define RTC_RATE_32786HZ	0x01
+#  define RTC_RATE_16384HZ	0x02
+#  define RTC_RATE_8192HZ	0x03
+#  define RTC_RATE_4096HZ	0x04
+#  define RTC_RATE_2048HZ	0x05
+#  define RTC_RATE_1024HZ	0x06
+#  define RTC_RATE_512HZ	0x07
+#  define RTC_RATE_256HZ	0x08
+#  define RTC_RATE_128HZ	0x09
+#  define RTC_RATE_64HZ		0x0a
+#  define RTC_RATE_32HZ		0x0b
+#  define RTC_RATE_16HZ		0x0c
+#  define RTC_RATE_8HZ		0x0d
+#  define RTC_RATE_4HZ		0x0e
+#  define RTC_RATE_2HZ		0x0f
+
+/**********************************************************************/
+#define RTC_CONTROL	RTC_REG_B
+# define RTC_SET 0x80		/* disable updates for clock setting */
+# define RTC_PIE 0x40		/* periodic interrupt enable */
+# define RTC_AIE 0x20		/* alarm interrupt enable */
+# define RTC_UIE 0x10		/* update-finished interrupt enable */
+# define RTC_SQWE 0x08		/* enable square-wave output */
+# define RTC_DM_BINARY 0x04	/* all time/date values are BCD if clear */
+# define RTC_24H 0x02		/* 24 hour mode - else hours bit 7 means pm */
+# define RTC_DST_EN 0x01	/* auto switch DST - works f. USA only */
+
+/**********************************************************************/
+#define RTC_INTR_FLAGS	RTC_REG_C
+/* caution - cleared by read */
+# define RTC_IRQF 0x80		/* any of the following 3 is active */
+# define RTC_PF 0x40
+# define RTC_AF 0x20
+# define RTC_UF 0x10
+
+/**********************************************************************/
+#define RTC_VALID	RTC_REG_D
+# define RTC_VRT 0x80		/* valid RAM and time */
+/**********************************************************************/
+
+
+
+static int rtc_checksum_valid(int range_start, int range_end, int cks_loc)
+{
+	int i;
+	unsigned sum, old_sum;
+	sum = 0;
+	for(i = range_start; i <= range_end; i++) {
+		sum += CMOS_READ(i);
+	}
+	sum = (~sum)&0x0ffff;
+	old_sum = ((CMOS_READ(cks_loc)<<8) | CMOS_READ(cks_loc+1))&0x0ffff;
+	return sum == old_sum;
+}
+
+static void rtc_set_checksum(int range_start, int range_end, int cks_loc)
+{
+	int i;
+	unsigned sum;
+	sum = 0;
+	for(i = range_start; i <= range_end; i++) {
+		sum += CMOS_READ(i);
+	}
+	sum = ~(sum & 0x0ffff);
+	CMOS_WRITE(((sum >> 8) & 0x0ff), cks_loc);
+	CMOS_WRITE(((sum >> 0) & 0x0ff), cks_loc+1);
+}
+
+#define RTC_CONTROL_DEFAULT (RTC_24H)
+#define RTC_FREQ_SELECT_DEFAULT (RTC_REF_CLCK_32KHZ | RTC_RATE_1024HZ)
+
+#if 0 /* alpha setup */
+#undef RTC_CONTROL_DEFAULT
+#undef RTC_FREQ_SELECT_DEFAULT
+#define RTC_CONTROL_DEFAULT (RTC_SQWE | RTC_24H)
+#define RTC_FREQ_SELECT_DEFAULT (RTC_REF_CLCK_32KHZ | RTC_RATE_1024HZ)
+#endif
+void rtc_init(int invalid)
+{
+	unsigned char x;
+	int cmos_invalid, checksum_invalid;
+
+  printk_debug("RTC Init\n");
+	/* See if there has been a CMOS power problem. */
+	x = CMOS_READ(RTC_VALID);
+	cmos_invalid = !(x & RTC_VRT);
+
+	/* See if there is a CMOS checksum error */
+	checksum_invalid = !rtc_checksum_valid(PC_CKS_RANGE_START,
+			PC_CKS_RANGE_END,PC_CKS_LOC);
+
+	if (invalid || cmos_invalid || checksum_invalid) {
+		int i;
+		printk_warning("RTC:%s%s%s zeroing cmos\n",
+			invalid?" Clear requested":"", 
+			cmos_invalid?" Power Problem":"",
+			checksum_invalid?" Checksum invalid":"");
+#if 0
+		CMOS_WRITE(0, 0x01);
+		CMOS_WRITE(0, 0x03);
+		CMOS_WRITE(0, 0x05);
+		for(i = 10; i < 48; i++) {
+			CMOS_WRITE(0, i);
+		}
+		
+		if (cmos_invalid) {
+			/* Now setup a default date of Sat 1 January 2000 */
+			CMOS_WRITE(0, 0x00); /* seconds */
+			CMOS_WRITE(0, 0x02); /* minutes */
+			CMOS_WRITE(1, 0x04); /* hours */
+			CMOS_WRITE(7, 0x06); /* day of week */
+			CMOS_WRITE(1, 0x07); /* day of month */
+			CMOS_WRITE(1, 0x08); /* month */
+			CMOS_WRITE(0, 0x09); /* year */
+		}
+#endif
+	}
+	/* See if there is a LB CMOS checksum error */
+	checksum_invalid = !rtc_checksum_valid(LB_CKS_RANGE_START,
+			LB_CKS_RANGE_END,LB_CKS_LOC);
+	if(checksum_invalid)
+		printk_debug("Invalid CMOS LB checksum\n");
+
+	/* Setup the real time clock */
+	CMOS_WRITE(RTC_CONTROL_DEFAULT, RTC_CONTROL);
+	/* Setup the frequency it operates at */
+	CMOS_WRITE(RTC_FREQ_SELECT_DEFAULT, RTC_FREQ_SELECT);
+	/* Make certain we have a valid checksum */
+	rtc_set_checksum(PC_CKS_RANGE_START,
+                        PC_CKS_RANGE_END,PC_CKS_LOC);
+	/* Clear any pending interrupts */
+	(void) CMOS_READ(RTC_INTR_FLAGS);
+}
+
+
+#if USE_OPTION_TABLE == 1
+/* This routine returns the value of the requested bits
+	input bit = bit count from the beginning of the cmos image
+	      length = number of bits to include in the value
+	      ret = a character pointer to where the value is to be returned
+	output the value placed in ret
+	      returns 0 = successful, -1 = an error occurred
+*/
+static int get_cmos_value(unsigned long bit, unsigned long length, void *vret)
+{
+	unsigned char *ret;
+	unsigned long byte,byte_bit;
+	unsigned long i;
+	unsigned char uchar;
+
+	/* The table is checked when it is built to ensure all 
+		values are valid. */
+	ret = vret;
+	byte=bit/8;	/* find the byte where the data starts */
+	byte_bit=bit%8; /* find the bit in the byte where the data starts */
+	if(length<9) {	/* one byte or less */
+		uchar = CMOS_READ(byte); /* load the byte */
+		uchar >>= byte_bit;	/* shift the bits to byte align */
+		/* clear unspecified bits */
+		ret[0] = uchar & ((1 << length) -1);
+	}
+	else {	/* more that one byte so transfer the whole bytes */
+		for(i=0;length;i++,length-=8,byte++) {
+			/* load the byte */
+			ret[i]=CMOS_READ(byte);
+		}
+	}
+	return 0;
+}
+
+int get_option(void *dest, char *name)
+{
+	extern struct cmos_option_table option_table;
+	struct cmos_option_table *ct;
+	struct cmos_entries *ce;
+	size_t namelen;
+	int found=0;
+
+	/* Figure out how long name is */
+	namelen = strnlen(name, CMOS_MAX_NAME_LENGTH);
+	
+	/* find the requested entry record */
+	ct=&option_table;
+	ce=(struct cmos_entries*)((unsigned char *)ct + ct->header_length);
+	for(;ce->tag==LB_TAG_OPTION;
+		ce=(struct cmos_entries*)((unsigned char *)ce + ce->size)) {
+		if (memcmp(ce->name, name, namelen) == 0) {
+			found=1;
+			break;
+		}
+	}
+	if(!found) {
+		printk_err("ERROR: No cmos option '%s'\n", name);
+		return(-2);
+	}
+	
+	if(get_cmos_value(ce->bit, ce->length, dest))
+		return(-3);
+	if(!rtc_checksum_valid(LB_CKS_RANGE_START,
+			LB_CKS_RANGE_END,LB_CKS_LOC))
+		return(-4);
+	return(0);
+}
+#endif /* USE_OPTION_TABLE */
diff --git a/src/pc80/serial.c b/src/pc80/serial.c
new file mode 100644
index 0000000..b10d22d
--- /dev/null
+++ b/src/pc80/serial.c
@@ -0,0 +1,93 @@
+#include <part/fallback_boot.h>
+
+/* Base Address */
+#ifndef TTYS0_BASE
+#define TTYS0_BASE 0x3f8
+#endif
+
+#ifndef TTYS0_BAUD
+#define TTYS0_BAUD 115200
+#endif
+
+#if ((115200%TTYS0_BAUD) != 0)
+#error Bad ttys0 baud rate
+#endif
+
+#define TTYS0_DIV	(115200/TTYS0_BAUD)
+
+/* Line Control Settings */
+#ifndef TTYS0_LCS
+/* Set 8bit, 1 stop bit, no parity */
+#define TTYS0_LCS	0x3
+#endif
+
+#define UART_LCS	TTYS0_LCS
+
+/* Data */
+#define UART_RBR 0x00
+#define UART_TBR 0x00
+
+/* Control */
+#define UART_IER 0x01
+#define UART_IIR 0x02
+#define UART_FCR 0x02
+#define UART_LCR 0x03
+#define UART_MCR 0x04
+#define UART_DLL 0x00
+#define UART_DLM 0x01
+
+/* Status */
+#define UART_LSR 0x05
+#define UART_MSR 0x06
+#define UART_SCR 0x07
+
+static int uart_can_tx_byte(void)
+{
+	return inb(TTYS0_BASE + UART_LSR) & 0x20;
+}
+
+static void uart_wait_to_tx_byte(void)
+{
+	while(!uart_can_tx_byte())
+		;
+}
+
+static void uart_wait_until_sent(void)
+{
+	while(!(inb(TTYS0_BASE + UART_LSR) & 0x40)) 
+		;
+}
+
+static void uart_tx_byte(unsigned char data)
+{
+	uart_wait_to_tx_byte();
+	outb(data, TTYS0_BASE + UART_TBR);
+	/* Make certain the data clears the fifos */
+	uart_wait_until_sent();
+}
+
+static void uart_init(void)
+{
+	/* disable interrupts */
+	outb(0x0, TTYS0_BASE + UART_IER);
+	/* enable fifo's */
+	outb(0x01, TTYS0_BASE + UART_FCR);
+	/* Set Baud Rate Divisor to 12 ==> 115200 Baud */
+	outb(0x80 | UART_LCS, TTYS0_BASE + UART_LCR);
+#if 0 &&  USE_OPTION_TABLE == 1
+ {
+		static const unsigned char divisor[] = { 1,2,3,6,12,24,48,96 };
+		unsigned ttys0_div, ttys0_index;
+		outb(RTC_BOOT_BYTE + 1, 0x70);
+		ttys0_index = inb(0x71);
+		ttys0_index &= 7;
+		ttys0_div = divisor[ttys0_index];
+		outb(ttys0_div & 0xff, TTYS0_BASE + UART_DLL);
+		outb(0, TTYS0_BASE + UART_DLM);
+ }
+#else
+		outb(TTYS0_DIV & 0xFF,   TTYS0_BASE + UART_DLL);
+		outb((TTYS0_DIV >> 8) & 0xFF,    TTYS0_BASE + UART_DLM);
+#endif
+	outb(UART_LCS, TTYS0_BASE + UART_LCR);
+}
diff --git a/src/pc80/serial.inc b/src/pc80/serial.inc
new file mode 100644
index 0000000..b0f1269
--- /dev/null
+++ b/src/pc80/serial.inc
@@ -0,0 +1,106 @@
+#include <part/fallback_boot.h>
+
+
+/* Base Address */
+#ifndef TTYS0_BASE
+#define TTYS0_BASE	0x3f8
+#endif
+
+/* Baud Rate */
+#ifndef TTYS0_BAUD
+#define TTYS0_BAUD 115200
+#endif
+
+#if ((115200%TTYS0_BAUD) != 0)
+#error Bad ttys0 baud rate
+#endif
+
+/* Baud Rate Divisor */
+#define TTYS0_DIV	(115200/TTYS0_BAUD)
+#define TTYS0_DIV_LO	(TTYS0_DIV&0xFF)
+#define TTYS0_DIV_HI	((TTYS0_DIV >> 8)&0xFF)
+
+/* Line Control Settings */
+#ifndef TTYS0_LCS
+/* Set 8bit, 1 stop bit, no parity */
+#define TTYS0_LCS	0x3
+#endif
+
+/* Data */
+#define TTYS0_RBR (TTYS0_BASE+0x00)
+
+/* Control */
+#define TTYS0_TBR TTYS0_RBR
+#define TTYS0_IER (TTYS0_BASE+0x01)
+#define TTYS0_IIR (TTYS0_BASE+0x02)
+#define TTYS0_FCR TTYS0_IIR
+#define TTYS0_LCR (TTYS0_BASE+0x03)
+#define TTYS0_MCR (TTYS0_BASE+0x04)
+#define TTYS0_DLL TTYS0_RBR
+#define TTYS0_DLM TTYS0_IER
+
+/* Status */
+#define TTYS0_LSR (TTYS0_BASE+0x05)
+#define TTYS0_MSR (TTYS0_BASE+0x06)
+#define TTYS0_SCR (TTYS0_BASE+0x07)
+
+#if USE_OPTION_TABLE == 1
+.section ".rom.data"
+	.type	 div,@object
+	.size	 div,8
+div:
+.byte 1,2,3,6,12,24,48,96
+
+.previous
+#endif
+
+	jmp	serial0
+
+	/* uses:	ax, dx */
+#define TTYS0_TX_AL		\
+	mov	%al, %ah	; \
+9:	mov	$TTYS0_LSR, %dx	; \
+	inb	%dx, %al	; \
+	test	$0x20, %al	; \
+	je	9b		; \
+	mov	$TTYS0_TBR, %dx	; \
+	mov	%ah, %al	; \
+	outb	%al, %dx
+
+
+serial0:
+	/* Set 115.2Kbps,8n1 */
+	/* Set 8bit, 1 stop bit, no parity, DLAB */
+	mov	$TTYS0_LCR, %dx
+	mov	$(TTYS0_LCS | 0x80), %al
+	out	%al, %dx
+
+	/* set Baud Rate Divisor to 1 ==> 115200 Buad */
+#if USE_OPTION_TABLE == 1
+
+	movb	$(RTC_BOOT_BYTE+1), %al
+	outb	%al, $0x70
+	xorl	%edx,%edx
+	inb	$0x71, %al
+	andb	$7,%al
+	movb	%al,%dl
+	movb	div(%edx),%al
+	mov	$TTYS0_DLL, %dx
+	out	%al, %dx
+	mov	$TTYS0_DLM, %dx
+	xorb	%al,%al
+	out	%al, %dx
+#else
+	mov	$TTYS0_DLL, %dx
+	mov	$TTYS0_DIV_LO, %al
+	out	%al, %dx
+	mov	$TTYS0_DLM, %dx
+	mov	$TTYS0_DIV_HI, %al
+	out	%al, %dx
+#endif
+	/* Disable DLAB */
+	mov	$TTYS0_LCR, %dx
+	mov	$(TTYS0_LCS & 0x7f), %al
+	out	%al, %dx
+
+
diff --git a/src/ram/ramtest.c b/src/ram/ramtest.c
new file mode 100644
index 0000000..0e5e698
--- /dev/null
+++ b/src/ram/ramtest.c
@@ -0,0 +1,89 @@
+static void write_phys(unsigned long addr, unsigned long value)
+{
+	unsigned long *ptr;
+	ptr = (void *)addr;
+	*ptr = value;
+}
+
+static unsigned long read_phys(unsigned long addr)
+{
+	unsigned long *ptr;
+	ptr = (void *)addr;
+	return *ptr;
+}
+
+void ram_fill(unsigned long start, unsigned long stop)
+{
+	unsigned long addr;
+	/* 
+	 * Fill.
+	 */
+	print_debug("DRAM fill: ");
+	print_debug_hex32(start);
+	print_debug("-");
+	print_debug_hex32(stop);
+	print_debug("\r\n");
+	for(addr = start; addr < stop ; addr += 4) {
+		/* Display address being filled */
+		if ((addr & 0xffff) == 0) {
+			print_debug_hex32(addr);
+			print_debug("\r");
+		}
+		write_phys(addr, addr);
+	};
+	/* Display final address */
+	print_debug_hex32(addr);
+	print_debug("\r\nDRAM filled\r\n");
+}
+
+void ram_verify(unsigned long start, unsigned long stop)
+{
+	unsigned long addr;
+	/* 
+	 * Verify.
+	 */
+	print_debug("DRAM verify: ");
+	print_debug_hex32(start);
+	print_debug_char('-');
+	print_debug_hex32(stop);
+	print_debug("\r\n");
+	for(addr = start; addr < stop ; addr += 4) {
+		unsigned long value;
+		/* Display address being tested */
+		if ((addr & 0xffff) == 0) {
+			print_debug_hex32(addr);
+			print_debug("\r");
+		}
+		value = read_phys(addr);
+		if (value != addr) {
+			/* Display address with error */
+			print_err_hex32(addr);
+			print_err_char(':');
+			print_err_hex32(value);
+			print_err("\r\n");
+		}
+	}
+	/* Display final address */
+	print_debug_hex32(addr);
+	print_debug("\r\nDRAM verified\r\n");
+}
+
+
+void ramcheck(unsigned long start, unsigned long stop)
+{
+	int result;
+	/*
+	 * This is much more of a "Is my DRAM properly configured?"
+	 * test than a "Is my DRAM faulty?" test.  Not all bits
+	 * are tested.   -Tyson
+	 */
+	print_debug("Testing DRAM : ");
+	print_debug_hex32(start);
+	print_debug("-");	
+	print_debug_hex32(stop);
+	print_debug("\r\n");
+	ram_fill(start, stop);
+	ram_verify(start, stop);
+	print_debug("Done.\n");
+}
+
diff --git a/src/sdram/generic_dump_spd.c b/src/sdram/generic_dump_spd.c
new file mode 100644
index 0000000..27f1844
--- /dev/null
+++ b/src/sdram/generic_dump_spd.c
@@ -0,0 +1,25 @@
+void dump_spd_registers(void)
+{
+	unsigned device;
+	device = SMBUS_MEM_DEVICE_START;
+	printk_debug("\n");
+	while(device <= SMBUS_MEM_DEVICE_END) {
+		int status = 0;
+		int i;
+		printk_debug("dimm %02x", device);
+		for(i = 0; (i < 256) && (status == 0); i++) {
+			unsigned char byte;
+			if ((i % 20) == 0) {
+				printk_debug("\n%3d: ", i);
+			}
+			status = smbus_read_byte(device, i, &byte);
+			if (status != 0) {
+				printk_debug("bad device\n");
+				continue;
+			}
+			printk_debug("%02x ", byte);
+		}
+		device += SMBUS_MEM_DEVICE_INC;
+		printk_debug("\n");
+	}
+}
diff --git a/src/sdram/generic_sdram.c b/src/sdram/generic_sdram.c
new file mode 100644
index 0000000..be5ae87
--- /dev/null
+++ b/src/sdram/generic_sdram.c
@@ -0,0 +1,35 @@
+void sdram_no_memory(void)
+{
+	print_err("No memory!!\r\n");
+	while(1) { 
+		hlt(); 
+	}
+}
+
+/* Setup SDRAM */
+void sdram_initialize(void)
+{
+	print_debug("Ram1\r\n");
+	/* Set the registers we can set once to reasonable values */
+	sdram_set_registers();
+
+	print_debug("Ram2\r\n");
+	/* Now setup those things we can auto detect */
+	sdram_set_spd_registers();
+
+	print_debug("Ram3\r\n");
+	/* Now that everything is setup enable the SDRAM.
+	 * Some chipsets do the work for use while on others 
+	 * we need to it by hand.
+	 */
+	sdram_enable();
+
+	print_debug("Ram4\r\n");
+	sdram_first_normal_reference();
+
+	print_debug("Ram5\r\n");
+	sdram_enable_refresh();
+	sdram_special_finishup();
+
+	print_debug("Ram6\r\n");
+}
diff --git a/src/stream/rom_stream.c b/src/stream/rom_stream.c
new file mode 100644
index 0000000..20b7686
--- /dev/null
+++ b/src/stream/rom_stream.c
@@ -0,0 +1,58 @@
+#include <console/console.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stream/read_bytes.h>
+#include <string.h>
+
+
+#ifndef CONFIG_ROM_STREAM_START
+#define CONFIG_ROM_STREAM_START 0xffff0000UL
+#endif
+
+static const unsigned char *rom_start = (void *)CONFIG_ROM_STREAM_START;
+static const unsigned char *rom_end   = (void *)(CONFIG_ROM_STREAM_START + PAYLOAD_SIZE - 1);
+static const unsigned char *rom;
+
+int stream_init(void)
+{
+	rom = rom_start;
+
+	printk_spew("%6d:%s() - rom_stream: 0x%08lx - 0x%08lx\n"
+		__LINE__, __FUNCTION__,
+		(unsigned long)rom_start,
+		(unsigned long)rom_end);
+	return 0;
+}
+
+
+void stream_fini(void)
+{
+	return;
+}
+
+byte_offset_t stream_skip(byte_offset_t count)
+{
+	byte_offset_t bytes;
+	bytes = count;
+	if ((rom + bytes) > rom_end) {
+		printk_warning("%6d:%s() - overflowed source buffer\n",
+			__LINE__, __FUNCTION__);
+		bytes = 0;
+		if (rom <= rom_end) {
+			bytes = (rom_end - rom) + 1;
+		}
+	}
+	rom += bytes;
+	return bytes;
+}
+
+byte_offset_t stream_read(void *vdest, byte_offset_t count)
+{
+	unsigned char *dest = vdest;
+	const unsigned char *src = rom;
+	byte_offset_t bytes;
+
+	bytes = stream_skip(count);
+	memcpy(dest, src, bytes);
+	return bytes;
+}