mtrr.c
来自「适合KS8695X」· C语言 代码 · 共 868 行 · 第 1/2 页
C
868 行
/****************************************************************************
*
* 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 region
size - The size in bytes of the region
RETURNS:
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 used
for 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 region
size - The size in bytes of the region
RETURNS:
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 used
for 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 region
size - The size in bytes of the region
RETURNS:
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 be
used 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 call
REMARKS:
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 from
REMARKS:
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 read
base - Place to store the starting physical base address of the region
size - Place to store the size in bytes of the region
type - Place to store the type of the MTRR register
REMARKS:
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 set
base - The starting physical base address of the region
size - The size in bytes of the region
type - Type to place into the MTRR register
REMARKS:
Intel specific function to set the value of a specific MTRR register to
the 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 this
because 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 set
base - The starting physical base address of the region
size - The size in bytes of the region
type - Type to place into the MTRR register
REMARKS:
Intel specific function to set the value of a specific MTRR register to
the 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 set
base - The starting physical base address of the region
size - The size in bytes of the region
type - Type to place into the MTRR register
REMARKS:
Intel specific function to set the value of a specific MTRR register to
the passed in base, size and type.
****************************************************************************/
static void AMD_setMTRR(
uint reg,
ulong base,
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?