- Initial checkin of the freebios2 tree
authorEric Biederman <ebiederm@xmission.com>
Tue, 22 Apr 2003 19:02:15 +0000 (19:02 +0000)
committerEric Biederman <ebiederm@xmission.com>
Tue, 22 Apr 2003 19:02:15 +0000 (19:02 +0000)
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@784 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1

109 files changed:
src/arch/i386/boot/boot.c [new file with mode: 0644]
src/arch/i386/boot/linuxbios_table.c [new file with mode: 0644]
src/arch/i386/boot/linuxbios_table.h [new file with mode: 0644]
src/arch/i386/boot/pirq_routing.c [new file with mode: 0644]
src/arch/i386/boot/tables.c [new file with mode: 0644]
src/arch/i386/include/arch/asm.h [new file with mode: 0644]
src/arch/i386/include/arch/boot/boot.h [new file with mode: 0644]
src/arch/i386/include/arch/intel.h [new file with mode: 0644]
src/arch/i386/include/arch/io.h [new file with mode: 0644]
src/arch/i386/include/arch/pciconf.h [new file with mode: 0644]
src/arch/i386/include/arch/pirq_routing.h [new file with mode: 0644]
src/arch/i386/include/arch/rom_segs.h [new file with mode: 0644]
src/arch/i386/include/arch/romcc_io.h [new file with mode: 0644]
src/arch/i386/include/arch/smp/mpspec.h [new file with mode: 0644]
src/arch/i386/include/bitops.h [new file with mode: 0644]
src/arch/i386/include/stddef.h [new file with mode: 0644]
src/arch/i386/include/stdint.h [new file with mode: 0644]
src/arch/i386/lib/c_start.S [new file with mode: 0644]
src/arch/i386/lib/console.c [new file with mode: 0644]
src/arch/i386/lib/console.inc [new file with mode: 0644]
src/arch/i386/lib/cpu.c [new file with mode: 0644]
src/arch/i386/lib/cpu_reset.inc [new file with mode: 0644]
src/arch/i386/lib/failover.lds [new file with mode: 0644]
src/arch/i386/lib/id.inc [new file with mode: 0644]
src/arch/i386/lib/id.lds [new file with mode: 0644]
src/arch/i386/lib/noop_failover.inc [new file with mode: 0644]
src/arch/i386/lib/pci_ops.c [new file with mode: 0644]
src/arch/i386/smp/mpspec.c [new file with mode: 0644]
src/boot/elfboot.c [new file with mode: 0644]
src/boot/hardwaremain.c [new file with mode: 0644]
src/config/LinuxBIOSDoc.config [new file with mode: 0755]
src/config/doxyscript.base [new file with mode: 0755]
src/config/linuxbios_c.ld [new file with mode: 0644]
src/console/console.c [new file with mode: 0644]
src/console/logbuf_console.c [new file with mode: 0644]
src/console/printk.c [new file with mode: 0644]
src/console/uart8250_console.c [new file with mode: 0644]
src/console/vga_console.c [new file with mode: 0644]
src/console/vsprintf.c [new file with mode: 0644]
src/cpu/i386/entry16.inc [new file with mode: 0644]
src/cpu/i386/entry16.lds [new file with mode: 0644]
src/cpu/i386/entry32.inc [new file with mode: 0644]
src/cpu/i386/entry32.lds [new file with mode: 0644]
src/cpu/i386/reset16.inc [new file with mode: 0644]
src/cpu/i386/reset16.lds [new file with mode: 0644]
src/cpu/i386/reset32.inc [new file with mode: 0644]
src/cpu/i386/reset32.lds [new file with mode: 0644]
src/cpu/k8/cpufixup.c [new file with mode: 0644]
src/cpu/k8/earlymtrr.inc [new file with mode: 0644]
src/cpu/p5/cpuid.c [new file with mode: 0644]
src/cpu/p6/mtrr.c [new file with mode: 0644]
src/devices/device.c [new file with mode: 0644]
src/devices/device_util.c [new file with mode: 0644]
src/devices/pci_device.c [new file with mode: 0644]
src/include/boot/elf.h [new file with mode: 0644]
src/include/boot/elf_boot.h [new file with mode: 0644]
src/include/boot/linuxbios_tables.h [new file with mode: 0644]
src/include/boot/tables.h [new file with mode: 0644]
src/include/console/console.h [new file with mode: 0644]
src/include/console/loglevel.h [new file with mode: 0644]
src/include/cpu/cpu.h [new file with mode: 0644]
src/include/cpu/cpufixup.h [new file with mode: 0644]
src/include/cpu/k7/cpufixup.h [new file with mode: 0644]
src/include/cpu/k7/mtrr.h [new file with mode: 0644]
src/include/cpu/k8/cpufixup.h [new file with mode: 0644]
src/include/cpu/k8/mtrr.h [new file with mode: 0644]
src/include/cpu/p5/cpuid.h [new file with mode: 0644]
src/include/cpu/p6/apic.h [new file with mode: 0644]
src/include/cpu/p6/cpufixup.h [new file with mode: 0644]
src/include/cpu/p6/msr.h [new file with mode: 0644]
src/include/cpu/p6/mtrr.h [new file with mode: 0644]
src/include/delay.h [new file with mode: 0644]
src/include/ip_checksum.h [new file with mode: 0644]
src/include/mem.h [new file with mode: 0644]
src/include/part/fallback_boot.h [new file with mode: 0644]
src/include/part/sizeram.h [new file with mode: 0644]
src/include/pc80/mc146818rtc.h [new file with mode: 0644]
src/include/smp/atomic.h [new file with mode: 0644]
src/include/smp/spinlock.h [new file with mode: 0644]
src/include/smp/start_stop.h [new file with mode: 0644]
src/include/stdlib.h [new file with mode: 0644]
src/include/stream/read_bytes.h [new file with mode: 0644]
src/include/string.h [new file with mode: 0644]
src/include/uart8250.h [new file with mode: 0644]
src/include/version.h [new file with mode: 0644]
src/lib/clog2.c [new file with mode: 0644]
src/lib/compute_ip_checksum.c [new file with mode: 0644]
src/lib/delay.c [new file with mode: 0644]
src/lib/fallback_boot.c [new file with mode: 0644]
src/lib/malloc.c [new file with mode: 0644]
src/lib/memcmp.c [new file with mode: 0644]
src/lib/memcpy.c [new file with mode: 0644]
src/lib/memset.c [new file with mode: 0644]
src/lib/uart8250.c [new file with mode: 0644]
src/lib/version.c [new file with mode: 0644]
src/mainboard/amd/solo/auto.c [new file with mode: 0644]
src/mainboard/amd/solo/cmos.layout [new file with mode: 0644]
src/mainboard/amd/solo/mainboard.c [new file with mode: 0644]
src/northbridge/amd/amdk8/northbridge.c [new file with mode: 0644]
src/pc80/mc146818rtc.c [new file with mode: 0644]
src/pc80/serial.c [new file with mode: 0644]
src/pc80/serial.inc [new file with mode: 0644]
src/ram/ramtest.c [new file with mode: 0644]
src/sdram/generic_dump_spd.c [new file with mode: 0644]
src/sdram/generic_sdram.c [new file with mode: 0644]
src/stream/rom_stream.c [new file with mode: 0644]
util/nrv2b/Makefile [new file with mode: 0644]
util/nrv2b/nrv2b.c [new file with mode: 0644]
util/options/build_opt_tbl.c [new file with mode: 0644]

