From nobody Mon May 6 21:45:25 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1517251245860422.8640546144302; Mon, 29 Jan 2018 10:40:45 -0800 (PST) Received: from localhost ([::1]:57417 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1egEMB-0000zH-Pl for importer@patchew.org; Mon, 29 Jan 2018 13:40:39 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:36579) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1egEFI-00040U-98 for qemu-devel@nongnu.org; Mon, 29 Jan 2018 13:33:37 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1egEFG-0004fI-IJ for qemu-devel@nongnu.org; Mon, 29 Jan 2018 13:33:32 -0500 Received: from mx1.redhat.com ([209.132.183.28]:51164) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1egEFG-0004ep-9u for qemu-devel@nongnu.org; Mon, 29 Jan 2018 13:33:30 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 8CB2DAB41D; Mon, 29 Jan 2018 18:33:29 +0000 (UTC) Received: from localhost (ovpn-112-47.ams2.redhat.com [10.36.112.47]) by smtp.corp.redhat.com (Postfix) with ESMTP id ECBAE85590; Mon, 29 Jan 2018 18:33:21 +0000 (UTC) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Mon, 29 Jan 2018 19:33:03 +0100 Message-Id: <20180129183307.19689-2-marcandre.lureau@redhat.com> In-Reply-To: <20180129183307.19689-1-marcandre.lureau@redhat.com> References: <20180129183307.19689-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.28]); Mon, 29 Jan 2018 18:33:29 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v4 1/5] tpm: fix alignment issues X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , stefanb@linux.vnet.ibm.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" The new tpm-crb-test fails on sparc host: TEST: tests/tpm-crb-test... (pid=3D230409) /i386/tpm-crb/test: Broken pipe FAIL GTester: last random seed: R02S29cea50247fe1efa59ee885a26d51a85 (pid=3D230423) FAIL: tests/tpm-crb-test and generates a new clang sanitizer runtime warning: /home/petmay01/linaro/qemu-for-merges/hw/tpm/tpm_util.h:36:24: runtime error: load of misaligned address 0x7fdc24c00002 for type 'const uint32_t' (aka 'const unsigned int'), which requires 4 byte alignment 0x7fdc24c00002: note: pointer points here The sparc architecture does not allow misaligned loads and will segfault if you try them. For example, this function: static inline uint32_t tpm_cmd_get_size(const void *b) { return be32_to_cpu(*(const uint32_t *)(b + 2)); } Should read, return ldl_be_p(b + 2); As a general rule you can't take an arbitrary pointer into a byte buffer and try to interpret it as a structure or a pointer to a larger-than-bytesize-data simply by casting the pointer. Use this clean up as an opportunity to remove unnecessary temporary buffers and casts. Reported-by: Peter Maydell Signed-off-by: Marc-Andr=C3=A9 Lureau Reviewed-by: Stefan Berger --- hw/tpm/tpm_util.h | 17 ++++++++++- hw/tpm/tpm_emulator.c | 14 ++++----- hw/tpm/tpm_passthrough.c | 6 ++-- hw/tpm/tpm_util.c | 75 ++++++++++++++++++++++----------------------= ---- 4 files changed, 58 insertions(+), 54 deletions(-) diff --git a/hw/tpm/tpm_util.h b/hw/tpm/tpm_util.h index 19b28474ae..f003d15615 100644 --- a/hw/tpm/tpm_util.h +++ b/hw/tpm/tpm_util.h @@ -31,9 +31,24 @@ bool tpm_util_is_selftest(const uint8_t *in, uint32_t in= _len); =20 int tpm_util_test_tpmdev(int tpm_fd, TPMVersion *tpm_version); =20 +static inline uint16_t tpm_cmd_get_tag(const void *b) +{ + return lduw_be_p(b); +} + static inline uint32_t tpm_cmd_get_size(const void *b) { - return be32_to_cpu(*(const uint32_t *)(b + 2)); + return ldl_be_p(b + 2); +} + +static inline uint32_t tpm_cmd_get_ordinal(const void *b) +{ + return ldl_be_p(b + 6); +} + +static inline uint32_t tpm_cmd_get_errcode(const void *b) +{ + return ldl_be_p(b + 6); } =20 int tpm_util_get_buffer_size(int tpm_fd, TPMVersion tpm_version, diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c index 35c78de5a9..a34a18ac7a 100644 --- a/hw/tpm/tpm_emulator.c +++ b/hw/tpm/tpm_emulator.c @@ -120,7 +120,6 @@ static int tpm_emulator_unix_tx_bufs(TPMEmulator *tpm_e= mu, { ssize_t ret; bool is_selftest =3D false; - const struct tpm_resp_hdr *hdr =3D NULL; =20 if (selftest_done) { *selftest_done =3D false; @@ -132,22 +131,21 @@ static int tpm_emulator_unix_tx_bufs(TPMEmulator *tpm= _emu, return -1; } =20 - ret =3D qio_channel_read_all(tpm_emu->data_ioc, (char *)out, sizeof(*h= dr), - err); + ret =3D qio_channel_read_all(tpm_emu->data_ioc, (char *)out, + sizeof(struct tpm_resp_hdr), err); if (ret !=3D 0) { return -1; } =20 - hdr =3D (struct tpm_resp_hdr *)out; - out +=3D sizeof(*hdr); - ret =3D qio_channel_read_all(tpm_emu->data_ioc, (char *)out, - be32_to_cpu(hdr->len) - sizeof(*hdr) , err); + ret =3D qio_channel_read_all(tpm_emu->data_ioc, + (char *)out + sizeof(struct tpm_resp_hdr), + tpm_cmd_get_size(out) - sizeof(struct tpm_resp_hdr), err); if (ret !=3D 0) { return -1; } =20 if (is_selftest) { - *selftest_done =3D (be32_to_cpu(hdr->errcode) =3D=3D 0); + *selftest_done =3D tpm_cmd_get_errcode(out) =3D=3D 0; } =20 return 0; diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c index 29142f38bb..537e11a3f9 100644 --- a/hw/tpm/tpm_passthrough.c +++ b/hw/tpm/tpm_passthrough.c @@ -87,7 +87,6 @@ static int tpm_passthrough_unix_tx_bufs(TPMPassthruState = *tpm_pt, { ssize_t ret; bool is_selftest; - const struct tpm_resp_hdr *hdr; =20 /* FIXME: protect shared variables or use other sync mechanism */ tpm_pt->tpm_op_canceled =3D false; @@ -116,15 +115,14 @@ static int tpm_passthrough_unix_tx_bufs(TPMPassthruSt= ate *tpm_pt, strerror(errno), errno); } } else if (ret < sizeof(struct tpm_resp_hdr) || - be32_to_cpu(((struct tpm_resp_hdr *)out)->len) !=3D ret) { + tpm_cmd_get_size(out) !=3D ret) { ret =3D -1; error_report("tpm_passthrough: received invalid response " "packet from TPM"); } =20 if (is_selftest && (ret >=3D sizeof(struct tpm_resp_hdr))) { - hdr =3D (struct tpm_resp_hdr *)out; - *selftest_done =3D (be32_to_cpu(hdr->errcode) =3D=3D 0); + *selftest_done =3D tpm_cmd_get_errcode(out) =3D=3D 0; } =20 err_exit: diff --git a/hw/tpm/tpm_util.c b/hw/tpm/tpm_util.c index 747075e244..8abde59915 100644 --- a/hw/tpm/tpm_util.c +++ b/hw/tpm/tpm_util.c @@ -106,20 +106,16 @@ const PropertyInfo qdev_prop_tpm =3D { void tpm_util_write_fatal_error_response(uint8_t *out, uint32_t out_len) { if (out_len >=3D sizeof(struct tpm_resp_hdr)) { - struct tpm_resp_hdr *resp =3D (struct tpm_resp_hdr *)out; - - resp->tag =3D cpu_to_be16(TPM_TAG_RSP_COMMAND); - resp->len =3D cpu_to_be32(sizeof(struct tpm_resp_hdr)); - resp->errcode =3D cpu_to_be32(TPM_FAIL); + stw_be_p(out, TPM_TAG_RSP_COMMAND); + stl_be_p(out + 2, sizeof(struct tpm_resp_hdr)); + stl_be_p(out + 6, TPM_FAIL); } } =20 bool tpm_util_is_selftest(const uint8_t *in, uint32_t in_len) { - struct tpm_req_hdr *hdr =3D (struct tpm_req_hdr *)in; - - if (in_len >=3D sizeof(*hdr)) { - return (be32_to_cpu(hdr->ordinal) =3D=3D TPM_ORD_ContinueSelfTest); + if (in_len >=3D sizeof(struct tpm_req_hdr)) { + return tpm_cmd_get_ordinal(in) =3D=3D TPM_ORD_ContinueSelfTest; } =20 return false; @@ -129,12 +125,11 @@ bool tpm_util_is_selftest(const uint8_t *in, uint32_t= in_len) * Send request to a TPM device. We expect a response within one second. */ static int tpm_util_request(int fd, - unsigned char *request, + const void *request, size_t requestlen, - unsigned char *response, + void *response, size_t responselen) { - struct tpm_resp_hdr *resp; fd_set readfds; int n; struct timeval tv =3D { @@ -164,9 +159,8 @@ static int tpm_util_request(int fd, return -EFAULT; } =20 - resp =3D (struct tpm_resp_hdr *)response; /* check the header */ - if (be32_to_cpu(resp->len) !=3D n) { + if (tpm_cmd_get_size(response) !=3D n) { return -EMSGSIZE; } =20 @@ -178,12 +172,11 @@ static int tpm_util_request(int fd, * (error response is fine). */ static int tpm_util_test(int fd, - unsigned char *request, + const void *request, size_t requestlen, uint16_t *return_tag) { - struct tpm_resp_hdr *resp; - unsigned char buf[1024]; + char buf[1024]; ssize_t ret; =20 ret =3D tpm_util_request(fd, request, requestlen, @@ -192,8 +185,7 @@ static int tpm_util_test(int fd, return ret; } =20 - resp =3D (struct tpm_resp_hdr *)buf; - *return_tag =3D be16_to_cpu(resp->tag); + *return_tag =3D tpm_cmd_get_tag(buf); =20 return 0; } @@ -228,7 +220,7 @@ int tpm_util_test_tpmdev(int tpm_fd, TPMVersion *tpm_ve= rsion) int ret; =20 /* Send TPM 2 command */ - ret =3D tpm_util_test(tpm_fd, (unsigned char *)&test_req_tpm2, + ret =3D tpm_util_test(tpm_fd, &test_req_tpm2, sizeof(test_req_tpm2), &return_tag); /* TPM 2 would respond with a tag of TPM2_ST_NO_SESSIONS */ if (!ret && return_tag =3D=3D TPM2_ST_NO_SESSIONS) { @@ -237,7 +229,7 @@ int tpm_util_test_tpmdev(int tpm_fd, TPMVersion *tpm_ve= rsion) } =20 /* Send TPM 1.2 command */ - ret =3D tpm_util_test(tpm_fd, (unsigned char *)&test_req, + ret =3D tpm_util_test(tpm_fd, &test_req, sizeof(test_req), &return_tag); if (!ret && return_tag =3D=3D TPM_TAG_RSP_COMMAND) { *tpm_version =3D TPM_VERSION_1_2; @@ -253,7 +245,6 @@ int tpm_util_test_tpmdev(int tpm_fd, TPMVersion *tpm_ve= rsion) int tpm_util_get_buffer_size(int tpm_fd, TPMVersion tpm_version, size_t *buffersize) { - unsigned char buf[1024]; int ret; =20 switch (tpm_version) { @@ -277,26 +268,27 @@ int tpm_util_get_buffer_size(int tpm_fd, TPMVersion t= pm_version, struct tpm_resp_hdr hdr; uint32_t len; uint32_t buffersize; - } QEMU_PACKED *tpm_resp =3D (struct tpm_resp_get_buffer_size *)buf; + } QEMU_PACKED tpm_resp; =20 - ret =3D tpm_util_request(tpm_fd, (unsigned char *)&tpm_get_buffer_= size, - sizeof(tpm_get_buffer_size), buf, sizeof(bu= f)); + ret =3D tpm_util_request(tpm_fd, &tpm_get_buffer_size, + sizeof(tpm_get_buffer_size), + &tpm_resp, sizeof(tpm_resp)); if (ret < 0) { return ret; } =20 - if (be32_to_cpu(tpm_resp->hdr.len) !=3D sizeof(*tpm_resp) || - be32_to_cpu(tpm_resp->len) !=3D sizeof(uint32_t)) { + if (be32_to_cpu(tpm_resp.hdr.len) !=3D sizeof(tpm_resp) || + be32_to_cpu(tpm_resp.len) !=3D sizeof(uint32_t)) { DPRINTF("tpm_resp->hdr.len =3D %u, expected =3D %zu\n", - be32_to_cpu(tpm_resp->hdr.len), sizeof(*tpm_resp)); + be32_to_cpu(tpm_resp.hdr.len), sizeof(tpm_resp)); DPRINTF("tpm_resp->len =3D %u, expected =3D %zu\n", - be32_to_cpu(tpm_resp->len), sizeof(uint32_t)); + be32_to_cpu(tpm_resp.len), sizeof(uint32_t)); error_report("tpm_util: Got unexpected response to " "TPM_GetCapability; errcode: 0x%x", - be32_to_cpu(tpm_resp->hdr.errcode)); + be32_to_cpu(tpm_resp.hdr.errcode)); return -EFAULT; } - *buffersize =3D be32_to_cpu(tpm_resp->buffersize); + *buffersize =3D be32_to_cpu(tpm_resp.buffersize); break; } case TPM_VERSION_2_0: { @@ -324,27 +316,28 @@ int tpm_util_get_buffer_size(int tpm_fd, TPMVersion t= pm_version, uint32_t value1; uint32_t property2; uint32_t value2; - } QEMU_PACKED *tpm2_resp =3D (struct tpm2_resp_get_buffer_size *)b= uf; + } QEMU_PACKED tpm2_resp; =20 - ret =3D tpm_util_request(tpm_fd, (unsigned char *)&tpm2_get_buffer= _size, - sizeof(tpm2_get_buffer_size), buf, sizeof(b= uf)); + ret =3D tpm_util_request(tpm_fd, &tpm2_get_buffer_size, + sizeof(tpm2_get_buffer_size), + &tpm2_resp, sizeof(tpm2_resp)); if (ret < 0) { return ret; } =20 - if (be32_to_cpu(tpm2_resp->hdr.len) !=3D sizeof(*tpm2_resp) || - be32_to_cpu(tpm2_resp->count) !=3D 2) { + if (be32_to_cpu(tpm2_resp.hdr.len) !=3D sizeof(tpm2_resp) || + be32_to_cpu(tpm2_resp.count) !=3D 2) { DPRINTF("tpm2_resp->hdr.len =3D %u, expected =3D %zu\n", - be32_to_cpu(tpm2_resp->hdr.len), sizeof(*tpm2_resp)); + be32_to_cpu(tpm2_resp.hdr.len), sizeof(tpm2_resp)); DPRINTF("tpm2_resp->len =3D %u, expected =3D %u\n", - be32_to_cpu(tpm2_resp->count), 2); + be32_to_cpu(tpm2_resp.count), 2); error_report("tpm_util: Got unexpected response to " "TPM2_GetCapability; errcode: 0x%x", - be32_to_cpu(tpm2_resp->hdr.errcode)); + be32_to_cpu(tpm2_resp.hdr.errcode)); return -EFAULT; } - *buffersize =3D MAX(be32_to_cpu(tpm2_resp->value1), - be32_to_cpu(tpm2_resp->value2)); + *buffersize =3D MAX(be32_to_cpu(tpm2_resp.value1), + be32_to_cpu(tpm2_resp.value2)); break; } case TPM_VERSION_UNSPEC: --=20 2.16.0.rc1.1.gef27df75a1 From nobody Mon May 6 21:45:25 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1517251342874212.65648882028847; Mon, 29 Jan 2018 10:42:22 -0800 (PST) Received: from localhost ([::1]:57564 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1egENq-0002Mb-7E for importer@patchew.org; Mon, 29 Jan 2018 13:42:22 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:36646) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1egEFQ-00046y-3F for qemu-devel@nongnu.org; Mon, 29 Jan 2018 13:33:40 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1egEFP-0004kI-5B for qemu-devel@nongnu.org; Mon, 29 Jan 2018 13:33:40 -0500 Received: from mx1.redhat.com ([209.132.183.28]:58734) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1egEFO-0004jp-Tm for qemu-devel@nongnu.org; Mon, 29 Jan 2018 13:33:39 -0500 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 341914A6F3; Mon, 29 Jan 2018 18:33:38 +0000 (UTC) Received: from localhost (ovpn-112-47.ams2.redhat.com [10.36.112.47]) by smtp.corp.redhat.com (Postfix) with ESMTP id EB7A1608FA; Mon, 29 Jan 2018 18:33:30 +0000 (UTC) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Mon, 29 Jan 2018 19:33:04 +0100 Message-Id: <20180129183307.19689-3-marcandre.lureau@redhat.com> In-Reply-To: <20180129183307.19689-1-marcandre.lureau@redhat.com> References: <20180129183307.19689-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.38]); Mon, 29 Jan 2018 18:33:38 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v4 2/5] tpm: lookup cancel path under tpm device class X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , stefanb@linux.vnet.ibm.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Since Linux commit 313d21eeab9282e, tpm devices have their own device class "tpm" and the cancel path must be looked up under /sys/class/tpm/ instead of /sys/class/misc/. Signed-off-by: Marc-Andr=C3=A9 Lureau --- hw/tpm/tpm_passthrough.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c index 537e11a3f9..fc42fe0933 100644 --- a/hw/tpm/tpm_passthrough.c +++ b/hw/tpm/tpm_passthrough.c @@ -214,7 +214,8 @@ static size_t tpm_passthrough_get_buffer_size(TPMBacken= d *tb) * Unless path or file descriptor set has been provided by user, * determine the sysfs cancel file following kernel documentation * in Documentation/ABI/stable/sysfs-class-tpm. - * From /dev/tpm0 create /sys/class/misc/tpm0/device/cancel + * From /dev/tpm0 create /sys/class/tpm/tpm0/device/cancel + * before 4.0: /sys/class/misc/tpm0/device/cancel */ static int tpm_passthrough_open_sysfs_cancel(TPMPassthruState *tpm_pt) { @@ -225,26 +226,35 @@ static int tpm_passthrough_open_sysfs_cancel(TPMPasst= hruState *tpm_pt) if (tpm_pt->options->cancel_path) { fd =3D qemu_open(tpm_pt->options->cancel_path, O_WRONLY); if (fd < 0) { - error_report("Could not open TPM cancel path : %s", + error_report("tpm_passthrough: Could not open TPM cancel path:= %s", strerror(errno)); } return fd; } =20 dev =3D strrchr(tpm_pt->tpm_dev, '/'); - if (dev) { - dev++; - if (snprintf(path, sizeof(path), "/sys/class/misc/%s/device/cancel= ", - dev) < sizeof(path)) { - fd =3D qemu_open(path, O_WRONLY); - if (fd < 0) { - error_report("tpm_passthrough: Could not open TPM cancel " - "path %s : %s", path, strerror(errno)); + if (!dev) { + error_report("tpm_passthrough: Bad TPM device path %s", + tpm_pt->tpm_dev); + return -1; + } + + dev++; + if (snprintf(path, sizeof(path), "/sys/class/tpm/%s/device/cancel", + dev) < sizeof(path)) { + fd =3D qemu_open(path, O_WRONLY); + if (fd < 0) { + if (snprintf(path, sizeof(path), "/sys/class/misc/%s/device/ca= ncel", + dev) < sizeof(path)) { + fd =3D qemu_open(path, O_WRONLY); } } + } + + if (fd < 0) { + error_report("tpm_passthrough: Could not guess TPM cancel path"); } else { - error_report("tpm_passthrough: Bad TPM device path %s", - tpm_pt->tpm_dev); + tpm_pt->options->cancel_path =3D g_strdup(path); } =20 return fd; --=20 2.16.0.rc1.1.gef27df75a1 From nobody Mon May 6 21:45:25 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1517251424461247.5120397128983; Mon, 29 Jan 2018 10:43:44 -0800 (PST) Received: from localhost ([::1]:57647 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1egEP5-00036P-NL for importer@patchew.org; Mon, 29 Jan 2018 13:43:39 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:36694) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1egEFa-0004HS-S1 for qemu-devel@nongnu.org; Mon, 29 Jan 2018 13:33:52 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1egEFV-0004oz-M8 for qemu-devel@nongnu.org; Mon, 29 Jan 2018 13:33:50 -0500 Received: from mx1.redhat.com ([209.132.183.28]:59144) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1egEFV-0004od-F0 for qemu-devel@nongnu.org; Mon, 29 Jan 2018 13:33:45 -0500 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id B56573AD84; Mon, 29 Jan 2018 18:33:44 +0000 (UTC) Received: from localhost (ovpn-112-47.ams2.redhat.com [10.36.112.47]) by smtp.corp.redhat.com (Postfix) with ESMTP id 89BC318ACD; Mon, 29 Jan 2018 18:33:39 +0000 (UTC) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Mon, 29 Jan 2018 19:33:05 +0100 Message-Id: <20180129183307.19689-4-marcandre.lureau@redhat.com> In-Reply-To: <20180129183307.19689-1-marcandre.lureau@redhat.com> References: <20180129183307.19689-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.38]); Mon, 29 Jan 2018 18:33:44 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v4 3/5] tpm: replace GThreadPool with AIO threadpool X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , stefanb@linux.vnet.ibm.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" The TPM backend uses a GThreadPool to handle IO in a seperate thread. However, GThreadPool isn't integrated with Qemu main loops, making it unnecessarily complicated to deal with. Qemu has a AIO threadpool, that is better integrated with loops and various IO functions, provides completion BH by default etc. Remove the only user of GThreadPool from qemu, use AIO threadpool. Note that the backend: - no longer accepts queing multiple requests (unneeded so far) - increase ref to itself when handling a command, for extra safety - tpm_backend_thread_end() is renamed tpm_backend_finish_sync() and will wait for completion of BH (request_completed), which will help migration handling. Signed-off-by: Marc-Andr=C3=A9 Lureau --- include/sysemu/tpm_backend.h | 12 ++++++++-- backends/tpm.c | 52 +++++++++++++++++++++++-----------------= ---- 2 files changed, 37 insertions(+), 27 deletions(-) diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h index 0d6c994a62..a69593e0cd 100644 --- a/include/sysemu/tpm_backend.h +++ b/include/sysemu/tpm_backend.h @@ -45,9 +45,8 @@ struct TPMBackend { /*< protected >*/ TPMIf *tpmif; bool opened; - GThreadPool *thread_pool; bool had_startup_error; - QEMUBH *bh; + TPMBackendCmd *cmd; =20 /* */ char *id; @@ -196,6 +195,15 @@ TPMVersion tpm_backend_get_tpm_version(TPMBackend *s); */ size_t tpm_backend_get_buffer_size(TPMBackend *s); =20 +/** + * tpm_backend_finish_sync: + * @s: the backend to call into + * + * Finish the pending command synchronously (this will call aio_poll() + * on qemu main AIOContext until it ends) + */ +void tpm_backend_finish_sync(TPMBackend *s); + /** * tpm_backend_query_tpm: * @s: the backend diff --git a/backends/tpm.c b/backends/tpm.c index 91222c5164..143807aa37 100644 --- a/backends/tpm.c +++ b/backends/tpm.c @@ -19,30 +19,35 @@ #include "sysemu/tpm.h" #include "qemu/thread.h" #include "qemu/main-loop.h" +#include "block/thread-pool.h" +#include "qemu/error-report.h" =20 -static void tpm_backend_request_completed_bh(void *opaque) +static void tpm_backend_request_completed(void *opaque, int ret) { TPMBackend *s =3D TPM_BACKEND(opaque); TPMIfClass *tic =3D TPM_IF_GET_CLASS(s->tpmif); =20 tic->request_completed(s->tpmif); + + /* no need for atomic, as long the BQL is taken */ + s->cmd =3D NULL; + object_unref(OBJECT(s)); } =20 -static void tpm_backend_worker_thread(gpointer data, gpointer user_data) +static int tpm_backend_worker_thread(gpointer data) { - TPMBackend *s =3D TPM_BACKEND(user_data); + TPMBackend *s =3D TPM_BACKEND(data); TPMBackendClass *k =3D TPM_BACKEND_GET_CLASS(s); =20 - k->handle_request(s, (TPMBackendCmd *)data); + k->handle_request(s, s->cmd); =20 - qemu_bh_schedule(s->bh); + return 0; } =20 -static void tpm_backend_thread_end(TPMBackend *s) +void tpm_backend_finish_sync(TPMBackend *s) { - if (s->thread_pool) { - g_thread_pool_free(s->thread_pool, FALSE, TRUE); - s->thread_pool =3D NULL; + while (s->cmd) { + aio_poll(qemu_get_aio_context(), true); } } =20 @@ -74,10 +79,7 @@ int tpm_backend_startup_tpm(TPMBackend *s, size_t buffer= size) TPMBackendClass *k =3D TPM_BACKEND_GET_CLASS(s); =20 /* terminate a running TPM */ - tpm_backend_thread_end(s); - - s->thread_pool =3D g_thread_pool_new(tpm_backend_worker_thread, s, 1, = TRUE, - NULL); + tpm_backend_finish_sync(s); =20 res =3D k->startup_tpm ? k->startup_tpm(s, buffersize) : 0; =20 @@ -93,7 +95,17 @@ bool tpm_backend_had_startup_error(TPMBackend *s) =20 void tpm_backend_deliver_request(TPMBackend *s, TPMBackendCmd *cmd) { - g_thread_pool_push(s->thread_pool, cmd, NULL); + ThreadPool *pool =3D aio_get_thread_pool(qemu_get_aio_context()); + + if (s->cmd !=3D NULL) { + error_report("There is a TPM request pending"); + return; + } + + s->cmd =3D cmd; + object_ref(OBJECT(s)); + thread_pool_submit_aio(pool, tpm_backend_worker_thread, s, + tpm_backend_request_completed, s); } =20 void tpm_backend_reset(TPMBackend *s) @@ -104,7 +116,7 @@ void tpm_backend_reset(TPMBackend *s) k->reset(s); } =20 - tpm_backend_thread_end(s); + tpm_backend_finish_sync(s); =20 s->had_startup_error =3D false; } @@ -159,28 +171,18 @@ TPMInfo *tpm_backend_query_tpm(TPMBackend *s) return info; } =20 -static void tpm_backend_instance_init(Object *obj) -{ - TPMBackend *s =3D TPM_BACKEND(obj); - - s->bh =3D qemu_bh_new(tpm_backend_request_completed_bh, s); -} - static void tpm_backend_instance_finalize(Object *obj) { TPMBackend *s =3D TPM_BACKEND(obj); =20 object_unref(OBJECT(s->tpmif)); g_free(s->id); - tpm_backend_thread_end(s); - qemu_bh_delete(s->bh); } =20 static const TypeInfo tpm_backend_info =3D { .name =3D TYPE_TPM_BACKEND, .parent =3D TYPE_OBJECT, .instance_size =3D sizeof(TPMBackend), - .instance_init =3D tpm_backend_instance_init, .instance_finalize =3D tpm_backend_instance_finalize, .class_size =3D sizeof(TPMBackendClass), .abstract =3D true, --=20 2.16.0.rc1.1.gef27df75a1 From nobody Mon May 6 21:45:25 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1517251059079460.1047500138749; Mon, 29 Jan 2018 10:37:39 -0800 (PST) Received: from localhost ([::1]:57248 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1egEJG-0006ye-8h for importer@patchew.org; Mon, 29 Jan 2018 13:37:38 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:36705) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1egEFb-0004IW-Vj for qemu-devel@nongnu.org; Mon, 29 Jan 2018 13:33:53 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1egEFa-0004rT-Kj for qemu-devel@nongnu.org; Mon, 29 Jan 2018 13:33:52 -0500 Received: from mx1.redhat.com ([209.132.183.28]:49480) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1egEFa-0004qy-CH for qemu-devel@nongnu.org; Mon, 29 Jan 2018 13:33:50 -0500 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 9FE02C05B00B; Mon, 29 Jan 2018 18:33:49 +0000 (UTC) Received: from localhost (ovpn-112-47.ams2.redhat.com [10.36.112.47]) by smtp.corp.redhat.com (Postfix) with ESMTP id 5272218F05; Mon, 29 Jan 2018 18:33:45 +0000 (UTC) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Mon, 29 Jan 2018 19:33:06 +0100 Message-Id: <20180129183307.19689-5-marcandre.lureau@redhat.com> In-Reply-To: <20180129183307.19689-1-marcandre.lureau@redhat.com> References: <20180129183307.19689-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Mon, 29 Jan 2018 18:33:49 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v4 4/5] tpm: report backend request error X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , stefanb@linux.vnet.ibm.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Use an Error** for request to let the caller handle error reporting. This will also allow to inform the frontend of a backend error. Signed-off-by: Marc-Andr=C3=A9 Lureau --- include/sysemu/tpm.h | 2 +- include/sysemu/tpm_backend.h | 3 ++- backends/tpm.c | 9 +++++++-- hw/tpm/tpm_emulator.c | 21 ++++++--------------- hw/tpm/tpm_passthrough.c | 31 +++++++++++++++---------------- hw/tpm/tpm_tis.c | 3 ++- 6 files changed, 33 insertions(+), 36 deletions(-) diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h index 852e02687c..ac04a9d4a2 100644 --- a/include/sysemu/tpm.h +++ b/include/sysemu/tpm.h @@ -41,7 +41,7 @@ typedef struct TPMIfClass { InterfaceClass parent_class; =20 enum TpmModel model; - void (*request_completed)(TPMIf *obj); + void (*request_completed)(TPMIf *obj, int ret); enum TPMVersion (*get_version)(TPMIf *obj); } TPMIfClass; =20 diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h index a69593e0cd..7e166ef954 100644 --- a/include/sysemu/tpm_backend.h +++ b/include/sysemu/tpm_backend.h @@ -18,6 +18,7 @@ #include "qapi-types.h" #include "qemu/option.h" #include "sysemu/tpm.h" +#include "qapi/error.h" =20 #define TYPE_TPM_BACKEND "tpm-backend" #define TPM_BACKEND(obj) \ @@ -84,7 +85,7 @@ struct TPMBackendClass { =20 TpmTypeOptions *(*get_tpm_options)(TPMBackend *t); =20 - void (*handle_request)(TPMBackend *s, TPMBackendCmd *cmd); + void (*handle_request)(TPMBackend *s, TPMBackendCmd *cmd, Error **errp= ); }; =20 /** diff --git a/backends/tpm.c b/backends/tpm.c index 143807aa37..d617ba7c52 100644 --- a/backends/tpm.c +++ b/backends/tpm.c @@ -27,7 +27,7 @@ static void tpm_backend_request_completed(void *opaque, i= nt ret) TPMBackend *s =3D TPM_BACKEND(opaque); TPMIfClass *tic =3D TPM_IF_GET_CLASS(s->tpmif); =20 - tic->request_completed(s->tpmif); + tic->request_completed(s->tpmif, ret); =20 /* no need for atomic, as long the BQL is taken */ s->cmd =3D NULL; @@ -38,8 +38,13 @@ static int tpm_backend_worker_thread(gpointer data) { TPMBackend *s =3D TPM_BACKEND(data); TPMBackendClass *k =3D TPM_BACKEND_GET_CLASS(s); + Error *err =3D NULL; =20 - k->handle_request(s, s->cmd); + k->handle_request(s, s->cmd, &err); + if (err) { + error_report_err(err); + return -1; + } =20 return 0; } diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c index a34a18ac7a..59a9f0e72e 100644 --- a/hw/tpm/tpm_emulator.c +++ b/hw/tpm/tpm_emulator.c @@ -183,28 +183,19 @@ static int tpm_emulator_set_locality(TPMEmulator *tpm= _emu, uint8_t locty_number, return 0; } =20 -static void tpm_emulator_handle_request(TPMBackend *tb, TPMBackendCmd *cmd) +static void tpm_emulator_handle_request(TPMBackend *tb, TPMBackendCmd *cmd, + Error **errp) { TPMEmulator *tpm_emu =3D TPM_EMULATOR(tb); - Error *err =3D NULL; =20 DPRINTF("processing TPM command"); =20 - if (tpm_emulator_set_locality(tpm_emu, cmd->locty, &err) < 0) { - goto error; - } - - if (tpm_emulator_unix_tx_bufs(tpm_emu, cmd->in, cmd->in_len, + if (tpm_emulator_set_locality(tpm_emu, cmd->locty, errp) < 0 || + tpm_emulator_unix_tx_bufs(tpm_emu, cmd->in, cmd->in_len, cmd->out, cmd->out_len, - &cmd->selftest_done, &err) < 0) { - goto error; + &cmd->selftest_done, errp) < 0) { + tpm_util_write_fatal_error_response(cmd->out, cmd->out_len); } - - return; - -error: - tpm_util_write_fatal_error_response(cmd->out, cmd->out_len); - error_report_err(err); } =20 static int tpm_emulator_probe_caps(TPMEmulator *tpm_emu) diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c index fc42fe0933..a495fe07f4 100644 --- a/hw/tpm/tpm_passthrough.c +++ b/hw/tpm/tpm_passthrough.c @@ -80,10 +80,11 @@ static int tpm_passthrough_unix_read(int fd, uint8_t *b= uf, uint32_t len) } return ret; } -static int tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt, - const uint8_t *in, uint32_t in_len, - uint8_t *out, uint32_t out_len, - bool *selftest_done) + +static void tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt, + const uint8_t *in, uint32_t in_le= n, + uint8_t *out, uint32_t out_len, + bool *selftest_done, Error **errp) { ssize_t ret; bool is_selftest; @@ -98,9 +99,8 @@ static int tpm_passthrough_unix_tx_bufs(TPMPassthruState = *tpm_pt, ret =3D qemu_write_full(tpm_pt->tpm_fd, in, in_len); if (ret !=3D in_len) { if (!tpm_pt->tpm_op_canceled || errno !=3D ECANCELED) { - error_report("tpm_passthrough: error while transmitting data " - "to TPM: %s (%i)", - strerror(errno), errno); + error_setg_errno(errp, errno, "tpm_passthrough: error while " + "transmitting data to TPM"); } goto err_exit; } @@ -110,15 +110,14 @@ static int tpm_passthrough_unix_tx_bufs(TPMPassthruSt= ate *tpm_pt, ret =3D tpm_passthrough_unix_read(tpm_pt->tpm_fd, out, out_len); if (ret < 0) { if (!tpm_pt->tpm_op_canceled || errno !=3D ECANCELED) { - error_report("tpm_passthrough: error while reading data from " - "TPM: %s (%i)", - strerror(errno), errno); + error_setg_errno(errp, errno, "tpm_passthrough: error while " + "reading data from TPM"); } } else if (ret < sizeof(struct tpm_resp_hdr) || tpm_cmd_get_size(out) !=3D ret) { ret =3D -1; - error_report("tpm_passthrough: received invalid response " - "packet from TPM"); + error_setg_errno(errp, errno, "tpm_passthrough: received invalid " + "response packet from TPM"); } =20 if (is_selftest && (ret >=3D sizeof(struct tpm_resp_hdr))) { @@ -131,18 +130,18 @@ err_exit: } =20 tpm_pt->tpm_executing =3D false; - - return ret; } =20 -static void tpm_passthrough_handle_request(TPMBackend *tb, TPMBackendCmd *= cmd) +static void tpm_passthrough_handle_request(TPMBackend *tb, TPMBackendCmd *= cmd, + Error **errp) { TPMPassthruState *tpm_pt =3D TPM_PASSTHROUGH(tb); =20 DPRINTF("tpm_passthrough: processing command %p\n", cmd); =20 tpm_passthrough_unix_tx_bufs(tpm_pt, cmd->in, cmd->in_len, - cmd->out, cmd->out_len, &cmd->selftest_do= ne); + cmd->out, cmd->out_len, &cmd->selftest_do= ne, + errp); } =20 static void tpm_passthrough_reset(TPMBackend *tb) diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c index 8b5eb01a2c..08f41d2707 100644 --- a/hw/tpm/tpm_tis.c +++ b/hw/tpm/tpm_tis.c @@ -393,7 +393,7 @@ static void tpm_tis_prep_abort(TPMState *s, uint8_t loc= ty, uint8_t newlocty) /* * Callback from the TPM to indicate that the response was received. */ -static void tpm_tis_request_completed(TPMIf *ti) +static void tpm_tis_request_completed(TPMIf *ti, int ret) { TPMState *s =3D TPM(ti); uint8_t locty =3D s->cmd.locty; @@ -405,6 +405,7 @@ static void tpm_tis_request_completed(TPMIf *ti) } } =20 + /* FIXME: report error if ret !=3D 0 */ tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE); s->loc[locty].state =3D TPM_TIS_STATE_COMPLETION; --=20 2.16.0.rc1.1.gef27df75a1 From nobody Mon May 6 21:45:25 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1517250995125199.69866994138363; Mon, 29 Jan 2018 10:36:35 -0800 (PST) Received: from localhost ([::1]:57082 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1egEIE-00063y-3b for importer@patchew.org; Mon, 29 Jan 2018 13:36:34 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:36864) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1egEG5-0004gC-Ku for qemu-devel@nongnu.org; Mon, 29 Jan 2018 13:34:24 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1egEG0-00053X-Ie for qemu-devel@nongnu.org; Mon, 29 Jan 2018 13:34:21 -0500 Received: from mx1.redhat.com ([209.132.183.28]:40962) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1egEG0-00052w-7T for qemu-devel@nongnu.org; Mon, 29 Jan 2018 13:34:16 -0500 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 814D98E718; Mon, 29 Jan 2018 18:34:15 +0000 (UTC) Received: from localhost (ovpn-112-47.ams2.redhat.com [10.36.112.47]) by smtp.corp.redhat.com (Postfix) with ESMTP id 4C719425F; Mon, 29 Jan 2018 18:33:50 +0000 (UTC) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Mon, 29 Jan 2018 19:33:07 +0100 Message-Id: <20180129183307.19689-6-marcandre.lureau@redhat.com> In-Reply-To: <20180129183307.19689-1-marcandre.lureau@redhat.com> References: <20180129183307.19689-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.25]); Mon, 29 Jan 2018 18:34:15 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v4 5/5] tpm: add CRB device X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Eduardo Habkost , "Michael S. Tsirkin" , stefanb@linux.vnet.ibm.com, Markus Armbruster , Paolo Bonzini , Igor Mammedov , Marcel Apfelbaum , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , Richard Henderson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" tpm_crb is a device for TPM 2.0 Command Response Buffer (CRB) Interface as defined in TCG PC Client Platform TPM Profile (PTP) Specification Family =E2=80=9C2.0=E2=80=9D Level 00 Revision 01.03 v22. The PTP allows device implementation to switch between TIS and CRB model at run time, but given that CRB is a simpler device to implement, I chose to implement it as a different device. The device doesn't implement other locality than 0 for now (my laptop TPM doesn't either, so I assume this isn't so bad) Tested with some success with Linux upstream and Windows 10, seabios & modified ovmf. The device is recognized and correctly transmit command/response with passthrough & emu. However, we are missing PPI ACPI part atm. Signed-off-by: Marc-Andr=C3=A9 Lureau --- qapi/tpm.json | 5 +- include/hw/acpi/tpm.h | 51 +++++++ include/sysemu/tpm.h | 3 + hw/i386/acpi-build.c | 34 ++++- hw/tpm/tpm_crb.c | 303 +++++++++++++++++++++++++++++++++= ++++ tests/tpm-crb-test.c | 275 +++++++++++++++++++++++++++++++++ default-configs/i386-softmmu.mak | 1 + default-configs/x86_64-softmmu.mak | 1 + hw/tpm/Makefile.objs | 1 + tests/Makefile.include | 2 + 10 files changed, 666 insertions(+), 10 deletions(-) create mode 100644 hw/tpm/tpm_crb.c create mode 100644 tests/tpm-crb-test.c diff --git a/qapi/tpm.json b/qapi/tpm.json index 7093f268fb..d50deef5e9 100644 --- a/qapi/tpm.json +++ b/qapi/tpm.json @@ -11,10 +11,11 @@ # An enumeration of TPM models # # @tpm-tis: TPM TIS model +# @tpm-crb: TPM CRB model (since 2.12) # # Since: 1.5 ## -{ 'enum': 'TpmModel', 'data': [ 'tpm-tis' ] } +{ 'enum': 'TpmModel', 'data': [ 'tpm-tis', 'tpm-crb' ] } =20 ## # @query-tpm-models: @@ -28,7 +29,7 @@ # Example: # # -> { "execute": "query-tpm-models" } -# <- { "return": [ "tpm-tis" ] } +# <- { "return": [ "tpm-tis", "tpm-crb" ] } # ## { 'command': 'query-tpm-models', 'returns': ['TpmModel'] } diff --git a/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h index 6d516c6a7f..96fd3a92f7 100644 --- a/include/hw/acpi/tpm.h +++ b/include/hw/acpi/tpm.h @@ -16,11 +16,61 @@ #ifndef HW_ACPI_TPM_H #define HW_ACPI_TPM_H =20 +#include "hw/registerfields.h" + #define TPM_TIS_ADDR_BASE 0xFED40000 #define TPM_TIS_ADDR_SIZE 0x5000 =20 #define TPM_TIS_IRQ 5 =20 +REG32(CRB_LOC_STATE, 0x00) + FIELD(CRB_LOC_STATE, tpmEstablished, 0, 1) + FIELD(CRB_LOC_STATE, locAssigned, 1, 1) + FIELD(CRB_LOC_STATE, activeLocality, 2, 3) + FIELD(CRB_LOC_STATE, reserved, 5, 2) + FIELD(CRB_LOC_STATE, tpmRegValidSts, 7, 1) +REG32(CRB_LOC_CTRL, 0x08) +REG32(CRB_LOC_STS, 0x0C) + FIELD(CRB_LOC_STS, Granted, 0, 1) + FIELD(CRB_LOC_STS, beenSeized, 1, 1) +REG32(CRB_INTF_ID, 0x30) + FIELD(CRB_INTF_ID, InterfaceType, 0, 4) + FIELD(CRB_INTF_ID, InterfaceVersion, 4, 4) + FIELD(CRB_INTF_ID, CapLocality, 8, 1) + FIELD(CRB_INTF_ID, CapCRBIdleBypass, 9, 1) + FIELD(CRB_INTF_ID, Reserved1, 10, 1) + FIELD(CRB_INTF_ID, CapDataXferSizeSupport, 11, 2) + FIELD(CRB_INTF_ID, CapFIFO, 13, 1) + FIELD(CRB_INTF_ID, CapCRB, 14, 1) + FIELD(CRB_INTF_ID, CapIFRes, 15, 2) + FIELD(CRB_INTF_ID, InterfaceSelector, 17, 2) + FIELD(CRB_INTF_ID, IntfSelLock, 19, 1) + FIELD(CRB_INTF_ID, Reserved2, 20, 4) + FIELD(CRB_INTF_ID, RID, 24, 8) +REG32(CRB_INTF_ID2, 0x34) + FIELD(CRB_INTF_ID2, VID, 0, 16) + FIELD(CRB_INTF_ID2, DID, 16, 16) +REG32(CRB_CTRL_EXT, 0x38) +REG32(CRB_CTRL_REQ, 0x40) +REG32(CRB_CTRL_STS, 0x44) + FIELD(CRB_CTRL_STS, tpmSts, 0, 1) + FIELD(CRB_CTRL_STS, tpmIdle, 1, 1) +REG32(CRB_CTRL_CANCEL, 0x48) +REG32(CRB_CTRL_START, 0x4C) +REG32(CRB_INT_ENABLED, 0x50) +REG32(CRB_INT_STS, 0x54) +REG32(CRB_CTRL_CMD_SIZE, 0x58) +REG32(CRB_CTRL_CMD_LADDR, 0x5C) +REG32(CRB_CTRL_CMD_HADDR, 0x60) +REG32(CRB_CTRL_RSP_SIZE, 0x64) +REG32(CRB_CTRL_RSP_ADDR, 0x68) +REG32(CRB_DATA_BUFFER, 0x80) + +#define TPM_CRB_ADDR_BASE 0xFED40000 +#define TPM_CRB_ADDR_SIZE 0x1000 +#define TPM_CRB_ADDR_CTRL (TPM_CRB_ADDR_BASE + A_CRB_CTRL_REQ) +#define TPM_CRB_R_MAX R_CRB_DATA_BUFFER + #define TPM_LOG_AREA_MINIMUM_SIZE (64 * 1024) =20 #define TPM_TCPA_ACPI_CLASS_CLIENT 0 @@ -30,5 +80,6 @@ #define TPM2_ACPI_CLASS_SERVER 1 =20 #define TPM2_START_METHOD_MMIO 6 +#define TPM2_START_METHOD_CRB 7 =20 #endif /* HW_ACPI_TPM_H */ diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h index ac04a9d4a2..233b1a3fc3 100644 --- a/include/sysemu/tpm.h +++ b/include/sysemu/tpm.h @@ -46,9 +46,12 @@ typedef struct TPMIfClass { } TPMIfClass; =20 #define TYPE_TPM_TIS "tpm-tis" +#define TYPE_TPM_CRB "tpm-crb" =20 #define TPM_IS_TIS(chr) \ object_dynamic_cast(OBJECT(chr), TYPE_TPM_TIS) +#define TPM_IS_CRB(chr) \ + object_dynamic_cast(OBJECT(chr), TYPE_TPM_CRB) =20 /* returns NULL unless there is exactly one TPM device */ static inline TPMIf *tpm_find(void) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index dc4b2b9ffe..ed78c4ed9f 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -2224,6 +2224,22 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, aml_append(sb_scope, scope); } } + + if (TPM_IS_CRB(tpm_find())) { + dev =3D aml_device("TPM"); + aml_append(dev, aml_name_decl("_HID", aml_string("MSFT0101"))); + crs =3D aml_resource_template(); + aml_append(crs, aml_memory32_fixed(TPM_CRB_ADDR_BASE, + TPM_CRB_ADDR_SIZE, AML_READ_WRI= TE)); + aml_append(dev, aml_name_decl("_CRS", crs)); + + method =3D aml_method("_STA", 0, AML_NOTSERIALIZED); + aml_append(method, aml_return(aml_int(0x0f))); + aml_append(dev, method); + + aml_append(sb_scope, dev); + } + aml_append(dsdt, sb_scope); =20 /* copy AML table into ACPI tables blob and patch header there */ @@ -2285,18 +2301,20 @@ build_tpm2(GArray *table_data, BIOSLinker *linker, = GArray *tcpalog) if (TPM_IS_TIS(tpm_find())) { tpm2_ptr->control_area_address =3D cpu_to_le64(0); tpm2_ptr->start_method =3D cpu_to_le32(TPM2_START_METHOD_MMIO); - - tpm2_ptr->log_area_minimum_length =3D - cpu_to_le32(TPM_LOG_AREA_MINIMUM_SIZE); - - /* log area start address to be filled by Guest linker */ - bios_linker_loader_add_pointer(linker, - ACPI_BUILD_TABLE_FILE, log_addr_offset, log_addr_size, - ACPI_BUILD_TPMLOG_FILE, 0); + } else if (TPM_IS_CRB(tpm_find())) { + tpm2_ptr->control_area_address =3D cpu_to_le64(TPM_CRB_ADDR_CTRL); + tpm2_ptr->start_method =3D cpu_to_le32(TPM2_START_METHOD_CRB); } else { g_warn_if_reached(); } =20 + tpm2_ptr->log_area_minimum_length =3D + cpu_to_le32(TPM_LOG_AREA_MINIMUM_SIZE); + + /* log area start address to be filled by Guest linker */ + bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE, + log_addr_offset, log_addr_size, + ACPI_BUILD_TPMLOG_FILE, 0); build_header(linker, table_data, (void *)tpm2_ptr, "TPM2", sizeof(*tpm2_ptr), 4, NULL, NUL= L); } diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c new file mode 100644 index 0000000000..687d2557b7 --- /dev/null +++ b/hw/tpm/tpm_crb.c @@ -0,0 +1,303 @@ +/* + * tpm_crb.c - QEMU's TPM CRB interface emulator + * + * Copyright (c) 2018 Red Hat, Inc. + * + * Authors: + * Marc-Andr=C3=A9 Lureau + * + * This work is licensed under the terms of the GNU GPL, version 2 or late= r. + * See the COPYING file in the top-level directory. + * + * tpm_crb is a device for TPM 2.0 Command Response Buffer (CRB) Interface + * as defined in TCG PC Client Platform TPM Profile (PTP) Specification + * Family =E2=80=9C2.0=E2=80=9D Level 00 Revision 01.03 v22 + */ + +#include "qemu/osdep.h" + +#include "qemu-common.h" +#include "qapi/error.h" +#include "exec/address-spaces.h" + +#include "hw/qdev-core.h" +#include "hw/qdev-properties.h" +#include "hw/pci/pci_ids.h" +#include "hw/acpi/tpm.h" +#include "migration/vmstate.h" +#include "sysemu/tpm_backend.h" +#include "tpm_int.h" +#include "tpm_util.h" + +typedef struct CRBState { + DeviceState parent_obj; + + TPMBackend *tpmbe; + TPMBackendCmd cmd; + uint32_t regs[TPM_CRB_R_MAX]; + MemoryRegion mmio; + MemoryRegion cmdmem; + + size_t be_buffer_size; +} CRBState; + +#define CRB(obj) OBJECT_CHECK(CRBState, (obj), TYPE_TPM_CRB) + +#define DEBUG_CRB 0 + +#define DPRINTF(fmt, ...) do { \ + if (DEBUG_CRB) { \ + printf(fmt, ## __VA_ARGS__); \ + } \ + } while (0) + +#define CRB_INTF_TYPE_CRB_ACTIVE 0b1 +#define CRB_INTF_VERSION_CRB 0b1 +#define CRB_INTF_CAP_LOCALITY_0_ONLY 0b0 +#define CRB_INTF_CAP_IDLE_FAST 0b0 +#define CRB_INTF_CAP_XFER_SIZE_64 0b11 +#define CRB_INTF_CAP_FIFO_NOT_SUPPORTED 0b0 +#define CRB_INTF_CAP_CRB_SUPPORTED 0b1 +#define CRB_INTF_IF_SELECTOR_CRB 0b1 + +#define CRB_CTRL_CMD_SIZE (TPM_CRB_ADDR_SIZE - A_CRB_DATA_BUFFER) + +enum crb_loc_ctrl { + CRB_LOC_CTRL_REQUEST_ACCESS =3D BIT(0), + CRB_LOC_CTRL_RELINQUISH =3D BIT(1), + CRB_LOC_CTRL_SEIZE =3D BIT(2), + CRB_LOC_CTRL_RESET_ESTABLISHMENT_BIT =3D BIT(3), +}; + +enum crb_ctrl_req { + CRB_CTRL_REQ_CMD_READY =3D BIT(0), + CRB_CTRL_REQ_GO_IDLE =3D BIT(1), +}; + +enum crb_start { + CRB_START_INVOKE =3D BIT(0), +}; + +enum crb_cancel { + CRB_CANCEL_INVOKE =3D BIT(0), +}; + +static uint64_t tpm_crb_mmio_read(void *opaque, hwaddr addr, + unsigned size) +{ + CRBState *s =3D CRB(opaque); + void *regs =3D (void *)&s->regs + (addr & ~3); + unsigned offset =3D addr & 3; + uint32_t val =3D *(uint32_t *)regs >> (8 * offset); + + DPRINTF("CRB read 0x" TARGET_FMT_plx " len:%u val: 0x%" PRIx32 "\n", + addr, size, val); + return val; +} + +static void tpm_crb_mmio_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + CRBState *s =3D CRB(opaque); + DPRINTF("CRB write 0x" TARGET_FMT_plx " len:%u val: 0x%" PRIx64 "\n", + addr, size, val); + + switch (addr) { + case A_CRB_CTRL_REQ: + switch (val) { + case CRB_CTRL_REQ_CMD_READY: + ARRAY_FIELD_DP32(s->regs, CRB_CTRL_STS, + tpmIdle, 0); + break; + case CRB_CTRL_REQ_GO_IDLE: + ARRAY_FIELD_DP32(s->regs, CRB_CTRL_STS, + tpmIdle, 1); + break; + } + break; + case A_CRB_CTRL_CANCEL: + if (val =3D=3D CRB_CANCEL_INVOKE && + s->regs[R_CRB_CTRL_START] & CRB_START_INVOKE) { + tpm_backend_cancel_cmd(s->tpmbe); + } + break; + case A_CRB_CTRL_START: + if (val =3D=3D CRB_START_INVOKE && + !(s->regs[R_CRB_CTRL_START] & CRB_START_INVOKE)) { + void *mem =3D memory_region_get_ram_ptr(&s->cmdmem); + + s->regs[R_CRB_CTRL_START] |=3D CRB_START_INVOKE; + s->cmd =3D (TPMBackendCmd) { + .in =3D mem, + .in_len =3D MIN(tpm_cmd_get_size(mem), s->be_buffer_size), + .out =3D mem, + .out_len =3D s->be_buffer_size, + }; + + tpm_backend_deliver_request(s->tpmbe, &s->cmd); + } + break; + case A_CRB_LOC_CTRL: + switch (val) { + case CRB_LOC_CTRL_RESET_ESTABLISHMENT_BIT: + /* not loc 3 or 4 */ + break; + case CRB_LOC_CTRL_RELINQUISH: + break; + case CRB_LOC_CTRL_REQUEST_ACCESS: + ARRAY_FIELD_DP32(s->regs, CRB_LOC_STS, + Granted, 1); + ARRAY_FIELD_DP32(s->regs, CRB_LOC_STS, + beenSeized, 0); + ARRAY_FIELD_DP32(s->regs, CRB_LOC_STATE, + locAssigned, 1); + ARRAY_FIELD_DP32(s->regs, CRB_LOC_STATE, + tpmRegValidSts, 1); + break; + } + break; + } +} + +static const MemoryRegionOps tpm_crb_memory_ops =3D { + .read =3D tpm_crb_mmio_read, + .write =3D tpm_crb_mmio_write, + .endianness =3D DEVICE_LITTLE_ENDIAN, + .valid =3D { + .min_access_size =3D 1, + .max_access_size =3D 4, + }, +}; + +static void tpm_crb_request_completed(TPMIf *ti, int ret) +{ + CRBState *s =3D CRB(ti); + + s->regs[R_CRB_CTRL_START] &=3D ~CRB_START_INVOKE; + if (ret !=3D 0) { + ARRAY_FIELD_DP32(s->regs, CRB_CTRL_STS, + tpmSts, 1); /* fatal error */ + } +} + +static enum TPMVersion tpm_crb_get_version(TPMIf *ti) +{ + CRBState *s =3D CRB(ti); + + return tpm_backend_get_tpm_version(s->tpmbe); +} + +static int tpm_crb_pre_save(void *opaque) +{ + CRBState *s =3D opaque; + + tpm_backend_finish_sync(s->tpmbe); + + return 0; +} + +static const VMStateDescription vmstate_tpm_crb =3D { + .name =3D "tpm-crb", + .pre_save =3D tpm_crb_pre_save, + .fields =3D (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, CRBState, TPM_CRB_R_MAX), + VMSTATE_END_OF_LIST(), + } +}; + +static Property tpm_crb_properties[] =3D { + DEFINE_PROP_TPMBE("tpmdev", CRBState, tpmbe), + DEFINE_PROP_END_OF_LIST(), +}; + +static void tpm_crb_realize(DeviceState *dev, Error **errp) +{ + CRBState *s =3D CRB(dev); + + if (!tpm_find()) { + error_setg(errp, "at most one TPM device is permitted"); + return; + } + if (!s->tpmbe) { + error_setg(errp, "'tpmdev' property is required"); + return; + } + + memory_region_init_io(&s->mmio, OBJECT(s), &tpm_crb_memory_ops, s, + "tpm-crb-mmio", sizeof(s->regs)); + memory_region_init_ram(&s->cmdmem, OBJECT(s), + "tpm-crb-cmd", CRB_CTRL_CMD_SIZE, errp); + + memory_region_add_subregion(get_system_memory(), + TPM_CRB_ADDR_BASE, &s->mmio); + memory_region_add_subregion(get_system_memory(), + TPM_CRB_ADDR_BASE + sizeof(s->regs), &s->cmdmem); + + tpm_backend_reset(s->tpmbe); + + ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID, + InterfaceType, CRB_INTF_TYPE_CRB_ACTIVE); + ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID, + InterfaceVersion, CRB_INTF_VERSION_CRB); + ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID, + CapLocality, CRB_INTF_CAP_LOCALITY_0_ONLY); + ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID, + CapCRBIdleBypass, CRB_INTF_CAP_IDLE_FAST); + ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID, + CapDataXferSizeSupport, CRB_INTF_CAP_XFER_SIZE_64); + ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID, + CapFIFO, CRB_INTF_CAP_FIFO_NOT_SUPPORTED); + ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID, + CapCRB, CRB_INTF_CAP_CRB_SUPPORTED); + ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID, + InterfaceSelector, CRB_INTF_IF_SELECTOR_CRB); + ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID, + RID, 0b0000); + ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID2, + VID, PCI_VENDOR_ID_IBM); + + s->regs[R_CRB_CTRL_CMD_SIZE] =3D CRB_CTRL_CMD_SIZE; + s->regs[R_CRB_CTRL_CMD_LADDR] =3D TPM_CRB_ADDR_BASE + A_CRB_DATA_BUFFE= R; + s->regs[R_CRB_CTRL_RSP_SIZE] =3D CRB_CTRL_CMD_SIZE; + s->regs[R_CRB_CTRL_RSP_ADDR] =3D TPM_CRB_ADDR_BASE + A_CRB_DATA_BUFFER; + + s->be_buffer_size =3D MIN(tpm_backend_get_buffer_size(s->tpmbe), + CRB_CTRL_CMD_SIZE); + + tpm_backend_startup_tpm(s->tpmbe, s->be_buffer_size); +} + +static void tpm_crb_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + TPMIfClass *tc =3D TPM_IF_CLASS(klass); + + dc->realize =3D tpm_crb_realize; + dc->props =3D tpm_crb_properties; + dc->vmsd =3D &vmstate_tpm_crb; + dc->user_creatable =3D true; + tc->model =3D TPM_MODEL_TPM_CRB; + tc->get_version =3D tpm_crb_get_version; + tc->request_completed =3D tpm_crb_request_completed; + + set_bit(DEVICE_CATEGORY_MISC, dc->categories); +} + +static const TypeInfo tpm_crb_info =3D { + .name =3D TYPE_TPM_CRB, + /* could be TYPE_SYS_BUS_DEVICE (or LPC etc) */ + .parent =3D TYPE_DEVICE, + .instance_size =3D sizeof(CRBState), + .class_init =3D tpm_crb_class_init, + .interfaces =3D (InterfaceInfo[]) { + { TYPE_TPM_IF }, + { } + } +}; + +static void tpm_crb_register(void) +{ + type_register_static(&tpm_crb_info); +} + +type_init(tpm_crb_register) diff --git a/tests/tpm-crb-test.c b/tests/tpm-crb-test.c new file mode 100644 index 0000000000..8bf1507e00 --- /dev/null +++ b/tests/tpm-crb-test.c @@ -0,0 +1,275 @@ +/* + * QTest testcase for TPM CRB + * + * Copyright (c) 2018 Red Hat, Inc. + * + * Authors: + * Marc-Andr=C3=A9 Lureau + * + * This work is licensed under the terms of the GNU GPL, version 2 or late= r. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include + +#include "hw/acpi/tpm.h" +#include "hw/tpm/tpm_ioctl.h" +#include "io/channel-socket.h" +#include "libqtest.h" +#include "qapi/error.h" + +#define TPM_RC_FAILURE 0x101 +#define TPM2_ST_NO_SESSIONS 0x8001 + +struct tpm_hdr { + uint16_t tag; + uint32_t len; + uint32_t code; /*ordinal/error */ + char buffer[]; +} QEMU_PACKED; + +typedef struct TestState { + CompatGMutex data_mutex; + CompatGCond data_cond; + SocketAddress *addr; + QIOChannel *tpm_ioc; + GThread *emu_tpm_thread; + struct tpm_hdr *tpm_msg; +} TestState; + +static void test_wait_cond(TestState *s) +{ + gint64 end_time =3D g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND; + + g_mutex_lock(&s->data_mutex); + if (!g_cond_wait_until(&s->data_cond, &s->data_mutex, end_time)) { + g_assert_not_reached(); + } + g_mutex_unlock(&s->data_mutex); +} + +static void *emu_tpm_thread(void *data) +{ + TestState *s =3D data; + QIOChannel *ioc =3D s->tpm_ioc; + + s->tpm_msg =3D g_new(struct tpm_hdr, 1); + while (true) { + int minhlen =3D sizeof(s->tpm_msg->tag) + sizeof(s->tpm_msg->len); + + if (!qio_channel_read(ioc, (char *)s->tpm_msg, minhlen, &error_abo= rt)) { + break; + } + s->tpm_msg->tag =3D be16_to_cpu(s->tpm_msg->tag); + s->tpm_msg->len =3D be32_to_cpu(s->tpm_msg->len); + g_assert_cmpint(s->tpm_msg->len, >=3D, minhlen); + g_assert_cmpint(s->tpm_msg->tag, =3D=3D, TPM2_ST_NO_SESSIONS); + + s->tpm_msg =3D g_realloc(s->tpm_msg, s->tpm_msg->len); + qio_channel_read(ioc, (char *)&s->tpm_msg->code, + s->tpm_msg->len - minhlen, &error_abort); + s->tpm_msg->code =3D be32_to_cpu(s->tpm_msg->code); + + /* reply error */ + s->tpm_msg->tag =3D cpu_to_be16(TPM2_ST_NO_SESSIONS); + s->tpm_msg->len =3D cpu_to_be32(sizeof(struct tpm_hdr)); + s->tpm_msg->code =3D cpu_to_be32(TPM_RC_FAILURE); + qio_channel_write(ioc, (char *)s->tpm_msg, be32_to_cpu(s->tpm_msg-= >len), + &error_abort); + } + + g_free(s->tpm_msg); + s->tpm_msg =3D NULL; + object_unref(OBJECT(s->tpm_ioc)); + return NULL; +} + +static void *emu_ctrl_thread(void *data) +{ + TestState *s =3D data; + QIOChannelSocket *lioc =3D qio_channel_socket_new(); + QIOChannel *ioc; + + qio_channel_socket_listen_sync(lioc, s->addr, &error_abort); + g_cond_signal(&s->data_cond); + + qio_channel_wait(QIO_CHANNEL(lioc), G_IO_IN); + ioc =3D QIO_CHANNEL(qio_channel_socket_accept(lioc, &error_abort)); + g_assert(ioc); + + { + uint32_t cmd =3D 0; + struct iovec iov =3D { .iov_base =3D &cmd, .iov_len =3D sizeof(cmd= ) }; + int *pfd =3D NULL; + size_t nfd =3D 0; + + qio_channel_readv_full(ioc, &iov, 1, &pfd, &nfd, &error_abort); + cmd =3D be32_to_cpu(cmd); + g_assert_cmpint(cmd, =3D=3D, CMD_SET_DATAFD); + g_assert_cmpint(nfd, =3D=3D, 1); + s->tpm_ioc =3D QIO_CHANNEL(qio_channel_socket_new_fd(*pfd, &error_= abort)); + g_free(pfd); + + cmd =3D 0; + qio_channel_write(ioc, (char *)&cmd, sizeof(cmd), &error_abort); + + s->emu_tpm_thread =3D g_thread_new(NULL, emu_tpm_thread, s); + } + + while (true) { + uint32_t cmd; + ssize_t ret; + + ret =3D qio_channel_read(ioc, (char *)&cmd, sizeof(cmd), NULL); + if (ret <=3D 0) { + break; + } + + cmd =3D be32_to_cpu(cmd); + switch (cmd) { + case CMD_GET_CAPABILITY: { + ptm_cap cap =3D cpu_to_be64(0x3fff); + qio_channel_write(ioc, (char *)&cap, sizeof(cap), &error_abort= ); + break; + } + case CMD_INIT: { + ptm_init init; + qio_channel_read(ioc, (char *)&init.u.req, sizeof(init.u.req), + &error_abort); + init.u.resp.tpm_result =3D 0; + qio_channel_write(ioc, (char *)&init.u.resp, sizeof(init.u.res= p), + &error_abort); + break; + } + case CMD_SHUTDOWN: { + ptm_res res =3D 0; + qio_channel_write(ioc, (char *)&res, sizeof(res), &error_abort= ); + qio_channel_close(s->tpm_ioc, &error_abort); + g_thread_join(s->emu_tpm_thread); + break; + } + case CMD_STOP: { + ptm_res res =3D 0; + qio_channel_write(ioc, (char *)&res, sizeof(res), &error_abort= ); + break; + } + case CMD_SET_BUFFERSIZE: { + ptm_setbuffersize sbs; + qio_channel_read(ioc, (char *)&sbs.u.req, sizeof(sbs.u.req), + &error_abort); + sbs.u.resp.buffersize =3D sbs.u.req.buffersize ?: cpu_to_be32(= 4096); + sbs.u.resp.tpm_result =3D 0; + sbs.u.resp.minsize =3D cpu_to_be32(128); + sbs.u.resp.maxsize =3D cpu_to_be32(4096); + qio_channel_write(ioc, (char *)&sbs.u.resp, sizeof(sbs.u.resp), + &error_abort); + break; + } + case CMD_SET_LOCALITY: { + ptm_loc loc; + /* Note: this time it's not u.req / u.resp... */ + qio_channel_read(ioc, (char *)&loc, sizeof(loc), &error_abort); + g_assert_cmpint(loc.u.req.loc, =3D=3D, 0); + loc.u.resp.tpm_result =3D 0; + qio_channel_write(ioc, (char *)&loc, sizeof(loc), &error_abort= ); + break; + } + default: + g_debug("unimplemented %u", cmd); + g_assert_not_reached(); + } + } + + object_unref(OBJECT(ioc)); + object_unref(OBJECT(lioc)); + return NULL; +} + +#define TPM_CMD "\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00" + +static void tpm_crb_test(const void *data) +{ + const TestState *s =3D data; + uint32_t intfid =3D readl(TPM_CRB_ADDR_BASE + A_CRB_INTF_ID); + uint32_t csize =3D readl(TPM_CRB_ADDR_BASE + A_CRB_CTRL_CMD_SIZE); + uint64_t caddr =3D readq(TPM_CRB_ADDR_BASE + A_CRB_CTRL_CMD_LADDR); + uint32_t rsize =3D readl(TPM_CRB_ADDR_BASE + A_CRB_CTRL_RSP_SIZE); + uint64_t raddr =3D readq(TPM_CRB_ADDR_BASE + A_CRB_CTRL_RSP_ADDR); + + g_assert_cmpint(FIELD_EX32(intfid, CRB_INTF_ID, InterfaceType), =3D=3D= , 1); + g_assert_cmpint(FIELD_EX32(intfid, CRB_INTF_ID, InterfaceVersion), =3D= =3D, 1); + g_assert_cmpint(FIELD_EX32(intfid, CRB_INTF_ID, CapLocality), =3D=3D, = 0); + g_assert_cmpint(FIELD_EX32(intfid, CRB_INTF_ID, CapCRBIdleBypass), =3D= =3D, 0); + g_assert_cmpint(FIELD_EX32(intfid, CRB_INTF_ID, CapDataXferSizeSupport= ), + =3D=3D, 3); + g_assert_cmpint(FIELD_EX32(intfid, CRB_INTF_ID, CapFIFO), =3D=3D, 0); + g_assert_cmpint(FIELD_EX32(intfid, CRB_INTF_ID, CapCRB), =3D=3D, 1); + g_assert_cmpint(FIELD_EX32(intfid, CRB_INTF_ID, InterfaceSelector), = =3D=3D, 1); + g_assert_cmpint(FIELD_EX32(intfid, CRB_INTF_ID, RID), =3D=3D, 0); + + g_assert_cmpint(csize, >=3D, 128); + g_assert_cmpint(rsize, >=3D, 128); + g_assert_cmpint(caddr, >, TPM_CRB_ADDR_BASE); + g_assert_cmpint(raddr, >, TPM_CRB_ADDR_BASE); + + memwrite(caddr, TPM_CMD, sizeof(TPM_CMD)); + + uint32_t sts, start =3D 1; + uint64_t end_time =3D g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND; + writel(TPM_CRB_ADDR_BASE + A_CRB_CTRL_START, start); + do { + start =3D readl(TPM_CRB_ADDR_BASE + A_CRB_CTRL_START); + if ((start & 1) =3D=3D 0) { + break; + } + } while (g_get_monotonic_time() < end_time); + start =3D readl(TPM_CRB_ADDR_BASE + A_CRB_CTRL_START); + g_assert_cmpint(start & 1, =3D=3D, 0); + sts =3D readl(TPM_CRB_ADDR_BASE + A_CRB_CTRL_STS); + g_assert_cmpint(sts & 1, =3D=3D, 0); + + struct tpm_hdr tpm_msg; + memread(raddr, &tpm_msg, sizeof(tpm_msg)); + g_assert_cmpmem(&tpm_msg, sizeof(tpm_msg), s->tpm_msg, sizeof(*s->tpm_= msg)); +} + +int main(int argc, char **argv) +{ + int ret; + char *args, *tmp_path =3D g_dir_make_tmp("qemu-tpm-crb-test.XXXXXX", N= ULL); + GThread *thread; + TestState test; + + module_call_init(MODULE_INIT_QOM); + g_test_init(&argc, &argv, NULL); + + test.addr =3D g_new0(SocketAddress, 1); + test.addr->type =3D SOCKET_ADDRESS_TYPE_UNIX; + test.addr->u.q_unix.path =3D g_build_filename(tmp_path, "sock", NULL); + g_mutex_init(&test.data_mutex); + g_cond_init(&test.data_cond); + + thread =3D g_thread_new(NULL, emu_ctrl_thread, &test); + test_wait_cond(&test); + + args =3D g_strdup_printf( + "-chardev socket,id=3Dchr,path=3D%s " + "-tpmdev emulator,id=3Ddev,chardev=3Dchr " + "-device tpm-crb,tpmdev=3Ddev", + test.addr->u.q_unix.path); + qtest_start(args); + + qtest_add_data_func("/tpm-crb/test", &test, tpm_crb_test); + ret =3D g_test_run(); + + qtest_end(); + + g_thread_join(thread); + g_unlink(test.addr->u.q_unix.path); + qapi_free_SocketAddress(test.addr); + g_rmdir(tmp_path); + g_free(tmp_path); + g_free(args); + return ret; +} diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmm= u.mak index 95ac4b464a..ac27700e79 100644 --- a/default-configs/i386-softmmu.mak +++ b/default-configs/i386-softmmu.mak @@ -37,6 +37,7 @@ CONFIG_APPLESMC=3Dy CONFIG_I8259=3Dy CONFIG_PFLASH_CFI01=3Dy CONFIG_TPM_TIS=3D$(CONFIG_TPM) +CONFIG_TPM_CRB=3D$(CONFIG_TPM) CONFIG_MC146818RTC=3Dy CONFIG_PCI_PIIX=3Dy CONFIG_WDT_IB700=3Dy diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-so= ftmmu.mak index 0221236825..b2104ade19 100644 --- a/default-configs/x86_64-softmmu.mak +++ b/default-configs/x86_64-softmmu.mak @@ -37,6 +37,7 @@ CONFIG_APPLESMC=3Dy CONFIG_I8259=3Dy CONFIG_PFLASH_CFI01=3Dy CONFIG_TPM_TIS=3D$(CONFIG_TPM) +CONFIG_TPM_CRB=3D$(CONFIG_TPM) CONFIG_MC146818RTC=3Dy CONFIG_PCI_PIIX=3Dy CONFIG_WDT_IB700=3Dy diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs index 7a93b24636..1dc9f8bf2c 100644 --- a/hw/tpm/Makefile.objs +++ b/hw/tpm/Makefile.objs @@ -1,4 +1,5 @@ common-obj-y +=3D tpm_util.o common-obj-$(CONFIG_TPM_TIS) +=3D tpm_tis.o +common-obj-$(CONFIG_TPM_CRB) +=3D tpm_crb.o common-obj-$(CONFIG_TPM_PASSTHROUGH) +=3D tpm_passthrough.o common-obj-$(CONFIG_TPM_EMULATOR) +=3D tpm_emulator.o diff --git a/tests/Makefile.include b/tests/Makefile.include index 851aafe9d1..ca82e0c0cc 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -286,6 +286,7 @@ check-qtest-i386-$(CONFIG_VHOST_USER_NET_TEST_i386) += =3D tests/vhost-user-test$(EX ifeq ($(CONFIG_VHOST_USER_NET_TEST_i386),) check-qtest-x86_64-$(CONFIG_VHOST_USER_NET_TEST_x86_64) +=3D tests/vhost-u= ser-test$(EXESUF) endif +check-qtest-i386-$(CONFIG_TPM) +=3D tests/tpm-crb-test$(EXESUF) check-qtest-i386-$(CONFIG_SLIRP) +=3D tests/test-netfilter$(EXESUF) check-qtest-i386-$(CONFIG_POSIX) +=3D tests/test-filter-mirror$(EXESUF) check-qtest-i386-$(CONFIG_POSIX) +=3D tests/test-filter-redirector$(EXESUF) @@ -708,6 +709,7 @@ tests/test-crypto-tlssession$(EXESUF): tests/test-crypt= o-tlssession.o \ tests/test-io-task$(EXESUF): tests/test-io-task.o $(test-io-obj-y) tests/test-io-channel-socket$(EXESUF): tests/test-io-channel-socket.o \ tests/io-channel-helpers.o $(test-io-obj-y) +tests/tpm-crb-test$(EXESUF): tests/tpm-crb-test.o $(test-io-obj-y) tests/test-io-channel-file$(EXESUF): tests/test-io-channel-file.o \ tests/io-channel-helpers.o $(test-io-obj-y) tests/test-io-channel-tls$(EXESUF): tests/test-io-channel-tls.o \ --=20 2.16.0.rc1.1.gef27df75a1