qemu/tests/acpi-utils.c
<<
>>
Prefs
   1/*
   2 * ACPI Utility Functions
   3 *
   4 * Copyright (c) 2013 Red Hat Inc.
   5 * Copyright (c) 2017 Skyport Systems
   6 *
   7 * Authors:
   8 *  Michael S. Tsirkin <mst@redhat.com>,
   9 *  Ben Warren <ben@skyportsystems.com>
  10 *
  11 * This work is licensed under the terms of the GNU GPL, version 2 or later.
  12 * See the COPYING file in the top-level directory.
  13 */
  14
  15#include "qemu/osdep.h"
  16#include <glib/gstdio.h>
  17#include "qemu-common.h"
  18#include "qemu/bitmap.h"
  19#include "acpi-utils.h"
  20#include "boot-sector.h"
  21
  22uint8_t acpi_calc_checksum(const uint8_t *data, int len)
  23{
  24    int i;
  25    uint8_t sum = 0;
  26
  27    for (i = 0; i < len; i++) {
  28        sum += data[i];
  29    }
  30
  31    return sum;
  32}
  33
  34uint32_t acpi_find_rsdp_address(QTestState *qts)
  35{
  36    uint32_t off;
  37
  38    /* RSDP location can vary across a narrow range */
  39    for (off = 0xf0000; off < 0x100000; off += 0x10) {
  40        uint8_t sig[] = "RSD PTR ";
  41        int i;
  42
  43        for (i = 0; i < sizeof sig - 1; ++i) {
  44            sig[i] = qtest_readb(qts, off + i);
  45        }
  46
  47        if (!memcmp(sig, "RSD PTR ", sizeof sig)) {
  48            break;
  49        }
  50    }
  51    return off;
  52}
  53
  54uint64_t acpi_get_xsdt_address(uint8_t *rsdp_table)
  55{
  56    uint64_t xsdt_physical_address;
  57    uint8_t revision = rsdp_table[15 /* Revision offset */];
  58
  59    /* We must have revision 2 if we're looking for an XSDT pointer */
  60    g_assert(revision == 2);
  61
  62    memcpy(&xsdt_physical_address, &rsdp_table[24 /* XsdtAddress offset */], 8);
  63    return le64_to_cpu(xsdt_physical_address);
  64}
  65
  66void acpi_parse_rsdp_table(QTestState *qts, uint32_t addr, uint8_t *rsdp_table)
  67{
  68    uint8_t revision;
  69
  70    /* Read mandatory revision 0 table data (20 bytes) first */
  71    qtest_memread(qts, addr, rsdp_table, 20);
  72    revision = rsdp_table[15 /* Revision offset */];
  73
  74    switch (revision) {
  75    case 0: /* ACPI 1.0 RSDP */
  76        break;
  77    case 2: /* ACPI 2.0+ RSDP */
  78        /* Read the rest of the RSDP table */
  79        qtest_memread(qts, addr + 20, rsdp_table + 20, 16);
  80        break;
  81    default:
  82        g_assert_not_reached();
  83    }
  84
  85    ACPI_ASSERT_CMP64(*((uint64_t *)(rsdp_table)), "RSD PTR ");
  86}
  87
  88/** acpi_fetch_table
  89 *  load ACPI table at @addr_ptr offset pointer into buffer and return it in
  90 *  @aml, its length in @aml_len and check that signature/checksum matches
  91 *  actual one.
  92 */
  93void acpi_fetch_table(QTestState *qts, uint8_t **aml, uint32_t *aml_len,
  94                      const uint8_t *addr_ptr, const char *sig,
  95                      bool verify_checksum)
  96{
  97    uint32_t addr, len;
  98
  99    memcpy(&addr, addr_ptr , sizeof(addr));
 100    addr = le32_to_cpu(addr);
 101    qtest_memread(qts, addr + 4, &len, 4); /* Length of ACPI table */
 102    *aml_len = le32_to_cpu(len);
 103    *aml = g_malloc0(*aml_len);
 104    /* get whole table */
 105    qtest_memread(qts, addr, *aml, *aml_len);
 106
 107    if (sig) {
 108        ACPI_ASSERT_CMP(**aml, sig);
 109    }
 110    if (verify_checksum) {
 111        g_assert(!acpi_calc_checksum(*aml, *aml_len));
 112    }
 113}
 114