Condividi tramite


Minidriver, driver miniport e coppie di driver

Un minidriver o un miniport driver funge da metà di una coppia di driver. Le coppie di driver come (miniport, porta) possono semplificare lo sviluppo dei driver. In una coppia di driver, un driver gestisce attività generali comuni a un'intera raccolta di dispositivi, mentre l'altro driver gestisce attività specifiche di un singolo dispositivo. I driver che gestiscono attività specifiche del dispositivo passano da un'ampia gamma di nomi, tra cui miniport driver, miniclass driver e minidriver.

Microsoft fornisce il driver generale e in genere un fornitore hardware indipendente fornisce il driver specifico. Prima di leggere questo argomento, è necessario comprendere le idee presentate nei nodi del dispositivo e negli stack di dispositivi enei pacchetti di richiesta di I/O.

Ogni driver in modalità kernel deve implementare una funzione denominata DriverEntry, che viene chiamata poco dopo il caricamento del driver. La funzione DriverEntry riempie determinati membri di una struttura DRIVER_OBJECT con puntatori a diverse altre funzioni implementate dal driver. Ad esempio, la funzione DriverEntry riempie il membro Scarica della struttura DRIVER_OBJECT con un puntatore alla funzione Scarica driver, come illustrato nel diagramma seguente.

diagramma che mostra la struttura dell'oggetto driver con il membro di scaricamento.

Il membro MajorFunction della struttura DRIVER_OBJECT è una matrice di puntatori alle funzioni che gestiscono i pacchetti di richiesta di I/O (IRP), come illustrato nel diagramma seguente. In genere il driver riempie diversi membri della matrice MajorFunction con puntatori alle funzioni (implementate dal driver) che gestiscono vari tipi di IRP.

diagramma che mostra la struttura dell'oggetto driver con il membro majorfunction.

Un'IRP può essere categorizzata in base al relativo codice di funzione principale, identificato da una costante, ad esempio IRP_MJ_READ, IRP_MJ_WRITE o IRP_MJ_PNP. Le costanti che identificano il codice della funzione principale fungono da indici nella matrice MajorFunction . Si supponga, ad esempio, che il driver implementi una funzione di invio per gestire i provider di accesso con codice di funzione principale IRP_MJ_WRITE. In questo caso, il driver deve compilare l'elemento MajorFunction[IRP_MJ_WRITE] della matrice con un puntatore alla funzione di invio.

In genere il driver riempie alcuni degli elementi della matrice MajorFunction e lascia gli elementi rimanenti impostati su valori predefiniti forniti dalla gestione I/O. Nell'esempio seguente viene illustrato come usare l'estensione del debugger !drvobj per controllare i puntatori di funzione per il driver parport.

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

Nell'output del debugger è possibile notare che parport.sys implementa GsDriverEntry, il punto di ingresso per il driver. GsDriverEntry, generato automaticamente al momento della compilazione del driver, esegue alcune inizializzazione e quindi chiama DriverEntry, implementato dallo sviluppatore del driver.

È anche possibile notare che il driver parport (nella relativa funzione DriverEntry ) fornisce puntatori per inviare funzioni per questi codici di funzione principali:

  • 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

Gli elementi rimanenti dei puntatori di blocco della matrice MajorFunction alla funzione di invio predefinita nt! IopInvalidDeviceRequest.

Nell'output del debugger è possibile notare che il driver parport ha fornito puntatori di funzione per Il caricamento e AddDevice, ma non ha fornito un puntatore di funzione per StartIo. La funzione AddDevice è insolita perché il puntatore alla funzione non è archiviato nella struttura DRIVER_OBJECT . Viene invece archiviato nel membro AddDevice di un'estensione alla struttura DRIVER_OBJECT . Il diagramma seguente illustra i puntatori alle funzioni forniti dal driver parport nella relativa funzione DriverEntry . I puntatori di funzione forniti da parport sono ombreggiati.

diagramma dei puntatori di funzione in una struttura a oggetti driver.

