security/tpm/tss/tcg-2.0: Add TPM2 function tlcl_getcapability()

Add function tlcl_getcapability() to return TPM2 capability.
To support TPM2 capability TPM_CAP_PCRS handling is added to
unmarshal_get_capability().

BUG=N/A
TEST=Build binary and verified logging on Facebook FBG-1701

Change-Id: I85e1bd2822aa6e7fd95ff2b9faa25cf183e6de37
Signed-off-by: Frans Hendriks <fhendriks@eltan.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/30826
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Julius Werner <jwerner@chromium.org>
diff --git a/src/security/tpm/tss.h b/src/security/tpm/tss.h
index 548a39a..30e2a7b 100644
--- a/src/security/tpm/tss.h
+++ b/src/security/tpm/tss.h
@@ -1,4 +1,5 @@
 /* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Copyright (C) 2018-2019 Eltan B.V.
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
@@ -66,6 +67,13 @@
 			   const uint8_t *nv_policy, size_t nv_policy_size);
 
 /*
+ * Issue TPM2_GetCapability command
+ */
+uint32_t tlcl_get_capability(TPM_CAP capability, uint32_t property,
+			     uint32_t property_count,
+			     TPMS_CAPABILITY_DATA *capability_data);
+
+/*
  * Makes tpm_process_command available for on top implementations of
  * custom tpm standards like cr50
  */
diff --git a/src/security/tpm/tss/tcg-2.0/tss.c b/src/security/tpm/tss/tcg-2.0/tss.c
index c4b5538..08a7caa 100644
--- a/src/security/tpm/tss/tcg-2.0/tss.c
+++ b/src/security/tpm/tss/tcg-2.0/tss.c
@@ -1,5 +1,6 @@
 /*
  * Copyright 2016 The Chromium OS Authors. All rights reserved.
+ * Copyright 2017-2019 Eltan B.V.
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
@@ -366,3 +367,31 @@
 
 	return TPM_SUCCESS;
 }
+
+uint32_t tlcl_get_capability(TPM_CAP capability, uint32_t property,
+		uint32_t property_count,
+		TPMS_CAPABILITY_DATA *capability_data)
+{
+	struct tpm2_get_capability cmd;
+	struct tpm2_response *response;
+
+	cmd.capability = capability;
+	cmd.property = property;
+	cmd.propertyCount = property_count;
+
+	if (property_count > 1) {
+		printk(BIOS_ERR, "%s: property_count more than one not "
+		       "supported yet\n", __func__);
+		return TPM_E_IOERROR;
+	}
+
+	response = tpm_process_command(TPM2_GetCapability, &cmd);
+
+	if (!response) {
+		printk(BIOS_ERR, "%s: Command Failed\n", __func__);
+		return TPM_E_IOERROR;
+	}
+
+	memcpy(capability_data, &response->gc.cd, sizeof(TPMS_CAPABILITY_DATA));
+	return TPM_SUCCESS;
+}
diff --git a/src/security/tpm/tss/tcg-2.0/tss_marshaling.c b/src/security/tpm/tss/tcg-2.0/tss_marshaling.c
index 21da73a..345aec5 100644
--- a/src/security/tpm/tss/tcg-2.0/tss_marshaling.c
+++ b/src/security/tpm/tss/tcg-2.0/tss_marshaling.c
@@ -1,5 +1,6 @@
 /*
  * Copyright 2016 The Chromium OS Authors. All rights reserved.
+ * Copyright (c) 2018 Eltan B.V.
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
@@ -12,6 +13,7 @@
 
 #include "tss_marshaling.h"
 #include <security/tpm/tss/vendor/cr50/cr50.h>
+#include <security/tpm/tss.h>
 
 static uint16_t tpm_tag CAR_GLOBAL;  /* Depends on the command type. */
 
@@ -421,6 +423,22 @@
 			rc |= ibuf_read_be32(ib, &pp->value);
 		}
 		break;
