From 9c2ff3eefe87cd6aae5946ec80dda10a8cc9127d Mon Sep 17 00:00:00 2001 From: marco_g Date: Tue, 5 Aug 2008 11:54:37 +0000 Subject: [PATCH] 2008-08-05 Colin D Bennett 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-pc.rmk (kernel_img_SOURCES): Add `kern/time.c', `kern/i386/tsc.c', `kern/generic/rtc_get_time_ms.c' and `kern/generic/millisleep.c'. * conf/i386-efi.rmk (kernel_mod_SOURCES): Add `kern/i386/tsc.c', `kern/generic/rtc_get_time_ms.c' and `kern/generic/millisleep.c'. * conf/x86_64-efi.rml (kernel_mod_SOURCES): Add `kern/generic/millisleep.c' and `kern/generic/rtc_get_time_ms.c'. * conf/sparc64-ieee1275.rmk (kernel_elf_SOURCES): Likewise. * conf/powerpc-ieee1275.rmk (kernel_elf_SOURCES): Add `kern/generic/millisleep.c'. * conf/i386-ieee1275.rmk (kernel_elf_SOURCES): Likewise. * conf/i386-coreboot.rmk (kernel_elf_SOURCES): Add `kern/time.c'. * kern/generic/rtc_get_time_ms.c: New file. * kern/generic/millisleep.c: New file. * kern/misc.c: Don't include anymore. (grub_millisleep_generic): Removed. * commands/sleep.c (grub_interruptible_millisleep): Uses grub_get_time_ms() instead of grub_get_rtc(). * 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. * include/grub/time.h: Include . Don't include anymore. (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: Include . (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 function. (grub_get_rtc): Now calls ieee1275_get_time_ms(), which does the real work. --- ChangeLog | 79 ++++++++++++++++++++++++++++++++++++ commands/sleep.c | 12 +++--- conf/i386-coreboot.rmk | 1 + conf/i386-efi.rmk | 5 ++- conf/i386-ieee1275.rmk | 1 + conf/i386-pc.rmk | 4 ++ conf/powerpc-ieee1275.rmk | 1 + conf/sparc64-ieee1275.rmk | 1 + conf/x86_64-efi.rmk | 1 + include/grub/time.h | 9 +++- kern/i386/efi/init.c | 9 +--- kern/i386/linuxbios/init.c | 2 + kern/i386/pc/init.c | 9 ++-- kern/ieee1275/init.c | 20 +++++---- kern/misc.c | 12 ------ kern/sparc64/ieee1275/init.c | 15 ++++--- 16 files changed, 133 insertions(+), 48 deletions(-) diff --git a/ChangeLog b/ChangeLog index f0a68eb00..68b63686f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,82 @@ +2008-08-05 Colin D Bennett + + 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-pc.rmk (kernel_img_SOURCES): Add `kern/time.c', + `kern/i386/tsc.c', `kern/generic/rtc_get_time_ms.c' and + `kern/generic/millisleep.c'. + + * conf/i386-efi.rmk (kernel_mod_SOURCES): Add `kern/i386/tsc.c', + `kern/generic/rtc_get_time_ms.c' and `kern/generic/millisleep.c'. + + * conf/x86_64-efi.rml (kernel_mod_SOURCES): Add + `kern/generic/millisleep.c' and `kern/generic/rtc_get_time_ms.c'. + + * conf/sparc64-ieee1275.rmk (kernel_elf_SOURCES): Likewise. + + * conf/powerpc-ieee1275.rmk (kernel_elf_SOURCES): Add + `kern/generic/millisleep.c'. + + * conf/i386-ieee1275.rmk (kernel_elf_SOURCES): Likewise. + + * conf/i386-coreboot.rmk (kernel_elf_SOURCES): Add `kern/time.c'. + + * kern/generic/rtc_get_time_ms.c: New file. + + * kern/generic/millisleep.c: New file. + + * kern/misc.c: Don't include + anymore. + (grub_millisleep_generic): Removed. + + * commands/sleep.c (grub_interruptible_millisleep): Uses + grub_get_time_ms() instead of grub_get_rtc(). + + * 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. + + * include/grub/time.h: Include . Don't include + anymore. + (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: Include . + (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 function. + (grub_get_rtc): Now calls ieee1275_get_time_ms(), which does the + real work. + 2008-08-05 Marco Gerards * disk/ata.c: Include . diff --git a/commands/sleep.c b/commands/sleep.c index c4744c57a..46c13268c 100644 --- a/commands/sleep.c +++ b/commands/sleep.c @@ -43,15 +43,15 @@ do_print (int n) 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; diff --git a/conf/i386-coreboot.rmk b/conf/i386-coreboot.rmk index c4dc567be..c4ca95e8c 100644 --- a/conf/i386-coreboot.rmk +++ b/conf/i386-coreboot.rmk @@ -16,6 +16,7 @@ kernel_elf_SOURCES = kern/i386/linuxbios/startup.S kern/i386/linuxbios/init.c \ 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 \ diff --git a/conf/i386-efi.rmk b/conf/i386-efi.rmk index 308dec4f0..e35a5c9a7 100644 --- a/conf/i386-efi.rmk +++ b/conf/i386-efi.rmk @@ -84,7 +84,10 @@ kernel_mod_SOURCES = kern/i386/efi/startup.S kern/main.c kern/device.c \ 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 \ diff --git a/conf/i386-ieee1275.rmk b/conf/i386-ieee1275.rmk index 1c7856227..818dc9191 100644 --- a/conf/i386-ieee1275.rmk +++ b/conf/i386-ieee1275.rmk @@ -19,6 +19,7 @@ kernel_elf_SOURCES = kern/i386/ieee1275/startup.S kern/i386/ieee1275/init.c \ 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 \ diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index 8617a9216..e400ffc63 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -42,7 +42,11 @@ cdboot_img_LDFLAGS = $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS) -Wl,-Ttext,7C00 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 diff --git a/conf/powerpc-ieee1275.rmk b/conf/powerpc-ieee1275.rmk index 9d7a6727d..0ed75f3e3 100644 --- a/conf/powerpc-ieee1275.rmk +++ b/conf/powerpc-ieee1275.rmk @@ -85,6 +85,7 @@ kernel_elf_SOURCES = kern/powerpc/ieee1275/crt0.S kern/ieee1275/cmain.c \ 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) diff --git a/conf/sparc64-ieee1275.rmk b/conf/sparc64-ieee1275.rmk index 8083e8c5f..4571bbdc9 100644 --- a/conf/sparc64-ieee1275.rmk +++ b/conf/sparc64-ieee1275.rmk @@ -73,6 +73,7 @@ kernel_elf_SOURCES = kern/sparc64/ieee1275/init.c kern/ieee1275/ieee1275.c \ 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) diff --git a/conf/x86_64-efi.rmk b/conf/x86_64-efi.rmk index 744eda49e..25dc8eb22 100644 --- a/conf/x86_64-efi.rmk +++ b/conf/x86_64-efi.rmk @@ -87,6 +87,7 @@ kernel_mod_SOURCES = kern/x86_64/efi/startup.S kern/x86_64/efi/callwrap.S \ 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 \ diff --git a/include/grub/time.h b/include/grub/time.h index bf017d204..4dcd843de 100644 --- a/include/grub/time.h +++ b/include/grub/time.h @@ -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 #include #include #include 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_sleep (grub_uint32_t s) grub_millisleep (1000 * s); } +void grub_install_get_time_ms (grub_uint64_t (*get_time_ms_func) (void)); + #endif /* ! KERNEL_TIME_HEADER */ diff --git a/kern/i386/efi/init.c b/kern/i386/efi/init.c index 0683502a8..e9cc07078 100644 --- a/kern/i386/efi/init.c +++ b/kern/i386/efi/init.c @@ -25,18 +25,13 @@ #include #include #include -#include - -void -grub_millisleep (grub_uint32_t ms) -{ - grub_millisleep_generic (ms); -} +#include void grub_machine_init (void) { grub_efi_init (); + grub_tsc_init (); } void diff --git a/kern/i386/linuxbios/init.c b/kern/i386/linuxbios/init.c index 7293a394a..1d25986b7 100644 --- a/kern/i386/linuxbios/init.c +++ b/kern/i386/linuxbios/init.c @@ -143,6 +143,8 @@ 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); } void diff --git a/kern/i386/pc/init.c b/kern/i386/pc/init.c index 0e973eaf4..955a52f08 100644 --- a/kern/i386/pc/init.c +++ b/kern/i386/pc/init.c @@ -30,6 +30,7 @@ #include #include #include +#include struct mem_region { @@ -46,12 +47,6 @@ grub_addr_t grub_os_area_addr; 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 @@ grub_machine_init (void) if (! grub_os_area_addr) grub_fatal ("no upper memory"); + + grub_tsc_init (); } void diff --git a/kern/ieee1275/init.c b/kern/ieee1275/init.c index d1d53e0cf..513e81fea 100644 --- a/kern/ieee1275/init.c +++ b/kern/ieee1275/init.c @@ -46,12 +46,6 @@ extern char _start[]; extern char _end[]; -void -grub_millisleep (grub_uint32_t ms) -{ - grub_millisleep_generic (ms); -} - void grub_exit (void) { @@ -209,6 +203,8 @@ grub_get_extended_memory (void) #endif +static grub_uint64_t ieee1275_get_time_ms (void); + void grub_machine_init (void) { @@ -258,6 +254,8 @@ grub_machine_init (void) } } } + + grub_install_get_time_ms (ieee1275_get_time_ms); } void @@ -267,8 +265,8 @@ grub_machine_fini (void) grub_console_fini (); } -grub_uint32_t -grub_get_rtc (void) +static grub_uint64_t +ieee1275_get_time_ms (void) { grub_uint32_t msecs = 0; @@ -277,6 +275,12 @@ grub_get_rtc (void) return msecs; } +grub_uint32_t +grub_get_rtc (void) +{ + return ieee1275_get_time_ms (); +} + grub_addr_t grub_arch_modules_addr (void) { diff --git a/kern/misc.c b/kern/misc.c index c662c963c..83fcc1684 100644 --- a/kern/misc.c +++ b/kern/misc.c @@ -23,7 +23,6 @@ #include #include #include -#include void * grub_memmove (void *dest, const void *src, grub_size_t n) @@ -1018,17 +1017,6 @@ grub_utf8_to_ucs4 (grub_uint32_t *dest, const grub_uint8_t *src, 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) diff --git a/kern/sparc64/ieee1275/init.c b/kern/sparc64/ieee1275/init.c index dbc1fee3e..57ffc3898 100644 --- a/kern/sparc64/ieee1275/init.c +++ b/kern/sparc64/ieee1275/init.c @@ -66,12 +66,6 @@ _start (uint64_t r0 __attribute__((unused)), /* 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_machine_set_prefix (void) grub_free (prefix); } +grub_uint64_t ieee1275_get_time_ms (void); + void grub_machine_init (void) { @@ -201,6 +197,7 @@ grub_machine_init (void) } } + grub_install_get_time_ms (ieee1275_get_time_ms); } void @@ -216,6 +213,12 @@ grub_exit (void) grub_ieee1275_enter (); } +grub_uint64_t +ieee1275_get_time_ms (void) +{ + return grub_get_rtc (); +} + grub_uint32_t grub_get_rtc (void) {