All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC] High resolution time support using x86 TSC
@ 2008-06-23 14:54 Colin D Bennett
  2008-07-03 18:52 ` Marco Gerards
  0 siblings, 1 reply; 24+ messages in thread
From: Colin D Bennett @ 2008-06-23 14:54 UTC (permalink / raw)
  To: The development of GRUB 2


[-- Attachment #1.1: Type: text/plain, Size: 1013 bytes --]

I have implemented high resolution time support (through the
new grub_get_time_ms() function) using the RDTSC instruction available
on Pentium and higher x86 CPUs.  The TSC value is simply a 64-bit block
cycle counter that is zeroed at bootup, so grub_main() calls
grub_time_init(), which is defined by each platform.  If a platform
links to kern/i386/tsc.c, then the grub_time_init() function from tsc.c
is used, which calibrates the TSC rate and absolute zero reference using
the RTC.

I also extracted the grub_millisleep_generic() function into
kern/generic/millisleep.c and renamed it to grub_millisleep() so that
platforms linking to it don't need to define a grub_millisleep() just
to call grub_millisleep_generic() anymore.  Simply linking in
kern/generic/millisleep.c will use the generic implementation.

I have only tested this patch on the i386-pc platform, so if anyone
tests it on another platform and finds problems, please let me know and
I can try to fix it.

Regards,
Colin

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: tsc_2008-06-23.patch --]
[-- Type: text/x-patch; name=tsc_2008-06-23.patch, Size: 20528 bytes --]

=== modified file 'ChangeLog'
--- ChangeLog	2008-06-21 14:21:03 +0000
+++ ChangeLog	2008-06-23 14:40:22 +0000
@@ -1,3 +1,87 @@
+2008-06-22  Colin D Bennett <colin@gibibit.com>
+
+	High resolution timer support.  Implemented for i386 CPU using TSC.
+	Extracted generic grub_millisleep() so it's linked in only as needed.
+
+	* conf/i386-efi.rmk: Added TSC high resolution time module, link with
+	generic grub_millisleep() function.
+
+	* conf/i386-pc.rmk: Likewise.
+
+	* conf/sparc64-ieee1275.rmk: Add kern/generic/millisleep.c and
+	kern/generic/get_time_ms.c to kernel, to use generic time functions.
+
+	* conf/powerpc-ieee1275.rmk: Add kern/generic/millisleep.c to kernel,
+	to use generic grub_millisleep() function.
+
+	* kern/generic/get_time_ms.c (grub_get_time_ms): New file.  Platform
+	independent implementation of grub_get_time_ms() using the RTC that
+	can be linked into a platform's kernel when it does not implement its
+	own specialized grub_get_time_ms() function.
+
+	* kern/generic/millisleep.c (grub_millisleep): New file.  Extracted
+	from grub_millisleep_generic() in kern/misc.c and renamed.  Now it is
+	not included in the kernel when a platform defines a specialized
+	grub_millisleep() implementation.
+
+	* include/grub/i386/tsc.h (grub_get_tsc): New file.  Inline function
+	grub_get_tsc() uses x86 RDTSC instruction (available on Pentium+ CPUs)
+	to read the counter value for the TSC.
+
+	* kern/i386/tsc.c (grub_get_time_ms): x86 TSC support providing a high
+	resolution clock.
+	(grub_tsc_calibrate): Static function to calibrate the TSC using RTC.
+	(grub_time_init): Implemented to call the static grub_tsc_calibrate()
+	function to calibrate the TSC.
+
+	* include/grub/kernel.h (grub_time_init): Add declaration for the
+	grub_time_init() platform specific time initialization function.  This
+	function should be implemented by all platforms.  If kern/i386/tsc.c
+	is linked in, it will provide grub_time_init().
+
+	* include/grub/time.h (grub_get_time_ms): Added grub_get_time_ms()
+	function to return the current time in millseconds since the epoch.
+	This supports higher resolution time than grub_get_rtc() on some
+	platforms such as i386-pc, where the RTC has only about 1/18 s
+	precision but a higher precision timer such as the TSC is available.
+
+	* kern/i386/efi/init.c (grub_millisleep): Don't define
+	grub_millisleep() -- it just called grub_millisleep_generic() but now
+	we just need to link with kern/generic/millisleep.c to use the generic
+	implementation.
+
+	* kern/i386/pc/init.c (grub_millisleep): Likewise.
+
+	* kern/ieee1275/init.c (grub_millisleep): Don't define
+	grub_millisleep() -- it just called grub_millisleep_generic() but now
+	we just need to link with kern/generic/millisleep.c to use the generic
+	implementation.
+	(grub_get_time_ms): Implement this required function.  Simply uses the
+	prior implementation of grub_get_rtc().
+	(grub_get_rtc): Now calls grub_get_time_ms(), which does the real
+	work.
+	(grub_time_init): Define this empty but required function. No further
+	initialization necessary.
+
+	* kern/sparc64/ieee1275/init.c (grub_millisleep): Don't define
+	grub_millisleep(), just link with kern/generic/millisleep.c.
+	(grub_time_init): Define this required function. Does nothing since
+	the generic RTC-based functions are used.
+
+	* kern/i386/linuxbios/init.c (grub_get_time_ms):
+	Define grub_get_time_ms() to always return 0.  This should be fixed
+	when RTC functionality is implemented.
+	(grub_time_init): Define this required function as a no-op. Inserted
+	a comment to remind us delete this function when proper time support 
+	is added to i386-linuxbios.
+
+	* kern/main.c (grub_main): Call grub_time_init() right after
+	grub_machine_init().
+
+	* kern/misc.c (grub_millisleep_generic): Moved to
+	kern/generic/millisleep.c so that it is only included in the kernel
+	image when a platform does not define a specialized version.
+
 2008-06-21  Javier Martín  <lordhabbit@gmail.com>
 
 	* util/i386/pc/grub-setup.c (setup): Remove literal "core.img" in a

=== modified file 'conf/i386-efi.rmk'
--- conf/i386-efi.rmk	2008-06-19 05:14:16 +0000
+++ conf/i386-efi.rmk	2008-06-23 02:29:15 +0000
@@ -84,7 +84,9 @@
 	kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \
 	kern/i386/dl.c kern/i386/efi/init.c kern/parser.c kern/partition.c \
 	kern/env.c symlist.c kern/efi/efi.c kern/efi/init.c kern/efi/mm.c \
-	term/efi/console.c disk/efi/efidisk.c
+	term/efi/console.c disk/efi/efidisk.c \
+	kern/i386/tsc.c \
+	kern/generic/millisleep.c
 kernel_mod_HEADERS = arg.h boot.h cache.h device.h disk.h dl.h elf.h elfload.h \
 	env.h err.h file.h fs.h kernel.h loader.h misc.h mm.h net.h parser.h \
 	partition.h pc_partition.h rescue.h symbol.h term.h time.h types.h \

=== modified file 'conf/i386-pc.rmk'
--- conf/i386-pc.rmk	2008-06-19 05:14:16 +0000
+++ conf/i386-pc.rmk	2008-06-23 02:29:15 +0000
@@ -43,6 +43,8 @@
 	kern/disk.c kern/dl.c kern/file.c kern/fs.c kern/err.c \
 	kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \
 	kern/i386/dl.c kern/i386/pc/init.c kern/parser.c kern/partition.c \
+	kern/i386/tsc.c \
+	kern/generic/millisleep.c \
 	kern/env.c \
 	term/i386/pc/console.c \
 	symlist.c

=== modified file 'conf/powerpc-ieee1275.rmk'
--- conf/powerpc-ieee1275.rmk	2008-06-19 05:14:16 +0000
+++ conf/powerpc-ieee1275.rmk	2008-06-23 14:33:56 +0000
@@ -85,6 +85,7 @@
 	kern/ieee1275/init.c term/ieee1275/ofconsole.c 		\
 	kern/ieee1275/openfw.c disk/ieee1275/ofdisk.c 		\
 	kern/parser.c kern/partition.c kern/env.c kern/powerpc/dl.c 	\
+	kern/generic/millisleep.c                                       \
 	symlist.c kern/powerpc/cache.S
 kernel_elf_HEADERS = grub/powerpc/ieee1275/ieee1275.h
 kernel_elf_CFLAGS = $(COMMON_CFLAGS)

=== modified file 'conf/sparc64-ieee1275.rmk'
--- conf/sparc64-ieee1275.rmk	2008-06-19 01:04:59 +0000
+++ conf/sparc64-ieee1275.rmk	2008-06-23 14:33:56 +0000
@@ -73,6 +73,7 @@
 	kern/rescue.c kern/term.c term/ieee1275/ofconsole.c \
 	kern/sparc64/ieee1275/openfw.c disk/ieee1275/ofdisk.c \
 	kern/partition.c kern/env.c kern/sparc64/dl.c symlist.c \
+	kern/generic/millisleep.c kern/generic/get_time_ms.c \
 	kern/sparc64/cache.S kern/parser.c
 kernel_elf_HEADERS = grub/sparc64/ieee1275/ieee1275.h
 kernel_elf_CFLAGS = $(COMMON_CFLAGS)

=== added file 'include/grub/i386/tsc.h'
--- include/grub/i386/tsc.h	1970-01-01 00:00:00 +0000
+++ include/grub/i386/tsc.h	2008-06-17 20:14:24 +0000
@@ -0,0 +1,41 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef KERNEL_CPU_TSC_HEADER
+#define KERNEL_CPU_TSC_HEADER	1
+
+#include <grub/types.h>
+
+/* Read the TSC value, which increments with each CPU clock cycle. */
+static __inline grub_uint64_t
+grub_get_tsc (void)
+{
+  grub_uint32_t lo, hi;
+
+  /* The CPUID instruction is a 'serializing' instruction, and
+   * avoids out-of-order execution of the RDTSC instruction. */
+  __asm__ __volatile__ ("xorl %%eax, %%eax\n\t"
+                        "cpuid":::"%rax", "%rbx", "%rcx", "%rdx");
+  /* Read TSC value.  We cannot use "=A", since this would use
+   * %rax on x86_64. */
+  __asm__ __volatile__ ("rdtsc":"=a" (lo), "=d" (hi));
+
+  return (((grub_uint64_t) hi) << 32) | lo;
+}
+
+#endif /* ! KERNEL_CPU_TSC_HEADER */

=== modified file 'include/grub/kernel.h'
--- include/grub/kernel.h	2008-01-21 00:04:04 +0000
+++ include/grub/kernel.h	2008-06-17 15:04:05 +0000
@@ -58,6 +58,9 @@
 /* The machine-specific prefix initialization.  */
 void grub_machine_set_prefix (void);
 
+/* The machine-specific time source initialization. */
+void grub_time_init (void);
+
 /* Register all the exported symbols. This is automatically generated.  */
 void grub_register_exported_symbols (void);
 

=== modified file 'include/grub/time.h'
--- include/grub/time.h	2007-10-22 20:02:16 +0000
+++ include/grub/time.h	2008-06-17 20:14:24 +0000
@@ -1,6 +1,6 @@
 /*
  *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 2007  Free Software Foundation, Inc.
+ *  Copyright (C) 2007, 2008  Free Software Foundation, Inc.
  *
  *  GRUB is free software: you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -19,12 +19,13 @@
 #ifndef KERNEL_TIME_HEADER
 #define KERNEL_TIME_HEADER	1
 
+#include <grub/types.h>
 #include <grub/symbol.h>
 #include <grub/machine/time.h>
 #include <grub/cpu/time.h>
 
 void EXPORT_FUNC(grub_millisleep) (grub_uint32_t ms);
-void EXPORT_FUNC(grub_millisleep_generic) (grub_uint32_t ms);
+grub_uint64_t EXPORT_FUNC(grub_get_time_ms) (void);
 
 static __inline void
 grub_sleep (grub_uint32_t s)

=== added directory 'kern/generic'
=== added file 'kern/generic/get_time_ms.c'
--- kern/generic/get_time_ms.c	1970-01-01 00:00:00 +0000
+++ kern/generic/get_time_ms.c	2008-06-17 15:04:05 +0000
@@ -0,0 +1,37 @@
+/* get_time_ms.c - generic time implementation -- using platform RTC.
+ * The generic implementation of these functions can be used for architectures
+ * or platforms that do not have a more specialized implementation. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/time.h>
+#include <grub/misc.h>
+
+/* Calculate the time in milliseconds since the epoch based on the RTC. */
+grub_uint64_t
+grub_get_time_ms (void)
+{
+  /* By dimensional analysis: 
+   *
+   *  1000 ms   N rtc ticks       1 s
+   *  ------- * ----------- * ----------- = 1000*N/T ms
+   *    1 s          1        T rtc ticks
+   */
+  grub_uint64_t ticks_ms_per_sec = ((grub_uint64_t) 1000) * grub_get_rtc ();
+  return grub_divmod64 (ticks_ms_per_sec, GRUB_TICKS_PER_SECOND, 0);
+}

=== added file 'kern/generic/millisleep.c'
--- kern/generic/millisleep.c	1970-01-01 00:00:00 +0000
+++ kern/generic/millisleep.c	2008-06-23 14:33:56 +0000
@@ -0,0 +1,39 @@
+/* millisleep.c - generic millisleep function.
+ * The generic implementation of these functions can be used for architectures
+ * or platforms that do not have a more specialized implementation. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/misc.h>
+#include <grub/time.h>
+
+void
+grub_millisleep (grub_uint32_t ms)
+{
+  /* Note: Perhaps this function should use grub_get_time_ms() instead of
+   * grub_get_rtc()so it can take advantage of high resolution timing
+   * on platforms where it is provided. */
+
+  grub_uint32_t end_at;
+
+  end_at =
+    grub_get_rtc () + grub_div_roundup (ms * GRUB_TICKS_PER_SECOND, 1000);
+
+  while (grub_get_rtc () < end_at)
+    grub_cpu_idle ();
+}

=== modified file 'kern/i386/efi/init.c'
--- kern/i386/efi/init.c	2007-10-22 19:59:33 +0000
+++ kern/i386/efi/init.c	2008-06-17 15:04:05 +0000
@@ -25,13 +25,6 @@
 #include <grub/cache.h>
 #include <grub/kernel.h>
 #include <grub/efi/efi.h>
-#include <grub/time.h>
-
-void
-grub_millisleep (grub_uint32_t ms)
-{
-  grub_millisleep_generic (ms);
-}
 
 void
 grub_machine_init (void)

=== modified file 'kern/i386/linuxbios/init.c'
--- kern/i386/linuxbios/init.c	2008-02-13 20:04:37 +0000
+++ kern/i386/linuxbios/init.c	2008-06-23 14:33:56 +0000
@@ -33,6 +33,7 @@
 #include <grub/time.h>
 #include <grub/symbol.h>
 #include <grub/cpu/io.h>
+#include <grub/cpu/time.h>
 
 #define GRUB_FLOPPY_REG_DIGITAL_OUTPUT		0x3f2
 
@@ -52,6 +53,23 @@
   return grub_time_tics;
 }
 
+grub_uint64_t
+grub_get_time_ms (void)
+{
+  /* FIXME: Delete this function and link to `kern/i386/tsc.c' once RTC
+   * is implemented.  See also comment below in grub_time_init(). */
+  return 0;
+}
+
+void
+grub_time_init (void)
+{
+  /* FIXME: Delete this function and link with `kern/i386/tsc.c' once RTC
+   * is implemented.  Until then, this dummy function simply defines 
+   * grub_time_init(), which is called by grub_main() in `kern/main.c'.
+   * Without RTC, TSC calibration will hang waiting for an RTC edge. */
+}
+
 /* Stop the floppy drive from spinning, so that other software is
    jumped to with a known state.  */
 void

=== modified file 'kern/i386/pc/init.c'
--- kern/i386/pc/init.c	2008-06-15 18:21:16 +0000
+++ kern/i386/pc/init.c	2008-06-17 16:28:36 +0000
@@ -30,6 +30,7 @@
 #include <grub/env.h>
 #include <grub/cache.h>
 #include <grub/time.h>
+#include <grub/cpu/time.h>
 
 struct mem_region
 {
@@ -46,12 +47,6 @@
 grub_size_t grub_os_area_size;
 grub_size_t grub_lower_mem, grub_upper_mem;
 
-void
-grub_millisleep (grub_uint32_t ms)
-{
-  grub_millisleep_generic (ms);
-}
-
 void 
 grub_arch_sync_caches (void *address __attribute__ ((unused)),
 		       grub_size_t len __attribute__ ((unused)))

=== added file 'kern/i386/tsc.c'
--- kern/i386/tsc.c	1970-01-01 00:00:00 +0000
+++ kern/i386/tsc.c	2008-06-17 15:04:05 +0000
@@ -0,0 +1,99 @@
+/* kern/i386/tsc.c - x86 TSC time source implementation
+ * Requires Pentium or better x86 CPU that supports the RDTSC instruction.
+ * This module uses the RTC (via grub_get_rtc()) to calibrate the TSC to 
+ * real time.
+ *
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2007  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/time.h>
+#include <grub/misc.h>
+#include <grub/i386/tsc.h>
+
+/* Reference for TSC=0.  This defines the time since the epoch in 
+ * milliseconds that TSC=0 refers to. */
+static grub_uint64_t tsc_boot_time = 0;
+
+/* TSC rate. TSC ticks per millisecond. 
+ * Begin with default (incorrect) value of assuming a 1 GHz machine.
+ * grub_tsc_calibrate() must be called to set this properly. */
+static grub_uint64_t tsc_ticks_per_ms = 1000000;
+
+
+/* Declared in <grub/time.h>. */
+grub_uint64_t
+grub_get_time_ms (void)
+{
+  return tsc_boot_time + grub_divmod64 (grub_get_tsc (), tsc_ticks_per_ms, 0);
+}
+
+
+/* How many RTC ticks to use for calibration loop. (>= 1) */
+#define CALIBRATION_TICKS 2
+
+/* Called by the machine-specific time initialization function
+ * grub_time_init() below. */
+static void
+grub_tsc_calibrate (void)
+{
+  /* First calbrate the TSC rate (relative, not absolute time). */
+  grub_uint64_t start_tsc;
+  grub_uint64_t end_tsc;
+  grub_uint32_t initial_tick;
+  grub_uint32_t start_tick;
+  grub_uint32_t end_tick;
+
+  /* Wait for the start of the next tick;
+     we'll base out timing off this edge. */
+  initial_tick = grub_get_rtc ();
+  do
+    {
+      start_tick = grub_get_rtc ();
+    }
+  while (start_tick == initial_tick);
+  start_tsc = grub_get_tsc ();
+
+  /* Wait for the start of the next tick.  This will
+     be the end of the 1-tick period. */
+  do
+    {
+      end_tick = grub_get_rtc ();
+    }
+  while (end_tick - start_tick < CALIBRATION_TICKS);
+  end_tsc = grub_get_tsc ();
+
+  tsc_ticks_per_ms =
+    grub_divmod64 (grub_divmod64
+                   (end_tsc - start_tsc, end_tick - start_tick, 0)
+                   * GRUB_TICKS_PER_SECOND, 1000, 0);
+
+  /* Reference the TSC zero (boot time) to the epoch to 
+   * get an absolute real time reference. */
+  grub_uint64_t ms_since_boot = grub_divmod64 (end_tsc, tsc_ticks_per_ms, 0);
+  grub_uint64_t mstime_now = grub_divmod64 ((grub_uint64_t) 1000 * end_tick,
+                                            GRUB_TICKS_PER_SECOND,
+                                            0);
+  tsc_boot_time = mstime_now - ms_since_boot;
+}
+
+/* Implement the machine-specific time initialization function. */
+void
+grub_time_init (void)
+{
+  grub_tsc_calibrate ();
+}

=== modified file 'kern/ieee1275/init.c'
--- kern/ieee1275/init.c	2008-04-25 19:41:48 +0000
+++ kern/ieee1275/init.c	2008-06-17 15:04:05 +0000
@@ -47,12 +47,6 @@
 extern char _end[];
 
 void
-grub_millisleep (grub_uint32_t ms)
-{
-  grub_millisleep_generic (ms);
-}
-
-void
 grub_exit (void)
 {
   grub_ieee1275_exit ();
@@ -257,8 +251,13 @@
   grub_console_fini ();
 }
 
-grub_uint32_t
-grub_get_rtc (void)
+void
+grub_time_init (void)
+{
+}
+
+grub_uint64_t
+grub_get_time_ms (void)
 {
   grub_uint32_t msecs = 0;
 
@@ -267,6 +266,12 @@
   return msecs;
 }
 
+grub_uint32_t
+grub_get_rtc (void)
+{
+  return grub_get_time_ms ();
+}
+
 grub_addr_t
 grub_arch_modules_addr (void)
 {

=== modified file 'kern/main.c'
--- kern/main.c	2008-06-19 20:08:57 +0000
+++ kern/main.c	2008-06-23 02:29:15 +0000
@@ -112,6 +112,7 @@
 {
   /* First of all, initialize the machine.  */
   grub_machine_init ();
+  grub_time_init ();
 
   /* Hello.  */
   grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT);

=== modified file 'kern/misc.c'
--- kern/misc.c	2008-06-16 00:42:48 +0000
+++ kern/misc.c	2008-06-17 16:28:36 +0000
@@ -1018,17 +1018,6 @@
   return p - dest;
 }
 
-void
-grub_millisleep_generic (grub_uint32_t ms)
-{
-  grub_uint32_t end_at;
-
-  end_at = grub_get_rtc () + grub_div_roundup (ms * GRUB_TICKS_PER_SECOND, 1000);
-
-  while (grub_get_rtc () < end_at)
-    grub_cpu_idle ();
-}
-
 /* Abort GRUB. This function does not return.  */
 void
 grub_abort (void)

=== modified file 'kern/sparc64/ieee1275/init.c'
--- kern/sparc64/ieee1275/init.c	2007-10-22 19:59:33 +0000
+++ kern/sparc64/ieee1275/init.c	2008-06-23 14:33:56 +0000
@@ -66,10 +66,10 @@
   /* Never reached.  */
 }
 
+/* Define the required grub_time_init() function. */
 void
-grub_millisleep (grub_uint32_t ms)
+grub_time_init (void)
 {
-  grub_millisleep_generic (ms);
 }
 
 int


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC] High resolution time support using x86 TSC
  2008-06-23 14:54 [RFC] High resolution time support using x86 TSC Colin D Bennett
