diff --git a/kernel/acpi/acpi.c b/kernel/acpi/acpi.c index 722651b..516c64c 100644 --- a/kernel/acpi/acpi.c +++ b/kernel/acpi/acpi.c @@ -4,21 +4,24 @@ #include "acpi.h" +#include "acpitables.h" + #include "../lib/common.h" #include "../lib/assert.h" #include "../lib/dump.h" #include "../lib/sprintf.h" #include "../lib/string.h" -#include "acpitables.h" #include "../int/apic.h" +#include "../lib/logging.h" + #include "../memory/vmap.h" #include "../memory/paging.h" -#include "../drivers/pcie.h" -#include "../lib/logging.h" + +#include "../drivers/pcie/scan.h" static void* apic_config_base, *hpet_config_space; -// defined in pcie.c +// defined in pcie/scan.c extern struct PCIE_Descriptor pcie_descriptor; static const struct XSDT* xsdt; @@ -187,7 +190,7 @@ static void parse_pcie(const struct PCIETable* table) { // fill the pcie driver's descriptor size_t size = (table->header.length-sizeof(struct ACPISDTHeader)-8); - pcie_descriptor.size = size / sizeof(struct PCIE_segment_group_descriptor); + pcie_descriptor.size = size / sizeof(struct PCIE_busgroup); assert(pcie_descriptor.size < PCIE_SUPPORTED_SEGMENT_GROUPS); diff --git a/kernel/acpi/acpitables.h b/kernel/acpi/acpitables.h index c77e316..71999c7 100644 --- a/kernel/acpi/acpitables.h +++ b/kernel/acpi/acpitables.h @@ -4,7 +4,7 @@ #include #include "../lib/common.h" -#include "../drivers/pcie.h" +#include "../drivers/pcie/scan.h" struct RSDPDescriptor { uint8_t signature[8]; @@ -141,13 +141,13 @@ struct MADT { static_assert( - sizeof(struct PCIE_segment_group_descriptor) == 16); + sizeof(struct PCIE_busgroup) == 16); struct PCIETable { struct ACPISDTHeader header; uint64_t reserved0; - struct PCIE_segment_group_descriptor segments[]; + struct PCIE_busgroup segments[]; } __packed; diff --git a/kernel/drivers/pcie.c b/kernel/drivers/pcie.c deleted file mode 100644 index 5766e19..0000000 --- a/kernel/drivers/pcie.c +++ /dev/null @@ -1,252 +0,0 @@ -#include "pcie.h" -#include "../lib/logging.h" -#include "../lib/dump.h" -#include "../lib/assert.h" -#include "../memory/heap.h" -#include "../memory/paging.h" -#include "../lib/string.h" - - -struct PCIE_configuration_space { - volatile uint16_t vendorID; - volatile uint16_t deviceID; - uint16_t unused0; - uint16_t unused1; - volatile uint8_t revID; - volatile uint8_t progIF; - volatile uint8_t subclasscode; - volatile uint8_t classcode; - volatile uint32_t infos; - volatile uint64_t bar[3]; - volatile uint32_t cardbud_cis_ptr; - volatile uint16_t subsystemID; - volatile uint16_t subsystem_vendorID; - volatile uint32_t expansion_base; - volatile uint8_t capabilities; - uint8_t reserved0[3]; - uint32_t reserved1; - volatile uint8_t interrupt_line; - volatile uint8_t interrupt_pin; - uint16_t reserved2[2]; -}; - -// higher bus number: could be 0xff -// if there is only one bus group -static size_t max_bus = 0; - -struct PCIE_Descriptor pcie_descriptor = {0}; -// 0 | group | bus | 0 | slot | 0 | func | -// | 2 | 8 | 1 | 3 | 1 | 3 | -// 16 8 - -static struct PCIE_segment_group_descriptor* get_segment_group(unsigned bus) { - struct PCIE_segment_group_descriptor* group = &pcie_descriptor.array[0]; - - unsigned group_number = 0; - unsigned start_bus, end_bus; - -// go through all segment groups -// if the bus is not in the range, -// it is not the right segment - - while((start_bus = group->start_bus) > bus - || (end_bus = group->end_bus) < bus) { - - assert(group_number != pcie_descriptor.size); - - group_number++; - group++; - } - return group; -} - -static struct PCIE_configuration_space* __attribute__((pure)) get_config_space_base( - unsigned bus, - unsigned device, - unsigned func - ) { - struct PCIE_segment_group_descriptor* group_desc = get_segment_group(bus); - - return group_desc->address + ( - (bus - group_desc->start_bus) << 20 - | device << 15 - | func << 12); -} - - -static int __attribute__((pure)) get_vendorID(unsigned bus, unsigned device, unsigned func) { - struct PCIE_configuration_space* config_space = get_config_space_base(bus,device,func); - - return config_space->vendorID; -} - - -struct pcie_device_descriptor { - uint16_t bus, device, function; - struct PCIE_configuration_space* config_space; -}; - -// array of all installed devices' functions -static struct pcie_device_descriptor* found_devices = NULL; -static size_t n_found_devices = 0; - - -/** - * constructs the found_devices array - */ -static void scan_devices(void) { - - // first create a linked list - // as we dont know how many devices are present - struct device_desc_node { - struct pcie_device_descriptor e; - struct device_desc_node* next; - }; - -// head of the list - struct device_desc_node ghost_node = {.next = NULL}; - struct device_desc_node* current = &ghost_node; -// count the number of devices - - void insert( - unsigned bus, - unsigned device, - unsigned func, - struct PCIE_configuration_space* config_space - ) - { - current->next = malloc(sizeof(struct device_desc_node)); - - current = current->next; - current->next = NULL; - - // fill the new node - current->e.bus = bus; - current->e.device = device; - current->e.function = func; - current->e.config_space = config_space; - - n_found_devices++; - } - - - for(unsigned bus = 0; bus < max_bus; bus++) { - for(unsigned device = 0; device < 32; device++) { - - // if the first function doesn't exist, so does - // the device - uint16_t vendorID = get_vendorID(bus,device, 0); - if(vendorID == 0xFFFF) - continue; - - insert(bus, - device, - 0, - get_config_space_base(bus,device,0) - ); - - for(unsigned func = 1; func < 8; func++) { - - if(get_vendorID(bus,device, func) != vendorID) - continue; - - insert(bus, - device, - func, - get_config_space_base(bus,device,func) - ); - } - } - } - - - // now create the final array - found_devices = malloc( - n_found_devices - * sizeof(struct pcie_device_descriptor)); - - - // now fill it and free the devices structure - struct pcie_device_descriptor* ptr = found_devices; - - for(struct device_desc_node* device = ghost_node.next; - device != NULL; - ) { - - memcpy(ptr++, &device->e, sizeof(struct pcie_device_descriptor)); - - - struct device_desc_node* next = device->next; - free(device); - device = next; - } -} -// identity map every page that might be a config space -static void identity_map_possible_config_spaces(void) { - for(unsigned i = 0; i < pcie_descriptor.size; i++) { - - // identity map the corresponding pages - map_pages( - (uint64_t)pcie_descriptor.array[i].address, // phys - (uint64_t)pcie_descriptor.array[i].address, // virt - 256 * // busses - 32 * // devices - 8, // functions - PRESENT_ENTRY | PCD | PL_XD - // no cache, execute disable - ); - } -} - -static void identity_unmap_possible_config_spaces(void) { - for(unsigned i = 0; i < pcie_descriptor.size; i++) - unmap_pages((uint64_t)pcie_descriptor.array[i].address, 256 * 32 * 8); -} - -/** - * during the init, - * we identity map the pcie configuration spaces - * - */ -void pcie_init(void) { - - log_debug("init pcie..."); - - // calculate the highest bus number - - for(unsigned i = 0; i < pcie_descriptor.size; i++) { - // map the corresponding pages - if(pcie_descriptor.array[i].end_bus > max_bus) - max_bus = pcie_descriptor.array[i].end_bus; - } - - log_debug("%u PCIE bus groups found", pcie_descriptor.size); - - identity_map_possible_config_spaces(); - scan_devices(); - - - for(unsigned i = 0; i < n_found_devices; i++) { - - log_warn("%2x:%2x:%2x: %2x:%2x:%2x, rev %2x, " - "vendor 0x%4x", - - found_devices[i].bus, - found_devices[i].device, - found_devices[i].function, - - found_devices[i].config_space->classcode, - found_devices[i].config_space->subclasscode, - found_devices[i].config_space->progIF, - found_devices[i].config_space->revID, - - found_devices[i].config_space->vendorID - ); - } - - identity_unmap_possible_config_spaces(); - log_info("found %u PCI Express devices", n_found_devices); -} - -void pcie_init_devices(void) { -} \ No newline at end of file diff --git a/kernel/drivers/pcie.h b/kernel/drivers/pcie.h deleted file mode 100644 index bbf181f..0000000 --- a/kernel/drivers/pcie.h +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once - -#include -#include -#include "../lib/assert.h" - -struct PCIE_segment_group_descriptor { - void* address; // Base address - // of enhanced configuration mechanism - uint16_t group; // PCI Segment Group Number - uint8_t start_bus; // Start PCI bus number - // decoded by this host bridge - uint8_t end_bus; // End PCI bus number - // decoded by this host bridge - uint32_t reserved; -} __attribute__((packed)); - -static_assert(sizeof(struct PCIE_segment_group_descriptor) == 16); - - -#define PCIE_SUPPORTED_SEGMENT_GROUPS 2 -struct PCIE_Descriptor { - size_t size; - struct PCIE_segment_group_descriptor array[PCIE_SUPPORTED_SEGMENT_GROUPS]; - // we only handle PCIE devices with only 4 segment groups max -}; - - -// defined in pcie.c -extern struct PCIE_Descriptor pcie_descriptor; - - -void pcie_init(void); -void pcie_scan(void); -void pcie_init_devices(void); - - - -typedef void (*driver_init_fun)(void* config_space); -typedef void (*driver_callback)(void); - -struct driver_descriptor { - driver_init_fun install; - driver_callback remove; - - const char* driver_name; - uint32_t status; - - void* driver_data; - size_t driver_data_len; -}; - - -/** - * PCIE drivers interfaces: - * - * provide void init(void* config_space_base) - * - * functions to call: - * register_irq(unsigned) - * unregister_irq(unsigned) - * - * int register_timer(void callback(void), unsigned period) - * void unregister_timer(int timer_id) - * - */ - diff --git a/kernel/drivers/pcie/pcie.c b/kernel/drivers/pcie/pcie.c new file mode 100644 index 0000000..5105b48 --- /dev/null +++ b/kernel/drivers/pcie/pcie.c @@ -0,0 +1,18 @@ +#include "pcie.h" +#include "../../lib/logging.h" +#include "../../lib/dump.h" +#include "../../lib/assert.h" +#include "../../memory/heap.h" +#include "../../memory/paging.h" +#include "../../lib/string.h" + + +static struct pcie_device* devices = NULL; + +void pcie_init(void) { + devices = pcie_scan(); +} + + +void pcie_init_devices(void) { +} \ No newline at end of file diff --git a/kernel/drivers/pcie/pcie.h b/kernel/drivers/pcie/pcie.h new file mode 100644 index 0000000..9fda246 --- /dev/null +++ b/kernel/drivers/pcie/pcie.h @@ -0,0 +1,86 @@ +#pragma once + +#include +#include + +#include "../../lib/assert.h" + +void pcie_init(void); +void pcie_init_devices(void); + + + +typedef void (*driver_init_fun)(void* config_space); +typedef void (*driver_callback)(void); + +struct resource { + void* addr; + size_t size; +}; + +typedef union { + struct { + unsigned domain: 32; + + unsigned unused: 8; + + unsigned bus: 8; + unsigned device: 8; + unsigned func: 8; + }; + uint64_t value; + +} pcie_path_t; + +struct dev_info { + uint16_t vendorID; + uint16_t deviceID; + + uint8_t classcode; + uint8_t subclasscode; + uint8_t progIF; + uint8_t revID; +}; + +static_assert_equals(sizeof(pcie_path_t), 8); + + +struct pcie_dev { + struct resource bars[3]; + struct dev_info info; + + void* config_space; + + pcie_path_t path; + + struct driver* driver; + +}; + +struct driver { + driver_init_fun install; + driver_callback remove; + + const char* driver_name; + uint32_t status; + + + struct resource data; + const struct pcie_device* dev; +}; + + +/** + * PCIE drivers interfaces: + * + * provide void init(void* config_space_base) + * + * functions to call: + * register_irq(unsigned) + * unregister_irq(unsigned) + * + * int register_timer(void callback(void), unsigned period) + * void unregister_timer(int timer_id) + * + */ + diff --git a/kernel/drivers/pcie/scan.c b/kernel/drivers/pcie/scan.c new file mode 100644 index 0000000..ae65d5b --- /dev/null +++ b/kernel/drivers/pcie/scan.c @@ -0,0 +1,325 @@ +#include "scan.h" +#include "pcie.h" +#include "../../lib/logging.h" +#include "../../lib/dump.h" +#include "../../lib/assert.h" +#include "../../memory/heap.h" +#include "../../memory/paging.h" +#include "../../lib/string.h" + + +struct PCIE_config_space { + volatile uint16_t vendorID; + volatile uint16_t deviceID; + uint16_t unused0; + uint16_t unused1; + volatile uint8_t revID; + volatile uint8_t progIF; + volatile uint8_t subclasscode; + volatile uint8_t classcode; + volatile uint32_t infos; + volatile uint64_t bar[3]; + volatile uint32_t cardbud_cis_ptr; + volatile uint16_t subsystemID; + volatile uint16_t subsystem_vendorID; + volatile uint32_t expansion_base; + volatile uint8_t capabilities; + uint8_t reserved0[3]; + uint32_t reserved1; + volatile uint8_t interrupt_line; + volatile uint8_t interrupt_pin; + uint16_t reserved2[2]; +}; + + +// higher bus number: could be 0xff +// if there is only one bus group +static size_t max_bus = 0; + +struct PCIE_Descriptor pcie_descriptor = {0}; +// 0 | group | bus | 0 | slot | 0 | func | +// | 2 | 8 | 1 | 3 | 1 | 3 | +// 16 8 + +__attribute__((pure)) +static struct resource get_bar_resource( + struct PCIE_config_space* cs, + unsigned i) +{ + volatile uint32_t* bar_reg = (uint32_t*)&cs->bar[i]; + uint32_t val = *bar_reg; + + *bar_reg = ~1; + + unsigned size = ~ *bar_reg + 1; + + *bar_reg = val; + + + return (struct resource) { + .addr = val, + .size = size, + }; +} + + +__attribute__((pure)) +static struct PCIE_config_space* + get_config_space_base(unsigned bus_group, + unsigned bus, + unsigned device, + unsigned func + ) +{ + assert(bus_group < pcie_descriptor.size); + struct PCIE_busgroup* group_desc = &pcie_descriptor.array[bus_group]; + + return group_desc->address + ( + (bus - group_desc->start_bus) << 20 + | device << 15 + | func << 12); +} + + +static int __attribute__((pure)) + get_vendorID(unsigned bus_group, + unsigned bus, + unsigned device, + unsigned func) +{ + struct PCIE_config_space* config_space = + get_config_space_base(bus_group, bus,device,func); + + return config_space->vendorID; +} + + +struct early_device_descriptor { + uint16_t bus, device, function, domain; + struct PCIE_config_space* config_space; +}; + +// array of all installed devices' functions +static struct pcie_dev* found_devices = NULL; +static size_t n_found_devices = 0; + + +/** + * constructs the found_devices array + */ +static void scan_devices(void) { + + // first create a linked list + // as we dont know how many devices are present + struct device_desc_node { + struct early_device_descriptor e; + struct device_desc_node* next; + }; + +// head of the list + struct device_desc_node ghost_node = {.next = NULL}; + struct device_desc_node* current = &ghost_node; +// count the number of devices + + void insert( + unsigned bus, + unsigned device, + unsigned func, + struct PCIE_config_space* config_space + ) + { + current->next = malloc(sizeof(struct device_desc_node)); + + current = current->next; + current->next = NULL; + + // fill the new node + current->e.bus = bus; + current->e.device = device; + current->e.function = func; + current->e.config_space = config_space; + + n_found_devices++; + } + + for(unsigned bus_group_i = 0; + bus_group_i < pcie_descriptor.size; + bus_group_i++) + { + struct PCIE_busgroup* group = + &pcie_descriptor.array[bus_group_i]; + + unsigned bus_group = group->group; + + for(unsigned bus = group->start_bus; + bus < group->end_bus; + bus++) + { + for(unsigned device = 0; device < 32; device++) { + + // if the first function doesn't exist, so does + // the device + uint16_t vendorID = get_vendorID(bus_group, + bus, + device, + 0); + + if(vendorID == 0xFFFF) + continue; + + insert(bus, + device, + 0, + get_config_space_base(bus_group, + bus, + device, + 0) + ); + + for(unsigned func = 1; func < 8; func++) { + + if(get_vendorID(bus_group, + bus, + device, + func) != vendorID) + continue; + + insert(bus, + device, + func, + get_config_space_base(bus_group, + bus, + device, + func) + ); + } + } + } + } + + + // now create the final array + found_devices = malloc( + n_found_devices + * sizeof(struct early_device_descriptor)); + + + // now fill it and free the devices structure + struct pcie_dev* ptr = found_devices; + + for(struct device_desc_node* device = ghost_node.next; + device != NULL; + ) { + struct early_device_descriptor* early_desc = &device->e; + struct PCIE_config_space* cs = early_desc->config_space; + + *ptr = (struct pcie_dev) { + .bars = { + get_bar_resource(cs, 0), + get_bar_resource(cs, 1), + get_bar_resource(cs, 2), + }, + .config_space = cs, + .driver = NULL, + .info = (struct dev_info) { + .vendorID = cs->vendorID, + .deviceID = cs->deviceID, + .classcode = cs->classcode, + .subclasscode = cs->subclasscode, + .progIF = cs->progIF, + .revID = cs->revID, + }, + .path = (pcie_path_t) { + .domain = early_desc->domain, + .bus = early_desc->bus, + .device = early_desc->device, + .func = early_desc->function, + } + }; + +struct resource bars[3]; +struct dev_info info; + +void* config_space; + +pcie_path_t path; + +struct driver* driver; + memcpy(ptr++, &device->e, sizeof(struct early_device_descriptor)); + + + struct device_desc_node* next = device->next; + free(device); + device = next; + } +} +// identity map every page that might be a config space +static void identity_map_possible_config_spaces(void) { + for(unsigned i = 0; i < pcie_descriptor.size; i++) { + + // identity map the corresponding pages + map_pages( + (uint64_t)pcie_descriptor.array[i].address, // phys + (uint64_t)pcie_descriptor.array[i].address, // virt + 256 * // busses + 32 * // devices + 8, // functions + PRESENT_ENTRY | PCD | PL_XD + // no cache, execute disable + ); + } +} + + +static void identity_unmap_possible_config_spaces(void) { + for(unsigned i = 0; i < pcie_descriptor.size; i++) + unmap_pages((uint64_t)pcie_descriptor.array[i].address, 256 * 32 * 8); +} + +/** + * during the init, + * we identity map the pcie configuration spaces + * + */ +struct pcie_device* pcie_scan(void) { + + log_debug("scanning pcie devices..."); + + // calculate the highest bus number + + for(unsigned i = 0; i < pcie_descriptor.size; i++) { + // map the corresponding pages + if(pcie_descriptor.array[i].end_bus > max_bus) + max_bus = pcie_descriptor.array[i].end_bus; + } + + log_debug("%u PCIE bus groups found", pcie_descriptor.size); + + + identity_map_possible_config_spaces(); + + scan_devices(); + + + for(unsigned i = 0; i < n_found_devices; i++) { + + log_warn("%2x:%2x:%2x: %2x:%2x:%2x, rev %2x, " + "vendor 0x%4x", + + found_devices[i].path.bus, + found_devices[i].path.device, + found_devices[i].path.func, + + found_devices[i].info.classcode, + found_devices[i].info.subclasscode, + found_devices[i].info.progIF, + found_devices[i].info.revID, + + found_devices[i].info.vendorID + ); + } + + identity_unmap_possible_config_spaces(); + log_info("found %u PCI Express devices", n_found_devices); +} + diff --git a/kernel/drivers/pcie/scan.h b/kernel/drivers/pcie/scan.h new file mode 100644 index 0000000..6fa6426 --- /dev/null +++ b/kernel/drivers/pcie/scan.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include +#include "../../lib/assert.h" + + +struct PCIE_busgroup { + void* address; // Base address + // of enhanced configuration mechanism + uint16_t group; // PCI Segment Group Number + uint8_t start_bus; // Start PCI bus number + // decoded by this host bridge + uint8_t end_bus; // End PCI bus number + // decoded by this host bridge + uint32_t reserved; +} __attribute__((packed)); + +static_assert_equals(sizeof(struct PCIE_busgroup), 16); + + +#define PCIE_SUPPORTED_SEGMENT_GROUPS 2 +struct PCIE_Descriptor { + size_t size; + struct PCIE_busgroup array[PCIE_SUPPORTED_SEGMENT_GROUPS]; + // we only handle PCIE devices with only 4 segment groups max +}; + + +// defined in pcie.c +extern struct PCIE_Descriptor pcie_descriptor; + + +struct pcie_device* pcie_scan(void); + + diff --git a/kernel/entry.c b/kernel/entry.c index 9beab32..8917b52 100644 --- a/kernel/entry.c +++ b/kernel/entry.c @@ -12,8 +12,9 @@ #include "int/pic.h" #include "drivers/hpet.h" -#include "drivers/pcie.h" #include "drivers/ps2kb.h" +#include "drivers/pcie/pcie.h" +#include "drivers/pcie/scan.h" #include "memory/physical_allocator.h" #include "memory/paging.h" @@ -210,7 +211,7 @@ void _start(struct stivale2_struct *stivale2_struct) { log_flush(); pcie_init(); - pcie_init_devices(); + pic_init(); ps2kb_init(); diff --git a/kernel/memory/heap.c b/kernel/memory/heap.c index f54db4e..4d4b7ca 100644 --- a/kernel/memory/heap.c +++ b/kernel/memory/heap.c @@ -277,7 +277,7 @@ void* __attribute__((noinline)) malloc(size_t size) { break; } - assert(is_kernel_memory(seg)); + assert(is_kernel_memory((uint64_t)seg)); if(!seg->free || seg->size < size) { // this segment is not right, check the next one