mb/google/rex/var/kanix: Set GPP_V14 to NC
[coreboot.git] / util / smmstoretool / fv.c
blobc6ee913d3cdd9e58888d10908456054313d0788d
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 #include "fv.h"
5 #include <assert.h>
6 #include <stdbool.h>
7 #include <stdint.h>
8 #include <stdio.h>
9 #include <string.h>
11 #include "udk2017.h"
13 // The same as in `smmstore.h` header, which isn't in `commonlib`.
14 #define SMM_BLOCK_SIZE (64 * 1024)
16 static const EFI_GUID EfiVariableGuid = EFI_VARIABLE_GUID;
18 static const EFI_GUID EfiAuthenticatedVariableGuid =
19 EFI_AUTHENTICATED_VARIABLE_GUID;
21 static const EFI_GUID EfiSystemNvDataFvGuid = {
22 0xfff12b8d, 0x7696, 0x4c8b,
23 { 0xa9, 0x85, 0x27, 0x47, 0x07, 0x5b, 0x4f, 0x50 }
26 static uint16_t calc_checksum(const uint16_t *hdr, size_t size)
28 assert(size % 2 == 0 && "Header can't have odd length.");
30 uint16_t checksum = 0;
31 for (size_t i = 0; i < size / 2; ++i)
32 checksum += hdr[i];
33 return checksum;
36 bool fv_init(struct mem_range_t fv)
38 if (fv.length % SMM_BLOCK_SIZE != 0) {
39 fprintf(stderr,
40 "Firmware Volume size is not a multiple of 64KiB\n");
41 return false;
44 memset(fv.start, 0xff, fv.length);
46 const EFI_FIRMWARE_VOLUME_HEADER vol_hdr = {
47 .FileSystemGuid = EfiSystemNvDataFvGuid,
48 .FvLength = fv.length,
49 .Signature = EFI_FVH_SIGNATURE,
50 .Attributes = EFI_FVB2_READ_ENABLED_CAP
51 | EFI_FVB2_READ_STATUS
52 | EFI_FVB2_WRITE_ENABLED_CAP
53 | EFI_FVB2_WRITE_STATUS
54 | EFI_FVB2_STICKY_WRITE
55 | EFI_FVB2_MEMORY_MAPPED
56 | EFI_FVB2_ERASE_POLARITY,
57 .HeaderLength = sizeof(vol_hdr)
58 + sizeof(EFI_FV_BLOCK_MAP_ENTRY),
59 .Revision = EFI_FVH_REVISION,
60 .BlockMap[0] = {
61 .NumBlocks = fv.length / SMM_BLOCK_SIZE,
62 .Length = SMM_BLOCK_SIZE,
66 EFI_FIRMWARE_VOLUME_HEADER *vol_hdr_dst = (void *)fv.start;
67 *vol_hdr_dst = vol_hdr;
68 vol_hdr_dst->BlockMap[1].NumBlocks = 0;
69 vol_hdr_dst->BlockMap[1].Length = 0;
71 vol_hdr_dst->Checksum =
72 ~calc_checksum((const void *)vol_hdr_dst, vol_hdr.HeaderLength);
73 ++vol_hdr_dst->Checksum;
75 const VARIABLE_STORE_HEADER var_store_hdr = {
76 // Authentication-related fields will be filled with 0xff.
77 .Signature = EfiAuthenticatedVariableGuid,
78 // Actual size of the storage is block size, the rest is
79 // Fault Tolerant Write (FTW) space and the FTW spare space.
80 .Size = SMM_BLOCK_SIZE - vol_hdr.HeaderLength,
81 .Format = VARIABLE_STORE_FORMATTED,
82 .State = VARIABLE_STORE_HEALTHY,
85 VARIABLE_STORE_HEADER *var_store_hdr_dst =
86 (void *)(fv.start + vol_hdr.HeaderLength);
87 *var_store_hdr_dst = var_store_hdr;
89 return true;
92 static bool guid_eq(const EFI_GUID *lhs, const EFI_GUID *rhs)
94 return memcmp(lhs, rhs, sizeof(*lhs)) == 0;
97 static bool check_fw_vol_hdr(const EFI_FIRMWARE_VOLUME_HEADER *hdr,
98 size_t max_size)
100 if (hdr->Revision != EFI_FVH_REVISION ||
101 hdr->Signature != EFI_FVH_SIGNATURE ||
102 hdr->FvLength > max_size ||
103 hdr->HeaderLength > max_size ||
104 hdr->HeaderLength % 2 != 0) {
105 fprintf(stderr, "No firmware volume header present\n");
106 return false;
109 if (!guid_eq(&hdr->FileSystemGuid, &EfiSystemNvDataFvGuid)) {
110 fprintf(stderr, "Firmware volume GUID non-compatible\n");
111 return false;
114 uint16_t checksum = calc_checksum((const void *)hdr, hdr->HeaderLength);
115 if (checksum != 0) {
116 fprintf(stderr,
117 "Firmware Volume checksum is non-zero: 0x%04X\n",
118 checksum);
119 return false;
122 return true;
125 static bool check_var_store_hdr(const VARIABLE_STORE_HEADER *hdr,
126 size_t max_size,
127 bool *auth_vars)
129 *auth_vars = guid_eq(&hdr->Signature, &EfiAuthenticatedVariableGuid);
130 if (!*auth_vars && !guid_eq(&hdr->Signature, &EfiVariableGuid)) {
131 fprintf(stderr, "Variable store has unexpected GUID\n");
132 return false;
135 if (hdr->Size > max_size) {
136 fprintf(stderr, "Variable store size is too large: %zu > %zu\n",
137 (size_t)hdr->Size, max_size);
138 return false;
141 if (hdr->Format != VARIABLE_STORE_FORMATTED) {
142 fprintf(stderr, "Variable store is not formatted\n");
143 return false;
146 if (hdr->State != VARIABLE_STORE_HEALTHY) {
147 fprintf(stderr, "Variable store is not in a healthy state\n");
148 return false;
151 return true;
154 bool fv_parse(struct mem_range_t fv, struct mem_range_t *var_store,
155 bool *auth_vars)
157 const EFI_FIRMWARE_VOLUME_HEADER *vol_hdr = (void *)fv.start;
158 if (!check_fw_vol_hdr(vol_hdr, fv.length)) {
159 fprintf(stderr, "No valid firmware volume was found\n");
160 return false;
163 uint8_t *fw_vol_data = fv.start + vol_hdr->HeaderLength;
164 size_t volume_size = fv.length - vol_hdr->HeaderLength;
165 const VARIABLE_STORE_HEADER *var_store_hdr = (void *)fw_vol_data;
166 if (!check_var_store_hdr(var_store_hdr, volume_size, auth_vars)) {
167 fprintf(stderr, "No valid variable store was found");
168 return false;
171 var_store->start = fw_vol_data + sizeof(*var_store_hdr);
172 var_store->length = volume_size - sizeof(*var_store_hdr);
173 return true;