blob: 5696a33f809e7f02617580543effdb81d7e3bb33 [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "acpi.h"
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <xefi.h>
const efi_guid kAcpiTableGuid = ACPI_TABLE_GUID;
const efi_guid kAcpi20TableGuid = ACPI_20_TABLE_GUID;
const uint8_t kAcpiRsdpSignature[8] = "RSD PTR ";
// Computes the checksum of an ACPI table, which is just the sum of the bytes
// in the table. The table is valid if the checksum is zero.
uint8_t acpi_checksum(uint8_t* bytes, uint32_t length) {
uint8_t checksum = 0;
for (uint32_t i = 0; i < length; i++) {
checksum += bytes[i];
}
return checksum;
}
acpi_rsdp_t* load_acpi_rsdp(efi_configuration_table* entries, size_t num_entries) {
acpi_rsdp_t* rsdp = NULL;
for (size_t i = 0; i < num_entries; i++) {
// Check if this entry is an ACPI RSD PTR.
if (!xefi_cmp_guid(&entries[i].VendorGuid, &kAcpiTableGuid) ||
!xefi_cmp_guid(&entries[i].VendorGuid, &kAcpi20TableGuid)) {
// Verify the signature of the ACPI RSD PTR.
if (!memcmp(entries[i].VendorTable, kAcpiRsdpSignature, sizeof(kAcpiRsdpSignature))) {
rsdp = (acpi_rsdp_t*)entries[i].VendorTable;
break;
}
}
}
// Verify an ACPI table was found.
if (rsdp == NULL) {
printf("RSDP was not found\n");
return NULL;
}
// Verify the checksum of this table. Both V1 and V2 RSDPs should pass the
// V1 checksum, which only covers the first 20 bytes of the table.
if (acpi_checksum((uint8_t*)rsdp, ACPI_RSDP_V1_SIZE)) {
printf("RSDP V1 checksum failed\n");
return NULL;
}
// V2 RSDPs should additionally pass a checksum of the entire table.
if (rsdp->revision > 0) {
if (acpi_checksum((uint8_t*)rsdp, rsdp->length)) {
printf("RSDP V2 checksum failed\n");
return NULL;
}
}
return rsdp;
}