1
0
Fork 0
mirror of https://github.com/hermitcore/libhermit.git synced 2025-03-09 00:00:03 +01:00

add basic PCI support

This commit is contained in:
Stefan Lankes 2015-10-24 18:51:31 +02:00
parent 56bed9455e
commit 7f562d49ed
6 changed files with 2152 additions and 2 deletions

View file

@ -0,0 +1,77 @@
/*
* Copyright (c) 2010-2015, Stefan Lankes, RWTH Aachen University
* All rights reserved.
*
* * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @author Stefan Lankes
* @file arch/x86/include/asm/pci.h
* @brief functions related to PCI initialization and information
*
* This file contains a procedure to initialize the PCI environment
* and functions to access information about specific PCI devices.
*/
#ifndef __ARCH_PCI_H__
#define __ARCH_PCI_H__
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
uint32_t base[6];
uint32_t size[6];
uint32_t irq;
} pci_info_t;
/** @brief Initialize the PCI environment
*/
int pci_init(void);
/** @brief Determine the IObase address and the interrupt number of a specific device
*
* @param vendor_id The device's vendor ID
* @param device_id the device's ID
* @param info Pointer to the record pci_info_t where among other the IObase address will be stored
*
* @return
* - 0 on success
* - -EINVAL (-22) on failure
*/
int pci_get_device_info(uint32_t vendor_id, uint32_t device_id, pci_info_t* info);
/** @brief Print information of existing pci adapters
*
* @return 0 in any case
*/
int print_pci_adapters(void);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -40,6 +40,7 @@
#include <asm/gdt.h>
#include <asm/apic.h>
#include <asm/irqflags.h>
#include <asm/pci.h>
#ifdef __cplusplus
extern "C" {
@ -637,6 +638,7 @@ inline static int system_init(void)
{
gdt_install();
cpu_detection();
pci_init();
return 0;
}

View file

@ -1,4 +1,4 @@
C_source := irq.c idt.c isrs.c gdt.c processor.c timer.c tasks.c apic.c
C_source := irq.c idt.c isrs.c gdt.c processor.c timer.c tasks.c apic.c pci.c
ASM_source := entry.asm string.asm
MODULE := arch_x86_kernel

View file

@ -0,0 +1,209 @@
/*
* Copyright (c) 2010-2015, Stefan Lankes, RWTH Aachen University
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <hermit/stdio.h>
#include <hermit/string.h>
#include <hermit/errno.h>
#include <asm/irqflags.h>
#include <asm/io.h>
#include <asm/pci.h>
#include "pcihdr.h"
/*
* PCI configuration registers
*/
#define PCI_CFID 0x00 /* Configuration ID */
#define PCI_CFCS 0x04 /* Configurtion Command/Status */
#define PCI_CFRV 0x08 /* Configuration Revision */
#define PCI_CFLT 0x0c /* Configuration Latency Timer */
#define PCI_CBIO 0x10 /* Configuration Base IO Address */
#define PCI_CFIT 0x3c /* Configuration Interrupt */
#define PCI_CFDA 0x40 /* Configuration Driver Area */
#define PHYS_IO_MEM_START 0
#define PCI_MEM 0
#define PCI_INTA 0
#define PCI_NSLOTS 22
#define PCI_NBUS 0
#define PCI_CONF_ADDR_REG 0xcf8
#define PCI_CONF_FRWD_REG 0xcf8
#define PCI_CONF_DATA_REG 0xcfc
#define PCI_IO_CONF_START 0xc000
#define MAX_BUS 16
#define MAX_SLOTS 32
static uint32_t mechanism = 0;
static uint32_t adapters[MAX_BUS][MAX_SLOTS] = {[0 ... MAX_BUS-1][0 ... MAX_SLOTS-1] = -1};
static void pci_conf_write(uint32_t bus, uint32_t slot, uint32_t off, uint32_t val)
{
if (mechanism == 1) {
outportl(PCI_CONF_FRWD_REG, bus);
outportl(PCI_CONF_ADDR_REG, 0xf0);
outportl(PCI_IO_CONF_START | (slot << 8) | off, val);
} else {
outportl(PCI_CONF_ADDR_REG,
(0x80000000 | (bus << 16) | (slot << 11) | off));
outportl(PCI_CONF_DATA_REG, val);
}
}
static uint32_t pci_conf_read(uint32_t bus, uint32_t slot, uint32_t off)
{
uint32_t data = -1;
outportl(PCI_CONF_ADDR_REG,
(0x80000000 | (bus << 16) | (slot << 11) | off));
data = inportl(PCI_CONF_DATA_REG);
if ((data == 0xffffffff) && (slot < 0x10)) {
outportl(PCI_CONF_FRWD_REG, bus);
outportl(PCI_CONF_ADDR_REG, 0xf0);
data = inportl(PCI_IO_CONF_START | (slot << 8) | off);
if (data == 0xffffffff)
return data;
if (!mechanism)
mechanism = 1;
} else if (!mechanism)
mechanism = 2;
return data;
}
static inline uint32_t pci_what_irq(uint32_t bus, uint32_t slot)
{
return pci_conf_read(bus, slot, PCI_CFIT) & 0xFF;
}
static inline uint32_t pci_what_iobase(uint32_t bus, uint32_t slot, uint32_t nr)
{
return pci_conf_read(bus, slot, PCI_CBIO + nr*4) & 0xFFFFFFFC;
}
static inline uint32_t pci_what_size(uint32_t bus, uint32_t slot, uint32_t nr)
{
uint32_t tmp, ret;
// backup the original value
tmp = pci_conf_read(bus, slot, PCI_CBIO + nr*4);
// determine size
pci_conf_write(bus, slot, PCI_CBIO + nr*4, 0xFFFFFFFF);
ret = ~pci_conf_read(bus, slot, PCI_CBIO + nr*4) + 1;
// restore original value
pci_conf_write(bus, slot, PCI_CBIO + nr*4, tmp);
return ret;
}
int pci_init(void)
{
uint32_t slot, bus;
for (bus = 0; bus < MAX_BUS; bus++)
for (slot = 0; slot < MAX_SLOTS; slot++)
adapters[bus][slot] = pci_conf_read(bus, slot, PCI_CFID);
return 0;
}
int pci_get_device_info(uint32_t vendor_id, uint32_t device_id, pci_info_t* info)
{
uint32_t slot, bus, i;
if (!info)
return -EINVAL;
if (!mechanism)
pci_init();
for (bus = 0; bus < MAX_BUS; bus++) {
for (slot = 0; slot < MAX_SLOTS; slot++) {
if (adapters[bus][slot] != -1) {
if (((adapters[bus][slot] & 0xffff) == vendor_id) &&
(((adapters[bus][slot] & 0xffff0000) >> 16) == device_id)) {
for(i=0; i<6; i++) {
info->base[i] = pci_what_iobase(bus, slot, i);
info->size[i] = (info->base[i]) ? pci_what_size(bus, slot, i) : 0;
}
info->irq = pci_what_irq(bus, slot);
return 0;
}
}
}
}
return -EINVAL;
}
int print_pci_adapters(void)
{
uint32_t slot, bus;
uint32_t i, counter = 0;
if (!mechanism)
pci_init();
for (bus = 0; bus < MAX_BUS; bus++) {
for (slot = 0; slot < MAX_SLOTS; slot++) {
if (adapters[bus][slot] != -1) {
counter++;
kprintf("%d) Vendor ID: 0x%x Device Id: 0x%x\n",
counter, adapters[bus][slot] & 0xffff,
(adapters[bus][slot] & 0xffff0000) >> 16);
for (i=0; i<PCI_VENTABLE_LEN; i++) {
if ((adapters[bus][slot] & 0xffff) ==
(uint32_t)PciVenTable[i].VenId)
kprintf("\tVendor is %s\n",
PciVenTable[i].VenShort);
}
for (i=0; i<PCI_DEVTABLE_LEN; i++) {
if ((adapters[bus][slot] & 0xffff) ==
(uint32_t)PciDevTable[i].VenId) {
if (((adapters[bus][slot] & 0xffff0000) >> 16) ==
PciDevTable[i].DevId) {
kprintf
("\tChip: %s ChipDesc: %s\n",
PciDevTable[i].Chip,
PciDevTable[i].ChipDesc);
}
}
}
}
}
}
return 0;
}

File diff suppressed because it is too large Load diff

View file

@ -342,11 +342,15 @@ int main(void)
kprintf("Current allocated memory: %zd KiB\n", atomic_int64_read(&total_allocated_pages) * PAGE_SIZE / 1024ULL);
kprintf("Current available memory: %zd MiB\n", atomic_int64_read(&total_available_pages) * PAGE_SIZE / (1024ULL*1024ULL));
#if 1
#if 0
kputs("Filesystem:\n");
list_fs(fs_root, 1);
#endif
#if 1
print_pci_adapters();
#endif
#ifdef DYNAMIC_TICKS
enable_dynticks();
#endif