@ 2008-07-03 18:52 ` Marco Gerards
  2008-07-04 15:58   ` Colin D Bennett
                     ` (2 more replies)
  0 siblings, 3 replies; 24+ messages in thread
From: Marco Gerards @ 2008-07-03 18:52 UTC (permalink / raw)
  To: The development of GRUB 2

Hi Colin,

Colin D Bennett <colin@gibibit.com> writes:

> I have implemented high resolution time support (through the
> new grub_get_time_ms() function) using the RDTSC instruction available
> on Pentium and higher x86 CPUs.  The TSC value is simply a 64-bit block
> cycle counter that is zeroed at bootup, so grub_main() calls
> grub_time_init(), which is defined by each platform.  If a platform
> links to kern/i386/tsc.c, then the grub_time_init() function from tsc.c
> is used, which calibrates the TSC rate and absolute zero reference using
> the RTC.

This is great!

> I also extracted the grub_millisleep_generic() function into
> kern/generic/millisleep.c and renamed it to grub_millisleep() so that
> platforms linking to it don't need to define a grub_millisleep() just
> to call grub_millisleep_generic() anymore.  Simply linking in
> kern/generic/millisleep.c will use the generic implementation.

Ok.

> I have only tested this patch on the i386-pc platform, so if anyone
> tests it on another platform and finds problems, please let me know and
> I can try to fix it.

Did someone else test it?  I can't...

> === modified file 'ChangeLog'
> --- ChangeLog	2008-06-21 14:21:03 +0000
> +++ ChangeLog	2008-06-23 14:40:22 +0000
> @@ -1,3 +1,87 @@
> +2008-06-22  Colin D Bennett <colin@gibibit.com>
> +
> +	High resolution timer support.  Implemented for i386 CPU using TSC.
> +	Extracted generic grub_millisleep() so it's linked in only as needed.

What if TSC is not available?

> +	* conf/i386-efi.rmk: Added TSC high resolution time module, link with
> +	generic grub_millisleep() function.
> +
> +	* conf/i386-pc.rmk: Likewise.
> +
> +	* conf/sparc64-ieee1275.rmk: Add kern/generic/millisleep.c and
> +	kern/generic/get_time_ms.c to kernel, to use generic time functions.
> +
> +	* conf/powerpc-ieee1275.rmk: Add kern/generic/millisleep.c to kernel,
> +	to use generic grub_millisleep() function.
> +
> +	* kern/generic/get_time_ms.c (grub_get_time_ms): New file.  Platform
> +	independent implementation of grub_get_time_ms() using the RTC that
> +	can be linked into a platform's kernel when it does not implement its
> +	own specialized grub_get_time_ms() function.
> +
> +	* kern/generic/millisleep.c (grub_millisleep): New file.  Extracted
> +	from grub_millisleep_generic() in kern/misc.c and renamed.  Now it is
> +	not included in the kernel when a platform defines a specialized
> +	grub_millisleep() implementation.
> +
> +	* include/grub/i386/tsc.h (grub_get_tsc): New file.  Inline function
> +	grub_get_tsc() uses x86 RDTSC instruction (available on Pentium+ CPUs)
> +	to read the counter value for the TSC.
> +
> +	* kern/i386/tsc.c (grub_get_time_ms): x86 TSC support providing a high
> +	resolution clock.
> +	(grub_tsc_calibrate): Static function to calibrate the TSC using RTC.
> +	(grub_time_init): Implemented to call the static grub_tsc_calibrate()
> +	function to calibrate the TSC.
> +
> +	* include/grub/kernel.h (grub_time_init): Add declaration for the
> +	grub_time_init() platform specific time initialization function.  This
> +	function should be implemented by all platforms.  If kern/i386/tsc.c
> +	is linked in, it will provide grub_time_init().
> +
> +	* include/grub/time.h (grub_get_time_ms): Added grub_get_time_ms()
> +	function to return the current time in millseconds since the epoch.
> +	This supports higher resolution time than grub_get_rtc() on some
> +	platforms such as i386-pc, where the RTC has only about 1/18 s
> +	precision but a higher precision timer such as the TSC is available.
> +
> +	* kern/i386/efi/init.c (grub_millisleep): Don't define
> +	grub_millisleep() -- it just called grub_millisleep_generic() but now
> +	we just need to link with kern/generic/millisleep.c to use the generic
> +	implementation.
> +
> +	* kern/i386/pc/init.c (grub_millisleep): Likewise.
> +
> +	* kern/ieee1275/init.c (grub_millisleep): Don't define
> +	grub_millisleep() -- it just called grub_millisleep_generic() but now
> +	we just need to link with kern/generic/millisleep.c to use the generic
> +	implementation.

No need to mention how it has to be linked.  I just assume you made
this change already?

> +	(grub_get_time_ms): Implement this required function.  Simply uses the
> +	prior implementation of grub_get_rtc().
> +	(grub_get_rtc): Now calls grub_get_time_ms(), which does the real
> +	work.
> +	(grub_time_init): Define this empty but required function. No further
> +	initialization necessary.
> +
> +	* kern/sparc64/ieee1275/init.c (grub_millisleep): Don't define
> +	grub_millisleep(), just link with kern/generic/millisleep.c.
> +	(grub_time_init): Define this required function. Does nothing since
> +	the generic RTC-based functions are used.

No need to mention what a function does.  Only describe the changes
you make.  Other information should go into the file itself as
comments, if it is important enough.  Here it is only noise...

> +	* kern/i386/linuxbios/init.c (grub_get_time_ms):
> +	Define grub_get_time_ms() to always return 0.  This should be fixed
> +	when RTC functionality is implemented.
> +	(grub_time_init): Define this required function as a no-op. Inserted
> +	a comment to remind us delete this function when proper time support 
> +	is added to i386-linuxbios.
> +
> +	* kern/main.c (grub_main): Call grub_time_init() right after
> +	grub_machine_init().

I think this should go into grub_machine_init?  Why didn't you just
add it there?

> +	* kern/misc.c (grub_millisleep_generic): Moved to
> +	kern/generic/millisleep.c so that it is only included in the kernel
> +	image when a platform does not define a specialized version.

Please scroll down for more comments.


>  2008-06-21  Javier Martín  <lordhabbit@gmail.com>
>  
>  	* util/i386/pc/grub-setup.c (setup): Remove literal "core.img" in a
>
> === modified file 'conf/i386-efi.rmk'
> --- conf/i386-efi.rmk	2008-06-19 05:14:16 +0000
> +++ conf/i386-efi.rmk	2008-06-23 02:29:15 +0000
> @@ -84,7 +84,9 @@
>  	kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \
>  	kern/i386/dl.c kern/i386/efi/init.c kern/parser.c kern/partition.c \
>  	kern/env.c symlist.c kern/efi/efi.c kern/efi/init.c kern/efi/mm.c \
> -	term/efi/console.c disk/efi/efidisk.c
> +	term/efi/console.c disk/efi/efidisk.c \
> +	kern/i386/tsc.c \
> +	kern/generic/millisleep.c
>  kernel_mod_HEADERS = arg.h boot.h cache.h device.h disk.h dl.h elf.h elfload.h \
>  	env.h err.h file.h fs.h kernel.h loader.h misc.h mm.h net.h parser.h \
>  	partition.h pc_partition.h rescue.h symbol.h term.h time.h types.h \
>
> === modified file 'conf/i386-pc.rmk'
> --- conf/i386-pc.rmk	2008-06-19 05:14:16 +0000
> +++ conf/i386-pc.rmk	2008-06-23 02:29:15 +0000
> @@ -43,6 +43,8 @@
>  	kern/disk.c kern/dl.c kern/file.c kern/fs.c kern/err.c \
>  	kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \
>  	kern/i386/dl.c kern/i386/pc/init.c kern/parser.c kern/partition.c \
> +	kern/i386/tsc.c \
> +	kern/generic/millisleep.c \
>  	kern/env.c \
>  	term/i386/pc/console.c \
>  	symlist.c
>
> === modified file 'conf/powerpc-ieee1275.rmk'
> --- conf/powerpc-ieee1275.rmk	2008-06-19 05:14:16 +0000
> +++ conf/powerpc-ieee1275.rmk	2008-06-23 14:33:56 +0000
> @@ -85,6 +85,7 @@
>  	kern/ieee1275/init.c term/ieee1275/ofconsole.c 		\
>  	kern/ieee1275/openfw.c disk/ieee1275/ofdisk.c 		\
>  	kern/parser.c kern/partition.c kern/env.c kern/powerpc/dl.c 	\
> +	kern/generic/millisleep.c                                       \
>  	symlist.c kern/powerpc/cache.S
>  kernel_elf_HEADERS = grub/powerpc/ieee1275/ieee1275.h
>  kernel_elf_CFLAGS = $(COMMON_CFLAGS)
>
> === modified file 'conf/sparc64-ieee1275.rmk'
> --- conf/sparc64-ieee1275.rmk	2008-06-19 01:04:59 +0000
> +++ conf/sparc64-ieee1275.rmk	2008-06-23 14:33:56 +0000
> @@ -73,6 +73,7 @@
>  	kern/rescue.c kern/term.c term/ieee1275/ofconsole.c \
>  	kern/sparc64/ieee1275/openfw.c disk/ieee1275/ofdisk.c \
>  	kern/partition.c kern/env.c kern/sparc64/dl.c symlist.c \
> +	kern/generic/millisleep.c kern/generic/get_time_ms.c \
>  	kern/sparc64/cache.S kern/parser.c
>  kernel_elf_HEADERS = grub/sparc64/ieee1275/ieee1275.h
>  kernel_elf_CFLAGS = $(COMMON_CFLAGS)
>
> === added file 'include/grub/i386/tsc.h'
> --- include/grub/i386/tsc.h	1970-01-01 00:00:00 +0000
> +++ include/grub/i386/tsc.h	2008-06-17 20:14:24 +0000
> @@ -0,0 +1,41 @@
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2008  Free Software Foundation, Inc.
> + *
> + *  GRUB is free software: you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation, either version 3 of the License, or
> + *  (at your option) any later version.
> + *
> + *  GRUB is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef KERNEL_CPU_TSC_HEADER
> +#define KERNEL_CPU_TSC_HEADER	1
> +
> +#include <grub/types.h>
> +
> +/* Read the TSC value, which increments with each CPU clock cycle. */
> +static __inline grub_uint64_t
> +grub_get_tsc (void)
> +{
> +  grub_uint32_t lo, hi;
> +
> +  /* The CPUID instruction is a 'serializing' instruction, and
> +   * avoids out-of-order execution of the RDTSC instruction. */
> +  __asm__ __volatile__ ("xorl %%eax, %%eax\n\t"
> +                        "cpuid":::"%rax", "%rbx", "%rcx", "%rdx");
> +  /* Read TSC value.  We cannot use "=A", since this would use
> +   * %rax on x86_64. */
> +  __asm__ __volatile__ ("rdtsc":"=a" (lo), "=d" (hi));
> +
> +  return (((grub_uint64_t) hi) << 32) | lo;
> +}
> +
> +#endif /* ! KERNEL_CPU_TSC_HEADER */
>
> === modified file 'include/grub/kernel.h'
> --- include/grub/kernel.h	2008-01-21 00:04:04 +0000
> +++ include/grub/kernel.h	2008-06-17 15:04:05 +0000
> @@ -58,6 +58,9 @@
>  /* The machine-specific prefix initialization.  */
>  void grub_machine_set_prefix (void);
>  
> +/* The machine-specific time source initialization. */
> +void grub_time_init (void);
> +
>  /* Register all the exported symbols. This is automatically generated.  */
>  void grub_register_exported_symbols (void);
>  
>
> === modified file 'include/grub/time.h'
> --- include/grub/time.h	2007-10-22 20:02:16 +0000
> +++ include/grub/time.h	2008-06-17 20:14:24 +0000
> @@ -1,6 +1,6 @@
>  /*
>   *  GRUB  --  GRand Unified Bootloader
> - *  Copyright (C) 2007  Free Software Foundation, Inc.
> + *  Copyright (C) 2007, 2008  Free Software Foundation, Inc.
>   *
>   *  GRUB is free software: you can redistribute it and/or modify
>   *  it under the terms of the GNU General Public License as published by
> @@ -19,12 +19,13 @@
>  #ifndef KERNEL_TIME_HEADER
>  #define KERNEL_TIME_HEADER	1
>  
> +#include <grub/types.h>
>  #include <grub/symbol.h>
>  #include <grub/machine/time.h>
>  #include <grub/cpu/time.h>
>  
>  void EXPORT_FUNC(grub_millisleep) (grub_uint32_t ms);
> -void EXPORT_FUNC(grub_millisleep_generic) (grub_uint32_t ms);
> +grub_uint64_t EXPORT_FUNC(grub_get_time_ms) (void);
>  
>  static __inline void
>  grub_sleep (grub_uint32_t s)
>
> === added directory 'kern/generic'
> === added file 'kern/generic/get_time_ms.c'
> --- kern/generic/get_time_ms.c	1970-01-01 00:00:00 +0000
> +++ kern/generic/get_time_ms.c	2008-06-17 15:04:05 +0000
> @@ -0,0 +1,37 @@
> +/* get_time_ms.c - generic time implementation -- using platform RTC.
> + * The generic implementation of these functions can be used for architectures
> + * or platforms that do not have a more specialized implementation. */
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2008  Free Software Foundation, Inc.
> + *
> + *  GRUB is free software: you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation, either version 3 of the License, or
> + *  (at your option) any later version.
> + *
> + *  GRUB is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <grub/time.h>
> +#include <grub/misc.h>
> +
> +/* Calculate the time in milliseconds since the epoch based on the RTC. */
> +grub_uint64_t
> +grub_get_time_ms (void)
> +{
> +  /* By dimensional analysis: 
> +   *
> +   *  1000 ms   N rtc ticks       1 s
> +   *  ------- * ----------- * ----------- = 1000*N/T ms
> +   *    1 s          1        T rtc ticks
> +   */
> +  grub_uint64_t ticks_ms_per_sec = ((grub_uint64_t) 1000) * grub_get_rtc ();
> +  return grub_divmod64 (ticks_ms_per_sec, GRUB_TICKS_PER_SECOND, 0);
> +}
>
> === added file 'kern/generic/millisleep.c'
> --- kern/generic/millisleep.c	1970-01-01 00:00:00 +0000
> +++ kern/generic/millisleep.c	2008-06-23 14:33:56 +0000
> @@ -0,0 +1,39 @@
> +/* millisleep.c - generic millisleep function.
> + * The generic implementation of these functions can be used for architectures
> + * or platforms that do not have a more specialized implementation. */
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008  Free Software Foundation, Inc.
> + *
> + *  GRUB is free software: you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation, either version 3 of the License, or
> + *  (at your option) any later version.
> + *
> + *  GRUB is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <grub/misc.h>
> +#include <grub/time.h>
> +
> +void
> +grub_millisleep (grub_uint32_t ms)
> +{
> +  /* Note: Perhaps this function should use grub_get_time_ms() instead of
> +   * grub_get_rtc()so it can take advantage of high resolution timing
> +   * on platforms where it is provided. */
> +
> +  grub_uint32_t end_at;
> +
> +  end_at =
> +    grub_get_rtc () + grub_div_roundup (ms * GRUB_TICKS_PER_SECOND, 1000);
> +
> +  while (grub_get_rtc () < end_at)
> +    grub_cpu_idle ();
> +}
>
> === modified file 'kern/i386/efi/init.c'
> --- kern/i386/efi/init.c	2007-10-22 19:59:33 +0000
> +++ kern/i386/efi/init.c	2008-06-17 15:04:05 +0000
> @@ -25,13 +25,6 @@
>  #include <grub/cache.h>
>  #include <grub/kernel.h>
>  #include <grub/efi/efi.h>
> -#include <grub/time.h>
> -
> -void
> -grub_millisleep (grub_uint32_t ms)
> -{
> -  grub_millisleep_generic (ms);
> -}
>  
>  void
>  grub_machine_init (void)
>
> === modified file 'kern/i386/linuxbios/init.c'
> --- kern/i386/linuxbios/init.c	2008-02-13 20:04:37 +0000
> +++ kern/i386/linuxbios/init.c	2008-06-23 14:33:56 +0000
> @@ -33,6 +33,7 @@
>  #include <grub/time.h>
>  #include <grub/symbol.h>
>  #include <grub/cpu/io.h>
> +#include <grub/cpu/time.h>
>  
>  #define GRUB_FLOPPY_REG_DIGITAL_OUTPUT		0x3f2
>  
> @@ -52,6 +53,23 @@
>    return grub_time_tics;
>  }
>  
> +grub_uint64_t
> +grub_get_time_ms (void)
> +{
> +  /* FIXME: Delete this function and link to `kern/i386/tsc.c' once RTC
> +   * is implemented.  See also comment below in grub_time_init(). */
> +  return 0;
> +}

Please do not use comments with *'s on each line.

> +void
> +grub_time_init (void)
> +{
> +  /* FIXME: Delete this function and link with `kern/i386/tsc.c' once RTC
> +   * is implemented.  Until then, this dummy function simply defines 
> +   * grub_time_init(), which is called by grub_main() in `kern/main.c'.
> +   * Without RTC, TSC calibration will hang waiting for an RTC edge. */
> +}
> +

Same here.  Can you explain what is going on here?

>  /* Stop the floppy drive from spinning, so that other software is
>     jumped to with a known state.  */
>  void
>
> === modified file 'kern/i386/pc/init.c'
> --- kern/i386/pc/init.c	2008-06-15 18:21:16 +0000
> +++ kern/i386/pc/init.c	2008-06-17 16:28:36 +0000
> @@ -30,6 +30,7 @@
>  #include <grub/env.h>
>  #include <grub/cache.h>
>  #include <grub/time.h>
> +#include <grub/cpu/time.h>
>  
>  struct mem_region
>  {
> @@ -46,12 +47,6 @@
>  grub_size_t grub_os_area_size;
>  grub_size_t grub_lower_mem, grub_upper_mem;
>  
> -void
> -grub_millisleep (grub_uint32_t ms)
> -{
> -  grub_millisleep_generic (ms);
> -}
> -
>  void 
>  grub_arch_sync_caches (void *address __attribute__ ((unused)),
>  		       grub_size_t len __attribute__ ((unused)))
>
> === added file 'kern/i386/tsc.c'
> --- kern/i386/tsc.c	1970-01-01 00:00:00 +0000
> +++ kern/i386/tsc.c	2008-06-17 15:04:05 +0000
> @@ -0,0 +1,99 @@
> +/* kern/i386/tsc.c - x86 TSC time source implementation
> + * Requires Pentium or better x86 CPU that supports the RDTSC instruction.
> + * This module uses the RTC (via grub_get_rtc()) to calibrate the TSC to 
> + * real time.
> + *
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2007  Free Software Foundation, Inc.
> + *
> + *  GRUB is free software: you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation, either version 3 of the License, or
> + *  (at your option) any later version.
> + *
> + *  GRUB is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <grub/types.h>
> +#include <grub/time.h>
> +#include <grub/misc.h>
> +#include <grub/i386/tsc.h>
> +
> +/* Reference for TSC=0.  This defines the time since the epoch in 
> + * milliseconds that TSC=0 refers to. */
> +static grub_uint64_t tsc_boot_time = 0;

Please do not use a * on each line for comments.  No need to set this
to zero explicitly.

> +/* TSC rate. TSC ticks per millisecond. 
> + * Begin with default (incorrect) value of assuming a 1 GHz machine.
> + * grub_tsc_calibrate() must be called to set this properly. */
> +static grub_uint64_t tsc_ticks_per_ms = 1000000;

Same as above.

The value is not correct.  Why can't we just set it to 0?

> +/* Declared in <grub/time.h>. */
> +grub_uint64_t
> +grub_get_time_ms (void)
> +{
> +  return tsc_boot_time + grub_divmod64 (grub_get_tsc (), tsc_ticks_per_ms, 0);
> +}
> +
> +
> +/* How many RTC ticks to use for calibration loop. (>= 1) */
> +#define CALIBRATION_TICKS 2
> +
> +/* Called by the machine-specific time initialization function
> + * grub_time_init() below. */
> +static void
> +grub_tsc_calibrate (void)
> +{
> +  /* First calbrate the TSC rate (relative, not absolute time). */
> +  grub_uint64_t start_tsc;
> +  grub_uint64_t end_tsc;
> +  grub_uint32_t initial_tick;
> +  grub_uint32_t start_tick;
> +  grub_uint32_t end_tick;
> +
> +  /* Wait for the start of the next tick;
> +     we'll base out timing off this edge. */
> +  initial_tick = grub_get_rtc ();
> +  do
> +    {
> +      start_tick = grub_get_rtc ();
> +    }
> +  while (start_tick == initial_tick);
> +  start_tsc = grub_get_tsc ();
> +
> +  /* Wait for the start of the next tick.  This will
> +     be the end of the 1-tick period. */
> +  do
> +    {
> +      end_tick = grub_get_rtc ();
> +    }
> +  while (end_tick - start_tick < CALIBRATION_TICKS);
> +  end_tsc = grub_get_tsc ();
> +
> +  tsc_ticks_per_ms =
> +    grub_divmod64 (grub_divmod64
> +                   (end_tsc - start_tsc, end_tick - start_tick, 0)
> +                   * GRUB_TICKS_PER_SECOND, 1000, 0);
> +
> +  /* Reference the TSC zero (boot time) to the epoch to 
> +   * get an absolute real time reference. */
> +  grub_uint64_t ms_since_boot = grub_divmod64 (end_tsc, tsc_ticks_per_ms, 0);
> +  grub_uint64_t mstime_now = grub_divmod64 ((grub_uint64_t) 1000 * end_tick,
> +                                            GRUB_TICKS_PER_SECOND,
> +                                            0);
> +  tsc_boot_time = mstime_now - ms_since_boot;
> +}
> +
> +/* Implement the machine-specific time initialization function. */
> +void
> +grub_time_init (void)
> +{
> +  grub_tsc_calibrate ();
> +}
>
> === modified file 'kern/ieee1275/init.c'
> --- kern/ieee1275/init.c	2008-04-25 19:41:48 +0000
> +++ kern/ieee1275/init.c	2008-06-17 15:04:05 +0000
> @@ -47,12 +47,6 @@
>  extern char _end[];
>  
>  void
> -grub_millisleep (grub_uint32_t ms)
> -{
> -  grub_millisleep_generic (ms);
> -}
> -
> -void
>  grub_exit (void)
>  {
>    grub_ieee1275_exit ();
> @@ -257,8 +251,13 @@
>    grub_console_fini ();
>  }
>  
> -grub_uint32_t
> -grub_get_rtc (void)
> +void
> +grub_time_init (void)
> +{
> +}
> +
> +grub_uint64_t
> +grub_get_time_ms (void)
>  {
>    grub_uint32_t msecs = 0;
>  
> @@ -267,6 +266,12 @@
>    return msecs;
>  }
>  
> +grub_uint32_t
> +grub_get_rtc (void)
> +{
> +  return grub_get_time_ms ();
> +}
> +
>  grub_addr_t
>  grub_arch_modules_addr (void)
>  {
>
> === modified file 'kern/main.c'
> --- kern/main.c	2008-06-19 20:08:57 +0000
> +++ kern/main.c	2008-06-23 02:29:15 +0000
> @@ -112,6 +112,7 @@
>  {
>    /* First of all, initialize the machine.  */
>    grub_machine_init ();
> +  grub_time_init ();
>  
>    /* Hello.  */
>    grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT);
>
> === modified file 'kern/misc.c'
> --- kern/misc.c	2008-06-16 00:42:48 +0000
> +++ kern/misc.c	2008-06-17 16:28:36 +0000
> @@ -1018,17 +1018,6 @@
>    return p - dest;
>  }
>  
> -void
> -grub_millisleep_generic (grub_uint32_t ms)
> -{
> -  grub_uint32_t end_at;
> -
> -  end_at = grub_get_rtc () + grub_div_roundup (ms * GRUB_TICKS_PER_SECOND, 1000);
> -
> -  while (grub_get_rtc () < end_at)
> -    grub_cpu_idle ();
> -}
> -
>  /* Abort GRUB. This function does not return.  */
>  void
>  grub_abort (void)
>
> === modified file 'kern/sparc64/ieee1275/init.c'
> --- kern/sparc64/ieee1275/init.c	2007-10-22 19:59:33 +0000
> +++ kern/sparc64/ieee1275/init.c	2008-06-23 14:33:56 +0000
> @@ -66,10 +66,10 @@
>    /* Never reached.  */
>  }
>  
> +/* Define the required grub_time_init() function. */
>  void
> -grub_millisleep (grub_uint32_t ms)
> +grub_time_init (void)
>  {
> -  grub_millisleep_generic (ms);
>  }
>  
>  int
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> http://lists.gnu.org/mailman/listinfo/grub-devel




^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC] High resolution time support using x86 TSC
  2008-07-03 18:52 ` Marco Gerards
@ 2008-07-04 15:58   ` Colin D Bennett
  2008-07-04 16:10     ` Vesa Jääskeläinen
  2008-07-04 17:26   ` Colin D Bennett
  2008-07-04 18:28   ` [RFC] TSC patch v2 Colin D Bennett
  2 siblings, 1 reply; 24+ messages in thread
From: Colin D Bennett @ 2008-07-04 15:58 UTC (permalink / raw)
  To: grub-devel

[-- Attachment #1: Type: text/plain, Size: 2721 bytes --]

On Thu, 03 Jul 2008 20:52:53 +0200
Marco Gerards <mgerards@xs4all.nl> wrote:

> Hi Colin,
> 
> Colin D Bennett <colin@gibibit.com> writes:
> 
> > +	* kern/i386/linuxbios/init.c (grub_get_time_ms):
> > +	Define grub_get_time_ms() to always return 0.  This should
> > be fixed
> > +	when RTC functionality is implemented.
> > +	(grub_time_init): Define this required function as a
> > no-op. Inserted
> > +	a comment to remind us delete this function when proper
> > time support 
> > +	is added to i386-linuxbios.
> > +
> > +	* kern/main.c (grub_main): Call grub_time_init() right
> > after
> > +	grub_machine_init().
> 
> I think this should go into grub_machine_init?  Why didn't you just
> add it there?

Originally, I had grub_machine_init() call grub_tsc_calibrate(), but
these are comments Vesa made to me about that code:

Vesa Jääskeläinen <dachaac@gmail.com> wrote
on Mon, 16 Jun 2008 20:34:54 +0300:

> Colin D Bennett wrote:
> > This week I implemented high resolution timer support using the x86
> > TSC (see attached patch <grub_tsc_2008-06-10.patch>).  It is
> > calibrated at GRUB startup using the RTC as a reference. The core
> > TSC function is ``grub_get_tsc()`` -- corresponding to
> > ``grub_get_rtc()``, but returning a uint64 value representing the
> > number of CPU cycles elapsed since boot.
> > 
> > In most situations, you will want to use ``grub_get_time_ms()`` to
> > get the system time in milliseconds based on the TSC value.  The
> > calibration function ``grub_tsc_calibrate()``, calculates the
> > proper scale factor and absolute offset so that the millisecond
> > value represents real time.
> > 
> > The ``grub_get_time_ms()`` function is implemented for non-x86
> > platforms to simply call ``grub_get_time_ms_generic()`` (defined in
> > kern/misc.c), which uses the RTC to get the time in milliseconds.  
> 
> We would probably want to leave that generic out from kernel, and let 
> every platform either use this generic code or implement their own 
> mechanism to do the job. Perhaps we should make own folder for
> generic stuff that can be included for arch specific build if there
> is no better replacement.
> 
> How about calling function like grub_time_init() which would then be 
> platform specific? Then platform can implement whatever way to
> calibrate (if needed) as long as it provides this grub_get_time_ms()
> function (also being platform specific). This would make
> initialization non-specific to arch while leaving more room for
> implementation.

Therefore, I thought this was the right way to do it.  Do you want me
to instead call grub_time_init() from grub_machine_init()?

Regards,
Colin

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC] High resolution time support using x86 TSC
  2008-07-04 15:58   ` Colin D Bennett
