Udostępnij przez


Procedury StartIo w sterownikach Lowest-Level

Wywołanie menedżera I/O do rutyny dyspozycji sterownika jest pierwszym etapem obsługi żądania operacji we/wy urządzenia. Procedura StartIo jest drugim etapem. Każdy sterownik urządzenia z procedurą StartIo prawdopodobnie wywoła IoStartPacket z procedur DispatchRead i DispatchWrite, a zwykle zrobi to dla podzbioru obsługiwanych kodów kontrolnych we/wy w swojej procedurze DispatchDeviceControl. Procedura IoStartPacket dodaje protokół IRP do kolejki urządzenia dostarczonej przez system lub, jeśli kolejka jest pusta, natychmiast wywołuje procedurę StartIo sterownika w celu przetworzenia protokołu IRP.

Można założyć, że po wywołaniu procedury StartIo sterownika urządzenie docelowe nie jest zajęte. Dzieje się tak, ponieważ menedżer we/wy wywołuje StartIo w dwóch okolicznościach; jedna z procedur wysyłania sterownika właśnie wywołała IoStartPacket, a kolejka urządzenia była pusta, lub procedura DpcForIsr sterownika kończy kolejne żądanie i właśnie wywołała IoStartNextPacket, aby zdjąć z kolejki następny IRP.

Przed wywołaniem procedury StartIo w sterowniku urządzenia najwyższego poziomu, procedura wysyłania tego sterownika powinna sondować i blokować bufor użytkownika, w razie potrzeby, aby skonfigurować prawidłowe zmapowane adresy bufora w IRP zakolejkowanym do jej procedury StartIo. Jeśli sterownik urządzenia najwyższego poziomu konfiguruje swoje obiekty urządzenia dla bezpośrednich operacji we/wy (lub nie buforowanych ani bezpośrednich operacji we/wy), sterownik nie może odroczyć blokowania bufora użytkownika dla procedury StartIo; każda procedura StartIo jest wywoływana w losowym kontekście wątku na poziomie IRQL = DISPATCH_LEVEL.

Uwaga / Notatka

Każda pamięć buforowa, do której ma uzyskać dostęp procedura StartIo sterownika, musi być zablokowana lub przydzielona z rezydentnej pamięci przestrzeni systemowej i być dostępna w dowolnym kontekście wątku.

