commit-grub
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[2161] 2009-05-02 Vladimir Serbinenko <address@hidden>


From: Vladimir Serbinenko
Subject: [2161] 2009-05-02 Vladimir Serbinenko <address@hidden>
Date: Sat, 02 May 2009 22:31:29 +0000

Revision: 2161
          http://svn.sv.gnu.org/viewvc/?view=rev&root=grub&revision=2161
Author:   phcoder
Date:     2009-05-02 22:31:29 +0000 (Sat, 02 May 2009)
Log Message:
-----------
2009-05-02  Vladimir Serbinenko <address@hidden>

        ACPI spoofing

        * commands/acpi.c: new file
        * commands/i386/pc/acpi.c: likewise
        * commands/efi/acpi.c: likewise
        * include/grub/acpi.h: likewise
        * conf/i386-pc.rmk (pkglib_MODULES): added acpi.mod
        (acpi_mod_SOURCES): new variable
        (acpi_mod_CFLAGS): likewise
        (acpi_mod_LDFLAGS): likewise
        * conf/i386-efi.rmk: likewise
        * conf/x86_64-efi.rmk: likewise

Modified Paths:
--------------
    trunk/grub2/ChangeLog
    trunk/grub2/conf/i386-efi.rmk
    trunk/grub2/conf/i386-pc.rmk
    trunk/grub2/conf/x86_64-efi.rmk

Added Paths:
-----------
    trunk/grub2/commands/acpi.c
    trunk/grub2/commands/efi/acpi.c
    trunk/grub2/commands/i386/pc/acpi.c
    trunk/grub2/include/grub/acpi.h

Modified: trunk/grub2/ChangeLog
===================================================================
--- trunk/grub2/ChangeLog       2009-05-02 22:27:29 UTC (rev 2160)
+++ trunk/grub2/ChangeLog       2009-05-02 22:31:29 UTC (rev 2161)
@@ -1,5 +1,20 @@
 2009-05-02  Vladimir Serbinenko <address@hidden>
 
+       ACPI spoofing
+
+       * commands/acpi.c: new file
+       * commands/i386/pc/acpi.c: likewise
+       * commands/efi/acpi.c: likewise
+       * include/grub/acpi.h: likewise
+       * conf/i386-pc.rmk (pkglib_MODULES): added acpi.mod
+       (acpi_mod_SOURCES): new variable
+       (acpi_mod_CFLAGS): likewise
+       (acpi_mod_LDFLAGS): likewise
+       * conf/i386-efi.rmk: likewise
+       * conf/x86_64-efi.rmk: likewise
+
+2009-05-02  Vladimir Serbinenko <address@hidden>
+
        Missing part from mmap patch
 
        * mmap/efi/mmap.c (grub_machine_mmap_unregister): renamed to