@ 2008-07-04 16:10     ` Vesa Jääskeläinen
  0 siblings, 0 replies; 24+ messages in thread
From: Vesa Jääskeläinen @ 2008-07-04 16:10 UTC (permalink / raw)
  To: The development of GRUB 2

Colin D Bennett wrote:
> On Thu, 03 Jul 2008 20:52:53 +0200
> Marco Gerards <mgerards@xs4all.nl> wrote:
> 
>> Hi Colin,
>>
>> Colin D Bennett <colin@gibibit.com> writes:
>>
>>> +	* kern/i386/linuxbios/init.c (grub_get_time_ms):
>>> +	Define grub_get_time_ms() to always return 0.  This should
>>> be fixed
>>> +	when RTC functionality is implemented.
>>> +	(grub_time_init): Define this required function as a
>>> no-op. Inserted
>>> +	a comment to remind us delete this function when proper
>>> time support 
>>> +	is added to i386-linuxbios.
>>> +
>>> +	* kern/main.c (grub_main): Call grub_time_init() right
>>> after
>>> +	grub_machine_init().
>> I think this should go into grub_machine_init?  Why didn't you just
>> add it there?
> 
> Originally, I had grub_machine_init() call grub_tsc_calibrate(), but
> these are comments Vesa made to me about that code:
> 
> Vesa Jääskeläinen <dachaac@gmail.com> wrote
> on Mon, 16 Jun 2008 20:34:54 +0300:
> 
>> Colin D Bennett wrote:
>>> This week I implemented high resolution timer support using the x86
>>> TSC (see attached patch <grub_tsc_2008-06-10.patch>).  It is
>>> calibrated at GRUB startup using the RTC as a reference. The core
>>> TSC function is ``grub_get_tsc()`` -- corresponding to
>>> ``grub_get_rtc()``, but returning a uint64 value representing the
>>> number of CPU cycles elapsed since boot.
>>>
>>> In most situations, you will want to use ``grub_get_time_ms()`` to
>>> get the system time in milliseconds based on the TSC value.  The
>>> calibration function ``grub_tsc_calibrate()``, calculates the
>>> proper scale factor and absolute offset so that the millisecond
>>> value represents real time.
>>>
>>> The ``grub_get_time_ms()`` function is implemented for non-x86
>>> platforms to simply call ``grub_get_time_ms_generic()`` (defined in
>>> kern/misc.c), which uses the RTC to get the time in milliseconds.  
>> We would probably want to leave that generic out from kernel, and let 
>> every platform either use this generic code or implement their own 
>> mechanism to do the job. Perhaps we should make own folder for
>> generic stuff that can be included for arch specific build if there
>> is no better replacement.
>>
>> How about calling function like grub_time_init() which would then be 
>> platform specific? Then platform can implement whatever way to
>> calibrate (if needed) as long as it provides this grub_get_time_ms()
>> function (also being platform specific). This would make
>> initialization non-specific to arch while leaving more room for
>> implementation.
> 
> Therefore, I thought this was the right way to do it.  Do you want me
> to instead call grub_time_init() from grub_machine_init()?

Hi Colin,

That is Ok.

My comment was more of calling directly tsc_calibrate which is not 
generic function at all. You can call grub_time_init() and in there you 
decide that you use tsc (and then call tsc_calibrate) or something else 
depending what is available. This way time handling stuff can be reside 
easily on one module and it is easy to provide generic function to other 
platforms.

Thanks,
Vesa Jääskeläinen



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC] High resolution time support using x86 TSC
  2008-07-03 18:52 ` Marco Gerards
  2008-07-04 15:58   ` Colin D Bennett
@ 2008-07-04 17:26   ` Colin D Bennett
  2008-07-20 18:21     ` Marco Gerards
  2008-07-04 18:28   ` [RFC] TSC patch v2 Colin D Bennett
  2 siblings, 1 reply; 24+ messages in thread
From: Colin D Bennett @ 2008-07-04 17:26 UTC (permalink / raw)
  To: The development of GRUB 2

[-- Attachment #1: Type: text/plain, Size: 5389 bytes --]

Hi Marco,

On Thu, 03 Jul 2008 20:52:53 +0200
Marco Gerards <mgerards@xs4all.nl> wrote:

> Hi Colin,
> 
> Colin D Bennett <colin@gibibit.com> writes:
> 
> > I have implemented high resolution time support (through the
> > new grub_get_time_ms() function) using the RDTSC instruction
> > available on Pentium and higher x86 CPUs.  The TSC value is simply
> > a 64-bit block cycle counter that is zeroed at bootup, so
> > grub_main() calls grub_time_init(), which is defined by each
> > platform.  If a platform links to kern/i386/tsc.c, then the
> > grub_time_init() function from tsc.c is used, which calibrates the
> > TSC rate and absolute zero reference using the RTC.
> What if TSC is not available?

I updated the changelog entry to indicate that running on a 386 or 486
will fail, since TSC is provided in Pentium+.  Do we support running on
386 or 386?  Should I check for this?  If so, the code will have to
change a bit, and be able to select between the generic implementation
and the TSC implementation at runtime.

I think this would be best done letting the "grub_get_time_ms"
implementation be selected by setting a function pointer in
grub_machine_init() depending on the machine's capabilities.  I would
have to significantly re-structure my patch, but it might be
necessary (and could lead to more understandable code?).
What do you think?

>...
> > +	* kern/i386/pc/init.c (grub_millisleep): Likewise.
> > +
> > +	* kern/ieee1275/init.c (grub_millisleep): Don't define
> > +	grub_millisleep() -- it just called
> > grub_millisleep_generic() but now
> > +	we just need to link with kern/generic/millisleep.c to use
> > the generic
> > +	implementation.
> 
> No need to mention how it has to be linked.  I just assume you made
> this change already?

Yes.  I removed that part of the changelog comment.

>...
> > +	(grub_time_init): Define this required function. Does
> > nothing since
> > +	the generic RTC-based functions are used.
> 
> No need to mention what a function does.  Only describe the changes
> you make.  Other information should go into the file itself as
> comments, if it is important enough.  Here it is only noise...

Ok.  I tried to clean this up.

> > +	* kern/i386/linuxbios/init.c (grub_get_time_ms):
> > +	Define grub_get_time_ms() to always return 0.  This should
> > be fixed
> > +	when RTC functionality is implemented.
> > +	(grub_time_init): Define this required function as a
> > no-op. Inserted
> > +	a comment to remind us delete this function when proper
> > time support 
> > +	is added to i386-linuxbios.
> > +
> > +	* kern/main.c (grub_main): Call grub_time_init() right
> > after
> > +	grub_machine_init().
> 
> I think this should go into grub_machine_init?  Why didn't you just
> add it there?

I commented on this in a separate message a few minutes ago.

> > +grub_uint64_t
> > +grub_get_time_ms (void)
> > +{
> > +  /* FIXME: Delete this function and link to `kern/i386/tsc.c'
> > once RTC
> > +   * is implemented.  See also comment below in grub_time_init().
> > */
> > +  return 0;
> > +}
> 
> Please do not use comments with *'s on each line.

Sorry, it was a habit of mine.  Fixed.

>...
> > +void
> > +grub_time_init (void)
> > +{
> > +  /* FIXME: Delete this function and link with `kern/i386/tsc.c'
> > once RTC
> > +   * is implemented.  Until then, this dummy function simply
> > defines 
> > +   * grub_time_init(), which is called by grub_main() in
> > `kern/main.c'.
> > +   * Without RTC, TSC calibration will hang waiting for an RTC
> > edge. */ +}
> > +
> 
> Same here.  Can you explain what is going on here?

Since grub_main() calls grub_time_init(), it must be defined.  However,
we can't use the TSC implementation of grub_time_init() from
kern/i386/tsc.c, since it will not be able to calibrate (it will hang)
if the RTC always returns the same value, which the i386-linuxbios
kernel does.

>...
> > +/* Reference for TSC=0.  This defines the time since the epoch
>in 
> > + * milliseconds that TSC=0 refers to. */
> > +static grub_uint64_t tsc_boot_time = 0;
> 
> Please do not use a * on each line for comments.  No need to set this
> to zero explicitly.

Ok.

> 
> > +/* TSC rate. TSC ticks per millisecond. 
> > + * Begin with default (incorrect) value of assuming a 1 GHz
> > machine.
> > + * grub_tsc_calibrate() must be called to set this properly. */
> > +static grub_uint64_t tsc_ticks_per_ms = 1000000;
> 
> Same as above.
> 
> The value is not correct.  Why can't we just set it to 0?

I figured that in case calibration was not done, we could at least fake
partial functionality by going with an incorrect value.  However, I
don't initialize tsc_boot_time, then there is no sense in initializing
tsc_ticks_per_ms either, since without both of them set to a valid
value, grub_get_time_ms() will not work.


I just realize I should probably not have chopped up the patch above in
my reply in an attempt to make it short. I hope I didn't make it too
hard to follow. I'll send a new patch shortly for your comments -- it
will include the minor changes you mentioned, but will not address the
issue of supporting 386/486 machines (no TSC), as I discussed at the
beginning of this message.  I await your comments regarding that point.

Regards,
Colin

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC] TSC patch v2
  2008-07-03 18:52 ` Marco Gerards
  2008-07-04 15:58   ` Colin D Bennett
  2008-07-04 17:26   ` Colin D Bennett
@ 2008-07-04 18:28   ` Colin D Bennett
  2008-07-04 19:49     ` Vesa Jääskeläinen
  2008-07-20 18:45     ` Marco Gerards
  2 siblings, 2 replies; 24+ messages in thread
From: Colin D Bennett @ 2008-07-04 18:28 UTC (permalink / raw)
  To: The development of GRUB 2


[-- Attachment #1.1: Type: text/plain, Size: 672 bytes --]

Here is an updated version of the TSC patch.

I addressed the issues in your comments with the exception of
supporting x86 CPUs that don't have a TSC (386 and 486).

I eliminated the grub_time_init() function and the call to it in
grub_main() in favor of having grub_machine_init() simply call
grub_tsc_calibrate().  The i386-pc and i386-efi platforms use the TSC.

I also changed the grub_millisleep() generic function to use
grub_get_time_ms() instead of grub_get_rtc() to achieve better
precision when a higher resolution time function is available.

Please take a look at it and give me your comments when you have a
chance.  Thanks!

Regards,
Colin

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: tsc_2008-07-04.patch --]
[-- Type: text/x-patch; name=tsc_2008-07-04.patch, Size: 19096 bytes --]

=== modified file 'ChangeLog'
--- ChangeLog	2008-07-04 02:26:10 +0000
+++ ChangeLog	2008-07-04 18:08:36 +0000
@@ -1,3 +1,70 @@
+2008-07-04  Colin D Bennett <colin@gibibit.com>
+
+	High resolution timer support.  Implemented for i386 CPU using TSC.
+	Extracted generic grub_millisleep() so it's linked in only as needed.
+	This requires a Pentium compatible CPU; currently the code does not
+	check for this (so it will fail on 386 and 486 machines).
+
+	* conf/i386-efi.rmk: Added TSC high resolution time module, link with
+	generic grub_millisleep() function.
+
+	* conf/i386-pc.rmk: Likewise.
+
+	* conf/sparc64-ieee1275.rmk: Add kern/generic/millisleep.c and
+	kern/generic/get_time_ms.c to kernel, to use generic time functions.
+
+	* conf/powerpc-ieee1275.rmk: Add kern/generic/millisleep.c to kernel,
+	to use generic grub_millisleep() function.
+
+	* conf/i386-linuxbios.rmk: Added kern/generic/get_time_ms.c to the
+	kernel.
+
+	* kern/generic/get_time_ms.c (grub_get_time_ms): New file.  Platform
+	independent implementation of grub_get_time_ms() using the RTC that
+	can be linked into a platform's kernel when it does not implement its
+	own specialized grub_get_time_ms() function.
+
+	* kern/generic/millisleep.c (grub_millisleep): New file.  Extracted
+	from grub_millisleep_generic() in kern/misc.c and renamed.  Changed it
+	to use grub_get_time_ms() instead of grub_get_rtc() for better
+	precision on when high resolution time is available.
+
+	* kern/misc.c (grub_millisleep_generic): Deleted.  Moved to
+	kern/generic/millisleep.c so that it is only included in the kernel
+	image when a platform does not define a specialized version.
+
+	* commands/sleep.c (grub_interruptible_millisleep): Uses
+	grub_get_time_ms() instead of grub_get_rtc() to stay in sync with
+	grub_millisleep() from kern/generic/millisleep.c.
+
+	* include/grub/i386/tsc.h (grub_get_tsc): New file.  Inline function
+	grub_get_tsc() uses x86 RDTSC instruction (available on Pentium+ CPUs)
+	to read the counter value for the TSC.
+	(grub_tsc_calibrate): Declare this function for grub_machine_init().
+
+	* kern/i386/tsc.c (grub_get_time_ms): x86 TSC support providing a high
+	resolution clock.
+	(grub_tsc_calibrate): New function to calibrate the TSC using RTC.
+
+	* include/grub/time.h (grub_get_time_ms): Added grub_get_time_ms()
+	function to return the current time in millseconds since the epoch.
+	This supports higher resolution time than grub_get_rtc() on some
+	platforms such as i386-pc, where the RTC has only about 1/18 s
+	precision but a higher precision timer such as the TSC is available.
+
+	* kern/i386/efi/init.c (grub_millisleep): Deleted.  Don't define
+	grub_millisleep() -- it just called grub_millisleep_generic() but now
+	it is linked to kern/generic/millisleep.c for the implementation.
+
+	* kern/sparc64/ieee1275/init.c (grub_millisleep): Deleted.
+
+	* kern/i386/pc/init.c (grub_machine_init): Call grub_tsc_calibrate().
+	(grub_millisleep): Deleted.
+
+	* kern/ieee1275/init.c (grub_millisleep): Deleted.
+	(grub_get_rtc): Now calls grub_get_time_ms(), which does the real
+	work.
+
 2008-07-04  Pavel Roskin  <proski@gnu.org>
 
 	* kern/i386/linuxbios/init.c (grub_machine_init): Cast addr to

=== modified file 'commands/sleep.c'
--- commands/sleep.c	2008-05-16 20:55:29 +0000
+++ commands/sleep.c	2008-07-04 16:55:48 +0000
@@ -43,15 +43,15 @@
   grub_printf ("%d    ", n);
 }
 
-/* Based on grub_millisleep() from kern/misc.c.  */
+/* Based on grub_millisleep() from kern/generic/millisleep.c.  */
 static int
 grub_interruptible_millisleep (grub_uint32_t ms)
 {
-  grub_uint32_t end_at;
-  
-  end_at = grub_get_rtc () + grub_div_roundup (ms * GRUB_TICKS_PER_SECOND, 1000);
-  
-  while (grub_get_rtc () < end_at)
+  grub_uint64_t start;
+
+  start = grub_get_time_ms ();
+
+  while (grub_get_time_ms () - start < ms)
     if (grub_checkkey () >= 0 &&
 	GRUB_TERM_ASCII_CHAR (grub_getkey ()) == GRUB_TERM_ESC)
       return 1;

=== modified file 'conf/i386-efi.rmk'
--- conf/i386-efi.rmk	2008-06-19 04:14:16 +0000
+++ conf/i386-efi.rmk	2008-07-03 04:19:16 +0000
@@ -84,7 +84,9 @@
 	kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \
 	kern/i386/dl.c kern/i386/efi/init.c kern/parser.c kern/partition.c \
 	kern/env.c symlist.c kern/efi/efi.c kern/efi/init.c kern/efi/mm.c \
-	term/efi/console.c disk/efi/efidisk.c
+	term/efi/console.c disk/efi/efidisk.c \
+	kern/i386/tsc.c \
+	kern/generic/millisleep.c
 kernel_mod_HEADERS = arg.h boot.h cache.h device.h disk.h dl.h elf.h elfload.h \
 	env.h err.h file.h fs.h kernel.h loader.h misc.h mm.h net.h parser.h \
 	partition.h pc_partition.h rescue.h symbol.h term.h time.h types.h \

=== modified file 'conf/i386-linuxbios.rmk'
--- conf/i386-linuxbios.rmk	2008-06-19 04:14:16 +0000
+++ conf/i386-linuxbios.rmk	2008-07-04 16:55:48 +0000
@@ -18,6 +18,7 @@
 	kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \
 	kern/i386/dl.c kern/parser.c kern/partition.c \
 	kern/env.c \
+	kern/generic/get_time_ms.c \
 	term/i386/pc/console.c \
 	term/i386/pc/at_keyboard.c term/i386/pc/vga_text.c \
 	symlist.c

=== modified file 'conf/i386-pc.rmk'
--- conf/i386-pc.rmk	2008-06-19 04:14:16 +0000
+++ conf/i386-pc.rmk	2008-07-03 04:19:16 +0000
@@ -43,6 +43,8 @@
 	kern/disk.c kern/dl.c kern/file.c kern/fs.c kern/err.c \
 	kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \
 	kern/i386/dl.c kern/i386/pc/init.c kern/parser.c kern/partition.c \
+	kern/i386/tsc.c \
+	kern/generic/millisleep.c \
 	kern/env.c \
 	term/i386/pc/console.c \
 	symlist.c

=== modified file 'conf/powerpc-ieee1275.rmk'
--- conf/powerpc-ieee1275.rmk	2008-06-19 04:14:16 +0000
+++ conf/powerpc-ieee1275.rmk	2008-07-03 04:19:16 +0000
@@ -85,6 +85,7 @@
 	kern/ieee1275/init.c term/ieee1275/ofconsole.c 		\
 	kern/ieee1275/openfw.c disk/ieee1275/ofdisk.c 		\
 	kern/parser.c kern/partition.c kern/env.c kern/powerpc/dl.c 	\
+	kern/generic/millisleep.c                                       \
 	symlist.c kern/powerpc/cache.S
 kernel_elf_HEADERS = grub/powerpc/ieee1275/ieee1275.h
 kernel_elf_CFLAGS = $(COMMON_CFLAGS)

=== modified file 'conf/sparc64-ieee1275.rmk'
--- conf/sparc64-ieee1275.rmk	2008-06-19 00:04:59 +0000
+++ conf/sparc64-ieee1275.rmk	2008-07-03 04:19:16 +0000
@@ -73,6 +73,7 @@
 	kern/rescue.c kern/term.c term/ieee1275/ofconsole.c \
 	kern/sparc64/ieee1275/openfw.c disk/ieee1275/ofdisk.c \
 	kern/partition.c kern/env.c kern/sparc64/dl.c symlist.c \
+	kern/generic/millisleep.c kern/generic/get_time_ms.c \
 	kern/sparc64/cache.S kern/parser.c
 kernel_elf_HEADERS = grub/sparc64/ieee1275/ieee1275.h
 kernel_elf_CFLAGS = $(COMMON_CFLAGS)

=== added file 'include/grub/i386/tsc.h'
--- include/grub/i386/tsc.h	1970-01-01 00:00:00 +0000
+++ include/grub/i386/tsc.h	2008-07-04 17:55:21 +0000
@@ -0,0 +1,43 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef KERNEL_CPU_TSC_HEADER
+#define KERNEL_CPU_TSC_HEADER	1
+
+#include <grub/types.h>
+
+/* Read the TSC value, which increments with each CPU clock cycle. */
+static __inline grub_uint64_t
+grub_get_tsc (void)
+{
+  grub_uint32_t lo, hi;
+
+  /* The CPUID instruction is a 'serializing' instruction, and
+     avoids out-of-order execution of the RDTSC instruction. */
+  __asm__ __volatile__ ("xorl %%eax, %%eax\n\t"
+                        "cpuid":::"%rax", "%rbx", "%rcx", "%rdx");
+  /* Read TSC value.  We cannot use "=A", since this would use
+     %rax on x86_64. */
+  __asm__ __volatile__ ("rdtsc":"=a" (lo), "=d" (hi));
+
+  return (((grub_uint64_t) hi) << 32) | lo;
+}
+
+void grub_tsc_calibrate (void);
+
+#endif /* ! KERNEL_CPU_TSC_HEADER */

=== modified file 'include/grub/time.h'
--- include/grub/time.h	2007-10-22 19:02:16 +0000
+++ include/grub/time.h	2008-07-03 04:19:16 +0000
@@ -1,6 +1,6 @@
 /*
  *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 2007  Free Software Foundation, Inc.
+ *  Copyright (C) 2007, 2008  Free Software Foundation, Inc.
  *
  *  GRUB is free software: you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -19,12 +19,13 @@
 #ifndef KERNEL_TIME_HEADER
 #define KERNEL_TIME_HEADER	1
 
+#include <grub/types.h>
 #include <grub/symbol.h>
 #include <grub/machine/time.h>
 #include <grub/cpu/time.h>
 
 void EXPORT_FUNC(grub_millisleep) (grub_uint32_t ms);
-void EXPORT_FUNC(grub_millisleep_generic) (grub_uint32_t ms);
+grub_uint64_t EXPORT_FUNC(grub_get_time_ms) (void);
 
 static __inline void
 grub_sleep (grub_uint32_t s)

=== added directory 'kern/generic'
=== added file 'kern/generic/get_time_ms.c'
--- kern/generic/get_time_ms.c	1970-01-01 00:00:00 +0000
+++ kern/generic/get_time_ms.c	2008-07-04 16:55:48 +0000
@@ -0,0 +1,37 @@
+/* get_time_ms.c - generic time implementation -- using platform RTC.
+ * The generic implementation of these functions can be used for architectures
+ * or platforms that do not have a more specialized implementation. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/time.h>
+#include <grub/misc.h>
+
+/* Calculate the time in milliseconds since the epoch based on the RTC. */
+grub_uint64_t
+grub_get_time_ms (void)
+{
+  /* By dimensional analysis: 
+    
+      1000 ms   N rtc ticks       1 s
+      ------- * ----------- * ----------- = 1000*N/T ms
+        1 s          1        T rtc ticks
+   */
+  grub_uint64_t ticks_ms_per_sec = ((grub_uint64_t) 1000) * grub_get_rtc ();
+  return grub_divmod64 (ticks_ms_per_sec, GRUB_TICKS_PER_SECOND, 0);
+}

=== added file 'kern/generic/millisleep.c'
--- kern/generic/millisleep.c	1970-01-01 00:00:00 +0000
+++ kern/generic/millisleep.c	2008-07-04 16:55:48 +0000
@@ -0,0 +1,39 @@
+/* millisleep.c - generic millisleep function.
+ * The generic implementation of these functions can be used for architectures
+ * or platforms that do not have a more specialized implementation. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/misc.h>
+#include <grub/time.h>
+
+void
+grub_millisleep (grub_uint32_t ms)
+{
+  grub_uint64_t start;
+
+  start = grub_get_time_ms ();
+
+  /* Instead of setting an end time and looping while the current time is 
+     less than that, comparing the elapsed sleep time with the desired sleep
+     time handles the (unlikely!) case that the timer would wrap around 
+     during the sleep. */
+
+  while (grub_get_time_ms () - start < ms)
+    grub_cpu_idle ();
+}

=== modified file 'kern/i386/efi/init.c'
--- kern/i386/efi/init.c	2007-10-22 18:59:33 +0000
+++ kern/i386/efi/init.c	2008-07-04 17:55:21 +0000
@@ -25,18 +25,13 @@
 #include <grub/cache.h>
 #include <grub/kernel.h>
 #include <grub/efi/efi.h>
-#include <grub/time.h>
-
-void
-grub_millisleep (grub_uint32_t ms)
-{
-  grub_millisleep_generic (ms);
-}
+#include <grub/cpu/tsc.h>
 
 void
 grub_machine_init (void)
 {
   grub_efi_init ();
+  grub_tsc_calibrate ();
 }
 
 void

=== modified file 'kern/i386/pc/init.c'
--- kern/i386/pc/init.c	2008-06-15 17:21:16 +0000
+++ kern/i386/pc/init.c	2008-07-04 18:03:26 +0000
@@ -30,6 +30,7 @@
 #include <grub/env.h>
 #include <grub/cache.h>
 #include <grub/time.h>
