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/random.h> 29 #include <dev/random/randomdev.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 #if defined TPM_HARVEST || defined RANDOM_ENABLE_TPM 45 static void tpm20_harvest(void *arg, int unused); 46 #endif 47 static int tpm20_restart(device_t dev, bool clear); 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 struct tpm_priv *priv; 71 size_t bytes_to_transfer; 72 size_t offset; 73 int result = 0; 74 75 sc = (struct tpm_sc *)dev->si_drv1; 76 devfs_get_cdevpriv((void **)&priv); 77 78 sx_xlock(&sc->dev_lock); 79 offset = priv->offset; 80 bytes_to_transfer = MIN(priv->len, uio->uio_resid); 81 if (bytes_to_transfer > 0) { 82 result = uiomove((caddr_t) priv->buf + offset, bytes_to_transfer, uio); 83 priv->offset += bytes_to_transfer; 84 priv->len -= bytes_to_transfer; 85 } else { 86 result = 0; 87 } 88 89 sx_xunlock(&sc->dev_lock); 90 91 return (result); 92 } 93 94 int 95 tpm20_write(struct cdev *dev, struct uio *uio, int flags) 96 { 97 struct tpm_sc *sc; 98 struct tpm_priv *priv; 99 size_t byte_count; 100 int result = 0; 101 102 sc = (struct tpm_sc *)dev->si_drv1; 103 devfs_get_cdevpriv((void **)&priv); 104 105 byte_count = uio->uio_resid; 106 if (byte_count < TPM_HEADER_SIZE) { 107 device_printf(sc->dev, 108 "Requested transfer is too small\n"); 109 return (EINVAL); 110 } 111 112 if (byte_count > TPM_BUFSIZE) { 113 device_printf(sc->dev, 114 "Requested transfer is too large\n"); 115 return (E2BIG); 116 } 117 118 sx_xlock(&sc->dev_lock); 119 120 result = uiomove(priv->buf, byte_count, uio); 121 if (result != 0) { 122 sx_xunlock(&sc->dev_lock); 123 return (result); 124 } 125 126 result = TPM_TRANSMIT(sc->dev, priv, byte_count); 127 128 sx_xunlock(&sc->dev_lock); 129 return (result); 130 } 131 132 static struct tpm_priv * 133 tpm20_priv_alloc(void) 134 { 135 struct tpm_priv *priv; 136 137 priv = malloc(sizeof (*priv), M_TPM20, M_WAITOK | M_ZERO); 138 return (priv); 139 } 140 141 static void 142 tpm20_priv_dtor(void *data) 143 { 144 struct tpm_priv *priv = data; 145 146 free(priv->buf, M_TPM20); 147 } 148 149 int 150 tpm20_open(struct cdev *dev, int flag, int mode, struct thread *td) 151 { 152 struct tpm_priv *priv; 153 154 priv = tpm20_priv_alloc(); 155 devfs_set_cdevpriv(priv, tpm20_priv_dtor); 156 157 return (0); 158 } 159 160 int 161 tpm20_close(struct cdev *dev, int flag, int mode, struct thread *td) 162 { 163 164 return (0); 165 } 166 167 int 168 tpm20_ioctl(struct cdev *dev, u_long cmd, caddr_t data, 169 int flags, struct thread *td) 170 { 171 172 return (ENOTTY); 173 } 174 175 #if defined TPM_HARVEST || defined RANDOM_ENABLE_TPM 176 static const struct random_source random_tpm = { 177 .rs_ident = "TPM", 178 .rs_source = RANDOM_PURE_TPM, 179 }; 180 #endif 181 182 int 183 tpm20_init(struct tpm_sc *sc) 184 { 185 struct make_dev_args args; 186 int result; 187 188 sc->internal_priv = tpm20_priv_alloc(); 189 190 make_dev_args_init(&args); 191 args.mda_devsw = &tpm20_cdevsw; 192 args.mda_uid = UID_ROOT; 193 args.mda_gid = GID_WHEEL; 194 args.mda_mode = TPM_CDEV_PERM_FLAG; 195 args.mda_si_drv1 = sc; 196 result = make_dev_s(&args, &sc->sc_cdev, TPM_CDEV_NAME); 197 if (result != 0) 198 tpm20_release(sc); 199 200 #if defined TPM_HARVEST || defined RANDOM_ENABLE_TPM 201 random_source_register(&random_tpm); 202 TIMEOUT_TASK_INIT(taskqueue_thread, &sc->harvest_task, 0, 203 tpm20_harvest, sc); 204 taskqueue_enqueue_timeout(taskqueue_thread, &sc->harvest_task, 0); 205 #endif 206 207 return (result); 208 209 } 210 211 void 212 tpm20_release(struct tpm_sc *sc) 213 { 214 215 #if defined TPM_HARVEST || defined RANDOM_ENABLE_TPM 216 if (device_is_attached(sc->dev)) 217 taskqueue_drain_timeout(taskqueue_thread, &sc->harvest_task); 218 random_source_deregister(&random_tpm); 219 #endif 220 221 tpm20_priv_dtor(sc->internal_priv); 222 sx_destroy(&sc->dev_lock); 223 if (sc->sc_cdev != NULL) 224 destroy_dev(sc->sc_cdev); 225 } 226 227 int 228 tpm20_resume(device_t dev) 229 { 230 231 tpm20_restart(dev, false); 232 233 #if defined TPM_HARVEST || defined RANDOM_ENABLE_TPM 234 struct tpm_sc *sc; 235 236 sc = device_get_softc(dev); 237 taskqueue_enqueue_timeout(taskqueue_thread, &sc->harvest_task, 238 hz * TPM_HARVEST_INTERVAL); 239 #endif 240 return (0); 241 } 242 243 int 244 tpm20_suspend(device_t dev) 245 { 246 #if defined TPM_HARVEST || defined RANDOM_ENABLE_TPM 247 struct tpm_sc *sc; 248 249 sc = device_get_softc(dev); 250 taskqueue_drain_timeout(taskqueue_thread, &sc->harvest_task); 251 #endif 252 return (tpm20_save_state(dev, true)); 253 } 254 255 int 256 tpm20_shutdown(device_t dev) 257 { 258 return (tpm20_save_state(dev, false)); 259 } 260 261 #if defined TPM_HARVEST || defined RANDOM_ENABLE_TPM 262 /* 263 * Get TPM_HARVEST_SIZE random bytes and add them 264 * into system entropy pool. 265 */ 266 static void 267 tpm20_harvest(void *arg, int unused) 268 { 269 struct tpm_sc *sc; 270 struct tpm_priv *priv; 271 unsigned char entropy[TPM_HARVEST_SIZE]; 272 uint16_t entropy_size; 273 int result; 274 uint8_t cmd[] = { 275 0x80, 0x01, /* TPM_ST_NO_SESSIONS tag*/ 276 0x00, 0x00, 0x00, 0x0c, /* cmd length */ 277 0x00, 0x00, 0x01, 0x7b, /* cmd TPM_CC_GetRandom */ 278 0x00, TPM_HARVEST_SIZE /* number of bytes requested */ 279 }; 280 281 sc = arg; 282 sx_xlock(&sc->dev_lock); 283 284 priv = sc->internal_priv; 285 memcpy(priv->buf, cmd, sizeof(cmd)); 286 287 result = TPM_TRANSMIT(sc->dev, priv, sizeof(cmd)); 288 if (result != 0) { 289 sx_xunlock(&sc->dev_lock); 290 return; 291 } 292 293 /* The number of random bytes we got is placed right after the header */ 294 entropy_size = (uint16_t) priv->buf[TPM_HEADER_SIZE + 1]; 295 if (entropy_size > 0) { 296 entropy_size = MIN(entropy_size, TPM_HARVEST_SIZE); 297 memcpy(entropy, 298 priv->buf + TPM_HEADER_SIZE + sizeof(uint16_t), 299 entropy_size); 300 } 301 302 sx_xunlock(&sc->dev_lock); 303 if (entropy_size > 0) 304 random_harvest_queue(entropy, entropy_size, RANDOM_PURE_TPM); 305 306 taskqueue_enqueue_timeout(taskqueue_thread, &sc->harvest_task, 307 hz * TPM_HARVEST_INTERVAL); 308 } 309 #endif /* TPM_HARVEST */ 310 311 static int 312 tpm20_restart(device_t dev, bool clear) 313 { 314 struct tpm_sc *sc; 315 struct tpm_priv *priv; 316 uint8_t startup_cmd[] = { 317 0x80, 0x01, /* TPM_ST_NO_SESSIONS tag*/ 318 0x00, 0x00, 0x00, 0x0C, /* cmd length */ 319 0x00, 0x00, 0x01, 0x44, /* cmd TPM_CC_Startup */ 320 0x00, 0x01 /* TPM_SU_STATE */ 321 }; 322 323 sc = device_get_softc(dev); 324 325 /* 326 * Inform the TPM whether we are resetting or resuming. 327 */ 328 if (clear) 329 startup_cmd[11] = 0; /* TPM_SU_CLEAR */ 330 331 if (sc == NULL) 332 return (0); 333 334 sx_xlock(&sc->dev_lock); 335 336 priv = sc->internal_priv; 337 memcpy(priv->buf, startup_cmd, sizeof(startup_cmd)); 338 339 /* XXX Ignoring both TPM_TRANSMIT return and tpm's response */ 340 TPM_TRANSMIT(sc->dev, priv, sizeof(startup_cmd)); 341 342 sx_xunlock(&sc->dev_lock); 343 344 return (0); 345 } 346 347 static int 348 tpm20_save_state(device_t dev, bool suspend) 349 { 350 struct tpm_sc *sc; 351 struct tpm_priv *priv; 352 uint8_t save_cmd[] = { 353 0x80, 0x01, /* TPM_ST_NO_SESSIONS tag*/ 354 0x00, 0x00, 0x00, 0x0C, /* cmd length */ 355 0x00, 0x00, 0x01, 0x45, /* cmd TPM_CC_Shutdown */ 356 0x00, 0x00 /* TPM_SU_STATE */ 357 }; 358 359 sc = device_get_softc(dev); 360 361 /* 362 * Inform the TPM whether we are going to suspend or reboot/shutdown. 363 */ 364 if (suspend) 365 save_cmd[11] = 1; /* TPM_SU_STATE */ 366 367 if (sc == NULL) 368 return (0); 369 370 sx_xlock(&sc->dev_lock); 371 372 priv = sc->internal_priv; 373 memcpy(priv->buf, save_cmd, sizeof(save_cmd)); 374 375 /* XXX Ignoring both TPM_TRANSMIT return and tpm's response */ 376 TPM_TRANSMIT(sc->dev, priv, sizeof(save_cmd)); 377 378 sx_xunlock(&sc->dev_lock); 379 380 return (0); 381 } 382 383 int32_t 384 tpm20_get_timeout(uint32_t command) 385 { 386 int32_t timeout; 387 388 switch (command) { 389 case TPM_CC_CreatePrimary: 390 case TPM_CC_Create: 391 case TPM_CC_CreateLoaded: 392 timeout = TPM_TIMEOUT_LONG; 393 break; 394 case TPM_CC_SequenceComplete: 395 case TPM_CC_Startup: 396 case TPM_CC_SequenceUpdate: 397 case TPM_CC_GetCapability: 398 case TPM_CC_PCR_Extend: 399 case TPM_CC_EventSequenceComplete: 400 case TPM_CC_HashSequenceStart: 401 timeout = TPM_TIMEOUT_C; 402 break; 403 default: 404 timeout = TPM_TIMEOUT_B; 405 break; 406 } 407 return timeout; 408 } 409