Added: trunk/grub2/commands/acpi.c
===================================================================
--- trunk/grub2/commands/acpi.c                         (rev 0)
+++ trunk/grub2/commands/acpi.c 2009-05-02 22:31:29 UTC (rev 2161)
@@ -0,0 +1,774 @@
+/* acpi.c - modify 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/dl.h>
+#include <grub/extcmd.h>
+#include <grub/file.h>
+#include <grub/disk.h>
+#include <grub/term.h>
+#include <grub/misc.h>
+#include <grub/gzio.h>
+#include <grub/acpi.h>
+#include <grub/mm.h>
+#include <grub/machine/machine.h>
+#include <grub/machine/memory.h>
+#include <grub/memory.h>
+
+#ifdef GRUB_MACHINE_EFI
+#include <grub/efi/efi.h>
+#include <grub/efi/api.h>
+#endif
+
+static const struct grub_arg_option options[] = {
+  {"exclude", 'x', 0, 
+   "Don't load host tables specified by comma-separated list", 
+   0, ARG_TYPE_STRING},
+  {"load-only", 'n', 0, 
+   "Load only tables specified by comma-separated list", 0, ARG_TYPE_STRING},
+  {"v1", '1', 0, "Expose v1 tables", 0, ARG_TYPE_NONE},
+  {"v2", '2', 0, "Expose v2 and v3 tables", 0, ARG_TYPE_NONE},
+  {"oemid", 'o', 0, "Set OEMID of RSDP, XSDT and RSDT", 0, ARG_TYPE_STRING},
+  {"oemtable", 't', 0, 
+   "Set OEMTABLE ID of RSDP, XSDT and RSDT", 0, ARG_TYPE_STRING},  
+  {"oemtablerev", 'r', 0, 
+   "Set OEMTABLE revision of RSDP, XSDT and RSDT", 0, ARG_TYPE_INT},  
+  {"oemtablecreator", 'c', 0, 
+   "Set creator field of RSDP, XSDT and RSDT", 0, ARG_TYPE_STRING},  
+  {"oemtablecreatorrev", 'd', 0, 
+   "Set creator revision of RSDP, XSDT and RSDT", 0, ARG_TYPE_INT},  
+  {"no-ebda", 'e', 0, "Don't update EBDA. May fix failures or hangs on some"
+   " BIOSes but makes it uneffective with OS not recieving RSDP fro GRUB", 
+   0, ARG_TYPE_NONE},
+  {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;
+static grub_dl_t my_mod;
+/* OEMID of RSDP, RSDT and XSDT. */
+static char root_oemid[6];
+/* OEMTABLE of the same tables. */
+static char root_oemtable[8];
+/* OEMREVISION of the same tables. */
+static grub_uint32_t root_oemrev;
+/* CreatorID of the same tables. */
+static char root_creator_id[4];
+/* CreatorRevision of the same tables. */
+static grub_uint32_t root_creator_rev;
+static struct grub_acpi_rsdp_v10 *rsdpv1_new = 0;
+static struct grub_acpi_rsdp_v20 *rsdpv2_new = 0;
+static char *playground = 0, *playground_ptr = 0;
+static int playground_size = 0;
+
+/* Linked list of ACPI tables. */
+struct efiemu_acpi_table
+{
+  void *addr;
+  grub_size_t size;
+  struct efiemu_acpi_table *next;
+};
+static struct efiemu_acpi_table *acpi_tables = 0;
+
+/* DSDT isn't in RSDT. So treat it specially. */
+static void *table_dsdt = 0;
+/* Pointer to recreated RSDT. */
+static void *rsdt_addr = 0;
+
+/* Allocation handles for different tables. */
+static grub_size_t dsdt_size = 0;
+
+/* Address of original FACS. */
+static grub_uint32_t facs_addr = 0;
+
+struct grub_acpi_rsdp_v20 *
+grub_acpi_get_rsdpv2 (void)
+{
+  if (rsdpv2_new)
+    return rsdpv2_new;
+  if (rsdpv1_new)
+    return 0;
+  return grub_machine_acpi_get_rsdpv2 ();
+}
+
+struct grub_acpi_rsdp_v10 *
+grub_acpi_get_rsdpv1 (void)
+{
+  if (rsdpv1_new)
+    return rsdpv1_new;
+  if (rsdpv2_new)
+    return 0;
+  return grub_machine_acpi_get_rsdpv1 ();
+}
+
+static inline int 
+iszero (grub_uint8_t *reg, int size)
+{
+  int i;
+  for (i = 0; i < size; i++)
+    if (reg[i])
+      return 0;
+  return 1;
+}
+
+grub_err_t 
+grub_acpi_create_ebda (void)
+{
+  int ebda_kb_len;
+  int ebda_len;
+  int mmapregion = 0;
+  grub_uint8_t *ebda, *v1inebda = 0, *v2inebda = 0;
+  grub_uint64_t highestlow = 0;
+  grub_uint8_t *targetebda, *target;
+  struct grub_acpi_rsdp_v10 *v1;
+  struct grub_acpi_rsdp_v20 *v2;
+  auto int NESTED_FUNC_ATTR find_hook (grub_uint64_t, grub_uint64_t, 
+                                      grub_uint32_t);
+  int NESTED_FUNC_ATTR find_hook (grub_uint64_t start, grub_uint64_t size, 
+                                 grub_uint32_t type)
+  {
+    grub_uint64_t end = start + size;
+    if (type != GRUB_MACHINE_MEMORY_AVAILABLE)
+      return 0;
+    if (end > 0x100000)
+      end = 0x100000;
+    if (end > start + ebda_len
+       && highestlow < ((end - ebda_len) & (~0xf)) )
+      highestlow = (end - ebda_len) & (~0xf);
+    return 0;
+  }
+  
+  ebda = (grub_uint8_t *) UINT_TO_PTR ((*((grub_uint16_t *)0x40e)) << 4);
+  ebda_kb_len = *(grub_uint16_t *) ebda;
+  if (! ebda || ebda_kb_len > 16)
+    ebda_kb_len = 0;
+  ebda_len = (ebda_kb_len + 1) << 10;
+
+  /* FIXME: use low-memory mm allocation once it's available. */
+  grub_mmap_iterate (find_hook);
+  targetebda = (grub_uint8_t *) UINT_TO_PTR (highestlow);
+  grub_dprintf ("acpi", "creating ebda @%llx\n",
+               (unsigned long long) highestlow);
+  if (! highestlow)
+    return grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+                      "couldn't find space for the new EBDA");
+
+  mmapregion = grub_mmap_register (PTR_TO_UINT64 (targetebda), ebda_len, 
+                                  GRUB_MACHINE_MEMORY_RESERVED);
+  if (! mmapregion)
+    return grub_errno;
+
+  /* XXX: EBDA is unstandartised, so this implementation is heuristical. */
+  if (ebda_kb_len)
+    grub_memcpy (targetebda, ebda, 0x400);
+  else
+    grub_memset (targetebda, 0, 0x400);
+  *((grub_uint16_t *) targetebda) = ebda_kb_len + 1;
+  target = targetebda;
+
+  v1 = grub_acpi_get_rsdpv1 ();
+  v2 = grub_acpi_get_rsdpv2 ();
+  if (v2 && v2->length > 40)
+    v2 = 0;
+
+  /* First try to replace already existing rsdp. */ 
+  if (v2)
+    {
+      grub_dprintf ("acpi", "Scanning EBDA for old rsdpv2\n");
+      for (; target < targetebda + 0x400 - v2->length; target += 0x10)
+       if (grub_memcmp (target, "RSD PTR ", 8) == 0
+           && grub_byte_checksum (target, 
+                                  sizeof (struct grub_acpi_rsdp_v10)) == 0
+           && ((struct grub_acpi_rsdp_v10 *) target)->revision != 0
+           && ((struct grub_acpi_rsdp_v20 *) target)->length <= v2->length)
+         {
+           grub_memcpy (target, v2, v2->length);
+           grub_dprintf ("acpi", "Copying rsdpv2 to %p\n", target);
+           v2inebda = target;
+           target += v2->length;
+           target = (grub_uint8_t *) ((((long) target - 1) | 0xf) + 1);
+           v2 = 0;
+           break;
+         }
+    }
+
+  if (v1)
+    {
+      grub_dprintf ("acpi", "Scanning EBDA for old rsdpv1\n");
+      for (; target < targetebda + 0x400 - sizeof (struct grub_acpi_rsdp_v10); 
+          target += 0x10)
+       if (grub_memcmp (target, "RSD PTR ", 8) == 0
+           && grub_byte_checksum (target, 
+                                  sizeof (struct grub_acpi_rsdp_v10)) == 0)
+         {
+           grub_memcpy (target, v1, sizeof (struct grub_acpi_rsdp_v10));
+           grub_dprintf ("acpi", "Copying rsdpv2 to %p\n", target);
+           v1inebda = target;
+           target += sizeof (struct grub_acpi_rsdp_v10);
+           target = (grub_uint8_t *) ((((long) target - 1) | 0xf) + 1);
+           v1 = 0;
+           break;
+         }
+    }
+
+  target = targetebda + 0x100;
+
+  /* Try contiguous zeros. */
+  if (v2)
+    {
+      grub_dprintf ("acpi", "Scanning EBDA for block of zeros\n");
+      for (; target < targetebda + 0x400 - v2->length; target += 0x10)
+       if (iszero (target, v2->length))
+         {
+           grub_dprintf ("acpi", "Copying rsdpv2 to %p\n", target);
+           grub_memcpy (target, v2, v2->length);
+           v2inebda = target;
+           target += v2->length;
+           target = (grub_uint8_t *) ((((long) target - 1) | 0xf) + 1);
+           v2 = 0;
+           break;
+         }
+    }
+
+  if (v1)
+    {
+      grub_dprintf ("acpi", "Scanning EBDA for block of zeros\n");
+      for (; target < targetebda + 0x400 - sizeof (struct grub_acpi_rsdp_v10); 
+          target += 0x10)
+       if (iszero (target, sizeof (struct grub_acpi_rsdp_v10)))
+         {
+           grub_dprintf ("acpi", "Copying rsdpv1 to %p\n", target);
+           grub_memcpy (target, v1, sizeof (struct grub_acpi_rsdp_v10));
+           v1inebda = target;
+           target += sizeof (struct grub_acpi_rsdp_v10);
+           target = (grub_uint8_t *) ((((long) target - 1) | 0xf) + 1);
+           v1 = 0;
+           break;
+         }
+    }
+
+  if (v1 || v2)
+    {
+      grub_mmap_unregister (mmapregion);
+      return grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+                        "Couldn't find suitable spot in EBDA");
+    }
+
+  /* Remove any other RSDT. */
+  for (target = targetebda; 
+       target < targetebda + 0x400 - sizeof (struct grub_acpi_rsdp_v10); 
+       target += 0x10)
+    if (grub_memcmp (target, "RSD PTR ", 8) == 0
+       && grub_byte_checksum (target, 
+                              sizeof (struct grub_acpi_rsdp_v10)) == 0
+       && target != v1inebda && target != v2inebda)
+      *target = 0;
+
+  grub_dprintf ("acpi", "Switching EBDA\n");
+  (*((grub_uint16_t *) 0x40e)) = ((long)targetebda) >> 4;
+  grub_dprintf ("acpi", "EBDA switched\n");
+
+  return GRUB_ERR_NONE;
+}
+
+/* Create tables common to ACPIv1 and ACPIv2+ */
+static void
+setup_common_tables (void)
+{
+  struct efiemu_acpi_table *cur;
+  struct grub_acpi_table_header *rsdt;
+  grub_uint32_t *rsdt_entry;
+  int numoftables;
+
+  /* Treat DSDT. */
+  grub_memcpy (playground_ptr, table_dsdt, dsdt_size);
+  grub_free (table_dsdt);
+  table_dsdt = playground_ptr;
+  playground_ptr += dsdt_size;
+  
+  /* Treat other tables. */
+  for (cur = acpi_tables; cur; cur = cur->next)
+    {
+      struct grub_acpi_fadt *fadt;
+
+      grub_memcpy (playground_ptr, cur->addr, cur->size);
+      grub_free (cur->addr);
+      cur->addr = playground_ptr;
+      playground_ptr += cur->size;
+
+      /* If it's FADT correct DSDT and FACS addresses. */
+      fadt = (struct grub_acpi_fadt *) cur->addr;
+      if (grub_memcmp (fadt->hdr.signature, "FACP", 4) == 0)
+       {
+         fadt->dsdt_addr = PTR_TO_UINT32 (table_dsdt);
+         fadt->facs_addr = facs_addr;
+
+         /* Does a revision 2 exist at all? */
+         if (fadt->hdr.revision >= 3)
+           {
+             fadt->dsdt_xaddr = PTR_TO_UINT64 (table_dsdt);
+             fadt->facs_xaddr = facs_addr;
+           }
+
+         /* Recompute checksum. */
+         fadt->hdr.checksum = 0;
+         fadt->hdr.checksum = 1 + ~grub_byte_checksum (fadt, fadt->hdr.length);
+       }
+    }
+ 
+  /* Fill RSDT entries. */
+  numoftables = 0;
+  for (cur = acpi_tables; cur; cur = cur->next)
+    numoftables++;
+
+  rsdt_addr = rsdt = (struct grub_acpi_table_header *) playground_ptr;
+  playground_ptr += sizeof (struct grub_acpi_table_header) + 4 * numoftables;
+
+  rsdt_entry = (grub_uint32_t *)(rsdt + 1);
+
+  /* Fill RSDT header. */
+  grub_memcpy (&(rsdt->signature), "RSDT", 4);
+  rsdt->length = sizeof (struct grub_acpi_table_header) + 4 * numoftables;
+  rsdt->revision = 1;
+  grub_memcpy (&(rsdt->oemid), root_oemid, 6);
+  grub_memcpy (&(rsdt->oemtable), root_oemtable, 4);
+  rsdt->oemrev = root_oemrev;
+  grub_memcpy (&(rsdt->creator_id), root_creator_id, 6);
+  rsdt->creator_rev = root_creator_rev;
+
+  for (cur = acpi_tables; cur; cur = cur->next)
+    *(rsdt_entry++) = PTR_TO_UINT32 (cur->addr);
+  
+  /* Recompute checksum. */
+  rsdt->checksum = 0;
+  rsdt->checksum = 1 + ~grub_byte_checksum (rsdt, rsdt->length);
+}
+
+/* Regenerate ACPIv1 RSDP */
+static void
+setv1table (void)
+{
+  /* Create RSDP. */
+  rsdpv1_new = (struct grub_acpi_rsdp_v10 *) playground_ptr;
+  playground_ptr += sizeof (struct grub_acpi_rsdp_v10);
+  grub_memcpy (&(rsdpv1_new->signature), "RSD PTR ", 8);
+  grub_memcpy (&(rsdpv1_new->oemid), root_oemid, sizeof  (rsdpv1_new->oemid));
+  rsdpv1_new->revision = 0;
+  rsdpv1_new->rsdt_addr = PTR_TO_UINT32 (rsdt_addr);
+  rsdpv1_new->checksum = 0;
+  rsdpv1_new->checksum = 1 + ~grub_byte_checksum (rsdpv1_new, 
+                                                 sizeof (*rsdpv1_new));  
+  grub_dprintf ("acpi", "Generated ACPIv1 tables\n");
+}
+
+static void
+setv2table (void)
+{
+  struct grub_acpi_table_header *xsdt;
+  struct efiemu_acpi_table *cur;
+  grub_uint64_t *xsdt_entry;
+  int numoftables;
+
+  numoftables = 0;
+  for (cur = acpi_tables; cur; cur = cur->next)
+    numoftables++;
+
+  /* Create XSDT. */
+  xsdt = (struct grub_acpi_table_header *) playground_ptr;
+  playground_ptr += sizeof (struct grub_acpi_table_header) + 8 * numoftables;
+
+  xsdt_entry = (grub_uint64_t *)(xsdt + 1);
+  for (cur = acpi_tables; cur; cur = cur->next)
+    *(xsdt_entry++) = PTR_TO_UINT64 (cur->addr);
+  grub_memcpy (&(xsdt->signature), "XSDT", 4);
+  xsdt->length = sizeof (struct grub_acpi_table_header) + 8 * numoftables;
+  xsdt->revision = 1;
+  grub_memcpy (&(xsdt->oemid), root_oemid, sizeof (xsdt->oemid));
+  grub_memcpy (&(xsdt->oemtable), root_oemtable, sizeof (xsdt->oemtable));
+  xsdt->oemrev = root_oemrev;
+  grub_memcpy (&(xsdt->creator_id), root_creator_id, sizeof 
(xsdt->creator_id));
+  xsdt->creator_rev = root_creator_rev;
+  xsdt->checksum = 0;
+  xsdt->checksum = 1 + ~grub_byte_checksum (xsdt, xsdt->length);
+
+  /* Create RSDPv2. */
+  rsdpv2_new = (struct grub_acpi_rsdp_v20 *) playground_ptr;
+  playground_ptr += sizeof (struct grub_acpi_rsdp_v20);
+  grub_memcpy (&(rsdpv2_new->rsdpv1.signature), "RSD PTR ", 
+              sizeof (rsdpv2_new->rsdpv1.signature));
+  grub_memcpy (&(rsdpv2_new->rsdpv1.oemid), root_oemid, 
+              sizeof (rsdpv2_new->rsdpv1.oemid));
+  rsdpv2_new->rsdpv1.revision = rev2;
+  rsdpv2_new->rsdpv1.rsdt_addr = PTR_TO_UINT32 (rsdt_addr);
+  rsdpv2_new->rsdpv1.checksum = 0;
+  rsdpv2_new->rsdpv1.checksum = 1 + ~grub_byte_checksum 
+    (&(rsdpv2_new->rsdpv1), sizeof (rsdpv2_new->rsdpv1));
+  rsdpv2_new->length = sizeof (*rsdpv2_new);
+  rsdpv2_new->xsdt_addr = PTR_TO_UINT64 (xsdt);
+  rsdpv2_new->checksum = 0;
+  rsdpv2_new->checksum = 1 + ~grub_byte_checksum (rsdpv2_new, 
+                                                 rsdpv2_new->length);
+  grub_dprintf ("acpi", "Generated ACPIv2 tables\n");
+}
+
+static void
+free_tables (void)
+{
+  struct efiemu_acpi_table *cur, *t;
+  if (table_dsdt)
+    grub_free (table_dsdt);
+  for (cur = acpi_tables; cur;)
+    {
+      t = cur;
+      grub_free (cur->addr);
+      cur = cur->next;
+      grub_free (t);
+    }
+  acpi_tables = 0;
+  table_dsdt = 0;
+}
+
+static grub_err_t
+grub_cmd_acpi (struct grub_extcmd *cmd,
+                     int argc, char **args)
+{
+  struct grub_arg_list *state = cmd->state;
+  struct grub_acpi_rsdp_v10 *rsdp;
+  struct efiemu_acpi_table *cur, *t;
+  grub_err_t err;
+  int i, mmapregion;
+  int numoftables;
+  
+  /* Default values if no RSDP is found. */
+  rev1 = 1;
+  rev2 = 3;
+
+  facs_addr = 0;
+  playground = playground_ptr = 0;
+  playground_size = 0;
+  
+  rsdp = (struct grub_acpi_rsdp_v10 *) grub_machine_acpi_get_rsdpv2 ();
+
+  if (! rsdp)
+    rsdp = grub_machine_acpi_get_rsdpv1 ();
+
+  if (rsdp)
+    {
+      grub_uint32_t *entry_ptr;
+      char *exclude = 0;
+      char *load_only = 0;
+      char *ptr;
+      /* RSDT consists of header and an array of 32-bit pointers. */
+      struct grub_acpi_table_header *rsdt;
+
+      exclude = state[0].set ? grub_strdup (state[0].arg) : 0;
+      if (exclude)
+       {
+         for (ptr = exclude; *ptr; ptr++)
+           *ptr = grub_tolower (*ptr);
+       }
+
+      load_only = state[1].set ? grub_strdup (state[1].arg) : 0;
+      if (load_only)
+       {
+         for (ptr = load_only; *ptr; ptr++)
+           *ptr = grub_tolower (*ptr);
+       }
+
+      /* Set revision variables to replicant the same version as host. */
+      rev1 = ! rsdp->revision;
+      rev2 = rsdp->revision;
+      rsdt = (struct grub_acpi_table_header *) UINT_TO_PTR (rsdp->rsdt_addr);
+      /* Load host tables. */
+      for (entry_ptr = (grub_uint32_t *) (rsdt + 1);
+          entry_ptr < (grub_uint32_t *) (((grub_uint8_t *) rsdt) 
+                                         + rsdt->length);
+          entry_ptr++)
+       {
+         char signature[5];
+         struct efiemu_acpi_table *table;
+         struct grub_acpi_table_header *curtable 
+           = (struct grub_acpi_table_header *) UINT_TO_PTR (*entry_ptr);
+         signature[4] = 0;
+         for (i = 0; i < 4;i++)
+           signature[i] = grub_tolower (curtable->signature[i]);
+         
+         /* If it's FADT it contains addresses of DSDT and FACS. */
+         if (grub_strcmp (signature, "facp") == 0)
+           {
+             struct grub_acpi_table_header *dsdt;
+             struct grub_acpi_fadt *fadt = (struct grub_acpi_fadt *) curtable;
+
+             /* Set root header variables to the same values 
+                as FACP by default. */
+             grub_memcpy (&root_oemid, &(fadt->hdr.oemid), 
+                          sizeof (root_oemid));
+             grub_memcpy (&root_oemtable, &(fadt->hdr.oemtable), 
+                          sizeof (root_oemtable));
+             root_oemrev = fadt->hdr.oemrev;
+             grub_memcpy (&root_creator_id, &(fadt->hdr.creator_id), 
+                          sizeof (root_creator_id));
+             root_creator_rev = fadt->hdr.creator_rev;
+
+             /* Load DSDT if not excluded. */
+             dsdt = (struct grub_acpi_table_header *) 
+               UINT_TO_PTR (fadt->dsdt_addr);
+             if (dsdt && (! exclude || ! grub_strword (exclude, "dsdt"))
+                 && (! load_only || grub_strword (load_only, "dsdt"))
+                 && dsdt->length >= sizeof (*dsdt))
+               {
+                 dsdt_size = dsdt->length;
+                 table_dsdt = grub_malloc (dsdt->length);
+                 if (! table_dsdt)
+                   {
+                     free_tables ();
+                     grub_free (exclude);
+                     grub_free (load_only);
+                     return grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+                                        "Could allocate table");
+                   }
+                 grub_memcpy (table_dsdt, dsdt, dsdt->length);
+               }
+
+             /* Save FACS address. FACS shouldn't be overriden. */
+             facs_addr = fadt->facs_addr;
+           }
+  
+         /* Skip excluded tables. */
+         if (exclude && grub_strword (exclude, signature))
+           continue;
+         if (load_only && ! grub_strword (load_only, signature))
+           continue;
+
+         /* Sanity check. */
+         if (curtable->length < sizeof (*curtable))
+           continue;
+         
+         table = (struct efiemu_acpi_table *) grub_malloc 
+           (sizeof (struct efiemu_acpi_table));
+         if (! table)
+           {
+             free_tables ();
+             grub_free (exclude);
+             grub_free (load_only);
+             return grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+                                "Could allocate table structure");
+           }
+         table->size = curtable->length;
+         table->addr = grub_malloc (table->size);
+         playground_size += table->size;
+         if (! table->addr)
+           {
+             free_tables ();
+             return grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+                                "Could allocate table");
+           }
+         table->next = acpi_tables;
+         acpi_tables = table;
+         grub_memcpy (table->addr, curtable, table->size);
+       }
+      grub_free (exclude);
+      grub_free (load_only);      
+    }
+
+  /* Does user specify versions to generate? */
+  if (state[2].set || state[3].set)
+    {
+      rev1 = state[2].set;
+      if (state[3].set)
+       rev2 = rev2 ? : 2;
+      else
+       rev2 = 0;
+    }
+
+  /* Does user override root header information? */
+  if (state[4].set)
+    grub_strncpy (root_oemid, state[4].arg, sizeof (root_oemid));
+  if (state[5].set)
+    grub_strncpy (root_oemtable, state[5].arg, sizeof (root_oemtable));
+  if (state[6].set)
+    root_oemrev = grub_strtoul (state[6].arg, 0, 0);
+  if (state[7].set)
+    grub_strncpy (root_creator_id, state[7].arg, sizeof (root_creator_id));
+  if (state[8].set)
+    root_creator_rev = grub_strtoul (state[8].arg, 0, 0);
+
+  /* Load user tables */
+  for (i = 0; i < argc; i++)
+    {
+      grub_file_t file;
+      grub_size_t size;
+      char *buf;
+
+      file = grub_gzfile_open (args[i], 1);
+      if (! file)
+       {
+         free_tables ();
+         return grub_error (GRUB_ERR_BAD_OS, "couldn't open file %s", args[i]);
+       }
+
+      size = grub_file_size (file);
+      if (size < sizeof (struct grub_acpi_table_header))
+       {
+         grub_file_close (file);
+         free_tables ();
+         return grub_error (GRUB_ERR_BAD_OS, "file %s is too small", args[i]);
+       }
+
+      buf = (char *) grub_malloc (size);
+      if (! buf)
+       {
+         grub_file_close (file);
+         free_tables ();
+         return grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+                            "couldn't read file %s", args[i]);
+       }
+
+      if (grub_file_read (file, buf, size) != (int) size)
+       {
+         grub_file_close (file);
+         free_tables ();
+         return grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", args[i]);
+       }
+      grub_file_close (file);      
+
+      if (grub_memcmp (((struct grub_acpi_table_header *) buf)->signature, 
+                      "DSDT", 4) == 0)
+       {
+         grub_free (table_dsdt);
+         table_dsdt = buf;
+         dsdt_size = size;
+       }
+      else
+       {
+         struct efiemu_acpi_table *table;
+         table = (struct efiemu_acpi_table *) grub_malloc 
+           (sizeof (struct efiemu_acpi_table));
+         if (! table)
+           {
+             free_tables ();
+             return grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+                                "Could allocate table structure");
+           }
+
+         table->size = size;
+         table->addr = buf;
+         playground_size += table->size;
+       }
+    }
+
+  numoftables = 0;
+  for (cur = acpi_tables; cur; cur = cur->next)
+    numoftables++;
+
+  /* DSDT. */
+  playground_size += dsdt_size;
+  /* RSDT. */
+  playground_size += sizeof (struct grub_acpi_table_header) + 4 * numoftables;
+  /* RSDPv1. */
+  playground_size += sizeof (struct grub_acpi_rsdp_v10);
+  /* XSDT. */
+  playground_size += sizeof (struct grub_acpi_table_header) + 8 * numoftables;
+  /* RSDPv2. */
+  playground_size += sizeof (struct grub_acpi_rsdp_v20);
+  
+  playground = playground_ptr 
+    = grub_mmap_malign_and_register (1, playground_size, &mmapregion,
+                                    GRUB_MACHINE_MEMORY_ACPI, 0);
+
+  if (! playground)
+    {
+      free_tables ();
+      return grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+                        "Couldn't allocate space for ACPI tables");
+    }
+
+  setup_common_tables ();
+
+  /* Request space for RSDPv1. */
+  if (rev1)
+    setv1table ();
+
+  /* Request space for RSDPv2+ and XSDT. */
+  if (rev2)
+    setv2table ();
+
+  for (cur = acpi_tables; cur;)
+    {
+      t = cur;
+      cur = cur->next;
+      grub_free (t);
+    }
+  acpi_tables = 0;
+
+  if (! state[9].set && (err = grub_acpi_create_ebda ()))
+    {
+      rsdpv1_new = 0;
+      rsdpv2_new = 0;
+      grub_mmap_free_and_unregister (mmapregion);
+      return err;
+    }
+
+#ifdef GRUB_MACHINE_EFI
+  {
+    struct grub_efi_guid acpi = GRUB_EFI_ACPI_TABLE_GUID;
+    struct grub_efi_guid acpi20 = GRUB_EFI_ACPI_20_TABLE_GUID;
+
+    grub_efi_system_table->boot_services->install_configuration_table 
+      (&acpi20, grub_acpi_get_rsdpv2 ());
+    grub_efi_system_table->boot_services->install_configuration_table 
+      (&acpi, grub_acpi_get_rsdpv1 ());
+  }
+#endif
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_extcmd_t cmd;
+
+GRUB_MOD_INIT(acpi)
+{
+  (void) mod;                  /* To stop warning. */
+  cmd = grub_register_extcmd ("acpi", grub_cmd_acpi, 
+                             GRUB_COMMAND_FLAG_BOTH,
+                             "acpi [-1|-2] [--exclude=table1,table2|"
+                             "--load-only=table1,table2] filename1 "
+                             " [filename2] [...]",
+                             "Load host acpi tables and tables "
+                             "specified by arguments", 
+                             options);
+  my_mod=mod;
+}
+
+GRUB_MOD_FINI(acpi)
+{
+  grub_unregister_extcmd (cmd);
+}

