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