Add VbExGetLocalizationCount

VbExGetLocalizationCount is a callback function which is supposed to
return the number of screen locales supported by VbExDisplayScreen.

After this change, we still try to get the number of locales from GBB
first but when it fails, VbExGetLocalizationCount is called. The error
code from VbGbbReadBmpHeader will be masked, similarly to the error from
VbDislayScreenFromGBB.

BUG=chromium:502066
BRANCH=tot
TEST=Tested on Samus. make runtests

Change-Id: I04ef8bf1ea02b1aaa05e65673b57bcea1932d8b0
Signed-off-by: Daisuke Nojiri <dnojiri@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/304376
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
diff --git a/firmware/include/vboot_api.h b/firmware/include/vboot_api.h
index bc90b19..18ee4cc 100644
--- a/firmware/include/vboot_api.h
+++ b/firmware/include/vboot_api.h
@@ -1078,4 +1078,12 @@
  * @return 0 if no override, 1-15 for override priority.
  */
 uint8_t VbExOverrideGptEntryPriority(const GptEntry *e);
+
+/**
+ * Return number of locales supported
+ *
+ * @param count		Pointer to the number of locales.
+ * @return VBERROR_... error, VBERROR_SUCCESS on success.
+ */
+VbError_t VbExGetLocalizationCount(uint32_t *count);
 #endif  /* VBOOT_REFERENCE_VBOOT_API_H_ */
diff --git a/firmware/lib/vboot_display.c b/firmware/lib/vboot_display.c
index 1a127e2..f8417b9 100644
--- a/firmware/lib/vboot_display.c
+++ b/firmware/lib/vboot_display.c
@@ -20,6 +20,11 @@
 static uint32_t disp_current_screen = VB_SCREEN_BLANK;
 static uint32_t disp_width = 0, disp_height = 0;
 
+__attribute__((weak))
+VbError_t VbExGetLocalizationCount(uint32_t *count) {
+	return VBERROR_UNKNOWN;
+}
+
 VbError_t VbGetLocalizationCount(VbCommonParams *cparams, uint32_t *count)
 {
 	BmpBlockHeader hdr;
@@ -28,12 +33,15 @@
 	/* Default to 0 on error */
 	*count = 0;
 
+	/* First try to get the count from GBB */
 	ret = VbGbbReadBmpHeader(cparams, &hdr);
-	if (ret)
+	if (ret == VBERROR_SUCCESS) {
+		*count = hdr.number_of_localizations;
 		return ret;
+	}
 
-	*count = hdr.number_of_localizations;
-	return VBERROR_SUCCESS;
+	/* If GBB is broken or missing, fallback to the callback */
+	return VbExGetLocalizationCount(count);
 }
 
 /*
diff --git a/tests/vboot_display_tests.c b/tests/vboot_display_tests.c
index 63f6890..6e36f64 100644
--- a/tests/vboot_display_tests.c
+++ b/tests/vboot_display_tests.c
@@ -149,14 +149,14 @@
 	ResetMocks();
 	cparams.gbb->bmpfv_size = 0;
 	TEST_EQ(VbGetLocalizationCount(&cparams, &count),
-		VBERROR_INVALID_GBB, "VbGetLocalizationCount bad gbb");
+		VBERROR_UNKNOWN, "VbGetLocalizationCount bad gbb");
 	TEST_EQ(count, 0, "  count");
 	VbApiKernelFree(&cparams);
 
 	ResetMocks();
 	bhdr->signature[0] ^= 0x5a;
 	TEST_EQ(VbGetLocalizationCount(&cparams, &count),
-		VBERROR_INVALID_BMPFV, "VbGetLocalizationCount bad bmpfv");
+		VBERROR_UNKNOWN, "VbGetLocalizationCount bad bmpfv");
 	VbApiKernelFree(&cparams);
 
 	ResetMocks();