xref: /freebsd/usr.sbin/acpi/acpidb/acpidb.c (revision 7660b554bc59a07be0431c17e0e33815818baa69)
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 <acpi.h>
45 #include <acnamesp.h>
46 #include <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%x ", val);
163 	printf(" / %u) >>", 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%x	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 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%x)]",
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%x)]",
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 	void			*HandlerContext,		\
326 	void			*RegionContext)			\
327 {								\
328 	return (aml_vm_space_handler(id, Function, Address,	\
329 		BitWidth, Value, aml_debug_prompt));		\
330 }
331 
332 DECLARE_VM_SPACE_HANDLER(system_memory,	ACPI_ADR_SPACE_SYSTEM_MEMORY);
333 DECLARE_VM_SPACE_HANDLER(system_io,	ACPI_ADR_SPACE_SYSTEM_IO);
334 DECLARE_VM_SPACE_HANDLER(pci_config,	ACPI_ADR_SPACE_PCI_CONFIG);
335 DECLARE_VM_SPACE_HANDLER(ec,		ACPI_ADR_SPACE_EC);
336 DECLARE_VM_SPACE_HANDLER(smbus,		ACPI_ADR_SPACE_SMBUS);
337 DECLARE_VM_SPACE_HANDLER(cmos,		ACPI_ADR_SPACE_CMOS);
338 DECLARE_VM_SPACE_HANDLER(pci_bar_target,ACPI_ADR_SPACE_PCI_BAR_TARGET);
339 
340 /*
341  * Load DSDT data file and invoke debugger
342  */
343 
344 static UINT32	DummyGlobalLock;
345 
346 static int
347 load_dsdt(const char *dsdtfile)
348 {
349 	char			filetmp[PATH_MAX];
350 	u_int8_t		*code, *amlptr;
351 	struct stat		 sb;
352 	int			 fd, fd2;
353 	int			 error;
354 	ACPI_TABLE_HEADER	*tableptr;
355 
356 	fd = open(dsdtfile, O_RDONLY, 0);
357 	if (fd == -1) {
358 		perror("open");
359 		return (-1);
360 	}
361 	if (fstat(fd, &sb) == -1) {
362 		perror("fstat");
363 		return (-1);
364 	}
365 	code = mmap(NULL, (size_t)sb.st_size, PROT_READ, MAP_PRIVATE, fd, (off_t)0);
366 	if (code == NULL) {
367 		perror("mmap");
368 		return (-1);
369 	}
370 	if ((error = AcpiInitializeSubsystem()) != AE_OK) {
371 		return (-1);
372 	}
373 
374 	/*
375 	 * make sure DSDT data contains table header or not.
376 	 */
377 	if (strncmp((char *)code, "DSDT", 4) == 0) {
378 		strncpy(filetmp, dsdtfile, sizeof(filetmp));
379 	} else {
380 		mode_t	mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
381 		dummy_dsdt_table.Length = sizeof(ACPI_TABLE_HEADER) + sb.st_size;
382 		snprintf(filetmp, sizeof(filetmp), "%s.tmp", dsdtfile);
383 		fd2 = open(filetmp, O_WRONLY | O_CREAT | O_TRUNC, mode);
384 		if (fd2 == -1) {
385 			perror("open");
386 			return (-1);
387 		}
388 		write(fd2, &dummy_dsdt_table, sizeof(ACPI_TABLE_HEADER));
389 
390 		write(fd2, code, sb.st_size);
391 		close(fd2);
392 	}
393 
394 	/*
395 	 * Install the virtual machine version of address space handlers.
396 	 */
397 	if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
398 			ACPI_ADR_SPACE_SYSTEM_MEMORY,
399 			aml_vm_space_handler_system_memory,
400 			NULL, NULL)) != AE_OK) {
401 		fprintf(stderr, "could not initialise SystemMemory handler: %d\n", error);
402 		return (-1);
403 	}
404 	if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
405 			ACPI_ADR_SPACE_SYSTEM_IO,
406 			aml_vm_space_handler_system_io,
407 			NULL, NULL)) != AE_OK) {
408 		fprintf(stderr, "could not initialise SystemIO handler: %d\n", error);
409 		return (-1);
410 	}
411 	if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
412 			ACPI_ADR_SPACE_PCI_CONFIG,
413 			aml_vm_space_handler_pci_config,
414 			NULL, NULL)) != AE_OK) {
415 		fprintf(stderr, "could not initialise PciConfig handler: %d\n", error);
416 		return (-1);
417 	}
418 	if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
419 			ACPI_ADR_SPACE_EC,
420 			aml_vm_space_handler_ec,
421 			NULL, NULL)) != AE_OK) {
422 		fprintf(stderr, "could not initialise EC handler: %d\n", error);
423 		return (-1);
424 	}
425 	if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
426 			ACPI_ADR_SPACE_SMBUS,
427 			aml_vm_space_handler_smbus,
428 			NULL, NULL)) != AE_OK) {
429 		fprintf(stderr, "could not initialise SMBUS handler: %d\n", error);
430 		return (-1);
431 	}
432 	if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
433 			ACPI_ADR_SPACE_CMOS,
434 			aml_vm_space_handler_cmos,
435 			NULL, NULL)) != AE_OK) {
436 		fprintf(stderr, "could not initialise CMOS handler: %d\n", error);
437 		return (-1);
438 	}
439 	if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
440 			ACPI_ADR_SPACE_PCI_BAR_TARGET,
441 			aml_vm_space_handler_pci_bar_target,
442 			NULL, NULL)) != AE_OK) {
443 		fprintf(stderr, "could not initialise PCI BAR TARGET handler: %d\n", error);
444 		return (-1);
445 	}
446 
447 	AcpiGbl_FACS = malloc(sizeof (ACPI_COMMON_FACS));
448 	if (AcpiGbl_FACS == NULL) {
449 		fprintf(stderr, "could not allocate memory for FACS\n");
450 		return (-1);
451 	}
452 	DummyGlobalLock = 0;
453 	AcpiGbl_CommonFACS.GlobalLock = &DummyGlobalLock;
454 	AcpiGbl_GlobalLockPresent = TRUE;
455 
456 	AcpiDbGetTableFromFile(filetmp, NULL);
457 	AcpiUtSetIntegerWidth (AcpiGbl_DSDT->Revision);
458 
459 	AcpiDbInitialize();
460 	AcpiGbl_DebuggerConfiguration = 0;
461 	AcpiDbUserCommands(':', NULL);
462 
463 	if (strcmp(dsdtfile, filetmp) != 0) {
464 		unlink(filetmp);
465 	}
466 
467 	return (0);
468 }
469 
470 static void
471 usage(const char *progname)
472 {
473 
474 	printf("usage: %s dsdt_file\n", progname);
475 	exit(1);
476 }
477 
478 int
479 main(int argc, char *argv[])
480 {
481 	char	*progname;
482 
483 	progname = argv[0];
484 
485 	if (argc == 1) {
486 		usage(progname);
487 	}
488 
489 	AcpiDbgLevel = ACPI_DEBUG_DEFAULT;
490 
491 	aml_simulation_regload("region.ini");
492 	if (load_dsdt(argv[1]) == 0) {
493 		aml_simulation_regdump("region.dmp");
494 	}
495 
496 	return (0);
497 }
498