+#include <grub/cpu/tsc.h>
 
 struct mem_region
 {
@@ -46,12 +47,6 @@
 grub_size_t grub_os_area_size;
 grub_size_t grub_lower_mem, grub_upper_mem;
 
-void
-grub_millisleep (grub_uint32_t ms)
-{
-  grub_millisleep_generic (ms);
-}
-
 void 
 grub_arch_sync_caches (void *address __attribute__ ((unused)),
 		       grub_size_t len __attribute__ ((unused)))
@@ -231,6 +226,8 @@
   
   if (! grub_os_area_addr)
     grub_fatal ("no upper memory");
+
+  grub_tsc_calibrate ();
 }
 
 void

=== added file 'kern/i386/tsc.c'
--- kern/i386/tsc.c	1970-01-01 00:00:00 +0000
+++ kern/i386/tsc.c	2008-07-04 17:55:21 +0000
@@ -0,0 +1,89 @@
+/* kern/i386/tsc.c - x86 TSC time source implementation
+ * Requires Pentium or better x86 CPU that supports the RDTSC instruction.
+ * This module uses the RTC (via grub_get_rtc()) to calibrate the TSC to 
+ * real time.
+ *
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/time.h>
+#include <grub/misc.h>
+#include <grub/i386/tsc.h>
+
+/* Calibrated reference for TSC=0.  This defines the time since the epoch in 
+   milliseconds that TSC=0 refers to. */
+static grub_uint64_t tsc_boot_time;
+
+/* Calibrated TSC rate.  (In TSC ticks per millisecond.) */
+static grub_uint64_t tsc_ticks_per_ms;
+
+
+/* Declared in <grub/time.h>. */
+grub_uint64_t
+grub_get_time_ms (void)
+{
+  return tsc_boot_time + grub_divmod64 (grub_get_tsc (), tsc_ticks_per_ms, 0);
+}
+
+
+/* How many RTC ticks to use for calibration loop. (>= 1) */
+#define CALIBRATION_TICKS 2
+
+/* Calibrate the TSC based on the RTC.  */
+void
+grub_tsc_calibrate (void)
+{
+  /* First calbrate the TSC rate (relative, not absolute time). */
+  grub_uint64_t start_tsc;
+  grub_uint64_t end_tsc;
+  grub_uint32_t initial_tick;
+  grub_uint32_t start_tick;
+  grub_uint32_t end_tick;
+
+  /* Wait for the start of the next tick;
+     we'll base out timing off this edge. */
+  initial_tick = grub_get_rtc ();
+  do
+    {
+      start_tick = grub_get_rtc ();
+    }
+  while (start_tick == initial_tick);
+  start_tsc = grub_get_tsc ();
+
+  /* Wait for the start of the next tick.  This will
+     be the end of the 1-tick period. */
+  do
+    {
+      end_tick = grub_get_rtc ();
+    }
+  while (end_tick - start_tick < CALIBRATION_TICKS);
+  end_tsc = grub_get_tsc ();
+
+  tsc_ticks_per_ms =
+    grub_divmod64 (grub_divmod64
+                   (end_tsc - start_tsc, end_tick - start_tick, 0)
+                   * GRUB_TICKS_PER_SECOND, 1000, 0);
+
+  /* Reference the TSC zero (boot time) to the epoch to 
+     get an absolute real time reference. */
+  grub_uint64_t ms_since_boot = grub_divmod64 (end_tsc, tsc_ticks_per_ms, 0);
+  grub_uint64_t mstime_now = grub_divmod64 ((grub_uint64_t) 1000 * end_tick,
+                                            GRUB_TICKS_PER_SECOND,
+                                            0);
+  tsc_boot_time = mstime_now - ms_since_boot;
+}

=== modified file 'kern/ieee1275/init.c'
--- kern/ieee1275/init.c	2008-07-04 02:01:55 +0000
+++ kern/ieee1275/init.c	2008-07-04 18:06:56 +0000
@@ -47,12 +47,6 @@
 extern char _end[];
 
 void
-grub_millisleep (grub_uint32_t ms)
-{
-  grub_millisleep_generic (ms);
-}
-
-void
 grub_exit (void)
 {
   grub_ieee1275_exit ();
@@ -260,8 +254,8 @@
   grub_console_fini ();
 }
 
-grub_uint32_t
-grub_get_rtc (void)
+grub_uint64_t
+grub_get_time_ms (void)
 {
   grub_uint32_t msecs = 0;
 
@@ -270,6 +264,12 @@
   return msecs;
 }
 
+grub_uint32_t
+grub_get_rtc (void)
+{
+  return grub_get_time_ms ();
+}
+
 grub_addr_t
 grub_arch_modules_addr (void)
 {

=== modified file 'kern/misc.c'
--- kern/misc.c	2008-06-15 23:42:48 +0000
+++ kern/misc.c	2008-07-04 18:03:26 +0000
@@ -23,7 +23,6 @@
 #include <stdarg.h>
 #include <grub/term.h>
 #include <grub/env.h>
-#include <grub/time.h>
 
 void *
 grub_memmove (void *dest, const void *src, grub_size_t n)
@@ -1018,17 +1017,6 @@
   return p - dest;
 }
 
-void
-grub_millisleep_generic (grub_uint32_t ms)
-{
-  grub_uint32_t end_at;
-
-  end_at = grub_get_rtc () + grub_div_roundup (ms * GRUB_TICKS_PER_SECOND, 1000);
-
-  while (grub_get_rtc () < end_at)
-    grub_cpu_idle ();
-}
-
 /* Abort GRUB. This function does not return.  */
 void
 grub_abort (void)

=== modified file 'kern/sparc64/ieee1275/init.c'
--- kern/sparc64/ieee1275/init.c	2007-10-22 18:59:33 +0000
+++ kern/sparc64/ieee1275/init.c	2008-07-04 17:55:21 +0000
@@ -66,12 +66,6 @@
   /* Never reached.  */
 }
 
-void
-grub_millisleep (grub_uint32_t ms)
-{
-  grub_millisleep_generic (ms);
-}
-
 int
 grub_ieee1275_test_flag (enum grub_ieee1275_flag flag)
 {


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC] TSC patch v2
  2008-07-04 18:28   ` [RFC] TSC patch v2 Colin D Bennett
@ 2008-07-04 19:49     ` Vesa Jääskeläinen
  2008-07-04 20:38       ` Colin D Bennett
  2008-07-20 18:45     ` Marco Gerards
  1 sibling, 1 reply; 24+ messages in thread
From: Vesa Jääskeläinen @ 2008-07-04 19:49 UTC (permalink / raw)
  To: The development of GRUB 2

Hi Colin,

Colin D Bennett wrote:
> Here is an updated version of the TSC patch.
> 
> I addressed the issues in your comments with the exception of
> supporting x86 CPUs that don't have a TSC (386 and 486).
> 
> I eliminated the grub_time_init() function and the call to it in
> grub_main() in favor of having grub_machine_init() simply call
> grub_tsc_calibrate().  The i386-pc and i386-efi platforms use the TSC.

Please still use grub_time_init(). Detect TSC, if it is there calibrate 
and adapt for it. If it is not there, use RTC.

grub_time_init() is just more clearer term than tsc. At least for people 
that are not familiar with it. in grub_time_init() you can have anything 
then. And people that are not interested on time stuff do not need to 
bother their heads about it. Also modifying logic afterwards do not 
change other parts and it will be less error prone.

Thanks,
Vesa Jääskeläinen



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC] TSC patch v2
  2008-07-04 19:49     ` Vesa Jääskeläinen
@ 2008-07-04 20:38       ` Colin D Bennett
  2008-07-04 20:48         ` Vesa Jääskeläinen
  0 siblings, 1 reply; 24+ messages in thread
From: Colin D Bennett @ 2008-07-04 20:38 UTC (permalink / raw)
  To: The development of GRUB 2

[-- Attachment #1: Type: text/plain, Size: 2240 bytes --]

On Fri, 04 Jul 2008 22:49:59 +0300
Vesa Jääskeläinen <chaac@nic.fi> wrote:

> Hi Colin,
> 
> Colin D Bennett wrote:
> > Here is an updated version of the TSC patch.
> > 
> > I addressed the issues in your comments with the exception of
> > supporting x86 CPUs that don't have a TSC (386 and 486).
> > 
> > I eliminated the grub_time_init() function and the call to it in
> > grub_main() in favor of having grub_machine_init() simply call
> > grub_tsc_calibrate().  The i386-pc and i386-efi platforms use the
> > TSC.
> 
> Please still use grub_time_init(). Detect TSC, if it is there
> calibrate and adapt for it. If it is not there, use RTC.

Should grub_time_init() be a CPU or machine independent function?
Should it use conditional compilation to be usable on different CPUs?
Or should grub_time_init() be specific to i386 kernels at this point?
(Since we don't have anything to initialize for non-TSC-supporting
platforms.)

If grub_time_init() is specific to the i386 CPU, then grub_time_init()
should check whether the CPU has TSC support, and if so,
grub_tsc_calibrate() should be called, and calls to grub_get_time_ms()
should be directed to the TSC implementation.  If no TSC support is
available, then no calibration is done, and calls to grub_get_time_ms()
should be directed to the generic get_time_ms() implementation that
uses grub_get_rtc() to do its job.

I want to make sure that I clearly understand what you want, since I
have made major re-designs of the TSC support in GRUB in an attempt to
do what you want.  Just in the past couple of days I have spent about 8
hours getting the TSC patch where it is now. (I know that seems
like a lot since it's not that much code, but I am just beginning to get
familiar with the GRUB kernel organization, so simple changes have been
taking me a long time.)

> grub_time_init() is just more clearer term than tsc. At least for
> people that are not familiar with it. in grub_time_init() you can
> have anything then. And people that are not interested on time stuff
> do not need to bother their heads about it. Also modifying logic
> afterwards do not change other parts and it will be less error prone.

OK.

Regards,
Colin

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC] TSC patch v2
  2008-07-04 20:38       ` Colin D Bennett
@ 2008-07-04 20:48         ` Vesa Jääskeläinen
  0 siblings, 0 replies; 24+ messages in thread
From: Vesa Jääskeläinen @ 2008-07-04 20:48 UTC (permalink / raw)
  To: The development of GRUB 2

Colin D Bennett wrote:
> On Fri, 04 Jul 2008 22:49:59 +0300
> Vesa Jääskeläinen <chaac@nic.fi> wrote:
> 
>> Hi Colin,
>>
>> Colin D Bennett wrote:
>>> Here is an updated version of the TSC patch.
>>>
>>> I addressed the issues in your comments with the exception of
>>> supporting x86 CPUs that don't have a TSC (386 and 486).
>>>
>>> I eliminated the grub_time_init() function and the call to it in
>>> grub_main() in favor of having grub_machine_init() simply call
>>> grub_tsc_calibrate().  The i386-pc and i386-efi platforms use the
>>> TSC.
>> Please still use grub_time_init(). Detect TSC, if it is there
>> calibrate and adapt for it. If it is not there, use RTC.
> 
> Should grub_time_init() be a CPU or machine independent function?
> Should it use conditional compilation to be usable on different CPUs?
> Or should grub_time_init() be specific to i386 kernels at this point?
> (Since we don't have anything to initialize for non-TSC-supporting
> platforms.)

In your patch you just change call of grub_tsc_calibrate() to 
grub_time_init(). And in grub_time_init() you check cpuflags if tsc is 
available or not. If tsc is available you call grub_tsc_calibrate(). And 
if you are planning to use function pointers then you set proper 
function pointers accordingly.

> If grub_time_init() is specific to the i386 CPU, then grub_time_init()
> should check whether the CPU has TSC support, and if so,
> grub_tsc_calibrate() should be called, and calls to grub_get_time_ms()
> should be directed to the TSC implementation.  If no TSC support is
> available, then no calibration is done, and calls to grub_get_time_ms()
> should be directed to the generic get_time_ms() implementation that
> uses grub_get_rtc() to do its job.

You can even make it something like:

- check for cpu flags (eg. detect method)
- if tsc, set function pointers rtc (init=tsc, getters=tsc)
- if no tsc set function pointers to rtc (init=rtc, getters=rtc)
- call function pointer init

> I want to make sure that I clearly understand what you want, since I
> have made major re-designs of the TSC support in GRUB in an attempt to
> do what you want.  Just in the past couple of days I have spent about 8
> hours getting the TSC patch where it is now. (I know that seems
> like a lot since it's not that much code, but I am just beginning to get
> familiar with the GRUB kernel organization, so simple changes have been
> taking me a long time.)

Sure... This is why it is good to discuss and design these things on 
mailing list :)




^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC] High resolution time support using x86 TSC
  2008-07-04 17:26   ` Colin D Bennett
