1 /*
2  * Copyright (c) 2009 Corey Tabaka
3  *
4  * Use of this source code is governed by a MIT-style
5  * license that can be found in the LICENSE file or at
6  * https://opensource.org/licenses/MIT
7  */
8 #include <app.h>
9 #include <lk/debug.h>
10 #include <stdint.h>
11 #include <string.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <lk/compiler.h>
15 #include <platform.h>
16 #include <dev/bus/pci.h>
17 #include <lk/console_cmd.h>
18 
19 /*
20  * enumerates pci devices
21  */
pci_list(void)22 static void pci_list(void) {
23     pci_location_t state;
24     uint16_t device_id, vendor_id;
25     uint8_t header_type;
26     uint8_t base_class, sub_class, interface;
27     int busses = 0, devices = 0, lines = 0, devfn, ret;
28     int c;
29 
30     printf("Scanning...\n");
31 
32     for (int bus = 0; bus <= (int)pci_get_last_bus(); bus++) {
33         busses++;
34 
35         state.bus = bus;
36 
37         for (devfn = 0; devfn < 256; devfn++) {
38             state.dev_fn = devfn;
39 
40             ret = pci_read_config_half(&state, PCI_CONFIG_VENDOR_ID, &vendor_id);
41             if (ret != _PCI_SUCCESSFUL) goto error;
42 
43             ret = pci_read_config_half(&state, PCI_CONFIG_DEVICE_ID, &device_id);
44             if (ret != _PCI_SUCCESSFUL) goto error;
45 
46             ret = pci_read_config_byte(&state, PCI_CONFIG_HEADER_TYPE, &header_type);
47             if (ret != _PCI_SUCCESSFUL) goto error;
48 
49             ret = pci_read_config_byte(&state, PCI_CONFIG_CLASS_CODE_BASE, &base_class);
50             if (ret != _PCI_SUCCESSFUL) goto error;
51 
52             ret = pci_read_config_byte(&state, PCI_CONFIG_CLASS_CODE_SUB, &sub_class);
53             if (ret != _PCI_SUCCESSFUL) goto error;
54 
55             ret = pci_read_config_byte(&state, PCI_CONFIG_CLASS_CODE_INTR, &interface);
56             if (ret != _PCI_SUCCESSFUL) goto error;
57 
58             if (vendor_id != 0xffff) {
59                 printf("%02x:%02x.%0x vendor_id=%04x device_id=%04x, header_type=%02x "
60                        "base_class=%02x, sub_class=%02x, interface=%02x\n",
61                        state.bus, state.dev_fn >> 3, state.dev_fn & 7,
62                        vendor_id, device_id, header_type, base_class, sub_class, interface);
63                 devices++;
64                 lines++;
65             }
66 
67             if (((devfn & 7) == 0) && ~header_type & PCI_HEADER_TYPE_MULTI_FN) {
68                 // this is not a multi-function device, so advance to the next device
69                 // only check when looking at function 0 of a device
70                 devfn |= 7;
71             }
72 
73             if (lines == 23) {
74                 printf("... press any key to continue, q to quit ...");
75                 while ((c = getchar()) < 0);
76                 printf("\n");
77                 lines = 0;
78 
79                 if (c == 'q' || c == 'Q') goto quit;
80             }
81         }
82     }
83 
84     printf("... done. Scanned %d busses, %d device/functions\n", busses, devices);
85 quit:
86     return;
87 
88 error:
89     printf("Error while reading PCI config space: %02x\n", ret);
90 }
91 
92 /*
93  * a somewhat fugly pci config space examine/modify command. this should probably
94  * be broken up a bit.
95  */
pci_config(int argc,const console_cmd_args * argv)96 static int pci_config(int argc, const console_cmd_args *argv) {
97     pci_location_t loc;
98     pci_config_t config;
99     uint32_t offset;
100     unsigned int i;
101     int ret;
102 
103     if (argc < 5) {
104         return -1;
105     }
106 
107     if (!strcmp(argv[2].str, "dump")) {
108         loc.bus = atoui(argv[3].str);
109         loc.dev_fn = atoui(argv[4].str);
110 
111         for (i=0; i < sizeof(pci_config_t); i++) {
112             ret = pci_read_config_byte(&loc, i, (uint8_t *) &config + i);
113             if (ret != _PCI_SUCCESSFUL) goto error;
114         }
115 
116         printf("Device at %02x:%02x.%1x vendor id=%04x device id=%04x\n", loc.bus,
117                loc.dev_fn >> 3, loc.dev_fn & 7, config.vendor_id, config.device_id);
118         printf("command=%04x status=%04x pi=%02x sub cls=%02x base cls=%02x\n",
119                config.command, config.status, config.program_interface,
120                config.sub_class, config.base_class);
121 
122         for (i=0; i < 6; i+=2) {
123             printf("bar%d=%08x  bar%d=%08x\n", i, config.base_addresses[i],
124                    i+1, config.base_addresses[i+1]);
125         }
126     } else if (!strcmp(argv[2].str, "rb") || !strcmp(argv[2].str, "rh") || !strcmp(argv[2].str, "rw")) {
127         if (argc != 6) {
128             return -1;
129         }
130 
131         loc.bus = atoui(argv[3].str);
132         loc.dev_fn = atoui(argv[4].str);
133         offset = atoui(argv[5].str);
134 
135         switch (argv[2].str[1]) {
136             case 'b': {
137                 uint8_t value;
138                 ret = pci_read_config_byte(&loc, offset, &value);
139                 if (ret != _PCI_SUCCESSFUL) goto error;
140 
141                 printf("byte at device %02x:%02x config offset %04x: %02x\n", loc.bus, loc.dev_fn, offset, value);
142             }
143             break;
144 
145             case 'h': {
146                 uint16_t value;
147                 ret = pci_read_config_half(&loc, offset, &value);
148                 if (ret != _PCI_SUCCESSFUL) goto error;
149 
150                 printf("half at device %02x:%02x config offset %04x: %04x\n", loc.bus, loc.dev_fn, offset, value);
151             }
152             break;
153 
154             case 'w': {
155                 uint32_t value;
156                 ret = pci_read_config_word(&loc, offset, &value);
157                 if (ret != _PCI_SUCCESSFUL) goto error;
158 
159                 printf("word at device %02x:%02x config offset %04x: %08x\n", loc.bus, loc.dev_fn, offset, value);
160             }
161             break;
162         }
163     } else if (!strcmp(argv[2].str, "mb") || !strcmp(argv[2].str, "mh") || !strcmp(argv[2].str, "mw")) {
164         if (argc != 7) {
165             return -1;
166         }
167 
168         loc.bus = atoui(argv[3].str);
169         loc.dev_fn = atoui(argv[4].str);
170         offset = atoui(argv[5].str);
171 
172         switch (argv[2].str[1]) {
173             case 'b': {
174                 uint8_t value = atoui(argv[6].str);
175                 ret = pci_write_config_byte(&loc, offset, value);
176                 if (ret != _PCI_SUCCESSFUL) goto error;
177 
178                 printf("byte to device %02x:%02x config offset %04x: %02x\n", loc.bus, loc.dev_fn, offset, value);
179             }
180             break;
181 
182             case 'h': {
183                 uint16_t value = atoui(argv[6].str);
184                 ret = pci_write_config_half(&loc, offset, value);
185                 if (ret != _PCI_SUCCESSFUL) goto error;
186 
187                 printf("half to device %02x:%02x config offset %04x: %04x\n", loc.bus, loc.dev_fn, offset, value);
188             }
189             break;
190 
191             case 'w': {
192                 uint32_t value = atoui(argv[6].str);
193                 ret = pci_write_config_word(&loc, offset, value);
194                 if (ret != _PCI_SUCCESSFUL) goto error;
195 
196                 printf("word to device %02x:%02x config offset %04x: %08x\n", loc.bus, loc.dev_fn, offset, value);
197             }
198             break;
199         }
200     } else {
201         return -1;
202     }
203 
204     return 0;
205 
206 error:
207     printf("Error while reading PCI config space: %02x\n", ret);
208     return -2;
209 }
210 
pci_cmd(int argc,const console_cmd_args * argv)211 static int pci_cmd(int argc, const console_cmd_args *argv) {
212     if (argc < 2) {
213         printf("pci commands:\n");
214 usage:
215         printf("%s list\n", argv[0].str);
216         printf("%s config dump <bus> <devfn>\n", argv[0].str);
217         printf("%s config <rb|rh|rw> <bus> <devfn> <offset>\n", argv[0].str);
218         printf("%s config <mb|mh|mw> <bus> <devfn> <offset> <value>\n", argv[0].str);
219         goto out;
220     }
221 
222     if (!strcmp(argv[1].str, "list")) {
223         pci_list();
224     } else if (!strcmp(argv[1].str, "config")) {
225         if (pci_config(argc, argv)) {
226             goto usage;
227         }
228     } else {
229         goto usage;
230     }
231 
232 out:
233     return 0;
234 }
235 
236 STATIC_COMMAND_START
237 STATIC_COMMAND("pci", "pci toolbox", &pci_cmd)
238 STATIC_COMMAND_END(pcitests);
239 
240