From 6fe3cfc69087217425b0408fc43ecd59f08ca66e Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 15 Oct 2019 11:55:40 +0300 Subject: [PATCH] Some stuff on PCI and IRQ routing --- etc/make/amd64/conf.mk | 2 + etc/make/amd64/platform.mk | 6 +- include/sys/amd64/hw/pci/pci.h | 12 ++++ sys/amd64/hw/ioapic.c | 105 +++++++++++++++++++++++++++++++++ sys/amd64/hw/pci/pci.c | 62 +++++++++++++++++++ sys/amd64/kernel.c | 2 + 6 files changed, 187 insertions(+), 2 deletions(-) create mode 100644 include/sys/amd64/hw/pci/pci.h create mode 100644 sys/amd64/hw/pci/pci.c diff --git a/etc/make/amd64/conf.mk b/etc/make/amd64/conf.mk index adc6a48..d78a86e 100644 --- a/etc/make/amd64/conf.mk +++ b/etc/make/amd64/conf.mk @@ -75,6 +75,8 @@ QEMU_BIN?=qemu-system-x86_64 QEMU_OPTS?=-serial mon:stdio \ -m $(QEMU_MEM) \ --accel tcg,thread=multi \ + -netdev type=user,id=net0 \ + -device rtl8139,netdev=net0 \ -smp $(QEMU_SMP) $(O)/sys/amd64/image.iso: $(O)/sys/amd64/kernel.elf \ diff --git a/etc/make/amd64/platform.mk b/etc/make/amd64/platform.mk index 5a34479..b8dad22 100644 --- a/etc/make/amd64/platform.mk +++ b/etc/make/amd64/platform.mk @@ -27,7 +27,8 @@ OBJS+=$(O)/sys/amd64/hw/rs232.o \ $(O)/sys/amd64/mm/pool.o \ $(O)/sys/amd64/syscall_s.o \ $(O)/sys/amd64/syscall.o \ - $(O)/sys/amd64/sys/thread.o + $(O)/sys/amd64/sys/thread.o \ + $(O)/sys/amd64/hw/pci/pci.o kernel_OBJS=$(O)/sys/amd64/entry.o \ $(OBJS) @@ -59,4 +60,5 @@ kernel_CFLAGS=-ffreestanding \ DIRS+=$(O)/sys/amd64/image/boot/grub \ $(O)/sys/amd64/hw \ $(O)/sys/amd64/sys \ - $(O)/sys/amd64/mm + $(O)/sys/amd64/mm \ + $(O)/sys/amd64/hw/pci diff --git a/include/sys/amd64/hw/pci/pci.h b/include/sys/amd64/hw/pci/pci.h new file mode 100644 index 0000000..6ccfd55 --- /dev/null +++ b/include/sys/amd64/hw/pci/pci.h @@ -0,0 +1,12 @@ +#pragma once +#include "sys/types.h" + +#define PCI_PORT_CONFIG_ADDR 0xCF8 +#define PCI_PORT_CONFIG_DATA 0xCFC + +#define PCI_ID(vnd, dev) (((uint32_t) (vnd)) | ((uint32_t) (dev) << 16)) + +uint32_t pci_config_read_dword(uint8_t bus, uint8_t slot, uint8_t func, uint8_t off); +uint16_t pci_config_read_word(uint8_t bus, uint8_t slot, uint8_t func, uint8_t off); + +void pci_enumerate(void); diff --git a/sys/amd64/hw/ioapic.c b/sys/amd64/hw/ioapic.c index 322e0bb..8f3a6e8 100644 --- a/sys/amd64/hw/ioapic.c +++ b/sys/amd64/hw/ioapic.c @@ -1,6 +1,37 @@ #include "sys/amd64/hw/ioapic.h" +#include "sys/string.h" +#include "sys/mm.h" #include "sys/debug.h" +struct pir_slot_entry { + uint8_t pci_bus; + uint8_t pci_dev; + uint8_t inta_link; + uint16_t inta_bitmap; + uint8_t intb_link; + uint16_t intb_bitmap; + uint8_t intc_link; + uint16_t intc_bitmap; + uint8_t intd_link; + uint16_t intd_bitmap; + uint8_t slot_number; + char __res0; +} __attribute__((packed)); + +struct pir_table { + char signature[4]; + uint16_t version; + uint16_t table_size; + uint8_t pci_router_bus; + uint8_t pci_router_dev_func; + uint16_t pci_exc_irqs; + uint32_t compat_pci_router; + uint32_t miniport_data; + char __res0[11]; + uint8_t checksum; + struct pir_slot_entry entries[]; +} __attribute__((packed)); + uintptr_t amd64_ioapic_base = 0; // Legacy PIC -> I/O APIC routing table @@ -54,6 +85,78 @@ void amd64_ioapic_int_src_override(uint8_t bus_src, uint8_t irq_src, uint32_t no amd64_ioapic_write(0x10 + no * 2, low); } +static void amd64_pir_dump(struct pir_table *table) { + uint8_t checksum = 0; + for (size_t i = 0; i < table->table_size; ++i) { + checksum += ((uint8_t *) table)[i]; + } + if (checksum != 0) { + kerror("$PIR checksum is invalid\n"); + return; + } + size_t nentr = (table->table_size - sizeof(struct pir_table)) / sizeof(struct pir_slot_entry); + + kdebug("$PIR: %lu entries:\n", nentr); + kdebug(" # BUS DEV PIN LINK IRQs\n"); + for (size_t i = 0; i < nentr; ++i) { + struct pir_slot_entry *ent = &table->entries[i]; + uint8_t pin = 0xFF; + uint8_t link = 0x00; + uint16_t bitmap = 0x0000; + + if (ent->inta_link != 0) { + pin = 0; + link = ent->inta_link; + bitmap = ent->inta_bitmap; + } else if (ent->intb_link != 0) { + pin = 1; + link = ent->intb_link; + bitmap = ent->intb_bitmap; + } else if (ent->intc_link != 0) { + pin = 2; + link = ent->intc_link; + bitmap = ent->intc_bitmap; + } else if (ent->intd_link != 0) { + pin = 3; + link = ent->intd_link; + bitmap = ent->intd_bitmap; + } + kdebug("[%02d] %02d %02d %2c %02x ", + i, + ent->pci_bus, + ent->pci_dev >> 3, + (pin == 0xFF ? '?' : 'A' + pin), + link); + for (uint8_t i = 0; i < 16; ++i) { + if (bitmap & (1 << i)) { + // Weird ways + char n[3] = {0}; + if (i > 10) { + n[1] = i % 10 + '0'; + n[0] = i / 10 + '0'; + } else { + n[0] = i % 10 + '0'; + } + debugs(DEBUG_DEFAULT, n); + debugc(DEBUG_DEFAULT, ' '); + } + } + debugc(DEBUG_DEFAULT, '\n'); + } +} + +static int amd64_find_pir_table(void) { + for (uintptr_t addr = MM_VIRTUALIZE(0xF0000); addr < MM_VIRTUALIZE(0x100000); ++addr) { + if (!strncmp((const char *) addr, "$PIR", 4)) { + kdebug("Found $PIR @ %p\n", addr); + + amd64_pir_dump((struct pir_table *) addr); + break; + } + } + return 0; +} + void amd64_ioapic_set(uintptr_t addr) { if (amd64_ioapic_base != 0) { // TODO: panic @@ -101,4 +204,6 @@ void amd64_ioapic_set(uintptr_t addr) { amd64_ioapic_write(0x10 + 1 * 2, low); amd64_ioapic_write(0x11 + 1 * 2, high); + + amd64_find_pir_table(); } diff --git a/sys/amd64/hw/pci/pci.c b/sys/amd64/hw/pci/pci.c new file mode 100644 index 0000000..1a53d8e --- /dev/null +++ b/sys/amd64/hw/pci/pci.c @@ -0,0 +1,62 @@ +#include "sys/amd64/hw/pci/pci.h" +#include "sys/amd64/hw/io.h" +#include "sys/debug.h" + +uint32_t pci_config_read_dword(uint8_t bus, uint8_t slot, uint8_t func, uint8_t off) { + uint32_t w0; + w0 = ((uint32_t) bus << 16) | + ((uint32_t) slot << 11) | + ((uint32_t) func << 8) | + ((uint32_t) off & ~0x3) | + (1 << 31); + + outl(PCI_PORT_CONFIG_ADDR, w0); + w0 = inl(PCI_PORT_CONFIG_DATA); + + return w0; +} + +static void pci_enumerate_func(uint8_t bus, uint8_t dev, uint8_t func) { + uint32_t id = pci_config_read_dword(bus, dev, func, 0); + uint32_t kind = pci_config_read_dword(bus, dev, func, 8); + uint32_t irq = pci_config_read_dword(bus, dev, func, 0x3C); + + // First find devices matching known IDs + switch (id) { + case PCI_ID(0x10EC, 0x8139): + // Think I'll implement this later + kdebug("rtl8139\n"); + kdebug("INT%c#%d\n", ('A' + ((irq >> 8) & 0xFF) - 1), irq & 0xFF); + break; + } + + // Check for generic-driver devices + switch (kind >> 16) { + case 0x0101: + kdebug("IDE drive controller\n"); + break; + } +} + +static void pci_enumerate_dev(uint8_t bus, uint8_t dev) { + // Check function 0 + uint32_t w0 = pci_config_read_dword(bus, dev, 0, 0); + if ((w0 & 0xFFFF) == 0xFFFF) { + // No functions here + return; + } + + for (uint8_t func = 0; func < 8; ++func) { + if (!func || (((w0 = pci_config_read_dword(bus, dev, func, 0)) & 0xFFFF) != 0xFFFF)) { + pci_enumerate_func(bus, dev, func); + } + } +} + +void pci_enumerate(void) { + for (uint8_t bus = 0; bus < 255; ++bus) { + for (uint8_t dev = 0; dev < 32; ++dev) { + pci_enumerate_dev(bus, dev); + } + } +} diff --git a/sys/amd64/kernel.c b/sys/amd64/kernel.c index ec73f63..1f42e46 100644 --- a/sys/amd64/kernel.c +++ b/sys/amd64/kernel.c @@ -6,6 +6,7 @@ #include "sys/amd64/mm/mm.h" #include "sys/amd64/mm/phys.h" #include "sys/amd64/hw/acpi.h" +#include "sys/amd64/hw/pci/pci.h" static multiboot_info_t *multiboot_info; @@ -19,6 +20,7 @@ void kernel_main(struct amd64_loader_data *data) { amd64_gdt_init(); amd64_idt_init(); amd64_mm_init(data); + pci_enumerate(); extern void sched_init(void); sched_init();