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
9 /* INCLUDES ******************************************************************/
13 #include <cache/newcc.h>
18 /* GLOBALS *******************************************************************/
20 ULONG PopShutdownPowerOffPolicy
;
21 KEVENT PopShutdownEvent
;
22 PPOP_SHUTDOWN_WAIT_ENTRY PopShutdownThreadList
;
23 LIST_ENTRY PopShutdownQueue
;
24 KGUARDED_MUTEX PopShutdownListMutex
;
25 BOOLEAN PopShutdownListAvailable
;
28 /* PRIVATE FUNCTIONS *********************************************************/
32 PopInitShutdownList(VOID
)
36 /* Initialize the global shutdown event */
37 KeInitializeEvent(&PopShutdownEvent
, NotificationEvent
, FALSE
);
39 /* Initialize the shutdown lists */
40 PopShutdownThreadList
= NULL
;
41 InitializeListHead(&PopShutdownQueue
);
43 /* Initialize the shutdown list lock */
44 KeInitializeGuardedMutex(&PopShutdownListMutex
);
46 /* The list is available now */
47 PopShutdownListAvailable
= TRUE
;
52 PoRequestShutdownWait(
55 PPOP_SHUTDOWN_WAIT_ENTRY ShutDownWaitEntry
;
59 /* Allocate a new shutdown wait entry */
60 ShutDownWaitEntry
= ExAllocatePoolWithTag(PagedPool
, sizeof(*ShutDownWaitEntry
), 'LSoP');
61 if (ShutDownWaitEntry
== NULL
)
63 return STATUS_NO_MEMORY
;
66 /* Reference the thread and save it in the wait entry */
67 ObReferenceObject(Thread
);
68 ShutDownWaitEntry
->Thread
= Thread
;
70 /* Acquire the shutdown list lock */
71 KeAcquireGuardedMutex(&PopShutdownListMutex
);
73 /* Check if the list is still available */
74 if (PopShutdownListAvailable
)
76 /* Insert the item in the list */
77 ShutDownWaitEntry
->NextEntry
= PopShutdownThreadList
;
78 PopShutdownThreadList
= ShutDownWaitEntry
;
80 /* We are successful */
81 Status
= STATUS_SUCCESS
;
85 /* We cannot proceed, cleanup and return failure */
86 ObDereferenceObject(Thread
);
87 ExFreePoolWithTag(ShutDownWaitEntry
, 'LSoP');
88 Status
= STATUS_UNSUCCESSFUL
;
91 /* Release the list lock */
92 KeReleaseGuardedMutex(&PopShutdownListMutex
);
94 /* Return the status */
100 PopProcessShutDownLists(VOID
)
102 PPOP_SHUTDOWN_WAIT_ENTRY ShutDownWaitEntry
;
103 PWORK_QUEUE_ITEM WorkItem
;
104 PLIST_ENTRY ListEntry
;
106 /* First signal the shutdown event */
107 KeSetEvent(&PopShutdownEvent
, IO_NO_INCREMENT
, FALSE
);
109 /* Acquire the shutdown list lock */
110 KeAcquireGuardedMutex(&PopShutdownListMutex
);
112 /* Block any further attempts to register a shutdown event */
113 PopShutdownListAvailable
= FALSE
;
115 /* Release the list lock, since we are exclusively using the lists now */
116 KeReleaseGuardedMutex(&PopShutdownListMutex
);
118 /* Process the shutdown queue */
119 while (!IsListEmpty(&PopShutdownQueue
))
121 /* Get the head entry */
122 ListEntry
= RemoveHeadList(&PopShutdownQueue
);
123 WorkItem
= CONTAINING_RECORD(ListEntry
, WORK_QUEUE_ITEM
, List
);
125 /* Call the shutdown worker routine */
126 WorkItem
->WorkerRoutine(WorkItem
->Parameter
);
129 /* Now process the shutdown thread list */
130 while (PopShutdownThreadList
!= NULL
)
132 /* Get the top entry and remove it from the list */
133 ShutDownWaitEntry
= PopShutdownThreadList
;
134 PopShutdownThreadList
= PopShutdownThreadList
->NextEntry
;
136 /* Wait for the thread to finish and dereference it */
137 KeWaitForSingleObject(ShutDownWaitEntry
->Thread
, 0, 0, 0, 0);
138 ObDereferenceObject(ShutDownWaitEntry
->Thread
);
140 /* Finally free the entry */
141 ExFreePoolWithTag(ShutDownWaitEntry
, 'LSoP');
147 PopShutdownHandler(VOID
)
152 /* Stop all interrupts */
153 KeRaiseIrqlToDpcLevel();
156 /* Do we have boot video */
157 if (InbvIsBootDriverInstalled())
159 /* Yes we do, cleanup for shutdown screen */
160 if (!InbvCheckDisplayOwnership()) InbvAcquireDisplayOwnership();
162 InbvSolidColorFill(0, 0, 639, 479, 0);
163 InbvEnableDisplayString(TRUE
);
164 InbvSetScrollRegion(0, 0, 639, 479);
166 /* Display shutdown logo and message */
167 Logo1
= InbvGetResourceAddress(IDB_SHUTDOWN_MSG
);
168 Logo2
= InbvGetResourceAddress(IDB_LOGO_DEFAULT
);
169 if ((Logo1
) && (Logo2
))
171 /* 16px space between logo and message */
172 InbvBitBlt(Logo1
, 213, 354);
173 InbvBitBlt(Logo2
, 225, 114);
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");
184 /* Hang the system */
185 for (;;) HalHaltSystem();
190 PopShutdownSystem(IN POWER_ACTION SystemAction
)
192 /* Note should notify caller of NtPowerInformation(PowerShutdownNotification) */
195 DPRINT("It's the final countdown...%lx\n", SystemAction
);
196 DbgUnLoadImageSymbols(NULL
, (PVOID
)-1, 0);
198 /* Run the thread on the boot processor */
199 KeSetSystemAffinityThread(1);
201 /* Now check what the caller wants */
202 switch (SystemAction
)
205 case PowerActionShutdownReset
:
207 /* Try platform driver first, then legacy */
208 //PopInvokeSystemStateHandler(PowerStateShutdownReset, NULL);
209 PopSetSystemPowerState(PowerSystemShutdown
, SystemAction
);
210 HalReturnToFirmware(HalRebootRoutine
);
213 case PowerActionShutdown
:
215 /* Check for group policy that says to use "it is now safe" screen */
216 if (PopShutdownPowerOffPolicy
)
218 /* FIXFIX: Switch to legacy shutdown handler */
219 //PopPowerStateHandlers[PowerStateShutdownOff].Handler = PopShutdownHandler;
222 case PowerActionShutdownOff
:
224 /* Call shutdown handler */
225 //PopInvokeSystemStateHandler(PowerStateShutdownOff, NULL);
228 PopSetSystemPowerState(PowerSystemShutdown
, SystemAction
);
229 PopShutdownHandler();
231 /* If that didn't work, call the HAL */
232 HalReturnToFirmware(HalPowerDownRoutine
);
239 /* Anything else should not happen */
240 KeBugCheckEx(INTERNAL_POWER_ERROR
, 5, 0, 0, 0);
245 PopGracefulShutdown(IN PVOID Context
)
247 PEPROCESS Process
= NULL
;
249 /* Process the registered waits and work items */
250 PopProcessShutDownLists();
252 /* Loop every process */
253 Process
= PsGetNextProcess(Process
);
256 /* Make sure this isn't the idle or initial process */
257 if ((Process
!= PsInitialSystemProcess
) && (Process
!= PsIdleProcess
))
260 DPRINT1("%15s is still RUNNING (%p)\n", Process
->ImageFileName
, Process
->UniqueProcessId
);
263 /* Get the next process */
264 Process
= PsGetNextProcess(Process
);
267 /* First, the HAL handles any "end of boot" special functionality */
268 DPRINT("HAL shutting down\n");
271 /* Shut down the Shim cache if enabled */
272 ApphelpCacheShutdown();
274 /* In this step, the I/O manager does first-chance shutdown notification */
275 DPRINT("I/O manager shutting down in phase 0\n");
278 /* In this step, all workers are killed and hives are flushed */
279 DPRINT("Configuration Manager shutting down\n");
282 /* Shut down the Executive */
283 DPRINT("Executive shutting down\n");
286 /* Note that modified pages should be written here (MiShutdownSystem) */
289 /* Flush all user files before we start shutting down IO */
290 /* This is where modified pages are written back by the IO manager */
293 /* In this step, the I/O manager does last-chance shutdown notification */
294 DPRINT("I/O manager shutting down in phase 1\n");
296 CcWaitForCurrentLazyWriterActivity();
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.
303 /* Note that here, we should broadcast the power IRP to devices */
305 /* In this step, the HAL disables any wake timers */
306 DPRINT("Disabling wake timers\n");
307 HalSetWakeEnable(FALSE
);
309 /* And finally the power request is sent */
310 DPRINT("Taking the system down\n");
311 PopShutdownSystem(PopAction
.Action
);
316 PopReadShutdownPolicy(VOID
)
318 UNICODE_STRING KeyString
;
319 OBJECT_ATTRIBUTES ObjectAttributes
;
323 UCHAR Buffer
[sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + sizeof(ULONG
)];
324 PKEY_VALUE_PARTIAL_INFORMATION Info
= (PVOID
)Buffer
;
326 /* Setup object attributes */
327 RtlInitUnicodeString(&KeyString
,
328 L
"\\Registry\\Machine\\Software\\Policies\\Microsoft\\Windows NT");
329 InitializeObjectAttributes(&ObjectAttributes
,
331 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
336 Status
= ZwOpenKey(&KeyHandle
, KEY_READ
, &ObjectAttributes
);
337 if (NT_SUCCESS(Status
))
339 /* Open the policy value and query it */
340 RtlInitUnicodeString(&KeyString
, L
"DontPowerOffAfterShutdown");
341 Status
= ZwQueryValueKey(KeyHandle
,
343 KeyValuePartialInformation
,
347 if ((NT_SUCCESS(Status
)) && (Info
->Type
== REG_DWORD
))
349 /* Read the policy */
350 PopShutdownPowerOffPolicy
= *Info
->Data
== 1;
358 /* PUBLIC FUNCTIONS **********************************************************/
365 PoQueueShutdownWorkItem(
366 _In_ PWORK_QUEUE_ITEM WorkItem
)
370 /* Acquire the shutdown list lock */
371 KeAcquireGuardedMutex(&PopShutdownListMutex
);
373 /* Check if the list is (already/still) available */
374 if (PopShutdownListAvailable
)
376 /* Insert the item into the list */
377 InsertTailList(&PopShutdownQueue
, &WorkItem
->List
);
378 Status
= STATUS_SUCCESS
;
382 /* We are already in shutdown */
383 Status
= STATUS_SYSTEM_SHUTDOWN
;
386 /* Release the list lock */
387 KeReleaseGuardedMutex(&PopShutdownListMutex
);
397 PoRequestShutdownEvent(OUT PVOID
*Event
)
402 /* Initialize to NULL */
403 if (Event
) *Event
= NULL
;
405 /* Request a shutdown wait */
406 Status
= PoRequestShutdownWait(PsGetCurrentThread());
407 if (!NT_SUCCESS(Status
))
412 /* Return the global shutdown event */
413 if (Event
) *Event
= &PopShutdownEvent
;
414 return STATUS_SUCCESS
;