@ 2008-07-20 18:21     ` Marco Gerards
  0 siblings, 0 replies; 24+ messages in thread
From: Marco Gerards @ 2008-07-20 18:21 UTC (permalink / raw)
  To: Colin D Bennett; +Cc: The development of GRUB 2

Colin D Bennett <colin@gibibit.com> writes:

> Hi Marco,
>
> On Thu, 03 Jul 2008 20:52:53 +0200
> Marco Gerards <mgerards@xs4all.nl> wrote:
>
>> Hi Colin,
>> 
>> Colin D Bennett <colin@gibibit.com> writes:
>> 
>> > I have implemented high resolution time support (through the
>> > new grub_get_time_ms() function) using the RDTSC instruction
>> > available on Pentium and higher x86 CPUs.  The TSC value is simply
>> > a 64-bit block cycle counter that is zeroed at bootup, so
>> > grub_main() calls grub_time_init(), which is defined by each
>> > platform.  If a platform links to kern/i386/tsc.c, then the
>> > grub_time_init() function from tsc.c is used, which calibrates the
>> > TSC rate and absolute zero reference using the RTC.
>> What if TSC is not available?
>
> I updated the changelog entry to indicate that running on a 386 or 486
> will fail, since TSC is provided in Pentium+.  Do we support running on
> 386 or 386?  Should I check for this?  If so, the code will have to
> change a bit, and be able to select between the generic implementation
> and the TSC implementation at runtime.
>
> I think this would be best done letting the "grub_get_time_ms"
> implementation be selected by setting a function pointer in
> grub_machine_init() depending on the machine's capabilities.  I would
> have to significantly re-structure my patch, but it might be
> necessary (and could lead to more understandable code?).
> What do you think?

That would be great.  I do not want to drop 486 support just because
of this.  You could even drop back to a lower granularity of the timer
or better: submit code that does the trick for the 486 as well.

--
Marco
 




^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC] TSC patch v2
  2008-07-04 18:28   ` [RFC] TSC patch v2 Colin D Bennett
  2008-07-04 19:49     ` Vesa Jääskeläinen
@ 2008-07-20 18:45     ` Marco Gerards
  2008-07-28 17:05       ` [PATCH] High resolution time/TSC patch v3 Colin D Bennett
  1 sibling, 1 reply; 24+ messages in thread
From: Marco Gerards @ 2008-07-20 18:45 UTC (permalink / raw)
  To: Colin D Bennett; +Cc: The development of GRUB 2

Colin D Bennett <colin@gibibit.com> writes:

> Here is an updated version of the TSC patch.
>
> I addressed the issues in your comments with the exception of
> supporting x86 CPUs that don't have a TSC (386 and 486).
>
> I eliminated the grub_time_init() function and the call to it in
> grub_main() in favor of having grub_machine_init() simply call
> grub_tsc_calibrate().  The i386-pc and i386-efi platforms use the TSC.
>
> I also changed the grub_millisleep() generic function to use
> grub_get_time_ms() instead of grub_get_rtc() to achieve better
> precision when a higher resolution time function is available.
>
> Please take a look at it and give me your comments when you have a
> chance.  Thanks!


Great!  Sorry I kept you waiting...

> === modified file 'ChangeLog'
> --- ChangeLog	2008-07-04 02:26:10 +0000
> +++ ChangeLog	2008-07-04 18:08:36 +0000
> @@ -1,3 +1,70 @@
> +2008-07-04  Colin D Bennett <colin@gibibit.com>
> +
> +	High resolution timer support.  Implemented for i386 CPU using TSC.
> +	Extracted generic grub_millisleep() so it's linked in only as needed.
> +	This requires a Pentium compatible CPU; currently the code does not
> +	check for this (so it will fail on 386 and 486 machines).

We really need to keep the current machines working.  If you will drop
support for something, please don't do it in a patch but in a separate
discussion so no one will miss it.  But please, I do not think it will
be that hard to keep this.

> +	* conf/i386-efi.rmk: Added TSC high resolution time module, link with
> +	generic grub_millisleep() function.
> +
> +	* conf/i386-pc.rmk: Likewise.
> +
> +	* conf/sparc64-ieee1275.rmk: Add kern/generic/millisleep.c and
> +	kern/generic/get_time_ms.c to kernel, to use generic time functions.
> +
> +	* conf/powerpc-ieee1275.rmk: Add kern/generic/millisleep.c to kernel,
> +	to use generic grub_millisleep() function.
> +
> +	* conf/i386-linuxbios.rmk: Added kern/generic/get_time_ms.c to the
> +	kernel.

Please describe where you change things.  Just have a look at existing
changelog entries how this was done.

> +	* kern/generic/get_time_ms.c (grub_get_time_ms): New file.  Platform
> +	independent implementation of grub_get_time_ms() using the RTC that
> +	can be linked into a platform's kernel when it does not implement its
> +	own specialized grub_get_time_ms() function.

"New file." is sufficient.

> +	* kern/generic/millisleep.c (grub_millisleep): New file.  Extracted
> +	from grub_millisleep_generic() in kern/misc.c and renamed.  Changed it
> +	to use grub_get_time_ms() instead of grub_get_rtc() for better
> +	precision on when high resolution time is available.

Same here.

> +	* kern/misc.c (grub_millisleep_generic): Deleted.  Moved to
> +	kern/generic/millisleep.c so that it is only included in the kernel
> +	image when a platform does not define a specialized version.

"Deleted." is sufficient.  Or better "Removed.", just because most
people use it :-)

> +	* commands/sleep.c (grub_interruptible_millisleep): Uses
> +	grub_get_time_ms() instead of grub_get_rtc() to stay in sync with
> +	grub_millisleep() from kern/generic/millisleep.c.
> +
> +	* include/grub/i386/tsc.h (grub_get_tsc): New file.  Inline function
> +	grub_get_tsc() uses x86 RDTSC instruction (available on Pentium+ CPUs)
> +	to read the counter value for the TSC.
> +	(grub_tsc_calibrate): Declare this function for grub_machine_init().

Same as above.

> +	* kern/i386/tsc.c (grub_get_time_ms): x86 TSC support providing a high
> +	resolution clock.

I would simply say: "New function."

> +	(grub_tsc_calibrate): New function to calibrate the TSC using RTC.

No need to explain what it does.

> +	* include/grub/time.h (grub_get_time_ms): Added grub_get_time_ms()
> +	function to return the current time in millseconds since the epoch.
> +	This supports higher resolution time than grub_get_rtc() on some
> +	platforms such as i386-pc, where the RTC has only about 1/18 s
> +	precision but a higher precision timer such as the TSC is available.

Perhaps: "New prototype."

You forgot to mention you included <grub/types.h>.  Please make sure
you mention all other inclusions of header files you added as well.

> +	* kern/i386/efi/init.c (grub_millisleep): Deleted.  Don't define
> +	grub_millisleep() -- it just called grub_millisleep_generic() but now
> +	it is linked to kern/generic/millisleep.c for the implementation.

Only "Removed." will be sufficient.

> +	* kern/sparc64/ieee1275/init.c (grub_millisleep): Deleted.

Hurray! ;-)

> +	* kern/i386/pc/init.c (grub_machine_init): Call grub_tsc_calibrate().
> +	(grub_millisleep): Deleted.
> +
> +	* kern/ieee1275/init.c (grub_millisleep): Deleted.
> +	(grub_get_rtc): Now calls grub_get_time_ms(), which does the real
> +	work.

As you can see from my comments, you do not have to say what something
does in the changelog entry.  Our changelog entries log changes only,
not the rationale why it was changed, that should perhaps go into
comments inside the sourcecode.  If you want, you can explain why you
made the changes at the beginning of the changelog entry (although I
wouldn't use it for any change), like you did. :-)

I noticed a few changes that were not in the Changelog entry.  Can you
please make sure everything is in the changelog entry?  If the
ChangeLog does not exactly describe what changed in the patch, it will
become harder for me to review the patch...

>  2008-07-04  Pavel Roskin  <proski@gnu.org>
>  
>  	* kern/i386/linuxbios/init.c (grub_machine_init): Cast addr to
>
> === modified file 'commands/sleep.c'
> --- commands/sleep.c	2008-05-16 20:55:29 +0000
> +++ commands/sleep.c	2008-07-04 16:55:48 +0000
> @@ -43,15 +43,15 @@
>    grub_printf ("%d    ", n);
>  }
>  
> -/* Based on grub_millisleep() from kern/misc.c.  */
> +/* Based on grub_millisleep() from kern/generic/millisleep.c.  */
>  static int
>  grub_interruptible_millisleep (grub_uint32_t ms)
>  {
> -  grub_uint32_t end_at;
> -  
> -  end_at = grub_get_rtc () + grub_div_roundup (ms * GRUB_TICKS_PER_SECOND, 1000);
> -  
> -  while (grub_get_rtc () < end_at)
> +  grub_uint64_t start;
> +
> +  start = grub_get_time_ms ();
> +
> +  while (grub_get_time_ms () - start < ms)
>      if (grub_checkkey () >= 0 &&
>  	GRUB_TERM_ASCII_CHAR (grub_getkey ()) == GRUB_TERM_ESC)
>        return 1;
>
> === modified file 'conf/i386-efi.rmk'
> --- conf/i386-efi.rmk	2008-06-19 04:14:16 +0000
> +++ conf/i386-efi.rmk	2008-07-03 04:19:16 +0000
> @@ -84,7 +84,9 @@
>  	kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \
>  	kern/i386/dl.c kern/i386/efi/init.c kern/parser.c kern/partition.c \
>  	kern/env.c symlist.c kern/efi/efi.c kern/efi/init.c kern/efi/mm.c \
> -	term/efi/console.c disk/efi/efidisk.c
> +	term/efi/console.c disk/efi/efidisk.c \
> +	kern/i386/tsc.c \
> +	kern/generic/millisleep.c
>  kernel_mod_HEADERS = arg.h boot.h cache.h device.h disk.h dl.h elf.h elfload.h \
>  	env.h err.h file.h fs.h kernel.h loader.h misc.h mm.h net.h parser.h \
>  	partition.h pc_partition.h rescue.h symbol.h term.h time.h types.h \
>
> === modified file 'conf/i386-linuxbios.rmk'
> --- conf/i386-linuxbios.rmk	2008-06-19 04:14:16 +0000
> +++ conf/i386-linuxbios.rmk	2008-07-04 16:55:48 +0000
> @@ -18,6 +18,7 @@
>  	kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \
>  	kern/i386/dl.c kern/parser.c kern/partition.c \
>  	kern/env.c \
> +	kern/generic/get_time_ms.c \
>  	term/i386/pc/console.c \
>  	term/i386/pc/at_keyboard.c term/i386/pc/vga_text.c \
>  	symlist.c
>
> === modified file 'conf/i386-pc.rmk'
> --- conf/i386-pc.rmk	2008-06-19 04:14:16 +0000
> +++ conf/i386-pc.rmk	2008-07-03 04:19:16 +0000
> @@ -43,6 +43,8 @@
>  	kern/disk.c kern/dl.c kern/file.c kern/fs.c kern/err.c \
>  	kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \
>  	kern/i386/dl.c kern/i386/pc/init.c kern/parser.c kern/partition.c \
> +	kern/i386/tsc.c \
> +	kern/generic/millisleep.c \
>  	kern/env.c \
>  	term/i386/pc/console.c \
>  	symlist.c
>
> === modified file 'conf/powerpc-ieee1275.rmk'
> --- conf/powerpc-ieee1275.rmk	2008-06-19 04:14:16 +0000
> +++ conf/powerpc-ieee1275.rmk	2008-07-03 04:19:16 +0000
> @@ -85,6 +85,7 @@
>  	kern/ieee1275/init.c term/ieee1275/ofconsole.c 		\
>  	kern/ieee1275/openfw.c disk/ieee1275/ofdisk.c 		\
>  	kern/parser.c kern/partition.c kern/env.c kern/powerpc/dl.c 	\
> +	kern/generic/millisleep.c                                       \
>  	symlist.c kern/powerpc/cache.S
>  kernel_elf_HEADERS = grub/powerpc/ieee1275/ieee1275.h
>  kernel_elf_CFLAGS = $(COMMON_CFLAGS)
>
> === modified file 'conf/sparc64-ieee1275.rmk'
> --- conf/sparc64-ieee1275.rmk	2008-06-19 00:04:59 +0000
> +++ conf/sparc64-ieee1275.rmk	2008-07-03 04:19:16 +0000
> @@ -73,6 +73,7 @@
>  	kern/rescue.c kern/term.c term/ieee1275/ofconsole.c \
>  	kern/sparc64/ieee1275/openfw.c disk/ieee1275/ofdisk.c \
>  	kern/partition.c kern/env.c kern/sparc64/dl.c symlist.c \
> +	kern/generic/millisleep.c kern/generic/get_time_ms.c \
>  	kern/sparc64/cache.S kern/parser.c
>  kernel_elf_HEADERS = grub/sparc64/ieee1275/ieee1275.h
>  kernel_elf_CFLAGS = $(COMMON_CFLAGS)
>
> === added file 'include/grub/i386/tsc.h'
> --- include/grub/i386/tsc.h	1970-01-01 00:00:00 +0000
> +++ include/grub/i386/tsc.h	2008-07-04 17:55:21 +0000
> @@ -0,0 +1,43 @@
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2008  Free Software Foundation, Inc.
> + *
> + *  GRUB is free software: you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation, either version 3 of the License, or
> + *  (at your option) any later version.
> + *
> + *  GRUB is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef KERNEL_CPU_TSC_HEADER
> +#define KERNEL_CPU_TSC_HEADER	1
> +
> +#include <grub/types.h>
> +
> +/* Read the TSC value, which increments with each CPU clock cycle. */

Very minor nitpick, but for consistency.  After a "." we insert two
spaces.

> +static __inline grub_uint64_t
> +grub_get_tsc (void)
> +{
> +  grub_uint32_t lo, hi;
> +
> +  /* The CPUID instruction is a 'serializing' instruction, and
> +     avoids out-of-order execution of the RDTSC instruction. */
> +  __asm__ __volatile__ ("xorl %%eax, %%eax\n\t"
> +                        "cpuid":::"%rax", "%rbx", "%rcx", "%rdx");
> +  /* Read TSC value.  We cannot use "=A", since this would use
> +     %rax on x86_64. */
> +  __asm__ __volatile__ ("rdtsc":"=a" (lo), "=d" (hi));
> +
> +  return (((grub_uint64_t) hi) << 32) | lo;
> +}
> +
> +void grub_tsc_calibrate (void);
> +
> +#endif /* ! KERNEL_CPU_TSC_HEADER */
>
> === modified file 'include/grub/time.h'
> --- include/grub/time.h	2007-10-22 19:02:16 +0000
> +++ include/grub/time.h	2008-07-03 04:19:16 +0000
> @@ -1,6 +1,6 @@
>  /*
>   *  GRUB  --  GRand Unified Bootloader
> - *  Copyright (C) 2007  Free Software Foundation, Inc.
> + *  Copyright (C) 2007, 2008  Free Software Foundation, Inc.
>   *
>   *  GRUB is free software: you can redistribute it and/or modify
>   *  it under the terms of the GNU General Public License as published by
> @@ -19,12 +19,13 @@
>  #ifndef KERNEL_TIME_HEADER
>  #define KERNEL_TIME_HEADER	1
>  
> +#include <grub/types.h>

You forgot this in the ChangeLog entry.

>  #include <grub/symbol.h>
>  #include <grub/machine/time.h>
>  #include <grub/cpu/time.h>
>  
>  void EXPORT_FUNC(grub_millisleep) (grub_uint32_t ms);
> -void EXPORT_FUNC(grub_millisleep_generic) (grub_uint32_t ms);
> +grub_uint64_t EXPORT_FUNC(grub_get_time_ms) (void);
>  
>  static __inline void
>  grub_sleep (grub_uint32_t s)
>
> === added directory 'kern/generic'
> === added file 'kern/generic/get_time_ms.c'
> --- kern/generic/get_time_ms.c	1970-01-01 00:00:00 +0000
> +++ kern/generic/get_time_ms.c	2008-07-04 16:55:48 +0000
> @@ -0,0 +1,37 @@
> +/* get_time_ms.c - generic time implementation -- using platform RTC.
> + * The generic implementation of these functions can be used for architectures
> + * or platforms that do not have a more specialized implementation. */
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2008  Free Software Foundation, Inc.
> + *
> + *  GRUB is free software: you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation, either version 3 of the License, or
> + *  (at your option) any later version.
> + *
> + *  GRUB is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <grub/time.h>
> +#include <grub/misc.h>
> +
> +/* Calculate the time in milliseconds since the epoch based on the RTC. */
> +grub_uint64_t
> +grub_get_time_ms (void)
> +{
> +  /* By dimensional analysis: 
> +    
> +      1000 ms   N rtc ticks       1 s
> +      ------- * ----------- * ----------- = 1000*N/T ms
> +        1 s          1        T rtc ticks
> +   */
> +  grub_uint64_t ticks_ms_per_sec = ((grub_uint64_t) 1000) * grub_get_rtc ();
> +  return grub_divmod64 (ticks_ms_per_sec, GRUB_TICKS_PER_SECOND, 0);
> +}
>
> === added file 'kern/generic/millisleep.c'
> --- kern/generic/millisleep.c	1970-01-01 00:00:00 +0000
> +++ kern/generic/millisleep.c	2008-07-04 16:55:48 +0000
> @@ -0,0 +1,39 @@
> +/* millisleep.c - generic millisleep function.
> + * The generic implementation of these functions can be used for architectures
> + * or platforms that do not have a more specialized implementation. */
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008  Free Software Foundation, Inc.
> + *
> + *  GRUB is free software: you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation, either version 3 of the License, or
> + *  (at your option) any later version.
> + *
> + *  GRUB is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <grub/misc.h>
> +#include <grub/time.h>
> +
> +void
> +grub_millisleep (grub_uint32_t ms)
> +{
> +  grub_uint64_t start;
> +
> +  start = grub_get_time_ms ();
> +
> +  /* Instead of setting an end time and looping while the current time is 
> +     less than that, comparing the elapsed sleep time with the desired sleep
> +     time handles the (unlikely!) case that the timer would wrap around 
> +     during the sleep. */
> +
> +  while (grub_get_time_ms () - start < ms)
> +    grub_cpu_idle ();
> +}
>
> === modified file 'kern/i386/efi/init.c'
> --- kern/i386/efi/init.c	2007-10-22 18:59:33 +0000
> +++ kern/i386/efi/init.c	2008-07-04 17:55:21 +0000
> @@ -25,18 +25,13 @@
>  #include <grub/cache.h>
>  #include <grub/kernel.h>
>  #include <grub/efi/efi.h>
> -#include <grub/time.h>

Did you mention this in the changelog entry?

> -
> -void
> -grub_millisleep (grub_uint32_t ms)
> -{
> -  grub_millisleep_generic (ms);
> -}
> +#include <grub/cpu/tsc.h>
>  
>  void
>  grub_machine_init (void)
>  {
>    grub_efi_init ();
> +  grub_tsc_calibrate ();
>  }

You forgot this one too.

>  void
>
> === modified file 'kern/i386/pc/init.c'
> --- kern/i386/pc/init.c	2008-06-15 17:21:16 +0000
> +++ kern/i386/pc/init.c	2008-07-04 18:03:26 +0000
> @@ -30,6 +30,7 @@
>  #include <grub/env.h>
>  #include <grub/cache.h>
>  #include <grub/time.h>
> +#include <grub/cpu/tsc.h>
>  
>  struct mem_region
>  {
> @@ -46,12 +47,6 @@
>  grub_size_t grub_os_area_size;
>  grub_size_t grub_lower_mem, grub_upper_mem;
>  
> -void
> -grub_millisleep (grub_uint32_t ms)
> -{
> -  grub_millisleep_generic (ms);
> -}
> -
>  void 
>  grub_arch_sync_caches (void *address __attribute__ ((unused)),
>  		       grub_size_t len __attribute__ ((unused)))
> @@ -231,6 +226,8 @@
>    
>    if (! grub_os_area_addr)
>      grub_fatal ("no upper memory");
> +
> +  grub_tsc_calibrate ();
>  }

This looks weird...  Which function did you change here and did you
mention it in the changelog entry?  Did you use "diff -up"?

>  void
>
> === added file 'kern/i386/tsc.c'
> --- kern/i386/tsc.c	1970-01-01 00:00:00 +0000
> +++ kern/i386/tsc.c	2008-07-04 17:55:21 +0000
> @@ -0,0 +1,89 @@
> +/* kern/i386/tsc.c - x86 TSC time source implementation
> + * Requires Pentium or better x86 CPU that supports the RDTSC instruction.
> + * This module uses the RTC (via grub_get_rtc()) to calibrate the TSC to 
> + * real time.
> + *
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2008  Free Software Foundation, Inc.
> + *
> + *  GRUB is free software: you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation, either version 3 of the License, or
> + *  (at your option) any later version.
> + *
> + *  GRUB is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <grub/types.h>
> +#include <grub/time.h>
> +#include <grub/misc.h>
> +#include <grub/i386/tsc.h>
> +
> +/* Calibrated reference for TSC=0.  This defines the time since the epoch in 
> +   milliseconds that TSC=0 refers to. */
> +static grub_uint64_t tsc_boot_time;
> +
> +/* Calibrated TSC rate.  (In TSC ticks per millisecond.) */
> +static grub_uint64_t tsc_ticks_per_ms;
> +
> +
> +/* Declared in <grub/time.h>. */
> +grub_uint64_t
> +grub_get_time_ms (void)
> +{
> +  return tsc_boot_time + grub_divmod64 (grub_get_tsc (), tsc_ticks_per_ms, 0);
> +}
> +
> +
> +/* How many RTC ticks to use for calibration loop. (>= 1) */
> +#define CALIBRATION_TICKS 2
> +
> +/* Calibrate the TSC based on the RTC.  */
> +void
> +grub_tsc_calibrate (void)
> +{
> +  /* First calbrate the TSC rate (relative, not absolute time). */
> +  grub_uint64_t start_tsc;
> +  grub_uint64_t end_tsc;
> +  grub_uint32_t initial_tick;
> +  grub_uint32_t start_tick;
> +  grub_uint32_t end_tick;
> +
> +  /* Wait for the start of the next tick;
> +     we'll base out timing off this edge. */
> +  initial_tick = grub_get_rtc ();
> +  do
> +    {
> +      start_tick = grub_get_rtc ();
> +    }
> +  while (start_tick == initial_tick);
> +  start_tsc = grub_get_tsc ();
> +
> +  /* Wait for the start of the next tick.  This will
> +     be the end of the 1-tick period. */
> +  do
> +    {
> +      end_tick = grub_get_rtc ();
> +    }
> +  while (end_tick - start_tick < CALIBRATION_TICKS);
> +  end_tsc = grub_get_tsc ();
> +
> +  tsc_ticks_per_ms =
> +    grub_divmod64 (grub_divmod64
> +                   (end_tsc - start_tsc, end_tick - start_tick, 0)
> +                   * GRUB_TICKS_PER_SECOND, 1000, 0);
> +
> +  /* Reference the TSC zero (boot time) to the epoch to 
> +     get an absolute real time reference. */
> +  grub_uint64_t ms_since_boot = grub_divmod64 (end_tsc, tsc_ticks_per_ms, 0);
> +  grub_uint64_t mstime_now = grub_divmod64 ((grub_uint64_t) 1000 * end_tick,
> +                                            GRUB_TICKS_PER_SECOND,
> +                                            0);
> +  tsc_boot_time = mstime_now - ms_since_boot;
> +}
>
> === modified file 'kern/ieee1275/init.c'
> --- kern/ieee1275/init.c	2008-07-04 02:01:55 +0000
> +++ kern/ieee1275/init.c	2008-07-04 18:06:56 +0000
> @@ -47,12 +47,6 @@
>  extern char _end[];
>  
>  void
> -grub_millisleep (grub_uint32_t ms)
> -{
> -  grub_millisleep_generic (ms);
> -}
> -
> -void
>  grub_exit (void)
>  {
>    grub_ieee1275_exit ();
> @@ -260,8 +254,8 @@
>    grub_console_fini ();
>  }
>  
> -grub_uint32_t
> -grub_get_rtc (void)
> +grub_uint64_t
> +grub_get_time_ms (void)
>  {
>    grub_uint32_t msecs = 0;
>  
> @@ -270,6 +264,12 @@
>    return msecs;
>  }
>  
> +grub_uint32_t
> +grub_get_rtc (void)
> +{
> +  return grub_get_time_ms ();
> +}
> +
>  grub_addr_t
>  grub_arch_modules_addr (void)
>  {
>
> === modified file 'kern/misc.c'
> --- kern/misc.c	2008-06-15 23:42:48 +0000
> +++ kern/misc.c	2008-07-04 18:03:26 +0000
> @@ -23,7 +23,6 @@
>  #include <stdarg.h>
>  #include <grub/term.h>
>  #include <grub/env.h>
> -#include <grub/time.h>
>  
>  void *
>  grub_memmove (void *dest, const void *src, grub_size_t n)
> @@ -1018,17 +1017,6 @@
>    return p - dest;
>  }
>  
> -void
> -grub_millisleep_generic (grub_uint32_t ms)
> -{
> -  grub_uint32_t end_at;
> -
> -  end_at = grub_get_rtc () + grub_div_roundup (ms * GRUB_TICKS_PER_SECOND, 1000);
> -
> -  while (grub_get_rtc () < end_at)
> -    grub_cpu_idle ();
> -}
> -
>  /* Abort GRUB. This function does not return.  */
>  void
>  grub_abort (void)
>
> === modified file 'kern/sparc64/ieee1275/init.c'
> --- kern/sparc64/ieee1275/init.c	2007-10-22 18:59:33 +0000
> +++ kern/sparc64/ieee1275/init.c	2008-07-04 17:55:21 +0000
> @@ -66,12 +66,6 @@
>    /* Never reached.  */
>  }
>  
> -void
> -grub_millisleep (grub_uint32_t ms)
> -{
> -  grub_millisleep_generic (ms);
> -}
> -
>  int
>  grub_ieee1275_test_flag (enum grub_ieee1275_flag flag)
>  {




^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH] High resolution time/TSC patch v3
  2008-07-20 18:45     ` Marco Gerards
