grub-devel
[Top][All Lists]
Advanced

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

[PATCH] acpihalt: expand parser to handle SSDTs and some more opcodes


From: Colin Watson
Subject: [PATCH] acpihalt: expand parser to handle SSDTs and some more opcodes
Date: Wed, 13 Mar 2013 00:05:18 +0000
User-agent: Mutt/1.5.21 (2010-09-15)

GRUB hangs in 'make check' with seabios 1.7.2 (and I think also 1.7.1,
although I haven't tested that specifically).  The immediate cause of
this is that the _S5 object has been moved from the DSDT into an SSDT as
part of some clever integration with qemu.  After adding support for
SSDTs, to make things work again with the current seabios I also had to
add some basic support for scopes and to fill in knowledge of how to
skip a few more extended opcodes.

As a result of supporting scopes, it may be necessary to add support for
even more opcodes later, since we may not be skipping over them in one
big block any more.  To the extent that we've got away with the current
limited implementation it's probably only by luck anyway.  I felt that
this was an acceptable risk to take to get the test suite working again,
which is the main case where we actually *have* to be able to halt.

I initially used a non-recursive implementation of scopes involving
grub_list.  However, this made it a pain to link the userspace test
program (-DGRUB_DSDT_TEST), so I switched to a recursive implementation.
I think this is probably clearer anyway, and the diff is certainly
shorter than my previous attempt, even if the extra arguments do make
the entry points a bit more complicated.

2013-03-13  Colin Watson  <address@hidden>

        * grub-core/commands/acpihalt.c (skip_ext_op): Add support for
          skipping Event, Device, Processor, PowerRes, ThermalZone, and
          BankField extended opcodes.
          (get_sleep_type): Add minimal scope handling (just enough to
          handle setting the scope to the root path).
          (grub_acpi_halt): Parse any SSDTs as well as the DSDT.
        * include/grub/acpi.h: Add enumeration values for Event, Device,
          Processor, PowerRes, ThermalZone, and BankField extended opcodes.

=== modified file 'grub-core/commands/acpihalt.c'
--- grub-core/commands/acpihalt.c       2012-03-03 11:59:28 +0000
+++ grub-core/commands/acpihalt.c       2013-03-13 00:02:38 +0000
@@ -41,6 +41,7 @@ typedef uint8_t grub_uint8_t;
 #endif
 
 #ifndef GRUB_DSDT_TEST
+#include <grub/mm.h>
 #include <grub/misc.h>
 #include <grub/time.h>
 #include <grub/cpu/io.h>
@@ -146,6 +147,10 @@ skip_ext_op (const grub_uint8_t *ptr, co
       ptr += skip_name_string (ptr, end);
       ptr++;
       break;
+    case GRUB_ACPI_EXTOPCODE_EVENT_OP:
+      ptr++;
+      ptr += skip_name_string (ptr, end);
+      break;
     case GRUB_ACPI_EXTOPCODE_OPERATION_REGION:
       ptr++;
       ptr += skip_name_string (ptr, end);
@@ -158,7 +163,12 @@ skip_ext_op (const grub_uint8_t *ptr, co
        return 0;
       break;
     case GRUB_ACPI_EXTOPCODE_FIELD_OP:
+    case GRUB_ACPI_EXTOPCODE_DEVICE_OP:
+    case GRUB_ACPI_EXTOPCODE_PROCESSOR_OP:
+    case GRUB_ACPI_EXTOPCODE_POWER_RES_OP:
+    case GRUB_ACPI_EXTOPCODE_THERMAL_ZONE_OP:
     case GRUB_ACPI_EXTOPCODE_INDEX_FIELD_OP:
+    case GRUB_ACPI_EXTOPCODE_BANK_FIELD_OP:
       ptr++;
       ptr += decode_length (ptr, 0);
       break;
@@ -170,12 +180,14 @@ skip_ext_op (const grub_uint8_t *ptr, co
 }
 
 static int
-get_sleep_type (grub_uint8_t *table, grub_uint8_t *end)
+get_sleep_type (grub_uint8_t *table, grub_uint8_t *ptr, grub_uint8_t *end,
+               grub_uint8_t *scope, int scope_len)
 {
-  grub_uint8_t *ptr, *prev = table;
-  int sleep_type = -1;
+  grub_uint8_t *prev = table;
+  int sleep_type = -2;
   
-  ptr = table + sizeof (struct grub_acpi_table_header);
+  if (!ptr)
+    ptr = table + sizeof (struct grub_acpi_table_header);
   while (ptr < end && prev < ptr)
     {
       int add;
@@ -202,7 +214,8 @@ get_sleep_type (grub_uint8_t *table, gru
          }
        case GRUB_ACPI_OPCODE_NAME:
          ptr++;
-         if (memcmp (ptr, "_S5_", 4) == 0 || memcmp (ptr, "\\_S5_", 4) == 0)
+         if ((!scope || memcmp (scope, "\\", scope_len) == 0) &&
+             (memcmp (ptr, "_S5_", 4) == 0 || memcmp (ptr, "\\_S5_", 4) == 0))
            {
              int ll;
              grub_uint8_t *ptr2 = ptr;
@@ -241,6 +254,25 @@ get_sleep_type (grub_uint8_t *table, gru
            return -1;
          break;
        case GRUB_ACPI_OPCODE_SCOPE:
+         {
+           int scope_sleep_type;
+           int ll;
+           grub_uint8_t *name;
+           int name_len;
+
+           ptr++;
+           add = decode_length (ptr, &ll);
+           name = ptr + ll;
+           name_len = skip_name_string (name, ptr + add);
+           if (!name_len)
+             return -1;
+           scope_sleep_type = get_sleep_type (table, name + name_len,
+                                              ptr + add, name, name_len);
+           if (scope_sleep_type != -2)
+             return scope_sleep_type;
+           ptr += add;
+           break;
+         }
        case GRUB_ACPI_OPCODE_IF:
        case GRUB_ACPI_OPCODE_METHOD:
          {
@@ -291,7 +323,7 @@ main (int argc, char **argv)
       return 2;
     }
 
-  printf ("Sleep type = %d\n", get_sleep_type (buf, buf + len));
+  printf ("Sleep type = %d\n", get_sleep_type (buf, NULL, buf + len, NULL, 0));
   free (buf);
   fclose (f);
   return 0;
@@ -304,8 +336,10 @@ 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;
+  struct grub_acpi_table_header *rsdt;
+  grub_uint32_t *entry_ptr;
+  grub_uint32_t port = 0;
+  int sleep_type = -1;
 
   rsdp2 = grub_acpi_get_rsdpv2 ();
   if (rsdp2)
@@ -324,33 +358,39 @@ grub_acpi_halt (void)
     {
       if (grub_memcmp ((void *) (grub_addr_t) *entry_ptr, "FACP", 4) == 0)
        {
-         grub_uint32_t port;
          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;
-         int sleep_type = -1;
+         grub_uint8_t *buf = (grub_uint8_t *) dsdt;
 
          port = fadt->pm1a;
 
          grub_dprintf ("acpi", "PM1a port=%x\n", port);
 
          if (grub_memcmp (dsdt->signature, "DSDT",
-                          sizeof (dsdt->signature)) != 0)
-           break;
+                          sizeof (dsdt->signature)) == 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)
+       {
+         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,
-                                      (grub_uint8_t *) dsdt + dsdt->length);
+         grub_dprintf ("acpi", "SSDT = %p\n", ssdt);
 
-         if (sleep_type < 0 || sleep_type >= 8)
-           break;
+         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);
+  if (port && sleep_type >= 0 && sleep_type < 8)
+    {
+      grub_dprintf ("acpi", "SLP_TYP = %d, port = 0x%x\n", sleep_type, port);
 
-         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);

=== modified file 'include/grub/acpi.h'
--- include/grub/acpi.h 2013-02-01 20:48:01 +0000
+++ include/grub/acpi.h 2013-03-12 22:51:59 +0000
@@ -203,9 +203,15 @@ enum
 enum
   {
     GRUB_ACPI_EXTOPCODE_MUTEX = 0x01,
+    GRUB_ACPI_EXTOPCODE_EVENT_OP = 0x02,
     GRUB_ACPI_EXTOPCODE_OPERATION_REGION = 0x80,
     GRUB_ACPI_EXTOPCODE_FIELD_OP = 0x81,
+    GRUB_ACPI_EXTOPCODE_DEVICE_OP = 0x82,
+    GRUB_ACPI_EXTOPCODE_PROCESSOR_OP = 0x83,
+    GRUB_ACPI_EXTOPCODE_POWER_RES_OP = 0x84,
+    GRUB_ACPI_EXTOPCODE_THERMAL_ZONE_OP = 0x85,
     GRUB_ACPI_EXTOPCODE_INDEX_FIELD_OP = 0x86,
+    GRUB_ACPI_EXTOPCODE_BANK_FIELD_OP = 0x87,
   };
 
 #endif /* ! GRUB_ACPI_HEADER */

Thanks,

-- 
Colin Watson                                       address@hidden



reply via email to

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