2 * Copyright (c) 2018 Stormshield.
3 * Copyright (c) 2018 Semihalf.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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.
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
33 MALLOC_DECLARE(M_TPM20);
34 MALLOC_DEFINE(M_TPM20, "tpm_buffer", "buffer for tpm 2.0 driver");
36 static void tpm20_discard_buffer(void *arg);
37 static int tpm20_save_state(device_t dev, bool suspend);
39 static d_open_t tpm20_open;
40 static d_close_t tpm20_close;
41 static d_read_t tpm20_read;
42 static d_write_t tpm20_write;
43 static d_ioctl_t tpm20_ioctl;
45 static struct cdevsw tpm20_cdevsw = {
46 .d_version = D_VERSION,
48 .d_close = tpm20_close,
50 .d_write = tpm20_write,
51 .d_ioctl = tpm20_ioctl,
56 tpm20_read(struct cdev *dev, struct uio *uio, int flags)
59 size_t bytes_to_transfer;
62 sc = (struct tpm_sc *)dev->si_drv1;
64 callout_stop(&sc->discard_buffer_callout);
65 sx_xlock(&sc->dev_lock);
67 bytes_to_transfer = MIN(sc->pending_data_length, uio->uio_resid);
68 if (bytes_to_transfer > 0) {
69 result = uiomove((caddr_t) sc->buf, bytes_to_transfer, uio);
70 memset(sc->buf, 0, TPM_BUFSIZE);
71 sc->pending_data_length = 0;
72 cv_signal(&sc->buf_cv);
77 sx_xunlock(&sc->dev_lock);
83 tpm20_write(struct cdev *dev, struct uio *uio, int flags)
89 sc = (struct tpm_sc *)dev->si_drv1;
91 byte_count = uio->uio_resid;
92 if (byte_count < TPM_HEADER_SIZE) {
93 device_printf(sc->dev,
94 "Requested transfer is too small\n");
98 if (byte_count > TPM_BUFSIZE) {
99 device_printf(sc->dev,
100 "Requested transfer is too large\n");
104 sx_xlock(&sc->dev_lock);
106 while (sc->pending_data_length != 0)
107 cv_wait(&sc->buf_cv, &sc->dev_lock);
109 result = uiomove(sc->buf, byte_count, uio);
111 sx_xunlock(&sc->dev_lock);
115 result = sc->transmit(sc, byte_count);
118 callout_reset(&sc->discard_buffer_callout,
119 TPM_READ_TIMEOUT / tick, tpm20_discard_buffer, sc);
121 sx_xunlock(&sc->dev_lock);
125 static void tpm20_discard_buffer(void *arg)
129 sc = (struct tpm_sc *)arg;
130 if (callout_pending(&sc->discard_buffer_callout))
133 sx_xlock(&sc->dev_lock);
135 memset(sc->buf, 0, TPM_BUFSIZE);
136 sc->pending_data_length = 0;
138 cv_signal(&sc->buf_cv);
139 sx_xunlock(&sc->dev_lock);
141 device_printf(sc->dev,
142 "User failed to read buffer in time\n");
146 tpm20_open(struct cdev *dev, int flag, int mode, struct thread *td)
153 tpm20_close(struct cdev *dev, int flag, int mode, struct thread *td)
161 tpm20_ioctl(struct cdev *dev, u_long cmd, caddr_t data,
162 int flags, struct thread *td)
169 tpm20_init(struct tpm_sc *sc)
171 struct make_dev_args args;
174 sc->buf = malloc(TPM_BUFSIZE, M_TPM20, M_WAITOK);
175 sx_init(&sc->dev_lock, "TPM driver lock");
176 cv_init(&sc->buf_cv, "TPM buffer cv");
177 callout_init(&sc->discard_buffer_callout, 1);
178 sc->pending_data_length = 0;
180 make_dev_args_init(&args);
181 args.mda_devsw = &tpm20_cdevsw;
182 args.mda_uid = UID_ROOT;
183 args.mda_gid = GID_WHEEL;
184 args.mda_mode = TPM_CDEV_PERM_FLAG;
185 args.mda_si_drv1 = sc;
186 result = make_dev_s(&args, &sc->sc_cdev, TPM_CDEV_NAME);
195 tpm20_release(struct tpm_sc *sc)
199 free(sc->buf, M_TPM20);
201 sx_destroy(&sc->dev_lock);
202 cv_destroy(&sc->buf_cv);
203 if (sc->sc_cdev != NULL)
204 destroy_dev(sc->sc_cdev);
209 tpm20_suspend(device_t dev)
211 return (tpm20_save_state(dev, true));
215 tpm20_shutdown(device_t dev)
217 return (tpm20_save_state(dev, false));
221 tpm20_save_state(device_t dev, bool suspend)
224 uint8_t save_cmd[] = {
225 0x80, 0x01, /* TPM_ST_NO_SESSIONS tag*/
226 0x00, 0x00, 0x00, 0x0C, /* cmd length */
227 0x00, 0x00, 0x01, 0x45, 0x00, 0x00 /* cmd TPM_CC_Shutdown */
230 sc = device_get_softc(dev);
233 * Inform the TPM whether we are going to suspend or reboot/shutdown.
236 save_cmd[11] = 1; /* TPM_SU_STATE */
238 if (sc == NULL || sc->buf == NULL)
241 sx_xlock(&sc->dev_lock);
243 memcpy(sc->buf, save_cmd, sizeof(save_cmd));
244 sc->transmit(sc, sizeof(save_cmd));
246 sx_xunlock(&sc->dev_lock);
252 tpm20_get_timeout(uint32_t command)
257 case TPM_CC_CreatePrimary:
259 case TPM_CC_CreateLoaded:
260 timeout = TPM_TIMEOUT_LONG;
262 case TPM_CC_SequenceComplete:
264 case TPM_CC_SequenceUpdate:
265 case TPM_CC_GetCapability:
266 case TPM_CC_PCR_Extend:
267 case TPM_CC_EventSequenceComplete:
268 case TPM_CC_HashSequenceStart:
269 timeout = TPM_TIMEOUT_C;
272 timeout = TPM_TIMEOUT_B;