1# SMM based flash storage driver Version 2 2 3This documents the API exposed by the x86 system management based 4storage driver. 5 6## SMMSTOREv2 7 8SMMSTOREv2 is a [SMM] mediated driver to read from, write to and erase 9a predefined region in flash. It can be enabled by setting 10`CONFIG_SMMSTORE=y` and `CONFIG_SMMSTORE_V2=y` in menuconfig. 11 12This can be used by the OS or the payload to implement persistent 13storage to hold for instance configuration data, without needing to 14implement a (platform specific) storage driver in the payload itself. 15 16### Storage size and alignment 17 18SMMSTORE version 2 requires a minimum alignment of 64 KiB, which should 19be supported by all flash chips. Not having to perform read-modify-write 20operations is desired, as it reduces complexity and potential for bugs. 21 22This can be used by a FTW (FaultTolerantWrite) implementation that uses 23at least two regions in an A/B update scheme. The FTW implementation in 24edk2 uses three different regions in the store: 25 26- The variable store 27- The FTW spare block 28- The FTW working block 29 30All regions must be block-aligned, and the FTW spare size must be larger 31than that of the variable store. FTW working block can be much smaller. 32With 64 KiB as block size, the minimum size of the FTW-enabled store is: 33 34- The variable store: 1 block = 64 KiB 35- The FTW spare block: 2 blocks = 2 * 64 KiB 36- The FTW working block: 1 block = 64 KiB 37 38Therefore, the minimum size for edk2 FTW is 4 blocks, or 256 KiB. 39 40## API 41 42The API provides read and write access to an unformatted block storage. 43 44### Storage region 45 46By default SMMSTOREv2 will operate on a separate FMAP region called 47`SMMSTORE`. The default generated FMAP will include such a region. On 48systems with a locked FMAP, e.g. in an existing vboot setup with a 49locked RO region, the option exists to add a cbfsfile called `smm_store` 50in the `RW_LEGACY` (if CHROMEOS) or in the `COREBOOT` FMAP regions. It 51is recommended for new builds using a handcrafted FMD that intend to 52make use of SMMSTORE to include a sufficiently large `SMMSTORE` FMAP 53region. It is mandatory to align the `SMMSTORE` region to 64KiB for 54compatibility with the largest flash erase operation. 55 56When a default generated FMAP is used, the size of the FMAP region is 57equal to `CONFIG_SMMSTORE_SIZE`. UEFI payloads expect at least 64 KiB. 58To support a fault tolerant write mechanism, at least a multiple of 59this size is recommended. 60 61### Communication buffer 62 63To prevent malicious ring0 code to access arbitrary memory locations, 64SMMSTOREv2 uses a communication buffer in CBMEM/HOB for all transfers. 65This buffer has to be at least 64 KiB in size and must be installed 66before calling any of the SMMSTORE read or write operations. Usually, 67coreboot will install this buffer to transfer data between ring0 and 68the [SMM] handler. 69 70In order to get the communication buffer address, the payload or OS 71has to read the coreboot table with tag `0x0039`, containing: 72 73```C 74struct lb_smmstorev2 { 75 uint32_t tag; 76 uint32_t size; 77 uint32_t num_blocks; /* Number of writeable blocks in SMM */ 78 uint32_t block_size; /* Size of a block in byte. Default: 64 KiB */ 79 uint32_t mmap_addr; /* MMIO address of the store for read only access */ 80 uint32_t com_buffer; /* Physical address of the communication buffer */ 81 uint32_t com_buffer_size; /* Size of the communication buffer in byte */ 82 uint8_t apm_cmd; /* The command byte to write to the APM I/O port */ 83 uint8_t unused[3]; /* Set to zero */ 84}; 85``` 86 87The absence of this coreboot table entry indicates that there's no 88SMMSTOREv2 support. 89 90### Blocks 91 92The SMMSTOREv2 splits the SMMSTORE FMAP partition into smaller chunks 93called *blocks*. Every block is at least the size of 64KiB to support 94arbitrary NOR flash erase ops. A payload or OS must make no further 95assumptions about the block or communication buffer size. 96 97### Generating the SMI 98 99SMMSTOREv2 is called via an SMI, which is generated via a write to the 100IO port defined in the smi_cmd entry of the FADT ACPI table. `%al` 101contains `APM_CNT_SMMSTORE=0xed` and is written to the smi_cmd IO 102port. `%ah` contains the SMMSTOREv2 command. `%ebx` contains the 103parameter buffer to the SMMSTOREv2 command. 104 105### Return values 106 107If a command succeeds, SMMSTOREv2 will return with 108`SMMSTORE_RET_SUCCESS=0` in `%eax`. On failure SMMSTORE will return 109`SMMSTORE_RET_FAILURE=1`. For unsupported SMMSTORE commands 110`SMMSTORE_REG_UNSUPPORTED=2` is returned. 111 112**NOTE 1**: The caller **must** check the return value and should make 113no assumption on the returned data if `%eax` does not contain 114`SMMSTORE_RET_SUCCESS`. 115 116**NOTE 2**: If the SMI returns without changing `%ax`, it can be assumed 117that the SMMSTOREv2 feature is not installed. 118 119### Calling arguments 120 121SMMSTOREv2 supports 3 subcommands that are passed via `%ah`, the 122additional calling arguments are passed via `%ebx`. 123 124**NOTE**: The size of the struct entries are in the native word size of 125smihandler. This means 32 bits in almost all cases. 126 127#### - SMMSTORE_CMD_INIT_DEPRECATED = 4 128 129Unused, returns SMMSTORE_REG_UNSUPPORTED. 130 131#### - SMMSTORE_CMD_RAW_READ = 5 132 133SMMSTOREv2 allows reading arbitrary data. It is up to the caller to 134initialize the store with meaningful data before using it. 135 136The additional parameter buffer `%ebx` contains a pointer to the 137following struct: 138 139```C 140struct smmstore_params_raw_read { 141 uint32_t bufsize; 142 uint32_t bufoffset; 143 uint32_t block_id; 144} __packed; 145``` 146 147INPUT: 148- `bufsize`: Size of data to read within the communication buffer 149- `bufoffset`: Offset within the communication buffer 150- `block_id`: Block to read from 151 152#### - SMMSTORE_CMD_RAW_WRITE = 6 153 154SMMSTOREv2 allows writing arbitrary data. It is up to the caller to 155erase a block before writing it. 156 157The additional parameter buffer `%ebx` contains a pointer to 158the following struct: 159 160```C 161struct smmstore_params_raw_write { 162 uint32_t bufsize; 163 uint32_t bufoffset; 164 uint32_t block_id; 165} __packed; 166``` 167 168INPUT: 169- `bufsize`: Size of data to write within the communication buffer 170- `bufoffset`: Offset within the communication buffer 171- `block_id`: Block to write to 172 173#### - SMMSTORE_CMD_RAW_CLEAR = 7 174 175SMMSTOREv2 allows clearing blocks. A cleared block will read as `0xff`. 176By providing multiple blocks the caller can implement a fault tolerant 177write mechanism. It is up to the caller to clear blocks before writing 178to them. 179 180 181```C 182struct smmstore_params_raw_clear { 183 uint32_t block_id; 184} __packed; 185``` 186 187INPUT: 188- `block_id`: Block to erase 189 190#### Security 191 192Pointers provided by the payload or OS are checked to not overlap with 193SMM. This protects the SMM handler from being compromised. 194 195As all information is exchanged using the communication buffer and 196coreboot tables, there's no risk that a malicious application capable 197of issuing SMIs could extract arbitrary data or modify the currently 198running kernel. 199 200## External links 201 202```{toctree} 203:maxdepth: 1 204 205A 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> 206``` 207Note that this differs significantly from coreboot's implementation. 208 209[SMM]: ../security/smm.md 210