MapPtrToProcess 用法 WINCE驱动分析3 转

本文探讨了在Windows CE环境下,应用程序与驱动程序间内存指针的映射问题。详细介绍了通过DeviceIoControl进行数据交换时,不同类型的指针(如栈上分配与堆上分配)的正确处理方式,以及何时需要使用MapPtrToProcess函数。

可以使用下面的应用程序代码测试这个driver,使用evc编译。

#include <windows.h>

#include<Windev.h>

#include <stdio.h>

#include "objbase.h"

#include "initguid.h"

 

#include "foo.h"

 

//char data1[10];

int  WinMain(void)

{

 

 

    HANDLE hnd;

    COPY_STRUCT cs[1];

    int i;

    //static char data1[10];

  auto char data1[10];

    auto char data2[10];

 

    static char* p1,*p2;

 

    //cs.pBuffer1 = (char *)malloc(10);

    //cs.pBuffer2 = (char*)malloc(10);

    //cs.nLen = 10;

 

    p1 = (char *)LocalAlloc(LPTR,10);

    p2 = (char *)malloc(10);

 

    //cs[0].pBuffer1 = (char *)malloc(10);

    //cs[0].pBuffer2 = (char*)malloc(10);

    cs[0].pBuffer1 = &data1[0];

    cs[0].pBuffer2 = &data2[0];

    cs[0].nLen = 10;

 

    memset(cs[0].pBuffer1,'a',10);

 

    hnd = CreateFile(FOO_DEV_NAME,GENERIC_READ|GENERIC_WRITE,0,NULL,0,0,NULL);

 

    if(hnd==NULL)

    {

           printf("Open device falied!/n");

           return;

    }

 

    DeviceIoControl(hnd,IOCTL_FOO_XER,&cs[0],sizeof(COPY_STRUCT),NULL,0,NULL,NULL);

 

    //for(i=0;i<9;i++)

    //{

           //printf(" %c",*(cs.pBuffer2++));

    //}

 

    printf("/n");

 

    CloseHandle(hnd);

 

//  free(cs[0].pBuffer1);

//  free(cs[0].pBuffer2);

 

 

}

 

可以通过evc的单步调试看结果。好了一切都完成了,我们来看看系统是怎么工作的吧,从应用程序开始,

CreateFile(FOO_DEV_NAME,GENERIC_READ|GENERIC_WRITE,0,NULL,0,0,NULL);

 

会调用到

FOO_Open(DWORD dwContext, DWORD AccessCode, DWORD ShareMode)

 

FOO_DEV_NAME名字定义在foo.h里面。

#define       FOO_DEV_NAME L"Foo1:"

注意后面是 1 ,这个是和注册表的这一项匹配的

"Index"=dword:1

 

当调用CreateFile发生了什么,slot之间的转换,一系列系统操作后,调用到我们自己的driver函数FOO_Open,在这个函数里我们返回了一个句柄,它可以用来存储我们的自己driver的信息。在其它I/O操作中可以使用。

 

Driver什么时候加载的?在注册表里,device manager会一个个的加载,会调用到FOO_Init函数。这个函数返回一个指针,在调用FOO_Open又传回来了,这样我们就可以实现初始化一些自己driver的东西。

 

接着一个重要的函数,

DeviceIoControl(hnd,IOCTL_FOO_XER,&cs[0],sizeof(COPY_STRUCT),NULL,0,NULL,NULL);

调用到

FOO_IOControl

 

走到这里

case IOCTL_FOO_XER:

           if((pInBuf==NULL))

                  {

                         SetLastError(ERROR_INVALID_PARAMETER);

                         break;

                  }

 

                  pcs = (COPY_STRUCT*)pInBuf;

                 

                  __try{

                         pMap1 =  MapPtrToProcess(pcs->pBuffer1,GetCallerProcess());

                         pMap2 =  MapPtrToProcess(pcs->pBuffer2,GetCallerProcess());

 

                         DEBUG_OUT(1, (TEXT("+FOO_IOControl(0x%x,0x%x)/r/n"),pcs->pBuffer1,pcs->pBuffer2));

 

                         memcpy(pcs->pBuffer2,pcs->pBuffer1,pcs->nLen);

 

                         bResult = TRUE;

                         }

                  __except(EXCEPTION_EXECUTE_HANDLER){

                         DEBUG_OUT(1,(TEXT("Exception:FOO_IOCTL/r/n")));

                         break;                         

                  }

                 

                  break;

           default:

                  break;

 

这里又很多东西要研究,

 

从应用程序传来的参数有, control codeIOCTL_FOO_XER和一个重要的输入参数&cs[0],它是一个指针。cs 是一个结构体,定义在FOO.H

