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:
Stefan Reinauer
2010-12-11 20:33:41 +00:00
committed by Stefan Reinauer
parent 198cb96387
commit 8677a23d5b
117 changed files with 82 additions and 82 deletions

92
src/arch/x86/Kconfig Normal file
View 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

View 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 $@

View 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
View 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
View 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)
}

View 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)
}

View 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

View 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
View 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
View 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
View 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
);
}

View 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
View 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
View 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 ");
}

View 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;
}

View 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
View 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
View 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)

View 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.*)
}
}

View 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

View 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

View 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 */

View 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 */

View 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 */

View 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 */

View 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 */

View 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);

View 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

View 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

View 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

View 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 */

View 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 */

View 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

View 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 */

View 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

View 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 */

View 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 */

View 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 */

View 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

View 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 */

View 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

View 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 */

View 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));
}

View 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

View 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 */

View 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 */

View File

@@ -0,0 +1 @@
# If you add something to this file, enable it in src/arch/x86/Makefile.inc first.

View 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");
}

View 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");
}

View 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
View 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.
*/

View 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);
}
}

View 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 = .;
}
}

View 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.*)
}
}

View 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");
}

View 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)

View 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
View 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

View 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
View 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;
}

View 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
View 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
View 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
View 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);
}
}

View 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);
}

View 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,
};

View 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,
};

View 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

View 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
View 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
View 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"

View 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:

View 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:

View 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

View 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:

View 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.