security/vboot: Add support for GSCVD (Google "RO verification")

This patch adds a new CONFIG_VBOOT_GSCVD option that will be enabled by
default for TPM_GOOGLE_TI50 devices. It makes the build system run the
`futility gscvd` command to create a GSCVD (GSC verification data) which
signs the CBFS trust anchor (bootblock and GBB). In order for this to
work, boards will need to have an RO_GSCVD section in their FMAP, and
production boards should override the CONFIG_VBOOT_GSC_BOARD_ID option
with the correct ID for each variant.

BUG=b:229015103

Signed-off-by: Julius Werner <jwerner@chromium.org>
Change-Id: I1cf86e90b2687e81edadcefa5a8826b02fbc8b24
Reviewed-on: https://review.coreboot.org/c/coreboot/+/64707
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Yu-Ping Wu <yupingso@google.com>
diff --git a/src/mainboard/google/brya/Kconfig b/src/mainboard/google/brya/Kconfig
index 9066a09..4ab0e29 100644
--- a/src/mainboard/google/brya/Kconfig
+++ b/src/mainboard/google/brya/Kconfig
@@ -244,6 +244,10 @@
 	select VBOOT_EARLY_EC_SYNC if !BOARD_GOOGLE_BASEBOARD_NISSA
 	select VBOOT_LID_SWITCH
 
+config VBOOT_GSC_BOARD_ID
+	string
+	default "LBTV" if BOARD_GOOGLE_JOXER
+
 config DIMM_SPD_SIZE
 	default 512
 
diff --git a/src/mainboard/google/skyrim/Kconfig b/src/mainboard/google/skyrim/Kconfig
index 5da562a..50068e7 100644
--- a/src/mainboard/google/skyrim/Kconfig
+++ b/src/mainboard/google/skyrim/Kconfig
@@ -78,6 +78,11 @@
 	select VBOOT_SEPARATE_VERSTAGE
 	select VBOOT_STARTS_IN_BOOTBLOCK
 
+# TODO: Remove once CBFS verification on AMD has been fixed.
+config VBOOT_GSCVD
+	bool
+	default n
+
 if !EM100	# EM100 defaults in soc/amd/common/blocks/spi/Kconfig
 config EFS_SPI_READ_MODE
 	default 2          # Dual IO (1-1-2)
diff --git a/src/mainboard/google/volteer/Kconfig b/src/mainboard/google/volteer/Kconfig
index 682d247..8947cd8 100644
--- a/src/mainboard/google/volteer/Kconfig
+++ b/src/mainboard/google/volteer/Kconfig
@@ -135,6 +135,10 @@
 	select VBOOT_EARLY_EC_SYNC
 	select VBOOT_LID_SWITCH
 
+config VBOOT_GSCVD
+	bool
+	default n
+
 config CHROMEOS_WIFI_SAR
 	bool "Enable SAR options for Chrome OS build"
 	depends on CHROMEOS
diff --git a/src/security/vboot/Kconfig b/src/security/vboot/Kconfig
index 3e29c7e..04770c9 100644
--- a/src/security/vboot/Kconfig
+++ b/src/security/vboot/Kconfig
@@ -290,6 +290,37 @@
 	  config will only define the counter space. Counters need to be incremented
 	  separately before any read operation is performed on them.
 
