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