Ogólnie rzecz biorąc, każda procedura StartIo sterownika urządzenia niższego poziomu jest odpowiedzialna za wywoływanie IoGetCurrentIrpStackLocation z wejściowym IRP, a następnie wykonywanie przetwarzania specyficznego dla żądania, co jest niezbędne do uruchomienia operacji I/O na urządzeniu. Przetwarzanie specyficzne dla żądania może obejmować następujące elementy:

  • Konfigurowanie lub aktualizowanie wszelkich informacji o stanie bieżącego żądania, które utrzymuje sterownik. Informacje o stanie mogą być przechowywane w rozszerzeniu obiektu urządzenia docelowego lub w innym miejscu w puli niestronicowanej przydzielonej przez sterownik.

    Jeśli na przykład sterownik urządzenia zachowuje wartość logiczną InterruptExpected dla bieżącej operacji transferu, jej procedura StartIo może ustawić tę zmienną na wartość TRUE. Jeśli sterownik utrzymuje licznik limitu czasu dla bieżącej operacji, jego procedura StartIo może skonfigurować tę wartość lub procedura StartIo może umieścić w kolejce procedurę CustomTimerDpc sterownika.

    Jeśli procedura StartIo udostępnia informacje o stanie lub zasoby sprzętowe z innymi rutynami sterownika, informacje o stanie lub zasoby muszą być chronione przez blokadę typu spin. (Zobacz Spin Locks).)

    Jeśli procedura StartIo udostępnia dostęp do informacji o stanie lub zasobów z procedurą InterruptService sterownika, StartIo musi użyć KeSynchronizeExecution do wywołania procedury SynchCritSection, która uzyskuje dostęp do informacji o stanie lub zasobie. (Zobacz Używanie sekcji krytycznych).

  • Przypisanie numeru sekwencji do IRP na wypadek, gdyby sterownik musiał zarejestrować błąd I/O urządzenia podczas przetwarzania IRP.

    Aby uzyskać więcej informacji, zobacz Błędy rejestrowania .

  • W razie potrzeby przetłumacz parametry w lokalizacji stosu wejścia/wyjścia sterownika na wartości specyficzne dla urządzenia.

    Na przykład sterownik dysku może wymagać obliczenia sektora początkowego lub przesunięcia bajtu do adresu fizycznego dysku dla operacji transferu oraz sprawdzenia, czy żądana długość transferu przekroczy określoną granicę sektora albo przekroczy pojemność transferu urządzenia fizycznego.

  • Jeśli sterownik kontroluje urządzenie nośnika wymiennego, należy sprawdzić zmiany nośnika przed skonfigurowaniem urządzenia do operacji we/wy i powiadomić jego nadrzędny system plików, jeśli nośnik uległ zmianie.

    Aby uzyskać więcej informacji, zobacz Obsługa nośnika wymiennego.

  • Jeśli urządzenie korzysta z DMA, należy sprawdzić, czy żądana długość (liczba bajtów do przeniesienia, znaleziona w lokalizacji stosu we/wy sterownika IRP) powinna zostać podzielona na operacje z podziałem na częściowe transfery, zgodnie z opisem w sekcji Techniki wejścia/wyjścia, przy założeniu, że ściśle powiązany sterownik wyższego poziomu wstępnie nie dzieli na części dużych transferów dla sterownika urządzenia.

    Procedura StartIo takiego sterownika urządzenia może być również odpowiedzialna za wywołanie KeFlushIoBuffers i, jeśli sterownik używa DMA bazującej na pakietach, za wywołanie AllocateAdapterChannel z procedurą AdapterControl sterownika.

    Aby uzyskać dodatkowe informacje, zobacz Adapter Objects and DMA (Obiekty adaptera i DMA) oraz Maintaining Cache Coherency (Obsługa współistnienia pamięci podręcznej).

  • Jeśli urządzenie używa PIO, mapuj podstawowy wirtualny adres buforu, opisanego w IRP na Irp-MdlAddress>, do adresu przestrzeni systemowej za pomocą MmGetSystemAddressForMdlSafe.

    W przypadku żądań odczytu procedura StartIo sterownika urządzenia może być odpowiedzialna za wywołanie protokołu KeFlushIoBuffers przed rozpoczęciem operacji PIO. Więcej informacji znajdziesz w sekcji Utrzymanie spójności pamięci podręcznej .

  • Jeśli sterownik inny niż WDM używa obiektu kontrolera, wywołując IoAllocateController , aby zarejestrować procedurę ControllerControl .

  • Jeśli sterownik obsługuje anulowalne IRP, sprawdź, czy wejściowy IRP został już anulowany.

  • Jeśli można anulować wejściowy IRP przed zakończeniem jego przetwarzania, procedura StartIo musi wywołać metodę IoSetCancelRoutine z użyciem IRP oraz punktu wejściowego procedury Cancel sterownika. Procedura StartIo musi uzyskać blokadę anulowania spin dla wywołania IoSetCancelRoutine. Alternatywnie sterownik może użyć atrybutów IoSetStartIoAttributes , aby ustawić atrybut NonCancelable dla procedury StartIo na wartość TRUE. Uniemożliwia to systemowi próbę anulowania protokołu IRP przekazanego do startio przez wywołanie IoStartPacket.

Ogólnie rzecz biorąc, sterownik używający buforowanego we/wy ma prostszą procedurę StartIo niż ta, która używa bezpośredniego we/wy. Sterowniki, które używają buforowanego IO, przesyłają małe ilości danych dla każdego żądania transferu, podczas gdy te, które używają bezpośredniego IO (zarówno DMA, jak i PIO), przesyłają duże ilości danych do lub z zablokowanych buforów, które mogą przekraczać fizyczne granice stron pamięci systemowej.

Sterowniki wyższego poziomu ułożone powyżej sterowników urządzeń fizycznych zwykle konfigurują swoje obiekty urządzeń w celu dopasowania ich do odpowiednich sterowników urządzeń. Jednak sterownik najwyższego poziomu, szczególnie sterownik systemu plików, może skonfigurować obiekty urządzenia bez wykorzystania ani bezpośredniego, ani buforowanego we/wy.

Sterowniki, które konfigurują swoje obiekty urządzeń dla buforowanego I/O, mogą polegać na menedżerze I/O do przekazywania prawidłowych buforów we wszystkich IRP, które wysyła do sterownika. Sterowniki niższego poziomu, które konfigurują obiekty urządzeń do bezpośredniego I/O, mogą polegać na sterowniku najwyższego poziomu w łańcuchu, aby przekazać prawidłowe bufory we wszystkich IRP wysłanych za pośrednictwem jakichkolwiek sterowników pośrednich do bazowego sterownika urządzenia na niższym poziomie.

Używanie buforowanego I/O w procedurach StartIo

