xref: /openbsd-src/usr.sbin/acpidump/acpidump.c (revision d1df930ffab53da22f3324c32bed7ac5709915e6)
1 /*	$OpenBSD: acpidump.c,v 1.21 2018/08/08 18:46:04 deraadt Exp $	*/
2 /*
3  * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
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.
14  *
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
25  * SUCH DAMAGE.
26  *
27  */
28 
29 #include <sys/types.h>
30 #include <sys/mman.h>
31 #include <sys/queue.h>
32 #include <sys/stat.h>
33 
34 #include <assert.h>
35 #include <err.h>
36 #include <fcntl.h>
37 #include <kvm.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42 #include <limits.h>
43 #include <paths.h>
44 
45 
46 #define vm_page_size sysconf(_SC_PAGESIZE)
47 #define PRINTFLAG(xx)							\
48 	do {								\
49 		if (facp->flags & ACPI_FACP_FLAG_## xx) {		\
50 			fprintf(fhdr, "%c%s", sep, #xx); sep = ',';	\
51 		}							\
52 	} while (0)
53 
54 
55 typedef unsigned long	vm_offset_t;
56 
57 struct ACPIrsdp {
58 	u_char		signature[8];
59 	u_char		sum;
60 	u_char		oem[6];
61 	u_char		rev;
62 	u_int32_t	addr;
63 #define SIZEOF_RSDP_REV_0	20
64 	u_int32_t	len;
65 	u_int64_t	xaddr;
66 	u_char		xsum;
67 	u_char		xres[3];
68 } __packed;
69 
70 struct ACPIsdt {
71 	u_char		signature[4];
72 	u_int32_t	len;
73 	u_char		rev;
74 	u_char		check;
75 	u_char		oemid[6];
76 	u_char		oemtblid[8];
77 	u_int32_t	oemrev;
78 	u_char		creator[4];
79 	u_int32_t	crerev;
80 #define SIZEOF_SDT_HDR	36	/* struct size except body */
81 	u_int32_t	body[1];/* This member should be casted */
82 } __packed;
83 
84 struct ACPIgas {
85 	u_int8_t	address_space_id;
86 #define ACPI_GAS_MEMORY		0
87 #define ACPI_GAS_IO		1
88 #define ACPI_GAS_PCI		2
89 #define ACPI_GAS_EMBEDDED	3
90 #define ACPI_GAS_SMBUS		4
91 #define ACPI_GAS_FIXED		0x7f
92 	u_int8_t	register_bit_width;
93 	u_int8_t	register_bit_offset;
94 	u_int8_t	res;
95 	u_int64_t	address;
96 } __packed;
97 
98 struct FACPbody {
99 	u_int32_t	facs_ptr;
100 	u_int32_t	dsdt_ptr;
101 	u_int8_t	int_model;
102 #define ACPI_FACP_INTMODEL_PIC	0	/* Standard PC-AT PIC */
103 #define ACPI_FACP_INTMODEL_APIC	1	/* Multiple APIC */
104 	u_char		reserved1;
105 	u_int16_t	sci_int;
106 	u_int32_t	smi_cmd;
107 	u_int8_t	acpi_enable;
108 	u_int8_t	acpi_disable;
109 	u_int8_t	s4biosreq;
110 	u_int8_t	reserved2;
111 	u_int32_t	pm1a_evt_blk;
112 	u_int32_t	pm1b_evt_blk;
113 	u_int32_t	pm1a_cnt_blk;
114 	u_int32_t	pm1b_cnt_blk;
115 	u_int32_t	pm2_cnt_blk;
116 	u_int32_t	pm_tmr_blk;
117 	u_int32_t	gpe0_blk;
118 	u_int32_t	gpe1_blk;
119 	u_int8_t	pm1_evt_len;
120 	u_int8_t	pm1_cnt_len;
121 	u_int8_t	pm2_cnt_len;
122 	u_int8_t	pm_tmr_len;
123 	u_int8_t	gpe0_len;
124 	u_int8_t	gpe1_len;
125 	u_int8_t	gpe1_base;
126 	u_int8_t	reserved3;
127 	u_int16_t	p_lvl2_lat;
128 	u_int16_t	p_lvl3_lat;
129 	u_int16_t	flush_size;
130 	u_int16_t	flush_stride;
131 	u_int8_t	duty_off;
132 	u_int8_t	duty_width;
133 	u_int8_t	day_alrm;
134 	u_int8_t	mon_alrm;
135 	u_int8_t	century;
136 	u_int16_t	iapc_boot_arch;
137 	u_char		reserved4[1];
138 	u_int32_t	flags;
139 #define ACPI_FACP_FLAG_WBINVD	1	/* WBINVD is correctly supported */
140 #define ACPI_FACP_FLAG_WBINVD_FLUSH 2	/* WBINVD flushes caches */
141 #define ACPI_FACP_FLAG_PROC_C1	4	/* C1 power state supported */
142 #define ACPI_FACP_FLAG_P_LVL2_UP 8	/* C2 power state works on SMP */
143 #define ACPI_FACP_FLAG_PWR_BUTTON 16	/* Power button uses control method */
144 #define ACPI_FACP_FLAG_SLP_BUTTON 32	/* Sleep button uses control method */
145 #define ACPI_FACP_FLAG_FIX_RTC	64	/* RTC wakeup not supported */
146 #define ACPI_FACP_FLAG_RTC_S4	128	/* RTC can wakeup from S4 state */
147 #define ACPI_FACP_FLAG_TMR_VAL_EXT 256	/* TMR_VAL is 32bit */
148 #define ACPI_FACP_FLAG_DCK_CAP	512	/* Can support docking */
149 	struct ACPIgas	reset_reg;
150 	u_int8_t	reset_value;
151 	u_int8_t	reserved5[3];
152 	u_int64_t	x_firmware_ctrl;
153 	u_int64_t	x_dsdt;
154 	struct ACPIgas	x_pm1a_evt_blk;
155 	struct ACPIgas	x_pm1b_evt_blk;
156 	struct ACPIgas	x_pm1a_cnt_blk;
157 	struct ACPIgas	x_pm1b_cnt_blk;
158 	struct ACPIgas	x_pm2_cnt_blk;
159 	struct ACPIgas	x_pm_tmr_blk;
160 	struct ACPIgas	x_gpe0_blk;
161 	struct ACPIgas	x_gpe1_blk;
162 } __packed;
163 
164 struct acpi_user_mapping {
165 	LIST_ENTRY(acpi_user_mapping)	link;
166 	vm_offset_t			pa;
167 	caddr_t				va;
168 	size_t				size;
169 };
170 
171 LIST_HEAD(acpi_user_mapping_list, acpi_user_mapping) maplist;
172 
173 int		acpi_mem_fd = -1;
174 char		*aml_dumpfile;
175 int		aml_dumpdir;
176 FILE		*fhdr;
177 
178 int	acpi_checksum(void *_p, size_t _length);
179 struct acpi_user_mapping *acpi_user_find_mapping(vm_offset_t _pa, size_t _size);
180 void	*acpi_map_physical(vm_offset_t _pa, size_t _size);
181 void	acpi_user_init(void);
182 struct ACPIrsdp *acpi_check_rsd_ptr(vm_offset_t _pa);
183 struct ACPIrsdp *acpi_find_rsd_ptr(void);
184 void	acpi_print_string(char *_s, size_t _length);
185 void	acpi_print_rsd_ptr(struct ACPIrsdp *_rp);
186 struct ACPIsdt *acpi_map_sdt(vm_offset_t _pa);
187 void	aml_dump(struct ACPIsdt *_hdr);
188 void	acpi_print_sdt(struct ACPIsdt *_sdp);
189 void	acpi_print_rsdt(struct ACPIsdt *_rsdp);
190 void	acpi_print_xsdt(struct ACPIsdt *_rsdp);
191 void	acpi_print_facp(struct FACPbody *_facp);
192 void	acpi_print_dsdt(struct ACPIsdt *_dsdp);
193 void	acpi_handle_dsdt(struct ACPIsdt *_dsdp);
194 void	acpi_handle_facp(struct FACPbody *_facp);
195 void	acpi_handle_rsdt(struct ACPIsdt *_rsdp);
196 void	acpi_handle_xsdt(struct ACPIsdt *_rsdp);
197 void	asl_dump_from_devmem(void);
198 void	usage(void);
199 u_long	efi_acpi_addr(void);
200 
201 
202 struct ACPIsdt	dsdt_header = {
203 	"DSDT", 0, 1, 0, "OEMID", "OEMTBLID", 0x12345678, "CRTR", 0x12345678
204 };
205 
206 int
207 acpi_checksum(void *p, size_t length)
208 {
209 	u_int8_t	*bp;
210 	u_int8_t	sum;
211 
212 	bp = p;
213 	sum = 0;
214 	while (length--)
215 		sum += *bp++;
216 
217 	return (sum);
218 }
219 
220 struct acpi_user_mapping *
221 acpi_user_find_mapping(vm_offset_t pa, size_t size)
222 {
223 	struct acpi_user_mapping	*map;
224 	int	page_mask = getpagesize() - 1;
225 
226 	/* First search for an existing mapping */
227 	for (map = LIST_FIRST(&maplist); map; map = LIST_NEXT(map, link)) {
228 		if (map->pa <= pa && map->size >= pa + size - map->pa)
229 			return (map);
230 	}
231 
232 	/* Then create a new one */
233 #undef round_page
234 #undef trunc_page
235 #define	round_page(x)	(((x) + page_mask) & ~page_mask)
236 #define	trunc_page(x)	((x) & ~page_mask)
237 	size = round_page(pa + size) - trunc_page(pa);
238 	pa = trunc_page(pa);
239 #undef round_page
240 #undef trunc_page
241 	map = malloc(sizeof(struct acpi_user_mapping));
242 	if (!map)
243 		errx(1, "out of memory");
244 	map->pa = pa;
245 	map->va = mmap(0, size, PROT_READ, MAP_SHARED, acpi_mem_fd, pa);
246 	map->size = size;
247 	if (map->va == MAP_FAILED)
248 		err(1, "can't map address");
249 	LIST_INSERT_HEAD(&maplist, map, link);
250 
251 	return (map);
252 }
253 
254 void *
255 acpi_map_physical(vm_offset_t pa, size_t size)
256 {
257 	struct acpi_user_mapping	*map;
258 
259 	map = acpi_user_find_mapping(pa, size);
260 	return (map->va + (pa - map->pa));
261 }
262 
263 void
264 acpi_user_init(void)
265 {
266 	if (acpi_mem_fd == -1) {
267 		acpi_mem_fd = open("/dev/mem", O_RDONLY);
268 		if (acpi_mem_fd == -1)
269 			err(1, "opening /dev/mem");
270 		LIST_INIT(&maplist);
271 	}
272 }
273 
274 struct ACPIrsdp *
275 acpi_check_rsd_ptr(vm_offset_t pa)
276 {
277 	struct ACPIrsdp rp;
278 
279 	lseek(acpi_mem_fd, pa, SEEK_SET);
280 	read(acpi_mem_fd, &rp, SIZEOF_RSDP_REV_0);
281 	if (memcmp(rp.signature, "RSD PTR ", 8) != 0)
282 		return NULL;
283 
284 	if (rp.rev >= 2) {
285 		read(acpi_mem_fd, &(rp.len),
286 		    sizeof(struct ACPIrsdp) - SIZEOF_RSDP_REV_0);
287 		if (acpi_checksum(&rp, sizeof(struct ACPIrsdp)) == 0)
288 			return acpi_map_physical(pa, sizeof(struct ACPIrsdp));
289 	}
290 
291 	if (acpi_checksum(&rp, SIZEOF_RSDP_REV_0) == 0)
292 		return (acpi_map_physical(pa, SIZEOF_RSDP_REV_0));
293 
294 	return NULL;
295 }
296 
297 struct ACPIrsdp *
298 acpi_find_rsd_ptr(void)
299 {
300 	struct ACPIrsdp *rp;
301 	u_long		addr;
302 
303 	if ((addr = efi_acpi_addr()) != 0) {
304 		if ((rp = acpi_check_rsd_ptr(addr)))
305 			return rp;
306 	}
307 
308 #if defined(__amd64__) || defined (__i386__)
309 	for (addr = 0; addr < 1024 * 1024; addr += 16) {
310 		if ((rp = acpi_check_rsd_ptr(addr)))
311 			return rp;
312 	}
313 #endif
314 
315 	return NULL;
316 }
317 
318 void
319 acpi_print_string(char *s, size_t length)
320 {
321 	int		c;
322 
323 	/* Trim trailing spaces and NULLs */
324 	while (length > 0 && (s[length - 1] == ' ' || s[length - 1] == '\0'))
325 		length--;
326 
327 	while (length--) {
328 		c = *s++;
329 		fputc(c, fhdr);
330 	}
331 }
332 
333 void
334 acpi_print_rsd_ptr(struct ACPIrsdp *rp)
335 {
336 	fprintf(fhdr, "\n");
337 	fprintf(fhdr, "RSD PTR: Checksum=%d, OEMID=", rp->sum);
338 	acpi_print_string(rp->oem, 6);
339 	fprintf(fhdr, ", Revision=%d", rp->rev);
340 	fprintf(fhdr, ", RsdtAddress=0x%08x\n", rp->addr);
341 	if (rp->rev >= 2) {
342 		fprintf(fhdr, "\tLength=%d", rp->len);
343 		fprintf(fhdr, ", XsdtAddress=0x%016llx", rp->xaddr);
344 		fprintf(fhdr, ", Extended Checksum=%d\n", rp->xsum);
345 	}
346 	fprintf(fhdr, "\n");
347 }
348 
349 struct ACPIsdt *
350 acpi_map_sdt(vm_offset_t pa)
351 {
352 	struct ACPIsdt	*sp;
353 
354 	sp = acpi_map_physical(pa, sizeof(struct ACPIsdt));
355 	sp = acpi_map_physical(pa, sp->len);
356 	return (sp);
357 }
358 
359 void
360 aml_dump(struct ACPIsdt *hdr)
361 {
362 	static int	hdr_index;
363 	char		name[PATH_MAX];
364 	int		fd;
365 	mode_t		mode;
366 
367 	snprintf(name, sizeof(name), "%s%c%c%c%c%c.%d",
368 	    aml_dumpfile, aml_dumpdir ? '/' : '.',
369 	    hdr->signature[0], hdr->signature[1],
370 	    hdr->signature[2], hdr->signature[3],
371 	    hdr_index++);
372 
373 	mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
374 	fd = open(name, O_WRONLY | O_CREAT | O_TRUNC, mode);
375 	if (fd == -1)
376 		err(1, "aml_dump");
377 
378 	write(fd, hdr, SIZEOF_SDT_HDR);
379 	write(fd, hdr->body, hdr->len - SIZEOF_SDT_HDR);
380 	close(fd);
381 }
382 
383 void
384 acpi_print_sdt(struct ACPIsdt *sdp)
385 {
386 	fprintf(fhdr, "\n");
387 	acpi_print_string(sdp->signature, 4);
388 	fprintf(fhdr, ": Length=%d, Revision=%d, Checksum=%d,\n",
389 	       sdp->len, sdp->rev, sdp->check);
390 	fprintf(fhdr, "\tOEMID=");
391 	acpi_print_string(sdp->oemid, 6);
392 	fprintf(fhdr, ", OEM Table ID=");
393 	acpi_print_string(sdp->oemtblid, 8);
394 	fprintf(fhdr, ", OEM Revision=0x%x,\n", sdp->oemrev);
395 	fprintf(fhdr, "\tCreator ID=");
396 	acpi_print_string(sdp->creator, 4);
397 	fprintf(fhdr, ", Creator Revision=0x%x\n", sdp->crerev);
398 	fprintf(fhdr, "\n");
399 	if (!memcmp(sdp->signature, "DSDT", 4))
400 		memcpy(&dsdt_header, sdp, sizeof(dsdt_header));
401 }
402 
403 void
404 acpi_print_rsdt(struct ACPIsdt *rsdp)
405 {
406 	int		i, entries;
407 
408 	acpi_print_sdt(rsdp);
409 	entries = (rsdp->len - SIZEOF_SDT_HDR) / sizeof(u_int32_t);
410 	fprintf(fhdr, "\n");
411 	fprintf(fhdr, "\tEntries={ ");
412 	for (i = 0; i < entries; i++) {
413 		if (i > 0)
414 			fprintf(fhdr, ", ");
415 		fprintf(fhdr, "0x%08x", rsdp->body[i]);
416 	}
417 	fprintf(fhdr, " }\n");
418 	fprintf(fhdr, "\n");
419 }
420 
421 void
422 acpi_print_xsdt(struct ACPIsdt *rsdp)
423 {
424 	int		i, entries;
425 	u_int64_t	*body = (u_int64_t *) rsdp->body;
426 
427 	acpi_print_sdt(rsdp);
428 	entries = (rsdp->len - SIZEOF_SDT_HDR) / sizeof(u_int64_t);
429 	fprintf(fhdr, "\n");
430 	fprintf(fhdr, "\tEntries={ ");
431 	for (i = 0; i < entries; i++) {
432 		if (i > 0)
433 			fprintf(fhdr, ", ");
434 		fprintf(fhdr, "0x%016llx", body[i]);
435 	}
436 	fprintf(fhdr, " }\n");
437 	fprintf(fhdr, "\n");
438 }
439 
440 void
441 acpi_print_facp(struct FACPbody *facp)
442 {
443 	char		sep;
444 
445 	fprintf(fhdr, "\n");
446 	fprintf(fhdr, "\tDSDT=0x%x\n", facp->dsdt_ptr);
447 	fprintf(fhdr, "\tINT_MODEL=%s\n", facp->int_model ? "APIC" : "PIC");
448 	fprintf(fhdr, "\tSCI_INT=%d\n", facp->sci_int);
449 	fprintf(fhdr, "\tSMI_CMD=0x%x, ", facp->smi_cmd);
450 	fprintf(fhdr, "ACPI_ENABLE=0x%x, ", facp->acpi_enable);
451 	fprintf(fhdr, "ACPI_DISABLE=0x%x, ", facp->acpi_disable);
452 	fprintf(fhdr, "S4BIOS_REQ=0x%x\n", facp->s4biosreq);
453 	if (facp->pm1a_evt_blk)
454 		fprintf(fhdr, "\tPM1a_EVT_BLK=0x%x-0x%x\n",
455 		    facp->pm1a_evt_blk,
456 		    facp->pm1a_evt_blk + facp->pm1_evt_len - 1);
457 	if (facp->pm1b_evt_blk)
458 		fprintf(fhdr, "\tPM1b_EVT_BLK=0x%x-0x%x\n",
459 		    facp->pm1b_evt_blk,
460 		    facp->pm1b_evt_blk + facp->pm1_evt_len - 1);
461 	if (facp->pm1a_cnt_blk)
462 		fprintf(fhdr, "\tPM1a_CNT_BLK=0x%x-0x%x\n",
463 		    facp->pm1a_cnt_blk,
464 		    facp->pm1a_cnt_blk + facp->pm1_cnt_len - 1);
465 	if (facp->pm1b_cnt_blk)
466 		fprintf(fhdr, "\tPM1b_CNT_BLK=0x%x-0x%x\n",
467 		    facp->pm1b_cnt_blk,
468 		    facp->pm1b_cnt_blk + facp->pm1_cnt_len - 1);
469 	if (facp->pm2_cnt_blk)
470 		fprintf(fhdr, "\tPM2_CNT_BLK=0x%x-0x%x\n",
471 		    facp->pm2_cnt_blk,
472 		    facp->pm2_cnt_blk + facp->pm2_cnt_len - 1);
473 	if (facp->pm_tmr_blk)
474 		fprintf(fhdr, "\tPM2_TMR_BLK=0x%x-0x%x\n",
475 		    facp->pm_tmr_blk,
476 		    facp->pm_tmr_blk + facp->pm_tmr_len - 1);
477 	if (facp->gpe0_blk)
478 		fprintf(fhdr, "\tPM2_GPE0_BLK=0x%x-0x%x\n",
479 		    facp->gpe0_blk,
480 		    facp->gpe0_blk + facp->gpe0_len - 1);
481 	if (facp->gpe1_blk)
482 		fprintf(fhdr, "\tPM2_GPE1_BLK=0x%x-0x%x, GPE1_BASE=%d\n",
483 		    facp->gpe1_blk,
484 		    facp->gpe1_blk + facp->gpe1_len - 1,
485 		    facp->gpe1_base);
486 	fprintf(fhdr, "\tP_LVL2_LAT=%dms, P_LVL3_LAT=%dms\n",
487 	    facp->p_lvl2_lat, facp->p_lvl3_lat);
488 	fprintf(fhdr, "\tFLUSH_SIZE=%d, FLUSH_STRIDE=%d\n",
489 	    facp->flush_size, facp->flush_stride);
490 	fprintf(fhdr, "\tDUTY_OFFSET=%d, DUTY_WIDTH=%d\n",
491 	    facp->duty_off, facp->duty_width);
492 	fprintf(fhdr, "\tDAY_ALRM=%d, MON_ALRM=%d, CENTURY=%d\n",
493 	    facp->day_alrm, facp->mon_alrm, facp->century);
494 	fprintf(fhdr, "\tFlags=");
495 	sep = '{';
496 
497 	PRINTFLAG(WBINVD);
498 	PRINTFLAG(WBINVD_FLUSH);
499 	PRINTFLAG(PROC_C1);
500 	PRINTFLAG(P_LVL2_UP);
501 	PRINTFLAG(PWR_BUTTON);
502 	PRINTFLAG(SLP_BUTTON);
503 	PRINTFLAG(FIX_RTC);
504 	PRINTFLAG(RTC_S4);
505 	PRINTFLAG(TMR_VAL_EXT);
506 	PRINTFLAG(DCK_CAP);
507 
508 	fprintf(fhdr, "}\n");
509 	fprintf(fhdr, "\n");
510 }
511 
512 void
513 acpi_print_dsdt(struct ACPIsdt *dsdp)
514 {
515 	acpi_print_sdt(dsdp);
516 }
517 
518 void
519 acpi_handle_dsdt(struct ACPIsdt *dsdp)
520 {
521 	u_int8_t	*dp;
522 	u_int8_t	*end;
523 
524 	acpi_print_dsdt(dsdp);
525 
526 	dp = (u_int8_t *)dsdp->body;
527 	end = (u_int8_t *)dsdp + dsdp->len;
528 }
529 
530 void
531 acpi_handle_facp(struct FACPbody *facp)
532 {
533 	struct ACPIsdt	*dsdp;
534 
535 	acpi_print_facp(facp);
536 	if (facp->dsdt_ptr == 0)
537 		dsdp = (struct ACPIsdt *) acpi_map_sdt(facp->x_dsdt);
538 	else
539 		dsdp = (struct ACPIsdt *) acpi_map_sdt(facp->dsdt_ptr);
540 	if (acpi_checksum(dsdp, dsdp->len))
541 		errx(1, "DSDT is corrupt");
542 	acpi_handle_dsdt(dsdp);
543 	aml_dump(dsdp);
544 }
545 
546 void
547 acpi_handle_rsdt(struct ACPIsdt *rsdp)
548 {
549 	int		i;
550 	int		entries;
551 	struct ACPIsdt	*sdp;
552 
553 	aml_dump(rsdp);
554 	entries = (rsdp->len - SIZEOF_SDT_HDR) / sizeof(u_int32_t);
555 	acpi_print_rsdt(rsdp);
556 	for (i = 0; i < entries; i++) {
557 		sdp = (struct ACPIsdt *) acpi_map_sdt(rsdp->body[i]);
558 		if (acpi_checksum(sdp, sdp->len))
559 			errx(1, "RSDT entry %d is corrupt", i);
560 		aml_dump(sdp);
561 		if (!memcmp(sdp->signature, "FACP", 4)) {
562 			acpi_handle_facp((struct FACPbody *) sdp->body);
563 		} else {
564 			acpi_print_sdt(sdp);
565 		}
566 	}
567 }
568 
569 void
570 acpi_handle_xsdt(struct ACPIsdt *rsdp)
571 {
572 	int		i;
573 	int		entries;
574 	struct ACPIsdt	*sdp;
575 	u_int64_t	*body = (u_int64_t *) rsdp->body;
576 
577 	aml_dump(rsdp);
578 	entries = (rsdp->len - SIZEOF_SDT_HDR) / sizeof(u_int64_t);
579 	acpi_print_xsdt(rsdp);
580 	for (i = 0; i < entries; i++) {
581 		sdp = (struct ACPIsdt *) acpi_map_sdt(body[i]);
582 		if (acpi_checksum(sdp, sdp->len))
583 			errx(1, "XSDT entry %d is corrupt", i);
584 		aml_dump(sdp);
585 		if (!memcmp(sdp->signature, "FACP", 4)) {
586 			acpi_handle_facp((struct FACPbody *) sdp->body);
587 		} else {
588 			acpi_print_sdt(sdp);
589 		}
590 	}
591 }
592 
593 void
594 asl_dump_from_devmem(void)
595 {
596 	struct ACPIrsdp	*rp;
597 	struct ACPIsdt	*rsdp;
598 	char		name[PATH_MAX];
599 
600 	snprintf(name, sizeof(name), "%s%cheaders", aml_dumpfile,
601 	    aml_dumpdir ? '/' : '.');
602 
603 	acpi_user_init();
604 
605 	/* Can only unveil if being dumped to a dir */
606 	if (aml_dumpdir) {
607 		if (unveil(aml_dumpfile, "wc") == -1)
608 			err(1, "unveil");
609 	} else if (aml_dumpfile[0] == '/') {	/* admittedly pretty shitty */
610 		if (unveil("/", "wc") == -1)
611 			err(1, "unveil");
612 	} else {
613 		if (unveil(".", "wc") == -1)
614 			err(1, "unveil");
615 	}
616 
617 	if (unveil(_PATH_MEM, "r") == -1)
618 		err(1, "unveil");
619 	if (unveil(_PATH_KMEM, "r") == -1)
620 		err(1, "unveil");
621 	if (unveil(_PATH_KVMDB, "r") == -1)
622 		err(1, "unveil");
623 	if (unveil(_PATH_KSYMS, "r") == -1)
624 		err(1, "unveil");
625 	if (unveil(_PATH_UNIX, "r") == -1)
626 		err(1, "unveil");
627 	if (pledge("stdio rpath wpath cpath", NULL) == -1)
628 		err(1, "pledge");
629 
630 	rp = acpi_find_rsd_ptr();
631 	if (!rp)
632 		errx(1, "Can't find ACPI information");
633 
634 	fhdr = fopen(name, "w");
635 	if (fhdr == NULL)
636 		err(1, "asl_dump_from_devmem");
637 
638 	acpi_print_rsd_ptr(rp);
639 	if (rp->addr != 0) {
640 		rsdp = (struct ACPIsdt *) acpi_map_sdt(rp->addr);
641 		if (memcmp(rsdp->signature, "RSDT", 4) ||
642 		    acpi_checksum(rsdp, rsdp->len))
643 			errx(1, "RSDT is corrupted");
644 
645 		acpi_handle_rsdt(rsdp);
646 	} else {
647 		rsdp = (struct ACPIsdt *) acpi_map_sdt(rp->xaddr);
648 		if (memcmp(rsdp->signature, "XSDT", 4) ||
649 		    acpi_checksum(rsdp, rsdp->len))
650 			errx(1, "XSDT is corrupted");
651 
652 		acpi_handle_xsdt(rsdp);
653 	}
654 
655 	fclose(fhdr);
656 }
657 
658 void
659 usage(void)
660 {
661 	extern char	*__progname;
662 
663 	fprintf(stderr, "usage: %s -o prefix\n", __progname);
664 	exit(1);
665 }
666 
667 int
668 main(int argc, char *argv[])
669 {
670 	struct stat	st;
671 	int		c;
672 
673 	while ((c = getopt(argc, argv, "o:")) != -1) {
674 		switch (c) {
675 		case 'o':
676 			aml_dumpfile = optarg;
677 			break;
678 		default:
679 			usage();
680 			break;
681 		}
682 	}
683 
684 	if (aml_dumpfile == NULL)
685 		usage();
686 
687 	if (stat(aml_dumpfile, &st) == 0 && S_ISDIR(st.st_mode))
688 		aml_dumpdir = 1;
689 
690 	asl_dump_from_devmem();
691 
692 	return (0);
693 }
694 
695 #ifdef __aarch64__
696 
697 u_long
698 efi_acpi_addr(void)
699 {
700 	kvm_t		*kd;
701 	struct nlist	 nl[2];
702 	uint64_t	 table;
703 
704 	memset(&nl, 0, sizeof(nl));
705 	kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, NULL);
706 	if (kd == NULL)
707 		goto on_error;
708 	nl[0].n_name = "efi_acpi_table";
709 	if (kvm_nlist(kd, nl) == -1)
710 		goto on_error;
711 	if (kvm_read(kd, nl[0].n_value, &table, sizeof(table)) == -1)
712 		goto on_error;
713 
714 	kvm_close(kd);
715 	return table;
716 
717 on_error:
718 	if (kd != NULL)
719 		kvm_close(kd);
720 	return (0);
721 }
722 
723 #else
724 
725 #include <machine/biosvar.h>
726 
727 u_long
728 efi_acpi_addr(void)
729 {
730 	kvm_t		*kd;
731 	struct nlist	 nl[2];
732 	bios_efiinfo_t	 efiinfo;
733 	u_long	 ptr;
734 
735 	memset(&nl, 0, sizeof(nl));
736 	kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, NULL);
737 	if (kd == NULL)
738 		goto on_error;
739 	nl[0].n_name = "_bios_efiinfo";
740 	if (kvm_nlist(kd, nl) == -1)
741 		goto on_error;
742 	if (kvm_read(kd, nl[0].n_value, &ptr, sizeof(ptr)) == -1)
743 		goto on_error;
744 	if (kvm_read(kd, ptr, &efiinfo, sizeof(efiinfo)) == -1)
745 		goto on_error;
746 
747 	kvm_close(kd);
748 	return (efiinfo.config_acpi);
749 
750 on_error:
751 	if (kd != NULL)
752 		kvm_close(kd);
753 	return (0);
754 }
755 
756 #endif
757