arch/x86: restore forwarding table on resume for EARLY_EBDA_INIT

In commit c06a3f72 (arch/x86: initialize EBDA in S3 and S0/S5 path)
the BDA and EBDA are wiped in the resume path. However, the coreboot
table forwarding entry wasn't taken into account so that was wiped
which resulted in cbmem not working on the resume path. Fix this
by stashing the forwarding table in cbmem and restoring it on
the resume path.

Change-Id: I142503535a78635fbb1c698fc7d032c1a2921813
Signed-off-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: https://review.coreboot.org/22078
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Matt DeVillier <matt.devillier@gmail.com>
Reviewed-by: Furquan Shaikh <furquan@google.com>
diff --git a/src/arch/x86/tables.c b/src/arch/x86/tables.c
index 7b06550..fc5870d 100644
--- a/src/arch/x86/tables.c
+++ b/src/arch/x86/tables.c
@@ -18,6 +18,7 @@
 #include <console/console.h>
 #include <cpu/cpu.h>
 #include <bootmem.h>
+#include <bootstate.h>
 #include <boot/tables.h>
 #include <boot/coreboot_tables.h>
 #include <arch/pirq_routing.h>
@@ -194,7 +195,45 @@
  * in case our data structures grow beyond 0x400. Only GDT
  * and the coreboot table use low_tables.
  */
-static uintptr_t forwarding_table = 0x500;
+#define FORWARDING_TABLE_ADDR ((uintptr_t)0x500)
+static uintptr_t forwarding_table = FORWARDING_TABLE_ADDR;
+
+/*
+ * For EARLY_EBDA_INIT the BDA area will be wiped on the resume path which
+ * has the forwarding table entry. Therefore, when tables are written an
+ * entry is placed in cbmem that can be restored on OS resume to the proper
+ * location.
+ */
+static void stash_forwarding_table(uintptr_t addr, size_t sz)
+{
+	void *cbmem_addr = cbmem_add(CBMEM_ID_CBTABLE_FWD, sz);
+
+	if (cbmem_addr == NULL) {
+		printk(BIOS_ERR, "Unable to allocate CBMEM forwarding entry.\n");
+		return;
+	}
+
+	memcpy(cbmem_addr, (void *)addr, sz);
+}
+
+#if IS_ENABLED(CONFIG_EARLY_EBDA_INIT)
+static void restore_forwarding_table(void *dest)
+{
+	const struct cbmem_entry *fwd_entry;
+
+	fwd_entry = cbmem_entry_find(CBMEM_ID_CBTABLE_FWD);
+
+	if (fwd_entry == NULL) {
+		printk(BIOS_ERR, "Unable to restore CBMEM forwarding entry.\n");
+		return;
+	}
+
+	memcpy(dest, cbmem_entry_start(fwd_entry), cbmem_entry_size(fwd_entry));
+}
+
+BOOT_STATE_INIT_ENTRY(BS_OS_RESUME, BS_ON_ENTRY,
+	restore_forwarding_table, (void *)FORWARDING_TABLE_ADDR);
+#endif
 
 void arch_write_tables(uintptr_t coreboot_table)
 {
@@ -217,6 +256,9 @@
 
 	sz = write_coreboot_forwarding_table(forwarding_table, coreboot_table);
 
+	if (IS_ENABLED(CONFIG_EARLY_EBDA_INIT))
+		stash_forwarding_table(forwarding_table, sz);
+
 	forwarding_table += sz;
 	/* Align up to page boundary for historical consistency. */
 	forwarding_table = ALIGN_UP(forwarding_table, 4*KiB);
diff --git a/src/commonlib/include/commonlib/cbmem_id.h b/src/commonlib/include/commonlib/cbmem_id.h
index 2c9b3c3..2595655 100644
--- a/src/commonlib/include/commonlib/cbmem_id.h
+++ b/src/commonlib/include/commonlib/cbmem_id.h
@@ -25,6 +25,7 @@
 #define CBMEM_ID_AMDMCT_MEMINFO 0x494D454E
 #define CBMEM_ID_CAR_GLOBALS	0xcac4e6a3
 #define CBMEM_ID_CBTABLE	0x43425442
+#define CBMEM_ID_CBTABLE_FWD	0x43425443
 #define CBMEM_ID_CONSOLE	0x434f4e53
 #define CBMEM_ID_COVERAGE	0x47434f56
 #define CBMEM_ID_EHCI_DEBUG	0xe4c1deb9
@@ -80,6 +81,7 @@
 	{ CBMEM_ID_AMDMCT_MEMINFO,	"AMDMEM INFO" }, \
 	{ CBMEM_ID_CAR_GLOBALS,		"CAR GLOBALS" }, \
 	{ CBMEM_ID_CBTABLE,		"COREBOOT   " }, \
+	{ CBMEM_ID_CBTABLE_FWD,		"COREBOOTFWD" }, \
 	{ CBMEM_ID_CONSOLE,		"CONSOLE    " }, \
 	{ CBMEM_ID_COVERAGE,		"COVERAGE   " }, \
 	{ CBMEM_ID_EHCI_DEBUG,		"USBDEBUG   " }, \