|
|
/*++
Copyright (c) 1997-2000 Microsoft Corporation
Module Name:
pat.c
Abstract:
This module implements interfaces that set the Page Attribute Table. These entry points only exist on i386 machines.
Author:
Shivnandan Kaushik (Intel Corp.)
Environment:
Kernel mode only.
Revision History:
--*/
#include "ki.h"
#include "pat.h"
//
// Use lockstep mechanism from mtrr code.
//
#include "mtrr.h"
#if DBG
#define DBGMSG(a) DbgPrint(a)
#else
#define DBGMSG(a)
#endif
//
// Structure used for PAT initialization
//
typedef struct _NEW_PAT {
PAT Attributes;
//
// IPI context to coordinate concurrent PAT update
//
PROCESSOR_LOCKSTEP Synchronize; } NEW_PAT, *PNEW_PAT;
// Prototypes
VOID KeRestorePAT ( VOID );
VOID KiInitializePAT ( VOID );
VOID KiLoadPAT ( IN PNEW_PAT Context );
VOID KiLoadPATTarget ( IN PKIPI_CONTEXT SignalDone, IN PVOID Context, IN PVOID Parameter2, IN PVOID Parameter3 );
#if DBG
VOID KiDumpPAT ( PUCHAR DebugString, PAT Attributes ); #endif
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGELK,KiInitializePAT)
#pragma alloc_text(PAGELK,KiLoadPAT)
#pragma alloc_text(PAGELK,KiLoadPATTarget)
#endif
VOID KeRestorePAT ( VOID ) /*++
Routine Description:
Reinitialize the Page Attribute Table (PAT) on all processors.
N.B. The caller must have the PAGELK code locked
Arguments:
None.
Return Value:
None. --*/ { if (KeFeatureBits & KF_PAT) { KiInitializePAT(); } }
VOID KiInitializePAT ( VOID ) /*++
Routine Description:
Initialize the Page Attribute Table (PAT) on all processors. PAT is setup to provide WB, WC, STRONG_UC and WEAK_UC as the memory types such that mm macros for enabling/disabling/querying caching (MI_DISABLE_CACHING, MI_ENABLE_CACHING and MI_IS_CACHING_ENABLED) are unaffected.
PAT_Entry PAT Index PCD PWT Memory Type 0 0 0 0 WB 1 0 0 1 WC * 2 0 1 0 WEAK_UC 3 0 1 1 STRONG_UC 4 1 0 0 WB 5 1 0 1 WC * 6 1 1 0 WEAK_UC 7 1 1 1 STRONG_UC
N.B. The caller must have the PAGELK code locked and ensure that the PAT feature is supported.
Arguments:
None.
Return Value:
None.
--*/ { PAT PatAttributes; KIRQL OldIrql; PKPRCB Prcb; NEW_PAT NewPAT; #if !defined(NT_UP)
KIRQL NewIrql; KAFFINITY TargetProcessors; #endif
ASSERT ((KeFeatureBits & KF_PAT) != 0);
//
// Initialize the PAT
//
PatAttributes.hw.Pat[0] = PAT_TYPE_WB; PatAttributes.hw.Pat[1] = PAT_TYPE_USWC; PatAttributes.hw.Pat[2] = PAT_TYPE_WEAK_UC; PatAttributes.hw.Pat[3] = PAT_TYPE_STRONG_UC; PatAttributes.hw.Pat[4] = PAT_TYPE_WB; PatAttributes.hw.Pat[5] = PAT_TYPE_USWC; PatAttributes.hw.Pat[6] = PAT_TYPE_WEAK_UC; PatAttributes.hw.Pat[7] = PAT_TYPE_STRONG_UC;
//
// Synchronize with other IPI functions which may stall
//
KeAcquireSpinLock (&KiReverseStallIpiLock, &OldIrql);
Prcb = KeGetCurrentPrcb();
NewPAT.Attributes = PatAttributes; NewPAT.Synchronize.TargetCount = 0; NewPAT.Synchronize.TargetPhase = &Prcb->ReverseStall; NewPAT.Synchronize.Processor = Prcb->Number;
#if !defined(NT_UP)
//
// Collect all the (other) processors
//
TargetProcessors = KeActiveProcessors & ~Prcb->SetMember; if (TargetProcessors != 0) {
KiIpiSendSynchronousPacket ( Prcb, TargetProcessors, KiLoadPATTarget, (PVOID) (&NewPAT), NULL, NULL );
//
// Wait for all processors to be collected
//
KiIpiStallOnPacketTargets(TargetProcessors);
//
// All processors are now waiting. Raise to high level to
// ensure this processor doesn't enter the debugger due to
// some interrupt service routine.
//
KeRaiseIrql (HIGH_LEVEL, &NewIrql);
//
// There's no reason for any debug events now, so signal
// the other processors that they can all begin the PAT update
//
Prcb->ReverseStall += 1; }
#endif
//
// Update PAT
//
KiLoadPAT(&NewPAT);
//
// Release lock and lower to initial irql
//
KeReleaseSpinLock (&KiReverseStallIpiLock, OldIrql); MmEnablePAT(); return; }
VOID KiLoadPATTarget ( IN PKIPI_CONTEXT SignalDone, IN PVOID NewPAT, IN PVOID Parameter2, IN PVOID Parameter3 ) /*++
Routine Description:
Synchronize with target processors prior to PAT modification.
Arguments:
Context - Context which includes the PAT to load
Return Value:
None
--*/ { PNEW_PAT Context;
UNREFERENCED_PARAMETER (Parameter2); UNREFERENCED_PARAMETER (Parameter3);
Context = (PNEW_PAT) NewPAT;
//
// Wait for all processors to be ready
//
KiIpiSignalPacketDoneAndStall(SignalDone, Context->Synchronize.TargetPhase);
//
// Update PAT
//
KiLoadPAT (Context); }
VOID KiLoadPAT ( IN PNEW_PAT Context ) /*++
Routine Description:
This function loads the PAT to all processors.
Arguments:
Context - Context which includes new PAT to load
Return Value:
PAT on all processors programmed to new values
--*/ { BOOLEAN Enable; ULONG HldCr0, HldCr4;
//
// Disable interrupts
//
Enable = KeDisableInterrupts();
//
// Synchronize all processors
//
KiLockStepExecution (&Context->Synchronize);
_asm { ; ; Get current CR0 ;
mov eax, cr0 mov HldCr0, eax
; ; Disable caching & line fill ;
and eax, not CR0_NW or eax, CR0_CD mov cr0, eax
; ; Flush caches ;
; ; wbinvd ;
_emit 0Fh _emit 09h
; ; Get current cr4 ;
_emit 0Fh _emit 20h _emit 0E0h ; mov eax, cr4 mov HldCr4, eax
; ; Disable global page ;
and eax, not CR4_PGE _emit 0Fh _emit 22h _emit 0E0h ; mov cr4, eax
; ; Flush TLB ;
mov eax, cr3 mov cr3, eax }
//
// Load new PAT
//
WRMSR (PAT_MSR, Context->Attributes.QuadPart);
_asm {
; ; Flush caches. ;
; ; wbinvd ;
_emit 0Fh _emit 09h
; ; Flush TLBs ;
mov eax, cr3 mov cr3, eax }
_asm { ; ; Restore CR4 (global page enable) ;
mov eax, HldCr4 _emit 0Fh _emit 22h _emit 0E0h ; mov cr4, eax
; ; Restore CR0 (cache enable) ;
mov eax, HldCr0 mov cr0, eax }
//
// Wait for all processors to reach the same place,
// restore interrupts and return.
//
KiLockStepExecution (&Context->Synchronize); KeEnableInterrupts (Enable); }
|