xref: /openbsd-src/usr.sbin/acpidump/acpidump.c (revision c3c82401f1ca742355f6d614ac731ead72a80852)
1*c3c82401Skettenis /*	$OpenBSD: acpidump.c,v 1.25 2022/09/11 10:40:35 kettenis Exp $	*/
212793204Smarco /*
37934d707Stholo  * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org>
47934d707Stholo  * All rights reserved.
57934d707Stholo  *
67934d707Stholo  * Redistribution and use in source and binary forms, with or without
77934d707Stholo  * modification, are permitted provided that the following conditions
87934d707Stholo  * are met:
97934d707Stholo  * 1. Redistributions of source code must retain the above copyright
107934d707Stholo  *    notice, this list of conditions and the following disclaimer.
117934d707Stholo  * 2. Redistributions in binary form must reproduce the above copyright
127934d707Stholo  *    notice, this list of conditions and the following disclaimer in the
137934d707Stholo  *    documentation and/or other materials provided with the distribution.
147934d707Stholo  *
157934d707Stholo  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
167934d707Stholo  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
177934d707Stholo  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
187934d707Stholo  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
197934d707Stholo  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
207934d707Stholo  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
217934d707Stholo  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
227934d707Stholo  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
237934d707Stholo  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
247934d707Stholo  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
257934d707Stholo  * SUCH DAMAGE.
267934d707Stholo  *
277934d707Stholo  */
287934d707Stholo 
297934d707Stholo #include <sys/types.h>
30d0c9fa7cSderaadt #include <sys/mman.h>
31d0c9fa7cSderaadt #include <sys/queue.h>
32d0c9fa7cSderaadt #include <sys/stat.h>
33d0c9fa7cSderaadt 
347934d707Stholo #include <assert.h>
357934d707Stholo #include <err.h>
3612793204Smarco #include <fcntl.h>
3788448ec7Syasuoka #include <kvm.h>
387934d707Stholo #include <stdio.h>
3912793204Smarco #include <stdlib.h>
4087e993edSmiod #include <string.h>
417934d707Stholo #include <unistd.h>
42d0c9fa7cSderaadt #include <limits.h>
43bc30430aSderaadt #include <paths.h>
447934d707Stholo 
4512793204Smarco 
4612793204Smarco #define vm_page_size sysconf(_SC_PAGESIZE)
4712793204Smarco #define PRINTFLAG(xx)							\
4812793204Smarco 	do {								\
4912793204Smarco 		if (facp->flags & ACPI_FACP_FLAG_## xx) {		\
5012793204Smarco 			fprintf(fhdr, "%c%s", sep, #xx); sep = ',';	\
5112793204Smarco 		}							\
5212793204Smarco 	} while (0)
5312793204Smarco 
5412793204Smarco 
5512793204Smarco typedef unsigned long	vm_offset_t;
5612793204Smarco 
5712793204Smarco struct ACPIrsdp {
5812793204Smarco 	u_char		signature[8];
5912793204Smarco 	u_char		sum;
6012793204Smarco 	u_char		oem[6];
616988a5d7Skettenis 	u_char		rev;
6212793204Smarco 	u_int32_t	addr;
636988a5d7Skettenis #define SIZEOF_RSDP_REV_0	20
646988a5d7Skettenis 	u_int32_t	len;
656988a5d7Skettenis 	u_int64_t	xaddr;
666988a5d7Skettenis 	u_char		xsum;
676988a5d7Skettenis 	u_char		xres[3];
6812793204Smarco } __packed;
6912793204Smarco 
7012793204Smarco struct ACPIsdt {
7112793204Smarco 	u_char		signature[4];
7212793204Smarco 	u_int32_t	len;
7312793204Smarco 	u_char		rev;
7412793204Smarco 	u_char		check;
7512793204Smarco 	u_char		oemid[6];
7612793204Smarco 	u_char		oemtblid[8];
7712793204Smarco 	u_int32_t	oemrev;
7812793204Smarco 	u_char		creator[4];
7912793204Smarco 	u_int32_t	crerev;
8012793204Smarco #define SIZEOF_SDT_HDR	36	/* struct size except body */
8112793204Smarco 	u_int32_t	body[1];/* This member should be casted */
8212793204Smarco } __packed;
8312793204Smarco 
8412793204Smarco struct ACPIgas {
8512793204Smarco 	u_int8_t	address_space_id;
8612793204Smarco #define ACPI_GAS_MEMORY		0
8712793204Smarco #define ACPI_GAS_IO		1
8812793204Smarco #define ACPI_GAS_PCI		2
8912793204Smarco #define ACPI_GAS_EMBEDDED	3
9012793204Smarco #define ACPI_GAS_SMBUS		4
9112793204Smarco #define ACPI_GAS_FIXED		0x7f
9212793204Smarco 	u_int8_t	register_bit_width;
9312793204Smarco 	u_int8_t	register_bit_offset;
9412793204Smarco 	u_int8_t	res;
9512793204Smarco 	u_int64_t	address;
9612793204Smarco } __packed;
9712793204Smarco 
9812793204Smarco struct FACPbody {
9912793204Smarco 	u_int32_t	facs_ptr;
10012793204Smarco 	u_int32_t	dsdt_ptr;
10112793204Smarco 	u_int8_t	int_model;
10212793204Smarco #define ACPI_FACP_INTMODEL_PIC	0	/* Standard PC-AT PIC */
10312793204Smarco #define ACPI_FACP_INTMODEL_APIC	1	/* Multiple APIC */
10412793204Smarco 	u_char		reserved1;
10512793204Smarco 	u_int16_t	sci_int;
10612793204Smarco 	u_int32_t	smi_cmd;
10712793204Smarco 	u_int8_t	acpi_enable;
10812793204Smarco 	u_int8_t	acpi_disable;
10912793204Smarco 	u_int8_t	s4biosreq;
11012793204Smarco 	u_int8_t	reserved2;
11112793204Smarco 	u_int32_t	pm1a_evt_blk;
11212793204Smarco 	u_int32_t	pm1b_evt_blk;
11312793204Smarco 	u_int32_t	pm1a_cnt_blk;
11412793204Smarco 	u_int32_t	pm1b_cnt_blk;
11512793204Smarco 	u_int32_t	pm2_cnt_blk;
11612793204Smarco 	u_int32_t	pm_tmr_blk;
11712793204Smarco 	u_int32_t	gpe0_blk;
11812793204Smarco 	u_int32_t	gpe1_blk;
11912793204Smarco 	u_int8_t	pm1_evt_len;
12012793204Smarco 	u_int8_t	pm1_cnt_len;
12112793204Smarco 	u_int8_t	pm2_cnt_len;
12212793204Smarco 	u_int8_t	pm_tmr_len;
12312793204Smarco 	u_int8_t	gpe0_len;
12412793204Smarco 	u_int8_t	gpe1_len;
12512793204Smarco 	u_int8_t	gpe1_base;
12612793204Smarco 	u_int8_t	reserved3;
12712793204Smarco 	u_int16_t	p_lvl2_lat;
12812793204Smarco 	u_int16_t	p_lvl3_lat;
12912793204Smarco 	u_int16_t	flush_size;
13012793204Smarco 	u_int16_t	flush_stride;
13112793204Smarco 	u_int8_t	duty_off;
13212793204Smarco 	u_int8_t	duty_width;
13312793204Smarco 	u_int8_t	day_alrm;
13412793204Smarco 	u_int8_t	mon_alrm;
13512793204Smarco 	u_int8_t	century;
13612793204Smarco 	u_int16_t	iapc_boot_arch;
13712793204Smarco 	u_char		reserved4[1];
13812793204Smarco 	u_int32_t	flags;
13912793204Smarco #define ACPI_FACP_FLAG_WBINVD	1	/* WBINVD is correctly supported */
14012793204Smarco #define ACPI_FACP_FLAG_WBINVD_FLUSH 2	/* WBINVD flushes caches */
14112793204Smarco #define ACPI_FACP_FLAG_PROC_C1	4	/* C1 power state supported */
14212793204Smarco #define ACPI_FACP_FLAG_P_LVL2_UP 8	/* C2 power state works on SMP */
14312793204Smarco #define ACPI_FACP_FLAG_PWR_BUTTON 16	/* Power button uses control method */
14412793204Smarco #define ACPI_FACP_FLAG_SLP_BUTTON 32	/* Sleep button uses control method */
14512793204Smarco #define ACPI_FACP_FLAG_FIX_RTC	64	/* RTC wakeup not supported */
14612793204Smarco #define ACPI_FACP_FLAG_RTC_S4	128	/* RTC can wakeup from S4 state */
14712793204Smarco #define ACPI_FACP_FLAG_TMR_VAL_EXT 256	/* TMR_VAL is 32bit */
14812793204Smarco #define ACPI_FACP_FLAG_DCK_CAP	512	/* Can support docking */
14912793204Smarco 	struct ACPIgas	reset_reg;
15012793204Smarco 	u_int8_t	reset_value;
15112793204Smarco 	u_int8_t	reserved5[3];
15212793204Smarco 	u_int64_t	x_firmware_ctrl;
15312793204Smarco 	u_int64_t	x_dsdt;
15412793204Smarco 	struct ACPIgas	x_pm1a_evt_blk;
15512793204Smarco 	struct ACPIgas	x_pm1b_evt_blk;
15612793204Smarco 	struct ACPIgas	x_pm1a_cnt_blk;
15712793204Smarco 	struct ACPIgas	x_pm1b_cnt_blk;
15812793204Smarco 	struct ACPIgas	x_pm2_cnt_blk;
15912793204Smarco 	struct ACPIgas	x_pm_tmr_blk;
16012793204Smarco 	struct ACPIgas	x_gpe0_blk;
16112793204Smarco 	struct ACPIgas	x_gpe1_blk;
16212793204Smarco } __packed;
16312793204Smarco 
16412793204Smarco struct acpi_user_mapping {
16512793204Smarco 	LIST_ENTRY(acpi_user_mapping)	link;
16612793204Smarco 	vm_offset_t			pa;
16712793204Smarco 	caddr_t				va;
16812793204Smarco 	size_t				size;
16912793204Smarco };
17012793204Smarco 
17112793204Smarco LIST_HEAD(acpi_user_mapping_list, acpi_user_mapping) maplist;
17212793204Smarco 
17312793204Smarco int		acpi_mem_fd = -1;
17412793204Smarco char		*aml_dumpfile;
175c8dab64cSkettenis int		aml_dumpdir;
17612793204Smarco FILE		*fhdr;
17717033bfcSkettenis int		quiet;
17812793204Smarco 
1790a667195Sderaadt int	acpi_checksum(void *_p, size_t _length);
1800a667195Sderaadt struct acpi_user_mapping *acpi_user_find_mapping(vm_offset_t _pa, size_t _size);
1810a667195Sderaadt void	*acpi_map_physical(vm_offset_t _pa, size_t _size);
1820a667195Sderaadt void	acpi_user_init(void);
1836988a5d7Skettenis struct ACPIrsdp *acpi_check_rsd_ptr(vm_offset_t _pa);
1840a667195Sderaadt struct ACPIrsdp *acpi_find_rsd_ptr(void);
1850a667195Sderaadt void	acpi_print_string(char *_s, size_t _length);
1860a667195Sderaadt void	acpi_print_rsd_ptr(struct ACPIrsdp *_rp);
1870a667195Sderaadt struct ACPIsdt *acpi_map_sdt(vm_offset_t _pa);
1880a667195Sderaadt void	aml_dump(struct ACPIsdt *_hdr);
1890a667195Sderaadt void	acpi_print_sdt(struct ACPIsdt *_sdp);
1900a667195Sderaadt void	acpi_print_rsdt(struct ACPIsdt *_rsdp);
1916988a5d7Skettenis void	acpi_print_xsdt(struct ACPIsdt *_rsdp);
1920a667195Sderaadt void	acpi_print_facp(struct FACPbody *_facp);
1930a667195Sderaadt void	acpi_print_dsdt(struct ACPIsdt *_dsdp);
1940a667195Sderaadt void	acpi_handle_dsdt(struct ACPIsdt *_dsdp);
1950a667195Sderaadt void	acpi_handle_facp(struct FACPbody *_facp);
1960a667195Sderaadt void	acpi_handle_rsdt(struct ACPIsdt *_rsdp);
1976988a5d7Skettenis void	acpi_handle_xsdt(struct ACPIsdt *_rsdp);
1980a667195Sderaadt void	asl_dump_from_devmem(void);
1990a667195Sderaadt void	usage(void);
2006988a5d7Skettenis u_long	efi_acpi_addr(void);
2010a667195Sderaadt 
2020a667195Sderaadt 
20312793204Smarco struct ACPIsdt	dsdt_header = {
20412793204Smarco 	"DSDT", 0, 1, 0, "OEMID", "OEMTBLID", 0x12345678, "CRTR", 0x12345678
20512793204Smarco };
20612793204Smarco 
20712793204Smarco int
acpi_checksum(void * p,size_t length)20812793204Smarco acpi_checksum(void *p, size_t length)
20912793204Smarco {
21012793204Smarco 	u_int8_t	*bp;
21112793204Smarco 	u_int8_t	sum;
21212793204Smarco 
21312793204Smarco 	bp = p;
21412793204Smarco 	sum = 0;
21512793204Smarco 	while (length--)
21612793204Smarco 		sum += *bp++;
21712793204Smarco 
21812793204Smarco 	return (sum);
21912793204Smarco }
22012793204Smarco 
22112793204Smarco struct acpi_user_mapping *
acpi_user_find_mapping(vm_offset_t pa,size_t size)22212793204Smarco acpi_user_find_mapping(vm_offset_t pa, size_t size)
22312793204Smarco {
22412793204Smarco 	struct acpi_user_mapping	*map;
225fadb1e41Sderaadt 	int	page_mask = getpagesize() - 1;
22612793204Smarco 
22712793204Smarco 	/* First search for an existing mapping */
22812793204Smarco 	for (map = LIST_FIRST(&maplist); map; map = LIST_NEXT(map, link)) {
22912793204Smarco 		if (map->pa <= pa && map->size >= pa + size - map->pa)
23012793204Smarco 			return (map);
23112793204Smarco 	}
23212793204Smarco 
23312793204Smarco 	/* Then create a new one */
234fadb1e41Sderaadt #undef round_page
235fadb1e41Sderaadt #undef trunc_page
236fadb1e41Sderaadt #define	round_page(x)	(((x) + page_mask) & ~page_mask)
237fadb1e41Sderaadt #define	trunc_page(x)	((x) & ~page_mask)
23812793204Smarco 	size = round_page(pa + size) - trunc_page(pa);
23912793204Smarco 	pa = trunc_page(pa);
240fadb1e41Sderaadt #undef round_page
241fadb1e41Sderaadt #undef trunc_page
24212793204Smarco 	map = malloc(sizeof(struct acpi_user_mapping));
24312793204Smarco 	if (!map)
24412793204Smarco 		errx(1, "out of memory");
24512793204Smarco 	map->pa = pa;
24612793204Smarco 	map->va = mmap(0, size, PROT_READ, MAP_SHARED, acpi_mem_fd, pa);
24712793204Smarco 	map->size = size;
24812793204Smarco 	if (map->va == MAP_FAILED)
24912793204Smarco 		err(1, "can't map address");
25012793204Smarco 	LIST_INSERT_HEAD(&maplist, map, link);
25112793204Smarco 
25212793204Smarco 	return (map);
25312793204Smarco }
25412793204Smarco 
25512793204Smarco void *
acpi_map_physical(vm_offset_t pa,size_t size)25612793204Smarco acpi_map_physical(vm_offset_t pa, size_t size)
25712793204Smarco {
25812793204Smarco 	struct acpi_user_mapping	*map;
25912793204Smarco 
26012793204Smarco 	map = acpi_user_find_mapping(pa, size);
26112793204Smarco 	return (map->va + (pa - map->pa));
26212793204Smarco }
26312793204Smarco 
26412793204Smarco void
acpi_user_init(void)26512793204Smarco acpi_user_init(void)
26612793204Smarco {
26712793204Smarco 	if (acpi_mem_fd == -1) {
26812793204Smarco 		acpi_mem_fd = open("/dev/mem", O_RDONLY);
26912793204Smarco 		if (acpi_mem_fd == -1)
27012793204Smarco 			err(1, "opening /dev/mem");
27112793204Smarco 		LIST_INIT(&maplist);
27212793204Smarco 	}
27312793204Smarco }
27412793204Smarco 
27512793204Smarco struct ACPIrsdp *
acpi_check_rsd_ptr(vm_offset_t pa)2766988a5d7Skettenis acpi_check_rsd_ptr(vm_offset_t pa)
2776988a5d7Skettenis {
2786988a5d7Skettenis 	struct ACPIrsdp rp;
2796988a5d7Skettenis 
2806988a5d7Skettenis 	lseek(acpi_mem_fd, pa, SEEK_SET);
2816988a5d7Skettenis 	read(acpi_mem_fd, &rp, SIZEOF_RSDP_REV_0);
2826988a5d7Skettenis 	if (memcmp(rp.signature, "RSD PTR ", 8) != 0)
2836988a5d7Skettenis 		return NULL;
2846988a5d7Skettenis 
2856988a5d7Skettenis 	if (rp.rev >= 2) {
2866988a5d7Skettenis 		read(acpi_mem_fd, &(rp.len),
2876988a5d7Skettenis 		    sizeof(struct ACPIrsdp) - SIZEOF_RSDP_REV_0);
2886988a5d7Skettenis 		if (acpi_checksum(&rp, sizeof(struct ACPIrsdp)) == 0)
2896988a5d7Skettenis 			return acpi_map_physical(pa, sizeof(struct ACPIrsdp));
2906988a5d7Skettenis 	}
2916988a5d7Skettenis 
2926988a5d7Skettenis 	if (acpi_checksum(&rp, SIZEOF_RSDP_REV_0) == 0)
2936988a5d7Skettenis 		return (acpi_map_physical(pa, SIZEOF_RSDP_REV_0));
2946988a5d7Skettenis 
2956988a5d7Skettenis 	return NULL;
2966988a5d7Skettenis }
2976988a5d7Skettenis 
2986988a5d7Skettenis struct ACPIrsdp *
acpi_find_rsd_ptr(void)2990a667195Sderaadt acpi_find_rsd_ptr(void)
30012793204Smarco {
3016988a5d7Skettenis 	struct ACPIrsdp *rp;
30288448ec7Syasuoka 	u_long		addr;
30312793204Smarco 
3046988a5d7Skettenis 	if ((addr = efi_acpi_addr()) != 0) {
3056988a5d7Skettenis 		if ((rp = acpi_check_rsd_ptr(addr)))
3066988a5d7Skettenis 			return rp;
30712793204Smarco 	}
30812793204Smarco 
3096988a5d7Skettenis #if defined(__amd64__) || defined (__i386__)
3106988a5d7Skettenis 	for (addr = 0; addr < 1024 * 1024; addr += 16) {
3116988a5d7Skettenis 		if ((rp = acpi_check_rsd_ptr(addr)))
3126988a5d7Skettenis 			return rp;
3136988a5d7Skettenis 	}
3146988a5d7Skettenis #endif
3156988a5d7Skettenis 
3166988a5d7Skettenis 	return NULL;
31712793204Smarco }
31812793204Smarco 
31912793204Smarco void
acpi_print_string(char * s,size_t length)32012793204Smarco acpi_print_string(char *s, size_t length)
32112793204Smarco {
32212793204Smarco 	int		c;
32312793204Smarco 
32412793204Smarco 	/* Trim trailing spaces and NULLs */
32512793204Smarco 	while (length > 0 && (s[length - 1] == ' ' || s[length - 1] == '\0'))
32612793204Smarco 		length--;
32712793204Smarco 
32812793204Smarco 	while (length--) {
32912793204Smarco 		c = *s++;
33012793204Smarco 		fputc(c, fhdr);
33112793204Smarco 	}
33212793204Smarco }
33312793204Smarco 
33412793204Smarco void
acpi_print_rsd_ptr(struct ACPIrsdp * rp)33512793204Smarco acpi_print_rsd_ptr(struct ACPIrsdp *rp)
33612793204Smarco {
33712793204Smarco 	fprintf(fhdr, "\n");
33812793204Smarco 	fprintf(fhdr, "RSD PTR: Checksum=%d, OEMID=", rp->sum);
33912793204Smarco 	acpi_print_string(rp->oem, 6);
3406988a5d7Skettenis 	fprintf(fhdr, ", Revision=%d", rp->rev);
34112793204Smarco 	fprintf(fhdr, ", RsdtAddress=0x%08x\n", rp->addr);
3426988a5d7Skettenis 	if (rp->rev >= 2) {
3436988a5d7Skettenis 		fprintf(fhdr, "\tLength=%d", rp->len);
3446988a5d7Skettenis 		fprintf(fhdr, ", XsdtAddress=0x%016llx", rp->xaddr);
3456988a5d7Skettenis 		fprintf(fhdr, ", Extended Checksum=%d\n", rp->xsum);
3466988a5d7Skettenis 	}
34712793204Smarco 	fprintf(fhdr, "\n");
34812793204Smarco }
34912793204Smarco 
35012793204Smarco struct ACPIsdt *
acpi_map_sdt(vm_offset_t pa)35112793204Smarco acpi_map_sdt(vm_offset_t pa)
35212793204Smarco {
35312793204Smarco 	struct ACPIsdt	*sp;
35412793204Smarco 
35512793204Smarco 	sp = acpi_map_physical(pa, sizeof(struct ACPIsdt));
35612793204Smarco 	sp = acpi_map_physical(pa, sp->len);
35712793204Smarco 	return (sp);
35812793204Smarco }
35912793204Smarco 
36012793204Smarco void
aml_dump(struct ACPIsdt * hdr)36112793204Smarco aml_dump(struct ACPIsdt *hdr)
36212793204Smarco {
36312793204Smarco 	static int	hdr_index;
36412793204Smarco 	char		name[PATH_MAX];
36512793204Smarco 	int		fd;
36612793204Smarco 	mode_t		mode;
36712793204Smarco 
368c8dab64cSkettenis 	snprintf(name, sizeof(name), "%s%c%c%c%c%c.%d",
369c8dab64cSkettenis 	    aml_dumpfile, aml_dumpdir ? '/' : '.',
370c8dab64cSkettenis 	    hdr->signature[0], hdr->signature[1],
37112793204Smarco 	    hdr->signature[2], hdr->signature[3],
37212793204Smarco 	    hdr_index++);
37312793204Smarco 
37412793204Smarco 	mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
37512793204Smarco 	fd = open(name, O_WRONLY | O_CREAT | O_TRUNC, mode);
37612793204Smarco 	if (fd == -1)
37712793204Smarco 		err(1, "aml_dump");
37812793204Smarco 
37912793204Smarco 	write(fd, hdr, SIZEOF_SDT_HDR);
38012793204Smarco 	write(fd, hdr->body, hdr->len - SIZEOF_SDT_HDR);
38112793204Smarco 	close(fd);
38212793204Smarco }
38312793204Smarco 
38412793204Smarco void
acpi_print_sdt(struct ACPIsdt * sdp)38512793204Smarco acpi_print_sdt(struct ACPIsdt *sdp)
38612793204Smarco {
38712793204Smarco 	fprintf(fhdr, "\n");
38812793204Smarco 	acpi_print_string(sdp->signature, 4);
38912793204Smarco 	fprintf(fhdr, ": Length=%d, Revision=%d, Checksum=%d,\n",
39012793204Smarco 	       sdp->len, sdp->rev, sdp->check);
39112793204Smarco 	fprintf(fhdr, "\tOEMID=");
39212793204Smarco 	acpi_print_string(sdp->oemid, 6);
39312793204Smarco 	fprintf(fhdr, ", OEM Table ID=");
39412793204Smarco 	acpi_print_string(sdp->oemtblid, 8);
39512793204Smarco 	fprintf(fhdr, ", OEM Revision=0x%x,\n", sdp->oemrev);
39612793204Smarco 	fprintf(fhdr, "\tCreator ID=");
39712793204Smarco 	acpi_print_string(sdp->creator, 4);
39812793204Smarco 	fprintf(fhdr, ", Creator Revision=0x%x\n", sdp->crerev);
39912793204Smarco 	fprintf(fhdr, "\n");
40012793204Smarco 	if (!memcmp(sdp->signature, "DSDT", 4))
40112793204Smarco 		memcpy(&dsdt_header, sdp, sizeof(dsdt_header));
40212793204Smarco }
40312793204Smarco 
40412793204Smarco void
acpi_print_rsdt(struct ACPIsdt * rsdp)40512793204Smarco acpi_print_rsdt(struct ACPIsdt *rsdp)
40612793204Smarco {
40712793204Smarco 	int		i, entries;
40812793204Smarco 
40912793204Smarco 	acpi_print_sdt(rsdp);
41012793204Smarco 	entries = (rsdp->len - SIZEOF_SDT_HDR) / sizeof(u_int32_t);
41112793204Smarco 	fprintf(fhdr, "\n");
41212793204Smarco 	fprintf(fhdr, "\tEntries={ ");
41312793204Smarco 	for (i = 0; i < entries; i++) {
41412793204Smarco 		if (i > 0)
41512793204Smarco 			fprintf(fhdr, ", ");
41612793204Smarco 		fprintf(fhdr, "0x%08x", rsdp->body[i]);
41712793204Smarco 	}
41812793204Smarco 	fprintf(fhdr, " }\n");
41912793204Smarco 	fprintf(fhdr, "\n");
42012793204Smarco }
42112793204Smarco 
42212793204Smarco void
acpi_print_xsdt(struct ACPIsdt * rsdp)4236988a5d7Skettenis acpi_print_xsdt(struct ACPIsdt *rsdp)
4246988a5d7Skettenis {
4256988a5d7Skettenis 	int		i, entries;
4266988a5d7Skettenis 	u_int64_t	*body = (u_int64_t *) rsdp->body;
4276988a5d7Skettenis 
4286988a5d7Skettenis 	acpi_print_sdt(rsdp);
4296988a5d7Skettenis 	entries = (rsdp->len - SIZEOF_SDT_HDR) / sizeof(u_int64_t);
4306988a5d7Skettenis 	fprintf(fhdr, "\n");
4316988a5d7Skettenis 	fprintf(fhdr, "\tEntries={ ");
4326988a5d7Skettenis 	for (i = 0; i < entries; i++) {
4336988a5d7Skettenis 		if (i > 0)
4346988a5d7Skettenis 			fprintf(fhdr, ", ");
4356988a5d7Skettenis 		fprintf(fhdr, "0x%016llx", body[i]);
4366988a5d7Skettenis 	}
4376988a5d7Skettenis 	fprintf(fhdr, " }\n");
4386988a5d7Skettenis 	fprintf(fhdr, "\n");
4396988a5d7Skettenis }
4406988a5d7Skettenis 
4416988a5d7Skettenis void
acpi_print_facp(struct FACPbody * facp)44212793204Smarco acpi_print_facp(struct FACPbody *facp)
44312793204Smarco {
44412793204Smarco 	char		sep;
44512793204Smarco 
44612793204Smarco 	fprintf(fhdr, "\n");
44712793204Smarco 	fprintf(fhdr, "\tDSDT=0x%x\n", facp->dsdt_ptr);
44812793204Smarco 	fprintf(fhdr, "\tINT_MODEL=%s\n", facp->int_model ? "APIC" : "PIC");
44912793204Smarco 	fprintf(fhdr, "\tSCI_INT=%d\n", facp->sci_int);
45012793204Smarco 	fprintf(fhdr, "\tSMI_CMD=0x%x, ", facp->smi_cmd);
45112793204Smarco 	fprintf(fhdr, "ACPI_ENABLE=0x%x, ", facp->acpi_enable);
45212793204Smarco 	fprintf(fhdr, "ACPI_DISABLE=0x%x, ", facp->acpi_disable);
45312793204Smarco 	fprintf(fhdr, "S4BIOS_REQ=0x%x\n", facp->s4biosreq);
45412793204Smarco 	if (facp->pm1a_evt_blk)
45512793204Smarco 		fprintf(fhdr, "\tPM1a_EVT_BLK=0x%x-0x%x\n",
45612793204Smarco 		    facp->pm1a_evt_blk,
45712793204Smarco 		    facp->pm1a_evt_blk + facp->pm1_evt_len - 1);
45812793204Smarco 	if (facp->pm1b_evt_blk)
45912793204Smarco 		fprintf(fhdr, "\tPM1b_EVT_BLK=0x%x-0x%x\n",
46012793204Smarco 		    facp->pm1b_evt_blk,
46112793204Smarco 		    facp->pm1b_evt_blk + facp->pm1_evt_len - 1);
46212793204Smarco 	if (facp->pm1a_cnt_blk)
46312793204Smarco 		fprintf(fhdr, "\tPM1a_CNT_BLK=0x%x-0x%x\n",
46412793204Smarco 		    facp->pm1a_cnt_blk,
46512793204Smarco 		    facp->pm1a_cnt_blk + facp->pm1_cnt_len - 1);
46612793204Smarco 	if (facp->pm1b_cnt_blk)
46712793204Smarco 		fprintf(fhdr, "\tPM1b_CNT_BLK=0x%x-0x%x\n",
46812793204Smarco 		    facp->pm1b_cnt_blk,
46912793204Smarco 		    facp->pm1b_cnt_blk + facp->pm1_cnt_len - 1);
47012793204Smarco 	if (facp->pm2_cnt_blk)
47112793204Smarco 		fprintf(fhdr, "\tPM2_CNT_BLK=0x%x-0x%x\n",
47212793204Smarco 		    facp->pm2_cnt_blk,
47312793204Smarco 		    facp->pm2_cnt_blk + facp->pm2_cnt_len - 1);
47412793204Smarco 	if (facp->pm_tmr_blk)
47512793204Smarco 		fprintf(fhdr, "\tPM2_TMR_BLK=0x%x-0x%x\n",
47612793204Smarco 		    facp->pm_tmr_blk,
47712793204Smarco 		    facp->pm_tmr_blk + facp->pm_tmr_len - 1);
47812793204Smarco 	if (facp->gpe0_blk)
47912793204Smarco 		fprintf(fhdr, "\tPM2_GPE0_BLK=0x%x-0x%x\n",
48012793204Smarco 		    facp->gpe0_blk,
48112793204Smarco 		    facp->gpe0_blk + facp->gpe0_len - 1);
48212793204Smarco 	if (facp->gpe1_blk)
48312793204Smarco 		fprintf(fhdr, "\tPM2_GPE1_BLK=0x%x-0x%x, GPE1_BASE=%d\n",
48412793204Smarco 		    facp->gpe1_blk,
48512793204Smarco 		    facp->gpe1_blk + facp->gpe1_len - 1,
48612793204Smarco 		    facp->gpe1_base);
48712793204Smarco 	fprintf(fhdr, "\tP_LVL2_LAT=%dms, P_LVL3_LAT=%dms\n",
48812793204Smarco 	    facp->p_lvl2_lat, facp->p_lvl3_lat);
48912793204Smarco 	fprintf(fhdr, "\tFLUSH_SIZE=%d, FLUSH_STRIDE=%d\n",
49012793204Smarco 	    facp->flush_size, facp->flush_stride);
49112793204Smarco 	fprintf(fhdr, "\tDUTY_OFFSET=%d, DUTY_WIDTH=%d\n",
49212793204Smarco 	    facp->duty_off, facp->duty_width);
49312793204Smarco 	fprintf(fhdr, "\tDAY_ALRM=%d, MON_ALRM=%d, CENTURY=%d\n",
49412793204Smarco 	    facp->day_alrm, facp->mon_alrm, facp->century);
49512793204Smarco 	fprintf(fhdr, "\tFlags=");
49612793204Smarco 	sep = '{';
49712793204Smarco 
49812793204Smarco 	PRINTFLAG(WBINVD);
49912793204Smarco 	PRINTFLAG(WBINVD_FLUSH);
50012793204Smarco 	PRINTFLAG(PROC_C1);
50112793204Smarco 	PRINTFLAG(P_LVL2_UP);
50212793204Smarco 	PRINTFLAG(PWR_BUTTON);
50312793204Smarco 	PRINTFLAG(SLP_BUTTON);
50412793204Smarco 	PRINTFLAG(FIX_RTC);
50512793204Smarco 	PRINTFLAG(RTC_S4);
50612793204Smarco 	PRINTFLAG(TMR_VAL_EXT);
50712793204Smarco 	PRINTFLAG(DCK_CAP);
50812793204Smarco 
50912793204Smarco 	fprintf(fhdr, "}\n");
51012793204Smarco 	fprintf(fhdr, "\n");
51112793204Smarco }
51212793204Smarco 
51312793204Smarco void
acpi_print_dsdt(struct ACPIsdt * dsdp)51412793204Smarco acpi_print_dsdt(struct ACPIsdt *dsdp)
51512793204Smarco {
51612793204Smarco 	acpi_print_sdt(dsdp);
51712793204Smarco }
51812793204Smarco 
51912793204Smarco void
acpi_handle_dsdt(struct ACPIsdt * dsdp)52012793204Smarco acpi_handle_dsdt(struct ACPIsdt *dsdp)
5217934d707Stholo {
5227934d707Stholo 	u_int8_t	*dp;
5237934d707Stholo 	u_int8_t	*end;
5247934d707Stholo 
52512793204Smarco 	acpi_print_dsdt(dsdp);
52612793204Smarco 
52712793204Smarco 	dp = (u_int8_t *)dsdp->body;
52812793204Smarco 	end = (u_int8_t *)dsdp + dsdp->len;
5297934d707Stholo }
5307934d707Stholo 
53112793204Smarco void
acpi_handle_facp(struct FACPbody * facp)53212793204Smarco acpi_handle_facp(struct FACPbody *facp)
53312793204Smarco {
53412793204Smarco 	struct ACPIsdt	*dsdp;
53512793204Smarco 
53612793204Smarco 	acpi_print_facp(facp);
537113b2535Skettenis 	if (facp->dsdt_ptr == 0)
538113b2535Skettenis 		dsdp = (struct ACPIsdt *) acpi_map_sdt(facp->x_dsdt);
539113b2535Skettenis 	else
54012793204Smarco 		dsdp = (struct ACPIsdt *) acpi_map_sdt(facp->dsdt_ptr);
54112793204Smarco 	if (acpi_checksum(dsdp, dsdp->len))
54212793204Smarco 		errx(1, "DSDT is corrupt");
54312793204Smarco 	acpi_handle_dsdt(dsdp);
54412793204Smarco 	aml_dump(dsdp);
54512793204Smarco }
54612793204Smarco 
54712793204Smarco void
acpi_handle_rsdt(struct ACPIsdt * rsdp)54812793204Smarco acpi_handle_rsdt(struct ACPIsdt *rsdp)
54912793204Smarco {
55012793204Smarco 	int		i;
55112793204Smarco 	int		entries;
55212793204Smarco 	struct ACPIsdt	*sdp;
55312793204Smarco 
55412793204Smarco 	aml_dump(rsdp);
55512793204Smarco 	entries = (rsdp->len - SIZEOF_SDT_HDR) / sizeof(u_int32_t);
55612793204Smarco 	acpi_print_rsdt(rsdp);
55712793204Smarco 	for (i = 0; i < entries; i++) {
55812793204Smarco 		sdp = (struct ACPIsdt *) acpi_map_sdt(rsdp->body[i]);
55912793204Smarco 		if (acpi_checksum(sdp, sdp->len))
56012793204Smarco 			errx(1, "RSDT entry %d is corrupt", i);
56112793204Smarco 		aml_dump(sdp);
56212793204Smarco 		if (!memcmp(sdp->signature, "FACP", 4)) {
56312793204Smarco 			acpi_handle_facp((struct FACPbody *) sdp->body);
56412793204Smarco 		} else {
56512793204Smarco 			acpi_print_sdt(sdp);
56612793204Smarco 		}
56712793204Smarco 	}
56812793204Smarco }
56912793204Smarco 
57012793204Smarco void
acpi_handle_xsdt(struct ACPIsdt * rsdp)5716988a5d7Skettenis acpi_handle_xsdt(struct ACPIsdt *rsdp)
5726988a5d7Skettenis {
5736988a5d7Skettenis 	int		i;
5746988a5d7Skettenis 	int		entries;
5756988a5d7Skettenis 	struct ACPIsdt	*sdp;
5766988a5d7Skettenis 	u_int64_t	*body = (u_int64_t *) rsdp->body;
5776988a5d7Skettenis 
5786988a5d7Skettenis 	aml_dump(rsdp);
5796988a5d7Skettenis 	entries = (rsdp->len - SIZEOF_SDT_HDR) / sizeof(u_int64_t);
5806988a5d7Skettenis 	acpi_print_xsdt(rsdp);
5816988a5d7Skettenis 	for (i = 0; i < entries; i++) {
5826988a5d7Skettenis 		sdp = (struct ACPIsdt *) acpi_map_sdt(body[i]);
5836988a5d7Skettenis 		if (acpi_checksum(sdp, sdp->len))
5846988a5d7Skettenis 			errx(1, "XSDT entry %d is corrupt", i);
5856988a5d7Skettenis 		aml_dump(sdp);
5866988a5d7Skettenis 		if (!memcmp(sdp->signature, "FACP", 4)) {
5876988a5d7Skettenis 			acpi_handle_facp((struct FACPbody *) sdp->body);
5886988a5d7Skettenis 		} else {
5896988a5d7Skettenis 			acpi_print_sdt(sdp);
5906988a5d7Skettenis 		}
5916988a5d7Skettenis 	}
5926988a5d7Skettenis }
5936988a5d7Skettenis 
5946988a5d7Skettenis void
asl_dump_from_devmem(void)59512793204Smarco asl_dump_from_devmem(void)
5967934d707Stholo {
5977934d707Stholo 	struct ACPIrsdp	*rp;
5987934d707Stholo 	struct ACPIsdt	*rsdp;
59912793204Smarco 	char		name[PATH_MAX];
60012793204Smarco 
601c8dab64cSkettenis 	snprintf(name, sizeof(name), "%s%cheaders", aml_dumpfile,
602c8dab64cSkettenis 	    aml_dumpdir ? '/' : '.');
6037934d707Stholo 
604d2f88ac2Sderaadt 	acpi_user_init();
605d2f88ac2Sderaadt 
606bc30430aSderaadt 	/* Can only unveil if being dumped to a dir */
607bc30430aSderaadt 	if (aml_dumpdir) {
608bc30430aSderaadt 		if (unveil(aml_dumpfile, "wc") == -1)
609bc5a8259Sbeck 			err(1, "unveil %s", aml_dumpfile);
6100c9a99e6Sderaadt 	} else if (aml_dumpfile[0] == '/') {	/* admittedly pretty shitty */
6110c9a99e6Sderaadt 		if (unveil("/", "wc") == -1)
612bc5a8259Sbeck 			err(1, "unveil /");
6130c9a99e6Sderaadt 	} else {
6140c9a99e6Sderaadt 		if (unveil(".", "wc") == -1)
615bc5a8259Sbeck 			err(1, "unveil .");
6160c9a99e6Sderaadt 	}
6170c9a99e6Sderaadt 
618bc30430aSderaadt 	if (unveil(_PATH_MEM, "r") == -1)
619bc5a8259Sbeck 		err(1, "unveil %s", _PATH_MEM);
620bc30430aSderaadt 	if (unveil(_PATH_KMEM, "r") == -1)
621bc5a8259Sbeck 		err(1, "unveil %s", _PATH_KMEM);
622bc30430aSderaadt 	if (unveil(_PATH_KVMDB, "r") == -1)
623bc5a8259Sbeck 		err(1, "unveil %s", _PATH_KVMDB);
624bc30430aSderaadt 	if (unveil(_PATH_KSYMS, "r") == -1)
625bc5a8259Sbeck 		err(1, "unveil %s", _PATH_KSYMS);
626bc30430aSderaadt 	if (unveil(_PATH_UNIX, "r") == -1)
627bc5a8259Sbeck 		err(1, "unveil %s", _PATH_UNIX);
6280462adfaSsemarie 	if (pledge("stdio rpath wpath cpath", NULL) == -1)
6290bd1216cSderaadt 		err(1, "pledge");
630d2f88ac2Sderaadt 
6317934d707Stholo 	rp = acpi_find_rsd_ptr();
63217033bfcSkettenis 	if (!rp) {
63317033bfcSkettenis 		if (!quiet)
63417033bfcSkettenis 			warnx("Can't find ACPI information");
63517033bfcSkettenis 		exit(1);
63617033bfcSkettenis 	}
6377934d707Stholo 
63812793204Smarco 	fhdr = fopen(name, "w");
63912793204Smarco 	if (fhdr == NULL)
64012793204Smarco 		err(1, "asl_dump_from_devmem");
64112793204Smarco 
6427934d707Stholo 	acpi_print_rsd_ptr(rp);
6437934d707Stholo 
6442a1d3267Slteo 	if (rp->rev == 2 && rp->xaddr) {
6456988a5d7Skettenis 		rsdp = (struct ACPIsdt *) acpi_map_sdt(rp->xaddr);
6466988a5d7Skettenis 		if (memcmp(rsdp->signature, "XSDT", 4) ||
6476988a5d7Skettenis 		    acpi_checksum(rsdp, rsdp->len))
6486988a5d7Skettenis 			errx(1, "XSDT is corrupted");
6496988a5d7Skettenis 
6506988a5d7Skettenis 		acpi_handle_xsdt(rsdp);
6512a1d3267Slteo 	} else if (rp->addr) {
6522a1d3267Slteo 		rsdp = (struct ACPIsdt *) acpi_map_sdt(rp->addr);
6532a1d3267Slteo 		if (memcmp(rsdp->signature, "RSDT", 4) ||
6542a1d3267Slteo 		    acpi_checksum(rsdp, rsdp->len))
6552a1d3267Slteo 			errx(1, "RSDT is corrupted");
6562a1d3267Slteo 
6572a1d3267Slteo 		acpi_handle_rsdt(rsdp);
6582a1d3267Slteo 	} else
6592a1d3267Slteo 		errx(1, "XSDT or RSDT not found");
66012793204Smarco 
66112793204Smarco 	fclose(fhdr);
6627934d707Stholo }
6637934d707Stholo 
66412793204Smarco void
usage(void)66568f43119Sderaadt usage(void)
6667934d707Stholo {
66712793204Smarco 	extern char	*__progname;
6687934d707Stholo 
669c8dab64cSkettenis 	fprintf(stderr, "usage: %s -o prefix\n", __progname);
6707934d707Stholo 	exit(1);
6717934d707Stholo }
6727934d707Stholo 
6737934d707Stholo int
main(int argc,char * argv[])6747934d707Stholo main(int argc, char *argv[])
6757934d707Stholo {
676c8dab64cSkettenis 	struct stat	st;
6776988a5d7Skettenis 	int		c;
6787934d707Stholo 
67917033bfcSkettenis 	while ((c = getopt(argc, argv, "o:q")) != -1) {
680d2f88ac2Sderaadt 		switch (c) {
681d2f88ac2Sderaadt 		case 'o':
6827934d707Stholo 			aml_dumpfile = optarg;
683d2f88ac2Sderaadt 			break;
68417033bfcSkettenis 		case 'q':
68517033bfcSkettenis 			quiet = 1;
68617033bfcSkettenis 			break;
687d2f88ac2Sderaadt 		default:
68868f43119Sderaadt 			usage();
689d2f88ac2Sderaadt 			break;
690d2f88ac2Sderaadt 		}
6917934d707Stholo 	}
69212793204Smarco 
69312793204Smarco 	if (aml_dumpfile == NULL)
69412793204Smarco 		usage();
6957934d707Stholo 
696c8dab64cSkettenis 	if (stat(aml_dumpfile, &st) == 0 && S_ISDIR(st.st_mode))
697c8dab64cSkettenis 		aml_dumpdir = 1;
698c8dab64cSkettenis 
6997934d707Stholo 	asl_dump_from_devmem();
70012793204Smarco 
7017934d707Stholo 	return (0);
7027934d707Stholo }
70388448ec7Syasuoka 
7046988a5d7Skettenis #ifdef __aarch64__
7056988a5d7Skettenis 
70688448ec7Syasuoka u_long
efi_acpi_addr(void)7076988a5d7Skettenis efi_acpi_addr(void)
7086988a5d7Skettenis {
7096988a5d7Skettenis 	kvm_t		*kd;
7106988a5d7Skettenis 	struct nlist	 nl[2];
7116988a5d7Skettenis 	uint64_t	 table;
7126988a5d7Skettenis 
7136988a5d7Skettenis 	memset(&nl, 0, sizeof(nl));
7146988a5d7Skettenis 	kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, NULL);
7156988a5d7Skettenis 	if (kd == NULL)
7166988a5d7Skettenis 		goto on_error;
717*c3c82401Skettenis 	nl[0].n_name = "_efi_acpi_table";
718*c3c82401Skettenis 	if (kvm_nlist(kd, nl) != 0)
7196988a5d7Skettenis 		goto on_error;
7206988a5d7Skettenis 	if (kvm_read(kd, nl[0].n_value, &table, sizeof(table)) == -1)
7216988a5d7Skettenis 		goto on_error;
7226988a5d7Skettenis 
7236988a5d7Skettenis 	kvm_close(kd);
7246988a5d7Skettenis 	return table;
7256988a5d7Skettenis 
7266988a5d7Skettenis on_error:
7276988a5d7Skettenis 	if (kd != NULL)
7286988a5d7Skettenis 		kvm_close(kd);
7296988a5d7Skettenis 	return (0);
7306988a5d7Skettenis }
7316988a5d7Skettenis 
7326988a5d7Skettenis #else
7336988a5d7Skettenis 
7346988a5d7Skettenis #include <machine/biosvar.h>
7356988a5d7Skettenis 
7366988a5d7Skettenis u_long
efi_acpi_addr(void)7376988a5d7Skettenis efi_acpi_addr(void)
73888448ec7Syasuoka {
73988448ec7Syasuoka 	kvm_t		*kd;
74088448ec7Syasuoka 	struct nlist	 nl[2];
74188448ec7Syasuoka 	bios_efiinfo_t	 efiinfo;
74288448ec7Syasuoka 	u_long	 ptr;
74388448ec7Syasuoka 
74488448ec7Syasuoka 	memset(&nl, 0, sizeof(nl));
74588448ec7Syasuoka 	kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, NULL);
74688448ec7Syasuoka 	if (kd == NULL)
74788448ec7Syasuoka 		goto on_error;
74888448ec7Syasuoka 	nl[0].n_name = "_bios_efiinfo";
749*c3c82401Skettenis 	if (kvm_nlist(kd, nl) != 0)
75088448ec7Syasuoka 		goto on_error;
75188448ec7Syasuoka 	if (kvm_read(kd, nl[0].n_value, &ptr, sizeof(ptr)) == -1)
75288448ec7Syasuoka 		goto on_error;
75388448ec7Syasuoka 	if (kvm_read(kd, ptr, &efiinfo, sizeof(efiinfo)) == -1)
75488448ec7Syasuoka 		goto on_error;
75588448ec7Syasuoka 
75688448ec7Syasuoka 	kvm_close(kd);
75788448ec7Syasuoka 	return (efiinfo.config_acpi);
75888448ec7Syasuoka 
75988448ec7Syasuoka on_error:
76088448ec7Syasuoka 	if (kd != NULL)
76188448ec7Syasuoka 		kvm_close(kd);
76288448ec7Syasuoka 	return (0);
76388448ec7Syasuoka }
7646988a5d7Skettenis 
7656988a5d7Skettenis #endif
766