|
|
1.1 ! root 1: /* ! 2: * GRUB -- GRand Unified Bootloader ! 3: * Copyright (C) 2010 Free Software Foundation, Inc. ! 4: * ! 5: * GRUB is free software: you can redistribute it and/or modify ! 6: * it under the terms of the GNU General Public License as published by ! 7: * the Free Software Foundation, either version 3 of the License, or ! 8: * (at your option) any later version. ! 9: * ! 10: * GRUB 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 ! 13: * GNU General Public License for more details. ! 14: * ! 15: * You should have received a copy of the GNU General Public License ! 16: * along with GRUB. If not, see <http://www.gnu.org/licenses/>. ! 17: */ ! 18: ! 19: #include <grub/glue.h> ! 20: ! 21: #ifdef GRUB_DSDT_TEST ! 22: #include <stdio.h> ! 23: #include <unistd.h> ! 24: #include <stdlib.h> ! 25: #include <stdint.h> ! 26: #include <string.h> ! 27: #include <errno.h> ! 28: ! 29: #define grub_dprintf(cond, args...) printf ( args ) ! 30: #define grub_printf printf ! 31: typedef uint64_t grub_uint64_t; ! 32: typedef uint32_t grub_uint32_t; ! 33: typedef uint16_t grub_uint16_t; ! 34: typedef uint8_t grub_uint8_t; ! 35: ! 36: #endif ! 37: ! 38: #include <grub/acpi.h> ! 39: #ifndef GRUB_DSDT_TEST ! 40: #include <grub/i18n.h> ! 41: #else ! 42: #define _(x) x ! 43: #define N_(x) x ! 44: #endif ! 45: ! 46: #ifndef GRUB_DSDT_TEST ! 47: #include <grub/mm.h> ! 48: #include <grub/misc.h> ! 49: #include <grub/time.h> ! 50: #include <grub/cpu/io.h> ! 51: #endif ! 52: ! 53: static inline grub_uint32_t ! 54: decode_length (const grub_uint8_t *ptr, int *numlen) ! 55: { ! 56: int num_bytes, i; ! 57: grub_uint32_t ret; ! 58: if (*ptr < 64) ! 59: { ! 60: if (numlen) ! 61: *numlen = 1; ! 62: return *ptr; ! 63: } ! 64: num_bytes = *ptr >> 6; ! 65: if (numlen) ! 66: *numlen = num_bytes + 1; ! 67: ret = *ptr & 0xf; ! 68: ptr++; ! 69: for (i = 0; i < num_bytes; i++) ! 70: { ! 71: ret |= *ptr << (8 * i + 4); ! 72: ptr++; ! 73: } ! 74: return ret; ! 75: } ! 76: ! 77: static inline grub_uint32_t ! 78: skip_name_string (const grub_uint8_t *ptr, const grub_uint8_t *end) ! 79: { ! 80: const grub_uint8_t *ptr0 = ptr; ! 81: ! 82: while (ptr < end && (*ptr == '^' || *ptr == '\\')) ! 83: ptr++; ! 84: switch (*ptr) ! 85: { ! 86: case '.': ! 87: ptr++; ! 88: ptr += 8; ! 89: break; ! 90: case '/': ! 91: ptr++; ! 92: ptr += 1 + (*ptr) * 4; ! 93: break; ! 94: case 0: ! 95: ptr++; ! 96: break; ! 97: default: ! 98: ptr += 4; ! 99: break; ! 100: } ! 101: return ptr - ptr0; ! 102: } ! 103: ! 104: static inline grub_uint32_t ! 105: skip_data_ref_object (const grub_uint8_t *ptr, const grub_uint8_t *end) ! 106: { ! 107: grub_dprintf ("acpi", "data type = 0x%x\n", *ptr); ! 108: switch (*ptr) ! 109: { ! 110: case GRUB_ACPI_OPCODE_PACKAGE: ! 111: case GRUB_ACPI_OPCODE_BUFFER: ! 112: return 1 + decode_length (ptr + 1, 0); ! 113: case GRUB_ACPI_OPCODE_ZERO: ! 114: case GRUB_ACPI_OPCODE_ONES: ! 115: case GRUB_ACPI_OPCODE_ONE: ! 116: return 1; ! 117: case GRUB_ACPI_OPCODE_BYTE_CONST: ! 118: return 2; ! 119: case GRUB_ACPI_OPCODE_WORD_CONST: ! 120: return 3; ! 121: case GRUB_ACPI_OPCODE_DWORD_CONST: ! 122: return 5; ! 123: case GRUB_ACPI_OPCODE_STRING_CONST: ! 124: { ! 125: const grub_uint8_t *ptr0 = ptr; ! 126: for (ptr++; ptr < end && *ptr; ptr++); ! 127: if (ptr == end) ! 128: return 0; ! 129: return ptr - ptr0 + 1; ! 130: } ! 131: default: ! 132: if (*ptr == '^' || *ptr == '\\' || *ptr == '_' ! 133: || (*ptr >= 'A' && *ptr <= 'Z')) ! 134: return skip_name_string (ptr, end); ! 135: grub_printf ("Unknown opcode 0x%x\n", *ptr); ! 136: return 0; ! 137: } ! 138: } ! 139: ! 140: static inline grub_uint32_t ! 141: skip_ext_op (const grub_uint8_t *ptr, const grub_uint8_t *end) ! 142: { ! 143: const grub_uint8_t *ptr0 = ptr; ! 144: int add; ! 145: grub_dprintf ("acpi", "Extended opcode: 0x%x\n", *ptr); ! 146: switch (*ptr) ! 147: { ! 148: case GRUB_ACPI_EXTOPCODE_MUTEX: ! 149: ptr++; ! 150: ptr += skip_name_string (ptr, end); ! 151: ptr++; ! 152: break; ! 153: case GRUB_ACPI_EXTOPCODE_EVENT_OP: ! 154: ptr++; ! 155: ptr += skip_name_string (ptr, end); ! 156: break; ! 157: case GRUB_ACPI_EXTOPCODE_OPERATION_REGION: ! 158: ptr++; ! 159: ptr += skip_name_string (ptr, end); ! 160: ptr++; ! 161: ptr += add = skip_data_ref_object (ptr, end); ! 162: if (!add) ! 163: return 0; ! 164: ptr += add = skip_data_ref_object (ptr, end); ! 165: if (!add) ! 166: return 0; ! 167: break; ! 168: case GRUB_ACPI_EXTOPCODE_FIELD_OP: ! 169: case GRUB_ACPI_EXTOPCODE_DEVICE_OP: ! 170: case GRUB_ACPI_EXTOPCODE_PROCESSOR_OP: ! 171: case GRUB_ACPI_EXTOPCODE_POWER_RES_OP: ! 172: case GRUB_ACPI_EXTOPCODE_THERMAL_ZONE_OP: ! 173: case GRUB_ACPI_EXTOPCODE_INDEX_FIELD_OP: ! 174: case GRUB_ACPI_EXTOPCODE_BANK_FIELD_OP: ! 175: ptr++; ! 176: ptr += decode_length (ptr, 0); ! 177: break; ! 178: default: ! 179: grub_printf ("Unexpected extended opcode: 0x%x\n", *ptr); ! 180: return 0; ! 181: } ! 182: return ptr - ptr0; ! 183: } ! 184: ! 185: static int ! 186: get_sleep_type (grub_uint8_t *table, grub_uint8_t *ptr, grub_uint8_t *end, ! 187: grub_uint8_t *scope, int scope_len) ! 188: { ! 189: grub_uint8_t *prev = table; ! 190: ! 191: if (!ptr) ! 192: ptr = table + sizeof (struct grub_acpi_table_header); ! 193: while (ptr < end && prev < ptr) ! 194: { ! 195: int add; ! 196: prev = ptr; ! 197: grub_dprintf ("acpi", "Opcode 0x%x\n", *ptr); ! 198: grub_dprintf ("acpi", "Tell %x\n", (unsigned) (ptr - table)); ! 199: switch (*ptr) ! 200: { ! 201: case GRUB_ACPI_OPCODE_EXTOP: ! 202: ptr++; ! 203: ptr += add = skip_ext_op (ptr, end); ! 204: if (!add) ! 205: return -1; ! 206: break; ! 207: case GRUB_ACPI_OPCODE_CREATE_WORD_FIELD: ! 208: case GRUB_ACPI_OPCODE_CREATE_BYTE_FIELD: ! 209: { ! 210: ptr += 5; ! 211: ptr += add = skip_data_ref_object (ptr, end); ! 212: if (!add) ! 213: return -1; ! 214: ptr += 4; ! 215: break; ! 216: } ! 217: case GRUB_ACPI_OPCODE_NAME: ! 218: ptr++; ! 219: if ((!scope || grub_memcmp (scope, "\\", scope_len) == 0) && ! 220: (grub_memcmp (ptr, "_S5_", 4) == 0 || grub_memcmp (ptr, "\\_S5_", 4) == 0)) ! 221: { ! 222: int ll; ! 223: grub_uint8_t *ptr2 = ptr; ! 224: grub_dprintf ("acpi", "S5 found\n"); ! 225: ptr2 += skip_name_string (ptr, end); ! 226: if (*ptr2 != 0x12) ! 227: { ! 228: grub_printf ("Unknown opcode in _S5: 0x%x\n", *ptr2); ! 229: return -1; ! 230: } ! 231: ptr2++; ! 232: decode_length (ptr2, &ll); ! 233: ptr2 += ll; ! 234: ptr2++; ! 235: switch (*ptr2) ! 236: { ! 237: case GRUB_ACPI_OPCODE_ZERO: ! 238: return 0; ! 239: case GRUB_ACPI_OPCODE_ONE: ! 240: return 1; ! 241: case GRUB_ACPI_OPCODE_BYTE_CONST: ! 242: return ptr2[1]; ! 243: default: ! 244: grub_printf ("Unknown data type in _S5: 0x%x\n", *ptr2); ! 245: return -1; ! 246: } ! 247: } ! 248: ptr += add = skip_name_string (ptr, end); ! 249: if (!add) ! 250: return -1; ! 251: ptr += add = skip_data_ref_object (ptr, end); ! 252: if (!add) ! 253: return -1; ! 254: break; ! 255: case GRUB_ACPI_OPCODE_SCOPE: ! 256: { ! 257: int scope_sleep_type; ! 258: int ll; ! 259: grub_uint8_t *name; ! 260: int name_len; ! 261: ! 262: ptr++; ! 263: add = decode_length (ptr, &ll); ! 264: name = ptr + ll; ! 265: name_len = skip_name_string (name, ptr + add); ! 266: if (!name_len) ! 267: return -1; ! 268: scope_sleep_type = get_sleep_type (table, name + name_len, ! 269: ptr + add, name, name_len); ! 270: if (scope_sleep_type != -2) ! 271: return scope_sleep_type; ! 272: ptr += add; ! 273: break; ! 274: } ! 275: case GRUB_ACPI_OPCODE_IF: ! 276: case GRUB_ACPI_OPCODE_METHOD: ! 277: { ! 278: ptr++; ! 279: ptr += decode_length (ptr, 0); ! 280: break; ! 281: } ! 282: default: ! 283: grub_printf ("Unknown opcode 0x%x\n", *ptr); ! 284: return -1; ! 285: } ! 286: } ! 287: ! 288: return -2; ! 289: } ! 290: ! 291: #ifdef GRUB_DSDT_TEST ! 292: int ! 293: main (int argc, char **argv) ! 294: { ! 295: FILE *f; ! 296: size_t len; ! 297: unsigned char *buf; ! 298: if (argc < 2) ! 299: printf ("Usage: %s FILE\n", argv[0]); ! 300: f = grub_util_fopen (argv[1], "rb"); ! 301: if (!f) ! 302: { ! 303: printf ("Couldn't open file\n"); ! 304: return 1; ! 305: } ! 306: fseek (f, 0, SEEK_END); ! 307: len = ftell (f); ! 308: fseek (f, 0, SEEK_SET); ! 309: buf = malloc (len); ! 310: if (!buf) ! 311: { ! 312: printf (_("error: %s.\n"), _("out of memory")); ! 313: fclose (f); ! 314: return 2; ! 315: } ! 316: if (fread (buf, 1, len, f) != len) ! 317: { ! 318: printf (_("cannot read `%s': %s"), argv[1], strerror (errno)); ! 319: free (buf); ! 320: fclose (f); ! 321: return 2; ! 322: } ! 323: ! 324: printf ("Sleep type = %d\n", get_sleep_type (buf, NULL, buf + len, NULL, 0)); ! 325: free (buf); ! 326: fclose (f); ! 327: return 0; ! 328: } ! 329: ! 330: #else ! 331: ! 332: void ! 333: grub_acpi_halt (void) ! 334: { ! 335: struct grub_acpi_rsdp_v20 *rsdp2; ! 336: struct grub_acpi_rsdp_v10 *rsdp1; ! 337: struct grub_acpi_table_header *rsdt; ! 338: grub_uint32_t *entry_ptr; ! 339: grub_uint32_t port = 0; ! 340: int sleep_type = -1; ! 341: ! 342: rsdp2 = grub_acpi_get_rsdpv2 (); ! 343: if (rsdp2) ! 344: rsdp1 = &(rsdp2->rsdpv1); ! 345: else ! 346: rsdp1 = grub_acpi_get_rsdpv1 (); ! 347: grub_dprintf ("acpi", "rsdp1=%p\n", rsdp1); ! 348: if (!rsdp1) ! 349: return; ! 350: ! 351: rsdt = (struct grub_acpi_table_header *) ! 352: io_map_cached (rsdp1->rsdt_addr, sizeof *rsdt); ! 353: rsdt = (struct grub_acpi_table_header *) ! 354: io_map_cached (rsdp1->rsdt_addr, rsdt->length); ! 355: ! 356: for (entry_ptr = (grub_uint32_t *) (rsdt + 1); ! 357: entry_ptr < (grub_uint32_t *) (((grub_uint8_t *) rsdt) ! 358: + rsdt->length); ! 359: entry_ptr++) ! 360: { ! 361: if (grub_memcmp ((void *) io_map_cached (*entry_ptr, 4), ! 362: "FACP", 4) == 0) ! 363: { ! 364: struct grub_acpi_fadt *fadt = (struct grub_acpi_fadt *) ! 365: io_map_cached (*entry_ptr, sizeof *fadt); ! 366: ! 367: struct grub_acpi_table_header *dsdt = ! 368: (struct grub_acpi_table_header *) ! 369: io_map_cached (fadt->dsdt_addr, sizeof *dsdt); ! 370: grub_uint8_t *buf = (grub_uint8_t *) ! 371: io_map_cached (fadt->dsdt_addr, dsdt->length); ! 372: ! 373: port = fadt->pm1a; ! 374: ! 375: grub_dprintf ("acpi", "PM1a port=%x\n", port); ! 376: ! 377: if (grub_memcmp (dsdt->signature, "DSDT", ! 378: sizeof (dsdt->signature)) == 0 ! 379: && sleep_type < 0) ! 380: sleep_type = get_sleep_type (buf, NULL, buf + dsdt->length, ! 381: NULL, 0); ! 382: } ! 383: else ! 384: if (grub_memcmp ((void *) io_map_cached (*entry_ptr, 4), "SSDT", 4) == 0 ! 385: && sleep_type < 0) ! 386: { ! 387: struct grub_acpi_table_header *ssdt ! 388: = (struct grub_acpi_table_header *) (grub_addr_t) ! 389: io_map_cached (*entry_ptr, sizeof *ssdt); ! 390: grub_uint8_t *buf = (grub_uint8_t *) ! 391: io_map_cached (*entry_ptr, ssdt->length); ! 392: ! 393: grub_dprintf ("acpi", "SSDT = %p\n", ssdt); ! 394: ! 395: sleep_type = get_sleep_type (buf, NULL, buf + ssdt->length, NULL, 0); ! 396: } ! 397: } ! 398: ! 399: grub_dprintf ("acpi", "SLP_TYP = %d, port = 0x%x\n", sleep_type, port); ! 400: if (port && sleep_type >= 0 && sleep_type < 8) ! 401: grub_outw (GRUB_ACPI_SLP_EN | (sleep_type << GRUB_ACPI_SLP_TYP_OFFSET), ! 402: port & 0xffff); ! 403: ! 404: grub_millisleep (1500); ! 405: ! 406: /* TRANSLATORS: It's computer shutdown using ACPI, not disabling ACPI. */ ! 407: grub_puts_ (N_("ACPI shutdown failed")); ! 408: } ! 409: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.