CeDOS - kernel/pci.c

kernel/pci.c (view raw)

#include <stdint.h>

#include "assembly.h"

#include "core.h"
#include "list.h"
#include "memory.h"

#define CONFIG_ADDR_ENABLE (31)
#define CONFIG_ADDR_BUS (16)
#define CONFIG_ADDR_PORT (11)
#define CONFIG_ADDR_FUNC (8)
#define CONFIG_ADDR_REG (0)

#define VENDOR_DEVICE_ID_REGISTER (0x00)

#define VENDOR_ID_BIT_MASK (0x0000FFFF)
#define VENDOR_ID_BIT_SHIFT (0)

#define DEVICE_ID_BIT_MASK (0xFFFF0000)
#define DEVICE_ID_BIT_SHIFT (16)

struct pci_device {
	uint8_t bus;
	uint8_t port;

	uint16_t vendor_id;
	uint16_t device_id;

	struct list_node node;
};

struct list pci_devices = LIST_INIT();

static int pci_read_register(struct pci_device *dev, uint8_t func, uint8_t reg, uint32_t *res) {
	uint32_t config_addr = 0;

	config_addr |= (1U << CONFIG_ADDR_ENABLE);
	config_addr |= (uint32_t)(dev->bus) << CONFIG_ADDR_BUS;
	config_addr |= (uint32_t)(dev->port) << CONFIG_ADDR_PORT;
	config_addr |= (uint32_t)(func) << CONFIG_ADDR_FUNC;
	config_addr |= (uint32_t)(reg) << CONFIG_ADDR_REG;

	outl(config_addr, 0xCF8);

	*res = inl(0xCFC);

	return 0;
}

int pci_init(void) {
	int num_devices = 0;

	for (int bus = 0; bus < 256; bus++) {
		for (int port = 0; port < 256; port++) {
			struct pci_device dev = {
				.bus = (uint8_t)(bus),
				.port = (uint8_t)(port),
			};

			uint32_t reg_value = 0;
			pci_read_register(&dev, 0, VENDOR_DEVICE_ID_REGISTER, &reg_value);

			uint16_t vendor_id =
				(reg_value & VENDOR_ID_BIT_MASK) >> VENDOR_ID_BIT_SHIFT;
			uint16_t device_id =
				(reg_value & DEVICE_ID_BIT_MASK) >> DEVICE_ID_BIT_SHIFT;

			if (vendor_id == 0xFFFF) {
				continue;
			}

			struct pci_device *list_entry = malloc(sizeof(struct pci_device));

			list_entry->bus = dev.bus;
			list_entry->port = dev.port;

			list_entry->vendor_id = vendor_id;
			list_entry->device_id = device_id;

			printk("list before first %p last %p\n", pci_devices.first, pci_devices.last);
			list_append(&pci_devices, &(list_entry->node));
			printk("list after  first %p last %p\n", pci_devices.first, pci_devices.last);
			num_devices++;
		}
	}

	printk("\nfound %i PCI devices:\n", num_devices);

	printk("\n     BUS  :  PORT     VENDOR : DEVICE\n");
	struct pci_device *entry;
	LIST_FOR_EACH_ENTRY(&pci_devices, struct pci_device, node, entry) {
		printk("- %x:%x  %x:%x\n", entry->bus, entry->port,
				entry->vendor_id, entry->device_id);
	}

	return 0;
}