2 pcboot - bootable PC demo/game kernel
3 Copyright (C) 2018 John Tsiombikas <nuclear@member.fsf.org>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY, without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>.
27 #define CONFIG_ADDR_PORT 0xcf8
28 #define CONFIG_DATA_PORT 0xcfc
30 #define ADDR_ENABLE 0x80000000
31 #define ADDR_BUSID(x) (((uint32_t)(x) & 0xff) << 16)
32 #define ADDR_DEVID(x) (((uint32_t)(x) & 0x1f) << 11)
33 #define ADDR_FUNC(x) (((uint32_t)(x) & 3) << 8)
35 /* signature returned in edx by the PCI BIOS present function: FOURCC "PCI " */
36 #define PCI_SIG 0x20494350
38 #define TYPE_MULTIFUNC 0x80
41 uint16_t vendor, device;
43 uint8_t rev, iface, subclass, class;
44 uint8_t cacheline_size;
45 uint8_t latency_timer;
48 uint32_t base_addr[6];
50 uint16_t subsys_vendor;
53 uint32_t reserved1, reserved2;
54 uint8_t intr_line, intr_pin;
55 uint8_t min_grant, max_latency;
56 } __attribute__((packed));
58 static int enum_bus(int busid);
59 static int enum_dev(int busid, int dev);
60 static int read_dev_info(struct config_data *res, int bus, int dev, int func);
61 static void print_dev_info(struct config_data *info, int bus, int dev, int func);
63 static uint32_t cfg_read32_m1(int bus, int dev, int func, int reg);
64 static uint32_t cfg_read32_m2(int bus, int dev, int func, int reg);
65 static const char *class_str(int cc);
66 static const char *subclass_str(int cc, int sub);
68 static uint32_t (*cfg_read32)(int, int, int, int);
74 struct int86regs regs;
76 intrflag = get_intr_flag();
78 memset(®s, 0, sizeof regs);
82 /* restore interrupt state in case bios changed it */
83 set_intr_flag(intrflag);
85 /* PCI BIOS present if CF=0, AH=0, and EDX has the "PCI " sig FOURCC */
86 if((regs.flags & FLAGS_CARRY) || (regs.eax & 0xff00) || regs.edx != PCI_SIG) {
87 printf("No PCI BIOS present\n");
91 printf("PCI BIOS v%x.%x found\n", (regs.ebx & 0xff00) >> 8, regs.ebx & 0xff);
93 cfg_read32 = cfg_read32_m1;
96 printf("Failed to find supported PCI mess mechanism\n");
99 printf("PCI mess mechanism #1 unsupported, falling back to mechanism #2\n");
100 cfg_read32 = cfg_read32_m2;
103 for(i=0; i<256; i++) {
104 count += enum_bus(i);
106 printf("found %d PCI devices\n\n", count);
109 static int enum_bus(int busid)
113 for(i=0; i<32; i++) {
114 count += enum_dev(busid, i);
120 static int enum_dev(int busid, int dev)
123 struct config_data info;
125 /* vendor id ffff is invalid */
126 if((cfg_read32(busid, dev, 0, 0) & 0xffff) == 0xffff) {
129 if(read_dev_info(&info, busid, dev, 0) == -1) {
132 /*print_dev_info(&info, busid, dev, 0);*/
136 if(info.hdr_type & TYPE_MULTIFUNC) {
138 if(read_dev_info(&info, busid, dev, i) == -1) {
141 /*print_dev_info(&info, busid, dev, i);*/
148 static int read_dev_info(struct config_data *res, int bus, int dev, int func)
151 uint32_t *ptr = (uint32_t*)res;
153 *ptr++ = cfg_read32(bus, dev, func, 0);
154 if(res->vendor == 0xffff) {
158 for(i=1; i<16; i++) {
159 *ptr++ = cfg_read32(bus, dev, func, i * 4);
164 static void print_dev_info(struct config_data *info, int bus, int dev, int func)
166 printf("- (%d:%d,%d) Device %04x:%04x: ", bus, dev, func, info->vendor, info->device);
167 printf("\"%s\" (%d) - %s-func\n", class_str(info->class), info->class,
168 info->hdr_type & TYPE_MULTIFUNC ? "multi" : "single");
169 printf(" subclass: \"%s\" (%d), iface: %d\n", subclass_str(info->class, info->subclass),
170 info->subclass, info->iface);
173 static uint32_t cfg_read32_m1(int bus, int dev, int func, int reg)
175 uint32_t addr = ADDR_ENABLE | ADDR_BUSID(bus) | ADDR_DEVID(dev) |
176 ADDR_FUNC(func) | reg;
178 outl(addr, CONFIG_ADDR_PORT);
179 return inl(CONFIG_DATA_PORT);
182 static uint32_t cfg_read32_m2(int bus, int dev, int func, int reg)
184 panic("BUG: PCI mess mechanism #2 not implemented yet!");
188 static const char *class_names[] = {
190 "mass storage controller",
191 "network controller",
192 "display controller",
196 "simple communication controller",
197 "base system peripheral",
201 "serial bus controller",
202 "wireless controller",
203 "intelligent I/O controller",
204 "satellite communication controller",
205 "encryption/decryption controller",
206 "data acquisition & signal processing controller"
209 static const char *class_mass_names[] = {
210 "SCSI bus controller",
212 "floppy disk controller",
213 "IPI bus controller",
217 static const char *class_net_names[] = {
218 "ethernet controller",
219 "token ring controller",
225 static const char *class_disp_names[] = {
226 "VGA-compatible controller",
231 static const char *class_mm_names[] = {
237 static const char *class_bridge_names[] = {
243 "Subtractive decode PCI-to-PCI bridge",
250 static const char *class_comm_names[] = {
253 "multiport serial controller",
257 static const char *class_base_names[] = {
258 "interrupt controller",
262 "PCI hot-plug controller"
265 static const char *class_input_names[] = {
266 "keyboard controller",
269 "scanner controller",
270 "gameport controller"
273 static const char *class_ser_names[] = {
282 static const char *class_sat_names[] = {
290 static const char *class_str(int cc)
298 return class_names[cc];
301 static const char *subclass_str(int cc, int sub)
303 if(sub == 0x80) return "other";
307 if(sub == 1) return "VGA-compatible device";
311 if(sub > 4) return "unknown";
312 return class_mass_names[sub];
315 if(sub > 4) return "unknown";
316 return class_net_names[sub];
319 if(sub > 2) return "unknown";
320 return class_disp_names[sub];
323 if(sub > 2) return "unknown";
324 return class_mm_names[sub];
327 if(sub == 0) return "RAM";
328 if(sub == 1) return "flash";
332 if(sub > 8) return "unknown";
333 return class_bridge_names[sub];
336 if(sub > 3) return "unknown";
337 return class_comm_names[sub];
340 if(sub > 4) return "unknown";
341 return class_base_names[sub];
344 if(sub > 4) return "unknown";
345 return class_input_names[sub];
348 if(sub == 0) return "generic docking station";
353 case 0: return "386";
354 case 1: return "486";
355 case 2: return "pentium";
356 case 0x10: return "alpha";
357 case 0x20: return "powerpc";
358 case 0x30: return "mips";
359 case 0x40: return "co-processor";
366 if(sub > 5) return "unknown";
367 return class_ser_names[sub];
370 if(sub == 0) return "irda controller";
371 if(sub == 1) return "IR controller";
372 if(sub == 0x10) return "RF controller";
376 if(sub > 4) return "unknown";
377 return class_sat_names[sub];
380 if(sub == 0) return "network & computing crypto";
381 if(sub == 1) return "entertainment crypto";
385 if(sub == 0) return "DPIO module";