В Sat, 11 Oct 2014 12:58:29 +0400
Andrei Borzenkov <arvidj...@gmail.com> пишет:

> В Sat, 11 Oct 2014 10:44:20 +0200
> Vladimir 'φ-coder/phcoder' Serbinenko <phco...@gmail.com> пишет:
> 
> > On 10.10.2014 23:23, Colin Watson wrote:
> > > On Fri, Oct 10, 2014 at 04:44:39PM +0000, Rigoberto Corujo wrote:
> > >> I attached a patch to bug #42944 and would like to know how I would go 
> > >> about getting it committed to the source tree?
> > >> https://savannah.gnu.org/bugs/?42944
> > > 
> > > I'd suggest attaching the patch to a mail here (not encased in a zip
> > > file).  It's usually easier to get public review that way.
> > > 
> > I don't like to use EFI timers if we can avoid them, they've been known
> > to hang. Attached is a patch to use pmtimer for calibration
> 
> What about systems without ACPI? Does it explicitly exclude them?

OK, I stay corrected. Still, this patch adds over 1K to kernel on
i386-pc and about 0.5K to common core.img with ext2:

-rw-r--r-- 1 bor bor 26848 Oct 12 20:09 /tmp/core.img-pmtimer
-rw-r--r-- 1 bor bor 26320 Oct 12 18:50 /tmp/core.img-vanilla
-rwxr-xr-x 1 bor bor 29224 Oct 12 20:08 /tmp/kernel.img-pmtimer
-rwxr-xr-x 1 bor bor 28060 Oct 12 10:12 /tmp/kernel.img-vanilla

I think it's too much for something that so far is needed only on very
specific platform. May be we could restrict it to EFI only where size
does not matter that much?

Attached rebased patch (I briefly checked and it still boots on i386-pc
and apparently correctly handles timeouts, but I cannot check other
platforms).
From: Andrei Borzenkov <arvidj...@gmail.com>
Subject: [PATCH] e/pmtimer

<patch description>

---
 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 <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/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 <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)
-    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 <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/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 <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)
+    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 <grub/i386/pit.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;
@@ -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)

Attachment: signature.asc
Description: PGP signature

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to