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

news/2024/12/29 2:30:55/

在操作系统中,声卡、网卡之类的设备驱动并不像硬盘、鼠标、键盘等等驱动直接编写就行了。它们是建立在内核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        0x00int 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 outlfor(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 edxmov dx, [esp + 2 * 4]mov al, [esp + 3 * 4]out dx, alpop edxretalign 16
_out16: ; void out16(unsigned short port, unsigned short data);push edxmov dx, [esp + 2 * 4]mov ax, [esp + 3 * 4]out dx, axpop edxretalign 16
_out32: ; void out32(unsigned short port, unsigned int data);push edxmov dx, [esp + 2 * 4]mov eax, [esp + 3 * 4]out dx, eaxpop edxretalign 16
_out8_: ; void out8_(unsigned char data, unsigned short port);push edxmov dx, [esp + 3 * 4]mov al, [esp + 2 * 4]out dx, alpop edxretalign 16
_out16_: ; void out16_(unsigned short data, unsigned short port);push edxmov dx, [esp + 3 * 4]mov ax, [esp + 2 * 4]out dx, axpop edxretalign 16
_out32_: ; void out32_(unsigned int data, unsigned short port);push edxmov dx, [esp + 3 * 4]mov eax, [esp + 2 * 4]out dx, eaxpop edxretalign 16
_in8_:
_in8: ; unsigned char in8(unsigned short port);push edxmov dx, [esp + 2 * 4]in al, dxpop edxretalign 16
_in16_:
_in16: ; unsigned short in16(unsigned short port);push edxmov dx, [esp + 2 * 4]in ax, dxpop edxretalign 16
_in32_:
_in32: ; unsigned int in32(unsigned short port);push edxmov dx, [esp + 2 * 4]in eax, dxpop edxret

下边是探测到的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.ppmy.cn/news/26693.html

相关文章

模拟用户登录-课后程序(JAVA基础案例教程-黑马程序员编著-第五章-课后作业)

【案例5-3】 模拟用户登录 【案例介绍】 1.任务描述 在使用一些APP时&#xff0c;通常都需要填写用户名和密码。用户名和密码输入都正确才会登录成功&#xff0c;否则会提示用户名或密码错误。 本例要求编写一个程序&#xff0c;模拟用户登录。程序要求如下&#xff1a; 用…

力扣mysql刷题记录

mysql刷题记录 刷题链接https://leetcode.cn/study-plan/sql/?progressjkih0qc mysql冲&#xff01;mysql刷题记录一. 1699. 两人之间的通话次数题解二、1251. 平均售价题解三. 1571. 仓库经理题解四.1445. 苹果和桔子解五.1193. 每月交易 I题解六.1633. 各赛事的用户注册率题…

如何使用Hugo Academic Theme构建自己的github主页

前期条件 自己已经注册好GitHub 搜索Hugo Academic Theme&#xff08;网址&#xff09; 进入后的网址为&#xff1a;https://academic-demo.netlify.app/ 点击Get Start 出现如下模板&#xff0c;选择一个喜欢的模板&#xff0c;点击“START WITH ACADEMIC RESUME” 点击 …

calico-kube-controllers 启动失败处理

故障描述calico-kube-controllers 异常&#xff0c;不断重启日志信息如下2023-02-21 01:26:47.085 [INFO][1] main.go 92: Loaded configuration from environment config&config.Config{LogLevel:"info", WorkloadEndpointWorkers:1, ProfileWorkers:1, PolicyW…

CAD正式学习(一)

CAD正式学习&#xff08;一&#xff09;&#xff08;23.2.20&#xff09; CAD简介 CAD是Autodesk&#xff08;欧特克&#xff09;公司首次于1982年开发的自动计算机辅助软件&#xff0c;主要用于二维绘图、详细绘制、设计文档和基本三维设计&#xff0c;是广为流行的绘图工具…

Web前端:什么是Vue Native 框架?有什么特点?

Vue Native是一个使用Vue.Js开发本地移动应用程序的框架。该框架将文档转换为React Native&#xff0c;进而为你提供适用于Android和iOS的本地应用程序。实际上&#xff0c;Vue Native应用程序据说是React API的包装。Vue将Vue.js和React结合在一起&#xff0c;让你的开发团队充…

学习OpenGL图形2D/3D编程

环境:Windows+Visual Studio 2019 最流行的几个库:GLUT,SDL,SFML和GLFW

我的创作纪念日

机缘 不敢相信已经整整四年了&#xff0c;从以前刚上大学的青涩&#xff0c;到现在对计算机和编程有了一些了解&#xff0c;真是感慨&#xff0c;时间流逝&#xff0c;这几年发生了很多&#xff0c;人也渐渐成长。哎&#xff0c;人生能有几个四年&#xff1f; 收获 提示&…