Intel FSP: add a shared set of functions for the FSP

- Move the non chipset-specific fsp pieces out of the chipset into a
shared area.  This is used by northbridge / southbrige / SOC code.  It
pulls in pieces from Kconfig, Makefile and FSP specific code.
- Enabled in the CPU code with a Kconfig "select PLATFORM_USES_FSP"

Change-Id: I7ffa934c1df09b71d48a876a56e3b888685870b8
Signed-off-by: Martin Roth <gaumless@gmail.com>
Signed-off-by: Martin Roth <martin.roth@se-eng.com>
Reviewed-on: http://review.coreboot.org/5635
Tested-by: build bot (Jenkins)
Reviewed-by: Marc Jones <marc.jones@se-eng.com>
This commit is contained in:
Martin Roth 2014-04-25 14:12:13 -06:00 committed by Martin Roth
parent f18abab200
commit a6427161c2
10 changed files with 1153 additions and 0 deletions

View File

@ -256,6 +256,7 @@ comment "Embedded Controllers"
source src/ec/Kconfig
comment "SoC"
source src/soc/Kconfig
source src/drivers/intel/fsp/Kconfig
endmenu

View File

@ -109,6 +109,13 @@ config X86_AMD_FIXED_MTRRS
This option informs the MTRR code to use the RdMem and WrMem fields
in the fixed MTRR MSRs.
config PLATFORM_USES_FSP
bool
default n
help
Selected for Intel processors/platform combinations that use the
Intel Firmware Support Package (FSP) for initialization.
config PARALLEL_MP
def_bool n
help

View File

@ -1 +1,2 @@
subdirs-y += gma
subdirs-$(CONFIG_PLATFORM_USES_FSP) += fsp

View File

@ -0,0 +1,143 @@
##
## This file is part of the coreboot project.
##
## Copyright (C) 2014 Sage Electronic Engineering, LLC.
##
## 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
##
if PLATFORM_USES_FSP
comment "Intel FSP"
config HAVE_FSP_BIN
bool "Use Intel Firmware Support Package"
help
Select this option to add an Intel FSP binary to
the resulting coreboot image.
Note: Without this binary, coreboot builds relying on the FSP
will not boot
config DCACHE_RAM_BASE
hex
default 0xfef00000
config DCACHE_RAM_SIZE
hex
default 0x4000
if HAVE_FSP_BIN
config FSP_FILE
string "Intel FSP binary path and filename"
help
The path and filename of the Intel FSP binary for this platform.
config FSP_LOC
hex "Intel FSP Binary location in CBFS"
help
The location in CBFS that the FSP is located. This must match the
value that is set in the FSP binary. If the FSP needs to be moved,
rebase the FSP with Intel's BCT (tool).
config ENABLE_FSP_FAST_BOOT
bool "Enable Fast Boot"
default n
help
Enabling this feature will force the MRC data to be cached in NV
storage to be used for speeding up boot time on future reboots
and/or power cycles.
config ENABLE_MRC_CACHE
bool
default ENABLE_FSP_FAST_BOOT
help
Enabling this feature will cause MRC data to be cached in NV storage.
This can either be used for fast boot, or just because the FSP wants
it to be saved.
config MRC_CACHE_SIZE
hex "Fast Boot Data Cache Size"
default 0x10000
depends on ENABLE_MRC_CACHE
help
This is the amount of space in NV storage that is reserved for the
fast boot data cache storage.
WARNING: Because this area will be erased and re-written, the size
should be a full sector of the flash ROM chip and nothing else should
be included in CBFS in any sector that the fast boot cache data is in.
config OVERRIDE_CACHE_CACHE_LOC
bool
help
Selected by the platform to set a new default location for the
MRC/fast boot cache.
config MRC_CACHE_LOC_OVERRIDE
hex
help
Sets the override CBFS location of the MRC/fast boot cache.
config MRC_CACHE_LOC
hex "Fast Boot Data Cache location in CBFS"
default MRC_CACHE_LOC_OVERRIDE if OVERRIDE_CACHE_CACHE_LOC
default 0xfff50000
depends on ENABLE_MRC_CACHE
help
The location in CBFS for the MRC data to be cached.
WARNING: This should be on a sector boundary of the BIOS ROM chip
and nothing else should be included in that sector, or IT WILL BE
ERASED.
config VIRTUAL_ROM_SIZE
hex "Virtual ROM Size"
default ROM_SIZE
depends on ENABLE_MRC_CACHE
help
This is used to calculate the offset of the MRC data cache in NV
Storage for fast boot. If in doubt, leave this set to the default
which sets the virtual size equal to the ROM size.
Example: Cougar Canyon 2 has two 8 MB SPI ROMs. When the SPI ROMs are
loaded with a 4 MB coreboot image, the virtual ROM size is 8 MB. When
the SPI ROMs are loaded with an 8 MB coreboot image, the virtual ROM
size is 16 MB.
endif #HAVE_FSP_BIN
config CACHE_ROM_SIZE_OVERRIDE
hex "Cache ROM Size"
default CBFS_SIZE
help
This is the size of the cachable area that is passed into the FSP in
the early initialization. Typically this should be the size of the CBFS
area, but the size must be a power of 2 whereas the CBFS size does not
have this limitation.
config USE_GENERIC_FSP_CAR_INC
bool
default n
help
The chipset can select this to use a generic cache_as_ram.inc file
that should be good for all FSP based platforms.
config FSP_USES_UPD
bool
default n
help
If this FSP uses UPD/VPD data regions, select this in the chipset Kconfig.
endif #PLATFORM_USES_FSP

