mb/emulation/qemu: Copy page tables to DRAM in assembly

To work around various bugs running KVM enabled, copy page tables to
DRAM in assembly before jumping to x86_64 mode.

Tested on QEMU using KVM, no more stange bugs happen:
Tested on host
 - CPU Intel(R) Core(TM) i7-7700HQ
 - Linux 5.9
 - qemu 4.2.1
 Used to crash on emulating MMX instructions and failed to translate
 some addresses using the virtual MMU when running in long mode.

Tested on host
 - CPU AMD EPYC 7401P 24-Core Processor
 - Linux 5.4
 - qemu 4.2.1
 Used to crash on jumping to long mode.

Change-Id: Ic0bdd2bef7197edd2e7488a8efdeba7eb4ab0dd4
Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/49228
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
diff --git a/src/mainboard/emulation/qemu-q35/Kconfig b/src/mainboard/emulation/qemu-q35/Kconfig
index edd2b2c..d88d0da 100644
--- a/src/mainboard/emulation/qemu-q35/Kconfig
+++ b/src/mainboard/emulation/qemu-q35/Kconfig
@@ -32,6 +32,15 @@
 	default "src/mainboard/\$(CONFIG_MAINBOARD_DIR)/vboot-rwa-16M.fmd" if VBOOT_SLOTS_RW_A && !VBOOT_SLOTS_RW_AB
 	default "src/mainboard/\$(CONFIG_MAINBOARD_DIR)/vboot-rwab-16M.fmd" if VBOOT_SLOTS_RW_AB
 
+if ARCH_BOOTBLOCK_X86_64
+# Need to install page tables in DRAM as the virtual MMU has problems translating paging
+# request when the page table resides in emulated ROM. This causes undefined behaviour
+# when handling data requests, as well as fetching and decoding instructions
+# Real hardware didn't show any problems until now.
+config ARCH_X86_64_PGTBL_LOC
+	default 0x8000
+endif
+
 if VBOOT
 
 config VBOOT_SLOTS_RW_A
diff --git a/src/mainboard/emulation/qemu-q35/mainboard.c b/src/mainboard/emulation/qemu-q35/mainboard.c
index d329e5a..c88874f 100644
--- a/src/mainboard/emulation/qemu-q35/mainboard.c
+++ b/src/mainboard/emulation/qemu-q35/mainboard.c
@@ -44,6 +44,12 @@
 	/* reserve mmconfig */
 	fixed_mem_resource(dev, 2, CONFIG_MMCONF_BASE_ADDRESS >> 10, 0x10000000 >> 10,
 			   IORESOURCE_RESERVE);
+
+	if (CONFIG(ARCH_RAMSTAGE_X86_64)) {
+		/* Reserve page tables in DRAM. FIXME: Remove once x86_64 page tables reside in CBMEM */
+		reserved_ram_resource(dev, 0, CONFIG_ARCH_X86_64_PGTBL_LOC / KiB,
+			(6 * 0x1000) / KiB);
+	}
 }