#include #include #include #include #include #include "opcode.h" #include "value.h" #include "object.h" #include "parser.h" #include "../table.h" #define BYTECODE(opcode, parser, name) \ { opcode, 0, parser, name } #define EXT_BYTECODE(opcode, parser, name) \ { AML_EXT_OP, opcode, parser, name } static int32_t read_pkg_length(struct aml_parser *parser) { int32_t p0 = aml_parser_advance(parser); if (p0 == PARSE_EOF) { return PARSE_EOF; } int32_t len = 0; int32_t p1 = 0, p2 = 0, p3 = 0; int nbytes = (p0 & 0xC0) >> 6; switch (nbytes) { case 3: p1 = aml_parser_advance(parser); p2 = aml_parser_advance(parser); p3 = aml_parser_advance(parser); if (p3 == PARSE_EOF) { return PARSE_EOF; } len = p0 & 0x0F; len |= p1 << 4; len |= p2 << 12; len |= p3 << 20; break; case 2: p1 = aml_parser_advance(parser); p2 = aml_parser_advance(parser); if (p2 == PARSE_EOF) { return PARSE_EOF; } len = p0 & 0x0F; len |= p1 << 4; len |= p2 << 12; break; case 1: p1 = aml_parser_advance(parser); if (p1 == PARSE_EOF) { return PARSE_EOF; } len = p0 & 0x0F; len |= p1 << 4; break; case 0: len = p0 & 0x3F; break; default: return -1; } return len; } static enum parse_status read_single_segment_name(struct aml_parser *parser, char name[ACPI_OBJECT_NAME_MAX]) { name[0] = 0; for (int i = 0; i < 4; i++) { int c = aml_parser_advance(parser); if (c < 0) { return c; } if (c == 0) { break; } if (c == AML_ROOT_CHAR) { c = '\\'; } if (!isalnum(c) && c != '_' && c != '\\') { return PARSE_BADSTRING; } name[i] = c; name[i + 1] = '\0'; } return PARSE_OK; } static enum parse_status read_name(struct aml_parser *parser, char **out) { int prefix = aml_parser_peek(parser); if (prefix < 0) { return PARSE_EOF; } int nsegments = 1; int root = 0; if (prefix == AML_ROOT_CHAR) { root = 1; aml_parser_advance(parser); prefix = aml_parser_peek(parser); } if (prefix == AML_DUAL_NAME_PREFIX) { aml_parser_advance(parser); nsegments = 2; } else if (prefix == AML_MULTI_NAME_PREFIX) { aml_parser_advance(parser); nsegments = aml_parser_advance(parser); } /* each segment is 4 characters long, with a dot separator between each segment */ size_t name_len = nsegments * 4 + (nsegments - 1) + 1; char *name = malloc(name_len + 1); if (!name) { return PARSE_NOMEM; } size_t offset = 0; if (root) { name[offset++] = '\\'; name[offset] = '\0'; } for (int seg = 0; seg < nsegments; seg++) { for (int i = 0; i < 4; i++) { int c = aml_parser_advance(parser); if (c < 0) { return c; } if (c == 0) { break; } if (c == AML_ROOT_CHAR) { c = '\\'; } if (c == AML_PARENT_PREFIX_CHAR) { c = '^'; } if (!isalnum(c) && c != '_' && c != '\\' && c != '^') { return PARSE_BADSTRING; } name[offset++] = c; name[offset] = '\0'; } if (seg < nsegments - 1) { name[offset++] = '.'; name[offset] = '\0'; } } *out = name; return PARSE_OK; } static enum parse_status parse_zero(struct aml_parser *parser, struct aml_value *out) { int opcode = aml_parser_advance(parser); out->type = AML_VALUE_UINT8; out->value.uint8 = 0; return PARSE_OK; } static enum parse_status parse_one(struct aml_parser *parser, struct aml_value *out) { int opcode = aml_parser_advance(parser); out->type = AML_VALUE_UINT8; out->value.uint8 = 1; return PARSE_OK; } static enum parse_status parse_byte_prefix(struct aml_parser *parser, struct aml_value *out) { int opcode = aml_parser_advance(parser); int a = aml_parser_advance(parser); if (a == PARSE_EOF) { return PARSE_EOF; } out->type = AML_VALUE_UINT8; out->value.uint8 = a; return PARSE_OK; } static enum parse_status parse_word_prefix(struct aml_parser *parser, struct aml_value *out) { int opcode = aml_parser_advance(parser); int a = aml_parser_advance(parser); int b = aml_parser_advance(parser); if (a == PARSE_EOF || b == PARSE_EOF) { return PARSE_EOF; } out->type = AML_VALUE_UINT16; out->value.uint16 = a | (b << 8); return PARSE_OK; } static enum parse_status parse_dword_prefix(struct aml_parser *parser, struct aml_value *out) { int opcode = aml_parser_advance(parser); int a = aml_parser_advance(parser); int b = aml_parser_advance(parser); int c = aml_parser_advance(parser); int d = aml_parser_advance(parser); if (a == PARSE_EOF || b == PARSE_EOF || c == PARSE_EOF || d == PARSE_EOF) { return PARSE_EOF; } out->type = AML_VALUE_UINT32; out->value.uint16 = a | (b << 8) | (c << 16) | (d << 24); return PARSE_OK; } static enum parse_status parse_region(struct aml_parser *parser, struct aml_value *out) { return PARSE_OK; } static enum parse_status parse_qword_prefix(struct aml_parser *parser, struct aml_value *out) { int opcode = aml_parser_advance(parser); int64_t a = aml_parser_advance(parser); int64_t b = aml_parser_advance(parser); int64_t c = aml_parser_advance(parser); int64_t d = aml_parser_advance(parser); int64_t e = aml_parser_advance(parser); int64_t f = aml_parser_advance(parser); int64_t g = aml_parser_advance(parser); int64_t h = aml_parser_advance(parser); if (a == PARSE_EOF || b == PARSE_EOF || c == PARSE_EOF || d == PARSE_EOF) { return PARSE_EOF; } if (e == PARSE_EOF || f == PARSE_EOF || g == PARSE_EOF || h == PARSE_EOF) { return PARSE_EOF; } out->type = AML_VALUE_UINT64; out->value.uint16 = a | (b << 8) | (c << 16) | (d << 24) | (e << 32) | (f << 40) | (g << 48) | (h << 56); return PARSE_OK; } static enum parse_status parse_string_prefix(struct aml_parser *parser, struct aml_value *out) { int opcode = aml_parser_advance(parser); aml_parser_save_cursor(parser); unsigned int len = 0; while (1) { int c = aml_parser_advance(parser); if (c == 0) { break; } if (c == PARSE_EOF) { return PARSE_EOF; } len++; } aml_parser_load_cursor(parser); char *buf = malloc(len + 1); if (!buf) { return PARSE_NOMEM; } for (unsigned int i = 0; i < len; i++) { int c = aml_parser_advance(parser); if (c == 0) { break; } if (c == PARSE_EOF) { return PARSE_EOF; } buf[i] = c; } buf[len] = '\0'; out->type = AML_VALUE_STRING; out->value.str = buf; return PARSE_OK; } static enum parse_status parse_scope(struct aml_parser *parser, struct aml_value *out) { int opcode = aml_parser_advance(parser); unsigned int scope_start = aml_parser_cursorpos(parser); int32_t scope_size = read_pkg_length(parser); if (scope_size < 0) { return scope_size; } unsigned int scope_end = scope_start + scope_size; char *scope_name; enum parse_status status = read_name(parser, &scope_name); if (status != PARSE_OK) { return status; } struct acpi_object *scope = aml_parser_resolve_path(parser, scope_name); if (!scope) { scope = acpi_object_create(NULL, ACPI_OBJECT_NAMESPACE); scope->publish_path = scope_name; } scope->scope_end = scope_end; out->type = AML_VALUE_OBJECT; out->value.object = scope; return PARSE_OK; } static enum parse_status parse_op_region(struct aml_parser *parser, struct aml_value *out) { aml_parser_advance(parser); aml_parser_advance(parser); char *name; enum parse_status status = read_name(parser, &name); if (status != PARSE_OK) { return status; } int region_space = aml_parser_advance(parser); if (region_space < 0) { free(name); return region_space; } struct aml_value region_offset; status = parse_opcode(parser, ®ion_offset); if (status != PARSE_OK) { free(name); return status; } if (aml_value_is_name(®ion_offset)) { /* TODO */ } else if (aml_value_is_integer(®ion_offset)) { /* TODO */ } else { free(name); return PARSE_BADTYPE; } struct aml_value region_len; status = parse_opcode(parser, ®ion_len); if (status != PARSE_OK) { free(name); return status; } if (aml_value_is_name(®ion_len)) { /* TODO */ } else if (aml_value_is_integer(®ion_len)) { /* TODO */ } else { free(name); return PARSE_BADTYPE; } struct acpi_object *op_region = acpi_object_create(NULL, ACPI_OBJECT_OPERATION_REGION); op_region->publish_path = name; out->type = AML_VALUE_OBJECT; out->value.object = op_region; return PARSE_OK; } static enum parse_status parse_named_field(struct aml_parser *parser, struct acpi_object *region) { char unit_name[ACPI_OBJECT_NAME_MAX]; enum parse_status status = read_single_segment_name(parser, unit_name); if (status != PARSE_OK) { return status; } int bits = read_pkg_length(parser); if (bits < 0) { return PARSE_EOF; } struct acpi_object *field = acpi_object_create(unit_name, ACPI_OBJECT_FIELD); //field_unit->field_unit.size = bits / 8; acpi_object_add_child(region, field); return PARSE_OK; } static enum parse_status parse_reserved_field(struct aml_parser *parser, struct acpi_object *region) { int c = aml_parser_advance(parser); if (c < 0) { return PARSE_EOF; } int bits = read_pkg_length(parser); if (bits < 0) { return PARSE_EOF; } struct acpi_object *field = acpi_object_create(NULL, ACPI_OBJECT_FIELD); //field_unit->field_unit.size = bits / 8; acpi_object_add_child(region, field); return PARSE_OK; } static enum parse_status parse_access_field(struct aml_parser *parser, struct acpi_object *region) { int c = aml_parser_advance(parser); if (c < 0) { return PARSE_EOF; } int access_type = aml_parser_advance(parser); if (access_type < 0) { return PARSE_EOF; } int access_attrib = aml_parser_advance(parser); if (access_attrib < 0) { return PARSE_EOF; } struct acpi_object *field = acpi_object_create(NULL, ACPI_OBJECT_FIELD); //field_unit->field_unit.size = bits / 8; acpi_object_add_child(region, field); return PARSE_OK; } static enum parse_status parse_extended_access_field(struct aml_parser *parser, struct acpi_object *region) { int c = aml_parser_advance(parser); if (c < 0) { return PARSE_EOF; } int access_type = aml_parser_advance(parser); if (access_type < 0) { return PARSE_EOF; } int ext_access_attrib = aml_parser_advance(parser); if (ext_access_attrib < 0) { return PARSE_EOF; } int access_length = aml_parser_advance(parser); if (access_length < 0) { return PARSE_EOF; } struct acpi_object *field = acpi_object_create(NULL, ACPI_OBJECT_FIELD); //field_unit->field_unit.size = bits / 8; acpi_object_add_child(region, field); return PARSE_OK; } static enum parse_status parse_connect_field(struct aml_parser *parser, struct acpi_object *region) { return PARSE_UNKNOWNOP; } static enum parse_status parse_field(struct aml_parser *parser, struct aml_value *out) { aml_parser_advance(parser); aml_parser_advance(parser); long start = aml_parser_cursorpos(parser); long len = read_pkg_length(parser); if (len < 0) { return PARSE_EOF; } char *name; enum parse_status status = read_name(parser, &name); if (status != PARSE_OK) { return status; } int flags = aml_parser_advance(parser); if (flags < 0) { free(name); return PARSE_EOF; } struct acpi_object *region = aml_parser_resolve_path(parser, name); if (!region) { return PARSE_BADREF; } free(name); long end = start + len; while (aml_parser_cursorpos(parser) < end) { int c = aml_parser_peek(parser); if (isalpha(c)) { /* Named field */ status = parse_named_field(parser, region); } else if (c == 0x00) { /* Reserved field */ status = parse_reserved_field(parser, region); } else if (c == 0x01) { /* Access field */ status = parse_access_field(parser, region); } else if (c == 0x03) { /* Extended access field */ status = parse_extended_access_field(parser, region); } else if (c == 0x02) { /* Connect field */ status = parse_connect_field(parser, region); } else if (c < 0) { return PARSE_EOF; } else { return PARSE_UNKNOWNOP; } } out->type = AML_VALUE_NONE; return PARSE_OK; } static enum parse_status parse_index_field(struct aml_parser *parser, struct aml_value *out) { aml_parser_advance(parser); aml_parser_advance(parser); long start = aml_parser_cursorpos(parser); long len = read_pkg_length(parser); if (len < 0) { return PARSE_EOF; } char *index_name; enum parse_status status = read_name(parser, &index_name); if (status != PARSE_OK) { return status; } char *data_name; status = read_name(parser, &data_name); if (status != PARSE_OK) { free(index_name); return status; } int flags = aml_parser_advance(parser); if (flags < 0) { free(index_name); free(data_name); return PARSE_EOF; } free(index_name); free(data_name); #if 0 struct acpi_object *region = aml_parser_resolve_path(parser, index_name); if (!region) { return PARSE_BADREF; } #endif long end = start + len; while (aml_parser_cursorpos(parser) < end) { int c = aml_parser_advance(parser); #if 0 if (isalpha(c)) { /* Named field */ status = parse_named_field(parser, region); } else if (c == 0x00) { /* Reserved field */ status = parse_reserved_field(parser, region); } else if (c == 0x01) { /* Access field */ status = parse_access_field(parser, region); } else if (c == 0x03) { /* Extended access field */ status = parse_extended_access_field(parser, region); } else if (c == 0x02) { /* Connect field */ status = parse_connect_field(parser, region); } else if (c < 0) { return PARSE_EOF; } else { return PARSE_UNKNOWNOP; } #endif } out->type = AML_VALUE_NONE; return PARSE_OK; } static enum parse_status parse_device(struct aml_parser *parser, struct aml_value *out) { aml_parser_advance(parser); aml_parser_advance(parser); long start = aml_parser_cursorpos(parser); long len = read_pkg_length(parser); if (len < 0) { return PARSE_EOF; } char *name; enum parse_status status = read_name(parser, &name); if (status != PARSE_OK) { return status; } struct acpi_object *device = acpi_object_create(NULL, ACPI_OBJECT_DEVICE); device->publish_path = name; device->scope_end = start + len; out->type = AML_VALUE_OBJECT; out->value.object = device; return PARSE_OK; } static enum parse_status parse_name(struct aml_parser *parser, struct aml_value *out) { aml_parser_advance(parser); char *name; enum parse_status status = read_name(parser, &name); if (status != PARSE_OK) { return status; } struct aml_value named_value; status = parse_opcode(parser, &named_value); if (status != PARSE_OK) { return status; } struct acpi_object *object = NULL; if (named_value.type == AML_VALUE_OBJECT) { object = named_value.value.object; } else { object = acpi_object_create(NULL, ACPI_OBJECT_VALUE); // TODO set value. } object->publish_path = name; out->type = AML_VALUE_OBJECT; out->value.object = object; return PARSE_OK; } static enum parse_status parse_package(struct aml_parser *parser, struct aml_value *out) { aml_parser_advance(parser); long start = aml_parser_cursorpos(parser); long len = read_pkg_length(parser); if (len < 0) { return PARSE_EOF; } int nitems = aml_parser_advance(parser); if (nitems < 0) { return PARSE_EOF; } struct acpi_object *pkg = acpi_object_create(NULL, ACPI_OBJECT_PACKAGE); for (int i = 0; i < nitems; i++) { struct aml_value pkg_item; enum parse_status status = parse_opcode(parser, &pkg_item); if (status != PARSE_OK) { acpi_object_deref(pkg); return status; } // TODO add value to package } while (aml_parser_cursorpos(parser) < start + len) { aml_parser_advance(parser); } out->type = AML_VALUE_OBJECT; out->value.object = pkg; return PARSE_OK; } static enum parse_status parse_name_chars(struct aml_parser *parser, struct aml_value *out) { char *name; enum parse_status status = read_name(parser, &name); if (status != PARSE_OK) { return status; } out->type = AML_VALUE_NAME; out->value.name = name; return PARSE_OK; } static enum parse_status parse_buffer(struct aml_parser *parser, struct aml_value *out) { aml_parser_advance(parser); long start = aml_parser_cursorpos(parser); long pkg_len = read_pkg_length(parser); if (pkg_len < 0) { return PARSE_EOF; } struct aml_value buffer_size; enum parse_status status = parse_opcode(parser, &buffer_size); if (status != PARSE_OK) { return status; } if (!aml_value_is_integer(&buffer_size)) { return PARSE_BADTYPE; } uint64_t nbytes = aml_value_get_integer(&buffer_size); long end = start + pkg_len; while (aml_parser_cursorpos(parser) < end) { //for (uint64_t i = 0; i < nbytes; i++) { int b = aml_parser_advance(parser); if (b < 0) { return PARSE_EOF; } } struct acpi_object *buffer = acpi_object_create(NULL, ACPI_OBJECT_BUFFER); out->type = AML_VALUE_OBJECT; out->value.object = buffer; return PARSE_OK; } static enum parse_status parse_method(struct aml_parser *parser, struct aml_value *out) { aml_parser_advance(parser); long start = aml_parser_cursorpos(parser); long pkg_len = read_pkg_length(parser); if (pkg_len < 0) { return PARSE_EOF; } char *name; enum parse_status status = read_name(parser, &name); if (status != PARSE_OK) { return status; } int flags = aml_parser_advance(parser); if (flags < 0) { return PARSE_EOF; } long end = start + pkg_len; while (aml_parser_cursorpos(parser) < end) { int b = aml_parser_advance(parser); if (b < 0) { return PARSE_EOF; } } struct acpi_object *method = acpi_object_create(NULL, ACPI_OBJECT_METHOD); method->publish_path = name; out->type = AML_VALUE_OBJECT; out->value.object = method; return PARSE_OK; } static enum parse_status parse_ones(struct aml_parser *parser, struct aml_value *out) { aml_parser_advance(parser); if (parser->revision == 0x02) { out->type = AML_VALUE_UINT64; out->value.uint64 = 0xFFFFFFFFFFFFFFFF; } else { out->type = AML_VALUE_UINT32; out->value.uint32 = 0xFFFFFFFF; } return PARSE_OK; } static enum parse_status parse_processor(struct aml_parser *parser, struct aml_value *out) { aml_parser_advance(parser); aml_parser_advance(parser); long start = aml_parser_cursorpos(parser); long pkg_len = read_pkg_length(parser); if (pkg_len < 0) { return PARSE_EOF; } char *name; enum parse_status status = read_name(parser, &name); if (status != PARSE_OK) { return status; } int proc_id = aml_parser_advance(parser); if (proc_id < 0) { return PARSE_EOF; } int a = aml_parser_advance(parser); int b = aml_parser_advance(parser); int c = aml_parser_advance(parser); int d = aml_parser_advance(parser); if (d < 0) { return PARSE_EOF; } int pblk_len = aml_parser_advance(parser); if (pblk_len < 0) { return PARSE_EOF; } struct acpi_object *processor = acpi_object_create(NULL, ACPI_OBJECT_PROCESSOR); processor->publish_path = name; processor->scope_end = start + pkg_len; out->type = AML_VALUE_OBJECT; out->value.object = processor; return PARSE_OK; } static enum parse_status parse_alias(struct aml_parser *parser, struct aml_value *out) { aml_parser_advance(parser); char *target_path, *alias_path; enum parse_status status = read_name(parser, &target_path); if (status != PARSE_OK) { return status; } status = read_name(parser, &alias_path); if (status != PARSE_OK) { return status; } struct acpi_object *alias = acpi_object_create(NULL, ACPI_OBJECT_ALIAS); alias->publish_path = alias_path; free(target_path); out->type = AML_VALUE_OBJECT; out->value.object = alias; return PARSE_OK; } static enum parse_status parse_mutex(struct aml_parser *parser, struct aml_value *out) { aml_parser_advance(parser); aml_parser_advance(parser); char *name; enum parse_status status = read_name(parser, &name); if (status != PARSE_OK) { return status; } int sync_flags = aml_parser_advance(parser); if (sync_flags < 0) { free(name); return PARSE_EOF; } struct acpi_object *mutex = acpi_object_create(NULL, ACPI_OBJECT_MUTEX); mutex->publish_path = name; out->type = AML_VALUE_OBJECT; out->value.object = mutex; return PARSE_OK; } static enum parse_status parse_create_byte_field(struct aml_parser *parser, struct aml_value *out) { aml_parser_advance(parser); char *buffer_path; enum parse_status status = read_name(parser, &buffer_path); if (status != PARSE_OK) { return status; } struct aml_value byte_index; status = parse_opcode(parser, &byte_index); if (status != PARSE_OK) { return status; } char *field_name; status = read_name(parser, &field_name); if (status != PARSE_OK) { return status; } struct acpi_object *field = acpi_object_create(NULL, ACPI_OBJECT_FIELD); field->publish_path = field_name; /* TODO */ free(buffer_path); out->type = AML_VALUE_OBJECT; out->value.object = field; return PARSE_OK; } static enum parse_status parse_create_word_field(struct aml_parser *parser, struct aml_value *out) { aml_parser_advance(parser); char *buffer_path; enum parse_status status = read_name(parser, &buffer_path); if (status != PARSE_OK) { return status; } struct aml_value byte_index; status = parse_opcode(parser, &byte_index); if (status != PARSE_OK) { return status; } char *field_name; status = read_name(parser, &field_name); if (status != PARSE_OK) { return status; } struct acpi_object *field = acpi_object_create(NULL, ACPI_OBJECT_FIELD); field->publish_path = field_name; /* TODO */ free(buffer_path); out->type = AML_VALUE_OBJECT; out->value.object = field; return PARSE_OK; } static enum parse_status parse_event(struct aml_parser *parser, struct aml_value *out) { aml_parser_advance(parser); aml_parser_advance(parser); char *name; enum parse_status status = read_name(parser, &name); if (status != PARSE_OK) { return status; } struct acpi_object *event = acpi_object_create(NULL, ACPI_OBJECT_EVENT); event->publish_path = name; out->type = AML_VALUE_OBJECT; out->value.object = event; return PARSE_OK; } struct aml_byte_encoding byte_encoding[] = { BYTECODE(AML_ZERO_OP, parse_zero, "ZeroOp"), BYTECODE(AML_ONE_OP, parse_one, "OneOp"), BYTECODE(AML_ALIAS_OP, parse_alias, "AliasOp"), BYTECODE(AML_NAME_OP, parse_name, "NameOp"), BYTECODE(AML_BYTE_PREFIX, parse_byte_prefix, "BytePrefix"), BYTECODE(AML_WORD_PREFIX, parse_word_prefix, "WordPrefix"), BYTECODE(AML_DWORD_PREFIX, parse_dword_prefix, "DWordPrefix"), BYTECODE(AML_STRING_PREFIX, parse_string_prefix, "StringPrefix"), BYTECODE(AML_QWORD_PREFIX, parse_qword_prefix, "QWordPrefix"), BYTECODE(AML_SCOPE_OP, parse_scope, "ScopeOp"), BYTECODE(AML_BUFFER_OP, parse_buffer, "BufferOp"), BYTECODE(AML_PACKAGE_OP, parse_package, "PackageOp"), BYTECODE(AML_VAR_PACKAGE_OP, NULL, "VarPackageOp"), BYTECODE(AML_METHOD_OP, parse_method, "MethodOp"), BYTECODE(AML_DUAL_NAME_PREFIX, NULL, "DualNamePrefix"), BYTECODE(AML_MULTI_NAME_PREFIX, NULL, "MultiNamePrefix"), BYTECODE('0', parse_name_chars, "DigitChar"), BYTECODE('1', parse_name_chars, "DigitChar"), BYTECODE('2', parse_name_chars, "DigitChar"), BYTECODE('3', parse_name_chars, "DigitChar"), BYTECODE('4', parse_name_chars, "DigitChar"), BYTECODE('5', parse_name_chars, "DigitChar"), BYTECODE('6', parse_name_chars, "DigitChar"), BYTECODE('7', parse_name_chars, "DigitChar"), BYTECODE('8', parse_name_chars, "DigitChar"), BYTECODE('9', parse_name_chars, "DigitChar"), BYTECODE('A', parse_name_chars, "NameChar"), BYTECODE('B', parse_name_chars, "NameChar"), BYTECODE('C', parse_name_chars, "NameChar"), BYTECODE('D', parse_name_chars, "NameChar"), BYTECODE('E', parse_name_chars, "NameChar"), BYTECODE('F', parse_name_chars, "NameChar"), BYTECODE('G', parse_name_chars, "NameChar"), BYTECODE('H', parse_name_chars, "NameChar"), BYTECODE('I', parse_name_chars, "NameChar"), BYTECODE('J', parse_name_chars, "NameChar"), BYTECODE('K', parse_name_chars, "NameChar"), BYTECODE('L', parse_name_chars, "NameChar"), BYTECODE('M', parse_name_chars, "NameChar"), BYTECODE('N', parse_name_chars, "NameChar"), BYTECODE('O', parse_name_chars, "NameChar"), BYTECODE('P', parse_name_chars, "NameChar"), BYTECODE('Q', parse_name_chars, "NameChar"), BYTECODE('R', parse_name_chars, "NameChar"), BYTECODE('S', parse_name_chars, "NameChar"), BYTECODE('T', parse_name_chars, "NameChar"), BYTECODE('U', parse_name_chars, "NameChar"), BYTECODE('V', parse_name_chars, "NameChar"), BYTECODE('W', parse_name_chars, "NameChar"), BYTECODE('X', parse_name_chars, "NameChar"), BYTECODE('Y', parse_name_chars, "NameChar"), BYTECODE('Z', parse_name_chars, "NameChar"), EXT_BYTECODE(AML_EXT_MUTEX_OP, parse_mutex, "MutexOp"), EXT_BYTECODE(AML_EXT_EVENT_OP, parse_event, "EventOp"), EXT_BYTECODE(AML_EXT_COND_REF_OF_OP, NULL, "CondRefOfOp"), EXT_BYTECODE(AML_EXT_CREATE_FIELD_OP, NULL, "CreateFieldOp"), EXT_BYTECODE(AML_EXT_LOAD_TABLE_OP, NULL, "LoadTableOp"), EXT_BYTECODE(AML_EXT_LOAD_OP, NULL, "LoadOp"), EXT_BYTECODE(AML_EXT_STALL_OP, NULL, "StallOp"), EXT_BYTECODE(AML_EXT_SLEEP_OP, NULL, "SleepOp"), EXT_BYTECODE(AML_EXT_ACQUIRE_OP, NULL, "AcquireOp"), EXT_BYTECODE(AML_EXT_SIGNAL_OP, NULL, "SignalOp"), EXT_BYTECODE(AML_EXT_WAIT_OP, NULL, "WaitOp"), EXT_BYTECODE(AML_EXT_RESET_OP, NULL, "ResetOp"), EXT_BYTECODE(AML_EXT_RELEASE_OP, NULL, "ReleaseOp"), EXT_BYTECODE(AML_EXT_FROM_BCD_OP, NULL, "FromBCDOp"), EXT_BYTECODE(AML_EXT_TO_BCD_OP, NULL, "ToBCDOp"), EXT_BYTECODE(AML_EXT_UNLOAD_OP, NULL, "UnloadOp"), EXT_BYTECODE(AML_EXT_REVISION_OP, NULL, "RevisionOp"), EXT_BYTECODE(AML_EXT_DEBUG_OP, NULL, "DebugOp"), EXT_BYTECODE(AML_EXT_FATAL_OP, NULL, "FatalOp"), EXT_BYTECODE(AML_EXT_TIMER_OP, NULL, "TimerOp"), EXT_BYTECODE(AML_EXT_REGION_OP, parse_op_region, "OpRegionOp"), EXT_BYTECODE(AML_EXT_FIELD_OP, parse_field, "FieldOp"), EXT_BYTECODE(AML_EXT_DEVICE_OP, parse_device, "DeviceOp"), EXT_BYTECODE(AML_EXT_PROCESSOR_OP, parse_processor, "ProcessorOp"), EXT_BYTECODE(AML_EXT_POWER_RES_OP, NULL, "PowerResOp"), EXT_BYTECODE(AML_EXT_THERMAL_ZONE_OP, NULL, "ThermalZoneOp"), EXT_BYTECODE(AML_EXT_INDEX_FIELD_OP, parse_index_field, "IndexFieldOp"), EXT_BYTECODE(AML_EXT_BANK_FIELD_OP, NULL, "BankFieldOp"), EXT_BYTECODE(AML_EXT_DATA_REGION_OP, NULL, "DataRegionOp"), BYTECODE(AML_ROOT_CHAR, NULL, "RootChar"), BYTECODE(AML_PARENT_PREFIX_CHAR, NULL, "ParentPrefixChar"), BYTECODE('_', NULL, "NameChar"), BYTECODE(AML_LOCAL0, NULL, "Local0Op"), BYTECODE(AML_LOCAL1, NULL, "Local1Op"), BYTECODE(AML_LOCAL2, NULL, "Local2Op"), BYTECODE(AML_LOCAL3, NULL, "Local3Op"), BYTECODE(AML_LOCAL4, NULL, "Local4Op"), BYTECODE(AML_LOCAL5, NULL, "Local5Op"), BYTECODE(AML_LOCAL6, NULL, "Local6Op"), BYTECODE(AML_LOCAL7, NULL, "Local7Op"), BYTECODE(AML_ARG0, NULL, "Arg0Op"), BYTECODE(AML_ARG1, NULL, "Arg1Op"), BYTECODE(AML_ARG2, NULL, "Arg2Op"), BYTECODE(AML_ARG3, NULL, "Arg3Op"), BYTECODE(AML_ARG4, NULL, "Arg4Op"), BYTECODE(AML_ARG5, NULL, "Arg5Op"), BYTECODE(AML_ARG6, NULL, "Arg6Op"), BYTECODE(AML_STORE_OP, NULL, "StoreOp"), BYTECODE(AML_REF_OF_OP, NULL, "RefOfOp"), BYTECODE(AML_ADD_OP, NULL, "AddOp"), BYTECODE(AML_CONCAT_OP, NULL, "ConcatOp"), BYTECODE(AML_SUBTRACT_OP, NULL, "SubtractOp"), BYTECODE(AML_INCREMENT_OP, NULL, "IncrementOp"), BYTECODE(AML_DECREMENT_OP, NULL, "DecrementOp"), BYTECODE(AML_MULTIPLY_OP, NULL, "MultiplyOp"), BYTECODE(AML_DIVIDE_OP, NULL, "DivideOp"), BYTECODE(AML_SHIFT_LEFT_OP, NULL, "ShiftLeftOp"), BYTECODE(AML_SHIFT_RIGHT_OP, NULL, "ShiftRightOp"), BYTECODE(AML_AND_OP, NULL, "AndOp"), BYTECODE(AML_NAND_OP, NULL, "NAndOp"), BYTECODE(AML_OR_OP, NULL, "OrOp"), BYTECODE(AML_NOR_OP, NULL, "NorOp"), BYTECODE(AML_XOR_OP, NULL, "XOrOp"), BYTECODE(AML_NOT_OP, NULL, "NotOp"), BYTECODE(AML_FIND_SET_LEFT_BIT_OP, NULL, "FindSetLeftBitOp"), BYTECODE(AML_FIND_SET_RIGHT_BIT_OP, NULL, "FindSetRightBitOp"), BYTECODE(AML_DEREF_OF_OP, NULL, "DerefOfOp"), BYTECODE(AML_CONCAT_RES_OP, NULL, "ConcatResOp"), BYTECODE(AML_MOD_OP, NULL, "ModOp"), BYTECODE(AML_NOTIFY_OP, NULL, "NotifyOp"), BYTECODE(AML_SIZE_OF_OP, NULL, "SizeOfOp"), BYTECODE(AML_INDEX_OP, NULL, "IndexOp"), BYTECODE(AML_MATCH_OP, NULL, "MatchOp"), BYTECODE(AML_CREATE_DWORD_FIELD_OP, NULL, "CreateDWordFieldOp"), BYTECODE(AML_CREATE_WORD_FIELD_OP, parse_create_word_field, "CreateWordFieldOp"), BYTECODE(AML_CREATE_BYTE_FIELD_OP, parse_create_byte_field, "CreateByteFieldOp"), BYTECODE(AML_CREATE_BIT_FIELD_OP, NULL, "CreateBitFieldOp"), BYTECODE(AML_OBJECT_TYPE_OP, NULL, "ObjectTypeOp"), BYTECODE(AML_CREATE_QWORD_FIELD_OP, NULL, "CreateQWordFieldOp"), BYTECODE(AML_LAND_OP, NULL, "LAndOp"), BYTECODE(AML_LOR_OP, NULL, "LOrOp"), BYTECODE(AML_LNOT_OP, NULL, "LNotOp"), BYTECODE(AML_LEQUAL_OP, NULL, "LEqualOp"), BYTECODE(AML_LGREATER_OP, NULL, "LGreaterOp"), BYTECODE(AML_LLESS_OP, NULL, "LLessOp"), BYTECODE(AML_TO_BUFFER_OP, NULL, "ToBufferOp"), BYTECODE(AML_TO_DEC_STRING_OP, NULL, "ToDecimalStringOp"), BYTECODE(AML_TO_HEX_STRING_OP, NULL, "ToHexStringOp"), BYTECODE(AML_TO_INTEGER_OP, NULL, "ToIntegerOp"), BYTECODE(AML_TO_STRING_OP, NULL, "ToStringOp"), BYTECODE(AML_COPY_OBJECT_OP, NULL, "CopyObjectOp"), BYTECODE(AML_MID_OP, NULL, "MidOp"), BYTECODE(AML_CONTINUE_OP, NULL, "ContinueOp"), BYTECODE(AML_IF_OP, NULL, "IfOp"), BYTECODE(AML_ELSE_OP, NULL, "ElseOp"), BYTECODE(AML_WHILE_OP, NULL, "WhileOp"), BYTECODE(AML_NOOP_OP, NULL, "NoopOp"), BYTECODE(AML_RETURN_OP, NULL, "ReturnOp"), BYTECODE(AML_BREAK_OP, NULL, "BreakOp"), BYTECODE(AML_BREAK_POINT_OP, NULL, "BreakPointOp"), BYTECODE(AML_ONES_OP, parse_ones, "OnesOp"), }; static unsigned int nr_byte_encoding = sizeof byte_encoding / sizeof(struct aml_byte_encoding); enum parse_status parse_opcode(struct aml_parser *parser, struct aml_value *out) { unsigned int offset = aml_parser_cursorpos(parser); int op0 = aml_parser_peek(parser); int op1 = 0; if (op0 == PARSE_EOF) { return PARSE_EOF; } if (op0 == AML_EXT_OP) { op1 = aml_parser_peek_next(parser); if (op1 == PARSE_EOF) { return PARSE_EOF; } } struct aml_byte_encoding *opcode = NULL; for (unsigned int i = 0; i < nr_byte_encoding; i++) { if (byte_encoding[i].opcode == op0 && byte_encoding[i].sub_opcode == op1) { opcode = &byte_encoding[i]; break; } } if (!opcode) { fprintf(stderr, "unrecognised opcode at 0x%04lx: %02x:%02x\n", offset + sizeof(struct acpi_table), op0, op1); return PARSE_UNKNOWNOP; } if (!opcode->parser) { fprintf(stderr, "unimplemented opcode at 0x%04lx: %02x:%02x (%s)\n", offset + sizeof(struct acpi_table), op0, op1, opcode->name); return PARSE_UNKNOWNOP; } return opcode->parser(parser, out); }