blob: 89b0fd28d9a5d681e1a6e13606f014ef4ee1083e [file] [log] [blame]
Patrick Georgiea063cb2020-05-08 19:28:13 +02001/* Firmware Interface Table support */
Patrick Georgi7333a112020-05-08 20:48:04 +02002/* SPDX-License-Identifier: GPL-2.0-only */
Aaron Durbin6b0d0d62012-12-14 17:16:21 -06003
Joel Kitchingb4a19812019-06-25 17:28:30 +08004#include <inttypes.h>
Aaron Durbin6b0d0d62012-12-14 17:16:21 -06005#include <stdint.h>
Sol Boucher32532ac2015-05-06 14:44:40 -07006#include <stdio.h>
Aaron Durbin6b0d0d62012-12-14 17:16:21 -06007#include <stdlib.h>
8#include <string.h>
Aaron Durbin6b0d0d62012-12-14 17:16:21 -06009
Aaron Durbin6b0d0d62012-12-14 17:16:21 -060010#include "fit.h"
11
12/* FIXME: This code assumes it is being executed on a little endian machine. */
13
14#define FIT_POINTER_LOCATION 0xffffffc0
15#define FIT_TABLE_LOWEST_ADDRESS ((uint32_t)(-(16 << 20)))
16#define FIT_ENTRY_CHECKSUM_VALID 0x80
Philipp Deppenwiese5ada0022018-11-20 13:54:49 +010017#define FIT_HEADER_VERSION 0x0100
18#define FIT_HEADER_ADDRESS "_FIT_ "
19#define FIT_MICROCODE_VERSION 0x0100
20#define FIT_TXT_VERSION 0x0100
21
22#define FIT_SIZE_ALIGNMENT 16
Aaron Durbin6b0d0d62012-12-14 17:16:21 -060023
24struct fit_entry {
Philipp Deppenwiese5ada0022018-11-20 13:54:49 +010025 /**
26 * Address is the base address of the firmware component
27 * must be aligned on 16 byte boundary
28 */
Aaron Durbin6b0d0d62012-12-14 17:16:21 -060029 uint64_t address;
Philipp Deppenwiese5ada0022018-11-20 13:54:49 +010030 /**
31 * Size is the span of the component in multiple of 16 bytes
32 * Bits [24:31] are reserved and must be set to 0
33 */
Aaron Durbin6b0d0d62012-12-14 17:16:21 -060034 uint32_t size_reserved;
Philipp Deppenwiese5ada0022018-11-20 13:54:49 +010035 /**
36 * Component's version number in binary coded decimal (BCD) format.
37 * For the FIT header entry, the value in this field will indicate the
38 * revision number of the FIT data structure. The upper byte of the
39 * revision field indicates the major revision and the lower byte
40 * indicates the minor revision.
41 */
Aaron Durbin6b0d0d62012-12-14 17:16:21 -060042 uint16_t version;
Philipp Deppenwiese5ada0022018-11-20 13:54:49 +010043 /**
44 * FIT types 0x00 to 0x7F
45 * Bit 7 (C_V) indicates whether component has valid checksum.
46 */
Aaron Durbin6b0d0d62012-12-14 17:16:21 -060047 uint8_t type_checksum_valid;
Philipp Deppenwiese5ada0022018-11-20 13:54:49 +010048 /**
49 * Component's checksum. The modulo sum of all the bytes in the
50 * component and the value in this field (Chksum) must add up to zero.
51 * This field is only valid if the C_V flag is non-zero.
52 */
Aaron Durbin6b0d0d62012-12-14 17:16:21 -060053 uint8_t checksum;
Stefan Reinauer6a001132017-07-13 02:20:27 +020054} __packed;
Aaron Durbin6b0d0d62012-12-14 17:16:21 -060055
56struct fit_table {
57 struct fit_entry header;
Sol Boucher0e539312015-03-05 15:38:03 -080058 struct fit_entry entries[];
Stefan Reinauer6a001132017-07-13 02:20:27 +020059} __packed;
Aaron Durbin6b0d0d62012-12-14 17:16:21 -060060
61struct microcode_header {
62 uint32_t version;
63 uint32_t revision;
64 uint32_t date;
65 uint32_t processor_signature;
66 uint32_t checksum;
67 uint32_t loader_revision;
68 uint32_t processor_flags;
69 uint32_t data_size;
70 uint32_t total_size;
71 uint8_t reserved[12];
Stefan Reinauer6a001132017-07-13 02:20:27 +020072} __packed;
Aaron Durbin6b0d0d62012-12-14 17:16:21 -060073
74struct microcode_entry {
75 int offset;
76 int size;
77};
78
Sol Boucher32532ac2015-05-06 14:44:40 -070079static inline void *rom_buffer_pointer(struct buffer *buffer, int offset)
Aaron Durbin6b0d0d62012-12-14 17:16:21 -060080{
Sol Boucher32532ac2015-05-06 14:44:40 -070081 return &buffer->data[offset];
Aaron Durbin6b0d0d62012-12-14 17:16:21 -060082}
83
Philipp Deppenwiese5ada0022018-11-20 13:54:49 +010084static inline size_t fit_entry_size_bytes(const struct fit_entry *entry)
Aaron Durbin6b0d0d62012-12-14 17:16:21 -060085{
86 return (entry->size_reserved & 0xffffff) << 4;
87}
88
89static inline void fit_entry_update_size(struct fit_entry *entry,
Philipp Deppenwiese5ada0022018-11-20 13:54:49 +010090 const int size_bytes)
Aaron Durbin6b0d0d62012-12-14 17:16:21 -060091{
92 /* Size is multiples of 16 bytes. */
93 entry->size_reserved = (size_bytes >> 4) & 0xffffff;
94}
95
96static inline void fit_entry_add_size(struct fit_entry *entry,
Philipp Deppenwiese5ada0022018-11-20 13:54:49 +010097 const int size_bytes)
Aaron Durbin6b0d0d62012-12-14 17:16:21 -060098{
99 int size = fit_entry_size_bytes(entry);
100 size += size_bytes;
101 fit_entry_update_size(entry, size);
102}
103
104static inline int fit_entry_type(struct fit_entry *entry)
105{
106 return entry->type_checksum_valid & ~FIT_ENTRY_CHECKSUM_VALID;
107}
108
109/*
110 * Get an offset from a host pointer. This function assumes the ROM is located
111 * in the host address space at [4G - romsize -> 4G). It also assume all
112 * pointers have values within this address range.
113 */
Sol Boucher32532ac2015-05-06 14:44:40 -0700114static inline int ptr_to_offset(fit_offset_converter_t helper,
115 const struct buffer *region, uint32_t host_ptr)
Aaron Durbin6b0d0d62012-12-14 17:16:21 -0600116{
Sol Boucher32532ac2015-05-06 14:44:40 -0700117 return helper(region, -host_ptr);
Aaron Durbin6b0d0d62012-12-14 17:16:21 -0600118}
119
120/*
121 * Get a pointer from an offset. This function assumes the ROM is located
122 * in the host address space at [4G - romsize -> 4G). It also assume all
123 * pointers have values within this address range.
124 */
Sol Boucher32532ac2015-05-06 14:44:40 -0700125static inline uint32_t offset_to_ptr(fit_offset_converter_t helper,
126 const struct buffer *region, int offset)
Aaron Durbin6b0d0d62012-12-14 17:16:21 -0600127{
Sol Boucher32532ac2015-05-06 14:44:40 -0700128 return -helper(region, offset);
Aaron Durbin6b0d0d62012-12-14 17:16:21 -0600129}
130
Philipp Deppenwiese5ada0022018-11-20 13:54:49 +0100131/*
132 * Return the number of FIT entries.
133 */
134static inline size_t fit_table_entries(const struct fit_table *fit)
135{
136 if (!fit)
137 return 0;
138
139 return (fit_entry_size_bytes(&fit->header) / FIT_SIZE_ALIGNMENT) - 1;
140}
141
142/*
143 * Return the number of unused entries.
144 */
145static inline size_t fit_free_space(struct fit_table *fit,
146 const size_t max_entries)
147{
148 if (!fit)
149 return 0;
150
151 return max_entries - fit_table_entries(fit);
152}
153
154/*
155 * Sort entries by type and fill gaps (entries with type unused).
156 * To be called after adding or deleting entries.
157 *
158 * This one is critical, as mentioned in Chapter 1.2.1 "FIT Ordering Rules"
159 * "Firmware Interface Table BIOS Specification".
160 *
Patrick Georgi01cfecc2020-01-29 13:31:16 +0100161 * We need to use a stable sorting algorithm, as the order of
Philipp Deppenwiese5ada0022018-11-20 13:54:49 +0100162 * FIT_TYPE_BIOS_STARTUP matter for measurements.
163 */
164static void sort_fit_table(struct fit_table *fit)
165{
166 struct fit_entry tmp;
167 size_t i, j;
168 int swapped;
169
170 /* Bubble sort entries */
171 for (j = 0; j < fit_table_entries(fit) - 1; j++) {
172 swapped = 0;
173 for (i = 0; i < fit_table_entries(fit) - j - 1; i++) {
174 if (fit->entries[i].type_checksum_valid <=
175 fit->entries[i + 1].type_checksum_valid)
176 continue;
177 /* SWAP entries */
178 memcpy(&tmp, &fit->entries[i], sizeof(tmp));
179 memcpy(&fit->entries[i], &fit->entries[i + 1],
180 sizeof(fit->entries[i]));
181 memcpy(&fit->entries[i + 1], &tmp,
182 sizeof(fit->entries[i + 1]));
183 swapped = 1;
184 }
185 if (!swapped)
186 break;
187 }
188}
189
Rizwan Qureshic1072f22018-06-04 23:02:46 +0530190static int fit_table_verified(struct fit_table *table)
191{
Philipp Deppenwiese5ada0022018-11-20 13:54:49 +0100192 if (!table)
193 return 0;
194
Rizwan Qureshic1072f22018-06-04 23:02:46 +0530195 /* Check that the address field has the proper signature. */
196 if (strncmp((const char *)&table->header.address, FIT_HEADER_ADDRESS,
197 sizeof(table->header.address)))
198 return 0;
199
200 if (table->header.version != FIT_HEADER_VERSION)
201 return 0;
202
203 if (fit_entry_type(&table->header) != FIT_TYPE_HEADER)
204 return 0;
205
Philipp Deppenwiese5ada0022018-11-20 13:54:49 +0100206 /* Assume that the FIT table contains at least the header */
207 if (fit_entry_size_bytes(&table->header) < sizeof(struct fit_entry))
Rizwan Qureshic1072f22018-06-04 23:02:46 +0530208 return 0;
209
210 return 1;
211}
212
Philipp Deppenwiese5ada0022018-11-20 13:54:49 +0100213/*
214 * Update the FIT checksum.
215 * To be called after modifiying the table.
216 */
Aaron Durbin6b0d0d62012-12-14 17:16:21 -0600217static void update_fit_checksum(struct fit_table *fit)
218{
219 int size_bytes;
220 uint8_t *buffer;
221 uint8_t result;
222 int i;
223
Philipp Deppenwiese5ada0022018-11-20 13:54:49 +0100224 if (!fit)
225 return;
226
Aaron Durbin6b0d0d62012-12-14 17:16:21 -0600227 fit->header.checksum = 0;
228 size_bytes = fit_entry_size_bytes(&fit->header);
229 result = 0;
230 buffer = (void *)fit;
231 for (i = 0; i < size_bytes; i++)
232 result += buffer[i];
233 fit->header.checksum = -result;
234}
235
Philipp Deppenwiese5ada0022018-11-20 13:54:49 +0100236/*
237 * Return a pointer to the next free entry.
238 * Caller must take care if enough space is available.
239 */
240static struct fit_entry *get_next_free_entry(struct fit_table *fit)
241{
242 return &fit->entries[fit_table_entries(fit)];
243}
244
245static void fit_location_from_cbfs_header(uint32_t *current_offset,
246 uint32_t *file_length, void *ptr)
247{
248 struct buffer buf;
249 struct cbfs_file header;
250 memset(&buf, 0, sizeof(buf));
251
252 buf.data = ptr;
253 buf.size = sizeof(header);
254
255 bgets(&buf, header.magic, sizeof(header.magic));
256 header.len = xdr_be.get32(&buf);
257 header.type = xdr_be.get32(&buf);
258 header.attributes_offset = xdr_be.get32(&buf);
259 header.offset = xdr_be.get32(&buf);
260
261 *current_offset = header.offset;
262 *file_length = header.len;
263}
264
265static int
266parse_microcode_blob(struct cbfs_image *image,
267 const char *blob_name,
268 size_t *mcus_found,
269 struct microcode_entry *mcus,
270 const size_t max_fit_entries)
271{
272 size_t num_mcus;
273 uint32_t current_offset;
274 uint32_t file_length;
275 struct cbfs_file *mcode_file;
276
277 mcode_file = cbfs_get_entry(image, blob_name);
278 if (!mcode_file)
279 return 1;
280
281 fit_location_from_cbfs_header(&current_offset, &file_length,
282 mcode_file);
283 current_offset += cbfs_get_entry_addr(image, mcode_file);
284
285 num_mcus = 0;
286 while (file_length > sizeof(struct microcode_header)) {
287 const struct microcode_header *mcu_header;
288
289 mcu_header = rom_buffer_pointer(&image->buffer, current_offset);
290 if (!mcu_header) {
291 ERROR("Couldn't parse microcode header.\n");
292 return 1;
293 }
294
295 /* Newer microcode updates include a size field, whereas older
296 * containers set it at 0 and are exactly 2048 bytes long */
297 uint32_t total_size = mcu_header->total_size ?: 2048;
298
299 /* Quickly sanity check a prospective microcode update. */
300 if (total_size < sizeof(*mcu_header))
301 break;
302
303 /* FIXME: Should the checksum be validated? */
304 mcus[num_mcus].offset = current_offset;
305 mcus[num_mcus].size = total_size;
306
307 /* Proceed to next payload. */
308 current_offset += mcus[num_mcus].size;
309 file_length -= mcus[num_mcus].size;
310 num_mcus++;
311 /* Reached limit of FIT entries. */
312 if (num_mcus == max_fit_entries)
313 break;
314 if (file_length < sizeof(struct microcode_header))
315 break;
316 }
317
318 /* Update how many microcode updates we found. */
319 *mcus_found = num_mcus;
320
321 return 0;
322}
323
324/* There can be zero or more FIT_TYPE_MICROCODE entries */
Rizwan Qureshic1072f22018-06-04 23:02:46 +0530325static void update_fit_ucode_entry(struct fit_table *fit,
Philipp Deppenwiese5ada0022018-11-20 13:54:49 +0100326 struct fit_entry *entry,
327 const uint64_t mcu_addr)
Rizwan Qureshic1072f22018-06-04 23:02:46 +0530328{
329 entry->address = mcu_addr;
330 /*
331 * While loading MCU, its size is not referred from FIT and
Philipp Deppenwiese5ada0022018-11-20 13:54:49 +0100332 * rather from the MCU header, hence we can assign zero here.
Rizwan Qureshic1072f22018-06-04 23:02:46 +0530333 */
Philipp Deppenwiese5ada0022018-11-20 13:54:49 +0100334 entry->size_reserved = 0;
Matt DeVillier0a36c2c2018-06-28 13:21:10 -0500335 entry->type_checksum_valid = FIT_TYPE_MICROCODE;
Rizwan Qureshic1072f22018-06-04 23:02:46 +0530336 entry->version = FIT_MICROCODE_VERSION;
337 entry->checksum = 0;
338 fit_entry_add_size(&fit->header, sizeof(struct fit_entry));
339}
340
Philipp Deppenwiese5ada0022018-11-20 13:54:49 +0100341/*
342 * There can be zero or one FIT_TYPE_BIOS_ACM entry per table.
343 * In case there's a FIT_TYPE_BIOS_ACM entry, at least one
344 * FIT_TYPE_BIOS_STARTUP entry must exist.
345 *
346 * The caller has to provide valid arguments as those aren't verfied.
347 */
348static void update_fit_bios_acm_entry(struct fit_table *fit,
349 struct fit_entry *entry,
350 const uint64_t acm_addr)
351{
352 entry->address = acm_addr;
353 /*
354 * The Address field points to a BIOS ACM. The Address field points to
355 * the first byte of the AC module header. When BIOS ACM is loaded in
356 * Authenticated Code RAM, one MTRR base/limit pair is used to map it.
357 */
358 entry->size_reserved = 0;
359 entry->type_checksum_valid = FIT_TYPE_BIOS_ACM;
360 entry->version = FIT_TXT_VERSION;
361 entry->checksum = 0;
362 fit_entry_add_size(&fit->header, sizeof(struct fit_entry));
363}
364
365/*
366 * In case there's a FIT_TYPE_BIOS_ACM entry, at least one
367 * FIT_TYPE_BIOS_STARTUP entry must exist.
368 *
369 * The caller has to provide valid arguments as those aren't verfied.
370 */
371static void update_fit_bios_startup_entry(struct fit_table *fit,
372 struct fit_entry *entry,
373 const uint64_t sm_addr,
374 const uint32_t sm_size)
375{
376 entry->address = sm_addr;
377 assert(sm_size % 16 == 0);
378 /*
379 * BIOS Startup code is defined as the code that gets control at the
380 * reset vector and continues the chain of trust in TCG-compliant
381 * fashion. In addition, this code may also configure memory and SMRAM.
382 */
383 fit_entry_update_size(entry, sm_size);
384 entry->type_checksum_valid = FIT_TYPE_BIOS_STARTUP;
385 entry->version = FIT_TXT_VERSION;
386 entry->checksum = 0;
387 fit_entry_add_size(&fit->header, sizeof(struct fit_entry));
388}
389
390/*
391 * There can be zero or one FIT_TYPE_BIOS_POLICY Record in the FIT.
392 * If the platform uses the hash comparison method and employs a
393 * failsafe bootblock, one FIT_TYPE_BIOS_POLICY entry is needed to
394 * contain the failsafe hash.
395 * If the platform uses the Signature verification method, one
396 * FIT_TYPE_BIOS_POLICY entry is needed. In this case, the entry
397 * contains the OEM key, hash of the BIOS and signature over the hash
398 * using the OEM key.
399 * In all other cases, the FIT_TYPE_BIOS_POLICY record is not required.
400 *
401 * The caller has to provide valid arguments as those aren't verfied.
402 */
403static void update_fit_bios_policy_entry(struct fit_table *fit,
404 struct fit_entry *entry,
405 const uint64_t lcp_policy_addr,
406 const uint32_t lcp_policy_size)
407{
408 entry->address = lcp_policy_addr;
409 fit_entry_update_size(entry, lcp_policy_size);
410 entry->type_checksum_valid = FIT_TYPE_BIOS_POLICY;
411 entry->version = FIT_TXT_VERSION;
412 entry->checksum = 0;
413 fit_entry_add_size(&fit->header, sizeof(struct fit_entry));
414}
415
416/*
417 * There can be zero or one FIT_TYPE_TXT_POLICY entries
418 *
419 * The caller has to provide valid arguments as those aren't verfied.
420 */
421static void update_fit_txt_policy_entry(struct fit_table *fit,
422 struct fit_entry *entry,
423 uint64_t txt_policy_addr)
424{
425 entry->address = txt_policy_addr;
426 /*
427 * Points to the flag indicating if TXT is enabled on this platform.
428 * If not present, TXT is not disabled by FIT.
429 */
430 entry->size_reserved = 0;
431 entry->type_checksum_valid = FIT_TYPE_TXT_POLICY;
432 entry->version = 0x1;
433 entry->checksum = 0;
434 fit_entry_add_size(&fit->header, sizeof(struct fit_entry));
435}
436
Michał Żygowski7ed40392020-07-11 15:50:55 +0200437/*
438 * There can be zero or one FIT_TYPE_BOOT_POLICY entries
439 *
440 * The caller has to provide valid arguments as those aren't verified.
441 */
442static void update_fit_boot_policy_entry(struct fit_table *fit,
443 struct fit_entry *entry,
444 uint64_t boot_policy_addr,
445 uint32_t boot_policy_size)
446{
447 entry->address = boot_policy_addr;
448 entry->type_checksum_valid = FIT_TYPE_BOOT_POLICY;
449 entry->size_reserved = boot_policy_size;
450 entry->version = FIT_TXT_VERSION;
451 entry->checksum = 0;
452 fit_entry_add_size(&fit->header, sizeof(struct fit_entry));
453}
454
455/*
456 * There can be zero or one FIT_TYPE_KEY_MANIFEST entries
457 *
458 * The caller has to provide valid arguments as those aren't verified.
459 */
460static void update_fit_key_manifest_entry(struct fit_table *fit,
461 struct fit_entry *entry,
462 uint64_t key_manifest_addr,
463 uint32_t key_manifest_size)
464{
465 entry->address = key_manifest_addr;
466
467 entry->type_checksum_valid = FIT_TYPE_KEY_MANIFEST;
468 entry->size_reserved = key_manifest_size;
469 entry->version = FIT_TXT_VERSION;
470 entry->checksum = 0;
471 fit_entry_add_size(&fit->header, sizeof(struct fit_entry));
472}
473
Philipp Deppenwiese5ada0022018-11-20 13:54:49 +0100474/* Special case for ucode CBFS file, as it might contain more than one ucode */
475int fit_add_microcode_file(struct fit_table *fit,
476 struct cbfs_image *image,
477 const char *blob_name,
478 fit_offset_converter_t offset_helper,
479 const size_t max_fit_entries)
480{
481 struct microcode_entry *mcus;
482
483 size_t i;
484 size_t mcus_found;
485
486 mcus = malloc(sizeof(*mcus) * max_fit_entries);
487 if (!mcus) {
488 ERROR("Couldn't allocate memory for microcode entries.\n");
489 return 1;
490 }
491
492 if (parse_microcode_blob(image, blob_name, &mcus_found, mcus,
493 max_fit_entries)) {
494 ERROR("Couldn't parse microcode blob.\n");
495 free(mcus);
496 return 1;
497 }
498
499 if (mcus_found > fit_free_space(fit, max_fit_entries)) {
500 ERROR("Maximum of FIT entries reached.\n");
501 free(mcus);
502 return 1;
503 }
504
505 for (i = 0; i < mcus_found; i++) {
506 if (fit_add_entry(fit,
507 offset_to_ptr(offset_helper, &image->buffer,
508 mcus[i].offset),
509 0,
510 FIT_TYPE_MICROCODE,
511 max_fit_entries)) {
512
513 free(mcus);
514 return 1;
515 }
516 }
517
518 free(mcus);
519 return 0;
520}
521
Arthur Heymanse9e4e542021-02-17 17:34:44 +0100522static uint32_t *get_fit_ptr(struct buffer *bootblock, fit_offset_converter_t offset_fn,
523 uint32_t topswap_size)
524{
525 return rom_buffer_pointer(bootblock,
526 ptr_to_offset(offset_fn, bootblock,
527 FIT_POINTER_LOCATION - topswap_size));
528}
529
530/* Set the FIT pointer to a FIT table. */
531int set_fit_pointer(struct buffer *bootblock,
532 const uint32_t fit_address,
533 fit_offset_converter_t offset_fn,
534 uint32_t topswap_size)
535{
536 struct fit_table *fit;
537 uint32_t *fit_pointer = get_fit_ptr(bootblock, offset_fn, topswap_size);
538
539 fit = rom_buffer_pointer(bootblock, ptr_to_offset(offset_fn, bootblock, fit_address));
540
541 if (fit_address < FIT_TABLE_LOWEST_ADDRESS) {
542 ERROR("FIT must be reside in the top 16MiB.\n");
543 return 1;
544 }
545
546 if (!fit_table_verified(fit)) {
547 ERROR("FIT not found at address.\n");
548 return 1;
549 }
550
551 fit_pointer[0] = fit_address;
552 fit_pointer[1] = 0;
553 return 0;
554}
555
Philipp Deppenwiese5ada0022018-11-20 13:54:49 +0100556/*
557 * Return a pointer to the active FIT.
558 */
559struct fit_table *fit_get_table(struct buffer *bootblock,
560 fit_offset_converter_t offset_fn,
561 uint32_t topswap_size)
562{
563 struct fit_table *fit;
Arthur Heymansf2b71042021-05-19 15:40:10 +0200564 uint32_t *fit_pointer = get_fit_ptr(bootblock, offset_fn, topswap_size);
Philipp Deppenwiese5ada0022018-11-20 13:54:49 +0100565
566 /* Ensure pointer is below 4GiB and within 16MiB of 4GiB */
567 if (fit_pointer[1] != 0 || fit_pointer[0] < FIT_TABLE_LOWEST_ADDRESS) {
568 ERROR("FIT not found.\n");
569 return NULL;
570 }
571
572 fit = rom_buffer_pointer(bootblock,
573 ptr_to_offset(offset_fn, bootblock, *fit_pointer));
574 if (!fit_table_verified(fit)) {
575 ERROR("FIT not found.\n");
576 return NULL;
577 }
578
Philipp Deppenwiese5ada0022018-11-20 13:54:49 +0100579 return fit;
580}
581
582/*
583 * Dump the current FIT in human readable format to stdout.
584 */
585int fit_dump(struct fit_table *fit)
586{
587 size_t i;
588
589 if (!fit)
590 return 1;
591
592 printf("\n");
593 printf(" FIT table:\n");
594
595 if (fit_table_entries(fit) < 1) {
596 printf(" empty\n\n");
597 return 0;
598 }
599
600 printf(" %-6s %-20s %-16s %-8s\n", "Index", "Type", "Addr", "Size");
601
602 for (i = 0; i < fit_table_entries(fit); i++) {
603 const char *name;
604
605 switch (fit->entries[i].type_checksum_valid) {
606 case FIT_TYPE_MICROCODE:
607 name = "Microcode";
608 break;
609 case FIT_TYPE_BIOS_ACM:
610 name = "BIOS ACM";
611 break;
612 case FIT_TYPE_BIOS_STARTUP:
613 name = "BIOS Startup Module";
614 break;
615 case FIT_TYPE_TPM_POLICY:
616 name = "TPM Policy";
617 break;
618 case FIT_TYPE_BIOS_POLICY:
619 name = "BIOS Policy";
620 break;
621 case FIT_TYPE_TXT_POLICY:
622 name = "TXT Policy";
623 break;
624 case FIT_TYPE_KEY_MANIFEST:
625 name = "Key Manifest";
626 break;
627 case FIT_TYPE_BOOT_POLICY:
628 name = "Boot Policy";
629 break;
630 case FIT_TYPE_CSE_SECURE_BOOT:
631 name = "CSE SecureBoot";
632 break;
633 case FIT_TYPE_TXTSX_POLICY:
634 name = "TXTSX policy";
635 break;
636 case FIT_TYPE_JMP_DEBUG_POLICY:
637 name = "JMP debug policy";
638 break;
639 case FIT_TYPE_UNUSED:
640 name = "unused";
641 break;
642 default:
643 name = "unknown";
644 }
645
646 printf(" %6zd %-20s 0x%08"PRIx64" 0x%08zx\n", i, name,
647 fit->entries[i].address,
648 fit_entry_size_bytes(&fit->entries[i]));
649 }
650 printf("\n");
651 return 0;
652}
653
654/*
655 * Remove all entries from table.
656 */
657int fit_clear_table(struct fit_table *fit)
658{
659 if (!fit)
660 return 1;
661
662 memset(fit->entries, 0,
663 sizeof(struct fit_entry) * fit_table_entries(fit));
664
665 /* Reset entry counter in header */
666 fit_entry_update_size(&fit->header, sizeof(fit->header));
667
668 update_fit_checksum(fit);
669
670 return 0;
671}
672
673/*
674 * Returns true if the FIT type is know and can be added to the table.
675 */
676int fit_is_supported_type(const enum fit_type type)
677{
678 switch (type) {
679 case FIT_TYPE_MICROCODE:
680 case FIT_TYPE_BIOS_ACM:
681 case FIT_TYPE_BIOS_STARTUP:
682 case FIT_TYPE_BIOS_POLICY:
683 case FIT_TYPE_TXT_POLICY:
Philipp Deppenwiese5ada0022018-11-20 13:54:49 +0100684 case FIT_TYPE_KEY_MANIFEST:
685 case FIT_TYPE_BOOT_POLICY:
Michał Żygowski7ed40392020-07-11 15:50:55 +0200686 return 1;
687 case FIT_TYPE_TPM_POLICY:
Philipp Deppenwiese5ada0022018-11-20 13:54:49 +0100688 default:
689 return 0;
690 }
691}
692
693/*
694 * Adds an known entry to the FIT.
695 * len is optional for same types and might be zero.
696 * offset is an absolute address in 32-bit protected mode address space.
697 */
698int fit_add_entry(struct fit_table *fit,
699 const uint32_t offset,
700 const uint32_t len,
701 const enum fit_type type,
702 const size_t max_fit_entries)
703{
704 struct fit_entry *entry;
705
706 if (!fit) {
707 ERROR("Internal error.");
708 return 1;
709 }
710
711 if (fit_free_space(fit, max_fit_entries) < 1) {
712 ERROR("No space left in FIT.");
713 return 1;
714 }
715
716 if (!fit_is_supported_type(type)) {
717 ERROR("Unsupported FIT type %u\n", type);
718 return 1;
719 }
720
721 DEBUG("Adding new entry type %u at offset %zd\n", type,
722 fit_table_entries(fit));
723
724 entry = get_next_free_entry(fit);
725
726 switch (type) {
727 case FIT_TYPE_MICROCODE:
728 update_fit_ucode_entry(fit, entry, offset);
729 break;
730 case FIT_TYPE_BIOS_ACM:
731 update_fit_bios_acm_entry(fit, entry, offset);
732 break;
733 case FIT_TYPE_BIOS_STARTUP:
734 update_fit_bios_startup_entry(fit, entry, offset, len);
735 break;
736 case FIT_TYPE_BIOS_POLICY:
737 update_fit_bios_policy_entry(fit, entry, offset, len);
738 break;
739 case FIT_TYPE_TXT_POLICY:
740 update_fit_txt_policy_entry(fit, entry, offset);
741 break;
Michał Żygowski7ed40392020-07-11 15:50:55 +0200742 case FIT_TYPE_KEY_MANIFEST:
743 update_fit_key_manifest_entry(fit, entry, offset, len);
744 break;
745 case FIT_TYPE_BOOT_POLICY:
746 update_fit_boot_policy_entry(fit, entry, offset, len);
747 break;
Philipp Deppenwiese5ada0022018-11-20 13:54:49 +0100748 default:
749 return 1;
750 }
751
752 sort_fit_table(fit);
753
754 update_fit_checksum(fit);
755
756 return 0;
757}
758
759/*
760 * Delete one entry from table.
761 */
762int fit_delete_entry(struct fit_table *fit,
763 const size_t idx)
764{
765 if (!fit) {
766 ERROR("Internal error.");
767 return 1;
768 }
769
770 if (idx >= fit_table_entries(fit)) {
771 ERROR("Index out of range.");
772 return 1;
773 }
774
775 memset(&fit->entries[idx], 0, sizeof(struct fit_entry));
776
777 fit->entries[idx].type_checksum_valid = FIT_TYPE_UNUSED;
778
779 sort_fit_table(fit);
780
781 /* The unused entry is now the last one */
782 fit_entry_add_size(&fit->header, -(int)sizeof(struct fit_entry));
783
784 update_fit_checksum(fit);
785
786 return 0;
787}