tools: add tool to decode AML files and build an ACPI namespace
This commit is contained in:
6
tools/amldecode/aml/constants.h
Normal file
6
tools/amldecode/aml/constants.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef AML_CONSTANTS_H_
|
||||
#define AML_CONSTANTS_H_
|
||||
|
||||
#define ACPI_OBJECT_NAME_MAX 5
|
||||
|
||||
#endif
|
||||
136
tools/amldecode/aml/object.c
Normal file
136
tools/amldecode/aml/object.c
Normal file
@@ -0,0 +1,136 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "object.h"
|
||||
|
||||
struct acpi_namespace *acpi_namespace_create(void)
|
||||
{
|
||||
struct acpi_namespace *ns = malloc(sizeof *ns);
|
||||
if (!ns) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(ns, 0x00, sizeof *ns);
|
||||
|
||||
ns->root = acpi_object_create("\\", ACPI_OBJECT_NAMESPACE);
|
||||
return ns;
|
||||
}
|
||||
|
||||
struct acpi_object *acpi_namespace_get_object(struct acpi_namespace *ns, const char *path)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct acpi_object *acpi_object_create(const char name[ACPI_OBJECT_NAME_MAX], enum acpi_object_type type)
|
||||
{
|
||||
struct acpi_object *object = malloc(sizeof *object);
|
||||
if (!object) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(object, 0x00, sizeof *object);
|
||||
|
||||
object->ref = 1;
|
||||
object->type = type;
|
||||
|
||||
if (name) {
|
||||
strncpy(object->name, name, sizeof object->name - 1);
|
||||
object->name[ACPI_OBJECT_NAME_MAX - 1] = '\0';
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
struct acpi_object *acpi_object_ref(struct acpi_object *object)
|
||||
{
|
||||
object->ref++;
|
||||
return object;
|
||||
}
|
||||
|
||||
void acpi_object_deref(struct acpi_object *object)
|
||||
{
|
||||
if (object->ref > 1) {
|
||||
object->ref--;
|
||||
return;
|
||||
}
|
||||
|
||||
object->ref = 0;
|
||||
free(object);
|
||||
}
|
||||
|
||||
void acpi_object_add_child(struct acpi_object *parent, struct acpi_object *child)
|
||||
{
|
||||
if (child->parent) {
|
||||
return;
|
||||
}
|
||||
|
||||
child->parent = parent;
|
||||
if (!parent->first_child) {
|
||||
parent->first_child = acpi_object_ref(child);
|
||||
return;
|
||||
}
|
||||
|
||||
struct acpi_object *cur = parent->first_child;
|
||||
while (cur->next_sibling) {
|
||||
cur = cur->next_sibling;
|
||||
}
|
||||
|
||||
cur->next_sibling = acpi_object_ref(child);
|
||||
}
|
||||
|
||||
struct acpi_object *acpi_object_get_child(struct acpi_object *object, const char *name)
|
||||
{
|
||||
struct acpi_object *cur = object->first_child;
|
||||
while (cur) {
|
||||
if (!strcmp(cur->name, name)) {
|
||||
return acpi_object_ref(cur);
|
||||
}
|
||||
|
||||
cur = cur->next_sibling;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void acpi_object_print(struct acpi_object *object, int depth)
|
||||
{
|
||||
for (int i = 0; i < depth; i++) {
|
||||
fputs(" ", stdout);
|
||||
}
|
||||
|
||||
if (object->name[0] == 0) {
|
||||
printf("<unnamed>\n");
|
||||
} else {
|
||||
printf("%s [%s]\n", object->name, acpi_object_type_string(object->type));
|
||||
}
|
||||
|
||||
struct acpi_object *cur = object->first_child;
|
||||
while (cur) {
|
||||
acpi_object_print(cur, depth + 1);
|
||||
cur = cur->next_sibling;
|
||||
}
|
||||
}
|
||||
|
||||
#define OBJECT_TYPE_STRING(type) \
|
||||
case type: \
|
||||
return #type;
|
||||
|
||||
const char *acpi_object_type_string(enum acpi_object_type type)
|
||||
{
|
||||
switch (type) {
|
||||
OBJECT_TYPE_STRING(ACPI_OBJECT_NONE)
|
||||
OBJECT_TYPE_STRING(ACPI_OBJECT_VALUE)
|
||||
OBJECT_TYPE_STRING(ACPI_OBJECT_NAMESPACE)
|
||||
OBJECT_TYPE_STRING(ACPI_OBJECT_CPU)
|
||||
OBJECT_TYPE_STRING(ACPI_OBJECT_DEVICE)
|
||||
OBJECT_TYPE_STRING(ACPI_OBJECT_METHOD)
|
||||
OBJECT_TYPE_STRING(ACPI_OBJECT_POWER_RESOURCE)
|
||||
OBJECT_TYPE_STRING(ACPI_OBJECT_OPERATION_REGION)
|
||||
OBJECT_TYPE_STRING(ACPI_OBJECT_THERMAL_ZONE)
|
||||
OBJECT_TYPE_STRING(ACPI_OBJECT_FIELD)
|
||||
OBJECT_TYPE_STRING(ACPI_OBJECT_PACKAGE)
|
||||
OBJECT_TYPE_STRING(ACPI_OBJECT_BUFFER)
|
||||
default:
|
||||
return "<unknown>";
|
||||
}
|
||||
}
|
||||
52
tools/amldecode/aml/object.h
Normal file
52
tools/amldecode/aml/object.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#ifndef AML_OBJECT_H_
|
||||
#define AML_OBJECT_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include "constants.h"
|
||||
|
||||
enum acpi_object_type {
|
||||
ACPI_OBJECT_NONE = 0,
|
||||
ACPI_OBJECT_VALUE,
|
||||
ACPI_OBJECT_NAMESPACE,
|
||||
ACPI_OBJECT_CPU,
|
||||
ACPI_OBJECT_DEVICE,
|
||||
ACPI_OBJECT_METHOD,
|
||||
ACPI_OBJECT_POWER_RESOURCE,
|
||||
ACPI_OBJECT_OPERATION_REGION,
|
||||
ACPI_OBJECT_THERMAL_ZONE,
|
||||
ACPI_OBJECT_FIELD,
|
||||
ACPI_OBJECT_PACKAGE,
|
||||
ACPI_OBJECT_BUFFER,
|
||||
};
|
||||
|
||||
struct acpi_object {
|
||||
int ref;
|
||||
enum acpi_object_type type;
|
||||
union {
|
||||
char name[ACPI_OBJECT_NAME_MAX];
|
||||
char *publish_path;
|
||||
};
|
||||
|
||||
size_t scope_end;
|
||||
|
||||
struct acpi_object *parent;
|
||||
struct acpi_object *first_child, *next_sibling;
|
||||
};
|
||||
|
||||
struct acpi_namespace {
|
||||
struct acpi_object *root;
|
||||
};
|
||||
|
||||
extern struct acpi_namespace *acpi_namespace_create(void);
|
||||
extern struct acpi_object *acpi_namespace_get_object(struct acpi_namespace *ns, const char *path);
|
||||
|
||||
extern struct acpi_object *acpi_object_create(const char name[ACPI_OBJECT_NAME_MAX], enum acpi_object_type type);
|
||||
extern struct acpi_object *acpi_object_ref(struct acpi_object *object);
|
||||
extern void acpi_object_deref(struct acpi_object *object);
|
||||
extern void acpi_object_add_child(struct acpi_object *parent, struct acpi_object *child);
|
||||
extern struct acpi_object *acpi_object_get_child(struct acpi_object *object, const char *name);
|
||||
extern void acpi_object_print(struct acpi_object *object, int depth);
|
||||
|
||||
extern const char *acpi_object_type_string(enum acpi_object_type type);
|
||||
|
||||
#endif
|
||||
818
tools/amldecode/aml/opcode.c
Normal file
818
tools/amldecode/aml/opcode.c
Normal file
@@ -0,0 +1,818 @@
|
||||
#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);
|
||||
}
|
||||
190
tools/amldecode/aml/opcode.h
Normal file
190
tools/amldecode/aml/opcode.h
Normal file
@@ -0,0 +1,190 @@
|
||||
#ifndef AML_OPCODE_H_
|
||||
#define AML_OPCODE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "parser.h"
|
||||
|
||||
struct aml_parser;
|
||||
struct aml_value;
|
||||
|
||||
//
|
||||
// Primary OpCode
|
||||
//
|
||||
#define AML_ZERO_OP 0x00
|
||||
#define AML_ONE_OP 0x01
|
||||
#define AML_ALIAS_OP 0x06
|
||||
#define AML_NAME_OP 0x08
|
||||
#define AML_BYTE_PREFIX 0x0a
|
||||
#define AML_WORD_PREFIX 0x0b
|
||||
#define AML_DWORD_PREFIX 0x0c
|
||||
#define AML_STRING_PREFIX 0x0d
|
||||
#define AML_QWORD_PREFIX 0x0e
|
||||
#define AML_SCOPE_OP 0x10
|
||||
#define AML_BUFFER_OP 0x11
|
||||
#define AML_PACKAGE_OP 0x12
|
||||
#define AML_VAR_PACKAGE_OP 0x13
|
||||
#define AML_METHOD_OP 0x14
|
||||
#define AML_EXTERNAL_OP 0x15
|
||||
#define AML_DUAL_NAME_PREFIX 0x2e
|
||||
#define AML_MULTI_NAME_PREFIX 0x2f
|
||||
#define AML_NAME_CHAR_A 0x41
|
||||
#define AML_NAME_CHAR_B 0x42
|
||||
#define AML_NAME_CHAR_C 0x43
|
||||
#define AML_NAME_CHAR_D 0x44
|
||||
#define AML_NAME_CHAR_E 0x45
|
||||
#define AML_NAME_CHAR_F 0x46
|
||||
#define AML_NAME_CHAR_G 0x47
|
||||
#define AML_NAME_CHAR_H 0x48
|
||||
#define AML_NAME_CHAR_I 0x49
|
||||
#define AML_NAME_CHAR_J 0x4a
|
||||
#define AML_NAME_CHAR_K 0x4b
|
||||
#define AML_NAME_CHAR_L 0x4c
|
||||
#define AML_NAME_CHAR_M 0x4d
|
||||
#define AML_NAME_CHAR_N 0x4e
|
||||
#define AML_NAME_CHAR_O 0x4f
|
||||
#define AML_NAME_CHAR_P 0x50
|
||||
#define AML_NAME_CHAR_Q 0x51
|
||||
#define AML_NAME_CHAR_R 0x52
|
||||
#define AML_NAME_CHAR_S 0x53
|
||||
#define AML_NAME_CHAR_T 0x54
|
||||
#define AML_NAME_CHAR_U 0x55
|
||||
#define AML_NAME_CHAR_V 0x56
|
||||
#define AML_NAME_CHAR_W 0x57
|
||||
#define AML_NAME_CHAR_X 0x58
|
||||
#define AML_NAME_CHAR_Y 0x59
|
||||
#define AML_NAME_CHAR_Z 0x5a
|
||||
#define AML_ROOT_CHAR 0x5c
|
||||
#define AML_PARENT_PREFIX_CHAR 0x5e
|
||||
#define AML_NAME_CHAR__ 0x5f
|
||||
#define AML_LOCAL0 0x60
|
||||
#define AML_LOCAL1 0x61
|
||||
#define AML_LOCAL2 0x62
|
||||
#define AML_LOCAL3 0x63
|
||||
#define AML_LOCAL4 0x64
|
||||
#define AML_LOCAL5 0x65
|
||||
#define AML_LOCAL6 0x66
|
||||
#define AML_LOCAL7 0x67
|
||||
#define AML_ARG0 0x68
|
||||
#define AML_ARG1 0x69
|
||||
#define AML_ARG2 0x6a
|
||||
#define AML_ARG3 0x6b
|
||||
#define AML_ARG4 0x6c
|
||||
#define AML_ARG5 0x6d
|
||||
#define AML_ARG6 0x6e
|
||||
#define AML_STORE_OP 0x70
|
||||
#define AML_REF_OF_OP 0x71
|
||||
#define AML_ADD_OP 0x72
|
||||
#define AML_CONCAT_OP 0x73
|
||||
#define AML_SUBTRACT_OP 0x74
|
||||
#define AML_INCREMENT_OP 0x75
|
||||
#define AML_DECREMENT_OP 0x76
|
||||
#define AML_MULTIPLY_OP 0x77
|
||||
#define AML_DIVIDE_OP 0x78
|
||||
#define AML_SHIFT_LEFT_OP 0x79
|
||||
#define AML_SHIFT_RIGHT_OP 0x7a
|
||||
#define AML_AND_OP 0x7b
|
||||
#define AML_NAND_OP 0x7c
|
||||
#define AML_OR_OP 0x7d
|
||||
#define AML_NOR_OP 0x7e
|
||||
#define AML_XOR_OP 0x7f
|
||||
#define AML_NOT_OP 0x80
|
||||
#define AML_FIND_SET_LEFT_BIT_OP 0x81
|
||||
#define AML_FIND_SET_RIGHT_BIT_OP 0x82
|
||||
#define AML_DEREF_OF_OP 0x83
|
||||
#define AML_CONCAT_RES_OP 0x84
|
||||
#define AML_MOD_OP 0x85
|
||||
#define AML_NOTIFY_OP 0x86
|
||||
#define AML_SIZE_OF_OP 0x87
|
||||
#define AML_INDEX_OP 0x88
|
||||
#define AML_MATCH_OP 0x89
|
||||
#define AML_CREATE_DWORD_FIELD_OP 0x8a
|
||||
#define AML_CREATE_WORD_FIELD_OP 0x8b
|
||||
#define AML_CREATE_BYTE_FIELD_OP 0x8c
|
||||
#define AML_CREATE_BIT_FIELD_OP 0x8d
|
||||
#define AML_OBJECT_TYPE_OP 0x8e
|
||||
#define AML_CREATE_QWORD_FIELD_OP 0x8f
|
||||
#define AML_LAND_OP 0x90
|
||||
#define AML_LOR_OP 0x91
|
||||
#define AML_LNOT_OP 0x92
|
||||
#define AML_LEQUAL_OP 0x93
|
||||
#define AML_LGREATER_OP 0x94
|
||||
#define AML_LLESS_OP 0x95
|
||||
#define AML_TO_BUFFER_OP 0x96
|
||||
#define AML_TO_DEC_STRING_OP 0x97
|
||||
#define AML_TO_HEX_STRING_OP 0x98
|
||||
#define AML_TO_INTEGER_OP 0x99
|
||||
#define AML_TO_STRING_OP 0x9c
|
||||
#define AML_COPY_OBJECT_OP 0x9d
|
||||
#define AML_MID_OP 0x9e
|
||||
#define AML_CONTINUE_OP 0x9f
|
||||
#define AML_IF_OP 0xa0
|
||||
#define AML_ELSE_OP 0xa1
|
||||
#define AML_WHILE_OP 0xa2
|
||||
#define AML_NOOP_OP 0xa3
|
||||
#define AML_RETURN_OP 0xa4
|
||||
#define AML_BREAK_OP 0xa5
|
||||
#define AML_BREAK_POINT_OP 0xcc
|
||||
#define AML_ONES_OP 0xff
|
||||
|
||||
//
|
||||
// Extended OpCode
|
||||
//
|
||||
#define AML_EXT_OP 0x5b
|
||||
|
||||
#define AML_EXT_MUTEX_OP 0x01
|
||||
#define AML_EXT_EVENT_OP 0x02
|
||||
#define AML_EXT_COND_REF_OF_OP 0x12
|
||||
#define AML_EXT_CREATE_FIELD_OP 0x13
|
||||
#define AML_EXT_LOAD_TABLE_OP 0x1f
|
||||
#define AML_EXT_LOAD_OP 0x20
|
||||
#define AML_EXT_STALL_OP 0x21
|
||||
#define AML_EXT_SLEEP_OP 0x22
|
||||
#define AML_EXT_ACQUIRE_OP 0x23
|
||||
#define AML_EXT_SIGNAL_OP 0x24
|
||||
#define AML_EXT_WAIT_OP 0x25
|
||||
#define AML_EXT_RESET_OP 0x26
|
||||
#define AML_EXT_RELEASE_OP 0x27
|
||||
#define AML_EXT_FROM_BCD_OP 0x28
|
||||
#define AML_EXT_TO_BCD_OP 0x29
|
||||
#define AML_EXT_UNLOAD_OP 0x2a
|
||||
#define AML_EXT_REVISION_OP 0x30
|
||||
#define AML_EXT_DEBUG_OP 0x31
|
||||
#define AML_EXT_FATAL_OP 0x32
|
||||
#define AML_EXT_TIMER_OP 0x33
|
||||
#define AML_EXT_REGION_OP 0x80
|
||||
#define AML_EXT_FIELD_OP 0x81
|
||||
#define AML_EXT_DEVICE_OP 0x82
|
||||
#define AML_EXT_PROCESSOR_OP 0x83
|
||||
#define AML_EXT_POWER_RES_OP 0x84
|
||||
#define AML_EXT_THERMAL_ZONE_OP 0x85
|
||||
#define AML_EXT_INDEX_FIELD_OP 0x86
|
||||
#define AML_EXT_BANK_FIELD_OP 0x87
|
||||
#define AML_EXT_DATA_REGION_OP 0x88
|
||||
|
||||
//
|
||||
// FieldElement OpCode
|
||||
//
|
||||
#define AML_FIELD_RESERVED_OP 0x00
|
||||
#define AML_FIELD_ACCESS_OP 0x01
|
||||
#define AML_FIELD_CONNECTION_OP 0x02
|
||||
#define AML_FIELD_EXT_ACCESS_OP 0x03
|
||||
|
||||
//
|
||||
// AML Name segment definitions
|
||||
//
|
||||
#define AML_NAME_SEG_SIZE 4
|
||||
|
||||
typedef enum parse_status(*aml_bytecode_parser)(struct aml_parser *, struct aml_value *);
|
||||
|
||||
struct aml_byte_encoding {
|
||||
uint8_t opcode;
|
||||
uint8_t sub_opcode;
|
||||
|
||||
aml_bytecode_parser parser;
|
||||
|
||||
const char *name;
|
||||
};
|
||||
|
||||
extern enum parse_status parse_opcode(struct aml_parser *parser, struct aml_value *out);
|
||||
|
||||
#endif
|
||||
271
tools/amldecode/aml/parser.c
Normal file
271
tools/amldecode/aml/parser.c
Normal file
@@ -0,0 +1,271 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "parser.h"
|
||||
#include "opcode.h"
|
||||
#include "object.h"
|
||||
#include "value.h"
|
||||
|
||||
void aml_parser_init(struct aml_parser *parser, void *p, size_t len)
|
||||
{
|
||||
memset(parser, 0x0, sizeof *parser);
|
||||
|
||||
parser->start = parser->ptr = p;
|
||||
parser->end = parser->start + len;
|
||||
}
|
||||
|
||||
void aml_parser_set_namespace(struct aml_parser *parser, struct acpi_namespace *ns)
|
||||
{
|
||||
parser->ns = ns;
|
||||
}
|
||||
|
||||
int aml_parser_peek(struct aml_parser *parser)
|
||||
{
|
||||
if (parser->ptr >= parser->end) {
|
||||
return PARSE_EOF;
|
||||
}
|
||||
|
||||
return *parser->ptr;
|
||||
}
|
||||
|
||||
int aml_parser_peek_next(struct aml_parser *parser)
|
||||
{
|
||||
if (parser->ptr + 1 >= parser->end) {
|
||||
return PARSE_EOF;
|
||||
}
|
||||
|
||||
return *(parser->ptr + 1);
|
||||
}
|
||||
|
||||
int aml_parser_advance(struct aml_parser *parser)
|
||||
{
|
||||
if (parser->ptr >= parser->end) {
|
||||
return PARSE_EOF;
|
||||
}
|
||||
|
||||
return *(parser->ptr++);
|
||||
}
|
||||
|
||||
unsigned int aml_parser_cursorpos(struct aml_parser *parser)
|
||||
{
|
||||
if (parser->ptr < parser->start) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return parser->ptr - parser->start;
|
||||
}
|
||||
|
||||
void aml_parser_save_cursor(struct aml_parser *parser)
|
||||
{
|
||||
parser->saved_ptr = parser->ptr;
|
||||
}
|
||||
|
||||
void aml_parser_load_cursor(struct aml_parser *parser)
|
||||
{
|
||||
parser->ptr = parser->saved_ptr;
|
||||
}
|
||||
|
||||
static bool object_name_is_always_root(const char *name)
|
||||
{
|
||||
return (!strcmp(name, "_SB_") || !strcmp(name, "GPE_") || !strcmp(name, "_PR_") || !strcmp(name, "_TZ_"));
|
||||
}
|
||||
|
||||
void aml_parser_add_object(struct aml_parser *parser, struct acpi_object *object)
|
||||
{
|
||||
if (object->parent) {
|
||||
return;
|
||||
}
|
||||
|
||||
char *publish_path = object->publish_path;
|
||||
char *rpath = publish_path;
|
||||
|
||||
//printf("adding object '%s'. current scope=%s\n", publish_path, parser->cur_scope ? parser->cur_scope->scope_object->name : "<none>");
|
||||
|
||||
struct acpi_object *cur = parser->cur_scope ? parser->cur_scope->scope_object : NULL;
|
||||
if (*rpath == '\\') {
|
||||
cur = parser->ns->root;
|
||||
rpath++;
|
||||
}
|
||||
|
||||
char *sp;
|
||||
char *tok = strtok_r(rpath, ".", &sp);
|
||||
if (object_name_is_always_root(tok)) {
|
||||
cur = parser->ns->root;
|
||||
}
|
||||
|
||||
if (!cur) {
|
||||
fprintf(stderr, "cannot add object with relative path: no scope!\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (!tok || *tok == '\0') {
|
||||
break;
|
||||
}
|
||||
|
||||
char *next_tok = strtok_r(NULL, ".", &sp);
|
||||
if (!next_tok) {
|
||||
break;
|
||||
}
|
||||
|
||||
struct acpi_object *next = acpi_object_get_child(cur, tok);
|
||||
if (!next) {
|
||||
//printf("auto-creating scope '%s' under '%s'\n", tok, cur->name);
|
||||
next = acpi_object_create(tok, ACPI_OBJECT_NAMESPACE);
|
||||
acpi_object_add_child(cur, next);
|
||||
}
|
||||
|
||||
tok = next_tok;
|
||||
}
|
||||
|
||||
strncpy(object->name, tok, sizeof object->name - 1);
|
||||
object->name[sizeof object->name - 1] = '\0';
|
||||
|
||||
acpi_object_add_child(cur, object);
|
||||
free(publish_path);
|
||||
}
|
||||
|
||||
void aml_parser_push_scope(struct aml_parser *parser, struct acpi_object *object)
|
||||
{
|
||||
struct aml_parser_scope *scope = malloc(sizeof *scope);
|
||||
if (!scope) {
|
||||
perror("aml_parser_push_scope: malloc");
|
||||
abort();
|
||||
}
|
||||
|
||||
scope->scope_object = object;
|
||||
scope->scope_end = object->scope_end;
|
||||
scope->next = parser->cur_scope;
|
||||
object->scope_end = 0;
|
||||
parser->cur_scope = scope;
|
||||
|
||||
//printf("## 0x%04x: moving into scope '%s' (ends at 0x%04zx)\n", aml_parser_cursorpos(parser), parser->cur_scope->scope_object->name, scope->scope_end);
|
||||
}
|
||||
|
||||
void aml_parser_pop_scope(struct aml_parser *parser)
|
||||
{
|
||||
if (!parser->cur_scope) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strcmp(parser->cur_scope->scope_object->name, "\\") && !parser->cur_scope->next) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
printf("## 0x%04x: moving out of scope '%s' up to scope '%s' (ends at 0x%04zx)\n",
|
||||
aml_parser_cursorpos(parser),
|
||||
parser->cur_scope ? parser->cur_scope->scope_object->name : "<none>",
|
||||
parser->cur_scope->next ? parser->cur_scope->next->scope_object->name : "<none>",
|
||||
parser->cur_scope->next ? parser->cur_scope->next->scope_end : 0xFFFF);
|
||||
*/
|
||||
|
||||
struct aml_parser_scope *previous_scope = parser->cur_scope;
|
||||
parser->cur_scope = parser->cur_scope->next;
|
||||
free(previous_scope);
|
||||
}
|
||||
|
||||
static void add_object_to_parser(struct aml_parser *parser, struct acpi_object *object)
|
||||
{
|
||||
if (!object->parent && object != parser->ns->root) {
|
||||
aml_parser_add_object(parser, object);
|
||||
}
|
||||
|
||||
if (object->scope_end != 0) {
|
||||
aml_parser_push_scope(parser, object);
|
||||
}
|
||||
}
|
||||
|
||||
static bool should_pop_current_scope(struct aml_parser *parser)
|
||||
{
|
||||
if (!parser->cur_scope) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!strcmp(parser->cur_scope->scope_object->name, "\\") && !parser->cur_scope->next) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return parser->cur_scope->scope_end <= aml_parser_cursorpos(parser);
|
||||
}
|
||||
|
||||
enum parse_status aml_parser_parse_into_namespace(struct aml_parser *parser, struct acpi_namespace *ns)
|
||||
{
|
||||
parser->ns = ns;
|
||||
|
||||
while (1) {
|
||||
struct aml_value value;
|
||||
enum parse_status status = parse_opcode(parser, &value);
|
||||
if (status != PARSE_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (value.type == AML_VALUE_OBJECT) {
|
||||
struct acpi_object *object = value.value.object;
|
||||
add_object_to_parser(parser, object);
|
||||
}
|
||||
|
||||
while (should_pop_current_scope(parser)) {
|
||||
aml_parser_pop_scope(parser);
|
||||
}
|
||||
}
|
||||
|
||||
return PARSE_OK;
|
||||
}
|
||||
|
||||
struct acpi_object *aml_parser_resolve_path(struct aml_parser *parser, const char *path)
|
||||
{
|
||||
struct acpi_object *cur = parser->cur_scope ? parser->cur_scope->scope_object : NULL;
|
||||
if (*path == '\\') {
|
||||
path++;
|
||||
cur = parser->ns->root;
|
||||
}
|
||||
|
||||
size_t path_len = strlen(path);
|
||||
char *rpath = malloc(path_len + 1);
|
||||
strcpy(rpath, path);
|
||||
|
||||
char *sp;
|
||||
char *tok = strtok_r(rpath, ".", &sp);
|
||||
if (tok && object_name_is_always_root(tok)) {
|
||||
cur = parser->ns->root;
|
||||
}
|
||||
|
||||
if (!cur) {
|
||||
free(rpath);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (tok) {
|
||||
struct acpi_object *child = acpi_object_get_child(cur, tok);
|
||||
if (!child) {
|
||||
free(rpath);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cur = child;
|
||||
tok = strtok_r(NULL, ".", &sp);
|
||||
}
|
||||
|
||||
free(rpath);
|
||||
return cur;
|
||||
}
|
||||
|
||||
#define STATUS_STRING(code) \
|
||||
case code: \
|
||||
return #code;
|
||||
|
||||
const char *parse_status_string(enum parse_status status)
|
||||
{
|
||||
switch (status) {
|
||||
STATUS_STRING(PARSE_OK)
|
||||
STATUS_STRING(PARSE_EOF)
|
||||
STATUS_STRING(PARSE_NOMEM)
|
||||
STATUS_STRING(PARSE_BADSTRING)
|
||||
STATUS_STRING(PARSE_UNKNOWNOP)
|
||||
STATUS_STRING(PARSE_BADTYPE)
|
||||
STATUS_STRING(PARSE_BADREF)
|
||||
default:
|
||||
return "<unknown>";
|
||||
}
|
||||
}
|
||||
48
tools/amldecode/aml/parser.h
Normal file
48
tools/amldecode/aml/parser.h
Normal file
@@ -0,0 +1,48 @@
|
||||
#ifndef AML_PARSER_H_
|
||||
#define AML_PARSER_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
struct acpi_namespace;
|
||||
|
||||
enum parse_status {
|
||||
PARSE_OK = 0,
|
||||
PARSE_EOF = -1,
|
||||
PARSE_NOMEM = -2,
|
||||
PARSE_BADSTRING = -3,
|
||||
PARSE_UNKNOWNOP = -4,
|
||||
PARSE_BADTYPE = -5,
|
||||
PARSE_BADREF = -6,
|
||||
};
|
||||
|
||||
struct aml_parser_scope {
|
||||
struct acpi_object *scope_object;
|
||||
size_t scope_end;
|
||||
struct aml_parser_scope *next;
|
||||
};
|
||||
|
||||
struct aml_parser {
|
||||
unsigned char *start, *end;
|
||||
unsigned char *ptr, *saved_ptr;
|
||||
struct acpi_namespace *ns;
|
||||
struct aml_parser_scope *cur_scope;
|
||||
};
|
||||
|
||||
extern void aml_parser_init(struct aml_parser *parser, void *p, size_t len);
|
||||
extern void aml_parser_set_namespace(struct aml_parser *parser, struct acpi_namespace *ns);
|
||||
extern int aml_parser_peek(struct aml_parser *parser);
|
||||
extern int aml_parser_peek_next(struct aml_parser *parser);
|
||||
extern int aml_parser_advance(struct aml_parser *parser);
|
||||
extern unsigned int aml_parser_cursorpos(struct aml_parser *parser);
|
||||
extern void aml_parser_save_cursor(struct aml_parser *parser);
|
||||
extern void aml_parser_load_cursor(struct aml_parser *parser);
|
||||
extern void aml_parser_add_object(struct aml_parser *parser, struct acpi_object *object);
|
||||
extern void aml_parser_push_scope(struct aml_parser *parser, struct acpi_object *object);
|
||||
extern void aml_parser_pop_scope(struct aml_parser *parser);
|
||||
|
||||
extern enum parse_status aml_parser_parse_into_namespace(struct aml_parser *parser, struct acpi_namespace *ns);
|
||||
extern struct acpi_object *aml_parser_resolve_path(struct aml_parser *parser, const char *path);
|
||||
|
||||
extern const char *parse_status_string(enum parse_status status);
|
||||
|
||||
#endif
|
||||
17
tools/amldecode/aml/value.c
Normal file
17
tools/amldecode/aml/value.c
Normal file
@@ -0,0 +1,17 @@
|
||||
#include "value.h"
|
||||
|
||||
uint64_t aml_value_get_integer(const struct aml_value *value)
|
||||
{
|
||||
switch (value->type) {
|
||||
case AML_VALUE_UINT8:
|
||||
return value->value.uint8;
|
||||
case AML_VALUE_UINT16:
|
||||
return value->value.uint8;
|
||||
case AML_VALUE_UINT32:
|
||||
return value->value.uint8;
|
||||
case AML_VALUE_UINT64:
|
||||
return value->value.uint8;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
43
tools/amldecode/aml/value.h
Normal file
43
tools/amldecode/aml/value.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#ifndef AML_VALUE_H_
|
||||
#define AML_VALUE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "constants.h"
|
||||
|
||||
struct acpi_object;
|
||||
|
||||
enum aml_value_type {
|
||||
AML_VALUE_NONE,
|
||||
AML_VALUE_UINT8,
|
||||
AML_VALUE_UINT16,
|
||||
AML_VALUE_UINT32,
|
||||
AML_VALUE_UINT64,
|
||||
AML_VALUE_OBJECT,
|
||||
AML_VALUE_NAME,
|
||||
AML_VALUE_STRING,
|
||||
};
|
||||
|
||||
struct aml_value {
|
||||
enum aml_value_type type;
|
||||
|
||||
union {
|
||||
uint8_t uint8;
|
||||
uint16_t uint16;
|
||||
uint32_t uint32;
|
||||
uint64_t uint64;
|
||||
struct acpi_object *object;
|
||||
const char *name;
|
||||
const char *str;
|
||||
} value;
|
||||
};
|
||||
|
||||
static inline bool aml_value_is_integer(const struct aml_value *value)
|
||||
{
|
||||
return value->type == AML_VALUE_UINT8 || value->type == AML_VALUE_UINT16 || value->type == AML_VALUE_UINT32 || value->type == AML_VALUE_UINT64;
|
||||
}
|
||||
|
||||
extern uint64_t aml_value_get_integer(const struct aml_value *value);
|
||||
extern void aml_value_destroy(struct aml_value *value);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user