Nucleus
Barry ACPI DSDT + PCI 53a772a (3 years, 3 months ago)
diff --git a/kernel/acpi/acpi.c b/kernel/acpi/acpi.c
index 2774dbe..431d471 100644
--- a/kernel/acpi/acpi.c
+++ b/kernel/acpi/acpi.c
@@ -1,5 +1,6 @@
/*
- * This file controls the ACPI.
+ * This file controls ACPI. It finds the ACPI Root System Descriptor Table then
+ * searches it for more tables, which can be initialised separately.
*/
#include <stdint.h>
@@ -18,24 +19,42 @@ struct RSDPDesc {
} __attribute__((packed));
void init_apic(struct SDTHeader *);
+void init_fadt(struct SDTHeader *);
+void init_dsdt(struct SDTHeader *);
/* Table handlers */
struct TableHandler {
char *sig;
void (*handler)(struct SDTHeader *);
} handlers[] = {
- {"APIC", init_apic},
+ { "APIC", init_apic },
+ { "FACP", init_fadt },
+ { "DSDT", init_dsdt },
};
-/* Calculate the ACPI checksum */
-static uint32_t
-checksum(struct SDTHeader *header)
+/* Match a signature to a handler */
+void
+init_table(struct SDTHeader *table)
{
- char *byte = (void *) header;
uint32_t i, check = 0;
- for (i = 0; i < header->length; i++)
+ char *byte = (void *) table;
+
+ set_page((uintptr_t) table, PAGE_ADDR((uintptr_t) table) |
+ PTE_PRESENT | PTE_WRITE);
+ flush_tlb((uintptr_t) table);
+
+ /* Checksum */
+ for (i = 0; i < table->length; i++)
check += byte[i];
- return ((check % 0x100) == 0);
+ if (check % 0x100)
+ return;
+
+ /* Match handler */
+ for (i = 0; i < sizeof(handlers) / sizeof(handlers[0]); i++) {
+ if (memcmp(table->signature, handlers[i].sig, 4))
+ continue;
+ handlers[i].handler(table);
+ }
}
/* Initialise ACPI */
@@ -65,14 +84,6 @@ init_acpi(void *ebda)
set_page((uintptr_t) rsdt, PAGE_ADDR((uintptr_t) rsdt) |
PTE_PRESENT | PTE_WRITE);
flush_tlb((uintptr_t) rsdt);
- for (i = 0; i < (rsdt->length - sizeof(struct SDTHeader)) / 4; i++) {
- if (!checksum(table[i]))
- continue;
- /* Try to match to a handler */
- for (j = 0; j < sizeof(handlers)/sizeof(handlers[0]); j++) {
- if (memcmp(table[i]->signature, handlers[j].sig, 4))
- continue;
- handlers[j].handler(table[i]);
- }
- }
+ for (i = 0; i < (rsdt->length - sizeof(struct SDTHeader)) / 4; i++)
+ init_table(table[i]);
}
diff --git a/kernel/acpi/acpi.h b/kernel/acpi/acpi.h
index 9821960..0c39b19 100644
--- a/kernel/acpi/acpi.h
+++ b/kernel/acpi/acpi.h
@@ -14,6 +14,7 @@ struct SDTHeader {
uint32_t creatorRevision;
};
+void init_table(struct SDTHeader *table);
void init_acpi(void *ebda);
#endif
diff --git a/kernel/acpi/apic.c b/kernel/acpi/apic.c
index 423d815..4d969f5 100644
--- a/kernel/acpi/apic.c
+++ b/kernel/acpi/apic.c
@@ -122,7 +122,7 @@ apic_start_timer(void)
c++;
}
-/* Initialise SMP (RSDT method) */
+/* Initialise SMP */
void
init_apic(struct SDTHeader *header)
{
diff --git a/kernel/acpi/dsdt.c b/kernel/acpi/dsdt.c
new file mode 100644
index 0000000..23b8178
--- /dev/null
+++ b/kernel/acpi/dsdt.c
@@ -0,0 +1,16 @@
+/*
+ * This file contains the Differentated System Descriptor Table initialisation
+ * code. The DSDT describes the peripherals attached to a machine, holding
+ * information on IO ports, IRQs, memory mappings and power management.
+ */
+
+#include <nucleus/panic.h>
+#include <io.h>
+#include "acpi.h"
+
+/* Parse the DSDT for information */
+void
+init_dsdt(struct SDTHeader *header)
+{
+ return;
+}
diff --git a/kernel/acpi/fadt.c b/kernel/acpi/fadt.c
new file mode 100644
index 0000000..92ce4c1
--- /dev/null
+++ b/kernel/acpi/fadt.c
@@ -0,0 +1,40 @@
+/*
+ * This file contains the code for handling the Fixed ACPI Description Table.
+ * The FADT describes the ACPI fixed register blocks related to power
+ * management. It should also contain a pointer to the Differentiated System
+ * Description Table.
+ */
+
+#include <io.h>
+#include "acpi.h"
+
+/* Preferred Power Management Profile */
+enum PMProfile {
+ PM_UNSPECIFIED,
+ PM_DESKTOP,
+ PM_MOBILE,
+ PM_WORKSTATION,
+ PM_ENTERPRISE_SERVER,
+ PM_SOHO_SERVER,
+ PM_APPLIANCE_PC,
+ PM_PERFORMANCE_SERVER,
+};
+
+/* Structure of the FADT */
+struct FADTable {
+ uint32_t firmwareCtrl;
+ uint32_t dsdt;
+ uint8_t reserved;
+ uint8_t prefPMProfile;
+ uint16_t sciInterrupt;
+ uint32_t smiCommandPort;
+ /* Bunch more boring stuff */
+};
+
+/* Parse FADT for information */
+void
+init_fadt(struct SDTHeader *header)
+{
+ struct FADTable *fadt = (struct FADTable *) (header + 1);
+ init_table((void *) fadt->dsdt);
+}
diff --git a/kernel/main.c b/kernel/main.c
index b4e639e..34bb397 100644
--- a/kernel/main.c
+++ b/kernel/main.c
@@ -13,6 +13,7 @@
#include "multiboot.h"
#include "desc.h"
#include "acpi/acpi.h"
+#include "pci/pci.h"
extern char _bss[], _end[];
@@ -45,9 +46,11 @@ cpu_load(void)
asm volatile("sti");
}
+#include <io.h>
+
/* Kernel main function */
_Noreturn void
-kmain(uint32_t esp, struct MultibootInfo *mbinfo)
+kmain(struct MultibootInfo *mbinfo)
{
void *ebda = (void *) (*((uint16_t *) 0x040E) << 4);
memset(_bss, 0, _end - _bss);
@@ -68,6 +71,7 @@ kmain(uint32_t esp, struct MultibootInfo *mbinfo)
init_vfs();
/* Search ACPI tables */
init_acpi(ebda);
+ init_pci();
panic("End of kernel!");
}
diff --git a/kernel/pci/pci.c b/kernel/pci/pci.c
new file mode 100644
index 0000000..408aeb8
--- /dev/null
+++ b/kernel/pci/pci.c
@@ -0,0 +1,86 @@
+/*
+ *
+ */
+
+#include <stdint.h>
+#include <io.h>
+#include "pci.h"
+
+const uint16_t CONFIG_ADDRESS = 0xCF8;
+const uint16_t CONFIG_DATA = 0xCFC;
+
+/* Make a PCI Address */
+static inline uint32_t
+make_pci_address(int bus, int dev, int func, int off)
+{
+ return (1 << 31) | (bus << 16) | (dev << 11) | (func << 8) |
+ (off & 0xFC);
+}
+
+/* Read PCI config byte */
+uint8_t
+pci_read_byte(int bus, int dev, int func, int off)
+{
+ outl(CONFIG_ADDRESS, make_pci_address(bus, dev, func, off));
+ return inb(CONFIG_DATA + (off & 3));
+}
+
+/* Read PCI config word */
+uint16_t
+pci_read_word(int bus, int dev, int func, int off)
+{
+ outl(CONFIG_ADDRESS, make_pci_address(bus, dev, func, off));
+ return inw(CONFIG_DATA + (off & 2));
+}
+
+/* Read PCI config dword */
+uint32_t
+pci_read_dword(int bus, int dev, int func, int off)
+{
+ outl(CONFIG_ADDRESS, make_pci_address(bus, dev, func, off));
+ return inl(CONFIG_DATA);
+}
+
+/* Write PCI config byte */
+void
+pci_write_byte(int bus, int dev, int func, int off, uint8_t value)
+{
+ outl(CONFIG_ADDRESS, make_pci_address(bus, dev, func, off));
+ outb(CONFIG_DATA + (off & 3), value);
+}
+
+/* Write PCI config word */
+void
+pci_write_word(int bus, int dev, int func, int off, uint16_t value)
+{
+ outl(CONFIG_ADDRESS, make_pci_address(bus, dev, func, off));
+ outw(CONFIG_DATA + (off & 2), value);
+}
+
+/* Write PCI config dword */
+void
+pci_write_dword(int bus, int dev, int func, int off, uint32_t value)
+{
+ outl(CONFIG_ADDRESS, make_pci_address(bus, dev, func, off));
+ outl(CONFIG_DATA, value);
+}
+
+/* Scan for PCI devices */
+void
+init_pci(void)
+{
+ uint16_t bus, slot, func;
+ uint16_t vendor, device;
+ uint8_t class, subclass;
+ uint32_t dev;
+ /* This is one massive iteration */
+ for (bus = 0; bus < 256; bus++)
+ for (slot = 0; slot < 32; slot++)
+ for (func = 0; func < 8; func++)
+ if ((vendor = pci_read_word(bus, slot, func, 0)) != 0xFFFF) {
+ device = pci_read_word(bus, slot, func, 2);
+ /* do something */
+// kprintf("PCI(%d,%d,%d) = %#.4x:%#.4x",
+// bus, slot, func, vendor, device);
+ }
+}
diff --git a/kernel/pci/pci.h b/kernel/pci/pci.h
new file mode 100644
index 0000000..b61dec3
--- /dev/null
+++ b/kernel/pci/pci.h
@@ -0,0 +1,15 @@
+#ifndef KERNEL_PCI_H
+#define KERNEL_PCI_H
+
+#include <stdint.h>
+
+uint8_t pci_read_byte(int bus, int dev, int func, int off);
+uint16_t pci_read_word(int bus, int dev, int func, int off);
+uint32_t pci_read_dword(int bus, int dev, int func, int off);
+void pci_write_byte(int bus, int dev, int func, int off, uint8_t value);
+void pci_write_word(int bus, int dev, int func, int off, uint16_t value);
+void pci_write_dword(int bus, int dev, int func, int off, uint32_t value);
+
+void init_pci(void);
+
+#endif