]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - usr.sbin/acpi/acpidb/acpidb.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / usr.sbin / acpi / acpidb / acpidb.c
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/stdint.h>
34 #include <sys/types.h>
35
36 #include <assert.h>
37 #include <ctype.h>
38 #include <err.h>
39 #include <fcntl.h>
40 #include <limits.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <unistd.h>
44
45 #include <contrib/dev/acpica/include/acpi.h>
46 #include <contrib/dev/acpica/include/accommon.h>
47 #include <contrib/dev/acpica/include/acdebug.h>
48 #include <contrib/dev/acpica/include/amlresrc.h>
49
50 /*
51  * Dummy DSDT Table Header
52  */
53
54 static ACPI_TABLE_HEADER dummy_dsdt_table = {
55         "DSDT", 123, 1, 123, "OEMID", "OEMTBLID", 1, "CRID", 1
56 };
57
58 /*
59  * Region space I/O routines on virtual machine
60  */
61
62 static int      aml_debug_prompt = 1;
63
64 struct ACPIRegionContent {
65         TAILQ_ENTRY(ACPIRegionContent) links;
66         int                     regtype;
67         ACPI_PHYSICAL_ADDRESS   addr;
68         UINT8                   value;
69 };
70
71 TAILQ_HEAD(ACPIRegionContentList, ACPIRegionContent);
72 static struct   ACPIRegionContentList RegionContentList;
73
74 static int               aml_simulation_initialized = 0;
75
76 ACPI_PHYSICAL_ADDRESS    AeLocalGetRootPointer(void);
77 void                     AeDoObjectOverrides(void);
78 void                     AeTableOverride(ACPI_TABLE_HEADER *, ACPI_TABLE_HEADER **);
79
80 static void              aml_simulation_init(void);
81 static int               aml_simulate_regcontent_add(int regtype,
82                              ACPI_PHYSICAL_ADDRESS addr,
83                              UINT8 value);
84 static int               aml_simulate_regcontent_read(int regtype,
85                              ACPI_PHYSICAL_ADDRESS addr,
86                              UINT8 *valuep); 
87 static int               aml_simulate_regcontent_write(int regtype,
88                              ACPI_PHYSICAL_ADDRESS addr,
89                              UINT8 *valuep);
90 static UINT64            aml_simulate_prompt(char *msg, UINT64 def_val);
91 static void              aml_simulation_regload(const char *dumpfile);
92 static void              aml_simulation_regdump(const char *dumpfile);
93
94 /* Stubs to simplify linkage to the ACPICA core subsystem. */
95 ACPI_PHYSICAL_ADDRESS
96 AcpiOsGetRootPointer(void)
97 {
98
99         return (0);
100 }
101
102 void
103 AeDoObjectOverrides(void)
104 {
105 }
106
107 void
108 AeTableOverride(ACPI_TABLE_HEADER *ExistingTable, ACPI_TABLE_HEADER **NewTable)
109 {
110 }
111
112 void
113 MpSaveGpioInfo(ACPI_PARSE_OBJECT *Op, AML_RESOURCE *Resource,
114     UINT32 PinCount, UINT16 *PinList, char *DeviceName)
115 {
116 }
117
118 void
119 MpSaveSerialInfo(ACPI_PARSE_OBJECT *Op, AML_RESOURCE *Resource,
120     char *DeviceName)
121 {
122 }
123
124 static void
125 aml_simulation_init(void)
126 {
127
128         aml_simulation_initialized = 1;
129         TAILQ_INIT(&RegionContentList);
130         aml_simulation_regload("region.ini");
131 }
132
133 static int
134 aml_simulate_regcontent_add(int regtype, ACPI_PHYSICAL_ADDRESS addr, UINT8 value)
135 {
136         struct  ACPIRegionContent *rc;
137
138         rc = malloc(sizeof(struct ACPIRegionContent));
139         if (rc == NULL) {
140                 return (-1);    /* malloc fail */
141         }
142         rc->regtype = regtype;
143         rc->addr = addr;
144         rc->value = value;
145
146         TAILQ_INSERT_TAIL(&RegionContentList, rc, links);
147         return (0);
148 }
149
150 static int
151 aml_simulate_regcontent_read(int regtype, ACPI_PHYSICAL_ADDRESS addr, UINT8 *valuep)
152 {
153         struct  ACPIRegionContent *rc;
154
155         if (!aml_simulation_initialized) {
156                 aml_simulation_init();
157         }
158         TAILQ_FOREACH(rc, &RegionContentList, links) {
159                 if (rc->regtype == regtype && rc->addr == addr) {
160                         *valuep = rc->value;
161                         return (1);     /* found */
162                 }
163         }
164
165         *valuep = 0;
166         return (aml_simulate_regcontent_add(regtype, addr, *valuep));
167 }
168
169 static int
170 aml_simulate_regcontent_write(int regtype, ACPI_PHYSICAL_ADDRESS addr, UINT8 *valuep)
171 {
172         struct  ACPIRegionContent *rc;
173
174         if (!aml_simulation_initialized) {
175                 aml_simulation_init();
176         }
177         TAILQ_FOREACH(rc, &RegionContentList, links) {
178                 if (rc->regtype == regtype && rc->addr == addr) {
179                         rc->value = *valuep;
180                         return (1);     /* exists */
181                 }
182         }
183
184         return (aml_simulate_regcontent_add(regtype, addr, *valuep));
185 }
186
187 static UINT64
188 aml_simulate_prompt(char *msg, UINT64 def_val)
189 {
190         char            buf[16], *ep;
191         UINT64          val;
192
193         val = def_val;
194         printf("DEBUG");
195         if (msg != NULL) {
196                 printf("%s", msg);
197         }
198         printf("(default: 0x%jx ", (uintmax_t)val);
199         printf(" / %ju) >>", (uintmax_t)val);
200         fflush(stdout);
201
202         bzero(buf, sizeof buf);
203         while (1) {
204                 if (read(0, buf, sizeof buf) == 0) {
205                         continue;
206                 }
207                 if (buf[0] == '\n') {
208                         break;  /* use default value */
209                 }
210                 if (buf[0] == '0' && buf[1] == 'x') {
211                         val = strtoq(buf, &ep, 16);
212                 } else {
213                         val = strtoq(buf, &ep, 10);
214                 }
215                 break;
216         }
217         return (val);
218 }
219
220 static void
221 aml_simulation_regload(const char *dumpfile)
222 {
223         char    buf[256], *np, *ep;
224         struct  ACPIRegionContent rc;
225         FILE    *fp;
226
227         if (!aml_simulation_initialized) {
228                 return;
229         }
230
231         if ((fp = fopen(dumpfile, "r")) == NULL) {
232                 return;
233         }
234
235         while (fgets(buf, sizeof buf, fp) != NULL) {
236                 np = buf;
237                 /* reading region type */
238                 rc.regtype = strtoq(np, &ep, 10);
239                 if (np == ep) {
240                         continue;
241                 }
242                 np = ep;
243
244                 /* reading address */
245                 rc.addr = strtoq(np, &ep, 16);
246                 if (np == ep) {
247                         continue;
248                 }
249                 np = ep;
250
251                 /* reading value */
252                 rc.value = strtoq(np, &ep, 16);
253                 if (np == ep) {
254                         continue;
255                 }
256                 aml_simulate_regcontent_write(rc.regtype, rc.addr, &rc.value);
257         }
258
259         fclose(fp);
260 }
261
262 static void
263 aml_simulation_regdump(const char *dumpfile)
264 {
265         struct  ACPIRegionContent *rc;
266         FILE    *fp;
267
268         if (!aml_simulation_initialized) {
269                 return;
270         }
271         if ((fp = fopen(dumpfile, "w")) == NULL) {
272                 warn("%s", dumpfile);
273                 return;
274         }
275         while (!TAILQ_EMPTY(&RegionContentList)) {
276                 rc = TAILQ_FIRST(&RegionContentList);
277                 fprintf(fp, "%d 0x%jx   0x%x\n",
278                     rc->regtype, (uintmax_t)rc->addr, rc->value);
279                 TAILQ_REMOVE(&RegionContentList, rc, links);
280                 free(rc);
281         }
282
283         fclose(fp);
284         TAILQ_INIT(&RegionContentList);
285 }
286
287 /*
288  * Space handlers on virtual machine
289  */
290
291 static ACPI_STATUS
292 aml_vm_space_handler(
293         UINT32                  SpaceID,
294         UINT32                  Function,
295         ACPI_PHYSICAL_ADDRESS   Address,
296         UINT32                  BitWidth,
297         UINT64                  *Value,
298         int                     Prompt)
299 {
300         int                     state;
301         UINT8                   val;
302         UINT64                  value, i;
303         char                    msg[256];
304         static const char       *space_names[] = {
305                 "SYSTEM_MEMORY", "SYSTEM_IO", "PCI_CONFIG",
306                 "EC", "SMBUS", "CMOS", "PCI_BAR_TARGET"};
307
308         switch (Function) {
309         case ACPI_READ:
310                 value = 0;
311                 for (i = 0; (i * 8) < BitWidth; i++) {
312                         state = aml_simulate_regcontent_read(SpaceID,
313                                                              Address + i, &val);
314                         if (state == -1) {
315                                 return (AE_NO_MEMORY);
316                         }
317                         value |= val << (i * 8);
318                 }
319                 *Value = value;
320                 if (Prompt) {
321                         sprintf(msg, "[read (%s, %2d, 0x%jx)]",
322                                 space_names[SpaceID], BitWidth,
323                                 (uintmax_t)Address);
324                         *Value = aml_simulate_prompt(msg, value);
325                         if (*Value != value) {
326                                 return(aml_vm_space_handler(SpaceID,
327                                                 ACPI_WRITE,
328                                                 Address, BitWidth, Value, 0));
329                         }
330                 }
331                 break;
332
333         case ACPI_WRITE:
334                 value = *Value;
335                 if (Prompt) {
336                         sprintf(msg, "[write(%s, %2d, 0x%jx)]",
337                                 space_names[SpaceID], BitWidth,
338                                 (uintmax_t)Address);
339                         value = aml_simulate_prompt(msg, *Value);
340                 }
341                 *Value = value;
342                 for (i = 0; (i * 8) < BitWidth; i++) {
343                         val = value & 0xff;
344                         state = aml_simulate_regcontent_write(SpaceID,
345                                                               Address + i, &val);
346                         if (state == -1) {
347                                 return (AE_NO_MEMORY);
348                         }
349                         value = value >> 8;
350                 }
351         }
352
353         return (AE_OK);
354 }
355
356 #define DECLARE_VM_SPACE_HANDLER(name, id);                     \
357 static ACPI_STATUS                                              \
358 aml_vm_space_handler_##name (                                   \
359         UINT32                  Function,                       \
360         ACPI_PHYSICAL_ADDRESS   Address,                        \
361         UINT32                  BitWidth,                       \
362         UINT64                  *Value)                         \
363 {                                                               \
364         return (aml_vm_space_handler(id, Function, Address,     \
365                 BitWidth, Value, aml_debug_prompt));            \
366 }
367
368 DECLARE_VM_SPACE_HANDLER(system_memory, ACPI_ADR_SPACE_SYSTEM_MEMORY);
369 DECLARE_VM_SPACE_HANDLER(system_io,     ACPI_ADR_SPACE_SYSTEM_IO);
370 DECLARE_VM_SPACE_HANDLER(pci_config,    ACPI_ADR_SPACE_PCI_CONFIG);
371 DECLARE_VM_SPACE_HANDLER(ec,            ACPI_ADR_SPACE_EC);
372 DECLARE_VM_SPACE_HANDLER(smbus,         ACPI_ADR_SPACE_SMBUS);
373 DECLARE_VM_SPACE_HANDLER(cmos,          ACPI_ADR_SPACE_CMOS);
374 DECLARE_VM_SPACE_HANDLER(pci_bar_target,ACPI_ADR_SPACE_PCI_BAR_TARGET);
375
376 /*
377  * Load DSDT data file and invoke debugger
378  */
379
380 static int
381 load_dsdt(const char *dsdtfile)
382 {
383         char                    filetmp[PATH_MAX];
384         u_int8_t                *code;
385         struct stat             sb;
386         int                     fd, fd2;
387         int                     error;
388
389         fd = open(dsdtfile, O_RDONLY, 0);
390         if (fd == -1) {
391                 perror("open");
392                 return (-1);
393         }
394         if (fstat(fd, &sb) == -1) {
395                 perror("fstat");
396                 close(fd);
397                 return (-1);
398         }
399         code = mmap(NULL, (size_t)sb.st_size, PROT_READ, MAP_PRIVATE, fd, (off_t)0);
400         if (code == NULL) {
401                 perror("mmap");
402                 return (-1);
403         }
404         if ((error = AcpiInitializeSubsystem()) != AE_OK) {
405                 return (-1);
406         }
407
408         /*
409          * make sure DSDT data contains table header or not.
410          */
411         if (strncmp((char *)code, "DSDT", 4) == 0) {
412                 strncpy(filetmp, dsdtfile, sizeof(filetmp));
413         } else {
414                 mode_t  mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
415                 dummy_dsdt_table.Length = sizeof(ACPI_TABLE_HEADER) + sb.st_size;
416                 snprintf(filetmp, sizeof(filetmp), "%s.tmp", dsdtfile);
417                 fd2 = open(filetmp, O_WRONLY | O_CREAT | O_TRUNC, mode);
418                 if (fd2 == -1) {
419                         perror("open");
420                         return (-1);
421                 }
422                 write(fd2, &dummy_dsdt_table, sizeof(ACPI_TABLE_HEADER));
423
424                 write(fd2, code, sb.st_size);
425                 close(fd2);
426         }
427
428         /*
429          * Install the virtual machine version of address space handlers.
430          */
431         if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
432                         ACPI_ADR_SPACE_SYSTEM_MEMORY,
433                         (ACPI_ADR_SPACE_HANDLER)aml_vm_space_handler_system_memory,
434                         NULL, NULL)) != AE_OK) {
435                 fprintf(stderr, "could not initialise SystemMemory handler: %d\n", error);
436                 return (-1);
437         }
438         if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
439                         ACPI_ADR_SPACE_SYSTEM_IO,
440                         (ACPI_ADR_SPACE_HANDLER)aml_vm_space_handler_system_io,
441                         NULL, NULL)) != AE_OK) {
442                 fprintf(stderr, "could not initialise SystemIO handler: %d\n", error);
443                 return (-1);
444         }
445         if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
446                         ACPI_ADR_SPACE_PCI_CONFIG,
447                         (ACPI_ADR_SPACE_HANDLER)aml_vm_space_handler_pci_config,
448                         NULL, NULL)) != AE_OK) {
449                 fprintf(stderr, "could not initialise PciConfig handler: %d\n", error);
450                 return (-1);
451         }
452         if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
453                         ACPI_ADR_SPACE_EC,
454                         (ACPI_ADR_SPACE_HANDLER)aml_vm_space_handler_ec,
455                         NULL, NULL)) != AE_OK) {
456                 fprintf(stderr, "could not initialise EC handler: %d\n", error);
457                 return (-1);
458         }
459         if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
460                         ACPI_ADR_SPACE_SMBUS,
461                         (ACPI_ADR_SPACE_HANDLER)aml_vm_space_handler_smbus,
462                         NULL, NULL)) != AE_OK) {
463                 fprintf(stderr, "could not initialise SMBUS handler: %d\n", error);
464                 return (-1);
465         }
466         if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
467                         ACPI_ADR_SPACE_CMOS,
468                         (ACPI_ADR_SPACE_HANDLER)aml_vm_space_handler_cmos,
469                         NULL, NULL)) != AE_OK) {
470                 fprintf(stderr, "could not initialise CMOS handler: %d\n", error);
471                 return (-1);
472         }
473         if ((error = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
474                         ACPI_ADR_SPACE_PCI_BAR_TARGET,
475                         (ACPI_ADR_SPACE_HANDLER)aml_vm_space_handler_pci_bar_target,
476                         NULL, NULL)) != AE_OK) {
477                 fprintf(stderr, "could not initialise PCI BAR TARGET handler: %d\n", error);
478                 return (-1);
479         }
480
481         AcpiDbGetTableFromFile(filetmp, NULL, TRUE);
482
483         AcpiDbInitialize();
484         AcpiGbl_DebuggerConfiguration = 0;
485         AcpiDbUserCommands(':', NULL);
486
487         if (strcmp(dsdtfile, filetmp) != 0) {
488                 unlink(filetmp);
489         }
490
491         return (0);
492 }
493
494 static void
495 usage(const char *progname)
496 {
497
498         printf("usage: %s dsdt_file\n", progname);
499         exit(1);
500 }
501
502 int
503 main(int argc, char *argv[])
504 {
505         char    *progname;
506
507         progname = argv[0];
508
509         if (argc == 1) {
510                 usage(progname);
511         }
512
513         AcpiDbgLevel = ACPI_DEBUG_DEFAULT;
514
515         /*
516          * Match kernel options for the interpreter.  Global variable names
517          * can be found in acglobal.h.
518          */
519         AcpiGbl_EnableInterpreterSlack = TRUE;
520
521         aml_simulation_regload("region.ini");
522         if (load_dsdt(argv[1]) == 0) {
523                 aml_simulation_regdump("region.dmp");
524         }
525
526         return (0);
527 }