+config VBOOT_HASH_BLOCK_SIZE
+	hex
+	default 0x400
+	help
+	  Set the default hash size.  Generally 1k is reasonable, but in some
+	  cases it may improve hashing speed to increase the size.
+
+	  Note that this buffer is allocated in the stack.  Although the
+	  build should fail if the stack size is exceeded, it's something to
+	  be aware of when changing the size.
+
+config VBOOT_GSCVD
+	bool "Generate GSC verification data"
+	depends on TPM_GOOGLE
+	select CBFS_VERIFICATION
+	default n if TPM_GOOGLE_CR50
+	default y
+	help
+	  Generate a Google Security Chip Verification Data (GSCVD) structure on the flash to
+	  allow the GSC to verify the CBFS verification anchor. Used by default with Ti50 GSCs.
+	  Requires an RO_GSCVD FMAP section.
+
+config VBOOT_GSC_BOARD_ID
+	string
+	depends on VBOOT_GSCVD
+	default "ZZCR"
+	help
+	  GSC board ID to be embedded in the GSCVD. Usually each specific mainboard variant
+	  has its own. Google engineers can find these in the go/cros-dlm database ("Products").
+	  (Note: This is a completely separate thing from coreboot's `board_id()` function.)
+
 menu "GBB configuration"
 
 config GBB_HWID
@@ -400,16 +431,21 @@
 	hex "Keyblock preamble flags"
 	default 0x0
 
-config VBOOT_HASH_BLOCK_SIZE
-	hex
-	default 0x400
-	help
-	  Set the default hash size.  Generally 1k is reasonable, but in some
-	  cases it may improve hashing speed to increase the size.
+if VBOOT_GSCVD
 
-	  Note that this buffer is allocated in the stack.  Although the
-	  build should fail if the stack size is exceeded, it's something to
-	  be aware of when changing the size.
+config VBOOT_GSCVD_ROOT_PUBKEY
+	string "GSCVD root key (public)"
+	default "\$(VBOOT_SOURCE)/tests/devkeys/arv_root.vbpubk"
+
+config VBOOT_GSCVD_PLATFORM_PRIVKEY
+	string "GSCVD platform key (private)"
+	default "\$(VBOOT_SOURCE)/tests/devkeys/arv_platform.vbprivk"
+
+config VBOOT_GSCVD_PLATFORM_KEYBLOCK
+	string "GSCVD platform keyblock (public)"
+	default "\$(VBOOT_SOURCE)/tests/devkeys/arv_platform.keyblock"
+
+endif # VBOOT_GSCVD
 
 endmenu # Keys
 endif # VBOOT
diff --git a/src/security/vboot/Makefile.inc b/src/security/vboot/Makefile.inc
index 2ea5d30..52f374e 100644
--- a/src/security/vboot/Makefile.inc
+++ b/src/security/vboot/Makefile.inc
@@ -294,6 +294,61 @@
 	$(CBFSTOOL) $(obj)/coreboot.rom write -u -r SHARED_DATA -i 0 -f $(obj)/shared_data.region
 endif
 
+fmap-section-offset-cmd = $(FUTILITY) dump_fmap -p $(obj)/coreboot.rom | \
+					grep '^$(1) ' | cut '-d ' -f2
+
+ifeq ($(CONFIG_VBOOT_GSCVD),y)
+#
+# vboot-gscvd-ranges
+#
+# This variable expands to the list of ranges that will be verified by the GSC
+# before releasing the SoC from reset. It needs to cover all security-relevant
+# ranges of the flash that CBFS verification cannot cover itself. By default
+# this is the `GBB` FMAP section (not handled here but through the special `-G`
+# parameter to `futility gscvd` below) and the bootblock. Here we are
+# initializing the variable to expansions that produce ranges for both the
+# `BOOTBLOCK` FMAP section (filled up to the real size of
+# `$(objcbfs)/bootblock.bin`) and the `bootblock` file in the primary CBFS --
+# only one of those two should normally exist on a given platform.
+#
+# Platforms where the bootblock isn't the first and only thing loaded by the
+# hardware or which otherwise have special security-relevant flash areas that
+# cannot be covered normally by CBFS verification will need to manually add
+# ranges to this variable in their own Makefiles, in the format produced by
+# printf("%x:%x", start_offset, size). The variable is only expanded once in a
+# recipe of the `files_added` target, so $(shell) expansions that depend on
+# inspecting $(obj)/coreboot.rom (or any of its dependencies) are valid.
+#
+vboot-gscvd-ranges += $(shell ( \
+	offset=$$($(call fmap-section-offset-cmd,BOOTBLOCK)) ;\
+	if [ -n "$$offset" ]; then \
+		size=$$(wc -c < $(objcbfs)/bootblock.bin) ;\
+		printf "%x:%x" $$offset $$size ;\
+	fi ;\
+))
+vboot-gscvd-ranges += $(shell ( \
+	line=$$($(CBFSTOOL) $(obj)/coreboot.rom print -k | grep '^bootblock[[:space:]]') ;\
+	if [ -n "$$line" ]; then \
+		cbfs_start=$$($(call fmap-section-offset-cmd,COREBOOT)) ;\
+		offset=$$(printf "$$line" | cut -f2) ;\
+		size=$$(printf "$$line" | cut -f6) ;\
+		printf "%x:%x" $$((cbfs_start + offset)) $$size ;\
+	fi ;\
+))
+files_added:: $(FUTILITY)
+	@printf "    WRITE GSCVD\n"
+	gscvd_range_args="$(foreach range,$(vboot-gscvd-ranges),-R $(range))" ;\
+	if [ -z "$$gscvd_range_args" ]; then \
+		echo "ERROR: No valid GSCVD ranges detected in image!" ;\
+		exit 1 ;\
+	fi ;\
+	$(FUTILITY) gscvd -G $$gscvd_range_args -b $(CONFIG_VBOOT_GSC_BOARD_ID) \
+		-r "$(CONFIG_VBOOT_GSCVD_ROOT_PUBKEY)" \
+		-p "$(CONFIG_VBOOT_GSCVD_PLATFORM_PRIVKEY)" \
+		-k "$(CONFIG_VBOOT_GSCVD_PLATFORM_KEYBLOCK)" \
+		$(obj)/coreboot.rom
+endif
+
 # Extract FW_MAIN_? region and minimize it if the last file is empty, so it
 # doesn't contain this empty file (that can have a significant size),
 # improving a lot on hash times due to a smaller amount of data loaded from