Luigi Di Biasi


XP Programming Style
Sondaggio
Argomento Spider e WebCrawler

Interessante
Non interessante

Approfondimento sugli IRP e sul modello di I/O (Microsoft DDK)

IRP
I/O Request Packet
ATTENZIONE
 La traduzione potrebbe contenere ERRORI.
Inoltre potrebbero essere presenti OMISSIONI, CAMBIAMENTI o APPUNTI inseriti per rendere il testo più accessibile... a "me" in primis... 

PENSIERO PERSONALE:
"In questo post analizziamo come il DDK ci presenta gli IRP in modo da avere, durante la lettura del secondo tutorial, un'idea precisa degli oggetti che stiamo utilizzando. "

1) Panoramica sul modello di I/O dell'architettura NT

Qualsiasi sistema operativo definisce un modello di I/O (implicito o esplicito) per gestire il flusso dei dati da e per le periferiche. Una caratteristica del modello di I/O di Microsoft Windows è quello di supportare l'I/O asincrono. Inoltre il modello I/O possiede le seguenti caratteristiche:

- L'I/O Manager fornisce interfacce consistenti per tutti i driver in kernel-model inclusi i driver di basso-medio livello e i driver di tipo filesystem. Tutte le richieste di I/O sono gestite tramite gli IRPs (I/O request packets).

- Le operazioni di I/O sono stratificate. Il manager di I/O mette a disposizione servizi di sistema (syscall) che i sottosistemi e le applicazioni in user-mode possono richiamare. L'I/O manager intercetta queste chiamate, le incapsula in IRPs e le smista attraverso lo stack dei driver della periferica di destinazione

- L'I/O manager definisce un set di routine standard, alcune richieste e altre opzioni, che i driver devono supportare. Tutti i driver seguono relativamente un modello di implementazione consistente, date le differenze tra i dipi di periferiche. (bus, function, filter e filesystem)

- Come il sistema operativo stesso i driver sono object-based. I driver, le periferiche e l'hardware di sistema sono rappresentati com oggetti. L'I/O manager e gli altri componenti del sistema esportano delle routine di supporto per lo sviluppo in kernel mode (Kernel-mode driver support routines o KMDSR) che i driver possono chiamare per fare il loro lavoro manipolando gli oggetti appropriati.

Il sistema degli IRPs è utilizzato per la gestione del Plug-n-Play e del PowerManager. I sottosistemi di I/O, PnP e PowerManagment comunicano tra loro attraverso gli IRPs. Se il sottosistema PnP deve inviare una richiesta utilizza il 
sottosistema di I/O per inviare i messaggi ai driver. In questo modo viene utilizzato un unico modello di comunicazione.


2) NT, le periferiche, i driver e gli IRPs

Un computer è un insieme di varie perieriche che forniscono INPUT e OUTPUT da e verso il mondo. Tipicamente le periferiche sono le tastiere, i mouse, i controller audio e video, i dischi, le interfaccie di rete e molte altre. I driver sono dei software che permettono di collegare le periferiche al sistema operativo. Per questo motivo il concetto di I/O è di estrema importanza per il programmatore di Driver.

Il Manager I/O di Windows è un sottosistema che gestisce la comunicazione tra le applicazioni e le interfacce che vengono messe a disposizioen dai Driver. Dato che le periferiche potrebbero operare ad una velocità diversa dal sistema operativo la comunicazione tra queste due entità avviene attraverso pacchetti IRPs. Questi pacchetti sono molto simili ai pacchetti di rete oppure ai pacchetti di messaggi di Windows. Essi possono essere utilizzati sia per far comunicare il sistema operativo con i driver e sia per la comunicazione tra driver.

Il sottosistema di I/O di Windows fornisce, per i driver, un modello a livelli chiamato stack dei driver. Solitamente un IRP viaggia da un driver all'altro nello stesso stack per facilitare la comunicazione. Ad esempio un joystick avrebbe bisogno di comunicare con un hub USB, che a sua volta avrebbe bisogno di comunicare con un host controller USB, che a sua volta dovrebbe comunicare tramite un bus PCI con il resto dell'hardware. Lo stack consiste nei driver per Joystick, Hub USB, USB Host controller e PCI BUS. Questa comunicazione è coordinata avendo ogni driver nello stack per mandare e ricevere IRPs.

Non bisogna mai dimenticare che un driver DEVE RICEVERE E MANDARE IRPs, attraverso l'intero stack, in maniera tempestiva per operare in maniera efficiente. Se il tuo driver fa parte di uno stack e non esegue correttamente le operazioni di ricezione, gestione e passaggio delle informazioni potrebbe causare un crash del sistema.

Le routine che forniscono interfacce per utilizzare l'I/O manager usualmente hanno il prefisso Io come ad esempio IoCreateDevice

Il manager di I/O ha due sottocomponenti. PnP Manager e PowerManager. Entrambi gestiscono le funzionalità per le tecnologie di Pnp e di Power Managment. 


3) Cos'è un IRP e come viene rappresentato dal Sistema Operativo

