From be92c65ffc88eb3e52f2a85194bc5303bd20f642 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sun, 22 Sep 2013 10:22:29 -0500 Subject: [PATCH] count TSC ticks instead of relying on CPUID The clock frequency stated for newer CPUs does not match the TSC frequency; count the ticks during one millisecond instead. --- src/efi/gummiboot.c | 97 ++++++++--------------------------------------------- 1 file changed, 14 insertions(+), 83 deletions(-) diff --git a/src/efi/gummiboot.c b/src/efi/gummiboot.c index f883087..1e16ef0 100644 --- a/src/efi/gummiboot.c +++ b/src/efi/gummiboot.c @@ -98,101 +98,32 @@ static UINT64 ticks_read(void) { } #endif -static void cpuid_read(UINT32 info, UINT32 *eax, UINT32 *ebx, UINT32 *ecx, UINT32 *edx) { - *eax = info; - __asm__ volatile ( - "mov %%ebx, %%edi;" - "cpuid;" - "mov %%ebx, %%esi;" - "mov %%edi, %%ebx;" - :"+a" (*eax), "=S" (*ebx), "=c" (*ecx), "=d" (*edx) - : :"edi" - ); -} - -static UINT64 cpufreq_read(void) { - UINT32 eax, ebx, ecx, edx; - union { - UINT32 i[3][4]; - CHAR8 s[4 * 4 * 3 + 1]; - } brand; - UINTN i; - CHAR8 *s; - UINT64 scale; - CHAR16 *str; - static UINT64 usec; - - if (usec > 0) - return usec; - - for (i = 0; i < 3; i++) { - cpuid_read(0x80000002 + i, &eax, &ebx, &ecx, &edx); - brand.i[i][0] = eax; - brand.i[i][1] = ebx; - brand.i[i][2] = ecx; - brand.i[i][3] = edx; - } - brand.s[4 * 4 * 3] = '\0'; - - /* - * Extract: - * “x.xxyHz” or “xxxxyHz”, where y=M,G,T - * from CPUID brand string: - * Intel(R) Core(TM) i5-2540M CPU @ 2.60GHz - * - * http://www.intel.com/content/dam/www/public/us/en/documents/ - * application-notes/processor-identification-cpuid-instruction-note.pdf - */ - s = NULL; - for (i = 4; i < (4 * 4 * 3) - 2; i++) { - if (brand.s[i+1] == 'H' && brand.s[i+2] == 'z') { - s = brand.s + i; - break; - } - } - if (!s) - return 0; +/* count TSC ticks during a millisecond delay */ +static UINT64 ticks_freq(void) { + UINT64 ticks_start, ticks_end; - scale = 1000; - switch(*s){ - case 'T': - scale *= 1000; - case 'G': - scale *= 1000; - case 'M': - scale *= 1000; - break; - default: - return 0; - } - - s -= 4; - s[4] = '\0'; - if (s[1] == '.') { - s[1] = s[0]; - s++; - scale /= 100; - } + ticks_start = ticks_read(); + uefi_call_wrapper(BS->Stall, 1, 1000); + ticks_end = ticks_read(); - str = stra_to_str(s); - usec = Atoi(str) * scale; - FreePool(str); - return usec; + return (ticks_end - ticks_start) * 1000; } static UINT64 time_usec(void) { UINT64 ticks; - UINT64 cpufreq; + static UINT64 freq; ticks = ticks_read(); if (ticks == 0) return 0; - cpufreq = cpufreq_read(); - if (cpufreq == 0) - return 0; + if (freq == 0) { + freq = ticks_freq(); + if (freq == 0) + return 0; + } - return 1000 * 1000 * ticks / cpufreq; + return 1000 * 1000 * ticks / freq; } static EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, CHAR16 *name, CHAR8 *buf, UINTN size, BOOLEAN persistent) { -- 2.7.4