From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from list by lists.gnu.org with archive (Exim 4.71) id 1ZvnKi-0001b6-4R for mharc-grub-devel@gnu.org; Mon, 09 Nov 2015 09:22:08 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:36174) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZvnKd-0001aw-Rd for grub-devel@gnu.org; Mon, 09 Nov 2015 09:22:06 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ZvnKX-0006dI-CC for grub-devel@gnu.org; Mon, 09 Nov 2015 09:22:03 -0500 Received: from mail-wm0-x229.google.com ([2a00:1450:400c:c09::229]:33025) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZvnKX-0006dE-03 for grub-devel@gnu.org; Mon, 09 Nov 2015 09:21:57 -0500 Received: by wmec201 with SMTP id c201so81975331wme.0 for ; Mon, 09 Nov 2015 06:21:56 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=subject:to:references:from:message-id:date:user-agent:mime-version :in-reply-to:content-type; bh=woJ6zDDYeTiIOnKaT6ZbcC6djL86JNsXskZH0WsAjbw=; b=RnPzE8dEisP0oy2bpwEttWFcJYjKCj4hvmXbdPzuYic9kfKwhlrpgmSjeFRL/ihp25 VzTfhidDthzTQ4BdSV4PlTe5sFTvRMGgzbSUW+Q/s+MFZ2fvhSMaSN7PnVF4o17xJ8FZ IIaVFvkTrxvxGEBLSVxdSQ7zByk764hnKyDGvV/ZmObapp14r+Z3J6tUS81MrvexVOjT u0vg+uaBAEadWOt+db0IjmQtQXLdZB7gDuluD4tsyl+6W+3cmlEbPaOo/y9Mf5vPmO8F CH9GHPi4HzaSbuZeGRYDCGA0a7lRow/YEcRBt4RfT4YGCjygA1fCp0W4WcjUe8wU33oR t3HQ== X-Received: by 10.28.16.132 with SMTP id 126mr24815753wmq.86.1447078916398; Mon, 09 Nov 2015 06:21:56 -0800 (PST) Received: from ?IPv6:2620:0:105f:fd00:863a:4bff:fe50:abc4? ([2620:0:105f:fd00:863a:4bff:fe50:abc4]) by smtp.gmail.com with ESMTPSA id e189sm14590396wma.4.2015.11.09.06.21.54 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 09 Nov 2015 06:21:55 -0800 (PST) Subject: Re: [PATCH] Use UEFI Time Service to calibrate TSC To: The development of GNU GRUB References: <20151109070746.GA21701@linux-dsax.tai.apac.novell.com> <20151109080356.GA20546@linux-dsax.tai.apac.novell.com> <56409E38.8010804@gmail.com> From: =?UTF-8?Q?Vladimir_'=cf=86-coder/phcoder'_Serbinenko?= X-Enigmail-Draft-Status: N1110 Message-ID: <5640ABF1.1020801@gmail.com> Date: Mon, 9 Nov 2015 15:21:37 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Icedove/38.3.0 MIME-Version: 1.0 In-Reply-To: <56409E38.8010804@gmail.com> Content-Type: multipart/signed; micalg=pgp-sha512; protocol="application/pgp-signature"; boundary="triKCQSHgCpwrEUJ8562QhMtRPlnJCcmJ" X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2a00:1450:400c:c09::229 X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.14 Precedence: list Reply-To: The development of GNU GRUB List-Id: The development of GNU GRUB List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 09 Nov 2015 14:22:06 -0000 This is an OpenPGP/MIME signed message (RFC 4880 and 3156) --triKCQSHgCpwrEUJ8562QhMtRPlnJCcmJ Content-Type: multipart/mixed; boundary="------------080308090402060904020605" This is a multi-part message in MIME format. --------------080308090402060904020605 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable On 09.11.2015 14:23, Vladimir '=CF=86-coder/phcoder' Serbinenko wrote: > On 09.11.2015 09:03, Michael Chang wrote: >> On Mon, Nov 09, 2015 at 10:29:55AM +0300, Andrei Borzenkov wrote: >>> On Mon, Nov 9, 2015 at 10:07 AM, Michael Chang wrot= e: >>>> This patch tries to detect PIT timer is broken and use UEFI Time Ser= vice >>>> to calibrate TSC. >>> >>> Second try :) >>> >>> https://lists.gnu.org/archive/html/grub-devel/2014-11/msg00079.html >>> >>> Although I think that this one is acceptable - it is used as fallback= >>> only. Will it also catch the case when PIT is not present at all? >> >> I think yes, actually this patch was tested and can fix the timeout >> problem on hyper-v Generation 2 VMs with UEFI, which is known to ship >> without PIT. >> >> In addition to that, the linux kernel also calibrates the tsc via PIT = as >> default on x86. >> >> http://lxr.free-electrons.com/source/arch/x86/kernel/tsc.c#L441 >> >> But with some sanity checks to detect the SMI storm interfering the >> result and will fallback to other timer sources if the sanity check >> fails. This patch is inspired by that one of that check with much more= >> restricted loopmin to "1" that's basically a insane condition.=20 >> > I like some aspects of this patch, i.a. that it's unlikely to break > compatibility. ut I feel that we can do a bit better: > 1) Returning through pointed variable is expensive in terms of binary > size. Just plain return is better. > 2) More modern calibrations can calibrate in 1ms, not 55ms. This is one= > that slows down coreboot boot (I think only USB init is slower). > 3) We could have a cascade of methods. E.g. > on EFI: PIT -> PM -> Stall -> hardcoded 1GHz (putting PM as first would= > be slightly more risk > on coreboot: PM -> PIT -> hardcoded 1GHz > rest: PIT -> hardcoded 1GHz (need to keep size down) >=20 > I'm going to prepare proof-of-concept patch Attached proof-of-concept. It's all in one file but different methods should probably go in separate files. --------------080308090402060904020605 Content-Type: text/x-diff; name="pm.diff" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="pm.diff" diff --git a/grub-core/commands/efi/acpi.c b/grub-core/commands/efi/acpi.= c deleted file mode 100644 index 74f8cd1..0000000 --- a/grub-core/commands/efi/acpi.c +++ /dev/null @@ -1,59 +0,0 @@ -/* acpi.c - get acpi tables. */ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2009 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 . - */ - -#include -#include -#include -#include - -struct grub_acpi_rsdp_v10 * -grub_machine_acpi_get_rsdpv1 (void) -{ - unsigned i; - static grub_efi_packed_guid_t acpi_guid =3D GRUB_EFI_ACPI_TABLE_GUID; - - for (i =3D 0; i < grub_efi_system_table->num_table_entries; i++) - { - grub_efi_packed_guid_t *guid =3D - &grub_efi_system_table->configuration_table[i].vendor_guid; - - if (! grub_memcmp (guid, &acpi_guid, sizeof (grub_efi_packed_guid_= t))) - return (struct grub_acpi_rsdp_v10 *) - grub_efi_system_table->configuration_table[i].vendor_table; - } - return 0; -} - -struct grub_acpi_rsdp_v20 * -grub_machine_acpi_get_rsdpv2 (void) -{ - unsigned i; - static grub_efi_packed_guid_t acpi20_guid =3D GRUB_EFI_ACPI_20_TABLE_G= UID; - - for (i =3D 0; i < grub_efi_system_table->num_table_entries; i++) - { - grub_efi_packed_guid_t *guid =3D - &grub_efi_system_table->configuration_table[i].vendor_guid; - - if (! grub_memcmp (guid, &acpi20_guid, sizeof (grub_efi_packed_gui= d_t))) - return (struct grub_acpi_rsdp_v20 *) - grub_efi_system_table->configuration_table[i].vendor_table; - } - return 0; -} diff --git a/grub-core/kern/acpi.c b/grub-core/kern/acpi.c new file mode 100644 index 0000000..5292597 --- /dev/null +++ b/grub-core/kern/acpi.c @@ -0,0 +1,119 @@ +/*=20 + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2012 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 . + */ + +#include +#include +#include +#include + +static void * +grub_acpi_rsdt_find_table (struct grub_acpi_table_header *rsdt, const ch= ar *sig) +{ + grub_size_t s; + grub_uint32_t *ptr; + + if (!rsdt) + return 0; + + if (grub_memcmp (rsdt->signature, "RSDT", 4) !=3D 0) + return 0; + + ptr =3D (grub_uint32_t *) (rsdt + 1); + s =3D (rsdt->length - sizeof (*rsdt)) / sizeof (grub_uint32_t); + for (; s; s--, ptr++) + { + struct grub_acpi_table_header *tbl; + tbl =3D (struct grub_acpi_table_header *) (grub_addr_t) *ptr; + if (grub_memcmp (tbl->signature, sig, 4) =3D=3D 0) + return tbl; + } + return 0; +} + +static void * +grub_acpi_xsdt_find_table (struct grub_acpi_table_header *xsdt, const ch= ar *sig) +{ + grub_size_t s; + grub_uint64_t *ptr; + + if (!xsdt) + return 0; + + if (grub_memcmp (xsdt->signature, "XSDT", 4) !=3D 0) + return 0; + + ptr =3D (grub_uint64_t *) (xsdt + 1); + s =3D (xsdt->length - sizeof (*xsdt)) / sizeof (grub_uint32_t); + for (; s; s--, ptr++) + { + struct grub_acpi_table_header *tbl; +#if GRUB_CPU_SIZEOF_VOID_P !=3D 8 + if (*ptr >> 32) + continue; +#endif + tbl =3D (struct grub_acpi_table_header *) (grub_addr_t) *ptr; + if (grub_memcmp (tbl->signature, sig, 4) =3D=3D 0) + return tbl; + } + return 0; +} + +struct grub_acpi_fadt * +grub_acpi_find_fadt (void) +{ + struct grub_acpi_fadt *fadt =3D 0; + struct grub_acpi_rsdp_v10 *rsdpv1; + struct grub_acpi_rsdp_v20 *rsdpv2; + rsdpv1 =3D grub_machine_acpi_get_rsdpv1 (); + if (rsdpv1) + fadt =3D grub_acpi_rsdt_find_table ((struct grub_acpi_table_header *= ) + (grub_addr_t) rsdpv1->rsdt_addr, + GRUB_ACPI_FADT_SIGNATURE); + if (fadt) + return fadt; + rsdpv2 =3D grub_machine_acpi_get_rsdpv2 (); + if (rsdpv2) + fadt =3D grub_acpi_rsdt_find_table ((struct grub_acpi_table_header *= ) + (grub_addr_t) rsdpv2->rsdpv1.rsdt_addr, + GRUB_ACPI_FADT_SIGNATURE); + if (fadt) + return fadt; + if (rsdpv2 +#if GRUB_CPU_SIZEOF_VOID_P !=3D 8 + && !(rsdpv2->xsdt_addr >> 32) +#endif + ) + fadt =3D grub_acpi_xsdt_find_table ((struct grub_acpi_table_header *= ) + (grub_addr_t) rsdpv2->xsdt_addr, + GRUB_ACPI_FADT_SIGNATURE); + if (fadt) + return fadt; + return 0; +} + +/* Simple checksum by summing all bytes. Used by ACPI and SMBIOS. */ +grub_uint8_t +grub_byte_checksum (void *base, grub_size_t size) +{ + grub_uint8_t *ptr; + grub_uint8_t ret =3D 0; + for (ptr =3D (grub_uint8_t *) base; ptr < ((grub_uint8_t *) base) + si= ze; + ptr++) + ret +=3D *ptr; + return ret; +} diff --git a/grub-core/kern/efi/acpi.c b/grub-core/kern/efi/acpi.c new file mode 100644 index 0000000..74f8cd1 --- /dev/null +++ b/grub-core/kern/efi/acpi.c @@ -0,0 +1,59 @@ +/* acpi.c - get acpi tables. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 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 . + */ + +#include +#include +#include +#include + +struct grub_acpi_rsdp_v10 * +grub_machine_acpi_get_rsdpv1 (void) +{ + unsigned i; + static grub_efi_packed_guid_t acpi_guid =3D GRUB_EFI_ACPI_TABLE_GUID; + + for (i =3D 0; i < grub_efi_system_table->num_table_entries; i++) + { + grub_efi_packed_guid_t *guid =3D + &grub_efi_system_table->configuration_table[i].vendor_guid; + + if (! grub_memcmp (guid, &acpi_guid, sizeof (grub_efi_packed_guid_= t))) + return (struct grub_acpi_rsdp_v10 *) + grub_efi_system_table->configuration_table[i].vendor_table; + } + return 0; +} + +struct grub_acpi_rsdp_v20 * +grub_machine_acpi_get_rsdpv2 (void) +{ + unsigned i; + static grub_efi_packed_guid_t acpi20_guid =3D GRUB_EFI_ACPI_20_TABLE_G= UID; + + for (i =3D 0; i < grub_efi_system_table->num_table_entries; i++) + { + grub_efi_packed_guid_t *guid =3D + &grub_efi_system_table->configuration_table[i].vendor_guid; + + if (! grub_memcmp (guid, &acpi20_guid, sizeof (grub_efi_packed_gui= d_t))) + return (struct grub_acpi_rsdp_v20 *) + grub_efi_system_table->configuration_table[i].vendor_table; + } + return 0; +} diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am index af0c7f4..7a1ffdc 100644 --- a/grub-core/Makefile.am +++ b/grub-core/Makefile.am @@ -101,6 +101,7 @@ if COND_i386_efi KERNEL_HEADER_FILES +=3D $(top_srcdir)/include/grub/efi/efi.h KERNEL_HEADER_FILES +=3D $(top_srcdir)/include/grub/efi/disk.h KERNEL_HEADER_FILES +=3D $(top_srcdir)/include/grub/i386/tsc.h +KERNEL_HEADER_FILES +=3D $(top_srcdir)/include/grub/acpi.h KERNEL_HEADER_FILES +=3D $(top_srcdir)/include/grub/pci.h endif =20 @@ -112,6 +113,7 @@ KERNEL_HEADER_FILES +=3D $(top_srcdir)/include/grub/v= ideo_fb.h KERNEL_HEADER_FILES +=3D $(top_srcdir)/include/grub/gfxterm.h KERNEL_HEADER_FILES +=3D $(top_srcdir)/include/grub/font.h KERNEL_HEADER_FILES +=3D $(top_srcdir)/include/grub/bufio.h +KERNEL_HEADER_FILES +=3D $(top_srcdir)/include/grub/acpi.h endif =20 if COND_i386_multiboot @@ -154,6 +156,7 @@ KERNEL_HEADER_FILES +=3D $(top_srcdir)/include/grub/e= fi/efi.h KERNEL_HEADER_FILES +=3D $(top_srcdir)/include/grub/efi/disk.h KERNEL_HEADER_FILES +=3D $(top_srcdir)/include/grub/i386/tsc.h KERNEL_HEADER_FILES +=3D $(top_srcdir)/include/grub/pci.h +KERNEL_HEADER_FILES +=3D $(top_srcdir)/include/grub/acpi.h endif =20 if COND_ia64_efi diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index d9fa0e3..cbef91f 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -171,6 +171,12 @@ kernel =3D { efi =3D kern/efi/init.c; efi =3D kern/efi/mm.c; efi =3D term/efi/console.c; + efi =3D kern/acpi.c; + efi =3D kern/efi/acpi.c; + i386_coreboot =3D kern/i386/pc/acpi.c; + i386_multiboot =3D kern/i386/pc/acpi.c; + i386_coreboot =3D kern/acpi.c; + i386_multiboot =3D kern/acpi.c; =20 x86 =3D kern/i386/tsc.c; =20 @@ -665,10 +671,6 @@ module =3D { name =3D acpi; =20 common =3D commands/acpi.c; - efi =3D commands/efi/acpi.c; - i386_pc =3D commands/i386/pc/acpi.c; - i386_coreboot =3D commands/i386/pc/acpi.c; - i386_multiboot =3D commands/i386/pc/acpi.c; =20 enable =3D efi; enable =3D i386_pc; diff --git a/grub-core/commands/acpi.c b/grub-core/commands/acpi.c index c3861f5..ece49b4 100644 --- a/grub-core/commands/acpi.c +++ b/grub-core/commands/acpi.c @@ -61,18 +61,6 @@ static const struct grub_arg_option options[] =3D { {0, 0, 0, 0, 0, 0} }; =20 -/* Simple checksum by summing all bytes. Used by ACPI and SMBIOS. */ -grub_uint8_t -grub_byte_checksum (void *base, grub_size_t size) -{ - grub_uint8_t *ptr; - grub_uint8_t ret =3D 0; - for (ptr =3D (grub_uint8_t *) base; ptr < ((grub_uint8_t *) base) + si= ze; - ptr++) - ret +=3D *ptr; - return ret; -} - /* rev1 is 1 if ACPIv1 is to be generated, 0 otherwise. rev2 contains the revision of ACPIv2+ to generate or 0 if none. */ static int rev1, rev2; diff --git a/grub-core/kern/i386/tsc.c b/grub-core/kern/i386/tsc.c index bc441d0..3b4786f 100644 --- a/grub-core/kern/i386/tsc.c +++ b/grub-core/kern/i386/tsc.c @@ -1,6 +1,6 @@ /* kern/i386/tsc.c - x86 TSC time source implementation * Requires Pentium or better x86 CPU that supports the RDTSC instructio= n. - * This module uses the RTC (via grub_get_rtc()) to calibrate the TSC to= + * This module uses the PIT to calibrate the TSC to * real time. * * GRUB -- GRand Unified Bootloader @@ -30,7 +30,12 @@ #else #include #endif +#ifdef GRUB_MACHINE_EFI +#include +#include +#endif #include +#include =20 /* This defines the value TSC had at the epoch (that is, when we calibra= ted it). */ static grub_uint64_t tsc_boot_time; @@ -57,11 +62,20 @@ grub_get_tsc (void) return (((grub_uint64_t) hi) << 32) | lo; } =20 -#ifndef GRUB_MACHINE_XEN +static grub_uint64_t +grub_tsc_get_time_ms (void) +{ + grub_uint64_t a =3D grub_get_tsc () - tsc_boot_time; + grub_uint64_t ah =3D a >> 32; + grub_uint64_t al =3D a & 0xffffffff; + + return ((al * grub_tsc_rate) >> 32) + ah * grub_tsc_rate; +} =20 static __inline int grub_cpu_is_tsc_supported (void) { +#ifndef GRUB_MACHINE_XEN grub_uint32_t a,b,c,d; if (! grub_cpu_is_cpuid_supported ()) return 0; @@ -69,11 +83,18 @@ grub_cpu_is_tsc_supported (void) grub_cpuid(1,a,b,c,d); =20 return (d & (1 << 4)) !=3D 0; +#else + return 1; +#endif } =20 -static void +#ifndef GRUB_MACHINE_XEN + +static int grub_pit_wait (grub_uint16_t tics) { + int ret =3D 0; + /* Disable timer2 gate and speaker. */ grub_outb (grub_inb (GRUB_PIT_SPEAKER_PORT) & ~ (GRUB_PIT_SPK_DATA | GRUB_PIT_SPK_TMR2), @@ -90,63 +111,147 @@ grub_pit_wait (grub_uint16_t tics) | GRUB_PIT_SPK_TMR2, GRUB_PIT_SPEAKER_PORT); =20 - /* Wait. */ - while ((grub_inb (GRUB_PIT_SPEAKER_PORT) & GRUB_PIT_SPK_TMR2_LATCH) =3D= =3D 0x00); + if ((grub_inb (GRUB_PIT_SPEAKER_PORT) & GRUB_PIT_SPK_TMR2_LATCH)) { + ret =3D 1; + /* Wait. */ + while ((grub_inb (GRUB_PIT_SPEAKER_PORT) & GRUB_PIT_SPK_TMR2_LATCH) = =3D=3D 0x00); + } =20 /* Disable timer2 gate and speaker. */ grub_outb (grub_inb (GRUB_PIT_SPEAKER_PORT) & ~ (GRUB_PIT_SPK_DATA | GRUB_PIT_SPK_TMR2), GRUB_PIT_SPEAKER_PORT); -} -#endif =20 -static grub_uint64_t -grub_tsc_get_time_ms (void) -{ - grub_uint64_t a =3D grub_get_tsc () - tsc_boot_time; - grub_uint64_t ah =3D a >> 32; - grub_uint64_t al =3D a & 0xffffffff; - - return ((al * grub_tsc_rate) >> 32) + ah * grub_tsc_rate; + return ret; } =20 -#ifndef GRUB_MACHINE_XEN /* Calibrate the TSC based on the RTC. */ -static void -calibrate_tsc (void) +static int +calibrate_tsc_pit (void) { /* First calibrate the TSC rate (relative, not absolute time). */ - grub_uint64_t end_tsc; + grub_uint64_t start_tsc, end_tsc; =20 - tsc_boot_time =3D grub_get_tsc (); - grub_pit_wait (0xffff); + start_tsc =3D grub_get_tsc (); + if (!grub_pit_wait (0xffff)) + return 0; end_tsc =3D grub_get_tsc (); =20 grub_tsc_rate =3D 0; if (end_tsc > tsc_boot_time) - grub_tsc_rate =3D grub_divmod64 ((55ULL << 32), end_tsc - tsc_boot_t= ime, 0); + grub_tsc_rate =3D grub_divmod64 ((55ULL << 32), end_tsc - start_tsc,= 0); if (grub_tsc_rate =3D=3D 0) - grub_tsc_rate =3D 5368;/* 800 MHz */ + return 0; + return 1; } + #endif =20 -void -grub_tsc_init (void) +#if defined (GRUB_MACHINE_EFI) +static int +calibrate_tsc_efi (void) +{ + grub_uint64_t start_tsc, end_tsc; + /* Use EFI Time Service to calibrate TSC */ + start_tsc =3D grub_get_tsc (); + efi_call_1 (grub_efi_system_table->boot_services->stall, 1000); + end_tsc =3D grub_get_tsc (); + grub_tsc_rate =3D grub_divmod64 ((1ULL << 32), end_tsc - start_tsc, 0)= ; + return 1; +} +#endif + +#if defined (GRUB_MACHINE_EFI) || defined (GRUB_MACHINE_COREBOOT) + +static int +calibrate_tsc_pmtimer (void) { + grub_uint32_t start; + grub_uint32_t last; + grub_uint32_t cur, end; + struct grub_acpi_fadt *fadt; + grub_port_t p; + grub_uint64_t start_tsc; + grub_uint64_t end_tsc; + int num_iter =3D 0; + + fadt =3D grub_acpi_find_fadt (); + if (!fadt) + return 0; + p =3D fadt->pmtimer; + if (!p) + return 0; + + start =3D grub_inl (p) & 0xffffff; + last =3D start; + /* It's 3.579545 MHz clock. Wait 1 ms. */ + end =3D start + 3580; + start_tsc =3D grub_get_tsc (); + while (1) + { + cur =3D grub_inl (p) & 0xffffff; + if (cur < last) + cur |=3D 0x1000000; + num_iter++; + if (cur >=3D end) + { + end_tsc =3D grub_get_tsc (); + grub_tsc_rate =3D grub_divmod64 ((1ULL << 32), end_tsc - start_tsc, 0= ); + return 1; + } + /* Check for broken PM timer. + 50000000 TSCs is between 5 ms (10GHz) and 200 ms (250 MHz) + if after this time we still don't have 1 ms on pmtimer, then + pmtimer is broken. + */ + if ((num_iter & 0xffffff) =3D=3D 0 && grub_get_tsc () - start_tsc = > 5000000) { + return 0; + } + } +} + +#endif + #ifdef GRUB_MACHINE_XEN + +static int +calibrate_tsc_xen (void) +{ grub_uint64_t t; - tsc_boot_time =3D grub_get_tsc (); t =3D grub_xen_shared_info->vcpu_info[0].time.tsc_to_system_mul; if (grub_xen_shared_info->vcpu_info[0].time.tsc_shift > 0) t <<=3D grub_xen_shared_info->vcpu_info[0].time.tsc_shift; else t >>=3D -grub_xen_shared_info->vcpu_info[0].time.tsc_shift; grub_tsc_rate =3D grub_divmod64 (t, 1000000, 0); - grub_install_get_time_ms (grub_tsc_get_time_ms); -#else + return 1; +} + +#endif + +static int +calibrate_tsc_hardcode (void) +{ + grub_tsc_rate =3D 5368;/* 800 MHz */ + return 1; +} + +void +grub_tsc_init (void) +{ + tsc_boot_time =3D grub_get_tsc (); + if (grub_cpu_is_tsc_supported ()) { - calibrate_tsc (); +#ifdef GRUB_MACHINE_XEN + calibrate_tsc_xen (); +#elif defined (GRUB_MACHINE_EFI) + (void) (calibrate_tsc_pit () || calibrate_tsc_pmtimer() || calibra= te_tsc_efi() || calibrate_tsc_hardcode()); +#elif defined (GRUB_MACHINE_COREBOOT) + (void) (calibrate_tsc_pmtimer() || calibrate_tsc_pit () || calibra= te_tsc_hardcode()); +#else + (void) (calibrate_tsc_pit () || calibrate_tsc_hardcode()); +#endif grub_install_get_time_ms (grub_tsc_get_time_ms); } else @@ -157,5 +262,4 @@ grub_tsc_init (void) grub_fatal ("no TSC found"); #endif } -#endif } diff --git a/include/grub/acpi.h b/include/grub/acpi.h index f6e6a11..af98776 100644 --- a/include/grub/acpi.h +++ b/include/grub/acpi.h @@ -67,10 +67,14 @@ struct grub_acpi_fadt grub_uint32_t dsdt_addr; grub_uint8_t somefields1[20]; grub_uint32_t pm1a; - grub_uint8_t somefields2[64]; + grub_uint8_t somefields2[8]; + grub_uint32_t pmtimer; + grub_uint8_t somefields3[32]; + grub_uint32_t flags; + grub_uint8_t somefields4[16]; grub_uint64_t facs_xaddr; grub_uint64_t dsdt_xaddr; - grub_uint8_t somefields3[96]; + grub_uint8_t somefields5[96]; } GRUB_PACKED; =20 #define GRUB_ACPI_MADT_SIGNATURE "APIC" @@ -176,9 +180,9 @@ enum #ifndef GRUB_DSDT_TEST struct grub_acpi_rsdp_v10 *grub_acpi_get_rsdpv1 (void); struct grub_acpi_rsdp_v20 *grub_acpi_get_rsdpv2 (void); -struct grub_acpi_rsdp_v10 *grub_machine_acpi_get_rsdpv1 (void); -struct grub_acpi_rsdp_v20 *grub_machine_acpi_get_rsdpv2 (void); -grub_uint8_t grub_byte_checksum (void *base, grub_size_t size); +struct grub_acpi_rsdp_v10 *EXPORT_FUNC(grub_machine_acpi_get_rsdpv1) (vo= id); +struct grub_acpi_rsdp_v20 *EXPORT_FUNC(grub_machine_acpi_get_rsdpv2) (vo= id); +grub_uint8_t EXPORT_FUNC(grub_byte_checksum) (void *base, grub_size_t si= ze); =20 grub_err_t grub_acpi_create_ebda (void); =20 @@ -234,4 +238,7 @@ enum GRUB_ACPI_EXTOPCODE_BANK_FIELD_OP =3D 0x87, }; =20 +struct grub_acpi_fadt * +EXPORT_FUNC(grub_acpi_find_fadt) (void); + #endif /* ! GRUB_ACPI_HEADER */ --------------080308090402060904020605-- --triKCQSHgCpwrEUJ8562QhMtRPlnJCcmJ Content-Type: application/pgp-signature; name="signature.asc" Content-Description: OpenPGP digital signature Content-Disposition: attachment; filename="signature.asc" -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iF4EAREKAAYFAlZAq/EACgkQmBXlbbo5nOud2gEArY6DJDp4u5Cdw+6CU+SRT5ut 3fRH6sLMXkbl4gSDmvgA/2St1OpL0swHNhAxcEvlGLYTOSIHFmx6932BazAiid6D =XrEo -----END PGP SIGNATURE----- --triKCQSHgCpwrEUJ8562QhMtRPlnJCcmJ--