summaryrefslogtreecommitdiff
path: root/src/kernel/pci.c
diff options
context:
space:
mode:
authorBenji Dial <Benji3.141@gmail.com>2020-08-11 11:33:21 -0400
committerBenji Dial <Benji3.141@gmail.com>2020-08-11 11:33:21 -0400
commit63167f223e1f54910f6b80e698390ee60aec79ee (patch)
tree41844f646bdcb5c9ba241bb5867c5e4f51737d52 /src/kernel/pci.c
parent77d7a284c02bc6b1b3a3a92ad5d957172cee9b81 (diff)
downloadportland-os-63167f223e1f54910f6b80e698390ee60aec79ee.tar.gz
lots of progress
currently, BAR fields of IDE drives are all returning zero, and the ATA read function isn't working. i'm not sure why. i'm going to work on VESA next, and come back to the IDE driver later
Diffstat (limited to 'src/kernel/pci.c')
-rw-r--r--src/kernel/pci.c77
1 files changed, 77 insertions, 0 deletions
diff --git a/src/kernel/pci.c b/src/kernel/pci.c
new file mode 100644
index 0000000..fe96c4c
--- /dev/null
+++ b/src/kernel/pci.c
@@ -0,0 +1,77 @@
+#include "boot.h"
+#include "mem.h"
+#include "util.h"
+#include "pci.h"
+#include "panic.h"
+
+enum {
+ PCP_SELECT = 0x0cf8,
+ PCP_READ = 0x0cfc
+};
+
+uint16_t n_pci_devices = 0;
+struct pci_device *pci_device_pages[256];
+
+#define PCI_DEVICES_PER_PAGE (4096 / sizeof(struct pci_device))
+
+struct pci_device *nth_pci_device(uint16_t n) {
+ return pci_device_pages[n / PCI_DEVICES_PER_PAGE] + (n % PCI_DEVICES_PER_PAGE);
+}
+
+struct pci_device *find_pci_device_from_class_and_subclass(uint8_t class, uint8_t subclass, uint16_t start, uint16_t *index) {
+ for (uint16_t n = start; n < n_pci_devices; ++n) {
+ struct pci_device *p = nth_pci_device(n);
+ if ((p->class == class) && (p->subclass == subclass)) {
+ *index = n;
+ return p;
+ }
+ }
+ return 0;
+}
+
+struct pci_device *next_pci_device() {
+ if (!(n_pci_devices % PCI_DEVICES_PER_PAGE))
+ pci_device_pages[n_pci_devices / PCI_DEVICES_PER_PAGE] = allocate_pages(1);
+ return nth_pci_device(n_pci_devices++);
+}
+
+static inline uint32_t pci_read_config(uint16_t number, uint8_t reg) {
+ uint32_t cspace_addr = 0x80000000 | (number << 8) | (reg << 2);
+ outd(PCP_SELECT, cspace_addr);
+
+ return ind(PCP_READ);
+}
+
+void pci_device_check(uint16_t number) {
+ uint32_t id = pci_read_config(number, 0);
+ if ((id & 0xffff) == 0xffff)
+ return;
+
+ struct pci_device *next_device = next_pci_device();
+
+ next_device->number = number;
+
+ next_device->id_vendor = id;
+ next_device->id_device = id >> 16;
+
+ uint32_t class = pci_read_config(number, 2);
+
+ next_device->class = class >> 24;
+ next_device->subclass = class >> 16;
+ next_device->iface = class >> 8;
+
+ next_device->bar0 = pci_read_config(number, 4);
+ next_device->bar1 = pci_read_config(number, 5);
+ next_device->bar2 = pci_read_config(number, 6);
+ next_device->bar3 = pci_read_config(number, 7);
+}
+
+void pci_init() {
+ if (!(BOOT_INFO->support_flags & BIS_PCI))
+ panic("No PCI support detected.");
+ if (!(BOOT_INFO->pci_hw_char & PHC_CS_M1))
+ panic("No PCI Mechanism 1 support");
+
+ for (uint32_t number = 0; number < (BOOT_INFO->last_pci_bus + 1) * 256; ++number)
+ pci_device_check(number);
+} \ No newline at end of file