xref: /reactos/ntoskrnl/io/iomgr/iomdl.c (revision 7e56b21a)
1*c2c66affSColin Finck /*
2*c2c66affSColin Finck  * PROJECT:         ReactOS Kernel
3*c2c66affSColin Finck  * LICENSE:         GPL - See COPYING in the top level directory
4*c2c66affSColin Finck  * FILE:            ntoskrnl/io/iomgr/iomdl.c
5*c2c66affSColin Finck  * PURPOSE:         I/O Wrappers for MDL Allocation and Deallocation
6*c2c66affSColin Finck  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
7*c2c66affSColin Finck  */
8*c2c66affSColin Finck 
9*c2c66affSColin Finck /* INCLUDES *****************************************************************/
10*c2c66affSColin Finck 
11*c2c66affSColin Finck #include <ntoskrnl.h>
12*c2c66affSColin Finck #define NDEBUG
13*c2c66affSColin Finck #include <debug.h>
14*c2c66affSColin Finck 
15*c2c66affSColin Finck /* FUNCTIONS *****************************************************************/
16*c2c66affSColin Finck 
17*c2c66affSColin Finck /*
18*c2c66affSColin Finck  * @implemented
19*c2c66affSColin Finck  */
20*c2c66affSColin Finck PMDL
21*c2c66affSColin Finck NTAPI
IoAllocateMdl(IN PVOID VirtualAddress,IN ULONG Length,IN BOOLEAN SecondaryBuffer,IN BOOLEAN ChargeQuota,IN PIRP Irp)22*c2c66affSColin Finck IoAllocateMdl(IN PVOID VirtualAddress,
23*c2c66affSColin Finck               IN ULONG Length,
24*c2c66affSColin Finck               IN BOOLEAN SecondaryBuffer,
25*c2c66affSColin Finck               IN BOOLEAN ChargeQuota,
26*c2c66affSColin Finck               IN PIRP Irp)
27*c2c66affSColin Finck {
28*c2c66affSColin Finck     PMDL Mdl = NULL, p;
29*c2c66affSColin Finck     ULONG Flags = 0;
30*c2c66affSColin Finck     ULONG Size;
31*c2c66affSColin Finck 
32*c2c66affSColin Finck     /* Make sure we got a valid length */
33*c2c66affSColin Finck     ASSERT(Length != 0);
34*c2c66affSColin Finck 
35*c2c66affSColin Finck     /* Fail if allocation is over 2GB */
36*c2c66affSColin Finck     if (Length & 0x80000000) return NULL;
37*c2c66affSColin Finck 
38*c2c66affSColin Finck     /* Calculate the number of pages for the allocation */
39*c2c66affSColin Finck     Size = ADDRESS_AND_SIZE_TO_SPAN_PAGES(VirtualAddress, Length);
40*c2c66affSColin Finck     if (Size > 23)
41*c2c66affSColin Finck     {
42*c2c66affSColin Finck         /* This is bigger then our fixed-size MDLs. Calculate real size */
43*c2c66affSColin Finck         Size *= sizeof(PFN_NUMBER);
44*c2c66affSColin Finck         Size += sizeof(MDL);
45*c2c66affSColin Finck         if (Size > MAXUSHORT) return NULL;
46*c2c66affSColin Finck     }
47*c2c66affSColin Finck     else
48*c2c66affSColin Finck     {
49*c2c66affSColin Finck         /* Use an internal fixed MDL size */
50*c2c66affSColin Finck         Size = (23 * sizeof(PFN_NUMBER)) + sizeof(MDL);
51*c2c66affSColin Finck         Flags |= MDL_ALLOCATED_FIXED_SIZE;
52*c2c66affSColin Finck 
53*c2c66affSColin Finck         /* Allocate one from the lookaside list */
54*c2c66affSColin Finck         Mdl = IopAllocateMdlFromLookaside(LookasideMdlList);
55*c2c66affSColin Finck     }
56*c2c66affSColin Finck 
57*c2c66affSColin Finck     /* Check if we don't have an mdl yet */
58*c2c66affSColin Finck     if (!Mdl)
59*c2c66affSColin Finck     {
60*c2c66affSColin Finck         /* Allocate one from pool */
61*c2c66affSColin Finck         Mdl = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_MDL);
62*c2c66affSColin Finck         if (!Mdl) return NULL;
63*c2c66affSColin Finck     }
64*c2c66affSColin Finck 
65*c2c66affSColin Finck     /* Initialize it */
66*c2c66affSColin Finck     MmInitializeMdl(Mdl, VirtualAddress, Length);
67*c2c66affSColin Finck     Mdl->MdlFlags |= Flags;
68*c2c66affSColin Finck 
69*c2c66affSColin Finck     /* Check if an IRP was given too */
70*c2c66affSColin Finck     if (Irp)
71*c2c66affSColin Finck     {
72*c2c66affSColin Finck         /* Check if it came with a secondary buffer */
73*c2c66affSColin Finck         if (SecondaryBuffer)
74*c2c66affSColin Finck         {
75*c2c66affSColin Finck             /* Insert the MDL at the end */
76*c2c66affSColin Finck             p = Irp->MdlAddress;
77*c2c66affSColin Finck             while (p->Next) p = p->Next;
78*c2c66affSColin Finck             p->Next = Mdl;
79*c2c66affSColin Finck         }
80*c2c66affSColin Finck         else
81*c2c66affSColin Finck         {
82*c2c66affSColin Finck             /* Otherwise, insert it directly */
83*c2c66affSColin Finck             Irp->MdlAddress = Mdl;
84*c2c66affSColin Finck         }
85*c2c66affSColin Finck     }
86*c2c66affSColin Finck 
87*c2c66affSColin Finck     /* Return the allocated mdl */
88*c2c66affSColin Finck     return Mdl;
89*c2c66affSColin Finck }
90*c2c66affSColin Finck 
91*c2c66affSColin Finck /*
92*c2c66affSColin Finck  * @implemented
93*c2c66affSColin Finck  */
94*c2c66affSColin Finck VOID
95*c2c66affSColin Finck NTAPI
IoBuildPartialMdl(IN PMDL SourceMdl,IN PMDL TargetMdl,IN PVOID VirtualAddress,IN ULONG Length)96*c2c66affSColin Finck IoBuildPartialMdl(IN PMDL SourceMdl,
97*c2c66affSColin Finck                   IN PMDL TargetMdl,
98*c2c66affSColin Finck                   IN PVOID VirtualAddress,
99*c2c66affSColin Finck                   IN ULONG Length)
100*c2c66affSColin Finck {
101*c2c66affSColin Finck     PPFN_NUMBER TargetPages = (PPFN_NUMBER)(TargetMdl + 1);
102*c2c66affSColin Finck     PPFN_NUMBER SourcePages = (PPFN_NUMBER)(SourceMdl + 1);
103*c2c66affSColin Finck     ULONG Offset;
104*c2c66affSColin Finck     ULONG FlagsMask = (MDL_IO_PAGE_READ |
105*c2c66affSColin Finck                        MDL_SOURCE_IS_NONPAGED_POOL |
106*c2c66affSColin Finck                        MDL_MAPPED_TO_SYSTEM_VA |
107*c2c66affSColin Finck                        MDL_IO_SPACE);
108*c2c66affSColin Finck 
109*c2c66affSColin Finck     /* Calculate the offset */
110*c2c66affSColin Finck     Offset = (ULONG)((ULONG_PTR)VirtualAddress -
111*c2c66affSColin Finck                      (ULONG_PTR)SourceMdl->StartVa) -
112*c2c66affSColin Finck                      SourceMdl->ByteOffset;
113*c2c66affSColin Finck 
114*c2c66affSColin Finck     /* Check if we don't have a length and calculate it */
115*c2c66affSColin Finck     if (!Length) Length = SourceMdl->ByteCount - Offset;
116*c2c66affSColin Finck 
117*c2c66affSColin Finck     /* Write the process, start VA and byte data */
118*c2c66affSColin Finck     TargetMdl->StartVa = (PVOID)PAGE_ROUND_DOWN(VirtualAddress);
119*c2c66affSColin Finck     TargetMdl->Process = SourceMdl->Process;
120*c2c66affSColin Finck     TargetMdl->ByteCount = Length;
121*c2c66affSColin Finck     TargetMdl->ByteOffset = BYTE_OFFSET(VirtualAddress);
122*c2c66affSColin Finck 
123*c2c66affSColin Finck     /* Recalculate the length in pages */
124*c2c66affSColin Finck     Length = ADDRESS_AND_SIZE_TO_SPAN_PAGES(VirtualAddress, Length);
125*c2c66affSColin Finck 
126*c2c66affSColin Finck     /* Set the MDL Flags */
127*c2c66affSColin Finck     TargetMdl->MdlFlags &= (MDL_ALLOCATED_FIXED_SIZE | MDL_ALLOCATED_MUST_SUCCEED);
128*c2c66affSColin Finck     TargetMdl->MdlFlags |= SourceMdl->MdlFlags & FlagsMask;
129*c2c66affSColin Finck     TargetMdl->MdlFlags |= MDL_PARTIAL;
130*c2c66affSColin Finck 
131*c2c66affSColin Finck     /* Set the mapped VA */
132*c2c66affSColin Finck     TargetMdl->MappedSystemVa = (PCHAR)SourceMdl->MappedSystemVa + Offset;
133*c2c66affSColin Finck 
134*c2c66affSColin Finck     /* Now do the copy */
135*c2c66affSColin Finck     Offset = (ULONG)(((ULONG_PTR)TargetMdl->StartVa -
136*c2c66affSColin Finck                       (ULONG_PTR)SourceMdl->StartVa) >> PAGE_SHIFT);
137*c2c66affSColin Finck     SourcePages += Offset;
138*c2c66affSColin Finck     RtlCopyMemory(TargetPages, SourcePages, Length * sizeof(PFN_NUMBER));
139*c2c66affSColin Finck }
140*c2c66affSColin Finck 
141*c2c66affSColin Finck /*
142*c2c66affSColin Finck  * @implemented
143*c2c66affSColin Finck  */
144*c2c66affSColin Finck VOID
145*c2c66affSColin Finck NTAPI
IoFreeMdl(PMDL Mdl)146*c2c66affSColin Finck IoFreeMdl(PMDL Mdl)
147*c2c66affSColin Finck {
148*c2c66affSColin Finck     /* Tell Mm to reuse the MDL */
149*c2c66affSColin Finck     MmPrepareMdlForReuse(Mdl);
150*c2c66affSColin Finck 
151*c2c66affSColin Finck     /* Check if this was a pool allocation */
152*c2c66affSColin Finck     if (!(Mdl->MdlFlags & MDL_ALLOCATED_FIXED_SIZE))
153*c2c66affSColin Finck     {
154*c2c66affSColin Finck         /* Free it from the pool */
155*c2c66affSColin Finck         ExFreePoolWithTag(Mdl, TAG_MDL);
156*c2c66affSColin Finck     }
157*c2c66affSColin Finck     else
158*c2c66affSColin Finck     {
159*c2c66affSColin Finck         /* Free it from the lookaside */
160*c2c66affSColin Finck         IopFreeMdlFromLookaside(Mdl, LookasideMdlList);
161*c2c66affSColin Finck     }
162*c2c66affSColin Finck }
163*c2c66affSColin Finck 
164*c2c66affSColin Finck /* EOF */
165