StartIo Routines di driver Lowest-Level

Panggilan manajer I/O ke rutinitas pengiriman driver adalah tahap pertama dalam memenuhi permintaan I/O perangkat. Rutinitas StartIo adalah tahap kedua. Setiap driver perangkat dengan rutinitas StartIo kemungkinan akan memanggil IoStartPacket dari rutinitas DispatchRead dan DispatchWrite , dan biasanya untuk subset kode kontrol I/O yang didukungnya dalam rutinitas DispatchDeviceControl-nya . Rutinitas IoStartPacket menambahkan IRP ke antrean perangkat yang disediakan sistem perangkat atau, jika antrean kosong, segera memanggil rutinitas StartIo driver untuk memproses IRP.

Anda dapat berasumsi bahwa ketika rutinitas StartIo driver dipanggil, perangkat target tidak sibuk. Ini karena manajer I/O memanggil StartIo dalam dua keadaan; salah satu rutinitas pengiriman driver baru saja disebut IoStartPacket dan antrean perangkat kosong, atau rutinitas DpcForIsr driver menyelesaikan permintaan lain dan baru saja memanggil IoStartNextPacket untuk menghapus antrean IRP berikutnya.

Sebelum rutinitas StartIo dalam driver perangkat tingkat tertinggi dipanggil, rutinitas pengiriman driver itu harus memeriksa dan mengunci buffer pengguna, jika perlu, untuk mengatur alamat buffer yang dipetakan yang valid di IRP yang diantrekan ke rutinitas StartIo-nya . Jika driver perangkat tingkat tertinggi mengatur objek perangkatnya untuk I/O langsung (atau untuk I/O langsung atau tidak di-buffer), driver tidak dapat menunda penguncian buffer pengguna ke rutinitas StartIo-nya ; setiap rutinitas StartIo dipanggil dalam konteks utas arbitrer di IRQL = DISPATCH_LEVEL.

Catatan

Setiap memori buffer yang akan diakses oleh rutinitas StartIo driver harus dikunci atau dialokasikan dari memori penghuni, ruang sistem dan harus dapat diakses dalam konteks utas arbitrer.

