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