]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Add wbinvd around bios call.
authorVladimir Serbinenko <phcoder@gmail.com>
Sun, 10 Jan 2016 12:48:26 +0000 (13:48 +0100)
committerroot <root@localhost>
Sun, 14 Feb 2016 07:34:10 +0000 (08:34 +0100)
Via C3 has problems with cache coherency when transitioning between the modes,
so flush it around bios calls.

grub-core/kern/i386/int.S
grub-core/kern/i386/pc/init.c

index 7edace4045ce5eaa1e76ae5337be4300f09804fe..862a5420268ea1f38e751ece0349b8183ca41057 100644 (file)
@@ -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
 
index 3c8160aab13050844177449b4dbb3826441c2131..27bc68b8a534ec0cea794f9e0584b58ac0acdfce 100644 (file)
@@ -32,6 +32,7 @@
 #include <grub/env.h>
 #include <grub/cache.h>
 #include <grub/time.h>
+#include <grub/cpu/cpuid.h>
 #include <grub/cpu/tsc.h>
 #include <grub/machine/time.h>
 
@@ -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.  */