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        OptsVisitor *ov;
 243
 244        ov = opts_visitor_new(opts);
 245        visit_type_AcpiTableOptions(opts_get_visitor(ov), NULL, &hdrs, &err);
 246        opts_visitor_cleanup(ov);
 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
 494void acpi_pm_tmr_calc_overflow_time(ACPIREGS *ar)
 495{
 496    int64_t d = acpi_pm_tmr_get_clock();
 497    ar->tmr.overflow_time = (d + 0x800000LL) & ~0x7fffffLL;
 498}
 499
 500static uint32_t acpi_pm_tmr_get(ACPIREGS *ar)
 501{
 502    uint32_t d = acpi_pm_tmr_get_clock();
 503    return d & 0xffffff;
 504}
 505
 506static void acpi_pm_tmr_timer(void *opaque)
 507{
 508    ACPIREGS *ar = opaque;
 509    qemu_system_wakeup_request(QEMU_WAKEUP_REASON_PMTIMER);
 510    ar->tmr.update_sci(ar);
 511}
 512
 513static uint64_t acpi_pm_tmr_read(void *opaque, hwaddr addr, unsigned width)
 514{
 515    return acpi_pm_tmr_get(opaque);
 516}
 517
 518static void acpi_pm_tmr_write(void *opaque, hwaddr addr, uint64_t val,
 519                              unsigned width)
 520{
 521    /* nothing */
 522}
 523
 524static const MemoryRegionOps acpi_pm_tmr_ops = {
 525    .read = acpi_pm_tmr_read,
 526    .write = acpi_pm_tmr_write,
 527    .valid.min_access_size = 4,
 528    .valid.max_access_size = 4,
 529    .endianness = DEVICE_LITTLE_ENDIAN,
 530};
 531
 532void acpi_pm_tmr_init(ACPIREGS *ar, acpi_update_sci_fn update_sci,
 533                      MemoryRegion *parent)
 534{
 535    ar->tmr.update_sci = update_sci;
 536    ar->tmr.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, acpi_pm_tmr_timer, ar);
 537    memory_region_init_io(&ar->tmr.io, memory_region_owner(parent),
 538                          &acpi_pm_tmr_ops, ar, "acpi-tmr", 4);
 539    memory_region_clear_global_locking(&ar->tmr.io);
 540    memory_region_add_subregion(parent, 8, &ar->tmr.io);
 541}
 542
 543void acpi_pm_tmr_reset(ACPIREGS *ar)
 544{
 545    ar->tmr.overflow_time = 0;
 546    timer_del(ar->tmr.timer);
 547}
 548
 549/* ACPI PM1aCNT */
 550static void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val)
 551{
 552    ar->pm1.cnt.cnt = val & ~(ACPI_BITMASK_SLEEP_ENABLE);
 553
 554    if (val & ACPI_BITMASK_SLEEP_ENABLE) {
 555        /* change suspend type */
 556        uint16_t sus_typ = (val >> 10) & 7;
 557        switch(sus_typ) {
 558        case 0: /* soft power off */
 559            qemu_system_shutdown_request();
 560            break;
 561        case 1:
 562            qemu_system_suspend_request();
 563            break;
 564        default:
 565            if (sus_typ == ar->pm1.cnt.s4_val) { /* S4 request */
 566                qapi_event_send_suspend_disk(&error_abort);
 567                qemu_system_shutdown_request();
 568            }
 569            break;
 570        }
 571    }
 572}
 573
 574void acpi_pm1_cnt_update(ACPIREGS *ar,
 575                         bool sci_enable, bool sci_disable)
 576{
 577    /* ACPI specs 3.0, 4.7.2.5 */
 578    if (sci_enable) {
 579        ar->pm1.cnt.cnt |= ACPI_BITMASK_SCI_ENABLE;
 580    } else if (sci_disable) {
 581        ar->pm1.cnt.cnt &= ~ACPI_BITMASK_SCI_ENABLE;
 582    }
 583}
 584
 585static uint64_t acpi_pm_cnt_read(void *opaque, hwaddr addr, unsigned width)
 586{
 587    ACPIREGS *ar = opaque;
 588    return ar->pm1.cnt.cnt;
 589}
 590
 591static void acpi_pm_cnt_write(void *opaque, hwaddr addr, uint64_t val,
 592                              unsigned width)
 593{
 594    acpi_pm1_cnt_write(opaque, val);
 595}
 596
 597static const MemoryRegionOps acpi_pm_cnt_ops = {
 598    .read = acpi_pm_cnt_read,
 599    .write = acpi_pm_cnt_write,
 600    .valid.min_access_size = 2,
 601    .valid.max_access_size = 2,
 602    .endianness = DEVICE_LITTLE_ENDIAN,
 603};
 604
 605void acpi_pm1_cnt_init(ACPIREGS *ar, MemoryRegion *parent,
 606                       bool disable_s3, bool disable_s4, uint8_t s4_val)
 607{
 608    FWCfgState *fw_cfg;
 609
 610    ar->pm1.cnt.s4_val = s4_val;
 611    ar->wakeup.notify = acpi_notify_wakeup;
 612    qemu_register_wakeup_notifier(&ar->wakeup);
 613    memory_region_init_io(&ar->pm1.cnt.io, memory_region_owner(parent),
 614                          &acpi_pm_cnt_ops, ar, "acpi-cnt", 2);
 615    memory_region_add_subregion(parent, 4, &ar->pm1.cnt.io);
 616
 617    fw_cfg = fw_cfg_find();
 618    if (fw_cfg) {
 619        uint8_t suspend[6] = {128, 0, 0, 129, 128, 128};
 620        suspend[3] = 1 | ((!disable_s3) << 7);
 621        suspend[4] = s4_val | ((!disable_s4) << 7);
 622
 623        fw_cfg_add_file(fw_cfg, "etc/system-states", g_memdup(suspend, 6), 6);
 624    }
 625}
 626
 627void acpi_pm1_cnt_reset(ACPIREGS *ar)
 628{
 629    ar->pm1.cnt.cnt = 0;
 630}
 631
 632/* ACPI GPE */
 633void acpi_gpe_init(ACPIREGS *ar, uint8_t len)
 634{
 635    ar->gpe.len = len;
 636    /* Only first len / 2 bytes are ever used,
 637     * but the caller in ich9.c migrates full len bytes.
 638     * TODO: fix ich9.c and drop the extra allocation.
 639     */
 640    ar->gpe.sts = g_malloc0(len);
 641    ar->gpe.en = g_malloc0(len);
 642}
 643
 644void acpi_gpe_reset(ACPIREGS *ar)
 645{
 646    memset(ar->gpe.sts, 0, ar->gpe.len / 2);
 647    memset(ar->gpe.en, 0, ar->gpe.len / 2);
 648}
 649
 650static uint8_t *acpi_gpe_ioport_get_ptr(ACPIREGS *ar, uint32_t addr)
 651{
 652    uint8_t *cur = NULL;
 653
 654    if (addr < ar->gpe.len / 2) {
 655        cur = ar->gpe.sts + addr;
 656    } else if (addr < ar->gpe.len) {
 657        cur = ar->gpe.en + addr - ar->gpe.len / 2;
 658    } else {
 659        abort();
 660    }
 661
 662    return cur;
 663}
 664
 665void acpi_gpe_ioport_writeb(ACPIREGS *ar, uint32_t addr, uint32_t val)
 666{
 667    uint8_t *cur;
 668
 669    cur = acpi_gpe_ioport_get_ptr(ar, addr);
 670    if (addr < ar->gpe.len / 2) {
 671        /* GPE_STS */
 672        *cur = (*cur) & ~val;
 673    } else if (addr < ar->gpe.len) {
 674        /* GPE_EN */
 675        *cur = val;
 676    } else {
 677        abort();
 678    }
 679}
 680
 681uint32_t acpi_gpe_ioport_readb(ACPIREGS *ar, uint32_t addr)
 682{
 683    uint8_t *cur;
 684    uint32_t val;
 685
 686    cur = acpi_gpe_ioport_get_ptr(ar, addr);
 687    val = 0;
 688    if (cur != NULL) {
 689        val = *cur;
 690    }
 691
 692    return val;
 693}
 694
 695void acpi_send_gpe_event(ACPIREGS *ar, qemu_irq irq,
 696                         AcpiGPEStatusBits status)
 697{
 698    ar->gpe.sts[0] |= status;
 699    acpi_update_sci(ar, irq);
 700}
 701
 702void acpi_update_sci(ACPIREGS *regs, qemu_irq irq)
 703{
 704    int sci_level, pm1a_sts;
 705
 706    pm1a_sts = acpi_pm1_evt_get_sts(regs);
 707
 708    sci_level = ((pm1a_sts &
 709                  regs->pm1.evt.en & ACPI_BITMASK_PM1_COMMON_ENABLED) != 0) ||
 710                ((regs->gpe.sts[0] & regs->gpe.en[0]) != 0);
 711
 712    qemu_set_irq(irq, sci_level);
 713
 714    /* schedule a timer interruption if needed */
 715    acpi_pm_tmr_update(regs,
 716                       (regs->pm1.evt.en & ACPI_BITMASK_TIMER_ENABLE) &&
 717                       !(pm1a_sts & ACPI_BITMASK_TIMER_STATUS));
 718}
 719