Merge amd64 NDK from amd64 branch:
[reactos.git] / reactos / ntoskrnl / rtl / libsupp.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/rtl/libsupp.c
5 * PURPOSE: RTL Support Routines
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * Gunnar Dalsnes
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 #define TAG_ATMT 'TotA' /* Atom table */
17
18 extern ULONG NtGlobalFlag;
19
20 typedef struct _RTL_RANGE_ENTRY
21 {
22 LIST_ENTRY Entry;
23 RTL_RANGE Range;
24 } RTL_RANGE_ENTRY, *PRTL_RANGE_ENTRY;
25
26 PAGED_LOOKASIDE_LIST RtlpRangeListEntryLookasideList;
27 SIZE_T RtlpAllocDeallocQueryBufferSize = 128;
28
29 /* FUNCTIONS *****************************************************************/
30
31 VOID
32 NTAPI
33 RtlInitializeRangeListPackage(VOID)
34 {
35 /* Setup the lookaside list for allocations (not used yet) */
36 ExInitializePagedLookasideList(&RtlpRangeListEntryLookasideList,
37 NULL,
38 NULL,
39 POOL_COLD_ALLOCATION,
40 sizeof(RTL_RANGE_ENTRY),
41 'elRR',
42 16);
43 }
44
45 BOOLEAN
46 NTAPI
47 RtlpCheckForActiveDebugger(BOOLEAN Type)
48 {
49 /* This check is meaningless in kernel-mode */
50 return Type;
51 }
52
53 BOOLEAN
54 NTAPI
55 RtlpSetInDbgPrint(IN BOOLEAN NewValue)
56 {
57 /* This check is meaningless in kernel-mode */
58 return FALSE;
59 }
60
61 KPROCESSOR_MODE
62 NTAPI
63 RtlpGetMode()
64 {
65 return KernelMode;
66 }
67
68 PVOID
69 NTAPI
70 RtlpAllocateMemory(ULONG Bytes,
71 ULONG Tag)
72 {
73 return ExAllocatePoolWithTag(PagedPool,
74 (SIZE_T)Bytes,
75 Tag);
76 }
77
78
79 #define TAG_USTR 'RTSU'
80 #define TAG_ASTR 'RTSA'
81 #define TAG_OSTR 'RTSO'
82 VOID
83 NTAPI
84 RtlpFreeMemory(PVOID Mem,
85 ULONG Tag)
86 {
87 if (Tag == TAG_ASTR || Tag == TAG_OSTR || Tag == TAG_USTR)
88 ExFreePool(Mem);
89 else
90 ExFreePoolWithTag(Mem, Tag);
91 }
92
93 /*
94 * @implemented
95 */
96 VOID NTAPI
97 RtlAcquirePebLock(VOID)
98 {
99
100 }
101
102 /*
103 * @implemented
104 */
105 VOID NTAPI
106 RtlReleasePebLock(VOID)
107 {
108
109 }
110
111 NTSTATUS
112 NTAPI
113 LdrShutdownThread(VOID)
114 {
115 return STATUS_SUCCESS;
116 }
117
118
119 PPEB
120 NTAPI
121 RtlGetCurrentPeb(VOID)
122 {
123 return ((PEPROCESS)(KeGetCurrentThread()->ApcState.Process))->Peb;
124 }
125
126 NTSTATUS
127 NTAPI
128 RtlDeleteHeapLock(
129 PRTL_CRITICAL_SECTION CriticalSection)
130 {
131 ASSERT(FALSE);
132 return STATUS_SUCCESS;
133 }
134
135 NTSTATUS
136 NTAPI
137 RtlEnterHeapLock(
138 PRTL_CRITICAL_SECTION CriticalSection)
139 {
140 ASSERT(FALSE);
141 return STATUS_SUCCESS;
142 }
143
144 NTSTATUS
145 NTAPI
146 RtlInitializeHeapLock(
147 PRTL_CRITICAL_SECTION CriticalSection)
148 {
149 ASSERT(FALSE);
150 return STATUS_SUCCESS;
151 }
152
153 NTSTATUS
154 NTAPI
155 RtlLeaveHeapLock(
156 PRTL_CRITICAL_SECTION CriticalSection)
157 {
158 ASSERT(FALSE);
159 return STATUS_SUCCESS;
160 }
161
162 #if DBG
163 VOID FASTCALL
164 CHECK_PAGED_CODE_RTL(char *file, int line)
165 {
166 if(KeGetCurrentIrql() > APC_LEVEL)
167 {
168 DbgPrint("%s:%i: Pagable code called at IRQL > APC_LEVEL (%d)\n", file, line, KeGetCurrentIrql());
169 ASSERT(FALSE);
170 }
171 }
172 #endif
173
174 VOID
175 NTAPI
176 RtlpCheckLogException(IN PEXCEPTION_RECORD ExceptionRecord,
177 IN PCONTEXT ContextRecord,
178 IN PVOID ContextData,
179 IN ULONG Size)
180 {
181 /* Check the global flag */
182 if (NtGlobalFlag & FLG_ENABLE_EXCEPTION_LOGGING)
183 {
184 /* FIXME: Log this exception */
185 }
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 PKPRCB Prcb;
196 ULONG_PTR DpcStack;
197
198 /* Check if we are at DISPATCH or higher */
199 if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
200 {
201 /* Get the PRCB and DPC Stack */
202 Prcb = KeGetCurrentPrcb();
203 DpcStack = (ULONG_PTR)Prcb->DpcStack;
204
205 /* Check if we are in a DPC and the stack matches */
206 if ((Prcb->DpcRoutineActive) &&
207 (RegistrationFrameEnd <= DpcStack) &&
208 ((ULONG_PTR)RegistrationFrame >= DpcStack - KERNEL_STACK_SIZE))
209 {
210 /* Update the limits to the DPC Stack's */
211 *StackHigh = DpcStack;
212 *StackLow = DpcStack - KERNEL_STACK_SIZE;
213 return TRUE;
214 }
215 }
216
217 /* Not in DPC stack */
218 return FALSE;
219 }
220
221 #ifndef _ARM_
222
223 BOOLEAN
224 NTAPI
225 RtlpCaptureStackLimits(IN ULONG_PTR Ebp,
226 IN ULONG_PTR *StackBegin,
227 IN ULONG_PTR *StackEnd)
228 {
229 PKTHREAD Thread = KeGetCurrentThread();
230
231 /* Don't even try at ISR level or later */
232 if (KeGetCurrentIrql() > DISPATCH_LEVEL) return FALSE;
233
234 /* Start with defaults */
235 *StackBegin = Thread->StackLimit;
236 *StackEnd = (ULONG_PTR)Thread->StackBase;
237
238 /* Check if EBP is inside the stack */
239 if ((*StackBegin <= Ebp) && (Ebp <= *StackEnd))
240 {
241 /* Then make the stack start at EBP */
242 *StackBegin = Ebp;
243 }
244 else
245 {
246 /* Now we're going to assume we're on the DPC stack */
247 *StackEnd = (ULONG_PTR)(KeGetPcr()->Prcb->DpcStack);
248 *StackBegin = *StackEnd - KERNEL_STACK_SIZE;
249
250 /* Check if we seem to be on the DPC stack */
251 if ((*StackEnd) && (*StackBegin < Ebp) && (Ebp <= *StackEnd))
252 {
253 /* We're on the DPC stack */
254 *StackBegin = Ebp;
255 }
256 else
257 {
258 /* We're somewhere else entirely... use EBP for safety */
259 *StackBegin = Ebp;
260 *StackEnd = (ULONG_PTR)PAGE_ALIGN(*StackBegin);
261 }
262 }
263
264 /* Return success */
265 return TRUE;
266 }
267
268 /*
269 * @implemented
270 */
271 ULONG
272 NTAPI
273 RtlWalkFrameChain(OUT PVOID *Callers,
274 IN ULONG Count,
275 IN ULONG Flags)
276 {
277 ULONG_PTR Stack, NewStack, StackBegin, StackEnd = 0;
278 ULONG Eip;
279 BOOLEAN Result, StopSearch = FALSE;
280 ULONG i = 0;
281 PKTHREAD Thread = KeGetCurrentThread();
282 PTEB Teb;
283 PKTRAP_FRAME TrapFrame;
284
285 /* Get current EBP */
286 #if defined(_M_IX86)
287 #if defined __GNUC__
288 __asm__("mov %%ebp, %0" : "=r" (Stack) : );
289 #elif defined(_MSC_VER)
290 __asm mov Stack, ebp
291 #endif
292 #elif defined(_M_MIPS)
293 __asm__("move $sp, %0" : "=r" (Stack) : );
294 #elif defined(_M_PPC)
295 __asm__("mr %0,1" : "=r" (Stack) : );
296 #elif defined(_M_ARM)
297 __asm__("mov sp, %0" : "=r"(Stack) : );
298 #else
299 #error Unknown architecture
300 #endif
301
302 /* Set it as the stack begin limit as well */
303 StackBegin = (ULONG_PTR)Stack;
304
305 /* Check if we're called for non-logging mode */
306 if (!Flags)
307 {
308 /* Get the actual safe limits */
309 Result = RtlpCaptureStackLimits((ULONG_PTR)Stack,
310 &StackBegin,
311 &StackEnd);
312 if (!Result) return 0;
313 }
314
315 /* Use a SEH block for maximum protection */
316 _SEH2_TRY
317 {
318 /* Check if we want the user-mode stack frame */
319 if (Flags == 1)
320 {
321 /* Get the trap frame and TEB */
322 TrapFrame = Thread->TrapFrame;
323 Teb = Thread->Teb;
324
325 /* Make sure we can trust the TEB and trap frame */
326 if (!(Teb) ||
327 !((PVOID)((ULONG_PTR)TrapFrame & 0x80000000)) ||
328 ((PVOID)TrapFrame <= (PVOID)Thread->StackLimit) ||
329 ((PVOID)TrapFrame >= (PVOID)Thread->StackBase) ||
330 (KeIsAttachedProcess()) ||
331 (KeGetCurrentIrql() >= DISPATCH_LEVEL))
332 {
333 /* Invalid or unsafe attempt to get the stack */
334 return 0;
335 }
336
337 /* Get the stack limits */
338 StackBegin = (ULONG_PTR)Teb->Tib.StackLimit;
339 StackEnd = (ULONG_PTR)Teb->Tib.StackBase;
340 #ifdef _M_IX86
341 Stack = TrapFrame->Ebp;
342 #elif defined(_M_PPC)
343 Stack = TrapFrame->Gpr1;
344 #else
345 #error Unknown architecture
346 #endif
347
348 /* Validate them */
349 if (StackEnd <= StackBegin) return 0;
350 ProbeForRead((PVOID)StackBegin,
351 StackEnd - StackBegin,
352 sizeof(CHAR));
353 }
354
355 /* Loop the frames */
356 for (i = 0; i < Count; i++)
357 {
358 /*
359 * Leave if we're past the stack,
360 * if we're before the stack,
361 * or if we've reached ourselves.
362 */
363 if ((Stack >= StackEnd) ||
364 (!i ? (Stack < StackBegin) : (Stack <= StackBegin)) ||
365 ((StackEnd - Stack) < (2 * sizeof(ULONG_PTR))))
366 {
367 /* We're done or hit a bad address */
368 break;
369 }
370
371 /* Get new stack and EIP */
372 NewStack = *(PULONG_PTR)Stack;
373 Eip = *(PULONG_PTR)(Stack + sizeof(ULONG_PTR));
374
375 /* Check if the new pointer is above the oldone and past the end */
376 if (!((Stack < NewStack) && (NewStack < StackEnd)))
377 {
378 /* Stop searching after this entry */
379 StopSearch = TRUE;
380 }
381
382 /* Also make sure that the EIP isn't a stack address */
383 if ((StackBegin < Eip) && (Eip < StackEnd)) break;
384
385 /* Check if we reached a user-mode address */
386 if (!(Flags) && !(Eip & 0x80000000)) break;
387
388 /* Save this frame */
389 Callers[i] = (PVOID)Eip;
390
391 /* Check if we should continue */
392 if (StopSearch)
393 {
394 /* Return the next index */
395 i++;
396 break;
397 }
398
399 /* Move to the next stack */
400 Stack = NewStack;
401 }
402 }
403 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
404 {
405 /* No index */
406 i = 0;
407 }
408 _SEH2_END;
409
410 /* Return frames parsed */
411 return i;
412 }
413
414 #endif
415
416 /* RTL Atom Tables ************************************************************/
417
418 NTSTATUS
419 RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable)
420 {
421 ExInitializeFastMutex(&AtomTable->FastMutex);
422
423 return STATUS_SUCCESS;
424 }
425
426
427 VOID
428 RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable)
429 {
430 }
431
432
433 BOOLEAN
434 RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable)
435 {
436 ExAcquireFastMutex(&AtomTable->FastMutex);
437 return TRUE;
438 }
439
440 VOID
441 RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable)
442 {
443 ExReleaseFastMutex(&AtomTable->FastMutex);
444 }
445
446 BOOLEAN
447 RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
448 {
449 AtomTable->ExHandleTable = ExCreateHandleTable(NULL);
450 return (AtomTable->ExHandleTable != NULL);
451 }
452
453 VOID
454 RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
455 {
456 if (AtomTable->ExHandleTable)
457 {
458 ExSweepHandleTable(AtomTable->ExHandleTable,
459 NULL,
460 NULL);
461 ExDestroyHandleTable(AtomTable->ExHandleTable, NULL);
462 AtomTable->ExHandleTable = NULL;
463 }
464 }
465
466 PRTL_ATOM_TABLE
467 RtlpAllocAtomTable(ULONG Size)
468 {
469 PRTL_ATOM_TABLE Table = ExAllocatePool(NonPagedPool,
470 Size);
471 if (Table != NULL)
472 {
473 RtlZeroMemory(Table,
474 Size);
475 }
476
477 return Table;
478 }
479
480 VOID
481 RtlpFreeAtomTable(PRTL_ATOM_TABLE AtomTable)
482 {
483 ExFreePool(AtomTable);
484 }
485
486 PRTL_ATOM_TABLE_ENTRY
487 RtlpAllocAtomTableEntry(ULONG Size)
488 {
489 PRTL_ATOM_TABLE_ENTRY Entry;
490
491 Entry = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_ATMT);
492 if (Entry != NULL)
493 {
494 RtlZeroMemory(Entry, Size);
495 }
496
497 return Entry;
498 }
499
500 VOID
501 RtlpFreeAtomTableEntry(PRTL_ATOM_TABLE_ENTRY Entry)
502 {
503 ExFreePoolWithTag(Entry, TAG_ATMT);
504 }
505
506 VOID
507 RtlpFreeAtomHandle(PRTL_ATOM_TABLE AtomTable, PRTL_ATOM_TABLE_ENTRY Entry)
508 {
509 ExDestroyHandle(AtomTable->ExHandleTable,
510 (HANDLE)((ULONG_PTR)Entry->HandleIndex << 2),
511 NULL);
512 }
513
514 BOOLEAN
515 RtlpCreateAtomHandle(PRTL_ATOM_TABLE AtomTable, PRTL_ATOM_TABLE_ENTRY Entry)
516 {
517 HANDLE_TABLE_ENTRY ExEntry;
518 HANDLE Handle;
519 USHORT HandleIndex;
520
521 /* Initialize ex handle table entry */
522 ExEntry.Object = Entry;
523 ExEntry.GrantedAccess = 0x1; /* FIXME - valid handle */
524
525 /* Create ex handle */
526 Handle = ExCreateHandle(AtomTable->ExHandleTable,
527 &ExEntry);
528 if (!Handle) return FALSE;
529
530 /* Calculate HandleIndex (by getting rid of the first two bits) */
531 HandleIndex = (USHORT)((ULONG_PTR)Handle >> 2);
532
533 /* Index must be less than 0xC000 */
534 if (HandleIndex >= 0xC000)
535 {
536 /* Destroy ex handle */
537 ExDestroyHandle(AtomTable->ExHandleTable,
538 Handle,
539 NULL);
540
541 /* Return failure */
542 return FALSE;
543 }
544
545 /* Initialize atom table entry */
546 Entry->HandleIndex = HandleIndex;
547 Entry->Atom = 0xC000 + HandleIndex;
548
549 /* Return success */
550 return TRUE;
551 }
552
553 PRTL_ATOM_TABLE_ENTRY
554 RtlpGetAtomEntry(PRTL_ATOM_TABLE AtomTable, ULONG Index)
555 {
556 PHANDLE_TABLE_ENTRY ExEntry;
557 PRTL_ATOM_TABLE_ENTRY Entry = NULL;
558
559 /* NOTE: There's no need to explicitly enter a critical region because it's
560 guaranteed that we're in a critical region right now (as we hold
561 the atom table lock) */
562
563 ExEntry = ExMapHandleToPointer(AtomTable->ExHandleTable,
564 (HANDLE)((ULONG_PTR)Index << 2));
565 if (ExEntry != NULL)
566 {
567 Entry = ExEntry->Object;
568
569 ExUnlockHandleTableEntry(AtomTable->ExHandleTable,
570 ExEntry);
571 }
572
573 return Entry;
574 }
575
576 /*
577 * Ldr Resource support code
578 */
579
580 IMAGE_RESOURCE_DIRECTORY *find_entry_by_name( IMAGE_RESOURCE_DIRECTORY *dir,
581 LPCWSTR name, void *root,
582 int want_dir );
583 IMAGE_RESOURCE_DIRECTORY *find_entry_by_id( IMAGE_RESOURCE_DIRECTORY *dir,
584 USHORT id, void *root, int want_dir );
585 IMAGE_RESOURCE_DIRECTORY *find_first_entry( IMAGE_RESOURCE_DIRECTORY *dir,
586 void *root, int want_dir );
587
588 /**********************************************************************
589 * find_entry
590 *
591 * Find a resource entry
592 */
593 NTSTATUS find_entry( PVOID BaseAddress, LDR_RESOURCE_INFO *info,
594 ULONG level, void **ret, int want_dir )
595 {
596 ULONG size;
597 void *root;
598 IMAGE_RESOURCE_DIRECTORY *resdirptr;
599
600 root = RtlImageDirectoryEntryToData( BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_RESOURCE, &size );
601 if (!root) return STATUS_RESOURCE_DATA_NOT_FOUND;
602 resdirptr = root;
603
604 if (!level--) goto done;
605 if (!(*ret = find_entry_by_name( resdirptr, (LPCWSTR)info->Type, root, want_dir || level )))
606 return STATUS_RESOURCE_TYPE_NOT_FOUND;
607 if (!level--) return STATUS_SUCCESS;
608
609 resdirptr = *ret;
610 if (!(*ret = find_entry_by_name( resdirptr, (LPCWSTR)info->Name, root, want_dir || level )))
611 return STATUS_RESOURCE_NAME_NOT_FOUND;
612 if (!level--) return STATUS_SUCCESS;
613 if (level) return STATUS_INVALID_PARAMETER; /* level > 3 */
614
615 resdirptr = *ret;
616
617 if ((*ret = find_first_entry( resdirptr, root, want_dir ))) return STATUS_SUCCESS;
618
619 return STATUS_RESOURCE_DATA_NOT_FOUND;
620
621 done:
622 *ret = resdirptr;
623 return STATUS_SUCCESS;
624 }
625
626
627 /* EOF */