soc/amd/picasso: add psp_verstage

This is the main code for building coreboot's verstage as a userspace
application to run on the PSP.  It does a minimal setup of hardware,
then runs verstage_main.  It uses hardware hashing to increase the speed
and will directly reboot into recovery mode if there are any failures.

BUG=b:158124527
TEST=Build & boot trembyle

Signed-off-by: Martin Roth <martin@coreboot.org>
Change-Id: Ia58839caa5bfbae0408702ee8d02ef482f2861c4
Reviewed-on: https://review.coreboot.org/c/coreboot/+/41816
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Raul Rangel <rrangel@chromium.org>
diff --git a/src/soc/amd/picasso/psp_verstage/vboot_crypto.c b/src/soc/amd/picasso/psp_verstage/vboot_crypto.c
new file mode 100644
index 0000000..c010eb6
--- /dev/null
+++ b/src/soc/amd/picasso/psp_verstage/vboot_crypto.c
@@ -0,0 +1,104 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <2crypto.h>
+#include <2return_codes.h>
+#include <bl_uapp/bl_syscall_public.h>
+#include <commonlib/bsd/helpers.h>
+#include <console/console.h>
+#include "psp_verstage.h"
+#include <stddef.h>
+#include <string.h>
+#include <vb2_api.h>
+
+static struct SHA_GENERIC_DATA_T sha_op;
+static uint32_t sha_op_size_remaining;
+static uint8_t __attribute__((aligned(32))) sha_hash[64];
+
+vb2_error_t vb2ex_hwcrypto_digest_init(enum vb2_hash_algorithm hash_alg, uint32_t data_size)
+{
+	printk(BIOS_DEBUG, "Calculating hash of %d bytes\n", data_size);
+
+	sha_op_size_remaining = data_size;
+
+	if (hash_alg == VB2_HASH_SHA256) {
+		sha_op.SHAType = SHA_TYPE_256;
+		sha_op.DigestLen = 32;
+	} else if (hash_alg == VB2_HASH_SHA512) {
+		sha_op.SHAType = SHA_TYPE_512;
+		sha_op.DigestLen = 64;
+	} else {
+		printk(BIOS_INFO, "Unsupported hash_alg %d!\n", hash_alg);
+		return VB2_ERROR_EX_HWCRYPTO_UNSUPPORTED;
+	}
+
+	/* Set init flag for first operation */
+	sha_op.Init = 1;
+
+	/* Clear eom flag until last operation */
+	sha_op.Eom = 0;
+
+	/* Need documentation on this b:157610147 */
+	sha_op.DataMemType = 2;
+
+	sha_op.Digest = sha_hash;
+
+	sha_op.IntermediateDigest = NULL;
+
+	sha_op.IntermediateMsgLen = 0;
+
+	return VB2_SUCCESS;
+}
+
+vb2_error_t vb2ex_hwcrypto_digest_extend(const uint8_t *buf, uint32_t size)
+{
+	uint32_t retval;
+	sha_op.Data = (uint8_t *) buf;
+
+	if (!sha_op_size_remaining) {
+		printk(BIOS_ERR, "ERROR: got more data than expected.\n");
+		return VB2_ERROR_UNKNOWN;
+	}
+
+	while (size) {
+		sha_op.DataLen = size;
+
+		sha_op_size_remaining -= sha_op.DataLen;
+
+		/* Set eom flag for final operation */
+		if (sha_op_size_remaining == 0)
+			sha_op.Eom = 1;
+
+		retval = svc_crypto_sha(&sha_op, SHA_GENERIC);
+		if (retval) {
+			printk(BIOS_ERR, "ERROR: HW crypto failed - errorcode: %#x\n",
+					retval);
+			return VB2_ERROR_UNKNOWN;
+		}
+
+		/* Clear init flag after first operation */
+		if (sha_op.Init == 1)
+			sha_op.Init = 0;
+
+		size -= sha_op.DataLen;
+	}
+
+	return VB2_SUCCESS;
+}
+
+/* Copy the hash back to verstage */
+vb2_error_t vb2ex_hwcrypto_digest_finalize(uint8_t *digest, uint32_t digest_size)
+{
+	if (sha_op.Eom == 0) {
+		printk(BIOS_ERR, "ERROR: Got less data than expected.\n");
+		return VB2_ERROR_UNKNOWN;
+	}
+
+	if (digest_size != sha_op.DigestLen) {
+		printk(BIOS_ERR, "ERROR: Digest size does not match expected length.\n");
+		return VB2_ERROR_UNKNOWN;
+	}
+
+	memcpy(digest, sha_hash, digest_size);
+
+	return VB2_SUCCESS;
+}