xref: /minix/minix/kernel/arch/i386/acpi.c (revision fb9c64b2)
1 
2 #include <string.h>
3 
4 #include "acpi.h"
5 #include "arch_proto.h"
6 
7 typedef int ((* acpi_read_t)(phys_bytes addr, void * buff, size_t size));
8 
9 struct acpi_rsdp acpi_rsdp;
10 
11 static acpi_read_t read_func;
12 
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)
28 
29 static struct acpi_rsdt {
30 	struct acpi_sdt_header	hdr;
31 	u32_t			data[MAX_RSDT];
32 } rsdt;
33 
34 static struct {
35 	char	signature [ACPI_SDT_SIGNATURE_LEN + 1];
36 	size_t	length;
37 } sdt_trans[MAX_RSDT];
38 
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;
44 
45 static int acpi_check_csum(struct acpi_sdt_header * tb, size_t size)
46 {
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;
52 }
53 
54 static int acpi_check_signature(const char * orig, const char * match)
55 {
56 	return strncmp(orig, match, ACPI_SDT_SIGNATURE_LEN);
57 }
58 
59 static u32_t acpi_phys2vir(u32_t p)
60 {
61 	if(!vm_running) {
62 		DEBUGEXTRA(("acpi: returning 0x%lx as vir addr\n", p));
63 		return p;
64 	}
65 	panic("acpi: can't get virtual address of arbitrary physical address");
66 }
67 
68 static int acpi_phys_copy(phys_bytes phys, void *target, size_t len)
69 {
70 	if(!vm_running) {
71 		memcpy(target, (void *) phys, len);
72 		return 0;
73 	}
74 	panic("can't acpi_phys_copy with vm");
75 }
76 
77 static int acpi_read_sdt_at(phys_bytes addr,
78 				struct acpi_sdt_header * tb,
79 				size_t size,
80 				const char * name)
81 {
82 	struct acpi_sdt_header hdr;
83 
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;
89 		}
90 
91 		return hdr.length;
92 	}
93 
94 	if (read_func(addr, tb, sizeof(struct acpi_sdt_header))) {
95 		printf("ERROR acpi cannot read %s header\n", name);
96 		return -1;
97 	}
98 
99 	if (acpi_check_signature(tb->signature, name)) {
100 		printf("ERROR acpi %s signature does not match\n", name);
101 		return -1;
102 	}
103 
104 	if (size < tb->length) {
105 		printf("ERROR acpi buffer too small for %s\n", name);
106 		return -1;
107 	}
108 
109 	if (read_func(addr, tb, size)) {
110 		printf("ERROR acpi cannot read %s\n", name);
111 		return -1;
112 	}
113 
114 	if (acpi_check_csum(tb, tb->length)) {
115 		printf("ERROR acpi %s checksum does not match\n", name);
116 		return -1;
117 	}
118 
119 	return tb->length;
120 }
121 
122 phys_bytes acpi_get_table_base(const char * name)
123 {
124 	int i;
125 
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];
130 	}
131 
132 	return (phys_bytes) NULL;
133 }
134 
135 size_t acpi_get_table_length(const char * name)
136 {
137 	int i;
138 
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;
143 	}
144 
145 	return 0;
146 }
147 
148 static void * acpi_madt_get_typed_item(struct acpi_madt_hdr * hdr,
149 					unsigned char type,
150 					unsigned idx)
151 {
152 	u8_t * t, * end;
153 	int i;
154 
155 	t = (u8_t *) hdr + sizeof(struct acpi_madt_hdr);
156 	end = (u8_t *) hdr + hdr->hdr.length;
157 
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++;
165 		}
166 		t += ((struct acpi_madt_item_hdr *) t)->length;
167 	}
168 
169 	return NULL;
170 }
171 
172 #if 0
173 static void * acpi_madt_get_item(struct acpi_madt_hdr * hdr,
174 				unsigned idx)
175 {
176 	u8_t * t, * end;
177 	int i;
178 
179 	t = (u8_t *) hdr + sizeof(struct acpi_madt_hdr);
180 	end = (u8_t *) hdr + hdr->hdr.length;
181 
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;
186 	}
187 
188 	return NULL;
189 }
190 #endif
191 
192 static int acpi_rsdp_test(void * buff)
193 {
194 	struct acpi_rsdp * rsdp = (struct acpi_rsdp *) buff;
195 
196 	if (!platform_tbl_checksum_ok(buff, 20))
197 		return 0;
198 	if (strncmp(rsdp->signature, "RSD PTR ", 8))
199 		return 0;
200 
201 	return 1;
202 }
203 
204 static int get_acpi_rsdp(void)
205 {
206 	u16_t ebda;
207 	/*
208 	 * Read 40:0Eh - to find the starting address of the EBDA.
209 	 */
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;
217 	}
218 
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;
224 
225 	machine.acpi_rsdp = 0; /* RSDP cannot be found at this address therefore
226 				  it is a valid negative value */
227 	return 0;
228 }
229 
230 static void acpi_init_poweroff(void)
231 {
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;
238 
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;
246 	}
247 
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;
253 	}
254 
255 	pm1a_cnt_blk = fadt_header->pm1a_cnt_blk;
256 	pm1b_cnt_blk = fadt_header->pm1b_cnt_blk;
257 
258 	ptr = start = (u8_t *) dsdt_header->data;
259 	end = start + dsdt_header->hdr.length - 4;
260 
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++;
265 
266 	msg = "Could not read S5 data. Use default SLP_TYPa and SLP_TYPb";
267 	if (ptr >= end || ptr == start)
268 		goto exit;
269 
270 	/* validate AML structure */
271 	if (*(ptr + AMI_S5_PACKAGE_OP_OFFSET) != AMI_PACKAGE_OP_CODE)
272 		goto exit;
273 
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;
279 
280 	ptr += AMI_S5_PACKET_LENGTH_OFFSET;
281 	if (ptr >= end)
282 		goto exit;
283 
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;
290 
291 	if (*ptr == AMI_BYTE_PREFIX_CODE)
292 		ptr++; /* skip byte prefix */
293 
294 	slp_typa = (*ptr) << AMI_SLP_TYPA_SHIFT;
295 
296 	ptr++; /* move to SLP_TYPb */
297 	if (*ptr == AMI_BYTE_PREFIX_CODE)
298 		ptr++; /* skip byte prefix */
299 
300 	slp_typb = (*ptr) << AMI_SLP_TYPB_SHIFT;
301 
302 	msg = "poweroff initialized";
303 
304 exit:
305 	if (msg) {
306 		DEBUGBASIC(("acpi: %s\n", msg));
307 	}
308 }
309 
310 void acpi_init(void)
311 {
312 	int s, i;
313 	read_func = acpi_phys_copy;
314 
315 	if (!get_acpi_rsdp()) {
316 		printf("WARNING : Cannot configure ACPI\n");
317 		return;
318 	}
319 
320 	s = acpi_read_sdt_at(acpi_rsdp.rsdt_addr, (struct acpi_sdt_header *) &rsdt,
321 			sizeof(struct acpi_rsdt), ACPI_SDT_SIGNATURE(RSDT));
322 
323 	sdt_count = (s - sizeof(struct acpi_sdt_header)) / sizeof(u32_t);
324 
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;
332 		}
333 
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;
338 	}
339 
340 	acpi_init_poweroff();
341 }
342 
343 struct acpi_madt_ioapic * acpi_get_ioapic_next(void)
344 {
345 	static unsigned idx = 0;
346 	static struct acpi_madt_hdr * madt_hdr;
347 
348 	struct acpi_madt_ioapic * ret;
349 
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;
355 	}
356 
357 	ret = (struct acpi_madt_ioapic *)
358 		acpi_madt_get_typed_item(madt_hdr, ACPI_MADT_TYPE_IOAPIC, idx);
359 	if (ret)
360 		idx++;
361 
362 	return ret;
363 }
364 
365 struct acpi_madt_lapic * acpi_get_lapic_next(void)
366 {
367 	static unsigned idx = 0;
368 	static struct acpi_madt_hdr * madt_hdr;
369 
370 	struct acpi_madt_lapic * ret;
371 
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;
377 	}
378 
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;
385 
386 		idx++;
387 
388 		/* report only usable CPUs */
389 		if (ret->flags & 1)
390 			break;
391 	}
392 
393 	return ret;
394 }
395 
396 void __k_unpaged_acpi_poweroff(void)
397 {
398 	/* NO OP poweroff symbol*/
399 }
400 
401 void acpi_poweroff(void)
402 {
403 	if (pm1a_cnt_blk == 0) {
404 		return;
405 	}
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);
409 	}
410 }
411