View File

@ -0,0 +1,48 @@
#
# This file is part of the coreboot project.
#
# Copyright (C) 2014 Sage Electronic Engineering, LLC.
#
# 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
#
ramstage-y += fsp_util.c
romstage-y += fsp_util.c
ramstage-$(CONFIG_ENABLE_MRC_CACHE) += fastboot_cache.c
romstage-$(CONFIG_ENABLE_MRC_CACHE) += fastboot_cache.c
INCLUDES += -Isrc/drivers/intel/fsp
ifeq ($(CONFIG_USE_GENERIC_FSP_CAR_INC),y)
cpu_incs += $(src)/drivers/intel/fsp/cache_as_ram.inc
endif
ifeq ($(CONFIG_HAVE_FSP_BIN),y)
cbfs-files-y += fsp.bin
fsp.bin-file := $(call strip_quotes,$(CONFIG_FSP_FILE))
fsp.bin-position := $(CONFIG_FSP_LOC)
fsp.bin-type := 0xab
endif
ifeq ($(CONFIG_ENABLE_MRC_CACHE),y)
$(obj)/mrc.cache:
dd if=/dev/zero count=1 \
bs=$(shell printf "%d" $(CONFIG_MRC_CACHE_SIZE) ) | \
tr '\000' '\377' > $@
cbfs-files-y += mrc.cache
mrc.cache-file := $(obj)/mrc.cache
mrc.cache-position := $(CONFIG_MRC_CACHE_LOC)
mrc.cache-type := 0xac
endif

View File

@ -0,0 +1,169 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2000,2007 Ronald G. Minnich <rminnich@gmail.com>
* Copyright (C) 2007-2008 coresystems GmbH
* Copyright (C) 2013-2014 Sage Electronic Engineering, LLC.
*
* 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/stack.h>
#include <cpu/x86/mtrr.h>
#include <cpu/x86/cache.h>
#include <cpu/x86/post_code.h>
#include <cbmem.h>
#ifndef CONFIG_FSP_LOC
# error "CONFIG_FSP_LOC must be set."
#endif
#ifndef CONFIG_POST_IO
# error "CONFIG_POST_IO must be set."
#endif
#if CONFIG_POST_IO
# ifndef CONFIG_POST_IO_PORT
# error "CONFIG_POST_IO_PORT must be set."
# endif
#endif
#ifndef CONFIG_CPU_MICROCODE_CBFS_LOC
# error "CONFIG_CPU_MICROCODE_CBFS_LOC must be set."
#endif
#define LHLT_DELAY 0x50000 /* I/O delay between post codes on failure */
cmp $0, %eax
jne bisthalt
cache_as_ram:
post_code(0x20)
/*
* Find the FSP binary in cbfs.
* Make a fake stack that has the return value back to this code.
*/
lea fake_fsp_stack, %esp
jmp find_fsp
find_fsp_ret:
/* Save the FSP location */
mov %eax, %ebp
cmp $CONFIG_FSP_LOC, %eax
jb halt1
post_code(0x22)
/* Calculate entry into FSP */
mov 0x30(%ebp), %eax /* Load TempRamInitEntry */
add 0x1c(%ebp), %eax /* add in the offset for the FSP base address */
/*
* Pass early init variables on a fake stack (no memory yet)
* as well as the return location
*/
lea CAR_init_stack, %esp
/* call FSP binary to setup temporary stack */
jmp *%eax
CAR_init_done:
addl $4, %esp
cmp $0, %eax
jne halt2
/* Save FSP_INFO_HEADER location in ebx */
mov %ebp, %ebx
/*
* set up bootloader stack
* ecx: stack base
* edx: stack top
*/
lea -4(%edx), %esp
movl %esp, %ebp
pushl %ebx
before_romstage:
post_code(0x23)
/* Call romstage.c main function. */
call main /* does not return */
movb $0xB8, %ah
jmp .Lhlt
bisthalt:
movb $0xB9, %ah
jmp .Lhlt
halt1:
/*
* Failures for postcode 0xBA - failed in find_fsp()
*
* Values are:
* 0x01 - FV signature, "_FVH" not present
* 0x02 - FFS GUID not present
* 0x03 - FSP INFO Header not found
* 0x04 - ImageBase does not equal CONFIG_FSP_LOC - Is the FSP rebased to
* a different location, or does it need to be?
* 0x05 - FSP INFO Header signature "FSPH" not found
* 0x06 - FSP Image ID is not the expected ID.
*/
movb $0xBA, %ah
jmp .Lhlt
halt2:
/*
* Failures for postcode 0xBB - failed in the FSP:
*
* 0x00 - FSP_SUCCESS: Temp RAM was initialized successfully.
* 0x02 - FSP_INVALID_PARAMETER: Input parameters are invalid.
* 0x0E - FSP_NOT_FOUND: No valid microcode was found in the microcode region.
* 0x03 - FSP_UNSUPPORTED: The FSP calling conditions were not met.
* 0x07 - FSP_DEVICE_ERROR: Temp RAM initialization failed
* 0x14 - FSP_ALREADY_STARTED: Temp RAM initialization has been invoked
*/
movb $0xBB, %ah
.Lhlt:
xchg %al, %ah
#if CONFIG_POST_IO
outb %al, $CONFIG_POST_IO_PORT
#else
post_code(POST_DEAD_CODE)
#endif
movl $LHLT_DELAY, %ecx
.Lhlt_Delay:
outb %al, $0xED
loop .Lhlt_Delay
jmp .Lhlt
/*
* esp is set to this location so that the call into and return from the FSP
* in find_fsp will work.
*/
.align 4
fake_fsp_stack:
.long find_fsp_ret
CAR_init_params:
.long CONFIG_CPU_MICROCODE_CBFS_LOC
.long CONFIG_CPU_MICROCODE_CBFS_LEN
.long 0xFFFFFFFF - CACHE_ROM_SIZE + 1 /* Firmware Location */
.long CACHE_ROM_SIZE /* Total Firmware Length */
CAR_init_stack:
.long CAR_init_done
.long CAR_init_params