Semplificando l'uso di coppie di driver

In un periodo di tempo, poiché gli sviluppatori di driver all'interno e all'esterno di Microsoft hanno acquisito esperienza con il modello di driver Windows (WDM), hanno realizzato un paio di cose sulle funzioni di invio:

  • Le funzioni di invio sono in gran parte boilerplate. Ad esempio, gran parte del codice nella funzione di invio per IRP_MJ_PNP è uguale per tutti i driver. È solo una piccola parte del codice Plug and Play (PnP) specifico di un singolo driver che controlla un singolo componente hardware.
  • Le funzioni di invio sono complesse e difficili da ottenere correttamente. L'implementazione di funzionalità come la sincronizzazione dei thread, l'accodamento IRP e l'annullamento di IRP è complessa e richiede una conoscenza approfondita del funzionamento del sistema operativo.

Per semplificare gli sviluppatori di driver, Microsoft ha creato diversi modelli di driver specifici della tecnologia. A prima vista, i modelli specifici della tecnologia sembrano piuttosto diversi tra loro, ma un aspetto più vicino rivela che molti di loro si basano su questo paradigma:

  • Il driver è suddiviso in due parti: una che gestisce l'elaborazione generale e una che gestisce l'elaborazione specifica di un determinato dispositivo.
  • Il pezzo generale è scritto da Microsoft.
  • Il pezzo specifico può essere scritto da Microsoft o da un fornitore hardware indipendente.

Si supponga che le aziende proseware e Contoso facciano entrambi un robot toy che richiede un driver WDM. Si supponga anche che Microsoft fornisca un driver robot generale denominato GeneralRobot.sys. Proseware e Contoso possono scrivere piccoli driver che gestiscono i requisiti dei robot specifici. Ad esempio, Proseware potrebbe scrivere ProsewareRobot.sys e la coppia di driver (ProsewareRobot.sys, GeneralRobot.sys) potrebbe essere combinata per formare un singolo driver WDM. Analogamente, la coppia di driver (ContosoRobot.sys, GeneralRobot.sys) potrebbe combinare per formare un singolo driver WDM. Nella forma più generale, l'idea è che è possibile creare driver usando (specific.sys, general.sys) coppie.

Puntatori di funzione nelle coppie driver

In una coppia (specific.sys, general.sys) Windows carica specific.sys e chiama la relativa funzione DriverEntry . La funzione DriverEntry di specific.sys riceve un puntatore a una struttura DRIVER_OBJECT . Normalmente si prevede che DriverEntry riempia diversi elementi della matrice MajorFunction con puntatori per inviare le funzioni. Si prevede inoltre che DriverEntry inserisca il membro Unload (e possibilmente il membro StartIo) della struttura DRIVER_OBJECT e il membro AddDevice dell'estensione dell'oggetto driver. Tuttavia, in un modello di coppia di driver , DriverEntry non esegue necessariamente questa operazione. Invece la funzione DriverEntry di specific.sys passa la struttura DRIVER_OBJECT insieme a una funzione di inizializzazione implementata da general.sys . Nell'esempio di codice seguente viene illustrato come la funzione di inizializzazione potrebbe essere chiamata nella coppia (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);
}

La funzione di inizializzazione in GeneralRobot.sys scrive puntatori di funzione ai membri appropriati della struttura DRIVER_OBJECT (e alla relativa estensione) e agli elementi appropriati della matrice MajorFunction . L'idea è che quando il gestore di I/O invia un'IRP alla coppia di driver, l'IRP passa prima a una funzione di invio implementata da GeneralRobot.sys. Se GeneralRobot.sys può gestire autonomamente l'IRP, il driver specifico, ProsewareRobot.sys, non deve essere coinvolto. Se GeneralRobot.sys può gestire alcuni elementi, ma non tutti, dell'elaborazione IRP, ottiene assistenza da una delle funzioni di callback implementate da ProsewareRobot.sys. GeneralRobot.sys riceve puntatori ai callback prosewareRobot nella chiamata GeneralRobotInit.

