PCI设备驱动初探(仅仅是内核部分,不是具体设备驱动)

news2024/12/22 22:48:08

在操作系统中,声卡、网卡之类的设备驱动并不像硬盘、鼠标、键盘等等驱动直接编写就行了。它们是建立在内核PCI驱动基础上的,也就是说这类设备通过PCI总线与系统通信。所以要编写这类的驱动首先要构造一个PCI设备的内核驱动,这样我们才能继续正常的使用连接在PCI总线的设备。

关于PCI设备的详细介绍,还是请大家参考网上诸位大侠的文章,笔者这里就不班门弄斧了。这中间的原因当然是笔者根本就看不懂,主要是PCI设备相较于普通的设备复杂了很多,不仔细研究个十天八天的真的是弄不懂啊。

那么笔者既然不懂,又是怎么编写出的PCI驱动程序呢。起始笔者还真没有那个本事。这次笔者是又一次发挥了复制粘贴的本领。干脆直接把linux内核的PCI驱动粘贴进自己的代码中,本来是只是抱着试试看的想法,没想真的奏效了,看来这些日子的运气还是不错的。

https://elixir.bootlin.com/

通过上图大家看到了吧。笔者这次居然敢去碰linux内核了。在这里就是PCI设备驱动的内核部分。而且笔者还可以把网页翻译成了中文。

关于文件的详情,笔者这里也没完全弄懂,所以还是请大家自主观看吧。这里要告诉大家的是其实linux为我们展示了3种PCI访问方式。笔者只是拿来了一种作为测试代码。前两种是通过输入输出指令直接探测设备,而第3种是调用BIOS的代码来实现的。哦对了,起始PCI设备也不是专为intel处理器设计的,所以我们参考的代码是与体系结构相关的,也就是i386架构的。

上图具体定位了真正的激活PCI设备的函数,由于linux代码的架构性太强,笔者有些代码根本就看不懂。好在笔者还是比较善于改编的,这不笔者就通过少量的修改,形成了自己系统的代码。

unsigned int tmp;

void out8_(unsigned char data, unsigned short port);
void out16_(unsigned short data, unsigned short port);
void out32_(unsigned int data, unsigned short port);
unsigned char in8_(unsigned short port);
unsigned short in16_(unsigned short port);
unsigned int in32_(unsigned short port);

#define inb in8_
#define inw in16_
#define inl in32_
#define outb out8_
#define outw out16_
#define outl out32_
    

#define CONFIG_CMD(bus, device_fn, where)   (0x80000000 | (bus << 16) \
                                            | (device_fn << 8) | (where & ~3))
#define PCIBIOS_SUCCESSFUL        0x00

int pci_conf1_read_config_byte(unsigned char bus, unsigned char device_fn,
                   unsigned char where, unsigned char *value)
{
    outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
    *value = inb(0xCFC + (where&3));
    return PCIBIOS_SUCCESSFUL;
}

int pci_conf1_read_config_word (unsigned char bus,
    unsigned char device_fn, unsigned char where, unsigned short *value)
{
    outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);    
    *value = inw(0xCFC + (where&2));
    return PCIBIOS_SUCCESSFUL;    
}

int pci_conf1_read_config_dword (unsigned char bus, unsigned char device_fn, 
                 unsigned char where, unsigned int *value)
{
    outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
    *value = inl(0xCFC);
    return PCIBIOS_SUCCESSFUL;    
}

int pci_conf1_write_config_byte (unsigned char bus, unsigned char device_fn, 
                 unsigned char where, unsigned char value)
{
    outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);    
    outb(value, 0xCFC + (where&3));
    return PCIBIOS_SUCCESSFUL;
}

int pci_conf1_write_config_word (unsigned char bus, unsigned char device_fn, 
                 unsigned char where, unsigned short value)
{
    outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
    outw(value, 0xCFC + (where&2));
    return PCIBIOS_SUCCESSFUL;
}

int pci_conf1_write_config_dword (unsigned char bus, unsigned char device_fn, 
                  unsigned char where, unsigned int value)
{
    outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
    outl(value, 0xCFC);
    return PCIBIOS_SUCCESSFUL;
}

    


#define PCI_CLASS_DEVICE        0x0a    /* Device class */
#define PCI_CLASS_DISPLAY_VGA        0x0300
#define  PCI_CLASS_BRIDGE_HOST        0x0600
#define PCI_VENDOR_ID        0x00    /* 16 bits */
#define PCI_VENDOR_ID_INTEL        0x8086
#define PCI_VENDOR_ID_COMPAQ        0x0e11
typedef unsigned short u16;

