--- /dev/null
+/*
+ * PROJECT: ReactOS Kernel
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: ntoskrnl/kd64/kdinit.c
+ * PURPOSE: KD64 Initialization Code
+ * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
+ * Stefan Ginsberg (stefan.ginsberg@reactos.org)
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include <ntoskrnl.h>
+#include <reactos/buildno.h>
+#define NDEBUG
+#include <debug.h>
+
+/* UTILITY FUNCTIONS *********************************************************/
+
+/*
+ * Get the total size of the memory before
+ * Mm is initialized, by counting the number
+ * of physical pages. Useful for debug logging.
+ *
+ * Strongly inspired by:
+ * mm\ARM3\mminit.c : MiScanMemoryDescriptors(...)
+ *
+ * See also: kd\kdio.c
+ */
+static SIZE_T
+INIT_FUNCTION
+KdpGetMemorySizeInMBs(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
+{
+ PLIST_ENTRY ListEntry;
+ PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
+ SIZE_T NumberOfPhysicalPages = 0;
+
+ /* Loop the memory descriptors */
+ for (ListEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
+ ListEntry != &LoaderBlock->MemoryDescriptorListHead;
+ ListEntry = ListEntry->Flink)
+ {
+ /* Get the descriptor */
+ Descriptor = CONTAINING_RECORD(ListEntry,
+ MEMORY_ALLOCATION_DESCRIPTOR,
+ ListEntry);
+
+ /* Check if this is invisible memory */
+ if ((Descriptor->MemoryType == LoaderFirmwarePermanent) ||
+ (Descriptor->MemoryType == LoaderSpecialMemory) ||
+ (Descriptor->MemoryType == LoaderHALCachedMemory) ||
+ (Descriptor->MemoryType == LoaderBBTMemory))
+ {
+ /* Skip this descriptor */
+ continue;
+ }
+
+ /* Check if this is bad memory */
+ if (Descriptor->MemoryType != LoaderBad)
+ {
+ /* Count this in the total of pages */
+ NumberOfPhysicalPages += Descriptor->PageCount;
+ }
+ }
+
+ return NumberOfPhysicalPages * PAGE_SIZE / 1024 / 1024;
+}
+
+/* FUNCTIONS *****************************************************************/
+
+VOID
+NTAPI
+KdUpdateDataBlock(VOID)
+{
+ /* Update the KeUserCallbackDispatcher pointer */
+ KdDebuggerDataBlock.KeUserCallbackDispatcher =
+ (ULONG_PTR)KeUserCallbackDispatcher;
+}
+
+BOOLEAN
+NTAPI
+KdRegisterDebuggerDataBlock(IN ULONG Tag,
+ IN PDBGKD_DEBUG_DATA_HEADER64 DataHeader,
+ IN ULONG Size)
+{
+ KIRQL OldIrql;
+ PLIST_ENTRY NextEntry;
+ PDBGKD_DEBUG_DATA_HEADER64 CurrentHeader;
+
+ /* Acquire the Data Lock */
+ KeAcquireSpinLock(&KdpDataSpinLock, &OldIrql);
+
+ /* Loop the debugger data list */
+ NextEntry = KdpDebuggerDataListHead.Flink;
+ while (NextEntry != &KdpDebuggerDataListHead)
+ {
+ /* Get the header for this entry */
+ CurrentHeader = CONTAINING_RECORD(NextEntry,
+ DBGKD_DEBUG_DATA_HEADER64,
+ List);
+
+ /* Move to the next one */
+ NextEntry = NextEntry->Flink;
+
+ /* Check if we already have this data block */
+ if ((CurrentHeader == DataHeader) || (CurrentHeader->OwnerTag == Tag))
+ {
+ /* Release the lock and fail */
+ KeReleaseSpinLock(&KdpDataSpinLock, OldIrql);
+ return FALSE;
+ }
+ }
+
+ /* Setup the header */
+ DataHeader->OwnerTag = Tag;
+ DataHeader->Size = Size;
+
+ /* Insert it into the list and release the lock */
+ InsertTailList(&KdpDebuggerDataListHead, (PLIST_ENTRY)&DataHeader->List);
+ KeReleaseSpinLock(&KdpDataSpinLock, OldIrql);
+ return TRUE;
+}
+
+BOOLEAN
+NTAPI
+KdInitSystem(IN ULONG BootPhase,
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock)
+{
+ BOOLEAN EnableKd, DisableKdAfterInit = FALSE, BlockEnable;
+ LPSTR CommandLine, DebugLine, DebugOptionStart, DebugOptionEnd;
+ STRING ImageName;
+ PLDR_DATA_TABLE_ENTRY LdrEntry;
+ PLIST_ENTRY NextEntry;
+ ULONG i, j, Length;
+ SIZE_T DebugOptionLength;
+ SIZE_T MemSizeMBs;
+ CHAR NameBuffer[256];
+ PWCHAR Name;
+
+#if defined(__GNUC__)
+ /* Make gcc happy */
+ BlockEnable = FALSE;
+#endif
+
+ /* Check if this is Phase 1 */
+ if (BootPhase)
+ {
+ /* Just query the performance counter */
+ KeQueryPerformanceCounter(&KdPerformanceCounterRate);
+ return TRUE;
+ }
+
+ /* Check if we already initialized once */
+ if (KdDebuggerEnabled) return TRUE;
+
+ /* Set the Debug Routine as the Stub for now */
+ KiDebugRoutine = KdpStub;
+
+ /* Disable break after symbol load for now */
+ KdBreakAfterSymbolLoad = FALSE;
+
+ /* Check if the Debugger Data Block was already initialized */
+ if (!KdpDebuggerDataListHead.Flink)
+ {
+ /* It wasn't...Initialize the KD Data Listhead */
+ InitializeListHead(&KdpDebuggerDataListHead);
+
+ /* Register the Debugger Data Block */
+ KdRegisterDebuggerDataBlock(KDBG_TAG,
+ &KdDebuggerDataBlock.Header,
+ sizeof(KdDebuggerDataBlock));
+
+ /* Fill out the KD Version Block */
+ KdVersionBlock.MajorVersion = (USHORT)((DBGKD_MAJOR_NT << 8) | (NtBuildNumber >> 28));
+ KdVersionBlock.MinorVersion = (USHORT)(NtBuildNumber & 0xFFFF);
+
+#ifdef CONFIG_SMP
+ /* This is an MP Build */
+ KdVersionBlock.Flags |= DBGKD_VERS_FLAG_MP;
+#endif
+
+ /* Save Pointers to Loaded Module List and Debugger Data */
+ KdVersionBlock.PsLoadedModuleList = (ULONG64)(LONG_PTR)&PsLoadedModuleList;
+ KdVersionBlock.DebuggerDataList = (ULONG64)(LONG_PTR)&KdpDebuggerDataListHead;
+
+ /* Set protocol limits */
+ KdVersionBlock.MaxStateChange = DbgKdMaximumStateChange -
+ DbgKdMinimumStateChange;
+ KdVersionBlock.MaxManipulate = DbgKdMaximumManipulate -
+ DbgKdMinimumManipulate;
+ KdVersionBlock.Unused[0] = 0;
+
+ /* Link us in the KPCR */
+ KeGetPcr()->KdVersionBlock = &KdVersionBlock;
+ }
+
+ /* Check if we have a loader block */
+ if (LoaderBlock)
+ {
+ /* Get the image entry */
+ LdrEntry = CONTAINING_RECORD(LoaderBlock->LoadOrderListHead.Flink,
+ LDR_DATA_TABLE_ENTRY,
+ InLoadOrderLinks);
+
+ /* Save the Kernel Base */
+ PsNtosImageBase = (ULONG_PTR)LdrEntry->DllBase;
+ KdVersionBlock.KernBase = (ULONG64)(LONG_PTR)LdrEntry->DllBase;
+
+ /* Check if we have a command line */
+ CommandLine = LoaderBlock->LoadOptions;
+ if (CommandLine)
+ {
+ /* Upcase it */
+ _strupr(CommandLine);
+
+ /* Assume we'll disable KD */
+ EnableKd = FALSE;
+
+ /* Check for CRASHDEBUG, NODEBUG and just DEBUG */
+ if (strstr(CommandLine, "CRASHDEBUG"))
+ {
+ /* Don't enable KD now, but allow it to be enabled later */
+ KdPitchDebugger = FALSE;
+ }
+ else if (strstr(CommandLine, "NODEBUG"))
+ {
+ /* Don't enable KD and don't let it be enabled later */
+ KdPitchDebugger = TRUE;
+ }
+ else if ((DebugLine = strstr(CommandLine, "DEBUG")) != NULL)
+ {
+ /* Enable KD */
+ EnableKd = TRUE;
+
+ /* Check if there are any options */
+ if (DebugLine[5] == '=')
+ {
+ /* Save pointers */
+ DebugOptionStart = DebugOptionEnd = &DebugLine[6];
+
+ /* Scan the string for debug options */
+ for (;;)
+ {
+ /* Loop until we reach the end of the string */
+ while (*DebugOptionEnd != ANSI_NULL)
+ {
+ /* Check if this is a comma, a space or a tab */
+ if ((*DebugOptionEnd == ',') ||
+ (*DebugOptionEnd == ' ') ||
+ (*DebugOptionEnd == '\t'))
+ {
+ /*
+ * We reached the end of the option or
+ * the end of the string, break out
+ */
+ break;
+ }
+ else
+ {
+ /* Move on to the next character */
+ DebugOptionEnd++;
+ }
+ }
+
+ /* Calculate the length of the current option */
+ DebugOptionLength = (DebugOptionEnd - DebugOptionStart);
+
+ /*
+ * Break out if we reached the last option
+ * or if there were no options at all
+ */
+ if (!DebugOptionLength) break;
+
+ /* Now check which option this is */
+ if ((DebugOptionLength == 10) &&
+ !(strncmp(DebugOptionStart, "AUTOENABLE", 10)))
+ {
+ /*
+ * Disable the debugger, but
+ * allow it to be reenabled
+ */
+ DisableKdAfterInit = TRUE;
+ BlockEnable = FALSE;
+ KdAutoEnableOnEvent = TRUE;
+ }
+ else if ((DebugOptionLength == 7) &&
+ !(strncmp(DebugOptionStart, "DISABLE", 7)))
+ {
+ /* Disable the debugger */
+ DisableKdAfterInit = TRUE;
+ BlockEnable = TRUE;
+ KdAutoEnableOnEvent = FALSE;
+ }
+ else if ((DebugOptionLength == 6) &&
+ !(strncmp(DebugOptionStart, "NOUMEX", 6)))
+ {
+ /* Ignore user mode exceptions */
+ KdIgnoreUmExceptions = TRUE;
+ }
+
+ /*
+ * If there are more options then
+ * the next character should be a comma
+ */
+ if (*DebugOptionEnd != ',')
+ {
+ /* It isn't, break out */
+ break;
+ }
+
+ /* Move on to the next option */
+ DebugOptionEnd++;
+ DebugOptionStart = DebugOptionEnd;
+ }
+ }
+ }
+ }
+ else
+ {
+ /* No command line options? Disable debugger by default */
+ KdPitchDebugger = TRUE;
+ EnableKd = FALSE;
+ }
+ }
+ else
+ {
+ /* Called from a bugcheck or a re-enable. Save the Kernel Base */
+ KdVersionBlock.KernBase = (ULONG64)(LONG_PTR)PsNtosImageBase;
+
+ /* Unconditionally enable KD */
+ EnableKd = TRUE;
+ }
+
+ /* Set the Kernel Base in the Data Block */
+ KdDebuggerDataBlock.KernBase = (ULONG_PTR)KdVersionBlock.KernBase;
+
+ /* Initialize the debugger if requested */
+ if (EnableKd && (NT_SUCCESS(KdDebuggerInitialize0(LoaderBlock))))
+ {
+ /* Now set our real KD routine */
+ KiDebugRoutine = KdpTrap;
+
+ /* Check if we've already initialized our structures */
+ if (!KdpDebuggerStructuresInitialized)
+ {
+ /* Set the Debug Switch Routine and Retries */
+ KdpContext.KdpDefaultRetries = 20;
+ KiDebugSwitchRoutine = KdpSwitchProcessor;
+
+ /* Initialize breakpoints owed flag and table */
+ KdpOweBreakpoint = FALSE;
+ for (i = 0; i < KD_BREAKPOINT_MAX; i++)
+ {
+ KdpBreakpointTable[i].Flags = 0;
+ KdpBreakpointTable[i].DirectoryTableBase = 0;
+ KdpBreakpointTable[i].Address = NULL;
+ }
+
+ /* Initialize the Time Slip DPC */
+ KeInitializeDpc(&KdpTimeSlipDpc, KdpTimeSlipDpcRoutine, NULL);
+ KeInitializeTimer(&KdpTimeSlipTimer);
+ ExInitializeWorkItem(&KdpTimeSlipWorkItem, KdpTimeSlipWork, NULL);
+
+ /* First-time initialization done! */
+ KdpDebuggerStructuresInitialized = TRUE;
+ }
+
+ /* Initialize the timer */
+ KdTimerStart.QuadPart = 0;
+
+ /* Officially enable KD */
+ KdPitchDebugger = FALSE;
+ KdDebuggerEnabled = TRUE;
+
+ /* Let user-mode know that it's enabled as well */
+ SharedUserData->KdDebuggerEnabled = TRUE;
+
+ /* Display separator + ReactOS version at start of the debug log */
+ DPRINT1("-----------------------------------------------------\n");
+ DPRINT1("ReactOS "KERNEL_VERSION_STR" (Build "KERNEL_VERSION_BUILD_STR")\n");
+ MemSizeMBs = KdpGetMemorySizeInMBs(KeLoaderBlock);
+ DPRINT1("%u System Processor [%u MB Memory]\n", KeNumberProcessors, MemSizeMBs);
+ if (KeLoaderBlock)
+ {
+ DPRINT1("Command Line: %s\n", KeLoaderBlock->LoadOptions);
+ DPRINT1("ARC Paths: %s %s %s %s\n", KeLoaderBlock->ArcBootDeviceName,
+ KeLoaderBlock->NtHalPathName,
+ KeLoaderBlock->ArcHalDeviceName,
+ KeLoaderBlock->NtBootPathName);
+ }
+
+ /* Check if the debugger should be disabled initially */
+ if (DisableKdAfterInit)
+ {
+ /* Disable it */
+ KdDisableDebuggerWithLock(FALSE);
+
+ /*
+ * Save the enable block state and return initialized
+ * (the debugger is active but disabled).
+ */
+ KdBlockEnable = BlockEnable;
+ return TRUE;
+ }
+
+ /* Check if we have a loader block */
+ if (LoaderBlock)
+ {
+ /* Loop boot images */
+ NextEntry = LoaderBlock->LoadOrderListHead.Flink;
+ i = 0;
+ while ((NextEntry != &LoaderBlock->LoadOrderListHead) && (i < 2))
+ {
+ /* Get the image entry */
+ LdrEntry = CONTAINING_RECORD(NextEntry,
+ LDR_DATA_TABLE_ENTRY,
+ InLoadOrderLinks);
+
+ /* Generate the image name */
+ Name = LdrEntry->FullDllName.Buffer;
+ Length = LdrEntry->FullDllName.Length / sizeof(WCHAR);
+ j = 0;
+ do
+ {
+ /* Do cheap Unicode to ANSI conversion */
+ NameBuffer[j++] = (CHAR)*Name++;
+ } while (j < Length);
+
+ /* Null-terminate */
+ NameBuffer[j] = ANSI_NULL;
+
+ /* Load symbols for image */
+ RtlInitString(&ImageName, NameBuffer);
+ DbgLoadImageSymbols(&ImageName,
+ LdrEntry->DllBase,
+ (ULONG_PTR)PsGetCurrentProcessId());
+
+ /* Go to the next entry */
+ NextEntry = NextEntry->Flink;
+ i++;
+ }
+ }
+
+ /* Check for incoming breakin and break on symbol load if we have it */
+ KdBreakAfterSymbolLoad = KdPollBreakIn();
+ }
+ else
+ {
+ /* Disable debugger */
+ KdDebuggerNotPresent = TRUE;
+ }
+
+ /* Return initialized */
+ return TRUE;
+}