Angel Pons | 6bc1374 | 2020-04-05 15:46:38 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
Aaron Durbin | 7d14af8 | 2017-02-07 11:33:56 -0600 | [diff] [blame] | 2 | |
Kyösti Mälkki | 13f6650 | 2019-03-03 08:01:05 +0200 | [diff] [blame] | 3 | #include <device/mmio.h> |
Aaron Durbin | 7d14af8 | 2017-02-07 11:33:56 -0600 | [diff] [blame] | 4 | #include <bootstate.h> |
Andrey Petrov | c5f3685 | 2017-03-12 00:51:34 -0800 | [diff] [blame] | 5 | #include <commonlib/region.h> |
Aaron Durbin | 7d14af8 | 2017-02-07 11:33:56 -0600 | [diff] [blame] | 6 | #include <console/console.h> |
Andrey Petrov | c5f3685 | 2017-03-12 00:51:34 -0800 | [diff] [blame] | 7 | #include <fmap.h> |
Andrey Petrov | b1aded2 | 2017-03-03 08:12:36 -0800 | [diff] [blame] | 8 | #include <intelblocks/cse.h> |
Furquan Shaikh | d2c2f83 | 2018-11-07 10:24:31 -0800 | [diff] [blame] | 9 | #include <intelblocks/p2sb.h> |
| 10 | #include <intelblocks/pcr.h> |
Sean Rhodes | e71ea1e | 2022-07-19 11:20:05 +0100 | [diff] [blame] | 11 | #include <soc/cse.h> |
Furquan Shaikh | d2c2f83 | 2018-11-07 10:24:31 -0800 | [diff] [blame] | 12 | #include <soc/heci.h> |
| 13 | #include <soc/iomap.h> |
| 14 | #include <soc/pcr_ids.h> |
Aaron Durbin | 7d14af8 | 2017-02-07 11:33:56 -0600 | [diff] [blame] | 15 | #include <soc/pci_devs.h> |
Patrick Rudolph | e56189c | 2018-04-18 10:11:59 +0200 | [diff] [blame] | 16 | #include <device/pci_ops.h> |
Aaron Durbin | 7d14af8 | 2017-02-07 11:33:56 -0600 | [diff] [blame] | 17 | #include <stdint.h> |
| 18 | |
Andrey Petrov | b1aded2 | 2017-03-03 08:12:36 -0800 | [diff] [blame] | 19 | #define MKHI_GROUP_ID_MCA 0x0a |
| 20 | #define READ_FILE 0x02 |
| 21 | #define READ_FILE_FLAG_DEFAULT (1 << 0) |
| 22 | #define READ_FILE_FLAG_HASH (1 << 1) |
| 23 | #define READ_FILE_FLAG_EMULATED (1 << 2) |
| 24 | #define READ_FILE_FLAG_HW (1 << 3) |
| 25 | |
| 26 | #define MCA_MAX_FILE_PATH_SIZE 64 |
| 27 | |
| 28 | #define FUSE_LOCK_FILE "/fpf/intel/SocCfgLock" |
| 29 | |
Andrey Petrov | c5f3685 | 2017-03-12 00:51:34 -0800 | [diff] [blame] | 30 | /* Status values are made in such a way erase is not needed */ |
| 31 | static enum fuse_flash_state { |
| 32 | FUSE_FLASH_FUSED = 0xfc, |
| 33 | FUSE_FLASH_UNFUSED = 0xfe, |
| 34 | FUSE_FLASH_UNKNOWN = 0xff, |
| 35 | } g_fuse_state; |
| 36 | |
| 37 | #define FPF_STATUS_FMAP "FPF_STATUS" |
Andrey Petrov | b1aded2 | 2017-03-03 08:12:36 -0800 | [diff] [blame] | 38 | |
| 39 | /* |
| 40 | * Read file from CSE internal filesystem. |
| 41 | * size is maximum length of provided buffer buff, which is updated with actual |
| 42 | * size of the file read. flags indicate whether real file or fuse is used. |
| 43 | * Returns 1 on success and 0 otherwise. |
| 44 | */ |
| 45 | static int read_cse_file(const char *path, void *buff, size_t *size, |
| 46 | size_t offset, uint32_t flags) |
| 47 | { |
Andrey Petrov | b1aded2 | 2017-03-03 08:12:36 -0800 | [diff] [blame] | 48 | size_t reply_size; |
| 49 | |
Andrey Petrov | b1aded2 | 2017-03-03 08:12:36 -0800 | [diff] [blame] | 50 | struct mca_command { |
Sridhar Siricilla | f35eee9 | 2019-09-23 19:38:21 +0530 | [diff] [blame] | 51 | struct mkhi_hdr hdr; |
Andrey Petrov | b1aded2 | 2017-03-03 08:12:36 -0800 | [diff] [blame] | 52 | char file_name[MCA_MAX_FILE_PATH_SIZE]; |
| 53 | uint32_t offset; |
| 54 | uint32_t data_size; |
| 55 | uint8_t flags; |
Stefan Reinauer | 6a00113 | 2017-07-13 02:20:27 +0200 | [diff] [blame] | 56 | } __packed msg; |
Andrey Petrov | b1aded2 | 2017-03-03 08:12:36 -0800 | [diff] [blame] | 57 | |
| 58 | struct mca_response { |
Sridhar Siricilla | f35eee9 | 2019-09-23 19:38:21 +0530 | [diff] [blame] | 59 | struct mkhi_hdr hdr; |
Andrey Petrov | b1aded2 | 2017-03-03 08:12:36 -0800 | [diff] [blame] | 60 | uint32_t data_size; |
| 61 | uint8_t buffer[128]; |
Stefan Reinauer | 6a00113 | 2017-07-13 02:20:27 +0200 | [diff] [blame] | 62 | } __packed rmsg; |
Andrey Petrov | b1aded2 | 2017-03-03 08:12:36 -0800 | [diff] [blame] | 63 | |
| 64 | if (sizeof(rmsg.buffer) < *size) { |
| 65 | printk(BIOS_ERR, "internal buffer is too small\n"); |
| 66 | return 0; |
| 67 | } |
| 68 | |
Hannah Williams | 58810c7 | 2017-08-02 18:13:33 -0700 | [diff] [blame] | 69 | if (strnlen(path, sizeof(msg.file_name)) >= sizeof(msg.file_name)) { |
| 70 | printk(BIOS_ERR, "path too big for msg.file_name buffer\n"); |
| 71 | return 0; |
| 72 | } |
Andrey Petrov | b1aded2 | 2017-03-03 08:12:36 -0800 | [diff] [blame] | 73 | strncpy(msg.file_name, path, sizeof(msg.file_name)); |
Sridhar Siricilla | f35eee9 | 2019-09-23 19:38:21 +0530 | [diff] [blame] | 74 | msg.hdr.group_id = MKHI_GROUP_ID_MCA; |
| 75 | msg.hdr.command = READ_FILE; |
Andrey Petrov | b1aded2 | 2017-03-03 08:12:36 -0800 | [diff] [blame] | 76 | msg.flags = flags; |
| 77 | msg.data_size = *size; |
| 78 | msg.offset = offset; |
| 79 | |
Andrey Petrov | b1aded2 | 2017-03-03 08:12:36 -0800 | [diff] [blame] | 80 | reply_size = sizeof(rmsg); |
Andrey Petrov | b1aded2 | 2017-03-03 08:12:36 -0800 | [diff] [blame] | 81 | |
Sridhar Siricilla | 6836da2 | 2022-02-23 23:36:45 +0530 | [diff] [blame] | 82 | if (heci_send_receive(&msg, sizeof(msg), &rmsg, &reply_size, HECI_MKHI_ADDR)) { |
Rizwan Qureshi | 957857d | 2021-08-30 16:43:57 +0530 | [diff] [blame] | 83 | printk(BIOS_ERR, "HECI: Failed to read file\n"); |
Andrey Petrov | b1aded2 | 2017-03-03 08:12:36 -0800 | [diff] [blame] | 84 | return 0; |
| 85 | } |
| 86 | |
| 87 | if (rmsg.data_size > *size) { |
| 88 | printk(BIOS_ERR, "reply is too large\n"); |
| 89 | return 0; |
| 90 | } |
| 91 | |
| 92 | memcpy(buff, rmsg.buffer, rmsg.data_size); |
| 93 | *size = rmsg.data_size; |
| 94 | |
| 95 | return 1; |
| 96 | } |
| 97 | |
Andrey Petrov | c5f3685 | 2017-03-12 00:51:34 -0800 | [diff] [blame] | 98 | static enum fuse_flash_state load_cached_fpf(struct region_device *rdev) |
| 99 | { |
| 100 | enum fuse_flash_state state; |
| 101 | uint8_t buff; |
| 102 | |
| 103 | state = FUSE_FLASH_UNKNOWN; |
| 104 | |
| 105 | if (rdev_readat(rdev, &buff, 0, sizeof(buff)) >= 0) { |
| 106 | state = read8(&buff); |
| 107 | return state; |
| 108 | } |
| 109 | |
| 110 | printk(BIOS_WARNING, "failed to load cached FPF value\n"); |
| 111 | |
| 112 | return state; |
| 113 | } |
| 114 | |
| 115 | static |
| 116 | int save_fpf_state(enum fuse_flash_state state, struct region_device *rdev) |
| 117 | { |
| 118 | uint8_t buff; |
| 119 | |
Elyes Haouas | 9018dee | 2022-11-18 15:07:33 +0100 | [diff] [blame] | 120 | write8(&buff, (uint8_t)state); |
Andrey Petrov | c5f3685 | 2017-03-12 00:51:34 -0800 | [diff] [blame] | 121 | return rdev_writeat(rdev, &buff, 0, sizeof(buff)); |
| 122 | } |
| 123 | |
Andrey Petrov | b1aded2 | 2017-03-03 08:12:36 -0800 | [diff] [blame] | 124 | static void fpf_blown(void *unused) |
| 125 | { |
Andrey Petrov | c5f3685 | 2017-03-12 00:51:34 -0800 | [diff] [blame] | 126 | uint8_t fuse; |
| 127 | struct region_device rdev; |
Andrey Petrov | b1aded2 | 2017-03-03 08:12:36 -0800 | [diff] [blame] | 128 | size_t sz = sizeof(fuse); |
Andrey Petrov | c5f3685 | 2017-03-12 00:51:34 -0800 | [diff] [blame] | 129 | bool rdev_valid = false; |
Andrey Petrov | b1aded2 | 2017-03-03 08:12:36 -0800 | [diff] [blame] | 130 | |
Andrey Petrov | c5f3685 | 2017-03-12 00:51:34 -0800 | [diff] [blame] | 131 | if (fmap_locate_area_as_rdev_rw(FPF_STATUS_FMAP, &rdev) == 0) { |
| 132 | rdev_valid = true; |
| 133 | g_fuse_state = load_cached_fpf(&rdev); |
| 134 | if (g_fuse_state != FUSE_FLASH_UNKNOWN) |
| 135 | return; |
Andrey Petrov | b1aded2 | 2017-03-03 08:12:36 -0800 | [diff] [blame] | 136 | } |
Andrey Petrov | c5f3685 | 2017-03-12 00:51:34 -0800 | [diff] [blame] | 137 | |
| 138 | if (!read_cse_file(FUSE_LOCK_FILE, &fuse, &sz, 0, READ_FILE_FLAG_HW)) |
| 139 | return; |
| 140 | |
| 141 | g_fuse_state = fuse == 1 ? FUSE_FLASH_FUSED : FUSE_FLASH_UNFUSED; |
| 142 | |
| 143 | if (rdev_valid && (save_fpf_state(g_fuse_state, &rdev) < 0)) |
| 144 | printk(BIOS_CRIT, "failed to save FPF state\n"); |
Andrey Petrov | b1aded2 | 2017-03-03 08:12:36 -0800 | [diff] [blame] | 145 | } |
| 146 | |
Aaron Durbin | 7d14af8 | 2017-02-07 11:33:56 -0600 | [diff] [blame] | 147 | static uint32_t dump_status(int index, int reg_addr) |
| 148 | { |
Sridhar Siricilla | 2cc6691 | 2019-08-31 11:20:34 +0530 | [diff] [blame] | 149 | uint32_t reg; |
| 150 | |
| 151 | reg = me_read_config32(reg_addr); |
Aaron Durbin | 7d14af8 | 2017-02-07 11:33:56 -0600 | [diff] [blame] | 152 | |
| 153 | printk(BIOS_DEBUG, "CSE FWSTS%d: 0x%08x\n", index, reg); |
| 154 | |
| 155 | return reg; |
| 156 | } |
| 157 | |
Furquan Shaikh | d2c2f83 | 2018-11-07 10:24:31 -0800 | [diff] [blame] | 158 | static void dump_cse_state(void) |
Aaron Durbin | 7d14af8 | 2017-02-07 11:33:56 -0600 | [diff] [blame] | 159 | { |
Sean Rhodes | e71ea1e | 2022-07-19 11:20:05 +0100 | [diff] [blame] | 160 | union cse_fwsts1 fwsts1; |
Sean Rhodes | 03f6820 | 2022-07-19 13:50:09 +0100 | [diff] [blame] | 161 | union cse_fwsts2 fwsts2; |
| 162 | union cse_fwsts3 fwsts3; |
| 163 | union cse_fwsts4 fwsts4; |
| 164 | union cse_fwsts5 fwsts5; |
| 165 | union cse_fwsts6 fwsts6; |
Aaron Durbin | 7d14af8 | 2017-02-07 11:33:56 -0600 | [diff] [blame] | 166 | |
Sridhar Siricilla | 2cc6691 | 2019-08-31 11:20:34 +0530 | [diff] [blame] | 167 | if (!is_cse_enabled()) |
| 168 | return; |
| 169 | |
Sean Rhodes | e71ea1e | 2022-07-19 11:20:05 +0100 | [diff] [blame] | 170 | fwsts1.data = dump_status(1, PCI_ME_HFSTS1); |
Sean Rhodes | 03f6820 | 2022-07-19 13:50:09 +0100 | [diff] [blame] | 171 | fwsts2.data = dump_status(2, PCI_ME_HFSTS2); |
| 172 | fwsts3.data = dump_status(3, PCI_ME_HFSTS3); |
| 173 | fwsts4.data = dump_status(4, PCI_ME_HFSTS4); |
| 174 | fwsts5.data = dump_status(5, PCI_ME_HFSTS5); |
| 175 | fwsts6.data = dump_status(6, PCI_ME_HFSTS6); |
Aaron Durbin | 7d14af8 | 2017-02-07 11:33:56 -0600 | [diff] [blame] | 176 | |
Sean Rhodes | e71ea1e | 2022-07-19 11:20:05 +0100 | [diff] [blame] | 177 | printk(BIOS_DEBUG, "CSE: Working State : %u\n", |
| 178 | fwsts1.fields.working_state); |
| 179 | printk(BIOS_DEBUG, "CSE: Manufacturing Mode : %s\n", |
| 180 | fwsts1.fields.mfg_mode ? "YES" : "NO"); |
| 181 | printk(BIOS_DEBUG, "CSE: Operation State : %u\n", |
| 182 | fwsts1.fields.operation_state); |
| 183 | printk(BIOS_DEBUG, "CSE: FW Init Complete : %s\n", |
| 184 | fwsts1.fields.fw_init_complete ? "YES" : "NO"); |
| 185 | printk(BIOS_DEBUG, "CSE: Error Code : %u\n", |
| 186 | fwsts1.fields.error_code); |
| 187 | printk(BIOS_DEBUG, "CSE: Operation Mode : %u\n", |
| 188 | fwsts1.fields.operation_mode); |
Sean Rhodes | 03f6820 | 2022-07-19 13:50:09 +0100 | [diff] [blame] | 189 | printk(BIOS_DEBUG, "CSE: IBB Verification Result: %s\n", |
| 190 | fwsts3.fields.ibb_verif_result ? "PASS" : "FAIL"); |
| 191 | printk(BIOS_DEBUG, "CSE: IBB Verification Done : %s\n", |
| 192 | fwsts3.fields.ibb_verif_done ? "YES" : "NO"); |
| 193 | printk(BIOS_DEBUG, "CSE: Actual IBB Size : %u\n", |
| 194 | fwsts3.fields.ibb_size); |
| 195 | printk(BIOS_DEBUG, "CSE: Verified Boot Valid : %s\n", |
| 196 | fwsts4.fields.txe_veri_boot_valid ? "PASS" : "FAIL"); |
| 197 | printk(BIOS_DEBUG, "CSE: Verified Boot Test : %s\n", |
| 198 | fwsts4.fields.txe_veri_boot_test ? "YES" : "NO"); |
| 199 | printk(BIOS_DEBUG, "CSE: FPF status : %s\n", |
| 200 | fwsts6.fields.fpf_commited ? "FUSED" : "UNFUSED"); |
| 201 | printk(BIOS_DEBUG, "CSE: Error Status Code : %u\n", |
| 202 | fwsts5.fields.error_status_code); |
Andrey Petrov | b1aded2 | 2017-03-03 08:12:36 -0800 | [diff] [blame] | 203 | } |
Furquan Shaikh | d2c2f83 | 2018-11-07 10:24:31 -0800 | [diff] [blame] | 204 | |
| 205 | #define PCR_PSFX_T0_SHDW_PCIEN 0x1C |
| 206 | #define PCR_PSFX_T0_SHDW_PCIEN_FUNDIS (1 << 8) |
| 207 | |
Subrata Banik | ea47c6b | 2022-01-28 13:12:58 +0530 | [diff] [blame] | 208 | void soc_disable_heci1_using_pcr(void) |
Furquan Shaikh | d2c2f83 | 2018-11-07 10:24:31 -0800 | [diff] [blame] | 209 | { |
| 210 | pcr_or32(PID_PSF3, PSF3_BASE_ADDRESS + PCR_PSFX_T0_SHDW_PCIEN, |
| 211 | PCR_PSFX_T0_SHDW_PCIEN_FUNDIS); |
| 212 | } |
| 213 | |
| 214 | void heci_cse_lockdown(void) |
| 215 | { |
| 216 | dump_cse_state(); |
| 217 | |
| 218 | /* |
| 219 | * It is safe to disable HECI1 now since we won't be talking to the ME |
| 220 | * anymore. |
| 221 | */ |
Subrata Banik | 206b0bc | 2022-01-06 09:34:43 +0000 | [diff] [blame] | 222 | if (CONFIG(DISABLE_HECI1_AT_PRE_BOOT)) |
Subrata Banik | ea47c6b | 2022-01-28 13:12:58 +0530 | [diff] [blame] | 223 | heci1_disable(); |
Furquan Shaikh | d2c2f83 | 2018-11-07 10:24:31 -0800 | [diff] [blame] | 224 | } |
| 225 | |
Andrey Petrov | b1aded2 | 2017-03-03 08:12:36 -0800 | [diff] [blame] | 226 | BOOT_STATE_INIT_ENTRY(BS_DEV_INIT, BS_ON_ENTRY, fpf_blown, NULL); |
Sridhar Siricilla | 24a974a | 2020-02-19 14:41:36 +0530 | [diff] [blame] | 227 | BOOT_STATE_INIT_ENTRY(BS_DEV_INIT, BS_ON_EXIT, print_me_fw_version, NULL); |