xref: /freebsd/usr.sbin/acpi/acpidb/acpidb.c (revision acd3428b7d3e94cef0e1881c868cb4b131d4ff41)
1 /*-
2  * Copyright (c) 2000-2002 Mitsuru IWASAKI <iwasaki@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  *	$FreeBSD$
27  */
28 
29 #include <sys/param.h>
30 #include <sys/queue.h>
31 #include <sys/mman.h>
32 #include <sys/stat.h>
33 #include <sys/types.h>
34 
35 #include <assert.h>
36 #include <ctype.h>
37 #include <err.h>
38 #include <fcntl.h>
39 #include <limits.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <unistd.h>
43 
44 #include <contrib/dev/acpica/acpi.h>
45 #include <contrib/dev/acpica/acnamesp.h>
46 #include <contrib/dev/acpica/acdebug.h>
47 
48 /*
49  * Dummy DSDT Table Header
50  */
51 
52 ACPI_TABLE_HEADER	dummy_dsdt_table = {
53 	"DSDT", 123, 1, 123, "OEMID", "OEMTBLID", 1, "CRID", 1
54 };
55 
56 /*
57  * Region space I/O routines on virtual machine
58  */
59 
60 int	aml_debug_prompt = 1;
61 
62 struct ACPIRegionContent {
63 	TAILQ_ENTRY(ACPIRegionContent) links;
64 	int			regtype;
65 	ACPI_PHYSICAL_ADDRESS	addr;
66 	UINT8			value;
67 };
68 
69 TAILQ_HEAD(ACPIRegionContentList, ACPIRegionContent);
70 struct	ACPIRegionContentList RegionContentList;
71 
72 static int		 aml_simulation_initialized = 0;
73 
74 static void		 aml_simulation_init(void);
75 static int		 aml_simulate_regcontent_add(int regtype,
76 			     ACPI_PHYSICAL_ADDRESS addr,
77 			     UINT8 value);
78 static int		 aml_simulate_regcontent_read(int regtype,
79 			     ACPI_PHYSICAL_ADDRESS addr,
80 			     UINT8 *valuep);
81 static int		 aml_simulate_regcontent_write(int regtype,
82 			     ACPI_PHYSICAL_ADDRESS addr,
83 			     UINT8 *valuep);
84 static ACPI_INTEGER	 aml_simulate_prompt(char *msg, ACPI_INTEGER def_val);
85 static void		 aml_simulation_regload(const char *dumpfile);
86 static void		 aml_simulation_regdump(const char *dumpfile);
87 
88 static void
89 aml_simulation_init(void)
90 {
91 
92 	aml_simulation_initialized = 1;
93 	TAILQ_INIT(&RegionContentList);
94 	aml_simulation_regload("region.ini");
95 }
96 
97 static int
98 aml_simulate_regcontent_add(int regtype, ACPI_PHYSICAL_ADDRESS addr, UINT8 value)
99 {
100 	struct	ACPIRegionContent *rc;
101 
102 	rc = malloc(sizeof(struct ACPIRegionContent));
103 	if (rc == NULL) {
104 		return (-1);	/* malloc fail */
105 	}
106 	rc->regtype = regtype;
107 	rc->addr = addr;
108 	rc->value = value;
109 
110 	TAILQ_INSERT_TAIL(&RegionContentList, rc, links);
111 	return (0);
112 }
113 
114 static int
115 aml_simulate_regcontent_read(int regtype, ACPI_PHYSICAL_ADDRESS addr, UINT8 *valuep)
116 {
117 	struct	ACPIRegionContent *rc;
118 
119 	if (!aml_simulation_initialized) {
120 		aml_simulation_init();
121 	}
122 	TAILQ_FOREACH(rc, &RegionContentList, links) {
123 		if (rc->regtype == regtype && rc->addr == addr) {
124 			*valuep = rc->value;
125 			return (1);	/* found */
126 		}
127 	}
128 
129 	*valuep = 0;
130 	return (aml_simulate_regcontent_add(regtype, addr, *valuep));
131 }
132 
133 static int
134 aml_simulate_regcontent_write(int regtype, ACPI_PHYSICAL_ADDRESS addr, UINT8 *valuep)
135 {
136 	struct	ACPIRegionContent *rc;
137 
138 	if (!aml_simulation_initialized) {
139 		aml_simulation_init();
140 	}
141 	TAILQ_FOREACH(rc, &RegionContentList, links) {
142 		if (rc->regtype == regtype && rc->addr == addr) {
143 			rc->value = *valuep;
144 			return (1);	/* exists */
145 		}
146 	}
147 
148 	return (aml_simulate_regcontent_add(regtype, addr, *valuep));
149 }
150 
151 static ACPI_INTEGER
152 aml_simulate_prompt(char *msg, ACPI_INTEGER def_val)
153 {
154 	char		buf[16], *ep;
155 	ACPI_INTEGER	val;
156 
157 	val = def_val;
158 	printf("DEBUG");
159 	if (msg != NULL) {
160 		printf("%s", msg);
161 	}
162 	printf("(default: 0x%jx ", val);
163 	printf(" / %ju) >>", val);
164 	fflush(stdout);
165 
166 	bzero(buf, sizeof buf);
167 	while (1) {
168 		if (read(0, buf, sizeof buf) == 0) {
169 			continue;
170 		}
171 		if (buf[0] == '\n') {
172 			break;	/* use default value */
173 		}
174 		if (buf[0] == '0' && buf[1] == 'x') {
175 			val = strtoq(buf, &ep, 16);
176 		} else {
177 			val = strtoq(buf, &ep, 10);
178 		}
179 		break;
180 	}
181 	return (val);
182 }
183 
184 static void
185 aml_simulation_regload(const char *dumpfile)
186 {
187 	char	buf[256], *np, *ep;
188 	struct	ACPIRegionContent rc;
189 	FILE	*fp;
190 
191 	if (!aml_simulation_initialized) {
192 		return;
193 	}
194 
195 	if ((fp = fopen(dumpfile, "r")) == NULL) {
196 		return;
197 	}
198 
199 	while (fgets(buf, sizeof buf, fp) != NULL) {
200 		np = buf;
201 		/* reading region type */
202 		rc.regtype = strtoq(np, &ep, 10);
203 		if (np == ep) {
204 			continue;
205 		}
206 		np = ep;
207 
208 		/* reading address */
209 		rc.addr = strtoq(np, &ep, 16);
210 		if (np == ep) {
211 			continue;
212 		}
213 		np = ep;
214 
215 		/* reading value */
216 		rc.value = strtoq(np, &ep, 16);
217 		if (np == ep) {
218 			continue;
219 		}
220 		aml_simulate_regcontent_write(rc.regtype, rc.addr, &rc.value);
221 	}
222 
223 	fclose(fp);
224 }
225 
226 static void
227 aml_simulation_regdump(const char *dumpfile)
228 {
229 	struct	ACPIRegionContent *rc;
230 	FILE	*fp;
231 
232 	if (!aml_simulation_initialized) {
233 		return;
234 	}
235 	if ((fp = fopen(dumpfile, "w")) == NULL) {
236 		warn("%s", dumpfile);
237 		return;
238 	}
239 	while (!TAILQ_EMPTY(&RegionContentList)) {
240 		rc = TAILQ_FIRST(&RegionContentList);
241 		fprintf(fp, "%d	0x%jx	0x%x\n",
242 		    rc->regtype, rc->addr, rc->value);
243 		TAILQ_REMOVE(&RegionContentList, rc, links);
244 		free(rc);
245 	}
246 
247 	fclose(fp);
248 	TAILQ_INIT(&RegionContentList);
249 }
250 
251 /*
252  * Space handlers on virtual machine
253  */
254 
255 static ACPI_STATUS
256 aml_vm_space_handler(
257 	UINT32			SpaceID,
258 	UINT32			Function,
259 	ACPI_PHYSICAL_ADDRESS	Address,
260 	UINT32			BitWidth,
261 	ACPI_INTEGER		*Value,
262 	int			Prompt)
263 {
264 	int			state;
265 	UINT8			val;
266 	ACPI_INTEGER		value, i;
267 	char			msg[256];
268 	static const char	*space_names[] = {
269 		"SYSTEM_MEMORY", "SYSTEM_IO", "PCI_CONFIG",
270 		"EC", "SMBUS", "CMOS", "PCI_BAR_TARGET"};
271 
272 	switch (Function) {
273 	case ACPI_READ:
274 		value = 0;
275 		for (i = 0; (i * 8) < BitWidth; i++) {
276 			state = aml_simulate_regcontent_read(SpaceID,
277 							     Address + i, &val);
278 			if (state == -1) {
279 				return (AE_NO_MEMORY);
280 			}
281 			value |= val << (i * 8);
282 		}
283 		*Value = value;
284 		if (Prompt) {
285 			sprintf(msg, "[read (%s, %2d, 0x%jx)]",
286 				space_names[SpaceID], BitWidth, Address);
287 			*Value = aml_simulate_prompt(msg, value);
288 			if (*Value != value) {
289 				return(aml_vm_space_handler(SpaceID,
290 						ACPI_WRITE,
291 						Address, BitWidth, Value, 0));
292 			}
293 		}
294 		break;
295 
296 	case ACPI_WRITE:
297 		value = *Value;
298 		if (Prompt) {
299 			sprintf(msg, "[write(%s, %2d, 0x%jx)]",
300 				space_names[SpaceID], BitWidth, Address);
301 			value = aml_simulate_prompt(msg, *Value);
302 		}
303 		*Value = value;
304 		for (i = 0; (i * 8) < BitWidth; i++) {
305 			val = value & 0xff;
306 			state = aml_simulate_regcontent_write(SpaceID,
307 							      Address + i, &val);
308 			if (state == -1) {
309 				return (AE_NO_MEMORY);
310 			}
311 			value = value >> 8;
312 		}
313 	}
314 
315 	return (AE_OK);
316 }
317 
318 #define DECLARE_VM_SPACE_HANDLER(name, id);			\
319 static ACPI_STATUS						\
320 aml_vm_space_handler_##name (					\
321 	UINT32			Function,			\
322 	ACPI_PHYSICAL_ADDRESS	Address,			\
323 	UINT32			BitWidth,			\
324 	ACPI_INTEGER		*Value)				\
325 {								\
326 	return (aml_vm_space_handler(id, Function, Address,	\
327 		BitWidth, Value, aml_debug_prompt));		\
328 }
329 
330 DECLARE_VM_SPACE_HANDLER(system_memory,	ACPI_ADR_SPACE_SYSTEM_MEMORY);
331 DECLARE_VM_SPACE_HANDLER(system_io,	ACPI_ADR_SPACE_SYSTEM_IO);
332 DECLARE_VM_SPACE_HANDLER(pci_config,	ACPI_ADR_SPACE_PCI_CONFIG);
333 DECLARE_VM_SPACE_HANDLER(ec,		ACPI_ADR_SPACE_EC);
334 DECLARE_VM_SPACE_HANDLER(smbus,		ACPI_ADR_SPACE_SMBUS);
335 DECLARE_VM_SPACE_HANDLER(cmos,		ACPI_ADR_SPACE_CMOS);
336 DECLARE_VM_SPACE_HANDLER(pci_bar_target,ACPI_ADR_SPACE_PCI_BAR_TARGET);
337 
338 /*
339  * Load DSDT data file and invoke debugger
340  */
341 
342 static UINT32	DummyGlobalLock;
343 
344 static int
345 load_dsdt(const char *dsdtfile)
346 {
347 	char			filetmp[PATH_MAX];
348 	u_int8_t		*code;
349 	struct stat		 sb;
350 	int			 fd, fd2;
351 	int			 error;
352 
353 	fd = open(dsdtfile, O_RDONLY, 0);
354 	if (fd == -1) {
355 		perror("open");
356 		return (-1);
357 	}
358 	if (fstat(fd, &sb) == -1) {
359 		perror("fstat");
360 		return (-1);
361 	}
362 	code = mmap(NULL, (size_t)sb.st_size, PROT_READ, MAP_PRIVATE, fd, (off_t)0);
363 	if (code == NULL) {
364 		perror("mmap");
365 		return (-1);
366 	}
367 	if ((error = AcpiInitializeSubsystem()) != AE_OK) {
368 		return (-1);
369 	}
370 
371 	/*
372 	 * make sure DSDT data contains table header or not.
373 	 */
374 	if (strncmp((char *)code, "DSDT", 4) == 0) {
375 		strncpy(filetmp, dsdtfile, sizeof(filetmp));
376 	} else {
377 		mode_t	mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
378 		dummy_dsdt_table.Length = sizeof(ACPI_TABLE_HEADER) + sb.st_size;
379 		snprintf(filetmp, sizeof(filetmp), "%s.tmp", dsdtfile);
380 		fd2 = open(filetmp, O_WRONLY | O_CREAT | O_TRUNC, mode);
381 		if (fd2 == -1) {
382 			perror("open");
383 			return (-1);
384 		}
385 		write(fd2, &dummy_dsdt_table, sizeof(ACPI_TABLE_HEADER));
386 
387 		write(fd2, code, sb.st_size);
388 		close(fd2);
389 	}
390 
391 	/*
392 	 * Install the virtual machine version of address space handlers.
393 	 */
394 	if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
395 			ACPI_ADR_SPACE_SYSTEM_MEMORY,
396 			(ACPI_ADR_SPACE_HANDLER)aml_vm_space_handler_system_memory,
397 			NULL, NULL)) != AE_OK) {
398 		fprintf(stderr, "could not initialise SystemMemory handler: %d\n", error);
399 		return (-1);
400 	}
401 	if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
402 			ACPI_ADR_SPACE_SYSTEM_IO,
403 			(ACPI_ADR_SPACE_HANDLER)aml_vm_space_handler_system_io,
404 			NULL, NULL)) != AE_OK) {
405 		fprintf(stderr, "could not initialise SystemIO handler: %d\n", error);
406 		return (-1);
407 	}
408 	if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
409 			ACPI_ADR_SPACE_PCI_CONFIG,
410 			(ACPI_ADR_SPACE_HANDLER)aml_vm_space_handler_pci_config,
411 			NULL, NULL)) != AE_OK) {
412 		fprintf(stderr, "could not initialise PciConfig handler: %d\n", error);
413 		return (-1);
414 	}
415 	if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
416 			ACPI_ADR_SPACE_EC,
417 			(ACPI_ADR_SPACE_HANDLER)aml_vm_space_handler_ec,
418 			NULL, NULL)) != AE_OK) {
419 		fprintf(stderr, "could not initialise EC handler: %d\n", error);
420 		return (-1);
421 	}
422 	if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
423 			ACPI_ADR_SPACE_SMBUS,
424 			(ACPI_ADR_SPACE_HANDLER)aml_vm_space_handler_smbus,
425 			NULL, NULL)) != AE_OK) {
426 		fprintf(stderr, "could not initialise SMBUS handler: %d\n", error);
427 		return (-1);
428 	}
429 	if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
430 			ACPI_ADR_SPACE_CMOS,
431 			(ACPI_ADR_SPACE_HANDLER)aml_vm_space_handler_cmos,
432 			NULL, NULL)) != AE_OK) {
433 		fprintf(stderr, "could not initialise CMOS handler: %d\n", error);
434 		return (-1);
435 	}
436 	if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
437 			ACPI_ADR_SPACE_PCI_BAR_TARGET,
438 			(ACPI_ADR_SPACE_HANDLER)aml_vm_space_handler_pci_bar_target,
439 			NULL, NULL)) != AE_OK) {
440 		fprintf(stderr, "could not initialise PCI BAR TARGET handler: %d\n", error);
441 		return (-1);
442 	}
443 
444 	AcpiGbl_FACS = malloc(sizeof (ACPI_COMMON_FACS));
445 	if (AcpiGbl_FACS == NULL) {
446 		fprintf(stderr, "could not allocate memory for FACS\n");
447 		return (-1);
448 	}
449 	DummyGlobalLock = 0;
450 	AcpiGbl_CommonFACS.GlobalLock = &DummyGlobalLock;
451 	AcpiGbl_GlobalLockPresent = TRUE;
452 
453 	AcpiDbGetTableFromFile(filetmp, NULL);
454 	AcpiUtSetIntegerWidth (AcpiGbl_DSDT->Revision);
455 
456 	AcpiDbInitialize();
457 	AcpiGbl_DebuggerConfiguration = 0;
458 	AcpiDbUserCommands(':', NULL);
459 
460 	if (strcmp(dsdtfile, filetmp) != 0) {
461 		unlink(filetmp);
462 	}
463 
464 	return (0);
465 }
466 
467 static void
468 usage(const char *progname)
469 {
470 
471 	printf("usage: %s dsdt_file\n", progname);
472 	exit(1);
473 }
474 
475 int
476 main(int argc, char *argv[])
477 {
478 	char	*progname;
479 
480 	progname = argv[0];
481 
482 	if (argc == 1) {
483 		usage(progname);
484 	}
485 
486 	AcpiDbgLevel = ACPI_DEBUG_DEFAULT;
487 
488 	/*
489 	 * Match kernel options for the interpreter.  Global variable names
490 	 * can be found in acglobal.h.
491 	 */
492 	AcpiGbl_EnableInterpreterSlack = TRUE;
493 
494 	aml_simulation_regload("region.ini");
495 	if (load_dsdt(argv[1]) == 0) {
496 		aml_simulation_regdump("region.dmp");
497 	}
498 
499 	return (0);
500 }
501