[NTOS:MM] Assert MmLocateMemoryAreaByAddress return value to satisfy Coverity. CID...
[reactos.git] / ntoskrnl / kd64 / kdinit.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/kd64/kdinit.c
5 * PURPOSE: KD64 Initialization Code
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Stefan Ginsberg (stefan.ginsberg@reactos.org)
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #include <reactos/buildno.h>
14 #define NDEBUG
15 #include <debug.h>
16
17 /* UTILITY FUNCTIONS *********************************************************/
18
19 /*
20 * Get the total size of the memory before
21 * Mm is initialized, by counting the number
22 * of physical pages. Useful for debug logging.
23 *
24 * Strongly inspired by:
25 * mm\ARM3\mminit.c : MiScanMemoryDescriptors(...)
26 *
27 * See also: kd\kdio.c
28 */
29 static SIZE_T
30 INIT_FUNCTION
31 KdpGetMemorySizeInMBs(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
32 {
33 PLIST_ENTRY ListEntry;
34 PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
35 SIZE_T NumberOfPhysicalPages = 0;
36
37 /* Loop the memory descriptors */
38 for (ListEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
39 ListEntry != &LoaderBlock->MemoryDescriptorListHead;
40 ListEntry = ListEntry->Flink)
41 {
42 /* Get the descriptor */
43 Descriptor = CONTAINING_RECORD(ListEntry,
44 MEMORY_ALLOCATION_DESCRIPTOR,
45 ListEntry);
46
47 /* Check if this is invisible memory */
48 if ((Descriptor->MemoryType == LoaderFirmwarePermanent) ||
49 (Descriptor->MemoryType == LoaderSpecialMemory) ||
50 (Descriptor->MemoryType == LoaderHALCachedMemory) ||
51 (Descriptor->MemoryType == LoaderBBTMemory))
52 {
53 /* Skip this descriptor */
54 continue;
55 }
56
57 /* Check if this is bad memory */
58 if (Descriptor->MemoryType != LoaderBad)
59 {
60 /* Count this in the total of pages */
61 NumberOfPhysicalPages += Descriptor->PageCount;
62 }
63 }
64
65 return NumberOfPhysicalPages * PAGE_SIZE / 1024 / 1024;
66 }
67
68 /* See also: kd\kdio.c */
69 static VOID
70 INIT_FUNCTION
71 KdpPrintBanner(IN SIZE_T MemSizeMBs)
72 {
73 DPRINT1("-----------------------------------------------------\n");
74 DPRINT1("ReactOS " KERNEL_VERSION_STR " (Build " KERNEL_VERSION_BUILD_STR ") (Commit " KERNEL_VERSION_COMMIT_HASH ")\n");
75 DPRINT1("%u System Processor [%u MB Memory]\n", KeNumberProcessors, MemSizeMBs);
76
77 if (KeLoaderBlock)
78 {
79 DPRINT1("Command Line: %s\n", KeLoaderBlock->LoadOptions);
80 DPRINT1("ARC Paths: %s %s %s %s\n", KeLoaderBlock->ArcBootDeviceName, KeLoaderBlock->NtHalPathName, KeLoaderBlock->ArcHalDeviceName, KeLoaderBlock->NtBootPathName);
81 }
82 }
83
84 /* FUNCTIONS *****************************************************************/
85
86 VOID
87 NTAPI
88 KdUpdateDataBlock(VOID)
89 {
90 /* Update the KeUserCallbackDispatcher pointer */
91 KdDebuggerDataBlock.KeUserCallbackDispatcher =
92 (ULONG_PTR)KeUserCallbackDispatcher;
93 }
94
95 BOOLEAN
96 NTAPI
97 KdRegisterDebuggerDataBlock(IN ULONG Tag,
98 IN PDBGKD_DEBUG_DATA_HEADER64 DataHeader,
99 IN ULONG Size)
100 {
101 KIRQL OldIrql;
102 PLIST_ENTRY NextEntry;
103 PDBGKD_DEBUG_DATA_HEADER64 CurrentHeader;
104
105 /* Acquire the Data Lock */
106 KeAcquireSpinLock(&KdpDataSpinLock, &OldIrql);
107
108 /* Loop the debugger data list */
109 NextEntry = KdpDebuggerDataListHead.Flink;
110 while (NextEntry != &KdpDebuggerDataListHead)
111 {
112 /* Get the header for this entry */
113 CurrentHeader = CONTAINING_RECORD(NextEntry,
114 DBGKD_DEBUG_DATA_HEADER64,
115 List);
116
117 /* Move to the next one */
118 NextEntry = NextEntry->Flink;
119
120 /* Check if we already have this data block */
121 if ((CurrentHeader == DataHeader) || (CurrentHeader->OwnerTag == Tag))
122 {
123 /* Release the lock and fail */
124 KeReleaseSpinLock(&KdpDataSpinLock, OldIrql);
125 return FALSE;
126 }
127 }
128
129 /* Setup the header */
130 DataHeader->OwnerTag = Tag;
131 DataHeader->Size = Size;
132
133 /* Insert it into the list and release the lock */
134 InsertTailList(&KdpDebuggerDataListHead, (PLIST_ENTRY)&DataHeader->List);
135 KeReleaseSpinLock(&KdpDataSpinLock, OldIrql);
136 return TRUE;
137 }
138
139 BOOLEAN
140 NTAPI
141 KdInitSystem(IN ULONG BootPhase,
142 IN PLOADER_PARAMETER_BLOCK LoaderBlock)
143 {
144 BOOLEAN EnableKd, DisableKdAfterInit = FALSE, BlockEnable;
145 LPSTR CommandLine, DebugLine, DebugOptionStart, DebugOptionEnd;
146 STRING ImageName;
147 PLDR_DATA_TABLE_ENTRY LdrEntry;
148 PLIST_ENTRY NextEntry;
149 ULONG i, j, Length;
150 SIZE_T DebugOptionLength;
151 SIZE_T MemSizeMBs;
152 CHAR NameBuffer[256];
153 PWCHAR Name;
154
155 #if defined(__GNUC__)
156 /* Make gcc happy */
157 BlockEnable = FALSE;
158 #endif
159
160 /* Check if this is Phase 1 */
161 if (BootPhase)
162 {
163 /* Just query the performance counter */
164 KeQueryPerformanceCounter(&KdPerformanceCounterRate);
165 return TRUE;
166 }
167
168 /* Check if we already initialized once */
169 if (KdDebuggerEnabled) return TRUE;
170
171 /* Set the Debug Routine as the Stub for now */
172 KiDebugRoutine = KdpStub;
173
174 /* Disable break after symbol load for now */
175 KdBreakAfterSymbolLoad = FALSE;
176
177 /* Check if the Debugger Data Block was already initialized */
178 if (!KdpDebuggerDataListHead.Flink)
179 {
180 /* It wasn't...Initialize the KD Data Listhead */
181 InitializeListHead(&KdpDebuggerDataListHead);
182
183 /* Register the Debugger Data Block */
184 KdRegisterDebuggerDataBlock(KDBG_TAG,
185 &KdDebuggerDataBlock.Header,
186 sizeof(KdDebuggerDataBlock));
187
188 /* Fill out the KD Version Block */
189 KdVersionBlock.MajorVersion = (USHORT)((DBGKD_MAJOR_NT << 8) | (NtBuildNumber >> 28));
190 KdVersionBlock.MinorVersion = (USHORT)(NtBuildNumber & 0xFFFF);
191
192 #ifdef CONFIG_SMP
193 /* This is an MP Build */
194 KdVersionBlock.Flags |= DBGKD_VERS_FLAG_MP;
195 #endif
196
197 /* Save Pointers to Loaded Module List and Debugger Data */
198 KdVersionBlock.PsLoadedModuleList = (ULONG64)(LONG_PTR)&PsLoadedModuleList;
199 KdVersionBlock.DebuggerDataList = (ULONG64)(LONG_PTR)&KdpDebuggerDataListHead;
200
201 /* Set protocol limits */
202 KdVersionBlock.MaxStateChange = DbgKdMaximumStateChange -
203 DbgKdMinimumStateChange;
204 KdVersionBlock.MaxManipulate = DbgKdMaximumManipulate -
205 DbgKdMinimumManipulate;
206 KdVersionBlock.Unused[0] = 0;
207
208 /* Link us in the KPCR */
209 KeGetPcr()->KdVersionBlock = &KdVersionBlock;
210 }
211
212 /* Check if we have a loader block */
213 if (LoaderBlock)
214 {
215 /* Get the image entry */
216 LdrEntry = CONTAINING_RECORD(LoaderBlock->LoadOrderListHead.Flink,
217 LDR_DATA_TABLE_ENTRY,
218 InLoadOrderLinks);
219
220 /* Save the Kernel Base */
221 PsNtosImageBase = (ULONG_PTR)LdrEntry->DllBase;
222 KdVersionBlock.KernBase = (ULONG64)(LONG_PTR)LdrEntry->DllBase;
223
224 /* Check if we have a command line */
225 CommandLine = LoaderBlock->LoadOptions;
226 if (CommandLine)
227 {
228 /* Upcase it */
229 _strupr(CommandLine);
230
231 /* Assume we'll disable KD */
232 EnableKd = FALSE;
233
234 /* Check for CRASHDEBUG, NODEBUG and just DEBUG */
235 if (strstr(CommandLine, "CRASHDEBUG"))
236 {
237 /* Don't enable KD now, but allow it to be enabled later */
238 KdPitchDebugger = FALSE;
239 }
240 else if (strstr(CommandLine, "NODEBUG"))
241 {
242 /* Don't enable KD and don't let it be enabled later */
243 KdPitchDebugger = TRUE;
244 }
245 else if ((DebugLine = strstr(CommandLine, "DEBUG")) != NULL)
246 {
247 /* Enable KD */
248 EnableKd = TRUE;
249
250 /* Check if there are any options */
251 if (DebugLine[5] == '=')
252 {
253 /* Save pointers */
254 DebugOptionStart = DebugOptionEnd = &DebugLine[6];
255
256 /* Scan the string for debug options */
257 for (;;)
258 {
259 /* Loop until we reach the end of the string */
260 while (*DebugOptionEnd != ANSI_NULL)
261 {
262 /* Check if this is a comma, a space or a tab */
263 if ((*DebugOptionEnd == ',') ||
264 (*DebugOptionEnd == ' ') ||
265 (*DebugOptionEnd == '\t'))
266 {
267 /*
268 * We reached the end of the option or
269 * the end of the string, break out
270 */
271 break;
272 }
273 else
274 {
275 /* Move on to the next character */
276 DebugOptionEnd++;
277 }
278 }
279
280 /* Calculate the length of the current option */
281 DebugOptionLength = (DebugOptionEnd - DebugOptionStart);
282
283 /*
284 * Break out if we reached the last option
285 * or if there were no options at all
286 */
287 if (!DebugOptionLength) break;
288
289 /* Now check which option this is */
290 if ((DebugOptionLength == 10) &&
291 !(strncmp(DebugOptionStart, "AUTOENABLE", 10)))
292 {
293 /*
294 * Disable the debugger, but
295 * allow it to be reenabled
296 */
297 DisableKdAfterInit = TRUE;
298 BlockEnable = FALSE;
299 KdAutoEnableOnEvent = TRUE;
300 }
301 else if ((DebugOptionLength == 7) &&
302 !(strncmp(DebugOptionStart, "DISABLE", 7)))
303 {
304 /* Disable the debugger */
305 DisableKdAfterInit = TRUE;
306 BlockEnable = TRUE;
307 KdAutoEnableOnEvent = FALSE;
308 }
309 else if ((DebugOptionLength == 6) &&
310 !(strncmp(DebugOptionStart, "NOUMEX", 6)))
311 {
312 /* Ignore user mode exceptions */
313 KdIgnoreUmExceptions = TRUE;
314 }
315
316 /*
317 * If there are more options then
318 * the next character should be a comma
319 */
320 if (*DebugOptionEnd != ',')
321 {
322 /* It isn't, break out */
323 break;
324 }
325
326 /* Move on to the next option */
327 DebugOptionEnd++;
328 DebugOptionStart = DebugOptionEnd;
329 }
330 }
331 }
332 }
333 else
334 {
335 /* No command line options? Disable debugger by default */
336 KdPitchDebugger = TRUE;
337 EnableKd = FALSE;
338 }
339 }
340 else
341 {
342 /* Called from a bugcheck or a re-enable. Save the Kernel Base */
343 KdVersionBlock.KernBase = (ULONG64)(LONG_PTR)PsNtosImageBase;
344
345 /* Unconditionally enable KD */
346 EnableKd = TRUE;
347 }
348
349 /* Set the Kernel Base in the Data Block */
350 KdDebuggerDataBlock.KernBase = (ULONG_PTR)KdVersionBlock.KernBase;
351
352 /* Initialize the debugger if requested */
353 if (EnableKd && (NT_SUCCESS(KdDebuggerInitialize0(LoaderBlock))))
354 {
355 /* Now set our real KD routine */
356 KiDebugRoutine = KdpTrap;
357
358 /* Check if we've already initialized our structures */
359 if (!KdpDebuggerStructuresInitialized)
360 {
361 /* Set the Debug Switch Routine and Retries */
362 KdpContext.KdpDefaultRetries = 20;
363 KiDebugSwitchRoutine = KdpSwitchProcessor;
364
365 /* Initialize breakpoints owed flag and table */
366 KdpOweBreakpoint = FALSE;
367 for (i = 0; i < KD_BREAKPOINT_MAX; i++)
368 {
369 KdpBreakpointTable[i].Flags = 0;
370 KdpBreakpointTable[i].DirectoryTableBase = 0;
371 KdpBreakpointTable[i].Address = NULL;
372 }
373
374 /* Initialize the Time Slip DPC */
375 KeInitializeDpc(&KdpTimeSlipDpc, KdpTimeSlipDpcRoutine, NULL);
376 KeInitializeTimer(&KdpTimeSlipTimer);
377 ExInitializeWorkItem(&KdpTimeSlipWorkItem, KdpTimeSlipWork, NULL);
378
379 /* First-time initialization done! */
380 KdpDebuggerStructuresInitialized = TRUE;
381 }
382
383 /* Initialize the timer */
384 KdTimerStart.QuadPart = 0;
385
386 /* Officially enable KD */
387 KdPitchDebugger = FALSE;
388 KdDebuggerEnabled = TRUE;
389
390 /* Let user-mode know that it's enabled as well */
391 SharedUserData->KdDebuggerEnabled = TRUE;
392
393 /* Display separator + ReactOS version at start of the debug log */
394 MemSizeMBs = KdpGetMemorySizeInMBs(KeLoaderBlock);
395 KdpPrintBanner(MemSizeMBs);
396
397 /* Check if the debugger should be disabled initially */
398 if (DisableKdAfterInit)
399 {
400 /* Disable it */
401 KdDisableDebuggerWithLock(FALSE);
402
403 /*
404 * Save the enable block state and return initialized
405 * (the debugger is active but disabled).
406 */
407 KdBlockEnable = BlockEnable;
408 return TRUE;
409 }
410
411 /* Check if we have a loader block */
412 if (LoaderBlock)
413 {
414 /* Loop boot images */
415 NextEntry = LoaderBlock->LoadOrderListHead.Flink;
416 i = 0;
417 while ((NextEntry != &LoaderBlock->LoadOrderListHead) && (i < 2))
418 {
419 /* Get the image entry */
420 LdrEntry = CONTAINING_RECORD(NextEntry,
421 LDR_DATA_TABLE_ENTRY,
422 InLoadOrderLinks);
423
424 /* Generate the image name */
425 Name = LdrEntry->FullDllName.Buffer;
426 Length = LdrEntry->FullDllName.Length / sizeof(WCHAR);
427 j = 0;
428 do
429 {
430 /* Do cheap Unicode to ANSI conversion */
431 NameBuffer[j++] = (CHAR)*Name++;
432 } while (j < Length);
433
434 /* Null-terminate */
435 NameBuffer[j] = ANSI_NULL;
436
437 /* Load symbols for image */
438 RtlInitString(&ImageName, NameBuffer);
439 DbgLoadImageSymbols(&ImageName,
440 LdrEntry->DllBase,
441 (ULONG_PTR)PsGetCurrentProcessId());
442
443 /* Go to the next entry */
444 NextEntry = NextEntry->Flink;
445 i++;
446 }
447 }
448
449 /* Check for incoming breakin and break on symbol load if we have it */
450 KdBreakAfterSymbolLoad = KdPollBreakIn();
451 }
452 else
453 {
454 /* Disable debugger */
455 KdDebuggerNotPresent = TRUE;
456 }
457
458 /* Return initialized */
459 return TRUE;
460 }