2023-07-19 19:00:27 +01:00
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include "parser.h"
|
|
|
|
|
#include "opcode.h"
|
|
|
|
|
#include "object.h"
|
|
|
|
|
#include "value.h"
|
2023-07-22 17:57:20 +01:00
|
|
|
#include "../table.h"
|
2023-07-19 19:00:27 +01:00
|
|
|
|
|
|
|
|
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;
|
2023-07-22 17:57:20 +01:00
|
|
|
cur = next;
|
2023-07-19 19:00:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
2023-07-22 17:57:20 +01:00
|
|
|
aml_parser_push_scope(parser, ns->root);
|
|
|
|
|
enum parse_status status = PARSE_OK;
|
2023-07-19 19:00:27 +01:00
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
|
struct aml_value value;
|
2023-07-22 17:57:20 +01:00
|
|
|
status = parse_opcode(parser, &value);
|
2023-07-19 19:00:27 +01:00
|
|
|
if (status != PARSE_OK) {
|
2023-07-22 17:57:20 +01:00
|
|
|
break;
|
2023-07-19 19:00:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-22 17:57:20 +01:00
|
|
|
if (status == PARSE_EOF && !parser->cur_scope->next) {
|
|
|
|
|
status = PARSE_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (status != PARSE_OK) {
|
|
|
|
|
fprintf(stderr, "parse error at 0x%04lx: %s\n",
|
|
|
|
|
aml_parser_cursorpos(parser) + sizeof(struct acpi_table), parse_status_string(status));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return status;
|
2023-07-19 19:00:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
2023-07-22 17:57:20 +01:00
|
|
|
char *token_buf = rpath;
|
2023-07-19 19:00:27 +01:00
|
|
|
strcpy(rpath, path);
|
|
|
|
|
|
2023-07-22 17:57:20 +01:00
|
|
|
while (*token_buf == '^') {
|
|
|
|
|
cur = cur->parent;
|
|
|
|
|
token_buf++;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-19 19:00:27 +01:00
|
|
|
char *sp;
|
2023-07-22 17:57:20 +01:00
|
|
|
char *tok = strtok_r(token_buf, ".", &sp);
|
2023-07-19 19:00:27 +01:00
|
|
|
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>";
|
|
|
|
|
}
|
|
|
|
|
}
|