In diesem Kapitel sollen die theoretischen und praktischen Grundlagen vermittelt werden, die für die Entwicklung von Treibern notwendig sind. Neben der Entwicklungsumgebung wird zunächst beschrieben, wie Treiber übersetzt und installiert werden. Danach werden der grundlegende Aufbau eines Treibers und die wichtigsten Datenstrukturen erläutert. Anschließend werden das Debugging mit WinDbg erklärt und die Grundlagen des Eventlogging unter Windows NT dargelegt.
4.1 Erstellen von Treibern für Windows NT
4.1.1 Die Entwicklungsumgebung
Zur Entwicklung eines Treibers benötigt man im einfachsten Fall nur einen Rechner und die notwendige Software. Sobald man aber in die Verlegenheit kommt, Kerneldebugging betreiben zu müssen, bleibt keine andere Wahl, als zusätzlich einen zweiten Rechner zu verwenden, sofern man auf die Tools von Microsoft angewiesen ist.(Fußnote 9)
Entwicklungssystem |
Zielsystem |
|
Software |
Voraussetzung: Windows NT 4.0 retail build MS Internet Explorer 4.0 MS Visual C++ (Standard Headerfiles, MFC, nmake) NT Device Driver Development Kit (NT DDK) Win 32 Software Development Kit (Win32 SDK) Quellcode des Treibers Empfehlung: UltraEdit 32 Symbol Dateien vom Zielsystem |
Voraussetzung: Windows NT 4.0 retail build Windows NT 4.0 checked build Ausführbarer Treiber (driver executabel) Empfehlung: Windows NT Hardware Kompatibilitätstest (Windows NT HCT) Crash Dump File |
Hardware |
Voraussetzung: Windows NT 4.0 kompatible Hardware Empfehlung: Pentium 133 MHz 32 MB RAM Netzwerkkarte 1,5 GB freier Festplattenspeicher für Entwicklungstools |
Voraussetzung: Windows NT 4.0 kompatible Hardware Empfehlung: Pentium 90 MHz 24 MB RAM Netzwerkkarte |
Tabelle 4.1.1-1: Systemvoraussetzungen der Entwicklungsrechner
In [DDK96] werden die minimalen Systemvoraussetzungen beschrieben. Die Tabelle 4.1.1-1 enthält einen Überblick über die notwendige Software und Empfehlungen für die Hardware-Ausstattung der beiden Rechner.
Auf einem der beiden Rechner, dem Entwicklungssystem, wird die zur Erstellung des Treibers benötigte Software und der Kerneldebugger installiert. Der andere Rechner, das Zielsystem, wird mit der Hardware ausgerüstet, die der Treiber ansprechen soll. Sind die beiden Rechner unterschiedlich ausgestattet, sollte man den schnelleren als Entwicklungssystem benutzen. Um das Kerneldebugging zu ermöglichen, müssen die Rechner mit einem seriellen Nullmodemkabel verbunden werden. Es empfiehlt sich weiterhin, beide Rechner in ein Netzwerk zu integrieren, damit der Austausch der Daten nicht über Disketten erfolgen muß.
Zum Bearbeiten der Treiberquelltexte kann ein ganz normaler Texteditor verwendet werden. Der Autor benutzt den Editor UltraEdit, da er verschiedene Funktionen zur Vereinfachung der Programmierung bietet, wie z.B Syntaxhervorhebung, definierbare Shortcuts und den Aufruf externer Programme.
4.1.2 Übersetzen des Treibers
Bevor man den Treiber kompiliert, muß man zunächst die Zielumgebung auswählen. In der Testphase verwendet man normalerweise die Checked Build Umgebung, die im Gegensatz zur Free Build Umgebung, die Debuginformationen in den ausführbaren Treiber integriert. Zur Auswahl der Umgebung benutzt man entweder die Verknüpfungen, die durch das Setup Programm des Windows NT DDK eingerichtet wurden oder man startet von der Kommandozeile das Batch setenv mit den entsprechenden Parametern free oder checked. Wird beim Start von setenv kein Parameter übergeben, wird automatisch die Free Build Umgebung ausgewählt.
Nachdem die Zielumgebung ausgewählt wurde, wechselt man in das Quellcodeverzeichnis des Treibers und startet das Programm Build.
Das Programm Build übernimmt die Übersetzung des Treibers. Es löst dabei automatisch die Abhängigkeiten für die unterschiedlichen Hardwareplattformen, übernimmt den Aufruf von nmake, das die Datei MAKEFILE erstellt, und wählt die richtigen Parameter für den Compiler und den Linker. Dazu werden sogenannte Kommandofiles benutzt.
Build wertet folgende Kommandofiles im Verzeichnis \ddk\inc aus:
Standard Makefile für build (master control file)
bestimmt die Zielplattform
enthalten plattformspezifische Compiler und Linker Optionen
Zusätzlich werden im aktuellen Verzeichnis die Dateien SOURCES und MAKEFILE verarbeitet.
Der Name der Datei ist "SOURCES" ohne eine Dateiendung. Das File enthält eine Reihe von Schlüsselworten, die die Build Operation beschreiben. Die wichtigsten sind:
gibt eine Liste von Pfaden an, die die Headerfiles enthalten
Liste von Quelltextdateien
der Zielpfad
der Name des Treibers (ohne Endung)
die Endung des Treibers
legt den Typ des Ziels fest (DRIVER, GDI_DRIVER, MINIPORT, LIBRARY, DYNLINK, ...)
Bibliotheken die mit gelinkt werden
Dem Schlüsselwort muß ohne ein Leerzeichen ein "=" folgen. Zeilen die mit einem "#" beginnen, werden als Kommentarzeilen behandelt. Lange Zeilen können mit einem "\" auf der nächsten Zeile fortgesetzt werden.
Beispiel:
# # SOURCE - File für den Treiber K # TARGETNAME=k TARGETPATH=e:\myfiles\k TARGETTYPE=DRIVER INCLUDES=$(BASEDIR)\inc SOURCES= k.c\ k_msg.rc
Das Build Utility legt folgende drei Logfiles an:
enthält eine Liste der Kommandos, die NMAKE ausführt
enthält Warnungen, die aufgetreten sind
enthält eine Liste der Fehler, die aufgetreten sind
Die Abbildung 4.1.2-1 veranschaulicht die Verzeichnisstruktur, die das Build Utility beim Übersetzen des Treibers benutzt.
Abbildung 4.1.2-1: Verzeichnisstruktur des Build Tools
ACHTUNG: Build erstellt zwar die Pfade für die verschiedenen Plattformen, die Pfade FREE bzw. CHECKED müssen allerdings von Hand erstellt werden, sonst bricht das Programm mit der Fehlermeldung "Datei XX kann nicht geöffnet werden" ab. In der Praxis bedeutet dies, daß für die jeweilige Zielplattform die gesamte Verzeichnisstruktur von Hand erstellt werden muß.
4.1.3 Installation des Treibers
Es gibt mehrere Wege, um einen Treiber zu installieren. Man kann ihn manuell installieren, die Funktionen des Advanced Windows 32 Base API verwenden oder eine INF Datei benutzen, die vom Treiberentwickler bereitgestellt wurde.
Beim manuellen Installieren des Treibers muß man zunächst die ausführbare Datei (diese Datei hat die Endung ".SYS") in das Verzeichnis %SystemRoot%\SYSTEM32\ DRIVERS kopieren. Danach müssen einige Werte in die Registry eingetragen werden. Die Tabelle 4.1.3-1 gibt einen Überblick über die notwendigen Einträge.
Name |
Datentyp |
Beschreibung |
Treibername |
(Schlüssel) |
*) |
Type |
REG_DWORD |
Art des Treibers *) 0x1 – Kernel-Mode Treiber 0x2 – File-System Treiber |
Start |
REG_DWORD |
Wann soll der Treiber gestartet werden: *) 0x0 – SERVICE_BOOT_START Treiber wird vom OS Loader gestartet noch bevor das Betriebssystem (BS) geladen wurde. 0x1 – SERVICE_SYSTEM_START Treiber wird, nachdem das BS geladen wurde, gestartet (das BS ist noch in der Initialisierungsphase). 0x2 – SERVICE_AUTO_START Treiber wird nach dem vollständigem Start des BS vom Service Control Manager (SCM) gestartet 0x3 – SERVICE_DEMAND_START Treiber wird manuell gestartet (über die Systemsteuerung oder über WIN32 API Aufrufe) 0x4 – SERVICE_DISABLED Treiber kann nicht gestartet werden, bis der Registry-Eintrag Start einen andern Wert bekommt. |
ErrorControl |
REG_DWORD |
Reaktion vom System, wenn der Treiber nicht gestartet werden kann. *) 0x0 – Fehler im Log eintragen und ignorieren 0x1 – Fehler im Log eintragen und eine Meldung anzeigen 0x2 – Fehler im Log eintragen und mit der letzten bekannten funktionierenden Konfiguration neu starten 0x3 – Fehler im Log eintragen und System stoppen, falls die letzte bekannte funktionierende Konfiguration schon aktiv ist |
Group |
REG_SZ |
Gruppe des Treibers |
DependOnGroup |
REG_MULTI_SZ |
andere Treiber, die von diesem Treiber benötigt werden |
Tag |
REG_BINARY |
Treiber soll in Abhängigkeit der Reihenfolge in einer Gruppe geladen werden |
Parameters |
(Schlüssel) |
treiberspezifische Parameter |
*) - Eintrag wird benötigt |
Tabelle 4.1.3-1: Registry Einträge
Die Einträge müssen in folgendem Zweig in der Registry gesetzt werden:
HKEY_LOCAL_MACHINE ï ï - SYSTEM ï ï - CurrentControlSet ï ï - Services ï ï - Treibername ï ï - ErrorControl ï - Start ï - Type ï ï - Parameters ï ï - (Parameter des Treibers) ï - :
Die Erstellung der Einträge in der Registry kann auch über Skripte erfolgen. Ein solches Skript hat die Dateiendung ".REG". In dem Skript wird als erstes der Schlüssel mit kompletten Pfad in eckigen Klammern angegeben. Danach folgen die Werte, die der Schlüssel enthalten soll, mit dem Format:
"
Wertname" = Datentyp:WertBei Werten vom Typ REG_SZ oder REG_MULTI_SZ muß der Datentyp nicht angegeben werden. In einem Skript können mehrere Schlüssel verarbeitet werden.
Beispielscript zum Erstellen der Einträge (Datei k.reg):
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\k] "ErrorControl" = dword:00000001 "Type" = dword:00000001 "Start" = dword:00000001 "Group" = "Keyboard Class" "DisplayName" = "K"
Nachdem die Werte in die Registry eingetragen wurden, muß der Rechner neu gestartet werden. Abhängig vom Wert Start wird der Treiber entweder nach dem nächsten Start geladen oder man kann ihn in der Systemsteuerung über den Eintrag Geräte manuell starten. Dort kann man auch den Treiber entladen, sofern er dies unterstützt, und die Startoptionen ändern.
Der Service Control Manager (SCM) stellt über das Advanced Windows 32 Base API alle Funktionen zum Installieren, Laden und Entladen sowie zum Starten und Beenden eines Treibers zur Verfügung.
Im folgenden werden die wichtigsten Funktionen kurz beschrieben:
Eine komplette Beschreibung aller Funktionen des SCM findet man in [Visual98] unter "Plattform-SDK/Windows Base Services/Executables/Services".
Das vom Autor entwickelte Tool DRV_Load implemetiert mit Hilfe der Delphi Unit drivers.pas die beschriebenen Funktionen. Das Programm stellt eine grafische Oberfläche zum dynamischen Laden und Entladen von Treibern zur Verfügung und ist, gerade in der Entwicklungsphase eines Treibers, ein nützliches Hilfsmittel. Der Quellcode des Programms und der Unit, sowie eine kurze Programmbeschreibung befinden sich im Anhang.
Die Installation von Treibern mit Hilfe von INF Dateien ist ein weiterer Weg, Treiber in das System zu integrieren. In INF Dateien kann man festlegen, welche Dateien kopiert, gelöscht oder umbenannt werden sollen. Man kann Registry Änderungen vornehmen und man kann auf recht einfache Weise Treiber am SCM anmelden.
INF Dateien können mit einem einfachen Texteditor erstellt und bearbeitet werden. Jede INF Datei besteht aus mehreren sogenannten Sektionen, die jeweils verschiedene Aufgaben haben, wie z.B. Dateien kopieren oder einen Wert in der Registry setzen. Es gibt etwa 20 verschiedene Typen von Sektionen. Eine genaue Beschreibung der Typen und deren Verwendung findet man in [PrgGd96].
Im folgenden Beispiel wird die Verwendungen einiger Sektionen kurz erläutert:
; ; Installationsfile für den Beispieltreiber K ; ; die Versionssektion muss immer vorhanden sein [Version] Signature="$Windows NT$" ; INF File soll nur unter NT ausgefuehrt werden [DefaultInstall] ; Die Installationssektion DefaultInstall wird ; automatisch aufgerufen, wenn die INF Datei ; ueber den Explorer ausgefuehrt wird. CopyFiles=K_Files ; CopyFiles - Dateien sollen kopiert werden. ; Welche Dateien das sind, wird in der Sektion ; [K_Files] festgelegt. [DefaultInstall.Services] ; eine Untersektion von [DefaultInstall] ; Die Erweiterung ".Services" gibt an, dass ; ein Dienst/Treiber (de-)installiert werden ; soll AddService= K,,K_ServiceInst ; AddService - ein Dienst/Treiber wird ; installiert. Der Name des Dienstes ist ; hier "K". Die Parameter fuer den Dienst ; werden in der Sektion [K_ServiceInst] ; festgelegt. [K_Files] ; Eine CopyFile Sektion, auf die von der ; Sektion [DefaultInstall] verwiesen wird. ; Hier werden die zu kopierenden Files angegeben. k.sys [SourceDisksNames] ; Liste der verschiedenen Quellverzeichnisse 1=%K_Name%,, ; In diesem Beispiel wird kein Pfad angegeben, das ; bedeutet, dass im aktuellen Verzeichnis gesucht ; wird. [SourceDisksFiles] ; Zuordnung der Files zu den Quellverzeichnissen k.sys=1 ; Fuer diese Datei wird das Quellverzeichnis "1", ; das in der Sektion [SourceDisksNames] definiert ; wurde, verwendet. [DestinationDirs] ; In dieser Sektion erfolgt die ; Zuordnung der CopyFile Sektionen ; zu einem Zielverzeichnis K_Files=12 ; Die Dateien der Sektion [K_Files] sollen in ; das Verzeichnis 12 ( %system32%\drivers - ; wird vom System definiert) kopiert werden. [K_ServiceInst] ; eine Service Install Sektion, auf die von ; der Sektion [DefaultInstall.Services] ; verwiesen wurde. ; Hier werden die Informationen fuer die ; Installtion des Dienstes/Treibers angegeben. DisplayName=%K_Name% ServiceType=1 ; SERVICE_KERNEL_DRIVER StartType=1 ; SERVICE_SYSTEM_START ErrorControl=1 ; SERVICE_ERROR_NORMAL ServiceBinary=%12%\k.sys [STRINGS] ; Liste der verwendeten Strings K_Name="K Beispieltreiber" ; ; Installationsfile für den Beispieltreiber K ; ; die Versionssektion muss immer vorhanden sein [Version] Signature="$Windows NT$" ; INF File soll nur unter NT ausgefuehrt werden [DefaultInstall] ; Die Installationssektion DefaultInstall wird ; automatisch aufgerufen, wenn die INF Datei ; ueber den Explorer ausgefuehrt wird. CopyFiles=K_Files ; CopyFiles - Dateien sollen kopiert werden. ; Welche Dateien das sind, wird in der Sektion ; [K_Files] festgelegt. [DefaultInstall.Services] ; eine Untersektion von [DefaultInstall] ; Die Erweiterung ".Services" gibt an, dass ; ein Dienst/Treiber (de-)installiert werden ; soll AddService= K,,K_ServiceInst ; AddService - ein Dienst/Treiber wird ; installiert. Der Name des Dienstes ist ; hier "K". Die Parameter fuer den Dienst ; werden in der Sektion [K_ServiceInst] ; festgelegt. [K_Files] ; Eine CopyFile Sektion, auf die von der ; Sektion [DefaultInstall] verwiesen wird. ; Hier werden die zu kopierenden Files angegeben. k.sys [SourceDisksNames] ; Liste der verschiedenen Quellverzeichnisse 1=%K_Name%,, ; In diesem Beispiel wird kein Pfad angegeben, das ; bedeutet, dass im aktuellen Verzeichnis gesucht ; wird. [SourceDisksFiles] ; Zuordnung der Files zu den Quellverzeichnissen k.sys=1 ; Fuer diese Datei wird das Quellverzeichnis "1", ; das in der Sektion [SourceDisksNames] definiert ; wurde, verwendet. [DestinationDirs] ; In dieser Sektion erfolgt die ; Zuordnung der CopyFile Sektionen ; zu einem Zielverzeichnis K_Files=12 ; Die Dateien der Sektion [K_Files] sollen in ; das Verzeichnis 12 ( %system32%\drivers - ; wird vom System definiert) kopiert werden. [K_ServiceInst] ; eine Service Install Sektion, auf die von ; der Sektion [DefaultInstall.Services] ; verwiesen wurde. ; Hier werden die Informationen fuer die ; Installtion des Dienstes/Treibers angegeben. DisplayName=%K_Name% ServiceType=1 ; SERVICE_KERNEL_DRIVER StartType=1 ; SERVICE_SYSTEM_START ErrorControl=1 ; SERVICE_ERROR_NORMAL ServiceBinary=%12%\k.sys [STRINGS] ; Liste der verwendeten Strings K_Name="K Beispieltreiber"
Ein Treiber wird nicht wie eine "normale" Anwendung mehr oder weniger sequentiell abgearbeitet. Vielmehr werden in bestimmten Situationen einzelne Funktionen direkt vom I/O Manager aufgerufen. Allgemeine Ereignisse, auf die ein Treiber reagiert, sind z.B.
Nachfolgend werden die wichtigsten Treiberfunktionen kurz beschrieben.
4.2.1 Treiberinitialisierungs- und Aufräumfunktionen
Bevor ein Treiber I/O Anfragen bearbeiten kann, sind normalerweise eine Reihe von Initialisierungen notwendig. Gleiches gilt, wenn der Treiber beendet wird. In diesem Fall sollten belegte Ressourcen freigegeben und die Hardware in einen stabilen Zustand versetzt werden.
Wenn der Treiber gestartet wird, ruft der I/O Manager die Funktion auf. Dies kann zum Zeitpunkt des Systemstarts sein, aber auch später, wenn der Treiber manuell gestartet wird. Die Funktion hat u.a. folgende Aufgaben:
Diese Funktion wird vom I/O Manager aufgerufen, wenn ein Treiber manuell bzw. über die Systemsteuerung beendet wird. Beim Entladen des Treibers müssen die belegten Hard- und Software Ressourcen wieder freigegeben werden.
Beim Herunterfahren des Systems wird diese Routine aufgerufen. Da das System sowieso beendet wird, ist es in diesem Fall eher unwichtig, daß belegte Ressourcen freigegeben werden. Vielmehr sollte die Hardware in einen stabilen Zustand versetzt werden.
Soll ein Treiber im Falle eines Systemabsturzes aufgerufen werden, kann er diese Routine registrieren. Auch hier sollte die Hardware in einen stabilen Zustand versetzt werden. Zusätzlich können Statusinformationen ausgegeben werden, die bei der Analyse des Absturzes hilfreich sein können.
4.2.2 Dispatch Routinen
Bei einer I/O Anfrage ruft der I/O Manager parameterabhängig eine der Dispatch Routinen des Treibers auf. Prinzipiell wird jede (zulässige) I/O Anfrage von einer Dispatch Routine verarbeitet.
Alle Treiber, die mit Usermode Programmen kommunizieren wollen, müssen eine Dispatch Routine haben, die den Win32-Aufruf CreateFile verarbeitet. Wenn Aufräumarbeiten notwendig sein sollten, kann eine Routine deklariert werden, die den CloseHandle Aufruf behandelt.
Abhängig vom Gerätetyp können vom Treiber verschiedene Routinen zur Behandlung und Verarbeitung bzw. zur Steuerung des Gerätes angeboten werden. Diese Routinen werden bei den Win32 Funktionen ReadFile, WriteFile und DeviceIOControl vom I/O Manager aufgerufen.
4.2.3 Routinen für denDatentransfer
Um einen Datentransfer von bzw. zu einem Gerät zu initiieren, wird vom I/O Manager die Start I/O Routine aufgerufen.
Wird von einem Gerät ein Interrupt generiert, ruft der Interrupt Dispatcher die entsprechende Service Routine auf. Hier wird der Interrupt bestätigt und alle notwendigen Informationen für den späteren Gebrauch werden gespeichert. Danach wird mit Hilfe des I/O Managers eine DPC Routine in die Warteschlange eingefügt.
Nach Beendigung der ISR werden alle weiteren Arbeiten, wie z.B. Freigabe von Ressourcen, Fehlermeldungen oder Rückgabe von Ergebnissen an den I/O Manager, in der DPC Routine durchgeführt.
Die Anzahl der DPC Routinen ist vom Treiber abhängig. Für Treiber, die mit einer DPC Routine auskommen, bietet der I/O Manager einen vereinfachten Mechanismus, genannt DpcForIsr.
4.2.4 Synchronisations-/ Rückruffunktionen
Windows NT ist ein Multitaskingsystem. Ein Treiber muß deshalb mehrere I/O Anfragen gleichzeitig verarbeiten und verwalten können. So kann beispielsweise ein User-Programm eine Datei von einer Diskette lesen, während ein anderes Programm auf die gleiche Diskette schreiben will.
Der I/O Manager bietet einige Funktionen, um solche Situationen zu behandeln.
Controller unterstützen in der Regel mehrere physikalische Geräte. Deshalb ist es wichtig, daß immer nur eine Operation zur gleichen Zeit auf dem Gerät ausgeführt wird. Bevor also der Zugriff auf die Register des Controllers erfolgt, wird von der Start I/O Routine das exklusive Zugriffsrecht beantragt. Wenn der Zugriff gewährt wird, wird die ControllerControl Rückruffunktion aufgerufen, ansonsten wird solange gewartet, bis der Controller zur Verfügung steht.
Ein spezieller Controller ist der DMA-Controller. Auch er kann von mehreren Geräten beansprucht werden. Wenn ein Treiber den DMA benutzen möchte, beantragt er das exklusive Zugriffsrecht. Wird der Zugriff gewährt, kommt die AdapterControl Rückruffunktion zur Ausführung, andernfalls wird solange gewartet, bis der DMA-Controller freigegeben wird.
Es ist möglich, daß eine ISR aufgerufen wird, während sich eine DPC Funktion in der Ausführung befindet. Damit es nicht zu Konflikten kommt, wenn beide auf die gleichen Ressourcen zugreifen, werden die kritischen Teile der DPC Funktion in einer SynchCritSection Routine durchgeführt.
Innerhalb von SynchCritSection Routinen wird der IRQL auf den der ISR angehoben, so daß diese nicht zur Ausführung kommt. Bei Multiprozessor Rechnern funktioniert dieser Mechanismus nicht. Dort werden sogenannte Spinlocks benutzt, die einem Prozessor exklusive Zugriffsrechte auf Datenstrukturen gewähren.
4.2.5 Andere Treiberfunktionen
Für die zeitliche Kontrolle stehen dem Treiber I/O Timer oder CustumTimerDPC Routinen zur Verfügung.
Wenn Treiber in höheren Schichten Funktionen von tieferliegenden Treibern aufrufen, ist es oftmals notwendig, daß sie nach Beendigung der Funktion informiert werden. Dafür werden I/O Completion Routinen verwendet.
Für Anfragen, die unter Umständen sehr lange dauern können, ist es sinnvoll, eine Funktion zu deklarieren, die die Anfrage abbricht. In dieser sogenannten Cancel I/O Funktion müssen alle notwendigen Aufräumarbeiten durchgeführt werden.
4.3 Zugriffsmechanismen auf Speicherpuffer
Wenn ein Usermode Programm eine I/O Anfrage startet, ergibt sich das Problem, daß eventuell übergebene Puffer im ausgelagerten Bereich des virtuellen Speichers liegen können. Code, der mit einem IRQL größer oder gleich DISPATCH_LEVEL ausgeführt wird, darf aber nicht auf solche Speicherbereiche zugreifen. Ein anderes Problem ist, daß die physikalische Adresse des Puffers sich durchaus während einer Anfrage ändern kann, z.B. wenn Speicherseiten ausgelagert werden, während der Treiber die Anfrage bearbeitet.
Der I/O Manager bietet deshalb zwei verschiedene Möglichkeiten, um auf Puffer zuzugreifen. Welche Methode verwendet wird, legt man in der DriverEntry Routine fest.
Bei dieser Methode belegt der I/O Manager am Anfang jeder I/O Operation einen Puffer im nicht ausgelagertem Bereich des Speichers und übergibt die Adresse des Puffers dem Treiber. Sollen Daten auf ein Gerät geschrieben werden, kopiert der I/O Manager Daten aus dem Benutzerpuffer in den Systempuffer. Wenn Daten gelesen werden sollen, kopiert der I/O Manager, nachdem der Treiber die Operation abgeschlossen hat, Daten aus dem Systempuffer in den Benutzerpuffer.
Hier wird das Kopieren von Daten vermieden, indem der Treiber direkten Zugriff auf den Benutzerpuffer bekommt. Am Anfang jeder I/O Operation wird, um Pagefaults zu vermeiden, der gesamte Benutzerpuffer im Speicher gelockt. Danach bildet der I/O Manager eine Liste der physikalischen Speicherseiten, die der Benutzerpuffer belegt. Diese Liste wird dem Treiber übergeben. Nachdem die Operation abgeschlossen ist, werden die gelockten Seiten vom I/O Manager wieder freigegeben.