Introduce a mechanism so that coreboot can provide a list of options to post-coreboot code. The options are grouped together into forms and have a meaning name and optional help text. This can be used to let payloads know which options should be displayed in a setup menu, for instance. Although this system was written to be used with edk2, it has been designed with flexibility in mind so that other payloads can also make use of this mechanism. The system currently lacks a way to describe where to find option values. This information is stored in a set of data structures specifically created for this purpose. This format is known as CFR, which means "coreboot forms representation" or "cursed forms representation". Although the "forms representation" is borrowed from UEFI, CFR can be used in non-UEFI scenarios as well. The data structures are implemented as an extension of cbtables records to support nesting. It should not break backwards compatibility because the CFR root record (LB_TAG_CFR_ROOT) size includes all of its children records. The concept of record nesting is borrowed from the records for CMOS options. It is not possible to reuse the CMOS records because they are too closely coupled with CMOS options; using these structures would needlessly restrict more capable backends to what can be done with CMOS options, which is undesired. Because CFR supports variable-length components, directly transforming options into CFR structures is not a trivial process. Furthermore, CFR structures need to be written in one go. Because of this, abstractions exist to generate CFR structures from a set of "setup menu" structures that are coreboot-specific and could be integrated with the devicetree at some point. Note that `struct sm_object` is a tagged union. This is used to have lists of options in an array, as building linked lists of options at runtime is extremely impractical because options would have to be added at the end of the linked list to maintain option order. To avoid mistakes defining `struct sm_object` values, helper macros exist for supported option types. The macros also provide some type checking as they initialise specific union members. It should be possible to extend CFR support for more sophisticated options like fan curve points. Feedback about this is highly appreciated. Change-Id: I304de7d26d79245a2e31a6d01f6c5643b31cb772 Signed-off-by: Angel Pons <th3fanbus@gmail.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/74121 Reviewed-by: Christian Walter <christian.walter@9elements.com> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
189 lines
4.3 KiB
Text
189 lines
4.3 KiB
Text
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
|
|
#include <memlayout.h>
|
|
|
|
/* This file is included inside a SECTIONS block */
|
|
|
|
/* First we place the code and read only data (typically const declared).
|
|
* This could theoretically be placed in rom.
|
|
* The '.' in '.text . : {' is actually significant to prevent missing some
|
|
* SoC's entry points due to artificial alignment restrictions, see
|
|
* https://sourceware.org/binutils/docs/ld/Output-Section-Address.html
|
|
*/
|
|
|
|
/* Starting with version 18 LLVM the combination -ffunction-section -mcmodel=large
|
|
* puts code and data in '.ltext, '.lrodata', '.ldata' and '.lbss'
|
|
*/
|
|
|
|
.text . : {
|
|
_program = .;
|
|
_text = .;
|
|
#if !(ENV_X86 && ENV_BOOTBLOCK)
|
|
*(.init._start);
|
|
*(.init);
|
|
*(.init.*);
|
|
#endif
|
|
*(.text._start);
|
|
*(.text.stage_entry);
|
|
KEEP(*(.metadata_hash_anchor));
|
|
*(.text);
|
|
*(.text.*);
|
|
*(.ltext);
|
|
*(.ltext.*);
|
|
|
|
#if ENV_HAS_CBMEM
|
|
. = ALIGN(ARCH_POINTER_ALIGN_SIZE);
|
|
_cbmem_init_hooks = .;
|
|
KEEP(*(.rodata.cbmem_init_hooks_early));
|
|
KEEP(*(.rodata.cbmem_init_hooks));
|
|
_ecbmem_init_hooks = .;
|
|
RECORD_SIZE(cbmem_init_hooks)
|
|
#endif
|
|
|
|
. = ALIGN(ARCH_POINTER_ALIGN_SIZE);
|
|
_rsbe_init_begin = .;
|
|
KEEP(*(.rsbe_init));
|
|
_ersbe_init_begin = .;
|
|
RECORD_SIZE(rsbe_init_begin)
|
|
|
|
#if ENV_RAMSTAGE
|
|
. = ALIGN(ARCH_POINTER_ALIGN_SIZE);
|
|
_pci_drivers = .;
|
|
KEEP(*(.rodata.pci_driver));
|
|
_epci_drivers = .;
|
|
RECORD_SIZE(pci_drivers)
|
|
. = ALIGN(ARCH_POINTER_ALIGN_SIZE);
|
|
_cpu_drivers = .;
|
|
KEEP(*(.rodata.cpu_driver));
|
|
_ecpu_drivers = .;
|
|
RECORD_SIZE(cpu_drivers)
|
|
. = ALIGN(ARCH_POINTER_ALIGN_SIZE);
|
|
_cfr_forms = .;
|
|
KEEP(*(.rodata.cfr_forms));
|
|
_ecfr_forms = .;
|
|
RECORD_SIZE(cfr_forms)
|
|
#endif
|
|
|
|
. = ALIGN(ARCH_POINTER_ALIGN_SIZE);
|
|
*(.rodata);
|
|
*(.rodata.*);
|
|
*(.lrodata);
|
|
*(.lrodata.*);
|
|
. = ALIGN(ARCH_POINTER_ALIGN_SIZE);
|
|
_etext = .;
|
|
RECORD_SIZE(text)
|
|
} : to_load
|
|
|
|
#if ENV_RAMSTAGE && (CONFIG(COVERAGE) || CONFIG(ASAN_IN_RAMSTAGE))
|
|
.ctors . : {
|
|
. = ALIGN(0x100);
|
|
__CTOR_LIST__ = .;
|
|
KEEP(*(.ctors));
|
|
LONG(0);
|
|
LONG(0);
|
|
__CTOR_END__ = .;
|
|
} : to_load
|
|
#endif
|
|
|
|
/* Include data, bss, and heap in that order. Not defined for all stages. */
|
|
#if !ENV_SEPARATE_DATA_AND_BSS
|
|
.data . : {
|
|
. = ALIGN(ARCH_CACHELINE_ALIGN_SIZE);
|
|
_data = .;
|
|
|
|
/*
|
|
* The postcar phase uses a stack value that is located in the relocatable
|
|
* module section. While the postcar stage could be linked like smm and
|
|
* other rmodules the postcar stage needs similar semantics of the more
|
|
* traditional stages in the coreboot infrastructure. Therefore it's easier
|
|
* to specialize this case.
|
|
*/
|
|
#if ENV_RMODULE || ENV_POSTCAR
|
|
_rmodule_params = .;
|
|
KEEP(*(.module_parameters));
|
|
_ermodule_params = .;
|
|
RECORD_SIZE(rmodule_params)
|
|
#endif
|
|
|
|
*(.data);
|
|
*(.data.*);
|
|
*(.ldata);
|
|
*(.ldata.*);
|
|
*(.sdata);
|
|
*(.sdata.*);
|
|
|
|
#if ENV_ROMSTAGE_OR_BEFORE
|
|
PROVIDE(_preram_cbmem_console = .);
|
|
PROVIDE(_epreram_cbmem_console = _preram_cbmem_console);
|
|
PROVIDE(_preram_cbmem_console_size = ABSOLUTE(0));
|
|
#elif ENV_RAMSTAGE
|
|
. = ALIGN(ARCH_POINTER_ALIGN_SIZE);
|
|
_bs_init_begin = .;
|
|
KEEP(*(.bs_init));
|
|
LONG(0);
|
|
LONG(0);
|
|
_ebs_init_begin = .;
|
|
RECORD_SIZE(bs_init_begin)
|
|
#endif
|
|
|
|
. = ALIGN(ARCH_POINTER_ALIGN_SIZE);
|
|
_edata = .;
|
|
RECORD_SIZE(data)
|
|
} : to_load
|
|
#endif
|
|
|
|
#if !ENV_SEPARATE_DATA_AND_BSS
|
|
.bss . (NOLOAD) : {
|
|
. = ALIGN(ARCH_POINTER_ALIGN_SIZE);
|
|
_bss = .;
|
|
*(.bss)
|
|
*(.bss.*)
|
|
*(.lbss)
|
|
*(.lbss.*)
|
|
*(.sbss)
|
|
*(.sbss.*)
|
|
. = ALIGN(ARCH_POINTER_ALIGN_SIZE);
|
|
_ebss = .;
|
|
RECORD_SIZE(bss)
|
|
} : to_load
|
|
#endif
|
|
|
|
#if ENV_HAS_HEAP_SECTION
|
|
.heap . (NOLOAD) : {
|
|
. = ALIGN(ARCH_POINTER_ALIGN_SIZE);
|
|
_heap = .;
|
|
. += CONFIG_HEAP_SIZE;
|
|
. = ALIGN(ARCH_POINTER_ALIGN_SIZE);
|
|
_eheap = .;
|
|
RECORD_SIZE(heap)
|
|
} : to_load
|
|
#endif
|
|
|
|
#if ENV_RAMSTAGE && CONFIG(ASAN_IN_RAMSTAGE)
|
|
_shadow_size = (_eheap - _data) >> 3;
|
|
REGION(asan_shadow, ., _shadow_size, ARCH_POINTER_ALIGN_SIZE)
|
|
#endif
|
|
|
|
_eprogram = .;
|
|
RECORD_SIZE(program)
|
|
|
|
/* The stage cache drops CONFIG_HEAP_SIZE bytes from the end of the in-memory
|
|
image of the ramstage, so ensure that when moving that many bytes backwards
|
|
from the program end, we're in the heap (or later), in some region that
|
|
doesn't contain initialized code or data. */
|
|
#if ENV_RAMSTAGE
|
|
_bogus = ASSERT(_eprogram - CONFIG_HEAP_SIZE >= _heap,
|
|
"HEAP_SIZE and heap misaligned");
|
|
#endif
|
|
|
|
/* Discard the sections we don't need/want */
|
|
|
|
zeroptr = 0;
|
|
|
|
/DISCARD/ : {
|
|
*(.comment)
|
|
*(.comment.*)
|
|
*(.note)
|
|
*(.note.*)
|
|
*(.eh_frame);
|
|
}
|