- 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);
+}
+