All of lore.kernel.org
 help / color / mirror / Atom feed
From: Marco Gerards <mgerards@xs4all.nl>
To: Colin D Bennett <colin@gibibit.com>
Cc: The development of GRUB 2 <grub-devel@gnu.org>,
	Robert Millan <rmh@aybabtu.com>
Subject: Re: [PATCH] High resolution time/TSC patch v3
Date: Thu, 31 Jul 2008 21:08:31 +0200	[thread overview]
Message-ID: <873alpkh1s.fsf@xs4all.nl> (raw)
In-Reply-To: <20080728100533.19118c0b@gibibit.com> (Colin D. Bennett's message of "Mon, 28 Jul 2008 10:05:33 -0700")

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;
> +}




  parent reply	other threads:[~2008-07-31 19:06 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=873alpkh1s.fsf@xs4all.nl \
    --to=mgerards@xs4all.nl \
    --cc=colin@gibibit.com \
    --cc=grub-devel@gnu.org \
    --cc=rmh@aybabtu.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.