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 ObfDereferenceObject(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_DEFAULT_LOGO); 169 if ((Logo1) && (Logo2)) 170 { 171 InbvBitBlt(Logo1, 220, 352); 172 InbvBitBlt(Logo2, 222, 111); 173 } 174 } 175 else 176 { 177 /* Do it in text-mode */ 178 for (i = 0; i < 25; i++) InbvDisplayString("\r\n"); 179 InbvDisplayString(" "); 180 InbvDisplayString("The system may be powered off now.\r\n"); 181 } 182 183 /* Hang the system */ 184 for (;;) HalHaltSystem(); 185 } 186 187 VOID 188 NTAPI 189 PopShutdownSystem(IN POWER_ACTION SystemAction) 190 { 191 /* Note should notify caller of NtPowerInformation(PowerShutdownNotification) */ 192 193 /* Unload symbols */ 194 DPRINT("It's the final countdown...%lx\n", SystemAction); 195 DbgUnLoadImageSymbols(NULL, (PVOID)-1, 0); 196 197 /* Run the thread on the boot processor */ 198 KeSetSystemAffinityThread(1); 199 200 /* Now check what the caller wants */ 201 switch (SystemAction) 202 { 203 /* Reset */ 204 case PowerActionShutdownReset: 205 206 /* Try platform driver first, then legacy */ 207 //PopInvokeSystemStateHandler(PowerStateShutdownReset, NULL); 208 PopSetSystemPowerState(PowerSystemShutdown, SystemAction); 209 HalReturnToFirmware(HalRebootRoutine); 210 break; 211 212 case PowerActionShutdown: 213 214 /* Check for group policy that says to use "it is now safe" screen */ 215 if (PopShutdownPowerOffPolicy) 216 { 217 /* FIXFIX: Switch to legacy shutdown handler */ 218 //PopPowerStateHandlers[PowerStateShutdownOff].Handler = PopShutdownHandler; 219 } 220 221 case PowerActionShutdownOff: 222 223 /* Call shutdown handler */ 224 //PopInvokeSystemStateHandler(PowerStateShutdownOff, NULL); 225 226 /* ReactOS Hack */ 227 PopSetSystemPowerState(PowerSystemShutdown, SystemAction); 228 PopShutdownHandler(); 229 230 /* If that didn't work, call the HAL */ 231 HalReturnToFirmware(HalPowerDownRoutine); 232 break; 233 234 default: 235 break; 236 } 237 238 /* Anything else should not happen */ 239 KeBugCheckEx(INTERNAL_POWER_ERROR, 5, 0, 0, 0); 240 } 241 242 VOID 243 NTAPI 244 PopGracefulShutdown(IN PVOID Context) 245 { 246 PEPROCESS Process = NULL; 247 248 /* Process the registered waits and work items */ 249 PopProcessShutDownLists(); 250 251 /* Loop every process */ 252 Process = PsGetNextProcess(Process); 253 while (Process) 254 { 255 /* Make sure this isn't the idle or initial process */ 256 if ((Process != PsInitialSystemProcess) && (Process != PsIdleProcess)) 257 { 258 /* Print it */ 259 DPRINT1("%15s is still RUNNING (%p)\n", Process->ImageFileName, Process->UniqueProcessId); 260 } 261 262 /* Get the next process */ 263 Process = PsGetNextProcess(Process); 264 } 265 266 /* First, the HAL handles any "end of boot" special functionality */ 267 DPRINT("HAL shutting down\n"); 268 HalEndOfBoot(); 269 270 /* Shut down the Shim cache if enabled */ 271 ApphelpCacheShutdown(); 272 273 /* In this step, the I/O manager does first-chance shutdown notification */ 274 DPRINT("I/O manager shutting down in phase 0\n"); 275 IoShutdownSystem(0); 276 277 /* In this step, all workers are killed and hives are flushed */ 278 DPRINT("Configuration Manager shutting down\n"); 279 CmShutdownSystem(); 280 281 /* Shut down the Executive */ 282 DPRINT("Executive shutting down\n"); 283 ExShutdownSystem(); 284 285 /* Note that modified pages should be written here (MiShutdownSystem) */ 286 287 /* Flush all user files before we start shutting down IO */ 288 /* This is where modified pages are written back by the IO manager */ 289 CcShutdownSystem(); 290 291 /* In this step, the I/O manager does last-chance shutdown notification */ 292 DPRINT("I/O manager shutting down in phase 1\n"); 293 IoShutdownSystem(1); 294 CcWaitForCurrentLazyWriterActivity(); 295 296 /* Note that here, we should broadcast the power IRP to devices */ 297 298 /* In this step, the HAL disables any wake timers */ 299 DPRINT("Disabling wake timers\n"); 300 HalSetWakeEnable(FALSE); 301 302 /* And finally the power request is sent */ 303 DPRINT("Taking the system down\n"); 304 PopShutdownSystem(PopAction.Action); 305 } 306 307 VOID 308 NTAPI 309 PopReadShutdownPolicy(VOID) 310 { 311 UNICODE_STRING KeyString; 312 OBJECT_ATTRIBUTES ObjectAttributes; 313 NTSTATUS Status; 314 HANDLE KeyHandle; 315 ULONG Length; 316 UCHAR Buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)]; 317 PKEY_VALUE_PARTIAL_INFORMATION Info = (PVOID)Buffer; 318 319 /* Setup object attributes */ 320 RtlInitUnicodeString(&KeyString, 321 L"\\Registry\\Machine\\Software\\Policies\\Microsoft\\Windows NT"); 322 InitializeObjectAttributes(&ObjectAttributes, 323 &KeyString, 324 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 325 NULL, 326 NULL); 327 328 /* Open the key */ 329 Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes); 330 if (NT_SUCCESS(Status)) 331 { 332 /* Open the policy value and query it */ 333 RtlInitUnicodeString(&KeyString, L"DontPowerOffAfterShutdown"); 334 Status = ZwQueryValueKey(KeyHandle, 335 &KeyString, 336 KeyValuePartialInformation, 337 &Info, 338 sizeof(Info), 339 &Length); 340 if ((NT_SUCCESS(Status)) && (Info->Type == REG_DWORD)) 341 { 342 /* Read the policy */ 343 PopShutdownPowerOffPolicy = *Info->Data == 1; 344 } 345 346 /* Close the key */ 347 ZwClose(KeyHandle); 348 } 349 } 350 351 /* PUBLIC FUNCTIONS **********************************************************/ 352 353 /* 354 * @unimplemented 355 */ 356 NTSTATUS 357 NTAPI 358 PoQueueShutdownWorkItem( 359 _In_ PWORK_QUEUE_ITEM WorkItem) 360 { 361 NTSTATUS Status; 362 363 /* Acquire the shutdown list lock */ 364 KeAcquireGuardedMutex(&PopShutdownListMutex); 365 366 /* Check if the list is (already/still) available */ 367 if (PopShutdownListAvailable) 368 { 369 /* Insert the item into the list */ 370 InsertTailList(&PopShutdownQueue, &WorkItem->List); 371 Status = STATUS_SUCCESS; 372 } 373 else 374 { 375 /* We are already in shutdown */ 376 Status = STATUS_SYSTEM_SHUTDOWN; 377 } 378 379 /* Release the list lock */ 380 KeReleaseGuardedMutex(&PopShutdownListMutex); 381 382 return Status; 383 } 384 385 /* 386 * @implemented 387 */ 388 NTSTATUS 389 NTAPI 390 PoRequestShutdownEvent(OUT PVOID *Event) 391 { 392 NTSTATUS Status; 393 PAGED_CODE(); 394 395 /* Initialize to NULL */ 396 if (Event) *Event = NULL; 397 398 /* Request a shutdown wait */ 399 Status = PoRequestShutdownWait(PsGetCurrentThread()); 400 if (!NT_SUCCESS(Status)) 401 { 402 return Status; 403 } 404 405 /* Return the global shutdown event */ 406 if (Event) *Event = &PopShutdownEvent; 407 return STATUS_SUCCESS; 408 } 409 410