Secara umum, rutinitas StartIo driver perangkat tingkat bawah apa pun bertanggung jawab untuk memanggil IoGetCurrentIrpStackLocation dengan IRP input dan kemudian melakukan pemrosesan khusus permintaan apa pun yang diperlukan untuk memulai operasi I/O pada perangkatnya. Pemrosesan khusus permintaan dapat mencakup hal-hal berikut:

  • Menyiapkan atau memperbarui informasi status apa pun tentang permintaan saat ini yang dikelola driver. Informasi status mungkin disimpan dalam ekstensi perangkat objek perangkat target atau di tempat lain di kumpulan yang tidak disebarkan yang dialokasikan oleh driver.

    Misalnya, jika driver perangkat mempertahankan Boolean InterruptExpected untuk operasi transfer saat ini, rutinitas StartIo-nya mungkin mengatur variabel ini ke TRUE. Jika driver mempertahankan penghitung waktu habis untuk operasi saat ini, rutinitas StartIo-nya mungkin mengatur nilai ini, atau rutinitas StartIo mungkin mengantre rutinitas CustomTimerDpc driver.

    Jika rutin StartIo berbagi akses ke informasi status atau sumber daya perangkat keras dengan rutinitas driver lainnya, informasi status atau sumber daya harus dilindungi oleh kunci putar. (Lihat Spin Locks.)

    Jika rutin StartIo berbagi akses ke informasi status atau sumber daya dengan rutinitas InterruptService driver, StartIo harus menggunakan KeSynchronizeExecution untuk memanggil rutinitas SynchCritSection yang mengakses informasi status atau sumber daya. (Lihat Menggunakan Bagian Penting.)

  • Menetapkan nomor urut ke IRP jika driver harus mencatat kesalahan I/O perangkat saat memproses IRP.

    Lihat Kesalahan Pengelogan untuk informasi selengkapnya.

  • Jika perlu, terjemahkan parameter di lokasi tumpukan I/O driver ke dalam nilai khusus perangkat.

    Misalnya, driver disk mungkin perlu menghitung sektor awal atau byte offset ke alamat disk fisik untuk operasi transfer, dan apakah panjang transfer yang diminta akan melewati batas sektor tertentu atau melebihi kapasitas transfer perangkat fisiknya.

  • Jika pengandar mengontrol perangkat media yang dapat dilepas, memeriksa perubahan media sebelum memprogram perangkat untuk I/O dan memberi tahu sistem file yang terlalu berlebihan jika media telah berubah.

    Untuk informasi selengkapnya, lihat Mendukung Media yang Dapat Dilepas.

  • Jika perangkat menggunakan DMA, memeriksa apakah Panjang yang diminta (jumlah byte yang akan ditransfer, ditemukan di lokasi tumpukan I/O driver IRP) harus dibagi menjadi operasi transfer parsial, seperti yang dijelaskan dalam Teknik Input/Output, dengan asumsi driver tingkat yang lebih tinggi yang dipasangkan erat tidak menginspirasi transfer besar untuk driver perangkat.

    Rutinitas StartIo dari driver perangkat tersebut juga dapat bertanggung jawab untuk memanggil KeFlushIoBuffers dan, jika driver menggunakan DMA berbasis paket, untuk memanggil AllocateAdapterChannel dengan rutinitas AdapterControl driver.

    Lihat Objek Adapter dan DMA, dan Mempertahankan Koherensi Cache, untuk detail tambahan.

  • Jika perangkat menggunakan PIO, pemetaan alamat virtual dasar buffer, dijelaskan dalam IRP di Irp-MdlAddress>, ke alamat ruang sistem dengan MmGetSystemAddressForMdlSafe.

    Untuk permintaan baca, rutinitas StartIo driver perangkat dapat bertanggung jawab untuk memanggil KeFlushIoBuffers sebelum operasi PIO dimulai. Lihat Mempertahankan Koherensi Cache untuk informasi selengkapnya.

  • Jika driver non-WDM menggunakan objek pengontrol, memanggil IoAllocateController untuk mendaftarkan rutinitas ControllerControl-nya .

  • Jika driver menangani IRP yang dapat dibatalkan, memeriksa apakah IRP input telah dibatalkan.

  • Jika IRP input dapat dibatalkan sebelum diproses hingga selesai, rutinitas StartIo harus memanggil IoSetCancelRoutine dengan IRP dan titik masuk dari rutinitas Batalkan driver. Rutinitas StartIo harus memperoleh kunci putar pembatalan untuk panggilannya ke IoSetCancelRoutine. Atau, driver dapat menggunakan IoSetStartIoAttributes untuk mengatur atribut NonCancelable untuk rutinitas StartIo ke TRUE. Ini mencegah sistem mencoba membatalkan IRP yang telah diteruskan ke StartIo melalui panggilan ke IoStartPacket.

Sebagai aturan umum, driver yang menggunakan I/O buffer memiliki rutinitas StartIo yang lebih sederhana daripada yang menggunakan I/O langsung. Driver yang menggunakan I/O buffer mentransfer data dalam jumlah kecil untuk setiap permintaan transfer, sementara yang menggunakan I/O langsung (baik DMA atau PIO) mentransfer data dalam jumlah besar ke atau dari buffer terkunci yang dapat menjangkau batas halaman fisik dalam memori sistem.

Driver tingkat yang lebih tinggi yang berlapis di atas driver perangkat fisik biasanya mengatur objek perangkat mereka agar sesuai dengan driver perangkat masing-masing. Namun, driver tingkat tertinggi, terutama driver sistem file, dapat mengatur objek perangkat untuk I/O langsung atau buffer.

Driver yang mengatur objek perangkat mereka untuk I/O buffer dapat mengandalkan manajer I/O untuk meneruskan buffer yang valid di semua IRP yang dikirimnya ke driver. Driver tingkat bawah yang menyiapkan objek perangkat untuk I/O langsung dapat mengandalkan driver tingkat tertinggi dalam rantainya untuk meneruskan buffer yang valid di semua RUN yang dikirim melalui driver perantara ke driver perangkat tingkat bawah yang mendasar.

Menggunakan I/O Buffered di StartIo Routines

