[PATCH 1/2] lib + tests: re-work iASL backand and API to handle externals (LP: #1317390)
Colin King
colin.king at canonical.com
Thu May 29 13:59:21 UTC 2014
From: Colin Ian King <colin.king at canonical.com>
Reduce the number of false positives by including in all tables
to help resolve external references. This requires a re-working
of the two iASL interfaces and consumers of the API.
Signed-off-by: Colin Ian King <colin.king at canonical.com>
---
src/acpi/osilinux/osilinux.c | 7 +
src/acpi/syntaxcheck/syntaxcheck.c | 46 ++---
src/acpica/source/compiler/fwts_iasl_interface.c | 31 ++-
src/acpica/source/compiler/fwts_iasl_interface.h | 2 +-
src/hpet/hpet_check/hpet_check.c | 14 +-
src/lib/include/fwts_iasl.h | 8 +-
src/lib/src/fwts_iasl.c | 232 +++++++++++++++++------
7 files changed, 241 insertions(+), 99 deletions(-)
diff --git a/src/acpi/osilinux/osilinux.c b/src/acpi/osilinux/osilinux.c
index 04a731a..857d141 100644
--- a/src/acpi/osilinux/osilinux.c
+++ b/src/acpi/osilinux/osilinux.c
@@ -36,10 +36,17 @@ static int osilinux_test1(fwts_framework *fw)
int dumpdepth = 0;
int found = 0;
+ if (fwts_iasl_init(fw) != FWTS_OK) {
+ fwts_aborted(fw, "Failure to initialise iasl, aborting.");
+ fwts_iasl_deinit();
+ return FWTS_ERROR;
+ }
if (fwts_iasl_disassemble(fw, "DSDT", 0, &disassembly) != FWTS_OK) {
fwts_aborted(fw, "Cannot disassemble DSDT with iasl.");
+ fwts_iasl_deinit();
return FWTS_ERROR;
}
+ fwts_iasl_deinit();
if (disassembly == NULL) {
fwts_failed(fw, LOG_LEVEL_MEDIUM, "NoDSDT",
diff --git a/src/acpi/syntaxcheck/syntaxcheck.c b/src/acpi/syntaxcheck/syntaxcheck.c
index 5281031..5e4f7d4 100644
--- a/src/acpi/syntaxcheck/syntaxcheck.c
+++ b/src/acpi/syntaxcheck/syntaxcheck.c
@@ -28,6 +28,7 @@
#include <json/json.h>
#define ASL_EXCEPTIONS /* so we can include AslErrorLevel in aslmessages.h */
+#define MAX_TABLES 128
#include "aslmessages.h"
@@ -226,6 +227,10 @@ static int syntaxcheck_init(fwts_framework *fw)
{
(void)syntaxcheck_load_advice(fw);
+ if (fwts_iasl_init(fw) != FWTS_OK) {
+ fwts_aborted(fw, "Failure to initialise iasl, aborting.");
+ return FWTS_ERROR;
+ }
return FWTS_OK;
}
@@ -233,6 +238,7 @@ static int syntaxcheck_deinit(fwts_framework *fw)
{
FWTS_UNUSED(fw);
+ fwts_iasl_deinit();
syntaxcheck_free_advice();
return FWTS_OK;
@@ -456,27 +462,19 @@ static void syntaxcheck_give_advice(fwts_framework *fw, uint32_t error_code)
/*
* syntaxcheck_table()
* disassemble and reassemble a table, check for errors. which indicates the Nth
- * table, for example, SSDT may have tables 1..N
+ * table
*/
-static int syntaxcheck_table(fwts_framework *fw, char *tablename, int which)
+static int syntaxcheck_table(fwts_framework *fw, const int which)
{
fwts_list_link *item;
int errors = 0;
int warnings = 0;
int remarks = 0;
- fwts_acpi_table_info *table;
+ char *tablename = fwts_iasl_aml_name(which);
fwts_list *iasl_stdout, *iasl_stderr, *iasl_disassembly;
- if (fwts_acpi_find_table(fw, tablename, which, &table) != FWTS_OK) {
- fwts_aborted(fw, "Cannot load ACPI table %s.", tablename);
- return FWTS_ERROR;
- }
-
- if (table == NULL)
- return FWTS_NO_TABLE; /* Table does not exist */
-
- if (fwts_iasl_reassemble(fw, table->data, table->length,
- &iasl_disassembly, &iasl_stdout, &iasl_stderr) != FWTS_OK) {
+ if (fwts_iasl_reassemble(fw, which,
+ &iasl_disassembly, &iasl_stdout, &iasl_stderr) != FWTS_OK) {
fwts_aborted(fw, "Cannot re-assasemble with iasl.");
return FWTS_ERROR;
}
@@ -611,34 +609,24 @@ static int syntaxcheck_table(fwts_framework *fw, char *tablename, int which)
return FWTS_OK;
}
-static int syntaxcheck_DSDT(fwts_framework *fw)
-{
- return syntaxcheck_table(fw, "DSDT", 0);
-}
-
-static int syntaxcheck_SSDT(fwts_framework *fw)
+static int syntaxcheck_tables(fwts_framework *fw)
{
int i;
+ const int n = fwts_iasl_aml_file_count();
- for (i=0; i < 100; i++) {
- int ret = syntaxcheck_table(fw, "SSDT", i);
- if (ret == FWTS_NO_TABLE)
- return FWTS_OK; /* Hit the last table */
- if (ret != FWTS_OK)
- return FWTS_ERROR;
- }
+ for (i = 0; i < n; i++)
+ syntaxcheck_table(fw, i);
return FWTS_OK;
}
static fwts_framework_minor_test syntaxcheck_tests[] = {
- { syntaxcheck_DSDT, "Disassemble and reassemble DSDT" },
- { syntaxcheck_SSDT, "Disassemble and reassemble SSDT" },
+ { syntaxcheck_tables, "Disassemble and reassemble DSDT and SSDTs." },
{ NULL, NULL }
};
static fwts_framework_ops syntaxcheck_ops = {
- .description = "Re-assemble DSDT and find syntax errors and warnings.",
+ .description = "Re-assemble DSDT and SSDTs to find syntax errors and warnings.",
.init = syntaxcheck_init,
.deinit = syntaxcheck_deinit,
.minor_tests = syntaxcheck_tests
diff --git a/src/acpica/source/compiler/fwts_iasl_interface.c b/src/acpica/source/compiler/fwts_iasl_interface.c
index 180dadd..f1498e5 100644
--- a/src/acpica/source/compiler/fwts_iasl_interface.c
+++ b/src/acpica/source/compiler/fwts_iasl_interface.c
@@ -27,6 +27,7 @@
#include "fwts_iasl_interface.h"
#include "aslcompiler.h"
+#include "acdisasm.h"
#include "acapps.h"
/*
@@ -61,16 +62,21 @@ static void init_asl_core(void)
* fwts_iasl_disassemble_aml()
* invoke iasl to disassemble AML
*/
-int fwts_iasl_disassemble_aml(const char *aml, const char *outputfile)
+int fwts_iasl_disassemble_aml(
+ char *tables[],
+ const int table_entries,
+ const int which,
+ const char *outputfile)
{
pid_t pid;
- int status;
+ int status, i;
pid = fork();
switch (pid) {
case -1:
return -1;
case 0:
+
/* Child */
init_asl_core();
@@ -83,9 +89,28 @@ int fwts_iasl_disassemble_aml(const char *aml, const char *outputfile)
Gbl_UseDefaultAmlFilename = FALSE;
UtConvertBackslashes (Gbl_OutputFilenamePrefix);
+ /*
+ * Add in external files and NOT the one we want
+ * disassemble
+ */
+ for (i = 0; i < table_entries; i++) {
+ if (i != which) {
+ ACPI_STATUS acpi_status;
+ /*
+ * Add in external tables that are NOT the table
+ * we intent to disassemble
+ */
+ acpi_status = AcpiDmAddToExternalFileList(tables[i]);
+ if (ACPI_FAILURE(acpi_status)) {
+ (void)unlink(outputfile);
+ _exit(1);
+ }
+ }
+ }
+
/* Throw away noisy errors */
if (freopen("/dev/null", "w", stderr) != NULL)
- AslDoOneFile((char *)aml);
+ AslDoOneFile((char *)tables[which]);
_exit(0);
break;
diff --git a/src/acpica/source/compiler/fwts_iasl_interface.h b/src/acpica/source/compiler/fwts_iasl_interface.h
index 71675d3..5e2647b 100644
--- a/src/acpica/source/compiler/fwts_iasl_interface.h
+++ b/src/acpica/source/compiler/fwts_iasl_interface.h
@@ -20,7 +20,7 @@
#ifndef __FWTS_IASL_INTERFACE__
#define __FWTS_IASL_INTERFACE__
-int fwts_iasl_disassemble_aml(const char *aml, const char *outputfile);
+int fwts_iasl_disassemble_aml(char *tables[], const int table_entries, const int which, const char *outputfile);
int fwts_iasl_assemble_aml(const char *source, char **stdout_output, char **stderr_output);
#endif
diff --git a/src/hpet/hpet_check/hpet_check.c b/src/hpet/hpet_check/hpet_check.c
index 553dbc0..1a87a35 100644
--- a/src/hpet/hpet_check/hpet_check.c
+++ b/src/hpet/hpet_check/hpet_check.c
@@ -106,8 +106,10 @@ static void hpet_check_base_acpi_table(fwts_framework *fw,
fwts_list *output;
fwts_list_link *item;
- if (fwts_iasl_disassemble(fw, table, which, &output) != FWTS_OK)
+ if (fwts_iasl_disassemble(fw, table, which, &output) != FWTS_OK) {
+ fwts_iasl_deinit();
return;
+ }
if (output == NULL)
return;
@@ -362,11 +364,19 @@ static int hpet_check_test3(fwts_framework *fw)
return FWTS_SKIP;
}
+ if (fwts_iasl_init(fw) != FWTS_OK) {
+ fwts_warning(fw, "Failure to initialise iasl, aborting.");
+ fwts_iasl_deinit();
+ return FWTS_ERROR;
+ }
+
hpet_check_base_acpi_table(fw, "DSDT", 0);
- for (i = 0; i< 11; i++)
+ for (i = 0; i < 11; i++)
hpet_check_base_acpi_table(fw, "SSDT", i);
+ fwts_iasl_deinit();
+
return FWTS_OK;
}
diff --git a/src/lib/include/fwts_iasl.h b/src/lib/include/fwts_iasl.h
index 5efc95c..3e103da 100644
--- a/src/lib/include/fwts_iasl.h
+++ b/src/lib/include/fwts_iasl.h
@@ -22,6 +22,11 @@
#include "fwts.h"
+int fwts_iasl_aml_file_count(void);
+char *fwts_iasl_aml_name(const int nth);
+int fwts_iasl_init(fwts_framework *fw);
+void fwts_iasl_deinit(void);
+
int fwts_iasl_disassemble_all_to_file(fwts_framework *fw,
const char *path);
@@ -31,8 +36,7 @@ int fwts_iasl_disassemble(fwts_framework *fw,
fwts_list **ias_output);
int fwts_iasl_reassemble(fwts_framework *fw,
- const uint8_t *data,
- const int len,
+ const int which,
fwts_list **iasl_disassembly,
fwts_list **iasl_stdout,
fwts_list **iasl_stderr);
diff --git a/src/lib/src/fwts_iasl.c b/src/lib/src/fwts_iasl.c
index 1800912..e4a8a68 100644
--- a/src/lib/src/fwts_iasl.c
+++ b/src/lib/src/fwts_iasl.c
@@ -31,27 +31,59 @@
#include "fwts_iasl_interface.h"
#include "fwts_acpica.h"
+#define MAX_TABLES (128)
+
+static fwts_acpi_table_info *iasl_cached_table_info[MAX_TABLES];
+static char *iasl_cached_table_files[MAX_TABLES];
+static int iasl_cached_table_file_max = 0;
+static bool iasl_init = false;
+
+/*
+ * fwts_iasl_aml_file_count()
+ * return number of cached dumped amlfiles
+ */
+int fwts_iasl_aml_file_count(void)
+{
+ if (iasl_init)
+ return iasl_cached_table_file_max;
+ else
+ return 0;
+}
+
+/*
+ * fwts_iasl_aml_name()
+ * return back nth iASL cached table name
+ */
+char *fwts_iasl_aml_name(const int nth)
+{
+ if (iasl_init && nth < iasl_cached_table_file_max)
+ return iasl_cached_table_info[nth]->name;
+ else
+ return "<unknown>";
+}
+
/*
* fwts_iasl_dump_aml_to_file()
* write AML data of given length to file amlfile.
*/
-static int fwts_iasl_dump_aml_to_file(fwts_framework *fw,
+static int fwts_iasl_dump_aml_to_file(
+ fwts_framework *fw,
const uint8_t *data,
const int length,
- const char *amlfile)
+ const char *filename)
{
int fd;
/* Dump the AML bytecode into a tempoary file so we can disassemble it */
- if ((fd = open(amlfile, O_WRONLY | O_CREAT | O_EXCL, S_IWUSR | S_IRUSR)) < 0) {
- fwts_log_error(fw, "Cannot create temporary file %s", amlfile);
+ if ((fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, S_IWUSR | S_IRUSR)) < 0) {
+ fwts_log_error(fw, "Cannot create temporary file %s", filename);
return FWTS_ERROR;
}
if (write(fd, data, length) != length) {
fwts_log_error(fw, "Cannot write all data to temporary file");
close(fd);
- (void)unlink(amlfile);
+ (void)unlink(filename);
return FWTS_ERROR;
}
close(fd);
@@ -60,42 +92,123 @@ static int fwts_iasl_dump_aml_to_file(fwts_framework *fw,
}
/*
+ * fwts_iasl_cache_table_to_file()
+ * to disassemble an APCPI table we need to dump it
+ * to file. To save effort in saving these to file
+ * multiple times, we dump out all the DSDT and
+ * SSDTs and cache the references to these.
+ */
+static int fwts_iasl_cache_table_to_file(fwts_framework *fw, char *tablename, int which)
+{
+ static pid_t pid = 0;
+ char tmpname[PATH_MAX];
+ fwts_acpi_table_info *table;
+ int ret;
+
+ if (iasl_cached_table_file_max >= MAX_TABLES) {
+ fwts_log_error(fw, "Temporary ACPI table lookup table full.");
+ return FWTS_ERROR;
+ }
+ ret = fwts_acpi_find_table(fw, tablename, which, &table);
+ if (ret != FWTS_OK) {
+ fwts_log_error(fw, "Cannot load ACPI table %s.", tablename);
+ return ret;
+ }
+ if (table == NULL)
+ return FWTS_NO_TABLE; /* Table does not exist */
+ if (!pid)
+ pid = getpid();
+
+ snprintf(tmpname, sizeof(tmpname), "/tmp/fwts_tmp_table_%d_%s_%d.dsl", pid, tablename, which);
+ iasl_cached_table_files[iasl_cached_table_file_max] = strdup(tmpname);
+ if (iasl_cached_table_files[iasl_cached_table_file_max] == NULL) {
+ fwts_log_error(fw, "Cannot allocate cached table file name.");
+ return FWTS_ERROR;
+ }
+ if (fwts_iasl_dump_aml_to_file(fw, table->data, table->length, tmpname) != FWTS_OK) {
+ free(iasl_cached_table_files[iasl_cached_table_file_max]);
+ iasl_cached_table_files[iasl_cached_table_file_max] = NULL;
+ return FWTS_ERROR;
+ }
+ iasl_cached_table_info[iasl_cached_table_file_max] = table;
+ iasl_cached_table_file_max++;
+ return FWTS_OK;
+}
+
+/*
+ * fwts_iasl_deinit()
+ * clean up cached files and references
+ */
+void fwts_iasl_deinit(void)
+{
+ int i;
+
+ for (i = 0; i < iasl_cached_table_file_max; i++) {
+ if (iasl_cached_table_files[i])
+ (void)unlink(iasl_cached_table_files[i]);
+ iasl_cached_table_files[i] = NULL;
+ iasl_cached_table_info[i] = NULL;
+ }
+ iasl_cached_table_file_max = 0;
+}
+
+/*
+ * fwts_iasl_init()
+ * initialise iasl - cache DSDT and SSDT to file
+ */
+int fwts_iasl_init(fwts_framework *fw)
+{
+ int i;
+ int ret;
+
+ fwts_iasl_deinit(); /* Ensure it is clean */
+
+ ret = fwts_iasl_cache_table_to_file(fw, "DSDT", 0);
+ if (ret != FWTS_OK)
+ return ret;
+
+ for (i = 0; i < MAX_TABLES; i++) {
+ if (fwts_iasl_cache_table_to_file(fw, "SSDT", i) != FWTS_OK)
+ break;
+ }
+
+ iasl_init = true;
+
+ return FWTS_OK;
+}
+
+/*
* fwts_iasl_disassemble_to_file()
* Disassemble a given table and dump disassembly to a file.
* For tables where there are multiple matches, e.g. SSDT, we
* specify the Nth table with 'which'.
- *
*/
-int fwts_iasl_disassemble_to_file(fwts_framework *fw,
+static int fwts_iasl_disassemble_to_file(fwts_framework *fw,
const char *tablename,
const int which,
const char *filename)
{
- fwts_acpi_table_info *table;
- char amlfile[PATH_MAX];
- int pid = getpid();
- int ret;
-
- fwts_acpcia_set_fwts_framework(fw);
+ int i, count, n = 0;
- if ((ret = fwts_acpi_find_table(fw, tablename, which, &table)) != FWTS_OK)
- return ret;
+ if (!iasl_init)
+ return FWTS_ERROR;
- if (table == NULL)
+ /* Find Nth table of a given name */
+ count = fwts_iasl_aml_file_count();
+ for (i = 0; i < count; i++) {
+ if (!strcmp(tablename, iasl_cached_table_info[i]->name)) {
+ if (n == which)
+ break;
+ n++;
+ }
+ }
+ if (i >= count)
return FWTS_NO_TABLE;
- snprintf(amlfile, sizeof(amlfile), "/tmp/fwts_iasl_%d_%s.dat", pid, tablename);
-
- /* Dump the AML bytecode into a tempoary file so we can disassemble it */
- if (fwts_iasl_dump_aml_to_file(fw, table->data, table->length, amlfile) != FWTS_OK)
- return FWTS_ERROR;
+ fwts_acpcia_set_fwts_framework(fw);
- if (fwts_iasl_disassemble_aml(amlfile, filename) < 0) {
- (void)unlink(amlfile);
+ if (fwts_iasl_disassemble_aml(iasl_cached_table_files, iasl_cached_table_file_max, i, filename) < 0)
return FWTS_ERROR;
- }
-
- (void)unlink(amlfile);
return FWTS_OK;
}
@@ -116,12 +229,14 @@ int fwts_iasl_disassemble(fwts_framework *fw,
int pid = getpid();
int ret;
+ if (!iasl_init)
+ return FWTS_ERROR;
if (iasl_output == NULL)
return FWTS_ERROR;
*iasl_output = NULL;
- snprintf(tmpfile, sizeof(tmpfile), "/tmp/fwts_iasl_%d_%s.dsl", pid, tablename);
+ snprintf(tmpfile, sizeof(tmpfile), "/tmp/fwts_iasl_disassemble_%d_%s.dsl", pid, tablename);
if ((ret = fwts_iasl_disassemble_to_file(fw, tablename, which, tmpfile)) != FWTS_OK)
return ret;
@@ -140,32 +255,36 @@ int fwts_iasl_disassemble(fwts_framework *fw,
int fwts_iasl_disassemble_all_to_file(fwts_framework *fw,
const char *path)
{
- int i;
+ int i, n;
int ret;
char filename[PATH_MAX];
char pathname[PATH_MAX];
- if (path == NULL)
- strncpy(pathname, "", sizeof(pathname));
- else
- snprintf(pathname, sizeof(pathname), "%s/", path);
-
- snprintf(filename, sizeof(filename), "%sDSDT.dsl", pathname);
-
- ret = fwts_iasl_disassemble_to_file(fw, "DSDT", 0, filename);
+ ret = fwts_iasl_init(fw);
if (ret == FWTS_ERROR_NO_PRIV) {
fprintf(stderr, "Need to have root privilege to read ACPI tables from memory! Re-run using sudo.\n");
return FWTS_ERROR;
}
- if (ret == FWTS_OK)
- printf("Disassembled DSDT to %s\n", filename);
+ if (ret != FWTS_OK) {
+ fprintf(stderr, "Could not initialise disassembler.\n");
+ return FWTS_ERROR;
+ }
- for (i=0; ;i++) {
- snprintf(filename, sizeof(filename), "%sSSDT%d.dsl", pathname, i);
- if (fwts_iasl_disassemble_to_file(fw, "SSDT", i, filename) != FWTS_OK)
- break;
- printf("Disassembled SSDT %d to %s\n", i, filename);
+ n = fwts_iasl_aml_file_count();
+ if (path == NULL)
+ strncpy(pathname, "", sizeof(pathname));
+ else
+ snprintf(pathname, sizeof(pathname), "%s/", path);
+
+ for (i = 0; i < n; i++) {
+ snprintf(filename, sizeof(filename), "%s%s%d.dsl", pathname, iasl_cached_table_info[i]->name, i);
+ fwts_iasl_disassemble_to_file(fw, "DSDT", 0, filename);
+ if (fwts_iasl_disassemble_aml(iasl_cached_table_files, iasl_cached_table_file_max, i, filename) < 0)
+ fprintf(stderr, "Could not disassemble %s\n", iasl_cached_table_info[i]->name);
+ else
+ printf("Disassembled %s to %s\n", iasl_cached_table_info[i]->name, filename);
}
+ fwts_iasl_deinit();
return FWTS_OK;
}
@@ -177,47 +296,38 @@ int fwts_iasl_disassemble_all_to_file(fwts_framework *fw,
* any re-assembly errors into list iasl_errors.
*/
int fwts_iasl_reassemble(fwts_framework *fw,
- const uint8_t *data,
- const int len,
+ const int which,
fwts_list **iasl_disassembly,
fwts_list **iasl_stdout,
fwts_list **iasl_stderr)
{
char tmpfile[PATH_MAX];
- char amlfile[PATH_MAX];
char *stdout_output = NULL, *stderr_output = NULL;
int pid = getpid();
- if ((iasl_disassembly == NULL) ||
+ if ((!iasl_init) ||
+ (iasl_disassembly == NULL) ||
(iasl_stdout == NULL) ||
- (iasl_stderr == NULL))
+ (iasl_stderr == NULL) ||
+ (which > iasl_cached_table_file_max))
return FWTS_ERROR;
fwts_acpcia_set_fwts_framework(fw);
*iasl_disassembly = NULL;
- snprintf(tmpfile, sizeof(tmpfile), "/tmp/fwts_iasl_%d.dsl", pid);
- snprintf(amlfile, sizeof(amlfile), "/tmp/fwts_iasl_%d.dat", pid);
-
- /* Dump the AML bytecode into a tempoary file so we can disassemble it */
- if (fwts_iasl_dump_aml_to_file(fw, data, len, amlfile) != FWTS_OK)
- return FWTS_ERROR;
+ snprintf(tmpfile, sizeof(tmpfile), "/tmp/fwts_iasl_reassemble_%d.dsl", pid);
- if (fwts_iasl_disassemble_aml(amlfile, tmpfile) < 0) {
+ if (fwts_iasl_disassemble_aml(iasl_cached_table_files, iasl_cached_table_file_max, which, tmpfile) < 0) {
(void)unlink(tmpfile);
- (void)unlink(amlfile);
return FWTS_ERROR;
}
- (void)unlink(amlfile);
/* Read in the disassembled text to return later */
*iasl_disassembly = fwts_file_open_and_read(tmpfile);
/* Now we have a disassembled source in tmpfile, so let's assemble it */
-
if (fwts_iasl_assemble_aml(tmpfile, &stdout_output, &stderr_output) < 0) {
- (void)unlink(amlfile);
(void)unlink(tmpfile);
free(stdout_output);
return FWTS_ERROR;
@@ -225,10 +335,9 @@ int fwts_iasl_reassemble(fwts_framework *fw,
/* Remove these now we don't need them */
(void)unlink(tmpfile);
- (void)unlink(amlfile);
/* And remove aml file generated from ACPICA compiler */
- snprintf(tmpfile, sizeof(tmpfile), "/tmp/fwts_iasl_%d.aml", pid);
+ snprintf(tmpfile, sizeof(tmpfile), "/tmp/fwts_iasl_reassemble_%d.aml", pid);
(void)unlink(tmpfile);
*iasl_stdout = fwts_list_from_text(stdout_output);
@@ -237,4 +346,3 @@ int fwts_iasl_reassemble(fwts_framework *fw,
return FWTS_OK;
}
-
--
2.0.0.rc4
More information about the fwts-devel
mailing list