1 /* SPDX-License-Identifier: GPL-2.0-or-later */
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
)
36 bool fv_init(struct mem_range_t fv
)
38 if (fv
.length
% SMM_BLOCK_SIZE
!= 0) {
40 "Firmware Volume size is not a multiple of 64KiB\n");
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
,
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
;
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
,
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");
109 if (!guid_eq(&hdr
->FileSystemGuid
, &EfiSystemNvDataFvGuid
)) {
110 fprintf(stderr
, "Firmware volume GUID non-compatible\n");
114 uint16_t checksum
= calc_checksum((const void *)hdr
, hdr
->HeaderLength
);
117 "Firmware Volume checksum is non-zero: 0x%04X\n",
125 static bool check_var_store_hdr(const VARIABLE_STORE_HEADER
*hdr
,
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");
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
);
141 if (hdr
->Format
!= VARIABLE_STORE_FORMATTED
) {
142 fprintf(stderr
, "Variable store is not formatted\n");
146 if (hdr
->State
!= VARIABLE_STORE_HEALTHY
) {
147 fprintf(stderr
, "Variable store is not in a healthy state\n");
154 bool fv_parse(struct mem_range_t fv
, struct mem_range_t
*var_store
,
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");
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");
171 var_store
->start
= fw_vol_data
+ sizeof(*var_store_hdr
);
172 var_store
->length
= volume_size
- sizeof(*var_store_hdr
);