From 58d6a5c65f51c567d8d5f7c0cbe089750099dfc6 Mon Sep 17 00:00:00 2001 From: catfood Date: Sun, 8 Jan 2023 21:03:48 +0800 Subject: [PATCH] add simple pci driver --- include/memman.h | 2 +- include/pci.h | 51 ++++++++++++++ include/proc.h | 2 + include/protect.h | 2 +- include/proto.h | 10 +++ include/type.h | 18 +++++ kernel/Makefrag | 1 + kernel/main.c | 5 +- kernel/pci.c | 166 ++++++++++++++++++++++++++++++++++++++++++++++ lib/kprintf.c | 6 +- 10 files changed, 256 insertions(+), 7 deletions(-) create mode 100644 include/pci.h create mode 100644 kernel/pci.c diff --git a/include/memman.h b/include/memman.h index ab223ce..c83c855 100644 --- a/include/memman.h +++ b/include/memman.h @@ -1,6 +1,6 @@ #ifndef _ORANGES_MEMMAN_H_ #define _ORANGES_MEMMAN_H_ - +#include "type.h" #define MEMMAN_FREES 4090 //32KB #define MEMMAN_ADDR 0x01ff0000 //存memman,31M960K #define FMIBuff 0x007ff000 //loader中getFreeMemInfo返回值存放起始地址(7M1020K) diff --git a/include/pci.h b/include/pci.h new file mode 100644 index 0000000..0c3a771 --- /dev/null +++ b/include/pci.h @@ -0,0 +1,51 @@ +/* +** Copyright 2002-2003, Michael Noisternig. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _PCI_H_ +#define _PCI_H_ +#include "type.h" +typedef struct { + char prefetchable; + uint32_t address; + uint8_t type; +} bar_t; +#define INPUT_OUTPUT 0 +#define MEMORY_MAPPED 1 + +struct device_desc_pci { + uint8_t bus; + uint8_t device; + uint8_t function; + uint16_t vendor_id; + uint16_t device_id; + uint8_t class_id; + uint8_t subclass_id; + uint8_t interface_id; + uint8_t revision_id; + uint32_t interrupt; + uint32_t port_base; + uint32_t type; +}; +typedef struct device_desc_pci pci_dev_t; + +enum DEVICES_TYPE { + DEVICE_STORAGE = (1 << 0), + DEVICE_SOUND = (1 << 1), + DEVICE_INPUT_SYSTEMS = (1 << 2), + DEVICE_NETWORK = (1 << 3), + DEVICE_DISPLAY = (1 << 4), + DEVICE_BUS_CONTROLLER = (1 << 5), + DEVICE_BRIDGE = (1 << 6), + DEVICE_CHAR = (1 << 7), + DEVICE_RTC = (1 << 8), + DEVICE_UNKNOWN = (1 << 9), +}; + +uint32_t pci_read(uint16_t bus, uint16_t device, uint16_t function, uint32_t offset); +void pci_write(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint32_t data); +pci_dev_t pci_get_device_desriptor(uint8_t bus, uint8_t device, uint8_t function); + +#define NR_PCI_DEV 8 + +#endif diff --git a/include/proc.h b/include/proc.h index 4b3dfc2..8d5583c 100644 --- a/include/proc.h +++ b/include/proc.h @@ -15,6 +15,8 @@ * below instead. * added by xw, 17/12/11 */ +#pragma once +#include "protect.h" #define INIT_STACK_SIZE 1024 * 8 //new kernel stack is 8kB #define P_STACKBASE 0 #define GSREG 0 diff --git a/include/protect.h b/include/protect.h index 2b796e0..d5231f1 100644 --- a/include/protect.h +++ b/include/protect.h @@ -7,7 +7,7 @@ #ifndef _ORANGES_PROTECT_H_ #define _ORANGES_PROTECT_H_ - +#include "type.h" /* 存储段描述符/系统段描述符 */ typedef struct s_descriptor /* 共 8 个字节 */ diff --git a/include/proto.h b/include/proto.h index dc7a860..c86b651 100644 --- a/include/proto.h +++ b/include/proto.h @@ -4,6 +4,11 @@ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Forrest Yu, 2005 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +#ifndef _PROTO_H_ +#define _PROTO_H_ + +#include "type.h" +#include "tty.h" // added by zcr void disable_irq(int irq); @@ -130,3 +135,8 @@ void write_page_pte(u32 TblPhyAddr, u32 AddrLin, u32 PhyAddr, u32 Attribute); u32 vmalloc(u32 size); int lin_mapping_phy(u32 AddrLin, u32 phy_addr, u32 pid, u32 pde_Attribute, u32 pte_Attribute); // edit by visual 2016.5.19 void clear_kernel_pagepte_low(); // add by visual 2016.5.12 + +/* add by catfood */ + +void init_pci(); +#endif \ No newline at end of file diff --git a/include/type.h b/include/type.h index 266615c..b14e537 100644 --- a/include/type.h +++ b/include/type.h @@ -24,6 +24,24 @@ typedef unsigned short u16; typedef char i8; typedef unsigned char u8; +typedef long long int64; +typedef unsigned long long uint64; +typedef int int32; +typedef unsigned int uint32; +typedef short int16; +typedef unsigned short uint16; +typedef char int8; +typedef unsigned char uint8; + +typedef long long int64_t; +typedef unsigned long long uint64_t; +typedef int int32_t; +typedef unsigned int uint32_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef char int8_t; +typedef unsigned char uint8_t; + typedef i32 intptr_t; typedef u32 uintptr_t; diff --git a/kernel/Makefrag b/kernel/Makefrag index fd64fba..a59d731 100644 --- a/kernel/Makefrag +++ b/kernel/Makefrag @@ -32,6 +32,7 @@ KERN_SRCFILES :=kernel/kernel.asm \ kernel/protect.c \ kernel/serialport.c \ kernel/vga.c \ + kernel/pci.c \ lib/klib.c \ diff --git a/kernel/main.c b/kernel/main.c index 972f997..24f01d9 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -32,9 +32,10 @@ static int initialize_cpus(); // added by xw, 18/6/2 *======================================================================*/ int kernel_main() { - clear_kernel_pagepte_low(); - init_serial(); + init_pci(); + clear_kernel_pagepte_low(); + while(1); int error; disp_pos = 0; diff --git a/kernel/pci.c b/kernel/pci.c new file mode 100644 index 0000000..d7d9497 --- /dev/null +++ b/kernel/pci.c @@ -0,0 +1,166 @@ +#include "type.h" +#include "assert.h" +#include "console.h" +#include "const.h" +#include "keyboard.h" +#include "memman.h" +#include "proc.h" +#include "protect.h" +#include "proto.h" +#include "stdio.h" +#include "string.h" +#include "x86.h" +#include "global.h" +#include "tty.h" +#include "pci.h" + +/* + * Copyright (C) 2020-2022 The opuntiaOS Project Authors. + * + Contributed by Nikita Melekhin + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#define DEBUG_PCI + +pci_dev_t pci_devs[NR_PCI_DEV]; + +static uint32_t _pci_do_read_bar(uint8_t bus, uint8_t device, uint8_t function, + uint8_t bar_id) { + uint32_t header_type = pci_read(bus, device, function, 0x0e) & 0x7f; + uint8_t max_bars = 6 - (header_type * 4); + if (bar_id >= max_bars) return 0; + uint32_t bar_val = pci_read(bus, device, function, 0x10 + 4 * bar_id); + return bar_val; +} + +static bar_t _pci_get_bar(uint8_t bus, uint8_t device, uint8_t function, + uint8_t bar_id) { + bar_t result; + + uint32_t bar_val = _pci_do_read_bar(bus, device, function, bar_id); + result.type = (bar_val & 0x1) ? INPUT_OUTPUT : MEMORY_MAPPED; + + if (result.type == MEMORY_MAPPED) { + } else { + result.address = (uint32_t)((bar_val >> 2) << 2); + result.prefetchable = 0; + } + return result; +} + +uint32_t pci_read(uint16_t bus, uint16_t device, uint16_t function, + uint32_t offset) { + uint32_t id = (0x1 << 31) | ((bus & 0xFF) << 16) | ((device & 0x1F) << 11) | + ((function & 0x07) << 8) | (offset & 0xFC); + outl(0xCF8, id); + uint32_t tmp = (uint32_t)(inl(0xCFC) >> (8 * (offset % 4))); + return tmp; +} + +void pci_write(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, + uint32_t data) { + uint32_t bus32 = bus; + uint32_t device32 = device; + uint16_t function16 = function; + uint32_t address = (1 << 31) | (bus32 << 16) | (device32 << 11) | + (function16 << 8) | (offset & 0xFC); + outl(0xCF8, address); + outl(0xCFC, data); +} + +static int dev_type_by_class(pci_dev_t* dd) { + switch (dd->class_id) { + case 0x1: + switch (dd->subclass_id) { + case 0x1: + case 0x3: + case 0x4: + return DEVICE_BUS_CONTROLLER; + default: + return DEVICE_STORAGE; + } + case 0x2: + return DEVICE_NETWORK; + case 0x3: + return DEVICE_DISPLAY; + case 0x6: + return DEVICE_BRIDGE; + default: +#ifdef DEBUG_PCI + kprintf("PCI: DEVICE_UNKNOWN: Class %d subclass %d", dd->class_id, + dd->subclass_id); +#endif + return DEVICE_UNKNOWN; + } +} + +static char pci_has_device_functions(uint8_t bus, uint8_t device) { + return pci_read(bus, device, 0, 0x0e) & (1 << 7); +} + +int pci_find_devices() { +#ifdef DEBUG_PCI + kprintf("PCI: scanning\n"); +#endif + uint8_t bus, device, function; + int count = 0; + for (bus = 0; bus < 8; bus++) { + for (device = 0; device < 32; device++) { + uint8_t functions_count = + pci_has_device_functions(bus, device) == 0 ? 8 : 1; + for (function = 0; function < functions_count; function++) { + pci_dev_t dev = + pci_get_device_desriptor(bus, device, function); + if (dev.vendor_id == 0x0000 || dev.vendor_id == 0xffff) { + continue; + } + + for (uint8_t bar_id = 0; bar_id < 6; bar_id++) { + bar_t bar = _pci_get_bar(bus, device, function, bar_id); + if (bar.address && (bar.type == INPUT_OUTPUT)) { + dev.port_base = (uint32_t)bar.address; + } + } + dev.type = dev_type_by_class(&dev); + pci_devs[count ++] = dev; +#ifdef DEBUG_PCI + kprintf("PCI: Vendor %x, devID %x, cl %x scl %x\n", + dev.vendor_id, dev.device_id, dev.class_id, + dev.subclass_id); +#endif + } + } + } + + return 0; +} + +pci_dev_t pci_get_device_desriptor(uint8_t bus, uint8_t device, + uint8_t function) { + pci_dev_t new_device = {0}; + + new_device.bus = bus; + new_device.device = device; + new_device.function = function; + + new_device.vendor_id = pci_read(bus, device, function, 0x00); + new_device.device_id = pci_read(bus, device, function, 0x02); + + new_device.class_id = pci_read(bus, device, function, 0x0b); + new_device.subclass_id = pci_read(bus, device, function, 0x0a); + new_device.interface_id = pci_read(bus, device, function, 0x09); + new_device.revision_id = pci_read(bus, device, function, 0x08); + + new_device.interrupt = pci_read(bus, device, function, 0x3c); + + return new_device; +} + +uint32_t pci_read_bar(pci_dev_t* pci_dev, int bar_id) { + return _pci_do_read_bar(pci_dev->bus, pci_dev->device, pci_dev->function, + bar_id); +} + +void init_pci() { pci_find_devices(); } \ No newline at end of file diff --git a/lib/kprintf.c b/lib/kprintf.c index c92dba6..0cc6378 100644 --- a/lib/kprintf.c +++ b/lib/kprintf.c @@ -8,9 +8,9 @@ static void kprintfputch(int ch, int *cnt) { - // write_serial(ch); - char _ch = ch; - tty_write(cur_ntty, &_ch, 1); + write_serial(ch); + // char _ch = ch; + // tty_write(cur_ntty, &_ch, 1); (*cnt)++; }