From patchwork Wed Dec 11 20:26:56 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 1207894 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47Y7mR4Fpqz9sR8 for ; Thu, 12 Dec 2019 07:28:23 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.vnet.ibm.com Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 47Y7mR2gSKzDqc9 for ; Thu, 12 Dec 2019 07:28:23 +1100 (AEDT) X-Original-To: slof@lists.ozlabs.org Delivered-To: slof@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=none (no SPF record) smtp.mailfrom=linux.vnet.ibm.com (client-ip=148.163.158.5; helo=mx0a-001b2d01.pphosted.com; envelope-from=stefanb@linux.vnet.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.vnet.ibm.com Received: from mx0a-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com [148.163.158.5]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 47Y7ll2fDyzDqPN for ; Thu, 12 Dec 2019 07:27:43 +1100 (AEDT) Received: from pps.filterd (m0098413.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id xBBKGf9w041117; Wed, 11 Dec 2019 15:27:41 -0500 Received: from ppma05wdc.us.ibm.com (1b.90.2fa9.ip4.static.sl-reverse.com [169.47.144.27]) by mx0b-001b2d01.pphosted.com with ESMTP id 2wsqc2pd1m-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 11 Dec 2019 15:27:41 -0500 Received: from pps.filterd (ppma05wdc.us.ibm.com [127.0.0.1]) by ppma05wdc.us.ibm.com (8.16.0.27/8.16.0.27) with SMTP id xBBKJrls031541; Wed, 11 Dec 2019 20:27:39 GMT Received: from b01cxnp23033.gho.pok.ibm.com (b01cxnp23033.gho.pok.ibm.com [9.57.198.28]) by ppma05wdc.us.ibm.com with ESMTP id 2wtdq7b85b-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 11 Dec 2019 20:27:39 +0000 Received: from b01ledav003.gho.pok.ibm.com (b01ledav003.gho.pok.ibm.com [9.57.199.108]) by b01cxnp23033.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id xBBKRdft38273310 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 11 Dec 2019 20:27:39 GMT Received: from b01ledav003.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 45A2DB2067; Wed, 11 Dec 2019 20:27:39 +0000 (GMT) Received: from b01ledav003.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 252E0B2065; Wed, 11 Dec 2019 20:27:39 +0000 (GMT) Received: from newfield.pok.ibm.com (unknown [9.47.158.66]) by b01ledav003.gho.pok.ibm.com (Postfix) with ESMTP; Wed, 11 Dec 2019 20:27:39 +0000 (GMT) From: Stefan Berger To: slof@lists.ozlabs.org Date: Wed, 11 Dec 2019 15:26:56 -0500 Message-Id: <20191211202728.127996-2-stefanb@linux.vnet.ibm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191211202728.127996-1-stefanb@linux.vnet.ibm.com> References: <20191211202728.127996-1-stefanb@linux.vnet.ibm.com> X-TM-AS-GCONF: 00 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.95, 18.0.572 definitions=2019-12-11_06:2019-12-11, 2019-12-11 signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 bulkscore=0 adultscore=0 malwarescore=0 suspectscore=0 clxscore=1015 mlxscore=0 phishscore=0 priorityscore=1501 mlxlogscore=999 spamscore=0 lowpriorityscore=0 impostorscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-1910280000 definitions=main-1912110168 Subject: [SLOF] [PATCH v4 01/33] tpm: Add a TPM driver implementation X-BeenThere: slof@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Patches for https://github.com/aik/SLOF" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kevin@koconnor.net MIME-Version: 1.0 Errors-To: slof-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "SLOF" This patch adds a TPM driver for the CRQ interface as used by the QEMU PAPR implementation. Also add a Readme that explains the benefits and installation procedure for the vTPM. Signed-off-by: Stefan Berger --- include/helpers.h | 1 + lib/libtpm/Makefile | 50 ++++ lib/libtpm/Readme | 95 ++++++++ lib/libtpm/tpm_drivers.c | 478 +++++++++++++++++++++++++++++++++++++++ lib/libtpm/tpm_drivers.h | 81 +++++++ slof/helpers.c | 6 + 6 files changed, 711 insertions(+) create mode 100644 lib/libtpm/Makefile create mode 100644 lib/libtpm/Readme create mode 100644 lib/libtpm/tpm_drivers.c create mode 100644 lib/libtpm/tpm_drivers.h diff --git a/include/helpers.h b/include/helpers.h index 5834bce..aaef977 100644 --- a/include/helpers.h +++ b/include/helpers.h @@ -42,6 +42,7 @@ extern void SLOF_encode_bootp_response(void *addr, size_t size); extern void SLOF_encode_dhcp_response(void *addr, size_t size); extern int SLOF_get_property(const char *node, const char *propname, char **addr, int *len); +extern unsigned long SLOF_get_vtpm_unit(void); #define offset_of(type, member) ((long) &((type *)0)->member) #define container_of(ptr, type, member) ({ \ diff --git a/lib/libtpm/Makefile b/lib/libtpm/Makefile new file mode 100644 index 0000000..ff19e1c --- /dev/null +++ b/lib/libtpm/Makefile @@ -0,0 +1,50 @@ +# ***************************************************************************** +# * Copyright (c) 2015 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +TOPCMNDIR ?= ../.. + +CPPFLAGS = -I../libc/include $(CPUARCHDEF) -I$(INCLBRDDIR) \ + -I$(INCLCMNDIR) -I$(INCLCMNDIR)/$(CPUARCH) -I$(SLOFCMNDIR) +CPPFLAGS += -I../libhvcall + +LDFLAGS = -nostdlib + +TARGET = ../libtpm.a + + +all: $(TARGET) + +SRCS = tpm_drivers.c + +OBJS = $(SRCS:%.c=%.o) + +$(TARGET): $(OBJS) + $(AR) -rc $@ $(OBJS) + $(RANLIB) $@ + +clean: + $(RM) $(TARGET) $(OBJS) + +distclean: clean + $(RM) Makefile.dep + + +# Rules for creating the dependency file: +depend: + $(RM) Makefile.dep + $(MAKE) Makefile.dep + +Makefile.dep: Makefile + $(CC) -M $(CPPFLAGS) $(CFLAGS) $(SRCS) $(SRCSS) > Makefile.dep + +# Include dependency file if available: +-include Makefile.dep diff --git a/lib/libtpm/Readme b/lib/libtpm/Readme new file mode 100644 index 0000000..c59de10 --- /dev/null +++ b/lib/libtpm/Readme @@ -0,0 +1,95 @@ +This directory hosts (v)TPM related code. + +Background: +----------- + +A TPM is a crypto chip that is found in many systems. Besides it offering +a secure key store, among other functionality, it is also used to implement +'trusted boot'. This is realized by code in the firmware measuring parts of the +firmware's code and data as well as system data, such as the boot block, and +logging these measurements and storing (extending) them in the TPM's platform +configuration register (PCR). + +The benefits of having a TPM (or vTPM) in a system are: + +- enablement of trusted boot; this allow us to eventually extend the chain of + trust from the hypervisor to the guests +- enablement of attestation so that one can verify what software is running on + a machine (OpenPTS, OpenAttestation) +- provides TPM functionality to VMs, which includes a standardized mechanism + to store keys and other blobs (Linux trusted keys, GNU TLS's TPM extensions) + + +QEMU/KVM + SLOF support: +------------------------ + +To enable a vTPM with QEMU, the following steps need to be followed + +- build a recent version of libtpms + + #> git clone https://github.com/stefanberger/libtpms + #> cd libtpms + #> ./autogen.sh --prefix=/usr --with-tpm2 --with-openssl + + The following step may require to install dependencies + + #> make + #> make check + #> make install + +- build swtpm + + #> git clone https://github.com/stefanberger/swtpm + #> cd swtpm + #> ./autogen.sh --prefix=/usr --with-openssl + + The following step may require to install dependencies + + #> ./configure --prefix=/usr --with-openssl + #> make + #> make check + #> make install + +- build QEMU with vTPM support: + + #> git clone https://github.com/stefanberger/qemu-tpm + #> cd qemu-tpm + + The PPC64 patches are currently in the tpm-next+spapr.v3 branch + #> git checkout origin/tpm-next+spapr.v3 -b tpm-next+spapr.v3 + + The following step may require to install dependencies + + #> ./configure --prefix=/usr --enable-kvm --target-list="ppc64-softmmu" + #> make + #> make install + +To start a QEMU VM with an attached vTPM (swtpm), run the following commands +as 'root'. The following will setup the vTPM so that its state will be stored +in /tmp/mytpm1. A unique directory for each VM instance with attached vTPM +should be provided. Whenever QEMU is started, the swtpm has to be started +before it. The './boot_rom.bin' represents SLOF with vTPM extensions built-in. + + #> mkdir -p /tmp/mytpm1 + #> swtpm socket --tpmstate dir=/tmp \ + --ctrl type=unixio,path=/tmp/mytpm1/ctrl.sock + + In another terminal: + + #> qemu-system-ppc64 \ + -enable-kvm \ + -boot menu=on \ + --chardev socket,id=chrtpm,path=/tmp/mytpm1/ctrl.sock \ + -tpmdev emulator,id=tpm0,chardev=chrtpm \ + -device tpm-spapr,tpmdev=tpm0 \ + -vnc 0.0.0.0:2 \ + [...] + + Add hard disk and other parameters as needed. + +Notes: + - The Linux kernel in the VM must have the tpm_ibmvtpm module available + or built-in. + + - 'swtpm_ioctl --unix /tmp/ctrl.sock -s' can be used to gracefully shut + down the vTPM. diff --git a/lib/libtpm/tpm_drivers.c b/lib/libtpm/tpm_drivers.c new file mode 100644 index 0000000..19e988d --- /dev/null +++ b/lib/libtpm/tpm_drivers.c @@ -0,0 +1,478 @@ +/***************************************************************************** + * Copyright (c) 2015 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include +#include +#include + +#include "string.h" +#include "helpers.h" +#include "byteorder.h" +#include "tpm_drivers.h" +#include "libhvcall.h" +#include "paflof.h" + +#undef PAPR_VTPM_DEBUG +//#define PAPR_VTPM_DEBUG +#ifdef PAPR_VTPM_DEBUG +#define dprintf(_x ...) do { printf("VTPM CRQ: " _x); } while(0) +#else +#define dprintf(_x ...) +#endif + +#define MIN(a, b) ((a) > (b) ? (b) : (a)) + +/* layout of the command request queue for vTPM */ +struct crq { + uint8_t valid; + uint8_t msg; + uint16_t len; + uint32_t data; + uint64_t reserved; +} __attribute__((packed)); + +#define PAPR_VTPM_INIT_CRQ_COMMAND 0xC0 +#define PAPR_VTPM_VALID_COMMAND 0x80 +#define PAPR_VTPM_MSG_RESULT 0x80 + +/* crq.msg request types when crq.valid = PAPR_VTPM_INIT_CRQ_COMMAND */ +#define PAPR_VTPM_INIT_CRQ_RESULT 0x1 + +/* crq.msg request types when crq.valid = PAPR_VTPM_VALID_COMMAND */ +#define PAPR_VTPM_GET_VERSION 0x1 +#define PAPR_VTPM_TPM_COMMAND 0x2 +#define PAPR_VTPM_GET_RTCE_BUFFER_SIZE 0x3 + +static const uint32_t tpm_default_durations[TPM_NUM_DURATIONS] = { + TPM_DEFAULT_DURATION_SHORT, + TPM_DEFAULT_DURATION_MEDIUM, + TPM_DEFAULT_DURATION_LONG, +}; + +#define QUEUE_SIZE 4096 + +/* state of the PAPR CRQ VTPM driver */ +static struct spapr_vtpm_driver_state { + /* whether it driver been initialized */ + bool initialized; + + /* durations of short, medium, & long commands */ + uint32_t durations[TPM_NUM_DURATIONS]; + + /* unit number */ + unsigned long unit; + + /* CRQ queue address and size */ + unsigned char *qaddr; + unsigned long qsize; + + /* current q_entry */ + unsigned int curr_q_entry; + + /* current response CRQ */ + struct crq *response; + + /* power firmware defined state and error code */ + vtpm_drv_state driver_state; + vtpm_drv_error driver_error; + + /* size of buffer supported by hypervisor */ + unsigned int buffer_size; + + /* buffer for commands and responses */ + char *buffer; + + /* version of the TPM we talk to -- from CRQ message */ + uint32_t tpm_version; +} spapr_vtpm = { + .qsize = QUEUE_SIZE, + .driver_state = VTPM_DRV_STATE_INVALID, + .driver_error = VTPM_DRV_ERROR_NO_FAILURE, +}; + +static void vtpm_drv_state_set(vtpm_drv_state s, vtpm_drv_error e) +{ + spapr_vtpm.driver_state = s; + spapr_vtpm.driver_error = e; +} + +static vtpm_drv_state vtpm_drv_state_get(void) +{ + return spapr_vtpm.driver_state; +} + +static vtpm_drv_error vtpm_drv_error_get(void) +{ + return spapr_vtpm.driver_error; +} + +void spapr_vtpm_set_durations(const uint32_t durations[TPM_NUM_DURATIONS]) +{ + memcpy(spapr_vtpm.durations, durations, + TPM_NUM_DURATIONS * sizeof(durations[0])); +} + +static struct crq* get_crq(void *qaddr, unsigned long q_entry) +{ + return &((struct crq *)qaddr)[q_entry]; +} + +/* + * Get the crq where the response will be found. This + * function will clear the CRQ's valid field and advance + * the entry counter to the next entry. + */ +static struct crq *get_response_crq(void) +{ + struct crq *crq; + + dprintf("curr_q_entry = %d\n", spapr_vtpm.curr_q_entry); + + crq = get_crq(spapr_vtpm.qaddr, spapr_vtpm.curr_q_entry); + memset(crq, 0, sizeof(*crq)); + + spapr_vtpm.curr_q_entry += 1; + if (spapr_vtpm.curr_q_entry == (spapr_vtpm.qsize / sizeof(struct crq))) + spapr_vtpm.curr_q_entry = 0; + + return crq; +} + +/* + * Send a message via CRQ and wait for the response + */ +static bool spapr_send_crq_and_wait(unsigned long unit, + struct crq *crq, + struct crq **response, + unsigned timeout, + vtpm_drv_state state1, + vtpm_drv_state state2) +{ + long rc; + unsigned i; + + *response = get_response_crq(); + + vtpm_drv_state_set(state1, VTPM_DRV_ERROR_NO_FAILURE); + + rc = hv_send_crq(unit, (uint64_t *)crq); + if (rc != H_SUCCESS) { + vtpm_drv_state_set(VTPM_DRV_STATE_WAIT_INIT, + VTPM_DRV_ERROR_TPM_CRQ_ERROR); + return false; + } + + vtpm_drv_state_set(state2, VTPM_DRV_ERROR_NO_FAILURE); + + for (i = 0; i < timeout; i += 1000) { + if (((*response)->valid & PAPR_VTPM_MSG_RESULT)) + return true; + SLOF_usleep(1000); + } + + vtpm_drv_state_set(VTPM_DRV_STATE_FAILURE, + VTPM_DRV_ERROR_WAIT_TIMEOUT); + + dprintf("Received no response from CRQ\n"); + return false; +} + +/* + * Get parameters from the CRQ + */ +static bool spapr_vtpm_get_params(void) +{ + struct crq crq, *response; + static bool completed = false; /* only once */ + + if (completed) + return true; + + /* get the TPM version */ + crq.valid = PAPR_VTPM_VALID_COMMAND; + crq.msg = PAPR_VTPM_GET_VERSION; + + if (!spapr_send_crq_and_wait(spapr_vtpm.unit, &crq, &response, 10, + VTPM_DRV_STATE_SEND_GET_VERSION, + VTPM_DRV_STATE_WAIT_VERSION)) { + printf("%s: Failure getting TPM version from CRQ\n", __func__); + return false; + } + + vtpm_drv_state_set(VTPM_DRV_STATE_CHECK_VERSION, + VTPM_DRV_ERROR_NO_FAILURE); + + spapr_vtpm.tpm_version = be32_to_cpu(response->data); + dprintf("TPM backend version: %d\n", spapr_vtpm.tpm_version); + + /* get the TPM's buffer size */ + crq.valid = PAPR_VTPM_VALID_COMMAND; + crq.msg = PAPR_VTPM_GET_RTCE_BUFFER_SIZE; + + if (!spapr_send_crq_and_wait(spapr_vtpm.unit, &crq, &response, 10, + VTPM_DRV_STATE_SEND_BUFSIZE_REQ, + VTPM_DRV_STATE_WAIT_BUFSIZE)) { + printf("%s: Failure getting RTCE buffer size from CRQ\n", + __func__); + return false; + } + + vtpm_drv_state_set(VTPM_DRV_STATE_ALLOC_RTCE_BUF, + VTPM_DRV_ERROR_NO_FAILURE); + + dprintf("RTCE buffer size: %u\n", be16_to_cpu(response->len)); + spapr_vtpm.buffer_size = be16_to_cpu(response->len); + if (spapr_vtpm.buffer_size < 1024) { + printf("%s: RTCE buffer size of %u bytes is too small. " + "Minimum is 1024 bytes.\n", __func__, + spapr_vtpm.buffer_size); + vtpm_drv_state_set(VTPM_DRV_STATE_FAILURE, + VTPM_DRV_ERROR_BAD_RTCE_SIZE); + return false; + } + spapr_vtpm.buffer = SLOF_alloc_mem(spapr_vtpm.buffer_size); + if (!spapr_vtpm.buffer) { + printf("%s: Could not allocate buffer of size %u.\n", + __func__, spapr_vtpm.buffer_size); + vtpm_drv_state_set(VTPM_DRV_STATE_FAILURE, + VTPM_DRV_ERROR_BAD_RTCE_SIZE); + return false; + } + + completed = true; + + return true; +} + +static bool spapr_vtpm_activate(void) +{ + long rc; + struct crq crq, *response; + + if (vtpm_drv_error_get() != VTPM_DRV_ERROR_NO_FAILURE) { + printf("%s: CRQ: In failure mode\n", __func__); + return false; + } + + vtpm_drv_state_set(VTPM_DRV_STATE_REG_CRQ, + VTPM_DRV_ERROR_NO_FAILURE); + + rc = hv_reg_crq(spapr_vtpm.unit, (unsigned long)spapr_vtpm.qaddr, + spapr_vtpm.qsize); + if (rc != H_SUCCESS) { + vtpm_drv_state_set(VTPM_DRV_STATE_WAIT_INIT, + VTPM_DRV_ERROR_UNEXPECTED_REG_ERROR); + printf("%s: CRQ registration failed\n", __func__); + return false; + } + + /* we always start with curr_q_entry 0 */ + spapr_vtpm.curr_q_entry = 0; + + if (!spapr_vtpm.initialized) { + + crq.valid = PAPR_VTPM_INIT_CRQ_COMMAND; + crq.msg = PAPR_VTPM_INIT_CRQ_RESULT; + + if (!spapr_send_crq_and_wait(spapr_vtpm.unit, + &crq, + &response, + 10, + VTPM_DRV_STATE_SEND_INIT, + VTPM_DRV_STATE_WAIT_INIT_COMP)) { + printf("%s: Initializing CRQ failed\n", __func__); + goto err_exit; + } + dprintf("Successfully initialized CRQ\n"); + + spapr_vtpm.initialized = true; + } + + if (spapr_vtpm_get_params()) + return true; + +err_exit: + hv_free_crq(spapr_vtpm.unit); + spapr_vtpm.unit = 0; + + return false; +} + +static bool spapr_vtpm_init(void) +{ + spapr_vtpm_set_durations(tpm_default_durations); + + return true; +} + +void spapr_vtpm_finalize(void) +{ + if (spapr_vtpm.unit) + hv_free_crq(spapr_vtpm.unit); +} + +/* + * Check whether we have a CRQ underneath us; if we do, the CRQ will + * be left open. + */ +static bool spapr_vtpm_probe(void) +{ + spapr_vtpm_init(); + + if (!spapr_vtpm.qaddr) { + spapr_vtpm.qaddr = SLOF_alloc_mem(spapr_vtpm.qsize); + if (!spapr_vtpm.qaddr) { + printf("%s: Unable to allocate memory\n", __func__); + return false; + } + memset(spapr_vtpm.qaddr, 0, spapr_vtpm.qsize); + + dprintf("getting FORTH vtpm-unit\n"); + spapr_vtpm.unit = SLOF_get_vtpm_unit(); + if (!spapr_vtpm.unit) { + printf("%s: Could not get valid vtpm-unit\n", __func__); + return false; + } + } + + dprintf("vtpm_unit = %lx, buffer = %p\n", + spapr_vtpm.unit, spapr_vtpm.qaddr); + + if (!spapr_vtpm_activate()) + return false; + + return true; +} + +static bool spapr_vtpm_senddata(const uint8_t *const data, uint32_t len) +{ + struct crq crq; + long rc; + + if (vtpm_drv_error_get() != VTPM_DRV_ERROR_NO_FAILURE) { + printf("%s: VTPM CRQ: In failure mode\n", __func__); + return false; + } + + if (len > spapr_vtpm.buffer_size) { + printf("%s: VTPM CRQ: Send buffer too large: %u > %u\n", + __func__, len, spapr_vtpm.buffer_size); + return false; + } + + spapr_vtpm.response = get_response_crq(); + spapr_vtpm.response->data = (uint64_t)spapr_vtpm.buffer; + /* response CRQ has been set and valid field cleared */ + + crq.valid = PAPR_VTPM_VALID_COMMAND; + crq.msg = PAPR_VTPM_TPM_COMMAND; + crq.len = cpu_to_be16(len); + crq.data = (uint64_t)spapr_vtpm.buffer; + memcpy(spapr_vtpm.buffer, data, MIN(len, spapr_vtpm.buffer_size)); + + vtpm_drv_state_set(VTPM_DRV_STATE_SEND_TPM_CMD, + VTPM_DRV_ERROR_NO_FAILURE); + + rc = hv_send_crq(spapr_vtpm.unit, (uint64_t *)&crq); + + if (rc == H_SUCCESS) { + vtpm_drv_state_set(VTPM_DRV_STATE_WAIT_TPM_RSP, + VTPM_DRV_ERROR_NO_FAILURE); + } else { + vtpm_drv_state_set(VTPM_DRV_STATE_WAIT_INIT, + VTPM_DRV_ERROR_UNEXPECTED_SEND_ERROR); + } + + return (rc == H_SUCCESS); +} + +static bool spapr_vtpm_waitresponseready(enum tpm_duration_type to_t) +{ + uint32_t timeout = spapr_vtpm.durations[to_t]; + int i; + + if (vtpm_drv_error_get() != VTPM_DRV_ERROR_NO_FAILURE) { + printf("%s: VTPM CRQ: In failure mode\n", __func__); + return false; + } + + /* response CRQ has been set */ + + for (i = 0; i < timeout; i += 1000) { + if (spapr_vtpm.response->valid & PAPR_VTPM_MSG_RESULT) { + /* TPM responded: move to Send tpm-cmd state */ + vtpm_drv_state_set(VTPM_DRV_STATE_SEND_TPM_CMD, + VTPM_DRV_ERROR_NO_FAILURE); + dprintf("Received response to TPM command\n"); + return true; + } + SLOF_usleep(1000); + } + + vtpm_drv_state_set(VTPM_DRV_STATE_FAILURE, + VTPM_DRV_ERROR_WAIT_TIMEOUT); + + dprintf("Received NO response to TPM command"); + + return false; +} + +static bool spapr_vtpm_readresponse(uint8_t *buffer, uint32_t *len) +{ + uint32_t length; + + if (vtpm_drv_error_get() != VTPM_DRV_ERROR_NO_FAILURE) { + printf("%s: VTPM CRQ: In failure mode\n", __func__); + return false; + } + + /* response CRQ has been set */ + length = MIN(*len, be32_to_cpu(spapr_vtpm.response->len)); + + memcpy(buffer, (void *)(uint64_t)spapr_vtpm.response->data, length); + + dprintf("Length of copied response: %d\n", length); + + spapr_vtpm.response = NULL; + *len = length; + + return true; +} + +uint32_t spapr_vtpm_get_buffersize(void) +{ + return spapr_vtpm.buffer_size; +} + +vtpm_drv_state spapr_vtpm_get_state(void) +{ + return vtpm_drv_state_get(); +} + +vtpm_drv_error spapr_vtpm_get_error(void) +{ + return vtpm_drv_error_get(); +} + +/**** higher layer interface ****/ + +bool spapr_is_vtpm_present(void) +{ + bool rc = false; + + if (spapr_vtpm_probe()) { + spapr_vtpm_init(); + rc = true; + } + + return rc; +} diff --git a/lib/libtpm/tpm_drivers.h b/lib/libtpm/tpm_drivers.h new file mode 100644 index 0000000..5d19514 --- /dev/null +++ b/lib/libtpm/tpm_drivers.h @@ -0,0 +1,81 @@ +/***************************************************************************** + * Copyright (c) 2015 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef TPM_DRIVERS_H +#define TPM_DRIVERS_H + +#include +#include +#include + +enum tpm_duration_type { + TPM_DURATION_TYPE_SHORT = 0, + TPM_DURATION_TYPE_MEDIUM, + TPM_DURATION_TYPE_LONG, +}; + +#define TPM_NUM_DURATIONS 3 + +/* durations in microseconds per TPM spec. */ +#define TPM_DEFAULT_DURATION_SHORT 2000000 /* us */ +#define TPM_DEFAULT_DURATION_MEDIUM 20000000 /* us */ +#define TPM_DEFAULT_DURATION_LONG 60000000 /* us */ + +/* firmware driver states */ +typedef enum { + VTPM_DRV_STATE_INVALID = 0, + VTPM_DRV_STATE_INIT_CALLED = 1, + VTPM_DRV_STATE_REG_CRQ = 2, + VTPM_DRV_STATE_WAIT_INIT = 3, + VTPM_DRV_STATE_SEND_INIT = 4, + VTPM_DRV_STATE_FAILURE = 5, + VTPM_DRV_STATE_WAIT_INIT_COMP = 6, + VTPM_DRV_STATE_SEND_INIT_COMP = 7, + VTPM_DRV_STATE_SEND_GET_VERSION = 8, + VTPM_DRV_STATE_WAIT_VERSION = 9, + VTPM_DRV_STATE_CHECK_VERSION = 10, + VTPM_DRV_STATE_SEND_BUFSIZE_REQ = 11, + VTPM_DRV_STATE_WAIT_BUFSIZE = 12, + VTPM_DRV_STATE_ALLOC_RTCE_BUF = 13, + VTPM_DRV_STATE_SEND_TPM_CMD = 14, + VTPM_DRV_STATE_WAIT_TPM_RSP = 15, +} vtpm_drv_state; + +/* firmware driver errors */ +typedef enum { + VTPM_DRV_ERROR_NO_FAILURE = -1, + VTPM_DRV_ERROR_NOT_FOUND_TIMEOUT = 0, + VTPM_DRV_ERROR_UNEXPECTED_REG_ERROR = 1, + VTPM_DRV_ERROR_PARTNER_FAILED = 2, + VTPM_DRV_ERROR_UNEXPECTED_TSP_ERROR = 3, + VTPM_DRV_ERROR_TPM_PROTOCOL_ERROR = 4, + VTPM_DRV_ERROR_WAIT_TIMEOUT = 5, + VTPM_DRV_ERROR_UNEXPECTED_SEND_ERROR = 6, + VTPM_DRV_ERROR_CRQ_OPEN_FAIL = 7, + VTPM_DRV_ERROR_BAD_STATE = 8, + VTPM_DRV_ERROR_TPM_FAIL = 9, + VTPM_DRV_ERROR_TPM_CRQ_ERROR = 10, + VTPM_DRV_ERROR_BAD_VERSION = 11, + VTPM_DRV_ERROR_BAD_RTCE_SIZE = 12, + VTPM_DRV_ERROR_SML_FAILURE = 13, + VTPM_DRV_ERROR_SML_HANDED_OVER = 14, +} vtpm_drv_error; + +/* exported functions */ +bool spapr_is_vtpm_present(void); +void spapr_vtpm_finalize(void); +void spapr_vtpm_set_durations(const uint32_t durations[TPM_NUM_DURATIONS]); +uint32_t spapr_vtpm_get_buffersize(void); +vtpm_drv_state spapr_vtpm_get_state(void); +vtpm_drv_error spapr_vtpm_get_error(void); + +#endif /* TPM_DRIVERS_H */ diff --git a/slof/helpers.c b/slof/helpers.c index dfb0c13..a287c6b 100644 --- a/slof/helpers.c +++ b/slof/helpers.c @@ -224,3 +224,9 @@ int SLOF_get_property(const char *node, const char *propname, *addr = (char *)forth_pop(); return 0; } + +unsigned long SLOF_get_vtpm_unit(void) +{ + forth_eval("vtpm-unit"); + return forth_pop(); +}