Aracılığıyla paylaş


MDL'leri kullanma

Bitişik bir sanal bellek adresi aralığına yayılan bir G/Ç arabelleği, birden fazla fiziksel sayfaya dağıtılabilir ve bu sayfalar birbirine bitişik olmayabilir. İşletim sistemi, sanal bellek arabelleğinin fiziksel sayfa düzenini açıklamak için bellek tanımlayıcısı listesi (MDL) kullanır.

MDL, MDL yapısı ve G/Ç arabelleğinin bulunduğu fiziksel belleği açıklayan bir veri dizisinden oluşur. MDL'nin boyutu, MDL'nin tanımladığı G/Ç arabelleğinin özelliklerine göre değişir. Sistem yordamları, bir MDL'nin gerekli boyutunu hesaplamak ve MDL'yi ayırmak ve boşaltmak için kullanılabilir.

MDL yapısı yarı opaktır. Sürücünüz, bu yapının yalnızca Next ve MdlFlags üyelerine doğrudan erişmelidir. Bu iki üyeyi kullanan bir kod örneği için aşağıdaki Örnek bölümüne bakın.

MDL'nin kalan üyeleri opaktır. MDL'nin opak üyelerine doğrudan erişmeyin. Bunun yerine, işletim sisteminin yapı üzerinde temel işlemleri gerçekleştirmek için sağladığı aşağıdaki makroları kullanın:

mmGetMdlVirtualAddress, MDL tarafından açıklanan G/Ç arabelleğinin sanal bellek adresini döndürür.

MmGetMdlByteCount, G/Ç arabelleğinin bayt cinsinden boyutunu döndürür.

MmGetMdlByteOffset, I/O arabelleğinin başlangıcının fiziksel bir sayfa içindeki ofsetini döndürür.

IoAllocateMdl yordamıyla bir MDL ayırabilirsiniz. MDL'yi boşaltmak için IoFreeMdl yordamını kullanın. Alternatif olarak, sayfasız bir bellek bloğu ayırabilir ve ardından MmInitializeMdl rutinini çağırarak bu bellek bloğunu MDL olarak biçimlendirebilirsiniz.

IoAllocateMdl veya MmInitializeMdl, MDL yapısının hemen ardından gelen veri dizisini başlatmaz. Sürücü tarafından ayrılmış, sayfasız bellekte bulunan bir MDL için, G/Ç arabelleğinin bulunduğu fiziksel belleği açıklamak amacıyla bu diziyi başlatmak için MmBuildMdlForNonPagedPool kullanın.

Sayfalama yapılabilen bellek için, sanal ve fiziksel bellek arasındaki ilişki geçicidir, bu nedenle MDL yapısından sonraki veri dizisi sadece bazı durumlarda geçerlidir. Şunları çağırın: MmProbeAndLockPages, belleği sayfalanabilir olarak yerinde kilitlemek ve mevcut düzen için bu veri dizisini başlatmak amacıyla. Çağıran MmUnlockPages yordamını kullanana kadar bellek sayfalandırılmaz ve bu noktada veri dizisinin içeriği artık geçerli olmaz.

MmGetSystemAddressForMdlSafe yordamı, belirtilen MDL tarafından açıklanan fiziksel sayfaları, sistem adres alanıyla henüz eşlenmemişlerse sistem adres alanında bir sanal adresle eşler. Bu sanal adres, G/Ç gerçekleştirmek için sayfalara bakılması gerekebilecek sürücüler için kullanışlıdır, çünkü özgün sanal adres yalnızca özgün bağlamında kullanılabilen ve herhangi bir zamanda silinebilen bir kullanıcı adresi olabilir.

MmGetMdlVirtualAddress IoBuildPartialMdl yordamını kullanarak kısmi bir MDL oluşturduğunuzda kısmi MDL'nin özgün başlangıç adresini döndürdüğünü unutmayın. MDL başlangıçta bir kullanıcı modu isteğinin sonucu olarak oluşturulduysa, bu adres kullanıcı modu adresidir. Bu nedenle, adresin isteğin kaynaklandığı işlemin bağlamı dışında bir ilgisi yoktur.

