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