+	case TPM_CAP_PCRS:
+		if (ibuf_read_be32(ib, &gcr->cd.data.assignedPCR.count))
+			return -1;
+		if (gcr->cd.data.assignedPCR.count >
+		    ARRAY_SIZE(gcr->cd.data.assignedPCR.pcrSelections)) {
+			printk(BIOS_INFO, "%s:%s:%d - %d - too many properties\n",
+			       __FILE__, __func__, __LINE__,
+			      gcr->cd.data.assignedPCR.count);
+			return -1;
+		}
+		for (i = 0; i < gcr->cd.data.assignedPCR.count; i++) {
+			TPMS_PCR_SELECTION *pp =
+				&gcr->cd.data.assignedPCR.pcrSelections[i];
+			rc |= ibuf_read(ib, pp, sizeof(TPMS_PCR_SELECTION));
+		}
+		break;
 	default:
 		printk(BIOS_ERR,
 		       "%s:%d - unable to unmarshal capability response",
diff --git a/src/security/tpm/tss/tcg-2.0/tss_structures.h b/src/security/tpm/tss/tcg-2.0/tss_structures.h
index 991cbcf..7332739 100644
--- a/src/security/tpm/tss/tcg-2.0/tss_structures.h
+++ b/src/security/tpm/tss/tcg-2.0/tss_structures.h
@@ -22,6 +22,8 @@
 #define TPM2_RC_SUCCESS    0
 #define TPM2_RC_NV_DEFINED 0x14c
 
+#define HASH_COUNT 2 /* SHA-1 and SHA-256 are supported */
+
 /* Basic TPM2 types. */
 typedef uint16_t TPM_SU;
 typedef uint16_t TPM_ALG_ID;
@@ -144,7 +146,9 @@
 };
 
 /* Various TPM capability types to use when querying the device. */
+/* Table 21 - TPM_CAP Constants */
 typedef uint32_t TPM_CAP;
+#define TPM_CAP_PCRS             ((TPM_CAP)0x00000005)
 #define TPM_CAP_TPM_PROPERTIES   ((TPM_CAP)0x00000006)
 
 typedef TPM_HANDLE TPMI_RH_NV_AUTH;
@@ -224,9 +228,29 @@
 		      sizeof(TPMI_YES_NO) - sizeof(TPM_CAP) - sizeof(uint32_t))
 #define MAX_TPM_PROPERTIES  (MAX_CAP_DATA/sizeof(TPMS_TAGGED_PROPERTY))
 
+#define IMPLEMENTATION_PCR            24
+#define PLATFORM_PCR                  24
+
+#define PCR_SELECT_MIN                (ALIGN_UP(PLATFORM_PCR, 8)/8)
+#define PCR_SELECT_MAX                (ALIGN_UP(IMPLEMENTATION_PCR, 8)/8)
+
 /* Somewhat arbitrary, leave enough room for command wrappers. */
 #define MAX_NV_BUFFER_SIZE (TPM_BUFFER_SIZE - sizeof(struct tpm_header) - 50)
 
+/* Table 81 - TPMS_PCR_SELECTION Structure */
+typedef struct {
+	TPMI_ALG_HASH   hash;
+	uint8_t         sizeofSelect;
+	uint8_t         pcrSelect[PCR_SELECT_MAX];
+} __packed TPMS_PCR_SELECTION;
+
+/* Table 98 - TPML_PCR_SELECTION Structure */
+typedef struct {
+	uint32_t           count;
+	TPMS_PCR_SELECTION pcrSelections[HASH_COUNT];
+} __packed TPML_PCR_SELECTION;
+
+/* Table 100 - TPML_TAGGED_TPM_PROPERTY Structure */
 typedef struct {
 	uint32_t              count;
 	TPMS_TAGGED_PROPERTY  tpmProperty[MAX_TPM_PROPERTIES];
@@ -234,6 +258,7 @@
 
 typedef union {
 	TPML_TAGGED_TPM_PROPERTY  tpmProperties;
+	TPML_PCR_SELECTION        assignedPCR;
 } TPMU_CAPABILITIES;
 
 typedef struct {