Genellikle bir sürücü, kısmi MDL'yi eşlemek için MmGetSystemAddressForMdlSafe makroyu çağırarak bir sistem modu adresi oluşturur. Bu, sürücünün işlem bağlamından bağımsız olarak sayfalara güvenli bir şekilde erişmeye devam etmesini sağlar.

Bir sürücü ioAllocateMdl çağırdığında, IoAllocateMdlIrp parametresi olarak IRP'ye yönelik bir işaretçi belirterek yeni ayrılan MDL ile bir IRP'yi ilişkilendirebilir. IRP ile ilişkilendirilmiş bir veya daha fazla MDL olabilir. IRP ile ilişkilendirilmiş tek bir MDL varsa, IRP'nin MdlAddress üyesi bu MDL'ye işaret eder. IRP ile ilişkilendirilmiş birden çok MDL varsa MdlAddress, MDL zinciri olarak bilinen IRP ile ilişkilendirilmiş MDL'lerin bağlantılı listesinde ilk MDL'yi işaret eder. MDL'ler, Next üyeleri tarafından birbirine bağlanır. Zincirdeki son MDL'nin bir sonraki üyesi NULLolarak ayarlanır.

Sürücü ioAllocateMdl çağırdığında, SecondaryBuffer parametresi için FALSE belirtirse, IRP'nin MdlAddress üyesi yeni MDL'ye işaret etmek üzere ayarlanır. SecondaryBuffer TRUE ise, yordam yeni MDL'yi MDL zincirinin sonuna ekler.

IRP tamamlandığında sistem, IRP ile ilişkili tüm MDL'lerin kilidini açar ve serbesttir. Sistem, G/Ç tamamlama yordamını kuyruğa almadan önce MDL'lerin kilidini açar ve G/Ç tamamlama yordamı yürütüldükten sonra bunları serbest bırakır.

Sürücüler, zincirdeki bir sonraki MDL'ye erişmek için her MDL'nin sonraki üyesi kullanarak MDL zincirinden geçiş yapabilir. Sürücüler, MDL'leri zincire manuel olarak eklemek için sonraki üyelerini güncelleştirebilir.

MDL zincirleri genellikle tek bir G/Ç isteğiyle ilişkili arabellek dizisini yönetmek için kullanılır. (Örneğin, bir ağ sürücüsü bir ağ işlemindeki her IP paketi için bir arabellek kullanabilir.) Dizideki her arabellek, zincirde kendi MDL'sine sahiptir. Sürücü isteği tamamladığında, arabelleklerin tümünü tek bir büyük arabelleğe birleştirir. Sistem daha sonra istek için ayrılan tüm MDL'leri otomatik olarak temizler.

G/Ç yöneticisi sık sık G/Ç isteklerinin kaynağıdır. G/Ç yöneticisi bir G/Ç isteğini tamamladığında, G/Ç yöneticisi IRP'yi serbest bırakır ve IRP'ye bağlı tüm MDL'leri serbest bırakır. Bu MDL'lerin bazıları, cihaz yığınındaki G/Ç yöneticisinin altında bulunan sürücüler tarafından IRP'ye eklenmiş olabilir. Benzer şekilde, sürücünüz bir G/Ç isteğinin kaynağıysa, sürücünüz G/Ç isteği tamamlandığında IRP'yi ve IRP'ye bağlı tüm MDL'leri temizlemelidir.

Örnek

Aşağıdaki kod örneği, bir MDL zincirini IRP'den kurtaran sürücü tarafından uygulanan bir işlevdir:

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);
    }
} 

Zincirdeki bir MDL tarafından açıklanan fiziksel sayfalar kilitliyse, örnek işlev, MDL'yi boşaltmak için IoFreeMdl çağırmadan önce sayfaların kilidini açmak için MmUnlockPages yordamını çağırır. Ancak, örnek işlevin IoFreeMdlçağırmadan önce sayfaların eşlemesini açıkça çıkarmasına gerek yoktur. Bunun yerine, IoFreeMdl, MDL'yi serbest ettiğinde sayfaların eşlemesini otomatik olarak kaldırır.