static inline grub_uint32_t skip_ext_op (const grub_uint8_t *ptr, const grub_uint8_t *end) { const grub_uint8_t *ptr0 = ptr; int add; grub_dprintf ("acpi", "Extended opcode: 0x%x\n", *ptr); switch (*ptr) { case GRUB_ACPI_EXTOPCODE_MUTEX: ptr++; ptr += skip_name_string (ptr, end); ptr++; break; case GRUB_ACPI_EXTOPCODE_OPERATION_REGION: ptr++; ptr += skip_name_string (ptr, end); ptr++; ptr += add = skip_data_ref_object (ptr, end); if (!add) return 0; ptr += add = skip_data_ref_object (ptr, end); if (!add) return 0; break; case GRUB_ACPI_EXTOPCODE_FIELD_OP: case GRUB_ACPI_EXTOPCODE_INDEX_FIELD_OP: ptr++; ptr += decode_length (ptr, 0); break; default: grub_printf ("Unexpected extended opcode: 0x%x\n", *ptr); return 0; } return ptr - ptr0; }
static int get_sleep_type (grub_uint8_t *table, grub_uint8_t *end) { grub_uint8_t *ptr, *prev = table; int sleep_type = -1; ptr = table + sizeof (struct grub_acpi_table_header); while (ptr < end && prev < ptr) { int add; prev = ptr; grub_dprintf ("acpi", "Opcode 0x%x\n", *ptr); grub_dprintf ("acpi", "Tell %x\n", (unsigned) (ptr - table)); switch (*ptr) { case GRUB_ACPI_OPCODE_EXTOP: ptr++; ptr += add = skip_ext_op (ptr, end); if (!add) return -1; break; case GRUB_ACPI_OPCODE_CREATE_WORD_FIELD: case GRUB_ACPI_OPCODE_CREATE_BYTE_FIELD: { ptr += 5; ptr += add = skip_data_ref_object (ptr, end); if (!add) return -1; ptr += 4; break; } case GRUB_ACPI_OPCODE_NAME: ptr++; if (memcmp (ptr, "_S5_", 4) == 0 || memcmp (ptr, "\\_S5_", 4) == 0) { int ll; grub_uint8_t *ptr2 = ptr; grub_dprintf ("acpi", "S5 found\n"); ptr2 += skip_name_string (ptr, end); if (*ptr2 != 0x12) { grub_printf ("Unknown opcode in _S5: 0x%x\n", *ptr2); return -1; } ptr2++; decode_length (ptr2, &ll); ptr2 += ll; ptr2++; switch (*ptr2) { case GRUB_ACPI_OPCODE_ZERO: sleep_type = 0; break; case GRUB_ACPI_OPCODE_ONE: sleep_type = 1; break; case GRUB_ACPI_OPCODE_BYTE_CONST: sleep_type = ptr2[1]; break; default: grub_printf ("Unknown data type in _S5: 0x%x\n", *ptr2); return -1; } } ptr += add = skip_name_string (ptr, end); if (!add) return -1; ptr += add = skip_data_ref_object (ptr, end); if (!add) return -1; break; case GRUB_ACPI_OPCODE_SCOPE: case GRUB_ACPI_OPCODE_IF: case GRUB_ACPI_OPCODE_METHOD: { ptr++; ptr += decode_length (ptr, 0); break; } default: grub_printf ("Unknown opcode 0x%x\n", *ptr); return -1; } } grub_dprintf ("acpi", "TYP = %d\n", sleep_type); return sleep_type; }
static int 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 *prev = table; if (!ptr) ptr = table + sizeof (struct grub_acpi_table_header); while (ptr < end && prev < ptr) { int add; prev = ptr; grub_dprintf ("acpi", "Opcode 0x%x\n", *ptr); grub_dprintf ("acpi", "Tell %x\n", (unsigned) (ptr - table)); switch (*ptr) { case GRUB_ACPI_OPCODE_EXTOP: ptr++; ptr += add = skip_ext_op (ptr, end); if (!add) return -1; break; case GRUB_ACPI_OPCODE_CREATE_WORD_FIELD: case GRUB_ACPI_OPCODE_CREATE_BYTE_FIELD: { ptr += 5; ptr += add = skip_data_ref_object (ptr, end); if (!add) return -1; ptr += 4; break; } case GRUB_ACPI_OPCODE_NAME: ptr++; if ((!scope || grub_memcmp (scope, "\\", scope_len) == 0) && (grub_memcmp (ptr, "_S5_", 4) == 0 || grub_memcmp (ptr, "\\_S5_", 4) == 0)) { int ll; grub_uint8_t *ptr2 = ptr; grub_dprintf ("acpi", "S5 found\n"); ptr2 += skip_name_string (ptr, end); if (*ptr2 != 0x12) { grub_printf ("Unknown opcode in _S5: 0x%x\n", *ptr2); return -1; } ptr2++; decode_length (ptr2, &ll); ptr2 += ll; ptr2++; switch (*ptr2) { case GRUB_ACPI_OPCODE_ZERO: return 0; case GRUB_ACPI_OPCODE_ONE: return 1; case GRUB_ACPI_OPCODE_BYTE_CONST: return ptr2[1]; default: grub_printf ("Unknown data type in _S5: 0x%x\n", *ptr2); return -1; } } ptr += add = skip_name_string (ptr, end); if (!add) return -1; ptr += add = skip_data_ref_object (ptr, end); if (!add) 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: { ptr++; ptr += decode_length (ptr, 0); break; } default: grub_printf ("Unknown opcode 0x%x\n", *ptr); return -1; } } return -2; }