xref: /openbsd-src/usr.sbin/acpidump/acpidump.c (revision 0b7734b3d77bb9b21afec6f4621cae6c805dbd45)
1 /*	$OpenBSD: acpidump.c,v 1.16 2015/10/12 04:02:57 semarie 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 #include <machine/biosvar.h>
34 
35 #include <assert.h>
36 #include <err.h>
37 #include <fcntl.h>
38 #include <kvm.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43 #include <limits.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		res;
62 	u_int32_t	addr;
63 } __packed;
64 
65 struct ACPIsdt {
66 	u_char		signature[4];
67 	u_int32_t	len;
68 	u_char		rev;
69 	u_char		check;
70 	u_char		oemid[6];
71 	u_char		oemtblid[8];
72 	u_int32_t	oemrev;
73 	u_char		creator[4];
74 	u_int32_t	crerev;
75 #define SIZEOF_SDT_HDR	36	/* struct size except body */
76 	u_int32_t	body[1];/* This member should be casted */
77 } __packed;
78 
79 struct ACPIgas {
80 	u_int8_t	address_space_id;
81 #define ACPI_GAS_MEMORY		0
82 #define ACPI_GAS_IO		1
83 #define ACPI_GAS_PCI		2
84 #define ACPI_GAS_EMBEDDED	3
85 #define ACPI_GAS_SMBUS		4
86 #define ACPI_GAS_FIXED		0x7f
87 	u_int8_t	register_bit_width;
88 	u_int8_t	register_bit_offset;
89 	u_int8_t	res;
90 	u_int64_t	address;
91 } __packed;
92 
93 struct FACPbody {
94 	u_int32_t	facs_ptr;
95 	u_int32_t	dsdt_ptr;
96 	u_int8_t	int_model;
97 #define ACPI_FACP_INTMODEL_PIC	0	/* Standard PC-AT PIC */
98 #define ACPI_FACP_INTMODEL_APIC	1	/* Multiple APIC */
99 	u_char		reserved1;
100 	u_int16_t	sci_int;
101 	u_int32_t	smi_cmd;
102 	u_int8_t	acpi_enable;
103 	u_int8_t	acpi_disable;
104 	u_int8_t	s4biosreq;
105 	u_int8_t	reserved2;
106 	u_int32_t	pm1a_evt_blk;
107 	u_int32_t	pm1b_evt_blk;
108 	u_int32_t	pm1a_cnt_blk;
109 	u_int32_t	pm1b_cnt_blk;
110 	u_int32_t	pm2_cnt_blk;
111 	u_int32_t	pm_tmr_blk;
112 	u_int32_t	gpe0_blk;
113 	u_int32_t	gpe1_blk;
114 	u_int8_t	pm1_evt_len;
115 	u_int8_t	pm1_cnt_len;
116 	u_int8_t	pm2_cnt_len;
117 	u_int8_t	pm_tmr_len;
118 	u_int8_t	gpe0_len;
119 	u_int8_t	gpe1_len;
120 	u_int8_t	gpe1_base;
121 	u_int8_t	reserved3;
122 	u_int16_t	p_lvl2_lat;
123 	u_int16_t	p_lvl3_lat;
124 	u_int16_t	flush_size;
125 	u_int16_t	flush_stride;
126 	u_int8_t	duty_off;
127 	u_int8_t	duty_width;
128 	u_int8_t	day_alrm;
129 	u_int8_t	mon_alrm;
130 	u_int8_t	century;
131 	u_int16_t	iapc_boot_arch;
132 	u_char		reserved4[1];
133 	u_int32_t	flags;
134 #define ACPI_FACP_FLAG_WBINVD	1	/* WBINVD is correctly supported */
135 #define ACPI_FACP_FLAG_WBINVD_FLUSH 2	/* WBINVD flushes caches */
136 #define ACPI_FACP_FLAG_PROC_C1	4	/* C1 power state supported */
137 #define ACPI_FACP_FLAG_P_LVL2_UP 8	/* C2 power state works on SMP */
138 #define ACPI_FACP_FLAG_PWR_BUTTON 16	/* Power button uses control method */
139 #define ACPI_FACP_FLAG_SLP_BUTTON 32	/* Sleep button uses control method */
140 #define ACPI_FACP_FLAG_FIX_RTC	64	/* RTC wakeup not supported */
141 #define ACPI_FACP_FLAG_RTC_S4	128	/* RTC can wakeup from S4 state */
142 #define ACPI_FACP_FLAG_TMR_VAL_EXT 256	/* TMR_VAL is 32bit */
143 #define ACPI_FACP_FLAG_DCK_CAP	512	/* Can support docking */
144 	struct ACPIgas	reset_reg;
145 	u_int8_t	reset_value;
146 	u_int8_t	reserved5[3];
147 	u_int64_t	x_firmware_ctrl;
148 	u_int64_t	x_dsdt;
149 	struct ACPIgas	x_pm1a_evt_blk;
150 	struct ACPIgas	x_pm1b_evt_blk;
151 	struct ACPIgas	x_pm1a_cnt_blk;
152 	struct ACPIgas	x_pm1b_cnt_blk;
153 	struct ACPIgas	x_pm2_cnt_blk;
154 	struct ACPIgas	x_pm_tmr_blk;
155 	struct ACPIgas	x_gpe0_blk;
156 	struct ACPIgas	x_gpe1_blk;
157 } __packed;
158 
159 struct acpi_user_mapping {
160 	LIST_ENTRY(acpi_user_mapping)	link;
161 	vm_offset_t			pa;
162 	caddr_t				va;
163 	size_t				size;
164 };
165 
166 LIST_HEAD(acpi_user_mapping_list, acpi_user_mapping) maplist;
167 
168 int		acpi_mem_fd = -1;
169 char		*aml_dumpfile;
170 FILE		*fhdr;
171 
172 int	acpi_checksum(void *_p, size_t _length);
173 struct acpi_user_mapping *acpi_user_find_mapping(vm_offset_t _pa, size_t _size);
174 void	*acpi_map_physical(vm_offset_t _pa, size_t _size);
175 void	acpi_user_init(void);
176 struct ACPIrsdp *acpi_find_rsd_ptr(void);
177 void	acpi_print_string(char *_s, size_t _length);
178 void	acpi_print_rsd_ptr(struct ACPIrsdp *_rp);
179 struct ACPIsdt *acpi_map_sdt(vm_offset_t _pa);
180 void	aml_dump(struct ACPIsdt *_hdr);
181 void	acpi_print_sdt(struct ACPIsdt *_sdp);
182 void	acpi_print_rsdt(struct ACPIsdt *_rsdp);
183 void	acpi_print_facp(struct FACPbody *_facp);
184 void	acpi_print_dsdt(struct ACPIsdt *_dsdp);
185 void	acpi_handle_dsdt(struct ACPIsdt *_dsdp);
186 void	acpi_handle_facp(struct FACPbody *_facp);
187 void	acpi_handle_rsdt(struct ACPIsdt *_rsdp);
188 void	asl_dump_from_devmem(void);
189 void	usage(void);
190 u_long	bios_acpi_addr(void);
191 
192 
193 struct ACPIsdt	dsdt_header = {
194 	"DSDT", 0, 1, 0, "OEMID", "OEMTBLID", 0x12345678, "CRTR", 0x12345678
195 };
196 
197 int
198 acpi_checksum(void *p, size_t length)
199 {
200 	u_int8_t	*bp;
201 	u_int8_t	sum;
202 
203 	bp = p;
204 	sum = 0;
205 	while (length--)
206 		sum += *bp++;
207 
208 	return (sum);
209 }
210 
211 struct acpi_user_mapping *
212 acpi_user_find_mapping(vm_offset_t pa, size_t size)
213 {
214 	struct acpi_user_mapping	*map;
215 	int	page_mask = getpagesize() - 1;
216 
217 	/* First search for an existing mapping */
218 	for (map = LIST_FIRST(&maplist); map; map = LIST_NEXT(map, link)) {
219 		if (map->pa <= pa && map->size >= pa + size - map->pa)
220 			return (map);
221 	}
222 
223 	/* Then create a new one */
224 #undef round_page
225 #undef trunc_page
226 #define	round_page(x)	(((x) + page_mask) & ~page_mask)
227 #define	trunc_page(x)	((x) & ~page_mask)
228 	size = round_page(pa + size) - trunc_page(pa);
229 	pa = trunc_page(pa);
230 #undef round_page
231 #undef trunc_page
232 	map = malloc(sizeof(struct acpi_user_mapping));
233 	if (!map)
234 		errx(1, "out of memory");
235 	map->pa = pa;
236 	map->va = mmap(0, size, PROT_READ, MAP_SHARED, acpi_mem_fd, pa);
237 	map->size = size;
238 	if (map->va == MAP_FAILED)
239 		err(1, "can't map address");
240 	LIST_INSERT_HEAD(&maplist, map, link);
241 
242 	return (map);
243 }
244 
245 void *
246 acpi_map_physical(vm_offset_t pa, size_t size)
247 {
248 	struct acpi_user_mapping	*map;
249 
250 	map = acpi_user_find_mapping(pa, size);
251 	return (map->va + (pa - map->pa));
252 }
253 
254 void
255 acpi_user_init(void)
256 {
257 	if (acpi_mem_fd == -1) {
258 		acpi_mem_fd = open("/dev/mem", O_RDONLY);
259 		if (acpi_mem_fd == -1)
260 			err(1, "opening /dev/mem");
261 		LIST_INIT(&maplist);
262 	}
263 }
264 
265 struct ACPIrsdp *
266 acpi_find_rsd_ptr(void)
267 {
268 	int		i;
269 	u_int8_t	buf[sizeof(struct ACPIrsdp)];
270 	u_long		addr;
271 
272 	if ((addr = bios_acpi_addr()) != 0) {
273 		lseek(acpi_mem_fd, addr, SEEK_SET);
274 		read(acpi_mem_fd, buf, 16);
275 		if (!memcmp(buf, "RSD PTR ", 8)) {
276 			read(acpi_mem_fd, buf + 16,
277 			    sizeof(struct ACPIrsdp) - 16);
278 			if (!acpi_checksum(buf, sizeof(struct ACPIrsdp)))
279 				return (acpi_map_physical(addr,
280 				    sizeof(struct ACPIrsdp)));
281 		}
282 		lseek(acpi_mem_fd, 0, SEEK_SET);
283 	}
284 	for (i = 0; i < 1024 * 1024; i += 16) {
285 		lseek(acpi_mem_fd, i, SEEK_SET);
286 		read(acpi_mem_fd, buf, 16);
287 		if (!memcmp(buf, "RSD PTR ", 8)) {
288 			/* Read the rest of the structure */
289 			read(acpi_mem_fd, buf + 16,
290 			    sizeof(struct ACPIrsdp) - 16);
291 
292 			/* Verify checksum before accepting it. */
293 			if (acpi_checksum(buf, sizeof(struct ACPIrsdp)))
294 				continue;
295 
296 			return (acpi_map_physical(i, sizeof(struct ACPIrsdp)));
297 		}
298 	}
299 
300 	return (0);
301 }
302 
303 void
304 acpi_print_string(char *s, size_t length)
305 {
306 	int		c;
307 
308 	/* Trim trailing spaces and NULLs */
309 	while (length > 0 && (s[length - 1] == ' ' || s[length - 1] == '\0'))
310 		length--;
311 
312 	while (length--) {
313 		c = *s++;
314 		fputc(c, fhdr);
315 	}
316 }
317 
318 void
319 acpi_print_rsd_ptr(struct ACPIrsdp *rp)
320 {
321 	fprintf(fhdr, "\n");
322 	fprintf(fhdr, "RSD PTR: Checksum=%d, OEMID=", rp->sum);
323 	acpi_print_string(rp->oem, 6);
324 	fprintf(fhdr, ", RsdtAddress=0x%08x\n", rp->addr);
325 	fprintf(fhdr, "\n");
326 }
327 
328 struct ACPIsdt *
329 acpi_map_sdt(vm_offset_t pa)
330 {
331 	struct ACPIsdt	*sp;
332 
333 	sp = acpi_map_physical(pa, sizeof(struct ACPIsdt));
334 	sp = acpi_map_physical(pa, sp->len);
335 	return (sp);
336 }
337 
338 void
339 aml_dump(struct ACPIsdt *hdr)
340 {
341 	static int	hdr_index;
342 	char		name[PATH_MAX];
343 	int		fd;
344 	mode_t		mode;
345 
346 	snprintf(name, sizeof(name), "%s.%c%c%c%c.%d",
347 	    aml_dumpfile, hdr->signature[0], hdr->signature[1],
348 	    hdr->signature[2], hdr->signature[3],
349 	    hdr_index++);
350 
351 	mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
352 	fd = open(name, O_WRONLY | O_CREAT | O_TRUNC, mode);
353 	if (fd == -1)
354 		err(1, "aml_dump");
355 
356 	write(fd, hdr, SIZEOF_SDT_HDR);
357 	write(fd, hdr->body, hdr->len - SIZEOF_SDT_HDR);
358 	close(fd);
359 }
360 
361 void
362 acpi_print_sdt(struct ACPIsdt *sdp)
363 {
364 	fprintf(fhdr, "\n");
365 	acpi_print_string(sdp->signature, 4);
366 	fprintf(fhdr, ": Length=%d, Revision=%d, Checksum=%d,\n",
367 	       sdp->len, sdp->rev, sdp->check);
368 	fprintf(fhdr, "\tOEMID=");
369 	acpi_print_string(sdp->oemid, 6);
370 	fprintf(fhdr, ", OEM Table ID=");
371 	acpi_print_string(sdp->oemtblid, 8);
372 	fprintf(fhdr, ", OEM Revision=0x%x,\n", sdp->oemrev);
373 	fprintf(fhdr, "\tCreator ID=");
374 	acpi_print_string(sdp->creator, 4);
375 	fprintf(fhdr, ", Creator Revision=0x%x\n", sdp->crerev);
376 	fprintf(fhdr, "\n");
377 	if (!memcmp(sdp->signature, "DSDT", 4))
378 		memcpy(&dsdt_header, sdp, sizeof(dsdt_header));
379 }
380 
381 void
382 acpi_print_rsdt(struct ACPIsdt *rsdp)
383 {
384 	int		i, entries;
385 
386 	acpi_print_sdt(rsdp);
387 	entries = (rsdp->len - SIZEOF_SDT_HDR) / sizeof(u_int32_t);
388 	fprintf(fhdr, "\n");
389 	fprintf(fhdr, "\tEntries={ ");
390 	for (i = 0; i < entries; i++) {
391 		if (i > 0)
392 			fprintf(fhdr, ", ");
393 		fprintf(fhdr, "0x%08x", rsdp->body[i]);
394 	}
395 	fprintf(fhdr, " }\n");
396 	fprintf(fhdr, "\n");
397 }
398 
399 void
400 acpi_print_facp(struct FACPbody *facp)
401 {
402 	char		sep;
403 
404 	fprintf(fhdr, "\n");
405 	fprintf(fhdr, "\tDSDT=0x%x\n", facp->dsdt_ptr);
406 	fprintf(fhdr, "\tINT_MODEL=%s\n", facp->int_model ? "APIC" : "PIC");
407 	fprintf(fhdr, "\tSCI_INT=%d\n", facp->sci_int);
408 	fprintf(fhdr, "\tSMI_CMD=0x%x, ", facp->smi_cmd);
409 	fprintf(fhdr, "ACPI_ENABLE=0x%x, ", facp->acpi_enable);
410 	fprintf(fhdr, "ACPI_DISABLE=0x%x, ", facp->acpi_disable);
411 	fprintf(fhdr, "S4BIOS_REQ=0x%x\n", facp->s4biosreq);
412 	if (facp->pm1a_evt_blk)
413 		fprintf(fhdr, "\tPM1a_EVT_BLK=0x%x-0x%x\n",
414 		    facp->pm1a_evt_blk,
415 		    facp->pm1a_evt_blk + facp->pm1_evt_len - 1);
416 	if (facp->pm1b_evt_blk)
417 		fprintf(fhdr, "\tPM1b_EVT_BLK=0x%x-0x%x\n",
418 		    facp->pm1b_evt_blk,
419 		    facp->pm1b_evt_blk + facp->pm1_evt_len - 1);
420 	if (facp->pm1a_cnt_blk)
421 		fprintf(fhdr, "\tPM1a_CNT_BLK=0x%x-0x%x\n",
422 		    facp->pm1a_cnt_blk,
423 		    facp->pm1a_cnt_blk + facp->pm1_cnt_len - 1);
424 	if (facp->pm1b_cnt_blk)
425 		fprintf(fhdr, "\tPM1b_CNT_BLK=0x%x-0x%x\n",
426 		    facp->pm1b_cnt_blk,
427 		    facp->pm1b_cnt_blk + facp->pm1_cnt_len - 1);
428 	if (facp->pm2_cnt_blk)
429 		fprintf(fhdr, "\tPM2_CNT_BLK=0x%x-0x%x\n",
430 		    facp->pm2_cnt_blk,
431 		    facp->pm2_cnt_blk + facp->pm2_cnt_len - 1);
432 	if (facp->pm_tmr_blk)
433 		fprintf(fhdr, "\tPM2_TMR_BLK=0x%x-0x%x\n",
434 		    facp->pm_tmr_blk,
435 		    facp->pm_tmr_blk + facp->pm_tmr_len - 1);
436 	if (facp->gpe0_blk)
437 		fprintf(fhdr, "\tPM2_GPE0_BLK=0x%x-0x%x\n",
438 		    facp->gpe0_blk,
439 		    facp->gpe0_blk + facp->gpe0_len - 1);
440 	if (facp->gpe1_blk)
441 		fprintf(fhdr, "\tPM2_GPE1_BLK=0x%x-0x%x, GPE1_BASE=%d\n",
442 		    facp->gpe1_blk,
443 		    facp->gpe1_blk + facp->gpe1_len - 1,
444 		    facp->gpe1_base);
445 	fprintf(fhdr, "\tP_LVL2_LAT=%dms, P_LVL3_LAT=%dms\n",
446 	    facp->p_lvl2_lat, facp->p_lvl3_lat);
447 	fprintf(fhdr, "\tFLUSH_SIZE=%d, FLUSH_STRIDE=%d\n",
448 	    facp->flush_size, facp->flush_stride);
449 	fprintf(fhdr, "\tDUTY_OFFSET=%d, DUTY_WIDTH=%d\n",
450 	    facp->duty_off, facp->duty_width);
451 	fprintf(fhdr, "\tDAY_ALRM=%d, MON_ALRM=%d, CENTURY=%d\n",
452 	    facp->day_alrm, facp->mon_alrm, facp->century);
453 	fprintf(fhdr, "\tFlags=");
454 	sep = '{';
455 
456 	PRINTFLAG(WBINVD);
457 	PRINTFLAG(WBINVD_FLUSH);
458 	PRINTFLAG(PROC_C1);
459 	PRINTFLAG(P_LVL2_UP);
460 	PRINTFLAG(PWR_BUTTON);
461 	PRINTFLAG(SLP_BUTTON);
462 	PRINTFLAG(FIX_RTC);
463 	PRINTFLAG(RTC_S4);
464 	PRINTFLAG(TMR_VAL_EXT);
465 	PRINTFLAG(DCK_CAP);
466 
467 	fprintf(fhdr, "}\n");
468 	fprintf(fhdr, "\n");
469 }
470 
471 void
472 acpi_print_dsdt(struct ACPIsdt *dsdp)
473 {
474 	acpi_print_sdt(dsdp);
475 }
476 
477 void
478 acpi_handle_dsdt(struct ACPIsdt *dsdp)
479 {
480 	u_int8_t	*dp;
481 	u_int8_t	*end;
482 
483 	acpi_print_dsdt(dsdp);
484 
485 	dp = (u_int8_t *)dsdp->body;
486 	end = (u_int8_t *)dsdp + dsdp->len;
487 }
488 
489 void
490 acpi_handle_facp(struct FACPbody *facp)
491 {
492 	struct ACPIsdt	*dsdp;
493 
494 	acpi_print_facp(facp);
495 	dsdp = (struct ACPIsdt *) acpi_map_sdt(facp->dsdt_ptr);
496 	if (acpi_checksum(dsdp, dsdp->len))
497 		errx(1, "DSDT is corrupt");
498 	acpi_handle_dsdt(dsdp);
499 	aml_dump(dsdp);
500 }
501 
502 void
503 acpi_handle_rsdt(struct ACPIsdt *rsdp)
504 {
505 	int		i;
506 	int		entries;
507 	struct ACPIsdt	*sdp;
508 
509 	aml_dump(rsdp);
510 	entries = (rsdp->len - SIZEOF_SDT_HDR) / sizeof(u_int32_t);
511 	acpi_print_rsdt(rsdp);
512 	for (i = 0; i < entries; i++) {
513 		sdp = (struct ACPIsdt *) acpi_map_sdt(rsdp->body[i]);
514 		if (acpi_checksum(sdp, sdp->len))
515 			errx(1, "RSDT entry %d is corrupt", i);
516 		aml_dump(sdp);
517 		if (!memcmp(sdp->signature, "FACP", 4)) {
518 			acpi_handle_facp((struct FACPbody *) sdp->body);
519 		} else {
520 			acpi_print_sdt(sdp);
521 		}
522 	}
523 }
524 
525 void
526 asl_dump_from_devmem(void)
527 {
528 	struct ACPIrsdp	*rp;
529 	struct ACPIsdt	*rsdp;
530 	char		name[PATH_MAX];
531 
532 	snprintf(name, sizeof(name), "%s.headers", aml_dumpfile);
533 
534 	acpi_user_init();
535 
536 	if (pledge("stdio rpath wpath cpath", NULL) == -1)
537 		err(1, "pledge");
538 
539 	rp = acpi_find_rsd_ptr();
540 	if (!rp)
541 		errx(1, "Can't find ACPI information");
542 
543 	fhdr = fopen(name, "w");
544 	if (fhdr == NULL)
545 		err(1, "asl_dump_from_devmem");
546 
547 	acpi_print_rsd_ptr(rp);
548 	rsdp = (struct ACPIsdt *) acpi_map_sdt(rp->addr);
549 	if (memcmp(rsdp->signature, "RSDT", 4) ||
550 	    acpi_checksum(rsdp, rsdp->len))
551 		errx(1, "RSDT is corrupted");
552 
553 	acpi_handle_rsdt(rsdp);
554 
555 	fclose(fhdr);
556 }
557 
558 void
559 usage(void)
560 {
561 	extern char	*__progname;
562 
563 	fprintf(stderr, "usage: %s -o prefix_for_output\n", __progname);
564 	exit(1);
565 }
566 
567 int
568 main(int argc, char *argv[])
569 {
570 	char		c;
571 
572 	while ((c = getopt(argc, argv, "o:")) != -1) {
573 		switch (c) {
574 		case 'o':
575 			aml_dumpfile = optarg;
576 			break;
577 		default:
578 			usage();
579 			break;
580 		}
581 	}
582 
583 	if (aml_dumpfile == NULL)
584 		usage();
585 
586 	asl_dump_from_devmem();
587 
588 	return (0);
589 }
590 
591 u_long
592 bios_acpi_addr(void)
593 {
594 	kvm_t		*kd;
595 	struct nlist	 nl[2];
596 	bios_efiinfo_t	 efiinfo;
597 	u_long	 ptr;
598 
599 	memset(&nl, 0, sizeof(nl));
600 	kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, NULL);
601 	if (kd == NULL)
602 		goto on_error;
603 	nl[0].n_name = "_bios_efiinfo";
604 	if (kvm_nlist(kd, nl) == -1)
605 		goto on_error;
606 	if (kvm_read(kd, nl[0].n_value, &ptr, sizeof(ptr)) == -1)
607 		goto on_error;
608 	if (kvm_read(kd, ptr, &efiinfo, sizeof(efiinfo)) == -1)
609 		goto on_error;
610 
611 	kvm_close(kd);
612 	return (efiinfo.config_acpi);
613 
614 on_error:
615 	if (kd != NULL)
616 		kvm_close(kd);
617 	return (0);
618 }
619