Windows DMA驱动调试
2019-07-13 20:16发布
生成海报
本文记录我调试微软官方提供的一个PCI驱动sample程序的过程。
一、开发环境和资源下载
1,在win10 X64操作系统下,安装VS2015+WDK10。(参考我前面的驱动开发入门篇)
2,使用TI6655 DSP开发板,点击打开链接。
3,下载微软官方发布在github上的驱动samples,点击打开链接,选择其中的“General/PLX9x5x”这个工程。
4,参考微软关于windows dma技术的文档,点击打开链接,该文档即以上面的工程代码为实例。
5,参考程序员博客:点击打开链接
二、调试过程
1,使用VS2015直接编译PLX9x5x工程,需选择debug模式和X64环境。
该工程分为sys和test两个模块,前者是驱动代码,后者是一个应用程序。
2,该工程中的inf文件(实际工程中是“.inx”,编译后会生产inf),其GUID和代码的public.h中的不一致,需修改为一致。这是唯一需要修改的地方。
3,将DSP开发板的venID和devID修改与inf文件中一致,在DSP侧修改即可。修改后,可以在“Windows设备管理”中查看。
(windows键+R,打开CMD,然后输入“devmgmt.msc”即可打开设备管理器;右键目标设备,选择属性,可以看详细信息,其中“硬件ID”即inf中需要填写一致的内容)
执行完以上操作,即可安装驱动,但此时驱动安装后显示不正确。实际上是没有配置DSP的“配置空间”。
4,在驱动的各个Routine中添加"KdPrint“打印信息,使用debugview查看驱动加载过程中的函数调用。
5,在init.c文件中的preparehardware函数中,扫描到memory resource后的地方,添加DSP配置空间的配置操作(调用DDK提供的写寄存器函数)。
//
// Parse the resource list and save the resource information.
//
for (i=0; i < WdfCmResourceListGetCount(ResourcesTranslated); i++) {
desc = WdfCmResourceListGetDescriptor( ResourcesTranslated, i );
if(!desc) {
TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
"WdfResourceCmGetDescriptor failed");
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
switch (desc->Type) {
case CmResourceTypeMemory:
bar = NULL;
if (foundSRAM && !foundSRAM2 &&
desc->u.Memory.Length == 0x400000) {
SRAM2BasePA = desc->u.Memory.Start;
SRAM2Length = desc->u.Memory.Length;
foundSRAM2 = TRUE;
bar = "BAR3";
KdPrint(("BAR3 found.
"));
}
if (foundRegs && !foundSRAM &&
desc->u.Memory.Length == 0x100000) {
SRAMBasePA = desc->u.Memory.Start;
SRAMLength = desc->u.Memory.Length;
foundSRAM = TRUE;
bar = "BAR2";
KdPrint(("BAR2 found.
" ));
}
if (!foundRegs &&
desc->u.Memory.Length == 0x1000) {
regsBasePA = desc->u.Memory.Start;
regsLength = desc->u.Memory.Length;
foundRegs = TRUE;
bar = "BAR0";
KdPrint(("BAR0 found.
"));
}
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
" - Memory Resource [%I64X-%I64X] %s",
desc->u.Memory.Start.QuadPart,
desc->u.Memory.Start.QuadPart +
desc->u.Memory.Length,
(bar) ? bar : "" );
KdPrint(("desc->u.Memory.Start is %x, desc->u.Memory.length is %x
", desc->u.Memory.Start, desc->u.Memory.Length));
break;
以上代码作用:扫描资源列表,获取windows操作系统为device分配的memory资源(可以再设备管理器的属性-》资源中看到)。保存系统分配的几块memory的基地址和长度。
6,将系统分配的空间基址和长度进行转换
// Map in the Registers Memory resource: BAR0
//
DevExt->RegsBase = (PUCHAR) LocalMmMapIoSpace(regsBasePA,
regsLength);
if (!DevExt->RegsBase) {
TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
" - Unable to map Registers memory %08I64X, length %d",
regsBasePA.QuadPart, regsLength);
return STATUS_INSUFFICIENT_RESOURCES;
}
DevExt->RegsLength = regsLength;
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
" - Registers %p, length %d",
DevExt->RegsBase, DevExt->RegsLength );
//
// Set seperated pointer to PCI9656_REGS structure.
//
DevExt->Regs = (PPCI9656_REGS) DevExt->RegsBase;
DevExt->Bar0Regs = (PBAR0_REGS)DevExt->RegsBase;
//
// Map in the SRAM Memory Space resource: BAR1
//
DevExt->SRAMBase = (PUCHAR) LocalMmMapIoSpace(SRAMBasePA,
SRAMLength);
if (!DevExt->SRAMBase) {
TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
" - Unable to map SRAM memory %08I64X, length %d",
SRAMBasePA.QuadPart, SRAMLength);
return STATUS_INSUFFICIENT_RESOURCES;
}
DevExt->SRAMLength = SRAMLength;
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
" - SRAM %p, length %d",
DevExt->SRAMBase, DevExt->SRAMLength );
7,DSP的“Configure空间”配置
// configure dsp bar
{
i = 0;
WRITE_REGISTER_ULONG((PULONG)&DevExt->Bar0Regs->ib_info[i].ib_bar, i);
WRITE_REGISTER_ULONG((PULONG)&DevExt->Bar0Regs->ib_info[i].ib_start_lo, regsBasePA.u.LowPart);
WRITE_REGISTER_ULONG((PULONG)&DevExt->Bar0Regs->ib_info[i].ib_start_hi, regsBasePA.u.HighPart);
WRITE_REGISTER_ULONG((PULONG)&DevExt->Bar0Regs->ib_info[i].ib_offset, PCIE_BASE_ADDRESS);
}
{
i = 1;
WRITE_REGISTER_ULONG((PULONG)&DevExt->Bar0Regs->ib_info[i].ib_bar, i);
WRITE_REGISTER_ULONG((PULONG)&DevExt->Bar0Regs->ib_info[i].ib_start_lo, SRAMBasePA.u.LowPart);
WRITE_REGISTER_ULONG((PULONG)&DevExt->Bar0Regs->ib_info[i].ib_start_hi, SRAMBasePA.u.HighPart);
WRITE_REGISTER_ULONG((PULONG)&DevExt->Bar0Regs->ib_info[i].ib_offset, MSMC_START);
}
{
i = 2;
WRITE_REGISTER_ULONG((PULONG)&DevExt->Bar0Regs->ib_info[i].ib_bar, i);
WRITE_REGISTER_ULONG((PULONG)&DevExt->Bar0Regs->ib_info[i].ib_start_lo, SRAM2BasePA.u.LowPart);
WRITE_REGISTER_ULONG((PULONG)&DevExt->Bar0Regs->ib_info[i].ib_start_hi, SRAM2BasePA.u.HighPart);
WRITE_REGISTER_ULONG((PULONG)&DevExt->Bar0Regs->ib_info[i].ib_offset, DDR_START);
}
DSP配置正确,此时再加载驱动,即显示运行正常。(DSP的配置可以根据芯片资料配置)
6,测试DMA读操作,需先注释init.c中的中断调用部分代码和read.c中的DMA操作硬件部分的代码。
7,添加相关的打印。
8,将error的初始值由FALSE改为TRUE,从而可以执行后面的completerequest操作,推出该Routine。
执行完以上操作,可以运行test工程,来查看read过程的函数调用(debugview)。
暂时调试到该步骤。
四、DMA配置
其实际就是将CommonBuffer的物理地址告诉DSP
三、经验总结
1,在驱动工程中,不要放其他inf文件,VS会优先编译inf文件,而不编译inx文件,会反复报编译错误。
2,用F5运行test程序时,报”createfile“失败。查看getlasterror,返回值为5——拒绝访问,这是权限不够引起的。需要以管理员身份运行VS或改程序。(应用程序掉系统函数失败,查看getlasterror非常重要)
3,需要禁用数字签名,参考我之前的相关博客。
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