Jeśli procedura DispatchRead, DispatchWrite lub DispatchDeviceControl sterownika określi, że żądanie jest prawidłowe i wywoła IoStartPacket, menedżer we/wy wywoła procedurę StartIo sterownika, aby przetworzyć IRP natychmiast, jeśli kolejka urządzenia jest pusta. Jeśli kolejka nie jest pusta, IoStartPacket kolejkuje IRP. W końcu wywołanie metody IoStartNextPacket z procedury DpcForIsr lub CustomDpc powoduje, że menedżer wejścia/wyjścia zdejmuje IRP z kolejki i wywołuje procedurę StartIo sterownika.

Procedury StartIo wywołuje metodę IoGetCurrentIrpStackLocation i określa, którą operację należy wykonać, aby spełnić żądanie. Wstępnie przetwarza protokół IRP w dowolny sposób, zanim zaprogramuje urządzenie fizyczne do wykonania żądania we/wy.

Jeśli dostęp do urządzenia fizycznego (lub rozszerzenia urządzenia) musi być zsynchronizowany z procedurą PrzerwanieUsługi , procedury StartIo muszą wywołać procedurę SynchCritSection w celu wykonania niezbędnego programowania urządzeń. Aby uzyskać więcej informacji, zobacz Używanie sekcji krytycznych.

Sterownik urządzenia fizycznego, który używa buforowanego I/O, transferuje dane do lub z bufora przestrzeni systemowej, przydzielonego przez menedżera I/O, który sterownik odnajduje w każdym IRP w Irp-AssociatedIrp.SystemBuffer>.

Używanie bezpośredniego WE/WY w procedurach StartIo

Jeśli procedura DispatchRead, DispatchWrite lub DispatchDeviceControl sterownika określi, że żądanie jest prawidłowe i wywoła IoStartPacket, menedżer we/wy wywoła procedurę StartIo sterownika, aby natychmiast przetworzyć żądanie IRP, jeśli kolejka urządzenia jest pusta. Jeśli kolejka nie jest pusta, IoStartPacket kolejkuje IRP. W końcu wywołanie metody IoStartNextPacket z procedury DpcForIsr lub CustomDpc powoduje, że menedżer wejścia/wyjścia zdejmuje IRP z kolejki i wywołuje procedurę StartIo sterownika.

Procedury StartIo wywołuje metodę IoGetCurrentIrpStackLocation i określa, którą operację należy wykonać, aby spełnić żądanie. Wstępnie przetwarza protokół IRP w dowolny sposób, na przykład podzielenie dużego żądania transferu DMA na zakresy częściowego transferu i zapisanie stanu długości przychodzącego żądania transferu, które należy podzielić. Następnie programuje urządzenie fizyczne do wykonania żądania we/wy.

Jeśli dostęp do urządzenia fizycznego (lub rozszerzenia urządzenia) musi być zsynchronizowany z isr sterownika, procedura StartIo musi używać procedury SynchCritSection dostarczonej przez sterownik, aby wykonać niezbędne programowanie. Aby uzyskać więcej informacji, zobacz Używanie sekcji krytycznych.

Każdy sterownik używający bezpośredniego we/wy odczytuje dane z lub zapisuje dane do bufora zablokowanego, opisanego przez listę deskryptorów pamięci (MDL), którą sterownik znajduje w IRP pod Irp-MdlAddress>. Taki sterownik często używa buforowanych operacji we/wy na potrzeby żądań sterowania urządzeniami. Aby uzyskać więcej informacji, zobacz Obsługa żądań kontroli we/wy w procedurach StartIo.

Typ MDL jest nieprzezroczystym typem, do którego sterowniki nie uzyskują bezpośredniego dostępu. Zamiast tego sterowniki używające funkcji PIO remapują bufory przestrzeni użytkownika, wywołując funkcję MmGetSystemAddressForMdlSafe z użyciem Irp-MdlAddress> jako parametru. Sterowniki korzystające z DMA przekazują również Irp-MdlAddress> do obsługi procedur podczas operacji transferu, aby adresy buforu zostały ponownie zamapowane na zakresy logiczne dla urządzeń.

Chyba że ściśle powiązany sterownik wyższego poziomu dzieli duże żądania transferu DMA dla bazowego sterownika urządzenia, procedura StartIo najniższego poziomu sterownika urządzenia musi podzielić każde żądanie transferu większe niż jego urządzenie może zarządzać w ramach jednej operacji transferu. Sterowniki korzystające z systemu DMA są wymagane do dzielenia żądań transferu, które są zbyt duże dla systemu kontrolera DMA lub dla ich urządzeń do obsługi w ramach jednej operacji transferu.

