From 3e89a76fee8edfbeb3d069f7d2f04df7fa34ecc3 Mon Sep 17 00:00:00 2001 From: Vladimir Serbinenko Date: Sun, 10 Jan 2016 13:48:26 +0100 Subject: [PATCH] Add wbinvd around bios call. Via C3 has problems with cache coherency when transitioning between the modes, so flush it around bios calls. --- grub-core/kern/i386/int.S | 11 +++++++++++ grub-core/kern/i386/pc/init.c | 24 ++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/grub-core/kern/i386/int.S b/grub-core/kern/i386/int.S index 7edace404..862a54202 100644 --- a/grub-core/kern/i386/int.S +++ b/grub-core/kern/i386/int.S @@ -44,6 +44,13 @@ FUNCTION(grub_bios_interrupt) movl 24(%edx), %esi movl 28(%edx), %edx + /* + Via C3 CPUs have cache coherence problems, so we need to call + wbinvd at these 2 points. As wbinvd slows down boot, don't do + it on non-VIA. 9090 is nop nop. */ +VARIABLE(grub_bios_via_workaround1) + .byte 0x90, 0x90 + PROT_TO_REAL .code16 pushf @@ -92,6 +99,10 @@ intno: movw %ax, LOCAL(bios_register_es) popf + +VARIABLE(grub_bios_via_workaround2) + .byte 0x90, 0x90 + REAL_TO_PROT .code32 diff --git a/grub-core/kern/i386/pc/init.c b/grub-core/kern/i386/pc/init.c index 3c8160aab..27bc68b8a 100644 --- a/grub-core/kern/i386/pc/init.c +++ b/grub-core/kern/i386/pc/init.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -184,6 +185,26 @@ mmap_iterate_hook (grub_uint64_t addr, grub_uint64_t size, return 0; } +extern grub_uint16_t grub_bios_via_workaround1, grub_bios_via_workaround2; + +/* Via needs additional wbinvd. */ +static void +grub_via_workaround_init (void) +{ + grub_uint32_t manufacturer[3], max_cpuid; + if (! grub_cpu_is_cpuid_supported ()) + return; + + grub_cpuid (0, max_cpuid, manufacturer[0], manufacturer[2], manufacturer[1]); + + if (grub_memcmp (manufacturer, "CentaurHauls", 12) != 0) + return; + + grub_bios_via_workaround1 = 0x090f; + grub_bios_via_workaround2 = 0x090f; + asm volatile ("wbinvd"); +} + void grub_machine_init (void) { @@ -193,6 +214,9 @@ grub_machine_init (void) #endif grub_addr_t modend; + /* This has to happen before any BIOS calls. */ + grub_via_workaround_init (); + grub_modbase = GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR + (_edata - _start); /* Initialize the console as early as possible. */ -- 2.47.2