From: Vladimir Serbinenko Date: Sun, 10 Jan 2016 12:48:26 +0000 (+0100) Subject: Add wbinvd around bios call. X-Git-Tag: 2.02-beta3~33 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=25492a0f047cb7a6583ae195568599c296a604d6;p=thirdparty%2Fgrub.git Add wbinvd around bios call. Via C3 has problems with cache coherency when transitioning between the modes, so flush it around bios calls. --- 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. */