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