forked from pciutils/pciutils
-
Notifications
You must be signed in to change notification settings - Fork 13
/
pciheader.c
280 lines (250 loc) · 7.88 KB
/
pciheader.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
/*
* pciheader -- Prints the header of a PCI(e) device
*
* Written by Johannes 4Linux and put to public domain. You can do
* with it anything you want, but I don't give you any warranty.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lib/pci.h"
/** struct to represent a bitfield in the PCI configuration space */
struct config_space_bitfield {
char name[64];
unsigned int offset;
unsigned int size;
};
/* Prototypes */
void print_pci_header(struct pci_dev *pdev);
struct pci_dev * search_device(struct pci_access *pacc, u8 bus, u8 slot, u8 func);
void int_2_hexstr(u32 value, unsigned int size, char *destination);
int convert_hexstring(char *hexstring);
/** PCI Type 0 Header for Endpoints */
struct config_space_bitfield type_0_header[] = {
{"Vendor ID", 0x0, 2},
{"Device ID", 0x2, 2},
{"Command", 0x4, 2},
{"Status", 0x6, 2},
{"Revision ID", 0x8, 1},
{"Class Code", 0xA, 3},
{"Cache Line S", 0xC, 1},
{"Lat. Timer", 0xD, 1},
{"Header Type", 0xE, 1},
{"BIST", 0xF, 1},
{"BAR 0", 0x10, 4},
{"BAR 1", 0x14, 4},
{"BAR 2", 0x18, 4},
{"BAR 3", 0x1C, 4},
{"BAR 4", 0x20, 4},
{"BAR 5", 0x24, 4},
{"Cardbus CIS Pointer", 0x28, 4},
{"Subsystem Vendor ID", 0x2C, 2},
{"Subsystem ID", 0x2E, 2},
{"Expansion ROM Address", 0x30, 4},
{"Cap. Pointer", 0x34, 1},
{"Reserved", 0x35, 3},
{"Reserved", 0x38, 4},
{"IRQ", 0x3C, 1},
{"IRQ Pin", 0x3D, 1},
{"Min Gnt.", 0x3E, 1},
{"Max Lat.", 0x3F, 1},
{"End", 0x40, 5},
};
/** PCI Type 0 Header for Endpoints */
struct config_space_bitfield type_1_header[] = {
{"Vendor ID", 0x0, 2},
{"Device ID", 0x2, 2},
{"Command", 0x4, 2},
{"Status", 0x6, 2},
{"Revision ID", 0x8, 1},
{"Class Code", 0xA, 3},
{"Cache Line S", 0xC, 1},
{"Lat. Timer", 0xD, 1},
{"Header Type", 0xE, 1},
{"BIST", 0xF, 1},
{"BAR 0", 0x10, 4},
{"BAR 1", 0x14, 4},
{"Primary Bus", 0x18, 1},
{"Secondary Bus", 0x19, 1},
{"Sub. Bus", 0x1A, 1},
{"Sec Lat timer", 0x1B, 1},
{"IO Base", 0x1C, 1},
{"IO Limit", 0x1D, 1},
{"Sec. Status", 0x1E, 2},
{"Memory Limit", 0x20, 2},
{"Memory Base", 0x22, 2},
{"Pref. Memory Limit", 0x24, 2},
{"Pref. Memory Base", 0x26, 2},
{"Pref. Memory Base U", 0x28, 4},
{"Pref. Memory Base L", 0x2C, 4},
{"IO Base Upper", 0x30, 2},
{"IO Limit Upper", 0x32, 2},
{"Cap. Pointer", 0x34, 1},
{"Reserved", 0x35, 3},
{"Exp. ROM Base Addr", 0x38, 4},
{"IRQ Line", 0x3C, 1},
{"IRQ Pin", 0x3D, 1},
{"Min Gnt.", 0x3E, 1},
{"Max Lat.", 0x3F, 1},
{"End", 0x40, 5},
};
/** Variable contain two possible header types */
struct config_space_bitfield *types[2] = {&type_0_header[0], &type_1_header[0]};
/**
* @brief prints the PCI config header of a given device
*
* @param device to print its header
*/
void print_pci_header(struct pci_dev *pdev) {
u8 header_type = 0;
u32 value, bf_value;
u64 mask;
unsigned int i, space_available, padding, bitfield = 0, bf2;
int j;
struct config_space_bitfield *ptr;
char str_value[16];
const char *ctypes[] = {"n Endpoint", " Bridge"};
/* Check if device is valid */
if(pdev == NULL)
return;
/* Check if device is bridge or EP */
header_type = pci_read_byte(pdev, PCI_HEADER_TYPE) & 0x1;
ptr = types[header_type];
printf("Selected device %x:%x:%x is a%s\n", pdev->bus, pdev->dev, pdev->func, ctypes[header_type]);
/* Read config space and dump it to console */
printf("| Byte 0 | Byte 1 | Byte 2 | Byte 3 |\t\t| Byte 0 | Byte 1 | Byte 2 | Byte 3 |\n");
printf("|-----------------------------------------------------------|\t\t|-----------------------------------------------------------|\tAddress\n");
for(i=0; i<0x40; i+=4){
bf2 = bitfield;
/* Print defintion of PCI header line */
putchar('|');
while(ptr[bitfield].offset < i+4){
space_available = 14 * ptr[bitfield].size + (ptr[bitfield].size -1);
padding = (space_available - strlen(ptr[bitfield].name)) / 2;
for(j=0; j<(int) padding; j++)
putchar(' ');
printf("%s", ptr[bitfield].name);
for(j=(int) padding + strlen(ptr[bitfield].name); j<(int) space_available; j++)
putchar(' ');
putchar('|');
bitfield++;
}
/* Read Value */
value = pci_read_long(pdev, i);
/* Print Values of PCI header line */
bitfield = bf2;
printf("\t\t|");
while(ptr[bitfield].offset < i+4){
if(ptr[bitfield].size == 5)
break;
/* Extracting Bitfield of interest */
mask = ((1L<<(ptr[bitfield].size * 8))-1) << (8*(ptr[bitfield].offset - i));
bf_value = (value & mask) >> (8*(ptr[bitfield].offset - i));
/* Print Bitfield and table */
space_available = 14 * ptr[bitfield].size + ptr[bitfield].size -1;
padding = (space_available - ( 2 + ptr[bitfield].size)) / 2;
for(j=0; j<(int) padding; j++)
putchar(' ');
int_2_hexstr(bf_value, ptr[bitfield].size, str_value);
printf("%s", str_value);
for(j=(int) padding+strlen(str_value); j<(int) space_available; j++)
putchar(' ');
putchar('|');
bitfield++;
}
printf("\t0x%02x", i);
printf("\n|-----------------------------------------------------------|\t\t|-----------------------------------------------------------|\n");
}
}
/**
* @brief searches for a device with a given Bus-, Slot- and Functionnumber
*
* @param pacc: PCI Access
* @param bus: Busnumber
* @param slot: Slotnumber
* @param func: Functionnumber
*
* @return NULL: No device found
* pointer to device
*/
struct pci_dev * search_device(struct pci_access *pacc, u8 bus, u8 slot, u8 func) {
struct pci_dev *dev;
for(dev = pacc->devices; dev != NULL; dev = dev->next){
if((dev-> bus == bus) &&
(dev->dev == slot) &&
(dev->func == func))
return dev;
}
return NULL;
}
/**
* @brief converts an integer value to a string
*
* @param value: int value to convert
* @param size: length of value in bytes
* @param destination: destination string
*/
void int_2_hexstr(u32 value, unsigned int size, char *destination) {
const char letters[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
unsigned int i;
/* Init string */
strcpy(destination, "0x");
for(i=0; i<size; i++)
strcat(destination, "00");
i=2+2*size - 1;
/* Copy value in string */
while((value > 0) && (i>1)){
destination[i] = letters[(value & 0xf)];
value = value >> 4;
i--;
}
}
/**
* @brief converts a hexadecimal string to an integer
*
* @param hexstring: String to convert
*
* @return: converted hexstring as integer
*/
int convert_hexstring(char *hexstring) {
int number;
if(strstr(hexstring, "0x") == NULL)
number = (int) strtol(hexstring, NULL, 16);
else
number = (int) strtol(hexstring, NULL, 0);
return number;
}
int main(int argc, char *argv[])
{
struct pci_access *pacc;
struct pci_dev *dev;
u8 bus, slot, func;
/* Check arguments */
if(argc != 4){
printf("Three Arguments must be passed!\n");
printf("Usage: %s [bus] [device] [function]\n", argv[0]);
printf("With:\n");
printf("\tbus:\tBusnumber of device to print PCI Header\n");
printf("\tdevice:\tDevicenumber of device to print PCI Header\n");
printf("\tbus:\tFunctionnumber of device to print PCI Header\n");
return -1;
}
pacc = pci_alloc(); /* Get the pci_access structure */
/* Set all options you want -- here we stick with the defaults */
pci_init(pacc); /* Initialize the PCI library */
pci_scan_bus(pacc); /* We want to get the list of devices */
/* Get numbers */
bus = convert_hexstring(argv[1]);
slot = convert_hexstring(argv[2]);
func = convert_hexstring(argv[3]);
/* Check if device with the passed numbers exist */
dev = search_device(pacc, bus, slot, func);
if(dev == NULL) {
printf("No device found with %x:%x:%x\n", bus, slot, func);
return -1;
}
/* If device exists, print header */
print_pci_header(dev);
pci_cleanup(pacc); /* Close everything */
return 0;
}