Added: trunk/grub2/commands/efi/acpi.c
===================================================================
--- trunk/grub2/commands/efi/acpi.c                             (rev 0)
+++ trunk/grub2/commands/efi/acpi.c     2009-05-02 22:31:29 UTC (rev 2161)
@@ -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_guid_t acpi_guid = GRUB_EFI_ACPI_TABLE_GUID;
+
+  for (i = 0; i < grub_efi_system_table->num_table_entries; i++)
+    {
+      grub_efi_guid_t *guid =
+       &grub_efi_system_table->configuration_table[i].vendor_guid;
+
+      if (! grub_memcmp (guid, &acpi_guid, sizeof (grub_efi_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_guid_t acpi20_guid = GRUB_EFI_ACPI_20_TABLE_GUID;
+
+  for (i = 0; i < grub_efi_system_table->num_table_entries; i++)
+    {
+      grub_efi_guid_t *guid =
+       &grub_efi_system_table->configuration_table[i].vendor_guid;
+
+      if (! grub_memcmp (guid, &acpi20_guid, sizeof (grub_efi_guid_t)))
+       return (struct grub_acpi_rsdp_v20 *) 
+         grub_efi_system_table->configuration_table[i].vendor_table;
+    }
+  return 0;
+}

Added: trunk/grub2/commands/i386/pc/acpi.c
===================================================================
--- trunk/grub2/commands/i386/pc/acpi.c                         (rev 0)
+++ trunk/grub2/commands/i386/pc/acpi.c 2009-05-02 22:31:29 UTC (rev 2161)
@@ -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, "RSD PTR ", 8) == 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, "RSD PTR ", 8) == 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, "RSD PTR ", 8) == 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, "RSD PTR ", 8) == 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;
+}

