From 706147c123d3e44ad7d07950b940f180a39998f3 Mon Sep 17 00:00:00 2001 From: Rick Rongen Date: Wed, 3 Feb 2021 22:50:39 +0100 Subject: [PATCH] feat: started pci driver structure and ide driver structure --- kernel/drivers/ide.c | 19 +++ kernel/drivers/ide.h | 10 ++ kernel/drivers/pci.c | 282 +++++++++++++++++++++++++++++++++++++++++ kernel/drivers/pci.h | 25 ++++ kernel/drivers/ports.c | 11 +- kernel/drivers/ports.h | 8 ++ kernel/kernel.c | 10 ++ kernel/libk.c | 7 + kernel/libk.h | 2 + 9 files changed, 373 insertions(+), 1 deletion(-) create mode 100644 kernel/drivers/ide.c create mode 100644 kernel/drivers/ide.h create mode 100644 kernel/drivers/pci.c create mode 100644 kernel/drivers/pci.h diff --git a/kernel/drivers/ide.c b/kernel/drivers/ide.c new file mode 100644 index 0000000..95dcc94 --- /dev/null +++ b/kernel/drivers/ide.c @@ -0,0 +1,19 @@ +// +// Created by rick on 03-02-21. +// + +#include "ide.h" +#include +#include +#include + +const char* ide_pci_driver_name = "pci-ide"; + +void ide_handle_pci_device(u8 bus, u8 slot, u8 func) { + kprint("IDE registered"); + // todo +} + +void ide_register() { + pci_register_driver(PCI_CLASS_MASS_STORAGE, PCI_SUB_CLASS_IDE, PCI_FLAG_USE_SUBCLASS, ide_handle_pci_device, ide_pci_driver_name); +} diff --git a/kernel/drivers/ide.h b/kernel/drivers/ide.h new file mode 100644 index 0000000..f29159d --- /dev/null +++ b/kernel/drivers/ide.h @@ -0,0 +1,10 @@ +// +// Created by rick on 03-02-21. +// + +#ifndef NEW_KERNEL_IDE_H +#define NEW_KERNEL_IDE_H + +void ide_register(); + +#endif //NEW_KERNEL_IDE_H diff --git a/kernel/drivers/pci.c b/kernel/drivers/pci.c new file mode 100644 index 0000000..405d4fb --- /dev/null +++ b/kernel/drivers/pci.c @@ -0,0 +1,282 @@ +// +// Created by rick on 02-02-21. +// + +#include "pci.h" + +#include +#include +#include +#include +#include + +#define PCI_CONFIG_ENABLE (1 << 31) + +#define PCI_CONFIG_SHIFT_BUS_NUMBER 16 +#define PCI_CONFIG_SHIFT_DEV_NUMBER 11 +#define PCI_CONFIG_SHIFT_FUNC_NUMBER 8 + +#define PCI_CONFIG_LINE_0 0x00 +#define PCI_CONFIG_VENDOR_ID 0x00 +#define PCI_CONFIG_DEVICE_ID 0x02 +#define PCI_CONFIG_LINE_1 0x01 +#define PCI_CONFIG_COMMAND 0x04 +#define PCI_CONFIG_STATUS 0x06 +#define PCI_CONFIG_LINE_2 0x08 +#define PCI_CONFIG_REVISION_ID 0x08 +#define PCI_CONFIG_PROG_IF 0x09 +#define PCI_CONFIG_SUBCLASS 0x0A +#define PCI_CONFIG_CLASS_CODE 0x0B +#define PCI_CONFIG_LINE_3 0x0C +#define PCI_CONFIG_CACHE_LINE_SIZE 0x0C +#define PCI_CONFIG_LATENCY_TIMER 0x0D +#define PCI_CONFIG_HEADER_TYPE 0x0E +#define PCI_CONFIG_BIST 0x0F +#define PCI_CONFIG_BAR0 0x10 +#define PCI_CONFIG_BAR1 0x14 +#define PCI_CONFIG_BAR2 0x18 +#define PCI_CONFIG_BAR3 0x1C +#define PCI_CONFIG_BAR4 0x20 +#define PCI_CONFIG_BAR5 0x24 +#define PCI_CONFIG_CARDBUS_CIS_P 0x28 +#define PCI_CONFIG_SUBSYSTEM_VENDOR_ID 0x2C +#define PCI_CONFIG_SUBSYSTEM_ID 0x2E +#define PCI_CONFIG_EXPANSION_ROM_ADDR 0x30 +#define PCI_CONFIG_CAP_POINTER 0x34 +#define PCI_CONFIG_INTERRUPT_LINE 0x3C +#define PCI_CONFIG_INTERRUPT_PIN 0x3D +#define PCI_CONFIG_MAX_GRANT 0x3E +#define PCI_CONFIG_MAX_LATENCY 0x3F + +#define PCI_HEADER_TYPE_MULTI_FUNC 0x80 + +#define MAX_PCI_DRIVERS 64 +#define MAX_PCI_DEVICES 64 + +typedef struct { + pci_driver driver; + const char *driver_name; + u8 pci_class; + u8 pci_subclass; + union { + u8 flags; + struct { + u8 pci_use_subclass: 1; + }; + }; +} pci_driver_info; + +typedef struct { + u8 bus; + u8 slot; + u8 func; + union { + struct { + u16 vendorId; + u16 deviceId; + }; + u32 config_line_0; + }; + union { + struct { + u8 revisionId; + u8 programInterface; + u8 subclass; + u8 class; + }; + u32 config_line_2; + }; + union { + struct { + u8 cacheLineSize; + u8 latencyTimer; + u8 headerType; + u8 bist; + }; + u32 config_line_3; + }; + pci_driver_info *driver_info; +} pci_device; + +pci_driver_info pci_drivers[MAX_PCI_DRIVERS]; +int last_pci_device_index = 0; +pci_device pci_devices[MAX_PCI_DEVICES]; + +u32 pci_register_driver(u8 pci_class, u8 pci_subclass, u8 flags, pci_driver driver, const char *driver_name) { + for (int i = 0; i < MAX_PCI_DRIVERS; ++i) { + if (pci_drivers[i].driver == NULL) { + pci_drivers[i].driver = driver; + pci_drivers[i].pci_class = pci_class; + pci_drivers[i].pci_subclass = pci_subclass; + pci_drivers[i].flags = flags; + pci_drivers[i].driver_name = driver_name; + return PCI_REGISTER_OK; + } + } + return PCI_REGISTER_ERR_FULL; +} + + +u32 pci_config_read_double_word(u8 bus, u8 slot, u8 func, u8 offset) { + u32 address = PCI_CONFIG_ENABLE + | ((u32) bus << PCI_CONFIG_SHIFT_BUS_NUMBER) + | ((u32) slot << PCI_CONFIG_SHIFT_DEV_NUMBER) + | ((u32) func << PCI_CONFIG_SHIFT_FUNC_NUMBER) + | (offset & 0xFC); + port_double_word_out(PORT_PCI_CONFIG_ADDRESS, address); + return port_double_word_in(PORT_PCI_CONFIG_DATA); +} + +u16 pci_config_read_word(u8 bus, u8 slot, u8 func, u8 offset) { + u32 address = PCI_CONFIG_ENABLE + | ((u32) bus << PCI_CONFIG_SHIFT_BUS_NUMBER) + | ((u32) slot << PCI_CONFIG_SHIFT_DEV_NUMBER) + | ((u32) func << PCI_CONFIG_SHIFT_FUNC_NUMBER) + | (offset & 0xFC); + port_double_word_out(PORT_PCI_CONFIG_ADDRESS, address); + return port_double_word_in(PORT_PCI_CONFIG_DATA) >> ((offset & 2) * 8) & 0xFFFF; +} + +u8 pci_config_read_byte(u8 bus, u8 slot, u8 func, u8 offset) { + u32 address = PCI_CONFIG_ENABLE + | ((u32) bus << PCI_CONFIG_SHIFT_BUS_NUMBER) + | ((u32) slot << PCI_CONFIG_SHIFT_DEV_NUMBER) + | ((u32) func << PCI_CONFIG_SHIFT_FUNC_NUMBER) + | (offset & 0xFC); + port_double_word_out(PORT_PCI_CONFIG_ADDRESS, address); + return port_double_word_in(PORT_PCI_CONFIG_DATA) >> ((offset & 0b11) * 8) & 0xFF; +} + +u16 pci_get_vendor_id(u8 bus, u8 slot, u8 func) { + return pci_config_read_word(bus, slot, func, PCI_CONFIG_VENDOR_ID); +} + +u16 pci_get_device_id(u8 bus, u8 slot, u8 func) { + return pci_config_read_word(bus, slot, func, PCI_CONFIG_DEVICE_ID); +} + +u8 pci_get_prog_if(u8 bus, u8 slot, u8 func) { + return pci_config_read_byte(bus, slot, func, PCI_CONFIG_PROG_IF); +} + +u8 pci_get_header_type(u8 bus, u8 slot, u8 func) { + return pci_config_read_byte(bus, slot, func, PCI_CONFIG_HEADER_TYPE); +} + +u8 pci_get_class_code(u8 bus, u8 slot, u8 func) { + return pci_config_read_byte(bus, slot, func, PCI_CONFIG_CLASS_CODE); +} + +u8 pci_get_subclass_code(u8 bus, u8 slot, u8 func) { + return pci_config_read_byte(bus, slot, func, PCI_CONFIG_SUBCLASS); +} + +void print_u8(u8 val) { + char buf[3]; + itoa(val, buf, 16); + kprint(buf); +} + +void print_u16(u16 val) { + char buf[5]; + itoa(val, buf, 16); + kprint(buf); +} + +void pci_pick_driver(pci_device *device) { + for (int i = 0; i < MAX_PCI_DRIVERS; ++i) { + if (pci_drivers[i].driver == NULL) { + continue; + } + if (device->class == pci_drivers[i].pci_class) { + if (!pci_drivers[i].pci_use_subclass || device->subclass == pci_drivers[i].pci_subclass) { + pci_drivers[i].driver(device->bus, device->slot, device->func); + device->driver_info = &pci_drivers[i]; + } + } + } +} + +void pci_check_function(u8 bus, u8 slot, u8 func) { + pci_devices[last_pci_device_index].bus = bus; + pci_devices[last_pci_device_index].slot = slot; + pci_devices[last_pci_device_index].func = func; + pci_devices[last_pci_device_index].config_line_0 = pci_config_read_double_word(bus, slot, func, PCI_CONFIG_LINE_0); + pci_devices[last_pci_device_index].config_line_2 = pci_config_read_double_word(bus, slot, func, PCI_CONFIG_LINE_2); + pci_devices[last_pci_device_index].config_line_3 = pci_config_read_double_word(bus, slot, func, PCI_CONFIG_LINE_3); + pci_pick_driver(&pci_devices[last_pci_device_index]); + last_pci_device_index++; + + // todo do something with the function +} + +void pci_check_device(u8 bus, u8 device) { + u8 function = 0; + u16 vendor_id = pci_get_vendor_id(bus, device, function); + if (vendor_id == 0xFFFF) return; + pci_check_function(bus, device, function); + u8 header_type = pci_get_header_type(bus, device, function); + if (header_type & PCI_HEADER_TYPE_MULTI_FUNC) { + for (function = 1; function < 8; ++function) { + if (pci_get_vendor_id(bus, device, function) != 0xFFFF) { + pci_check_function(bus, device, function); + } + } + } +} + +void pci_check_bus(u8 bus) { + for (int device = 0; device < 32; ++device) { + pci_check_device(bus, device); + } +} + +void pci_scan() { + if (last_pci_device_index != 0) { + k_panics("Can only scan once!"); + } + u8 header_type = pci_get_header_type(0, 0, 0); + if (header_type & PCI_HEADER_TYPE_MULTI_FUNC) { + // multiple pci host controllers + for (int function = 0; function < 8; ++function) { + pci_check_bus(function); + } + } else { + pci_check_bus(0); + } +} + +void pci_print_info() { + for (int i = 0; i < last_pci_device_index; ++i) { + kprint("PCI BSF: "); + print_u8(pci_devices[i].bus); + kprint("/"); + print_u8(pci_devices[i].slot); + kprint("/"); + print_u8(pci_devices[i].func); + kprint(", Class/Sub/If: "); + print_u8(pci_devices[i].class); + kprint("/"); + print_u8(pci_devices[i].subclass); + kprint("/"); + print_u8(pci_devices[i].programInterface); + + kprint(", V/D: "); + print_u16(pci_devices[i].vendorId); + kprint("/"); + print_u16(pci_devices[i].deviceId); + kprint(" driver_info: "); + + if (pci_devices[i].driver_info == NULL) { + kprint("NULL"); + } else { + kprint(pci_devices[i].driver_info->driver_name); + } + + kprint("\n"); + } +} + +// todo https://wiki.osdev.org/PCI +// todo https://wiki.osdev.org/PCI_IDE_Controller +// todo https://wiki.osdev.org/Universal_Serial_Bus if i dare \ No newline at end of file diff --git a/kernel/drivers/pci.h b/kernel/drivers/pci.h new file mode 100644 index 0000000..7e4fecb --- /dev/null +++ b/kernel/drivers/pci.h @@ -0,0 +1,25 @@ +// +// Created by rick on 02-02-21. +// + +#ifndef NEW_KERNEL_PCI_H +#define NEW_KERNEL_PCI_H +#include + +#define PCI_CLASS_MASS_STORAGE 0x01 + +#define PCI_SUB_CLASS_IDE 0x01 + +#define PCI_FLAG_USE_SUBCLASS (1 << 0) +#define PCI_REGISTER_OK 0; +#define PCI_REGISTER_ERR_FULL -1; + +typedef void (*pci_driver)(u8 bus, u8 slot, u8 func); + +void pci_print_info(); + +u32 pci_register_driver(u8 pci_class, u8 pci_subclass, u8 flags, pci_driver driver, const char *driver_name); + +void pci_scan(); + +#endif //NEW_KERNEL_PCI_H diff --git a/kernel/drivers/ports.c b/kernel/drivers/ports.c index 9837225..4c7ad14 100644 --- a/kernel/drivers/ports.c +++ b/kernel/drivers/ports.c @@ -28,6 +28,15 @@ unsigned short port_word_in(unsigned short port) { return result; } -void port_wordt_out(unsigned short port, unsigned short data) { +void port_word_out(unsigned short port, unsigned short data) { __asm__("out %%ax, %%dx" : : "a" (data), "d" (port)); } +unsigned int port_double_word_in(unsigned int port) { + unsigned int result; + __asm__("in %%dx, %%eax" : "=a" (result) : "d" (port)); + return result; +} + +void port_double_word_out(unsigned short port, unsigned int data) { + __asm__("out %%eax, %%dx" : : "a" (data), "d" (port)); +} diff --git a/kernel/drivers/ports.h b/kernel/drivers/ports.h index 11db0a0..28f341e 100644 --- a/kernel/drivers/ports.h +++ b/kernel/drivers/ports.h @@ -40,6 +40,10 @@ #define PORT_PS2_STATUS 0x64 #define PORT_PS2_COMMAND 0x64 +// https://wiki.osdev.org/PCI +#define PORT_PCI_CONFIG_ADDRESS (0xCF8) +#define PORT_PCI_CONFIG_DATA (0xCFC) + unsigned char port_byte_in(unsigned short port); void port_byte_out(unsigned short port, unsigned char data); @@ -48,4 +52,8 @@ unsigned short port_word_in(unsigned short port); void port_word_out(unsigned short port, unsigned short data); +unsigned int port_double_word_in(unsigned int port); + +void port_double_word_out(unsigned short port, unsigned int data); + #endif diff --git a/kernel/kernel.c b/kernel/kernel.c index b4fd934..7a80aad 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include #define BOOTLOADER_NAME_MAX_LENGTH 64 #define CMDLINE_MAX_LENGTH 256 @@ -78,6 +80,8 @@ void print(const char *arg) { print_current_tick(); } else if (strcmp(arg, "bootinfo") == 0) { print_bootinfo(); + } else if (strcmp(arg, "pci") == 0) { + pci_print_info(); } else { kprint("Unknown print "); kprint(arg); @@ -129,6 +133,12 @@ void kmain(multiboot_info_t *multiboot_info) { store_bootloader_info(multiboot_info); init_mmap(multiboot_info); + // register drivers + ide_register(); + + // scan PCI + pci_scan(); + kprint(msg_booted); kprint(newline); diff --git a/kernel/libk.c b/kernel/libk.c index 66f6191..f38a573 100644 --- a/kernel/libk.c +++ b/kernel/libk.c @@ -9,6 +9,13 @@ void k_wait_for_interrupt() { __asm__ __volatile__("hlt;"); } +void k_panics(const char* msg) { + kprint(msg); + kprint("PANIC!"); + __asm__ __volatile__("cli;" + "hlt;"); +} + void k_panic() { kprint("PANIC!"); __asm__ __volatile__("cli;" diff --git a/kernel/libk.h b/kernel/libk.h index f78d12f..9438332 100644 --- a/kernel/libk.h +++ b/kernel/libk.h @@ -7,6 +7,8 @@ void k_wait_for_interrupt(); +void k_panics(const char* msg); + void k_panic(); #endif //NEW_KERNEL_LIBK_H