1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2022 Beckhoff Automation GmbH & Co. KG 5 * Author: Corvin Köhne <c.koehne@beckhoff.com> 6 */ 7 8 #include <sys/cdefs.h> 9 #include <sys/types.h> 10 #include <sys/param.h> 11 #include <sys/linker_set.h> 12 13 #include <machine/vmm.h> 14 15 #include <assert.h> 16 #include <err.h> 17 #include <errno.h> 18 #include <pthread.h> 19 #include <pthread_np.h> 20 #include <stddef.h> 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <vmmapi.h> 24 25 #include "basl.h" 26 #include "config.h" 27 #include "mem.h" 28 #include "qemu_fwcfg.h" 29 #include "tpm_intf.h" 30 31 #define TPM_CRB_ADDRESS 0xFED40000 32 #define TPM_CRB_REGS_SIZE 0x1000 33 34 #define TPM_CRB_DATA_BUFFER_ADDRESS \ 35 (TPM_CRB_ADDRESS + offsetof(struct tpm_crb_regs, data_buffer)) 36 #define TPM_CRB_DATA_BUFFER_SIZE 0xF80 37 38 #define TPM_CRB_LOCALITIES_MAX 5 39 40 struct tpm_crb_regs { 41 union tpm_crb_reg_loc_state { 42 struct { 43 uint32_t tpm_established : 1; 44 uint32_t loc_assigned : 1; 45 uint32_t active_locality : 3; 46 uint32_t _reserved : 2; 47 uint32_t tpm_req_valid_sts : 1; 48 }; 49 uint32_t val; 50 } loc_state; /* 0h */ 51 uint8_t _reserved1[4]; /* 4h */ 52 union tpm_crb_reg_loc_ctrl { 53 struct { 54 uint32_t request_access : 1; 55 uint32_t relinquish : 1; 56 uint32_t seize : 1; 57 uint32_t reset_establishment_bit : 1; 58 }; 59 uint32_t val; 60 } loc_ctrl; /* 8h */ 61 union tpm_crb_reg_loc_sts { 62 struct { 63 uint32_t granted : 1; 64 uint32_t been_seized : 1; 65 }; 66 uint32_t val; 67 } loc_sts; /* Ch */ 68 uint8_t _reserved2[0x20]; /* 10h */ 69 union tpm_crb_reg_intf_id { 70 struct { 71 uint64_t interface_type : 4; 72 uint64_t interface_version : 4; 73 uint64_t cap_locality : 1; 74 uint64_t cap_crb_idle_bypass : 1; 75 uint64_t _reserved1 : 1; 76 uint64_t cap_data_xfer_size_support : 2; 77 uint64_t cap_fifo : 1; 78 uint64_t cap_crb : 1; 79 uint64_t _reserved2 : 2; 80 uint64_t interface_selector : 2; 81 uint64_t intf_sel_lock : 1; 82 uint64_t _reserved3 : 4; 83 uint64_t rid : 8; 84 uint64_t vid : 16; 85 uint64_t did : 16; 86 }; 87 uint64_t val; 88 } intf_id; /* 30h */ 89 union tpm_crb_reg_ctrl_ext { 90 struct { 91 uint32_t clear; 92 uint32_t remaining_bytes; 93 }; 94 uint64_t val; 95 } ctrl_ext; /* 38 */ 96 union tpm_crb_reg_ctrl_req { 97 struct { 98 uint32_t cmd_ready : 1; 99 uint32_t go_idle : 1; 100 }; 101 uint32_t val; 102 } ctrl_req; /* 40h */ 103 union tpm_crb_reg_ctrl_sts { 104 struct { 105 uint32_t tpm_sts : 1; 106 uint32_t tpm_idle : 1; 107 }; 108 uint32_t val; 109 } ctrl_sts; /* 44h */ 110 union tpm_crb_reg_ctrl_cancel { 111 struct { 112 uint32_t cancel : 1; 113 }; 114 uint32_t val; 115 } ctrl_cancel; /* 48h */ 116 union tpm_crb_reg_ctrl_start { 117 struct { 118 uint32_t start : 1; 119 }; 120 uint32_t val; 121 } ctrl_start; /* 4Ch*/ 122 uint32_t int_enable; /* 50h */ 123 uint32_t int_sts; /* 54h */ 124 uint32_t cmd_size; /* 58h */ 125 uint32_t cmd_addr_lo; /* 5Ch */ 126 uint32_t cmd_addr_hi; /* 60h */ 127 uint32_t rsp_size; /* 64h */ 128 uint64_t rsp_addr; /* 68h */ 129 uint8_t _reserved3[0x10]; /* 70h */ 130 uint8_t data_buffer[TPM_CRB_DATA_BUFFER_SIZE]; /* 80h */ 131 } __packed; 132 static_assert(sizeof(struct tpm_crb_regs) == TPM_CRB_REGS_SIZE, 133 "Invalid size of tpm_crb"); 134 135 #define CRB_CMD_SIZE_READ(regs) (regs.cmd_size) 136 #define CRB_CMD_SIZE_WRITE(regs, val) \ 137 do { \ 138 regs.cmd_size = val; \ 139 } while (0) 140 #define CRB_CMD_ADDR_READ(regs) \ 141 (((uint64_t)regs.cmd_addr_hi << 32) | regs.cmd_addr_lo) 142 #define CRB_CMD_ADDR_WRITE(regs, val) \ 143 do { \ 144 regs.cmd_addr_lo = val & 0xFFFFFFFF; \ 145 regs.cmd_addr_hi = val >> 32; \ 146 } while (0) 147 #define CRB_RSP_SIZE_READ(regs) (regs.rsp_size) 148 #define CRB_RSP_SIZE_WRITE(regs, val) \ 149 do { \ 150 regs.rsp_size = val; \ 151 } while (0) 152 #define CRB_RSP_ADDR_READ(regs) (regs.rsp_addr) 153 #define CRB_RSP_ADDR_WRITE(regs, val) \ 154 do { \ 155 regs.rsp_addr = val; \ 156 } while (0) 157 158 struct tpm_crb { 159 struct tpm_crb_regs regs; 160 }; 161 162 static int 163 tpm_crb_init(void **sc) 164 { 165 struct tpm_crb *crb = NULL; 166 int error; 167 168 assert(sc != NULL); 169 170 crb = calloc(1, sizeof(struct tpm_crb)); 171 if (crb == NULL) { 172 warnx("%s: failed to allocate tpm crb", __func__); 173 error = ENOMEM; 174 goto err_out; 175 } 176 177 memset(crb, 0, sizeof(*crb)); 178 179 crb->regs.loc_state.tpm_req_valid_sts = true; 180 crb->regs.loc_state.tpm_established = true; 181 182 crb->regs.intf_id.interface_type = TPM_INTF_TYPE_CRB; 183 crb->regs.intf_id.interface_version = TPM_INTF_VERSION_CRB; 184 crb->regs.intf_id.cap_locality = false; 185 crb->regs.intf_id.cap_crb_idle_bypass = false; 186 crb->regs.intf_id.cap_data_xfer_size_support = 187 TPM_INTF_CAP_CRB_DATA_XFER_SIZE_64; 188 crb->regs.intf_id.cap_fifo = false; 189 crb->regs.intf_id.cap_crb = true; 190 crb->regs.intf_id.interface_selector = TPM_INTF_SELECTOR_CRB; 191 crb->regs.intf_id.intf_sel_lock = false; 192 crb->regs.intf_id.rid = 0; 193 crb->regs.intf_id.vid = 0x1014; /* IBM */ 194 crb->regs.intf_id.did = 0x1014; /* IBM */ 195 196 crb->regs.ctrl_sts.tpm_idle = true; 197 198 CRB_CMD_SIZE_WRITE(crb->regs, TPM_CRB_DATA_BUFFER_SIZE); 199 CRB_CMD_ADDR_WRITE(crb->regs, TPM_CRB_DATA_BUFFER_ADDRESS); 200 CRB_RSP_SIZE_WRITE(crb->regs, TPM_CRB_DATA_BUFFER_SIZE); 201 CRB_RSP_ADDR_WRITE(crb->regs, TPM_CRB_DATA_BUFFER_ADDRESS); 202 203 *sc = crb; 204 205 return (0); 206 207 err_out: 208 free(crb); 209 210 return (error); 211 } 212 213 static void 214 tpm_crb_deinit(void *sc) 215 { 216 struct tpm_crb *crb; 217 218 if (sc == NULL) { 219 return; 220 } 221 222 crb = sc; 223 224 free(crb); 225 } 226 227 static struct tpm_intf tpm_intf_crb = { 228 .name = "crb", 229 .init = tpm_crb_init, 230 .deinit = tpm_crb_deinit, 231 }; 232 TPM_INTF_SET(tpm_intf_crb); 233