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.
Buffer I/O yang mencakup rentang alamat memori virtual yang berdekatan dapat tersebar di beberapa halaman fisik, dan halaman ini dapat tidak berurutan. Sistem operasi menggunakan daftar deskriptor memori (MDL) untuk menjelaskan tata letak halaman fisik untuk buffer memori virtual.
MDL terdiri dari struktur MDL yang diikuti oleh array data yang menjelaskan memori fisik tempat buffer I/O berada. Ukuran MDL bervariasi sesuai dengan karakteristik buffer I/O yang dijelaskan MDL. Rutinitas sistem tersedia untuk menghitung ukuran MDL yang diperlukan dan untuk mengalokasikan dan membebaskan MDL.
Struktur MDL adalah setengah transparan. Driver Anda harus hanya mengakses langsung anggota Berikutnya dan MdlFlags dari struktur ini. Untuk contoh kode yang menggunakan kedua anggota ini, lihat bagian Contoh berikut.
Anggota MDL yang tersisa tidak jelas. Jangan mengakses langsung elemen opak dari MDL. Sebagai gantinya, gunakan makro berikut, yang disediakan sistem operasi untuk melakukan operasi dasar pada struktur:
MmGetMdlVirtualAddress mengembalikan alamat memori virtual buffer I/O yang dijelaskan oleh MDL.
MmGetMdlByteCount mengembalikan ukuran, dalam byte, dari buffer I/O.
MmGetMdlByteOffset mengembalikan offset dalam halaman fisik awal buffer I/O.
Anda dapat mengalokasikan MDL dengan rutinitas IoAllocateMdl . Untuk membebaskan MDL, gunakan rutinitas IoFreeMdl . Atau, Anda dapat mengalokasikan blok memori non-halaman dan kemudian memformat blok ini sebagai MDL dengan memanggil rutinitas MmInitializeMdl.
Baik IoAllocateMdl maupun MmInitializeMdl tidak menginisialisasi array data yang langsung mengikuti struktur MDL. Untuk MDL yang berada di blok memori nonpaged yang dialokasikan oleh driver, gunakan MmBuildMdlForNonPagedPool untuk menginisialisasi array ini guna mendeskripsikan memori fisik tempat buffer I/O berada.
Untuk memori yang dapat di-pageable, korespondensi antara memori virtual dan fisik bersifat sementara, sehingga array data yang mengikuti struktur MDL hanya valid dalam keadaan tertentu. Panggil MmProbeAndLockPages untuk mengunci memori yang dapat di-pageable ke tempatnya dan untuk menginisialisasi array data ini untuk tata letak saat ini. Memori tidak akan di-page out sampai pemanggil menggunakan rutinitas MmUnlockPages , di mana konten array data tidak lagi valid.
Rutinitas MmGetSystemAddressForMdlSafe memetakan halaman fisik yang dijelaskan oleh MDL yang ditentukan ke alamat virtual di ruang alamat sistem, jika belum dipetakan ke ruang alamat sistem. Alamat virtual ini berguna untuk driver yang mungkin harus melihat halaman untuk melakukan I/O, karena alamat virtual asli mungkin merupakan alamat pengguna yang hanya dapat digunakan dalam konteks aslinya dan dapat dihapus kapan saja.
Perhatikan bahwa ketika Anda membangun MDL parsial dengan menggunakan rutinitas IoBuildPartialMdl bahwa MmGetMdlVirtualAddress mengembalikan alamat awal asli untuk MDL parsial. Alamat ini adalah alamat mode pengguna jika MDL awalnya dibuat sebagai hasil dari permintaan mode pengguna. Dengan demikian, alamat tidak memiliki relevansi di luar konteks proses tempat permintaan berasal.
Biasanya, driver sebagai gantinya membuat alamat mode sistem dengan memanggil makro MmGetSystemAddressForMdlSafe untuk memetakan MDL parsial. Ini memastikan bahwa driver dapat terus mengakses halaman dengan aman terlepas dari konteks proses.
Ketika driver memanggil IoAllocateMdl, driver dapat mengaitkan IRP dengan MDL yang baru dialokasikan dengan menentukan pointer ke IRP sebagai parameter IrpIoAllocateMdl. IRP dapat memiliki satu atau beberapa MDL yang terkait dengannya. Jika IRP memiliki satu MDL yang terkait dengannya, anggota MdlAddress IRP menunjuk ke MDL tersebut. Jika IRP memiliki beberapa MDL yang terkait dengannya, MdlAddress menunjuk ke MDL pertama dalam daftar MDL tertaut yang terkait dengan IRP, yang dikenal sebagai rantai MDL. MDL dihubungkan oleh anggota Berikutnya mereka. Anggota Berikutnya dari MDL terakhir dalam rantai diatur ke NULL.
Jika, ketika driver memanggil IoAllocateMdl, driver menentukan FALSE untuk parameter SecondaryBuffer, anggota MdlAddress IRP disetel untuk mengarah ke MDL baru. Jika SecondaryBuffer adalah TRUE, rutin menyisipkan MDL baru di akhir rantai MDL.
Ketika IRP selesai, sistem mengunci dan membebaskan seluruh MDL yang terkait dengan IRP. Sistem membuka kunci MDL sebelum mengantrekan rutinitas penyelesaian I/O dan membebaskannya setelah rutinitas penyelesaian I/O dijalankan.
Para driver dapat melintasi rantai MDL dengan menggunakan anggota Next pada setiap MDL untuk mengakses MDL selanjutnya dalam rantai. Driver dapat memasukkan MDL secara manual ke dalam rantai dengan memperbarui anggota Berikutnya .
Rantai MDL biasanya digunakan untuk mengelola array buffer yang terkait dengan satu permintaan I/O. (Misalnya, driver jaringan dapat menggunakan satu buffer untuk setiap paket IP dalam operasi jaringan.) Setiap buffer dalam array memiliki MDL sendiri dalam rantai. Ketika driver menyelesaikan permintaan, driver menggabungkan buffer menjadi satu buffer besar. Sistem kemudian secara otomatis membersihkan semua MDL yang dialokasikan untuk permintaan tersebut.
Manajer I/O adalah sumber permintaan I/O yang sering. Ketika manajer I/O menyelesaikan permintaan I/O, manajer I/O membebaskan IRP dan melepas MDL apa pun yang terlampir pada IRP. Beberapa MDL ini mungkin telah dilampirkan ke IRP oleh driver yang terletak di bawah manajer I/O di tumpukan perangkat. Demikian pula, jika driver Anda adalah sumber permintaan I/O, driver Anda harus membersihkan IRP dan MDL apa pun yang dilampirkan ke IRP ketika permintaan I/O selesai.
Contoh
Contoh kode berikut adalah fungsi yang diimplementasikan driver yang membebaskan rantai MDL dari IRP:
VOID MyFreeMdl(PMDL Mdl)
{
PMDL currentMdl, nextMdl;
for (currentMdl = Mdl; currentMdl != NULL; currentMdl = nextMdl)
{
nextMdl = currentMdl->Next;
if (currentMdl->MdlFlags & MDL_PAGES_LOCKED)
{
MmUnlockPages(currentMdl);
}
IoFreeMdl(currentMdl);
}
}
Jika halaman fisik yang dijelaskan oleh MDL dalam rantai dikunci, fungsi contoh memanggil rutinitas MmUnlockPages untuk membuka kunci halaman sebelum memanggil IoFreeMdl untuk membebaskan MDL. Namun, fungsi tersebut tidak perlu secara eksplisit membatalkan pemetaan halaman sebelum memanggil IoFreeMdl. Sebaliknya, IoFreeMdl secara otomatis melepaskan peta halaman saat membebaskan MDL.