xref: /openbsd-src/usr.sbin/acpidump/acpidump.c (revision 897fc685943471cf985a0fe38ba076ea6fe74fa5)
1 /*	$OpenBSD: acpidump.c,v 1.17 2016/09/26 19:58:26 kettenis 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 int		aml_dumpdir;
171 FILE		*fhdr;
172 
173 int	acpi_checksum(void *_p, size_t _length);
174 struct acpi_user_mapping *acpi_user_find_mapping(vm_offset_t _pa, size_t _size);
175 void	*acpi_map_physical(vm_offset_t _pa, size_t _size);
176 void	acpi_user_init(void);
177 struct ACPIrsdp *acpi_find_rsd_ptr(void);
178 void	acpi_print_string(char *_s, size_t _length);
179 void	acpi_print_rsd_ptr(struct ACPIrsdp *_rp);
180 struct ACPIsdt *acpi_map_sdt(vm_offset_t _pa);
181 void	aml_dump(struct ACPIsdt *_hdr);
182 void	acpi_print_sdt(struct ACPIsdt *_sdp);
183 void	acpi_print_rsdt(struct ACPIsdt *_rsdp);
184 void	acpi_print_facp(struct FACPbody *_facp);
185 void	acpi_print_dsdt(struct ACPIsdt *_dsdp);
186 void	acpi_handle_dsdt(struct ACPIsdt *_dsdp);
187 void	acpi_handle_facp(struct FACPbody *_facp);
188 void	acpi_handle_rsdt(struct ACPIsdt *_rsdp);
189 void	asl_dump_from_devmem(void);
190 void	usage(void);
191 u_long	bios_acpi_addr(void);
192 
193 
194 struct ACPIsdt	dsdt_header = {
195 	"DSDT", 0, 1, 0, "OEMID", "OEMTBLID", 0x12345678, "CRTR", 0x12345678
196 };
197 
198 int
199 acpi_checksum(void *p, size_t length)
200 {
201 	u_int8_t	*bp;
202 	u_int8_t	sum;
203 
204 	bp = p;
205 	sum = 0;
206 	while (length--)
207 		sum += *bp++;
208 
209 	return (sum);
210 }
211 
212 struct acpi_user_mapping *
213 acpi_user_find_mapping(vm_offset_t pa, size_t size)
214 {
215 	struct acpi_user_mapping	*map;
216 	int	page_mask = getpagesize() - 1;
217 
218 	/* First search for an existing mapping */
219 	for (map = LIST_FIRST(&maplist); map; map = LIST_NEXT(map, link)) {
220 		if (map->pa <= pa && map->size >= pa + size - map->pa)
221 			return (map);
222 	}
223 
224 	/* Then create a new one */
225 #undef round_page
226 #undef trunc_page
227 #define	round_page(x)	(((x) + page_mask) & ~page_mask)
228 #define	trunc_page(x)	((x) & ~page_mask)
229 	size = round_page(pa + size) - trunc_page(pa);
230 	pa = trunc_page(pa);
231 #undef round_page
232 #undef trunc_page
233 	map = malloc(sizeof(struct acpi_user_mapping));
234 	if (!map)
235 		errx(1, "out of memory");
236 	map->pa = pa;
237 	map->va = mmap(0, size, PROT_READ, MAP_SHARED, acpi_mem_fd, pa);
238 	map->size = size;
239 	if (map->va == MAP_FAILED)
240 		err(1, "can't map address");
241 	LIST_INSERT_HEAD(&maplist, map, link);
242 
243 	return (map);
244 }
245 
246 void *
247 acpi_map_physical(vm_offset_t pa, size_t size)
248 {
249 	struct acpi_user_mapping	*map;
250 
251 	map = acpi_user_find_mapping(pa, size);
252 	return (map->va + (pa - map->pa));
253 }
254 
255 void
256 acpi_user_init(void)
257 {
258 	if (acpi_mem_fd == -1) {
259 		acpi_mem_fd = open("/dev/mem", O_RDONLY);
260 		if (acpi_mem_fd == -1)
261 			err(1, "opening /dev/mem");
262 		LIST_INIT(&maplist);
263 	}
264 }
265 
266 struct ACPIrsdp *
267 acpi_find_rsd_ptr(void)
268 {
269 	int		i;
270 	u_int8_t	buf[sizeof(struct ACPIrsdp)];
271 	u_long		addr;
272 
273 	if ((addr = bios_acpi_addr()) != 0) {
274 		lseek(acpi_mem_fd, addr, SEEK_SET);
275 		read(acpi_mem_fd, buf, 16);
276 		if (!memcmp(buf, "RSD PTR ", 8)) {
277 			read(acpi_mem_fd, buf + 16,
278 			    sizeof(struct ACPIrsdp) - 16);
279 			if (!acpi_checksum(buf, sizeof(struct ACPIrsdp)))
280 				return (acpi_map_physical(addr,
281 				    sizeof(struct ACPIrsdp)));
282 		}
283 		lseek(acpi_mem_fd, 0, SEEK_SET);
284 	}
285 	for (i = 0; i < 1024 * 1024; i += 16) {
286 		lseek(acpi_mem_fd, i, SEEK_SET);
287 		read(acpi_mem_fd, buf, 16);
288 		if (!memcmp(buf, "RSD PTR ", 8)) {
289 			/* Read the rest of the structure */
290 			read(acpi_mem_fd, buf + 16,
291 			    sizeof(struct ACPIrsdp) - 16);
292 
293 			/* Verify checksum before accepting it. */
294 			if (acpi_checksum(buf, sizeof(struct ACPIrsdp)))
295 				continue;
296 
297 			return (acpi_map_physical(i, sizeof(struct ACPIrsdp)));
298 		}
299 	}
300 
301 	return (0);
302 }
303 
304 void
305 acpi_print_string(char *s, size_t length)
306 {
307 	int		c;
308 
309 	/* Trim trailing spaces and NULLs */
310 	while (length > 0 && (s[length - 1] == ' ' || s[length - 1] == '\0'))
311 		length--;
312 
313 	while (length--) {
314 		c = *s++;
315 		fputc(c, fhdr);
316 	}
317 }
318 
319 void
320 acpi_print_rsd_ptr(struct ACPIrsdp *rp)
321 {
322 	fprintf(fhdr, "\n");
323 	fprintf(fhdr, "RSD PTR: Checksum=%d, OEMID=", rp->sum);
324 	acpi_print_string(rp->oem, 6);
325 	fprintf(fhdr, ", RsdtAddress=0x%08x\n", rp->addr);
326 	fprintf(fhdr, "\n");
327 }
328 
329 struct ACPIsdt *
330 acpi_map_sdt(vm_offset_t pa)
331 {
332 	struct ACPIsdt	*sp;
333 
334 	sp = acpi_map_physical(pa, sizeof(struct ACPIsdt));
335 	sp = acpi_map_physical(pa, sp->len);
336 	return (sp);
337 }
338 
339 void
340 aml_dump(struct ACPIsdt *hdr)
341 {
342 	static int	hdr_index;
343 	char		name[PATH_MAX];
344 	int		fd;
345 	mode_t		mode;
346 
347 	snprintf(name, sizeof(name), "%s%c%c%c%c%c.%d",
348 	    aml_dumpfile, aml_dumpdir ? '/' : '.',
349 	    hdr->signature[0], hdr->signature[1],
350 	    hdr->signature[2], hdr->signature[3],
351 	    hdr_index++);
352 
353 	mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
354 	fd = open(name, O_WRONLY | O_CREAT | O_TRUNC, mode);
355 	if (fd == -1)
356 		err(1, "aml_dump");
357 
358 	write(fd, hdr, SIZEOF_SDT_HDR);
359 	write(fd, hdr->body, hdr->len - SIZEOF_SDT_HDR);
360 	close(fd);
361 }
362 
363 void
364 acpi_print_sdt(struct ACPIsdt *sdp)
365 {
366 	fprintf(fhdr, "\n");
367 	acpi_print_string(sdp->signature, 4);
368 	fprintf(fhdr, ": Length=%d, Revision=%d, Checksum=%d,\n",
369 	       sdp->len, sdp->rev, sdp->check);
370 	fprintf(fhdr, "\tOEMID=");
371 	acpi_print_string(sdp->oemid, 6);
372 	fprintf(fhdr, ", OEM Table ID=");
373 	acpi_print_string(sdp->oemtblid, 8);
374 	fprintf(fhdr, ", OEM Revision=0x%x,\n", sdp->oemrev);
375 	fprintf(fhdr, "\tCreator ID=");
376 	acpi_print_string(sdp->creator, 4);
377 	fprintf(fhdr, ", Creator Revision=0x%x\n", sdp->crerev);
378 	fprintf(fhdr, "\n");
379 	if (!memcmp(sdp->signature, "DSDT", 4))
380 		memcpy(&dsdt_header, sdp, sizeof(dsdt_header));
381 }
382 
383 void
384 acpi_print_rsdt(struct ACPIsdt *rsdp)
385 {
386 	int		i, entries;
387 
388 	acpi_print_sdt(rsdp);
389 	entries = (rsdp->len - SIZEOF_SDT_HDR) / sizeof(u_int32_t);
390 	fprintf(fhdr, "\n");
391 	fprintf(fhdr, "\tEntries={ ");
392 	for (i = 0; i < entries; i++) {
393 		if (i > 0)
394 			fprintf(fhdr, ", ");
395 		fprintf(fhdr, "0x%08x", rsdp->body[i]);
396 	}
397 	fprintf(fhdr, " }\n");
398 	fprintf(fhdr, "\n");
399 }
400 
401 void
402 acpi_print_facp(struct FACPbody *facp)
403 {
404 	char		sep;
405 
406 	fprintf(fhdr, "\n");
407 	fprintf(fhdr, "\tDSDT=0x%x\n", facp->dsdt_ptr);
408 	fprintf(fhdr, "\tINT_MODEL=%s\n", facp->int_model ? "APIC" : "PIC");
409 	fprintf(fhdr, "\tSCI_INT=%d\n", facp->sci_int);
410 	fprintf(fhdr, "\tSMI_CMD=0x%x, ", facp->smi_cmd);
411 	fprintf(fhdr, "ACPI_ENABLE=0x%x, ", facp->acpi_enable);
412 	fprintf(fhdr, "ACPI_DISABLE=0x%x, ", facp->acpi_disable);
413 	fprintf(fhdr, "S4BIOS_REQ=0x%x\n", facp->s4biosreq);
414 	if (facp->pm1a_evt_blk)
415 		fprintf(fhdr, "\tPM1a_EVT_BLK=0x%x-0x%x\n",
416 		    facp->pm1a_evt_blk,
417 		    facp->pm1a_evt_blk + facp->pm1_evt_len - 1);
418 	if (facp->pm1b_evt_blk)
419 		fprintf(fhdr, "\tPM1b_EVT_BLK=0x%x-0x%x\n",
420 		    facp->pm1b_evt_blk,
421 		    facp->pm1b_evt_blk + facp->pm1_evt_len - 1);
422 	if (facp->pm1a_cnt_blk)
423 		fprintf(fhdr, "\tPM1a_CNT_BLK=0x%x-0x%x\n",
424 		    facp->pm1a_cnt_blk,
425 		    facp->pm1a_cnt_blk + facp->pm1_cnt_len - 1);
426 	if (facp->pm1b_cnt_blk)
427 		fprintf(fhdr, "\tPM1b_CNT_BLK=0x%x-0x%x\n",
428 		    facp->pm1b_cnt_blk,
429 		    facp->pm1b_cnt_blk + facp->pm1_cnt_len - 1);
430 	if (facp->pm2_cnt_blk)
431 		fprintf(fhdr, "\tPM2_CNT_BLK=0x%x-0x%x\n",
432 		    facp->pm2_cnt_blk,
433 		    facp->pm2_cnt_blk + facp->pm2_cnt_len - 1);
434 	if (facp->pm_tmr_blk)
435 		fprintf(fhdr, "\tPM2_TMR_BLK=0x%x-0x%x\n",
436 		    facp->pm_tmr_blk,
437 		    facp->pm_tmr_blk + facp->pm_tmr_len - 1);
438 	if (facp->gpe0_blk)
439 		fprintf(fhdr, "\tPM2_GPE0_BLK=0x%x-0x%x\n",
440 		    facp->gpe0_blk,
441 		    facp->gpe0_blk + facp->gpe0_len - 1);
442 	if (facp->gpe1_blk)
443 		fprintf(fhdr, "\tPM2_GPE1_BLK=0x%x-0x%x, GPE1_BASE=%d\n",
444 		    facp->gpe1_blk,
445 		    facp->gpe1_blk + facp->gpe1_len - 1,
446 		    facp->gpe1_base);
447 	fprintf(fhdr, "\tP_LVL2_LAT=%dms, P_LVL3_LAT=%dms\n",
448 	    facp->p_lvl2_lat, facp->p_lvl3_lat);
449 	fprintf(fhdr, "\tFLUSH_SIZE=%d, FLUSH_STRIDE=%d\n",
450 	    facp->flush_size, facp->flush_stride);
451 	fprintf(fhdr, "\tDUTY_OFFSET=%d, DUTY_WIDTH=%d\n",
452 	    facp->duty_off, facp->duty_width);
453 	fprintf(fhdr, "\tDAY_ALRM=%d, MON_ALRM=%d, CENTURY=%d\n",
454 	    facp->day_alrm, facp->mon_alrm, facp->century);
455 	fprintf(fhdr, "\tFlags=");
456 	sep = '{';
457 
458 	PRINTFLAG(WBINVD);
459 	PRINTFLAG(WBINVD_FLUSH);
460 	PRINTFLAG(PROC_C1);
461 	PRINTFLAG(P_LVL2_UP);
462 	PRINTFLAG(PWR_BUTTON);
463 	PRINTFLAG(SLP_BUTTON);
464 	PRINTFLAG(FIX_RTC);
465 	PRINTFLAG(RTC_S4);
466 	PRINTFLAG(TMR_VAL_EXT);
467 	PRINTFLAG(DCK_CAP);
468 
469 	fprintf(fhdr, "}\n");
470 	fprintf(fhdr, "\n");
471 }
472 
473 void
474 acpi_print_dsdt(struct ACPIsdt *dsdp)
475 {
476 	acpi_print_sdt(dsdp);
477 }
478 
479 void
480 acpi_handle_dsdt(struct ACPIsdt *dsdp)
481 {
482 	u_int8_t	*dp;
483 	u_int8_t	*end;
484 
485 	acpi_print_dsdt(dsdp);
486 
487 	dp = (u_int8_t *)dsdp->body;
488 	end = (u_int8_t *)dsdp + dsdp->len;
489 }
490 
491 void
492 acpi_handle_facp(struct FACPbody *facp)
493 {
494 	struct ACPIsdt	*dsdp;
495 
496 	acpi_print_facp(facp);
497 	dsdp = (struct ACPIsdt *) acpi_map_sdt(facp->dsdt_ptr);
498 	if (acpi_checksum(dsdp, dsdp->len))
499 		errx(1, "DSDT is corrupt");
500 	acpi_handle_dsdt(dsdp);
501 	aml_dump(dsdp);
502 }
503 
504 void
505 acpi_handle_rsdt(struct ACPIsdt *rsdp)
506 {
507 	int		i;
508 	int		entries;
509 	struct ACPIsdt	*sdp;
510 
511 	aml_dump(rsdp);
512 	entries = (rsdp->len - SIZEOF_SDT_HDR) / sizeof(u_int32_t);
513 	acpi_print_rsdt(rsdp);
514 	for (i = 0; i < entries; i++) {
515 		sdp = (struct ACPIsdt *) acpi_map_sdt(rsdp->body[i]);
516 		if (acpi_checksum(sdp, sdp->len))
517 			errx(1, "RSDT entry %d is corrupt", i);
518 		aml_dump(sdp);
519 		if (!memcmp(sdp->signature, "FACP", 4)) {
520 			acpi_handle_facp((struct FACPbody *) sdp->body);
521 		} else {
522 			acpi_print_sdt(sdp);
523 		}
524 	}
525 }
526 
527 void
528 asl_dump_from_devmem(void)
529 {
530 	struct ACPIrsdp	*rp;
531 	struct ACPIsdt	*rsdp;
532 	char		name[PATH_MAX];
533 
534 	snprintf(name, sizeof(name), "%s%cheaders", aml_dumpfile,
535 	    aml_dumpdir ? '/' : '.');
536 
537 	acpi_user_init();
538 
539 	if (pledge("stdio rpath wpath cpath", NULL) == -1)
540 		err(1, "pledge");
541 
542 	rp = acpi_find_rsd_ptr();
543 	if (!rp)
544 		errx(1, "Can't find ACPI information");
545 
546 	fhdr = fopen(name, "w");
547 	if (fhdr == NULL)
548 		err(1, "asl_dump_from_devmem");
549 
550 	acpi_print_rsd_ptr(rp);
551 	rsdp = (struct ACPIsdt *) acpi_map_sdt(rp->addr);
552 	if (memcmp(rsdp->signature, "RSDT", 4) ||
553 	    acpi_checksum(rsdp, rsdp->len))
554 		errx(1, "RSDT is corrupted");
555 
556 	acpi_handle_rsdt(rsdp);
557 
558 	fclose(fhdr);
559 }
560 
561 void
562 usage(void)
563 {
564 	extern char	*__progname;
565 
566 	fprintf(stderr, "usage: %s -o prefix\n", __progname);
567 	exit(1);
568 }
569 
570 int
571 main(int argc, char *argv[])
572 {
573 	struct stat	st;
574 	char		c;
575 
576 	while ((c = getopt(argc, argv, "o:")) != -1) {
577 		switch (c) {
578 		case 'o':
579 			aml_dumpfile = optarg;
580 			break;
581 		default:
582 			usage();
583 			break;
584 		}
585 	}
586 
587 	if (aml_dumpfile == NULL)
588 		usage();
589 
590 	if (stat(aml_dumpfile, &st) == 0 && S_ISDIR(st.st_mode))
591 		aml_dumpdir = 1;
592 
593 	asl_dump_from_devmem();
594 
595 	return (0);
596 }
597 
598 u_long
599 bios_acpi_addr(void)
600 {
601 	kvm_t		*kd;
602 	struct nlist	 nl[2];
603 	bios_efiinfo_t	 efiinfo;
604 	u_long	 ptr;
605 
606 	memset(&nl, 0, sizeof(nl));
607 	kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, NULL);
608 	if (kd == NULL)
609 		goto on_error;
610 	nl[0].n_name = "_bios_efiinfo";
611 	if (kvm_nlist(kd, nl) == -1)
612 		goto on_error;
613 	if (kvm_read(kd, nl[0].n_value, &ptr, sizeof(ptr)) == -1)
614 		goto on_error;
615 	if (kvm_read(kd, ptr, &efiinfo, sizeof(efiinfo)) == -1)
616 		goto on_error;
617 
618 	kvm_close(kd);
619 	return (efiinfo.config_acpi);
620 
621 on_error:
622 	if (kd != NULL)
623 		kvm_close(kd);
624 	return (0);
625 }
626