From patchwork Wed Dec 11 20:26:57 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 1207895 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 47Y7mZ21cqz9sR7 for ; Thu, 12 Dec 2019 07:28:30 +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 47Y7mZ0fN7zDqhn for ; Thu, 12 Dec 2019 07:28:30 +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.156.1; 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 (mx0a-001b2d01.pphosted.com [148.163.156.1]) (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 47Y7ll37wDzDqQY for ; Thu, 12 Dec 2019 07:27:44 +1100 (AEDT) Received: from pps.filterd (m0098396.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id xBBKGgML020465; Wed, 11 Dec 2019 15:27:41 -0500 Received: from ppma03wdc.us.ibm.com (ba.79.3fa9.ip4.static.sl-reverse.com [169.63.121.186]) by mx0a-001b2d01.pphosted.com with ESMTP id 2wtfbxur3m-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 (ppma03wdc.us.ibm.com [127.0.0.1]) by ppma03wdc.us.ibm.com (8.16.0.27/8.16.0.27) with SMTP id xBBKIKdL016878; 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 ppma03wdc.us.ibm.com with ESMTP id 2wr3q6r3x1-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 xBBKRdUB45220186 (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 6AC25B205F; 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 49CE3B206A; 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:57 -0500 Message-Id: <20191211202728.127996-3-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 suspectscore=15 spamscore=0 mlxlogscore=999 malwarescore=0 phishscore=0 priorityscore=1501 bulkscore=0 adultscore=0 mlxscore=0 lowpriorityscore=0 clxscore=1015 impostorscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-1910280000 definitions=main-1912110168 Subject: [SLOF] [PATCH v4 02/33] tpm: Add TPM initialization support 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 implements the main part of the firmware extensions. It provides the following functionality: - initialization of the TPM by sending a sequence of commands to it - proper setup of the TPM before the firmware hands over control to the bootloader Structures that are needed in subsequent patches are also included in the private header file tcgbios_int.h at this point. Signed-off-by: Stefan Berger --- board-qemu/Makefile | 2 +- board-qemu/slof/Makefile | 13 +- board-qemu/slof/tree.fs | 3 + board-qemu/slof/vio-vtpm-cdriver.fs | 72 ++++++++ board-qemu/slof/vtpm-sml.fs | 62 +++++++ lib/Makefile | 2 +- lib/libtpm/Makefile | 2 +- lib/libtpm/tcgbios.c | 271 ++++++++++++++++++++++++++++ lib/libtpm/tcgbios.h | 22 +++ lib/libtpm/tcgbios_int.h | 153 ++++++++++++++++ lib/libtpm/tpm.code | 46 +++++ lib/libtpm/tpm.in | 18 ++ lib/libtpm/tpm_drivers.c | 13 ++ lib/libtpm/tpm_drivers.h | 5 + slof/fs/start-up.fs | 7 + 15 files changed, 685 insertions(+), 6 deletions(-) create mode 100644 board-qemu/slof/vio-vtpm-cdriver.fs create mode 100644 board-qemu/slof/vtpm-sml.fs create mode 100644 lib/libtpm/tcgbios.c create mode 100644 lib/libtpm/tcgbios.h create mode 100644 lib/libtpm/tcgbios_int.h create mode 100644 lib/libtpm/tpm.code create mode 100644 lib/libtpm/tpm.in diff --git a/board-qemu/Makefile b/board-qemu/Makefile index 61a1367..f419202 100644 --- a/board-qemu/Makefile +++ b/board-qemu/Makefile @@ -15,7 +15,7 @@ BOARD_TARGETS = tools_build romfs_build stage1 subdirs SUBDIRS = slof COMMON_LIBS = libc libbootmsg libbases libnvram libelf libhvcall libvirtio \ - libusb libveth libe1k libnet libbootmenu + libusb libveth libe1k libnet libbootmenu libtpm all: $(BOARD_TARGETS) $(MAKE) boot_rom.bin diff --git a/board-qemu/slof/Makefile b/board-qemu/slof/Makefile index d7ed2d7..a8cff6d 100644 --- a/board-qemu/slof/Makefile +++ b/board-qemu/slof/Makefile @@ -22,7 +22,8 @@ CPPFLAGS = -I$(LIBCMNDIR)/libbootmsg -I$(LIBCMNDIR)/libhvcall \ -I$(LIBCMNDIR)/libvirtio -I$(LIBCMNDIR)/libnvram \ -I$(LIBCMNDIR)/libusb -I$(LIBCMNDIR)/libveth \ -I$(LIBCMNDIR)/libe1k -I$(LIBCMNDIR)/libnet \ - -I$(LIBCMNDIR)/libbootmenu + -I$(LIBCMNDIR)/libbootmenu -I$(LIBCMNDIR)/libtpm + SLOF_LIBS = \ $(LIBCMNDIR)/libbootmsg.a \ $(LIBCMNDIR)/libelf.a \ @@ -33,7 +34,9 @@ SLOF_LIBS = \ $(LIBCMNDIR)/libveth.a \ $(LIBCMNDIR)/libe1k.a \ $(LIBCMNDIR)/libnet.a \ - $(LIBCMNDIR)/libbootmenu.a + $(LIBCMNDIR)/libbootmenu.a \ + $(LIBCMNDIR)/libtpm.a + BOARD_SLOF_IN = \ $(LIBCMNDIR)/libhvcall/hvcall.in \ $(LIBCMNDIR)/libvirtio/virtio.in \ @@ -45,7 +48,9 @@ BOARD_SLOF_IN = \ $(LIBCMNDIR)/libveth/veth.in \ $(LIBCMNDIR)/libe1k/e1k.in \ $(LIBCMNDIR)/libnet/libnet.in \ - $(LIBCMNDIR)/libbootmenu/bootmenu.in + $(LIBCMNDIR)/libbootmenu/bootmenu.in \ + $(LIBCMNDIR)/libtpm/tpm.in + BOARD_SLOF_CODE = $(BOARD_SLOF_IN:%.in=%.code) include $(SLOFCMNDIR)/Makefile.inc @@ -83,6 +88,7 @@ VIO_FFS_FILES = \ $(SLOFBRDDIR)/pci-device_1af4_1050.fs \ $(SLOFBRDDIR)/vio-hvterm.fs \ $(SLOFBRDDIR)/vio-vscsi.fs \ + $(SLOFBRDDIR)/vio-vtpm-cdriver.fs \ $(SLOFBRDDIR)/vio-veth.fs \ $(SLOFBRDDIR)/rtas-nvram.fs \ $(SLOFBRDDIR)/virtio-net.fs \ @@ -114,6 +120,7 @@ OF_FFS_FILES = \ $(SLOFBRDDIR)/default-font.bin \ $(SLOFBRDDIR)/pci-phb.fs \ $(SLOFBRDDIR)/rtas.fs \ + $(SLOFBRDDIR)/vtpm-sml.fs \ $(SLOFBRDDIR)/pci-device_1234_1111.fs \ $(SLOFBRDDIR)/pci-device_1013_00b8.fs \ $(SLOFBRDDIR)/pci-device_8086_100e.fs \ diff --git a/board-qemu/slof/tree.fs b/board-qemu/slof/tree.fs index d95fde3..39dc6f6 100644 --- a/board-qemu/slof/tree.fs +++ b/board-qemu/slof/tree.fs @@ -87,6 +87,9 @@ include fbuffer.fs 2dup " qemu,spapr-nvram" strequal IF " rtas-nvram.fs" included THEN + 2dup " IBM,vtpm" strequal IF + " vio-vtpm-cdriver.fs" included + THEN 2drop THEN peer diff --git a/board-qemu/slof/vio-vtpm-cdriver.fs b/board-qemu/slof/vio-vtpm-cdriver.fs new file mode 100644 index 0000000..f873456 --- /dev/null +++ b/board-qemu/slof/vio-vtpm-cdriver.fs @@ -0,0 +1,72 @@ +\ ***************************************************************************** +\ * 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 +\ ****************************************************************************/ + +." Populating " pwd + +false VALUE vtpm-debug? +0 VALUE vtpm-unit + +: setup-alias + " ibm,vtpm" find-alias 0= IF + " ibm,vtpm" get-node node>path set-alias + ELSE + drop + THEN +; + +: vtpm-cleanup ( ) + vtpm-debug? IF ." VTPM: Disabling RTAS bypass" cr THEN + tpm-finalize + vtpm-unit 0 rtas-set-tce-bypass +; + +: vtpm-init ( -- true | false ) + 0 0 get-node open-node ?dup 0= IF EXIT THEN + my-self >r + dup to my-self + + vtpm-debug? IF ." VTPM: Initializing for c-driver" cr THEN + + my-unit to vtpm-unit + + \ Enable TCE bypass special qemu feature + vtpm-unit 1 rtas-set-tce-bypass + + \ Have TCE bypass cleaned up + ['] vtpm-cleanup add-quiesce-xt + + tpm-start dup 0= IF + vtpm-debug? IF ." VTPM: Success from tpm-start" cr THEN + drop + setup-alias + ELSE + ." VTPM: Error code from tpm-start: " . cr + THEN + + close-node + r> to my-self +; + +: open ( ) + vtpm-debug? IF ." VTPM: vTPM open()" cr THEN + true +; + +: close ( ) + vtpm-debug? IF ." VTPM: vTPM close()" cr THEN +; + +\ setup alias and the RTAS bypass +vtpm-init + +\ setup the log +include vtpm-sml.fs diff --git a/board-qemu/slof/vtpm-sml.fs b/board-qemu/slof/vtpm-sml.fs new file mode 100644 index 0000000..7cd3729 --- /dev/null +++ b/board-qemu/slof/vtpm-sml.fs @@ -0,0 +1,62 @@ +\ ***************************************************************************** +\ * 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 +\ ****************************************************************************/ + +\ KVM/qemu TPM Stored Measurement Log (SML) entries in /ibm,vtpm + +" /" find-device + +new-device + +false VALUE vtpm-debug? +0 VALUE log-base +40000 CONSTANT LOG-SIZE \ 256k per VTPM FW spec. + +LOG-SIZE BUFFER: log-base + +\ create /ibm,vtpm +s" ibm,vtpm" 2dup device-name device-type + +: sml-get-allocated-size ( -- buffer-size) + vtpm-debug? IF + ." Call to sml-get-allocated-size; size = 0x" LOG-SIZE . cr + THEN + LOG-SIZE +; + +: sml-handover ( dest size -- ) + vtpm-debug? IF + 2dup + ." Call to sml-handover; size = 0x" . ." dest = " . cr + THEN + log-base ( dest size src ) + -rot ( src dest size ) + move +; + +\ +\ internal API calls +\ + +: unassert-physical-presence ( -- ) + tpm-unassert-physical-presence ( errcode ) + dup 0<> IF + ." VTPM: Error code from tpm-unassert-physical-presence: " . cr + ELSE + drop + THEN +; + +: open true ; +: close ; + +finish-device +device-end diff --git a/lib/Makefile b/lib/Makefile index 1e8bb62..7369894 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -11,7 +11,7 @@ # ****************************************************************************/ SUBDIRS = libc libipmi libbootmsg libbases libnvram libelf libhvcall libvirtio \ - libusb libveth libe1k libbcm libnet libbootmenu + libusb libveth libe1k libbcm libnet libbootmenu libtpm all: subdirs diff --git a/lib/libtpm/Makefile b/lib/libtpm/Makefile index ff19e1c..012fe37 100644 --- a/lib/libtpm/Makefile +++ b/lib/libtpm/Makefile @@ -23,7 +23,7 @@ TARGET = ../libtpm.a all: $(TARGET) -SRCS = tpm_drivers.c +SRCS = tpm_drivers.c tcgbios.c OBJS = $(SRCS:%.c=%.o) diff --git a/lib/libtpm/tcgbios.c b/lib/libtpm/tcgbios.c new file mode 100644 index 0000000..5b12461 --- /dev/null +++ b/lib/libtpm/tcgbios.c @@ -0,0 +1,271 @@ + +/***************************************************************************** + * 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 + *****************************************************************************/ + +/* + * Implementation of the TPM BIOS extension according to the specification + * described in the IBM VTPM Firmware document and the TCG Specification + * that can be found here under the following link: + * http://www.trustedcomputinggroup.org/resources/pc_client_work_group_specific_implementation_specification_for_conventional_bios + */ + +#include "types.h" +#include "byteorder.h" +#include "tpm_drivers.h" +#include "string.h" +#include "tcgbios.h" +#include "tcgbios_int.h" +#include "stdio.h" + +#undef TCGBIOS_DEBUG +//#define TCGBIOS_DEBUG +#ifdef TCGBIOS_DEBUG +#define dprintf(_x ...) do { printf("TCGBIOS: " _x); } while(0) +#else +#define dprintf(_x ...) +#endif + +struct tpm_state { + unsigned tpm_probed:1; + unsigned tpm_found:1; + unsigned tpm_working:1; + unsigned has_physical_presence:1; +}; + +static struct tpm_state tpm_state; + +/******************************************************** + Extensions for TCG-enabled BIOS + *******************************************************/ + +static void probe_tpm(void) +{ + tpm_state.tpm_probed = true; + tpm_state.tpm_found = spapr_is_vtpm_present(); + tpm_state.tpm_working = tpm_state.tpm_found; +} + +/**************************************************************** + * TPM hardware command wrappers + ****************************************************************/ + +/* Helper function for sending TPM commands that take a single + * optional parameter (0, 1, or 2 bytes) and have no special response. + */ +static int +tpm_simple_cmd(uint8_t locty, uint32_t ordinal, int param_size, uint16_t param, + enum tpm_duration_type to_t) +{ + struct { + struct tpm_req_header trqh; + uint16_t param; + } __attribute__((packed)) req = { + .trqh.totlen = cpu_to_be32(sizeof(req.trqh) + param_size), + .trqh.tag = cpu_to_be16(TPM_TAG_RQU_CMD), + .trqh.ordinal = cpu_to_be32(ordinal), + }; + uint8_t obuffer[64]; + struct tpm_rsp_header *trsh = (void *)obuffer; + uint32_t obuffer_len = sizeof(obuffer); + int ret; + + switch (param_size) { + case 2: + req.param = cpu_to_be16(param); + break; + case 1: + *(uint8_t *)&req.param = param; + break; + } + + memset(obuffer, 0, sizeof(obuffer)); + ret = tpmhw_transmit(locty, &req.trqh, obuffer, &obuffer_len, to_t); + ret = ret ? -1 : be32_to_cpu(trsh->errcode); + dprintf("Return from tpm_simple_cmd(%x, %x) = %x\n", + ordinal, param, ret); + + return ret; +} + +static int tpm12_get_capability(uint32_t cap, uint32_t subcap, + struct tpm_rsp_header *rsp, uint32_t rsize) +{ + struct tpm_req_getcap trgc = { + .hdr.tag = cpu_to_be16(TPM_TAG_RQU_CMD), + .hdr.totlen = cpu_to_be32(sizeof(trgc)), + .hdr.ordinal = cpu_to_be32(TPM_ORD_GET_CAPABILITY), + .capArea = cpu_to_be32(cap), + .subCapSize = cpu_to_be32(sizeof(trgc.subCap)), + .subCap = cpu_to_be32(subcap) + }; + uint32_t resp_size = rsize; + int ret = tpmhw_transmit(0, &trgc.hdr, rsp, &resp_size, + TPM_DURATION_TYPE_SHORT); + ret = (ret || resp_size != rsize) ? -1 : be32_to_cpu(rsp->errcode); + dprintf("TCGBIOS: Return code from TPM_GetCapability(%d, %d) = %x\n", + cap, subcap, ret); + return ret; +} + +static int tpm12_read_permanent_flags(char *buf, size_t buf_len) +{ + struct tpm_rsp_getcap_perm_flags pf; + int ret; + + memset(buf, 0, buf_len); + ret = tpm12_get_capability(TPM_CAP_FLAG, TPM_CAP_FLAG_PERMANENT, + &pf.hdr, sizeof(pf)); + if (ret) + return -1; + + memcpy(buf, &pf.perm_flags, buf_len); + + return 0; +} + +static int tpm12_determine_timeouts(void) +{ + struct tpm_rsp_getcap_durations durations; + int i; + int ret = tpm12_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_DURATION, + &durations.hdr, sizeof(durations)); + + if (ret) + return ret; + + for (i = 0; i < TPM_NUM_DURATIONS; i++) + durations.durations[i] = be32_to_cpu(durations.durations[i]); + + dprintf("durations: %u %u %u\n", + durations.durations[0], + durations.durations[1], + durations.durations[2]); + + spapr_vtpm_set_durations(durations.durations); + + return 0; +} + +/**************************************************************** + * Setup and Measurements + ****************************************************************/ + +static bool tpm_is_working(void) +{ + if (!tpm_state.tpm_probed) + probe_tpm(); + + return tpm_state.tpm_working; +} + +static void tpm_set_failure(void) +{ + /* we will try to deactivate the TPM now - ignoring all errors */ + tpm_simple_cmd(0, TPM_ORD_SET_TEMP_DEACTIVATED, + 0, 0, TPM_DURATION_TYPE_SHORT); + + tpm_state.tpm_working = false; +} + +static int tpm12_assert_physical_presence(void) +{ + struct tpm_permanent_flags pf; + int ret = tpm_simple_cmd(0, TPM_ORD_PHYSICAL_PRESENCE, + 2, TPM_PP_PRESENT, TPM_DURATION_TYPE_SHORT); + if (!ret) + return 0; + + ret = tpm12_read_permanent_flags((char *)&pf, sizeof(pf)); + if (ret) + return -1; + + /* check if hardware physical presence is supported */ + if (pf.flags[PERM_FLAG_IDX_PHYSICAL_PRESENCE_HW_ENABLE]) { + /* HW. phys. presence may not be asserted ... */ + return 0; + } + + if (!pf.flags[PERM_FLAG_IDX_PHYSICAL_PRESENCE_LIFETIME_LOCK] + && !pf.flags[PERM_FLAG_IDX_PHYSICAL_PRESENCE_CMD_ENABLE]) { + tpm_simple_cmd(0, TPM_ORD_PHYSICAL_PRESENCE, + 2, TPM_PP_CMD_ENABLE, TPM_DURATION_TYPE_SHORT); + return tpm_simple_cmd(0, TPM_ORD_PHYSICAL_PRESENCE, + 2, TPM_PP_PRESENT, + TPM_DURATION_TYPE_SHORT); + } + return -1; +} + +static int tpm12_startup(void) +{ + dprintf("Starting with TPM_Startup(ST_CLEAR)\n"); + int ret = tpm_simple_cmd(0, TPM_ORD_STARTUP, + 2, TPM_ST_CLEAR, TPM_DURATION_TYPE_SHORT); + if (ret) + goto err_exit; + + /* asssertion of physical presence is only possible after startup */ + ret = tpm12_assert_physical_presence(); + if (!ret) + tpm_state.has_physical_presence = true; + + ret = tpm12_determine_timeouts(); + if (ret) + goto err_exit; + + ret = tpm_simple_cmd(0, TPM_ORD_SELF_TEST_FULL, + 0, 0, TPM_DURATION_TYPE_LONG); + if (ret) + goto err_exit; + + return 0; + +err_exit: + dprintf("TPM malfunctioning (line %d).\n", __LINE__); + + tpm_set_failure(); + return -1; +} + +uint32_t tpm_start(void) +{ + tpm_state.has_physical_presence = false; + + probe_tpm(); + + if (!tpm_is_working()) { + dprintf("%s: Machine does not have a working TPM\n", + __func__); + return TCGBIOS_FATAL_COM_ERROR; + } + + return tpm12_startup(); +} + +void tpm_finalize(void) +{ + spapr_vtpm_finalize(); +} + +/* + * Give up physical presence; this function has to be called before + * the firmware transitions to the boot loader. + */ +uint32_t tpm_unassert_physical_presence(void) +{ + if (tpm_state.has_physical_presence) + tpm_simple_cmd(0, TPM_ORD_PHYSICAL_PRESENCE, + 2, TPM_PP_NOT_PRESENT_LOCK, + TPM_DURATION_TYPE_SHORT); + + return 0; +} diff --git a/lib/libtpm/tcgbios.h b/lib/libtpm/tcgbios.h new file mode 100644 index 0000000..5b5e481 --- /dev/null +++ b/lib/libtpm/tcgbios.h @@ -0,0 +1,22 @@ +/***************************************************************************** + * 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 TCGBIOS_H +#define TCGBIOS_H + +#include + +uint32_t tpm_start(void); +void tpm_finalize(void); +uint32_t tpm_unassert_physical_presence(void); + +#endif /* TCGBIOS_H */ diff --git a/lib/libtpm/tcgbios_int.h b/lib/libtpm/tcgbios_int.h new file mode 100644 index 0000000..11f91a7 --- /dev/null +++ b/lib/libtpm/tcgbios_int.h @@ -0,0 +1,153 @@ +/***************************************************************************** + * 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 TCGBIOS_INT_H +#define TCGBIOS_INT_H + +#include + +#include "tpm_drivers.h" + +/* internal error codes */ +#define TCGBIOS_OK 0x0 +#define TCGBIOS_LOGOVERFLOW 0x1 +#define TCGBIOS_GENERAL_ERROR 0x2 +#define TCGBIOS_FIRMWARE_ERROR 0x3 +#define TCGBIOS_FATAL_COM_ERROR 0x4 +#define TCGBIOS_INVALID_INPUT_PARA 0x5 +#define TCGBIOS_COMMAND_ERROR 0x6 +#define TCGBIOS_INTERFACE_SHUTDOWN 0x7 + +#define TPM_ORD_SELF_TEST_FULL 0x00000050 +#define TPM_ORD_FORCE_CLEAR 0x0000005d +#define TPM_ORD_GET_CAPABILITY 0x00000065 +#define TPM_ORD_PHYSICAL_ENABLE 0x0000006f +#define TPM_ORD_PHYSICAL_DISABLE 0x00000070 +#define TPM_ORD_SET_OWNER_INSTALL 0x00000071 +#define TPM_ORD_PHYSICAL_SET_DEACTIVATED 0x00000072 +#define TPM_ORD_SET_TEMP_DEACTIVATED 0x00000073 +#define TPM_ORD_STARTUP 0x00000099 +#define TPM_ORD_PHYSICAL_PRESENCE 0x4000000a +#define TPM_ORD_EXTEND 0x00000014 + +#define TPM_ST_CLEAR 0x1 +#define TPM_ST_STATE 0x2 +#define TPM_ST_DEACTIVATED 0x3 + +#define TPM_PP_CMD_ENABLE 0x0020 +#define TPM_PP_PRESENT 0x0008 +#define TPM_PP_NOT_PRESENT_LOCK 0x0014 + +#define TPM_TAG_RQU_CMD 0x00c1 + +/* TPM command error codes */ +#define TPM_INVALID_POSTINIT 0x26 + +/* event types */ +#define EV_POST_CODE 1 +#define EV_SEPARATOR 4 +#define EV_ACTION 5 +#define EV_EVENT_TAG 6 +#define EV_IPL 13 +#define EV_IPL_PARTITION_DATA 14 + +#define SHA1_BUFSIZE 20 + +/* Input and Output blocks for the TCG BIOS commands */ + +/* PCClient_PCREventStruct -- format of log entries; compatible with x86 */ +struct pcpes { + uint32_t pcrindex; + uint32_t eventtype; + uint8_t digest[SHA1_BUFSIZE]; + uint32_t eventdatasize; + uint32_t event; +} __attribute__((packed)); + +struct tpm_req_header { + uint16_t tag; + uint32_t totlen; + uint32_t ordinal; +} __attribute__((packed)); + +#define TPM_REQ_HEADER_SIZE (sizeof(struct tpm_req_header)) + +struct tpm_rsp_header { + uint16_t tag; + uint32_t totlen; + uint32_t errcode; +} __attribute__((packed)); + +#define TPM_RSP_HEADER_SIZE (sizeof(struct tpm_rsp_header)) + +struct tpm_req_extend { + struct tpm_req_header hdr; + uint32_t pcrindex; + uint8_t digest[SHA1_BUFSIZE]; +} __attribute__((packed)); + +struct tpm_rsp_extend { + struct tpm_rsp_header hdr; + uint8_t digest[SHA1_BUFSIZE]; +} __attribute__((packed)); + +struct tpm_req_getcap { + struct tpm_req_header hdr; + uint32_t capArea; + uint32_t subCapSize; + uint32_t subCap; +} __attribute__((packed)); + +#define TPM_CAP_FLAG 0x04 +#define TPM_CAP_PROPERTY 0x05 +#define TPM_CAP_FLAG_PERMANENT 0x108 +#define TPM_CAP_PROP_DURATION 0x120 + +struct tpm_req_getcap_perm_flags { + struct tpm_req_header hdr; + uint32_t cap_area; + uint32_t sub_cap_zize; + uint32_t sub_cap; +} __attribute__((packed)); + +struct tpm_permanent_flags { + uint16_t tag; + uint8_t flags[20]; +} __attribute__((packed)); + +#define PERM_FLAG_IDX_DISABLE 0 +#define PERM_FLAG_IDX_OWNERSHIP 1 +#define PERM_FLAG_IDX_DEACTIVATED 2 +#define PERM_FLAG_IDX_DISABLEOWNERCLEAR 4 +#define PERM_FLAG_IDX_PHYSICAL_PRESENCE_LIFETIME_LOCK 6 +#define PERM_FLAG_IDX_PHYSICAL_PRESENCE_HW_ENABLE 7 +#define PERM_FLAG_IDX_PHYSICAL_PRESENCE_CMD_ENABLE 8 + +struct tpm_rsp_getcap_perm_flags { + struct tpm_rsp_header hdr; + uint32_t size; + struct tpm_permanent_flags perm_flags; +} __attribute__((packed)); + +struct tpm_rsp_getcap_ownerauth { + struct tpm_rsp_header hdr; + uint32_t size; + uint8_t flag; +} __attribute__((packed)); + +struct tpm_rsp_getcap_durations { + struct tpm_rsp_header hdr; + uint32_t size; + uint32_t durations[TPM_NUM_DURATIONS]; +} __attribute__((packed)); + +#endif /* TCGBIOS_INT_H */ diff --git a/lib/libtpm/tpm.code b/lib/libtpm/tpm.code new file mode 100644 index 0000000..08f52e9 --- /dev/null +++ b/lib/libtpm/tpm.code @@ -0,0 +1,46 @@ +/****************************************************************************** + * 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 + *****************************************************************************/ +/* + * libtpm bindings for SLOF - implementation + */ + +#include + + +/************************************************/ +/* Startup TPM code */ +/* SLOF: tpm-start ( -- errcode ) */ +/* LIBTPM: tpm_start(void) */ +/************************************************/ +PRIM(tpm_X2d_start) + PUSH; + TOS.n = tpm_start(); +MIRP + +/************************************************/ +/* Shutdown TPM layer before OS takes over */ +/* SLOF: tpm-finalize ( -- ) */ +/* LIBTPM: tpm_finalize(void) */ +/************************************************/ +PRIM(tpm_X2d_finalize) + tpm_finalize(); +MIRP + +/***************************************************************/ +/* Prepare TPM state for bootloader */ +/* SLOF: tpm-unassert-physical-presence ( -- errcode ) */ +/* LIBTPM: tpm_unassert_physical-presence(void) */ +/***************************************************************/ +PRIM(tpm_X2d_unassert_X2d_physical_X2d_presence) + PUSH; + TOS.n = tpm_unassert_physical_presence(); +MIRP diff --git a/lib/libtpm/tpm.in b/lib/libtpm/tpm.in new file mode 100644 index 0000000..e212483 --- /dev/null +++ b/lib/libtpm/tpm.in @@ -0,0 +1,18 @@ +/****************************************************************************** + * 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 + *****************************************************************************/ +/* + * libtpm bindings for SLOF - definitions + */ + +cod(tpm-start) +cod(tpm-finalize) +cod(tpm-unassert-physical-presence) diff --git a/lib/libtpm/tpm_drivers.c b/lib/libtpm/tpm_drivers.c index 19e988d..7b1c9c8 100644 --- a/lib/libtpm/tpm_drivers.c +++ b/lib/libtpm/tpm_drivers.c @@ -20,6 +20,7 @@ #include "tpm_drivers.h" #include "libhvcall.h" #include "paflof.h" +#include "tcgbios_int.h" #undef PAPR_VTPM_DEBUG //#define PAPR_VTPM_DEBUG @@ -476,3 +477,15 @@ bool spapr_is_vtpm_present(void) return rc; } + +int tpmhw_transmit(uint8_t locty, struct tpm_req_header *req, + void *respbuffer, uint32_t *respbufferlen, + enum tpm_duration_type to_t) +{ + if (!spapr_vtpm_senddata((uint8_t *)req, be32_to_cpu(req->totlen)) || + !spapr_vtpm_waitresponseready(to_t) || + !spapr_vtpm_readresponse(respbuffer, respbufferlen) || + *respbufferlen < sizeof(struct tpm_rsp_header)) + return -1; + return 0; +} diff --git a/lib/libtpm/tpm_drivers.h b/lib/libtpm/tpm_drivers.h index 5d19514..ab2e152 100644 --- a/lib/libtpm/tpm_drivers.h +++ b/lib/libtpm/tpm_drivers.h @@ -78,4 +78,9 @@ uint32_t spapr_vtpm_get_buffersize(void); vtpm_drv_state spapr_vtpm_get_state(void); vtpm_drv_error spapr_vtpm_get_error(void); +struct tpm_req_header; +int tpmhw_transmit(uint8_t locty, struct tpm_req_header *req, + void *respbuffer, uint32_t *respbufferlen, + enum tpm_duration_type to_t); + #endif /* TPM_DRIVERS_H */ diff --git a/slof/fs/start-up.fs b/slof/fs/start-up.fs index 7020f5c..0715357 100644 --- a/slof/fs/start-up.fs +++ b/slof/fs/start-up.fs @@ -56,6 +56,13 @@ ; : (boot?) ( -- ) + \ last step before we boot we give up physical presence on the TPM + s" /ibm,vtpm" find-node dup IF + s" unassert-physical-presence" rot $call-static + ELSE + drop + THEN + of-prompt? not auto-boot? and IF (boot) THEN