summaryrefslogtreecommitdiff
path: root/kernel/drivers/pci.c
diff options
context:
space:
mode:
authorAnton Kling <anton@kling.gg>2023-11-12 15:12:25 +0100
committerAnton Kling <anton@kling.gg>2023-11-12 15:12:48 +0100
commit4e34a5f97786b3bab82f08297ead63e1618744ec (patch)
tree9d95150ddb5305bfab24dedbe665939bd7a82f10 /kernel/drivers/pci.c
parent429b619013d68b98ebadc1e90f77506bcf2dbc9e (diff)
Kernel/PCI: Add functions for getting BAR and specific PCI devices by
class
Diffstat (limited to 'kernel/drivers/pci.c')
-rw-r--r--kernel/drivers/pci.c83
1 files changed, 77 insertions, 6 deletions
diff --git a/kernel/drivers/pci.c b/kernel/drivers/pci.c
index f73b341..362d5c3 100644
--- a/kernel/drivers/pci.c
+++ b/kernel/drivers/pci.c
@@ -1,13 +1,56 @@
#include <assert.h>
#include <cpu/io.h>
#include <drivers/pci.h>
+#include <kmalloc.h>
#include <stdio.h>
#define CONFIG_ADDRESS 0xCF8
#define CONFIG_DATA 0xCFC
-void pci_config_write32(const struct PCI_DEVICE *device, u8 func,
- u8 offset, u32 data) {
+// Gets the bar address and size the populates the struct("bar") given.
+// Return value:
+// 1 Success
+// 0 Failure
+u8 pci_get_bar(const struct PCI_DEVICE *device, u8 bar_index,
+ struct PCI_BaseAddressRegister *bar) {
+ if (bar_index > 5)
+ return 0;
+ u8 offset = 0x10 + bar_index * sizeof(u32);
+ u32 physical_bar = pci_config_read32(device, 0, offset);
+ u32 original_bar = physical_bar;
+ physical_bar &= 0xFFFFFFF0;
+ // Now we do the konami code of PCI devices to figure out the size of what
+ // the BAR is pointing to.
+
+ // Comments taken from https://wiki.osdev.org/PCI#Address_and_size_of_the_BAR
+
+ // write a value of all 1's to the register,
+ pci_config_write32(device, 0, 0x24, 0xFFFFFFFF);
+ // then read it back.
+ u32 bar_result = pci_config_read32(device, 0, 0x24);
+
+ // The amount of memory can then be determined by masking the information
+ // bits,
+ bar_result &=
+ ~(0xF); // Apparently the "information bits" are the last 4 bits according
+ // to this answer: https://stackoverflow.com/a/39618552
+
+ // performing a bitwise NOT ('~' in C),
+ bar_result = ~bar_result;
+
+ // and incrementing the value by 1.
+ bar_result++;
+
+ // Restore the old result
+ pci_config_write32(device, 0, 0x24, original_bar);
+
+ bar->address = physical_bar;
+ bar->size = bar_result;
+ return 1;
+}
+
+void pci_config_write32(const struct PCI_DEVICE *device, u8 func, u8 offset,
+ u32 data) {
u32 address;
u32 lbus = (u32)device->bus;
u32 lslot = (u32)device->slot;
@@ -15,15 +58,14 @@ void pci_config_write32(const struct PCI_DEVICE *device, u8 func,
// Create configuration address as per Figure 1
address = (u32)((lbus << 16) | (lslot << 11) | (lfunc << 8) |
- (offset & 0xFC) | ((u32)0x80000000));
+ (offset & 0xFC) | ((u32)0x80000000));
// Write out the address
outl(CONFIG_ADDRESS, address);
outl(CONFIG_DATA, data);
}
-u32 pci_config_read32(const struct PCI_DEVICE *device, u8 func,
- u8 offset) {
+u32 pci_config_read32(const struct PCI_DEVICE *device, u8 func, u8 offset) {
u32 address;
u32 lbus = (u32)device->bus;
u32 lslot = (u32)device->slot;
@@ -31,13 +73,42 @@ u32 pci_config_read32(const struct PCI_DEVICE *device, u8 func,
// Create configuration address as per Figure 1
address = (u32)((lbus << 16) | (lslot << 11) | (lfunc << 8) |
- (offset & 0xFC) | ((u32)0x80000000));
+ (offset & 0xFC) | ((u32)0x80000000));
// Write out the address
outl(CONFIG_ADDRESS, address);
return inl(CONFIG_DATA);
}
+// Returns number of devices found.
+u8 pci_devices_by_id(u8 class_id, u8 subclass_id,
+ struct PCI_DEVICE *pci_device) {
+ for (u8 bus = 0; bus < 255; bus++) {
+ for (u8 slot = 0; slot < 255; slot++) {
+ pci_device->bus = bus;
+ pci_device->slot = slot;
+ u16 class_info = pci_config_read32(pci_device, 0, 0x8) >> 16;
+ u16 h_classcode = (class_info & 0xFF00) >> 8;
+ u16 h_subclass = (class_info & 0x00FF);
+ if (h_classcode != class_id)
+ continue;
+ if (h_subclass != subclass_id)
+ continue;
+
+ u32 device_vendor = pci_config_read32(pci_device, 0, 0);
+ pci_device->vendor = (device_vendor & 0xFFFF);
+ pci_device->device = (device_vendor >> 16);
+
+ u32 BIST_headertype_latencytimer_cachesize =
+ pci_config_read32(pci_device, 0, 0xC);
+ pci_device->header_type = BIST_headertype_latencytimer_cachesize >> 16;
+ pci_device->header_type &= 0xFF;
+ return 1;
+ }
+ }
+ return 0;
+}
+
int pci_populate_device_struct(u16 vendor, u16 device,
struct PCI_DEVICE *pci_device) {
pci_device->vendor = vendor;