int pci_sanity_check(void)
{
    u16 dfn, x;
    for(dfn=0; dfn < 0x100; dfn++)
        if ((!pci_conf1_read_config_word(0, dfn, PCI_CLASS_DEVICE, &x) &&
             (x == PCI_CLASS_BRIDGE_HOST || x == PCI_CLASS_DISPLAY_VGA)) ||
            (!pci_conf1_read_config_word(0, dfn, PCI_VENDOR_ID, &x) &&
             (x == PCI_VENDOR_ID_INTEL || x == PCI_VENDOR_ID_COMPAQ)))
            return 1;
    return 0;
}

void pci_check_direct(void)
{
    unsigned int tmp;
    unsigned long flags;
    
    outb (0x01, 0xCFB);
    tmp = inl (0xCF8);
    outl (0x80000000, 0xCF8);
    if (inl (0xCF8) == 0x80000000 && pci_sanity_check()) {
        outl (tmp, 0xCF8);
        return;
    }
    outl (tmp, 0xCF8);
}

    pci_check_direct();


#undef inb
#undef inw
#undef inl
#undef outb
#undef outw
#undef outl

    for(i = 0x28; i < 0x28 + 1; i++) {
        pci_conf1_read_config_dword(0, i, 0, &tmp);
        printf_(" %x %x ", i, tmp);        
    }

    unsigned short nambar, nabmbar;
    
    pci_conf1_read_config_dword(0, 0x28, 0x10, &tmp);
    nambar = tmp & 0xfffe;
    pci_conf1_read_config_dword(0, 0x28, 0x14, &tmp);
    nabmbar = tmp & 0xffc0;
    
    printf_("|NAMBAR=%x, NABMBAR=%x|", nambar, nabmbar);

下边是汇编的部分

global _out8, _out16, _out32, _in8, _in16, _in32
global _out8_, _out16_, _out32_, _in8_, _in16_, _in32_
align 16
_out8: ; void out8(unsigned short port, unsigned char data);
    push edx
    mov dx, [esp + 2 * 4]
    mov al, [esp + 3 * 4]
    out dx, al
    pop edx
    ret
    
align 16
_out16: ; void out16(unsigned short port, unsigned short data);
    push edx
    mov dx, [esp + 2 * 4]
    mov ax, [esp + 3 * 4]
    out dx, ax
    pop edx
    ret
    
align 16
_out32: ; void out32(unsigned short port, unsigned int data);
    push edx
    mov dx, [esp + 2 * 4]
    mov eax, [esp + 3 * 4]
    out dx, eax
    pop edx
    ret

align 16
_out8_: ; void out8_(unsigned char data, unsigned short port);
    push edx
    mov dx, [esp + 3 * 4]
    mov al, [esp + 2 * 4]
    out dx, al
    pop edx
    ret
    
align 16
_out16_: ; void out16_(unsigned short data, unsigned short port);
    push edx
    mov dx, [esp + 3 * 4]
    mov ax, [esp + 2 * 4]
    out dx, ax
    pop edx
    ret
    
align 16
_out32_: ; void out32_(unsigned int data, unsigned short port);
    push edx
    mov dx, [esp + 3 * 4]
    mov eax, [esp + 2 * 4]
    out dx, eax
    pop edx
    ret

align 16
_in8_:
_in8: ; unsigned char in8(unsigned short port);
    push edx
    mov dx, [esp + 2 * 4]
    in al, dx
    pop edx
    ret

align 16
_in16_:
_in16: ; unsigned short in16(unsigned short port);
    push edx
    mov dx, [esp + 2 * 4]
    in ax, dx
    pop edx
    ret

align 16
_in32_:
_in32: ; unsigned int in32(unsigned short port);
    push edx
    mov dx, [esp + 2 * 4]
    in eax, dx
    pop edx
    ret

下边是探测到的ICH ac97声卡的设备号和音频混音器的寄存器的端口基地址以及音频总线主控制器的端口基地址。当然在Snail OS中为了看清探测的结果,已经关闭了所有中断。

结合虚拟机的调试信息大家可以知道,探测的设备信息完全正确。

VBoxDbg> info pci

00:00.0 i440FX: 8086-1237 PIIX3

Class base/sub: 0600 (bridge device)

Command: 0000, Status: 0000

Bus master: No

00:01.0 PIIX3: 8086-7000 PIIX3

Class base/sub: 0601 (bridge device)

Command: 0007, Status: 0200

Bus master: Yes

00:01.1 piix3ide: 8086-7111 PIIX3

Class base/sub: 0101 (mass storage controller)

IO region #4: d000..d00f

Command: 0007, Status: 0000

Bus master: Yes

