xref: /openbmc/qemu/hw/acpi/core.c (revision dccdb0f82a0d018443b12fb13d91655a10b0a151)
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  
36  struct 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  
57  static 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  
63  char unsigned *acpi_tables;
64  size_t acpi_tables_len;
65  
66  static 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  
73  static void acpi_register_config(void)
74  {
75      qemu_add_opts(&qemu_acpi_opts);
76  }
77  
78  opts_init(acpi_register_config);
79  
80  static 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   */
107  static 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  
239  void 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  
302  out:
303      g_free(blob);
304      g_strfreev(pathnames);
305      qapi_free_AcpiTableOptions(hdrs);
306  }
307  
308  unsigned acpi_table_len(void *current)
309  {
310      struct acpi_table_header *hdr = current - sizeof(hdr->_length);
311      return hdr->_length;
312  }
313  
314  static
315  void *acpi_table_hdr(void *h)
316  {
317      struct acpi_table_header *hdr = h;
318      return &hdr->sig;
319  }
320  
321  uint8_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  
329  uint8_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  
340  int 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  
356  static 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 */
382  uint16_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  
394  static 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  
404  static 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  
413  void 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  
421  void 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  
429  static 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  
442  static 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  
458  static 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  
467  void 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 */
477  void 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  
491  static 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  
497  void 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  
503  static uint32_t acpi_pm_tmr_get(ACPIREGS *ar)
504  {
505      uint32_t d = acpi_pm_tmr_get_clock();
506      return d & 0xffffff;
507  }
508  
509  static 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  
517  static uint64_t acpi_pm_tmr_read(void *opaque, hwaddr addr, unsigned width)
518  {
519      return acpi_pm_tmr_get(opaque);
520  }
521  
522  static void acpi_pm_tmr_write(void *opaque, hwaddr addr, uint64_t val,
523                                unsigned width)
524  {
525      /* nothing */
526  }
527  
528  static 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  
537  void 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  
547  void acpi_pm_tmr_reset(ACPIREGS *ar)
548  {
549      ar->tmr.overflow_time = 0;
550      timer_del(ar->tmr.timer);
551  }
552  
553  /* ACPI PM1aCNT */
554  static 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  
578  void 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 (sci_enable) {
583          ar->pm1.cnt.cnt |= ACPI_BITMASK_SCI_ENABLE;
584      } else if (sci_disable) {
585          ar->pm1.cnt.cnt &= ~ACPI_BITMASK_SCI_ENABLE;
586      }
587  }
588  
589  static uint64_t acpi_pm_cnt_read(void *opaque, hwaddr addr, unsigned width)
590  {
591      ACPIREGS *ar = opaque;
592      return ar->pm1.cnt.cnt;
593  }
594  
595  static void acpi_pm_cnt_write(void *opaque, hwaddr addr, uint64_t val,
596                                unsigned width)
597  {
598      acpi_pm1_cnt_write(opaque, val);
599  }
600  
601  static const MemoryRegionOps acpi_pm_cnt_ops = {
602      .read = acpi_pm_cnt_read,
603      .write = acpi_pm_cnt_write,
604      .impl.min_access_size = 2,
605      .valid.min_access_size = 1,
606      .valid.max_access_size = 2,
607      .endianness = DEVICE_LITTLE_ENDIAN,
608  };
609  
610  void 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  
619      /*
620       * Register wake-up support in QMP query-current-machine API
621       */
622      qemu_register_wakeup_support();
623  
624      memory_region_init_io(&ar->pm1.cnt.io, memory_region_owner(parent),
625                            &acpi_pm_cnt_ops, ar, "acpi-cnt", 2);
626      memory_region_add_subregion(parent, 4, &ar->pm1.cnt.io);
627  
628      fw_cfg = fw_cfg_find();
629      if (fw_cfg) {
630          uint8_t suspend[6] = {128, 0, 0, 129, 128, 128};
631          suspend[3] = 1 | ((!disable_s3) << 7);
632          suspend[4] = s4_val | ((!disable_s4) << 7);
633  
634          fw_cfg_add_file(fw_cfg, "etc/system-states", g_memdup(suspend, 6), 6);
635      }
636  }
637  
638  void acpi_pm1_cnt_reset(ACPIREGS *ar)
639  {
640      ar->pm1.cnt.cnt = 0;
641  }
642  
643  /* ACPI GPE */
644  void acpi_gpe_init(ACPIREGS *ar, uint8_t len)
645  {
646      ar->gpe.len = len;
647      /* Only first len / 2 bytes are ever used,
648       * but the caller in ich9.c migrates full len bytes.
649       * TODO: fix ich9.c and drop the extra allocation.
650       */
651      ar->gpe.sts = g_malloc0(len);
652      ar->gpe.en = g_malloc0(len);
653  }
654  
655  void acpi_gpe_reset(ACPIREGS *ar)
656  {
657      memset(ar->gpe.sts, 0, ar->gpe.len / 2);
658      memset(ar->gpe.en, 0, ar->gpe.len / 2);
659  }
660  
661  static uint8_t *acpi_gpe_ioport_get_ptr(ACPIREGS *ar, uint32_t addr)
662  {
663      uint8_t *cur = NULL;
664  
665      if (addr < ar->gpe.len / 2) {
666          cur = ar->gpe.sts + addr;
667      } else if (addr < ar->gpe.len) {
668          cur = ar->gpe.en + addr - ar->gpe.len / 2;
669      } else {
670          abort();
671      }
672  
673      return cur;
674  }
675  
676  void acpi_gpe_ioport_writeb(ACPIREGS *ar, uint32_t addr, uint32_t val)
677  {
678      uint8_t *cur;
679  
680      cur = acpi_gpe_ioport_get_ptr(ar, addr);
681      if (addr < ar->gpe.len / 2) {
682          /* GPE_STS */
683          *cur = (*cur) & ~val;
684      } else if (addr < ar->gpe.len) {
685          /* GPE_EN */
686          *cur = val;
687      } else {
688          abort();
689      }
690  }
691  
692  uint32_t acpi_gpe_ioport_readb(ACPIREGS *ar, uint32_t addr)
693  {
694      uint8_t *cur;
695      uint32_t val;
696  
697      cur = acpi_gpe_ioport_get_ptr(ar, addr);
698      val = 0;
699      if (cur != NULL) {
700          val = *cur;
701      }
702  
703      return val;
704  }
705  
706  void acpi_send_gpe_event(ACPIREGS *ar, qemu_irq irq,
707                           AcpiEventStatusBits status)
708  {
709      ar->gpe.sts[0] |= status;
710      acpi_update_sci(ar, irq);
711  }
712  
713  void acpi_update_sci(ACPIREGS *regs, qemu_irq irq)
714  {
715      int sci_level, pm1a_sts;
716  
717      pm1a_sts = acpi_pm1_evt_get_sts(regs);
718  
719      sci_level = ((pm1a_sts &
720                    regs->pm1.evt.en & ACPI_BITMASK_PM1_COMMON_ENABLED) != 0) ||
721                  ((regs->gpe.sts[0] & regs->gpe.en[0]) != 0);
722  
723      qemu_set_irq(irq, sci_level);
724  
725      /* schedule a timer interruption if needed */
726      acpi_pm_tmr_update(regs,
727                         (regs->pm1.evt.en & ACPI_BITMASK_TIMER_ENABLE) &&
728                         !(pm1a_sts & ACPI_BITMASK_TIMER_STATUS));
729  }
730