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
, 8u, '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
, 0);
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 ObfDereferenceObject(ShutDownWaitEntry
->Thread
);
140 /* Finally free the entry */
141 ExFreePoolWithTag(ShutDownWaitEntry
, 0);
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_LOGO
);
168 Logo2
= InbvGetResourceAddress(IDB_LOGO
);
169 if ((Logo1
) && (Logo2
))
171 InbvBitBlt(Logo1
, 215, 352);
172 InbvBitBlt(Logo2
, 217, 111);
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");
183 /* Hang the system */
184 for (;;) HalHaltSystem();
189 PopShutdownSystem(IN POWER_ACTION SystemAction
)
191 /* Note should notify caller of NtPowerInformation(PowerShutdownNotification) */
194 DPRINT1("It's the final countdown...%lx\n", SystemAction
);
195 DbgUnLoadImageSymbols(NULL
, (PVOID
)-1, 0);
197 /* Run the thread on the boot processor */
198 KeSetSystemAffinityThread(1);
200 /* Now check what the caller wants */
201 switch (SystemAction
)
204 case PowerActionShutdownReset
:
206 /* Try platform driver first, then legacy */
207 //PopInvokeSystemStateHandler(PowerStateShutdownReset, NULL);
208 PopSetSystemPowerState(PowerSystemShutdown
, SystemAction
);
209 HalReturnToFirmware(HalRebootRoutine
);
212 case PowerActionShutdown
:
214 /* Check for group policy that says to use "it is now safe" screen */
215 if (PopShutdownPowerOffPolicy
)
217 /* FIXFIX: Switch to legacy shutdown handler */
218 //PopPowerStateHandlers[PowerStateShutdownOff].Handler = PopShutdownHandler;
221 case PowerActionShutdownOff
:
223 /* Call shutdown handler */
224 //PopInvokeSystemStateHandler(PowerStateShutdownOff, NULL);
227 PopSetSystemPowerState(PowerSystemShutdown
, SystemAction
);
228 PopShutdownHandler();
230 /* If that didn't work, call the HAL */
231 HalReturnToFirmware(HalPowerDownRoutine
);
238 /* Anything else should not happen */
239 KeBugCheckEx(INTERNAL_POWER_ERROR
, 5, 0, 0, 0);
244 PopGracefulShutdown(IN PVOID Context
)
246 PEPROCESS Process
= NULL
;
248 /* Process the registered waits and work items */
249 PopProcessShutDownLists();
251 /* Loop every process */
252 Process
= PsGetNextProcess(Process
);
255 /* Make sure this isn't the idle or initial process */
256 if ((Process
!= PsInitialSystemProcess
) && (Process
!= PsIdleProcess
))
259 DPRINT1("%15s is still RUNNING (%p)\n", Process
->ImageFileName
, Process
->UniqueProcessId
);
262 /* Get the next process */
263 Process
= PsGetNextProcess(Process
);
266 /* First, the HAL handles any "end of boot" special functionality */
267 DPRINT1("HAL shutting down\n");
270 /* In this step, the I/O manager does first-chance shutdown notification */
271 DPRINT1("I/O manager shutting down in phase 0\n");
274 /* In this step, all workers are killed and hives are flushed */
275 DPRINT1("Configuration Manager shutting down\n");
278 /* Note that modified pages should be written here (MiShutdownSystem) */
280 /* Flush all user files before we start shutting down IO */
281 /* This is where modified pages are written back by the IO manager */
285 /* In this step, the I/O manager does last-chance shutdown notification */
286 DPRINT1("I/O manager shutting down in phase 1\n");
288 CcWaitForCurrentLazyWriterActivity();
290 /* Note that here, we should broadcast the power IRP to devices */
292 /* In this step, the HAL disables any wake timers */
293 DPRINT1("Disabling wake timers\n");
294 HalSetWakeEnable(FALSE
);
296 /* And finally the power request is sent */
297 DPRINT1("Taking the system down\n");
298 PopShutdownSystem(PopAction
.Action
);
303 PopReadShutdownPolicy(VOID
)
305 UNICODE_STRING KeyString
;
306 OBJECT_ATTRIBUTES ObjectAttributes
;
310 UCHAR Buffer
[sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + sizeof(ULONG
)];
311 PKEY_VALUE_PARTIAL_INFORMATION Info
= (PVOID
)Buffer
;
313 /* Setup object attributes */
314 RtlInitUnicodeString(&KeyString
,
315 L
"\\Registry\\Machine\\Software\\Policies\\Microsoft\\Windows NT");
316 InitializeObjectAttributes(&ObjectAttributes
,
318 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
323 Status
= ZwOpenKey(&KeyHandle
, KEY_READ
, &ObjectAttributes
);
324 if (NT_SUCCESS(Status
))
326 /* Open the policy value and query it */
327 RtlInitUnicodeString(&KeyString
, L
"DontPowerOffAfterShutdown");
328 Status
= ZwQueryValueKey(KeyHandle
,
330 KeyValuePartialInformation
,
334 if ((NT_SUCCESS(Status
)) && (Info
->Type
== REG_DWORD
))
336 /* Read the policy */
337 PopShutdownPowerOffPolicy
= *Info
->Data
== 1;
345 /* PUBLIC FUNCTIONS **********************************************************/
352 PoQueueShutdownWorkItem(
353 _In_ PWORK_QUEUE_ITEM WorkItem
)
357 /* Acquire the shutdown list lock */
358 KeAcquireGuardedMutex(&PopShutdownListMutex
);
360 /* Check if the list is (already/still) available */
361 if (PopShutdownListAvailable
)
363 /* Insert the item into the list */
364 InsertTailList(&PopShutdownQueue
, &WorkItem
->List
);
365 Status
= STATUS_SUCCESS
;
369 /* We are already in shutdown */
370 Status
= STATUS_SYSTEM_SHUTDOWN
;
373 /* Release the list lock */
374 KeReleaseGuardedMutex(&PopShutdownListMutex
);
384 PoRequestShutdownEvent(OUT PVOID
*Event
)
389 /* Initialize to NULL */
390 if (Event
) *Event
= NULL
;
392 /* Request a shutdown wait */
393 Status
= PoRequestShutdownWait(PsGetCurrentThread());
394 if (!NT_SUCCESS(Status
))
399 /* Return the global shutdown event */
400 if (Event
) *Event
= &PopShutdownEvent
;
401 return STATUS_SUCCESS
;