xref: /reactos/boot/environ/lib/misc/util.c (revision 9393fc32)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * COPYRIGHT:       See COPYING.ARM in the top level directory
3c2c66affSColin Finck  * PROJECT:         ReactOS UEFI Boot Library
4c2c66affSColin Finck  * FILE:            boot/environ/lib/misc/util.c
5c2c66affSColin Finck  * PURPOSE:         Boot Library Utility Functions
6c2c66affSColin Finck  * PROGRAMMER:      Alex Ionescu (alex.ionescu@reactos.org)
7c2c66affSColin Finck  */
8c2c66affSColin Finck 
9c2c66affSColin Finck /* INCLUDES ******************************************************************/
10c2c66affSColin Finck 
11c2c66affSColin Finck #include "bl.h"
12c2c66affSColin Finck 
13c2c66affSColin Finck /* DATA VARIABLES ************************************************************/
14c2c66affSColin Finck 
15c2c66affSColin Finck PRSDT UtlRsdt;
16c2c66affSColin Finck PXSDT UtlXsdt;
17c2c66affSColin Finck 
18c2c66affSColin Finck PVOID UtlMcContext;
19c2c66affSColin Finck PVOID UtlMcDisplayMessageRoutine;
20c2c66affSColin Finck PVOID UtlMcUpdateMessageRoutine;
21c2c66affSColin Finck 
22c2c66affSColin Finck PVOID UtlProgressRoutine;
23c2c66affSColin Finck PVOID UtlProgressContext;
24c2c66affSColin Finck PVOID UtlProgressInfoRoutine;
25c2c66affSColin Finck ULONG UtlProgressGranularity;
26c2c66affSColin Finck ULONG UtlCurrentPercentComplete;
27c2c66affSColin Finck ULONG UtlNextUpdatePercentage;
28c2c66affSColin Finck BOOLEAN UtlProgressNeedsInfoUpdate;
29c2c66affSColin Finck PVOID UtlProgressInfo;
30c2c66affSColin Finck 
31c2c66affSColin Finck /* FUNCTIONS *****************************************************************/
32c2c66affSColin Finck 
33c2c66affSColin Finck NTSTATUS
BlUtlGetAcpiTable(_Out_ PVOID * TableAddress,_In_ ULONG Signature)34c2c66affSColin Finck BlUtlGetAcpiTable (
35c2c66affSColin Finck     _Out_ PVOID* TableAddress,
36c2c66affSColin Finck     _In_ ULONG Signature
37c2c66affSColin Finck     )
38c2c66affSColin Finck {
39c2c66affSColin Finck     ULONG i, TableCount, HeaderLength;
40c2c66affSColin Finck     NTSTATUS Status;
41c2c66affSColin Finck     PRSDT Rsdt;
42c2c66affSColin Finck     PXSDT Xsdt;
43c2c66affSColin Finck     PHYSICAL_ADDRESS PhysicalAddress;
44c2c66affSColin Finck     PDESCRIPTION_HEADER Header;
45c2c66affSColin Finck 
46c2c66affSColin Finck     Header = 0;
47c2c66affSColin Finck 
48c2c66affSColin Finck     /* Make sure there's an output parameter */
49c2c66affSColin Finck     if (!TableAddress)
50c2c66affSColin Finck     {
51c2c66affSColin Finck         return STATUS_INVALID_PARAMETER;
52c2c66affSColin Finck     }
53c2c66affSColin Finck 
54c2c66affSColin Finck     /* Get the currently known RSDT and XSDT */
55c2c66affSColin Finck     Rsdt = (PRSDT)UtlRsdt;
56c2c66affSColin Finck     Xsdt = (PXSDT)UtlXsdt;
57c2c66affSColin Finck 
58c2c66affSColin Finck     /* Is there an RSDT? */
59c2c66affSColin Finck     if (!Rsdt)
60c2c66affSColin Finck     {
61c2c66affSColin Finck         /* No -- is there an XSDT? */
62c2c66affSColin Finck         if (!Xsdt)
63c2c66affSColin Finck         {
64c2c66affSColin Finck             /* No. Look up the RSDT */
65c2c66affSColin Finck             Status = EfipGetRsdt(&PhysicalAddress);
66c2c66affSColin Finck             if (!NT_SUCCESS(Status))
67c2c66affSColin Finck             {
68c2c66affSColin Finck                 EfiPrintf(L"no rsdp found\r\n");
69c2c66affSColin Finck                 return Status;
70c2c66affSColin Finck             }
71c2c66affSColin Finck 
72c2c66affSColin Finck             /* Map the header */
73c2c66affSColin Finck             Status = BlMmMapPhysicalAddressEx((PVOID)&Header,
74c2c66affSColin Finck                                               0,
75c2c66affSColin Finck                                               sizeof(*Header),
76c2c66affSColin Finck                                               PhysicalAddress);
77c2c66affSColin Finck             if (!NT_SUCCESS(Status))
78c2c66affSColin Finck             {
79c2c66affSColin Finck                 return Status;
80c2c66affSColin Finck             }
81c2c66affSColin Finck 
82c2c66affSColin Finck             /* Unmap the header */
83c2c66affSColin Finck             BlMmUnmapVirtualAddressEx(Header, sizeof(*Header));
84c2c66affSColin Finck 
85c2c66affSColin Finck             /* Map the whole table */
86c2c66affSColin Finck             Status = BlMmMapPhysicalAddressEx((PVOID)&Header,
87c2c66affSColin Finck                                               0,
88c2c66affSColin Finck                                               Header->Length,
89c2c66affSColin Finck                                               PhysicalAddress);
90c2c66affSColin Finck             if (!NT_SUCCESS(Status))
91c2c66affSColin Finck             {
92c2c66affSColin Finck                 return Status;
93c2c66affSColin Finck             }
94c2c66affSColin Finck 
95c2c66affSColin Finck             /* Check if its an XSDT or an RSDT */
96c2c66affSColin Finck             if (Header->Signature == XSDT_SIGNATURE)
97c2c66affSColin Finck             {
98c2c66affSColin Finck                 /* It's an XSDT */
99c2c66affSColin Finck                 Xsdt = (PXSDT)Header;
100c2c66affSColin Finck                 UtlXsdt = Xsdt;
101c2c66affSColin Finck             }
102c2c66affSColin Finck             else
103c2c66affSColin Finck             {
104c2c66affSColin Finck                 /* It's an RSDT */
105c2c66affSColin Finck                 Rsdt = (PRSDT)Header;
106c2c66affSColin Finck                 UtlRsdt = Rsdt;
107c2c66affSColin Finck             }
108c2c66affSColin Finck         }
109c2c66affSColin Finck     }
110c2c66affSColin Finck 
111c2c66affSColin Finck     /* OK, so do we have an XSDT after all? */
112c2c66affSColin Finck     if (Xsdt)
113c2c66affSColin Finck     {
114c2c66affSColin Finck         /* Yes... how big is it? */
115c2c66affSColin Finck         HeaderLength = Xsdt->Header.Length;
116c2c66affSColin Finck         if (HeaderLength >= sizeof(*Header))
117c2c66affSColin Finck         {
118c2c66affSColin Finck             HeaderLength = sizeof(*Header);
119c2c66affSColin Finck         }
120c2c66affSColin Finck 
121c2c66affSColin Finck         /* Based on that, how many tables are there? */
122c2c66affSColin Finck         TableCount = (Xsdt->Header.Length - HeaderLength) / sizeof(PHYSICAL_ADDRESS);
123c2c66affSColin Finck     }
124c2c66affSColin Finck     else
125c2c66affSColin Finck     {
126c2c66affSColin Finck         /* Nope, we have an RSDT. How big is it? */
127c2c66affSColin Finck         HeaderLength = Rsdt->Header.Length;
128c2c66affSColin Finck         if (HeaderLength >= sizeof(*Header))
129c2c66affSColin Finck         {
130c2c66affSColin Finck             HeaderLength = sizeof(*Header);
131c2c66affSColin Finck         }
132c2c66affSColin Finck 
133c2c66affSColin Finck         /* Based on that, how many tables are there? */
134c2c66affSColin Finck         TableCount = (Rsdt->Header.Length - HeaderLength) / sizeof(ULONG);
135c2c66affSColin Finck     }
136c2c66affSColin Finck 
137c2c66affSColin Finck     /* Loop through the ACPI tables */
138c2c66affSColin Finck     for (i = 0; i < TableCount; i++)
139c2c66affSColin Finck     {
140c2c66affSColin Finck         /* For an XSDT, read the 64-bit address directly */
141c2c66affSColin Finck         if (Xsdt)
142c2c66affSColin Finck         {
143c2c66affSColin Finck             PhysicalAddress = Xsdt->Tables[i];
144c2c66affSColin Finck         }
145c2c66affSColin Finck         else
146c2c66affSColin Finck         {
147c2c66affSColin Finck             /* For RSDT, cast it */
148c2c66affSColin Finck             PhysicalAddress.QuadPart = Rsdt->Tables[i];
149c2c66affSColin Finck         }
150c2c66affSColin Finck 
151c2c66affSColin Finck         /* Map the header */
152c2c66affSColin Finck         Status = BlMmMapPhysicalAddressEx((PVOID)&Header,
153c2c66affSColin Finck                                           0,
154c2c66affSColin Finck                                           sizeof(*Header),
155c2c66affSColin Finck                                           PhysicalAddress);
156c2c66affSColin Finck         if (!NT_SUCCESS(Status))
157c2c66affSColin Finck         {
158c2c66affSColin Finck             return Status;
159c2c66affSColin Finck         }
160c2c66affSColin Finck 
161c2c66affSColin Finck         /* Is it the right one? */
162c2c66affSColin Finck         if (Header->Signature == Signature)
163c2c66affSColin Finck         {
164c2c66affSColin Finck             /* Unmap the header */
165c2c66affSColin Finck             BlMmUnmapVirtualAddressEx(Header, sizeof(*Header));
166c2c66affSColin Finck 
167c2c66affSColin Finck             /* Map the whole table */
168c2c66affSColin Finck             return BlMmMapPhysicalAddressEx(TableAddress,
169c2c66affSColin Finck                                             0,
170c2c66affSColin Finck                                             Header->Length,
171c2c66affSColin Finck                                             PhysicalAddress);
172c2c66affSColin Finck         }
173c2c66affSColin Finck     }
174c2c66affSColin Finck 
175c2c66affSColin Finck     /* Requested table does not exist */
176c2c66affSColin Finck     return STATUS_NOT_FOUND;
177c2c66affSColin Finck }
178c2c66affSColin Finck 
179c2c66affSColin Finck 
180c2c66affSColin Finck VOID
BlUtlUpdateProgress(_In_ ULONG Percentage,_Out_opt_ PBOOLEAN Completed)181c2c66affSColin Finck BlUtlUpdateProgress (
182c2c66affSColin Finck     _In_ ULONG Percentage,
183c2c66affSColin Finck     _Out_opt_ PBOOLEAN Completed
184c2c66affSColin Finck     )
185c2c66affSColin Finck {
186c2c66affSColin Finck     if (UtlProgressRoutine)
187c2c66affSColin Finck     {
188c2c66affSColin Finck         EfiPrintf(L"Unimplemented\r\n");
189c2c66affSColin Finck     }
190c2c66affSColin Finck     else if (*Completed)
191c2c66affSColin Finck     {
192c2c66affSColin Finck         *Completed = TRUE;
193c2c66affSColin Finck     }
194c2c66affSColin Finck }
195c2c66affSColin Finck 
196c2c66affSColin Finck NTSTATUS
BlUtlInitialize(VOID)197c2c66affSColin Finck BlUtlInitialize (
198c2c66affSColin Finck     VOID
199c2c66affSColin Finck     )
200c2c66affSColin Finck {
201c2c66affSColin Finck     UtlRsdt = 0;
202c2c66affSColin Finck     UtlXsdt = 0;
203c2c66affSColin Finck 
204c2c66affSColin Finck     UtlMcContext = 0;
205c2c66affSColin Finck     UtlMcDisplayMessageRoutine = 0;
206c2c66affSColin Finck     UtlMcUpdateMessageRoutine = 0;
207c2c66affSColin Finck 
208c2c66affSColin Finck     UtlProgressRoutine = 0;
209c2c66affSColin Finck     UtlProgressContext = 0;
210c2c66affSColin Finck     UtlProgressInfoRoutine = 0;
211c2c66affSColin Finck     UtlProgressGranularity = 0;
212c2c66affSColin Finck     UtlCurrentPercentComplete = 0;
213c2c66affSColin Finck     UtlNextUpdatePercentage = 0;
214c2c66affSColin Finck     UtlProgressNeedsInfoUpdate = 0;
215c2c66affSColin Finck     UtlProgressInfo = 0;
216c2c66affSColin Finck 
217c2c66affSColin Finck     return STATUS_SUCCESS;
218c2c66affSColin Finck }
219c2c66affSColin Finck 
220c2c66affSColin Finck VOID
BmUpdateProgressInfo(_In_ PVOID Unknown,_In_ PWCHAR ProgressInfo)221c2c66affSColin Finck BmUpdateProgressInfo (
222c2c66affSColin Finck     _In_ PVOID Unknown,
223c2c66affSColin Finck     _In_ PWCHAR ProgressInfo
224c2c66affSColin Finck     )
225c2c66affSColin Finck {
226c2c66affSColin Finck     EfiPrintf(L"Progress Info: %s\r\n", ProgressInfo);
227c2c66affSColin Finck }
228c2c66affSColin Finck 
229c2c66affSColin Finck VOID
BmUpdateProgress(_In_ PVOID Unknown,_In_ ULONG Percent,_Out_ PBOOLEAN Completed)230c2c66affSColin Finck BmUpdateProgress (
231c2c66affSColin Finck     _In_ PVOID Unknown,
232c2c66affSColin Finck     _In_ ULONG Percent,
233c2c66affSColin Finck     _Out_ PBOOLEAN Completed
234c2c66affSColin Finck     )
235c2c66affSColin Finck {
236c2c66affSColin Finck     EfiPrintf(L"Progress: %d\r\n", Percent);
237c2c66affSColin Finck     if (Completed)
238c2c66affSColin Finck     {
239c2c66affSColin Finck         *Completed = TRUE;
240c2c66affSColin Finck     }
241c2c66affSColin Finck }
242c2c66affSColin Finck 
243c2c66affSColin Finck NTSTATUS
BlUtlRegisterProgressRoutine(VOID)244c2c66affSColin Finck BlUtlRegisterProgressRoutine (
245c2c66affSColin Finck     VOID
246c2c66affSColin Finck     )
247c2c66affSColin Finck {
248c2c66affSColin Finck     /* One shouldn't already exist */
249c2c66affSColin Finck     if (UtlProgressRoutine)
250c2c66affSColin Finck     {
251c2c66affSColin Finck         return STATUS_UNSUCCESSFUL;
252c2c66affSColin Finck     }
253c2c66affSColin Finck 
254c2c66affSColin Finck     /* Set the routine, and no context */
255c2c66affSColin Finck     UtlProgressRoutine = BmUpdateProgress;
256c2c66affSColin Finck     UtlProgressContext = NULL;
257c2c66affSColin Finck 
258c2c66affSColin Finck     /* Progress increases by one */
259c2c66affSColin Finck     UtlProgressGranularity = 1;
260c2c66affSColin Finck 
261c2c66affSColin Finck     /* Set progress to zero for now */
262c2c66affSColin Finck     UtlCurrentPercentComplete = 0;
263c2c66affSColin Finck     UtlNextUpdatePercentage = 0;
264c2c66affSColin Finck 
265c2c66affSColin Finck     /* Set the info routine if there is one */
266c2c66affSColin Finck     UtlProgressInfoRoutine = BmUpdateProgressInfo;
267c2c66affSColin Finck 
268c2c66affSColin Finck     /* All good */
269c2c66affSColin Finck     return STATUS_SUCCESS;
270c2c66affSColin Finck }
271c2c66affSColin Finck 
272c2c66affSColin Finck PVOID
BlTblFindEntry(_In_ PVOID * Table,_In_ ULONG Count,_Out_ PULONG EntryIndex,_In_ PBL_TBL_LOOKUP_ROUTINE Callback,_In_ PVOID Argument1,_In_ PVOID Argument2,_In_ PVOID Argument3,_In_ PVOID Argument4)273c2c66affSColin Finck BlTblFindEntry (
274c2c66affSColin Finck     _In_ PVOID *Table,
275c2c66affSColin Finck     _In_ ULONG Count,
276c2c66affSColin Finck     _Out_ PULONG EntryIndex,
277c2c66affSColin Finck     _In_ PBL_TBL_LOOKUP_ROUTINE Callback,
278c2c66affSColin Finck     _In_ PVOID Argument1,
279c2c66affSColin Finck     _In_ PVOID Argument2,
280c2c66affSColin Finck     _In_ PVOID Argument3,
281c2c66affSColin Finck     _In_ PVOID Argument4
282c2c66affSColin Finck     )
283c2c66affSColin Finck {
284c2c66affSColin Finck     PVOID Entry = NULL;
285c2c66affSColin Finck     ULONG Index;
286c2c66affSColin Finck     BOOLEAN Result;
287c2c66affSColin Finck 
288c2c66affSColin Finck     /* Check for invalid parameters */
289c2c66affSColin Finck     if (!(Table) || !(EntryIndex))
290c2c66affSColin Finck     {
291c2c66affSColin Finck         return Entry;
292c2c66affSColin Finck     }
293c2c66affSColin Finck 
294c2c66affSColin Finck     /* Loop each entry in the table */
295c2c66affSColin Finck     for (Index = 0; Index < Count;  Index++)
296c2c66affSColin Finck     {
297c2c66affSColin Finck         /* Check if this entry is filled out */
298c2c66affSColin Finck         if (Table[Index])
299c2c66affSColin Finck         {
300c2c66affSColin Finck             /* Call the comparison function */
301c2c66affSColin Finck             Result = Callback(Table[Index],
302c2c66affSColin Finck                               Argument1,
303c2c66affSColin Finck                               Argument2,
304c2c66affSColin Finck                               Argument3,
305c2c66affSColin Finck                               Argument4);
306c2c66affSColin Finck             if (Result)
307c2c66affSColin Finck             {
308c2c66affSColin Finck                 /* Entry found return it */
309c2c66affSColin Finck                 *EntryIndex = Index;
310c2c66affSColin Finck                 Entry = Table[Index];
311c2c66affSColin Finck                 break;
312c2c66affSColin Finck             }
313c2c66affSColin Finck         }
314c2c66affSColin Finck     }
315c2c66affSColin Finck 
316c2c66affSColin Finck     /* Return the entry that was (or wasn't) found */
317c2c66affSColin Finck     return Entry;
318c2c66affSColin Finck }
319c2c66affSColin Finck 
320c2c66affSColin Finck NTSTATUS
BlTblSetEntry(_Inout_ PVOID ** Table,_Inout_ PULONG Count,_In_ PVOID Entry,_Out_ PULONG EntryIndex,_In_ PBL_TBL_SET_ROUTINE Callback)321c2c66affSColin Finck BlTblSetEntry (
322c2c66affSColin Finck     _Inout_ PVOID** Table,
323c2c66affSColin Finck     _Inout_ PULONG Count,
324c2c66affSColin Finck     _In_ PVOID Entry,
325c2c66affSColin Finck     _Out_ PULONG EntryIndex,
326c2c66affSColin Finck     _In_ PBL_TBL_SET_ROUTINE Callback
327c2c66affSColin Finck     )
328c2c66affSColin Finck {
329c2c66affSColin Finck     ULONG NewCount;
330c2c66affSColin Finck     NTSTATUS Status = STATUS_SUCCESS;
331c2c66affSColin Finck     ULONG Index = 0;
332c2c66affSColin Finck     PVOID* NewTable;
333c2c66affSColin Finck 
334c2c66affSColin Finck     /* Make sure all the parameters were specified */
335c2c66affSColin Finck     if (!(Table) || !(*Table) || !(Count) || !(Callback))
336c2c66affSColin Finck     {
337c2c66affSColin Finck         return STATUS_INVALID_PARAMETER;
338c2c66affSColin Finck     }
339c2c66affSColin Finck 
340c2c66affSColin Finck     /* Read the current table */
341c2c66affSColin Finck     NewTable = *Table;
342c2c66affSColin Finck     NewCount = *Count;
343c2c66affSColin Finck 
344c2c66affSColin Finck     /* Iterate over it */
345c2c66affSColin Finck     while (Index < NewCount)
346c2c66affSColin Finck     {
347c2c66affSColin Finck         /* Look for a free index */
348c2c66affSColin Finck         if (!NewTable[Index])
349c2c66affSColin Finck         {
350c2c66affSColin Finck             goto SetIndex;
351c2c66affSColin Finck         }
352c2c66affSColin Finck 
353c2c66affSColin Finck         /* No free index yet, keep going */
354c2c66affSColin Finck         ++Index;
355c2c66affSColin Finck     }
356c2c66affSColin Finck 
357c2c66affSColin Finck     /* No free index was found, try to purge some entries */
358c2c66affSColin Finck     Index = 0;
359c2c66affSColin Finck     while (Index < NewCount)
360c2c66affSColin Finck     {
361c2c66affSColin Finck         /* Call each purge callback, trying to make space */
362c2c66affSColin Finck         Status = Callback(NewTable[Index]);
363c2c66affSColin Finck         if (NT_SUCCESS(Status))
364c2c66affSColin Finck         {
365c2c66affSColin Finck             /* We should have this slot available now */
366c2c66affSColin Finck             goto SetIndex;
367c2c66affSColin Finck         }
368c2c66affSColin Finck 
369c2c66affSColin Finck         /* Keep trying to purge more */
370c2c66affSColin Finck         ++Index;
371c2c66affSColin Finck     }
372c2c66affSColin Finck 
373c2c66affSColin Finck     /* Double the table */
374c2c66affSColin Finck     NewTable = BlMmAllocateHeap(2 * sizeof(PVOID) * NewCount);
375c2c66affSColin Finck     if (!NewTable)
376c2c66affSColin Finck     {
377c2c66affSColin Finck         return STATUS_NO_MEMORY;
378c2c66affSColin Finck     }
379c2c66affSColin Finck 
380c2c66affSColin Finck     /* Clear the new table, and copy the old entries */
381c2c66affSColin Finck     RtlZeroMemory(&NewTable[NewCount], sizeof(PVOID) * NewCount);
382c2c66affSColin Finck     RtlCopyMemory(NewTable, *Table, sizeof(PVOID) * NewCount);
383c2c66affSColin Finck 
384c2c66affSColin Finck     /* Free the old table */
385c2c66affSColin Finck     BlMmFreeHeap(*Table);
386c2c66affSColin Finck 
387c2c66affSColin Finck     /* Return the new table and count */
388c2c66affSColin Finck     *Count = 2 * NewCount;
389c2c66affSColin Finck     *Table = NewTable;
390c2c66affSColin Finck 
391c2c66affSColin Finck SetIndex:
392c2c66affSColin Finck     /* Set the index and return */
393c2c66affSColin Finck     NewTable[Index] = Entry;
394c2c66affSColin Finck     *EntryIndex = Index;
395c2c66affSColin Finck     return Status;
396c2c66affSColin Finck }
397c2c66affSColin Finck 
398c2c66affSColin Finck NTSTATUS
BlTblMap(_In_ PVOID * Table,_In_ ULONG Count,_In_ PBL_TBL_MAP_ROUTINE MapCallback)399c2c66affSColin Finck BlTblMap (
400c2c66affSColin Finck     _In_ PVOID *Table,
401c2c66affSColin Finck     _In_ ULONG Count,
402c2c66affSColin Finck     _In_ PBL_TBL_MAP_ROUTINE MapCallback
403c2c66affSColin Finck     )
404c2c66affSColin Finck {
405c2c66affSColin Finck     NTSTATUS Status, LocalStatus;
406c2c66affSColin Finck     PVOID Entry;
407c2c66affSColin Finck     ULONG Index;
408c2c66affSColin Finck 
409c2c66affSColin Finck     /* Bail out if there's no table */
410c2c66affSColin Finck     if (!Table)
411c2c66affSColin Finck     {
412c2c66affSColin Finck         return STATUS_INVALID_PARAMETER;
413c2c66affSColin Finck     }
414c2c66affSColin Finck 
415c2c66affSColin Finck     /* Assume success and loop each index */
416c2c66affSColin Finck     Status = STATUS_SUCCESS;
417c2c66affSColin Finck     for (Index = 0; Index < Count; Index++)
418c2c66affSColin Finck     {
419c2c66affSColin Finck         /* See if an entry exists at this index */
420c2c66affSColin Finck         Entry = Table[Index];
421c2c66affSColin Finck         if (Entry)
422c2c66affSColin Finck         {
423c2c66affSColin Finck             /* Call the map routine for this entry */
424c2c66affSColin Finck             LocalStatus = MapCallback(Entry, Index);
425c2c66affSColin Finck             if (!NT_SUCCESS(LocalStatus))
426c2c66affSColin Finck             {
427c2c66affSColin Finck                 /* Propagate failure only */
428c2c66affSColin Finck                 Status = LocalStatus;
429c2c66affSColin Finck             }
430c2c66affSColin Finck         }
431c2c66affSColin Finck     }
432c2c66affSColin Finck 
433c2c66affSColin Finck     /* Return status to caller */
434c2c66affSColin Finck     return Status;
435c2c66affSColin Finck }
436c2c66affSColin Finck 
437c2c66affSColin Finck ULONG HtTableSize;
438c2c66affSColin Finck PBL_HASH_TABLE* HtTableArray;
439c2c66affSColin Finck ULONG HtTableEntries;
440c2c66affSColin Finck 
441c2c66affSColin Finck ULONG
DefaultHashFunction(_In_ PBL_HASH_ENTRY Entry,_In_ ULONG TableSize)442c2c66affSColin Finck DefaultHashFunction (
443c2c66affSColin Finck     _In_ PBL_HASH_ENTRY Entry,
444c2c66affSColin Finck     _In_ ULONG TableSize
445c2c66affSColin Finck     )
446c2c66affSColin Finck {
447c2c66affSColin Finck     PUCHAR Value;
448c2c66affSColin Finck     ULONG KeyHash, i;
449c2c66affSColin Finck 
450c2c66affSColin Finck     /* Check if the value is a pointer, or embedded inline */
451c2c66affSColin Finck     Value = (Entry->Flags & BL_HT_VALUE_IS_INLINE) ? Entry->Value : (PUCHAR)&Entry->Value;
452c2c66affSColin Finck 
453c2c66affSColin Finck     /* Iterate over each byte, and sum it */
454c2c66affSColin Finck     for (i = 0, KeyHash = 0; i < Entry->Size; i++)
455c2c66affSColin Finck     {
456c2c66affSColin Finck         KeyHash += Value[i++];
457c2c66affSColin Finck     }
458c2c66affSColin Finck 
459c2c66affSColin Finck     /* Modulo the number of buckets */
460c2c66affSColin Finck     return KeyHash % TableSize;
461c2c66affSColin Finck }
462c2c66affSColin Finck 
463c2c66affSColin Finck BOOLEAN
HtpCompareKeys(_In_ PBL_HASH_ENTRY Entry1,_In_ PBL_HASH_ENTRY Entry2)464c2c66affSColin Finck HtpCompareKeys (
465c2c66affSColin Finck     _In_ PBL_HASH_ENTRY Entry1,
466c2c66affSColin Finck     _In_ PBL_HASH_ENTRY Entry2
467c2c66affSColin Finck     )
468c2c66affSColin Finck {
469c2c66affSColin Finck     ULONG Flags;
470c2c66affSColin Finck     BOOLEAN ValueMatch;
471c2c66affSColin Finck 
472c2c66affSColin Finck     /* Check if the flags or sizes are not matching */
473c2c66affSColin Finck     Flags = Entry1->Flags;
474c2c66affSColin Finck     if ((Entry1->Size != Entry2->Size) || (Flags != Entry2->Flags))
475c2c66affSColin Finck     {
476c2c66affSColin Finck         ValueMatch = FALSE;
477c2c66affSColin Finck     }
478c2c66affSColin Finck     else if (Flags & BL_HT_VALUE_IS_INLINE)
479c2c66affSColin Finck     {
480c2c66affSColin Finck         /* Check if this is an in-line value, compare it */
481c2c66affSColin Finck         ValueMatch = Entry1->Value == Entry2->Value;
482c2c66affSColin Finck     }
483c2c66affSColin Finck     else
484c2c66affSColin Finck     {
485c2c66affSColin Finck         /* This is a pointer value, compare it */
486c2c66affSColin Finck         ValueMatch = (RtlCompareMemory(Entry1->Value, Entry2->Value, Entry1->Size) ==
487c2c66affSColin Finck                       Entry1->Size);
488c2c66affSColin Finck     }
489c2c66affSColin Finck 
490c2c66affSColin Finck     /* Return if it matched */
491c2c66affSColin Finck     return ValueMatch;
492c2c66affSColin Finck }
493c2c66affSColin Finck 
494c2c66affSColin Finck NTSTATUS
TblDoNotPurgeEntry(_In_ PVOID Entry)495c2c66affSColin Finck TblDoNotPurgeEntry (
496c2c66affSColin Finck     _In_ PVOID Entry
497c2c66affSColin Finck     )
498c2c66affSColin Finck {
499c2c66affSColin Finck     /* Never purge this entry */
500c2c66affSColin Finck     return STATUS_UNSUCCESSFUL;
501c2c66affSColin Finck }
502c2c66affSColin Finck 
503c2c66affSColin Finck NTSTATUS
BlHtCreate(_In_ ULONG Size,_In_ PBL_HASH_TABLE_HASH_FUNCTION HashFunction,_In_ PBL_HASH_TABLE_COMPARE_FUNCTION CompareFunction,_Out_ PULONG Id)504c2c66affSColin Finck BlHtCreate (
505c2c66affSColin Finck     _In_ ULONG Size,
506c2c66affSColin Finck     _In_ PBL_HASH_TABLE_HASH_FUNCTION HashFunction,
507c2c66affSColin Finck     _In_ PBL_HASH_TABLE_COMPARE_FUNCTION CompareFunction,
508c2c66affSColin Finck     _Out_ PULONG Id
509c2c66affSColin Finck     )
510c2c66affSColin Finck {
511c2c66affSColin Finck     NTSTATUS Status;
512c2c66affSColin Finck     PBL_HASH_TABLE HashTable;
513c2c66affSColin Finck     ULONG i;
514c2c66affSColin Finck 
515c2c66affSColin Finck     /* Assume failure */
516c2c66affSColin Finck     HashTable = NULL;
517c2c66affSColin Finck 
518c2c66affSColin Finck     /* Can't create a table with no ID */
519c2c66affSColin Finck     if (!Id)
520c2c66affSColin Finck     {
521c2c66affSColin Finck         return STATUS_INVALID_PARAMETER;
522c2c66affSColin Finck     }
523c2c66affSColin Finck 
524c2c66affSColin Finck     /* Check if we don't already have a hash table table */
525c2c66affSColin Finck     if (!HtTableSize)
526c2c66affSColin Finck     {
527c2c66affSColin Finck         /* Allocate it and zero it out */
528c2c66affSColin Finck         HtTableSize = 4;
529c2c66affSColin Finck         HtTableArray = BlMmAllocateHeap(HtTableSize * sizeof(PVOID));
530c2c66affSColin Finck         if (!HtTableArray)
531c2c66affSColin Finck         {
532c2c66affSColin Finck             Status = STATUS_NO_MEMORY;
533c2c66affSColin Finck             goto Quickie;
534c2c66affSColin Finck         }
535c2c66affSColin Finck         RtlZeroMemory(HtTableArray, HtTableSize * sizeof(PVOID));
536c2c66affSColin Finck         HtTableEntries = 0;
537c2c66affSColin Finck     }
538c2c66affSColin Finck 
539c2c66affSColin Finck     /* Allocate the hash table */
540c2c66affSColin Finck     HashTable = BlMmAllocateHeap(sizeof(*HashTable));
541c2c66affSColin Finck     if (!HashTable)
542c2c66affSColin Finck     {
543c2c66affSColin Finck         Status = STATUS_NO_MEMORY;
544c2c66affSColin Finck         goto Quickie;
545c2c66affSColin Finck     }
546c2c66affSColin Finck 
547c2c66affSColin Finck     /* Fill it out */
548c2c66affSColin Finck     HashTable->HashFunction = HashFunction ? HashFunction : DefaultHashFunction;
549c2c66affSColin Finck     HashTable->CompareFunction = CompareFunction ? CompareFunction : HtpCompareKeys;
550c2c66affSColin Finck     HashTable->Size = Size ? Size : 13;
551c2c66affSColin Finck 
552c2c66affSColin Finck     /* Allocate the hash links, one for each bucket */
553c2c66affSColin Finck     HashTable->HashLinks = BlMmAllocateHeap(sizeof(LIST_ENTRY) * HashTable->Size);
554c2c66affSColin Finck     if (!HashTable->HashLinks)
555c2c66affSColin Finck     {
556c2c66affSColin Finck         Status = STATUS_NO_MEMORY;
557c2c66affSColin Finck         goto Quickie;
558c2c66affSColin Finck     }
559c2c66affSColin Finck 
560c2c66affSColin Finck     /* Initialize the hash links */
561c2c66affSColin Finck     for (i = 0; i < HashTable->Size; i++)
562c2c66affSColin Finck     {
563c2c66affSColin Finck         InitializeListHead(&HashTable->HashLinks[i]);
564c2c66affSColin Finck     }
565c2c66affSColin Finck 
566c2c66affSColin Finck     /* Save us in the table of hash tables */
567c2c66affSColin Finck     Status = BlTblSetEntry((PVOID**)&HtTableArray,
568c2c66affSColin Finck                            &Size,
569c2c66affSColin Finck                            HashTable,
570c2c66affSColin Finck                            Id,
571c2c66affSColin Finck                            TblDoNotPurgeEntry);
572c2c66affSColin Finck     if (NT_SUCCESS(Status))
573c2c66affSColin Finck     {
574c2c66affSColin Finck         /* One more -- we're done */
575c2c66affSColin Finck         ++HtTableEntries;
576c2c66affSColin Finck         return Status;
577c2c66affSColin Finck     }
578c2c66affSColin Finck 
579c2c66affSColin Finck Quickie:
580c2c66affSColin Finck     /* Check if we just allocated the table array now */
581c2c66affSColin Finck     if (!(HtTableEntries) && (HtTableArray))
582c2c66affSColin Finck     {
583c2c66affSColin Finck         /* Free it */
584c2c66affSColin Finck         BlMmFreeHeap(HtTableArray);
585c2c66affSColin Finck         HtTableArray = NULL;
586c2c66affSColin Finck         HtTableSize = 0;
587c2c66affSColin Finck     }
588c2c66affSColin Finck 
589c2c66affSColin Finck     /* Check if we allocated a hash table*/
590c2c66affSColin Finck     if (HashTable)
591c2c66affSColin Finck     {
592c2c66affSColin Finck         /* With links? */
593c2c66affSColin Finck         if (HashTable->HashLinks)
594c2c66affSColin Finck         {
595c2c66affSColin Finck             /* Free them */
596c2c66affSColin Finck             BlMmFreeHeap(HashTable->HashLinks);
597c2c66affSColin Finck         }
598c2c66affSColin Finck 
599c2c66affSColin Finck         /* Free the table*/
600c2c66affSColin Finck         BlMmFreeHeap(HashTable);
601c2c66affSColin Finck     }
602c2c66affSColin Finck 
603c2c66affSColin Finck     /* We're done */
604c2c66affSColin Finck     return Status;
605c2c66affSColin Finck }
606c2c66affSColin Finck 
607c2c66affSColin Finck NTSTATUS
BlHtLookup(_In_ ULONG TableId,_In_ PBL_HASH_ENTRY Entry,_Out_opt_ PBL_HASH_VALUE * Value)608c2c66affSColin Finck BlHtLookup (
609c2c66affSColin Finck     _In_ ULONG TableId,
610c2c66affSColin Finck     _In_ PBL_HASH_ENTRY Entry,
611c2c66affSColin Finck     _Out_opt_ PBL_HASH_VALUE *Value
612c2c66affSColin Finck     )
613c2c66affSColin Finck {
614c2c66affSColin Finck     PBL_HASH_TABLE HashTable;
615c2c66affSColin Finck     ULONG HashValue;
616c2c66affSColin Finck     NTSTATUS Status;
617c2c66affSColin Finck     PLIST_ENTRY HashLinkHead, HashLink;
618c2c66affSColin Finck     PBL_HASH_NODE HashNode;
619c2c66affSColin Finck 
620c2c66affSColin Finck     /* Check if the table ID is invalid, or we have no entry, or it's malformed */
621c2c66affSColin Finck     if ((HtTableSize <= TableId) ||
622c2c66affSColin Finck         !(Entry) ||
623c2c66affSColin Finck         ((Entry->Flags & BL_HT_VALUE_IS_INLINE) && (Entry->Size != sizeof(ULONG))))
624c2c66affSColin Finck     {
625c2c66affSColin Finck         /* Fail */
626c2c66affSColin Finck         Status = STATUS_INVALID_PARAMETER;
627c2c66affSColin Finck     }
628c2c66affSColin Finck     else
629c2c66affSColin Finck     {
630c2c66affSColin Finck         /* Otherwise, get the hash table for this index */
631c2c66affSColin Finck         HashTable = HtTableArray[TableId];
632c2c66affSColin Finck 
633c2c66affSColin Finck         /* Get the hash bucket */
634c2c66affSColin Finck         HashValue = HashTable->HashFunction(Entry, HashTable->Size);
635c2c66affSColin Finck 
636c2c66affSColin Finck         /* Start iterating each entry in the bucket, assuming failure */
637c2c66affSColin Finck         Status = STATUS_NOT_FOUND;
638c2c66affSColin Finck         HashLinkHead = &HashTable->HashLinks[HashValue];
639c2c66affSColin Finck         HashLink = HashLinkHead->Flink;
640c2c66affSColin Finck         while (HashLink != HashLinkHead)
641c2c66affSColin Finck         {
642c2c66affSColin Finck             /* Get a node in this bucket, and compare the value */
643c2c66affSColin Finck             HashNode = CONTAINING_RECORD(HashLink, BL_HASH_NODE, ListEntry);
644c2c66affSColin Finck             if (HashTable->CompareFunction(&HashNode->Entry, Entry))
645c2c66affSColin Finck             {
646c2c66affSColin Finck                 /* Does the caller want the value? */
647c2c66affSColin Finck                 if (Value)
648c2c66affSColin Finck                 {
649c2c66affSColin Finck                     /* Return it */
650c2c66affSColin Finck                     *Value = &HashNode->Value;
651c2c66affSColin Finck                 }
652c2c66affSColin Finck 
653c2c66affSColin Finck                 /* Return success and stop scanning */
654c2c66affSColin Finck                 Status = STATUS_SUCCESS;
655c2c66affSColin Finck                 break;
656c2c66affSColin Finck             }
657c2c66affSColin Finck 
658c2c66affSColin Finck             /* Try the next node */
659c2c66affSColin Finck             HashLink = HashLink->Flink;
660c2c66affSColin Finck         }
661c2c66affSColin Finck     }
662c2c66affSColin Finck 
663c2c66affSColin Finck     /* Return back to the caller */
664c2c66affSColin Finck     return Status;
665c2c66affSColin Finck }
666c2c66affSColin Finck 
667c2c66affSColin Finck NTSTATUS
BlHtStore(_In_ ULONG TableId,_In_ PBL_HASH_ENTRY Entry,_In_ PVOID Data,_In_ ULONG DataSize)668c2c66affSColin Finck BlHtStore (
669c2c66affSColin Finck     _In_ ULONG TableId,
670c2c66affSColin Finck     _In_ PBL_HASH_ENTRY Entry,
671c2c66affSColin Finck     _In_ PVOID Data,
672c2c66affSColin Finck     _In_ ULONG DataSize
673c2c66affSColin Finck     )
674c2c66affSColin Finck {
675c2c66affSColin Finck     PBL_HASH_NODE HashNode;
676c2c66affSColin Finck     NTSTATUS Status;
677c2c66affSColin Finck     PLIST_ENTRY HashLinkHead;
678c2c66affSColin Finck     PBL_HASH_TABLE HashTable;
679c2c66affSColin Finck 
680c2c66affSColin Finck     /* Check for invalid table ID, missing arguments, or malformed entry */
681c2c66affSColin Finck     if ((HtTableSize <= TableId) ||
682c2c66affSColin Finck         !(Entry) ||
683c2c66affSColin Finck         !(Data) ||
684c2c66affSColin Finck         !(Entry->Size) ||
685c2c66affSColin Finck         !(Entry->Value) ||
686c2c66affSColin Finck         !(DataSize) ||
687c2c66affSColin Finck         ((Entry->Flags & BL_HT_VALUE_IS_INLINE) && (Entry->Size != sizeof(ULONG))))
688c2c66affSColin Finck     {
689c2c66affSColin Finck         /* Fail the call */
690c2c66affSColin Finck         Status = STATUS_INVALID_PARAMETER;
691c2c66affSColin Finck         goto Quickie;
692c2c66affSColin Finck     }
693c2c66affSColin Finck 
694c2c66affSColin Finck     /* Get the hash table for this ID */
695c2c66affSColin Finck     HashTable = HtTableArray[TableId];
696c2c66affSColin Finck 
697c2c66affSColin Finck     /* Allocate a hash node */
698c2c66affSColin Finck     HashNode = BlMmAllocateHeap(sizeof(*HashNode));
699c2c66affSColin Finck     if (!HashNode)
700c2c66affSColin Finck     {
701c2c66affSColin Finck         Status = STATUS_NO_MEMORY;
702c2c66affSColin Finck         goto Quickie;
703c2c66affSColin Finck     }
704c2c66affSColin Finck 
705c2c66affSColin Finck     /* Capture all the data*/
706c2c66affSColin Finck     HashNode->Entry.Size = Entry->Size;
707c2c66affSColin Finck     HashNode->Entry.Flags = Entry->Flags;
708c2c66affSColin Finck     HashNode->Entry.Value = Entry->Value;
709c2c66affSColin Finck     HashNode->Value.DataSize = DataSize;
710c2c66affSColin Finck     HashNode->Value.Data = Data;
711c2c66affSColin Finck 
712c2c66affSColin Finck     /* Insert it into the bucket list and return success */
713c2c66affSColin Finck     HashLinkHead = &HashTable->HashLinks[HashTable->HashFunction(Entry, HashTable->Size)];
714c2c66affSColin Finck     InsertTailList(HashLinkHead, &HashNode->ListEntry);
715c2c66affSColin Finck     Status = STATUS_SUCCESS;
716c2c66affSColin Finck 
717c2c66affSColin Finck Quickie:
718c2c66affSColin Finck     return Status;
719c2c66affSColin Finck }
720c2c66affSColin Finck 
721c2c66affSColin Finck NTSTATUS
BlHtDelete(_In_ ULONG TableId,_In_ PBL_HASH_ENTRY Entry)722c2c66affSColin Finck BlHtDelete (
723c2c66affSColin Finck     _In_ ULONG TableId,
724c2c66affSColin Finck     _In_ PBL_HASH_ENTRY Entry
725c2c66affSColin Finck     )
726c2c66affSColin Finck {
727c2c66affSColin Finck     PBL_HASH_TABLE HashTable;
728c2c66affSColin Finck     ULONG HashValue;
729c2c66affSColin Finck     NTSTATUS Status;
730c2c66affSColin Finck     PLIST_ENTRY HashLinkHead, HashLink;
731c2c66affSColin Finck     PBL_HASH_NODE HashNode;
732c2c66affSColin Finck 
733c2c66affSColin Finck     /* Check if the table ID is invalid, or we have no entry, or it's malformed */
734c2c66affSColin Finck     if ((HtTableSize <= TableId) ||
735c2c66affSColin Finck         !(Entry) ||
736c2c66affSColin Finck         !(Entry->Size) ||
737c2c66affSColin Finck         !(Entry->Value) ||
738c2c66affSColin Finck         ((Entry->Flags & BL_HT_VALUE_IS_INLINE) && (Entry->Size != sizeof(ULONG))))
739c2c66affSColin Finck     {
740c2c66affSColin Finck         /* Fail */
741c2c66affSColin Finck         Status = STATUS_INVALID_PARAMETER;
742c2c66affSColin Finck     }
743c2c66affSColin Finck     else
744c2c66affSColin Finck     {
745c2c66affSColin Finck         /* Otherwise, get the hash table for this index */
746c2c66affSColin Finck         HashTable = HtTableArray[TableId];
747c2c66affSColin Finck 
748c2c66affSColin Finck         /* Get the hash bucket */
749c2c66affSColin Finck         HashValue = HashTable->HashFunction(Entry, HashTable->Size);
750c2c66affSColin Finck 
751c2c66affSColin Finck         /* Start iterating each entry in the bucket, assuming failure */
752c2c66affSColin Finck         Status = STATUS_NOT_FOUND;
753c2c66affSColin Finck         HashLinkHead = &HashTable->HashLinks[HashValue];
754c2c66affSColin Finck         HashLink = HashLinkHead->Flink;
755c2c66affSColin Finck         while (HashLink != HashLinkHead)
756c2c66affSColin Finck         {
757c2c66affSColin Finck             /* Get a node in this bucket, and compare the value */
758c2c66affSColin Finck             HashNode = CONTAINING_RECORD(HashLink, BL_HASH_NODE, ListEntry);
759c2c66affSColin Finck             if (HashTable->CompareFunction(&HashNode->Entry, Entry))
760c2c66affSColin Finck             {
761c2c66affSColin Finck                 /* Remove it from the list and free it */
762c2c66affSColin Finck                 RemoveEntryList(&HashNode->ListEntry);
763c2c66affSColin Finck                 BlMmFreeHeap(HashNode);
764c2c66affSColin Finck                 return STATUS_SUCCESS;
765c2c66affSColin Finck             }
766c2c66affSColin Finck 
767c2c66affSColin Finck             /* Try the next node */
768c2c66affSColin Finck             HashLink = HashLink->Flink;
769c2c66affSColin Finck         }
770c2c66affSColin Finck     }
771c2c66affSColin Finck 
772c2c66affSColin Finck     /* Return back to the caller */
773c2c66affSColin Finck     return Status;
774c2c66affSColin Finck }
775c2c66affSColin Finck 
776c2c66affSColin Finck ULONG
BlUtlCheckSum(_In_ ULONG PartialSum,_In_ PUCHAR Buffer,_In_ ULONG Length,_In_ ULONG Flags)777c2c66affSColin Finck BlUtlCheckSum (
778c2c66affSColin Finck     _In_ ULONG PartialSum,
779c2c66affSColin Finck     _In_ PUCHAR Buffer,
780c2c66affSColin Finck     _In_ ULONG Length,
781c2c66affSColin Finck     _In_ ULONG Flags
782c2c66affSColin Finck     )
783c2c66affSColin Finck {
784c2c66affSColin Finck     ULONG i;
785c2c66affSColin Finck 
786c2c66affSColin Finck     if (Flags & BL_UTL_CHECKSUM_UCHAR_BUFFER)
787c2c66affSColin Finck     {
788c2c66affSColin Finck         EfiPrintf(L"Not supported\r\n");
789c2c66affSColin Finck         return 0;
790c2c66affSColin Finck     }
791c2c66affSColin Finck     else if (Flags & BL_UTL_CHECKSUM_USHORT_BUFFER)
792c2c66affSColin Finck     {
793c2c66affSColin Finck         PartialSum = (unsigned __int16)PartialSum;
794c2c66affSColin Finck         Length &= ~1;
795c2c66affSColin Finck 
796c2c66affSColin Finck         for (i = 0; i < Length; i += 2)
797c2c66affSColin Finck         {
798c2c66affSColin Finck             PartialSum += *(unsigned __int16 *)&Buffer[i];
799c2c66affSColin Finck             if (Flags & BL_UTL_CHECKSUM_COMPLEMENT)
800c2c66affSColin Finck             {
801c2c66affSColin Finck                 PartialSum = (unsigned __int16)((PartialSum >> 16) + PartialSum);
802c2c66affSColin Finck             }
803c2c66affSColin Finck         }
804c2c66affSColin Finck 
805c2c66affSColin Finck         if (i != Length)
806c2c66affSColin Finck         {
807c2c66affSColin Finck             PartialSum += (unsigned __int8)Buffer[Length];
808c2c66affSColin Finck             if (Flags & BL_UTL_CHECKSUM_COMPLEMENT)
809c2c66affSColin Finck             {
810c2c66affSColin Finck                 PartialSum = (unsigned __int16)((PartialSum >> 16) + PartialSum);
811c2c66affSColin Finck             }
812c2c66affSColin Finck         }
813c2c66affSColin Finck 
814c2c66affSColin Finck         if (Flags & BL_UTL_CHECKSUM_NEGATE)
815c2c66affSColin Finck         {
816c2c66affSColin Finck             return ~PartialSum;
817c2c66affSColin Finck         }
818c2c66affSColin Finck 
819c2c66affSColin Finck         PartialSum = (unsigned __int16)PartialSum;
820c2c66affSColin Finck     }
821c2c66affSColin Finck     else
822c2c66affSColin Finck     {
823c2c66affSColin Finck         /* Invalid mode */
824c2c66affSColin Finck         return 0;
825c2c66affSColin Finck     }
826c2c66affSColin Finck 
827c2c66affSColin Finck     if (Flags & BL_UTL_CHECKSUM_NEGATE)
828c2c66affSColin Finck     {
829c2c66affSColin Finck         return ~PartialSum;
830c2c66affSColin Finck     }
831c2c66affSColin Finck 
832c2c66affSColin Finck     return PartialSum;
833c2c66affSColin Finck }
834c2c66affSColin Finck 
835c2c66affSColin Finck #if defined(_M_IX86) || defined(_M_X64)
836c2c66affSColin Finck BOOLEAN
Archx86IsCpuidSupported(VOID)837c2c66affSColin Finck Archx86IsCpuidSupported (
838c2c66affSColin Finck     VOID
839c2c66affSColin Finck     )
840c2c66affSColin Finck {
841c2c66affSColin Finck     ULONG CallerFlags, Flags;
842c2c66affSColin Finck 
843c2c66affSColin Finck     /* Read the original flags, and add the CPUID bit */
844c2c66affSColin Finck     CallerFlags = __readeflags() ^ 0x200000;
845c2c66affSColin Finck     __writeeflags(CallerFlags);
846c2c66affSColin Finck 
847c2c66affSColin Finck     /* Read our flags now */
848c2c66affSColin Finck     Flags = __readeflags();
849c2c66affSColin Finck 
850c2c66affSColin Finck     /* Check if the bit stuck */
851c2c66affSColin Finck     return (((CallerFlags ^ Flags) >> 21) & 1) ^ 1;
852c2c66affSColin Finck }
853c2c66affSColin Finck #endif
854c2c66affSColin Finck 
855c2c66affSColin Finck BOOLEAN
BlArchIsCpuIdFunctionSupported(_In_ ULONG Function)856c2c66affSColin Finck BlArchIsCpuIdFunctionSupported (
857c2c66affSColin Finck     _In_ ULONG Function
858c2c66affSColin Finck     )
859c2c66affSColin Finck {
860c2c66affSColin Finck #if defined(_M_IX86) || defined(_M_X64)
861c2c66affSColin Finck     BOOLEAN Supported;
862c2c66affSColin Finck     INT CpuInfo[4];
863c2c66affSColin Finck 
864c2c66affSColin Finck     /* Check if the CPU supports this instruction */
865c2c66affSColin Finck     Supported = Archx86IsCpuidSupported();
866c2c66affSColin Finck     if (!Supported)
867c2c66affSColin Finck     {
868c2c66affSColin Finck         return FALSE;
869c2c66affSColin Finck     }
870c2c66affSColin Finck 
871c2c66affSColin Finck     /* Check if it's the extended function */
872c2c66affSColin Finck     if (Function >= 0x80000000)
873c2c66affSColin Finck     {
874c2c66affSColin Finck         /* Check if extended functions are supported */
875c2c66affSColin Finck         __cpuid(CpuInfo, 0x80000000);
876c2c66affSColin Finck         if ((CpuInfo[0] & 0xFFFFFF00) != 0x80000000)
877c2c66affSColin Finck         {
878c2c66affSColin Finck             /* Nope */
879c2c66affSColin Finck             return FALSE;
880c2c66affSColin Finck         }
881c2c66affSColin Finck     }
882c2c66affSColin Finck     else
883c2c66affSColin Finck     {
884c2c66affSColin Finck         /* It's a regular function, get the maximum one supported */
885c2c66affSColin Finck         __cpuid(CpuInfo, 0);
886c2c66affSColin Finck     }
887c2c66affSColin Finck 
888c2c66affSColin Finck     /* Check if our function is within bounds */
889c2c66affSColin Finck     if (Function <= CpuInfo[0])
890c2c66affSColin Finck     {
891c2c66affSColin Finck         return TRUE;
892c2c66affSColin Finck     }
893c2c66affSColin Finck #else
894c2c66affSColin Finck     EfiPrintf(L"BlArchIsCpuIdFunctionSupported not implemented for this platform.\r\n");
895c2c66affSColin Finck #endif
896c2c66affSColin Finck 
897c2c66affSColin Finck     /* Nope */
898c2c66affSColin Finck     return FALSE;
899c2c66affSColin Finck }
900c2c66affSColin Finck 
901c2c66affSColin Finck ULONGLONG
BlArchGetPerformanceCounter(VOID)902c2c66affSColin Finck BlArchGetPerformanceCounter (
903c2c66affSColin Finck     VOID
904c2c66affSColin Finck     )
905c2c66affSColin Finck {
906c2c66affSColin Finck #if defined(_M_IX86) || defined(_M_X64)
907478348eaSAlex Ionescu     CPU_INFO CpuInfo;
908c2c66affSColin Finck 
909c2c66affSColin Finck     /* Serialize with CPUID, if it exists */
910c2c66affSColin Finck     if (Archx86IsCpuidSupported())
911c2c66affSColin Finck     {
912478348eaSAlex Ionescu         BlArchCpuId(0, 0, &CpuInfo);
913c2c66affSColin Finck     }
914c2c66affSColin Finck 
915c2c66affSColin Finck     /* Read the TSC */
916c2c66affSColin Finck     return __rdtsc();
917c2c66affSColin Finck #else
918c2c66affSColin Finck     EfiPrintf(L"BlArchGetPerformanceCounter not implemented for this platform.\r\n");
919c2c66affSColin Finck     return 0;
920c2c66affSColin Finck #endif
921c2c66affSColin Finck }
922c2c66affSColin Finck 
923c2c66affSColin Finck VOID
BlArchCpuId(_In_ ULONG Function,_In_ ULONG SubFunction,_Out_ PCPU_INFO Result)924c2c66affSColin Finck BlArchCpuId (
925c2c66affSColin Finck     _In_ ULONG Function,
926c2c66affSColin Finck     _In_ ULONG SubFunction,
927478348eaSAlex Ionescu     _Out_ PCPU_INFO Result
928c2c66affSColin Finck     )
929c2c66affSColin Finck {
930c2c66affSColin Finck #if defined(_M_IX86) || defined(_M_X64)
931c2c66affSColin Finck     /* Use the intrinsic */
932478348eaSAlex Ionescu     __cpuidex((INT*)Result->AsUINT32, Function, SubFunction);
933c2c66affSColin Finck #endif
934c2c66affSColin Finck }
935e836d0b5SAlex Ionescu 
936e836d0b5SAlex Ionescu CPU_VENDORS
BlArchGetCpuVendor(VOID)937e836d0b5SAlex Ionescu BlArchGetCpuVendor (
938e836d0b5SAlex Ionescu     VOID
939e836d0b5SAlex Ionescu     )
940e836d0b5SAlex Ionescu {
941478348eaSAlex Ionescu     CPU_INFO CpuInfo;
942e836d0b5SAlex Ionescu     INT Temp;
943e836d0b5SAlex Ionescu 
944e836d0b5SAlex Ionescu     /* Get the CPU Vendor */
945478348eaSAlex Ionescu     BlArchCpuId(0, 0, &CpuInfo);
946*a380a616SMark Jansen #if defined(_M_IX86) || defined(_M_X64)
947478348eaSAlex Ionescu     Temp = CpuInfo.Ecx;
948478348eaSAlex Ionescu     CpuInfo.Ecx = CpuInfo.Edx;
949478348eaSAlex Ionescu     CpuInfo.Edx = Temp;
950e836d0b5SAlex Ionescu 
951e836d0b5SAlex Ionescu     /* Check against supported values */
952478348eaSAlex Ionescu     if (!strncmp((PCHAR)&CpuInfo.Ebx, "GenuineIntel", 12))
953e836d0b5SAlex Ionescu     {
954e836d0b5SAlex Ionescu         return CPU_INTEL;
955e836d0b5SAlex Ionescu     }
956478348eaSAlex Ionescu     if (!strncmp((PCHAR)&CpuInfo.Ebx, "AuthenticAMD", 12))
957e836d0b5SAlex Ionescu     {
958e836d0b5SAlex Ionescu         return CPU_AMD;
959e836d0b5SAlex Ionescu     }
960478348eaSAlex Ionescu     if (!strncmp((PCHAR)&CpuInfo.Ebx, "CentaurHauls", 12))
961e836d0b5SAlex Ionescu     {
962e836d0b5SAlex Ionescu         return CPU_VIA;
963e836d0b5SAlex Ionescu     }
9643be40816STimo Kreuzer #ifdef _M_IX86
965478348eaSAlex Ionescu     if (!strncmp((PCHAR)&CpuInfo.Ebx, "CyrixInstead", 12))
966e836d0b5SAlex Ionescu     {
967e836d0b5SAlex Ionescu         return CPU_CYRIX;
968e836d0b5SAlex Ionescu     }
969478348eaSAlex Ionescu     if (!strncmp((PCHAR)&CpuInfo.Ebx, "GenuineTMx86", 12))
970e836d0b5SAlex Ionescu     {
971e836d0b5SAlex Ionescu         return CPU_TRANSMETA;
972e836d0b5SAlex Ionescu     }
973478348eaSAlex Ionescu     if (!strncmp((PCHAR)&CpuInfo.Ebx, "RiseRiseRise", 12))
974e836d0b5SAlex Ionescu     {
975e836d0b5SAlex Ionescu         return CPU_RISE;
976e836d0b5SAlex Ionescu     }
9773be40816STimo Kreuzer #endif // _M_IX86
978*a380a616SMark Jansen #else // defined(_M_IX86) || defined(_M_X64)
979*a380a616SMark Jansen     EfiPrintf(L"BlArchGetCpuVendor not implemented for this platform.\r\n");
980*a380a616SMark Jansen #endif
981e836d0b5SAlex Ionescu     /* Other */
982e836d0b5SAlex Ionescu     return CPU_UNKNOWN;
983e836d0b5SAlex Ionescu }
984