1 /*- 2 * Copyright (c) 2018 Stormshield. 3 * Copyright (c) 2018 Semihalf. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 19 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 #include <sys/random.h> 30 31 #include "tpm20.h" 32 33 #define TPM_HARVEST_SIZE 16 34 /* 35 * Perform a harvest every 10 seconds. 36 * Since discrete TPMs are painfully slow 37 * we don't want to execute this too often 38 * as the chip is likely to be used by others too. 39 */ 40 #define TPM_HARVEST_INTERVAL 10 41 42 MALLOC_DEFINE(M_TPM20, "tpm_buffer", "buffer for tpm 2.0 driver"); 43 44 static void tpm20_discard_buffer(void *arg); 45 #ifdef TPM_HARVEST 46 static void tpm20_harvest(void *arg, int unused); 47 #endif 48 static int tpm20_save_state(device_t dev, bool suspend); 49 50 static d_open_t tpm20_open; 51 static d_close_t tpm20_close; 52 static d_read_t tpm20_read; 53 static d_write_t tpm20_write; 54 static d_ioctl_t tpm20_ioctl; 55 56 static struct cdevsw tpm20_cdevsw = { 57 .d_version = D_VERSION, 58 .d_open = tpm20_open, 59 .d_close = tpm20_close, 60 .d_read = tpm20_read, 61 .d_write = tpm20_write, 62 .d_ioctl = tpm20_ioctl, 63 .d_name = "tpm20", 64 }; 65 66 int 67 tpm20_read(struct cdev *dev, struct uio *uio, int flags) 68 { 69 struct tpm_sc *sc; 70 size_t bytes_to_transfer; 71 int result = 0; 72 73 sc = (struct tpm_sc *)dev->si_drv1; 74 75 callout_stop(&sc->discard_buffer_callout); 76 sx_xlock(&sc->dev_lock); 77 if (sc->owner_tid != uio->uio_td->td_tid) { 78 sx_xunlock(&sc->dev_lock); 79 return (EPERM); 80 } 81 82 bytes_to_transfer = MIN(sc->pending_data_length, uio->uio_resid); 83 if (bytes_to_transfer > 0) { 84 result = uiomove((caddr_t) sc->buf, bytes_to_transfer, uio); 85 memset(sc->buf, 0, TPM_BUFSIZE); 86 sc->pending_data_length = 0; 87 cv_signal(&sc->buf_cv); 88 } else { 89 result = ETIMEDOUT; 90 } 91 92 sx_xunlock(&sc->dev_lock); 93 94 return (result); 95 } 96 97 int 98 tpm20_write(struct cdev *dev, struct uio *uio, int flags) 99 { 100 struct tpm_sc *sc; 101 size_t byte_count; 102 int result = 0; 103 104 sc = (struct tpm_sc *)dev->si_drv1; 105 106 byte_count = uio->uio_resid; 107 if (byte_count < TPM_HEADER_SIZE) { 108 device_printf(sc->dev, 109 "Requested transfer is too small\n"); 110 return (EINVAL); 111 } 112 113 if (byte_count > TPM_BUFSIZE) { 114 device_printf(sc->dev, 115 "Requested transfer is too large\n"); 116 return (E2BIG); 117 } 118 119 sx_xlock(&sc->dev_lock); 120 121 while (sc->pending_data_length != 0) 122 cv_wait(&sc->buf_cv, &sc->dev_lock); 123 124 result = uiomove(sc->buf, byte_count, uio); 125 if (result != 0) { 126 sx_xunlock(&sc->dev_lock); 127 return (result); 128 } 129 130 result = sc->transmit(sc, byte_count); 131 132 if (result == 0) { 133 callout_reset(&sc->discard_buffer_callout, 134 TPM_READ_TIMEOUT / tick, tpm20_discard_buffer, sc); 135 sc->owner_tid = uio->uio_td->td_tid; 136 } 137 138 sx_xunlock(&sc->dev_lock); 139 return (result); 140 } 141 142 static void 143 tpm20_discard_buffer(void *arg) 144 { 145 struct tpm_sc *sc; 146 147 sc = (struct tpm_sc *)arg; 148 if (callout_pending(&sc->discard_buffer_callout)) 149 return; 150 151 sx_xlock(&sc->dev_lock); 152 153 memset(sc->buf, 0, TPM_BUFSIZE); 154 sc->pending_data_length = 0; 155 156 cv_signal(&sc->buf_cv); 157 sx_xunlock(&sc->dev_lock); 158 159 device_printf(sc->dev, 160 "User failed to read buffer in time\n"); 161 } 162 163 int 164 tpm20_open(struct cdev *dev, int flag, int mode, struct thread *td) 165 { 166 167 return (0); 168 } 169 170 int 171 tpm20_close(struct cdev *dev, int flag, int mode, struct thread *td) 172 { 173 174 return (0); 175 } 176 177 int 178 tpm20_ioctl(struct cdev *dev, u_long cmd, caddr_t data, 179 int flags, struct thread *td) 180 { 181 182 return (ENOTTY); 183 } 184 185 int 186 tpm20_init(struct tpm_sc *sc) 187 { 188 struct make_dev_args args; 189 int result; 190 191 cv_init(&sc->buf_cv, "TPM buffer cv"); 192 callout_init(&sc->discard_buffer_callout, 1); 193 sc->pending_data_length = 0; 194 195 make_dev_args_init(&args); 196 args.mda_devsw = &tpm20_cdevsw; 197 args.mda_uid = UID_ROOT; 198 args.mda_gid = GID_WHEEL; 199 args.mda_mode = TPM_CDEV_PERM_FLAG; 200 args.mda_si_drv1 = sc; 201 result = make_dev_s(&args, &sc->sc_cdev, TPM_CDEV_NAME); 202 if (result != 0) 203 tpm20_release(sc); 204 205 #ifdef TPM_HARVEST 206 random_harvest_register_source(RANDOM_PURE_TPM); 207 TIMEOUT_TASK_INIT(taskqueue_thread, &sc->harvest_task, 0, 208 tpm20_harvest, sc); 209 taskqueue_enqueue_timeout(taskqueue_thread, &sc->harvest_task, 0); 210 #endif 211 212 return (result); 213 214 } 215 216 void 217 tpm20_release(struct tpm_sc *sc) 218 { 219 220 #ifdef TPM_HARVEST 221 if (device_is_attached(sc->dev)) 222 taskqueue_drain_timeout(taskqueue_thread, &sc->harvest_task); 223 random_harvest_deregister_source(RANDOM_PURE_TPM); 224 #endif 225 226 if (sc->buf != NULL) 227 free(sc->buf, M_TPM20); 228 229 sx_destroy(&sc->dev_lock); 230 cv_destroy(&sc->buf_cv); 231 if (sc->sc_cdev != NULL) 232 destroy_dev(sc->sc_cdev); 233 } 234 235 int 236 tpm20_suspend(device_t dev) 237 { 238 return (tpm20_save_state(dev, true)); 239 } 240 241 int 242 tpm20_shutdown(device_t dev) 243 { 244 return (tpm20_save_state(dev, false)); 245 } 246 247 #ifdef TPM_HARVEST 248 /* 249 * Get TPM_HARVEST_SIZE random bytes and add them 250 * into system entropy pool. 251 */ 252 static void 253 tpm20_harvest(void *arg, int unused) 254 { 255 struct tpm_sc *sc; 256 unsigned char entropy[TPM_HARVEST_SIZE]; 257 uint16_t entropy_size; 258 int result; 259 uint8_t cmd[] = { 260 0x80, 0x01, /* TPM_ST_NO_SESSIONS tag*/ 261 0x00, 0x00, 0x00, 0x0c, /* cmd length */ 262 0x00, 0x00, 0x01, 0x7b, /* cmd TPM_CC_GetRandom */ 263 0x00, TPM_HARVEST_SIZE /* number of bytes requested */ 264 }; 265 266 sc = arg; 267 sx_xlock(&sc->dev_lock); 268 while (sc->pending_data_length != 0) 269 cv_wait(&sc->buf_cv, &sc->dev_lock); 270 271 memcpy(sc->buf, cmd, sizeof(cmd)); 272 result = sc->transmit(sc, sizeof(cmd)); 273 if (result != 0) { 274 sx_xunlock(&sc->dev_lock); 275 return; 276 } 277 278 /* Ignore response size */ 279 sc->pending_data_length = 0; 280 281 /* The number of random bytes we got is placed right after the header */ 282 entropy_size = (uint16_t) sc->buf[TPM_HEADER_SIZE + 1]; 283 if (entropy_size > 0) { 284 entropy_size = MIN(entropy_size, TPM_HARVEST_SIZE); 285 memcpy(entropy, 286 sc->buf + TPM_HEADER_SIZE + sizeof(uint16_t), 287 entropy_size); 288 } 289 290 sx_xunlock(&sc->dev_lock); 291 if (entropy_size > 0) 292 random_harvest_queue(entropy, entropy_size, RANDOM_PURE_TPM); 293 294 taskqueue_enqueue_timeout(taskqueue_thread, &sc->harvest_task, 295 hz * TPM_HARVEST_INTERVAL); 296 } 297 #endif /* TPM_HARVEST */ 298 299 static int 300 tpm20_save_state(device_t dev, bool suspend) 301 { 302 struct tpm_sc *sc; 303 uint8_t save_cmd[] = { 304 0x80, 0x01, /* TPM_ST_NO_SESSIONS tag*/ 305 0x00, 0x00, 0x00, 0x0C, /* cmd length */ 306 0x00, 0x00, 0x01, 0x45, /* cmd TPM_CC_Shutdown */ 307 0x00, 0x00 /* TPM_SU_STATE */ 308 }; 309 310 sc = device_get_softc(dev); 311 312 /* 313 * Inform the TPM whether we are going to suspend or reboot/shutdown. 314 */ 315 if (suspend) 316 save_cmd[11] = 1; /* TPM_SU_STATE */ 317 318 if (sc == NULL || sc->buf == NULL) 319 return (0); 320 321 sx_xlock(&sc->dev_lock); 322 323 memcpy(sc->buf, save_cmd, sizeof(save_cmd)); 324 sc->transmit(sc, sizeof(save_cmd)); 325 326 sx_xunlock(&sc->dev_lock); 327 328 return (0); 329 } 330 331 int32_t 332 tpm20_get_timeout(uint32_t command) 333 { 334 int32_t timeout; 335 336 switch (command) { 337 case TPM_CC_CreatePrimary: 338 case TPM_CC_Create: 339 case TPM_CC_CreateLoaded: 340 timeout = TPM_TIMEOUT_LONG; 341 break; 342 case TPM_CC_SequenceComplete: 343 case TPM_CC_Startup: 344 case TPM_CC_SequenceUpdate: 345 case TPM_CC_GetCapability: 346 case TPM_CC_PCR_Extend: 347 case TPM_CC_EventSequenceComplete: 348 case TPM_CC_HashSequenceStart: 349 timeout = TPM_TIMEOUT_C; 350 break; 351 default: 352 timeout = TPM_TIMEOUT_B; 353 break; 354 } 355 return timeout; 356 } 357