xref: /illumos-gate/usr/src/boot/efi/libefi/acpi.c (revision 7249bc1087a62c0594078dc84de55f3cadcae5d2)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2016 Tooams Soome <tsoome@me.com>
14  */
15 
16 #include <sys/cdefs.h>
17 
18 #include <stand.h>
19 #include <sys/stdint.h>
20 #include <machine/stdarg.h>
21 #include <bootstrap.h>
22 #include <efi.h>
23 #include <efilib.h>
24 #include <Guid/Acpi.h>
25 
26 #include "platform/acfreebsd.h"
27 #include "acconfig.h"
28 #define	ACPI_SYSTEM_XFACE
29 #include "actypes.h"
30 #include "actbl.h"
31 
32 ACPI_TABLE_RSDP	*rsdp;
33 EFI_GUID gEfiAcpiTableGuid = ACPI_TABLE_GUID;
34 EFI_GUID gEfiAcpi20TableGuid = EFI_ACPI_TABLE_GUID;
35 
36 static void *
acpi_map_sdt(vm_offset_t addr)37 acpi_map_sdt(vm_offset_t addr)
38 {
39 	/* PA == VA */
40 	return ((void *)addr);
41 }
42 
43 static uint8_t
acpi_checksum(const void * p,size_t length)44 acpi_checksum(const void *p, size_t length)
45 {
46 	const uint8_t *bp;
47 	uint8_t sum;
48 
49 	bp = p;
50 	sum = 0;
51 	while (length--)
52 		sum += *bp++;
53 
54 	return (sum);
55 }
56 
57 /*
58  * We have duplication there, the same implementation is also
59  * in libi386/biosacpi.c. We will address this duplication later.
60  */
61 void *
acpi_find_table(const char * sig)62 acpi_find_table(const char *sig)
63 {
64 	uint_t entries, i;
65 	ACPI_TABLE_HEADER *sdp;
66 	ACPI_TABLE_RSDT *rsdt;
67 	ACPI_TABLE_XSDT *xsdt;
68 
69 	if (rsdp == NULL)
70 		return (NULL);
71 
72 	/*
73 	 * Note, we need to check both address value and size there,
74 	 * as 32-bit code can not access 64-bit address space.
75 	 */
76 	if (rsdp->Revision >= 2 &&
77 	    rsdp->XsdtPhysicalAddress != 0 &&
78 	    rsdp->XsdtPhysicalAddress < UINTPTR_MAX) {
79 		xsdt = acpi_map_sdt(rsdp->XsdtPhysicalAddress);
80 		sdp = (ACPI_TABLE_HEADER *)xsdt;
81 		if (sdp->Length < sizeof (ACPI_TABLE_HEADER)) {
82 			entries = 0;
83 		} else {
84 			entries = sdp->Length - sizeof (ACPI_TABLE_HEADER);
85 			entries /= ACPI_XSDT_ENTRY_SIZE;
86 		}
87 		for (i = 0; i < entries; i++) {
88 			if (xsdt->TableOffsetEntry[i] == 0 ||
89 			    xsdt->TableOffsetEntry[i] >= UINTPTR_MAX)
90 				continue;
91 			sdp = acpi_map_sdt(xsdt->TableOffsetEntry[i]);
92 			if (sdp->Length < sizeof (ACPI_TABLE_HEADER))
93 				continue;
94 
95 			if (acpi_checksum(sdp, sdp->Length))
96 				continue;
97 
98 			if (ACPI_COMPARE_NAME(sig, sdp->Signature))
99 				return (sdp);
100 		}
101 	}
102 
103 	if (rsdp->RsdtPhysicalAddress != 0) {
104 		rsdt = acpi_map_sdt(rsdp->RsdtPhysicalAddress);
105 		sdp = (ACPI_TABLE_HEADER *)rsdt;
106 		if (sdp->Length < sizeof (ACPI_TABLE_HEADER)) {
107 			entries = 0;
108 		} else {
109 			entries = sdp->Length - sizeof (ACPI_TABLE_HEADER);
110 			entries /= ACPI_RSDT_ENTRY_SIZE;
111 		}
112 		for (i = 0; i < entries; i++) {
113 			if (rsdt->TableOffsetEntry[i] == 0)
114 				continue;
115 			sdp = acpi_map_sdt(rsdt->TableOffsetEntry[i]);
116 			if (sdp->Length < sizeof (ACPI_TABLE_HEADER))
117 				continue;
118 
119 			if (acpi_checksum(sdp, sdp->Length))
120 				continue;
121 
122 			if (ACPI_COMPARE_NAME(sig, sdp->Signature))
123 				return (sdp);
124 		}
125 	}
126 	return (NULL);
127 }
128 
129 void
acpi_detect(void)130 acpi_detect(void)
131 {
132 	char	buf[24];
133 	int	revision;
134 
135 	if ((rsdp = efi_get_table(&gEfiAcpi20TableGuid)) == NULL)
136 		rsdp = efi_get_table(&gEfiAcpiTableGuid);
137 
138 	if (rsdp == NULL)
139 		return;
140 
141 	/* export values from the RSDP */
142 #ifdef _LP64
143 	snprintf(buf, sizeof (buf), "0x%016llx", (unsigned long long)rsdp);
144 #else
145 	snprintf(buf, sizeof (buf), "0x%08x", (unsigned int)rsdp);
146 #endif
147 	setenv("acpi.rsdp", buf, 1);
148 	revision = rsdp->Revision;
149 	if (revision == 0)
150 		revision = 1;
151 	snprintf(buf, sizeof (buf), "%d", revision);
152 	setenv("acpi.revision", buf, 1);
153 	strncpy(buf, rsdp->OemId, sizeof (rsdp->OemId));
154 	buf[sizeof (rsdp->OemId)] = '\0';
155 	setenv("acpi.oem", buf, 1);
156 #ifdef _LP64
157 	snprintf(buf, sizeof (buf), "0x%016llx",
158 	    (unsigned long long)rsdp->RsdtPhysicalAddress);
159 #else
160 	snprintf(buf, sizeof (buf), "0x%08x", rsdp->RsdtPhysicalAddress);
161 #endif
162 	setenv("acpi.rsdt", buf, 1);
163 	if (revision >= 2) {
164 		snprintf(buf, sizeof (buf), "0x%016llx",
165 		    (unsigned long long)rsdp->XsdtPhysicalAddress);
166 		setenv("acpi.xsdt", buf, 1);
167 		snprintf(buf, sizeof (buf), "%d", rsdp->Length);
168 		setenv("acpi.xsdt_length", buf, 1);
169 	}
170 }
171