583 lines
14 KiB
C
583 lines
14 KiB
C
/*++
|
||
|
||
Copyright (c) 1997 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
ixslpsup.c
|
||
|
||
Abstract:
|
||
|
||
This file provides the code that saves and restores
|
||
state for traditional motherboard devices when the
|
||
system goes into a sleep state that removes power.
|
||
|
||
This code is included in multiple HALs.
|
||
|
||
Author:
|
||
|
||
Jake Oshins (jakeo) May 6, 1997
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
#include "halp.h"
|
||
#include "ixsleep.h"
|
||
|
||
#if defined(APIC_HAL)
|
||
#include "apic.inc"
|
||
#include "..\..\halmps\i386\pcmp_nt.inc"
|
||
|
||
VOID
|
||
StartPx_RMStub(
|
||
VOID
|
||
);
|
||
#endif
|
||
|
||
typedef struct _SAVE_CONTEXT_DPC_CONTEXT {
|
||
PVOID SaveArea;
|
||
volatile ULONG Complete;
|
||
} SAVE_CONTEXT_DPC_CONTEXT, *PSAVE_CONTEXT_DPC_CONTEXT;
|
||
|
||
VOID
|
||
HalpSaveContextTargetProcessor (
|
||
IN PKDPC Dpc,
|
||
IN PVOID DeferredContext,
|
||
IN PVOID SystemArgument1,
|
||
IN PVOID SystemArgument2
|
||
);
|
||
|
||
#ifdef WANT_IRQ_ROUTING
|
||
#include "ixpciir.h"
|
||
#endif
|
||
extern UCHAR HalpAsmDataMarker;
|
||
extern PVOID HalpEisaControlBase;
|
||
extern ULONG HalpIrqMiniportInitialized;
|
||
|
||
PKPROCESSOR_STATE HalpHiberProcState;
|
||
ULONG CurTiledCr3LowPart;
|
||
PPHYSICAL_ADDRESS HalpTiledCr3Addresses;
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE, HaliLocateHiberRanges)
|
||
#pragma alloc_text(PAGELK, HalpSavePicState)
|
||
#pragma alloc_text(PAGELK, HalpSaveDmaControllerState)
|
||
#pragma alloc_text(PAGELK, HalpSaveTimerState)
|
||
#pragma alloc_text(PAGELK, HalpRestorePicState)
|
||
#pragma alloc_text(PAGELK, HalpRestoreDmaControllerState)
|
||
#pragma alloc_text(PAGELK, HalpRestoreTimerState)
|
||
#pragma alloc_text(PAGELK, HalpBuildResumeStructures)
|
||
#pragma alloc_text(PAGELK, HalpFreeResumeStructures)
|
||
#pragma alloc_text(PAGELK, HalpSaveContextTargetProcessor)
|
||
#endif
|
||
|
||
|
||
#define EISA_CONTROL (PUCHAR)&((PEISA_CONTROL) HalpEisaControlBase)
|
||
|
||
|
||
VOID
|
||
HalpPowerStateCallback(
|
||
IN PVOID CallbackContext,
|
||
IN PVOID Argument1,
|
||
IN PVOID Argument2
|
||
)
|
||
{
|
||
ULONG action = PtrToUlong(Argument1);
|
||
ULONG state = PtrToUlong(Argument2);
|
||
|
||
if (action == PO_CB_SYSTEM_STATE_LOCK) {
|
||
|
||
switch (state) {
|
||
case 0:
|
||
|
||
//
|
||
// Lock down everything in the PAGELK code section. (We chose
|
||
// HalpSaveDmaControllerState because it exists in every HAL.)
|
||
//
|
||
|
||
HalpSleepPageLock = MmLockPagableCodeSection((PVOID)HalpSaveDmaControllerState);
|
||
#if defined(APIC_HAL)
|
||
HalpSleepPage16Lock = MmLockPagableCodeSection((PVOID) StartPx_RMStub );
|
||
#endif
|
||
|
||
#ifdef ACPI_HAL
|
||
|
||
HalpMapNvsArea();
|
||
#endif
|
||
break;
|
||
|
||
case 1: // unlock it all
|
||
|
||
MmUnlockPagableImageSection(HalpSleepPageLock);
|
||
#ifdef APIC_HAL
|
||
MmUnlockPagableImageSection(HalpSleepPage16Lock);
|
||
#endif
|
||
|
||
#ifdef ACPI_HAL
|
||
HalpFreeNvsBuffers();
|
||
#endif
|
||
}
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
VOID
|
||
HalpSavePicState(
|
||
VOID
|
||
)
|
||
{
|
||
HalpMotherboardState.PicState.MasterMask =
|
||
READ_PORT_UCHAR(EISA_CONTROL->Interrupt1ControlPort1);
|
||
|
||
HalpMotherboardState.PicState.SlaveMask =
|
||
READ_PORT_UCHAR(EISA_CONTROL->Interrupt2ControlPort1);
|
||
|
||
#if !defined(ACPI_HAL)
|
||
|
||
#ifdef WANT_IRQ_ROUTING
|
||
if(HalpIrqMiniportInitialized)
|
||
{
|
||
ULONG elcrMask = 0;
|
||
|
||
PciirqmpGetTrigger(&elcrMask);
|
||
HalpMotherboardState.PicState.MasterEdgeLevelControl = (UCHAR)((elcrMask >> 8) & 0xFF);
|
||
HalpMotherboardState.PicState.SlaveEdgeLevelControl = (UCHAR)(elcrMask & 0xFF);
|
||
}
|
||
else
|
||
{
|
||
#endif
|
||
if (HalpBusType == MACHINE_TYPE_EISA) {
|
||
#endif
|
||
HalpMotherboardState.PicState.MasterEdgeLevelControl =
|
||
READ_PORT_UCHAR(EISA_CONTROL->Interrupt1EdgeLevel);
|
||
|
||
HalpMotherboardState.PicState.SlaveEdgeLevelControl =
|
||
READ_PORT_UCHAR(EISA_CONTROL->Interrupt2EdgeLevel);
|
||
|
||
#if !defined(ACPI_HAL)
|
||
}
|
||
#ifdef WANT_IRQ_ROUTING
|
||
}
|
||
#endif
|
||
#endif
|
||
}
|
||
|
||
VOID
|
||
HalpRestorePicState(
|
||
VOID
|
||
)
|
||
{
|
||
ULONG flags;
|
||
|
||
|
||
flags = HalpDisableInterrupts();
|
||
|
||
HalpInitializePICs(FALSE);
|
||
|
||
WRITE_PORT_UCHAR(EISA_CONTROL->Interrupt1ControlPort1,
|
||
HalpMotherboardState.PicState.MasterMask);
|
||
|
||
WRITE_PORT_UCHAR(EISA_CONTROL->Interrupt2ControlPort1,
|
||
HalpMotherboardState.PicState.SlaveMask);
|
||
|
||
//
|
||
// For halx86, the PCI interrupt vector programming
|
||
// is static, so this code can just restore everything.
|
||
//
|
||
|
||
HalpRestorePicEdgeLevelRegister();
|
||
|
||
HalpRestoreInterrupts(flags);
|
||
}
|
||
|
||
VOID
|
||
HalpRestorePicEdgeLevelRegister(
|
||
VOID
|
||
)
|
||
{
|
||
#if !defined(ACPI_HAL)
|
||
#ifdef WANT_IRQ_ROUTING
|
||
if(HalpIrqMiniportInitialized)
|
||
{
|
||
PLINK_NODE linkNode;
|
||
PLINK_STATE temp;
|
||
ULONG elcrMask = (HalpMotherboardState.PicState.MasterEdgeLevelControl << 8) |
|
||
HalpMotherboardState.PicState.SlaveEdgeLevelControl;
|
||
|
||
PciirqmpSetTrigger(elcrMask);
|
||
|
||
//
|
||
// Reprogram all links.
|
||
//
|
||
|
||
for ( linkNode = HalpPciIrqRoutingInfo.LinkNodeHead;
|
||
linkNode;
|
||
linkNode = linkNode->Next)
|
||
{
|
||
//
|
||
// Swap the possible with the allocation.
|
||
//
|
||
|
||
temp = linkNode->Allocation;
|
||
linkNode->Allocation = linkNode->PossibleAllocation;
|
||
linkNode->PossibleAllocation = temp;
|
||
HalpCommitLink(linkNode);
|
||
}
|
||
|
||
}
|
||
else
|
||
{
|
||
#endif
|
||
if (HalpBusType == MACHINE_TYPE_EISA) {
|
||
#endif
|
||
|
||
WRITE_PORT_UCHAR(EISA_CONTROL->Interrupt1EdgeLevel,
|
||
HalpMotherboardState.PicState.MasterEdgeLevelControl);
|
||
|
||
WRITE_PORT_UCHAR(EISA_CONTROL->Interrupt2EdgeLevel,
|
||
HalpMotherboardState.PicState.SlaveEdgeLevelControl);
|
||
#if !defined(ACPI_HAL)
|
||
}
|
||
#ifdef WANT_IRQ_ROUTING
|
||
}
|
||
#endif
|
||
#endif
|
||
}
|
||
|
||
VOID
|
||
HalpSaveDmaControllerState(
|
||
VOID
|
||
)
|
||
{
|
||
}
|
||
|
||
VOID
|
||
HalpRestoreDmaControllerState(
|
||
VOID
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
|
||
This function puts the DMA controller back into the
|
||
same state it was in before the machine went to sleep.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Notes:
|
||
|
||
Normally, the DMA controller structures would be guarded
|
||
by spinlocks. But this function is called with interrupts
|
||
turned off and all but one processor spinning.
|
||
|
||
--*/
|
||
{
|
||
UCHAR i;
|
||
|
||
WRITE_PORT_UCHAR(EISA_CONTROL->Dma1BasePort.AllMask,0xF);
|
||
WRITE_PORT_UCHAR(EISA_CONTROL->Dma2BasePort.AllMask,0xE);
|
||
HalpIoDelay();
|
||
|
||
//
|
||
//Reset the DMA command registers
|
||
//
|
||
#if defined(NEC_98)
|
||
WRITE_PORT_UCHAR(EISA_CONTROL->Dma1BasePort.DmaStatus,0x40);
|
||
WRITE_PORT_UCHAR(EISA_CONTROL->Dma2BasePort.DmaStatus,0x40);
|
||
#else
|
||
WRITE_PORT_UCHAR(EISA_CONTROL->Dma1BasePort.DmaStatus,0);
|
||
WRITE_PORT_UCHAR(EISA_CONTROL->Dma2BasePort.DmaStatus,0);
|
||
#endif
|
||
HalpIoDelay();
|
||
|
||
for (i = 0; i < (EISA_DMA_CHANNELS / 2); i++) {
|
||
|
||
//
|
||
// Check to see if the array contains a value for this channel.
|
||
//
|
||
if (HalpDmaChannelState[i].ChannelProgrammed) {
|
||
|
||
WRITE_PORT_UCHAR(EISA_CONTROL->Dma1BasePort.Mode,
|
||
HalpDmaChannelState[i].ChannelMode);
|
||
|
||
if (HalpEisaDma) {
|
||
WRITE_PORT_UCHAR(EISA_CONTROL->Dma1ExtendedModePort,
|
||
HalpDmaChannelState[i].ChannelExtendedMode);
|
||
}
|
||
|
||
WRITE_PORT_UCHAR(EISA_CONTROL->Dma1BasePort.SingleMask,
|
||
HalpDmaChannelState[i].ChannelMask);
|
||
|
||
HalpIoDelay();
|
||
}
|
||
}
|
||
|
||
for (i = (EISA_DMA_CHANNELS / 2); i < EISA_DMA_CHANNELS; i++) {
|
||
|
||
//
|
||
// Check to see if the array contains a value for this channel.
|
||
//
|
||
if (HalpDmaChannelState[i].ChannelProgrammed) {
|
||
|
||
WRITE_PORT_UCHAR(EISA_CONTROL->Dma2BasePort.Mode,
|
||
HalpDmaChannelState[i].ChannelMode);
|
||
|
||
if (HalpEisaDma) {
|
||
WRITE_PORT_UCHAR(EISA_CONTROL->Dma2ExtendedModePort,
|
||
HalpDmaChannelState[i].ChannelExtendedMode);
|
||
}
|
||
|
||
WRITE_PORT_UCHAR(EISA_CONTROL->Dma2BasePort.SingleMask,
|
||
HalpDmaChannelState[i].ChannelMask);
|
||
|
||
HalpIoDelay();
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
HalpSaveTimerState(
|
||
VOID
|
||
)
|
||
{
|
||
}
|
||
|
||
VOID
|
||
HalpRestoreTimerState(
|
||
VOID
|
||
)
|
||
{
|
||
HalpInitializeClock();
|
||
}
|
||
|
||
VOID
|
||
HaliLocateHiberRanges (
|
||
IN PVOID MemoryMap
|
||
)
|
||
{
|
||
//
|
||
// Mark the hal's data section as needed to be cloned
|
||
//
|
||
|
||
PoSetHiberRange (
|
||
MemoryMap,
|
||
PO_MEM_CLONE,
|
||
(PVOID) &HalpFeatureBits,
|
||
0,
|
||
'dlah'
|
||
);
|
||
|
||
#if defined(_HALPAE_)
|
||
|
||
//
|
||
// Mark DMA buffers as not needing to be saved.
|
||
//
|
||
|
||
if (MasterAdapter24.MapBufferSize != 0) {
|
||
PoSetHiberRange( MemoryMap,
|
||
PO_MEM_DISCARD | PO_MEM_PAGE_ADDRESS,
|
||
(PVOID)(ULONG_PTR)(MasterAdapter24.MapBufferPhysicalAddress.LowPart >>
|
||
PAGE_SHIFT),
|
||
MasterAdapter24.MapBufferSize >> PAGE_SHIFT,
|
||
'mlah' );
|
||
}
|
||
|
||
if (MasterAdapter32.MapBufferSize != 0) {
|
||
PoSetHiberRange( MemoryMap,
|
||
PO_MEM_DISCARD | PO_MEM_PAGE_ADDRESS,
|
||
(PVOID)(ULONG_PTR)(MasterAdapter32.MapBufferPhysicalAddress.LowPart >>
|
||
PAGE_SHIFT),
|
||
MasterAdapter32.MapBufferSize >> PAGE_SHIFT,
|
||
'mlah' );
|
||
}
|
||
|
||
#else
|
||
|
||
//
|
||
// Mark DMA buffer has not needing saved
|
||
//
|
||
|
||
if (HalpMapBufferSize) {
|
||
PoSetHiberRange (
|
||
MemoryMap,
|
||
PO_MEM_DISCARD | PO_MEM_PAGE_ADDRESS,
|
||
(PVOID) (HalpMapBufferPhysicalAddress.LowPart >> PAGE_SHIFT),
|
||
HalpMapBufferSize >> PAGE_SHIFT,
|
||
'mlah'
|
||
);
|
||
}
|
||
|
||
#endif
|
||
}
|
||
|
||
NTSTATUS
|
||
HalpBuildResumeStructures(
|
||
VOID
|
||
)
|
||
{
|
||
KAFFINITY CurrentAffinity, ActiveProcessors;
|
||
ULONG ProcNum, Processor, NumberProcessors = 1;
|
||
KDPC Dpc;
|
||
SAVE_CONTEXT_DPC_CONTEXT Context;
|
||
|
||
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
|
||
|
||
#if defined(APIC_HAL)
|
||
//
|
||
// If KeActiveProcessors() were callable at
|
||
// DISPATCH_LEVEL, I would use that.
|
||
//
|
||
|
||
NumberProcessors = HalpMpInfoTable.NtProcessors;
|
||
#endif
|
||
ActiveProcessors = (1 << NumberProcessors) - 1;
|
||
|
||
#if defined(APIC_HAL) || defined(ACPI_HAL)
|
||
//
|
||
// Allocate space to save processor context for other processors
|
||
//
|
||
|
||
HalpTiledCr3Addresses = NULL;
|
||
|
||
HalpHiberProcState =
|
||
ExAllocatePoolWithTag(NonPagedPool,
|
||
(NumberProcessors * sizeof(KPROCESSOR_STATE)),
|
||
HAL_POOL_TAG);
|
||
|
||
if (!HalpHiberProcState) {
|
||
goto BuildResumeStructuresError;
|
||
}
|
||
|
||
RtlZeroMemory(HalpHiberProcState,
|
||
NumberProcessors * sizeof(KPROCESSOR_STATE));
|
||
|
||
//
|
||
// Allocate space for tiled CR3 for all processors
|
||
//
|
||
|
||
HalpTiledCr3Addresses =
|
||
ExAllocatePoolWithTag(NonPagedPool,
|
||
(NumberProcessors * sizeof(PHYSICAL_ADDRESS)),
|
||
HAL_POOL_TAG);
|
||
|
||
if (!HalpTiledCr3Addresses) {
|
||
goto BuildResumeStructuresError;
|
||
}
|
||
|
||
RtlZeroMemory(HalpTiledCr3Addresses,
|
||
(NumberProcessors * sizeof(PHYSICAL_ADDRESS)));
|
||
|
||
//
|
||
// Get IDT and GDT for all processors except BSP,
|
||
// map and save tiled CR3
|
||
//
|
||
|
||
KeInitializeDpc (&Dpc, HalpSaveContextTargetProcessor, &Context);
|
||
KeSetImportanceDpc (&Dpc, HighImportance);
|
||
|
||
ProcNum = 0;
|
||
CurrentAffinity = 1;
|
||
Processor = 0;
|
||
|
||
while (ActiveProcessors) {
|
||
if (ActiveProcessors & CurrentAffinity) {
|
||
|
||
ActiveProcessors &= ~CurrentAffinity;
|
||
|
||
RtlZeroMemory(&Context, sizeof(Context));
|
||
Context.SaveArea = &(HalpHiberProcState[ProcNum]);
|
||
|
||
if (Processor == (KeGetPcr())->Prcb->Number) {
|
||
|
||
//
|
||
// We're running on this processor. Just call
|
||
// the DPC routine from here.
|
||
|
||
HalpSaveContextTargetProcessor(&Dpc, &Context, NULL, NULL);
|
||
|
||
} else {
|
||
|
||
//
|
||
// Issue DPC to target processor
|
||
//
|
||
|
||
KeSetTargetProcessorDpc (&Dpc, (CCHAR) Processor);
|
||
KeInsertQueueDpc (&Dpc, NULL, NULL);
|
||
|
||
//
|
||
// Wait for DPC to be complete.
|
||
//
|
||
while (Context.Complete == FALSE);
|
||
}
|
||
|
||
ProcNum++;
|
||
}
|
||
|
||
Processor++;
|
||
CurrentAffinity <<= 1;
|
||
}
|
||
|
||
for (ProcNum = 0; ProcNum < NumberProcessors; ProcNum++) {
|
||
HalpTiledCr3Addresses[ProcNum].LowPart =
|
||
HalpBuildTiledCR3Ex(&(HalpHiberProcState[ProcNum]),ProcNum);
|
||
}
|
||
#endif
|
||
|
||
return STATUS_SUCCESS;
|
||
|
||
#if defined(APIC_HAL) || defined(ACPI_HAL)
|
||
BuildResumeStructuresError:
|
||
|
||
if (HalpHiberProcState) ExFreePool(HalpHiberProcState);
|
||
if (HalpTiledCr3Addresses) ExFreePool(HalpTiledCr3Addresses);
|
||
return STATUS_UNSUCCESSFUL;
|
||
#endif
|
||
}
|
||
|
||
NTSTATUS
|
||
HalpFreeResumeStructures(
|
||
VOID
|
||
)
|
||
{
|
||
ULONG ProcNum, NumberProcessors = 1;
|
||
|
||
#if defined(APIC_HAL)
|
||
NumberProcessors = HalpMpInfoTable.NtProcessors;
|
||
#endif
|
||
|
||
#if defined(APIC_HAL) || defined(ACPI_HAL)
|
||
|
||
if (HalpHiberProcState) {
|
||
ExFreePool(HalpHiberProcState);
|
||
HalpHiberProcState = NULL;
|
||
}
|
||
|
||
if (HalpTiledCr3Addresses) {
|
||
ExFreePool(HalpTiledCr3Addresses);
|
||
HalpTiledCr3Addresses = NULL;
|
||
}
|
||
|
||
for (ProcNum = 0; ProcNum < NumberProcessors; ProcNum++) {
|
||
HalpFreeTiledCR3Ex(ProcNum);
|
||
}
|
||
#endif
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
VOID
|
||
HalpSaveContextTargetProcessor (
|
||
IN PKDPC Dpc,
|
||
IN PVOID DeferredContext,
|
||
IN PVOID SystemArgument1,
|
||
IN PVOID SystemArgument2
|
||
)
|
||
{
|
||
PSAVE_CONTEXT_DPC_CONTEXT Context = (PSAVE_CONTEXT_DPC_CONTEXT)DeferredContext;
|
||
|
||
KeSaveStateForHibernate(Context->SaveArea);
|
||
InterlockedIncrement(&Context->Complete);
|
||
}
|