typedef struct {

    char* pBuffer1;

    char* pBuffer2;

    int nLen;

 

}COPY_STRUCT;

 

而且这个结构体里有两个指针。

DeviceIoControl 传过来的指针可以用吗?它包含的两个指针可以直接用吗?

 

按照PB连接帮助文档看,

The operating system (OS ) manages pointers passed directly as parameters. Drivers must map all pointers contained in structures. DeviceIoControl buffers are often structures that contain data, some of which might be pointers.

You can map a pointer contained in a structure by calling MapPtrToProcess, setting the first parameter to the pointer, and then setting the second parameter to GetCallerProcess.

cs指针已经映射好了,但是它指向的结构里的指针我们需要自己使用MapPtrToProcess函数映射。

这也就是:

                         pMap1 =  MapPtrToProcess(pcs->pBuffer1,GetCallerProcess());

                         pMap2 =  MapPtrToProcess(pcs->pBuffer2,GetCallerProcess());

的由来,可是后面的代码没有使用pMap1pMap2。而是直接使用:

memcpy(pcs->pBuffer2,pcs->pBuffer1,pcs->nLen);

 

而且它还工作了,没有出现exception。很奇怪。我第一次在一个家伙的代码里看见这种情况,很吃惊,但是它工作的很好,是文档出错了?

我们来分析一下,看看应用程序的代码:

    COPY_STRUCT cs[1];

  auto char data1[10];

    auto char data2[10];

cs结构和data1data2数组都是自动变量,存放在堆栈里。假设这个应用程序被加载到0x18000000位置的slot里,那么他们的地址都是0x18XXXXXX。不熟悉wince memory architecture的可以看看资料,了解一下slot。当调用了

DeviceIoControl,按照文档的说法,cs指针得到了转换,因为从应用程序的进程转到了device.exe进程,而device进程又是当前的运行的进程,被映射到了slot0,系统负责转换cs指针。而cs包含的pBuffer1pBuffer2是没有映射不能直接用的。

事实上,我们传过来的指针根本就是不需要映射,因为他们都是0x18xxxxxx,在应用程序的slot里,所以只要device.exe有访问应用程序的权限,就可以了。而这个权限,系统已经帮我们设置好了。

 

那什么情况下要自己映射呢?

如果应用程序在定义 data1data2使用static关键字,或者使用LocalAllocHeapAlloc的时候,一定要自己映射cs里的指针。

在应用程序里这样写:

    cs.pBuffer1 = (char *)malloc(10);

    cs.pBuffer2 = (char*)malloc(10);

    cs.nLen = 10;

如果不使用MapPtrToProcess完成映射,那就出现data abort exception.

 

为什么呢?

因为这些变量都是在堆里分配的,而当应用程序运行时,被映射到slot0,堆的地址也就是处于slot的范围内,传递到device.exe后,device.exe被映射到了slot0,这个时候必须要将应用程序的指针映射回应用程序所在的slot。否则访问的是device.exe的空间,会发生不可知道的结果。

 

验证一下上面说的地址分配问题。

 

我们这样定义

COPY_STRUCT cs[1];

  static char data1[10]; 堆里

  auto char data2[10];   栈里

 

这样赋值:

 

  cs[0].pBuffer1 = &data1[0];

  cs[0].pBuffer2 = &data2[0];

  cs[0].nLen = 10;

 

调试信息:

cs[0].pBuffer1 = &data1[0];

 

