1 /*
2 * COPYRIGHT: See COPYING.ARM in the top level directory
3 * PROJECT: ReactOS UEFI Boot Library
4 * FILE: boot/environ/lib/mm/blkalloc.c
5 * PURPOSE: Boot Library Memory Manager Block Allocator
6 * PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include "bl.h"
12
13 /* DATA VARIABLES ************************************************************/
14
15 PVOID* MmBlockAllocatorTable;
16 ULONG MmBlockAllocatorTableEntries;
17 BOOLEAN MmBlockAllocatorInitialized;
18
19 typedef struct _BL_BLOCK_DESCRIPTOR
20 {
21 LIST_ENTRY ListHead;
22 ULONG Unknown;
23 BL_MEMORY_TYPE Type;
24 ULONG Attributes;
25 ULONG Unknown2;
26 ULONG Count;
27 ULONG Count2;
28 ULONG Size;
29 ULONG BlockId;
30 ULONG ReferenceCount;
31 } BL_BLOCK_DESCRIPTOR, *PBL_BLOCK_DESCRIPTOR;
32
33 typedef struct _BL_BLOCK_ENTRY
34 {
35 LIST_ENTRY ListEntry;
36 ULONG Todo;
37 } BL_BLOCK_ENTRY, *PBL_BLOCK_ENTRY;
38
39 /* FUNCTIONS *****************************************************************/
40
41 BOOLEAN
MmBapCompareBlockAllocatorTableEntry(_In_ PVOID Entry,_In_ PVOID Argument1,_In_ PVOID Argument2,_In_ PVOID Argument3,_In_ PVOID Argument4)42 MmBapCompareBlockAllocatorTableEntry (
43 _In_ PVOID Entry,
44 _In_ PVOID Argument1,
45 _In_ PVOID Argument2,
46 _In_ PVOID Argument3,
47 _In_ PVOID Argument4
48 )
49 {
50 PBL_BLOCK_DESCRIPTOR BlockInfo = (PBL_BLOCK_DESCRIPTOR)Entry;
51 ULONG BlockId = PtrToUlong(Argument1);
52
53 /* Check if the block ID matches */
54 return BlockInfo->BlockId == BlockId;
55 }
56
57 PBL_BLOCK_DESCRIPTOR
MmBapFindBlockInformation(ULONG BlockId)58 MmBapFindBlockInformation (
59 ULONG BlockId
60 )
61 {
62 ULONG EntryId;
63
64 /* Find the block that matches */
65 EntryId = BlockId;
66 return BlTblFindEntry(MmBlockAllocatorTable,
67 MmBlockAllocatorTableEntries,
68 &EntryId,
69 MmBapCompareBlockAllocatorTableEntry,
70 UlongToPtr(EntryId),
71 NULL,
72 NULL,
73 NULL);
74 }
75
76 NTSTATUS
MmBapFreeBlockAllocatorDescriptor(_In_ PBL_BLOCK_DESCRIPTOR BlockInfo,_In_ PBL_BLOCK_ENTRY BlockEntry)77 MmBapFreeBlockAllocatorDescriptor (
78 _In_ PBL_BLOCK_DESCRIPTOR BlockInfo,
79 _In_ PBL_BLOCK_ENTRY BlockEntry
80 )
81 {
82 /* @TODO FIXME: Later */
83 EfiPrintf(L"Block free not yet implemented\r\n");
84 return STATUS_NOT_IMPLEMENTED;
85 }
86
87 NTSTATUS
BlpMmDeleteBlockAllocator(_In_ ULONG BlockId)88 BlpMmDeleteBlockAllocator (
89 _In_ ULONG BlockId
90 )
91 {
92 NTSTATUS Status, LocalStatus;
93 PBL_BLOCK_DESCRIPTOR BlockInfo;
94 PLIST_ENTRY ListHead, NextEntry;
95 PBL_BLOCK_ENTRY BlockEntry;
96
97 /* Nothing to delete if we're not initialized */
98 if (!MmBlockAllocatorInitialized)
99 {
100 return STATUS_UNSUCCESSFUL;
101 }
102
103 /* Find the block descriptor */
104 BlockInfo = MmBapFindBlockInformation(BlockId);
105 if (BlockInfo)
106 {
107 /* Assume success for now */
108 Status = STATUS_SUCCESS;
109
110 /* Do we have at least one reference? */
111 if (BlockInfo->ReferenceCount)
112 {
113 /* Iterate over the allocated blocks */
114 ListHead = &BlockInfo->ListHead;
115 NextEntry = ListHead->Flink;
116 while (NextEntry != ListHead)
117 {
118 /* Free each one */
119 BlockEntry = CONTAINING_RECORD(NextEntry,
120 BL_BLOCK_ENTRY,
121 ListEntry);
122 LocalStatus = MmBapFreeBlockAllocatorDescriptor(BlockInfo,
123 BlockEntry);
124 if (!NT_SUCCESS(LocalStatus))
125 {
126 /* Remember status on failure only */
127 Status = LocalStatus;
128 }
129 }
130
131 /* Drop a reference */
132 BlockInfo->ReferenceCount--;
133 }
134 else
135 {
136 /* There aren't any references, so why are we being called? */
137 Status = STATUS_INVALID_PARAMETER;
138 }
139 }
140 else
141 {
142 /* No block exists with this ID */
143 Status = STATUS_UNSUCCESSFUL;
144 }
145
146 /* Return back */
147 return Status;
148 }
149
150 NTSTATUS
MmBapFreeBlockAllocatorTableEntry(_In_ PVOID Entry,_In_ ULONG Index)151 MmBapFreeBlockAllocatorTableEntry (
152 _In_ PVOID Entry,
153 _In_ ULONG Index
154 )
155 {
156 PBL_BLOCK_DESCRIPTOR BlockInfo = (PBL_BLOCK_DESCRIPTOR)Entry;
157 NTSTATUS Status, LocalStatus;
158
159 /* Assume success */
160 Status = STATUS_SUCCESS;
161
162 /* Check if there was at least one reference */
163 if (BlockInfo->ReferenceCount > 1)
164 {
165 /* Try to delete the allocator */
166 LocalStatus = BlpMmDeleteBlockAllocator(BlockInfo->BlockId);
167 if (!NT_SUCCESS(LocalStatus))
168 {
169 /* Remember status on failure only */
170 Status = LocalStatus;
171 }
172 }
173
174 /* Now destroy the allocator's descriptor */
175 LocalStatus = BlMmFreeHeap(BlockInfo);
176 if (!NT_SUCCESS(LocalStatus))
177 {
178 /* Remember status on failure only */
179 Status = LocalStatus;
180 }
181
182 /* Free the entry, and return failure, if any */
183 MmBlockAllocatorTable[Index] = NULL;
184 return Status;
185 }
186
187 NTSTATUS
MmBapPurgeBlockAllocatorTableEntry(_In_ PVOID Entry)188 MmBapPurgeBlockAllocatorTableEntry (
189 _In_ PVOID Entry
190 )
191 {
192 PBL_BLOCK_DESCRIPTOR BlockInfo = (PBL_BLOCK_DESCRIPTOR)Entry;
193 NTSTATUS Status;
194
195 /* Check if there's a reference on the block descriptor */
196 if (BlockInfo->ReferenceCount)
197 {
198 /* Don't allow purging */
199 Status = STATUS_UNSUCCESSFUL;
200 }
201 else
202 {
203 /* Free the entry */
204 Status = MmBapFreeBlockAllocatorTableEntry(BlockInfo,
205 BlockInfo->BlockId);
206 }
207
208 /* Return purge status */
209 return Status;
210 }
211
212 NTSTATUS
BlpMmCreateBlockAllocator(VOID)213 BlpMmCreateBlockAllocator (
214 VOID
215 )
216 {
217 PBL_BLOCK_DESCRIPTOR BlockInfo;
218 ULONG BlockId;
219 NTSTATUS Status;
220
221 /* If the block allocator isn't initialized, bail out */
222 BlockId = -1;
223 if (!MmBlockAllocatorInitialized)
224 {
225 goto Quickie;
226 }
227
228 /* Allocate a block descriptor and zero it out */
229 BlockInfo = BlMmAllocateHeap(sizeof(*BlockInfo));
230 if (!BlockInfo)
231 {
232 goto Quickie;
233 }
234 RtlZeroMemory(BlockInfo, sizeof(*BlockInfo));
235
236 /* Setup the block descriptor */
237 BlockInfo->Attributes = 0;
238 BlockInfo->Type = BlLoaderBlockMemory;
239 BlockInfo->Unknown = 1;
240 BlockInfo->Unknown2 = 1;
241 BlockInfo->Size = PAGE_SIZE;
242 BlockInfo->Count = 128;
243 BlockInfo->Count2 = 128;
244 InitializeListHead(&BlockInfo->ListHead);
245
246 /* Add it to the list of block descriptors */
247 Status = BlTblSetEntry(&MmBlockAllocatorTable,
248 &MmBlockAllocatorTableEntries,
249 BlockInfo,
250 &BlockId,
251 MmBapPurgeBlockAllocatorTableEntry);
252 if (NT_SUCCESS(Status))
253 {
254 /* Add the initial reference and store the block ID */
255 BlockInfo->ReferenceCount = 1;
256 BlockInfo->BlockId = BlockId;
257 }
258
259 Quickie:
260 /* On failure, free the block descriptor */
261 if (BlockId == -1)
262 {
263 BlMmFreeHeap(BlockInfo);
264 }
265
266 /* Return the block descriptor ID, or -1 on failure */
267 return BlockId;
268 }
269
270 NTSTATUS
MmBaInitialize(VOID)271 MmBaInitialize (
272 VOID
273 )
274 {
275 NTSTATUS Status;
276 ULONG Size;
277
278 /* Allocate 8 table entries */
279 MmBlockAllocatorTableEntries = 8;
280 Size = sizeof(BL_BLOCK_DESCRIPTOR) * MmBlockAllocatorTableEntries;
281 MmBlockAllocatorTable = BlMmAllocateHeap(Size);
282 if (MmBlockAllocatorTable)
283 {
284 /* Zero them out -- we're all done */
285 Status = STATUS_SUCCESS;
286 RtlZeroMemory(MmBlockAllocatorTable, Size);
287 MmBlockAllocatorInitialized = 1;
288 }
289 else
290 {
291 /* Bail out since we're out of memory */
292 Status = STATUS_NO_MEMORY;
293 MmBlockAllocatorInitialized = 0;
294 }
295
296 /* Return initialization status */
297 return Status;
298 }
299