diff --git a/ChangeLog b/ChangeLog index 002461c64..6b35a5c2b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2014-09-21 Valentin Dornauer + + The AML parser implements only a small subset of possible AML + opcodes. On the Fujitsu Lifebook E744 this and another bug in + the parser (incorrect handling of TermArg data types) would lead + to the laptop not turning off (_S5 not found). + + * grub-core/commands/acpihalt.c: Support OpAlias in the AML parser; + in skip_ext_op(), handle some Type2Opcodes more correctly (TermArgs + aren't always simply strings!); Add function to skip TermArgs + * include/grub/acpi.h: Add new opcodes + 2014-09-21 Vladimir Serbinenko * grub-core/normal/main.c: Don't drop to rescue console in diff --git a/grub-core/commands/acpihalt.c b/grub-core/commands/acpihalt.c index 83bdfe1f2..da68b5b52 100644 --- a/grub-core/commands/acpihalt.c +++ b/grub-core/commands/acpihalt.c @@ -135,6 +135,49 @@ skip_data_ref_object (const grub_uint8_t *ptr, const grub_uint8_t *end) } } +static inline grub_uint32_t +skip_term (const grub_uint8_t *ptr, const grub_uint8_t *end) +{ + grub_uint32_t add; + const grub_uint8_t *ptr0 = ptr; + + switch(*ptr) + { + case GRUB_ACPI_OPCODE_ADD: + case GRUB_ACPI_OPCODE_AND: + case GRUB_ACPI_OPCODE_CONCAT: + case GRUB_ACPI_OPCODE_CONCATRES: + case GRUB_ACPI_OPCODE_DIVIDE: + case GRUB_ACPI_OPCODE_INDEX: + case GRUB_ACPI_OPCODE_LSHIFT: + case GRUB_ACPI_OPCODE_MOD: + case GRUB_ACPI_OPCODE_MULTIPLY: + case GRUB_ACPI_OPCODE_NAND: + case GRUB_ACPI_OPCODE_NOR: + case GRUB_ACPI_OPCODE_OR: + case GRUB_ACPI_OPCODE_RSHIFT: + case GRUB_ACPI_OPCODE_SUBTRACT: + case GRUB_ACPI_OPCODE_TOSTRING: + case GRUB_ACPI_OPCODE_XOR: + /* + * Parameters for these opcodes: TermArg, TermArg Target, see ACPI + * spec r5.0, page 828f. + */ + ptr++; + ptr += add = skip_term (ptr, end); + if (!add) + return 0; + ptr += add = skip_term (ptr, end); + if (!add) + return 0; + ptr += skip_name_string (ptr, end); + break; + default: + return skip_data_ref_object (ptr, end); + } + return ptr - ptr0; +} + static inline grub_uint32_t skip_ext_op (const grub_uint8_t *ptr, const grub_uint8_t *end) { @@ -156,10 +199,10 @@ skip_ext_op (const grub_uint8_t *ptr, const grub_uint8_t *end) ptr++; ptr += skip_name_string (ptr, end); ptr++; - ptr += add = skip_data_ref_object (ptr, end); + ptr += add = skip_term (ptr, end); if (!add) return 0; - ptr += add = skip_data_ref_object (ptr, end); + ptr += add = skip_term (ptr, end); if (!add) return 0; break; @@ -180,6 +223,7 @@ skip_ext_op (const grub_uint8_t *ptr, const grub_uint8_t *end) return ptr - ptr0; } + static int get_sleep_type (grub_uint8_t *table, grub_uint8_t *ptr, grub_uint8_t *end, grub_uint8_t *scope, int scope_len) @@ -250,6 +294,17 @@ get_sleep_type (grub_uint8_t *table, grub_uint8_t *ptr, grub_uint8_t *end, if (!add) return -1; break; + case GRUB_ACPI_OPCODE_ALIAS: + ptr++; + /* We need to skip two name strings */ + ptr += add = skip_name_string (ptr, end); + if (!add) + return -1; + ptr += add = skip_name_string (ptr, end); + if (!add) + return -1; + break; + case GRUB_ACPI_OPCODE_SCOPE: { int scope_sleep_type; diff --git a/include/grub/acpi.h b/include/grub/acpi.h index 2ac2bd6fd..f6e6a11c5 100644 --- a/include/grub/acpi.h +++ b/include/grub/acpi.h @@ -191,7 +191,8 @@ void grub_acpi_halt (void); enum { GRUB_ACPI_OPCODE_ZERO = 0, GRUB_ACPI_OPCODE_ONE = 1, - GRUB_ACPI_OPCODE_NAME = 8, GRUB_ACPI_OPCODE_BYTE_CONST = 0x0a, + GRUB_ACPI_OPCODE_NAME = 8, GRUB_ACPI_OPCODE_ALIAS = 0x06, + GRUB_ACPI_OPCODE_BYTE_CONST = 0x0a, GRUB_ACPI_OPCODE_WORD_CONST = 0x0b, GRUB_ACPI_OPCODE_DWORD_CONST = 0x0c, GRUB_ACPI_OPCODE_STRING_CONST = 0x0d, @@ -199,6 +200,22 @@ enum GRUB_ACPI_OPCODE_BUFFER = 0x11, GRUB_ACPI_OPCODE_PACKAGE = 0x12, GRUB_ACPI_OPCODE_METHOD = 0x14, GRUB_ACPI_OPCODE_EXTOP = 0x5b, + GRUB_ACPI_OPCODE_ADD = 0x72, + GRUB_ACPI_OPCODE_CONCAT = 0x73, + GRUB_ACPI_OPCODE_SUBTRACT = 0x74, + GRUB_ACPI_OPCODE_MULTIPLY = 0x77, + GRUB_ACPI_OPCODE_DIVIDE = 0x78, + GRUB_ACPI_OPCODE_LSHIFT = 0x79, + GRUB_ACPI_OPCODE_RSHIFT = 0x7a, + GRUB_ACPI_OPCODE_AND = 0x7b, + GRUB_ACPI_OPCODE_NAND = 0x7c, + GRUB_ACPI_OPCODE_OR = 0x7d, + GRUB_ACPI_OPCODE_NOR = 0x7e, + GRUB_ACPI_OPCODE_XOR = 0x7f, + GRUB_ACPI_OPCODE_CONCATRES = 0x84, + GRUB_ACPI_OPCODE_MOD = 0x85, + GRUB_ACPI_OPCODE_INDEX = 0x88, + GRUB_ACPI_OPCODE_TOSTRING = 0x9c, GRUB_ACPI_OPCODE_CREATE_WORD_FIELD = 0x8b, GRUB_ACPI_OPCODE_CREATE_BYTE_FIELD = 0x8c, GRUB_ACPI_OPCODE_IF = 0xa0, GRUB_ACPI_OPCODE_ONES = 0xff