@ 2008-07-28 17:05       ` Colin D Bennett
  2008-07-28 17:59         ` Robert Millan
                           ` (3 more replies)
  0 siblings, 4 replies; 24+ messages in thread
From: Colin D Bennett @ 2008-07-28 17:05 UTC (permalink / raw)
  To: The development of GRUB 2, Robert Millan


[-- Attachment #1.1: Type: text/plain, Size: 376 bytes --]

Another updated TSC patch.  Now it detects TSC support for x86 CPUs at
runtime and selects either the TSC or RTC time source.  This way 386
and 486 CPUs without RDTSC instruction support are supported.

Robert Millan was interested in getting this patch merged for the
Coreboot port, so I decided to take another crack at it.

Comments are welcome!

Regards,
Colin

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: tsc_2008-07-28.patch --]
[-- Type: text/x-patch; name=tsc_2008-07-28.patch, Size: 23781 bytes --]

=== modified file 'ChangeLog'
--- ChangeLog	2008-07-27 19:57:43 +0000
+++ ChangeLog	2008-07-28 16:51:30 +0000
@@ -1,3 +1,68 @@
+2008-07-28  Colin D Bennett <colin@gibibit.com>
+
+	High resolution timer support.  Implemented for x86 CPUs using TSC.
+	Extracted generic grub_millisleep() so it's linked in only as needed.
+	This requires a Pentium compatible CPU; if the RDTSC instruction is
+	not supported, then it falls back on the generic grub_get_time_ms()
+	implementation that uses the machine's RTC.
+
+	* conf/i386-efi.rmk: Added new source files to kernel_elf_SOURCES.
+
+	* conf/i386-pc.rmk: Likewise.
+
+	* conf/sparc64-ieee1275.rmk: Likewise.
+
+	* conf/powerpc-ieee1275.rmk: Likewise.
+
+	* conf/i386-coreboot.rmk: Likewise.
+
+	* kern/generic/rtc_get_time_ms.c: New file.
+
+	* kern/generic/millisleep.c: New file.
+
+	* kern/misc.c (grub_millisleep_generic): Removed.
+
+	* commands/sleep.c (grub_interruptible_millisleep): Uses
+	grub_get_time_ms() instead of grub_get_rtc() to stay in sync with
+	grub_millisleep() from kern/generic/millisleep.c.
+
+	* include/grub/i386/tsc.h (grub_get_tsc): New file.  New inline
+	function.
+	(grub_cpu_is_cpuid_supported): New inline function.
+	(grub_cpu_is_tsc_supported): New inline function.
+	(grub_tsc_init): New function prototype.
+	(grub_tsc_get_time_ms): New function prototype.
+
+	* kern/i386/tsc.c (grub_get_time_ms): New file.  New function.
+	(calibrate_tsc): New static function.
+	(grub_tsc_init): New function.
+
+	* include/grub/time.h (grub_millisleep_generic): Removed.
+	(grub_get_time_ms): New function.
+	(grub_install_get_time_ms): New function.
+
+	* kern/time.c (grub_get_time_ms): New function.
+	(grub_install_get_time_ms): New function.
+
+	* kern/i386/efi/init.c (grub_millisleep): Removed.
+	(grub_machine_init): Call grub_tsc_init.
+
+	* kern/i386/linuxbios/init.c (grub_machine_init): Install the RTC
+	get_time_ms() implementation.
+
+	* kern/sparc64/ieee1275/init.c (grub_millisleep): Removed.
+	(ieee1275_get_time_ms): New function.
+	(grub_machine_init): Install get_time_ms() implementation.
+
+	* kern/i386/pc/init.c (grub_machine_init): Call grub_tsc_init().
+	(grub_millisleep): Removed.
+
+	* kern/ieee1275/init.c (grub_millisleep): Removed.
+	(grub_machine_init): Install ieee1275_get_time_ms() implementation.
+	(ieee1275_get_time_ms): New static function.
+	(grub_get_rtc): Now calls ieee1275_get_time_ms(), which does the real
+	work.
+
 2008-07-27  Robert Millan  <rmh@aybabtu.com>
 
 	* disk/ata.c (grub_ata_dumpinfo): Use grub_dprintf() for debugging

=== modified file 'commands/sleep.c'
--- commands/sleep.c	2008-05-16 20:55:29 +0000
+++ commands/sleep.c	2008-07-04 16:55:48 +0000
@@ -43,15 +43,15 @@
   grub_printf ("%d    ", n);
 }
 
-/* Based on grub_millisleep() from kern/misc.c.  */
+/* Based on grub_millisleep() from kern/generic/millisleep.c.  */
 static int
 grub_interruptible_millisleep (grub_uint32_t ms)
 {
-  grub_uint32_t end_at;
-  
-  end_at = grub_get_rtc () + grub_div_roundup (ms * GRUB_TICKS_PER_SECOND, 1000);
-  
-  while (grub_get_rtc () < end_at)
+  grub_uint64_t start;
+
+  start = grub_get_time_ms ();
+
+  while (grub_get_time_ms () - start < ms)
     if (grub_checkkey () >= 0 &&
 	GRUB_TERM_ASCII_CHAR (grub_getkey ()) == GRUB_TERM_ESC)
       return 1;

=== modified file 'conf/i386-coreboot.rmk'
--- conf/i386-coreboot.rmk	2008-07-27 12:51:30 +0000
+++ conf/i386-coreboot.rmk	2008-07-28 16:23:46 +0000
@@ -16,6 +16,7 @@
 	kern/main.c kern/device.c \
 	kern/disk.c kern/dl.c kern/file.c kern/fs.c kern/err.c \
 	kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \
+	kern/time.c \
 	kern/i386/dl.c kern/parser.c kern/partition.c \
 	kern/env.c \
 	term/i386/pc/console.c \

=== modified file 'conf/i386-efi.rmk'
--- conf/i386-efi.rmk	2008-07-27 12:51:30 +0000
+++ conf/i386-efi.rmk	2008-07-28 16:23:46 +0000
@@ -84,7 +84,10 @@
 	kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \
 	kern/i386/dl.c kern/i386/efi/init.c kern/parser.c kern/partition.c \
 	kern/env.c symlist.c kern/efi/efi.c kern/efi/init.c kern/efi/mm.c \
-	term/efi/console.c disk/efi/efidisk.c
+	term/efi/console.c disk/efi/efidisk.c \
+	kern/i386/tsc.c \
+	kern/generic/rtc_get_time_ms.c \
+	kern/generic/millisleep.c
 kernel_mod_HEADERS = arg.h boot.h cache.h device.h disk.h dl.h elf.h elfload.h \
 	env.h err.h file.h fs.h kernel.h loader.h misc.h mm.h net.h parser.h \
 	partition.h pc_partition.h rescue.h symbol.h term.h time.h types.h \

=== modified file 'conf/i386-ieee1275.rmk'
--- conf/i386-ieee1275.rmk	2008-07-27 12:51:30 +0000
+++ conf/i386-ieee1275.rmk	2008-07-28 16:23:46 +0000
@@ -19,6 +19,7 @@
 	kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \
 	kern/i386/dl.c kern/parser.c kern/partition.c \
 	kern/env.c \
+	kern/generic/millisleep.c \
 	kern/ieee1275/ieee1275.c \
 	term/ieee1275/ofconsole.c term/i386/pc/at_keyboard.c \
 	disk/ieee1275/ofdisk.c \

=== modified file 'conf/i386-pc.rmk'
--- conf/i386-pc.rmk	2008-07-27 12:51:30 +0000
+++ conf/i386-pc.rmk	2008-07-28 16:23:46 +0000
@@ -42,7 +42,11 @@
 kernel_img_SOURCES = kern/i386/pc/startup.S kern/main.c kern/device.c \
 	kern/disk.c kern/dl.c kern/file.c kern/fs.c kern/err.c \
 	kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \
+	kern/time.c \
 	kern/i386/dl.c kern/i386/pc/init.c kern/parser.c kern/partition.c \
+	kern/i386/tsc.c \
+	kern/generic/rtc_get_time_ms.c \
+	kern/generic/millisleep.c \
 	kern/env.c \
 	term/i386/pc/console.c \
 	symlist.c

=== modified file 'conf/powerpc-ieee1275.rmk'
--- conf/powerpc-ieee1275.rmk	2008-07-27 12:51:30 +0000
+++ conf/powerpc-ieee1275.rmk	2008-07-28 13:59:50 +0000
@@ -85,6 +85,7 @@
 	kern/ieee1275/init.c term/ieee1275/ofconsole.c 		\
 	kern/ieee1275/openfw.c disk/ieee1275/ofdisk.c 		\
 	kern/parser.c kern/partition.c kern/env.c kern/powerpc/dl.c 	\
+	kern/generic/millisleep.c                                       \
 	symlist.c kern/powerpc/cache.S
 kernel_elf_HEADERS = grub/powerpc/ieee1275/ieee1275.h
 kernel_elf_CFLAGS = $(COMMON_CFLAGS)

=== modified file 'conf/sparc64-ieee1275.rmk'
--- conf/sparc64-ieee1275.rmk	2008-06-19 00:04:59 +0000
+++ conf/sparc64-ieee1275.rmk	2008-07-03 04:19:16 +0000
@@ -73,6 +73,7 @@
 	kern/rescue.c kern/term.c term/ieee1275/ofconsole.c \
 	kern/sparc64/ieee1275/openfw.c disk/ieee1275/ofdisk.c \
 	kern/partition.c kern/env.c kern/sparc64/dl.c symlist.c \
+	kern/generic/millisleep.c kern/generic/get_time_ms.c \
 	kern/sparc64/cache.S kern/parser.c
 kernel_elf_HEADERS = grub/sparc64/ieee1275/ieee1275.h
 kernel_elf_CFLAGS = $(COMMON_CFLAGS)

=== modified file 'conf/x86_64-efi.rmk'
--- conf/x86_64-efi.rmk	2008-07-27 12:51:30 +0000
+++ conf/x86_64-efi.rmk	2008-07-28 16:23:46 +0000
@@ -87,6 +87,7 @@
 	kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \
 	kern/x86_64/dl.c kern/i386/efi/init.c kern/parser.c kern/partition.c \
 	kern/env.c symlist.c kern/efi/efi.c kern/efi/init.c kern/efi/mm.c \
+	kern/generic/millisleep.c kern/generic/rtc_get_time_ms.c \
 	term/efi/console.c disk/efi/efidisk.c
 kernel_mod_HEADERS = arg.h boot.h cache.h device.h disk.h dl.h elf.h elfload.h \
 	env.h err.h file.h fs.h kernel.h loader.h misc.h mm.h net.h parser.h \

=== added file 'include/grub/i386/tsc.h'
--- include/grub/i386/tsc.h	1970-01-01 00:00:00 +0000
+++ include/grub/i386/tsc.h	2008-07-28 16:23:46 +0000
@@ -0,0 +1,80 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef KERNEL_CPU_TSC_HEADER
+#define KERNEL_CPU_TSC_HEADER   1
+
+#include <grub/types.h>
+
+/* Read the TSC value, which increments with each CPU clock cycle. */
+static __inline grub_uint64_t
+grub_get_tsc (void)
+{
+  grub_uint32_t lo, hi;
+
+  /* The CPUID instruction is a 'serializing' instruction, and
+     avoids out-of-order execution of the RDTSC instruction. */
+  __asm__ __volatile__ ("xorl %%eax, %%eax\n\t"
+                        "cpuid":::"%rax", "%rbx", "%rcx", "%rdx");
+  /* Read TSC value.  We cannot use "=A", since this would use
+     %rax on x86_64. */
+  __asm__ __volatile__ ("rdtsc":"=a" (lo), "=d" (hi));
+
+  return (((grub_uint64_t) hi) << 32) | lo;
+}
+
+static __inline int
+grub_cpu_is_cpuid_supported (void)
+{
+  grub_uint32_t id_supported;
+
+  __asm__ ("pushfl\n\t"
+           "popl %%eax             /* Get EFLAGS into EAX */\n\t"
+           "movl %%eax, %%ecx      /* Save original flags in ECX */\n\t"
+           "xorl $0x200000, %%eax  /* Flip ID bit in EFLAGS */\n\t"
+           "pushl %%eax            /* Store modified EFLAGS on stack */\n\t"
+           "popfl                  /* Replace current EFLAGS */\n\t"
+           "pushfl                 /* Read back the EFLAGS */\n\t"
+           "popl %%eax             /* Get EFLAGS into EAX */\n\t"
+           "xorl %%ecx, %%eax      /* Check if flag could be modified */\n\t"
+           : "=a" (id_supported)
+           : /* No inputs.  */
+           : /* Clobbered:  */ "%rcx");
+
+  return id_supported != 0;
+}
+
+static __inline int
+grub_cpu_is_tsc_supported (void)
+{
+  if (! grub_cpu_is_cpuid_supported ())
+    return 0;
+
+  grub_uint32_t features;
+  __asm__ ("movl $1, %%eax\n\t"
+           "cpuid"
+           : "=d" (features)
+           : /* No inputs.  */
+           : /* Clobbered:  */ "%rax", "%rbx", "%rcx");
+  return (features & (1 << 4)) != 0;
+}
+
+void grub_tsc_init (void);
+grub_uint64_t grub_tsc_get_time_ms (void);
+
+#endif /* ! KERNEL_CPU_TSC_HEADER */

=== modified file 'include/grub/time.h'
--- include/grub/time.h	2007-10-22 19:02:16 +0000
+++ include/grub/time.h	2008-07-28 16:51:30 +0000
@@ -1,6 +1,6 @@
 /*
  *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 2007  Free Software Foundation, Inc.
+ *  Copyright (C) 2007, 2008  Free Software Foundation, Inc.
  *
  *  GRUB is free software: you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -19,12 +19,15 @@
 #ifndef KERNEL_TIME_HEADER
 #define KERNEL_TIME_HEADER	1
 
+#include <grub/types.h>
 #include <grub/symbol.h>
 #include <grub/machine/time.h>
 #include <grub/cpu/time.h>
 
 void EXPORT_FUNC(grub_millisleep) (grub_uint32_t ms);
-void EXPORT_FUNC(grub_millisleep_generic) (grub_uint32_t ms);
+grub_uint64_t EXPORT_FUNC(grub_get_time_ms) (void);
+
+grub_uint64_t grub_rtc_get_time_ms (void);
 
 static __inline void
 grub_sleep (grub_uint32_t s)
@@ -32,4 +35,6 @@
   grub_millisleep (1000 * s);
 }
 
+void grub_install_get_time_ms (grub_uint64_t (*get_time_ms_func) (void));
+
 #endif /* ! KERNEL_TIME_HEADER */

=== added directory 'kern/generic'
=== added file 'kern/generic/millisleep.c'
--- kern/generic/millisleep.c	1970-01-01 00:00:00 +0000
+++ kern/generic/millisleep.c	2008-07-28 16:51:30 +0000
@@ -0,0 +1,39 @@
+/* millisleep.c - generic millisleep function.
+ * The generic implementation of these functions can be used for architectures
+ * or platforms that do not have a more specialized implementation. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/misc.h>
+#include <grub/time.h>
+
+void
+grub_millisleep (grub_uint32_t ms)
+{
+  grub_uint64_t start;
+
+  start = grub_get_time_ms ();
+
+  /* Instead of setting an end time and looping while the current time is 
+     less than that, comparing the elapsed sleep time with the desired sleep
+     time handles the (unlikely!) case that the timer would wrap around 
+     during the sleep. */
+
+  while (grub_get_time_ms () - start < ms)
+    grub_cpu_idle ();
+}

=== added file 'kern/generic/rtc_get_time_ms.c'
--- kern/generic/rtc_get_time_ms.c	1970-01-01 00:00:00 +0000
+++ kern/generic/rtc_get_time_ms.c	2008-07-28 16:51:30 +0000
@@ -0,0 +1,37 @@
+/* rtc_get_time_ms.c - get_time_ms implementation using platform RTC.
+ * The generic implementation of these functions can be used for architectures
+ * or platforms that do not have a more specialized implementation. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/time.h>
+#include <grub/misc.h>
+
+/* Calculate the time in milliseconds since the epoch based on the RTC. */
+grub_uint64_t
+grub_rtc_get_time_ms (void)
+{
+  /* By dimensional analysis: 
+    
+      1000 ms   N rtc ticks       1 s
+      ------- * ----------- * ----------- = 1000*N/T ms
+        1 s          1        T rtc ticks
+   */
+  grub_uint64_t ticks_ms_per_sec = ((grub_uint64_t) 1000) * grub_get_rtc ();
+  return grub_divmod64 (ticks_ms_per_sec, GRUB_TICKS_PER_SECOND, 0);
+}

=== modified file 'kern/i386/efi/init.c'
--- kern/i386/efi/init.c	2007-10-22 18:59:33 +0000
+++ kern/i386/efi/init.c	2008-07-28 16:23:46 +0000
@@ -25,18 +25,13 @@
 #include <grub/cache.h>
 #include <grub/kernel.h>
 #include <grub/efi/efi.h>
-#include <grub/time.h>
-
-void
-grub_millisleep (grub_uint32_t ms)
-{
-  grub_millisleep_generic (ms);
-}
+#include <grub/cpu/tsc.h>
 
 void
 grub_machine_init (void)
 {
   grub_efi_init ();
+  grub_tsc_init ();
 }
 
 void

=== modified file 'kern/i386/linuxbios/init.c'
--- kern/i386/linuxbios/init.c	2008-07-04 02:26:10 +0000
+++ kern/i386/linuxbios/init.c	2008-07-28 16:23:46 +0000
@@ -149,6 +149,8 @@
 
   /* This variable indicates size, not offset.  */
   grub_upper_mem -= GRUB_MEMORY_MACHINE_UPPER_START;
+
+  grub_install_get_time_ms (grub_rtc_get_time_ms);
 }
 
 void

=== modified file 'kern/i386/pc/init.c'
--- kern/i386/pc/init.c	2008-06-15 17:21:16 +0000
+++ kern/i386/pc/init.c	2008-07-28 16:23:46 +0000
@@ -30,6 +30,7 @@
 #include <grub/env.h>
 #include <grub/cache.h>
 #include <grub/time.h>
+#include <grub/cpu/tsc.h>
 
 struct mem_region
 {
@@ -46,12 +47,6 @@
 grub_size_t grub_os_area_size;
 grub_size_t grub_lower_mem, grub_upper_mem;
 
-void
-grub_millisleep (grub_uint32_t ms)
-{
-  grub_millisleep_generic (ms);
-}
-
 void 
 grub_arch_sync_caches (void *address __attribute__ ((unused)),
 		       grub_size_t len __attribute__ ((unused)))
@@ -231,6 +226,8 @@
   
   if (! grub_os_area_addr)
     grub_fatal ("no upper memory");
+
+  grub_tsc_init ();
 }
 
 void

=== added file 'kern/i386/tsc.c'
--- kern/i386/tsc.c	1970-01-01 00:00:00 +0000
+++ kern/i386/tsc.c	2008-07-28 16:51:30 +0000
@@ -0,0 +1,102 @@
+/* kern/i386/tsc.c - x86 TSC time source implementation
+ * Requires Pentium or better x86 CPU that supports the RDTSC instruction.
+ * This module uses the RTC (via grub_get_rtc()) to calibrate the TSC to 
+ * real time.
+ *
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/time.h>
+#include <grub/misc.h>
+#include <grub/i386/tsc.h>
+
+/* Calibrated reference for TSC=0.  This defines the time since the epoch in 
+   milliseconds that TSC=0 refers to. */
+static grub_uint64_t tsc_boot_time;
+
+/* Calibrated TSC rate.  (In TSC ticks per millisecond.) */
+static grub_uint64_t tsc_ticks_per_ms;
+
+
+grub_uint64_t
+grub_tsc_get_time_ms (void)
+{
+  return tsc_boot_time + grub_divmod64 (grub_get_tsc (), tsc_ticks_per_ms, 0);
+}
+
+
+/* How many RTC ticks to use for calibration loop. (>= 1) */
+#define CALIBRATION_TICKS 2
+
+/* Calibrate the TSC based on the RTC.  */
+static void
+calibrate_tsc (void)
+{
+  /* First calbrate the TSC rate (relative, not absolute time). */
+  grub_uint64_t start_tsc;
+  grub_uint64_t end_tsc;
+  grub_uint32_t initial_tick;
+  grub_uint32_t start_tick;
+  grub_uint32_t end_tick;
+
+  /* Wait for the start of the next tick;
+     we'll base out timing off this edge. */
+  initial_tick = grub_get_rtc ();
+  do
+    {
+      start_tick = grub_get_rtc ();
+    }
+  while (start_tick == initial_tick);
+  start_tsc = grub_get_tsc ();
+
+  /* Wait for the start of the next tick.  This will
+     be the end of the 1-tick period. */
+  do
+    {
+      end_tick = grub_get_rtc ();
+    }
+  while (end_tick - start_tick < CALIBRATION_TICKS);
+  end_tsc = grub_get_tsc ();
+
+  tsc_ticks_per_ms =
+    grub_divmod64 (grub_divmod64
+                   (end_tsc - start_tsc, end_tick - start_tick, 0)
+                   * GRUB_TICKS_PER_SECOND, 1000, 0);
+
+  /* Reference the TSC zero (boot time) to the epoch to 
+     get an absolute real time reference. */
+  grub_uint64_t ms_since_boot = grub_divmod64 (end_tsc, tsc_ticks_per_ms, 0);
+  grub_uint64_t mstime_now = grub_divmod64 ((grub_uint64_t) 1000 * end_tick,
+                                            GRUB_TICKS_PER_SECOND,
+                                            0);
+  tsc_boot_time = mstime_now - ms_since_boot;
+}
+
+void
+grub_tsc_init (void)
+{
+  if (grub_cpu_is_tsc_supported ())
+    {
+      calibrate_tsc ();
+      grub_install_get_time_ms (grub_tsc_get_time_ms);
+    }
+  else
+    {
+      grub_install_get_time_ms (grub_rtc_get_time_ms);
+    }
+}

=== modified file 'kern/ieee1275/init.c'
--- kern/ieee1275/init.c	2008-07-04 02:01:55 +0000
+++ kern/ieee1275/init.c	2008-07-28 16:23:46 +0000
@@ -47,12 +47,6 @@
 extern char _end[];
 
 void
-grub_millisleep (grub_uint32_t ms)
-{
-  grub_millisleep_generic (ms);
-}
-
-void
 grub_exit (void)
 {
   grub_ieee1275_exit ();
@@ -202,6 +196,8 @@
 
 #endif
 
+static grub_uint64_t ieee1275_get_time_ms (void);
+
 void
 grub_machine_init (void)
 {
@@ -251,6 +247,8 @@
 	    }
 	}
     }
+
+  grub_install_get_time_ms (ieee1275_get_time_ms);
 }
 
 void
@@ -260,8 +258,8 @@
   grub_console_fini ();
 }
 
-grub_uint32_t
-grub_get_rtc (void)
+static grub_uint64_t
+ieee1275_get_time_ms (void)
 {
   grub_uint32_t msecs = 0;
 
@@ -270,6 +268,12 @@
   return msecs;
 }
 
+grub_uint32_t
+grub_get_rtc (void)
+{
+  return ieee1275_get_time_ms ();
+}
+
 grub_addr_t
 grub_arch_modules_addr (void)
 {

=== modified file 'kern/misc.c'
--- kern/misc.c	2008-06-15 23:42:48 +0000
+++ kern/misc.c	2008-07-04 18:03:26 +0000
@@ -23,7 +23,6 @@
 #include <stdarg.h>
 #include <grub/term.h>
 #include <grub/env.h>
-#include <grub/time.h>
 
 void *
 grub_memmove (void *dest, const void *src, grub_size_t n)
@@ -1018,17 +1017,6 @@
   return p - dest;
 }
 
-void
-grub_millisleep_generic (grub_uint32_t ms)
-{
-  grub_uint32_t end_at;
-
-  end_at = grub_get_rtc () + grub_div_roundup (ms * GRUB_TICKS_PER_SECOND, 1000);
-
-  while (grub_get_rtc () < end_at)
-    grub_cpu_idle ();
-}
-
 /* Abort GRUB. This function does not return.  */
 void
 grub_abort (void)

=== modified file 'kern/sparc64/ieee1275/init.c'
--- kern/sparc64/ieee1275/init.c	2007-10-22 18:59:33 +0000
+++ kern/sparc64/ieee1275/init.c	2008-07-28 16:23:46 +0000
@@ -66,12 +66,6 @@
   /* Never reached.  */
 }
 
-void
-grub_millisleep (grub_uint32_t ms)
-{
-  grub_millisleep_generic (ms);
-}
-
 int
 grub_ieee1275_test_flag (enum grub_ieee1275_flag flag)
 {
@@ -145,6 +139,8 @@
   grub_free (prefix);
 }
 
+grub_uint64_t ieee1275_get_time_ms (void);
+
 void
 grub_machine_init (void)
 {
@@ -201,6 +197,7 @@
 	}
     }
 
+  grub_install_get_time_ms (ieee1275_get_time_ms);
 }
 
 void
@@ -216,6 +213,12 @@
   grub_ieee1275_enter ();
 }
 
+grub_uint64_t
+ieee1275_get_time_ms (void)
+{
+  return grub_get_rtc ();
+}
+
 grub_uint32_t
 grub_get_rtc (void)
 {

=== added file 'kern/time.c'
--- kern/time.c	1970-01-01 00:00:00 +0000
+++ kern/time.c	2008-07-28 16:23:46 +0000
@@ -0,0 +1,37 @@
+/* time.c - kernel time functions */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/time.h>
+
+typedef grub_uint64_t (*get_time_ms_func_t) (void);
+
+/* Function pointer to the implementation in use.  */
+static get_time_ms_func_t get_time_ms_func;
+
+grub_uint64_t
+grub_get_time_ms (void)
+{
+  return get_time_ms_func ();
+}
+
+void
+grub_install_get_time_ms (get_time_ms_func_t func)
+{
+  get_time_ms_func = func;
+}


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] High resolution time/TSC patch v3
  2008-07-28 17:05       ` [PATCH] High resolution time/TSC patch v3 Colin D Bennett
