xref: /aosp_15_r20/external/pciutils/lib/dump.c (revision c2e0c6b56a71da9abe8df5c8348fb3eb5c2c9251)
1*c2e0c6b5SAndroid Build Coastguard Worker /*
2*c2e0c6b5SAndroid Build Coastguard Worker  *	The PCI Library -- Reading of Bus Dumps
3*c2e0c6b5SAndroid Build Coastguard Worker  *
4*c2e0c6b5SAndroid Build Coastguard Worker  *	Copyright (c) 1997--2008 Martin Mares <[email protected]>
5*c2e0c6b5SAndroid Build Coastguard Worker  *
6*c2e0c6b5SAndroid Build Coastguard Worker  *	Can be freely distributed and used under the terms of the GNU GPL v2+.
7*c2e0c6b5SAndroid Build Coastguard Worker  *
8*c2e0c6b5SAndroid Build Coastguard Worker  *	SPDX-License-Identifier: GPL-2.0-or-later
9*c2e0c6b5SAndroid Build Coastguard Worker  */
10*c2e0c6b5SAndroid Build Coastguard Worker 
11*c2e0c6b5SAndroid Build Coastguard Worker #include <stdio.h>
12*c2e0c6b5SAndroid Build Coastguard Worker #include <ctype.h>
13*c2e0c6b5SAndroid Build Coastguard Worker #include <string.h>
14*c2e0c6b5SAndroid Build Coastguard Worker #include <errno.h>
15*c2e0c6b5SAndroid Build Coastguard Worker 
16*c2e0c6b5SAndroid Build Coastguard Worker #include "internal.h"
17*c2e0c6b5SAndroid Build Coastguard Worker 
18*c2e0c6b5SAndroid Build Coastguard Worker struct dump_data {
19*c2e0c6b5SAndroid Build Coastguard Worker   int len, allocated;
20*c2e0c6b5SAndroid Build Coastguard Worker   byte data[1];
21*c2e0c6b5SAndroid Build Coastguard Worker };
22*c2e0c6b5SAndroid Build Coastguard Worker 
23*c2e0c6b5SAndroid Build Coastguard Worker static void
dump_config(struct pci_access * a)24*c2e0c6b5SAndroid Build Coastguard Worker dump_config(struct pci_access *a)
25*c2e0c6b5SAndroid Build Coastguard Worker {
26*c2e0c6b5SAndroid Build Coastguard Worker   pci_define_param(a, "dump.name", "", "Name of the bus dump file to read from");
27*c2e0c6b5SAndroid Build Coastguard Worker }
28*c2e0c6b5SAndroid Build Coastguard Worker 
29*c2e0c6b5SAndroid Build Coastguard Worker static int
dump_detect(struct pci_access * a)30*c2e0c6b5SAndroid Build Coastguard Worker dump_detect(struct pci_access *a)
31*c2e0c6b5SAndroid Build Coastguard Worker {
32*c2e0c6b5SAndroid Build Coastguard Worker   char *name = pci_get_param(a, "dump.name");
33*c2e0c6b5SAndroid Build Coastguard Worker   return name && name[0];
34*c2e0c6b5SAndroid Build Coastguard Worker }
35*c2e0c6b5SAndroid Build Coastguard Worker 
36*c2e0c6b5SAndroid Build Coastguard Worker static void
dump_alloc_data(struct pci_dev * dev,int len)37*c2e0c6b5SAndroid Build Coastguard Worker dump_alloc_data(struct pci_dev *dev, int len)
38*c2e0c6b5SAndroid Build Coastguard Worker {
39*c2e0c6b5SAndroid Build Coastguard Worker   struct dump_data *dd = pci_malloc(dev->access, sizeof(struct dump_data) + len - 1);
40*c2e0c6b5SAndroid Build Coastguard Worker   dd->allocated = len;
41*c2e0c6b5SAndroid Build Coastguard Worker   dd->len = 0;
42*c2e0c6b5SAndroid Build Coastguard Worker   memset(dd->data, 0xff, len);
43*c2e0c6b5SAndroid Build Coastguard Worker   dev->backend_data = dd;
44*c2e0c6b5SAndroid Build Coastguard Worker }
45*c2e0c6b5SAndroid Build Coastguard Worker 
46*c2e0c6b5SAndroid Build Coastguard Worker static int
dump_validate(char * s,char * fmt)47*c2e0c6b5SAndroid Build Coastguard Worker dump_validate(char *s, char *fmt)
48*c2e0c6b5SAndroid Build Coastguard Worker {
49*c2e0c6b5SAndroid Build Coastguard Worker   while (*fmt)
50*c2e0c6b5SAndroid Build Coastguard Worker     {
51*c2e0c6b5SAndroid Build Coastguard Worker       if (*fmt == '#' ? !isxdigit(*s) : *fmt != *s)
52*c2e0c6b5SAndroid Build Coastguard Worker 	return 0;
53*c2e0c6b5SAndroid Build Coastguard Worker       fmt++, s++;
54*c2e0c6b5SAndroid Build Coastguard Worker     }
55*c2e0c6b5SAndroid Build Coastguard Worker   return 1;
56*c2e0c6b5SAndroid Build Coastguard Worker }
57*c2e0c6b5SAndroid Build Coastguard Worker 
58*c2e0c6b5SAndroid Build Coastguard Worker static void
dump_init(struct pci_access * a)59*c2e0c6b5SAndroid Build Coastguard Worker dump_init(struct pci_access *a)
60*c2e0c6b5SAndroid Build Coastguard Worker {
61*c2e0c6b5SAndroid Build Coastguard Worker   char *name = pci_get_param(a, "dump.name");
62*c2e0c6b5SAndroid Build Coastguard Worker   FILE *f;
63*c2e0c6b5SAndroid Build Coastguard Worker   char buf[256];
64*c2e0c6b5SAndroid Build Coastguard Worker   struct pci_dev *dev = NULL;
65*c2e0c6b5SAndroid Build Coastguard Worker   int len, mn, bn, dn, fn, i, j;
66*c2e0c6b5SAndroid Build Coastguard Worker 
67*c2e0c6b5SAndroid Build Coastguard Worker   if (!name)
68*c2e0c6b5SAndroid Build Coastguard Worker     a->error("dump: File name not given.");
69*c2e0c6b5SAndroid Build Coastguard Worker   if (!(f = fopen(name, "r")))
70*c2e0c6b5SAndroid Build Coastguard Worker     a->error("dump: Cannot open %s: %s", name, strerror(errno));
71*c2e0c6b5SAndroid Build Coastguard Worker   while (fgets(buf, sizeof(buf)-1, f))
72*c2e0c6b5SAndroid Build Coastguard Worker     {
73*c2e0c6b5SAndroid Build Coastguard Worker       char *z = strchr(buf, '\n');
74*c2e0c6b5SAndroid Build Coastguard Worker       if (!z)
75*c2e0c6b5SAndroid Build Coastguard Worker 	{
76*c2e0c6b5SAndroid Build Coastguard Worker 	  fclose(f);
77*c2e0c6b5SAndroid Build Coastguard Worker 	  a->error("dump: line too long or unterminated");
78*c2e0c6b5SAndroid Build Coastguard Worker 	}
79*c2e0c6b5SAndroid Build Coastguard Worker       *z-- = 0;
80*c2e0c6b5SAndroid Build Coastguard Worker       if (z >= buf && *z == '\r')
81*c2e0c6b5SAndroid Build Coastguard Worker 	*z-- = 0;
82*c2e0c6b5SAndroid Build Coastguard Worker       len = z - buf + 1;
83*c2e0c6b5SAndroid Build Coastguard Worker       mn = 0;
84*c2e0c6b5SAndroid Build Coastguard Worker       if (dump_validate(buf, "##:##.# ") && sscanf(buf, "%x:%x.%d", &bn, &dn, &fn) == 3 ||
85*c2e0c6b5SAndroid Build Coastguard Worker 	  dump_validate(buf, "####:##:##.# ") && sscanf(buf, "%x:%x:%x.%d", &mn, &bn, &dn, &fn) == 4 ||
86*c2e0c6b5SAndroid Build Coastguard Worker 	  dump_validate(buf, "#####:##:##.# ") && sscanf(buf, "%x:%x:%x.%d", &mn, &bn, &dn, &fn) == 4 ||
87*c2e0c6b5SAndroid Build Coastguard Worker 	  dump_validate(buf, "######:##:##.# ") && sscanf(buf, "%x:%x:%x.%d", &mn, &bn, &dn, &fn) == 4)
88*c2e0c6b5SAndroid Build Coastguard Worker 	{
89*c2e0c6b5SAndroid Build Coastguard Worker 	  dev = pci_get_dev(a, mn, bn, dn, fn);
90*c2e0c6b5SAndroid Build Coastguard Worker 	  dump_alloc_data(dev, 256);
91*c2e0c6b5SAndroid Build Coastguard Worker 	  pci_link_dev(a, dev);
92*c2e0c6b5SAndroid Build Coastguard Worker 	}
93*c2e0c6b5SAndroid Build Coastguard Worker       else if (!len)
94*c2e0c6b5SAndroid Build Coastguard Worker 	dev = NULL;
95*c2e0c6b5SAndroid Build Coastguard Worker       else if (dev &&
96*c2e0c6b5SAndroid Build Coastguard Worker 	       (dump_validate(buf, "##: ") || dump_validate(buf, "###: ") || dump_validate(buf, "####: ") ||
97*c2e0c6b5SAndroid Build Coastguard Worker 		dump_validate(buf, "#####: ") || dump_validate(buf, "######: ") ||
98*c2e0c6b5SAndroid Build Coastguard Worker 		dump_validate(buf, "#######: ") || dump_validate(buf, "########: ")) &&
99*c2e0c6b5SAndroid Build Coastguard Worker 	       sscanf(buf, "%x: ", &i) == 1)
100*c2e0c6b5SAndroid Build Coastguard Worker 	{
101*c2e0c6b5SAndroid Build Coastguard Worker 	  struct dump_data *dd = dev->backend_data;
102*c2e0c6b5SAndroid Build Coastguard Worker 	  z = strchr(buf, ' ') + 1;
103*c2e0c6b5SAndroid Build Coastguard Worker 	  while (isxdigit(z[0]) && isxdigit(z[1]) && (!z[2] || z[2] == ' ') &&
104*c2e0c6b5SAndroid Build Coastguard Worker 		 sscanf(z, "%x", &j) == 1 && j < 256)
105*c2e0c6b5SAndroid Build Coastguard Worker 	    {
106*c2e0c6b5SAndroid Build Coastguard Worker 	      if (i >= 4096)
107*c2e0c6b5SAndroid Build Coastguard Worker 		{
108*c2e0c6b5SAndroid Build Coastguard Worker 		  fclose(f);
109*c2e0c6b5SAndroid Build Coastguard Worker 		  a->error("dump: At most 4096 bytes of config space are supported");
110*c2e0c6b5SAndroid Build Coastguard Worker 		}
111*c2e0c6b5SAndroid Build Coastguard Worker 	      if (i >= dd->allocated)	/* Need to re-allocate the buffer */
112*c2e0c6b5SAndroid Build Coastguard Worker 		{
113*c2e0c6b5SAndroid Build Coastguard Worker 		  dump_alloc_data(dev, 4096);
114*c2e0c6b5SAndroid Build Coastguard Worker 		  memcpy(((struct dump_data *) dev->backend_data)->data, dd->data, 256);
115*c2e0c6b5SAndroid Build Coastguard Worker 		  pci_mfree(dd);
116*c2e0c6b5SAndroid Build Coastguard Worker 		  dd = dev->backend_data;
117*c2e0c6b5SAndroid Build Coastguard Worker 		}
118*c2e0c6b5SAndroid Build Coastguard Worker 	      dd->data[i++] = j;
119*c2e0c6b5SAndroid Build Coastguard Worker 	      if (i > dd->len)
120*c2e0c6b5SAndroid Build Coastguard Worker 		dd->len = i;
121*c2e0c6b5SAndroid Build Coastguard Worker 	      z += 2;
122*c2e0c6b5SAndroid Build Coastguard Worker 	      if (*z)
123*c2e0c6b5SAndroid Build Coastguard Worker 		z++;
124*c2e0c6b5SAndroid Build Coastguard Worker 	    }
125*c2e0c6b5SAndroid Build Coastguard Worker 	  if (*z)
126*c2e0c6b5SAndroid Build Coastguard Worker 	    {
127*c2e0c6b5SAndroid Build Coastguard Worker 	      fclose(f);
128*c2e0c6b5SAndroid Build Coastguard Worker 	      a->error("dump: Malformed line");
129*c2e0c6b5SAndroid Build Coastguard Worker 	    }
130*c2e0c6b5SAndroid Build Coastguard Worker 	}
131*c2e0c6b5SAndroid Build Coastguard Worker     }
132*c2e0c6b5SAndroid Build Coastguard Worker   fclose(f);
133*c2e0c6b5SAndroid Build Coastguard Worker }
134*c2e0c6b5SAndroid Build Coastguard Worker 
135*c2e0c6b5SAndroid Build Coastguard Worker static void
dump_cleanup(struct pci_access * a UNUSED)136*c2e0c6b5SAndroid Build Coastguard Worker dump_cleanup(struct pci_access *a UNUSED)
137*c2e0c6b5SAndroid Build Coastguard Worker {
138*c2e0c6b5SAndroid Build Coastguard Worker }
139*c2e0c6b5SAndroid Build Coastguard Worker 
140*c2e0c6b5SAndroid Build Coastguard Worker static void
dump_scan(struct pci_access * a UNUSED)141*c2e0c6b5SAndroid Build Coastguard Worker dump_scan(struct pci_access *a UNUSED)
142*c2e0c6b5SAndroid Build Coastguard Worker {
143*c2e0c6b5SAndroid Build Coastguard Worker }
144*c2e0c6b5SAndroid Build Coastguard Worker 
145*c2e0c6b5SAndroid Build Coastguard Worker static int
dump_read(struct pci_dev * d,int pos,byte * buf,int len)146*c2e0c6b5SAndroid Build Coastguard Worker dump_read(struct pci_dev *d, int pos, byte *buf, int len)
147*c2e0c6b5SAndroid Build Coastguard Worker {
148*c2e0c6b5SAndroid Build Coastguard Worker   struct dump_data *dd;
149*c2e0c6b5SAndroid Build Coastguard Worker   if (!(dd = d->backend_data))
150*c2e0c6b5SAndroid Build Coastguard Worker     {
151*c2e0c6b5SAndroid Build Coastguard Worker       struct pci_dev *e = d->access->devices;
152*c2e0c6b5SAndroid Build Coastguard Worker       while (e && (e->domain != d->domain || e->bus != d->bus || e->dev != d->dev || e->func != d->func))
153*c2e0c6b5SAndroid Build Coastguard Worker 	e = e->next;
154*c2e0c6b5SAndroid Build Coastguard Worker       if (!e)
155*c2e0c6b5SAndroid Build Coastguard Worker 	return 0;
156*c2e0c6b5SAndroid Build Coastguard Worker       dd = e->backend_data;
157*c2e0c6b5SAndroid Build Coastguard Worker     }
158*c2e0c6b5SAndroid Build Coastguard Worker   if (pos + len > dd->len)
159*c2e0c6b5SAndroid Build Coastguard Worker     return 0;
160*c2e0c6b5SAndroid Build Coastguard Worker   memcpy(buf, dd->data + pos, len);
161*c2e0c6b5SAndroid Build Coastguard Worker   return 1;
162*c2e0c6b5SAndroid Build Coastguard Worker }
163*c2e0c6b5SAndroid Build Coastguard Worker 
164*c2e0c6b5SAndroid Build Coastguard Worker static int
dump_write(struct pci_dev * d UNUSED,int pos UNUSED,byte * buf UNUSED,int len UNUSED)165*c2e0c6b5SAndroid Build Coastguard Worker dump_write(struct pci_dev *d UNUSED, int pos UNUSED, byte *buf UNUSED, int len UNUSED)
166*c2e0c6b5SAndroid Build Coastguard Worker {
167*c2e0c6b5SAndroid Build Coastguard Worker   d->access->error("Writing to dump files is not supported.");
168*c2e0c6b5SAndroid Build Coastguard Worker   return 0;
169*c2e0c6b5SAndroid Build Coastguard Worker }
170*c2e0c6b5SAndroid Build Coastguard Worker 
171*c2e0c6b5SAndroid Build Coastguard Worker static void
dump_cleanup_dev(struct pci_dev * d)172*c2e0c6b5SAndroid Build Coastguard Worker dump_cleanup_dev(struct pci_dev *d)
173*c2e0c6b5SAndroid Build Coastguard Worker {
174*c2e0c6b5SAndroid Build Coastguard Worker   if (d->backend_data)
175*c2e0c6b5SAndroid Build Coastguard Worker     {
176*c2e0c6b5SAndroid Build Coastguard Worker       pci_mfree(d->backend_data);
177*c2e0c6b5SAndroid Build Coastguard Worker       d->backend_data = NULL;
178*c2e0c6b5SAndroid Build Coastguard Worker     }
179*c2e0c6b5SAndroid Build Coastguard Worker }
180*c2e0c6b5SAndroid Build Coastguard Worker 
181*c2e0c6b5SAndroid Build Coastguard Worker struct pci_methods pm_dump = {
182*c2e0c6b5SAndroid Build Coastguard Worker   .name = "dump",
183*c2e0c6b5SAndroid Build Coastguard Worker   .help = "Reading of register dumps (set the `dump.name' parameter)",
184*c2e0c6b5SAndroid Build Coastguard Worker   .config = dump_config,
185*c2e0c6b5SAndroid Build Coastguard Worker   .detect = dump_detect,
186*c2e0c6b5SAndroid Build Coastguard Worker   .init = dump_init,
187*c2e0c6b5SAndroid Build Coastguard Worker   .cleanup = dump_cleanup,
188*c2e0c6b5SAndroid Build Coastguard Worker   .scan = dump_scan,
189*c2e0c6b5SAndroid Build Coastguard Worker   .fill_info = pci_generic_fill_info,
190*c2e0c6b5SAndroid Build Coastguard Worker   .read = dump_read,
191*c2e0c6b5SAndroid Build Coastguard Worker   .write = dump_write,
192*c2e0c6b5SAndroid Build Coastguard Worker   .cleanup_dev = dump_cleanup_dev,
193*c2e0c6b5SAndroid Build Coastguard Worker };
194