mb/google/nissa/var/rull: Configure Acoustic noise mitigation
[coreboot2.git] / src / soc / amd / common / block / apob / apob_cache.c
blob713826a297d67cfb14b9bd8bd2ba212ad8fe7bea
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 #include <acpi/acpi.h>
4 #include <amdblocks/apob_cache.h>
5 #include <assert.h>
6 #include <boot_device.h>
7 #include <bootstate.h>
8 #include <commonlib/helpers.h>
9 #include <commonlib/region.h>
10 #include <console/console.h>
11 #include <fmap.h>
12 #include <fmap_config.h>
13 #include <security/vboot/vboot_common.h>
14 #include <spi_flash.h>
15 #include <string.h>
16 #include <thread.h>
17 #include <timestamp.h>
18 #include <types.h>
19 #include <xxhash.h>
21 #define DEFAULT_MRC_CACHE "RW_MRC_CACHE"
22 #define DEFAULT_MRC_CACHE_SIZE FMAP_SECTION_RW_MRC_CACHE_SIZE
24 #if CONFIG(HAS_RECOVERY_MRC_CACHE)
25 #define RECOVERY_MRC_CACHE "RECOVERY_MRC_CACHE"
26 #define RECOVERY_MRC_CACHE_SIZE FMAP_SECTION_RECOVERY_MRC_CACHE_SIZE
27 #else
28 #define RECOVERY_MRC_CACHE DEFAULT_MRC_CACHE
29 #define RECOVERY_MRC_CACHE_SIZE DEFAULT_MRC_CACHE_SIZE
30 #endif
32 #if CONFIG(SOC_AMD_COMMON_BLOCK_APOB_HASH)
33 #define MRC_HASH_SIZE ((uint32_t)sizeof(uint64_t))
34 #else
35 #define MRC_HASH_SIZE 0
36 #endif
37 #define MRC_HASH_OFFSET (DEFAULT_MRC_CACHE_SIZE-MRC_HASH_SIZE)
38 #define MRC_HASH_UNINITIALIZED 0xffffffffull
40 #if !CONFIG_PSP_APOB_DRAM_ADDRESS
41 #error Incorrect APOB configuration setting(s)
42 #endif
44 _Static_assert(CONFIG_PSP_APOB_DRAM_SIZE == DEFAULT_MRC_CACHE_SIZE,
45 "APOB DRAM reserved space != to MRC CACHE size - check your config");
47 _Static_assert(CONFIG_PSP_APOB_DRAM_SIZE == RECOVERY_MRC_CACHE_SIZE,
48 "APOB DRAM reserved space != to RECOVERY MRC CACHE size - check your config");
50 #define APOB_SIGNATURE 0x424F5041 /* 'APOB' */
52 /* APOB_BASE_HEADER from AGESA */
53 struct apob_base_header {
54 uint32_t signature; /* APOB signature */
55 uint32_t version; /* Version */
56 uint32_t size; /* APOB Size */
57 uint32_t offset_of_first_entry; /* APOB Header Size */
60 static bool apob_header_valid(const struct apob_base_header *apob_header_ptr, const char *where)
62 uint32_t size_plus_hash = apob_header_ptr->size + MRC_HASH_SIZE;
64 if (apob_header_ptr->signature != APOB_SIGNATURE) {
65 printk(BIOS_WARNING, "Invalid %s APOB signature %x\n",
66 where, apob_header_ptr->signature);
67 return false;
70 if (apob_header_ptr->size == 0 || size_plus_hash > DEFAULT_MRC_CACHE_SIZE) {
71 printk(BIOS_WARNING, "%s APOB data is too large (%x + %x) > %x\n",
72 where, apob_header_ptr->size, MRC_HASH_SIZE, DEFAULT_MRC_CACHE_SIZE);
73 return false;
76 return true;
79 static void *get_apob_dram_address(void)
82 * TODO: Find the APOB destination by parsing the PSP's tables
83 * (once vboot is implemented).
85 void *apob_src_ram = (void *)(uintptr_t)CONFIG_PSP_APOB_DRAM_ADDRESS;
87 if (apob_header_valid(apob_src_ram, "RAM") == false)
88 return NULL;
90 return apob_src_ram;
93 static enum cb_err get_nv_rdev(struct region_device *r)
95 if (fmap_locate_area_as_rdev(vboot_recovery_mode_enabled() ?
96 RECOVERY_MRC_CACHE : DEFAULT_MRC_CACHE, r) < 0) {
97 printk(BIOS_ERR, "No APOB NV region is found in flash\n");
98 return CB_ERR;
101 return CB_SUCCESS;
104 static enum cb_err get_nv_rdev_rw(struct region_device *r)
106 if (fmap_locate_area_as_rdev_rw(vboot_recovery_mode_enabled() ?
107 RECOVERY_MRC_CACHE : DEFAULT_MRC_CACHE, r) < 0) {
108 printk(BIOS_ERR, "No APOB NV region is found in flash\n");
109 return CB_ERR;
112 return CB_SUCCESS;
115 static struct apob_thread_context {
116 uint8_t buffer[DEFAULT_MRC_CACHE_SIZE] __aligned(64);
117 struct thread_handle handle;
118 struct region_device apob_rdev;
119 } global_apob_thread;
121 static enum cb_err apob_thread_entry(void *arg)
123 ssize_t size;
124 struct apob_thread_context *thread = arg;
126 printk(BIOS_DEBUG, "APOB thread running\n");
127 size = rdev_readat(&thread->apob_rdev, thread->buffer, 0,
128 region_device_sz(&thread->apob_rdev));
130 printk(BIOS_DEBUG, "APOB thread done\n");
132 if (size == region_device_sz(&thread->apob_rdev))
133 return CB_SUCCESS;
135 return CB_ERR;
138 void start_apob_cache_read(void)
140 struct apob_thread_context *thread = &global_apob_thread;
142 if (!CONFIG(COOP_MULTITASKING) || CONFIG(SOC_AMD_COMMON_BLOCK_APOB_HASH))
143 return;
145 /* We don't perform any comparison on S3 resume */
146 if (acpi_is_wakeup_s3())
147 return;
149 if (get_nv_rdev(&thread->apob_rdev) != CB_SUCCESS)
150 return;
152 assert(ARRAY_SIZE(thread->buffer) == region_device_sz(&thread->apob_rdev));
154 printk(BIOS_DEBUG, "Starting APOB preload\n");
155 if (thread_run(&thread->handle, apob_thread_entry, thread))
156 printk(BIOS_ERR, "Failed to start APOB preload thread\n");
159 static void *get_apob_from_nv_rdev(struct region_device *read_rdev)
161 struct apob_base_header apob_header;
163 if (rdev_readat(read_rdev, &apob_header, 0, sizeof(apob_header)) < 0) {
164 printk(BIOS_ERR, "Couldn't read APOB header!\n");
165 return NULL;
168 if (apob_header_valid(&apob_header, "ROM") == false) {
169 printk(BIOS_ERR, "No APOB NV data!\n");
170 return NULL;
173 assert(CONFIG(BOOT_DEVICE_MEMORY_MAPPED));
174 return rdev_mmap_full(read_rdev);
177 static uint64_t get_apob_hash_from_nv_rdev(const struct region_device *read_rdev)
179 uint64_t hash;
181 if (rdev_readat(read_rdev, &hash, MRC_HASH_OFFSET, MRC_HASH_SIZE) < 0) {
182 printk(BIOS_ERR, "Couldn't read APOB hash!\n");
183 return MRC_HASH_UNINITIALIZED;
186 return hash;
189 static void update_apob_nv_hash(uint64_t hash, struct region_device *write_rdev)
191 if (rdev_writeat(write_rdev, &hash, MRC_HASH_OFFSET, MRC_HASH_SIZE) < 0) {
192 printk(BIOS_ERR, "APOB hash flash region update failed\n");
196 /* Save APOB buffer to flash */
197 static void soc_update_apob_cache(void *unused)
199 struct apob_base_header *apob_rom = NULL;
200 struct region_device read_rdev, write_rdev;
201 bool update_needed = false;
202 const struct apob_base_header *apob_src_ram;
203 uint64_t ram_hash, nv_hash;
205 /* Nothing to update in case of S3 resume. */
206 if (acpi_is_wakeup_s3())
207 return;
209 apob_src_ram = get_apob_dram_address();
210 if (apob_src_ram == NULL)
211 return;
213 if (get_nv_rdev(&read_rdev) != CB_SUCCESS)
214 return;
216 timestamp_add_now(TS_AMD_APOB_READ_START);
218 if (CONFIG(SOC_AMD_COMMON_BLOCK_APOB_HASH)) {
219 nv_hash = get_apob_hash_from_nv_rdev(&read_rdev);
220 ram_hash = xxh64(apob_src_ram, apob_src_ram->size, 0);
222 if (nv_hash != ram_hash) {
223 printk(BIOS_INFO, "APOB RAM hash differs from flash\n");
224 update_needed = true;
225 } else {
226 printk(BIOS_DEBUG, "APOB hash matches flash\n");
227 timestamp_add_now(TS_AMD_APOB_END);
228 return;
232 if (CONFIG(COOP_MULTITASKING) && thread_join(&global_apob_thread.handle) == CB_SUCCESS)
233 apob_rom = (struct apob_base_header *)global_apob_thread.buffer;
234 else if (!update_needed)
235 apob_rom = get_apob_from_nv_rdev(&read_rdev);
237 if (apob_rom == NULL) {
238 update_needed = true;
239 } else if (memcmp(apob_src_ram, apob_rom, apob_src_ram->size)) {
240 printk(BIOS_INFO, "APOB RAM copy differs from flash\n");
241 update_needed = true;
242 } else
243 printk(BIOS_DEBUG, "APOB valid copy is already in flash\n");
245 if (!update_needed) {
246 timestamp_add_now(TS_AMD_APOB_END);
247 return;
250 printk(BIOS_SPEW, "Copy APOB from RAM %p/%#x to flash %#zx/%#zx\n",
251 apob_src_ram, apob_src_ram->size,
252 region_device_offset(&read_rdev), region_device_sz(&read_rdev));
254 if (get_nv_rdev_rw(&write_rdev) != CB_SUCCESS)
255 return;
257 timestamp_add_now(TS_AMD_APOB_ERASE_START);
259 /* write data to flash region */
260 if (rdev_eraseat(&write_rdev, 0, DEFAULT_MRC_CACHE_SIZE) < 0) {
261 printk(BIOS_ERR, "APOB flash region erase failed\n");
262 return;
265 timestamp_add_now(TS_AMD_APOB_WRITE_START);
267 if (rdev_writeat(&write_rdev, apob_src_ram, 0, apob_src_ram->size) < 0) {
268 printk(BIOS_ERR, "APOB flash region update failed\n");
269 return;
272 if (CONFIG(SOC_AMD_COMMON_BLOCK_APOB_HASH))
273 update_apob_nv_hash(ram_hash, &write_rdev);
275 timestamp_add_now(TS_AMD_APOB_END);
277 printk(BIOS_INFO, "Updated APOB in flash\n");
280 static void *get_apob_nv_address(void)
282 struct region_device rdev;
284 if (get_nv_rdev(&rdev) != CB_SUCCESS)
285 return NULL;
287 return get_apob_from_nv_rdev(&rdev);
290 void *soc_fill_apob_cache(void)
292 /* If this is non-S3 boot, then use the APOB data placed by PSP in DRAM. */
293 if (!acpi_is_wakeup_s3())
294 return get_apob_dram_address();
297 * In case of S3 resume, PSP does not copy APOB data to DRAM. Thus, coreboot needs to
298 * provide the APOB NV data from RW_MRC_CACHE on SPI flash so that FSP can use it
299 * without having to traverse the BIOS directory table.
301 return get_apob_nv_address();
305 * BS_POST_DEVICE was chosen because this gives start_apob_cache_read plenty of time to read
306 * the APOB from SPI.
308 BOOT_STATE_INIT_ENTRY(BS_POST_DEVICE, BS_ON_EXIT, soc_update_apob_cache, NULL);