Annotation of Gnu-Mach/i386/i386at/acpihalt.c, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.