mirror of
https://github.com/reactos/reactos.git
synced 2024-07-05 04:06:22 +00:00
[NTOS]: Have I/O Manager Volume Device Objects register with the Power Manager so that they can receive dope.
[NTOS]: Reimplement NtShutdownSystem. [NTOS]: Implement NtSetSystemPowerState for the shutdown/reboot cases. [NTOS]: Use the dope from the volume device objects to flush all writeable (non-floppy) devices. Pending hard-disk changes are now flushed to disks before shutdown. [NTOS]: Flush \\REGISTRY during shutdown. This flushes all pending changes. [NTOS]: Call into Cc to flush lazy writer during shutdown. [NTOS]: Stop killing processes on shutdown. The kernel should not be doing this. [NTOS]: Don't only shutdown disk file systems, but also cdrom and tape. [NTOS]: Don't only notify drivers of first-chance shutdown -- also parse the last-change shutdown list. [NTOS]: Reference drivers registering for shutdown notifications so that they remain loaded for them to get the notification at shutdown. [NTOS]: Notify drivers that have registered/opened the Power State callback. [NTOS]: A lot of the Po* power state code is highly simplified, but provides a good roadmap to anyone interested in this functionality long-term. svn path=/trunk/; revision=46004
This commit is contained in:
parent
c14fc3dc56
commit
8a4845b409
|
@ -14,123 +14,40 @@
|
||||||
|
|
||||||
/* FUNCTIONS *****************************************************************/
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
|
||||||
VOID NTAPI
|
|
||||||
ShutdownThreadMain(PVOID Context)
|
|
||||||
{
|
|
||||||
SHUTDOWN_ACTION Action = (SHUTDOWN_ACTION)Context;
|
|
||||||
PUCHAR Logo1, Logo2;
|
|
||||||
ULONG i;
|
|
||||||
|
|
||||||
/* Run the thread on the boot processor */
|
|
||||||
KeSetSystemAffinityThread(1);
|
|
||||||
|
|
||||||
PspShutdownProcessManager();
|
|
||||||
|
|
||||||
CmShutdownSystem();
|
|
||||||
IoShutdownRegisteredFileSystems();
|
|
||||||
IoShutdownRegisteredDevices();
|
|
||||||
|
|
||||||
if (Action == ShutdownNoReboot)
|
|
||||||
{
|
|
||||||
/* Try the platform driver */
|
|
||||||
PopSetSystemPowerState(PowerSystemShutdown);
|
|
||||||
|
|
||||||
/* If that didn't work, try legacy switch off */
|
|
||||||
//HalReturnToFirmware(HalPowerDownRoutine);
|
|
||||||
|
|
||||||
/* If that still didn't work, stop all interrupts */
|
|
||||||
KeRaiseIrqlToDpcLevel();
|
|
||||||
_disable();
|
|
||||||
|
|
||||||
/* Do we have boot video */
|
|
||||||
if (InbvIsBootDriverInstalled())
|
|
||||||
{
|
|
||||||
/* Yes we do, cleanup for shutdown screen */
|
|
||||||
if (!InbvCheckDisplayOwnership()) InbvAcquireDisplayOwnership();
|
|
||||||
InbvResetDisplay();
|
|
||||||
InbvSolidColorFill(0, 0, 639, 479, 0);
|
|
||||||
InbvEnableDisplayString(TRUE);
|
|
||||||
InbvSetScrollRegion(0, 0, 639, 479);
|
|
||||||
|
|
||||||
/* Display shutdown logo and message */
|
|
||||||
Logo1 = InbvGetResourceAddress(IDB_SHUTDOWN_LOGO);
|
|
||||||
Logo2 = InbvGetResourceAddress(IDB_LOGO);
|
|
||||||
if ((Logo1) && (Logo2))
|
|
||||||
{
|
|
||||||
InbvBitBlt(Logo1, 215, 352);
|
|
||||||
InbvBitBlt(Logo2, 217, 111);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Do it in text-mode */
|
|
||||||
for (i = 0; i < 25; i++) InbvDisplayString("\n");
|
|
||||||
InbvDisplayString(" ");
|
|
||||||
InbvDisplayString("The system may be powered off now.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Hang the system */
|
|
||||||
for (;;) HalHaltSystem();
|
|
||||||
}
|
|
||||||
else if (Action == ShutdownReboot)
|
|
||||||
{
|
|
||||||
HalReturnToFirmware (HalRebootRoutine);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
HalReturnToFirmware (HalHaltRoutine);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
NTSTATUS NTAPI
|
|
||||||
NtSetSystemPowerState(IN POWER_ACTION SystemAction,
|
|
||||||
IN SYSTEM_POWER_STATE MinSystemState,
|
|
||||||
IN ULONG Flags)
|
|
||||||
{
|
|
||||||
/* Windows 2000 only */
|
|
||||||
return(STATUS_NOT_IMPLEMENTED);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @implemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
NTSTATUS NTAPI
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
NtShutdownSystem(IN SHUTDOWN_ACTION Action)
|
NtShutdownSystem(IN SHUTDOWN_ACTION Action)
|
||||||
{
|
{
|
||||||
NTSTATUS Status;
|
POWER_ACTION PowerAction;
|
||||||
HANDLE ThreadHandle;
|
|
||||||
PETHREAD ShutdownThread;
|
|
||||||
|
|
||||||
if (Action > ShutdownPowerOff)
|
/* Convert to power action */
|
||||||
|
if (Action == ShutdownNoReboot)
|
||||||
|
{
|
||||||
|
PowerAction = PowerActionShutdown;
|
||||||
|
}
|
||||||
|
else if (Action == ShutdownReboot)
|
||||||
|
{
|
||||||
|
PowerAction = PowerActionShutdownReset;
|
||||||
|
}
|
||||||
|
else if (Action == ShutdownPowerOff)
|
||||||
|
{
|
||||||
|
PowerAction = PowerActionShutdownOff;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return STATUS_INVALID_PARAMETER;
|
return STATUS_INVALID_PARAMETER;
|
||||||
Status = PsCreateSystemThread(&ThreadHandle,
|
|
||||||
THREAD_ALL_ACCESS,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
ShutdownThreadMain,
|
|
||||||
(PVOID)Action);
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
ASSERT(FALSE);
|
|
||||||
}
|
|
||||||
Status = ObReferenceObjectByHandle(ThreadHandle,
|
|
||||||
THREAD_ALL_ACCESS,
|
|
||||||
PsThreadType,
|
|
||||||
KernelMode,
|
|
||||||
(PVOID*)&ShutdownThread,
|
|
||||||
NULL);
|
|
||||||
NtClose(ThreadHandle);
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
ASSERT(FALSE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
KeSetPriorityThread(&ShutdownThread->Tcb, LOW_REALTIME_PRIORITY + 1);
|
/* Now call the power manager */
|
||||||
ObDereferenceObject(ShutdownThread);
|
DPRINT1("Setting state to: %lx\n", PowerAction);
|
||||||
|
return NtSetSystemPowerState(PowerAction,
|
||||||
return STATUS_SUCCESS;
|
PowerSystemSleeping3,
|
||||||
|
POWER_ACTION_OVERRIDE_APPS |
|
||||||
|
POWER_ACTION_DISABLE_WAKES |
|
||||||
|
POWER_ACTION_CRITICAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
|
@ -743,14 +743,14 @@ IoInitShutdownNotification(
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
IoShutdownRegisteredDevices(
|
IoShutdownSystem(
|
||||||
VOID
|
IN ULONG Phase
|
||||||
);
|
);
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
IoShutdownRegisteredFileSystems(
|
IopShutdownBaseFileSystems(
|
||||||
VOID
|
IN PLIST_ENTRY ListHead
|
||||||
);
|
);
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
|
@ -32,6 +32,228 @@
|
||||||
#define POTRACE(x, ...) DPRINT(__VA_ARGS__)
|
#define POTRACE(x, ...) DPRINT(__VA_ARGS__)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
typedef struct _PO_HIBER_PERF
|
||||||
|
{
|
||||||
|
ULONGLONG IoTicks;
|
||||||
|
ULONGLONG InitTicks;
|
||||||
|
ULONGLONG CopyTicks;
|
||||||
|
ULONGLONG StartCount;
|
||||||
|
ULONG ElapsedTime;
|
||||||
|
ULONG IoTime;
|
||||||
|
ULONG CopyTime;
|
||||||
|
ULONG InitTime;
|
||||||
|
ULONG PagesWritten;
|
||||||
|
ULONG PagesProcessed;
|
||||||
|
ULONG BytesCopied;
|
||||||
|
ULONG DumpCount;
|
||||||
|
ULONG FileRuns;
|
||||||
|
} PO_HIBER_PERF, *PPO_HIBER_PERF;
|
||||||
|
|
||||||
|
typedef struct _PO_MEMORY_IMAGE
|
||||||
|
{
|
||||||
|
ULONG Signature;
|
||||||
|
ULONG Version;
|
||||||
|
ULONG CheckSum;
|
||||||
|
ULONG LengthSelf;
|
||||||
|
PFN_NUMBER PageSelf;
|
||||||
|
ULONG PageSize;
|
||||||
|
ULONG ImageType;
|
||||||
|
LARGE_INTEGER SystemTime;
|
||||||
|
ULONGLONG InterruptTime;
|
||||||
|
ULONG FeatureFlags;
|
||||||
|
UCHAR HiberFlags;
|
||||||
|
UCHAR spare[3];
|
||||||
|
ULONG NoHiberPtes;
|
||||||
|
ULONG_PTR HiberVa;
|
||||||
|
PHYSICAL_ADDRESS HiberPte;
|
||||||
|
ULONG NoFreePages;
|
||||||
|
ULONG FreeMapCheck;
|
||||||
|
ULONG WakeCheck;
|
||||||
|
PFN_NUMBER TotalPages;
|
||||||
|
PFN_NUMBER FirstTablePage;
|
||||||
|
PFN_NUMBER LastFilePage;
|
||||||
|
PO_HIBER_PERF PerfInfo;
|
||||||
|
} PO_MEMORY_IMAGE, *PPO_MEMORY_IMAGE;
|
||||||
|
|
||||||
|
typedef struct _PO_MEMORY_RANGE_ARRAY_RANGE
|
||||||
|
{
|
||||||
|
PFN_NUMBER PageNo;
|
||||||
|
PFN_NUMBER StartPage;
|
||||||
|
PFN_NUMBER EndPage;
|
||||||
|
ULONG CheckSum;
|
||||||
|
} PO_MEMORY_RANGE_ARRAY_RANGE;
|
||||||
|
|
||||||
|
typedef struct _PO_MEMORY_RANGE_ARRAY_LINK
|
||||||
|
{
|
||||||
|
struct _PO_MEMORY_RANGE_ARRAY *Next;
|
||||||
|
PFN_NUMBER NextTable;
|
||||||
|
ULONG CheckSum;
|
||||||
|
ULONG EntryCount;
|
||||||
|
} PO_MEMORY_RANGE_ARRAY_LINK;
|
||||||
|
|
||||||
|
typedef struct _PO_MEMORY_RANGE_ARRAY
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
PO_MEMORY_RANGE_ARRAY_RANGE Range;
|
||||||
|
PO_MEMORY_RANGE_ARRAY_LINK Link;
|
||||||
|
};
|
||||||
|
} PO_MEMORY_RANGE_ARRAY, *PPO_MEMORY_RANGE_ARRAY;
|
||||||
|
|
||||||
|
typedef struct _POP_HIBER_CONTEXT
|
||||||
|
{
|
||||||
|
BOOLEAN WriteToFile;
|
||||||
|
BOOLEAN ReserveLoaderMemory;
|
||||||
|
BOOLEAN ReserveFreeMemory;
|
||||||
|
BOOLEAN VerifyOnWake;
|
||||||
|
BOOLEAN Reset;
|
||||||
|
UCHAR HiberFlags;
|
||||||
|
BOOLEAN LinkFile;
|
||||||
|
HANDLE LinkFileHandle;
|
||||||
|
PKSPIN_LOCK Lock;
|
||||||
|
BOOLEAN MapFrozen;
|
||||||
|
RTL_BITMAP MemoryMap;
|
||||||
|
LIST_ENTRY ClonedRanges;
|
||||||
|
ULONG ClonedRangeCount;
|
||||||
|
PLIST_ENTRY NextCloneRange;
|
||||||
|
PFN_NUMBER NextPreserve;
|
||||||
|
PMDL LoaderMdl;
|
||||||
|
PMDL Clones;
|
||||||
|
PUCHAR NextClone;
|
||||||
|
ULONG NoClones;
|
||||||
|
PMDL Spares;
|
||||||
|
ULONGLONG PagesOut;
|
||||||
|
PVOID IoPage;
|
||||||
|
PVOID CurrentMcb;
|
||||||
|
PVOID DumpStack;
|
||||||
|
PKPROCESSOR_STATE WakeState;
|
||||||
|
ULONG NoRanges;
|
||||||
|
ULONG_PTR HiberVa;
|
||||||
|
PHYSICAL_ADDRESS HiberPte;
|
||||||
|
NTSTATUS Status;
|
||||||
|
PPO_MEMORY_IMAGE MemoryImage;
|
||||||
|
PPO_MEMORY_RANGE_ARRAY TableHead;
|
||||||
|
PVOID CompressionWorkspace;
|
||||||
|
PUCHAR CompressedWriteBuffer;
|
||||||
|
PULONG PerformanceStats;
|
||||||
|
PVOID CompressionBlock;
|
||||||
|
PVOID DmaIO;
|
||||||
|
PVOID TemporaryHeap;
|
||||||
|
PO_HIBER_PERF PerfInfo;
|
||||||
|
} POP_HIBER_CONTEXT, *PPOP_HIBER_CONTEXT;
|
||||||
|
|
||||||
|
typedef struct _PO_NOTIFY_ORDER_LEVEL
|
||||||
|
{
|
||||||
|
KEVENT LevelReady;
|
||||||
|
ULONG DeviceCount;
|
||||||
|
ULONG ActiveCount;
|
||||||
|
LIST_ENTRY WaitSleep;
|
||||||
|
LIST_ENTRY ReadySleep;
|
||||||
|
LIST_ENTRY Pending;
|
||||||
|
LIST_ENTRY Complete;
|
||||||
|
LIST_ENTRY ReadyS0;
|
||||||
|
LIST_ENTRY WaitS0;
|
||||||
|
} PO_NOTIFY_ORDER_LEVEL, *PPO_NOTIFY_ORDER_LEVEL;
|
||||||
|
|
||||||
|
typedef struct _POP_SHUTDOWN_BUG_CHECK
|
||||||
|
{
|
||||||
|
HANDLE ThreadHandle;
|
||||||
|
HANDLE ThreadId;
|
||||||
|
HANDLE ProcessId;
|
||||||
|
ULONG Code;
|
||||||
|
ULONG_PTR Parameter1;
|
||||||
|
ULONG_PTR Parameter2;
|
||||||
|
ULONG_PTR Parameter3;
|
||||||
|
ULONG_PTR Parameter4;
|
||||||
|
} POP_SHUTDOWN_BUG_CHECK, *PPOP_SHUTDOWN_BUG_CHECK;
|
||||||
|
|
||||||
|
typedef struct _POP_DEVICE_POWER_IRP
|
||||||
|
{
|
||||||
|
SINGLE_LIST_ENTRY Free;
|
||||||
|
PIRP Irp;
|
||||||
|
PPO_DEVICE_NOTIFY Notify;
|
||||||
|
LIST_ENTRY Pending;
|
||||||
|
LIST_ENTRY Complete;
|
||||||
|
LIST_ENTRY Abort;
|
||||||
|
LIST_ENTRY Failed;
|
||||||
|
} POP_DEVICE_POWER_IRP, *PPOP_DEVICE_POWER_IRP;
|
||||||
|
|
||||||
|
typedef struct _PO_DEVICE_NOTIFY_ORDER
|
||||||
|
{
|
||||||
|
ULONG DevNodeSequence;
|
||||||
|
PDEVICE_OBJECT *WarmEjectPdoPointer;
|
||||||
|
PO_NOTIFY_ORDER_LEVEL OrderLevel[8];
|
||||||
|
} PO_DEVICE_NOTIFY_ORDER, *PPO_DEVICE_NOTIFY_ORDER;
|
||||||
|
|
||||||
|
typedef struct _POP_DEVICE_SYS_STATE
|
||||||
|
{
|
||||||
|
UCHAR IrpMinor;
|
||||||
|
SYSTEM_POWER_STATE SystemState;
|
||||||
|
PKEVENT Event;
|
||||||
|
KSPIN_LOCK SpinLock;
|
||||||
|
PKTHREAD Thread;
|
||||||
|
BOOLEAN GetNewDeviceList;
|
||||||
|
PO_DEVICE_NOTIFY_ORDER Order;
|
||||||
|
NTSTATUS Status;
|
||||||
|
PDEVICE_OBJECT FailedDevice;
|
||||||
|
BOOLEAN Waking;
|
||||||
|
BOOLEAN Cancelled;
|
||||||
|
BOOLEAN IgnoreErrors;
|
||||||
|
BOOLEAN IgnoreNotImplemented;
|
||||||
|
BOOLEAN _WaitAny;
|
||||||
|
BOOLEAN _WaitAll;
|
||||||
|
LIST_ENTRY PresentIrpQueue;
|
||||||
|
POP_DEVICE_POWER_IRP Head;
|
||||||
|
POP_DEVICE_POWER_IRP PowerIrpState[20];
|
||||||
|
} POP_DEVICE_SYS_STATE, *PPOP_DEVICE_SYS_STATE;
|
||||||
|
|
||||||
|
typedef struct _POP_POWER_ACTION
|
||||||
|
{
|
||||||
|
UCHAR Updates;
|
||||||
|
UCHAR State;
|
||||||
|
BOOLEAN Shutdown;
|
||||||
|
POWER_ACTION Action;
|
||||||
|
SYSTEM_POWER_STATE LightestState;
|
||||||
|
ULONG Flags;
|
||||||
|
NTSTATUS Status;
|
||||||
|
UCHAR IrpMinor;
|
||||||
|
SYSTEM_POWER_STATE SystemState;
|
||||||
|
SYSTEM_POWER_STATE NextSystemState;
|
||||||
|
PPOP_SHUTDOWN_BUG_CHECK ShutdownBugCode;
|
||||||
|
PPOP_DEVICE_SYS_STATE DevState;
|
||||||
|
PPOP_HIBER_CONTEXT HiberContext;
|
||||||
|
ULONGLONG WakeTime;
|
||||||
|
ULONGLONG SleepTime;
|
||||||
|
} POP_POWER_ACTION, *PPOP_POWER_ACTION;
|
||||||
|
|
||||||
|
typedef enum _POP_DEVICE_IDLE_TYPE
|
||||||
|
{
|
||||||
|
DeviceIdleNormal,
|
||||||
|
DeviceIdleDisk,
|
||||||
|
} POP_DEVICE_IDLE_TYPE, *PPOP_DEVICE_IDLE_TYPE;
|
||||||
|
|
||||||
|
typedef struct _POWER_CHANNEL_SUMMARY
|
||||||
|
{
|
||||||
|
ULONG Signature;
|
||||||
|
ULONG TotalCount;
|
||||||
|
ULONG D0Count;
|
||||||
|
LIST_ENTRY NotifyList;
|
||||||
|
} POWER_CHANNEL_SUMMARY, *PPOWER_CHANNEL_SUMMARY;
|
||||||
|
|
||||||
|
typedef struct _DEVICE_OBJECT_POWER_EXTENSION
|
||||||
|
{
|
||||||
|
ULONG IdleCount;
|
||||||
|
ULONG ConservationIdleTime;
|
||||||
|
ULONG PerformanceIdleTime;
|
||||||
|
PDEVICE_OBJECT DeviceObject;
|
||||||
|
LIST_ENTRY IdleList;
|
||||||
|
DEVICE_POWER_STATE State;
|
||||||
|
LIST_ENTRY NotifySourceList;
|
||||||
|
LIST_ENTRY NotifyTargetList;
|
||||||
|
POWER_CHANNEL_SUMMARY PowerChannelSummary;
|
||||||
|
LIST_ENTRY Volume;
|
||||||
|
} DEVICE_OBJECT_POWER_EXTENSION, *PDEVICE_OBJECT_POWER_EXTENSION;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Initialization routines
|
// Initialization routines
|
||||||
//
|
//
|
||||||
|
@ -47,6 +269,21 @@ PoInitializePrcb(
|
||||||
IN PKPRCB Prcb
|
IN PKPRCB Prcb
|
||||||
);
|
);
|
||||||
|
|
||||||
|
//
|
||||||
|
// I/O Routines
|
||||||
|
//
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
PoInitializeDeviceObject(
|
||||||
|
IN OUT PDEVOBJ_EXTENSION DeviceObjectExtension
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
PoVolumeDevice(
|
||||||
|
IN PDEVICE_OBJECT DeviceObject
|
||||||
|
);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Power State routines
|
// Power State routines
|
||||||
//
|
//
|
||||||
|
@ -78,7 +315,33 @@ PoNotifySystemTimeSet(
|
||||||
VOID
|
VOID
|
||||||
);
|
);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Shutdown routines
|
||||||
|
//
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
PopReadShutdownPolicy(
|
||||||
|
VOID
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
PopGracefulShutdown(
|
||||||
|
IN PVOID Context
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
PopFlushVolumes(
|
||||||
|
IN BOOLEAN ShuttingDown
|
||||||
|
);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Global data inside the Power Manager
|
// Global data inside the Power Manager
|
||||||
//
|
//
|
||||||
extern PDEVICE_NODE PopSystemPowerDeviceNode;
|
extern PDEVICE_NODE PopSystemPowerDeviceNode;
|
||||||
|
extern KGUARDED_MUTEX PopVolumeLock;
|
||||||
|
extern LIST_ENTRY PopVolumeDevices;
|
||||||
|
extern KSPIN_LOCK PopDopeGlobalLock;
|
||||||
|
extern POP_POWER_ACTION PopAction;
|
||||||
|
|
||||||
|
|
|
@ -17,9 +17,11 @@
|
||||||
/* GLOBALS ********************************************************************/
|
/* GLOBALS ********************************************************************/
|
||||||
|
|
||||||
ULONG IopDeviceObjectNumber = 0;
|
ULONG IopDeviceObjectNumber = 0;
|
||||||
|
|
||||||
LIST_ENTRY ShutdownListHead, LastChanceShutdownListHead;
|
LIST_ENTRY ShutdownListHead, LastChanceShutdownListHead;
|
||||||
KSPIN_LOCK ShutdownListLock;
|
KSPIN_LOCK ShutdownListLock;
|
||||||
|
extern LIST_ENTRY IopDiskFsListHead;
|
||||||
|
extern LIST_ENTRY IopCdRomFsListHead;
|
||||||
|
extern LIST_ENTRY IopTapeFsListHead;
|
||||||
|
|
||||||
/* PRIVATE FUNCTIONS **********************************************************/
|
/* PRIVATE FUNCTIONS **********************************************************/
|
||||||
|
|
||||||
|
@ -95,7 +97,15 @@ IopAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice,
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
IoShutdownRegisteredDevices(VOID)
|
IoShutdownPnpDevices(VOID)
|
||||||
|
{
|
||||||
|
/* This routine is only used by Driver Verifier to validate shutdown */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
IoShutdownSystem(IN ULONG Phase)
|
||||||
{
|
{
|
||||||
PLIST_ENTRY ListEntry;
|
PLIST_ENTRY ListEntry;
|
||||||
PDEVICE_OBJECT DeviceObject;
|
PDEVICE_OBJECT DeviceObject;
|
||||||
|
@ -108,7 +118,13 @@ IoShutdownRegisteredDevices(VOID)
|
||||||
/* Initialize an event to wait on */
|
/* Initialize an event to wait on */
|
||||||
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
||||||
|
|
||||||
/* Get the first entry and start looping */
|
/* What phase? */
|
||||||
|
if (Phase == 0)
|
||||||
|
{
|
||||||
|
/* Shutdown PnP */
|
||||||
|
IoShutdownPnpDevices();
|
||||||
|
|
||||||
|
/* Loop first-chance shutdown notifications */
|
||||||
ListEntry = ExInterlockedRemoveHeadList(&ShutdownListHead,
|
ListEntry = ExInterlockedRemoveHeadList(&ShutdownListHead,
|
||||||
&ShutdownListLock);
|
&ShutdownListLock);
|
||||||
while (ListEntry)
|
while (ListEntry)
|
||||||
|
@ -136,6 +152,9 @@ IoShutdownRegisteredDevices(VOID)
|
||||||
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get rid of our reference to it */
|
||||||
|
ObDereferenceObject(DeviceObject);
|
||||||
|
|
||||||
/* Free the shutdown entry and reset the event */
|
/* Free the shutdown entry and reset the event */
|
||||||
ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
|
ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
|
||||||
KeClearEvent(&Event);
|
KeClearEvent(&Event);
|
||||||
|
@ -144,6 +163,59 @@ IoShutdownRegisteredDevices(VOID)
|
||||||
ListEntry = ExInterlockedRemoveHeadList(&ShutdownListHead,
|
ListEntry = ExInterlockedRemoveHeadList(&ShutdownListHead,
|
||||||
&ShutdownListLock);
|
&ShutdownListLock);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else if (Phase == 1)
|
||||||
|
{
|
||||||
|
/* Shutdown disk file systems */
|
||||||
|
IopShutdownBaseFileSystems(&IopDiskFsListHead);
|
||||||
|
|
||||||
|
/* Shutdown cdrom file systems */
|
||||||
|
IopShutdownBaseFileSystems(&IopCdRomFsListHead);
|
||||||
|
|
||||||
|
/* Shutdown tape filesystems */
|
||||||
|
IopShutdownBaseFileSystems(&IopTapeFsListHead);
|
||||||
|
|
||||||
|
/* Loop last-chance shutdown notifications */
|
||||||
|
ListEntry = ExInterlockedRemoveHeadList(&LastChanceShutdownListHead,
|
||||||
|
&ShutdownListLock);
|
||||||
|
while (ListEntry)
|
||||||
|
{
|
||||||
|
/* Get the shutdown entry */
|
||||||
|
ShutdownEntry = CONTAINING_RECORD(ListEntry,
|
||||||
|
SHUTDOWN_ENTRY,
|
||||||
|
ShutdownList);
|
||||||
|
|
||||||
|
/* Get the attached device */
|
||||||
|
DeviceObject = IoGetAttachedDevice(ShutdownEntry->DeviceObject);
|
||||||
|
|
||||||
|
/* Build the shutdown IRP and call the driver */
|
||||||
|
Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
|
||||||
|
DeviceObject,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
&Event,
|
||||||
|
&StatusBlock);
|
||||||
|
Status = IoCallDriver(DeviceObject, Irp);
|
||||||
|
if (Status == STATUS_PENDING)
|
||||||
|
{
|
||||||
|
/* Wait on the driver */
|
||||||
|
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get rid of our reference to it */
|
||||||
|
ObDereferenceObject(DeviceObject);
|
||||||
|
|
||||||
|
/* Free the shutdown entry and reset the event */
|
||||||
|
ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
|
||||||
|
KeClearEvent(&Event);
|
||||||
|
|
||||||
|
/* Go to the next entry */
|
||||||
|
ListEntry = ExInterlockedRemoveHeadList(&LastChanceShutdownListHead,
|
||||||
|
&ShutdownListLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
|
@ -844,6 +916,9 @@ IoCreateDevice(IN PDRIVER_OBJECT DriverObject,
|
||||||
DeviceObjectExtension->Type = IO_TYPE_DEVICE_OBJECT_EXTENSION;
|
DeviceObjectExtension->Type = IO_TYPE_DEVICE_OBJECT_EXTENSION;
|
||||||
DeviceObjectExtension->Size = 0;
|
DeviceObjectExtension->Size = 0;
|
||||||
|
|
||||||
|
/* Initialize with Power Manager */
|
||||||
|
PoInitializeDeviceObject(DeviceObjectExtension);
|
||||||
|
|
||||||
/* Link the Object and Extension */
|
/* Link the Object and Extension */
|
||||||
DeviceObjectExtension->DeviceObject = CreatedDeviceObject;
|
DeviceObjectExtension->DeviceObject = CreatedDeviceObject;
|
||||||
CreatedDeviceObject->DeviceObjectExtension = DeviceObjectExtension;
|
CreatedDeviceObject->DeviceObjectExtension = DeviceObjectExtension;
|
||||||
|
@ -933,6 +1008,9 @@ IoCreateDevice(IN PDRIVER_OBJECT DriverObject,
|
||||||
CreatedDeviceObject->DriverObject = DriverObject;
|
CreatedDeviceObject->DriverObject = DriverObject;
|
||||||
IopEditDeviceList(DriverObject, CreatedDeviceObject, IopAdd);
|
IopEditDeviceList(DriverObject, CreatedDeviceObject, IopAdd);
|
||||||
|
|
||||||
|
/* Link with the power manager */
|
||||||
|
if (CreatedDeviceObject->Vpb) PoVolumeDevice(CreatedDeviceObject);
|
||||||
|
|
||||||
/* Close the temporary handle and return to caller */
|
/* Close the temporary handle and return to caller */
|
||||||
ObCloseHandle(TempHandle, KernelMode);
|
ObCloseHandle(TempHandle, KernelMode);
|
||||||
*DeviceObject = CreatedDeviceObject;
|
*DeviceObject = CreatedDeviceObject;
|
||||||
|
@ -1352,6 +1430,9 @@ IoRegisterLastChanceShutdownNotification(IN PDEVICE_OBJECT DeviceObject)
|
||||||
/* Set the DO */
|
/* Set the DO */
|
||||||
Entry->DeviceObject = DeviceObject;
|
Entry->DeviceObject = DeviceObject;
|
||||||
|
|
||||||
|
/* Reference it so it doesn't go away */
|
||||||
|
ObReferenceObject(DeviceObject);
|
||||||
|
|
||||||
/* Insert it into the list */
|
/* Insert it into the list */
|
||||||
ExInterlockedInsertHeadList(&LastChanceShutdownListHead,
|
ExInterlockedInsertHeadList(&LastChanceShutdownListHead,
|
||||||
&Entry->ShutdownList,
|
&Entry->ShutdownList,
|
||||||
|
@ -1380,6 +1461,9 @@ IoRegisterShutdownNotification(PDEVICE_OBJECT DeviceObject)
|
||||||
/* Set the DO */
|
/* Set the DO */
|
||||||
Entry->DeviceObject = DeviceObject;
|
Entry->DeviceObject = DeviceObject;
|
||||||
|
|
||||||
|
/* Reference it so it doesn't go away */
|
||||||
|
ObReferenceObject(DeviceObject);
|
||||||
|
|
||||||
/* Insert it into the list */
|
/* Insert it into the list */
|
||||||
ExInterlockedInsertHeadList(&ShutdownListHead,
|
ExInterlockedInsertHeadList(&ShutdownListHead,
|
||||||
&Entry->ShutdownList,
|
&Entry->ShutdownList,
|
||||||
|
@ -1420,6 +1504,9 @@ IoUnregisterShutdownNotification(PDEVICE_OBJECT DeviceObject)
|
||||||
|
|
||||||
/* Free the entry */
|
/* Free the entry */
|
||||||
ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
|
ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
|
||||||
|
|
||||||
|
/* Get rid of our reference to it */
|
||||||
|
ObDereferenceObject(DeviceObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Go to the next entry */
|
/* Go to the next entry */
|
||||||
|
@ -1444,6 +1531,9 @@ IoUnregisterShutdownNotification(PDEVICE_OBJECT DeviceObject)
|
||||||
|
|
||||||
/* Free the entry */
|
/* Free the entry */
|
||||||
ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
|
ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
|
||||||
|
|
||||||
|
/* Get rid of our reference to it */
|
||||||
|
ObDereferenceObject(DeviceObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Go to the next entry */
|
/* Go to the next entry */
|
||||||
|
|
|
@ -245,7 +245,7 @@ IopNotifyFileSystemChange(IN PDEVICE_OBJECT DeviceObject,
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
IoShutdownRegisteredFileSystems(VOID)
|
IopShutdownBaseFileSystems(IN PLIST_ENTRY ListHead)
|
||||||
{
|
{
|
||||||
PLIST_ENTRY ListEntry;
|
PLIST_ENTRY ListEntry;
|
||||||
PDEVICE_OBJECT DeviceObject;
|
PDEVICE_OBJECT DeviceObject;
|
||||||
|
@ -260,8 +260,8 @@ IoShutdownRegisteredFileSystems(VOID)
|
||||||
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
||||||
|
|
||||||
/* Get the first entry and start looping */
|
/* Get the first entry and start looping */
|
||||||
ListEntry = IopDiskFsListHead.Flink;
|
ListEntry = ListHead->Flink;
|
||||||
while (ListEntry != &IopDiskFsListHead)
|
while (ListEntry != ListHead)
|
||||||
{
|
{
|
||||||
/* Get the device object */
|
/* Get the device object */
|
||||||
DeviceObject = CONTAINING_RECORD(ListEntry,
|
DeviceObject = CONTAINING_RECORD(ListEntry,
|
||||||
|
|
|
@ -438,8 +438,10 @@
|
||||||
<file>obwait.c</file>
|
<file>obwait.c</file>
|
||||||
</directory>
|
</directory>
|
||||||
<directory name="po">
|
<directory name="po">
|
||||||
<file>power.c</file>
|
|
||||||
<file>events.c</file>
|
<file>events.c</file>
|
||||||
|
<file>power.c</file>
|
||||||
|
<file>poshtdwn.c</file>
|
||||||
|
<file>povolume.c</file>
|
||||||
</directory>
|
</directory>
|
||||||
<directory name="ps">
|
<directory name="ps">
|
||||||
<if property="ARCH" value="i386">
|
<if property="ARCH" value="i386">
|
||||||
|
|
196
reactos/ntoskrnl/po/poshtdwn.c
Normal file
196
reactos/ntoskrnl/po/poshtdwn.c
Normal file
|
@ -0,0 +1,196 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS Kernel
|
||||||
|
* LICENSE: BSD - See COPYING.ARM in the top level directory
|
||||||
|
* FILE: ntoskrnl/po/poshtdwn.c
|
||||||
|
* PURPOSE: Power Manager Shutdown Code
|
||||||
|
* PROGRAMMERS: ReactOS Portable Systems Group
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* INCLUDES ******************************************************************/
|
||||||
|
|
||||||
|
#include <ntoskrnl.h>
|
||||||
|
#define NDEBUG
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
/* GLOBALS *******************************************************************/
|
||||||
|
|
||||||
|
ULONG PopShutdownPowerOffPolicy;
|
||||||
|
|
||||||
|
/* PRIVATE FUNCTIONS *********************************************************/
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
PopShutdownHandler(VOID)
|
||||||
|
{
|
||||||
|
PUCHAR Logo1, Logo2;
|
||||||
|
ULONG i;
|
||||||
|
|
||||||
|
/* Stop all interrupts */
|
||||||
|
KeRaiseIrqlToDpcLevel();
|
||||||
|
_disable();
|
||||||
|
|
||||||
|
/* Do we have boot video */
|
||||||
|
if (InbvIsBootDriverInstalled())
|
||||||
|
{
|
||||||
|
/* Yes we do, cleanup for shutdown screen */
|
||||||
|
if (!InbvCheckDisplayOwnership()) InbvAcquireDisplayOwnership();
|
||||||
|
InbvResetDisplay();
|
||||||
|
InbvSolidColorFill(0, 0, 639, 479, 0);
|
||||||
|
InbvEnableDisplayString(TRUE);
|
||||||
|
InbvSetScrollRegion(0, 0, 639, 479);
|
||||||
|
|
||||||
|
/* Display shutdown logo and message */
|
||||||
|
Logo1 = InbvGetResourceAddress(IDB_SHUTDOWN_LOGO);
|
||||||
|
Logo2 = InbvGetResourceAddress(IDB_LOGO);
|
||||||
|
if ((Logo1) && (Logo2))
|
||||||
|
{
|
||||||
|
InbvBitBlt(Logo1, 215, 352);
|
||||||
|
InbvBitBlt(Logo2, 217, 111);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Do it in text-mode */
|
||||||
|
for (i = 0; i < 25; i++) InbvDisplayString("\n");
|
||||||
|
InbvDisplayString(" ");
|
||||||
|
InbvDisplayString("The system may be powered off now.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hang the system */
|
||||||
|
for (;;) HalHaltSystem();
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
PopShutdownSystem(IN POWER_ACTION SystemAction)
|
||||||
|
{
|
||||||
|
/* Note should notify caller of NtPowerInformation(PowerShutdownNotification) */
|
||||||
|
|
||||||
|
/* Unload symbols */
|
||||||
|
DPRINT1("It's the final countdown...%lx\n", SystemAction);
|
||||||
|
DbgUnLoadImageSymbols(NULL, (PVOID)-1, 0);
|
||||||
|
|
||||||
|
/* Run the thread on the boot processor */
|
||||||
|
KeSetSystemAffinityThread(1);
|
||||||
|
|
||||||
|
/* Now check what the caller wants */
|
||||||
|
switch (SystemAction)
|
||||||
|
{
|
||||||
|
/* Reset */
|
||||||
|
case PowerActionShutdownReset:
|
||||||
|
|
||||||
|
/* Try platform driver first, then legacy */
|
||||||
|
//PopInvokeSystemStateHandler(PowerStateShutdownReset, NULL);
|
||||||
|
HalReturnToFirmware(HalRebootRoutine);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PowerActionShutdown:
|
||||||
|
|
||||||
|
/* Check for group policy that says to use "it is now safe" screen */
|
||||||
|
if (PopShutdownPowerOffPolicy)
|
||||||
|
{
|
||||||
|
/* FIXFIX: Switch to legacy shutdown handler */
|
||||||
|
//PopPowerStateHandlers[PowerStateShutdownOff].Handler = PopShutdownHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PowerActionShutdownOff:
|
||||||
|
|
||||||
|
/* Call shutdown handler */
|
||||||
|
//PopInvokeSystemStateHandler(PowerStateShutdownOff, NULL);
|
||||||
|
|
||||||
|
/* ReactOS Hack */
|
||||||
|
PopSetSystemPowerState(PowerSystemShutdown);
|
||||||
|
PopShutdownHandler();
|
||||||
|
|
||||||
|
/* If that didn't work, call the HAL */
|
||||||
|
HalReturnToFirmware(HalPowerDownRoutine);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Anything else should not happen */
|
||||||
|
KeBugCheckEx(INTERNAL_POWER_ERROR, 5, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
PopGracefulShutdown(IN PVOID Context)
|
||||||
|
{
|
||||||
|
/* First, the HAL handles any "end of boot" special functionality */
|
||||||
|
DPRINT1("HAL shutting down\n");
|
||||||
|
HalEndOfBoot();
|
||||||
|
|
||||||
|
/* In this step, the I/O manager does first-chance shutdown notification */
|
||||||
|
DPRINT1("I/O manager shutting down in phase 0\n");
|
||||||
|
IoShutdownSystem(0);
|
||||||
|
|
||||||
|
/* In this step, all workers are killed and hives are flushed */
|
||||||
|
DPRINT1("Configuration Manager shutting down\n");
|
||||||
|
CmShutdownSystem();
|
||||||
|
|
||||||
|
/* Note that modified pages should be written here (MiShutdownSystem) */
|
||||||
|
|
||||||
|
/* In this step, the I/O manager does last-chance shutdown notification */
|
||||||
|
DPRINT1("I/O manager shutting down in phase 1\n");
|
||||||
|
IoShutdownSystem(1);
|
||||||
|
CcWaitForCurrentLazyWriterActivity();
|
||||||
|
|
||||||
|
/* Note that here, we should broadcast the power IRP to devices */
|
||||||
|
|
||||||
|
/* In this step, the HAL disables any wake timers */
|
||||||
|
DPRINT1("Disabling wake timers\n");
|
||||||
|
HalSetWakeEnable(FALSE);
|
||||||
|
|
||||||
|
/* And finally the power request is sent */
|
||||||
|
DPRINT1("Taking the system down\n");
|
||||||
|
PopShutdownSystem(PopAction.Action);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
PopReadShutdownPolicy(VOID)
|
||||||
|
{
|
||||||
|
UNICODE_STRING KeyString;
|
||||||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||||
|
NTSTATUS Status;
|
||||||
|
HANDLE KeyHandle;
|
||||||
|
ULONG Length;
|
||||||
|
UCHAR Buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
|
||||||
|
PKEY_VALUE_PARTIAL_INFORMATION Info = (PVOID)Buffer;
|
||||||
|
|
||||||
|
/* Setup object attributes */
|
||||||
|
RtlInitUnicodeString(&KeyString,
|
||||||
|
L"\\Registry\\Machine\\Software\\Policies\\Microsoft\\Windows NT");
|
||||||
|
InitializeObjectAttributes(&ObjectAttributes,
|
||||||
|
&KeyString,
|
||||||
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
/* Open the key */
|
||||||
|
Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* Open the policy value and query it */
|
||||||
|
RtlInitUnicodeString(&KeyString, L"DontPowerOffAfterShutdown");
|
||||||
|
Status = ZwQueryValueKey(KeyHandle,
|
||||||
|
&KeyString,
|
||||||
|
KeyValuePartialInformation,
|
||||||
|
&Info,
|
||||||
|
sizeof(Info),
|
||||||
|
&Length);
|
||||||
|
if ((NT_SUCCESS(Status)) && (Info->Type == REG_DWORD))
|
||||||
|
{
|
||||||
|
/* Read the policy */
|
||||||
|
PopShutdownPowerOffPolicy = *Info->Data == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Close the key */
|
||||||
|
ZwClose(KeyHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PUBLIC FUNCTIONS **********************************************************/
|
||||||
|
|
334
reactos/ntoskrnl/po/povolume.c
Normal file
334
reactos/ntoskrnl/po/povolume.c
Normal file
|
@ -0,0 +1,334 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS Kernel
|
||||||
|
* LICENSE: BSD - See COPYING.ARM in the top level directory
|
||||||
|
* FILE: ntoskrnl/po/povolume.c
|
||||||
|
* PURPOSE: Power Manager DOPE and Volume Management
|
||||||
|
* PROGRAMMERS: ReactOS Portable Systems Group
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* INCLUDES ******************************************************************/
|
||||||
|
|
||||||
|
#include <ntoskrnl.h>
|
||||||
|
#define NDEBUG
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
/* GLOBALS *******************************************************************/
|
||||||
|
|
||||||
|
typedef struct _POP_FLUSH_VOLUME
|
||||||
|
{
|
||||||
|
LIST_ENTRY List;
|
||||||
|
LONG Count;
|
||||||
|
KEVENT Wait;
|
||||||
|
} POP_FLUSH_VOLUME, *PPOP_FLUSH_VOLUME;
|
||||||
|
|
||||||
|
ULONG PopFlushPolicy = 0;
|
||||||
|
|
||||||
|
KGUARDED_MUTEX PopVolumeLock;
|
||||||
|
LIST_ENTRY PopVolumeDevices;
|
||||||
|
KSPIN_LOCK PopDopeGlobalLock;
|
||||||
|
|
||||||
|
/* PRIVATE FUNCTIONS *********************************************************/
|
||||||
|
|
||||||
|
PDEVICE_OBJECT_POWER_EXTENSION
|
||||||
|
NTAPI
|
||||||
|
PopGetDope(IN PDEVICE_OBJECT DeviceObject)
|
||||||
|
{
|
||||||
|
PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
|
||||||
|
PDEVICE_OBJECT_POWER_EXTENSION Dope;
|
||||||
|
KIRQL OldIrql;
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
/* If the device already has the dope, return it */
|
||||||
|
DeviceExtension = IoGetDevObjExtension(DeviceObject);
|
||||||
|
if (DeviceExtension->Dope) goto Return;
|
||||||
|
|
||||||
|
/* Allocate some dope for the device */
|
||||||
|
Dope = ExAllocatePoolWithTag(NonPagedPool,
|
||||||
|
sizeof(DEVICE_OBJECT_POWER_EXTENSION),
|
||||||
|
'Dope');
|
||||||
|
if (!Dope) goto Return;
|
||||||
|
|
||||||
|
/* Initialize the initial contents of the dope */
|
||||||
|
RtlZeroMemory(Dope, sizeof(DEVICE_OBJECT_POWER_EXTENSION));
|
||||||
|
Dope->DeviceObject = DeviceObject;
|
||||||
|
Dope->State = PowerDeviceUnspecified;
|
||||||
|
InitializeListHead(&Dope->IdleList);
|
||||||
|
|
||||||
|
/* Make sure only one caller can assign dope to a device */
|
||||||
|
KeAcquireSpinLock(&PopDopeGlobalLock, &OldIrql);
|
||||||
|
|
||||||
|
/* Make sure the device still has no dope */
|
||||||
|
if (!DeviceExtension->Dope)
|
||||||
|
{
|
||||||
|
/* Give the local dope to this device, and remember we won the race */
|
||||||
|
DeviceExtension->Dope = (PVOID)Dope;
|
||||||
|
Dope = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allow other dope transactions now */
|
||||||
|
KeReleaseSpinLock(&PopDopeGlobalLock, OldIrql);
|
||||||
|
|
||||||
|
/* Check if someone other than us already assigned the dope, so free ours */
|
||||||
|
if (Dope) ExFreePoolWithTag(Dope, 'Dope');
|
||||||
|
|
||||||
|
/* Return the dope to the caller */
|
||||||
|
Return:
|
||||||
|
return (PDEVICE_OBJECT_POWER_EXTENSION)DeviceExtension->Dope;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
PoVolumeDevice(IN PDEVICE_OBJECT DeviceObject)
|
||||||
|
{
|
||||||
|
PDEVICE_OBJECT_POWER_EXTENSION Dope;
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
/* Get dope from the device (if the device has no dope, it will receive some) */
|
||||||
|
DPRINT1("New volume: %p\n", DeviceObject);
|
||||||
|
Dope = PopGetDope(DeviceObject);
|
||||||
|
if (Dope)
|
||||||
|
{
|
||||||
|
/* Make sure we can flush safely */
|
||||||
|
DPRINT1("Acquiring volume lock\n");
|
||||||
|
KeAcquireGuardedMutex(&PopVolumeLock);
|
||||||
|
|
||||||
|
/* Add this volume into the list of power-manager volumes */
|
||||||
|
DPRINT1("Got DOPE: %p\n", Dope);
|
||||||
|
if (!Dope->Volume.Flink) InsertTailList(&PopVolumeDevices, &Dope->Volume);
|
||||||
|
|
||||||
|
/* Allow flushes to go through */
|
||||||
|
KeReleaseGuardedMutex(&PopVolumeLock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
PopFlushVolumeWorker(IN PVOID Context)
|
||||||
|
{
|
||||||
|
PPOP_FLUSH_VOLUME FlushContext = (PPOP_FLUSH_VOLUME)Context;
|
||||||
|
PDEVICE_OBJECT_POWER_EXTENSION Dope;
|
||||||
|
PLIST_ENTRY NextEntry;
|
||||||
|
NTSTATUS Status;
|
||||||
|
UCHAR Buffer[sizeof(OBJECT_NAME_INFORMATION) + 512];
|
||||||
|
POBJECT_NAME_INFORMATION NameInfo = (PVOID)Buffer;
|
||||||
|
ULONG Length;
|
||||||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||||
|
HANDLE VolumeHandle;
|
||||||
|
IO_STATUS_BLOCK IoStatusBlock;
|
||||||
|
|
||||||
|
/* Acquire the flush lock since we're messing with the list */
|
||||||
|
KeAcquireGuardedMutex(&PopVolumeLock);
|
||||||
|
|
||||||
|
/* Loop the flush list */
|
||||||
|
while (!IsListEmpty(&FlushContext->List))
|
||||||
|
{
|
||||||
|
/* Grab the next (ie: current) entry and remove it */
|
||||||
|
NextEntry = FlushContext->List.Flink;
|
||||||
|
RemoveEntryList(NextEntry);
|
||||||
|
|
||||||
|
/* Add it back on the volume list */
|
||||||
|
InsertTailList(&PopVolumeDevices, NextEntry);
|
||||||
|
|
||||||
|
/* Done touching the volume list */
|
||||||
|
KeReleaseGuardedMutex(&PopVolumeLock);
|
||||||
|
|
||||||
|
/* Get the dope from the volume link */
|
||||||
|
Dope = CONTAINING_RECORD(NextEntry, DEVICE_OBJECT_POWER_EXTENSION, Volume);
|
||||||
|
|
||||||
|
/* Get the name */
|
||||||
|
Status = ObQueryNameString(Dope->DeviceObject,
|
||||||
|
NameInfo,
|
||||||
|
sizeof(Buffer),
|
||||||
|
&Length);
|
||||||
|
if ((NT_SUCCESS(Status)) && (NameInfo->Name.Buffer))
|
||||||
|
{
|
||||||
|
/* Open the volume */
|
||||||
|
DPRINT1("Opening: %wZ\n", &NameInfo->Name);
|
||||||
|
InitializeObjectAttributes(&ObjectAttributes,
|
||||||
|
&NameInfo->Name,
|
||||||
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
||||||
|
0,
|
||||||
|
0);
|
||||||
|
Status = ZwCreateFile(&VolumeHandle,
|
||||||
|
SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
|
||||||
|
&ObjectAttributes,
|
||||||
|
&IoStatusBlock,
|
||||||
|
NULL,
|
||||||
|
GENERIC_READ | GENERIC_WRITE,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
|
FILE_OPEN,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
0);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* Flush it and close it */
|
||||||
|
DPRINT1("Sending flush to: %lx\n", VolumeHandle);
|
||||||
|
ZwFlushBuffersFile(VolumeHandle, &IoStatusBlock);
|
||||||
|
ZwClose(VolumeHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Acquire the flush lock again since we'll touch the list */
|
||||||
|
KeAcquireGuardedMutex(&PopVolumeLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* One more flush completed... if it was the last, signal the caller */
|
||||||
|
if (!--FlushContext->Count) KeSetEvent(&FlushContext->Wait, IO_NO_INCREMENT, FALSE);
|
||||||
|
|
||||||
|
/* Serialize with flushers */
|
||||||
|
KeReleaseGuardedMutex(&PopVolumeLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
PopFlushVolumes(IN BOOLEAN ShuttingDown)
|
||||||
|
{
|
||||||
|
POP_FLUSH_VOLUME FlushContext = {{0}};
|
||||||
|
ULONG FlushPolicy;
|
||||||
|
UNICODE_STRING RegistryName = RTL_CONSTANT_STRING(L"\\Registry");
|
||||||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||||
|
HANDLE RegistryHandle;
|
||||||
|
PLIST_ENTRY NextEntry;
|
||||||
|
PDEVICE_OBJECT_POWER_EXTENSION Dope;
|
||||||
|
ULONG VolumeCount = 0;
|
||||||
|
NTSTATUS Status;
|
||||||
|
HANDLE ThreadHandle;
|
||||||
|
ULONG ThreadCount;
|
||||||
|
|
||||||
|
/* Setup the flush context */
|
||||||
|
InitializeListHead(&FlushContext.List);
|
||||||
|
KeInitializeEvent(&FlushContext.Wait, NotificationEvent, FALSE);
|
||||||
|
|
||||||
|
/* What to flush */
|
||||||
|
FlushPolicy = ShuttingDown ? 1 | 2 : PopFlushPolicy;
|
||||||
|
if ((FlushPolicy & 1))
|
||||||
|
{
|
||||||
|
/* Registry flush requested, so open it */
|
||||||
|
DPRINT1("Opening registry\n");
|
||||||
|
InitializeObjectAttributes(&ObjectAttributes,
|
||||||
|
&RegistryName,
|
||||||
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
Status = ZwOpenKey(&RegistryHandle, KEY_READ, &ObjectAttributes);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* Flush the registry */
|
||||||
|
DPRINT1("Flushing registry\n");
|
||||||
|
ZwFlushKey(RegistryHandle);
|
||||||
|
ZwClose(RegistryHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Serialize with other flushes */
|
||||||
|
KeAcquireGuardedMutex(&PopVolumeLock);
|
||||||
|
|
||||||
|
/* Scan the volume list */
|
||||||
|
NextEntry = PopVolumeDevices.Flink;
|
||||||
|
while (NextEntry != &PopVolumeDevices)
|
||||||
|
{
|
||||||
|
/* Get the dope from the link */
|
||||||
|
Dope = CONTAINING_RECORD(NextEntry, DEVICE_OBJECT_POWER_EXTENSION, Volume);
|
||||||
|
|
||||||
|
/* Grab the next entry now, since we'll be modifying the list */
|
||||||
|
NextEntry = NextEntry->Flink;
|
||||||
|
|
||||||
|
/* Make sure the object is mounted, writable, exists, and is not a floppy */
|
||||||
|
if (!(Dope->DeviceObject->Vpb->Flags & VPB_MOUNTED) ||
|
||||||
|
(Dope->DeviceObject->Characteristics & FILE_FLOPPY_DISKETTE) ||
|
||||||
|
(Dope->DeviceObject->Characteristics & FILE_READ_ONLY_DEVICE) ||
|
||||||
|
((Dope->DeviceObject->Vpb->RealDevice) &&
|
||||||
|
(Dope->DeviceObject->Vpb->RealDevice->Characteristics & FILE_FLOPPY_DISKETTE)))
|
||||||
|
{
|
||||||
|
/* Not flushable */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove it from the dope and add it to the flush context list */
|
||||||
|
RemoveEntryList(&Dope->Volume);
|
||||||
|
InsertTailList(&FlushContext.List, &Dope->Volume);
|
||||||
|
|
||||||
|
/* Next */
|
||||||
|
VolumeCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if we should skip non-removable devices */
|
||||||
|
if (!(FlushPolicy & 2))
|
||||||
|
{
|
||||||
|
/* ReactOS only implements this routine for shutdown, which requires it */
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
while (TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if there were no volumes at all */
|
||||||
|
if (!VolumeCount)
|
||||||
|
{
|
||||||
|
/* Nothing to do */
|
||||||
|
KeReleaseGuardedMutex(&PopVolumeLock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate up to 8 flusher threads */
|
||||||
|
ThreadCount = min(VolumeCount, 8);
|
||||||
|
InitializeObjectAttributes(&ObjectAttributes,
|
||||||
|
NULL,
|
||||||
|
OBJ_KERNEL_HANDLE,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
/* We will ourselves become a flusher thread */
|
||||||
|
FlushContext.Count = 1;
|
||||||
|
ThreadCount--;
|
||||||
|
|
||||||
|
/* Look for any extra ones we might need */
|
||||||
|
while (ThreadCount > 0)
|
||||||
|
{
|
||||||
|
/* Create a new one */
|
||||||
|
ThreadCount--;
|
||||||
|
DPRINT1("Creating flush thread\n");
|
||||||
|
Status = PsCreateSystemThread(&ThreadHandle,
|
||||||
|
THREAD_ALL_ACCESS,
|
||||||
|
&ObjectAttributes,
|
||||||
|
0L,
|
||||||
|
NULL,
|
||||||
|
PopFlushVolumeWorker,
|
||||||
|
&FlushContext);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* One more created... */
|
||||||
|
FlushContext.Count++;
|
||||||
|
ZwClose(ThreadHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allow flushes to go through */
|
||||||
|
KeReleaseGuardedMutex(&PopVolumeLock);
|
||||||
|
|
||||||
|
/* Enter the flush work */
|
||||||
|
DPRINT1("Local flush\n");
|
||||||
|
PopFlushVolumeWorker(&FlushContext);
|
||||||
|
|
||||||
|
/* Wait for all flushes to be over */
|
||||||
|
DPRINT1("Waiting for flushes\n");
|
||||||
|
KeWaitForSingleObject(&FlushContext.Wait, Executive, KernelMode, FALSE, NULL);
|
||||||
|
DPRINT1("Flushes have completed\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
PoInitializeDeviceObject(IN OUT PDEVOBJ_EXTENSION DeviceObjectExtension)
|
||||||
|
{
|
||||||
|
PEXTENDED_DEVOBJ_EXTENSION DeviceExtension = (PVOID)DeviceObjectExtension;
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
/* Initialize the power flags */
|
||||||
|
DeviceExtension->PowerFlags = PowerSystemUnspecified & 0xF;
|
||||||
|
DeviceExtension->PowerFlags |= ((PowerDeviceUnspecified << 4) & 0xF0);
|
||||||
|
|
||||||
|
/* The device object is not on drugs yet */
|
||||||
|
DeviceExtension->Dope = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PUBLIC FUNCTIONS **********************************************************/
|
||||||
|
|
|
@ -24,6 +24,8 @@ typedef struct _REQUEST_POWER_ITEM
|
||||||
|
|
||||||
PDEVICE_NODE PopSystemPowerDeviceNode = NULL;
|
PDEVICE_NODE PopSystemPowerDeviceNode = NULL;
|
||||||
BOOLEAN PopAcpiPresent = FALSE;
|
BOOLEAN PopAcpiPresent = FALSE;
|
||||||
|
POP_POWER_ACTION PopAction;
|
||||||
|
WORK_QUEUE_ITEM PopShutdownWorkItem;
|
||||||
|
|
||||||
/* PRIVATE FUNCTIONS *********************************************************/
|
/* PRIVATE FUNCTIONS *********************************************************/
|
||||||
|
|
||||||
|
@ -165,6 +167,13 @@ PoInitSystem(IN ULONG BootPhase)
|
||||||
PopAcpiPresent = KeLoaderBlock->Extension->AcpiTable != NULL ? TRUE : FALSE;
|
PopAcpiPresent = KeLoaderBlock->Extension->AcpiTable != NULL ? TRUE : FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Initialize volume support */
|
||||||
|
InitializeListHead(&PopVolumeDevices);
|
||||||
|
KeInitializeGuardedMutex(&PopVolumeLock);
|
||||||
|
|
||||||
|
/* Initialize support for dope */
|
||||||
|
KeInitializeSpinLock(&PopDopeGlobalLock);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -636,3 +645,138 @@ NtSetThreadExecutionState(IN EXECUTION_STATE esFlags,
|
||||||
/* All is good */
|
/* All is good */
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
NtSetSystemPowerState(IN POWER_ACTION SystemAction,
|
||||||
|
IN SYSTEM_POWER_STATE MinSystemState,
|
||||||
|
IN ULONG Flags)
|
||||||
|
{
|
||||||
|
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
|
||||||
|
POP_POWER_ACTION Action = {0};
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
|
/* Check for invalid parameter combinations */
|
||||||
|
if ((MinSystemState >= PowerSystemMaximum) ||
|
||||||
|
(MinSystemState <= PowerSystemUnspecified) ||
|
||||||
|
(SystemAction > PowerActionWarmEject) ||
|
||||||
|
(SystemAction < PowerActionReserved) ||
|
||||||
|
(Flags & ~(POWER_ACTION_QUERY_ALLOWED |
|
||||||
|
POWER_ACTION_UI_ALLOWED |
|
||||||
|
POWER_ACTION_OVERRIDE_APPS |
|
||||||
|
POWER_ACTION_LIGHTEST_FIRST |
|
||||||
|
POWER_ACTION_LOCK_CONSOLE |
|
||||||
|
POWER_ACTION_DISABLE_WAKES |
|
||||||
|
POWER_ACTION_CRITICAL)))
|
||||||
|
{
|
||||||
|
DPRINT1("NtSetSystemPowerState: Bad parameters!\n");
|
||||||
|
DPRINT1(" SystemAction: 0x%x\n", SystemAction);
|
||||||
|
DPRINT1(" MinSystemState: 0x%x\n", MinSystemState);
|
||||||
|
DPRINT1(" Flags: 0x%x\n", Flags);
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for user caller */
|
||||||
|
if (PreviousMode != KernelMode)
|
||||||
|
{
|
||||||
|
/* Check for shutdown permission */
|
||||||
|
if (!SeSinglePrivilegeCheck(SeShutdownPrivilege, PreviousMode))
|
||||||
|
{
|
||||||
|
/* Not granted */
|
||||||
|
DPRINT1("ERROR: Privilege not held for shutdown\n");
|
||||||
|
//return STATUS_PRIVILEGE_NOT_HELD; HACK!
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do it as a kernel-mode caller for consistency with system state */
|
||||||
|
return ZwSetSystemPowerState (SystemAction, MinSystemState, Flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read policy settings (partial shutdown vs. full shutdown) */
|
||||||
|
if (SystemAction == PowerActionShutdown) PopReadShutdownPolicy();
|
||||||
|
|
||||||
|
/* Disable lazy flushing of registry */
|
||||||
|
DPRINT1("Stopping lazy flush\n");
|
||||||
|
CmSetLazyFlushState(FALSE);
|
||||||
|
|
||||||
|
/* Setup the power action */
|
||||||
|
Action.Action = SystemAction;
|
||||||
|
Action.Flags = Flags;
|
||||||
|
|
||||||
|
/* Notify callbacks */
|
||||||
|
DPRINT1("Notifying callbacks\n");
|
||||||
|
ExNotifyCallback(PowerStateCallback, (PVOID)3, NULL);
|
||||||
|
|
||||||
|
/* Swap in any worker thread stacks */
|
||||||
|
DPRINT1("Swapping worker threads\n");
|
||||||
|
ExSwapinWorkerThreads(FALSE);
|
||||||
|
|
||||||
|
/* Make our action global */
|
||||||
|
PopAction = Action;
|
||||||
|
|
||||||
|
/* Start power loop */
|
||||||
|
Status = STATUS_CANCELLED;
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
/* Break out if there's nothing to do */
|
||||||
|
if (Action.Action == PowerActionNone) break;
|
||||||
|
|
||||||
|
/* Check for first-pass or restart */
|
||||||
|
if (Status == STATUS_CANCELLED)
|
||||||
|
{
|
||||||
|
/* Check for shutdown action */
|
||||||
|
if ((PopAction.Action == PowerActionShutdown) ||
|
||||||
|
(PopAction.Action == PowerActionShutdownReset) ||
|
||||||
|
(PopAction.Action == PowerActionShutdownOff))
|
||||||
|
{
|
||||||
|
/* Set the action */
|
||||||
|
PopAction.Shutdown = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now we are good to go */
|
||||||
|
Status = STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if we're still in an invalid status */
|
||||||
|
if (!NT_SUCCESS(Status)) break;
|
||||||
|
|
||||||
|
/* Flush all volumes and the registry */
|
||||||
|
DPRINT1("Flushing volumes\n");
|
||||||
|
PopFlushVolumes(PopAction.Shutdown);
|
||||||
|
|
||||||
|
/* Set IRP for drivers */
|
||||||
|
PopAction.IrpMinor = IRP_MN_SET_POWER;
|
||||||
|
if (PopAction.Shutdown)
|
||||||
|
{
|
||||||
|
DPRINT1("Queueing shutdown thread\n");
|
||||||
|
/* Check if we are running in the system context */
|
||||||
|
if (PsGetCurrentProcess() != PsInitialSystemProcess)
|
||||||
|
{
|
||||||
|
/* We're not, so use a worker thread for shutdown */
|
||||||
|
ExInitializeWorkItem(&PopShutdownWorkItem,
|
||||||
|
&PopGracefulShutdown,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
ExQueueWorkItem(&PopShutdownWorkItem, CriticalWorkQueue);
|
||||||
|
|
||||||
|
/* Spend us -- when we wake up, the system is good to go down */
|
||||||
|
KeSuspendThread(KeGetCurrentThread());
|
||||||
|
Status = STATUS_SYSTEM_SHUTDOWN;
|
||||||
|
goto Exit;
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Do the shutdown inline */
|
||||||
|
PopGracefulShutdown(NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* You should not have made it this far */
|
||||||
|
ASSERT(FALSE && "System is still up and running?!");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Exit:
|
||||||
|
/* We're done, return */
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue