Some stuff on PCI and IRQ routing
This commit is contained in:
@@ -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 \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user