View File

@ -0,0 +1,253 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2012 Google Inc.
* Copyright (C) 2013-2014 Sage Electronic Engineering, LLC.
*
* 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 <stdint.h>
#include <string.h>
#include <bootstate.h>
#include <console/console.h>
#include <cbfs.h>
#include <ip_checksum.h>
#include <device/device.h>
#include <cbmem.h>
#include <spi-generic.h>
#include <spi_flash.h>
#include <lib.h> // hexdump
#include "fsp_util.h"
#ifndef CONFIG_VIRTUAL_ROM_SIZE
#error "CONFIG_VIRTUAL_ROM_SIZE must be set."
#endif
/* convert a pointer to flash area into the offset inside the flash */
static inline u32 to_flash_offset(void *p) {
return ((u32)p + CONFIG_VIRTUAL_ROM_SIZE);
}
static struct mrc_data_container *next_mrc_block(
struct mrc_data_container *mrc_cache)
{
/* MRC data blocks are aligned within the region */
u32 mrc_size = sizeof(*mrc_cache) + mrc_cache->mrc_data_size;
if (mrc_size & (MRC_DATA_ALIGN - 1UL)) {
mrc_size &= ~(MRC_DATA_ALIGN - 1UL);
mrc_size += MRC_DATA_ALIGN;
}
u8 *region_ptr = (u8*)mrc_cache;
region_ptr += mrc_size;
return (struct mrc_data_container *)region_ptr;
}
static int is_mrc_cache(struct mrc_data_container *mrc_cache)
{
return (!!mrc_cache) && (mrc_cache->mrc_signature == MRC_DATA_SIGNATURE);
}
static u32 get_mrc_cache_region(struct mrc_data_container **mrc_region_ptr)
{
size_t region_size;
*mrc_region_ptr = cbfs_get_file_content(CBFS_DEFAULT_MEDIA,
"mrc.cache", 0xac,
&region_size);
return region_size;
}
/*
* Find the largest index block in the MRC cache. Return NULL if none is
* found.
*/
static struct mrc_data_container *find_current_mrc_cache_local
(struct mrc_data_container *mrc_cache, u32 region_size)
{
u32 region_end;
u32 entry_id = 0;
struct mrc_data_container *mrc_next = mrc_cache;
region_end = (u32) mrc_cache + region_size;
/* Search for the last filled entry in the region */
while (is_mrc_cache(mrc_next)) {
entry_id++;
mrc_cache = mrc_next;
mrc_next = next_mrc_block(mrc_next);
if ((u32)mrc_next >= region_end) {
/* Stay in the MRC data region */
break;
}
}
if (entry_id == 0) {
printk(BIOS_ERR, "%s: No valid fast boot cache found.\n", __func__);
return NULL;
}
/* Verify checksum */
if (mrc_cache->mrc_checksum !=
compute_ip_checksum(mrc_cache->mrc_data,
mrc_cache->mrc_data_size)) {
printk(BIOS_ERR, "%s: fast boot cache checksum mismatch\n", __func__);
return NULL;
}
printk(BIOS_DEBUG, "%s: picked entry %u from cache block\n", __func__,
entry_id - 1);
return mrc_cache;
}
/* SPI code needs malloc/free.
* Also unknown if writing flash from XIP-flash code is a good idea
*/
#if !defined(__PRE_RAM__)
/* find the first empty block in the MRC cache area.
* If there's none, return NULL.
*
* @mrc_cache_base - base address of the MRC cache area
* @mrc_cache - current entry (for which we need to find next)
* @region_size - total size of the MRC cache area
*/
static struct mrc_data_container *find_next_mrc_cache
(struct mrc_data_container *mrc_cache_base,
struct mrc_data_container *mrc_cache,
u32 region_size)
{
u32 region_end = (u32) mrc_cache_base + region_size;
u32 mrc_data_size = mrc_cache->mrc_data_size;
mrc_cache = next_mrc_block(mrc_cache);
if (((u32)mrc_cache + mrc_data_size) >= region_end) {
/* Crossed the boundary */
mrc_cache = NULL;
printk(BIOS_DEBUG, "%s: no available entries found\n",
__func__);
} else {
printk(BIOS_DEBUG,
"%s: picked next entry from cache block at %p\n",
__func__, mrc_cache);
}
return mrc_cache;
}
void update_mrc_cache(void *unused)
{
printk(BIOS_DEBUG, "Updating fast boot cache data.\n");
struct mrc_data_container *current = cbmem_find(CBMEM_ID_MRCDATA);
struct mrc_data_container *cache, *cache_base;
u32 cache_size;
if (!current) {
printk(BIOS_ERR, "No fast boot cache in cbmem. Can't update flash.\n");
return;
}
if (current->mrc_data_size == -1) {
printk(BIOS_ERR, "Fast boot cache data in cbmem invalid.\n");
return;
}
cache_size = get_mrc_cache_region(&cache_base);
if (cache_base == NULL) {
printk(BIOS_ERR, "%s: could not find fast boot cache area\n",
__func__);
return;
}
/*
* we need to:
* 0. compare MRC data to last mrc-cache block (exit if same)
*/
cache = find_current_mrc_cache_local(cache_base, cache_size);
if (cache && (cache->mrc_data_size == current->mrc_data_size) &&
(memcmp(cache, current, cache->mrc_data_size) == 0)) {
printk(BIOS_DEBUG,
"MRC data in flash is up to date. No update.\n");
return;
}
/* 1. use spi_flash_probe() to find the flash, then... */
spi_init();
struct spi_flash *flash = spi_flash_probe(0, 0, 1000000, SPI_MODE_3);
if (!flash) {
printk(BIOS_DEBUG, "Could not find SPI device\n");
return;
}
/* 2. look up the first unused block */
if (cache)
cache = find_next_mrc_cache(cache_base, cache, cache_size);
/*
* 3. if no such place exists, erase entire mrc-cache range & use
* block 0. First time around the erase is not needed, but this is a
* small overhead for simpler code.
*/
if (!cache) {
printk(BIOS_DEBUG,
"Need to erase the MRC cache region of %d bytes at %p\n",
cache_size, cache_base);
flash->erase(flash, to_flash_offset(cache_base), cache_size);
/* we will start at the beginning again */
cache = cache_base;
}
/* 4. write mrc data with flash->write() */
printk(BIOS_DEBUG, "Write MRC cache update to flash at %p\n",
cache);
flash->write(flash, to_flash_offset(cache),
current->mrc_data_size + sizeof(*current), current);
}
#endif /* !defined(__PRE_RAM__) */
void * find_and_set_fastboot_cache(void)
{
struct mrc_data_container *mrc_cache = NULL;
if (((mrc_cache = find_current_mrc_cache()) == NULL) ||
(mrc_cache->mrc_data_size == -1UL)) {
printk(BIOS_DEBUG, "FSP MRC cache not present.\n");
return NULL;
}
printk(BIOS_DEBUG, "FSP MRC cache present at %x.\n", (u32)mrc_cache);
printk(BIOS_SPEW, "Saved MRC data:\n");
hexdump32(BIOS_SPEW, (void *)mrc_cache->mrc_data, mrc_cache->mrc_data_size);
return (void *) mrc_cache->mrc_data;
}
struct mrc_data_container *find_current_mrc_cache(void)
{
struct mrc_data_container *cache_base;
u32 cache_size;
cache_size = get_mrc_cache_region(&cache_base);
if (cache_base == NULL) {
printk(BIOS_ERR, "%s: could not find fast boot cache area\n",
__func__);
return NULL;
}
/*
* we need to:
* 0. compare MRC data to last mrc-cache block (exit if same)
*/
return find_current_mrc_cache_local(cache_base, cache_size);
}

