📄 mtrr.c
字号:
/****************************************************************************** SciTech OS Portability Manager Library** ========================================================================** The contents of this file are subject to the SciTech MGL Public* License Version 1.0 (the "License"); you may not use this file* except in compliance with the License. You may obtain a copy of* the License at http://www.scitechsoft.com/mgl-license.txt** Software distributed under the License is distributed on an* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or* implied. See the License for the specific language governing* rights and limitations under the License.** The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.** The Initial Developer of the Original Code is SciTech Software, Inc.* All Rights Reserved.** ========================================================================** Heavily based on code copyright (C) Richard Gooch** Language: ANSI C* Environment: 32-bit Ring 0 device driver** Description: Generic Memory Type Range Register (MTRR) functions to* manipulate the MTRR registers on supported CPU's. This code* *must* run at ring 0, so you can't normally include this* code directly in normal applications (the except is DOS4GW* apps which run at ring 0 under real DOS). Thus this code* will normally be compiled into a ring 0 device driver for* the target operating system.*****************************************************************************/#include "pmapi.h"#include "ztimerc.h"#include "mtrr.h"#ifndef REALMODE/*--------------------------- Global variables ----------------------------*//* Intel pre-defined MTRR registers */#define NUM_FIXED_RANGES 88#define INTEL_cap_MSR 0x0FE#define INTEL_defType_MSR 0x2FF#define INTEL_fix64K_00000_MSR 0x250#define INTEL_fix16K_80000_MSR 0x258#define INTEL_fix16K_A0000_MSR 0x259#define INTEL_fix4K_C0000_MSR 0x268#define INTEL_fix4K_C8000_MSR 0x269#define INTEL_fix4K_D0000_MSR 0x26A#define INTEL_fix4K_D8000_MSR 0x26B#define INTEL_fix4K_E0000_MSR 0x26C#define INTEL_fix4K_E8000_MSR 0x26D#define INTEL_fix4K_F0000_MSR 0x26E#define INTEL_fix4K_F8000_MSR 0x26F/* Macros to find the address of a paricular MSR register */#define INTEL_physBase_MSR(reg) (0x200 + 2 * (reg))#define INTEL_physMask_MSR(reg) (0x200 + 2 * (reg) + 1)/* Cyrix CPU configuration register indexes */#define CX86_CCR0 0xC0#define CX86_CCR1 0xC1#define CX86_CCR2 0xC2#define CX86_CCR3 0xC3#define CX86_CCR4 0xE8#define CX86_CCR5 0xE9#define CX86_CCR6 0xEA#define CX86_DIR0 0xFE#define CX86_DIR1 0xFF#define CX86_ARR_BASE 0xC4#define CX86_RCR_BASE 0xDC/* Structure to maintain machine state while updating MTRR registers */typedef struct { ulong flags; ulong defTypeLo; ulong defTypeHi; ulong cr4Val; ulong ccr3; } MTRRContext;static int numMTRR = -1;static int cpuFamily,cpuType,cpuStepping;static void (*getMTRR)(uint reg,ulong *base,ulong *size,int *type) = NULL;static void (*setMTRR)(uint reg,ulong base,ulong size,int type) = NULL;static int (*getFreeRegion)(ulong base,ulong size) = NULL;/*----------------------------- Implementation ----------------------------*//****************************************************************************RETURNS:Returns non-zero if we have the write-combining memory type****************************************************************************/static int MTRR_haveWriteCombine(void){ ulong config,dummy; switch (cpuFamily) { case CPU_AMD: if (cpuType < CPU_AMDAthlon) { /* AMD K6-2 stepping 8 and later support the MTRR registers. * The earlier K6-2 steppings (300Mhz models) do not * support MTRR's. */ if ((cpuType < CPU_AMDK6_2) || (cpuType == CPU_AMDK6_2 && cpuStepping < 8)) return 0; return 1; } /* Fall through for AMD Athlon which uses P6 style MTRR's */ case CPU_Intel: _MTRR_readMSR(INTEL_cap_MSR,&config,&dummy); return (config & (1 << 10)); case CPU_Cyrix: /* Cyrix 6x86 and later support the MTRR registers */ if (cpuType < CPU_Cyrix6x86) return 0; return 1; } return 0;}/****************************************************************************PARAMETERS:base - The starting physical base address of the regionsize - The size in bytes of the regionRETURNS:The index of the region on success, else -1 on error.REMARKS:Generic function to find the location of a free MTRR register to be usedfor creating a new mapping.****************************************************************************/static int GENERIC_getFreeRegion( ulong base, ulong size){ int i,ltype; ulong lbase,lsize; for (i = 0; i < numMTRR; i++) { getMTRR(i,&lbase,&lsize,<ype); if (lsize < 1) return i; } (void)base; (void)size; return -1;}/****************************************************************************PARAMETERS:base - The starting physical base address of the regionsize - The size in bytes of the regionRETURNS:The index of the region on success, else -1 on error.REMARKS:Generic function to find the location of a free MTRR register to be usedfor creating a new mapping.****************************************************************************/static int AMDK6_getFreeRegion( ulong base, ulong size){ int i,ltype; ulong lbase,lsize; for (i = 0; i < numMTRR; i++) { getMTRR(i,&lbase,&lsize,<ype); if (lsize < 1) return i; } (void)base; (void)size; return -1;}/****************************************************************************PARAMETERS:base - The starting physical base address of the regionsize - The size in bytes of the regionRETURNS:The index of the region on success, else -1 on error.REMARKS:Cyrix specific function to find the location of a free MTRR register to beused for creating a new mapping.****************************************************************************/static int CYRIX_getFreeRegion( ulong base, ulong size){ int i,ltype; ulong lbase, lsize; if (size > 0x2000000UL) { /* If we are to set up a region >32M then look at ARR7 immediately */ getMTRR(7,&lbase,&lsize,<ype); if (lsize < 1) return 7; } else { /* Check ARR0-6 registers */ for (i = 0; i < 7; i++) { getMTRR(i,&lbase,&lsize,<ype); if (lsize < 1) return i; } /* Try ARR7 but its size must be at least 256K */ getMTRR(7,&lbase,&lsize,<ype); if ((lsize < 1) && (size >= 0x40000)) return i; } (void)base; return -1;}/****************************************************************************PARAMETERS:c - Place to store the machine context across the callREMARKS:Puts the processor into a state where MTRRs can be safely updated****************************************************************************/static void MTRR_beginUpdate( MTRRContext *c){ c->flags = _MTRR_disableInt(); if (cpuFamily != CPU_AMD || (cpuFamily == CPU_AMD && cpuType >= CPU_AMDAthlon)) { switch (cpuFamily) { case CPU_Intel: case CPU_AMD: /* Disable MTRRs, and set the default type to uncached */ c->cr4Val = _MTRR_saveCR4(); _MTRR_readMSR(INTEL_defType_MSR,&c->defTypeLo,&c->defTypeHi); _MTRR_writeMSR(INTEL_defType_MSR,c->defTypeLo & 0xF300UL,c->defTypeHi); break; case CPU_Cyrix: c->ccr3 = _MTRR_getCx86(CX86_CCR3); _MTRR_setCx86(CX86_CCR3, (uchar)((c->ccr3 & 0x0F) | 0x10)); break; } }}/****************************************************************************PARAMETERS:c - Place to restore the machine context fromREMARKS:Restores the processor after updating any of the registers****************************************************************************/static void MTRR_endUpdate( MTRRContext *c){ if (cpuFamily != CPU_AMD || (cpuFamily == CPU_AMD && cpuType >= CPU_AMDAthlon)) { PM_flushTLB(); switch (cpuFamily) { case CPU_Intel: case CPU_AMD: _MTRR_writeMSR(INTEL_defType_MSR,c->defTypeLo,c->defTypeHi); _MTRR_restoreCR4(c->cr4Val); break; case CPU_Cyrix: _MTRR_setCx86(CX86_CCR3,(uchar)c->ccr3); break; } } /* Re-enable interrupts (if enabled previously) */ _MTRR_restoreInt(c->flags);}/****************************************************************************PARAMETERS:reg - MTRR register to readbase - Place to store the starting physical base address of the regionsize - Place to store the size in bytes of the regiontype - Place to store the type of the MTRR registerREMARKS:Intel specific function to read the value of a specific MTRR register.****************************************************************************/static void INTEL_getMTRR( uint reg, ulong *base, ulong *size, int *type){ ulong hi,maskLo,baseLo; _MTRR_readMSR(INTEL_physMask_MSR(reg),&maskLo,&hi); if ((maskLo & 0x800) == 0) { /* MTRR is disabled, so it is free */ *base = 0; *size = 0; *type = 0; return; } _MTRR_readMSR(INTEL_physBase_MSR(reg),&baseLo,&hi); maskLo = (maskLo & 0xFFFFF000UL); *size = ~(maskLo - 1); *base = (baseLo & 0xFFFFF000UL); *type = (baseLo & 0xFF);}/****************************************************************************PARAMETERS:reg - MTRR register to setbase - The starting physical base address of the regionsize - The size in bytes of the regiontype - Type to place into the MTRR registerREMARKS:Intel specific function to set the value of a specific MTRR register tothe passed in base, size and type.****************************************************************************/static void INTEL_setMTRR( uint reg, ulong base, ulong size, int type){ MTRRContext c; MTRR_beginUpdate(&c); if (size == 0) { /* The invalid bit is kept in the mask, so we simply clear the * relevant mask register to disable a range. */ _MTRR_writeMSR(INTEL_physMask_MSR(reg),0,0); } else { _MTRR_writeMSR(INTEL_physBase_MSR(reg),base | type,0); _MTRR_writeMSR(INTEL_physMask_MSR(reg),~(size - 1) | 0x800,0); } MTRR_endUpdate(&c);}/****************************************************************************REMARKS:Disabled banked write combing for Intel processors. We always disable thisbecause it invariably causes problems with older hardware.****************************************************************************/static void INTEL_disableBankedWriteCombine(void){ MTRRContext c; MTRR_beginUpdate(&c); _MTRR_writeMSR(INTEL_fix16K_A0000_MSR,0,0); MTRR_endUpdate(&c);}/****************************************************************************PARAMETERS:reg - MTRR register to setbase - The starting physical base address of the regionsize - The size in bytes of the regiontype - Type to place into the MTRR registerREMARKS:Intel specific function to set the value of a specific MTRR register tothe passed in base, size and type.****************************************************************************/static void AMD_getMTRR( uint reg, ulong *base, ulong *size, int *type){ ulong low,high; /* Upper dword is region 1, lower is region 0 */ _MTRR_readMSR(0xC0000085, &low, &high); if (reg == 1) low = high; /* Find the base and type for the region */ *base = low & 0xFFFE0000; *type = 0; if (low & 1) *type = PM_MTRR_UNCACHABLE; if (low & 2) *type = PM_MTRR_WRCOMB; if ((low & 3) == 0) { *size = 0; return; } /* This needs a little explaining. The size is stored as an * inverted mask of bits of 128K granularity 15 bits long offset * 2 bits * * So to get a size we do invert the mask and add 1 to the lowest * mask bit (4 as its 2 bits in). This gives us a size we then shift * to turn into 128K blocks * * eg 111 1111 1111 1100 is 512K * * invert 000 0000 0000 0011 * +1 000 0000 0000 0100 * *128K ... */ low = (~low) & 0x0FFFC; *size = (low + 4) << 15;}/****************************************************************************PARAMETERS:reg - MTRR register to setbase - The starting physical base address of the regionsize - The size in bytes of the regiontype - Type to place into the MTRR registerREMARKS:Intel specific function to set the value of a specific MTRR register tothe passed in base, size and type.****************************************************************************/static void AMD_setMTRR( uint reg, ulong base,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -