]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[acpi] Compute and check checksum for ACPI tables
authorLaurent Gourvénec <laurent.gourvenec@qarnot-computing.com>
Thu, 27 Jul 2017 14:04:35 +0000 (16:04 +0200)
committerMichael Brown <mcb30@ipxe.org>
Fri, 28 Jul 2017 16:05:33 +0000 (17:05 +0100)
Modified-by: Michael Brown <mcb30@ipxe.org>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/core/acpi.c

index ff8875e1c10930089a65c13b1307c757931b6d76..07679153f8e70d67e132e2081f1cd60232e377ea 100644 (file)
@@ -42,19 +42,41 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
  ******************************************************************************
  */
 
+/**
+ * Compute ACPI table checksum
+ *
+ * @v table            Any ACPI table
+ * @ret checksum       0 if checksum is good
+ */
+static uint8_t acpi_checksum ( userptr_t table ) {
+       struct acpi_header acpi;
+       uint8_t sum = 0;
+       uint8_t data;
+       unsigned int i;
+
+       /* Read table length */
+       copy_from_user ( &acpi.length, table,
+                        offsetof ( typeof ( acpi ), length ),
+                        sizeof ( acpi.length ) );
+
+       /* Compute checksum */
+       for ( i = 0 ; i < le32_to_cpu ( acpi.length ) ; i++ ) {
+               copy_from_user ( &data, table, i, sizeof ( data ) );
+               sum += data;
+       }
+
+       return sum;
+}
+
 /**
  * Fix up ACPI table checksum
  *
  * @v acpi             ACPI table header
  */
 void acpi_fix_checksum ( struct acpi_header *acpi ) {
-       unsigned int i = 0;
-       uint8_t sum = 0;
 
-       for ( i = 0 ; i < acpi->length ; i++ ) {
-               sum += *( ( ( uint8_t * ) acpi ) + i );
-       }
-       acpi->checksum -= sum;
+       /* Update checksum */
+       acpi->checksum -= acpi_checksum ( virt_to_user ( acpi ) );
 }
 
 /**
@@ -123,6 +145,15 @@ userptr_t acpi_find ( uint32_t signature, unsigned int index ) {
                if ( index-- )
                        continue;
 
+               /* Check table integrity */
+               if ( acpi_checksum ( table ) != 0 ) {
+                       DBGC ( rsdt, "RSDT %#08lx found %s with bad checksum "
+                              "at %08lx\n", user_to_phys ( rsdt, 0 ),
+                              acpi_name ( signature ),
+                              user_to_phys ( table, 0 ) );
+                       break;
+               }
+
                DBGC ( rsdt, "RSDT %#08lx found %s at %08lx\n",
                       user_to_phys ( rsdt, 0 ), acpi_name ( signature ),
                       user_to_phys ( table, 0 ) );