2 * COPYRIGHT: See COPYING.ARM in the top level directory
3 * PROJECT: ReactOS UEFI Boot Library
4 * FILE: boot/environ/lib/misc/util.c
5 * PURPOSE: Boot Library Utility Functions
6 * PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES ******************************************************************/
13 /* DATA VARIABLES ************************************************************/
19 PVOID UtlMcDisplayMessageRoutine
;
20 PVOID UtlMcUpdateMessageRoutine
;
22 PVOID UtlProgressRoutine
;
23 PVOID UtlProgressContext
;
24 PVOID UtlProgressInfoRoutine
;
25 ULONG UtlProgressGranularity
;
26 ULONG UtlCurrentPercentComplete
;
27 ULONG UtlNextUpdatePercentage
;
28 BOOLEAN UtlProgressNeedsInfoUpdate
;
29 PVOID UtlProgressInfo
;
31 /* FUNCTIONS *****************************************************************/
35 _In_ ULONG Percentage
,
36 _Out_opt_ PBOOLEAN Completed
39 if (UtlProgressRoutine
)
41 EfiPrintf(L
"Unimplemented\r\n");
58 UtlMcDisplayMessageRoutine
= 0;
59 UtlMcUpdateMessageRoutine
= 0;
61 UtlProgressRoutine
= 0;
62 UtlProgressContext
= 0;
63 UtlProgressInfoRoutine
= 0;
64 UtlProgressGranularity
= 0;
65 UtlCurrentPercentComplete
= 0;
66 UtlNextUpdatePercentage
= 0;
67 UtlProgressNeedsInfoUpdate
= 0;
70 return STATUS_SUCCESS
;
77 _Out_ PULONG EntryIndex
,
78 _In_ PBL_TBL_LOOKUP_ROUTINE Callback
,
89 /* Check for invalid parameters */
90 if (!(Table
) || !(EntryIndex
))
95 /* Loop each entry in the table */
96 for (Index
= 0; Index
< Count
; Index
++)
98 /* Check if this entry is filled out */
101 /* Call the comparison function */
102 Result
= Callback(Table
[Index
],
109 /* Entry fouund return it */
111 Entry
= Table
[Index
];
117 /* Return the entry that was (or wasn't) found */
123 _Inout_ PVOID
** Table
,
124 _Inout_ PULONG Count
,
126 _Out_ PULONG EntryIndex
,
127 _In_ PBL_TBL_SET_ROUTINE Callback
131 NTSTATUS Status
= STATUS_SUCCESS
;
135 /* Make sure all the parameters were specified */
136 if (!(Table
) || !(*Table
) || !(Count
) || !(Callback
))
138 return STATUS_INVALID_PARAMETER
;
141 /* Read the current table */
145 /* Iterate over it */
146 while (Index
< NewCount
)
148 /* Look for a free index */
149 if (!NewTable
[Index
])
154 /* No free index yet, keep going */
158 /* No free index was found, try to purge some entries */
160 while (Index
< NewCount
)
162 /* Call each purge callback, trying to make space */
163 Status
= Callback(NewTable
[Index
]);
164 if (NT_SUCCESS(Status
))
166 /* We should have this slot available now */
170 /* Keep trying to purge more */
174 /* Double the table */
175 NewTable
= BlMmAllocateHeap(2 * sizeof(PVOID
) * NewCount
);
178 return STATUS_NO_MEMORY
;
181 /* Clear the new table, and copy the old entries */
182 RtlZeroMemory(&NewTable
[NewCount
], sizeof(PVOID
) * NewCount
);
183 RtlCopyMemory(NewTable
, *Table
, sizeof(PVOID
) * NewCount
);
185 /* Free the old table */
186 BlMmFreeHeap(*Table
);
188 /* Return the new table and count */
189 *Count
= 2 * NewCount
;
193 /* Set the index and return */
194 NewTable
[Index
] = Entry
;
203 _In_ PBL_TBL_MAP_ROUTINE MapCallback
206 NTSTATUS Status
, LocalStatus
;
210 /* Bail out if there's no table */
213 return STATUS_INVALID_PARAMETER
;
216 /* Assume success and loop each index */
217 Status
= STATUS_SUCCESS
;
218 for (Index
= 0; Index
< Count
; Index
++)
220 /* See if an entry exists at this index */
221 Entry
= Table
[Index
];
224 /* Call the map routine for this entry */
225 LocalStatus
= MapCallback(Entry
, Index
);
226 if (!NT_SUCCESS(LocalStatus
))
228 /* Propagate failure only */
229 Status
= LocalStatus
;
234 /* Return status to caller */
239 PBL_HASH_TABLE
* HtTableArray
;
240 ULONG HtTableEntries
;
243 DefaultHashFunction (
244 _In_ PBL_HASH_ENTRY Entry
,
251 /* Check if the value is a pointer, or embedded inline */
252 Value
= (Entry
->Flags
& BL_HT_VALUE_IS_INLINE
) ? Entry
->Value
: (PUCHAR
)&Entry
->Value
;
254 /* Iterate over each byte, and sum it */
255 for (i
= 0, KeyHash
= 0; i
< Entry
->Size
; i
++)
257 KeyHash
+= Value
[i
++];
260 /* Modulo the number of buckets */
261 return KeyHash
% TableSize
;
266 _In_ PBL_HASH_ENTRY Entry1
,
267 _In_ PBL_HASH_ENTRY Entry2
273 /* Check if the flags or sizes are not matching */
274 Flags
= Entry1
->Flags
;
275 if ((Entry1
->Size
!= Entry2
->Size
) || (Flags
!= Entry2
->Flags
))
279 else if (Flags
& BL_HT_VALUE_IS_INLINE
)
281 /* Check if this is an in-line value, compare it */
282 ValueMatch
= Entry1
->Value
== Entry2
->Value
;
286 /* This is a pointer value, compare it */
287 ValueMatch
= (RtlCompareMemory(Entry1
->Value
, Entry2
->Value
, Entry1
->Size
) ==
291 /* Return if it matched */
300 /* Never purge this entry */
301 return STATUS_UNSUCCESSFUL
;
307 _In_ PBL_HASH_TABLE_HASH_FUNCTION HashFunction
,
308 _In_ PBL_HASH_TABLE_COMPARE_FUNCTION CompareFunction
,
313 PBL_HASH_TABLE HashTable
;
319 /* Can't create a table with no ID */
322 return STATUS_INVALID_PARAMETER
;
325 /* Check if we don't already have a hash table table */
328 /* Allocate it and zero it out */
330 HtTableArray
= BlMmAllocateHeap(HtTableSize
* sizeof(PVOID
));
333 Status
= STATUS_NO_MEMORY
;
336 RtlZeroMemory(HtTableArray
, HtTableSize
* sizeof(PVOID
));
340 /* Allocate the hash table */
341 HashTable
= BlMmAllocateHeap(sizeof(*HashTable
));
344 Status
= STATUS_NO_MEMORY
;
349 HashTable
->HashFunction
= HashFunction
? HashFunction
: DefaultHashFunction
;
350 HashTable
->CompareFunction
= CompareFunction
? CompareFunction
: HtpCompareKeys
;
351 HashTable
->Size
= Size
? Size
: 13;
353 /* Allocate the hash links, one for each bucket */
354 HashTable
->HashLinks
= BlMmAllocateHeap(sizeof(LIST_ENTRY
) * HashTable
->Size
);
355 if (!HashTable
->HashLinks
)
357 Status
= STATUS_NO_MEMORY
;
361 /* Initialize the hash links */
362 for (i
= 0; i
< HashTable
->Size
; i
++)
364 InitializeListHead(&HashTable
->HashLinks
[i
]);
367 /* Save us in the table of hash tables */
368 Status
= BlTblSetEntry((PVOID
**)&HtTableArray
,
373 if (NT_SUCCESS(Status
))
375 /* One more -- we're done */
381 /* Check if we just allocated the table array now */
382 if (!(HtTableEntries
) && (HtTableArray
))
385 BlMmFreeHeap(HtTableArray
);
390 /* Check if we allocated a hash table*/
394 if (HashTable
->HashLinks
)
397 BlMmFreeHeap(HashTable
->HashLinks
);
401 BlMmFreeHeap(HashTable
);
411 _In_ PBL_HASH_ENTRY Entry
,
412 _Out_opt_ PBL_HASH_VALUE
*Value
415 PBL_HASH_TABLE HashTable
;
418 PLIST_ENTRY HashLinkHead
, HashLink
;
419 PBL_HASH_NODE HashNode
;
421 /* Check if the table ID is invalid, or we have no entry, or it's malformed */
422 if ((HtTableSize
<= TableId
) ||
424 ((Entry
->Flags
& BL_HT_VALUE_IS_INLINE
) && (Entry
->Size
!= sizeof(ULONG
))))
427 Status
= STATUS_INVALID_PARAMETER
;
431 /* Otherwise, get the hash table for this index */
432 HashTable
= HtTableArray
[TableId
];
434 /* Get the hash bucket */
435 HashValue
= HashTable
->HashFunction(Entry
, HashTable
->Size
);
437 /* Start iterating each entry in the bucket, assuming failure */
438 Status
= STATUS_NOT_FOUND
;
439 HashLinkHead
= &HashTable
->HashLinks
[HashValue
];
440 HashLink
= HashLinkHead
->Flink
;
441 while (HashLink
!= HashLinkHead
)
443 /* Get a node in this bucket, and compare the value */
444 HashNode
= CONTAINING_RECORD(HashLink
, BL_HASH_NODE
, ListEntry
);
445 if (HashTable
->CompareFunction(&HashNode
->Entry
, Entry
))
447 /* Does the caller want the value? */
451 *Value
= &HashNode
->Value
;
454 /* Return success and stop scanning */
455 Status
= STATUS_SUCCESS
;
459 /* Try the next node */
460 HashLink
= HashLink
->Flink
;
464 /* Return back to the caller */
471 _In_ PBL_HASH_ENTRY Entry
,
476 PBL_HASH_NODE HashNode
;
478 PLIST_ENTRY HashLinkHead
;
479 PBL_HASH_TABLE HashTable
;
481 /* Check for invalid tablle ID, missing arguments, or malformed entry */
482 if ((HtTableSize
<= TableId
) ||
488 ((Entry
->Flags
& BL_HT_VALUE_IS_INLINE
) && (Entry
->Size
!= sizeof(ULONG
))))
491 Status
= STATUS_INVALID_PARAMETER
;
495 /* Get the hash table for this ID */
496 HashTable
= HtTableArray
[TableId
];
498 /* Allocate a hash node */
499 HashNode
= BlMmAllocateHeap(sizeof(*HashNode
));
502 Status
= STATUS_NO_MEMORY
;
506 /* Capture all the data*/
507 HashNode
->Entry
.Size
= Entry
->Size
;
508 HashNode
->Entry
.Flags
= Entry
->Flags
;
509 HashNode
->Entry
.Value
= Entry
->Value
;
510 HashNode
->Value
.DataSize
= DataSize
;
511 HashNode
->Value
.Data
= Data
;
513 /* Insert it into the bucket list and return success */
514 HashLinkHead
= &HashTable
->HashLinks
[HashTable
->HashFunction(Entry
, HashTable
->Size
)];
515 InsertTailList(HashLinkHead
, &HashNode
->ListEntry
);
516 Status
= STATUS_SUCCESS
;