summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.zig2
-rw-r--r--kernel/drivers/drivers.c7
-rw-r--r--kernel/drivers/pci.c174
-rw-r--r--kernel/include/comus/drivers.h17
-rw-r--r--kernel/include/comus/drivers/pci.h72
-rw-r--r--kernel/kernel.c9
6 files changed, 276 insertions, 5 deletions
diff --git a/build.zig b/build.zig
index 468478b..42147ee 100644
--- a/build.zig
+++ b/build.zig
@@ -30,6 +30,8 @@ const kernel_src = &[_][]const u8{
"kernel/cpu/idt.c",
"kernel/cpu/idt.S",
"kernel/cpu/pic.c",
+ "kernel/drivers/drivers.c",
+ "kernel/drivers/pci.c",
"kernel/io/io.c",
"kernel/io/panic.c",
"kernel/mboot/mboot.c",
diff --git a/kernel/drivers/drivers.c b/kernel/drivers/drivers.c
new file mode 100644
index 0000000..5b68248
--- /dev/null
+++ b/kernel/drivers/drivers.c
@@ -0,0 +1,7 @@
+#include <comus/drivers.h>
+#include <comus/drivers/pci.h>
+
+void drivers_init(void)
+{
+ pci_init();
+}
diff --git a/kernel/drivers/pci.c b/kernel/drivers/pci.c
new file mode 100644
index 0000000..83c47f1
--- /dev/null
+++ b/kernel/drivers/pci.c
@@ -0,0 +1,174 @@
+#include <comus/drivers/pci.h>
+#include <comus/asm.h>
+#include <lib.h>
+
+#define CONF_ADDR 0xCF8
+#define CONF_DATA 0xCFC
+#define TABLE_LEN 16
+
+struct pci_table_entry {
+ struct pci_device device;
+ uint16_t device_id;
+ uint16_t vendor_id;
+ uint8_t class;
+ uint8_t subclass;
+ uint8_t prog_if;
+ uint8_t revision;
+};
+
+static struct pci_table_entry pci_table[TABLE_LEN];
+static size_t pci_table_next = 0;
+
+uint32_t pci_rcfg_d(struct pci_device dev, uint8_t offset)
+{
+ uint32_t addr = 0x80000000;
+ addr |= ((uint32_t)dev.bus) << 16;
+ addr |= ((uint32_t)dev.device) << 11;
+ addr |= ((uint32_t)dev.function) << 8;
+ addr |= offset & 0xFC;
+
+ outl(CONF_ADDR, addr);
+ uint32_t in = inl(CONF_DATA);
+ return in;
+}
+
+static void print_device(struct pci_table_entry *entry)
+{
+ printf(
+ "BUS: %#-4x DEV: %#-4x FUNC: %#-4x ID: %04x:%04x CLASS: %02x:%02x:%02x REV: %#02x\n",
+ entry->device.bus, entry->device.device, entry->device.function,
+ entry->vendor_id, entry->device_id, entry->class, entry->subclass,
+ entry->prog_if, entry->revision);
+}
+
+static struct pci_table_entry *load_device(struct pci_device dev)
+{
+ if (pci_table_next >= TABLE_LEN)
+ panic("Too many PCI devices: limit is %d", TABLE_LEN);
+ struct pci_table_entry *entry = &pci_table[pci_table_next++];
+ entry->device = dev;
+ uint32_t dword0 = pci_rcfg_d(dev, 0);
+ uint32_t dword2 = pci_rcfg_d(dev, 8);
+
+ entry->device_id = (dword0 >> 16) & 0xFFFF;
+ entry->vendor_id = dword0 & 0xFFFF;
+
+ entry->class = (dword2 >> 24) & 0xFF;
+ entry->subclass = (dword2 >> 16) & 0xFF;
+ entry->prog_if = (dword2 >> 8) & 0xFF;
+ entry->revision = dword2 & 0xFF;
+
+ return entry;
+}
+
+uint16_t pci_rcfg_w(struct pci_device dev, uint8_t offset)
+{
+ uint32_t dword = pci_rcfg_d(dev, offset);
+ return (uint16_t)((dword >> ((offset & 2) * 8)) & 0xFFFF);
+}
+
+uint8_t pci_rcfg_b(struct pci_device dev, uint8_t offset)
+{
+ uint32_t dword = pci_rcfg_d(dev, offset);
+ return (uint8_t)((dword >> ((offset & 3) * 8)) & 0xFF);
+}
+
+void pci_wcfg_d(struct pci_device dev, uint8_t offset, uint32_t dword)
+{
+ uint32_t addr = 0x80000000;
+ addr |= ((uint32_t)dev.bus) << 16;
+ addr |= ((uint32_t)dev.device) << 11;
+ addr |= ((uint32_t)dev.function) << 8;
+ addr |= offset & 0xFC;
+
+ outl(CONF_ADDR, addr);
+ outl(CONF_DATA, dword);
+}
+
+void pci_wcfg_w(struct pci_device dev, uint8_t offset, uint16_t word)
+{
+ size_t shift = (offset & 2) * 8;
+ uint32_t dword = pci_rcfg_d(dev, offset);
+ dword &= ~(0xFFFF << shift);
+ dword |= word << shift;
+ pci_wcfg_d(dev, offset, dword);
+}
+
+void pci_wcfg_b(struct pci_device dev, uint8_t offset, uint8_t byte)
+{
+ size_t shift = (offset & 3) * 8;
+ uint32_t dword = pci_rcfg_d(dev, offset);
+ dword &= ~(0xFF << shift);
+ dword |= byte << shift;
+ pci_wcfg_d(dev, offset, dword);
+}
+
+void pci_init(void)
+{
+ pci_table_next = 0;
+ struct pci_device pcidev;
+ for (int bus = 0; bus < 256; bus++) {
+ pcidev.bus = bus;
+ for (int dev = 0; dev < 32; dev++) {
+ pcidev.device = dev;
+ pcidev.function = 0;
+
+ uint16_t vendor = pci_rcfg_w(pcidev, 0);
+ if (vendor == 0xFFFF)
+ continue;
+
+ load_device(pcidev);
+
+ uint8_t header_type = pci_rcfg_b(pcidev, 14);
+
+ if (!(header_type & 0x80))
+ continue;
+ for (int func = 1; func < 8; func++) {
+ pcidev.function = func;
+
+ uint16_t vendor = pci_rcfg_w(pcidev, 0);
+ if (vendor == 0xFFFF)
+ continue;
+
+ load_device(pcidev);
+ }
+ }
+ }
+ printf("PCI DEVICES\n");
+ for (size_t i = 0; i < pci_table_next; i++) {
+ print_device(&pci_table[i]);
+ }
+ printf("\n");
+}
+
+bool pci_findby_class(struct pci_device *dest, uint8_t class, uint8_t subclass,
+ size_t *offset)
+{
+ size_t o = 0;
+ if (offset == NULL)
+ offset = &o;
+ for (; *offset < pci_table_next; (*offset)++) {
+ struct pci_table_entry *entry = &pci_table[*offset];
+ if (entry->class == class && entry->subclass == subclass) {
+ *dest = entry->device;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool pci_findby_id(struct pci_device *dest, uint16_t device, uint16_t vendor,
+ size_t *offset)
+{
+ size_t o = 0;
+ if (offset == NULL)
+ offset = &o;
+ for (; *offset < pci_table_next; (*offset)++) {
+ struct pci_table_entry *entry = &pci_table[*offset];
+ if (entry->device_id == device && entry->vendor_id == vendor) {
+ *dest = entry->device;
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/kernel/include/comus/drivers.h b/kernel/include/comus/drivers.h
new file mode 100644
index 0000000..3a38d3b
--- /dev/null
+++ b/kernel/include/comus/drivers.h
@@ -0,0 +1,17 @@
+/**
+ * @file drivers.h
+ *
+ * @author Freya Murphy <freya@freyacat.org>
+ *
+ * Entrypoint for initalizing all devices
+ */
+
+#ifndef DRIVERS_H_
+#define DRIVERS_H_
+
+/**
+ * Initalize all supported drivers
+ */
+void drivers_init(void);
+
+#endif /* drivers.h */
diff --git a/kernel/include/comus/drivers/pci.h b/kernel/include/comus/drivers/pci.h
new file mode 100644
index 0000000..34bcdda
--- /dev/null
+++ b/kernel/include/comus/drivers/pci.h
@@ -0,0 +1,72 @@
+/**
+ * @file pci.h
+ *
+ * @author Freya Murphy <freya@freyacaat.org>
+ * @author Tristan Miller <trimill@trimillxyz.org>
+ *
+ * PCI driver
+ */
+
+#ifndef PCI_H_
+#define PCI_H_
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+// common
+#define PCI_VENDOR_W 0x00
+#define PCI_DEVICE_W 0x02
+#define PCI_COMMAND_W 0x04
+#define PCI_STATUS_W 0x06
+#define PCI_REVISION_B 0x08
+#define PCI_PROG_IF_B 0x09
+#define PCI_SUBCLASS_B 0x0A
+#define PCI_CLASS_B 0x0B
+#define PCI_CACHE_SIZE_B 0x0C
+#define PCI_LATENCY_TIMER_B 0x0D
+#define PCI_HEADER_TYPE_B 0x0E
+#define PCI_BIST_B 0x0F
+
+// header type 0
+#define PCI_BAR0_D 0x10
+#define PCI_BAR1_D 0x14
+#define PCI_BAR2_D 0x18
+#define PCI_BAR3_D 0x1C
+#define PCI_BAR4_D 0x20
+#define PCI_BAR5_D 0x24
+#define PCI_CARDBUS_CIS_D 0x28
+#define PCI_SUBSYSTEM_VENDOR_W 0x2C
+#define PCI_SUBSYSTEM_W 0x2E
+#define PCI_EXPANSION_ROM_D 0x30
+#define PCI_CAP_PTR_B 0x34
+#define PCI_INT_LINE_B 0x3C
+#define PCI_INT_PIN_B 0x3D
+#define PCI_MIN_GRANT_B 0x3E
+#define PCI_MAX_LATENCY_B 0x3F
+
+struct pci_device {
+ uint8_t bus : 8;
+ uint8_t device : 5;
+ uint8_t function : 3;
+};
+
+/**
+ * Load the PCI driver
+ */
+void pci_init(void);
+
+bool pci_findby_class(struct pci_device *dest, uint8_t class, uint8_t subclass,
+ size_t *offset);
+bool pci_findby_id(struct pci_device *dest, uint16_t device, uint16_t vendor,
+ size_t *offset);
+
+uint32_t pci_rcfg_d(struct pci_device dev, uint8_t offset);
+uint16_t pci_rcfg_w(struct pci_device dev, uint8_t offset);
+uint8_t pci_rcfg_b(struct pci_device dev, uint8_t offset);
+
+void pci_wcfg_d(struct pci_device dev, uint8_t offset, uint32_t dword);
+void pci_wcfg_w(struct pci_device dev, uint8_t offset, uint16_t word);
+void pci_wcfg_b(struct pci_device dev, uint8_t offset, uint8_t byte);
+
+#endif /* pci.h */
diff --git a/kernel/kernel.c b/kernel/kernel.c
index d817741..4896b38 100644
--- a/kernel/kernel.c
+++ b/kernel/kernel.c
@@ -1,15 +1,14 @@
#include <comus/cpu.h>
#include <comus/memory.h>
#include <comus/mboot.h>
+#include <comus/drivers.h>
#include <lib.h>
-#include <stdio.h>
-#include <stdlib.h>
struct memory_map mmap;
void main(long magic, volatile void *mboot)
{
- (void) magic; // TODO: check multiboot magic
+ (void)magic; // TODO: check multiboot magic
// initalize idt and pic
// WARNING: must be done before anything else
@@ -21,8 +20,8 @@ void main(long magic, volatile void *mboot)
// initalize memory
memory_init(&mmap);
- char *a = malloc(3);
- *a = 3;
+ // initalize devices
+ drivers_init();
// halt
printf("halting...\n");