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
;
33 /* FUNCTIONS *****************************************************************/
37 _Out_ PVOID
* TableAddress
,
41 ULONG i
, TableCount
, HeaderLength
;
45 PHYSICAL_ADDRESS PhysicalAddress
;
46 PDESCRIPTION_HEADER Header
;
50 /* Make sure there's an output parameter */
53 return STATUS_INVALID_PARAMETER
;
56 /* Get the currently known RSDT and XSDT */
57 Rsdt
= (PRSDT
)UtlRsdt
;
58 Xsdt
= (PXSDT
)UtlXsdt
;
60 /* Is there an RSDT? */
63 /* No -- is there an XSDT? */
66 /* No. Look up the RSDT */
67 Status
= EfipGetRsdt(&PhysicalAddress
);
68 if (!NT_SUCCESS(Status
))
70 EfiPrintf(L
"no rsdp found\r\n");
75 Status
= BlMmMapPhysicalAddressEx((PVOID
)&Header
,
79 if (!NT_SUCCESS(Status
))
84 /* Unmap the header */
85 BlMmUnmapVirtualAddressEx(Header
, sizeof(*Header
));
87 /* Map the whole table */
88 Status
= BlMmMapPhysicalAddressEx((PVOID
)&Header
,
92 if (!NT_SUCCESS(Status
))
97 /* Check if its an XSDT or an RSDT */
98 if (Header
->Signature
== XSDT_SIGNATURE
)
101 Xsdt
= (PXSDT
)Header
;
107 Rsdt
= (PRSDT
)Header
;
113 /* OK, so do we have an XSDT after all? */
116 /* Yes... how big is it? */
117 HeaderLength
= Xsdt
->Header
.Length
;
118 if (HeaderLength
>= sizeof(*Header
))
120 HeaderLength
= sizeof(*Header
);
123 /* Based on that, how many tables are there? */
124 TableCount
= (Xsdt
->Header
.Length
- HeaderLength
) / sizeof(PHYSICAL_ADDRESS
);
128 /* Nope, we have an RSDT. How big is it? */
129 HeaderLength
= Rsdt
->Header
.Length
;
130 if (HeaderLength
>= sizeof(*Header
))
132 HeaderLength
= sizeof(*Header
);
135 /* Based on that, how many tables are there? */
136 TableCount
= (Rsdt
->Header
.Length
- HeaderLength
) / sizeof(ULONG
);
139 /* Loop through the ACPI tables */
140 for (i
= 0; i
< TableCount
; i
++)
142 /* For an XSDT, read the 64-bit address directly */
145 PhysicalAddress
= Xsdt
->Tables
[i
];
149 /* For RSDT, cast it */
150 PhysicalAddress
.QuadPart
= Rsdt
->Tables
[i
];
154 Status
= BlMmMapPhysicalAddressEx((PVOID
)&Header
,
158 if (!NT_SUCCESS(Status
))
163 /* Is it the right one? */
164 if (Header
->Signature
== Signature
)
166 /* Unmap the header */
167 BlMmUnmapVirtualAddressEx(Header
, sizeof(*Header
));
169 /* Map the whole table */
170 return BlMmMapPhysicalAddressEx(TableAddress
,
177 /* Requested table does not exist */
178 return STATUS_NOT_FOUND
;
183 BlUtlUpdateProgress (
184 _In_ ULONG Percentage
,
185 _Out_opt_ PBOOLEAN Completed
188 if (UtlProgressRoutine
)
190 EfiPrintf(L
"Unimplemented\r\n");
207 UtlMcDisplayMessageRoutine
= 0;
208 UtlMcUpdateMessageRoutine
= 0;
210 UtlProgressRoutine
= 0;
211 UtlProgressContext
= 0;
212 UtlProgressInfoRoutine
= 0;
213 UtlProgressGranularity
= 0;
214 UtlCurrentPercentComplete
= 0;
215 UtlNextUpdatePercentage
= 0;
216 UtlProgressNeedsInfoUpdate
= 0;
219 return STATUS_SUCCESS
;
223 BmUpdateProgressInfo (
225 _In_ PWCHAR ProgressInfo
228 EfiPrintf(L
"Progress Info: %s\r\n", ProgressInfo
);
235 _Out_ PBOOLEAN Completed
238 EfiPrintf(L
"Progress: %d\r\n", Percent
);
246 BlUtlRegisterProgressRoutine (
250 /* One shouldn't already exist */
251 if (UtlProgressRoutine
)
253 return STATUS_UNSUCCESSFUL
;
256 /* Set the routine, and no context */
257 UtlProgressRoutine
= BmUpdateProgress
;
258 UtlProgressContext
= NULL
;
260 /* Progress increases by one */
261 UtlProgressGranularity
= 1;
263 /* Set progress to zero for now */
264 UtlCurrentPercentComplete
= 0;
265 UtlNextUpdatePercentage
= 0;
267 /* Set the info routine if there is one */
268 UtlProgressInfoRoutine
= BmUpdateProgressInfo
;
271 return STATUS_SUCCESS
;
278 _Out_ PULONG EntryIndex
,
279 _In_ PBL_TBL_LOOKUP_ROUTINE Callback
,
280 _In_ PVOID Argument1
,
281 _In_ PVOID Argument2
,
282 _In_ PVOID Argument3
,
290 /* Check for invalid parameters */
291 if (!(Table
) || !(EntryIndex
))
296 /* Loop each entry in the table */
297 for (Index
= 0; Index
< Count
; Index
++)
299 /* Check if this entry is filled out */
302 /* Call the comparison function */
303 Result
= Callback(Table
[Index
],
310 /* Entry found return it */
312 Entry
= Table
[Index
];
318 /* Return the entry that was (or wasn't) found */
324 _Inout_ PVOID
** Table
,
325 _Inout_ PULONG Count
,
327 _Out_ PULONG EntryIndex
,
328 _In_ PBL_TBL_SET_ROUTINE Callback
332 NTSTATUS Status
= STATUS_SUCCESS
;
336 /* Make sure all the parameters were specified */
337 if (!(Table
) || !(*Table
) || !(Count
) || !(Callback
))
339 return STATUS_INVALID_PARAMETER
;
342 /* Read the current table */
346 /* Iterate over it */
347 while (Index
< NewCount
)
349 /* Look for a free index */
350 if (!NewTable
[Index
])
355 /* No free index yet, keep going */
359 /* No free index was found, try to purge some entries */
361 while (Index
< NewCount
)
363 /* Call each purge callback, trying to make space */
364 Status
= Callback(NewTable
[Index
]);
365 if (NT_SUCCESS(Status
))
367 /* We should have this slot available now */
371 /* Keep trying to purge more */
375 /* Double the table */
376 NewTable
= BlMmAllocateHeap(2 * sizeof(PVOID
) * NewCount
);
379 return STATUS_NO_MEMORY
;
382 /* Clear the new table, and copy the old entries */
383 RtlZeroMemory(&NewTable
[NewCount
], sizeof(PVOID
) * NewCount
);
384 RtlCopyMemory(NewTable
, *Table
, sizeof(PVOID
) * NewCount
);
386 /* Free the old table */
387 BlMmFreeHeap(*Table
);
389 /* Return the new table and count */
390 *Count
= 2 * NewCount
;
394 /* Set the index and return */
395 NewTable
[Index
] = Entry
;
404 _In_ PBL_TBL_MAP_ROUTINE MapCallback
407 NTSTATUS Status
, LocalStatus
;
411 /* Bail out if there's no table */
414 return STATUS_INVALID_PARAMETER
;
417 /* Assume success and loop each index */
418 Status
= STATUS_SUCCESS
;
419 for (Index
= 0; Index
< Count
; Index
++)
421 /* See if an entry exists at this index */
422 Entry
= Table
[Index
];
425 /* Call the map routine for this entry */
426 LocalStatus
= MapCallback(Entry
, Index
);
427 if (!NT_SUCCESS(LocalStatus
))
429 /* Propagate failure only */
430 Status
= LocalStatus
;
435 /* Return status to caller */
440 PBL_HASH_TABLE
* HtTableArray
;
441 ULONG HtTableEntries
;
444 DefaultHashFunction (
445 _In_ PBL_HASH_ENTRY Entry
,
452 /* Check if the value is a pointer, or embedded inline */
453 Value
= (Entry
->Flags
& BL_HT_VALUE_IS_INLINE
) ? Entry
->Value
: (PUCHAR
)&Entry
->Value
;
455 /* Iterate over each byte, and sum it */
456 for (i
= 0, KeyHash
= 0; i
< Entry
->Size
; i
++)
458 KeyHash
+= Value
[i
++];
461 /* Modulo the number of buckets */
462 return KeyHash
% TableSize
;
467 _In_ PBL_HASH_ENTRY Entry1
,
468 _In_ PBL_HASH_ENTRY Entry2
474 /* Check if the flags or sizes are not matching */
475 Flags
= Entry1
->Flags
;
476 if ((Entry1
->Size
!= Entry2
->Size
) || (Flags
!= Entry2
->Flags
))
480 else if (Flags
& BL_HT_VALUE_IS_INLINE
)
482 /* Check if this is an in-line value, compare it */
483 ValueMatch
= Entry1
->Value
== Entry2
->Value
;
487 /* This is a pointer value, compare it */
488 ValueMatch
= (RtlCompareMemory(Entry1
->Value
, Entry2
->Value
, Entry1
->Size
) ==
492 /* Return if it matched */
501 /* Never purge this entry */
502 return STATUS_UNSUCCESSFUL
;
508 _In_ PBL_HASH_TABLE_HASH_FUNCTION HashFunction
,
509 _In_ PBL_HASH_TABLE_COMPARE_FUNCTION CompareFunction
,
514 PBL_HASH_TABLE HashTable
;
520 /* Can't create a table with no ID */
523 return STATUS_INVALID_PARAMETER
;
526 /* Check if we don't already have a hash table table */
529 /* Allocate it and zero it out */
531 HtTableArray
= BlMmAllocateHeap(HtTableSize
* sizeof(PVOID
));
534 Status
= STATUS_NO_MEMORY
;
537 RtlZeroMemory(HtTableArray
, HtTableSize
* sizeof(PVOID
));
541 /* Allocate the hash table */
542 HashTable
= BlMmAllocateHeap(sizeof(*HashTable
));
545 Status
= STATUS_NO_MEMORY
;
550 HashTable
->HashFunction
= HashFunction
? HashFunction
: DefaultHashFunction
;
551 HashTable
->CompareFunction
= CompareFunction
? CompareFunction
: HtpCompareKeys
;
552 HashTable
->Size
= Size
? Size
: 13;
554 /* Allocate the hash links, one for each bucket */
555 HashTable
->HashLinks
= BlMmAllocateHeap(sizeof(LIST_ENTRY
) * HashTable
->Size
);
556 if (!HashTable
->HashLinks
)
558 Status
= STATUS_NO_MEMORY
;
562 /* Initialize the hash links */
563 for (i
= 0; i
< HashTable
->Size
; i
++)
565 InitializeListHead(&HashTable
->HashLinks
[i
]);
568 /* Save us in the table of hash tables */
569 Status
= BlTblSetEntry((PVOID
**)&HtTableArray
,
574 if (NT_SUCCESS(Status
))
576 /* One more -- we're done */
582 /* Check if we just allocated the table array now */
583 if (!(HtTableEntries
) && (HtTableArray
))
586 BlMmFreeHeap(HtTableArray
);
591 /* Check if we allocated a hash table*/
595 if (HashTable
->HashLinks
)
598 BlMmFreeHeap(HashTable
->HashLinks
);
602 BlMmFreeHeap(HashTable
);
612 _In_ PBL_HASH_ENTRY Entry
,
613 _Out_opt_ PBL_HASH_VALUE
*Value
616 PBL_HASH_TABLE HashTable
;
619 PLIST_ENTRY HashLinkHead
, HashLink
;
620 PBL_HASH_NODE HashNode
;
622 /* Check if the table ID is invalid, or we have no entry, or it's malformed */
623 if ((HtTableSize
<= TableId
) ||
625 ((Entry
->Flags
& BL_HT_VALUE_IS_INLINE
) && (Entry
->Size
!= sizeof(ULONG
))))
628 Status
= STATUS_INVALID_PARAMETER
;
632 /* Otherwise, get the hash table for this index */
633 HashTable
= HtTableArray
[TableId
];
635 /* Get the hash bucket */
636 HashValue
= HashTable
->HashFunction(Entry
, HashTable
->Size
);
638 /* Start iterating each entry in the bucket, assuming failure */
639 Status
= STATUS_NOT_FOUND
;
640 HashLinkHead
= &HashTable
->HashLinks
[HashValue
];
641 HashLink
= HashLinkHead
->Flink
;
642 while (HashLink
!= HashLinkHead
)
644 /* Get a node in this bucket, and compare the value */
645 HashNode
= CONTAINING_RECORD(HashLink
, BL_HASH_NODE
, ListEntry
);
646 if (HashTable
->CompareFunction(&HashNode
->Entry
, Entry
))
648 /* Does the caller want the value? */
652 *Value
= &HashNode
->Value
;
655 /* Return success and stop scanning */
656 Status
= STATUS_SUCCESS
;
660 /* Try the next node */
661 HashLink
= HashLink
->Flink
;
665 /* Return back to the caller */
672 _In_ PBL_HASH_ENTRY Entry
,
677 PBL_HASH_NODE HashNode
;
679 PLIST_ENTRY HashLinkHead
;
680 PBL_HASH_TABLE HashTable
;
682 /* Check for invalid table ID, missing arguments, or malformed entry */
683 if ((HtTableSize
<= TableId
) ||
689 ((Entry
->Flags
& BL_HT_VALUE_IS_INLINE
) && (Entry
->Size
!= sizeof(ULONG
))))
692 Status
= STATUS_INVALID_PARAMETER
;
696 /* Get the hash table for this ID */
697 HashTable
= HtTableArray
[TableId
];
699 /* Allocate a hash node */
700 HashNode
= BlMmAllocateHeap(sizeof(*HashNode
));
703 Status
= STATUS_NO_MEMORY
;
707 /* Capture all the data*/
708 HashNode
->Entry
.Size
= Entry
->Size
;
709 HashNode
->Entry
.Flags
= Entry
->Flags
;
710 HashNode
->Entry
.Value
= Entry
->Value
;
711 HashNode
->Value
.DataSize
= DataSize
;
712 HashNode
->Value
.Data
= Data
;
714 /* Insert it into the bucket list and return success */
715 HashLinkHead
= &HashTable
->HashLinks
[HashTable
->HashFunction(Entry
, HashTable
->Size
)];
716 InsertTailList(HashLinkHead
, &HashNode
->ListEntry
);
717 Status
= STATUS_SUCCESS
;
725 _In_ ULONG PartialSum
,
733 if (Flags
& BL_UTL_CHECKSUM_UCHAR_BUFFER
)
735 EfiPrintf(L
"Not supported\r\n");
738 else if (Flags
& BL_UTL_CHECKSUM_USHORT_BUFFER
)
740 PartialSum
= (unsigned __int16
)PartialSum
;
743 for (i
= 0; i
< Length
; i
+= 2)
745 PartialSum
+= *(unsigned __int16
*)&Buffer
[i
];
746 if (Flags
& BL_UTL_CHECKSUM_COMPLEMENT
)
748 PartialSum
= (unsigned __int16
)((PartialSum
>> 16) + PartialSum
);
754 PartialSum
+= (unsigned __int8
)Buffer
[Length
];
755 if (Flags
& BL_UTL_CHECKSUM_COMPLEMENT
)
757 PartialSum
= (unsigned __int16
)((PartialSum
>> 16) + PartialSum
);
761 if (Flags
& BL_UTL_CHECKSUM_NEGATE
)
766 PartialSum
= (unsigned __int16
)PartialSum
;
774 if (Flags
& BL_UTL_CHECKSUM_NEGATE
)