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/>.
26 #define CONFIG_ADDR_PORT 0xcf8
27 #define CONFIG_DATA_PORT 0xcfc
29 #define ADDR_ENABLE 0x80000000
30 #define ADDR_BUSID(x) (((uint32_t)(x) & 0xff) << 16)
31 #define ADDR_DEVID(x) (((uint32_t)(x) & 0x1f) << 11)
32 #define ADDR_FUNC(x) (((uint32_t)(x) & 3) << 8)
34 /* signature returned in edx by the PCI BIOS present function: FOURCC "PCI " */
35 #define PCI_SIG 0x20494350
37 #define TYPE_MULTIFUNC 0x80
40 uint16_t vendor, device;
42 uint8_t rev, iface, subclass, class;
43 uint8_t cacheline_size;
44 uint8_t latency_timer;
47 uint32_t base_addr[6];
49 uint16_t subsys_vendor;
52 uint32_t reserved1, reserved2;
53 uint8_t intr_line, intr_pin;
54 uint8_t min_grant, max_latency;
55 } __attribute__((packed));
57 static int enum_bus(int busid);
58 static int enum_dev(int busid, int dev);
59 static int read_dev_info(struct config_data *res, int bus, int dev, int func);
60 static void print_dev_info(struct config_data *info, int bus, int dev, int func);
62 static uint32_t cfg_read32_m1(int bus, int dev, int func, int reg);
63 static uint32_t cfg_read32_m2(int bus, int dev, int func, int reg);
64 static const char *class_str(int cc);
65 static const char *subclass_str(int cc, int sub);
67 static uint32_t (*cfg_read32)(int, int, int, int);
72 struct int86regs regs;
74 memset(®s, 0, sizeof regs);
78 /* PCI BIOS present if CF=0, AH=0, and EDX has the "PCI " sig FOURCC */
79 if((regs.flags & FLAGS_CARRY) || (regs.eax & 0xff00) || regs.edx != PCI_SIG) {
80 printf("No PCI BIOS present\n");
84 printf("PCI BIOS v%x.%x found\n", (regs.ebx & 0xff00) >> 8, regs.ebx & 0xff);
86 cfg_read32 = cfg_read32_m1;
89 printf("Failed to find supported PCI mess mechanism\n");
92 printf("PCI mess mechanism #1 unsupported, falling back to mechanism #2\n");
93 cfg_read32 = cfg_read32_m2;
96 for(i=0; i<256; i++) {
99 printf("found %d PCI devices\n", count);
102 static int enum_bus(int busid)
106 for(i=0; i<32; i++) {
107 count += enum_dev(busid, i);
113 static int enum_dev(int busid, int dev)
116 struct config_data info;
118 /* vendor id ffff is invalid */
119 if((cfg_read32(busid, dev, 0, 0) & 0xffff) == 0xffff) {
122 if(read_dev_info(&info, busid, dev, 0) == -1) {
125 print_dev_info(&info, busid, dev, 0);
129 if(info.hdr_type & TYPE_MULTIFUNC) {
131 if(read_dev_info(&info, busid, dev, i) == -1) {
134 print_dev_info(&info, busid, dev, i);
141 static int read_dev_info(struct config_data *res, int bus, int dev, int func)
144 uint32_t *ptr = (uint32_t*)res;
146 *ptr++ = cfg_read32(bus, dev, func, 0);
147 if(res->vendor == 0xffff) {
151 for(i=1; i<16; i++) {
152 *ptr++ = cfg_read32(bus, dev, func, i * 4);
157 static void print_dev_info(struct config_data *info, int bus, int dev, int func)
159 printf("- (%d:%d,%d) Device %04x:%04x: ", bus, dev, func, info->vendor, info->device);
160 printf("\"%s\" (%d) - %s-func\n", class_str(info->class), info->class,
161 info->hdr_type & TYPE_MULTIFUNC ? "multi" : "single");
162 printf(" subclass: \"%s\" (%d), iface: %d\n", subclass_str(info->class, info->subclass),
163 info->subclass, info->iface);
166 static uint32_t cfg_read32_m1(int bus, int dev, int func, int reg)
168 uint32_t addr = ADDR_ENABLE | ADDR_BUSID(bus) | ADDR_DEVID(dev) |
169 ADDR_FUNC(func) | reg;
171 outl(addr, CONFIG_ADDR_PORT);
172 return inl(CONFIG_DATA_PORT);
175 static uint32_t cfg_read32_m2(int bus, int dev, int func, int reg)
177 panic("BUG: PCI mess mechanism #2 not implemented yet!");
181 static const char *class_names[] = {
183 "mass storage controller",
184 "network controller",
185 "display controller",
189 "simple communication controller",
190 "base system peripheral",
194 "serial bus controller",
195 "wireless controller",
196 "intelligent I/O controller",
197 "satellite communication controller",
198 "encryption/decryption controller",
199 "data acquisition & signal processing controller"
202 static const char *class_mass_names[] = {
203 "SCSI bus controller",
205 "floppy disk controller",
206 "IPI bus controller",
210 static const char *class_net_names[] = {
211 "ethernet controller",
212 "token ring controller",
218 static const char *class_disp_names[] = {
219 "VGA-compatible controller",
224 static const char *class_mm_names[] = {
230 static const char *class_bridge_names[] = {
236 "Subtractive decode PCI-to-PCI bridge",
243 static const char *class_comm_names[] = {
246 "multiport serial controller",
250 static const char *class_base_names[] = {
251 "interrupt controller",
255 "PCI hot-plug controller"
258 static const char *class_input_names[] = {
259 "keyboard controller",
262 "scanner controller",
263 "gameport controller"
266 static const char *class_ser_names[] = {
275 static const char *class_sat_names[] = {
283 static const char *class_str(int cc)
291 return class_names[cc];
294 static const char *subclass_str(int cc, int sub)
296 if(sub == 0x80) return "other";
300 if(sub == 1) return "VGA-compatible device";
304 if(sub > 4) return "unknown";
305 return class_mass_names[sub];
308 if(sub > 4) return "unknown";
309 return class_net_names[sub];
312 if(sub > 2) return "unknown";
313 return class_disp_names[sub];
316 if(sub > 2) return "unknown";
317 return class_mm_names[sub];
320 if(sub == 0) return "RAM";
321 if(sub == 1) return "flash";
325 if(sub > 8) return "unknown";
326 return class_bridge_names[sub];
329 if(sub > 3) return "unknown";
330 return class_comm_names[sub];
333 if(sub > 4) return "unknown";
334 return class_base_names[sub];
337 if(sub > 4) return "unknown";
338 return class_input_names[sub];
341 if(sub == 0) return "generic docking station";
346 case 0: return "386";
347 case 1: return "486";
348 case 2: return "pentium";
349 case 0x10: return "alpha";
350 case 0x20: return "powerpc";
351 case 0x30: return "mips";
352 case 0x40: return "co-processor";
359 if(sub > 5) return "unknown";
360 return class_ser_names[sub];
363 if(sub == 0) return "irda controller";
364 if(sub == 1) return "IR controller";
365 if(sub == 0x10) return "RF controller";
369 if(sub > 4) return "unknown";
370 return class_sat_names[sub];
373 if(sub == 0) return "network & computing crypto";
374 if(sub == 1) return "entertainment crypto";
378 if(sub == 0) return "DPIO module";