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