Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Semua pengembang driver harus mempertimbangkan tingkat permintaan interupsi (IRQL). IRQL adalah bilangan bulat antara 0 dan 31; PASSIVE_LEVEL, DISPATCH_LEVEL, dan APC_LEVEL biasanya disebut secara simbolis, dan yang lain dengan nilai numeriknya. Menaikkan dan menurunkan IRQL harus mengikuti disiplin penumpukan yang ketat. Fungsi harus bertujuan untuk kembali pada IRQL yang sama di mana fungsi tersebut dipanggil. Nilai IRQL tidak boleh berkurang dalam tumpukan. Dan fungsi tidak dapat menurunkan IRQL tanpa terlebih dahulu menaikkannya. Anotasi IRQL dimaksudkan untuk membantu menegakkan aturan tersebut.
Ketika kode driver memiliki anotasi IRQL, alat analisis kode dapat membuat inferensi yang lebih baik tentang rentang tingkat di mana fungsi harus berjalan dan dapat menemukan kesalahan dengan lebih akurat. Misalnya, Anda dapat menambahkan anotasi yang menentukan IRQL maksimum di mana fungsi dapat dipanggil; jika fungsi dipanggil pada IRQL yang lebih tinggi, alat analisis kode dapat mengidentifikasi inkonsistensi.
Fungsi driver harus diannotasi dengan informasi sebanyak mungkin tentang IRQL yang mungkin sesuai. Jika informasi tambahan tersedia, ini membantu alat analisis kode dalam pemeriksaan selanjutnya dari fungsi pemanggil dan fungsi yang dipanggil. Dalam beberapa kasus, menambahkan anotasi adalah cara yang baik untuk mengurangi positif palsu. Beberapa fungsi, seperti fungsi utilitas, dapat dipanggil di IRQL apa pun. Dalam hal ini, tidak memiliki anotasi IRQL adalah anotasi yang tepat.
Ketika menganotasi fungsi untuk IRQL, sangat penting untuk mempertimbangkan bagaimana fungsi mungkin berkembang, bukan hanya implementasinya saat ini. Misalnya, fungsi seperti yang diimplementasikan mungkin berfungsi dengan benar pada IRQL yang lebih tinggi daripada yang dimaksudkan perancang. Walaupun menggoda untuk menandai fungsi berdasarkan fungsionalitas aktual kode, desainer mungkin sudah menyadari kebutuhan masa mendatang, seperti perlunya menurunkan IRQL maksimum untuk beberapa peningkatan di masa depan atau persyaratan sistem yang tertunda. Anotasi harus berasal dari niat perancang fungsi, bukan dari implementasi aktual.
Anda dapat menggunakan anotasi dalam tabel berikut untuk menunjukkan IRQL yang benar untuk fungsi dan parameternya. Nilai IRQL didefinisikan dalam Wdm.h.
| Anotasi IRQL | Deskripsi |
|---|---|
| _IRQL_requires_max_(irql) | Irql adalah IRQL maksimum di mana fungsi dapat dipanggil. |
| _IRQL_requires_min_(irql) | Irql adalah IRQL minimum di mana fungsi dapat dipanggil. |
| _IRQL_requires_(irql) | Fungsi harus dimasukkan di IRQL yang ditentukan oleh irql. |
| _IRQL_raises_(irql) | Fungsi keluar pada irql yang ditentukan, tetapi hanya dapat dipanggil untuk menaikkan (tidak lebih rendah) IRQL saat ini. |
| _IRQL_saves_ | Parameter yang dianotasi menyimpan IRQL saat ini untuk dipulihkan nanti. |
| _IRQL_restores_ | Parameter anotasi berisi nilai IRQL dari IRQL_saves yang akan dipulihkan saat fungsi kembali. |
| _IRQL_saves_global_(jenis, param) | IRQL saat ini disimpan ke lokasi yang bersifat internal dalam alat analisis kode tempat IRQL tersebut akan dipulihkan. Anotasi ini digunakan untuk menandai fungsi. Lokasinya diidentifikasi berdasarkan jenis dan lebih diperinci oleh parameter. Misalnya, OldIrql bisa menjadi jenisnya, dan FastMutex bisa menjadi parameter yang memegang nilai IRQL lama tersebut. |
| _IRQL_restores_global_(jenis, param) | IRQL yang disimpan oleh fungsi yang diberi anotasi dengan IRQL_saves_global dipulihkan dari lokasi yang bersifat internal untuk alat Analisis Kode. |
| _IRQL_always_function_min_(nilai) | Nilai IRQL adalah nilai minimum ke mana fungsi dapat menurunkan IRQL. |
| _IRQL_always_function_max_(nilai) | Nilai IRQL adalah nilai maksimum di mana fungsi dapat menaikkan IRQL. |
| _IRQL_requires_same_ | Fungsi yang dianotasi harus masuk dan keluar di IRQL yang sama. Fungsi ini dapat mengubah IRQL, tetapi harus memulihkan IRQL ke nilai aslinya sebelum keluar. |
| _IRQL_menggunakan_batal_ | Parameter yang dianotasi adalah nilai IRQL yang harus dipulihkan oleh fungsi panggilan balik DRIVER_CANCEL. Dalam kebanyakan kasus, gunakan anotasi IRQL_is_cancel sebagai gantinya. |
Anotasi untuk fitur DRIVER_CANCEL
Ada perbedaan antara anotasi _IRQL_uses_cancel_ dan _IRQL_is_cancel_. Anotasi _IRQL_uses_cancel_ hanya menentukan bahwa parameter anotasi adalah nilai IRQL yang harus dipulihkan oleh fungsi panggilan balik DRIVER_CANCEL. Anotasi _IRQL_is_cancel_ adalah anotasi komposit yang terdiri dari _IRQL_uses_cancel_ ditambah beberapa anotasi lain yang memastikan perilaku yang benar dari fungsi utilitas panggilan balik DRIVER_CANCEL. Dengan sendirinya, anotasi _IRQL_uses_cancel_ hanya kadang-kadang berguna; misalnya, jika sisa kewajiban yang dijelaskan oleh _IRQL_is_cancel_ telah dipenuhi dengan cara lain.
| Anotasi IRQL | Deskripsi |
|---|---|
| _IRQL_is_cancel_ | Parameter yang dianotasi adalah IRQL yang diteruskan sebagai bagian dari panggilan ke fungsi panggilan balik DRIVER_CANCEL. Anotasi ini menunjukkan bahwa fungsi tersebut adalah utilitas yang dipanggil dari rutin pembatalan dan melengkapi persyaratan untuk fungsi DRIVER_CANCEL, termasuk pelepasan spin lock pembatalan. |
Bagaimana anotasi IRQL berinteraksi
Anotasi parameter IRQL berinteraksi satu sama lain lebih dari anotasi lain karena nilai IRQL diatur, diatur ulang, disimpan, dan dipulihkan oleh berbagai fungsi yang disebut.
Menentukan IRQL Maksimum dan Minimum
Anotasi _IRQL_requires_max_ dan _IRQL_requires_min_ menentukan bahwa fungsi tidak boleh dipanggil dari IRQL yang lebih tinggi atau lebih rendah dari nilai yang ditentukan. Misalnya, ketika PREfast melihat urutan panggilan fungsi yang tidak mengubah IRQL, jika menemukannya dengan nilai _IRQL_requires_max_ yang berada di bawah _IRQL_requires_min_ terdekat, ia melaporkan peringatan pada panggilan kedua yang ditemuinya. Kesalahan mungkin benar-benar terjadi pada panggilan pertama; pesan menunjukkan di mana setengah konflik lainnya terjadi.
Jika anotasi pada fungsi menyebutkan IRQL dan tidak secara eksplisit menerapkan _IRQL_requires_max_, alat Analisis Kode secara implisit menerapkan anotasi _IRQL_requires_max_(DISPATCH_LEVEL), yang biasanya benar dengan pengecualian langka. Menerapkan ini sebagai default secara implisit menghilangkan banyak keruwetan anotasi dan membuat pengecualian jauh lebih terlihat.
Anotasi _IRQL_requires_min_(PASSIVE_LEVEL) selalu tersirat karena IRQL tidak bisa lebih rendah; akibatnya, tidak ada aturan eksplisit yang sesuai tentang IRQL minimum. Sangat sedikit fungsi memiliki batas atas selain DISPATCH_LEVEL dan batas yang lebih rendah selain PASSIVE_LEVEL.
Beberapa fungsi dipanggil dalam konteks di mana fungsi yang disebut tidak dapat dengan aman menaikkan IRQL di atas beberapa maksimum atau, lebih sering, tidak dapat dengan aman menurunkannya di bawah beberapa minimum. Anotasi _IRQL_always_function_max_ dan _IRQL_always_function_min_ membantu PREfast menemukan kasus di mana ini terjadi secara tidak sengaja.
Misalnya, fungsi jenis DRIVER_STARTIO diannotasikan dengan _IRQL_always_function_min_(DISPATCH_LEVEL). Ini berarti bahwa selama eksekusi fungsi DRIVER_STARTIO, merupakan kesalahan jika menurunkan IRQL di bawah DISPATCH_LEVEL. Anotasi lain menunjukkan bahwa fungsi harus dimasukkan dan keluar pada DISPATCH_LEVEL.
Penetapan IRQL yang Eksplisit
Gunakan anotasi _IRQL_raises_ atau _IRQL_requires_ untuk membantu PREfast melaporkan inkonsistensi yang ditemukan dengan anotasi _IRQL_requires_max_ atau _IRQL_requires_min_, karena dengan demikian, PREfast mengetahui IRQL tersebut.
Anotasi _IRQL_raises_ menunjukkan bahwa fungsi kembali dengan IRQL diatur ke nilai baru. Saat Anda menggunakan anotasi _IRQL_raises_, anotasi tersebut juga secara efektif mengatur anotasi _drv_maxFunctionIRQL ke nilai IRQL yang sama. Namun, jika fungsi menaikkan IRQL lebih tinggi dari nilai akhir dan kemudian menurunkannya ke nilai akhir, Anda harus menambahkan anotasi _IRQL_always_function_max_ eksplisit setelah anotasi _IRQL_raises_ untuk memungkinkan nilai IRQL yang lebih tinggi.
Meningkatkan atau Menurunkan IRQL
Anotasi _IRQL_raises_ menunjukkan bahwa fungsi harus digunakan hanya untuk menaikkan IRQL dan tidak boleh digunakan untuk menurunkan IRQL, bahkan jika sintaks fungsi akan memungkinkannya. KeRaiseIrql adalah contoh fungsi yang tidak boleh digunakan untuk menurunkan IRQL.
Menyimpan dan Memulihkan IRQL
Gunakan anotasi _IRQL_saves_ dan _IRQL_restores_ untuk menunjukkan bahwa IRQL saat ini (apakah diketahui dengan tepat atau hanya perkiraan) disimpan ke atau dikembalikan dari parameter yang dianotasi.
Beberapa fungsi menyimpan dan memulihkan IRQL secara implisit. Misalnya, fungsi sistem ExAcquireFastMutex menyimpan IRQL di lokasi buram yang terkait dengan objek mutex cepat yang diidentifikasi parameter pertama; IRQL yang disimpan dipulihkan oleh fungsi ExReleaseFastMutex yang sesuai untuk objek mutex cepat tersebut. Untuk menunjukkan tindakan ini secara eksplisit, gunakan anotasi _IRQL_saves_global_ dan _IRQL_restores_global_. Parameter jenis dan param menunjukkan tempat nilai IRQL disimpan. Lokasi tempat nilai disimpan tidak harus ditentukan dengan tepat, selama anotasi yang menyimpan dan memulihkan nilai konsisten.
Mempertahankan IRQL yang Sama
Anda harus membuat anotasi pada fungsi apa pun yang driver buat untuk mengubah IRQL, menggunakan anotasi _IRQL_requires_same_ atau salah satu anotasi IRQL lainnya, untuk menunjukkan bahwa perubahan IRQL tersebut diharapkan. Dengan tidak adanya anotasi yang menunjukkan perubahan IRQL, alat analisis kode akan mengeluarkan peringatan untuk fungsi apa pun yang tidak keluar pada IRQL yang sama tempat fungsi dimasukkan. Jika perubahan IRQL dimaksudkan, tambahkan anotasi yang sesuai untuk menekan kesalahan. Jika perubahan IRQL tidak dimaksudkan, kode harus diperbaiki.
Menyimpan dan Memulihkan IRQL untuk Rutinitas Pembatalan I/O
Gunakan anotasi _IRQL_uses_cancel_ untuk menunjukkan bahwa parameter anotasi adalah nilai IRQL yang harus dipulihkan oleh fungsi panggilan balik DRIVER_CANCEL. Fungsi ini adalah utilitas yang dipanggil dari rutinitas pembatalan dan melengkapi persyaratan yang dibuat pada fungsi DRIVER_CANCEL, yaitu menghapuskan kewajiban dari pemanggil.
Misalnya, berikut ini adalah deklarasi untuk jenis fungsi panggilan balik DRIVER_CANCEL. Salah satu parameternya adalah IRQL yang harus dipulihkan oleh fungsi ini. Anotasi menunjukkan semua persyaratan fungsi pembatalan.
// Define driver cancel routine type. //
__drv_functionClass(DRIVER_CANCEL)
_Requires_lock_held_(_Global_cancel_spin_lock_)
_Releases_lock_(_Global_cancel_spin_lock_)
_IRQL_requires_min_(DISPATCH_LEVEL)
_IRQL_requires_(DISPATCH_LEVEL)
typedef
VOID
DRIVER_CANCEL (
_Inout_ struct _DEVICE_OBJECT *DeviceObject,
_Inout_ _IRQL_uses_cancel_ struct _IRP *Irp
);
typedef DRIVER_CANCEL *PDRIVER_CANCEL;