- Move the code from my previous commit before signalling the user event
[reactos.git] / reactos / ntoskrnl / io / iomgr / iomdl.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/mdl.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_PTR)TargetMdl->StartVa - (ULONG_PTR)SourceMdl->StartVa) >>
136 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 */