diff --git a/src/Kconfig b/src/Kconfig index 614b95f976..8646b19fb1 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -429,6 +429,14 @@ config RELOCATABLE_RAMSTAGE wake. When selecting this option the romstage is responsible for determing a stack location to use for loading the ramstage. +config CACHE_RELOCATED_RAMSTAGE_OUTSIDE_CBMEM + depends on RELOCATABLE_RAMSTAGE + bool "Cache the relocated ramstage outside of cbmem." + default n + help + The relocated ramstage is saved in an area specified by the + by the board and/or chipset. + config HAVE_REFCODE_BLOB depends on ARCH_X86 bool "An external reference code blob should be put into cbfs." diff --git a/src/cpu/intel/haswell/haswell.h b/src/cpu/intel/haswell/haswell.h index dcd5dc70ea..190abc65ee 100644 --- a/src/cpu/intel/haswell/haswell.h +++ b/src/cpu/intel/haswell/haswell.h @@ -215,22 +215,6 @@ void release_aps_for_smm_relocation(int do_parallel_relocation); extern int ht_disabled; #endif -/* This structure is saved along with the relocated ramstage program in SMM - * space. It is used to protect the integrity of the ramstage program on S3 - * resume by saving a copy of the relocated ramstage in SMM space with the - * assumption that the SMM region cannot be altered from the OS. The magic - * value just serves as a quick sanity check. */ - -#define RAMSTAGE_CACHE_MAGIC 0xf3c3a02a - -struct ramstage_cache { - uint32_t magic; - uint32_t entry_point; - uint32_t load_address; - uint32_t size; - char program[0]; -} __attribute__((packed)); - /* CPU identification */ int haswell_family_model(void); int haswell_stepping(void); diff --git a/src/cpu/intel/haswell/romstage.c b/src/cpu/intel/haswell/romstage.c index 6b5780bdbc..60a1c3a155 100644 --- a/src/cpu/intel/haswell/romstage.c +++ b/src/cpu/intel/haswell/romstage.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #if CONFIG_CHROMEOS @@ -316,67 +317,20 @@ void romstage_after_car(void) #if CONFIG_RELOCATABLE_RAMSTAGE -void cache_loaded_ramstage(struct romstage_handoff *handoff, - const struct cbmem_entry *ramstage, - void *entry_point) +#include + +struct ramstage_cache *ramstage_cache_location(long *size) { - struct ramstage_cache *cache; - uint32_t total_size; - uint32_t ramstage_size; - void *ramstage_base; - - ramstage_size = cbmem_entry_size(ramstage); - ramstage_base = cbmem_entry_start(ramstage); - /* The ramstage cache lives in the TSEG region at RESERVED_SMM_OFFSET. * The top of ram is defined to be the TSEG base address. */ - cache = (void *)(get_top_of_ram() + RESERVED_SMM_OFFSET); - total_size = sizeof(*cache) + ramstage_size; - if (total_size > RESERVED_SMM_SIZE) { - printk(BIOS_DEBUG, "0x%08x > RESERVED_SMM_SIZE (0x%08x)\n", - total_size, RESERVED_SMM_SIZE); - /* Nuke whatever may be there now just in case. */ - cache->magic = ~RAMSTAGE_CACHE_MAGIC; - return; - } - - cache->magic = RAMSTAGE_CACHE_MAGIC; - cache->entry_point = (uint32_t)entry_point; - cache->load_address = (uint32_t)ramstage_base; - cache->size = ramstage_size; - - printk(BIOS_DEBUG, "Saving ramstage to SMM space cache.\n"); - - /* Copy over the program. */ - memcpy(&cache->program[0], ramstage_base, ramstage_size); - - if (handoff == NULL) - return; - - handoff->ramstage_entry_point = (uint32_t)entry_point; + *size = RESERVED_SMM_SIZE; + return (void *)(get_top_of_ram() + RESERVED_SMM_OFFSET); } -void *load_cached_ramstage(struct romstage_handoff *handoff, - const struct cbmem_entry *ramstage) +void ramstage_cache_invalid(struct ramstage_cache *cache) { - struct ramstage_cache *cache; - - /* The ramstage cache lives in the TSEG region at RESERVED_SMM_OFFSET. - * The top of ram is defined to be the TSEG base address. */ - cache = (void *)(get_top_of_ram() + RESERVED_SMM_OFFSET); - - if (cache->magic != RAMSTAGE_CACHE_MAGIC) { - printk(BIOS_DEBUG, "Invalid ramstage cache found.\n"); - #if CONFIG_RESET_ON_INVALID_RAMSTAGE_CACHE - reset_system(); - #endif - return NULL; - } - - printk(BIOS_DEBUG, "Loading ramstage from SMM space cache.\n"); - - memcpy((void *)cache->load_address, &cache->program[0], cache->size); - - return (void *)cache->entry_point; +#if CONFIG_RESET_ON_INVALID_RAMSTAGE_CACHE + reset_system(); +#endif } #endif diff --git a/src/include/ramstage_cache.h b/src/include/ramstage_cache.h new file mode 100644 index 0000000000..5b0597a828 --- /dev/null +++ b/src/include/ramstage_cache.h @@ -0,0 +1,49 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _RAMSTAGE_CACHE_ +#define _RAMSTAGE_CACHE_ + +#if !defined(__PRE_RAM__) +#error "ramstage_cache only used in romstage for loading ramstage." +#endif + +/* This structure is saved along with the relocated ramstage program when + * CONFIG_RELOCATED_RAMSTAGE is employed. For x86, it can used to protect + * the integrity of the ramstage program on S3 resume by saving a copy of + * the relocated ramstage in SMM space with the assumption that the SMM region + * cannot be altered from the OS. The magic value just serves as a quick sanity + * check. */ + +#define RAMSTAGE_CACHE_MAGIC 0xf3c3a02a + +struct ramstage_cache { + uint32_t magic; + uint32_t entry_point; + uint32_t load_address; + uint32_t size; + char program[0]; +} __attribute__((packed)); + +/* Chipset/Board function for obtaining cache location and size. */ +struct ramstage_cache *ramstage_cache_location(long *size); +/* Chipset/Board function called when cache is invalid on resume. */ +void ramstage_cache_invalid(struct ramstage_cache *cache); + +#endif /* _RAMSTAGE_CACHE_ */ diff --git a/src/lib/Makefile.inc b/src/lib/Makefile.inc index 37c7dea2ec..18b30efefa 100644 --- a/src/lib/Makefile.inc +++ b/src/lib/Makefile.inc @@ -119,6 +119,8 @@ romstage-y += hexdump.c ramstage-$(CONFIG_CONSOLE_NE2K) += ne2k.c +romstage-$(CONFIG_CACHE_RELOCATED_RAMSTAGE_OUTSIDE_CBMEM) += ramstage_cache.c + ifneq ($(CONFIG_HAVE_ARCH_MEMSET),y) smm-y += memset.c endif diff --git a/src/lib/cbfs.c b/src/lib/cbfs.c index d101f452ec..9fe1757a65 100644 --- a/src/lib/cbfs.c +++ b/src/lib/cbfs.c @@ -127,53 +127,6 @@ void *cbfs_load_optionrom(struct cbfs_media *media, uint16_t vendor, #include #include -/* When CONFIG_RELOCATABLE_RAMSTAGE is enabled and this file is being compiled - * for the romstage, the rmodule loader is used. */ -void __attribute__((weak)) -cache_loaded_ramstage(struct romstage_handoff *handoff, - const struct cbmem_entry *ramstage, void *entry_point) -{ - uint32_t ramstage_size; - const struct cbmem_entry *entry; - - if (handoff == NULL) - return; - - ramstage_size = cbmem_entry_size(ramstage); - /* cbmem_entry_add() does a find() before add(). */ - entry = cbmem_entry_add(CBMEM_ID_RAMSTAGE_CACHE, ramstage_size); - - if (entry == NULL) - return; - - /* Keep track of the entry point in the handoff structure. */ - handoff->ramstage_entry_point = (uint32_t)entry_point; - - memcpy(cbmem_entry_start(entry), cbmem_entry_start(ramstage), - ramstage_size); -} - -void * __attribute__((weak)) -load_cached_ramstage(struct romstage_handoff *handoff, - const struct cbmem_entry *ramstage) -{ - const struct cbmem_entry *entry_cache; - - if (handoff == NULL) - return NULL; - - entry_cache = cbmem_entry_find(CBMEM_ID_RAMSTAGE_CACHE); - - if (entry_cache == NULL) - return NULL; - - /* Load the cached ramstage copy into the to-be-run region. */ - memcpy(cbmem_entry_start(ramstage), cbmem_entry_start(entry_cache), - cbmem_entry_size(ramstage)); - - return (void *)handoff->ramstage_entry_point; -} - static void *load_stage_from_cbfs(struct cbfs_media *media, const char *name, struct romstage_handoff *handoff) { diff --git a/src/lib/ramstage_cache.c b/src/lib/ramstage_cache.c new file mode 100644 index 0000000000..a1a4804a16 --- /dev/null +++ b/src/lib/ramstage_cache.c @@ -0,0 +1,144 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include + +#if CONFIG_CACHE_RELOCATED_RAMSTAGE_OUTSIDE_CBMEM + +void cache_loaded_ramstage(struct romstage_handoff *handoff, + const struct cbmem_entry *ramstage, + void *entry_point) +{ + struct ramstage_cache *cache; + uint32_t total_size; + uint32_t ramstage_size; + void *ramstage_base; + long cache_size = 0; + + ramstage_size = cbmem_entry_size(ramstage); + ramstage_base = cbmem_entry_start(ramstage); + + cache = ramstage_cache_location(&cache_size); + + if (cache == NULL) { + printk(BIOS_DEBUG, "No ramstage cache location provided.\n"); + return; + } + + total_size = sizeof(*cache) + ramstage_size; + if (total_size > cache_size) { + printk(BIOS_DEBUG, "cache size too small: 0x%08x > 0x%08lx\n", + total_size, cache_size); + /* Nuke whatever may be there now just in case. */ + cache->magic = ~RAMSTAGE_CACHE_MAGIC; + return; + } + + cache->magic = RAMSTAGE_CACHE_MAGIC; + cache->entry_point = (uint32_t)entry_point; + cache->load_address = (uint32_t)ramstage_base; + cache->size = ramstage_size; + + printk(BIOS_DEBUG, "Saving ramstage to %p.\n", cache); + + /* Copy over the program. */ + memcpy(&cache->program[0], ramstage_base, ramstage_size); + + if (handoff == NULL) + return; + + handoff->ramstage_entry_point = (uint32_t)entry_point; +} + +void *load_cached_ramstage(struct romstage_handoff *handoff, + const struct cbmem_entry *ramstage) +{ + struct ramstage_cache *cache; + long size = 0; + + cache = ramstage_cache_location(&size); + + if (cache == NULL || cache->magic != RAMSTAGE_CACHE_MAGIC) { + printk(BIOS_DEBUG, "Invalid ramstage cache found.\n"); + ramstage_cache_invalid(cache); + return NULL; + } + + printk(BIOS_DEBUG, "Loading ramstage from %p.\n", cache); + + memcpy((void *)cache->load_address, &cache->program[0], cache->size); + + return (void *)cache->entry_point; +} + +#else + +/* Cache relocated ramstage in CBMEM. */ + +void __attribute__((weak)) +cache_loaded_ramstage(struct romstage_handoff *handoff, + const struct cbmem_entry *ramstage, void *entry_point) +{ + uint32_t ramstage_size; + const struct cbmem_entry *entry; + + if (handoff == NULL) + return; + + ramstage_size = cbmem_entry_size(ramstage); + /* cbmem_entry_add() does a find() before add(). */ + entry = cbmem_entry_add(CBMEM_ID_RAMSTAGE_CACHE, ramstage_size); + + if (entry == NULL) + return; + + /* Keep track of the entry point in the handoff structure. */ + handoff->ramstage_entry_point = (uint32_t)entry_point; + + memcpy(cbmem_entry_start(entry), cbmem_entry_start(ramstage), + ramstage_size); +} + +void * __attribute__((weak)) +load_cached_ramstage(struct romstage_handoff *handoff, + const struct cbmem_entry *ramstage) +{ + const struct cbmem_entry *entry_cache; + + if (handoff == NULL) + return NULL; + + entry_cache = cbmem_entry_find(CBMEM_ID_RAMSTAGE_CACHE); + + if (entry_cache == NULL) + return NULL; + + /* Load the cached ramstage copy into the to-be-run region. */ + memcpy(cbmem_entry_start(ramstage), cbmem_entry_start(entry_cache), + cbmem_entry_size(ramstage)); + + return (void *)handoff->ramstage_entry_point; +} + +#endif