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