ACPICA: Utilities: Add support to read table from files
authorLv Zheng <lv.zheng@intel.com>
Tue, 8 Jul 2014 02:06:12 +0000 (10:06 +0800)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Tue, 8 Jul 2014 12:22:25 +0000 (14:22 +0200)
After the new table reading utility functions are well tested, acpidump can
also switch to use the generic acpi_ut_read_table_xxx() APIs. Currently
this patch is no-op as acpidump does not link to the new APIs.

This patch is only useful for ACPICA applications, most of which are not
shipped in the Linux kernel.

Signed-off-by: Lv Zheng <lv.zheng@intel.com>
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
drivers/acpi/acpica/Makefile
drivers/acpi/acpica/acdebug.h
drivers/acpi/acpica/acutils.h
drivers/acpi/acpica/utfileio.c [new file with mode: 0644]

index 8bb43f0..14b851f 100644 (file)
@@ -175,5 +175,5 @@ acpi-y +=           \
        utxferror.o     \
        utxfmutex.o
 
-acpi-$(ACPI_FUTURE_USAGE) += uttrack.o utcache.o
+acpi-$(ACPI_FUTURE_USAGE) += utfileio.o uttrack.o utcache.o
 
index 68a91eb..1d026ff 100644 (file)
@@ -233,9 +233,6 @@ acpi_status acpi_db_load_acpi_table(char *filename);
 acpi_status
 acpi_db_get_table_from_file(char *filename, struct acpi_table_header **table);
 
-acpi_status
-acpi_db_read_table_from_file(char *filename, struct acpi_table_header **table);
-
 /*
  * dbhistry - debugger HISTORY command
  */
index caeb81a..8a44148 100644 (file)
@@ -394,6 +394,14 @@ acpi_ut_execute_power_methods(struct acpi_namespace_node *device_node,
                              u8 method_count, u8 *out_values);
 
 /*
+ * utfileio - file operations
+ */
+#ifdef ACPI_APPLICATION
+acpi_status
+acpi_ut_read_table_from_file(char *filename, struct acpi_table_header **table);
+#endif
+
+/*
  * utids - device ID support
  */
 acpi_status
