diff options
author | Alex Auvolat <alex.auvolat@ens.fr> | 2015-02-24 11:06:48 +0100 |
---|---|---|
committer | Alex Auvolat <alex.auvolat@ens.fr> | 2015-02-24 11:06:48 +0100 |
commit | 91c5969cdddf2241418082998e76bdbb836ed03e (patch) | |
tree | a4597e44f36f6fc3406e0dd2671d265bce3a7d53 /src/kernel | |
parent | 9ba449a6e5f9db20923fb9802eefe0f090ba5fff (diff) | |
download | kogata-91c5969cdddf2241418082998e76bdbb836ed03e.tar.gz kogata-91c5969cdddf2241418082998e76bdbb836ed03e.zip |
PCI enumeration ; rename dev:/ to io:/
Diffstat (limited to 'src/kernel')
-rw-r--r-- | src/kernel/Makefile | 3 | ||||
-rw-r--r-- | src/kernel/core/kmain.c | 27 | ||||
-rw-r--r-- | src/kernel/dev/pci.c | 224 | ||||
-rw-r--r-- | src/kernel/include/dev/ata.h | 7 | ||||
-rw-r--r-- | src/kernel/include/dev/pci.h | 63 | ||||
-rw-r--r-- | src/kernel/include/idt.h | 32 | ||||
-rw-r--r-- | src/kernel/include/sys.h | 10 |
7 files changed, 338 insertions, 28 deletions
diff --git a/src/kernel/Makefile b/src/kernel/Makefile index 20bbfe0..0c9a62b 100644 --- a/src/kernel/Makefile +++ b/src/kernel/Makefile @@ -2,7 +2,8 @@ OBJ = core/loader.o core/dbglog.o \ core/gdt.o core/idt.o core/interrupt.o core/context_switch.o core/thread.o \ core/frame.o core/paging.o core/region.o core/kmalloc.o core/worker.o \ - user/vfs.o user/nullfs.o user/process.o user/elf.o user/syscall.o + user/vfs.o user/nullfs.o user/process.o user/elf.o user/syscall.o \ + dev/pci.o LIB = ../common/libc/libc.lib ../common/libkogata/libkogata.lib ../common/libalgo/libalgo.lib diff --git a/src/kernel/core/kmain.c b/src/kernel/core/kmain.c index fa5d69c..c77750a 100644 --- a/src/kernel/core/kmain.c +++ b/src/kernel/core/kmain.c @@ -23,6 +23,8 @@ #include <slab_alloc.h> #include <string.h> +#include <dev/pci.h> + // ===== FOR TESTS ===== #define TEST_PLACEHOLDER_AFTER_IDT #define TEST_PLACEHOLDER_AFTER_REGION @@ -126,20 +128,23 @@ void kernel_init_stage2(void* data) { TEST_PLACEHOLDER_AFTER_TASKING; - // Create devfs + // Create iofs register_nullfs_driver(); - fs_t *devfs = make_fs("nullfs", 0, ""); - ASSERT(devfs != 0); + fs_t *iofs = make_fs("nullfs", 0, ""); + ASSERT(iofs != 0); + + // Scan for devices + pci_setup(); - // Add kernel command line to devfs + // Add kernel command line to iofs { dbg_printf("Kernel command line: '%s'\n", (char*)mbd->cmdline); size_t len = strlen((char*)mbd->cmdline); - ASSERT(nullfs_add_ram_file(devfs, "/cmdline", (char*)mbd->cmdline, len, false, FM_READ)); + ASSERT(nullfs_add_ram_file(iofs, "/cmdline", (char*)mbd->cmdline, len, false, FM_READ)); } - // Populate devfs with files for kernel modules - ASSERT(fs_create(devfs, "/mod", FT_DIR)); + // Populate iofs with files for kernel modules + ASSERT(fs_create(iofs, "/mod", FT_DIR)); multiboot_module_t *mods = (multiboot_module_t*)mbd->mods_addr; for (unsigned i = 0; i < mbd->mods_count; i++) { char* modname = (char*)mods[i].string; @@ -157,7 +162,7 @@ void kernel_init_stage2(void* data) { dbg_printf("Adding module to VFS: '%s' (size %d)\n", name, len); - ASSERT(nullfs_add_ram_file(devfs, name, + ASSERT(nullfs_add_ram_file(iofs, name, (char*)mods[i].mod_start, len, false, FM_READ)); } @@ -165,15 +170,15 @@ void kernel_init_stage2(void* data) { TEST_PLACEHOLDER_AFTER_DEVFS; // Launch INIT - fs_handle_t *init_bin = fs_open(devfs, "/mod/init.bin", FM_READ); + fs_handle_t *init_bin = fs_open(iofs, "/mod/init.bin", FM_READ); if (init_bin == 0) PANIC("No init.bin module provided!"); if (!is_elf(init_bin)) PANIC("init.bin is not valid ELF32 binary"); process_t *init_p = new_process(0); ASSERT(init_p != 0); - bool add_devfs_ok = proc_add_fs(init_p, devfs, "dev"); - ASSERT(add_devfs_ok); + bool add_iofs_ok = proc_add_fs(init_p, iofs, "io"); + ASSERT(add_iofs_ok); proc_entry_t *e = elf_load(init_bin, init_p); if (e == 0) PANIC("Could not load ELF file init.bin"); diff --git a/src/kernel/dev/pci.c b/src/kernel/dev/pci.c new file mode 100644 index 0000000..cfd2318 --- /dev/null +++ b/src/kernel/dev/pci.c @@ -0,0 +1,224 @@ +#include <string.h> + +#include <idt.h> + +#include <dev/pci.h> + +#define BUS(i) pci_devices[i].bus +#define SLOT(i) pci_devices[i].slot +#define FUNC(i) pci_devices[i].func + +static void check_bus(uint8_t); +static void pci_irq_default(registers_t*); +static void pci_irq_storage(registers_t*); +static void pci_irq_network(registers_t*); + +pci_device_t pci_devices[PCI_MAX_DEVICES]; + +// ================================= // +// READ-WRITE WITH BUS/SLOT/FUNC IDS // +// ================================= // + +static uint32_t read_config_long(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) { + uint32_t lbus = (uint32_t)bus; + uint32_t lslot = (uint32_t)slot; + uint32_t lfunc = (uint32_t)func; + + uint32_t address = (uint32_t)((lbus << 16) | (lslot << 11) | + (lfunc << 8) | (offset & 0xfc) | ((uint32_t)0x80000000)); + + /* write out the address */ + outl(0xCF8, address); + /* read in the data */ + return inl(0xCFC); +} + +static uint16_t read_config_word(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) { + uint32_t tmp = read_config_long(bus, slot, func, offset); + + return (tmp >> ((offset & 2) * 8)) & 0xFFFF; +} + +static uint8_t read_config_byte(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) { + uint32_t tmp = read_config_long(bus, slot, func, offset); + + return (tmp >> ((offset & 3) * 8)) & 0xFF; +} + +static void write_config_long(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint32_t data) { + uint32_t lbus = (uint32_t)bus; + uint32_t lslot = (uint32_t)slot; + uint32_t lfunc = (uint32_t)func; + + uint32_t address = (uint32_t)((lbus << 16) | (lslot << 11) | + (lfunc << 8) | (offset & 0xfc) | ((uint32_t)0x80000000)); + + /* write out the address */ + outl(0xCF8, address); + /* write out the data */ + outl(0xCFC, data); +} + +static void write_config_word(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint16_t d) { + uint32_t tmp = read_config_long(bus, slot, func, offset); + + int shift = (offset & 2) * 8; + uint32_t mask = 0xFFFF << shift; + tmp = (tmp & ~mask) | (d << shift); + + write_config_long(bus, slot, func, offset, tmp); +} + +static void write_config_byte(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint8_t d) { + uint32_t tmp = read_config_long(bus, slot, func, offset); + + int shift = (offset & 3) * 8; + uint32_t mask = 0xFF << shift; + tmp = (tmp & ~mask) | (d << shift); + + write_config_long(bus, slot, func, offset, tmp); +} + + +// ========================= // +// READ-WRITE WITH DEVICE ID // +// ========================= // + +uint32_t pci_read_config_long(int i, uint8_t offset) { + return read_config_long(BUS(i), SLOT(i), FUNC(i), offset); +} + +uint16_t pci_read_config_word(int i, uint8_t offset) { + return read_config_word(BUS(i), SLOT(i), FUNC(i), offset); +} + +uint8_t pci_read_config_byte(int i, uint8_t offset) { + return read_config_byte(BUS(i), SLOT(i), FUNC(i), offset); +} + +void pci_write_config_long(int i, uint8_t offset, uint32_t d) { + return write_config_long(BUS(i), SLOT(i), FUNC(i), offset, d); +} + +void pci_write_config_word(int i, uint8_t offset, uint16_t d) { + return write_config_word(BUS(i), SLOT(i), FUNC(i), offset, d); +} + +void pci_write_config_byte(int i, uint8_t offset, uint8_t d) { + return write_config_byte(BUS(i), SLOT(i), FUNC(i), offset, d); +} + +// ======================= // +// PCI ENUMERATION & SETUP // +// ======================= // + +static void check_function(uint8_t bus, uint8_t slot, uint8_t func) { + static int id = 0; + if (id >= PCI_MAX_DEVICES) return; + + pci_devices[id].bus = bus; + pci_devices[id].slot = slot; + pci_devices[id].func = func; + + pci_devices[id].vendor_id = pci_read_config_word(id, PCI_CONFIG_VENDOR_ID); + if (pci_devices[id].vendor_id == 0xFFFF) return; + + pci_devices[id].device_id = pci_read_config_word(id, PCI_CONFIG_DEVICE_ID); + pci_devices[id].base_class = pci_read_config_byte(id, PCI_CONFIG_CLASS); + pci_devices[id].sub_class = pci_read_config_byte(id, PCI_CONFIG_SUBCLASS); + pci_set_irq(id, PCI_IRQ_DEFAULT); + + dbg_printf("PCI %d:%d:%d : %x:%x %x %x (irq %d)\n", bus, slot, func, + pci_devices[id].vendor_id, pci_devices[id].device_id, + pci_devices[id].base_class, pci_devices[id].sub_class, + pci_devices[id].irq); + + if (pci_devices[id].base_class == PCI_BC_BRIDGE + && pci_devices[id].sub_class == PCI_SC_PCI_TO_PCI) + check_bus(pci_read_config_byte(id, PCI_CONFIG_SECONDARY_BUS)); + + id++; +} + +static void check_device(uint8_t bus, uint8_t device) { + uint8_t function = 0; + + uint16_t vendor_id = read_config_word(bus, device, function, PCI_CONFIG_VENDOR_ID); + if (vendor_id == 0xFFFF) return; + + check_function(bus, device, function); + + uint8_t header_type = read_config_byte(bus, device, function, PCI_CONFIG_HEADER_TYPE); + if (header_type & 0x80) { + for (function = 1; function < 8; function++) { + vendor_id = read_config_word(bus, device, function, PCI_CONFIG_VENDOR_ID); + if (vendor_id != 0xFFFF) { + check_function(bus, device, function); + } + } + } + +} + +void check_bus(uint8_t bus) { + for (uint8_t device = 0; device < 32; device++) { + check_device(bus, device); + } +} + +void pci_setup() { + for (int i = 0; i < PCI_MAX_DEVICES; i++) { + memset(&pci_devices[i], 0, sizeof(pci_device_t)); + pci_devices[i].vendor_id = 0xFFFF; // not in use; + } + + idt_set_irq_handler(PCI_IRQ_DEFAULT, pci_irq_default); + idt_set_irq_handler(PCI_IRQ_STORAGE, pci_irq_storage); + idt_set_irq_handler(PCI_IRQ_NETWORK, pci_irq_network); + + if (read_config_byte(0, 0, 0, PCI_CONFIG_HEADER_TYPE) & 0x80) { + for (uint8_t func = 0; func < 8; func++) { + if (read_config_word(0, 0, func, PCI_CONFIG_VENDOR_ID) != 0xFFFF) + check_bus(func); + } + } else { + check_bus(0); + } +} + +// ================ // +// PCI IRQ HANDLING // +// ================ // + +void pci_irq_storage(registers_t *r) { + for (int i = 0; i < PCI_MAX_DEVICES; i++) { + if (pci_devices[i].irq == PCI_IRQ_STORAGE && pci_devices[i].irq_handler != 0) + pci_devices[i].irq_handler(); + } +} + +void pci_irq_network(registers_t *r) { + for (int i = 0; i < PCI_MAX_DEVICES; i++) { + if (pci_devices[i].irq == PCI_IRQ_NETWORK && pci_devices[i].irq_handler != 0) + pci_devices[i].irq_handler(); + } +} + +void pci_irq_default(registers_t *r) { + for (int i = 0; i < PCI_MAX_DEVICES; i++) { + if (pci_devices[i].irq == PCI_IRQ_DEFAULT && pci_devices[i].irq_handler != 0) + pci_devices[i].irq_handler(); + } +} + +void pci_set_irq(int dev_id, uint8_t irq) { + if (dev_id < 0 || dev_id >= PCI_MAX_DEVICES) return; + if (irq != PCI_IRQ_DEFAULT + && irq != PCI_IRQ_STORAGE && irq != PCI_IRQ_NETWORK + && irq != PCI_IRQ_DISABLE) return; + + pci_devices[dev_id].irq = irq; + pci_write_config_byte(dev_id, PCI_CONFIG_INTERRUPT_LINE, irq); +} + +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/kernel/include/dev/ata.h b/src/kernel/include/dev/ata.h new file mode 100644 index 0000000..c0a4bff --- /dev/null +++ b/src/kernel/include/dev/ata.h @@ -0,0 +1,7 @@ +#pragma once + +#include <vfs.h> + + + +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/kernel/include/dev/pci.h b/src/kernel/include/dev/pci.h new file mode 100644 index 0000000..9fe0f3b --- /dev/null +++ b/src/kernel/include/dev/pci.h @@ -0,0 +1,63 @@ +#pragma once + +#include <sys.h> + +#define PCI_MAX_DEVICES 32 + +// IRQs 9, 10 and 11 are controlled by the PCI driver +// By default all devices are remapped to IRQ 9 +// For specific devices other IRQs may be mapped +#define PCI_IRQ_DEFAULT 9 +#define PCI_IRQ_STORAGE 10 +#define PCI_IRQ_NETWORK 11 +#define PCI_IRQ_DISABLE 0xFF + +#define PCI_CONFIG_DEVICE_ID 0x02 +#define PCI_CONFIG_VENDOR_ID 0x00 +#define PCI_CONFIG_CLASS 0x0B +#define PCI_CONFIG_SUBCLASS 0x0A +#define PCI_CONFIG_HEADER_TYPE 0x0E +#define PCI_CONFIG_SECONDARY_BUS 0x19 +#define PCI_CONFIG_INTERRUPT_LINE 0x3C + +// base classes +#define PCI_BC_STORAGE 0x01 +#define PCI_BC_BRIDGE 0x06 + +// sub-classes +#define PCI_SC_IDE 0x01 +#define PCI_SC_PCI_TO_PCI 0x04 + +typedef void (*pci_irq_handler_t)(); + +typedef struct { + uint8_t bus; + uint8_t slot; + uint8_t func; + + uint16_t device_id; + uint16_t vendor_id; + + uint8_t base_class; + uint8_t sub_class; + + uint8_t irq; + pci_irq_handler_t irq_handler; +} pci_device_t; + +extern pci_device_t pci_devices[PCI_MAX_DEVICES]; + +void pci_setup(); // does scan and sets up IRQs + +void pci_set_irq(int dev_id, uint8_t irq); // irq = 0xFF disables the IRQ for this device + +uint32_t pci_read_config_long(int dev_id, uint8_t offset); +uint16_t pci_read_config_word(int dev_id, uint8_t offset); +uint8_t pci_read_config_byte(int dev_id, uint8_t offset); + +void pci_write_config_long(int dev_id, uint8_t offset, uint32_t l); +void pci_write_config_word(int dev_id, uint8_t offset, uint16_t w); +void pci_write_config_byte(int dev_id, uint8_t offset, uint8_t b); + + +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/kernel/include/idt.h b/src/kernel/include/idt.h index 8e84cea..d9dd927 100644 --- a/src/kernel/include/idt.h +++ b/src/kernel/include/idt.h @@ -8,22 +8,22 @@ #include <config.h> -#define IRQ0 0 -#define IRQ1 1 -#define IRQ2 2 -#define IRQ3 3 -#define IRQ4 4 -#define IRQ5 5 -#define IRQ6 6 -#define IRQ7 7 -#define IRQ8 8 -#define IRQ9 9 -#define IRQ10 10 -#define IRQ11 11 -#define IRQ12 12 -#define IRQ13 13 -#define IRQ14 14 -#define IRQ15 15 +#define IRQ0 0 // PIT +#define IRQ1 1 // PCKBD +#define IRQ2 2 // not used +#define IRQ3 3 // COM2 +#define IRQ4 4 // COM1 +#define IRQ5 5 // LPT2 +#define IRQ6 6 // Floppy +#define IRQ7 7 // LPT1 +#define IRQ8 8 // CMOS RTC +#define IRQ9 9 // free -> PCI IRQ +#define IRQ10 10 // free -> PCI IRQ +#define IRQ11 11 // free -> PCI IRQ +#define IRQ12 12 // PS2 mouse +#define IRQ13 13 // FPU +#define IRQ14 14 // Primary ATA HD +#define IRQ15 15 // Secondary ATA HD #define EX_DIVIDE_ERROR 0 // No error code #define EX_DEBUG 1 // No error code diff --git a/src/kernel/include/sys.h b/src/kernel/include/sys.h index 29735fa..365e709 100644 --- a/src/kernel/include/sys.h +++ b/src/kernel/include/sys.h @@ -11,6 +11,10 @@ static inline void outw(uint16_t port, uint16_t value) { asm volatile("outw %1, %0" : : "dN"(port), "a"(value)); } +static inline void outl(uint16_t port, uint32_t value) { + asm volatile("outl %1, %0" : : "dN"(port), "a"(value)); +} + static inline uint8_t inb(uint16_t port) { uint8_t ret; asm volatile("inb %1, %0" : "=a"(ret) : "dN"(port)); @@ -23,6 +27,12 @@ static inline uint16_t inw(uint16_t port) { return ret; } +static inline uint32_t inl(uint16_t port) { + uint32_t ret; + asm volatile("inl %1, %0" : "=a"(ret) : "dN"(port)); + return ret; +} + static inline void invlpg(void* addr) { asm volatile("invlpg (%0)" : : "r"(addr) : "memory"); } |