819 lines
25 KiB
C
819 lines
25 KiB
C
|
|
#include <stddef.h>
|
||
|
|
#include <stdio.h>
|
||
|
|
#include <string.h>
|
||
|
|
#include <stdlib.h>
|
||
|
|
#include <ctype.h>
|
||
|
|
#include "opcode.h"
|
||
|
|
#include "value.h"
|
||
|
|
#include "object.h"
|
||
|
|
#include "parser.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 tmp = 0;
|
||
|
|
|
||
|
|
int nbytes = (p0 & 0xC0) >> 6;
|
||
|
|
switch (nbytes) {
|
||
|
|
case 3:
|
||
|
|
tmp = aml_parser_advance(parser);
|
||
|
|
if (tmp == PARSE_EOF) {
|
||
|
|
return PARSE_EOF;
|
||
|
|
}
|
||
|
|
|
||
|
|
len |= tmp << 20;
|
||
|
|
case 2:
|
||
|
|
tmp = aml_parser_advance(parser);
|
||
|
|
if (tmp == PARSE_EOF) {
|
||
|
|
return PARSE_EOF;
|
||
|
|
}
|
||
|
|
|
||
|
|
len |= tmp << 12;
|
||
|
|
case 1:
|
||
|
|
len |= p0 & 0x0F;
|
||
|
|
tmp = aml_parser_advance(parser);
|
||
|
|
if (tmp == PARSE_EOF) {
|
||
|
|
return PARSE_EOF;
|
||
|
|
}
|
||
|
|
|
||
|
|
len |= tmp << 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 (!isalnum(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 - 1] = '\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_integer(®ion_offset)) {
|
||
|
|
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_integer(®ion_len)) {
|
||
|
|
free(name);
|
||
|
|
return PARSE_BADTYPE;
|
||
|
|
}
|
||
|
|
|
||
|
|
struct acpi_object *op_region = acpi_object_create(name, 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_field(struct aml_parser *parser, struct aml_value *out)
|
||
|
|
{
|
||
|
|
long start = aml_parser_cursorpos(parser);
|
||
|
|
|
||
|
|
aml_parser_advance(parser);
|
||
|
|
aml_parser_advance(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);
|
||
|
|
free(name);
|
||
|
|
|
||
|
|
if (!region) {
|
||
|
|
return PARSE_BADREF;
|
||
|
|
}
|
||
|
|
|
||
|
|
long end = start + len;
|
||
|
|
while (aml_parser_cursorpos(parser) < end) {
|
||
|
|
char unit_name[ACPI_OBJECT_NAME_MAX];
|
||
|
|
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);
|
||
|
|
}
|
||
|
|
|
||
|
|
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 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
|
||
|
|
}
|
||
|
|
|
||
|
|
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 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);
|
||
|
|
|
||
|
|
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;
|
||
|
|
}
|
||
|
|
|
||
|
|
struct aml_byte_encoding byte_encoding[] = {
|
||
|
|
BYTECODE(AML_ZERO_OP, parse_zero, "ZeroOp"),
|
||
|
|
BYTECODE(AML_ONE_OP, parse_one, "OneOp"),
|
||
|
|
BYTECODE(AML_ALIAS_OP, NULL, "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, NULL, "MutexOp"),
|
||
|
|
EXT_BYTECODE(AML_EXT_EVENT_OP, NULL, "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, NULL, "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, NULL, "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, NULL, "CreateWordFieldOp"),
|
||
|
|
BYTECODE(AML_CREATE_BYTE_FIELD_OP, NULL, "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, NULL, "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%04x: %02x:%02x\n", offset, op0, op1);
|
||
|
|
return PARSE_UNKNOWNOP;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!opcode->parser) {
|
||
|
|
fprintf(stderr, "unimplemented opcode at 0x%04x: %02x:%02x (%s)\n", offset, op0, op1, opcode->name);
|
||
|
|
return PARSE_UNKNOWNOP;
|
||
|
|
}
|
||
|
|
|
||
|
|
return opcode->parser(parser, out);
|
||
|
|
}
|