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