Modified: trunk/grub2/conf/i386-efi.rmk
===================================================================
--- trunk/grub2/conf/i386-efi.rmk       2009-05-02 22:27:29 UTC (rev 2160)
+++ trunk/grub2/conf/i386-efi.rmk       2009-05-02 22:31:29 UTC (rev 2161)
@@ -82,7 +82,8 @@
 # Modules.
 pkglib_MODULES = kernel.mod chain.mod appleldr.mod \
        linux.mod halt.mod reboot.mod pci.mod lspci.mod \
-       datetime.mod date.mod datehook.mod loadbios.mod fixvideo.mod mmap.mod
+       datetime.mod date.mod datehook.mod loadbios.mod \
+       fixvideo.mod mmap.mod acpi.mod
 
 # For kernel.mod.
 kernel_mod_EXPORTS = no
@@ -115,6 +116,11 @@
 kernel_syms.lst: $(addprefix include/grub/,$(kernel_mod_HEADERS)) config.h 
genkernsyms.sh
        /bin/sh genkernsyms.sh $(filter %.h,$^) > $@ || (rm -f $@; exit 1)
 
+# For acpi.mod.
+acpi_mod_SOURCES = commands/acpi.c commands/efi/acpi.c
+acpi_mod_CFLAGS = $(COMMON_CFLAGS)
+acpi_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
 # For mmap.mod.
 mmap_mod_SOURCES = mmap/mmap.c mmap/i386/uppermem.c mmap/i386/mmap.c \
                   mmap/efi/mmap.c

