Angel Pons | 986d50e | 2020-04-02 23:48:53 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 2 | |
| 3 | #include <console/console.h> |
| 4 | #include <fmap.h> |
Sergii Dmytruk | 26203e7 | 2022-11-10 17:56:26 +0200 | [diff] [blame] | 5 | #include <bootstate.h> |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 6 | #include <cbfs.h> |
Sergii Dmytruk | 26203e7 | 2022-11-10 17:56:26 +0200 | [diff] [blame] | 7 | #include <symbols.h> |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 8 | #include "crtm.h" |
Elyes Haouas | bdd03c2 | 2024-05-27 11:20:07 +0200 | [diff] [blame^] | 9 | #include <stdio.h> |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 10 | #include <string.h> |
| 11 | |
Sergii Dmytruk | 2710df7 | 2022-11-10 00:40:51 +0200 | [diff] [blame] | 12 | static int tpm_log_initialized; |
| 13 | static inline int tpm_log_available(void) |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 14 | { |
| 15 | if (ENV_BOOTBLOCK) |
Sergii Dmytruk | 2710df7 | 2022-11-10 00:40:51 +0200 | [diff] [blame] | 16 | return tpm_log_initialized; |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 17 | |
| 18 | return 1; |
| 19 | } |
| 20 | |
Arthur Heymans | 17cb5be | 2021-06-14 09:17:49 +0200 | [diff] [blame] | 21 | /* |
| 22 | * Initializes the Core Root of Trust for Measurements |
| 23 | * in coreboot. The initial code in a chain of trust must measure |
| 24 | * itself. |
| 25 | * |
| 26 | * Summary: |
| 27 | * + Measures the FMAP FMAP partition. |
| 28 | * + Measures bootblock in CBFS or BOOTBLOCK FMAP partition. |
| 29 | * + If vboot starts in romstage, it measures the romstage |
| 30 | * in CBFS. |
| 31 | * + Measure the verstage if it is compiled as separate |
| 32 | * stage. |
| 33 | * |
| 34 | * Takes the current vboot context as parameter for s3 checks. |
Jon Murphy | d7b8dc9 | 2023-09-05 11:36:43 -0600 | [diff] [blame] | 35 | * returns on success TPM_SUCCESS, else a TPM error. |
Arthur Heymans | 17cb5be | 2021-06-14 09:17:49 +0200 | [diff] [blame] | 36 | */ |
Jon Murphy | d7b8dc9 | 2023-09-05 11:36:43 -0600 | [diff] [blame] | 37 | static tpm_result_t tspi_init_crtm(void) |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 38 | { |
Jon Murphy | d7b8dc9 | 2023-09-05 11:36:43 -0600 | [diff] [blame] | 39 | tpm_result_t rc = TPM_SUCCESS; |
Sergii Dmytruk | 2710df7 | 2022-11-10 00:40:51 +0200 | [diff] [blame] | 40 | /* Initialize TPM PRERAM log. */ |
| 41 | if (!tpm_log_available()) { |
| 42 | tpm_preram_log_clear(); |
| 43 | tpm_log_initialized = 1; |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 44 | } else { |
| 45 | printk(BIOS_WARNING, "TSPI: CRTM already initialized!\n"); |
Jon Murphy | d7b8dc9 | 2023-09-05 11:36:43 -0600 | [diff] [blame] | 46 | return TPM_SUCCESS; |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 47 | } |
| 48 | |
Arthur Heymans | f28dcbc | 2021-04-29 09:31:01 +0200 | [diff] [blame] | 49 | struct region_device fmap; |
| 50 | if (fmap_locate_area_as_rdev("FMAP", &fmap) == 0) { |
Jon Murphy | d7b8dc9 | 2023-09-05 11:36:43 -0600 | [diff] [blame] | 51 | rc = tpm_measure_region(&fmap, CONFIG_PCR_SRTM, "FMAP: FMAP"); |
| 52 | if (rc) { |
Arthur Heymans | f28dcbc | 2021-04-29 09:31:01 +0200 | [diff] [blame] | 53 | printk(BIOS_ERR, |
Jon Murphy | d7b8dc9 | 2023-09-05 11:36:43 -0600 | [diff] [blame] | 54 | "TSPI: Couldn't measure FMAP into CRTM! rc %#x\n", rc); |
| 55 | return rc; |
Arthur Heymans | f28dcbc | 2021-04-29 09:31:01 +0200 | [diff] [blame] | 56 | } |
| 57 | } else { |
| 58 | printk(BIOS_ERR, "TSPI: Could not find FMAP!\n"); |
| 59 | } |
| 60 | |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 61 | /* measure bootblock from RO */ |
Werner Zeh | 823b7b3 | 2022-05-19 14:14:13 +0200 | [diff] [blame] | 62 | if (!CONFIG(ARCH_X86)) { |
| 63 | struct region_device bootblock_fmap; |
| 64 | if (fmap_locate_area_as_rdev("BOOTBLOCK", &bootblock_fmap) == 0) { |
Jon Murphy | d7b8dc9 | 2023-09-05 11:36:43 -0600 | [diff] [blame] | 65 | rc = tpm_measure_region(&bootblock_fmap, |
Sergii Dmytruk | 4129c26 | 2022-10-24 01:17:41 +0300 | [diff] [blame] | 66 | CONFIG_PCR_SRTM, |
Jon Murphy | d7b8dc9 | 2023-09-05 11:36:43 -0600 | [diff] [blame] | 67 | "FMAP: BOOTBLOCK"); |
| 68 | if (rc) |
| 69 | return rc; |
Werner Zeh | 823b7b3 | 2022-05-19 14:14:13 +0200 | [diff] [blame] | 70 | } |
Naveen R. Iyer | 93cbbbf | 2024-04-19 17:26:17 -0500 | [diff] [blame] | 71 | } else if (CONFIG(BOOTBLOCK_IN_CBFS)) { |
Julius Werner | 7e7cc1a | 2021-08-11 18:19:23 -0700 | [diff] [blame] | 72 | /* Mapping measures the file. We know we can safely map here because |
| 73 | bootblock-as-a-file is only used on x86, where we don't need cache to map. */ |
| 74 | enum cbfs_type type = CBFS_TYPE_BOOTBLOCK; |
| 75 | void *mapping = cbfs_ro_type_map("bootblock", NULL, &type); |
| 76 | if (!mapping) { |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 77 | printk(BIOS_INFO, |
| 78 | "TSPI: Couldn't measure bootblock into CRTM!\n"); |
Jon Murphy | d7b8dc9 | 2023-09-05 11:36:43 -0600 | [diff] [blame] | 79 | return TPM_CB_FAIL; |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 80 | } |
Julius Werner | 7e7cc1a | 2021-08-11 18:19:23 -0700 | [diff] [blame] | 81 | cbfs_unmap(mapping); |
Werner Zeh | 5c808e0 | 2022-05-19 09:16:28 +0200 | [diff] [blame] | 82 | } else { |
| 83 | /* Since none of the above conditions are met let the SOC code measure the |
| 84 | * bootblock. This accomplishes for cases where the bootblock is treated |
| 85 | * in a special way (e.g. part of IFWI or located in a different CBFS). */ |
Sergii Dmytruk | 4129c26 | 2022-10-24 01:17:41 +0300 | [diff] [blame] | 86 | if (tspi_soc_measure_bootblock(CONFIG_PCR_SRTM)) { |
Werner Zeh | 5c808e0 | 2022-05-19 09:16:28 +0200 | [diff] [blame] | 87 | printk(BIOS_INFO, |
| 88 | "TSPI: Couldn't measure bootblock into CRTM on SoC level!\n"); |
Jon Murphy | d7b8dc9 | 2023-09-05 11:36:43 -0600 | [diff] [blame] | 89 | return TPM_CB_FAIL; |
Werner Zeh | 5c808e0 | 2022-05-19 09:16:28 +0200 | [diff] [blame] | 90 | } |
| 91 | } |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 92 | |
Jon Murphy | d7b8dc9 | 2023-09-05 11:36:43 -0600 | [diff] [blame] | 93 | return TPM_SUCCESS; |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 94 | } |
| 95 | |
| 96 | static bool is_runtime_data(const char *name) |
| 97 | { |
Duncan Laurie | ab673ce | 2020-06-12 10:41:32 -0700 | [diff] [blame] | 98 | const char *allowlist = CONFIG_TPM_MEASURED_BOOT_RUNTIME_DATA; |
| 99 | size_t allowlist_len = sizeof(CONFIG_TPM_MEASURED_BOOT_RUNTIME_DATA) - 1; |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 100 | size_t name_len = strlen(name); |
harshit | aae1633 | 2020-05-12 12:55:39 +0530 | [diff] [blame] | 101 | const char *end; |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 102 | |
Duncan Laurie | ab673ce | 2020-06-12 10:41:32 -0700 | [diff] [blame] | 103 | if (!allowlist_len || !name_len) |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 104 | return false; |
| 105 | |
Duncan Laurie | ab673ce | 2020-06-12 10:41:32 -0700 | [diff] [blame] | 106 | while ((end = strchr(allowlist, ' '))) { |
| 107 | if (end - allowlist == name_len && !strncmp(allowlist, name, name_len)) |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 108 | return true; |
Duncan Laurie | ab673ce | 2020-06-12 10:41:32 -0700 | [diff] [blame] | 109 | allowlist = end + 1; |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 110 | } |
| 111 | |
Duncan Laurie | ab673ce | 2020-06-12 10:41:32 -0700 | [diff] [blame] | 112 | return !strcmp(allowlist, name); |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 113 | } |
| 114 | |
Jon Murphy | d7b8dc9 | 2023-09-05 11:36:43 -0600 | [diff] [blame] | 115 | tpm_result_t tspi_cbfs_measurement(const char *name, uint32_t type, const struct vb2_hash *hash) |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 116 | { |
| 117 | uint32_t pcr_index; |
Jon Murphy | d7b8dc9 | 2023-09-05 11:36:43 -0600 | [diff] [blame] | 118 | tpm_result_t rc = TPM_SUCCESS; |
Sergii Dmytruk | 2710df7 | 2022-11-10 00:40:51 +0200 | [diff] [blame] | 119 | char tpm_log_metadata[TPM_CB_LOG_PCR_HASH_NAME]; |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 120 | |
Sergii Dmytruk | 2710df7 | 2022-11-10 00:40:51 +0200 | [diff] [blame] | 121 | if (!tpm_log_available()) { |
Jon Murphy | d7b8dc9 | 2023-09-05 11:36:43 -0600 | [diff] [blame] | 122 | rc = tspi_init_crtm(); |
| 123 | if (rc) { |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 124 | printk(BIOS_WARNING, |
Frans Hendriks | 4622a2f | 2020-10-22 15:12:32 +0200 | [diff] [blame] | 125 | "Initializing CRTM failed!\n"); |
Jon Murphy | d7b8dc9 | 2023-09-05 11:36:43 -0600 | [diff] [blame] | 126 | return rc; |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 127 | } |
Frans Hendriks | 4622a2f | 2020-10-22 15:12:32 +0200 | [diff] [blame] | 128 | printk(BIOS_DEBUG, "CRTM initialized.\n"); |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 129 | } |
| 130 | |
Julius Werner | 7e7cc1a | 2021-08-11 18:19:23 -0700 | [diff] [blame] | 131 | switch (type) { |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 132 | case CBFS_TYPE_MRC_CACHE: |
Sergii Dmytruk | 4129c26 | 2022-10-24 01:17:41 +0300 | [diff] [blame] | 133 | pcr_index = CONFIG_PCR_RUNTIME_DATA; |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 134 | break; |
Bill XIE | bad08c2 | 2020-02-13 11:11:35 +0800 | [diff] [blame] | 135 | /* |
| 136 | * mrc.bin is code executed on CPU, so it |
| 137 | * should not be considered runtime data |
| 138 | */ |
| 139 | case CBFS_TYPE_MRC: |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 140 | case CBFS_TYPE_STAGE: |
| 141 | case CBFS_TYPE_SELF: |
Julius Werner | 0057262 | 2022-05-26 20:29:42 -0700 | [diff] [blame] | 142 | case CBFS_TYPE_FIT_PAYLOAD: |
Sergii Dmytruk | 4129c26 | 2022-10-24 01:17:41 +0300 | [diff] [blame] | 143 | pcr_index = CONFIG_PCR_SRTM; |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 144 | break; |
| 145 | default: |
| 146 | if (is_runtime_data(name)) |
Sergii Dmytruk | 4129c26 | 2022-10-24 01:17:41 +0300 | [diff] [blame] | 147 | pcr_index = CONFIG_PCR_RUNTIME_DATA; |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 148 | else |
Sergii Dmytruk | 4129c26 | 2022-10-24 01:17:41 +0300 | [diff] [blame] | 149 | pcr_index = CONFIG_PCR_SRTM; |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 150 | break; |
| 151 | } |
| 152 | |
Sergii Dmytruk | 2710df7 | 2022-11-10 00:40:51 +0200 | [diff] [blame] | 153 | snprintf(tpm_log_metadata, TPM_CB_LOG_PCR_HASH_NAME, "CBFS: %s", name); |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 154 | |
Julius Werner | 7e7cc1a | 2021-08-11 18:19:23 -0700 | [diff] [blame] | 155 | return tpm_extend_pcr(pcr_index, hash->algo, hash->raw, vb2_digest_size(hash->algo), |
Sergii Dmytruk | 2710df7 | 2022-11-10 00:40:51 +0200 | [diff] [blame] | 156 | tpm_log_metadata); |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 157 | } |
| 158 | |
Sergii Dmytruk | 26203e7 | 2022-11-10 17:56:26 +0200 | [diff] [blame] | 159 | void *tpm_log_init(void) |
| 160 | { |
| 161 | static void *tclt; |
| 162 | |
| 163 | /* We are dealing here with pre CBMEM environment. |
| 164 | * If cbmem isn't available use CAR or SRAM */ |
Arthur Heymans | b7cbb7c | 2023-08-11 11:31:05 +0200 | [diff] [blame] | 165 | if (!ENV_HAS_CBMEM && !CONFIG(VBOOT_RETURN_FROM_VERSTAGE)) |
Sergii Dmytruk | 26203e7 | 2022-11-10 17:56:26 +0200 | [diff] [blame] | 166 | return _tpm_log; |
| 167 | else if (ENV_CREATES_CBMEM |
| 168 | && !CONFIG(VBOOT_RETURN_FROM_VERSTAGE)) { |
| 169 | tclt = tpm_log_cbmem_init(); |
| 170 | if (!tclt) |
| 171 | return _tpm_log; |
| 172 | } else { |
| 173 | tclt = tpm_log_cbmem_init(); |
| 174 | } |
| 175 | |
| 176 | return tclt; |
| 177 | } |
| 178 | |
Jon Murphy | d7b8dc9 | 2023-09-05 11:36:43 -0600 | [diff] [blame] | 179 | tpm_result_t tspi_measure_cache_to_pcr(void) |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 180 | { |
| 181 | int i; |
Sergii Dmytruk | 26203e7 | 2022-11-10 17:56:26 +0200 | [diff] [blame] | 182 | int pcr; |
| 183 | const char *event_name; |
| 184 | const uint8_t *digest_data; |
| 185 | enum vb2_hash_algorithm digest_algo; |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 186 | |
Arthur Heymans | d873fa8 | 2021-06-14 09:18:45 +0200 | [diff] [blame] | 187 | /* This means the table is empty. */ |
Sergii Dmytruk | 2710df7 | 2022-11-10 00:40:51 +0200 | [diff] [blame] | 188 | if (!tpm_log_available()) |
Jon Murphy | d7b8dc9 | 2023-09-05 11:36:43 -0600 | [diff] [blame] | 189 | return TPM_SUCCESS; |
Arthur Heymans | d873fa8 | 2021-06-14 09:18:45 +0200 | [diff] [blame] | 190 | |
Sergii Dmytruk | 26203e7 | 2022-11-10 17:56:26 +0200 | [diff] [blame] | 191 | if (tpm_log_init() == NULL) { |
Sergii Dmytruk | 2710df7 | 2022-11-10 00:40:51 +0200 | [diff] [blame] | 192 | printk(BIOS_WARNING, "TPM LOG: log non-existent!\n"); |
Jon Murphy | d7b8dc9 | 2023-09-05 11:36:43 -0600 | [diff] [blame] | 193 | return TPM_CB_FAIL; |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 194 | } |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 195 | |
Sergii Dmytruk | 2710df7 | 2022-11-10 00:40:51 +0200 | [diff] [blame] | 196 | printk(BIOS_DEBUG, "TPM: Write digests cached in TPM log to PCR\n"); |
Sergii Dmytruk | 26203e7 | 2022-11-10 17:56:26 +0200 | [diff] [blame] | 197 | i = 0; |
| 198 | while (!tpm_log_get(i++, &pcr, &digest_data, &digest_algo, &event_name)) { |
| 199 | printk(BIOS_DEBUG, "TPM: Write digest for %s into PCR %d\n", event_name, pcr); |
Jon Murphy | d7b8dc9 | 2023-09-05 11:36:43 -0600 | [diff] [blame] | 200 | tpm_result_t rc = tlcl_extend(pcr, digest_data, digest_algo); |
Jon Murphy | 2460481 | 2023-09-05 10:37:05 -0600 | [diff] [blame] | 201 | if (rc != TPM_SUCCESS) { |
Sergii Dmytruk | 26203e7 | 2022-11-10 17:56:26 +0200 | [diff] [blame] | 202 | printk(BIOS_ERR, |
| 203 | "TPM: Writing digest of %s into PCR failed with error %d\n", |
Jon Murphy | 2460481 | 2023-09-05 10:37:05 -0600 | [diff] [blame] | 204 | event_name, rc); |
Jon Murphy | d7b8dc9 | 2023-09-05 11:36:43 -0600 | [diff] [blame] | 205 | return rc; |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 206 | } |
| 207 | } |
| 208 | |
Jon Murphy | d7b8dc9 | 2023-09-05 11:36:43 -0600 | [diff] [blame] | 209 | return TPM_SUCCESS; |
Bill XIE | c79e96b | 2019-08-22 20:28:36 +0800 | [diff] [blame] | 210 | } |
Sergii Dmytruk | 26203e7 | 2022-11-10 17:56:26 +0200 | [diff] [blame] | 211 | |
| 212 | #if !CONFIG(VBOOT_RETURN_FROM_VERSTAGE) |
| 213 | static void recover_tpm_log(int is_recovery) |
| 214 | { |
| 215 | const void *preram_log = _tpm_log; |
| 216 | void *ram_log = tpm_log_cbmem_init(); |
| 217 | |
| 218 | if (tpm_log_get_size(preram_log) > MAX_PRERAM_TPM_LOG_ENTRIES) { |
| 219 | printk(BIOS_WARNING, "TPM LOG: pre-RAM log is too full, possible corruption\n"); |
| 220 | return; |
| 221 | } |
| 222 | |
| 223 | if (ram_log == NULL) { |
| 224 | printk(BIOS_WARNING, "TPM LOG: CBMEM not available, something went wrong\n"); |
| 225 | return; |
| 226 | } |
| 227 | |
| 228 | tpm_log_copy_entries(_tpm_log, ram_log); |
| 229 | } |
| 230 | CBMEM_CREATION_HOOK(recover_tpm_log); |
| 231 | #endif |
| 232 | |
| 233 | BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_BOOT, BS_ON_ENTRY, tpm_log_dump, NULL); |