View File

@ -0,0 +1,432 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2013-2014 Sage Electronic Engineering, LLC.
*
* 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 <cpu/x86/stack.h>
#include <console/console.h>
#include <bootstate.h>
#include <cbmem.h>
#include "fsp_util.h"
#include <lib.h> // hexdump
#include <ip_checksum.h>
#include <timestamp.h>
#ifndef __PRE_RAM__
/* Globals pointers for FSP structures */
void *FspHobListPtr = NULL;
FSP_INFO_HEADER *fsp_header_ptr = NULL;
void FspNotify (u32 Phase)
{
FSP_NOTFY_PHASE NotifyPhaseProc;
NOTIFY_PHASE_PARAMS NotifyPhaseParams;
EFI_STATUS Status;
if (fsp_header_ptr == NULL) {
fsp_header_ptr = (void *)find_fsp();
if ((u32)fsp_header_ptr < 0xff) {
post_code(0x4F); /* output something in case there is no serial */
die("Can't find the FSP!\n");
}
}
/* call FSP PEI to Notify PostPciEnumeration */
NotifyPhaseProc = (FSP_NOTFY_PHASE)(fsp_header_ptr->ImageBase +
fsp_header_ptr->NotifyPhaseEntry);
NotifyPhaseParams.Phase = Phase;
timestamp_add_now(Phase == EnumInitPhaseReadyToBoot ?
TS_FSP_BEFORE_FINALIZE : TS_FSP_BEFORE_ENUMERATE);
Status = NotifyPhaseProc (&NotifyPhaseParams);
timestamp_add_now(Phase == EnumInitPhaseReadyToBoot ?
TS_FSP_AFTER_FINALIZE : TS_FSP_AFTER_ENUMERATE);
if (Status != 0)
printk(BIOS_ERR,"FSP API NotifyPhase failed for phase 0x%x with status: 0x%x\n", Phase, Status);
}
#endif /* #ifndef __PRE_RAM__ */
#ifdef __PRE_RAM__
/*
* Call the FSP to do memory init. The FSP doesn't return to this function.
* The FSP returns to the romstage_main_continue().
*/
void __attribute__ ((noreturn)) fsp_early_init (FSP_INFO_HEADER *fsp_ptr)
{
FSP_FSP_INIT FspInitApi;
FSP_INIT_PARAMS FspInitParams;
FSP_INIT_RT_BUFFER FspRtBuffer;
#if IS_ENABLED(CONFIG_FSP_USES_UPD)
UPD_DATA_REGION fsp_upd_data;
#endif
memset((void*)&FspRtBuffer, 0, sizeof(FSP_INIT_RT_BUFFER));
FspRtBuffer.Common.StackTop = (u32 *)ROMSTAGE_STACK;
FspInitParams.NvsBufferPtr = NULL;
#if IS_ENABLED(CONFIG_FSP_USES_UPD)
FspRtBuffer.Common.UpdDataRgnPtr = &fsp_upd_data;
#endif
FspInitParams.RtBufferPtr = (FSP_INIT_RT_BUFFER *)&FspRtBuffer;
FspInitParams.ContinuationFunc = (CONTINUATION_PROC)ChipsetFspReturnPoint;
FspInitApi = (FSP_FSP_INIT)(fsp_ptr->ImageBase + fsp_ptr->FspInitEntry);
/* Call the chipset code to fill in the chipset specific structures */
chipset_fsp_early_init(&FspInitParams, fsp_ptr);
/* Call back to romstage for board specific changes */
romstage_fsp_rt_buffer_callback(&FspRtBuffer);
FspInitApi(&FspInitParams);
/* Should never return. Control will continue from ContinuationFunc */
die("Uh Oh! FspInitApi returned");
}
#endif /* __PRE_RAM__ */
volatile u8 * __attribute__((optimize("O0"))) find_fsp ()
{
#ifdef __PRE_RAM__
volatile register u8 *fsp_ptr asm ("eax");
/* Entry point for CAR assembly routine */
__asm__ __volatile__ (
".global find_fsp\n\t"
"find_fsp:\n\t"
);
#else
volatile u8 *fsp_ptr;
#endif /* __PRE_RAM__ */
#ifndef CONFIG_FSP_LOC
#error "CONFIG_FSP_LOC must be set."
#endif
/* The FSP is stored in CBFS */
fsp_ptr = (u8 *) CONFIG_FSP_LOC;
/* Check the FV signature, _FVH */
if (((EFI_FIRMWARE_VOLUME_HEADER *)fsp_ptr)->Signature == 0x4856465F) {
/* Go to the end of the FV header and align the address. */
fsp_ptr += ((EFI_FIRMWARE_VOLUME_HEADER *)fsp_ptr)->ExtHeaderOffset;
fsp_ptr += ((EFI_FIRMWARE_VOLUME_EXT_HEADER *)fsp_ptr)->ExtHeaderSize;
fsp_ptr = (u8 *)(((u32)fsp_ptr + 7) & 0xFFFFFFF8);
} else {
fsp_ptr = (u8*)ERROR_NO_FV_SIG;
}
/* Check the FFS GUID */
if (((u32)fsp_ptr > 0xff) &&
(((u32 *)&(((EFI_FFS_FILE_HEADER *)fsp_ptr)->Name))[0] == 0x912740BE) &&
(((u32 *)&(((EFI_FFS_FILE_HEADER *)fsp_ptr)->Name))[1] == 0x47342284) &&
(((u32 *)&(((EFI_FFS_FILE_HEADER *)fsp_ptr)->Name))[2] == 0xB08471B9) &&
(((u32 *)&(((EFI_FFS_FILE_HEADER *)fsp_ptr)->Name))[3] == 0x0C3F3527)) {
/* Add the FFS Header size to the base to find the Raw section Header */
fsp_ptr += sizeof(EFI_FFS_FILE_HEADER);
} else {
fsp_ptr = (u8 *)ERROR_NO_FFS_GUID;
}
if (((u32)fsp_ptr > 0xff) &&
((EFI_RAW_SECTION *)fsp_ptr)->Type == EFI_SECTION_RAW) {
/* Add the Raw Header size to the base to find the FSP INFO Header */
fsp_ptr += sizeof(EFI_RAW_SECTION);
} else {
fsp_ptr = (u8 *)ERROR_NO_INFO_HEADER;
}
/* Verify that the FSP is set to the base address we're expecting.*/
if (((u32)fsp_ptr > 0xff) &&
(*(u32*)(fsp_ptr + FSP_IMAGE_BASE_LOC) != CONFIG_FSP_LOC)) {
fsp_ptr = (u8 *)ERROR_IMAGEBASE_MISMATCH;
}
/* Verify the FSP Signature */
if (((u32)fsp_ptr > 0xff) &&
(*(u32*)(fsp_ptr + FSP_IMAGE_SIG_LOC) != FSP_SIG)){
fsp_ptr = (u8 *)ERROR_INFO_HEAD_SIG_MISMATCH;
}
/* Verify the FSP ID */
if (((u32)fsp_ptr > 0xff) &&
((*(u32 *)(fsp_ptr + FSP_IMAGE_ID_LOC) != FSP_IMAGE_ID_DWORD0) ||
(*(u32 *)(fsp_ptr + (FSP_IMAGE_ID_LOC + 4)) != FSP_IMAGE_ID_DWORD1))) {
fsp_ptr = (u8 *)ERROR_FSP_SIG_MISMATCH;
}
return (fsp_ptr);
}
#ifndef __PRE_RAM__ /* Only parse HOB data in ramstage */
void print_fsp_info(void) {
if (fsp_header_ptr == NULL)
fsp_header_ptr = (void *)find_fsp();
if ((u32)fsp_header_ptr < 0xff) {
post_code(0x4F); /* output something in case there is no serial */
die("Can't find the FSP!\n");
}
if (FspHobListPtr == NULL) {
FspHobListPtr = (void*)*((u32*) cbmem_find(CBMEM_ID_HOB_POINTER));
}
printk(BIOS_SPEW,"fsp_header_ptr: %p\n", fsp_header_ptr);
printk(BIOS_INFO,"FSP Header Version: %d\n", fsp_header_ptr->HeaderRevision);
printk(BIOS_INFO,"FSP Revision: %d.%d\n",
(u8)((fsp_header_ptr->ImageRevision >> 8) & 0xff),
(u8)(fsp_header_ptr->ImageRevision & 0xff));
}
static void print_hob_mem_attributes(void *Hobptr) {
EFI_HOB_MEMORY_ALLOCATION *HobMemoryPtr = (EFI_HOB_MEMORY_ALLOCATION *)Hobptr;
EFI_MEMORY_TYPE Hobmemtype = HobMemoryPtr->AllocDescriptor.MemoryType;
u64 Hobmemaddr = HobMemoryPtr->AllocDescriptor.MemoryBaseAddress;
u64 Hobmemlength = HobMemoryPtr->AllocDescriptor.MemoryLength;
const char * Hobmemtypenames[15];
Hobmemtypenames[0] = "EfiReservedMemoryType";
Hobmemtypenames[1] = "EfiLoaderCode";
Hobmemtypenames[2] = "EfiLoaderData";
Hobmemtypenames[3] = "EfiBootServicesCode";
Hobmemtypenames[4] = "EfiBootServicesData";
Hobmemtypenames[5] = "EfiRuntimeServicesCode";
Hobmemtypenames[6] = "EfiRuntimeServicesData";
Hobmemtypenames[7] = "EfiConventionalMemory";
Hobmemtypenames[8] = "EfiUnusableMemory";
Hobmemtypenames[9] = "EfiACPIReclaimMemory";
Hobmemtypenames[10] = "EfiACPIMemoryNVS";
Hobmemtypenames[11] = "EfiMemoryMappedIO";
Hobmemtypenames[12] = "EfiMemoryMappedIOPortSpace";
Hobmemtypenames[13] = "EfiPalCode";
Hobmemtypenames[14] = "EfiMaxMemoryType";
printk(BIOS_SPEW, " Memory type %s (0x%x)\n",
Hobmemtypenames[(u32)Hobmemtype], (u32) Hobmemtype);
printk(BIOS_SPEW, " at location 0x%0lx with length 0x%0lx\n",
(long unsigned int)Hobmemaddr, (long unsigned int)Hobmemlength);
}
static void print_hob_resource_attributes(void *Hobptr) {
EFI_HOB_RESOURCE_DESCRIPTOR *HobResourcePtr =
(EFI_HOB_RESOURCE_DESCRIPTOR *)Hobptr;
u32 Hobrestype = HobResourcePtr->ResourceType;
u32 Hobresattr = HobResourcePtr->ResourceAttribute;
u64 Hobresaddr = HobResourcePtr->PhysicalStart;
u64 Hobreslength = HobResourcePtr->ResourceLength;
const char *Hobrestypestr = NULL;
// HOB Resource Types
switch (Hobrestype) {
case EFI_RESOURCE_SYSTEM_MEMORY:
Hobrestypestr = "EFI_RESOURCE_SYSTEM_MEMORY"; break;
case EFI_RESOURCE_MEMORY_MAPPED_IO:
Hobrestypestr = "EFI_RESOURCE_MEMORY_MAPPED_IO"; break;
case EFI_RESOURCE_IO:
Hobrestypestr = "EFI_RESOURCE_IO"; break;
case EFI_RESOURCE_FIRMWARE_DEVICE:
Hobrestypestr = "EFI_RESOURCE_FIRMWARE_DEVICE"; break;
case EFI_RESOURCE_MEMORY_MAPPED_IO_PORT:
Hobrestypestr = "EFI_RESOURCE_MEMORY_MAPPED_IO_PORT"; break;
case EFI_RESOURCE_MEMORY_RESERVED:
Hobrestypestr = "EFI_RESOURCE_MEMORY_RESERVED"; break;
case EFI_RESOURCE_IO_RESERVED:
Hobrestypestr = "EFI_RESOURCE_IO_RESERVED"; break;
case EFI_RESOURCE_MAX_MEMORY_TYPE:
Hobrestypestr = "EFI_RESOURCE_MAX_MEMORY_TYPE"; break;
default:
Hobrestypestr = "EFI_RESOURCE_UNKNOWN"; break;
}
printk(BIOS_SPEW, " Resource %s (0x%0x) has attributes 0x%0x\n",
Hobrestypestr, Hobrestype, Hobresattr);
printk(BIOS_SPEW, " at location 0x%0lx with length 0x%0lx\n",
(long unsigned int)Hobresaddr, (long unsigned int)Hobreslength);
}
static const char * get_hob_type_string(void *Hobptr) {
EFI_HOB_GENERIC_HEADER *HobHeaderPtr = (EFI_HOB_GENERIC_HEADER *)Hobptr;
u16 Hobtype = HobHeaderPtr->HobType;
const char *Hobtypestring = NULL;
switch (Hobtype) {
case EFI_HOB_TYPE_HANDOFF:
Hobtypestring = "EFI_HOB_TYPE_HANDOFF"; break;
case EFI_HOB_TYPE_MEMORY_ALLOCATION:
Hobtypestring = "EFI_HOB_TYPE_MEMORY_ALLOCATION"; break;
case EFI_HOB_TYPE_RESOURCE_DESCRIPTOR:
Hobtypestring = "EFI_HOB_TYPE_RESOURCE_DESCRIPTOR"; break;
case EFI_HOB_TYPE_GUID_EXTENSION:
Hobtypestring = "EFI_HOB_TYPE_GUID_EXTENSION"; break;
case EFI_HOB_TYPE_MEMORY_POOL:
Hobtypestring = "EFI_HOB_TYPE_MEMORY_POOL"; break;
case EFI_HOB_TYPE_UNUSED:
Hobtypestring = "EFI_HOB_TYPE_UNUSED"; break;
case EFI_HOB_TYPE_END_OF_HOB_LIST:
Hobtypestring = "EFI_HOB_TYPE_END_OF_HOB_LIST"; break;
default:
Hobtypestring = "EFI_HOB_TYPE_UNRECOGNIZED"; break;
}
return Hobtypestring;
}
/* Print out a structure of all the HOBs
* that match a certain type:
* Print all types (0x0000)
* EFI_HOB_TYPE_HANDOFF (0x0001)
* EFI_HOB_TYPE_MEMORY_ALLOCATION (0x0002)
* EFI_HOB_TYPE_RESOURCE_DESCRIPTOR (0x0003)
* EFI_HOB_TYPE_GUID_EXTENSION (0x0004)
* EFI_HOB_TYPE_MEMORY_POOL (0x0007)
* EFI_HOB_TYPE_UNUSED (0xFFFE)
* EFI_HOB_TYPE_END_OF_HOB_LIST (0xFFFF)
*/
void print_hob_type_structure(u16 Hobtype, void *Hoblistptr) {
u32 *Currenthob;
u32 *Nexthob = 0;
u8 Lasthob = 0;
u32 Currenttype;
const char *Currenttypestr;
Currenthob = Hoblistptr;
/* Print out HOBs of our desired type until
* the end of the HOB list
*/
printk(BIOS_DEBUG, "\n=== FSP HOB Data Structure ===\n");
printk(BIOS_DEBUG, "FSP Hoblistptr: 0x%0x\n",
(u32) Hoblistptr);
do {
EFI_HOB_GENERIC_HEADER *CurrentHeaderPtr =
(EFI_HOB_GENERIC_HEADER *)Currenthob;
Currenttype = CurrentHeaderPtr->HobType; /* Get the type of this HOB */
Currenttypestr = get_hob_type_string(Currenthob);
if (Currenttype == Hobtype || Hobtype == 0x0000) {
printk(BIOS_DEBUG, "HOB 0x%0x is an %s (type 0x%0x)\n",
(u32) Currenthob, Currenttypestr, Currenttype);
switch (Currenttype) {
case EFI_HOB_TYPE_MEMORY_ALLOCATION:
print_hob_mem_attributes(Currenthob); break;
case EFI_HOB_TYPE_RESOURCE_DESCRIPTOR:
print_hob_resource_attributes(Currenthob); break;
}
}
Lasthob = END_OF_HOB_LIST(Currenthob); /* Check for end of HOB list */
if (!Lasthob) {
Nexthob = GET_NEXT_HOB(Currenthob); /* Get next HOB pointer */
Currenthob = Nexthob; // Start on next HOB
}
} while (!Lasthob);
printk(BIOS_DEBUG, "=== End of FSP HOB Data Structure ===\n\n");
}
#if IS_ENABLED(CONFIG_ENABLE_MRC_CACHE)
/**
* Save the FSP memory HOB (mrc data) to the MRC area in CBMEM
*/
int save_mrc_data(void *hob_start)
{
u32 *mrc_hob;
u32 *mrc_hob_data;
u32 mrc_hob_size;
struct mrc_data_container *mrc_data;
int output_len;
const EFI_GUID mrc_guid = FSP_NON_VOLATILE_STORAGE_HOB_GUID;
mrc_hob = GetNextGuidHob(&mrc_guid, hob_start);
if (mrc_hob == NULL){
printk(BIOS_DEBUG, "Memory Configure Data Hob is not present\n");
return(0);
}
mrc_hob_data = GET_GUID_HOB_DATA (mrc_hob);
mrc_hob_size = (u32) GET_HOB_LENGTH(mrc_hob);
printk(BIOS_DEBUG, "Memory Configure Data Hob at %p (size = 0x%x).\n",
(void *)mrc_hob_data, mrc_hob_size);
output_len = ALIGN(mrc_hob_size, 16);
/* Save the MRC S3/fast boot/ADR restore data to cbmem */
mrc_data = cbmem_add (CBMEM_ID_MRCDATA,
output_len + sizeof(struct mrc_data_container));
/* Just return if there was a problem with getting CBMEM */
if (mrc_data == NULL) {
printk(BIOS_WARNING, "CBMEM was not available to save the fast boot cache data.\n");
return 0;
}
printk(BIOS_DEBUG, "Copy FSP MRC DATA to HOB (source addr %p, dest addr %p, %u bytes)\n",
(void *)mrc_hob_data, mrc_data, output_len);
mrc_data->mrc_signature = MRC_DATA_SIGNATURE;
mrc_data->mrc_data_size = output_len;
mrc_data->reserved = 0;
memcpy(mrc_data->mrc_data, (const void *)mrc_hob_data, mrc_hob_size);
/* Zero the unused space in aligned buffer. */
if (output_len > mrc_hob_size)
memset((mrc_data->mrc_data + mrc_hob_size), 0,
output_len - mrc_hob_size);
mrc_data->mrc_checksum = compute_ip_checksum(mrc_data->mrc_data,
mrc_data->mrc_data_size);
printk(BIOS_SPEW, "Fast boot data (includes align and checksum):\n");
hexdump32(BIOS_SPEW, (void *)mrc_data->mrc_data, output_len);
return (1);
}
#endif /* CONFIG_ENABLE_MRC_CACHE */
static void find_fsp_hob_update_mrc(void *unused)
{
/* Set the global HOB list pointer */
FspHobListPtr = (void*)*((u32*) cbmem_find(CBMEM_ID_HOB_POINTER));
if (!FspHobListPtr){
printk(BIOS_ERR, "ERROR: Could not find FSP HOB pointer in CBFS!\n");
} else {
/* 0x0000: Print all types */
print_hob_type_structure(0x000, FspHobListPtr);
#if IS_ENABLED(CONFIG_ENABLE_MRC_CACHE)
if(save_mrc_data(FspHobListPtr))
update_mrc_cache(NULL);
else
printk(BIOS_DEBUG,"Not updating MRC data in flash.\n");
#endif
}
}
/* Update the MRC/fast boot cache as part of the late table writing stage */
BOOT_STATE_INIT_ENTRIES(fsp_hob_find) = {
BOOT_STATE_INIT_ENTRY(BS_WRITE_TABLES, BS_ON_ENTRY,
find_fsp_hob_update_mrc, NULL),
};
#endif /* #ifndef __PRE_RAM__ */