Modified: trunk/grub2/conf/i386-pc.rmk
===================================================================
--- trunk/grub2/conf/i386-pc.rmk        2009-05-02 22:27:29 UTC (rev 2160)
+++ trunk/grub2/conf/i386-pc.rmk        2009-05-02 22:31:29 UTC (rev 2161)
@@ -185,8 +185,13 @@
        aout.mod bsd.mod pxe.mod pxecmd.mod datetime.mod date.mod \
        datehook.mod lsmmap.mod ata_pthru.mod hdparm.mod \
        usb.mod uhci.mod ohci.mod usbtest.mod usbms.mod usb_keyboard.mod \
-       mmap.mod
+       mmap.mod acpi.mod
 
+# For acpi.mod.
+acpi_mod_SOURCES = commands/acpi.c commands/i386/pc/acpi.c
+acpi_mod_CFLAGS = $(COMMON_CFLAGS)
+acpi_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
 # For mmap.mod.
 mmap_mod_SOURCES = mmap/mmap.c mmap/i386/uppermem.c mmap/i386/mmap.c \
                   mmap/i386/pc/mmap.c mmap/i386/pc/mmap_helper.S

Modified: trunk/grub2/conf/x86_64-efi.rmk
===================================================================
--- trunk/grub2/conf/x86_64-efi.rmk     2009-05-02 22:27:29 UTC (rev 2160)
+++ trunk/grub2/conf/x86_64-efi.rmk     2009-05-02 22:31:29 UTC (rev 2161)
@@ -80,7 +80,8 @@
 # Modules.
 pkglib_MODULES = kernel.mod chain.mod appleldr.mod \
        halt.mod reboot.mod linux.mod pci.mod lspci.mod \