Jika rutinitas DispatchRead, DispatchWrite, atau DispatchDeviceControl driver menentukan bahwa permintaan valid dan memanggil IoStartPacket, manajer I/O memanggil rutinitas StartIo driver untuk segera memproses IRP jika antrean perangkat kosong. Jika antrean tidak kosong, IoStartPacket mengantre IRP. Akhirnya, panggilan ke IoStartNextPacket dari rutinitas DpcForIsr atau CustomDpc driver menyebabkan manajer I/O menghapus antrean IRP dan memanggil rutinitas StartIo driver.

Rutinitas StartIo memanggil IoGetCurrentIrpStackLocation dan menentukan operasi mana yang harus dilakukan untuk memenuhi permintaan. Ini praproses IRP dengan cara apa pun yang diperlukan sebelum memprogram perangkat fisik untuk melakukan permintaan I/O.

Jika akses ke perangkat fisik (atau ekstensi perangkat) harus disinkronkan dengan rutinitas InterruptService , rutinitas StartIo harus memanggil rutinitas SynchCritSection untuk melakukan pemrograman perangkat yang diperlukan. Untuk informasi selengkapnya, lihat Menggunakan Bagian Penting.

Driver perangkat fisik yang menggunakan I/O buffer mentransfer data baik ke atau dari buffer ruang sistem, yang dialokasikan oleh manajer I/O, yang ditemukan driver di setiap IRP di Irp-AssociatedIrp.SystemBuffer>.

Menggunakan I/O Langsung di StartIo Routines

Jika rutinitas DispatchRead, DispatchWrite, atau DispatchDeviceControl driver menentukan bahwa permintaan valid dan memanggil IoStartPacket, manajer I/O memanggil rutinitas StartIo driver untuk segera memproses IRP jika antrean perangkat kosong. Jika antrean tidak kosong, IoStartPacket mengantre IRP. Akhirnya, panggilan ke IoStartNextPacket dari rutinitas DpcForIsr atau CustomDpc driver menyebabkan manajer I/O menghapus antrean IRP dan memanggil rutinitas StartIo driver.

Rutinitas StartIo memanggil IoGetCurrentIrpStackLocation dan menentukan operasi mana yang harus dilakukan untuk memenuhi permintaan. Ini praproses IRP dengan cara apa pun yang diperlukan, seperti membagi permintaan transfer DMA besar menjadi rentang transfer parsial dan menghemat status tentang Panjang permintaan transfer masuk yang harus dipisahkan. Kemudian memprogram perangkat fisik untuk melakukan permintaan I/O.

Jika akses ke perangkat fisik (atau ekstensi perangkat) harus disinkronkan dengan ISR driver, rutinitas StartIo harus menggunakan rutinitas SynchCritSection yang disediakan driver untuk melakukan pemrograman yang diperlukan. Untuk informasi selengkapnya, lihat Menggunakan Bagian Penting.

Setiap driver yang menggunakan I/O langsung membaca data ke dalam atau menulis data dari buffer terkunci, yang dijelaskan oleh daftar deskriptor memori (MDL), yang ditemukan driver di IRP di Irp-MdlAddress>. Driver seperti itu biasanya menggunakan I/O buffer untuk permintaan kontrol perangkat. Untuk informasi selengkapnya, lihat Menangani Permintaan Kontrol I/O di StartIo Routines.

Jenis MDL adalah jenis buram yang tidak diakses driver secara langsung. Sebagai gantinya, driver yang menggunakan PIO memetakan buffer ruang pengguna dengan memanggil MmGetSystemAddressForMdlSafe dengan Irp-MdlAddress> sebagai parameter. Driver yang menggunakan DMA juga meneruskan Irp-MdlAddress> untuk mendukung rutinitas selama operasi transfer mereka agar alamat buffer dipetakan ulang ke rentang logis untuk perangkat mereka.

Kecuali driver tingkat yang lebih tinggi yang digabungkan erat membagi permintaan transfer DMA besar untuk driver perangkat yang mendasar, rutinitas StartIo driver perangkat tingkat terendah harus membagi setiap permintaan transfer yang lebih besar dari yang dapat dikelola perangkatnya dalam satu operasi transfer. Driver yang menggunakan DMA sistem diperlukan untuk membagi permintaan transfer yang terlalu besar untuk pengontrol DMA sistem atau untuk ditangani perangkat mereka dalam satu operasi transfer.

