|
|
/*++
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) || defined(ACPI_HAL))
#include "apic.inc"
#include "..\..\halmps\i386\pcmp_nt.inc"
#if !defined(_AMD64_)
VOID StartPx_RMStub( VOID );
#endif
#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) || defined(ACPI_HAL)) && !defined(_AMD64_)
HalpSleepPage16Lock = MmLockPagableCodeSection((PVOID) StartPx_RMStub ); #endif
#ifdef ACPI_HAL
HalpMapNvsArea(); #endif
break;
case 1: // unlock it all
MmUnlockPagableImageSection(HalpSleepPageLock); #if (defined(APIC_HAL) || defined(ACPI_HAL)) && !defined(_AMD64_)
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 == CurrentPrcb(KeGetPcr())->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); }
|