summaryrefslogtreecommitdiff
path: root/src/arch/x86
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch/x86')
-rw-r--r--src/arch/x86/Kconfig92
-rw-r--r--src/arch/x86/Makefile.bigbootblock.inc38
-rw-r--r--src/arch/x86/Makefile.bootblock.inc117
-rw-r--r--src/arch/x86/Makefile.inc257
-rw-r--r--src/arch/x86/acpi/debug.asl198
-rw-r--r--src/arch/x86/acpi/globutil.asl118
-rw-r--r--src/arch/x86/acpi/statdef.asl93
-rw-r--r--src/arch/x86/boot/Makefile.inc13
-rw-r--r--src/arch/x86/boot/acpi.c604
-rw-r--r--src/arch/x86/boot/acpigen.c517
-rw-r--r--src/arch/x86/boot/boot.c186
-rw-r--r--src/arch/x86/boot/coreboot_table.c600
-rw-r--r--src/arch/x86/boot/gdt.c60
-rw-r--r--src/arch/x86/boot/mpspec.c383
-rw-r--r--src/arch/x86/boot/multiboot.c77
-rw-r--r--src/arch/x86/boot/pirq_routing.c169
-rw-r--r--src/arch/x86/boot/tables.c231
-rw-r--r--src/arch/x86/boot/wakeup.S105
-rw-r--r--src/arch/x86/coreboot_ram.ld128
-rw-r--r--src/arch/x86/include/arch/acpi.h440
-rw-r--r--src/arch/x86/include/arch/acpigen.h56
-rw-r--r--src/arch/x86/include/arch/boot/boot.h8
-rw-r--r--src/arch/x86/include/arch/byteorder.h20
-rw-r--r--src/arch/x86/include/arch/coreboot_tables.h25
-rw-r--r--src/arch/x86/include/arch/cpu.h165
-rw-r--r--src/arch/x86/include/arch/hlt.h16
-rw-r--r--src/arch/x86/include/arch/interrupt.h25
-rw-r--r--src/arch/x86/include/arch/io.h168
-rw-r--r--src/arch/x86/include/arch/ioapic.h44
-rw-r--r--src/arch/x86/include/arch/llshell.h11
-rw-r--r--src/arch/x86/include/arch/mmio_conf.h67
-rw-r--r--src/arch/x86/include/arch/pci_ops.h13
-rw-r--r--src/arch/x86/include/arch/pciconf.h14
-rw-r--r--src/arch/x86/include/arch/pirq_routing.h54
-rw-r--r--src/arch/x86/include/arch/registers.h32
-rw-r--r--src/arch/x86/include/arch/rom_segs.h7
-rw-r--r--src/arch/x86/include/arch/romcc_io.h341
-rw-r--r--src/arch/x86/include/arch/smp/atomic.h69
-rw-r--r--src/arch/x86/include/arch/smp/mpspec.h281
-rw-r--r--src/arch/x86/include/arch/smp/spinlock.h64
-rw-r--r--src/arch/x86/include/arch/stages.h25
-rw-r--r--src/arch/x86/include/bitops.h20
-rw-r--r--src/arch/x86/include/bootblock_common.h33
-rw-r--r--src/arch/x86/include/div64.h51
-rw-r--r--src/arch/x86/include/stddef.h15
-rw-r--r--src/arch/x86/include/stdint.h77
-rw-r--r--src/arch/x86/init/Makefile.inc1
-rw-r--r--src/arch/x86/init/bootblock_normal.c26
-rw-r--r--src/arch/x86/init/bootblock_simple.c15
-rw-r--r--src/arch/x86/init/crt0_romcc_epilogue.inc26
-rw-r--r--src/arch/x86/init/entry.S149
-rw-r--r--src/arch/x86/init/ldscript.ld40
-rw-r--r--src/arch/x86/init/ldscript_apc.lb31
-rw-r--r--src/arch/x86/init/ldscript_failover.lb53
-rw-r--r--src/arch/x86/init/ldscript_fallback_cbfs.lb53
-rw-r--r--src/arch/x86/init/prologue.inc29
-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
-rw-r--r--src/arch/x86/llshell/console.inc340
-rw-r--r--src/arch/x86/llshell/llshell.inc901
-rw-r--r--src/arch/x86/llshell/pci.inc229
-rw-r--r--src/arch/x86/llshell/ramtest.inc125
-rw-r--r--src/arch/x86/llshell/readme.coreboot25
76 files changed, 9986 insertions, 0 deletions
diff --git a/src/arch/x86/Kconfig b/src/arch/x86/Kconfig
new file mode 100644
index 0000000000..ef86d99119
--- /dev/null
+++ b/src/arch/x86/Kconfig
@@ -0,0 +1,92 @@
+# This option is used to set the architecture of a mainboard to X86.
+# It is usually set in mainboard/*/Kconfig.
+config ARCH_X86
+ bool
+ default n
+
+# This is an SMP option. It relates to starting up APs.
+# It is usually set in mainboard/*/Kconfig.
+# TODO: Improve description.
+config AP_IN_SIPI_WAIT
+ bool
+ default n
+ depends on ARCH_X86
+
+# This is the name of the respective architecture subdirectory in arch/.
+config ARCH
+ string
+ default i386
+ depends on ARCH_X86
+
+config ROMBASE
+ hex
+ default 0xffff0000
+
+config ROM_IMAGE_SIZE
+ hex
+ default 0x10000
+
+config RAMBASE
+ hex
+ default 0x100000
+
+config RAMTOP
+ hex
+ default 0x200000
+
+config STACK_SIZE
+ hex
+ default 0x8000
+
+# Maximum reboot count
+# TODO: Improve description.
+config MAX_REBOOT_CNT
+ int
+ default 3
+
+config TINY_BOOTBLOCK
+ bool
+ default n
+
+config BIG_BOOTBLOCK
+ bool
+ default n if TINY_BOOTBLOCK
+ default y
+
+choice
+ prompt "Bootblock behaviour"
+ default BOOTBLOCK_SIMPLE
+ depends on TINY_BOOTBLOCK
+
+config BOOTBLOCK_SIMPLE
+ bool "Always load fallback"
+
+config BOOTBLOCK_NORMAL
+ bool "Switch to normal if CMOS says so"
+
+endchoice
+
+config BOOTBLOCK_SOURCE
+ string
+ default "bootblock_simple.c" if BOOTBLOCK_SIMPLE
+ default "bootblock_normal.c" if BOOTBLOCK_NORMAL
+
+config UPDATE_IMAGE
+ bool "Update existing coreboot.rom image"
+ default n
+ depends on TINY_BOOTBLOCK
+ help
+ If this option is enabled, no new coreboot.rom file
+ is created. Instead it is expected that there already
+ is a suitable file for further processing.
+ The bootblock will not be modified.
+
+config ROMCC
+ bool
+ default n
+
+config BOOTBLOCK_NORTHBRIDGE_INIT
+ string
+
+config BOOTBLOCK_SOUTHBRIDGE_INIT
+ string
diff --git a/src/arch/x86/Makefile.bigbootblock.inc b/src/arch/x86/Makefile.bigbootblock.inc
new file mode 100644
index 0000000000..a60681670b
--- /dev/null
+++ b/src/arch/x86/Makefile.bigbootblock.inc
@@ -0,0 +1,38 @@
+#######################################################################
+# Build the final rom image
+
+$(obj)/coreboot.pre: $(obj)/coreboot.bootblock $(CBFSTOOL)
+ rm -f $@
+ $(CBFSTOOL) $@ create $(CONFIG_COREBOOT_ROMSIZE_KB)K $(obj)/coreboot.bootblock
+
+#######################################################################
+# Build the bootblock
+
+$(obj)/coreboot.bootblock: $(obj)/coreboot
+ @printf " OBJCOPY $(subst $(obj)/,,$(@))\n"
+ $(OBJCOPY) -O binary $< $@
+
+$(obj)/ldscript.ld: $$(ldscripts) $(obj)/ldoptions
+ printf 'INCLUDE "ldoptions"\n' > $@
+ printf '$(foreach ldscript,$(ldscripts),INCLUDE "$(ldscript:$(obj)/%=%)"\n)' >> $@
+
+$(obj)/crt0.S: $$(crt0s)
+ @printf " GEN $(subst $(obj)/,,$(@))\n"
+ printf '$(foreach crt0,config.h $(crt0s),#include "$(crt0:$(obj)/%=%)"\n)' > $@
+
+$(obj)/mainboard/$(MAINBOARDDIR)/crt0.romstage.o: $(obj)/mainboard/$(MAINBOARDDIR)/crt0.s
+ @printf " CC $(subst $(obj)/,,$(@))\n"
+ $(CC) -MMD -I$(obj) -Wa,-acdlns -c -o $@ $< > $(dir $@)/crt0.disasm
+
+$(obj)/mainboard/$(MAINBOARDDIR)/crt0.s: $(obj)/crt0.S
+ @printf " CC $(subst $(obj)/,,$(@))\n"
+ $(CC) -MMD -x assembler-with-cpp -DASSEMBLY -E -I$(src)/include -I$(src)/arch/x86/include -I$(obj) -include $(obj)/config.h -I. -I$(src) $< -o $@
+
+$(obj)/coreboot: $$(romstage-objs) $(obj)/ldscript.ld
+ @printf " LINK $(subst $(obj)/,,$(@))\n"
+ $(CC) -nostdlib -nostartfiles -static -o $@ -L$(obj) -T $(obj)/ldscript.ld $(romstage-objs)
+ $(NM) -n $(obj)/coreboot | sort > $(obj)/coreboot.map
+ $(OBJCOPY) --only-keep-debug $@ $(obj)/bootblock.debug
+ $(OBJCOPY) --strip-debug $@
+ $(OBJCOPY) --add-gnu-debuglink=$(obj)/bootblock.debug $@
+
diff --git a/src/arch/x86/Makefile.bootblock.inc b/src/arch/x86/Makefile.bootblock.inc
new file mode 100644
index 0000000000..f522fc2150
--- /dev/null
+++ b/src/arch/x86/Makefile.bootblock.inc
@@ -0,0 +1,117 @@
+#######################################################################
+# Build the final rom image
+
+ifneq ($(CONFIG_UPDATE_IMAGE),y)
+$(obj)/coreboot.pre1: $(obj)/coreboot.bootblock $(CBFSTOOL)
+ rm -f $@
+ $(CBFSTOOL) $@ create $(CONFIG_COREBOOT_ROMSIZE_KB)K $(obj)/coreboot.bootblock
+else
+$(obj)/coreboot.pre1: $(CBFSTOOL)
+ mv $(obj)/coreboot.rom $@
+endif
+
+$(obj)/coreboot.pre: $(obj)/coreboot.romstage $(obj)/coreboot.pre1 $(CBFSTOOL)
+ rm -f $@
+ cp $(obj)/coreboot.pre1 $@
+ $(CBFSTOOL) $@ add-stage $(obj)/romstage.elf $(CONFIG_CBFS_PREFIX)/romstage x 0x$(shell cat $(obj)/location.txt)
+#FIXME: location.txt might require an offset of header size
+
+#######################################################################
+# Build the bootblock
+
+$(obj)/coreboot.bootblock: $(obj)/bootblock.elf
+ @printf " OBJCOPY $(subst $(obj)/,,$(@))\n"
+ $(OBJCOPY) -O binary $< $@
+
+bootblock_lds = $(src)/arch/x86/init/ldscript_failover.lb
+bootblock_lds += $(src)/cpu/x86/16bit/entry16.lds
+bootblock_lds += $(src)/cpu/x86/16bit/reset16.lds
+bootblock_lds += $(src)/arch/x86/lib/id.lds
+bootblock_lds += $(chipset_bootblock_lds)
+
+bootblock_inc = $(src)/arch/x86/init/prologue.inc
+bootblock_inc += $(src)/cpu/x86/16bit/entry16.inc
+bootblock_inc += $(src)/cpu/x86/16bit/reset16.inc
+bootblock_inc += $(src)/cpu/x86/32bit/entry32.inc
+bootblock_inc += $(src)/arch/x86/lib/id.inc
+bootblock_inc += $(chipset_bootblock_inc)
+
+ifeq ($(CONFIG_SSE),y)
+bootblock_inc += $(src)/cpu/x86/sse_enable.inc
+endif
+bootblock_inc += $(obj)/mainboard/$(MAINBOARDDIR)/bootblock.inc
+bootblock_inc += $(src)/arch/x86/lib/walkcbfs.S
+
+bootblock_romccflags := -mcpu=i386 -O2 -D__PRE_RAM__
+ifeq ($(CONFIG_SSE),y)
+bootblock_romccflags := -mcpu=k7 -msse -O2 -D__PRE_RAM__
+endif
+
+$(obj)/bootblock/ldscript.ld: $$(bootblock_lds) $(obj)/ldoptions
+ @printf " GEN $(subst $(obj)/,,$(@))\n"
+ mkdir -p $(obj)/bootblock
+ printf '$(foreach ldscript,ldoptions $(bootblock_lds),INCLUDE "$(ldscript)"\n)' > $@
+
+$(obj)/bootblock/bootblock.S: $$(bootblock_inc)
+ @printf " GEN $(subst $(obj)/,,$(@))\n"
+ mkdir -p $(obj)/bootblock
+ printf '$(foreach crt0,config.h $(bootblock_inc),#include "$(crt0)"\n)' > $@
+
+$(obj)/mainboard/$(MAINBOARDDIR)/bootblock.o: $(obj)/mainboard/$(MAINBOARDDIR)/bootblock.s
+ @printf " CC $(subst $(obj)/,,$(@))\n"
+ $(CC) -I$(obj) -Wa,-acdlns -c -o $@ $< > $(dir $@)/crt0.disasm
+
+$(obj)/mainboard/$(MAINBOARDDIR)/bootblock.s: $(obj)/bootblock/bootblock.S
+ @printf " CC $(subst $(obj)/,,$(@))\n"
+ $(CC) -MMD -DASSEMBLY -E -I$(src)/include -I$(src)/arch/x86/include -I$(obj) -I$(obj)/bootblock -include $(obj)/config.h -I. -I$(src) $< -o $@
+
+$(obj)/mainboard/$(MAINBOARDDIR)/bootblock.inc: $(src)/arch/x86/init/$(subst ",,$(CONFIG_BOOTBLOCK_SOURCE)) $(objutil)/romcc/romcc
+ @printf " ROMCC $(subst $(obj)/,,$(@))\n"
+ $(CC) -MM -MT$(obj)/mainboard/$(MAINBOARDDIR)/bootblock.inc \
+ $< > $(obj)/mainboard/$(MAINBOARDDIR)/bootblock.inc.d
+ $(ROMCC) -c -S $(bootblock_romccflags) $(ROMCCFLAGS) -I. $(INCLUDES) $< -o $@
+
+$(obj)/bootblock.elf: $(obj)/mainboard/$(MAINBOARDDIR)/bootblock.o $(obj)/bootblock/ldscript.ld
+ @printf " LINK $(subst $(obj)/,,$(@))\n"
+ $(CC) -nostdlib -nostartfiles -static -o $@ -L$(obj) -T $(obj)/bootblock/ldscript.ld $<
+ $(NM) -n $(obj)/bootblock.elf | sort > $(obj)/bootblock.map
+ $(OBJCOPY) --only-keep-debug $@ $(obj)/bootblock.debug
+ $(OBJCOPY) --strip-debug $@
+ $(OBJCOPY) --add-gnu-debuglink=$(obj)/bootblock.debug $@
+
+#######################################################################
+# Build the romstage
+$(obj)/coreboot.romstage: $(obj)/coreboot.pre1 $$(romstage-objs) $(obj)/romstage/ldscript.ld
+ @printf " LINK $(subst $(obj)/,,$(@))\n"
+ printf "CONFIG_ROMBASE = 0x0;\nAUTO_XIP_ROM_BASE = 0x0;\n" > $(obj)/location.ld
+ $(CC) -nostdlib -nostartfiles -static -o $(obj)/romstage.elf -L$(obj) -T $(obj)/romstage/ldscript.ld $(romstage-objs)
+ $(OBJCOPY) -O binary $(obj)/romstage.elf $(obj)/romstage.bin
+ printf "CONFIG_ROMBASE = 0x" > $(obj)/location.ld
+ $(CBFSTOOL) $(obj)/coreboot.pre1 locate $(obj)/romstage.bin $(CONFIG_CBFS_PREFIX)/romstage $(CONFIG_XIP_ROM_SIZE) > $(obj)/location.txt
+ cat $(obj)/location.txt >> $(obj)/location.ld
+ printf ';\nAUTO_XIP_ROM_BASE = CONFIG_ROMBASE & ~(CONFIG_XIP_ROM_SIZE - 1);\n' >> $(obj)/location.ld
+ $(CC) -nostdlib -nostartfiles -static -o $(obj)/romstage.elf -L$(obj) -T $(obj)/romstage/ldscript.ld $(romstage-objs)
+ $(NM) -n $(obj)/romstage.elf | sort > $(obj)/romstage.map
+ $(OBJCOPY) --only-keep-debug $(obj)/romstage.elf $(obj)/romstage.debug
+ $(OBJCOPY) --strip-debug $(obj)/romstage.elf
+ $(OBJCOPY) --add-gnu-debuglink=$(obj)/romstage.debug $(obj)/romstage.elf
+ $(OBJCOPY) -O binary $(obj)/romstage.elf $@
+
+$(obj)/romstage/ldscript.ld: $$(ldscripts) $(obj)/ldoptions
+ @printf " GEN $(subst $(obj)/,,$(@))\n"
+ mkdir -p $(obj)/romstage
+ printf '$(foreach ldscript,ldoptions location.ld $(ldscripts),INCLUDE "$(ldscript:$(obj)/%=%)"\n)' > $@
+
+$(obj)/romstage/crt0.S: $$(crt0s)
+ @printf " GEN $(subst $(obj)/,,$(@))\n"
+ mkdir -p $(obj)/romstage
+ printf '$(foreach crt0,config.h $(crt0s),#include "$(crt0:$(obj)/%=%)"\n)' > $@
+
+$(obj)/mainboard/$(MAINBOARDDIR)/crt0.romstage.o: $(obj)/mainboard/$(MAINBOARDDIR)/crt0.s
+ @printf " CC $(subst $(obj)/,,$(@))\n"
+ $(CC) -I$(obj) -Wa,-acdlns -c -o $@ $< > $(dir $@)/crt0.disasm
+
+$(obj)/mainboard/$(MAINBOARDDIR)/crt0.s: $(obj)/romstage/crt0.S
+ @printf " CC $(subst $(obj)/,,$(@))\n"
+ $(CC) -MMD -x assembler-with-cpp -DASSEMBLY -E -I$(src)/include -I$(src)/arch/x86/include -I$(obj) -I$(obj)/romstage -include $(obj)/config.h -I. -I$(src) $< -o $@
+
diff --git a/src/arch/x86/Makefile.inc b/src/arch/x86/Makefile.inc
new file mode 100644
index 0000000000..ea6e3ecb14
--- /dev/null
+++ b/src/arch/x86/Makefile.inc
@@ -0,0 +1,257 @@
+##
+## This file is part of the coreboot project.
+##
+## Copyright (C) 2009-2010 coresystems GmbH
+## Copyright (C) 2009 Ronald G. Minnich
+##
+## 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
+##
+
+#######################################################################
+# Take care of subdirectories
+subdirs-y += boot
+# subdirs-y += init
+subdirs-y += lib
+subdirs-y += smp
+
+OPTION_TABLE_H:=
+ifeq ($(CONFIG_HAVE_OPTION_TABLE),y)
+ramstage-srcs += $(obj)/option_table.c
+OPTION_TABLE_H:=$(obj)/option_table.h
+endif
+
+#######################################################################
+# Build the final rom image
+COREBOOT_ROM_DEPENDENCIES:=
+ifneq ($(CONFIG_PAYLOAD_NONE),y)
+COREBOOT_ROM_DEPENDENCIES+=$(CONFIG_FALLBACK_PAYLOAD_FILE)
+endif
+ifeq ($(CONFIG_VGA_BIOS),y)
+COREBOOT_ROM_DEPENDENCIES+=$(CONFIG_FALLBACK_VGA_BIOS_FILE)
+endif
+ifeq ($(CONFIG_INTEL_MBI),y)
+COREBOOT_ROM_DEPENDENCIES+=$(CONFIG_FALLBACK_MBI_FILE)
+endif
+ifeq ($(CONFIG_BOOTSPLASH),y)
+COREBOOT_ROM_DEPENDENCIES+=$(CONFIG_FALLBACK_BOOTSPLASH_FILE)
+endif
+ifeq ($(CONFIG_AP_CODE_IN_CAR),y)
+COREBOOT_ROM_DEPENDENCIES+=$(obj)/coreboot_ap
+endif
+ifeq ($(CONFIG_GEODE_VSA_FILE),y)
+COREBOOT_ROM_DEPENDENCIES+=$(CONFIG_VSA_FILENAME)
+endif
+
+$(obj)/coreboot.rom: $(obj)/coreboot.pre $(obj)/coreboot_ram $(CBFSTOOL) $(call strip_quotes,$(COREBOOT_ROM_DEPENDENCIES))
+ @printf " CBFS $(subst $(obj)/,,$(@))\n"
+ cp $(obj)/coreboot.pre $@.tmp
+ if [ -f $(obj)/coreboot_ap ]; \
+ then \
+ $(CBFSTOOL) $@.tmp add-stage $(obj)/coreboot_ap $(CONFIG_CBFS_PREFIX)/coreboot_ap $(CBFS_COMPRESS_FLAG); \
+ fi
+ $(CBFSTOOL) $@.tmp add-stage $(obj)/coreboot_ram $(CONFIG_CBFS_PREFIX)/coreboot_ram $(CBFS_COMPRESS_FLAG)
+ifeq ($(CONFIG_PAYLOAD_NONE),y)
+ @printf " PAYLOAD \e[1;31mnone (as specified by user)\e[0m\n"
+else
+ @printf " PAYLOAD $(CONFIG_FALLBACK_PAYLOAD_FILE) (compression: $(CBFS_PAYLOAD_COMPRESS_NAME))\n"
+ $(CBFSTOOL) $@.tmp add-payload $(CONFIG_FALLBACK_PAYLOAD_FILE) $(CONFIG_CBFS_PREFIX)/payload $(CBFS_PAYLOAD_COMPRESS_FLAG)
+endif
+ifeq ($(CONFIG_VGA_BIOS),y)
+ @printf " VGABIOS $(CONFIG_FALLBACK_VGA_BIOS_FILE) $(CONFIG_FALLBACK_VGA_BIOS_ID)\n"
+ $(CBFSTOOL) $@.tmp add $(CONFIG_FALLBACK_VGA_BIOS_FILE) "pci$(CONFIG_FALLBACK_VGA_BIOS_ID).rom" optionrom
+endif
+ifeq ($(CONFIG_INTEL_MBI),y)
+ @printf " MBI $(CONFIG_FALLBACK_MBI_FILE)\n"
+ $(CBFSTOOL) $@.tmp add $(CONFIG_FALLBACK_MBI_FILE) mbi.bin mbi
+endif
+ifeq ($(CONFIG_BOOTSPLASH),y)
+ @printf " BOOTSPLASH $(CONFIG_FALLBACK_BOOTSPLASH_FILE)\n"
+ $(CBFSTOOL) $@.tmp add $(CONFIG_FALLBACK_BOOTSPLASH_FILE) bootsplash.jpg bootsplash
+endif
+ifeq ($(CONFIG_GEODE_VSA_FILE),y)
+ @printf " VSA $(CONFIG_VSA_FILENAME)\n"
+ $(OBJCOPY) --set-start 0x20 --adjust-vma 0x60000 -I binary -O elf32-i386 -B i386 $(CONFIG_VSA_FILENAME) $(obj)/vsa.o
+ $(LD) -m elf_i386 -e 0x60020 --section-start .data=0x60000 $(obj)/vsa.o -o $(obj)/vsa.elf
+ $(CBFSTOOL) $@.tmp add-stage $(obj)/vsa.elf vsa
+endif
+ mv $@.tmp $@
+ @printf " CBFSPRINT $(subst $(obj)/,,$(@))\n\n"
+ $(CBFSTOOL) $@ print
+
+#######################################################################
+# i386 specific tools
+
+$(OPTION_TABLE_H): $(objutil)/options/build_opt_tbl $(top)/src/mainboard/$(MAINBOARDDIR)/cmos.layout
+ @printf " OPTION $(subst $(obj)/,,$(@))\n"
+ $(objutil)/options/build_opt_tbl --config $(top)/src/mainboard/$(MAINBOARDDIR)/cmos.layout --header $@
+
+$(obj)/option_table.c: $(objutil)/options/build_opt_tbl $(top)/src/mainboard/$(MAINBOARDDIR)/cmos.layout
+ @printf " OPTION $(subst $(obj)/,,$(@))\n"
+ $(objutil)/options/build_opt_tbl --config $(top)/src/mainboard/$(MAINBOARDDIR)/cmos.layout --option $@
+
+$(objutil)/options/build_opt_tbl: $(top)/util/options/build_opt_tbl.c $(top)/src/include/pc80/mc146818rtc.h $(top)/src/include/boot/coreboot_tables.h
+ @printf " HOSTCC $(subst $(obj)/,,$(@))\n"
+ $(HOSTCC) $(HOSTCFLAGS) $< -o $@
+
+#######################################################################
+# Build the coreboot_ram (stage 2)
+
+$(obj)/coreboot_ram: $(obj)/coreboot_ram.o $(src)/arch/x86/coreboot_ram.ld #ldoptions
+ @printf " CC $(subst $(obj)/,,$(@))\n"
+ $(CC) -nostdlib -nostartfiles -static -o $@ -L$(obj) -T $(src)/arch/x86/coreboot_ram.ld $(obj)/coreboot_ram.o
+ $(NM) -n $(obj)/coreboot_ram | sort > $(obj)/coreboot_ram.map
+ $(OBJCOPY) --only-keep-debug $@ $(obj)/coreboot_ram.debug
+ $(OBJCOPY) --strip-debug $@
+ $(OBJCOPY) --add-gnu-debuglink=$(obj)/coreboot_ram.debug $@
+
+$(obj)/coreboot_ram.o: $(obj)/arch/x86/lib/c_start.ramstage.o $$(driver-objs) $(obj)/coreboot.a $(LIBGCC_FILE_NAME)
+ @printf " CC $(subst $(obj)/,,$(@))\n"
+ $(CC) -nostdlib -r -o $@ $(obj)/arch/x86/lib/c_start.ramstage.o $(driver-objs) -Wl,--wrap,__divdi3 -Wl,--wrap,__udivdi3 -Wl,--wrap,__moddi3 -Wl,--wrap,__umoddi3 -Wl,--start-group $(obj)/coreboot.a $(LIBGCC_FILE_NAME) -Wl,--end-group
+
+$(obj)/coreboot.a: $$(ramstage-objs)
+ @printf " AR $(subst $(obj)/,,$(@))\n"
+ rm -f $(obj)/coreboot.a
+ $(AR) cr $(obj)/coreboot.a $^
+
+#######################################################################
+# coreboot_ap.rom
+
+ifeq ($(CONFIG_AP_CODE_IN_CAR),y)
+
+$(obj)/coreboot_ap: $(obj)/mainboard/$(MAINBOARDDIR)/ap_romstage.o
+ @printf " CC $(subst $(obj)/,,$(@))\n"
+ $(CC) -nostdlib -nostartfiles -static -o $@ -L$(obj) -T $(src)/arch/x86/init/ldscript_apc.lb $^
+ $(OBJCOPY) --only-keep-debug $@ $(obj)/coreboot_ap.debug
+ $(OBJCOPY) --strip-debug $@
+ $(OBJCOPY) --add-gnu-debuglink=$(obj)/coreboot_ap.debug $@
+ $(NM) -n $(obj)/coreboot_ap | sort > $(obj)/coreboot_ap.map
+
+
+endif
+
+#######################################################################
+# done
+
+crt0s = $(src)/arch/x86/init/prologue.inc
+ldscripts =
+ldscripts += $(src)/arch/x86/init/ldscript_fallback_cbfs.lb
+ifeq ($(CONFIG_BIG_BOOTBLOCK),y)
+crt0s += $(src)/cpu/x86/16bit/entry16.inc
+ldscripts += $(src)/cpu/x86/16bit/entry16.lds
+endif
+crt0s += $(src)/cpu/x86/32bit/entry32.inc
+ldscripts += $(src)/cpu/x86/32bit/entry32.lds
+ifeq ($(CONFIG_BIG_BOOTBLOCK),y)
+crt0s += $(src)/cpu/x86/16bit/reset16.inc
+ldscripts += $(src)/cpu/x86/16bit/reset16.lds
+crt0s += $(src)/arch/x86/lib/id.inc
+ldscripts += $(src)/arch/x86/lib/id.lds
+endif
+
+crt0s += $(src)/cpu/x86/fpu_enable.inc
+ifeq ($(CONFIG_SSE),y)
+crt0s += $(src)/cpu/x86/sse_enable.inc
+endif
+
+crt0s += $(cpu_incs)
+
+#
+# FIXME move to CPU_INTEL_SOCKET_MPGA604
+#
+ifeq ($(CONFIG_BOARD_TYAN_S2735),y)
+crt0s += $(src)/cpu/intel/car/cache_as_ram.inc
+endif
+
+ifeq ($(CONFIG_LLSHELL),y)
+crt0s += $(src)/arch/x86/llshell/llshell.inc
+endif
+
+crt0s += $(obj)/mainboard/$(MAINBOARDDIR)/romstage.inc
+
+ifeq ($(CONFIG_SSE),y)
+crt0s += $(src)/cpu/x86/sse_disable.inc
+endif
+ifeq ($(CONFIG_MMX),y)
+crt0s += $(src)/cpu/x86/mmx_disable.inc
+endif
+
+ifeq ($(CONFIG_BIG_BOOTBLOCK),y)
+crt0s += $(chipset_bootblock_inc)
+ldscripts += $(chipset_bootblock_lds)
+endif
+
+ifeq ($(CONFIG_ROMCC),y)
+crt0s += $(src)/arch/x86/init/crt0_romcc_epilogue.inc
+endif
+
+ifeq ($(CONFIG_ROMCC),y)
+ROMCCFLAGS ?= -mcpu=p2 -O2
+
+$(obj)/mainboard/$(MAINBOARDDIR)/romstage.inc: $(src)/mainboard/$(MAINBOARDDIR)/romstage.c $(objutil)/romcc/romcc $(OPTION_TABLE_H) $(obj)/build.h $(obj)/config.h
+ printf " ROMCC romstage.inc\n"
+ $(ROMCC) -c -S $(ROMCCFLAGS) -D__PRE_RAM__ -I. $(INCLUDES) $< -o $@
+else
+
+$(obj)/mainboard/$(MAINBOARDDIR)/ap_romstage.o: $(src)/mainboard/$(MAINBOARDDIR)/ap_romstage.c $(OPTION_TABLE_H)
+ @printf " CC $(subst $(obj)/,,$(@))\n"
+ $(CC) -MMD $(CFLAGS) -I$(src) -I. -I$(obj) -c $(src)/mainboard/$(MAINBOARDDIR)/ap_romstage.c -o $@
+
+$(obj)/mainboard/$(MAINBOARDDIR)/romstage.pre.inc: $(src)/mainboard/$(MAINBOARDDIR)/romstage.c $(OPTION_TABLE_H) $(obj)/build.h
+ @printf " CC romstage.inc\n"
+ $(CC) -MMD $(CFLAGS) -D__PRE_RAM__ -I$(src) -I. -I$(obj) -c -S $< -o $@
+
+$(obj)/mainboard/$(MAINBOARDDIR)/romstage.inc: $(obj)/mainboard/$(MAINBOARDDIR)/romstage.pre.inc
+ @printf " POST romstage.inc\n"
+ sed -e 's/\.rodata/.rom.data/g' -e 's/\.text/.section .rom.text/g' $^ > $@.tmp
+ mv $@.tmp $@
+endif
+
+# Things that appear in every board
+romstage-srcs += $(obj)/mainboard/$(MAINBOARDDIR)/crt0.s
+ramstage-srcs += src/mainboard/$(MAINBOARDDIR)/mainboard.c
+ifeq ($(CONFIG_GENERATE_MP_TABLE),y)
+ramstage-srcs += src/mainboard/$(MAINBOARDDIR)/mptable.c
+endif
+ifeq ($(CONFIG_GENERATE_PIRQ_TABLE),y)
+ramstage-srcs += src/mainboard/$(MAINBOARDDIR)/irq_tables.c
+endif
+ifeq ($(CONFIG_BOARD_HAS_HARD_RESET),y)
+ramstage-srcs += src/mainboard/$(MAINBOARDDIR)/reset.c
+endif
+ifeq ($(CONFIG_GENERATE_ACPI_TABLES),y)
+ramstage-srcs += src/mainboard/$(MAINBOARDDIR)/acpi_tables.c
+ramstage-srcs += src/mainboard/$(MAINBOARDDIR)/dsdt.asl
+# make doesn't have arithmetic operators or greater-than comparisons
+ifeq ($(subst 5,4,$(CONFIG_ACPI_SSDTX_NUM)),4)
+ramstage-srcs += src/mainboard/$(MAINBOARDDIR)/ssdt2.asl
+ramstage-srcs += src/mainboard/$(MAINBOARDDIR)/ssdt3.asl
+ramstage-srcs += src/mainboard/$(MAINBOARDDIR)/ssdt4.asl
+endif
+ifeq ($(CONFIG_ACPI_SSDTX_NUM),5)
+ramstage-srcs += src/mainboard/$(MAINBOARDDIR)/ssdt5.asl
+endif
+ifeq ($(CONFIG_BOARD_HAS_FADT),y)
+ramstage-srcs += src/mainboard/$(MAINBOARDDIR)/fadt.c
+endif
+endif
+
+ifeq ($(CONFIG_HAVE_BUS_CONFIG),y)
+ramstage-srcs += src/mainboard/$(MAINBOARDDIR)/get_bus_conf.c
+endif
+
+ifeq ($(CONFIG_TINY_BOOTBLOCK),y)
+include $(src)/arch/x86/Makefile.bootblock.inc
+else
+include $(src)/arch/x86/Makefile.bigbootblock.inc
+endif
diff --git a/src/arch/x86/acpi/debug.asl b/src/arch/x86/acpi/debug.asl
new file mode 100644
index 0000000000..bd5c9659e5
--- /dev/null
+++ b/src/arch/x86/acpi/debug.asl
@@ -0,0 +1,198 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2008 Advanced Micro Devices, Inc.
+ *
+ * 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
+ */
+
+/*
+ DefinitionBlock (
+ "DSDT.AML",
+ "DSDT",
+ 0x01,
+ "XXXXXX",
+ "XXXXXXXX",
+ 0x00010001
+ )
+ {
+ #include "debug.asl"
+ }
+*/
+
+/*
+* 0x80: POST_BASE
+* 0x3F8: DEBCOM_BASE
+* X80: POST_REGION
+* P80: PORT80
+*
+* CREG: DEBCOM_REGION
+* CUAR: DEBCOM_UART
+* CDAT: DEBCOM_DATA
+* CDLM: DEBCOM_DLM
+* DLCR: DEBCOM_LCR
+* CMCR: DEBCOM_MCR
+* CLSR: DEBCOM_LSR
+*
+* DEBUG_INIT DINI
+*/
+
+OperationRegion(X80, SystemIO, 0x80, 1)
+ Field(X80, ByteAcc, NoLock, Preserve)
+{
+ P80, 8
+}
+
+OperationRegion(CREG, SystemIO, 0x3F8, 8)
+ Field(CREG, ByteAcc, NoLock, Preserve)
+{
+ CDAT, 8,
+ CDLM, 8,, 8, DLCR, 8, CMCR, 8, CLSR, 8
+}
+
+/*
+* DINI
+* Initialize the COM port to 115,200 8-N-1
+*/
+Method(DINI)
+{
+ store(0x83, DLCR)
+ store(0x01, CDAT) /* 115200 baud (low) */
+ store(0x00, CDLM) /* 115200 baud (high) */
+ store(0x03, DLCR) /* word=8 stop=1 parity=none */
+ store(0x03, CMCR) /* DTR=1 RTS=1 Out2=Off Loop=Off */
+ store(0x00, CDLM) /* turn off interrupts */
+}
+
+/*
+* THRE
+* Wait for COM port transmitter holding register to go empty
+*/
+Method(THRE)
+{
+ and(CLSR, 0x20, local0)
+ while (Lequal(local0, Zero)) {
+ and(CLSR, 0x20, local0)
+ }
+}
+
+/*
+* OUTX
+* Send a single raw character
+*/
+Method(OUTX, 1)
+{
+ THRE()
+ store(Arg0, CDAT)
+}
+
+/*
+* OUTC
+* Send a single character, expanding LF into CR/LF
+*/
+Method(OUTC, 1)
+{
+ if (LEqual(Arg0, 0x0a)) {
+ OUTX(0x0d)
+ }
+ OUTX(Arg0)
+}
+
+/*
+* DBGN
+* Send a single hex nibble
+*/
+Method(DBGN, 1)
+{
+ and(Arg0, 0x0f, Local0)
+ if (LLess(Local0, 10)) {
+ add(Local0, 0x30, Local0)
+ } else {
+ add(Local0, 0x37, Local0)
+ }
+ OUTC(Local0)
+}
+
+/*
+* DBGB
+* Send a hex byte
+*/
+Method(DBGB, 1)
+{
+ ShiftRight(Arg0, 4, Local0)
+ DBGN(Local0)
+ DBGN(Arg0)
+}
+
+/*
+* DBGW
+* Send a hex word
+*/
+Method(DBGW, 1)
+{
+ ShiftRight(Arg0, 8, Local0)
+ DBGB(Local0)
+ DBGB(Arg0)
+}
+
+/*
+* DBGD
+* Send a hex Dword
+*/
+Method(DBGD, 1)
+{
+ ShiftRight(Arg0, 16, Local0)
+ DBGW(Local0)
+ DBGW(Arg0)
+}
+
+/*
+* DBGO
+* Send either a string or an integer
+*/
+Method(DBGO, 1)
+{
+ /* DINI() */
+ if (LEqual(ObjectType(Arg0), 1)) {
+ if (LGreater(Arg0, 0xffff)) {
+ DBGD(Arg0)
+ } else {
+ if (LGreater(Arg0, 0xff)) {
+ DBGW(Arg0)
+ } else {
+ DBGB(Arg0)
+ }
+ }
+ } else {
+ Name(BDBG, Buffer(80) {})
+ store(Arg0, BDBG)
+ store(0, Local1)
+ while (One) {
+ store(GETC(BDBG, Local1), Local0)
+ if (LEqual(Local0, 0)) {
+ return (0)
+ }
+ OUTC(Local0)
+ Increment(Local1)
+ }
+ }
+ return (0)
+}
+
+/* Get a char from a string */
+Method(GETC, 2)
+{
+ CreateByteField(Arg0, Arg1, DBGC)
+ return (DBGC)
+}
diff --git a/src/arch/x86/acpi/globutil.asl b/src/arch/x86/acpi/globutil.asl
new file mode 100644
index 0000000000..7e7f4e1e16
--- /dev/null
+++ b/src/arch/x86/acpi/globutil.asl
@@ -0,0 +1,118 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2008 Advanced Micro Devices, Inc.
+ *
+ * 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
+ */
+
+/*
+Scope(\_SB) {
+ #include "globutil.asl"
+}
+*/
+
+/* string compare functions */
+Method(MIN, 2)
+{
+ if (LLess(Arg0, Arg1)) {
+ Return(Arg0)
+ } else {
+ Return(Arg1)
+ }
+}
+
+Method(SLEN, 1)
+{
+ Store(Arg0, Local0)
+ Return(Sizeof(Local0))
+}
+
+Method(S2BF, 1)
+{
+ Add(SLEN(Arg0), One, Local0)
+ Name(BUFF, Buffer(Local0) {})
+ Store(Arg0, BUFF)
+ Return(BUFF)
+}
+
+/* Strong string compare. Checks both length and content */
+Method(SCMP, 2)
+{
+ Store(S2BF(Arg0), Local0)
+ Store(S2BF(Arg1), Local1)
+ Store(Zero, Local4)
+ Store(SLEN(Arg0), Local5)
+ Store(SLEN(Arg1), Local6)
+ Store(MIN(Local5, Local6), Local7)
+
+ While(LLess(Local4, Local7)) {
+ Store(Derefof(Index(Local0, Local4)), Local2)
+ Store(Derefof(Index(Local1, Local4)), Local3)
+ if (LGreater(Local2, Local3)) {
+ Return(One)
+ } else {
+ if (LLess(Local2, Local3)) {
+ Return(Ones)
+ }
+ }
+ Increment(Local4)
+ }
+ if (LLess(Local4, Local5)) {
+ Return(One)
+ } else {
+ if (LLess(Local4, Local6)) {
+ Return(Ones)
+ } else {
+ Return(Zero)
+ }
+ }
+}
+
+/* Weak string compare. Checks to find Arg1 at beginning of Arg0.
+* Fails if length(Arg0) < length(Arg1). Returns 0 on Fail, 1 on
+* Pass.
+*/
+Method(WCMP, 2)
+{
+ Store(S2BF(Arg0), Local0)
+ Store(S2BF(Arg1), Local1)
+ if (LLess(SLEN(Arg0), SLEN(Arg1))) {
+ Return(0)
+ }
+ Store(Zero, Local2)
+ Store(SLEN(Arg1), Local3)
+
+ While(LLess(Local2, Local3)) {
+ if (LNotEqual(Derefof(Index(Local0, Local2)),
+ Derefof(Index(Local1, Local2)))) {
+ Return(0)
+ }
+ Increment(Local2)
+ }
+ Return(One)
+}
+
+/* ARG0 = IRQ Number(0-15)
+* Returns Bit Map
+*/
+Method(I2BM, 1)
+{
+ Store(0, Local0)
+ if (LNotEqual(ARG0, 0)) {
+ Store(1, Local1)
+ ShiftLeft(Local1, ARG0, Local0)
+ }
+ Return(Local0)
+}
diff --git a/src/arch/x86/acpi/statdef.asl b/src/arch/x86/acpi/statdef.asl
new file mode 100644
index 0000000000..12a5932a12
--- /dev/null
+++ b/src/arch/x86/acpi/statdef.asl
@@ -0,0 +1,93 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2008 Advanced Micro Devices, Inc.
+ *
+ * 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
+ */
+
+
+/* Status and notification definitions */
+
+#define STA_MISSING 0x00
+#define STA_PRESENT 0x01
+#define STA_ENABLED 0x03
+#define STA_DISABLED 0x09
+#define STA_INVISIBLE 0x0B
+#define STA_UNAVAILABLE 0x0D
+#define STA_VISIBLE 0x0F
+
+/* SMBus status codes */
+#define SMB_OK 0x00
+#define SMB_UnknownFail 0x07
+#define SMB_DevAddrNAK 0x10
+#define SMB_DeviceError 0x11
+#define SMB_DevCmdDenied 0x12
+#define SMB_UnknownErr 0x13
+#define SMB_DevAccDenied 0x17
+#define SMB_Timeout 0x18
+#define SMB_HstUnsuppProtocol 0x19
+#define SMB_Busy 0x1A
+#define SMB_PktChkError 0x1F
+
+/* Device Object Notification Values */
+#define NOTIFY_BUS_CHECK 0x00
+#define NOTIFY_DEVICE_CHECK 0x01
+#define NOTIFY_DEVICE_WAKE 0x02
+#define NOTIFY_EJECT_REQUEST 0x03
+#define NOTIFY_DEVICE_CHECK_JR 0x04
+#define NOTIFY_FREQUENCY_ERROR 0x05
+#define NOTIFY_BUS_MODE 0x06
+#define NOTIFY_POWER_FAULT 0x07
+#define NOTIFY_CAPABILITIES 0x08
+#define NOTIFY_PLD_CHECK 0x09
+#define NOTIFY_SLIT_UPDATE 0x0B
+
+/* Battery Device Notification Values */
+#define NOTIFY_BAT_STATUSCHG 0x80
+#define NOTIFY_BAT_INFOCHG 0x81
+#define NOTIFY_BAT_MAINTDATA 0x82
+
+/* Power Source Object Notification Values */
+#define NOTIFY_PWR_STATUSCHG 0x80
+
+/* Thermal Zone Object Notification Values */
+#define NOTIFY_TZ_STATUSCHG 0x80
+#define NOTIFY_TZ_TRIPPTCHG 0x81
+#define NOTIFY_TZ_DEVLISTCHG 0x82
+#define NOTIFY_TZ_RELTBLCHG 0x83
+
+/* Power Button Notification Values */
+#define NOTIFY_POWER_BUTTON 0x80
+
+/* Sleep Button Notification Values */
+#define NOTIFY_SLEEP_BUTTON 0x80
+
+/* Lid Notification Values */
+#define NOTIFY_LID_STATUSCHG 0x80
+
+/* Processor Device Notification Values */
+#define NOTIFY_CPU_PPCCHG 0x80
+#define NOTIFY_CPU_CSTATECHG 0x81
+#define NOTIFY_CPU_THROTLCHG 0x82
+
+/* User Presence Device Notification Values */
+#define NOTIFY_USR_PRESNCECHG 0x80
+
+/* Battery Device Notification Values */
+#define NOTIFY_ALS_ILLUMCHG 0x80
+#define NOTIFY_ALS_COLORTMPCHG 0x81
+#define NOTIFY_ALS_RESPCHG 0x82
+
+
diff --git a/src/arch/x86/boot/Makefile.inc b/src/arch/x86/boot/Makefile.inc
new file mode 100644
index 0000000000..d4a377f74b
--- /dev/null
+++ b/src/arch/x86/boot/Makefile.inc
@@ -0,0 +1,13 @@
+ramstage-y += boot.c
+ramstage-y += coreboot_table.c
+ramstage-$(CONFIG_MULTIBOOT) += multiboot.c
+ramstage-y += gdt.c
+ramstage-y += tables.c
+ramstage-$(CONFIG_GENERATE_MP_TABLE) += mpspec.c
+ramstage-$(CONFIG_GENERATE_PIRQ_TABLE) += pirq_routing.c
+ramstage-$(CONFIG_GENERATE_ACPI_TABLES) += acpi.c
+ramstage-$(CONFIG_GENERATE_ACPI_TABLES) += acpigen.c
+ramstage-$(CONFIG_HAVE_ACPI_RESUME) += wakeup.S
+
+$(obj)/arch/x86/boot/coreboot_table.ramstage.o : $(OPTION_TABLE_H)
+
diff --git a/src/arch/x86/boot/acpi.c b/src/arch/x86/boot/acpi.c
new file mode 100644
index 0000000000..957ec4559a
--- /dev/null
+++ b/src/arch/x86/boot/acpi.c
@@ -0,0 +1,604 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * coreboot ACPI Table support
+ * written by Stefan Reinauer <stepan@openbios.org>
+ *
+ * Copyright (C) 2004 SUSE LINUX AG
+ * Copyright (C) 2005-2009 coresystems GmbH
+ *
+ * ACPI FADT, FACS, and DSDT table support added by
+ * Nick Barker <nick.barker9@btinternet.com>, and those portions
+ * Copyright (C) 2004 Nick Barker
+ *
+ * Copyright (C) 2005 ADVANCED MICRO DEVICES, INC. All Rights Reserved.
+ * 2005.9 yhlu add SRAT table generation
+ */
+
+/*
+ * Each system port implementing ACPI has to provide two functions:
+ *
+ * write_acpi_tables()
+ * acpi_dump_apics()
+ *
+ * See Kontron 986LCD-M port for a good example of an ACPI implementation
+ * in coreboot.
+ */
+
+#include <console/console.h>
+#include <string.h>
+#include <arch/acpi.h>
+#include <arch/acpigen.h>
+#include <device/pci.h>
+#include <cbmem.h>
+
+u8 acpi_checksum(u8 *table, u32 length)
+{
+ u8 ret = 0;
+ while (length--) {
+ ret += *table;
+ table++;
+ }
+ return -ret;
+}
+
+/**
+ * Add an ACPI table to the RSDT (and XSDT) structure, recalculate length
+ * and checksum.
+ */
+void acpi_add_table(acpi_rsdp_t *rsdp, void *table)
+{
+ int i, entries_num;
+ acpi_rsdt_t *rsdt;
+ acpi_xsdt_t *xsdt = NULL;
+
+ /* The RSDT is mandatory... */
+ rsdt = (acpi_rsdt_t *)rsdp->rsdt_address;
+
+ /* ...while the XSDT is not. */
+ if (rsdp->xsdt_address)
+ xsdt = (acpi_xsdt_t *)((u32)rsdp->xsdt_address);
+
+ /* This should always be MAX_ACPI_TABLES. */
+ entries_num = ARRAY_SIZE(rsdt->entry);
+
+ for (i = 0; i < entries_num; i++) {
+ if (rsdt->entry[i] == 0)
+ break;
+ }
+
+ if (i >= entries_num) {
+ printk(BIOS_ERR, "ACPI: Error: Could not add ACPI table, "
+ "too many tables.\n");
+ return;
+ }
+
+ /* Add table to the RSDT. */
+ rsdt->entry[i] = (u32)table;
+
+ /* Fix RSDT length or the kernel will assume invalid entries. */
+ rsdt->header.length = sizeof(acpi_header_t) + (sizeof(u32) * (i + 1));
+
+ /* Re-calculate checksum. */
+ rsdt->header.checksum = 0; /* Hope this won't get optimized away */
+ rsdt->header.checksum = acpi_checksum((u8 *)rsdt, rsdt->header.length);
+
+ /*
+ * And now the same thing for the XSDT. We use the same index as for
+ * now we want the XSDT and RSDT to always be in sync in coreboot.
+ */
+ if (xsdt) {
+ /* Add table to the XSDT. */
+ xsdt->entry[i] = (u64)(u32)table;
+
+ /* Fix XSDT length. */
+ xsdt->header.length = sizeof(acpi_header_t) +
+ (sizeof(u64) * (i + 1));
+
+ /* Re-calculate checksum. */
+ xsdt->header.checksum = 0;
+ xsdt->header.checksum = acpi_checksum((u8 *)xsdt,
+ xsdt->header.length);
+ }
+
+ printk(BIOS_DEBUG, "ACPI: added table %d/%d, length now %d\n",
+ i + 1, entries_num, rsdt->header.length);
+}
+
+int acpi_create_mcfg_mmconfig(acpi_mcfg_mmconfig_t *mmconfig, u32 base,
+ u16 seg_nr, u8 start, u8 end)
+{
+ mmconfig->base_address = base;
+ mmconfig->base_reserved = 0;
+ mmconfig->pci_segment_group_number = seg_nr;
+ mmconfig->start_bus_number = start;
+ mmconfig->end_bus_number = end;
+
+ return sizeof(acpi_mcfg_mmconfig_t);
+}
+
+int acpi_create_madt_lapic(acpi_madt_lapic_t *lapic, u8 cpu, u8 apic)
+{
+ lapic->type = 0; /* Local APIC structure */
+ lapic->length = sizeof(acpi_madt_lapic_t);
+ lapic->flags = (1 << 0); /* Processor/LAPIC enabled */
+ lapic->processor_id = cpu;
+ lapic->apic_id = apic;
+
+ return lapic->length;
+}
+
+unsigned long acpi_create_madt_lapics(unsigned long current)
+{
+ device_t cpu;
+ int cpu_index = 0;
+
+ for (cpu = all_devices; cpu; cpu = cpu->next) {
+ if ((cpu->path.type != DEVICE_PATH_APIC) ||
+ (cpu->bus->dev->path.type != DEVICE_PATH_APIC_CLUSTER)) {
+ continue;
+ }
+ if (!cpu->enabled)
+ continue;
+ current += acpi_create_madt_lapic((acpi_madt_lapic_t *)current,
+ cpu_index, cpu->path.apic.apic_id);
+ cpu_index++;
+ }
+
+ return current;
+}
+
+int acpi_create_madt_ioapic(acpi_madt_ioapic_t *ioapic, u8 id, u32 addr,
+ u32 gsi_base)
+{
+ ioapic->type = 1; /* I/O APIC structure */
+ ioapic->length = sizeof(acpi_madt_ioapic_t);
+ ioapic->reserved = 0x00;
+ ioapic->gsi_base = gsi_base;
+ ioapic->ioapic_id = id;
+ ioapic->ioapic_addr = addr;
+
+ return ioapic->length;
+}
+
+int acpi_create_madt_irqoverride(acpi_madt_irqoverride_t *irqoverride,
+ u8 bus, u8 source, u32 gsirq, u16 flags)
+{
+ irqoverride->type = 2; /* Interrupt source override */
+ irqoverride->length = sizeof(acpi_madt_irqoverride_t);
+ irqoverride->bus = bus;
+ irqoverride->source = source;
+ irqoverride->gsirq = gsirq;
+ irqoverride->flags = flags;
+
+ return irqoverride->length;
+}
+
+int acpi_create_madt_lapic_nmi(acpi_madt_lapic_nmi_t *lapic_nmi, u8 cpu,
+ u16 flags, u8 lint)
+{
+ lapic_nmi->type = 4; /* Local APIC NMI structure */
+ lapic_nmi->length = sizeof(acpi_madt_lapic_nmi_t);
+ lapic_nmi->flags = flags;
+ lapic_nmi->processor_id = cpu;
+ lapic_nmi->lint = lint;
+
+ return lapic_nmi->length;
+}
+
+void acpi_create_madt(acpi_madt_t *madt)
+{
+#define LOCAL_APIC_ADDR 0xfee00000ULL
+
+ acpi_header_t *header = &(madt->header);
+ unsigned long current = (unsigned long)madt + sizeof(acpi_madt_t);
+
+ memset((void *)madt, 0, sizeof(acpi_madt_t));
+
+ /* Fill out header fields. */
+ memcpy(header->signature, "APIC", 4);
+ memcpy(header->oem_id, OEM_ID, 6);
+ memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
+ memcpy(header->asl_compiler_id, ASLC, 4);
+
+ header->length = sizeof(acpi_madt_t);
+ header->revision = 1; /* ACPI 1.0/2.0: 1, ACPI 3.0: 2, ACPI 4.0: 3 */
+
+ madt->lapic_addr = LOCAL_APIC_ADDR;
+ madt->flags = 0x1; /* PCAT_COMPAT */
+
+ current = acpi_fill_madt(current);
+
+ /* (Re)calculate length and checksum. */
+ header->length = current - (unsigned long)madt;
+
+ header->checksum = acpi_checksum((void *)madt, header->length);
+}
+
+/* MCFG is defined in the PCI Firmware Specification 3.0. */
+void acpi_create_mcfg(acpi_mcfg_t *mcfg)
+{
+ acpi_header_t *header = &(mcfg->header);
+ unsigned long current = (unsigned long)mcfg + sizeof(acpi_mcfg_t);
+
+ memset((void *)mcfg, 0, sizeof(acpi_mcfg_t));
+
+ /* Fill out header fields. */
+ memcpy(header->signature, "MCFG", 4);
+ memcpy(header->oem_id, OEM_ID, 6);
+ memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
+ memcpy(header->asl_compiler_id, ASLC, 4);
+
+ header->length = sizeof(acpi_mcfg_t);
+ header->revision = 1;
+
+ current = acpi_fill_mcfg(current);
+
+ /* (Re)calculate length and checksum. */
+ header->length = current - (unsigned long)mcfg;
+ header->checksum = acpi_checksum((void *)mcfg, header->length);
+}
+
+/*
+ * This can be overriden by platform ACPI setup code, if it calls
+ * acpi_create_ssdt_generator().
+ */
+unsigned long __attribute__((weak)) acpi_fill_ssdt_generator(
+ unsigned long current, const char *oem_table_id)
+{
+ return current;
+}
+
+void acpi_create_ssdt_generator(acpi_header_t *ssdt, const char *oem_table_id)
+{
+ unsigned long current = (unsigned long)ssdt + sizeof(acpi_header_t);
+
+ memset((void *)ssdt, 0, sizeof(acpi_header_t));
+
+ memcpy(&ssdt->signature, "SSDT", 4);
+ ssdt->revision = 2; /* ACPI 1.0/2.0: ?, ACPI 3.0/4.0: 2 */
+ memcpy(&ssdt->oem_id, OEM_ID, 6);
+ memcpy(&ssdt->oem_table_id, oem_table_id, 8);
+ ssdt->oem_revision = 42;
+ memcpy(&ssdt->asl_compiler_id, ASLC, 4);
+ ssdt->asl_compiler_revision = 42;
+ ssdt->length = sizeof(acpi_header_t);
+
+ acpigen_set_current((char *) current);
+ current = acpi_fill_ssdt_generator(current, oem_table_id);
+
+ /* (Re)calculate length and checksum. */
+ ssdt->length = current - (unsigned long)ssdt;
+ ssdt->checksum = acpi_checksum((void *)ssdt, ssdt->length);
+}
+
+int acpi_create_srat_lapic(acpi_srat_lapic_t *lapic, u8 node, u8 apic)
+{
+ memset((void *)lapic, 0, sizeof(acpi_srat_lapic_t));
+
+ lapic->type = 0; /* Processor local APIC/SAPIC affinity structure */
+ lapic->length = sizeof(acpi_srat_lapic_t);
+ lapic->flags = (1 << 0); /* Enabled (the use of this structure). */
+ lapic->proximity_domain_7_0 = node;
+ /* TODO: proximity_domain_31_8, local SAPIC EID, clock domain. */
+ lapic->apic_id = apic;
+
+ return lapic->length;
+}
+
+int acpi_create_srat_mem(acpi_srat_mem_t *mem, u8 node, u32 basek, u32 sizek,
+ u32 flags)
+{
+ mem->type = 1; /* Memory affinity structure */
+ mem->length = sizeof(acpi_srat_mem_t);
+ mem->base_address_low = (basek << 10);
+ mem->base_address_high = (basek >> (32 - 10));
+ mem->length_low = (sizek << 10);
+ mem->length_high = (sizek >> (32 - 10));
+ mem->proximity_domain = node;
+ mem->flags = flags;
+
+ return mem->length;
+}
+
+/* http://www.microsoft.com/whdc/system/sysinternals/sratdwn.mspx */
+void acpi_create_srat(acpi_srat_t *srat)
+{
+ acpi_header_t *header = &(srat->header);
+ unsigned long current = (unsigned long)srat + sizeof(acpi_srat_t);
+
+ memset((void *)srat, 0, sizeof(acpi_srat_t));
+
+ /* Fill out header fields. */
+ memcpy(header->signature, "SRAT", 4);
+ memcpy(header->oem_id, OEM_ID, 6);
+ memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
+ memcpy(header->asl_compiler_id, ASLC, 4);
+
+ header->length = sizeof(acpi_srat_t);
+ header->revision = 1; /* ACPI 1.0: N/A, 2.0: 1, 3.0: 2, 4.0: 3 */
+
+ srat->resv = 1; /* Spec: Reserved to 1 for backwards compatibility. */
+
+ current = acpi_fill_srat(current);
+
+ /* (Re)calculate length and checksum. */
+ header->length = current - (unsigned long)srat;
+ header->checksum = acpi_checksum((void *)srat, header->length);
+}
+
+/* http://h21007.www2.hp.com/portal/download/files/unprot/Itanium/slit.pdf */
+void acpi_create_slit(acpi_slit_t *slit)
+{
+ acpi_header_t *header = &(slit->header);
+ unsigned long current = (unsigned long)slit + sizeof(acpi_slit_t);
+
+ memset((void *)slit, 0, sizeof(acpi_slit_t));
+
+ /* Fill out header fields. */
+ memcpy(header->signature, "SLIT", 4);
+ memcpy(header->oem_id, OEM_ID, 6);
+ memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
+ memcpy(header->asl_compiler_id, ASLC, 4);
+
+ header->length = sizeof(acpi_slit_t);
+ header->revision = 1; /* ACPI 1.0: N/A, ACPI 2.0/3.0/4.0: 1 */
+
+ current = acpi_fill_slit(current);
+
+ /* (Re)calculate length and checksum. */
+ header->length = current - (unsigned long)slit;
+ header->checksum = acpi_checksum((void *)slit, header->length);
+}
+
+/* http://www.intel.com/hardwaredesign/hpetspec_1.pdf */
+void acpi_create_hpet(acpi_hpet_t *hpet)
+{
+#define HPET_ADDR 0xfed00000ULL
+ acpi_header_t *header = &(hpet->header);
+ acpi_addr_t *addr = &(hpet->addr);
+
+ memset((void *)hpet, 0, sizeof(acpi_hpet_t));
+
+ /* Fill out header fields. */
+ memcpy(header->signature, "HPET", 4);
+ memcpy(header->oem_id, OEM_ID, 6);
+ memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
+ memcpy(header->asl_compiler_id, ASLC, 4);
+
+ header->length = sizeof(acpi_hpet_t);
+ header->revision = 1; /* Currently 1. Table added in ACPI 2.0. */
+
+ /* Fill out HPET address. */
+ addr->space_id = 0; /* Memory */
+ addr->bit_width = 64;
+ addr->bit_offset = 0;
+ addr->addrl = HPET_ADDR & 0xffffffff;
+ addr->addrh = HPET_ADDR >> 32;
+
+ hpet->id = 0x102282a0; /* AMD! FIXME */
+ hpet->number = 0;
+ hpet->min_tick = 4096;
+
+ header->checksum = acpi_checksum((void *)hpet, sizeof(acpi_hpet_t));
+}
+
+void acpi_create_facs(acpi_facs_t *facs)
+{
+ memset((void *)facs, 0, sizeof(acpi_facs_t));
+
+ memcpy(facs->signature, "FACS", 4);
+ facs->length = sizeof(acpi_facs_t);
+ facs->hardware_signature = 0;
+ facs->firmware_waking_vector = 0;
+ facs->global_lock = 0;
+ facs->flags = 0;
+ facs->x_firmware_waking_vector_l = 0;
+ facs->x_firmware_waking_vector_h = 0;
+ facs->version = 1; /* ACPI 1.0: 0, ACPI 2.0/3.0: 1, ACPI 4.0: 2 */
+}
+
+void acpi_write_rsdt(acpi_rsdt_t *rsdt)
+{
+ acpi_header_t *header = &(rsdt->header);
+
+ /* Fill out header fields. */
+ memcpy(header->signature, "RSDT", 4);
+ memcpy(header->oem_id, OEM_ID, 6);
+ memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
+ memcpy(header->asl_compiler_id, ASLC, 4);
+
+ header->length = sizeof(acpi_rsdt_t);
+ header->revision = 1; /* ACPI 1.0/2.0/3.0/4.0: 1 */
+
+ /* Entries are filled in later, we come with an empty set. */
+
+ /* Fix checksum. */
+ header->checksum = acpi_checksum((void *)rsdt, sizeof(acpi_rsdt_t));
+}
+
+void acpi_write_xsdt(acpi_xsdt_t *xsdt)
+{
+ acpi_header_t *header = &(xsdt->header);
+
+ /* Fill out header fields. */
+ memcpy(header->signature, "XSDT", 4);
+ memcpy(header->oem_id, OEM_ID, 6);
+ memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
+ memcpy(header->asl_compiler_id, ASLC, 4);
+
+ header->length = sizeof(acpi_xsdt_t);
+ header->revision = 1; /* ACPI 1.0: N/A, 2.0/3.0/4.0: 1 */
+
+ /* Entries are filled in later, we come with an empty set. */
+
+ /* Fix checksum. */
+ header->checksum = acpi_checksum((void *)xsdt, sizeof(acpi_xsdt_t));
+}
+
+void acpi_write_rsdp(acpi_rsdp_t *rsdp, acpi_rsdt_t *rsdt, acpi_xsdt_t *xsdt)
+{
+ memset(rsdp, 0, sizeof(acpi_rsdp_t));
+
+ memcpy(rsdp->signature, RSDP_SIG, 8);
+ memcpy(rsdp->oem_id, OEM_ID, 6);
+
+ rsdp->length = sizeof(acpi_rsdp_t);
+ rsdp->rsdt_address = (u32)rsdt;
+
+ /*
+ * Revision: ACPI 1.0: 0, ACPI 2.0/3.0/4.0: 2.
+ *
+ * Some OSes expect an XSDT to be present for RSD PTR revisions >= 2.
+ * If we don't have an ACPI XSDT, force ACPI 1.0 (and thus RSD PTR
+ * revision 0).
+ */
+ if (xsdt == NULL) {
+ rsdp->revision = 0;
+ } else {
+ rsdp->xsdt_address = (u64)(u32)xsdt;
+ rsdp->revision = 2;
+ }
+
+ /* Calculate checksums. */
+ rsdp->checksum = acpi_checksum((void *)rsdp, 20);
+ rsdp->ext_checksum = acpi_checksum((void *)rsdp, sizeof(acpi_rsdp_t));
+}
+
+#if CONFIG_HAVE_ACPI_RESUME == 1
+void suspend_resume(void)
+{
+ void *wake_vec;
+
+ /* If we happen to be resuming find wakeup vector and jump to OS. */
+ wake_vec = acpi_find_wakeup_vector();
+ if (wake_vec)
+ acpi_jump_to_wakeup(wake_vec);
+}
+
+/* This is to be filled by SB code - startup value what was found. */
+u8 acpi_slp_type = 0;
+
+static int acpi_is_wakeup(void)
+{
+ return (acpi_slp_type == 3);
+}
+
+static acpi_rsdp_t *valid_rsdp(acpi_rsdp_t *rsdp)
+{
+ if (strncmp((char *)rsdp, RSDP_SIG, sizeof(RSDP_SIG) - 1) != 0)
+ return NULL;
+
+ printk(BIOS_DEBUG, "Looking on %p for valid checksum\n", rsdp);
+
+ if (acpi_checksum((void *)rsdp, 20) != 0)
+ return NULL;
+ printk(BIOS_DEBUG, "Checksum 1 passed\n");
+
+ if ((rsdp->revision > 1) && (acpi_checksum((void *)rsdp,
+ rsdp->length) != 0))
+ return NULL;
+ printk(BIOS_DEBUG, "Checksum 2 passed all OK\n");
+
+ return rsdp;
+}
+
+static acpi_rsdp_t *rsdp;
+
+void *acpi_get_wakeup_rsdp(void)
+{
+ return rsdp;
+}
+
+void *acpi_find_wakeup_vector(void)
+{
+ char *p, *end;
+ acpi_rsdt_t *rsdt;
+ acpi_facs_t *facs;
+ acpi_fadt_t *fadt;
+ void *wake_vec;
+ int i;
+
+ rsdp = NULL;
+
+ if (!acpi_is_wakeup())
+ return NULL;
+
+ printk(BIOS_DEBUG, "Trying to find the wakeup vector...\n");
+
+ /* Find RSDP. */
+ for (p = (char *)0xe0000; p < (char *)0xfffff; p += 16) {
+ if ((rsdp = valid_rsdp((acpi_rsdp_t *)p)))
+ break;
+ }
+
+ if (rsdp == NULL)
+ return NULL;
+
+ printk(BIOS_DEBUG, "RSDP found at %p\n", rsdp);
+ rsdt = (acpi_rsdt_t *) rsdp->rsdt_address;
+
+ end = (char *)rsdt + rsdt->header.length;
+ printk(BIOS_DEBUG, "RSDT found at %p ends at %p\n", rsdt, end);
+
+ for (i = 0; ((char *)&rsdt->entry[i]) < end; i++) {
+ fadt = (acpi_fadt_t *)rsdt->entry[i];
+ if (strncmp((char *)fadt, "FACP", 4) == 0)
+ break;
+ fadt = NULL;
+ }
+
+ if (fadt == NULL)
+ return NULL;
+
+ printk(BIOS_DEBUG, "FADT found at %p\n", fadt);
+ facs = (acpi_facs_t *)fadt->firmware_ctrl;
+
+ if (facs == NULL) {
+ printk(BIOS_DEBUG, "No FACS found, wake up from S3 not "
+ "possible.\n");
+ return NULL;
+ }
+
+ printk(BIOS_DEBUG, "FACS found at %p\n", facs);
+ wake_vec = (void *)facs->firmware_waking_vector;
+ printk(BIOS_DEBUG, "OS waking vector is %p\n", wake_vec);
+
+ return wake_vec;
+}
+
+extern char *lowmem_backup;
+extern char *lowmem_backup_ptr;
+extern int lowmem_backup_size;
+
+#define WAKEUP_BASE 0x600
+
+void (*acpi_do_wakeup)(u32 vector, u32 backup_source, u32 backup_target,
+ u32 backup_size) __attribute__((regparm(0))) = (void *)WAKEUP_BASE;
+
+extern unsigned char __wakeup, __wakeup_size;
+
+void acpi_jump_to_wakeup(void *vector)
+{
+ u32 acpi_backup_memory = (u32)cbmem_find(CBMEM_ID_RESUME);
+
+ if (!acpi_backup_memory) {
+ printk(BIOS_WARNING, "ACPI: Backup memory missing. "
+ "No S3 resume.\n");
+ return;
+ }
+
+ // FIXME: This should go into the ACPI backup memory, too. No pork saussages.
+ /*
+ * Just restore the SMP trampoline and continue with wakeup on
+ * assembly level.
+ */
+ memcpy(lowmem_backup_ptr, lowmem_backup, lowmem_backup_size);
+
+ /* Copy wakeup trampoline in place. */
+ memcpy((void *)WAKEUP_BASE, &__wakeup, (size_t)&__wakeup_size);
+
+ acpi_do_wakeup((u32)vector, acpi_backup_memory, CONFIG_RAMBASE,
+ HIGH_MEMORY_SAVE);
+}
+#endif
diff --git a/src/arch/x86/boot/acpigen.c b/src/arch/x86/boot/acpigen.c
new file mode 100644
index 0000000000..e8cd724e23
--- /dev/null
+++ b/src/arch/x86/boot/acpigen.c
@@ -0,0 +1,517 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2009 Rudolf Marek <r.marek@assembler.cz>
+ *
+ * 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
+ */
+
+/* how many nesting we support */
+#define ACPIGEN_LENSTACK_SIZE 10
+
+/* if you need to change this, change the acpigen_write_f and
+ acpigen_patch_len */
+
+#define ACPIGEN_MAXLEN 0xfff
+
+#include <string.h>
+#include <arch/acpigen.h>
+#include <console/console.h>
+#include <device/device.h>
+
+static char *gencurrent;
+
+char *len_stack[ACPIGEN_LENSTACK_SIZE];
+int ltop = 0;
+
+static int acpigen_write_len_f(void)
+{
+ ASSERT(ltop < (ACPIGEN_LENSTACK_SIZE - 1))
+ len_stack[ltop++] = gencurrent;
+ acpigen_emit_byte(0);
+ acpigen_emit_byte(0);
+ return 2;
+}
+
+void acpigen_patch_len(int len)
+{
+ ASSERT(len <= ACPIGEN_MAXLEN)
+ ASSERT(ltop > 0)
+ char *p = len_stack[--ltop];
+ /* generate store length for 0xfff max */
+ p[0] = (0x40 | (len & 0xf));
+ p[1] = (len >> 4 & 0xff);
+
+}
+
+void acpigen_set_current(char *curr)
+{
+ gencurrent = curr;
+}
+
+char *acpigen_get_current(void)
+{
+ return gencurrent;
+}
+
+int acpigen_emit_byte(unsigned char b)
+{
+ (*gencurrent++) = b;
+ return 1;
+}
+
+int acpigen_write_package(int nr_el)
+{
+ int len;
+ /* package op */
+ acpigen_emit_byte(0x12);
+ len = acpigen_write_len_f();
+ acpigen_emit_byte(nr_el);
+ return len + 2;
+}
+
+int acpigen_write_byte(unsigned int data)
+{
+ /* byte op */
+ acpigen_emit_byte(0xa);
+ acpigen_emit_byte(data & 0xff);
+ return 2;
+}
+
+int acpigen_write_dword(unsigned int data)
+{
+ /* dword op */
+ acpigen_emit_byte(0xc);
+ acpigen_emit_byte(data & 0xff);
+ acpigen_emit_byte((data >> 8) & 0xff);
+ acpigen_emit_byte((data >> 16) & 0xff);
+ acpigen_emit_byte((data >> 24) & 0xff);
+ return 5;
+}
+
+int acpigen_write_qword(uint64_t data)
+{
+ /* qword op */
+ acpigen_emit_byte(0xe);
+ acpigen_emit_byte(data & 0xff);
+ acpigen_emit_byte((data >> 8) & 0xff);
+ acpigen_emit_byte((data >> 16) & 0xff);
+ acpigen_emit_byte((data >> 24) & 0xff);
+ acpigen_emit_byte((data >> 32) & 0xff);
+ acpigen_emit_byte((data >> 40) & 0xff);
+ acpigen_emit_byte((data >> 48) & 0xff);
+ acpigen_emit_byte((data >> 56) & 0xff);
+ return 9;
+}
+
+int acpigen_write_name_byte(const char *name, uint8_t val)
+{
+ int len;
+ len = acpigen_write_name(name);
+ len += acpigen_write_byte(val);
+ return len;
+}
+
+int acpigen_write_name_dword(const char *name, uint32_t val)
+{
+ int len;
+ len = acpigen_write_name(name);
+ len += acpigen_write_dword(val);
+ return len;
+}
+
+int acpigen_write_name_qword(const char *name, uint64_t val)
+{
+ int len;
+ len = acpigen_write_name(name);
+ len += acpigen_write_qword(val);
+ return len;
+}
+
+int acpigen_emit_stream(const char *data, int size)
+{
+ int i;
+ for (i = 0; i < size; i++) {
+ acpigen_emit_byte(data[i]);
+ }
+ return size;
+}
+
+/* The NameString are bit tricky, each element can be 4 chars, if
+ less its padded with underscore. Check 18.2.2 and 18.4
+ and 5.3 of ACPI specs 3.0 for details
+*/
+
+static int acpigen_emit_simple_namestring(const char *name) {
+ int i, len = 0;
+ char ud[] = "____";
+ for (i = 0; i < 4; i++) {
+ if ((name[i] == '\0') || (name[i] == '.')) {
+ len += acpigen_emit_stream(ud, 4 - i);
+ break;
+ } else {
+ len += acpigen_emit_byte(name[i]);
+ }
+ }
+ return len;
+}
+
+static int acpigen_emit_double_namestring(const char *name, int dotpos) {
+ int len = 0;
+ /* mark dual name prefix */
+ len += acpigen_emit_byte(0x2e);
+ len += acpigen_emit_simple_namestring(name);
+ len += acpigen_emit_simple_namestring(&name[dotpos + 1]);
+ return len;
+}
+
+static int acpigen_emit_multi_namestring(const char *name) {
+ int len = 0, count = 0;
+ unsigned char *pathlen;
+ /* mark multi name prefix */
+ len += acpigen_emit_byte(0x2f);
+ len += acpigen_emit_byte(0x0);
+ pathlen = ((unsigned char *) acpigen_get_current()) - 1;
+
+ while (name[0] != '\0') {
+ len += acpigen_emit_simple_namestring(name);
+ /* find end or next entity */
+ while ((name[0] != '.') && (name[0] != '\0'))
+ name++;
+ /* forward to next */
+ if (name[0] == '.')
+ name++;
+ count++;
+ }
+
+ pathlen[0] = count;
+ return len;
+}
+
+
+int acpigen_emit_namestring(const char *namepath) {
+ int dotcount = 0, i;
+ int dotpos = 0;
+ int len = 0;
+
+ /* we can start with a \ */
+ if (namepath[0] == '\\') {
+ len += acpigen_emit_byte('\\');
+ namepath++;
+ }
+
+ /* and there can be any number of ^ */
+ while (namepath[0] == '^') {
+ len += acpigen_emit_byte('^');
+ namepath++;
+ }
+
+ ASSERT(namepath[0] != '\0');
+
+ i = 0;
+ while (namepath[i] != '\0') {
+ if (namepath[i] == '.') {
+ dotcount++;
+ dotpos = i;
+ }
+ i++;
+ }
+
+ if (dotcount == 0) {
+ len += acpigen_emit_simple_namestring(namepath);
+ } else if (dotcount == 1) {
+ len += acpigen_emit_double_namestring(namepath, dotpos);
+ } else {
+ len += acpigen_emit_multi_namestring(namepath);
+ }
+ return len;
+}
+
+int acpigen_write_name(const char *name)
+{
+ int len;
+ /* name op */
+ len = acpigen_emit_byte(0x8);
+ return len + acpigen_emit_namestring(name);
+}
+
+int acpigen_write_scope(const char *name)
+{
+ int len;
+ /* scope op */
+ len = acpigen_emit_byte(0x10);
+ len += acpigen_write_len_f();
+ return len + acpigen_emit_namestring(name);
+}
+
+int acpigen_write_processor(u8 cpuindex, u32 pblock_addr, u8 pblock_len)
+{
+/*
+ Processor (\_PR.CPUcpuindex, cpuindex, pblock_addr, pblock_len)
+ {
+*/
+ char pscope[16];
+ int len;
+ /* processor op */
+ acpigen_emit_byte(0x5b);
+ acpigen_emit_byte(0x83);
+ len = acpigen_write_len_f();
+
+ sprintf(pscope, "\\_PR.CPU%x", (unsigned int) cpuindex);
+ len += acpigen_emit_namestring(pscope);
+ acpigen_emit_byte(cpuindex);
+ acpigen_emit_byte(pblock_addr & 0xff);
+ acpigen_emit_byte((pblock_addr >> 8) & 0xff);
+ acpigen_emit_byte((pblock_addr >> 16) & 0xff);
+ acpigen_emit_byte((pblock_addr >> 24) & 0xff);
+ acpigen_emit_byte(pblock_len);
+ return 6 + 2 + len;
+}
+
+int acpigen_write_empty_PCT(void)
+{
+/*
+ Name (_PCT, Package (0x02)
+ {
+ ResourceTemplate ()
+ {
+ Register (FFixedHW,
+ 0x00, // Bit Width
+ 0x00, // Bit Offset
+ 0x0000000000000000, // Address
+ ,)
+ },
+
+ ResourceTemplate ()
+ {
+ Register (FFixedHW,
+ 0x00, // Bit Width
+ 0x00, // Bit Offset
+ 0x0000000000000000, // Address
+ ,)
+ }
+ })
+*/
+ static char stream[] = {
+ 0x08, 0x5F, 0x50, 0x43, 0x54, 0x12, 0x2C, /* 00000030 "0._PCT.," */
+ 0x02, 0x11, 0x14, 0x0A, 0x11, 0x82, 0x0C, 0x00, /* 00000038 "........" */
+ 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00000040 "........" */
+ 0x00, 0x00, 0x00, 0x00, 0x79, 0x00, 0x11, 0x14, /* 00000048 "....y..." */
+ 0x0A, 0x11, 0x82, 0x0C, 0x00, 0x7F, 0x00, 0x00, /* 00000050 "........" */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00000058 "........" */
+ 0x00, 0x79, 0x00
+ };
+ return acpigen_emit_stream(stream, ARRAY_SIZE(stream));
+}
+
+/* generates a func with max supported P states */
+int acpigen_write_PPC(u8 nr)
+{
+/*
+ Method (_PPC, 0, NotSerialized)
+ {
+ Return (nr)
+ }
+*/
+ int len;
+ /* method op */
+ acpigen_emit_byte(0x14);
+ len = acpigen_write_len_f();
+ len += acpigen_emit_namestring("_PPC");
+ /* no fnarg */
+ acpigen_emit_byte(0x00);
+ /* return */
+ acpigen_emit_byte(0xa4);
+ /* arg */
+ len += acpigen_write_byte(nr);
+ /* add all single bytes */
+ len += 3;
+ acpigen_patch_len(len - 1);
+ return len;
+}
+
+int acpigen_write_PSS_package(u32 coreFreq, u32 power, u32 transLat,
+ u32 busmLat, u32 control, u32 status)
+{
+ int len;
+ len = acpigen_write_package(6);
+ len += acpigen_write_dword(coreFreq);
+ len += acpigen_write_dword(power);
+ len += acpigen_write_dword(transLat);
+ len += acpigen_write_dword(busmLat);
+ len += acpigen_write_dword(control);
+ len += acpigen_write_dword(status);
+ //pkglen without the len opcode
+ acpigen_patch_len(len - 1);
+ return len;
+}
+
+int acpigen_write_PSD_package(u32 domain, u32 numprocs, PSD_coord coordtype)
+{
+ int len, lenh, lenp;
+ lenh = acpigen_write_name("_PSD");
+ lenp = acpigen_write_package(1);
+ len = acpigen_write_package(5);
+ len += acpigen_write_byte(5); // 5 values
+ len += acpigen_write_byte(0); // revision 0
+ len += acpigen_write_dword(domain);
+ len += acpigen_write_dword(coordtype);
+ len += acpigen_write_dword(numprocs);
+ acpigen_patch_len(len - 1);
+ len += lenp;
+ acpigen_patch_len(len - 1);
+ return len + lenh;
+}
+
+int acpigen_write_mem32fixed(int readwrite, u32 base, u32 size)
+{
+ /*
+ * acpi 4.0 section 6.4.3.4: 32-Bit Fixed Memory Range Descriptor
+ * Byte 0:
+ * Bit7 : 1 => big item
+ * Bit6-0: 0000110 (0x6) => 32-bit fixed memory
+ */
+ acpigen_emit_byte(0x86);
+ /* Byte 1+2: length (0x0009) */
+ acpigen_emit_byte(0x09);
+ acpigen_emit_byte(0x00);
+ /* bit1-7 are ignored */
+ acpigen_emit_byte(readwrite ? 0x01 : 0x00);
+ acpigen_emit_byte(base & 0xff);
+ acpigen_emit_byte((base >> 8) & 0xff);
+ acpigen_emit_byte((base >> 16) & 0xff);
+ acpigen_emit_byte((base >> 24) & 0xff);
+ acpigen_emit_byte(size & 0xff);
+ acpigen_emit_byte((size >> 8) & 0xff);
+ acpigen_emit_byte((size >> 16) & 0xff);
+ acpigen_emit_byte((size >> 24) & 0xff);
+ return 12;
+}
+
+int acpigen_write_io16(u16 min, u16 max, u8 align, u8 len, u8 decode16)
+{
+ /*
+ * acpi 4.0 section 6.4.2.6: I/O Port Descriptor
+ * Byte 0:
+ * Bit7 : 0 => small item
+ * Bit6-3: 1000 (0x8) => I/O port descriptor
+ * Bit2-0: 111 (0x7) => 7 Bytes long
+ */
+ acpigen_emit_byte(0x47);
+ /* does the device decode all 16 or just 10 bits? */
+ /* bit1-7 are ignored */
+ acpigen_emit_byte(decode16 ? 0x01 : 0x00);
+ /* minimum base address the device may be configured for */
+ acpigen_emit_byte(min & 0xff);
+ acpigen_emit_byte((min >> 8) & 0xff);
+ /* maximum base address the device may be configured for */
+ acpigen_emit_byte(max & 0xff);
+ acpigen_emit_byte((max >> 8) & 0xff);
+ /* alignment for min base */
+ acpigen_emit_byte(align & 0xff);
+ acpigen_emit_byte(len & 0xff);
+ return 8;
+}
+
+int acpigen_write_resourcetemplate_header(void)
+{
+ int len;
+ /*
+ * A ResourceTemplate() is a Buffer() with a
+ * (Byte|Word|DWord) containing the length, followed by one or more
+ * resource items, terminated by the end tag
+ * (small item 0xf, len 1)
+ */
+ len = acpigen_emit_byte(0x11); /* Buffer opcode */
+ len += acpigen_write_len_f();
+ len += acpigen_emit_byte(0x0b); /* Word opcode */
+ len_stack[ltop++] = acpigen_get_current();
+ len += acpigen_emit_byte(0x00);
+ len += acpigen_emit_byte(0x00);
+ return len;
+}
+
+int acpigen_write_resourcetemplate_footer(int len)
+{
+ char *p = len_stack[--ltop];
+ /*
+ * end tag (acpi 4.0 Section 6.4.2.8)
+ * 0x79 <checksum>
+ * 0x00 is treated as a good checksum according to the spec
+ * and is what iasl generates.
+ */
+ len += acpigen_emit_byte(0x79);
+ len += acpigen_emit_byte(0x00);
+ /* patch len word */
+ p[0] = (len-6) & 0xff;
+ p[1] = ((len-6) >> 8) & 0xff;
+ /* patch len field */
+ acpigen_patch_len(len-1);
+ return 2;
+}
+
+static void acpigen_add_mainboard_rsvd_mem32(void *gp, struct device *dev,
+ struct resource *res)
+{
+ acpigen_write_mem32fixed(0, res->base, res->size);
+}
+
+static void acpigen_add_mainboard_rsvd_io(void *gp, struct device *dev,
+ struct resource *res)
+{
+ resource_t base = res->base;
+ resource_t size = res->size;
+ while (size > 0) {
+ resource_t sz = size > 255 ? 255 : size;
+ acpigen_write_io16(base, base, 0, sz, 1);
+ size -= sz;
+ base += sz;
+ }
+}
+
+int acpigen_write_mainboard_resource_template(void)
+{
+ int len;
+ char *start;
+ char *end;
+ len = acpigen_write_resourcetemplate_header();
+ start = acpigen_get_current();
+
+ /* Add reserved memory ranges */
+ search_global_resources(
+ IORESOURCE_MEM | IORESOURCE_RESERVE,
+ IORESOURCE_MEM | IORESOURCE_RESERVE,
+ acpigen_add_mainboard_rsvd_mem32, 0);
+
+ /* Add reserved io ranges */
+ search_global_resources(
+ IORESOURCE_IO | IORESOURCE_RESERVE,
+ IORESOURCE_IO | IORESOURCE_RESERVE,
+ acpigen_add_mainboard_rsvd_io, 0);
+
+ end = acpigen_get_current();
+ len += end-start;
+ len += acpigen_write_resourcetemplate_footer(len);
+ return len;
+}
+
+int acpigen_write_mainboard_resources(const char *scope, const char *name)
+{
+ int len;
+ len = acpigen_write_scope(scope);
+ len += acpigen_write_name(name);
+ len += acpigen_write_mainboard_resource_template();
+ acpigen_patch_len(len - 1);
+ return len;
+}
diff --git a/src/arch/x86/boot/boot.c b/src/arch/x86/boot/boot.c
new file mode 100644
index 0000000000..d9cb02e776
--- /dev/null
+++ b/src/arch/x86/boot/boot.c
@@ -0,0 +1,186 @@
+#include <console/console.h>
+#include <ip_checksum.h>
+#include <boot/elf.h>
+#include <boot/elf_boot.h>
+#include <string.h>
+#include <cpu/x86/multiboot.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, unsigned long size)
+{
+ extern unsigned char _ram_seg, _eram_seg;
+ unsigned long lb_start, lb_size;
+ unsigned long adjust, adjusted_boot_notes;
+
+ elf_boot_notes.hdr.b_checksum =
+ compute_ip_checksum(&elf_boot_notes, sizeof(elf_boot_notes));
+
+ lb_start = (unsigned long)&_ram_seg;
+ lb_size = (unsigned long)(&_eram_seg - &_ram_seg);
+ adjust = buffer + size - lb_start;
+
+ adjusted_boot_notes = (unsigned long)&elf_boot_notes;
+ adjusted_boot_notes += adjust;
+
+ printk(BIOS_SPEW, "entry = 0x%08lx\n", (unsigned long)entry);
+ printk(BIOS_SPEW, "lb_start = 0x%08lx\n", lb_start);
+ printk(BIOS_SPEW, "lb_size = 0x%08lx\n", lb_size);
+ printk(BIOS_SPEW, "adjust = 0x%08lx\n", adjust);
+ printk(BIOS_SPEW, "buffer = 0x%08lx\n", buffer);
+ printk(BIOS_SPEW, " elf_boot_notes = 0x%08lx\n", (unsigned long)&elf_boot_notes);
+ printk(BIOS_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 coreboot in its new location */
+ /* Move ``longs'' the coreboot 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 coreboot image */
+ " addl 20(%%esp), %%esp\n\t"
+ /* Adjust the instruction pointer to point into the new coreboot image */
+ " movl $1f, %%eax\n\t"
+ " addl 20(%%esp), %%eax\n\t"
+ " jmp *%%eax\n\t"
+ "1: \n\t"
+
+ /* Copy the coreboot bounce buffer over coreboot */
+ /* Move ``longs'' the coreboot 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 %5, %%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 coreboot where coreboot runs */
+ /* Move ``longs'' the coreboot 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 coreboot image */
+ " subl 20(%%esp), %%esp\n\t"
+
+ /* Adjust the instruction pointer to point into the old coreboot 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"
+
+ ::
+ "ri" (lb_start), "ri" (buffer), "ri" (lb_size),
+ "ri" (entry),
+#if CONFIG_MULTIBOOT
+ "ri"(mbi), "ri" (MB_MAGIC2)
+#else
+ "ri"(adjusted_boot_notes), "ri" (0x0E1FB007)
+#endif
+ );
+}
+
+
diff --git a/src/arch/x86/boot/coreboot_table.c b/src/arch/x86/boot/coreboot_table.c
new file mode 100644
index 0000000000..484340c96a
--- /dev/null
+++ b/src/arch/x86/boot/coreboot_table.c
@@ -0,0 +1,600 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2003-2004 Eric Biederman
+ * Copyright (C) 2005-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 <console/console.h>
+#include <ip_checksum.h>
+#include <boot/tables.h>
+#include <boot/coreboot_tables.h>
+#include <arch/coreboot_tables.h>
+#include <string.h>
+#include <version.h>
+#include <device/device.h>
+#include <stdlib.h>
+#if (CONFIG_USE_OPTION_TABLE == 1)
+#include <option_table.h>
+#endif
+
+static 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;
+}
+
+static struct lb_record *lb_first_record(struct lb_header *header)
+{
+ struct lb_record *rec;
+ rec = (void *)(((char *)header) + sizeof(*header));
+ return rec;
+}
+
+static 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;
+}
+
+#if 0
+static struct lb_record *lb_next_record(struct lb_record *rec)
+{
+ rec = (void *)(((char *)rec) + rec->size);
+ return rec;
+}
+#endif
+
+static 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;
+}
+
+
+static 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;
+}
+
+static struct lb_serial *lb_serial(struct lb_header *header)
+{
+#if CONFIG_CONSOLE_SERIAL8250
+ struct lb_record *rec;
+ struct lb_serial *serial;
+ rec = lb_new_record(header);
+ serial = (struct lb_serial *)rec;
+ serial->tag = LB_TAG_SERIAL;
+ serial->size = sizeof(*serial);
+ serial->ioport = CONFIG_TTYS0_BASE;
+ serial->baud = CONFIG_TTYS0_BAUD;
+ return serial;
+#else
+ return header;
+#endif
+}
+
+static void add_console(struct lb_header *header, u16 consoletype)
+{
+ struct lb_console *console;
+
+ console = (struct lb_console *)lb_new_record(header);
+ console->tag = LB_TAG_CONSOLE;
+ console->size = sizeof(*console);
+ console->type = consoletype;
+}
+
+static void lb_console(struct lb_header *header)
+{
+#if CONFIG_CONSOLE_SERIAL8250
+ add_console(header, LB_TAG_CONSOLE_SERIAL8250);
+#endif
+#if CONFIG_CONSOLE_LOGBUF
+ add_console(header, LB_TAG_CONSOLE_LOGBUF);
+#endif
+#if CONFIG_USBDEBUG
+ add_console(header, LB_TAG_CONSOLE_EHCI);
+#endif
+}
+
+static void lb_framebuffer(struct lb_header *header)
+{
+#if defined(CONFIG_BOOTSPLASH) && CONFIG_BOOTSPLASH && CONFIG_COREBOOT_KEEP_FRAMEBUFFER
+ void fill_lb_framebuffer(struct lb_framebuffer *framebuffer);
+
+ struct lb_framebuffer *framebuffer;
+ framebuffer = (struct lb_framebuffer *)lb_new_record(header);
+ framebuffer->tag = LB_TAG_FRAMEBUFFER;
+ framebuffer->size = sizeof(*framebuffer);
+ fill_lb_framebuffer(framebuffer);
+#endif
+}
+
+static 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;
+}
+
+#if (CONFIG_USE_OPTION_TABLE == 1)
+static struct cmos_checksum *lb_cmos_checksum(struct lb_header *header)
+{
+ struct lb_record *rec;
+ struct cmos_checksum *cmos_checksum;
+ rec = lb_new_record(header);
+ cmos_checksum = (struct cmos_checksum *)rec;
+ cmos_checksum->tag = LB_TAG_OPTION_CHECKSUM;
+
+ cmos_checksum->size = (sizeof(*cmos_checksum));
+
+ cmos_checksum->range_start = LB_CKS_RANGE_START * 8;
+ cmos_checksum->range_end = ( LB_CKS_RANGE_END * 8 ) + 7;
+ cmos_checksum->location = LB_CKS_LOC * 8;
+ cmos_checksum->type = CHECKSUM_PCBIOS;
+
+ return cmos_checksum;
+}
+#endif
+
+static void lb_strings(struct lb_header *header)
+{
+ static const struct {
+ uint32_t tag;
+ const char *string;
+ } strings[] = {
+ { LB_TAG_VERSION, coreboot_version, },
+ { LB_TAG_EXTRA_VERSION, coreboot_extra_version, },
+ { LB_TAG_BUILD, coreboot_build, },
+ { LB_TAG_COMPILE_TIME, coreboot_compile_time, },
+ { LB_TAG_COMPILE_BY, coreboot_compile_by, },
+ { LB_TAG_COMPILE_HOST, coreboot_compile_host, },
+ { LB_TAG_COMPILE_DOMAIN, coreboot_compile_domain, },
+ { LB_TAG_COMPILER, coreboot_compiler, },
+ { LB_TAG_LINKER, coreboot_linker, },
+ { LB_TAG_ASSEMBLER, coreboot_assembler, },
+ };
+ unsigned int i;
+ for(i = 0; i < ARRAY_SIZE(strings); 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);
+ }
+
+}
+
+#if CONFIG_WRITE_HIGH_TABLES == 1
+static struct lb_forward *lb_forward(struct lb_header *header, struct lb_header *next_header)
+{
+ struct lb_record *rec;
+ struct lb_forward *forward;
+ rec = lb_new_record(header);
+ forward = (struct lb_forward *)rec;
+ forward->tag = LB_TAG_FORWARD;
+ forward->size = sizeof(*forward);
+ forward->forward = (uint64_t)(unsigned long)next_header;
+ return forward;
+}
+#endif
+
+void lb_memory_range(struct lb_memory *mem,
+ uint32_t type, uint64_t start, uint64_t size)
+{
+ int entries;
+ entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
+ mem->map[entries].start = pack_lb64(start);
+ mem->map[entries].size = pack_lb64(size);
+ 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 = unpack_lb64(mem->map[i].start);
+ uint64_t map_end = map_start + unpack_lb64(mem->map[i].size);
+ /* Does this area need to be expanded? */
+ if (map_end == start) {
+ mem->map[i].size = pack_lb64(end - map_start);
+ }
+ /* Does this area need to be contracted? */
+ else if (map_start == start) {
+ mem->map[i].start = pack_lb64(end);
+ mem->map[i].size = pack_lb64(map_end - end);
+ }
+ }
+}
+
+static unsigned long lb_table_fini(struct lb_header *head, int fixup)
+{
+ struct lb_record *rec, *first_rec;
+ rec = lb_last_record(head);
+ if (head->table_entries) {
+ head->table_bytes += rec->size;
+ }
+
+ if (fixup)
+ 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(BIOS_DEBUG, "Wrote coreboot table at: %p - %p checksum %x\n",
+ head, rec, head->table_checksum);
+ return (unsigned long)rec;
+}
+
+static void lb_cleanup_memory_ranges(struct lb_memory *mem)
+{
+ int entries;
+ int i, j;
+ entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
+
+ /* Sort the lb memory ranges */
+ for(i = 0; i < entries; i++) {
+ uint64_t entry_start = unpack_lb64(mem->map[i].start);
+ for(j = i; j < entries; j++) {
+ uint64_t temp_start = unpack_lb64(mem->map[j].start);
+ if (temp_start < entry_start) {
+ struct lb_memory_range tmp;
+ tmp = mem->map[i];
+ mem->map[i] = mem->map[j];
+ mem->map[j] = tmp;
+ }
+ }
+ }
+
+ /* Merge adjacent entries */
+ for(i = 0; (i + 1) < entries; i++) {
+ uint64_t start, end, nstart, nend;
+ if (mem->map[i].type != mem->map[i + 1].type) {
+ continue;
+ }
+ start = unpack_lb64(mem->map[i].start);
+ end = start + unpack_lb64(mem->map[i].size);
+ nstart = unpack_lb64(mem->map[i + 1].start);
+ nend = nstart + unpack_lb64(mem->map[i + 1].size);
+ if ((start <= nstart) && (end > nstart)) {
+ if (start > nstart) {
+ start = nstart;
+ }
+ if (end < nend) {
+ end = nend;
+ }
+ /* Record the new region size */
+ mem->map[i].start = pack_lb64(start);
+ mem->map[i].size = pack_lb64(end - start);
+
+ /* Delete the entry I have merged with */
+ memmove(&mem->map[i + 1], &mem->map[i + 2],
+ ((entries - i - 2) * sizeof(mem->map[0])));
+ mem->size -= sizeof(mem->map[0]);
+ entries -= 1;
+ /* See if I can merge with the next entry as well */
+ i -= 1;
+ }
+ }
+}
+
+static void lb_remove_memory_range(struct lb_memory *mem,
+ uint64_t start, uint64_t size)
+{
+ uint64_t end;
+ int entries;
+ int i;
+
+ end = start + size;
+ entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
+
+ /* Remove a reserved area from the memory map */
+ for(i = 0; i < entries; i++) {
+ uint64_t map_start = unpack_lb64(mem->map[i].start);
+ uint64_t map_end = map_start + unpack_lb64(mem->map[i].size);
+ if ((start <= map_start) && (end >= map_end)) {
+ /* Remove the completely covered range */
+ memmove(&mem->map[i], &mem->map[i + 1],
+ ((entries - i - 1) * sizeof(mem->map[0])));
+ mem->size -= sizeof(mem->map[0]);
+ entries -= 1;
+ /* Since the index will disappear revisit what will appear here */
+ i -= 1;
+ }
+ else if ((start > map_start) && (end < map_end)) {
+ /* Split the memory range */
+ memmove(&mem->map[i + 1], &mem->map[i],
+ ((entries - i) * sizeof(mem->map[0])));
+ mem->size += sizeof(mem->map[0]);
+ entries += 1;
+ /* Update the first map entry */
+ mem->map[i].size = pack_lb64(start - map_start);
+ /* Update the second map entry */
+ mem->map[i + 1].start = pack_lb64(end);
+ mem->map[i + 1].size = pack_lb64(map_end - end);
+ /* Don't bother with this map entry again */
+ i += 1;
+ }
+ else if ((start <= map_start) && (end > map_start)) {
+ /* Shrink the start of the memory range */
+ mem->map[i].start = pack_lb64(end);
+ mem->map[i].size = pack_lb64(map_end - end);
+ }
+ else if ((start < map_end) && (start > map_start)) {
+ /* Shrink the end of the memory range */
+ mem->map[i].size = pack_lb64(start - map_start);
+ }
+ }
+}
+
+/* This function is used in mainboard specific code, too */
+void lb_add_memory_range(struct lb_memory *mem,
+ uint32_t type, uint64_t start, uint64_t size)
+{
+ lb_remove_memory_range(mem, start, size);
+ lb_memory_range(mem, type, start, size);
+ lb_cleanup_memory_ranges(mem);
+}
+
+static void lb_dump_memory_ranges(struct lb_memory *mem)
+{
+ int entries;
+ int i;
+ entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
+
+ printk(BIOS_DEBUG, "coreboot memory table:\n");
+ for(i = 0; i < entries; i++) {
+ uint64_t entry_start = unpack_lb64(mem->map[i].start);
+ uint64_t entry_size = unpack_lb64(mem->map[i].size);
+ const char *entry_type;
+
+ switch (mem->map[i].type) {
+ case LB_MEM_RAM: entry_type="RAM"; break;
+ case LB_MEM_RESERVED: entry_type="RESERVED"; break;
+ case LB_MEM_ACPI: entry_type="ACPI"; break;
+ case LB_MEM_NVS: entry_type="NVS"; break;
+ case LB_MEM_UNUSABLE: entry_type="UNUSABLE"; break;
+ case LB_MEM_VENDOR_RSVD: entry_type="VENDOR RESERVED"; break;
+ case LB_MEM_TABLE: entry_type="CONFIGURATION TABLES"; break;
+ default: entry_type="UNKNOWN!"; break;
+ }
+
+ printk(BIOS_DEBUG, "%2d. %016llx-%016llx: %s\n",
+ i, entry_start, entry_start+entry_size-1, entry_type);
+
+ }
+}
+
+
+/* Routines to extract part so the coreboot table or
+ * information from the coreboot 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;
+}
+
+static void build_lb_mem_range(void *gp, struct device *dev, struct resource *res)
+{
+ struct lb_memory *mem = gp;
+ lb_memory_range(mem, LB_MEM_RAM, res->base, res->size);
+}
+
+static struct lb_memory *build_lb_mem(struct lb_header *head)
+{
+ struct lb_memory *mem;
+
+ /* Record where the lb memory ranges will live */
+ mem = lb_memory(head);
+ mem_ranges = mem;
+
+ /* Build the raw table of memory */
+ search_global_resources(
+ IORESOURCE_MEM | IORESOURCE_CACHEABLE, IORESOURCE_MEM | IORESOURCE_CACHEABLE,
+ build_lb_mem_range, mem);
+ lb_cleanup_memory_ranges(mem);
+ return mem;
+}
+
+static void lb_add_rsvd_range(void *gp, struct device *dev, struct resource *res)
+{
+ struct lb_memory *mem = gp;
+ lb_add_memory_range(mem, LB_MEM_RESERVED, res->base, res->size);
+}
+
+static void add_lb_reserved(struct lb_memory *mem)
+{
+ /* Add reserved ranges */
+ search_global_resources(
+ IORESOURCE_MEM | IORESOURCE_RESERVE, IORESOURCE_MEM | IORESOURCE_RESERVE,
+ lb_add_rsvd_range, mem);
+}
+
+#if CONFIG_WRITE_HIGH_TABLES == 1
+extern uint64_t high_tables_base, high_tables_size;
+#endif
+
+unsigned long write_coreboot_table(
+ unsigned long low_table_start, unsigned long low_table_end,
+ unsigned long rom_table_start, unsigned long rom_table_end)
+{
+ struct lb_header *head;
+ struct lb_memory *mem;
+
+#if CONFIG_WRITE_HIGH_TABLES == 1
+ printk(BIOS_DEBUG, "Writing high table forward entry at 0x%08lx\n",
+ low_table_end);
+ head = lb_table_init(low_table_end);
+ lb_forward(head, (struct lb_header*)rom_table_end);
+
+ low_table_end = (unsigned long) lb_table_fini(head, 0);
+ printk(BIOS_DEBUG, "New low_table_end: 0x%08lx\n", low_table_end);
+ printk(BIOS_DEBUG, "Now going to write high coreboot table at 0x%08lx\n",
+ rom_table_end);
+
+ head = lb_table_init(rom_table_end);
+ rom_table_end = (unsigned long)head;
+ printk(BIOS_DEBUG, "rom_table_end = 0x%08lx\n", rom_table_end);
+#else
+ if(low_table_end > (0x1000 - sizeof(struct lb_header))) { /* after 4K */
+ /* We need to put lbtable on to [0xf0000,0x100000) */
+ head = lb_table_init(rom_table_end);
+ rom_table_end = (unsigned long)head;
+ } else {
+ head = lb_table_init(low_table_end);
+ low_table_end = (unsigned long)head;
+ }
+#endif
+
+ printk(BIOS_DEBUG, "Adjust low_table_end from 0x%08lx to ", low_table_end);
+ low_table_end += 0xfff; // 4K aligned
+ low_table_end &= ~0xfff;
+ printk(BIOS_DEBUG, "0x%08lx \n", low_table_end);
+
+ /* The Linux kernel assumes this region is reserved */
+ printk(BIOS_DEBUG, "Adjust rom_table_end from 0x%08lx to ", rom_table_end);
+ rom_table_end += 0xffff; // 64K align
+ rom_table_end &= ~0xffff;
+ printk(BIOS_DEBUG, "0x%08lx \n", rom_table_end);
+
+#if (CONFIG_USE_OPTION_TABLE == 1)
+ {
+ struct lb_record *rec_dest = lb_new_record(head);
+ /* Copy the option config table, it's already a lb_record... */
+ memcpy(rec_dest, &option_table, option_table.size);
+ /* Create cmos checksum entry in coreboot table */
+ lb_cmos_checksum(head);
+ }
+#endif
+ /* Record where RAM is located */
+ mem = build_lb_mem(head);
+
+ /* Record the mptable and the the lb_table (This will be adjusted later) */
+ lb_add_memory_range(mem, LB_MEM_TABLE,
+ low_table_start, low_table_end - low_table_start);
+
+ /* Record the pirq table, acpi tables, and maybe the mptable */
+ lb_add_memory_range(mem, LB_MEM_TABLE,
+ rom_table_start, rom_table_end-rom_table_start);
+
+#if CONFIG_WRITE_HIGH_TABLES == 1
+ printk(BIOS_DEBUG, "Adding high table area\n");
+ // should this be LB_MEM_ACPI?
+ lb_add_memory_range(mem, LB_MEM_TABLE,
+ high_tables_base, high_tables_size);
+#endif
+
+ /* Add reserved regions */
+ add_lb_reserved(mem);
+
+#if (CONFIG_HAVE_MAINBOARD_RESOURCES == 1)
+ add_mainboard_resources(mem);
+#endif
+
+ lb_dump_memory_ranges(mem);
+
+ /* Note:
+ * I assume that there is always memory at immediately after
+ * the low_table_end. This means that after I setup the coreboot table.
+ * I can trivially fixup the reserved memory ranges to hold the correct
+ * size of the coreboot table.
+ */
+
+ /* Record our motherboard */
+ lb_mainboard(head);
+ /* Record the serial port, if present */
+ lb_serial(head);
+ /* Record our console setup */
+ lb_console(head);
+ /* Record our various random string information */
+ lb_strings(head);
+ /* Record our framebuffer */
+ lb_framebuffer(head);
+
+ /* Remember where my valid memory ranges are */
+ return lb_table_fini(head, 1);
+
+}
diff --git a/src/arch/x86/boot/gdt.c b/src/arch/x86/boot/gdt.c
new file mode 100644
index 0000000000..b425ade59d
--- /dev/null
+++ b/src/arch/x86/boot/gdt.c
@@ -0,0 +1,60 @@
+/*
+ * 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 <types.h>
+#include <string.h>
+#include <cbmem.h>
+#include <lib.h>
+#include <console/console.h>
+
+// Global Descriptor Table, defined in c_start.S
+extern char gdt;
+extern char gdt_end;
+
+/* i386 lgdt argument */
+struct gdtarg {
+ u16 limit;
+ u32 base;
+} __attribute__((packed));
+
+// Copy GDT to new location and reload it
+void move_gdt(void)
+{
+ void *newgdt;
+ u16 num_gdt_bytes = &gdt_end - &gdt;
+ struct gdtarg gdtarg;
+
+ newgdt = cbmem_find(CBMEM_ID_GDT);
+ if (!newgdt) {
+ newgdt = cbmem_add(CBMEM_ID_GDT, ALIGN(num_gdt_bytes, 512));
+ if (!newgdt) {
+ printk(BIOS_ERR, "Error: Could not relocate GDT.\n");
+ return;
+ }
+ printk(BIOS_DEBUG, "Moving GDT to %p...", newgdt);
+ memcpy((void*)newgdt, &gdt, num_gdt_bytes);
+ }
+
+ gdtarg.base = (u32)newgdt;
+ gdtarg.limit = num_gdt_bytes - 1;
+
+ __asm__ __volatile__ ("lgdt %0\n\t" : : "m" (gdtarg));
+ printk(BIOS_DEBUG, "ok\n");
+}
+
diff --git a/src/arch/x86/boot/mpspec.c b/src/arch/x86/boot/mpspec.c
new file mode 100644
index 0000000000..70bc5401fd
--- /dev/null
+++ b/src/arch/x86/boot/mpspec.c
@@ -0,0 +1,383 @@
+#include <console/console.h>
+#include <device/path.h>
+#include <device/pci_ids.h>
+#include <cpu/cpu.h>
+#include <arch/smp/mpspec.h>
+#include <string.h>
+#include <arch/cpu.h>
+#include <cpu/x86/lapic.h>
+
+/* Initialize the specified "mc" struct with initial values. */
+void mptable_init(struct mp_config_table *mc, const char *productid,
+ u32 lapic_addr)
+{
+ /* Error out if 'product_id' length doesn't match exactly. */
+ if (strlen(productid) != 12)
+ die("ERROR: 'productid' must be 12 bytes long!");
+
+ memset(mc, 0, sizeof(*mc));
+ memcpy(mc->mpc_signature, MPC_SIGNATURE, 4);
+ mc->mpc_length = sizeof(*mc); /* Initially just the header size. */
+ mc->mpc_spec = 0x04; /* MultiProcessor specification 1.4 */
+ mc->mpc_checksum = 0; /* Not yet computed. */
+ memcpy(mc->mpc_oem, "COREBOOT", 8);
+ memcpy(mc->mpc_productid, productid, 12);
+ mc->mpc_oemptr = 0;
+ mc->mpc_oemsize = 0;
+ mc->mpc_entry_count = 0; /* No entries yet... */
+ mc->mpc_lapic = lapic_addr;
+ mc->mpe_length = 0;
+ mc->mpe_checksum = 0;
+ mc->reserved = 0;
+}
+
+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)
+{
+ /* 16 byte align the table address */
+ addr = (addr + 0xf) & (~0xf);
+ return smp_write_floating_table_physaddr(addr, addr + SMP_FLOATING_TABLE_LEN);
+}
+
+void *smp_write_floating_table_physaddr(unsigned long addr, unsigned long mpf_physptr)
+{
+ struct intel_mp_floating *mf;
+ void *v;
+
+ 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 = mpf_physptr;
+ 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)
+{
+ int boot_apic_id;
+ unsigned apic_version;
+ unsigned cpu_features;
+ unsigned cpu_feature_flags;
+ struct cpuid_result result;
+ device_t cpu;
+
+ boot_apic_id = lapicid();
+ apic_version = lapic_read(LAPIC_LVR) & 0xff;
+ result = cpuid(1);
+ cpu_features = result.eax;
+ cpu_feature_flags = result.edx;
+ for(cpu = all_devices; cpu; cpu = cpu->next) {
+ unsigned long cpu_flag;
+ if ((cpu->path.type != DEVICE_PATH_APIC) ||
+ (cpu->bus->dev->path.type != DEVICE_PATH_APIC_CLUSTER))
+ {
+ continue;
+ }
+ if (!cpu->enabled) {
+ continue;
+ }
+ cpu_flag = MPC_CPU_ENABLED;
+ if (boot_apic_id == cpu->path.apic.apic_id) {
+ cpu_flag = MPC_CPU_ENABLED | MPC_CPU_BOOTPROCESSOR;
+ }
+ smp_write_processor(mc,
+ cpu->path.apic.apic_id, apic_version,
+ cpu_flag, cpu_features, cpu_feature_flags
+ );
+ }
+}
+
+static void smp_write_bus(struct mp_config_table *mc,
+ unsigned char id, const 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));
+#ifdef DEBUG_MPTABLE
+ printk(BIOS_DEBUG, "add intsrc srcbus 0x%x srcbusirq 0x%x, dstapic 0x%x, dstirq 0x%x\n",
+ srcbus, srcbusirq, dstapic, dstirq);
+ hexdump(__func__, mpc, sizeof(*mpc));
+#endif
+}
+
+void smp_write_intsrc_pci_bridge(struct mp_config_table *mc,
+ unsigned char irqtype, unsigned short irqflag,
+ struct device *dev,
+ unsigned char dstapic, unsigned char *dstirq)
+{
+ struct device *child;
+
+ int i;
+ int srcbus;
+ int slot;
+
+ struct bus *link;
+ unsigned char dstirq_x[4];
+
+ for (link = dev->link_list; link; link = link->next) {
+
+ child = link->children;
+ srcbus = link->secondary;
+
+ while (child) {
+ if (child->path.type != DEVICE_PATH_PCI)
+ goto next;
+
+ slot = (child->path.pci.devfn >> 3);
+ /* round pins */
+ for (i = 0; i < 4; i++)
+ dstirq_x[i] = dstirq[(i + slot) % 4];
+
+ if ((child->class >> 16) != PCI_BASE_CLASS_BRIDGE) {
+ /* pci device */
+ printk(BIOS_DEBUG, "route irq: %s\n", dev_path(child));
+ for (i = 0; i < 4; i++)
+ smp_write_intsrc(mc, irqtype, irqflag, srcbus, (slot<<2)|i, dstapic, dstirq_x[i]);
+ goto next;
+ }
+
+ switch (child->class>>8) {
+ case PCI_CLASS_BRIDGE_PCI:
+ case PCI_CLASS_BRIDGE_PCMCIA:
+ case PCI_CLASS_BRIDGE_CARDBUS:
+ printk(BIOS_DEBUG, "route irq bridge: %s\n", dev_path(child));
+ smp_write_intsrc_pci_bridge(mc, irqtype, irqflag, child, dstapic, dstirq_x);
+ }
+
+ next:
+ child = child->sibling;
+ }
+
+ }
+}
+
+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);
+}
+
+void mptable_add_isa_interrupts(struct mp_config_table *mc, unsigned long bus_isa, unsigned long apicid, int external_int2)
+{
+/*I/O Ints: Type Trigger Polarity Bus ID IRQ APIC ID PIN# */
+ smp_write_intsrc(mc, external_int2?mp_INT:mp_ExtINT,
+ MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0x0, apicid, 0x0);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0x1, apicid, 0x1);
+ smp_write_intsrc(mc, external_int2?mp_ExtINT:mp_INT,
+ MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0x0, apicid, 0x2);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0x3, apicid, 0x3);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0x4, apicid, 0x4);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0x6, apicid, 0x6);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0x7, apicid, 0x7);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0x8, apicid, 0x8);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0x9, apicid, 0x9);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0xa, apicid, 0xa);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0xb, apicid, 0xb);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0xc, apicid, 0xc);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0xd, apicid, 0xd);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0xe, apicid, 0xe);
+ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH, bus_isa, 0xf, apicid, 0xf);
+}
+
+void mptable_write_buses(struct mp_config_table *mc, int *max_pci_bus, int *isa_bus) {
+ int dummy, i, highest;
+ char buses[256];
+ struct device *dev;
+
+ if (!max_pci_bus) max_pci_bus = &dummy;
+ if (!isa_bus) isa_bus = &dummy;
+
+ *max_pci_bus = 0;
+ highest = 0;
+ memset(buses, 0, sizeof(buses));
+
+ for (dev = all_devices; dev; dev = dev->next) {
+ struct bus *bus;
+ for (bus = dev->link_list; bus; bus = bus->next) {
+ if (bus->secondary > 255) {
+ printk(BIOS_ERR, "A bus claims to have a bus ID > 255?!? Aborting");
+ return;
+ }
+ buses[bus->secondary] = 1;
+ if (highest < bus->secondary) highest = bus->secondary;
+ }
+ }
+ for (i=0; i <= highest; i++) {
+ if (buses[i]) {
+ smp_write_bus(mc, i, "PCI ");
+ *max_pci_bus = i;
+ }
+ }
+ *isa_bus = *max_pci_bus + 1;
+ smp_write_bus(mc, *isa_bus, "ISA ");
+}
+
diff --git a/src/arch/x86/boot/multiboot.c b/src/arch/x86/boot/multiboot.c
new file mode 100644
index 0000000000..4059f2736b
--- /dev/null
+++ b/src/arch/x86/boot/multiboot.c
@@ -0,0 +1,77 @@
+/*
+ * support for Multiboot payloads
+ *
+ * Copyright (C) 2008 Robert Millan
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <cpu/x86/multiboot.h>
+#include <string.h>
+#include <device/resource.h>
+#include <console/console.h>
+#include <boot/coreboot_tables.h>
+#include <arch/coreboot_tables.h>
+
+struct multiboot_info *mbi = NULL;
+
+unsigned long write_multiboot_info(unsigned long rom_table_end)
+{
+ static struct multiboot_mmap_entry *mb_mem;
+ struct lb_memory* coreboot_table;
+ int entries;
+ int i;
+
+ mbi = (struct multiboot_info *)rom_table_end;
+
+ memset(mbi, 0, sizeof(*mbi));
+ rom_table_end += sizeof(*mbi);
+
+ mbi->mmap_addr = (u32) rom_table_end;
+ mb_mem = (struct multiboot_mmap_entry *)rom_table_end;
+
+ /* copy regions from coreboot tables */
+ coreboot_table = get_lb_mem();
+ entries = (coreboot_table->size - sizeof(*coreboot_table))/sizeof(coreboot_table->map[0]);
+
+ if (coreboot_table == NULL || entries < 1) {
+ printk(BIOS_INFO, "%s: Cannot find coreboot table.\n", __func__);
+ return (unsigned long) mb_mem;
+ }
+
+ for (i = 0; i < entries; i++) {
+ uint64_t entry_start = unpack_lb64(coreboot_table->map[i].start);
+ uint64_t entry_size = unpack_lb64(coreboot_table->map[i].size);
+ mb_mem->addr = entry_start;
+ mb_mem->len = entry_size;
+ switch (coreboot_table->map[i].type) {
+ case LB_MEM_RAM:
+ mb_mem->type = MULTIBOOT_MEMORY_AVAILABLE;
+ break;
+ default: // anything other than usable RAM
+ mb_mem->type = MULTIBOOT_MEMORY_RESERVED;
+ break;
+ }
+ mb_mem->size = sizeof(*mb_mem) - sizeof(mb_mem->size);
+ mb_mem++;
+ }
+
+ mbi->mmap_length = ((u32) mb_mem) - mbi->mmap_addr;
+ mbi->flags |= MB_INFO_MEM_MAP;
+
+ printk(BIOS_INFO, "Multiboot Information structure has been written.\n");
+
+ return (unsigned long)mb_mem;
+}
diff --git a/src/arch/x86/boot/pirq_routing.c b/src/arch/x86/boot/pirq_routing.c
new file mode 100644
index 0000000000..bb8a7b605a
--- /dev/null
+++ b/src/arch/x86/boot/pirq_routing.c
@@ -0,0 +1,169 @@
+#include <console/console.h>
+#include <arch/pirq_routing.h>
+#include <string.h>
+#include <device/pci.h>
+
+#if CONFIG_DEBUG_PIRQ
+static void check_pirq_routing_table(struct irq_routing_table *rt)
+{
+ uint8_t *addr = (uint8_t *)rt;
+ uint8_t sum=0;
+ int i;
+
+ printk(BIOS_INFO, "Checking Interrupt Routing Table consistency...\n");
+
+ if (sizeof(struct irq_routing_table) != rt->size) {
+ printk(BIOS_WARNING, "Inconsistent Interrupt Routing Table size (0x%x/0x%x).\n",
+ (unsigned int) sizeof(struct irq_routing_table),
+ rt->size
+ );
+ rt->size=sizeof(struct irq_routing_table);
+ }
+
+ for (i = 0; i < rt->size; i++)
+ sum += addr[i];
+
+ printk(BIOS_DEBUG, "%s(): Interrupt Routing Table located at %p.\n",
+ __func__, addr);
+
+
+ sum = rt->checksum - sum;
+
+ if (sum != rt->checksum) {
+ printk(BIOS_WARNING, "Interrupt Routing Table checksum is: 0x%02x but should be: 0x%02x.\n",
+ rt->checksum, sum);
+ rt->checksum = sum;
+ }
+
+ if (rt->signature != PIRQ_SIGNATURE || rt->version != PIRQ_VERSION ||
+ rt->size % 16 ) {
+ printk(BIOS_WARNING, "Interrupt Routing Table not valid.\n");
+ return;
+ }
+
+ sum = 0;
+ for (i=0; i<rt->size; i++)
+ sum += addr[i];
+
+ /* We're manually fixing the checksum above. This warning can probably
+ * never happen because if the target location is read-only this
+ * function would have bailed out earlier.
+ */
+ if (sum) {
+ printk(BIOS_WARNING, "Checksum error in Interrupt Routing Table "
+ "could not be fixed.\n");
+ }
+
+ printk(BIOS_INFO, "done.\n");
+}
+
+static int verify_copy_pirq_routing_table(unsigned long addr)
+{
+ int i;
+ uint8_t *rt_orig, *rt_curr;
+
+ rt_curr = (uint8_t*)addr;
+ rt_orig = (uint8_t*)&intel_irq_routing_table;
+ printk(BIOS_INFO, "Verifying copy of Interrupt Routing Table at 0x%08lx... ", addr);
+ for (i = 0; i < intel_irq_routing_table.size; i++) {
+ if (*(rt_curr + i) != *(rt_orig + i)) {
+ printk(BIOS_INFO, "failed\n");
+ return -1;
+ }
+ }
+ printk(BIOS_INFO, "done\n");
+
+ check_pirq_routing_table((struct irq_routing_table *)addr);
+
+ return 0;
+}
+#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(BIOS_INFO, "Copying Interrupt Routing Table to 0x%08lx... ", addr);
+ memcpy((void *)addr, &intel_irq_routing_table, intel_irq_routing_table.size);
+ printk(BIOS_INFO, "done.\n");
+#if CONFIG_DEBUG_PIRQ
+ verify_copy_pirq_routing_table(addr);
+#endif
+ pirq_routing_irqs(addr);
+ return addr + intel_irq_routing_table.size;
+}
+
+#if CONFIG_PIRQ_ROUTE
+void pirq_routing_irqs(unsigned long addr)
+{
+ int i, j, k, num_entries;
+ unsigned char irq_slot[4];
+ unsigned char pirq[4] = {0, 0, 0, 0};
+ struct irq_routing_table *pirq_tbl;
+
+ pirq_tbl = (struct irq_routing_table *)(addr);
+ num_entries = (pirq_tbl->size - 32) / 16;
+
+ /* Set PCI IRQs. */
+ for (i = 0; i < num_entries; i++) {
+
+ printk(BIOS_DEBUG, "PIRQ Entry %d Dev/Fn: %X Slot: %d\n", i,
+ pirq_tbl->slots[i].devfn >> 3, pirq_tbl->slots[i].slot);
+
+ for (j = 0; j < 4; j++) {
+
+ int link = pirq_tbl->slots[i].irq[j].link;
+ int bitmap = pirq_tbl->slots[i].irq[j].bitmap;
+ int irq = 0;
+
+ printk(BIOS_DEBUG, "INT: %c link: %x bitmap: %x ",
+ 'A' + j, link, bitmap);
+
+ if (!bitmap|| !link || link > 4) {
+
+ printk(BIOS_DEBUG, "not routed\n");
+ irq_slot[j] = irq;
+ continue;
+ }
+
+ /* yet not routed */
+ if (!pirq[link - 1]) {
+
+ for (k = 2; k <= 15; k++) {
+
+ if (!((bitmap >> k) & 1))
+ continue;
+
+ irq = k;
+
+ /* yet not routed */
+ if (pirq[0] != irq && pirq[1] != irq && pirq[2] != irq && pirq[3] != irq)
+ break;
+ }
+
+ if (irq)
+ pirq[link - 1] = irq;
+ }
+ else
+ irq = pirq[link - 1];
+
+ printk(BIOS_DEBUG, "IRQ: %d\n", irq);
+ irq_slot[j] = irq;
+ }
+
+ /* Bus, device, slots IRQs for {A,B,C,D}. */
+ pci_assign_irqs(pirq_tbl->slots[i].bus,
+ pirq_tbl->slots[i].devfn >> 3, irq_slot);
+ }
+
+ printk(BIOS_DEBUG, "PIRQ1: %d\n", pirq[0]);
+ printk(BIOS_DEBUG, "PIRQ2: %d\n", pirq[1]);
+ printk(BIOS_DEBUG, "PIRQ3: %d\n", pirq[2]);
+ printk(BIOS_DEBUG, "PIRQ4: %d\n", pirq[3]);
+
+ pirq_assign_irqs(pirq);
+}
+#endif
diff --git a/src/arch/x86/boot/tables.c b/src/arch/x86/boot/tables.c
new file mode 100644
index 0000000000..d816e76750
--- /dev/null
+++ b/src/arch/x86/boot/tables.c
@@ -0,0 +1,231 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2003 Eric Biederman
+ * Copyright (C) 2005 Steve Magnani
+ * 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 <cpu/cpu.h>
+#include <boot/tables.h>
+#include <boot/coreboot_tables.h>
+#include <arch/coreboot_tables.h>
+#include <arch/pirq_routing.h>
+#include <arch/smp/mpspec.h>
+#include <arch/acpi.h>
+#include <string.h>
+#include <cpu/x86/multiboot.h>
+#include <cbmem.h>
+#include <lib.h>
+
+uint64_t high_tables_base = 0;
+uint64_t high_tables_size;
+
+void cbmem_arch_init(void)
+{
+ /* defined in gdt.c */
+ move_gdt();
+}
+
+struct lb_memory *write_tables(void)
+{
+ unsigned long low_table_start, low_table_end;
+ unsigned long rom_table_start, rom_table_end;
+
+ /* Even if high tables are configured, some tables are copied both to
+ * the low and the high area, so payloads and OSes don't need to know
+ * about the high tables.
+ */
+ unsigned long high_table_pointer;
+
+ if (!high_tables_base) {
+ printk(BIOS_ERR, "ERROR: High Tables Base is not set.\n");
+ // Are there any boards without?
+ // Stepan thinks we should die() here!
+ }
+
+ printk(BIOS_DEBUG, "High Tables Base is %llx.\n", high_tables_base);
+
+ rom_table_start = 0xf0000;
+ rom_table_end = 0xf0000;
+
+ /* Start low addr at 0x500, so we don't run into conflicts with the BDA
+ * in case our data structures grow beyound 0x400. Only multiboot, GDT
+ * and the coreboot table use low_tables.
+ */
+ low_table_start = 0;
+ low_table_end = 0x500;
+
+#if CONFIG_GENERATE_PIRQ_TABLE == 1
+#define MAX_PIRQ_TABLE_SIZE (4 * 1024)
+ post_code(0x9a);
+
+ /* This table must be between 0x0f0000 and 0x100000 */
+ rom_table_end = write_pirq_routing_table(rom_table_end);
+ rom_table_end = ALIGN(rom_table_end, 1024);
+
+ /* And add a high table version for those payloads that
+ * want to live in the F segment
+ */
+ high_table_pointer = (unsigned long)cbmem_add(CBMEM_ID_PIRQ, MAX_PIRQ_TABLE_SIZE);
+ if (high_table_pointer) {
+ unsigned long new_high_table_pointer;
+ new_high_table_pointer = write_pirq_routing_table(high_table_pointer);
+ // FIXME make pirq table code intelligent enough to know how
+ // much space it's going to need.
+ if (new_high_table_pointer > (high_table_pointer + MAX_PIRQ_TABLE_SIZE)) {
+ printk(BIOS_ERR, "ERROR: Increase PIRQ size.\n");
+ }
+ printk(BIOS_DEBUG, "PIRQ table: %ld bytes.\n",
+ new_high_table_pointer - high_table_pointer);
+ }
+
+#endif
+
+#if CONFIG_GENERATE_MP_TABLE == 1
+#define MAX_MP_TABLE_SIZE (4 * 1024)
+ post_code(0x9b);
+
+ /* The smp table must be in 0-1K, 639K-640K, or 960K-1M */
+ rom_table_end = write_smp_table(rom_table_end);
+ rom_table_end = ALIGN(rom_table_end, 1024);
+
+ high_table_pointer = (unsigned long)cbmem_add(CBMEM_ID_MPTABLE, MAX_MP_TABLE_SIZE);
+ if (high_table_pointer) {
+ unsigned long new_high_table_pointer;
+ new_high_table_pointer = write_smp_table(high_table_pointer);
+ // FIXME make mp table code intelligent enough to know how
+ // much space it's going to need.
+ if (new_high_table_pointer > (high_table_pointer + MAX_MP_TABLE_SIZE)) {
+ printk(BIOS_ERR, "ERROR: Increase MP table size.\n");
+ }
+
+ printk(BIOS_DEBUG, "MP table: %ld bytes.\n",
+ new_high_table_pointer - high_table_pointer);
+ }
+#endif /* CONFIG_GENERATE_MP_TABLE */
+
+#if CONFIG_GENERATE_ACPI_TABLES == 1
+#define MAX_ACPI_SIZE (47 * 1024)
+ post_code(0x9c);
+
+ /* Write ACPI tables to F segment and high tables area */
+
+ /* Ok, this is a bit hacky still, because some day we want to have this
+ * completely dynamic. But right now we are setting fixed sizes.
+ * It's probably still better than the old high_table_base code because
+ * now at least we know when we have an overflow in the area.
+ *
+ * We want to use 1MB - 64K for Resume backup. We use 512B for TOC and
+ * 512 byte for GDT, 4K for PIRQ and 4K for MP table and 8KB for the
+ * coreboot table. This leaves us with 47KB for all of ACPI. Let's see
+ * how far we get.
+ */
+ high_table_pointer = (unsigned long)cbmem_add(CBMEM_ID_ACPI, MAX_ACPI_SIZE);
+ if (high_table_pointer) {
+ unsigned long acpi_start = high_table_pointer;
+ unsigned long new_high_table_pointer;
+
+ rom_table_end = ALIGN(rom_table_end, 16);
+ new_high_table_pointer = write_acpi_tables(high_table_pointer);
+ if (new_high_table_pointer > ( high_table_pointer + MAX_ACPI_SIZE)) {
+ printk(BIOS_ERR, "ERROR: Increase ACPI size\n");
+ }
+ printk(BIOS_DEBUG, "ACPI tables: %ld bytes.\n",
+ new_high_table_pointer - high_table_pointer);
+
+ /* Now we need to create a low table copy of the RSDP. */
+
+ /* First we look for the high table RSDP */
+ while (acpi_start < new_high_table_pointer) {
+ if (memcmp(((acpi_rsdp_t *)acpi_start)->signature, RSDP_SIG, 8) == 0) {
+ break;
+ }
+ acpi_start++;
+ }
+
+ /* Now, if we found the RSDP, we take the RSDT and XSDT pointer
+ * from it in order to write the low RSDP
+ */
+ if (acpi_start < new_high_table_pointer) {
+ acpi_rsdp_t *low_rsdp = (acpi_rsdp_t *)rom_table_end,
+ *high_rsdp = (acpi_rsdp_t *)acpi_start;
+
+ acpi_write_rsdp(low_rsdp,
+ (acpi_rsdt_t *)(high_rsdp->rsdt_address),
+ (acpi_xsdt_t *)((unsigned long)high_rsdp->xsdt_address));
+ } else {
+ printk(BIOS_ERR, "ERROR: Didn't find RSDP in high table.\n");
+ }
+ rom_table_end = ALIGN(rom_table_end + sizeof(acpi_rsdp_t), 16);
+ } else {
+ rom_table_end = write_acpi_tables(rom_table_end);
+ rom_table_end = ALIGN(rom_table_end, 1024);
+ }
+
+#endif
+
+
+#define MAX_COREBOOT_TABLE_SIZE (8 * 1024)
+ post_code(0x9d);
+
+ high_table_pointer = (unsigned long)cbmem_add(CBMEM_ID_CBTABLE, MAX_COREBOOT_TABLE_SIZE);
+
+ if (high_table_pointer) {
+ unsigned long new_high_table_pointer;
+
+ /* Also put a forwarder entry into 0-4K */
+ new_high_table_pointer = write_coreboot_table(low_table_start, low_table_end,
+ high_tables_base, high_table_pointer);
+
+ if (new_high_table_pointer > (high_table_pointer +
+ MAX_COREBOOT_TABLE_SIZE))
+ printk(BIOS_ERR, "%s: coreboot table didn't fit (%lx)\n",
+ __func__, new_high_table_pointer -
+ high_table_pointer);
+
+ printk(BIOS_DEBUG, "coreboot table: %ld bytes.\n",
+ new_high_table_pointer - high_table_pointer);
+ } else {
+ /* The coreboot table must be in 0-4K or 960K-1M */
+ rom_table_end = write_coreboot_table(
+ low_table_start, low_table_end,
+ rom_table_start, rom_table_end);
+ }
+
+ post_code(0x9e);
+
+#if CONFIG_HAVE_ACPI_RESUME
+ /* Let's prepare the ACPI S3 Resume area now already, so we can rely on
+ * it begin there during reboot time. We don't need the pointer, nor
+ * the result right now. If it fails, ACPI resume will be disabled.
+ */
+ cbmem_add(CBMEM_ID_RESUME, HIGH_MEMORY_SAVE);
+#endif
+
+#if CONFIG_MULTIBOOT
+ post_code(0x9d);
+
+ /* The Multiboot information structure */
+ write_multiboot_info(rom_table_end);
+#endif
+
+ // Remove before sending upstream
+ cbmem_list();
+
+ return get_lb_mem();
+}
diff --git a/src/arch/x86/boot/wakeup.S b/src/arch/x86/boot/wakeup.S
new file mode 100644
index 0000000000..a1df4d5597
--- /dev/null
+++ b/src/arch/x86/boot/wakeup.S
@@ -0,0 +1,105 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2009 Rudolf Marek <r.marek@assembler.cz>
+ * Copyright (C) 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
+ */
+
+#define WAKEUP_BASE 0x600
+#define RELOCATED(x) (x - __wakeup + WAKEUP_BASE)
+
+/* CR0 bits */
+#define PE (1 << 0)
+
+ .code32
+ .globl __wakeup
+__wakeup:
+ /* First prepare the jmp to the resume vector */
+ mov 0x4(%esp), %eax /* vector */
+ /* last 4 bits of linear addr are taken as offset */
+ andw $0x0f, %ax
+ movw %ax, (__wakeup_offset)
+ mov 0x4(%esp), %eax
+ /* the rest is taken as segment */
+ shr $4, %eax
+ movw %ax, (__wakeup_segment)
+
+ /* Then overwrite coreboot with our backed up memory */
+ movl 8(%esp), %esi
+ movl 12(%esp), %edi
+ movl 16(%esp), %ecx
+ shrl $4, %ecx
+1:
+ movl 0(%esi),%eax
+ movl 4(%esi),%edx
+ movl 8(%esi),%ebx
+ movl 12(%esi),%ebp
+ addl $16,%esi
+ subl $1,%ecx
+ movl %eax,0(%edi)
+ movl %edx,4(%edi)
+ movl %ebx,8(%edi)
+ movl %ebp,12(%edi)
+ leal 16(%edi),%edi
+ jne 1b
+
+ /* Activate the right segment descriptor real mode. */
+ ljmp $0x28, $RELOCATED(1f)
+1:
+.code16
+ /* 16 bit code from here on... */
+
+ /* Load the segment registers w/ properly configured
+ * segment descriptors. They will retain these
+ * configurations (limits, writability, etc.) once
+ * protected mode is turned off.
+ */
+ mov $0x30, %ax
+ mov %ax, %ds
+ mov %ax, %es
+ mov %ax, %fs
+ mov %ax, %gs
+ mov %ax, %ss
+
+ /* Turn off protection */
+ movl %cr0, %eax
+ andl $~PE, %eax
+ movl %eax, %cr0
+
+ /* Now really going into real mode */
+ ljmp $0, $RELOCATED(1f)
+1:
+ movw $0x0, %ax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %ss
+ movw %ax, %fs
+ movw %ax, %gs
+
+ /* This is a FAR JMP to the OS waking vector. The C code changed
+ * the address to be correct.
+ */
+ .byte 0xea
+
+__wakeup_offset = RELOCATED(.)
+ .word 0x0000
+
+__wakeup_segment = RELOCATED(.)
+ .word 0x0000
+
+ .globl __wakeup_size
+__wakeup_size = ( . - __wakeup)
+
diff --git a/src/arch/x86/coreboot_ram.ld b/src/arch/x86/coreboot_ram.ld
new file mode 100644
index 0000000000..57ddd03c0d
--- /dev/null
+++ b/src/arch/x86/coreboot_ram.ld
@@ -0,0 +1,128 @@
+/*
+ * Memory map:
+ *
+ * CONFIG_RAMBASE : text segment
+ * : rodata segment
+ * : data segment
+ * : bss segment
+ * : stack
+ * : heap
+ */
+/*
+ * Bootstrap code for the STPC Consumer
+ * Copyright (c) 1999 by Net Insight AB. All Rights Reserved.
+ */
+
+/*
+ * Written by Johan Rydberg, based on work by Daniel Kahlin.
+ * Rewritten by Eric Biederman
+ * 2005.12 yhlu add coreboot_ram cross the vga font buffer handling
+ */
+
+/* We use ELF as output format. So that we can debug the code in some form. */
+INCLUDE ldoptions
+
+ENTRY(_start)
+
+SECTIONS
+{
+ . = CONFIG_RAMBASE;
+ /* First we place the code and read only data (typically const declared).
+ * This could theoretically be placed in rom.
+ */
+ .text : {
+ _text = .;
+ *(.text);
+ *(.text.*);
+ . = ALIGN(16);
+ _etext = .;
+ }
+
+ .rodata : {
+ _rodata = .;
+ . = ALIGN(4);
+ console_drivers = .;
+ *(.rodata.console_drivers)
+ econsole_drivers = . ;
+ . = ALIGN(4);
+ pci_drivers = . ;
+ *(.rodata.pci_driver)
+ epci_drivers = . ;
+ cpu_drivers = . ;
+ *(.rodata.cpu_driver)
+ ecpu_drivers = . ;
+ *(.rodata)
+ *(.rodata.*)
+ /* kevinh/Ispiri - Added an align, because the objcopy tool
+ * incorrectly converts sections that are not long word aligned.
+ */
+ . = ALIGN(4);
+
+ _erodata = .;
+ }
+ /* After the code we place initialized data (typically initialized
+ * global variables). This gets copied into ram by startup code.
+ * __data_start and __data_end shows where in ram this should be placed,
+ * whereas __data_loadstart and __data_loadend shows where in rom to
+ * copy from.
+ */
+ .data : {
+ _data = .;
+ *(.data)
+ _edata = .;
+ }
+
+ /* bss does not contain data, it is just a space that should be zero
+ * initialized on startup. (typically uninitialized global variables)
+ * crt0.S fills between _bss and _ebss with zeroes.
+ */
+ _bss = .;
+ .bss . : {
+ *(.bss)
+ *(.sbss)
+ *(COMMON)
+ }
+ _ebss = .;
+ _end = .;
+
+ /* coreboot really "ends" here. Only heap and stack are placed after
+ * this line.
+ */
+
+ . = ALIGN(CONFIG_STACK_SIZE);
+
+ _stack = .;
+ .stack . : {
+ /* Reserve a stack for each possible cpu */
+ . += CONFIG_MAX_CPUS*CONFIG_STACK_SIZE;
+ }
+ _estack = .;
+
+ _heap = .;
+ .heap . : {
+ /* Reserve CONFIG_HEAP_SIZE bytes for the heap */
+ . = CONFIG_HEAP_SIZE ;
+ . = ALIGN(4);
+ }
+ _eheap = .;
+
+ /* The ram segment. This includes all memory used by the memory
+ * resident copy of coreboot, except the tables that are produced on
+ * the fly, but including stack and heap.
+ */
+ _ram_seg = _text;
+ _eram_seg = _eheap;
+
+ /* CONFIG_RAMTOP is the upper address of cached memory (among other
+ * things). We must not exceed beyond that address, there be dragons.
+ */
+ _bogus = ASSERT( ( _eram_seg < (CONFIG_RAMTOP)) , "Please increase CONFIG_RAMTOP");
+
+ /* Discard the sections we don't need/want */
+
+ /DISCARD/ : {
+ *(.comment)
+ *(.note)
+ *(.note.*)
+ }
+}
diff --git a/src/arch/x86/include/arch/acpi.h b/src/arch/x86/include/arch/acpi.h
new file mode 100644
index 0000000000..030745d5ab
--- /dev/null
+++ b/src/arch/x86/include/arch/acpi.h
@@ -0,0 +1,440 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2004 SUSE LINUX AG
+ * Copyright (C) 2004 Nick Barker
+ * Copyright (C) 2008-2009 coresystems GmbH
+ * (Written by Stefan Reinauer <stepan@coresystems.de>)
+ *
+ * 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
+ */
+
+/*
+ * coreboot ACPI support - headers and defines.
+ */
+
+#ifndef __ASM_ACPI_H
+#define __ASM_ACPI_H
+
+#if CONFIG_GENERATE_ACPI_TABLES==1
+
+#include <stdint.h>
+
+#define RSDP_SIG "RSD PTR " /* RSDT pointer signature */
+#define ACPI_TABLE_CREATOR "COREBOOT" /* Must be exactly 8 bytes long! */
+#define OEM_ID "CORE " /* Must be exactly 6 bytes long! */
+#define ASLC "CORE" /* Must be exactly 4 bytes long! */
+
+/* RSDP (Root System Description Pointer) */
+typedef struct acpi_rsdp {
+ char signature[8]; /* RSDP signature */
+ u8 checksum; /* Checksum of the first 20 bytes */
+ char oem_id[6]; /* OEM ID */
+ u8 revision; /* 0 for ACPI 1.0, 2 for ACPI 2.0/3.0/4.0 */
+ u32 rsdt_address; /* Physical address of RSDT (32 bits) */
+ u32 length; /* Total RSDP length (incl. extended part) */
+ u64 xsdt_address; /* Physical address of XSDT (64 bits) */
+ u8 ext_checksum; /* Checksum of the whole table */
+ u8 reserved[3];
+} __attribute__ ((packed)) acpi_rsdp_t;
+/* Note: ACPI 1.0 didn't have length, xsdt_address, and ext_checksum. */
+
+/* GAS (Generic Address Structure) */
+typedef struct acpi_gen_regaddr {
+ u8 space_id; /* Address space ID */
+ u8 bit_width; /* Register size in bits */
+ u8 bit_offset; /* Register bit offset */
+ u8 resv; /* FIXME: Access size in ACPI 2.0/3.0/4.0 */
+ u32 addrl; /* Register address, low 32 bits */
+ u32 addrh; /* Register address, high 32 bits */
+} __attribute__ ((packed)) acpi_addr_t;
+
+#define ACPI_ADDRESS_SPACE_MEMORY 0 /* System memory */
+#define ACPI_ADDRESS_SPACE_IO 1 /* System I/O */
+#define ACPI_ADDRESS_SPACE_PCI 2 /* PCI config space */
+#define ACPI_ADDRESS_SPACE_EC 3 /* Embedded controller */
+#define ACPI_ADDRESS_SPACE_SMBUS 4 /* SMBus */
+#define ACPI_ADDRESS_SPACE_FIXED 0x7f /* Functional fixed hardware */
+/* 0x80-0xbf: Reserved */
+/* 0xc0-0xff: OEM defined */
+
+/* Generic ACPI header, provided by (almost) all tables */
+typedef struct acpi_table_header {
+ char signature[4]; /* ACPI signature (4 ASCII characters) */
+ u32 length; /* Table length in bytes (incl. header) */
+ u8 revision; /* Table version (not ACPI version!) */
+ u8 checksum; /* To make sum of entire table == 0 */
+ char oem_id[6]; /* OEM identification */
+ char oem_table_id[8]; /* OEM table identification */
+ u32 oem_revision; /* OEM revision number */
+ char asl_compiler_id[4]; /* ASL compiler vendor ID */
+ u32 asl_compiler_revision; /* ASL compiler revision number */
+} __attribute__ ((packed)) acpi_header_t;
+
+/* A maximum number of 32 ACPI tables ought to be enough for now. */
+#define MAX_ACPI_TABLES 32
+
+/* RSDT (Root System Description Table) */
+typedef struct acpi_rsdt {
+ struct acpi_table_header header;
+ u32 entry[MAX_ACPI_TABLES];
+} __attribute__ ((packed)) acpi_rsdt_t;
+
+/* XSDT (Extended System Description Table) */
+typedef struct acpi_xsdt {
+ struct acpi_table_header header;
+ u64 entry[MAX_ACPI_TABLES];
+} __attribute__ ((packed)) acpi_xsdt_t;
+
+/* HPET timers */
+typedef struct acpi_hpet {
+ struct acpi_table_header header;
+ u32 id;
+ struct acpi_gen_regaddr addr;
+ u8 number;
+ u16 min_tick;
+ u8 attributes;
+} __attribute__ ((packed)) acpi_hpet_t;
+
+/* MCFG (PCI Express MMIO config space BAR description table) */
+typedef struct acpi_mcfg {
+ struct acpi_table_header header;
+ u8 reserved[8];
+} __attribute__ ((packed)) acpi_mcfg_t;
+
+typedef struct acpi_mcfg_mmconfig {
+ u32 base_address;
+ u32 base_reserved;
+ u16 pci_segment_group_number;
+ u8 start_bus_number;
+ u8 end_bus_number;
+ u8 reserved[4];
+} __attribute__ ((packed)) acpi_mcfg_mmconfig_t;
+
+/* SRAT (System Resource Affinity Table) */
+typedef struct acpi_srat {
+ struct acpi_table_header header;
+ u32 resv;
+ u64 resv1;
+ /* Followed by static resource allocation structure[n] */
+} __attribute__ ((packed)) acpi_srat_t;
+
+/* SRAT: Processor Local APIC/SAPIC Affinity Structure */
+typedef struct acpi_srat_lapic {
+ u8 type; /* Type (0) */
+ u8 length; /* Length in bytes (16) */
+ u8 proximity_domain_7_0; /* Proximity domain bits[7:0] */
+ u8 apic_id; /* Local APIC ID */
+ u32 flags; /* Enable bit 0 = 1, other bits reserved to 0 */
+ u8 local_sapic_eid; /* Local SAPIC EID */
+ u8 proximity_domain_31_8[3]; /* Proximity domain bits[31:8] */
+ u32 resv; /* TODO: Clock domain in ACPI 4.0. */
+} __attribute__ ((packed)) acpi_srat_lapic_t;
+
+/* SRAT: Memory Affinity Structure */
+typedef struct acpi_srat_mem {
+ u8 type; /* Type (1) */
+ u8 length; /* Length in bytes (40) */
+ u32 proximity_domain; /* Proximity domain */
+ u16 resv;
+ u32 base_address_low; /* Mem range base address, low */
+ u32 base_address_high; /* Mem range base address, high */
+ u32 length_low; /* Mem range length, low */
+ u32 length_high; /* Mem range length, high */
+ u32 resv1;
+ u32 flags; /* Enable bit 0, hot pluggable bit 1; Non Volatile bit 2, other bits reserved to 0 */
+ u32 resv2[2];
+} __attribute__ ((packed)) acpi_srat_mem_t;
+
+/* SLIT (System Locality Distance Information Table) */
+typedef struct acpi_slit {
+ struct acpi_table_header header;
+ /* Followed by static resource allocation 8+byte[num*num] */
+} __attribute__ ((packed)) acpi_slit_t;
+
+/* MADT (Multiple APIC Description Table) */
+typedef struct acpi_madt {
+ struct acpi_table_header header;
+ u32 lapic_addr; /* Local APIC address */
+ u32 flags; /* Multiple APIC flags */
+} __attribute__ ((packed)) acpi_madt_t;
+
+/* MADT: APIC Structure Types */
+/* TODO: Convert to ALLCAPS. */
+enum acpi_apic_types {
+ LocalApic = 0, /* Processor local APIC */
+ IOApic = 1, /* I/O APIC */
+ IRQSourceOverride = 2, /* Interrupt source override */
+ NMIType = 3, /* NMI source */
+ LocalApicNMI = 4, /* Local APIC NMI */
+ LApicAddressOverride = 5, /* Local APIC address override */
+ IOSApic = 6, /* I/O SAPIC */
+ LocalSApic = 7, /* Local SAPIC */
+ PlatformIRQSources = 8, /* Platform interrupt sources */
+ Localx2Apic = 9, /* Processor local x2APIC */
+ Localx2ApicNMI = 10, /* Local x2APIC NMI */
+ /* 0x0b-0x7f: Reserved */
+ /* 0x80-0xff: Reserved for OEM use */
+};
+
+/* MADT: Processor Local APIC Structure */
+typedef struct acpi_madt_lapic {
+ u8 type; /* Type (0) */
+ u8 length; /* Length in bytes (8) */
+ u8 processor_id; /* ACPI processor ID */
+ u8 apic_id; /* Local APIC ID */
+ u32 flags; /* Local APIC flags */
+} __attribute__ ((packed)) acpi_madt_lapic_t;
+
+/* MADT: Local APIC NMI Structure */
+typedef struct acpi_madt_lapic_nmi {
+ u8 type; /* Type (4) */
+ u8 length; /* Length in bytes (6) */
+ u8 processor_id; /* ACPI processor ID */
+ u16 flags; /* MPS INTI flags */
+ u8 lint; /* Local APIC LINT# */
+} __attribute__ ((packed)) acpi_madt_lapic_nmi_t;
+
+/* MADT: I/O APIC Structure */
+typedef struct acpi_madt_ioapic {
+ u8 type; /* Type (1) */
+ u8 length; /* Length in bytes (12) */
+ u8 ioapic_id; /* I/O APIC ID */
+ u8 reserved;
+ u32 ioapic_addr; /* I/O APIC address */
+ u32 gsi_base; /* Global system interrupt base */
+} __attribute__ ((packed)) acpi_madt_ioapic_t;
+
+/* MADT: Interrupt Source Override Structure */
+typedef struct acpi_madt_irqoverride {
+ u8 type; /* Type (2) */
+ u8 length; /* Length in bytes (10) */
+ u8 bus; /* ISA (0) */
+ u8 source; /* Bus-relative int. source (IRQ) */
+ u32 gsirq; /* Global system interrupt */
+ u16 flags; /* MPS INTI flags */
+} __attribute__ ((packed)) acpi_madt_irqoverride_t;
+
+/* FADT (Fixed ACPI Description Table) */
+typedef struct acpi_fadt {
+ struct acpi_table_header header;
+ u32 firmware_ctrl;
+ u32 dsdt;
+ u8 model;
+ u8 preferred_pm_profile;
+ u16 sci_int;
+ u32 smi_cmd;
+ u8 acpi_enable;
+ u8 acpi_disable;
+ u8 s4bios_req;
+ u8 pstate_cnt;
+ u32 pm1a_evt_blk;
+ u32 pm1b_evt_blk;
+ u32 pm1a_cnt_blk;
+ u32 pm1b_cnt_blk;
+ u32 pm2_cnt_blk;
+ u32 pm_tmr_blk;
+ u32 gpe0_blk;
+ u32 gpe1_blk;
+ u8 pm1_evt_len;
+ u8 pm1_cnt_len;
+ u8 pm2_cnt_len;
+ u8 pm_tmr_len;
+ u8 gpe0_blk_len;
+ u8 gpe1_blk_len;
+ u8 gpe1_base;
+ u8 cst_cnt;
+ u16 p_lvl2_lat;
+ u16 p_lvl3_lat;
+ u16 flush_size;
+ u16 flush_stride;
+ u8 duty_offset;
+ u8 duty_width;
+ u8 day_alrm;
+ u8 mon_alrm;
+ u8 century;
+ u16 iapc_boot_arch;
+ u8 res2;
+ u32 flags;
+ struct acpi_gen_regaddr reset_reg;
+ u8 reset_value;
+ u8 res3;
+ u8 res4;
+ u8 res5;
+ u32 x_firmware_ctl_l;
+ u32 x_firmware_ctl_h;
+ u32 x_dsdt_l;
+ u32 x_dsdt_h;
+ struct acpi_gen_regaddr x_pm1a_evt_blk;
+ struct acpi_gen_regaddr x_pm1b_evt_blk;
+ struct acpi_gen_regaddr x_pm1a_cnt_blk;
+ struct acpi_gen_regaddr x_pm1b_cnt_blk;
+ struct acpi_gen_regaddr x_pm2_cnt_blk;
+ struct acpi_gen_regaddr x_pm_tmr_blk;
+ struct acpi_gen_regaddr x_gpe0_blk;
+ struct acpi_gen_regaddr x_gpe1_blk;
+} __attribute__ ((packed)) acpi_fadt_t;
+
+/* FADT Feature Flags */
+#define ACPI_FADT_WBINVD (1 << 0)
+#define ACPI_FADT_WBINVD_FLUSH (1 << 1)
+#define ACPI_FADT_C1_SUPPORTED (1 << 2)
+#define ACPI_FADT_C2_MP_SUPPORTED (1 << 3)
+#define ACPI_FADT_POWER_BUTTON (1 << 4)
+#define ACPI_FADT_SLEEP_BUTTON (1 << 5)
+#define ACPI_FADT_FIXED_RTC (1 << 6)
+#define ACPI_FADT_S4_RTC_WAKE (1 << 7)
+#define ACPI_FADT_32BIT_TIMER (1 << 8)
+#define ACPI_FADT_DOCKING_SUPPORTED (1 << 9)
+#define ACPI_FADT_RESET_REGISTER (1 << 10)
+#define ACPI_FADT_SEALED_CASE (1 << 11)
+#define ACPI_FADT_HEADLESS (1 << 12)
+#define ACPI_FADT_SLEEP_TYPE (1 << 13)
+#define ACPI_FADT_PCI_EXPRESS_WAKE (1 << 14)
+#define ACPI_FADT_PLATFORM_CLOCK (1 << 15)
+#define ACPI_FADT_S4_RTC_VALID (1 << 16)
+#define ACPI_FADT_REMOTE_POWER_ON (1 << 17)
+#define ACPI_FADT_APIC_CLUSTER (1 << 18)
+#define ACPI_FADT_APIC_PHYSICAL (1 << 19)
+/* Bits 20-31: reserved */
+
+/* FADT Boot Architecture Flags */
+#define ACPI_FADT_LEGACY_DEVICES (1 << 0)
+#define ACPI_FADT_8042 (1 << 1)
+#define ACPI_FADT_VGA_NOT_PRESENT (1 << 2)
+#define ACPI_FADT_MSI_NOT_SUPPORTED (1 << 3)
+#define ACPI_FADT_NO_PCIE_ASPM_CONTROL (1 << 4)
+
+/* FADT Preferred Power Management Profile */
+enum acpi_preferred_pm_profiles {
+ PM_UNSPECIFIED = 0,
+ PM_DESKTOP = 1,
+ PM_MOBILE = 2,
+ PM_WORKSTATION = 3,
+ PM_ENTERPRISE_SERVER = 4,
+ PM_SOHO_SERVER = 5,
+ PM_APPLIANCE_PC = 6,
+ PM_PERFORMANCE_SERVER = 7,
+};
+
+/* FACS (Firmware ACPI Control Structure) */
+typedef struct acpi_facs {
+ char signature[4]; /* "FACS" */
+ u32 length; /* Length in bytes (>= 64) */
+ u32 hardware_signature; /* Hardware signature */
+ u32 firmware_waking_vector; /* Firmware waking vector */
+ u32 global_lock; /* Global lock */
+ u32 flags; /* FACS flags */
+ u32 x_firmware_waking_vector_l; /* X FW waking vector, low */
+ u32 x_firmware_waking_vector_h; /* X FW waking vector, high */
+ u8 version; /* ACPI 4.0: 2 */
+ u8 resv[31]; /* FIXME: 4.0: ospm_flags */
+} __attribute__ ((packed)) acpi_facs_t;
+
+/* FACS flags */
+#define ACPI_FACS_S4BIOS_F (1 << 0)
+#define ACPI_FACS_64BIT_WAKE_F (1 << 1)
+/* Bits 31..2: reserved */
+
+/* ECDT (Embedded Controller Boot Resources Table) */
+typedef struct acpi_ecdt {
+ struct acpi_table_header header;
+ struct acpi_gen_regaddr ec_control; /* EC control register */
+ struct acpi_gen_regaddr ec_data; /* EC data register */
+ u32 uid; /* UID */
+ u8 gpe_bit; /* GPE bit */
+ u8 ec_id[]; /* EC ID */
+} __attribute__ ((packed)) acpi_ecdt_t;
+
+/* These are implemented by the target port or north/southbridge. */
+unsigned long write_acpi_tables(unsigned long addr);
+unsigned long acpi_fill_madt(unsigned long current);
+unsigned long acpi_fill_mcfg(unsigned long current);
+unsigned long acpi_fill_srat(unsigned long current);
+unsigned long acpi_fill_slit(unsigned long current);
+unsigned long acpi_fill_ssdt_generator(unsigned long current,
+ const char *oem_table_id);
+void acpi_create_ssdt_generator(acpi_header_t *ssdt, const char *oem_table_id);
+void acpi_create_fadt(acpi_fadt_t *fadt,acpi_facs_t *facs, void *dsdt);
+
+void update_ssdt(void *ssdt);
+void update_ssdtx(void *ssdtx, int i);
+
+/* These can be used by the target port. */
+u8 acpi_checksum(u8 *table, u32 length);
+
+void acpi_add_table(acpi_rsdp_t *rsdp, void *table);
+
+int acpi_create_madt_lapic(acpi_madt_lapic_t *lapic, u8 cpu, u8 apic);
+int acpi_create_madt_ioapic(acpi_madt_ioapic_t *ioapic, u8 id, u32 addr,
+ u32 gsi_base);
+int acpi_create_madt_irqoverride(acpi_madt_irqoverride_t *irqoverride,
+ u8 bus, u8 source, u32 gsirq, u16 flags);
+int acpi_create_madt_lapic_nmi(acpi_madt_lapic_nmi_t *lapic_nmi, u8 cpu,
+ u16 flags, u8 lint);
+void acpi_create_madt(acpi_madt_t *madt);
+unsigned long acpi_create_madt_lapics(unsigned long current);
+unsigned long acpi_create_madt_lapic_nmis(unsigned long current, u16 flags,
+ u8 lint);
+
+int acpi_create_srat_lapic(acpi_srat_lapic_t *lapic, u8 node, u8 apic);
+int acpi_create_srat_mem(acpi_srat_mem_t *mem, u8 node, u32 basek,u32 sizek,
+ u32 flags);
+int acpi_create_mcfg_mmconfig(acpi_mcfg_mmconfig_t *mmconfig, u32 base,
+ u16 seg_nr, u8 start, u8 end);
+unsigned long acpi_create_srat_lapics(unsigned long current);
+void acpi_create_srat(acpi_srat_t *srat);
+
+void acpi_create_slit(acpi_slit_t *slit);
+
+void acpi_create_hpet(acpi_hpet_t *hpet);
+
+void acpi_create_mcfg(acpi_mcfg_t *mcfg);
+
+void acpi_create_facs(acpi_facs_t *facs);
+
+#if CONFIG_HAVE_ACPI_SLIC
+unsigned long acpi_create_slic(unsigned long current);
+#endif
+
+void acpi_write_rsdt(acpi_rsdt_t *rsdt);
+void acpi_write_xsdt(acpi_xsdt_t *xsdt);
+void acpi_write_rsdp(acpi_rsdp_t *rsdp, acpi_rsdt_t *rsdt, acpi_xsdt_t *xsdt);
+
+#if CONFIG_HAVE_ACPI_RESUME
+/* 0 = S0, 1 = S1 ...*/
+extern u8 acpi_slp_type;
+
+void suspend_resume(void);
+void *acpi_find_wakeup_vector(void);
+void *acpi_get_wakeup_rsdp(void);
+void acpi_jump_to_wakeup(void *wakeup_addr);
+
+int acpi_get_sleep_type(void);
+
+#endif
+
+/* northbridge/amd/amdfam10/amdfam10_acpi.c */
+unsigned long acpi_add_ssdt_pstates(acpi_rsdp_t *rsdp, unsigned long current);
+
+/* cpu/intel/speedstep/acpi.c */
+void generate_cpu_entries(void);
+
+#else // CONFIG_GENERATE_ACPI_TABLES
+
+#define write_acpi_tables(start) (start)
+
+#endif
+
+#endif
diff --git a/src/arch/x86/include/arch/acpigen.h b/src/arch/x86/include/arch/acpigen.h
new file mode 100644
index 0000000000..6f13a7ae1f
--- /dev/null
+++ b/src/arch/x86/include/arch/acpigen.h
@@ -0,0 +1,56 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2009 Rudolf Marek <r.marek@assembler.cz>
+ *
+ * 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
+ */
+
+#ifndef LIBACPI_H
+#define LIBACPI_H
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+void acpigen_patch_len(int len);
+void acpigen_set_current(char *curr);
+char *acpigen_get_current(void);
+int acpigen_write_package(int nr_el);
+int acpigen_write_byte(unsigned int data);
+int acpigen_emit_byte(unsigned char data);
+int acpigen_emit_stream(const char *data, int size);
+int acpigen_emit_namestring(const char *namepath);
+int acpigen_write_dword(unsigned int data);
+int acpigen_write_qword(uint64_t data);
+int acpigen_write_name(const char *name);
+int acpigen_write_name_dword(const char *name, uint32_t val);
+int acpigen_write_name_qword(const char *name, uint64_t val);
+int acpigen_write_name_byte(const char *name, uint8_t val);
+int acpigen_write_scope(const char *name);
+int acpigen_write_PPC(u8 nr);
+int acpigen_write_empty_PCT(void);
+int acpigen_write_PSS_package(u32 coreFreq, u32 power, u32 transLat, u32 busmLat,
+ u32 control, u32 status);
+typedef enum { SW_ALL=0xfc, SW_ANY=0xfd, HW_ALL=0xfe } PSD_coord;
+int acpigen_write_PSD_package(u32 domain, u32 numprocs, PSD_coord coordtype);
+int acpigen_write_processor(u8 cpuindex, u32 pblock_addr, u8 pblock_len);
+int acpigen_write_mem32fixed(int readwrite, u32 base, u32 size);
+int acpigen_write_io16(u16 min, u16 max, u8 align, u8 len, u8 decode16);
+int acpigen_write_resourcetemplate_header(void);
+int acpigen_write_resourcetemplate_footer(int len);
+int acpigen_write_mainboard_resource_template(void);
+int acpigen_write_mainboard_resources(const char *scope, const char *name);
+
+#endif
diff --git a/src/arch/x86/include/arch/boot/boot.h b/src/arch/x86/include/arch/boot/boot.h
new file mode 100644
index 0000000000..3ff51c3082
--- /dev/null
+++ b/src/arch/x86/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/x86/include/arch/byteorder.h b/src/arch/x86/include/arch/byteorder.h
new file mode 100644
index 0000000000..ab344e6394
--- /dev/null
+++ b/src/arch/x86/include/arch/byteorder.h
@@ -0,0 +1,20 @@
+#ifndef _BYTEORDER_H
+#define _BYTEORDER_H
+
+#define __LITTLE_ENDIAN 1234
+
+#include <swab.h>
+
+#define cpu_to_le32(x) ((unsigned int)(x))
+#define le32_to_cpu(x) ((unsigned int)(x))
+#define cpu_to_le16(x) ((unsigned short)(x))
+#define le16_to_cpu(x) ((unsigned short)(x))
+#define cpu_to_be32(x) swab32((x))
+#define be32_to_cpu(x) swab32((x))
+#define cpu_to_be16(x) swab16((x))
+#define be16_to_cpu(x) swab16((x))
+
+#define ntohl(x) be32_to_cpu(x)
+#define htonl(x) cpu_to_be32(x)
+
+#endif /* _BYTEORDER_H */
diff --git a/src/arch/x86/include/arch/coreboot_tables.h b/src/arch/x86/include/arch/coreboot_tables.h
new file mode 100644
index 0000000000..3c9bf98f22
--- /dev/null
+++ b/src/arch/x86/include/arch/coreboot_tables.h
@@ -0,0 +1,25 @@
+#ifndef COREBOOT_TABLE_H
+#define COREBOOT_TABLE_H
+
+#include <boot/coreboot_tables.h>
+
+/* This file holds function prototypes for building the coreboot table. */
+unsigned long write_coreboot_table(
+ unsigned long low_table_start, unsigned long low_table_end,
+ unsigned long rom_table_start, unsigned long rom_table_end);
+
+void lb_memory_range(struct lb_memory *mem,
+ uint32_t type, uint64_t start, uint64_t size);
+
+/* Routines to extract part so the coreboot table or information
+ * from the coreboot table.
+ */
+struct lb_memory *get_lb_mem(void);
+
+extern struct cmos_option_table option_table;
+
+/* defined by mainboard.c if the mainboard requires extra resources */
+int add_mainboard_resources(struct lb_memory *mem);
+int add_northbridge_resources(struct lb_memory *mem);
+
+#endif /* COREBOOT_TABLE_H */
diff --git a/src/arch/x86/include/arch/cpu.h b/src/arch/x86/include/arch/cpu.h
new file mode 100644
index 0000000000..4d7be86223
--- /dev/null
+++ b/src/arch/x86/include/arch/cpu.h
@@ -0,0 +1,165 @@
+#ifndef ARCH_CPU_H
+#define ARCH_CPU_H
+
+/*
+ * EFLAGS bits
+ */
+#define X86_EFLAGS_CF 0x00000001 /* Carry Flag */
+#define X86_EFLAGS_PF 0x00000004 /* Parity Flag */
+#define X86_EFLAGS_AF 0x00000010 /* Auxillary carry Flag */
+#define X86_EFLAGS_ZF 0x00000040 /* Zero Flag */
+#define X86_EFLAGS_SF 0x00000080 /* Sign Flag */
+#define X86_EFLAGS_TF 0x00000100 /* Trap Flag */
+#define X86_EFLAGS_IF 0x00000200 /* Interrupt Flag */
+#define X86_EFLAGS_DF 0x00000400 /* Direction Flag */
+#define X86_EFLAGS_OF 0x00000800 /* Overflow Flag */
+#define X86_EFLAGS_IOPL 0x00003000 /* IOPL mask */
+#define X86_EFLAGS_NT 0x00004000 /* Nested Task */
+#define X86_EFLAGS_RF 0x00010000 /* Resume Flag */
+#define X86_EFLAGS_VM 0x00020000 /* Virtual Mode */
+#define X86_EFLAGS_AC 0x00040000 /* Alignment Check */
+#define X86_EFLAGS_VIF 0x00080000 /* Virtual Interrupt Flag */
+#define X86_EFLAGS_VIP 0x00100000 /* Virtual Interrupt Pending */
+#define X86_EFLAGS_ID 0x00200000 /* CPUID detection flag */
+
+struct cpuid_result {
+ uint32_t eax;
+ uint32_t ebx;
+ uint32_t ecx;
+ uint32_t edx;
+};
+
+/*
+ * Generic CPUID function
+ */
+static inline struct cpuid_result cpuid(int op)
+{
+ struct cpuid_result result;
+ asm volatile(
+ "cpuid"
+ : "=a" (result.eax),
+ "=b" (result.ebx),
+ "=c" (result.ecx),
+ "=d" (result.edx)
+ : "0" (op));
+ return result;
+}
+
+/*
+ * CPUID functions returning a single datum
+ */
+static inline unsigned int cpuid_eax(unsigned int op)
+{
+ unsigned int eax;
+
+ __asm__("cpuid"
+ : "=a" (eax)
+ : "0" (op)
+ : "ebx", "ecx", "edx");
+ return eax;
+}
+
+static inline unsigned int cpuid_ebx(unsigned int op)
+{
+ unsigned int eax, ebx;
+
+ __asm__("cpuid"
+ : "=a" (eax), "=b" (ebx)
+ : "0" (op)
+ : "ecx", "edx" );
+ return ebx;
+}
+
+static inline unsigned int cpuid_ecx(unsigned int op)
+{
+ unsigned int eax, ecx;
+
+ __asm__("cpuid"
+ : "=a" (eax), "=c" (ecx)
+ : "0" (op)
+ : "ebx", "edx" );
+ return ecx;
+}
+
+static inline unsigned int cpuid_edx(unsigned int op)
+{
+ unsigned int eax, edx;
+
+ __asm__("cpuid"
+ : "=a" (eax), "=d" (edx)
+ : "0" (op)
+ : "ebx", "ecx");
+ return edx;
+}
+
+#define X86_VENDOR_INVALID 0
+#define X86_VENDOR_INTEL 1
+#define X86_VENDOR_CYRIX 2
+#define X86_VENDOR_AMD 3
+#define X86_VENDOR_UMC 4
+#define X86_VENDOR_NEXGEN 5
+#define X86_VENDOR_CENTAUR 6
+#define X86_VENDOR_RISE 7
+#define X86_VENDOR_TRANSMETA 8
+#define X86_VENDOR_NSC 9
+#define X86_VENDOR_SIS 10
+#define X86_VENDOR_UNKNOWN 0xff
+
+#if !defined(__PRE_RAM__)
+#include <device/device.h>
+
+struct cpu_device_id {
+ unsigned vendor;
+ unsigned device;
+};
+
+struct cpu_driver {
+ struct device_operations *ops;
+ struct cpu_device_id *id_table;
+};
+
+struct cpu_info {
+ device_t cpu;
+ unsigned long index;
+};
+
+static inline struct cpu_info *cpu_info(void)
+{
+ struct cpu_info *ci;
+ __asm__("andl %%esp,%0; "
+ "orl %2, %0 "
+ :"=r" (ci)
+ : "0" (~(CONFIG_STACK_SIZE - 1)),
+ "r" (CONFIG_STACK_SIZE - sizeof(struct cpu_info))
+ );
+ return ci;
+}
+
+static inline unsigned long cpu_index(void)
+{
+ struct cpu_info *ci;
+ ci = cpu_info();
+ return ci->index;
+}
+
+struct cpuinfo_x86 {
+ uint8_t x86; /* CPU family */
+ uint8_t x86_vendor; /* CPU vendor */
+ uint8_t x86_model;
+ uint8_t x86_mask;
+};
+
+static void inline get_fms(struct cpuinfo_x86 *c, uint32_t tfms)
+{
+ c->x86 = (tfms >> 8) & 0xf;
+ c->x86_model = (tfms >> 4) & 0xf;
+ c->x86_mask = tfms & 0xf;
+ if (c->x86 == 0xf)
+ c->x86 += (tfms >> 20) & 0xff;
+ if (c->x86 >= 0x6)
+ c->x86_model += ((tfms >> 16) & 0xF) << 4;
+
+}
+#endif
+
+#endif /* ARCH_CPU_H */
diff --git a/src/arch/x86/include/arch/hlt.h b/src/arch/x86/include/arch/hlt.h
new file mode 100644
index 0000000000..ddfe169954
--- /dev/null
+++ b/src/arch/x86/include/arch/hlt.h
@@ -0,0 +1,16 @@
+#ifndef ARCH_HLT_H
+#define ARCH_HLT_H
+
+#if defined(__ROMCC__)
+static void hlt(void)
+{
+ __builtin_hlt();
+}
+#else
+static inline __attribute__((always_inline)) void hlt(void)
+{
+ asm("hlt");
+}
+#endif
+
+#endif /* ARCH_HLT_H */
diff --git a/src/arch/x86/include/arch/interrupt.h b/src/arch/x86/include/arch/interrupt.h
new file mode 100644
index 0000000000..2d2330b739
--- /dev/null
+++ b/src/arch/x86/include/arch/interrupt.h
@@ -0,0 +1,25 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2009 coresystems GmbH
+ * Copyright (C) 2009 Libra Li <libra.li@technexion.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "registers.h"
+
+/* setup interrupt handlers for mainboard */
+extern void mainboard_interrupt_handlers(int intXX, void *intXX_func);
diff --git a/src/arch/x86/include/arch/io.h b/src/arch/x86/include/arch/io.h
new file mode 100644
index 0000000000..aad84088d6
--- /dev/null
+++ b/src/arch/x86/include/arch/io.h
@@ -0,0 +1,168 @@
+#ifndef _ASM_IO_H
+#define _ASM_IO_H
+
+#include <stdint.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). You can also use "pausing"
+ * versions of the single-IO instructions (inb_p/inw_p/..).
+ */
+#if defined(__ROMCC__)
+static inline void outb(uint8_t value, uint16_t port)
+{
+ __builtin_outb(value, port);
+}
+
+static inline void outw(uint16_t value, uint16_t port)
+{
+ __builtin_outw(value, port);
+}
+
+static inline void outl(uint32_t value, uint16_t port)
+{
+ __builtin_outl(value, port);
+}
+
+
+static inline uint8_t inb(uint16_t port)
+{
+ return __builtin_inb(port);
+}
+
+
+static inline uint16_t inw(uint16_t port)
+{
+ return __builtin_inw(port);
+}
+
+static inline uint32_t inl(uint16_t port)
+{
+ return __builtin_inl(port);
+}
+#else
+static inline void outb(uint8_t value, uint16_t port)
+{
+ __asm__ __volatile__ ("outb %b0, %w1" : : "a" (value), "Nd" (port));
+}
+
+static inline void outw(uint16_t value, uint16_t port)
+{
+ __asm__ __volatile__ ("outw %w0, %w1" : : "a" (value), "Nd" (port));
+}
+
+static inline void outl(uint32_t value, uint16_t port)
+{
+ __asm__ __volatile__ ("outl %0, %w1" : : "a" (value), "Nd" (port));
+}
+
+static inline uint8_t inb(uint16_t port)
+{
+ uint8_t value;
+ __asm__ __volatile__ ("inb %w1, %b0" : "=a"(value) : "Nd" (port));
+ return value;
+}
+
+static inline uint16_t inw(uint16_t port)
+{
+ uint16_t value;
+ __asm__ __volatile__ ("inw %w1, %w0" : "=a"(value) : "Nd" (port));
+ return value;
+}
+
+static inline uint32_t inl(uint16_t port)
+{
+ uint32_t value;
+ __asm__ __volatile__ ("inl %w1, %0" : "=a"(value) : "Nd" (port));
+ return value;
+}
+#endif /* __ROMCC__ */
+
+static inline void outsb(uint16_t port, const void *addr, unsigned long count)
+{
+ __asm__ __volatile__ (
+ "cld ; rep ; outsb "
+ : "=S" (addr), "=c" (count)
+ : "d"(port), "0"(addr), "1" (count)
+ );
+}
+
+static inline void outsw(uint16_t port, const void *addr, unsigned long count)
+{
+ __asm__ __volatile__ (
+ "cld ; rep ; outsw "
+ : "=S" (addr), "=c" (count)
+ : "d"(port), "0"(addr), "1" (count)
+ );
+}
+
+static inline void outsl(uint16_t port, const void *addr, unsigned long count)
+{
+ __asm__ __volatile__ (
+ "cld ; rep ; outsl "
+ : "=S" (addr), "=c" (count)
+ : "d"(port), "0"(addr), "1" (count)
+ );
+}
+
+
+static inline void insb(uint16_t port, void *addr, unsigned long count)
+{
+ __asm__ __volatile__ (
+ "cld ; rep ; insb "
+ : "=D" (addr), "=c" (count)
+ : "d"(port), "0"(addr), "1" (count)
+ );
+}
+
+static inline void insw(uint16_t port, void *addr, unsigned long count)
+{
+ __asm__ __volatile__ (
+ "cld ; rep ; insw "
+ : "=D" (addr), "=c" (count)
+ : "d"(port), "0"(addr), "1" (count)
+ );
+}
+
+static inline void insl(uint16_t port, void *addr, unsigned long count)
+{
+ __asm__ __volatile__ (
+ "cld ; rep ; insl "
+ : "=D" (addr), "=c" (count)
+ : "d"(port), "0"(addr), "1" (count)
+ );
+}
+
+static inline __attribute__((always_inline)) uint8_t read8(unsigned long addr)
+{
+ return *((volatile uint8_t *)(addr));
+}
+
+static inline __attribute__((always_inline)) uint16_t read16(unsigned long addr)
+{
+ return *((volatile uint16_t *)(addr));
+}
+
+static inline __attribute__((always_inline)) uint32_t read32(unsigned long addr)
+{
+ return *((volatile uint32_t *)(addr));
+}
+
+static inline __attribute__((always_inline)) void write8(unsigned long addr, uint8_t value)
+{
+ *((volatile uint8_t *)(addr)) = value;
+}
+
+static inline __attribute__((always_inline)) void write16(unsigned long addr, uint16_t value)
+{
+ *((volatile uint16_t *)(addr)) = value;
+}
+
+static inline __attribute__((always_inline)) void write32(unsigned long addr, uint32_t value)
+{
+ *((volatile uint32_t *)(addr)) = value;
+}
+
+#endif
+
diff --git a/src/arch/x86/include/arch/ioapic.h b/src/arch/x86/include/arch/ioapic.h
new file mode 100644
index 0000000000..623f617253
--- /dev/null
+++ b/src/arch/x86/include/arch/ioapic.h
@@ -0,0 +1,44 @@
+/*
+ * 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
+ */
+
+#ifndef __I386_ARCH_IOAPIC_H
+#define __I386_ARCH_IOAPIC_H
+
+#define IO_APIC_ADDR 0xfec00000UL
+#define IO_APIC_INTERRUPTS 24
+
+#define ALL (0xff << 24)
+#define NONE (0)
+#define DISABLED (1 << 16)
+#define ENABLED (0 << 16)
+#define TRIGGER_EDGE (0 << 15)
+#define TRIGGER_LEVEL (1 << 15)
+#define POLARITY_HIGH (0 << 13)
+#define POLARITY_LOW (1 << 13)
+#define PHYSICAL_DEST (0 << 11)
+#define LOGICAL_DEST (1 << 11)
+#define ExtINT (7 << 8)
+#define NMI (4 << 8)
+#define SMI (2 << 8)
+#define INT (1 << 8)
+
+void setup_ioapic(u32 ioapic_base, u8 ioapic_id);
+void clear_ioapic(u32 ioapic_base);
+
+#endif
diff --git a/src/arch/x86/include/arch/llshell.h b/src/arch/x86/include/arch/llshell.h
new file mode 100644
index 0000000000..556df7d046
--- /dev/null
+++ b/src/arch/x86/include/arch/llshell.h
@@ -0,0 +1,11 @@
+#ifndef __ARCH_LLSHELL__
+#define __ARCH_LLSHELL__
+
+
+#if CONFIG_LLSHELL
+#define llshell() asm("jmp low_level_shell");
+#else
+#define llshell() print_debug("LLSHELL not active.\n");
+#endif
+
+#endif
diff --git a/src/arch/x86/include/arch/mmio_conf.h b/src/arch/x86/include/arch/mmio_conf.h
new file mode 100644
index 0000000000..08962f02fa
--- /dev/null
+++ b/src/arch/x86/include/arch/mmio_conf.h
@@ -0,0 +1,67 @@
+#ifndef ARCH_MMIO_H
+#define ARCH_MMIO_H 1
+
+
+// Extended read, constrain to use registers as mandated by AMD MMCONFIG mechanism.
+
+static inline __attribute__((always_inline)) uint8_t read8x(uint32_t addr)
+{
+ uint8_t value;
+ __asm__ volatile (
+ "movb (%1), %%al\n\t"
+ :"=a"(value): "b" (addr)
+ );
+ return value;
+}
+
+static inline __attribute__((always_inline)) uint16_t read16x(uint32_t addr)
+{
+ uint16_t value;
+ __asm__ volatile (
+ "movw (%1), %%ax\n\t"
+ :"=a"(value): "b" (addr)
+ );
+
+ return value;
+
+}
+
+static inline __attribute__((always_inline)) uint32_t read32x(uint32_t addr)
+{
+ uint32_t value;
+ __asm__ volatile (
+ "movl (%1), %%eax\n\t"
+ :"=a"(value): "b" (addr)
+ );
+
+ return value;
+
+}
+
+static inline __attribute__((always_inline)) void write8x(uint32_t addr, uint8_t value)
+{
+ __asm__ volatile (
+ "movb %%al, (%0)\n\t"
+ :: "b" (addr), "a" (value)
+ );
+
+}
+
+static inline __attribute__((always_inline)) void write16x(uint32_t addr, uint16_t value)
+{
+ __asm__ volatile (
+ "movw %%ax, (%0)\n\t"
+ :: "b" (addr), "a" (value)
+ );
+
+}
+
+static inline __attribute__((always_inline)) void write32x(uint32_t addr, uint32_t value)
+{
+ __asm__ volatile (
+ "movl %%eax, (%0)\n\t"
+ :: "b" (addr), "a" (value)
+ );
+}
+
+#endif /* ARCH_MMIO_H */
diff --git a/src/arch/x86/include/arch/pci_ops.h b/src/arch/x86/include/arch/pci_ops.h
new file mode 100644
index 0000000000..9c4e029b24
--- /dev/null
+++ b/src/arch/x86/include/arch/pci_ops.h
@@ -0,0 +1,13 @@
+#ifndef ARCH_I386_PCI_OPS_H
+#define ARCH_I386_PCI_OPS_H
+
+extern const struct pci_bus_operations pci_cf8_conf1;
+extern const struct pci_bus_operations pci_cf8_conf2;
+
+#if CONFIG_MMCONF_SUPPORT==1
+extern const struct pci_bus_operations pci_ops_mmconf;
+#endif
+
+void pci_set_method(device_t dev);
+
+#endif /* ARCH_I386_PCI_OPS_H */
diff --git a/src/arch/x86/include/arch/pciconf.h b/src/arch/x86/include/arch/pciconf.h
new file mode 100644
index 0000000000..a35693519e
--- /dev/null
+++ b/src/arch/x86/include/arch/pciconf.h
@@ -0,0 +1,14 @@
+#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
+
+#if CONFIG_PCI_IO_CFG_EXT == 0
+#define CONFIG_ADDR(bus,devfn,where) (((bus) << 16) | ((devfn) << 8) | (where))
+#else
+#define CONFIG_ADDR(bus,devfn,where) (((bus) << 16) | ((devfn) << 8) | (where & 0xff) | ((where & 0xf00)<<16) )
+#endif
+
+#endif
diff --git a/src/arch/x86/include/arch/pirq_routing.h b/src/arch/x86/include/arch/pirq_routing.h
new file mode 100644
index 0000000000..0b65eac29b
--- /dev/null
+++ b/src/arch/x86/include/arch/pirq_routing.h
@@ -0,0 +1,54 @@
+#ifndef ARCH_PIRQ_ROUTING_H
+#define ARCH_PIRQ_ROUTING_H
+
+#if CONFIG_GENERATE_PIRQ_TABLE==1
+#include <stdint.h>
+
+#define PIRQ_SIGNATURE (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24))
+#define PIRQ_VERSION 0x0100
+
+struct irq_info {
+ u8 bus, devfn; /* Bus, device and function */
+ struct {
+ u8 link; /* IRQ line ID, chipset dependent, 0=not routed */
+ u16 bitmap; /* Available IRQs */
+ } __attribute__((packed)) irq[4];
+ u8 slot; /* Slot number, 0=onboard */
+ u8 rfu;
+} __attribute__((packed));
+
+#ifndef CONFIG_IRQ_SLOT_COUNT
+#warning "IRQ_SLOT_COUNT is not defined in Kconfig. PIRQ won't work correctly."
+#endif
+
+struct irq_routing_table {
+ u32 signature; /* PIRQ_SIGNATURE should be here */
+ u16 version; /* PIRQ_VERSION */
+ u16 size; /* Table size in bytes */
+ u8 rtr_bus, rtr_devfn; /* Where the interrupt router lies */
+ u16 exclusive_irqs; /* IRQs devoted exclusively to PCI usage */
+ u16 rtr_vendor, rtr_device;/* Vendor/device ID of interrupt router */
+ u32 miniport_data;
+ u8 rfu[11];
+ u8 checksum; /* Modulo 256 checksum must give zero */
+ struct irq_info slots[CONFIG_IRQ_SLOT_COUNT];
+} __attribute__((packed));
+
+extern const struct irq_routing_table intel_irq_routing_table;
+
+unsigned long copy_pirq_routing_table(unsigned long start);
+unsigned long write_pirq_routing_table(unsigned long start);
+
+#if CONFIG_PIRQ_ROUTE==1
+void pirq_routing_irqs(unsigned long start);
+void pirq_assign_irqs(const unsigned char pIntAtoD[4]);
+#else
+#define pirq_routing_irqs(start) {}
+#endif
+
+#else
+#define copy_pirq_routing_table(start) (start)
+#define write_pirq_routing_table(start) (start)
+#endif
+
+#endif /* ARCH_PIRQ_ROUTING_H */
diff --git a/src/arch/x86/include/arch/registers.h b/src/arch/x86/include/arch/registers.h
new file mode 100644
index 0000000000..bc1b681339
--- /dev/null
+++ b/src/arch/x86/include/arch/registers.h
@@ -0,0 +1,32 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 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
+ */
+
+#ifndef __ARCH_REGISTERS_H
+#define __ARCH_REGISTERS_H
+
+struct eregs {
+ uint32_t eax, ecx, edx, ebx, esp, ebp, esi, edi;
+ uint32_t vector;
+ uint32_t error_code;
+ uint32_t eip;
+ uint32_t cs;
+ uint32_t eflags;
+};
+
+#endif
diff --git a/src/arch/x86/include/arch/rom_segs.h b/src/arch/x86/include/arch/rom_segs.h
new file mode 100644
index 0000000000..8c00eb3b7a
--- /dev/null
+++ b/src/arch/x86/include/arch/rom_segs.h
@@ -0,0 +1,7 @@
+#ifndef ROM_SEGS_H
+#define ROM_SEGS_H
+
+#define ROM_CODE_SEG 0x08
+#define ROM_DATA_SEG 0x10
+
+#endif /* ROM_SEGS_H */
diff --git a/src/arch/x86/include/arch/romcc_io.h b/src/arch/x86/include/arch/romcc_io.h
new file mode 100644
index 0000000000..79ea26550e
--- /dev/null
+++ b/src/arch/x86/include/arch/romcc_io.h
@@ -0,0 +1,341 @@
+#ifndef ARCH_ROMCC_IO_H
+#define ARCH_ROMCC_IO_H 1
+
+#include <stdint.h>
+
+// arch/io.h is pulled in in many places but it could
+// also be pulled in here for all romcc/romstage code.
+// #include <arch/io.h>
+
+#if CONFIG_MMCONF_SUPPORT
+
+#include <arch/mmio_conf.h>
+
+#endif
+
+static inline int log2(int value)
+{
+ unsigned int r = 0;
+ __asm__ volatile (
+ "bsrl %1, %0\n\t"
+ "jnz 1f\n\t"
+ "movl $-1, %0\n\t"
+ "1:\n\t"
+ : "=r" (r) : "r" (value));
+ return r;
+
+}
+static inline int log2f(int value)
+{
+ unsigned int r = 0;
+ __asm__ volatile (
+ "bsfl %1, %0\n\t"
+ "jnz 1f\n\t"
+ "movl $-1, %0\n\t"
+ "1:\n\t"
+ : "=r" (r) : "r" (value));
+ return r;
+
+}
+
+#define PCI_ADDR(SEGBUS, DEV, FN, WHERE) ( \
+ (((SEGBUS) & 0xFFF) << 20) | \
+ (((DEV) & 0x1F) << 15) | \
+ (((FN) & 0x07) << 12) | \
+ ((WHERE) & 0xFFF))
+
+#define PCI_DEV(SEGBUS, DEV, FN) ( \
+ (((SEGBUS) & 0xFFF) << 20) | \
+ (((DEV) & 0x1F) << 15) | \
+ (((FN) & 0x07) << 12))
+
+#define PCI_ID(VENDOR_ID, DEVICE_ID) \
+ ((((DEVICE_ID) & 0xFFFF) << 16) | ((VENDOR_ID) & 0xFFFF))
+
+
+#define PNP_DEV(PORT, FUNC) (((PORT) << 8) | (FUNC))
+
+typedef unsigned device_t; /* pci and pci_mmio need to have different ways to have dev */
+
+/* FIXME: We need to make the coreboot to run at 64bit mode, So when read/write memory above 4G,
+ * We don't need to set %fs, and %gs anymore
+ * Before that We need to use %gs, and leave %fs to other RAM access
+ */
+
+static inline __attribute__((always_inline)) uint8_t pci_io_read_config8(device_t dev, unsigned where)
+{
+ unsigned addr;
+#if CONFIG_PCI_IO_CFG_EXT == 0
+ addr = (dev>>4) | where;
+#else
+ addr = (dev>>4) | (where & 0xff) | ((where & 0xf00)<<16); //seg == 0
+#endif
+ outl(0x80000000 | (addr & ~3), 0xCF8);
+ return inb(0xCFC + (addr & 3));
+}
+
+#if CONFIG_MMCONF_SUPPORT
+static inline __attribute__((always_inline)) uint8_t pci_mmio_read_config8(device_t dev, unsigned where)
+{
+ unsigned addr;
+ addr = CONFIG_MMCONF_BASE_ADDRESS | dev | where;
+ return read8x(addr);
+}
+#endif
+static inline __attribute__((always_inline)) uint8_t pci_read_config8(device_t dev, unsigned where)
+{
+#if CONFIG_MMCONF_SUPPORT_DEFAULT
+ return pci_mmio_read_config8(dev, where);
+#else
+ return pci_io_read_config8(dev, where);
+#endif
+}
+
+static inline __attribute__((always_inline)) uint16_t pci_io_read_config16(device_t dev, unsigned where)
+{
+ unsigned addr;
+#if CONFIG_PCI_IO_CFG_EXT == 0
+ addr = (dev>>4) | where;
+#else
+ addr = (dev>>4) | (where & 0xff) | ((where & 0xf00)<<16);
+#endif
+ outl(0x80000000 | (addr & ~3), 0xCF8);
+ return inw(0xCFC + (addr & 2));
+}
+
+#if CONFIG_MMCONF_SUPPORT
+static inline __attribute__((always_inline)) uint16_t pci_mmio_read_config16(device_t dev, unsigned where)
+{
+ unsigned addr;
+ addr = CONFIG_MMCONF_BASE_ADDRESS | dev | (where & ~1);
+ return read16x(addr);
+}
+#endif
+
+static inline __attribute__((always_inline)) uint16_t pci_read_config16(device_t dev, unsigned where)
+{
+#if CONFIG_MMCONF_SUPPORT_DEFAULT
+ return pci_mmio_read_config16(dev, where);
+#else
+ return pci_io_read_config16(dev, where);
+#endif
+}
+
+
+static inline __attribute__((always_inline)) uint32_t pci_io_read_config32(device_t dev, unsigned where)
+{
+ unsigned addr;
+#if CONFIG_PCI_IO_CFG_EXT == 0
+ addr = (dev>>4) | where;
+#else
+ addr = (dev>>4) | (where & 0xff) | ((where & 0xf00)<<16);
+#endif
+ outl(0x80000000 | (addr & ~3), 0xCF8);
+ return inl(0xCFC);
+}
+
+#if CONFIG_MMCONF_SUPPORT
+static inline __attribute__((always_inline)) uint32_t pci_mmio_read_config32(device_t dev, unsigned where)
+{
+ unsigned addr;
+ addr = CONFIG_MMCONF_BASE_ADDRESS | dev | (where & ~3);
+ return read32x(addr);
+}
+#endif
+
+static inline __attribute__((always_inline)) uint32_t pci_read_config32(device_t dev, unsigned where)
+{
+#if CONFIG_MMCONF_SUPPORT_DEFAULT
+ return pci_mmio_read_config32(dev, where);
+#else
+ return pci_io_read_config32(dev, where);
+#endif
+}
+
+static inline __attribute__((always_inline)) void pci_io_write_config8(device_t dev, unsigned where, uint8_t value)
+{
+ unsigned addr;
+#if CONFIG_PCI_IO_CFG_EXT == 0
+ addr = (dev>>4) | where;
+#else
+ addr = (dev>>4) | (where & 0xff) | ((where & 0xf00)<<16);
+#endif
+ outl(0x80000000 | (addr & ~3), 0xCF8);
+ outb(value, 0xCFC + (addr & 3));
+}
+
+#if CONFIG_MMCONF_SUPPORT
+static inline __attribute__((always_inline)) void pci_mmio_write_config8(device_t dev, unsigned where, uint8_t value)
+{
+ unsigned addr;
+ addr = CONFIG_MMCONF_BASE_ADDRESS | dev | where;
+ write8x(addr, value);
+}
+#endif
+
+static inline __attribute__((always_inline)) void pci_write_config8(device_t dev, unsigned where, uint8_t value)
+{
+#if CONFIG_MMCONF_SUPPORT_DEFAULT
+ pci_mmio_write_config8(dev, where, value);
+#else
+ pci_io_write_config8(dev, where, value);
+#endif
+}
+
+
+static inline __attribute__((always_inline)) void pci_io_write_config16(device_t dev, unsigned where, uint16_t value)
+{
+ unsigned addr;
+#if CONFIG_PCI_IO_CFG_EXT == 0
+ addr = (dev>>4) | where;
+#else
+ addr = (dev>>4) | (where & 0xff) | ((where & 0xf00)<<16);
+#endif
+ outl(0x80000000 | (addr & ~3), 0xCF8);
+ outw(value, 0xCFC + (addr & 2));
+}
+
+#if CONFIG_MMCONF_SUPPORT
+static inline __attribute__((always_inline)) void pci_mmio_write_config16(device_t dev, unsigned where, uint16_t value)
+{
+ unsigned addr;
+ addr = CONFIG_MMCONF_BASE_ADDRESS | dev | (where & ~1);
+ write16x(addr, value);
+}
+#endif
+
+static inline __attribute__((always_inline)) void pci_write_config16(device_t dev, unsigned where, uint16_t value)
+{
+#if CONFIG_MMCONF_SUPPORT_DEFAULT
+ pci_mmio_write_config16(dev, where, value);
+#else
+ pci_io_write_config16(dev, where, value);
+#endif
+}
+
+
+static inline __attribute__((always_inline)) void pci_io_write_config32(device_t dev, unsigned where, uint32_t value)
+{
+ unsigned addr;
+#if CONFIG_PCI_IO_CFG_EXT == 0
+ addr = (dev>>4) | where;
+#else
+ addr = (dev>>4) | (where & 0xff) | ((where & 0xf00)<<16);
+#endif
+ outl(0x80000000 | (addr & ~3), 0xCF8);
+ outl(value, 0xCFC);
+}
+
+#if CONFIG_MMCONF_SUPPORT
+static inline __attribute__((always_inline)) void pci_mmio_write_config32(device_t dev, unsigned where, uint32_t value)
+{
+ unsigned addr;
+ addr = CONFIG_MMCONF_BASE_ADDRESS | dev | (where & ~3);
+ write32x(addr, value);
+}
+#endif
+
+static inline __attribute__((always_inline)) void pci_write_config32(device_t dev, unsigned where, uint32_t value)
+{
+#if CONFIG_MMCONF_SUPPORT_DEFAULT
+ pci_mmio_write_config32(dev, where, value);
+#else
+ pci_io_write_config32(dev, where, value);
+#endif
+}
+
+#define PCI_DEV_INVALID (0xffffffffU)
+static inline device_t pci_io_locate_device(unsigned pci_id, device_t dev)
+{
+ for(; dev <= PCI_DEV(255, 31, 7); dev += PCI_DEV(0,0,1)) {
+ unsigned int id;
+ id = pci_io_read_config32(dev, 0);
+ if (id == pci_id) {
+ return dev;
+ }
+ }
+ return PCI_DEV_INVALID;
+}
+
+static inline device_t pci_locate_device(unsigned pci_id, device_t dev)
+{
+ for(; dev <= PCI_DEV(255|(((1<<CONFIG_PCI_BUS_SEGN_BITS)-1)<<8), 31, 7); dev += PCI_DEV(0,0,1)) {
+ unsigned int id;
+ id = pci_read_config32(dev, 0);
+ if (id == pci_id) {
+ return dev;
+ }
+ }
+ return PCI_DEV_INVALID;
+}
+
+static inline device_t pci_locate_device_on_bus(unsigned pci_id, unsigned bus)
+{
+ device_t dev, last;
+
+ dev = PCI_DEV(bus, 0, 0);
+ last = PCI_DEV(bus, 31, 7);
+
+ for(; dev <=last; dev += PCI_DEV(0,0,1)) {
+ unsigned int id;
+ id = pci_read_config32(dev, 0);
+ if (id == pci_id) {
+ return dev;
+ }
+ }
+ return PCI_DEV_INVALID;
+}
+
+/* Generic functions for pnp devices */
+static inline __attribute__((always_inline)) void pnp_write_config(device_t dev, uint8_t reg, uint8_t value)
+{
+ unsigned port = dev >> 8;
+ outb(reg, port );
+ outb(value, port +1);
+}
+
+static inline __attribute__((always_inline)) uint8_t pnp_read_config(device_t dev, uint8_t reg)
+{
+ unsigned port = dev >> 8;
+ outb(reg, port);
+ return inb(port +1);
+}
+
+static inline __attribute__((always_inline)) void pnp_set_logical_device(device_t dev)
+{
+ unsigned device = dev & 0xff;
+ pnp_write_config(dev, 0x07, device);
+}
+
+static inline __attribute__((always_inline)) void pnp_set_enable(device_t dev, int enable)
+{
+ pnp_write_config(dev, 0x30, enable?0x1:0x0);
+}
+
+static inline __attribute__((always_inline)) int pnp_read_enable(device_t dev)
+{
+ return !!pnp_read_config(dev, 0x30);
+}
+
+static inline __attribute__((always_inline)) void pnp_set_iobase(device_t dev, unsigned index, unsigned iobase)
+{
+ pnp_write_config(dev, index + 0, (iobase >> 8) & 0xff);
+ pnp_write_config(dev, index + 1, iobase & 0xff);
+}
+
+static inline __attribute__((always_inline)) uint16_t pnp_read_iobase(device_t dev, unsigned index)
+{
+ return ((uint16_t)(pnp_read_config(dev, index)) << 8) | pnp_read_config(dev, index + 1);
+}
+
+static inline __attribute__((always_inline)) void pnp_set_irq(device_t dev, unsigned index, unsigned irq)
+{
+ pnp_write_config(dev, index, irq);
+}
+
+static inline __attribute__((always_inline)) void pnp_set_drq(device_t dev, unsigned index, unsigned drq)
+{
+ pnp_write_config(dev, index, drq & 0xff);
+}
+
+#endif /* ARCH_ROMCC_IO_H */
diff --git a/src/arch/x86/include/arch/smp/atomic.h b/src/arch/x86/include/arch/smp/atomic.h
new file mode 100644
index 0000000000..18bbae27cb
--- /dev/null
+++ b/src/arch/x86/include/arch/smp/atomic.h
@@ -0,0 +1,69 @@
+#ifndef ARCH_SMP_ATOMIC_H
+#define ARCH_SMP_ATOMIC_H
+
+/*
+ * Make sure gcc doesn't try to be clever and move things around
+ * on us. We need to use _exactly_ the address the user gave us,
+ * not some alias that contains the same information.
+ */
+typedef struct { volatile int counter; } atomic_t;
+
+#define ATOMIC_INIT(i) { (i) }
+
+/*
+ * Atomic operations that C can't guarantee us. Useful for
+ * resource counting etc..
+ */
+
+/**
+ * atomic_read - read atomic variable
+ * @v: pointer of type atomic_t
+ *
+ * Atomically reads the value of @v. Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
+#define atomic_read(v) ((v)->counter)
+
+/**
+ * atomic_set - set atomic variable
+ * @v: pointer of type atomic_t
+ * @i: required value
+ *
+ * Atomically sets the value of @v to @i. Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
+#define atomic_set(v,i) (((v)->counter) = (i))
+
+/**
+ * atomic_inc - increment atomic variable
+ * @v: pointer of type atomic_t
+ *
+ * Atomically increments @v by 1. Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
+static __inline__ __attribute__((always_inline)) void atomic_inc(atomic_t *v)
+{
+ __asm__ __volatile__(
+ "lock ; incl %0"
+ :"=m" (v->counter)
+ :"m" (v->counter));
+}
+
+/**
+ * atomic_dec - decrement atomic variable
+ * @v: pointer of type atomic_t
+ *
+ * Atomically decrements @v by 1. Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
+static __inline__ __attribute__((always_inline)) void atomic_dec(atomic_t *v)
+{
+ __asm__ __volatile__(
+ "lock ; decl %0"
+ :"=m" (v->counter)
+ :"m" (v->counter));
+}
+
+
+
+#endif /* ARCH_SMP_ATOMIC_H */
diff --git a/src/arch/x86/include/arch/smp/mpspec.h b/src/arch/x86/include/arch/smp/mpspec.h
new file mode 100644
index 0000000000..bc09f485d8
--- /dev/null
+++ b/src/arch/x86/include/arch/smp/mpspec.h
@@ -0,0 +1,281 @@
+#ifndef __ASM_MPSPEC_H
+#define __ASM_MPSPEC_H
+
+#include <device/device.h>
+/*
+ * 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 */
+#define MP_FEATURE_VIRTUALWIRE (1 << 7)
+#define MP_FEATURE_PIC (0 << 7)
+ unsigned char mpf_feature3; /* Unused (0) */
+ unsigned char mpf_feature4; /* Unused (0) */
+ unsigned char mpf_feature5; /* Unused (0) */
+} __attribute__((packed));
+
+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;
+} __attribute__((packed));
+
+/* 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];
+} __attribute__((packed));
+
+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;
+} __attribute__((packed));
+
+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;
+} __attribute__((packed));
+
+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;
+} __attribute__((packed));
+
+/*
+ * 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;
+} __attribute__((packed));
+
+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;
+} __attribute__((packed));
+
+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];
+} __attribute__((packed));
+
+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
+ */
+} __attribute__((packed));
+
+/* Default local apic addr */
+#define LAPIC_ADDR 0xFEE00000
+
+void mptable_init(struct mp_config_table *mc, const char *productid,
+ u32 lapic_addr);
+
+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);
+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_intsrc_pci_bridge(struct mp_config_table *mc,
+ unsigned char irqtype, unsigned short irqflag,
+ struct device *dev,
+ 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);
+void *smp_write_floating_table_physaddr(unsigned long addr,
+ unsigned long mpf_physptr);
+unsigned long write_smp_table(unsigned long addr);
+
+void mptable_add_isa_interrupts(struct mp_config_table *mc, unsigned long bus_isa, unsigned long apicid, int external);
+void mptable_write_buses(struct mp_config_table *mc, int *max_pci_bus, int *isa_bus);
+
+#endif
+
diff --git a/src/arch/x86/include/arch/smp/spinlock.h b/src/arch/x86/include/arch/smp/spinlock.h
new file mode 100644
index 0000000000..5c1dd94c36
--- /dev/null
+++ b/src/arch/x86/include/arch/smp/spinlock.h
@@ -0,0 +1,64 @@
+#ifndef ARCH_SMP_SPINLOCK_H
+#define ARCH_SMP_SPINLOCK_H
+
+/*
+ * Your basic SMP spinlocks, allowing only a single CPU anywhere
+ */
+
+typedef struct {
+ volatile unsigned int lock;
+} spinlock_t;
+
+
+#define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 }
+#define DECLARE_SPIN_LOCK(x) static spinlock_t x = SPIN_LOCK_UNLOCKED;
+
+/*
+ * Simple spin lock operations. There are two variants, one clears IRQ's
+ * on the local processor, one does not.
+ *
+ * We make no fairness assumptions. They have a cost.
+ */
+#define barrier() __asm__ __volatile__("": : :"memory")
+#define spin_is_locked(x) (*(volatile char *)(&(x)->lock) <= 0)
+#define spin_unlock_wait(x) do { barrier(); } while(spin_is_locked(x))
+
+#define spin_lock_string \
+ "\n1:\t" \
+ "lock ; decb %0\n\t" \
+ "js 2f\n" \
+ ".section .text.lock,\"ax\"\n" \
+ "2:\t" \
+ "cmpb $0,%0\n\t" \
+ "rep;nop\n\t" \
+ "jle 2b\n\t" \
+ "jmp 1b\n" \
+ ".previous"
+
+/*
+ * This works. Despite all the confusion.
+ */
+#define spin_unlock_string \
+ "movb $1,%0"
+
+static inline __attribute__((always_inline)) void spin_lock(spinlock_t *lock)
+{
+ __asm__ __volatile__(
+ spin_lock_string
+ :"=m" (lock->lock) : : "memory");
+}
+
+static inline __attribute__((always_inline)) void spin_unlock(spinlock_t *lock)
+{
+ __asm__ __volatile__(
+ spin_unlock_string
+ :"=m" (lock->lock) : : "memory");
+}
+
+/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
+static inline __attribute__((always_inline)) void cpu_relax(void)
+{
+ __asm__ __volatile__("rep;nop": : :"memory");
+}
+
+#endif /* ARCH_SMP_SPINLOCK_H */
diff --git a/src/arch/x86/include/arch/stages.h b/src/arch/x86/include/arch/stages.h
new file mode 100644
index 0000000000..00d2a93ea3
--- /dev/null
+++ b/src/arch/x86/include/arch/stages.h
@@ -0,0 +1,25 @@
+/*
+ * 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
+ */
+
+#ifndef __ARCH_STAGES_H
+#define __ARCH_STAGES_H
+void cbfs_and_run_core(const char *filename, unsigned int ebp);
+void __attribute__((regparm(0))) copy_and_run(unsigned cpu_reset);
+void __attribute__((regparm(0))) copy_and_run_ap_code_in_car(unsigned ret_addr);
+#endif
diff --git a/src/arch/x86/include/bitops.h b/src/arch/x86/include/bitops.h
new file mode 100644
index 0000000000..9206465c77
--- /dev/null
+++ b/src/arch/x86/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/x86/include/bootblock_common.h b/src/arch/x86/include/bootblock_common.h
new file mode 100644
index 0000000000..895a185c6f
--- /dev/null
+++ b/src/arch/x86/include/bootblock_common.h
@@ -0,0 +1,33 @@
+#define __PRE_RAM__
+#if CONFIG_LOGICAL_CPUS && \
+ (defined(CONFIG_BOOTBLOCK_NORTHBRIDGE_INIT) || defined(CONFIG_BOOTBLOCK_SOUTHBRIDGE_INIT))
+#include <cpu/x86/lapic/boot_cpu.c>
+#else
+#define boot_cpu(x) 1
+#endif
+
+#ifdef CONFIG_BOOTBLOCK_NORTHBRIDGE_INIT
+#include CONFIG_BOOTBLOCK_NORTHBRIDGE_INIT
+#else
+static void bootblock_northbridge_init(void) { }
+#endif
+#ifdef CONFIG_BOOTBLOCK_SOUTHBRIDGE_INIT
+#include CONFIG_BOOTBLOCK_SOUTHBRIDGE_INIT
+#else
+static void bootblock_southbridge_init(void) { }
+#endif
+
+static unsigned long findstage(char* target)
+{
+ unsigned long entry;
+ asm volatile (
+ "mov $1f, %%esp\n\t"
+ "jmp walkcbfs\n\t"
+ "1:\n\t" : "=a" (entry) : "S" (target) : "ebx", "ecx", "edi", "esp");
+ return entry;
+}
+
+static void call(unsigned long addr, unsigned long bist)
+{
+ asm volatile ("jmp *%0\n\t" : : "r" (addr), "a" (bist));
+}
diff --git a/src/arch/x86/include/div64.h b/src/arch/x86/include/div64.h
new file mode 100644
index 0000000000..3634f6dd14
--- /dev/null
+++ b/src/arch/x86/include/div64.h
@@ -0,0 +1,51 @@
+#ifndef __I386_DIV64
+#define __I386_DIV64
+
+/*
+ * do_div() is NOT a C function. It wants to return
+ * two values (the quotient and the remainder), but
+ * since that doesn't work very well in C, what it
+ * does is:
+ *
+ * - modifies the 64-bit dividend _in_place_
+ * - returns the 32-bit remainder
+ *
+ * This ends up being the most efficient "calling
+ * convention" on x86.
+ */
+#define do_div(n,base) ({ \
+ unsigned long __upper, __low, __high, __mod, __base; \
+ __base = (base); \
+ asm("":"=a" (__low), "=d" (__high):"A" (n)); \
+ __upper = __high; \
+ if (__high) { \
+ __upper = __high % (__base); \
+ __high = __high / (__base); \
+ } \
+ asm("divl %2":"=a" (__low), "=d" (__mod):"rm" (__base), "0" (__low), "1" (__upper)); \
+ asm("":"=A" (n):"a" (__low),"d" (__high)); \
+ __mod; \
+})
+
+/*
+ * (long)X = ((long long)divs) / (long)div
+ * (long)rem = ((long long)divs) % (long)div
+ *
+ * Warning, this will do an exception if X overflows.
+ */
+#define div_long_long_rem(a,b,c) div_ll_X_l_rem(a,b,c)
+
+extern inline long
+div_ll_X_l_rem(long long divs, long div, long *rem);
+
+extern inline long
+div_ll_X_l_rem(long long divs, long div, long *rem)
+{
+ long dum2;
+ __asm__("divl %2":"=a"(dum2), "=d"(*rem)
+ : "rm"(div), "A"(divs));
+
+ return dum2;
+
+}
+#endif
diff --git a/src/arch/x86/include/stddef.h b/src/arch/x86/include/stddef.h
new file mode 100644
index 0000000000..e4fc019c87
--- /dev/null
+++ b/src/arch/x86/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 ((void *)0)
+
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+#endif /* I386_STDDEF_H */
diff --git a/src/arch/x86/include/stdint.h b/src/arch/x86/include/stdint.h
new file mode 100644
index 0000000000..b393cc10e0
--- /dev/null
+++ b/src/arch/x86/include/stdint.h
@@ -0,0 +1,77 @@
+#ifndef I386_STDINT_H
+#define I386_STDINT_H
+
+#if defined(__GNUC__)
+#define __HAVE_LONG_LONG__ 1
+#else
+#define __HAVE_LONG_LONG__ 0
+#endif
+
+/* 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;
+
+#if __HAVE_LONG_LONG__
+typedef unsigned long long uint64_t;
+typedef signed long long int64_t;
+#endif
+
+/* 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;
+
+#if __HAVE_LONG_LONG__
+typedef unsigned long long uint_least64_t;
+typedef signed long long int_least64_t;
+#endif
+
+/* 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;
+
+#if __HAVE_LONG_LONG__
+typedef unsigned long long uint_fast64_t;
+typedef signed long long int_fast64_t;
+#endif
+
+/* Types for `void *' pointers. */
+typedef int intptr_t;
+typedef unsigned int uintptr_t;
+
+/* Largest integral types */
+#if __HAVE_LONG_LONG__
+typedef long long int intmax_t;
+typedef unsigned long long uintmax_t;
+#else
+typedef long int intmax_t;
+typedef unsigned long int uintmax_t;
+#endif
+
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+#if __HAVE_LONG_LONG__
+typedef uint64_t u64;
+#endif
+
+#undef __HAVE_LONG_LONG__
+
+#endif /* I386_STDINT_H */
diff --git a/src/arch/x86/init/Makefile.inc b/src/arch/x86/init/Makefile.inc
new file mode 100644
index 0000000000..263c58e891
--- /dev/null
+++ b/src/arch/x86/init/Makefile.inc
@@ -0,0 +1 @@
+# If you add something to this file, enable it in src/arch/x86/Makefile.inc first.
diff --git a/src/arch/x86/init/bootblock_normal.c b/src/arch/x86/init/bootblock_normal.c
new file mode 100644
index 0000000000..08651c32bb
--- /dev/null
+++ b/src/arch/x86/init/bootblock_normal.c
@@ -0,0 +1,26 @@
+#include <bootblock_common.h>
+#include <pc80/mc146818rtc.h>
+
+static void main(unsigned long bist)
+{
+ if (boot_cpu()) {
+ bootblock_northbridge_init();
+ bootblock_southbridge_init();
+ }
+
+ unsigned long entry;
+ if (do_normal_boot())
+ entry = findstage("normal/romstage");
+ else
+ entry = findstage("fallback/romstage");
+
+ if (entry) call(entry, bist);
+
+ /* run fallback if normal can't be found */
+ entry = findstage("fallback/romstage");
+ if (entry) call(entry, bist);
+
+ /* duh. we're stuck */
+ asm volatile ("1:\n\thlt\n\tjmp 1b\n\t");
+}
+
diff --git a/src/arch/x86/init/bootblock_simple.c b/src/arch/x86/init/bootblock_simple.c
new file mode 100644
index 0000000000..e8994ee092
--- /dev/null
+++ b/src/arch/x86/init/bootblock_simple.c
@@ -0,0 +1,15 @@
+#include <bootblock_common.h>
+
+static void main(unsigned long bist)
+{
+ if (boot_cpu()) {
+ bootblock_northbridge_init();
+ bootblock_southbridge_init();
+ }
+ const char* target1 = "fallback/romstage";
+ unsigned long entry;
+ entry = findstage(target1);
+ if (entry) call(entry, bist);
+ asm volatile ("1:\n\thlt\n\tjmp 1b\n\t");
+}
+
diff --git a/src/arch/x86/init/crt0_romcc_epilogue.inc b/src/arch/x86/init/crt0_romcc_epilogue.inc
new file mode 100644
index 0000000000..3bd1b36992
--- /dev/null
+++ b/src/arch/x86/init/crt0_romcc_epilogue.inc
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2002 Eric Biederman
+ *
+ * This file 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.
+ */
+
+ /* clear boot_complete flag */
+ xorl %ebp, %ebp
+__main:
+ post_code(0x11)
+ cld /* clear direction flag */
+
+ movl %ebp, %esi
+
+ movl $ROMSTAGE_STACK, %esp
+ movl %esp, %ebp
+ pushl %esi
+ call copy_and_run
+
+.Lhlt:
+ post_code(0xee)
+ hlt
+ jmp .Lhlt
+
diff --git a/src/arch/x86/init/entry.S b/src/arch/x86/init/entry.S
new file mode 100644
index 0000000000..af29296403
--- /dev/null
+++ b/src/arch/x86/init/entry.S
@@ -0,0 +1,149 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 1999 Ronald G. Minnich
+ *
+ * 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/rom_segs.h>
+ .code16
+ .globl _stage0
+_stage0:
+ cli
+
+ /* Save the BIST result. */
+ movl %eax, %ebp;
+
+ /* thanks to kmliu@sis.com.tw for this TLB fix */
+ /* IMMEDIATELY invalidate the translation lookaside buffer (TLB) before
+ * executing any further code. Even though paging is disabled we
+ * could still get false address translations due to the TLB if we
+ * didn't invalidate it.
+ */
+ xorl %eax, %eax
+ movl %eax, %cr3 /* Invalidate TLB. */
+
+ /* Switch to protected mode. */
+
+ /* NOTE: With GNU assembler version 2.15.94.0.2.2 (i386-redhat-linux)
+ * using BFD version 2.15.94.0.2.2 20041220 this works fine without all
+ * the ld hackery and other things. So leave it as is with this comment.
+ */
+
+ data32 lgdt %cs:gdtptr
+
+ movl %cr0, %eax
+ andl $0x7FFAFFD1, %eax /* PG, AM, WP, NE, TS, EM, MP = 0 */
+ orl $0x60000001, %eax /* CD, NW, PE = 1 */
+ movl %eax, %cr0
+
+ /* Restore BIST result. */
+ movl %ebp, %eax
+
+ // port80_post(0x23)
+ /* Now we are in protected mode. Jump to a 32 bit code segment. */
+ data32 ljmp $ROM_CODE_SEG, $protected_stage0
+
+ /* I am leaving this weird jump in here in the event that future gas
+ * bugs force it to be used.
+ */
+ /* .byte 0x66 */
+ .code32
+ /* ljmp $ROM_CODE_SEG, $protected_stage0 */
+
+ /* .code16 */
+ .align 4
+ .globl gdt16
+gdt16 = . - _stage0
+gdt16x:
+ .word gdt16xend - gdt16x -1 /* Compute the table limit. */
+ .long gdt16x
+ .word 0
+
+ /* selgdt 0x08, flat code segment */
+ .word 0xffff, 0x0000
+ .byte 0x00, 0x9b, 0xcf, 0x00
+
+ /* selgdt 0x10, flat data segment */
+ .word 0xffff, 0x0000
+ .byte 0x00, 0x93, 0xcf, 0x00
+gdt16xend:
+
+ /* From now on we are 32 bit. */
+ .code32
+
+ /* We have two gdts where we could have one. That is ok.
+ *
+ * Let's not worry about this -- optimizing gdt is pointless since
+ * we're only in it for a little bit.
+ *
+ * Btw. note the trick below: The GDT points to ITSELF, and the first
+ * good descriptor is at offset 8. So you word-align the table, and
+ * then because you chose 8, you get a nice 64-bit aligned GDT entry,
+ * which is good as this is the size of the entry.
+ * Just in case you ever wonder why people do this.
+ */
+ .align 4
+ .globl gdtptr
+ .globl gdt_limit
+gdt_limit = gdt_end - gdt - 1 /* Compute the table limit. */
+
+gdt:
+gdtptr:
+ .word gdt_end - gdt -1 /* Compute the table limit. */
+ .long gdt /* We know the offset. */
+ .word 0
+
+ /* selgdt 0x08, flat code segment */
+ .word 0xffff, 0x0000
+ .byte 0x00, 0x9b, 0xcf, 0x00
+
+ /* selgdt 0x10, flat data segment */
+ .word 0xffff, 0x0000
+ .byte 0x00, 0x93, 0xcf, 0x00
+
+gdt_end:
+
+/* Reset vector. */
+
+/*
+ * RVECTOR: Size of reset vector, default is 0x10.
+ * RESRVED: Size of vpd code, default is 0xf0.
+ * BOOTBLK: Size of bootblock code, default is 0x1f00 (8k-256b).
+ */
+
+SEGMENT_SIZE = 0x10000
+RVECTOR = 0x00010
+
+/* Due to YET ANOTHER BUG in GNU bintools, you can NOT have a code16 here.
+ * I think we should leave it this way forever, as the bugs come and
+ * go -- and come again.
+ *
+ * .code16
+ * .section ".rom.text"
+ */
+.section ".reset", "ax"
+ .globl _resetjump
+_resetjump:
+ /* GNU bintools bugs again. This jumps to stage0 - 2. Sigh. */
+ /* jmp _stage0 */
+ .byte 0xe9
+ .int _stage0 - ( . + 2 )
+
+ /* Note: The above jump is hand coded to work around bugs in binutils.
+ * 5 bytes are used for a 3 byte instruction. This works because x86
+ * is little endian and allows us to use supported 32 bit relocations
+ * instead of the weird 16 bit relocations that binutils does not
+ * handle consistenly between versions because they are used so rarely.
+ */
diff --git a/src/arch/x86/init/ldscript.ld b/src/arch/x86/init/ldscript.ld
new file mode 100644
index 0000000000..149f048638
--- /dev/null
+++ b/src/arch/x86/init/ldscript.ld
@@ -0,0 +1,40 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2007 Ronald G. Minnich <rminnich@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+TARGET(binary)
+SECTIONS
+{
+ /DISCARD/ : {
+ *(.comment)
+ *(.note.*)
+ *(.note)
+ }
+}
+
+SECTIONS {
+ _ROMTOP = 0xfffffff0;
+ . = _ROMTOP;
+ .resetvector . : {
+ *(.reset)
+ . = 15 ;
+ BYTE(0x00);
+ }
+}
+
diff --git a/src/arch/x86/init/ldscript_apc.lb b/src/arch/x86/init/ldscript_apc.lb
new file mode 100644
index 0000000000..789a168e0e
--- /dev/null
+++ b/src/arch/x86/init/ldscript_apc.lb
@@ -0,0 +1,31 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2006 Advanced Micro Devices, Inc.
+ * Copyright (C) 2008-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 "ldoptions"
+SECTIONS
+{
+ .apcrom . : {
+ _apcrom = .;
+ *(.text)
+ *(.rodata)
+ *(.rodata.*)
+ _eapcrom = .;
+ }
+}
diff --git a/src/arch/x86/init/ldscript_failover.lb b/src/arch/x86/init/ldscript_failover.lb
new file mode 100644
index 0000000000..7e48dc1a25
--- /dev/null
+++ b/src/arch/x86/init/ldscript_failover.lb
@@ -0,0 +1,53 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2006 Advanced Micro Devices, Inc.
+ * Copyright (C) 2008-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
+ */
+
+/* We use ELF as output format. So that we can debug the code in some form. */
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+
+MEMORY {
+ rom : ORIGIN = 0xffff0000, LENGTH = 64K
+}
+
+TARGET(binary)
+SECTIONS
+{
+ /* This section might be better named .setup */
+ .rom ROMLOC : {
+ _rom = .;
+ *(.rom.text);
+ *(.rom.data);
+ *(.rom.data.*);
+ *(.rodata.*);
+ _erom = .;
+ } >rom = 0xff
+
+ ROMLOC = 0xffffff00 - (_erom - _rom) + 1;
+
+ /DISCARD/ : {
+ *(.comment)
+ *(.note)
+ *(.comment.*)
+ *(.note.*)
+ *(.iplt)
+ *(.rel.*)
+ *(.igot.*)
+ }
+}
diff --git a/src/arch/x86/init/ldscript_fallback_cbfs.lb b/src/arch/x86/init/ldscript_fallback_cbfs.lb
new file mode 100644
index 0000000000..480fd32d5d
--- /dev/null
+++ b/src/arch/x86/init/ldscript_fallback_cbfs.lb
@@ -0,0 +1,53 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2006 Advanced Micro Devices, Inc.
+ * Copyright (C) 2008-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
+ */
+
+/* We use ELF as output format. So that we can debug the code in some form. */
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+
+TARGET(binary)
+SECTIONS
+{
+ . = CONFIG_ROMBASE;
+
+ /* cut _start into last 64k*/
+ _x = .;
+ . = (_x < (CONFIG_ROMBASE - 0x10000 + CONFIG_ROM_IMAGE_SIZE)) ? (CONFIG_ROMBASE - 0x10000 + CONFIG_ROM_IMAGE_SIZE) : _x;
+
+ /* This section might be better named .setup */
+ .rom . : {
+ _rom = .;
+ *(.rom.text);
+ *(.rom.data);
+ *(.rodata);
+ *(.rodata.*);
+ *(.rom.data.*);
+ . = ALIGN(16);
+ _erom = .;
+ }
+
+ /DISCARD/ : {
+ *(.comment)
+ *(.note)
+ *(.comment.*)
+ *(.note.*)
+ }
+ _bogus = ASSERT((SIZEOF(.bss) + SIZEOF(.data)) == 0, "Do not use global variables in romstage");
+}
diff --git a/src/arch/x86/init/prologue.inc b/src/arch/x86/init/prologue.inc
new file mode 100644
index 0000000000..8947f20de3
--- /dev/null
+++ b/src/arch/x86/init/prologue.inc
@@ -0,0 +1,29 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2002 Eric Biederman
+ *
+ * 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 <cpu/x86/post_code.h>
+#include <cpu/x86/stack.h>
+
+.section ".rom.data", "a", @progbits
+.section ".rom.text", "ax", @progbits
+
+/* This is the entry code. The code in the .reset section jumps here. */
+
+ post_code(0x01)
+
diff --git a/src/arch/x86/lib/Makefile.inc b/src/arch/x86/lib/Makefile.inc
new file mode 100644
index 0000000000..43ac4693f7
--- /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 0000000000..94ce4a70c3
--- /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 0000000000..5e3d8fe922
--- /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 0000000000..3732ae296e
--- /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 0000000000..20917b6f40
--- /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 0000000000..443dbad38a
--- /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 0000000000..d646270daf
--- /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 0000000000..e39fe8fd0a
--- /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 0000000000..92eedd30fb
--- /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 0000000000..36db54c21b
--- /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 0000000000..839f5b44c7
--- /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 0000000000..7d8fb329d0
--- /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 0000000000..2f7f751832
--- /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 0000000000..a6a232a04a
--- /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 0000000000..395c46e20c
--- /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"
diff --git a/src/arch/x86/llshell/console.inc b/src/arch/x86/llshell/console.inc
new file mode 100644
index 0000000000..84f62e3448
--- /dev/null
+++ b/src/arch/x86/llshell/console.inc
@@ -0,0 +1,340 @@
+
+jmp console0
+
+#define __STR(X) #X
+#define STR(X) __STR(X)
+
+
+#undef STR
+ /* uses: ax, dx */
+#if defined(SERIAL_CONSOLE)
+#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)
+
+ /* 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:
diff --git a/src/arch/x86/llshell/llshell.inc b/src/arch/x86/llshell/llshell.inc
new file mode 100644
index 0000000000..a66ac150b5
--- /dev/null
+++ b/src/arch/x86/llshell/llshell.inc
@@ -0,0 +1,901 @@
+
+#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
+
+
+#include "console.inc"
+#include "pci.inc"
+#include "ramtest.inc"
+
+jmp llshell_out
+
+// (c) 2004 Bryan Chafy, This program is released under the GPL
+
+// LLShell, A low level interactive debug shell
+// Designed to be an interactive shell that operates with zero
+// system resources. For example at initial boot.
+
+// to use, jump to label "low_level_shell"
+// set %esp to the return address for exiting
+
+
+#define UART_BASEADDR $0x3f8
+#define resultreg %esi
+#define subroutinereg %edi
+#define freqtime $2193 // 1.93 * freq
+#define timertime $6000
+.equ sys_IOPL, 110
+
+// .data
+// .text
+
+welcome:
+ .string "\r\n! Low Level Shell (LLShell) (c)2004 Bryan Chafy \r\n\r\n"
+prompt:
+ .string "\r\n!> "
+badcmd:
+ .string "bad command\r\n"
+sorry:
+ .string "sorry, not yet implemented\r\n"
+cmds:
+ .string "\r\nList of commands:\r\n \
+\r\nbeep -- pc speaker beep \
+\r\nrst (or RST) -- reset \
+\r\nout(b,w,l) <val> <port> -- raw out val at port \
+\r\nin(b,w,l) <port> -- show raw port value \
+\r\njmp <address> -- jmp to address (llshell addr is in eax) \
+\r\ncall <address> -- funcion call (assumes a working stack) \
+\r\ncli -- clear interrupts \
+\r\nsti -- enable interrupts \
+\r\npush <value> -- push value onto stack \
+\r\npop -- pop from stack and display \
+\r\nwm(b,w,l) <addr> <val> -- write mem \
+\r\ndm <addr> <lines> -- dump mem \
+\r\nmcp <src> <dst> <size> -- mem copy \
+\r\nmpat <pat> <dst> <size> -- mem pattern \
+\r\nmemt <begin> <end> -- memory test \
+\r\npcir(b,w,l) <loc> -- pci read config \
+\r\npciw(b,w,l) <loc> <val> -- pci write config \
+\r\ndl <addr> <size> -- memory download (display xor cheksum at completion) \
+\r\ncram <addr> <size> -- enable cache to be ram (experimental) \
+\r\nbaud <val> -- change baudrate (not yet implemented) \
+\r\nexit -- exit shell \
+\r\nAll values in hex (0x prefixing ok) \
+\r\n"
+
+cr:
+ .string "\r\n"
+spaces:
+ .string " "
+
+// .globl _start
+//ASSUME CS:@CODE, DS:@DATA
+
+// _start:
+
+// call ioperms
+
+low_level_shell:
+
+mov $preamble,subroutinereg
+jmp beep
+preamble:
+mov $welcome,resultreg
+mov $readcommand,subroutinereg
+jmp displaystring
+
+readcommand:
+mov $prompt,resultreg
+mov $rcmd,subroutinereg
+jmp displaystring
+
+rcmd:
+mov $readcommand,subroutinereg
+movl $0x0, resultreg
+
+readchar:
+mov UART_BASEADDR+5,%dx
+in %dx, %al
+and $0x9f,%al
+test $0x01,%al
+jz readchar
+mov UART_BASEADDR,%dx
+in %dx,%al //char in al
+xchg %al,%ah
+
+send_char:
+mov UART_BASEADDR+5,%dx
+us_wait:
+in %dx,%al
+test $0x20,%al
+jz us_wait
+mov UART_BASEADDR,%dx
+xchg %al,%ah
+out %al,%dx // output char
+
+cmp $0x0D,%al //CR
+jnz eval_char
+mov $0x0A,%ah
+jmp send_char
+
+eval_char:
+cmp $0x20,%al //space
+jz cmdtable
+cmp $0x0A,%al //CR
+jz cmdtable
+cmp $0x08,%al //BS
+jnz additup
+//subit:
+shr $0x8,resultreg
+jmp readchar
+additup:
+shl $0x8,resultreg
+and $0xff,%eax
+add %eax,resultreg
+jmp readchar
+
+cmdtable:
+mov resultreg,%eax
+cmp $0,%eax
+jz readcommand
+cmp $0x74657374,%eax
+jz dotest
+cmp $0x68656c70,%eax
+jz dohelp
+cmp $0x0000003f,%eax
+jz dohelp
+cmp $0x6f757462,%eax
+jz dooutb
+cmp $0x6f757477,%eax
+jz dooutw
+cmp $0x6f75746c,%eax
+jz dooutd
+cmp $0x00696e62,%eax
+jz doinb
+cmp $0x00696e77,%eax
+jz doinw
+cmp $0x00696e6c,%eax
+jz doind
+cmp $0x63697262,%eax
+jz pcirb
+cmp $0x63697277,%eax
+jz pcirw
+cmp $0x6369726c,%eax
+jz pcirl
+cmp $0x63697762,%eax
+jz pciwb
+cmp $0x63697777,%eax
+jz pciww
+cmp $0x6369776c,%eax
+jz pciwl
+cmp $0x00776d62,%eax
+jz wmemb
+cmp $0x00776d77,%eax
+jz wmemw
+cmp $0x00776d6c,%eax
+jz wmeml
+cmp $0x0000646d,%eax
+jz dodmem
+cmp $0x6d656d74,%eax
+jz memt // mem test
+cmp $0x00727374,%eax
+jz rst // reset
+cmp $0x00525354,%eax
+jz RST
+cmp $0x62656570,%eax
+jz beep
+cmp $0x0000646c,%eax
+jz dodl // download to mem <loc> <size>
+cmp $0x006a6d70,%eax
+jz jmpto // jump to location (eax holds return addr)
+cmp $0x62617564,%eax
+jz baud // change baudrate
+cmp $0x00696e74,%eax
+jz doint // trigger an interrupt
+cmp $0x63616c6c,%eax
+jz callto // call assumes memory
+cmp $0x70757368,%eax
+jz dopush // assumes mem
+cmp $0x00706f70,%eax
+jz dopop // assumes mem
+cmp $0x6372616d,%eax
+jz cram // cache ram trick <location> <size>
+cmp $0x006d6370,%eax
+jz mcp // mem copy <src> <dst> <size>
+cmp $0x6d706174,%eax
+jz dopattern
+cmp $0x00636c69,%eax
+jz docli
+cmp $0x00737469,%eax
+jz dosti
+cmp $0x65786974,%eax
+jz doexit
+mov $badcmd,resultreg
+mov $readcommand,subroutinereg
+jmp displaystring
+
+
+readnibbles:
+movl $0x0, resultreg
+readit:
+mov UART_BASEADDR+5,%dx
+in %dx, %al
+and $0x9f,%al
+test $0x1,%al
+jz readit
+mov UART_BASEADDR,%dx
+in %dx,%al
+xchg %al,%ah
+
+sendchar:
+mov UART_BASEADDR+5,%dx
+us_waitit:
+in %dx,%al
+test $0x20,%al
+jz us_waitit
+mov UART_BASEADDR,%dx
+xchg %al,%ah
+out %al,%dx // output char
+
+cmp $0x78,%al
+jz readit
+cmp $0x0D,%al //CR
+jnz evalchar
+mov $0x0A,%ah
+jmp sendchar
+
+evalchar:
+cmp $0x20,%al //space
+jz gosub
+cmp $0x0A,%al //CR
+jz gosub
+cmp $0x08,%al //BS
+jnz processchar
+//subit:
+shr $0x04,resultreg
+jmp readit
+processchar:
+cmp $0x3A,%al
+jl subnum
+cmp $0x47,%al
+jl subcaps
+//sublc:
+sub $0x57,%al
+jmp additupn
+subcaps:
+sub $0x37,%al
+jmp additupn
+subnum:
+sub $0x30,%al
+additupn:
+shl $0x04,resultreg
+and $0xf,%eax
+add %eax,resultreg
+jmp readit
+
+gosub:
+jmp *subroutinereg
+
+//intersubcall
+// eax,edx,esi,edi
+
+// ebx,ecx,ebp,esp(?)
+// ds,es,fs,gs
+
+dotest:
+mov $ramtest,resultreg
+mov $test1a,subroutinereg
+jmp displayhex
+test1a:
+mov $welcome,resultreg
+mov $readcommand,subroutinereg
+jmp displayhex
+
+dodmem:
+
+movl $dmem1a, subroutinereg
+jmp readnibbles
+dmem1a:
+mov resultreg,%ebx // address
+movl $dmem1b, subroutinereg
+jmp readnibbles
+dmem1b:
+mov resultreg,%ecx // length
+
+dmemloop:
+mov %ebx,resultreg
+mov $daddr1,subroutinereg
+jmp displayhex
+daddr1:
+mov $spaces,resultreg
+mov $startshowm,subroutinereg
+jmp displaystring
+
+startshowm:
+mov (%ebx),resultreg
+mov $showm1,subroutinereg
+jmp displayhexlinear
+showm1:
+add $0x04,%ebx
+mov (%ebx),resultreg
+mov $showm2,subroutinereg
+jmp displayhexlinear
+showm2:
+add $0x04,%ebx
+mov (%ebx),resultreg
+mov $showm3,subroutinereg
+jmp displayhexlinear
+showm3:
+add $0x04,%ebx
+mov (%ebx),resultreg
+mov $showa0,subroutinereg
+jmp displayhexlinear
+
+showa0:
+sub $0xC,%ebx
+mov (%ebx),resultreg
+mov $showa1,subroutinereg
+jmp displayasciilinear
+showa1:
+add $0x04,%ebx
+mov (%ebx),resultreg
+mov $showa2,subroutinereg
+jmp displayasciilinear
+showa2:
+add $0x04,%ebx
+mov (%ebx),resultreg
+mov $showa3,subroutinereg
+jmp displayasciilinear
+showa3:
+add $0x04,%ebx
+mov (%ebx),resultreg
+mov $doneshow,subroutinereg
+jmp displayasciilinear
+doneshow:
+mov $cr,resultreg
+mov $doneshow1,subroutinereg
+jmp displaystring
+doneshow1:
+dec %cx
+cmp $0x0,%cx
+jz exitdmem
+add $0x04,%ebx
+jmp dmemloop
+exitdmem:
+jmp readcommand
+
+dooutb:
+// out val,port
+movl $outb1a, subroutinereg
+jmp readnibbles
+outb1a:
+mov resultreg,%ebx
+movl $outb1b, subroutinereg
+jmp readnibbles
+outb1b:
+mov resultreg,%edx
+mov %ebx,%eax
+out %al,%dx
+jmp readcommand
+
+dooutw:
+// out val,port
+movl $outw1a, subroutinereg
+jmp readnibbles
+outw1a:
+mov resultreg,%ebx
+movl $outw1b, subroutinereg
+jmp readnibbles
+outw1b:
+mov resultreg,%edx
+mov %ebx,%eax
+out %ax,%dx
+jmp readcommand
+
+dooutd:
+// out val,port
+movl $outd1a, subroutinereg
+jmp readnibbles
+outd1a:
+mov resultreg,%ebx
+movl $outd1b, subroutinereg
+jmp readnibbles
+outd1b:
+mov resultreg,%edx
+mov %ebx,%eax
+out %eax,%dx
+jmp readcommand
+
+wmemb:
+movl $wmemba, subroutinereg
+jmp readnibbles
+wmemba:
+mov resultreg,%ebx
+movl $wmembb, subroutinereg
+jmp readnibbles
+wmembb:
+mov resultreg,%eax
+mov %al,(%ebx)
+jmp readcommand
+
+wmemw:
+movl $wmemwa, subroutinereg
+jmp readnibbles
+wmemwa:
+mov resultreg,%ebx
+movl $wmemwb, subroutinereg
+jmp readnibbles
+wmemwb:
+mov resultreg,%eax
+mov %ax,(%ebx)
+jmp readcommand
+
+wmeml:
+movl $wmemla, subroutinereg
+jmp readnibbles
+wmemla:
+mov resultreg,%ebx
+movl $wmemlb, subroutinereg
+jmp readnibbles
+wmemlb:
+mov resultreg,%eax
+mov %eax,(%ebx)
+jmp readcommand
+
+doinb:
+// in port
+movl $inb1a, subroutinereg
+jmp readnibbles
+inb1a:
+mov resultreg,%edx
+mov $0x0,%eax
+in %dx,%al
+mov %eax,resultreg
+mov $readcommand,subroutinereg
+jmp displayhex
+
+doinw:
+// in port
+movl $inw1a, subroutinereg
+jmp readnibbles
+inw1a:
+mov resultreg,%edx
+mov $0x0,%eax
+in %dx,%ax
+mov %eax,resultreg
+mov $readcommand,subroutinereg
+jmp displayhex
+
+doind:
+// in port
+movl $ind1a, subroutinereg
+jmp readnibbles
+ind1a:
+mov resultreg,%edx
+in %dx,%eax
+mov %eax,resultreg
+mov $readcommand,subroutinereg
+jmp displayhex
+
+jmpto:
+movl $jmp1a, subroutinereg
+jmp readnibbles
+jmp1a:
+mov $readcommand,%eax
+jmp *resultreg
+
+callto:
+movl $call1a, subroutinereg
+jmp readnibbles
+call1a:
+mov $readcommand,%eax
+call *resultreg
+jmp readcommand
+
+dopush:
+movl $push1a, subroutinereg
+jmp readnibbles
+push1a:
+mov resultreg,%eax
+push %eax
+jmp readcommand
+
+doint:
+movl $int1a, subroutinereg
+jmp readnibbles
+int1a:
+mov resultreg,%eax
+// need to lookup int table?
+// int %eax
+jmp readcommand
+
+doenter:
+//setup stack frame
+
+
+dopop:
+movl $readcommand, subroutinereg
+pop resultreg
+jmp displayhex
+
+docli:
+cli
+jmp readcommand
+
+dosti:
+sti
+jmp readcommand
+
+
+displaystring:
+// resultreg= pointer to string terminated by \0
+dsloop:
+movb (resultreg),%ah
+cmp $0x0, %ah
+jz displaystringexit
+mov UART_BASEADDR+5,%dx
+us_waits:
+in %dx,%al
+test $0x20,%al
+jz us_waits
+mov UART_BASEADDR,%dx
+xchg %al,%ah
+out %al,%dx // output char
+inc resultreg
+jmp dsloop
+displaystringexit:
+jmp *subroutinereg
+
+displayhexlinear:
+mov resultreg,%eax
+xchg %al,%ah
+rol $0x10,%eax
+xchg %al,%ah
+mov %eax,resultreg
+displayhex:
+rol $0x10,%ecx
+mov $0x8,%cx
+dhloop:
+cmp $0xf,%cl
+je exitdisplayhex
+rol $0x04,resultreg
+movl resultreg,%eax
+and $0xf,%al
+cmp $0xa,%al
+jl addnum
+//addcaps
+add $0x37,%al
+jmp outcharhex
+addnum:
+add $0x30,%al
+outcharhex:
+xchg %al,%ah
+mov UART_BASEADDR+5,%dx
+us_waith:
+in %dx,%al
+test $0x20,%al
+jz us_waith
+mov UART_BASEADDR,%dx
+xchg %al,%ah
+out %al,%dx // output char
+dec %cx
+cmp $0x0,%cx
+jne dhloop
+mov $0x20,%al
+mov $0x10,%cl
+jmp outcharhex
+exitdisplayhex:
+rol $0x10,%ecx
+jmp *subroutinereg
+
+displayasciilinear:
+mov resultreg,%eax
+xchg %al,%ah
+rol $0x10,%eax
+xchg %al,%ah
+mov %eax,resultreg
+displayascii:
+rol $0x10,%ecx
+mov $0x4,%cx
+daloop:
+rol $0x08,resultreg
+movl resultreg,%eax
+cmp $0x7e,%al
+jg unprintable
+cmp $0x20,%al
+jl unprintable
+jmp outcharascii
+unprintable:
+mov $0x2e,%al // dot
+outcharascii:
+xchg %al,%ah
+mov UART_BASEADDR+5,%dx
+us_waita:
+in %dx,%al
+test $0x20,%al
+jz us_waita
+mov UART_BASEADDR,%dx
+xchg %al,%ah
+out %al,%dx // output char
+dec %cx
+cmp $0x0,%cx
+jne daloop
+rol $0x10,%ecx
+jmp *subroutinereg
+
+rst:
+cli
+movb $0x0fe,%al
+out %al,$0x64
+hlt
+
+RST:
+cli
+lidt %cs:0x03fff
+int $0x3
+hlt
+
+
+beep:
+mov timertime,%eax
+rol $0x10,%eax
+mov $0xb6,%al
+out %al,$0x43
+mov freqtime,%ax
+out %al,$0x42
+xchg %al,%ah
+out %al,$0x42
+
+in $0x61,%al
+or $0x03,%al
+out %al,$0x61
+
+//timer here
+timer:
+in $0x42,%al
+// xchg %al,%ah
+in $0x42,%al
+// xchg %al,%ah
+cmp $0x0,%al
+jnz timer
+rol $0x10,%eax
+dec %ax
+cmp $0x0,%ax;
+rol $0x10,%eax
+jnz timer
+// timer
+
+in $0x61,%al
+and $0xfc,%al
+out %al,$0x61
+jmp *subroutinereg
+
+dohelp:
+mov $cmds,resultreg
+mov $readcommand,subroutinereg
+jmp displaystring
+
+memt:
+movl $memt1, subroutinereg
+jmp readnibbles
+memt1:
+mov resultreg,%ecx
+movl $memt2, subroutinereg
+jmp readnibbles
+memt2:
+mov resultreg,%ebx
+xchg %ecx,%eax
+mov $readcommand,%esp // internal to linux bios
+jmp ramtest
+
+pcirb:
+movl $pcirb1, subroutinereg
+jmp readnibbles
+pcirb1:
+mov resultreg,%eax
+PCI_READ_CONFIG_BYTE
+and $0xff,%eax
+mov %eax,resultreg
+mov $readcommand,subroutinereg
+jmp displayhex
+
+pcirw:
+movl $pcirw1, subroutinereg
+jmp readnibbles
+pcirw1:
+mov resultreg,%eax
+PCI_READ_CONFIG_WORD
+and $0xffff,%eax
+mov %eax,resultreg
+mov $readcommand,subroutinereg
+jmp displayhex
+
+pcirl:
+movl $pcirl1, subroutinereg
+jmp readnibbles
+pcirl1:
+mov resultreg,%eax
+PCI_READ_CONFIG_DWORD
+mov %eax,resultreg
+mov $readcommand,subroutinereg
+jmp displayhex
+
+
+
+
+pciwb:
+movl $pciwb1, subroutinereg
+jmp readnibbles
+pciwb1:
+mov resultreg,%ebx
+movl $pciwb2, subroutinereg
+jmp readnibbles
+pciwb2:
+mov resultreg,%edx
+mov %ebx,%eax
+PCI_WRITE_CONFIG_BYTE
+jmp readcommand
+
+pciww:
+movl $pciww1, subroutinereg
+jmp readnibbles
+pciww1:
+mov resultreg,%ebx
+movl $pciww2, subroutinereg
+jmp readnibbles
+pciww2:
+mov resultreg,%ecx
+mov %ebx,%eax
+PCI_WRITE_CONFIG_WORD
+jmp readcommand
+
+pciwl:
+movl $pciwl1, subroutinereg
+jmp readnibbles
+pciwl1:
+mov resultreg,%ebx
+movl $pciwl2, subroutinereg
+jmp readnibbles
+pciwl2:
+mov resultreg,%ecx
+mov %ebx,%eax
+PCI_WRITE_CONFIG_DWORD
+jmp readcommand
+
+cram:
+//likely not working. Just testing for now
+movl $cram1, subroutinereg
+jmp readnibbles
+cram1:
+mov resultreg,%ebx
+movl $cram1, subroutinereg
+jmp readnibbles
+cram2:
+mov resultreg,%ecx
+// enable it
+mov %cr0,%eax
+and $0x9fffffff,%eax // also try 0x0fff, 0x2ff(write back)...
+mov %eax,%cr0
+//wbinvd ??
+cacheloop:
+mov (%ebx),%eax
+inc %ebx
+loop cacheloop
+// disable it
+mov %cr0,%eax
+or $0x60000000,%eax
+mov %eax,%cr0
+//wbinvd ??
+
+dodl:
+movl $dl1, subroutinereg
+jmp readnibbles
+dl1:
+mov resultreg,%ebx
+movl $dl2, subroutinereg
+jmp readnibbles
+dl2:
+mov resultreg,%ecx
+mov resultreg,subroutinereg
+mov %ebx,resultreg
+dlloop:
+mov UART_BASEADDR+5,%dx
+in %dx, %al
+and $0x9f,%al
+test $0x01,%al
+jz dlloop
+mov UART_BASEADDR,%dx
+in %dx,%al
+mov %al,(%ebx)
+inc %ebx
+loop dlloop
+csum:
+mov subroutinereg,%ecx
+shr $0x02,%ecx
+mov resultreg,%ebx
+mov $0x0,%eax
+csumloop:
+rol $0x03,%eax
+mov (%ebx),%dl
+xor %dl,%al
+inc %ebx
+loop csumloop
+mov $readcommand,subroutinereg
+mov %eax,resultreg
+jmp displayhex
+
+baud:
+mov $sorry,resultreg
+mov $readcommand,subroutinereg
+jmp displaystring
+
+mcp:
+movl $mcp1, subroutinereg
+jmp readnibbles
+mcp1:
+mov resultreg,%ebx
+movl $mcp2, subroutinereg
+jmp readnibbles
+mcp2:
+mov resultreg,%ecx
+movl $mcp3, subroutinereg
+jmp readnibbles
+mcp3:
+mov resultreg,%eax
+xchg %ecx,%eax
+mcploop:
+mov (%ebx),%dl
+mov %dl,(%eax)
+inc %ebx
+inc %eax
+loop mcploop
+jmp readcommand
+
+dopattern:
+movl $pat1, subroutinereg
+jmp readnibbles
+pat1:
+mov resultreg,%ebx
+movl $pat2, subroutinereg
+jmp readnibbles
+pat2:
+mov resultreg,%ecx
+movl $pat3, subroutinereg
+jmp readnibbles
+pat3:
+mov resultreg,%eax
+xchg %ecx,%eax
+patloop:
+rol $0x08,%ebx
+mov %bl,(%eax)
+inc %eax
+loop patloop
+jmp readcommand
+
+
+doexit:
+ // LB specific:
+RETSP // if there's no stack yet, caller must set %esp manually
+// RET_LABEL(low_level_shell)
+
+
+//Linux OS Specific
+ioperms:
+movl $sys_IOPL, %eax # system-call ID-number
+movl $3, %ebx # new value for IO0PL
+int $0x80 # enter the kernel
+ret
+
+llshell_out:
diff --git a/src/arch/x86/llshell/pci.inc b/src/arch/x86/llshell/pci.inc
new file mode 100644
index 0000000000..7cb741008e
--- /dev/null
+++ b/src/arch/x86/llshell/pci.inc
@@ -0,0 +1,229 @@
+
+ /*
+ * 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
+
+
+
diff --git a/src/arch/x86/llshell/ramtest.inc b/src/arch/x86/llshell/ramtest.inc
new file mode 100644
index 0000000000..c02cf451ec
--- /dev/null
+++ b/src/arch/x86/llshell/ramtest.inc
@@ -0,0 +1,125 @@
+ /*
+ * This is much more of a "Is my SDRAM properly configured?"
+ * test than a "Is my SDRAM faulty?" test. Not all bits
+ * are tested. -Tyson
+ */
+
+ jmp rt_skip
+#define RAMTEST 1
+#if RAMTEST
+ .section ".rom.data"
+
+rt_test: .string "Testing SDRAM : "
+rt_fill: .string "SDRAM fill:\r\n"
+rt_verify: .string "SDRAM verify:\r\n"
+rt_toomany: .string "Too many errors.\r\n"
+rt_done: .string "Done.\r\n"
+ .previous
+#endif
+
+ramtest:
+#if RAMTEST
+ mov %eax, %esi
+ mov %ebx, %edi
+ mov %esp, %ebp
+
+ CONSOLE_INFO_TX_STRING($rt_test)
+ CONSOLE_INFO_TX_HEX32(%esi)
+ CONSOLE_INFO_TX_CHAR($'-')
+ CONSOLE_INFO_TX_HEX32(%edi)
+ CONSOLE_INFO_TX_CHAR($'\r')
+ CONSOLE_INFO_TX_CHAR($'\n')
+
+ /* ============== Fill ram block ==== */
+
+ CONSOLE_INFO_TX_STRING($rt_fill)
+
+ mov %esi, %ebx
+1:
+ cmp $0, %bx
+ jne 2f
+
+ /* Display address being filled */
+ /* CONSOLE_INFO_TX_HEX32(arg) will overwrite %ebx with arg */
+
+ CONSOLE_INFO_TX_HEX32(%ebx)
+ CONSOLE_INFO_TX_CHAR($'\r')
+2:
+#if i786
+ /* Use a non temporal store to go faster and
+ * to bypass the cache.
+ */
+ movnti %ebx, (%ebx)
+#else
+ mov %ebx, (%ebx)
+#endif
+ add $4, %ebx
+ cmp %edi, %ebx
+ jl 1b
+
+ /* Display final address */
+
+ CONSOLE_INFO_TX_HEX32(%edi)
+ CONSOLE_INFO_TX_CHAR($'\r')
+ CONSOLE_INFO_TX_CHAR($'\n')
+
+ /* ========= Verify ram block ========== */
+
+ CONSOLE_INFO_TX_STRING($rt_verify)
+ mov %esi, %ebx
+
+1:
+ cmp $0, %bx
+ jne 2f
+
+ /* Display address being tested */
+
+ CONSOLE_INFO_TX_HEX32(%ebx)
+ CONSOLE_INFO_TX_CHAR($'\r')
+2:
+ cmp %ebx, (%ebx)
+ jne 4f
+3:
+ add $4, %ebx
+ cmp %edi, %ebx
+ jl 1b
+
+ /* Display final address */
+ CONSOLE_INFO_TX_HEX32(%edi)
+ CONSOLE_INFO_TX_CHAR($'\r')
+ CONSOLE_INFO_TX_CHAR($'\n')
+ jmp 6f
+
+4:
+ /* Display address with error */
+
+ CONSOLE_INFO_TX_HEX32(%ebx)
+ CONSOLE_INFO_TX_CHAR($':')
+
+ /* Display data in address with error */
+
+ /* CONSOLE_INFO_TX_HEX32(arg) will overwrite %ebx with arg */
+
+ mov %ebx, %esi
+ mov 0(%ebx), %eax
+ CONSOLE_INFO_TX_HEX32(%eax)
+ mov %esi, %ebx
+
+ CONSOLE_INFO_TX_CHAR($'\r')
+ CONSOLE_INFO_TX_CHAR($'\n')
+ sub $1, %ecx
+ jz 5f
+ jmp 3b
+5:
+ CONSOLE_INFO_TX_STRING($rt_toomany)
+ post_code(0xf1)
+ jmp .Lhlt
+
+6:
+ CONSOLE_INFO_TX_STRING($rt_done)
+ mov %ebp, %esp
+
+#endif
+ RETSP
+
+rt_skip:
diff --git a/src/arch/x86/llshell/readme.coreboot b/src/arch/x86/llshell/readme.coreboot
new file mode 100644
index 0000000000..ae7dcbecd0
--- /dev/null
+++ b/src/arch/x86/llshell/readme.coreboot
@@ -0,0 +1,25 @@
+
+1) Include llshell.inc in your northbridge Config file
+2) In raminit.inc (or whatever), make a jmp out to low_level_shell, setting
+ a return label in %esp.
+For example:
+ram_set_registers:
+
+ mov $llshell_ret1,%esp
+ jmp low_level_shell
+llshell_ret1:
+
+ /* Disable and invalidate the cache */
+ invd
+ mov %cr0, %eax
+ ....
+3) Optionally, comment out two lines in ramtest.inc:
+5:
+ CONSOLE_INFO_TX_STRING($rt_toomany)
+ // post_code(0xf1)
+ // jmp .Lhlt
+otherwise, a ramtest failure will hang
+
+4) build and flash as normal
+If it worked, the speaker will beep, and you'll get a shell.
+Type help or ? at the prompt for a list of commands.