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 /* like strncpy() but zero-fills the tail of destination */
65 static void strzcpy(char *dst
, const char *src
, size_t size
)
67 size_t len
= strlen(src
);
71 memset(dst
+ len
, 0, size
- len
);
73 memcpy(dst
, src
, len
);
76 /* XXX fixme: this function uses obsolete argument parsing interface */
77 int acpi_table_add(const char *t
)
79 char buf
[1024], *p
, *f
;
81 size_t len
, start
, allen
;
85 struct acpi_table_header hdr
;
88 r
|= get_param_value(buf
, sizeof(buf
), "data", t
) ? 1 : 0;
89 r
|= get_param_value(buf
, sizeof(buf
), "file", t
) ? 2 : 0;
93 /* fallthrough for default behavior */
101 fprintf(stderr
, "acpitable: both data and file are specified\n");
106 allen
= sizeof(uint16_t);
107 acpi_tables
= g_malloc0(allen
);
109 allen
= acpi_tables_len
;
113 acpi_tables
= g_realloc(acpi_tables
, start
+ ACPI_TABLE_HDR_SIZE
);
114 allen
+= has_header
? ACPI_TABLE_PFX_SIZE
: ACPI_TABLE_HDR_SIZE
;
116 /* now read in the data files, reallocating buffer as needed */
118 for (f
= strtok(buf
, ":"); f
; f
= strtok(NULL
, ":")) {
119 int fd
= open(f
, O_RDONLY
);
122 fprintf(stderr
, "can't open file %s: %s\n", f
, strerror(errno
));
128 r
= read(fd
, data
, sizeof(data
));
132 acpi_tables
= g_realloc(acpi_tables
, allen
+ r
);
133 memcpy(acpi_tables
+ allen
, data
, r
);
135 } else if (errno
!= EINTR
) {
136 fprintf(stderr
, "can't read file %s: %s\n",
146 /* now fill in the header fields */
148 f
= acpi_tables
+ start
; /* start of the table */
151 /* copy the header to temp place to align the fields */
152 memcpy(&hdr
, has_header
? f
: dfl_hdr
, ACPI_TABLE_HDR_SIZE
);
154 /* length of the table minus our prefix */
155 len
= allen
- start
- ACPI_TABLE_PFX_SIZE
;
157 hdr
._length
= cpu_to_le16(len
);
159 if (get_param_value(buf
, sizeof(buf
), "sig", t
)) {
160 strzcpy(hdr
.sig
, buf
, sizeof(hdr
.sig
));
164 /* length of the table including header, in bytes */
166 /* check if actual length is correct */
167 val
= le32_to_cpu(hdr
.length
);
170 "warning: acpitable has wrong length,"
171 " header says %lu, actual size %zu bytes\n",
176 /* we may avoid putting length here if has_header is true */
177 hdr
.length
= cpu_to_le32(len
);
179 if (get_param_value(buf
, sizeof(buf
), "rev", t
)) {
180 val
= strtoul(buf
, &p
, 0);
181 if (val
> 255 || *p
) {
182 fprintf(stderr
, "acpitable: \"rev=%s\" is invalid\n", buf
);
185 hdr
.revision
= (uint8_t)val
;
189 if (get_param_value(buf
, sizeof(buf
), "oem_id", t
)) {
190 strzcpy(hdr
.oem_id
, buf
, sizeof(hdr
.oem_id
));
194 if (get_param_value(buf
, sizeof(buf
), "oem_table_id", t
)) {
195 strzcpy(hdr
.oem_table_id
, buf
, sizeof(hdr
.oem_table_id
));
199 if (get_param_value(buf
, sizeof(buf
), "oem_rev", t
)) {
200 val
= strtol(buf
, &p
, 0);
202 fprintf(stderr
, "acpitable: \"oem_rev=%s\" is invalid\n", buf
);
205 hdr
.oem_revision
= cpu_to_le32(val
);
209 if (get_param_value(buf
, sizeof(buf
), "asl_compiler_id", t
)) {
210 strzcpy(hdr
.asl_compiler_id
, buf
, sizeof(hdr
.asl_compiler_id
));
214 if (get_param_value(buf
, sizeof(buf
), "asl_compiler_rev", t
)) {
215 val
= strtol(buf
, &p
, 0);
217 fprintf(stderr
, "acpitable: \"%s=%s\" is invalid\n",
218 "asl_compiler_rev", buf
);
221 hdr
.asl_compiler_revision
= cpu_to_le32(val
);
225 if (!has_header
&& !changed
) {
226 fprintf(stderr
, "warning: acpitable: no table headers are specified\n");
230 /* now calculate checksum of the table, complete with the header */
231 /* we may as well leave checksum intact if has_header is true */
232 /* alternatively there may be a way to set cksum to a given value */
233 hdr
.checksum
= 0; /* for checksum calculation */
235 /* put header back */
236 memcpy(f
, &hdr
, sizeof(hdr
));
238 if (changed
|| !has_header
|| 1) {
239 ((struct acpi_table_header
*)f
)->checksum
=
240 acpi_checksum((uint8_t *)f
+ ACPI_TABLE_PFX_SIZE
, len
);
243 /* increase number of tables */
244 (*(uint16_t *)acpi_tables
) =
245 cpu_to_le32(le32_to_cpu(*(uint16_t *)acpi_tables
) + 1);
247 acpi_tables_len
= allen
;
252 static void acpi_notify_wakeup(Notifier
*notifier
, void *data
)
254 ACPIREGS
*ar
= container_of(notifier
, ACPIREGS
, wakeup
);
255 WakeupReason
*reason
= data
;
258 case QEMU_WAKEUP_REASON_RTC
:
260 (ACPI_BITMASK_WAKE_STATUS
| ACPI_BITMASK_RT_CLOCK_STATUS
);
262 case QEMU_WAKEUP_REASON_PMTIMER
:
264 (ACPI_BITMASK_WAKE_STATUS
| ACPI_BITMASK_TIMER_STATUS
);
266 case QEMU_WAKEUP_REASON_OTHER
:
268 /* ACPI_BITMASK_WAKE_STATUS should be set on resume.
269 Pretend that resume was caused by power button */
271 (ACPI_BITMASK_WAKE_STATUS
| ACPI_BITMASK_POWER_BUTTON_STATUS
);
277 uint16_t acpi_pm1_evt_get_sts(ACPIREGS
*ar
)
279 int64_t d
= acpi_pm_tmr_get_clock();
280 if (d
>= ar
->tmr
.overflow_time
) {
281 ar
->pm1
.evt
.sts
|= ACPI_BITMASK_TIMER_STATUS
;
283 return ar
->pm1
.evt
.sts
;
286 void acpi_pm1_evt_write_sts(ACPIREGS
*ar
, uint16_t val
)
288 uint16_t pm1_sts
= acpi_pm1_evt_get_sts(ar
);
289 if (pm1_sts
& val
& ACPI_BITMASK_TIMER_STATUS
) {
290 /* if TMRSTS is reset, then compute the new overflow time */
291 acpi_pm_tmr_calc_overflow_time(ar
);
293 ar
->pm1
.evt
.sts
&= ~val
;
296 void acpi_pm1_evt_write_en(ACPIREGS
*ar
, uint16_t val
)
298 ar
->pm1
.evt
.en
= val
;
299 qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_RTC
,
300 val
& ACPI_BITMASK_RT_CLOCK_ENABLE
);
301 qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_PMTIMER
,
302 val
& ACPI_BITMASK_TIMER_ENABLE
);
305 void acpi_pm1_evt_power_down(ACPIREGS
*ar
)
307 if (ar
->pm1
.evt
.en
& ACPI_BITMASK_POWER_BUTTON_ENABLE
) {
308 ar
->pm1
.evt
.sts
|= ACPI_BITMASK_POWER_BUTTON_STATUS
;
309 ar
->tmr
.update_sci(ar
);
313 void acpi_pm1_evt_reset(ACPIREGS
*ar
)
317 qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_RTC
, 0);
318 qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_PMTIMER
, 0);
322 void acpi_pm_tmr_update(ACPIREGS
*ar
, bool enable
)
326 /* schedule a timer interruption if needed */
328 expire_time
= muldiv64(ar
->tmr
.overflow_time
, get_ticks_per_sec(),
330 qemu_mod_timer(ar
->tmr
.timer
, expire_time
);
332 qemu_del_timer(ar
->tmr
.timer
);
336 void acpi_pm_tmr_calc_overflow_time(ACPIREGS
*ar
)
338 int64_t d
= acpi_pm_tmr_get_clock();
339 ar
->tmr
.overflow_time
= (d
+ 0x800000LL
) & ~0x7fffffLL
;
342 uint32_t acpi_pm_tmr_get(ACPIREGS
*ar
)
344 uint32_t d
= acpi_pm_tmr_get_clock();
348 static void acpi_pm_tmr_timer(void *opaque
)
350 ACPIREGS
*ar
= opaque
;
351 qemu_system_wakeup_request(QEMU_WAKEUP_REASON_PMTIMER
);
352 ar
->tmr
.update_sci(ar
);
355 void acpi_pm_tmr_init(ACPIREGS
*ar
, acpi_update_sci_fn update_sci
)
357 ar
->tmr
.update_sci
= update_sci
;
358 ar
->tmr
.timer
= qemu_new_timer_ns(vm_clock
, acpi_pm_tmr_timer
, ar
);
361 void acpi_pm_tmr_reset(ACPIREGS
*ar
)
363 ar
->tmr
.overflow_time
= 0;
364 qemu_del_timer(ar
->tmr
.timer
);
368 void acpi_pm1_cnt_init(ACPIREGS
*ar
)
370 ar
->wakeup
.notify
= acpi_notify_wakeup
;
371 qemu_register_wakeup_notifier(&ar
->wakeup
);
374 void acpi_pm1_cnt_write(ACPIREGS
*ar
, uint16_t val
, char s4
)
376 ar
->pm1
.cnt
.cnt
= val
& ~(ACPI_BITMASK_SLEEP_ENABLE
);
378 if (val
& ACPI_BITMASK_SLEEP_ENABLE
) {
379 /* change suspend type */
380 uint16_t sus_typ
= (val
>> 10) & 7;
382 case 0: /* soft power off */
383 qemu_system_shutdown_request();
386 qemu_system_suspend_request();
389 if (sus_typ
== s4
) { /* S4 request */
390 monitor_protocol_event(QEVENT_SUSPEND_DISK
, NULL
);
391 qemu_system_shutdown_request();
398 void acpi_pm1_cnt_update(ACPIREGS
*ar
,
399 bool sci_enable
, bool sci_disable
)
401 /* ACPI specs 3.0, 4.7.2.5 */
403 ar
->pm1
.cnt
.cnt
|= ACPI_BITMASK_SCI_ENABLE
;
404 } else if (sci_disable
) {
405 ar
->pm1
.cnt
.cnt
&= ~ACPI_BITMASK_SCI_ENABLE
;
409 void acpi_pm1_cnt_reset(ACPIREGS
*ar
)
415 void acpi_gpe_init(ACPIREGS
*ar
, uint8_t len
)
418 ar
->gpe
.sts
= g_malloc0(len
/ 2);
419 ar
->gpe
.en
= g_malloc0(len
/ 2);
422 void acpi_gpe_blk(ACPIREGS
*ar
, uint32_t blk
)
427 void acpi_gpe_reset(ACPIREGS
*ar
)
429 memset(ar
->gpe
.sts
, 0, ar
->gpe
.len
/ 2);
430 memset(ar
->gpe
.en
, 0, ar
->gpe
.len
/ 2);
433 static uint8_t *acpi_gpe_ioport_get_ptr(ACPIREGS
*ar
, uint32_t addr
)
437 if (addr
< ar
->gpe
.len
/ 2) {
438 cur
= ar
->gpe
.sts
+ addr
;
439 } else if (addr
< ar
->gpe
.len
) {
440 cur
= ar
->gpe
.en
+ addr
- ar
->gpe
.len
/ 2;
448 void acpi_gpe_ioport_writeb(ACPIREGS
*ar
, uint32_t addr
, uint32_t val
)
453 cur
= acpi_gpe_ioport_get_ptr(ar
, addr
);
454 if (addr
< ar
->gpe
.len
/ 2) {
456 *cur
= (*cur
) & ~val
;
457 } else if (addr
< ar
->gpe
.len
) {
465 uint32_t acpi_gpe_ioport_readb(ACPIREGS
*ar
, uint32_t addr
)
471 cur
= acpi_gpe_ioport_get_ptr(ar
, addr
);