diff --git a/src/arch/i386/boot/boot.c b/src/arch/i386/boot/boot.c
new file mode 100644 (file)
index 0000000..84c71da
--- /dev/null
@@ -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 (file)
index 0000000..1925f2d
--- /dev/null
@@ -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 (file)
index 0000000..42c0a07
--- /dev/null
@@ -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 (file)
index 0000000..a7325c4
--- /dev/null
@@ -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 (file)
index 0000000..07579fe
--- /dev/null
@@ -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 (file)
index 0000000..ea63e2d
--- /dev/null
@@ -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 (file)
index 0000000..3ff51c3
--- /dev/null
@@ -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 (file)
index 0000000..df6604e
--- /dev/null
@@ -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 (file)
index 0000000..bcba9a9
--- /dev/null
@@ -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 (file)
index 0000000..8695ee2
--- /dev/null
@@ -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 (file)
index 0000000..215c4e5
--- /dev/null
@@ -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 (file)
index 0000000..b51a805
--- /dev/null
@@ -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 (file)
index 0000000..02cc272
--- /dev/null
@@ -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 (file)
index 0000000..305276e
--- /dev/null
@@ -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 (file)
index 0000000..fae2045
--- /dev/null
@@ -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 (file)
index 0000000..4bf6b0a
--- /dev/null
@@ -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 (file)
index 0000000..58d7519
--- /dev/null
@@ -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 (file)
index 0000000..f5ca338
--- /dev/null
@@ -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 (file)
index 0000000..8c8eccd
--- /dev/null
@@ -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 (file)
index 0000000..3d6b01b
--- /dev/null
@@ -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 (file)
index 0000000..3e27e7a
--- /dev/null
@@ -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 (file)
index 0000000..c7c05e2
--- /dev/null
@@ -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 (file)
index 0000000..c9cf729
--- /dev/null
@@ -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 (file)
index 0000000..f28e23a
--- /dev/null
@@ -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 (file)
index 0000000..ccdf700
--- /dev/null
@@ -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 (file)
index 0000000..70c10b0
--- /dev/null
@@ -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 (file)
index 0000000..80921bf
--- /dev/null
@@ -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 (file)
index 0000000..3bb5fa1
--- /dev/null
@@ -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 (file)
index 0000000..da0e909
--- /dev/null
@@ -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 (file)
index 0000000..3507f88
--- /dev/null
@@ -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 (executable)
index 0000000..557b952
--- /dev/null
@@ -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 (executable)
index 0000000..557b952
--- /dev/null
@@ -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 (file)
index 0000000..187a99a
--- /dev/null
@@ -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 (file)
index 0000000..458fbb8
--- /dev/null
@@ -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 (file)
index 0000000..e605ae5
--- /dev/null
@@ -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 (file)
index 0000000..67b0d4e
--- /dev/null
@@ -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 (file)
index 0000000..6eeeb6a
--- /dev/null
@@ -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 (file)
index 0000000..ffd6699
--- /dev/null
@@ -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 (file)
index 0000000..b1310c6
--- /dev/null
@@ -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 (file)
index 0000000..c357504
--- /dev/null
@@ -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 (file)
index 0000000..db37e66
--- /dev/null
@@ -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 (file)
index 0000000..8ccd638
--- /dev/null
@@ -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 (file)
index 0000000..37a75ba
--- /dev/null
@@ -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 (file)
index 0000000..7c911d9
--- /dev/null
@@ -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 (file)
index 0000000..80f2fc0
--- /dev/null
@@ -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 (file)
index 0000000..ec743b7
--- /dev/null
@@ -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 (file)
index 0000000..fa6db86
--- /dev/null
@@ -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 (file)
index 0000000..9f306d1
--- /dev/null
@@ -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 (file)
index 0000000..7cd8443
--- /dev/null
@@ -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 (file)
index 0000000..d90cc2c
--- /dev/null
@@ -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 (file)
index 0000000..b88e174
--- /dev/null
@@ -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 (file)
index 0000000..ffc7253
--- /dev/null
@@ -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 (file)
index 0000000..fdaa20d
--- /dev/null
@@ -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 (file)
index 0000000..2b309a9
--- /dev/null
@@ -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 (file)
index 0000000..3503388
--- /dev/null
@@ -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 (file)
index 0000000..ee6750d
--- /dev/null
@@ -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 (file)
index 0000000..5f37993
--- /dev/null
@@ -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 (file)
index 0000000..618c32e
--- /dev/null
@@ -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 (file)
index 0000000..57ba9da
--- /dev/null
@@ -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 (file)
index 0000000..a191b30
--- /dev/null
@@ -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 (file)
index 0000000..208dab0
--- /dev/null
@@ -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 (file)
index 0000000..b23afa5
--- /dev/null
@@ -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 (file)
index 0000000..0e3db3d
--- /dev/null
@@ -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 (file)
index 0000000..ea376da
--- /dev/null
@@ -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 (file)
index 0000000..9500ec2
--- /dev/null
@@ -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 (file)
index 0000000..ce9e6d4
--- /dev/null
@@ -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 (file)
index 0000000..b8ffc88
--- /dev/null
@@ -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 (file)
index 0000000..b91cdb2
--- /dev/null
@@ -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 (file)
index 0000000..9b0f2fa
--- /dev/null
@@ -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 (file)
index 0000000..4977b02
--- /dev/null
@@ -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 (file)
index 0000000..16af10b
--- /dev/null
@@ -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 (file)
index 0000000..bffb719
--- /dev/null
@@ -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 (file)
index 0000000..c2cb938
--- /dev/null
@@ -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 (file)
index 0000000..e8f633b
--- /dev/null
@@ -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 (file)
index 0000000..1eb2f7b
--- /dev/null
@@ -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 (file)
index 0000000..50a44f3
--- /dev/null
@@ -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 (file)
index 0000000..1daf39a
--- /dev/null
@@ -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 (file)
index 0000000..b36e0e2
--- /dev/null
@@ -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 (file)
index 0000000..9e0f8af
--- /dev/null
@@ -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 (file)
index 0000000..c0eebd0
--- /dev/null
@@ -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 (file)
index 0000000..eb67d20
--- /dev/null
@@ -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 (file)
index 0000000..dd3ef04
--- /dev/null
@@ -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 (file)
index 0000000..cf9bbb1
--- /dev/null
@@ -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 (file)
index 0000000..ae45615
--- /dev/null
@@ -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 (file)
index 0000000..223b9a3
--- /dev/null
@@ -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 (file)
index 0000000..092b49c
--- /dev/null
@@ -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 (file)
index 0000000..0b8eb90
--- /dev/null
@@ -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 (file)
index 0000000..af5f786
--- /dev/null
@@ -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 (file)
index 0000000..1bddd0a
--- /dev/null
@@ -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 (file)
index 0000000..bd403e4
--- /dev/null
@@ -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 (file)
index 0000000..46f13a4
--- /dev/null
@@ -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 (file)
index 0000000..ad8e8bd
--- /dev/null
@@ -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 (file)
index 0000000..c1bb4f8
--- /dev/null
@@ -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 (file)
index 0000000..778919b
--- /dev/null
@@ -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 (file)
index 0000000..73d52ca
--- /dev/null
@@ -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 (file)
index 0000000..bc549fa
--- /dev/null
@@ -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 (file)
index 0000000..5ba4c03
--- /dev/null
@@ -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 (file)
index 0000000..b8b8d6c
--- /dev/null
@@ -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 (file)
index 0000000..1ba87bd
--- /dev/null
@@ -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 (file)
index 0000000..b77653c
--- /dev/null
@@ -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 (file)
index 0000000..b10d22d
--- /dev/null
@@ -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 (file)
index 0000000..b0f1269
--- /dev/null
@@ -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 (file)
index 0000000..0e5e698
--- /dev/null
@@ -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 (file)
index 0000000..27f1844
--- /dev/null
@@ -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 (file)
index 0000000..be5ae87
--- /dev/null
@@ -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 (file)
index 0000000..20b7686
--- /dev/null
@@ -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;
+}
diff --git a/util/nrv2b/Makefile b/util/nrv2b/Makefile
new file mode 100644 (file)
index 0000000..e4d6e7b
--- /dev/null
@@ -0,0 +1,7 @@
+GCC=gcc
+
+nrv2b: nrv2b.c
+       $(GCC) -O2 -DENCODE -DDECODE -DMAIN -DVERBOSE -DNDEBUG -DBITSIZE=32 -DENDIAN=0 -o $@ $<
+
+clean:
+       rm -f nrv2b
diff --git a/util/nrv2b/nrv2b.c b/util/nrv2b/nrv2b.c
new file mode 100644 (file)
index 0000000..f12a4f5
--- /dev/null
@@ -0,0 +1,1472 @@
+/**************************************************************
+    Form adapted from lzhuf.c
+    written by Haruyasu Yoshizaki 11/20/1988
+    some minor changes 4/6/1989
+    comments translated by Haruhiko Okumura 4/7/1989
+
+    minor beautifications and adjustments for compiling under Linux
+    by Markus Gutschke <gutschk@math.uni-muenster.de>
+                                               1997-01-27
+
+    Modifications to allow use as a filter by Ken Yap
+    <ken_yap@users.sourceforge.net>.
+
+                                               1997-07-01
+
+    Small mod to cope with running on big-endian machines
+    by Jim Hague <jim.hague@acm.org)
+                                               1998-02-06
+
+    Make compression statistics report shorter
+    by Ken Yap <ken_yap@users.sourceforge.net>.
+                                               2001-04-25
+
+    Replaced algorithm with nrv2b from ucl the compression
+    library from upx.  That code is:
+    Copyright (C) 1996-2002 Markus Franz Xaver Johannes Oberhumer
+    And is distributed under the terms of the GPL.
+    The conversion was performed 
+    by Eric Biederman <ebiederman@lnxi.com>.
+                                             20 August 2002
+                                                
+**************************************************************/
+#define UCLPACK_COMPAT 0
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdint.h>
+#include <limits.h>
+#include <assert.h>
+#if UCLPACK_COMPAT
+#include <netinet/in.h>
+#endif
+
+#ifndef VERBOSE
+#define Fprintf(x)
+#define wterr     0
+#else
+#define Fprintf(x) fprintf x
+#endif
+
+#ifndef MAIN
+extern
+#endif
+FILE  *infile, *outfile;
+
+#if defined(ENCODE) || defined(DECODE)
+
+#ifndef ENDIAN
+#define ENDIAN   0
+#endif
+#ifndef BITSIZE
+#define BITSIZE 32
+#endif
+
+static __inline__ void Error(char *message)
+{
+       Fprintf((stderr, "\n%s\n", message));
+       exit(EXIT_FAILURE);
+}
+
+/* These will be a complete waste of time on a lo-endian */
+/* system, but it only gets done once so WTF. */
+static unsigned long i86ul_to_host(unsigned long ul)
+{
+       unsigned long res = 0;
+       int i;
+       union
+       {
+               unsigned char c[4];
+               unsigned long ul;
+       } u;
+
+       u.ul = ul;
+       for (i = 3; i >= 0; i--)
+               res = (res << 8) + u.c[i];
+       return res;
+}
+
+static unsigned long host_to_i86ul(unsigned long ul)
+{
+       int i;
+       union
+       {
+               unsigned char c[4];
+               unsigned long ul;
+       } u;
+
+       for (i = 0; i < 4; i++)
+       {
+               u.c[i] = ul & 0xff;
+               ul >>= 8;
+       }
+       return u.ul;
+}
+#endif
+
+
+
+#if UCLPACK_COMPAT
+/* magic file header for compressed files */
+static const unsigned char magic[8] =
+{ 0x00, 0xe9, 0x55, 0x43, 0x4c, 0xff, 0x01, 0x1a };
+
+#endif
+
+#ifdef ENCODE
+/********** NRV2B_99 compression **********/
+
+#define N       (1024*1024ul)       /* size of ring buffer */
+#define THRESHOLD       1           /* lower limit for match length */
+#define F            2048           /* upper limit for match length */
+#define M2_MAX_OFFSET                 0xd00
+
+/* note: to use default values pass -1, i.e. initialize
+ * this struct by a memset(x,0xff,sizeof(x)) */
+struct ucl_compress_config
+{
+       int bb_endian;
+       int bb_size;
+       unsigned int max_offset;
+       unsigned int max_match;
+       int s_level;
+       int h_level;
+       int p_level;
+       int c_flags;
+       unsigned int m_size;
+};
+
+struct ucl_compress
+{
+       int init;
+
+       unsigned int look;          /* bytes in lookahead buffer */
+       
+       unsigned int m_len;
+       unsigned int m_off;
+       
+       unsigned int last_m_len;
+       unsigned int last_m_off;
+       
+       const unsigned char *bp;
+       const unsigned char *ip;
+       const unsigned char *in;
+       const unsigned char *in_end;
+       unsigned char *out;
+       
+       uint32_t bb_b;
+       unsigned bb_k;
+       unsigned bb_c_endian;
+       unsigned bb_c_s;
+       unsigned bb_c_s8;
+       unsigned char *bb_p;
+       unsigned char *bb_op;
+       
+       struct ucl_compress_config conf;
+       unsigned int *result;
+
+       unsigned int textsize;      /* text size counter */
+       unsigned int codesize;      /* code size counter */
+       unsigned int printcount; /* counter for reporting progress every 1K
+                                   bytes */
+
+       
+       /* some stats */
+       unsigned long lit_bytes;
+       unsigned long match_bytes;
+       unsigned long rep_bytes;
+       unsigned long lazy;
+};
+
+
+
+#define getbyte(c)  ((c).ip < (c).in_end ? *((c).ip)++ : (-1))
+
+#define UCL_E_OK               0
+#define UCL_E_INVALID_ARGUMENT 1
+#define UCL_E_OUT_OF_MEMORY    2
+#define UCL_E_ERROR            3
+
+/***********************************************************************
+//
+************************************************************************/
+
+#define SWD_HSIZE      16384
+#define SWD_MAX_CHAIN  2048
+
+#define HEAD3(b,p) \
+    (((0x9f5f*(((((uint32_t)b[p]<<5)^b[p+1])<<5)^b[p+2]))>>5) & (SWD_HSIZE-1))
+
+#define HEAD2(b,p)      (b[p] ^ ((unsigned)b[p+1]<<8))
+#define NIL2              UINT_MAX
+
+struct ucl_swd
+{
+/* public - "built-in" */
+       unsigned int n;
+       unsigned int f;
+       unsigned int threshold;
+       
+/* public - configuration */
+       unsigned int max_chain;
+       unsigned int nice_length;
+       int use_best_off;
+       unsigned int lazy_insert;
+       
+/* public - output */
+       unsigned int m_len;
+       unsigned int m_off;
+       unsigned int look;
+       int b_char;
+#if defined(SWD_BEST_OFF)
+       unsigned int best_off[ SWD_BEST_OFF ];
+#endif
+       
+/* semi public */
+       struct ucl_compress *c;
+       unsigned int m_pos;
+#if defined(SWD_BEST_OFF)
+       unsigned int best_pos[ SWD_BEST_OFF ];
+#endif
+       
+/* private */
+       const uint8_t *dict;
+       const uint8_t *dict_end;
+       unsigned int dict_len;
+       
+/* private */
+       unsigned int ip;                /* input pointer (lookahead) */
+       unsigned int bp;                /* buffer pointer */
+       unsigned int rp;                /* remove pointer */
+       unsigned int b_size;
+       
+       unsigned char *b_wrap;
+       
+       unsigned int node_count;
+       unsigned int first_rp;
+
+       unsigned char b [ N + F + F ];
+       unsigned int head3 [ SWD_HSIZE ];
+       unsigned int succ3 [ N + F ];
+       unsigned int best3 [ N + F ];
+       unsigned int llen3 [ SWD_HSIZE ];
+       unsigned int head2 [ 65536U ];
+};
+
+#define s_head3(s,key)        s->head3[key]
+
+
+#if !defined( NDEBUG)
+static void assert_match(const struct ucl_swd * swd, unsigned int m_len,
+       unsigned int m_off )
+
+{
+       const struct ucl_compress *c = swd->c;
+       unsigned int d_off;
+       
+       assert(m_len >= 2);
+       if (m_off <= (unsigned int) (c->bp - c->in))
+       {
+               assert(c->bp - m_off + m_len < c->ip);
+               assert(memcmp(c->bp, c->bp - m_off, m_len) == 0);
+       }
+       else
+       {
+               assert(swd->dict != NULL);
+               d_off = m_off - (unsigned int) (c->bp - c->in);
+               assert(d_off <= swd->dict_len);
+               if (m_len > d_off)
+               {
+                       assert(memcmp(c->bp, swd->dict_end - d_off, d_off) ==
+                               0);
+
+                       assert(c->in + m_len - d_off < c->ip);
+                       assert(memcmp(c->bp + d_off, c->in, m_len - d_off) ==
+                               0);
+
+               }
+               else
+               {
+                       assert(memcmp(c->bp, swd->dict_end - d_off, m_len) ==
+                               0);
+
+               }
+       }
+}
+#else
+#  define assert_match(a,b,c)   ((void)0)
+#endif
+
+/***********************************************************************
+//
+************************************************************************/
+
+
+static
+void swd_initdict(struct ucl_swd *s, const uint8_t *dict, unsigned int dict_len)
+
+{
+       s->dict = s->dict_end = NULL;
+       s->dict_len = 0;
+
+       if (!dict || dict_len <= 0)
+               return;
+       if (dict_len > s->n)
+       {
+               dict += dict_len - s->n;
+               dict_len = s->n;
+       }
+
+       s->dict = dict;
+       s->dict_len = dict_len;
+       s->dict_end = dict + dict_len;
+       memcpy(s->b,dict,dict_len);
+       s->ip = dict_len;
+}
+
+
+static
+void swd_insertdict(struct ucl_swd *s, unsigned int node, unsigned int len)
+{
+       unsigned int key;
+
+       s->node_count = s->n - len;
+       s->first_rp = node;
+
+       while (len-- > 0)
+       {
+               key = HEAD3(s->b,node);
+               s->succ3[node] = s_head3(s,key);
+               s->head3[key] = (unsigned int)(node);
+               s->best3[node] = (unsigned int)(s->f + 1);
+               s->llen3[key]++;
+               assert(s->llen3[key] <= s->n);
+
+               key = HEAD2(s->b,node);
+               s->head2[key] = (unsigned int)(node);
+
+               node++;
+       }
+}
+
+/***********************************************************************
+//
+************************************************************************/
+
+
+static
+int swd_init(struct ucl_swd *s, const uint8_t *dict, unsigned int dict_len)
+{
+       unsigned int i = 0;
+       int c = 0;
+
+       if (s->n == 0)
+               s->n = N;
+       if (s->f == 0)
+               s->f = F;
+       s->threshold = THRESHOLD;
+       if (s->n > N || s->f > F)
+               return UCL_E_INVALID_ARGUMENT;
+
+       /* defaults */
+       s->max_chain = SWD_MAX_CHAIN;
+       s->nice_length = s->f;
+       s->use_best_off = 0;
+       s->lazy_insert = 0;
+
+       s->b_size = s->n + s->f;
+       if (s->b_size + s->f >= UINT_MAX)
+               return UCL_E_ERROR;
+       s->b_wrap = s->b + s->b_size;
+       s->node_count = s->n;
+
+       memset(s->llen3, 0, sizeof(s->llen3[0]) * SWD_HSIZE);
+       for (i = 0; i < 65536U; i++)
+               s->head2[i] = NIL2;
+
+       s->ip = 0;
+       swd_initdict(s,dict,dict_len);
+       s->bp = s->ip;
+       s->first_rp = s->ip;
+
+       assert(s->ip + s->f <= s->b_size);
+
+       s->look = (unsigned int) (s->c->in_end - s->c->ip);
+       if (s->look > 0)
+       {
+               if (s->look > s->f)
+                       s->look = s->f;
+               memcpy(&s->b[s->ip],s->c->ip,s->look);
+               s->c->ip += s->look;
+               s->ip += s->look;
+       }
+       if (s->ip == s->b_size)
+               s->ip = 0;
+
+       if (s->look >= 2 && s->dict_len > 0)
+               swd_insertdict(s,0,s->dict_len);
+
+       s->rp = s->first_rp;
+       if (s->rp >= s->node_count)
+               s->rp -= s->node_count;
+       else
+               s->rp += s->b_size - s->node_count;
+
+       /* unused i */
+       /* unused c */
+       return UCL_E_OK;
+}
+
+
+static
+void swd_exit(struct ucl_swd *s)
+{
+       /* unused s */
+
+}
+
+#define swd_pos2off(s,pos) \
+       (s->bp > (pos) ? s->bp - (pos) : s->b_size - ((pos) - s->bp))
+
+/***********************************************************************
+//
+************************************************************************/
+
+static __inline__
+void swd_getbyte(struct ucl_swd *s)
+{
+       int c;
+
+       if ((c = getbyte(*(s->c))) < 0)
+       {
+               if (s->look > 0)
+                       --s->look;
+       }
+       else
+       {
+               s->b[s->ip] = (uint8_t)(c);
+               if (s->ip < s->f)
+                       s->b_wrap[s->ip] = (uint8_t)(c);
+       }
+       if (++s->ip == s->b_size)
+               s->ip = 0;
+       if (++s->bp == s->b_size)
+               s->bp = 0;
+       if (++s->rp == s->b_size)
+               s->rp = 0;
+}
+/***********************************************************************
+// remove node from lists
+************************************************************************/
+
+static __inline__
+void swd_remove_node(struct ucl_swd *s, unsigned int node)
+{
+       if (s->node_count == 0)
+       {
+               unsigned int key;
+               
+#ifdef UCL_DEBUG
+               if (s->first_rp != UINT_MAX)
+               {
+                       if (node != s->first_rp)
+                               printf("Remove %5d: %5d %5d %5d %5d %6d %6d\n",
+
+                                       node, s->rp, s->ip, s->bp, s->first_rp,
+                                       s->ip - node, s->ip - s->bp);
+                       assert(node == s->first_rp);
+                       s->first_rp = UINT_MAX;
+               }
+#endif
+               
+               key = HEAD3(s->b,node);
+               assert(s->llen3[key] > 0);
+               --s->llen3[key];
+               
+               key = HEAD2(s->b,node);
+               assert(s->head2[key] != NIL2);
+               if ((unsigned int) s->head2[key] == node)
+                       s->head2[key] = NIL2;
+       }
+       else
+               --s->node_count;
+}
+
+
+/***********************************************************************
+//
+************************************************************************/
+
+
+static
+void swd_accept(struct ucl_swd *s, unsigned int n)
+{
+       assert(n <= s->look);
+
+       if (n > 0) do
+       {
+               unsigned int key;
+
+               swd_remove_node(s,s->rp);
+
+               /* add bp into HEAD3 */
+               key = HEAD3(s->b,s->bp);
+               s->succ3[s->bp] = s_head3(s,key);
+               s->head3[key] = (unsigned int)(s->bp);
+               s->best3[s->bp] = (unsigned int)(s->f + 1);
+               s->llen3[key]++;
+               assert(s->llen3[key] <= s->n);
+
+               /* add bp into HEAD2 */
+               key = HEAD2(s->b,s->bp);
+               s->head2[key] = (unsigned int)(s->bp);
+
+               swd_getbyte(s);
+       } while (--n > 0);
+}
+
+/***********************************************************************
+//
+************************************************************************/
+
+static
+void swd_search(struct ucl_swd *s, unsigned int node, unsigned int cnt)
+{
+       const unsigned char *p1;
+       const unsigned char *p2;
+       const unsigned char *px;
+
+       unsigned int m_len = s->m_len;
+       const unsigned char * b  = s->b;
+       const unsigned char * bp = s->b + s->bp;
+       const unsigned char * bx = s->b + s->bp + s->look;
+       unsigned char scan_end1;
+       
+       assert(s->m_len > 0);
+       
+       scan_end1 = bp[m_len - 1];
+       for ( ; cnt-- > 0; node = s->succ3[node])
+       {
+               p1 = bp;
+               p2 = b + node;
+               px = bx;
+               
+               assert(m_len < s->look);
+               
+               if (
+                       p2[m_len - 1] == scan_end1 &&
+                       p2[m_len] == p1[m_len] &&
+                       p2[0] == p1[0] &&
+                       p2[1] == p1[1])
+               {
+                       unsigned int i;
+                       assert(memcmp(bp,&b[node],3) == 0);
+                       
+                       p1 += 2; p2 += 2;
+                       do {} while (++p1 < px && *p1 == *++p2);
+                       i = p1 - bp;
+                       
+#ifdef UCL_DEBUG
+                       if (memcmp(bp,&b[node],i) != 0)
+                               printf("%5ld %5ld %02x%02x %02x%02x\n",
+                                       (long)s->bp, (long) node,
+                                       bp[0], bp[1], b[node], b[node+1]);
+#endif
+                       assert(memcmp(bp,&b[node],i) == 0);
+                       
+#if defined(SWD_BEST_OFF)
+                       if (i < SWD_BEST_OFF)
+                       {
+                               if (s->best_pos[i] == 0)
+                                       s->best_pos[i] = node + 1;
+                       }
+#endif
+                       if (i > m_len)
+                       {
+                               s->m_len = m_len = i;
+                               s->m_pos = node;
+                               if (m_len == s->look)
+                                       return;
+                               if (m_len >= s->nice_length)
+                                       return;
+                               if (m_len > (unsigned int) s->best3[node])
+                                       return;
+                               scan_end1 = bp[m_len - 1];
+                       }
+               }
+       }
+}
+
+static int swd_search2(struct ucl_swd *s)
+{
+       unsigned int key;
+       
+       assert(s->look >= 2);
+       assert(s->m_len > 0);
+       
+       key = s->head2[ HEAD2(s->b,s->bp) ];
+       if (key == NIL2)
+               return 0;
+#ifdef UCL_DEBUG
+       if (memcmp(&s->b[s->bp],&s->b[key],2) != 0)
+               printf("%5ld %5ld %02x%02x %02x%02x\n", (long)s->bp, (long)key,
+                       s->b[s->bp], s->b[s->bp+1], s->b[key], s->b[key+1]);
+#endif
+       assert(memcmp(&s->b[s->bp],&s->b[key],2) == 0);
+#if defined(SWD_BEST_OFF)
+       if (s->best_pos[2] == 0)
+               s->best_pos[2] = key + 1;
+#endif
+       
+       if (s->m_len < 2)
+       {
+               s->m_len = 2;
+               s->m_pos = key;
+       }
+       return 1;
+}
+
+/***********************************************************************
+//
+************************************************************************/
+
+static
+void swd_findbest(struct ucl_swd *s)
+{
+       unsigned int key;
+       unsigned int cnt, node;
+       unsigned int len;
+
+       assert(s->m_len > 0);
+
+       /* get current head, add bp into HEAD3 */
+       key = HEAD3(s->b,s->bp);
+       node = s->succ3[s->bp] = s_head3(s,key);
+       cnt = s->llen3[key]++;
+       assert(s->llen3[key] <= s->n + s->f);
+       if (cnt > s->max_chain && s->max_chain > 0)
+               cnt = s->max_chain;
+       s->head3[key] = (unsigned int)(s->bp);
+
+       s->b_char = s->b[s->bp];
+       len = s->m_len;
+       if (s->m_len >= s->look)
+       {
+               if (s->look == 0)
+                       s->b_char = -1;
+               s->m_off = 0;
+               s->best3[s->bp] = (unsigned int)(s->f + 1);
+       }
+       else
+       {
+               if (swd_search2(s))
+                       if (s->look >= 3)
+                               swd_search(s,node,cnt);
+               if (s->m_len > len)
+                       s->m_off = swd_pos2off(s,s->m_pos);
+               s->best3[s->bp] = (unsigned int)(s->m_len);
+
+#if defined(SWD_BEST_OFF)
+               if (s->use_best_off)
+               {
+                       int i;
+                       for (i = 2; i < SWD_BEST_OFF; i++)
+                               if (s->best_pos[i] > 0)
+                                       s->best_off[i] =
+                                               swd_pos2off(s,s->best_pos[i]-1);
+
+                               else
+                                       s->best_off[i] = 0;
+               }
+#endif
+       }
+
+       swd_remove_node(s,s->rp);
+
+       /* add bp into HEAD2 */
+       key = HEAD2(s->b,s->bp);
+       s->head2[key] = (unsigned int)(s->bp);
+}
+
+
+/***********************************************************************
+//
+************************************************************************/
+
+static int
+init_match ( struct ucl_compress *c, struct ucl_swd *s,
+       const uint8_t *dict, unsigned int dict_len,
+       uint32_t flags )
+{
+       int r;
+       
+       assert(!c->init);
+       c->init = 1;
+       
+       s->c = c;
+       
+       c->last_m_len = c->last_m_off = 0;
+       
+       c->textsize = c->codesize = c->printcount = 0;
+       c->lit_bytes = c->match_bytes = c->rep_bytes = 0;
+       c->lazy = 0;
+       
+       r = swd_init(s,dict,dict_len);
+       if (r != UCL_E_OK)
+       {
+               swd_exit(s);
+               return r;
+       }
+       
+       s->use_best_off = (flags & 1) ? 1 : 0;
+       return UCL_E_OK;
+}
+
+static int
+find_match ( struct ucl_compress *c, struct ucl_swd *s,
+       unsigned int this_len, unsigned int skip )
+{
+       assert(c->init);
+       
+       if (skip > 0)
+       {
+               assert(this_len >= skip);
+               swd_accept(s, this_len - skip);
+               c->textsize += this_len - skip + 1;
+       }
+       else
+       {
+               assert(this_len <= 1);
+               c->textsize += this_len - skip;
+       }
+       
+       s->m_len = THRESHOLD;
+#ifdef SWD_BEST_OFF
+       if (s->use_best_off)
+               memset(s->best_pos,0,sizeof(s->best_pos));
+#endif
+       swd_findbest(s);
+       c->m_len = s->m_len;
+       c->m_off = s->m_off;
+       
+       swd_getbyte(s);
+       
+       if (s->b_char < 0)
+       {
+               c->look = 0;
+               c->m_len = 0;
+               swd_exit(s);
+       }
+       else
+       {
+               c->look = s->look + 1;
+       }
+       c->bp = c->ip - c->look;
+       
+#if 0
+       /* brute force match search */
+       if (c->m_len > THRESHOLD && c->m_len + 1 <= c->look)
+       {
+               const uint8_t *ip = c->bp;
+               const uint8_t *m  = c->bp - c->m_off;
+               const uint8_t *in = c->in;
+               
+               if (ip - in > N)
+                       in = ip - N;
+               for (;;)
+               {
+                       while (*in != *ip)
+                               in++;
+                       if (in == ip)
+                               break;
+                       if (in != m)
+                               if (memcmp(in,ip,c->m_len+1) == 0)
+                                       printf("%p %p %p
+%5d\n",in,ip,m,c->m_len);
+
+                       in++;
+               }
+       }
+#endif
+       
+       return UCL_E_OK;
+}
+
+
+static int bbConfig(struct ucl_compress *c, int endian, int bitsize)
+{
+       if (endian != -1)
+       {
+               if (endian != 0)
+                       return UCL_E_ERROR;
+               c->bb_c_endian = endian;
+       }
+       if (bitsize != -1)
+       {
+               if (bitsize != 8 && bitsize != 16 && bitsize != 32)
+                       return UCL_E_ERROR;
+               c->bb_c_s = bitsize;
+               c->bb_c_s8 = bitsize / 8;
+       }
+       c->bb_b = 0; c->bb_k = 0;
+       c->bb_p = NULL;
+       c->bb_op = NULL;
+       return UCL_E_OK;
+}
+
+static void bbWriteBits(struct ucl_compress *c)
+{
+       uint8_t *p = c->bb_p;
+       uint32_t b = c->bb_b;
+
+       p[0] = (uint8_t)(b >>  0);
+       if (c->bb_c_s >= 16)
+       {
+               p[1] = (uint8_t)(b >>  8);
+               if (c->bb_c_s == 32)
+               {
+                       p[2] = (uint8_t)(b >> 16);
+                       p[3] = (uint8_t)(b >> 24);
+               }
+       }
+}
+
+
+static void bbPutBit(struct ucl_compress *c, unsigned bit)
+{
+       assert(bit == 0 || bit == 1);
+       assert(c->bb_k <= c->bb_c_s);
+
+       if (c->bb_k < c->bb_c_s)
+       {
+               if (c->bb_k == 0)
+               {
+                       assert(c->bb_p == NULL);
+                       c->bb_p = c->bb_op;
+                       c->bb_op += c->bb_c_s8;
+               }
+               assert(c->bb_p != NULL);
+               assert(c->bb_p + c->bb_c_s8 <= c->bb_op);
+
+               c->bb_b = (c->bb_b << 1) + bit;
+               c->bb_k++;
+       }
+       else
+       {
+               assert(c->bb_p != NULL);
+               assert(c->bb_p + c->bb_c_s8 <= c->bb_op);
+
+               bbWriteBits(c);
+               c->bb_p = c->bb_op;
+               c->bb_op += c->bb_c_s8;
+               c->bb_b = bit;
+               c->bb_k = 1;
+       }
+}
+
+
+static void bbPutByte(struct ucl_compress *c, unsigned b)
+{
+       /**printf("putbyte %p %p %x  (%d)\n", op, bb_p, x, bb_k);*/
+       assert(c->bb_p == NULL || c->bb_p + c->bb_c_s8 <= c->bb_op);
+       *c->bb_op++ = (uint8_t)(b);
+}
+
+static void bbFlushBits(struct ucl_compress *c, unsigned filler_bit)
+{
+       if (c->bb_k > 0)
+       {
+               assert(c->bb_k <= c->bb_c_s);
+               while (c->bb_k != c->bb_c_s)
+                       bbPutBit(c, filler_bit);
+               bbWriteBits(c);
+               c->bb_k = 0;
+       }
+       c->bb_p = NULL;
+}
+
+
+
+/***********************************************************************
+//
+************************************************************************/
+
+
+static void code_prefix_ss11(struct ucl_compress *c, uint32_t i)
+{
+       if (i >= 2)
+       {
+               uint32_t t = 4;
+               i += 2;
+               do {
+                       t <<= 1;
+               } while (i >= t);
+               t >>= 1;
+               do {
+                       t >>= 1;
+                       bbPutBit(c, (i & t) ? 1 : 0);
+                       bbPutBit(c, 0);
+               } while (t > 2);
+       }
+       bbPutBit(c, (unsigned)i & 1);
+       bbPutBit(c, 1);
+}
+
+static void
+code_match(struct ucl_compress *c, unsigned int m_len, const unsigned int m_off)
+
+{
+       while (m_len > c->conf.max_match)
+       {
+               code_match(c, c->conf.max_match - 3, m_off);
+               m_len -= c->conf.max_match - 3;
+       }
+       
+       c->match_bytes += m_len;
+       if (m_len > c->result[3])
+               c->result[3] = m_len;
+       if (m_off > c->result[1])
+               c->result[1] = m_off;
+
+       bbPutBit(c, 0);
+
+       if (m_off == c->last_m_off)
+       {
+               bbPutBit(c, 0);
+               bbPutBit(c, 1);
+       }
+       else
+       {
+               code_prefix_ss11(c, 1 + ((m_off - 1) >> 8));
+               bbPutByte(c, (unsigned)m_off - 1);
+       }
+       m_len = m_len - 1 - (m_off > M2_MAX_OFFSET);
+       if (m_len >= 4)
+       {
+               bbPutBit(c,0);
+               bbPutBit(c,0);
+               code_prefix_ss11(c, m_len - 4);
+       }
+       else
+       {
+               bbPutBit(c, m_len > 1);
+               bbPutBit(c, (unsigned)m_len & 1);
+       }
+
+       c->last_m_off = m_off;
+}
+
+static void
+code_run(struct ucl_compress *c, const uint8_t *ii, unsigned int lit)
+{
+       if (lit == 0)
+               return;
+       c->lit_bytes += lit;
+       if (lit > c->result[5])
+               c->result[5] = lit;
+       do {
+               bbPutBit(c, 1);
+               bbPutByte(c, *ii++);
+       } while (--lit > 0);
+}
+
+/***********************************************************************
+//
+************************************************************************/
+
+static int
+len_of_coded_match(struct ucl_compress *c, unsigned int m_len, unsigned int
+       m_off)
+
+{
+       int b;
+       if (m_len < 2 || (m_len == 2 && (m_off > M2_MAX_OFFSET))
+               || m_off > c->conf.max_offset)
+               return -1;
+       assert(m_off > 0);
+       
+       m_len = m_len - 2 - (m_off > M2_MAX_OFFSET);
+       
+       if (m_off == c->last_m_off)
+               b = 1 + 2;
+       else
+       {
+               b = 1 + 10;
+               m_off = (m_off - 1) >> 8;
+               while (m_off > 0)
+               {
+                       b += 2;
+                       m_off >>= 1;
+               }
+       }
+
+       b += 2;
+       if (m_len < 3)
+               return b;
+       m_len -= 3;
+
+       do {
+               b += 2;
+               m_len >>= 1;
+       } while (m_len > 0);
+
+       return b;
+}
+
+int ucl_nrv2b_99_compress(
+       const uint8_t *in, unsigned long in_len,
+       uint8_t *out, unsigned long *out_len,
+       unsigned int *result)
+{
+       const uint8_t *ii;
+       unsigned int lit;
+       unsigned int m_len, m_off;
+       struct ucl_compress c_buffer;
+       struct ucl_compress * const c = &c_buffer;
+       struct ucl_swd *swd;
+       unsigned int result_buffer[16];
+       int r;
+
+/* max compression */
+#define SC_TRY_LAZY    2
+#define SC_GOOD_LENGTH F
+#define SC_MAX_LAZY    F
+#define SC_NICE_LENGTH F
+#define SC_MAX_CHAIN   4096
+#define SC_FLAGS       1
+#define SC_MAX_OFFSET  N
+       
+       memset(c, 0, sizeof(*c));
+       c->ip = c->in = in;
+       c->in_end = in + in_len;
+       c->out = out;
+       c->result = result ? result : result_buffer;
+       memset(c->result, 0, 16*sizeof(*c->result));
+       c->result[0] = c->result[2] = c->result[4] = UINT_MAX;
+       result = NULL;
+       memset(&c->conf, 0xff, sizeof(c->conf));
+       r = bbConfig(c, ENDIAN, BITSIZE);
+       if (r == 0)
+               r = bbConfig(c, c->conf.bb_endian, c->conf.bb_size);
+       if (r != 0)
+               return UCL_E_INVALID_ARGUMENT;
+       c->bb_op = out;
+       
+       ii = c->ip;             /* point to start of literal run */
+       lit = 0;
+       
+
+       swd = (struct ucl_swd *) malloc(sizeof(*swd));
+       if (!swd)
+               return UCL_E_OUT_OF_MEMORY;
+
+       swd->f = F;
+       swd->n = N;
+       if (in_len >= 256 && in_len < swd->n)
+               swd->n = in_len;
+       if (swd->f < 8 || swd->n < 256)
+               return UCL_E_INVALID_ARGUMENT;
+
+       r = init_match(c,swd,NULL,0, SC_FLAGS);
+       if (r != UCL_E_OK)
+       {
+               free(swd);
+               return r;
+       }
+       if (SC_MAX_CHAIN > 0)
+               swd->max_chain = SC_MAX_CHAIN;
+       if (SC_NICE_LENGTH > 0)
+               swd->nice_length = SC_NICE_LENGTH;
+       if (c->conf.max_match < swd->nice_length)
+               swd->nice_length = c->conf.max_match;
+       
+       c->last_m_off = 1;
+       r = find_match(c,swd,0,0);
+       if (r != UCL_E_OK)
+               return r;
+       while (c->look > 0)
+       {
+               unsigned int ahead;
+               unsigned int max_ahead;
+               int l1, l2;
+               
+               c->codesize = c->bb_op - out;
+               
+               m_len = c->m_len;
+               m_off = c->m_off;
+               
+               assert(c->bp == c->ip - c->look);
+               assert(c->bp >= in);
+               if (lit == 0)
+                       ii = c->bp;
+               assert(ii + lit == c->bp);
+               assert(swd->b_char == *(c->bp));
+               
+               if (m_len < 2 || (m_len == 2 && (m_off > M2_MAX_OFFSET))
+                       || m_off > c->conf.max_offset)
+               {
+                       /* a literal */
+                       lit++;
+                       swd->max_chain = SC_MAX_CHAIN;
+                       r = find_match(c,swd,1,0);
+                       assert(r == 0);
+                       continue;
+               }
+               
+               /* a match */
+               assert_match(swd,m_len,m_off);
+               
+               /* shall we try a lazy match ? */
+               ahead = 0;
+               if (SC_TRY_LAZY <= 0 || m_len >= SC_MAX_LAZY || m_off ==
+                       c->last_m_off)
+
+               {
+                       /* no */
+                       l1 = 0;
+                       max_ahead = 0;
+               }
+               else
+               {
+                       /* yes, try a lazy match */
+                       l1 = len_of_coded_match(c,m_len,m_off);
+                       assert(l1 > 0);
+                       max_ahead = SC_TRY_LAZY;
+                       if ((m_len - 1) < max_ahead) {
+                               max_ahead = m_len -1;
+                       }
+               }
+               
+               while (ahead < max_ahead && c->look > m_len)
+               {
+                       if (m_len >= SC_GOOD_LENGTH)
+                               swd->max_chain = SC_MAX_CHAIN >> 2;
+                       else
+                               swd->max_chain = SC_MAX_CHAIN;
+                       r = find_match(c,swd,1,0);
+                       ahead++;
+                       
+                       assert(r == 0);
+                       assert(c->look > 0);
+                       assert(ii + lit + ahead == c->bp);
+                       
+                       if (c->m_len < 2)
+                               continue;
+                       l2 = len_of_coded_match(c,c->m_len,c->m_off);
+                       if (l2 < 0)
+                               continue;
+                       if (l1 + (int)(ahead + c->m_len - m_len) * 5 > l2 +
+                               (int)(ahead) * 9)
+                       {
+                               c->lazy++;
+                               assert_match(swd,c->m_len,c->m_off);
+                               lit += ahead;
+                               assert(ii + lit == c->bp);
+                               goto lazy_match_done;
+                       }
+               }
+               
+               assert(ii + lit + ahead == c->bp);
+               
+               /* 1 - code run */
+               code_run(c,ii,lit);
+               lit = 0;
+               
+               /* 2 - code match */
+               code_match(c,m_len,m_off);
+               swd->max_chain = SC_MAX_CHAIN;
+               r = find_match(c,swd,m_len,1+ahead);
+               assert(r == 0);
+               
+       lazy_match_done: ;
+       }
+       
+       /* store final run */
+       code_run(c,ii,lit);
+       
+       /* EOF */
+       bbPutBit(c, 0);
+       code_prefix_ss11(c, 0x1000000U);
+       bbPutByte(c, 0xff);
+
+       bbFlushBits(c, 0);
+       
+       assert(c->textsize == in_len);
+       c->codesize = c->bb_op - out;
+       *out_len = c->bb_op - out;
+       
+#if 0
+       printf("%7ld %7ld -> %7ld   %7ld %7ld   %ld  (max: %d %d %d)\n",
+               (long) c->textsize, (long) in_len, (long) c->codesize,
+               c->match_bytes, c->lit_bytes,  c->lazy,
+               c->result[1], c->result[3], c->result[5]);
+#endif
+       assert(c->lit_bytes + c->match_bytes == in_len);
+       
+       swd_exit(swd);
+       free(swd);
+
+       return UCL_E_OK;
+}
+
+
+void Encode(void)  /* compression */
+{
+       uint8_t *in, *out;
+       unsigned long in_len, out_len;
+       uint32_t tw;
+       int r;
+       fseek(infile, 0, SEEK_END);
+       in_len = ftell(infile);
+#ifdef VERBOSE
+       if ((signed long)in_len < 0)
+               Fprintf((stderr, "Errno: %d", errno));
+#endif
+#if UCLPACK_COMPAT
+       {
+               uint8_t byte;
+               if (fwrite(magic, sizeof(magic), 1, outfile) != 1)
+                       Error("Can't write.");
+               tw = htonl(0); /* flags */
+               if (fwrite(&tw, sizeof(tw), 1, outfile) != 1)
+                       Error("Can't write.");
+               byte = 0x2b;            /* method */
+               if (fwrite(&byte, sizeof(byte), 1, outfile) != 1)
+                       Error("Can't write.");
+               byte = 10;              /* level */
+               if (fwrite(&byte, sizeof(byte), 1, outfile) != 1)
+                       Error("Can't write.");
+               tw = htonl(256*1024);           /* block_size */
+               if (fwrite(&tw, sizeof(tw), 1, outfile) != 1)
+                       Error("Can't write.");
+               tw = htonl(in_len);
+               if (fwrite(&tw, sizeof(tw), 1, outfile) != 1)
+                       Error("Can't write.");  /* output size of text */
+       }
+#else
+       tw = host_to_i86ul(in_len);
+       if (fwrite(&tw, sizeof(tw), 1, outfile) != 1)
+               Error("Can't write.");  /* output size of text */
+#endif 
+       if (in_len == 0)
+               return;
+       rewind(infile);
+
+       in = malloc(in_len);
+       out_len = in_len + (in_len/8) + 256;
+       out = malloc(out_len);
+       if (!in || !out) {
+               Error("Can't malloc");
+       }
+       if (fread(in, in_len, 1, infile) != 1) {
+               Error("Can't read");
+       }
+       r = ucl_nrv2b_99_compress(in, in_len, out, &out_len, 0 );
+#if UCLPACK_COMPAT
+       tw = htonl(out_len);
+       if (fwrite(&tw, sizeof(tw), 1, outfile) != 1)
+               Error("Can't write.");  /* file size of text */
+
+#endif
+       if (fwrite(out, out_len, 1, outfile) != 1) {
+               Error("Write error\n");
+       }
+#if UCLPACK_COMPAT
+       tw = htonl(0); /* EOF marker */
+       if (fwrite(&tw, sizeof(tw), 1, outfile) != 1)
+               Error("Can't write.");
+
+#endif
+
+#ifdef LONG_REPORT
+       Fprintf((stderr, "input size    %ld bytes\n", in_len));
+       Fprintf((stderr, "output size   %ld bytes\n", out_len));
+       Fprintf((stderr, "input/output  %.3f\n", (double)in_len / out_len));
+#else
+       Fprintf((stderr, "input/output = %ld/%ld = %.3f\n", in_len, out_len,
+               (double)in_len / out_len));
+#endif
+       
+}
+
+#endif
+
+#ifdef DECODE
+
+#define GETBIT_8(bb, src, ilen) \
+    (((bb = bb & 0x7f ? bb*2 : ((unsigned)src[ilen++]*2+1)) >> 8) & 1)
+
+#define GETBIT_LE16(bb, src, ilen) \
+    (bb*=2,bb&0xffff ? (bb>>16)&1 : (ilen+=2,((bb=(src[ilen-2]+src[ilen-1]*256u)*2+1)>>16)&1))
+
+#define GETBIT_LE32(bb, src, ilen) \
+    (bc > 0 ? ((bb>>--bc)&1) : (bc=31,\
+    bb=*(const uint32_t *)((src)+ilen),ilen+=4,(bb>>31)&1))
+
+#if ENDIAN == 0 && BITSIZE == 8
+#define GETBIT(bb, src, ilen) GETBIT_8(bb, src, ilen)
+#endif
+#if ENDIAN == 0 && BITSIZE == 16
+#define GETBIT(bb, src, ilen) GETBIT_LE16(bb, src, ilen)
+#endif
+#if ENDIAN == 0 && BITSIZE == 32
+#define GETBIT(bb, src, ilen) GETBIT_LE32(bb, src, ilen)
+#endif
+
+#ifndef GETBIT
+#error "Bad Combination of ENDIAN and BITSIZE values specified"
+#endif
+
+#undef SAFE
+
+#ifdef SAFE
+#define FAIL(x,r)   if (x) { Error(r); }
+#else
+#define FAIL(x,r)
+#endif
+
+void Decode(void)  /* recover */
+{
+       uint32_t tw;
+       uint8_t *src, *dst;
+       unsigned long max_src_len, src_len, dst_len;
+       unsigned long ilen = 0, olen = 0, last_m_off =  1;
+       uint32_t bb = 0;
+       unsigned bc = 0;
+#if UCLPACK_COMPAT
+       if (fseek(infile, sizeof(magic) + sizeof(tw) + 1 + 1 + sizeof(tw),
+               SEEK_SET) != 0)
+
+               Error("Seek Error");
+       if (fread(&tw, sizeof(tw), 1, infile) < 1)
+               Error("Can't read"); /* read size of text */
+       dst_len = ntohl(tw);
+       if (fread(&tw, sizeof(tw), 1, infile) < 1)
+               Error("Can't read"); /* read size of file */
+       max_src_len = ntohl(tw);
+#else
+       if (fread(&tw, sizeof(tw), 1, infile) < 1)
+               Error("Can't read"); /* read size of text */
+       dst_len = i86ul_to_host(tw);
+       max_src_len = dst_len + (dst_len/8) + 256;
+#endif
+       if (dst_len == 0)
+               return;
+       dst = malloc(dst_len);
+       if (!dst)
+               Error("Can't malloc");
+       src = malloc(max_src_len);
+       if (!src)
+               Error("Can't malloc");
+       src_len = fread(src, 1, max_src_len, infile);
+       if (src_len <= 0) 
+               Error("Can't read");
+
+       for(;;) {
+               unsigned int m_off, m_len;
+               while(GETBIT(bb, src, ilen)) {
+                       FAIL(ilen >= src_len, "input overrun");
+                       FAIL(olen >= dst_len, "output  overrun");
+                       dst[olen++] = src[ilen++];
+               }
+               m_off = 1;
+               do {
+                       m_off = m_off*2 + GETBIT(bb, src, ilen);
+                       FAIL(ilen >= src_len, "input overrun");
+                       FAIL(m_off > 0xffffffU +3, "lookbehind overrun");
+               } while (!GETBIT(bb, src, ilen));
+               if (m_off == 2)
+               {
+                       m_off = last_m_off;
+               }
+               else
+               {
+                       FAIL(ilen >= src_len, "input overrun");
+                       m_off = (m_off - 3)*256 + src[ilen++];
+                       if(m_off == 0xffffffffU)
+                               break;
+                       last_m_off = ++m_off;
+               }
+               m_len = GETBIT(bb, src, ilen);
+               m_len = m_len*2 + GETBIT(bb, src, ilen);
+               if (m_len == 0) 
+               {
+                       m_len++;
+                       do {
+                               m_len = m_len*2 + GETBIT(bb, src, ilen);
+                               FAIL(ilen >= src_len, "input overrun");
+                               FAIL(m_len >= dst_len, "output overrun");
+                       } while(!GETBIT(bb, src, ilen));
+                       m_len += 2;
+               }
+               m_len += (m_off > 0xd00);
+               FAIL(olen + m_len > dst_len, "output overrun");
+               FAIL(m_off > olen, "lookbeind overrun");
+               {
+                       const uint8_t *m_pos;
+                       m_pos = dst + olen - m_off;
+                       dst[olen++] = *m_pos++;
+                       do {
+                               dst[olen++] = *m_pos++;
+                       } while(--m_len > 0);
+               }
+       }
+       FAIL(ilen < src_len, "input not consumed");
+       FAIL(ilen > src_len, "input overrun");
+       assert(ilen == src_len);
+       Fprintf((stderr, "%12ld\n", olen));
+       if (dst_len != olen) {
+               fprintf(stderr, "length != expected length\n");
+       }
+       if (fwrite(dst, olen, 1, outfile) != 1)
+               Error("Write error\n");
+       free(src);
+       free(dst);
+}
+#endif
+
+#ifdef MAIN
+int main(int argc, char *argv[])
+{
+       char  *s;
+       FILE  *f;
+       int    c;
+       
+       if (argc == 2) {
+               outfile = stdout;
+               if ((f = tmpfile()) == NULL) {
+                       perror("tmpfile");
+                       return EXIT_FAILURE;
+               }
+               while ((c = getchar()) != EOF)
+                       fputc(c, f);
+               rewind(infile = f);
+       }
+       else if (argc != 4) {
+               Fprintf((stderr, "'lzhuf e file1 file2' encodes file1 into
+file2.\n"
+
+                       "'lzhuf d file2 file1' decodes file2 into
+file1.\n"));
+
+               return EXIT_FAILURE;
+       }
+       if (argc == 4) {
+               if ((s = argv[1], s[1] || strpbrk(s, "DEde") == NULL)
+                       || (s = argv[2], (infile  = fopen(s, "rb")) == NULL)
+                       || (s = argv[3], (outfile = fopen(s, "wb")) == NULL)) {
+                       Fprintf((stderr, "??? %s\n", s));
+                       return EXIT_FAILURE;
+               }
+       }
+       if (toupper(*argv[1]) == 'E')
+               Encode();
+       else
+               Decode();
+       fclose(infile);
+       fclose(outfile);
+       return EXIT_SUCCESS;
+}
+#endif
diff --git a/util/options/build_opt_tbl.c b/util/options/build_opt_tbl.c
new file mode 100644 (file)
index 0000000..6a489bd
--- /dev/null
@@ -0,0 +1,443 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/io.h>
+#include <string.h>
+#include <ctype.h>
+#include "../../src/include/pc80/mc146818rtc.h"
+#include "../../src/include/boot/linuxbios_tables.h"
+
+#define CMOS_IMAGE_BUFFER_SIZE 128
+#define INPUT_LINE_MAX 256
+#define MAX_VALUE_BYTE_LENGTH 64
+
+
+static unsigned char cmos_table[4096];
+
+/* This array is used to isolate bits that are to be changed in a byte */
+static unsigned char clip[9]={0,1,3,7,0x0f,0x1f,0x3f,0x7f,0xff};
+
+
+/* This routine loops through the entried and tests if any of the fields overlap
+       input entry_start = the memory pointer to the start of the entries.
+             entry_end = the byte past the entries.
+       output  none
+               if there is an overlap, the routine exits, other wise it returns.
+*/
+void test_for_entry_overlaps(int entry_start,int entry_end)
+{
+       int ptr;
+       int buffer_bit_size;
+       int offset;
+       int byte;
+       int byte_length;
+        struct cmos_entries *ce;
+       unsigned char test[CMOS_IMAGE_BUFFER_SIZE];
+       unsigned char set;
+
+       /* calculate the size of the cmos buffer in bits */
+       buffer_bit_size=(CMOS_IMAGE_BUFFER_SIZE*8);
+       /* clear the temporary test buffer */
+       for(ptr=0;ptr<CMOS_IMAGE_BUFFER_SIZE;ptr++)
+               test[ptr]=0;
+       /* loop through each entry in the table testing for errors */
+       for(ptr=entry_start;ptr<entry_end;ptr+=ce->size) {
+               ce=(struct cmos_entries *)ptr;
+               /* test if entry goes past the end of the buffer */
+               if((ce->bit+ce->length)>buffer_bit_size) {
+                       printf("Error - Entry %s start bit + length must be less than %d\n",
+                               ce->name,buffer_bit_size);
+                       exit(1);
+               }
+               byte=ce->bit/8;
+               offset=ce->bit%8;
+               byte_length=ce->length/8;
+               if(byte_length) {       /* entry is 8 bits long or more */
+                       if(offset) { /* if 8 bits or more long, it must be byte aligned */
+                               printf("Error - Entry %s length over 8 must be byte aligned\n",
+                                       ce->name);
+                               exit(1);
+                       }
+                       /* test if entries 8 or more in length are even bytes */ 
+                       if(ce->length%8){
+                                printf("Error - Entry %s length over 8 must be a multiple of 8\n",
+                                        ce->name);
+                                exit(1);
+                        }
+                       /* test if any of the bits have been previously used */
+                       for(;byte_length;byte_length--,byte++) {
+                               if(test[byte]) {
+                                    printf("Error - Entry %s uses same bits previously used\n",
+                                               ce->name);
+                                    exit(1);
+                               }
+                               test[byte]=clip[8]; /* set the bits defined in test */
+                       }
+               } else {
+                       /* test if bits overlap byte boundaries */
+                       if(ce->length>(8-offset)) {
+                                printf("Error - Entry %s length overlaps a byte boundry\n",                                        ce->name);
+                                exit(1);
+                        }
+                       /* test for bits previously used */
+                       set=(clip[ce->length]<<offset);
+                       if(test[byte]&set) {
+                               printf("Error - Entry %s uses same bits previously used\n",
+                                                ce->name);
+                                exit(1);
+                        }
+                        test[byte]|=set;  /* set the bits defined in test */
+               }
+       }
+       return;
+}
+
+/* This routine displays the usage options */
+void display_usage(void)
+{
+        printf("Usage build_opt_table [-b] [--option filename]\n");
+        printf("                [--config filename]\n");
+        printf("b = build option_table.c\n");
+        printf("--option = name of option table output file\n");
+        printf("--config = build the definitions table from the given file\n");
+        exit(1);
+}
+
+
+static void skip_spaces(char *line, char **ptr)
+{
+       if (!isspace(**ptr)) {
+               printf("Error missing whitespace in line\n%s\n", line);
+               exit(1);
+       }
+       while(isspace(**ptr)) {
+               (*ptr)++;
+       }
+       return;
+}
+static unsigned long get_number(char *line, char **ptr, int base)
+{
+       unsigned long value;
+       char *ptr2;
+       value = strtoul(*ptr, &ptr2, base);
+       if (ptr2 == *ptr) {
+               printf("Error missing digits at: \n%s\n in line:\n%s\n", 
+                       *ptr, line);
+               exit(1);
+       }
+       *ptr = ptr2;
+       return value;
+}
+
+/* This routine builds the cmos definition table from the cmos layout file
+       input The input comes from the configuration file which contains two parts
+               entries and enumerations. Each section is started with the key words
+               entries and enumerations.  Records then follow in their respective 
+               formats.
+       output The output of this program is the cmos definitions table.  It is stored
+               in the cmos_table array. If this module is called, and the global 
+               table_file has been implimented by the user, the table is also written
+               to the specified file.
+               This program exits on and error.  It returns a 1 on successful 
+               completion
+*/
+int main(int argc, char **argv)
+{
+       int i;
+       char *config=0;
+       char *option=0;
+       FILE *fp;
+       struct cmos_option_table *ct;
+       struct cmos_entries *ce;
+       struct cmos_enums *c_enums, *c_enums_start;
+       struct cmos_checksum *cs;
+       unsigned char line[INPUT_LINE_MAX];
+       unsigned char uc;
+       int entry_mode=0;
+       int enum_mode=0;
+       int checksum_mode=0;
+       int ptr,cnt;
+       char *cptr;
+       int offset,entry_start;
+       int entries_length;
+       int enum_length;
+       int len;
+       unsigned char buf[16];
+
+        for(i=1;i<argc;i++) {
+                if(argv[i][0]!='-') {
+                        display_usage();
+                }
+                switch(argv[i][1]) {
+                        case 'b':       /* build the table */
+                                break;
+                        case '-':       /* data is requested from a file */
+                                switch(argv[i][2]) {
+                                        case 'c':  /* use a configuration file */
+                                                if(strcmp(&argv[i][2],"config")) {
+                                                        display_usage();
+                                                }
+                                                config=argv[++i];
+                                                break;
+                                        case 'o':  /* use a cmos definitions table file */
+                                                if(strcmp(&argv[i][2],"option")) {
+                                                        display_usage();
+                                                }
+                                                option=argv[++i];
+                                                break;
+                                        default:
+                                                display_usage();
+                                                break;
+                                }
+                                break;
+                        default:
+                                display_usage();
+                                break;
+                }
+        }
+
+
+       /* Has the user specified a configuration file */
+       if(config) {    /* if yes, open it */
+               if((fp=fopen(config,"r"))==NULL){
+                       printf("Error - Can not open config file %s\n",config);
+                       exit(1);  /* exit if it can not be opened */
+               }
+       }
+       else {  /* no configuration file specified, so try the default */
+               if((fp=fopen("cmos.layout","r"))==NULL){
+                       printf("Error - Can not open cmos.layout\n");
+                       exit(1);  /* end of no configuration file is found */
+               }
+       }
+       /* type cast a pointer, so we can us the structure */
+       ct=(struct cmos_option_table*)cmos_table;
+       /* start the table with the type signature */
+       ct->tag = LB_TAG_CMOS_OPTION_TABLE;
+       /* put in the header length */
+       ct->header_length=sizeof(*ct);
+
+       /* Get the entry records */
+       ce=(struct cmos_entries*)(cmos_table+(ct->header_length));
+       cptr = (char*)ce;
+       for(;;){  /* this section loops through the entry records */
+               if(fgets(line,INPUT_LINE_MAX,fp)==NULL) 
+                       break; /* end if no more input */
+               if(!entry_mode) {  /* skip input until the entries key word */
+                       if (strstr(line,"entries") != 0) {
+                               entry_mode=1;
+                               continue;
+                       }
+               }
+               else{  /* Test if we are done with entries and starting enumerations */
+                       if (strstr(line,"enumerations") != 0){
+                               entry_mode=0;
+                               enum_mode=1;
+                               break;
+                       }
+                       if (strstr(line, "checksums") != 0) {
+                               enum_mode=0;
+                               checksum_mode=1;
+                               break;
+                       }
+               }
+
+               /* skip commented and blank lines */
+               if(line[0]=='#') continue;
+               if(line[strspn(line," ")]=='\n') continue;
+               /* scan in the input data */
+               sscanf(line,"%d %d %c %d %s",
+                       &ce->bit,&ce->length,&uc,&ce->config_id,&ce->name[0]);
+               ce->config=(int)uc;
+               /* check bit and length ranges */
+               if(ce->bit>(CMOS_IMAGE_BUFFER_SIZE*8)) {
+                        printf("Error - bit is to big in line \n%s\n",line);
+                        exit(1);
+                }
+               if((ce->length>(MAX_VALUE_BYTE_LENGTH*8))&&(uc!='r')) {
+                       printf("Error - Length is to long in line \n%s\n",line);
+                       exit(1);
+               }
+               /* put in the record type */
+               ce->tag=LB_TAG_OPTION;
+               /* calculate and save the record length */
+               len=strlen(ce->name)+1;
+               /* make the record int aligned */
+               if(len%4)
+                       len+=(4-(len%4));
+               ce->size=sizeof(struct cmos_entries)-32+len;
+               cptr = (char*)ce;
+               cptr+=ce->size;  /* increment to the next table position */
+               ce = (struct cmos_entries*) cptr;
+       }
+
+       /* put the length of the entries into the header section */
+       entries_length=(int)cptr;
+       entries_length-=(int)(cmos_table+ct->header_length);
+
+       /* compute the start of the enumerations section */
+       entry_start=(int)cmos_table;
+       entry_start+=ct->header_length;
+       offset=entry_start+entries_length;
+       c_enums_start=c_enums=(struct cmos_enums*)offset;
+       /* test for overlaps in the entry records */
+       test_for_entry_overlaps(entry_start,offset);
+
+       for(;enum_mode;){ /* loop to build the enumerations section */
+               if(fgets(line,INPUT_LINE_MAX,fp)==NULL) 
+                       break; /* go till end of input */
+
+               if (strstr(line, "checksums") != 0) {
+                       enum_mode=0;
+                       checksum_mode=1;
+                       break;
+               }
+
+               /* skip commented and blank lines */
+               if(line[0]=='#') continue;
+               if(line[strspn(line," ")]=='\n') continue;
+
+               /* scan in the data */
+               for(ptr=0;(line[ptr]==' ')||(line[ptr]=='\t');ptr++);
+               c_enums->config_id=strtol(&line[ptr],(char**)NULL,10);
+               for(;(line[ptr]!=' ')&&(line[ptr]!='\t');ptr++);
+               for(;(line[ptr]==' ')||(line[ptr]=='\t');ptr++);
+               c_enums->value=strtol(&line[ptr],(char**)NULL,10);
+               for(;(line[ptr]!=' ')&&(line[ptr]!='\t');ptr++);
+               for(;(line[ptr]==' ')||(line[ptr]=='\t');ptr++);
+               for(cnt=0;(line[ptr]!='\n')&&(cnt<31);ptr++,cnt++)
+                       c_enums->text[cnt]=line[ptr];
+               c_enums->text[cnt]=0;
+       
+               /* make the record int aligned */
+               cnt++;
+               if(cnt%4)
+                       cnt+=4-(cnt%4);
+               /* store the record length */
+               c_enums->size=((int)&c_enums->text[cnt])-(int)c_enums;
+               /* store the record type */
+               c_enums->tag=LB_TAG_OPTION_ENUM;
+               /* increment to the next record */
+               c_enums=(struct cmos_enums*)&c_enums->text[cnt];
+       }
+       /* save the enumerations length */
+       enum_length=(int)c_enums-(int)c_enums_start;
+       ct->size=ct->header_length+enum_length+entries_length;
+
+       /* Get the checksum records */
+       cs=(struct cmos_checksum *)(cmos_table+(ct->size));
+       cptr = (char*)cs;
+       for(;checksum_mode;) { /* This section finds the checksums */
+               char *ptr;
+               if(fgets(line, INPUT_LINE_MAX,fp)==NULL)
+                       break; /* end if no more input */
+
+               /* skip commented and blank lines */
+               if (line[0]=='#') continue;
+               if (line[strspn(line, " ")]=='\n') continue;
+               if (memcmp(line, "checksum", 8) != 0) continue;
+
+               /* get the information */
+               ptr = line + 8;
+               skip_spaces(line, &ptr);
+               cs->range_start = get_number(line, &ptr, 10);
+
+               skip_spaces(line, &ptr);
+               cs->range_end = get_number(line, &ptr, 10);
+
+               skip_spaces(line, &ptr);
+               cs->location = get_number(line, &ptr, 10);
+               
+               /* Make certain there are spaces until the end of the line */
+               skip_spaces(line, &ptr);
+
+               if ((cs->range_start%8) != 0) {
+                       printf("Error - range start is not byte aligned in line\n%s\n", line);
+                       exit(1);
+               }
+               if (cs->range_start >= (CMOS_IMAGE_BUFFER_SIZE*8)) {
+                       printf("Error - range start is to big in line\n%s\n", line);
+                       exit(1);
+               }
+               if ((cs->range_end%8) != 7) {
+                       printf("Error - range end is not byte aligned in line\n%s\n", line);
+                       exit(1);
+               }
+               if ((cs->range_end) >= (CMOS_IMAGE_BUFFER_SIZE*8)) {
+                       printf("Error - range end is to long in line\n%s\n", line);
+                       exit(1);
+               }
+               if ((cs->location%8) != 0) {
+                       printf("Error - location is not byte aligned in line\n%s\n", line);
+                       exit(1);
+               }
+               if ((cs->location >= (CMOS_IMAGE_BUFFER_SIZE*8)) ||
+                       ((cs->location + 16) > (CMOS_IMAGE_BUFFER_SIZE*8))) 
+               {
+                       printf("Error - location is to big in line\n%s\n", line);
+                       exit(1);
+               }
+               /* And since we are not ready to be fully general purpose yet.. */
+               if ((cs->range_start/8) != LB_CKS_RANGE_START) {
+                       printf("Error - Range start(%d) does not match define(%d) in line\n%s\n", 
+                               cs->range_start/8, LB_CKS_RANGE_START, line);
+                       exit(1);
+               }
+               if ((cs->range_end/8) != LB_CKS_RANGE_END) {
+                       printf("Error - Range end does not match define in line\n%s\n", line);
+                       exit(1);
+               }
+               if ((cs->location/8) != LB_CKS_LOC) {
+                       printf("Error - Location does not match define in line\n%s\n", line);
+                       exit(1);
+               }
+
+               cs->tag = LB_TAG_OPTION_CHECKSUM;
+               cs->size = sizeof(*cs);
+               cs->type = CHECKSUM_PCBIOS;
+               cptr = (char *)cs;
+               cptr += cs->size;
+               cs = (struct cmos_checksum *)cptr;
+
+       }
+       ct->size += (cptr - (char *)(cmos_table + ct->size));
+       fclose(fp);
+
+       /* test if an alternate file is to be created */
+       if(option) {
+               if((fp=fopen(option,"w"))==NULL){
+                        printf("Error - Can not open %s\n",option);
+                        exit(1);
+               }
+       }
+       else {  /* no, so use the default option_table.c */
+                if((fp=fopen("option_table.c","w"))==NULL){
+                        printf("Error - Can not open option_table.c\n");
+                        exit(1);
+               }
+       }
+       /* write the header */
+        if(!fwrite("unsigned char option_table[] = {",1,32,fp)) {
+                printf("Error - Could not write image file\n");
+                fclose(fp);
+                exit(1);
+        }
+       /* write the array values */
+       for(i=0;i<(ct->size-1);i++) {
+               if(!(i%10)) fwrite("\n\t",1,2,fp);
+               sprintf(buf,"0x%02x,",cmos_table[i]);
+               fwrite(buf,1,5,fp);
+       }
+       /* write the end */
+       sprintf(buf,"0x%02x",cmos_table[i]);
+       fwrite(buf,1,4,fp);
+        if(!fwrite("};\n",1,3,fp)) {
+                printf("Error - Could not write image file\n");
+                fclose(fp);
+                exit(1);
+        }
+
+        fclose(fp);
+       return(0);
+}
+
+