diff --git a/drivers/acpi/acpica/utfileio.c b/drivers/acpi/acpica/utfileio.c
new file mode 100644 (file)
index 0000000..c8f6359
--- /dev/null
@@ -0,0 +1,337 @@
+/*******************************************************************************
+ *
+ * Module Name: utfileio - simple file I/O routines
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2014, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "actables.h"
+#include "acapps.h"
+
+#ifdef ACPI_ASL_COMPILER
+#include "aslcompiler.h"
+#endif
+
+#define _COMPONENT          ACPI_CA_DEBUGGER
+ACPI_MODULE_NAME("utfileio")
+
+#ifdef ACPI_APPLICATION
+/* Local prototypes */
+static acpi_status
+acpi_ut_check_text_mode_corruption(u8 *table,
+                                  u32 table_length, u32 file_length);
+
+static acpi_status
+acpi_ut_read_table(FILE * fp,
+                  struct acpi_table_header **table, u32 *table_length);
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_check_text_mode_corruption
+ *
+ * PARAMETERS:  table           - Table buffer
+ *              table_length    - Length of table from the table header
+ *              file_length     - Length of the file that contains the table
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Check table for text mode file corruption where all linefeed
+ *              characters (LF) have been replaced by carriage return linefeed
+ *              pairs (CR/LF).
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ut_check_text_mode_corruption(u8 *table, u32 table_length, u32 file_length)
+{
+       u32 i;
+       u32 pairs = 0;
+
+       if (table_length != file_length) {
+               ACPI_WARNING((AE_INFO,
+                             "File length (0x%X) is not the same as the table length (0x%X)",
+                             file_length, table_length));
+       }
+
+       /* Scan entire table to determine if each LF has been prefixed with a CR */
+
+       for (i = 1; i < file_length; i++) {
+               if (table[i] == 0x0A) {
+                       if (table[i - 1] != 0x0D) {
+
+                               /* The LF does not have a preceding CR, table not corrupted */
+
+                               return (AE_OK);
+                       } else {
+                               /* Found a CR/LF pair */
+
+                               pairs++;
+                       }
+                       i++;
+               }
+       }
+
+       if (!pairs) {
+               return (AE_OK);
+       }
+
+       /*
+        * Entire table scanned, each CR is part of a CR/LF pair --
+        * meaning that the table was treated as a text file somewhere.
+        *
+        * NOTE: We can't "fix" the table, because any existing CR/LF pairs in the
+        * original table are left untouched by the text conversion process --
+        * meaning that we cannot simply replace CR/LF pairs with LFs.
+        */
+       acpi_os_printf("Table has been corrupted by text mode conversion\n");
+       acpi_os_printf("All LFs (%u) were changed to CR/LF pairs\n", pairs);
+       acpi_os_printf("Table cannot be repaired!\n");
+       return (AE_BAD_VALUE);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_read_table
+ *
+ * PARAMETERS:  fp              - File that contains table
+ *              table           - Return value, buffer with table
+ *              table_length    - Return value, length of table
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Load the DSDT from the file pointer
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ut_read_table(FILE * fp,
+                  struct acpi_table_header **table, u32 *table_length)
+{
+       struct acpi_table_header table_header;
+       u32 actual;
+       acpi_status status;
+       u32 file_size;
+       u8 standard_header = TRUE;
+
+       /* Get the file size */
+
+       file_size = cm_get_file_size(fp);
+       if (file_size == ACPI_UINT32_MAX) {
+               return (AE_ERROR);
+       }
+
+       if (file_size < 4) {
+               return (AE_BAD_HEADER);
+       }
+
+       /* Read the signature */
+
+       if (fread(&table_header, 1, 4, fp) != 4) {
+               acpi_os_printf("Could not read the table signature\n");
+               return (AE_BAD_HEADER);
+       }
+
+       fseek(fp, 0, SEEK_SET);
+
+       /* The RSDP table does not have standard ACPI header */
+
+       if (ACPI_COMPARE_NAME(table_header.signature, "RSD ")) {
+               *table_length = file_size;
+               standard_header = FALSE;
+       } else {
+               /* Read the table header */
+
+               if (fread
+                   (&table_header, 1, sizeof(struct acpi_table_header),
+                    fp) != sizeof(struct acpi_table_header)) {
+                       acpi_os_printf("Could not read the table header\n");
+                       return (AE_BAD_HEADER);
+               }
+#if 0
+               /* Validate the table header/length */
+
+               status = acpi_tb_validate_table_header(&table_header);
+               if (ACPI_FAILURE(status)) {
+                       acpi_os_printf("Table header is invalid!\n");
+                       return (status);
+               }
+#endif
+
+               /* File size must be at least as long as the Header-specified length */
+
+               if (table_header.length > file_size) {
+                       acpi_os_printf
+                           ("TableHeader length [0x%X] greater than the input file size [0x%X]\n",
+                            table_header.length, file_size);
+
+#ifdef ACPI_ASL_COMPILER
+                       status = fl_check_for_ascii(fp, NULL, FALSE);
+                       if (ACPI_SUCCESS(status)) {
+                               acpi_os_printf
+                                   ("File appears to be ASCII only, must be binary\n",
+                                    table_header.length, file_size);
+                       }
+#endif
+                       return (AE_BAD_HEADER);
+               }
+#ifdef ACPI_OBSOLETE_CODE
+               /* We only support a limited number of table types */
+
+               if (!ACPI_COMPARE_NAME
+                   ((char *)table_header.signature, ACPI_SIG_DSDT)
+                   && !ACPI_COMPARE_NAME((char *)table_header.signature,
+                                         ACPI_SIG_PSDT)
+                   && !ACPI_COMPARE_NAME((char *)table_header.signature,
+                                         ACPI_SIG_SSDT)) {
+                       acpi_os_printf
+                           ("Table signature [%4.4s] is invalid or not supported\n",
+                            (char *)table_header.signature);
+                       ACPI_DUMP_BUFFER(&table_header,
+                                        sizeof(struct acpi_table_header));
+                       return (AE_ERROR);
+               }
+#endif
+
+               *table_length = table_header.length;
+       }
+
+       /* Allocate a buffer for the table */
+
+       *table = acpi_os_allocate((size_t) file_size);
+       if (!*table) {
+               acpi_os_printf
+                   ("Could not allocate memory for ACPI table %4.4s (size=0x%X)\n",
+                    table_header.signature, *table_length);
+               return (AE_NO_MEMORY);
+       }
+
+       /* Get the rest of the table */
+
+       fseek(fp, 0, SEEK_SET);
+       actual = fread(*table, 1, (size_t) file_size, fp);
+       if (actual == file_size) {
+               if (standard_header) {
+
+                       /* Now validate the checksum */
+
+                       status = acpi_tb_verify_checksum((void *)*table,
+                                                        ACPI_CAST_PTR(struct
+                                                                      acpi_table_header,
+                                                                      *table)->
+                                                        length);
+
+                       if (status == AE_BAD_CHECKSUM) {
+                               status =
+                                   acpi_ut_check_text_mode_corruption((u8 *)
+                                                                      *table,
+                                                                      file_size,
+                                                                      (*table)->
+                                                                      length);
+                               return (status);
+                       }
+               }
+               return (AE_OK);
+       }
+
+       if (actual > 0) {
+               acpi_os_printf("Warning - reading table, asked for %X got %X\n",
+                              file_size, actual);
+               return (AE_OK);
+       }
+
+       acpi_os_printf("Error - could not read the table file\n");
+       acpi_os_free(*table);
+       *table = NULL;
+       *table_length = 0;
+       return (AE_ERROR);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_read_table_from_file
+ *
+ * PARAMETERS:  filename         - File where table is located
+ *              table            - Where a pointer to the table is returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Get an ACPI table from a file
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_read_table_from_file(char *filename, struct acpi_table_header ** table)
+{
+       FILE *file;
+       u32 file_size;
+       u32 table_length;
+       acpi_status status = AE_ERROR;
+
+       /* Open the file, get current size */
+
+       file = fopen(filename, "rb");
+       if (!file) {
+               perror("Could not open input file");
+               return (status);
+       }
+
+       file_size = cm_get_file_size(file);
+       if (file_size == ACPI_UINT32_MAX) {
+               goto exit;
+       }
+
+       /* Get the entire file */
+
+       fprintf(stderr,
+               "Loading Acpi table from file %10s - Length %.8u (%06X)\n",
+               filename, file_size, file_size);
+
+       status = acpi_ut_read_table(file, table, &table_length);
+       if (ACPI_FAILURE(status)) {
+               acpi_os_printf("Could not get table from the file\n");
+       }
+
+exit:
+       fclose(file);
+       return (status);
+}
+
+#endif