* [PATCH] Use UEFI Time Service to calibrate TSC
@ 2015-11-09 7:07 Michael Chang
2015-11-09 7:29 ` Andrei Borzenkov
0 siblings, 1 reply; 8+ messages in thread
From: Michael Chang @ 2015-11-09 7:07 UTC (permalink / raw)
To: grub-devel
This patch tries to detect PIT timer is broken and use UEFI Time Service
to calibrate TSC.
---
grub-core/kern/i386/tsc.c | 33 +++++++++++++++++++++++++++++----
1 files changed, 29 insertions(+), 4 deletions(-)
diff --git a/grub-core/kern/i386/tsc.c b/grub-core/kern/i386/tsc.c
index bc441d0..bd24cea 100644
--- a/grub-core/kern/i386/tsc.c
+++ b/grub-core/kern/i386/tsc.c
@@ -29,6 +29,10 @@
#include <grub/xen.h>
#else
#include <grub/i386/pit.h>
+#ifdef GRUB_MACHINE_EFI
+#include <grub/efi/efi.h>
+#include <grub/efi/api.h>
+#endif
#endif
#include <grub/cpu/io.h>
@@ -72,7 +76,7 @@ grub_cpu_is_tsc_supported (void)
}
static void
-grub_pit_wait (grub_uint16_t tics)
+grub_pit_wait (grub_uint16_t tics, int *is_started)
{
/* Disable timer2 gate and speaker. */
grub_outb (grub_inb (GRUB_PIT_SPEAKER_PORT)
@@ -90,8 +94,17 @@ grub_pit_wait (grub_uint16_t tics)
| GRUB_PIT_SPK_TMR2,
GRUB_PIT_SPEAKER_PORT);
- /* Wait. */
- while ((grub_inb (GRUB_PIT_SPEAKER_PORT) & GRUB_PIT_SPK_TMR2_LATCH) == 0x00);
+ if ((grub_inb (GRUB_PIT_SPEAKER_PORT) & GRUB_PIT_SPK_TMR2_LATCH))
+ {
+ /* The ticks have expired too fast to know the counting really started or not */
+ *is_started = 0;
+ }
+ else
+ {
+ *is_started = 1;
+ /* Wait. */
+ while ((grub_inb (GRUB_PIT_SPEAKER_PORT) & GRUB_PIT_SPK_TMR2_LATCH) == 0x00);
+ }
/* Disable timer2 gate and speaker. */
grub_outb (grub_inb (GRUB_PIT_SPEAKER_PORT)
@@ -117,11 +130,23 @@ calibrate_tsc (void)
{
/* First calibrate the TSC rate (relative, not absolute time). */
grub_uint64_t end_tsc;
+ int is_started;
tsc_boot_time = grub_get_tsc ();
- grub_pit_wait (0xffff);
+ grub_pit_wait (0xffff, &is_started);
end_tsc = grub_get_tsc ();
+#ifdef GRUB_MACHINE_EFI
+ /* The PIT is broken as 55ms is too sufficent to any cpu to catch it */
+ if (!is_started)
+ {
+ /* Use EFI Time Service to calibrate TSC */
+ tsc_boot_time = grub_get_tsc ();
+ efi_call_1 (grub_efi_system_table->boot_services->stall, 54925);
+ end_tsc = grub_get_tsc ();
+ }
+#endif
+
grub_tsc_rate = 0;
if (end_tsc > tsc_boot_time)
grub_tsc_rate = grub_divmod64 ((55ULL << 32), end_tsc - tsc_boot_time, 0);
--
1.7.3.4
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH] Use UEFI Time Service to calibrate TSC
2015-11-09 7:07 [PATCH] Use UEFI Time Service to calibrate TSC Michael Chang
@ 2015-11-09 7:29 ` Andrei Borzenkov
2015-11-09 8:03 ` Michael Chang
0 siblings, 1 reply; 8+ messages in thread
From: Andrei Borzenkov @ 2015-11-09 7:29 UTC (permalink / raw)
To: The development of GNU GRUB
On Mon, Nov 9, 2015 at 10:07 AM, Michael Chang <mchang@suse.com> wrote:
> This patch tries to detect PIT timer is broken and use UEFI Time Service
> 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?
> ---
> grub-core/kern/i386/tsc.c | 33 +++++++++++++++++++++++++++++----
> 1 files changed, 29 insertions(+), 4 deletions(-)
>
> diff --git a/grub-core/kern/i386/tsc.c b/grub-core/kern/i386/tsc.c
> index bc441d0..bd24cea 100644
> --- a/grub-core/kern/i386/tsc.c
> +++ b/grub-core/kern/i386/tsc.c
> @@ -29,6 +29,10 @@
> #include <grub/xen.h>
> #else
> #include <grub/i386/pit.h>
> +#ifdef GRUB_MACHINE_EFI
> +#include <grub/efi/efi.h>
> +#include <grub/efi/api.h>
> +#endif
> #endif
> #include <grub/cpu/io.h>
>
> @@ -72,7 +76,7 @@ grub_cpu_is_tsc_supported (void)
> }
>
> static void
> -grub_pit_wait (grub_uint16_t tics)
> +grub_pit_wait (grub_uint16_t tics, int *is_started)
> {
> /* Disable timer2 gate and speaker. */
> grub_outb (grub_inb (GRUB_PIT_SPEAKER_PORT)
> @@ -90,8 +94,17 @@ grub_pit_wait (grub_uint16_t tics)
> | GRUB_PIT_SPK_TMR2,
> GRUB_PIT_SPEAKER_PORT);
>
> - /* Wait. */
> - while ((grub_inb (GRUB_PIT_SPEAKER_PORT) & GRUB_PIT_SPK_TMR2_LATCH) == 0x00);
> + if ((grub_inb (GRUB_PIT_SPEAKER_PORT) & GRUB_PIT_SPK_TMR2_LATCH))
> + {
> + /* The ticks have expired too fast to know the counting really started or not */
> + *is_started = 0;
> + }
> + else
> + {
> + *is_started = 1;
> + /* Wait. */
> + while ((grub_inb (GRUB_PIT_SPEAKER_PORT) & GRUB_PIT_SPK_TMR2_LATCH) == 0x00);
> + }
>
> /* Disable timer2 gate and speaker. */
> grub_outb (grub_inb (GRUB_PIT_SPEAKER_PORT)
> @@ -117,11 +130,23 @@ calibrate_tsc (void)
> {
> /* First calibrate the TSC rate (relative, not absolute time). */
> grub_uint64_t end_tsc;
> + int is_started;
>
> tsc_boot_time = grub_get_tsc ();
> - grub_pit_wait (0xffff);
> + grub_pit_wait (0xffff, &is_started);
> end_tsc = grub_get_tsc ();
>
> +#ifdef GRUB_MACHINE_EFI
> + /* The PIT is broken as 55ms is too sufficent to any cpu to catch it */
> + if (!is_started)
> + {
> + /* Use EFI Time Service to calibrate TSC */
> + tsc_boot_time = grub_get_tsc ();
> + efi_call_1 (grub_efi_system_table->boot_services->stall, 54925);
> + end_tsc = grub_get_tsc ();
> + }
> +#endif
> +
> grub_tsc_rate = 0;
> if (end_tsc > tsc_boot_time)
> grub_tsc_rate = grub_divmod64 ((55ULL << 32), end_tsc - tsc_boot_time, 0);
> --
> 1.7.3.4
>
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] Use UEFI Time Service to calibrate TSC
2015-11-09 7:29 ` Andrei Borzenkov
@ 2015-11-09 8:03 ` Michael Chang
2015-11-09 13:23 ` Vladimir 'φ-coder/phcoder' Serbinenko
0 siblings, 1 reply; 8+ messages in thread
From: Michael Chang @ 2015-11-09 8:03 UTC (permalink / raw)
To: grub-devel
On Mon, Nov 09, 2015 at 10:29:55AM +0300, Andrei Borzenkov wrote:
> On Mon, Nov 9, 2015 at 10:07 AM, Michael Chang <mchang@suse.com> wrote:
> > This patch tries to detect PIT timer is broken and use UEFI Time Service
> > 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.
Thanks,
Michael
>
> > ---
> > grub-core/kern/i386/tsc.c | 33 +++++++++++++++++++++++++++++----
> > 1 files changed, 29 insertions(+), 4 deletions(-)
> >
> > diff --git a/grub-core/kern/i386/tsc.c b/grub-core/kern/i386/tsc.c
> > index bc441d0..bd24cea 100644
> > --- a/grub-core/kern/i386/tsc.c
> > +++ b/grub-core/kern/i386/tsc.c
> > @@ -29,6 +29,10 @@
> > #include <grub/xen.h>
> > #else
> > #include <grub/i386/pit.h>
> > +#ifdef GRUB_MACHINE_EFI
> > +#include <grub/efi/efi.h>
> > +#include <grub/efi/api.h>
> > +#endif
> > #endif
> > #include <grub/cpu/io.h>
> >
> > @@ -72,7 +76,7 @@ grub_cpu_is_tsc_supported (void)
> > }
> >
> > static void
> > -grub_pit_wait (grub_uint16_t tics)
> > +grub_pit_wait (grub_uint16_t tics, int *is_started)
> > {
> > /* Disable timer2 gate and speaker. */
> > grub_outb (grub_inb (GRUB_PIT_SPEAKER_PORT)
> > @@ -90,8 +94,17 @@ grub_pit_wait (grub_uint16_t tics)
> > | GRUB_PIT_SPK_TMR2,
> > GRUB_PIT_SPEAKER_PORT);
> >
> > - /* Wait. */
> > - while ((grub_inb (GRUB_PIT_SPEAKER_PORT) & GRUB_PIT_SPK_TMR2_LATCH) == 0x00);
> > + if ((grub_inb (GRUB_PIT_SPEAKER_PORT) & GRUB_PIT_SPK_TMR2_LATCH))
> > + {
> > + /* The ticks have expired too fast to know the counting really started or not */
> > + *is_started = 0;
> > + }
> > + else
> > + {
> > + *is_started = 1;
> > + /* Wait. */
> > + while ((grub_inb (GRUB_PIT_SPEAKER_PORT) & GRUB_PIT_SPK_TMR2_LATCH) == 0x00);
> > + }
> >
> > /* Disable timer2 gate and speaker. */
> > grub_outb (grub_inb (GRUB_PIT_SPEAKER_PORT)
> > @@ -117,11 +130,23 @@ calibrate_tsc (void)
> > {
> > /* First calibrate the TSC rate (relative, not absolute time). */
> > grub_uint64_t end_tsc;
> > + int is_started;
> >
> > tsc_boot_time = grub_get_tsc ();
> > - grub_pit_wait (0xffff);
> > + grub_pit_wait (0xffff, &is_started);
> > end_tsc = grub_get_tsc ();
> >
> > +#ifdef GRUB_MACHINE_EFI
> > + /* The PIT is broken as 55ms is too sufficent to any cpu to catch it */
> > + if (!is_started)
> > + {
> > + /* Use EFI Time Service to calibrate TSC */
> > + tsc_boot_time = grub_get_tsc ();
> > + efi_call_1 (grub_efi_system_table->boot_services->stall, 54925);
> > + end_tsc = grub_get_tsc ();
> > + }
> > +#endif
> > +
> > grub_tsc_rate = 0;
> > if (end_tsc > tsc_boot_time)
> > grub_tsc_rate = grub_divmod64 ((55ULL << 32), end_tsc - tsc_boot_time, 0);
> > --
> > 1.7.3.4
> >
> >
> > _______________________________________________
> > Grub-devel mailing list
> > Grub-devel@gnu.org
> > https://lists.gnu.org/mailman/listinfo/grub-devel
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] Use UEFI Time Service to calibrate TSC
2015-11-09 8:03 ` Michael Chang
@ 2015-11-09 13:23 ` Vladimir 'φ-coder/phcoder' Serbinenko
2015-11-09 14:21 ` Vladimir 'φ-coder/phcoder' Serbinenko
0 siblings, 1 reply; 8+ messages in thread
From: Vladimir 'φ-coder/phcoder' Serbinenko @ 2015-11-09 13:23 UTC (permalink / raw)
To: The development of GNU GRUB
[-- Attachment #1: Type: text/plain, Size: 4885 bytes --]
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 <mchang@suse.com> wrote:
>>> This patch tries to detect PIT timer is broken and use UEFI Time Service
>>> 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.
>
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)
I'm going to prepare proof-of-concept patch
> Thanks,
> Michael
>
>>
>>> ---
>>> grub-core/kern/i386/tsc.c | 33 +++++++++++++++++++++++++++++----
>>> 1 files changed, 29 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/grub-core/kern/i386/tsc.c b/grub-core/kern/i386/tsc.c
>>> index bc441d0..bd24cea 100644
>>> --- a/grub-core/kern/i386/tsc.c
>>> +++ b/grub-core/kern/i386/tsc.c
>>> @@ -29,6 +29,10 @@
>>> #include <grub/xen.h>
>>> #else
>>> #include <grub/i386/pit.h>
>>> +#ifdef GRUB_MACHINE_EFI
>>> +#include <grub/efi/efi.h>
>>> +#include <grub/efi/api.h>
>>> +#endif
>>> #endif
>>> #include <grub/cpu/io.h>
>>>
>>> @@ -72,7 +76,7 @@ grub_cpu_is_tsc_supported (void)
>>> }
>>>
>>> static void
>>> -grub_pit_wait (grub_uint16_t tics)
>>> +grub_pit_wait (grub_uint16_t tics, int *is_started)
>>> {
>>> /* Disable timer2 gate and speaker. */
>>> grub_outb (grub_inb (GRUB_PIT_SPEAKER_PORT)
>>> @@ -90,8 +94,17 @@ grub_pit_wait (grub_uint16_t tics)
>>> | GRUB_PIT_SPK_TMR2,
>>> GRUB_PIT_SPEAKER_PORT);
>>>
>>> - /* Wait. */
>>> - while ((grub_inb (GRUB_PIT_SPEAKER_PORT) & GRUB_PIT_SPK_TMR2_LATCH) == 0x00);
>>> + if ((grub_inb (GRUB_PIT_SPEAKER_PORT) & GRUB_PIT_SPK_TMR2_LATCH))
>>> + {
>>> + /* The ticks have expired too fast to know the counting really started or not */
>>> + *is_started = 0;
>>> + }
>>> + else
>>> + {
>>> + *is_started = 1;
>>> + /* Wait. */
>>> + while ((grub_inb (GRUB_PIT_SPEAKER_PORT) & GRUB_PIT_SPK_TMR2_LATCH) == 0x00);
>>> + }
>>>
>>> /* Disable timer2 gate and speaker. */
>>> grub_outb (grub_inb (GRUB_PIT_SPEAKER_PORT)
>>> @@ -117,11 +130,23 @@ calibrate_tsc (void)
>>> {
>>> /* First calibrate the TSC rate (relative, not absolute time). */
>>> grub_uint64_t end_tsc;
>>> + int is_started;
>>>
>>> tsc_boot_time = grub_get_tsc ();
>>> - grub_pit_wait (0xffff);
>>> + grub_pit_wait (0xffff, &is_started);
>>> end_tsc = grub_get_tsc ();
>>>
>>> +#ifdef GRUB_MACHINE_EFI
>>> + /* The PIT is broken as 55ms is too sufficent to any cpu to catch it */
>>> + if (!is_started)
>>> + {
>>> + /* Use EFI Time Service to calibrate TSC */
>>> + tsc_boot_time = grub_get_tsc ();
>>> + efi_call_1 (grub_efi_system_table->boot_services->stall, 54925);
>>> + end_tsc = grub_get_tsc ();
>>> + }
>>> +#endif
>>> +
>>> grub_tsc_rate = 0;
>>> if (end_tsc > tsc_boot_time)
>>> grub_tsc_rate = grub_divmod64 ((55ULL << 32), end_tsc - tsc_boot_time, 0);
>>> --
>>> 1.7.3.4
>>>
>>>
>>> _______________________________________________
>>> Grub-devel mailing list
>>> Grub-devel@gnu.org
>>> https://lists.gnu.org/mailman/listinfo/grub-devel
>>
>> _______________________________________________
>> Grub-devel mailing list
>> Grub-devel@gnu.org
>> https://lists.gnu.org/mailman/listinfo/grub-devel
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel
>
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 213 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] Use UEFI Time Service to calibrate TSC
2015-11-09 13:23 ` Vladimir 'φ-coder/phcoder' Serbinenko
@ 2015-11-09 14:21 ` Vladimir 'φ-coder/phcoder' Serbinenko
2015-11-12 7:34 ` Michael Chang
0 siblings, 1 reply; 8+ messages in thread
From: Vladimir 'φ-coder/phcoder' Serbinenko @ 2015-11-09 14:21 UTC (permalink / raw)
To: The development of GNU GRUB
[-- Attachment #1.1: Type: text/plain, Size: 2043 bytes --]
On 09.11.2015 14:23, Vladimir 'φ-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 <mchang@suse.com> wrote:
>>>> This patch tries to detect PIT timer is broken and use UEFI Time Service
>>>> 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.
>>
> 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)
>
> 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.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: pm.diff --]
[-- Type: text/x-diff; name="pm.diff", Size: 18939 bytes --]
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 <http://www.gnu.org/licenses/>.
- */
-
-#include <grub/acpi.h>
-#include <grub/misc.h>
-#include <grub/efi/efi.h>
-#include <grub/efi/api.h>
-
-struct grub_acpi_rsdp_v10 *
-grub_machine_acpi_get_rsdpv1 (void)
-{
- unsigned i;
- static grub_efi_packed_guid_t acpi_guid = GRUB_EFI_ACPI_TABLE_GUID;
-
- for (i = 0; i < grub_efi_system_table->num_table_entries; i++)
- {
- grub_efi_packed_guid_t *guid =
- &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 = GRUB_EFI_ACPI_20_TABLE_GUID;
-
- for (i = 0; i < grub_efi_system_table->num_table_entries; i++)
- {
- grub_efi_packed_guid_t *guid =
- &grub_efi_system_table->configuration_table[i].vendor_guid;
-
- if (! grub_memcmp (guid, &acpi20_guid, sizeof (grub_efi_packed_guid_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 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/time.h>
+#include <grub/misc.h>
+#include <grub/acpi.h>
+
+static void *
+grub_acpi_rsdt_find_table (struct grub_acpi_table_header *rsdt, const char *sig)
+{
+ grub_size_t s;
+ grub_uint32_t *ptr;
+
+ if (!rsdt)
+ return 0;
+
+ if (grub_memcmp (rsdt->signature, "RSDT", 4) != 0)
+ return 0;
+
+ ptr = (grub_uint32_t *) (rsdt + 1);
+ s = (rsdt->length - sizeof (*rsdt)) / sizeof (grub_uint32_t);
+ for (; s; s--, ptr++)
+ {
+ struct grub_acpi_table_header *tbl;
+ tbl = (struct grub_acpi_table_header *) (grub_addr_t) *ptr;
+ if (grub_memcmp (tbl->signature, sig, 4) == 0)
+ return tbl;
+ }
+ return 0;
+}
+
+static void *
+grub_acpi_xsdt_find_table (struct grub_acpi_table_header *xsdt, const char *sig)
+{
+ grub_size_t s;
+ grub_uint64_t *ptr;
+
+ if (!xsdt)
+ return 0;
+
+ if (grub_memcmp (xsdt->signature, "XSDT", 4) != 0)
+ return 0;
+
+ ptr = (grub_uint64_t *) (xsdt + 1);
+ s = (xsdt->length - sizeof (*xsdt)) / sizeof (grub_uint32_t);
+ for (; s; s--, ptr++)
+ {
+ struct grub_acpi_table_header *tbl;
+#if GRUB_CPU_SIZEOF_VOID_P != 8
+ if (*ptr >> 32)
+ continue;
+#endif
+ tbl = (struct grub_acpi_table_header *) (grub_addr_t) *ptr;
+ if (grub_memcmp (tbl->signature, sig, 4) == 0)
+ return tbl;
+ }
+ return 0;
+}
+
+struct grub_acpi_fadt *
+grub_acpi_find_fadt (void)
+{
+ struct grub_acpi_fadt *fadt = 0;
+ struct grub_acpi_rsdp_v10 *rsdpv1;
+ struct grub_acpi_rsdp_v20 *rsdpv2;
+ rsdpv1 = grub_machine_acpi_get_rsdpv1 ();
+ if (rsdpv1)
+ fadt = 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 = grub_machine_acpi_get_rsdpv2 ();
+ if (rsdpv2)
+ fadt = 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 != 8
+ && !(rsdpv2->xsdt_addr >> 32)
+#endif
+ )
+ fadt = 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 = 0;
+ for (ptr = (grub_uint8_t *) base; ptr < ((grub_uint8_t *) base) + size;
+ ptr++)
+ ret += *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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/acpi.h>
+#include <grub/misc.h>
+#include <grub/efi/efi.h>
+#include <grub/efi/api.h>
+
+struct grub_acpi_rsdp_v10 *
+grub_machine_acpi_get_rsdpv1 (void)
+{
+ unsigned i;
+ static grub_efi_packed_guid_t acpi_guid = GRUB_EFI_ACPI_TABLE_GUID;
+
+ for (i = 0; i < grub_efi_system_table->num_table_entries; i++)
+ {
+ grub_efi_packed_guid_t *guid =
+ &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 = GRUB_EFI_ACPI_20_TABLE_GUID;
+
+ for (i = 0; i < grub_efi_system_table->num_table_entries; i++)
+ {
+ grub_efi_packed_guid_t *guid =
+ &grub_efi_system_table->configuration_table[i].vendor_guid;
+
+ if (! grub_memcmp (guid, &acpi20_guid, sizeof (grub_efi_packed_guid_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 += $(top_srcdir)/include/grub/efi/efi.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/tsc.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/pci.h
endif
@@ -112,6 +113,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/video_fb.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/gfxterm.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/font.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/bufio.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h
endif
if COND_i386_multiboot
@@ -154,6 +156,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/tsc.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/pci.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h
endif
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 = {
efi = kern/efi/init.c;
efi = kern/efi/mm.c;
efi = term/efi/console.c;
+ efi = kern/acpi.c;
+ efi = kern/efi/acpi.c;
+ i386_coreboot = kern/i386/pc/acpi.c;
+ i386_multiboot = kern/i386/pc/acpi.c;
+ i386_coreboot = kern/acpi.c;
+ i386_multiboot = kern/acpi.c;
x86 = kern/i386/tsc.c;
@@ -665,10 +671,6 @@ module = {
name = acpi;
common = commands/acpi.c;
- efi = commands/efi/acpi.c;
- i386_pc = commands/i386/pc/acpi.c;
- i386_coreboot = commands/i386/pc/acpi.c;
- i386_multiboot = commands/i386/pc/acpi.c;
enable = efi;
enable = 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[] = {
{0, 0, 0, 0, 0, 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 = 0;
- for (ptr = (grub_uint8_t *) base; ptr < ((grub_uint8_t *) base) + size;
- ptr++)
- ret += *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 instruction.
- * 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 <grub/i386/pit.h>
#endif
+#ifdef GRUB_MACHINE_EFI
+#include <grub/efi/efi.h>
+#include <grub/efi/api.h>
+#endif
#include <grub/cpu/io.h>
+#include <grub/acpi.h>
/* This defines the value TSC had at the epoch (that is, when we calibrated it). */
static grub_uint64_t tsc_boot_time;
@@ -57,11 +62,20 @@ grub_get_tsc (void)
return (((grub_uint64_t) hi) << 32) | lo;
}
-#ifndef GRUB_MACHINE_XEN
+static grub_uint64_t
+grub_tsc_get_time_ms (void)
+{
+ grub_uint64_t a = grub_get_tsc () - tsc_boot_time;
+ grub_uint64_t ah = a >> 32;
+ grub_uint64_t al = a & 0xffffffff;
+
+ return ((al * grub_tsc_rate) >> 32) + ah * grub_tsc_rate;
+}
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);
return (d & (1 << 4)) != 0;
+#else
+ return 1;
+#endif
}
-static void
+#ifndef GRUB_MACHINE_XEN
+
+static int
grub_pit_wait (grub_uint16_t tics)
{
+ int ret = 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);
- /* Wait. */
- while ((grub_inb (GRUB_PIT_SPEAKER_PORT) & GRUB_PIT_SPK_TMR2_LATCH) == 0x00);
+ if ((grub_inb (GRUB_PIT_SPEAKER_PORT) & GRUB_PIT_SPK_TMR2_LATCH)) {
+ ret = 1;
+ /* Wait. */
+ while ((grub_inb (GRUB_PIT_SPEAKER_PORT) & GRUB_PIT_SPK_TMR2_LATCH) == 0x00);
+ }
/* 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
-static grub_uint64_t
-grub_tsc_get_time_ms (void)
-{
- grub_uint64_t a = grub_get_tsc () - tsc_boot_time;
- grub_uint64_t ah = a >> 32;
- grub_uint64_t al = a & 0xffffffff;
-
- return ((al * grub_tsc_rate) >> 32) + ah * grub_tsc_rate;
+ return ret;
}
-#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;
- tsc_boot_time = grub_get_tsc ();
- grub_pit_wait (0xffff);
+ start_tsc = grub_get_tsc ();
+ if (!grub_pit_wait (0xffff))
+ return 0;
end_tsc = grub_get_tsc ();
grub_tsc_rate = 0;
if (end_tsc > tsc_boot_time)
- grub_tsc_rate = grub_divmod64 ((55ULL << 32), end_tsc - tsc_boot_time, 0);
+ grub_tsc_rate = grub_divmod64 ((55ULL << 32), end_tsc - start_tsc, 0);
if (grub_tsc_rate == 0)
- grub_tsc_rate = 5368;/* 800 MHz */
+ return 0;
+ return 1;
}
+
#endif
-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 = grub_get_tsc ();
+ efi_call_1 (grub_efi_system_table->boot_services->stall, 1000);
+ end_tsc = grub_get_tsc ();
+ grub_tsc_rate = 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 = 0;
+
+ fadt = grub_acpi_find_fadt ();
+ if (!fadt)
+ return 0;
+ p = fadt->pmtimer;
+ if (!p)
+ return 0;
+
+ start = grub_inl (p) & 0xffffff;
+ last = start;
+ /* It's 3.579545 MHz clock. Wait 1 ms. */
+ end = start + 3580;
+ start_tsc = grub_get_tsc ();
+ while (1)
+ {
+ cur = grub_inl (p) & 0xffffff;
+ if (cur < last)
+ cur |= 0x1000000;
+ num_iter++;
+ if (cur >= end)
+ {
+ end_tsc = grub_get_tsc ();
+ grub_tsc_rate = 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) == 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 = grub_get_tsc ();
t = 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 <<= grub_xen_shared_info->vcpu_info[0].time.tsc_shift;
else
t >>= -grub_xen_shared_info->vcpu_info[0].time.tsc_shift;
grub_tsc_rate = 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 = 5368;/* 800 MHz */
+ return 1;
+}
+
+void
+grub_tsc_init (void)
+{
+ tsc_boot_time = 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() || calibrate_tsc_efi() || calibrate_tsc_hardcode());
+#elif defined (GRUB_MACHINE_COREBOOT)
+ (void) (calibrate_tsc_pmtimer() || calibrate_tsc_pit () || calibrate_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;
#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) (void);
+struct grub_acpi_rsdp_v20 *EXPORT_FUNC(grub_machine_acpi_get_rsdpv2) (void);
+grub_uint8_t EXPORT_FUNC(grub_byte_checksum) (void *base, grub_size_t size);
grub_err_t grub_acpi_create_ebda (void);
@@ -234,4 +238,7 @@ enum
GRUB_ACPI_EXTOPCODE_BANK_FIELD_OP = 0x87,
};
+struct grub_acpi_fadt *
+EXPORT_FUNC(grub_acpi_find_fadt) (void);
+
#endif /* ! GRUB_ACPI_HEADER */
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 213 bytes --]
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH] Use UEFI Time Service to calibrate TSC
2015-11-09 14:21 ` Vladimir 'φ-coder/phcoder' Serbinenko
@ 2015-11-12 7:34 ` Michael Chang
2015-11-12 8:52 ` Andrei Borzenkov
0 siblings, 1 reply; 8+ messages in thread
From: Michael Chang @ 2015-11-12 7:34 UTC (permalink / raw)
To: The development of GNU GRUB
[-- Attachment #1: Type: text/plain, Size: 928 bytes --]
On Mon, Nov 09, 2015 at 03:21:37PM +0100, Vladimir 'φ-coder/phcoder' Serbinenko wrote:
> On 09.11.2015 14:23, Vladimir 'φ-coder/phcoder' Serbinenko wrote:
> > On 09.11.2015 09:03, Michael Chang wrote:
> Attached proof-of-concept. It's all in one file but different methods
> should probably go in separate files.
Hi Vladmir,
Thanks for your guidence to the better fix. I built your patch with
attach patch on top of yours to fix the errors found in our build
service and also some other affected platforms which might also need the
similar fix.
In the attatched patch, for i386-pc the acpi module was not built into
kernel because from your patch seems not use pmtimer on it. That would
be help in saving up the kernel image size.
I have tested on x86_64-efi and i386-pc and so far it works as expected.
Please note I also manually tweaked the patch to run pmtimer calibration
in efi and it also worked.
Thanks,
Michael
[-- Attachment #2: pm-build-fix.diff --]
[-- Type: text/x-patch, Size: 9145 bytes --]
diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am
index 7a1ffdc..c671aed 100644
--- a/grub-core/Makefile.am
+++ b/grub-core/Makefile.am
@@ -118,6 +118,7 @@ endif
if COND_i386_multiboot
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/tsc.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h
endif
if COND_i386_qemu
@@ -162,6 +163,7 @@ endif
if COND_ia64_efi
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h
endif
if COND_mips
@@ -236,11 +238,13 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/arm/efi/loader.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/arm/system.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h
endif
if COND_arm64_efi
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h
endif
if COND_emu
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index c4c82ec..54ec3c8 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -675,6 +675,8 @@ module = {
name = acpi;
common = commands/acpi.c;
+ i386_pc = kern/i386/pc/acpi.c;
+ i386_pc = kern/acpi.c;
enable = efi;
enable = i386_pc;
diff --git a/grub-core/commands/i386/pc/acpi.c b/grub-core/commands/i386/pc/acpi.c
deleted file mode 100644
index 297f5d0..0000000
--- a/grub-core/commands/i386/pc/acpi.c
+++ /dev/null
@@ -1,83 +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 <http://www.gnu.org/licenses/>.
- */
-
-#include <grub/acpi.h>
-#include <grub/misc.h>
-
-struct grub_acpi_rsdp_v10 *
-grub_machine_acpi_get_rsdpv1 (void)
-{
- int ebda_len;
- grub_uint8_t *ebda, *ptr;
-
- grub_dprintf ("acpi", "Looking for RSDP. Scanning EBDA\n");
- ebda = (grub_uint8_t *) ((* ((grub_uint16_t *) 0x40e)) << 4);
- ebda_len = * (grub_uint16_t *) ebda;
- if (! ebda_len) /* FIXME do we really need this check? */
- goto scan_bios;
- for (ptr = ebda; ptr < ebda + 0x400; ptr += 16)
- if (grub_memcmp (ptr, GRUB_RSDP_SIGNATURE, GRUB_RSDP_SIGNATURE_SIZE) == 0
- && grub_byte_checksum (ptr, sizeof (struct grub_acpi_rsdp_v10)) == 0
- && ((struct grub_acpi_rsdp_v10 *) ptr)->revision == 0)
- return (struct grub_acpi_rsdp_v10 *) ptr;
-
-scan_bios:
- grub_dprintf ("acpi", "Looking for RSDP. Scanning BIOS\n");
- for (ptr = (grub_uint8_t *) 0xe0000; ptr < (grub_uint8_t *) 0x100000;
- ptr += 16)
- if (grub_memcmp (ptr, GRUB_RSDP_SIGNATURE, GRUB_RSDP_SIGNATURE_SIZE) == 0
- && grub_byte_checksum (ptr, sizeof (struct grub_acpi_rsdp_v10)) == 0
- && ((struct grub_acpi_rsdp_v10 *) ptr)->revision == 0)
- return (struct grub_acpi_rsdp_v10 *) ptr;
- return 0;
-}
-
-struct grub_acpi_rsdp_v20 *
-grub_machine_acpi_get_rsdpv2 (void)
-{
- int ebda_len;
- grub_uint8_t *ebda, *ptr;
-
- grub_dprintf ("acpi", "Looking for RSDP. Scanning EBDA\n");
- ebda = (grub_uint8_t *) ((* ((grub_uint16_t *) 0x40e)) << 4);
- ebda_len = * (grub_uint16_t *) ebda;
- if (! ebda_len) /* FIXME do we really need this check? */
- goto scan_bios;
- for (ptr = ebda; ptr < ebda + 0x400; ptr += 16)
- if (grub_memcmp (ptr, GRUB_RSDP_SIGNATURE, GRUB_RSDP_SIGNATURE_SIZE) == 0
- && grub_byte_checksum (ptr, sizeof (struct grub_acpi_rsdp_v10)) == 0
- && ((struct grub_acpi_rsdp_v10 *) ptr)->revision != 0
- && ((struct grub_acpi_rsdp_v20 *) ptr)->length < 1024
- && grub_byte_checksum (ptr, ((struct grub_acpi_rsdp_v20 *) ptr)->length)
- == 0)
- return (struct grub_acpi_rsdp_v20 *) ptr;
-
-scan_bios:
- grub_dprintf ("acpi", "Looking for RSDP. Scanning BIOS\n");
- for (ptr = (grub_uint8_t *) 0xe0000; ptr < (grub_uint8_t *) 0x100000;
- ptr += 16)
- if (grub_memcmp (ptr, GRUB_RSDP_SIGNATURE, GRUB_RSDP_SIGNATURE_SIZE) == 0
- && grub_byte_checksum (ptr, sizeof (struct grub_acpi_rsdp_v10)) == 0
- && ((struct grub_acpi_rsdp_v10 *) ptr)->revision != 0
- && ((struct grub_acpi_rsdp_v20 *) ptr)->length < 1024
- && grub_byte_checksum (ptr, ((struct grub_acpi_rsdp_v20 *) ptr)->length)
- == 0)
- return (struct grub_acpi_rsdp_v20 *) ptr;
- return 0;
-}
diff --git a/grub-core/kern/i386/pc/acpi.c b/grub-core/kern/i386/pc/acpi.c
new file mode 100644
index 0000000..297f5d0
--- /dev/null
+++ b/grub-core/kern/i386/pc/acpi.c
@@ -0,0 +1,83 @@
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/acpi.h>
+#include <grub/misc.h>
+
+struct grub_acpi_rsdp_v10 *
+grub_machine_acpi_get_rsdpv1 (void)
+{
+ int ebda_len;
+ grub_uint8_t *ebda, *ptr;
+
+ grub_dprintf ("acpi", "Looking for RSDP. Scanning EBDA\n");
+ ebda = (grub_uint8_t *) ((* ((grub_uint16_t *) 0x40e)) << 4);
+ ebda_len = * (grub_uint16_t *) ebda;
+ if (! ebda_len) /* FIXME do we really need this check? */
+ goto scan_bios;
+ for (ptr = ebda; ptr < ebda + 0x400; ptr += 16)
+ if (grub_memcmp (ptr, GRUB_RSDP_SIGNATURE, GRUB_RSDP_SIGNATURE_SIZE) == 0
+ && grub_byte_checksum (ptr, sizeof (struct grub_acpi_rsdp_v10)) == 0
+ && ((struct grub_acpi_rsdp_v10 *) ptr)->revision == 0)
+ return (struct grub_acpi_rsdp_v10 *) ptr;
+
+scan_bios:
+ grub_dprintf ("acpi", "Looking for RSDP. Scanning BIOS\n");
+ for (ptr = (grub_uint8_t *) 0xe0000; ptr < (grub_uint8_t *) 0x100000;
+ ptr += 16)
+ if (grub_memcmp (ptr, GRUB_RSDP_SIGNATURE, GRUB_RSDP_SIGNATURE_SIZE) == 0
+ && grub_byte_checksum (ptr, sizeof (struct grub_acpi_rsdp_v10)) == 0
+ && ((struct grub_acpi_rsdp_v10 *) ptr)->revision == 0)
+ return (struct grub_acpi_rsdp_v10 *) ptr;
+ return 0;
+}
+
+struct grub_acpi_rsdp_v20 *
+grub_machine_acpi_get_rsdpv2 (void)
+{
+ int ebda_len;
+ grub_uint8_t *ebda, *ptr;
+
+ grub_dprintf ("acpi", "Looking for RSDP. Scanning EBDA\n");
+ ebda = (grub_uint8_t *) ((* ((grub_uint16_t *) 0x40e)) << 4);
+ ebda_len = * (grub_uint16_t *) ebda;
+ if (! ebda_len) /* FIXME do we really need this check? */
+ goto scan_bios;
+ for (ptr = ebda; ptr < ebda + 0x400; ptr += 16)
+ if (grub_memcmp (ptr, GRUB_RSDP_SIGNATURE, GRUB_RSDP_SIGNATURE_SIZE) == 0
+ && grub_byte_checksum (ptr, sizeof (struct grub_acpi_rsdp_v10)) == 0
+ && ((struct grub_acpi_rsdp_v10 *) ptr)->revision != 0
+ && ((struct grub_acpi_rsdp_v20 *) ptr)->length < 1024
+ && grub_byte_checksum (ptr, ((struct grub_acpi_rsdp_v20 *) ptr)->length)
+ == 0)
+ return (struct grub_acpi_rsdp_v20 *) ptr;
+
+scan_bios:
+ grub_dprintf ("acpi", "Looking for RSDP. Scanning BIOS\n");
+ for (ptr = (grub_uint8_t *) 0xe0000; ptr < (grub_uint8_t *) 0x100000;
+ ptr += 16)
+ if (grub_memcmp (ptr, GRUB_RSDP_SIGNATURE, GRUB_RSDP_SIGNATURE_SIZE) == 0
+ && grub_byte_checksum (ptr, sizeof (struct grub_acpi_rsdp_v10)) == 0
+ && ((struct grub_acpi_rsdp_v10 *) ptr)->revision != 0
+ && ((struct grub_acpi_rsdp_v20 *) ptr)->length < 1024
+ && grub_byte_checksum (ptr, ((struct grub_acpi_rsdp_v20 *) ptr)->length)
+ == 0)
+ return (struct grub_acpi_rsdp_v20 *) ptr;
+ return 0;
+}
diff --git a/grub-core/kern/i386/tsc.c b/grub-core/kern/i386/tsc.c
index 3b4786f..271c4db 100644
--- a/grub-core/kern/i386/tsc.c
+++ b/grub-core/kern/i386/tsc.c
@@ -145,6 +145,13 @@ calibrate_tsc_pit (void)
return 1;
}
+static int
+calibrate_tsc_hardcode (void)
+{
+ grub_tsc_rate = 5368;/* 800 MHz */
+ return 1;
+}
+
#endif
#if defined (GRUB_MACHINE_EFI)
@@ -229,13 +236,6 @@ calibrate_tsc_xen (void)
#endif
-static int
-calibrate_tsc_hardcode (void)
-{
- grub_tsc_rate = 5368;/* 800 MHz */
- return 1;
-}
-
void
grub_tsc_init (void)
{
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH] Use UEFI Time Service to calibrate TSC
2015-11-12 7:34 ` Michael Chang
@ 2015-11-12 8:52 ` Andrei Borzenkov
2015-11-12 9:22 ` Michael Chang
0 siblings, 1 reply; 8+ messages in thread
From: Andrei Borzenkov @ 2015-11-12 8:52 UTC (permalink / raw)
To: The development of GNU GRUB
On Thu, Nov 12, 2015 at 10:34 AM, Michael Chang <mchang@suse.com> wrote:
> On Mon, Nov 09, 2015 at 03:21:37PM +0100, Vladimir 'φ-coder/phcoder' Serbinenko wrote:
>> On 09.11.2015 14:23, Vladimir 'φ-coder/phcoder' Serbinenko wrote:
>> > On 09.11.2015 09:03, Michael Chang wrote:
>
>> Attached proof-of-concept. It's all in one file but different methods
>> should probably go in separate files.
>
> Hi Vladmir,
>
> Thanks for your guidence to the better fix. I built your patch with
> attach patch on top of yours to fix the errors found in our build
> service and also some other affected platforms which might also need the
> similar fix.
>
Why did you need to move i386-pc ACPI files to core? They are used by
acpi module only anyway, so there is no logical reason to do it?
> In the attatched patch, for i386-pc the acpi module was not built into
> kernel because from your patch seems not use pmtimer on it. That would
> be help in saving up the kernel image size.
>
> I have tested on x86_64-efi and i386-pc and so far it works as expected.
> Please note I also manually tweaked the patch to run pmtimer calibration
> in efi and it also worked.
>
> Thanks,
> Michael
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] Use UEFI Time Service to calibrate TSC
2015-11-12 8:52 ` Andrei Borzenkov
@ 2015-11-12 9:22 ` Michael Chang
0 siblings, 0 replies; 8+ messages in thread
From: Michael Chang @ 2015-11-12 9:22 UTC (permalink / raw)
To: The development of GNU GRUB
On Thu, Nov 12, 2015 at 11:52:24AM +0300, Andrei Borzenkov wrote:
> On Thu, Nov 12, 2015 at 10:34 AM, Michael Chang <mchang@suse.com> wrote:
> > On Mon, Nov 09, 2015 at 03:21:37PM +0100, Vladimir 'φ-coder/phcoder' Serbinenko wrote:
> >> On 09.11.2015 14:23, Vladimir 'φ-coder/phcoder' Serbinenko wrote:
> >> > On 09.11.2015 09:03, Michael Chang wrote:
> >
> >> Attached proof-of-concept. It's all in one file but different methods
> >> should probably go in separate files.
> >
> > Hi Vladmir,
> >
> > Thanks for your guidence to the better fix. I built your patch with
> > attach patch on top of yours to fix the errors found in our build
> > service and also some other affected platforms which might also need the
> > similar fix.
> >
>
> Why did you need to move i386-pc ACPI files to core? They are used by
> acpi module only anyway, so there is no logical reason to do it?
Because Vladimir's prototype patch has been moved them.
+ i386_coreboot = kern/i386/pc/acpi.c;
+ i386_multiboot = kern/i386/pc/acpi.c;
+ i386_coreboot = kern/acpi.c;
+ i386_multiboot = kern/acpi.c;
My patch was just intended to fix build error and test, Looking into the
patch it seems needed by coreboot. I could't tell much that
GRUB_MACHINE_MULTIBOOT is missed by accident or not in his patch.
+#elif defined (GRUB_MACHINE_COREBOOT)
+ (void) (calibrate_tsc_pmtimer() || calibrate_tsc_pit () ||
calibrate_tsc_hardcode());
+#else
Thanks,
Michael
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2015-11-12 9:33 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-11-09 7:07 [PATCH] Use UEFI Time Service to calibrate TSC Michael Chang
2015-11-09 7:29 ` Andrei Borzenkov
2015-11-09 8:03 ` Michael Chang
2015-11-09 13:23 ` Vladimir 'φ-coder/phcoder' Serbinenko
2015-11-09 14:21 ` Vladimir 'φ-coder/phcoder' Serbinenko
2015-11-12 7:34 ` Michael Chang
2015-11-12 8:52 ` Andrei Borzenkov
2015-11-12 9:22 ` Michael Chang
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.