104 lines
2.9 KiB
Diff
104 lines
2.9 KiB
Diff
From 8d52adac75a53452e6b1e6ed527b90b7cbaac7a6 Mon Sep 17 00:00:00 2001
|
|
From: Laszlo Ersek <lersek@redhat.com>
|
|
Date: Fri, 10 Oct 2014 11:11:09 +0200
|
|
Subject: [PATCH 131/192] calibrate_tsc(): use the Stall() EFI boot service on
|
|
GRUB_MACHINE_EFI
|
|
|
|
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1150698
|
|
|
|
HyperV Gen2 virtual machines have no PIT; guest code should rely on UEFI
|
|
services instead.
|
|
|
|
Signed-off-by: RHEL Ninjas <example@example.com>
|
|
---
|
|
grub-core/kern/i386/tsc.c | 59 +++++++++++++++++++++++++++++++++++++++++++++--
|
|
1 file changed, 57 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/grub-core/kern/i386/tsc.c b/grub-core/kern/i386/tsc.c
|
|
index 2e85289d8..0787b6f3e 100644
|
|
--- a/grub-core/kern/i386/tsc.c
|
|
+++ b/grub-core/kern/i386/tsc.c
|
|
@@ -24,6 +24,17 @@
|
|
#include <grub/misc.h>
|
|
#include <grub/i386/tsc.h>
|
|
#include <grub/i386/cpuid.h>
|
|
+#ifdef GRUB_MACHINE_XEN
|
|
+# include <grub/xen.h>
|
|
+#else
|
|
+# ifdef GRUB_MACHINE_EFI
|
|
+# include <grub/efi/efi.h>
|
|
+# include <grub/efi/api.h>
|
|
+# else
|
|
+# include <grub/i386/pit.h>
|
|
+# endif
|
|
+#endif
|
|
+#include <grub/cpu/io.h>
|
|
|
|
/* This defines the value TSC had at the epoch (that is, when we calibrated it). */
|
|
static grub_uint64_t tsc_boot_time;
|
|
@@ -33,6 +44,44 @@ static grub_uint64_t tsc_boot_time;
|
|
in 32-bit. */
|
|
grub_uint32_t grub_tsc_rate;
|
|
|
|
+#ifndef GRUB_MACHINE_XEN
|
|
+
|
|
+static void
|
|
+grub_stall (grub_uint16_t tics)
|
|
+{
|
|
+# ifdef GRUB_MACHINE_EFI
|
|
+ grub_uint64_t microseconds;
|
|
+
|
|
+ microseconds = (grub_uint64_t)tics * 1000 * 1000 * 3 / 3579545;
|
|
+ efi_call_1 (grub_efi_system_table->boot_services->stall, microseconds);
|
|
+# else
|
|
+ /* Disable timer2 gate and speaker. */
|
|
+ grub_outb (grub_inb (GRUB_PIT_SPEAKER_PORT)
|
|
+ & ~ (GRUB_PIT_SPK_DATA | GRUB_PIT_SPK_TMR2),
|
|
+ GRUB_PIT_SPEAKER_PORT);
|
|
+
|
|
+ /* Set tics. */
|
|
+ grub_outb (GRUB_PIT_CTRL_SELECT_2 | GRUB_PIT_CTRL_READLOAD_WORD,
|
|
+ GRUB_PIT_CTRL);
|
|
+ grub_outb (tics & 0xff, GRUB_PIT_COUNTER_2);
|
|
+ grub_outb (tics >> 8, GRUB_PIT_COUNTER_2);
|
|
+
|
|
+ /* Enable timer2 gate, keep speaker disabled. */
|
|
+ grub_outb ((grub_inb (GRUB_PIT_SPEAKER_PORT) & ~ GRUB_PIT_SPK_DATA)
|
|
+ | GRUB_PIT_SPK_TMR2,
|
|
+ GRUB_PIT_SPEAKER_PORT);
|
|
+
|
|
+ /* Wait. */
|
|
+ while ((grub_inb (GRUB_PIT_SPEAKER_PORT) & GRUB_PIT_SPK_TMR2_LATCH) == 0x00);
|
|
+
|
|
+ /* Disable timer2 gate and speaker. */
|
|
+ grub_outb (grub_inb (GRUB_PIT_SPEAKER_PORT)
|
|
+ & ~ (GRUB_PIT_SPK_DATA | GRUB_PIT_SPK_TMR2),
|
|
+ GRUB_PIT_SPEAKER_PORT);
|
|
+# endif
|
|
+}
|
|
+#endif
|
|
+
|
|
static grub_uint64_t
|
|
grub_tsc_get_time_ms (void)
|
|
{
|
|
@@ -46,8 +95,14 @@ grub_tsc_get_time_ms (void)
|
|
static int
|
|
calibrate_tsc_hardcode (void)
|
|
{
|
|
- grub_tsc_rate = 5368;/* 800 MHz */
|
|
- return 1;
|
|
+ /* First calibrate the TSC rate (relative, not absolute time). */
|
|
+ grub_uint64_t end_tsc;
|
|
+
|
|
+ tsc_boot_time = grub_get_tsc ();
|
|
+ grub_stall (0xffff);
|
|
+ end_tsc = grub_get_tsc ();
|
|
+
|
|
+ grub_tsc_rate = grub_divmod64 ((55ULL << 32), end_tsc - tsc_boot_time, 0);
|
|
}
|
|
|
|
void
|
|
--
|
|
2.13.4
|
|
|