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