Lee Leahy | 3dad489 | 2015-05-05 11:14:02 -0700 | [diff] [blame] | 1 | /* |
| 2 | * This file is part of the coreboot project. |
| 3 | * |
| 4 | * Copyright (C) 2013-2014 Sage Electronic Engineering, LLC. |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License as published by |
| 8 | * the Free Software Foundation; version 2 of the License. |
| 9 | * |
| 10 | * This program is distributed in the hope that it will be useful, |
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | * GNU General Public License for more details. |
| 14 | * |
| 15 | * You should have received a copy of the GNU General Public License |
| 16 | * along with this program; if not, write to the Free Software |
Patrick Georgi | b890a12 | 2015-03-26 15:17:45 +0100 | [diff] [blame^] | 17 | * Foundation, Inc. |
Lee Leahy | 3dad489 | 2015-05-05 11:14:02 -0700 | [diff] [blame] | 18 | */ |
| 19 | |
| 20 | #include <types.h> |
| 21 | #include <string.h> |
| 22 | #include <console/console.h> |
| 23 | #include <bootstate.h> |
| 24 | #include <cbmem.h> |
| 25 | #include "fsp_util.h" |
| 26 | #include <lib.h> // hexdump |
| 27 | #include <ip_checksum.h> |
| 28 | #include <timestamp.h> |
| 29 | |
| 30 | #ifndef __PRE_RAM__ |
| 31 | /* Globals pointers for FSP structures */ |
| 32 | void *FspHobListPtr = NULL; |
| 33 | FSP_INFO_HEADER *fsp_header_ptr = NULL; |
| 34 | |
| 35 | void FspNotify (u32 Phase) |
| 36 | { |
| 37 | FSP_NOTFY_PHASE NotifyPhaseProc; |
| 38 | NOTIFY_PHASE_PARAMS NotifyPhaseParams; |
| 39 | EFI_STATUS Status; |
| 40 | |
| 41 | if (fsp_header_ptr == NULL) { |
| 42 | fsp_header_ptr = (void *)find_fsp(); |
| 43 | if ((u32)fsp_header_ptr < 0xff) { |
| 44 | post_code(0x4F); /* output something in case there is no serial */ |
| 45 | die("Can't find the FSP!\n"); |
| 46 | } |
| 47 | } |
| 48 | |
| 49 | /* call FSP PEI to Notify PostPciEnumeration */ |
| 50 | NotifyPhaseProc = (FSP_NOTFY_PHASE)(fsp_header_ptr->ImageBase + |
| 51 | fsp_header_ptr->NotifyPhaseEntry); |
| 52 | NotifyPhaseParams.Phase = Phase; |
| 53 | |
| 54 | timestamp_add_now(Phase == EnumInitPhaseReadyToBoot ? |
| 55 | TS_FSP_BEFORE_FINALIZE : TS_FSP_BEFORE_ENUMERATE); |
| 56 | |
| 57 | Status = NotifyPhaseProc (&NotifyPhaseParams); |
| 58 | |
| 59 | timestamp_add_now(Phase == EnumInitPhaseReadyToBoot ? |
| 60 | TS_FSP_AFTER_FINALIZE : TS_FSP_AFTER_ENUMERATE); |
| 61 | |
| 62 | if (Status != 0) |
| 63 | printk(BIOS_ERR,"FSP API NotifyPhase failed for phase 0x%x with status: 0x%x\n", Phase, Status); |
| 64 | } |
| 65 | #endif /* #ifndef __PRE_RAM__ */ |
| 66 | |
| 67 | #ifdef __PRE_RAM__ |
| 68 | |
| 69 | /* |
| 70 | * Call the FSP to do memory init. The FSP doesn't return to this function. |
| 71 | * The FSP returns to the romstage_main_continue(). |
| 72 | */ |
| 73 | void __attribute__ ((noreturn)) fsp_early_init (FSP_INFO_HEADER *fsp_ptr) |
| 74 | { |
| 75 | FSP_FSP_INIT FspInitApi; |
| 76 | FSP_INIT_PARAMS FspInitParams; |
| 77 | FSP_INIT_RT_BUFFER FspRtBuffer; |
| 78 | #if IS_ENABLED(CONFIG_FSP_USES_UPD) |
| 79 | UPD_DATA_REGION fsp_upd_data; |
| 80 | #endif |
| 81 | |
| 82 | memset((void*)&FspRtBuffer, 0, sizeof(FSP_INIT_RT_BUFFER)); |
| 83 | FspRtBuffer.Common.StackTop = (u32 *)CONFIG_RAMTOP; |
| 84 | FspInitParams.NvsBufferPtr = NULL; |
| 85 | |
| 86 | #if IS_ENABLED(CONFIG_FSP_USES_UPD) |
| 87 | FspRtBuffer.Common.UpdDataRgnPtr = &fsp_upd_data; |
| 88 | #endif |
| 89 | FspInitParams.RtBufferPtr = (FSP_INIT_RT_BUFFER *)&FspRtBuffer; |
| 90 | FspInitParams.ContinuationFunc = (CONTINUATION_PROC)ChipsetFspReturnPoint; |
| 91 | FspInitApi = (FSP_FSP_INIT)(fsp_ptr->ImageBase + fsp_ptr->FspInitEntry); |
| 92 | |
| 93 | /* Call the chipset code to fill in the chipset specific structures */ |
| 94 | chipset_fsp_early_init(&FspInitParams, fsp_ptr); |
| 95 | |
| 96 | /* Call back to romstage for board specific changes */ |
| 97 | romstage_fsp_rt_buffer_callback(&FspRtBuffer); |
| 98 | |
| 99 | FspInitApi(&FspInitParams); |
| 100 | |
| 101 | /* Should never return. Control will continue from ContinuationFunc */ |
| 102 | die("Uh Oh! FspInitApi returned"); |
| 103 | } |
| 104 | #endif /* __PRE_RAM__ */ |
| 105 | |
| 106 | volatile u8 * find_fsp () |
| 107 | { |
| 108 | |
| 109 | #ifdef __PRE_RAM__ |
| 110 | volatile register u8 *fsp_ptr asm ("eax"); |
| 111 | |
| 112 | /* Entry point for CAR assembly routine */ |
| 113 | __asm__ __volatile__ ( |
| 114 | ".global find_fsp\n\t" |
| 115 | "find_fsp:\n\t" |
| 116 | ); |
| 117 | #else |
| 118 | volatile u8 *fsp_ptr; |
| 119 | #endif /* __PRE_RAM__ */ |
| 120 | |
| 121 | #ifndef CONFIG_FSP_LOC |
| 122 | #error "CONFIG_FSP_LOC must be set." |
| 123 | #endif |
| 124 | |
| 125 | /* The FSP is stored in CBFS */ |
| 126 | fsp_ptr = (u8 *) CONFIG_FSP_LOC; |
| 127 | |
| 128 | /* Check the FV signature, _FVH */ |
| 129 | if (((EFI_FIRMWARE_VOLUME_HEADER *)fsp_ptr)->Signature == 0x4856465F) { |
| 130 | /* Go to the end of the FV header and align the address. */ |
| 131 | fsp_ptr += ((EFI_FIRMWARE_VOLUME_HEADER *)fsp_ptr)->ExtHeaderOffset; |
| 132 | fsp_ptr += ((EFI_FIRMWARE_VOLUME_EXT_HEADER *)fsp_ptr)->ExtHeaderSize; |
| 133 | fsp_ptr = (u8 *)(((u32)fsp_ptr + 7) & 0xFFFFFFF8); |
| 134 | } else { |
| 135 | fsp_ptr = (u8*)ERROR_NO_FV_SIG; |
| 136 | } |
| 137 | |
| 138 | /* Check the FFS GUID */ |
| 139 | if (((u32)fsp_ptr > 0xff) && |
| 140 | (((u32 *)&(((EFI_FFS_FILE_HEADER *)fsp_ptr)->Name))[0] == 0x912740BE) && |
| 141 | (((u32 *)&(((EFI_FFS_FILE_HEADER *)fsp_ptr)->Name))[1] == 0x47342284) && |
| 142 | (((u32 *)&(((EFI_FFS_FILE_HEADER *)fsp_ptr)->Name))[2] == 0xB08471B9) && |
| 143 | (((u32 *)&(((EFI_FFS_FILE_HEADER *)fsp_ptr)->Name))[3] == 0x0C3F3527)) { |
| 144 | /* Add the FFS Header size to the base to find the Raw section Header */ |
| 145 | fsp_ptr += sizeof(EFI_FFS_FILE_HEADER); |
| 146 | } else { |
| 147 | fsp_ptr = (u8 *)ERROR_NO_FFS_GUID; |
| 148 | } |
| 149 | |
| 150 | if (((u32)fsp_ptr > 0xff) && |
| 151 | ((EFI_RAW_SECTION *)fsp_ptr)->Type == EFI_SECTION_RAW) { |
| 152 | /* Add the Raw Header size to the base to find the FSP INFO Header */ |
| 153 | fsp_ptr += sizeof(EFI_RAW_SECTION); |
| 154 | } else { |
| 155 | fsp_ptr = (u8 *)ERROR_NO_INFO_HEADER; |
| 156 | } |
| 157 | |
| 158 | /* Verify that the FSP is set to the base address we're expecting.*/ |
| 159 | if (((u32)fsp_ptr > 0xff) && |
| 160 | (*(u32*)(fsp_ptr + FSP_IMAGE_BASE_LOC) != CONFIG_FSP_LOC)) { |
| 161 | fsp_ptr = (u8 *)ERROR_IMAGEBASE_MISMATCH; |
| 162 | } |
| 163 | |
| 164 | /* Verify the FSP Signature */ |
| 165 | if (((u32)fsp_ptr > 0xff) && |
| 166 | (*(u32*)(fsp_ptr + FSP_IMAGE_SIG_LOC) != FSP_SIG)){ |
| 167 | fsp_ptr = (u8 *)ERROR_INFO_HEAD_SIG_MISMATCH; |
| 168 | } |
| 169 | |
| 170 | /* Verify the FSP ID */ |
| 171 | if (((u32)fsp_ptr > 0xff) && |
| 172 | ((*(u32 *)(fsp_ptr + FSP_IMAGE_ID_LOC) != FSP_IMAGE_ID_DWORD0) || |
| 173 | (*(u32 *)(fsp_ptr + (FSP_IMAGE_ID_LOC + 4)) != FSP_IMAGE_ID_DWORD1))) { |
| 174 | fsp_ptr = (u8 *)ERROR_FSP_SIG_MISMATCH; |
| 175 | } |
| 176 | |
| 177 | return (fsp_ptr); |
| 178 | } |
| 179 | |
| 180 | /** finds the saved temporary memory information in the FSP HOB list |
| 181 | * |
| 182 | * @param hob_list_ptr pointer to the start of the hob list |
| 183 | * @return pointer to saved CAR MEM or NULL if not found. |
| 184 | */ |
| 185 | void * find_saved_temp_mem(void *hob_list_ptr) |
| 186 | { |
| 187 | EFI_GUID temp_hob_guid = FSP_BOOTLOADER_TEMPORARY_MEMORY_HOB_GUID; |
| 188 | EFI_HOB_GUID_TYPE *saved_mem_hob = |
| 189 | (EFI_HOB_GUID_TYPE *) find_hob_by_guid( |
| 190 | hob_list_ptr, &temp_hob_guid); |
| 191 | |
| 192 | if (saved_mem_hob == NULL) |
| 193 | return NULL; |
| 194 | |
| 195 | return (void *) ((char *) saved_mem_hob + sizeof(EFI_HOB_GUID_TYPE)); |
| 196 | } |
| 197 | |
| 198 | #ifndef FSP_RESERVE_MEMORY_SIZE |
| 199 | /** @brief locates the HOB containing the location of the fsp reserved mem area |
| 200 | * |
| 201 | * @param hob_list_ptr pointer to the start of the hob list |
| 202 | * @return pointer to the start of the FSP reserved memory or NULL if not found. |
| 203 | */ |
| 204 | void * find_fsp_reserved_mem(void *hob_list_ptr) |
| 205 | { |
| 206 | EFI_GUID fsp_reserved_guid = FSP_HOB_RESOURCE_OWNER_FSP_GUID; |
| 207 | EFI_HOB_RESOURCE_DESCRIPTOR *fsp_reserved_mem = |
| 208 | (EFI_HOB_RESOURCE_DESCRIPTOR *) find_hob_by_guid( |
| 209 | hob_list_ptr, &fsp_reserved_guid); |
| 210 | |
| 211 | if (fsp_reserved_mem == NULL) |
| 212 | return NULL; |
| 213 | |
| 214 | return (void *)((uintptr_t)fsp_reserved_mem->PhysicalStart); |
| 215 | } |
| 216 | #endif /* FSP_RESERVE_MEMORY_SIZE */ |
| 217 | |
| 218 | #ifndef __PRE_RAM__ /* Only parse HOB data in ramstage */ |
| 219 | |
| 220 | void print_fsp_info(void) { |
| 221 | |
| 222 | if (fsp_header_ptr == NULL) |
| 223 | fsp_header_ptr = (void *)find_fsp(); |
| 224 | if ((u32)fsp_header_ptr < 0xff) { |
| 225 | post_code(0x4F); /* output something in case there is no serial */ |
| 226 | die("Can't find the FSP!\n"); |
| 227 | } |
| 228 | |
| 229 | if (FspHobListPtr == NULL) { |
| 230 | FspHobListPtr = (void*)*((u32*) cbmem_find(CBMEM_ID_HOB_POINTER)); |
| 231 | } |
| 232 | |
| 233 | printk(BIOS_SPEW,"fsp_header_ptr: %p\n", fsp_header_ptr); |
| 234 | printk(BIOS_INFO,"FSP Header Version: %d\n", fsp_header_ptr->HeaderRevision); |
| 235 | printk(BIOS_INFO,"FSP Revision: %d.%d\n", |
| 236 | (u8)((fsp_header_ptr->ImageRevision >> 8) & 0xff), |
| 237 | (u8)(fsp_header_ptr->ImageRevision & 0xff)); |
| 238 | } |
| 239 | |
| 240 | |
| 241 | #if IS_ENABLED(CONFIG_ENABLE_MRC_CACHE) |
| 242 | /** |
| 243 | * Save the FSP memory HOB (mrc data) to the MRC area in CBMEM |
| 244 | */ |
| 245 | int save_mrc_data(void *hob_start) |
| 246 | { |
| 247 | u32 *mrc_hob; |
| 248 | u32 *mrc_hob_data; |
| 249 | u32 mrc_hob_size; |
| 250 | struct mrc_data_container *mrc_data; |
| 251 | int output_len; |
| 252 | const EFI_GUID mrc_guid = FSP_NON_VOLATILE_STORAGE_HOB_GUID; |
| 253 | |
| 254 | mrc_hob = GetNextGuidHob(&mrc_guid, hob_start); |
| 255 | if (mrc_hob == NULL){ |
| 256 | printk(BIOS_DEBUG, "Memory Configure Data Hob is not present\n"); |
| 257 | return(0); |
| 258 | } |
| 259 | |
| 260 | mrc_hob_data = GET_GUID_HOB_DATA (mrc_hob); |
| 261 | mrc_hob_size = (u32) GET_HOB_LENGTH(mrc_hob); |
| 262 | |
| 263 | printk(BIOS_DEBUG, "Memory Configure Data Hob at %p (size = 0x%x).\n", |
| 264 | (void *)mrc_hob_data, mrc_hob_size); |
| 265 | |
| 266 | output_len = ALIGN(mrc_hob_size, 16); |
| 267 | |
| 268 | /* Save the MRC S3/fast boot/ADR restore data to cbmem */ |
| 269 | mrc_data = cbmem_add (CBMEM_ID_MRCDATA, |
| 270 | output_len + sizeof(struct mrc_data_container)); |
| 271 | |
| 272 | /* Just return if there was a problem with getting CBMEM */ |
| 273 | if (mrc_data == NULL) { |
| 274 | printk(BIOS_WARNING, "CBMEM was not available to save the fast boot cache data.\n"); |
| 275 | return 0; |
| 276 | } |
| 277 | |
| 278 | printk(BIOS_DEBUG, "Copy FSP MRC DATA to HOB (source addr %p, dest addr %p, %u bytes)\n", |
| 279 | (void *)mrc_hob_data, mrc_data, output_len); |
| 280 | |
| 281 | mrc_data->mrc_signature = MRC_DATA_SIGNATURE; |
| 282 | mrc_data->mrc_data_size = output_len; |
| 283 | mrc_data->reserved = 0; |
| 284 | memcpy(mrc_data->mrc_data, (const void *)mrc_hob_data, mrc_hob_size); |
| 285 | |
| 286 | /* Zero the unused space in aligned buffer. */ |
| 287 | if (output_len > mrc_hob_size) |
| 288 | memset((mrc_data->mrc_data + mrc_hob_size), 0, |
| 289 | output_len - mrc_hob_size); |
| 290 | |
| 291 | mrc_data->mrc_checksum = compute_ip_checksum(mrc_data->mrc_data, |
| 292 | mrc_data->mrc_data_size); |
| 293 | |
| 294 | printk(BIOS_SPEW, "Fast boot data (includes align and checksum):\n"); |
| 295 | hexdump32(BIOS_SPEW, (void *)mrc_data->mrc_data, output_len / 4); |
| 296 | return (1); |
| 297 | } |
| 298 | #endif /* CONFIG_ENABLE_MRC_CACHE */ |
| 299 | |
| 300 | static void find_fsp_hob_update_mrc(void *unused) |
| 301 | { |
| 302 | /* Set the global HOB list pointer */ |
| 303 | FspHobListPtr = (void*)*((u32*) cbmem_find(CBMEM_ID_HOB_POINTER)); |
| 304 | |
| 305 | if (!FspHobListPtr){ |
| 306 | printk(BIOS_ERR, "ERROR: Could not find FSP HOB pointer in CBFS!\n"); |
| 307 | } else { |
| 308 | /* 0x0000: Print all types */ |
| 309 | print_hob_type_structure(0x000, FspHobListPtr); |
| 310 | |
| 311 | #if IS_ENABLED(CONFIG_ENABLE_MRC_CACHE) |
| 312 | if(save_mrc_data(FspHobListPtr)) |
| 313 | update_mrc_cache(NULL); |
| 314 | else |
| 315 | printk(BIOS_DEBUG,"Not updating MRC data in flash.\n"); |
| 316 | #endif |
| 317 | } |
| 318 | } |
| 319 | |
| 320 | /** @brief Notify FSP for PostPciEnumeration |
| 321 | * |
| 322 | * @param unused |
| 323 | */ |
| 324 | static void fsp_after_pci_enum(void *unused) |
| 325 | { |
| 326 | /* This call needs to be done before resource allocation. */ |
| 327 | printk(BIOS_DEBUG, "FspNotify(EnumInitPhaseAfterPciEnumeration)\n"); |
| 328 | FspNotify(EnumInitPhaseAfterPciEnumeration); |
| 329 | printk(BIOS_DEBUG, |
| 330 | "Returned from FspNotify(EnumInitPhaseAfterPciEnumeration)\n"); |
| 331 | } |
| 332 | |
| 333 | /** @brief Notify FSP for ReadyToBoot |
| 334 | * |
| 335 | * @param unused |
| 336 | */ |
| 337 | static void fsp_finalize(void *unused) |
| 338 | { |
| 339 | printk(BIOS_DEBUG, "FspNotify(EnumInitPhaseReadyToBoot)\n"); |
| 340 | print_fsp_info(); |
| 341 | FspNotify(EnumInitPhaseReadyToBoot); |
| 342 | printk(BIOS_DEBUG, "Returned from FspNotify(EnumInitPhaseReadyToBoot)\n"); |
| 343 | } |
| 344 | |
| 345 | /* Set up for the ramstage FSP calls */ |
| 346 | BOOT_STATE_INIT_ENTRY(BS_DEV_ENUMERATE, BS_ON_EXIT, fsp_after_pci_enum, NULL); |
| 347 | BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_BOOT, BS_ON_ENTRY, fsp_finalize, NULL); |
| 348 | |
| 349 | /* Update the MRC/fast boot cache as part of the late table writing stage */ |
| 350 | BOOT_STATE_INIT_ENTRY(BS_WRITE_TABLES, BS_ON_ENTRY, |
| 351 | find_fsp_hob_update_mrc, NULL); |
| 352 | #endif /* #ifndef __PRE_RAM__ */ |