Jeśli urządzenie jest podrzędnym urządzeniem DMA, jego sterownik musi synchronizować transfery za pośrednictwem systemowego kontrolera DMA z obiektem adaptera przydzielonym przez sterownik, reprezentującym kanał DMA, oraz dostarczoną przez sterownik procedurą AdapterControl. Sterownik urządzenia DMA magistrali głównego dostępu musi również używać obiektu adaptera przydzielonego przez sterownik do synchronizowania transferów i musi podać funkcję AdapterControl, jeśli używa systemowej obsługi DMA opartej na pakietach, lub funkcję AdapterListControl, jeśli używa systemowej obsługi rozproszonego/zebranego dostępu.

W zależności od projektu sterownika może synchronizować operacje transferu i sterowania urządzeniami na urządzeniu fizycznym z obiektem kontrolera i dostarczać procedurę ControllerControl .

Aby uzyskać więcej informacji, zobacz Adapter Objects and DMA and Controller Objects (Obiekty adaptera i obiekty DMA i kontrolerów ).

Obsługa żądań kontroli we/wy w procedurach StartIo

Ogólnie rzecz biorąc, tylko podzbiór żądań sterowania urządzeniem we/wy jest przekazywany z procedury DispatchDeviceControl lub DispatchInternalDeviceControl w celu dalszego przetwarzania przez procedurę StartIo sterownika. Procedura StartIo sterownika musi obsługiwać tylko prawidłowe żądania kontroli urządzenia, które wymagają zmian stanu urządzenia lub zwracają niestabilne informacje o bieżącym stanie urządzenia.

Każdy nowy sterownik musi obsługiwać ten sam zestaw publicznych kodów kontroli we/wy co wszystkie inne sterowniki dla tego samego rodzaju urządzenia. System definiuje publiczne kody kontroli we/wy specyficzne dla typu urządzenia dla żądań IRP_MJ_DEVICE_CONTROL jako żądania buforowane.

W związku z tym fizyczne sterowniki urządzeń przesyłają dane do lub z bufora przestrzeni systemowej, który każdy sterownik znajduje w IRP pod Irp-AssociatedIrp.SystemBuffer> dla żądań dotyczących kontroli urządzeń. Nawet sterowniki, które konfigurują swoje obiekty urządzeń do bezpośredniego we/wy, używają buforowanego we/wy, aby spełnić żądania kontroli urządzeń za pomocą publicznych kodów I/O.

Definicja każdego kodu sterującego we/wy określa, czy dane przesyłane dla tego żądania są buforowane. Dowolne prywatnie zdefiniowane kody sterowania we/wy dla specyficznych dla sterownika żądań IRP_MJ_INTERNAL_DEVICE_CONTROL między sparowanymi sterownikami mogą definiować kod z buforowaną metodą, metodą bezpośrednią lub metodą ani jedną, ani drugą. Zasadniczo, każdy prywatnie zdefiniowany kod kontrolny we/wy nie powinien określać metody, jeśli ściśle powiązany sterownik wyższego poziomu musi przydzielić bufor dla tego żądania.

Programowanie urządzenia na potrzeby operacji we/wy

Zwykle procedura StartIo w sterowniku urządzenia najniższego poziomu musi synchronizować dostęp do dowolnej pamięci lub rejestrów urządzenia, które współdzieli z ISR sterownika, używając KeSynchronizeExecution do wywołania procedury SynchCritSection dostarczonej przez sterownik. Procedura StartIo sterownika używa procedury SynchCritSection, aby rzeczywiście konfigurować urządzenie fizyczne do operacji we/wy na poziomie DIRQL. Aby uzyskać więcej informacji, zobacz Używanie sekcji krytycznych.

Przed wywołaniem metody KeSynchronizeExecution procedury StartIo muszą wykonać wszelkie wstępne przetwarzanie niezbędne dla żądania. Wstępne przetwarzanie może obejmować obliczanie początkowego zakresu częściowego transferu i zapisywanie wszelkich informacji o stanie oryginalnego żądania dla innych procedur sterowników.

Jeśli sterownik urządzenia korzysta z funkcji DMA, jego procedura StartIo zwykle wywołuje metodę AllocateAdapterChannel z dostarczoną przez sterownik procedurą AdapterControl . W takich okolicznościach rutyna StartIo odrocza odpowiedzialność za programowanie urządzenia fizycznego na procedurę AdapterControl . To z kolei może wywołać KeSynchronizeExecution, aby procedura SynchCritSection dostarczona przez sterownik zaprogramowała urządzenie do transferu DMA.