> -----Original Message----- > From: Stefan Berger [mailto:stef...@linux.vnet.ibm.com] > Sent: Wednesday, April 01, 2015 3:40 AM > To: qemu-devel@nongnu.org; m...@redhat.com > Cc: Xu, Quan; Stefan Berger; Stefan Berger > Subject: [PATCH 2/3] tpm: Probe for connected TPM 1.2 or TPM 2 > > In the TPM passthrough backend driver, modify the probing code so that we can > check whether a TPM 1.2 or TPM 2 is being used and adapt the behavior of the > TPM TIS accordingly. > > Move the code that tested for a TPM 1.2 into tpm_utils.c and extend it with > test > for probing for TPM 2. Have the function return the version of TPM found. > > Signed-off-by: Stefan Berger <stef...@us.ibm.com> > --- > hw/tpm/Makefile.objs | 2 +- > hw/tpm/tpm_int.h | 6 +++ > hw/tpm/tpm_passthrough.c | 59 +++------------------- > hw/tpm/tpm_util.c | 126 > +++++++++++++++++++++++++++++++++++++++++++++++ > hw/tpm/tpm_util.h | 28 +++++++++++ > 5 files changed, 167 insertions(+), 54 deletions(-) create mode 100644 > hw/tpm/tpm_util.c create mode 100644 hw/tpm/tpm_util.h > > diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs index > 99f5983..64cecc3 100644 > --- a/hw/tpm/Makefile.objs > +++ b/hw/tpm/Makefile.objs > @@ -1,2 +1,2 @@ > common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o > -common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o > +common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o > tpm_util.o > diff --git a/hw/tpm/tpm_int.h b/hw/tpm/tpm_int.h index 24e12ce..edab824 > 100644 > --- a/hw/tpm/tpm_int.h > +++ b/hw/tpm/tpm_int.h > @@ -66,4 +66,10 @@ struct tpm_resp_hdr { #define > TPM_ORD_ContinueSelfTest 0x53 > #define TPM_ORD_GetTicks 0xf1 > > + > +/* TPM2 defines */ > +#define TPM_ST_NO_SESSIONS 0x8001 > + > +#define TPM_CC_ReadClock 0x00000181 > +
Could you define TPM2 macro definitions beginning with 'TPM2_*'? > #endif /* TPM_TPM_INT_H */ > diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c index > dd769a7..2e65703 100644 > --- a/hw/tpm/tpm_passthrough.c > +++ b/hw/tpm/tpm_passthrough.c > @@ -33,6 +33,7 @@ > #include "hw/i386/pc.h" > #include "sysemu/tpm_backend_int.h" > #include "tpm_tis.h" > +#include "tpm_util.h" > > #define DEBUG_TPM 0 > > @@ -69,6 +70,8 @@ struct TPMPassthruState { > bool tpm_op_canceled; > int cancel_fd; > bool had_startup_error; > + > + enum TPMVersion tpm_version; > }; > > typedef struct TPMPassthruState TPMPassthruState; @@ -333,59 +336,9 @@ > static const char *tpm_passthrough_create_desc(void) > > static enum TPMVersion tpm_passthrough_get_tpm_version(TPMBackend *tb) > { > - return TPMVersion1_2; > -} > - > -/* > - * A basic test of a TPM device. We expect a well formatted response header > - * (error response is fine) within one second. > - */ > -static int tpm_passthrough_test_tpmdev(int fd) -{ > - struct tpm_req_hdr req = { > - .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND), > - .len = cpu_to_be32(sizeof(req)), > - .ordinal = cpu_to_be32(TPM_ORD_GetTicks), > - }; > - struct tpm_resp_hdr *resp; > - fd_set readfds; > - int n; > - struct timeval tv = { > - .tv_sec = 1, > - .tv_usec = 0, > - }; > - unsigned char buf[1024]; > - > - n = write(fd, &req, sizeof(req)); > - if (n < 0) { > - return errno; > - } > - if (n != sizeof(req)) { > - return EFAULT; > - } > - > - FD_ZERO(&readfds); > - FD_SET(fd, &readfds); > - > - /* wait for a second */ > - n = select(fd + 1, &readfds, NULL, NULL, &tv); > - if (n != 1) { > - return errno; > - } > - > - n = read(fd, &buf, sizeof(buf)); > - if (n < sizeof(struct tpm_resp_hdr)) { > - return EFAULT; > - } > - > - resp = (struct tpm_resp_hdr *)buf; > - /* check the header */ > - if (be16_to_cpu(resp->tag) != TPM_TAG_RSP_COMMAND || > - be32_to_cpu(resp->len) != n) { > - return EBADMSG; > - } > + TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); > > - return 0; > + return tpm_pt->tpm_version; > } > > /* > @@ -455,7 +408,7 @@ static int > tpm_passthrough_handle_device_opts(QemuOpts *opts, TPMBackend *tb) > goto err_free_parameters; > } > > - if (tpm_passthrough_test_tpmdev(tpm_pt->tpm_fd)) { > + if (tpm_util_test_tpmdev(tpm_pt->tpm_fd, &tpm_pt->tpm_version)) { > error_report("'%s' is not a TPM device.", > tpm_pt->tpm_dev); > goto err_close_tpmdev; > diff --git a/hw/tpm/tpm_util.c b/hw/tpm/tpm_util.c new file mode 100644 index > 0000000..f9fb9c1 > --- /dev/null > +++ b/hw/tpm/tpm_util.c > @@ -0,0 +1,126 @@ > +/* > + * TPM utility functions > + * > + * Copyright (c) 2010 - 2015 IBM Corporation > + * Authors: > + * Stefan Berger <stef...@us.ibm.com> > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, see > +<http://www.gnu.org/licenses/> */ > + > +#include "tpm_util.h" > +#include "tpm_int.h" > + > +/* > + * A basic test of a TPM device. We expect a well formatted response > +header > + * (error response is fine) within one second. > + */ > +static int tpm_util_test(int fd, > + unsigned char *request, > + size_t requestlen, > + uint16_t *returnTag) { > + struct tpm_resp_hdr *resp; > + fd_set readfds; > + int n; > + struct timeval tv = { > + .tv_sec = 1, > + .tv_usec = 0, > + }; > + unsigned char buf[1024]; > + > + n = write(fd, request, requestlen); > + if (n < 0) { > + return errno; > + } > + if (n != requestlen) { > + return EFAULT; > + } > + > + FD_ZERO(&readfds); > + FD_SET(fd, &readfds); > + > + /* wait for a second */ > + n = select(fd + 1, &readfds, NULL, NULL, &tv); > + if (n != 1) { > + return errno; > + } > + > + n = read(fd, &buf, sizeof(buf)); > + if (n < sizeof(struct tpm_resp_hdr)) { > + return EFAULT; > + } > + > + resp = (struct tpm_resp_hdr *)buf; > + /* check the header */ > + if (be32_to_cpu(resp->len) != n) { > + return EBADMSG; > + } > + > + *returnTag = be16_to_cpu(resp->tag); > + > + return 0; > +} > + > +/* > + * Probe for the TPM device in the back > + * Returns 0 on success with the version of the probed TPM set, 1 on failure. > + */ > +int tpm_util_test_tpmdev(int tpm_fd, enum TPMVersion *tpm_version) { > + /* > + * Sending a TPM1.2 command to a TPM2 should return a TPM1.2 > + * header (tag = 0xc4) and error code (TPM_BADTAG = 0x1e) > + * > + * Sending a TPM2 command to a TPM 2 will give a TPM 2 tag in the > + * header. > + * Sending a TPM2 command to a TPM 1.2 will give a TPM 1.2 tag > + * in the header and an error code. > + */ > + const struct tpm_req_hdr test_req = { > + .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND), > + .len = cpu_to_be32(sizeof(test_req)), > + .ordinal = cpu_to_be32(TPM_ORD_GetTicks), > + }; > + > + const struct tpm_req_hdr test_req_tpm2 = { > + .tag = cpu_to_be16(TPM_ST_NO_SESSIONS), > + .len = cpu_to_be32(sizeof(test_req_tpm2)), > + .ordinal = cpu_to_be32(TPM_CC_ReadClock), > + }; > + uint16_t returnTag; > + int ret; > + > + /* Send TPM 2 command */ > + ret = tpm_util_test(tpm_fd, (unsigned char *)&test_req_tpm2, > + sizeof(test_req_tpm2), &returnTag); > + /* TPM 2 would respond with a tag of TPM_ST_NO_SESSIONS */ > + if (!ret && returnTag == TPM_ST_NO_SESSIONS) { > + *tpm_version = TPMVersion2_0; > + return 0; > + } > + > + /* Send TPM 1.2 command */ > + ret = tpm_util_test(tpm_fd, (unsigned char *)&test_req, > + sizeof(test_req), &returnTag); > + if (!ret && returnTag == TPM_TAG_RSP_COMMAND) { > + *tpm_version = TPMVersion1_2; > + /* this is a TPM 1.2 */ > + return 0; > + } > + > + *tpm_version = TPMVersion_Unspec; > + > + return 1; > +} In my opinion, I prefer to point out tpm_version in QEMU command line options, then tpm_util_test_tpmdev() tries to verify it. Intel Quan Xu > diff --git a/hw/tpm/tpm_util.h b/hw/tpm/tpm_util.h new file mode 100644 index > 0000000..3ce25c8 > --- /dev/null > +++ b/hw/tpm/tpm_util.h > @@ -0,0 +1,28 @@ > +/* > + * TPM utility functions > + * > + * Copyright (c) 2010 - 2015 IBM Corporation > + * Authors: > + * Stefan Berger <stef...@us.ibm.com> > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, see > +<http://www.gnu.org/licenses/> */ #ifndef TPM_TPM_UTILS_H #define > +TPM_TPM_UTILS_H > + > +#include "sysemu/tpm_backend.h" > + > +int tpm_util_test_tpmdev(int tpm_fd, enum TPMVersion *tpm_version); > + > +#endif /* TPM_TPM_UTILS_H */ > -- > 1.9.3