Un IRP è la struttura di base che l'I/O manager utilizza per comunicare con i driver e che i driver utilizzano per comunicare tra loro. Ogni pacchetto IRP è composto da due parti differenti:

Header
E' una parte fissa dell'IRP. E' utilizzato dal manager di I/O per registrare informazioni sulla richiesta originale,come i parametri device-indipendent dei chiamante, l'indirizzo della device-object che rappresenta la periferica e altro. Inoltre è utilizzato per slavare informazioni sullo stato finale della richiesta.
IO Stack Location
Dopo l'header troviamo un insieme di I/O stack location, una per ogni driver contenuti nello stack dei driver. Ogni stack location (ognuna è associata ad un driver nella coda) contiene i parametri, i function-codes (IRP_MJ_XXX) e il contesto. 

I driver di alto livello possono controllare il valore nel membro Cancel associato al proprio IRP, tuttavia non potrebbero sapere niente sullo stato finale dell'IRP nel driver a basso livello. (Ad esempio un Cancel nel primo driver non implica una FAIL nell'ultimo) 

La struttura IRP è parzialmente opaca (e quindi non tutti i membri sono visibili) e rappresenta un I/O request Packet. I driver devono utilizzare solo alcuni membri perchè gli altri sono utilizzati dal sistema operativo.  Il DDK riporta la seguente definizione:

typedef struct _IRP {
  .
  .
  PMDL  MdlAddress;
  ULONG  Flags;
  union {
    struct _IRP  *MasterIrp;
    .
    .
    PVOID  SystemBuffer;
  } AssociatedIrp;
  .
  .
  IO_STATUS_BLOCK  IoStatus;
  KPROCESSOR_MODE  RequestorMode;
  BOOLEAN PendingReturned;
  .
  .
  BOOLEAN  Cancel;
  KIRQL  CancelIrql;
  .
  .
  PDRIVER_CANCEL  CancelRoutine;
  PVOID UserBuffer;
  union {
    struct {
    .
    .
    union {
      KDEVICE_QUEUE_ENTRY DeviceQueueEntry;
      struct {
        PVOID  DriverContext[4];
      };
    };
    .
    .
    PETHREAD  Thread;
    .
    .
    LIST_ENTRY  ListEntry;
    .
    .
    } Overlay;
  .
  .
  } Tail;
} IRP, *PIRP;

Membri:

MdlAddress

Se il metodo di I/O utilizzato per comunicare con il driver è di tipo Direct I/O e l'IRP è uno di quelli indicati di seguito, MDLAddress conterrà un puntatore a una struttura di tipo MemoryDescriptionList. 
Nel caso in cui il tipo di I/O non sia Direct I/O il membro è NULL
Questa struttura è utilizzata per determinare l'indirizzo fisico (visto che i programmi user-mode usano indirizzi logici) della porzione di memoria che driver e programma in user-mode utilizzeranno per comunicare. 
  Lista degli IRP associati a MDLAddress
IRP_MJ_READ: La struttura MDL descrive un buffer vuoto che il driver o la periferica devono riempire. Qualcuno ha chiesto una READ sulla periferica. 

IRP_MJ_WRITELa struttura MDL descrive un buffer che contiene informazioni inviate al driver o alla periferica. Qualcuno ha effettuato una WRITE sulla periferica.
Gli IRP che seguono sono legati agli IOCTLs
IRP_MJ_DEVICE_CONTROL or IRP_MJ_INTERNAL_DEVICE_CONTROL
Se il codice IOCTL specifica un metodo di trasferimento METHOD_IN_DIRECT il descrittore MDL descrive il buffer che contiene i dati inviati verso il device. 

Se invece il codice IOCTL specifica il metodo di trasferimento METHOD_OUT_DIRECT il descrittore MDL descrive un buffer vuoto dove il driver o la periferica andranno a scrivere.

Per ulteriori informazioni sui BUFFER che sono associati ai due metodi di trasferimento descritti fare riferimento alla sezione MSDN Buffer Descripton for I/O Control Codes

Flags
   Il driver di tipo FileSystem utilizzano questo campo che è di sola lettura per tutti i driver. Alcuni driver di alto
   livello e i driver per le interfacce di rete ( Network Driver ) invece oltre a leggerlo potrebbero anche settare una
    di queste maschere definite dal sistema.

IRP_NOCACHE

IRP_PAGING_IO

IRP_MOUNT_COMPLETION

IRP_SYNCHRONOUS_API

IRP_ASSOCIATED_IRP

IRP_BUFFERED_IO

IRP_DEALLOCATE_BUFFER

IRP_INPUT_OPERATION

IRP_SYNCHRONOUS_PAGING_IO

IRP_CREATE_OPERATION

IRP_READ_OPERATION

IRP_WRITE_OPERATION

IRP_CLOSE_OPERATION

IRP_DEFER_IO_COMPLETION

AssociatedIrp.MasterIrp
  E' un puntatore all'IRP primario in un IRP creato tramite la funzione IoMakeAssociatedIrp.

