summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEric Biederman <ebiederm@xmission.com>2003-04-22 19:02:15 +0000
committerEric Biederman <ebiederm@xmission.com>2003-04-22 19:02:15 +0000
commit8ca8d7665d671e10d72b8fcb4d69121d75f7906e (patch)
treedaad2699b4e6b6014bce5a76e82dd9c974801777 /src
parentb138ac83b53da9abf3dc9a87a1cd4b3d3a8150bd (diff)
- Initial checkin of the freebios2 tree
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@784 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'src')
-rw-r--r--src/arch/i386/boot/boot.c182
-rw-r--r--src/arch/i386/boot/linuxbios_table.c281
-rw-r--r--src/arch/i386/boot/linuxbios_table.h33
-rw-r--r--src/arch/i386/boot/pirq_routing.c93
-rw-r--r--src/arch/i386/boot/tables.c69
-rw-r--r--src/arch/i386/include/arch/asm.h30
-rw-r--r--src/arch/i386/include/arch/boot/boot.h8
-rw-r--r--src/arch/i386/include/arch/intel.h369
-rw-r--r--src/arch/i386/include/arch/io.h76
-rw-r--r--src/arch/i386/include/arch/pciconf.h9
-rw-r--r--src/arch/i386/include/arch/pirq_routing.h54
-rw-r--r--src/arch/i386/include/arch/rom_segs.h10
-rw-r--r--src/arch/i386/include/arch/romcc_io.h84
-rw-r--r--src/arch/i386/include/arch/smp/mpspec.h282
-rw-r--r--src/arch/i386/include/bitops.h20
-rw-r--r--src/arch/i386/include/stddef.h15
-rw-r--r--src/arch/i386/include/stdint.h52
-rw-r--r--src/arch/i386/lib/c_start.S135
-rw-r--r--src/arch/i386/lib/console.c119
-rw-r--r--src/arch/i386/lib/console.inc527
-rw-r--r--src/arch/i386/lib/cpu.c139
-rw-r--r--src/arch/i386/lib/cpu_reset.inc9
-rw-r--r--src/arch/i386/lib/failover.lds1
-rw-r--r--src/arch/i386/lib/id.inc21
-rw-r--r--src/arch/i386/lib/id.lds6
-rw-r--r--src/arch/i386/lib/noop_failover.inc9
-rw-r--r--src/arch/i386/lib/pci_ops.c281
-rw-r--r--src/arch/i386/smp/mpspec.c245
-rw-r--r--src/boot/elfboot.c663
-rw-r--r--src/boot/hardwaremain.c216
-rwxr-xr-xsrc/config/LinuxBIOSDoc.config691
-rwxr-xr-xsrc/config/doxyscript.base691
-rw-r--r--src/config/linuxbios_c.ld112
-rw-r--r--src/console/console.c75
-rw-r--r--src/console/logbuf_console.c19
-rw-r--r--src/console/printk.c56
-rw-r--r--src/console/uart8250_console.c49
-rw-r--r--src/console/vga_console.c100
-rw-r--r--src/console/vsprintf.c352
-rw-r--r--src/cpu/i386/entry16.inc112
-rw-r--r--src/cpu/i386/entry16.lds2
-rw-r--r--src/cpu/i386/entry32.inc55
-rw-r--r--src/cpu/i386/entry32.lds14
-rw-r--r--src/cpu/i386/reset16.inc27
-rw-r--r--src/cpu/i386/reset16.lds14
-rw-r--r--src/cpu/i386/reset32.inc10
-rw-r--r--src/cpu/i386/reset32.lds14
-rw-r--r--src/cpu/k8/cpufixup.c59
-rw-r--r--src/cpu/k8/earlymtrr.inc99
-rw-r--r--src/cpu/p5/cpuid.c222
-rw-r--r--src/cpu/p6/mtrr.c356
-rw-r--r--src/devices/device.c423
-rw-r--r--src/devices/device_util.c56
-rw-r--r--src/devices/pci_device.c670
-rw-r--r--src/include/boot/elf.h401
-rw-r--r--src/include/boot/elf_boot.h89
-rw-r--r--src/include/boot/linuxbios_tables.h183
-rw-r--r--src/include/boot/tables.h9
-rw-r--r--src/include/console/console.h76
-rw-r--r--src/include/console/loglevel.h30
-rw-r--r--src/include/cpu/cpu.h11
-rw-r--r--src/include/cpu/cpufixup.h24
-rw-r--r--src/include/cpu/k7/cpufixup.h6
-rw-r--r--src/include/cpu/k7/mtrr.h42
-rw-r--r--src/include/cpu/k8/cpufixup.h6
-rw-r--r--src/include/cpu/k8/mtrr.h45
-rw-r--r--src/include/cpu/p5/cpuid.h25
-rw-r--r--src/include/cpu/p6/apic.h175
-rw-r--r--src/include/cpu/p6/cpufixup.h6
-rw-r--r--src/include/cpu/p6/msr.h33
-rw-r--r--src/include/cpu/p6/mtrr.h44
-rw-r--r--src/include/delay.h8
-rw-r--r--src/include/ip_checksum.h7
-rw-r--r--src/include/mem.h13
-rw-r--r--src/include/part/fallback_boot.h16
-rw-r--r--src/include/part/sizeram.h7
-rw-r--r--src/include/pc80/mc146818rtc.h110
-rw-r--r--src/include/smp/atomic.h53
-rw-r--r--src/include/smp/spinlock.h24
-rw-r--r--src/include/smp/start_stop.h17
-rw-r--r--src/include/stdlib.h14
-rw-r--r--src/include/stream/read_bytes.h13
-rw-r--r--src/include/string.h36
-rw-r--r--src/include/uart8250.h7
-rw-r--r--src/include/version.h22
-rw-r--r--src/lib/clog2.c18
-rw-r--r--src/lib/compute_ip_checksum.c53
-rw-r--r--src/lib/delay.c15
-rw-r--r--src/lib/fallback_boot.c25
-rw-r--r--src/lib/malloc.c52
-rw-r--r--src/lib/memcmp.c17
-rw-r--r--src/lib/memcpy.c11
-rw-r--r--src/lib/memset.c12
-rw-r--r--src/lib/uart8250.c64
-rw-r--r--src/lib/version.c62
-rw-r--r--src/mainboard/amd/solo/auto.c1070
-rw-r--r--src/mainboard/amd/solo/cmos.layout74
-rw-r--r--src/mainboard/amd/solo/mainboard.c25
-rw-r--r--src/northbridge/amd/amdk8/northbridge.c22
-rw-r--r--src/pc80/mc146818rtc.c249
-rw-r--r--src/pc80/serial.c93
-rw-r--r--src/pc80/serial.inc106
-rw-r--r--src/ram/ramtest.c89
-rw-r--r--src/sdram/generic_dump_spd.c25
-rw-r--r--src/sdram/generic_sdram.c35
-rw-r--r--src/stream/rom_stream.c58
106 files changed, 12043 insertions, 0 deletions
diff --git a/src/arch/i386/boot/boot.c b/src/arch/i386/boot/boot.c
new file mode 100644
index 0000000000..84c71da800
--- /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 0000000000..1925f2ddb5
--- /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 0000000000..42c0a07dac
--- /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 0000000000..a7325c42ac
--- /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 0000000000..07579fefe2
--- /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 0000000000..ea63e2d4eb
--- /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 0000000000..3ff51c3082
--- /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 0000000000..df6604e08e
--- /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 0000000000..bcba9a932c
--- /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 0000000000..8695ee2294
--- /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 0000000000..215c4e58c8
--- /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 0000000000..b51a805948
--- /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 0000000000..02cc272884
--- /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 0000000000..305276e482
--- /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 0000000000..fae2045b9a
--- /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 0000000000..4bf6b0a867
--- /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 0000000000..58d7519cde
--- /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 0000000000..f5ca3388f8
--- /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 0000000000..8c8eccdd2a
--- /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 0000000000..3d6b01b3a2
--- /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 0000000000..3e27e7acdc
--- /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 0000000000..c7c05e2198
--- /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 0000000000..c9cf7298f8
--- /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 0000000000..f28e23a2e8
--- /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 0000000000..ccdf7008f7
--- /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 0000000000..70c10b0d3e
--- /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 0000000000..80921bf9da
--- /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 0000000000..3bb5fa1985
--- /dev/null
+++ b/src/arch/i386/smp/mpspec.c
@@ -0,0 +1,245 @@
+#include <console/console.h>
+#include <cpu/cpu.h>
+#include <smp/start_stop.h>
+#include <arch/smp/mpspec.h>
+#include <string.h>
+#include <cpu/p5/cpuid.h>
+#include <cpu/p6/apic.h>
+
+unsigned char smp_compute_checksum(void *v, int len)
+{
+ unsigned char *bytes;
+ unsigned char checksum;
+ int i;
+ bytes = v;
+ checksum = 0;
+ for(i = 0; i < len; i++) {
+ checksum -= bytes[i];
+ }
+ return checksum;
+}
+
+void *smp_write_floating_table(unsigned long addr)
+{
+ struct intel_mp_floating *mf;
+ void *v;
+
+ /* 16 byte align the table address */
+ addr += 15;
+ addr &= ~15;
+ v = (void *)addr;
+
+ mf = v;
+ mf->mpf_signature[0] = '_';
+ mf->mpf_signature[1] = 'M';
+ mf->mpf_signature[2] = 'P';
+ mf->mpf_signature[3] = '_';
+ mf->mpf_physptr = (unsigned long)(((char *)v) + SMP_FLOATING_TABLE_LEN);
+ mf->mpf_length = 1;
+ mf->mpf_specification = 4;
+ mf->mpf_checksum = 0;
+ mf->mpf_feature1 = 0;
+ mf->mpf_feature2 = 0;
+ mf->mpf_feature3 = 0;
+ mf->mpf_feature4 = 0;
+ mf->mpf_feature5 = 0;
+ mf->mpf_checksum = smp_compute_checksum(mf, mf->mpf_length*16);
+ return v;
+}
+
+void *smp_next_mpc_entry(struct mp_config_table *mc)
+{
+ void *v;
+ v = (void *)(((char *)mc) + mc->mpc_length);
+ return v;
+}
+static void smp_add_mpc_entry(struct mp_config_table *mc, unsigned length)
+{
+ mc->mpc_length += length;
+ mc->mpc_entry_count++;
+}
+
+void *smp_next_mpe_entry(struct mp_config_table *mc)
+{
+ void *v;
+ v = (void *)(((char *)mc) + mc->mpc_length + mc->mpe_length);
+ return v;
+}
+static void smp_add_mpe_entry(struct mp_config_table *mc, mpe_t mpe)
+{
+ mc->mpe_length += mpe->mpe_length;
+}
+
+void smp_write_processor(struct mp_config_table *mc,
+ unsigned char apicid, unsigned char apicver,
+ unsigned char cpuflag, unsigned int cpufeature,
+ unsigned int featureflag)
+{
+ struct mpc_config_processor *mpc;
+ mpc = smp_next_mpc_entry(mc);
+ memset(mpc, '\0', sizeof(*mpc));
+ mpc->mpc_type = MP_PROCESSOR;
+ mpc->mpc_apicid = apicid;
+ mpc->mpc_apicver = apicver;
+ mpc->mpc_cpuflag = cpuflag;
+ mpc->mpc_cpufeature = cpufeature;
+ mpc->mpc_featureflag = featureflag;
+ smp_add_mpc_entry(mc, sizeof(*mpc));
+}
+
+/* If we assume a symmetric processor configuration we can
+ * get all of the information we need to write the processor
+ * entry from the bootstrap processor.
+ * Plus I don't think linux really even cares.
+ * Having the proper apicid's in the table so the non-bootstrap
+ * processors can be woken up should be enough.
+ */
+void smp_write_processors(struct mp_config_table *mc,
+ unsigned long *processor_map)
+{
+ int i;
+ int processor_id;
+ unsigned apic_version;
+ unsigned cpu_features;
+ unsigned cpu_feature_flags;
+ int eax, ebx, ecx, edx;
+ processor_id = this_processors_id();
+ apic_version = apic_read(APIC_LVR) & 0xff;
+ cpuid(1, &eax, &ebx, &ecx, &edx);
+ cpu_features = eax;
+ cpu_feature_flags = edx;
+ for(i = 0; i < MAX_CPUS; i++) {
+ unsigned long cpu_apicid = initial_apicid[i];
+ unsigned long cpu_flag;
+ if(initial_apicid[i]==-1)
+ continue;
+ cpu_flag = MPC_CPU_ENABLED
+ if (processor_map[i] & CPU_BOOTPROCESSOR) {
+ cpu_flag |= MPC_CPU_BOOTPROCESSOR;
+ }
+ smp_write_processor(mc, cpu_apicid, apic_version,
+ cpu_flag, cpu_features, cpu_feature_flags
+ );
+
+ }
+}
+
+void smp_write_bus(struct mp_config_table *mc,
+ unsigned char id, unsigned char *bustype)
+{
+ struct mpc_config_bus *mpc;
+ mpc = smp_next_mpc_entry(mc);
+ memset(mpc, '\0', sizeof(*mpc));
+ mpc->mpc_type = MP_BUS;
+ mpc->mpc_busid = id;
+ memcpy(mpc->mpc_bustype, bustype, sizeof(mpc->mpc_bustype));
+ smp_add_mpc_entry(mc, sizeof(*mpc));
+}
+
+void smp_write_ioapic(struct mp_config_table *mc,
+ unsigned char id, unsigned char ver,
+ unsigned long apicaddr)
+{
+ struct mpc_config_ioapic *mpc;
+ mpc = smp_next_mpc_entry(mc);
+ memset(mpc, '\0', sizeof(*mpc));
+ mpc->mpc_type = MP_IOAPIC;
+ mpc->mpc_apicid = id;
+ mpc->mpc_apicver = ver;
+ mpc->mpc_flags = MPC_APIC_USABLE;
+ mpc->mpc_apicaddr = apicaddr;
+ smp_add_mpc_entry(mc, sizeof(*mpc));
+}
+
+void smp_write_intsrc(struct mp_config_table *mc,
+ unsigned char irqtype, unsigned short irqflag,
+ unsigned char srcbus, unsigned char srcbusirq,
+ unsigned char dstapic, unsigned char dstirq)
+{
+ struct mpc_config_intsrc *mpc;
+ mpc = smp_next_mpc_entry(mc);
+ memset(mpc, '\0', sizeof(*mpc));
+ mpc->mpc_type = MP_INTSRC;
+ mpc->mpc_irqtype = irqtype;
+ mpc->mpc_irqflag = irqflag;
+ mpc->mpc_srcbus = srcbus;
+ mpc->mpc_srcbusirq = srcbusirq;
+ mpc->mpc_dstapic = dstapic;
+ mpc->mpc_dstirq = dstirq;
+ smp_add_mpc_entry(mc, sizeof(*mpc));
+#if CONFIG_DEBUG_MPTABLE == 1
+ printk_info("add intsrc srcbus 0x%x srcbusirq 0x%x, dstapic 0x%x, dstirq 0x%x\n",
+ srcbus, srcbusirq, dstapic, dstirq);
+ hexdump(__FUNCTION__, mpc, sizeof(*mpc));
+#endif
+}
+
+
+void smp_write_lintsrc(struct mp_config_table *mc,
+ unsigned char irqtype, unsigned short irqflag,
+ unsigned char srcbusid, unsigned char srcbusirq,
+ unsigned char destapic, unsigned char destapiclint)
+{
+ struct mpc_config_lintsrc *mpc;
+ mpc = smp_next_mpc_entry(mc);
+ memset(mpc, '\0', sizeof(*mpc));
+ mpc->mpc_type = MP_LINTSRC;
+ mpc->mpc_irqtype = irqtype;
+ mpc->mpc_irqflag = irqflag;
+ mpc->mpc_srcbusid = srcbusid;
+ mpc->mpc_srcbusirq = srcbusirq;
+ mpc->mpc_destapic = destapic;
+ mpc->mpc_destapiclint = destapiclint;
+ smp_add_mpc_entry(mc, sizeof(*mpc));
+}
+
+void smp_write_address_space(struct mp_config_table *mc,
+ unsigned char busid, unsigned char address_type,
+ unsigned int address_base_low, unsigned int address_base_high,
+ unsigned int address_length_low, unsigned int address_length_high)
+{
+ struct mp_exten_system_address_space *mpe;
+ mpe = smp_next_mpe_entry(mc);
+ memset(mpe, '\0', sizeof(*mpe));
+ mpe->mpe_type = MPE_SYSTEM_ADDRESS_SPACE;
+ mpe->mpe_length = sizeof(*mpe);
+ mpe->mpe_busid = busid;
+ mpe->mpe_address_type = address_type;
+ mpe->mpe_address_base_low = address_base_low;
+ mpe->mpe_address_base_high = address_base_high;
+ mpe->mpe_address_length_low = address_length_low;
+ mpe->mpe_address_length_high = address_length_high;
+ smp_add_mpe_entry(mc, (mpe_t)mpe);
+}
+
+
+void smp_write_bus_hierarchy(struct mp_config_table *mc,
+ unsigned char busid, unsigned char bus_info,
+ unsigned char parent_busid)
+{
+ struct mp_exten_bus_hierarchy *mpe;
+ mpe = smp_next_mpe_entry(mc);
+ memset(mpe, '\0', sizeof(*mpe));
+ mpe->mpe_type = MPE_BUS_HIERARCHY;
+ mpe->mpe_length = sizeof(*mpe);
+ mpe->mpe_busid = busid;
+ mpe->mpe_bus_info = bus_info;
+ mpe->mpe_parent_busid = parent_busid;
+ smp_add_mpe_entry(mc, (mpe_t)mpe);
+}
+
+void smp_write_compatibility_address_space(struct mp_config_table *mc,
+ unsigned char busid, unsigned char address_modifier,
+ unsigned int range_list)
+{
+ struct mp_exten_compatibility_address_space *mpe;
+ mpe = smp_next_mpe_entry(mc);
+ memset(mpe, '\0', sizeof(*mpe));
+ mpe->mpe_type = MPE_COMPATIBILITY_ADDRESS_SPACE;
+ mpe->mpe_length = sizeof(*mpe);
+ mpe->mpe_busid = busid;
+ mpe->mpe_address_modifier = address_modifier;
+ mpe->mpe_range_list = range_list;
+ smp_add_mpe_entry(mc, (mpe_t)mpe);
+}
+
diff --git a/src/boot/elfboot.c b/src/boot/elfboot.c
new file mode 100644
index 0000000000..da0e909ced
--- /dev/null
+++ b/src/boot/elfboot.c
@@ -0,0 +1,663 @@
+#include <console/console.h>
+#include <part/fallback_boot.h>
+#include <boot/elf.h>
+#include <boot/elf_boot.h>
+#include <boot/linuxbios_tables.h>
+#include <ip_checksum.h>
+#include <stream/read_bytes.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Maximum physical address we can use for the linuxBIOS bounce buffer.
+ */
+#ifndef MAX_ADDR
+#define MAX_ADDR -1UL
+#endif
+
+extern unsigned char _ram_seg;
+extern unsigned char _eram_seg;
+
+struct segment {
+ struct segment *next;
+ struct segment *prev;
+ struct segment *phdr_next;
+ struct segment *phdr_prev;
+ unsigned long s_addr;
+ unsigned long s_memsz;
+ unsigned long s_offset;
+ unsigned long s_filesz;
+};
+
+struct verify_callback {
+ struct verify_callback *next;
+ int (*callback)(struct verify_callback *vcb,
+ Elf_ehdr *ehdr, Elf_phdr *phdr, struct segment *head);
+ unsigned long desc_offset;
+ unsigned long desc_addr;
+};
+
+struct ip_checksum_vcb {
+ struct verify_callback data;
+ unsigned short ip_checksum;
+};
+
+int verify_ip_checksum(
+ struct verify_callback *vcb,
+ Elf_ehdr *ehdr, Elf_phdr *phdr, struct segment *head)
+{
+ struct ip_checksum_vcb *cb;
+ struct segment *ptr;
+ unsigned long bytes;
+ unsigned long checksum;
+ unsigned char buff[2], *n_desc;
+ cb = (struct ip_checksum_vcb *)vcb;
+ /* zero the checksum so it's value won't
+ * get in the way of verifying the checksum.
+ */
+ n_desc = 0;
+ if (vcb->desc_addr) {
+ n_desc = (unsigned char *)(vcb->desc_addr);
+ memcpy(buff, n_desc, 2);
+ memset(n_desc, 0, 2);
+ }
+ bytes = 0;
+ checksum = compute_ip_checksum(ehdr, sizeof(*ehdr));
+ bytes += sizeof(*ehdr);
+ checksum = add_ip_checksums(bytes, checksum,
+ compute_ip_checksum(phdr, ehdr->e_phnum*sizeof(*phdr)));
+ bytes += ehdr->e_phnum*sizeof(*phdr);
+ for(ptr = head->phdr_next; ptr != head; ptr = ptr->phdr_next) {
+ checksum = add_ip_checksums(bytes, checksum,
+ compute_ip_checksum((void *)ptr->s_addr, ptr->s_memsz));
+ bytes += ptr->s_memsz;
+ }
+ if (n_desc != 0) {
+ memcpy(n_desc, buff, 2);
+ }
+ if (checksum != cb->ip_checksum) {
+ printk_err("Image checksum: %04x != computed checksum: %04x\n",
+ cb->ip_checksum, checksum);
+ }
+ return checksum == cb->ip_checksum;
+}
+
+/* The problem:
+ * Static executables all want to share the same addresses
+ * in memory because only a few addresses are reliably present on
+ * a machine, and implementing general relocation is hard.
+ *
+ * The solution:
+ * - Allocate a buffer twice the size of the linuxBIOS image.
+ * - Anything that would overwrite linuxBIOS copy into the lower half of
+ * the buffer.
+ * - After loading an ELF image copy linuxBIOS to the upper half of the
+ * buffer.
+ * - Then jump to the loaded image.
+ *
+ * Benefits:
+ * - Nearly arbitrary standalone executables can be loaded.
+ * - LinuxBIOS is preserved, so it can be returned to.
+ * - The implementation is still relatively simple,
+ * and much simpler then the general case implemented in kexec.
+ *
+ */
+
+static unsigned long get_bounce_buffer(struct lb_memory *mem)
+{
+ unsigned long lb_size;
+ unsigned long mem_entries;
+ unsigned long buffer;
+ int i;
+ lb_size = (unsigned long)(&_eram_seg - &_ram_seg);
+ /* Double linuxBIOS size so I have somewhere to place a copy to return to */
+ lb_size = lb_size + lb_size;
+ mem_entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
+ buffer = 0;
+ for(i = 0; i < mem_entries; i++) {
+ unsigned long mstart, mend;
+ unsigned long msize;
+ unsigned long tbuffer;
+ if (mem->map[i].type != LB_MEM_RAM)
+ continue;
+ if (mem->map[i].start > MAX_ADDR)
+ continue;
+ if (mem->map[i].size < lb_size)
+ continue;
+ mstart = mem->map[i].start;
+ msize = MAX_ADDR - mstart +1;
+ if (msize > mem->map[i].size)
+ msize = mem->map[i].size;
+ mend = mstart + msize;
+ tbuffer = mend - lb_size;
+ if (tbuffer < buffer)
+ continue;
+ buffer = tbuffer;
+ }
+ return buffer;
+}
+
+
+static struct verify_callback *process_elf_notes(
+ unsigned char *header,
+ unsigned long offset, unsigned long length)
+{
+ struct verify_callback *cb_chain;
+ unsigned char *note, *end;
+ char *program, *version;
+
+ cb_chain = 0;
+ note = header + offset;
+ end = note + length;
+ program = version = 0;
+ while(note < end) {
+ Elf_Nhdr *hdr;
+ unsigned char *n_name, *n_desc, *next;
+ hdr = (Elf_Nhdr *)note;
+ n_name = note + sizeof(*hdr);
+ n_desc = n_name + ((hdr->n_namesz + 3) & ~3);
+ next = n_desc + ((hdr->n_descsz + 3) & ~3);
+ if (next > end) {
+ break;
+ }
+ if ((hdr->n_namesz == sizeof(ELF_NOTE_BOOT)) &&
+ (memcmp(n_name, ELF_NOTE_BOOT, sizeof(ELF_NOTE_BOOT)) == 0)) {
+ switch(hdr->n_type) {
+ case EIN_PROGRAM_NAME:
+ if (n_desc[hdr->n_descsz -1] == 0) {
+ program = n_desc;
+ }
+ break;
+ case EIN_PROGRAM_VERSION:
+ if (n_desc[hdr->n_descsz -1] == 0) {
+ version = n_desc;
+ }
+ break;
+ case EIN_PROGRAM_CHECKSUM:
+ {
+ struct ip_checksum_vcb *cb;
+ cb = malloc(sizeof(*cb));
+ cb->ip_checksum = *((uint16_t *)n_desc);
+ cb->data.callback = verify_ip_checksum;
+ cb->data.next = cb_chain;
+ cb->data.desc_offset = n_desc - header;
+ cb_chain = &cb->data;
+ break;
+ }
+ }
+ }
+ printk_spew("n_type: %08x n_name(%d): %-*.*s n_desc(%d): %-*.*s\n",
+ hdr->n_type,
+ hdr->n_namesz, hdr->n_namesz, hdr->n_namesz, n_name,
+ hdr->n_descsz,hdr->n_descsz, hdr->n_descsz, n_desc);
+ note = next;
+ }
+ if (program && version) {
+ printk_info("Loading %s version: %s\n",
+ program, version);
+ }
+ return cb_chain;
+}
+
+static int valid_area(struct lb_memory *mem, unsigned long buffer,
+ unsigned long start, unsigned long len)
+{
+ /* Check through all of the memory segments and ensure
+ * the segment that was passed in is completely contained
+ * in RAM.
+ */
+ int i;
+ unsigned long end = start + len;
+ unsigned long mem_entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
+
+ /* See if I conflict with the bounce buffer */
+ if (end >= buffer) {
+ return 0;
+ }
+
+ /* Walk through the table of valid memory ranges and see if I
+ * have a match.
+ */
+ for(i = 0; i < mem_entries; i++) {
+ uint64_t mstart, mend;
+ uint32_t mtype;
+ mtype = mem->map[i].type;
+ mstart = mem->map[i].start;
+ mend = mstart + mem->map[i].size;
+ if ((mtype == LB_MEM_RAM) && (start < mend) && (end > mstart)) {
+ break;
+ }
+ }
+ if (i == mem_entries) {
+ printk_err("No matching ram area found for range:\n");
+ printk_err(" [0x%016lx, 0x%016lx)\n", start, end);
+ printk_err("Ram areas\n");
+ for(i = 0; i < mem_entries; i++) {
+ uint64_t mstart, mend;
+ uint32_t mtype;
+ mtype = mem->map[i].type;
+ mstart = mem->map[i].start;
+ mend = mstart + mem->map[i].size;
+ printk_err(" [0x%016lx, 0x%016lx) %s\n",
+ (unsigned long)mstart,
+ (unsigned long)mend,
+ (mtype == LB_MEM_RAM)?"RAM":"Reserved");
+
+ }
+ return 0;
+ }
+ return 1;
+}
+
+static void relocate_segment(unsigned long buffer, struct segment *seg)
+{
+ /* Modify all segments that want to load onto linuxBIOS
+ * to load onto the bounce buffer instead.
+ */
+ unsigned long lb_start = (unsigned long)&_ram_seg;
+ unsigned long lb_end = (unsigned long)&_eram_seg;
+ unsigned long start, middle, end;
+
+ printk_spew("lb: [0x%016lx, 0x%016lx)\n",
+ lb_start, lb_end);
+
+ start = seg->s_addr;
+ middle = start + seg->s_filesz;
+ end = start + seg->s_memsz;
+ /* I don't conflict with linuxBIOS so get out of here */
+ if ((end <= lb_start) || (start >= lb_end))
+ return;
+
+ printk_spew("segment: [0x%016lx, 0x%016lx, 0x%016lx)\n",
+ start, middle, end);
+
+ /* Slice off a piece at the beginning
+ * that doesn't conflict with linuxBIOS.
+ */
+ if (start < lb_start) {
+ struct segment *new;
+ unsigned long len = lb_start - start;
+ new = malloc(sizeof(*new));
+ *new = *seg;
+ new->s_memsz = len;
+ seg->s_memsz -= len;
+ seg->s_addr += len;
+ seg->s_offset += len;
+ if (seg->s_filesz > len) {
+ new->s_filesz = len;
+ seg->s_filesz -= len;
+ } else {
+ seg->s_filesz = 0;
+ }
+
+ /* Order by stream offset */
+ new->next = seg;
+ new->prev = seg->prev;
+ seg->prev->next = new;
+ seg->prev = new;
+ /* Order by original program header order */
+ new->phdr_next = seg;
+ new->phdr_prev = seg->phdr_prev;
+ seg->phdr_prev->phdr_next = new;
+ seg->phdr_prev = new;
+
+ /* compute the new value of start */
+ start = seg->s_addr;
+
+ printk_spew(" early: [0x%016lx, 0x%016lx, 0x%016lx)\n",
+ new->s_addr,
+ new->s_addr + new->s_filesz,
+ new->s_addr + new->s_memsz);
+ }
+
+ /* Slice off a piece at the end
+ * that doesn't conflict with linuxBIOS
+ */
+ if (end > lb_end) {
+ unsigned long len = lb_end - start;
+ struct segment *new;
+ new = malloc(sizeof(*new));
+ *new = *seg;
+ seg->s_memsz = len;
+ new->s_memsz -= len;
+ new->s_addr += len;
+ new->s_offset += len;
+ if (seg->s_filesz > len) {
+ seg->s_filesz = len;
+ new->s_filesz -= len;
+ } else {
+ new->s_filesz = 0;
+ }
+ /* Order by stream offset */
+ new->next = seg->next;
+ new->prev = seg;
+ seg->next->prev = new;
+ seg->next = new;
+ /* Order by original program header order */
+ new->phdr_next = seg->phdr_next;
+ new->phdr_prev = seg;
+ seg->phdr_next->phdr_prev = new;
+ seg->phdr_next = new;
+
+ /* compute the new value of end */
+ end = start + len;
+
+ printk_spew(" late: [0x%016lx, 0x%016lx, 0x%016lx)\n",
+ new->s_addr,
+ new->s_addr + new->s_filesz,
+ new->s_addr + new->s_memsz);
+
+ }
+ /* Now retarget this segment onto the bounce buffer */
+ seg->s_addr = buffer + (seg->s_addr - lb_start);
+
+ printk_spew(" bounce: [0x%016lx, 0x%016lx, 0x%016lx)\n",
+ seg->s_addr,
+ seg->s_addr + seg->s_filesz,
+ seg->s_addr + seg->s_memsz);
+}
+
+
+static int build_elf_segment_list(
+ struct segment *head,
+ unsigned long bounce_buffer, struct lb_memory *mem,
+ Elf_phdr *phdr, int headers)
+{
+ struct segment *ptr;
+ int i;
+ memset(head, 0, sizeof(*head));
+ head->next = head->prev = head;
+ for(i = 0; i < headers; i++) {
+ struct segment *new;
+ /* Ignore data that I don't need to handle */
+ if (phdr[i].p_type != PT_LOAD) {
+ printk_debug("Dropping non PT_LOAD segment\n");
+ continue;
+ }
+ if (phdr[i].p_memsz == 0) {
+ printk_debug("Dropping empty segment\n");
+ continue;
+ }
+ new = malloc(sizeof(*new));
+ new->s_addr = phdr[i].p_paddr;
+ new->s_memsz = phdr[i].p_memsz;
+ new->s_offset = phdr[i].p_offset;
+ new->s_filesz = phdr[i].p_filesz;
+ printk_debug("New segment addr 0x%lx size 0x%lx offset 0x%lx filesize 0x%lx\n",
+ new->s_addr, new->s_memsz, new->s_offset, new->s_filesz);
+ /* Clean up the values */
+ if (new->s_filesz > new->s_memsz) {
+ new->s_filesz = new->s_memsz;
+ }
+ printk_debug("(cleaned up) New segment addr 0x%lx size 0x%lx offset 0x%lx filesize 0x%lx\n",
+ new->s_addr, new->s_memsz, new->s_offset, new->s_filesz);
+ for(ptr = head->next; ptr != head; ptr = ptr->next) {
+ if (new->s_offset < ptr->s_offset)
+ break;
+ }
+ /* Order by stream offset */
+ new->next = ptr;
+ new->prev = ptr->prev;
+ ptr->prev->next = new;
+ ptr->prev = new;
+ /* Order by original program header order */
+ new->phdr_next = head;
+ new->phdr_prev = head->phdr_prev;
+ head->phdr_prev->phdr_next = new;
+ head->phdr_prev = new;
+
+ /* Verify the memory addresses in the segment are valid */
+ if (!valid_area(mem, bounce_buffer, new->s_addr, new->s_memsz))
+ goto out;
+
+ /* Modify the segment to load onto the bounce_buffer if necessary.
+ */
+ relocate_segment(bounce_buffer, new);
+ }
+ return 1;
+ out:
+ return 0;
+}
+
+static int load_elf_segments(
+ struct segment *head, unsigned char *header, unsigned long header_size)
+{
+ unsigned long offset;
+ struct segment *ptr;
+
+ offset = 0;
+ for(ptr = head->next; ptr != head; ptr = ptr->next) {
+ unsigned long start_offset;
+ unsigned long skip_bytes, read_bytes;
+ unsigned char *dest, *middle, *end;
+ byte_offset_t result;
+ printk_debug("Loading Segment: addr: 0x%016lx memsz: 0x%016lx filesz: 0x%016lx\n",
+ ptr->s_addr, ptr->s_memsz, ptr->s_filesz);
+
+ /* Compute the boundaries of the segment */
+ dest = (unsigned char *)(ptr->s_addr);
+ end = dest + ptr->s_memsz;
+ middle = dest + ptr->s_filesz;
+ start_offset = ptr->s_offset;
+
+ printk_spew("[ 0x%016lx, %016lx, 0x%016lx) <- %016lx\n",
+ (unsigned long)dest,
+ (unsigned long)middle,
+ (unsigned long)end,
+ (unsigned long)start_offset);
+
+ /* Skip intial buffer unused bytes */
+ if (offset < header_size) {
+ if (start_offset < header_size) {
+ offset = start_offset;
+ } else {
+ offset = header_size;
+ }
+ }
+
+ /* Skip the unused bytes */
+ skip_bytes = start_offset - offset;
+ if (skip_bytes &&
+ ((result = stream_skip(skip_bytes)) != skip_bytes)) {
+ printk_err("ERROR: Skip of %ld bytes skiped %ld bytes\n",
+ skip_bytes, result);
+ goto out;
+ }
+ offset = start_offset;
+
+ /* Copy data from the initial buffer */
+ if (offset < header_size) {
+ size_t len;
+ if ((ptr->s_filesz + start_offset) > header_size) {
+ len = header_size - start_offset;
+ }
+ else {
+ len = ptr->s_filesz;
+ }
+ memcpy(dest, &header[start_offset], len);
+ dest += len;
+ }
+
+ /* Read the segment into memory */
+ read_bytes = middle - dest;
+ if (read_bytes &&
+ ((result = stream_read(dest, read_bytes)) != read_bytes)) {
+ printk_err("ERROR: Read of %ld bytes read %ld bytes...\n",
+ read_bytes, result);
+ goto out;
+ }
+ offset += ptr->s_filesz;
+
+ /* Zero the extra bytes between middle & end */
+ if (middle < end) {
+ printk_debug("Clearing Segment: addr: 0x%016lx memsz: 0x%016lx\n",
+ (unsigned long)middle, end - middle);
+
+ /* Zero the extra bytes */
+ memset(middle, 0, end - middle);
+ }
+ }
+ return 1;
+ out:
+ return 0;
+}
+
+static int verify_loaded_image(
+ struct verify_callback *vcb,
+ Elf_ehdr *ehdr, Elf_phdr *phdr,
+ struct segment *head
+ )
+{
+ struct segment *ptr;
+ int ok;
+ ok = 1;
+ for(; ok && vcb ; vcb = vcb->next) {
+ /* Find where the note is loaded */
+ /* The whole note must be loaded intact
+ * so an address of 0 for the descriptor is impossible
+ */
+ vcb->desc_addr = 0;
+ for(ptr = head->next; ptr != head; ptr = ptr->next) {
+ unsigned long desc_addr;
+ desc_addr = ptr->s_addr + vcb->desc_offset - ptr->s_offset;
+ if ((desc_addr >= ptr->s_addr) &&
+ (desc_addr < (ptr->s_addr + ptr->s_filesz))) {
+ vcb->desc_addr = desc_addr;
+ }
+ }
+ ok = vcb->callback(vcb, ehdr, phdr, head);
+ }
+ return ok;
+}
+
+int elfload(struct lb_memory *mem,
+ unsigned char *header, unsigned long header_size)
+{
+ Elf_ehdr *ehdr;
+ Elf_phdr *phdr;
+ void *entry;
+ struct segment head;
+ struct verify_callback *cb_chain;
+ unsigned long bounce_buffer;
+
+ /* Find a bounce buffer so I can load to linuxBIOS's current location */
+ bounce_buffer = get_bounce_buffer(mem);
+ if (!bounce_buffer) {
+ printk_err("Could not find a bounce buffer...\n");
+ goto out;
+ }
+
+ ehdr = (Elf_ehdr *)header;
+ entry = (void *)(ehdr->e_entry);
+ phdr = (Elf_phdr *)(&header[ehdr->e_phoff]);
+
+ /* Digest elf note information... */
+ cb_chain = 0;
+ if ((phdr[0].p_type == PT_NOTE) &&
+ ((phdr[0].p_offset + phdr[0].p_filesz) < header_size)) {
+ cb_chain = process_elf_notes(header,
+ phdr[0].p_offset, phdr[0].p_filesz);
+ }
+
+ /* Preprocess the elf segments */
+ if (!build_elf_segment_list(&head,
+ bounce_buffer, mem, phdr, ehdr->e_phnum))
+ goto out;
+
+ /* Load the segments */
+ if (!load_elf_segments(&head, header, header_size))
+ goto out;
+
+ printk_spew("Loaded segments\n");
+ /* Verify the loaded image */
+ if (!verify_loaded_image(cb_chain, ehdr, phdr, &head))
+ goto out;
+
+ printk_spew("verified segments\n");
+ /* Shutdown the stream device */
+ stream_fini();
+
+ printk_spew("closed down stream\n");
+ /* Reset to booting from this image as late as possible */
+ boot_successful();
+
+ printk_debug("Jumping to boot code at 0x%x\n", entry);
+ post_code(0xfe);
+
+ /* Jump to kernel */
+ jmp_to_elf_entry(entry, bounce_buffer);
+ return 1;
+
+ out:
+ return 0;
+}
+
+int elfboot(struct lb_memory *mem)
+{
+ Elf_ehdr *ehdr;
+ static unsigned char header[ELF_HEAD_SIZE];
+ int header_offset;
+ int i, result;
+
+ result = 0;
+ printk_info("\n");
+ printk_info("Welcome to %s, the open sourced starter.\n", BOOTLOADER);
+ printk_info("January 2002, Eric Biederman.\n");
+ printk_info("Version %s\n", BOOTLOADER_VERSION);
+ printk_info("\n");
+ post_code(0xf8);
+
+ if (stream_init() < 0) {
+ printk_err("Could not initialize driver...\n");
+ goto out;
+ }
+
+ /* Read in the initial ELF_HEAD_SIZE bytes */
+ if (stream_read(header, ELF_HEAD_SIZE) != ELF_HEAD_SIZE) {
+ printk_err("Read failed...\n");
+ goto out;
+ }
+ /* Scan for an elf header */
+ header_offset = -1;
+ for(i = 0; i < ELF_HEAD_SIZE - (sizeof(Elf_ehdr) + sizeof(Elf_phdr)); i+=16) {
+ ehdr = (Elf_ehdr *)(&header[i]);
+ if (memcmp(ehdr->e_ident, ELFMAG, 4) != 0) {
+ printk_spew("NO header at %d\n", i);
+ continue;
+ }
+ printk_debug("Found ELF candiate at offset %d\n", i);
+ /* Sanity check the elf header */
+ if ((ehdr->e_type == ET_EXEC) &&
+ elf_check_arch(ehdr) &&
+ (ehdr->e_ident[EI_VERSION] == EV_CURRENT) &&
+ (ehdr->e_version == EV_CURRENT) &&
+ (ehdr->e_ehsize == sizeof(Elf_ehdr)) &&
+ (ehdr->e_phentsize = sizeof(Elf_phdr)) &&
+ (ehdr->e_phoff < (ELF_HEAD_SIZE - i)) &&
+ ((ehdr->e_phoff + (ehdr->e_phentsize * ehdr->e_phnum)) <=
+ (ELF_HEAD_SIZE - i))) {
+ header_offset = i;
+ break;
+ }
+ ehdr = 0;
+ }
+ printk_spew("header_offset is %d\n", header_offset);
+ if (header_offset == -1) {
+ goto out;
+ }
+
+ printk_spew("Try to load at offset 0x%x\n", header_offset);
+ result = elfload(mem,
+ header + header_offset , ELF_HEAD_SIZE - header_offset);
+ out:
+ if (!result) {
+ /* Shutdown the stream device */
+ stream_fini();
+
+ printk_err("Cannot Load ELF Image\n");
+
+ post_code(0xff);
+ }
+ return 0;
+
+}
diff --git a/src/boot/hardwaremain.c b/src/boot/hardwaremain.c
new file mode 100644
index 0000000000..3507f88f0a
--- /dev/null
+++ b/src/boot/hardwaremain.c
@@ -0,0 +1,216 @@
+/*
+This software and ancillary information (herein called SOFTWARE )
+called LinuxBIOS is made available under the terms described
+here. The SOFTWARE has been approved for release with associated
+LA-CC Number 00-34 . Unless otherwise indicated, this SOFTWARE has
+been authored by an employee or employees of the University of
+California, operator of the Los Alamos National Laboratory under
+Contract No. W-7405-ENG-36 with the U.S. Department of Energy. The
+U.S. Government has rights to use, reproduce, and distribute this
+SOFTWARE. The public may copy, distribute, prepare derivative works
+and publicly display this SOFTWARE without charge, provided that this
+Notice and any statement of authorship are reproduced on all copies.
+Neither the Government nor the University makes any warranty, express
+or implied, or assumes any liability or responsibility for the use of
+this SOFTWARE. If SOFTWARE is modified to produce derivative works,
+such modified SOFTWARE should be clearly marked, so as not to confuse
+it with the version available from LANL.
+ */
+/* Copyright 2000, Ron Minnich, Advanced Computing Lab, LANL
+ * rminnich@lanl.gov
+ */
+
+
+/*
+ * C Bootstrap code for the LinuxBIOS
+ */
+
+
+#include <console/console.h>
+#include <cpu/cpu.h>
+#include <mem.h>
+#include <version.h>
+#include <smp/start_stop.h>
+#include <boot/tables.h>
+#include <part/sizeram.h>
+#include <device.h>
+#include <pci.h>
+#if 0
+#include <part/mainboard.h>
+#endif
+#if 0
+#include <part/hard_reset.h>
+#endif
+#include <smp/atomic.h>
+#include <boot/elf.h>
+
+
+#ifndef CONFIG_MAX_PHYSICAL_CPUS
+#define CONFIG_MAX_PHYSICAL_CPUS CONFIG_MAX_CPUS
+#endif
+
+/* The processor map.
+ * Now that SMP is in linuxbios, and Linux counts on us
+ * giving accurate information about processors, we need a map
+ * of what processors are out there. This could be a bit mask,
+ * but we will be optimistic and hope we someday run on
+ * REALLY BIG SMPs. Also we may need more than one bit of
+ * info per processor at some point. I hope we don't need
+ * anything more complex than an int.
+ */
+static unsigned long processor_map[MAX_CPUS];
+
+static struct mem_range *get_ramsize(void)
+{
+ struct mem_range *mem = 0;
+ if (!mem) {
+ mem = sizeram();
+ }
+ if (!mem) {
+ printk_err("No memory size information!\n");
+ for(;;);
+ }
+ return mem;
+}
+
+
+#if SMP == 1
+/* Number of cpus that are currently running in linuxbios */
+static atomic_t active_cpus = ATOMIC_INIT(1);
+
+void secondary_cpu_init(void)
+{
+ struct mem_range *mem;
+ unsigned long id;
+ int index;
+
+ atomic_inc(&active_cpus);
+ printk_debug(__FUNCTION__ "\n");
+ mem = get_ramsize();
+ id = cpu_initialize(mem);
+ index = processor_index(id);
+ printk_debug(__FUNCTION__ " %d/%u\n", index, id);
+ processor_map[index] = CPU_ENABLED;
+ atomic_dec(&active_cpus);
+ stop_cpu(id);
+}
+
+static void wait_for_other_cpus(void)
+{
+ int old_active_count, active_count;
+ int i;
+ old_active_count = 1;
+
+ active_count = atomic_read(&active_cpus);
+ while(active_count > 1) {
+ if (active_count != old_active_count) {
+ printk_info("Waiting for %d CPUS to stop\n", active_count);
+ old_active_count = active_count;
+ }
+ active_count = atomic_read(&active_cpus);
+ }
+ for(i = 0; i < MAX_CPUS; i++) {
+ if (!(processor_map[i] & CPU_ENABLED)) {
+ printk_err("CPU %d/%u did not initialize!\n",
+ i, initial_apicid[i]);
+ processor_map[i] = 0;
+ mainboard_cpu_fixup(i);
+ }
+ }
+ printk_debug("All AP CPUs stopped\n");
+}
+
+#else /* SMP */
+#define wait_for_other_cpus() do {} while(0)
+#endif /* SMP */
+
+void hardwaremain(int boot_complete)
+{
+ /* Processor ID of the BOOT cpu (i.e. the one running this code) */
+ unsigned long boot_cpu;
+ int boot_index;
+
+ /* the order here is a bit tricky. We don't want to do much of
+ * anything that uses config registers until after PciAllocateResources
+ * since that function also figures out what kind of config strategy
+ * to use (type 1 or type 2).
+ * so we turn on cache, then worry about PCI setup, then do other
+ * things, so that the other work can use the PciRead* and PciWrite*
+ * functions.
+ */
+ struct mem_range *mem, *tmem;
+ struct lb_memory *lb_mem;
+ unsigned long totalmem;
+
+ post_code(0x80);
+ /* displayinit MUST PRECEDE ALL PRINTK! */
+ console_init();
+
+ post_code(0x39);
+ printk_notice("LinuxBIOS-%s%s %s %s...\n",
+ linuxbios_version, linuxbios_extra_version, linuxbios_build,
+ (boot_complete)?"rebooting":"booting");
+
+ post_code(0x40);
+
+#if 0
+ /* If we have already booted attempt a hard reboot */
+ if (boot_complete) {
+ hard_reset();
+ }
+#endif
+#if 1
+
+ // pick how to scan the bus. This is first so we can get at memory size.
+ printk_info("Finding PCI configuration type.\n");
+ pci_set_method();
+ post_code(0x5f);
+#if 0
+ enumerate_static_devices();
+#endif
+ dev_enumerate();
+ post_code(0x66);
+ // Now do the real bus
+ // we round the total ram up a lot for thing like the SISFB, which
+ // shares high memory with the CPU.
+ dev_configure();
+ post_code(0x88);
+
+ dev_enable();
+ dev_initialize();
+ post_code(0x89);
+#endif
+
+ mem = get_ramsize();
+ post_code(0x70);
+ totalmem = 0;
+ for(tmem = mem; tmem->sizek; tmem++) {
+ totalmem += tmem->sizek;
+ }
+ printk_info("totalram: %ldM\n",
+ (totalmem + 512) >> 10); /* Round to the nearest meg */
+
+ /* Fully initialize the cpu before configuring the bus */
+ boot_cpu = cpu_initialize(mem);
+ boot_index = processor_index(boot_cpu);
+ printk_spew("BOOT CPU is %d\n", boot_cpu);
+ processor_map[boot_index] = CPU_BOOTPROCESSOR|CPU_ENABLED;
+
+ /* Now start the other cpus initializing
+ * The sooner they start the sooner they stop.
+ */
+ post_code(0x75);
+ startup_other_cpus(processor_map);
+ post_code(0x77);
+
+ /* make certain we are the only cpu running in linuxBIOS */
+ wait_for_other_cpus();
+
+ /* Now that we have collected all of our information
+ * write our configuration tables.
+ */
+ lb_mem = write_tables(mem, processor_map);
+
+ elfboot(lb_mem);
+}
+
diff --git a/src/config/LinuxBIOSDoc.config b/src/config/LinuxBIOSDoc.config
new file mode 100755
index 0000000000..557b952ee5
--- /dev/null
+++ b/src/config/LinuxBIOSDoc.config
@@ -0,0 +1,691 @@
+# Doxyfile 1.2.1
+
+# This file describes the settings to be used by doxygen for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# General configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = "LinuxBIOS"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = .
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Dutch, French, Italian, Czech, Swedish, German, Finnish, Japanese,
+# Spanish, Russian, Croatian, Polish, and Portuguese.
+
+OUTPUT_LANGUAGE = English
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = YES
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these class will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. It is allowed to use relative paths in the argument list.
+
+STRIP_FROM_PATH =
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a class diagram (in Html and LaTeX) for classes with base or
+# super classes. Setting the tag to NO turns the diagrams off.
+
+CLASS_DIAGRAMS = YES
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the CASE_SENSE_NAMES tag is set to NO (the default) then Doxygen
+# will only generate file names in lower case letters. If set to
+# YES upper case letters are also allowed. This is useful if you have
+# classes or files whose names only differ in case and if your file system
+# supports case sensitive file names.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES (the default) then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the Javadoc-style will
+# behave just like the Qt-style comments.
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# reimplements.
+
+INHERIT_DOCS = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# The ENABLE_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+# INPUT = ../src
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+# FILE_PATTERNS = *.c *.h *.S
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+
+EXCLUDE_PATTERNS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+
+INPUT_FILTER =
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimised for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = YES
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using a WORD or other.
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assigments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = YES
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation. Warning: This feature
+# is still experimental and very incomplete.
+
+GENERATE_XML = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_PREDEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tagfiles.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, INCLUDE_GRAPH, and HAVE_DOT tags are set to
+# YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other
+# documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, INCLUDED_BY_GRAPH, and HAVE_DOT tags are set to
+# YES then doxygen will generate a graph for each documented header file showing
+# the documented files that directly or indirectly include this file
+
+INCLUDED_BY_GRAPH = YES
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found on the path.
+
+DOT_PATH =
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_WIDTH = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT = 1024
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
+
+# The CGI_NAME tag should be the name of the CGI script that
+# starts the search engine (doxysearch) with the correct parameters.
+# A script with this name will be generated by doxygen.
+
+CGI_NAME = search.cgi
+
+# The CGI_URL tag should be the absolute URL to the directory where the
+# cgi binaries are located. See the documentation of your http daemon for
+# details.
+
+CGI_URL =
+
+# The DOC_URL tag should be the absolute URL to the directory where the
+# documentation is located. If left blank the absolute path to the
+# documentation, with file:// prepended to it, will be used.
+
+DOC_URL =
+
+# The DOC_ABSPATH tag should be the absolute path to the directory where the
+# documentation is located. If left blank the directory on the local machine
+# will be used.
+
+DOC_ABSPATH =
+
+# The BIN_ABSPATH tag must point to the directory where the doxysearch binary
+# is installed.
+
+BIN_ABSPATH = /usr/local/bin/
+
+# The EXT_DOC_PATHS tag can be used to specify one or more paths to
+# documentation generated for other projects. This allows doxysearch to search
+# the documentation for these projects as well.
+
+EXT_DOC_PATHS =
diff --git a/src/config/doxyscript.base b/src/config/doxyscript.base
new file mode 100755
index 0000000000..557b952ee5
--- /dev/null
+++ b/src/config/doxyscript.base
@@ -0,0 +1,691 @@
+# Doxyfile 1.2.1
+
+# This file describes the settings to be used by doxygen for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# General configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = "LinuxBIOS"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = .
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Dutch, French, Italian, Czech, Swedish, German, Finnish, Japanese,
+# Spanish, Russian, Croatian, Polish, and Portuguese.
+
+OUTPUT_LANGUAGE = English
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = YES
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these class will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. It is allowed to use relative paths in the argument list.
+
+STRIP_FROM_PATH =
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a class diagram (in Html and LaTeX) for classes with base or
+# super classes. Setting the tag to NO turns the diagrams off.
+
+CLASS_DIAGRAMS = YES
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the CASE_SENSE_NAMES tag is set to NO (the default) then Doxygen
+# will only generate file names in lower case letters. If set to
+# YES upper case letters are also allowed. This is useful if you have
+# classes or files whose names only differ in case and if your file system
+# supports case sensitive file names.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES (the default) then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the Javadoc-style will
+# behave just like the Qt-style comments.
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# reimplements.
+
+INHERIT_DOCS = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# The ENABLE_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+# INPUT = ../src
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+# FILE_PATTERNS = *.c *.h *.S
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+
+EXCLUDE_PATTERNS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+
+INPUT_FILTER =
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimised for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = YES
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using a WORD or other.
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assigments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = YES
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation. Warning: This feature
+# is still experimental and very incomplete.
+
+GENERATE_XML = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_PREDEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tagfiles.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, INCLUDE_GRAPH, and HAVE_DOT tags are set to
+# YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other
+# documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, INCLUDED_BY_GRAPH, and HAVE_DOT tags are set to
+# YES then doxygen will generate a graph for each documented header file showing
+# the documented files that directly or indirectly include this file
+
+INCLUDED_BY_GRAPH = YES
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found on the path.
+
+DOT_PATH =
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_WIDTH = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT = 1024
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
+
+# The CGI_NAME tag should be the name of the CGI script that
+# starts the search engine (doxysearch) with the correct parameters.
+# A script with this name will be generated by doxygen.
+
+CGI_NAME = search.cgi
+
+# The CGI_URL tag should be the absolute URL to the directory where the
+# cgi binaries are located. See the documentation of your http daemon for
+# details.
+
+CGI_URL =
+
+# The DOC_URL tag should be the absolute URL to the directory where the
+# documentation is located. If left blank the absolute path to the
+# documentation, with file:// prepended to it, will be used.
+
+DOC_URL =
+
+# The DOC_ABSPATH tag should be the absolute path to the directory where the
+# documentation is located. If left blank the directory on the local machine
+# will be used.
+
+DOC_ABSPATH =
+
+# The BIN_ABSPATH tag must point to the directory where the doxysearch binary
+# is installed.
+
+BIN_ABSPATH = /usr/local/bin/
+
+# The EXT_DOC_PATHS tag can be used to specify one or more paths to
+# documentation generated for other projects. This allows doxysearch to search
+# the documentation for these projects as well.
+
+EXT_DOC_PATHS =
diff --git a/src/config/linuxbios_c.ld b/src/config/linuxbios_c.ld
new file mode 100644
index 0000000000..187a99a638
--- /dev/null
+++ b/src/config/linuxbios_c.ld
@@ -0,0 +1,112 @@
+/*
+ * Memory map:
+ *
+ * _RAMBASE
+ * : data segment
+ * : bss segment
+ * : heap
+ * : stack
+ */
+/*
+ * Bootstrap code for the STPC Consumer
+ * Copyright (c) 1999 by Net Insight AB. All Rights Reserved.
+ *
+ * $Id$
+ *
+ */
+
+/*
+ * Written by Johan Rydberg, based on work by Daniel Kahlin.
+ * Rewritten by Eric Biederman
+ */
+/*
+ * We use ELF as output format. So that we can
+ * debug the code in some form.
+ */
+INCLUDE ldoptions
+
+ENTRY(_start)
+
+SECTIONS
+{
+ . = _RAMBASE;
+ /*
+ * First we place the code and read only data (typically const declared).
+ * This get placed in rom.
+ */
+ .text : {
+ _text = .;
+ *(.text);
+ *(.text.*);
+ . = ALIGN(16);
+ _etext = .;
+ }
+ .rodata : {
+ _rodata = .;
+ . = ALIGN(4);
+ console_drivers = .;
+ *(.rodata.console_drivers)
+ econsole_drivers = . ;
+ . = ALIGN(4);
+ pci_drivers = . ;
+ *(.rodata.pci_drivers)
+ epci_drivers = . ;
+ *(.rodata)
+ *(.rodata.*)
+ /*
+ * kevinh/Ispiri - Added an align, because the objcopy tool
+ * incorrectly converts sections that are not long word aligned.
+ * This breaksthe linuxbios.strip target.
+ */
+ . = ALIGN(4);
+
+ _erodata = .;
+ }
+ /*
+ * After the code we place initialized data (typically initialized
+ * global variables). This gets copied into ram by startup code.
+ * __data_start and __data_end shows where in ram this should be placed,
+ * whereas __data_loadstart and __data_loadend shows where in rom to
+ * copy from.
+ */
+ .data : {
+ _data = .;
+ *(.data)
+ _edata = .;
+ }
+ /*
+ * bss does not contain data, it is just a space that should be zero
+ * initialized on startup. (typically uninitialized global variables)
+ * crt0.S fills between _bss and _ebss with zeroes.
+ */
+ _bss = .;
+ .bss . : {
+ *(.bss)
+ *(.sbss)
+ *(COMMON)
+ }
+ _ebss = .;
+ _end = .;
+ _stack = .;
+ .stack . : {
+ /* Reserve a stack for each possible cpu, +1 extra */
+ . = ((MAX_CPUS * STACK_SIZE) + STACK_SIZE) ;
+ }
+ _estack = .;
+ _heap = .;
+ .heap . : {
+ /* Reserve 256K for the heap */
+ . = HEAP_SIZE ;
+ . = ALIGN(4);
+ }
+ _eheap = .;
+ /* The ram segment
+ * This is all address of the memory resident copy of linuxBIOS.
+ */
+ _ram_seg = _text;
+ _eram_seg = _eheap;
+ /DISCARD/ : {
+ *(.comment)
+ *(.note)
+ }
+}
diff --git a/src/console/console.c b/src/console/console.c
new file mode 100644
index 0000000000..458fbb8fff
--- /dev/null
+++ b/src/console/console.c
@@ -0,0 +1,75 @@
+/*
+ * Bootstrap code for the INTEL
+ * $Id$
+ *
+ */
+
+#include <arch/io.h>
+#include <console/console.h>
+#include <string.h>
+#include <pc80/mc146818rtc.h>
+
+
+static int initialized;
+
+/* initialize the console */
+void console_init(void)
+{
+ struct console_driver *driver;
+ if(get_option(&console_loglevel, "debug_level"))
+ console_loglevel=DEFAULT_CONSOLE_LOGLEVEL;
+
+ for(driver = console_drivers; driver < econsole_drivers; driver++) {
+ if (!driver->init)
+ continue;
+ driver->init();
+ }
+ initialized = 1;
+}
+
+static void __console_tx_byte(unsigned char byte)
+{
+ struct console_driver *driver;
+ for(driver = console_drivers; driver < econsole_drivers; driver++) {
+ driver->tx_byte(byte);
+ }
+}
+
+void console_tx_flush(void)
+{
+ struct console_driver *driver;
+ for(driver = console_drivers; driver < econsole_drivers; driver++) {
+ if (!driver->tx_flush)
+ continue;
+ driver->tx_flush();
+ }
+}
+
+void console_tx_byte(unsigned char byte)
+{
+ if (!initialized)
+ return;
+ if (byte == '\n')
+ __console_tx_byte('\r');
+ __console_tx_byte(byte);
+}
+
+/*
+ * Write POST information
+ */
+void post_code(uint8_t value)
+{
+#ifdef CONFIG_SERIAL_POST
+ printk_info("POST: 0x%02x\n", value);
+#elsif !define(NO_POST)
+ outb(value, 0x80);
+#endif
+}
+
+/* Report a fatal error */
+void die(char *msg)
+{
+ printk_emerg("%s", msg);
+ post_code(0xff);
+ while (1); /* Halt */
+}
diff --git a/src/console/logbuf_console.c b/src/console/logbuf_console.c
new file mode 100644
index 0000000000..e605ae5c23
--- /dev/null
+++ b/src/console/logbuf_console.c
@@ -0,0 +1,19 @@
+#include <console/console.h>
+
+#define LOGBUF_SIZE 1024
+
+// KEEP THIS GLOBAL.
+// I need the address so I can watch it with the ARIUM hardware. RGM.
+char logbuf[LOGBUF_SIZE];
+int logbuf_offset = 0;
+
+static void logbuf_tx_byte(unsigned char byte)
+{
+ logbuf[logbuf_offset] = byte;
+ logbuf_offset = (logbuf_offset +1) % LOGBUF_SIZE;
+}
+
+static struct console_driver __console = {
+ .init = 0,
+ .tx_byte = logbuf_tx_byte,
+};}
diff --git a/src/console/printk.c b/src/console/printk.c
new file mode 100644
index 0000000000..67b0d4e19b
--- /dev/null
+++ b/src/console/printk.c
@@ -0,0 +1,56 @@
+/*
+ * blantantly copied from linux/kernel/printk.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id$";
+#endif
+
+//typedef void * va_list;
+
+#include <stdarg.h>
+#include <smp/spinlock.h>
+#include <console/console.h>
+
+/* printk's without a loglevel use this.. */
+#define DEFAULT_MESSAGE_LOGLEVEL 4 /* BIOS_WARNING */
+
+/* We show everything that is MORE important than this.. */
+#define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */
+
+/* Keep together for sysctl support */
+
+int console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
+int default_message_loglevel = DEFAULT_MESSAGE_LOGLEVEL;
+int minimum_console_loglevel = MINIMUM_CONSOLE_LOGLEVEL;
+int default_console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
+
+void display(char*);
+extern int vtxprintf(void (*)(unsigned char), const char *, va_list);
+
+spinlock_t console_lock = SPIN_LOCK_UNLOCKED;
+
+int do_printk(int msg_level, const char *fmt, ...)
+{
+ va_list args;
+ int i;
+
+ if (msg_level >= console_loglevel) {
+ return 0;
+ }
+
+ spin_lock(&console_lock);
+
+ va_start(args, fmt);
+ i = vtxprintf(console_tx_byte, fmt, args);
+ va_end(args);
+
+ console_tx_flush();
+
+ spin_unlock(&console_lock);
+
+ return i;
+}
diff --git a/src/console/uart8250_console.c b/src/console/uart8250_console.c
new file mode 100644
index 0000000000..6eeeb6aa55
--- /dev/null
+++ b/src/console/uart8250_console.c
@@ -0,0 +1,49 @@
+#include <console/console.h>
+#include <uart8250.h>
+#include <pc80/mc146818rtc.h>
+
+/* Base Address */
+#ifndef TTYS0_BASE
+#define TTYS0_BASE 0x3f8
+#endif
+
+#ifndef TTYS0_BAUD
+#define TTYS0_BAUD 115200
+#endif
+
+#if ((115200%TTYS0_BAUD) != 0)
+#error Bad ttys0 baud rate
+#endif
+
+#define TTYS0_DIV (115200/TTYS0_BAUD)
+
+/* Line Control Settings */
+#ifndef TTYS0_LCS
+/* Set 8bit, 1 stop bit, no parity */
+#define TTYS0_LCS 0x3
+#endif
+
+#define UART_LCS TTYS0_LCS
+
+void ttyS0_init(void)
+{
+ static unsigned char div[8]={1,2,3,6,12,24,48,96};
+ int b_index=0;
+ unsigned int divisor=TTYS0_DIV;
+
+ if(get_option(&b_index,"baud_rate")==0) {
+ divisor=div[b_index];
+ }
+ uart8250_init(TTYS0_BASE, divisor, TTYS0_LCS);
+}
+
+void ttyS0_tx_byte(unsigned char data)
+{
+ uart8250_tx_byte(TTYS0_BASE, data);
+}
+
+static struct console_driver uart8250_console __console = {
+ .init = ttyS0_init,
+ .tx_byte = ttyS0_tx_byte,
+};
+
diff --git a/src/console/vga_console.c b/src/console/vga_console.c
new file mode 100644
index 0000000000..ffd6699529
--- /dev/null
+++ b/src/console/vga_console.c
@@ -0,0 +1,100 @@
+/*
+ *
+ * modified from original freebios code
+ * by Steve M. Gehlbach <steve@kesa.com>
+ *
+ */
+
+#include <arch/io.h>
+#include <string.h>
+#include <pc80/vga.h>
+#include <console/console.h>
+
+void beep(int ms);
+
+static char *vidmem; /* The video buffer, should be replaced by symbol in ldscript.ld */
+int vga_line, vga_col;
+
+#define VIDBUFFER 0xB8000;
+
+static void memsetw(void *s, int c, unsigned int n)
+{
+ int i;
+ u16 *ss = (u16 *) s;
+
+ for (i = 0; i < n; i++) {
+ ss[i] = ( u16 ) c;
+ }
+}
+
+static void vga_init(void)
+{
+
+ // these are globals
+ vga_line = 0;
+ vga_col = 0;
+ vidmem = (unsigned char *) VIDBUFFER;
+
+ // mainboard or chip specific init routines
+ // also loads font
+ vga_hardware_fixup();
+
+ // set attributes, char for entire screen
+ // font should be previously loaded in
+ // device specific code (vga_hardware_fixup)
+ memsetw(vidmem, VGA_ATTR_CLR_WHT, 2*1024); //
+}
+
+static void vga_scroll(void)
+{
+ int i;
+
+ memcpy(vidmem, vidmem + COLS * 2, (LINES - 1) * COLS * 2);
+ for (i = (LINES - 1) * COLS * 2; i < LINES * COLS * 2; i += 2)
+ vidmem[i] = ' ';
+}
+
+static void vga_tx_byte(unsigned char byte)
+{
+ if (byte == '\n') {
+ vga_line++;
+ vga_col = 0;
+
+ } else if (byte == '\r') {
+ vga_col = 0;
+
+ } else if (byte == '\b') {
+ vga_col--;
+
+ } else if (byte == '\t') {
+ vga_col += 4;
+
+ } else if (byte == '\a') {
+ //beep
+ beep(500);
+
+ } else {
+ vidmem[((vga_col + (vga_line *COLS)) * 2)] = byte;
+ vidmem[((vga_col + (vga_line *COLS)) * 2) +1] = VGA_ATTR_CLR_WHT;
+ vga_col++;
+ }
+ if (vga_col < 0) {
+ vga_col = 0;
+ }
+ if (vga_col >= COLS) {
+ vga_line++;
+ vga_col = 0;
+ }
+ if (vga_line >= LINES) {
+ vga_scroll();
+ vga_line--;
+ }
+ // move the cursor
+ write_crtc((vga_col + (vga_line *COLS)) >> 8, CRTC_CURSOR_HI);
+ write_crtc((vga_col + (vga_line *COLS)) & 0x0ff, CRTC_CURSOR_LO);
+}
+
+struct console_driver {
+ .init = vga_init,
+ .tx_byte = vga_tx_byte,
+};
diff --git a/src/console/vsprintf.c b/src/console/vsprintf.c
new file mode 100644
index 0000000000..b1310c62d1
--- /dev/null
+++ b/src/console/vsprintf.c
@@ -0,0 +1,352 @@
+/*
+ * linux/lib/vsprintf.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
+/*
+ * Wirzenius wrote this portably, Torvalds fucked it up :-)
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id$";
+#endif
+
+#include <stdarg.h>
+#include <string.h>
+
+/* haha, don't need ctype.c */
+#define isdigit(c) ((c) >= '0' && (c) <= '9')
+#define is_digit isdigit
+#define isxdigit(c) (((c) >= '0' && (c) <= '9') || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F'))
+#define islower(c) ((c) >= 'a' && (c) <= 'z')
+#define toupper(c) __toupper(c)
+
+static inline unsigned char __toupper(unsigned char c)
+{
+ if (islower(c))
+ c -= 'a'-'A';
+ return c;
+}
+
+
+unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
+{
+ unsigned long result = 0,value;
+
+ if (!base) {
+ base = 10;
+ if (*cp == '0') {
+ base = 8;
+ cp++;
+ if ((*cp == 'x') && isxdigit(cp[1])) {
+ cp++;
+ base = 16;
+ }
+ }
+ }
+ while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
+ ? toupper(*cp) : *cp)-'A'+10) < base) {
+ result = result*base + value;
+ cp++;
+ }
+ if (endp)
+ *endp = (char *)cp;
+ return result;
+}
+
+long simple_strtol(const char *cp,char **endp,unsigned int base)
+{
+ if(*cp=='-')
+ return -simple_strtoul(cp+1,endp,base);
+ return simple_strtoul(cp,endp,base);
+}
+
+
+static int skip_atoi(const char **s)
+{
+ int i=0;
+
+ while (is_digit(**s))
+ i = i*10 + *((*s)++) - '0';
+ return i;
+}
+
+#define ZEROPAD 1 /* pad with zero */
+#define SIGN 2 /* unsigned/signed long */
+#define PLUS 4 /* show plus */
+#define SPACE 8 /* space if plus */
+#define LEFT 16 /* left justified */
+#define SPECIAL 32 /* 0x */
+#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
+
+#define do_div(n,base) ({ \
+int __res; \
+__res = ((unsigned long) n) % (unsigned) base; \
+n = ((unsigned long) n) / (unsigned) base; \
+__res; })
+
+static int number(void (*tx_byte)(unsigned char byte), long num, int base, int size, int precision
+ ,int type)
+{
+ char c,sign,tmp[66];
+ const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
+ int i;
+ int count = 0;
+
+ if (type & LARGE)
+ digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ if (type & LEFT)
+ type &= ~ZEROPAD;
+ if (base < 2 || base > 36)
+ return 0;
+ c = (type & ZEROPAD) ? '0' : ' ';
+ sign = 0;
+ if (type & SIGN) {
+ if (num < 0) {
+ sign = '-';
+ num = -num;
+ size--;
+ } else if (type & PLUS) {
+ sign = '+';
+ size--;
+ } else if (type & SPACE) {
+ sign = ' ';
+ size--;
+ }
+ }
+ if (type & SPECIAL) {
+ if (base == 16)
+ size -= 2;
+ else if (base == 8)
+ size--;
+ }
+ i = 0;
+ if (num == 0)
+ tmp[i++]='0';
+ else while (num != 0)
+ tmp[i++] = digits[do_div(num,base)];
+ if (i > precision)
+ precision = i;
+ size -= precision;
+ if (!(type&(ZEROPAD+LEFT)))
+ while(size-->0)
+ tx_byte(' '), count++;
+ if (sign)
+ tx_byte(sign), count++;
+ if (type & SPECIAL) {
+ if (base==8)
+ tx_byte('0'), count++;
+ else if (base==16) {
+ tx_byte('0'), count++;
+ tx_byte(digits[33]), count++;
+ }
+ }
+ if (!(type & LEFT))
+ while (size-- > 0)
+ tx_byte(c), count++;
+ while (i < precision--)
+ tx_byte('0'), count++;
+ while (i-- > 0)
+ tx_byte(tmp[i]), count++;
+ while (size-- > 0)
+ tx_byte(' '), count++;
+ return count;
+}
+
+
+int vtxprintf(void (*tx_byte)(unsigned char byte), const char *fmt, va_list args)
+{
+ int len;
+ unsigned long num;
+ int i, base;
+ const char *s;
+
+ int flags; /* flags to number() */
+
+ int field_width; /* width of output field */
+ int precision; /* min. # of digits for integers; max
+ number of chars for from string */
+ int qualifier; /* 'h', 'l', or 'L' for integer fields */
+
+ int count;
+
+ for (count=0; *fmt ; ++fmt) {
+ if (*fmt != '%') {
+ tx_byte(*fmt), count++;
+ continue;
+ }
+
+ /* process flags */
+ flags = 0;
+ repeat:
+ ++fmt; /* this also skips first '%' */
+ switch (*fmt) {
+ case '-': flags |= LEFT; goto repeat;
+ case '+': flags |= PLUS; goto repeat;
+ case ' ': flags |= SPACE; goto repeat;
+ case '#': flags |= SPECIAL; goto repeat;
+ case '0': flags |= ZEROPAD; goto repeat;
+ }
+
+ /* get field width */
+ field_width = -1;
+ if (is_digit(*fmt))
+ field_width = skip_atoi(&fmt);
+ else if (*fmt == '*') {
+ ++fmt;
+ /* it's the next argument */
+ field_width = va_arg(args, int);
+ if (field_width < 0) {
+ field_width = -field_width;
+ flags |= LEFT;
+ }
+ }
+
+ /* get the precision */
+ precision = -1;
+ if (*fmt == '.') {
+ ++fmt;
+ if (is_digit(*fmt))
+ precision = skip_atoi(&fmt);
+ else if (*fmt == '*') {
+ ++fmt;
+ /* it's the next argument */
+ precision = va_arg(args, int);
+ }
+ if (precision < 0)
+ precision = 0;
+ }
+
+ /* get the conversion qualifier */
+ qualifier = -1;
+ if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
+ qualifier = *fmt;
+ ++fmt;
+ }
+
+ /* default base */
+ base = 10;
+
+ switch (*fmt) {
+ case 'c':
+ if (!(flags & LEFT))
+ while (--field_width > 0)
+ tx_byte(' '), count++;
+ tx_byte((unsigned char) va_arg(args, int)), count++;
+ while (--field_width > 0)
+ tx_byte(' '), count++;
+ continue;
+
+ case 's':
+ s = va_arg(args, char *);
+ if (!s)
+ s = "<NULL>";
+
+ len = strnlen(s, precision);
+
+ if (!(flags & LEFT))
+ while (len < field_width--)
+ tx_byte(' '), count++;
+ for (i = 0; i < len; ++i)
+ tx_byte(*s++), count++;
+ while (len < field_width--)
+ tx_byte(' '), count++;
+ continue;
+
+ case 'p':
+ if (field_width == -1) {
+ field_width = 2*sizeof(void *);
+ flags |= ZEROPAD;
+ }
+ count += number(tx_byte,
+ (unsigned long) va_arg(args, void *), 16,
+ field_width, precision, flags);
+ continue;
+
+
+ case 'n':
+ if (qualifier == 'l') {
+ long * ip = va_arg(args, long *);
+ *ip = count;
+ } else {
+ int * ip = va_arg(args, int *);
+ *ip = count;
+ }
+ continue;
+
+ case '%':
+ tx_byte('%'), count++;
+ continue;
+
+ /* integer number formats - set up the flags and "break" */
+ case 'o':
+ base = 8;
+ break;
+
+ case 'X':
+ flags |= LARGE;
+ case 'x':
+ base = 16;
+ break;
+
+ case 'd':
+ case 'i':
+ flags |= SIGN;
+ case 'u':
+ break;
+
+ default:
+ tx_byte('%'), count++;
+ if (*fmt)
+ tx_byte(*fmt), count++;
+ else
+ --fmt;
+ continue;
+ }
+ if (qualifier == 'l')
+ num = va_arg(args, unsigned long);
+ else if (qualifier == 'h') {
+ num = (unsigned short) va_arg(args, int);
+ if (flags & SIGN)
+ num = (short) num;
+ } else if (flags & SIGN)
+ num = va_arg(args, int);
+ else
+ num = va_arg(args, unsigned int);
+ count += number(tx_byte, num, base, field_width, precision, flags);
+ }
+ return count;
+}
+
+/* FIXME this global makes vsprintf non-reentrant
+ */
+static char *str_buf;
+static void str_tx_byte(unsigned char byte)
+{
+ *str_buf = byte;
+ str_buf++;
+}
+
+int vsprintf(char * buf, const char *fmt, va_list args)
+{
+ int i;
+ str_buf = buf;
+ i = vtxprintf(str_tx_byte, fmt, args);
+ /* maeder/Ispiri -- The null termination was missing a deference */
+ /* and was just zeroing out the pointer instead */
+ *str_buf = '\0';
+ return i;
+}
+
+int sprintf(char * buf, const char *fmt, ...)
+{
+ va_list args;
+ int i;
+
+ va_start(args, fmt);
+ i=vsprintf(buf,fmt,args);
+ va_end(args);
+ return i;
+}
diff --git a/src/cpu/i386/entry16.inc b/src/cpu/i386/entry16.inc
new file mode 100644
index 0000000000..c357504735
--- /dev/null
+++ b/src/cpu/i386/entry16.inc
@@ -0,0 +1,112 @@
+/*
+This software and ancillary information (herein called SOFTWARE )
+called LinuxBIOS is made available under the terms described
+here. The SOFTWARE has been approved for release with associated
+LA-CC Number 00-34 . Unless otherwise indicated, this SOFTWARE has
+been authored by an employee or employees of the University of
+California, operator of the Los Alamos National Laboratory under
+Contract No. W-7405-ENG-36 with the U.S. Department of Energy. The
+U.S. Government has rights to use, reproduce, and distribute this
+SOFTWARE. The public may copy, distribute, prepare derivative works
+and publicly display this SOFTWARE without charge, provided that this
+Notice and any statement of authorship are reproduced on all copies.
+Neither the Government nor the University makes any warranty, express
+or implied, or assumes any liability or responsibility for the use of
+this SOFTWARE. If SOFTWARE is modified to produce derivative works,
+such modified SOFTWARE should be clearly marked, so as not to confuse
+it with the version available from LANL.
+ */
+/* Copyright 2000, Ron Minnich, Advanced Computing Lab, LANL
+ * rminnich@lanl.gov
+ */
+
+
+/** Start code to put an i386 or later processor into 32-bit
+ * protected mode.
+ */
+
+/* .section ".rom.text" */
+#include <arch/rom_segs.h>
+.code16
+.globl EXT(_start)
+.type EXT(_start), @function
+
+EXT(_start):
+ cli
+
+/* thanks to kmliu@sis.tw.com for this TBL fix ... */
+/**/
+/* IMMEDIATELY invalidate the translation lookaside buffer before executing*/
+/* any further code. Even though paging is disabled we could still get*/
+/*false address translations due to the TLB if we didn't invalidate it.*/
+/**/
+ xorl %eax, %eax
+ movl %eax, %cr3 /* Invalidate TLB*/
+
+ /* invalidate the cache */
+ invd
+
+ /* Note: gas handles memory addresses in 16 bit code very poorly.
+ * In particular it doesn't appear to have a directive allowing you
+ * associate a section or even an absolute offset with a segment register.
+ *
+ * This means that anything except cs:ip relative offsets are
+ * a real pain in 16 bit mode. And explains why it is almost
+ * imposible to get gas to do lgdt correctly.
+ *
+ * One way to work around this is to have the linker do the
+ * math instead of the assembler. This solves the very
+ * pratical problem of being able to write code that can
+ * be relocated.
+ *
+ * An lgdt call before we have memory enabled cannot be
+ * position independent, as we cannot execute a call
+ * instruction to get our current instruction pointer.
+ * So while this code is relocateable it isn't arbitrarily
+ * relocatable.
+ *
+ * The criteria for relocation have been relaxed to their
+ * utmost, so that we can use the same code for both
+ * our initial entry point and startup of the second cpu.
+ * The code assumes when executing at _start that:
+ * (((cs & 0xfff) == 0) and (ip == _start & 0xffff))
+ * or
+ * ((cs == anything) and (ip == 0)).
+ *
+ * The restrictions in reset16.inc mean that _start initially
+ * must be loaded at or above 0xffff0000 or below 0x100000.
+ *
+ * The linker scripts computs gdtptr16_offset by simply returning
+ * the low 16 bits. This means that the intial segment used
+ * when start is called must be 64K aligned. This should not
+ * restrict the address as the ip address can be anything.
+ */
+
+ movw %cs, %ax
+ shlw $4, %ax
+ movw $EXT(gdtptr16_offset), %bx
+ subw %ax, %bx
+ data32 lgdt %cs:(%bx)
+
+ movl %cr0, %eax
+ andl $0x7FFAFFD1, %eax /* PG,AM,WP,NE,TS,EM,MP = 0 */
+ orl $0x60000001, %eax /* CD, NW, PE = 1 */
+ movl %eax, %cr0
+
+ /* Now that we are in protected mode jump to a 32 bit code segment. */
+ data32 ljmp $ROM_CODE_SEG, $__protected_start
+
+/** The gdt has a 4 Gb code segment at 0x10, and a 4 GB data segment
+ * at 0x18; these are Linux-compatible.
+ */
+
+.align 4
+.globl EXT(gdtptr16)
+EXT(gdtptr16):
+ .word gdt_end - gdt -1 /* compute the table limit */
+ .long gdt /* we know the offset */
+
+.globl EXT(_estart)
+EXT(_estart):
+ .code32
+
diff --git a/src/cpu/i386/entry16.lds b/src/cpu/i386/entry16.lds
new file mode 100644
index 0000000000..db37e66302
--- /dev/null
+++ b/src/cpu/i386/entry16.lds
@@ -0,0 +1,2 @@
+ gdtptr16_offset = gdtptr16 & 0xffff;
+ _start_offset = _start & 0xffff;
diff --git a/src/cpu/i386/entry32.inc b/src/cpu/i386/entry32.inc
new file mode 100644
index 0000000000..8ccd638e95
--- /dev/null
+++ b/src/cpu/i386/entry32.inc
@@ -0,0 +1,55 @@
+/* For starting linuxBIOS in protected mode */
+
+#include <arch/rom_segs.h>
+
+/* .section ".rom.text" */
+ .code32
+
+ .align 4
+.globl EXT(gdtptr)
+
+gdt:
+EXT(gdtptr):
+ .word gdt_end - gdt -1 /* compute the table limit */
+ .long gdt /* we know the offset */
+ .word 0
+
+/* flat code segment */
+ .word 0xffff, 0x0000
+ .byte 0x00, 0x9b, 0xcf, 0x00
+
+/* flat data segment */
+ .word 0xffff, 0x0000
+ .byte 0x00, 0x93, 0xcf, 0x00
+
+gdt_end:
+
+
+/*
+ * When we come here we are in protected mode. We expand
+ * the stack and copies the data segment from ROM to the
+ * memory.
+ *
+ * After that, we call the chipset bootstrap routine that
+ * does what is left of the chipset initialization.
+ *
+ * NOTE aligned to 4 so that we are sure that the prefetch
+ * cache will be reloaded.
+ */
+ .align 4
+.globl EXT(protected_start)
+EXT(protected_start):
+
+ lgdt %cs:gdtptr
+ ljmp $ROM_CODE_SEG, $__protected_start
+
+__protected_start:
+ intel_chip_post_macro(0x10) /* post 10 */
+
+ movw $ROM_DATA_SEG, %ax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %ss
+ movw %ax, %fs
+ movw %ax, %gs
+
diff --git a/src/cpu/i386/entry32.lds b/src/cpu/i386/entry32.lds
new file mode 100644
index 0000000000..37a75ba6ae
--- /dev/null
+++ b/src/cpu/i386/entry32.lds
@@ -0,0 +1,14 @@
+/*
+ _cache_ram_seg_base = DEFINED(CACHE_RAM_BASE)? CACHE_RAM_BASE - _rodata : 0;
+ _cache_ram_seg_base_low = (_cache_ram_seg_base) & 0xffff;
+ _cache_ram_seg_base_middle = (_cache_ram_seg_base >> 16) & 0xff;
+ _cache_ram_seg_base_high = (_cache_ram_seg_base >> 24) & 0xff;
+
+ _rom_code_seg_base = _ltext - _text;
+ _rom_code_seg_base_low = (_rom_code_seg_base) & 0xffff;
+ _rom_code_seg_base_middle = (_rom_code_seg_base >> 16) & 0xff;
+ _rom_code_seg_base_high = (_rom_code_seg_base >> 24) & 0xff;
+*/
+
+
+
diff --git a/src/cpu/i386/reset16.inc b/src/cpu/i386/reset16.inc
new file mode 100644
index 0000000000..7c911d9ff2
--- /dev/null
+++ b/src/cpu/i386/reset16.inc
@@ -0,0 +1,27 @@
+ .section ".reset"
+ .code16
+.globl EXT(reset_vector)
+EXT(reset_vector):
+#if _ROMBASE >= 0xffff0000
+ /* Hmm.
+ * _start_offset is the low 16 bits of _start.
+ * Theoretically we should have problems but it compiles
+ * and links properly with binutils 2.9.5 & 2.10.90
+ * This is probably a case that needs fixing in binutils.
+ * And then we can just use _start.
+ * We also need something like the assume directive in
+ * other assemblers to tell it where the segment registers
+ * are pointing in memory right now.
+ */
+ jmp EXT(_start_offset)
+#elif (_ROMBASE < 0x100000)
+ ljmp $((_ROMBASE & 0xf0000)>>4),$EXT(_start_offset);
+#else
+#error _ROMBASE is an unsupported value
+#endif
+
+ . = 0x8;
+ .code32
+ jmp EXT(protected_start)
+
+ .previous
diff --git a/src/cpu/i386/reset16.lds b/src/cpu/i386/reset16.lds
new file mode 100644
index 0000000000..80f2fc0c6f
--- /dev/null
+++ b/src/cpu/i386/reset16.lds
@@ -0,0 +1,14 @@
+/*
+ * _ROMTOP : The top of the rom used where we
+ * need to put the reset vector.
+ */
+
+SECTIONS {
+ _ROMTOP = (_ROMBASE >= 0xffff0000)? 0xfffffff0 : 0xffff0;
+ . = _ROMTOP;
+ .reset . : {
+ *(.reset)
+ . = 15 ;
+ BYTE(0x00);
+ }
+}
diff --git a/src/cpu/i386/reset32.inc b/src/cpu/i386/reset32.inc
new file mode 100644
index 0000000000..ec743b70cc
--- /dev/null
+++ b/src/cpu/i386/reset32.inc
@@ -0,0 +1,10 @@
+ .section ".reset"
+ .code16
+.globl EXT(reset_vector)
+EXT(reset_vector):
+
+ . = 0x8;
+ .code32
+ jmp EXT(protected_start)
+
+ .previous
diff --git a/src/cpu/i386/reset32.lds b/src/cpu/i386/reset32.lds
new file mode 100644
index 0000000000..fa6db86b1a
--- /dev/null
+++ b/src/cpu/i386/reset32.lds
@@ -0,0 +1,14 @@
+/*
+ * _ROMTOP : The top of the rom used where we
+ * need to put the reset vector.
+ */
+
+SECTIONS {
+ _ROMTOP = _ROMBASE + ROM_IMAGE_SIZE - 0x10;
+ . = _ROMTOP;
+ .reset (.): {
+ *(.reset)
+ . = 15 ;
+ BYTE(0x00);
+ }
+}
diff --git a/src/cpu/k8/cpufixup.c b/src/cpu/k8/cpufixup.c
new file mode 100644
index 0000000000..9f306d1156
--- /dev/null
+++ b/src/cpu/k8/cpufixup.c
@@ -0,0 +1,59 @@
+/* Needed so the AMD K8 runs correctly. */
+#include <console/console.h>
+#include <mem.h>
+#include <cpu/p6/msr.h>
+
+#define TOP_MEM 0xc001001A
+#define TOP_MEM2 0xc001001D
+#define IORR_FIRST 0xC0010016
+#define IORR_LAST 0xC0010019
+#define SYSCFG 0xC0010010
+
+#define MTRRVARDRAMEN (1 << 20)
+
+void k8_cpufixup(struct mem_range *mem)
+{
+ unsigned long lo = 0, hi = 0, i;
+ unsigned long ram_megabytes;
+
+ /* For now no Athlon board has significant holes in it's
+ * address space so just find the last memory region
+ * and compute the end of memory from that.
+ */
+ for(i = 0; mem[i].sizek; i++)
+ ;
+ if (i == 0)
+ return;
+ ram_megabytes = (mem[i-1].basek + mem[i-1].sizek) *1024;
+
+
+ // 8 MB alignment please
+ ram_megabytes += 0x7fffff;
+ ram_megabytes &= (~0x7fffff);
+
+ // set top_mem registers to ram size
+ printk_spew("Setting top_mem to 0x%x\n", ram_megabytes);
+ rdmsr(TOP_MEM, lo, hi);
+ printk_spew("TOPMEM was 0x%02x:0x%02x\n", hi, lo);
+ hi = 0;
+ lo = ram_megabytes;
+ wrmsr(TOP_MEM, lo, hi);
+
+ // I am setting this even though I won't enable it
+ wrmsr(TOP_MEM2, lo, hi);
+
+ /* zero the IORR's before we enable to prevent
+ * undefined side effects
+ */
+ lo = hi = 0;
+ for (i = IORR_FIRST; i <= IORR_LAST; i++)
+ wrmsr(i, lo, hi);
+
+ rdmsr(SYSCFG, lo, hi);
+ printk_spew("SYSCFG was 0x%x:0x%x\n", hi, lo);
+ lo |= MTRRVARDRAMEN;
+ wrmsr(SYSCFG, lo, hi);
+ rdmsr(SYSCFG, lo, hi);
+ printk_spew("SYSCFG IS NOW 0x%x:0x%x\n", hi, lo);
+}
+
diff --git a/src/cpu/k8/earlymtrr.inc b/src/cpu/k8/earlymtrr.inc
new file mode 100644
index 0000000000..7cd8443618
--- /dev/null
+++ b/src/cpu/k8/earlymtrr.inc
@@ -0,0 +1,99 @@
+#include <cpu/k8/mtrr.h>
+
+/* The fixed and variable MTRRs are powered-up with random values, clear them to
+ * MTRR_TYPE_UNCACHABLE for safty reason
+ */
+
+earlymtrr_start:
+ xorl %eax, %eax # clear %eax and %edx
+ xorl %edx, %edx #
+ movl $fixed_mtrr_msr, %esi
+
+clear_fixed_var_mtrr:
+ lodsl (%esi), %eax
+ testl %eax, %eax
+ jz clear_fixed_var_mtrr_out
+
+ movl %eax, %ecx
+ xorl %eax, %eax
+ wrmsr
+
+ jmp clear_fixed_var_mtrr
+clear_fixed_var_mtrr_out:
+
+/* enable memory access for 0 - 8MB using top_mem */
+ movl $TOP_MEM, %ecx
+ xorl %edx, %edx
+ movl $0x0800000, %eax
+ wrmsr
+
+set_var_mtrr:
+ /* enable caching for 0 - 128MB using variable mtrr */
+ movl $0x200, %ecx
+ rdmsr
+ andl $0xfffffff0, %edx
+ orl $0x00000000, %edx
+ andl $0x00000f00, %eax
+ orl $0x00000006, %eax
+ wrmsr
+
+ movl $0x201, %ecx
+ rdmsr
+ andl $0xfffffff0, %edx
+ orl $0x0000000f, %edx
+ andl $0x000007ff, %eax
+ orl $0xf0000800, %eax
+ wrmsr
+
+#if defined(XIP_ROM_SIZE) && defined(XIP_ROM_BASE)
+ /* enable write protect caching so we can do execute in place
+ * on the flash rom.
+ */
+ movl $0x202, %ecx
+ xorl %edx, %edx
+ movl $(XIP_ROM_BASE | 0x005), %eax
+ wrmsr
+
+ movl $0x203, %ecx
+ movl $0x0000000f, %edx
+ movl $(~(XIP_ROM_SIZE - 1) | 0x800), %eax
+ wrmsr
+#endif /* XIP_ROM_SIZE && XIP_ROM_BASE */
+
+enable_mtrr:
+ /* Set the default memory type and enable fixed and variable MTRRs */
+ movl $0x2ff, %ecx
+ xorl %edx, %edx
+ /* Enable Variable MTRRs */
+ movl $0x00000800, %eax
+ wrmsr
+
+ /* Enable the MTRRs in SYSCFG */
+ movl $SYSCFG_MSR, %ecx
+ rdmsr
+ orl $(SYSCFG_MSR_MtrrVarDramEn), %eax
+ wrmsr
+
+ /* enable cache */
+ movl %cr0, %eax
+ andl $0x9fffffff,%eax
+ movl %eax, %cr0
+
+ jmp earlymtrr_end
+
+fixed_mtrr_msr:
+ .long 0x250, 0x258, 0x259
+ .long 0x268, 0x269, 0x26A
+ .long 0x26B, 0x26C, 0x26D
+ .long 0x26E, 0x26F
+var_mtrr_msr:
+ .long 0x200, 0x201, 0x202, 0x203
+ .long 0x204, 0x205, 0x206, 0x207
+ .long 0x208, 0x209, 0x20A, 0x20B
+ .long 0x20C, 0x20D, 0x20E, 0x20F
+var_iorr_msr:
+ .long 0xC0010016, 0xC0010017, 0xC0010018, 0xC0010019
+mem_top:
+ .long 0xC001001A, 0xC001001D
+ .long 0x000 /* NULL, end of table */
+earlymtrr_end:
diff --git a/src/cpu/p5/cpuid.c b/src/cpu/p5/cpuid.c
new file mode 100644
index 0000000000..d90cc2c124
--- /dev/null
+++ b/src/cpu/p5/cpuid.c
@@ -0,0 +1,222 @@
+#ifndef lint
+static char rcsid[] = "$Id$";
+#endif
+
+#include <console/console.h>
+#include <cpu/p5/cpuid.h>
+#ifdef i586
+#include <cpu/p6/msr.h>
+#endif
+
+
+int mtrr_check(void)
+{
+#ifdef i686
+ /* Only Pentium Pro and later have MTRR */
+ unsigned long low, high;
+
+ printk_debug("\nMTRR check\n");
+
+ rdmsr(0x2ff, low, high);
+ low = low >> 10;
+
+ printk_debug("Fixed MTRRs : ");
+ if (low & 0x01)
+ printk_debug("Enabled\n");
+ else
+ printk_debug("Disabled\n");
+
+ printk_debug("Variable MTRRs: ");
+ if (low & 0x02)
+ printk_debug("Enabled\n");
+ else
+ printk_debug("Disabled\n");
+
+ printk_debug("\n");
+
+ post_code(0x93);
+ return ((int) low);
+#else /* !i686 */
+ return 0;
+#endif /* i686 */
+}
+
+void display_cpuid(void)
+{
+ int op, eax, ebx, ecx, edx;
+ int max_op;
+
+ max_op = 0;
+
+ printk_debug("\n");
+
+ for (op = 0; op <= max_op; op++) {
+ cpuid(op, &eax, &ebx, &ecx, &edx);
+
+ if (0 == op) {
+ max_op = eax;
+ printk_debug("Max cpuid index : %d\n", eax);
+ printk_debug("Vendor ID : "
+ "%c%c%c%c%c%c%c%c%c%c%c%c\n",
+ ebx, ebx >> 8, ebx >> 16, ebx >> 24, edx,
+ edx >> 8, edx >> 16, edx >> 24, ecx, ecx >> 8,
+ ecx >> 16, ecx >> 24);
+ } else if (1 == op) {
+ printk_debug("Processor Type : 0x%02x\n",
+ (eax >> 12) & 0x03);
+ printk_debug("Processor Family : 0x%02x\n",
+ (eax >> 8) & 0x0f);
+ printk_debug("Processor Model : 0x%02x\n",
+ (eax >> 4) & 0x0f);
+ printk_debug("Processor Mask : 0x%02x\n",
+ (ecx >> 0) & 0x0f);
+ printk_debug("Processor Stepping : 0x%02x\n",
+ (eax >> 0) & 0x0f);
+ printk_debug("Feature flags : 0x%08x\n", edx);
+ } else if (2 == op) {
+ int desc[4];
+ int ii;
+ int _desc;
+
+ printk_debug("\n");
+
+ printk_debug("Cache/TLB descriptor values: %d "
+ "reads required\n", eax & 0xff);
+
+ desc[0] = eax;
+ desc[1] = ebx;
+ desc[2] = ecx;
+ desc[3] = edx;
+
+ for (ii = 1; ii < 16; ii++) {
+ if (desc[ii >> 2] & 0x80000000) {
+ printk_debug("reserved descriptor\n");
+ continue;
+ }
+
+ _desc =
+ ((desc[ii >> 2]) >> ((ii & 0x3) << 3))
+ & 0xff;
+ printk_debug("Desc 0x%02x : ", _desc);
+
+ switch (_desc) {
+ case 0x00:
+ printk_debug("null\n");
+ break;
+
+ case 0x01:
+ printk_debug("Instr TLB: "
+ "4KB pages, "
+ "4-way set assoc, "
+ "32 entries\n");
+ break;
+
+ case 0x02:
+ printk_debug("Instr TLB: "
+ "4MB pages, "
+ "fully assoc, " "2 entries\n");
+ break;
+
+ case 0x03:
+ printk_debug("Data TLB: "
+ "4KB pages, "
+ "4-way set assoc, "
+ "64 entries\n");
+ break;
+
+ case 0x04:
+ printk_debug("Data TLB: "
+ "4MB pages, "
+ "4-way set assoc, "
+ "8 entries\n");
+ break;
+
+ case 0x06:
+ printk_debug("Inst cache: "
+ "8K bytes, "
+ "4-way set assoc, "
+ "32 byte line size\n");
+ break;
+
+ case 0x08:
+ printk_debug("Inst cache: "
+ "16K bytes, "
+ "4-way set assoc, "
+ "32 byte line size\n");
+ break;
+
+ case 0x0a:
+ printk_debug("Data cache: "
+ "8K bytes, "
+ "2-way set assoc, "
+ "32 byte line size\n");
+ break;
+
+ case 0x0c:
+ printk_debug("Data cache: "
+ "16K bytes, "
+ "2-way or 4-way set assoc, "
+ "32 byte line size\n");
+ break;
+
+ case 0x40:
+ printk_debug("No L2 cache\n");
+ break;
+
+ case 0x41:
+ printk_debug("L2 Unified cache: "
+ "128K bytes, "
+ "4-way set assoc, "
+ "32 byte line size\n");
+ break;
+
+ case 0x42:
+ printk_debug("L2 Unified cache: "
+ "256K bytes, "
+ "4-way set assoc, "
+ "32 byte line size\n");
+ break;
+
+ case 0x43:
+ printk_debug("L2 Unified cache: "
+ "512K bytes, "
+ "4-way set assoc, "
+ "32 byte line size\n");
+ break;
+
+ case 0x44:
+ printk_debug("L2 Unified cache: "
+ "1M byte, "
+ "4-way set assoc, "
+ "32 byte line size\n");
+ break;
+
+ case 0x45:
+ printk_debug("L2 Unified cache: "
+ "2M byte, "
+ "4-way set assoc, "
+ "32 byte line size\n");
+ break;
+
+ case 0x82:
+ printk_debug("L2 Unified cache: "
+ "256K bytes, "
+ "8-way set assoc, "
+ "32 byte line size\n");
+ break;
+
+ default:
+ printk_debug("UNKNOWN\n");
+ }
+ }
+ printk_debug("\n");
+ } else {
+ printk_debug("op: 0x%02x eax:0x%08x "
+ "ebx:0x%08x ecx:0x%08x edx:0x%08x\n",
+ op, eax, ebx, ecx, edx);
+ }
+ }
+
+ printk_debug("\n");
+ post_code(0x92);
+}
diff --git a/src/cpu/p6/mtrr.c b/src/cpu/p6/mtrr.c
new file mode 100644
index 0000000000..b88e174869
--- /dev/null
+++ b/src/cpu/p6/mtrr.c
@@ -0,0 +1,356 @@
+/*
+ * intel_mtrr.c: setting MTRR to decent values for cache initialization on P6
+ *
+ * Derived from intel_set_mtrr in intel_subr.c and mtrr.c in linux kernel
+ *
+ * Copyright 2000 Silicon Integrated System Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * Reference: Intel Architecture Software Developer's Manual, Volume 3: System Programming
+ *
+ * $Id$
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id$";
+#endif
+
+#include <console/console.h>
+#include <mem.h>
+#include <cpu/p6/msr.h>
+#include <cpu/p6/mtrr.h>
+#include <cpu/k7/mtrr.h>
+
+#define arraysize(x) (sizeof(x)/sizeof((x)[0]))
+
+static unsigned int mtrr_msr[] = {
+ MTRRfix64K_00000_MSR, MTRRfix16K_80000_MSR, MTRRfix16K_A0000_MSR,
+ MTRRfix4K_C0000_MSR, MTRRfix4K_C8000_MSR, MTRRfix4K_D0000_MSR, MTRRfix4K_D8000_MSR,
+ MTRRfix4K_E0000_MSR, MTRRfix4K_E8000_MSR, MTRRfix4K_F0000_MSR, MTRRfix4K_F8000_MSR,
+};
+
+
+static void intel_enable_fixed_mtrr(void)
+{
+ unsigned long low, high;
+
+ rdmsr(MTRRdefType_MSR, low, high);
+ low |= 0xc00;
+ wrmsr(MTRRdefType_MSR, low, high);
+}
+
+static void intel_enable_var_mtrr(void)
+{
+ unsigned long low, high;
+
+ rdmsr(MTRRdefType_MSR, low, high);
+ low |= 0x800;
+ wrmsr(MTRRdefType_MSR, low, high);
+}
+
+static inline void disable_cache(void)
+{
+ unsigned int tmp;
+ /* Disable cache */
+ /* Write back the cache and flush TLB */
+ asm volatile (
+ "movl %%cr0, %0\n\t"
+ "orl $0x40000000, %0\n\t"
+ "wbinvd\n\t"
+ "movl %0, %%cr0\n\t"
+ "wbinvd\n\t"
+ :"=r" (tmp)
+ ::"memory");
+}
+
+static inline void enable_cache(void)
+{
+ unsigned int tmp;
+ // turn cache back on.
+ asm volatile (
+ "movl %%cr0, %0\n\t"
+ "andl $0x9fffffff, %0\n\t"
+ "movl %0, %%cr0\n\t"
+ :"=r" (tmp)
+ ::"memory");
+}
+
+/* setting variable mtrr, comes from linux kernel source */
+static void intel_set_var_mtrr(unsigned int reg, unsigned long basek, unsigned long sizek, unsigned char type)
+{
+ unsigned long base_high, base_low;
+ unsigned long mask_high, mask_low;
+
+ base_high = basek >> 22;
+ base_low = basek << 10;
+
+ if (sizek < 4*1024*1024) {
+ mask_high = 0x0F;
+ mask_low = ~((sizek << 10) -1);
+ }
+ else {
+ mask_high = 0x0F & (~((sizek >> 22) -1));
+ mask_low = 0;
+ }
+
+ if (reg >= 8)
+ return;
+
+ // it is recommended that we disable and enable cache when we
+ // do this.
+ disable_cache();
+ if (sizek == 0) {
+ /* The invalid bit is kept in the mask, so we simply clear the
+ relevant mask register to disable a range. */
+ wrmsr (MTRRphysMask_MSR (reg), 0, 0);
+ } else {
+ /* Bit 32-35 of MTRRphysMask should be set to 1 */
+ wrmsr (MTRRphysBase_MSR(reg), base_low | type, base_high);
+ wrmsr (MTRRphysMask_MSR(reg), mask_low | 0x800, mask_high);
+ }
+ enable_cache();
+}
+
+/* setting variable mtrr, comes from linux kernel source */
+void set_var_mtrr(unsigned int reg, unsigned long base, unsigned long size, unsigned char type)
+{
+ unsigned int tmp;
+
+ if (reg >= 8)
+ return;
+
+ // it is recommended that we disable and enable cache when we
+ // do this.
+ disable_cache();
+ if (size == 0) {
+ /* The invalid bit is kept in the mask, so we simply clear the
+ relevant mask register to disable a range. */
+ wrmsr (MTRRphysMask_MSR (reg), 0, 0);
+ } else {
+ /* Bit 32-35 of MTRRphysMask should be set to 1 */
+ wrmsr (MTRRphysBase_MSR (reg), base | type, 0);
+ wrmsr (MTRRphysMask_MSR (reg), ~(size - 1) | 0x800, 0x0F);
+ }
+
+ // turn cache back on.
+ enable_cache();
+}
+
+/* fms: find most sigificant bit set, stolen from Linux Kernel Source. */
+static inline unsigned int fms(unsigned int x)
+{
+ int r;
+
+ __asm__("bsrl %1,%0\n\t"
+ "jnz 1f\n\t"
+ "movl $0,%0\n"
+ "1:" : "=r" (r) : "g" (x));
+ return r;
+}
+
+/* fms: find least sigificant bit set */
+static inline unsigned int fls(unsigned int x)
+{
+ int r;
+
+ __asm__("bsfl %1,%0\n\t"
+ "jnz 1f\n\t"
+ "movl $32,%0\n"
+ "1:" : "=r" (r) : "g" (x));
+ return r;
+}
+
+/* setting up variable and fixed mtrr
+ *
+ * From Intel Vol. III Section 9.12.4, the Range Size and Base Alignment has some kind of requirement:
+ * 1. The range size must be 2^N byte for N >= 12 (i.e 4KB minimum).
+ * 2. The base address must be 2^N aligned, where the N here is equal to the N in previous
+ * requirement. So a 8K range must be 8K aligned not 4K aligned.
+ *
+ * These requirement is meet by "decompositing" the ramsize into Sum(Cn * 2^n, n = [0..N], Cn = [0, 1]).
+ * For Cm = 1, there is a WB range of 2^m size at base address Sum(Cm * 2^m, m = [N..n]).
+ * A 124MB (128MB - 4MB SMA) example:
+ * ramsize = 124MB == 64MB (at 0MB) + 32MB (at 64MB) + 16MB (at 96MB ) + 8MB (at 112MB) + 4MB (120MB).
+ * But this wastes a lot of MTRR registers so we use another more "aggresive" way with Uncacheable Regions.
+ *
+ * In the Uncacheable Region scheme, we try to cover the whole ramsize by one WB region as possible,
+ * If (an only if) this can not be done we will try to decomposite the ramesize, the mathematical formula
+ * whould be ramsize = Sum(Cn * 2^n, n = [0..N], Cn = [-1, 0, 1]). For Cn = -1, a Uncachable Region is used.
+ * The same 124MB example:
+ * ramsize = 124MB == 128MB WB (at 0MB) + 4MB UC (at 124MB)
+ * or a 156MB (128MB + 32MB - 4MB SMA) example:
+ * ramsize = 156MB == 128MB WB (at 0MB) + 32MB WB (at 128MB) + 4MB UC (at 156MB)
+ */
+/* 2 MTRRS are reserved for the operating system */
+#define BIOS_MTRRS 6
+#define OS_MTRRS 2
+#define MTRRS (BIOS_MTRRS + OS_MTRRS)
+
+
+static void set_fixed_mtrrs(unsigned int first, unsigned int last, unsigned char type)
+{
+ unsigned int i;
+ unsigned int fixed_msr = NUM_FIXED_RANGES >> 3;
+ unsigned long low, high;
+ low = high = 0; /* Shut up gcc */
+ for(i = first; i < last; i++) {
+ /* When I switch to a new msr read it in */
+ if (fixed_msr != i >> 3) {
+ /* But first write out the old msr */
+ if (fixed_msr < (NUM_FIXED_RANGES >> 3)) {
+ disable_cache();
+ wrmsr(mtrr_msr[fixed_msr], low, high);
+ enable_cache();
+ }
+ fixed_msr = i>>3;
+ rdmsr(mtrr_msr[fixed_msr], low, high);
+ }
+ if ((i & 7) < 4) {
+ low &= ~(0xff << ((i&3)*8));
+ low |= type << ((i&3)*8);
+ } else {
+ high &= ~(0xff << ((i&3)*8));
+ high |= type << ((i&3)*8);
+ }
+ }
+ /* Write out the final msr */
+ if (fixed_msr < (NUM_FIXED_RANGES >> 3)) {
+ disable_cache();
+ wrmsr(mtrr_msr[fixed_msr], low, high);
+ enable_cache();
+ }
+}
+
+static unsigned fixed_mtrr_index(unsigned long addrk)
+{
+ unsigned index;
+ index = (addrk - 0) >> 6;
+ if (index >= 8) {
+ index = ((addrk - 8*64) >> 4) + 8;
+ }
+ if (index >= 24) {
+ index = ((addrk - (8*64 + 16*16)) >> 2) + 24;
+ }
+ if (index > NUM_FIXED_RANGES) {
+ index = NUM_FIXED_RANGES;
+ }
+ return index;
+}
+
+static unsigned int range_to_mtrr(unsigned int reg,
+ unsigned long range_startk, unsigned long range_sizek,
+ unsigned long next_range_startk)
+{
+ if (!range_sizek || (reg >= BIOS_MTRRS)) {
+ return reg;
+ }
+ while(range_sizek) {
+ unsigned long max_align, align;
+ unsigned long sizek;
+ /* Compute the maximum size I can make a range */
+ max_align = fls(range_startk);
+ align = fms(range_sizek);
+ if (align > max_align) {
+ align = max_align;
+ }
+ sizek = 1 << align;
+ printk_debug("Setting variable MTRR %d, base: %4dMB, range: %4dMB, type WB\n",
+ reg, range_startk >>10, sizek >> 10);
+ intel_set_var_mtrr(reg++, range_startk, sizek, MTRR_TYPE_WRBACK);
+ range_startk += sizek;
+ range_sizek -= sizek;
+ if (reg >= BIOS_MTRRS)
+ break;
+ }
+ return reg;
+}
+
+void setup_mtrrs(struct mem_range *mem)
+{
+ /* Try this the simple way of incrementally adding together
+ * mtrrs. If this doesn't work out we can get smart again
+ * and clear out the mtrrs.
+ */
+ struct mem_range *memp;
+ unsigned long range_startk, range_sizek;
+ unsigned int reg;
+
+ printk_debug("\n");
+ /* Initialized the fixed_mtrrs to uncached */
+ printk_debug("Setting fixed MTRRs(%d-%d) type: UC\n",
+ 0, NUM_FIXED_RANGES);
+ set_fixed_mtrrs(0, NUM_FIXED_RANGES, MTRR_TYPE_UNCACHABLE);
+
+ /* Now see which of the fixed mtrrs cover ram.
+ */
+ for(memp = mem; memp->sizek; memp++) {
+ unsigned int start_mtrr;
+ unsigned int last_mtrr;
+ start_mtrr = fixed_mtrr_index(memp->basek);
+ last_mtrr = fixed_mtrr_index(memp->basek + memp->sizek);
+ if (start_mtrr >= NUM_FIXED_RANGES) {
+ break;
+ }
+ printk_debug("Setting fixed MTRRs(%d-%d) type: WB\n",
+ start_mtrr, last_mtrr);
+ set_fixed_mtrrs(start_mtrr, last_mtrr, MTRR_TYPE_WRBACK);
+ }
+ printk_debug("DONE fixed MTRRs\n");
+ /* Cache as many memory areas as possible */
+ /* FIXME is there an algorithm for computing the optimal set of mtrrs?
+ * In some cases it is definitely possible to do better.
+ */
+ range_startk = 0;
+ range_sizek = 0;
+ reg = 0;
+ for (memp = mem; memp->sizek; memp++) {
+ /* See if I can merge with the last range
+ * Either I am below 1M and the fixed mtrrs handle it, or
+ * the ranges touch.
+ */
+ if ((memp->basek <= 1024) || (range_startk + range_sizek == memp->basek)) {
+ unsigned long endk = memp->basek + memp->sizek;
+ range_sizek = endk - range_startk;
+ continue;
+ }
+ /* Write the range mtrrs */
+ if (range_sizek != 0) {
+ reg = range_to_mtrr(reg, range_startk, range_sizek, memp->basek);
+ range_startk = 0;
+ range_sizek = 0;
+ if (reg >= BIOS_MTRRS)
+ break;
+ }
+ /* Allocate an msr */
+ range_startk = memp->basek;
+ range_sizek = memp->sizek;
+ }
+ /* Write the last range */
+ reg = range_to_mtrr(reg, range_startk, range_sizek, 0);
+ printk_debug("DONE variable MTRRs\n");
+ printk_debug("Clear out the extra MTRR's\n");
+ /* Clear out the extra MTRR's */
+ while(reg < MTRRS) {
+ intel_set_var_mtrr(reg++, 0, 0, 0);
+ }
+ /* enable fixed MTRR */
+ printk_debug("call intel_enable_fixed_mtrr()\n");
+ intel_enable_fixed_mtrr();
+ printk_debug("call intel_enable_var_mtrr()\n");
+ intel_enable_var_mtrr();
+ printk_debug("Leave %s\n", __FUNCTION__);
+}
diff --git a/src/devices/device.c b/src/devices/device.c
new file mode 100644
index 0000000000..ffc7253389
--- /dev/null
+++ b/src/devices/device.c
@@ -0,0 +1,423 @@
+/*
+ * (c) 1999--2000 Martin Mares <mj@suse.cz>
+ * (c) 2003 Eric Biederman <ebiederm@xmission.com>
+ */
+/* lots of mods by ron minnich (rminnich@lanl.gov), with
+ * the final architecture guidance from Tom Merritt (tjm@codegen.com)
+ * In particular, we changed from the one-pass original version to
+ * Tom's recommended multiple-pass version. I wasn't sure about doing
+ * it with multiple passes, until I actually started doing it and saw
+ * the wisdom of Tom's recommendations ...
+ *
+ * Lots of cleanups by Eric Biederman to handle bridges, and to
+ * handle resource allocation for non-pci devices.
+ */
+
+#include <console/console.h>
+#include <bitops.h>
+#include <device.h>
+#include <arch/io.h>
+#include <pci.h>
+
+/**
+ * This is the root of the device tree. A PCI tree always has
+ * one bus, bus 0. Bus 0 contains devices and bridges.
+ */
+struct device dev_root;
+/* Linked list of ALL devices */
+struct device *all_devices = 0;
+/* pointer to the last device */
+static struct device **last_dev_p = &all_devices;
+
+#define DEVICE_MEM_HIGH 0xFEC00000UL /* Reserve 20M for the system */
+#define DEVICE_IO_START 0x1000
+
+
+unsigned long device_memory_base;
+
+
+/* Append a new device to the global device chain.
+ * The chain is used to find devices once everything is set up.
+ */
+void append_device(struct device *dev)
+{
+ *last_dev_p = dev;
+ last_dev_p = &dev->next;
+}
+
+
+/** round a number to an alignment.
+ * @param val the starting value
+ * @param roundup Alignment as a power of two
+ * @returns rounded up number
+ */
+static unsigned long round(unsigned long val, unsigned long roundup)
+{
+ /* ROUNDUP MUST BE A POWER OF TWO. */
+ unsigned long inverse;
+ inverse = ~(roundup - 1);
+ val += (roundup - 1);
+ val &= inverse;
+ return val;
+}
+
+static unsigned long round_down(unsigned long val, unsigned long round_down)
+{
+ /* ROUND_DOWN MUST BE A POWER OF TWO. */
+ unsigned long inverse;
+ inverse = ~(round_down - 1);
+ val &= inverse;
+ return val;
+}
+
+
+/** Read the resources on all devices of a given bus.
+ * @param bus bus to read the resources on.
+ */
+static void read_resources(struct device *bus)
+{
+ struct device *curdev;
+
+
+ /* Walk through all of the devices and find which resources they need. */
+ for(curdev = bus->children; curdev; curdev = curdev->sibling) {
+ if (curdev->resources > 0) {
+ continue;
+ }
+ curdev->ops->read_resources(curdev);
+ }
+}
+
+static struct device *largest_resource(struct device *bus, struct resource **result_res,
+ unsigned long type_mask, unsigned long type)
+{
+ struct device *curdev;
+ struct device *result_dev = 0;
+ struct resource *last = *result_res;
+ struct resource *result = 0;
+ int seen_last = 0;
+ for(curdev = bus->children; curdev; curdev = curdev->sibling) {
+ int i;
+ for(i = 0; i < curdev->resources; i++) {
+ struct resource *resource = &curdev->resource[i];
+ /* If it isn't the right kind of resource ignore it */
+ if ((resource->flags & type_mask) != type) {
+ continue;
+ }
+ /* Be certain to pick the successor to last */
+ if (resource == last) {
+ seen_last = 1;
+ continue;
+ }
+ if (last && (
+ (last->align < resource->align) ||
+ ((last->align == resource->align) &&
+ (last->size < resource->size)) ||
+ ((last->align == resource->align) &&
+ (last->size == resource->size) &&
+ (!seen_last)))) {
+ continue;
+ }
+ if (!result ||
+ (result->align < resource->align) ||
+ ((result->align == resource->align) &&
+ (result->size < resource->size))) {
+ result_dev = curdev;
+ result = resource;
+ }
+ }
+ }
+ *result_res = result;
+ return result_dev;
+}
+
+/* Compute allocate resources is the guts of the resource allocator.
+ *
+ * The problem.
+ * - Allocate resources locations for every device.
+ * - Don't overlap, and follow the rules of bridges.
+ * - Don't overlap with resources in fixed locations.
+ * - Be efficient so we don't have ugly strategies.
+ *
+ * The strategy.
+ * - Devices that have fixed addresses are the minority so don't
+ * worry about them too much. Instead only use part of the address
+ * space for devices with programmable addresses. This easily handles
+ * everything except bridges.
+ *
+ * - PCI devices are required to have thier sizes and their alignments
+ * equal. In this case an optimal solution to the packing problem
+ * exists. Allocate all devices from highest alignment to least
+ * alignment or vice versa. Use this.
+ *
+ * - So we can handle more than PCI run two allocation passes on
+ * bridges. The first to see how large the resources are behind
+ * the bridge, and what their alignment requirements are. The
+ * second to assign a safe address to the devices behind the
+ * bridge. This allows me to treat a bridge as just a device with
+ * a couple of resources, and not need to special case it in the
+ * allocator. Also this allows handling of other types of bridges.
+ *
+ */
+
+void compute_allocate_resource(
+ struct device *bus,
+ struct resource *bridge,
+ unsigned long type_mask,
+ unsigned long type)
+{
+ struct device *dev;
+ struct resource *resource;
+ unsigned long base;
+ unsigned long align, min_align;
+ min_align = 0;
+ base = bridge->base;
+
+ /* We want different minimum alignments for different kinds of
+ * resources. These minimums are not device type specific
+ * but resource type specific.
+ */
+ if (bridge->flags & IORESOURCE_IO) {
+ min_align = log2(DEVICE_IO_ALIGN);
+ }
+ if (bridge->flags & IORESOURCE_MEM) {
+ min_align = log2(DEVICE_MEM_ALIGN);
+ }
+
+ printk_spew("DEV: %02x:%02x.%01x compute_allocate_%s: base: %08lx size: %08lx align: %d gran: %d\n",
+ bus->bus->secondary,
+ PCI_SLOT(bus->devfn), PCI_FUNC(bus->devfn),
+ (bridge->flags & IORESOURCE_IO)? "io":
+ (bridge->flags & IORESOURCE_PREFETCH)? "prefmem" : "mem",
+ base, bridge->size, bridge->align, bridge->gran);
+
+ /* Make certain I have read in all of the resources */
+ read_resources(bus);
+
+ /* Remember I haven't found anything yet. */
+ resource = 0;
+
+ /* Walk through all the devices on the current bus and compute the addresses */
+ while((dev = largest_resource(bus, &resource, type_mask, type))) {
+ unsigned long size;
+ /* Do NOT I repeat do not ignore resources which have zero size.
+ * If they need to be ignored dev->read_resources should not even
+ * return them. Some resources must be set even when they have
+ * no size. PCI bridge resources are a good example of this.
+ */
+
+ /* Propogate the resource alignment to the bridge register */
+ if (resource->align > bridge->align) {
+ bridge->align = resource->align;
+ }
+
+ /* Make certain we are dealing with a good minimum size */
+ size = resource->size;
+ align = resource->align;
+ if (align < min_align) {
+ align = min_align;
+ }
+ if (resource->flags & IORESOURCE_IO) {
+ /* Don't allow potential aliases over the
+ * legacy pci expansion card addresses.
+ */
+ if ((base > 0x3ff) && ((base & 0x300) != 0)) {
+ base = (base & ~0x3ff) + 0x400;
+ }
+ /* Don't allow allocations in the VGA IO range.
+ * PCI has special cases for that.
+ */
+ else if ((base >= 0x3b0) && (base <= 0x3df)) {
+ base = 0x3e0;
+ }
+ }
+ if (((round(base, 1UL << align) + size) -1) <= resource->limit) {
+ /* base must be aligned to size */
+ base = round(base, 1UL << align);
+ resource->base = base;
+ resource->flags |= IORESOURCE_SET;
+ base += size;
+
+ printk_spew(
+ "DEV: %02x:%02x.%01x %02x * [0x%08lx - 0x%08lx] %s\n",
+ dev->bus->secondary,
+ PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
+ resource->index,
+ resource->base, resource->base + resource->size -1,
+ (resource->flags & IORESOURCE_IO)? "io":
+ (resource->flags & IORESOURCE_PREFETCH)? "prefmem": "mem");
+ }
+
+ }
+ /* A pci bridge resource does not need to be a power
+ * of two size, but it does have a minimum granularity.
+ * Round the size up to that minimum granularity so we
+ * know not to place something else at an address postitively
+ * decoded by the bridge.
+ */
+ bridge->size = round(base, 1UL << bridge->gran) - bridge->base;
+
+ printk_spew("DEV: %02x:%02x.%01x compute_allocate_%s: base: %08lx size: %08lx align: %d gran: %d done\n",
+ bus->bus->secondary,
+ PCI_SLOT(bus->devfn), PCI_FUNC(bus->devfn),
+ (bridge->flags & IORESOURCE_IO)? "io":
+ (bridge->flags & IORESOURCE_PREFETCH)? "prefmem" : "mem",
+ base, bridge->size, bridge->align, bridge->gran);
+
+
+}
+
+static void allocate_vga_resource(void)
+{
+ /* FIXME handle the VGA pallette snooping */
+ struct device *dev, *vga, *bus;
+ bus = vga = 0;
+ for(dev = all_devices; dev; dev = dev->next) {
+ uint32_t class_revision;
+ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_revision);
+ if (((class_revision >> 24) == 0x03) &&
+ ((class_revision >> 16) != 0x380)) {
+ if (!vga) {
+ printk_debug("Allocating VGA resource\n");
+ vga = dev;
+ }
+ if (vga == dev) {
+ /* All legacy VGA cards have MEM & I/O space registers */
+ dev->command |= PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
+ } else {
+ /* It isn't safe to enable other VGA cards */
+ dev->command &= ~(PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
+ }
+ }
+ }
+ if (vga) {
+ bus = vga->bus;
+ }
+ /* Now walk up the bridges setting the VGA enable */
+ while(bus) {
+ uint16_t ctrl;
+ pci_read_config_word(bus, PCI_BRIDGE_CONTROL, &ctrl);
+ ctrl |= PCI_BRIDGE_CTL_VGA;
+ pci_write_config_word(bus, PCI_BRIDGE_CONTROL, ctrl);
+ bus = (bus == bus->bus)? 0 : bus->bus;
+ }
+}
+
+
+/** Assign the computed resources to the bridges and devices on the bus.
+ * Recurse to any bridges found on this bus first. Then do the devices
+ * on this bus.
+ * @param bus Pointer to the structure for this bus
+ */
+void assign_resources(struct device *bus)
+{
+ struct device *curdev;
+
+ printk_debug("ASSIGN RESOURCES, bus %d\n", bus->secondary);
+
+ for (curdev = bus->children; curdev; curdev = curdev->sibling) {
+ curdev->ops->set_resources(curdev);
+ }
+ printk_debug("ASSIGNED RESOURCES, bus %d\n", bus->secondary);
+}
+
+static void enable_resources(struct device *bus)
+{
+ struct device *curdev;
+
+ /* Walk through the chain of all pci devices and enable them.
+ * This is effectively a breadth first traversal so we should
+ * not have enalbing ordering problems.
+ */
+ for (curdev = all_devices; curdev; curdev = curdev->next) {
+ uint16_t command;
+ pci_read_config_word(curdev, PCI_COMMAND, &command);
+ command |= curdev->command;
+ printk_debug("DEV: %02x:%02x.%01x cmd <- %02x\n",
+ curdev->bus->secondary,
+ PCI_SLOT(curdev->devfn), PCI_FUNC(curdev->devfn),
+ command);
+ pci_write_config_word(curdev, PCI_COMMAND, command);
+ }
+}
+
+/** Enumerate the resources on the PCI by calling pci_init
+ */
+void dev_enumerate(void)
+{
+ struct device *root;
+ printk_info("Enumerating buses...");
+ root = &dev_root;
+ if (!root->ops) {
+ root->ops = &default_pci_ops_root;
+ }
+ root->subordinate = root->ops->scan_bus(root, 0);
+ printk_info("done\n");
+}
+
+/** Starting at the root, compute what resources are needed and allocate them.
+ * I/O starts at PCI_IO_START. Since the assignment is hierarchical we
+ * set the values into the dev_root struct.
+ */
+void dev_configure(void)
+{
+ struct device *root = &dev_root;
+ printk_info("Allocating resources...");
+ printk_debug("\n");
+
+
+ root->ops->read_resources(root);
+
+ /* Make certain the io devices are allocated somewhere
+ * safe.
+ */
+ root->resource[0].base = DEVICE_IO_START;
+ root->resource[0].flags |= IORESOURCE_SET;
+ /* Now reallocate the pci resources memory with the
+ * highest addresses I can manage.
+ */
+ root->resource[1].base =
+ round_down(DEVICE_MEM_HIGH - root->resource[1].size,
+ 1UL << root->resource[1].align);
+ device_memory_base = root->resource[1].base;
+ root->resource[1].flags |= IORESOURCE_SET;
+ // now just set things into registers ... we hope ...
+ root->ops->set_resources(root);
+
+ allocate_vga_resource();
+
+ printk_info("done.\n");
+}
+
+/** Starting at the root, walk the tree and enable all devices/bridges.
+ * What really happens is computed COMMAND bits get set in register 4
+ */
+void dev_enable(void)
+{
+ printk_info("Enabling resourcess...");
+
+ /* now enable everything. */
+ enable_resources(&dev_root);
+ printk_info("done.\n");
+}
+
+/** Starting at the root, walk the tree and call a driver to
+ * do device specific setup.
+ */
+void dev_initialize(void)
+{
+ struct device *dev;
+
+ printk_info("Initializing devices...\n");
+ for (dev = all_devices; dev; dev = dev->next) {
+ if (dev->ops->init) {
+ printk_debug("PCI: %02x:%02x.%01x init\n",
+ dev->bus->secondary,
+ PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+ dev->ops->init(dev);
+ }
+ }
+ printk_info("Devices initialized\n");
+}
+
+
diff --git a/src/devices/device_util.c b/src/devices/device_util.c
new file mode 100644
index 0000000000..fdaa20d966
--- /dev/null
+++ b/src/devices/device_util.c
@@ -0,0 +1,56 @@
+#include <console/console.h>
+#include <device.h>
+
+/**
+ * Given a bus and a devfn number, find the device structure
+ * @param bus The bus number
+ * @param devfn a device/function number
+ * @return pointer to the device structure
+ */
+struct device *dev_find_slot(unsigned int bus, unsigned int devfn)
+{
+ struct device *dev;
+
+ for (dev = all_devices; dev; dev = dev->next)
+ if (dev->bus->secondary == bus && dev->devfn == devfn)
+ break;
+ return dev;
+}
+
+/** Find a device of a given vendor and type
+ * @param vendor Vendor ID (e.g. 0x8086 for Intel)
+ * @param device Device ID
+ * @param from Pointer to the device structure, used as a starting point
+ * in the linked list of all_devices, which can be 0 to start at the
+ * head of the list (i.e. all_devices)
+ * @return Pointer to the device struct
+ */
+struct device *dev_find_device(unsigned int vendor, unsigned int device, struct device *from)
+{
+ if (!from)
+ from = all_devices;
+ else
+ from = from->next;
+ while (from && (from->vendor != vendor || from->device != device))
+ from = from->next;
+ return from;
+}
+
+/** Find a device of a given class
+ * @param class Class of the device
+ * @param from Pointer to the device structure, used as a starting point
+ * in the linked list of all_devices, which can be 0 to start at the
+ * head of the list (i.e. all_devices)
+ * @return Pointer to the device struct
+ */
+struct device *dev_find_class(unsigned int class, struct device *from)
+{
+ if (!from)
+ from = all_devices;
+ else
+ from = from->next;
+ while (from && from->class != class)
+ from = from->next;
+ return from;
+}
+
diff --git a/src/devices/pci_device.c b/src/devices/pci_device.c
new file mode 100644
index 0000000000..2b309a9ae1
--- /dev/null
+++ b/src/devices/pci_device.c
@@ -0,0 +1,670 @@
+/*
+ * PCI Bus Services, see include/linux/pci.h for further explanation.
+ *
+ * Copyright 1993 -- 1997 Drew Eckhardt, Frederic Potter,
+ * David Mosberger-Tang
+ *
+ * Copyright 1997 -- 1999 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *
+ * Copyright 2003 -- Eric Biederman <ebiederman@lnxi.com>
+ */
+
+#include <console/console.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <bitops.h>
+#include <pci.h>
+#include <pci_ids.h>
+#include <string.h>
+
+static unsigned int pci_scan_bridge(struct device *bus, unsigned int max);
+
+/** Given a device and register, read the size of the BAR for that register.
+ * @param dev Pointer to the device structure
+ * @param resource Pointer to the resource structure
+ * @param index Address of the pci configuration register
+ */
+static void pci_get_resource(struct device *dev, struct resource *resource, unsigned long index)
+{
+ uint32_t addr, size, base;
+ unsigned long type;
+
+ /* Initialize the resources to nothing */
+ resource->base = 0;
+ resource->size = 0;
+ resource->align = 0;
+ resource->gran = 0;
+ resource->limit = 0;
+ resource->flags = 0;
+ resource->index = index;
+
+ pci_read_config_dword(dev, index, &addr);
+ if (addr == 0xffffffffUL)
+ return;
+
+ /* FIXME: more consideration for 64-bit PCI devices,
+ * we currently detect their size but otherwise
+ * treat them as 32-bit resources
+ */
+ /* get the size */
+ pci_write_config_dword(dev, index, ~0);
+ pci_read_config_dword(dev, index, &size);
+
+ /* get the minimum value the bar can be set to */
+ pci_write_config_dword(dev, index, 0);
+ pci_read_config_dword(dev, index, &base);
+
+ /* restore addr */
+ pci_write_config_dword(dev, index, addr);
+
+ /*
+ * some broken hardware has read-only registers that do not
+ * really size correctly. You can tell this if addr == size
+ * Example: the acer m7229 has BARs 1-4 normally read-only.
+ * so BAR1 at offset 0x10 reads 0x1f1. If you size that register
+ * by writing 0xffffffff to it, it will read back as 0x1f1 -- a
+ * violation of the spec.
+ * We catch this case and ignore it by settting size and type to 0.
+ * This incidentally catches the common case where registers
+ * read back as 0 for both address and size.
+ */
+ if ((addr == size) && (addr == base)) {
+ if (size != 0) {
+ printk_debug(
+ "PCI: %02x:%02x.%01x register %02x(%08x), read-only ignoring it\n",
+ dev->bus->secondary,
+ PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
+ index, addr);
+ }
+ resource->flags = 0;
+ }
+ /* Now compute the actual size, See PCI Spec 6.2.5.1 ... */
+ else if (size & PCI_BASE_ADDRESS_SPACE_IO) {
+ type = size & (~PCI_BASE_ADDRESS_IO_MASK);
+ /* BUG! Top 16 bits can be zero (or not)
+ * So set them to 0xffff so they go away ...
+ */
+ resource->size = (~((size | 0xffff0000) & PCI_BASE_ADDRESS_IO_MASK)) +1;
+ resource->align = log2(resource->size);
+ resource->gran = resource->align;
+ resource->flags = IORESOURCE_IO;
+ resource->limit = 0xffff;
+ }
+ else {
+ /* A Memory mapped base address */
+ type = size & (~PCI_BASE_ADDRESS_MEM_MASK);
+ resource->size = (~(size &PCI_BASE_ADDRESS_MEM_MASK)) +1;
+ resource->align = log2(resource->size);
+ resource->gran = resource->align;
+ resource->flags = IORESOURCE_MEM;
+ if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) {
+ resource->flags |= IORESOURCE_PREFETCH;
+ }
+ type &= PCI_BASE_ADDRESS_MEM_TYPE_MASK;
+ if (type == PCI_BASE_ADDRESS_MEM_TYPE_32) {
+ /* 32bit limit */
+ resource->limit = 0xffffffffUL;
+ }
+ else if (type == PCI_BASE_ADDRESS_MEM_TYPE_1M) {
+ /* 1MB limit */
+ resource->limit = 0x000fffffUL;
+ }
+ else if (type == PCI_BASE_ADDRESS_MEM_TYPE_64) {
+ unsigned long index_hi;
+ /* 64bit limit
+ * For now just treat this as a 32bit limit
+ */
+ index_hi = index + 4;
+ resource->limit = 0xffffffffUL;
+ resource->flags |= IORESOURCE_PCI64;
+ pci_read_config_dword( dev, index_hi, &addr);
+ /* get the extended size */
+ pci_write_config_dword(dev, index_hi, 0xffffffffUL);
+ pci_read_config_dword( dev, index_hi, &size);
+
+ /* get the minimum value the bar can be set to */
+ pci_write_config_dword(dev, index_hi, 0);
+ pci_read_config_dword(dev, index_hi, &base);
+
+ /* restore addr */
+ pci_write_config_dword(dev, index_hi, addr);
+
+ if ((size == 0xffffffff) && (base == 0)) {
+ /* Clear the top half of the bar */
+ pci_write_config_dword(dev, index_hi, 0);
+ }
+ else {
+ printk_err("PCI: %02x:%02x.%01x Unable to handle 64-bit address\n",
+ dev->bus->secondary,
+ PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+ resource->flags = IORESOURCE_PCI64;
+ }
+ }
+ else {
+ /* Invalid value */
+ resource->flags = 0;
+ }
+ }
+ /* dev->size holds the flags... */
+ return;
+}
+
+/** Read the base address registers for a given device.
+ * @param dev Pointer to the dev structure
+ * @param howmany How many registers to read (6 for device, 2 for bridge)
+ */
+static void pci_read_bases(struct device *dev, unsigned int howmany)
+{
+ unsigned int reg;
+ unsigned long index;
+
+ reg = dev->resources;
+ for(index = PCI_BASE_ADDRESS_0;
+ (reg < MAX_RESOURCES) && (index < PCI_BASE_ADDRESS_0 + (howmany << 2)); ) {
+ struct resource *resource;
+ resource = &dev->resource[reg];
+ pci_get_resource(dev, resource, index);
+ reg += (resource->flags & (IORESOURCE_IO | IORESOURCE_MEM))? 1:0;
+ index += (resource->flags & IORESOURCE_PCI64)?8:4;
+ }
+ dev->resources = reg;
+}
+
+
+static void pci_bridge_read_bases(struct device *dev)
+{
+ unsigned int reg = dev->resources;
+
+ /* FIXME handle bridges without some of the optional resources */
+
+ /* Initialize the io space constraints on the current bus */
+ dev->resource[reg].base = 0;
+ dev->resource[reg].size = 0;
+ dev->resource[reg].align = log2(PCI_IO_BRIDGE_ALIGN);
+ dev->resource[reg].gran = log2(PCI_IO_BRIDGE_ALIGN);
+ dev->resource[reg].limit = 0xffffUL;
+ dev->resource[reg].flags = IORESOURCE_IO | IORESOURCE_PCI_BRIDGE;
+ dev->resource[reg].index = PCI_IO_BASE;
+ compute_allocate_resource(dev, &dev->resource[reg],
+ IORESOURCE_IO, IORESOURCE_IO);
+ reg++;
+
+ /* Initiliaze the prefetchable memory constraints on the current bus */
+ dev->resource[reg].base = 0;
+ dev->resource[reg].size = 0;
+ dev->resource[reg].align = log2(PCI_MEM_BRIDGE_ALIGN);
+ dev->resource[reg].gran = log2(PCI_MEM_BRIDGE_ALIGN);
+ dev->resource[reg].limit = 0xffffffffUL;
+ dev->resource[reg].flags = IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_PCI_BRIDGE;
+ dev->resource[reg].index = PCI_PREF_MEMORY_BASE;
+ compute_allocate_resource(dev, &dev->resource[reg],
+ IORESOURCE_MEM | IORESOURCE_PREFETCH,
+ IORESOURCE_MEM | IORESOURCE_PREFETCH);
+ reg++;
+
+ /* Initialize the memory resources on the current bus */
+ dev->resource[reg].base = 0;
+ dev->resource[reg].size = 0;
+ dev->resource[reg].align = log2(PCI_MEM_BRIDGE_ALIGN);
+ dev->resource[reg].gran = log2(PCI_MEM_BRIDGE_ALIGN);
+ dev->resource[reg].limit = 0xffffffffUL;
+ dev->resource[reg].flags = IORESOURCE_MEM | IORESOURCE_PCI_BRIDGE;
+ dev->resource[reg].index = PCI_MEMORY_BASE;
+ compute_allocate_resource(dev, &dev->resource[reg],
+ IORESOURCE_MEM | IORESOURCE_PREFETCH,
+ IORESOURCE_MEM);
+ reg++;
+
+ dev->resources = reg;
+}
+
+
+static void pci_dev_read_resources(struct device *dev)
+{
+ uint32_t addr;
+ dev->resources = 0;
+ memset(&dev->resource[0], 0, sizeof(dev->resource));
+ pci_read_bases(dev, 6);
+ pci_read_config_dword(dev, PCI_ROM_ADDRESS, &addr);
+ dev->rom_address = (addr == 0xffffffff)? 0 : addr;
+}
+
+static void pci_bus_read_resources(struct device *dev)
+{
+ uint32_t addr;
+ dev->resources = 0;
+ memset(&dev->resource[0], 0, sizeof(dev->resource));
+ pci_bridge_read_bases(dev);
+ pci_read_bases(dev, 2);
+
+ pci_read_config_dword(dev, PCI_ROM_ADDRESS1, &addr);
+ dev->rom_address = (addr == 0xffffffff)? 0 : addr;
+
+}
+
+
+static void pci_set_resource(struct device *dev, struct resource *resource)
+{
+ unsigned long base, limit;
+ unsigned long bridge_align = PCI_MEM_BRIDGE_ALIGN;
+ unsigned char buf[10];
+
+ /* Make certain the resource has actually been set */
+ if (!(resource->flags & IORESOURCE_SET)) {
+#if 1
+ printk_err("ERROR: %02x:%02x.%01x %02x not allocated\n",
+ dev->bus->secondary,
+ PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
+ resource->index);
+#endif
+ return;
+ }
+
+ /* Only handle PCI memory and IO resources for now */
+ if (!(resource->flags & (IORESOURCE_MEM |IORESOURCE_IO)))
+ return;
+
+ if (resource->flags & IORESOURCE_MEM) {
+ dev->command |= PCI_COMMAND_MEMORY;
+ bridge_align = PCI_MEM_BRIDGE_ALIGN;
+ }
+ if (resource->flags & IORESOURCE_IO) {
+ dev->command |= PCI_COMMAND_IO;
+ bridge_align = PCI_IO_BRIDGE_ALIGN;
+ }
+ if (resource->flags & IORESOURCE_PCI_BRIDGE) {
+ dev->command |= PCI_COMMAND_MASTER;
+ }
+ /* Get the base address */
+ base = resource->base;
+
+ /* Get the limit (rounded up) */
+ limit = base + ((resource->size + bridge_align - 1UL) & ~(bridge_align -1)) -1UL;
+
+ if (!(resource->flags & IORESOURCE_PCI_BRIDGE)) {
+ /*
+ * some chipsets allow us to set/clear the IO bit.
+ * (e.g. VIA 82c686a.) So set it to be safe)
+ */
+ limit = base + resource->size -1;
+ if (resource->flags & IORESOURCE_IO) {
+ base |= PCI_BASE_ADDRESS_SPACE_IO;
+ }
+ pci_write_config_dword(dev, resource->index, base & 0xffffffff);
+ if (resource->flags & IORESOURCE_PCI64) {
+ /* FIXME handle real 64bit base addresses */
+ pci_write_config_dword(dev, resource->index + 4, 0);
+ }
+ }
+ else if (resource->index == PCI_IO_BASE) {
+ /* set the IO ranges
+ * WARNING: we don't really do 32-bit addressing for IO yet!
+ */
+ compute_allocate_resource(dev, resource,
+ IORESOURCE_IO, IORESOURCE_IO);
+ pci_write_config_byte(dev, PCI_IO_BASE, base >> 8);
+ pci_write_config_byte(dev, PCI_IO_LIMIT, limit >> 8);
+ }
+ else if (resource->index == PCI_MEMORY_BASE) {
+ /* set the memory range
+ */
+ compute_allocate_resource(dev, resource,
+ IORESOURCE_MEM | IORESOURCE_PREFETCH,
+ IORESOURCE_MEM);
+ pci_write_config_word(dev, PCI_MEMORY_BASE, base >> 16);
+ pci_write_config_word(dev, PCI_MEMORY_LIMIT, limit >> 16);
+ }
+ else if (resource->index == PCI_PREF_MEMORY_BASE) {
+ /* set the prefetchable memory range
+ * WARNING: we don't really do 64-bit addressing for prefetchable memory yet!
+ */
+ compute_allocate_resource(dev, resource,
+ IORESOURCE_MEM | IORESOURCE_PREFETCH,
+ IORESOURCE_MEM | IORESOURCE_PREFETCH);
+ pci_write_config_word(dev, PCI_PREF_MEMORY_BASE, base >> 16);
+ pci_write_config_word(dev, PCI_PREF_MEMORY_LIMIT, limit >> 16);
+ }
+ else {
+ printk_err("ERROR: invalid resource->index %x\n",
+ resource->index);
+ }
+ buf[0] = '\0';
+ if (resource->flags & IORESOURCE_PCI_BRIDGE) {
+ sprintf(buf, "bus %d ", dev->secondary);
+ }
+
+ printk_debug(
+ "PCI: %02x:%02x.%01x %02x <- [0x%08lx - 0x%08lx] %s%s\n",
+ dev->bus->secondary,
+ PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
+ resource->index,
+ resource->base, limit,
+ buf,
+ (resource->flags & IORESOURCE_IO)? "io":
+ (resource->flags & IORESOURCE_PREFETCH)? "prefmem": "mem");
+ return;
+}
+
+static void pci_dev_set_resources(struct device *dev)
+{
+ struct resource *resource, *last;
+ uint8_t line;
+
+ last = &dev->resource[dev->resources];
+
+ for(resource = &dev->resource[0]; resource < last; resource++) {
+ pci_set_resource(dev, resource);
+ }
+ if (dev->children) {
+ assign_resources(dev);
+ }
+
+ /* set a default latency timer */
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40);
+
+ /* set a default secondary latency timer */
+ if ((dev->hdr_type & 0x7f) == PCI_HEADER_TYPE_BRIDGE) {
+ pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 0x40);
+ }
+
+ /* zero the irq settings */
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &line);
+ if (line) {
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 0);
+ }
+ /* set the cache line size, so far 64 bytes is good for everyone */
+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 64 >> 2);
+}
+
+struct device_operations default_pci_ops_dev = {
+ .read_resources = pci_dev_read_resources,
+ .set_resources = pci_dev_set_resources,
+ .init = 0,
+ .scan_bus = 0,
+};
+struct device_operations default_pci_ops_bus = {
+ .read_resources = pci_bus_read_resources,
+ .set_resources = pci_dev_set_resources,
+ .init = 0,
+ .scan_bus = pci_scan_bridge,
+};
+static void set_pci_ops(struct device *dev)
+{
+ struct pci_driver *driver;
+ if (dev->ops) {
+ return;
+ }
+ /* Look through the list of setup drivers and find one for
+ * this pci device
+ */
+ for(driver = &pci_drivers[0]; driver != &epci_drivers[0]; driver++) {
+ if ((driver->vendor == dev->vendor) &&
+ (driver->device = dev->device)) {
+ dev->ops = driver->ops;
+ break;
+ }
+ }
+ /* If I don't have a specific driver use the default operations */
+ switch(dev->hdr_type & 0x7f) { /* header type */
+ case PCI_HEADER_TYPE_NORMAL: /* standard header */
+ if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)
+ goto bad;
+ dev->ops = &default_pci_ops_dev;
+ break;
+ case PCI_HEADER_TYPE_BRIDGE:
+ if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
+ goto bad;
+ dev->ops = &default_pci_ops_bus;
+ break;
+ default:
+ bad:
+ printk_err("PCI: %02x:%02x.%01x [%04x/%04x/%06x] has unknown header "
+ "type %02x, ignoring.\n",
+ dev->bus->secondary,
+ PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
+ dev->vendor, dev->device,
+ dev->class >> 8, dev->hdr_type);
+ }
+ return;
+}
+
+/**
+ * Given a bus and a devfn number, find the device structure
+ * @param bus The bus structure
+ * @param devfn a device/function number
+ * @return pointer to the device structure
+ */
+static struct device *pci_scan_get_dev(struct device **list, unsigned int devfn)
+{
+ struct device *dev = 0;
+ for(; *list; list = &(*list)->sibling) {
+ if ((*list)->devfn == devfn) {
+ /* Unlink from the list */
+ dev = *list;
+ *list = (*list)->sibling;
+ dev->sibling = 0;
+ break;
+ }
+ }
+ return dev;
+}
+
+
+/** Scan the pci bus devices and bridges.
+ * @param pci_bus pointer to the bus structure
+ * @param max current bus number
+ * @return The maximum bus number found, after scanning all subordinate busses
+ */
+unsigned int pci_scan_bus(struct device *bus, unsigned int max)
+{
+ unsigned int devfn;
+ struct device *dev, **bus_last;
+ struct device *old_devices;
+ struct device *child;
+
+ printk_debug("PCI: pci_scan_bus for bus %d\n", bus->secondary);
+
+ old_devices = bus->children;
+ bus->children = 0;
+ bus_last = &bus->children;
+
+ post_code(0x24);
+
+
+ /* probe all devices on this bus with some optimization for non-existance and
+ single funcion devices */
+ for (devfn = 0; devfn < 0xff; devfn++) {
+ struct device dummy;
+ uint32_t id, class;
+ uint8_t cmd, tmp, hdr_type;
+
+ /* First thing setup the device structure */
+ dev = pci_scan_get_dev(&old_devices, devfn);
+
+ dummy.bus = bus;
+ dummy.devfn = devfn;
+ pci_read_config_dword(&dummy, PCI_VENDOR_ID, &id);
+ /* some broken boards return 0 if a slot is empty: */
+ if (!dev &&
+ (id == 0xffffffff || id == 0x00000000 ||
+ id == 0x0000ffff || id == 0xffff0000)) {
+ printk_spew("PCI: devfn 0x%x, bad id 0x%x\n", devfn, id);
+ if (PCI_FUNC(devfn) == 0x00) {
+ /* if this is a function 0 device and it is not present,
+ skip to next device */
+ devfn += 0x07;
+ }
+ /* multi function device, skip to next function */
+ continue;
+ }
+ pci_read_config_byte(&dummy, PCI_HEADER_TYPE, &hdr_type);
+ pci_read_config_dword(&dummy, PCI_CLASS_REVISION, &class);
+
+ if (!dev) {
+ if ((dev = malloc(sizeof(*dev))) == 0) {
+ printk_err("PCI: out of memory.\n");
+ continue;
+ }
+ memset(dev, 0, sizeof(*dev));
+ }
+
+ dev->bus = bus;
+ dev->devfn = devfn;
+ dev->vendor = id & 0xffff;
+ dev->device = (id >> 16) & 0xffff;
+ dev->hdr_type = hdr_type;
+ /* class code, the upper 3 bytes of PCI_CLASS_REVISION */
+ dev->class = class >> 8;
+
+ /* non-destructively determine if device can be a master: */
+ pci_read_config_byte(dev, PCI_COMMAND, &cmd);
+ pci_write_config_byte(dev, PCI_COMMAND, cmd | PCI_COMMAND_MASTER);
+ pci_read_config_byte(dev, PCI_COMMAND, &tmp);
+
+ dev->master = ((tmp & PCI_COMMAND_MASTER) != 0);
+ pci_write_config_byte(dev, PCI_COMMAND, cmd);
+
+ /* Look at the vendor and device id, or at least the
+ * header type and class and figure out which set of configuration
+ * methods to use.
+ */
+ set_pci_ops(dev);
+ /* Kill the device if we don't have some pci operations for it */
+ if (!dev->ops) {
+ free(dev);
+ continue;
+ }
+ printk_debug("PCI: %02x:%02x.%01x [%04x/%04x]\n",
+ bus->secondary, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
+ dev->vendor, dev->device);
+
+ /* Put it into the global device chain. */
+ append_device(dev);
+
+ /* Now insert it into the list of devices held by the parent bus. */
+ *bus_last = dev;
+ bus_last = &dev->sibling;
+
+ if (PCI_FUNC(devfn) == 0x00 && (hdr_type & 0x80) != 0x80) {
+ /* if this is not a multi function device, don't waste time probe
+ another function. Skip to next device. */
+ devfn += 0x07;
+ }
+ }
+ post_code(0x25);
+
+ for(child = bus->children; child; child = child->sibling) {
+ if (!child->ops->scan_bus)
+ continue;
+ max = child->ops->scan_bus(child, max);
+
+ }
+ /*
+ * We've scanned the bus and so we know all about what's on
+ * the other side of any bridges that may be on this bus plus
+ * any devices.
+ *
+ * Return how far we've got finding sub-buses.
+ */
+ printk_debug("PCI: pci_scan_bus returning with max=%02x\n", max);
+ post_code(0x55);
+ return max;
+}
+
+/** Scan the bus, first for bridges and next for devices.
+ * @param pci_bus pointer to the bus structure
+ * @return The maximum bus number found, after scanning all subordinate busses
+ */
+static unsigned int pci_scan_bridge(struct device *bus, unsigned int max)
+{
+ uint32_t buses;
+ uint16_t cr;
+ /* Set up the primary, secondary and subordinate bus numbers. We have
+ * no idea how many buses are behind this bridge yet, so we set the
+ * subordinate bus number to 0xff for the moment
+ */
+ bus->secondary = ++max;
+ bus->subordinate = 0xff;
+
+ /* Clear all status bits and turn off memory, I/O and master enables. */
+ pci_read_config_word(bus, PCI_COMMAND, &cr);
+ pci_write_config_word(bus, PCI_COMMAND, 0x0000);
+ pci_write_config_word(bus, PCI_STATUS, 0xffff);
+
+ /*
+ * Read the existing primary/secondary/subordinate bus
+ * number configuration.
+ */
+ pci_read_config_dword(bus, PCI_PRIMARY_BUS, &buses);
+
+ /* Configure the bus numbers for this bridge: the configuration
+ * transactions will not be propagated by the bridge if it is not
+ * correctly configured
+ */
+ buses &= 0xff000000;
+ buses |= (((unsigned int) (bus->bus->secondary) << 0) |
+ ((unsigned int) (bus->secondary) << 8) |
+ ((unsigned int) (bus->subordinate) << 16));
+ pci_write_config_dword(bus, PCI_PRIMARY_BUS, buses);
+
+ /* Now we can scan all subordinate buses i.e. the bus hehind the bridge */
+ max = pci_scan_bus(bus, max);
+
+ /* We know the number of buses behind this bridge. Set the subordinate
+ * bus number to its real value
+ */
+ bus->subordinate = max;
+ buses = (buses & 0xff00ffff) |
+ ((unsigned int) (bus->subordinate) << 16);
+ pci_write_config_dword(bus, PCI_PRIMARY_BUS, buses);
+ pci_write_config_word(bus, PCI_COMMAND, cr);
+
+ return max;
+}
+
+
+static void pci_root_read_resources(struct device *bus)
+{
+ int res = 0;
+ /* Initialize the system wide io space constraints */
+ bus->resource[res].base = 0x400;
+ bus->resource[res].size = 0;
+ bus->resource[res].align = 0;
+ bus->resource[res].gran = 0;
+ bus->resource[res].limit = 0xffffUL;
+ bus->resource[res].flags = IORESOURCE_IO;
+ bus->resource[res].index = PCI_IO_BASE;
+ compute_allocate_resource(bus, &bus->resource[res],
+ IORESOURCE_IO, IORESOURCE_IO);
+ res++;
+
+ /* Initialize the system wide memory resources constraints */
+ bus->resource[res].base = 0;
+ bus->resource[res].size = 0;
+ bus->resource[res].align = 0;
+ bus->resource[res].gran = 0;
+ bus->resource[res].limit = 0xffffffffUL;
+ bus->resource[res].flags = IORESOURCE_MEM;
+ bus->resource[res].index = PCI_MEMORY_BASE;
+ compute_allocate_resource(bus, &bus->resource[res],
+ IORESOURCE_MEM, IORESOURCE_MEM);
+ res++;
+
+ bus->resources = res;
+}
+static void pci_root_set_resources(struct device *bus)
+{
+ compute_allocate_resource(bus,
+ &bus->resource[0], IORESOURCE_IO, IORESOURCE_IO);
+ compute_allocate_resource(bus,
+ &bus->resource[1], IORESOURCE_MEM, IORESOURCE_MEM);
+ assign_resources(bus);
+}
+
+struct device_operations default_pci_ops_root = {
+ .read_resources = pci_root_read_resources,
+ .set_resources = pci_root_set_resources,
+ .init = 0,
+ .scan_bus = pci_scan_bus,
+};
+
diff --git a/src/include/boot/elf.h b/src/include/boot/elf.h
new file mode 100644
index 0000000000..3503388078
--- /dev/null
+++ b/src/include/boot/elf.h
@@ -0,0 +1,401 @@
+#ifndef ELF_H
+#define ELF_H
+
+/* Standard ELF types. */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <arch/boot/boot.h>
+
+/* Type for a 16-bit quantity. */
+typedef uint16_t Elf32_Half;
+typedef uint16_t Elf64_Half;
+
+/* Types for signed and unsigned 32-bit quantities. */
+typedef uint32_t Elf32_Word;
+typedef int32_t Elf32_Sword;
+typedef uint32_t Elf64_Word;
+typedef int32_t Elf64_Sword;
+
+/* Types for signed and unsigned 64-bit quantities. */
+typedef uint64_t Elf32_Xword;
+typedef int64_t Elf32_Sxword;
+typedef uint64_t Elf64_Xword;
+typedef int64_t Elf64_Sxword;
+
+/* Type of addresses. */
+typedef uint32_t Elf32_Addr;
+typedef uint64_t Elf64_Addr;
+
+/* Type of file offsets. */
+typedef uint32_t Elf32_Off;
+typedef uint64_t Elf64_Off;
+
+/* Type for section indices, which are 16-bit quantities. */
+typedef uint16_t Elf32_Section;
+typedef uint16_t Elf64_Section;
+
+/* Type of symbol indices. */
+typedef uint32_t Elf32_Symndx;
+typedef uint64_t Elf64_Symndx;
+
+
+/* The ELF file header. This appears at the start of every ELF file. */
+
+#define EI_NIDENT (16)
+
+typedef struct
+{
+ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
+ Elf32_Half e_type; /* Object file type */
+ Elf32_Half e_machine; /* Architecture */
+ Elf32_Word e_version; /* Object file version */
+ Elf32_Addr e_entry; /* Entry point virtual address */
+ Elf32_Off e_phoff; /* Program header table file offset */
+ Elf32_Off e_shoff; /* Section header table file offset */
+ Elf32_Word e_flags; /* Processor-specific flags */
+ Elf32_Half e_ehsize; /* ELF header size in bytes */
+ Elf32_Half e_phentsize; /* Program header table entry size */
+ Elf32_Half e_phnum; /* Program header table entry count */
+ Elf32_Half e_shentsize; /* Section header table entry size */
+ Elf32_Half e_shnum; /* Section header table entry count */
+ Elf32_Half e_shstrndx; /* Section header string table index */
+} Elf32_Ehdr;
+
+typedef struct
+{
+ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
+ Elf64_Half e_type; /* Object file type */
+ Elf64_Half e_machine; /* Architecture */
+ Elf64_Word e_version; /* Object file version */
+ Elf64_Addr e_entry; /* Entry point virtual address */
+ Elf64_Off e_phoff; /* Program header table file offset */
+ Elf64_Off e_shoff; /* Section header table file offset */
+ Elf64_Word e_flags; /* Processor-specific flags */
+ Elf64_Half e_ehsize; /* ELF header size in bytes */
+ Elf64_Half e_phentsize; /* Program header table entry size */
+ Elf64_Half e_phnum; /* Program header table entry count */
+ Elf64_Half e_shentsize; /* Section header table entry size */
+ Elf64_Half e_shnum; /* Section header table entry count */
+ Elf64_Half e_shstrndx; /* Section header string table index */
+} Elf64_Ehdr;
+
+/* Fields in the e_ident array. The EI_* macros are indices into the
+ array. The macros under each EI_* macro are the values the byte
+ may have. */
+
+#define EI_MAG0 0 /* File identification byte 0 index */
+#define ELFMAG0 0x7f /* Magic number byte 0 */
+
+#define EI_MAG1 1 /* File identification byte 1 index */
+#define ELFMAG1 'E' /* Magic number byte 1 */
+
+#define EI_MAG2 2 /* File identification byte 2 index */
+#define ELFMAG2 'L' /* Magic number byte 2 */
+
+#define EI_MAG3 3 /* File identification byte 3 index */
+#define ELFMAG3 'F' /* Magic number byte 3 */
+
+/* Conglomeration of the identification bytes, for easy testing as a word. */
+#define ELFMAG "\177ELF"
+#define SELFMAG 4
+
+#define EI_CLASS 4 /* File class byte index */
+#define ELFCLASSNONE 0 /* Invalid class */
+#define ELFCLASS32 1 /* 32-bit objects */
+#define ELFCLASS64 2 /* 64-bit objects */
+#define ELFCLASSNUM 3
+
+#define EI_DATA 5 /* Data encoding byte index */
+#define ELFDATANONE 0 /* Invalid data encoding */
+#define ELFDATA2LSB 1 /* 2's complement, little endian */
+#define ELFDATA2MSB 2 /* 2's complement, big endian */
+#define ELFDATANUM 3
+
+#define EI_VERSION 6 /* File version byte index */
+ /* Value must be EV_CURRENT */
+
+#define EI_OSABI 7 /* OS ABI identification */
+#define ELFOSABI_SYSV 0 /* UNIX System V ABI */
+#define ELFOSABI_HPUX 1 /* HP-UX */
+#define ELFOSABI_ARM 97 /* ARM */
+#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */
+
+#define EI_ABIVERSION 8 /* ABI version */
+
+#define EI_PAD 9 /* Byte index of padding bytes */
+
+/* Legal values for e_type (object file type). */
+
+#define ET_NONE 0 /* No file type */
+#define ET_REL 1 /* Relocatable file */
+#define ET_EXEC 2 /* Executable file */
+#define ET_DYN 3 /* Shared object file */
+#define ET_CORE 4 /* Core file */
+#define ET_NUM 5 /* Number of defined types */
+#define ET_LOPROC 0xff00 /* Processor-specific */
+#define ET_HIPROC 0xffff /* Processor-specific */
+
+/* Legal values for e_machine (architecture). */
+
+#define EM_NONE 0 /* No machine */
+#define EM_M32 1 /* AT&T WE 32100 */
+#define EM_SPARC 2 /* SUN SPARC */
+#define EM_386 3 /* Intel 80386 */
+#define EM_68K 4 /* Motorola m68k family */
+#define EM_88K 5 /* Motorola m88k family */
+#define EM_486 6 /* Intel 80486 */
+#define EM_860 7 /* Intel 80860 */
+#define EM_MIPS 8 /* MIPS R3000 big-endian */
+#define EM_S370 9 /* Amdahl */
+#define EM_MIPS_RS4_BE 10 /* MIPS R4000 big-endian */
+#define EM_RS6000 11 /* RS6000 */
+
+#define EM_PARISC 15 /* HPPA */
+#define EM_nCUBE 16 /* nCUBE */
+#define EM_VPP500 17 /* Fujitsu VPP500 */
+#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */
+#define EM_960 19 /* Intel 80960 */
+#define EM_PPC 20 /* PowerPC */
+
+#define EM_V800 36 /* NEC V800 series */
+#define EM_FR20 37 /* Fujitsu FR20 */
+#define EM_RH32 38 /* TRW RH32 */
+#define EM_MMA 39 /* Fujitsu MMA */
+#define EM_ARM 40 /* ARM */
+#define EM_FAKE_ALPHA 41 /* Digital Alpha */
+#define EM_SH 42 /* Hitachi SH */
+#define EM_SPARCV9 43 /* SPARC v9 64-bit */
+#define EM_TRICORE 44 /* Siemens Tricore */
+#define EM_ARC 45 /* Argonaut RISC Core */
+#define EM_H8_300 46 /* Hitachi H8/300 */
+#define EM_H8_300H 47 /* Hitachi H8/300H */
+#define EM_H8S 48 /* Hitachi H8S */
+#define EM_H8_500 49 /* Hitachi H8/500 */
+#define EM_IA_64 50 /* Intel Merced */
+#define EM_MIPS_X 51 /* Stanford MIPS-X */
+#define EM_COLDFIRE 52 /* Motorola Coldfire */
+#define EM_68HC12 53 /* Motorola M68HC12 */
+#define EM_NUM 54
+
+/* If it is necessary to assign new unofficial EM_* values, please
+ pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the
+ chances of collision with official or non-GNU unofficial values. */
+
+#define EM_ALPHA 0x9026
+
+/* Legal values for e_version (version). */
+
+#define EV_NONE 0 /* Invalid ELF version */
+#define EV_CURRENT 1 /* Current version */
+#define EV_NUM 2
+
+
+/* Program segment header. */
+
+typedef struct
+{
+ Elf32_Word p_type; /* Segment type */
+ Elf32_Off p_offset; /* Segment file offset */
+ Elf32_Addr p_vaddr; /* Segment virtual address */
+ Elf32_Addr p_paddr; /* Segment physical address */
+ Elf32_Word p_filesz; /* Segment size in file */
+ Elf32_Word p_memsz; /* Segment size in memory */
+ Elf32_Word p_flags; /* Segment flags */
+ Elf32_Word p_align; /* Segment alignment */
+} Elf32_Phdr;
+
+typedef struct
+{
+ Elf64_Word p_type; /* Segment type */
+ Elf64_Word p_flags; /* Segment flags */
+ Elf64_Off p_offset; /* Segment file offset */
+ Elf64_Addr p_vaddr; /* Segment virtual address */
+ Elf64_Addr p_paddr; /* Segment physical address */
+ Elf64_Xword p_filesz; /* Segment size in file */
+ Elf64_Xword p_memsz; /* Segment size in memory */
+ Elf64_Xword p_align; /* Segment alignment */
+} Elf64_Phdr;
+
+/* Legal values for p_type (segment type). */
+
+#define PT_NULL 0 /* Program header table entry unused */
+#define PT_LOAD 1 /* Loadable program segment */
+#define PT_DYNAMIC 2 /* Dynamic linking information */
+#define PT_INTERP 3 /* Program interpreter */
+#define PT_NOTE 4 /* Auxiliary information */
+#define PT_SHLIB 5 /* Reserved */
+#define PT_PHDR 6 /* Entry for header table itself */
+#define PT_NUM 7 /* Number of defined types. */
+#define PT_LOOS 0x60000000 /* Start of OS-specific */
+#define PT_HIOS 0x6fffffff /* End of OS-specific */
+#define PT_LOPROC 0x70000000 /* Start of processor-specific */
+#define PT_HIPROC 0x7fffffff /* End of processor-specific */
+
+/* Legal values for p_flags (segment flags). */
+
+#define PF_X (1 << 0) /* Segment is executable */
+#define PF_W (1 << 1) /* Segment is writable */
+#define PF_R (1 << 2) /* Segment is readable */
+#define PF_MASKPROC 0xf0000000 /* Processor-specific */
+
+
+/* Note section contents. Each entry in the note section begins with
+ a header of a fixed form. */
+
+typedef struct
+{
+ Elf32_Word n_namesz; /* Length of the note's name. */
+ Elf32_Word n_descsz; /* Length of the note's descriptor. */
+ Elf32_Word n_type; /* Type of the note. */
+} Elf32_Nhdr;
+
+typedef struct
+{
+ Elf64_Word n_namesz; /* Length of the note's name. */
+ Elf64_Word n_descsz; /* Length of the note's descriptor. */
+ Elf64_Word n_type; /* Type of the note. */
+} Elf64_Nhdr;
+
+/* Known names of notes. */
+
+/* Solaris entries in the note section have this name. */
+#define ELF_NOTE_SOLARIS "SUNW Solaris"
+
+/* Note entries for GNU systems have this name. */
+#define ELF_NOTE_GNU "GNU"
+
+
+/* Defined types of notes for Solaris. */
+
+/* Value of descriptor (one word) is desired pagesize for the binary. */
+#define ELF_NOTE_PAGESIZE_HINT 1
+
+
+/* Defined note types for GNU systems. */
+
+/* ABI information. The descriptor consists of words:
+ word 0: OS descriptor
+ word 1: major version of the ABI
+ word 2: minor version of the ABI
+ word 3: subminor version of the ABI
+*/
+#define ELF_NOTE_ABI 1
+
+/* Known OSes. These value can appear in word 0 of an ELF_NOTE_ABI
+ note section entry. */
+#define ELF_NOTE_OS_LINUX 0
+#define ELF_NOTE_OS_GNU 1
+#define ELF_NOTE_OS_SOLARIS2 2
+
+
+/* Motorola 68k specific definitions. */
+
+/* Intel 80386 specific definitions. */
+
+/* SUN SPARC specific definitions. */
+
+/* Values for Elf64_Ehdr.e_flags. */
+
+#define EF_SPARCV9_MM 3
+#define EF_SPARCV9_TSO 0
+#define EF_SPARCV9_PSO 1
+#define EF_SPARCV9_RMO 2
+#define EF_SPARC_EXT_MASK 0xFFFF00
+#define EF_SPARC_SUN_US1 0x000200
+#define EF_SPARC_HAL_R1 0x000400
+
+/* MIPS R3000 specific definitions. */
+
+/* Legal values for e_flags field of Elf32_Ehdr. */
+
+#define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used */
+#define EF_MIPS_PIC 2 /* Contains PIC code */
+#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence */
+#define EF_MIPS_XGOT 8
+#define EF_MIPS_64BIT_WHIRL 16
+#define EF_MIPS_ABI2 32
+#define EF_MIPS_ABI_ON32 64
+#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level */
+
+/* Legal values for MIPS architecture level. */
+
+#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */
+#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */
+#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */
+#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */
+#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */
+
+/* Legal values for p_type field of Elf32_Phdr. */
+
+#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */
+#define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */
+#define PT_MIPS_OPTIONS 0x70000002
+
+/* Special program header types. */
+
+#define PF_MIPS_LOCAL 0x10000000
+
+
+/* HPPA specific definitions. */
+
+/* Legal values for e_flags field of Elf32_Ehdr. */
+
+#define EF_PARISC_TRAPNL 1 /* Trap nil pointer dereference. */
+#define EF_PARISC_EXT 2 /* Program uses arch. extensions. */
+#define EF_PARISC_ARCH 0xffff0000 /* Architecture version. */
+/* Defined values are:
+ 0x020b PA-RISC 1.0 big-endian
+ 0x0210 PA-RISC 1.1 big-endian
+ 0x028b PA-RISC 1.0 little-endian
+ 0x0290 PA-RISC 1.1 little-endian
+*/
+
+
+/* Alpha specific definitions. */
+
+/* Legal values for e_flags field of Elf64_Ehdr. */
+
+#define EF_ALPHA_32BIT 1 /* All addresses must be < 2GB. */
+#define EF_ALPHA_CANRELAX 2 /* Relocations for relaxing exist. */
+
+
+/* PowerPC specific declarations */
+
+/* ARM specific declarations */
+
+/* Processor specific flags for the ELF header e_flags field. */
+#define EF_ARM_RELEXEC 0x01
+#define EF_ARM_HASENTRY 0x02
+#define EF_ARM_INTERWORK 0x04
+#define EF_ARM_APCS_26 0x08
+#define EF_ARM_APCS_FLOAT 0x10
+#define EF_ARM_PIC 0x20
+#define EF_ALIGN8 0x40 /* 8-bit structure alignment is in use */
+#define EF_NEW_ABI 0x80
+#define EF_OLD_ABI 0x100
+
+/* ARM-specific program header flags */
+#define PF_ARM_SB 0x10000000 /* Segment contains the location
+ addressed by the static base */
+
+#if ELF_CLASS == ELFCLASS32
+typedef Elf32_Ehdr Elf_ehdr;
+typedef Elf32_Phdr Elf_phdr;
+#endif
+
+#if ELF_CLASS == ELFCLASS64
+typedef Elf64_Ehdr Elf_ehdr;
+typedef Elf64_Phdr Elf_phdr;
+#endif
+
+extern int elf_check_arch(Elf_ehdr *ehdr);
+extern void jmp_to_elf_entry(void *entry, unsigned long buffer);
+struct lb_memory;
+extern int elfboot(struct lb_memory *mem);
+
+#define FIRMWARE_TYPE "LinuxBIOS"
+#define BOOTLOADER "elfboot"
+#define BOOTLOADER_VERSION "1.3"
+
+#endif /* elf.h */
diff --git a/src/include/boot/elf_boot.h b/src/include/boot/elf_boot.h
new file mode 100644
index 0000000000..ee6750d293
--- /dev/null
+++ b/src/include/boot/elf_boot.h
@@ -0,0 +1,89 @@
+#ifndef ELF_BOOT_H
+#define ELF_BOOT_H
+
+#include <stdint.h>
+
+/* This defines the structure of a table of parameters useful for ELF
+ * bootable images. These parameters are all passed and generated
+ * by the bootloader to the booted image. For simplicity and
+ * consistency the Elf Note format is reused.
+ *
+ * All of the information must be Position Independent Data.
+ * That is it must be safe to relocate the whole ELF boot parameter
+ * block without changing the meaning or correctnes of the data.
+ * Additionally it must be safe to permute the order of the ELF notes
+ * to any possible permutation without changing the meaning or correctness
+ * of the data.
+ *
+ */
+
+#define ELF_HEAD_SIZE (8*1024)
+#define ELF_BOOT_MAGIC 0x0E1FB007
+
+typedef uint16_t Elf_Half;
+typedef uint32_t Elf_Word;
+typedef uint64_t Elf_Xword;
+
+typedef struct
+{
+ Elf_Word b_signature; /* "0x0E1FB007" */
+ Elf_Word b_size;
+ Elf_Half b_checksum;
+ Elf_Half b_records;
+} Elf_Bhdr;
+
+typedef struct
+{
+ Elf_Word n_namesz; /* Length of the note's name. */
+ Elf_Word n_descsz; /* Length of the note's descriptor. */
+ Elf_Word n_type; /* Type of the note. */
+} Elf_Nhdr;
+
+
+/* For standard notes n_namesz must be zero */
+/* All of the following standard note types provide a single null
+ * terminated string in the descriptor.
+ */
+#define EBN_FIRMWARE_TYPE 0x00000001
+/* On platforms that support multiple classes of firmware this field
+ * specifies the class of firmware you are loaded under.
+ */
+#define EBN_BOOTLOADER_NAME 0x00000002
+/* This specifies just the name of the bootloader for easy comparison */
+#define EBN_BOOTLOADER_VERSION 0x00000003
+/* This specifies the version of the bootlader */
+#define EBN_COMMAND_LINE 0x00000004
+/* This specifies a command line that can be set by user interaction,
+ * and is provided as a free form string to the loaded image.
+ */
+
+
+/* Standardized Elf image notes for booting... The name for all of these is ELFBoot */
+
+#define ELF_NOTE_BOOT "ELFBoot"
+
+#define EIN_PROGRAM_NAME 0x00000001
+/* The program in this ELF file */
+#define EIN_PROGRAM_VERSION 0x00000002
+/* The version of the program in this ELF file */
+#define EIN_PROGRAM_CHECKSUM 0x00000003
+/* ip style checksum of the memory image. */
+
+
+/* Linux image notes for booting... The name for all of these is Linux */
+
+#define LINUX_NOTE_BOOT "Linux"
+
+#define LIN_COMMAND_LINE 0x00000001
+/* The command line to pass to the loaded kernel. */
+#define LIN_ROOT_DEV 0x00000002
+/* The root dev to pass to the loaded kernel. */
+#define LIN_RAMDISK_FLAGS 0x00000003
+/* Various old ramdisk flags */
+#define LIN_INITRD_START 0x00000004
+/* Start of the ramdisk in bytes */
+#define LIN_INITRD_SIZE 0x00000005
+/* Size of the ramdisk in bytes */
+
+
+#endif /* ELF_BOOT_H */
diff --git a/src/include/boot/linuxbios_tables.h b/src/include/boot/linuxbios_tables.h
new file mode 100644
index 0000000000..5f37993807
--- /dev/null
+++ b/src/include/boot/linuxbios_tables.h
@@ -0,0 +1,183 @@
+#ifndef LINUXBIOS_TABLES_H
+#define LINUXBIOS_TABLES_H
+
+#include <stdint.h>
+
+/* The linuxbios table information is for conveying information
+ * from the firmware to the loaded OS image. Primarily this
+ * is expected to be information that cannot be discovered by
+ * other means, such as quering the hardware directly.
+ *
+ * All of the information should be Position Independent Data.
+ * That is it should be safe to relocated any of the information
+ * without it's meaning/correctnes changing. For table that
+ * can reasonably be used on multiple architectures the data
+ * size should be fixed. This should ease the transition between
+ * 32 bit and 64 bit architectures etc.
+ *
+ * The completeness test for the information in this table is:
+ * - Can all of the hardware be detected?
+ * - Are the per motherboard constants available?
+ * - Is there enough to allow a kernel to run that was written before
+ * a particular motherboard is constructed? (Assuming the kernel
+ * has drivers for all of the hardware but it does not have
+ * assumptions on how the hardware is connected together).
+ *
+ * With this test it should be straight forward to determine if a
+ * table entry is required or not. This should remove much of the
+ * long term compatibility burden as table entries which are
+ * irrelevant or have been replaced by better alternatives may be
+ * dropped. Of course it is polite and expidite to include extra
+ * table entries and be backwards compatible, but it is not required.
+ */
+
+
+struct lb_header
+{
+ uint8_t signature[4]; /* LBIO */
+ uint32_t header_bytes;
+ uint32_t header_checksum;
+ uint32_t table_bytes;
+ uint32_t table_checksum;
+ uint32_t table_entries;
+};
+
+/* Every entry in the boot enviroment list will correspond to a boot
+ * info record. Encoding both type and size. The type is obviously
+ * so you can tell what it is. The size allows you to skip that
+ * boot enviroment record if you don't know what it easy. This allows
+ * forward compatibility with records not yet defined.
+ */
+struct lb_record {
+ uint32_t tag; /* tag ID */
+ uint32_t size; /* size of record (in bytes) */
+};
+
+#define LB_TAG_UNUSED 0x0000
+
+#define LB_TAG_MEMORY 0x0001
+
+struct lb_memory_range {
+ uint64_t start;
+ uint64_t size;
+ uint32_t type;
+#define LB_MEM_RAM 1 /* Memory anyone can use */
+#define LB_MEM_RESERVED 2 /* Don't use this memory region */
+#define LB_MEM_TABLE 16 /* Ram configuration tables are kept in */
+
+};
+
+struct lb_memory {
+ uint32_t tag;
+ uint32_t size;
+ struct lb_memory_range map[0];
+};
+
+#define LB_TAG_HWRPB 0x0002
+struct lb_hwrpb {
+ uint32_t tag;
+ uint32_t size;
+ uint64_t hwrpb;
+};
+
+#define LB_TAG_MAINBOARD 0x0003
+struct lb_mainboard {
+ uint32_t tag;
+ uint32_t size;
+ uint8_t vendor_idx;
+ uint8_t part_number_idx;
+ uint8_t strings[0];
+};
+
+#define LB_TAG_VERSION 0x0004
+#define LB_TAG_EXTRA_VERSION 0x0005
+#define LB_TAG_BUILD 0x0006
+#define LB_TAG_COMPILE_TIME 0x0007
+#define LB_TAG_COMPILE_BY 0x0008
+#define LB_TAG_COMPILE_HOST 0x0009
+#define LB_TAG_COMPILE_DOMAIN 0x000a
+#define LB_TAG_COMPILER 0x000b
+#define LB_TAG_LINKER 0x000c
+#define LB_TAG_ASSEMBLER 0x000d
+struct lb_string {
+ uint32_t tag;
+ uint32_t size;
+ uint8_t string[0];
+};
+
+/* The following structures are for the cmos definitions table */
+#define LB_TAG_CMOS_OPTION_TABLE 200
+/* cmos header record */
+struct cmos_option_table {
+ uint32_t tag; /* CMOS definitions table type */
+ uint32_t size; /* size of the entire table */
+ uint32_t header_length; /* length of header */
+};
+
+/* cmos entry record
+ This record is variable length. The name field may be
+ shorter than CMOS_MAX_NAME_LENGTH. The entry may start
+ anywhere in the byte, but can not span bytes unless it
+ starts at the beginning of the byte and the length is
+ fills complete bytes.
+*/
+#define LB_TAG_OPTION 201
+struct cmos_entries {
+ uint32_t tag; /* entry type */
+ uint32_t size; /* length of this record */
+ uint32_t bit; /* starting bit from start of image */
+ uint32_t length; /* length of field in bits */
+ uint32_t config; /* e=enumeration, h=hex, r=reserved */
+ uint32_t config_id; /* a number linking to an enumeration record */
+#define CMOS_MAX_NAME_LENGTH 32
+ uint8_t name[CMOS_MAX_NAME_LENGTH]; /* name of entry in ascii,
+ variable length int aligned */
+};
+
+
+/* cmos enumerations record
+ This record is variable length. The text field may be
+ shorter than CMOS_MAX_TEXT_LENGTH.
+*/
+#define LB_TAG_OPTION_ENUM 202
+struct cmos_enums {
+ uint32_t tag; /* enumeration type */
+ uint32_t size; /* length of this record */
+ uint32_t config_id; /* a number identifying the config id */
+ uint32_t value; /* the value associated with the text */
+#define CMOS_MAX_TEXT_LENGTH 32
+ uint8_t text[CMOS_MAX_TEXT_LENGTH]; /* enum description in ascii,
+ variable length int aligned */
+};
+
+/* cmos defaults record
+ This record contains default settings for the cmos ram.
+*/
+#define LB_TAG_OPTION_DEFAULTS 203
+struct cmos_defaults {
+ uint32_t tag; /* default type */
+ uint32_t size; /* length of this record */
+ uint32_t name_length; /* length of the following name field */
+ uint8_t name[CMOS_MAX_NAME_LENGTH]; /* name identifying the default */
+#define CMOS_IMAGE_BUFFER_SIZE 128
+ uint8_t default_set[CMOS_IMAGE_BUFFER_SIZE]; /* default settings */
+};
+
+#define LB_TAG_OPTION_CHECKSUM 204
+struct cmos_checksum {
+ uint32_t tag;
+ uint32_t size;
+ /* In practice everything is byte aligned, but things are measured
+ * in bits to be consistent.
+ */
+ uint32_t range_start; /* First bit that is checksummed (byte aligned) */
+ uint32_t range_end; /* Last bit that is checksummed (byte aligned) */
+ uint32_t location; /* First bit of the checksum (byte aligned) */
+ uint32_t type; /* Checksum algorithm that is used */
+#define CHECKSUM_NONE 0
+#define CHECKSUM_PCBIOS 1
+};
+
+
+
+#endif /* LINUXBIOS_TABLES_H */
diff --git a/src/include/boot/tables.h b/src/include/boot/tables.h
new file mode 100644
index 0000000000..618c32ef94
--- /dev/null
+++ b/src/include/boot/tables.h
@@ -0,0 +1,9 @@
+#ifndef BOOT_TABLES_H
+#define BOOT_TABLES_H
+
+#include <mem.h>
+#include <boot/linuxbios_tables.h>
+
+struct lb_memory *write_tables(struct mem_range *mem, unsigned long *processor_map);
+
+#endif /* BOOT_TABLES_H */
diff --git a/src/include/console/console.h b/src/include/console/console.h
new file mode 100644
index 0000000000..57ba9da268
--- /dev/null
+++ b/src/include/console/console.h
@@ -0,0 +1,76 @@
+#ifndef CONSOLE_CONSOLE_H_
+#define CONSOLE_CONSOLE_H_
+
+#include <stdint.h>
+#include <console/loglevel.h>
+
+void console_init(void);
+void console_tx_byte(unsigned char byte);
+void console_tx_flush(void);
+void post_code(uint8_t value);
+void die(char *msg);
+
+struct console_driver {
+ void (*init)(void);
+ void (*tx_byte)(unsigned char byte);
+ void (*tx_flush)(void);
+};
+
+#define __console __attribute__((unused, __section__ (".rodata.console_drivers")))
+
+/* Defined by the linker... */
+extern struct console_driver console_drivers[];
+extern struct console_driver econsole_drivers[];
+
+extern int console_loglevel;
+int do_printk(int msg_level, const char *fmt, ...);
+
+#define printk_emerg(fmt, arg...) do_printk(BIOS_EMERG ,fmt, ##arg)
+#define printk_alert(fmt, arg...) do_printk(BIOS_ALERT ,fmt, ##arg)
+#define printk_crit(fmt, arg...) do_printk(BIOS_CRIT ,fmt, ##arg)
+#define printk_err(fmt, arg...) do_printk(BIOS_ERR ,fmt, ##arg)
+#define printk_warning(fmt, arg...) do_printk(BIOS_WARNING ,fmt, ##arg)
+#define printk_notice(fmt, arg...) do_printk(BIOS_NOTICE ,fmt, ##arg)
+#define printk_info(fmt, arg...) do_printk(BIOS_INFO ,fmt, ##arg)
+#define printk_debug(fmt, arg...) do_printk(BIOS_DEBUG ,fmt, ##arg)
+#define printk_spew(fmt, arg...) do_printk(BIOS_SPEW ,fmt, ##arg)
+
+#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_EMERG
+#undef printk_emerg
+#define printk_emerg(fmt, arg...) do {} while(0)
+#endif
+#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_ALERT
+#undef printk_alert
+#define printk_alart(fmt, arg...) do {} while(0)
+#endif
+#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_CRIT
+#undef printk_crit
+#define printk_crit(fmt, arg...) do {} while(0)
+#endif
+#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_ERR
+#undef printk_err
+#define printk_err(fmt, arg...) do {} while(0)
+#endif
+#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_WARNING
+#undef printk_warning
+#define printk_warning(fmt, arg...) do {} while(0)
+#endif
+#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_NOTICE
+#undef printk_notice
+#define printk_notice(fmt, arg...) do {} while(0)
+#endif
+#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_INFO
+#undef printk_info
+#define printk_info(fmt, arg...) do {} while(0)
+#endif
+#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_DEBUG
+#undef printk_debug
+#define printk_debug(fmt, arg...) do {} while(0)
+#endif
+#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_SPEW
+#undef printk_spew
+#define printk_spew(fmt, arg...) do {} while(0)
+#endif
+
+
+#endif /* CONSOLE_CONSOLE_H_ */
diff --git a/src/include/console/loglevel.h b/src/include/console/loglevel.h
new file mode 100644
index 0000000000..a191b308d3
--- /dev/null
+++ b/src/include/console/loglevel.h
@@ -0,0 +1,30 @@
+#ifndef LOGLEVEL_H
+#define LOGLEVEL_H
+
+/* Safe for inclusion in assembly */
+
+#ifndef MAXIMUM_CONSOLE_LOGLEVEL
+#define MAXIMUM_CONSOLE_LOGLEVEL 8
+#endif
+
+#ifndef DEFAULT_CONSOLE_LOGLEVEL
+#define DEFAULT_CONSOLE_LOGLEVEL 8 /* anything MORE serious than BIOS_SPEW */
+#endif
+
+#if (DEFAULT_CONSOLE_LOGLEVEL <= MAXIMUM_CONSOLE_LOGLEVEL)
+#define ASM_CONSOLE_LOGLEVEL DEFAULT_CONSOLE_LOGLEVEL
+#else
+#define ASM_CONSOLE_LOGLEVEL MAXIMUM_CONSOLE_LOGLEVEL
+#endif
+
+#define BIOS_EMERG 0 /* system is unusable */
+#define BIOS_ALERT 1 /* action must be taken immediately */
+#define BIOS_CRIT 2 /* critical conditions */
+#define BIOS_ERR 3 /* error conditions */
+#define BIOS_WARNING 4 /* warning conditions */
+#define BIOS_NOTICE 5 /* normal but significant condition */
+#define BIOS_INFO 6 /* informational */
+#define BIOS_DEBUG 7 /* debug-level messages */
+#define BIOS_SPEW 8 /* Way too many details */
+
+#endif /* LOGLEVEL_H */
diff --git a/src/include/cpu/cpu.h b/src/include/cpu/cpu.h
new file mode 100644
index 0000000000..208dab055b
--- /dev/null
+++ b/src/include/cpu/cpu.h
@@ -0,0 +1,11 @@
+#ifndef CPU_CPU_H
+#define CPU_CPU_H
+
+#include <mem.h>
+
+unsigned long cpu_initialize(struct mem_range *mem);
+#define CPU_ENABLED 1 /* Processor is available */
+#define CPU_BOOTPROCESSOR 2 /* Processor is the BP */
+
+
+#endif /* CPU_CPU_H */
diff --git a/src/include/cpu/cpufixup.h b/src/include/cpu/cpufixup.h
new file mode 100644
index 0000000000..b23afa510a
--- /dev/null
+++ b/src/include/cpu/cpufixup.h
@@ -0,0 +1,24 @@
+#ifndef CPU_CPUFIXUP_H
+#define CPU_CPUFIXUP_H
+
+struct mem_range;
+
+#include <cpu/k8/cpufixup.h>
+#include <cpu/k7/cpufixup.h>
+#include <cpu/p6/cpufixup.h>
+
+#if CPU_FIXUP == 1
+# if defined(k8)
+# define cpufixup(mem) k8_cpufixup(mem)
+# elif defined(k7)
+# define cpufixup(mem) k7_cpufixup(mem)
+# elif defined(i786)
+# define cpufixup(mem) i786_cpufixup(mem)
+# elif defined(i686)
+# define cpufixup(mem) p6_cpufixup(mem)
+# endif
+#else
+# define cpufixup(mem) do {} while(0)
+#endif
+
+#endif /* CPU_CPUFIXUP_H */
diff --git a/src/include/cpu/k7/cpufixup.h b/src/include/cpu/k7/cpufixup.h
new file mode 100644
index 0000000000..0e3db3d655
--- /dev/null
+++ b/src/include/cpu/k7/cpufixup.h
@@ -0,0 +1,6 @@
+#ifndef CPU_K7_CPUFIXUP_H
+#define CPU_K7_CPUFIXUP_H
+
+void k7_cpufixup(struct mem_range *mem);
+
+#endif /* CPU_K7_CPUFIXUP_H */
diff --git a/src/include/cpu/k7/mtrr.h b/src/include/cpu/k7/mtrr.h
new file mode 100644
index 0000000000..ea376da2df
--- /dev/null
+++ b/src/include/cpu/k7/mtrr.h
@@ -0,0 +1,42 @@
+#ifndef CPU_K7_MTRR_H
+#define CPU_K7_MTRR_H
+
+#include <cpu/p6/mtrr.h>
+
+#define IORR_FIRST 0xC0010016
+#define IORR_LAST 0xC0010019
+#define SYSCFG 0xC0010010
+
+#define MTRR_READ_MEM (1 << 4)
+#define MTRR_WRITE_MEM (1 << 3)
+
+#define SYSCFG_MSR 0xC0010010
+#define SYSCFG_MSR_EvictEn (1 << 22)
+#define SYSCFG_MSR_TOM2En (1 << 21)
+#define SYSCFG_MSR_MtrrVarDramEn (1 << 20)
+#define SYSCFG_MSR_MtrrFixDramModEn (1 << 19)
+#define SYSCFG_MSR_MtrrFixDramEn (1 << 18)
+#define SYSCFG_MSR_UcLockEn (1 << 17)
+#define SYSCFG_MSR_ChxToDirtyDis (1 << 16)
+#define SYSCFG_MSR_SysEccEn (1 << 15)
+#define SYSCFG_MSR_RdBlkL2WayEn (1 << 14)
+#define SYSCFG_MSR_SysFillValIsD1 (1 << 13)
+#define SYSCFG_MSR_IcInclusive (1 << 12)
+#define SYSCFG_MSR_ClVicBlkEn (1 << 11)
+#define SYSCFG_MSR_SetDirtyEnO (1 << 10)
+#define SYSCFG_MSR_SetDirtyEnS (1 << 9)
+#define SYSCFG_MSR_SetDirtyEnE (1 << 8)
+#define SYSCFG_MSR_SysVicLimitMask ((1 << 8) - (1 << 5))
+#define SYSCFG_MSR_SysAckLimitMask ((1 << 5) - (1 << 0))
+
+
+
+#define IORR0_BASE 0xC0010016
+#define IORR0_MASK 0xC0010017
+#define IORR1_BASE 0xC0010018
+#define IORR1_MASK 0xC0010019
+#define TOP_MEM 0xC001001A
+#define TOP_MEM2 0xC001001D
+#define HWCR_MSR 0xC0010015
+
+#endif /* CPU_K7_MTRR_H */
diff --git a/src/include/cpu/k8/cpufixup.h b/src/include/cpu/k8/cpufixup.h
new file mode 100644
index 0000000000..9500ec216e
--- /dev/null
+++ b/src/include/cpu/k8/cpufixup.h
@@ -0,0 +1,6 @@
+#ifndef CPU_K8_CPUFIXUP_H
+#define CPU_K8_CPUFIXUP_H
+
+void k8_cpufixup(struct mem_range *mem);
+
+#endif /* CPU_K8_CPUFIXUP_H */
diff --git a/src/include/cpu/k8/mtrr.h b/src/include/cpu/k8/mtrr.h
new file mode 100644
index 0000000000..ce9e6d4d04
--- /dev/null
+++ b/src/include/cpu/k8/mtrr.h
@@ -0,0 +1,45 @@
+#ifndef CPU_K8_MTRR_H
+#define CPU_K8_MTRR_H
+
+#include <cpu/k7/mtrr.h>
+
+#if 0
+#define IORR_FIRST 0xC0010016
+#define IORR_LAST 0xC0010019
+#define SYSCFG 0xC0010010
+
+#define MTRR_READ_MEM (1 << 4)
+#define MTRR_WRITE_MEM (1 << 3)
+
+#define SYSCFG_MSR 0xC0010010
+#define SYSCFG_MSR_EvictEn (1 << 22)
+#define SYSCFG_MSR_TOM2En (1 << 21)
+#define SYSCFG_MSR_MtrrVarDramEn (1 << 20)
+#define SYSCFG_MSR_MtrrFixDramModEn (1 << 19)
+#define SYSCFG_MSR_MtrrFixDramEn (1 << 18)
+#define SYSCFG_MSR_UcLockEn (1 << 17)
+#define SYSCFG_MSR_ChxToDirtyDis (1 << 16)
+#define SYSCFG_MSR_SysEccEn (1 << 15)
+#define SYSCFG_MSR_RdBlkL2WayEn (1 << 14)
+#define SYSCFG_MSR_SysFillValIsD1 (1 << 13)
+#define SYSCFG_MSR_IcInclusive (1 << 12)
+#define SYSCFG_MSR_ClVicBlkEn (1 << 11)
+#define SYSCFG_MSR_SetDirtyEnO (1 << 10)
+#define SYSCFG_MSR_SetDirtyEnS (1 << 9)
+#define SYSCFG_MSR_SetDirtyEnE (1 << 8)
+#define SYSCFG_MSR_SysVicLimitMask ((1 << 8) - (1 << 5))
+#define SYSCFG_MSR_SysAckLimitMask ((1 << 5) - (1 << 0))
+
+
+
+#define IORR0_BASE 0xC0010016
+#define IORR0_MASK 0xC0010017
+#define IORR1_BASE 0xC0010018
+#define IORR1_MASK 0xC0010019
+#define TOP_MEM 0xC001001A
+#define TOP_MEM2 0xC001001D
+#define HWCR_MSR 0xC0010015
+
+#endif
+
+#endif /* CPU_K8_MTRR_H */
diff --git a/src/include/cpu/p5/cpuid.h b/src/include/cpu/p5/cpuid.h
new file mode 100644
index 0000000000..b8ffc88a84
--- /dev/null
+++ b/src/include/cpu/p5/cpuid.h
@@ -0,0 +1,25 @@
+#ifndef CPU_P5_CPUID_H
+#define CPU_P5_CPUID_H
+
+int mtrr_check(void);
+void display_cpuid(void);
+
+/*
+ * Generic CPUID function. copied from Linux kernel headers
+ */
+
+static inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx)
+{
+ __asm__("pushl %%ebx\n\t"
+ "cpuid\n\t"
+ "movl %%ebx, %%esi\n\t"
+ "popl %%ebx\n\t"
+ : "=a" (*eax),
+ "=S" (*ebx),
+ "=c" (*ecx),
+ "=d" (*edx)
+ : "a" (op)
+ : "cc");
+}
+
+#endif /* CPU_P5_CPUID_H */
diff --git a/src/include/cpu/p6/apic.h b/src/include/cpu/p6/apic.h
new file mode 100644
index 0000000000..b91cdb2a86
--- /dev/null
+++ b/src/include/cpu/p6/apic.h
@@ -0,0 +1,175 @@
+#ifndef APIC_H
+#define APIC_H
+
+#define APIC_BASE_MSR 0x1B
+#define APIC_BASE_MSR_BOOTSTRAP_PROCESSOR (1 << 8)
+#define APIC_BASE_MSR_ENABLE (1 << 11)
+#define APIC_BASE_MSR_ADDR_MASK 0xFFFFF000
+
+#define APIC_DEFAULT_BASE 0xfee00000
+
+#define APIC_ID 0x020
+#define APIC_LVR 0x030
+#define APIC_ARBID 0x090
+#define APIC_RRR 0x0C0
+#define APIC_SVR 0x0f0
+#define APIC_SPIV 0x0f0
+#define APIC_SPIV_ENABLE 0x100
+#define APIC_ESR 0x280
+#define APIC_ESR_SEND_CS 0x00001
+#define APIC_ESR_RECV_CS 0x00002
+#define APIC_ESR_SEND_ACC 0x00004
+#define APIC_ESR_RECV_ACC 0x00008
+#define APIC_ESR_SENDILL 0x00020
+#define APIC_ESR_RECVILL 0x00040
+#define APIC_ESR_ILLREGA 0x00080
+#define APIC_ICR 0x300
+#define APIC_DEST_SELF 0x40000
+#define APIC_DEST_ALLINC 0x80000
+#define APIC_DEST_ALLBUT 0xC0000
+#define APIC_ICR_RR_MASK 0x30000
+#define APIC_ICR_RR_INVALID 0x00000
+#define APIC_ICR_RR_INPROG 0x10000
+#define APIC_ICR_RR_VALID 0x20000
+#define APIC_INT_LEVELTRIG 0x08000
+#define APIC_INT_ASSERT 0x04000
+#define APIC_ICR_BUSY 0x01000
+#define APIC_DEST_LOGICAL 0x00800
+#define APIC_DM_FIXED 0x00000
+#define APIC_DM_LOWEST 0x00100
+#define APIC_DM_SMI 0x00200
+#define APIC_DM_REMRD 0x00300
+#define APIC_DM_NMI 0x00400
+#define APIC_DM_INIT 0x00500
+#define APIC_DM_STARTUP 0x00600
+#define APIC_DM_EXTINT 0x00700
+#define APIC_VECTOR_MASK 0x000FF
+#define APIC_ICR2 0x310
+#define GET_APIC_DEST_FIELD(x) (((x)>>24)&0xFF)
+#define SET_APIC_DEST_FIELD(x) ((x)<<24)
+#define APIC_LVTT 0x320
+#define APIC_LVTPC 0x340
+#define APIC_LVT0 0x350
+#define APIC_LVT_TIMER_BASE_MASK (0x3<<18)
+#define GET_APIC_TIMER_BASE(x) (((x)>>18)&0x3)
+#define SET_APIC_TIMER_BASE(x) (((x)<<18))
+#define APIC_TIMER_BASE_CLKIN 0x0
+#define APIC_TIMER_BASE_TMBASE 0x1
+#define APIC_TIMER_BASE_DIV 0x2
+#define APIC_LVT_TIMER_PERIODIC (1<<17)
+#define APIC_LVT_MASKED (1<<16)
+#define APIC_LVT_LEVEL_TRIGGER (1<<15)
+#define APIC_LVT_REMOTE_IRR (1<<14)
+#define APIC_INPUT_POLARITY (1<<13)
+#define APIC_SEND_PENDING (1<<12)
+#define APIC_LVT_RESERVED_1 (1<<11)
+#define APIC_DELIVERY_MODE_MASK (7<<8)
+#define APIC_DELIVERY_MODE_FIXED (0<<8)
+#define APIC_DELIVERY_MODE_NMI (4<<8)
+#define APIC_DELIVERY_MODE_EXTINT (7<<8)
+#define GET_APIC_DELIVERY_MODE(x) (((x)>>8)&0x7)
+#define SET_APIC_DELIVERY_MODE(x,y) (((x)&~0x700)|((y)<<8))
+#define APIC_MODE_FIXED 0x0
+#define APIC_MODE_NMI 0x4
+#define APIC_MODE_EXINT 0x7
+#define APIC_LVT1 0x360
+#define APIC_LVTERR 0x370
+
+
+#if !defined(ASSEMBLY)
+
+#include <console/console.h>
+
+
+#define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
+
+struct __xchg_dummy { unsigned long a[100]; };
+#define __xg(x) ((struct __xchg_dummy *)(x))
+
+/*
+ * Note: no "lock" prefix even on SMP: xchg always implies lock anyway
+ * Note 2: xchg has side effect, so that attribute volatile is necessary,
+ * but generally the primitive is invalid, *ptr is output argument. --ANK
+ */
+static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
+{
+ switch (size) {
+ case 1:
+ __asm__ __volatile__("xchgb %b0,%1"
+ :"=q" (x)
+ :"m" (*__xg(ptr)), "0" (x)
+ :"memory");
+ break;
+ case 2:
+ __asm__ __volatile__("xchgw %w0,%1"
+ :"=r" (x)
+ :"m" (*__xg(ptr)), "0" (x)
+ :"memory");
+ break;
+ case 4:
+ __asm__ __volatile__("xchgl %0,%1"
+ :"=r" (x)
+ :"m" (*__xg(ptr)), "0" (x)
+ :"memory");
+ break;
+ }
+ return x;
+}
+
+
+static inline unsigned long apic_read(unsigned long reg)
+{
+ return *((volatile unsigned long *)(APIC_DEFAULT_BASE+reg));
+}
+
+extern inline void apic_write_atomic(unsigned long reg, unsigned long v)
+{
+ xchg((volatile unsigned long *)(APIC_DEFAULT_BASE+reg), v);
+}
+
+static inline void apic_write(unsigned long reg, unsigned long v)
+{
+ *((volatile unsigned long *)(APIC_DEFAULT_BASE+reg)) = v;
+}
+
+static inline void apic_wait_icr_idle(void)
+{
+ do { } while ( apic_read( APIC_ICR ) & APIC_ICR_BUSY );
+}
+
+#ifdef CONFIG_X86_GOOD_APIC
+# define FORCE_READ_AROUND_WRITE 0
+# define apic_read_around(x) apic_read(x)
+# define apic_write_around(x,y) apic_write((x),(y))
+#else
+# define FORCE_READ_AROUND_WRITE 1
+# define apic_read_around(x) apic_read(x)
+# define apic_write_around(x,y) apic_write_atomic((x),(y))
+#endif
+
+static inline int apic_remote_read(int apicid, int reg, unsigned long *pvalue)
+{
+ int timeout;
+ unsigned long status;
+ int result;
+ apic_wait_icr_idle();
+ apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
+ apic_write_around(APIC_ICR, APIC_DM_REMRD | (reg >> 4));
+ timeout = 0;
+ do {
+#if 0
+ udelay(100);
+#endif
+ status = apic_read(APIC_ICR) & APIC_ICR_RR_MASK;
+ } while (status == APIC_ICR_RR_INPROG && timeout++ < 1000);
+
+ result = -1;
+ if (status == APIC_ICR_RR_VALID) {
+ *pvalue = apic_read(APIC_RRR);
+ result = 0;
+ }
+ return result;
+}
+#endif /* ASSEMBLY */
+
+#endif /* APIC_H */
diff --git a/src/include/cpu/p6/cpufixup.h b/src/include/cpu/p6/cpufixup.h
new file mode 100644
index 0000000000..9b0f2fa096
--- /dev/null
+++ b/src/include/cpu/p6/cpufixup.h
@@ -0,0 +1,6 @@
+#ifndef CPU_P6_CPUFIXUP_H
+#define CPU_P6_CPUFIXUP_H
+
+void p6_cpufixup(struct mem_range *mem);
+
+#endif /* CPU_P6_CPUFIXUP_H */
diff --git a/src/include/cpu/p6/msr.h b/src/include/cpu/p6/msr.h
new file mode 100644
index 0000000000..4977b0201d
--- /dev/null
+++ b/src/include/cpu/p6/msr.h
@@ -0,0 +1,33 @@
+#ifndef CPU_P6_MSR_H
+#define CPU_P6_MSR_H
+
+/*
+ * Access to machine-specific registers (available on 586 and better only)
+ * Note: the rd* operations modify the parameters directly (without using
+ * pointer indirection), this allows gcc to optimize better
+ */
+
+#define rdmsr(msr,val1,val2) \
+ __asm__ __volatile__("rdmsr" \
+ : "=a" (val1), "=d" (val2) \
+ : "c" (msr))
+
+#define wrmsr(msr,val1,val2) \
+ __asm__ __volatile__("wrmsr" \
+ : /* no outputs */ \
+ : "c" (msr), "a" (val1), "d" (val2))
+
+#define rdtsc(low,high) \
+ __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
+
+#define rdtscl(low) \
+ __asm__ __volatile__ ("rdtsc" : "=a" (low) : : "edx")
+
+#define rdtscll(val) \
+ __asm__ __volatile__ ("rdtsc" : "=A" (val))
+
+#define rdpmc(counter,low,high) \
+ __asm__ __volatile__("rdpmc" \
+ : "=a" (low), "=d" (high) \
+ : "c" (counter))
+#endif /* CPU_P6_MSR_H */
diff --git a/src/include/cpu/p6/mtrr.h b/src/include/cpu/p6/mtrr.h
new file mode 100644
index 0000000000..16af10b81b
--- /dev/null
+++ b/src/include/cpu/p6/mtrr.h
@@ -0,0 +1,44 @@
+#ifndef __LINUXBIOS_CPU_P6_MTRR_H
+#define __LINUXBIOS_CPU_P6_MTRR_H
+
+/* These are the region types */
+#define MTRR_TYPE_UNCACHABLE 0
+#define MTRR_TYPE_WRCOMB 1
+/*#define MTRR_TYPE_ 2*/
+/*#define MTRR_TYPE_ 3*/
+#define MTRR_TYPE_WRTHROUGH 4
+#define MTRR_TYPE_WRPROT 5
+#define MTRR_TYPE_WRBACK 6
+#define MTRR_NUM_TYPES 7
+
+#define MTRRcap_MSR 0x0fe
+#define MTRRdefType_MSR 0x2ff
+
+#define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg))
+#define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1)
+
+#define NUM_FIXED_RANGES 88
+#define MTRRfix64K_00000_MSR 0x250
+#define MTRRfix16K_80000_MSR 0x258
+#define MTRRfix16K_A0000_MSR 0x259
+#define MTRRfix4K_C0000_MSR 0x268
+#define MTRRfix4K_C8000_MSR 0x269
+#define MTRRfix4K_D0000_MSR 0x26a
+#define MTRRfix4K_D8000_MSR 0x26b
+#define MTRRfix4K_E0000_MSR 0x26c
+#define MTRRfix4K_E8000_MSR 0x26d
+#define MTRRfix4K_F0000_MSR 0x26e
+#define MTRRfix4K_F8000_MSR 0x26f
+
+
+#if !defined(ASSEMBLY)
+
+void set_var_mtrr(unsigned int reg, unsigned long base, unsigned long size, unsigned char type);
+#if defined(INTEL_PPRO_MTRR)
+struct mem_range;
+void setup_mtrrs(struct mem_range *mem);
+#endif
+
+#endif /* ASSEMBLY */
+
+#endif /* __LINUXBIOS_CPU_P6_MTRR_H */
diff --git a/src/include/delay.h b/src/include/delay.h
new file mode 100644
index 0000000000..bffb719a55
--- /dev/null
+++ b/src/include/delay.h
@@ -0,0 +1,8 @@
+#ifndef DELAY_H
+#define DELAY_H
+
+void udelay(int usecs);
+void mdelay(int msecs);
+void delay(int secs);
+
+#endif /* DELAY_H */
diff --git a/src/include/ip_checksum.h b/src/include/ip_checksum.h
new file mode 100644
index 0000000000..c2cb938294
--- /dev/null
+++ b/src/include/ip_checksum.h
@@ -0,0 +1,7 @@
+#ifndef IP_CHECKSUM_H
+#define IP_CHECKSUM_H
+
+unsigned long compute_ip_checksum(void *addr, unsigned long length);
+unsigned long add_ip_checksums(unsigned long offset, unsigned long sum, unsigned long new);
+
+#endif /* IP_CHECKSUM_H */
diff --git a/src/include/mem.h b/src/include/mem.h
new file mode 100644
index 0000000000..e8f633b25a
--- /dev/null
+++ b/src/include/mem.h
@@ -0,0 +1,13 @@
+#ifndef MEM_H
+#define MEM_H
+
+struct mem_range {
+ unsigned long basek;
+ unsigned long sizek;
+};
+
+/* mem_range arrays are non-overlapping, in ascending order and null terminated */
+
+struct mem_range *sizeram(void);
+
+#endif /* MEM_H */
diff --git a/src/include/part/fallback_boot.h b/src/include/part/fallback_boot.h
new file mode 100644
index 0000000000..1eb2f7bffc
--- /dev/null
+++ b/src/include/part/fallback_boot.h
@@ -0,0 +1,16 @@
+#ifndef PART_FALLBACK_BOOT_H
+#define PART_FALLBACK_BOOT_H
+
+#ifndef ASSEMBLY
+
+#if HAVE_FALLBACK_BOOT
+void boot_successful(void);
+#else
+#define boot_successful()
+#endif
+
+#endif /* ASSEMBLY */
+
+#define RTC_BOOT_BYTE 48
+
+#endif /* PART_FALLBACK_BOOT_H */
diff --git a/src/include/part/sizeram.h b/src/include/part/sizeram.h
new file mode 100644
index 0000000000..50a44f3e82
--- /dev/null
+++ b/src/include/part/sizeram.h
@@ -0,0 +1,7 @@
+#ifndef PART_SIZERAM_H
+#define PART_SIZERAM_H
+
+struct mem_rang;
+struct mem_range *sizeram(void);
+
+#endif /* PART_SIZERAM_H */
diff --git a/src/include/pc80/mc146818rtc.h b/src/include/pc80/mc146818rtc.h
new file mode 100644
index 0000000000..1daf39aa25
--- /dev/null
+++ b/src/include/pc80/mc146818rtc.h
@@ -0,0 +1,110 @@
+#ifndef PC80_MC146818RTC_H
+#define PC80_MC146818RTC_H
+
+#ifndef RTC_BASE_PORT
+#define RTC_BASE_PORT 0x70
+#endif
+
+#define RTC_PORT(x) (RTC_BASE_PORT + (x))
+
+/* On PCs, the checksum is built only over bytes 16..45 */
+#define PC_CKS_RANGE_START 16
+#define PC_CKS_RANGE_END 45
+#define PC_CKS_LOC 46
+
+
+/* Linux bios checksum is built only over bytes 49..125 */
+#define LB_CKS_RANGE_START 49
+#define LB_CKS_RANGE_END 125
+#define LB_CKS_LOC 126
+
+
+/* control registers - Moto names
+ */
+#define RTC_REG_A 10
+#define RTC_REG_B 11
+#define RTC_REG_C 12
+#define RTC_REG_D 13
+
+
+/**********************************************************************
+ * register details
+ **********************************************************************/
+#define RTC_FREQ_SELECT RTC_REG_A
+
+/* update-in-progress - set to "1" 244 microsecs before RTC goes off the bus,
+ * reset after update (may take 1.984ms @ 32768Hz RefClock) is complete,
+ * totalling to a max high interval of 2.228 ms.
+ */
+# define RTC_UIP 0x80
+# define RTC_DIV_CTL 0x70
+ /* divider control: refclock values 4.194 / 1.049 MHz / 32.768 kHz */
+# define RTC_REF_CLCK_4MHZ 0x00
+# define RTC_REF_CLCK_1MHZ 0x10
+# define RTC_REF_CLCK_32KHZ 0x20
+ /* 2 values for divider stage reset, others for "testing purposes only" */
+# define RTC_DIV_RESET1 0x60
+# define RTC_DIV_RESET2 0x70
+ /* Periodic intr. / Square wave rate select. 0=none, 1=32.8kHz,... 15=2Hz */
+# define RTC_RATE_SELECT 0x0F
+# define RTC_RATE_NONE 0x00
+# define RTC_RATE_32786HZ 0x01
+# define RTC_RATE_16384HZ 0x02
+# define RTC_RATE_8192HZ 0x03
+# define RTC_RATE_4096HZ 0x04
+# define RTC_RATE_2048HZ 0x05
+# define RTC_RATE_1024HZ 0x06
+# define RTC_RATE_512HZ 0x07
+# define RTC_RATE_256HZ 0x08
+# define RTC_RATE_128HZ 0x09
+# define RTC_RATE_64HZ 0x0a
+# define RTC_RATE_32HZ 0x0b
+# define RTC_RATE_16HZ 0x0c
+# define RTC_RATE_8HZ 0x0d
+# define RTC_RATE_4HZ 0x0e
+# define RTC_RATE_2HZ 0x0f
+
+/**********************************************************************/
+#define RTC_CONTROL RTC_REG_B
+# define RTC_SET 0x80 /* disable updates for clock setting */
+# define RTC_PIE 0x40 /* periodic interrupt enable */
+# define RTC_AIE 0x20 /* alarm interrupt enable */
+# define RTC_UIE 0x10 /* update-finished interrupt enable */
+# define RTC_SQWE 0x08 /* enable square-wave output */
+# define RTC_DM_BINARY 0x04 /* all time/date values are BCD if clear */
+# define RTC_24H 0x02 /* 24 hour mode - else hours bit 7 means pm */
+# define RTC_DST_EN 0x01 /* auto switch DST - works f. USA only */
+
+/**********************************************************************/
+#define RTC_INTR_FLAGS RTC_REG_C
+/* caution - cleared by read */
+# define RTC_IRQF 0x80 /* any of the following 3 is active */
+# define RTC_PF 0x40
+# define RTC_AF 0x20
+# define RTC_UF 0x10
+
+/**********************************************************************/
+#define RTC_VALID RTC_REG_D
+# define RTC_VRT 0x80 /* valid RAM and time */
+/**********************************************************************/
+
+
+/* On PCs, the checksum is built only over bytes 16..45 */
+#define PC_CKS_RANGE_START 16
+#define PC_CKS_RANGE_END 45
+#define PC_CKS_LOC 46
+
+#define LB_CKS_RANGE_START 49
+#define LB_CKS_RANGE_END 125
+#define LB_CKS_LOC 126
+
+#if !defined(ASSEMBLY)
+void rtc_init(int invalid);
+#if USE_OPTION_TABLE == 1
+int get_option(void *dest, char *name);
+#else
+#define get_option(dest, name) (-2)
+#endif
+#endif
+
+#endif /* PC80_MC146818RTC_H */
diff --git a/src/include/smp/atomic.h b/src/include/smp/atomic.h
new file mode 100644
index 0000000000..b36e0e2051
--- /dev/null
+++ b/src/include/smp/atomic.h
@@ -0,0 +1,53 @@
+#ifndef SMP_ATOMIC_H
+#define SMP_ATOMIC_H
+
+#ifdef SMP
+#include <arch/smp/atomic.h>
+#else
+
+typedef struct { int counter; } atomic_t;
+#define ATOMIC_INIT(i) { (i) }
+
+/**
+ * atomic_read - read atomic variable
+ * @v: pointer of type atomic_t
+ *
+ * Atomically reads the value of @v. Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
+#define atomic_read(v) ((v)->counter)
+
+/**
+ * atomic_set - set atomic variable
+ * @v: pointer of type atomic_t
+ * @i: required value
+ *
+ * Atomically sets the value of @v to @i. Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
+#define atomic_set(v,i) (((v)->counter) = (i))
+
+
+/**
+ * atomic_inc - increment atomic variable
+ * @v: pointer of type atomic_t
+ *
+ * Atomically increments @v by 1. Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
+#define atomic_inc(v) (((v)->counter)++)
+
+
+/**
+ * atomic_dec - decrement atomic variable
+ * @v: pointer of type atomic_t
+ *
+ * Atomically decrements @v by 1. Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
+#define atomic_dec(v) (((v)->counter)--)
+
+
+#endif /* SMP */
+
+#endif /* SMP_ATOMIC_H */
diff --git a/src/include/smp/spinlock.h b/src/include/smp/spinlock.h
new file mode 100644
index 0000000000..9e0f8af0a9
--- /dev/null
+++ b/src/include/smp/spinlock.h
@@ -0,0 +1,24 @@
+#ifndef SMP_SPINLOCK_H
+#define SMP_SPINLOCK_H
+
+#ifdef SMP
+#include <arch/smp/spinlock.h>
+#else /* !SMP */
+
+/* Most GCC versions have a nasty bug with empty initializers */
+#if (__GNUC__ > 2)
+typedef struct { } spinlock_t;
+#define SPIN_LOCK_UNLOCKED (spinlock_t) { }
+#else
+typedef struct { int gcc_is_buggy; } spinlock_t;
+#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
+#endif
+
+#define barrier() do {} while(0)
+#define spin_is_locked(lock) 0
+#define spin_unlock_wait(lock) do {} while(0)
+#define spin_lock(lock) do {} while(0)
+#define spin_unlock(lock) do {} while(0)
+#endif
+
+#endif /* SMP_SPINLOCK_H */
diff --git a/src/include/smp/start_stop.h b/src/include/smp/start_stop.h
new file mode 100644
index 0000000000..c0eebd0e2c
--- /dev/null
+++ b/src/include/smp/start_stop.h
@@ -0,0 +1,17 @@
+#ifndef SMP_START_STOP_H
+#define SMP_START_STOP_H
+
+#if SMP == 1
+#include <smp/atomic.h>
+unsigned long this_processors_id(void);
+int processor_index(unsigned long processor_id);
+void stop_cpu(unsigned long processor_id);
+int start_cpu(unsigned long processor_id);
+void startup_other_cpus(unsigned long *processor_map);
+#else
+#define this_processors_id() 0
+#define startup_other_cpus(p) do {} while(0)
+#define processor_index(p) 0
+#endif
+
+#endif /* SMP_START_STOP_H */
diff --git a/src/include/stdlib.h b/src/include/stdlib.h
new file mode 100644
index 0000000000..eb67d20fe7
--- /dev/null
+++ b/src/include/stdlib.h
@@ -0,0 +1,14 @@
+#ifndef STDLIB_H
+#define STDLIB_H
+
+#include <stddef.h>
+
+extern void *malloc(size_t size);
+void free(void *ptr);
+
+/* Extensions to malloc... */
+typedef size_t malloc_mark_t;
+void malloc_mark(malloc_mark_t *place);
+void malloc_release(malloc_mark_t *place);
+
+#endif /* STDLIB_H */
diff --git a/src/include/stream/read_bytes.h b/src/include/stream/read_bytes.h
new file mode 100644
index 0000000000..dd3ef04090
--- /dev/null
+++ b/src/include/stream/read_bytes.h
@@ -0,0 +1,13 @@
+#ifndef STREAM_READ_BYTES_H
+#define STREAM_READ_BYTES_H
+
+#include <stdint.h>
+
+typedef long byte_offset_t;
+
+extern int stream_init(void);
+extern byte_offset_t stream_read(void *vdest, byte_offset_t count);
+extern byte_offset_t stream_skip(byte_offset_t count);
+extern void stream_fini(void);
+
+#endif /* STREAM_READ_BYTES_H */
diff --git a/src/include/string.h b/src/include/string.h
new file mode 100644
index 0000000000..cf9bbb14d2
--- /dev/null
+++ b/src/include/string.h
@@ -0,0 +1,36 @@
+#ifndef STRING_H
+#define STRING_H
+
+#include <stddef.h>
+
+// yes, linux has fancy ones. We don't care. This stuff gets used
+// hardly at all. And the pain of including those files is just too high.
+
+//extern inline void strcpy(char *dst, char *src) {while (*src) *dst++ = *src++;}
+
+//extern inline int strlen(char *src) { int i = 0; while (*src++) i++; return i;}
+
+static inline size_t strnlen(const char *src, size_t max)
+{
+ size_t i = 0;
+ while((*src++) && (i < max)) {
+ i++;
+ }
+ return i;
+}
+
+static inline size_t strlen(const char *src)
+{
+ size_t i = 0;
+ while(*src++) {
+ i++;
+ }
+ return i;
+}
+
+extern void *memcpy(void *dest, const void *src, size_t n);
+extern void *memset(void *s, int c, size_t n);
+extern int memcmp(const void *s1, const void *s2, size_t n);
+
+extern int sprintf(char * buf, const char *fmt, ...);
+#endif /* STRING_H */
diff --git a/src/include/uart8250.h b/src/include/uart8250.h
new file mode 100644
index 0000000000..ae45615758
--- /dev/null
+++ b/src/include/uart8250.h
@@ -0,0 +1,7 @@
+#ifndef UART8250_H
+#define UART8250_H
+
+void uart8250_tx_byte(unsigned base_port, unsigned char data);
+void uart8250_init(unsigned base_port, unsigned divisor, unsigned lcs);
+
+#endif /* UART8250_H */
diff --git a/src/include/version.h b/src/include/version.h
new file mode 100644
index 0000000000..223b9a3f75
--- /dev/null
+++ b/src/include/version.h
@@ -0,0 +1,22 @@
+#ifndef VERSION_H
+#define VERSION_H
+
+/* Motherboard Information */
+extern const char mainboard_vendor[];
+extern const char mainboard_part_number[];
+
+/* LinuxBIOS Version */
+extern const char linuxbios_version[];
+extern const char linuxbios_extra_version[];
+extern const char linuxbios_build[];
+
+/* When LinuxBIOS was compiled */
+extern const char linuxbios_compile_time[];
+extern const char linuxbios_compile_by[];
+extern const char linuxbios_compile_host[];
+extern const char linuxbios_compile_domain[];
+extern const char linuxbios_compiler[];
+extern const char linuxbios_linker[];
+extern const char linuxbios_assembler[];
+
+#endif /* VERSION_H */
diff --git a/src/lib/clog2.c b/src/lib/clog2.c
new file mode 100644
index 0000000000..092b49c821
--- /dev/null
+++ b/src/lib/clog2.c
@@ -0,0 +1,18 @@
+#include <console/console.h>
+
+unsigned long log2(unsigned long x)
+{
+ // assume 8 bits per byte.
+ unsigned long i = 1 << (sizeof(x)*8 - 1);
+ unsigned long pow = sizeof(x) * 8 - 1;
+
+ if (! x) {
+ printk_warning("%s called with invalid parameter of 0\n",
+ __FUNCTION__);
+ return -1;
+ }
+ for(; i > x; i >>= 1, pow--)
+ ;
+
+ return pow;
+}
diff --git a/src/lib/compute_ip_checksum.c b/src/lib/compute_ip_checksum.c
new file mode 100644
index 0000000000..0b8eb90f85
--- /dev/null
+++ b/src/lib/compute_ip_checksum.c
@@ -0,0 +1,53 @@
+#include <stdint.h>
+#include <ip_checksum.h>
+
+unsigned long compute_ip_checksum(void *addr, unsigned long length)
+{
+ uint8_t *ptr;
+ volatile union {
+ uint8_t byte[2];
+ uint16_t word;
+ } value;
+ unsigned long sum;
+ unsigned long i;
+ /* In the most straight forward way possible,
+ * compute an ip style checksum.
+ */
+ sum = 0;
+ ptr = addr;
+ for(i = 0; i < length; i++) {
+ unsigned long value;
+ value = ptr[i];
+ if (i & 1) {
+ value <<= 8;
+ }
+ /* Add the new value */
+ sum += value;
+ /* Wrap around the carry */
+ if (sum > 0xFFFF) {
+ sum = (sum + (sum >> 16)) & 0xFFFF;
+ }
+ }
+ value.byte[0] = sum & 0xff;
+ value.byte[1] = (sum >> 8) & 0xff;
+ return (~value.word) & 0xFFFF;
+}
+
+unsigned long add_ip_checksums(unsigned long offset, unsigned long sum, unsigned long new)
+{
+ unsigned long checksum;
+ sum = ~sum & 0xFFFF;
+ new = ~new & 0xFFFF;
+ if (offset & 1) {
+ /* byte swap the sum if it came from an odd offset
+ * since the computation is endian independant this
+ * works.
+ */
+ new = ((new >> 8) & 0xff) | ((new << 8) & 0xff00);
+ }
+ checksum = sum + new;
+ if (checksum > 0xFFFF) {
+ checksum -= 0xFFFF;
+ }
+ return (~checksum) & 0xFFFF;
+}
diff --git a/src/lib/delay.c b/src/lib/delay.c
new file mode 100644
index 0000000000..af5f78613e
--- /dev/null
+++ b/src/lib/delay.c
@@ -0,0 +1,15 @@
+#include <delay.h>
+void mdelay(int msecs)
+{
+ int i;
+ for(i = 0; i < msecs; i++) {
+ udelay(1000);
+ }
+}
+void delay(int secs)
+{
+ int i;
+ for(i = 0; i < secs; i++) {
+ mdelay(1000);
+ }
+}
diff --git a/src/lib/fallback_boot.c b/src/lib/fallback_boot.c
new file mode 100644
index 0000000000..1bddd0a169
--- /dev/null
+++ b/src/lib/fallback_boot.c
@@ -0,0 +1,25 @@
+#include <console/console.h>
+#include <part/fallback_boot.h>
+#include <pc80/mc146818rtc.h>
+#include <arch/io.h>
+
+void boot_successful(void)
+{
+ /* Remember I succesfully booted by setting
+ * the initial boot direction
+ * to the direction that I booted.
+ */
+ unsigned char index, byte;
+ index = inb(RTC_PORT(0)) & 0x80;
+ index |= RTC_BOOT_BYTE;
+ outb(index, RTC_PORT(0));
+
+ byte = inb(RTC_PORT(1));
+ byte &= 0xfe;
+ byte |= (byte & 2) >> 1;
+
+ /* If we are in normal mode set the boot count to 0 */
+ if(byte & 1)
+ byte &= 0x0f;
+ outb(byte, RTC_PORT(1));
+}
diff --git a/src/lib/malloc.c b/src/lib/malloc.c
new file mode 100644
index 0000000000..bd403e47e9
--- /dev/null
+++ b/src/lib/malloc.c
@@ -0,0 +1,52 @@
+#include <stdlib.h>
+#include <console/console.h>
+
+#if 0
+#define MALLOCDBG(x)
+#else
+#define MALLOCDBG(x) printk_spew x
+#endif
+extern unsigned char _heap, _eheap;
+static size_t free_mem_ptr = (size_t)&_heap; /* Start of heap */
+static size_t free_mem_end_ptr = (size_t)&_eheap; /* End of heap */
+
+
+void malloc_mark(malloc_mark_t *place)
+{
+ *place = free_mem_ptr;
+ printk_spew("malloc_mark 0x%08lx\n", (unsigned long)free_mem_ptr);
+}
+
+void malloc_release(malloc_mark_t *ptr)
+{
+ free_mem_ptr = *ptr;
+ printk_spew("malloc_release 0x%08lx\n", (unsigned long)free_mem_ptr);
+}
+
+void *malloc(size_t size)
+{
+ void *p;
+
+ MALLOCDBG(("%s Enter, size %d, free_mem_ptr %p\n", __FUNCTION__, size, free_mem_ptr));
+ if (size < 0)
+ die("Error! malloc: Size < 0");
+ if (free_mem_ptr <= 0)
+ die("Error! malloc: Free_mem_ptr <= 0");
+
+ free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */
+
+ p = (void *) free_mem_ptr;
+ free_mem_ptr += size;
+
+ if (free_mem_ptr >= free_mem_end_ptr)
+ die("Error! malloc: Free_mem_ptr >= free_mem_end_ptr");
+
+ MALLOCDBG(("malloc 0x%08lx\n", (unsigned long)p));
+
+ return p;
+}
+
+void free(void *where)
+{
+ /* Don't care */
+}
diff --git a/src/lib/memcmp.c b/src/lib/memcmp.c
new file mode 100644
index 0000000000..46f13a41bd
--- /dev/null
+++ b/src/lib/memcmp.c
@@ -0,0 +1,17 @@
+#include <string.h>
+
+int memcmp(const void *src1, const void *src2, size_t bytes)
+{
+ const unsigned char *s1, *s2;
+ int result;
+ s1 = src1;
+ s2 = src2;
+ result = 0;
+ while((bytes > 0) && (result == 0)) {
+ result = *s1 - *s2;
+ bytes--;
+ s1++;
+ s2++;
+ }
+ return result;
+}
diff --git a/src/lib/memcpy.c b/src/lib/memcpy.c
new file mode 100644
index 0000000000..ad8e8bd3f0
--- /dev/null
+++ b/src/lib/memcpy.c
@@ -0,0 +1,11 @@
+#include <string.h>
+void *memcpy(void *__dest, __const void *__src, size_t __n)
+{
+ int i;
+ char *d = (char *) __dest, *s = (char *) __src;
+
+ for (i = 0; i < __n; i++)
+ d[i] = s[i];
+
+ return __dest;
+}
diff --git a/src/lib/memset.c b/src/lib/memset.c
new file mode 100644
index 0000000000..c1bb4f841f
--- /dev/null
+++ b/src/lib/memset.c
@@ -0,0 +1,12 @@
+#include <string.h>
+
+void *memset(void *s, int c, size_t n)
+{
+ int i;
+ char *ss = (char *) s;
+
+ for (i = 0; i < n; i++)
+ ss[i] = c;
+
+ return s;
+}
diff --git a/src/lib/uart8250.c b/src/lib/uart8250.c
new file mode 100644
index 0000000000..778919b7ff
--- /dev/null
+++ b/src/lib/uart8250.c
@@ -0,0 +1,64 @@
+#ifndef lint
+static char rcsid[] = "$Id$";
+#endif
+
+/* Should support 8250, 16450, 16550, 16550A type uarts */
+#include <arch/io.h>
+#include <uart8250.h>
+
+/* Data */
+#define UART_RBR 0x00
+#define UART_TBR 0x00
+
+/* Control */
+#define UART_IER 0x01
+#define UART_IIR 0x02
+#define UART_FCR 0x02
+#define UART_LCR 0x03
+#define UART_MCR 0x04
+#define UART_DLL 0x00
+#define UART_DLM 0x01
+
+/* Status */
+#define UART_LSR 0x05
+#define UART_MSR 0x06
+#define UART_SCR 0x07
+
+static inline int uart8250_can_tx_byte(unsigned base_port)
+{
+ return inb(base_port + UART_LSR) & 0x20;
+}
+
+static inline void uart8250_wait_to_tx_byte(unsigned base_port)
+{
+ while(!uart8250_can_tx_byte(base_port))
+ ;
+}
+
+static inline void uart8250_wait_until_sent(unsigned base_port)
+{
+ while(!(inb(base_port + UART_LSR) & 0x40))
+ ;
+}
+
+void uart8250_tx_byte(unsigned base_port, unsigned char data)
+{
+ uart8250_wait_to_tx_byte(base_port);
+ outb(data, base_port + UART_TBR);
+ /* Make certain the data clears the fifos */
+ uart8250_wait_until_sent(base_port);
+}
+
+void uart8250_init(unsigned base_port, unsigned divisor, unsigned lcs)
+{
+ lcs &= 0x7f;
+ /* disable interrupts */
+ outb(0x0, base_port + UART_IER);
+ /* enable fifo's */
+ outb(0x01, base_port + UART_FCR);
+ /* Set Baud Rate Divisor to 12 ==> 115200 Baud */
+ outb(0x80 | lcs, base_port + UART_LCR);
+ outb(divisor & 0xFF, base_port + UART_DLL);
+ outb((divisor >> 8) & 0xFF, base_port + UART_DLM);
+ outb(lcs, base_port + UART_LCR);
+}
diff --git a/src/lib/version.c b/src/lib/version.c
new file mode 100644
index 0000000000..73d52ca843
--- /dev/null
+++ b/src/lib/version.c
@@ -0,0 +1,62 @@
+#include <version.h>
+
+#define __STR(X) #X
+#define STR(X) __STR(X)
+
+#ifndef MAINBOARD_VENDOR
+#error MAINBOARD_VENDOR not defined
+#endif
+#ifndef MAINBOARD_PART_NUMBER
+#error MAINBOARD_PART_NUMBER not defined
+#endif
+
+#ifndef LINUXBIOS_VERSION
+#error LINUXBIOS_VERSION not defined
+#endif
+#ifndef LINUXBIOS_BUILD
+#error LINUXBIOS_BUILD not defined
+#endif
+
+#ifndef LINUXBIOS_COMPILE_TIME
+#error LINUXBIOS_COMPILE_TIME not defined
+#endif
+#ifndef LINUXBIOS_COMPILE_BY
+#error LINUXBIOS_COMPILE_BY not defined
+#endif
+#ifndef LINUXBIOS_COMPILE_HOST
+#error LINUXBIOS_COMPILE_HOST not defined
+#endif
+
+#ifndef LINUXBIOS_COMPILER
+#error LINUXBIOS_COMPILER not defined
+#endif
+#ifndef LINUXBIOS_LINKER
+#error LINUXBIOS_LINKER not defined
+#endif
+#ifndef LINUXBIOS_ASSEMBLER
+#error LINUXBIOS_ASSEMBLER not defined
+#endif
+
+
+#ifndef LINUXBIOS_EXTRA_VERSION
+#define LINUXBIOS_EXTRA_VERSION
+#endif
+
+const char mainboard_vendor[] = STR(MAINBOARD_VENDOR);
+const char mainboard_part_number[] = STR(MAINBOARD_PART_NUMBER);
+
+const char linuxbios_version[] = STR(LINUXBIOS_VERSION);
+const char linuxbios_extra_version[] = STR(LINUXBIOS_EXTRA_VERSION);
+const char linuxbios_build[] = STR(LINUXBIOS_BUILD);
+
+const char linuxbios_compile_time[] = STR(LINUXBIOS_COMPILE_TIME);
+const char linuxbios_compile_by[] = STR(LINUXBIOS_COMPILE_BY);
+const char linuxbios_compile_host[] = STR(LINUXBIOS_COMPILE_HOST);
+const char linuxbios_compile_domain[] = STR(LINUXBIOS_COMPILE_DOMAIN);
+const char linuxbios_compiler[] = STR(LINUXBIOS_COMPILER);
+const char linuxbios_linker[] = STR(LINUXBIOS_LINKER);
+const char linuxbios_assembler[] = STR(LINUXBIOS_ASSEMBLER);
+
+
+
+
diff --git a/src/mainboard/amd/solo/auto.c b/src/mainboard/amd/solo/auto.c
new file mode 100644
index 0000000000..bc549fac90
--- /dev/null
+++ b/src/mainboard/amd/solo/auto.c
@@ -0,0 +1,1070 @@
+#define ASSEMBLY 1
+#include "arch/romcc_io.h"
+#include "pc80/serial.c"
+#include "arch/i386/lib/console.c"
+#include "ram/ramtest.c"
+
+
+static void sdram_set_registers(void)
+{
+ static const unsigned int register_values[] = {
+ /* Routing Table Node i
+ * F0:0x40 i = 0,
+ * F0:0x44 i = 1,
+ * F0:0x48 i = 2,
+ * F0:0x4c i = 3,
+ * F0:0x50 i = 4,
+ * F0:0x54 i = 5,
+ * F0:0x58 i = 6,
+ * F0:0x5c i = 7
+ * [ 0: 3] Request Route
+ * [0] Route to this node
+ * [1] Route to Link 0
+ * [2] Route to Link 1
+ * [3] Route to Link 2
+ * [11: 8] Response Route
+ * [0] Route to this node
+ * [1] Route to Link 0
+ * [2] Route to Link 1
+ * [3] Route to Link 2
+ * [19:16] Broadcast route
+ * [0] Route to this node
+ * [1] Route to Link 0
+ * [2] Route to Link 1
+ * [3] Route to Link 2
+ */
+ 0xc040, 0xfff0f0f0, 0x00010101,
+ 0xc044, 0xfff0f0f0, 0x00010101,
+ 0xc048, 0xfff0f0f0, 0x00010101,
+ 0xc04c, 0xfff0f0f0, 0x00010101,
+ 0xc050, 0xfff0f0f0, 0x00010101,
+ 0xc054, 0xfff0f0f0, 0x00010101,
+ 0xc058, 0xfff0f0f0, 0x00010101,
+ 0xc05c, 0xfff0f0f0, 0x00010101,
+
+ /* Hypetransport Transaction Control Register
+ * F0:0x68
+ * [ 0: 0] Disable read byte probe
+ * 0 = Probes issues
+ * 1 = Probes not issued
+ * [ 1: 1] Disable Read Doubleword probe
+ * 0 = Probes issued
+ * 1 = Probes not issued
+ * [ 2: 2] Disable write byte probes
+ * 0 = Probes issued
+ * 1 = Probes not issued
+ * [ 3: 3] Disalbe Write Doubleword Probes
+ * 0 = Probes issued
+ * 1 = Probes not issued.
+ * [ 4: 4] Disable Memroy Controller Target Start
+ * 0 = TgtStart packets are generated
+ * 1 = TgtStart packets are not generated.
+ * [ 5: 5] CPU1 Enable
+ * 0 = Second CPU disabled or not present
+ * 1 = Second CPU enabled.
+ * [ 6: 6] CPU Request PassPW
+ * 0 = CPU requests do not pass posted writes
+ * 1 = CPU requests pass posted writes.
+ * [ 7: 7] CPU read Respons PassPW
+ * 0 = CPU Responses do not pass posted writes
+ * 1 = CPU responses pass posted writes.
+ * [ 8: 8] Disable Probe Memory Cancel
+ * 0 = Probes may generate MemCancels
+ * 1 = Probes may not generate MemCancels
+ * [ 9: 9] Disable Remote Probe Memory Cancel.
+ * 0 = Probes hitting dirty blocks generate memory cancel packets
+ * 1 = Only probed caches on the same node as the memory controller
+ * generate cancel packets.
+ * [10:10] Disable Fill Probe
+ * 0 = Probes issued for cache fills
+ * 1 = Probes not issued for cache fills.
+ * [11:11] Response PassPw
+ * 0 = Downstream response PassPW based on original request
+ * 1 = Downstream response PassPW set to 1
+ * [12:12] Change ISOC to Ordered
+ * 0 = Bit 1 of coherent HT RdSz/WrSz command used for iosynchronous prioritization
+ * 1 = Bit 1 of coherent HT RdSz/WrSz command used for ordering.
+ * [14:13] Buffer Release Priority select
+ * 00 = 64
+ * 01 = 16
+ * 10 = 8
+ * 11 = 2
+ * [15:15] Limit Coherent HT Configuration Space Range
+ * 0 = No coherent HT configuration space restrictions
+ * 1 = Limit coherent HT configuration space based on node count
+ * [16:16] Local Interrupt Conversion Enable.
+ * 0 = ExtInt/NMI interrups unaffected.
+ * 1 = ExtInt/NMI broadcat interrupts converted to LINT0/1
+ * [17:17] APIC Extended Broadcast Enable.
+ * 0 = APIC broadcast is 0F
+ * 1 = APIC broadcast is FF
+ * [18:18] APIC Extended ID Enable
+ * 0 = APIC ID is 4 bits.
+ * 1 = APIC ID is 8 bits.
+ * [19:19] APIC Extended Spurious Vector Enable
+ * 0 = Lower 4 bits of spurious vector are read-only 1111
+ * 1 = Lower 4 bits of spurious vecotr are writeable.
+ * [20:20] Sequence ID Source Node Enable
+ * 0 = Normal operation
+ * 1 = Keep SeqID on routed packets for debugging.
+ * [22:21] Downstream non-posted request limit
+ * 00 = No limit
+ * 01 = Limited to 1
+ * 10 = Limited to 4
+ * 11 = Limited to 8
+ * [23:23] RESERVED
+ * [25:24] Medium-Priority Bypass Count
+ * - Maximum # of times a medium priority access can pass a low
+ * priority access before Medium-Priority mode is disabled for one access.
+ * [27:26] High-Priority Bypass Count
+ * - Maximum # of times a high prioirty access can pass a medium or low
+ * priority access before High-prioirty mode is disabled for one access.
+ * [28:28] Enable High Priority CPU Reads
+ * 0 = Cpu reads are medium prioirty
+ * 1 = Cpu reads are high prioirty
+ * [29:29] Disable Low Priority Writes
+ * 0 = Non-isochronous writes are low priority
+ * 1 = Non-isochronous writes are medium prioirty
+ * [30:30] Disable High Priority Isochronous writes
+ * 0 = Isochronous writes are high priority
+ * 1 = Isochronous writes are medium priority
+ * [31:31] Disable Medium Priority Isochronous writes
+ * 0 = Isochronous writes are medium are high
+ * 1 = With bit 30 set makes Isochrouns writes low priority.
+ */
+ 0xc068, 0x00800000, 0x0f00840f,
+ /* HT Initialization Control Register
+ * F0:0x68
+ * [ 0: 0] Routing Table Disable
+ * 0 = Packets are routed according to routing tables
+ * 1 = Packets are routed according to the default link field
+ * [ 1: 1] Request Disable (BSP should clear this)
+ * 0 = Request packets may be generated
+ * 1 = Request packets may not be generated.
+ * [ 3: 2] Default Link (Read-only)
+ * 00 = LDT0
+ * 01 = LDT1
+ * 10 = LDT2
+ * 11 = CPU on same node
+ * [ 4: 4] Cold Reset
+ * - Scratch bit cleared by a cold reset
+ * [ 5: 5] BIOS Reset Detect
+ * - Scratch bit cleared by a cold reset
+ * [ 6: 6] INIT Detect
+ * - Scratch bit cleared by a warm or cold reset not by an INIT
+ *
+ */
+ 0xc06C, 0xffffff8c, 0x00000000,
+ /* LDTi Capabilities Registers
+ * F0:0x80 i = 0,
+ * F0:0xA0 i = 1,
+ * F0:0xC0 i = 2,
+ */
+ /* LDTi Link Control Registrs
+ * F0:0x84 i = 0,
+ * F0:0xA4 i = 1,
+ * F0:0xC4 i = 2,
+ * [ 1: 1] CRC Flood Enable
+ * 0 = Do not generate sync packets on CRC error
+ * 1 = Generate sync packets on CRC error
+ * [ 2: 2] CRC Start Test (Read-Only)
+ * [ 3: 3] CRC Force Frame Error
+ * 0 = Do not generate bad CRC
+ * 1 = Generate bad CRC
+ * [ 4: 4] Link Failure
+ * 0 = No link failure detected
+ * 1 = Link failure detected
+ * [ 5: 5] Initialization Complete
+ * 0 = Initialization not complete
+ * 1 = Initialization complete
+ * [ 6: 6] Receiver off
+ * 0 = Recevier on
+ * 1 = Receiver off
+ * [ 7: 7] Transmitter Off
+ * 0 = Transmitter on
+ * 1 = Transmitter off
+ * [ 9: 8] CRC_Error
+ * 00 = No error
+ * [0] = 1 Error on byte lane 0
+ * [1] = 1 Error on byte lane 1
+ * [12:12] Isochrnous Enable (Read-Only)
+ * [13:13] HT Stop Tristate Enable
+ * 0 = Driven during an LDTSTOP_L
+ * 1 = Tristated during and LDTSTOP_L
+ * [14:14] Extended CTL Time
+ * 0 = CTL is asserted for 16 bit times during link initialization
+ * 1 = CTL is asserted for 50us during link initialization
+ * [18:16] Max Link Width In (Read-Only?)
+ * 000 = 8 bit link
+ * 001 = 16bit link
+ * [19:19] Doubleword Flow Control in (Read-Only)
+ * 0 = This link does not support doubleword flow control
+ * 1 = This link supports doubleword flow control
+ * [22:20] Max Link Width Out (Read-Only?)
+ * 000 = 8 bit link
+ * 001 = 16bit link
+ * [23:23] Doubleworld Flow Control out (Read-Only)
+ * 0 = This link does not support doubleword flow control
+ * 1 = This link supports doubleworkd flow control
+ * [26:24] Link Width In
+ * 000 = Use 8 bits
+ * 001 = Use 16 bits
+ * 010 = reserved
+ * 011 = Use 32 bits
+ * 100 = Use 2 bits
+ * 101 = Use 4 bits
+ * 110 = reserved
+ * 111 = Link physically not connected
+ * [27:27] Doubleword Flow Control In Enable
+ * 0 = Doubleword flow control disabled
+ * 1 = Doubleword flow control enabled (Not currently supported)
+ * [30:28] Link Width Out
+ * 000 = Use 8 bits
+ * 001 = Use 16 bits
+ * 010 = reserved
+ * 011 = Use 32 bits
+ * 100 = Use 2 bits
+ * 101 = Use 4 bits
+ * 110 = reserved
+ * 111 = Link physically not connected
+ * [31:31] Doubleworld Flow Control Out Enable
+ * 0 = Doubleworld flow control disabled
+ * 1 = Doubleword flow control enabled (Not currently supported)
+ */
+ 0xc084, 0x00009c05, 0x11110020,
+ /* LDTi Frequency/Revision Registers
+ * F0:0x88 i = 0,
+ * F0:0xA8 i = 1,
+ * F0:0xC8 i = 2,
+ * [ 4: 0] Minor Revision
+ * Contains the HT Minor revision
+ * [ 7: 5] Major Revision
+ * Contains the HT Major revision
+ * [11: 8] Link Frequency (Takes effect the next time the link is reconnected)
+ * 0000 = 200Mhz
+ * 0001 = reserved
+ * 0010 = 400Mhz
+ * 0011 = reserved
+ * 0100 = 600Mhz
+ * 0101 = 800Mhz
+ * 0110 = 1000Mhz
+ * 0111 = reserved
+ * 1000 = reserved
+ * 1001 = reserved
+ * 1010 = reserved
+ * 1011 = reserved
+ * 1100 = reserved
+ * 1101 = reserved
+ * 1110 = reserved
+ * 1111 = 100 Mhz
+ * [15:12] Error (Not currently Implemented)
+ * [31:16] Indicates the frequency capabilities of the link
+ * [16] = 1 encoding 0000 of freq supported
+ * [17] = 1 encoding 0001 of freq supported
+ * [18] = 1 encoding 0010 of freq supported
+ * [19] = 1 encoding 0011 of freq supported
+ * [20] = 1 encoding 0100 of freq supported
+ * [21] = 1 encoding 0101 of freq supported
+ * [22] = 1 encoding 0110 of freq supported
+ * [23] = 1 encoding 0111 of freq supported
+ * [24] = 1 encoding 1000 of freq supported
+ * [25] = 1 encoding 1001 of freq supported
+ * [26] = 1 encoding 1010 of freq supported
+ * [27] = 1 encoding 1011 of freq supported
+ * [28] = 1 encoding 1100 of freq supported
+ * [29] = 1 encoding 1101 of freq supported
+ * [30] = 1 encoding 1110 of freq supported
+ * [31] = 1 encoding 1111 of freq supported
+ */
+ 0xC088, 0xfffff0ff, 0x00000200,
+ /* LDTi Feature Capability
+ * F0:0x8C i = 0,
+ * F0:0xAC i = 1,
+ * F0:0xCC i = 2,
+ */
+ /* LDTi Buffer Count Registers
+ * F0:0x90 i = 0,
+ * F0:0xB0 i = 1,
+ * F0:0xD0 i = 2,
+ */
+ /* LDTi Bus Number Registers
+ * F0:0x94 i = 0,
+ * F0:0xB4 i = 1,
+ * F0:0xD4 i = 2,
+ * For NonCoherent HT specifies the bus number downstream (behind the host bridge)
+ * [ 0: 7] Primary Bus Number
+ * [15: 8] Secondary Bus Number
+ * [23:15] Subordiante Bus Number
+ * [31:24] reserved
+ */
+ 0xC094, 0xff000000, 0x00ff0000,
+ /* LDTi Type Registers
+ * F0:0x98 i = 0,
+ * F0:0xB8 i = 1,
+ * F0:0xD8 i = 2,
+ */
+ /* Careful set limit registers before base registers which contain the enables */
+ /* DRAM Limit i Registers
+ * F1:0x44 i = 0
+ * F1:0x4C i = 1
+ * F1:0x54 i = 2
+ * F1:0x5C i = 3
+ * F1:0x64 i = 4
+ * F1:0x6C i = 5
+ * F1:0x74 i = 6
+ * F1:0x7C i = 7
+ * [ 2: 0] Destination Node ID
+ * 000 = Node 0
+ * 001 = Node 1
+ * 010 = Node 2
+ * 011 = Node 3
+ * 100 = Node 4
+ * 101 = Node 5
+ * 110 = Node 6
+ * 111 = Node 7
+ * [ 7: 3] Reserved
+ * [10: 8] Interleave select
+ * specifies the values of A[14:12] to use with interleave enable.
+ * [15:11] Reserved
+ * [31:16] DRAM Limit Address i Bits 39-24
+ * This field defines the upper address bits of a 40 bit address
+ * that define the end of the DRAM region.
+ */
+ 0xC144, 0x0000f8f8, 0x003f0000,
+ 0xC148, 0x0000f8f8, 0x00000001,
+ 0xC154, 0x0000f8f8, 0x00000002,
+ 0xC158, 0x0000f8f8, 0x00000003,
+ 0xC164, 0x0000f8f8, 0x00000004,
+ 0xC168, 0x0000f8f8, 0x00000005,
+ 0xC174, 0x0000f8f8, 0x00000006,
+ 0xC178, 0x0000f8f8, 0x00000007,
+ /* DRAM Base i Registers
+ * F1:0x40 i = 0
+ * F1:0x48 i = 1
+ * F1:0x50 i = 2
+ * F1:0x58 i = 3
+ * F1:0x60 i = 4
+ * F1:0x68 i = 5
+ * F1:0x70 i = 6
+ * F1:0x78 i = 7
+ * [ 0: 0] Read Enable
+ * 0 = Reads Disabled
+ * 1 = Reads Enabled
+ * [ 1: 1] Write Enable
+ * 0 = Writes Disabled
+ * 1 = Writes Enabled
+ * [ 7: 2] Reserved
+ * [10: 8] Interleave Enable
+ * 000 = No interleave
+ * 001 = Interleave on A[12] (2 nodes)
+ * 010 = reserved
+ * 011 = Interleave on A[12] and A[14] (4 nodes)
+ * 100 = reserved
+ * 101 = reserved
+ * 110 = reserved
+ * 111 = Interleve on A[12] and A[13] and A[14] (8 nodes)
+ * [15:11] Reserved
+ * [13:16] DRAM Base Address i Bits 39-24
+ * This field defines the upper address bits of a 40-bit address
+ * that define the start of the DRAM region.
+ */
+ 0xC140, 0x0000f8fc, 0x00000003,
+ 0xC148, 0x0000f8fc, 0x00400000,
+ 0xC150, 0x0000f8fc, 0x00400000,
+ 0xC158, 0x0000f8fc, 0x00400000,
+ 0xC160, 0x0000f8fc, 0x00400000,
+ 0xC168, 0x0000f8fc, 0x00400000,
+ 0xC170, 0x0000f8fc, 0x00400000,
+ 0xC178, 0x0000f8fc, 0x00400000,
+
+ /* Memory-Mapped I/O Limit i Registers
+ * F1:0x84 i = 0
+ * F1:0x8C i = 1
+ * F1:0x94 i = 2
+ * F1:0x9C i = 3
+ * F1:0xA4 i = 4
+ * F1:0xAC i = 5
+ * F1:0xB4 i = 6
+ * F1:0xBC i = 7
+ * [ 2: 0] Destination Node ID
+ * 000 = Node 0
+ * 001 = Node 1
+ * 010 = Node 2
+ * 011 = Node 3
+ * 100 = Node 4
+ * 101 = Node 5
+ * 110 = Node 6
+ * 111 = Node 7
+ * [ 3: 3] Reserved
+ * [ 5: 4] Destination Link ID
+ * 00 = Link 0
+ * 01 = Link 1
+ * 10 = Link 2
+ * 11 = Reserved
+ * [ 6: 6] Reserved
+ * [ 7: 7] Non-Posted
+ * 0 = CPU writes may be posted
+ * 1 = CPU writes must be non-posted
+ * [31: 8] Memory-Mapped I/O Limit Address i (39-16)
+ * This field defines the upp adddress bits of a 40-bit address that
+ * defines the end of a memory-mapped I/O region n
+ */
+ 0xC184, 0x00000048, 0x00e1ff00,
+ 0xC18C, 0x00000048, 0x00dfff00,
+ 0xC194, 0x00000048, 0x00e3ff00,
+ 0xC19C, 0x00000048, 0x00000000,
+ 0xC1A4, 0x00000048, 0x00000000,
+ 0xC1AC, 0x00000048, 0x00000000,
+ 0xC1B4, 0x00000048, 0x00000b00,
+
+
+ /* Memory-Mapped I/O Base i Registers
+ * F1:0x80 i = 0
+ * F1:0x88 i = 1
+ * F1:0x90 i = 2
+ * F1:0x98 i = 3
+ * F1:0xA0 i = 4
+ * F1:0xA8 i = 5
+ * F1:0xB0 i = 6
+ * F1:0xB8 i = 7
+ * [ 0: 0] Read Enable
+ * 0 = Reads disabled
+ * 1 = Reads Enabled
+ * [ 1: 1] Write Enable
+ * 0 = Writes disabled
+ * 1 = Writes Enabled
+ * [ 2: 2] Cpu Disable
+ * 0 = Cpu can use this I/O range
+ * 1 = Cpu requests do not use this I/O range
+ * [ 3: 3] Lock
+ * 0 = base/limit registers i are read/write
+ * 1 = base/limit registers i are read-only
+ * [ 7: 4] Reserved
+ * [31: 8] Memory-Mapped I/O Base Address i (39-16)
+ * This field defines the upper address bits of a 40bit address
+ * that defines the start of memory-mapped I/O region i
+ */
+ 0xC1BC, 0x00000048, 0x00fe0b00,
+ 0xC180, 0x000000f0, 0x00e00003,
+ 0xC188, 0x000000f0, 0x00d80003,
+ 0xC190, 0x000000f0, 0x00e20003,
+ 0xC198, 0x000000f0, 0x00000000,
+ 0xC1A0, 0x000000f0, 0x00000000,
+ 0xC1A8, 0x000000f0, 0x00000000,
+ 0xC1B0, 0x000000f0, 0x0000a003,
+ 0xC1B8, 0x000000f0, 0x00400003,
+
+ /* PCI I/O Limit i Registers
+ * F1:0xC4 i = 0
+ * F1:0xCC i = 1
+ * F1:0xD4 i = 2
+ * F1:0xDC i = 3
+ * [ 2: 0] Destination Node ID
+ * 000 = Node 0
+ * 001 = Node 1
+ * 010 = Node 2
+ * 011 = Node 3
+ * 100 = Node 4
+ * 101 = Node 5
+ * 110 = Node 6
+ * 111 = Node 7
+ * [ 3: 3] Reserved
+ * [ 5: 4] Destination Link ID
+ * 00 = Link 0
+ * 01 = Link 1
+ * 10 = Link 2
+ * 11 = reserved
+ * [11: 6] Reserved
+ * [24:12] PCI I/O Limit Address i
+ * This field defines the end of PCI I/O region n
+ * [31:25] Reserved
+ */
+ 0xC1C4, 0xFE000FC8, 0x0000d000,
+ 0xC1CC, 0xFE000FC8, 0x000ff000,
+ 0xC1D4, 0xFE000FC8, 0x00000000,
+ 0xC1DC, 0xFE000FC8, 0x00000000,
+
+ /* PCI I/O Base i Registers
+ * F1:0xC0 i = 0
+ * F1:0xC8 i = 1
+ * F1:0xD0 i = 2
+ * F1:0xD8 i = 3
+ * [ 0: 0] Read Enable
+ * 0 = Reads Disabled
+ * 1 = Reads Enabled
+ * [ 1: 1] Write Enable
+ * 0 = Writes Disabled
+ * 1 = Writes Enabled
+ * [ 3: 2] Reserved
+ * [ 4: 4] VGA Enable
+ * 0 = VGA matches Disabled
+ * 1 = matches all address < 64K and where A[9:0] is in the
+ * range 3B0-3BB or 3C0-3DF independen of the base & limit registers
+ * [ 5: 5] ISA Enable
+ * 0 = ISA matches Disabled
+ * 1 = Blocks address < 64K and in the last 768 bytes of eack 1K block
+ * from matching agains this base/limit pair
+ * [11: 6] Reserved
+ * [24:12] PCI I/O Base i
+ * This field defines the start of PCI I/O region n
+ * [31:25] Reserved
+ */
+ 0xC1C0, 0xFE000FCC, 0x0000d003,
+ 0xC1C8, 0xFE000FCC, 0x00001013,
+ 0xC1D0, 0xFE000FCC, 0x00000000,
+ 0xC1D8, 0xFE000FCC, 0x00000000,
+
+ /* Config Base and Limit i Registers
+ * F1:0xE0 i = 0
+ * F1:0xE4 i = 1
+ * F1:0xE8 i = 2
+ * F1:0xEC i = 3
+ * [ 0: 0] Read Enable
+ * 0 = Reads Disabled
+ * 1 = Reads Enabled
+ * [ 1: 1] Write Enable
+ * 0 = Writes Disabled
+ * 1 = Writes Enabled
+ * [ 2: 2] Device Number Compare Enable
+ * 0 = The ranges are based on bus number
+ * 1 = The ranges are ranges of devices on bus 0
+ * [ 3: 3] Reserved
+ * [ 6: 4] Destination Node
+ * 000 = Node 0
+ * 001 = Node 1
+ * 010 = Node 2
+ * 011 = Node 3
+ * 100 = Node 4
+ * 101 = Node 5
+ * 110 = Node 6
+ * 111 = Node 7
+ * [ 7: 7] Reserved
+ * [ 9: 8] Destination Link
+ * 00 = Link 0
+ * 01 = Link 1
+ * 10 = Link 2
+ * 11 - Reserved
+ * [15:10] Reserved
+ * [23:16] Bus Number Base i
+ * This field defines the lowest bus number in configuration region i
+ * [31:24] Bus Number Limit i
+ * This field defines the highest bus number in configuration regin i
+ */
+ 0xC1E0, 0x0000FC88, 0xff000003,
+ 0xC1E4, 0x0000FC88, 0x00000000,
+ 0xC1E8, 0x0000FC88, 0x00000000,
+ 0xC1EC, 0x0000FC88, 0x00000000,
+
+ /* DRAM CS Base Address i Registers
+ * F2:0x40 i = 0
+ * F2:0x44 i = 1
+ * F2:0x48 i = 2
+ * F2:0x4C i = 3
+ * F2:0x50 i = 4
+ * F2:0x54 i = 5
+ * F2:0x58 i = 6
+ * F2:0x5C i = 7
+ * [ 0: 0] Chip-Select Bank Enable
+ * 0 = Bank Disabled
+ * 1 = Bank Enabled
+ * [ 8: 1] Reserved
+ * [15: 9] Base Address (19-13)
+ * An optimization used when all DIMM are the same size...
+ * [20:16] Reserved
+ * [31:21] Base Address (35-25)
+ * This field defines the top 11 addresses bit of a 40-bit
+ * address that define the memory address space. These
+ * bits decode 32-MByte blocks of memory.
+ */
+ 0xC240, 0x001f01fe, 0x00000001,
+ 0xC244, 0x001f01fe, 0x01000001,
+ 0xC248, 0x001f01fe, 0x02000001,
+ 0xC24C, 0x001f01fe, 0x03000001,
+ 0xC250, 0x001f01fe, 0x00000000,
+ 0xC254, 0x001f01fe, 0x00000000,
+ 0xC258, 0x001f01fe, 0x00000000,
+ 0xC25C, 0x001f01fe, 0x00000000,
+ /* DRAM CS Mask Address i Registers
+ * F2:0x60 i = 0
+ * F2:0x64 i = 1
+ * F2:0x68 i = 2
+ * F2:0x6C i = 3
+ * F2:0x70 i = 4
+ * F2:0x74 i = 5
+ * F2:0x78 i = 6
+ * F2:0x7C i = 7
+ * Select bits to exclude from comparison with the DRAM Base address register.
+ * [ 8: 0] Reserved
+ * [15: 9] Address Mask (19-13)
+ * Address to be excluded from the optimized case
+ * [20:16] Reserved
+ * [29:21] Address Mask (33-25)
+ * The bits with an address mask of 1 are excluded from address comparison
+ * [31:30] Reserved
+ *
+ */
+ 0xC260, 0xC01f01ff, 0x00e0fe00,
+ 0xC264, 0xC01f01ff, 0x00e0fe00,
+ 0xC268, 0xC01f01ff, 0x00e0fe00,
+ 0xC26C, 0xC01f01ff, 0x00e0fe00,
+ 0xC270, 0xC01f01ff, 0x00000000,
+ 0xC274, 0xC01f01ff, 0x00000000,
+ 0xC278, 0xC01f01ff, 0x00000000,
+ 0xC27C, 0xC01f01ff, 0x00000000,
+ /* DRAM Bank Address Mapping Register
+ * F2:0x80
+ * Specify the memory module size
+ * [ 2: 0] CS1/0
+ * [ 6: 4] CS3/2
+ * [10: 8] CS5/4
+ * [14:12] CS7/6
+ * 000 = 32Mbyte (Rows = 12 & Col = 8)
+ * 001 = 64Mbyte (Rows = 12 & Col = 9)
+ * 010 = 128Mbyte (Rows = 13 & Col = 9)|(Rows = 12 & Col = 10)
+ * 011 = 256Mbyte (Rows = 13 & Col = 10)|(Rows = 12 & Col = 11)
+ * 100 = 512Mbyte (Rows = 13 & Col = 11)|(Rows = 14 & Col = 10)
+ * 101 = 1Gbyte (Rows = 14 & Col = 11)|(Rows = 13 & Col = 12)
+ * 110 = 2Gbyte (Rows = 14 & Col = 12)
+ * 111 = reserved
+ * [ 3: 3] Reserved
+ * [ 7: 7] Reserved
+ * [11:11] Reserved
+ * [31:15]
+ */
+ 0xC280, 0xffff8888, 0x00000033,
+ /* DRAM Timing Low Register
+ * F2:0x88
+ * [ 2: 0] Tcl (Cas# Latency, Cas# to read-data-valid)
+ * 000 = reserved
+ * 001 = CL 2
+ * 010 = CL 3
+ * 011 = reserved
+ * 100 = reserved
+ * 101 = CL 2.5
+ * 110 = reserved
+ * 111 = reserved
+ * [ 3: 3] Reserved
+ * [ 7: 4] Trc (Row Cycle Time, Ras#-active to Ras#-active/bank auto refresh)
+ * 0000 = 7 bus clocks
+ * 0001 = 8 bus clocks
+ * ...
+ * 1110 = 21 bus clocks
+ * 1111 = 22 bus clocks
+ * [11: 8] Trfc (Row refresh Cycle time, Auto-refresh-active to RAS#-active or RAS#auto-refresh)
+ * 0000 = 9 bus clocks
+ * 0010 = 10 bus clocks
+ * ....
+ * 1110 = 23 bus clocks
+ * 1111 = 24 bus clocks
+ * [14:12] Trcd (Ras#-active to Case#-read/write Delay)
+ * 000 = reserved
+ * 001 = reserved
+ * 010 = 2 bus clocks
+ * 011 = 3 bus clocks
+ * 100 = 4 bus clocks
+ * 101 = 5 bus clocks
+ * 110 = 6 bus clocks
+ * 111 = reserved
+ * [15:15] Reserved
+ * [18:16] Trrd (Ras# to Ras# Delay)
+ * 000 = reserved
+ * 001 = reserved
+ * 010 = 2 bus clocks
+ * 011 = 3 bus clocks
+ * 100 = 4 bus clocks
+ * 101 = reserved
+ * 110 = reserved
+ * 111 = reserved
+ * [19:19] Reserved
+ * [23:20] Tras (Minmum Ras# Active Time)
+ * 0000 to 0100 = reserved
+ * 0101 = 5 bus clocks
+ * ...
+ * 1111 = 15 bus clocks
+ * [26:24] Trp (Row Precharge Time)
+ * 000 = reserved
+ * 001 = reserved
+ * 010 = 2 bus clocks
+ * 011 = 3 bus clocks
+ * 100 = 4 bus clocks
+ * 101 = 5 bus clocks
+ * 110 = 6 bus clocks
+ * 111 = reserved
+ * [27:27] Reserved
+ * [28:28] Twr (Write Recovery Time)
+ * 0 = 2 bus clocks
+ * 1 = 3 bus clocks
+ * [31:29] Reserved
+ */
+ 0xC288, 0xe8088008, 0x03623125,
+ /* DRAM Timing High Register
+ * F2:0x8C
+ * [ 0: 0] Twtr (Write to Read Delay)
+ * 0 = 1 bus Clocks
+ * 1 = 2 bus Clocks
+ * [ 3: 1] Reserved
+ * [ 6: 4] Trwf (Read to Write Delay)
+ * 000 = 1 bus clocks
+ * 001 = 2 bus clocks
+ * 010 = 3 bus clocks
+ * 011 = 4 bus clocks
+ * 100 = 5 bus clocks
+ * 101 = 6 bus clocks
+ * 110 = reserved
+ * 111 = reserved
+ * [ 7: 7] Reserved
+ * [12: 8] Tref (Refresh Rate)
+ * 00000 = 100Mhz 4K rows
+ * 00001 = 133Mhz 4K rows
+ * 00010 = 166Mhz 4K rows
+ * 01000 = 100Mhz 8K/16K rows
+ * 01001 = 133Mhz 8K/16K rows
+ * 01010 = 166Mhz 8K/16K rows
+ * [19:13] Reserved
+ * [22:20] Twcl (Write CAS Latency)
+ * 000 = 1 Mem clock after CAS# (Unbuffered Dimms)
+ * 001 = 2 Mem clocks after CAS# (Registered Dimms)
+ * [31:23] Reserved
+ */
+ 0xC28c, 0xff8fe08e, 0x00000930,
+
+ /* DRAM Config Low Register
+ * F2:0x90
+ * [ 0: 0] DLL Disable
+ * 0 = Enabled
+ * 1 = Disabled
+ * [ 1: 1] D_DRV
+ * 0 = Normal Drive
+ * 1 = Weak Drive
+ * [ 2: 2] QFC_EN
+ * 0 = Disabled
+ * 1 = Enabled
+ * [ 3: 3] Disable DQS Hystersis (FIXME handle this one carefully)
+ * 0 = Enable DQS input filter
+ * 1 = Disable DQS input filtering
+ * [ 7: 4] Reserved
+ * [ 8: 8] DRAM_Init
+ * 0 = Initialization done or not yet started.
+ * 1 = Initiate DRAM intialization sequence
+ * [ 9: 9] SO-Dimm Enable
+ * 0 = Do nothing
+ * 1 = SO-Dimms present
+ * [10:10] DramEnable
+ * 0 = DRAM not enabled
+ * 1 = DRAM initialized and enabled
+ * [11:11] Memory Clear Status
+ * 0 = Memory Clear function has not completed
+ * 1 = Memory Clear function has completed
+ * [12:12] Exit Self-Refresh
+ * 0 = Exit from self-refresh done or not yet started
+ * 1 = DRAM exiting from self refresh
+ * [13:13] Self-Refresh Status
+ * 0 = Normal Operation
+ * 1 = Self-refresh mode active
+ * [15:14] Read/Write Queue Bypass Count
+ * 00 = 2
+ * 01 = 4
+ * 10 = 8
+ * 11 = 16
+ * [16:16] 128-bit/64-Bit
+ * 0 = 64bit Interface to DRAM
+ * 1 = 128bit Interface to DRAM
+ * [17:17] DIMM ECC Enable
+ * 0 = Some DIMMs do not have ECC
+ * 1 = ALL DIMMS have ECC bits
+ * [18:18] UnBuffered DIMMs
+ * 0 = Buffered DIMMS
+ * 1 = Unbuffered DIMMS
+ * [19:19] Enable 32-Byte Granularity
+ * 0 = Optimize for 64byte bursts
+ * 1 = Optimize for 32byte bursts
+ * [20:20] DIMM 0 is x4
+ * [21:21] DIMM 1 is x4
+ * [22:22] DIMM 2 is x4
+ * [23:23] DIMM 3 is x4
+ * 0 = DIMM is not x4
+ * 1 = x4 DIMM present
+ * [24:24] Disable DRAM Receivers
+ * 0 = Receivers enabled
+ * 1 = Receivers disabled
+ * [27:25] Bypass Max
+ * 000 = Arbiters chois is always respected
+ * 001 = Oldest entry in DCQ can be bypassed 1 time
+ * 010 = Oldest entry in DCQ can be bypassed 2 times
+ * 011 = Oldest entry in DCQ can be bypassed 3 times
+ * 100 = Oldest entry in DCQ can be bypassed 4 times
+ * 101 = Oldest entry in DCQ can be bypassed 5 times
+ * 110 = Oldest entry in DCQ can be bypassed 6 times
+ * 111 = Oldest entry in DCQ can be bypassed 7 times
+ * [31:28] Reserved
+ */
+ 0xC290, 0xf0000000,
+ (4 << 25)|(0 << 24)|
+ (0 << 23)|(0 << 22)|(0 << 21)|(0 << 20)|
+ (1 << 19)|(1 << 18)|(0 << 17)|(0 << 16)|
+ (2 << 14)|(0 << 13)|(0 << 12)|
+ (0 << 11)|(0 << 10)|(0 << 9)|(0 << 8)|
+ (0 << 3) |(0 << 1) |(0 << 0),
+ /* DRAM Config High Register
+ * F2:0x94
+ * [ 0: 3] Maximum Asynchronous Latency
+ * 0000 = 0 ns
+ * ...
+ * 1111 = 15 ns
+ * [ 7: 4] Reserved
+ * [11: 8] Read Preamble
+ * 0000 = 2.0 ns
+ * 0001 = 2.5 ns
+ * 0010 = 3.0 ns
+ * 0011 = 3.5 ns
+ * 0100 = 4.0 ns
+ * 0101 = 4.5 ns
+ * 0110 = 5.0 ns
+ * 0111 = 5.5 ns
+ * 1000 = 6.0 ns
+ * 1001 = 6.5 ns
+ * 1010 = 7.0 ns
+ * 1011 = 7.5 ns
+ * 1100 = 8.0 ns
+ * 1101 = 8.5 ns
+ * 1110 = 9.0 ns
+ * 1111 = 9.5 ns
+ * [15:12] Reserved
+ * [18:16] Idle Cycle Limit
+ * 000 = 0 cycles
+ * 001 = 4 cycles
+ * 010 = 8 cycles
+ * 011 = 16 cycles
+ * 100 = 32 cycles
+ * 101 = 64 cycles
+ * 110 = 128 cycles
+ * 111 = 256 cycles
+ * [19:19] Dynamic Idle Cycle Center Enable
+ * 0 = Use Idle Cycle Limit
+ * 1 = Generate a dynamic Idle cycle limit
+ * [22:20] DRAM MEMCLK Frequency
+ * 000 = 100Mhz
+ * 001 = reserved
+ * 010 = 133Mhz
+ * 011 = reserved
+ * 100 = reserved
+ * 101 = 166Mhz
+ * 110 = reserved
+ * 111 = reserved
+ * [24:23] Reserved
+ * [25:25] Memory Clock Ratio Valid (FIXME carefully enable memclk)
+ * 0 = Disable MemClks
+ * 1 = Enable MemClks
+ * [26:26] Memory Clock 0 Enable
+ * 0 = Disabled
+ * 1 = Enabled
+ * [27:27] Memory Clock 1 Enable
+ * 0 = Disabled
+ * 1 = Enabled
+ * [28:28] Memory Clock 2 Enable
+ * 0 = Disabled
+ * 1 = Enabled
+ * [29:29] Memory Clock 3 Enable
+ * 0 = Disabled
+ * 1 = Enabled
+ * [31:30] Reserved
+ */
+ 0xC294, 0xc180f0f0, 0x0e2b0a05,
+ /* DRAM Delay Line Register
+ * F2:0x98
+ * Adjust the skew of the input DQS strobe relative to DATA
+ * [15: 0] Reserved
+ * [23:16] Delay Line Adjust
+ * Adjusts the DLL derived PDL delay by one or more delay stages
+ * in either the faster or slower direction.
+ * [24:24} Adjust Slower
+ * 0 = Do Nothing
+ * 1 = Adj is used to increase the PDL delay
+ * [25:25] Adjust Faster
+ * 0 = Do Nothing
+ * 1 = Adj is used to decrease the PDL delay
+ * [31:26] Reserved
+ */
+ 0xC298, 0xfc00ffff, 0x00000000,
+ /* DRAM Scrub Control Register
+ * F3:0x58
+ * [ 4: 0] DRAM Scrube Rate
+ * [ 7: 5] reserved
+ * [12: 8] L2 Scrub Rate
+ * [15:13] reserved
+ * [20:16] Dcache Scrub
+ * [31:21] reserved
+ * Scrub Rates
+ * 00000 = Do not scrub
+ * 00001 = 40.00 ns
+ * 00010 = 80.00 ns
+ * 00011 = 160.00 ns
+ * 00100 = 320.00 ns
+ * 00101 = 640.00 ns
+ * 00110 = 1.28 us
+ * 00111 = 2.56 us
+ * 01000 = 5.12 us
+ * 01001 = 10.20 us
+ * 01011 = 41.00 us
+ * 01100 = 81.90 us
+ * 01101 = 163.80 us
+ * 01110 = 327.70 us
+ * 01111 = 655.40 us
+ * 10000 = 1.31 ms
+ * 10001 = 2.62 ms
+ * 10010 = 5.24 ms
+ * 10011 = 10.49 ms
+ * 10100 = 20.97 ms
+ * 10101 = 42.00 ms
+ * 10110 = 84.00 ms
+ * All Others = Reserved
+ */
+ 0xC358, 0xffe0e0e0, 0x00000000,
+ /* DRAM Scrub Address Low Register
+ * F3:0x5C
+ * [ 0: 0] DRAM Scrubber Redirect Enable
+ * 0 = Do nothing
+ * 1 = Scrubber Corrects errors found in normal operation
+ * [ 5: 1] Reserved
+ * [31: 6] DRAM Scrub Address 31-6
+ */
+ 0xC35C, 0x0000003e, 0x00000000,
+ /* DRAM Scrub Address High Register
+ * F3:0x60
+ * [ 7: 0] DRAM Scrubb Address 39-32
+ * [31: 8] Reserved
+ */
+ 0xC360, 0xffffff00, 0x00000000,
+ };
+ int i;
+ int max;
+ print_debug("setting up northbridge registers\r\n");
+ max = sizeof(register_values)/sizeof(register_values[0]);
+ for(i = 0; i < max; i += 3) {
+ unsigned long reg;
+#if 0
+ print_debug_hex32(register_values[i]);
+ print_debug(" <-");
+ print_debug_hex32(register_values[i+2]);
+ print_debug("\r\n");
+#endif
+ reg = pcibios_read_config_dword(
+ 0, register_values[i] >> 8, register_values[i] & 0xff);
+ reg &= register_values[i+1];
+ reg |= register_values[i+2] & ~register_values[i+1];
+ pcibios_write_config_dword(
+ 0, register_values[i] >> 8, register_values[i] & 0xff, reg);
+ }
+ print_debug("setting up northbridge registers done. hurray!\r\n");
+}
+
+#define PCI_DEVFN(slot,func) ((((slot) & 0x1f) << 3) | ((func) & 0x07))
+
+#define DRAM_CONFIG_LOW 0x90
+#define DCL_DLL_Disable (1<<0)
+#define DCL_D_DRV (1<<1)
+#define DCL_QFC_EN (1<<2)
+#define DCL_DisDqsHys (1<<3)
+#define DCL_DramInit (1<<8)
+#define DCL_DramEnable (1<<10)
+#define DCL_MemClrStatus (1<<11)
+#define DCL_DimmEcEn (1<<17)
+
+static void sdram_set_spd_registers(void)
+{
+ unsigned long dcl;
+ dcl = pcibios_read_config_dword(0, PCI_DEVFN(0x18,2), DRAM_CONFIG_LOW);
+ /* Until I know what is going on disable ECC support */
+ dcl &= ~DCL_DimmEcEn;
+ pcibios_write_config_dword(0, PCI_DEVFN(0x18,2), DRAM_CONFIG_LOW, dcl);
+}
+
+#define TIMEOUT_LOOPS 300000
+static void sdram_enable(void)
+{
+ unsigned long dcl;
+
+ /* Toggle DisDqsHys to get it working */
+ dcl = pcibios_read_config_dword(0, PCI_DEVFN(0x18,2), DRAM_CONFIG_LOW);
+ print_debug("dcl: ");
+ print_debug_hex32(dcl);
+ print_debug("\r\n");
+ dcl |= DCL_DisDqsHys;
+ pcibios_write_config_dword(0, PCI_DEVFN(0x18, 2), DRAM_CONFIG_LOW, dcl);
+ dcl &= ~DCL_DisDqsHys;
+ dcl &= ~DCL_DLL_Disable;
+ dcl &= ~DCL_D_DRV;
+ dcl &= ~DCL_QFC_EN;
+ dcl |= DCL_DramInit;
+ pcibios_write_config_dword(0, PCI_DEVFN(0x18, 2), DRAM_CONFIG_LOW, dcl);
+
+ print_debug("Initializing memory: ");
+ int loops = 0;
+ do {
+ dcl = pcibios_read_config_dword(0, PCI_DEVFN(0x18, 2), DRAM_CONFIG_LOW);
+ loops += 1;
+ if ((loops & 1023) == 0) {
+ print_debug(" ");
+ print_debug_hex32(loops);
+ }
+ } while(((dcl & DCL_DramInit) != 0) && (loops < TIMEOUT_LOOPS));
+ if (loops >= TIMEOUT_LOOPS) {
+ print_debug(" failed\r\n");
+ } else {
+ print_debug(" done\r\n");
+ }
+
+#if 0
+ print_debug("Clearing memory: ");
+ loops = 0;
+ do {
+ dcl = pcibios_read_config_dword(0, PCI_DEVFN(0x18, 2), DRAM_CONFIG_LOW);
+ loops += 1;
+ if ((loops & 1023) == 0) {
+ print_debug(" ");
+ print_debug_hex32(loops);
+ }
+ } while(((dcl & DCL_MemClrStatus) == 0) && (loops < TIMEOUT_LOOPS));
+ if (loops >= TIMEOUT_LOOPS) {
+ print_debug("failed\r\n");
+ } else {
+ print_debug("done\r\n");
+ }
+#endif
+}
+
+static void sdram_first_normal_reference(void) {}
+static void sdram_enable_refresh(void) {}
+static void sdram_special_finishup(void) {}
+
+static int sdram_enabled(void)
+{
+ unsigned long dcl;
+ int enabled;
+ dcl = pcibios_read_config_dword(0, PCI_DEVFN(0x18, 2), DRAM_CONFIG_LOW);
+ enabled = !!(dcl & DCL_DramEnable);
+ if (enabled) {
+ print_debug("DRAM already enabled.");
+ }
+ return enabled;
+}
+
+
+#include "sdram/generic_sdram.c"
+
+static void main(void)
+{
+ uart_init();
+ console_init();
+ if (!sdram_enabled()) {
+ sdram_initialize();
+#if 0
+ ram_fill( 0x00100000, 0x00180000);
+ ram_verify(0x00100000, 0x00180000);
+#endif
+#if 1
+ ram_fill( 0x00000000, 0x00001000);
+ ram_verify(0x00000000, 0x00001000);
+#endif
+ }
+}
diff --git a/src/mainboard/amd/solo/cmos.layout b/src/mainboard/amd/solo/cmos.layout
new file mode 100644
index 0000000000..5ba4c032c1
--- /dev/null
+++ b/src/mainboard/amd/solo/cmos.layout
@@ -0,0 +1,74 @@
+entries
+
+#start-bit length config config-ID name
+#0 8 r 0 seconds
+#8 8 r 0 alarm_seconds
+#16 8 r 0 minutes
+#24 8 r 0 alarm_minutes
+#32 8 r 0 hours
+#40 8 r 0 alarm_hours
+#48 8 r 0 day_of_week
+#56 8 r 0 day_of_month
+#64 8 r 0 month
+#72 8 r 0 year
+#80 4 r 0 rate_select
+#84 3 r 0 REF_Clock
+#87 1 r 0 UIP
+#88 1 r 0 auto_switch_DST
+#89 1 r 0 24_hour_mode
+#90 1 r 0 binary_values_enable
+#91 1 r 0 square-wave_out_enable
+#92 1 r 0 update_finished_enable
+#93 1 r 0 alarm_interrupt_enable
+#94 1 r 0 periodic_interrupt_enable
+#95 1 r 0 disable_clock_updates
+#96 288 r 0 temporary_filler
+0 384 r 0 reserved_memory
+384 1 e 4 boot_option
+385 1 e 4 last_boot
+386 1 e 1 ECC_memory
+388 4 r 0 reboot_bits
+392 3 e 5 baud_rate
+400 1 e 1 power_on_after_fail
+412 4 e 6 debug_level
+416 4 e 7 boot_first
+420 4 e 7 boot_second
+424 4 e 7 boot_third
+428 4 h 0 boot_index
+432 8 h 0 boot_countdown
+1008 16 h 0 check_sum
+
+enumerations
+
+#ID value text
+1 0 Disable
+1 1 Enable
+2 0 Enable
+2 1 Disable
+4 0 Fallback
+4 1 Normal
+5 0 115200
+5 1 57600
+5 2 38400
+5 3 19200
+5 4 9600
+5 5 4800
+5 6 2400
+5 7 1200
+6 6 Notice
+6 7 Info
+6 8 Debug
+6 9 Spew
+7 0 Network
+7 1 HDD
+7 2 Floppy
+7 8 Fallback_Network
+7 9 Fallback_HDD
+7 10 Fallback_Floppy
+#7 3 ROM
+
+checksums
+
+checksum 392 1007 1008
+
+
diff --git a/src/mainboard/amd/solo/mainboard.c b/src/mainboard/amd/solo/mainboard.c
new file mode 100644
index 0000000000..b8b8d6c3f2
--- /dev/null
+++ b/src/mainboard/amd/solo/mainboard.c
@@ -0,0 +1,25 @@
+#if 0
+#include <printk.h>
+#endif
+
+void
+mainboard_fixup(void)
+{
+}
+
+void
+final_mainboard_fixup(void)
+{
+#if 0
+// void final_southbridge_fixup(void);
+// void final_superio_fixup(void);
+
+ printk_info("AMD Solo initializing...");
+
+// final_southbridge_fixup();
+
+//#ifndef USE_NEW_SUPERIO_INTERFACE
+//final_superio_fixup();
+//#endif
+#endif
+}
diff --git a/src/northbridge/amd/amdk8/northbridge.c b/src/northbridge/amd/amdk8/northbridge.c
new file mode 100644
index 0000000000..1ba87bd083
--- /dev/null
+++ b/src/northbridge/amd/amdk8/northbridge.c
@@ -0,0 +1,22 @@
+#include <arch/io.h>
+#include <stdint.h>
+#include <mem.h>
+#include <part/sizeram.h>
+
+struct mem_range *sizeram(void)
+{
+ static struct mem_range mem[3];
+ uint32_t size;
+ /* Convert size in bytes to size in K */
+ /* FIXME hardcoded for now */
+ size = 512*1024;
+
+ mem[0].basek = 0;
+ mem[0].sizek = 640;
+ mem[1].basek = 1024;
+ mem[1].sizek = size - mem[1].basek;
+ mem[2].basek = 0;
+ mem[2].sizek = 0;
+ return mem;
+}
+
diff --git a/src/pc80/mc146818rtc.c b/src/pc80/mc146818rtc.c
new file mode 100644
index 0000000000..b77653c52e
--- /dev/null
+++ b/src/pc80/mc146818rtc.c
@@ -0,0 +1,249 @@
+#include <console/console.h>
+#include <arch/io.h>
+#include <pc80/mc146818rtc.h>
+#include <boot/linuxbios_tables.h>
+#include <string.h>
+
+#define CMOS_READ(addr) ({ \
+outb((addr),RTC_PORT(0)); \
+inb(RTC_PORT(1)); \
+})
+
+#define CMOS_WRITE(val, addr) ({ \
+outb((addr),RTC_PORT(0)); \
+outb((val),RTC_PORT(1)); \
+})
+
+/* control registers - Moto names
+ */
+#define RTC_REG_A 10
+#define RTC_REG_B 11
+#define RTC_REG_C 12
+#define RTC_REG_D 13
+
+
+/**********************************************************************
+ * register details
+ **********************************************************************/
+#define RTC_FREQ_SELECT RTC_REG_A
+
+/* update-in-progress - set to "1" 244 microsecs before RTC goes off the bus,
+ * reset after update (may take 1.984ms @ 32768Hz RefClock) is complete,
+ * totalling to a max high interval of 2.228 ms.
+ */
+# define RTC_UIP 0x80
+# define RTC_DIV_CTL 0x70
+ /* divider control: refclock values 4.194 / 1.049 MHz / 32.768 kHz */
+# define RTC_REF_CLCK_4MHZ 0x00
+# define RTC_REF_CLCK_1MHZ 0x10
+# define RTC_REF_CLCK_32KHZ 0x20
+ /* 2 values for divider stage reset, others for "testing purposes only" */
+# define RTC_DIV_RESET1 0x60
+# define RTC_DIV_RESET2 0x70
+ /* Periodic intr. / Square wave rate select. 0=none, 1=32.8kHz,... 15=2Hz */
+# define RTC_RATE_SELECT 0x0F
+# define RTC_RATE_NONE 0x00
+# define RTC_RATE_32786HZ 0x01
+# define RTC_RATE_16384HZ 0x02
+# define RTC_RATE_8192HZ 0x03
+# define RTC_RATE_4096HZ 0x04
+# define RTC_RATE_2048HZ 0x05
+# define RTC_RATE_1024HZ 0x06
+# define RTC_RATE_512HZ 0x07
+# define RTC_RATE_256HZ 0x08
+# define RTC_RATE_128HZ 0x09
+# define RTC_RATE_64HZ 0x0a
+# define RTC_RATE_32HZ 0x0b
+# define RTC_RATE_16HZ 0x0c
+# define RTC_RATE_8HZ 0x0d
+# define RTC_RATE_4HZ 0x0e
+# define RTC_RATE_2HZ 0x0f
+
+/**********************************************************************/
+#define RTC_CONTROL RTC_REG_B
+# define RTC_SET 0x80 /* disable updates for clock setting */
+# define RTC_PIE 0x40 /* periodic interrupt enable */
+# define RTC_AIE 0x20 /* alarm interrupt enable */
+# define RTC_UIE 0x10 /* update-finished interrupt enable */
+# define RTC_SQWE 0x08 /* enable square-wave output */
+# define RTC_DM_BINARY 0x04 /* all time/date values are BCD if clear */
+# define RTC_24H 0x02 /* 24 hour mode - else hours bit 7 means pm */
+# define RTC_DST_EN 0x01 /* auto switch DST - works f. USA only */
+
+/**********************************************************************/
+#define RTC_INTR_FLAGS RTC_REG_C
+/* caution - cleared by read */
+# define RTC_IRQF 0x80 /* any of the following 3 is active */
+# define RTC_PF 0x40
+# define RTC_AF 0x20
+# define RTC_UF 0x10
+
+/**********************************************************************/
+#define RTC_VALID RTC_REG_D
+# define RTC_VRT 0x80 /* valid RAM and time */
+/**********************************************************************/
+
+
+
+static int rtc_checksum_valid(int range_start, int range_end, int cks_loc)
+{
+ int i;
+ unsigned sum, old_sum;
+ sum = 0;
+ for(i = range_start; i <= range_end; i++) {
+ sum += CMOS_READ(i);
+ }
+ sum = (~sum)&0x0ffff;
+ old_sum = ((CMOS_READ(cks_loc)<<8) | CMOS_READ(cks_loc+1))&0x0ffff;
+ return sum == old_sum;
+}
+
+static void rtc_set_checksum(int range_start, int range_end, int cks_loc)
+{
+ int i;
+ unsigned sum;
+ sum = 0;
+ for(i = range_start; i <= range_end; i++) {
+ sum += CMOS_READ(i);
+ }
+ sum = ~(sum & 0x0ffff);
+ CMOS_WRITE(((sum >> 8) & 0x0ff), cks_loc);
+ CMOS_WRITE(((sum >> 0) & 0x0ff), cks_loc+1);
+}
+
+#define RTC_CONTROL_DEFAULT (RTC_24H)
+#define RTC_FREQ_SELECT_DEFAULT (RTC_REF_CLCK_32KHZ | RTC_RATE_1024HZ)
+
+#if 0 /* alpha setup */
+#undef RTC_CONTROL_DEFAULT
+#undef RTC_FREQ_SELECT_DEFAULT
+#define RTC_CONTROL_DEFAULT (RTC_SQWE | RTC_24H)
+#define RTC_FREQ_SELECT_DEFAULT (RTC_REF_CLCK_32KHZ | RTC_RATE_1024HZ)
+#endif
+void rtc_init(int invalid)
+{
+ unsigned char x;
+ int cmos_invalid, checksum_invalid;
+
+ printk_debug("RTC Init\n");
+ /* See if there has been a CMOS power problem. */
+ x = CMOS_READ(RTC_VALID);
+ cmos_invalid = !(x & RTC_VRT);
+
+ /* See if there is a CMOS checksum error */
+ checksum_invalid = !rtc_checksum_valid(PC_CKS_RANGE_START,
+ PC_CKS_RANGE_END,PC_CKS_LOC);
+
+ if (invalid || cmos_invalid || checksum_invalid) {
+ int i;
+ printk_warning("RTC:%s%s%s zeroing cmos\n",
+ invalid?" Clear requested":"",
+ cmos_invalid?" Power Problem":"",
+ checksum_invalid?" Checksum invalid":"");
+#if 0
+ CMOS_WRITE(0, 0x01);
+ CMOS_WRITE(0, 0x03);
+ CMOS_WRITE(0, 0x05);
+ for(i = 10; i < 48; i++) {
+ CMOS_WRITE(0, i);
+ }
+
+ if (cmos_invalid) {
+ /* Now setup a default date of Sat 1 January 2000 */
+ CMOS_WRITE(0, 0x00); /* seconds */
+ CMOS_WRITE(0, 0x02); /* minutes */
+ CMOS_WRITE(1, 0x04); /* hours */
+ CMOS_WRITE(7, 0x06); /* day of week */
+ CMOS_WRITE(1, 0x07); /* day of month */
+ CMOS_WRITE(1, 0x08); /* month */
+ CMOS_WRITE(0, 0x09); /* year */
+ }
+#endif
+ }
+ /* See if there is a LB CMOS checksum error */
+ checksum_invalid = !rtc_checksum_valid(LB_CKS_RANGE_START,
+ LB_CKS_RANGE_END,LB_CKS_LOC);
+ if(checksum_invalid)
+ printk_debug("Invalid CMOS LB checksum\n");
+
+ /* Setup the real time clock */
+ CMOS_WRITE(RTC_CONTROL_DEFAULT, RTC_CONTROL);
+ /* Setup the frequency it operates at */
+ CMOS_WRITE(RTC_FREQ_SELECT_DEFAULT, RTC_FREQ_SELECT);
+ /* Make certain we have a valid checksum */
+ rtc_set_checksum(PC_CKS_RANGE_START,
+ PC_CKS_RANGE_END,PC_CKS_LOC);
+ /* Clear any pending interrupts */
+ (void) CMOS_READ(RTC_INTR_FLAGS);
+}
+
+
+#if USE_OPTION_TABLE == 1
+/* This routine returns the value of the requested bits
+ input bit = bit count from the beginning of the cmos image
+ length = number of bits to include in the value
+ ret = a character pointer to where the value is to be returned
+ output the value placed in ret
+ returns 0 = successful, -1 = an error occurred
+*/
+static int get_cmos_value(unsigned long bit, unsigned long length, void *vret)
+{
+ unsigned char *ret;
+ unsigned long byte,byte_bit;
+ unsigned long i;
+ unsigned char uchar;
+
+ /* The table is checked when it is built to ensure all
+ values are valid. */
+ ret = vret;
+ byte=bit/8; /* find the byte where the data starts */
+ byte_bit=bit%8; /* find the bit in the byte where the data starts */
+ if(length<9) { /* one byte or less */
+ uchar = CMOS_READ(byte); /* load the byte */
+ uchar >>= byte_bit; /* shift the bits to byte align */
+ /* clear unspecified bits */
+ ret[0] = uchar & ((1 << length) -1);
+ }
+ else { /* more that one byte so transfer the whole bytes */
+ for(i=0;length;i++,length-=8,byte++) {
+ /* load the byte */
+ ret[i]=CMOS_READ(byte);
+ }
+ }
+ return 0;
+}
+
+int get_option(void *dest, char *name)
+{
+ extern struct cmos_option_table option_table;
+ struct cmos_option_table *ct;
+ struct cmos_entries *ce;
+ size_t namelen;
+ int found=0;
+
+ /* Figure out how long name is */
+ namelen = strnlen(name, CMOS_MAX_NAME_LENGTH);
+
+ /* find the requested entry record */
+ ct=&option_table;
+ ce=(struct cmos_entries*)((unsigned char *)ct + ct->header_length);
+ for(;ce->tag==LB_TAG_OPTION;
+ ce=(struct cmos_entries*)((unsigned char *)ce + ce->size)) {
+ if (memcmp(ce->name, name, namelen) == 0) {
+ found=1;
+ break;
+ }
+ }
+ if(!found) {
+ printk_err("ERROR: No cmos option '%s'\n", name);
+ return(-2);
+ }
+
+ if(get_cmos_value(ce->bit, ce->length, dest))
+ return(-3);
+ if(!rtc_checksum_valid(LB_CKS_RANGE_START,
+ LB_CKS_RANGE_END,LB_CKS_LOC))
+ return(-4);
+ return(0);
+}
+#endif /* USE_OPTION_TABLE */
diff --git a/src/pc80/serial.c b/src/pc80/serial.c
new file mode 100644
index 0000000000..b10d22dcba
--- /dev/null
+++ b/src/pc80/serial.c
@@ -0,0 +1,93 @@
+#include <part/fallback_boot.h>
+
+/* Base Address */
+#ifndef TTYS0_BASE
+#define TTYS0_BASE 0x3f8
+#endif
+
+#ifndef TTYS0_BAUD
+#define TTYS0_BAUD 115200
+#endif
+
+#if ((115200%TTYS0_BAUD) != 0)
+#error Bad ttys0 baud rate
+#endif
+
+#define TTYS0_DIV (115200/TTYS0_BAUD)
+
+/* Line Control Settings */
+#ifndef TTYS0_LCS
+/* Set 8bit, 1 stop bit, no parity */
+#define TTYS0_LCS 0x3
+#endif
+
+#define UART_LCS TTYS0_LCS
+
+/* Data */
+#define UART_RBR 0x00
+#define UART_TBR 0x00
+
+/* Control */
+#define UART_IER 0x01
+#define UART_IIR 0x02
+#define UART_FCR 0x02
+#define UART_LCR 0x03
+#define UART_MCR 0x04
+#define UART_DLL 0x00
+#define UART_DLM 0x01
+
+/* Status */
+#define UART_LSR 0x05
+#define UART_MSR 0x06
+#define UART_SCR 0x07
+
+static int uart_can_tx_byte(void)
+{
+ return inb(TTYS0_BASE + UART_LSR) & 0x20;
+}
+
+static void uart_wait_to_tx_byte(void)
+{
+ while(!uart_can_tx_byte())
+ ;
+}
+
+static void uart_wait_until_sent(void)
+{
+ while(!(inb(TTYS0_BASE + UART_LSR) & 0x40))
+ ;
+}
+
+static void uart_tx_byte(unsigned char data)
+{
+ uart_wait_to_tx_byte();
+ outb(data, TTYS0_BASE + UART_TBR);
+ /* Make certain the data clears the fifos */
+ uart_wait_until_sent();
+}
+
+static void uart_init(void)
+{
+ /* disable interrupts */
+ outb(0x0, TTYS0_BASE + UART_IER);
+ /* enable fifo's */
+ outb(0x01, TTYS0_BASE + UART_FCR);
+ /* Set Baud Rate Divisor to 12 ==> 115200 Baud */
+ outb(0x80 | UART_LCS, TTYS0_BASE + UART_LCR);
+#if 0 && USE_OPTION_TABLE == 1
+ {
+ static const unsigned char divisor[] = { 1,2,3,6,12,24,48,96 };
+ unsigned ttys0_div, ttys0_index;
+ outb(RTC_BOOT_BYTE + 1, 0x70);
+ ttys0_index = inb(0x71);
+ ttys0_index &= 7;
+ ttys0_div = divisor[ttys0_index];
+ outb(ttys0_div & 0xff, TTYS0_BASE + UART_DLL);
+ outb(0, TTYS0_BASE + UART_DLM);
+ }
+#else
+ outb(TTYS0_DIV & 0xFF, TTYS0_BASE + UART_DLL);
+ outb((TTYS0_DIV >> 8) & 0xFF, TTYS0_BASE + UART_DLM);
+#endif
+ outb(UART_LCS, TTYS0_BASE + UART_LCR);
+}
diff --git a/src/pc80/serial.inc b/src/pc80/serial.inc
new file mode 100644
index 0000000000..b0f12699e1
--- /dev/null
+++ b/src/pc80/serial.inc
@@ -0,0 +1,106 @@
+#include <part/fallback_boot.h>
+
+
+/* Base Address */
+#ifndef TTYS0_BASE
+#define TTYS0_BASE 0x3f8
+#endif
+
+/* Baud Rate */
+#ifndef TTYS0_BAUD
+#define TTYS0_BAUD 115200
+#endif
+
+#if ((115200%TTYS0_BAUD) != 0)
+#error Bad ttys0 baud rate
+#endif
+
+/* Baud Rate Divisor */
+#define TTYS0_DIV (115200/TTYS0_BAUD)
+#define TTYS0_DIV_LO (TTYS0_DIV&0xFF)
+#define TTYS0_DIV_HI ((TTYS0_DIV >> 8)&0xFF)
+
+/* Line Control Settings */
+#ifndef TTYS0_LCS
+/* Set 8bit, 1 stop bit, no parity */
+#define TTYS0_LCS 0x3
+#endif
+
+/* Data */
+#define TTYS0_RBR (TTYS0_BASE+0x00)
+
+/* Control */
+#define TTYS0_TBR TTYS0_RBR
+#define TTYS0_IER (TTYS0_BASE+0x01)
+#define TTYS0_IIR (TTYS0_BASE+0x02)
+#define TTYS0_FCR TTYS0_IIR
+#define TTYS0_LCR (TTYS0_BASE+0x03)
+#define TTYS0_MCR (TTYS0_BASE+0x04)
+#define TTYS0_DLL TTYS0_RBR
+#define TTYS0_DLM TTYS0_IER
+
+/* Status */
+#define TTYS0_LSR (TTYS0_BASE+0x05)
+#define TTYS0_MSR (TTYS0_BASE+0x06)
+#define TTYS0_SCR (TTYS0_BASE+0x07)
+
+#if USE_OPTION_TABLE == 1
+.section ".rom.data"
+ .type div,@object
+ .size div,8
+div:
+.byte 1,2,3,6,12,24,48,96
+
+.previous
+#endif
+
+ jmp serial0
+
+ /* uses: ax, dx */
+#define TTYS0_TX_AL \
+ mov %al, %ah ; \
+9: mov $TTYS0_LSR, %dx ; \
+ inb %dx, %al ; \
+ test $0x20, %al ; \
+ je 9b ; \
+ mov $TTYS0_TBR, %dx ; \
+ mov %ah, %al ; \
+ outb %al, %dx
+
+
+serial0:
+ /* Set 115.2Kbps,8n1 */
+ /* Set 8bit, 1 stop bit, no parity, DLAB */
+ mov $TTYS0_LCR, %dx
+ mov $(TTYS0_LCS | 0x80), %al
+ out %al, %dx
+
+ /* set Baud Rate Divisor to 1 ==> 115200 Buad */
+#if USE_OPTION_TABLE == 1
+
+ movb $(RTC_BOOT_BYTE+1), %al
+ outb %al, $0x70
+ xorl %edx,%edx
+ inb $0x71, %al
+ andb $7,%al
+ movb %al,%dl
+ movb div(%edx),%al
+ mov $TTYS0_DLL, %dx
+ out %al, %dx
+ mov $TTYS0_DLM, %dx
+ xorb %al,%al
+ out %al, %dx
+#else
+ mov $TTYS0_DLL, %dx
+ mov $TTYS0_DIV_LO, %al
+ out %al, %dx
+ mov $TTYS0_DLM, %dx
+ mov $TTYS0_DIV_HI, %al
+ out %al, %dx
+#endif
+ /* Disable DLAB */
+ mov $TTYS0_LCR, %dx
+ mov $(TTYS0_LCS & 0x7f), %al
+ out %al, %dx
+
+
diff --git a/src/ram/ramtest.c b/src/ram/ramtest.c
new file mode 100644
index 0000000000..0e5e6982a3
--- /dev/null
+++ b/src/ram/ramtest.c
@@ -0,0 +1,89 @@
+static void write_phys(unsigned long addr, unsigned long value)
+{
+ unsigned long *ptr;
+ ptr = (void *)addr;
+ *ptr = value;
+}
+
+static unsigned long read_phys(unsigned long addr)
+{
+ unsigned long *ptr;
+ ptr = (void *)addr;
+ return *ptr;
+}
+
+void ram_fill(unsigned long start, unsigned long stop)
+{
+ unsigned long addr;
+ /*
+ * Fill.
+ */
+ print_debug("DRAM fill: ");
+ print_debug_hex32(start);
+ print_debug("-");
+ print_debug_hex32(stop);
+ print_debug("\r\n");
+ for(addr = start; addr < stop ; addr += 4) {
+ /* Display address being filled */
+ if ((addr & 0xffff) == 0) {
+ print_debug_hex32(addr);
+ print_debug("\r");
+ }
+ write_phys(addr, addr);
+ };
+ /* Display final address */
+ print_debug_hex32(addr);
+ print_debug("\r\nDRAM filled\r\n");
+}
+
+void ram_verify(unsigned long start, unsigned long stop)
+{
+ unsigned long addr;
+ /*
+ * Verify.
+ */
+ print_debug("DRAM verify: ");
+ print_debug_hex32(start);
+ print_debug_char('-');
+ print_debug_hex32(stop);
+ print_debug("\r\n");
+ for(addr = start; addr < stop ; addr += 4) {
+ unsigned long value;
+ /* Display address being tested */
+ if ((addr & 0xffff) == 0) {
+ print_debug_hex32(addr);
+ print_debug("\r");
+ }
+ value = read_phys(addr);
+ if (value != addr) {
+ /* Display address with error */
+ print_err_hex32(addr);
+ print_err_char(':');
+ print_err_hex32(value);
+ print_err("\r\n");
+ }
+ }
+ /* Display final address */
+ print_debug_hex32(addr);
+ print_debug("\r\nDRAM verified\r\n");
+}
+
+
+void ramcheck(unsigned long start, unsigned long stop)
+{
+ int result;
+ /*
+ * This is much more of a "Is my DRAM properly configured?"
+ * test than a "Is my DRAM faulty?" test. Not all bits
+ * are tested. -Tyson
+ */
+ print_debug("Testing DRAM : ");
+ print_debug_hex32(start);
+ print_debug("-");
+ print_debug_hex32(stop);
+ print_debug("\r\n");
+ ram_fill(start, stop);
+ ram_verify(start, stop);
+ print_debug("Done.\n");
+}
+
diff --git a/src/sdram/generic_dump_spd.c b/src/sdram/generic_dump_spd.c
new file mode 100644
index 0000000000..27f1844d3c
--- /dev/null
+++ b/src/sdram/generic_dump_spd.c
@@ -0,0 +1,25 @@
+void dump_spd_registers(void)
+{
+ unsigned device;
+ device = SMBUS_MEM_DEVICE_START;
+ printk_debug("\n");
+ while(device <= SMBUS_MEM_DEVICE_END) {
+ int status = 0;
+ int i;
+ printk_debug("dimm %02x", device);
+ for(i = 0; (i < 256) && (status == 0); i++) {
+ unsigned char byte;
+ if ((i % 20) == 0) {
+ printk_debug("\n%3d: ", i);
+ }
+ status = smbus_read_byte(device, i, &byte);
+ if (status != 0) {
+ printk_debug("bad device\n");
+ continue;
+ }
+ printk_debug("%02x ", byte);
+ }
+ device += SMBUS_MEM_DEVICE_INC;
+ printk_debug("\n");
+ }
+}
diff --git a/src/sdram/generic_sdram.c b/src/sdram/generic_sdram.c
new file mode 100644
index 0000000000..be5ae87407
--- /dev/null
+++ b/src/sdram/generic_sdram.c
@@ -0,0 +1,35 @@
+void sdram_no_memory(void)
+{
+ print_err("No memory!!\r\n");
+ while(1) {
+ hlt();
+ }
+}
+
+/* Setup SDRAM */
+void sdram_initialize(void)
+{
+ print_debug("Ram1\r\n");
+ /* Set the registers we can set once to reasonable values */
+ sdram_set_registers();
+
+ print_debug("Ram2\r\n");
+ /* Now setup those things we can auto detect */
+ sdram_set_spd_registers();
+
+ print_debug("Ram3\r\n");
+ /* Now that everything is setup enable the SDRAM.
+ * Some chipsets do the work for use while on others
+ * we need to it by hand.
+ */
+ sdram_enable();
+
+ print_debug("Ram4\r\n");
+ sdram_first_normal_reference();
+
+ print_debug("Ram5\r\n");
+ sdram_enable_refresh();
+ sdram_special_finishup();
+
+ print_debug("Ram6\r\n");
+}
diff --git a/src/stream/rom_stream.c b/src/stream/rom_stream.c
new file mode 100644
index 0000000000..20b7686c84
--- /dev/null
+++ b/src/stream/rom_stream.c
@@ -0,0 +1,58 @@
+#include <console/console.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stream/read_bytes.h>
+#include <string.h>
+
+
+#ifndef CONFIG_ROM_STREAM_START
+#define CONFIG_ROM_STREAM_START 0xffff0000UL
+#endif
+
+static const unsigned char *rom_start = (void *)CONFIG_ROM_STREAM_START;
+static const unsigned char *rom_end = (void *)(CONFIG_ROM_STREAM_START + PAYLOAD_SIZE - 1);
+static const unsigned char *rom;
+
+int stream_init(void)
+{
+ rom = rom_start;
+
+ printk_spew("%6d:%s() - rom_stream: 0x%08lx - 0x%08lx\n"
+ __LINE__, __FUNCTION__,
+ (unsigned long)rom_start,
+ (unsigned long)rom_end);
+ return 0;
+}
+
+
+void stream_fini(void)
+{
+ return;
+}
+
+byte_offset_t stream_skip(byte_offset_t count)
+{
+ byte_offset_t bytes;
+ bytes = count;
+ if ((rom + bytes) > rom_end) {
+ printk_warning("%6d:%s() - overflowed source buffer\n",
+ __LINE__, __FUNCTION__);
+ bytes = 0;
+ if (rom <= rom_end) {
+ bytes = (rom_end - rom) + 1;
+ }
+ }
+ rom += bytes;
+ return bytes;
+}
+
+byte_offset_t stream_read(void *vdest, byte_offset_t count)
+{
+ unsigned char *dest = vdest;
+ const unsigned char *src = rom;
+ byte_offset_t bytes;
+
+ bytes = stream_skip(count);
+ memcpy(dest, src, bytes);
+ return bytes;
+}