180112D0   ldr       r2, [pc, #0xD0]

180112D4   str       r2, [sp, #0x10]

 

读取&data1[0]使用的是PC作为基址,而此时的应用程序处于运行阶段映射到slot0,那么pc也就在0~01ffffff范围,我的调试结果是在0x000112D0+8,使用的是arm,流水线机制,当前指令地址+8才是pc值。

 

143:      cs[0].pBuffer2 = &data2[0];

180112D8   add       r0, sp, #0x20

180112DC   str       r0, [sp, #0x14]

读取&data2[0]采用的是sp作为基址,sp在应用程序加载到slot的时候就确定了的。所以保持了在应用程序slot的值,处于0x18xxxxxx范围。

 

我们看到因为winceslot机制,我们有时候需要映射,有时候不需要。所以wince文档说结构里的指针要映射。毕竟你不知道应用程序怎么写。

当然,你可以根本不映射,只要把那个结构屏蔽调,写一个STATIC LIBRARY给用户使用,自己保证使用正确的地址分配就可以了。上面我说的那个家伙就是这么干的。

 

好了,接着

调用:

  CloseHandle(hnd);

程序结束了,完成了一次简单的拷贝。

 

这个框架完成了,driver的基本接口设计,强调了内存指针的使用问题。但是相对于一个真正的driver,还缺少点东西,就是访问硬件的方法。下面继续讨论如何访问硬件。
内容概要:本文介绍了一种用于电磁暂态(EMT)研究的第四类全变流器型风力发电系统的通用Simulink仿真模型,旨在构建一个能够准确反映实际风电系统动态特性的简化通用模型。该模型涵盖了风力机、传动链、发电机、全功率变流器及其控制策略等关键组成部分,重点突出系统在电网故障、风速波动等复杂工况下的动态响应能力,适用于风电并网电磁暂态分析、新型电力系统稳定性评估及高比例可再生能源接入场景的研究。模型设计兼顾准确性与仿真效率,便于研究人员快速搭建和调试,推动风电系统建模与控制技术的发展; 适合人群:具备一定电力系统理论基础和MATLAB/Simulink仿真能力,从事新能源发电、电力电子变换、风电并网控制及相关方向的研究生、科研人员及工程技术人员; 使用场景及目标:①开展风电系统在电网扰动下的电磁暂态仿真分析;②研究全功率变流器风电机组的动态行为与控制特性;③支撑新型电力系统中高渗透率风电接入的稳定性与电能质量评估,服务于学术研究、课程教学与工程项目前期仿真验证; 阅读建议:建议读者结合文中提供的模型结构与参数设置,在Simulink环境中动手复现并调试仿真模型,通过设置不同运行工况(如三相短路、低电压穿越、风速突变等)观察系统响应,深入理解全变流器风电机组的建模方法、控制逻辑与动态特性,进而拓展应用于更复杂的多机并网或综合能源系统仿真场景。
内容概要:本文探讨了Hash算法在芯片行业,特别是网络处理器(NPU)中的性能优化实践,聚焦于如何通过硬件流水线设计实现纳秒级高速哈希查找。文章分析了传统软件哈希方案在高带宽场景下的局限性,提出基于硬件描述语言或高层次综合(HLS)的设计方法,采用CRC32等硬件友好型哈希函数、并行多路哈希、流水线化解耦以及双端口存储结构等核心技术,实现低延迟、无阻塞的数据包处理。通过C++风格的HLS代码示例,展示了从算法选择到资源优化的完整硬件加速逻辑,并深入剖析了循环展开、位宽控制、内存映射和流水线调度等关键实现细节。最后展望了可编程交换机、P4语言支持及TCAM与哈希混合架构等未来发展方向。; 适合人群:具备数字电路基础、熟悉Verilog/SystemVerilog或HLS的芯片设计工程师,以及从事网络芯片、FPGA加速、高性能路由设备研发的技术人员(工作年限1-5年为宜);也适合对硬件加速算法感兴趣的研究人员。; 使用场景及目标:①掌握如何将哈希算法高效映射到硬件逻辑中以满足线速发需求;②理解流水线设计、资源约束优化、读写冲突规避等在实际芯片项目中的应用;③为开发高性能网络处理器中的流表/路由表查找单元提供技术参考与实现范例。; 阅读建议:学习时应结合HLS工具(如Xilinx Vitis HLS)进行代码仿真与综合,重点关注#pragma指令对硬件结构的影响,并对比不同哈希算法在资源占用与时序表现上的差异,深入理解“空间换时间”的硬件优化本质。
内容概要:本文系统研究了基于粒子群优化(PSO)、灰狼优化(GWO)、鲸鱼优化(WOA)、哈里斯鹰优化(HHO)、蜣螂优化(DBO)和麻雀搜索算法(SSA)六种智能优化算法在无人机三维路径规划中的应用,并在Matlab平台上实现了相应的仿真代码。研究构建了复杂的三维地形与障碍物环境模型,设计了包含路径长度、飞行时间、能耗及安全性等多维度的成本函数,通过定义合理的适应度函数与飞行约束条件,对各类算法的路径搜索能力、收敛速度与规划质量进行了全面对比分析。通过仿真实验验证了各算法在静态复杂环境下的性能表现,旨在为实际无人机任务中优化算法的选择提供科学依据和技术支持。; 适合人群:具备一定Matlab编程基础,从事智能优化算法、无人机路径规划、自动化控制及相关领域研究的研究生、科研人员或工程技术人员。; 使用场景及目标:① 掌握主流群智能优化算法在无人机三维路径规划中的建模与实现方法;② 对比分析不同算法在相同复杂环境下的性能差异,为算法选型提供量化依据;③ 为后续研究动态环境路径规划、多无人机协同任务分配等问题奠定理论与技术基础; 阅读建议:建议读者结合提供的Matlab代码逐模块分析算法实现流程,重点关注适应度函数的设计、障碍物规避策略的实现以及多目标成本函数的权衡机制,同时可通过调整参数设置或引入新型优化算法进行扩展实验,以深化对算法性能的理解与实际应用能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值