AssociatedIrp.SystemBuffer
   E' un puntatore a un buffer di sistema utilizzato con il metodo di I/O di tipo Buffered. Il tipo di buffer è determinato in base al tipo di IRP ( come per il Direct I/O)
IRP_MJ_READ
  Il buffer riceve dati dal Device o dal Driver. La dimensione del buffer è specificata attraverso il parametro   Parameters.Read.Length nella struttura IO_STACK_LOCATION.

IRP_MJ_WRITE
  Il buffer fornisce i dati al device o alla perifercia. La lunghezza è specificata nel parametro
  Parameters.Write.Length nella struttura IO_STACK_LOCATION.

IRP_MJ_DEVICE_CONTROL or IRP_MJ_INTERNAL_DEVICE_CONTROL

Il buffer rappresenta sia il buffer di Input che di Output fornito dalla funzione DeviceIoControl e IoBuildDeviceIoControlRequest. I dati in OUTPUT sovrascrivono quelli in INPUT. 

La lunghezza dell'input è specificata in Parameters.DeviceIoControl.InputBufferLenght nella struttura IO_STACK_LOCATION.

La lunghezza dell'output è specificata in Parameters.DeviceIoControl.OutputBufferLenght nella struttura IO_STACK_LOCATION.

Per ulteriori informazioni sui BUFFER che sono associati ai due metodi di trasferimento descritti fare riferimento alla sezione MSDN Buffer Descripton for I/O Control Codes

Se il driver utilizza il metodo Direct I/O il tipo di buffer è determianto dal tipo di IRP che può essere uno dei seguenti:

IRP_MJ_READ

IRP_MJ_WRITE

IRP_MJ_DEVICE_CONTROL or IRP_MJ_INTERNAL_DEVICE_CONTROL
  Il buffer rappresneta l'INPUT fornito con DeviceIoControl e IoBuildDeviceIoControlRequest. La lunghezza del   buffer è riportata in Parameters.DeviceIoControl.InputBufferLength nella struttura IO_STACK_LOCATION.

IoStatus
  Contiene la struttura IO_STATUS_BLOCK dove un driver può registrare informazioni di stato prima di chiamare   IoCompleteRequest.

RequestorMode
  Indica la modalità di esecuzione di chi ha richiesto l'operazione. Esistono due modalità UserMoed e KernelMode.

PendingReturned
  Se è settato a TRUE il driver marca l'IRP come 'pending'. Ogni IoCompletion routine farà il check del valore di questo
    flag. Se il flag è TRUE e se la routine IoCompletion non ritorna STATUS_MORE_PROCESSING_REQUIRED la routine   chiamerà IoMarkIrpPending per propagare lo stato di pending in tutto lo stack.
Cancel
  Se è settato a TRUE 
If set to TRUE, l'IRP viene annullato.
CancelIrql
          Contiene il livello IRQL dove sta girando il driver quando viene chiamata la funzione IoAcquireCancelSpinLock.

CancelRoutine
  Contiene l'entry-point che verrà richiamata quando l'IRP viene cancellato. Se questo membro è NULL l'IRP non può   essere cancelato.

UserBuffer
  Contiene l'indirizzo per un buffer di OUTPUT se l'IRP_MAJOR_CODE è uno tra  IRP_MJ_DEVICE_CONTROLIRP_MJ_INTERNAL_DEVICE_CONTROL e il metodo di I/O è METHOD_NEITHER. (ne Direct , ne buffer )

Tail.Overlay.DeviceQueueEntry
  Se l'IRP è in coda nella coda del device questo campo punta alla locazione nella coda. 
  Questo link può essere usato solo mentre il driver processa l'IRP

Tail.Overlay.DriverContext
  Se l'IRP non è in coda nella coda del device associato al driver questo campo può essere usato dal driver per   registrare fino a quattro puntatori.
  Questo link può essere usato solo mentre il driver processa l'IRP.

Tail.Overlay.Thread
  E' un puntatore al thread-control block del chiamante. I driver di alto livello che alloca IRP per driver di basso livello   di device removibili devono settare questo campo nell'IRP altrimenti l'FSD non potrà determianre quale thread   notificare quando accade qualcosa al media. 

Tail.Overlay.ListEntry
  Se il driver  gestisce la propria coda di IRP usa questo campo per collegare un IRP con il successivo. Questo link può   essere usato solo mentre il driver ha l'IRP bloccato nella sua coda oppure mentre lo sta processando.

Commenti
I membri non documentati della struttura IRP sono riservati. Solo l'I/O manager e l'FSD li utilizzano. 



mercoledì, 02 set 2009 Ore. 16.14
Statistiche
  • Views Home Page: 27.212
  • Views Posts: 51.100
  • Views Gallerie: 0
  • n° Posts: 41
  • n° Commenti: 33
Archivio Posts
Anno 2012

Anno 2011

Anno 2010

Anno 2009

Anno 2008
Copyright © 2002-2007 - Blogs 2.0
dotNetHell.it | Home Page Blogs
ASP.NET 2.0 Windows 2003