Verwenden der direkten E/A mit PIO
Ein Treiber, der anstelle von DMA (Programmed I/O) programmierte E/A (PIO) verwendet, muss Benutzerraumpuffer einem Adressbereich des Systemraums doppelt zuordnen. Die folgende Abbildung veranschaulicht, wie der E/A-Manager eine IRP_MJ_READ-Anforderung für einen PIO-Übertragungsvorgang einrichtet, der direkte E/A verwendet.
Die Abbildung zeigt, wie ein Gerät, das PIO verwendet, dieselbe Aufgabe verarbeitet.
Ein Bereich von virtuellen Benutzerspeicheradressen stellt den Puffer des aktuellen Threads dar, und der Inhalt dieses Puffers kann tatsächlich auf einer Anzahl physisch nicht ordnungsgemäßer Seiten gespeichert werden. Wenn die Pufferlänge ungleich null ist, erstellt der E/A-Manager eine MDL, um diesen Puffer zu beschreiben.
Der E/A-Manager verarbeitet die Leseanforderung des aktuellen Threads, für die der Thread einen Bereich von virtuellen Benutzerraumadressen übergibt, die einen Puffer darstellen.
Der E/A-Manager oder FSD überprüft den vom Benutzer bereitgestellten Puffer auf Barrierefreiheit. Wenn der E/A-Manager eine MDL erstellt hat, ruft er MmProbeAndLockPages mit einer MDL auf, die den Bereich der virtuellen Adressen für den Benutzerpuffer angibt. MmProbeAndLockPages füllt auch den entsprechenden physischen Adressbereich in der MDL aus.
Der E/A-Manager stellt einen Zeiger auf die MDL (MdlAddress) in einem IRP bereit, der einen Übertragungsvorgang anfordert. Bis der E/A-Manager oder das Dateisystem MmUnlockPages aufruft , nachdem der Treiber die IRP abgeschlossen hat, bleiben die in der MDL beschriebenen physischen Seiten gesperrt und dem Puffer zugewiesen. Die virtuellen Adressen in einer solchen MDL können jedoch unsichtbar (und ungültig) werden, bevor der IRP an den Gerätetreiber oder einen zwischengeschalteten Treiber gesendet wird, der sich möglicherweise über dem Gerätetreiber befindet.
Wenn der Treiber (virtuelle) Systemadressen benötigt, ruft der Treiber MmGetSystemAddressForMdlSafe mit dem MdlAddress-Zeiger des IRP auf, um die virtuellen Benutzerraumadressen in der MDL einem Adressbereich des Systembereichs zuzuordnen. In der obigen Abbildung stellt AliasBuff die MDL dar, die die doppelt zugeordneten Adressen beschreibt.
Der Treiber verwendet den virtuellen Adressbereich des Systemraums aus der doppelt zugeordneten MDL (AliasBuff), um Daten in den Arbeitsspeicher zu lesen.
Wenn der Treiber die IRP durch Aufrufen von IoCompleteRequest abschließt, gibt der E/A-Manager oder das Dateisystem den doppelt zugeordneten Systemraumbereich der MDL frei, wenn der Treiber MmGetSystemAddressForMdlSafe aufgerufen hat. Der E/A-Manager oder das Dateisystem entsperrt die in der MDL beschriebenen Seiten und entwendet die MDL und den IRP im Namen des Treibers. Um die Leistung zu verbessern, sollten Treiber vermeiden, dass physische MDL-Adressen wie in Schritt 3 beschrieben dem Systemspeicher doppelt zugeordnet werden, es sei denn, sie müssen virtuelle Adressen verwenden. Auf diese Weise werden unnötig Systemseitentabelleneinträge verwendet und können sowohl die Treiberleistung als auch die Skalierbarkeit verringern. Darüber hinaus kann das System abstürzen, wenn keine Seitentabelleneinträge vorhanden sind, da die meisten älteren Treiber diese Situation nicht bewältigen können.
Die Puffer des aktuellen Benutzerthreads und der Thread selbst befinden sich garantiert nur dann im physischen Speicher, wenn dieser Thread aktuell ist. Für den in der vorherigen Abbildung gezeigten Thread kann der Inhalt des Benutzerpuffers in den sekundären Speicher ausgelagert werden, während die Threads eines anderen Prozesses ausgeführt werden. Wenn der Thread eines anderen Prozesses ausgeführt wird, kann der physische Systemspeicher für den Puffer des anfordernden Threads überschrieben werden, es sei denn, der Speicher-Manager hat die entsprechenden physischen Seiten, die den Puffer des ursprünglichen Threads enthalten, gesperrt und beibehalten.
Die virtuellen Adressen des ursprünglichen Threads für den Puffer bleiben jedoch nicht sichtbar, während ein anderer Thread aktuell ist, auch wenn der Speicher-Manager die physischen Seiten des Puffers bei behält. Daher können Treiber keine virtuelle Adresse verwenden, die von MmGetMdlVirtualAddress zurückgegeben wird, um auf den Arbeitsspeicher zuzugreifen. Aufrufer dieser Routine müssen ihre Ergebnisse an MapTransfer (zusammen mit dem MdlAddress-Zeiger des IRP) übergeben, um Daten mit paketbasiertem System oder bus-master DMA zu übertragen.