@ 2008-07-28 17:59         ` Robert Millan
  2008-07-31 19:08         ` Marco Gerards
                           ` (2 subsequent siblings)
  3 siblings, 0 replies; 24+ messages in thread
From: Robert Millan @ 2008-07-28 17:59 UTC (permalink / raw)
  To: Colin D Bennett; +Cc: The development of GRUB 2

[-- Attachment #1: Type: text/plain, Size: 2408 bytes --]

On Mon, Jul 28, 2008 at 10:05:33AM -0700, Colin D Bennett wrote:
> Another updated TSC patch.  Now it detects TSC support for x86 CPUs at
> runtime and selects either the TSC or RTC time source.  This way 386
> and 486 CPUs without RDTSC instruction support are supported.
> 
> Robert Millan was interested in getting this patch merged for the
> Coreboot port, so I decided to take another crack at it.

Very nice.  Thanks for taking the time to send this.

It needed some adjustments in order to build in Coreboot (see attached
patch).

Unfortunately, on runtime the value returned is always 0.  I didn't think
this would be related to firmware in some way, but it is.  Maybe some hardware
needs to be initialized?  Or perhaps it's a QEMU bug.

> +static __inline int
> +grub_cpu_is_cpuid_supported (void)
> +{
> +  grub_uint32_t id_supported;
> +
> +  __asm__ ("pushfl\n\t"
> +           "popl %%eax             /* Get EFLAGS into EAX */\n\t"
> +           "movl %%eax, %%ecx      /* Save original flags in ECX */\n\t"
> +           "xorl $0x200000, %%eax  /* Flip ID bit in EFLAGS */\n\t"
> +           "pushl %%eax            /* Store modified EFLAGS on stack */\n\t"
> +           "popfl                  /* Replace current EFLAGS */\n\t"
> +           "pushfl                 /* Read back the EFLAGS */\n\t"
> +           "popl %%eax             /* Get EFLAGS into EAX */\n\t"
> +           "xorl %%ecx, %%eax      /* Check if flag could be modified */\n\t"
> +           : "=a" (id_supported)
> +           : /* No inputs.  */
> +           : /* Clobbered:  */ "%rcx");
> +
> +  return id_supported != 0;
> +}

There's similar code in commands/i386/cpuid.c.  I'd suggest harmonizing them.

> +static __inline int
> +grub_cpu_is_tsc_supported (void)
> +{
> +  if (! grub_cpu_is_cpuid_supported ())
> +    return 0;
> +
> +  grub_uint32_t features;
> +  __asm__ ("movl $1, %%eax\n\t"
> +           "cpuid"
> +           : "=d" (features)
> +           : /* No inputs.  */
> +           : /* Clobbered:  */ "%rax", "%rbx", "%rcx");
> +  return (features & (1 << 4)) != 0;
> +}

Maybe the same would make sense here.  How about a generic "is_flag_supported"
function?

-- 
Robert Millan

  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
  how) you may access your data; but nobody's threatening your freedom: we
  still allow you to remove your data and not access it at all."

[-- Attachment #2: coreboot.diff --]
[-- Type: text/x-diff, Size: 1012 bytes --]

diff -x .svn -x '*.mk' -ur grub2.old/conf/i386-coreboot.rmk grub2/conf/i386-coreboot.rmk
--- grub2.old/conf/i386-coreboot.rmk	2008-07-28 19:51:19.000000000 +0200
+++ grub2/conf/i386-coreboot.rmk	2008-07-28 19:44:19.000000000 +0200
@@ -16,7 +16,7 @@
 	kern/main.c kern/device.c \
 	kern/disk.c kern/dl.c kern/file.c kern/fs.c kern/err.c \
 	kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \
-	kern/time.c \
+	kern/time.c kern/generic/rtc_get_time_ms.c kern/generic/millisleep.c \
 	kern/i386/dl.c kern/parser.c kern/partition.c \
 	kern/env.c \
 	term/i386/pc/console.c \
diff -x .svn -x '*.mk' -ur grub2.old/kern/i386/linuxbios/init.c grub2/kern/i386/linuxbios/init.c
--- grub2.old/kern/i386/linuxbios/init.c	2008-07-28 19:51:19.000000000 +0200
+++ grub2/kern/i386/linuxbios/init.c	2008-07-28 19:44:02.000000000 +0200
@@ -61,11 +61,6 @@
 }
 
 void
-grub_millisleep (grub_uint32_t ms __attribute__ ((unused)))
-{
-}
-
-void
 grub_exit (void)
 {
   grub_printf ("grub_exit() is not implemented.\n");

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] High resolution time/TSC patch v3
  2008-07-28 17:05       ` [PATCH] High resolution time/TSC patch v3 Colin D Bennett
  2008-07-28 17:59         ` Robert Millan
@ 2008-07-31 19:08         ` Marco Gerards
  2008-07-31 19:24           ` Robert Millan
  2008-08-03 19:48         ` Robert Millan
  2008-08-05 11:59         ` [PATCH] High resolution time/TSC patch v3 Marco Gerards
  3 siblings, 1 reply; 24+ messages in thread
From: Marco Gerards @ 2008-07-31 19:08 UTC (permalink / raw)
  To: Colin D Bennett; +Cc: The development of GRUB 2, Robert Millan

Colin D Bennett <colin@gibibit.com> writes:

> Another updated TSC patch.  Now it detects TSC support for x86 CPUs at
> runtime and selects either the TSC or RTC time source.  This way 386
> and 486 CPUs without RDTSC instruction support are supported.
>
> Robert Millan was interested in getting this patch merged for the
> Coreboot port, so I decided to take another crack at it.
>
> Comments are welcome!

Great!  Did you have a look at Roberts comment that it does not work
in Qemu?  This is the most important testing ground for many of us...

> === modified file 'ChangeLog'
> --- ChangeLog	2008-07-27 19:57:43 +0000
> +++ ChangeLog	2008-07-28 16:51:30 +0000
> @@ -1,3 +1,68 @@
> +2008-07-28  Colin D Bennett <colin@gibibit.com>
> +
> +	High resolution timer support.  Implemented for x86 CPUs using TSC.
> +	Extracted generic grub_millisleep() so it's linked in only as needed.
> +	This requires a Pentium compatible CPU; if the RDTSC instruction is
> +	not supported, then it falls back on the generic grub_get_time_ms()
> +	implementation that uses the machine's RTC.
> +
> +	* conf/i386-efi.rmk: Added new source files to kernel_elf_SOURCES.

Do you mean:

   * conf/i386-efi.rmk (kernel_elf_SOURCES): Add <...>.

Please replace <...> by your source files :-)

> +	* conf/i386-pc.rmk: Likewise.
> +
> +	* conf/sparc64-ieee1275.rmk: Likewise.
> +
> +	* conf/powerpc-ieee1275.rmk: Likewise.
> +
> +	* conf/i386-coreboot.rmk: Likewise.
> +
> +	* kern/generic/rtc_get_time_ms.c: New file.
> +
> +	* kern/generic/millisleep.c: New file.
> +
> +	* kern/misc.c (grub_millisleep_generic): Removed.
> +
> +	* commands/sleep.c (grub_interruptible_millisleep): Uses
> +	grub_get_time_ms() instead of grub_get_rtc() to stay in sync with
> +	grub_millisleep() from kern/generic/millisleep.c.
> +
> +	* include/grub/i386/tsc.h (grub_get_tsc): New file.  New inline
> +	function.

Huh?

        * include/grub/i386/tsc.h: New file.

Would be correct, right?

> +	(grub_cpu_is_cpuid_supported): New inline function.
> +	(grub_cpu_is_tsc_supported): New inline function.
> +	(grub_tsc_init): New function prototype.
> +	(grub_tsc_get_time_ms): New function prototype.

No need to describe the contents of a new file, simply stating the
file is new is sufficient.

> +	* kern/i386/tsc.c (grub_get_time_ms): New file.  New function.
> +	(calibrate_tsc): New static function.
> +	(grub_tsc_init): New function.

Same here.

> +	* include/grub/time.h (grub_millisleep_generic): Removed.
> +	(grub_get_time_ms): New function.
> +	(grub_install_get_time_ms): New function.
> +
> +	* kern/time.c (grub_get_time_ms): New function.
> +	(grub_install_get_time_ms): New function.
> +
> +	* kern/i386/efi/init.c (grub_millisleep): Removed.
> +	(grub_machine_init): Call grub_tsc_init.
> +
> +	* kern/i386/linuxbios/init.c (grub_machine_init): Install the RTC
> +	get_time_ms() implementation.
> +
> +	* kern/sparc64/ieee1275/init.c (grub_millisleep): Removed.
> +	(ieee1275_get_time_ms): New function.
> +	(grub_machine_init): Install get_time_ms() implementation.
> +
> +	* kern/i386/pc/init.c (grub_machine_init): Call grub_tsc_init().
> +	(grub_millisleep): Removed.
> +
> +	* kern/ieee1275/init.c (grub_millisleep): Removed.
> +	(grub_machine_init): Install ieee1275_get_time_ms() implementation.
> +	(ieee1275_get_time_ms): New static function.
> +	(grub_get_rtc): Now calls ieee1275_get_time_ms(), which does the real
> +	work.
> +
>  2008-07-27  Robert Millan  <rmh@aybabtu.com>
>  
>  	* disk/ata.c (grub_ata_dumpinfo): Use grub_dprintf() for debugging
>
> === modified file 'commands/sleep.c'
> --- commands/sleep.c	2008-05-16 20:55:29 +0000
> +++ commands/sleep.c	2008-07-04 16:55:48 +0000
> @@ -43,15 +43,15 @@
>    grub_printf ("%d    ", n);
>  }
>  
> -/* Based on grub_millisleep() from kern/misc.c.  */
> +/* Based on grub_millisleep() from kern/generic/millisleep.c.  */
>  static int
>  grub_interruptible_millisleep (grub_uint32_t ms)
>  {
> -  grub_uint32_t end_at;
> -  
> -  end_at = grub_get_rtc () + grub_div_roundup (ms * GRUB_TICKS_PER_SECOND, 1000);
> -  
> -  while (grub_get_rtc () < end_at)
> +  grub_uint64_t start;
> +
> +  start = grub_get_time_ms ();
> +
> +  while (grub_get_time_ms () - start < ms)
>      if (grub_checkkey () >= 0 &&
>  	GRUB_TERM_ASCII_CHAR (grub_getkey ()) == GRUB_TERM_ESC)
>        return 1;
>
> === modified file 'conf/i386-coreboot.rmk'
> --- conf/i386-coreboot.rmk	2008-07-27 12:51:30 +0000
> +++ conf/i386-coreboot.rmk	2008-07-28 16:23:46 +0000
> @@ -16,6 +16,7 @@
>  	kern/main.c kern/device.c \
>  	kern/disk.c kern/dl.c kern/file.c kern/fs.c kern/err.c \
>  	kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \
> +	kern/time.c \
>  	kern/i386/dl.c kern/parser.c kern/partition.c \
>  	kern/env.c \
>  	term/i386/pc/console.c \
>
> === modified file 'conf/i386-efi.rmk'
> --- conf/i386-efi.rmk	2008-07-27 12:51:30 +0000
> +++ conf/i386-efi.rmk	2008-07-28 16:23:46 +0000
> @@ -84,7 +84,10 @@
>  	kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \
>  	kern/i386/dl.c kern/i386/efi/init.c kern/parser.c kern/partition.c \
>  	kern/env.c symlist.c kern/efi/efi.c kern/efi/init.c kern/efi/mm.c \
> -	term/efi/console.c disk/efi/efidisk.c
> +	term/efi/console.c disk/efi/efidisk.c \
> +	kern/i386/tsc.c \
> +	kern/generic/rtc_get_time_ms.c \
> +	kern/generic/millisleep.c
>  kernel_mod_HEADERS = arg.h boot.h cache.h device.h disk.h dl.h elf.h elfload.h \
>  	env.h err.h file.h fs.h kernel.h loader.h misc.h mm.h net.h parser.h \
>  	partition.h pc_partition.h rescue.h symbol.h term.h time.h types.h \
>
> === modified file 'conf/i386-ieee1275.rmk'
> --- conf/i386-ieee1275.rmk	2008-07-27 12:51:30 +0000
> +++ conf/i386-ieee1275.rmk	2008-07-28 16:23:46 +0000
> @@ -19,6 +19,7 @@
>  	kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \
>  	kern/i386/dl.c kern/parser.c kern/partition.c \
>  	kern/env.c \
> +	kern/generic/millisleep.c \
>  	kern/ieee1275/ieee1275.c \
>  	term/ieee1275/ofconsole.c term/i386/pc/at_keyboard.c \
>  	disk/ieee1275/ofdisk.c \
>
> === modified file 'conf/i386-pc.rmk'
> --- conf/i386-pc.rmk	2008-07-27 12:51:30 +0000
> +++ conf/i386-pc.rmk	2008-07-28 16:23:46 +0000
> @@ -42,7 +42,11 @@
>  kernel_img_SOURCES = kern/i386/pc/startup.S kern/main.c kern/device.c \
>  	kern/disk.c kern/dl.c kern/file.c kern/fs.c kern/err.c \
>  	kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \
> +	kern/time.c \
>  	kern/i386/dl.c kern/i386/pc/init.c kern/parser.c kern/partition.c \
> +	kern/i386/tsc.c \
> +	kern/generic/rtc_get_time_ms.c \
> +	kern/generic/millisleep.c \
>  	kern/env.c \
>  	term/i386/pc/console.c \
>  	symlist.c
>
> === modified file 'conf/powerpc-ieee1275.rmk'
> --- conf/powerpc-ieee1275.rmk	2008-07-27 12:51:30 +0000
> +++ conf/powerpc-ieee1275.rmk	2008-07-28 13:59:50 +0000
> @@ -85,6 +85,7 @@
>  	kern/ieee1275/init.c term/ieee1275/ofconsole.c 		\
>  	kern/ieee1275/openfw.c disk/ieee1275/ofdisk.c 		\
>  	kern/parser.c kern/partition.c kern/env.c kern/powerpc/dl.c 	\
> +	kern/generic/millisleep.c                                       \
>  	symlist.c kern/powerpc/cache.S
>  kernel_elf_HEADERS = grub/powerpc/ieee1275/ieee1275.h
>  kernel_elf_CFLAGS = $(COMMON_CFLAGS)
>
> === modified file 'conf/sparc64-ieee1275.rmk'
> --- conf/sparc64-ieee1275.rmk	2008-06-19 00:04:59 +0000
> +++ conf/sparc64-ieee1275.rmk	2008-07-03 04:19:16 +0000
> @@ -73,6 +73,7 @@
>  	kern/rescue.c kern/term.c term/ieee1275/ofconsole.c \
>  	kern/sparc64/ieee1275/openfw.c disk/ieee1275/ofdisk.c \
>  	kern/partition.c kern/env.c kern/sparc64/dl.c symlist.c \
> +	kern/generic/millisleep.c kern/generic/get_time_ms.c \
>  	kern/sparc64/cache.S kern/parser.c
>  kernel_elf_HEADERS = grub/sparc64/ieee1275/ieee1275.h
>  kernel_elf_CFLAGS = $(COMMON_CFLAGS)
>
> === modified file 'conf/x86_64-efi.rmk'
> --- conf/x86_64-efi.rmk	2008-07-27 12:51:30 +0000
> +++ conf/x86_64-efi.rmk	2008-07-28 16:23:46 +0000
> @@ -87,6 +87,7 @@
>  	kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \
>  	kern/x86_64/dl.c kern/i386/efi/init.c kern/parser.c kern/partition.c \
>  	kern/env.c symlist.c kern/efi/efi.c kern/efi/init.c kern/efi/mm.c \
> +	kern/generic/millisleep.c kern/generic/rtc_get_time_ms.c \
>  	term/efi/console.c disk/efi/efidisk.c
>  kernel_mod_HEADERS = arg.h boot.h cache.h device.h disk.h dl.h elf.h elfload.h \
>  	env.h err.h file.h fs.h kernel.h loader.h misc.h mm.h net.h parser.h \
>
> === added file 'include/grub/i386/tsc.h'
> --- include/grub/i386/tsc.h	1970-01-01 00:00:00 +0000
> +++ include/grub/i386/tsc.h	2008-07-28 16:23:46 +0000
> @@ -0,0 +1,80 @@
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2008  Free Software Foundation, Inc.
> + *
> + *  GRUB is free software: you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation, either version 3 of the License, or
> + *  (at your option) any later version.
> + *
> + *  GRUB is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef KERNEL_CPU_TSC_HEADER
> +#define KERNEL_CPU_TSC_HEADER   1
> +
> +#include <grub/types.h>
> +
> +/* Read the TSC value, which increments with each CPU clock cycle. */
> +static __inline grub_uint64_t
> +grub_get_tsc (void)
> +{
> +  grub_uint32_t lo, hi;
> +
> +  /* The CPUID instruction is a 'serializing' instruction, and
> +     avoids out-of-order execution of the RDTSC instruction. */
> +  __asm__ __volatile__ ("xorl %%eax, %%eax\n\t"
> +                        "cpuid":::"%rax", "%rbx", "%rcx", "%rdx");
> +  /* Read TSC value.  We cannot use "=A", since this would use
> +     %rax on x86_64. */
> +  __asm__ __volatile__ ("rdtsc":"=a" (lo), "=d" (hi));
> +
> +  return (((grub_uint64_t) hi) << 32) | lo;
> +}
> +
> +static __inline int
> +grub_cpu_is_cpuid_supported (void)
> +{
> +  grub_uint32_t id_supported;
> +
> +  __asm__ ("pushfl\n\t"
> +           "popl %%eax             /* Get EFLAGS into EAX */\n\t"
> +           "movl %%eax, %%ecx      /* Save original flags in ECX */\n\t"
> +           "xorl $0x200000, %%eax  /* Flip ID bit in EFLAGS */\n\t"
> +           "pushl %%eax            /* Store modified EFLAGS on stack */\n\t"
> +           "popfl                  /* Replace current EFLAGS */\n\t"
> +           "pushfl                 /* Read back the EFLAGS */\n\t"
> +           "popl %%eax             /* Get EFLAGS into EAX */\n\t"
> +           "xorl %%ecx, %%eax      /* Check if flag could be modified */\n\t"
> +           : "=a" (id_supported)
> +           : /* No inputs.  */
> +           : /* Clobbered:  */ "%rcx");
> +
> +  return id_supported != 0;
> +}
> +
> +static __inline int
> +grub_cpu_is_tsc_supported (void)
> +{
> +  if (! grub_cpu_is_cpuid_supported ())
> +    return 0;
> +
> +  grub_uint32_t features;
> +  __asm__ ("movl $1, %%eax\n\t"
> +           "cpuid"
> +           : "=d" (features)
> +           : /* No inputs.  */
> +           : /* Clobbered:  */ "%rax", "%rbx", "%rcx");
> +  return (features & (1 << 4)) != 0;
> +}
> +
> +void grub_tsc_init (void);
> +grub_uint64_t grub_tsc_get_time_ms (void);
> +
> +#endif /* ! KERNEL_CPU_TSC_HEADER */
>
> === modified file 'include/grub/time.h'
> --- include/grub/time.h	2007-10-22 19:02:16 +0000
> +++ include/grub/time.h	2008-07-28 16:51:30 +0000
> @@ -1,6 +1,6 @@
>  /*
>   *  GRUB  --  GRand Unified Bootloader
> - *  Copyright (C) 2007  Free Software Foundation, Inc.
> + *  Copyright (C) 2007, 2008  Free Software Foundation, Inc.
>   *
>   *  GRUB is free software: you can redistribute it and/or modify
>   *  it under the terms of the GNU General Public License as published by
> @@ -19,12 +19,15 @@
>  #ifndef KERNEL_TIME_HEADER
>  #define KERNEL_TIME_HEADER	1
>  
> +#include <grub/types.h>

This include is not mentioned in the changelog entry.

>  #include <grub/symbol.h>
>  #include <grub/machine/time.h>
>  #include <grub/cpu/time.h>
>  
>  void EXPORT_FUNC(grub_millisleep) (grub_uint32_t ms);
> -void EXPORT_FUNC(grub_millisleep_generic) (grub_uint32_t ms);
> +grub_uint64_t EXPORT_FUNC(grub_get_time_ms) (void);
> +
> +grub_uint64_t grub_rtc_get_time_ms (void);
>  
>  static __inline void
>  grub_sleep (grub_uint32_t s)
> @@ -32,4 +35,6 @@
>    grub_millisleep (1000 * s);
>  }
>  
> +void grub_install_get_time_ms (grub_uint64_t (*get_time_ms_func) (void));
> +
>  #endif /* ! KERNEL_TIME_HEADER */
>
> === added directory 'kern/generic'
> === added file 'kern/generic/millisleep.c'
> --- kern/generic/millisleep.c	1970-01-01 00:00:00 +0000
> +++ kern/generic/millisleep.c	2008-07-28 16:51:30 +0000
> @@ -0,0 +1,39 @@
> +/* millisleep.c - generic millisleep function.
> + * The generic implementation of these functions can be used for architectures
> + * or platforms that do not have a more specialized implementation. */
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008  Free Software Foundation, Inc.
> + *
> + *  GRUB is free software: you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation, either version 3 of the License, or
> + *  (at your option) any later version.
> + *
> + *  GRUB is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <grub/misc.h>
> +#include <grub/time.h>
> +
> +void
> +grub_millisleep (grub_uint32_t ms)
> +{
> +  grub_uint64_t start;
> +
> +  start = grub_get_time_ms ();
> +
> +  /* Instead of setting an end time and looping while the current time is 
> +     less than that, comparing the elapsed sleep time with the desired sleep
> +     time handles the (unlikely!) case that the timer would wrap around 
> +     during the sleep. */
> +
> +  while (grub_get_time_ms () - start < ms)
> +    grub_cpu_idle ();
> +}
>
> === added file 'kern/generic/rtc_get_time_ms.c'
> --- kern/generic/rtc_get_time_ms.c	1970-01-01 00:00:00 +0000
> +++ kern/generic/rtc_get_time_ms.c	2008-07-28 16:51:30 +0000
> @@ -0,0 +1,37 @@
> +/* rtc_get_time_ms.c - get_time_ms implementation using platform RTC.
> + * The generic implementation of these functions can be used for architectures
> + * or platforms that do not have a more specialized implementation. */
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2008  Free Software Foundation, Inc.
> + *
> + *  GRUB is free software: you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation, either version 3 of the License, or
> + *  (at your option) any later version.
> + *
> + *  GRUB is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <grub/time.h>
> +#include <grub/misc.h>
> +
> +/* Calculate the time in milliseconds since the epoch based on the RTC. */
> +grub_uint64_t
> +grub_rtc_get_time_ms (void)
> +{
> +  /* By dimensional analysis: 
> +    
> +      1000 ms   N rtc ticks       1 s
> +      ------- * ----------- * ----------- = 1000*N/T ms
> +        1 s          1        T rtc ticks
> +   */
> +  grub_uint64_t ticks_ms_per_sec = ((grub_uint64_t) 1000) * grub_get_rtc ();
> +  return grub_divmod64 (ticks_ms_per_sec, GRUB_TICKS_PER_SECOND, 0);
> +}
>
> === modified file 'kern/i386/efi/init.c'
> --- kern/i386/efi/init.c	2007-10-22 18:59:33 +0000
> +++ kern/i386/efi/init.c	2008-07-28 16:23:46 +0000
> @@ -25,18 +25,13 @@
>  #include <grub/cache.h>
>  #include <grub/kernel.h>
>  #include <grub/efi/efi.h>
> -#include <grub/time.h>
> -
> -void
> -grub_millisleep (grub_uint32_t ms)
> -{
> -  grub_millisleep_generic (ms);
> -}
> +#include <grub/cpu/tsc.h>
>  
>  void
>  grub_machine_init (void)
>  {
>    grub_efi_init ();
> +  grub_tsc_init ();
>  }
>  
>  void
>
> === modified file 'kern/i386/linuxbios/init.c'
> --- kern/i386/linuxbios/init.c	2008-07-04 02:26:10 +0000
> +++ kern/i386/linuxbios/init.c	2008-07-28 16:23:46 +0000
> @@ -149,6 +149,8 @@
>  
>    /* This variable indicates size, not offset.  */
>    grub_upper_mem -= GRUB_MEMORY_MACHINE_UPPER_START;
> +
> +  grub_install_get_time_ms (grub_rtc_get_time_ms);
>  }
>  
>  void
>
> === modified file 'kern/i386/pc/init.c'
> --- kern/i386/pc/init.c	2008-06-15 17:21:16 +0000
> +++ kern/i386/pc/init.c	2008-07-28 16:23:46 +0000
> @@ -30,6 +30,7 @@
>  #include <grub/env.h>
>  #include <grub/cache.h>
>  #include <grub/time.h>
> +#include <grub/cpu/tsc.h>
>  
>  struct mem_region
>  {
> @@ -46,12 +47,6 @@
>  grub_size_t grub_os_area_size;
>  grub_size_t grub_lower_mem, grub_upper_mem;
>  
> -void
> -grub_millisleep (grub_uint32_t ms)
> -{
> -  grub_millisleep_generic (ms);
> -}
> -
>  void 
>  grub_arch_sync_caches (void *address __attribute__ ((unused)),
>  		       grub_size_t len __attribute__ ((unused)))
> @@ -231,6 +226,8 @@
>    
>    if (! grub_os_area_addr)
>      grub_fatal ("no upper memory");
> +
> +  grub_tsc_init ();
>  }
>  
>  void
>
> === added file 'kern/i386/tsc.c'
> --- kern/i386/tsc.c	1970-01-01 00:00:00 +0000
> +++ kern/i386/tsc.c	2008-07-28 16:51:30 +0000
> @@ -0,0 +1,102 @@
> +/* kern/i386/tsc.c - x86 TSC time source implementation
> + * Requires Pentium or better x86 CPU that supports the RDTSC instruction.
> + * This module uses the RTC (via grub_get_rtc()) to calibrate the TSC to 
> + * real time.
> + *
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2008  Free Software Foundation, Inc.
> + *
> + *  GRUB is free software: you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation, either version 3 of the License, or
> + *  (at your option) any later version.
> + *
> + *  GRUB is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <grub/types.h>
> +#include <grub/time.h>
> +#include <grub/misc.h>
> +#include <grub/i386/tsc.h>
> +
> +/* Calibrated reference for TSC=0.  This defines the time since the epoch in 
> +   milliseconds that TSC=0 refers to. */
> +static grub_uint64_t tsc_boot_time;
> +
> +/* Calibrated TSC rate.  (In TSC ticks per millisecond.) */
> +static grub_uint64_t tsc_ticks_per_ms;
> +
> +
> +grub_uint64_t
> +grub_tsc_get_time_ms (void)
> +{
> +  return tsc_boot_time + grub_divmod64 (grub_get_tsc (), tsc_ticks_per_ms, 0);
> +}
> +
> +
> +/* How many RTC ticks to use for calibration loop. (>= 1) */
> +#define CALIBRATION_TICKS 2
> +
> +/* Calibrate the TSC based on the RTC.  */
> +static void
> +calibrate_tsc (void)
> +{
> +  /* First calbrate the TSC rate (relative, not absolute time). */
> +  grub_uint64_t start_tsc;
> +  grub_uint64_t end_tsc;
> +  grub_uint32_t initial_tick;
> +  grub_uint32_t start_tick;
> +  grub_uint32_t end_tick;
> +
> +  /* Wait for the start of the next tick;
> +     we'll base out timing off this edge. */
> +  initial_tick = grub_get_rtc ();
> +  do
> +    {
> +      start_tick = grub_get_rtc ();
> +    }
> +  while (start_tick == initial_tick);
> +  start_tsc = grub_get_tsc ();
> +
> +  /* Wait for the start of the next tick.  This will
> +     be the end of the 1-tick period. */
> +  do
> +    {
> +      end_tick = grub_get_rtc ();
> +    }
> +  while (end_tick - start_tick < CALIBRATION_TICKS);
> +  end_tsc = grub_get_tsc ();
> +
> +  tsc_ticks_per_ms =
> +    grub_divmod64 (grub_divmod64
> +                   (end_tsc - start_tsc, end_tick - start_tick, 0)
> +                   * GRUB_TICKS_PER_SECOND, 1000, 0);
> +
> +  /* Reference the TSC zero (boot time) to the epoch to 
> +     get an absolute real time reference. */
> +  grub_uint64_t ms_since_boot = grub_divmod64 (end_tsc, tsc_ticks_per_ms, 0);
> +  grub_uint64_t mstime_now = grub_divmod64 ((grub_uint64_t) 1000 * end_tick,
> +                                            GRUB_TICKS_PER_SECOND,
> +                                            0);
> +  tsc_boot_time = mstime_now - ms_since_boot;
> +}
> +
> +void
> +grub_tsc_init (void)
> +{
> +  if (grub_cpu_is_tsc_supported ())
> +    {
> +      calibrate_tsc ();
> +      grub_install_get_time_ms (grub_tsc_get_time_ms);
> +    }
> +  else
> +    {
> +      grub_install_get_time_ms (grub_rtc_get_time_ms);
> +    }
> +}
>
> === modified file 'kern/ieee1275/init.c'
> --- kern/ieee1275/init.c	2008-07-04 02:01:55 +0000
> +++ kern/ieee1275/init.c	2008-07-28 16:23:46 +0000
> @@ -47,12 +47,6 @@
>  extern char _end[];
>  
>  void
> -grub_millisleep (grub_uint32_t ms)
> -{
> -  grub_millisleep_generic (ms);
> -}
> -
> -void
>  grub_exit (void)
>  {
>    grub_ieee1275_exit ();
> @@ -202,6 +196,8 @@
>  
>  #endif
>  
> +static grub_uint64_t ieee1275_get_time_ms (void);
> +
>  void
>  grub_machine_init (void)
>  {
> @@ -251,6 +247,8 @@
>  	    }
>  	}
>      }
> +
> +  grub_install_get_time_ms (ieee1275_get_time_ms);
>  }
>  
>  void
> @@ -260,8 +258,8 @@
>    grub_console_fini ();
>  }
>  
> -grub_uint32_t
> -grub_get_rtc (void)
> +static grub_uint64_t
> +ieee1275_get_time_ms (void)
>  {
>    grub_uint32_t msecs = 0;
>  
> @@ -270,6 +268,12 @@
>    return msecs;
>  }
>  
> +grub_uint32_t
> +grub_get_rtc (void)
> +{
> +  return ieee1275_get_time_ms ();
> +}
> +
>  grub_addr_t
>  grub_arch_modules_addr (void)
>  {
>
> === modified file 'kern/misc.c'
> --- kern/misc.c	2008-06-15 23:42:48 +0000
> +++ kern/misc.c	2008-07-04 18:03:26 +0000
> @@ -23,7 +23,6 @@
>  #include <stdarg.h>
>  #include <grub/term.h>
>  #include <grub/env.h>
> -#include <grub/time.h>
>  
>  void *
>  grub_memmove (void *dest, const void *src, grub_size_t n)
> @@ -1018,17 +1017,6 @@
>    return p - dest;
>  }
>  
> -void
> -grub_millisleep_generic (grub_uint32_t ms)
> -{
> -  grub_uint32_t end_at;
> -
> -  end_at = grub_get_rtc () + grub_div_roundup (ms * GRUB_TICKS_PER_SECOND, 1000);
> -
> -  while (grub_get_rtc () < end_at)
> -    grub_cpu_idle ();
> -}
> -
>  /* Abort GRUB. This function does not return.  */
>  void
>  grub_abort (void)
>
> === modified file 'kern/sparc64/ieee1275/init.c'
> --- kern/sparc64/ieee1275/init.c	2007-10-22 18:59:33 +0000
> +++ kern/sparc64/ieee1275/init.c	2008-07-28 16:23:46 +0000
> @@ -66,12 +66,6 @@
>    /* Never reached.  */
>  }
>  
> -void
> -grub_millisleep (grub_uint32_t ms)
> -{
> -  grub_millisleep_generic (ms);
> -}
> -
>  int
>  grub_ieee1275_test_flag (enum grub_ieee1275_flag flag)
>  {
> @@ -145,6 +139,8 @@
>    grub_free (prefix);
>  }
>  
> +grub_uint64_t ieee1275_get_time_ms (void);
> +
>  void
>  grub_machine_init (void)
>  {
> @@ -201,6 +197,7 @@
>  	}
>      }
>  
> +  grub_install_get_time_ms (ieee1275_get_time_ms);
>  }
>  
>  void
> @@ -216,6 +213,12 @@
>    grub_ieee1275_enter ();
>  }
>  
> +grub_uint64_t
> +ieee1275_get_time_ms (void)
> +{
> +  return grub_get_rtc ();
> +}
> +
>  grub_uint32_t
>  grub_get_rtc (void)
>  {
>
> === added file 'kern/time.c'
> --- kern/time.c	1970-01-01 00:00:00 +0000
> +++ kern/time.c	2008-07-28 16:23:46 +0000
> @@ -0,0 +1,37 @@
> +/* time.c - kernel time functions */
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2008  Free Software Foundation, Inc.
> + *
> + *  GRUB is free software: you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation, either version 3 of the License, or
> + *  (at your option) any later version.
> + *
> + *  GRUB is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <grub/time.h>
> +
> +typedef grub_uint64_t (*get_time_ms_func_t) (void);
> +
> +/* Function pointer to the implementation in use.  */
> +static get_time_ms_func_t get_time_ms_func;
> +
> +grub_uint64_t
> +grub_get_time_ms (void)
> +{
> +  return get_time_ms_func ();
> +}
> +
> +void
> +grub_install_get_time_ms (get_time_ms_func_t func)
> +{
> +  get_time_ms_func = func;
> +}




^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] High resolution time/TSC patch v3
  2008-07-31 19:08         ` Marco Gerards
@ 2008-07-31 19:24           ` Robert Millan
  2008-07-31 20:07             ` Marco Gerards
  0 siblings, 1 reply; 24+ messages in thread
From: Robert Millan @ 2008-07-31 19:24 UTC (permalink / raw)
  To: Marco Gerards; +Cc: The development of GRUB 2, Colin D Bennett

On Thu, Jul 31, 2008 at 09:08:31PM +0200, Marco Gerards wrote:
> Colin D Bennett <colin@gibibit.com> writes:
> 
> > Another updated TSC patch.  Now it detects TSC support for x86 CPUs at
> > runtime and selects either the TSC or RTC time source.  This way 386
> > and 486 CPUs without RDTSC instruction support are supported.
> >
> > Robert Millan was interested in getting this patch merged for the
> > Coreboot port, so I decided to take another crack at it.
> >
> > Comments are welcome!
> 
> Great!  Did you have a look at Roberts comment that it does not work
> in Qemu?  This is the most important testing ground for many of us...

