diff options
Diffstat (limited to 'src/drivers')
-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 */ |