Recommonmark has been deprecated since 2021 [1] and the last release was over 3 years ago [2]. As per their announcement, Markedly Structured Text (MyST) Parser [3] is the recommended replacement. For the most part, the existing documentation is compatible with MyST, as both parsers are built around the CommonMark flavor of Markdown. The main difference that affects coreboot is how the Sphinx toctree is generated. Recommonmark has a feature called auto_toc_tree, which converts single level lists of references into a toctree: * [Part 1: Starting from scratch](part1.md) * [Part 2: Submitting a patch to coreboot.org](part2.md) * [Part 3: Writing unit tests](part3.md) * [Managing local additions](managing_local_additions.md) * [Flashing firmware](flashing_firmware/index.md) MyST Parser does not provide a replacement for this feature, meaning the toctree must be defined manually. This is done using MyST's syntax for Sphinx directives: ```{toctree} :maxdepth: 1 Part 1: Starting from scratch <part1.md> Part 2: Submitting a patch to coreboot.org <part2.md> Part 3: Writing unit tests <part3.md> Managing local additions <managing_local_additions.md> Flashing firmware <flashing_firmware/index.md> ``` Internally, auto_toc_tree essentially converts lists of references into the Sphinx toctree structure that the MyST syntax above more directly represents. The toctrees were converted to the MyST syntax using the following command and Python script: `find ./ -iname "*.md" | xargs -n 1 python conv_toctree.py` ``` import re import sys in_list = False f = open(sys.argv[1]) lines = f.readlines() f.close() with open(sys.argv[1], "w") as f: for line in lines: match = re.match(r"^[-*+] \[(.*)\]\((.*)\)$", line) if match is not None: if not in_list: in_list = True f.write("```{toctree}\n") f.write(":maxdepth: 1\n\n") f.write(match.group(1) + " <" + match.group(2) + ">\n") else: if in_list: f.write("```\n") f.write(line) in_list = False if in_list: f.write("```\n") ``` While this does add a little more work for creating the toctree, this does give more control over exactly what goes into the toctree. For instance, lists of links to external resources currently end up in the toctree, but we may want to limit it to pages within coreboot. This change does break rendering and navigation of the documentation in applications that can render Markdown, such as Okular, Gitiles, or the GitHub mirror. Assuming the docs are mainly intended to be viewed after being rendered to doc.coreboot.org, this is probably not an issue in practice. Another difference is that MyST natively supports Markdown tables, whereas with Recommonmark, tables had to be written in embedded rST [4]. However, MyST also supports embedded rST, so the existing tables can be easily converted as the syntax is nearly identical. These were converted using `find ./ -iname "*.md" | xargs -n 1 sed -i "s/eval_rst/{eval-rst}/"` Makefile.sphinx and conf.py were regenerated from scratch by running `sphinx-quickstart` using the updated version of Sphinx, which removes a lot of old commented out boilerplate. Any relevant changes coreboot had made on top of the previous autogenerated versions of these files were ported over to the newly generated file. From some initial testing the generated webpages appear and function identically to the existing documentation built with Recommonmark. TEST: `make -C util/docker docker-build-docs` builds the documentation successfully and the generated output renders properly when viewed in a web browser. [1] https://github.com/readthedocs/recommonmark/issues/221 [2] https://pypi.org/project/recommonmark/ [3] https://myst-parser.readthedocs.io/en/latest/ [4] https://doc.coreboot.org/getting_started/writing_documentation.html Change-Id: I0837c1722fa56d25c9441ea218e943d8f3d9b804 Signed-off-by: Nicholas Chin <nic.c3.14@gmail.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/73158 Reviewed-by: Matt DeVillier <matt.devillier@gmail.com> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
226 lines
7.5 KiB
Markdown
226 lines
7.5 KiB
Markdown
# SMM based flash storage driver Version 2
|
|
|
|
This documents the API exposed by the x86 system management based
|
|
storage driver.
|
|
|
|
## SMMSTOREv2
|
|
|
|
SMMSTOREv2 is a [SMM] mediated driver to read from, write to and erase
|
|
a predefined region in flash. It can be enabled by setting
|
|
`CONFIG_SMMSTORE=y` and `CONFIG_SMMSTORE_V2=y` in menuconfig.
|
|
|
|
This can be used by the OS or the payload to implement persistent
|
|
storage to hold for instance configuration data, without needing to
|
|
implement a (platform specific) storage driver in the payload itself.
|
|
|
|
### Storage size and alignment
|
|
|
|
SMMSTORE version 2 requires a minimum alignment of 64 KiB, which should
|
|
be supported by all flash chips. Not having to perform read-modify-write
|
|
operations is desired, as it reduces complexity and potential for bugs.
|
|
|
|
This can be used by a FTW (FaultTolerantWrite) implementation that uses
|
|
at least two regions in an A/B update scheme. The FTW implementation in
|
|
edk2 uses three different regions in the store:
|
|
|
|
- The variable store
|
|
- The FTW spare block
|
|
- The FTW working block
|
|
|
|
All regions must be block-aligned, and the FTW spare size must be larger
|
|
than that of the variable store. FTW working block can be much smaller.
|
|
With 64 KiB as block size, the minimum size of the FTW-enabled store is:
|
|
|
|
- The variable store: 1 block = 64 KiB
|
|
- The FTW spare block: 2 blocks = 2 * 64 KiB
|
|
- The FTW working block: 1 block = 64 KiB
|
|
|
|
Therefore, the minimum size for edk2 FTW is 4 blocks, or 256 KiB.
|
|
|
|
## API
|
|
|
|
The API provides read and write access to an unformatted block storage.
|
|
|
|
### Storage region
|
|
|
|
By default SMMSTOREv2 will operate on a separate FMAP region called
|
|
`SMMSTORE`. The default generated FMAP will include such a region. On
|
|
systems with a locked FMAP, e.g. in an existing vboot setup with a
|
|
locked RO region, the option exists to add a cbfsfile called `smm_store`
|
|
in the `RW_LEGACY` (if CHROMEOS) or in the `COREBOOT` FMAP regions. It
|
|
is recommended for new builds using a handcrafted FMD that intend to
|
|
make use of SMMSTORE to include a sufficiently large `SMMSTORE` FMAP
|
|
region. It is mandatory to align the `SMMSTORE` region to 64KiB for
|
|
compatibility with the largest flash erase operation.
|
|
|
|
When a default generated FMAP is used, the size of the FMAP region is
|
|
equal to `CONFIG_SMMSTORE_SIZE`. UEFI payloads expect at least 64 KiB.
|
|
To support a fault tolerant write mechanism, at least a multiple of
|
|
this size is recommended.
|
|
|
|
### Communication buffer
|
|
|
|
To prevent malicious ring0 code to access arbitrary memory locations,
|
|
SMMSTOREv2 uses a communication buffer in CBMEM/HOB for all transfers.
|
|
This buffer has to be at least 64 KiB in size and must be installed
|
|
before calling any of the SMMSTORE read or write operations. Usually,
|
|
coreboot will install this buffer to transfer data between ring0 and
|
|
the [SMM] handler.
|
|
|
|
In order to get the communication buffer address, the payload or OS
|
|
has to read the coreboot table with tag `0x0039`, containing:
|
|
|
|
```C
|
|
struct lb_smmstorev2 {
|
|
uint32_t tag;
|
|
uint32_t size;
|
|
uint32_t num_blocks; /* Number of writeable blocks in SMM */
|
|
uint32_t block_size; /* Size of a block in byte. Default: 64 KiB */
|
|
uint32_t mmap_addr; /* MMIO address of the store for read only access */
|
|
uint32_t com_buffer; /* Physical address of the communication buffer */
|
|
uint32_t com_buffer_size; /* Size of the communication buffer in byte */
|
|
uint8_t apm_cmd; /* The command byte to write to the APM I/O port */
|
|
uint8_t unused[3]; /* Set to zero */
|
|
};
|
|
```
|
|
|
|
The absence of this coreboot table entry indicates that there's no
|
|
SMMSTOREv2 support.
|
|
|
|
### Blocks
|
|
|
|
The SMMSTOREv2 splits the SMMSTORE FMAP partition into smaller chunks
|
|
called *blocks*. Every block is at least the size of 64KiB to support
|
|
arbitrary NOR flash erase ops. A payload or OS must make no further
|
|
assumptions about the block or communication buffer size.
|
|
|
|
### Generating the SMI
|
|
|
|
SMMSTOREv2 is called via an SMI, which is generated via a write to the
|
|
IO port defined in the smi_cmd entry of the FADT ACPI table. `%al`
|
|
contains `APM_CNT_SMMSTORE=0xed` and is written to the smi_cmd IO
|
|
port. `%ah` contains the SMMSTOREv2 command. `%ebx` contains the
|
|
parameter buffer to the SMMSTOREv2 command.
|
|
|
|
### Return values
|
|
|
|
If a command succeeds, SMMSTOREv2 will return with
|
|
`SMMSTORE_RET_SUCCESS=0` in `%eax`. On failure SMMSTORE will return
|
|
`SMMSTORE_RET_FAILURE=1`. For unsupported SMMSTORE commands
|
|
`SMMSTORE_REG_UNSUPPORTED=2` is returned.
|
|
|
|
**NOTE 1**: The caller **must** check the return value and should make
|
|
no assumption on the returned data if `%eax` does not contain
|
|
`SMMSTORE_RET_SUCCESS`.
|
|
|
|
**NOTE 2**: If the SMI returns without changing `%ax`, it can be assumed
|
|
that the SMMSTOREv2 feature is not installed.
|
|
|
|
### Calling arguments
|
|
|
|
SMMSTOREv2 supports 3 subcommands that are passed via `%ah`, the
|
|
additional calling arguments are passed via `%ebx`.
|
|
|
|
**NOTE**: The size of the struct entries are in the native word size of
|
|
smihandler. This means 32 bits in almost all cases.
|
|
|
|
#### - SMMSTORE_CMD_INIT = 4
|
|
|
|
This installs the communication buffer to use and thus enables the
|
|
SMMSTORE handler. This command can only be executed once and is done
|
|
by the firmware. Calling this function at runtime has no effect.
|
|
|
|
The additional parameter buffer `%ebx` contains a pointer to the
|
|
following struct:
|
|
|
|
```C
|
|
struct smmstore_params_init {
|
|
uint32_t com_buffer;
|
|
uint32_t com_buffer_size;
|
|
} __packed;
|
|
```
|
|
|
|
INPUT:
|
|
- `com_buffer`: Physical address of the communication buffer (CBMEM)
|
|
- `com_buffer_size`: Size in bytes of the communication buffer
|
|
|
|
#### - SMMSTORE_CMD_RAW_READ = 5
|
|
|
|
SMMSTOREv2 allows reading arbitrary data. It is up to the caller to
|
|
initialize the store with meaningful data before using it.
|
|
|
|
The additional parameter buffer `%ebx` contains a pointer to the
|
|
following struct:
|
|
|
|
```C
|
|
struct smmstore_params_raw_read {
|
|
uint32_t bufsize;
|
|
uint32_t bufoffset;
|
|
uint32_t block_id;
|
|
} __packed;
|
|
```
|
|
|
|
INPUT:
|
|
- `bufsize`: Size of data to read within the communication buffer
|
|
- `bufoffset`: Offset within the communication buffer
|
|
- `block_id`: Block to read from
|
|
|
|
#### - SMMSTORE_CMD_RAW_WRITE = 6
|
|
|
|
SMMSTOREv2 allows writing arbitrary data. It is up to the caller to
|
|
erase a block before writing it.
|
|
|
|
The additional parameter buffer `%ebx` contains a pointer to
|
|
the following struct:
|
|
|
|
```C
|
|
struct smmstore_params_raw_write {
|
|
uint32_t bufsize;
|
|
uint32_t bufoffset;
|
|
uint32_t block_id;
|
|
} __packed;
|
|
```
|
|
|
|
INPUT:
|
|
- `bufsize`: Size of data to write within the communication buffer
|
|
- `bufoffset`: Offset within the communication buffer
|
|
- `block_id`: Block to write to
|
|
|
|
#### - SMMSTORE_CMD_RAW_CLEAR = 7
|
|
|
|
SMMSTOREv2 allows clearing blocks. A cleared block will read as `0xff`.
|
|
By providing multiple blocks the caller can implement a fault tolerant
|
|
write mechanism. It is up to the caller to clear blocks before writing
|
|
to them.
|
|
|
|
|
|
```C
|
|
struct smmstore_params_raw_clear {
|
|
uint32_t block_id;
|
|
} __packed;
|
|
```
|
|
|
|
INPUT:
|
|
- `block_id`: Block to erase
|
|
|
|
#### Security
|
|
|
|
Pointers provided by the payload or OS are checked to not overlap with
|
|
SMM. This protects the SMM handler from being compromised.
|
|
|
|
As all information is exchanged using the communication buffer and
|
|
coreboot tables, there's no risk that a malicious application capable
|
|
of issuing SMIs could extract arbitrary data or modify the currently
|
|
running kernel.
|
|
|
|
## External links
|
|
|
|
```{toctree}
|
|
:maxdepth: 1
|
|
|
|
A Tour Beyond BIOS Implementing UEFI Authenticated Variables in SMM with EDKI <https://software.intel.com/sites/default/files/managed/cf/ea/a_tour_beyond_bios_implementing_uefi_authenticated_variables_in_smm_with_edkii.pdf>
|
|
```
|
|
Note that this differs significantly from coreboot's implementation.
|
|
|
|
[SMM]: ../security/smm.md
|