No no, I said it doesn't work on Coreboot.

-- 
Robert Millan

  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
  how) you may access your data; but nobody's threatening your freedom: we
  still allow you to remove your data and not access it at all."



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] High resolution time/TSC patch v3
  2008-07-31 19:24           ` Robert Millan
@ 2008-07-31 20:07             ` Marco Gerards
  2008-07-31 20:35               ` Robert Millan
  0 siblings, 1 reply; 24+ messages in thread
From: Marco Gerards @ 2008-07-31 20:07 UTC (permalink / raw)
  To: Robert Millan; +Cc: The development of GRUB 2, Colin D Bennett

Robert Millan <rmh@aybabtu.com> writes:

> On Thu, Jul 31, 2008 at 09:08:31PM +0200, Marco Gerards wrote:
>> Colin D Bennett <colin@gibibit.com> writes:
>> 
>> > Another updated TSC patch.  Now it detects TSC support for x86 CPUs at
>> > runtime and selects either the TSC or RTC time source.  This way 386
>> > and 486 CPUs without RDTSC instruction support are supported.
>> >
>> > Robert Millan was interested in getting this patch merged for the
>> > Coreboot port, so I decided to take another crack at it.
>> >
>> > Comments are welcome!
>> 
>> Great!  Did you have a look at Roberts comment that it does not work
>> in Qemu?  This is the most important testing ground for many of us...
>
> No no, I said it doesn't work on Coreboot.

Coreboot in Qemu?

--
Marco




^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] High resolution time/TSC patch v3
  2008-07-31 20:07             ` Marco Gerards
@ 2008-07-31 20:35               ` Robert Millan
  0 siblings, 0 replies; 24+ messages in thread
From: Robert Millan @ 2008-07-31 20:35 UTC (permalink / raw)
  To: The development of GRUB 2; +Cc: Colin D Bennett

On Thu, Jul 31, 2008 at 10:07:46PM +0200, Marco Gerards wrote:
> Robert Millan <rmh@aybabtu.com> writes:
> 
> > On Thu, Jul 31, 2008 at 09:08:31PM +0200, Marco Gerards wrote:
> >> Colin D Bennett <colin@gibibit.com> writes:
> >> 
> >> > Another updated TSC patch.  Now it detects TSC support for x86 CPUs at
> >> > runtime and selects either the TSC or RTC time source.  This way 386
> >> > and 486 CPUs without RDTSC instruction support are supported.
> >> >
> >> > Robert Millan was interested in getting this patch merged for the
> >> > Coreboot port, so I decided to take another crack at it.
> >> >
> >> > Comments are welcome!
> >> 
> >> Great!  Did you have a look at Roberts comment that it does not work
> >> in Qemu?  This is the most important testing ground for many of us...
> >
> > No no, I said it doesn't work on Coreboot.
> 
> Coreboot in Qemu?

Yep

-- 
Robert Millan

  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
  how) you may access your data; but nobody's threatening your freedom: we
  still allow you to remove your data and not access it at all."



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] High resolution time/TSC patch v3
  2008-07-28 17:05       ` [PATCH] High resolution time/TSC patch v3 Colin D Bennett
  2008-07-28 17:59         ` Robert Millan
  2008-07-31 19:08         ` Marco Gerards
@ 2008-08-03 19:48         ` Robert Millan
  2008-08-03 23:53           ` TSC on coreboot (Re: [PATCH] High resolution time/TSC patch v3) Robert Millan
  2008-08-05 11:59         ` [PATCH] High resolution time/TSC patch v3 Marco Gerards
  3 siblings, 1 reply; 24+ messages in thread
From: Robert Millan @ 2008-08-03 19:48 UTC (permalink / raw)
  To: The development of GRUB 2

On Mon, Jul 28, 2008 at 10:05:33AM -0700, Colin D Bennett wrote:
> +/* Calibrate the TSC based on the RTC.  */
> +static void
> +calibrate_tsc (void)
> +{
> +  /* First calbrate the TSC rate (relative, not absolute time). */
> +  grub_uint64_t start_tsc;
> +  grub_uint64_t end_tsc;
> +  grub_uint32_t initial_tick;
> +  grub_uint32_t start_tick;
> +  grub_uint32_t end_tick;
> +
> +  /* Wait for the start of the next tick;
> +     we'll base out timing off this edge. */
> +  initial_tick = grub_get_rtc ();

Ah, I see the problem.  It calls grub_get_rtc() which in grub-coreboot is just
a stub.

How about using the interval timer for calibration instead?

-- 
Robert Millan

  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
  how) you may access your data; but nobody's threatening your freedom: we
  still allow you to remove your data and not access it at all."



^ permalink raw reply	[flat|nested] 24+ messages in thread

* TSC on coreboot (Re: [PATCH] High resolution time/TSC patch v3)
  2008-08-03 19:48         ` Robert Millan
@ 2008-08-03 23:53           ` Robert Millan
  2008-08-04  2:14             ` Colin D Bennett
  2008-08-04 20:21             ` Marco Gerards
  0 siblings, 2 replies; 24+ messages in thread
From: Robert Millan @ 2008-08-03 23:53 UTC (permalink / raw)
  To: The development of GRUB 2

[-- Attachment #1: Type: text/plain, Size: 1461 bytes --]

On Sun, Aug 03, 2008 at 09:48:16PM +0200, Robert Millan wrote:
> On Mon, Jul 28, 2008 at 10:05:33AM -0700, Colin D Bennett wrote:
> > +/* Calibrate the TSC based on the RTC.  */
> > +static void
> > +calibrate_tsc (void)
> > +{
> > +  /* First calbrate the TSC rate (relative, not absolute time). */
> > +  grub_uint64_t start_tsc;
> > +  grub_uint64_t end_tsc;
> > +  grub_uint32_t initial_tick;
> > +  grub_uint32_t start_tick;
> > +  grub_uint32_t end_tick;
> > +
> > +  /* Wait for the start of the next tick;
> > +     we'll base out timing off this edge. */
> > +  initial_tick = grub_get_rtc ();
> 
> Ah, I see the problem.  It calls grub_get_rtc() which in grub-coreboot is just
> a stub.
> 
> How about using the interval timer for calibration instead?

Here.  With this patch your code works on coreboot too.

Note:  AFAICT we can't calculate the epoch without RTC.  But then again, this
epoch is just as defined by the time BIOS enables RTC interrupts, so why not
define it ourselves?  I propose that we define epoch as the time in which our
TSC code is initialized.

If knowing the time in which BIOS was started is really useful, maybe we could
#ifdef it instead.  Though if it's not I'd prefer the simplicity.

-- 
Robert Millan

  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
  how) you may access your data; but nobody's threatening your freedom: we
  still allow you to remove your data and not access it at all."

[-- Attachment #2: tsc_coreboot.diff --]
[-- Type: text/x-diff, Size: 6903 bytes --]

diff -Nurp -x .svn -x '*.mk' -x '*~' ../grub2.tsc/conf/i386-coreboot.rmk ./conf/i386-coreboot.rmk
--- ../grub2.tsc/conf/i386-coreboot.rmk	2008-08-04 00:19:11.000000000 +0200
+++ ./conf/i386-coreboot.rmk	2008-08-04 01:40:37.000000000 +0200
@@ -18,6 +18,9 @@ kernel_elf_SOURCES = kern/i386/linuxbios
 	kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \
 	kern/time.c \
 	kern/i386/dl.c kern/parser.c kern/partition.c \
+	kern/i386/tsc.c kern/i386/pit.c \
+	kern/generic/rtc_get_time_ms.c \
+	kern/generic/millisleep.c \
 	kern/env.c \
 	term/i386/pc/console.c \
 	term/i386/pc/at_keyboard.c term/i386/pc/vga_text.c \
diff -Nurp -x .svn -x '*.mk' -x '*~' ../grub2.tsc/conf/i386-pc.rmk ./conf/i386-pc.rmk
--- ../grub2.tsc/conf/i386-pc.rmk	2008-08-04 00:19:11.000000000 +0200
+++ ./conf/i386-pc.rmk	2008-08-04 01:21:32.000000000 +0200
@@ -44,7 +44,7 @@ kernel_img_SOURCES = kern/i386/pc/startu
 	kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \
 	kern/time.c \
 	kern/i386/dl.c kern/i386/pc/init.c kern/parser.c kern/partition.c \
-	kern/i386/tsc.c \
+	kern/i386/tsc.c kern/i386/pit.c \
 	kern/generic/rtc_get_time_ms.c \
 	kern/generic/millisleep.c \
 	kern/env.c \
diff -Nurp -x .svn -x '*.mk' -x '*~' ../grub2.tsc/include/grub/i386/pit.h ./include/grub/i386/pit.h
--- ../grub2.tsc/include/grub/i386/pit.h	1970-01-01 01:00:00.000000000 +0100
+++ ./include/grub/i386/pit.h	2008-08-04 01:22:12.000000000 +0200
@@ -0,0 +1,19 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+extern void grub_pit_wait (grub_uint16_t tics);
diff -Nurp -x .svn -x '*.mk' -x '*~' ../grub2.tsc/kern/i386/linuxbios/init.c ./kern/i386/linuxbios/init.c
--- ../grub2.tsc/kern/i386/linuxbios/init.c	2008-08-04 00:19:11.000000000 +0200
+++ ./kern/i386/linuxbios/init.c	2008-08-04 00:31:45.000000000 +0200
@@ -61,11 +61,6 @@ grub_stop_floppy (void)
 }
 
 void
-grub_millisleep (grub_uint32_t ms __attribute__ ((unused)))
-{
-}
-
-void
 grub_exit (void)
 {
   grub_printf ("grub_exit() is not implemented.\n");
@@ -144,7 +139,7 @@ grub_machine_init (void)
   /* This variable indicates size, not offset.  */
   grub_upper_mem -= GRUB_MEMORY_MACHINE_UPPER_START;
 
-  grub_install_get_time_ms (grub_rtc_get_time_ms);
+  grub_tsc_init ();
 }
 
 void
diff -Nurp -x .svn -x '*.mk' -x '*~' ../grub2.tsc/kern/i386/pit.c ./kern/i386/pit.c
--- ../grub2.tsc/kern/i386/pit.c	1970-01-01 01:00:00.000000000 +0100
+++ ./kern/i386/pit.c	2008-08-04 01:27:07.000000000 +0200
@@ -0,0 +1,39 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/cpu/io.h>
+
+#define TIMER2_REG_CONTROL	0x42
+#define TIMER_REG_COMMAND	0x43
+#define TIMER2_REG_LATCH	0x61
+
+#define TIMER2_SELECT		0x80
+#define TIMER_ENABLE_LSB	0x20
+#define TIMER_ENABLE_MSB	0x10
+#define TIMER2_LATCH		0x20
+
+void
+grub_pit_wait (grub_uint16_t tics)
+{
+  grub_outb (TIMER2_SELECT | TIMER_ENABLE_LSB | TIMER_ENABLE_MSB, TIMER_REG_COMMAND);
+  grub_outb (tics & 0xff, TIMER2_REG_CONTROL);
+  grub_outb (tics >> 8, TIMER2_REG_CONTROL);
+
+  while ((grub_inb (TIMER2_REG_LATCH) & TIMER2_LATCH) == 0x00);
+}
diff -Nurp -x .svn -x '*.mk' -x '*~' ../grub2.tsc/kern/i386/tsc.c ./kern/i386/tsc.c
--- ../grub2.tsc/kern/i386/tsc.c	2008-08-04 00:19:11.000000000 +0200
+++ ./kern/i386/tsc.c	2008-08-04 01:36:51.000000000 +0200
@@ -25,8 +25,7 @@
 #include <grub/misc.h>
 #include <grub/i386/tsc.h>
 
-/* Calibrated reference for TSC=0.  This defines the time since the epoch in 
-   milliseconds that TSC=0 refers to. */
+/* This defines the value TSC had at the epoch (that is, when we calibrated it). */
 static grub_uint64_t tsc_boot_time;
 
 /* Calibrated TSC rate.  (In TSC ticks per millisecond.) */
@@ -47,44 +46,15 @@ grub_tsc_get_time_ms (void)
 static void
 calibrate_tsc (void)
 {
-  /* First calbrate the TSC rate (relative, not absolute time). */
+  /* First calibrate the TSC rate (relative, not absolute time). */
   grub_uint64_t start_tsc;
   grub_uint64_t end_tsc;
-  grub_uint32_t initial_tick;
-  grub_uint32_t start_tick;
-  grub_uint32_t end_tick;
-
-  /* Wait for the start of the next tick;
-     we'll base out timing off this edge. */
-  initial_tick = grub_get_rtc ();
-  do
-    {
-      start_tick = grub_get_rtc ();
-    }
-  while (start_tick == initial_tick);
-  start_tsc = grub_get_tsc ();
 
-  /* Wait for the start of the next tick.  This will
-     be the end of the 1-tick period. */
-  do
-    {
-      end_tick = grub_get_rtc ();
-    }
-  while (end_tick - start_tick < CALIBRATION_TICKS);
+  start_tsc = grub_get_tsc ();
+  grub_pit_wait (0xffff);
   end_tsc = grub_get_tsc ();
 
-  tsc_ticks_per_ms =
-    grub_divmod64 (grub_divmod64
-                   (end_tsc - start_tsc, end_tick - start_tick, 0)
-                   * GRUB_TICKS_PER_SECOND, 1000, 0);
-
-  /* Reference the TSC zero (boot time) to the epoch to 
-     get an absolute real time reference. */
-  grub_uint64_t ms_since_boot = grub_divmod64 (end_tsc, tsc_ticks_per_ms, 0);
-  grub_uint64_t mstime_now = grub_divmod64 ((grub_uint64_t) 1000 * end_tick,
-                                            GRUB_TICKS_PER_SECOND,
-                                            0);
-  tsc_boot_time = mstime_now - ms_since_boot;
+  tsc_ticks_per_ms = grub_divmod64 (end_tsc - start_tsc, 55, 0);
 }
 
 void
@@ -92,6 +62,7 @@ grub_tsc_init (void)
 {
   if (grub_cpu_is_tsc_supported ())
     {
+      tsc_boot_time = grub_get_tsc ();
       calibrate_tsc ();
       grub_install_get_time_ms (grub_tsc_get_time_ms);
     }

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: TSC on coreboot (Re: [PATCH] High resolution time/TSC patch v3)
  2008-08-03 23:53           ` TSC on coreboot (Re: [PATCH] High resolution time/TSC patch v3) Robert Millan
@ 2008-08-04  2:14             ` Colin D Bennett
  2008-08-04  9:09               ` Robert Millan
  2008-08-04 20:21             ` Marco Gerards
  1 sibling, 1 reply; 24+ messages in thread
From: Colin D Bennett @ 2008-08-04  2:14 UTC (permalink / raw)
  To: The development of GRUB 2; +Cc: rmh

[-- Attachment #1: Type: text/plain, Size: 1815 bytes --]

On Mon, 4 Aug 2008 01:53:48 +0200
Robert Millan <rmh@aybabtu.com> wrote:

> On Sun, Aug 03, 2008 at 09:48:16PM +0200, Robert Millan wrote:
> > On Mon, Jul 28, 2008 at 10:05:33AM -0700, Colin D Bennett wrote:
> > > +/* Calibrate the TSC based on the RTC.  */
> > > +static void
> > > +calibrate_tsc (void)
> > > +{
> > > +  /* First calbrate the TSC rate (relative, not absolute time).
> > > */
> > > +  grub_uint64_t start_tsc;
> > > +  grub_uint64_t end_tsc;
> > > +  grub_uint32_t initial_tick;
> > > +  grub_uint32_t start_tick;
> > > +  grub_uint32_t end_tick;
> > > +
> > > +  /* Wait for the start of the next tick;
> > > +     we'll base out timing off this edge. */
> > > +  initial_tick = grub_get_rtc ();
> > 
> > Ah, I see the problem.  It calls grub_get_rtc() which in
> > grub-coreboot is just a stub.
> > 
> > How about using the interval timer for calibration instead?
> 
> Here.  With this patch your code works on coreboot too.
> 
> Note:  AFAICT we can't calculate the epoch without RTC.  But then
> again, this epoch is just as defined by the time BIOS enables RTC
> interrupts, so why not define it ourselves?  I propose that we define
> epoch as the time in which our TSC code is initialized.
> 
> If knowing the time in which BIOS was started is really useful, maybe
> we could #ifdef it instead.  Though if it's not I'd prefer the
> simplicity.

So far we never use the value returned by ``grub_get_time_ms()`` as an
absolute time.  It is currently only used in relative terms, so only
the rate at which it changes is important, not the definition of the
zero point.  Perhaps that simplifies things?  I think it's fine to go
with that definition for now -- if we need to use absolute time at some
point, we can deal with it then.

Regards,
Colin

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: TSC on coreboot (Re: [PATCH] High resolution time/TSC patch v3)
  2008-08-04  2:14             ` Colin D Bennett
@ 2008-08-04  9:09               ` Robert Millan
  0 siblings, 0 replies; 24+ messages in thread
From: Robert Millan @ 2008-08-04  9:09 UTC (permalink / raw)
  To: Colin D Bennett; +Cc: The development of GRUB 2

On Sun, Aug 03, 2008 at 07:14:29PM -0700, Colin D Bennett wrote:
> > 
> > Note:  AFAICT we can't calculate the epoch without RTC.  But then
> > again, this epoch is just as defined by the time BIOS enables RTC
> > interrupts, so why not define it ourselves?  I propose that we define
> > epoch as the time in which our TSC code is initialized.
> > 
> > If knowing the time in which BIOS was started is really useful, maybe
> > we could #ifdef it instead.  Though if it's not I'd prefer the
> > simplicity.
> 
> So far we never use the value returned by ``grub_get_time_ms()`` as an
> absolute time.  It is currently only used in relative terms, so only
> the rate at which it changes is important, not the definition of the
> zero point.  Perhaps that simplifies things?  I think it's fine to go
> with that definition for now -- if we need to use absolute time at some
> point, we can deal with it then.

Hi Colin,

As far as I'm concerned the combined patch can be committed, even without
the cpuid harmonization I suggested (we can always arrange that later).

If there's no objection I'll check it in.

-- 
Robert Millan

  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
  how) you may access your data; but nobody's threatening your freedom: we
  still allow you to remove your data and not access it at all."



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: TSC on coreboot (Re: [PATCH] High resolution time/TSC patch v3)
  2008-08-03 23:53           ` TSC on coreboot (Re: [PATCH] High resolution time/TSC patch v3) Robert Millan
  2008-08-04  2:14             ` Colin D Bennett
@ 2008-08-04 20:21             ` Marco Gerards
  1 sibling, 0 replies; 24+ messages in thread
From: Marco Gerards @ 2008-08-04 20:21 UTC (permalink / raw)
  To: The development of GRUB 2

Hi Robert,

Robert Millan <rmh@aybabtu.com> writes:

You forgot the changelog entry :-)

> On Sun, Aug 03, 2008 at 09:48:16PM +0200, Robert Millan wrote:
>> On Mon, Jul 28, 2008 at 10:05:33AM -0700, Colin D Bennett wrote:
>> > +/* Calibrate the TSC based on the RTC.  */
>> > +static void
>> > +calibrate_tsc (void)
>> > +{
>> > +  /* First calbrate the TSC rate (relative, not absolute time). */
>> > +  grub_uint64_t start_tsc;
>> > +  grub_uint64_t end_tsc;
>> > +  grub_uint32_t initial_tick;
>> > +  grub_uint32_t start_tick;
>> > +  grub_uint32_t end_tick;
>> > +
>> > +  /* Wait for the start of the next tick;
>> > +     we'll base out timing off this edge. */
>> > +  initial_tick = grub_get_rtc ();
>> 
>> Ah, I see the problem.  It calls grub_get_rtc() which in grub-coreboot is just
>> a stub.
>> 
>> How about using the interval timer for calibration instead?
>
> Here.  With this patch your code works on coreboot too.
>
> Note:  AFAICT we can't calculate the epoch without RTC.  But then again, this
> epoch is just as defined by the time BIOS enables RTC interrupts, so why not
> define it ourselves?  I propose that we define epoch as the time in which our
> TSC code is initialized.
>
> If knowing the time in which BIOS was started is really useful, maybe we could
> #ifdef it instead.  Though if it's not I'd prefer the simplicity.

If this works and fixes coreboot, it is fine to me ;-)

One comment follows below.

> --- ../grub2.tsc/include/grub/i386/pit.h	1970-01-01 01:00:00.000000000 +0100
> +++ ./include/grub/i386/pit.h	2008-08-04 01:22:12.000000000 +0200
> @@ -0,0 +1,19 @@
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2008  Free Software Foundation, Inc.
> + *
> + *  GRUB is free software: you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation, either version 3 of the License, or
> + *  (at your option) any later version.
> + *
> + *  GRUB is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +extern void grub_pit_wait (grub_uint16_t tics);

Please us an inclusion guard.

--
Marco




^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] High resolution time/TSC patch v3
  2008-07-28 17:05       ` [PATCH] High resolution time/TSC patch v3 Colin D Bennett
                           ` (2 preceding siblings ...)
  2008-08-03 19:48         ` Robert Millan
@ 2008-08-05 11:59         ` Marco Gerards
  2008-08-05 20:24           ` Robert Millan
  3 siblings, 1 reply; 24+ messages in thread
From: Marco Gerards @ 2008-08-05 11:59 UTC (permalink / raw)
  To: Colin D Bennett; +Cc: The development of GRUB 2, Robert Millan

Hi Colin,

Colin D Bennett <colin@gibibit.com> writes:

> Another updated TSC patch.  Now it detects TSC support for x86 CPUs at
> runtime and selects either the TSC or RTC time source.  This way 386
> and 486 CPUs without RDTSC instruction support are supported.
>
> Robert Millan was interested in getting this patch merged for the
> Coreboot port, so I decided to take another crack at it.
>
> Comments are welcome!

I have just committed your patch, with the ChangeLog changes I
proposed.  Please have a look to see what I changed.

--
Marco




^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] High resolution time/TSC patch v3
  2008-08-05 11:59         ` [PATCH] High resolution time/TSC patch v3 Marco Gerards
@ 2008-08-05 20:24           ` Robert Millan
  0 siblings, 0 replies; 24+ messages in thread
From: Robert Millan @ 2008-08-05 20:24 UTC (permalink / raw)
  To: The development of GRUB 2; +Cc: Colin D Bennett

On Tue, Aug 05, 2008 at 01:59:28PM +0200, Marco Gerards wrote:
> Hi Colin,
> 
> Colin D Bennett <colin@gibibit.com> writes:
> 
> > Another updated TSC patch.  Now it detects TSC support for x86 CPUs at
> > runtime and selects either the TSC or RTC time source.  This way 386
> > and 486 CPUs without RDTSC instruction support are supported.
> >
> > Robert Millan was interested in getting this patch merged for the
> > Coreboot port, so I decided to take another crack at it.
> >
> > Comments are welcome!
> 
> I have just committed your patch, with the ChangeLog changes I
> proposed.  Please have a look to see what I changed.

Ok I committed my followup patch too.

-- 
Robert Millan

  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
  how) you may access your data; but nobody's threatening your freedom: we
  still allow you to remove your data and not access it at all."



^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2008-08-05 20:26 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-06-23 14:54 [RFC] High resolution time support using x86 TSC Colin D Bennett
2008-07-03 18:52 ` Marco Gerards
2008-07-04 15:58   ` Colin D Bennett
2008-07-04 16:10     ` Vesa Jääskeläinen
2008-07-04 17:26   ` Colin D Bennett
2008-07-20 18:21     ` Marco Gerards
2008-07-04 18:28   ` [RFC] TSC patch v2 Colin D Bennett
2008-07-04 19:49     ` Vesa Jääskeläinen
2008-07-04 20:38       ` Colin D Bennett
2008-07-04 20:48         ` Vesa Jääskeläinen
2008-07-20 18:45     ` Marco Gerards
2008-07-28 17:05       ` [PATCH] High resolution time/TSC patch v3 Colin D Bennett
2008-07-28 17:59         ` Robert Millan
2008-07-31 19:08         ` Marco Gerards
2008-07-31 19:24           ` Robert Millan
2008-07-31 20:07             ` Marco Gerards
2008-07-31 20:35               ` Robert Millan
2008-08-03 19:48         ` Robert Millan
2008-08-03 23:53           ` TSC on coreboot (Re: [PATCH] High resolution time/TSC patch v3) Robert Millan
2008-08-04  2:14             ` Colin D Bennett
2008-08-04  9:09               ` Robert Millan
2008-08-04 20:21             ` Marco Gerards
2008-08-05 11:59         ` [PATCH] High resolution time/TSC patch v3 Marco Gerards
2008-08-05 20:24           ` Robert Millan

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.