Leroy P Leahy (leroy.p.leahy@intel.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/10049
-gerrit
commit b034ef322d990fde13022d3c9ee76177685e37c9 Author: Lee Leahy leroy.p.leahy@intel.com Date: Mon Apr 20 15:29:16 2015 -0700
DO NOT MERGE: drivers/intel: Add FSP 1.1 Driver
Add the FSP 1.1 driver files.
Updates will occur manually to these files only for FSP 1.1 support. An fsp_x_y should be added in the future to support newer versions of the FSP specification.
Please note that due to the interface with EDK2, these files make references to data structures and fields that use CamelCase.
BRANCH=none BUG=None TEST=Build for Braswell or Skylake boards using FSP 1.1.
Change-Id: I2914c047d786a3060075356783ac9758bc41f633 Signed-off-by: Lee Leahy leroy.p.leahy@intel.com --- src/drivers/intel/Kconfig | 1 + src/drivers/intel/Makefile.inc | 1 + src/drivers/intel/fsp1_1/Kconfig | 225 +++++++++++++ src/drivers/intel/fsp1_1/Makefile.inc | 65 ++++ src/drivers/intel/fsp1_1/cache_as_ram.inc | 332 +++++++++++++++++++ src/drivers/intel/fsp1_1/fastboot_cache.c | 271 ++++++++++++++++ src/drivers/intel/fsp1_1/fsp_gop.c | 100 ++++++ src/drivers/intel/fsp1_1/fsp_gop.h | 35 ++ src/drivers/intel/fsp1_1/fsp_hob.c | 512 ++++++++++++++++++++++++++++++ src/drivers/intel/fsp1_1/fsp_relocate.c | 458 ++++++++++++++++++++++++++ src/drivers/intel/fsp1_1/fsp_util.c | 252 +++++++++++++++ src/drivers/intel/fsp1_1/fsp_util.h | 122 +++++++ 12 files changed, 2374 insertions(+)
diff --git a/src/drivers/intel/Kconfig b/src/drivers/intel/Kconfig index 511cf5c..f405927 100644 --- a/src/drivers/intel/Kconfig +++ b/src/drivers/intel/Kconfig @@ -17,5 +17,6 @@ ## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ##
+source src/drivers/intel/fsp1_1/Kconfig source src/drivers/intel/gma/Kconfig source src/drivers/intel/i210/Kconfig diff --git a/src/drivers/intel/Makefile.inc b/src/drivers/intel/Makefile.inc index dc947ff..3ddb05f 100644 --- a/src/drivers/intel/Makefile.inc +++ b/src/drivers/intel/Makefile.inc @@ -1,4 +1,5 @@ subdirs-y += gma subdirs-y += wifi subdirs-$(CONFIG_PLATFORM_USES_FSP1_0) += fsp1_0 +subdirs-$(CONFIG_PLATFORM_USES_FSP1_1) += fsp1_1 subdirs-$(CONFIG_DRIVER_INTEL_I210) += i210 diff --git a/src/drivers/intel/fsp1_1/Kconfig b/src/drivers/intel/fsp1_1/Kconfig new file mode 100644 index 0000000..48dd74c --- /dev/null +++ b/src/drivers/intel/fsp1_1/Kconfig @@ -0,0 +1,225 @@ +## +## 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 +## + +comment "Intel FSP" + +config PLATFORM_USES_FSP1_1 + bool "Use Intel Firmware Support Package" + help + Does the code require the Intel Firmware Support Package? + +if PLATFORM_USES_FSP1_1 + +config DCACHE_RAM_BASE + hex + default 0xfef00000 + +config DCACHE_RAM_SIZE + hex + default 0x4000 + +config HAVE_FSP_BIN + bool "Should the Intel FSP binary be added to the flash image" + 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 + +if HAVE_FSP_BIN + +config CPU_MICROCODE_CBFS_LEN + hex "Microcode update region length in bytes" + default 0 + help + The length in bytes of the microcode update region. + +config CPU_MICROCODE_CBFS_LOC + hex "Microcode update base address in CBFS" + default 0 + help + The location (base address) in CBFS that contains the microcode update + binary. + +config ENABLE_MRC_CACHE + bool + default y if HAVE_ACPI_RESUME + default n + 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 FSP_FILE + string "Intel FSP binary path and filename" + help + The path and filename of the Intel FSP binary for this platform. + +config FSP_IMAGE_ID_DWORD0 + hex "First 4 bytes of 8 byte platform string" + help + The first four bytes of the eight byte platform specific string + used to identify the FSP binary that should be used. + +config FSP_IMAGE_ID_DWORD1 + hex "Second 4 bytes of 8 byte platform string" + help + The second four bytes of the eight byte platform specific string + used to identify the FSP binary that should be used. + +config FSP_INCLUDE_PATH + string "Path for FSP specific include files" + 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 FSP_RESERVED_MEM_SIZE + hex "FSP Reserved Memory" + default 0x00100000 + help + Memory size in bytes reserved by FSP between PEI Memory and the + base of TSEG. + +config MRC_CACHE_FILE + string "File containing the cached MRC values" + help + The path and filename of the cached MRC values. + +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 MRC_CACHE_LOC_OVERRIDE + hex + help + Sets the override CBFS location of the MRC/fast boot cache. + +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 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 DISPLAY_FAST_BOOT_DATA + bool "Display fast boot data" + default n + +config DISPLAY_HOBS + bool "Display hand-off-blocks (HOBs)" + default n + +config DISPLAY_VBT + bool "Display Video BIOS Table (VBT)" + default n + +config DISPLAY_FSP_ENTRY_POINTS + bool "Display FSP entry points" + default n + +config DISPLAY_UPD_DATA + bool "Display UPD data" + default n + help + Display the user specified product data prior to memory + initialization. + +config FSP_USES_UPD + bool + default n + help + If this FSP uses UPD/VPD data regions, select this in the chipset + Kconfig. + +config GOP_SUPPORT + bool "Enables GOP support" + default y + +config POST_IO + bool + default y + +config POST_IO_PORT + hex + default 0x80 + +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 VBT_FILE + string "GOP Video BIOS table binary path" + depends on GOP_SUPPORT + default "3rdparty/mainboard/$(MAINBOARDDIR)/vbt.bin" + +endif #PLATFORM_USES_FSP1_1 diff --git a/src/drivers/intel/fsp1_1/Makefile.inc b/src/drivers/intel/fsp1_1/Makefile.inc new file mode 100644 index 0000000..1b5d6ca --- /dev/null +++ b/src/drivers/intel/fsp1_1/Makefile.inc @@ -0,0 +1,65 @@ +# +# This file is part of the coreboot project. +# +# Copyright (C) 2014 Sage Electronic Engineering, LLC. +# Copyright (C) 2015 Intel Corp. +# +# 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 +# + +romstage-$(CONFIG_ENABLE_MRC_CACHE) += fastboot_cache.c +romstage-$(CONFIG_GOP_SUPPORT) += fsp_gop.c +romstage-y += fsp_hob.c +romstage-y += fsp_util.c + +ramstage-$(CONFIG_ENABLE_MRC_CACHE) += fastboot_cache.c +ramstage-$(CONFIG_GOP_SUPPORT) += fsp_gop.c +ramstage-y += fsp_hob.c +ramstage-y += fsp_relocate.c +ramstage-y += fsp_util.c + +CPPFLAGS_common += -Isrc/drivers/intel/fsp1_1 + +ifeq ($(CONFIG_USE_GENERIC_FSP_CAR_INC),y) +cpu_incs-y += $(src)/drivers/intel/fsp1_1/cache_as_ram.inc +endif + + +# Add the GOP Video BIOS Table to the cbfs image +cbfs-files-$(CONFIG_GOP_SUPPORT) += vbt.bin +vbt.bin-file := $(call strip_quotes,$(CONFIG_VBT_FILE)) +vbt.bin-type := optionrom + + +# Add the FSP binary to the cbfs image +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 + + +# Create and add the MRC cache to the cbfs image +ifeq ($(CONFIG_ENABLE_MRC_CACHE_FILE),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 := $(call strip_quotes,$(CONFIG_MRC_CACHE_FILE)) +mrc.cache-position := $(CONFIG_MRC_CACHE_LOC) +mrc.cache-type := 0xac +endif diff --git a/src/drivers/intel/fsp1_1/cache_as_ram.inc b/src/drivers/intel/fsp1_1/cache_as_ram.inc new file mode 100644 index 0000000..ef6510e --- /dev/null +++ b/src/drivers/intel/fsp1_1/cache_as_ram.inc @@ -0,0 +1,332 @@ +/* + * 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. + * Copyright (C) 2015 Intel Corp. + * + * 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 + */ + +/* + * This code locates the FSP binary, initializes the cache as RAM and + * performs the first stage of initialization. Next this code switches + * the stack from the cache to RAM and then disables the cache as RAM. + * Finally this code performs the final stage of initialization. + */ + +#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 IS_ENABLED(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 */ + + /* + * eax: BIST value + * mm0: low 32-bits of TSC value + * mm1: high 32-bits of TSC value + */ + + mov %eax, %edi + +cache_as_ram: + post_code(0x20) + + /* + * edi: BIST value + * mm0: low 32-bits of TSC value + * mm1: high 32-bits of TSC value + */ + + /* + * 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 + + /* + * Only when a valid FSP binary is found at CONFIG_FSP_LOC is + * the returned FSP_INFO_HEADER structure address above the base + * address of FSP binary specified by the CONFIG_FSP_LOC value. + * All of the error values are in the 0x8xxxxxxx range which are + * below the CONFIG_FSP_LOC value. + */ + cmp $CONFIG_FSP_LOC, %eax + jbe halt1 + + post_code(0x22) + + /* Calculate entry into FSP */ + mov 0x30(%ebp), %eax /* Load TempRamInitEntry */ + add 0x1c(%ebp), %eax /* add in the offset for FSP */ + + /* + * Pass early init variables on a fake stack (no memory yet) + * as well as the return location + */ + lea CAR_init_stack, %esp + + /* + * BIST value is zero + * eax: TempRamInitApi address + * ebp: FSP_INFO_HEADER address + * edi: BIST value + * esi: Not used + * mm0: low 32-bits of TSC value + * mm1: high 32-bits of TSC value + */ + + /* call FSP binary to setup temporary stack */ + jmp *%eax + +CAR_init_done: + addl $4, %esp + + /* + * ebp: FSP_INFO_HEADER address + * ecx: Temp RAM base + * edx: Temp RAM top + * edi: BIST value + * mm0: low 32-bits of TSC value + * mm1: high 32-bits of TSC value + */ + + cmp $0, %eax + jne halt2 + + /* Setup bootloader stack */ + movl %edx, %esp + + /* Save BIST value */ + movd %edi, %mm2 + + /* + * ebp: FSP_INFO_HEADER address + * ecx: Temp RAM base + * edx: Temp RAM top + * esp: Top of stack in temp RAM + * mm0: low 32-bits of TSC value + * mm1: high 32-bits of TSC value + * mm2: BIST value + */ + + /* Coreboot assumes stack/heap region will be zero */ + cld + movl %ecx, %edi + neg %ecx + add %edx, %ecx + shrl $2, %ecx + xorl %eax, %eax + rep stosl + + /* Save FSP_INFO_HEADER location in ebx */ + mov %ebp, %ebx + + /* + * ebx: FSP_INFO_HEADER address + * esi: Temp RAM base + * esp: Top of stack in temp RAM + * mm0: low 32-bits of TSC value + * mm1: high 32-bits of TSC value + * mm2: BIST value + */ + + /* Build frame for romstage_main(bist, tsc_low, tsc_hi) */ + movd %mm1, %eax + pushl %eax + movd %mm0, %eax + pushl %eax + movd %mm2, %eax + pushl %eax + +before_romstage: + post_code(0x23) + + /* Call romstage.c main function. */ + call romstage_main + + /* + * eax: New stack address + * ebx: FSP_INFO_HEADER address + */ + + /* Switch to the stack in RAM */ + movl %eax, %esp + + /* Calculate TempRamExit entry into FSP */ + movl %ebx, %ebp + mov 0x40(%ebp), %eax + add 0x1c(%ebp), %eax + + /* Build the call frame */ + pushl $0 + + /* Call TempRamExit */ + call *%eax + add $4, %esp + cmp $0, %eax + jne halt3 + + /* Get number of MTRRs. */ + popl %ebx + movl $MTRRphysBase_MSR(0), %ecx +1: + testl %ebx, %ebx + jz 1f + + /* Low 32 bits of MTRR base. */ + popl %eax + /* Upper 32 bits of MTRR base. */ + popl %edx + /* Write MTRR base. */ + wrmsr + inc %ecx + /* Low 32 bits of MTRR mask. */ + popl %eax + /* Upper 32 bits of MTRR mask. */ + popl %edx + /* Write MTRR mask. */ + wrmsr + inc %ecx + + dec %ebx + jmp 1b +1: + post_code(0x39) + + /* And enable cache again after setting MTRRs. */ + movl %cr0, %eax + andl $~(CR0_CacheDisable | CR0_NoWriteThrough), %eax + movl %eax, %cr0 + + post_code(0x3a) + + /* Enable MTRR. */ + movl $MTRRdefType_MSR, %ecx + rdmsr + orl $MTRRdefTypeEn, %eax + wrmsr + + post_code(0x3b) + + /* Invalidate the cache again. */ + invd + + post_code(0x3c) + +__main: + post_code(POST_PREPARE_RAMSTAGE) + cld /* Clear direction flag. */ + call romstage_after_car + + + movb $0x69, %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. + * 0x03 - FSP_UNSUPPORTED: The FSP calling conditions were not met. + * 0x07 - FSP_DEVICE_ERROR: Temp RAM initialization failed + * 0x0E - FSP_NOT_FOUND: No valid microcode was found in the microcode region. + * 0x14 - FSP_ALREADY_STARTED: Temp RAM initialization has been invoked + */ + movb $0xBB, %ah + jmp .Lhlt + +halt3: + /* + * Failures for post code BC - failed in TempRamExit + * + * 0x00 - FSP_SUCCESS: Temp RAM Exit completed successfully. + * 0x02 - FSP_INVALID_PARAMETER: Input parameters are invalid. + * 0x03 - FSP_UNSUPPORTED: The FSP calling conditions were not met. + * 0x07 - FSP_DEVICE_ERROR: Temp RAM Exit failed. + */ + movb $0xBC, %ah + +.Lhlt: + xchg %al, %ah +#if IS_ENABLED(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 /* Microcode Location */ + .long CONFIG_CPU_MICROCODE_CBFS_LEN /* Microcode Length */ + .long 0xFFFFFFFF - CONFIG_CBFS_SIZE + 1 /* Firmware Location */ + .long CONFIG_CBFS_SIZE /* Total Firmware Length */ + +CAR_init_stack: + .long CAR_init_done + .long CAR_init_params diff --git a/src/drivers/intel/fsp1_1/fastboot_cache.c b/src/drivers/intel/fsp1_1/fastboot_cache.c new file mode 100644 index 0000000..91796c6 --- /dev/null +++ b/src/drivers/intel/fsp1_1/fastboot_cache.c @@ -0,0 +1,271 @@ +/* + * 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) +{ + const char *name = "mrc.cache"; + int type = 0xac; + struct cbfs_file *file = cbfs_get_file(CBFS_DEFAULT_MEDIA, name); + + if (file == NULL) { + printk(BIOS_ERR, "Could not find file '%s'.\n", name); + return 0; + } + + if (ntohl(file->type) != type) { + printk(BIOS_ERR, "File '%s' is of type %x, but we requested %x.\n", + name, ntohl(file->type), type); + return 0; + } + + return ntohl(file->len); +} + +/* + * 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_base = NULL; + 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); + 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; + mrc_cache = find_current_mrc_cache(); + if ((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_base = NULL; + 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); +} diff --git a/src/drivers/intel/fsp1_1/fsp_gop.c b/src/drivers/intel/fsp1_1/fsp_gop.c new file mode 100644 index 0000000..1979f04 --- /dev/null +++ b/src/drivers/intel/fsp1_1/fsp_gop.c @@ -0,0 +1,100 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 Intel Corp. + * + * 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 <cbfs.h> +#include <console/console.h> +#include "fsp_util.h" +#include <lib.h> + +/* Reading VBT table from flash */ +const optionrom_vbt_t *fsp_get_vbt(uint32_t *vbt_len) +{ + struct cbfs_file *vbt_file; + union { + const optionrom_vbt_t *data; + uint32_t *signature; + } vbt; + + /* Locate the vbt file in cbfs */ + vbt_file = cbfs_get_file(CBFS_DEFAULT_MEDIA, "vbt.bin"); + if (!vbt_file) { + printk(BIOS_DEBUG, "vbt data not found"); + return NULL; + } + + /* Validate the vbt file */ + vbt.data = CBFS_SUBHEADER(vbt_file); + if (*vbt.signature != VBT_SIGNATURE) { + printk(BIOS_DEBUG, "FSP VBT not found!\n"); + return NULL; + } + *vbt_len = ntohl(vbt_file->len); + printk(BIOS_DEBUG, "VBT found at %p, 0x%08x bytes\n", vbt.data, + *vbt_len); + +#if IS_ENABLED(CONFIG_DISPLAY_VBT) + /* Display the vbt file contents */ + printk(BIOS_DEBUG, "VBT Data:\n"); + hexdump(vbt.data, *vbt_len); + printk(BIOS_DEBUG, "\n"); +#endif + + /* Return the pointer to the vbt file data */ + return vbt.data; +} + +#ifndef __PRE_RAM__ +void fsp_gop_framebuffer(struct lb_header *header) +{ + struct lb_framebuffer *framebuffer; + framebuffer = (struct lb_framebuffer *)lb_new_record(header); + + VOID *hob_list_ptr; + hob_list_ptr = get_hob_list(); + const EFI_GUID vbt_guid = EFI_PEI_GRAPHICS_INFO_HOB_GUID; + u32 *vbt_hob; + EFI_PEI_GRAPHICS_INFO_HOB *vbt_gop; + vbt_hob = get_next_guid_hob(&vbt_guid, hob_list_ptr); + if (vbt_hob == NULL) { + printk(BIOS_DEBUG, "Graphics Data Hob is not present\n"); + return; + } else { + printk(BIOS_DEBUG, "Graphics Data present\n"); + vbt_gop = GET_GUID_HOB_DATA(vbt_hob); + } + + framebuffer->physical_address = vbt_gop->FrameBufferBase; + framebuffer->x_resolution = vbt_gop->GraphicsMode.HorizontalResolution; + framebuffer->y_resolution = vbt_gop->GraphicsMode.VerticalResolution; + framebuffer->bytes_per_line = vbt_gop->GraphicsMode.PixelsPerScanLine + * 4; + framebuffer->bits_per_pixel = 32; + framebuffer->red_mask_pos = 16; + framebuffer->red_mask_size = 8; + framebuffer->green_mask_pos = 8; + framebuffer->green_mask_size = 8; + framebuffer->blue_mask_pos = 0; + framebuffer->blue_mask_size = 8; + framebuffer->reserved_mask_pos = 24; + framebuffer->reserved_mask_size = 8; + framebuffer->tag = LB_TAG_FRAMEBUFFER; + framebuffer->size = sizeof(*framebuffer); +} +#endif /* __PRE_RAM__ */ + diff --git a/src/drivers/intel/fsp1_1/fsp_gop.h b/src/drivers/intel/fsp1_1/fsp_gop.h new file mode 100644 index 0000000..3446d5f --- /dev/null +++ b/src/drivers/intel/fsp1_1/fsp_gop.h @@ -0,0 +1,35 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 Intel Corp. + * + * 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_GOP_H_ +#define _FSP_GOP_H_ + +/* GOP support */ +#if IS_ENABLED(CONFIG_GOP_SUPPORT) + +#include <boot/coreboot_tables.h> +#include <soc/intel/common/gma.h> + +const optionrom_vbt_t *fsp_get_vbt(uint32_t *vbt_len); +#ifndef __PRE_RAM__ +void fsp_gop_framebuffer(struct lb_header *header); +#endif /* __PRE_RAM__ */ +#endif /* CONFIG_GOP_SUPPORT */ +#endif /* _FSP_GOP_H_ */ + diff --git a/src/drivers/intel/fsp1_1/fsp_hob.c b/src/drivers/intel/fsp1_1/fsp_hob.c new file mode 100644 index 0000000..6de67f2 --- /dev/null +++ b/src/drivers/intel/fsp1_1/fsp_hob.c @@ -0,0 +1,512 @@ +/****************************************************************************** + +Copyright (C) 2013, Intel Corporation + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. +* Neither the name of Intel Corporation nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + THE POSSIBILITY OF SUCH DAMAGE. + + ******************************************************************************/ + +/*********************************************************************** + * + * fsp_hob.c + * + * HOB infrastructure code. + * + **********************************************************************/ + +#include <arch/early_variables.h> +#include <arch/hlt.h> +#include <bootstate.h> +#include <cbmem.h> +#include <console/console.h> +#include "fsp_util.h" +#include <ip_checksum.h> +#include <lib.h> // hexdump +#include <string.h> + +/* + * Reads a 64-bit value from memory that may be unaligned. + * + * This function returns the 64-bit value pointed to by buffer. The + * function guarantees that the read operation does not produce an + * alignment fault. + * + * If buffer is NULL, then ASSERT(). + * + * buffer: Pointer to a 64-bit value that may be unaligned. + * + * Returns the 64-bit value read from buffer. + * + */ +static +uint64_t +read_unaligned_64( + const uint64_t *buffer + ) +{ + ASSERT(buffer != NULL); + + return *buffer; +} + +/* + * Compares two GUIDs. + * + * This function compares guid1 to guid2. If the GUIDs are identical then + * TRUE is returned. If there are any bit differences in the two GUIDs, + * then FALSE is returned. + * + * If guid1 is NULL, then ASSERT(). + * If guid2 is NULL, then ASSERT(). + * + * guid1: A pointer to a 128 bit GUID. + * guid2: A pointer to a 128 bit GUID. + * + * Returns non-zero if guid1 and guid2 are identical, otherwise returns 0. + * + */ +static +long +compare_guid( + const EFI_GUID * guid1, + const EFI_GUID * guid2 + ) +{ + uint64_t low_part_of_guid1; + uint64_t low_part_of_guid2; + uint64_t high_part_of_guid1; + uint64_t high_part_of_guid2; + + low_part_of_guid1 = read_unaligned_64((const uint64_t *) guid1); + low_part_of_guid2 = read_unaligned_64((const uint64_t *) guid2); + high_part_of_guid1 = read_unaligned_64((const uint64_t *) guid1 + 1); + high_part_of_guid2 = read_unaligned_64((const uint64_t *) guid2 + 1); + + return ((low_part_of_guid1 == low_part_of_guid2) + && (high_part_of_guid1 == high_part_of_guid2)); +} + +/* Returns the pointer to the HOB list. */ +VOID * +EFIAPI +get_hob_list( + VOID + ) +{ + void *hob_list; + + hob_list = fsp_get_hob_list(); + if (hob_list == NULL) + die("Call fsp_set_runtime() before this call!\n"); + return hob_list; +} + +/* Returns the next instance of a HOB type from the starting HOB. */ +VOID * +EFIAPI +get_next_hob( + UINT16 type, + CONST VOID *hob_start + ) +{ + EFI_PEI_HOB_POINTERS hob; + + ASSERT(hob_start != NULL); + + hob.Raw = (UINT8 *)hob_start; + + /* Parse the HOB list until end of list or matching type is found. */ + while (!END_OF_HOB_LIST(hob.Raw)) { + if (hob.Header->HobType == type) + return hob.Raw; + if (GET_HOB_LENGTH(hob.Raw) < sizeof(*hob.Header)) + break; + hob.Raw = GET_NEXT_HOB(hob.Raw); + } + return NULL; +} + +/* Returns the first instance of a HOB type among the whole HOB list. */ +VOID * +EFIAPI +get_first_hob( + UINT16 type + ) +{ + VOID *hob_list; + + hob_list = get_hob_list(); + return get_next_hob(type, hob_list); +} + +/* Returns the next instance of the matched GUID HOB from the starting HOB. */ +VOID * +EFIAPI +get_next_guid_hob( + CONST EFI_GUID * guid, + CONST VOID *hob_start + ) +{ + EFI_PEI_HOB_POINTERS hob; + + hob.Raw = (UINT8 *)hob_start; + while ((hob.Raw = get_next_hob(EFI_HOB_TYPE_GUID_EXTENSION, hob.Raw)) + != NULL) { + if (compare_guid(guid, &hob.Guid->Name)) + break; + hob.Raw = GET_NEXT_HOB(hob.Raw); + } + return hob.Raw; +} + +/* + * Returns the first instance of the matched GUID HOB among the whole HOB list. + */ +VOID * +EFIAPI +get_first_guid_hob( + CONST EFI_GUID * guid + ) +{ + return get_next_guid_hob(guid, get_hob_list()); +} + +/* + * Returns the next instance of the matching resource HOB from the starting HOB. + */ +void *get_next_resource_hob(const EFI_GUID *guid, const void *hob_start) +{ + EFI_PEI_HOB_POINTERS hob; + + hob.Raw = (UINT8 *)hob_start; + while ((hob.Raw = get_next_hob(EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, + hob.Raw)) != NULL) { + if (compare_guid(guid, &hob.ResourceDescriptor->Owner)) + break; + hob.Raw = GET_NEXT_HOB(hob.Raw); + } + return hob.Raw; +} + +/* + * Returns the first instance of the matching resource HOB among the whole HOB + * list. + */ +void *get_first_resource_hob(const EFI_GUID *guid) +{ + return get_next_resource_hob(guid, get_hob_list()); +} + +static void print_hob_mem_attributes(void *hob_ptr) +{ + EFI_HOB_MEMORY_ALLOCATION *hob_memory_ptr = + (EFI_HOB_MEMORY_ALLOCATION *)hob_ptr; + EFI_MEMORY_TYPE hob_mem_type = + hob_memory_ptr->AllocDescriptor.MemoryType; + u64 hob_mem_addr = hob_memory_ptr->AllocDescriptor.MemoryBaseAddress; + u64 hob_mem_length = hob_memory_ptr->AllocDescriptor.MemoryLength; + const char *hob_mem_type_names[15]; + + hob_mem_type_names[0] = "EfiReservedMemoryType"; + hob_mem_type_names[1] = "EfiLoaderCode"; + hob_mem_type_names[2] = "EfiLoaderData"; + hob_mem_type_names[3] = "EfiBootServicesCode"; + hob_mem_type_names[4] = "EfiBootServicesData"; + hob_mem_type_names[5] = "EfiRuntimeServicesCode"; + hob_mem_type_names[6] = "EfiRuntimeServicesData"; + hob_mem_type_names[7] = "EfiConventionalMemory"; + hob_mem_type_names[8] = "EfiUnusableMemory"; + hob_mem_type_names[9] = "EfiACPIReclaimMemory"; + hob_mem_type_names[10] = "EfiACPIMemoryNVS"; + hob_mem_type_names[11] = "EfiMemoryMappedIO"; + hob_mem_type_names[12] = "EfiMemoryMappedIOPortSpace"; + hob_mem_type_names[13] = "EfiPalCode"; + hob_mem_type_names[14] = "EfiMaxMemoryType"; + + printk(BIOS_SPEW, " Memory type %s (0x%x)\n", + hob_mem_type_names[(u32)hob_mem_type], + (u32)hob_mem_type); + printk(BIOS_SPEW, " at location 0x%0lx with length 0x%0lx\n", + (unsigned long)hob_mem_addr, + (unsigned long)hob_mem_length); +} + +static void print_hob_resource_attributes(void *hob_ptr) +{ + EFI_HOB_RESOURCE_DESCRIPTOR *hob_resource_ptr = + (EFI_HOB_RESOURCE_DESCRIPTOR *)hob_ptr; + u32 hob_res_type = hob_resource_ptr->ResourceType; + u32 hob_res_attr = hob_resource_ptr->ResourceAttribute; + u64 hob_res_addr = hob_resource_ptr->PhysicalStart; + u64 hob_res_length = hob_resource_ptr->ResourceLength; + const char *hob_res_type_str = NULL; + + /* HOB Resource Types */ + switch (hob_res_type) { + case EFI_RESOURCE_SYSTEM_MEMORY: + hob_res_type_str = "EFI_RESOURCE_SYSTEM_MEMORY"; + break; + case EFI_RESOURCE_MEMORY_MAPPED_IO: + hob_res_type_str = "EFI_RESOURCE_MEMORY_MAPPED_IO"; + break; + case EFI_RESOURCE_IO: + hob_res_type_str = "EFI_RESOURCE_IO"; + break; + case EFI_RESOURCE_FIRMWARE_DEVICE: + hob_res_type_str = "EFI_RESOURCE_FIRMWARE_DEVICE"; + break; + case EFI_RESOURCE_MEMORY_MAPPED_IO_PORT: + hob_res_type_str = "EFI_RESOURCE_MEMORY_MAPPED_IO_PORT"; + break; + case EFI_RESOURCE_MEMORY_RESERVED: + hob_res_type_str = "EFI_RESOURCE_MEMORY_RESERVED"; + break; + case EFI_RESOURCE_IO_RESERVED: + hob_res_type_str = "EFI_RESOURCE_IO_RESERVED"; + break; + case EFI_RESOURCE_MAX_MEMORY_TYPE: + hob_res_type_str = "EFI_RESOURCE_MAX_MEMORY_TYPE"; + break; + default: + hob_res_type_str = "EFI_RESOURCE_UNKNOWN"; + break; + } + + printk(BIOS_SPEW, " Resource %s (0x%0x) has attributes 0x%0x\n", + hob_res_type_str, hob_res_type, hob_res_attr); + printk(BIOS_SPEW, " at location 0x%0lx with length 0x%0lx\n", + (unsigned long)hob_res_addr, + (unsigned long)hob_res_length); +} + +static const char *get_hob_type_string(void *hob_ptr) +{ + EFI_PEI_HOB_POINTERS hob; + const char *hob_type_string = NULL; + const EFI_GUID fsp_reserved_guid = + FSP_RESERVED_MEMORY_RESOURCE_HOB_GUID; + const EFI_GUID mrc_guid = FSP_NON_VOLATILE_STORAGE_HOB_GUID; + const EFI_GUID bootldr_tmp_mem_guid = + FSP_BOOTLOADER_TEMP_MEMORY_HOB_GUID; + const EFI_GUID bootldr_tolum_guid = FSP_BOOTLOADER_TOLUM_HOB_GUID; + const EFI_GUID graphics_info_guid = EFI_PEI_GRAPHICS_INFO_HOB_GUID; + + hob.Header = (EFI_HOB_GENERIC_HEADER *)hob_ptr; + switch (hob.Header->HobType) { + case EFI_HOB_TYPE_HANDOFF: + hob_type_string = "EFI_HOB_TYPE_HANDOFF"; + break; + case EFI_HOB_TYPE_MEMORY_ALLOCATION: + hob_type_string = "EFI_HOB_TYPE_MEMORY_ALLOCATION"; + break; + case EFI_HOB_TYPE_RESOURCE_DESCRIPTOR: + hob_type_string = "EFI_HOB_TYPE_RESOURCE_DESCRIPTOR"; + break; + case EFI_HOB_TYPE_GUID_EXTENSION: + hob_type_string = "EFI_HOB_TYPE_GUID_EXTENSION"; + if (compare_guid(&bootldr_tmp_mem_guid, &hob.Guid->Name)) + hob_type_string = "FSP_BOOTLOADER_TEMP_MEMORY_HOB"; + else if (compare_guid(&fsp_reserved_guid, &hob.Guid->Name)) + hob_type_string = "FSP_RESERVED_MEMORY_RESOURCE_HOB"; + else if (compare_guid(&mrc_guid, &hob.Guid->Name)) + hob_type_string = "FSP_NON_VOLATILE_STORAGE_HOB"; + else if (compare_guid(&bootldr_tolum_guid, &hob.Guid->Name)) + hob_type_string = "FSP_BOOTLOADER_TOLUM_HOB_GUID"; + else if (compare_guid(&graphics_info_guid, &hob.Guid->Name)) + hob_type_string = "EFI_PEI_GRAPHICS_INFO_HOB_GUID"; + break; + case EFI_HOB_TYPE_MEMORY_POOL: + hob_type_string = "EFI_HOB_TYPE_MEMORY_POOL"; + break; + case EFI_HOB_TYPE_UNUSED: + hob_type_string = "EFI_HOB_TYPE_UNUSED"; + break; + case EFI_HOB_TYPE_END_OF_HOB_LIST: + hob_type_string = "EFI_HOB_TYPE_END_OF_HOB_LIST"; + break; + default: + hob_type_string = "EFI_HOB_TYPE_UNRECOGNIZED"; + break; + } + + return hob_type_string; +} + +/* + * 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 hob_type, void *hob_list_ptr) +{ + u32 *current_hob; + u32 *next_hob = 0; + u8 last_hob = 0; + u32 current_type; + const char *current_type_str; + + current_hob = hob_list_ptr; + + /* + * 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, "0x%p: hob_list_ptr\n", hob_list_ptr); + do { + EFI_HOB_GENERIC_HEADER *current_header_ptr = + (EFI_HOB_GENERIC_HEADER *)current_hob; + + /* Get the type of this HOB */ + current_type = current_header_ptr->HobType; + current_type_str = get_hob_type_string(current_hob); + + if (current_type == hob_type || hob_type == 0x0000) { + printk(BIOS_DEBUG, "HOB 0x%0x is an %s (type 0x%0x)\n", + (u32)current_hob, current_type_str, + current_type); + switch (current_type) { + case EFI_HOB_TYPE_MEMORY_ALLOCATION: + print_hob_mem_attributes(current_hob); + break; + case EFI_HOB_TYPE_RESOURCE_DESCRIPTOR: + print_hob_resource_attributes(current_hob); + break; + } + } + + /* Check for end of HOB list */ + last_hob = END_OF_HOB_LIST(current_hob); + if (!last_hob) { + /* Get next HOB pointer */ + next_hob = GET_NEXT_HOB(current_hob); + + /* Start on next HOB */ + current_hob = next_hob; + } + } while (!last_hob); + 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 = get_next_guid_hob(&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); + +#if IS_ENABLED(CONFIG_DISPLAY_FAST_BOOT_DATA) + printk(BIOS_SPEW, "Fast boot data (includes align and checksum):\n"); + hexdump32(BIOS_SPEW, (void *)mrc_data->mrc_data, output_len); +#endif + return 1; +} + +void __attribute__ ((weak)) update_mrc_cache(void *unused) +{ + printk(BIOS_ERR, "Add routine %s to save the MRC data.\n", __func__); +} +#endif /* CONFIG_ENABLE_MRC_CACHE */ + +static void find_fsp_hob_update_mrc(void *unused) +{ + void *hob_list_ptr; + + /* 0x0000: Print all types */ + hob_list_ptr = get_hob_list(); +#if IS_ENABLED(CONFIG_DISPLAY_HOBS) + print_hob_type_structure(0x000, hob_list_ptr); +#endif + + #if IS_ENABLED(CONFIG_ENABLE_MRC_CACHE) + if (save_mrc_data(hob_list_ptr)) + 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), +}; + diff --git a/src/drivers/intel/fsp1_1/fsp_relocate.c b/src/drivers/intel/fsp1_1/fsp_relocate.c new file mode 100644 index 0000000..db613ee --- /dev/null +++ b/src/drivers/intel/fsp1_1/fsp_relocate.c @@ -0,0 +1,458 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2015 Google 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. + */ + +#include <console/console.h> +#include <cbmem.h> +#include <fsp_util.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <uefi_types.h> + +#define FSP_DBG_LVL BIOS_NEVER + +static const EFI_GUID ffs2_guid = EFI_FIRMWARE_FILE_SYSTEM2_GUID; +static const EFI_GUID fih_guid = FSP_INFO_HEADER_GUID; + +struct fsp_patch_table { + uint32_t signature; + uint16_t header_length; + uint8_t header_revision; + uint8_t reserved; + uint32_t patch_entry_num; + uint32_t patch_entries[0]; +} __attribute__((packed)); + +#define FSPP_SIG 0x50505346 + +static void *relative_offset(void *base, ssize_t offset) +{ + uintptr_t loc; + + loc = (uintptr_t)base; + loc += offset; + + return (void *)loc; +} + +static uint32_t *fspp_reloc(void *fsp, size_t fsp_size, uint32_t e) +{ + size_t offset; + + /* Offsets live in bits 23:0. */ + offset = e & 0xffffff; + + /* If bit 31 is set then the offset is considered a negative value + * relative to the end of the image using 16MiB as the offset's + * reference. */ + if (e & (1 << 31)) + offset = fsp_size - (16 * MiB - offset); + + /* Determine if offset falls within fsp_size for a 32 bit relocation. */ + if (offset > fsp_size - sizeof(uint32_t)) + return NULL; + + return relative_offset(fsp, offset); +} + +static int reloc_type(uint16_t reloc_entry) +{ + /* Reloc type in upper 4 bits */ + return reloc_entry >> 12; +} + +static size_t reloc_offset(uint16_t reloc_entry) +{ + /* Offsets are in low 12 bits. */ + return reloc_entry & ((1 << 12) - 1); +} + +static int te_relocate_in_place(void *te, size_t size) +{ + EFI_TE_IMAGE_HEADER *teih; + EFI_IMAGE_DATA_DIRECTORY *relocd; + EFI_IMAGE_BASE_RELOCATION *relocb; + size_t fixup_offset; + size_t num_relocs; + uint16_t *reloc; + size_t relocd_offset; + uint8_t *te_base; + uint32_t adj; + + teih = te; + + if (teih->Signature != EFI_TE_IMAGE_HEADER_SIGNATURE) { + printk(BIOS_ERR, "TE Signature mismatch: %x vs %x\n", + teih->Signature, EFI_TE_IMAGE_HEADER_SIGNATURE); + return -1; + } + + /* + * A TE image is created by converting a PE file. Because of this + * the offsets within the headers are off. In order to calculate + * the correct releative offets one needs to subtract fixup_offset + * from the encoded offets. Similarly, the linked address of the + * program is found by adding the fixup_offset to the ImageBase. + */ + fixup_offset = teih->StrippedSize - sizeof(EFI_TE_IMAGE_HEADER); + /* Keep track of a base that is correctly adjusted so that offsets + * can be used directly. */ + te_base = te; + te_base -= fixup_offset; + + adj = (uintptr_t)te - (teih->ImageBase + fixup_offset); + + printk(FSP_DBG_LVL, "TE Image %p -> %p adjust value: %x\n", + (void *)(uintptr_t)(teih->ImageBase + fixup_offset), + te, adj); + + /* Adjust ImageBase for consistency. Need to subtract fixup_offset + * so the image could be relocated if needed. */ + teih->ImageBase += adj - fixup_offset; + + relocd = &teih->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC]; + + relocd_offset = 0; + /* Though the field name is VirtualAddress it's actually relative to + * the beginning of the image which is linked at ImageBase. */ + relocb = relative_offset(te, relocd->VirtualAddress - fixup_offset); + while (relocd_offset < relocd->Size) { + size_t rva_offset = relocb->VirtualAddress; + + printk(FSP_DBG_LVL, "Relocs for RVA offset %zx\n", rva_offset); + num_relocs = relocb->SizeOfBlock - sizeof(*relocb); + num_relocs /= sizeof(uint16_t); + reloc = relative_offset(relocb, sizeof(*relocb)); + + printk(FSP_DBG_LVL, "Num relocs in block: %zx\n", num_relocs); + + while (num_relocs > 0) { + int type = reloc_type(*reloc); + size_t offset = reloc_offset(*reloc); + + printk(FSP_DBG_LVL, "reloc type %x offset %zx\n", + type, offset); + + if (type == EFI_IMAGE_REL_BASED_HIGHLOW) { + uint32_t *reloc_addr; + + offset += rva_offset; + reloc_addr = (void *)&te_base[offset]; + + printk(FSP_DBG_LVL, "Adjusting %p %x -> %x\n", + reloc_addr, *reloc_addr, + *reloc_addr + adj); + *reloc_addr += adj; + } else if (type != EFI_IMAGE_REL_BASED_ABSOLUTE) { + printk(BIOS_ERR, "Unknown reloc type: %x\n", + type); + return -1; + } + num_relocs--; + reloc++; + } + + /* Track consumption of relocation directory contents. */ + relocd_offset += relocb->SizeOfBlock; + /* Get next relocation block to process. */ + relocb = relative_offset(relocb, relocb->SizeOfBlock); + } + + return 0; +} + +static size_t csh_size(const EFI_COMMON_SECTION_HEADER *csh) +{ + size_t size; + + /* Unpack the array into a type that can be used. */ + size = 0; + size |= csh->Size[0] << 0; + size |= csh->Size[1] << 8; + size |= csh->Size[2] << 16; + + return size; +} + +static size_t section_data_offset(const EFI_COMMON_SECTION_HEADER *csh) +{ + if (csh_size(csh) == 0x00ffffff) + return sizeof(EFI_COMMON_SECTION_HEADER2); + else + return sizeof(EFI_COMMON_SECTION_HEADER); +} + +static size_t section_data_size(const EFI_COMMON_SECTION_HEADER *csh) +{ + size_t section_size; + + if (csh_size(csh) == 0x00ffffff) + section_size = SECTION2_SIZE(csh); + else + section_size = csh_size(csh); + + return section_size - section_data_offset(csh); +} + +static size_t file_section_offset(const EFI_FFS_FILE_HEADER *ffsfh) +{ + if (IS_FFS_FILE2(ffsfh)) + return sizeof(EFI_FFS_FILE_HEADER2); + else + return sizeof(EFI_FFS_FILE_HEADER); +} + +static size_t ffs_file_size(const EFI_FFS_FILE_HEADER *ffsfh) +{ + size_t size; + + if (IS_FFS_FILE2(ffsfh)) + size = FFS_FILE2_SIZE(ffsfh); + else { + size = ffsfh->Size[0] << 0; + size |= ffsfh->Size[1] << 8; + size |= ffsfh->Size[2] << 16; + } + return size; +} + +static int relocate_patch_table(void *fsp, size_t size, size_t offset, + ssize_t adjustment) +{ + struct fsp_patch_table *table; + uint32_t num; + + table = relative_offset(fsp, offset); + + if ((offset + sizeof(*table) > size) || + (table->header_length + offset) > size) { + printk(BIOS_ERR, "FSPP not entirely contained in region.\n"); + return -1; + } + + printk(FSP_DBG_LVL, "FSPP relocs: %x\n", table->patch_entry_num); + + for (num = 0; num < table->patch_entry_num; num++) { + uint32_t *reloc; + + reloc = fspp_reloc(fsp, size, table->patch_entries[num]); + + if (reloc == NULL) { + printk(BIOS_ERR, "Ignoring FSPP entry: %x\n", + table->patch_entries[num]); + continue; + } + + printk(FSP_DBG_LVL, "Adjusting %p %x -> %x\n", + reloc, *reloc, (unsigned int)(*reloc + adjustment)); + + *reloc += adjustment; + } + + return 0; +} + +static void *relocate_remaining_items(void *fsp, size_t size, size_t fih_offset) +{ + EFI_FFS_FILE_HEADER *ffsfh; + EFI_COMMON_SECTION_HEADER *csh; + FSP_INFO_HEADER *fih; + ssize_t adjustment; + size_t offset; + + printk(FSP_DBG_LVL, "FSP_INFO_HEADER offset is %zx\n", fih_offset); + + if (fih_offset == 0) { + printk(BIOS_ERR, "FSP_INFO_HEADER offset is 0.\n"); + return NULL; + } + + /* FSP_INFO_HEADER at first file in FV within first RAW section. */ + ffsfh = relative_offset(fsp, fih_offset); + fih_offset += file_section_offset(ffsfh); + csh = relative_offset(fsp, fih_offset); + fih_offset += section_data_offset(csh); + fih = relative_offset(fsp, fih_offset); + + if (memcmp(&ffsfh->Name, &fih_guid, sizeof(fih_guid))) { + printk(BIOS_ERR, "Bad FIH GUID.\n"); + return NULL; + } + + if (csh->Type != EFI_SECTION_RAW) { + printk(BIOS_ERR, "FIH file should have raw section: %x\n", + csh->Type); + return NULL; + } + + if (fih->Signature != FSP_SIG) { + printk(BIOS_ERR, "Unexpected FIH signature: %08x\n", + fih->Signature); + return NULL; + } + + adjustment = (intptr_t)fsp - fih->ImageBase; + + /* Update ImageBase to reflect FSP's new home. */ + fih->ImageBase += adjustment; + + /* Need to find patch table and adjust each entry. The tables + * following FSP_INFO_HEADER have a 32-bit signature and header + * length. The patch table is denoted as having a 'FSPP' signature; + * the table format doesn't follow the other tables. */ + offset = fih_offset + fih->HeaderLength; + while (offset + 2 * sizeof(uint32_t) <= size) { + uint32_t *table_headers; + + table_headers = relative_offset(fsp, offset); + + printk(FSP_DBG_LVL, "Checking offset %zx for 'FSPP'\n", + offset); + + if (table_headers[0] != FSPP_SIG) { + offset += table_headers[1]; + continue; + } + + if (relocate_patch_table(fsp, size, offset, adjustment)) { + printk(BIOS_ERR, "FSPP relocation failed.\n"); + return NULL; + } + + return fih; + } + + printk(BIOS_ERR, "Could not find the FSP patch table.\n"); + return NULL; +} + +static FSP_INFO_HEADER *fsp_relocate_in_place(void *fsp, size_t size) +{ + EFI_FIRMWARE_VOLUME_HEADER *fvh; + EFI_FFS_FILE_HEADER *ffsfh; + EFI_COMMON_SECTION_HEADER *csh; + size_t offset; + size_t file_offset; + size_t fih_offset; + + fih_offset = 0; + offset = 0; + fvh = fsp; + + if (fvh->Signature != EFI_FVH_SIGNATURE) + return NULL; + + printk(FSP_DBG_LVL, "FVH length: %zx Mapping length: %zx\n", + (size_t)fvh->FvLength, size); + + if (fvh->FvLength != size) + return NULL; + + if (memcmp(&fvh->FileSystemGuid, &ffs2_guid, sizeof(ffs2_guid))) { + printk(BIOS_ERR, "FVH not an FFS2 type.\n"); + return NULL; + } + + if (fvh->ExtHeaderOffset != 0) { + EFI_FIRMWARE_VOLUME_EXT_HEADER *fveh; + + offset += fvh->ExtHeaderOffset; + fveh = relative_offset(fsp, offset); + printk(FSP_DBG_LVL, "Extended Header Offset: %zx Size: %zx\n", + (size_t)fvh->ExtHeaderOffset, + (size_t)fveh->ExtHeaderSize); + offset += fveh->ExtHeaderSize; + /* FFS files are 8 byte aligned after extended header. */ + offset = ALIGN_UP(offset, 8); + } else { + offset += fvh->HeaderLength; + } + + file_offset = offset; + while (file_offset + sizeof(*ffsfh) < size) { + offset = file_offset; + printk(FSP_DBG_LVL, "file offset: %zx\n", file_offset); + + /* First file and section should be FSP info header. */ + if (fih_offset == 0) + fih_offset = file_offset; + + ffsfh = relative_offset(fsp, file_offset); + + printk(FSP_DBG_LVL, "file type = %x\n", ffsfh->Type); + printk(FSP_DBG_LVL, "file attribs = %x\n", ffsfh->Attributes); + + /* Next file on 8 byte alignment. */ + file_offset += ffs_file_size(ffsfh); + file_offset = ALIGN_UP(file_offset, 8); + + /* Padding files have no section information. */ + if (ffsfh->Type == EFI_FV_FILETYPE_FFS_PAD) + continue; + + offset += file_section_offset(ffsfh); + + while (offset + sizeof(*csh) < file_offset) { + size_t data_size; + size_t data_offset; + + csh = relative_offset(fsp, offset); + + printk(FSP_DBG_LVL, "section offset: %zx\n", offset); + printk(FSP_DBG_LVL, "section type: %x\n", csh->Type); + + data_size = section_data_size(csh); + data_offset = section_data_offset(csh); + + if (data_size + data_offset + offset > file_offset) { + printk(BIOS_ERR, "Section exceeds FV size.\n"); + return NULL; + } + + if (csh->Type == EFI_SECTION_TE) { + void *te; + size_t te_offset = offset + data_offset; + + printk(FSP_DBG_LVL, "TE image at offset %zx\n", + te_offset); + te = relative_offset(fsp, te_offset); + te_relocate_in_place(te, data_size); + } + + offset += data_size + data_offset; + /* Sections are aligned to 4 bytes. */ + offset = ALIGN_UP(offset, 4); + } + } + + return relocate_remaining_items(fsp, size, fih_offset); +} + +FSP_INFO_HEADER *fsp_relocate(void *fsp_src, size_t size) +{ + void *new_loc; + + new_loc = cbmem_add(CBMEM_ID_REFCODE, size); + if (new_loc == NULL) { + printk(BIOS_ERR, "Unable to load FSP into memory.\n"); + return NULL; + } + memcpy(new_loc, fsp_src, size); + return fsp_relocate_in_place(new_loc, size); +} diff --git a/src/drivers/intel/fsp1_1/fsp_util.c b/src/drivers/intel/fsp1_1/fsp_util.c new file mode 100644 index 0000000..9fa4ac4 --- /dev/null +++ b/src/drivers/intel/fsp1_1/fsp_util.c @@ -0,0 +1,252 @@ +/* + * 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 <bootstate.h> +#include <cbmem.h> +#include <console/console.h> +#include "fsp_util.h" +#include <timestamp.h> + +/* Locate the FSP binary in the coreboot filesystem */ +FSP_INFO_HEADER *find_fsp(void) +{ + union { + EFI_FFS_FILE_HEADER *ffh; + FSP_INFO_HEADER *fih; + EFI_FIRMWARE_VOLUME_EXT_HEADER *fveh; + EFI_FIRMWARE_VOLUME_HEADER *fvh; + EFI_RAW_SECTION *rs; + u8 *u8; + u32 u32; + } fsp_ptr; + u32 *image_id; + +#ifndef CONFIG_FSP_LOC +#error "CONFIG_FSP_LOC must be set." +#endif + + for (;;) { + /* Get the FSP binary base address in CBFS */ + fsp_ptr.u8 = (u8 *)CONFIG_FSP_LOC; + + /* Check the FV signature, _FVH */ + if (fsp_ptr.fvh->Signature != 0x4856465F) { + fsp_ptr.u8 = (u8 *)ERROR_NO_FV_SIG; + break; + } + + /* Locate the file header which follows the FV header. */ + fsp_ptr.u8 += fsp_ptr.fvh->ExtHeaderOffset; + fsp_ptr.u8 += fsp_ptr.fveh->ExtHeaderSize; + fsp_ptr.u8 = (u8 *)((fsp_ptr.u32 + 7) & 0xFFFFFFF8); + + /* Check the FFS GUID */ + if ((((u32 *)&fsp_ptr.ffh->Name)[0] != 0x912740BE) + || (((u32 *)&fsp_ptr.ffh->Name)[1] != 0x47342284) + || (((u32 *)&fsp_ptr.ffh->Name)[2] != 0xB08471B9) + || (((u32 *)&fsp_ptr.ffh->Name)[3] != 0x0C3F3527)) { + fsp_ptr.u8 = (u8 *)ERROR_NO_FFS_GUID; + break; + } + + /* Locate the Raw Section Header */ + fsp_ptr.u8 += sizeof(EFI_FFS_FILE_HEADER); + + if (fsp_ptr.rs->Type != EFI_SECTION_RAW) { + fsp_ptr.u8 = (u8 *)ERROR_NO_INFO_HEADER; + break; + } + + /* Locate the FSP INFO Header which follows the Raw Header. */ + fsp_ptr.u8 += sizeof(EFI_RAW_SECTION); + + /* Verify that the FSP base address.*/ + if (fsp_ptr.fih->ImageBase != CONFIG_FSP_LOC) { + fsp_ptr.u8 = (u8 *)ERROR_IMAGEBASE_MISMATCH; + break; + } + + /* Verify the FSP Signature */ + if (fsp_ptr.fih->Signature != FSP_SIG) { + fsp_ptr.u8 = (u8 *)ERROR_INFO_HEAD_SIG_MISMATCH; + break; + } + + /* Verify the FSP ID */ + image_id = (u32 *)&fsp_ptr.fih->ImageId[0]; + if ((image_id[0] != CONFIG_FSP_IMAGE_ID_DWORD0) + || (image_id[1] != CONFIG_FSP_IMAGE_ID_DWORD1)) + fsp_ptr.u8 = (u8 *)ERROR_FSP_SIG_MISMATCH; + break; + } + + return fsp_ptr.fih; +} + +void print_fsp_info(FSP_INFO_HEADER *fsp_header) +{ + u8 *fsp_base; + + fsp_base = (u8 *)fsp_header->ImageBase; + printk(BIOS_SPEW, "FSP_INFO_HEADER: %p\n", fsp_header); + printk(BIOS_INFO, "FSP Signature: %c%c%c%c%c%c%c%c\n", + fsp_header->ImageId[0], fsp_header->ImageId[1], + fsp_header->ImageId[2], fsp_header->ImageId[3], + fsp_header->ImageId[4], fsp_header->ImageId[5], + fsp_header->ImageId[6], fsp_header->ImageId[7]); + printk(BIOS_INFO, "FSP Header Version: %d\n", + fsp_header->HeaderRevision); + printk(BIOS_INFO, "FSP Revision: %d.%d\n", + (u8)((fsp_header->ImageRevision >> 8) & 0xff), + (u8)(fsp_header->ImageRevision & 0xff)); +#if IS_ENABLED(CONFIG_DISPLAY_FSP_ENTRY_POINTS) + printk(BIOS_SPEW, "FSP Entry Points:\n"); + printk(BIOS_SPEW, " 0x%p: Image Base\n", fsp_base); + printk(BIOS_SPEW, " 0x%p: TempRamInit\n", + &fsp_base[fsp_header->TempRamInitEntryOffset]); + printk(BIOS_SPEW, " 0x%p: FspInit\n", + &fsp_base[fsp_header->FspInitEntryOffset]); + if (fsp_header->HeaderRevision >= FSP_HEADER_REVISION_2) { + printk(BIOS_SPEW, " 0x%p: MemoryInit\n", + &fsp_base[fsp_header->FspMemoryInitEntryOffset]); + printk(BIOS_SPEW, " 0x%p: TempRamExit\n", + &fsp_base[fsp_header->TempRamExitEntryOffset]); + printk(BIOS_SPEW, " 0x%p: SiliconInit\n", + &fsp_base[fsp_header->FspSiliconInitEntryOffset]); + } + printk(BIOS_SPEW, " 0x%p: NotifyPhase\n", + &fsp_base[fsp_header->NotifyPhaseEntryOffset]); + printk(BIOS_SPEW, " 0x%p: Image End\n", + &fsp_base[fsp_header->ImageSize]); +#endif +} + +#ifndef __PRE_RAM__ + +void fsp_notify(u32 phase) +{ + FSP_NOTIFY_PHASE notify_phase_proc; + NOTIFY_PHASE_PARAMS notify_phase_params; + EFI_STATUS status; + FSP_INFO_HEADER *fsp_header_ptr; + + fsp_header_ptr = fsp_get_fih(); + if (fsp_header_ptr == NULL) { + fsp_header_ptr = (void *)find_fsp(); + if ((u32)fsp_header_ptr < 0xff) { + /* output something in case there is no serial */ + post_code(0x4F); + die("Can't find the FSP!\n"); + } + } + + /* call FSP PEI to Notify PostPciEnumeration */ + notify_phase_proc = (FSP_NOTIFY_PHASE)(fsp_header_ptr->ImageBase + + fsp_header_ptr->NotifyPhaseEntryOffset); + notify_phase_params.Phase = phase; + + timestamp_add_now(phase == EnumInitPhaseReadyToBoot ? + TS_FSP_BEFORE_FINALIZE : TS_FSP_BEFORE_ENUMERATE); + + status = notify_phase_proc(¬ify_phase_params); + + 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); +} + +static void fsp_notify_boot_state_callback(void *arg) +{ + u32 phase = (u32)arg; + + printk(BIOS_SPEW, "Calling FspNotify(0x%08x)\n", phase); + fsp_notify(phase); +} + +BOOT_STATE_INIT_ENTRIES(fsp_bscbs) = { + BOOT_STATE_INIT_ENTRY(BS_DEV_RESOURCES, BS_ON_EXIT, + fsp_notify_boot_state_callback, + (void *)EnumInitPhaseAfterPciEnumeration), + BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_LOAD, BS_ON_EXIT, + fsp_notify_boot_state_callback, + (void *)EnumInitPhaseReadyToBoot), + BOOT_STATE_INIT_ENTRY(BS_OS_RESUME, BS_ON_ENTRY, + fsp_notify_boot_state_callback, + (void *)EnumInitPhaseReadyToBoot) +}; + +#endif /* #ifndef __PRE_RAM__ */ + +struct fsp_runtime { + uint32_t fih; + uint32_t hob_list; +} __attribute__((packed)); + + +void fsp_set_runtime(FSP_INFO_HEADER *fih, void *hob_list) +{ + struct fsp_runtime *fspr; + + fspr = cbmem_add(CBMEM_ID_FSP_RUNTIME, sizeof(*fspr)); + + if (fspr == NULL) + die("Can't save FSP runtime information.\n"); + + fspr->fih = (uintptr_t)fih; + fspr->hob_list = (uintptr_t)hob_list; +} + +FSP_INFO_HEADER *fsp_get_fih(void) +{ + struct fsp_runtime *fspr; + + fspr = cbmem_find(CBMEM_ID_FSP_RUNTIME); + + if (fspr == NULL) + return NULL; + + return (void *)(uintptr_t)fspr->fih; +} + +void *fsp_get_hob_list(void) +{ + struct fsp_runtime *fspr; + + fspr = cbmem_find(CBMEM_ID_FSP_RUNTIME); + + if (fspr == NULL) + return NULL; + + return (void *)(uintptr_t)fspr->hob_list; +} + +void fsp_update_fih(FSP_INFO_HEADER *fih) +{ + struct fsp_runtime *fspr; + + fspr = cbmem_find(CBMEM_ID_FSP_RUNTIME); + + if (fspr == NULL) + die("Can't update FSP runtime information.\n"); + + fspr->fih = (uintptr_t)fih; +} diff --git a/src/drivers/intel/fsp1_1/fsp_util.h b/src/drivers/intel/fsp1_1/fsp_util.h new file mode 100644 index 0000000..4e65bac --- /dev/null +++ b/src/drivers/intel/fsp1_1/fsp_util.h @@ -0,0 +1,122 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013-2014 Sage Electronic Engineering, LLC. + * Copyright (C) 2015 Intel Corp. + * + * 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 <types.h> +#include <arch/cpu.h> +#include <fsp_gop.h> + +/* + * The following are functions with prototypes defined in the EDK2 headers. The + * EDK2 headers are included with chipset_fsp_util.h. Define the following + * names to reduce the use of CamelCase in the other source files. + */ +#define GetHobList get_hob_list +#define GetNextHob get_next_hob +#define GetFirstHob get_first_hob +#define GetNextGuidHob get_next_guid_hob +#define GetFirstGuidHob get_first_guid_hob + +/* Include the EDK2 headers */ +#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 + +/* find_fsp() should only be called from assembly code. */ +FSP_INFO_HEADER *find_fsp(void); +/* Set FSP's runtime information. */ +void fsp_set_runtime(FSP_INFO_HEADER *fih, void *hob_list); +/* Use a new FSP_INFO_HEADER at runtime. */ +void fsp_update_fih(FSP_INFO_HEADER *fih); +/* fsp_get_fih() is only valid after calling fsp_set_runtime(). */ +FSP_INFO_HEADER *fsp_get_fih(void); +/* fsp_get_hob_list() is only valid after calling fsp_set_runtime(). */ +void *fsp_get_hob_list(void); +void fsp_early_init(FSP_INFO_HEADER *fsp_info); +void fsp_notify(u32 phase); +void print_hob_type_structure(u16 hob_type, void *hob_list_ptr); +void print_fsp_info(FSP_INFO_HEADER *fsp_header); +void *get_next_type_guid_hob(UINT16 type, const EFI_GUID *guid, + const void *hob_start); +void *get_next_resource_hob(const EFI_GUID *guid, const void *hob_start); +void *get_first_resource_hob(const EFI_GUID *guid); +/* + * Relocate FSP entire binary into ram. Returns NULL on error. Otherwise the + * FSP_INFO_HEADER pointer to the relocated FSP. + */ +FSP_INFO_HEADER *fsp_relocate(void *fsp_src, size_t size); + +/* 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); + +void update_mrc_cache(void *unused); + +#endif /* CONFIG_ENABLE_MRC_CACHE */ + +/* 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 */