security/tpm: Retrieve factory configuration for device w/ Google TPM

This patch enables retrieval of factory configuration data from
Google TPM devices (both Cr50 and Ti50).

This patch utilizes vendor-specific command
TPM2_CR50_SUB_CMD_GET_FACTORY_CONFIG (68).

The factory config space is a 64-bit, one-time programmable.
For the unprovisioned one, the read will be 0x0.

BUG=b:317880956
TEST=Able to retrieve the factory config from google/screebo.

Change-Id: Ifd0e850770152a03aa46d7f8bbb76f7520a59081
Signed-off-by: Subrata Banik <subratabanik@google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/79736
Reviewed-by: Kapil Porwal <kapilporwal@google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
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 f1b9522..5ade639 100644
--- a/src/security/tpm/tss/tcg-2.0/tss_marshaling.c
+++ b/src/security/tpm/tss/tcg-2.0/tss_marshaling.c
@@ -348,6 +348,9 @@
 	case TPM2_CR50_SUB_CMD_RESET_EC:
 		rc |= obuf_write_be16(ob, *sub_command);
 		break;
+	case TPM2_CR50_SUB_CMD_GET_FACTORY_CONFIG:
+		rc |= obuf_write_be16(ob, *sub_command);
+		break;
 	default:
 		/* Unsupported subcommand. */
 		printk(BIOS_WARNING, "Unsupported cr50 subcommand: 0x%04x\n",
@@ -581,6 +584,8 @@
 		return ibuf_read_be8(ib, &vcr->boot_mode);
 	case TPM2_CR50_SUB_CMD_RESET_EC:
 		break;
+	case TPM2_CR50_SUB_CMD_GET_FACTORY_CONFIG:
+		return ibuf_read_be64(ib, &vcr->factory_config);
 	default:
 		printk(BIOS_ERR,
 		       "%s:%d - unsupported vendor command %#04x!\n",
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 a73f4c4..f2682b1 100644
--- a/src/security/tpm/tss/tcg-2.0/tss_structures.h
+++ b/src/security/tpm/tss/tcg-2.0/tss_structures.h
@@ -352,6 +352,11 @@
 		uint8_t recovery_button_state;
 		uint8_t tpm_mode;
 		uint8_t boot_mode;
+		/*
+		 * bits 63..8 : reserved
+		 * bits 7..0 : factory config
+		 */
+		uint64_t factory_config;
 	};
 };
 
diff --git a/src/security/tpm/tss/vendor/cr50/cr50.c b/src/security/tpm/tss/vendor/cr50/cr50.c
index 87889d1..31eab2d 100644
--- a/src/security/tpm/tss/vendor/cr50/cr50.c
+++ b/src/security/tpm/tss/vendor/cr50/cr50.c
@@ -176,3 +176,31 @@
 
 	return TPM_SUCCESS;
 }
+
+tpm_result_t tlcl_cr50_get_factory_config(uint64_t *factory_config)
+{
+	struct tpm2_response *response;
+	uint16_t factory_config_command = TPM2_CR50_SUB_CMD_GET_FACTORY_CONFIG;
+	*factory_config = 0;
+
+	response = tpm_process_command(TPM2_CR50_VENDOR_COMMAND, &factory_config_command);
+
+	if (!response)
+		return TPM_IOERROR;
+
+	/* Explicitly inform caller when command is not supported */
+	if (response->hdr.tpm_code == VENDOR_RC_NO_SUCH_COMMAND ||
+	    response->hdr.tpm_code == VENDOR_RC_NO_SUCH_SUBCOMMAND)
+		return TPM_CB_NO_SUCH_COMMAND;
+
+	/* Unexpected return code from TPM */
+	if (response->hdr.tpm_code)
+		return TPM_IOERROR;
+
+	/* TPM command completed without error */
+	*factory_config = response->vcr.factory_config;
+
+	printk(BIOS_INFO, "Reading factory config = %016" PRIX64 "\n", *factory_config);
+
+	return TPM_SUCCESS;
+}
diff --git a/src/security/tpm/tss/vendor/cr50/cr50.h b/src/security/tpm/tss/vendor/cr50/cr50.h
index edd5083..f7e5c68 100644
--- a/src/security/tpm/tss/vendor/cr50/cr50.h
+++ b/src/security/tpm/tss/vendor/cr50/cr50.h
@@ -17,6 +17,7 @@
 #define TPM2_CR50_SUB_CMD_TPM_MODE (40)
 #define TPM2_CR50_SUB_CMD_GET_BOOT_MODE (52)
 #define TPM2_CR50_SUB_CMD_RESET_EC (53)
+#define TPM2_CR50_SUB_CMD_GET_FACTORY_CONFIG (68)
 
 /* Cr50 vendor-specific error codes. */
 #define VENDOR_RC_ERR              0x00000500
@@ -105,4 +106,12 @@
  */
 tpm_result_t tlcl_cr50_reset_ec(void);
 
+/**
+ * TPM command to get the factory config.
+ *
+ * Returns TPM_* for errors.
+ * On Success, TPM_SUCCESS if factory config is successfully retrieved.
+ */
+tpm_result_t tlcl_cr50_get_factory_config(uint64_t *factory_config);
+
 #endif /* CR50_TSS_STRUCTURES_H_ */