liskman
驱动牛犊
驱动牛犊
  • 注册日期2002-05-11
  • 最后登录2007-08-31
  • 粉丝0
  • 关注0
  • 积分61分
  • 威望7点
  • 贡献值0点
  • 好评度6点
  • 原创分0分
  • 专家分0分
阅读:1484回复:3

怎样将硬件地址映射到用户程序中?

楼主#
更多 发布于:2003-12-05 14:24
能不能将硬件的物理地址映射到当前用户进程中,使用用户程序直接使用CopyMemory函数读写硬件内存?
在DDK中该使用什么函数?

最新喜欢:

mapoflmapofl
流云
exdata
驱动牛犊
驱动牛犊
  • 注册日期2002-11-11
  • 最后登录2007-07-16
  • 粉丝0
  • 关注0
  • 积分30分
  • 威望3点
  • 贡献值0点
  • 好评度3点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2003-12-07 17:34
MapPhysicalMemoryToLinearSpace
exdata
驱动牛犊
驱动牛犊
  • 注册日期2002-11-11
  • 最后登录2007-07-16
  • 粉丝0
  • 关注0
  • 积分30分
  • 威望3点
  • 贡献值0点
  • 好评度3点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2003-12-07 17:37
//copy from WINIO source code:

NTSTATUS MapPhysicalMemoryToLinearSpace(PVOID pPhysAddress,
                                        ULONG PhysMemSizeInBytes,
                                        PVOID *ppPhysMemLin,
                                        HANDLE *pPhysicalMemoryHandle)
{
  UNICODE_STRING     PhysicalMemoryUnicodeString;
  PVOID              PhysicalMemorySection = NULL;
  OBJECT_ATTRIBUTES  ObjectAttributes;
  PHYSICAL_ADDRESS   ViewBase;
  NTSTATUS           ntStatus;
  PHYSICAL_ADDRESS   pStartPhysAddress;
  PHYSICAL_ADDRESS   pEndPhysAddress;
  PHYSICAL_ADDRESS   MappingLength;
  BOOLEAN            Result1, Result2;
  ULONG              IsIOSpace;
  unsigned char     *pbPhysMemLin = NULL;

  OutputDebugString (\"Entering MapPhysicalMemoryToLinearSpace\");

  RtlInitUnicodeString (&PhysicalMemoryUnicodeString,
                        L\"\\\\Device\\\\PhysicalMemory\");

  InitializeObjectAttributes (&ObjectAttributes,
                              &PhysicalMemoryUnicodeString,
                              OBJ_CASE_INSENSITIVE,
                              (HANDLE) NULL,
                              (PSECURITY_DESCRIPTOR) NULL);

  *pPhysicalMemoryHandle = NULL;

  ntStatus = ZwOpenSection (pPhysicalMemoryHandle,
                            SECTION_ALL_ACCESS,
                            &ObjectAttributes);

  if (NT_SUCCESS(ntStatus))
  {

    ntStatus = ObReferenceObjectByHandle (*pPhysicalMemoryHandle,
                                          SECTION_ALL_ACCESS,
                                          (POBJECT_TYPE) NULL,
                                          KernelMode,
                                          &PhysicalMemorySection,
                                          (POBJECT_HANDLE_INFORMATION) NULL);

    if (NT_SUCCESS(ntStatus))
    {

      pStartPhysAddress.QuadPart = (ULONGLONG)pPhysAddress;

      pEndPhysAddress = RtlLargeIntegerAdd (pStartPhysAddress,
                                            RtlConvertUlongToLargeInteger(PhysMemSizeInBytes));

      IsIOSpace = 0;

      Result1 = HalTranslateBusAddress (1, 0, pStartPhysAddress, &IsIOSpace, &pStartPhysAddress);

      IsIOSpace = 0;

      Result2 = HalTranslateBusAddress (1, 0, pEndPhysAddress, &IsIOSpace, &pEndPhysAddress);

      if (Result1 && Result2)
      {

        MappingLength = RtlLargeIntegerSubtract (pEndPhysAddress, pStartPhysAddress);

        if (MappingLength.LowPart)
        {
        
          // Let ZwMapViewOfSection pick a linear address

          PhysMemSizeInBytes = MappingLength.LowPart;

          ViewBase = pStartPhysAddress;

          ntStatus = ZwMapViewOfSection (*pPhysicalMemoryHandle,
                                         (HANDLE) -1,
                                         &pbPhysMemLin,
                                         0L,
                                         PhysMemSizeInBytes,
                                         &ViewBase,
                                         &PhysMemSizeInBytes,
                                         ViewShare,
                                         0,
                                         PAGE_READWRITE | PAGE_NOCACHE);

          if (!NT_SUCCESS(ntStatus))
            OutputDebugString (\"ERROR: ZwMapViewOfSection failed\");
          else
          {
            pbPhysMemLin += (ULONG)pStartPhysAddress.LowPart - (ULONG)ViewBase.LowPart;
            *ppPhysMemLin = pbPhysMemLin;
          }  
        }
        else
          OutputDebugString (\"ERROR: RtlLargeIntegerSubtract failed\");
      }
      else
        OutputDebugString (\"ERROR: MappingLength = 0\");
    }
    else
      OutputDebugString (\"ERROR: ObReferenceObjectByHandle failed\");
  }
  else
    OutputDebugString (\"ERROR: ZwOpenSection failed\");
    
  if (!NT_SUCCESS(ntStatus))
    ZwClose(*pPhysicalMemoryHandle);
  
  OutputDebugString (\"Leaving MapPhysicalMemoryToLinearSpace\");

  return ntStatus;
}
liskman
驱动牛犊
驱动牛犊
  • 注册日期2002-05-11
  • 最后登录2007-08-31
  • 粉丝0
  • 关注0
  • 积分61分
  • 威望7点
  • 贡献值0点
  • 好评度6点
  • 原创分0分
  • 专家分0分
地板#
发布于:2003-12-07 19:06
非常感谢.

我在DDK中也找到了其它方法,非常适用于KernelDriver中.

使用KernelDriver6.11,假设一块PCI卡,有1024字节缓存,想要映射到用户程序中,使用户程序可以直接读写,方法如下:

驱动程序中的TEST_STRUCT结构体中增加两中定义
  PMDL pMdl;
  PVOID pUserVirtualAddress;

在TEST_Open例程中,WD_CardRegister函数调用成功后,在hTEST结构体中已经有PCI卡内存的物理地址和ring0虚拟地址,想要得到ring3虚拟地址,过程如下:
在return TRUE;前面加入
hTEST->pMdl = IoAllocateMdl((PVOID)hTEST->cardReg.Card.Item[hTEST->addrDesc[AD_PCI_BAR1].index].I.Mem.dwTransAddr),1024, FALSE, FALSE, NULL);
if(hTEST->pMdl != NULL)
{
  MmBuildMdlForNonPagedPool(hhTEST->pMdl);
  hTEST->pUserVirtualAddress = MmMapLockedPages(hTEST->pMdl,UserMode);//得到ring3虚拟地址!
}

这样就把PCI卡上的内存映射到了用户程序中,通过DeviceIoControl,把映射指针pUserVirtualAddress传给用户程序,用户程序就可以直接读写PCI卡的内存了。

最后在驱动程序关闭时的操作:
在TEST_Close例程中的开头加入
if (hTEST->pMdl != NULL)
{
  MmUnmapLockedPages(hTEST->pUserVirtualAddress, hTEST->pMdl);
  IoFreeMdl(hTEST->pMdl);
}

有不正确处,请高手指正.
流云
游客

返回顶部