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