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 "sysemu.h" 22 #include "hw.h" 23 #include "pc.h" 24 #include "acpi.h" 25 #include "monitor.h" 26 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 */ 39 } QEMU_PACKED; 40 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 */ 43 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) */ 49 ; 50 51 char *acpi_tables; 52 size_t acpi_tables_len; 53 54 static int acpi_checksum(const uint8_t *data, int len) 55 { 56 int sum, i; 57 sum = 0; 58 for (i = 0; i < len; i++) { 59 sum += data[i]; 60 } 61 return (-sum) & 0xff; 62 } 63 64 /* like strncpy() but zero-fills the tail of destination */ 65 static void strzcpy(char *dst, const char *src, size_t size) 66 { 67 size_t len = strlen(src); 68 if (len >= size) { 69 len = size; 70 } else { 71 memset(dst + len, 0, size - len); 72 } 73 memcpy(dst, src, len); 74 } 75 76 /* XXX fixme: this function uses obsolete argument parsing interface */ 77 int acpi_table_add(const char *t) 78 { 79 char buf[1024], *p, *f; 80 unsigned long val; 81 size_t len, start, allen; 82 bool has_header; 83 int changed; 84 int r; 85 struct acpi_table_header hdr; 86 87 r = 0; 88 r |= get_param_value(buf, sizeof(buf), "data", t) ? 1 : 0; 89 r |= get_param_value(buf, sizeof(buf), "file", t) ? 2 : 0; 90 switch (r) { 91 case 0: 92 buf[0] = '\0'; 93 /* fallthrough for default behavior */ 94 case 1: 95 has_header = false; 96 break; 97 case 2: 98 has_header = true; 99 break; 100 default: 101 fprintf(stderr, "acpitable: both data and file are specified\n"); 102 return -1; 103 } 104 105 if (!acpi_tables) { 106 allen = sizeof(uint16_t); 107 acpi_tables = g_malloc0(allen); 108 } else { 109 allen = acpi_tables_len; 110 } 111 112 start = allen; 113 acpi_tables = g_realloc(acpi_tables, start + ACPI_TABLE_HDR_SIZE); 114 allen += has_header ? ACPI_TABLE_PFX_SIZE : ACPI_TABLE_HDR_SIZE; 115 116 /* now read in the data files, reallocating buffer as needed */ 117 118 for (f = strtok(buf, ":"); f; f = strtok(NULL, ":")) { 119 int fd = open(f, O_RDONLY); 120 121 if (fd < 0) { 122 fprintf(stderr, "can't open file %s: %s\n", f, strerror(errno)); 123 return -1; 124 } 125 126 for (;;) { 127 char data[8192]; 128 r = read(fd, data, sizeof(data)); 129 if (r == 0) { 130 break; 131 } else if (r > 0) { 132 acpi_tables = g_realloc(acpi_tables, allen + r); 133 memcpy(acpi_tables + allen, data, r); 134 allen += r; 135 } else if (errno != EINTR) { 136 fprintf(stderr, "can't read file %s: %s\n", 137 f, strerror(errno)); 138 close(fd); 139 return -1; 140 } 141 } 142 143 close(fd); 144 } 145 146 /* now fill in the header fields */ 147 148 f = acpi_tables + start; /* start of the table */ 149 changed = 0; 150 151 /* copy the header to temp place to align the fields */ 152 memcpy(&hdr, has_header ? f : dfl_hdr, ACPI_TABLE_HDR_SIZE); 153 154 /* length of the table minus our prefix */ 155 len = allen - start - ACPI_TABLE_PFX_SIZE; 156 157 hdr._length = cpu_to_le16(len); 158 159 if (get_param_value(buf, sizeof(buf), "sig", t)) { 160 strzcpy(hdr.sig, buf, sizeof(hdr.sig)); 161 ++changed; 162 } 163 164 /* length of the table including header, in bytes */ 165 if (has_header) { 166 /* check if actual length is correct */ 167 val = le32_to_cpu(hdr.length); 168 if (val != len) { 169 fprintf(stderr, 170 "warning: acpitable has wrong length," 171 " header says %lu, actual size %zu bytes\n", 172 val, len); 173 ++changed; 174 } 175 } 176 /* we may avoid putting length here if has_header is true */ 177 hdr.length = cpu_to_le32(len); 178 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); 183 return -1; 184 } 185 hdr.revision = (uint8_t)val; 186 ++changed; 187 } 188 189 if (get_param_value(buf, sizeof(buf), "oem_id", t)) { 190 strzcpy(hdr.oem_id, buf, sizeof(hdr.oem_id)); 191 ++changed; 192 } 193 194 if (get_param_value(buf, sizeof(buf), "oem_table_id", t)) { 195 strzcpy(hdr.oem_table_id, buf, sizeof(hdr.oem_table_id)); 196 ++changed; 197 } 198 199 if (get_param_value(buf, sizeof(buf), "oem_rev", t)) { 200 val = strtol(buf, &p, 0); 201 if (*p) { 202 fprintf(stderr, "acpitable: \"oem_rev=%s\" is invalid\n", buf); 203 return -1; 204 } 205 hdr.oem_revision = cpu_to_le32(val); 206 ++changed; 207 } 208 209 if (get_param_value(buf, sizeof(buf), "asl_compiler_id", t)) { 210 strzcpy(hdr.asl_compiler_id, buf, sizeof(hdr.asl_compiler_id)); 211 ++changed; 212 } 213 214 if (get_param_value(buf, sizeof(buf), "asl_compiler_rev", t)) { 215 val = strtol(buf, &p, 0); 216 if (*p) { 217 fprintf(stderr, "acpitable: \"%s=%s\" is invalid\n", 218 "asl_compiler_rev", buf); 219 return -1; 220 } 221 hdr.asl_compiler_revision = cpu_to_le32(val); 222 ++changed; 223 } 224 225 if (!has_header && !changed) { 226 fprintf(stderr, "warning: acpitable: no table headers are specified\n"); 227 } 228 229 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 */ 234 235 /* put header back */ 236 memcpy(f, &hdr, sizeof(hdr)); 237 238 if (changed || !has_header || 1) { 239 ((struct acpi_table_header *)f)->checksum = 240 acpi_checksum((uint8_t *)f + ACPI_TABLE_PFX_SIZE, len); 241 } 242 243 /* increase number of tables */ 244 (*(uint16_t *)acpi_tables) = 245 cpu_to_le32(le32_to_cpu(*(uint16_t *)acpi_tables) + 1); 246 247 acpi_tables_len = allen; 248 return 0; 249 250 } 251 252 static void acpi_notify_wakeup(Notifier *notifier, void *data) 253 { 254 ACPIREGS *ar = container_of(notifier, ACPIREGS, wakeup); 255 WakeupReason *reason = data; 256 257 switch (*reason) { 258 case QEMU_WAKEUP_REASON_RTC: 259 ar->pm1.evt.sts |= 260 (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_RT_CLOCK_STATUS); 261 break; 262 case QEMU_WAKEUP_REASON_PMTIMER: 263 ar->pm1.evt.sts |= 264 (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_TIMER_STATUS); 265 break; 266 case QEMU_WAKEUP_REASON_OTHER: 267 default: 268 /* ACPI_BITMASK_WAKE_STATUS should be set on resume. 269 Pretend that resume was caused by power button */ 270 ar->pm1.evt.sts |= 271 (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_POWER_BUTTON_STATUS); 272 break; 273 } 274 } 275 276 /* ACPI PM1a EVT */ 277 uint16_t acpi_pm1_evt_get_sts(ACPIREGS *ar) 278 { 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; 282 } 283 return ar->pm1.evt.sts; 284 } 285 286 void acpi_pm1_evt_write_sts(ACPIREGS *ar, uint16_t val) 287 { 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); 292 } 293 ar->pm1.evt.sts &= ~val; 294 } 295 296 void acpi_pm1_evt_write_en(ACPIREGS *ar, uint16_t val) 297 { 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); 303 } 304 305 void acpi_pm1_evt_power_down(ACPIREGS *ar) 306 { 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); 310 } 311 } 312 313 void acpi_pm1_evt_reset(ACPIREGS *ar) 314 { 315 ar->pm1.evt.sts = 0; 316 ar->pm1.evt.en = 0; 317 qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_RTC, 0); 318 qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_PMTIMER, 0); 319 } 320 321 /* ACPI PM_TMR */ 322 void acpi_pm_tmr_update(ACPIREGS *ar, bool enable) 323 { 324 int64_t expire_time; 325 326 /* schedule a timer interruption if needed */ 327 if (enable) { 328 expire_time = muldiv64(ar->tmr.overflow_time, get_ticks_per_sec(), 329 PM_TIMER_FREQUENCY); 330 qemu_mod_timer(ar->tmr.timer, expire_time); 331 } else { 332 qemu_del_timer(ar->tmr.timer); 333 } 334 } 335 336 void acpi_pm_tmr_calc_overflow_time(ACPIREGS *ar) 337 { 338 int64_t d = acpi_pm_tmr_get_clock(); 339 ar->tmr.overflow_time = (d + 0x800000LL) & ~0x7fffffLL; 340 } 341 342 uint32_t acpi_pm_tmr_get(ACPIREGS *ar) 343 { 344 uint32_t d = acpi_pm_tmr_get_clock(); 345 return d & 0xffffff; 346 } 347 348 static void acpi_pm_tmr_timer(void *opaque) 349 { 350 ACPIREGS *ar = opaque; 351 qemu_system_wakeup_request(QEMU_WAKEUP_REASON_PMTIMER); 352 ar->tmr.update_sci(ar); 353 } 354 355 void acpi_pm_tmr_init(ACPIREGS *ar, acpi_update_sci_fn update_sci) 356 { 357 ar->tmr.update_sci = update_sci; 358 ar->tmr.timer = qemu_new_timer_ns(vm_clock, acpi_pm_tmr_timer, ar); 359 } 360 361 void acpi_pm_tmr_reset(ACPIREGS *ar) 362 { 363 ar->tmr.overflow_time = 0; 364 qemu_del_timer(ar->tmr.timer); 365 } 366 367 /* ACPI PM1aCNT */ 368 void acpi_pm1_cnt_init(ACPIREGS *ar) 369 { 370 ar->wakeup.notify = acpi_notify_wakeup; 371 qemu_register_wakeup_notifier(&ar->wakeup); 372 } 373 374 void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val, char s4) 375 { 376 ar->pm1.cnt.cnt = val & ~(ACPI_BITMASK_SLEEP_ENABLE); 377 378 if (val & ACPI_BITMASK_SLEEP_ENABLE) { 379 /* change suspend type */ 380 uint16_t sus_typ = (val >> 10) & 7; 381 switch(sus_typ) { 382 case 0: /* soft power off */ 383 qemu_system_shutdown_request(); 384 break; 385 case 1: 386 qemu_system_suspend_request(); 387 break; 388 default: 389 if (sus_typ == s4) { /* S4 request */ 390 monitor_protocol_event(QEVENT_SUSPEND_DISK, NULL); 391 qemu_system_shutdown_request(); 392 } 393 break; 394 } 395 } 396 } 397 398 void acpi_pm1_cnt_update(ACPIREGS *ar, 399 bool sci_enable, bool sci_disable) 400 { 401 /* ACPI specs 3.0, 4.7.2.5 */ 402 if (sci_enable) { 403 ar->pm1.cnt.cnt |= ACPI_BITMASK_SCI_ENABLE; 404 } else if (sci_disable) { 405 ar->pm1.cnt.cnt &= ~ACPI_BITMASK_SCI_ENABLE; 406 } 407 } 408 409 void acpi_pm1_cnt_reset(ACPIREGS *ar) 410 { 411 ar->pm1.cnt.cnt = 0; 412 } 413 414 /* ACPI GPE */ 415 void acpi_gpe_init(ACPIREGS *ar, uint8_t len) 416 { 417 ar->gpe.len = len; 418 ar->gpe.sts = g_malloc0(len / 2); 419 ar->gpe.en = g_malloc0(len / 2); 420 } 421 422 void acpi_gpe_blk(ACPIREGS *ar, uint32_t blk) 423 { 424 ar->gpe.blk = blk; 425 } 426 427 void acpi_gpe_reset(ACPIREGS *ar) 428 { 429 memset(ar->gpe.sts, 0, ar->gpe.len / 2); 430 memset(ar->gpe.en, 0, ar->gpe.len / 2); 431 } 432 433 static uint8_t *acpi_gpe_ioport_get_ptr(ACPIREGS *ar, uint32_t addr) 434 { 435 uint8_t *cur = NULL; 436 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; 441 } else { 442 abort(); 443 } 444 445 return cur; 446 } 447 448 void acpi_gpe_ioport_writeb(ACPIREGS *ar, uint32_t addr, uint32_t val) 449 { 450 uint8_t *cur; 451 452 addr -= ar->gpe.blk; 453 cur = acpi_gpe_ioport_get_ptr(ar, addr); 454 if (addr < ar->gpe.len / 2) { 455 /* GPE_STS */ 456 *cur = (*cur) & ~val; 457 } else if (addr < ar->gpe.len) { 458 /* GPE_EN */ 459 *cur = val; 460 } else { 461 abort(); 462 } 463 } 464 465 uint32_t acpi_gpe_ioport_readb(ACPIREGS *ar, uint32_t addr) 466 { 467 uint8_t *cur; 468 uint32_t val; 469 470 addr -= ar->gpe.blk; 471 cur = acpi_gpe_ioport_get_ptr(ar, addr); 472 val = 0; 473 if (cur != NULL) { 474 val = *cur; 475 } 476 477 return val; 478 } 479