2 * Copyright (c) 1998 Doug Rabson
3 * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/param.h>
31 #include <sys/endian.h>
33 #include <sys/queue.h>
35 #include <sys/sysctl.h>
49 static void acpi_handle_apic(struct ACPIsdt *sdp);
50 static struct ACPIsdt *acpi_map_sdt(vm_offset_t pa);
51 static void acpi_handle_rsdt(struct ACPIsdt *rsdp);
52 static struct acpi_user_mapping *acpi_user_find_mapping(vm_offset_t, size_t);
53 static void * acpi_map_physical(vm_offset_t, size_t);
55 /* Size of an address. 32-bit for ACPI 1.0, 64-bit for ACPI 2.0 and up. */
60 int acpi_detect(void);
63 acpi_handle_apic(struct ACPIsdt *sdp)
65 struct MADTbody *madtp;
67 struct MADT_local_apic *apic;
68 struct MADT_local_sapic *sapic;
70 madtp = (struct MADTbody *) sdp->body;
71 mp = (struct MADT_APIC *)madtp->body;
72 while (((uintptr_t)mp) - ((uintptr_t)sdp) < sdp->len) {
74 case ACPI_MADT_APIC_TYPE_LOCAL_APIC:
75 apic = &mp->body.local_apic;
76 warnx("MADT: Found CPU APIC ID %d %s",
78 apic->flags & ACPI_MADT_APIC_LOCAL_FLAG_ENABLED ?
79 "enabled" : "disabled");
80 if (apic->flags & ACPI_MADT_APIC_LOCAL_FLAG_ENABLED)
83 case ACPI_MADT_APIC_TYPE_LOCAL_SAPIC:
84 sapic = &mp->body.local_sapic;
85 warnx("MADT: Found CPU SAPIC ID %d %s",
87 sapic->flags & ACPI_MADT_APIC_LOCAL_FLAG_ENABLED ?
88 "enabled" : "disabled");
89 /* XXX is enable flag the same? */
90 if (sapic->flags & ACPI_MADT_APIC_LOCAL_FLAG_ENABLED)
96 mp = (struct MADT_APIC *) ((char *)mp + mp->len);
101 acpi_checksum(void *p, size_t length)
114 static struct ACPIsdt *
115 acpi_map_sdt(vm_offset_t pa)
119 sp = acpi_map_physical(pa, sizeof(struct ACPIsdt));
120 sp = acpi_map_physical(pa, sp->len);
125 acpi_handle_rsdt(struct ACPIsdt *rsdp)
131 entries = (rsdp->len - SIZEOF_SDT_HDR) / addr_size;
132 for (i = 0; i < entries; i++) {
135 addr = le32dec((char*)rsdp->body + i * addr_size);
138 addr = le64dec((char*)rsdp->body + i * addr_size);
144 sdp = (struct ACPIsdt *)acpi_map_sdt(addr);
145 if (acpi_checksum(sdp, sdp->len)) {
147 warnx("RSDT entry %d (sig %.4s) has bad checksum", i,
152 if (!memcmp(sdp->signature, "APIC", 4))
153 acpi_handle_apic(sdp);
157 static char machdep_acpi_root[] = "machdep.acpi_root";
158 static int acpi_mem_fd = -1;
160 struct acpi_user_mapping {
161 LIST_ENTRY(acpi_user_mapping) link;
167 LIST_HEAD(acpi_user_mapping_list, acpi_user_mapping) maplist;
173 if (acpi_mem_fd == -1) {
174 acpi_mem_fd = open(_PATH_MEM, O_RDONLY);
175 if (acpi_mem_fd == -1)
176 err(1, "opening " _PATH_MEM);
181 static struct acpi_user_mapping *
182 acpi_user_find_mapping(vm_offset_t pa, size_t size)
184 struct acpi_user_mapping *map;
186 /* First search for an existing mapping */
187 for (map = LIST_FIRST(&maplist); map; map = LIST_NEXT(map, link)) {
188 if (map->pa <= pa && map->size >= pa + size - map->pa)
192 /* Then create a new one */
193 size = round_page(pa + size) - trunc_page(pa);
195 map = malloc(sizeof(struct acpi_user_mapping));
197 errx(1, "out of memory");
199 map->va = mmap(0, size, PROT_READ, MAP_SHARED, acpi_mem_fd, pa);
201 if ((intptr_t) map->va == -1)
202 err(1, "can't map address");
203 LIST_INSERT_HEAD(&maplist, map, link);
209 acpi_map_physical(vm_offset_t pa, size_t size)
211 struct acpi_user_mapping *map;
213 map = acpi_user_find_mapping(pa, size);
214 return (map->va + (pa - map->pa));
217 static struct ACPIrsdp *
218 acpi_get_rsdp(u_long addr)
220 struct ACPIrsdp rsdp;
223 /* Read in the table signature and check it. */
224 pread(acpi_mem_fd, &rsdp, 8, addr);
225 if (memcmp(rsdp.signature, "RSD PTR ", 8))
228 /* Read the entire table. */
229 pread(acpi_mem_fd, &rsdp, sizeof(rsdp), addr);
231 /* Run the checksum only over the version 1 header. */
232 if (acpi_checksum(&rsdp, 20))
235 /* If the revision is 0, assume a version 1 length. */
236 if (rsdp.revision == 0)
241 /* XXX Should handle ACPI 2.0 RSDP extended checksum here. */
243 return (acpi_map_physical(addr, len));
247 devstate(devinfo_state_t state)
251 return "not-present";
259 return "unknown-state";
264 acpi0_check(struct devinfo_dev *dd, void *arg)
266 printf("%s: %s %s\n", __func__, dd->dd_name, devstate(dd->dd_state));
267 /* NB: device must be present AND attached */
268 if (strcmp(dd->dd_name, "acpi0") == 0)
269 return (dd->dd_state == DS_ATTACHED ||
270 dd->dd_state == DS_BUSY);
271 return devinfo_foreach_device_child(dd, acpi0_check, arg);
277 struct devinfo_dev *root;
282 root = devinfo_handle_to_device(DEVINFO_ROOT_DEVICE);
284 found = devinfo_foreach_device_child(root, acpi0_check, NULL);
293 struct ACPIsdt *rsdp;
297 if (!acpi0_present()) {
298 warnx("no acpi0 device located");
304 /* Attempt to use sysctl to find RSD PTR record. */
306 if (sysctlbyname(machdep_acpi_root, &addr, &len, NULL, 0) != 0) {
307 warnx("cannot find ACPI information");
310 rp = acpi_get_rsdp(addr);
312 warnx("cannot find ACPI information: sysctl %s does not point to RSDP",
316 if (rp->revision < 2) {
317 rsdp = (struct ACPIsdt *)acpi_map_sdt(rp->rsdt_addr);
318 if (memcmp(rsdp->signature, "RSDT", 4) != 0 ||
319 acpi_checksum(rsdp, rsdp->len) != 0)
320 errx(1, "RSDT is corrupted");
321 addr_size = sizeof(uint32_t);
323 rsdp = (struct ACPIsdt *)acpi_map_sdt(rp->xsdt_addr);
324 if (memcmp(rsdp->signature, "XSDT", 4) != 0 ||
325 acpi_checksum(rsdp, rsdp->len) != 0)
326 errx(1, "XSDT is corrupted");
327 addr_size = sizeof(uint64_t);
330 acpi_handle_rsdt(rsdp);
331 return (ncpu == 0 ? 1 : ncpu);