1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: BSD - See COPYING.ARM in the top level directory 4 * FILE: ntoskrnl/po/poshtdwn.c 5 * PURPOSE: Power Manager Shutdown Code 6 * PROGRAMMERS: ReactOS Portable Systems Group 7 */ 8 9 /* INCLUDES ******************************************************************/ 10 11 #include <ntoskrnl.h> 12 #ifdef NEWCC 13 #include <cache/newcc.h> 14 #endif 15 16 #define NDEBUG 17 #include <debug.h> 18 19 #include "inbv/logo.h" 20 21 /* GLOBALS *******************************************************************/ 22 23 ULONG PopShutdownPowerOffPolicy; 24 KEVENT PopShutdownEvent; 25 PPOP_SHUTDOWN_WAIT_ENTRY PopShutdownThreadList; 26 LIST_ENTRY PopShutdownQueue; 27 KGUARDED_MUTEX PopShutdownListMutex; 28 BOOLEAN PopShutdownListAvailable; 29 30 31 /* PRIVATE FUNCTIONS *********************************************************/ 32 33 VOID 34 NTAPI 35 PopInitShutdownList(VOID) 36 { 37 PAGED_CODE(); 38 39 /* Initialize the global shutdown event */ 40 KeInitializeEvent(&PopShutdownEvent, NotificationEvent, FALSE); 41 42 /* Initialize the shutdown lists */ 43 PopShutdownThreadList = NULL; 44 InitializeListHead(&PopShutdownQueue); 45 46 /* Initialize the shutdown list lock */ 47 KeInitializeGuardedMutex(&PopShutdownListMutex); 48 49 /* The list is available now */ 50 PopShutdownListAvailable = TRUE; 51 } 52 53 NTSTATUS 54 NTAPI 55 PoRequestShutdownWait( 56 _In_ PETHREAD Thread) 57 { 58 PPOP_SHUTDOWN_WAIT_ENTRY ShutDownWaitEntry; 59 NTSTATUS Status; 60 PAGED_CODE(); 61 62 /* Allocate a new shutdown wait entry */ 63 ShutDownWaitEntry = ExAllocatePoolWithTag(PagedPool, sizeof(*ShutDownWaitEntry), 'LSoP'); 64 if (ShutDownWaitEntry == NULL) 65 { 66 return STATUS_NO_MEMORY; 67 } 68 69 /* Reference the thread and save it in the wait entry */ 70 ObReferenceObject(Thread); 71 ShutDownWaitEntry->Thread = Thread; 72 73 /* Acquire the shutdown list lock */ 74 KeAcquireGuardedMutex(&PopShutdownListMutex); 75 76 /* Check if the list is still available */ 77 if (PopShutdownListAvailable) 78 { 79 /* Insert the item in the list */ 80 ShutDownWaitEntry->NextEntry = PopShutdownThreadList; 81 PopShutdownThreadList = ShutDownWaitEntry; 82 83 /* We are successful */ 84 Status = STATUS_SUCCESS; 85 } 86 else 87 { 88 /* We cannot proceed, cleanup and return failure */ 89 ObDereferenceObject(Thread); 90 ExFreePoolWithTag(ShutDownWaitEntry, 'LSoP'); 91 Status = STATUS_UNSUCCESSFUL; 92 } 93 94 /* Release the list lock */ 95 KeReleaseGuardedMutex(&PopShutdownListMutex); 96 97 /* Return the status */ 98 return Status; 99 } 100 101 VOID 102 NTAPI 103 PopProcessShutDownLists(VOID) 104 { 105 PPOP_SHUTDOWN_WAIT_ENTRY ShutDownWaitEntry; 106 PWORK_QUEUE_ITEM WorkItem; 107 PLIST_ENTRY ListEntry; 108 109 /* First signal the shutdown event */ 110 KeSetEvent(&PopShutdownEvent, IO_NO_INCREMENT, FALSE); 111 112 /* Acquire the shutdown list lock */ 113 KeAcquireGuardedMutex(&PopShutdownListMutex); 114 115 /* Block any further attempts to register a shutdown event */ 116 PopShutdownListAvailable = FALSE; 117 118 /* Release the list lock, since we are exclusively using the lists now */ 119 KeReleaseGuardedMutex(&PopShutdownListMutex); 120 121 /* Process the shutdown queue */ 122 while (!IsListEmpty(&PopShutdownQueue)) 123 { 124 /* Get the head entry */ 125 ListEntry = RemoveHeadList(&PopShutdownQueue); 126 WorkItem = CONTAINING_RECORD(ListEntry, WORK_QUEUE_ITEM, List); 127 128 /* Call the shutdown worker routine */ 129 WorkItem->WorkerRoutine(WorkItem->Parameter); 130 } 131 132 /* Now process the shutdown thread list */ 133 while (PopShutdownThreadList != NULL) 134 { 135 /* Get the top entry and remove it from the list */ 136 ShutDownWaitEntry = PopShutdownThreadList; 137 PopShutdownThreadList = PopShutdownThreadList->NextEntry; 138 139 /* Wait for the thread to finish and dereference it */ 140 KeWaitForSingleObject(ShutDownWaitEntry->Thread, 0, 0, 0, 0); 141 ObDereferenceObject(ShutDownWaitEntry->Thread); 142 143 /* Finally free the entry */ 144 ExFreePoolWithTag(ShutDownWaitEntry, 'LSoP'); 145 } 146 } 147 148 VOID 149 NTAPI 150 PopShutdownHandler(VOID) 151 { 152 /* Stop all interrupts */ 153 KeRaiseIrqlToDpcLevel(); 154 _disable(); 155 156 /* Do we have boot video */ 157 if (InbvIsBootDriverInstalled()) 158 { 159 /* Yes we do, cleanup for shutdown screen */ 160 if (!InbvCheckDisplayOwnership()) InbvAcquireDisplayOwnership(); 161 InbvResetDisplay(); 162 // InbvEnableDisplayString(TRUE); 163 DisplayShutdownBitmap(); 164 } 165 else 166 { 167 /* Do it in text-mode */ 168 DisplayShutdownText(); 169 } 170 171 /* Hang the system */ 172 for (;;) HalHaltSystem(); 173 } 174 175 VOID 176 NTAPI 177 PopShutdownSystem(IN POWER_ACTION SystemAction) 178 { 179 /* Note should notify caller of NtPowerInformation(PowerShutdownNotification) */ 180 181 /* Unload symbols */ 182 DPRINT("It's the final countdown...%lx\n", SystemAction); 183 DbgUnLoadImageSymbols(NULL, (PVOID)-1, 0); 184 185 /* Run the thread on the boot processor */ 186 KeSetSystemAffinityThread(1); 187 188 /* Now check what the caller wants */ 189 switch (SystemAction) 190 { 191 /* Reset */ 192 case PowerActionShutdownReset: 193 194 /* Try platform driver first, then legacy */ 195 //PopInvokeSystemStateHandler(PowerStateShutdownReset, NULL); 196 PopSetSystemPowerState(PowerSystemShutdown, SystemAction); 197 HalReturnToFirmware(HalRebootRoutine); 198 break; 199 200 case PowerActionShutdown: 201 202 /* Check for group policy that says to use "it is now safe" screen */ 203 if (PopShutdownPowerOffPolicy) 204 { 205 /* FIXFIX: Switch to legacy shutdown handler */ 206 //PopPowerStateHandlers[PowerStateShutdownOff].Handler = PopShutdownHandler; 207 } 208 209 case PowerActionShutdownOff: 210 211 /* Call shutdown handler */ 212 //PopInvokeSystemStateHandler(PowerStateShutdownOff, NULL); 213 214 /* ReactOS Hack */ 215 PopSetSystemPowerState(PowerSystemShutdown, SystemAction); 216 PopShutdownHandler(); 217 218 /* If that didn't work, call the HAL */ 219 HalReturnToFirmware(HalPowerDownRoutine); 220 break; 221 222 default: 223 break; 224 } 225 226 /* Anything else should not happen */ 227 KeBugCheckEx(INTERNAL_POWER_ERROR, 5, 0, 0, 0); 228 } 229 230 VOID 231 NTAPI 232 PopGracefulShutdown(IN PVOID Context) 233 { 234 PEPROCESS Process = NULL; 235 236 /* Process the registered waits and work items */ 237 PopProcessShutDownLists(); 238 239 /* Loop every process */ 240 Process = PsGetNextProcess(Process); 241 while (Process) 242 { 243 /* Make sure this isn't the idle or initial process */ 244 if ((Process != PsInitialSystemProcess) && (Process != PsIdleProcess)) 245 { 246 /* Print it */ 247 DPRINT1("%15s is still RUNNING (%p)\n", Process->ImageFileName, Process->UniqueProcessId); 248 } 249 250 /* Get the next process */ 251 Process = PsGetNextProcess(Process); 252 } 253 254 /* First, the HAL handles any "end of boot" special functionality */ 255 DPRINT("HAL shutting down\n"); 256 HalEndOfBoot(); 257 258 /* Shut down the Shim cache if enabled */ 259 ApphelpCacheShutdown(); 260 261 /* In this step, the I/O manager does first-chance shutdown notification */ 262 DPRINT("I/O manager shutting down in phase 0\n"); 263 IoShutdownSystem(0); 264 265 /* In this step, all workers are killed and hives are flushed */ 266 DPRINT("Configuration Manager shutting down\n"); 267 CmShutdownSystem(); 268 269 /* Shut down the Executive */ 270 DPRINT("Executive shutting down\n"); 271 ExShutdownSystem(); 272 273 /* Note that modified pages should be written here (MiShutdownSystem) */ 274 MmShutdownSystem(0); 275 276 /* Flush all user files before we start shutting down IO */ 277 /* This is where modified pages are written back by the IO manager */ 278 CcShutdownSystem(); 279 280 /* In this step, the I/O manager does last-chance shutdown notification */ 281 DPRINT("I/O manager shutting down in phase 1\n"); 282 IoShutdownSystem(1); 283 CcWaitForCurrentLazyWriterActivity(); 284 285 /* FIXME: Calling Mm shutdown phase 1 here to get page file dereference 286 * but it shouldn't be called here. Only phase 2 should be called. 287 */ 288 MmShutdownSystem(1); 289 290 /* Note that here, we should broadcast the power IRP to devices */ 291 292 /* In this step, the HAL disables any wake timers */ 293 DPRINT("Disabling wake timers\n"); 294 HalSetWakeEnable(FALSE); 295 296 /* And finally the power request is sent */ 297 DPRINT("Taking the system down\n"); 298 PopShutdownSystem(PopAction.Action); 299 } 300 301 VOID 302 NTAPI 303 PopReadShutdownPolicy(VOID) 304 { 305 UNICODE_STRING KeyString; 306 OBJECT_ATTRIBUTES ObjectAttributes; 307 NTSTATUS Status; 308 HANDLE KeyHandle; 309 ULONG Length; 310 UCHAR Buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)]; 311 PKEY_VALUE_PARTIAL_INFORMATION Info = (PVOID)Buffer; 312 313 /* Setup object attributes */ 314 RtlInitUnicodeString(&KeyString, 315 L"\\Registry\\Machine\\Software\\Policies\\Microsoft\\Windows NT"); 316 InitializeObjectAttributes(&ObjectAttributes, 317 &KeyString, 318 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 319 NULL, 320 NULL); 321 322 /* Open the key */ 323 Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes); 324 if (NT_SUCCESS(Status)) 325 { 326 /* Open the policy value and query it */ 327 RtlInitUnicodeString(&KeyString, L"DontPowerOffAfterShutdown"); 328 Status = ZwQueryValueKey(KeyHandle, 329 &KeyString, 330 KeyValuePartialInformation, 331 &Info, 332 sizeof(Info), 333 &Length); 334 if ((NT_SUCCESS(Status)) && (Info->Type == REG_DWORD)) 335 { 336 /* Read the policy */ 337 PopShutdownPowerOffPolicy = *Info->Data == 1; 338 } 339 340 /* Close the key */ 341 ZwClose(KeyHandle); 342 } 343 } 344 345 /* PUBLIC FUNCTIONS **********************************************************/ 346 347 /* 348 * @unimplemented 349 */ 350 NTSTATUS 351 NTAPI 352 PoQueueShutdownWorkItem( 353 _In_ PWORK_QUEUE_ITEM WorkItem) 354 { 355 NTSTATUS Status; 356 357 /* Acquire the shutdown list lock */ 358 KeAcquireGuardedMutex(&PopShutdownListMutex); 359 360 /* Check if the list is (already/still) available */ 361 if (PopShutdownListAvailable) 362 { 363 /* Insert the item into the list */ 364 InsertTailList(&PopShutdownQueue, &WorkItem->List); 365 Status = STATUS_SUCCESS; 366 } 367 else 368 { 369 /* We are already in shutdown */ 370 Status = STATUS_SYSTEM_SHUTDOWN; 371 } 372 373 /* Release the list lock */ 374 KeReleaseGuardedMutex(&PopShutdownListMutex); 375 376 return Status; 377 } 378 379 /* 380 * @implemented 381 */ 382 NTSTATUS 383 NTAPI 384 PoRequestShutdownEvent(OUT PVOID *Event) 385 { 386 NTSTATUS Status; 387 PAGED_CODE(); 388 389 /* Initialize to NULL */ 390 if (Event) *Event = NULL; 391 392 /* Request a shutdown wait */ 393 Status = PoRequestShutdownWait(PsGetCurrentThread()); 394 if (!NT_SUCCESS(Status)) 395 { 396 return Status; 397 } 398 399 /* Return the global shutdown event */ 400 if (Event) *Event = &PopShutdownEvent; 401 return STATUS_SUCCESS; 402 } 403 404