1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS NT User-Mode DLL 4 * FILE: lib/ntdll/rtl/libsup.c 5 * PURPOSE: RTL Support Routines 6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) 7 * Gunnar Dalsnes 8 */ 9 10 /* INCLUDES *****************************************************************/ 11 12 #include <ntdll.h> 13 14 #define NDEBUG 15 #include <debug.h> 16 17 SIZE_T RtlpAllocDeallocQueryBufferSize = PAGE_SIZE; 18 PTEB LdrpTopLevelDllBeingLoadedTeb = NULL; 19 PVOID MmHighestUserAddress = (PVOID)MI_HIGHEST_USER_ADDRESS; 20 21 /* FUNCTIONS ***************************************************************/ 22 23 BOOLEAN 24 NTAPI 25 RtlpCheckForActiveDebugger(VOID) 26 { 27 /* Return the flag in the PEB */ 28 return NtCurrentPeb()->BeingDebugged; 29 } 30 31 BOOLEAN 32 NTAPI 33 RtlpSetInDbgPrint(VOID) 34 { 35 /* Check if it's already set and return TRUE if so */ 36 if (NtCurrentTeb()->InDbgPrint) return TRUE; 37 38 /* Set it and return */ 39 NtCurrentTeb()->InDbgPrint = TRUE; 40 return FALSE; 41 } 42 43 VOID 44 NTAPI 45 RtlpClearInDbgPrint(VOID) 46 { 47 /* Clear the flag */ 48 NtCurrentTeb()->InDbgPrint = FALSE; 49 } 50 51 KPROCESSOR_MODE 52 NTAPI 53 RtlpGetMode(VOID) 54 { 55 return UserMode; 56 } 57 58 /* 59 * @implemented 60 */ 61 PPEB 62 NTAPI 63 RtlGetCurrentPeb(VOID) 64 { 65 return NtCurrentPeb(); 66 } 67 68 /* 69 * @implemented 70 */ 71 VOID NTAPI 72 RtlAcquirePebLock(VOID) 73 { 74 PPEB Peb = NtCurrentPeb (); 75 RtlEnterCriticalSection(Peb->FastPebLock); 76 } 77 78 /* 79 * @implemented 80 */ 81 VOID NTAPI 82 RtlReleasePebLock(VOID) 83 { 84 PPEB Peb = NtCurrentPeb (); 85 RtlLeaveCriticalSection(Peb->FastPebLock); 86 } 87 88 /* 89 * @implemented 90 */ 91 ULONG 92 NTAPI 93 RtlGetNtGlobalFlags(VOID) 94 { 95 PPEB pPeb = NtCurrentPeb(); 96 return pPeb->NtGlobalFlag; 97 } 98 99 NTSTATUS 100 NTAPI 101 RtlDeleteHeapLock(IN OUT PHEAP_LOCK Lock) 102 { 103 return RtlDeleteCriticalSection(&Lock->CriticalSection); 104 } 105 106 NTSTATUS 107 NTAPI 108 RtlEnterHeapLock(IN OUT PHEAP_LOCK Lock, IN BOOLEAN Exclusive) 109 { 110 UNREFERENCED_PARAMETER(Exclusive); 111 112 return RtlEnterCriticalSection(&Lock->CriticalSection); 113 } 114 115 BOOLEAN 116 NTAPI 117 RtlTryEnterHeapLock(IN OUT PHEAP_LOCK Lock, IN BOOLEAN Exclusive) 118 { 119 UNREFERENCED_PARAMETER(Exclusive); 120 121 return RtlTryEnterCriticalSection(&Lock->CriticalSection); 122 } 123 124 NTSTATUS 125 NTAPI 126 RtlInitializeHeapLock(IN OUT PHEAP_LOCK *Lock) 127 { 128 return RtlInitializeCriticalSection(&(*Lock)->CriticalSection); 129 } 130 131 NTSTATUS 132 NTAPI 133 RtlLeaveHeapLock(IN OUT PHEAP_LOCK Lock) 134 { 135 return RtlLeaveCriticalSection(&Lock->CriticalSection); 136 } 137 138 PVOID 139 NTAPI 140 RtlpAllocateMemory(UINT Bytes, 141 ULONG Tag) 142 { 143 UNREFERENCED_PARAMETER(Tag); 144 145 return RtlAllocateHeap(RtlGetProcessHeap(), 146 0, 147 Bytes); 148 } 149 150 151 VOID 152 NTAPI 153 RtlpFreeMemory(PVOID Mem, 154 ULONG Tag) 155 { 156 UNREFERENCED_PARAMETER(Tag); 157 158 RtlFreeHeap(RtlGetProcessHeap(), 159 0, 160 Mem); 161 } 162 163 164 #if DBG 165 VOID FASTCALL 166 CHECK_PAGED_CODE_RTL(char *file, int line) 167 { 168 /* meaningless in user mode */ 169 } 170 #endif 171 172 VOID 173 NTAPI 174 RtlpSetHeapParameters(IN PRTL_HEAP_PARAMETERS Parameters) 175 { 176 PPEB Peb; 177 178 /* Get PEB */ 179 Peb = RtlGetCurrentPeb(); 180 181 /* Apply defaults for non-set parameters */ 182 if (!Parameters->SegmentCommit) Parameters->SegmentCommit = Peb->HeapSegmentCommit; 183 if (!Parameters->SegmentReserve) Parameters->SegmentReserve = Peb->HeapSegmentReserve; 184 if (!Parameters->DeCommitFreeBlockThreshold) Parameters->DeCommitFreeBlockThreshold = Peb->HeapDeCommitFreeBlockThreshold; 185 if (!Parameters->DeCommitTotalFreeThreshold) Parameters->DeCommitTotalFreeThreshold = Peb->HeapDeCommitTotalFreeThreshold; 186 } 187 188 BOOLEAN 189 NTAPI 190 RtlpHandleDpcStackException(IN PEXCEPTION_REGISTRATION_RECORD RegistrationFrame, 191 IN ULONG_PTR RegistrationFrameEnd, 192 IN OUT PULONG_PTR StackLow, 193 IN OUT PULONG_PTR StackHigh) 194 { 195 /* There's no such thing as a DPC stack in user-mode */ 196 return FALSE; 197 } 198 199 VOID 200 NTAPI 201 RtlpCheckLogException(IN PEXCEPTION_RECORD ExceptionRecord, 202 IN PCONTEXT ContextRecord, 203 IN PVOID ContextData, 204 IN ULONG Size) 205 { 206 /* Exception logging is not done in user-mode */ 207 } 208 209 BOOLEAN 210 NTAPI 211 RtlpCaptureStackLimits(IN ULONG_PTR Ebp, 212 IN ULONG_PTR *StackBegin, 213 IN ULONG_PTR *StackEnd) 214 { 215 /* FIXME: Verify */ 216 *StackBegin = (ULONG_PTR)NtCurrentTeb()->NtTib.StackLimit; 217 *StackEnd = (ULONG_PTR)NtCurrentTeb()->NtTib.StackBase; 218 return TRUE; 219 } 220 221 #ifndef _M_AMD64 222 /* 223 * @implemented 224 */ 225 ULONG 226 NTAPI 227 RtlWalkFrameChain(OUT PVOID *Callers, 228 IN ULONG Count, 229 IN ULONG Flags) 230 { 231 ULONG_PTR Stack, NewStack, StackBegin, StackEnd = 0; 232 ULONG Eip; 233 BOOLEAN Result, StopSearch = FALSE; 234 ULONG i = 0; 235 236 /* Get current EBP */ 237 #if defined(_M_IX86) 238 #if defined __GNUC__ 239 __asm__("mov %%ebp, %0" : "=r" (Stack) : ); 240 #elif defined(_MSC_VER) 241 __asm mov Stack, ebp 242 #endif 243 #elif defined(_M_MIPS) 244 __asm__("move $sp, %0" : "=r" (Stack) : ); 245 #elif defined(_M_PPC) 246 __asm__("mr %0,1" : "=r" (Stack) : ); 247 #elif defined(_M_ARM) 248 #if defined __GNUC__ 249 __asm__("mov sp, %0" : "=r"(Stack) : ); 250 #elif defined(_MSC_VER) 251 // FIXME: Hack. Probably won't work if this ever actually manages to run someday. 252 Stack = (ULONG_PTR)&Stack; 253 #endif 254 #else 255 #error Unknown architecture 256 #endif 257 258 /* Set it as the stack begin limit as well */ 259 StackBegin = (ULONG_PTR)Stack; 260 261 /* Check if we're called for non-logging mode */ 262 if (!Flags) 263 { 264 /* Get the actual safe limits */ 265 Result = RtlpCaptureStackLimits((ULONG_PTR)Stack, 266 &StackBegin, 267 &StackEnd); 268 if (!Result) return 0; 269 } 270 271 /* Use a SEH block for maximum protection */ 272 _SEH2_TRY 273 { 274 /* Loop the frames */ 275 for (i = 0; i < Count; i++) 276 { 277 /* 278 * Leave if we're past the stack, 279 * if we're before the stack, 280 * or if we've reached ourselves. 281 */ 282 if ((Stack >= StackEnd) || 283 (!i ? (Stack < StackBegin) : (Stack <= StackBegin)) || 284 ((StackEnd - Stack) < (2 * sizeof(ULONG_PTR)))) 285 { 286 /* We're done or hit a bad address */ 287 break; 288 } 289 290 /* Get new stack and EIP */ 291 NewStack = *(PULONG_PTR)Stack; 292 Eip = *(PULONG_PTR)(Stack + sizeof(ULONG_PTR)); 293 294 /* Check if the new pointer is above the oldone and past the end */ 295 if (!((Stack < NewStack) && (NewStack < StackEnd))) 296 { 297 /* Stop searching after this entry */ 298 StopSearch = TRUE; 299 } 300 301 /* Also make sure that the EIP isn't a stack address */ 302 if ((StackBegin < Eip) && (Eip < StackEnd)) break; 303 304 /* FIXME: Check that EIP is inside a loaded module */ 305 306 /* Save this frame */ 307 Callers[i] = (PVOID)Eip; 308 309 /* Check if we should continue */ 310 if (StopSearch) 311 { 312 /* Return the next index */ 313 i++; 314 break; 315 } 316 317 /* Move to the next stack */ 318 Stack = NewStack; 319 } 320 } 321 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 322 { 323 /* No index */ 324 i = 0; 325 } 326 _SEH2_END; 327 328 /* Return frames parsed */ 329 return i; 330 } 331 #endif 332 333 #ifdef _AMD64_ 334 VOID 335 NTAPI 336 RtlpGetStackLimits( 337 OUT PULONG_PTR LowLimit, 338 OUT PULONG_PTR HighLimit) 339 { 340 *LowLimit = (ULONG_PTR)NtCurrentTeb()->NtTib.StackLimit; 341 *HighLimit = (ULONG_PTR)NtCurrentTeb()->NtTib.StackBase; 342 return; 343 } 344 #endif 345 346 BOOLEAN 347 NTAPI 348 RtlIsThreadWithinLoaderCallout(VOID) 349 { 350 return LdrpTopLevelDllBeingLoadedTeb == NtCurrentTeb(); 351 } 352 353 /* RTL Atom Tables ************************************************************/ 354 355 typedef struct _RTL_ATOM_HANDLE 356 { 357 RTL_HANDLE_TABLE_ENTRY Handle; 358 PRTL_ATOM_TABLE_ENTRY AtomEntry; 359 } RTL_ATOM_HANDLE, *PRTL_ATOM_HANDLE; 360 361 NTSTATUS 362 RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable) 363 { 364 RtlInitializeCriticalSection(&AtomTable->CriticalSection); 365 return STATUS_SUCCESS; 366 } 367 368 369 VOID 370 RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable) 371 { 372 RtlDeleteCriticalSection(&AtomTable->CriticalSection); 373 } 374 375 376 BOOLEAN 377 RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable) 378 { 379 RtlEnterCriticalSection(&AtomTable->CriticalSection); 380 return TRUE; 381 } 382 383 384 VOID 385 RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable) 386 { 387 RtlLeaveCriticalSection(&AtomTable->CriticalSection); 388 } 389 390 391 /* handle functions */ 392 393 BOOLEAN 394 RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable) 395 { 396 RtlInitializeHandleTable(0xCFFF, 397 sizeof(RTL_ATOM_HANDLE), 398 &AtomTable->RtlHandleTable); 399 400 return TRUE; 401 } 402 403 VOID 404 RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable) 405 { 406 RtlDestroyHandleTable(&AtomTable->RtlHandleTable); 407 } 408 409 PRTL_ATOM_TABLE 410 RtlpAllocAtomTable(ULONG Size) 411 { 412 return (PRTL_ATOM_TABLE)RtlAllocateHeap(RtlGetProcessHeap(), 413 HEAP_ZERO_MEMORY, 414 Size); 415 } 416 417 VOID 418 RtlpFreeAtomTable(PRTL_ATOM_TABLE AtomTable) 419 { 420 RtlFreeHeap(RtlGetProcessHeap(), 421 0, 422 AtomTable); 423 } 424 425 PRTL_ATOM_TABLE_ENTRY 426 RtlpAllocAtomTableEntry(ULONG Size) 427 { 428 return (PRTL_ATOM_TABLE_ENTRY)RtlAllocateHeap(RtlGetProcessHeap(), 429 HEAP_ZERO_MEMORY, 430 Size); 431 } 432 433 VOID 434 RtlpFreeAtomTableEntry(PRTL_ATOM_TABLE_ENTRY Entry) 435 { 436 RtlFreeHeap(RtlGetProcessHeap(), 437 0, 438 Entry); 439 } 440 441 VOID 442 RtlpFreeAtomHandle(PRTL_ATOM_TABLE AtomTable, PRTL_ATOM_TABLE_ENTRY Entry) 443 { 444 PRTL_HANDLE_TABLE_ENTRY RtlHandleEntry; 445 446 if (RtlIsValidIndexHandle(&AtomTable->RtlHandleTable, 447 (ULONG)Entry->HandleIndex, 448 &RtlHandleEntry)) 449 { 450 RtlFreeHandle(&AtomTable->RtlHandleTable, 451 RtlHandleEntry); 452 } 453 } 454 455 BOOLEAN 456 RtlpCreateAtomHandle(PRTL_ATOM_TABLE AtomTable, PRTL_ATOM_TABLE_ENTRY Entry) 457 { 458 ULONG HandleIndex; 459 PRTL_HANDLE_TABLE_ENTRY RtlHandle; 460 461 RtlHandle = RtlAllocateHandle(&AtomTable->RtlHandleTable, 462 &HandleIndex); 463 if (RtlHandle != NULL) 464 { 465 PRTL_ATOM_HANDLE AtomHandle = (PRTL_ATOM_HANDLE)RtlHandle; 466 467 /* FIXME - Handle Indexes >= 0xC000 ?! */ 468 if (HandleIndex < 0xC000) 469 { 470 Entry->HandleIndex = (USHORT)HandleIndex; 471 Entry->Atom = 0xC000 + (USHORT)HandleIndex; 472 473 AtomHandle->AtomEntry = Entry; 474 AtomHandle->Handle.Flags = RTL_HANDLE_VALID; 475 476 return TRUE; 477 } 478 else 479 { 480 /* set the valid flag, otherwise RtlFreeHandle will fail! */ 481 AtomHandle->Handle.Flags = RTL_HANDLE_VALID; 482 483 RtlFreeHandle(&AtomTable->RtlHandleTable, 484 RtlHandle); 485 } 486 } 487 488 return FALSE; 489 } 490 491 PRTL_ATOM_TABLE_ENTRY 492 RtlpGetAtomEntry(PRTL_ATOM_TABLE AtomTable, ULONG Index) 493 { 494 PRTL_HANDLE_TABLE_ENTRY RtlHandle; 495 496 if (RtlIsValidIndexHandle(&AtomTable->RtlHandleTable, 497 Index, 498 &RtlHandle)) 499 { 500 PRTL_ATOM_HANDLE AtomHandle = (PRTL_ATOM_HANDLE)RtlHandle; 501 502 return AtomHandle->AtomEntry; 503 } 504 505 return NULL; 506 } 507 508 509 /* 510 * Ldr Resource support code 511 */ 512 513 IMAGE_RESOURCE_DIRECTORY *find_entry_by_name( IMAGE_RESOURCE_DIRECTORY *dir, 514 LPCWSTR name, void *root, 515 int want_dir ); 516 IMAGE_RESOURCE_DIRECTORY *find_entry_by_id( IMAGE_RESOURCE_DIRECTORY *dir, 517 WORD id, void *root, int want_dir ); 518 IMAGE_RESOURCE_DIRECTORY *find_first_entry( IMAGE_RESOURCE_DIRECTORY *dir, 519 void *root, int want_dir ); 520 int push_language( USHORT *list, ULONG pos, WORD lang ); 521 522 /********************************************************************** 523 * find_entry 524 * 525 * Find a resource entry 526 */ 527 NTSTATUS find_entry( PVOID BaseAddress, LDR_RESOURCE_INFO *info, 528 ULONG level, void **ret, int want_dir ) 529 { 530 ULONG size; 531 void *root; 532 IMAGE_RESOURCE_DIRECTORY *resdirptr; 533 USHORT list[9]; /* list of languages to try */ 534 int i, pos = 0; 535 LCID user_lcid, system_lcid; 536 537 root = RtlImageDirectoryEntryToData( BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_RESOURCE, &size ); 538 if (!root) return STATUS_RESOURCE_DATA_NOT_FOUND; 539 if (size < sizeof(*resdirptr)) return STATUS_RESOURCE_DATA_NOT_FOUND; 540 resdirptr = root; 541 542 if (!level--) goto done; 543 if (!(*ret = find_entry_by_name( resdirptr, (LPCWSTR)info->Type, root, want_dir || level ))) 544 return STATUS_RESOURCE_TYPE_NOT_FOUND; 545 if (!level--) return STATUS_SUCCESS; 546 547 resdirptr = *ret; 548 if (!(*ret = find_entry_by_name( resdirptr, (LPCWSTR)info->Name, root, want_dir || level ))) 549 return STATUS_RESOURCE_NAME_NOT_FOUND; 550 if (!level--) return STATUS_SUCCESS; 551 if (level) return STATUS_INVALID_PARAMETER; /* level > 3 */ 552 553 /* 1. specified language */ 554 pos = push_language( list, pos, info->Language ); 555 556 /* 2. specified language with neutral sublanguage */ 557 pos = push_language( list, pos, MAKELANGID( PRIMARYLANGID(info->Language), SUBLANG_NEUTRAL ) ); 558 559 /* 3. neutral language with neutral sublanguage */ 560 pos = push_language( list, pos, MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL ) ); 561 562 /* if no explicitly specified language, try some defaults */ 563 if (PRIMARYLANGID(info->Language) == LANG_NEUTRAL) 564 { 565 /* user defaults, unless SYS_DEFAULT sublanguage specified */ 566 if (SUBLANGID(info->Language) != SUBLANG_SYS_DEFAULT) 567 { 568 /* 4. current thread locale language */ 569 pos = push_language( list, pos, LANGIDFROMLCID(NtCurrentTeb()->CurrentLocale) ); 570 571 if (NT_SUCCESS(NtQueryDefaultLocale(TRUE, &user_lcid))) 572 { 573 /* 5. user locale language */ 574 pos = push_language( list, pos, LANGIDFROMLCID(user_lcid) ); 575 576 /* 6. user locale language with neutral sublanguage */ 577 pos = push_language( list, pos, MAKELANGID( PRIMARYLANGID(user_lcid), SUBLANG_NEUTRAL ) ); 578 } 579 } 580 581 /* now system defaults */ 582 583 if (NT_SUCCESS(NtQueryDefaultLocale(FALSE, &system_lcid))) 584 { 585 /* 7. system locale language */ 586 pos = push_language( list, pos, LANGIDFROMLCID( system_lcid ) ); 587 588 /* 8. system locale language with neutral sublanguage */ 589 pos = push_language( list, pos, MAKELANGID( PRIMARYLANGID(system_lcid), SUBLANG_NEUTRAL ) ); 590 } 591 592 /* 9. English */ 593 pos = push_language( list, pos, MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT ) ); 594 } 595 596 resdirptr = *ret; 597 for (i = 0; i < pos; i++) 598 if ((*ret = find_entry_by_id( resdirptr, list[i], root, want_dir ))) return STATUS_SUCCESS; 599 600 /* if no explicitly specified language, return the first entry */ 601 if (PRIMARYLANGID(info->Language) == LANG_NEUTRAL) 602 { 603 if ((*ret = find_first_entry( resdirptr, root, want_dir ))) return STATUS_SUCCESS; 604 } 605 return STATUS_RESOURCE_LANG_NOT_FOUND; 606 607 done: 608 *ret = resdirptr; 609 return STATUS_SUCCESS; 610 } 611 612 /* 613 * @implemented 614 */ 615 PVOID NTAPI 616 RtlPcToFileHeader(IN PVOID PcValue, 617 PVOID* BaseOfImage) 618 { 619 PLIST_ENTRY ModuleListHead; 620 PLIST_ENTRY Entry; 621 PLDR_DATA_TABLE_ENTRY Module; 622 PVOID ImageBase = NULL; 623 624 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock); 625 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList; 626 Entry = ModuleListHead->Flink; 627 while (Entry != ModuleListHead) 628 { 629 Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); 630 631 if ((ULONG_PTR)PcValue >= (ULONG_PTR)Module->DllBase && 632 (ULONG_PTR)PcValue < (ULONG_PTR)Module->DllBase + Module->SizeOfImage) 633 { 634 ImageBase = Module->DllBase; 635 break; 636 } 637 Entry = Entry->Flink; 638 } 639 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock); 640 641 *BaseOfImage = ImageBase; 642 return ImageBase; 643 } 644 645 /* 646 * @unimplemented 647 */ 648 NTSYSAPI 649 NTSTATUS 650 NTAPI 651 RtlDosApplyFileIsolationRedirection_Ustr(IN ULONG Flags, 652 IN PUNICODE_STRING OriginalName, 653 IN PUNICODE_STRING Extension, 654 IN OUT PUNICODE_STRING StaticString, 655 IN OUT PUNICODE_STRING DynamicString, 656 IN OUT PUNICODE_STRING *NewName, 657 IN PULONG NewFlags, 658 IN PSIZE_T FileNameSize, 659 IN PSIZE_T RequiredLength) 660 { 661 return STATUS_SXS_KEY_NOT_FOUND; 662 } 663 664 /* 665 * @implemented 666 */ 667 NTSYSAPI 668 NTSTATUS 669 NTAPI 670 RtlWow64EnableFsRedirection(IN BOOLEAN Wow64FsEnableRedirection) 671 { 672 /* This is what Windows returns on x86 */ 673 return STATUS_NOT_IMPLEMENTED; 674 } 675 676 /* 677 * @implemented 678 */ 679 NTSYSAPI 680 NTSTATUS 681 NTAPI 682 RtlWow64EnableFsRedirectionEx(IN PVOID Wow64FsEnableRedirection, 683 OUT PVOID *OldFsRedirectionLevel) 684 { 685 /* This is what Windows returns on x86 */ 686 return STATUS_NOT_IMPLEMENTED; 687 } 688 689 /* 690 * @unimplemented 691 */ 692 NTSYSAPI 693 NTSTATUS 694 NTAPI 695 RtlComputeImportTableHash(IN HANDLE FileHandle, 696 OUT PCHAR Hash, 697 IN ULONG ImportTableHashSize) 698 { 699 UNIMPLEMENTED; 700 return STATUS_NOT_IMPLEMENTED; 701 } 702 703 NTSTATUS 704 NTAPI 705 RtlpSafeCopyMemory( 706 _Out_writes_bytes_all_(Length) VOID UNALIGNED *Destination, 707 _In_reads_bytes_(Length) CONST VOID UNALIGNED *Source, 708 _In_ SIZE_T Length) 709 { 710 _SEH2_TRY 711 { 712 RtlCopyMemory(Destination, Source, Length); 713 } 714 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 715 { 716 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 717 } 718 _SEH2_END; 719 720 return STATUS_SUCCESS; 721 } 722 723 /* FIXME: code duplication with kernel32/client/time.c */ 724 ULONG 725 NTAPI 726 RtlGetTickCount(VOID) 727 { 728 ULARGE_INTEGER TickCount; 729 730 #ifdef _WIN64 731 TickCount.QuadPart = *((volatile ULONG64*)&SharedUserData->TickCount); 732 #else 733 while (TRUE) 734 { 735 TickCount.HighPart = (ULONG)SharedUserData->TickCount.High1Time; 736 TickCount.LowPart = SharedUserData->TickCount.LowPart; 737 738 if (TickCount.HighPart == (ULONG)SharedUserData->TickCount.High2Time) 739 break; 740 741 YieldProcessor(); 742 } 743 #endif 744 745 return (ULONG)((UInt32x32To64(TickCount.LowPart, 746 SharedUserData->TickCountMultiplier) >> 24) + 747 UInt32x32To64((TickCount.HighPart << 8) & 0xFFFFFFFF, 748 SharedUserData->TickCountMultiplier)); 749 } 750 751 /* EOF */ 752