Remove building with NOCRYPTO option
[minix3.git] / minix / kernel / arch / i386 / acpi.c
blob63ddde12ed478f208c775e850de9316b520fe928
2 #include <string.h>
4 #include "acpi.h"
5 #include "arch_proto.h"
7 typedef int ((* acpi_read_t)(phys_bytes addr, void * buff, size_t size));
9 struct acpi_rsdp acpi_rsdp;
11 static acpi_read_t read_func;
13 #define MAX_RSDT 35 /* ACPI defines 35 signatures */
14 #define SLP_EN_CODE (1 << 13) /* ACPI SLP_EN_CODE code */
15 #define AMI_PACKAGE_OP_CODE (0x12)
16 #define AMI_NAME_OP_CODE (0x8)
17 #define AMI_BYTE_PREFIX_CODE (0xA)
18 #define AMI_PACKAGE_LENGTH_ENCODING_BITS_MASK (0xC0)
19 #define AMI_PACKAGE_LENGTH_ENCODING_BITS_SHIFT (6)
20 #define AMI_MIN_PACKAGE_LENGTH (1)
21 #define AMI_NUM_ELEMENTS_LENGTH (1)
22 #define AMI_SLP_TYPA_SHIFT (10)
23 #define AMI_SLP_TYPB_SHIFT (10)
24 #define AMI_S5_NAME_OP_OFFSET_1 (-1)
25 #define AMI_S5_NAME_OP_OFFSET_2 (-2)
26 #define AMI_S5_PACKAGE_OP_OFFSET (4)
27 #define AMI_S5_PACKET_LENGTH_OFFSET (5)
29 static struct acpi_rsdt {
30 struct acpi_sdt_header hdr;
31 u32_t data[MAX_RSDT];
32 } rsdt;
34 static struct {
35 char signature [ACPI_SDT_SIGNATURE_LEN + 1];
36 size_t length;
37 } sdt_trans[MAX_RSDT];
39 static int sdt_count;
40 static u16_t pm1a_cnt_blk = 0;
41 static u16_t pm1b_cnt_blk = 0;
42 static u16_t slp_typa = 0;
43 static u16_t slp_typb = 0;
45 static int acpi_check_csum(struct acpi_sdt_header * tb, size_t size)
47 u8_t total = 0;
48 int i;
49 for (i = 0; i < size; i++)
50 total += ((unsigned char *)tb)[i];
51 return total == 0 ? 0 : -1;
54 static int acpi_check_signature(const char * orig, const char * match)
56 return strncmp(orig, match, ACPI_SDT_SIGNATURE_LEN);
59 static u32_t acpi_phys2vir(u32_t p)
61 if(!vm_running) {
62 DEBUGEXTRA(("acpi: returning 0x%lx as vir addr\n", p));
63 return p;
65 panic("acpi: can't get virtual address of arbitrary physical address");
68 static int acpi_phys_copy(phys_bytes phys, void *target, size_t len)
70 if(!vm_running) {
71 memcpy(target, (void *) phys, len);
72 return 0;
74 panic("can't acpi_phys_copy with vm");
77 static int acpi_read_sdt_at(phys_bytes addr,
78 struct acpi_sdt_header * tb,
79 size_t size,
80 const char * name)
82 struct acpi_sdt_header hdr;
84 /* if NULL is supplied, we only return the size of the table */
85 if (tb == NULL) {
86 if (read_func(addr, &hdr, sizeof(struct acpi_sdt_header))) {
87 printf("ERROR acpi cannot read %s header\n", name);
88 return -1;
91 return hdr.length;
94 if (read_func(addr, tb, sizeof(struct acpi_sdt_header))) {
95 printf("ERROR acpi cannot read %s header\n", name);
96 return -1;
99 if (acpi_check_signature(tb->signature, name)) {
100 printf("ERROR acpi %s signature does not match\n", name);
101 return -1;
104 if (size < tb->length) {
105 printf("ERROR acpi buffer too small for %s\n", name);
106 return -1;
109 if (read_func(addr, tb, size)) {
110 printf("ERROR acpi cannot read %s\n", name);
111 return -1;
114 if (acpi_check_csum(tb, tb->length)) {
115 printf("ERROR acpi %s checksum does not match\n", name);
116 return -1;
119 return tb->length;
122 phys_bytes acpi_get_table_base(const char * name)
124 int i;
126 for(i = 0; i < sdt_count; i++) {
127 if (strncmp(name, sdt_trans[i].signature,
128 ACPI_SDT_SIGNATURE_LEN) == 0)
129 return (phys_bytes) rsdt.data[i];
132 return (phys_bytes) NULL;
135 size_t acpi_get_table_length(const char * name)
137 int i;
139 for(i = 0; i < sdt_count; i++) {
140 if (strncmp(name, sdt_trans[i].signature,
141 ACPI_SDT_SIGNATURE_LEN) == 0)
142 return sdt_trans[i].length;
145 return 0;
148 static void * acpi_madt_get_typed_item(struct acpi_madt_hdr * hdr,
149 unsigned char type,
150 unsigned idx)
152 u8_t * t, * end;
153 int i;
155 t = (u8_t *) hdr + sizeof(struct acpi_madt_hdr);
156 end = (u8_t *) hdr + hdr->hdr.length;
158 i = 0;
159 while(t < end) {
160 if (type == ((struct acpi_madt_item_hdr *) t)->type) {
161 if (i == idx)
162 return t;
163 else
164 i++;
166 t += ((struct acpi_madt_item_hdr *) t)->length;
169 return NULL;
172 #if 0
173 static void * acpi_madt_get_item(struct acpi_madt_hdr * hdr,
174 unsigned idx)
176 u8_t * t, * end;
177 int i;
179 t = (u8_t *) hdr + sizeof(struct acpi_madt_hdr);
180 end = (u8_t *) hdr + hdr->hdr.length;
182 for(i = 0 ; i <= idx && t < end; i++) {
183 if (i == idx)
184 return t;
185 t += ((struct acpi_madt_item_hdr *) t)->length;
188 return NULL;
190 #endif
192 static int acpi_rsdp_test(void * buff)
194 struct acpi_rsdp * rsdp = (struct acpi_rsdp *) buff;
196 if (!platform_tbl_checksum_ok(buff, 20))
197 return 0;
198 if (strncmp(rsdp->signature, "RSD PTR ", 8))
199 return 0;
201 return 1;
204 static int get_acpi_rsdp(void)
206 u16_t ebda;
208 * Read 40:0Eh - to find the starting address of the EBDA.
210 acpi_phys_copy (0x40E, &ebda, sizeof(ebda));
211 if (ebda) {
212 ebda <<= 4;
213 if(platform_tbl_ptr(ebda, ebda + 0x400, 16, &acpi_rsdp,
214 sizeof(acpi_rsdp), &machine.acpi_rsdp,
215 acpi_rsdp_test))
216 return 1;
219 /* try BIOS read only mem space */
220 if(platform_tbl_ptr(0xE0000, 0x100000, 16, &acpi_rsdp,
221 sizeof(acpi_rsdp), &machine.acpi_rsdp,
222 acpi_rsdp_test))
223 return 1;
225 machine.acpi_rsdp = 0; /* RSDP cannot be found at this address therefore
226 it is a valid negative value */
227 return 0;
230 static void acpi_init_poweroff(void)
232 u8_t *ptr = NULL;
233 u8_t *start = NULL;
234 u8_t *end = NULL;
235 struct acpi_fadt_header *fadt_header = NULL;
236 struct acpi_rsdt * dsdt_header = NULL;
237 char *msg = NULL;
239 /* Everything used here existed since ACPI spec 1.0 */
240 /* So we can safely use them */
241 fadt_header = (struct acpi_fadt_header *)
242 acpi_phys2vir(acpi_get_table_base("FACP"));
243 if (fadt_header == NULL) {
244 msg = "Could not load FACP";
245 goto exit;
248 dsdt_header = (struct acpi_rsdt *)
249 acpi_phys2vir((phys_bytes) fadt_header->dsdt);
250 if (dsdt_header == NULL) {
251 msg = "Could not load DSDT";
252 goto exit;
255 pm1a_cnt_blk = fadt_header->pm1a_cnt_blk;
256 pm1b_cnt_blk = fadt_header->pm1b_cnt_blk;
258 ptr = start = (u8_t *) dsdt_header->data;
259 end = start + dsdt_header->hdr.length - 4;
261 /* See http://forum.osdev.org/viewtopic.php?t=16990 */
262 /* for layout of \_S5 */
263 while (ptr < end && memcmp(ptr, "_S5_", 4) != 0)
264 ptr++;
266 msg = "Could not read S5 data. Use default SLP_TYPa and SLP_TYPb";
267 if (ptr >= end || ptr == start)
268 goto exit;
270 /* validate AML structure */
271 if (*(ptr + AMI_S5_PACKAGE_OP_OFFSET) != AMI_PACKAGE_OP_CODE)
272 goto exit;
274 if ((ptr < start + (-AMI_S5_NAME_OP_OFFSET_2) ||
275 (*(ptr + AMI_S5_NAME_OP_OFFSET_2) != AMI_NAME_OP_CODE ||
276 *(ptr + AMI_S5_NAME_OP_OFFSET_2 + 1) != '\\')) &&
277 *(ptr + AMI_S5_NAME_OP_OFFSET_1) != AMI_NAME_OP_CODE)
278 goto exit;
280 ptr += AMI_S5_PACKET_LENGTH_OFFSET;
281 if (ptr >= end)
282 goto exit;
284 /* package length */
285 ptr += ((*ptr & AMI_PACKAGE_LENGTH_ENCODING_BITS_MASK) >>
286 AMI_PACKAGE_LENGTH_ENCODING_BITS_SHIFT) +
287 AMI_MIN_PACKAGE_LENGTH + AMI_NUM_ELEMENTS_LENGTH;
288 if (ptr >= end)
289 goto exit;
291 if (*ptr == AMI_BYTE_PREFIX_CODE)
292 ptr++; /* skip byte prefix */
294 slp_typa = (*ptr) << AMI_SLP_TYPA_SHIFT;
296 ptr++; /* move to SLP_TYPb */
297 if (*ptr == AMI_BYTE_PREFIX_CODE)
298 ptr++; /* skip byte prefix */
300 slp_typb = (*ptr) << AMI_SLP_TYPB_SHIFT;
302 msg = "poweroff initialized";
304 exit:
305 if (msg) {
306 DEBUGBASIC(("acpi: %s\n", msg));
310 void acpi_init(void)
312 int s, i;
313 read_func = acpi_phys_copy;
315 if (!get_acpi_rsdp()) {
316 printf("WARNING : Cannot configure ACPI\n");
317 return;
320 s = acpi_read_sdt_at(acpi_rsdp.rsdt_addr, (struct acpi_sdt_header *) &rsdt,
321 sizeof(struct acpi_rsdt), ACPI_SDT_SIGNATURE(RSDT));
323 sdt_count = (s - sizeof(struct acpi_sdt_header)) / sizeof(u32_t);
325 for (i = 0; i < sdt_count; i++) {
326 struct acpi_sdt_header hdr;
327 int j;
328 if (read_func(rsdt.data[i], &hdr, sizeof(struct acpi_sdt_header))) {
329 printf("ERROR acpi cannot read header at 0x%x\n",
330 rsdt.data[i]);
331 return;
334 for (j = 0 ; j < ACPI_SDT_SIGNATURE_LEN; j++)
335 sdt_trans[i].signature[j] = hdr.signature[j];
336 sdt_trans[i].signature[ACPI_SDT_SIGNATURE_LEN] = '\0';
337 sdt_trans[i].length = hdr.length;
340 acpi_init_poweroff();
343 struct acpi_madt_ioapic * acpi_get_ioapic_next(void)
345 static unsigned idx = 0;
346 static struct acpi_madt_hdr * madt_hdr;
348 struct acpi_madt_ioapic * ret;
350 if (idx == 0) {
351 madt_hdr = (struct acpi_madt_hdr *)
352 acpi_phys2vir(acpi_get_table_base("APIC"));
353 if (madt_hdr == NULL)
354 return NULL;
357 ret = (struct acpi_madt_ioapic *)
358 acpi_madt_get_typed_item(madt_hdr, ACPI_MADT_TYPE_IOAPIC, idx);
359 if (ret)
360 idx++;
362 return ret;
365 struct acpi_madt_lapic * acpi_get_lapic_next(void)
367 static unsigned idx = 0;
368 static struct acpi_madt_hdr * madt_hdr;
370 struct acpi_madt_lapic * ret;
372 if (idx == 0) {
373 madt_hdr = (struct acpi_madt_hdr *)
374 acpi_phys2vir(acpi_get_table_base("APIC"));
375 if (madt_hdr == NULL)
376 return NULL;
379 for (;;) {
380 ret = (struct acpi_madt_lapic *)
381 acpi_madt_get_typed_item(madt_hdr,
382 ACPI_MADT_TYPE_LAPIC, idx);
383 if (!ret)
384 break;
386 idx++;
388 /* report only usable CPUs */
389 if (ret->flags & 1)
390 break;
393 return ret;
396 void __k_unpaged_acpi_poweroff(void)
398 /* NO OP poweroff symbol*/
401 void acpi_poweroff(void)
403 if (pm1a_cnt_blk == 0) {
404 return;
406 outw(pm1a_cnt_blk, slp_typa | SLP_EN_CODE);
407 if (pm1b_cnt_blk != 0) {
408 outw(pm1b_cnt_blk, slp_typb | SLP_EN_CODE);