diff --git a/ntoskrnl/include/internal/kd.h b/ntoskrnl/include/internal/kd.h index 325e0b0ea3c..424ae89fe1f 100644 --- a/ntoskrnl/include/internal/kd.h +++ b/ntoskrnl/include/internal/kd.h @@ -39,7 +39,7 @@ typedef enum _KD_CONTINUE_TYPE } KD_CONTINUE_TYPE; typedef -VOID +NTSTATUS (NTAPI *PKDP_INIT_ROUTINE)( _In_ struct _KD_DISPATCH_TABLE *DispatchTable, _In_ ULONG BootPhase); @@ -70,19 +70,19 @@ KdpScreenAcquire(VOID); VOID KdpScreenRelease(VOID); -VOID +NTSTATUS NTAPI KdpScreenInit( _In_ struct _KD_DISPATCH_TABLE *DispatchTable, _In_ ULONG BootPhase); -VOID +NTSTATUS NTAPI KdpSerialInit( _In_ struct _KD_DISPATCH_TABLE *DispatchTable, _In_ ULONG BootPhase); -VOID +NTSTATUS NTAPI KdpDebugLogInit( _In_ struct _KD_DISPATCH_TABLE *DispatchTable, @@ -168,6 +168,7 @@ typedef struct _KD_DISPATCH_TABLE LIST_ENTRY KdProvidersList; PKDP_INIT_ROUTINE KdpInitRoutine; PKDP_PRINT_ROUTINE KdpPrintRoutine; + NTSTATUS InitStatus; } KD_DISPATCH_TABLE, *PKD_DISPATCH_TABLE; /* The current Debugging Mode */ diff --git a/ntoskrnl/io/iomgr/iomgr.c b/ntoskrnl/io/iomgr/iomgr.c index 380a8518661..b982414e270 100644 --- a/ntoskrnl/io/iomgr/iomgr.c +++ b/ntoskrnl/io/iomgr/iomgr.c @@ -588,14 +588,6 @@ IoInitSystem(IN PLOADER_PARAMETER_BLOCK LoaderBlock) * We can finally load other drivers from the boot volume. */ PnPBootDriversInitialized = TRUE; -#if !defined(_WINKD_) && defined(KDBG) - /* Read KDB Data */ - KdbpCliInit(); - - /* I/O is now setup for disk access, so phase 3 */ - KdInitSystem(3, LoaderBlock); -#endif - /* Load system start drivers */ IopInitializeSystemDrivers(); PnpSystemInit = TRUE; diff --git a/ntoskrnl/kd/kdio.c b/ntoskrnl/kd/kdio.c index 129db8b9b5e..4575b9a2e8b 100644 --- a/ntoskrnl/kd/kdio.c +++ b/ntoskrnl/kd/kdio.c @@ -19,7 +19,6 @@ #define KdpBufferSize (1024 * 512) static BOOLEAN KdpLoggingEnabled = FALSE; -static BOOLEAN KdpLoggingStarting = FALSE; static PCHAR KdpDebugBuffer = NULL; static volatile ULONG KdpCurrentPosition = 0; static volatile ULONG KdpFreeBytes = 0; @@ -39,14 +38,14 @@ static ULONG KdpScreenLineBufferPos = 0, KdpScreenLineLength = 0; KDP_DEBUG_MODE KdpDebugMode; LIST_ENTRY KdProviders = {&KdProviders, &KdProviders}; -KD_DISPATCH_TABLE DispatchTable[KdMax]; +KD_DISPATCH_TABLE DispatchTable[KdMax] = {0}; PKDP_INIT_ROUTINE InitRoutines[KdMax] = { KdpScreenInit, KdpSerialInit, KdpDebugLogInit, -#ifdef KDBG +#ifdef KDBG // See kdb_cli.c KdpKdbgInit #endif }; @@ -158,7 +157,6 @@ KdpPrintToLogFile(PCHAR String, { KIRQL OldIrql; ULONG beg, end, num; - BOOLEAN DoReinit = FALSE; if (KdpDebugBuffer == NULL) return; @@ -185,45 +183,31 @@ KdpPrintToLogFile(PCHAR String, } /* Release the spinlock */ - if (OldIrql == PASSIVE_LEVEL && !KdpLoggingStarting && !KdpLoggingEnabled && ExpInitializationPhase >= 2) - { - DoReinit = TRUE; - } KdbpReleaseLock(&KdpDebugLogSpinLock, OldIrql); - if (DoReinit) - { - KdpLoggingStarting = TRUE; - KdpDebugLogInit(NULL, 3); - } - /* Signal the logger thread */ if (OldIrql <= DISPATCH_LEVEL && KdpLoggingEnabled) KeSetEvent(&KdpLoggerThreadEvent, IO_NO_INCREMENT, FALSE); } -VOID +NTSTATUS NTAPI KdpDebugLogInit( _In_ PKD_DISPATCH_TABLE DispatchTable, _In_ ULONG BootPhase) { - NTSTATUS Status; - UNICODE_STRING FileName; - OBJECT_ATTRIBUTES ObjectAttributes; - IO_STATUS_BLOCK Iosb; - HANDLE ThreadHandle; - KPRIORITY Priority; + NTSTATUS Status = STATUS_SUCCESS; - if (!KdpDebugMode.File) return; + if (!KdpDebugMode.File) + return STATUS_PORT_DISCONNECTED; if (BootPhase == 0) { /* Write out the functions that we support for now */ - DispatchTable->KdpInitRoutine = KdpDebugLogInit; DispatchTable->KdpPrintRoutine = KdpPrintToLogFile; - /* Register as a Provider */ + /* Register for BootPhase 1 initialization and as a Provider */ + DispatchTable->KdpInitRoutine = KdpDebugLogInit; InsertTailList(&KdProviders, &DispatchTable->KdProvidersList); } else if (BootPhase == 1) @@ -235,20 +219,35 @@ KdpDebugLogInit( if (!KdpDebugBuffer) { KdpDebugMode.File = FALSE; - return; + RemoveEntryList(&DispatchTable->KdProvidersList); + return STATUS_NO_MEMORY; } KdpFreeBytes = KdpBufferSize; /* Initialize spinlock */ KeInitializeSpinLock(&KdpDebugLogSpinLock); + /* Register for later BootPhase 2 reinitialization */ + DispatchTable->KdpInitRoutine = KdpDebugLogInit; + HalDisplayString("\r\n File log debugging enabled\r\n\r\n"); } - else if (BootPhase == 3) + else if (BootPhase >= 2) { + UNICODE_STRING FileName; + OBJECT_ATTRIBUTES ObjectAttributes; + IO_STATUS_BLOCK Iosb; + HANDLE ThreadHandle; + KPRIORITY Priority; + + /* If we have already successfully opened the log file, bail out */ + if (KdpLogFileHandle != NULL) + return STATUS_SUCCESS; + /* Setup the log name */ Status = RtlAnsiStringToUnicodeString(&FileName, &KdpLogFileName, TRUE); - if (!NT_SUCCESS(Status)) return; + if (!NT_SUCCESS(Status)) + goto Failure; InitializeObjectAttributes(&ObjectAttributes, &FileName, @@ -274,8 +273,16 @@ KdpDebugLogInit( if (!NT_SUCCESS(Status)) { - DPRINT1("Failed to open log file: 0x%08x\n", Status); - return; + DPRINT1("Failed to open log file: 0x%08lx\n", Status); + + /* Schedule an I/O reinitialization if needed */ + if (Status == STATUS_OBJECT_NAME_NOT_FOUND || + Status == STATUS_OBJECT_PATH_NOT_FOUND) + { + DispatchTable->KdpInitRoutine = KdpDebugLogInit; + return Status; + } + goto Failure; } /** HACK for FILE_APPEND_DATA ** @@ -323,18 +330,29 @@ KdpDebugLogInit( NULL); if (!NT_SUCCESS(Status)) { + DPRINT1("Failed to create log file thread: 0x%08lx\n", Status); ZwClose(KdpLogFileHandle); - return; + goto Failure; } - Priority = 7; + Priority = HIGH_PRIORITY; ZwSetInformationThread(ThreadHandle, ThreadPriority, &Priority, sizeof(Priority)); ZwClose(ThreadHandle); + return Status; + +Failure: + KdpFreeBytes = 0; + ExFreePoolWithTag(KdpDebugBuffer, TAG_KDBG); + KdpDebugBuffer = NULL; + KdpDebugMode.File = FALSE; + RemoveEntryList(&DispatchTable->KdProvidersList); } + + return Status; } /* SERIAL FUNCTIONS **********************************************************/ @@ -365,38 +383,41 @@ KdpSerialPrint(PCHAR String, KdbpReleaseLock(&KdpSerialSpinLock, OldIrql); } -VOID +NTSTATUS NTAPI KdpSerialInit( _In_ PKD_DISPATCH_TABLE DispatchTable, _In_ ULONG BootPhase) { - if (!KdpDebugMode.Serial) return; + if (!KdpDebugMode.Serial) + return STATUS_PORT_DISCONNECTED; if (BootPhase == 0) { /* Write out the functions that we support for now */ - DispatchTable->KdpInitRoutine = KdpSerialInit; DispatchTable->KdpPrintRoutine = KdpSerialPrint; /* Initialize the Port */ if (!KdPortInitializeEx(&SerialPortInfo, SerialPortNumber)) { KdpDebugMode.Serial = FALSE; - return; + return STATUS_DEVICE_DOES_NOT_EXIST; } KdComPortInUse = SerialPortInfo.Address; /* Initialize spinlock */ KeInitializeSpinLock(&KdpSerialSpinLock); - /* Register as a Provider */ + /* Register for BootPhase 1 initialization and as a Provider */ + DispatchTable->KdpInitRoutine = KdpSerialInit; InsertTailList(&KdProviders, &DispatchTable->KdProvidersList); } else if (BootPhase == 1) { HalDisplayString("\r\n Serial debugging enabled\r\n\r\n"); } + + return STATUS_SUCCESS; } /* SCREEN FUNCTIONS **********************************************************/ @@ -483,21 +504,22 @@ KdpScreenPrint(PCHAR String, } } -VOID +NTSTATUS NTAPI KdpScreenInit( _In_ PKD_DISPATCH_TABLE DispatchTable, _In_ ULONG BootPhase) { - if (!KdpDebugMode.Screen) return; + if (!KdpDebugMode.Screen) + return STATUS_PORT_DISCONNECTED; if (BootPhase == 0) { /* Write out the functions that we support for now */ - DispatchTable->KdpInitRoutine = KdpScreenInit; DispatchTable->KdpPrintRoutine = KdpScreenPrint; - /* Register as a Provider */ + /* Register for BootPhase 1 initialization and as a Provider */ + DispatchTable->KdpInitRoutine = KdpScreenInit; InsertTailList(&KdProviders, &DispatchTable->KdProvidersList); } else if (BootPhase == 1) @@ -507,16 +529,13 @@ KdpScreenInit( HalDisplayString("\r\n Screen debugging enabled\r\n\r\n"); } + + return STATUS_SUCCESS; } /* GENERAL FUNCTIONS *********************************************************/ -BOOLEAN -NTAPI -KdpPrintString( - _In_ PSTRING Output); - extern STRING KdbPromptString; VOID @@ -551,20 +570,16 @@ KdSendPacket( if (!KdpDebugMode.Value) return; - /* Call the registered handlers */ - CurrentEntry = KdProviders.Flink; - while (CurrentEntry != &KdProviders) + /* Call the registered providers */ + for (CurrentEntry = KdProviders.Flink; + CurrentEntry != &KdProviders; + CurrentEntry = CurrentEntry->Flink) { - /* Get the current table */ CurrentTable = CONTAINING_RECORD(CurrentEntry, KD_DISPATCH_TABLE, KdProvidersList); - /* Call it */ CurrentTable->KdpPrintRoutine(MessageData->Buffer, MessageData->Length); - - /* Next Table */ - CurrentEntry = CurrentEntry->Flink; } return; } diff --git a/ntoskrnl/kd/kdmain.c b/ntoskrnl/kd/kdmain.c index be749a705a9..abd358da0fc 100644 --- a/ntoskrnl/kd/kdmain.c +++ b/ntoskrnl/kd/kdmain.c @@ -1,10 +1,10 @@ /* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS Kernel - * FILE: ntoskrnl/kd/kdmain.c - * PURPOSE: Kernel Debugger Initialization - * - * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) + * PROJECT: ReactOS Kernel + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Kernel Debugger Initialization + * COPYRIGHT: Copyright 2005 Alex Ionescu + * Copyright 2020 Hervé Poussineau + * Copyright 2023 Hermès Bélusca-Maïto */ #include @@ -13,8 +13,6 @@ /* VARIABLES ***************************************************************/ -VOID NTAPI PspDumpThreads(BOOLEAN SystemThreads); - extern ANSI_STRING KdpLogFileName; /* PUBLIC FUNCTIONS *********************************************************/ @@ -86,8 +84,9 @@ NTAPI KdDebuggerInitialize0( _In_opt_ PLOADER_PARAMETER_BLOCK LoaderBlock) { - ULONG i; PCHAR CommandLine, Port = NULL; + ULONG i; + BOOLEAN Success = FALSE; if (LoaderBlock) { @@ -127,15 +126,174 @@ KdDebuggerInitialize0( if (KdpDebugMode.Value == 0) KdpDebugMode.Serial = TRUE; - /* Call Providers at Phase 0 */ - for (i = 0; i < KdMax; i++) + /* Call the providers at Phase 0 */ + for (i = 0; i < RTL_NUMBER_OF(DispatchTable); i++) { - InitRoutines[i](&DispatchTable[i], 0); + DispatchTable[i].InitStatus = InitRoutines[i](&DispatchTable[i], 0); + Success = (Success || NT_SUCCESS(DispatchTable[i].InitStatus)); } + /* Return success if at least one of the providers succeeded */ + return (Success ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL); +} + + +/** + * @brief Reinitialization routine. + * DRIVER_REINITIALIZE + * + * Calls each registered provider for reinitialization at Phase >= 2. + * I/O is now set up for disk access, at different phases. + **/ +static VOID +NTAPI +KdpDriverReinit( + _In_ PDRIVER_OBJECT DriverObject, + _In_opt_ PVOID Context, + _In_ ULONG Count) +{ + PLIST_ENTRY CurrentEntry; + PKD_DISPATCH_TABLE CurrentTable; + PKDP_INIT_ROUTINE KdpInitRoutine; + ULONG BootPhase = (Count + 1); // Do BootPhase >= 2 + BOOLEAN ScheduleReinit = FALSE; + + ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); + + DPRINT("*** KD %sREINITIALIZATION - Phase %d ***\n", + Context ? "" : "BOOT ", BootPhase); + + /* Call the registered providers */ + for (CurrentEntry = KdProviders.Flink; + CurrentEntry != &KdProviders; NOTHING) + { + /* Get the provider */ + CurrentTable = CONTAINING_RECORD(CurrentEntry, + KD_DISPATCH_TABLE, + KdProvidersList); + /* Go to the next entry (the Init routine may unlink us) */ + CurrentEntry = CurrentEntry->Flink; + + /* Call it if it requires a reinitialization */ + if (CurrentTable->KdpInitRoutine) + { + /* Get the initialization routine and reset it */ + KdpInitRoutine = CurrentTable->KdpInitRoutine; + CurrentTable->KdpInitRoutine = NULL; + CurrentTable->InitStatus = KdpInitRoutine(CurrentTable, BootPhase); + DPRINT("KdpInitRoutine(%p) returned 0x%08lx\n", + CurrentTable, CurrentTable->InitStatus); + + /* Check whether it needs to be reinitialized again */ + ScheduleReinit = (ScheduleReinit || CurrentTable->KdpInitRoutine); + } + } + + DPRINT("ScheduleReinit: %s\n", ScheduleReinit ? "TRUE" : "FALSE"); + if (ScheduleReinit) + { + /* + * Determine when to reinitialize. + * If Context == NULL, we are doing a boot-driver reinitialization. + * It is initially done once (Count == 1), and is rescheduled once + * after all other boot drivers get loaded (Count == 2). + * If further reinitialization is needed, switch to system-driver + * reinitialization and do it again, not more than twice. + */ + if (Count <= 1) + { + IoRegisterBootDriverReinitialization(DriverObject, + KdpDriverReinit, + (PVOID)FALSE); + } + else if (Count <= 3) + { + IoRegisterDriverReinitialization(DriverObject, + KdpDriverReinit, + (PVOID)TRUE); + } + else + { + /* Too late, no more reinitializations! */ + DPRINT("Cannot reinitialize anymore!\n"); + ScheduleReinit = FALSE; + } + } + + if (!ScheduleReinit) + { + /* All the necessary reinitializations are done, + * the driver object is not needed anymore. */ + ObMakeTemporaryObject(DriverObject); + IoDeleteDriver(DriverObject); + } +} + +/** + * @brief Entry point for the auxiliary driver. + * DRIVER_INITIALIZE + **/ +static NTSTATUS +NTAPI +KdpDriverEntry( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING RegistryPath) +{ + UNREFERENCED_PARAMETER(RegistryPath); + + /* Register for reinitialization after the other drivers are loaded */ + IoRegisterBootDriverReinitialization(DriverObject, + KdpDriverReinit, + (PVOID)FALSE); + + /* Set the driver as initialized */ + DriverObject->Flags |= DRVO_INITIALIZED; return STATUS_SUCCESS; } +/** + * @brief Hooked HalInitPnpDriver() callback. + * It is initially set by the HAL when HalInitSystem(0, ...) + * is called earlier on. + **/ +static pHalInitPnpDriver orgHalInitPnpDriver = NULL; + +/** + * @brief + * HalInitPnpDriver() callback hook installed by KdDebuggerInitialize1(). + * + * It is called during initialization of the I/O manager and is where + * the auxiliary driver is created. This driver is needed for receiving + * reinitialization callbacks in KdpDriverReinit() later. + * This hook must *always* call the original HalInitPnpDriver() function + * and return its returned value, or return STATUS_SUCCESS. + **/ +static NTSTATUS +NTAPI +KdpInitDriver(VOID) +{ + static BOOLEAN InitCalled = FALSE; + NTSTATUS Status; + UNICODE_STRING DriverName = RTL_CONSTANT_STRING(L"\\Driver\\KdDriver"); + + ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); + + /* Ensure we are not called more than once */ + if (_InterlockedCompareExchange8((char*)&InitCalled, TRUE, FALSE) != FALSE) + return STATUS_SUCCESS; + + /* Create the driver */ + Status = IoCreateDriver(&DriverName, KdpDriverEntry); + if (!NT_SUCCESS(Status)) + DPRINT1("IoCreateDriver failed: 0x%08lx\n", Status); + /* Ignore any failure from IoCreateDriver(). If it fails, no I/O-related + * initialization will happen (no file log debugging, etc.). */ + + /* Finally, restore and call the original HalInitPnpDriver() */ + InterlockedExchangePointer((PVOID*)&HalInitPnpDriver, orgHalInitPnpDriver); + return (HalInitPnpDriver ? HalInitPnpDriver() : STATUS_SUCCESS); +} + NTSTATUS NTAPI KdDebuggerInitialize1( @@ -143,26 +301,119 @@ KdDebuggerInitialize1( { PLIST_ENTRY CurrentEntry; PKD_DISPATCH_TABLE CurrentTable; + PKDP_INIT_ROUTINE KdpInitRoutine; + BOOLEAN Success = FALSE; + BOOLEAN ReinitForPhase2 = FALSE; - /* Call the registered handlers */ - CurrentEntry = KdProviders.Flink; - while (CurrentEntry != &KdProviders) + /* Call the registered providers */ + for (CurrentEntry = KdProviders.Flink; + CurrentEntry != &KdProviders; NOTHING) { - /* Get the current table */ + /* Get the provider */ CurrentTable = CONTAINING_RECORD(CurrentEntry, KD_DISPATCH_TABLE, KdProvidersList); + /* Go to the next entry (the Init routine may unlink us) */ + CurrentEntry = CurrentEntry->Flink; + + /* Get the initialization routine and reset it */ + ASSERT(CurrentTable->KdpInitRoutine); + KdpInitRoutine = CurrentTable->KdpInitRoutine; + CurrentTable->KdpInitRoutine = NULL; /* Call it */ - CurrentTable->KdpInitRoutine(CurrentTable, 1); + CurrentTable->InitStatus = KdpInitRoutine(CurrentTable, 1); - /* Next Table */ - CurrentEntry = CurrentEntry->Flink; + /* Check whether it needs to be reinitialized for Phase 2 */ + Success = (Success || NT_SUCCESS(CurrentTable->InitStatus)); + ReinitForPhase2 = (ReinitForPhase2 || CurrentTable->KdpInitRoutine); } NtGlobalFlag |= FLG_STOP_ON_EXCEPTION; + /* If we don't need to reinitialize providers for Phase 2, we are done */ + if (!ReinitForPhase2) + { + /* Return success if at least one of them succeeded */ + return (Success ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL); + } + + /** + * We want to be able to perform I/O-related initialization (starting a + * logger thread for file log debugging, loading KDBinit file for KDBG, + * etc.). A good place for this would be as early as possible, once the + * I/O Manager has started the storage and the boot filesystem drivers. + * + * Here is an overview of the initialization steps of the NT Kernel and + * Executive: + * ---- + * KiSystemStartup(KeLoaderBlock) + * if (Cpu == 0) KdInitSystem(0, KeLoaderBlock); + * KiSwitchToBootStack() -> KiSystemStartupBootStack() + * -> KiInitializeKernel() -> ExpInitializeExecutive(Cpu, KeLoaderBlock) + * + * (NOTE: Any unexpected debugger break will call KdInitSystem(0, NULL); ) + * KdInitSystem(0, LoaderBlock) -> KdDebuggerInitialize0(LoaderBlock); + * + * ExpInitializeExecutive(Cpu == 0): ExpInitializationPhase = 0; + * HalInitSystem(0, KeLoaderBlock); <-- Sets HalInitPnpDriver callback. + * ... + * PsInitSystem(LoaderBlock) + * PsCreateSystemThread(Phase1Initialization) + * + * Phase1Initialization(Discard): ExpInitializationPhase = 1; + * HalInitSystem(1, KeLoaderBlock); + * ... + * Early initialization of Ob, Ex, Ke. + * KdInitSystem(1, KeLoaderBlock); + * ... + * KdDebuggerInitialize1(LoaderBlock); + * ... + * IoInitSystem(LoaderBlock); + * ... + * ---- + * As we can see, KdDebuggerInitialize1() is the last KD initialization + * routine the kernel calls, and is called *before* the I/O Manager starts. + * Thus, direct Nt/ZwCreateFile ... calls done there would fail. Also, + * we want to do the I/O initialization as soon as possible. There does + * not seem to be any exported way to be notified about the I/O manager + * initialization steps... that is, unless we somehow become a driver and + * insert ourselves in the flow! + * + * Since we are not a regular driver, we need to invoke IoCreateDriver() + * to create one. However, remember that we are currently running *before* + * IoInitSystem(), the I/O subsystem is not initialized yet. Due to this, + * calling IoCreateDriver(), much like any other IO functions, would lead + * to a crash, because it calls + * ObCreateObject(..., IoDriverObjectType, ...), and IoDriverObjectType + * is non-initialized yet (it's NULL). + * + * The chosen solution is to hook a "known" exported callback: namely, the + * HalInitPnpDriver() callback (it initializes the "HAL Root Bus Driver"). + * It is set very early on by the HAL via the HalInitSystem(0, ...) call, + * and is called early on by IoInitSystem() before any driver is loaded, + * but after the I/O Manager has been minimally set up so that new drivers + * can be created. + * When the hook: KdpInitDriver() is called, we create our driver with + * IoCreateDriver(), specifying its entrypoint KdpDriverEntry(), then + * restore and call the original HalInitPnpDriver() callback. + * + * Another possible unexplored alternative, could be to insert ourselves + * in the KeLoaderBlock->LoadOrderListHead boot modules list, or in the + * KeLoaderBlock->BootDriverListHead boot-driver list. (Note that while + * we may be able to do this, because boot-drivers are resident in memory, + * much like we are, we cannot insert ourselves in the system-driver list + * however, since those drivers are expected to come from PE image files.) + * + * Once the KdpDriverEntry() driver entrypoint is called, we register + * KdpDriverReinit() for re-initialization with the I/O Manager, in order + * to provide more initialization points. KdpDriverReinit() calls the KD + * providers at BootPhase >= 2, and schedules further reinitializations + * (at most 3 more) if any of the providers request so. + **/ + orgHalInitPnpDriver = + InterlockedExchangePointer((PVOID*)&HalInitPnpDriver, KdpInitDriver); return STATUS_SUCCESS; } - /* EOF */ +/* EOF */ diff --git a/ntoskrnl/kdbg/kdb.h b/ntoskrnl/kdbg/kdb.h index 11bc4cb452f..4424dd4837c 100644 --- a/ntoskrnl/kdbg/kdb.h +++ b/ntoskrnl/kdbg/kdb.h @@ -82,7 +82,7 @@ KdbpStackSwitchAndCall( extern PCHAR KdbInitFileBuffer; -VOID +NTSTATUS NTAPI KdbInitialize( _In_ PKD_DISPATCH_TABLE DispatchTable, @@ -94,7 +94,7 @@ KdbRegisterCliCallback( PVOID Callback, BOOLEAN Deregister); -VOID +NTSTATUS KdbpCliInit(VOID); VOID diff --git a/ntoskrnl/kdbg/kdb_cli.c b/ntoskrnl/kdbg/kdb_cli.c index fdd5d694924..aaebf573cf8 100644 --- a/ntoskrnl/kdbg/kdb_cli.c +++ b/ntoskrnl/kdbg/kdb_cli.c @@ -3795,11 +3795,13 @@ KdbpCliInterpretInitFile(VOID) DPRINT("KDB: KDBinit executed\n"); } -/*!\brief Called when KDB is initialized +/** + * @brief Called when KDB is initialized. * - * Reads the KDBinit file from the SystemRoot\System32\drivers\etc directory and executes it. - */ -VOID + * Reads the KDBinit file from the SystemRoot\System32\drivers\etc directory + * and executes it. + **/ +NTSTATUS KdbpCliInit(VOID) { NTSTATUS Status; @@ -3812,6 +3814,10 @@ KdbpCliInit(VOID) PCHAR FileBuffer; ULONG OldEflags; + /* Don't load the KDBinit file if its buffer is already lying around */ + if (KdbInitFileBuffer) + return STATUS_SUCCESS; + /* Initialize the object attributes */ RtlInitUnicodeString(&FileName, L"\\SystemRoot\\System32\\drivers\\etc\\KDBinit"); InitializeObjectAttributes(&ObjectAttributes, @@ -3828,7 +3834,7 @@ KdbpCliInit(VOID) if (!NT_SUCCESS(Status)) { DPRINT("Could not open \\SystemRoot\\System32\\drivers\\etc\\KDBinit (Status 0x%x)", Status); - return; + return Status; } /* Get the size of the file */ @@ -3839,7 +3845,7 @@ KdbpCliInit(VOID) { ZwClose(hFile); DPRINT("Could not query size of \\SystemRoot\\System32\\drivers\\etc\\KDBinit (Status 0x%x)", Status); - return; + return Status; } FileSize = FileStdInfo.EndOfFile.u.LowPart; @@ -3849,7 +3855,7 @@ KdbpCliInit(VOID) { ZwClose(hFile); DPRINT("Could not allocate %d bytes for KDBinit file\n", FileSize); - return; + return Status; } /* Load file into memory */ @@ -3860,7 +3866,7 @@ KdbpCliInit(VOID) { ExFreePool(FileBuffer); DPRINT("Could not read KDBinit file into memory (Status 0x%lx)\n", Status); - return; + return Status; } FileSize = min(FileSize, (INT)Iosb.Information); @@ -3872,13 +3878,15 @@ KdbpCliInit(VOID) /* Interpret the init file... */ KdbInitFileBuffer = FileBuffer; - //KdbEnter(); // FIXME + //KdbEnter(); // FIXME, see commit baa47fa5e KdbInitFileBuffer = NULL; /* Leave critical section */ __writeeflags(OldEflags); ExFreePool(FileBuffer); + + return STATUS_SUCCESS; } @@ -3947,10 +3955,10 @@ KdbDebugPrint( * @param[in] BootPhase * Phase of initialization. * - * @return None. + * @return A status value. * @note Also known as "KdpKdbgInit". **/ -VOID +NTSTATUS NTAPI KdbInitialize( _In_ PKD_DISPATCH_TABLE DispatchTable, @@ -3959,14 +3967,17 @@ KdbInitialize( if (BootPhase == 0) { /* Write out the functions that we support for now */ - DispatchTable->KdpInitRoutine = KdbInitialize; DispatchTable->KdpPrintRoutine = KdbDebugPrint; - /* Register as a Provider */ + /* Register for BootPhase 1 initialization and as a Provider */ + DispatchTable->KdpInitRoutine = KdbInitialize; InsertTailList(&KdProviders, &DispatchTable->KdProvidersList); } else if (BootPhase == 1) { + /* Register for later BootPhase 2 reinitialization */ + DispatchTable->KdpInitRoutine = KdbInitialize; + /* Initialize Dmesg support */ /* Allocate a buffer for Dmesg log buffer. +1 for terminating null, @@ -3987,6 +3998,20 @@ KdbInitialize( /* Initialize symbols support */ KdbSymInit(BootPhase); } + else if (BootPhase >= 2) + { + /* I/O is now set up for disk access: Read KDB Data */ + NTSTATUS Status = KdbpCliInit(); + + /* Schedule an I/O reinitialization if needed */ + if (Status == STATUS_OBJECT_NAME_NOT_FOUND || + Status == STATUS_OBJECT_PATH_NOT_FOUND) + { + DispatchTable->KdpInitRoutine = KdbInitialize; + } + } + + return STATUS_SUCCESS; } /* EOF */