-       datetime.mod date.mod datehook.mod loadbios.mod fixvideo.mod mmap.mod
+       datetime.mod date.mod datehook.mod loadbios.mod \
+       fixvideo.mod mmap.mod acpi.mod
 
 # For kernel.mod.
 kernel_mod_EXPORTS = no
@@ -114,6 +115,11 @@
 kernel_syms.lst: $(addprefix include/grub/,$(kernel_mod_HEADERS)) config.h 
genkernsyms.sh
        /bin/sh genkernsyms.sh $(filter %.h,$^) > $@ || (rm -f $@; exit 1)
 
+# For acpi.mod.
+acpi_mod_SOURCES = commands/acpi.c commands/efi/acpi.c
+acpi_mod_CFLAGS = $(COMMON_CFLAGS)
+acpi_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
 # For mmap.mod.
 mmap_mod_SOURCES = mmap/mmap.c mmap/i386/uppermem.c mmap/i386/mmap.c \
                   mmap/efi/mmap.c

Added: trunk/grub2/include/grub/acpi.h
===================================================================
--- trunk/grub2/include/grub/acpi.h                             (rev 0)
+++ trunk/grub2/include/grub/acpi.h     2009-05-02 22:31:29 UTC (rev 2161)
@@ -0,0 +1,75 @@
+/*
+ *  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/>.
+ */
+
+#ifndef GRUB_ACPI_HEADER
+#define GRUB_ACPI_HEADER       1
+
+#include <grub/types.h>
+#include <grub/err.h>
+
+struct grub_acpi_rsdp_v10
+{
+  grub_uint8_t signature[8];
+  grub_uint8_t checksum;
+  grub_uint8_t oemid[6];
+  grub_uint8_t revision;
+  grub_uint32_t rsdt_addr;
+} __attribute__ ((packed));
+
+struct grub_acpi_rsdp_v20
+{
+  struct grub_acpi_rsdp_v10 rsdpv1;
+  grub_uint32_t length;
+  grub_uint64_t xsdt_addr;
+  grub_uint8_t checksum;
+  grub_uint8_t reserved[3];
+} __attribute__ ((packed));
+
+struct grub_acpi_table_header
+{
+  grub_uint8_t signature[4];
+  grub_uint32_t length;
+  grub_uint8_t revision;
+  grub_uint8_t checksum;
+  grub_uint8_t oemid[6];
+  grub_uint8_t oemtable[8];
+  grub_uint32_t oemrev;
+  grub_uint8_t creator_id[4];
+  grub_uint32_t creator_rev;  
+} __attribute__ ((packed));
+
+struct grub_acpi_fadt
+{
+  struct grub_acpi_table_header hdr;
+  grub_uint32_t facs_addr;
+  grub_uint32_t dsdt_addr;
+  grub_uint8_t somefields1[88];
+  grub_uint64_t facs_xaddr;
+  grub_uint64_t dsdt_xaddr;
+  grub_uint8_t somefields2[96];
+} __attribute__ ((packed));
+
+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);
+
+grub_err_t grub_acpi_create_ebda (void);
+
+#endif /* ! GRUB_ACPI_HEADER */





reply via email to

[Prev in Thread] Current Thread [Next in Thread]