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>
This commit is contained in:
Patrick Rudolph
2021-01-07 14:12:38 +01:00
committed by Patrick Georgi
parent cbfe4ba76a
commit 82e111cc2a
6 changed files with 91 additions and 2 deletions

View File

@@ -2,6 +2,7 @@
bootblock-y += cache_as_ram_bootblock.S
bootblock-y += bootblock.c
bootblock-$(CONFIG_ARCH_BOOTBLOCK_X86_64) += $(top)/src/arch/x86/walkcbfs.S
romstage-y += ../intel/car/romstage.c

View File

@@ -2,7 +2,14 @@
#include <cpu/x86/post_code.h>
#define CBFS_FILE_MAGIC 0
#define CBFS_FILE_LEN (CBFS_FILE_MAGIC + 8)
#define CBFS_FILE_TYPE (CBFS_FILE_LEN + 4)
#define CBFS_FILE_CHECKSUM (CBFS_FILE_TYPE + 4)
#define CBFS_FILE_OFFSET (CBFS_FILE_CHECKSUM + 4)
.section .init, "ax", @progbits
.code32
.global bootblock_pre_c_entry
bootblock_pre_c_entry:
@@ -24,12 +31,55 @@ cache_as_ram:
post_code(0x21)
#if defined(__x86_64__)
/*
* Copy page tables to final location in DRAM. This prevents some strange
* bugs when running KVM enabled:
* Accessing MMX instructions in long mode causes an abort
* Some physical addresses aren't properly translated
* Emulation fault on every instruction fetched due to page tables in ROM
* Enabling or disabling paging causes a fault
*
* First, find page tables in CBFS:
*/
lea pagetables_name, %esi
mov $1f, %esp
jmp walkcbfs_asm
1:
cmpl $0, %eax
je .Lhlt
/* Test if page tables are memory-mapped and skip relocation */
cmpl $(CONFIG_ARCH_X86_64_PGTBL_LOC), %eax
je pages_done
movl CBFS_FILE_OFFSET(%eax), %ebx
bswap %ebx
addl %eax, %ebx
movl %ebx, %esi
movl CBFS_FILE_LEN(%eax), %ecx
bswap %ecx
shr $2, %ecx
movl $(CONFIG_ARCH_X86_64_PGTBL_LOC), %edi
loop:
movl (%esi), %eax
movl %eax, (%edi)
addl $4, %esi
addl $4, %edi
decl %ecx
jnz loop
pages_done:
#endif
movl $_ecar_stack, %esp
/* Align the stack and keep aligned for call to bootblock_c_entry() */
and $0xfffffff0, %esp
/* entry64.inc preserves ebx. */
/* entry64.inc preserves ebx. */
#include <cpu/x86/64bit/entry64.inc>
/* Restore the BIST result and timestamps. */
@@ -60,3 +110,6 @@ before_c_entry:
post_code(POST_DEAD_CODE)
hlt
jmp .Lhlt
pagetables_name:
.string "pagetables"