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/>.
26 #define grub_dprintf(cond, args...) printf ( args )
27 #define grub_printf printf
28 typedef uint64_t grub_uint64_t
;
29 typedef uint32_t grub_uint32_t
;
30 typedef uint16_t grub_uint16_t
;
31 typedef uint8_t grub_uint8_t
;
35 #include <grub/acpi.h>
36 #ifndef GRUB_DSDT_TEST
37 #include <grub/i18n.h>
43 #ifndef GRUB_DSDT_TEST
44 #include <grub/misc.h>
45 #include <grub/time.h>
46 #include <grub/cpu/io.h>
49 static inline grub_uint32_t
50 decode_length (const grub_uint8_t
*ptr
, int *numlen
)
60 num_bytes
= *ptr
>> 6;
62 *numlen
= num_bytes
+ 1;
65 for (i
= 0; i
< num_bytes
; i
++)
67 ret
|= *ptr
<< (8 * i
+ 4);
73 static inline grub_uint32_t
74 skip_name_string (const grub_uint8_t
*ptr
, const grub_uint8_t
*end
)
76 const grub_uint8_t
*ptr0
= ptr
;
78 while (ptr
< end
&& (*ptr
== '^' || *ptr
== '\\'))
88 ptr
+= 1 + (*ptr
) * 4;
100 static inline grub_uint32_t
101 skip_data_ref_object (const grub_uint8_t
*ptr
, const grub_uint8_t
*end
)
103 grub_dprintf ("acpi", "data type = 0x%x\n", *ptr
);
106 case GRUB_ACPI_OPCODE_PACKAGE
:
107 case GRUB_ACPI_OPCODE_BUFFER
:
108 return 1 + decode_length (ptr
+ 1, 0);
109 case GRUB_ACPI_OPCODE_ZERO
:
110 case GRUB_ACPI_OPCODE_ONES
:
111 case GRUB_ACPI_OPCODE_ONE
:
113 case GRUB_ACPI_OPCODE_BYTE_CONST
:
115 case GRUB_ACPI_OPCODE_WORD_CONST
:
117 case GRUB_ACPI_OPCODE_DWORD_CONST
:
119 case GRUB_ACPI_OPCODE_STRING_CONST
:
121 const grub_uint8_t
*ptr0
= ptr
;
122 for (ptr
++; ptr
< end
&& *ptr
; ptr
++);
125 return ptr
- ptr0
+ 1;
128 if (*ptr
== '^' || *ptr
== '\\' || *ptr
== '_'
129 || (*ptr
>= 'A' && *ptr
<= 'Z'))
130 return skip_name_string (ptr
, end
);
131 grub_printf ("Unknown opcode 0x%x\n", *ptr
);
136 static inline grub_uint32_t
137 skip_ext_op (const grub_uint8_t
*ptr
, const grub_uint8_t
*end
)
139 const grub_uint8_t
*ptr0
= ptr
;
141 grub_dprintf ("acpi", "Extended opcode: 0x%x\n", *ptr
);
144 case GRUB_ACPI_EXTOPCODE_MUTEX
:
146 ptr
+= skip_name_string (ptr
, end
);
149 case GRUB_ACPI_EXTOPCODE_OPERATION_REGION
:
151 ptr
+= skip_name_string (ptr
, end
);
153 ptr
+= add
= skip_data_ref_object (ptr
, end
);
156 ptr
+= add
= skip_data_ref_object (ptr
, end
);
160 case GRUB_ACPI_EXTOPCODE_FIELD_OP
:
161 case GRUB_ACPI_EXTOPCODE_INDEX_FIELD_OP
:
163 ptr
+= decode_length (ptr
, 0);
166 grub_printf ("Unexpected extended opcode: 0x%x\n", *ptr
);
173 get_sleep_type (grub_uint8_t
*table
, grub_uint8_t
*end
)
175 grub_uint8_t
*ptr
, *prev
= table
;
178 ptr
= table
+ sizeof (struct grub_acpi_table_header
);
179 while (ptr
< end
&& prev
< ptr
)
183 grub_dprintf ("acpi", "Opcode 0x%x\n", *ptr
);
184 grub_dprintf ("acpi", "Tell %x\n", (unsigned) (ptr
- table
));
187 case GRUB_ACPI_OPCODE_EXTOP
:
189 ptr
+= add
= skip_ext_op (ptr
, end
);
193 case GRUB_ACPI_OPCODE_CREATE_WORD_FIELD
:
194 case GRUB_ACPI_OPCODE_CREATE_BYTE_FIELD
:
197 ptr
+= add
= skip_data_ref_object (ptr
, end
);
203 case GRUB_ACPI_OPCODE_NAME
:
205 if (memcmp (ptr
, "_S5_", 4) == 0 || memcmp (ptr
, "\\_S5_", 4) == 0)
208 grub_uint8_t
*ptr2
= ptr
;
209 grub_dprintf ("acpi", "S5 found\n");
210 ptr2
+= skip_name_string (ptr
, end
);
213 grub_printf ("Unknown opcode in _S5: 0x%x\n", *ptr2
);
217 decode_length (ptr2
, &ll
);
222 case GRUB_ACPI_OPCODE_ZERO
:
225 case GRUB_ACPI_OPCODE_ONE
:
228 case GRUB_ACPI_OPCODE_BYTE_CONST
:
229 sleep_type
= ptr2
[1];
232 grub_printf ("Unknown data type in _S5: 0x%x\n", *ptr2
);
236 ptr
+= add
= skip_name_string (ptr
, end
);
239 ptr
+= add
= skip_data_ref_object (ptr
, end
);
243 case GRUB_ACPI_OPCODE_SCOPE
:
244 case GRUB_ACPI_OPCODE_IF
:
245 case GRUB_ACPI_OPCODE_METHOD
:
248 ptr
+= decode_length (ptr
, 0);
252 grub_printf ("Unknown opcode 0x%x\n", *ptr
);
257 grub_dprintf ("acpi", "TYP = %d\n", sleep_type
);
261 #ifdef GRUB_DSDT_TEST
263 main (int argc
, char **argv
)
269 printf ("Usage: %s FILE\n", argv
[0]);
270 f
= fopen (argv
[1], "rb");
273 printf ("Couldn't open file\n");
276 fseek (f
, 0, SEEK_END
);
278 fseek (f
, 0, SEEK_SET
);
282 printf ("Couldn't malloc buffer\n");
286 if (fread (buf
, 1, len
, f
) != len
)
288 printf ("Read failed\n");
294 printf ("Sleep type = %d\n", get_sleep_type (buf
, buf
+ len
));
303 grub_acpi_halt (void)
305 struct grub_acpi_rsdp_v20
*rsdp2
;
306 struct grub_acpi_rsdp_v10
*rsdp1
;
307 struct grub_acpi_table_header
*rsdt
;
308 grub_uint32_t
*entry_ptr
;
310 rsdp2
= grub_acpi_get_rsdpv2 ();
312 rsdp1
= &(rsdp2
->rsdpv1
);
314 rsdp1
= grub_acpi_get_rsdpv1 ();
315 grub_dprintf ("acpi", "rsdp1=%p\n", rsdp1
);
319 rsdt
= (struct grub_acpi_table_header
*) (grub_addr_t
) rsdp1
->rsdt_addr
;
320 for (entry_ptr
= (grub_uint32_t
*) (rsdt
+ 1);
321 entry_ptr
< (grub_uint32_t
*) (((grub_uint8_t
*) rsdt
)
325 if (grub_memcmp ((void *) (grub_addr_t
) *entry_ptr
, "FACP", 4) == 0)
328 struct grub_acpi_fadt
*fadt
329 = ((struct grub_acpi_fadt
*) (grub_addr_t
) *entry_ptr
);
330 struct grub_acpi_table_header
*dsdt
331 = (struct grub_acpi_table_header
*) (grub_addr_t
) fadt
->dsdt_addr
;
336 grub_dprintf ("acpi", "PM1a port=%x\n", port
);
338 if (grub_memcmp (dsdt
->signature
, "DSDT",
339 sizeof (dsdt
->signature
)) != 0)
342 sleep_type
= get_sleep_type ((grub_uint8_t
*) dsdt
,
343 (grub_uint8_t
*) dsdt
+ dsdt
->length
);
345 if (sleep_type
< 0 || sleep_type
>= 8)
348 grub_dprintf ("acpi", "SLP_TYP = %d, port = 0x%x\n",
351 grub_outw (GRUB_ACPI_SLP_EN
352 | (sleep_type
<< GRUB_ACPI_SLP_TYP_OFFSET
), port
& 0xffff);
356 grub_millisleep (1500);
358 /* TRANSLATORS: It's computer shutdown using ACPI, not disabling ACPI. */
359 grub_puts_ (N_("ACPI shutdown failed"));