blob: 8559c06dfb588078af639764d63ee320e8be896b [file] [log] [blame]
Patrick Georgi11f00792020-03-04 15:10:45 +01001/* SPDX-License-Identifier: GPL-2.0-only */
Marshall Dawson991467d2018-09-04 12:32:56 -06002
Marshall Dawson991467d2018-09-04 12:32:56 -06003#include <cbmem.h>
4#include <console/console.h>
5#include <cpu/x86/name.h>
6#include <cpu/x86/msr.h>
7#include <cpu/x86/lapic.h>
Furquan Shaikh76cedd22020-05-02 10:24:23 -07008#include <acpi/acpi.h>
Marshall Dawson991467d2018-09-04 12:32:56 -06009#include <arch/bert_storage.h>
10#include <string.h>
Felix Held0a88c602021-05-27 20:16:45 +020011#include <types.h>
Marshall Dawson991467d2018-09-04 12:32:56 -060012
13/* BERT region management: Allow the chipset to determine the specific
14 * location of the BERT region. We find that base and size, then manage
15 * the allocation of error information within it.
16 *
17 * Use simple static variables for managing the BERT region. This is a thin
18 * implementation; it is only created and consumed by coreboot, and only in
19 * a single stage, and we don't want its information to survive reboot or
20 * resume cycles. If the requirements change, consider using IMD to help
21 * manage the space.
22 */
Felix Held0a88c602021-05-27 20:16:45 +020023static bool bert_region_broken;
Marshall Dawson991467d2018-09-04 12:32:56 -060024static void *bert_region_base;
25static size_t bert_region_size;
26static size_t bert_region_used;
27
28/* Calculate the remaining space in the BERT region. This knowledge may help
29 * the caller prioritize the information to store.
30 */
31size_t bert_storage_remaining(void)
32{
33 return bert_region_broken ? 0 : bert_region_size - bert_region_used;
34}
35
Felix Held0a88c602021-05-27 20:16:45 +020036bool bert_errors_present(void)
Marshall Dawson991467d2018-09-04 12:32:56 -060037{
Felix Held0a88c602021-05-27 20:16:45 +020038 return !bert_region_broken && bert_region_used;
Marshall Dawson991467d2018-09-04 12:32:56 -060039}
40
41void bert_errors_region(void **start, size_t *size)
42{
43 if (bert_region_broken) {
44 *start = NULL;
45 *size = 0;
46 return;
47 }
48
49 /* No metadata, etc. with our region, so this is easy */
50 *start = bert_region_base;
51 *size = bert_region_used;
52}
53
54static void *bert_allocate_storage(size_t size)
55{
56 size_t alloc;
57
58 if (bert_region_broken)
59 return NULL;
60 if (bert_region_used + size > bert_region_size)
61 return NULL;
62
63 alloc = bert_region_used;
64 bert_region_used += size;
65
66 return (void *)((u8 *)bert_region_base + alloc);
67}
68
69/* Generic Error Status: Each Status represents a unique error event within
70 * the BERT errors region. Each event may have multiple errors associated
71 * with it.
72 */
73
74/* Find the nth (1-based) Generic Data Structure attached to an Error Status */
75static void *acpi_hest_generic_data_nth(
76 acpi_generic_error_status_t *status, int num)
77{
78 acpi_hest_generic_data_v300_t *ptr;
79 size_t struct_size;
80
81 if (!num || num > bert_entry_count(status))
82 return NULL;
83
84 ptr = (acpi_hest_generic_data_v300_t *)(status + 1);
85 while (--num) {
86 if (ptr->revision == HEST_GENERIC_ENTRY_V300)
87 struct_size = sizeof(acpi_hest_generic_data_v300_t);
88 else
89 struct_size = sizeof(acpi_hest_generic_data_t);
90 ptr = (acpi_hest_generic_data_v300_t *)(
91 (u8 *)ptr
92 + ptr->data_length
93 + struct_size);
94 }
95 return ptr;
96}
97
98/* Update data_length for this Error Status, and final Data Entry it contains */
99static void revise_error_sizes(acpi_generic_error_status_t *status, size_t size)
100{
101 acpi_hest_generic_data_v300_t *entry;
102 int entries;
103
104 if (!status)
105 return;
106
107 entries = bert_entry_count(status);
108 entry = acpi_hest_generic_data_nth(status, entries);
109 status->data_length += size;
110 if (entry)
111 entry->data_length += size;
112}
113
114/* Create space for a new BERT Generic Error Status Block, by finding the next
115 * available slot and moving the ending location. There is nothing to designate
116 * this as another Generic Error Status Block (e.g. no signature); only that it
117 * is within the BERT region.
118 *
119 * It is up to the caller to correctly fill the information, including status
120 * and error severity, and to update/maintain data offsets and lengths as
121 * entries are added.
122 */
123static acpi_generic_error_status_t *new_bert_status(void)
124{
125 acpi_generic_error_status_t *status;
126
127 status = bert_allocate_storage(sizeof(*status));
128
129 if (!status) {
Julius Wernere9665952022-01-21 17:06:20 -0800130 printk(BIOS_ERR, "New BERT error entry would exceed available region\n");
Marshall Dawson991467d2018-09-04 12:32:56 -0600131 return NULL;
132 }
133
134 status->error_severity = ACPI_GENERROR_SEV_NONE;
135 return status;
136}
137
138/* Generic Error Data: Each Generic Error Status may contain zero or more
139 * Generic Error Data structures. The data structures describe particular
140 * error(s) associated with an event. The definition for the structure is
141 * found in the ACPI spec, however the data types and any accompanying data
142 * definitions are in the Common Platform Error Record appendix of the UEFI
143 * spec.
144 */
145
146/* Create space for a new BERT Generic Data Entry. Update the count and
147 * data length in the parent Generic Error Status Block. Version 0x300 of
148 * the structure is used, and the timestamp is filled and marked precise
149 * (i.e. assumed close enough for reporting).
150 *
151 * It is up to the caller to fill the Section Type field and add the Common
152 * Platform Error Record type data as appropriate. In addition, the caller
153 * should update the error severity, and may optionally add FRU information
154 * or override any existing information.
155 */
156static acpi_hest_generic_data_v300_t *new_generic_error_entry(
157 acpi_generic_error_status_t *status)
158{
159 acpi_hest_generic_data_v300_t *entry;
160
161 if (bert_entry_count(status) == GENERIC_ERR_STS_ENTRY_COUNT_MAX) {
Julius Wernere9665952022-01-21 17:06:20 -0800162 printk(BIOS_ERR, "New BERT error would exceed maximum entries\n");
Marshall Dawson991467d2018-09-04 12:32:56 -0600163 return NULL;
164 }
165
166 entry = bert_allocate_storage(sizeof(*entry));
167 if (!entry) {
Julius Wernere9665952022-01-21 17:06:20 -0800168 printk(BIOS_ERR, "New BERT error entry would exceed available region\n");
Marshall Dawson991467d2018-09-04 12:32:56 -0600169 return NULL;
170 }
171
172 entry->revision = HEST_GENERIC_ENTRY_V300;
173
174 entry->timestamp = cper_timestamp(CPER_TIMESTAMP_PRECISE);
175 entry->validation_bits |= ACPI_GENERROR_VALID_TIMESTAMP;
176
177 status->data_length += sizeof(*entry);
178 bert_bump_entry_count(status);
179
180 return entry;
181}
182
183/* Find the size of a CPER error section w/o any add-ons */
184static size_t sizeof_error_section(guid_t *guid)
185{
186 if (!guidcmp(guid, &CPER_SEC_PROC_GENERIC_GUID))
187 return sizeof(cper_proc_generic_error_section_t);
188 else if (!guidcmp(guid, &CPER_SEC_PROC_IA32X64_GUID))
189 return sizeof(cper_ia32x64_proc_error_section_t);
Francois Toguo522e0db2021-01-21 09:55:19 -0800190 else if (!guidcmp(guid, &CPER_SEC_FW_ERR_REC_REF_GUID))
191 return sizeof(cper_fw_err_rec_section_t);
Marshall Dawson991467d2018-09-04 12:32:56 -0600192 /* else if ... sizeof(structures not yet defined) */
193
Julius Wernere9665952022-01-21 17:06:20 -0800194 printk(BIOS_ERR, "Requested size of unrecognized CPER GUID\n");
Marshall Dawson991467d2018-09-04 12:32:56 -0600195 return 0;
196}
197
Francois Toguo522e0db2021-01-21 09:55:19 -0800198void *new_cper_fw_error_crashlog(acpi_generic_error_status_t *status, size_t cl_size)
199{
200 void *cl_data = bert_allocate_storage(cl_size);
201 if (!cl_data) {
Julius Wernere9665952022-01-21 17:06:20 -0800202 printk(BIOS_ERR, "Crashlog entry (size %zu) would exceed available region\n",
Francois Toguo522e0db2021-01-21 09:55:19 -0800203 cl_size);
204 return NULL;
205 }
206
207 revise_error_sizes(status, cl_size);
208
209 return cl_data;
210}
211
212/* Helper to append an ACPI Generic Error Data Entry per crashlog data */
213acpi_hest_generic_data_v300_t *bert_append_fw_err(acpi_generic_error_status_t *status)
214{
215 acpi_hest_generic_data_v300_t *entry;
216 cper_fw_err_rec_section_t *fw_err;
217
218 entry = bert_append_error_datasection(status, &CPER_SEC_FW_ERR_REC_REF_GUID);
219 if (!entry)
220 return NULL;
221
222 status->block_status |= GENERIC_ERR_STS_UNCORRECTABLE_VALID;
223 status->error_severity = ACPI_GENERROR_SEV_FATAL;
224 entry->error_severity = ACPI_GENERROR_SEV_FATAL;
225
226 fw_err = section_of_acpientry(fw_err, entry);
227
228 fw_err->record_type = CRASHLOG_RECORD_TYPE;
229 fw_err->revision = CRASHLOG_FW_ERR_REV;
230 fw_err->record_id = 0;
231 guidcpy(&fw_err->record_guid, &FW_ERR_RECORD_ID_CRASHLOG_GUID);
232
233 return entry;
234}
235
Marshall Dawson991467d2018-09-04 12:32:56 -0600236/* Append a new ACPI Generic Error Data Entry plus CPER Error Section to an
237 * existing ACPI Generic Error Status Block. The caller is responsible for
238 * the setting the status and entry severity, as well as populating all fields
239 * of the error section.
240 */
241acpi_hest_generic_data_v300_t *bert_append_error_datasection(
242 acpi_generic_error_status_t *status, guid_t *guid)
243{
244 acpi_hest_generic_data_v300_t *entry;
245 void *sect;
246 size_t sect_size;
247
248 sect_size = sizeof_error_section(guid);
249 if (!sect_size)
250 return NULL; /* Don't allocate structure if bad GUID passed */
251
252 if (sizeof(*entry) + sect_size > bert_storage_remaining())
253 return NULL;
254
255 entry = new_generic_error_entry(status);
256 if (!entry)
257 return NULL;
258
259 /* error section immediately follows the Generic Error Data Entry */
260 sect = bert_allocate_storage(sect_size);
261 if (!sect)
262 return NULL;
263
264 revise_error_sizes(status, sect_size);
265
266 guidcpy(&entry->section_type, guid);
267 return entry;
268}
269
270/* Helper to append an ACPI Generic Error Data Entry plus a CPER Processor
271 * Generic Error Section. As many fields are populated as possible for the
272 * caller.
273 */
274acpi_hest_generic_data_v300_t *bert_append_genproc(
275 acpi_generic_error_status_t *status)
276{
277 acpi_hest_generic_data_v300_t *entry;
278 cper_proc_generic_error_section_t *ges;
279
280 entry = bert_append_error_datasection(status,
281 &CPER_SEC_PROC_GENERIC_GUID);
282 if (!entry)
283 return NULL;
284
285 status->block_status |= GENERIC_ERR_STS_UNCORRECTABLE_VALID;
286 status->error_severity = ACPI_GENERROR_SEV_FATAL;
287
288 entry->error_severity = ACPI_GENERROR_SEV_FATAL;
289
290 ges = section_of_acpientry(ges, entry);
291
292 ges->proc_type = GENPROC_PROCTYPE_IA32X64;
293 ges->validation |= GENPROC_VALID_PROC_TYPE;
294
295 ges->cpu_version = cpuid_eax(1);
296 ges->validation |= GENPROC_VALID_CPU_VERSION;
297
298 fill_processor_name(ges->cpu_brand_string);
299 ges->validation |= GENPROC_VALID_CPU_BRAND;
300
301 ges->proc_id = lapicid();
302 ges->validation |= GENPROC_VALID_CPU_ID;
303
304 return entry;
305}
306
307/* Add a new IA32/X64 Processor Context Structure (Table 261), following any
308 * other contexts, to an existing Processor Error Section (Table 255). Contexts
309 * may only be added after the entire Processor Error Info array has been
310 * created.
311 *
312 * This function fills only the minimal amount of information required to parse
313 * or step through the contexts. The type is filled and PROC_CONTEXT_INFO_NUM
314 * is updated.
315 *
316 * type is one of:
317 * CPER_IA32X64_CTX_UNCL
318 * CPER_IA32X64_CTX_MSR
319 * CPER_IA32X64_CTX_32BIT_EX
320 * CPER_IA32X64_CTX_64BIT_EX
321 * CPER_IA32X64_CTX_FXSAVE
322 * CPER_IA32X64_CTX_32BIT_DBG
323 * CPER_IA32X64_CTX_64BIT_DBG
324 * CPER_IA32X64_CTX_MEMMAPPED
325 * num is the number of bytes eventually used to fill the context's register
326 * array, e.g. 4 MSRs * sizeof(msr_t)
327 *
328 * status and entry data_length values are updated.
329 */
330cper_ia32x64_context_t *new_cper_ia32x64_ctx(
331 acpi_generic_error_status_t *status,
332 cper_ia32x64_proc_error_section_t *x86err, int type, int num)
333{
334 size_t size;
335 cper_ia32x64_context_t *ctx;
336 static const char * const ctx_names[] = {
337 "Unclassified Data",
338 "MSR Registers",
339 "32-bit Mode Execution",
340 "64-bit Mode Execution",
Richard Spiegelc75f2d82018-09-14 08:27:50 -0700341 "FXSAVE",
342 "32-bit Mode Debug",
343 "64-bit Mode Debug",
Marshall Dawson991467d2018-09-04 12:32:56 -0600344 "Memory Mapped"
345 };
346
347 if (type > CPER_IA32X64_CTX_MEMMAPPED)
348 return NULL;
349
350 if (cper_ia32x64_proc_num_ctxs(x86err) == I32X64SEC_VALID_CTXNUM_MAX) {
Julius Wernere9665952022-01-21 17:06:20 -0800351 printk(BIOS_ERR, "New IA32X64 %s context entry would exceed max allowable contexts\n",
Marshall Dawson991467d2018-09-04 12:32:56 -0600352 ctx_names[type]);
353 return NULL;
354 }
355
356 size = cper_ia32x64_ctx_sz_bytype(type, num);
357 ctx = bert_allocate_storage(size);
358 if (!ctx) {
Julius Wernere9665952022-01-21 17:06:20 -0800359 printk(BIOS_ERR, "New IA32X64 %s context entry would exceed available region\n",
Marshall Dawson991467d2018-09-04 12:32:56 -0600360 ctx_names[type]);
361 return NULL;
362 }
363
364 revise_error_sizes(status, size);
365
366 ctx->type = type;
367 ctx->array_size = num;
368 cper_bump_ia32x64_ctx_count(x86err);
369
370 return ctx;
371}
372
373/* Add a new IA32/X64 Processor Error Information Structure (Table 256),
374 * following any other errors, to an existing Processor Error Section
375 * (Table 255). All error structures must be added before any contexts are
376 * added.
377 *
378 * This function fills only the minimal amount of information required to parse
379 * or step through the errors. The type is filled and PROC_ERR_INFO_NUM is
380 * updated.
381 */
382cper_ia32x64_proc_error_info_t *new_cper_ia32x64_check(
383 acpi_generic_error_status_t *status,
384 cper_ia32x64_proc_error_section_t *x86err,
385 enum cper_x86_check_type type)
386{
387 cper_ia32x64_proc_error_info_t *check;
388 static const char * const check_names[] = {
389 "cache",
390 "TLB",
391 "bus",
392 "MS"
393 };
394 const guid_t check_guids[] = {
395 X86_PROCESSOR_CACHE_CHK_ERROR_GUID,
396 X86_PROCESSOR_TLB_CHK_ERROR_GUID,
397 X86_PROCESSOR_BUS_CHK_ERROR_GUID,
398 X86_PROCESSOR_MS_CHK_ERROR_GUID
399 };
400
401 if (type > X86_PROCESSOR_CHK_MAX)
402 return NULL;
403
404 if (cper_ia32x64_proc_num_chks(x86err) == I32X64SEC_VALID_ERRNUM_MAX) {
Julius Wernere9665952022-01-21 17:06:20 -0800405 printk(BIOS_ERR, "New IA32X64 %s check entry would exceed max allowable errors\n",
Marshall Dawson991467d2018-09-04 12:32:56 -0600406 check_names[type]);
407 return NULL;
408 }
409
410 check = bert_allocate_storage(sizeof(*check));
411 if (!check) {
Julius Wernere9665952022-01-21 17:06:20 -0800412 printk(BIOS_ERR, "New IA32X64 %s check entry would exceed available region\n",
Marshall Dawson991467d2018-09-04 12:32:56 -0600413 check_names[type]);
414 return NULL;
415 }
416
417 revise_error_sizes(status, sizeof(*check));
418
419 guidcpy(&check->type, &check_guids[type]);
420 cper_bump_ia32x64_chk_count(x86err);
421
422 return check;
423}
424
425/* Helper to append an ACPI Generic Error Data Entry plus a CPER IA32/X64
426 * Processor Error Section. As many fields are populated as possible for the
427 * caller.
428 */
429acpi_hest_generic_data_v300_t *bert_append_ia32x64(
430 acpi_generic_error_status_t *status)
431{
432 acpi_hest_generic_data_v300_t *entry;
433 cper_ia32x64_proc_error_section_t *ipe;
434 struct cpuid_result id;
435
436 entry = bert_append_error_datasection(status,
437 &CPER_SEC_PROC_IA32X64_GUID);
438 if (!entry)
439 return NULL;
440
441 status->block_status |= GENERIC_ERR_STS_UNCORRECTABLE_VALID;
442 status->error_severity = ACPI_GENERROR_SEV_FATAL;
443
444 entry->error_severity = ACPI_GENERROR_SEV_FATAL;
445
446 ipe = section_of_acpientry(ipe, entry);
447
448 ipe->apicid = lapicid();
449 ipe->validation |= I32X64SEC_VALID_LAPIC;
450
451 id = cpuid(1);
452 ipe->cpuid[0] = id.eax;
453 ipe->cpuid[1] = id.ebx;
454 ipe->cpuid[2] = id.ecx;
455 ipe->cpuid[3] = id.edx;
456 ipe->validation |= I32X64SEC_VALID_CPUID;
457
458 return entry;
459}
460
461static const char * const generic_error_types[] = {
462 "PROCESSOR_GENERIC",
463 "PROCESSOR_SPECIFIC_X86",
464 "PROCESSOR_SPECIFIC_ARM",
465 "PLATFORM_MEMORY",
466 "PLATFORM_MEMORY2",
467 "PCIE",
468 "FW_ERROR_RECORD",
469 "PCI_PCIX_BUS",
470 "PCI_DEVICE",
471 "DMAR_GENERIC",
472 "DIRECTED_IO_DMAR",
473 "IOMMU_DMAR",
474 "UNRECOGNIZED"
475};
476
477static const char *generic_error_name(guid_t *guid)
478{
479 if (!guidcmp(guid, &CPER_SEC_PROC_GENERIC_GUID))
480 return generic_error_types[0];
481 if (!guidcmp(guid, &CPER_SEC_PROC_IA32X64_GUID))
482 return generic_error_types[1];
483 if (!guidcmp(guid, &CPER_SEC_PROC_ARM_GUID))
484 return generic_error_types[2];
485 if (!guidcmp(guid, &CPER_SEC_PLATFORM_MEM_GUID))
486 return generic_error_types[3];
487 if (!guidcmp(guid, &CPER_SEC_PLATFORM_MEM2_GUID))
488 return generic_error_types[4];
489 if (!guidcmp(guid, &CPER_SEC_PCIE_GUID))
490 return generic_error_types[5];
491 if (!guidcmp(guid, &CPER_SEC_FW_ERR_REC_REF_GUID))
492 return generic_error_types[6];
493 if (!guidcmp(guid, &CPER_SEC_PCI_X_BUS_GUID))
494 return generic_error_types[7];
495 if (!guidcmp(guid, &CPER_SEC_PCI_DEV_GUID))
496 return generic_error_types[8];
497 if (!guidcmp(guid, &CPER_SEC_DMAR_GENERIC_GUID))
498 return generic_error_types[9];
499 if (!guidcmp(guid, &CPER_SEC_DMAR_VT_GUID))
500 return generic_error_types[10];
501 if (!guidcmp(guid, &CPER_SEC_DMAR_IOMMU_GUID))
502 return generic_error_types[11];
503 return generic_error_types[12];
504}
505
506/* Add a new event to the BERT region. An event consists of an ACPI Error
507 * Status Block, a Generic Error Data Entry, and an associated CPER Error
508 * Section.
509 */
510acpi_generic_error_status_t *bert_new_event(guid_t *guid)
511{
512 size_t size;
513 acpi_generic_error_status_t *status;
514 acpi_hest_generic_data_v300_t *entry, *r;
515
516 size = sizeof(*status);
517 size += sizeof(*entry);
518 size += sizeof_error_section(guid);
519
520 if (size > bert_storage_remaining()) {
Julius Wernere9665952022-01-21 17:06:20 -0800521 printk(BIOS_ERR, "Not enough BERT region space to add event for type %s\n",
Marshall Dawson991467d2018-09-04 12:32:56 -0600522 generic_error_name(guid));
523 return NULL;
524 }
525
526 status = new_bert_status();
527 if (!status)
528 return NULL;
529
530 if (!guidcmp(guid, &CPER_SEC_PROC_GENERIC_GUID))
531 r = bert_append_genproc(status);
532 else if (!guidcmp(guid, &CPER_SEC_PROC_GENERIC_GUID))
533 r = bert_append_ia32x64(status);
Lijian Zhao94e49612021-02-06 12:18:12 +0800534 else if (!guidcmp(guid, &CPER_SEC_FW_ERR_REC_REF_GUID))
Francois Toguo522e0db2021-01-21 09:55:19 -0800535 r = bert_append_fw_err(status);
Marshall Dawson991467d2018-09-04 12:32:56 -0600536 /* else if other types not implemented */
537 else
538 r = NULL;
539
540 if (r)
541 return status;
542 return NULL;
543}
544
545/* Helper to add an MSR context to an existing IA32/X64-type error entry */
546cper_ia32x64_context_t *cper_new_ia32x64_context_msr(
547 acpi_generic_error_status_t *status,
548 cper_ia32x64_proc_error_section_t *x86err, u32 addr, int num)
549{
550 cper_ia32x64_context_t *ctx;
551 int i;
552 msr_t *dest;
553
554 ctx = new_cper_ia32x64_ctx(status, x86err, CPER_IA32X64_CTX_MSR, num);
555 if (!ctx)
556 return NULL;
557
558 /* already filled ctx->type = CPER_IA32X64_CTX_MSR; */
559 ctx->msr_addr = addr;
560 ctx->array_size = num * sizeof(msr_t);
561
562 dest = (msr_t *)((u8 *)(ctx + 1)); /* point to the Register Array */
563
564 for (i = 0 ; i < num ; i++)
565 *(dest + i) = rdmsr(addr + i);
566 return ctx;
567}
568
569/* The region must be in memory marked as reserved. If not implemented,
570 * skip generating the information in the region.
571 */
572__weak void bert_reserved_region(void **start, size_t *size)
573{
Julius Wernere9665952022-01-21 17:06:20 -0800574 printk(BIOS_ERR, "%s not implemented. BERT region generation disabled\n",
Marshall Dawson991467d2018-09-04 12:32:56 -0600575 __func__);
576 *start = NULL;
577 *size = 0;
578}
579
580static void bert_storage_setup(int unused)
581{
582 /* Always start with a blank bert region. Make sure nothing is
583 * maintained across reboots or resumes.
584 */
Felix Held0a88c602021-05-27 20:16:45 +0200585 bert_region_broken = false;
Marshall Dawson991467d2018-09-04 12:32:56 -0600586 bert_region_used = 0;
587
588 bert_reserved_region(&bert_region_base, &bert_region_size);
589
590 if (!bert_region_base || !bert_region_size) {
591 printk(BIOS_ERR, "Bug: Can't find/add BERT storage area\n");
Felix Held0a88c602021-05-27 20:16:45 +0200592 bert_region_broken = true;
Marshall Dawson991467d2018-09-04 12:32:56 -0600593 return;
594 }
595
596 memset(bert_region_base, 0, bert_region_size);
597}
598
599RAMSTAGE_CBMEM_INIT_HOOK(bert_storage_setup)