mirror of
https://github.com/kenshineto/kern.git
synced 2025-04-16 23:47:25 +00:00
pci
This commit is contained in:
parent
d0854aa095
commit
d604f8e93f
6 changed files with 276 additions and 5 deletions
|
@ -30,6 +30,8 @@ const kernel_src = &[_][]const u8{
|
|||
"kernel/cpu/idt.c",
|
||||
"kernel/cpu/idt.S",
|
||||
"kernel/cpu/pic.c",
|
||||
"kernel/drivers/drivers.c",
|
||||
"kernel/drivers/pci.c",
|
||||
"kernel/io/io.c",
|
||||
"kernel/io/panic.c",
|
||||
"kernel/mboot/mboot.c",
|
||||
|
|
7
kernel/drivers/drivers.c
Normal file
7
kernel/drivers/drivers.c
Normal file
|
@ -0,0 +1,7 @@
|
|||
#include <comus/drivers.h>
|
||||
#include <comus/drivers/pci.h>
|
||||
|
||||
void drivers_init(void)
|
||||
{
|
||||
pci_init();
|
||||
}
|
174
kernel/drivers/pci.c
Normal file
174
kernel/drivers/pci.c
Normal file
|
@ -0,0 +1,174 @@
|
|||
#include <comus/drivers/pci.h>
|
||||
#include <comus/asm.h>
|
||||
#include <lib.h>
|
||||
|
||||
#define CONF_ADDR 0xCF8
|
||||
#define CONF_DATA 0xCFC
|
||||
#define TABLE_LEN 16
|
||||
|
||||
struct pci_table_entry {
|
||||
struct pci_device device;
|
||||
uint16_t device_id;
|
||||
uint16_t vendor_id;
|
||||
uint8_t class;
|
||||
uint8_t subclass;
|
||||
uint8_t prog_if;
|
||||
uint8_t revision;
|
||||
};
|
||||
|
||||
static struct pci_table_entry pci_table[TABLE_LEN];
|
||||
static size_t pci_table_next = 0;
|
||||
|
||||
uint32_t pci_rcfg_d(struct pci_device dev, uint8_t offset)
|
||||
{
|
||||
uint32_t addr = 0x80000000;
|
||||
addr |= ((uint32_t)dev.bus) << 16;
|
||||
addr |= ((uint32_t)dev.device) << 11;
|
||||
addr |= ((uint32_t)dev.function) << 8;
|
||||
addr |= offset & 0xFC;
|
||||
|
||||
outl(CONF_ADDR, addr);
|
||||
uint32_t in = inl(CONF_DATA);
|
||||
return in;
|
||||
}
|
||||
|
||||
static void print_device(struct pci_table_entry *entry)
|
||||
{
|
||||
printf(
|
||||
"BUS: %#-4x DEV: %#-4x FUNC: %#-4x ID: %04x:%04x CLASS: %02x:%02x:%02x REV: %#02x\n",
|
||||
entry->device.bus, entry->device.device, entry->device.function,
|
||||
entry->vendor_id, entry->device_id, entry->class, entry->subclass,
|
||||
entry->prog_if, entry->revision);
|
||||
}
|
||||
|
||||
static struct pci_table_entry *load_device(struct pci_device dev)
|
||||
{
|
||||
if (pci_table_next >= TABLE_LEN)
|
||||
panic("Too many PCI devices: limit is %d", TABLE_LEN);
|
||||
struct pci_table_entry *entry = &pci_table[pci_table_next++];
|
||||
entry->device = dev;
|
||||
uint32_t dword0 = pci_rcfg_d(dev, 0);
|
||||
uint32_t dword2 = pci_rcfg_d(dev, 8);
|
||||
|
||||
entry->device_id = (dword0 >> 16) & 0xFFFF;
|
||||
entry->vendor_id = dword0 & 0xFFFF;
|
||||
|
||||
entry->class = (dword2 >> 24) & 0xFF;
|
||||
entry->subclass = (dword2 >> 16) & 0xFF;
|
||||
entry->prog_if = (dword2 >> 8) & 0xFF;
|
||||
entry->revision = dword2 & 0xFF;
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
uint16_t pci_rcfg_w(struct pci_device dev, uint8_t offset)
|
||||
{
|
||||
uint32_t dword = pci_rcfg_d(dev, offset);
|
||||
return (uint16_t)((dword >> ((offset & 2) * 8)) & 0xFFFF);
|
||||
}
|
||||
|
||||
uint8_t pci_rcfg_b(struct pci_device dev, uint8_t offset)
|
||||
{
|
||||
uint32_t dword = pci_rcfg_d(dev, offset);
|
||||
return (uint8_t)((dword >> ((offset & 3) * 8)) & 0xFF);
|
||||
}
|
||||
|
||||
void pci_wcfg_d(struct pci_device dev, uint8_t offset, uint32_t dword)
|
||||
{
|
||||
uint32_t addr = 0x80000000;
|
||||
addr |= ((uint32_t)dev.bus) << 16;
|
||||
addr |= ((uint32_t)dev.device) << 11;
|
||||
addr |= ((uint32_t)dev.function) << 8;
|
||||
addr |= offset & 0xFC;
|
||||
|
||||
outl(CONF_ADDR, addr);
|
||||
outl(CONF_DATA, dword);
|
||||
}
|
||||
|
||||
void pci_wcfg_w(struct pci_device dev, uint8_t offset, uint16_t word)
|
||||
{
|
||||
size_t shift = (offset & 2) * 8;
|
||||
uint32_t dword = pci_rcfg_d(dev, offset);
|
||||
dword &= ~(0xFFFF << shift);
|
||||
dword |= word << shift;
|
||||
pci_wcfg_d(dev, offset, dword);
|
||||
}
|
||||
|
||||
void pci_wcfg_b(struct pci_device dev, uint8_t offset, uint8_t byte)
|
||||
{
|
||||
size_t shift = (offset & 3) * 8;
|
||||
uint32_t dword = pci_rcfg_d(dev, offset);
|
||||
dword &= ~(0xFF << shift);
|
||||
dword |= byte << shift;
|
||||
pci_wcfg_d(dev, offset, dword);
|
||||
}
|
||||
|
||||
void pci_init(void)
|
||||
{
|
||||
pci_table_next = 0;
|
||||
struct pci_device pcidev;
|
||||
for (int bus = 0; bus < 256; bus++) {
|
||||
pcidev.bus = bus;
|
||||
for (int dev = 0; dev < 32; dev++) {
|
||||
pcidev.device = dev;
|
||||
pcidev.function = 0;
|
||||
|
||||
uint16_t vendor = pci_rcfg_w(pcidev, 0);
|
||||
if (vendor == 0xFFFF)
|
||||
continue;
|
||||
|
||||
load_device(pcidev);
|
||||
|
||||
uint8_t header_type = pci_rcfg_b(pcidev, 14);
|
||||
|
||||
if (!(header_type & 0x80))
|
||||
continue;
|
||||
for (int func = 1; func < 8; func++) {
|
||||
pcidev.function = func;
|
||||
|
||||
uint16_t vendor = pci_rcfg_w(pcidev, 0);
|
||||
if (vendor == 0xFFFF)
|
||||
continue;
|
||||
|
||||
load_device(pcidev);
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("PCI DEVICES\n");
|
||||
for (size_t i = 0; i < pci_table_next; i++) {
|
||||
print_device(&pci_table[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
bool pci_findby_class(struct pci_device *dest, uint8_t class, uint8_t subclass,
|
||||
size_t *offset)
|
||||
{
|
||||
size_t o = 0;
|
||||
if (offset == NULL)
|
||||
offset = &o;
|
||||
for (; *offset < pci_table_next; (*offset)++) {
|
||||
struct pci_table_entry *entry = &pci_table[*offset];
|
||||
if (entry->class == class && entry->subclass == subclass) {
|
||||
*dest = entry->device;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool pci_findby_id(struct pci_device *dest, uint16_t device, uint16_t vendor,
|
||||
size_t *offset)
|
||||
{
|
||||
size_t o = 0;
|
||||
if (offset == NULL)
|
||||
offset = &o;
|
||||
for (; *offset < pci_table_next; (*offset)++) {
|
||||
struct pci_table_entry *entry = &pci_table[*offset];
|
||||
if (entry->device_id == device && entry->vendor_id == vendor) {
|
||||
*dest = entry->device;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
17
kernel/include/comus/drivers.h
Normal file
17
kernel/include/comus/drivers.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
/**
|
||||
* @file drivers.h
|
||||
*
|
||||
* @author Freya Murphy <freya@freyacat.org>
|
||||
*
|
||||
* Entrypoint for initalizing all devices
|
||||
*/
|
||||
|
||||
#ifndef DRIVERS_H_
|
||||
#define DRIVERS_H_
|
||||
|
||||
/**
|
||||
* Initalize all supported drivers
|
||||
*/
|
||||
void drivers_init(void);
|
||||
|
||||
#endif /* drivers.h */
|
72
kernel/include/comus/drivers/pci.h
Normal file
72
kernel/include/comus/drivers/pci.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
/**
|
||||
* @file pci.h
|
||||
*
|
||||
* @author Freya Murphy <freya@freyacaat.org>
|
||||
* @author Tristan Miller <trimill@trimillxyz.org>
|
||||
*
|
||||
* PCI driver
|
||||
*/
|
||||
|
||||
#ifndef PCI_H_
|
||||
#define PCI_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// common
|
||||
#define PCI_VENDOR_W 0x00
|
||||
#define PCI_DEVICE_W 0x02
|
||||
#define PCI_COMMAND_W 0x04
|
||||
#define PCI_STATUS_W 0x06
|
||||
#define PCI_REVISION_B 0x08
|
||||
#define PCI_PROG_IF_B 0x09
|
||||
#define PCI_SUBCLASS_B 0x0A
|
||||
#define PCI_CLASS_B 0x0B
|
||||
#define PCI_CACHE_SIZE_B 0x0C
|
||||
#define PCI_LATENCY_TIMER_B 0x0D
|
||||
#define PCI_HEADER_TYPE_B 0x0E
|
||||
#define PCI_BIST_B 0x0F
|
||||
|
||||
// header type 0
|
||||
#define PCI_BAR0_D 0x10
|
||||
#define PCI_BAR1_D 0x14
|
||||
#define PCI_BAR2_D 0x18
|
||||
#define PCI_BAR3_D 0x1C
|
||||
#define PCI_BAR4_D 0x20
|
||||
#define PCI_BAR5_D 0x24
|
||||
#define PCI_CARDBUS_CIS_D 0x28
|
||||
#define PCI_SUBSYSTEM_VENDOR_W 0x2C
|
||||
#define PCI_SUBSYSTEM_W 0x2E
|
||||
#define PCI_EXPANSION_ROM_D 0x30
|
||||
#define PCI_CAP_PTR_B 0x34
|
||||
#define PCI_INT_LINE_B 0x3C
|
||||
#define PCI_INT_PIN_B 0x3D
|
||||
#define PCI_MIN_GRANT_B 0x3E
|
||||
#define PCI_MAX_LATENCY_B 0x3F
|
||||
|
||||
struct pci_device {
|
||||
uint8_t bus : 8;
|
||||
uint8_t device : 5;
|
||||
uint8_t function : 3;
|
||||
};
|
||||
|
||||
/**
|
||||
* Load the PCI driver
|
||||
*/
|
||||
void pci_init(void);
|
||||
|
||||
bool pci_findby_class(struct pci_device *dest, uint8_t class, uint8_t subclass,
|
||||
size_t *offset);
|
||||
bool pci_findby_id(struct pci_device *dest, uint16_t device, uint16_t vendor,
|
||||
size_t *offset);
|
||||
|
||||
uint32_t pci_rcfg_d(struct pci_device dev, uint8_t offset);
|
||||
uint16_t pci_rcfg_w(struct pci_device dev, uint8_t offset);
|
||||
uint8_t pci_rcfg_b(struct pci_device dev, uint8_t offset);
|
||||
|
||||
void pci_wcfg_d(struct pci_device dev, uint8_t offset, uint32_t dword);
|
||||
void pci_wcfg_w(struct pci_device dev, uint8_t offset, uint16_t word);
|
||||
void pci_wcfg_b(struct pci_device dev, uint8_t offset, uint8_t byte);
|
||||
|
||||
#endif /* pci.h */
|
|
@ -1,15 +1,14 @@
|
|||
#include <comus/cpu.h>
|
||||
#include <comus/memory.h>
|
||||
#include <comus/mboot.h>
|
||||
#include <comus/drivers.h>
|
||||
#include <lib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct memory_map mmap;
|
||||
|
||||
void main(long magic, volatile void *mboot)
|
||||
{
|
||||
(void) magic; // TODO: check multiboot magic
|
||||
(void)magic; // TODO: check multiboot magic
|
||||
|
||||
// initalize idt and pic
|
||||
// WARNING: must be done before anything else
|
||||
|
@ -21,8 +20,8 @@ void main(long magic, volatile void *mboot)
|
|||
// initalize memory
|
||||
memory_init(&mmap);
|
||||
|
||||
char *a = malloc(3);
|
||||
*a = 3;
|
||||
// initalize devices
|
||||
drivers_init();
|
||||
|
||||
// halt
|
||||
printf("halting...\n");
|
||||
|
|
Loading…
Add table
Reference in a new issue