View File

@ -0,0 +1,95 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2013-2014 Sage Electronic Engineering, LLC.
*
* 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 FSP_UTIL_H
#define FSP_UTIL_H
#include <chipset_fsp_util.h>
#if IS_ENABLED(CONFIG_ENABLE_MRC_CACHE)
int save_mrc_data(void *hob_start);
void * find_and_set_fastboot_cache(void);
#endif
volatile u8 * find_fsp (void);
void fsp_early_init(FSP_INFO_HEADER *fsp_info);
void FspNotify(u32 Phase);
void FspNotifyReturnPoint(EFI_STATUS Status, VOID *HobListPtr);
void print_hob_type_structure(u16 Hobtype, void *Hoblistptr);
void romstage_fsp_rt_buffer_callback(FSP_INIT_RT_BUFFER *FspRtBuffer);
void print_fsp_info(void);
void chipset_fsp_early_init(FSP_INIT_PARAMS *FspInitParams,
FSP_INFO_HEADER *fsp_ptr);
void ChipsetFspReturnPoint(EFI_STATUS Status, VOID *HobListPtr);
/* Additional HOB types not included in the FSP:
* #define EFI_HOB_TYPE_HANDOFF 0x0001
* #define EFI_HOB_TYPE_MEMORY_ALLOCATION 0x0002
* #define EFI_HOB_TYPE_RESOURCE_DESCRIPTOR 0x0003
* #define EFI_HOB_TYPE_GUID_EXTENSION 0x0004
* #define EFI_HOB_TYPE_FV 0x0005
* #define EFI_HOB_TYPE_CPU 0x0006
* #define EFI_HOB_TYPE_MEMORY_POOL 0x0007
* #define EFI_HOB_TYPE_CV 0x0008
* #define EFI_HOB_TYPE_UNUSED 0xFFFE
* #define EFI_HOB_TYPE_END_OF_HOB_LIST 0xffff
*/
#define EFI_HOB_TYPE_HANDOFF 0x0001
#define EFI_HOB_TYPE_MEMORY_POOL 0x0007
#if IS_ENABLED(CONFIG_ENABLE_MRC_CACHE)
#define MRC_DATA_ALIGN 0x1000
#define MRC_DATA_SIGNATURE (('M'<<0)|('R'<<8)|('C'<<16)|('D'<<24))
struct mrc_data_container {
u32 mrc_signature; // "MRCD"
u32 mrc_data_size; // Actual total size of this structure
u32 mrc_checksum; // IP style checksum
u32 reserved; // For header alignment
u8 mrc_data[0]; // Variable size, platform/run time dependent.
} __attribute__ ((packed));
struct mrc_data_container *find_current_mrc_cache(void);
#if !defined(__PRE_RAM__)
void update_mrc_cache(void *unused);
#endif
#endif
/* The offset in bytes from the start of the info structure */
#define FSP_IMAGE_SIG_LOC 0
#define FSP_IMAGE_ID_LOC 16
#define FSP_IMAGE_BASE_LOC 28
#define FSP_SIG 0x48505346 /* 'FSPH' */
#define ERROR_NO_FV_SIG 1
#define ERROR_NO_FFS_GUID 2
#define ERROR_NO_INFO_HEADER 3
#define ERROR_IMAGEBASE_MISMATCH 4
#define ERROR_INFO_HEAD_SIG_MISMATCH 5
#define ERROR_FSP_SIG_MISMATCH 6
#ifndef __PRE_RAM__
extern void *FspHobListPtr;
#endif
#endif /* FSP_UTIL_H */

View File

@ -43,12 +43,16 @@ enum timestamp_id {
TS_END_COPYRAM = 9,
TS_START_RAMSTAGE = 10,
TS_DEVICE_ENUMERATE = 30,
TS_FSP_BEFORE_ENUMERATE,
TS_FSP_AFTER_ENUMERATE,
TS_DEVICE_CONFIGURE = 40,
TS_DEVICE_ENABLE = 50,
TS_DEVICE_INITIALIZE = 60,
TS_DEVICE_DONE = 70,
TS_CBMEM_POST = 75,
TS_WRITE_TABLES = 80,
TS_FSP_BEFORE_FINALIZE,
TS_FSP_AFTER_FINALIZE,
TS_LOAD_PAYLOAD = 90,
TS_ACPI_WAKE_JUMP = 98,
TS_SELFBOOT_JUMP = 99,