00:02.0 vga: 80ee-beef PIIX3 IRQ10 (INTA#->IRQ18)

Class base/sub: 0300 (display controller)

MMIO32 PREFETCH region #0: e0000000..e07fffff

Command: 0003, Status: 0000

Bus master: No

00:03.0 pcnet: 1022-2000 PIIX3 IRQ9 (INTA#->IRQ19)

Class base/sub: 0200 (network controller)

IO region #0: d020..d03f

MMIO32 region #1: f0000000..f0000fff

Command: 0007, Status: 0280

Bus master: Yes

00:04.0 VMMDev: 80ee-cafe PIIX3 IRQ11 (INTA#->IRQ20)

Class base/sub: 0880 (base system peripherals)

IO region #0: d040..d05f

MMIO32 region #1: f0400000..f07fffff

MMIO32 PREFETCH region #2: f0800000..f0803fff

Command: 0003, Status: 0000

Bus master: No

00:05.0 ichac97: 8086-2415 PIIX3 IRQ11 (INTA#->IRQ21)

Class base/sub: 0401 (multimedia controller)

IO region #0: d100..d1ff

IO region #1: d200..d23f

Command: 0001, Status: 0280

Bus master: No

00:06.0 usb-ohci: 106b-003f PIIX3 IRQ10 (INTA#->IRQ22)

Class base/sub: 0c03 (serial bus controllers)

MMIO32 region #0: f0804000..f0804fff

Command: 0002, Status: 0010

Bus master: No

00:07.0 acpi: 8086-7113 PIIX3 IRQ9 (INTA#->IRQ23)

Class base/sub: 0680 (bridge device)

Command: 0001, Status: 0280

Bus master: No

VBoxDbg>

总线上PCI设备可接256种之多,所以大家只要把代码中的for语句从0号设备开始循环查询就能够看到所有设备的全貌了。

下图是笔者探测的前64个,不知道大家是否能和调试信息对号入座吗?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/358447.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Hive学习——DDLDML语句

目录 一、Hive数据类型 (一)Hive基本数据类型 (二)Hive的基本数据类型转换 (三)Hive集合数据类型 (四)文本文件数据编码 (五)读时模式 (六)Hive数据结构 二、DDL&DML命令 (一)数据库操作 1.创建数据库 2.查看数据库 3.修改数据库 4.删除数据库 5.切换(使用)指…

【LeetCode】No.225. 用队列实现栈 -- Java Version

题目链接&#xff1a;https://leetcode.cn/problems/implement-stack-using-queues/ 1. 题目介绍&#xff08;225. 用队列实现栈&#xff09; 请你仅使用两个队列实现一个后入先出&#xff08;LIFO&#xff09;的栈&#xff0c;并支持普通栈的全部四种操作&#xff08;push、t…

回文子串的数量[寻找回文子串的完整思路过程]

寻找回文子串的完整思路过程前言一、回文串的数量二、动态规划1、完整思考过程2、go总结参考文献前言 回文字符串&#xff0c;就是从左遍历和从右遍历的字符是相同顺序的&#xff0c;转换一下&#xff0c;就是该字符串是对称的。寻找回文子串面临两个直接的问题&#xff0c;1-…

pytorch深度学习案例(二)——航拍街道语义分割

数据集 使用的数据集是kaggle的Semantic segmentation of aerial imagery 其数据的组织形式为 项目结构 utils dataConvert.py dataConvert中主要包含数据的变换过程 函数作用loadColorMap用于加载标签的颜色映射voc_colormap2label获取颜色标签到数值标签的映射关系voc_…

黑马Spring学习笔记(二)——注解开发

目录 一、纯注解开发 1.1 实现步骤 1.2 小结 二、注解开发依赖注入 2.1 自动装配 2.1.1 Autowired——按照类型注入 2.1.2 Qualifier——按照名称注入 2.1.3 Value——简单类型注入 2.2 注解读取properties配置文件——PropertySource 三、注解开发管理第三方B…

【基础算法】差分

&#x1f339;作者:云小逸 &#x1f4dd;个人主页:云小逸的主页 &#x1f4dd;Github:云小逸的Github &#x1f91f;motto:要敢于一个人默默的面对自己&#xff0c;强大自己才是核心。不要等到什么都没有了&#xff0c;才下定决心去做。种一颗树&#xff0c;最好的时间是十年前…

Kotlin 33. CompileSdkVersion 和 targetSdkVersion 有什么区别?

CompileSdkVersion 和 targetSdkVersion 有什么区别&#xff1f; 在 build.gradle (Module) 文件中&#xff0c;我们通常会看到 CompileSdkVersion 和 targetSdkVersion 的使用&#xff0c;比如下面是一个完整的 build.gradle (Module) 文件&#xff1a; plugins {id com.and…

JavaScript随手笔记---比较两个数组差异

&#x1f48c; 所属专栏&#xff1a;【JavaScript随手笔记】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &#…

0基础学习diffusion_model扩散模型【易理解的公式推导】

0基础学习diffusion_model扩散模型【易理解的公式推导】一、概述二、扩散过程(已知X0求Xt)三、逆扩散过程(已知Xt求Xt-1)1。算法流程图四、结论五、损失函数六、心得体会&#xff08;优缺点分析&#xff09;一、概述 DDPM论文链接&#xff1a; Jonathan Ho_Denoising Diffusion…

Android入门第64天-MVVM下瀑布流界面的完美实现-使用RecyclerView

前言 网上充满着不完善的基于RecyclerView的瀑布流实现&#xff0c;要么根本是错的、要么就是只知其一不知其二、要么就是一充诉了一堆无用代码、要么用的是古老的MVC设计模式。 一个真正的、用户体验类似于淘宝、抖音的瀑布流怎么实现目前基本为无解。因为本人正好自己空闲时也…

32岁,薪水被应届生倒挂,裸辞了

今年 32 岁&#xff0c;我从公司离职了&#xff0c;是裸辞。 前段时间&#xff0c;我有一件事情一直憋在心里很难受&#xff0c;想了很久也没找到合适的人倾诉&#xff0c;就借着今天写出来。 我一个十几年开发经验&#xff0c;八年 软件测试 经验的职场老人&#xff0c;我慢…

markdown常用语法--花括号(超详细)

&#x1f48c; 所属专栏&#xff1a;【Markdown常用语法】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &#x1…

2023年,自动化测试岗位有这么吃香吗

测试人员需要具备自动化测试或者测试开发能力&#xff0c;已经成为测试行业内容的一种显在趋势&#xff0c;而且这种趋势呈放大态势&#xff0c;其发展前景是十分明朗的。 2022疫情期间&#xff0c;就业大环境不是很理想&#xff0c;目前呢&#xff0c;企业倾向于招自动化测试…

易基因项目文章| 组蛋白ChIP-seq揭示烟粉虱含菌细胞共生菌调控宿主生殖的新机制

喜报&#xff1a;易基因组蛋白ChIP-seq研究成果见刊《Cell Reports》2023年02月10日&#xff0c;沈阳农业大学植物保护学院博士研究生姚亚林为第一作者、栾军波教授为论文通讯作者在《Cell Reports》杂志以“A bacteriocyte symbiont determines whitefly sex ratio by regulat…

④ 链表

24. 两两交换链表中的节点 题目链接&#xff1a;https://leetcode.cn/problems/swap-nodes-in-pairs/ 注意点&#xff1a; 遍历链表的时候什么时候截止&#xff08;避免空指针异常或无限死循环的问题&#xff09;&#xff1f; 节点数量为偶数或链表为空时&#xff0c;cur.ne…

关于欧拉角你需要知道几个点

基础理解&#xff0c;参照&#xff1a;https://www.cnblogs.com/Estranged-Tech/p/16903025.html 欧拉角、万向节死锁&#xff08;锁死&#xff09;理解 一、欧拉角理解 举例讲解 欧拉角用三次独立的绕确定的轴旋转角度来表示姿态。如下图所示 经过三次旋转&#xff0c;旋…

原创不易,坚持更难

早上CSDN发消息&#xff0c;今天是创作满三年的纪念日&#xff0c;邀请写一篇博文&#xff0c;谈谈感受 开博原因 2020年是一个特殊的年份&#xff0c;疫情刚爆发第一年&#xff0c;也是第一次居家办公&#xff0c;从过完年就一直居家办公&#xff0c;一直居家了38天。2020年…

宗教生活污水处理项目的设计原则

我国的历史源远流长&#xff0c;许多传统文化都延续了上千年以上。同时&#xff0c;我国也是宗教信仰自由的国家&#xff0c;儒释道文化相互影响&#xff0c;交相辉映。游人穿过山间小道&#xff0c;走到寺院庄严礼拜&#xff0c;游客和信众的增多&#xff0c;使教堂、寺庙等宗…

机器学习笔记之谱聚类(一)k-Means聚类算法介绍

机器学习笔记之谱聚类——K-Means聚类算法介绍引言回顾&#xff1a;高斯混合模型聚类任务基本介绍距离计算k-Means\text{k-Means}k-Means算法介绍k-Means\text{k-Means}k-Means算法示例k-Means\text{k-Means}k-Means算法与高斯混合模型的关系k-Means\text{k-Means}k-Means算法的…