2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2010 Free Software Foundation, Inc.
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.
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.
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/>.
27 #define grub_dprintf(cond, args...) printf ( args )
28 #define grub_printf printf
29 typedef uint64_t grub_uint64_t
;
30 typedef uint32_t grub_uint32_t
;
31 typedef uint16_t grub_uint16_t
;
32 typedef uint8_t grub_uint8_t
;
36 #include <grub/acpi.h>
37 #ifndef GRUB_DSDT_TEST
38 #include <grub/i18n.h>
44 #ifndef GRUB_DSDT_TEST
46 #include <grub/misc.h>
47 #include <grub/time.h>
48 #include <grub/cpu/io.h>
51 static inline grub_uint32_t
52 decode_length (const grub_uint8_t
*ptr
, int *numlen
)
62 num_bytes
= *ptr
>> 6;
64 *numlen
= num_bytes
+ 1;
67 for (i
= 0; i
< num_bytes
; i
++)
69 ret
|= *ptr
<< (8 * i
+ 4);
75 static inline grub_uint32_t
76 skip_name_string (const grub_uint8_t
*ptr
, const grub_uint8_t
*end
)
78 const grub_uint8_t
*ptr0
= ptr
;
80 while (ptr
< end
&& (*ptr
== '^' || *ptr
== '\\'))
90 ptr
+= 1 + (*ptr
) * 4;
102 static inline grub_uint32_t
103 skip_data_ref_object (const grub_uint8_t
*ptr
, const grub_uint8_t
*end
)
105 grub_dprintf ("acpi", "data type = 0x%x\n", *ptr
);
108 case GRUB_ACPI_OPCODE_PACKAGE
:
109 case GRUB_ACPI_OPCODE_BUFFER
:
110 return 1 + decode_length (ptr
+ 1, 0);
111 case GRUB_ACPI_OPCODE_ZERO
:
112 case GRUB_ACPI_OPCODE_ONES
:
113 case GRUB_ACPI_OPCODE_ONE
:
115 case GRUB_ACPI_OPCODE_BYTE_CONST
:
117 case GRUB_ACPI_OPCODE_WORD_CONST
:
119 case GRUB_ACPI_OPCODE_DWORD_CONST
:
121 case GRUB_ACPI_OPCODE_STRING_CONST
:
123 const grub_uint8_t
*ptr0
= ptr
;
124 for (ptr
++; ptr
< end
&& *ptr
; ptr
++);
127 return ptr
- ptr0
+ 1;
130 if (*ptr
== '^' || *ptr
== '\\' || *ptr
== '_'
131 || (*ptr
>= 'A' && *ptr
<= 'Z'))
132 return skip_name_string (ptr
, end
);
133 grub_printf ("Unknown opcode 0x%x\n", *ptr
);
138 static inline grub_uint32_t
139 skip_term (const grub_uint8_t
*ptr
, const grub_uint8_t
*end
)
142 const grub_uint8_t
*ptr0
= ptr
;
146 case GRUB_ACPI_OPCODE_ADD
:
147 case GRUB_ACPI_OPCODE_AND
:
148 case GRUB_ACPI_OPCODE_CONCAT
:
149 case GRUB_ACPI_OPCODE_CONCATRES
:
150 case GRUB_ACPI_OPCODE_DIVIDE
:
151 case GRUB_ACPI_OPCODE_INDEX
:
152 case GRUB_ACPI_OPCODE_LSHIFT
:
153 case GRUB_ACPI_OPCODE_MOD
:
154 case GRUB_ACPI_OPCODE_MULTIPLY
:
155 case GRUB_ACPI_OPCODE_NAND
:
156 case GRUB_ACPI_OPCODE_NOR
:
157 case GRUB_ACPI_OPCODE_OR
:
158 case GRUB_ACPI_OPCODE_RSHIFT
:
159 case GRUB_ACPI_OPCODE_SUBTRACT
:
160 case GRUB_ACPI_OPCODE_TOSTRING
:
161 case GRUB_ACPI_OPCODE_XOR
:
163 * Parameters for these opcodes: TermArg, TermArg Target, see ACPI
164 * spec r5.0, page 828f.
167 ptr
+= add
= skip_term (ptr
, end
);
170 ptr
+= add
= skip_term (ptr
, end
);
173 ptr
+= skip_name_string (ptr
, end
);
176 return skip_data_ref_object (ptr
, end
);
181 static inline grub_uint32_t
182 skip_ext_op (const grub_uint8_t
*ptr
, const grub_uint8_t
*end
)
184 const grub_uint8_t
*ptr0
= ptr
;
186 grub_dprintf ("acpi", "Extended opcode: 0x%x\n", *ptr
);
189 case GRUB_ACPI_EXTOPCODE_MUTEX
:
191 ptr
+= skip_name_string (ptr
, end
);
194 case GRUB_ACPI_EXTOPCODE_EVENT_OP
:
196 ptr
+= skip_name_string (ptr
, end
);
198 case GRUB_ACPI_EXTOPCODE_OPERATION_REGION
:
200 ptr
+= skip_name_string (ptr
, end
);
202 ptr
+= add
= skip_term (ptr
, end
);
205 ptr
+= add
= skip_term (ptr
, end
);
209 case GRUB_ACPI_EXTOPCODE_FIELD_OP
:
210 case GRUB_ACPI_EXTOPCODE_DEVICE_OP
:
211 case GRUB_ACPI_EXTOPCODE_PROCESSOR_OP
:
212 case GRUB_ACPI_EXTOPCODE_POWER_RES_OP
:
213 case GRUB_ACPI_EXTOPCODE_THERMAL_ZONE_OP
:
214 case GRUB_ACPI_EXTOPCODE_INDEX_FIELD_OP
:
215 case GRUB_ACPI_EXTOPCODE_BANK_FIELD_OP
:
217 ptr
+= decode_length (ptr
, 0);
220 grub_printf ("Unexpected extended opcode: 0x%x\n", *ptr
);
228 get_sleep_type (grub_uint8_t
*table
, grub_uint8_t
*ptr
, grub_uint8_t
*end
,
229 grub_uint8_t
*scope
, int scope_len
)
231 grub_uint8_t
*prev
= table
;
234 ptr
= table
+ sizeof (struct grub_acpi_table_header
);
235 while (ptr
< end
&& prev
< ptr
)
239 grub_dprintf ("acpi", "Opcode 0x%x\n", *ptr
);
240 grub_dprintf ("acpi", "Tell %x\n", (unsigned) (ptr
- table
));
243 case GRUB_ACPI_OPCODE_EXTOP
:
245 ptr
+= add
= skip_ext_op (ptr
, end
);
249 case GRUB_ACPI_OPCODE_CREATE_WORD_FIELD
:
250 case GRUB_ACPI_OPCODE_CREATE_BYTE_FIELD
:
253 ptr
+= add
= skip_data_ref_object (ptr
, end
);
259 case GRUB_ACPI_OPCODE_NAME
:
261 if ((!scope
|| grub_memcmp (scope
, "\\", scope_len
) == 0) &&
262 (grub_memcmp (ptr
, "_S5_", 4) == 0 || grub_memcmp (ptr
, "\\_S5_", 4) == 0))
265 grub_uint8_t
*ptr2
= ptr
;
266 grub_dprintf ("acpi", "S5 found\n");
267 ptr2
+= skip_name_string (ptr
, end
);
270 grub_printf ("Unknown opcode in _S5: 0x%x\n", *ptr2
);
274 decode_length (ptr2
, &ll
);
279 case GRUB_ACPI_OPCODE_ZERO
:
281 case GRUB_ACPI_OPCODE_ONE
:
283 case GRUB_ACPI_OPCODE_BYTE_CONST
:
286 grub_printf ("Unknown data type in _S5: 0x%x\n", *ptr2
);
290 ptr
+= add
= skip_name_string (ptr
, end
);
293 ptr
+= add
= skip_data_ref_object (ptr
, end
);
297 case GRUB_ACPI_OPCODE_ALIAS
:
299 /* We need to skip two name strings */
300 ptr
+= add
= skip_name_string (ptr
, end
);
303 ptr
+= add
= skip_name_string (ptr
, end
);
308 case GRUB_ACPI_OPCODE_SCOPE
:
310 int scope_sleep_type
;
316 add
= decode_length (ptr
, &ll
);
318 name_len
= skip_name_string (name
, ptr
+ add
);
321 scope_sleep_type
= get_sleep_type (table
, name
+ name_len
,
322 ptr
+ add
, name
, name_len
);
323 if (scope_sleep_type
!= -2)
324 return scope_sleep_type
;
328 case GRUB_ACPI_OPCODE_IF
:
329 case GRUB_ACPI_OPCODE_METHOD
:
332 ptr
+= decode_length (ptr
, 0);
336 grub_printf ("Unknown opcode 0x%x\n", *ptr
);
344 #ifdef GRUB_DSDT_TEST
346 main (int argc
, char **argv
)
352 printf ("Usage: %s FILE\n", argv
[0]);
353 f
= grub_util_fopen (argv
[1], "rb");
356 printf ("Couldn't open file\n");
359 fseek (f
, 0, SEEK_END
);
361 fseek (f
, 0, SEEK_SET
);
365 printf (_("error: %s.\n"), _("out of memory"));
369 if (fread (buf
, 1, len
, f
) != len
)
371 printf (_("cannot read `%s': %s"), argv
[1], strerror (errno
));
377 printf ("Sleep type = %d\n", get_sleep_type (buf
, NULL
, buf
+ len
, NULL
, 0));
386 grub_acpi_halt (void)
388 struct grub_acpi_rsdp_v20
*rsdp2
;
389 struct grub_acpi_rsdp_v10
*rsdp1
;
390 struct grub_acpi_table_header
*rsdt
;
391 grub_uint32_t
*entry_ptr
;
392 grub_uint32_t port
= 0;
395 rsdp2
= grub_acpi_get_rsdpv2 ();
397 rsdp1
= &(rsdp2
->rsdpv1
);
399 rsdp1
= grub_acpi_get_rsdpv1 ();
400 grub_dprintf ("acpi", "rsdp1=%p\n", rsdp1
);
404 rsdt
= (struct grub_acpi_table_header
*) (grub_addr_t
) rsdp1
->rsdt_addr
;
405 for (entry_ptr
= (grub_uint32_t
*) (rsdt
+ 1);
406 entry_ptr
< (grub_uint32_t
*) (((grub_uint8_t
*) rsdt
)
410 if (grub_memcmp ((void *) (grub_addr_t
) *entry_ptr
, "FACP", 4) == 0)
412 struct grub_acpi_fadt
*fadt
413 = ((struct grub_acpi_fadt
*) (grub_addr_t
) *entry_ptr
);
414 struct grub_acpi_table_header
*dsdt
415 = (struct grub_acpi_table_header
*) (grub_addr_t
) fadt
->dsdt_addr
;
416 grub_uint8_t
*buf
= (grub_uint8_t
*) dsdt
;
420 grub_dprintf ("acpi", "PM1a port=%x\n", port
);
422 if (grub_memcmp (dsdt
->signature
, "DSDT",
423 sizeof (dsdt
->signature
)) == 0
425 sleep_type
= get_sleep_type (buf
, NULL
, buf
+ dsdt
->length
,
428 else if (grub_memcmp ((void *) (grub_addr_t
) *entry_ptr
, "SSDT", 4) == 0
431 struct grub_acpi_table_header
*ssdt
432 = (struct grub_acpi_table_header
*) (grub_addr_t
) *entry_ptr
;
433 grub_uint8_t
*buf
= (grub_uint8_t
*) ssdt
;
435 grub_dprintf ("acpi", "SSDT = %p\n", ssdt
);
437 sleep_type
= get_sleep_type (buf
, NULL
, buf
+ ssdt
->length
, NULL
, 0);
441 grub_dprintf ("acpi", "SLP_TYP = %d, port = 0x%x\n", sleep_type
, port
);
442 if (port
&& sleep_type
>= 0 && sleep_type
< 8)
443 grub_outw (GRUB_ACPI_SLP_EN
| (sleep_type
<< GRUB_ACPI_SLP_TYP_OFFSET
),
446 grub_millisleep (1500);
448 /* TRANSLATORS: It's computer shutdown using ACPI, not disabling ACPI. */
449 grub_puts_ (N_("ACPI shutdown failed"));