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.
26 struct acpi_table_header
{
27 uint16_t _length
; /* our length, not actual part of the hdr */
28 /* XXX why we have 2 length fields here? */
29 char sig
[4]; /* ACPI signature (4 ASCII characters) */
30 uint32_t length
; /* Length of table, in bytes, including header */
31 uint8_t revision
; /* ACPI Specification minor version # */
32 uint8_t checksum
; /* To make sum of entire table == 0 */
33 char oem_id
[6]; /* OEM identification */
34 char oem_table_id
[8]; /* OEM table identification */
35 uint32_t oem_revision
; /* OEM revision number */
36 char asl_compiler_id
[4]; /* ASL compiler vendor ID */
37 uint32_t asl_compiler_revision
; /* ASL compiler revision number */
40 #define ACPI_TABLE_HDR_SIZE sizeof(struct acpi_table_header)
41 #define ACPI_TABLE_PFX_SIZE sizeof(uint16_t) /* size of the extra prefix */
43 static const char dfl_hdr
[ACPI_TABLE_HDR_SIZE
] =
44 "\0\0" /* fake _length (2) */
45 "QEMU\0\0\0\0\1\0" /* sig (4), len(4), revno (1), csum (1) */
46 "QEMUQEQEMUQEMU\1\0\0\0" /* OEM id (6), table (8), revno (4) */
47 "QEMU\1\0\0\0" /* ASL compiler ID (4), version (4) */
51 size_t acpi_tables_len
;
53 static int acpi_checksum(const uint8_t *data
, int len
)
57 for (i
= 0; i
< len
; i
++) {
63 /* like strncpy() but zero-fills the tail of destination */
64 static void strzcpy(char *dst
, const char *src
, size_t size
)
66 size_t len
= strlen(src
);
70 memset(dst
+ len
, 0, size
- len
);
72 memcpy(dst
, src
, len
);
75 /* XXX fixme: this function uses obsolete argument parsing interface */
76 int acpi_table_add(const char *t
)
78 char buf
[1024], *p
, *f
;
80 size_t len
, start
, allen
;
84 struct acpi_table_header hdr
;
87 r
|= get_param_value(buf
, sizeof(buf
), "data", t
) ? 1 : 0;
88 r
|= get_param_value(buf
, sizeof(buf
), "file", t
) ? 2 : 0;
92 /* fallthrough for default behavior */
100 fprintf(stderr
, "acpitable: both data and file are specified\n");
105 allen
= sizeof(uint16_t);
106 acpi_tables
= g_malloc0(allen
);
108 allen
= acpi_tables_len
;
112 acpi_tables
= g_realloc(acpi_tables
, start
+ ACPI_TABLE_HDR_SIZE
);
113 allen
+= has_header
? ACPI_TABLE_PFX_SIZE
: ACPI_TABLE_HDR_SIZE
;
115 /* now read in the data files, reallocating buffer as needed */
117 for (f
= strtok(buf
, ":"); f
; f
= strtok(NULL
, ":")) {
118 int fd
= open(f
, O_RDONLY
);
121 fprintf(stderr
, "can't open file %s: %s\n", f
, strerror(errno
));
127 r
= read(fd
, data
, sizeof(data
));
131 acpi_tables
= g_realloc(acpi_tables
, allen
+ r
);
132 memcpy(acpi_tables
+ allen
, data
, r
);
134 } else if (errno
!= EINTR
) {
135 fprintf(stderr
, "can't read file %s: %s\n",
145 /* now fill in the header fields */
147 f
= acpi_tables
+ start
; /* start of the table */
150 /* copy the header to temp place to align the fields */
151 memcpy(&hdr
, has_header
? f
: dfl_hdr
, ACPI_TABLE_HDR_SIZE
);
153 /* length of the table minus our prefix */
154 len
= allen
- start
- ACPI_TABLE_PFX_SIZE
;
156 hdr
._length
= cpu_to_le16(len
);
158 if (get_param_value(buf
, sizeof(buf
), "sig", t
)) {
159 strzcpy(hdr
.sig
, buf
, sizeof(hdr
.sig
));
163 /* length of the table including header, in bytes */
165 /* check if actual length is correct */
166 val
= le32_to_cpu(hdr
.length
);
169 "warning: acpitable has wrong length,"
170 " header says %lu, actual size %zu bytes\n",
175 /* we may avoid putting length here if has_header is true */
176 hdr
.length
= cpu_to_le32(len
);
178 if (get_param_value(buf
, sizeof(buf
), "rev", t
)) {
179 val
= strtoul(buf
, &p
, 0);
180 if (val
> 255 || *p
) {
181 fprintf(stderr
, "acpitable: \"rev=%s\" is invalid\n", buf
);
184 hdr
.revision
= (uint8_t)val
;
188 if (get_param_value(buf
, sizeof(buf
), "oem_id", t
)) {
189 strzcpy(hdr
.oem_id
, buf
, sizeof(hdr
.oem_id
));
193 if (get_param_value(buf
, sizeof(buf
), "oem_table_id", t
)) {
194 strzcpy(hdr
.oem_table_id
, buf
, sizeof(hdr
.oem_table_id
));
198 if (get_param_value(buf
, sizeof(buf
), "oem_rev", t
)) {
199 val
= strtol(buf
, &p
, 0);
201 fprintf(stderr
, "acpitable: \"oem_rev=%s\" is invalid\n", buf
);
204 hdr
.oem_revision
= cpu_to_le32(val
);
208 if (get_param_value(buf
, sizeof(buf
), "asl_compiler_id", t
)) {
209 strzcpy(hdr
.asl_compiler_id
, buf
, sizeof(hdr
.asl_compiler_id
));
213 if (get_param_value(buf
, sizeof(buf
), "asl_compiler_rev", t
)) {
214 val
= strtol(buf
, &p
, 0);
216 fprintf(stderr
, "acpitable: \"%s=%s\" is invalid\n",
217 "asl_compiler_rev", buf
);
220 hdr
.asl_compiler_revision
= cpu_to_le32(val
);
224 if (!has_header
&& !changed
) {
225 fprintf(stderr
, "warning: acpitable: no table headers are specified\n");
229 /* now calculate checksum of the table, complete with the header */
230 /* we may as well leave checksum intact if has_header is true */
231 /* alternatively there may be a way to set cksum to a given value */
232 hdr
.checksum
= 0; /* for checksum calculation */
234 /* put header back */
235 memcpy(f
, &hdr
, sizeof(hdr
));
237 if (changed
|| !has_header
|| 1) {
238 ((struct acpi_table_header
*)f
)->checksum
=
239 acpi_checksum((uint8_t *)f
+ ACPI_TABLE_PFX_SIZE
, len
);
242 /* increase number of tables */
243 (*(uint16_t *)acpi_tables
) =
244 cpu_to_le32(le32_to_cpu(*(uint16_t *)acpi_tables
) + 1);
246 acpi_tables_len
= allen
;
251 static void acpi_notify_wakeup(Notifier
*notifier
, void *data
)
253 ACPIREGS
*ar
= container_of(notifier
, ACPIREGS
, wakeup
);
254 WakeupReason
*reason
= data
;
257 case QEMU_WAKEUP_REASON_RTC
:
259 (ACPI_BITMASK_WAKE_STATUS
| ACPI_BITMASK_RT_CLOCK_STATUS
);
261 case QEMU_WAKEUP_REASON_PMTIMER
:
263 (ACPI_BITMASK_WAKE_STATUS
| ACPI_BITMASK_TIMER_STATUS
);
265 case QEMU_WAKEUP_REASON_OTHER
:
267 /* ACPI_BITMASK_WAKE_STATUS should be set on resume.
268 Pretend that resume was caused by power button */
270 (ACPI_BITMASK_WAKE_STATUS
| ACPI_BITMASK_POWER_BUTTON_STATUS
);
276 uint16_t acpi_pm1_evt_get_sts(ACPIREGS
*ar
)
278 int64_t d
= acpi_pm_tmr_get_clock();
279 if (d
>= ar
->tmr
.overflow_time
) {
280 ar
->pm1
.evt
.sts
|= ACPI_BITMASK_TIMER_STATUS
;
282 return ar
->pm1
.evt
.sts
;
285 void acpi_pm1_evt_write_sts(ACPIREGS
*ar
, uint16_t val
)
287 uint16_t pm1_sts
= acpi_pm1_evt_get_sts(ar
);
288 if (pm1_sts
& val
& ACPI_BITMASK_TIMER_STATUS
) {
289 /* if TMRSTS is reset, then compute the new overflow time */
290 acpi_pm_tmr_calc_overflow_time(ar
);
292 ar
->pm1
.evt
.sts
&= ~val
;
295 void acpi_pm1_evt_write_en(ACPIREGS
*ar
, uint16_t val
)
297 ar
->pm1
.evt
.en
= val
;
298 qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_RTC
,
299 val
& ACPI_BITMASK_RT_CLOCK_ENABLE
);
300 qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_PMTIMER
,
301 val
& ACPI_BITMASK_TIMER_ENABLE
);
304 void acpi_pm1_evt_power_down(ACPIREGS
*ar
)
306 if (ar
->pm1
.evt
.en
& ACPI_BITMASK_POWER_BUTTON_ENABLE
) {
307 ar
->pm1
.evt
.sts
|= ACPI_BITMASK_POWER_BUTTON_STATUS
;
308 ar
->tmr
.update_sci(ar
);
312 void acpi_pm1_evt_reset(ACPIREGS
*ar
)
316 qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_RTC
, 0);
317 qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_PMTIMER
, 0);
321 void acpi_pm_tmr_update(ACPIREGS
*ar
, bool enable
)
325 /* schedule a timer interruption if needed */
327 expire_time
= muldiv64(ar
->tmr
.overflow_time
, get_ticks_per_sec(),
329 qemu_mod_timer(ar
->tmr
.timer
, expire_time
);
331 qemu_del_timer(ar
->tmr
.timer
);
335 void acpi_pm_tmr_calc_overflow_time(ACPIREGS
*ar
)
337 int64_t d
= acpi_pm_tmr_get_clock();
338 ar
->tmr
.overflow_time
= (d
+ 0x800000LL
) & ~0x7fffffLL
;
341 uint32_t acpi_pm_tmr_get(ACPIREGS
*ar
)
343 uint32_t d
= acpi_pm_tmr_get_clock();
347 static void acpi_pm_tmr_timer(void *opaque
)
349 ACPIREGS
*ar
= opaque
;
350 qemu_system_wakeup_request(QEMU_WAKEUP_REASON_PMTIMER
);
351 ar
->tmr
.update_sci(ar
);
354 void acpi_pm_tmr_init(ACPIREGS
*ar
, acpi_update_sci_fn update_sci
)
356 ar
->tmr
.update_sci
= update_sci
;
357 ar
->tmr
.timer
= qemu_new_timer_ns(vm_clock
, acpi_pm_tmr_timer
, ar
);
360 void acpi_pm_tmr_reset(ACPIREGS
*ar
)
362 ar
->tmr
.overflow_time
= 0;
363 qemu_del_timer(ar
->tmr
.timer
);
367 void acpi_pm1_cnt_init(ACPIREGS
*ar
)
369 ar
->wakeup
.notify
= acpi_notify_wakeup
;
370 qemu_register_wakeup_notifier(&ar
->wakeup
);
373 void acpi_pm1_cnt_write(ACPIREGS
*ar
, uint16_t val
, char s4
)
375 ar
->pm1
.cnt
.cnt
= val
& ~(ACPI_BITMASK_SLEEP_ENABLE
);
377 if (val
& ACPI_BITMASK_SLEEP_ENABLE
) {
378 /* change suspend type */
379 uint16_t sus_typ
= (val
>> 10) & 7;
381 case 0: /* soft power off */
382 qemu_system_shutdown_request();
385 qemu_system_suspend_request();
388 if (sus_typ
== s4
) { /* S4 request */
389 qemu_system_shutdown_request();
396 void acpi_pm1_cnt_update(ACPIREGS
*ar
,
397 bool sci_enable
, bool sci_disable
)
399 /* ACPI specs 3.0, 4.7.2.5 */
401 ar
->pm1
.cnt
.cnt
|= ACPI_BITMASK_SCI_ENABLE
;
402 } else if (sci_disable
) {
403 ar
->pm1
.cnt
.cnt
&= ~ACPI_BITMASK_SCI_ENABLE
;
407 void acpi_pm1_cnt_reset(ACPIREGS
*ar
)
413 void acpi_gpe_init(ACPIREGS
*ar
, uint8_t len
)
416 ar
->gpe
.sts
= g_malloc0(len
/ 2);
417 ar
->gpe
.en
= g_malloc0(len
/ 2);
420 void acpi_gpe_blk(ACPIREGS
*ar
, uint32_t blk
)
425 void acpi_gpe_reset(ACPIREGS
*ar
)
427 memset(ar
->gpe
.sts
, 0, ar
->gpe
.len
/ 2);
428 memset(ar
->gpe
.en
, 0, ar
->gpe
.len
/ 2);
431 static uint8_t *acpi_gpe_ioport_get_ptr(ACPIREGS
*ar
, uint32_t addr
)
435 if (addr
< ar
->gpe
.len
/ 2) {
436 cur
= ar
->gpe
.sts
+ addr
;
437 } else if (addr
< ar
->gpe
.len
) {
438 cur
= ar
->gpe
.en
+ addr
- ar
->gpe
.len
/ 2;
446 void acpi_gpe_ioport_writeb(ACPIREGS
*ar
, uint32_t addr
, uint32_t val
)
451 cur
= acpi_gpe_ioport_get_ptr(ar
, addr
);
452 if (addr
< ar
->gpe
.len
/ 2) {
454 *cur
= (*cur
) & ~val
;
455 } else if (addr
< ar
->gpe
.len
) {
463 uint32_t acpi_gpe_ioport_readb(ACPIREGS
*ar
, uint32_t addr
)
469 cur
= acpi_gpe_ioport_get_ptr(ar
, addr
);