Voxia OS v0.0.1
Hobby Project Operating System Targeting x86-64
Loading...
Searching...
No Matches
scan.c
Go to the documentation of this file.
1#include "./pci.h"
2#include "hal/cpu/paging.h"
3#include <type.h>
4#include "memory/kalloc.h"
5#include "memory/vm_manager.h"
6#include <ioforge/ioforge.h>
8#include <libk/io.h>
9#include <libk/serial.h>
10#include <str.h>
11#include <memory/memory_utils.h>
12
14static size_t segment_count = 0;
15static boolean_t has_ecam = false;
16
18 for (size_t i = 0; i < segment_count; i++) {
19 pci_segment_t* s = &segments[i];
20 if (s->valid && bus >= s->bus_start && bus <= s->bus_end)
21 return s;
22 }
23 return NULL; /* fallback ke segment 0 */
24}
25
26void register_segment(uint16_t seg_id, uint8_t start, uint8_t end,
30 return;
32 s->segment_id = seg_id;
33 s->bus_start = start;
34 s->bus_end = end;
35 s->vbase = vbase;
36 s->ops = ops;
37 s->valid = true;
38 s->type = type;
39}
40
41// legacy_ops
43 .read32 = legacy_read32,
44 .write32 = legacy_write32,
45};
46
47// unified
48
51 if (!s)
52 s = &segments[0]; /* fallback segment pertama */
53 return s->ops->read32(s->vbase, bus, dev, func, off);
54}
55
57 uint32_t dword1 = pci_read32(bus, dev, func, off & ~3);
58 uint32_t dword2 = pci_read32(bus, dev, func, (off & ~3) + 4);
59 return ((uint64_t) dword1 << 32) | dword2;
60}
61
63 uint32_t dword = pci_read32(bus, dev, func, off & ~3);
64 return (dword >> ((off & 2) * 8)) & 0xFFFF;
65}
66
68 uint32_t dword = pci_read32(bus, dev, func, off & ~3);
69 return (dword >> ((off & 3) * 8)) & 0xFF;
70}
71
72void pci_write32(uint8_t bus, uint8_t dev, uint8_t func, uint16_t off,
73 uint32_t val) {
75 if (!s)
76 s = &segments[0];
77 s->ops->write32(s->vbase, bus, dev, func, off, val);
78}
79
80void pci_write64(uint8_t bus, uint8_t dev, uint8_t func, uint16_t off,
81 uint64_t val) {
82 uint32_t dword1 = val >> 32;
83 uint32_t dword2 = val & 0xFFFFFFFF;
84 pci_write32(bus, dev, func, off & ~3, dword1);
85 pci_write32(bus, dev, func, (off & ~3) + 4, dword2);
86}
87
88void pci_write16(uint8_t bus, uint8_t dev, uint8_t func, uint16_t off,
89 uint16_t val) {
90 uint32_t dword = pci_read32(bus, dev, func, off & ~3);
91 uint32_t shift = (off & 2) * 8;
92 dword = (dword & (uint32_t) ~(0xFFFF << shift))
93 | ((uint32_t) val << shift);
94 pci_write32(bus, dev, func, off & ~3, dword);
95}
96//
97
98// Sekarang: hanya deteksi MSI ada/tidak
99// Yang berguna: actually enable MSI supaya tidak pakai legacy IRQ
100
103 sizeof(struct ioforge_pci_device));
104 memset(pci, 0, sizeof(*pci));
105
106 pci->pci_bus = (size_t) bus;
107 pci->pci_dev = (size_t) device;
108 pci->pci_func = (size_t) func;
109
110 pci->device = device;
111
112 pci->base.type = IOFORGE_PCI;
113 pci->vendor_id = pci_read16(bus, device, func, 0);
114 pci->device_id = pci_read16(bus, device, func, 2);
115 LOG_INFO("PCI", "device id : 0x%x", pci->device_id);
116 LOG_INFO("PCI", "vendor id : 0x%x", pci->vendor_id);
117 pci->command = pci_read16(bus, device, func, 4);
118
119 pci->status = pci_read16(bus, device, func, 6);
120 if ((pci->status & (1 << 4))) {
121 uint8_t cap_ptr = pci_read8(bus, device, func, 0x34);
122 pci->capability_ptr = cap_ptr;
123 }
124 pci->revision_id = pci_read16(bus, device, func, 8) & 0xFF;
125 pci->prog_if = (pci_read16(bus, device, func, 8) >> 8) & 0xFF;
126 pci->subclass = pci_read16(bus, device, func, 10) & 0xFF;
127 pci->classes = (pci_read16(bus, device, func, 10) >> 8) & 0xFF;
128
129 // uint8_t cache_line_size = pci_read16(bus, device, func, 12) & 0xFF;
130 // uint8_t latency_timer = pci_read16(bus, device, func, 13) & 0xFF;
131 // uint8_t header_type = pci_read16(bus, device, func, 14) & 0xFF;
132 // uint8_t bist = pci_read16(bus, device, func, 15) & 0xFF;
133
134 for (int i = 0; i < 6; i++) {
135
136 // Fix: disable command register dulu
137 uint16_t cmd = pci_read16(bus, device, func, 0x04);
138 pci_write16(bus, device, func, 0x04, cmd & ~0x7);
139
141 (uint16_t) (0x10 + i * 4));
142 int bar_idx = i; // simpan index asli sebelum i++
143
144 if (bar & 1) {
145 // I/O space
146 pci->bar[i].iospace = 1;
147 pci->bar[i].address = bar & ~3UL;
148 LOG_INFO("PCI", "[%d] BAR IO 0x%x (0x%x)", i, bar,
149 pci->bar[i].address);
150 continue;
151 }
152
153 // Memory space
154 pci->bar[i].iospace = 0;
155 pci->bar[i].address = bar & ~0xFUL;
156
157 // Check 64-bit BAR
158 uint64_t addr = pci->bar[i].address;
159 if ((bar & 0x6) == 0x4) {
160 uint32_t bar_high =
161 pci_read32(bus, device, func,
162 (uint16_t) (0x10 + (i + 1) * 4));
163 addr |= ((uint64_t) bar_high << 32);
164 LOG_INFO("PCI",
165 " 64-bit BAR detected at index %d (0x%lx)", i,
166 addr);
167 i++; // skip next BAR
168 }
169
170 uint32_t original_bar = bar;
171 pci_write32(bus, device, func, (uint16_t) (0x10 + bar_idx * 4),
172 0xFFFFFFFF);
174 (uint16_t) (0x10 + bar_idx * 4));
175 uint32_t size = (uint32_t) (~(value & ~0xFUL) + 1);
176 pci_write32(bus, device, func, (uint16_t) (0x10 + bar_idx * 4),
177 original_bar);
178
179 uint32_t size_4kb = (size + PAGE_SIZE - 1) / PAGE_SIZE;
180
181 uintptr_t vaddr = bar;
182 if (original_bar) {
185 addr, size_4kb, 0b10011);
187 vma_register(get_kernel_vmm_page(), addr, vaddr, size_4kb * PAGE_SIZE);
188 }
191 LOG_INFO("PCI", "[%d] BAR 0x%lx [0x%lx] (0x%lx) size: %d KB",
192 bar_idx, addr, vaddr, offset, size_4kb * 4);
193
194 pci->bar[bar_idx].address = vaddr;
195
196 pci_write16(bus, device, func, 0x04, cmd); // restore
197 }
198
199 // TODO: turn on bus mastering only if needed by module
200 // sementara untuk e1000 saja
201 // if (pci->vendor_id == 0x8086 && pci->device_id == 0x100C) {
202 if ((pci->vendor_id == 0x8086 && pci->device_id == 0x10D3)
203 || (pci->vendor_id == 0x8086 && pci->device_id == 0x24C2)
204 || (pci->vendor_id == 0x8086 && pci->device_id == 0x2922)
205 || (pci->vendor_id == 0x1AF4)) {
206 auto cmd = pci->command;
207 cmd |= (1 << 2); // Bus Master
208 // cmd |= (1 << 1); // Memory Space
209 // cmd |= ~(1 << 10); // Memory Space
210 pci_write16(bus, device, func, 4, cmd);
211
212 // check
213 cmd = pci_read16(bus, device, func, 4);
214 auto bus_master = (cmd & (1 << 2)) >> 2;
215 auto memory_space = (cmd & (1 << 1)) >> 1;
216 LOG_INFO("PCI", "bus master : %d", bus_master);
217 LOG_INFO("PCI", "memory space : %d", memory_space);
218 }
219
220 // uint32_t cardbus_cis_pointer =
221 // pci_read16(bus, device, func, 41) & 0xFFFF;
222 // cardbus_cis_pointer |= pci_read16(bus, device, func, 43) << 16;
223 // uint16_t subsystem_vendor_id = pci_read16(bus, device, func, 44);
224 // uint16_t subsystem_id = pci_read16(bus, device, func, 46);
225 // uint32_t expansion_rom_base_address =
226 // pci_read16(bus, device, func, 48) & 0xFFFF;
227 // expansion_rom_base_address |= pci_read16(bus, device, func, 50) << 16;
228 // pci->capability_ptr = pci_read16(bus, device, func, 52);
229
230 uint8_t interrupt_line = pci_read16(bus, device, func, 60) & 0xFF;
231 uint8_t interrupt_pin = (pci_read16(bus, device, func, 60) >> 8) & 0xFF;
232 LOG_INFO("PCI", "IRQ %d pin : %d", interrupt_line, interrupt_pin);
233 pci->interrupt_line = interrupt_line;
234 pci->interrupt_pin = interrupt_pin;
235
236 // uint8_t min_grant = pci_read16(bus, device, func, 62) & 0xFF;
237 // uint8_t max_latency = pci_read16(bus, device, func, 63) & 0xFF;
238
239 LOG_INFO("PCI", "class : 0x%x subclass : 0x%x", pci->classes,
240 pci->subclass);
241
242 // initialize standard supported device
243 switch (pci->classes) {
244 case 0x00:
245 switch (pci->subclass) {
246 case 0x00:
247 LOG_INFO("PCI", "Unclassified device");
248 break;
249 case 0x01:
250 LOG_INFO("PCI", "Mass storage controller");
251 break;
252 case 0x02:
253 LOG_INFO("PCI", "Network controller");
254 break;
255 case 0x03:
256 LOG_INFO("PCI", "Display controller");
257 break;
258 case 0x04:
259 LOG_INFO("PCI", "Multimedia controller");
260 break;
261 case 0x05:
262 LOG_INFO("PCI", "Memory controller");
263 break;
264 case 0x06:
265 LOG_INFO("PCI", "Bridge device");
266 break;
267 case 0x07:
268 LOG_INFO("PCI", "Simple communication controller");
269 break;
270 case 0x08:
271 LOG_INFO("PCI", "Base system peripheral");
272 break;
273 case 0x09:
274 LOG_INFO("PCI", "Input device controller");
275 break;
276 case 0x0A:
277 LOG_INFO("PCI", "Docking station");
278 break;
279 case 0x0B:
280 LOG_INFO("PCI", "Processor");
281 break;
282 case 0x0C:
283 LOG_INFO("PCI", "Serial bus controller");
284 break;
285 case 0x0D:
286 LOG_INFO("PCI", "Wireless controller");
287 break;
288 case 0x0E:
289 LOG_INFO("PCI", "Intelligent controller");
290 break;
291 case 0x0F:
292 LOG_INFO("PCI", "Satellite communication controller");
293 break;
294 case 0x10:
295 LOG_INFO("PCI", "Encryption controller");
296 break;
297 case 0x11:
298 LOG_INFO("PCI", "Signal processing controller");
299 break;
300 case 0x12:
301 LOG_INFO("PCI", "Processing accelerators");
302 break;
303 case 0x13:
304 LOG_INFO("PCI", "Non-Essential Instrumentation");
305 break;
306 case 0x40:
307 LOG_INFO("PCI", "Co-processor");
308 break;
309 case 0xFF:
310 LOG_INFO("PCI",
311 "Device does not fit in any defined class");
312 break;
313 default:
314 LOG_INFO("PCI", "Unknown class");
315 break;
316 }
317 break;
318 case 0x01:
319 switch (pci->subclass) {
320 case 0x00:
321 LOG_INFO("PCI", "SCSI storage controller");
322 break;
323 case 0x01:
324 LOG_INFO("PCI", "IDE interface");
325 break;
326 }
327 break;
328 case 0x02:
329 switch (pci->subclass) {
330 case 0x00:
331 LOG_INFO("PCI", "Ethernet controller");
332 break;
333 }
334 break;
335 case 0xC:
336 switch (pci->subclass) {
337 case 0x3:
338 switch (pci->prog_if) {
339 case 0x20:
340 LOG_INFO("PCI", "EHCI device");
341 /* pci->service.init = ehci_init; */
342 break;
343 }
344 break;
345 }
346 break;
347 }
348
349 switch (pci->vendor_id) {
350 case 0x1AF4: {
351 LOG_INFO("PCI", "virtio device found w device_id : 0x%x",
352 pci->device_id);
353 switch (pci->device_id) {
354 case 0x1050:
355 LOG_INFO("PCI", "found virtio VGA device");
356 pci->base.flags |= (uint32_t) IOFORGE_F_VIRTIO;
357 // pci->service.init = (void (*)(struct IoForgeService
358 // *))virtio_gpu_init;
359 break;
360 }
361 break;
362 }
363 }
364 serial_printf("\n");
365
367}
368
369static void pci_check_bus(uint8_t bus);
370
371static void pci_check_func(uint8_t bus, uint8_t dev, uint8_t func) {
372 uint8_t class = pci_read8(bus, dev, func, 0x0B);
373 uint8_t subclass = pci_read8(bus, dev, func, 0x0A);
374
375 if (class == 0x06 && subclass == 0x04) {
376 serial_trace("PCI-to-PCI bridge\n");
377 uint8_t sec_bus = pci_read8(bus, dev, func, 0x19);
378 pci_check_bus(sec_bus);
379 } else {
380 vxPCIGatheringBusInfo(bus, dev, func);
381 }
382}
383
384static void pci_check_bus(uint8_t bus) {
385 for (uint8_t dev = 0; dev < 32; dev++) {
386 uint32_t id0 = pci_read32(bus, dev, 0, 0x00);
387 uint16_t vendor = id0 & 0xFFFF;
388 if (vendor == 0xFFFF || vendor == 0x0000)
389 continue;
390
391 uint8_t header = (pci_read32(bus, dev, 0, 0x0C) >> 16) & 0xFF;
392 uint8_t func_count = (header & 0x80) ? 8 : 1;
393
394 for (uint8_t func = 0; func < func_count; func++) {
395 uint32_t id =
396 (func == 0) ? id0
397 : pci_read32(bus, dev, func, 0x00);
398 if ((id & 0xFFFF) == 0xFFFF || (id & 0xFFFF) == 0x0000)
399 continue;
400
401 LOG_INFO("PCI", "device found %d:%d:%d", bus, dev,
402 func);
403 pci_check_func(bus, dev, func);
404 }
405 }
406}
407
408extern boolean_t has_ecam;
409
411 uint8_t host_header = pci_read8(s->bus_start, 0, 0, 0x0E);
412
413 if (host_header & 0x80) {
414 for (uint8_t func = 0; func < 8; func++) {
415 if (pci_read16(s->bus_start, 0, func, 0) == 0xFFFF)
416 break;
417 pci_check_bus(func);
418 }
419 } else {
420 // Mulai dari bus_start — bus lain via bridge traversal
422 }
423}
424
425void pci_scan() {
426 if (has_ecam) {
427 LOG_INFO("pci", "No MCFG, fallback to PCI");
429 } else {
430 LOG_INFO("pci", "Found MCFG, using pcie");
431 }
432
433 for (size_t i = 0; i < segment_count; i++) {
434 pci_segment_t* s = &segments[i];
435 if (!s->valid)
436 continue;
437
438 LOG_INFO("PCI", "Scanning segment %d (bus %d-%d)",
439 s->segment_id, s->bus_start, s->bus_end);
440
441 pci_scan_bus(s);
442 }
443}
struct SDT header
Definition acpi.h:0
void * ops
Definition dev.h:2
volatile uint64_t addr
Definition e1000.hpp:0
volatile uint8_t cmd
Definition e1000.hpp:3
void serial_printf(const char *fmt,...)
void ioforge_attach(struct ioforge_device *parent, struct ioforge_device *child)
#define IOFORGE_F_VIRTIO
Definition ioforge.h:23
struct ioforge_device * ioforge_get_pci_root()
@ IOFORGE_PCI
Definition ioforge.h:12
struct ioforge_pci_device pci
void * kalloc(size_t size)
#define ALIGN_DOWN(x, align)
Definition memory_utils.h:9
return value
Definition oct2bin.h:22
void paging_reload(page_t p)
Definition paging.c:457
page_t paging_get_highest_page_map(void)
Definition paging.c:463
void vxMultipleMmap(page_t page_dir, uint64_t virt, uint64_t phys, uint64_t size, uint64_t flags)
Definition paging.c:340
#define PAGE_SIZE
Definition paging.h:6
void legacy_write32(uintptr_t base, uint8_t bus, uint8_t dev, uint8_t func, uint16_t offset, uint32_t val)
Definition pci.c:38
uint32_t legacy_read32(uintptr_t base, uint8_t bus, uint8_t dev, uint8_t func, uint16_t offset)
Definition pci.c:32
struct pci_segment pci_segment_t
#define PCI_MAX_SEGMENTS
Definition pci.h:15
struct pci_access_ops pci_access_ops_t
PCI_SEGMENT_TYPE
Definition pci.h:17
@ PCI_SEGMENT_LEGACY
Definition pci.h:18
uint8_t pci_read8(uint8_t bus, uint8_t dev, uint8_t func, uint16_t off)
Definition scan.c:67
boolean_t has_ecam
Definition pcie.c:34
static void pci_scan_bus(pci_segment_t *s)
Definition scan.c:410
void pci_scan()
Definition scan.c:425
uint64_t pci_read64(uint8_t bus, uint8_t dev, uint8_t func, uint16_t off)
Definition scan.c:56
static pci_access_ops_t legacy_ops
Definition scan.c:42
static void vxPCIGatheringBusInfo(uint8_t bus, uint8_t device, uint8_t func)
Definition scan.c:101
static pci_segment_t segments[16]
Definition scan.c:13
void pci_write16(uint8_t bus, uint8_t dev, uint8_t func, uint16_t off, uint16_t val)
Definition scan.c:88
void pci_write32(uint8_t bus, uint8_t dev, uint8_t func, uint16_t off, uint32_t val)
Definition scan.c:72
static void pci_check_func(uint8_t bus, uint8_t dev, uint8_t func)
Definition scan.c:371
uint16_t pci_read16(uint8_t bus, uint8_t dev, uint8_t func, uint16_t off)
Definition scan.c:62
static size_t segment_count
Definition scan.c:14
static void pci_check_bus(uint8_t bus)
Definition scan.c:384
void pci_write64(uint8_t bus, uint8_t dev, uint8_t func, uint16_t off, uint64_t val)
Definition scan.c:80
uint8_t pci_read8(uint8_t bus, uint8_t dev, uint8_t func, uint16_t off)
Definition scan.c:67
static pci_segment_t * find_segment(uint8_t bus)
Definition scan.c:17
void register_segment(uint16_t seg_id, uint8_t start, uint8_t end, uintptr_t vbase, pci_access_ops_t *ops, PCI_SEGMENT_TYPE type)
Definition scan.c:26
uint32_t pci_read32(uint8_t bus, uint8_t dev, uint8_t func, uint16_t off)
Definition scan.c:49
#define LOG_INFO(mod, fmt,...)
Definition serial.h:20
#define serial_trace(...)
Definition serial.h:19
void memset(void *ptr, int value, size_t num)
uint32_t(* read32)(uintptr_t base, uint8_t bus, uint8_t dev, uint8_t func, uint16_t offset)
Definition pci.h:9
void(* write32)(uintptr_t base, uint8_t bus, uint8_t dev, uint8_t func, uint16_t offset, uint32_t val)
Definition pci.h:11
boolean_t valid
Definition pci.h:28
pci_access_ops_t * ops
Definition pci.h:27
uint8_t bus_end
Definition pci.h:25
PCI_SEGMENT_TYPE type
Definition pci.h:29
uintptr_t vbase
Definition pci.h:26
uint8_t bus_start
Definition pci.h:24
uint16_t segment_id
Definition pci.h:23
#define NULL
Definition type.h:76
unsigned short uint16_t
Definition type.h:13
unsigned int uint32_t
Definition type.h:19
uint8_t boolean_t
Definition type.h:89
unsigned long uintptr_t
Definition type.h:73
unsigned long uint64_t
Definition type.h:25
unsigned char uint8_t
Definition type.h:7
unsigned long size_t
Definition type.h:55
uint32_t offset
Definition virtio.h:6
uint8_t bar
Definition virtio.h:4
uintptr_t vma_lookup_free_vaddr(struct virtual_memory_page *page, mem_vma_region region, size_t size)
Definition vm_manager.c:156
void vma_register(struct virtual_memory_page *page, uintptr_t phys_address, uintptr_t virt_addr, size_t size)
Definition vm_manager.c:101
struct virtual_memory_page * get_kernel_vmm_page()
@ VMA_REGION_C
Definition vm_manager.h:15
uint8_t type
Definition vnode.h:2
size_t size
Definition vnode.h:3
struct device_id device
Definition vnode.h:13