4 * Copyright (c) 2006 Fabrice Bellard
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.
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.
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/>
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.
27 struct acpi_table_header
{
28 uint16_t _length
; /* our length, not actual part of the hdr */
29 /* XXX why we have 2 length fields here? */
30 char sig
[4]; /* ACPI signature (4 ASCII characters) */
31 uint32_t length
; /* Length of table, in bytes, including header */
32 uint8_t revision
; /* ACPI Specification minor version # */
33 uint8_t checksum
; /* To make sum of entire table == 0 */
34 char oem_id
[6]; /* OEM identification */
35 char oem_table_id
[8]; /* OEM table identification */
36 uint32_t oem_revision
; /* OEM revision number */
37 char asl_compiler_id
[4]; /* ASL compiler vendor ID */
38 uint32_t asl_compiler_revision
; /* ASL compiler revision number */
41 #define ACPI_TABLE_HDR_SIZE sizeof(struct acpi_table_header)
42 #define ACPI_TABLE_PFX_SIZE sizeof(uint16_t) /* size of the extra prefix */
44 static const char dfl_hdr
[ACPI_TABLE_HDR_SIZE
] =
45 "\0\0" /* fake _length (2) */
46 "QEMU\0\0\0\0\1\0" /* sig (4), len(4), revno (1), csum (1) */
47 "QEMUQEQEMUQEMU\1\0\0\0" /* OEM id (6), table (8), revno (4) */
48 "QEMU\1\0\0\0" /* ASL compiler ID (4), version (4) */
52 size_t acpi_tables_len
;
54 static int acpi_checksum(const uint8_t *data
, int len
)
58 for (i
= 0; i
< len
; i
++) {
64 /* XXX fixme: this function uses obsolete argument parsing interface */
65 int acpi_table_add(const char *t
)
67 char buf
[1024], *p
, *f
;
69 size_t len
, start
, allen
;
73 struct acpi_table_header hdr
;
76 r
|= get_param_value(buf
, sizeof(buf
), "data", t
) ? 1 : 0;
77 r
|= get_param_value(buf
, sizeof(buf
), "file", t
) ? 2 : 0;
81 /* fallthrough for default behavior */
89 fprintf(stderr
, "acpitable: both data and file are specified\n");
94 allen
= sizeof(uint16_t);
95 acpi_tables
= g_malloc0(allen
);
97 allen
= acpi_tables_len
;
101 acpi_tables
= g_realloc(acpi_tables
, start
+ ACPI_TABLE_HDR_SIZE
);
102 allen
+= has_header
? ACPI_TABLE_PFX_SIZE
: ACPI_TABLE_HDR_SIZE
;
104 /* now read in the data files, reallocating buffer as needed */
106 for (f
= strtok(buf
, ":"); f
; f
= strtok(NULL
, ":")) {
107 int fd
= open(f
, O_RDONLY
);
110 fprintf(stderr
, "can't open file %s: %s\n", f
, strerror(errno
));
116 r
= read(fd
, data
, sizeof(data
));
120 acpi_tables
= g_realloc(acpi_tables
, allen
+ r
);
121 memcpy(acpi_tables
+ allen
, data
, r
);
123 } else if (errno
!= EINTR
) {
124 fprintf(stderr
, "can't read file %s: %s\n",
134 /* now fill in the header fields */
136 f
= acpi_tables
+ start
; /* start of the table */
139 /* copy the header to temp place to align the fields */
140 memcpy(&hdr
, has_header
? f
: dfl_hdr
, ACPI_TABLE_HDR_SIZE
);
142 /* length of the table minus our prefix */
143 len
= allen
- start
- ACPI_TABLE_PFX_SIZE
;
145 hdr
._length
= cpu_to_le16(len
);
147 if (get_param_value(buf
, sizeof(buf
), "sig", t
)) {
148 /* strncpy is justified: the field need not be NUL-terminated. */
149 strncpy(hdr
.sig
, buf
, sizeof(hdr
.sig
));
153 /* length of the table including header, in bytes */
155 /* check if actual length is correct */
156 val
= le32_to_cpu(hdr
.length
);
159 "warning: acpitable has wrong length,"
160 " header says %lu, actual size %zu bytes\n",
165 /* we may avoid putting length here if has_header is true */
166 hdr
.length
= cpu_to_le32(len
);
168 if (get_param_value(buf
, sizeof(buf
), "rev", t
)) {
169 val
= strtoul(buf
, &p
, 0);
170 if (val
> 255 || *p
) {
171 fprintf(stderr
, "acpitable: \"rev=%s\" is invalid\n", buf
);
174 hdr
.revision
= (uint8_t)val
;
178 if (get_param_value(buf
, sizeof(buf
), "oem_id", t
)) {
179 /* strncpy is justified: the field need not be NUL-terminated. */
180 strncpy(hdr
.oem_id
, buf
, sizeof(hdr
.oem_id
));
184 if (get_param_value(buf
, sizeof(buf
), "oem_table_id", t
)) {
185 /* strncpy is justified: the field need not be NUL-terminated. */
186 strncpy(hdr
.oem_table_id
, buf
, sizeof(hdr
.oem_table_id
));
190 if (get_param_value(buf
, sizeof(buf
), "oem_rev", t
)) {
191 val
= strtol(buf
, &p
, 0);
193 fprintf(stderr
, "acpitable: \"oem_rev=%s\" is invalid\n", buf
);
196 hdr
.oem_revision
= cpu_to_le32(val
);
200 if (get_param_value(buf
, sizeof(buf
), "asl_compiler_id", t
)) {
201 /* strncpy is justified: the field need not be NUL-terminated. */
202 strncpy(hdr
.asl_compiler_id
, buf
, sizeof(hdr
.asl_compiler_id
));
206 if (get_param_value(buf
, sizeof(buf
), "asl_compiler_rev", t
)) {
207 val
= strtol(buf
, &p
, 0);
209 fprintf(stderr
, "acpitable: \"%s=%s\" is invalid\n",
210 "asl_compiler_rev", buf
);
213 hdr
.asl_compiler_revision
= cpu_to_le32(val
);
217 if (!has_header
&& !changed
) {
218 fprintf(stderr
, "warning: acpitable: no table headers are specified\n");
222 /* now calculate checksum of the table, complete with the header */
223 /* we may as well leave checksum intact if has_header is true */
224 /* alternatively there may be a way to set cksum to a given value */
225 hdr
.checksum
= 0; /* for checksum calculation */
227 /* put header back */
228 memcpy(f
, &hdr
, sizeof(hdr
));
230 if (changed
|| !has_header
|| 1) {
231 ((struct acpi_table_header
*)f
)->checksum
=
232 acpi_checksum((uint8_t *)f
+ ACPI_TABLE_PFX_SIZE
, len
);
235 /* increase number of tables */
236 (*(uint16_t *)acpi_tables
) =
237 cpu_to_le32(le32_to_cpu(*(uint16_t *)acpi_tables
) + 1);
239 acpi_tables_len
= allen
;
244 static void acpi_notify_wakeup(Notifier
*notifier
, void *data
)
246 ACPIREGS
*ar
= container_of(notifier
, ACPIREGS
, wakeup
);
247 WakeupReason
*reason
= data
;
250 case QEMU_WAKEUP_REASON_RTC
:
252 (ACPI_BITMASK_WAKE_STATUS
| ACPI_BITMASK_RT_CLOCK_STATUS
);
254 case QEMU_WAKEUP_REASON_PMTIMER
:
256 (ACPI_BITMASK_WAKE_STATUS
| ACPI_BITMASK_TIMER_STATUS
);
258 case QEMU_WAKEUP_REASON_OTHER
:
260 /* ACPI_BITMASK_WAKE_STATUS should be set on resume.
261 Pretend that resume was caused by power button */
263 (ACPI_BITMASK_WAKE_STATUS
| ACPI_BITMASK_POWER_BUTTON_STATUS
);
269 uint16_t acpi_pm1_evt_get_sts(ACPIREGS
*ar
)
271 int64_t d
= acpi_pm_tmr_get_clock();
272 if (d
>= ar
->tmr
.overflow_time
) {
273 ar
->pm1
.evt
.sts
|= ACPI_BITMASK_TIMER_STATUS
;
275 return ar
->pm1
.evt
.sts
;
278 void acpi_pm1_evt_write_sts(ACPIREGS
*ar
, uint16_t val
)
280 uint16_t pm1_sts
= acpi_pm1_evt_get_sts(ar
);
281 if (pm1_sts
& val
& ACPI_BITMASK_TIMER_STATUS
) {
282 /* if TMRSTS is reset, then compute the new overflow time */
283 acpi_pm_tmr_calc_overflow_time(ar
);
285 ar
->pm1
.evt
.sts
&= ~val
;
288 void acpi_pm1_evt_write_en(ACPIREGS
*ar
, uint16_t val
)
290 ar
->pm1
.evt
.en
= val
;
291 qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_RTC
,
292 val
& ACPI_BITMASK_RT_CLOCK_ENABLE
);
293 qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_PMTIMER
,
294 val
& ACPI_BITMASK_TIMER_ENABLE
);
297 void acpi_pm1_evt_power_down(ACPIREGS
*ar
)
299 if (ar
->pm1
.evt
.en
& ACPI_BITMASK_POWER_BUTTON_ENABLE
) {
300 ar
->pm1
.evt
.sts
|= ACPI_BITMASK_POWER_BUTTON_STATUS
;
301 ar
->tmr
.update_sci(ar
);
305 void acpi_pm1_evt_reset(ACPIREGS
*ar
)
309 qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_RTC
, 0);
310 qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_PMTIMER
, 0);
314 void acpi_pm_tmr_update(ACPIREGS
*ar
, bool enable
)
318 /* schedule a timer interruption if needed */
320 expire_time
= muldiv64(ar
->tmr
.overflow_time
, get_ticks_per_sec(),
322 qemu_mod_timer(ar
->tmr
.timer
, expire_time
);
324 qemu_del_timer(ar
->tmr
.timer
);
328 void acpi_pm_tmr_calc_overflow_time(ACPIREGS
*ar
)
330 int64_t d
= acpi_pm_tmr_get_clock();
331 ar
->tmr
.overflow_time
= (d
+ 0x800000LL
) & ~0x7fffffLL
;
334 uint32_t acpi_pm_tmr_get(ACPIREGS
*ar
)
336 uint32_t d
= acpi_pm_tmr_get_clock();
340 static void acpi_pm_tmr_timer(void *opaque
)
342 ACPIREGS
*ar
= opaque
;
343 qemu_system_wakeup_request(QEMU_WAKEUP_REASON_PMTIMER
);
344 ar
->tmr
.update_sci(ar
);
347 void acpi_pm_tmr_init(ACPIREGS
*ar
, acpi_update_sci_fn update_sci
)
349 ar
->tmr
.update_sci
= update_sci
;
350 ar
->tmr
.timer
= qemu_new_timer_ns(vm_clock
, acpi_pm_tmr_timer
, ar
);
353 void acpi_pm_tmr_reset(ACPIREGS
*ar
)
355 ar
->tmr
.overflow_time
= 0;
356 qemu_del_timer(ar
->tmr
.timer
);
360 void acpi_pm1_cnt_init(ACPIREGS
*ar
)
362 ar
->wakeup
.notify
= acpi_notify_wakeup
;
363 qemu_register_wakeup_notifier(&ar
->wakeup
);
366 void acpi_pm1_cnt_write(ACPIREGS
*ar
, uint16_t val
, char s4
)
368 ar
->pm1
.cnt
.cnt
= val
& ~(ACPI_BITMASK_SLEEP_ENABLE
);
370 if (val
& ACPI_BITMASK_SLEEP_ENABLE
) {
371 /* change suspend type */
372 uint16_t sus_typ
= (val
>> 10) & 7;
374 case 0: /* soft power off */
375 qemu_system_shutdown_request();
378 qemu_system_suspend_request();
381 if (sus_typ
== s4
) { /* S4 request */
382 monitor_protocol_event(QEVENT_SUSPEND_DISK
, NULL
);
383 qemu_system_shutdown_request();
390 void acpi_pm1_cnt_update(ACPIREGS
*ar
,
391 bool sci_enable
, bool sci_disable
)
393 /* ACPI specs 3.0, 4.7.2.5 */
395 ar
->pm1
.cnt
.cnt
|= ACPI_BITMASK_SCI_ENABLE
;
396 } else if (sci_disable
) {
397 ar
->pm1
.cnt
.cnt
&= ~ACPI_BITMASK_SCI_ENABLE
;
401 void acpi_pm1_cnt_reset(ACPIREGS
*ar
)
407 void acpi_gpe_init(ACPIREGS
*ar
, uint8_t len
)
410 ar
->gpe
.sts
= g_malloc0(len
/ 2);
411 ar
->gpe
.en
= g_malloc0(len
/ 2);
414 void acpi_gpe_blk(ACPIREGS
*ar
, uint32_t blk
)
419 void acpi_gpe_reset(ACPIREGS
*ar
)
421 memset(ar
->gpe
.sts
, 0, ar
->gpe
.len
/ 2);
422 memset(ar
->gpe
.en
, 0, ar
->gpe
.len
/ 2);
425 static uint8_t *acpi_gpe_ioport_get_ptr(ACPIREGS
*ar
, uint32_t addr
)
429 if (addr
< ar
->gpe
.len
/ 2) {
430 cur
= ar
->gpe
.sts
+ addr
;
431 } else if (addr
< ar
->gpe
.len
) {
432 cur
= ar
->gpe
.en
+ addr
- ar
->gpe
.len
/ 2;
440 void acpi_gpe_ioport_writeb(ACPIREGS
*ar
, uint32_t addr
, uint32_t val
)
445 cur
= acpi_gpe_ioport_get_ptr(ar
, addr
);
446 if (addr
< ar
->gpe
.len
/ 2) {
448 *cur
= (*cur
) & ~val
;
449 } else if (addr
< ar
->gpe
.len
) {
457 uint32_t acpi_gpe_ioport_readb(ACPIREGS
*ar
, uint32_t addr
)
463 cur
= acpi_gpe_ioport_get_ptr(ar
, addr
);