xref: /reactos/boot/environ/lib/mm/blkalloc.c (revision 3be40816)
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