A un certo punto dopo che DriverEntry restituisce, uno stack di dispositivi viene costruito per il nodo del dispositivo Proseware Robot. Lo stack di dispositivi potrebbe essere simile al seguente.

diagramma del nodo del dispositivo robot proseware, che mostra tre oggetti dispositivo nello stack di dispositivi: afterthought.sys (filtro do), prosewarerobot.sys, generalrobot.sys (fdo) e pci.sys (pdo).

Come illustrato nel diagramma precedente, lo stack di dispositivi per Proseware Robot ha tre oggetti dispositivo. L'oggetto dispositivo principale è un oggetto del dispositivo di filtro (Filter DO) associato al driver di filtro AfterThought.sys. L'oggetto dispositivo centrale è un oggetto dispositivo funzionale associato alla coppia di driver (ProsewareRobot.sys, GeneralRobot.sys). La coppia di driver funge da driver di funzione per lo stack di dispositivi. L'oggetto dispositivo inferiore è un oggetto dispositivo fisico (PDO) associato a Pci.sys.

Si noti che la coppia di driver occupa un solo livello nello stack di dispositivi ed è associata a un solo oggetto dispositivo: l'oggetto FDO. Quando GeneralRobot.sys elabora un'IRP, può chiamare ProsewareRobot.sys per assistenza, ma non è uguale al passaggio della richiesta nello stack di dispositivi. La coppia di driver forma un singolo driver WDM a un livello nello stack di dispositivi. La coppia di driver completa l'IRP o lo passa allo stack di dispositivi al PDO, associato a Pci.sys.

Esempio di coppia di driver

Si supponga di avere una scheda di rete wireless nel computer portatile e cercando in Gestione dispositivi, si determina che netwlv64.sys è il driver per la scheda di rete. È possibile usare l'estensione del debugger !drvobj per controllare i puntatori di funzione per 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

Nell'output del debugger è possibile notare che netwlv64.sys implementa GsDriverEntry, il punto di ingresso per il driver. GsDriverEntry, generato automaticamente al momento della compilazione del driver, esegue alcune inizializzazione e quindi chiama DriverEntry, scritto dallo sviluppatore del driver.

In questo esempio netwlv64.sys implementa DriverEntry, ma ndis.sys implementa AddDevice, Unload e diverse funzioni di invio. Netwlv64.sys viene chiamato un driver miniport NDIS e ndis.sys viene chiamato libreria NDIS. Insieme, i due moduli formano una coppia (miniport NDIS, libreria NDIS).

Questo diagramma mostra lo stack di dispositivi per la scheda di rete wireless. Si noti che la coppia di driver (netwlv64.sys, ndis.sys) occupa un solo livello nello stack di dispositivi ed è associato a un solo oggetto dispositivo: l'oggetto FDO.

diagramma dello stack di schede di rete wireless, che mostra netwlv64.sys, ndis.sys come coppia di driver associata al fdo e pci.sys associato al pdo .

Coppie di driver disponibili

I diversi modelli di driver specifici della tecnologia usano un'ampia gamma di nomi per le parti specifiche e generali di una coppia di driver. In molti casi, la parte specifica della coppia ha il prefisso "mini". Ecco alcune coppie (specifiche, generali) disponibili:

  • (display miniport driver, display port driver)
  • (driver miniport audio, driver della porta audio)
  • (driver miniport di archiviazione, driver porta di archiviazione)
  • (miniclasse batteria, driver di classe batteria)
  • (minidriver HID, driver di classe HID)
  • (driver miniclasse changer, driver porta changer)
  • (driver miniport NDIS, libreria NDIS)

Nota Come si può vedere nell'elenco, diversi modelli usano il driver di classe termine per la parte generale di una coppia di driver. Questo tipo di driver di classe è diverso da un driver di classe autonomo e diverso da un driver di filtro di classe.

Concetti per tutti gli sviluppatori di driver

Nodi del dispositivo e stack di dispositivi

Stack di driver