Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
En minidrivrutin eller en miniportdrivrutin fungerar som hälften av ett drivrutinpar. Ett drivrutinspar som till exempel (miniport, port) kan göra utvecklingen av drivrutiner enklare. I ett drivrutinspar hanterar en drivrutin allmänna uppgifter som är gemensamma för en hel samling enheter, medan den andra drivrutinen hanterar uppgifter som är specifika för en enskild enhet. De drivrutiner som hanterar enhetsspecifika uppgifter har en mängd olika namn, inklusive miniportdrivrutin, miniklassdrivrutin och minidrivrutin.
Microsoft tillhandahåller den allmänna drivrutinen, och vanligtvis tillhandahåller en oberoende maskinvaruleverantör den specifika drivrutinen. Innan du läser det här avsnittet bör du förstå de idéer som presenteras i Enhetsnoder och enhetsstackar och I/O-begärandepaket.
Varje drivrutin i kernelläge måste implementera en funktion med namnet DriverEntry, som anropas kort efter att drivrutinen har lästs in. Funktionen DriverEntry fyller i vissa element i en DRIVER_OBJECT struktur med pekare till flera andra funktioner som drivrutinen implementerar. Funktionen DriverEntry fyller till exempel i Unload-medlemmen i DRIVER_OBJECT-strukturen med en pekare till drivrutinens Unload-funktion, enligt följande diagram.
MajorFunction medlem i DRIVER_OBJECT-strukturen är en matris med pekare till funktioner som hanterar I/O-begärandepaket (IRP-s), enligt följande diagram. Vanligtvis fyller drivrutinen i flera medlemmar i MajorFunction-fältet med pekare till funktioner (implementerade av drivrutinen) som hanterar olika typer av IRP:er.
En IRP kan kategoriseras enligt dess huvudfunktionskod, som identifieras av en konstant, till exempel IRP_MJ_READ, IRP_MJ_WRITEeller IRP_MJ_PNP. Konstanterna som identifierar viktig funktionskod fungerar som index i matrisen MajorFunction. Anta till exempel att drivrutinen implementerar en dispatch-funktion för att hantera IRP:er som har huvudfunktionskoden IRP_MJ_WRITE. I det här fallet måste drivrutinen fylla i elementet MajorFunction[IRP_MJ_WRITE] i matrisen med en pekare till dispatchfunktionen.
Vanligtvis fyller drivrutinen i några av elementen i matrisen MajorFunction och lämnar de återstående elementen inställda på standardvärden som tillhandahålls av I/O-chefen. I följande exempel visas hur du använder !drvobj debuggertillägg för att inspektera parport-drivrutinens funktionspekare.
0: kd> !drvobj parport 2
Driver object (fffffa80048d9e70) is for:
\Driver\Parport
DriverEntry: fffff880065ea070 parport!GsDriverEntry
DriverStartIo: 00000000
DriverUnload: fffff880065e131c parport!PptUnload
AddDevice: fffff880065d2008 parport!P5AddDevice
Dispatch routines:
[00] IRP_MJ_CREATE fffff880065d49d0 parport!PptDispatchCreateOpen
[01] IRP_MJ_CREATE_NAMED_PIPE fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[02] IRP_MJ_CLOSE fffff880065d4a78 parport!PptDispatchClose
[03] IRP_MJ_READ fffff880065d4bac parport!PptDispatchRead
[04] IRP_MJ_WRITE fffff880065d4bac parport!PptDispatchRead
[05] IRP_MJ_QUERY_INFORMATION fffff880065d4c40 parport!PptDispatchQueryInformation
[06] IRP_MJ_SET_INFORMATION fffff880065d4ce4 parport!PptDispatchSetInformation
[07] IRP_MJ_QUERY_EA fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[08] IRP_MJ_SET_EA fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[09] IRP_MJ_FLUSH_BUFFERS fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[0a] IRP_MJ_QUERY_VOLUME_INFORMATION fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[0b] IRP_MJ_SET_VOLUME_INFORMATION fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[0c] IRP_MJ_DIRECTORY_CONTROL fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[0d] IRP_MJ_FILE_SYSTEM_CONTROL fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[0e] IRP_MJ_DEVICE_CONTROL fffff880065d4be8 parport!PptDispatchDeviceControl
[0f] IRP_MJ_INTERNAL_DEVICE_CONTROL fffff880065d4c24 parport!PptDispatchInternalDeviceControl
[10] IRP_MJ_SHUTDOWN fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[11] IRP_MJ_LOCK_CONTROL fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[12] IRP_MJ_CLEANUP fffff880065d4af4 parport!PptDispatchCleanup
[13] IRP_MJ_CREATE_MAILSLOT fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[14] IRP_MJ_QUERY_SECURITY fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[15] IRP_MJ_SET_SECURITY fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[16] IRP_MJ_POWER fffff880065d491c parport!PptDispatchPower
[17] IRP_MJ_SYSTEM_CONTROL fffff880065d4d4c parport!PptDispatchSystemControl
[18] IRP_MJ_DEVICE_CHANGE fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[19] IRP_MJ_QUERY_QUOTA fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[1a] IRP_MJ_SET_QUOTA fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[1b] IRP_MJ_PNP fffff880065d4840 parport!PptDispatchPnp
I debuggerns utdata kan du se att parport.sys implementerar GsDriverEntry, inträdespunkten för drivrutinen. GsDriverEntry, som genererades automatiskt när drivrutinen skapades, utför viss initiering och anropar sedan DriverEntry, som implementerades av drivrutinsutvecklaren.
Du kan också se att parporteringsdrivrutinen (i dess DriverEntry-funktion) innehåller pekare för att skicka funktioner för dessa viktiga funktionskoder:
- IRP_MJ_CREATE
- IRP_MJ_CLOSE
- IRP_MJ_READ
- IRP_MJ_WRITE
- IRP_MJ_QUERY_INFORMATION
- IRP_MJ_SET_INFORMATION
- IRP_MJ_DEVICE_CONTROL
- IRP_MJ_INTERNAL_DEVICE_CONTROL
- IRP_MJ_CLEANUP
- IRP_MJ_POWER
- IRP_MJ_SYSTEM_CONTROL
- IRP_MJ_PNP
De återstående elementen i MajorFunction matrisen innehåller pekare till dispatchstandardfunktionen nt!IopInvalidDeviceRequest.
I felsökningsprogrammets utdata kan du se att parportdrivrutinen gav funktionspekare för Avlasta och AddDevice, men inte gav en funktionspekare för StartIo. Funktionen AddDevice är ovanlig eftersom funktionspekaren inte lagras i strukturen DRIVER_OBJECT. I stället lagras den i AddDevice medlem i ett tillägg till DRIVER_OBJECT-strukturen. Följande diagram illustrerar de funktionspekare som parportdrivrutinen angav i funktionen DriverEntry. Funktionspekare som tillhandahålls av parport är skuggade.
Gör det enklare genom att använda förarpar
Under en tidsperiod, när drivrutinsutvecklare inom och utanför Microsoft fick erfarenhet av Windows Driver Model (WDM), insåg de ett par saker om dispatch-funktioner:
- Dispatch-funktioner är till stor del standardkod. Till exempel är mycket av koden i funktionen dispatch för IRP_MJ_PNP densamma för alla drivrutiner. Det är bara en liten del av PnP-koden (Plug and Play) som är specifik för en enskild drivrutin som styr en enskild maskinvarudel.
- Dispatch-funktioner är komplicerade och svåra att få rätt. Det är svårt att implementera funktioner som trådsynkronisering, IRP-köer och IRP-annullering och kräver en djup förståelse för hur operativsystemet fungerar.
För att göra det enklare för förarutvecklare skapade Microsoft flera teknikspecifika drivrutinsmodeller. Vid första anblicken verkar de teknikspecifika modellerna helt annorlunda än varandra, men en närmare titt visar att många av dem är baserade på detta paradigm:
- Drivrutinen är uppdelad i två delar: en som hanterar den allmänna bearbetningen och en som hanterar bearbetning som är specifik för en viss enhet.
- Den allmänna delen är skriven av Microsoft.
- Den specifika delen kan vara skriven av Microsoft eller en oberoende maskinvaruleverantör.
Anta att både Proseware- och Contoso-företagen gör en leksaksrobot som kräver en WDM-drivrutin. Anta också att Microsoft tillhandahåller en allmän robotdrivrutin med namnet GeneralRobot.sys. Proseware och Contoso kan var och en skriva små drivrutiner som hanterar kraven för deras specifika robotar. Proseware kan till exempel skriva ProsewareRobot.sysoch de två drivrutinerna (ProsewareRobot.sys, GeneralRobot.sys) kan kombineras för att bilda en enda WDM-drivrutin. På samma sätt kan drivrutinsparet (ContosoRobot.sys, GeneralRobot.sys) kombineras för att bilda en enda WDM-drivrutin. I sin mest allmänna form är tanken att du kan skapa drivrutiner med hjälp av (specific.sys, general.sys) par.
Funktionspekare i drivpar
I ett par (specific.sys, general.sys) laddar Windows specific.sys och anropar DriverEntry-funktionen. Funktionen DriverEntry hos specific.sys tar emot en pekare till en DRIVER_OBJECT-struktur. Normalt kan du förvänta dig att DriverEntry fyller i flera element i MajorFunction-array med pekare till dispatch-funktioner. Du kan också förvänta dig att DriverEntry fyller i Unload-medlemmen (och eventuellt StartIo-medlemmen) i DRIVER_OBJECT-strukturen samt AddDevice-medlemmen i drivrutinsobjektets tillägg. Men i en modell med drivrutinspar behöver DriverEntry inte nödvändigtvis göra detta. Funktionen DriverEntry i specific.sys skickar i stället DRIVER_OBJECT-strukturen till en initieringsfunktion som implementeras av general.sys. I följande kodexempel visas hur initieringsfunktionen kan anropas i paret (ProsewareRobot.sys, GeneralRobot.sys).
PVOID g_ProsewareRobottCallbacks[3] = {DeviceControlCallback, PnpCallback, PowerCallback};
// DriverEntry function in ProsewareRobot.sys
NTSTATUS DriverEntry (DRIVER_OBJECT *DriverObject, PUNICODE_STRING RegistryPath)
{
// Call the initialization function implemented by GeneralRobot.sys.
return GeneralRobotInit(DriverObject, RegistryPath, g_ProsewareRobottCallbacks);
}
Initieringsfunktionen i GeneralRobot.sys skriver funktionspekare till lämpliga medlemmar i DRIVER_OBJECT-strukturen (och dess utvidgning) och lämpliga element i MajorFunction-matrisen. Tanken är att när I/O-hanteraren skickar en IRP till drivrutinsparet går IRP först till distributionsfunktionen som implementeras av GeneralRobot.sys. Om GeneralRobot.sys kan hantera IRP på egen hand behöver den specifika drivrutinen, ProsewareRobot.sys, inte vara inblandad. Om GeneralRobot.sys kan hantera vissa, men inte alla, av IRP-bearbetningen får den hjälp från en av återanropsfunktionerna som implementeras av ProsewareRobot.sys. GeneralRobot.sys tar emot pekare till callbacks för ProsewareRobot i GeneralRobotInit-anropet.
Vid någon tidpunkt efter att DriverEntry- returnerar, konstrueras en enhetsstack för Proseware Robot-enhetsnoden. Enhetsstacken kan se ut så här.
Som du ser i föregående diagram har enhetsstacken för Proseware Robot tre enhetsobjekt. Det översta enhetsobjektet är ett filterenhetsobjekt (Filter DO) som är associerat med filterdrivrutinen AfterThought.sys. Det mellersta enhetsobjektet är ett funktionellt enhetsobjekt (FDO) som är associerat med drivrutinsparet (ProsewareRobot.sys, GeneralRobot.sys). Drivrutinsparet fungerar som funktionsdrivrutin för enhetsstacken. Det nedre enhetsobjektet är ett fysiskt enhetsobjekt (PDO) som är associerat med Pci.sys.
Observera att drivrutinsparet endast upptar en nivå i enhetsstacken och endast är associerat med ett enhetsobjekt: FDO. När GeneralRobot.sys bearbetar en IRP kan den anropa ProsewareRobot.sys för hjälp, men det är inte samma sak som att skicka begäran nedåt i enhetsstacken. Drivarparet bildar en enda WDM-drivrutin som befinner sig på en nivå i enhetsstacken. Drivrutinsparet slutför antingen IRP eller skickar den nedåt i enhetsstacken till PDO:n, som är associerad med Pci.sys.
Exempel på ett drivpar
Anta att du har ett trådlöst nätverkskort på den bärbara datorn, och genom att titta i Enhetshanteraren kan du fastställa att netwlv64.sys är drivrutinen för nätverkskortet. Du kan använda debuggerutvidgningen !drvobj för att granska funktionspekarna för netwlv64.sys.
1: kd> !drvobj netwlv64 2
Driver object (fffffa8002e5f420) is for:
\Driver\netwlv64
DriverEntry: fffff8800482f064 netwlv64!GsDriverEntry
DriverStartIo: 00000000
DriverUnload: fffff8800195c5f4 ndis!ndisMUnloadEx
AddDevice: fffff88001940d30 ndis!ndisPnPAddDevice
Dispatch routines:
[00] IRP_MJ_CREATE fffff880018b5530 ndis!ndisCreateIrpHandler
[01] IRP_MJ_CREATE_NAMED_PIPE fffff88001936f00 ndis!ndisDummyIrpHandler
[02] IRP_MJ_CLOSE fffff880018b5870 ndis!ndisCloseIrpHandler
[03] IRP_MJ_READ fffff88001936f00 ndis!ndisDummyIrpHandler
[04] IRP_MJ_WRITE fffff88001936f00 ndis!ndisDummyIrpHandler
[05] IRP_MJ_QUERY_INFORMATION fffff88001936f00 ndis!ndisDummyIrpHandler
[06] IRP_MJ_SET_INFORMATION fffff88001936f00 ndis!ndisDummyIrpHandler
[07] IRP_MJ_QUERY_EA fffff88001936f00 ndis!ndisDummyIrpHandler
[08] IRP_MJ_SET_EA fffff88001936f00 ndis!ndisDummyIrpHandler
[09] IRP_MJ_FLUSH_BUFFERS fffff88001936f00 ndis!ndisDummyIrpHandler
[0a] IRP_MJ_QUERY_VOLUME_INFORMATION fffff88001936f00 ndis!ndisDummyIrpHandler
[0b] IRP_MJ_SET_VOLUME_INFORMATION fffff88001936f00 ndis!ndisDummyIrpHandler
[0c] IRP_MJ_DIRECTORY_CONTROL fffff88001936f00 ndis!ndisDummyIrpHandler
[0d] IRP_MJ_FILE_SYSTEM_CONTROL fffff88001936f00 ndis!ndisDummyIrpHandler
[0e] IRP_MJ_DEVICE_CONTROL fffff8800193696c ndis!ndisDeviceControlIrpHandler
[0f] IRP_MJ_INTERNAL_DEVICE_CONTROL fffff880018f9114 ndis!ndisDeviceInternalIrpDispatch
[10] IRP_MJ_SHUTDOWN fffff88001936f00 ndis!ndisDummyIrpHandler
[11] IRP_MJ_LOCK_CONTROL fffff88001936f00 ndis!ndisDummyIrpHandler
[12] IRP_MJ_CLEANUP fffff88001936f00 ndis!ndisDummyIrpHandler
[13] IRP_MJ_CREATE_MAILSLOT fffff88001936f00 ndis!ndisDummyIrpHandler
[14] IRP_MJ_QUERY_SECURITY fffff88001936f00 ndis!ndisDummyIrpHandler
[15] IRP_MJ_SET_SECURITY fffff88001936f00 ndis!ndisDummyIrpHandler
[16] IRP_MJ_POWER fffff880018c35e8 ndis!ndisPowerDispatch
[17] IRP_MJ_SYSTEM_CONTROL fffff880019392c8 ndis!ndisWMIDispatch
[18] IRP_MJ_DEVICE_CHANGE fffff88001936f00 ndis!ndisDummyIrpHandler
[19] IRP_MJ_QUERY_QUOTA fffff88001936f00 ndis!ndisDummyIrpHandler
[1a] IRP_MJ_SET_QUOTA fffff88001936f00 ndis!ndisDummyIrpHandler
[1b] IRP_MJ_PNP fffff8800193e518 ndis!ndisPnPDispatch
I felsökningsprogrammets utdata kan du se att netwlv64.sys implementerar GsDriverEntry, ingångspunkten för drivrutinen. GsDriverEntry, som genererades automatiskt när drivrutinen skapades, utför viss initiering och anropar sedan DriverEntry, som skrevs av drivrutinsutvecklaren.
I det här exemplet implementerar netwlv64.sys DriverEntry, men ndis.sys implementerar AddDevice, Unloadoch flera dispatch-funktioner. Netwlv64.sys kallas för en NDIS-miniportdrivrutin och ndis.sys kallas för NDIS-biblioteket. Tillsammans bildar de två modulerna ett (NDIS-miniport, NDIS-bibliotek) par.
Det här diagrammet visar enhetsstacken för det trådlösa nätverkskortet. Observera att drivrutinsparet (netwlv64.sys, ndis.sys) endast upptar en nivå i enhetsstacken och endast är associerat med ett enhetsobjekt: FDO.
Tillgängliga drivrutinpar
De olika teknikspecifika drivrutinsmodellerna använder en mängd olika namn för de specifika och allmänna delarna i ett drivrutinspar. I många fall har den specifika delen av paret prefixet "mini". Här är några av (specifika, allmänna) par som är tillgängliga:
- (visa miniportdrivrutin, visa portdrivrutin)
- (ljudminiportdrivrutin, ljudportdrivrutin)
- (miniportdrivrutin för lagring, lagringsportdrivrutin)
- (batteri miniklass drivrutin, batteriklass drivrutin)
- (HID-minidrivrutin, HID-klassdrivrutin)
- (ändringsdrivrutin för miniklass, växelportdrivrutin)
- (NDIS-miniportdrivrutin, NDIS-bibliotek)
Obs Som du kan se i listan, använder flera av modellerna termen klassdrivrutin för den allmänna delen av ett drivrutinspar. Den här typen av klassdrivrutin skiljer sig från en fristående klassdrivrutin och skiljer sig från en klassfilterdrivrutin.