cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

core.c (21642B)


      1/*
      2 * ACPI implementation
      3 *
      4 * Copyright (c) 2006 Fabrice Bellard
      5 *
      6 * This library is free software; you can redistribute it and/or
      7 * modify it under the terms of the GNU Lesser General Public
      8 * License version 2.1 as published by the Free Software Foundation.
      9 *
     10 * This library is distributed in the hope that it will be useful,
     11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13 * Lesser General Public License for more details.
     14 *
     15 * You should have received a copy of the GNU Lesser General Public
     16 * License along with this library; if not, see <http://www.gnu.org/licenses/>
     17 *
     18 * Contributions after 2012-01-13 are licensed under the terms of the
     19 * GNU GPL, version 2 or (at your option) any later version.
     20 */
     21
     22#include "qemu/osdep.h"
     23#include "hw/irq.h"
     24#include "hw/acpi/acpi.h"
     25#include "hw/nvram/fw_cfg.h"
     26#include "qemu/config-file.h"
     27#include "qapi/error.h"
     28#include "qapi/opts-visitor.h"
     29#include "qapi/qapi-events-run-state.h"
     30#include "qapi/qapi-visit-acpi.h"
     31#include "qemu/error-report.h"
     32#include "qemu/module.h"
     33#include "qemu/option.h"
     34#include "sysemu/runstate.h"
     35
     36struct acpi_table_header {
     37    uint16_t _length;         /* our length, not actual part of the hdr */
     38                              /* allows easier parsing for fw_cfg clients */
     39    char sig[4]
     40             QEMU_NONSTRING;  /* ACPI signature (4 ASCII characters) */
     41    uint32_t length;          /* Length of table, in bytes, including header */
     42    uint8_t revision;         /* ACPI Specification minor version # */
     43    uint8_t checksum;         /* To make sum of entire table == 0 */
     44    char oem_id[6]
     45             QEMU_NONSTRING;  /* OEM identification */
     46    char oem_table_id[8]
     47             QEMU_NONSTRING;  /* OEM table identification */
     48    uint32_t oem_revision;    /* OEM revision number */
     49    char asl_compiler_id[4]
     50             QEMU_NONSTRING;  /* ASL compiler vendor ID */
     51    uint32_t asl_compiler_revision; /* ASL compiler revision number */
     52} QEMU_PACKED;
     53
     54#define ACPI_TABLE_HDR_SIZE sizeof(struct acpi_table_header)
     55#define ACPI_TABLE_PFX_SIZE sizeof(uint16_t)  /* size of the extra prefix */
     56
     57static const char unsigned dfl_hdr[ACPI_TABLE_HDR_SIZE - ACPI_TABLE_PFX_SIZE] =
     58    "QEMU\0\0\0\0\1\0"       /* sig (4), len(4), revno (1), csum (1) */
     59    "QEMUQEQEMUQEMU\1\0\0\0" /* OEM id (6), table (8), revno (4) */
     60    "QEMU\1\0\0\0"           /* ASL compiler ID (4), version (4) */
     61    ;
     62
     63char unsigned *acpi_tables;
     64size_t acpi_tables_len;
     65
     66static QemuOptsList qemu_acpi_opts = {
     67    .name = "acpi",
     68    .implied_opt_name = "data",
     69    .head = QTAILQ_HEAD_INITIALIZER(qemu_acpi_opts.head),
     70    .desc = { { 0 } } /* validated with OptsVisitor */
     71};
     72
     73static void acpi_register_config(void)
     74{
     75    qemu_add_opts(&qemu_acpi_opts);
     76}
     77
     78opts_init(acpi_register_config);
     79
     80static int acpi_checksum(const uint8_t *data, int len)
     81{
     82    int sum, i;
     83    sum = 0;
     84    for (i = 0; i < len; i++) {
     85        sum += data[i];
     86    }
     87    return (-sum) & 0xff;
     88}
     89
     90
     91/* Install a copy of the ACPI table specified in @blob.
     92 *
     93 * If @has_header is set, @blob starts with the System Description Table Header
     94 * structure. Otherwise, "dfl_hdr" is prepended. In any case, each header field
     95 * is optionally overwritten from @hdrs.
     96 *
     97 * It is valid to call this function with
     98 * (@blob == NULL && bloblen == 0 && !has_header).
     99 *
    100 * @hdrs->file and @hdrs->data are ignored.
    101 *
    102 * SIZE_MAX is considered "infinity" in this function.
    103 *
    104 * The number of tables that can be installed is not limited, but the 16-bit
    105 * counter at the beginning of "acpi_tables" wraps around after UINT16_MAX.
    106 */
    107static void acpi_table_install(const char unsigned *blob, size_t bloblen,
    108                               bool has_header,
    109                               const struct AcpiTableOptions *hdrs,
    110                               Error **errp)
    111{
    112    size_t body_start;
    113    const char unsigned *hdr_src;
    114    size_t body_size, acpi_payload_size;
    115    struct acpi_table_header *ext_hdr;
    116    unsigned changed_fields;
    117
    118    /* Calculate where the ACPI table body starts within the blob, plus where
    119     * to copy the ACPI table header from.
    120     */
    121    if (has_header) {
    122        /*   _length             | ACPI header in blob | blob body
    123         *   ^^^^^^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^^^   ^^^^^^^^^
    124         *   ACPI_TABLE_PFX_SIZE     sizeof dfl_hdr      body_size
    125         *                           == body_start
    126         *
    127         *                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    128         *                           acpi_payload_size == bloblen
    129         */
    130        body_start = sizeof dfl_hdr;
    131
    132        if (bloblen < body_start) {
    133            error_setg(errp, "ACPI table claiming to have header is too "
    134                       "short, available: %zu, expected: %zu", bloblen,
    135                       body_start);
    136            return;
    137        }
    138        hdr_src = blob;
    139    } else {
    140        /*   _length             | ACPI header in template | blob body
    141         *   ^^^^^^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^^^^^^^   ^^^^^^^^^^
    142         *   ACPI_TABLE_PFX_SIZE       sizeof dfl_hdr        body_size
    143         *                                                   == bloblen
    144         *
    145         *                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    146         *                                  acpi_payload_size
    147         */
    148        body_start = 0;
    149        hdr_src = dfl_hdr;
    150    }
    151    body_size = bloblen - body_start;
    152    acpi_payload_size = sizeof dfl_hdr + body_size;
    153
    154    if (acpi_payload_size > UINT16_MAX) {
    155        error_setg(errp, "ACPI table too big, requested: %zu, max: %u",
    156                   acpi_payload_size, (unsigned)UINT16_MAX);
    157        return;
    158    }
    159
    160    /* We won't fail from here on. Initialize / extend the globals. */
    161    if (acpi_tables == NULL) {
    162        acpi_tables_len = sizeof(uint16_t);
    163        acpi_tables = g_malloc0(acpi_tables_len);
    164    }
    165
    166    acpi_tables = g_realloc(acpi_tables, acpi_tables_len +
    167                                         ACPI_TABLE_PFX_SIZE +
    168                                         sizeof dfl_hdr + body_size);
    169
    170    ext_hdr = (struct acpi_table_header *)(acpi_tables + acpi_tables_len);
    171    acpi_tables_len += ACPI_TABLE_PFX_SIZE;
    172
    173    memcpy(acpi_tables + acpi_tables_len, hdr_src, sizeof dfl_hdr);
    174    acpi_tables_len += sizeof dfl_hdr;
    175
    176    if (blob != NULL) {
    177        memcpy(acpi_tables + acpi_tables_len, blob + body_start, body_size);
    178        acpi_tables_len += body_size;
    179    }
    180
    181    /* increase number of tables */
    182    stw_le_p(acpi_tables, lduw_le_p(acpi_tables) + 1u);
    183
    184    /* Update the header fields. The strings need not be NUL-terminated. */
    185    changed_fields = 0;
    186    ext_hdr->_length = cpu_to_le16(acpi_payload_size);
    187
    188    if (hdrs->has_sig) {
    189        strncpy(ext_hdr->sig, hdrs->sig, sizeof ext_hdr->sig);
    190        ++changed_fields;
    191    }
    192
    193    if (has_header && le32_to_cpu(ext_hdr->length) != acpi_payload_size) {
    194        warn_report("ACPI table has wrong length, header says "
    195                    "%" PRIu32 ", actual size %zu bytes",
    196                    le32_to_cpu(ext_hdr->length), acpi_payload_size);
    197    }
    198    ext_hdr->length = cpu_to_le32(acpi_payload_size);
    199
    200    if (hdrs->has_rev) {
    201        ext_hdr->revision = hdrs->rev;
    202        ++changed_fields;
    203    }
    204
    205    ext_hdr->checksum = 0;
    206
    207    if (hdrs->has_oem_id) {
    208        strncpy(ext_hdr->oem_id, hdrs->oem_id, sizeof ext_hdr->oem_id);
    209        ++changed_fields;
    210    }
    211    if (hdrs->has_oem_table_id) {
    212        strncpy(ext_hdr->oem_table_id, hdrs->oem_table_id,
    213                sizeof ext_hdr->oem_table_id);
    214        ++changed_fields;
    215    }
    216    if (hdrs->has_oem_rev) {
    217        ext_hdr->oem_revision = cpu_to_le32(hdrs->oem_rev);
    218        ++changed_fields;
    219    }
    220    if (hdrs->has_asl_compiler_id) {
    221        strncpy(ext_hdr->asl_compiler_id, hdrs->asl_compiler_id,
    222                sizeof ext_hdr->asl_compiler_id);
    223        ++changed_fields;
    224    }
    225    if (hdrs->has_asl_compiler_rev) {
    226        ext_hdr->asl_compiler_revision = cpu_to_le32(hdrs->asl_compiler_rev);
    227        ++changed_fields;
    228    }
    229
    230    if (!has_header && changed_fields == 0) {
    231        warn_report("ACPI table: no headers are specified");
    232    }
    233
    234    /* recalculate checksum */
    235    ext_hdr->checksum = acpi_checksum((const char unsigned *)ext_hdr +
    236                                      ACPI_TABLE_PFX_SIZE, acpi_payload_size);
    237}
    238
    239void acpi_table_add(const QemuOpts *opts, Error **errp)
    240{
    241    AcpiTableOptions *hdrs = NULL;
    242    char **pathnames = NULL;
    243    char **cur;
    244    size_t bloblen = 0;
    245    char unsigned *blob = NULL;
    246
    247    {
    248        Visitor *v;
    249
    250        v = opts_visitor_new(opts);
    251        visit_type_AcpiTableOptions(v, NULL, &hdrs, errp);
    252        visit_free(v);
    253    }
    254
    255    if (!hdrs) {
    256        goto out;
    257    }
    258    if (hdrs->has_file == hdrs->has_data) {
    259        error_setg(errp, "'-acpitable' requires one of 'data' or 'file'");
    260        goto out;
    261    }
    262
    263    pathnames = g_strsplit(hdrs->has_file ? hdrs->file : hdrs->data, ":", 0);
    264    if (pathnames == NULL || pathnames[0] == NULL) {
    265        error_setg(errp, "'-acpitable' requires at least one pathname");
    266        goto out;
    267    }
    268
    269    /* now read in the data files, reallocating buffer as needed */
    270    for (cur = pathnames; *cur; ++cur) {
    271        int fd = open(*cur, O_RDONLY | O_BINARY);
    272
    273        if (fd < 0) {
    274            error_setg(errp, "can't open file %s: %s", *cur, strerror(errno));
    275            goto out;
    276        }
    277
    278        for (;;) {
    279            char unsigned data[8192];
    280            ssize_t r;
    281
    282            r = read(fd, data, sizeof data);
    283            if (r == 0) {
    284                break;
    285            } else if (r > 0) {
    286                blob = g_realloc(blob, bloblen + r);
    287                memcpy(blob + bloblen, data, r);
    288                bloblen += r;
    289            } else if (errno != EINTR) {
    290                error_setg(errp, "can't read file %s: %s", *cur,
    291                           strerror(errno));
    292                close(fd);
    293                goto out;
    294            }
    295        }
    296
    297        close(fd);
    298    }
    299
    300    acpi_table_install(blob, bloblen, hdrs->has_file, hdrs, errp);
    301
    302out:
    303    g_free(blob);
    304    g_strfreev(pathnames);
    305    qapi_free_AcpiTableOptions(hdrs);
    306}
    307
    308unsigned acpi_table_len(void *current)
    309{
    310    struct acpi_table_header *hdr = current - sizeof(hdr->_length);
    311    return hdr->_length;
    312}
    313
    314static
    315void *acpi_table_hdr(void *h)
    316{
    317    struct acpi_table_header *hdr = h;
    318    return &hdr->sig;
    319}
    320
    321uint8_t *acpi_table_first(void)
    322{
    323    if (!acpi_tables) {
    324        return NULL;
    325    }
    326    return acpi_table_hdr(acpi_tables + ACPI_TABLE_PFX_SIZE);
    327}
    328
    329uint8_t *acpi_table_next(uint8_t *current)
    330{
    331    uint8_t *next = current + acpi_table_len(current);
    332
    333    if (next - acpi_tables >= acpi_tables_len) {
    334        return NULL;
    335    } else {
    336        return acpi_table_hdr(next);
    337    }
    338}
    339
    340int acpi_get_slic_oem(AcpiSlicOem *oem)
    341{
    342    uint8_t *u;
    343
    344    for (u = acpi_table_first(); u; u = acpi_table_next(u)) {
    345        struct acpi_table_header *hdr = (void *)(u - sizeof(hdr->_length));
    346
    347        if (memcmp(hdr->sig, "SLIC", 4) == 0) {
    348            oem->id = hdr->oem_id;
    349            oem->table_id = hdr->oem_table_id;
    350            return 0;
    351        }
    352    }
    353    return -1;
    354}
    355
    356static void acpi_notify_wakeup(Notifier *notifier, void *data)
    357{
    358    ACPIREGS *ar = container_of(notifier, ACPIREGS, wakeup);
    359    WakeupReason *reason = data;
    360
    361    switch (*reason) {
    362    case QEMU_WAKEUP_REASON_RTC:
    363        ar->pm1.evt.sts |=
    364            (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_RT_CLOCK_STATUS);
    365        break;
    366    case QEMU_WAKEUP_REASON_PMTIMER:
    367        ar->pm1.evt.sts |=
    368            (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_TIMER_STATUS);
    369        break;
    370    case QEMU_WAKEUP_REASON_OTHER:
    371        /* ACPI_BITMASK_WAKE_STATUS should be set on resume.
    372           Pretend that resume was caused by power button */
    373        ar->pm1.evt.sts |=
    374            (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_POWER_BUTTON_STATUS);
    375        break;
    376    default:
    377        break;
    378    }
    379}
    380
    381/* ACPI PM1a EVT */
    382uint16_t acpi_pm1_evt_get_sts(ACPIREGS *ar)
    383{
    384    /* Compare ns-clock, not PM timer ticks, because
    385       acpi_pm_tmr_update function uses ns for setting the timer. */
    386    int64_t d = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
    387    if (d >= muldiv64(ar->tmr.overflow_time,
    388                      NANOSECONDS_PER_SECOND, PM_TIMER_FREQUENCY)) {
    389        ar->pm1.evt.sts |= ACPI_BITMASK_TIMER_STATUS;
    390    }
    391    return ar->pm1.evt.sts;
    392}
    393
    394static void acpi_pm1_evt_write_sts(ACPIREGS *ar, uint16_t val)
    395{
    396    uint16_t pm1_sts = acpi_pm1_evt_get_sts(ar);
    397    if (pm1_sts & val & ACPI_BITMASK_TIMER_STATUS) {
    398        /* if TMRSTS is reset, then compute the new overflow time */
    399        acpi_pm_tmr_calc_overflow_time(ar);
    400    }
    401    ar->pm1.evt.sts &= ~val;
    402}
    403
    404static void acpi_pm1_evt_write_en(ACPIREGS *ar, uint16_t val)
    405{
    406    ar->pm1.evt.en = val;
    407    qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_RTC,
    408                              val & ACPI_BITMASK_RT_CLOCK_ENABLE);
    409    qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_PMTIMER,
    410                              val & ACPI_BITMASK_TIMER_ENABLE);
    411}
    412
    413void acpi_pm1_evt_power_down(ACPIREGS *ar)
    414{
    415    if (ar->pm1.evt.en & ACPI_BITMASK_POWER_BUTTON_ENABLE) {
    416        ar->pm1.evt.sts |= ACPI_BITMASK_POWER_BUTTON_STATUS;
    417        ar->tmr.update_sci(ar);
    418    }
    419}
    420
    421void acpi_pm1_evt_reset(ACPIREGS *ar)
    422{
    423    ar->pm1.evt.sts = 0;
    424    ar->pm1.evt.en = 0;
    425    qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_RTC, 0);
    426    qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_PMTIMER, 0);
    427}
    428
    429static uint64_t acpi_pm_evt_read(void *opaque, hwaddr addr, unsigned width)
    430{
    431    ACPIREGS *ar = opaque;
    432    switch (addr) {
    433    case 0:
    434        return acpi_pm1_evt_get_sts(ar);
    435    case 2:
    436        return ar->pm1.evt.en;
    437    default:
    438        return 0;
    439    }
    440}
    441
    442static void acpi_pm_evt_write(void *opaque, hwaddr addr, uint64_t val,
    443                              unsigned width)
    444{
    445    ACPIREGS *ar = opaque;
    446    switch (addr) {
    447    case 0:
    448        acpi_pm1_evt_write_sts(ar, val);
    449        ar->pm1.evt.update_sci(ar);
    450        break;
    451    case 2:
    452        acpi_pm1_evt_write_en(ar, val);
    453        ar->pm1.evt.update_sci(ar);
    454        break;
    455    }
    456}
    457
    458static const MemoryRegionOps acpi_pm_evt_ops = {
    459    .read = acpi_pm_evt_read,
    460    .write = acpi_pm_evt_write,
    461    .impl.min_access_size = 2,
    462    .valid.min_access_size = 1,
    463    .valid.max_access_size = 2,
    464    .endianness = DEVICE_LITTLE_ENDIAN,
    465};
    466
    467void acpi_pm1_evt_init(ACPIREGS *ar, acpi_update_sci_fn update_sci,
    468                       MemoryRegion *parent)
    469{
    470    ar->pm1.evt.update_sci = update_sci;
    471    memory_region_init_io(&ar->pm1.evt.io, memory_region_owner(parent),
    472                          &acpi_pm_evt_ops, ar, "acpi-evt", 4);
    473    memory_region_add_subregion(parent, 0, &ar->pm1.evt.io);
    474}
    475
    476/* ACPI PM_TMR */
    477void acpi_pm_tmr_update(ACPIREGS *ar, bool enable)
    478{
    479    int64_t expire_time;
    480
    481    /* schedule a timer interruption if needed */
    482    if (enable) {
    483        expire_time = muldiv64(ar->tmr.overflow_time, NANOSECONDS_PER_SECOND,
    484                               PM_TIMER_FREQUENCY);
    485        timer_mod(ar->tmr.timer, expire_time);
    486    } else {
    487        timer_del(ar->tmr.timer);
    488    }
    489}
    490
    491static inline int64_t acpi_pm_tmr_get_clock(void)
    492{
    493    return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), PM_TIMER_FREQUENCY,
    494                    NANOSECONDS_PER_SECOND);
    495}
    496
    497void acpi_pm_tmr_calc_overflow_time(ACPIREGS *ar)
    498{
    499    int64_t d = acpi_pm_tmr_get_clock();
    500    ar->tmr.overflow_time = (d + 0x800000LL) & ~0x7fffffLL;
    501}
    502
    503static uint32_t acpi_pm_tmr_get(ACPIREGS *ar)
    504{
    505    uint32_t d = acpi_pm_tmr_get_clock();
    506    return d & 0xffffff;
    507}
    508
    509static void acpi_pm_tmr_timer(void *opaque)
    510{
    511    ACPIREGS *ar = opaque;
    512
    513    qemu_system_wakeup_request(QEMU_WAKEUP_REASON_PMTIMER, NULL);
    514    ar->tmr.update_sci(ar);
    515}
    516
    517static uint64_t acpi_pm_tmr_read(void *opaque, hwaddr addr, unsigned width)
    518{
    519    return acpi_pm_tmr_get(opaque);
    520}
    521
    522static void acpi_pm_tmr_write(void *opaque, hwaddr addr, uint64_t val,
    523                              unsigned width)
    524{
    525    /* nothing */
    526}
    527
    528static const MemoryRegionOps acpi_pm_tmr_ops = {
    529    .read = acpi_pm_tmr_read,
    530    .write = acpi_pm_tmr_write,
    531    .impl.min_access_size = 4,
    532    .valid.min_access_size = 1,
    533    .valid.max_access_size = 4,
    534    .endianness = DEVICE_LITTLE_ENDIAN,
    535};
    536
    537void acpi_pm_tmr_init(ACPIREGS *ar, acpi_update_sci_fn update_sci,
    538                      MemoryRegion *parent)
    539{
    540    ar->tmr.update_sci = update_sci;
    541    ar->tmr.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, acpi_pm_tmr_timer, ar);
    542    memory_region_init_io(&ar->tmr.io, memory_region_owner(parent),
    543                          &acpi_pm_tmr_ops, ar, "acpi-tmr", 4);
    544    memory_region_add_subregion(parent, 8, &ar->tmr.io);
    545}
    546
    547void acpi_pm_tmr_reset(ACPIREGS *ar)
    548{
    549    ar->tmr.overflow_time = 0;
    550    timer_del(ar->tmr.timer);
    551}
    552
    553/* ACPI PM1aCNT */
    554static void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val)
    555{
    556    ar->pm1.cnt.cnt = val & ~(ACPI_BITMASK_SLEEP_ENABLE);
    557
    558    if (val & ACPI_BITMASK_SLEEP_ENABLE) {
    559        /* change suspend type */
    560        uint16_t sus_typ = (val >> 10) & 7;
    561        switch (sus_typ) {
    562        case 0: /* soft power off */
    563            qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
    564            break;
    565        case 1:
    566            qemu_system_suspend_request();
    567            break;
    568        default:
    569            if (sus_typ == ar->pm1.cnt.s4_val) { /* S4 request */
    570                qapi_event_send_suspend_disk();
    571                qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
    572            }
    573            break;
    574        }
    575    }
    576}
    577
    578void acpi_pm1_cnt_update(ACPIREGS *ar,
    579                         bool sci_enable, bool sci_disable)
    580{
    581    /* ACPI specs 3.0, 4.7.2.5 */
    582    if (ar->pm1.cnt.acpi_only) {
    583        return;
    584    }
    585
    586    if (sci_enable) {
    587        ar->pm1.cnt.cnt |= ACPI_BITMASK_SCI_ENABLE;
    588    } else if (sci_disable) {
    589        ar->pm1.cnt.cnt &= ~ACPI_BITMASK_SCI_ENABLE;
    590    }
    591}
    592
    593static uint64_t acpi_pm_cnt_read(void *opaque, hwaddr addr, unsigned width)
    594{
    595    ACPIREGS *ar = opaque;
    596    return ar->pm1.cnt.cnt;
    597}
    598
    599static void acpi_pm_cnt_write(void *opaque, hwaddr addr, uint64_t val,
    600                              unsigned width)
    601{
    602    acpi_pm1_cnt_write(opaque, val);
    603}
    604
    605static const MemoryRegionOps acpi_pm_cnt_ops = {
    606    .read = acpi_pm_cnt_read,
    607    .write = acpi_pm_cnt_write,
    608    .impl.min_access_size = 2,
    609    .valid.min_access_size = 1,
    610    .valid.max_access_size = 2,
    611    .endianness = DEVICE_LITTLE_ENDIAN,
    612};
    613
    614void acpi_pm1_cnt_init(ACPIREGS *ar, MemoryRegion *parent,
    615                       bool disable_s3, bool disable_s4, uint8_t s4_val,
    616                       bool acpi_only)
    617{
    618    FWCfgState *fw_cfg;
    619
    620    ar->pm1.cnt.s4_val = s4_val;
    621    ar->pm1.cnt.acpi_only = acpi_only;
    622    ar->wakeup.notify = acpi_notify_wakeup;
    623    qemu_register_wakeup_notifier(&ar->wakeup);
    624
    625    /*
    626     * Register wake-up support in QMP query-current-machine API
    627     */
    628    qemu_register_wakeup_support();
    629
    630    memory_region_init_io(&ar->pm1.cnt.io, memory_region_owner(parent),
    631                          &acpi_pm_cnt_ops, ar, "acpi-cnt", 2);
    632    memory_region_add_subregion(parent, 4, &ar->pm1.cnt.io);
    633
    634    fw_cfg = fw_cfg_find();
    635    if (fw_cfg) {
    636        uint8_t suspend[6] = {128, 0, 0, 129, 128, 128};
    637        suspend[3] = 1 | ((!disable_s3) << 7);
    638        suspend[4] = s4_val | ((!disable_s4) << 7);
    639
    640        fw_cfg_add_file(fw_cfg, "etc/system-states", g_memdup(suspend, 6), 6);
    641    }
    642}
    643
    644void acpi_pm1_cnt_reset(ACPIREGS *ar)
    645{
    646    ar->pm1.cnt.cnt = 0;
    647    if (ar->pm1.cnt.acpi_only) {
    648        ar->pm1.cnt.cnt |= ACPI_BITMASK_SCI_ENABLE;
    649    }
    650}
    651
    652/* ACPI GPE */
    653void acpi_gpe_init(ACPIREGS *ar, uint8_t len)
    654{
    655    ar->gpe.len = len;
    656    /* Only first len / 2 bytes are ever used,
    657     * but the caller in ich9.c migrates full len bytes.
    658     * TODO: fix ich9.c and drop the extra allocation.
    659     */
    660    ar->gpe.sts = g_malloc0(len);
    661    ar->gpe.en = g_malloc0(len);
    662}
    663
    664void acpi_gpe_reset(ACPIREGS *ar)
    665{
    666    memset(ar->gpe.sts, 0, ar->gpe.len / 2);
    667    memset(ar->gpe.en, 0, ar->gpe.len / 2);
    668}
    669
    670static uint8_t *acpi_gpe_ioport_get_ptr(ACPIREGS *ar, uint32_t addr)
    671{
    672    uint8_t *cur = NULL;
    673
    674    if (addr < ar->gpe.len / 2) {
    675        cur = ar->gpe.sts + addr;
    676    } else if (addr < ar->gpe.len) {
    677        cur = ar->gpe.en + addr - ar->gpe.len / 2;
    678    } else {
    679        abort();
    680    }
    681
    682    return cur;
    683}
    684
    685void acpi_gpe_ioport_writeb(ACPIREGS *ar, uint32_t addr, uint32_t val)
    686{
    687    uint8_t *cur;
    688
    689    cur = acpi_gpe_ioport_get_ptr(ar, addr);
    690    if (addr < ar->gpe.len / 2) {
    691        /* GPE_STS */
    692        *cur = (*cur) & ~val;
    693    } else if (addr < ar->gpe.len) {
    694        /* GPE_EN */
    695        *cur = val;
    696    } else {
    697        abort();
    698    }
    699}
    700
    701uint32_t acpi_gpe_ioport_readb(ACPIREGS *ar, uint32_t addr)
    702{
    703    uint8_t *cur;
    704    uint32_t val;
    705
    706    cur = acpi_gpe_ioport_get_ptr(ar, addr);
    707    val = 0;
    708    if (cur != NULL) {
    709        val = *cur;
    710    }
    711
    712    return val;
    713}
    714
    715void acpi_send_gpe_event(ACPIREGS *ar, qemu_irq irq,
    716                         AcpiEventStatusBits status)
    717{
    718    ar->gpe.sts[0] |= status;
    719    acpi_update_sci(ar, irq);
    720}
    721
    722void acpi_update_sci(ACPIREGS *regs, qemu_irq irq)
    723{
    724    int sci_level, pm1a_sts;
    725
    726    pm1a_sts = acpi_pm1_evt_get_sts(regs);
    727
    728    sci_level = ((pm1a_sts &
    729                  regs->pm1.evt.en & ACPI_BITMASK_PM1_COMMON_ENABLED) != 0) ||
    730                ((regs->gpe.sts[0] & regs->gpe.en[0]) != 0);
    731
    732    qemu_set_irq(irq, sci_level);
    733
    734    /* schedule a timer interruption if needed */
    735    acpi_pm_tmr_update(regs,
    736                       (regs->pm1.evt.en & ACPI_BITMASK_TIMER_ENABLE) &&
    737                       !(pm1a_sts & ACPI_BITMASK_TIMER_STATUS));
    738}