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 <[email protected]> * 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 [[email protected]] _______________________________________________ Grub-devel mailing list [email protected] https://lists.gnu.org/mailman/listinfo/grub-devel
