aboutsummaryrefslogtreecommitdiffstats
path: root/src/arch/x86/lib
diff options
context:
space:
mode:
authorStefan Reinauer <stepan@coreboot.org>2010-12-11 20:33:41 +0000
committerStefan Reinauer <stepan@openbios.org>2010-12-11 20:33:41 +0000
commit8677a23d5b053d550f70246de9c7dc8fd4e2fbf9 (patch)
treed9a7c6042de85d623739e2679ba90c66aad2797f /src/arch/x86/lib
parent198cb96387c457affa01696405ffaa4531e8e361 (diff)
downloadcoreboot-8677a23d5b053d550f70246de9c7dc8fd4e2fbf9.tar.gz
coreboot-8677a23d5b053d550f70246de9c7dc8fd4e2fbf9.tar.xz
coreboot-8677a23d5b053d550f70246de9c7dc8fd4e2fbf9.zip
After this has been brought up many times before, rename src/arch/i386 to
src/arch/x86. Signed-off-by: Stefan Reinauer <stepan@coreboot.org> Acked-by: Patrick Georgi <patrick@georgi-clan.de> git-svn-id: svn://svn.coreboot.org/coreboot/trunk@6161 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'src/arch/x86/lib')
-rw-r--r--src/arch/x86/lib/Makefile.inc13
-rw-r--r--src/arch/x86/lib/c_start.S317
-rw-r--r--src/arch/x86/lib/cbfs_and_run.c55
-rw-r--r--src/arch/x86/lib/cpu.c268
-rw-r--r--src/arch/x86/lib/exception.c489
-rw-r--r--src/arch/x86/lib/id.inc15
-rw-r--r--src/arch/x86/lib/id.lds6
-rw-r--r--src/arch/x86/lib/ioapic.c139
-rw-r--r--src/arch/x86/lib/pci_ops_auto.c100
-rw-r--r--src/arch/x86/lib/pci_ops_conf1.c63
-rw-r--r--src/arch/x86/lib/pci_ops_conf2.c76
-rw-r--r--src/arch/x86/lib/pci_ops_mmconf.c64
-rw-r--r--src/arch/x86/lib/printk_init.c57
-rw-r--r--src/arch/x86/lib/stages.c28
-rw-r--r--src/arch/x86/lib/walkcbfs.S126
15 files changed, 1816 insertions, 0 deletions
diff --git a/src/arch/x86/lib/Makefile.inc b/src/arch/x86/lib/Makefile.inc
new file mode 100644
index 000000000..43ac4693f
--- /dev/null
+++ b/src/arch/x86/lib/Makefile.inc
@@ -0,0 +1,13 @@
+ramstage-y += c_start.S
+ramstage-y += cpu.c
+ramstage-y += pci_ops_conf1.c
+ramstage-y += pci_ops_conf2.c
+ramstage-y += pci_ops_mmconf.c
+ramstage-y += pci_ops_auto.c
+ramstage-y += exception.c
+ramstage-$(CONFIG_IOAPIC) += ioapic.c
+
+romstage-y += printk_init.c
+romstage-y += cbfs_and_run.c
+
+$(obj)/arch/x86/lib/console.ramstage.o :: $(obj)/build.h
diff --git a/src/arch/x86/lib/c_start.S b/src/arch/x86/lib/c_start.S
new file mode 100644
index 000000000..94ce4a70c
--- /dev/null
+++ b/src/arch/x86/lib/c_start.S
@@ -0,0 +1,317 @@
+#include <cpu/x86/post_code.h>
+
+ .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
+
+ post_code(0x13) /* post 13 */
+
+ /** clear stack */
+ cld
+ leal _stack, %edi
+ movl $_estack, %ecx
+ subl %edi, %ecx
+ shrl $2, %ecx /* it is 32 bit aligned, right? */
+ xorl %eax, %eax
+ rep
+ stosl
+
+ /** clear bss */
+ leal _bss, %edi
+ movl $_ebss, %ecx
+ subl %edi, %ecx
+ jz .Lnobss
+ shrl $2, %ecx /* it is 32 bit aligned, right? */
+ xorl %eax, %eax
+ rep
+ stosl
+.Lnobss:
+
+ /* set new stack */
+ movl $_estack, %esp
+
+ /* Push the cpu index and struct cpu */
+ pushl $0
+ pushl $0
+
+ /* push the boot_complete flag */
+ pushl %ebp
+
+ /* Save the stack location */
+ movl %esp, %ebp
+
+ /* Initialize the Interrupt Descriptor table */
+ leal _idt, %edi
+ leal vec0, %ebx
+ movl $(0x10 << 16), %eax /* cs selector */
+
+1: movw %bx, %ax
+ movl %ebx, %edx
+ movw $0x8E00, %dx /* Interrupt gate - dpl=0, present */
+ movl %eax, 0(%edi)
+ movl %edx, 4(%edi)
+ addl $6, %ebx
+ addl $8, %edi
+ cmpl $_idt_end, %edi
+ jne 1b
+
+ /* Load the Interrupt descriptor table */
+ lidt idtarg
+
+ /*
+ * 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.
+ */
+ post_code(0xfe) /* post fe */
+
+ /* Restore the stack location */
+ movl %ebp, %esp
+
+ /* The boot_complete flag has already been pushed */
+ call hardwaremain
+ /* NOTREACHED */
+.Lhlt:
+ post_code(0xee) /* post ee */
+ hlt
+ jmp .Lhlt
+
+vec0:
+ pushl $0 /* error code */
+ pushl $0 /* vector */
+ jmp int_hand
+vec1:
+ pushl $0 /* error code */
+ pushl $1 /* vector */
+ jmp int_hand
+
+vec2:
+ pushl $0 /* error code */
+ pushl $2 /* vector */
+ jmp int_hand
+
+vec3:
+ pushl $0 /* error code */
+ pushl $3 /* vector */
+ jmp int_hand
+
+vec4:
+ pushl $0 /* error code */
+ pushl $4 /* vector */
+ jmp int_hand
+
+vec5:
+ pushl $0 /* error code */
+ pushl $5 /* vector */
+ jmp int_hand
+
+vec6:
+ pushl $0 /* error code */
+ pushl $6 /* vector */
+ jmp int_hand
+
+vec7:
+ pushl $0 /* error code */
+ pushl $7 /* vector */
+ jmp int_hand
+
+vec8:
+ /* error code */
+ pushl $8 /* vector */
+ jmp int_hand
+ .word 0x9090
+
+vec9:
+ pushl $0 /* error code */
+ pushl $9 /* vector */
+ jmp int_hand
+
+vec10:
+ /* error code */
+ pushl $10 /* vector */
+ jmp int_hand
+ .word 0x9090
+
+vec11:
+ /* error code */
+ pushl $11 /* vector */
+ jmp int_hand
+ .word 0x9090
+
+vec12:
+ /* error code */
+ pushl $12 /* vector */
+ jmp int_hand
+ .word 0x9090
+
+vec13:
+ /* error code */
+ pushl $13 /* vector */
+ jmp int_hand
+ .word 0x9090
+
+vec14:
+ /* error code */
+ pushl $14 /* vector */
+ jmp int_hand
+ .word 0x9090
+
+vec15:
+ pushl $0 /* error code */
+ pushl $15 /* vector */
+ jmp int_hand
+
+vec16:
+ pushl $0 /* error code */
+ pushl $16 /* vector */
+ jmp int_hand
+
+vec17:
+ /* error code */
+ pushl $17 /* vector */
+ jmp int_hand
+ .word 0x9090
+
+vec18:
+ pushl $0 /* error code */
+ pushl $18 /* vector */
+ jmp int_hand
+
+vec19:
+ pushl $0 /* error code */
+ pushl $19 /* vector */
+ jmp int_hand
+
+int_hand:
+ /* At this point on the stack there is:
+ * 0(%esp) vector
+ * 4(%esp) error code
+ * 8(%esp) eip
+ * 12(%esp) cs
+ * 16(%esp) eflags
+ */
+ pushl %edi
+ pushl %esi
+ pushl %ebp
+ /* Original stack pointer */
+ leal 32(%esp), %ebp
+ pushl %ebp
+ pushl %ebx
+ pushl %edx
+ pushl %ecx
+ pushl %eax
+
+ pushl %esp /* Pointer to structure on the stack */
+ call x86_exception
+ pop %eax /* Drop the pointer */
+
+ popl %eax
+ popl %ecx
+ popl %edx
+ popl %ebx
+ popl %ebp /* Ignore saved %esp value */
+ popl %ebp
+ popl %esi
+ popl %edi
+
+ addl $8, %esp /* pop of the vector and error code */
+
+ iret
+
+#if CONFIG_GDB_STUB == 1
+
+ .globl gdb_stub_breakpoint
+gdb_stub_breakpoint:
+ popl %eax /* Return address */
+ pushfl
+ pushl %cs
+ pushl %eax /* Return address */
+ pushl $0 /* No error code */
+ pushl $32 /* vector 32 is user defined */
+ jmp int_hand
+
+#endif
+
+ .globl gdt, gdt_end, gdt_limit, idtarg
+
+gdt_limit = gdt_end - gdt - 1 /* compute the table limit */
+gdtaddr:
+ .word gdt_limit
+ .long gdt /* we know the offset */
+
+ .data
+
+ /* This is the gdt for GCC part of coreboot.
+ * It is different from the gdt in ROMCC/ASM part of coreboot
+ * which is defined in entry32.inc
+ *
+ * When the machine is initially started, we use a very simple
+ * gdt from rom (that in entry32.inc) which only contains those
+ * entries we need for protected mode.
+ *
+ * When we're executing code from RAM, we want to do more complex
+ * stuff, like initializing PCI option roms in real mode, or doing
+ * a resume from a suspend to ram.
+ */
+gdt:
+ /* selgdt 0, unused */
+ .word 0x0000, 0x0000 /* dummy */
+ .byte 0x00, 0x00, 0x00, 0x00
+
+ /* selgdt 8, unused */
+ .word 0x0000, 0x0000 /* dummy */
+ .byte 0x00, 0x00, 0x00, 0x00
+
+ /* selgdt 0x10, flat code segment */
+ .word 0xffff, 0x0000
+ .byte 0x00, 0x9b, 0xcf, 0x00 /* G=1 and 0x0f, So we get 4Gbytes for limit */
+
+ /* selgdt 0x18, flat data segment */
+ .word 0xffff, 0x0000
+ .byte 0x00, 0x93, 0xcf, 0x00
+
+ /* selgdt 0x20, unused */
+ .word 0x0000, 0x0000 /* dummy */
+ .byte 0x00, 0x00, 0x00, 0x00
+
+ /* The next two entries are used for executing VGA option ROMs */
+
+ /* 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
+
+ /* The next two entries are used for ACPI S3 RESUME */
+
+ /* selgdt 0x38, flat data segment 16 bit */
+ .word 0x0000, 0x0000 /* dummy */
+ .byte 0x00, 0x93, 0x8f, 0x00 /* G=1 and 0x0f, So we get 4Gbytes for limit */
+
+ /* selgdt 0x40, flat code segment 16 bit */
+ .word 0xffff, 0x0000
+ .byte 0x00, 0x9b, 0x8f, 0x00 /* G=1 and 0x0f, So we get 4Gbytes for limit */
+gdt_end:
+
+idtarg:
+ .word _idt_end - _idt - 1 /* limit */
+ .long _idt
+ .word 0
+_idt:
+ .fill 20, 8, 0 # idt is uninitialized
+_idt_end:
+
+ .previous
+.code32
diff --git a/src/arch/x86/lib/cbfs_and_run.c b/src/arch/x86/lib/cbfs_and_run.c
new file mode 100644
index 000000000..5e3d8fe92
--- /dev/null
+++ b/src/arch/x86/lib/cbfs_and_run.c
@@ -0,0 +1,55 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2008-2009 coresystems GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <console/console.h>
+#include <cbfs.h>
+#include <arch/stages.h>
+
+void cbfs_and_run_core(const char *filename, unsigned ebp)
+{
+ u8 *dst;
+
+ print_debug("Loading image.\n");
+ dst = cbfs_load_stage(filename);
+ if ((void *)dst == (void *) -1)
+ die("FATAL: Essential component is missing.\n");
+
+ print_debug("Jumping to image.\n");
+ __asm__ volatile (
+ "movl %%eax, %%ebp\n"
+ "jmp *%%edi\n"
+ :: "a"(ebp), "D"(dst)
+ );
+}
+
+void __attribute__((regparm(0))) copy_and_run(unsigned cpu_reset)
+{
+ // FIXME fix input parameters instead normalizing them here.
+ if (cpu_reset == 1) cpu_reset = -1;
+ else cpu_reset = 0;
+
+ cbfs_and_run_core(CONFIG_CBFS_PREFIX "/coreboot_ram", cpu_reset);
+}
+
+#if CONFIG_AP_CODE_IN_CAR == 1
+void __attribute__((regparm(0))) copy_and_run_ap_code_in_car(unsigned ret_addr)
+{
+ cbfs_and_run_core(CONFIG_CBFS_PREFIX "/coreboot_ap", ret_addr);
+}
+#endif
diff --git a/src/arch/x86/lib/cpu.c b/src/arch/x86/lib/cpu.c
new file mode 100644
index 000000000..3732ae296
--- /dev/null
+++ b/src/arch/x86/lib/cpu.c
@@ -0,0 +1,268 @@
+#include <console/console.h>
+#include <cpu/cpu.h>
+#include <arch/io.h>
+#include <string.h>
+#include <cpu/x86/mtrr.h>
+#include <cpu/x86/msr.h>
+#include <cpu/x86/lapic.h>
+#include <arch/cpu.h>
+#include <device/path.h>
+#include <device/device.h>
+#include <smp/spinlock.h>
+
+/* Standard macro to see if a specific flag is changeable */
+static inline int flag_is_changeable_p(uint32_t flag)
+{
+ uint32_t f1, f2;
+
+ asm(
+ "pushfl\n\t"
+ "pushfl\n\t"
+ "popl %0\n\t"
+ "movl %0,%1\n\t"
+ "xorl %2,%0\n\t"
+ "pushl %0\n\t"
+ "popfl\n\t"
+ "pushfl\n\t"
+ "popl %0\n\t"
+ "popfl\n\t"
+ : "=&r" (f1), "=&r" (f2)
+ : "ir" (flag));
+ return ((f1^f2) & flag) != 0;
+}
+
+
+/* Probe for the CPUID instruction */
+static int have_cpuid_p(void)
+{
+ return flag_is_changeable_p(X86_EFLAGS_ID);
+}
+
+/*
+ * Cyrix CPUs without cpuid or with cpuid not yet enabled can be detected
+ * by the fact that they preserve the flags across the division of 5/2.
+ * PII and PPro exhibit this behavior too, but they have cpuid available.
+ */
+
+/*
+ * Perform the Cyrix 5/2 test. A Cyrix won't change
+ * the flags, while other 486 chips will.
+ */
+static inline int test_cyrix_52div(void)
+{
+ unsigned int test;
+
+ __asm__ __volatile__(
+ "sahf\n\t" /* clear flags (%eax = 0x0005) */
+ "div %b2\n\t" /* divide 5 by 2 */
+ "lahf" /* store flags into %ah */
+ : "=a" (test)
+ : "0" (5), "q" (2)
+ : "cc");
+
+ /* AH is 0x02 on Cyrix after the divide.. */
+ return (unsigned char) (test >> 8) == 0x02;
+}
+
+/*
+ * Detect a NexGen CPU running without BIOS hypercode new enough
+ * to have CPUID. (Thanks to Herbert Oppmann)
+ */
+
+static int deep_magic_nexgen_probe(void)
+{
+ int ret;
+
+ __asm__ __volatile__ (
+ " movw $0x5555, %%ax\n"
+ " xorw %%dx,%%dx\n"
+ " movw $2, %%cx\n"
+ " divw %%cx\n"
+ " movl $0, %%eax\n"
+ " jnz 1f\n"
+ " movl $1, %%eax\n"
+ "1:\n"
+ : "=a" (ret) : : "cx", "dx" );
+ return ret;
+}
+
+/* List of cpu vendor strings along with their normalized
+ * id values.
+ */
+static struct {
+ int vendor;
+ const char *name;
+} x86_vendors[] = {
+ { X86_VENDOR_INTEL, "GenuineIntel", },
+ { X86_VENDOR_CYRIX, "CyrixInstead", },
+ { X86_VENDOR_AMD, "AuthenticAMD", },
+ { X86_VENDOR_UMC, "UMC UMC UMC ", },
+ { X86_VENDOR_NEXGEN, "NexGenDriven", },
+ { X86_VENDOR_CENTAUR, "CentaurHauls", },
+ { X86_VENDOR_RISE, "RiseRiseRise", },
+ { X86_VENDOR_TRANSMETA, "GenuineTMx86", },
+ { X86_VENDOR_TRANSMETA, "TransmetaCPU", },
+ { X86_VENDOR_NSC, "Geode by NSC", },
+ { X86_VENDOR_SIS, "SiS SiS SiS ", },
+};
+
+static const char *x86_vendor_name[] = {
+ [X86_VENDOR_INTEL] = "Intel",
+ [X86_VENDOR_CYRIX] = "Cyrix",
+ [X86_VENDOR_AMD] = "AMD",
+ [X86_VENDOR_UMC] = "UMC",
+ [X86_VENDOR_NEXGEN] = "NexGen",
+ [X86_VENDOR_CENTAUR] = "Centaur",
+ [X86_VENDOR_RISE] = "Rise",
+ [X86_VENDOR_TRANSMETA] = "Transmeta",
+ [X86_VENDOR_NSC] = "NSC",
+ [X86_VENDOR_SIS] = "SiS",
+};
+
+static const char *cpu_vendor_name(int vendor)
+{
+ const char *name;
+ name = "<invalid cpu vendor>";
+ if ((vendor < (ARRAY_SIZE(x86_vendor_name))) &&
+ (x86_vendor_name[vendor] != 0))
+ {
+ name = x86_vendor_name[vendor];
+ }
+ return name;
+}
+
+static void identify_cpu(struct device *cpu)
+{
+ char vendor_name[16];
+ int i;
+
+ vendor_name[0] = '\0'; /* Unset */
+
+ /* Find the id and vendor_name */
+ if (!have_cpuid_p()) {
+ /* Its a 486 if we can modify the AC flag */
+ if (flag_is_changeable_p(X86_EFLAGS_AC)) {
+ cpu->device = 0x00000400; /* 486 */
+ } else {
+ cpu->device = 0x00000300; /* 386 */
+ }
+ if ((cpu->device == 0x00000400) && test_cyrix_52div()) {
+ memcpy(vendor_name, "CyrixInstead", 13);
+ /* If we ever care we can enable cpuid here */
+ }
+ /* Detect NexGen with old hypercode */
+ else if (deep_magic_nexgen_probe()) {
+ memcpy(vendor_name, "NexGenDriven", 13);
+ }
+ }
+ if (have_cpuid_p()) {
+ int cpuid_level;
+ struct cpuid_result result;
+ result = cpuid(0x00000000);
+ cpuid_level = result.eax;
+ vendor_name[ 0] = (result.ebx >> 0) & 0xff;
+ vendor_name[ 1] = (result.ebx >> 8) & 0xff;
+ vendor_name[ 2] = (result.ebx >> 16) & 0xff;
+ vendor_name[ 3] = (result.ebx >> 24) & 0xff;
+ vendor_name[ 4] = (result.edx >> 0) & 0xff;
+ vendor_name[ 5] = (result.edx >> 8) & 0xff;
+ vendor_name[ 6] = (result.edx >> 16) & 0xff;
+ vendor_name[ 7] = (result.edx >> 24) & 0xff;
+ vendor_name[ 8] = (result.ecx >> 0) & 0xff;
+ vendor_name[ 9] = (result.ecx >> 8) & 0xff;
+ vendor_name[10] = (result.ecx >> 16) & 0xff;
+ vendor_name[11] = (result.ecx >> 24) & 0xff;
+ vendor_name[12] = '\0';
+
+ /* Intel-defined flags: level 0x00000001 */
+ if (cpuid_level >= 0x00000001) {
+ cpu->device = cpuid_eax(0x00000001);
+ }
+ else {
+ /* Have CPUID level 0 only unheard of */
+ cpu->device = 0x00000400;
+ }
+ }
+ cpu->vendor = X86_VENDOR_UNKNOWN;
+ for(i = 0; i < ARRAY_SIZE(x86_vendors); i++) {
+ if (memcmp(vendor_name, x86_vendors[i].name, 12) == 0) {
+ cpu->vendor = x86_vendors[i].vendor;
+ break;
+ }
+ }
+}
+
+static void set_cpu_ops(struct device *cpu)
+{
+ struct cpu_driver *driver;
+ cpu->ops = 0;
+ for (driver = cpu_drivers; driver < ecpu_drivers; driver++) {
+ struct cpu_device_id *id;
+ for(id = driver->id_table; id->vendor != X86_VENDOR_INVALID; id++) {
+ if ((cpu->vendor == id->vendor) &&
+ (cpu->device == id->device))
+ {
+ goto found;
+ }
+ }
+ }
+ return;
+ found:
+ cpu->ops = driver->ops;
+}
+
+void cpu_initialize(void)
+{
+ /* 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.
+ */
+ struct device *cpu;
+ struct cpu_info *info;
+ struct cpuinfo_x86 c;
+
+ info = cpu_info();
+
+ printk(BIOS_INFO, "Initializing CPU #%ld\n", info->index);
+
+ cpu = info->cpu;
+ if (!cpu) {
+ die("CPU: missing cpu device structure");
+ }
+
+ /* Find what type of cpu we are dealing with */
+ identify_cpu(cpu);
+ printk(BIOS_DEBUG, "CPU: vendor %s device %x\n",
+ cpu_vendor_name(cpu->vendor), cpu->device);
+
+ get_fms(&c, cpu->device);
+
+ printk(BIOS_DEBUG, "CPU: family %02x, model %02x, stepping %02x\n",
+ c.x86, c.x86_model, c.x86_mask);
+
+ /* Lookup the cpu's operations */
+ set_cpu_ops(cpu);
+
+ if(!cpu->ops) {
+ /* mask out the stepping and try again */
+ cpu->device -= c.x86_mask;
+ set_cpu_ops(cpu);
+ cpu->device += c.x86_mask;
+ if(!cpu->ops) die("Unknown cpu");
+ printk(BIOS_DEBUG, "Using generic cpu ops (good)\n");
+ }
+
+
+ /* Initialize the cpu */
+ if (cpu->ops && cpu->ops->init) {
+ cpu->enabled = 1;
+ cpu->initialized = 1;
+ cpu->ops->init(cpu);
+ }
+
+ printk(BIOS_INFO, "CPU #%ld initialized\n", info->index);
+
+ return;
+}
+
diff --git a/src/arch/x86/lib/exception.c b/src/arch/x86/lib/exception.c
new file mode 100644
index 000000000..20917b6f4
--- /dev/null
+++ b/src/arch/x86/lib/exception.c
@@ -0,0 +1,489 @@
+#include <console/console.h>
+#include <string.h>
+
+#if defined(CONFIG_GDB_STUB) && CONFIG_GDB_STUB == 1
+
+/* BUFMAX defines the maximum number of characters in inbound/outbound buffers.
+ * At least NUM_REGBYTES*2 are needed for register packets
+ */
+#define BUFMAX 400
+enum regnames {
+ EAX = 0, ECX, EDX, EBX, ESP, EBP, ESI, EDI,
+ PC /* also known as eip */,
+ PS /* also known as eflags */,
+ CS, SS, DS, ES, FS, GS,
+ NUM_REGS /* Number of registers. */
+};
+
+static uint32_t gdb_stub_registers[NUM_REGS];
+
+#define GDB_SIG0 0 /* Signal 0 */
+#define GDB_SIGHUP 1 /* Hangup */
+#define GDB_SIGINT 2 /* Interrupt */
+#define GDB_SIGQUIT 3 /* Quit */
+#define GDB_SIGILL 4 /* Illegal instruction */
+#define GDB_SIGTRAP 5 /* Trace/breakpoint trap */
+#define GDB_SIGABRT 6 /* Aborted */
+#define GDB_SIGEMT 7 /* Emulation trap */
+#define GDB_SIGFPE 8 /* Arithmetic exception */
+#define GDB_SIGKILL 9 /* Killed */
+#define GDB_SIGBUS 10 /* Bus error */
+#define GDB_SIGSEGV 11 /* Segmentation fault */
+#define GDB_SIGSYS 12 /* Bad system call */
+#define GDB_SIGPIPE 13 /* Broken pipe */
+#define GDB_SIGALRM 14 /* Alarm clock */
+#define GDB_SIGTERM 15 /* Terminated */
+#define GDB_SIGURG 16 /* Urgent I/O condition */
+#define GDB_SIGSTOP 17 /* Stopped (signal) */
+#define GDB_SIGTSTP 18 /* Stopped (user) */
+#define GDB_SIGCONT 19 /* Continued */
+#define GDB_SIGCHLD 20 /* Child status changed */
+#define GDB_SIGTTIN 21 /* Stopped (tty input) */
+#define GDB_SIGTTOU 22 /* Stopped (tty output) */
+#define GDB_SIGIO 23 /* I/O possible */
+#define GDB_SIGXCPU 24 /* CPU time limit exceeded */
+#define GDB_SIGXFSZ 25 /* File size limit exceeded */
+#define GDB_SIGVTALRM 26 /* Virtual timer expired */
+#define GDB_SIGPROF 27 /* Profiling timer expired */
+#define GDB_SIGWINCH 28 /* Window size changed */
+#define GDB_SIGLOST 29 /* Resource lost */
+#define GDB_SIGUSR1 30 /* User defined signal 1 */
+#define GDB_SUGUSR2 31 /* User defined signal 2 */
+#define GDB_SIGPWR 32 /* Power fail/restart */
+#define GDB_SIGPOLL 33 /* Pollable event occurred */
+#define GDB_SIGWIND 34 /* SIGWIND */
+#define GDB_SIGPHONE 35 /* SIGPHONE */
+#define GDB_SIGWAITING 36 /* Process's LWPs are blocked */
+#define GDB_SIGLWP 37 /* Signal LWP */
+#define GDB_SIGDANGER 38 /* Swap space dangerously low */
+#define GDB_SIGGRANT 39 /* Monitor mode granted */
+#define GDB_SIGRETRACT 40 /* Need to relinquish monitor mode */
+#define GDB_SIGMSG 41 /* Monitor mode data available */
+#define GDB_SIGSOUND 42 /* Sound completed */
+#define GDB_SIGSAK 43 /* Secure attention */
+#define GDB_SIGPRIO 44 /* SIGPRIO */
+
+#define GDB_SIG33 45 /* Real-time event 33 */
+#define GDB_SIG34 46 /* Real-time event 34 */
+#define GDB_SIG35 47 /* Real-time event 35 */
+#define GDB_SIG36 48 /* Real-time event 36 */
+#define GDB_SIG37 49 /* Real-time event 37 */
+#define GDB_SIG38 50 /* Real-time event 38 */
+#define GDB_SIG39 51 /* Real-time event 39 */
+#define GDB_SIG40 52 /* Real-time event 40 */
+#define GDB_SIG41 53 /* Real-time event 41 */
+#define GDB_SIG42 54 /* Real-time event 42 */
+#define GDB_SIG43 55 /* Real-time event 43 */
+#define GDB_SIG44 56 /* Real-time event 44 */
+#define GDB_SIG45 57 /* Real-time event 45 */
+#define GDB_SIG46 58 /* Real-time event 46 */
+#define GDB_SIG47 59 /* Real-time event 47 */
+#define GDB_SIG48 60 /* Real-time event 48 */
+#define GDB_SIG49 61 /* Real-time event 49 */
+#define GDB_SIG50 62 /* Real-time event 50 */
+#define GDB_SIG51 63 /* Real-time event 51 */
+#define GDB_SIG52 64 /* Real-time event 52 */
+#define GDB_SIG53 65 /* Real-time event 53 */
+#define GDB_SIG54 66 /* Real-time event 54 */
+#define GDB_SIG55 67 /* Real-time event 55 */
+#define GDB_SIG56 68 /* Real-time event 56 */
+#define GDB_SIG57 69 /* Real-time event 57 */
+#define GDB_SIG58 70 /* Real-time event 58 */
+#define GDB_SIG59 71 /* Real-time event 59 */
+#define GDB_SIG60 72 /* Real-time event 60 */
+#define GDB_SIG61 73 /* Real-time event 61 */
+#define GDB_SIG62 74 /* Real-time event 62 */
+#define GDB_SIG63 75 /* Real-time event 63 */
+#define GDB_SIGCANCEL 76 /* LWP internal signal */
+#define GDB_SIG32 77 /* Real-time event 32 */
+#define GDB_SIG64 78 /* Real-time event 64 */
+#define GDB_SIG65 79 /* Real-time event 65 */
+#define GDB_SIG66 80 /* Real-time event 66 */
+#define GDB_SIG67 81 /* Real-time event 67 */
+#define GDB_SIG68 82 /* Real-time event 68 */
+#define GDB_SIG69 83 /* Real-time event 69 */
+#define GDB_SIG70 84 /* Real-time event 70 */
+#define GDB_SIG71 85 /* Real-time event 71 */
+#define GDB_SIG72 86 /* Real-time event 72 */
+#define GDB_SIG73 87 /* Real-time event 73 */
+#define GDB_SIG74 88 /* Real-time event 74 */
+#define GDB_SIG75 89 /* Real-time event 75 */
+#define GDB_SIG76 90 /* Real-time event 76 */
+#define GDB_SIG77 91 /* Real-time event 77 */
+#define GDB_SIG78 92 /* Real-time event 78 */
+#define GDB_SIG79 93 /* Real-time event 79 */
+#define GDB_SIG80 94 /* Real-time event 80 */
+#define GDB_SIG81 95 /* Real-time event 81 */
+#define GDB_SIG82 96 /* Real-time event 82 */
+#define GDB_SIG83 97 /* Real-time event 83 */
+#define GDB_SIG84 98 /* Real-time event 84 */
+#define GDB_SIG85 99 /* Real-time event 85 */
+#define GDB_SIG86 100 /* Real-time event 86 */
+#define GDB_SIG87 101 /* Real-time event 87 */
+#define GDB_SIG88 102 /* Real-time event 88 */
+#define GDB_SIG89 103 /* Real-time event 89 */
+#define GDB_SIG90 104 /* Real-time event 90 */
+#define GDB_SIG91 105 /* Real-time event 91 */
+#define GDB_SIG92 106 /* Real-time event 92 */
+#define GDB_SIG93 107 /* Real-time event 93 */
+#define GDB_SIG94 108 /* Real-time event 94 */
+#define GDB_SIG95 109 /* Real-time event 95 */
+#define GDB_SIG96 110 /* Real-time event 96 */
+#define GDB_SIG97 111 /* Real-time event 97 */
+#define GDB_SIG98 112 /* Real-time event 98 */
+#define GDB_SIG99 113 /* Real-time event 99 */
+#define GDB_SIG100 114 /* Real-time event 100 */
+#define GDB_SIG101 115 /* Real-time event 101 */
+#define GDB_SIG102 116 /* Real-time event 102 */
+#define GDB_SIG103 117 /* Real-time event 103 */
+#define GDB_SIG104 118 /* Real-time event 104 */
+#define GDB_SIG105 119 /* Real-time event 105 */
+#define GDB_SIG106 120 /* Real-time event 106 */
+#define GDB_SIG107 121 /* Real-time event 107 */
+#define GDB_SIG108 122 /* Real-time event 108 */
+#define GDB_SIG109 123 /* Real-time event 109 */
+#define GDB_SIG110 124 /* Real-time event 110 */
+#define GDB_SIG111 125 /* Real-time event 111 */
+#define GDB_SIG112 126 /* Real-time event 112 */
+#define GDB_SIG113 127 /* Real-time event 113 */
+#define GDB_SIG114 128 /* Real-time event 114 */
+#define GDB_SIG115 129 /* Real-time event 115 */
+#define GDB_SIG116 130 /* Real-time event 116 */
+#define GDB_SIG117 131 /* Real-time event 117 */
+#define GDB_SIG118 132 /* Real-time event 118 */
+#define GDB_SIG119 133 /* Real-time event 119 */
+#define GDB_SIG120 134 /* Real-time event 120 */
+#define GDB_SIG121 135 /* Real-time event 121 */
+#define GDB_SIG122 136 /* Real-time event 122 */
+#define GDB_SIG123 137 /* Real-time event 123 */
+#define GDB_SIG124 138 /* Real-time event 124 */
+#define GDB_SIG125 139 /* Real-time event 125 */
+#define GDB_SIG126 140 /* Real-time event 126 */
+#define GDB_SIG127 141 /* Real-time event 127 */
+#define GDB_SIGINFO 142 /* Information request */
+#define GDB_UNKNOWN 143 /* Unknown signal */
+#define GDB_DEFAULT 144 /* error: default signal */
+/* Mach exceptions */
+#define GDB_EXC_BAD_ACCESS 145 /* Could not access memory */
+#define GDB_EXC_BAD_INSTRCTION 146 /* Illegal instruction/operand */
+#define GDB_EXC_ARITHMETIC 147 /* Arithmetic exception */
+#define GDB_EXC_EMULATION 148 /* Emulation instruction */
+#define GDB_EXC_SOFTWARE 149 /* Software generated exception */
+#define GDB_EXC_BREAKPOINT 150 /* Breakpoint */
+
+
+
+static unsigned char exception_to_signal[] =
+{
+ [0] = GDB_SIGFPE, /* divide by zero */
+ [1] = GDB_SIGTRAP, /* debug exception */
+ [2] = GDB_SIGSEGV, /* NMI Interrupt */
+ [3] = GDB_SIGTRAP, /* Breakpoint */
+ [4] = GDB_SIGSEGV, /* into instruction (overflow) */
+ [5] = GDB_SIGSEGV, /* bound instruction */
+ [6] = GDB_SIGILL, /* Invalid opcode */
+ [7] = GDB_SIGSEGV, /* coprocessor not available */
+ [8] = GDB_SIGSEGV, /* double fault */
+ [9] = GDB_SIGFPE, /* coprocessor segment overrun */
+ [10] = GDB_SIGSEGV, /* Invalid TSS */
+ [11] = GDB_SIGBUS, /* Segment not present */
+ [12] = GDB_SIGBUS, /* stack exception */
+ [13] = GDB_SIGSEGV, /* general protection */
+ [14] = GDB_SIGSEGV, /* page fault */
+ [15] = GDB_UNKNOWN, /* reserved */
+ [16] = GDB_SIGEMT, /* coprocessor error */
+ [17] = GDB_SIGBUS, /* alignment check */
+ [18] = GDB_SIGSEGV, /* machine check */
+ [19] = GDB_SIGFPE, /* simd floating point exception */
+ [20] = GDB_UNKNOWN,
+ [21] = GDB_UNKNOWN,
+ [22] = GDB_UNKNOWN,
+ [23] = GDB_UNKNOWN,
+ [24] = GDB_UNKNOWN,
+ [25] = GDB_UNKNOWN,
+ [26] = GDB_UNKNOWN,
+ [27] = GDB_UNKNOWN,
+ [28] = GDB_UNKNOWN,
+ [29] = GDB_UNKNOWN,
+ [30] = GDB_UNKNOWN,
+ [31] = GDB_UNKNOWN,
+ [32] = GDB_SIGINT, /* User interrupt */
+};
+
+static const char hexchars[] = "0123456789abcdef";
+static char in_buffer[BUFMAX];
+static char out_buffer[BUFMAX];
+
+
+static inline void stub_putc(int ch)
+{
+ console_tx_byte(ch);
+}
+
+static inline int stub_getc(void)
+{
+ return console_rx_byte();
+}
+
+static int hex(char ch)
+{
+ if ((ch >= 'a') && (ch <= 'f'))
+ return (ch - 'a' + 10);
+ if ((ch >= '0') && (ch <= '9'))
+ return (ch - '0');
+ if ((ch >= 'A') && (ch <= 'F'))
+ return (ch - 'A' + 10);
+ return (-1);
+}
+
+/*
+ * While we find hexadecimal digits, build an int.
+ * Fals is returned if nothing is parsed true otherwise.
+ */
+static int parse_ulong(char **ptr, unsigned long *value)
+{
+ int digit;
+ char *start;
+
+ start = *ptr;
+ *value = 0;
+
+ while((digit = hex(**ptr)) >= 0) {
+ *value = ((*value) << 4) | digit;
+ (*ptr)++;
+ }
+ return start != *ptr;
+}
+
+/* convert the memory pointed to by mem into hex, placing result in buf */
+/* return a pointer to the last char put in buf (null) */
+static void copy_to_hex(char *buf, void *addr, unsigned long count)
+{
+ unsigned char ch;
+ char *mem = addr;
+
+ while(count--) {
+ ch = *mem++;
+ *buf++ = hexchars[ch >> 4];
+ *buf++ = hexchars[ch & 0x0f];
+ }
+ *buf = 0;
+ return;
+}
+
+
+/* convert the hex array pointed to by buf into binary to be placed in mem */
+/* return a pointer to the character AFTER the last byte written */
+static void copy_from_hex(void *addr, char *buf, unsigned long count)
+{
+ unsigned char ch;
+ char *mem = addr;
+
+ while(count--) {
+ ch = hex (*buf++) << 4;
+ ch = ch + hex (*buf++);
+ *mem++ = ch;
+ }
+}
+
+
+/* scan for the sequence $<data>#<checksum> */
+
+static int get_packet(char *buffer)
+{
+ unsigned char checksum;
+ unsigned char xmitcsum;
+ int count;
+ char ch;
+
+ /* Wishlit implement a timeout in get_packet */
+ do {
+ /* wait around for the start character, ignore all other characters */
+ while ((ch = (stub_getc() & 0x7f)) != '$');
+ checksum = 0;
+ xmitcsum = -1;
+
+ count = 0;
+
+ /* now, read until a # or end of buffer is found */
+ while (count < BUFMAX) {
+ ch = stub_getc() & 0x7f;
+ if (ch == '#')
+ break;
+ checksum = checksum + ch;
+ buffer[count] = ch;
+ count = count + 1;
+ }
+ buffer[count] = 0;
+
+ if (ch == '#') {
+ xmitcsum = hex(stub_getc() & 0x7f) << 4;
+ xmitcsum += hex(stub_getc() & 0x7f);
+
+ if (checksum != xmitcsum) {
+ stub_putc('-'); /* failed checksum */
+ }
+ else {
+ stub_putc('+'); /* successful transfer */
+ }
+ }
+ } while(checksum != xmitcsum);
+ return 1;
+}
+
+/* send the packet in buffer.*/
+static void put_packet(char *buffer)
+{
+ unsigned char checksum;
+ int count;
+ char ch;
+
+ /* $<packet info>#<checksum>. */
+ do {
+ stub_putc('$');
+ checksum = 0;
+ count = 0;
+
+ while ((ch = buffer[count])) {
+ stub_putc(ch);
+ checksum += ch;
+ count += 1;
+ }
+
+ stub_putc('#');
+ stub_putc(hexchars[checksum >> 4]);
+ stub_putc(hexchars[checksum % 16]);
+
+ } while ((stub_getc() & 0x7f) != '+');
+
+}
+#endif /* CONFIG_GDB_STUB */
+
+#include <arch/registers.h>
+
+void x86_exception(struct eregs *info);
+
+void x86_exception(struct eregs *info)
+{
+#if CONFIG_GDB_STUB == 1
+ int signo;
+ memcpy(gdb_stub_registers, info, 8*sizeof(uint32_t));
+ gdb_stub_registers[PC] = info->eip;
+ gdb_stub_registers[CS] = info->cs;
+ gdb_stub_registers[PS] = info->eflags;
+ signo = GDB_UNKNOWN;
+ if (info->vector < ARRAY_SIZE(exception_to_signal)) {
+ signo = exception_to_signal[info->vector];
+ }
+
+ /* reply to the host that an exception has occured */
+ out_buffer[0] = 'S';
+ out_buffer[1] = hexchars[(signo>>4) & 0xf];
+ out_buffer[2] = hexchars[signo & 0xf];
+ out_buffer[3] = '\0';
+ put_packet(out_buffer);
+
+ while(1) {
+ unsigned long addr, length;
+ char *ptr;
+ out_buffer[0] = '\0';
+ out_buffer[1] = '\0';
+ if (!get_packet(in_buffer)) {
+ break;
+ }
+ switch(in_buffer[0]) {
+ case '?': /* last signal */
+ out_buffer[0] = 'S';
+ out_buffer[1] = hexchars[(signo >> 4) & 0xf];
+ out_buffer[2] = hexchars[signo & 0xf];
+ out_buffer[3] = '\0';
+ break;
+ case 'g': /* return the value of the cpu registers */
+ copy_to_hex(out_buffer, &gdb_stub_registers, sizeof(gdb_stub_registers));
+ break;
+ case 'G': /* set the value of the CPU registers - return OK */
+ copy_from_hex(&gdb_stub_registers, in_buffer + 1, sizeof(gdb_stub_registers));
+ memcpy(info, gdb_stub_registers, 8*sizeof(uint32_t));
+ info->eip = gdb_stub_registers[PC];
+ info->cs = gdb_stub_registers[CS];
+ info->eflags = gdb_stub_registers[PS];
+ memcpy(out_buffer, "OK",3);
+ break;
+ case 'm':
+ /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
+ ptr = &in_buffer[1];
+ if ( parse_ulong(&ptr, &addr) &&
+ (*ptr++ == ',') &&
+ parse_ulong(&ptr, &length)) {
+ copy_to_hex(out_buffer, (void *)addr, length);
+ } else {
+ memcpy(out_buffer, "E01", 4);
+ }
+ break;
+ case 'M':
+ /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
+ ptr = &in_buffer[1];
+ if ( parse_ulong(&ptr, &addr) &&
+ (*(ptr++) == ',') &&
+ parse_ulong(&ptr, &length) &&
+ (*(ptr++) == ':')) {
+ copy_from_hex((void *)addr, ptr, length);
+ memcpy(out_buffer, "OK", 3);
+ }
+ else {
+ memcpy(out_buffer, "E02", 4);
+ }
+ break;
+ case 's':
+ case 'c':
+ /* cAA..AA Continue at address AA..AA(optional) */
+ /* sAA..AA Step one instruction from AA..AA(optional) */
+ ptr = &in_buffer[1];
+ if (parse_ulong(&ptr, &addr)) {
+ info->eip = addr;
+ }
+
+ /* Clear the trace bit */
+ info->eflags &= ~(1 << 8);
+ /* Set the trace bit if we are single stepping */
+ if (in_buffer[0] == 's') {
+ info->eflags |= (1 << 8);
+ }
+ return;
+ break;
+ case 'D':
+ memcpy(out_buffer, "OK", 3);
+ break;
+ case 'k': /* kill request? */
+ break;
+ case 'q': /* query */
+ break;
+ case 'z': /* z0AAAA,LLLL remove memory breakpoint */
+ /* z1AAAA,LLLL remove hardware breakpoint */
+ /* z2AAAA,LLLL remove write watchpoint */
+ /* z3AAAA,LLLL remove read watchpoint */
+ /* z4AAAA,LLLL remove access watchpoint */
+ case 'Z': /* Z0AAAA,LLLL insert memory breakpoint */
+ /* Z1AAAA,LLLL insert hardware breakpoint */
+ /* Z2AAAA,LLLL insert write watchpoint */
+ /* Z3AAAA,LLLL insert read watchpoint */
+ /* Z4AAAA,LLLL insert access watchpoint */
+ break;
+ default:
+ break;
+ }
+ put_packet(out_buffer);
+ }
+#else /* !CONFIG_GDB_STUB */
+ printk(BIOS_EMERG,
+ "Unexpected Exception: %d @ %02x:%08x - Halting\n"
+ "Code: %d eflags: %08x\n"
+ "eax: %08x ebx: %08x ecx: %08x edx: %08x\n"
+ "edi: %08x esi: %08x ebp: %08x esp: %08x\n",
+ info->vector, info->cs, info->eip,
+ info->error_code, info->eflags,
+ info->eax, info->ebx, info->ecx, info->edx,
+ info->edi, info->esi, info->ebp, info->esp);
+ die("");
+#endif
+}
diff --git a/src/arch/x86/lib/id.inc b/src/arch/x86/lib/id.inc
new file mode 100644
index 000000000..443dbad38
--- /dev/null
+++ b/src/arch/x86/lib/id.inc
@@ -0,0 +1,15 @@
+ .section ".id", "a", @progbits
+
+ .globl __id_start
+__id_start:
+vendor:
+ .asciz CONFIG_MAINBOARD_VENDOR
+part:
+ .asciz CONFIG_MAINBOARD_PART_NUMBER
+.long __id_end + CONFIG_ID_SECTION_OFFSET - vendor /* Reverse offset to the vendor id */
+.long __id_end + CONFIG_ID_SECTION_OFFSET - part /* Reverse offset to the part number */
+.long CONFIG_ROM_SIZE /* Size of this romimage */
+ .globl __id_end
+
+__id_end:
+.previous
diff --git a/src/arch/x86/lib/id.lds b/src/arch/x86/lib/id.lds
new file mode 100644
index 000000000..d646270da
--- /dev/null
+++ b/src/arch/x86/lib/id.lds
@@ -0,0 +1,6 @@
+SECTIONS {
+ . = (CONFIG_ROMBASE + CONFIG_ROM_IMAGE_SIZE - CONFIG_ID_SECTION_OFFSET) - (__id_end - __id_start);
+ .id (.): {
+ *(.id)
+ }
+}
diff --git a/src/arch/x86/lib/ioapic.c b/src/arch/x86/lib/ioapic.c
new file mode 100644
index 000000000..e39fe8fd0
--- /dev/null
+++ b/src/arch/x86/lib/ioapic.c
@@ -0,0 +1,139 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 coresystems GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <arch/io.h>
+#include <arch/ioapic.h>
+#include <console/console.h>
+#include <cpu/x86/lapic.h>
+
+static u32 io_apic_read(u32 ioapic_base, u32 reg)
+{
+ write32(ioapic_base, reg);
+ return read32(ioapic_base + 0x10);
+}
+
+static void io_apic_write(u32 ioapic_base, u32 reg, u32 value)
+{
+ write32(ioapic_base, reg);
+ write32(ioapic_base + 0x10, value);
+}
+
+void clear_ioapic(u32 ioapic_base)
+{
+ u32 low, high;
+ u32 i, ioapic_interrupts;
+
+ printk(BIOS_DEBUG, "IOAPIC: Clearing IOAPIC at 0x%08x\n", ioapic_base);
+
+ /* Read the available number of interrupts. */
+ ioapic_interrupts = (io_apic_read(ioapic_base, 0x01) >> 16) & 0xff;
+ if (!ioapic_interrupts || ioapic_interrupts == 0xff)
+ ioapic_interrupts = 24;
+ printk(BIOS_DEBUG, "IOAPIC: %d interrupts\n", ioapic_interrupts);
+
+ low = DISABLED;
+ high = NONE;
+
+ for (i = 0; i < ioapic_interrupts; i++) {
+ io_apic_write(ioapic_base, i * 2 + 0x10, low);
+ io_apic_write(ioapic_base, i * 2 + 0x11, high);
+
+ printk(BIOS_SPEW, "IOAPIC: reg 0x%08x value 0x%08x 0x%08x\n",
+ i, high, low);
+ }
+
+ if (io_apic_read(ioapic_base, 0x10) == 0xffffffff) {
+ printk(BIOS_WARNING, "IOAPIC not responding.\n");
+ return;
+ }
+}
+
+void setup_ioapic(u32 ioapic_base, u8 ioapic_id)
+{
+ u32 bsp_lapicid = lapicid();
+ u32 low, high;
+ u32 i, ioapic_interrupts;
+
+ printk(BIOS_DEBUG, "IOAPIC: Initializing IOAPIC at 0x%08x\n",
+ ioapic_base);
+ printk(BIOS_DEBUG, "IOAPIC: Bootstrap Processor Local APIC = 0x%02x\n",
+ bsp_lapicid);
+
+ if (ioapic_id) {
+ printk(BIOS_DEBUG, "IOAPIC: ID = 0x%02x\n", ioapic_id);
+ /* Set IOAPIC ID if it has been specified. */
+ io_apic_write(ioapic_base, 0x00,
+ (io_apic_read(ioapic_base, 0x00) & 0xfff0ffff) |
+ (ioapic_id << 24));
+ }
+
+ /* Read the available number of interrupts. */
+ ioapic_interrupts = (io_apic_read(ioapic_base, 0x01) >> 16) & 0xff;
+ if (!ioapic_interrupts || ioapic_interrupts == 0xff)
+ ioapic_interrupts = 24;
+ printk(BIOS_DEBUG, "IOAPIC: %d interrupts\n", ioapic_interrupts);
+
+// XXX this decision should probably be made elsewhere, and
+// it's the C3, not the EPIA this depends on.
+#if defined(CONFIG_EPIA_VT8237R_INIT) && CONFIG_EPIA_VT8237R_INIT
+#define IOAPIC_INTERRUPTS_ON_APIC_SERIAL_BUS
+#else
+#define IOAPIC_INTERRUPTS_ON_FSB
+#endif
+
+#ifdef IOAPIC_INTERRUPTS_ON_FSB
+ /*
+ * For the Pentium 4 and above APICs deliver their interrupts
+ * on the front side bus, enable that.
+ */
+ printk(BIOS_DEBUG, "IOAPIC: Enabling interrupts on FSB\n");
+ io_apic_write(ioapic_base, 0x03,
+ io_apic_read(ioapic_base, 0x03) | (1 << 0));
+#endif
+#ifdef IOAPIC_INTERRUPTS_ON_APIC_SERIAL_BUS
+ printk(BIOS_DEBUG, "IOAPIC: Enabling interrupts on APIC serial bus\n");
+ io_apic_write(ioapic_base, 0x03, 0);
+#endif
+
+ /* Enable Virtual Wire Mode. */
+ low = ENABLED | TRIGGER_EDGE | POLARITY_HIGH | PHYSICAL_DEST | ExtINT;
+ high = bsp_lapicid << (56 - 32);
+
+ io_apic_write(ioapic_base, 0x10, low);
+ io_apic_write(ioapic_base, 0x11, high);
+
+ if (io_apic_read(ioapic_base, 0x10) == 0xffffffff) {
+ printk(BIOS_WARNING, "IOAPIC not responding.\n");
+ return;
+ }
+
+ printk(BIOS_SPEW, "IOAPIC: reg 0x%08x value 0x%08x 0x%08x\n",
+ 0, high, low);
+
+ low = DISABLED;
+ high = NONE;
+
+ for (i = 1; i < ioapic_interrupts; i++) {
+ io_apic_write(ioapic_base, i * 2 + 0x10, low);
+ io_apic_write(ioapic_base, i * 2 + 0x11, high);
+
+ printk(BIOS_SPEW, "IOAPIC: reg 0x%08x value 0x%08x 0x%08x\n",
+ i, high, low);
+ }
+}
diff --git a/src/arch/x86/lib/pci_ops_auto.c b/src/arch/x86/lib/pci_ops_auto.c
new file mode 100644
index 000000000..92eedd30f
--- /dev/null
+++ b/src/arch/x86/lib/pci_ops_auto.c
@@ -0,0 +1,100 @@
+#include <stddef.h>
+#include <console/console.h>
+#include <arch/io.h>
+#include <arch/pciconf.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+
+/*
+ * 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_bus_operations *o)
+{
+ uint16_t class, vendor;
+ unsigned bus;
+ int devfn;
+ struct bus pbus; /* Dummy device */
+#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++) {
+ class = o->read16(&pbus, bus, devfn, PCI_CLASS_DEVICE);
+ vendor = o->read16(&pbus, bus, devfn, PCI_VENDOR_ID);
+ if (((class == PCI_CLASS_BRIDGE_HOST) || (class == PCI_CLASS_DISPLAY_VGA)) ||
+ ((vendor == PCI_VENDOR_ID_INTEL) || (vendor == PCI_VENDOR_ID_COMPAQ) ||
+ (vendor == PCI_VENDOR_ID_MOTOROLA))) {
+ return 1;
+ }
+ }
+ printk(BIOS_ERR, "PCI: Sanity check failed\n");
+ return 0;
+}
+
+struct pci_bus_operations *pci_bus_fallback_ops = NULL;
+
+static const struct pci_bus_operations *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_cf8_conf1))
+ {
+ outl(tmp, 0xCF8);
+ printk(BIOS_DEBUG, "PCI: Using configuration type 1\n");
+ return &pci_cf8_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_cf8_conf2))
+ {
+ printk(BIOS_DEBUG, "PCI: Using configuration type 2\n");
+ return &pci_cf8_conf2;
+ }
+ }
+
+ die("pci_check_direct failed\n");
+ return NULL;
+}
+
+const struct pci_bus_operations *pci_remember_direct(void)
+{
+ if (!pci_bus_fallback_ops)
+ pci_bus_fallback_ops = (struct pci_bus_operations *)pci_check_direct();
+ return pci_bus_fallback_ops;
+}
+
+/** Set the method to be used for PCI, type I or type II
+ */
+void pci_set_method(device_t dev)
+{
+ printk(BIOS_INFO, "Finding PCI configuration type.\n");
+ dev->ops->ops_pci_bus = pci_remember_direct();
+ post_code(0x5f);
+}
diff --git a/src/arch/x86/lib/pci_ops_conf1.c b/src/arch/x86/lib/pci_ops_conf1.c
new file mode 100644
index 000000000..36db54c21
--- /dev/null
+++ b/src/arch/x86/lib/pci_ops_conf1.c
@@ -0,0 +1,63 @@
+#include <console/console.h>
+#include <arch/io.h>
+#include <arch/pciconf.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+/*
+ * Functions for accessing PCI configuration space with type 1 accesses
+ */
+
+#if CONFIG_PCI_IO_CFG_EXT == 0
+#define CONFIG_CMD(bus,devfn, where) (0x80000000 | (bus << 16) | (devfn << 8) | (where & ~3))
+#else
+#define CONFIG_CMD(bus,devfn, where) (0x80000000 | (bus << 16) | (devfn << 8) | ((where & 0xff) & ~3) | ((where & 0xf00)<<16) )
+#endif
+
+static uint8_t pci_conf1_read_config8(struct bus *pbus, int bus, int devfn, int where)
+{
+ outl(CONFIG_CMD(bus, devfn, where), 0xCF8);
+ return inb(0xCFC + (where & 3));
+}
+
+static uint16_t pci_conf1_read_config16(struct bus *pbus, int bus, int devfn, int where)
+{
+ outl(CONFIG_CMD(bus, devfn, where), 0xCF8);
+ return inw(0xCFC + (where & 2));
+}
+
+static uint32_t pci_conf1_read_config32(struct bus *pbus, int bus, int devfn, int where)
+{
+ outl(CONFIG_CMD(bus, devfn, where), 0xCF8);
+ return inl(0xCFC);
+}
+
+static void pci_conf1_write_config8(struct bus *pbus, int bus, int devfn, int where, uint8_t value)
+{
+ outl(CONFIG_CMD(bus, devfn, where), 0xCF8);
+ outb(value, 0xCFC + (where & 3));
+}
+
+static void pci_conf1_write_config16(struct bus *pbus, int bus, int devfn, int where, uint16_t value)
+{
+ outl(CONFIG_CMD(bus, devfn, where), 0xCF8);
+ outw(value, 0xCFC + (where & 2));
+}
+
+static void pci_conf1_write_config32(struct bus *pbus, int bus, int devfn, int where, uint32_t value)
+{
+ outl(CONFIG_CMD(bus, devfn, where), 0xCF8);
+ outl(value, 0xCFC);
+}
+
+#undef CONFIG_CMD
+
+const struct pci_bus_operations pci_cf8_conf1 =
+{
+ .read8 = pci_conf1_read_config8,
+ .read16 = pci_conf1_read_config16,
+ .read32 = pci_conf1_read_config32,
+ .write8 = pci_conf1_write_config8,
+ .write16 = pci_conf1_write_config16,
+ .write32 = pci_conf1_write_config32,
+};
diff --git a/src/arch/x86/lib/pci_ops_conf2.c b/src/arch/x86/lib/pci_ops_conf2.c
new file mode 100644
index 000000000..839f5b44c
--- /dev/null
+++ b/src/arch/x86/lib/pci_ops_conf2.c
@@ -0,0 +1,76 @@
+#include <console/console.h>
+#include <arch/io.h>
+#include <arch/pciconf.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+/*
+ * 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) outb(FUNC(devfn), 0xCF8); outb(bus, 0xCFA);
+
+static uint8_t pci_conf2_read_config8(struct bus *pbus, int bus, int devfn, int where)
+{
+ uint8_t value;
+ SET(bus, devfn);
+ value = inb(IOADDR(devfn, where));
+ outb(0, 0xCF8);
+ return value;
+}
+
+static uint16_t pci_conf2_read_config16(struct bus *pbus, int bus, int devfn, int where)
+{
+ uint16_t value;
+ SET(bus, devfn);
+ value = inw(IOADDR(devfn, where));
+ outb(0, 0xCF8);
+ return value;
+}
+
+static uint32_t pci_conf2_read_config32(struct bus *pbus, int bus, int devfn, int where)
+{
+ uint32_t value;
+ SET(bus, devfn);
+ value = inl(IOADDR(devfn, where));
+ outb(0, 0xCF8);
+ return value;
+}
+
+static void pci_conf2_write_config8(struct bus *pbus, int bus, int devfn, int where, uint8_t value)
+{
+ SET(bus, devfn);
+ outb(value, IOADDR(devfn, where));
+ outb(0, 0xCF8);
+}
+
+static void pci_conf2_write_config16(struct bus *pbus, int bus, int devfn, int where, uint16_t value)
+{
+ SET(bus, devfn);
+ outw(value, IOADDR(devfn, where));
+ outb(0, 0xCF8);
+}
+
+static void pci_conf2_write_config32(struct bus *pbus, int bus, int devfn, int where, uint32_t value)
+{
+ SET(bus, devfn);
+ outl(value, IOADDR(devfn, where));
+ outb(0, 0xCF8);
+}
+
+#undef SET
+#undef IOADDR
+#undef FUNC
+
+const struct pci_bus_operations pci_cf8_conf2 =
+{
+ .read8 = pci_conf2_read_config8,
+ .read16 = pci_conf2_read_config16,
+ .read32 = pci_conf2_read_config32,
+ .write8 = pci_conf2_write_config8,
+ .write16 = pci_conf2_write_config16,
+ .write32 = pci_conf2_write_config32,
+};
+
diff --git a/src/arch/x86/lib/pci_ops_mmconf.c b/src/arch/x86/lib/pci_ops_mmconf.c
new file mode 100644
index 000000000..7d8fb329d
--- /dev/null
+++ b/src/arch/x86/lib/pci_ops_mmconf.c
@@ -0,0 +1,64 @@
+#if CONFIG_MMCONF_SUPPORT
+
+#include <console/console.h>
+#include <arch/io.h>
+#include <arch/pciconf.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+
+
+/*
+ * Functions for accessing PCI configuration space with mmconf accesses
+ */
+
+#define PCI_MMIO_ADDR(SEGBUS, DEVFN, WHERE) ( \
+ CONFIG_MMCONF_BASE_ADDRESS | \
+ (((SEGBUS) & 0xFFF) << 20) | \
+ (((DEVFN) & 0xFF) << 12) | \
+ ((WHERE) & 0xFFF))
+
+#include <arch/mmio_conf.h>
+
+static uint8_t pci_mmconf_read_config8(struct bus *pbus, int bus, int devfn, int where)
+{
+ return (read8x(PCI_MMIO_ADDR(bus, devfn, where)));
+}
+
+static uint16_t pci_mmconf_read_config16(struct bus *pbus, int bus, int devfn, int where)
+{
+ return (read16x(PCI_MMIO_ADDR(bus, devfn, where) & ~1));
+}
+
+static uint32_t pci_mmconf_read_config32(struct bus *pbus, int bus, int devfn, int where)
+{
+ return (read32x(PCI_MMIO_ADDR(bus, devfn, where) & ~3));
+}
+
+static void pci_mmconf_write_config8(struct bus *pbus, int bus, int devfn, int where, uint8_t value)
+{
+ write8x(PCI_MMIO_ADDR(bus, devfn, where), value);
+}
+
+static void pci_mmconf_write_config16(struct bus *pbus, int bus, int devfn, int where, uint16_t value)
+{
+ write16x(PCI_MMIO_ADDR(bus, devfn, where) & ~1, value);
+}
+
+static void pci_mmconf_write_config32(struct bus *pbus, int bus, int devfn, int where, uint32_t value)
+{
+ write32x(PCI_MMIO_ADDR(bus, devfn, where) & ~3, value);
+}
+
+
+const struct pci_bus_operations pci_ops_mmconf =
+{
+ .read8 = pci_mmconf_read_config8,
+ .read16 = pci_mmconf_read_config16,
+ .read32 = pci_mmconf_read_config32,
+ .write8 = pci_mmconf_write_config8,
+ .write16 = pci_mmconf_write_config16,
+ .write32 = pci_mmconf_write_config32,
+};
+
+#endif
diff --git a/src/arch/x86/lib/printk_init.c b/src/arch/x86/lib/printk_init.c
new file mode 100644
index 000000000..2f7f75183
--- /dev/null
+++ b/src/arch/x86/lib/printk_init.c
@@ -0,0 +1,57 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of
+ * the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#include <console/console.h>
+#include <console/vtxprintf.h>
+#include <uart8250.h>
+
+#if CONFIG_CONSOLE_NE2K
+#include <console/ne2k.h>
+#endif
+
+static void console_tx_byte(unsigned char byte)
+{
+#if CONFIG_CONSOLE_NE2K
+#ifdef __PRE_RAM__
+ ne2k_append_data(&byte, 1, CONFIG_CONSOLE_NE2K_IO_PORT);
+#endif
+#endif
+ if (byte == '\n')
+ uart8250_tx_byte(CONFIG_TTYS0_BASE, '\r');
+
+ uart8250_tx_byte(CONFIG_TTYS0_BASE, byte);
+}
+
+int do_printk(int msg_level, const char *fmt, ...)
+{
+ va_list args;
+ int i;
+
+ if (msg_level > console_loglevel) {
+ return 0;
+ }
+
+ va_start(args, fmt);
+ i = vtxprintf(console_tx_byte, fmt, args);
+ va_end(args);
+#if CONFIG_CONSOLE_NE2K
+ ne2k_transmit(CONFIG_CONSOLE_NE2K_IO_PORT);
+#endif
+ return i;
+}
diff --git a/src/arch/x86/lib/stages.c b/src/arch/x86/lib/stages.c
new file mode 100644
index 000000000..a6a232a04
--- /dev/null
+++ b/src/arch/x86/lib/stages.c
@@ -0,0 +1,28 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 coresystems GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+static void skip_romstage(void)
+{
+ asm volatile (
+ "/* set the boot_complete flag */\n"
+ "movl $0xffffffff, %%ebp\n"
+ "jmp __main\n"
+ );
+}
+
diff --git a/src/arch/x86/lib/walkcbfs.S b/src/arch/x86/lib/walkcbfs.S
new file mode 100644
index 000000000..395c46e20
--- /dev/null
+++ b/src/arch/x86/lib/walkcbfs.S
@@ -0,0 +1,126 @@
+#define CBFS_HEADER_PTR 0xfffffffc
+
+#define CBFS_HEADER_MAGIC 0
+#define CBFS_HEADER_VERSION (CBFS_HEADER_MAGIC + 4)
+#define CBFS_HEADER_ROMSIZE (CBFS_HEADER_VERSION + 4)
+#define CBFS_HEADER_BOOTBLOCKSIZE (CBFS_HEADER_ROMSIZE + 4)
+#define CBFS_HEADER_ALIGN (CBFS_HEADER_BOOTBLOCKSIZE + 4)
+#define CBFS_HEADER_OFFSET (CBFS_HEADER_ALIGN + 4)
+
+#define CBFS_FILE_MAGIC 0
+#define CBFS_FILE_LEN (CBFS_FILE_MAGIC + 8)
+#define CBFS_FILE_TYPE (CBFS_FILE_LEN + 4)
+#define CBFS_FILE_CHECKSUM (CBFS_FILE_TYPE + 4)
+#define CBFS_FILE_OFFSET (CBFS_FILE_CHECKSUM + 4)
+
+#define CBFS_FILE_STRUCTSIZE (CBFS_FILE_OFFSET + 4)
+
+#define CBFS_STAGE_COMPRESSION 0
+#define CBFS_STAGE_ENTRY (CBFS_STAGE_COMPRESSION + 4)
+#define CBFS_STAGE_LOAD (CBFS_STAGE_ENTRY + 8)
+#define CBFS_STAGE_LEN (CBFS_STAGE_LOAD + 8)
+#define CBFS_STAGE_MEMLEN (CBFS_STAGE_LEN + 4)
+
+/*
+ input %esi: filename
+ input %esp: return address (not pointer to return address!)
+ output %eax: entry point
+ clobbers %ebx, %ecx, %edi
+*/
+walkcbfs:
+ cld
+
+ mov CBFS_HEADER_PTR, %eax
+ mov CBFS_HEADER_ROMSIZE(%eax), %ecx
+ bswap %ecx
+ mov $0, %ebx
+ sub %ecx, %ebx
+ mov CBFS_HEADER_OFFSET(%eax), %ecx
+ bswap %ecx
+ add %ecx, %ebx
+
+ /* determine filename length */
+ mov $0, %eax
+1:
+ cmpb $0, (%eax,%esi)
+ jz 2f
+ add $1, %eax
+ jmp 1b
+2:
+ add $1, %eax
+walker:
+ mov 0(%ebx), %edi
+ cmp %edi, filemagic
+ jne searchfile
+ mov 4(%ebx), %edi
+ cmp %edi, filemagic+4
+ jne searchfile
+
+ mov %ebx, %edi
+ add $CBFS_FILE_STRUCTSIZE, %edi /* edi = address of first byte after struct cbfs_file */
+ mov %eax, %ecx
+ repe cmpsb
+ # zero flag set if strings are equal
+ jnz tryharder
+
+ # we found it!
+ mov CBFS_FILE_OFFSET(%ebx), %eax
+ bswap %eax
+ add %ebx, %eax
+ add $CBFS_STAGE_ENTRY, %eax /* eax = ((cbfs_stage* (cbfs_file* ebx)->offset)->entry) */
+ mov 0(%eax), %eax
+ jmp *%esp
+
+tryharder:
+ sub %ebx, %edi
+ sub $CBFS_FILE_STRUCTSIZE, %edi /* edi = # of walked bytes */
+ sub %edi, %esi /* esi = start of filename */
+
+ /* ebx = ecx = (current+offset+len+ALIGN-1) & ~(ALIGN-1) */
+ mov CBFS_FILE_OFFSET(%ebx), %ecx
+ bswap %ecx
+ add %ebx, %ecx
+ mov CBFS_FILE_LEN(%ebx), %edi
+ bswap %edi
+ add %edi, %ecx
+ mov CBFS_HEADER_PTR, %edi
+ mov CBFS_HEADER_ALIGN(%edi), %edi
+ bswap %edi
+ sub $1, %edi
+ add %edi, %ecx
+ not %edi
+ and %edi, %ecx
+
+ /* if oldaddr >= addr, leave */
+ cmp %ebx, %ecx
+ jbe out
+
+ mov %ecx, %ebx
+
+check_for_exit:
+ /* look if we should exit: did we pass into the bootblock already? */
+ mov CBFS_HEADER_PTR, %ecx
+ mov CBFS_HEADER_BOOTBLOCKSIZE(%ecx), %ecx
+ bswap %ecx
+ not %ecx
+ add $1, %ecx
+
+ cmp %ecx, %ebx
+ /* if bootblockstart >= addr (==we're still in the data area) , jump back */
+ jbe walker
+
+out:
+ mov $0, %eax
+ jmp *%esp
+
+
+searchfile:
+ /* if filemagic isn't found, move forward cbfs_header->align bytes */
+ mov CBFS_HEADER_PTR, %edi
+ mov CBFS_HEADER_ALIGN(%edi), %edi
+ bswap %edi
+ add %edi, %ebx
+ jmp check_for_exit
+
+filemagic:
+ .ascii "LARCHIVE"