开发者

Looking for an explanation of kernel driver I/O interface capability

I am looking at ways of interfacing to specific hardware I/O addresses from various Windows versions from 32-bit XP up 64-bit Win7 and beyond. There seem to be various solutions published with varying degrees of capability under different Windows versions and I am trying to understand the possibilities for creating my own kernel driver. The most basic kernal I/O R/W capability seems to be the direct I/O operations such as READ_PORT_UCHAR and WRITE_PORT_UCHAR (and their word and long derivatives). I have also seen the technique below which I dont understand, appearing to be some memory mapping capability of which I have no experience and can find little readable documentation. Could someone comment on the suitability / compatibility of READ开发者_C百科_PORT_UCHAR / WRITE_PORT_UCHAR versus this mapping technique that I reproduce below please?

Thanks in advance.

case IOCTL_PHYMEM_MAP:

            if (dwInBufLen==sizeof(PHYMEM_MEM) && dwOutBufLen==sizeof(PVOID))
            {
                PHYSICAL_ADDRESS phyAddr;
                PVOID pvk, pvu;

                phyAddr.QuadPart=(ULONGLONG)pMem->pvAddr;

                //get mapped kernel address
                pvk=MmMapIoSpace(phyAddr, pMem->dwSize, MmNonCached);

                if (pvk)
                {
                    //allocate mdl for the mapped kernel address
                    PMDL pMdl=IoAllocateMdl(pvk, pMem->dwSize, FALSE, FALSE, NULL);
                    if (pMdl)
                    {
                        PMAPINFO pMapInfo;

                        //build mdl and map to user space
                        MmBuildMdlForNonPagedPool(pMdl);
                        pvu=MmMapLockedPages(pMdl, UserMode);

                        //insert mapped infomation to list
                        pMapInfo=(PMAPINFO)ExAllocatePool(\
                            NonPagedPool, sizeof(MAPINFO));
                        pMapInfo->pMdl=pMdl;
                        pMapInfo->pvk=pvk;
                        pMapInfo->pvu=pvu;
                        pMapInfo->memSize=pMem->dwSize;
                        PushEntryList(&lstMapInfo, &pMapInfo->link);

                        DebugPrint("Map physical 0x%x to virtual 0x%x, size %u", \
                            pMem->pvAddr, pvu, pMem->dwSize);

                        RtlCopyMemory(pSysBuf, &pvu, sizeof(PVOID));

                        irp->IoStatus.Information=sizeof(PVOID);
                    }
                    else
                    {
                        //allocate mdl error, unmap the mapped physical memory
                        MmUnmapIoSpace(pvk, pMem->dwSize);

                        irp->IoStatus.Status=STATUS_INSUFFICIENT_RESOURCES;
                    }
                }
                else
                    irp->IoStatus.Status=STATUS_INSUFFICIENT_RESOURCES;
            }
            else
                irp->IoStatus.Status=STATUS_INVALID_PARAMETER;

            break;


What are these I/O ports that you're trying to access? It's generally a Really Bad Idea to go partying on ports that you don't own because you have no way of synchronizing access to those ports with the driver that owns them, the O/S, or the BIOS (it's possible to take an SMI and have the BIOS start talking to ports that it thinks it owns).

The code snippet provided is also a horribly bad idea and should be burned. Basically, all it's doing is mapping a kernel virtual address to a device register (MmMapIoSpace) and then doing the work to then map that device register into user mode (MmMapLockedPages). There are two obvious problems with it:

1) You don't know the caching attributes of the memory, so randomly specifying MmNonCached can hang the system

2) Same as with I/O ports, you can't just arbitrarily access a device's registers. You can't properly synchronize yourself with the driver that owns them, so you're doomed to eventually borking your system.

-scott

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