1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2023 Beckhoff Automation GmbH & Co. KG 5 * Author: Corvin Köhne <corvink@FreeBSD.org> 6 */ 7 8 #include <sys/types.h> 9 10 #include <err.h> 11 #include <errno.h> 12 #include <fcntl.h> 13 #ifdef __FreeBSD__ 14 #include <malloc_np.h> 15 #else 16 #include <sys/vmm.h> 17 #endif 18 #include <stdlib.h> 19 #include <unistd.h> 20 21 #include "config.h" 22 #include "tpm_device.h" 23 #include "tpm_emul.h" 24 25 struct tpm_passthru { 26 int fd; 27 }; 28 29 struct tpm_resp_hdr { 30 uint16_t tag; 31 uint32_t len; 32 uint32_t errcode; 33 } __packed; 34 35 static int 36 tpm_passthru_init(void **sc, nvlist_t *nvl) 37 { 38 #ifndef __FreeBSD__ 39 /* 40 * Until illumos has a TPM 2.0 driver, we can't finish plumbing the TPM 41 * pass-through. 42 */ 43 errx(4, "TPM pass-through devices are not yet supported on illumos"); 44 #else 45 struct tpm_passthru *tpm; 46 const char *path; 47 48 tpm = calloc(1, sizeof(struct tpm_passthru)); 49 if (tpm == NULL) { 50 warnx("%s: failed to allocate tpm passthru", __func__); 51 return (ENOMEM); 52 } 53 54 path = get_config_value_node(nvl, "path"); 55 tpm->fd = open(path, O_RDWR); 56 if (tpm->fd < 0) { 57 warnx("%s: unable to open tpm device \"%s\"", __func__, path); 58 return (ENOENT); 59 } 60 61 *sc = tpm; 62 #endif /* __FreeBSD__ */ 63 64 return (0); 65 } 66 67 static int 68 tpm_passthru_execute_cmd(void *sc, void *cmd, uint32_t cmd_size, void *rsp, 69 uint32_t rsp_size) 70 { 71 struct tpm_passthru *tpm; 72 ssize_t len; 73 74 if (rsp_size < (ssize_t)sizeof(struct tpm_resp_hdr)) { 75 warn("%s: rsp_size of %u is too small", __func__, rsp_size); 76 return (EINVAL); 77 } 78 79 tpm = sc; 80 81 len = write(tpm->fd, cmd, cmd_size); 82 if (len != cmd_size) { 83 warn("%s: cmd write failed (bytes written: %zd / %d)", __func__, 84 len, cmd_size); 85 return (EFAULT); 86 } 87 88 len = read(tpm->fd, rsp, rsp_size); 89 if (len < (ssize_t)sizeof(struct tpm_resp_hdr)) { 90 warn("%s: rsp read failed (bytes read: %zd / %d)", __func__, 91 len, rsp_size); 92 return (EFAULT); 93 } 94 95 return (0); 96 } 97 98 static void 99 tpm_passthru_deinit(void *sc) 100 { 101 struct tpm_passthru *tpm; 102 103 tpm = sc; 104 if (tpm == NULL) 105 return; 106 107 if (tpm->fd >= 0) 108 close(tpm->fd); 109 110 free(tpm); 111 } 112 113 static const struct tpm_emul tpm_emul_passthru = { 114 .name = "passthru", 115 .init = tpm_passthru_init, 116 .deinit = tpm_passthru_deinit, 117 .execute_cmd = tpm_passthru_execute_cmd, 118 }; 119 TPM_EMUL_SET(tpm_emul_passthru); 120