mirror of
https://github.com/reactos/reactos.git
synced 2025-02-24 01:15:09 +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
9 changed files with 1102 additions and 156 deletions
|
@ -14,123 +14,40 @@
|
|||
|
||||
/* 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
|
||||
*/
|
||||
NTSTATUS NTAPI
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtShutdownSystem(IN SHUTDOWN_ACTION Action)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
HANDLE ThreadHandle;
|
||||
PETHREAD ShutdownThread;
|
||||
|
||||
if (Action > ShutdownPowerOff)
|
||||
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);
|
||||
ObDereferenceObject(ShutdownThread);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
POWER_ACTION PowerAction;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* Now call the power manager */
|
||||
DPRINT1("Setting state to: %lx\n", PowerAction);
|
||||
return NtSetSystemPowerState(PowerAction,
|
||||
PowerSystemSleeping3,
|
||||
POWER_ACTION_OVERRIDE_APPS |
|
||||
POWER_ACTION_DISABLE_WAKES |
|
||||
POWER_ACTION_CRITICAL);
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -743,14 +743,14 @@ IoInitShutdownNotification(
|
|||
|
||||
VOID
|
||||
NTAPI
|
||||
IoShutdownRegisteredDevices(
|
||||
VOID
|
||||
IoShutdownSystem(
|
||||
IN ULONG Phase
|
||||
);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
IoShutdownRegisteredFileSystems(
|
||||
VOID
|
||||
IopShutdownBaseFileSystems(
|
||||
IN PLIST_ENTRY ListHead
|
||||
);
|
||||
|
||||
//
|
||||
|
|
|
@ -32,6 +32,228 @@
|
|||
#define POTRACE(x, ...) DPRINT(__VA_ARGS__)
|
||||
#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
|
||||
//
|
||||
|
@ -47,6 +269,21 @@ PoInitializePrcb(
|
|||
IN PKPRCB Prcb
|
||||
);
|
||||
|
||||
//
|
||||
// I/O Routines
|
||||
//
|
||||
VOID
|
||||
NTAPI
|
||||
PoInitializeDeviceObject(
|
||||
IN OUT PDEVOBJ_EXTENSION DeviceObjectExtension
|
||||
);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
PoVolumeDevice(
|
||||
IN PDEVICE_OBJECT DeviceObject
|
||||
);
|
||||
|
||||
//
|
||||
// Power State routines
|
||||
//
|
||||
|
@ -78,7 +315,33 @@ PoNotifySystemTimeSet(
|
|||
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
|
||||
//
|
||||
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 ********************************************************************/
|
||||
|
||||
ULONG IopDeviceObjectNumber = 0;
|
||||
|
||||
LIST_ENTRY ShutdownListHead, LastChanceShutdownListHead;
|
||||
KSPIN_LOCK ShutdownListLock;
|
||||
extern LIST_ENTRY IopDiskFsListHead;
|
||||
extern LIST_ENTRY IopCdRomFsListHead;
|
||||
extern LIST_ENTRY IopTapeFsListHead;
|
||||
|
||||
/* PRIVATE FUNCTIONS **********************************************************/
|
||||
|
||||
|
@ -95,7 +97,15 @@ IopAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice,
|
|||
|
||||
VOID
|
||||
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;
|
||||
PDEVICE_OBJECT DeviceObject;
|
||||
|
@ -104,46 +114,108 @@ IoShutdownRegisteredDevices(VOID)
|
|||
PIRP Irp;
|
||||
KEVENT Event;
|
||||
NTSTATUS Status;
|
||||
|
||||
|
||||
/* Initialize an event to wait on */
|
||||
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
||||
|
||||
/* Get the first entry and start looping */
|
||||
ListEntry = ExInterlockedRemoveHeadList(&ShutdownListHead,
|
||||
&ShutdownListLock);
|
||||
while (ListEntry)
|
||||
|
||||
/* What phase? */
|
||||
if (Phase == 0)
|
||||
{
|
||||
/* Get the shutdown entry */
|
||||
ShutdownEntry = CONTAINING_RECORD(ListEntry,
|
||||
SHUTDOWN_ENTRY,
|
||||
ShutdownList);
|
||||
/* Shutdown PnP */
|
||||
IoShutdownPnpDevices();
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* Free the shutdown entry and reset the event */
|
||||
ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
|
||||
KeClearEvent(&Event);
|
||||
|
||||
/* Go to the next entry */
|
||||
/* Loop first-chance shutdown notifications */
|
||||
ListEntry = ExInterlockedRemoveHeadList(&ShutdownListHead,
|
||||
&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(&ShutdownListHead,
|
||||
&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
|
||||
|
@ -843,6 +915,9 @@ IoCreateDevice(IN PDRIVER_OBJECT DriverObject,
|
|||
/* Set the Type and Size. Question: why is Size 0 on Windows? */
|
||||
DeviceObjectExtension->Type = IO_TYPE_DEVICE_OBJECT_EXTENSION;
|
||||
DeviceObjectExtension->Size = 0;
|
||||
|
||||
/* Initialize with Power Manager */
|
||||
PoInitializeDeviceObject(DeviceObjectExtension);
|
||||
|
||||
/* Link the Object and Extension */
|
||||
DeviceObjectExtension->DeviceObject = CreatedDeviceObject;
|
||||
|
@ -932,6 +1007,9 @@ IoCreateDevice(IN PDRIVER_OBJECT DriverObject,
|
|||
ASSERT((DriverObject->Flags & DRVO_UNLOAD_INVOKED) == 0);
|
||||
CreatedDeviceObject->DriverObject = DriverObject;
|
||||
IopEditDeviceList(DriverObject, CreatedDeviceObject, IopAdd);
|
||||
|
||||
/* Link with the power manager */
|
||||
if (CreatedDeviceObject->Vpb) PoVolumeDevice(CreatedDeviceObject);
|
||||
|
||||
/* Close the temporary handle and return to caller */
|
||||
ObCloseHandle(TempHandle, KernelMode);
|
||||
|
@ -1351,6 +1429,9 @@ IoRegisterLastChanceShutdownNotification(IN PDEVICE_OBJECT DeviceObject)
|
|||
|
||||
/* Set the DO */
|
||||
Entry->DeviceObject = DeviceObject;
|
||||
|
||||
/* Reference it so it doesn't go away */
|
||||
ObReferenceObject(DeviceObject);
|
||||
|
||||
/* Insert it into the list */
|
||||
ExInterlockedInsertHeadList(&LastChanceShutdownListHead,
|
||||
|
@ -1379,6 +1460,9 @@ IoRegisterShutdownNotification(PDEVICE_OBJECT DeviceObject)
|
|||
|
||||
/* Set the DO */
|
||||
Entry->DeviceObject = DeviceObject;
|
||||
|
||||
/* Reference it so it doesn't go away */
|
||||
ObReferenceObject(DeviceObject);
|
||||
|
||||
/* Insert it into the list */
|
||||
ExInterlockedInsertHeadList(&ShutdownListHead,
|
||||
|
@ -1420,6 +1504,9 @@ IoUnregisterShutdownNotification(PDEVICE_OBJECT DeviceObject)
|
|||
|
||||
/* Free the entry */
|
||||
ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
|
||||
|
||||
/* Get rid of our reference to it */
|
||||
ObDereferenceObject(DeviceObject);
|
||||
}
|
||||
|
||||
/* Go to the next entry */
|
||||
|
@ -1444,6 +1531,9 @@ IoUnregisterShutdownNotification(PDEVICE_OBJECT DeviceObject)
|
|||
|
||||
/* Free the entry */
|
||||
ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
|
||||
|
||||
/* Get rid of our reference to it */
|
||||
ObDereferenceObject(DeviceObject);
|
||||
}
|
||||
|
||||
/* Go to the next entry */
|
||||
|
|
|
@ -245,7 +245,7 @@ IopNotifyFileSystemChange(IN PDEVICE_OBJECT DeviceObject,
|
|||
|
||||
VOID
|
||||
NTAPI
|
||||
IoShutdownRegisteredFileSystems(VOID)
|
||||
IopShutdownBaseFileSystems(IN PLIST_ENTRY ListHead)
|
||||
{
|
||||
PLIST_ENTRY ListEntry;
|
||||
PDEVICE_OBJECT DeviceObject;
|
||||
|
@ -260,8 +260,8 @@ IoShutdownRegisteredFileSystems(VOID)
|
|||
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
||||
|
||||
/* Get the first entry and start looping */
|
||||
ListEntry = IopDiskFsListHead.Flink;
|
||||
while (ListEntry != &IopDiskFsListHead)
|
||||
ListEntry = ListHead->Flink;
|
||||
while (ListEntry != ListHead)
|
||||
{
|
||||
/* Get the device object */
|
||||
DeviceObject = CONTAINING_RECORD(ListEntry,
|
||||
|
|
|
@ -438,8 +438,10 @@
|
|||
<file>obwait.c</file>
|
||||
</directory>
|
||||
<directory name="po">
|
||||
<file>events.c</file>
|
||||
<file>power.c</file>
|
||||
<file>events.c</file>
|
||||
<file>poshtdwn.c</file>
|
||||
<file>povolume.c</file>
|
||||
</directory>
|
||||
<directory name="ps">
|
||||
<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;
|
||||
BOOLEAN PopAcpiPresent = FALSE;
|
||||
POP_POWER_ACTION PopAction;
|
||||
WORK_QUEUE_ITEM PopShutdownWorkItem;
|
||||
|
||||
/* PRIVATE FUNCTIONS *********************************************************/
|
||||
|
||||
|
@ -165,6 +167,13 @@ PoInitSystem(IN ULONG BootPhase)
|
|||
PopAcpiPresent = KeLoaderBlock->Extension->AcpiTable != NULL ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* Initialize volume support */
|
||||
InitializeListHead(&PopVolumeDevices);
|
||||
KeInitializeGuardedMutex(&PopVolumeLock);
|
||||
|
||||
/* Initialize support for dope */
|
||||
KeInitializeSpinLock(&PopDopeGlobalLock);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -636,3 +645,138 @@ NtSetThreadExecutionState(IN EXECUTION_STATE esFlags,
|
|||
/* All is good */
|
||||
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