MonkOS  v0.1
A simple 64-bit operating system (x86_64)
pci.c
Go to the documentation of this file.
1 //============================================================================
2 /// @file pci.c
3 /// @brief PCI controller.
4 //
5 // Copyright 2016 Brett Vickers.
6 // Use of this source code is governed by a BSD-style license that can
7 // be found in the MonkOS LICENSE file.
8 //============================================================================
9 
10 #include <core.h>
11 #include <kernel/device/pci.h>
12 #include <kernel/device/tty.h>
13 #include <kernel/x86/cpu.h>
14 
15 #define DEBUG_PCI 1
16 
17 #define PCI_CONFIG_ADDR 0x0cf8
18 #define PCI_CONFIG_DATA 0x0cfc
19 
20 static inline uint32_t
21 read(uint32_t bus, uint32_t device, uint32_t func, uint32_t offset)
22 {
23  uint32_t addr = (1u << 31) |
24  (bus << 16) |
25  (device << 11) |
26  (func << 8) |
27  offset;
28 
29  io_outd(PCI_CONFIG_ADDR, addr);
30  return io_ind(PCI_CONFIG_DATA);
31 }
32 
33 static inline uint32_t
34 read_hdrtype(uint32_t bus, uint32_t device, uint32_t func)
35 {
36  uint32_t value = read(bus, device, func, 0x0c);
37  return (value >> 16) & 0xff;
38 }
39 
40 static inline uint32_t
41 read_deviceid(uint32_t bus, uint32_t device, uint32_t func)
42 {
43  uint32_t value = read(bus, device, func, 0x00);
44  return (value >> 16) & 0xffff;
45 }
46 
47 static inline uint32_t
48 read_vendor(uint32_t bus, uint32_t device, uint32_t func)
49 {
50  uint32_t value = read(bus, device, func, 0x00);
51  return value & 0xffff;
52 }
53 
54 static inline uint32_t
55 read_class(uint32_t bus, uint32_t device, uint32_t func)
56 {
57  uint32_t value = read(bus, device, func, 0x08);
58  return value >> 24;
59 }
60 
61 static inline uint32_t
62 read_subclass(uint32_t bus, uint32_t device, uint32_t func)
63 {
64  uint32_t value = read(bus, device, func, 0x08);
65  return (value >> 16) & 0xff;
66 }
67 
68 static inline uint32_t
69 read_secondary_bus(uint32_t bus, uint32_t device, uint32_t func)
70 {
71  uint32_t value = read(bus, device, func, 0x18);
72  return (value >> 8) & 0xff;
73 }
74 
75 static void probe_bus(uint32_t bus);
76 
77 static bool
78 probe_function(uint32_t bus, uint32_t device, uint32_t func)
79 {
80  // Validate the function
81  uint32_t vendor = read_vendor(bus, device, func);
82  if (vendor == 0xffff)
83  return false;
84 
85  // Read the device's class/subclass
86  uint32_t class = read_class(bus, device, func);
87  uint32_t subclass = read_subclass(bus, device, func);
88 
89  // Is this a PCI-to-PCI bridge device? If so, recursively scan the
90  // bridge's secondary bus.
91  if (class == 6 && subclass == 4) {
92  uint32_t bus2 = read_secondary_bus(bus, device, func);
93  probe_bus(bus2);
94  }
95 
96 #if DEBUG_PCI
97  else {
98  uint32_t devid = read_deviceid(bus, device, func);
99  tty_printf(
100  0,
101  "[pci] %u/%u/%u vendor=0x%04x devid=0x%04x "
102  "class=%02x subclass=%02x\n",
103  bus, device, func, vendor, devid, class, subclass);
104  }
105 #endif
106 
107  return true;
108 }
109 
110 static void
111 probe_device(uint32_t bus, uint32_t device)
112 {
113  // Probe device function 0.
114  if (!probe_function(bus, device, 0))
115  return;
116 
117  // Probe functions 1 through 8 if the device is multi-function.
118  uint32_t hdrtype = read_hdrtype(bus, device, 0);
119  if (hdrtype & 0x80) {
120  for (uint32_t func = 1; func < 8; ++func)
121  probe_function(bus, device, func);
122  }
123 }
124 
125 static void
126 probe_bus(uint32_t bus)
127 {
128  // Probe all possible devices on the bus.
129  for (uint32_t device = 0; device < 32; ++device)
130  probe_device(bus, device);
131 }
132 
133 void
135 {
136  // Always probe bus 0.
137  probe_bus(0);
138 
139  // If bus 0 device 0 is multi-function, probe remaining 7 buses.
140  uint32_t hdrtype = read_hdrtype(0, 0, 0);
141  if (hdrtype & 0x80) {
142  for (uint32_t bus = 1; bus < 8; ++bus) {
143  uint32_t vendor = read_vendor(0, 0, bus); // func = bus #
144  if (vendor != 0xffff)
145  probe_bus(bus);
146  }
147  }
148 }
#define PCI_CONFIG_ADDR
Definition: pci.c:17
static uint32_t read(uint32_t bus, uint32_t device, uint32_t func, uint32_t offset)
Definition: pci.c:21
__forceinline void io_outd(uint16_t port, uint32_t value)
Definition: cpu_inl.h:103
Core include file.
static void probe_bus(uint32_t bus)
Definition: pci.c:126
static uint32_t read_hdrtype(uint32_t bus, uint32_t device, uint32_t func)
Definition: pci.c:34
static uint32_t read_subclass(uint32_t bus, uint32_t device, uint32_t func)
Definition: pci.c:62
static uint32_t read_secondary_bus(uint32_t bus, uint32_t device, uint32_t func)
Definition: pci.c:69
PCI controller.
static bool probe_function(uint32_t bus, uint32_t device, uint32_t func)
Definition: pci.c:78
void pci_init()
Definition: pci.c:134
x86 CPU-specific function implementations.
__forceinline uint32_t io_ind(uint16_t port)
Definition: cpu_inl.h:91
#define PCI_CONFIG_DATA
Definition: pci.c:18
int tty_printf(int id, const char *format,...)
Output a printf-formatted string to the virtual console using the console&#39;s current text color and sc...
Definition: tty.c:372
Teletype (console) screen text manipulation routines.
static void probe_device(uint32_t bus, uint32_t device)
Definition: pci.c:111
static uint32_t read_vendor(uint32_t bus, uint32_t device, uint32_t func)
Definition: pci.c:48
static uint32_t read_deviceid(uint32_t bus, uint32_t device, uint32_t func)
Definition: pci.c:41
static uint32_t read_class(uint32_t bus, uint32_t device, uint32_t func)
Definition: pci.c:55