Jika perangkat adalah perangkat DMA subordinat, drivernya harus menyinkronkan transfer melalui pengontrol DMA sistem dengan objek adaptor yang dialokasikan driver, mewakili saluran DMA, dan rutinitas AdapterControl yang disediakan driver. Driver perangkat DMA master bus juga harus menggunakan objek adaptor yang dialokasikan driver untuk menyinkronkan transfernya dan harus menyediakan rutinitas AdapterControl jika menggunakan dukungan DMA berbasis paket sistem, atau rutinitas AdapterListControl jika menggunakan dukungan sebar/kumpulkan sistem.

Tergantung pada desain driver, ini mungkin menyinkronkan operasi transfer dan kontrol perangkat pada perangkat fisik dengan objek pengontrol dan menyediakan rutinitas ControllerControl .

Lihat Objek Adapter dan Objek DMA dan Pengontrol untuk informasi selengkapnya.

Menangani Permintaan Kontrol I/O dalam Rutinitas StartIo

Secara umum, hanya subset permintaan kontrol I/O perangkat yang diteruskan dari rutinitas DispatchDeviceControl atau DispatchInternalDeviceControl driver untuk diproses lebih lanjut oleh rutinitas StartIo driver. Rutinitas StartIo driver hanya harus menangani permintaan kontrol perangkat yang valid yang memerlukan perubahan status perangkat atau mengembalikan informasi volatil tentang status perangkat saat ini.

Setiap driver baru harus mendukung set kode kontrol I/O publik yang sama dengan semua driver lain untuk jenis perangkat yang sama. Sistem mendefinisikan kode kontrol I/O khusus jenis perangkat publik untuk permintaan IRP_MJ_DEVICE_CONTROL sebagai permintaan buffer.

Akibatnya, driver perangkat fisik melakukan transfer data ke atau dari buffer ruang sistem yang ditemukan setiap driver di IRP di Irp-AssociatedIrp.SystemBuffer> untuk permintaan kontrol perangkat. Bahkan driver yang mengatur objek perangkat mereka untuk I/O langsung menggunakan I/O buffer untuk memenuhi permintaan kontrol perangkat dengan kode kontrol I/O publik.

Definisi setiap kode kontrol I/O menentukan apakah data yang ditransfer untuk permintaan tersebut di-buffer. Setiap kode kontrol I/O yang ditentukan secara privat untuk permintaan IRP_MJ_INTERNAL_DEVICE_CONTROL khusus driver antara driver yang dipasangkan dapat menentukan kode dengan metode yang di-buffer, metode langsung, atau metode keduanya. Sebagai aturan umum, setiap kode kontrol I/O yang ditentukan secara privat harus didefinisikan dengan metode tidak jika driver tingkat yang lebih tinggi yang digabungkan dengan erat harus mengalokasikan buffer untuk permintaan tersebut.

Memprogram Perangkat untuk Operasi I/O

Biasanya, rutinitas StartIo di driver perangkat tingkat terendah harus menyinkronkan akses ke memori atau perangkat apa pun yang dibagikannya dengan ISR driver dengan menggunakan KeSynchronizeExecution untuk memanggil rutinitas SynchCritSection yang disediakan driver. Rutinitas StartIo driver menggunakan rutinitas SynchCritSection untuk benar-benar memprogram perangkat fisik untuk I/O di DIRQL. Untuk informasi selengkapnya, lihat Menggunakan Bagian Penting.

Sebelum memanggil KeSynchronizeExecution, rutinitas StartIo harus melakukan pra-pemrosesan yang diperlukan untuk permintaan tersebut. Pra-pemrosesan mungkin termasuk menghitung rentang transfer parsial awal dan menyimpan informasi status apa pun tentang permintaan asli untuk rutinitas driver lainnya.

Jika driver perangkat menggunakan DMA, rutinitas StartIo-nya biasanya memanggil AllocateAdapterChannel dengan rutinitas AdapterControl yang disediakan driver. Dalam keadaan ini, rutinitas StartIo menunda tanggung jawab untuk memprogram perangkat fisik ke rutinitas AdapterControl . Pada gilirannya, dapat memanggil KeSynchronizeExecution untuk memiliki program rutin SynchCritSection yang disediakan driver perangkat untuk transfer DMA.