summaryrefslogtreecommitdiff
path: root/src/arch
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch')
-rw-r--r--src/arch/i386/boot/boot.c182
-rw-r--r--src/arch/i386/boot/linuxbios_table.c281
-rw-r--r--src/arch/i386/boot/linuxbios_table.h33
-rw-r--r--src/arch/i386/boot/pirq_routing.c93
-rw-r--r--src/arch/i386/boot/tables.c69
-rw-r--r--src/arch/i386/include/arch/asm.h30
-rw-r--r--src/arch/i386/include/arch/boot/boot.h8
-rw-r--r--src/arch/i386/include/arch/intel.h369
-rw-r--r--src/arch/i386/include/arch/io.h76
-rw-r--r--src/arch/i386/include/arch/pciconf.h9
-rw-r--r--src/arch/i386/include/arch/pirq_routing.h54
-rw-r--r--src/arch/i386/include/arch/rom_segs.h10
-rw-r--r--src/arch/i386/include/arch/romcc_io.h84
-rw-r--r--src/arch/i386/include/arch/smp/mpspec.h282
-rw-r--r--src/arch/i386/include/bitops.h20
-rw-r--r--src/arch/i386/include/stddef.h15
-rw-r--r--src/arch/i386/include/stdint.h52
-rw-r--r--src/arch/i386/lib/c_start.S135
-rw-r--r--src/arch/i386/lib/console.c119
-rw-r--r--src/arch/i386/lib/console.inc527
-rw-r--r--src/arch/i386/lib/cpu.c139
-rw-r--r--src/arch/i386/lib/cpu_reset.inc9
-rw-r--r--src/arch/i386/lib/failover.lds1
-rw-r--r--src/arch/i386/lib/id.inc21
-rw-r--r--src/arch/i386/lib/id.lds6
-rw-r--r--src/arch/i386/lib/noop_failover.inc9
-rw-r--r--src/arch/i386/lib/pci_ops.c281
-rw-r--r--src/arch/i386/smp/mpspec.c245
28 files changed, 3159 insertions, 0 deletions
diff --git a/src/arch/i386/boot/boot.c b/src/arch/i386/boot/boot.c
new file mode 100644
index 0000000000..84c71da800
--- /dev/null
+++ b/src/arch/i386/boot/boot.c
@@ -0,0 +1,182 @@
+#include <console/console.h>
+#include <ip_checksum.h>
+#include <boot/elf.h>
+#include <boot/elf_boot.h>
+#include <string.h>
+
+
+#ifndef CMD_LINE
+#define CMD_LINE ""
+#endif
+
+
+
+#define UPSZ(X) ((sizeof(X) + 3) &~3)
+
+static struct {
+ Elf_Bhdr hdr;
+ Elf_Nhdr ft_hdr;
+ unsigned char ft_desc[UPSZ(FIRMWARE_TYPE)];
+ Elf_Nhdr bl_hdr;
+ unsigned char bl_desc[UPSZ(BOOTLOADER)];
+ Elf_Nhdr blv_hdr;
+ unsigned char blv_desc[UPSZ(BOOTLOADER_VERSION)];
+ Elf_Nhdr cmd_hdr;
+ unsigned char cmd_desc[UPSZ(CMD_LINE)];
+} elf_boot_notes = {
+ .hdr = {
+ .b_signature = 0x0E1FB007,
+ .b_size = sizeof(elf_boot_notes),
+ .b_checksum = 0,
+ .b_records = 4,
+ },
+ .ft_hdr = {
+ .n_namesz = 0,
+ .n_descsz = sizeof(FIRMWARE_TYPE),
+ .n_type = EBN_FIRMWARE_TYPE,
+ },
+ .ft_desc = FIRMWARE_TYPE,
+ .bl_hdr = {
+ .n_namesz = 0,
+ .n_descsz = sizeof(BOOTLOADER),
+ .n_type = EBN_BOOTLOADER_NAME,
+ },
+ .bl_desc = BOOTLOADER,
+ .blv_hdr = {
+ .n_namesz = 0,
+ .n_descsz = sizeof(BOOTLOADER_VERSION),
+ .n_type = EBN_BOOTLOADER_VERSION,
+ },
+ .blv_desc = BOOTLOADER_VERSION,
+ .cmd_hdr = {
+ .n_namesz = 0,
+ .n_descsz = sizeof(CMD_LINE),
+ .n_type = EBN_COMMAND_LINE,
+ },
+ .cmd_desc = CMD_LINE,
+};
+
+
+int elf_check_arch(Elf_ehdr *ehdr)
+{
+ return (
+ ((ehdr->e_machine == EM_386) || (ehdr->e_machine == EM_486)) &&
+ (ehdr->e_ident[EI_CLASS] == ELFCLASS32) &&
+ (ehdr->e_ident[EI_DATA] == ELFDATA2LSB)
+ );
+
+}
+
+void jmp_to_elf_entry(void *entry, unsigned long buffer)
+{
+ extern unsigned char _ram_seg, _eram_seg;
+ unsigned long lb_start, lb_size;
+ unsigned long adjust, adjusted_boot_notes;
+ unsigned long type;
+
+ elf_boot_notes.hdr.b_checksum =
+ compute_ip_checksum(&elf_boot_notes, sizeof(elf_boot_notes));
+
+ type = 0x0E1FB007;
+ lb_start = (unsigned long)&_ram_seg;
+ lb_size = (unsigned long)(&_eram_seg - &_ram_seg);
+ adjust = buffer + lb_size - lb_start;
+
+ adjusted_boot_notes = (unsigned long)&elf_boot_notes;
+ adjusted_boot_notes += adjust;
+
+ printk_spew("entry = 0x%08lx\n", (unsigned long)entry);
+ printk_spew("lb_start = 0x%08lx\n", lb_start);
+ printk_spew("lb_size = 0x%08lx\n", lb_size);
+ printk_spew("adjust = 0x%08lx\n", adjust);
+ printk_spew("buffer = 0x%08lx\n", buffer);
+ printk_spew(" elf_boot_notes = 0x%08lx\n", (unsigned long)&elf_boot_notes);
+ printk_spew("adjusted_boot_notes = 0x%08lx\n", adjusted_boot_notes);
+
+ /* Jump to kernel */
+ __asm__ __volatile__(
+ " cld \n\t"
+ /* Save the callee save registers... */
+ " pushl %%esi\n\t"
+ " pushl %%edi\n\t"
+ " pushl %%ebx\n\t"
+ /* Save the parameters I was passed */
+ " pushl $0\n\t" /* 20 adjust */
+ " pushl %0\n\t" /* 16 lb_start */
+ " pushl %1\n\t" /* 12 buffer */
+ " pushl %2\n\t" /* 8 lb_size */
+ " pushl %3\n\t" /* 4 entry */
+ " pushl %4\n\t" /* 0 elf_boot_notes */
+ /* Compute the adjustment */
+ " xorl %%eax, %%eax\n\t"
+ " subl 16(%%esp), %%eax\n\t"
+ " addl 12(%%esp), %%eax\n\t"
+ " addl 8(%%esp), %%eax\n\t"
+ " movl %%eax, 20(%%esp)\n\t"
+ /* Place a copy of linuxBIOS in it's new location */
+ /* Move ``longs'' the linuxBIOS size is 4 byte aligned */
+ " movl 12(%%esp), %%edi\n\t"
+ " addl 8(%%esp), %%edi\n\t"
+ " movl 16(%%esp), %%esi\n\t"
+ " movl 8(%%esp), %%ecx\n\n"
+ " shrl $2, %%ecx\n\t"
+ " rep movsl\n\t"
+
+ /* Adjust the stack pointer to point into the new linuxBIOS image */
+ " addl 20(%%esp), %%esp\n\t"
+ /* Adjust the instruction pointer to point into the new linuxBIOS image */
+ " movl $1f, %%eax\n\t"
+ " addl 20(%%esp), %%eax\n\t"
+ " jmp *%%eax\n\t"
+ "1: \n\t"
+
+ /* Copy the linuxBIOS bounce buffer over linuxBIOS */
+ /* Move ``longs'' the linuxBIOS size is 4 byte aligned */
+ " movl 16(%%esp), %%edi\n\t"
+ " movl 12(%%esp), %%esi\n\t"
+ " movl 8(%%esp), %%ecx\n\t"
+ " shrl $2, %%ecx\n\t"
+ " rep movsl\n\t"
+
+ /* Now jump to the loaded image */
+ " movl $0x0E1FB007, %%eax\n\t"
+ " movl 0(%%esp), %%ebx\n\t"
+ " call *4(%%esp)\n\t"
+
+ /* The loaded image returned? */
+ " cli \n\t"
+ " cld \n\t"
+
+ /* Copy the saved copy of linuxBIOS where linuxBIOS runs */
+ /* Move ``longs'' the linuxBIOS size is 4 byte aligned */
+ " movl 16(%%esp), %%edi\n\t"
+ " movl 12(%%esp), %%esi\n\t"
+ " addl 8(%%esp), %%esi\n\t"
+ " movl 8(%%esp), %%ecx\n\t"
+ " shrl $2, %%ecx\n\t"
+ " rep movsl\n\t"
+
+ /* Adjust the stack pointer to point into the old linuxBIOS image */
+ " subl 20(%%esp), %%esp\n\t"
+
+ /* Adjust the instruction pointer to point into the old linuxBIOS image */
+ " movl $1f, %%eax\n\t"
+ " subl 20(%%esp), %%eax\n\t"
+ " jmp *%%eax\n\t"
+ "1: \n\t"
+
+ /* Drop the parameters I was passed */
+ " addl $24, %%esp\n\t"
+
+ /* Restore the callee save registers */
+ " popl %%ebx\n\t"
+ " popl %%edi\n\t"
+ " popl %%esi\n\t"
+
+ ::
+ "g" (lb_start), "g" (buffer), "g" (lb_size),
+ "g" (entry), "g"(adjusted_boot_notes)
+ );
+}
+
+
diff --git a/src/arch/i386/boot/linuxbios_table.c b/src/arch/i386/boot/linuxbios_table.c
new file mode 100644
index 0000000000..1925f2ddb5
--- /dev/null
+++ b/src/arch/i386/boot/linuxbios_table.c
@@ -0,0 +1,281 @@
+#include <console/console.h>
+#include <mem.h>
+#include <ip_checksum.h>
+#include <boot/linuxbios_tables.h>
+#include "linuxbios_table.h"
+#include <string.h>
+#include <version.h>
+
+
+struct lb_header *lb_table_init(unsigned long addr)
+{
+ struct lb_header *header;
+
+ /* 16 byte align the address */
+ addr += 15;
+ addr &= ~15;
+
+ header = (void *)addr;
+ header->signature[0] = 'L';
+ header->signature[1] = 'B';
+ header->signature[2] = 'I';
+ header->signature[3] = 'O';
+ header->header_bytes = sizeof(*header);
+ header->header_checksum = 0;
+ header->table_bytes = 0;
+ header->table_checksum = 0;
+ header->table_entries = 0;
+ return header;
+}
+
+struct lb_record *lb_first_record(struct lb_header *header)
+{
+ struct lb_record *rec;
+ rec = (void *)(((char *)header) + sizeof(*header));
+ return rec;
+}
+
+struct lb_record *lb_last_record(struct lb_header *header)
+{
+ struct lb_record *rec;
+ rec = (void *)(((char *)header) + sizeof(*header) + header->table_bytes);
+ return rec;
+}
+
+struct lb_record *lb_next_record(struct lb_record *rec)
+{
+ rec = (void *)(((char *)rec) + rec->size);
+ return rec;
+}
+
+struct lb_record *lb_new_record(struct lb_header *header)
+{
+ struct lb_record *rec;
+ rec = lb_last_record(header);
+ if (header->table_entries) {
+ header->table_bytes += rec->size;
+ }
+ rec = lb_last_record(header);
+ header->table_entries++;
+ rec->tag = LB_TAG_UNUSED;
+ rec->size = sizeof(*rec);
+ return rec;
+}
+
+
+struct lb_memory *lb_memory(struct lb_header *header)
+{
+ struct lb_record *rec;
+ struct lb_memory *mem;
+ rec = lb_new_record(header);
+ mem = (struct lb_memory *)rec;
+ mem->tag = LB_TAG_MEMORY;
+ mem->size = sizeof(*mem);
+ return mem;
+}
+
+struct lb_mainboard *lb_mainboard(struct lb_header *header)
+{
+ struct lb_record *rec;
+ struct lb_mainboard *mainboard;
+ rec = lb_new_record(header);
+ mainboard = (struct lb_mainboard *)rec;
+ mainboard->tag = LB_TAG_MAINBOARD;
+
+ mainboard->size = (sizeof(*mainboard) +
+ strlen(mainboard_vendor) + 1 +
+ strlen(mainboard_part_number) + 1 +
+ 3) & ~3;
+
+ mainboard->vendor_idx = 0;
+ mainboard->part_number_idx = strlen(mainboard_vendor) + 1;
+
+ memcpy(mainboard->strings + mainboard->vendor_idx,
+ mainboard_vendor, strlen(mainboard_vendor) + 1);
+ memcpy(mainboard->strings + mainboard->part_number_idx,
+ mainboard_part_number, strlen(mainboard_part_number) + 1);
+
+ return mainboard;
+}
+
+void lb_strings(struct lb_header *header)
+{
+ static const struct {
+ uint32_t tag;
+ const uint8_t *string;
+ } strings[] = {
+ { LB_TAG_VERSION, linuxbios_version, },
+ { LB_TAG_EXTRA_VERSION, linuxbios_extra_version, },
+ { LB_TAG_BUILD, linuxbios_build, },
+ { LB_TAG_COMPILE_TIME, linuxbios_compile_time, },
+ { LB_TAG_COMPILE_BY, linuxbios_compile_by, },
+ { LB_TAG_COMPILE_HOST, linuxbios_compile_host, },
+ { LB_TAG_COMPILE_DOMAIN, linuxbios_compile_domain, },
+ { LB_TAG_COMPILER, linuxbios_compiler, },
+ { LB_TAG_LINKER, linuxbios_linker, },
+ { LB_TAG_ASSEMBLER, linuxbios_assembler, },
+ };
+ int i;
+ for(i = 0; i < sizeof(strings)/sizeof(strings[0]); i++) {
+ struct lb_string *rec;
+ size_t len;
+ rec = (struct lb_string *)lb_new_record(header);
+ len = strlen(strings[i].string);
+ rec->tag = strings[i].tag;
+ rec->size = (sizeof(*rec) + len + 1 + 3) & ~3;
+ memcpy(rec->string, strings[i].string, len+1);
+ }
+
+}
+
+/* Some version of gcc have problems with 64 bit types so
+ * take an unsigned long instead of a uint64_t for now.
+ */
+void lb_memory_range(struct lb_memory *mem,
+ uint32_t type, unsigned long start, unsigned long size)
+{
+ int entries;
+ entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
+ mem->map[entries].start = start;
+ mem->map[entries].size = size;
+ mem->map[entries].type = type;
+ mem->size += sizeof(mem->map[0]);
+}
+
+static void lb_memory_rangek(struct lb_memory *mem,
+ uint32_t type, unsigned long startk, unsigned long endk)
+{
+ int entries;
+ entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
+ mem->map[entries].start = startk;
+ mem->map[entries].start <<= 10;
+ mem->map[entries].size = endk - startk;
+ mem->map[entries].size <<= 10;
+ mem->map[entries].type = type;
+ mem->size += sizeof(mem->map[0]);
+}
+
+static void lb_reserve_table_memory(struct lb_header *head)
+{
+ struct lb_record *last_rec;
+ struct lb_memory *mem;
+ uint64_t start;
+ uint64_t end;
+ int i, entries;
+
+ last_rec = lb_last_record(head);
+ mem = get_lb_mem();
+ start = (unsigned long)head;
+ end = (unsigned long)last_rec;
+ entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
+ /* Resize the right two memory areas so this table is in
+ * a reserved area of memory. Everything has been carefully
+ * setup so that is all we need to do.
+ */
+ for(i = 0; i < entries; i++ ) {
+ uint64_t map_start = mem->map[i].start;
+ uint64_t map_end = map_start + mem->map[i].size;
+ /* Does this area need to be expanded? */
+ if (map_end == start) {
+ mem->map[i].size = end - map_start;
+ }
+ /* Does this area need to be contracted? */
+ else if (map_start == start) {
+ mem->map[i].start = end;
+ mem->map[i].size = map_end - end;
+ }
+ }
+}
+
+
+unsigned long lb_table_fini(struct lb_header *head)
+{
+ struct lb_record *rec, *first_rec;
+ rec = lb_last_record(head);
+ if (head->table_entries) {
+ head->table_bytes += rec->size;
+ }
+ lb_reserve_table_memory(head);
+ first_rec = lb_first_record(head);
+ head->table_checksum = compute_ip_checksum(first_rec, head->table_bytes);
+ head->header_checksum = 0;
+ head->header_checksum = compute_ip_checksum(head, sizeof(*head));
+ printk_debug("Wrote linuxbios table at: %p - %p checksum %lx\n",
+ head, rec, head->table_checksum);
+ return (unsigned long)rec;
+}
+
+
+/* Routines to extract part so the linuxBIOS table or
+ * information from the linuxBIOS table after we have written it.
+ * Currently get_lb_mem relies on a global we can change the
+ * implementaiton.
+ */
+static struct lb_memory *mem_ranges = 0;
+struct lb_memory *get_lb_mem(void)
+{
+ return mem_ranges;
+}
+
+unsigned long write_linuxbios_table(
+ unsigned long *processor_map,
+ struct mem_range *ram,
+ unsigned long low_table_start, unsigned long low_table_end,
+ unsigned long rom_table_startk, unsigned long rom_table_endk)
+{
+ unsigned long table_size;
+ struct mem_range *ramp;
+ struct lb_header *head;
+ struct lb_memory *mem;
+ struct lb_record *rec_dest, *rec_src;
+
+ head = lb_table_init(low_table_end);
+ low_table_end = (unsigned long)head;
+#if HAVE_OPTION_TABLE == 1
+ /* Write the option config table... */
+ rec_dest = lb_new_record(head);
+ rec_src = (struct lb_record *)&option_table;
+ memcpy(rec_dest, rec_src, rec_src->size);
+#endif
+ mem = lb_memory(head);
+ mem_ranges = mem;
+ /* I assume there is always ram at address 0 */
+ /* Reserve our tables in low memory */
+ table_size = (low_table_end - low_table_start);
+ lb_memory_range(mem, LB_MEM_TABLE, 0, table_size);
+ lb_memory_range(mem, LB_MEM_RAM, table_size, (ram[0].sizek << 10) - table_size);
+ /* Reserving pci memory mapped space will keep the kernel from booting seeing
+ * any pci resources.
+ */
+ for(ramp = &ram[1]; ramp->sizek; ramp++) {
+ unsigned long startk, endk;
+ startk = ramp->basek;
+ endk = startk + ramp->sizek;
+ if ((startk < rom_table_startk) && (endk > rom_table_startk)) {
+ lb_memory_rangek(mem, LB_MEM_RAM, startk, rom_table_startk);
+ startk = rom_table_startk;
+ }
+ if ((startk == rom_table_startk) && (endk > startk)) {
+ unsigned long tend;
+ tend = rom_table_endk;
+ if (tend > endk) {
+ tend = endk;
+ }
+ lb_memory_rangek(mem, LB_MEM_TABLE, rom_table_startk, tend);
+ startk = tend;
+ }
+ if (endk > startk) {
+ lb_memory_rangek(mem, LB_MEM_RAM, startk, endk);
+ }
+ }
+
+ /* Record our motheboard */
+ lb_mainboard(head);
+ /* Record our various random string information */
+ lb_strings(head);
+
+ low_table_end = lb_table_fini(head);
+
+ /* Remember where my valid memory ranges are */
+ return low_table_end;
+}
diff --git a/src/arch/i386/boot/linuxbios_table.h b/src/arch/i386/boot/linuxbios_table.h
new file mode 100644
index 0000000000..42c0a07dac
--- /dev/null
+++ b/src/arch/i386/boot/linuxbios_table.h
@@ -0,0 +1,33 @@
+#ifndef LINUXBIOS_TABLE_H
+#define LINUXBIOS_TABLE_H
+
+#include <boot/linuxbios_tables.h>
+
+struct mem_range;
+
+/* This file holds function prototypes for building the linuxbios table. */
+unsigned long write_linuxbios_table(
+ unsigned long *processor_map,
+ struct mem_range *ram,
+ unsigned long low_table_start, unsigned long low_table_end,
+ unsigned long rom_table_start, unsigned long rom_table_end);
+
+struct lb_header *lb_table_init(unsigned long addr);
+struct lb_record *lb_first_record(struct lb_header *header);
+struct lb_record *lb_last_record(struct lb_header *header);
+struct lb_record *lb_next_record(struct lb_record *rec);
+struct lb_record *lb_new_record(struct lb_header *header);
+struct lb_memory *lb_memory(struct lb_header *header);
+void lb_memory_range(struct lb_memory *mem,
+ uint32_t type, unsigned long startk, unsigned long sizek);
+struct lb_mainboard *lb_mainboard(struct lb_header *header);
+unsigned long lb_table_fini(struct lb_header *header);
+
+/* Routines to extract part so the linuxBIOS table or information
+ * from the linuxBIOS table.
+ */
+struct lb_memory *get_lb_mem(void);
+
+extern struct cmos_option_table option_table;
+
+#endif /* LINUXBIOS_TABLE_H */
diff --git a/src/arch/i386/boot/pirq_routing.c b/src/arch/i386/boot/pirq_routing.c
new file mode 100644
index 0000000000..a7325c42ac
--- /dev/null
+++ b/src/arch/i386/boot/pirq_routing.c
@@ -0,0 +1,93 @@
+#include <console/console.h>
+#include <arch/pirq_routing.h>
+#include <string.h>
+
+#ifdef DEBUG
+void check_pirq_routing_table(void)
+{
+ const u8 *addr;
+ const struct irq_routing_table *rt;
+ int i;
+ u8 sum;
+
+ printk_info("Checking IRQ routing tables...\n");
+
+#ifdef(IRQ_SLOT_COUNT)
+ if (sizeof(intel_irq_routing_table) != intel_irq_routing_table.size) {
+ printk_warning("Inconsistent IRQ routing table size\n");
+ }
+#endif
+
+ rt = &intel_irq_routing_table;
+ addr = (u8 *)rt;
+
+ sum = 0;
+ for (i = 0; i < rt->size; i++)
+ sum += addr[i];
+
+ printk_debug("%s:%6d:%s() - irq_routing_table located at: 0x%p\n",
+ __FILE__, __LINE__, __FUNCTION__, addr);
+
+ sum = (unsigned char)(rt->checksum-sum);
+
+ if (sum != rt->checksum) {
+ printk_warning("%s:%6d:%s() - "
+ "checksum is: 0x%02x but should be: 0x%02x\n",
+ __FILE__, __LINE__, __FUNCTION__, rt->checksum, sum);
+ }
+
+ if (rt->signature != PIRQ_SIGNATURE || rt->version != PIRQ_VERSION ||
+ rt->size % 16 || rt->size < sizeof(struct irq_routing_table)) {
+ printk_warning("%s:%6d:%s() - "
+ "Interrupt Routing Table not valid\n",
+ __FILE__, __LINE__, __FUNCTION__);
+ return;
+ }
+
+ sum = 0;
+ for (i=0; i<rt->size; i++)
+ sum += addr[i];
+
+ if (sum) {
+ printk_warning("%s:%6d:%s() - "
+ "checksum error in irq routing table\n",
+ __FILE__, __LINE__, __FUNCTION__);
+ }
+
+ printk_info("done.\n");
+}
+
+int verify_copy_pirq_routing_table(unsigned long addr)
+{
+ int i;
+ u8 *rt_orig, *rt_curr;
+
+ rt_curr = (u8*)addr;
+ rt_orig = (u8*)&intel_irq_routing_table;
+ printk_info("Verifing priq routing tables copy at 0x%x...", addr);
+ for (i = 0; i < intel_irq_routing_table.size; i++) {
+ if (*(rt_curr + i) != *(rt_orig + i)) {
+ printk_info("failed\n");
+ return -1;
+ }
+ }
+ printk_info("succeed\n");
+ return 0;
+}
+#else
+#define verify_copy_pirq_routing_table(addr)
+#endif
+
+unsigned long copy_pirq_routing_table(unsigned long addr)
+{
+ /* Align the table to be 16 byte aligned. */
+ addr += 15;
+ addr &= ~15;
+
+ /* This table must be betweeen 0xf0000 & 0x100000 */
+ printk_info("Copying IRQ routing tables to 0x%x...", addr);
+ memcpy((void *)addr, &intel_irq_routing_table, intel_irq_routing_table.size);
+ printk_info("done.\n");
+ verify_copy_pirq_routing_table(addr);
+ return addr + intel_irq_routing_table.size;
+}
diff --git a/src/arch/i386/boot/tables.c b/src/arch/i386/boot/tables.c
new file mode 100644
index 0000000000..07579fefe2
--- /dev/null
+++ b/src/arch/i386/boot/tables.c
@@ -0,0 +1,69 @@
+#include <console/console.h>
+#include <mem.h>
+#include <cpu/cpu.h>
+#include <boot/tables.h>
+#include <boot/linuxbios_tables.h>
+#include <arch/pirq_routing.h>
+#include <arch/smp/mpspec.h>
+#include "linuxbios_table.h"
+
+#if CONFIG_SMP && CONFIG_MAX_PHYSICAL_CPUS && (CONFIG_MAX_PHYSICAL_CPUS < CONFIG_MAX_CPUS)
+static void remove_logical_cpus(unsigned long *processor_map)
+{
+ /* To turn off hyperthreading just remove the logical
+ * cpus from the processor map.
+ */
+ int disable_logical_cpus = !CONFIG_LOGICAL_CPUS;
+ if (get_option(&disable_logical_cpus,"hyper_threading")) {
+ disable_logical_cpus = !CONFIG_LOGICAL_CPUS;
+ }
+ if (disable_logical_cpus) {
+ /* disable logical cpus */
+ int cnt;
+ for(cnt=MAX_PHYSICAL_CPUS;cnt<MAX_CPUS;cnt++)
+ processor_map[cnt]=0;
+ printk_debug("logical cpus disabled\n");
+ }
+}
+#else
+
+#define remove_logical_cpus(processor_map) do {} while(0)
+
+#endif /* CONFIG_SMP && CONFIG_MAX_PHYSICAL_CPUS */
+
+struct lb_memory *write_tables(struct mem_range *mem, unsigned long *processor_map)
+{
+ unsigned long low_table_start, low_table_end;
+ unsigned long rom_table_start, rom_table_end;
+
+ rom_table_start = 0xf0000;
+ rom_table_end = 0xf0000;
+ /* Start low addr at 16 bytes instead of 0 because of a buglet
+ * in the generic linux unzip code, as it tests for the a20 line.
+ */
+ low_table_start = 0;
+ low_table_end = 16;
+
+ post_code(0x9a);
+ check_pirq_routing_table();
+ /* This table must be betweeen 0xf0000 & 0x100000 */
+ rom_table_end = copy_pirq_routing_table(rom_table_end);
+ rom_table_end = (rom_table_end + 1023) & ~1023;
+
+ /* copy the smp block to address 0 */
+ post_code(0x96);
+ /* The smp table must be in 0-1K, 639K-640K, or 960K-1M */
+ remove_logical_cpus(processor_map);
+ low_table_end = write_smp_table(low_table_end, processor_map);
+
+ /* Don't write anything in the traditional x86 BIOS data segment */
+ if (low_table_end < 0x500) {
+ low_table_end = 0x500;
+ }
+ /* The linuxbios table must be in 0-4K or 960K-1M */
+ write_linuxbios_table(processor_map, mem,
+ low_table_start, low_table_end,
+ rom_table_start >> 10, rom_table_end >> 10);
+
+ return get_lb_mem();
+}
diff --git a/src/arch/i386/include/arch/asm.h b/src/arch/i386/include/arch/asm.h
new file mode 100644
index 0000000000..ea63e2d4eb
--- /dev/null
+++ b/src/arch/i386/include/arch/asm.h
@@ -0,0 +1,30 @@
+#ifndef ASM_H
+#define ASM_H
+
+#define ASSEMBLER
+
+/*
+ * Bootstrap code for the STPC Consumer
+ * Copyright (c) 1999 by Net Insight AB. All Rights Reserved.
+ *
+ * $Id$
+ *
+ */
+
+#define I386_ALIGN_TEXT 0
+#define I386_ALIGN_DATA 0
+
+/*
+ * XXX
+ */
+#ifdef __ELF__
+#define EXT(x) x
+#else
+#define EXT(x) _ ## x
+#endif
+
+#define STATIC(x) .align I386_ALIGN_TEXT; EXT(x):
+#define GLOBAL(x) .globl EXT(x); STATIC(x)
+#define ENTRY(x) .text; GLOBAL(x)
+
+#endif /* ASM_H */
diff --git a/src/arch/i386/include/arch/boot/boot.h b/src/arch/i386/include/arch/boot/boot.h
new file mode 100644
index 0000000000..3ff51c3082
--- /dev/null
+++ b/src/arch/i386/include/arch/boot/boot.h
@@ -0,0 +1,8 @@
+#ifndef ASM_I386_BOOT_H
+#define ASM_I386_BOOT_H
+
+#define ELF_CLASS ELFCLASS32
+#define ELF_DATA ELFDATA2LSB
+#define ELF_ARCH EM_386
+
+#endif /* ASM_I386_BOOT_H */
diff --git a/src/arch/i386/include/arch/intel.h b/src/arch/i386/include/arch/intel.h
new file mode 100644
index 0000000000..df6604e08e
--- /dev/null
+++ b/src/arch/i386/include/arch/intel.h
@@ -0,0 +1,369 @@
+/*
+This software and ancillary information (herein called SOFTWARE )
+called LinuxBIOS is made available under the terms described
+here. The SOFTWARE has been approved for release with associated
+LA-CC Number 00-34 . Unless otherwise indicated, this SOFTWARE has
+been authored by an employee or employees of the University of
+California, operator of the Los Alamos National Laboratory under
+Contract No. W-7405-ENG-36 with the U.S. Department of Energy. The
+U.S. Government has rights to use, reproduce, and distribute this
+SOFTWARE. The public may copy, distribute, prepare derivative works
+and publicly display this SOFTWARE without charge, provided that this
+Notice and any statement of authorship are reproduced on all copies.
+Neither the Government nor the University makes any warranty, express
+or implied, or assumes any liability or responsibility for the use of
+this SOFTWARE. If SOFTWARE is modified to produce derivative works,
+such modified SOFTWARE should be clearly marked, so as not to confuse
+it with the version available from LANL.
+ */
+/* Copyright 2000, Ron Minnich, Advanced Computing Lab, LANL
+ * rminnich@lanl.gov
+ */
+
+
+#ifndef ROM_INTEL_H
+#define ROM_INTEL_H
+
+/*
+ * Bootstrap code for the Intel
+ *
+ * $Id$
+ *
+ */
+
+/*
+ * Config registers.
+ */
+/* yeah, yeah, I know these are macros, which is bad. Don't forget:
+ * we have almost no assembly, so I am not worrying just yet about this.
+ * we'll fix it someday if we care. My guess is we won't.
+ */
+
+/* well we want functions. But first we want to see it work at all. */
+#undef FUNCTIONS
+#ifndef FUNCTIONS
+
+
+#define RET_LABEL(label) \
+ jmp label##_done
+
+#define CALL_LABEL(label) \
+ jmp label ;\
+label##_done:
+
+#define CALLSP(func) \
+ lea 0f, %esp ; \
+ jmp func ; \
+0:
+
+#define RETSP \
+ jmp *%esp
+
+
+#define DELAY(x) mov x, %ecx ;\
+ 1: loop 1b ;\
+
+
+ /*
+ * Macro: PCI_WRITE_CONFIG_BYTE
+ * Arguments: %eax address to write to (includes bus, device, function, &offset)
+ * %dl byte to write
+ *
+ * Results: none
+ *
+ * Trashed: %eax, %edx
+ * Effects: writes a single byte to pci config space
+ *
+ * Notes: This routine is optimized for minimal register usage.
+ * And the tricks it does cannot scale beyond writing a single byte.
+ *
+ * What it does is almost simple.
+ * It preserves %eax (baring special bits) until it is written
+ * out to the appropriate port. And hides the data byte
+ * in the high half of edx.
+ *
+ * In %edx[3] it stores the byte to write.
+ * In %edx[2] it stores the lower three bits of the address.
+ */
+
+
+#define PCI_WRITE_CONFIG_BYTE \
+ shll $8, %edx ; \
+ movb %al, %dl ; \
+ andb $0x3, %dl ; \
+ shll $16, %edx ; \
+ \
+ orl $0x80000000, %eax ; \
+ andl $0xfffffffc, %eax ; \
+ movw $0xcf8, %dx ; \
+ outl %eax, %dx ; \
+ \
+ shrl $16, %edx ; \
+ movb %dh, %al ; \
+ movb $0, %dh ; \
+ addl $0xcfc, %edx ; \
+ outb %al, %dx
+
+
+ /*
+ * Macro: PCI_WRITE_CONFIG_WORD
+ * Arguments: %eax address to write to (includes bus, device, function, &offset)
+ * %ecx word to write
+ *
+ * Results: none
+ *
+ * Trashed: %eax, %edx
+ * Preserved: %ecx
+ * Effects: writes a single byte to pci config space
+ *
+ * Notes: This routine is optimized for minimal register usage.
+ *
+ * What it does is almost simple.
+ * It preserves %eax (baring special bits) until it is written
+ * out to the appropriate port. And hides the least significant
+ * bits of the address in the high half of edx.
+ *
+ * In %edx[2] it stores the lower three bits of the address.
+ */
+
+
+#define PCI_WRITE_CONFIG_WORD \
+ movb %al, %dl ; \
+ andl $0x3, %edx ; \
+ shll $16, %edx ; \
+ \
+ orl $0x80000000, %eax ; \
+ andl $0xfffffffc, %eax ; \
+ movw $0xcf8, %dx ; \
+ outl %eax, %dx ; \
+ \
+ shrl $16, %edx ; \
+ movl %ecx, %eax ; \
+ addl $0xcfc, %edx ; \
+ outw %ax, %dx
+
+
+
+ /*
+ * Macro: PCI_WRITE_CONFIG_DWORD
+ * Arguments: %eax address to write to (includes bus, device, function, &offset)
+ * %ecx dword to write
+ *
+ * Results: none
+ *
+ * Trashed: %eax, %edx
+ * Preserved: %ecx
+ * Effects: writes a single byte to pci config space
+ *
+ * Notes: This routine is optimized for minimal register usage.
+ *
+ * What it does is almost simple.
+ * It preserves %eax (baring special bits) until it is written
+ * out to the appropriate port. And hides the least significant
+ * bits of the address in the high half of edx.
+ *
+ * In %edx[2] it stores the lower three bits of the address.
+ */
+
+
+#define PCI_WRITE_CONFIG_DWORD \
+ movb %al, %dl ; \
+ andl $0x3, %edx ; \
+ shll $16, %edx ; \
+ \
+ orl $0x80000000, %eax ; \
+ andl $0xfffffffc, %eax ; \
+ movw $0xcf8, %dx ; \
+ outl %eax, %dx ; \
+ \
+ shrl $16, %edx ; \
+ movl %ecx, %eax ; \
+ addl $0xcfc, %edx ; \
+ outl %eax, %dx
+
+
+
+
+ /*
+ * Macro: PCI_READ_CONFIG_BYTE
+ * Arguments: %eax address to read from (includes bus, device, function, &offset)
+ *
+ * Results: %al Byte read
+ *
+ * Trashed: %eax, %edx
+ * Effects: reads a single byte from pci config space
+ *
+ * Notes: This routine is optimized for minimal register usage.
+ *
+ * What it does is almost simple.
+ * It preserves %eax (baring special bits) until it is written
+ * out to the appropriate port. And hides the least significant
+ * bits of the address in the high half of edx.
+ *
+ * In %edx[2] it stores the lower three bits of the address.
+ */
+
+
+#define PCI_READ_CONFIG_BYTE \
+ movb %al, %dl ; \
+ andl $0x3, %edx ; \
+ shll $16, %edx ; \
+ \
+ orl $0x80000000, %eax ; \
+ andl $0xfffffffc, %eax ; \
+ movw $0xcf8, %dx ; \
+ outl %eax, %dx ; \
+ \
+ shrl $16, %edx ; \
+ addl $0xcfc, %edx ; \
+ inb %dx, %al
+
+
+
+ /*
+ * Macro: PCI_READ_CONFIG_WORD
+ * Arguments: %eax address to read from (includes bus, device, function, &offset)
+ *
+ * Results: %ax word read
+ *
+ * Trashed: %eax, %edx
+ * Effects: reads a 2 bytes from pci config space
+ *
+ * Notes: This routine is optimized for minimal register usage.
+ *
+ * What it does is almost simple.
+ * It preserves %eax (baring special bits) until it is written
+ * out to the appropriate port. And hides the least significant
+ * bits of the address in the high half of edx.
+ *
+ * In %edx[2] it stores the lower three bits of the address.
+ */
+
+
+#define PCI_READ_CONFIG_WORD \
+ movb %al, %dl ; \
+ andl $0x3, %edx ; \
+ shll $16, %edx ; \
+ \
+ orl $0x80000000, %eax ; \
+ andl $0xfffffffc, %eax ; \
+ movw $0xcf8, %dx ; \
+ outl %eax, %dx ; \
+ \
+ shrl $16, %edx ; \
+ addl $0xcfc, %edx ; \
+ inw %dx, %ax
+
+
+
+ /*
+ * Macro: PCI_READ_CONFIG_DWORD
+ * Arguments: %eax address to read from (includes bus, device, function, &offset)
+ *
+ * Results: %eax
+ *
+ * Trashed: %edx
+ * Effects: reads 4 bytes from pci config space
+ *
+ * Notes: This routine is optimized for minimal register usage.
+ *
+ * What it does is almost simple.
+ * It preserves %eax (baring special bits) until it is written
+ * out to the appropriate port. And hides the least significant
+ * bits of the address in the high half of edx.
+ *
+ * In %edx[2] it stores the lower three bits of the address.
+ */
+
+
+#define PCI_READ_CONFIG_DWORD \
+ movb %al, %dl ; \
+ andl $0x3, %edx ; \
+ shll $16, %edx ; \
+ \
+ orl $0x80000000, %eax ; \
+ andl $0xfffffffc, %eax ; \
+ movw $0xcf8, %dx ; \
+ outl %eax, %dx ; \
+ \
+ shrl $16, %edx ; \
+ addl $0xcfc, %edx ; \
+ inl %dx, %eax
+
+
+
+
+#define CS_READ(which) \
+ mov $0x80000000,%eax ; \
+ mov which,%ax ; \
+ and $0xfc,%al /* clear bits 1-0 */ ; \
+ mov $0xcf8,%dx /* port 0xcf8 ?*/ ; \
+ outl %eax,%dx /* open up CS config */ ; \
+ add $0x4,%dl /* 0xcfc data port 0 */ ; \
+ mov which,%al ; \
+ and $0x3,%al /* only bits 1-0 */ ; \
+ add %al,%dl ; \
+ inb %dx,%al /* read */ ; \
+
+
+#define CS_WRITE(which, data) \
+ mov $0x80000000,%eax /* 32bit word with bit 31 set */ ; \
+ mov which,%ax /* put the reg# in the low part */ ; \
+ and $0xfc,%al /* dword align the reg# */ ; \
+ mov $0xcf8,%dx /* enable port */ ; \
+ outl %eax,%dx ; \
+ add $0x4,%dl /* 1st data port */ ; \
+ mov which,%ax /* register# */ ; \
+ and $0x3,%ax ; \
+ add %al,%dl ; \
+ mov data, %al ; \
+ outb %al,%dx /* write to reg */
+
+#define REGBIS(which, bis) \
+ CS_READ(which) ;\
+ movb bis, %cl ;\
+ orb %al, %cl ;\
+ CS_WRITE(which, %cl)
+
+#define REGBIC(which, bic) \
+ CS_READ(which) ;\
+ movb bic, %cl ;\
+ notb %cl ;\
+ andb %al, %cl ;\
+ CS_WRITE(which, %cl)
+
+
+/* macro to BIC and BIS a reg. calls read a reg,
+ * does a BIC and then a BIS on it.
+ * to clear no bits, make BIC 0.
+ * to set no bits, make BIS 0
+ */
+#define REGBICBIS(which, bic, bis) \
+ CS_READ(which) ;\
+ movb bic, %cl ;\
+ notb %cl ;\
+ andb %cl, %al ;\
+ movb bis, %cl ;\
+ orb %al, %cl ;\
+ CS_WRITE(which, %cl)
+
+#else
+NO FUNCTIONS YET!
+#endif
+
+
+
+/* originally this macro was from STPC BIOS */
+#define intel_chip_post_macro(value) \
+ movb $value, %al ; \
+ outb %al, $0x80
+
+#define INTEL_PDATA_MAGIC 0xdeadbeef
+
+/* SLOW_DOWN_IO is a delay we can use that is roughly cpu neutral,
+ * and can be used before memory or timer chips come up.
+ * Since this hits the isa bus it's roughly
+ */
+#define SLOW_DOWN_IO inb $0x80, %al
+
+#endif /* ROM_INTEL_H */
diff --git a/src/arch/i386/include/arch/io.h b/src/arch/i386/include/arch/io.h
new file mode 100644
index 0000000000..bcba9a932c
--- /dev/null
+++ b/src/arch/i386/include/arch/io.h
@@ -0,0 +1,76 @@
+#ifndef _ASM_IO_H
+#define _ASM_IO_H
+
+/*
+ * This file contains the definitions for the x86 IO instructions
+ * inb/inw/inl/outb/outw/outl and the "string versions" of the same
+ * (insb/insw/insl/outsb/outsw/outsl).
+ *
+ * This file is not meant to be obfuscating: it's just complicated
+ * to (a) handle it all in a way that makes gcc able to optimize it
+ * as well as possible and (b) trying to avoid writing the same thing
+ * over and over again with slight variations and possibly making a
+ * mistake somewhere.
+ */
+
+ /*
+ * Bit simplified and optimized by Jan Hubicka
+ * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999.
+ */
+
+/*
+ * Talk about misusing macros..
+ */
+#define __OUT1(s,x) \
+extern inline void out##s(unsigned x value, unsigned short port) {
+
+#define __OUT2(s,s1,s2) \
+__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
+
+#define __OUT(s,s1,x) \
+__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); }
+
+#define __IN1(s) \
+extern inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
+
+#define __IN2(s,s1,s2) \
+__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
+
+#define __IN(s,s1,i...) \
+__IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; }
+
+#define __INS(s) \
+extern inline void ins##s(unsigned short port, void * addr, unsigned long count) \
+{ __asm__ __volatile__ ("cld ; rep ; ins" #s \
+: "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
+
+#define __OUTS(s) \
+extern inline void outs##s(unsigned short port, const void * addr, unsigned long count) \
+{ __asm__ __volatile__ ("cld ; rep ; outs" #s \
+: "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
+
+#define RETURN_TYPE unsigned char
+__IN(b,"")
+#undef RETURN_TYPE
+#define RETURN_TYPE unsigned short
+__IN(w,"")
+#undef RETURN_TYPE
+#define RETURN_TYPE unsigned int
+__IN(l,"")
+#undef RETURN_TYPE
+
+__OUT(b,"b",char)
+__OUT(w,"w",short)
+__OUT(l,,int)
+
+__INS(b)
+__INS(w)
+__INS(l)
+
+__OUTS(b)
+__OUTS(w)
+__OUTS(l)
+
+
+#endif
+
diff --git a/src/arch/i386/include/arch/pciconf.h b/src/arch/i386/include/arch/pciconf.h
new file mode 100644
index 0000000000..8695ee2294
--- /dev/null
+++ b/src/arch/i386/include/arch/pciconf.h
@@ -0,0 +1,9 @@
+#ifndef PCI_CONF_REG_INDEX
+
+// These are defined in the PCI spec, and hence are theoretically
+// inclusive of ANYTHING that uses a PCI bus.
+#define PCI_CONF_REG_INDEX 0xcf8
+#define PCI_CONF_REG_DATA 0xcfc
+#define CONFIG_ADDR(bus,devfn,where) (((bus) << 16) | ((devfn) << 8) | (where))
+
+#endif
diff --git a/src/arch/i386/include/arch/pirq_routing.h b/src/arch/i386/include/arch/pirq_routing.h
new file mode 100644
index 0000000000..215c4e58c8
--- /dev/null
+++ b/src/arch/i386/include/arch/pirq_routing.h
@@ -0,0 +1,54 @@
+#ifndef ARCH_PIRQ_ROUTING_H
+#define ARCH_PIRQ_ROUTING_H
+
+#include <stdint.h>
+
+#define PIRQ_SIGNATURE (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24))
+#define PIRQ_VERSION 0x0100
+
+struct irq_info {
+ uint8_t bus, devfn; /* Bus, device and function */
+ struct {
+ uint8_t link; /* IRQ line ID, chipset dependent, 0=not routed */
+ uint16_t bitmap; /* Available IRQs */
+ } __attribute__((packed)) irq[4];
+ uint8_t slot; /* Slot number, 0=onboard */
+ uint8_t rfu;
+} __attribute__((packed));
+
+#if defined(IRQ_SLOT_COUNT)
+#define IRQ_SLOTS_COUNT IRQ_SLOT_COUNT
+#elif (__GNUC__ < 3)
+#define IRQ_SLOTS_COUNT 1
+#else
+#define IRQ_SLOTS_COUNT
+#endif
+
+struct irq_routing_table {
+ uint32_t signature; /* PIRQ_SIGNATURE should be here */
+ uint16_t version; /* PIRQ_VERSION */
+ uint16_t size; /* Table size in bytes */
+ uint8_t rtr_bus, rtr_devfn; /* Where the interrupt router lies */
+ uint16_t exclusive_irqs; /* IRQs devoted exclusively to PCI usage */
+ uint16_t rtr_vendor, rtr_device; /* Vendor and device ID of interrupt router */
+ uint32_t miniport_data; /* Crap */
+ uint8_t rfu[11];
+ uint8_t checksum; /* Modulo 256 checksum must give zero */
+ struct irq_info slots[IRQ_SLOTS_COUNT];
+} __attribute__((packed));
+
+extern const struct irq_routing_table intel_irq_routing_table;
+
+#if defined(DEBUG) && defined(HAVE_PIRQ_TABLE)
+void check_pirq_routing_table(void);
+#else
+#define check_pirq_routing_table() do {} while(0)
+#endif
+
+#if defined(HAVE_PIRQ_TABLE)
+unsigned long copy_pirq_routing_table(unsigned long start);
+#else
+#define copy_pirq_routing_table(start) (start)
+#endif
+
+#endif /* ARCH_PIRQ_ROUTING_H */
diff --git a/src/arch/i386/include/arch/rom_segs.h b/src/arch/i386/include/arch/rom_segs.h
new file mode 100644
index 0000000000..b51a805948
--- /dev/null
+++ b/src/arch/i386/include/arch/rom_segs.h
@@ -0,0 +1,10 @@
+#ifndef ROM_SEGS_H
+#define ROM_SEGS_H
+
+#define ROM_CODE_SEG 0x08
+#define ROM_DATA_SEG 0x10
+
+#define CACHE_RAM_CODE_SEG 0x18
+#define CACHE_RAM_DATA_SEG 0x20
+
+#endif /* ROM_SEGS_H */
diff --git a/src/arch/i386/include/arch/romcc_io.h b/src/arch/i386/include/arch/romcc_io.h
new file mode 100644
index 0000000000..02cc272884
--- /dev/null
+++ b/src/arch/i386/include/arch/romcc_io.h
@@ -0,0 +1,84 @@
+static void outb(unsigned char value, unsigned short port)
+{
+ __builtin_outb(value, port);
+}
+
+static void outw(unsigned short value, unsigned short port)
+{
+ __builtin_outw(value, port);
+}
+
+static void outl(unsigned int value, unsigned short port)
+{
+ __builtin_outl(value, port);
+}
+
+
+static unsigned char inb(unsigned short port)
+{
+ return __builtin_inb(port);
+}
+
+
+static unsigned char inw(unsigned short port)
+{
+ return __builtin_inw(port);
+}
+
+static unsigned char inl(unsigned short port)
+{
+ return __builtin_inl(port);
+}
+
+static void hlt(void)
+{
+ __builtin_hlt();
+}
+
+static unsigned int config_cmd(unsigned char bus, unsigned devfn, unsigned where)
+{
+ return 0x80000000 | (bus << 16) | (devfn << 8) | (where & ~3);
+}
+
+static unsigned char pcibios_read_config_byte(
+ unsigned char bus, unsigned devfn, unsigned where)
+{
+ outl(config_cmd(bus, devfn, where), 0xCF8);
+ return inb(0xCFC + (where & 3));
+}
+
+static unsigned short pcibios_read_config_word(
+ unsigned char bus, unsigned devfn, unsigned where)
+{
+ outl(config_cmd(bus, devfn, where), 0xCF8);
+ return inw(0xCFC + (where & 2));
+}
+
+static unsigned int pcibios_read_config_dword(
+ unsigned char bus, unsigned devfn, unsigned where)
+{
+ outl(config_cmd(bus, devfn, where), 0xCF8);
+ return inl(0xCFC);
+}
+
+
+static void pcibios_write_config_byte(
+ unsigned char bus, unsigned devfn, unsigned where, unsigned char value)
+{
+ outl(config_cmd(bus, devfn, where), 0xCF8);
+ outb(value, 0xCFC + (where & 3));
+}
+
+static void pcibios_write_config_word(
+ unsigned char bus, unsigned devfn, unsigned where, unsigned short value)
+{
+ outl(config_cmd(bus, devfn, where), 0xCF8);
+ outw(value, 0xCFC + (where & 2));
+}
+
+static void pcibios_write_config_dword(
+ unsigned char bus, unsigned devfn, unsigned where, unsigned int value)
+{
+ outl(config_cmd(bus, devfn, where), 0xCF8);
+ outl(value, 0xCFC);
+}
diff --git a/src/arch/i386/include/arch/smp/mpspec.h b/src/arch/i386/include/arch/smp/mpspec.h
new file mode 100644
index 0000000000..305276e482
--- /dev/null
+++ b/src/arch/i386/include/arch/smp/mpspec.h
@@ -0,0 +1,282 @@
+#ifndef __ASM_MPSPEC_H
+#define __ASM_MPSPEC_H
+
+#ifdef HAVE_MP_TABLE
+
+/*
+ * Structure definitions for SMP machines following the
+ * Intel Multiprocessing Specification 1.1 and 1.4.
+ */
+
+/*
+ * This tag identifies where the SMP configuration
+ * information is.
+ */
+
+#define SMP_MAGIC_IDENT (('_'<<24)|('P'<<16)|('M'<<8)|'_')
+
+/*
+ * a maximum of 16 APICs with the current APIC ID architecture.
+ */
+#define MAX_APICS 16
+
+
+#define SMP_FLOATING_TABLE_LEN sizeof(struct intel_mp_floating)
+
+struct intel_mp_floating
+{
+ char mpf_signature[4]; /* "_MP_" */
+ unsigned long mpf_physptr; /* Configuration table address */
+ unsigned char mpf_length; /* Our length (paragraphs) */
+ unsigned char mpf_specification;/* Specification version */
+ unsigned char mpf_checksum; /* Checksum (makes sum 0) */
+ unsigned char mpf_feature1; /* Standard or configuration ? */
+ unsigned char mpf_feature2; /* Bit7 set for IMCR|PIC */
+ unsigned char mpf_feature3; /* Unused (0) */
+ unsigned char mpf_feature4; /* Unused (0) */
+ unsigned char mpf_feature5; /* Unused (0) */
+};
+
+struct mp_config_table
+{
+ char mpc_signature[4];
+#define MPC_SIGNATURE "PCMP"
+ unsigned short mpc_length; /* Size of table */
+ char mpc_spec; /* 0x01 */
+ char mpc_checksum;
+ char mpc_oem[8];
+ char mpc_productid[12];
+ unsigned long mpc_oemptr; /* 0 if not present */
+ unsigned short mpc_oemsize; /* 0 if not present */
+ unsigned short mpc_entry_count;
+ unsigned long mpc_lapic; /* APIC address */
+ unsigned short mpe_length; /* Extended Table size */
+ unsigned char mpe_checksum; /* Extended Table checksum */
+ unsigned char reserved;
+};
+
+/* Followed by entries */
+
+#define MP_PROCESSOR 0
+#define MP_BUS 1
+#define MP_IOAPIC 2
+#define MP_INTSRC 3
+#define MP_LINTSRC 4
+
+struct mpc_config_processor
+{
+ unsigned char mpc_type;
+ unsigned char mpc_apicid; /* Local APIC number */
+ unsigned char mpc_apicver; /* Its versions */
+ unsigned char mpc_cpuflag;
+#define MPC_CPU_ENABLED 1 /* Processor is available */
+#define MPC_CPU_BOOTPROCESSOR 2 /* Processor is the BP */
+ unsigned long mpc_cpufeature;
+#define MPC_CPU_STEPPING_MASK 0x0F
+#define MPC_CPU_MODEL_MASK 0xF0
+#define MPC_CPU_FAMILY_MASK 0xF00
+ unsigned long mpc_featureflag; /* CPUID feature value */
+ unsigned long mpc_reserved[2];
+};
+
+struct mpc_config_bus
+{
+ unsigned char mpc_type;
+ unsigned char mpc_busid;
+ unsigned char mpc_bustype[6] __attribute((packed));
+};
+
+#define BUSTYPE_EISA "EISA"
+#define BUSTYPE_ISA "ISA"
+#define BUSTYPE_INTERN "INTERN" /* Internal BUS */
+#define BUSTYPE_MCA "MCA"
+#define BUSTYPE_VL "VL" /* Local bus */
+#define BUSTYPE_PCI "PCI"
+#define BUSTYPE_PCMCIA "PCMCIA"
+
+struct mpc_config_ioapic
+{
+ unsigned char mpc_type;
+ unsigned char mpc_apicid;
+ unsigned char mpc_apicver;
+ unsigned char mpc_flags;
+#define MPC_APIC_USABLE 0x01
+ unsigned long mpc_apicaddr;
+};
+
+struct mpc_config_intsrc
+{
+ unsigned char mpc_type;
+ unsigned char mpc_irqtype;
+ unsigned short mpc_irqflag;
+ unsigned char mpc_srcbus;
+ unsigned char mpc_srcbusirq;
+ unsigned char mpc_dstapic;
+ unsigned char mpc_dstirq;
+};
+
+enum mp_irq_source_types {
+ mp_INT = 0,
+ mp_NMI = 1,
+ mp_SMI = 2,
+ mp_ExtINT = 3
+};
+
+#define MP_IRQ_POLARITY_DEFAULT 0x0
+#define MP_IRQ_POLARITY_HIGH 0x1
+#define MP_IRQ_POLARITY_LOW 0x3
+#define MP_IRQ_POLARITY_MASK 0x3
+#define MP_IRQ_TRIGGER_DEFAULT 0x0
+#define MP_IRQ_TRIGGER_EDGE 0x4
+#define MP_IRQ_TRIGGER_LEVEL 0xc
+#define MP_IRQ_TRIGGER_MASK 0xc
+
+
+struct mpc_config_lintsrc
+{
+ unsigned char mpc_type;
+ unsigned char mpc_irqtype;
+ unsigned short mpc_irqflag;
+ unsigned char mpc_srcbusid;
+ unsigned char mpc_srcbusirq;
+ unsigned char mpc_destapic;
+#define MP_APIC_ALL 0xFF
+ unsigned char mpc_destapiclint;
+};
+
+/*
+ * Default configurations
+ *
+ * 1 2 CPU ISA 82489DX
+ * 2 2 CPU EISA 82489DX neither IRQ 0 timer nor IRQ 13 DMA chaining
+ * 3 2 CPU EISA 82489DX
+ * 4 2 CPU MCA 82489DX
+ * 5 2 CPU ISA+PCI
+ * 6 2 CPU EISA+PCI
+ * 7 2 CPU MCA+PCI
+ */
+
+#define MAX_IRQ_SOURCES 128
+#define MAX_MP_BUSSES 32
+enum mp_bustype {
+ MP_BUS_ISA,
+ MP_BUS_EISA,
+ MP_BUS_PCI,
+ MP_BUS_MCA
+};
+
+/* Followed by entries */
+
+#define MPE_SYSTEM_ADDRESS_SPACE 0x80
+#define MPE_BUS_HIERARCHY 0x81
+#define MPE_COMPATIBILITY_ADDRESS_SPACE 0x82
+
+struct mp_exten_config {
+ unsigned char mpe_type;
+ unsigned char mpe_length;
+};
+
+typedef struct mp_exten_config *mpe_t;
+
+struct mp_exten_system_address_space {
+ unsigned char mpe_type;
+ unsigned char mpe_length;
+ unsigned char mpe_busid;
+ unsigned char mpe_address_type;
+#define ADDRESS_TYPE_IO 0
+#define ADDRESS_TYPE_MEM 1
+#define ADDRESS_TYPE_PREFETCH 2
+ unsigned int mpe_address_base_low;
+ unsigned int mpe_address_base_high;
+ unsigned int mpe_address_length_low;
+ unsigned int mpe_address_length_high;
+};
+
+struct mp_exten_bus_hierarchy {
+ unsigned char mpe_type;
+ unsigned char mpe_length;
+ unsigned char mpe_busid;
+ unsigned char mpe_bus_info;
+#define BUS_SUBTRACTIVE_DECODE 1
+ unsigned char mpe_parent_busid;
+ unsigned char reserved[3];
+};
+
+struct mp_exten_compatibility_address_space {
+ unsigned char mpe_type;
+ unsigned char mpe_length;
+ unsigned char mpe_busid;
+ unsigned char mpe_address_modifier;
+#define ADDRESS_RANGE_SUBTRACT 1
+#define ADDRESS_RANGE_ADD 0
+ unsigned int mpe_range_list;
+#define RANGE_LIST_IO_ISA 0
+ /* X100 - X3FF
+ * X500 - X7FF
+ * X900 - XBFF
+ * XD00 - XFFF
+ */
+#define RANGE_LIST_IO_VGA 1
+ /* X3B0 - X3BB
+ * X3C0 - X3DF
+ * X7B0 - X7BB
+ * X7C0 - X7DF
+ * XBB0 - XBBB
+ * XBC0 - XBDF
+ * XFB0 - XFBB
+ * XFC0 - XCDF
+ */
+};
+
+/* Default local apic addr */
+#define LAPIC_ADDR 0xFEE00000
+
+void *smp_next_mpc_entry(struct mp_config_table *mc);
+void *smp_next_mpe_entry(struct mp_config_table *mc);
+
+void smp_write_processor(struct mp_config_table *mc,
+ unsigned char apicid, unsigned char apicver,
+ unsigned char cpuflag, unsigned int cpufeature,
+ unsigned int featureflag);
+void smp_write_processors(struct mp_config_table *mc,
+ unsigned long *processor_map);
+void smp_write_bus(struct mp_config_table *mc,
+ unsigned char id, unsigned char *bustype);
+void smp_write_ioapic(struct mp_config_table *mc,
+ unsigned char id, unsigned char ver,
+ unsigned long apicaddr);
+void smp_write_intsrc(struct mp_config_table *mc,
+ unsigned char irqtype, unsigned short irqflag,
+ unsigned char srcbus, unsigned char srcbusirq,
+ unsigned char dstapic, unsigned char dstirq);
+void smp_write_lintsrc(struct mp_config_table *mc,
+ unsigned char irqtype, unsigned short irqflag,
+ unsigned char srcbusid, unsigned char srcbusirq,
+ unsigned char destapic, unsigned char destapiclint);
+void smp_write_address_space(struct mp_config_table *mc,
+ unsigned char busid, unsigned char address_type,
+ unsigned int address_base_low, unsigned int address_base_high,
+ unsigned int address_length_low, unsigned int address_length_high);
+void smp_write_bus_hierarchy(struct mp_config_table *mc,
+ unsigned char busid, unsigned char bus_info,
+ unsigned char parent_busid);
+void smp_write_compatibility_address_space(struct mp_config_table *mc,
+ unsigned char busid, unsigned char address_modifier,
+ unsigned int range_list);
+unsigned char smp_compute_checksum(void *v, int len);
+void *smp_write_floating_table(unsigned long addr);
+unsigned long write_smp_table(unsigned long addr, unsigned long *processor_map);
+
+/* A table (per mainboard) listing the initial apicid of each cpu. */
+extern unsigned long initial_apicid[MAX_CPUS];
+
+#else /* HAVE_MP_TABLE */
+static inline
+unsigned long write_smp_table(unsigned long addr, unsigned long *processor_map)
+{
+ return addr;
+}
+#endif /* HAVE_MP_TABLE */
+
+#endif
+
diff --git a/src/arch/i386/include/bitops.h b/src/arch/i386/include/bitops.h
new file mode 100644
index 0000000000..fae2045b9a
--- /dev/null
+++ b/src/arch/i386/include/bitops.h
@@ -0,0 +1,20 @@
+#ifndef I386_BITOPS_H
+#define I386_BITOPS_H
+
+/**
+ * log2 - Find the truncated log base 2 of x
+ */
+
+static inline unsigned long log2(unsigned long x)
+{
+ unsigned long r = 0;
+ __asm__(
+ "bsrl %1, %0\n\t"
+ "jnz 1f\n\t"
+ "movl $-1, %0\n\t"
+ "1:\n\t"
+ : "=r" (r) : "r" (x));
+ return r;
+
+}
+#endif /* I386_BITOPS_H */
diff --git a/src/arch/i386/include/stddef.h b/src/arch/i386/include/stddef.h
new file mode 100644
index 0000000000..4bf6b0a867
--- /dev/null
+++ b/src/arch/i386/include/stddef.h
@@ -0,0 +1,15 @@
+#ifndef I386_STDDEF_H
+#define I386_STDDEF_H
+
+typedef long ptrdiff_t;
+typedef unsigned long size_t;
+typedef long ssize_t;
+
+typedef int wchar_t;
+typedef unsigned int wint_t;
+
+#define NULL 0
+
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+#endif /* I386_STDDEF_H */
diff --git a/src/arch/i386/include/stdint.h b/src/arch/i386/include/stdint.h
new file mode 100644
index 0000000000..58d7519cde
--- /dev/null
+++ b/src/arch/i386/include/stdint.h
@@ -0,0 +1,52 @@
+#ifndef I386_STDINT_H
+#define I386_STDINT_H
+
+/* Exact integral types */
+typedef unsigned char uint8_t;
+typedef signed char int8_t;
+
+typedef unsigned short uint16_t;
+typedef signed short int16_t;
+
+typedef unsigned int uint32_t;
+typedef signed int int32_t;
+
+typedef unsigned long long uint64_t;
+typedef signed long long int64_t;
+
+/* Small types */
+typedef unsigned char uint_least8_t;
+typedef signed char int_least8_t;
+
+typedef unsigned short uint_least16_t;
+typedef signed short int_least16_t;
+
+typedef unsigned int uint_least32_t;
+typedef signed int int_least32_t;
+
+typedef unsigned long long uint_least64_t;
+typedef signed long long int_least64_t;
+
+/* Fast Types */
+typedef unsigned char uint_fast8_t;
+typedef signed char int_fast8_t;
+
+typedef unsigned int uint_fast16_t;
+typedef signed int int_fast16_t;
+
+typedef unsigned int uint_fast32_t;
+typedef signed int int_fast32_t;
+
+typedef unsigned long long uint_fast64_t;
+typedef signed long long int_fast64_t;
+
+/* Types for `void *' pointers. */
+typedef int intptr_t;
+typedef unsigned int uintptr_t;
+
+/* Largest integral types */
+typedef long long int intmax_t;
+typedef unsigned long long uintmax_t;
+
+
+#endif /* I386_STDINT_H */
diff --git a/src/arch/i386/lib/c_start.S b/src/arch/i386/lib/c_start.S
new file mode 100644
index 0000000000..f5ca3388f8
--- /dev/null
+++ b/src/arch/i386/lib/c_start.S
@@ -0,0 +1,135 @@
+#include <arch/asm.h>
+#include <arch/intel.h>
+#ifdef SMP
+#include <cpu/p6/apic.h>
+#endif
+ .section ".text"
+ .code32
+ .globl _start
+_start:
+ cli
+ lgdt %cs:gdtaddr
+ ljmp $0x10, $1f
+1: movl $0x18, %eax
+ movl %eax, %ds
+ movl %eax, %es
+ movl %eax, %ss
+ movl %eax, %fs
+ movl %eax, %gs
+
+ intel_chip_post_macro(0x13) /* post 12 */
+
+ /** clear stack */
+ leal EXT(_stack), %edi
+ movl $EXT(_estack), %ecx
+ subl %edi, %ecx
+ xorl %eax, %eax
+ rep
+ stosb
+
+ /** clear bss */
+ leal EXT(_bss), %edi
+ movl $EXT(_ebss), %ecx
+ subl %edi, %ecx
+ jz .Lnobss
+ xorl %eax, %eax
+ rep
+ stosb
+.Lnobss:
+
+ /* set new stack */
+ movl $_estack, %esp
+#ifdef SMP
+ /* Get the cpu id */
+ movl $APIC_DEFAULT_BASE, %edi
+ movl APIC_ID(%edi), %eax
+ shrl $24, %eax
+
+ /* Get the cpu index (MAX_CPUS on error) */
+ movl $-4, %ebx
+1: addl $4, %ebx
+ cmpl $(MAX_CPUS << 2), %ebx
+ je 2
+ cmpl %eax, EXT(initial_apicid)(%ebx)
+ jne 1b
+2: shrl $2, %ebx
+
+ /* Now compute the appropriate stack */
+ movl %ebx, %eax
+ movl $STACK_SIZE, %ebx
+ mull %ebx
+ subl %eax, %esp
+#endif
+
+ /* push the boot_complete flag */
+ pushl %ebp
+
+ /* Save the stack location */
+ movl %esp, %ebp
+
+ /*
+ * Now we are finished. Memory is up, data is copied and
+ * bss is cleared. Now we call the main routine and
+ * let it do the rest.
+ */
+ intel_chip_post_macro(0xfe) /* post fe */
+
+ /* Resort the stack location */
+ movl %ebp, %esp
+
+ /* The boot_complete flag has already been pushed */
+ call EXT(hardwaremain)
+ /*NOTREACHED*/
+.Lhlt:
+ intel_chip_post_macro(0xee) /* post fe */
+ hlt
+ jmp .Lhlt
+
+
+ .globl gdt, gdt_end, gdt_limit
+
+gdt_limit = gdt_end - gdt - 1 /* compute the table limit */
+gdtaddr:
+ .word gdt_limit
+ .long gdt /* we know the offset */
+
+gdt:
+// selgdt 0
+ .word 0x0000, 0x0000 /* dummy */
+ .byte 0x00, 0x00, 0x00, 0x00
+
+// selgdt 8
+ .word 0x0000, 0x0000 /* dummy */
+ .byte 0x00, 0x00, 0x00, 0x00
+
+// selgdt 0x10
+/* flat code segment */
+ .word 0xffff, 0x0000
+ .byte 0x00, 0x9b, 0xcf, 0x00
+
+//selgdt 0x18
+/* flat data segment */
+ .word 0xffff, 0x0000
+ .byte 0x00, 0x93, 0xcf, 0x00
+
+//selgdt 0x20
+ .word 0x0000, 0x0000 /* dummy */
+ .byte 0x00, 0x00, 0x00, 0x00
+
+#if defined(CONFIG_VGABIOS) && (CONFIG_VGABIOS == 1)
+ // from monty:
+ /* 0x00009a00,0000ffffULL, 20h: 16-bit 64k code at 0x00000000 */
+ /* 0x00009200,0000ffffULL 28h: 16-bit 64k data at 0x00000000 */
+// selgdt 0x28
+/*16-bit 64k code at 0x00000000 */
+ .word 0xffff, 0x0000
+ .byte 0, 0x9a, 0, 0
+
+// selgdt 0x30
+/*16-bit 64k data at 0x00000000 */
+ .word 0xffff, 0x0000
+ .byte 0, 0x92, 0, 0
+#endif // defined(CONFIG_VGABIOS) && (CONFIG_VGABIOS == 1)
+gdt_end:
+
+.code32
diff --git a/src/arch/i386/lib/console.c b/src/arch/i386/lib/console.c
new file mode 100644
index 0000000000..8c8eccdd2a
--- /dev/null
+++ b/src/arch/i386/lib/console.c
@@ -0,0 +1,119 @@
+#include <console/loglevel.h>
+
+static void __console_tx_byte(unsigned char byte)
+{
+ uart_tx_byte(byte);
+}
+
+static void __console_tx_nibble(unsigned nibble)
+{
+ unsigned char digit;
+ digit = nibble + '0';
+ if (digit > '9') {
+ digit += 39;
+ }
+ __console_tx_byte(digit);
+}
+
+static void __console_tx_char(int loglevel, unsigned char byte)
+{
+ if (ASM_CONSOLE_LOGLEVEL > loglevel) {
+ uart_tx_byte(byte);
+ }
+}
+
+static void __console_tx_hex8(int loglevel, unsigned char byte)
+{
+ if (ASM_CONSOLE_LOGLEVEL > loglevel) {
+ __console_tx_nibble(byte >> 4U);
+ __console_tx_nibble(byte & 0x0fU);
+ }
+}
+
+static void __console_tx_hex32(int loglevel, unsigned int value)
+{
+ if (ASM_CONSOLE_LOGLEVEL > loglevel) {
+ __console_tx_nibble((value >> 28U) & 0x0fU);
+ __console_tx_nibble((value >> 24U) & 0x0fU);
+ __console_tx_nibble((value >> 20U) & 0x0fU);
+ __console_tx_nibble((value >> 16U) & 0x0fU);
+ __console_tx_nibble((value >> 12U) & 0x0fU);
+ __console_tx_nibble((value >> 8U) & 0x0fU);
+ __console_tx_nibble((value >> 4U) & 0x0fU);
+ __console_tx_nibble(value & 0x0fU);
+ }
+}
+
+static void __console_tx_string(int loglevel, const char *str)
+{
+ if (ASM_CONSOLE_LOGLEVEL > loglevel) {
+ unsigned char ch;
+ while((ch = *str++) != '\0') {
+ __console_tx_byte(ch);
+ }
+ }
+}
+
+static void print_emerg_char(unsigned char byte) { __console_tx_char(BIOS_EMERG, byte); }
+static void print_emerg_hex8(unsigned char value){ __console_tx_hex8(BIOS_EMERG, value); }
+static void print_emerg_hex32(unsigned int value) { __console_tx_hex32(BIOS_EMERG, value); }
+static void print_emerg(const char *str) { __console_tx_string(BIOS_EMERG, str); }
+
+static void print_alert_char(unsigned char byte) { __console_tx_char(BIOS_ALERT, byte); }
+static void print_alert_hex8(unsigned char value) { __console_tx_hex8(BIOS_ALERT, value); }
+static void print_alert_hex32(unsigned int value) { __console_tx_hex32(BIOS_ALERT, value); }
+static void print_alert(const char *str) { __console_tx_string(BIOS_ALERT, str); }
+
+static void print_crit_char(unsigned char byte) { __console_tx_char(BIOS_CRIT, byte); }
+static void print_crit_hex8(unsigned char value) { __console_tx_hex8(BIOS_CRIT, value); }
+static void print_crit_hex32(unsigned int value) { __console_tx_hex32(BIOS_CRIT, value); }
+static void print_crit(const char *str) { __console_tx_string(BIOS_CRIT, str); }
+
+static void print_err_char(unsigned char byte) { __console_tx_char(BIOS_ERR, byte); }
+static void print_err_hex8(unsigned char value) { __console_tx_hex8(BIOS_ERR, value); }
+static void print_err_hex32(unsigned int value) { __console_tx_hex32(BIOS_ERR, value); }
+static void print_err(const char *str) { __console_tx_string(BIOS_ERR, str); }
+
+static void print_warning_char(unsigned char byte) { __console_tx_char(BIOS_WARNING, byte); }
+static void print_warning_hex8(unsigned char value) { __console_tx_hex8(BIOS_WARNING, value); }
+static void print_warning_hex32(unsigned int value) { __console_tx_hex32(BIOS_WARNING, value); }
+static void print_warning(const char *str) { __console_tx_string(BIOS_WARNING, str); }
+
+static void print_notice_char(unsigned char byte) { __console_tx_char(BIOS_NOTICE, byte); }
+static void print_notice_hex8(unsigned char value) { __console_tx_hex8(BIOS_NOTICE, value); }
+static void print_notice_hex32(unsigned int value) { __console_tx_hex32(BIOS_NOTICE, value); }
+static void print_notice(const char *str) { __console_tx_string(BIOS_NOTICE, str); }
+
+static void print_info_char(unsigned char byte) { __console_tx_char(BIOS_INFO, byte); }
+static void print_info_hex8(unsigned char value) { __console_tx_hex8(BIOS_INFO, value); }
+static void print_info_hex32(unsigned int value) { __console_tx_hex32(BIOS_INFO, value); }
+static void print_info(const char *str) { __console_tx_string(BIOS_INFO, str); }
+
+static void print_debug_char(unsigned char byte) { __console_tx_char(BIOS_DEBUG, byte); }
+static void print_debug_hex8(unsigned char value) { __console_tx_hex8(BIOS_DEBUG, value); }
+static void print_debug_hex32(unsigned int value) { __console_tx_hex32(BIOS_DEBUG, value); }
+static void print_debug(const char *str) { __console_tx_string(BIOS_DEBUG, str); }
+
+static void print_spew_char(unsigned char byte) { __console_tx_char(BIOS_SPEW, byte); }
+static void print_spew_hex8(unsigned char value) { __console_tx_hex8(BIOS_SPEW, value); }
+static void print_spew_hex32(unsigned int value) { __console_tx_hex32(BIOS_SPEW, value); }
+static void print_spew(const char *str) { __console_tx_string(BIOS_SPEW, str); }
+
+#define __STR(X) #X
+#define STR(X) __STR(X)
+
+#ifndef LINUXBIOS_EXTRA_VERSION
+#define LINUXBIOS_EXTRA_VERSION
+#endif
+
+static void console_init(void)
+{
+ static const char console_test[] =
+ "\r\n\r\nLinuxBIOS-"
+ STR(LINUXBIOS_VERSION)
+ STR(LINUXBIOS_EXTRA_VERSION)
+ " "
+ STR(LINUXBIOS_BUILD)
+ " starting...\r\n";
+ print_info(console_test);
+}
diff --git a/src/arch/i386/lib/console.inc b/src/arch/i386/lib/console.inc
new file mode 100644
index 0000000000..3d6b01b3a2
--- /dev/null
+++ b/src/arch/i386/lib/console.inc
@@ -0,0 +1,527 @@
+#include <console/loglevel.h>
+
+jmp console0
+
+#define __STR(X) #X
+#define STR(X) __STR(X)
+
+#ifndef LINUXBIOS_EXTRA_VERSION
+#define LINUXBIOS_EXTRA_VERSION
+#endif
+
+console_test:
+ .ascii "\r\n\r\nLinuxBIOS-"
+ .ascii STR(LINUXBIOS_VERSION)
+ .ascii STR(LINUXBIOS_EXTRA_VERSION)
+ .ascii " "
+ .ascii STR(LINUXBIOS_BUILD)
+ .asciz " starting...\r\n"
+
+#undef STR
+ /* uses: ax, dx */
+#if CONFIG_CONSOLE_SERIAL8250
+#define __CONSOLE_INLINE_TX_AL TTYS0_TX_AL
+#else
+#define __CONSOLE_INLINE_TX_AL
+#endif
+
+ /* uses: esp, ax, dx */
+#define __CONSOLE_TX_CHAR(byte) \
+ mov byte, %al ; \
+ CALLSP(console_tx_al)
+
+ /* uses: ax, dx */
+#define __CONSOLE_INLINE_TX_CHAR(byte) \
+ mov byte, %al ; \
+ __CONSOLE_INLINE_TX_AL
+
+ /* uses: esp, ax, edx */
+#define __CONSOLE_TX_HEX8(byte) \
+ mov byte, %al ; \
+ CALLSP(console_tx_hex8)
+
+ /* uses: byte, ax, dx */
+#define __CONSOLE_INLINE_TX_HEX8(byte) \
+ movb byte, %dl ; \
+ shll $16, %edx ; \
+ shr $4, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ __CONSOLE_INLINE_TX_AL ; \
+ shrl $16, %edx ; \
+ movb %dl, %al ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ __CONSOLE_INLINE_TX_AL
+
+ /* uses: esp, eax, ebx, dx */
+#define __CONSOLE_TX_HEX32(lword) \
+ mov lword, %eax ; \
+ CALLSP(console_tx_hex32)
+
+ /* uses: eax, lword, dx */
+#define __CONSOLE_INLINE_TX_HEX32(lword) \
+ mov lword, %eax ; \
+ shr $28, %eax ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ __CONSOLE_INLINE_TX_AL ; \
+ ; \
+ mov lword, %eax ; \
+ shr $24, %eax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ __CONSOLE_INLINE_TX_AL ; \
+ ; \
+ mov lword, %eax ; \
+ shr $20, %eax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ __CONSOLE_INLINE_TX_AL ; \
+ ; \
+ mov lword, %eax ; \
+ shr $16, %eax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ __CONSOLE_INLINE_TX_AL ; \
+ ; \
+ mov lword, %eax ; \
+ shr $12, %eax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ __CONSOLE_INLINE_TX_AL ; \
+ ; \
+ mov lword, %eax ; \
+ shr $8, %eax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ __CONSOLE_INLINE_TX_AL ; \
+ ; \
+ mov lword, %eax ; \
+ shr $4, %eax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ __CONSOLE_INLINE_TX_AL ; \
+ ; \
+ mov lword, %eax ; \
+ and $0x0f, %al ; \
+ add $'0', %al ; \
+ cmp $'9', %al ; \
+ jle 9f ; \
+ add $39, %al ; \
+9: ; \
+ __CONSOLE_INLINE_TX_AL
+
+
+ /* uses: esp, ebx, ax, dx */
+#define __CONSOLE_TX_STRING(string) \
+ mov string, %ebx ; \
+ CALLSP(console_tx_string)
+
+ /* uses: ebx, ax, dx */
+#define __CONSOLE_INLINE_TX_STRING(string) \
+ movl string, %ebx ; \
+10: movb (%ebx), %al ; \
+ incl %ebx ; \
+ testb %al, %al ; \
+ jz 11f ; \
+ __CONSOLE_INLINE_TX_AL ; \
+ jmp 10b ; \
+11:
+
+
+#define CONSOLE_EMERG_TX_CHAR(byte) __CONSOLE_TX_CHAR(byte)
+#define CONSOLE_EMERG_INLINE_TX_CHAR(byte) __CONSOLE_INLINE_TX_CHAR(byte)
+#define CONSOLE_EMERG_TX_HEX8(byte) __CONSOLE_TX_HEX8(byte)
+#define CONSOLE_EMERG_INLINE_TX_HEX8(byte) __CONSOLE_INLINE_TX_HEX8(byte)
+#define CONSOLE_EMERG_TX_HEX32(lword) __CONSOLE_TX_HEX32(lword)
+#define CONSOLE_EMERG_INLINE_TX_HEX32(lword) __CONSOLE_INLINE_TX_HEX32(lword)
+#define CONSOLE_EMERG_TX_STRING(string) __CONSOLE_TX_STRING(string)
+#define CONSOLE_EMERG_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string)
+
+#define CONSOLE_ALERT_TX_CHAR(byte) __CONSOLE_TX_CHAR(byte)
+#define CONSOLE_ALERT_INLINE_TX_CHAR(byte) __CONSOLE_INLINE_TX_CHAR(byte)
+#define CONSOLE_ALERT_TX_HEX8(byte) __CONSOLE_TX_HEX8(byte)
+#define CONSOLE_ALERT_INLINE_TX_HEX8(byte) __CONSOLE_INLINE_TX_HEX8(byte)
+#define CONSOLE_ALERT_TX_HEX32(lword) __CONSOLE_TX_HEX32(lword)
+#define CONSOLE_ALERT_INLINE_TX_HEX32(lword) __CONSOLE_INLINE_TX_HEX32(lword)
+#define CONSOLE_ALERT_TX_STRING(string) __CONSOLE_TX_STRING(string)
+#define CONSOLE_ALERT_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string)
+
+#define CONSOLE_CRIT_TX_CHAR(byte) __CONSOLE_TX_CHAR(byte)
+#define CONSOLE_CRIT_INLINE_TX_CHAR(byte) __CONSOLE_INLINE_TX_CHAR(byte)
+#define CONSOLE_CRIT_TX_HEX8(byte) __CONSOLE_TX_HEX8(byte)
+#define CONSOLE_CRIT_INLINE_TX_HEX8(byte) __CONSOLE_INLINE_TX_HEX8(byte)
+#define CONSOLE_CRIT_TX_HEX32(lword) __CONSOLE_TX_HEX32(lword)
+#define CONSOLE_CRIT_INLINE_TX_HEX32(lword) __CONSOLE_INLINE_TX_HEX32(lword)
+#define CONSOLE_CRIT_TX_STRING(string) __CONSOLE_TX_STRING(string)
+#define CONSOLE_CRIT_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string)
+
+#define CONSOLE_ERR_TX_CHAR(byte) __CONSOLE_TX_CHAR(byte)
+#define CONSOLE_ERR_INLINE_TX_CHAR(byte) __CONSOLE_INLINE_TX_CHAR(byte)
+#define CONSOLE_ERR_TX_HEX8(byte) __CONSOLE_TX_HEX8(byte)
+#define CONSOLE_ERR_INLINE_TX_HEX8(byte) __CONSOLE_INLINE_TX_HEX8(byte)
+#define CONSOLE_ERR_TX_HEX32(lword) __CONSOLE_TX_HEX32(lword)
+#define CONSOLE_ERR_INLINE_TX_HEX32(lword) __CONSOLE_INLINE_TX_HEX32(lword)
+#define CONSOLE_ERR_TX_STRING(string) __CONSOLE_TX_STRING(string)
+#define CONSOLE_ERR_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string)
+
+#define CONSOLE_WARNING_TX_CHAR(byte) __CONSOLE_TX_CHAR(byte)
+#define CONSOLE_WARNING_INLINE_TX_CHAR(byte) __CONSOLE_INLINE_TX_CHAR(byte)
+#define CONSOLE_WARNING_TX_HEX8(byte) __CONSOLE_TX_HEX8(byte)
+#define CONSOLE_WARNING_INLINE_TX_HEX8(byte) __CONSOLE_INLINE_TX_HEX8(byte)
+#define CONSOLE_WARNING_TX_HEX32(lword) __CONSOLE_TX_HEX32(lword)
+#define CONSOLE_WARNING_INLINE_TX_HEX32(lword) __CONSOLE_INLINE_TX_HEX32(lword)
+#define CONSOLE_WARNING_TX_STRING(string) __CONSOLE_TX_STRING(string)
+#define CONSOLE_WARNING_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string)
+
+#define CONSOLE_NOTICE_TX_CHAR(byte) __CONSOLE_TX_CHAR(byte)
+#define CONSOLE_NOTICE_INLINE_TX_CHAR(byte) __CONSOLE_INLINE_TX_CHAR(byte)
+#define CONSOLE_NOTICE_TX_HEX8(byte) __CONSOLE_TX_HEX8(byte)
+#define CONSOLE_NOTICE_INLINE_TX_HEX8(byte) __CONSOLE_INLINE_TX_HEX8(byte)
+#define CONSOLE_NOTICE_TX_HEX32(lword) __CONSOLE_TX_HEX32(lword)
+#define CONSOLE_NOTICE_INLINE_TX_HEX32(lword) __CONSOLE_INLINE_TX_HEX32(lword)
+#define CONSOLE_NOTICE_TX_STRING(string) __CONSOLE_TX_STRING(string)
+#define CONSOLE_NOTICE_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string)
+
+#define CONSOLE_INFO_TX_CHAR(byte) __CONSOLE_TX_CHAR(byte)
+#define CONSOLE_INFO_INLINE_TX_CHAR(byte) __CONSOLE_INLINE_TX_CHAR(byte)
+#define CONSOLE_INFO_TX_HEX8(byte) __CONSOLE_TX_HEX8(byte)
+#define CONSOLE_INFO_INLINE_TX_HEX8(byte) __CONSOLE_INLINE_TX_HEX8(byte)
+#define CONSOLE_INFO_TX_HEX32(lword) __CONSOLE_TX_HEX32(lword)
+#define CONSOLE_INFO_INLINE_TX_HEX32(lword) __CONSOLE_INLINE_TX_HEX32(lword)
+#define CONSOLE_INFO_TX_STRING(string) __CONSOLE_TX_STRING(string)
+#define CONSOLE_INFO_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string)
+
+#define CONSOLE_DEBUG_TX_CHAR(byte) __CONSOLE_TX_CHAR(byte)
+#define CONSOLE_DEBUG_INLINE_TX_CHAR(byte) __CONSOLE_INLINE_TX_CHAR(byte)
+#define CONSOLE_DEBUG_TX_HEX8(byte) __CONSOLE_TX_HEX8(byte)
+#define CONSOLE_DEBUG_INLINE_TX_HEX8(byte) __CONSOLE_INLINE_TX_HEX8(byte)
+#define CONSOLE_DEBUG_TX_HEX32(lword) __CONSOLE_TX_HEX32(lword)
+#define CONSOLE_DEBUG_INLINE_TX_HEX32(lword) __CONSOLE_INLINE_TX_HEX32(lword)
+#define CONSOLE_DEBUG_TX_STRING(string) __CONSOLE_TX_STRING(string)
+#define CONSOLE_DEBUG_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string)
+
+#define CONSOLE_SPEW_TX_CHAR(byte) __CONSOLE_TX_CHAR(byte)
+#define CONSOLE_SPEW_INLINE_TX_CHAR(byte) __CONSOLE_INLINE_TX_CHAR(byte)
+#define CONSOLE_SPEW_TX_HEX8(byte) __CONSOLE_TX_HEX8(byte)
+#define CONSOLE_SPEW_INLINE_TX_HEX8(byte) __CONSOLE_INLINE_TX_HEX8(byte)
+#define CONSOLE_SPEW_TX_HEX32(lword) __CONSOLE_TX_HEX32(lword)
+#define CONSOLE_SPEW_INLINE_TX_HEX32(lword) __CONSOLE_INLINE_TX_HEX32(lword)
+#define CONSOLE_SPEW_TX_STRING(string) __CONSOLE_TX_STRING(string)
+#define CONSOLE_SPEW_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string)
+
+#if ASM_CONSOLE_LOGLEVEL <= BIOS_EMERG
+#undef CONSOLE_EMERG_TX_CHAR
+#undef CONSOLE_EMERG_INLINE_TX_CHAR
+#undef CONSOLE_EMERG_TX_HEX8
+#undef CONSOLE_EMERG_INLINE_TX_HEX8
+#undef CONSOLE_EMERG_TX_HEX32
+#undef CONSOLE_EMERG_INLINE_TX_HEX32
+#undef CONSOLE_EMERG_TX_STRING
+#undef CONSOLE_EMERG_INLINE_TX_STRING
+#define CONSOLE_EMERG_TX_CHAR(byte)
+#define CONSOLE_EMERG_INLINE_TX_CHAR(byte)
+#define CONSOLE_EMERG_TX_HEX8(byte)
+#define CONSOLE_EMERG_INLINE_TX_HEX8(byte)
+#define CONSOLE_EMERG_TX_HEX32(lword)
+#define CONSOLE_EMERG_INLINE_TX_HEX32(lword)
+#define CONSOLE_EMERG_TX_STRING(string)
+#define CONSOLE_EMERG_INLINE_TX_STRING(string)
+#endif
+
+
+#if ASM_CONSOLE_LOGLEVEL <= BIOS_ALERT
+#undef CONSOLE_ALERT_TX_CHAR
+#undef CONSOLE_ALERT_INLINE_TX_CHAR
+#undef CONSOLE_ALERT_TX_HEX8
+#undef CONSOLE_ALERT_INLINE_TX_HEX8
+#undef CONSOLE_ALERT_TX_HEX32
+#undef CONSOLE_ALERT_INLINE_TX_HEX32
+#undef CONSOLE_ALERT_TX_STRING
+#undef CONSOLE_ALERT_INLINE_TX_STRING
+#define CONSOLE_ALERT_TX_CHAR(byte)
+#define CONSOLE_ALERT_INLINE_TX_CHAR(byte)
+#define CONSOLE_ALERT_TX_HEX8(byte)
+#define CONSOLE_ALERT_INLINE_TX_HEX8(byte)
+#define CONSOLE_ALERT_TX_HEX32(lword)
+#define CONSOLE_ALERT_INLINE_TX_HEX32(lword)
+#define CONSOLE_ALERT_TX_STRING(string)
+#define CONSOLE_ALERT_INLINE_TX_STRING(string)
+#endif
+
+#if ASM_CONSOLE_LOGLEVEL <= BIOS_CRIT
+#undef CONSOLE_CRIT_TX_CHAR
+#undef CONSOLE_CRIT_INLINE_TX_CHAR
+#undef CONSOLE_CRIT_TX_HEX8
+#undef CONSOLE_CRIT_INLINE_TX_HEX8
+#undef CONSOLE_CRIT_TX_HEX32
+#undef CONSOLE_CRIT_INLINE_TX_HEX32
+#undef CONSOLE_CRIT_TX_STRING
+#undef CONSOLE_CRIT_INLINE_TX_STRING
+#define CONSOLE_CRIT_TX_CHAR(byte)
+#define CONSOLE_CRIT_INLINE_TX_CHAR(byte)
+#define CONSOLE_CRIT_TX_HEX8(byte)
+#define CONSOLE_CRIT_INLINE_TX_HEX8(byte)
+#define CONSOLE_CRIT_TX_HEX32(lword)
+#define CONSOLE_CRIT_INLINE_TX_HEX32(lword)
+#define CONSOLE_CRIT_TX_STRING(string)
+#define CONSOLE_CRIT_INLINE_TX_STRING(string)
+#endif
+
+#if ASM_CONSOLE_LOGLEVEL <= BIOS_ERR
+#undef CONSOLE_ERR_TX_CHAR
+#undef CONSOLE_ERR_INLINE_TX_CHAR
+#undef CONSOLE_ERR_TX_HEX8
+#undef CONSOLE_ERR_INLINE_TX_HEX8
+#undef CONSOLE_ERR_TX_HEX32
+#undef CONSOLE_ERR_INLINE_TX_HEX32
+#undef CONSOLE_ERR_TX_STRING
+#undef CONSOLE_ERR_INLINE_TX_STRING
+#define CONSOLE_ERR_TX_CHAR(byte)
+#define CONSOLE_ERR_INLINE_TX_CHAR(byte)
+#define CONSOLE_ERR_TX_HEX8(byte)
+#define CONSOLE_ERR_INLINE_TX_HEX8(byte)
+#define CONSOLE_ERR_TX_HEX32(lword)
+#define CONSOLE_ERR_INLINE_TX_HEX32(lword)
+#define CONSOLE_ERR_TX_STRING(string)
+#define CONSOLE_ERR_INLINE_TX_STRING(string)
+#endif
+
+#if ASM_CONSOLE_LOGLEVEL <= BIOS_WARNING
+#undef CONSOLE_WARNING_TX_CHAR
+#undef CONSOLE_WARNING_INLINE_TX_CHAR
+#undef CONSOLE_WARNING_TX_HEX8
+#undef CONSOLE_WARNING_INLINE_TX_HEX8
+#undef CONSOLE_WARNING_TX_HEX32
+#undef CONSOLE_WARNING_INLINE_TX_HEX32
+#undef CONSOLE_WARNING_TX_STRING
+#undef CONSOLE_WARNING_INLINE_TX_STRING
+#define CONSOLE_WARNING_TX_CHAR(byte)
+#define CONSOLE_WARNING_INLINE_TX_CHAR(byte)
+#define CONSOLE_WARNING_TX_HEX8(byte)
+#define CONSOLE_WARNING_INLINE_TX_HEX8(byte)
+#define CONSOLE_WARNING_TX_HEX32(lword)
+#define CONSOLE_WARNING_INLINE_TX_HEX32(lword)
+#define CONSOLE_WARNING_TX_STRING(string)
+#define CONSOLE_WARNING_INLINE_TX_STRING(string)
+#endif
+
+#if ASM_CONSOLE_LOGLEVEL <= BIOS_NOTICE
+#undef CONSOLE_NOTICE_TX_CHAR
+#undef CONSOLE_NOTICE_INLINE_TX_CHAR
+#undef CONSOLE_NOTICE_TX_HEX8
+#undef CONSOLE_NOTICE_INLINE_TX_HEX8
+#undef CONSOLE_NOTICE_TX_HEX32
+#undef CONSOLE_NOTICE_INLINE_TX_HEX32
+#undef CONSOLE_NOTICE_TX_STRING
+#undef CONSOLE_NOTICE_INLINE_TX_STRING
+#define CONSOLE_NOTICE_TX_CHAR(byte)
+#define CONSOLE_NOTICE_INLINE_TX_CHAR(byte)
+#define CONSOLE_NOTICE_TX_HEX8(byte)
+#define CONSOLE_NOTICE_INLINE_TX_HEX8(byte)
+#define CONSOLE_NOTICE_TX_HEX32(lword)
+#define CONSOLE_NOTICE_INLINE_TX_HEX32(lword)
+#define CONSOLE_NOTICE_TX_STRING(string)
+#define CONSOLE_NOTICE_INLINE_TX_STRING(string)
+#endif
+
+#if ASM_CONSOLE_LOGLEVEL <= BIOS_INFO
+#undef CONSOLE_INFO_TX_CHAR
+#undef CONSOLE_INFO_INLINE_TX_CHAR
+#undef CONSOLE_INFO_TX_HEX8
+#undef CONSOLE_INFO_INLINE_TX_HEX8
+#undef CONSOLE_INFO_TX_HEX32
+#undef CONSOLE_INFO_INLINE_TX_HEX32
+#undef CONSOLE_INFO_TX_STRING
+#undef CONSOLE_INFO_INLINE_TX_STRING
+#define CONSOLE_INFO_TX_CHAR(byte)
+#define CONSOLE_INFO_INLINE_TX_CHAR(byte)
+#define CONSOLE_INFO_TX_HEX8(byte)
+#define CONSOLE_INFO_INLINE_TX_HEX8(byte)
+#define CONSOLE_INFO_TX_HEX32(lword)
+#define CONSOLE_INFO_INLINE_TX_HEX32(lword)
+#define CONSOLE_INFO_TX_STRING(string)
+#define CONSOLE_INFO_INLINE_TX_STRING(string)
+#endif
+
+#if ASM_CONSOLE_LOGLEVEL <= BIOS_DEBUG
+#undef CONSOLE_DEBUG_TX_CHAR
+#undef CONSOLE_DEBUG_INLINE_TX_CHAR
+#undef CONSOLE_DEBUG_TX_HEX8
+#undef CONSOLE_DEBUG_INLINE_TX_HEX8
+#undef CONSOLE_DEBUG_TX_HEX32
+#undef CONSOLE_DEBUG_INLINE_TX_HEX32
+#undef CONSOLE_DEBUG_TX_STRING
+#undef CONSOLE_DEBUG_INLINE_TX_STRING
+#define CONSOLE_DEBUG_TX_CHAR(byte)
+#define CONSOLE_DEBUG_INLINE_TX_CHAR(byte)
+#define CONSOLE_DEBUG_TX_HEX8(byte)
+#define CONSOLE_DEBUG_INLINE_TX_HEX8(byte)
+#define CONSOLE_DEBUG_TX_HEX32(lword)
+#define CONSOLE_DEBUG_INLINE_TX_HEX32(lword)
+#define CONSOLE_DEBUG_TX_STRING(string)
+#define CONSOLE_DEBUG_INLINE_TX_STRING(string)
+#endif
+
+#if ASM_CONSOLE_LOGLEVEL <= BIOS_SPEW
+#undef CONSOLE_SPEW_TX_CHAR
+#undef CONSOLE_SPEW_INLINE_TX_CHAR
+#undef CONSOLE_SPEW_TX_HEX8
+#undef CONSOLE_SPEW_INLINE_TX_HEX8
+#undef CONSOLE_SPEW_TX_HEX32
+#undef CONSOLE_SPEW_INLINE_TX_HEX32
+#undef CONSOLE_SPEW_TX_STRING
+#undef CONSOLE_SPEW_INLINE_TX_STRING
+#define CONSOLE_SPEW_TX_CHAR(byte)
+#define CONSOLE_SPEW_INLINE_TX_CHAR(byte)
+#define CONSOLE_SPEW_TX_HEX8(byte)
+#define CONSOLE_SPEW_INLINE_TX_HEX8(byte)
+#define CONSOLE_SPEW_TX_HEX32(lword)
+#define CONSOLE_SPEW_INLINE_TX_HEX32(lword)
+#define CONSOLE_SPEW_TX_STRING(string)
+#define CONSOLE_SPEW_INLINE_TX_STRING(string)
+#endif
+
+
+ /* uses: esp, ax, dx */
+console_tx_al:
+ __CONSOLE_INLINE_TX_AL
+ RETSP
+
+ /* uses: esp, ax, edx */
+console_tx_hex8:
+ __CONSOLE_INLINE_TX_HEX8(%al)
+ RETSP
+
+
+ /* uses: esp, ebx, eax, dx */
+console_tx_hex32:
+ mov %eax, %ebx
+ shr $28, %eax
+ add $'0', %al
+ cmp $'9', %al
+ jle 9f
+ add $39, %al
+9:
+ __CONSOLE_INLINE_TX_AL
+
+ mov %ebx, %eax
+ shr $24, %eax
+ and $0x0f, %al
+ add $'0', %al
+ cmp $'9', %al
+ jle 9f
+ add $39, %al
+9:
+ __CONSOLE_INLINE_TX_AL
+
+ mov %ebx, %eax
+ shr $20, %eax
+ and $0x0f, %al
+ add $'0', %al
+ cmp $'9', %al
+ jle 9f
+ add $39, %al
+9:
+ __CONSOLE_INLINE_TX_AL
+
+ mov %ebx, %eax
+ shr $16, %eax
+ and $0x0f, %al
+ add $'0', %al
+ cmp $'9', %al
+ jle 9f
+ add $39, %al
+9:
+ __CONSOLE_INLINE_TX_AL
+
+ mov %ebx, %eax
+ shr $12, %eax
+ and $0x0f, %al
+ add $'0', %al
+ cmp $'9', %al
+ jle 9f
+ add $39, %al
+9:
+ __CONSOLE_INLINE_TX_AL
+
+ mov %ebx, %eax
+ shr $8, %eax
+ and $0x0f, %al
+ add $'0', %al
+ cmp $'9', %al
+ jle 9f
+ add $39, %al
+9:
+ __CONSOLE_INLINE_TX_AL
+
+ mov %ebx, %eax
+ shr $4, %eax
+ and $0x0f, %al
+ add $'0', %al
+ cmp $'9', %al
+ jle 9f
+ add $39, %al
+9:
+ __CONSOLE_INLINE_TX_AL
+
+ mov %ebx, %eax
+ and $0x0f, %al
+ add $'0', %al
+ cmp $'9', %al
+ jle 9f
+ add $39, %al
+9:
+ __CONSOLE_INLINE_TX_AL
+ RETSP
+
+ /* Uses esp, ebx, ax, dx */
+
+console_tx_string:
+ mov (%ebx), %al
+ inc %ebx
+ cmp $0, %al
+ jne 9f
+ RETSP
+9:
+ __CONSOLE_INLINE_TX_AL
+ jmp console_tx_string
+
+console0:
+ CONSOLE_INFO_TX_STRING($console_test)
+
diff --git a/src/arch/i386/lib/cpu.c b/src/arch/i386/lib/cpu.c
new file mode 100644
index 0000000000..3e27e7acdc
--- /dev/null
+++ b/src/arch/i386/lib/cpu.c
@@ -0,0 +1,139 @@
+#include <console/console.h>
+#include <cpu/cpu.h>
+#include <mem.h>
+#include <arch/io.h>
+#include <string.h>
+#include <cpu/cpufixup.h>
+#include <smp/start_stop.h>
+#include <cpu/cpufixup.h>
+#include <cpu/p6/mtrr.h>
+#include <cpu/p6/msr.h>
+#include <cpu/p6/apic.h>
+#include <cpu/p5/cpuid.h>
+#if 0
+#include <cpu/l2_cache.h>
+#endif
+
+#if CONFIG_SMP || CONFIG_IOAPIC
+#define APIC 1
+#endif
+
+static void cache_on(struct mem_range *mem)
+{
+ post_code(0x60);
+ printk_info("Enabling cache...");
+
+
+ /* we need an #ifdef i586 here at some point ... */
+ __asm__ __volatile__("mov %cr0, %eax\n\t"
+ "and $0x9fffffff,%eax\n\t"
+ "mov %eax, %cr0\n\t");
+ /* turns out cache isn't really on until you set MTRR registers on
+ * 686 and later.
+ * NOTHING FANCY. Linux does a much better job anyway.
+ * so absolute minimum needed to get it going.
+ */
+ /* OK, linux it turns out does nothing. We have to do it ... */
+#if defined(i686)
+ // totalram here is in linux sizing, i.e. units of KB.
+ // set_mtrr is responsible for getting it into the right units!
+ setup_mtrrs(mem);
+#endif
+
+ post_code(0x6A);
+ printk_info("done.\n");
+}
+
+static void interrupts_on()
+{
+ /* this is so interrupts work. This is very limited scope --
+ * linux will do better later, we hope ...
+ */
+ /* this is the first way we learned to do it. It fails on real SMP
+ * stuff. So we have to do things differently ...
+ * see the Intel mp1.4 spec, page A-3
+ */
+
+#if defined(APIC)
+ /* Only Pentium Pro and later have those MSR stuff */
+ unsigned long low, high;
+
+ printk_info("Setting up local apic...");
+
+ /* Enable the local apic */
+ rdmsr(APIC_BASE_MSR, low, high);
+ low |= APIC_BASE_MSR_ENABLE;
+ low &= ~APIC_BASE_MSR_ADDR_MASK;
+ low |= APIC_DEFAULT_BASE;
+ wrmsr(APIC_BASE_MSR, low, high);
+
+
+ /* Put the local apic in virtual wire mode */
+ apic_write_around(APIC_SPIV,
+ (apic_read_around(APIC_SPIV) & ~(APIC_VECTOR_MASK))
+ | APIC_SPIV_ENABLE);
+ apic_write_around(APIC_LVT0,
+ (apic_read_around(APIC_LVT0) &
+ ~(APIC_LVT_MASKED | APIC_LVT_LEVEL_TRIGGER |
+ APIC_LVT_REMOTE_IRR | APIC_INPUT_POLARITY |
+ APIC_SEND_PENDING |APIC_LVT_RESERVED_1 |
+ APIC_DELIVERY_MODE_MASK))
+ | (APIC_LVT_REMOTE_IRR |APIC_SEND_PENDING |
+ APIC_DELIVERY_MODE_EXTINT)
+ );
+ apic_write_around(APIC_LVT1,
+ (apic_read_around(APIC_LVT1) &
+ ~(APIC_LVT_MASKED | APIC_LVT_LEVEL_TRIGGER |
+ APIC_LVT_REMOTE_IRR | APIC_INPUT_POLARITY |
+ APIC_SEND_PENDING |APIC_LVT_RESERVED_1 |
+ APIC_DELIVERY_MODE_MASK))
+ | (APIC_LVT_REMOTE_IRR |APIC_SEND_PENDING |
+ APIC_DELIVERY_MODE_NMI)
+ );
+#else /* APIC */
+#ifdef i686
+ /* Only Pentium Pro and later have those MSR stuff */
+ unsigned long low, high;
+
+ printk_info("Disabling local apic...");
+
+ rdmsr(APIC_BASE_MSR, low, high);
+ low &= ~APIC_BASE_MSR_ENABLE;
+ wrmsr(APIC_BASE_MSR, low, high);
+#endif /* i686 */
+#endif /* APIC */
+ printk_info("done.\n");
+ post_code(0x9b);
+}
+
+unsigned long cpu_initialize(struct mem_range *mem)
+{
+ /* Because we busy wait at the printk spinlock.
+ * It is important to keep the number of printed messages
+ * from secondary cpus to a minimum, when debugging is
+ * disabled.
+ */
+ unsigned long processor_id = this_processors_id();
+ printk_notice("Initializing CPU #%d\n", processor_id);
+
+ /* some cpus need a fixup done. This is the hook for doing that. */
+ cpufixup(mem);
+
+ /* Turn on caching if we haven't already */
+ cache_on(mem);
+
+ display_cpuid();
+ mtrr_check();
+
+#if 0
+ /* now that everything is really up, enable the l2 cache if desired.
+ * The enable can wait until this point, because linuxbios and it's
+ * data areas are tiny, easily fitting into the L1 cache.
+ */
+ configure_l2_cache();
+#endif
+ interrupts_on();
+ printk_info("CPU #%d Initialized\n", processor_id);
+ return processor_id;
+}
+
diff --git a/src/arch/i386/lib/cpu_reset.inc b/src/arch/i386/lib/cpu_reset.inc
new file mode 100644
index 0000000000..c7c05e2198
--- /dev/null
+++ b/src/arch/i386/lib/cpu_reset.inc
@@ -0,0 +1,9 @@
+jmp cpu_reset_out
+
+__cpu_reset:
+ movl $0xffffffff, %ebp
+ jmp __main
+
+cpu_reset_out:
+
+
diff --git a/src/arch/i386/lib/failover.lds b/src/arch/i386/lib/failover.lds
new file mode 100644
index 0000000000..c9cf7298f8
--- /dev/null
+++ b/src/arch/i386/lib/failover.lds
@@ -0,0 +1 @@
+ __normal_image = (ZKERNEL_START & 0xfffffff0) - 8;
diff --git a/src/arch/i386/lib/id.inc b/src/arch/i386/lib/id.inc
new file mode 100644
index 0000000000..f28e23a2e8
--- /dev/null
+++ b/src/arch/i386/lib/id.inc
@@ -0,0 +1,21 @@
+ .section ".id", "a", @progbits
+
+#define __STR(X) #X
+#define STR(X) __STR(X)
+
+ .globl __id_start
+__id_start:
+vendor:
+ .asciz STR(MAINBOARD_VENDOR)
+part:
+ .asciz STR(MAINBOARD_PART_NUMBER)
+.long __id_end + 0x10 - vendor /* Reverse offset to the vendor id */
+.long __id_end + 0x10 - part /* Reverse offset to the part number */
+.long PAYLOAD_SIZE + ROM_IMAGE_SIZE /* Size of this romimage */
+ .globl __id_end
+
+#undef __STR
+#undef STR
+
+__id_end:
+.previous
diff --git a/src/arch/i386/lib/id.lds b/src/arch/i386/lib/id.lds
new file mode 100644
index 0000000000..ccdf7008f7
--- /dev/null
+++ b/src/arch/i386/lib/id.lds
@@ -0,0 +1,6 @@
+SECTIONS {
+ . = (_ROMBASE + ROM_IMAGE_SIZE - 0x10) - (__id_end - __id_start);
+ .id (.): {
+ *(.id)
+ }
+}
diff --git a/src/arch/i386/lib/noop_failover.inc b/src/arch/i386/lib/noop_failover.inc
new file mode 100644
index 0000000000..70c10b0d3e
--- /dev/null
+++ b/src/arch/i386/lib/noop_failover.inc
@@ -0,0 +1,9 @@
+/* Step 1: Test for cpu reset
+ * That is, did I just boot or is this a later boot since power on.
+ * The result of this test in %al
+ * %al == 1 -- We are rebooting
+ * %al == 0 -- This is the initial boot
+ *
+ */
+ testb %al, %al
+ jnz __cpu_reset
diff --git a/src/arch/i386/lib/pci_ops.c b/src/arch/i386/lib/pci_ops.c
new file mode 100644
index 0000000000..80921bf9da
--- /dev/null
+++ b/src/arch/i386/lib/pci_ops.c
@@ -0,0 +1,281 @@
+#include <console/console.h>
+#include <arch/io.h>
+#include <arch/pciconf.h>
+#include <pci.h>
+#include <pci_ids.h>
+#include <pci_ops.h>
+
+static const struct pci_ops *conf;
+struct pci_ops {
+ int (*read_byte) (uint8_t bus, int devfn, int where, uint8_t * val);
+ int (*read_word) (uint8_t bus, int devfn, int where, uint16_t * val);
+ int (*read_dword) (uint8_t bus, int devfn, int where, uint32_t * val);
+ int (*write_byte) (uint8_t bus, int devfn, int where, uint8_t val);
+ int (*write_word) (uint8_t bus, int devfn, int where, uint16_t val);
+ int (*write_dword) (uint8_t bus, int devfn, int where, uint32_t val);
+};
+
+/*
+ * Direct access to PCI hardware...
+ */
+
+
+/*
+ * Functions for accessing PCI configuration space with type 1 accesses
+ */
+
+#define CONFIG_CMD(bus,devfn, where) (0x80000000 | (bus << 16) | (devfn << 8) | (where & ~3))
+
+static int pci_conf1_read_config_byte(unsigned char bus, int devfn, int where, uint8_t * value)
+{
+ outl(CONFIG_CMD(bus, devfn, where), 0xCF8);
+ *value = inb(0xCFC + (where & 3));
+ return 0;
+}
+
+static int pci_conf1_read_config_word(unsigned char bus, int devfn, int where, uint16_t * value)
+{
+ outl(CONFIG_CMD(bus, devfn, where), 0xCF8);
+ *value = inw(0xCFC + (where & 2));
+ return 0;
+}
+
+static int pci_conf1_read_config_dword(unsigned char bus, int devfn, int where, uint32_t * value)
+{
+ outl(CONFIG_CMD(bus, devfn, where), 0xCF8);
+ *value = inl(0xCFC);
+ return 0;
+}
+
+static int pci_conf1_write_config_byte(unsigned char bus, int devfn, int where, uint8_t value)
+{
+ outl(CONFIG_CMD(bus, devfn, where), 0xCF8);
+ outb(value, 0xCFC + (where & 3));
+ return 0;
+}
+
+static int pci_conf1_write_config_word(unsigned char bus, int devfn, int where, uint16_t value)
+{
+ outl(CONFIG_CMD(bus, devfn, where), 0xCF8);
+ outw(value, 0xCFC + (where & 2));
+ return 0;
+}
+
+static int pci_conf1_write_config_dword(unsigned char bus, int devfn, int where, uint32_t value)
+{
+ outl(CONFIG_CMD(bus, devfn, where), 0xCF8);
+ outl(value, 0xCFC);
+ return 0;
+}
+
+#undef CONFIG_CMD
+
+static const struct pci_ops pci_direct_conf1 =
+{
+ pci_conf1_read_config_byte,
+ pci_conf1_read_config_word,
+ pci_conf1_read_config_dword,
+ pci_conf1_write_config_byte,
+ pci_conf1_write_config_word,
+ pci_conf1_write_config_dword
+};
+
+/*
+ * Functions for accessing PCI configuration space with type 2 accesses
+ */
+
+#define IOADDR(devfn, where) ((0xC000 | ((devfn & 0x78) << 5)) + where)
+#define FUNC(devfn) (((devfn & 7) << 1) | 0xf0)
+#define SET(bus,devfn) if (devfn & 0x80) return -1;outb(FUNC(devfn), 0xCF8); outb(bus, 0xCFA);
+
+static int pci_conf2_read_config_byte(unsigned char bus, int devfn, int where, uint8_t * value)
+{
+ SET(bus, devfn);
+ *value = inb(IOADDR(devfn, where));
+ outb(0, 0xCF8);
+ return 0;
+}
+
+static int pci_conf2_read_config_word(unsigned char bus, int devfn, int where, uint16_t * value)
+{
+ SET(bus, devfn);
+ *value = inw(IOADDR(devfn, where));
+ outb(0, 0xCF8);
+ return 0;
+}
+
+static int pci_conf2_read_config_dword(unsigned char bus, int devfn, int where, uint32_t * value)
+{
+ SET(bus, devfn);
+ *value = inl(IOADDR(devfn, where));
+ outb(0, 0xCF8);
+ return 0;
+}
+
+static int pci_conf2_write_config_byte(unsigned char bus, int devfn, int where, uint8_t value)
+{
+ SET(bus, devfn);
+ outb(value, IOADDR(devfn, where));
+ outb(0, 0xCF8);
+ return 0;
+}
+
+static int pci_conf2_write_config_word(unsigned char bus, int devfn, int where, uint16_t value)
+{
+ SET(bus, devfn);
+ outw(value, IOADDR(devfn, where));
+ outb(0, 0xCF8);
+ return 0;
+}
+
+static int pci_conf2_write_config_dword(unsigned char bus, int devfn, int where, uint32_t value)
+{
+ SET(bus, devfn);
+ outl(value, IOADDR(devfn, where));
+ outb(0, 0xCF8);
+ return 0;
+}
+
+#undef SET
+#undef IOADDR
+#undef FUNC
+
+static const struct pci_ops pci_direct_conf2 =
+{
+ pci_conf2_read_config_byte,
+ pci_conf2_read_config_word,
+ pci_conf2_read_config_dword,
+ pci_conf2_write_config_byte,
+ pci_conf2_write_config_word,
+ pci_conf2_write_config_dword
+};
+
+/*
+ * Before we decide to use direct hardware access mechanisms, we try to do some
+ * trivial checks to ensure it at least _seems_ to be working -- we just test
+ * whether bus 00 contains a host bridge (this is similar to checking
+ * techniques used in XFree86, but ours should be more reliable since we
+ * attempt to make use of direct access hints provided by the PCI BIOS).
+ *
+ * This should be close to trivial, but it isn't, because there are buggy
+ * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID.
+ */
+static int pci_sanity_check(const struct pci_ops *o)
+{
+ uint16_t x;
+ uint8_t bus;
+ int devfn;
+#define PCI_CLASS_BRIDGE_HOST 0x0600
+#define PCI_CLASS_DISPLAY_VGA 0x0300
+#define PCI_VENDOR_ID_COMPAQ 0x0e11
+#define PCI_VENDOR_ID_INTEL 0x8086
+#define PCI_VENDOR_ID_MOTOROLA 0x1057
+
+ for (bus = 0, devfn = 0; devfn < 0x100; devfn++)
+ if ((!o->read_word(bus, devfn, PCI_CLASS_DEVICE, &x) &&
+ (x == PCI_CLASS_BRIDGE_HOST || x == PCI_CLASS_DISPLAY_VGA)) ||
+ (!o->read_word(bus, devfn, PCI_VENDOR_ID, &x) &&
+ (x == PCI_VENDOR_ID_INTEL || x == PCI_VENDOR_ID_COMPAQ || x == PCI_VENDOR_ID_MOTOROLA)))
+ return 1;
+ printk_err("PCI: Sanity check failed\n");
+ return 0;
+}
+
+static const struct pci_ops *pci_check_direct(void)
+{
+ unsigned int tmp;
+
+ /*
+ * Check if configuration type 1 works.
+ */
+ {
+ outb(0x01, 0xCFB);
+ tmp = inl(0xCF8);
+ outl(0x80000000, 0xCF8);
+ if (inl(0xCF8) == 0x80000000 &&
+ pci_sanity_check(&pci_direct_conf1)) {
+ outl(tmp, 0xCF8);
+ printk_debug("PCI: Using configuration type 1\n");
+ return &pci_direct_conf1;
+ }
+ outl(tmp, 0xCF8);
+ }
+
+ /*
+ * Check if configuration type 2 works.
+ */
+ {
+ outb(0x00, 0xCFB);
+ outb(0x00, 0xCF8);
+ outb(0x00, 0xCFA);
+ if (inb(0xCF8) == 0x00 && inb(0xCFA) == 0x00 &&
+ pci_sanity_check(&pci_direct_conf2)) {
+ printk_debug("PCI: Using configuration type 2\n");
+ return &pci_direct_conf2;
+ }
+ }
+
+ printk_debug("pci_check_direct failed\n");
+
+ return 0;
+}
+
+int pci_read_config_byte(struct device *dev, uint8_t where, uint8_t * val)
+{
+ int res;
+ res = conf->read_byte(dev->bus->secondary, dev->devfn, where, val);
+ printk_spew("Read config byte bus %d,devfn 0x%x,reg 0x%x,val 0x%x,res 0x%x\n",
+ dev->bus->secondary, dev->devfn, where, *val, res);
+ return res;
+
+
+}
+
+int pci_read_config_word(struct device *dev, uint8_t where, uint16_t * val)
+{
+ int res;
+ res = conf->read_word(dev->bus->secondary, dev->devfn, where, val);
+ printk_spew( "Read config word bus %d,devfn 0x%x,reg 0x%x,val 0x%x,res 0x%x\n",
+ dev->bus->secondary, dev->devfn, where, *val, res);
+ return res;
+}
+
+int pci_read_config_dword(struct device *dev, uint8_t where, uint32_t * val)
+{
+ int res;
+ res = conf->read_dword(dev->bus->secondary, dev->devfn, where, val);
+ printk_spew( "Read config dword bus %d,devfn 0x%x,reg 0x%x,val 0x%x,res 0x%x\n",
+ dev->bus->secondary, dev->devfn, where, *val, res);
+ return res;
+}
+
+int pci_write_config_byte(struct device *dev, uint8_t where, uint8_t val)
+{
+ printk_spew( "Write config byte bus %d, devfn 0x%x, reg 0x%x, val 0x%x\n",
+ dev->bus->secondary, dev->devfn, where, val);
+ return conf->write_byte(dev->bus->secondary, dev->devfn, where, val);
+}
+
+int pci_write_config_word(struct device *dev, uint8_t where, uint16_t val)
+{
+ printk_spew( "Write config word bus %d, devfn 0x%x, reg 0x%x, val 0x%x\n",
+ dev->bus->secondary, dev->devfn, where, val);
+ return conf->write_word(dev->bus->secondary, dev->devfn, where, val);
+}
+
+int pci_write_config_dword(struct device *dev, uint8_t where, uint32_t val)
+{
+ printk_spew( "Write config dword bus %d, devfn 0x%x, reg 0x%x, val 0x%x\n",
+ dev->bus->secondary, dev->devfn, where, val);
+ return conf->write_dword(dev->bus->secondary, dev->devfn, where, val);
+}
+
+/** Set the method to be used for PCI, type I or type II
+ */
+void pci_set_method(void)
+{
+ conf = &pci_direct_conf1;
+ conf = pci_check_direct();
+}
+
+
diff --git a/src/arch/i386/smp/mpspec.c b/src/arch/i386/smp/mpspec.c
new file mode 100644
index 0000000000..3bb5fa1985
--- /dev/null
+++ b/src/arch/i386/smp/mpspec.c
@@ -0,0 +1,245 @@
+#include <console/console.h>
+#include <cpu/cpu.h>
+#include <smp/start_stop.h>
+#include <arch/smp/mpspec.h>
+#include <string.h>
+#include <cpu/p5/cpuid.h>
+#include <cpu/p6/apic.h>
+
+unsigned char smp_compute_checksum(void *v, int len)
+{
+ unsigned char *bytes;
+ unsigned char checksum;
+ int i;
+ bytes = v;
+ checksum = 0;
+ for(i = 0; i < len; i++) {
+ checksum -= bytes[i];
+ }
+ return checksum;
+}
+
+void *smp_write_floating_table(unsigned long addr)
+{
+ struct intel_mp_floating *mf;
+ void *v;
+
+ /* 16 byte align the table address */
+ addr += 15;
+ addr &= ~15;
+ v = (void *)addr;
+
+ mf = v;
+ mf->mpf_signature[0] = '_';
+ mf->mpf_signature[1] = 'M';
+ mf->mpf_signature[2] = 'P';
+ mf->mpf_signature[3] = '_';
+ mf->mpf_physptr = (unsigned long)(((char *)v) + SMP_FLOATING_TABLE_LEN);
+ mf->mpf_length = 1;
+ mf->mpf_specification = 4;
+ mf->mpf_checksum = 0;
+ mf->mpf_feature1 = 0;
+ mf->mpf_feature2 = 0;
+ mf->mpf_feature3 = 0;
+ mf->mpf_feature4 = 0;
+ mf->mpf_feature5 = 0;
+ mf->mpf_checksum = smp_compute_checksum(mf, mf->mpf_length*16);
+ return v;
+}
+
+void *smp_next_mpc_entry(struct mp_config_table *mc)
+{
+ void *v;
+ v = (void *)(((char *)mc) + mc->mpc_length);
+ return v;
+}
+static void smp_add_mpc_entry(struct mp_config_table *mc, unsigned length)
+{
+ mc->mpc_length += length;
+ mc->mpc_entry_count++;
+}
+
+void *smp_next_mpe_entry(struct mp_config_table *mc)
+{
+ void *v;
+ v = (void *)(((char *)mc) + mc->mpc_length + mc->mpe_length);
+ return v;
+}
+static void smp_add_mpe_entry(struct mp_config_table *mc, mpe_t mpe)
+{
+ mc->mpe_length += mpe->mpe_length;
+}
+
+void smp_write_processor(struct mp_config_table *mc,
+ unsigned char apicid, unsigned char apicver,
+ unsigned char cpuflag, unsigned int cpufeature,
+ unsigned int featureflag)
+{
+ struct mpc_config_processor *mpc;
+ mpc = smp_next_mpc_entry(mc);
+ memset(mpc, '\0', sizeof(*mpc));
+ mpc->mpc_type = MP_PROCESSOR;
+ mpc->mpc_apicid = apicid;
+ mpc->mpc_apicver = apicver;
+ mpc->mpc_cpuflag = cpuflag;
+ mpc->mpc_cpufeature = cpufeature;
+ mpc->mpc_featureflag = featureflag;
+ smp_add_mpc_entry(mc, sizeof(*mpc));
+}
+
+/* If we assume a symmetric processor configuration we can
+ * get all of the information we need to write the processor
+ * entry from the bootstrap processor.
+ * Plus I don't think linux really even cares.
+ * Having the proper apicid's in the table so the non-bootstrap
+ * processors can be woken up should be enough.
+ */
+void smp_write_processors(struct mp_config_table *mc,
+ unsigned long *processor_map)
+{
+ int i;
+ int processor_id;
+ unsigned apic_version;
+ unsigned cpu_features;
+ unsigned cpu_feature_flags;
+ int eax, ebx, ecx, edx;
+ processor_id = this_processors_id();
+ apic_version = apic_read(APIC_LVR) & 0xff;
+ cpuid(1, &eax, &ebx, &ecx, &edx);
+ cpu_features = eax;
+ cpu_feature_flags = edx;
+ for(i = 0; i < MAX_CPUS; i++) {
+ unsigned long cpu_apicid = initial_apicid[i];
+ unsigned long cpu_flag;
+ if(initial_apicid[i]==-1)
+ continue;
+ cpu_flag = MPC_CPU_ENABLED
+ if (processor_map[i] & CPU_BOOTPROCESSOR) {
+ cpu_flag |= MPC_CPU_BOOTPROCESSOR;
+ }
+ smp_write_processor(mc, cpu_apicid, apic_version,
+ cpu_flag, cpu_features, cpu_feature_flags
+ );
+
+ }
+}
+
+void smp_write_bus(struct mp_config_table *mc,
+ unsigned char id, unsigned char *bustype)
+{
+ struct mpc_config_bus *mpc;
+ mpc = smp_next_mpc_entry(mc);
+ memset(mpc, '\0', sizeof(*mpc));
+ mpc->mpc_type = MP_BUS;
+ mpc->mpc_busid = id;
+ memcpy(mpc->mpc_bustype, bustype, sizeof(mpc->mpc_bustype));
+ smp_add_mpc_entry(mc, sizeof(*mpc));
+}
+
+void smp_write_ioapic(struct mp_config_table *mc,
+ unsigned char id, unsigned char ver,
+ unsigned long apicaddr)
+{
+ struct mpc_config_ioapic *mpc;
+ mpc = smp_next_mpc_entry(mc);
+ memset(mpc, '\0', sizeof(*mpc));
+ mpc->mpc_type = MP_IOAPIC;
+ mpc->mpc_apicid = id;
+ mpc->mpc_apicver = ver;
+ mpc->mpc_flags = MPC_APIC_USABLE;
+ mpc->mpc_apicaddr = apicaddr;
+ smp_add_mpc_entry(mc, sizeof(*mpc));
+}
+
+void smp_write_intsrc(struct mp_config_table *mc,
+ unsigned char irqtype, unsigned short irqflag,
+ unsigned char srcbus, unsigned char srcbusirq,
+ unsigned char dstapic, unsigned char dstirq)
+{
+ struct mpc_config_intsrc *mpc;
+ mpc = smp_next_mpc_entry(mc);
+ memset(mpc, '\0', sizeof(*mpc));
+ mpc->mpc_type = MP_INTSRC;
+ mpc->mpc_irqtype = irqtype;
+ mpc->mpc_irqflag = irqflag;
+ mpc->mpc_srcbus = srcbus;
+ mpc->mpc_srcbusirq = srcbusirq;
+ mpc->mpc_dstapic = dstapic;
+ mpc->mpc_dstirq = dstirq;
+ smp_add_mpc_entry(mc, sizeof(*mpc));
+#if CONFIG_DEBUG_MPTABLE == 1
+ printk_info("add intsrc srcbus 0x%x srcbusirq 0x%x, dstapic 0x%x, dstirq 0x%x\n",
+ srcbus, srcbusirq, dstapic, dstirq);
+ hexdump(__FUNCTION__, mpc, sizeof(*mpc));
+#endif
+}
+
+
+void smp_write_lintsrc(struct mp_config_table *mc,
+ unsigned char irqtype, unsigned short irqflag,
+ unsigned char srcbusid, unsigned char srcbusirq,
+ unsigned char destapic, unsigned char destapiclint)
+{
+ struct mpc_config_lintsrc *mpc;
+ mpc = smp_next_mpc_entry(mc);
+ memset(mpc, '\0', sizeof(*mpc));
+ mpc->mpc_type = MP_LINTSRC;
+ mpc->mpc_irqtype = irqtype;
+ mpc->mpc_irqflag = irqflag;
+ mpc->mpc_srcbusid = srcbusid;
+ mpc->mpc_srcbusirq = srcbusirq;
+ mpc->mpc_destapic = destapic;
+ mpc->mpc_destapiclint = destapiclint;
+ smp_add_mpc_entry(mc, sizeof(*mpc));
+}
+
+void smp_write_address_space(struct mp_config_table *mc,
+ unsigned char busid, unsigned char address_type,
+ unsigned int address_base_low, unsigned int address_base_high,
+ unsigned int address_length_low, unsigned int address_length_high)
+{
+ struct mp_exten_system_address_space *mpe;
+ mpe = smp_next_mpe_entry(mc);
+ memset(mpe, '\0', sizeof(*mpe));
+ mpe->mpe_type = MPE_SYSTEM_ADDRESS_SPACE;
+ mpe->mpe_length = sizeof(*mpe);
+ mpe->mpe_busid = busid;
+ mpe->mpe_address_type = address_type;
+ mpe->mpe_address_base_low = address_base_low;
+ mpe->mpe_address_base_high = address_base_high;
+ mpe->mpe_address_length_low = address_length_low;
+ mpe->mpe_address_length_high = address_length_high;
+ smp_add_mpe_entry(mc, (mpe_t)mpe);
+}
+
+
+void smp_write_bus_hierarchy(struct mp_config_table *mc,
+ unsigned char busid, unsigned char bus_info,
+ unsigned char parent_busid)
+{
+ struct mp_exten_bus_hierarchy *mpe;
+ mpe = smp_next_mpe_entry(mc);
+ memset(mpe, '\0', sizeof(*mpe));
+ mpe->mpe_type = MPE_BUS_HIERARCHY;
+ mpe->mpe_length = sizeof(*mpe);
+ mpe->mpe_busid = busid;
+ mpe->mpe_bus_info = bus_info;
+ mpe->mpe_parent_busid = parent_busid;
+ smp_add_mpe_entry(mc, (mpe_t)mpe);
+}
+
+void smp_write_compatibility_address_space(struct mp_config_table *mc,
+ unsigned char busid, unsigned char address_modifier,
+ unsigned int range_list)
+{
+ struct mp_exten_compatibility_address_space *mpe;
+ mpe = smp_next_mpe_entry(mc);
+ memset(mpe, '\0', sizeof(*mpe));
+ mpe->mpe_type = MPE_COMPATIBILITY_ADDRESS_SPACE;
+ mpe->mpe_length = sizeof(*mpe);
+ mpe->mpe_busid = busid;
+ mpe->mpe_address_modifier = address_modifier;
+ mpe->mpe_range_list = range_list;
+ smp_add_mpe_entry(mc, (mpe_t)mpe);
+}
+