From: Andrei Borzenkov
Subject: [PATCH] e/pmtimer
---
grub-core/Makefile.am | 6 ++
grub-core/Makefile.core.def | 13 +++--
grub-core/commands/acpi.c | 12 ----
grub-core/commands/acpihalt.c | 66 ++++++---------------
grub-core/commands/efi/acpi.c | 59 -------------------
grub-core/commands/i386/pc/acpi.c | 81 --------------------------
grub-core/kern/acpi.c | 119 ++++++++++++++++++++++++++++++++++++++
grub-core/kern/efi/acpi.c | 59 +++++++++++++++++++
grub-core/kern/i386/pc/acpi.c | 81 ++++++++++++++++++++++++++
grub-core/kern/i386/tsc.c | 43 +++++++++++++-
include/grub/acpi.h | 31 ++++++++--
11 files changed, 361 insertions(+), 209 deletions(-)
diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am
index 5c087c8..da18dc5 100644
--- a/grub-core/Makefile.am
+++ b/grub-core/Makefile.am
@@ -93,6 +93,7 @@ KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h
KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/pxe.h
KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/int.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/tsc.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h
endif
if COND_i386_efi
@@ -100,6 +101,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_i386_coreboot
@@ -110,10 +112,12 @@ 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
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/tsc.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h
endif
if COND_i386_qemu
@@ -152,11 +156,13 @@ 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
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
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 42443bc..27ee48a 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -173,9 +173,18 @@ kernel = {
efi = kern/efi/init.c;
efi = kern/efi/mm.c;
efi = term/efi/console.c;
+ efi = kern/efi/acpi.c;
x86 = kern/i386/tsc.c;
+ efi = kern/acpi.c;
+ i386_coreboot = kern/acpi.c;
+ i386_multiboot = kern/acpi.c;
+ i386_pc = kern/acpi.c;
+ i386_pc = kern/i386/pc/acpi.c;
+ i386_coreboot = kern/i386/pc/acpi.c;
+ i386_multiboot = kern/i386/pc/acpi.c;
+
i386_efi = kern/i386/efi/init.c;
i386_efi = bus/pci.c;
@@ -683,10 +692,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 97c2cf2..2aaa202 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/commands/acpihalt.c b/grub-core/commands/acpihalt.c
index da68b5b..576e2bb 100644
--- a/grub-core/commands/acpihalt.c
+++ b/grub-core/commands/acpihalt.c
@@ -385,63 +385,35 @@ main (int argc, char **argv)
void
grub_acpi_halt (void)
{
- struct grub_acpi_rsdp_v20 *rsdp2;
- struct grub_acpi_rsdp_v10 *rsdp1;
- struct grub_acpi_table_header *rsdt;
- grub_uint32_t *entry_ptr;
- grub_uint32_t port = 0;
+ struct grub_acpi_fadt *fadt;
+ grub_uint32_t port;
+ struct grub_acpi_table_header *dsdt;
int sleep_type = -1;
- rsdp2 = grub_acpi_get_rsdpv2 ();
- if (rsdp2)
- rsdp1 = &(rsdp2->rsdpv1);
- else
- rsdp1 = grub_acpi_get_rsdpv1 ();
- grub_dprintf ("acpi", "rsdp1=%p\n", rsdp1);
- if (!rsdp1)
+ fadt = grub_acpi_find_fadt ();
+ if (!fadt)
return;
- rsdt = (struct grub_acpi_table_header *) (grub_addr_t) rsdp1->rsdt_addr;
- for (entry_ptr = (grub_uint32_t *) (rsdt + 1);
- entry_ptr < (grub_uint32_t *) (((grub_uint8_t *) rsdt)
- + rsdt->length);
- entry_ptr++)
- {
- if (grub_memcmp ((void *) (grub_addr_t) *entry_ptr, "FACP", 4) == 0)
- {
- struct grub_acpi_fadt *fadt
- = ((struct grub_acpi_fadt *) (grub_addr_t) *entry_ptr);
- struct grub_acpi_table_header *dsdt
- = (struct grub_acpi_table_header *) (grub_addr_t) fadt->dsdt_addr;
- grub_uint8_t *buf = (grub_uint8_t *) dsdt;
+ dsdt = (struct grub_acpi_table_header *) (grub_addr_t) fadt->dsdt_addr;
+ port = fadt->pm1a;
- port = fadt->pm1a;
+ grub_dprintf ("acpi", "PM1a port=%x\n", port);
- grub_dprintf ("acpi", "PM1a port=%x\n", port);
+ if (grub_memcmp (dsdt->signature, "DSDT",
+ sizeof (dsdt->signature)) != 0)
+ return;
- if (grub_memcmp (dsdt->signature, "DSDT",
- sizeof (dsdt->signature)) == 0
- && sleep_type < 0)
- sleep_type = get_sleep_type (buf, NULL, buf + dsdt->length,
- NULL, 0);
- }
- else if (grub_memcmp ((void *) (grub_addr_t) *entry_ptr, "SSDT", 4) == 0
- && sleep_type < 0)
- {
- struct grub_acpi_table_header *ssdt
- = (struct grub_acpi_table_header *) (grub_addr_t) *entry_ptr;
- grub_uint8_t *buf = (grub_uint8_t *) ssdt;
+ sleep_type = get_sleep_type ((grub_uint8_t *) dsdt, 0,
+ (grub_uint8_t *) dsdt + dsdt->length, 0, 0);
- grub_dprintf ("acpi", "SSDT = %p\n", ssdt);
+ if (sleep_type < 0 || sleep_type >= 8)
+ return;
- sleep_type = get_sleep_type (buf, NULL, buf + ssdt->length, NULL, 0);
- }
- }
+ grub_dprintf ("acpi", "SLP_TYP = %d, port = 0x%x\n",
+ sleep_type, port);
- grub_dprintf ("acpi", "SLP_TYP = %d, port = 0x%x\n", sleep_type, port);
- if (port && sleep_type >= 0 && sleep_type < 8)
- grub_outw (GRUB_ACPI_SLP_EN | (sleep_type << GRUB_ACPI_SLP_TYP_OFFSET),
- port & 0xffff);
+ grub_outw (GRUB_ACPI_SLP_EN
+ | (sleep_type << GRUB_ACPI_SLP_TYP_OFFSET), port & 0xffff);
grub_millisleep (1500);
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 = 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/commands/i386/pc/acpi.c b/grub-core/commands/i386/pc/acpi.c
deleted file mode 100644
index d415d23..0000000
--- a/grub-core/commands/i386/pc/acpi.c
+++ /dev/null
@@ -1,81 +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
-
-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)
- return 0;
- 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;
-
- 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)
- return 0;
- 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;
-
- 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/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 .
+ */
+
+#include
+#include
+#include
+#include
+
+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 .
+ */
+
+#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 = 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/i386/pc/acpi.c b/grub-core/kern/i386/pc/acpi.c
new file mode 100644
index 0000000..d415d23
--- /dev/null
+++ b/grub-core/kern/i386/pc/acpi.c
@@ -0,0 +1,81 @@
+/* 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
+
+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)
+ return 0;
+ 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;
+
+ 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)
+ return 0;
+ 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;
+
+ 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 3a4cae6..91bcb52 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
@@ -31,6 +31,7 @@
#include
#endif
#include
+#include
/* This defines the value TSC had at the epoch (that is, when we calibrated it). */
static grub_uint64_t tsc_boot_time;
@@ -111,6 +112,43 @@ grub_tsc_get_time_ms (void)
}
#ifndef GRUB_MACHINE_XEN
+static int
+grub_pmtimer_tsc_calibrate (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 end_tsc;
+
+ 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;
+ tsc_boot_time = grub_get_tsc ();
+ while (1)
+ {
+ cur = grub_inl (p) & 0xffffff;
+ if (cur < last)
+ cur |= 0x1000000;
+ if (cur >= end)
+ {
+ end_tsc = grub_get_tsc ();
+ grub_tsc_rate = grub_divmod64 (1ULL<<32, end_tsc - tsc_boot_time, 0);
+ grub_printf ("synced on PM\n");
+ return 1;
+ }
+ }
+}
+
/* Calibrate the TSC based on the RTC. */
static void
calibrate_tsc (void)
@@ -118,6 +156,9 @@ calibrate_tsc (void)
/* First calibrate the TSC rate (relative, not absolute time). */
grub_uint64_t end_tsc;
+ if (grub_pmtimer_tsc_calibrate ())
+ return;
+
tsc_boot_time = grub_get_tsc ();
grub_pit_wait (0xffff);
end_tsc = grub_get_tsc ();
diff --git a/include/grub/acpi.h b/include/grub/acpi.h
index f6e6a11..fc189c2 100644
--- a/include/grub/acpi.h
+++ b/include/grub/acpi.h
@@ -63,16 +63,34 @@ struct grub_acpi_table_header
struct grub_acpi_fadt
{
struct grub_acpi_table_header hdr;
+ /* 36 */
grub_uint32_t facs_addr;
grub_uint32_t dsdt_addr;
+ /* 44 */
grub_uint8_t somefields1[20];
+ /* 64 */
grub_uint32_t pm1a;
- grub_uint8_t somefields2[64];
+ /* 68 */
+ grub_uint8_t somefields2[8];
+ /* 76 */
+ grub_uint32_t pmtimer;
+ /* 80 */
+ grub_uint8_t somefields3[32];
+ /* 112 */
+ grub_uint32_t flags;
+ /* 116 */
+ grub_uint8_t somefields4[16];
+ /* 132 */
grub_uint64_t facs_xaddr;
grub_uint64_t dsdt_xaddr;
- grub_uint8_t somefields3[96];
+ grub_uint8_t somefields5[96];
} GRUB_PACKED;
+enum
+ {
+ GRUB_ACPI_FADT_FLAGS_LONG_PMTIMER = (1 << 8)
+ };
+
#define GRUB_ACPI_MADT_SIGNATURE "APIC"
struct grub_acpi_madt_entry_header
@@ -176,9 +194,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 +252,7 @@ enum
GRUB_ACPI_EXTOPCODE_BANK_FIELD_OP = 0x87,
};
+struct grub_acpi_fadt *
+EXPORT_FUNC(grub_acpi_find_fadt) (void);
+
#endif /* ! GRUB_ACPI_HEADER */
--
tg: (77063f4..) e/pmtimer (depends on: master)