reactos/ntoskrnl/po/power.c

1150 lines
32 KiB
C
Raw Normal View History

/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/po/power.c
* PURPOSE: Power Manager
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
* Herv<EFBFBD> Poussineau (hpoussin@reactos.com)
*/
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
/* GLOBALS *******************************************************************/
typedef struct _POWER_STATE_TRAVERSE_CONTEXT
{
SYSTEM_POWER_STATE SystemPowerState;
POWER_ACTION PowerAction;
PDEVICE_OBJECT PowerDevice;
} POWER_STATE_TRAVERSE_CONTEXT, *PPOWER_STATE_TRAVERSE_CONTEXT;
PDEVICE_NODE PopSystemPowerDeviceNode = NULL;
BOOLEAN PopAcpiPresent = FALSE;
POP_POWER_ACTION PopAction;
WORK_QUEUE_ITEM PopShutdownWorkItem;
SYSTEM_POWER_CAPABILITIES PopCapabilities;
/* PRIVATE FUNCTIONS *********************************************************/
static WORKER_THREAD_ROUTINE PopPassivePowerCall;
_Use_decl_annotations_
static
VOID
NTAPI
PopPassivePowerCall(
PVOID Parameter)
{
PIRP Irp = Parameter;
PIO_STACK_LOCATION IoStack;
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
_Analysis_assume_(Irp != NULL);
IoStack = IoGetNextIrpStackLocation(Irp);
(VOID)IoCallDriver(IoStack->DeviceObject, Irp);
}
_IRQL_requires_max_(DISPATCH_LEVEL)
_IRQL_requires_same_
static
NTSTATUS
PopPresentIrp(
_In_ PIO_STACK_LOCATION NextStack,
_In_ PIRP Irp)
{
NTSTATUS Status;
BOOLEAN CallAtPassiveLevel;
PDEVICE_OBJECT DeviceObject;
PWORK_QUEUE_ITEM WorkQueueItem;
ASSERT(NextStack->MajorFunction == IRP_MJ_POWER);
DeviceObject = NextStack->DeviceObject;
/* Determine whether the IRP must be handled at PASSIVE_LEVEL.
* Only SET_POWER to working state can happen at raised IRQL. */
CallAtPassiveLevel = TRUE;
if ((NextStack->MinorFunction == IRP_MN_SET_POWER) &&
!(DeviceObject->Flags & DO_POWER_PAGABLE))
{
if (NextStack->Parameters.Power.Type == DevicePowerState &&
NextStack->Parameters.Power.State.DeviceState == PowerDeviceD0)
{
CallAtPassiveLevel = FALSE;
}
if (NextStack->Parameters.Power.Type == SystemPowerState &&
NextStack->Parameters.Power.State.SystemState == PowerSystemWorking)
{
CallAtPassiveLevel = FALSE;
}
}
if (CallAtPassiveLevel)
{
/* We need to fit a work item into the DriverContext below */
C_ASSERT(sizeof(Irp->Tail.Overlay.DriverContext) >= sizeof(WORK_QUEUE_ITEM));
if (KeGetCurrentIrql() == PASSIVE_LEVEL)
{
/* Already at passive, call next driver directly */
return IoCallDriver(DeviceObject, Irp);
}
/* Need to schedule a work item and return pending */
NextStack->Control |= SL_PENDING_RETURNED;
WorkQueueItem = (PWORK_QUEUE_ITEM)&Irp->Tail.Overlay.DriverContext;
ExInitializeWorkItem(WorkQueueItem,
PopPassivePowerCall,
Irp);
ExQueueWorkItem(WorkQueueItem, DelayedWorkQueue);
return STATUS_PENDING;
}
/* Direct call. Raise IRQL in debug to catch invalid paged memory access. */
#if DBG
{
KIRQL OldIrql;
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
#endif
Status = IoCallDriver(DeviceObject, Irp);
#if DBG
KeLowerIrql(OldIrql);
}
#endif
return Status;
}
static IO_COMPLETION_ROUTINE PopRequestPowerIrpCompletion;
static
NTSTATUS
NTAPI
PopRequestPowerIrpCompletion(
_In_ PDEVICE_OBJECT DeviceObject,
_In_ PIRP Irp,
_In_reads_opt_(_Inexpressible_("varies")) PVOID Context)
{
PIO_STACK_LOCATION Stack;
PREQUEST_POWER_COMPLETE CompletionRoutine;
POWER_STATE PowerState;
Stack = IoGetCurrentIrpStackLocation(Irp);
CompletionRoutine = Context;
PowerState.DeviceState = (ULONG_PTR)Stack->Parameters.Others.Argument3;
if (CompletionRoutine)
{
CompletionRoutine(Stack->Parameters.Others.Argument1,
(UCHAR)(ULONG_PTR)Stack->Parameters.Others.Argument2,
PowerState,
Stack->Parameters.Others.Argument4,
&Irp->IoStatus);
}
IoSkipCurrentIrpStackLocation(Irp);
IoFreeIrp(Irp);
ObDereferenceObject(DeviceObject);
return STATUS_MORE_PROCESSING_REQUIRED;
}
VOID
NTAPI
PopCleanupPowerState(IN PPOWER_STATE PowerState)
{
//UNIMPLEMENTED;
}
NTSTATUS
PopSendQuerySystemPowerState(PDEVICE_OBJECT DeviceObject, SYSTEM_POWER_STATE SystemState, POWER_ACTION PowerAction)
{
KEVENT Event;
IO_STATUS_BLOCK IoStatusBlock;
PIO_STACK_LOCATION IrpSp;
PIRP Irp;
NTSTATUS Status;
KeInitializeEvent(&Event,
NotificationEvent,
FALSE);
Irp = IoBuildSynchronousFsdRequest(IRP_MJ_POWER,
DeviceObject,
NULL,
0,
NULL,
&Event,
&IoStatusBlock);
if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
IrpSp = IoGetNextIrpStackLocation(Irp);
IrpSp->MinorFunction = IRP_MN_QUERY_POWER;
IrpSp->Parameters.Power.Type = SystemPowerState;
IrpSp->Parameters.Power.State.SystemState = SystemState;
IrpSp->Parameters.Power.ShutdownType = PowerAction;
Status = PoCallDriver(DeviceObject, Irp);
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&Event,
Executive,
KernelMode,
FALSE,
NULL);
Status = IoStatusBlock.Status;
}
return Status;
}
NTSTATUS
PopSendSetSystemPowerState(PDEVICE_OBJECT DeviceObject, SYSTEM_POWER_STATE SystemState, POWER_ACTION PowerAction)
{
KEVENT Event;
IO_STATUS_BLOCK IoStatusBlock;
PIO_STACK_LOCATION IrpSp;
PIRP Irp;
NTSTATUS Status;
KeInitializeEvent(&Event,
NotificationEvent,
FALSE);
Irp = IoBuildSynchronousFsdRequest(IRP_MJ_POWER,
DeviceObject,
NULL,
0,
NULL,
&Event,
&IoStatusBlock);
if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
IrpSp = IoGetNextIrpStackLocation(Irp);
IrpSp->MinorFunction = IRP_MN_SET_POWER;
IrpSp->Parameters.Power.Type = SystemPowerState;
IrpSp->Parameters.Power.State.SystemState = SystemState;
IrpSp->Parameters.Power.ShutdownType = PowerAction;
Status = PoCallDriver(DeviceObject, Irp);
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&Event,
Executive,
KernelMode,
FALSE,
NULL);
Status = IoStatusBlock.Status;
}
return Status;
}
NTSTATUS
PopQuerySystemPowerStateTraverse(PDEVICE_NODE DeviceNode,
PVOID Context)
{
PPOWER_STATE_TRAVERSE_CONTEXT PowerStateContext = Context;
PDEVICE_OBJECT TopDeviceObject;
NTSTATUS Status;
DPRINT("PopQuerySystemPowerStateTraverse(%p, %p)\n", DeviceNode, Context);
if (DeviceNode == IopRootDeviceNode)
return STATUS_SUCCESS;
if (DeviceNode->Flags & DNF_LEGACY_DRIVER)
return STATUS_SUCCESS;
TopDeviceObject = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject);
Status = PopSendQuerySystemPowerState(TopDeviceObject,
PowerStateContext->SystemPowerState,
PowerStateContext->PowerAction);
if (!NT_SUCCESS(Status))
{
DPRINT1("Device '%wZ' failed IRP_MN_QUERY_POWER\n", &DeviceNode->InstancePath);
}
ObDereferenceObject(TopDeviceObject);
#if 0
return Status;
#else
return STATUS_SUCCESS;
#endif
}
NTSTATUS
PopSetSystemPowerStateTraverse(PDEVICE_NODE DeviceNode,
PVOID Context)
{
PPOWER_STATE_TRAVERSE_CONTEXT PowerStateContext = Context;
PDEVICE_OBJECT TopDeviceObject;
NTSTATUS Status;
DPRINT("PopSetSystemPowerStateTraverse(%p, %p)\n", DeviceNode, Context);
if (DeviceNode == IopRootDeviceNode)
return STATUS_SUCCESS;
if (DeviceNode->PhysicalDeviceObject == PowerStateContext->PowerDevice)
return STATUS_SUCCESS;
if (DeviceNode->Flags & DNF_LEGACY_DRIVER)
return STATUS_SUCCESS;
TopDeviceObject = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject);
if (TopDeviceObject == PowerStateContext->PowerDevice)
{
ObDereferenceObject(TopDeviceObject);
return STATUS_SUCCESS;
}
Status = PopSendSetSystemPowerState(TopDeviceObject,
PowerStateContext->SystemPowerState,
PowerStateContext->PowerAction);
if (!NT_SUCCESS(Status))
{
DPRINT1("Device '%wZ' failed IRP_MN_SET_POWER\n", &DeviceNode->InstancePath);
}
ObDereferenceObject(TopDeviceObject);
#if 0
return Status;
#else
return STATUS_SUCCESS;
#endif
}
NTSTATUS
NTAPI
PopSetSystemPowerState(SYSTEM_POWER_STATE PowerState, POWER_ACTION PowerAction)
{
PDEVICE_OBJECT DeviceObject;
PDEVICE_OBJECT Fdo;
NTSTATUS Status;
DEVICETREE_TRAVERSE_CONTEXT Context;
POWER_STATE_TRAVERSE_CONTEXT PowerContext;
Status = IopGetSystemPowerDeviceObject(&DeviceObject);
if (!NT_SUCCESS(Status))
{
DPRINT1("No system power driver available\n");
Fdo = NULL;
}
else
{
Fdo = IoGetAttachedDeviceReference(DeviceObject);
if (Fdo == DeviceObject)
{
DPRINT("An FDO was not attached\n");
return STATUS_UNSUCCESSFUL;
}
}
/* Set up context */
PowerContext.PowerAction = PowerAction;
PowerContext.SystemPowerState = PowerState;
PowerContext.PowerDevice = Fdo;
/* Query for system power change */
IopInitDeviceTreeTraverseContext(&Context,
IopRootDeviceNode,
PopQuerySystemPowerStateTraverse,
&PowerContext);
Status = IopTraverseDeviceTree(&Context);
if (!NT_SUCCESS(Status))
{
DPRINT1("Query system power state failed; changing state anyway\n");
}
/* Set system power change */
IopInitDeviceTreeTraverseContext(&Context,
IopRootDeviceNode,
PopSetSystemPowerStateTraverse,
&PowerContext);
IopTraverseDeviceTree(&Context);
if (!PopAcpiPresent) return STATUS_NOT_IMPLEMENTED;
if (Fdo != NULL)
{
if (PowerAction != PowerActionShutdownReset)
PopSendSetSystemPowerState(Fdo, PowerState, PowerAction);
ObDereferenceObject(Fdo);
}
return Status;
}
CODE_SEG("INIT")
- Rename KiSetSystemTime to KeSetSystemTime and enhance prototype for later use. - Create Phase 1 initialization for the SRM (SeInitSystem). Right now it inserts the system boot token into object manager, which is something we forgot to do before. - Renamed ExPhase2Init to Phase1Initialization, since it's not Phase 2. - Updated Phase 1 PS Initialization to get the KeLoaderBlock pointer and use it as a context parameter when calling Phase1Initialization. - Split off Phase1Initialization into Phase1InitializationDiscard, which is the bulk of the phase 1 code (99% of it) and can be put in an .INIT section to be freed after boot. - Modify parts of the Inbv setup code. Also implement support for /SOS, and try to mimic its behaviour on NT (not fully achieved). You will need /SOS to see boot messages on the screen! FreeLDR now adds this by default to the "Debug "configuration. - Temporarily disable ReactOS Banner during boot. We will get this data from the .mc/.res file in a later patch instead of hard-coding it. - Optimize calling and usage of ExpLoadInitialProcess. - Add support for Y2K bug fix documented for Windows NT (/YEAR). - Add support to detect WinPE/MiniNT/ReactOS Live CD. - Add temporary debugging code to MmInit2 and some Mm functions to detect if these functions are being used too early, which could result in catastrophic to subtle bugs. - Add more bugchecks when failures occur, and enhance others. Also add more codes to ntoskrnl.mc. - Disable calls to ObfDereferenceDeviceMap since it's not yet implemented. svn path=/trunk/; revision=25624
2007-01-25 01:13:09 +00:00
BOOLEAN
NTAPI
- Disable the MiCacheImageSymbols call in MmLoadSystemImage for KD too as this hack is required for rossym rather than KDBG. Fixes detection of non-boot driver images by WinDbg. - Add another hack to freeldr.c to make sure that HAL is the second entry in the Load Order list -- detect if it isn't and insert it as the second entry manually if it isn't. - KdbInitialize can now assume that the 2nd entry in the Load Order list is HAL, just like ExpLoadBootSymbols and KD does, so get the Loader Entry directly instead of searching for it. - Move KiBootTss and KiBootGdt to freeldr.c as this is where they belong -- they are not required for NTLDR/WINLDR boot style and are only used directly in freeldr.c. - Get rid of the AcpiTableDetected variable from freeldr.c. Instead, set the AcpiTable entry to something and make PoInitSystem check for that instead to preserve the old behavior. - Implement KdpGetFirstParameter and KdpGetSecondParameter for ARM too -- just retrieve R3/R4 here. Also rename those macros to clarify what parameters we are retrieving. - Add MmIsSessionAddress stub and use it from KD handle session space properly in the Memory Query API, and ASSERT that we are not trying to do a copy to/from session space in MmDbgCopyMemory as we don't handle it properly. Put this in mmdbg.c for now as we don't implement session space, and it is only called from KD right now. - Rename the 3 kdsup.c files to kdx86.c, kdx64.c and kdarm.c to differ them from each other. - Implement KdpAllowDisable -- just check if any processor breakpoints are set on any processor in the system and disallow the disable if so. The routine is now architecture dependant, so move it to the appropriate files. - Get rid of the MmFreeLdr* variables too. These have been deprecated for some time now. - The ModuleObject and ImageBaseAddress parameters of MmLoadSystemImage are not optional so don't treat them as such, and don't zero initialize them as callers shouldn't rely on this. - Set LDRP_ENTRY_NATIVE instead of LDRP_COMPAT_DATABASE_PROCESSED to mark the image as a native image. Also fix the value of LDRP_ENTRY_NATIVE. - Fix definition of LDR_DATA_TABLE_ENTRY -- the Checksum member should be in the union too. - Remove some unnecessary externs for stuff we now define globally in the kernel headers. - Rename some variables in KD to better match the logic. - Move some x86 only stuff from global ke.h and ke_x.h to the x86 dependent ke.h. Remove DR_ACTIVE_MASK as it has been deprecated/unused for a while now. svn path=/trunk/; revision=44023
2009-11-08 01:13:49 +00:00
PoInitSystem(IN ULONG BootPhase)
{
PVOID NotificationEntry;
PCHAR CommandLine;
BOOLEAN ForceAcpiDisable = FALSE;
/* Check if this is phase 1 init */
if (BootPhase == 1)
{
NTSTATUS Status;
/* Register power button notification */
Status = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
(PVOID)&GUID_DEVICE_SYS_BUTTON,
IopRootDeviceNode->PhysicalDeviceObject->DriverObject,
PopAddRemoveSysCapsCallback,
(PVOID)(ULONG_PTR)PolicyDeviceSystemButton,
&NotificationEntry);
if (!NT_SUCCESS(Status))
return FALSE;
/* Register lid notification */
Status = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
(PVOID)&GUID_DEVICE_LID,
IopRootDeviceNode->PhysicalDeviceObject->DriverObject,
PopAddRemoveSysCapsCallback,
(PVOID)(ULONG_PTR)PolicyDeviceSystemButton,
&NotificationEntry);
if (!NT_SUCCESS(Status))
return FALSE;
/* Register battery notification */
Status = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
(PVOID)&GUID_DEVICE_BATTERY,
IopRootDeviceNode->PhysicalDeviceObject->DriverObject,
PopAddRemoveSysCapsCallback,
(PVOID)(ULONG_PTR)PolicyDeviceBattery,
&NotificationEntry);
return NT_SUCCESS(Status);
}
/* Initialize the power capabilities */
RtlZeroMemory(&PopCapabilities, sizeof(SYSTEM_POWER_CAPABILITIES));
/* Get the Command Line */
CommandLine = KeLoaderBlock->LoadOptions;
/* Upcase it */
_strupr(CommandLine);
/* Check for ACPI disable */
if (strstr(CommandLine, "NOACPI")) ForceAcpiDisable = TRUE;
if (ForceAcpiDisable)
{
/* Set the ACPI State to False if it's been forced that way */
PopAcpiPresent = FALSE;
}
else
{
- Disable the MiCacheImageSymbols call in MmLoadSystemImage for KD too as this hack is required for rossym rather than KDBG. Fixes detection of non-boot driver images by WinDbg. - Add another hack to freeldr.c to make sure that HAL is the second entry in the Load Order list -- detect if it isn't and insert it as the second entry manually if it isn't. - KdbInitialize can now assume that the 2nd entry in the Load Order list is HAL, just like ExpLoadBootSymbols and KD does, so get the Loader Entry directly instead of searching for it. - Move KiBootTss and KiBootGdt to freeldr.c as this is where they belong -- they are not required for NTLDR/WINLDR boot style and are only used directly in freeldr.c. - Get rid of the AcpiTableDetected variable from freeldr.c. Instead, set the AcpiTable entry to something and make PoInitSystem check for that instead to preserve the old behavior. - Implement KdpGetFirstParameter and KdpGetSecondParameter for ARM too -- just retrieve R3/R4 here. Also rename those macros to clarify what parameters we are retrieving. - Add MmIsSessionAddress stub and use it from KD handle session space properly in the Memory Query API, and ASSERT that we are not trying to do a copy to/from session space in MmDbgCopyMemory as we don't handle it properly. Put this in mmdbg.c for now as we don't implement session space, and it is only called from KD right now. - Rename the 3 kdsup.c files to kdx86.c, kdx64.c and kdarm.c to differ them from each other. - Implement KdpAllowDisable -- just check if any processor breakpoints are set on any processor in the system and disallow the disable if so. The routine is now architecture dependant, so move it to the appropriate files. - Get rid of the MmFreeLdr* variables too. These have been deprecated for some time now. - The ModuleObject and ImageBaseAddress parameters of MmLoadSystemImage are not optional so don't treat them as such, and don't zero initialize them as callers shouldn't rely on this. - Set LDRP_ENTRY_NATIVE instead of LDRP_COMPAT_DATABASE_PROCESSED to mark the image as a native image. Also fix the value of LDRP_ENTRY_NATIVE. - Fix definition of LDR_DATA_TABLE_ENTRY -- the Checksum member should be in the union too. - Remove some unnecessary externs for stuff we now define globally in the kernel headers. - Rename some variables in KD to better match the logic. - Move some x86 only stuff from global ke.h and ke_x.h to the x86 dependent ke.h. Remove DR_ACTIVE_MASK as it has been deprecated/unused for a while now. svn path=/trunk/; revision=44023
2009-11-08 01:13:49 +00:00
/* Otherwise check if the LoaderBlock has a ACPI Table */
PopAcpiPresent = KeLoaderBlock->Extension->AcpiTable != NULL ? TRUE : FALSE;
}
- Rename KiSetSystemTime to KeSetSystemTime and enhance prototype for later use. - Create Phase 1 initialization for the SRM (SeInitSystem). Right now it inserts the system boot token into object manager, which is something we forgot to do before. - Renamed ExPhase2Init to Phase1Initialization, since it's not Phase 2. - Updated Phase 1 PS Initialization to get the KeLoaderBlock pointer and use it as a context parameter when calling Phase1Initialization. - Split off Phase1Initialization into Phase1InitializationDiscard, which is the bulk of the phase 1 code (99% of it) and can be put in an .INIT section to be freed after boot. - Modify parts of the Inbv setup code. Also implement support for /SOS, and try to mimic its behaviour on NT (not fully achieved). You will need /SOS to see boot messages on the screen! FreeLDR now adds this by default to the "Debug "configuration. - Temporarily disable ReactOS Banner during boot. We will get this data from the .mc/.res file in a later patch instead of hard-coding it. - Optimize calling and usage of ExpLoadInitialProcess. - Add support for Y2K bug fix documented for Windows NT (/YEAR). - Add support to detect WinPE/MiniNT/ReactOS Live CD. - Add temporary debugging code to MmInit2 and some Mm functions to detect if these functions are being used too early, which could result in catastrophic to subtle bugs. - Add more bugchecks when failures occur, and enhance others. Also add more codes to ntoskrnl.mc. - Disable calls to ObfDereferenceDeviceMap since it's not yet implemented. svn path=/trunk/; revision=25624
2007-01-25 01:13:09 +00:00
/* Enable shutdown by power button */
if (PopAcpiPresent)
PopCapabilities.SystemS5 = TRUE;
/* Initialize volume support */
InitializeListHead(&PopVolumeDevices);
KeInitializeGuardedMutex(&PopVolumeLock);
/* Initialize support for dope */
KeInitializeSpinLock(&PopDopeGlobalLock);
/* Initialize support for shutdown waits and work-items */
PopInitShutdownList();
- Rename KiSetSystemTime to KeSetSystemTime and enhance prototype for later use. - Create Phase 1 initialization for the SRM (SeInitSystem). Right now it inserts the system boot token into object manager, which is something we forgot to do before. - Renamed ExPhase2Init to Phase1Initialization, since it's not Phase 2. - Updated Phase 1 PS Initialization to get the KeLoaderBlock pointer and use it as a context parameter when calling Phase1Initialization. - Split off Phase1Initialization into Phase1InitializationDiscard, which is the bulk of the phase 1 code (99% of it) and can be put in an .INIT section to be freed after boot. - Modify parts of the Inbv setup code. Also implement support for /SOS, and try to mimic its behaviour on NT (not fully achieved). You will need /SOS to see boot messages on the screen! FreeLDR now adds this by default to the "Debug "configuration. - Temporarily disable ReactOS Banner during boot. We will get this data from the .mc/.res file in a later patch instead of hard-coding it. - Optimize calling and usage of ExpLoadInitialProcess. - Add support for Y2K bug fix documented for Windows NT (/YEAR). - Add support to detect WinPE/MiniNT/ReactOS Live CD. - Add temporary debugging code to MmInit2 and some Mm functions to detect if these functions are being used too early, which could result in catastrophic to subtle bugs. - Add more bugchecks when failures occur, and enhance others. Also add more codes to ntoskrnl.mc. - Disable calls to ObfDereferenceDeviceMap since it's not yet implemented. svn path=/trunk/; revision=25624
2007-01-25 01:13:09 +00:00
return TRUE;
}
VOID
NTAPI
PopPerfIdle(PPROCESSOR_POWER_STATE PowerState)
{
DPRINT1("PerfIdle function: %p\n", PowerState);
}
VOID
NTAPI
PopPerfIdleDpc(IN PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2)
{
/* Call the Perf Idle function */
PopPerfIdle(&((PKPRCB)DeferredContext)->PowerState);
}
VOID
FASTCALL
PopIdle0(IN PPROCESSOR_POWER_STATE PowerState)
{
/* FIXME: Extremly naive implementation */
HalProcessorIdle();
}
CODE_SEG("INIT")
VOID
NTAPI
PoInitializePrcb(IN PKPRCB Prcb)
{
/* Initialize the Power State */
RtlZeroMemory(&Prcb->PowerState, sizeof(Prcb->PowerState));
Prcb->PowerState.Idle0KernelTimeLimit = 0xFFFFFFFF;
Prcb->PowerState.CurrentThrottle = 100;
Prcb->PowerState.CurrentThrottleIndex = 0;
Prcb->PowerState.IdleFunction = PopIdle0;
/* Initialize the Perf DPC and Timer */
KeInitializeDpc(&Prcb->PowerState.PerfDpc, PopPerfIdleDpc, Prcb);
KeSetTargetProcessorDpc(&Prcb->PowerState.PerfDpc, Prcb->Number);
KeInitializeTimerEx(&Prcb->PowerState.PerfTimer, SynchronizationTimer);
}
/* PUBLIC FUNCTIONS **********************************************************/
/*
* @unimplemented
*/
NTSTATUS
NTAPI
PoCancelDeviceNotify(IN PVOID NotifyBlock)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @unimplemented
*/
NTSTATUS
NTAPI
PoRegisterDeviceNotify(OUT PVOID Unknown0,
IN ULONG Unknown1,
IN ULONG Unknown2,
IN ULONG Unknown3,
IN PVOID Unknown4,
IN PVOID Unknown5)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @unimplemented
*/
VOID
NTAPI
PoShutdownBugCheck(IN BOOLEAN LogError,
IN ULONG BugCheckCode,
IN ULONG_PTR BugCheckParameter1,
IN ULONG_PTR BugCheckParameter2,
IN ULONG_PTR BugCheckParameter3,
IN ULONG_PTR BugCheckParameter4)
{
DPRINT1("PoShutdownBugCheck called\n");
/* FIXME: Log error if requested */
/* FIXME: Initiate a shutdown */
/* Bugcheck the system */
KeBugCheckEx(BugCheckCode,
BugCheckParameter1,
BugCheckParameter2,
BugCheckParameter3,
BugCheckParameter4);
}
/*
* @unimplemented
*/
VOID
NTAPI
PoSetHiberRange(IN PVOID HiberContext,
IN ULONG Flags,
IN OUT PVOID StartPage,
IN ULONG Length,
IN ULONG PageTag)
{
UNIMPLEMENTED;
return;
}
/*
* @implemented
*/
_IRQL_requires_max_(DISPATCH_LEVEL)
NTSTATUS
NTAPI
PoCallDriver(
_In_ PDEVICE_OBJECT DeviceObject,
_Inout_ __drv_aliasesMem PIRP Irp)
{
PIO_STACK_LOCATION NextStack;
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
ASSERT(DeviceObject);
ASSERT(Irp);
NextStack = IoGetNextIrpStackLocation(Irp);
ASSERT(NextStack->MajorFunction == IRP_MJ_POWER);
/* Set DeviceObject for PopPresentIrp */
NextStack->DeviceObject = DeviceObject;
/* Only QUERY_POWER and SET_POWER use special handling */
if (NextStack->MinorFunction != IRP_MN_SET_POWER &&
NextStack->MinorFunction != IRP_MN_QUERY_POWER)
{
return IoCallDriver(DeviceObject, Irp);
}
/* Call the next driver, either directly or at PASSIVE_LEVEL */
return PopPresentIrp(NextStack, Irp);
}
/*
* @unimplemented
*/
PULONG
NTAPI
PoRegisterDeviceForIdleDetection(IN PDEVICE_OBJECT DeviceObject,
IN ULONG ConservationIdleTime,
IN ULONG PerformanceIdleTime,
IN DEVICE_POWER_STATE State)
{
UNIMPLEMENTED;
return NULL;
}
/*
* @unimplemented
*/
PVOID
NTAPI
PoRegisterSystemState(IN PVOID StateHandle,
IN EXECUTION_STATE Flags)
{
UNIMPLEMENTED;
return NULL;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
PoRequestPowerIrp(
_In_ PDEVICE_OBJECT DeviceObject,
_In_ UCHAR MinorFunction,
_In_ POWER_STATE PowerState,
_In_opt_ PREQUEST_POWER_COMPLETE CompletionFunction,
_In_opt_ __drv_aliasesMem PVOID Context,
_Outptr_opt_ PIRP *pIrp)
{
PDEVICE_OBJECT TopDeviceObject;
PIO_STACK_LOCATION Stack;
PIRP Irp;
if (MinorFunction != IRP_MN_QUERY_POWER
&& MinorFunction != IRP_MN_SET_POWER
&& MinorFunction != IRP_MN_WAIT_WAKE)
return STATUS_INVALID_PARAMETER_2;
/* Always call the top of the device stack */
TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
Irp = IoAllocateIrp(TopDeviceObject->StackSize + 2, FALSE);
if (!Irp)
{
ObDereferenceObject(TopDeviceObject);
return STATUS_INSUFFICIENT_RESOURCES;
}
Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
Irp->IoStatus.Information = 0;
IoSetNextIrpStackLocation(Irp);
Stack = IoGetNextIrpStackLocation(Irp);
Stack->Parameters.Others.Argument1 = DeviceObject;
Stack->Parameters.Others.Argument2 = (PVOID)(ULONG_PTR)MinorFunction;
Stack->Parameters.Others.Argument3 = (PVOID)(ULONG_PTR)PowerState.DeviceState;
Stack->Parameters.Others.Argument4 = Context;
Stack->DeviceObject = TopDeviceObject;
IoSetNextIrpStackLocation(Irp);
Stack = IoGetNextIrpStackLocation(Irp);
Stack->MajorFunction = IRP_MJ_POWER;
Stack->MinorFunction = MinorFunction;
if (MinorFunction == IRP_MN_WAIT_WAKE)
{
Stack->Parameters.WaitWake.PowerState = PowerState.SystemState;
}
else
{
Stack->Parameters.Power.Type = DevicePowerState;
Stack->Parameters.Power.State = PowerState;
}
if (pIrp != NULL)
*pIrp = Irp;
IoSetCompletionRoutine(Irp, PopRequestPowerIrpCompletion, CompletionFunction, TRUE, TRUE, TRUE);
PoCallDriver(TopDeviceObject, Irp);
/* Always return STATUS_PENDING. The completion routine
* will call CompletionFunction and complete the Irp.
*/
return STATUS_PENDING;
}
/*
* @unimplemented
*/
POWER_STATE
NTAPI
PoSetPowerState(IN PDEVICE_OBJECT DeviceObject,
IN POWER_STATE_TYPE Type,
IN POWER_STATE State)
{
POWER_STATE ps;
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
ps.SystemState = PowerSystemWorking; // Fully on
ps.DeviceState = PowerDeviceD0; // Fully on
return ps;
}
/*
* @unimplemented
*/
VOID
NTAPI
PoSetSystemState(IN EXECUTION_STATE Flags)
{
UNIMPLEMENTED;
}
/*
* @unimplemented
*/
VOID
NTAPI
PoStartNextPowerIrp(IN PIRP Irp)
{
2019-08-20 12:20:17 +00:00
UNIMPLEMENTED_ONCE;
}
/*
* @unimplemented
*/
VOID
NTAPI
PoUnregisterSystemState(IN PVOID StateHandle)
{
UNIMPLEMENTED;
}
/*
* @unimplemented
*/
NTSTATUS
NTAPI
NtInitiatePowerAction(IN POWER_ACTION SystemAction,
IN SYSTEM_POWER_STATE MinSystemState,
IN ULONG Flags,
IN BOOLEAN Asynchronous)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @unimplemented
*/
NTSTATUS
NTAPI
NtPowerInformation(IN POWER_INFORMATION_LEVEL PowerInformationLevel,
IN PVOID InputBuffer OPTIONAL,
IN ULONG InputBufferLength,
OUT PVOID OutputBuffer OPTIONAL,
IN ULONG OutputBufferLength)
{
NTSTATUS Status;
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
PAGED_CODE();
DPRINT("NtPowerInformation(PowerInformationLevel 0x%x, InputBuffer 0x%p, "
"InputBufferLength 0x%x, OutputBuffer 0x%p, OutputBufferLength 0x%x)\n",
PowerInformationLevel,
InputBuffer, InputBufferLength,
OutputBuffer, OutputBufferLength);
if (PreviousMode != KernelMode)
{
_SEH2_TRY
{
ProbeForRead(InputBuffer, InputBufferLength, 1);
ProbeForWrite(OutputBuffer, OutputBufferLength, sizeof(ULONG));
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
switch (PowerInformationLevel)
{
case SystemBatteryState:
{
PSYSTEM_BATTERY_STATE BatteryState = (PSYSTEM_BATTERY_STATE)OutputBuffer;
if (InputBuffer != NULL)
return STATUS_INVALID_PARAMETER;
if (OutputBufferLength < sizeof(SYSTEM_BATTERY_STATE))
return STATUS_BUFFER_TOO_SMALL;
_SEH2_TRY
{
/* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
RtlZeroMemory(BatteryState, sizeof(SYSTEM_BATTERY_STATE));
BatteryState->EstimatedTime = MAXULONG;
BatteryState->BatteryPresent = PopCapabilities.SystemBatteriesPresent;
// BatteryState->AcOnLine = TRUE;
// BatteryState->MaxCapacity = ;
// BatteryState->RemainingCapacity = ;
Status = STATUS_SUCCESS;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
break;
}
case SystemPowerCapabilities:
{
PSYSTEM_POWER_CAPABILITIES PowerCapabilities = (PSYSTEM_POWER_CAPABILITIES)OutputBuffer;
if (InputBuffer != NULL)
return STATUS_INVALID_PARAMETER;
if (OutputBufferLength < sizeof(SYSTEM_POWER_CAPABILITIES))
return STATUS_BUFFER_TOO_SMALL;
_SEH2_TRY
{
RtlCopyMemory(PowerCapabilities,
&PopCapabilities,
sizeof(SYSTEM_POWER_CAPABILITIES));
Status = STATUS_SUCCESS;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
break;
}
case ProcessorInformation:
{
PPROCESSOR_POWER_INFORMATION PowerInformation = (PPROCESSOR_POWER_INFORMATION)OutputBuffer;
if (InputBuffer != NULL)
return STATUS_INVALID_PARAMETER;
if (OutputBufferLength < sizeof(PROCESSOR_POWER_INFORMATION))
return STATUS_BUFFER_TOO_SMALL;
/* FIXME: return structures for all processors */
_SEH2_TRY
{
/* FIXME: some values are hardcoded */
PowerInformation->Number = 0;
PowerInformation->MaxMhz = 1000;
PowerInformation->CurrentMhz = KeGetCurrentPrcb()->MHz;
PowerInformation->MhzLimit = 1000;
PowerInformation->MaxIdleState = 0;
PowerInformation->CurrentIdleState = 0;
Status = STATUS_SUCCESS;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
break;
}
default:
Status = STATUS_NOT_IMPLEMENTED;
DPRINT1("PowerInformationLevel 0x%x is UNIMPLEMENTED! Have a nice day.\n",
PowerInformationLevel);
break;
}
return Status;
}
NTSTATUS
NTAPI
NtGetDevicePowerState(IN HANDLE Device,
IN PDEVICE_POWER_STATE PowerState)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
BOOLEAN
NTAPI
NtIsSystemResumeAutomatic(VOID)
{
UNIMPLEMENTED;
return FALSE;
}
NTSTATUS
NTAPI
NtRequestWakeupLatency(IN LATENCY_TIME Latency)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
NTAPI
NtSetThreadExecutionState(IN EXECUTION_STATE esFlags,
OUT EXECUTION_STATE *PreviousFlags)
{
PKTHREAD Thread = KeGetCurrentThread();
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
EXECUTION_STATE PreviousState;
PAGED_CODE();
/* Validate flags */
if (esFlags & ~(ES_CONTINUOUS | ES_USER_PRESENT))
{
/* Fail the request */
return STATUS_INVALID_PARAMETER;
}
/* Check for user parameters */
if (PreviousMode != KernelMode)
{
/* Protect the probes */
_SEH2_TRY
{
/* Check if the pointer is valid */
ProbeForWriteUlong(PreviousFlags);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* It isn't -- fail */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
/* Save the previous state, always masking in the continous flag */
PreviousState = Thread->PowerState | ES_CONTINUOUS;
/* Check if we need to update the power state */
if (esFlags & ES_CONTINUOUS) Thread->PowerState = (UCHAR)esFlags;
/* Protect the write back to user mode */
_SEH2_TRY
{
/* Return the previous flags */
*PreviousFlags = PreviousState;
}
_SEH2_EXCEPT(ExSystemExceptionFilter())
{
/* Something's wrong, fail */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
/* 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;
ULONG Dummy;
/* 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;
}
/* 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 */
DPRINT("Stopping lazy flush\n");
CmSetLazyFlushState(FALSE);
/* Setup the power action */
Action.Action = SystemAction;
Action.Flags = Flags;
/* Notify callbacks */
DPRINT("Notifying callbacks\n");
ExNotifyCallback(PowerStateCallback, (PVOID)3, NULL);
/* Swap in any worker thread stacks */
DPRINT("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 */
DPRINT("Flushing volumes\n");
PopFlushVolumes(PopAction.Shutdown);
[CACHE] The cache manager rewrite I started years ago has finally appeared in ReactOS' trunk and although at this point it's not quite perfectly integrated, it's enough to boot up the bootcd or livecd. To check out the more mature original, check out arty-newcc-reactos, branch arty-newcc on bitbucket.org . Amine Khaldi encouraged me quite a bit to not give up on it, and was able to reach out and be an advocate when i really wasn't able to. Others agree that the time has come to begin removing the old cache manager. I expect the remaining problems in the version going to trunk will be taken care of relatively quickly. The motivation for this effort lies in the particularly hairy relationship between ReactOS' cache manager and data sections. This code completely removes page sharing between cache manager and section and reimagines cache manager as being a facility layered on the memory manager, not really caring about individual pages, but simply managing data section objects where caching might occur. It took me about 2 years to do the first pass of this rewrite and most of this year to fix some lingering issues, properly implement demand paging in ReactOS (code which didn't come with this patch in a recognizable form), and finish getting the PrivateCacheMap and SharedCacheMap relationship correct. Currently, the new ntoskrnl/cache directory contains an own implementation of data file sections. After things have settled down, we can begin to deprecate and remove the parts of ReactOS' section implementation that depend on a close relationship with cache manager. Eventually, I think that the extra code added to ntoskrnl/cache/section will be removed and ReactOS' own sections will replace the use of the special MM_CACHE_SECTION_SEGMENT in the cache path. Note also, that this makes all cache manager (and new section parts) use wide file offsets. If my section code were to take over other parts of the ReactOS memory manager, they would also benefit from these improvements. I invite anyone who wants to to peek at this code and fix whatever bugs can be found. svn path=/trunk/; revision=49423
2010-11-02 02:32:39 +00:00
#ifndef NEWCC
/* Flush dirty cache pages */
/* XXX: Is that still mandatory? As now we'll wait on lazy writer to complete? */
CcRosFlushDirtyPages(MAXULONG, &Dummy, TRUE, FALSE);
DPRINT("Cache flushed %lu pages\n", Dummy);
#else
Dummy = 0;
[CACHE] The cache manager rewrite I started years ago has finally appeared in ReactOS' trunk and although at this point it's not quite perfectly integrated, it's enough to boot up the bootcd or livecd. To check out the more mature original, check out arty-newcc-reactos, branch arty-newcc on bitbucket.org . Amine Khaldi encouraged me quite a bit to not give up on it, and was able to reach out and be an advocate when i really wasn't able to. Others agree that the time has come to begin removing the old cache manager. I expect the remaining problems in the version going to trunk will be taken care of relatively quickly. The motivation for this effort lies in the particularly hairy relationship between ReactOS' cache manager and data sections. This code completely removes page sharing between cache manager and section and reimagines cache manager as being a facility layered on the memory manager, not really caring about individual pages, but simply managing data section objects where caching might occur. It took me about 2 years to do the first pass of this rewrite and most of this year to fix some lingering issues, properly implement demand paging in ReactOS (code which didn't come with this patch in a recognizable form), and finish getting the PrivateCacheMap and SharedCacheMap relationship correct. Currently, the new ntoskrnl/cache directory contains an own implementation of data file sections. After things have settled down, we can begin to deprecate and remove the parts of ReactOS' section implementation that depend on a close relationship with cache manager. Eventually, I think that the extra code added to ntoskrnl/cache/section will be removed and ReactOS' own sections will replace the use of the special MM_CACHE_SECTION_SEGMENT in the cache path. Note also, that this makes all cache manager (and new section parts) use wide file offsets. If my section code were to take over other parts of the ReactOS memory manager, they would also benefit from these improvements. I invite anyone who wants to to peek at this code and fix whatever bugs can be found. svn path=/trunk/; revision=49423
2010-11-02 02:32:39 +00:00
#endif
/* Set IRP for drivers */
PopAction.IrpMinor = IRP_MN_SET_POWER;
if (PopAction.Shutdown)
{
DPRINT("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 */
// ASSERTMSG("System is still up and running?!\n", FALSE);
DPRINT1("System is still up and running, you may not have chosen a yet supported power option: %u\n", PopAction.Action);
break;
}
Exit:
/* We're done, return */
return Status;
}