diff options
author | Lee Leahy <leroy.p.leahy@intel.com> | 2015-04-20 15:29:16 -0700 |
---|---|---|
committer | Leroy P Leahy <leroy.p.leahy@intel.com> | 2015-05-23 01:33:31 +0200 |
commit | b5ad827ee584a960212ae983e30cd1a0b18c55a5 (patch) | |
tree | 915ca1f01080073fe24007c0903bf04c33378699 | |
parent | 65ff63f5ea70ca08d451d8e25791bf1200ce8c11 (diff) |
drivers/intel: Update FSP 1.1 Driver
Update the FSP driver files from 1.0 to 1.1.
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>
Reviewed-on: http://review.coreboot.org/10049
Tested-by: build bot (Jenkins)
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
-rw-r--r-- | src/drivers/intel/Kconfig | 1 | ||||
-rw-r--r-- | src/drivers/intel/Makefile.inc | 1 | ||||
-rw-r--r-- | src/drivers/intel/fsp1_1/Kconfig | 159 | ||||
-rw-r--r-- | src/drivers/intel/fsp1_1/Makefile.inc | 34 | ||||
-rw-r--r-- | src/drivers/intel/fsp1_1/cache_as_ram.inc | 268 | ||||
-rw-r--r-- | src/drivers/intel/fsp1_1/fastboot_cache.c | 45 | ||||
-rw-r--r-- | src/drivers/intel/fsp1_1/fsp_gop.c | 101 | ||||
-rw-r--r-- | src/drivers/intel/fsp1_1/fsp_gop.h (renamed from src/drivers/intel/fsp1_1/fsp_values.h) | 33 | ||||
-rw-r--r-- | src/drivers/intel/fsp1_1/fsp_relocate.c | 496 | ||||
-rw-r--r-- | src/drivers/intel/fsp1_1/fsp_util.c | 449 | ||||
-rw-r--r-- | src/drivers/intel/fsp1_1/fsp_util.h | 110 | ||||
-rw-r--r-- | src/drivers/intel/fsp1_1/hob.c | 560 |
12 files changed, 1600 insertions, 657 deletions
diff --git a/src/drivers/intel/Kconfig b/src/drivers/intel/Kconfig index 0f2d27eb47..a37ab739d6 100644 --- a/src/drivers/intel/Kconfig +++ b/src/drivers/intel/Kconfig @@ -17,5 +17,6 @@ ## Foundation, Inc. ## +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 dc947ff4f0..3ddb05fb20 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 index d2e144f31c..a6d34eef6f 100644 --- a/src/drivers/intel/fsp1_1/Kconfig +++ b/src/drivers/intel/fsp1_1/Kconfig @@ -17,18 +17,14 @@ ## Foundation, Inc. ## -if PLATFORM_USES_FSP1_0 - comment "Intel FSP" -config HAVE_FSP_BIN +config PLATFORM_USES_FSP1_1 bool "Use Intel Firmware Support Package" help - Select this option to add an Intel FSP binary to - the resulting coreboot image. + Does the code require the Intel Firmware Support Package? - Note: Without this binary, coreboot builds relying on the FSP - will not boot +if PLATFORM_USES_FSP1_1 config DCACHE_RAM_BASE hex @@ -38,13 +34,61 @@ 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 @@ -52,23 +96,27 @@ config FSP_LOC 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" - select ENABLE_MRC_CACHE - default n +config MRC_CACHE_FILE + string "File containing the cached MRC values" 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. + The path and filename of the cached MRC values. -config ENABLE_MRC_CACHE - bool - default y if HAVE_ACPI_RESUME - default n +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 - 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. + 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" @@ -88,23 +136,6 @@ config OVERRIDE_CACHE_CACHE_LOC 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 @@ -126,20 +157,54 @@ config CACHE_ROM_SIZE_OVERRIDE 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. + 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 +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 - The chipset can select this to use a generic cache_as_ram.inc file - that should be good for all FSP based platforms. + 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. -endif #PLATFORM_USES_FSP1_0 + If this FSP uses UPD/VPD data regions, select this in the chipset + Kconfig. + +config GOP_SUPPORT + bool "Enable GOP support" + default y + +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 index a29bf32136..9bb3fc4842 100644 --- a/src/drivers/intel/fsp1_1/Makefile.inc +++ b/src/drivers/intel/fsp1_1/Makefile.inc @@ -2,6 +2,7 @@ # 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 @@ -17,18 +18,29 @@ # Foundation, Inc. # -ramstage-y += fsp_util.c hob.c -romstage-y += fsp_util.c hob.c +romstage-$(CONFIG_ENABLE_MRC_CACHE) += fastboot_cache.c +romstage-$(CONFIG_GOP_SUPPORT) += fsp_gop.c +romstage-y += fsp_util.c +romstage-y += hob.c ramstage-$(CONFIG_ENABLE_MRC_CACHE) += fastboot_cache.c -romstage-$(CONFIG_ENABLE_MRC_CACHE) += fastboot_cache.c +ramstage-$(CONFIG_GOP_SUPPORT) += fsp_gop.c +ramstage-y += fsp_relocate.c +ramstage-y += fsp_util.c +ramstage-y += hob.c -CPPFLAGS_common += -Isrc/drivers/intel/fsp1_0 +CPPFLAGS_common += -Isrc/drivers/intel/fsp1_1 + +cpu_incs-$(CONFIG_USE_GENERIC_FSP_CAR_INC) += $(src)/drivers/intel/fsp1_1/cache_as_ram.inc -ifeq ($(CONFIG_USE_GENERIC_FSP_CAR_INC),y) -cpu_incs += $(src)/drivers/intel/fsp1_0/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)) @@ -36,14 +48,16 @@ fsp.bin-position := $(CONFIG_FSP_LOC) fsp.bin-type := fsp endif -ifeq ($(CONFIG_ENABLE_MRC_CACHE),y) + +# 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 := $(obj)/mrc.cache +mrc.cache-file := $(call strip_quotes,$(CONFIG_MRC_CACHE_FILE)) mrc.cache-position := $(CONFIG_MRC_CACHE_LOC) -mrc.cache-type := mrc_cache +mrc.cache-type := CBFS_TYPE_MRC_CACHE endif diff --git a/src/drivers/intel/fsp1_1/cache_as_ram.inc b/src/drivers/intel/fsp1_1/cache_as_ram.inc index 941da3bdf9..4a0827d2df 100644 --- a/src/drivers/intel/fsp1_1/cache_as_ram.inc +++ b/src/drivers/intel/fsp1_1/cache_as_ram.inc @@ -4,6 +4,7 @@ * 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 @@ -19,10 +20,17 @@ * Foundation, Inc. */ +/* + * Replacement for cache_as_ram.inc when using the FSP binary. 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/mtrr.h> #include <cpu/x86/cache.h> #include <cpu/x86/post_code.h> -#include <microcode_size.h> #include <cbmem.h> #ifndef CONFIG_FSP_LOC @@ -33,7 +41,7 @@ # error "CONFIG_POST_IO must be set." #endif -#if CONFIG_POST_IO +#if IS_ENABLED(CONFIG_POST_IO) # ifndef CONFIG_POST_IO_PORT # error "CONFIG_POST_IO_PORT must be set." # endif @@ -45,79 +53,216 @@ #define LHLT_DELAY 0x50000 /* I/O delay between post codes on failure */ - cmp $0, %eax - jne bisthalt + /* + * 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 + 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 + 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 the FSP base address */ + 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 + 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 + jmp *%eax CAR_init_done: - addl $4, %esp - cmp $0, %eax - jne halt2 + 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 + mov %ebp, %ebx /* - * set up bootloader stack - * ecx: stack base - * edx: stack top + * 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 */ - mov %edx, %esp - movl %esp, %ebp - /* Clear the cbmem CAR memory region. */ - movl %ecx, %edi - movl %edx, %ecx - sub %edi, %ecx - shr $2, %ecx - xorl %eax, %eax - rep stosl + /* Frame for romstage_main(bist, tsc_low, tsc_hi, fih) */ + pushl %ebx + 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. */ - pushl %ebx /* main takes FSP_INFO_HEADER as its argument */ - call main /* does not return */ - movb $0xB8, %ah - jmp .Lhlt + 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) -bisthalt: - movb $0xB9, %ah - jmp .Lhlt + /* 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() + * Failures for postcode 0xBA - failed in fsp_fih_early_find() * * Values are: * 0x01 - FV signature, "_FVH" not present @@ -128,8 +273,8 @@ halt1: * 0x05 - FSP INFO Header signature "FSPH" not found * 0x06 - FSP Image ID is not the expected ID. */ - movb $0xBA, %ah - jmp .Lhlt + movb $0xBA, %ah + jmp .Lhlt halt2: /* @@ -137,25 +282,37 @@ halt2: * * 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 + * 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 + 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 CONFIG_POST_IO - outb %al, $CONFIG_POST_IO_PORT + 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 + movl $LHLT_DELAY, %ecx .Lhlt_Delay: - outb %al, $0xED - loop .Lhlt_Delay - jmp .Lhlt + outb %al, $0xED + loop .Lhlt_Delay + jmp .Lhlt /* * esp is set to this location so that the call into and return from the FSP @@ -163,15 +320,14 @@ halt2: */ .align 4 fake_fsp_stack: - .long find_fsp_ret + .long find_fsp_ret CAR_init_params: - .long CONFIG_CPU_MICROCODE_CBFS_LOC - .long MICROCODE_REGION_LENGTH - .long 0xFFFFFFFF - CACHE_ROM_SIZE + 1 /* Firmware Location */ - .long CACHE_ROM_SIZE /* Total Firmware Length */ + .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 - + .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 index 306359eafc..a0d15c4769 100644 --- a/src/drivers/intel/fsp1_1/fastboot_cache.c +++ b/src/drivers/intel/fsp1_1/fastboot_cache.c @@ -3,6 +3,7 @@ * * Copyright (C) 2012 Google Inc. * 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 @@ -18,26 +19,23 @@ * Foundation, Inc. */ -#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 <console/console.h> #include "fsp_util.h" +#include <ip_checksum.h> +#include <lib.h> // hexdump +#include <spi_flash.h> +#include <string.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 inline u32 to_flash_offset(void *p) +{ + return (u32)p + CONFIG_VIRTUAL_ROM_SIZE; } static struct mrc_data_container *next_mrc_block( @@ -50,14 +48,15 @@ static struct mrc_data_container *next_mrc_block( mrc_size += MRC_DATA_ALIGN; } - u8 *region_ptr = (u8*)mrc_cache; + 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); + return (!!mrc_cache) + && (mrc_cache->mrc_signature == MRC_DATA_SIGNATURE); } static u32 get_mrc_cache_region(struct mrc_data_container **mrc_region_ptr) @@ -96,7 +95,8 @@ static struct mrc_data_container *find_current_mrc_cache_local } if (entry_id == 0) { - printk(BIOS_ERR, "%s: No valid fast boot cache found.\n", __func__); + printk(BIOS_ERR, "%s: No valid fast boot cache found.\n", + __func__); return NULL; } @@ -104,7 +104,8 @@ static struct mrc_data_container *find_current_mrc_cache_local 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__); + printk(BIOS_ERR, "%s: fast boot cache checksum mismatch\n", + __func__); return NULL; } @@ -117,7 +118,7 @@ static struct mrc_data_container *find_current_mrc_cache_local /* SPI code needs malloc/free. * Also unknown if writing flash from XIP-flash code is a good idea */ -#if !defined(__PRE_RAM__) +#if ENV_RAMSTAGE /* find the first empty block in the MRC cache area. * If there's none, return NULL. * @@ -164,6 +165,7 @@ void update_mrc_cache(void *unused) 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", @@ -218,19 +220,21 @@ void update_mrc_cache(void *unused) current->mrc_data_size + sizeof(*current), current); } -#endif /* !defined(__PRE_RAM__) */ +#endif /* ENV_RAMSTAGE */ -void * find_and_set_fastboot_cache(void) +void *find_and_set_fastboot_cache(void) { struct mrc_data_container *mrc_cache = NULL; - if (((mrc_cache = find_current_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) / 4); + hexdump32(BIOS_SPEW, (void *)mrc_cache->mrc_data, + mrc_cache->mrc_data_size); return (void *) mrc_cache->mrc_data; } @@ -239,6 +243,7 @@ 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", 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 0000000000..cf781cdea7 --- /dev/null +++ b/src/drivers/intel/fsp1_1/fsp_gop.c @@ -0,0 +1,101 @@ +/* + * 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_INFO, + "FSP_INFO: VBT data file (vbt.bin) not found in CBFS"); + return NULL; + } + + /* Validate the vbt file */ + vbt.data = CBFS_SUBHEADER(vbt_file); + if (*vbt.signature != VBT_SIGNATURE) { + printk(BIOS_WARNING, + "FSP_WARNING: Invalid signature in VBT data file (vbt.bin)!\n"); + return NULL; + } + *vbt_len = ntohl(vbt_file->len); + printk(BIOS_DEBUG, "FSP_INFO: 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; +} + +#if ENV_RAMSTAGE +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_ERR, "FSP_ERR: Graphics Data HOB is not present\n"); + return; + } else { + printk(BIOS_DEBUG, "FSP_DEBUG: Graphics Data HOB 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 /* ENV_RAMSTAGE */ diff --git a/src/drivers/intel/fsp1_1/fsp_values.h b/src/drivers/intel/fsp1_1/fsp_gop.h index 1e83d401aa..fc259014e3 100644 --- a/src/drivers/intel/fsp1_1/fsp_values.h +++ b/src/drivers/intel/fsp1_1/fsp_gop.h @@ -1,7 +1,7 @@ /* * 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 @@ -17,25 +17,18 @@ * Foundation, Inc. */ -#ifndef FSP_VALUES_H -#define FSP_VALUES_H +#ifndef _FSP_GOP_H_ +#define _FSP_GOP_H_ -#ifndef FSP_DEBUG_LEVEL -# define FSP_DEBUG_LEVEL BIOS_SPEW -#endif +/* GOP support */ +#if IS_ENABLED(CONFIG_GOP_SUPPORT) -#ifndef FSP_INFO_LEVEL -# define FSP_INFO_LEVEL BIOS_DEBUG -#endif +#include <boot/coreboot_tables.h> +#include <soc/intel/common/gma.h> -#define INCREMENT_FOR_DEFAULT(x) (x+1) - -#define UPD_DEFAULT 0x00 -#define UPD_DISABLE INCREMENT_FOR_DEFAULT(0) -#define UPD_ENABLE INCREMENT_FOR_DEFAULT(1) -#define UPD_USE_DEVICETREE 0xff - -#define UPD_SPD_ADDR_DEFAULT UPD_DEFAULT -#define UPD_SPD_ADDR_DISABLED 0xFF - -#endif +const optionrom_vbt_t *fsp_get_vbt(uint32_t *vbt_len); +#if ENV_RAMSTAGE +void fsp_gop_framebuffer(struct lb_header *header); +#endif /* ENV_RAMSTAGE */ +#endif /* CONFIG_GOP_SUPPORT */ +#endif /* _FSP_GOP_H_ */ 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 0000000000..08e1eb82f0 --- /dev/null +++ b/src/drivers/intel/fsp1_1/fsp_relocate.c @@ -0,0 +1,496 @@ +/* + * 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. */ + teih->ImageBase = (uint32_t)(teih->ImageBase + adj); + + 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 ssize_t relocate_fvh(void *fsp, size_t fsp_size, size_t fvh_offset, + size_t *fih_offset) +{ + EFI_FIRMWARE_VOLUME_HEADER *fvh; + EFI_FFS_FILE_HEADER *ffsfh; + EFI_COMMON_SECTION_HEADER *csh; + size_t offset; + size_t file_offset; + size_t size; + + offset = fvh_offset; + fvh = relative_offset(fsp, offset); + + if (fvh->Signature != EFI_FVH_SIGNATURE) + return -1; + + printk(FSP_DBG_LVL, "FVH length: %zx Offset: %zx Mapping length: %zx\n", + (size_t)fvh->FvLength, offset, fsp_size); + + if (fvh->FvLength + offset > fsp_size) + return -1; + + /* Parse only this FV. However, the algorithm uses offsets into the + * entire FSP region so make size include the starting offset. */ + size = fvh->FvLength + offset; + + if (memcmp(&fvh->FileSystemGuid, &ffs2_guid, sizeof(ffs2_guid))) { + printk(BIOS_ERR, "FVH not an FFS2 type.\n"); + return -1; + } + + 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 != NULL && *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); + + /* Exit FV relocation when empty space found */ + if (ffsfh->Type == EFI_FV_FILETYPE_FFS_MAX) + break; + + /* 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 -1; + } + + 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 amount of buffer parsed: FV size. */ + return fvh->FvLength; +} + +static FSP_INFO_HEADER *fsp_relocate_in_place(void *fsp, size_t size) +{ + size_t offset; + size_t fih_offset; + + offset = 0; + fih_offset = 0; + while (offset < size) { + ssize_t nparsed; + + /* Relocate each FV within the FSP region. The FSP_INFO_HEADER + * should only be located in the first FV. */ + if (offset == 0) + nparsed = relocate_fvh(fsp, size, offset, &fih_offset); + else + nparsed = relocate_fvh(fsp, size, offset, NULL); + + /* FV should be larger than 0 or failed to parse. */ + if (nparsed <= 0) { + printk(BIOS_ERR, "FV @ offset %zx relocation failed\n", + offset); + return NULL; + } + + offset += nparsed; + } + + 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 index 9dbd50278e..51ddc67de3 100644 --- a/src/drivers/intel/fsp1_1/fsp_util.c +++ b/src/drivers/intel/fsp1_1/fsp_util.c @@ -2,6 +2,7 @@ * 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 @@ -17,336 +18,234 @@ * Foundation, Inc. */ -#include <types.h> -#include <string.h> -#include <console/console.h> #include <bootstate.h> #include <cbmem.h> +#include <console/console.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) +/* Locate the FSP binary in the coreboot filesystem */ +FSP_INFO_HEADER *find_fsp(void) { - 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; + 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; - timestamp_add_now(Phase == EnumInitPhaseReadyToBoot ? - TS_FSP_BEFORE_FINALIZE : TS_FSP_BEFORE_ENUMERATE); +#ifndef CONFIG_FSP_LOC +#error "CONFIG_FSP_LOC must be set." +#endif - Status = NotifyPhaseProc (&NotifyPhaseParams); + for (;;) { + /* Get the FSP binary base address in CBFS */ + fsp_ptr.u8 = (u8 *)CONFIG_FSP_LOC; - timestamp_add_now(Phase == EnumInitPhaseReadyToBoot ? - TS_FSP_AFTER_FINALIZE : TS_FSP_AFTER_ENUMERATE); + /* Check the FV signature, _FVH */ + if (fsp_ptr.fvh->Signature != 0x4856465F) { + fsp_ptr.u8 = (u8 *)ERROR_NO_FV_SIG; + break; + } - 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__ */ + /* 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; + } -#ifdef __PRE_RAM__ + /* Locate the Raw Section Header */ + fsp_ptr.u8 += sizeof(EFI_FFS_FILE_HEADER); -/* - * 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 *)CONFIG_RAMTOP; - FspInitParams.NvsBufferPtr = NULL; + if (fsp_ptr.rs->Type != EFI_SECTION_RAW) { + fsp_ptr.u8 = (u8 *)ERROR_NO_INFO_HEADER; + break; + } -#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); + /* Locate the FSP INFO Header which follows the Raw Header. */ + fsp_ptr.u8 += sizeof(EFI_RAW_SECTION); - /* Call the chipset code to fill in the chipset specific structures */ - chipset_fsp_early_init(&FspInitParams, fsp_ptr); + /* Verify that the FSP base address.*/ + if (fsp_ptr.fih->ImageBase != CONFIG_FSP_LOC) { + fsp_ptr.u8 = (u8 *)ERROR_IMAGEBASE_MISMATCH; + break; + } - /* Call back to romstage for board specific changes */ - romstage_fsp_rt_buffer_callback(&FspRtBuffer); + /* Verify the FSP Signature */ + if (fsp_ptr.fih->Signature != FSP_SIG) { + fsp_ptr.u8 = (u8 *)ERROR_INFO_HEAD_SIG_MISMATCH; + break; + } - FspInitApi(&FspInitParams); + /* 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; + } - /* Should never return. Control will continue from ContinuationFunc */ - die("Uh Oh! FspInitApi returned"); + return fsp_ptr.fih; } -#endif /* __PRE_RAM__ */ -volatile u8 * find_fsp () +void print_fsp_info(FSP_INFO_HEADER *fsp_header) { - -#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; + 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 +} - 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; - } +#if ENV_RAMSTAGE - /* 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; - } +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; - /* 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; + 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"); + } } - /* 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; - } + /* 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; - return (fsp_ptr); -} + timestamp_add_now(phase == EnumInitPhaseReadyToBoot ? + TS_FSP_BEFORE_FINALIZE : TS_FSP_BEFORE_ENUMERATE); -/** finds the saved temporary memory information in the FSP HOB list - * - * @param hob_list_ptr pointer to the start of the hob list - * @return pointer to saved CAR MEM or NULL if not found. - */ -void * find_saved_temp_mem(void *hob_list_ptr) -{ - EFI_GUID temp_hob_guid = FSP_BOOTLOADER_TEMPORARY_MEMORY_HOB_GUID; - EFI_HOB_GUID_TYPE *saved_mem_hob = - (EFI_HOB_GUID_TYPE *) find_hob_by_guid( - hob_list_ptr, &temp_hob_guid); + status = notify_phase_proc(¬ify_phase_params); - if (saved_mem_hob == NULL) - return NULL; + timestamp_add_now(phase == EnumInitPhaseReadyToBoot ? + TS_FSP_AFTER_FINALIZE : TS_FSP_AFTER_ENUMERATE); - return (void *) ((char *) saved_mem_hob + sizeof(EFI_HOB_GUID_TYPE)); + if (status != 0) + printk(BIOS_ERR, "FSP API NotifyPhase failed for phase 0x%x with status: 0x%x\n", + phase, status); } -#ifndef FSP_RESERVE_MEMORY_SIZE -/** @brief locates the HOB containing the location of the fsp reserved mem area - * - * @param hob_list_ptr pointer to the start of the hob list - * @return pointer to the start of the FSP reserved memory or NULL if not found. - */ -void * find_fsp_reserved_mem(void *hob_list_ptr) +static void fsp_notify_boot_state_callback(void *arg) { - EFI_GUID fsp_reserved_guid = FSP_HOB_RESOURCE_OWNER_FSP_GUID; - EFI_HOB_RESOURCE_DESCRIPTOR *fsp_reserved_mem = - (EFI_HOB_RESOURCE_DESCRIPTOR *) find_hob_by_guid( - hob_list_ptr, &fsp_reserved_guid); + u32 phase = (u32)arg; - if (fsp_reserved_mem == NULL) - return NULL; - - return (void *)((uintptr_t)fsp_reserved_mem->PhysicalStart); + printk(BIOS_SPEW, "Calling FspNotify(0x%08x)\n", phase); + fsp_notify(phase); } -#endif /* FSP_RESERVE_MEMORY_SIZE */ -#ifndef __PRE_RAM__ /* Only parse HOB data in ramstage */ +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); -void print_fsp_info(void) { +#endif /* ENV_RAMSTAGE */ - 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"); - } +struct fsp_runtime { + uint32_t fih; + uint32_t hob_list; +} __attribute__((packed)); - 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)); -} - - -#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) +void fsp_set_runtime(FSP_INFO_HEADER *fih, void *hob_list) { - 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); - } + struct fsp_runtime *fspr; - mrc_hob_data = GET_GUID_HOB_DATA (mrc_hob); - mrc_hob_size = (u32) GET_HOB_LENGTH(mrc_hob); + fspr = cbmem_add(CBMEM_ID_FSP_RUNTIME, sizeof(*fspr)); - printk(BIOS_DEBUG, "Memory Configure Data Hob at %p (size = 0x%x).\n", - (void *)mrc_hob_data, mrc_hob_size); + if (fspr == NULL) + die("Can't save FSP runtime information.\n"); - output_len = ALIGN(mrc_hob_size, 16); + fspr->fih = (uintptr_t)fih; + fspr->hob_list = (uintptr_t)hob_list; +} - /* 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)); +FSP_INFO_HEADER *fsp_get_fih(void) +{ + struct fsp_runtime *fspr; - /* 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; - } + fspr = cbmem_find(CBMEM_ID_FSP_RUNTIME); - 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); + if (fspr == NULL) + return NULL; - 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); + return (void *)(uintptr_t)fspr->fih; +} - /* 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); +void *fsp_get_hob_list(void) +{ + struct fsp_runtime *fspr; - mrc_data->mrc_checksum = compute_ip_checksum(mrc_data->mrc_data, - mrc_data->mrc_data_size); + fspr = cbmem_find(CBMEM_ID_FSP_RUNTIME); - printk(BIOS_SPEW, "Fast boot data (includes align and checksum):\n"); - hexdump32(BIOS_SPEW, (void *)mrc_data->mrc_data, output_len / 4); - return (1); -} -#endif /* CONFIG_ENABLE_MRC_CACHE */ + if (fspr == NULL) + return NULL; -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 - } + return (void *)(uintptr_t)fspr->hob_list; } -/** @brief Notify FSP for PostPciEnumeration - * - * @param unused - */ -static void fsp_after_pci_enum(void *unused) +void fsp_update_fih(FSP_INFO_HEADER *fih) { - /* This call needs to be done before resource allocation. */ - printk(BIOS_DEBUG, "FspNotify(EnumInitPhaseAfterPciEnumeration)\n"); - FspNotify(EnumInitPhaseAfterPciEnumeration); - printk(BIOS_DEBUG, - "Returned from FspNotify(EnumInitPhaseAfterPciEnumeration)\n"); -} + struct fsp_runtime *fspr; -/** @brief Notify FSP for ReadyToBoot - * - * @param unused - */ -static void fsp_finalize(void *unused) -{ - printk(BIOS_DEBUG, "FspNotify(EnumInitPhaseReadyToBoot)\n"); - print_fsp_info(); - FspNotify(EnumInitPhaseReadyToBoot); - printk(BIOS_DEBUG, "Returned from FspNotify(EnumInitPhaseReadyToBoot)\n"); -} + fspr = cbmem_find(CBMEM_ID_FSP_RUNTIME); -/* Set up for the ramstage FSP calls */ -BOOT_STATE_INIT_ENTRY(BS_DEV_ENUMERATE, BS_ON_EXIT, fsp_after_pci_enum, NULL); -BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_BOOT, BS_ON_ENTRY, fsp_finalize, NULL); + if (fspr == NULL) + die("Can't update FSP runtime information.\n"); -/* Update the MRC/fast boot cache as part of the late table writing stage */ -BOOT_STATE_INIT_ENTRY(BS_WRITE_TABLES, BS_ON_ENTRY, - find_fsp_hob_update_mrc, NULL); -#endif /* #ifndef __PRE_RAM__ */ + 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 index 054de1c5a1..38fa86211b 100644 --- a/src/drivers/intel/fsp1_1/fsp_util.h +++ b/src/drivers/intel/fsp1_1/fsp_util.h @@ -2,6 +2,7 @@ * 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 @@ -20,35 +21,52 @@ #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> -#include "fsp_values.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); +/* 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 FspNotify(u32 Phase); -void FspNotifyReturnPoint(EFI_STATUS Status, 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); -void * find_saved_temp_mem(void *hob_list_ptr); -void * find_fsp_reserved_mem(void *hob_list_ptr); - -/* functions in hob.c */ -void print_hob_mem_attributes(void *Hobptr); -void print_hob_type_structure(u16 Hobtype, void *Hoblistptr); -void print_hob_resource_attributes(void *Hobptr); -void print_guid_type_attributes(void *Hobptr); -const char * get_hob_type_string(void *Hobptr); -void * find_hob_by_guid(void *Hoblistptr, EFI_GUID *guid1); -uint8_t guids_are_equal(EFI_GUID *guid1, EFI_GUID *guid2); -void printguid(EFI_GUID *guid); +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 @@ -73,63 +91,31 @@ 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 + 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 +#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_IMAGE_SIG_LOC 0 +#define FSP_IMAGE_ID_LOC 16 +#define FSP_IMAGE_BASE_LOC 28 -#define FSP_SIG 0x48505346 /* 'FSPH' */ +#define FSP_SIG 0x48505346 /* 'FSPH' */ #define ERROR_NO_FV_SIG 1 -#define ERROR_NO_FFS_GUID 2 +#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_INFO_HEAD_SIG_MISMATCH 5 #define ERROR_FSP_SIG_MISMATCH 6 -#ifndef __PRE_RAM__ +#if ENV_RAMSTAGE extern void *FspHobListPtr; #endif -#define UPD_DEFAULT_CHECK(member) \ - if (config->member != UPD_DEFAULT) { \ - UpdData->member = config->member - 1; \ - } \ - printk(FSP_INFO_LEVEL, #member ":\t\t0x%02x %s\n", UpdData->member, \ - config->member ? "(set)" : "(default)"); - -#define UPD_SPD_CHECK(member) \ - if (config->member == UPD_SPD_ADDR_DISABLED) { \ - UpdData->member = 0x00; \ - } else if (config->member != UPD_SPD_ADDR_DEFAULT) { \ - UpdData->member = config->member; \ - } \ - printk(FSP_INFO_LEVEL, #member ":\t\t0x%02x %s\n", UpdData->member, \ - config->member ? "(set)" : "(default)"); - -#define UPD_DEVICE_CHECK(devicename, member, statement) \ - case devicename: \ - UpdData->member = dev->enabled; \ - printk(FSP_INFO_LEVEL, statement "%s\n", \ - UpdData->member?"Enabled":"Disabled"); \ - break; - - -#ifndef FSP_BOOTLOADER_TEMPORARY_MEMORY_HOB_GUID -#define FSP_BOOTLOADER_TEMPORARY_MEMORY_HOB_GUID \ - { 0xbbcff46c, 0xc8d3, 0x4113, { 0x89, 0x85, 0xb9, 0xd4, 0xf3, 0xb3, 0xf6, 0x4e } }; -#endif - #endif /* FSP_UTIL_H */ diff --git a/src/drivers/intel/fsp1_1/hob.c b/src/drivers/intel/fsp1_1/hob.c index ecc6bad845..905d3ec1ab 100644 --- a/src/drivers/intel/fsp1_1/hob.c +++ b/src/drivers/intel/fsp1_1/hob.c @@ -2,6 +2,7 @@ * 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 @@ -17,150 +18,329 @@ * Foundation, Inc. */ -#include <types.h> -#include <string.h> +#include <arch/early_variables.h> +#include <arch/hlt.h> +#include <bootstate.h> +#include <cbmem.h> #include <console/console.h> -#include <lib.h> // hexdump #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; +} -/** Displays a GUID's address and value +/* + * 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. * - * @param guid pointer to the GUID to display + * 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 printguid(EFI_GUID *guid) +void *get_next_resource_hob(const EFI_GUID *guid, const void *hob_start) { - printk(BIOS_SPEW,"Address: %p Guid: %08lx-%04x-%04x-", - guid, (unsigned long)guid->Data1, - guid->Data2, guid->Data3); - printk(BIOS_SPEW,"%02x%02x%02x%02x%02x%02x%02x%02x\n", - guid->Data4[0], guid->Data4[1], - guid->Data4[2], guid->Data4[3], - guid->Data4[4], guid->Data4[5], - guid->Data4[6], guid->Data4[7] ); + 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()); } -void print_hob_mem_attributes(void *Hobptr) +static void print_hob_mem_attributes(void *hob_ptr) { - 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"; + 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", - Hobmemtypenames[(u32)Hobmemtype], (u32) Hobmemtype); + 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)Hobmemaddr, (unsigned long)Hobmemlength); + (unsigned long)hob_mem_addr, + (unsigned long)hob_mem_length); } -void print_hob_resource_attributes(void *Hobptr) +static void print_hob_resource_attributes(void *hob_ptr) { - 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) { + 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: - Hobrestypestr = "EFI_RESOURCE_SYSTEM_MEMORY"; break; + hob_res_type_str = "EFI_RESOURCE_SYSTEM_MEMORY"; + break; case EFI_RESOURCE_MEMORY_MAPPED_IO: - Hobrestypestr = "EFI_RESOURCE_MEMORY_MAPPED_IO"; break; + hob_res_type_str = "EFI_RESOURCE_MEMORY_MAPPED_IO"; + break; case EFI_RESOURCE_IO: - Hobrestypestr = "EFI_RESOURCE_IO"; break; + hob_res_type_str = "EFI_RESOURCE_IO"; + break; case EFI_RESOURCE_FIRMWARE_DEVICE: - Hobrestypestr = "EFI_RESOURCE_FIRMWARE_DEVICE"; break; + hob_res_type_str = "EFI_RESOURCE_FIRMWARE_DEVICE"; + break; case EFI_RESOURCE_MEMORY_MAPPED_IO_PORT: - Hobrestypestr = "EFI_RESOURCE_MEMORY_MAPPED_IO_PORT"; break; + hob_res_type_str = "EFI_RESOURCE_MEMORY_MAPPED_IO_PORT"; + break; case EFI_RESOURCE_MEMORY_RESERVED: - Hobrestypestr = "EFI_RESOURCE_MEMORY_RESERVED"; break; + hob_res_type_str = "EFI_RESOURCE_MEMORY_RESERVED"; + break; case EFI_RESOURCE_IO_RESERVED: - Hobrestypestr = "EFI_RESOURCE_IO_RESERVED"; break; + hob_res_type_str = "EFI_RESOURCE_IO_RESERVED"; + break; case EFI_RESOURCE_MAX_MEMORY_TYPE: - Hobrestypestr = "EFI_RESOURCE_MAX_MEMORY_TYPE"; break; + hob_res_type_str = "EFI_RESOURCE_MAX_MEMORY_TYPE"; + break; default: - Hobrestypestr = "EFI_RESOURCE_UNKNOWN"; break; + hob_res_type_str = "EFI_RESOURCE_UNKNOWN"; + break; } printk(BIOS_SPEW, " Resource %s (0x%0x) has attributes 0x%0x\n", - Hobrestypestr, Hobrestype, Hobresattr); + hob_res_type_str, hob_res_type, hob_res_attr); printk(BIOS_SPEW, " at location 0x%0lx with length 0x%0lx\n", - (unsigned long)Hobresaddr, (unsigned long)Hobreslength); + (unsigned long)hob_res_addr, + (unsigned long)hob_res_length); } -const char * get_hob_type_string(void *Hobptr) +static const char *get_hob_type_string(void *hob_ptr) { - EFI_HOB_GENERIC_HEADER *HobHeaderPtr = (EFI_HOB_GENERIC_HEADER *)Hobptr; - u16 Hobtype = HobHeaderPtr->HobType; - const char *Hobtypestring = NULL; + 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; - switch (Hobtype) { + hob.Header = (EFI_HOB_GENERIC_HEADER *)hob_ptr; + switch (hob.Header->HobType) { case EFI_HOB_TYPE_HANDOFF: - Hobtypestring = "EFI_HOB_TYPE_HANDOFF"; break; + hob_type_string = "EFI_HOB_TYPE_HANDOFF"; + break; case EFI_HOB_TYPE_MEMORY_ALLOCATION: - Hobtypestring = "EFI_HOB_TYPE_MEMORY_ALLOCATION"; break; + hob_type_string = "EFI_HOB_TYPE_MEMORY_ALLOCATION"; + break; case EFI_HOB_TYPE_RESOURCE_DESCRIPTOR: - Hobtypestring = "EFI_HOB_TYPE_RESOURCE_DESCRIPTOR"; break; + hob_type_string = "EFI_HOB_TYPE_RESOURCE_DESCRIPTOR"; + break; case EFI_HOB_TYPE_GUID_EXTENSION: - Hobtypestring = "EFI_HOB_TYPE_GUID_EXTENSION"; break; + 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: - Hobtypestring = "EFI_HOB_TYPE_MEMORY_POOL"; break; + hob_type_string = "EFI_HOB_TYPE_MEMORY_POOL"; + break; case EFI_HOB_TYPE_UNUSED: - Hobtypestring = "EFI_HOB_TYPE_UNUSED"; break; + hob_type_string = "EFI_HOB_TYPE_UNUSED"; + break; case EFI_HOB_TYPE_END_OF_HOB_LIST: - Hobtypestring = "EFI_HOB_TYPE_END_OF_HOB_LIST"; break; + hob_type_string = "EFI_HOB_TYPE_END_OF_HOB_LIST"; + break; default: - Hobtypestring = "EFI_HOB_TYPE_UNRECOGNIZED"; break; + hob_type_string = "EFI_HOB_TYPE_UNRECOGNIZED"; + break; } - return Hobtypestring; + return hob_type_string; } -/** Displays the length, location, and GUID value of a GUID extension - * - * The EFI_HOB_GUID_TYPE is very basic - it just contains the standard - * HOB header containing the HOB type and length, and a GUID for - * identification. The rest of the data is undefined and must be known - * based on the GUID. - * - * This displays the entire HOB length, and the location of the start - * of the HOB, *NOT* the length of or the start of the data inside the HOB. - * - * @param Hobptr - */ -void print_guid_type_attributes(void *Hobptr) -{ - printk(BIOS_SPEW, " at location %p with length0x%0lx\n ", - Hobptr, (unsigned long)(((EFI_PEI_HOB_POINTERS *) \ - Hobptr)->Guid->Header.HobLength)); - printguid(&(((EFI_HOB_GUID_TYPE *)Hobptr)->Name)); - -} - -/* Print out a structure of all the HOBs +/* + * 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_HANDOFF (0x0001) * EFI_HOB_TYPE_MEMORY_ALLOCATION (0x0002) * EFI_HOB_TYPE_RESOURCE_DESCRIPTOR (0x0003) * EFI_HOB_TYPE_GUID_EXTENSION (0x0004) @@ -168,102 +348,148 @@ void print_guid_type_attributes(void *Hobptr) * EFI_HOB_TYPE_UNUSED (0xFFFE) * EFI_HOB_TYPE_END_OF_HOB_LIST (0xFFFF) */ -void print_hob_type_structure(u16 Hobtype, void *Hoblistptr) +void print_hob_type_structure(u16 hob_type, void *hob_list_ptr) { - u32 *Currenthob; - u32 *Nexthob = 0; - u8 Lasthob = 0; - u32 Currenttype; - const char *Currenttypestr; + u32 *current_hob; + u32 *next_hob = 0; + u8 last_hob = 0; + u32 current_type; + const char *current_type_str; - Currenthob = Hoblistptr; + current_hob = hob_list_ptr; - /* Print out HOBs of our desired type until + /* + * 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); + printk(BIOS_DEBUG, "0x%p: hob_list_ptr\n", hob_list_ptr); 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); + 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 (Currenttype == Hobtype || Hobtype == 0x0000) { + if (current_type == hob_type || hob_type == 0x0000) { printk(BIOS_DEBUG, "HOB 0x%0x is an %s (type 0x%0x)\n", - (u32) Currenthob, Currenttypestr, Currenttype); - switch (Currenttype) { + (u32)current_hob, current_type_str, + current_type); + switch (current_type) { case EFI_HOB_TYPE_MEMORY_ALLOCATION: - print_hob_mem_attributes(Currenthob); break; + print_hob_mem_attributes(current_hob); + break; case EFI_HOB_TYPE_RESOURCE_DESCRIPTOR: - print_hob_resource_attributes(Currenthob); break; - case EFI_HOB_TYPE_GUID_EXTENSION: - print_guid_type_attributes(Currenthob); break; + print_hob_resource_attributes(current_hob); + 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 + /* 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 (!Lasthob); + } while (!last_hob); printk(BIOS_DEBUG, "=== End of FSP HOB Data Structure ===\n\n"); } - -/** Finds a HOB entry based on type and guid - * - * @param current_hob pointer to the start of the HOB list - * @param guid the GUID of the HOB entry to find - * @return pointer to the start of the requested HOB or NULL if not found. +#if IS_ENABLED(CONFIG_ENABLE_MRC_CACHE) +/* + * Save the FSP memory HOB (mrc data) to the MRC area in CBMEM */ -void * find_hob_by_guid(void *current_hob, EFI_GUID *guid) +int save_mrc_data(void *hob_start) { - do { - switch (((EFI_HOB_GENERIC_HEADER *)current_hob)->HobType) { + 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; - case EFI_HOB_TYPE_MEMORY_ALLOCATION: - if (guids_are_equal(guid, &(((EFI_HOB_MEMORY_ALLOCATION *) \ - current_hob)->AllocDescriptor.Name))) - return current_hob; - break; - case EFI_HOB_TYPE_RESOURCE_DESCRIPTOR: - if (guids_are_equal(guid, - &(((EFI_HOB_RESOURCE_DESCRIPTOR *) \ - current_hob)->Owner))) - return current_hob; - break; - case EFI_HOB_TYPE_GUID_EXTENSION: - if (guids_are_equal(guid, &(((EFI_HOB_GUID_TYPE *) \ - current_hob)->Name))) - return current_hob; - break; - } + 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; + } - if (!END_OF_HOB_LIST(current_hob)) - current_hob = GET_NEXT_HOB(current_hob); /* Get next HOB pointer */ - } while (!END_OF_HOB_LIST(current_hob)); + mrc_hob_data = GET_GUID_HOB_DATA(mrc_hob); + mrc_hob_size = (u32) GET_HOB_LENGTH(mrc_hob); - return NULL; -} + printk(BIOS_DEBUG, "Memory Configure Data Hob at %p (size = 0x%x).\n", + (void *)mrc_hob_data, mrc_hob_size); -/** Compares a pair of GUIDs to see if they are equal - * - * GUIDs are 128 bits long, so compare them as pairs of quadwords. - * - * @param guid1 pointer to the first of the GUIDs to compare - * @param guid2 pointer to the second of the GUIDs to compare - * @return 1 if the GUIDs were equal, 0 if GUIDs were not equal - */ -uint8_t guids_are_equal(EFI_GUID *guid1, EFI_GUID *guid2) -{ - uint64_t* guid_1 = (void *) guid1; - uint64_t* guid_2 = (void *) guid2; + 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)); - if ((*(guid_1) != *(guid_2)) || (*(guid_1 + 1) != *(guid_2 + 1))) + /* 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 */ + +#if ENV_RAMSTAGE + +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_ENTRY(BS_WRITE_TABLES, BS_ON_ENTRY, + find_fsp_hob_update_mrc, NULL); + +#endif /* ENV_RAMSTAGE */ |