After this has been brought up many times before, rename src/arch/i386 to
src/arch/x86. Signed-off-by: Stefan Reinauer <stepan@coreboot.org> Acked-by: Patrick Georgi <patrick@georgi-clan.de> git-svn-id: svn://svn.coreboot.org/coreboot/trunk@6161 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
This commit is contained in:
committed by
Stefan Reinauer
parent
198cb96387
commit
8677a23d5b
92
src/arch/x86/Kconfig
Normal file
92
src/arch/x86/Kconfig
Normal file
@@ -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
|
38
src/arch/x86/Makefile.bigbootblock.inc
Normal file
38
src/arch/x86/Makefile.bigbootblock.inc
Normal file
@@ -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 $@
|
||||
|
117
src/arch/x86/Makefile.bootblock.inc
Normal file
117
src/arch/x86/Makefile.bootblock.inc
Normal file
@@ -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 $@
|
||||
|
257
src/arch/x86/Makefile.inc
Normal file
257
src/arch/x86/Makefile.inc
Normal file
@@ -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
|
198
src/arch/x86/acpi/debug.asl
Normal file
198
src/arch/x86/acpi/debug.asl
Normal file
@@ -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)
|
||||
}
|
118
src/arch/x86/acpi/globutil.asl
Normal file
118
src/arch/x86/acpi/globutil.asl
Normal file
@@ -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)
|
||||
}
|
93
src/arch/x86/acpi/statdef.asl
Normal file
93
src/arch/x86/acpi/statdef.asl
Normal file
@@ -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
|
||||
|
||||
|
13
src/arch/x86/boot/Makefile.inc
Normal file
13
src/arch/x86/boot/Makefile.inc
Normal file
@@ -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)
|
||||
|
604
src/arch/x86/boot/acpi.c
Normal file
604
src/arch/x86/boot/acpi.c
Normal file
@@ -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
|
517
src/arch/x86/boot/acpigen.c
Normal file
517
src/arch/x86/boot/acpigen.c
Normal file
@@ -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;
|
||||
}
|
186
src/arch/x86/boot/boot.c
Normal file
186
src/arch/x86/boot/boot.c
Normal file
@@ -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
|
||||
);
|
||||
}
|
||||
|
||||
|
600
src/arch/x86/boot/coreboot_table.c
Normal file
600
src/arch/x86/boot/coreboot_table.c
Normal file
@@ -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);
|
||||
|
||||
}
|
60
src/arch/x86/boot/gdt.c
Normal file
60
src/arch/x86/boot/gdt.c
Normal file
@@ -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");
|
||||
}
|
||||
|
383
src/arch/x86/boot/mpspec.c
Normal file
383
src/arch/x86/boot/mpspec.c
Normal file
@@ -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 ");
|
||||
}
|
||||
|
77
src/arch/x86/boot/multiboot.c
Normal file
77
src/arch/x86/boot/multiboot.c
Normal file
@@ -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;
|
||||
}
|
169
src/arch/x86/boot/pirq_routing.c
Normal file
169
src/arch/x86/boot/pirq_routing.c
Normal file
@@ -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
|
231
src/arch/x86/boot/tables.c
Normal file
231
src/arch/x86/boot/tables.c
Normal file
@@ -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();
|
||||
}
|
105
src/arch/x86/boot/wakeup.S
Normal file
105
src/arch/x86/boot/wakeup.S
Normal file
@@ -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)
|
||||
|
128
src/arch/x86/coreboot_ram.ld
Normal file
128
src/arch/x86/coreboot_ram.ld
Normal file
@@ -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.*)
|
||||
}
|
||||
}
|
440
src/arch/x86/include/arch/acpi.h
Normal file
440
src/arch/x86/include/arch/acpi.h
Normal file
@@ -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
|
56
src/arch/x86/include/arch/acpigen.h
Normal file
56
src/arch/x86/include/arch/acpigen.h
Normal file
@@ -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
|
8
src/arch/x86/include/arch/boot/boot.h
Normal file
8
src/arch/x86/include/arch/boot/boot.h
Normal file
@@ -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 */
|
20
src/arch/x86/include/arch/byteorder.h
Normal file
20
src/arch/x86/include/arch/byteorder.h
Normal file
@@ -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 */
|
25
src/arch/x86/include/arch/coreboot_tables.h
Normal file
25
src/arch/x86/include/arch/coreboot_tables.h
Normal file
@@ -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 */
|
165
src/arch/x86/include/arch/cpu.h
Normal file
165
src/arch/x86/include/arch/cpu.h
Normal file
@@ -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 */
|
16
src/arch/x86/include/arch/hlt.h
Normal file
16
src/arch/x86/include/arch/hlt.h
Normal file
@@ -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 */
|
25
src/arch/x86/include/arch/interrupt.h
Normal file
25
src/arch/x86/include/arch/interrupt.h
Normal file
@@ -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);
|
168
src/arch/x86/include/arch/io.h
Normal file
168
src/arch/x86/include/arch/io.h
Normal file
@@ -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
|
||||
|
44
src/arch/x86/include/arch/ioapic.h
Normal file
44
src/arch/x86/include/arch/ioapic.h
Normal file
@@ -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
|
11
src/arch/x86/include/arch/llshell.h
Normal file
11
src/arch/x86/include/arch/llshell.h
Normal file
@@ -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
|
67
src/arch/x86/include/arch/mmio_conf.h
Normal file
67
src/arch/x86/include/arch/mmio_conf.h
Normal file
@@ -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 */
|
13
src/arch/x86/include/arch/pci_ops.h
Normal file
13
src/arch/x86/include/arch/pci_ops.h
Normal file
@@ -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 */
|
14
src/arch/x86/include/arch/pciconf.h
Normal file
14
src/arch/x86/include/arch/pciconf.h
Normal file
@@ -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
|
54
src/arch/x86/include/arch/pirq_routing.h
Normal file
54
src/arch/x86/include/arch/pirq_routing.h
Normal file
@@ -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 */
|
32
src/arch/x86/include/arch/registers.h
Normal file
32
src/arch/x86/include/arch/registers.h
Normal file
@@ -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
|
7
src/arch/x86/include/arch/rom_segs.h
Normal file
7
src/arch/x86/include/arch/rom_segs.h
Normal file
@@ -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 */
|
341
src/arch/x86/include/arch/romcc_io.h
Normal file
341
src/arch/x86/include/arch/romcc_io.h
Normal file
@@ -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 */
|
69
src/arch/x86/include/arch/smp/atomic.h
Normal file
69
src/arch/x86/include/arch/smp/atomic.h
Normal file
@@ -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 */
|
281
src/arch/x86/include/arch/smp/mpspec.h
Normal file
281
src/arch/x86/include/arch/smp/mpspec.h
Normal file
@@ -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
|
||||
|
64
src/arch/x86/include/arch/smp/spinlock.h
Normal file
64
src/arch/x86/include/arch/smp/spinlock.h
Normal file
@@ -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 */
|
25
src/arch/x86/include/arch/stages.h
Normal file
25
src/arch/x86/include/arch/stages.h
Normal file
@@ -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
|
20
src/arch/x86/include/bitops.h
Normal file
20
src/arch/x86/include/bitops.h
Normal file
@@ -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 */
|
33
src/arch/x86/include/bootblock_common.h
Normal file
33
src/arch/x86/include/bootblock_common.h
Normal file
@@ -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));
|
||||
}
|
51
src/arch/x86/include/div64.h
Normal file
51
src/arch/x86/include/div64.h
Normal file
@@ -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
|
15
src/arch/x86/include/stddef.h
Normal file
15
src/arch/x86/include/stddef.h
Normal file
@@ -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 */
|
77
src/arch/x86/include/stdint.h
Normal file
77
src/arch/x86/include/stdint.h
Normal file
@@ -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 */
|
1
src/arch/x86/init/Makefile.inc
Normal file
1
src/arch/x86/init/Makefile.inc
Normal file
@@ -0,0 +1 @@
|
||||
# If you add something to this file, enable it in src/arch/x86/Makefile.inc first.
|
26
src/arch/x86/init/bootblock_normal.c
Normal file
26
src/arch/x86/init/bootblock_normal.c
Normal file
@@ -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");
|
||||
}
|
||||
|
15
src/arch/x86/init/bootblock_simple.c
Normal file
15
src/arch/x86/init/bootblock_simple.c
Normal file
@@ -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");
|
||||
}
|
||||
|
26
src/arch/x86/init/crt0_romcc_epilogue.inc
Normal file
26
src/arch/x86/init/crt0_romcc_epilogue.inc
Normal file
@@ -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
|
||||
|
149
src/arch/x86/init/entry.S
Normal file
149
src/arch/x86/init/entry.S
Normal file
@@ -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.
|
||||
*/
|
40
src/arch/x86/init/ldscript.ld
Normal file
40
src/arch/x86/init/ldscript.ld
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
|
31
src/arch/x86/init/ldscript_apc.lb
Normal file
31
src/arch/x86/init/ldscript_apc.lb
Normal file
@@ -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 = .;
|
||||
}
|
||||
}
|
53
src/arch/x86/init/ldscript_failover.lb
Normal file
53
src/arch/x86/init/ldscript_failover.lb
Normal file
@@ -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.*)
|
||||
}
|
||||
}
|
53
src/arch/x86/init/ldscript_fallback_cbfs.lb
Normal file
53
src/arch/x86/init/ldscript_fallback_cbfs.lb
Normal file
@@ -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");
|
||||
}
|
29
src/arch/x86/init/prologue.inc
Normal file
29
src/arch/x86/init/prologue.inc
Normal file
@@ -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)
|
||||
|
13
src/arch/x86/lib/Makefile.inc
Normal file
13
src/arch/x86/lib/Makefile.inc
Normal file
@@ -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
|
317
src/arch/x86/lib/c_start.S
Normal file
317
src/arch/x86/lib/c_start.S
Normal file
@@ -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
|
55
src/arch/x86/lib/cbfs_and_run.c
Normal file
55
src/arch/x86/lib/cbfs_and_run.c
Normal file
@@ -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
|
268
src/arch/x86/lib/cpu.c
Normal file
268
src/arch/x86/lib/cpu.c
Normal file
@@ -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;
|
||||
}
|
||||
|
489
src/arch/x86/lib/exception.c
Normal file
489
src/arch/x86/lib/exception.c
Normal file
@@ -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
|
||||
}
|
15
src/arch/x86/lib/id.inc
Normal file
15
src/arch/x86/lib/id.inc
Normal file
@@ -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
|
6
src/arch/x86/lib/id.lds
Normal file
6
src/arch/x86/lib/id.lds
Normal file
@@ -0,0 +1,6 @@
|
||||
SECTIONS {
|
||||
. = (CONFIG_ROMBASE + CONFIG_ROM_IMAGE_SIZE - CONFIG_ID_SECTION_OFFSET) - (__id_end - __id_start);
|
||||
.id (.): {
|
||||
*(.id)
|
||||
}
|
||||
}
|
139
src/arch/x86/lib/ioapic.c
Normal file
139
src/arch/x86/lib/ioapic.c
Normal file
@@ -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);
|
||||
}
|
||||
}
|
100
src/arch/x86/lib/pci_ops_auto.c
Normal file
100
src/arch/x86/lib/pci_ops_auto.c
Normal file
@@ -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);
|
||||
}
|
63
src/arch/x86/lib/pci_ops_conf1.c
Normal file
63
src/arch/x86/lib/pci_ops_conf1.c
Normal file
@@ -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,
|
||||
};
|
76
src/arch/x86/lib/pci_ops_conf2.c
Normal file
76
src/arch/x86/lib/pci_ops_conf2.c
Normal file
@@ -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,
|
||||
};
|
||||
|
64
src/arch/x86/lib/pci_ops_mmconf.c
Normal file
64
src/arch/x86/lib/pci_ops_mmconf.c
Normal file
@@ -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
|
57
src/arch/x86/lib/printk_init.c
Normal file
57
src/arch/x86/lib/printk_init.c
Normal file
@@ -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;
|
||||
}
|
28
src/arch/x86/lib/stages.c
Normal file
28
src/arch/x86/lib/stages.c
Normal file
@@ -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"
|
||||
);
|
||||
}
|
||||
|
126
src/arch/x86/lib/walkcbfs.S
Normal file
126
src/arch/x86/lib/walkcbfs.S
Normal file
@@ -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"
|
340
src/arch/x86/llshell/console.inc
Normal file
340
src/arch/x86/llshell/console.inc
Normal file
@@ -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:
|
901
src/arch/x86/llshell/llshell.inc
Normal file
901
src/arch/x86/llshell/llshell.inc
Normal file
@@ -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:
|
229
src/arch/x86/llshell/pci.inc
Normal file
229
src/arch/x86/llshell/pci.inc
Normal file
@@ -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
|
||||
|
||||
|
||||
|
125
src/arch/x86/llshell/ramtest.inc
Normal file
125
src/arch/x86/llshell/ramtest.inc
Normal file
@@ -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:
|
25
src/arch/x86/llshell/readme.coreboot
Normal file
25
src/arch/x86/llshell/readme.coreboot
Normal file
@@ -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.
|
Reference in New Issue
Block a user