grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH] High resolution time/TSC patch v3


From: Marco Gerards
Subject: Re: [PATCH] High resolution time/TSC patch v3
Date: Thu, 31 Jul 2008 21:08:31 +0200
User-agent: Gnus/5.110006 (No Gnus v0.6) Emacs/21.4 (gnu/linux)

Colin D Bennett <address@hidden> 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 <address@hidden>
> +
> +     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  <address@hidden>
>  
>       * 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;
> +}





reply via email to

[Prev in Thread] Current Thread [Next in Thread]