/*
|
/*
|
* Read and write Memory Type Range Registers (MTRRs)
|
* Read and write Memory Type Range Registers (MTRRs)
|
*
|
*
|
* These machine specific registers contain information about
|
* These machine specific registers contain information about
|
* caching of memory regions on Intel processors.
|
* caching of memory regions on Intel processors.
|
*
|
*
|
* This code has been derived from pform_mod.c by M. Tisch"auser
|
* This code has been derived from pform_mod.c by M. Tisch"auser
|
* (email martin@ikcbarka.fzk.de). Special thanks to mingo for
|
* (email martin@ikcbarka.fzk.de). Special thanks to mingo for
|
* his hint.
|
* his hint.
|
*
|
*
|
* (c) 1997 M. Ohlenroth <moh@informatik.tu-chemnitz.de>
|
* (c) 1997 M. Ohlenroth <moh@informatik.tu-chemnitz.de>
|
* NO WARRANTY: use this code at your own risk!
|
* NO WARRANTY: use this code at your own risk!
|
*
|
*
|
* This code is released under the GNU public license version 2 or
|
* This code is released under the GNU public license version 2 or
|
* later.
|
* later.
|
*
|
*
|
* modified to have a /proc/mtrr interface by M. Fr"ohlich, Jan. 1998
|
* modified to have a /proc/mtrr interface by M. Fr"ohlich, Jan. 1998
|
* <frohlich@na.uni-tuebingen.de>
|
* <frohlich@na.uni-tuebingen.de>
|
* the user Interface is partly taken form mtrr-patch-v1.5
|
* the user Interface is partly taken form mtrr-patch-v1.5
|
* Richard Gooch may be reached by email at rgooch@atnf.csiro.au
|
* Richard Gooch may be reached by email at rgooch@atnf.csiro.au
|
* The postal address is:
|
* The postal address is:
|
* Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
|
* Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
|
*
|
*
|
*/
|
*/
|
|
|
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
#include <linux/ctype.h>
|
#include <linux/ctype.h>
|
#include <linux/proc_fs.h>
|
#include <linux/proc_fs.h>
|
#include <linux/smp.h>
|
#include <linux/smp.h>
|
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
#include <asm/system.h>
|
#include <asm/system.h>
|
#include <asm/processor.h>
|
#include <asm/processor.h>
|
#include <asm/mtrr.h>
|
#include <asm/mtrr.h>
|
|
|
#define MTRR_CAP 0x0fe /* MTRRcap register */
|
#define MTRR_CAP 0x0fe /* MTRRcap register */
|
#define MTRR_VARIABLE 0x200 /* variable length registers */
|
#define MTRR_VARIABLE 0x200 /* variable length registers */
|
#define MTRR_FIXED64K 0x250 /* fixed size registers 64k */
|
#define MTRR_FIXED64K 0x250 /* fixed size registers 64k */
|
#define MTRR_FIXED16K 0x258 /* fixed size registers 16K */
|
#define MTRR_FIXED16K 0x258 /* fixed size registers 16K */
|
#define MTRR_FIXED4K 0x268 /* fixed size registers 4K */
|
#define MTRR_FIXED4K 0x268 /* fixed size registers 4K */
|
#define MTRR_DEFTYPE 0x2ff /* MTRRdefType register */
|
#define MTRR_DEFTYPE 0x2ff /* MTRRdefType register */
|
|
|
/*
|
/*
|
* data type for the MTRRcap register
|
* data type for the MTRRcap register
|
*/
|
*/
|
typedef struct {
|
typedef struct {
|
__u64 VCNT : 8 __attribute__ ((packed)),
|
__u64 VCNT : 8 __attribute__ ((packed)),
|
FIX : 1 __attribute__ ((packed)),
|
FIX : 1 __attribute__ ((packed)),
|
__reserved_2 : 1 __attribute__ ((packed)),
|
__reserved_2 : 1 __attribute__ ((packed)),
|
WC : 1 __attribute__ ((packed)),
|
WC : 1 __attribute__ ((packed)),
|
__reserved_1 : 53 __attribute__ ((packed));
|
__reserved_1 : 53 __attribute__ ((packed));
|
} MTRRcap_t __attribute__ ((packed));
|
} MTRRcap_t __attribute__ ((packed));
|
|
|
|
|
/*
|
/*
|
* data type for the MTRRdefType register
|
* data type for the MTRRdefType register
|
*/
|
*/
|
typedef struct {
|
typedef struct {
|
__u64 Type : 8 __attribute__ ((packed)),
|
__u64 Type : 8 __attribute__ ((packed)),
|
__reserved_1 : 2 __attribute__ ((packed)),
|
__reserved_1 : 2 __attribute__ ((packed)),
|
FE : 1 __attribute__ ((packed)),
|
FE : 1 __attribute__ ((packed)),
|
E : 1 __attribute__ ((packed)),
|
E : 1 __attribute__ ((packed)),
|
__reserved_2 : 52 __attribute__ ((packed));
|
__reserved_2 : 52 __attribute__ ((packed));
|
} MTRRdefType_t __attribute__ ((packed));
|
} MTRRdefType_t __attribute__ ((packed));
|
|
|
/* FIXME implement the entry struct */
|
/* FIXME implement the entry struct */
|
typedef struct MTRRfix64K_t {
|
typedef struct MTRRfix64K_t {
|
__u64 raw;
|
__u64 raw;
|
} MTRRfix64K_t __attribute__ ((packed));
|
} MTRRfix64K_t __attribute__ ((packed));
|
|
|
typedef struct MTRRfix16K_t {
|
typedef struct MTRRfix16K_t {
|
__u64 raw;
|
__u64 raw;
|
} MTRRfix16K_t __attribute__ ((packed));
|
} MTRRfix16K_t __attribute__ ((packed));
|
|
|
typedef struct MTRRfix4K_t {
|
typedef struct MTRRfix4K_t {
|
__u64 raw;
|
__u64 raw;
|
} MTRRfix4K_t __attribute__ ((packed));
|
} MTRRfix4K_t __attribute__ ((packed));
|
|
|
/*
|
/*
|
* data type for a pair of variable MTRR registers
|
* data type for a pair of variable MTRR registers
|
*/
|
*/
|
typedef struct {
|
typedef struct {
|
struct {
|
struct {
|
__u64 Type : 8 __attribute__ ((packed)),
|
__u64 Type : 8 __attribute__ ((packed)),
|
__reserved_1 : 4 __attribute__ ((packed)),
|
__reserved_1 : 4 __attribute__ ((packed)),
|
PhysBase : 24 __attribute__ ((packed)),
|
PhysBase : 24 __attribute__ ((packed)),
|
__reserved_2 : 28 __attribute__ ((packed));
|
__reserved_2 : 28 __attribute__ ((packed));
|
} MTRRphysBase __attribute__ ((packed));
|
} MTRRphysBase __attribute__ ((packed));
|
|
|
struct {
|
struct {
|
__u64 __reserved_3 : 11 __attribute__ ((packed)),
|
__u64 __reserved_3 : 11 __attribute__ ((packed)),
|
V : 1 __attribute__ ((packed)),
|
V : 1 __attribute__ ((packed)),
|
PhysMask : 24 __attribute__ ((packed)),
|
PhysMask : 24 __attribute__ ((packed)),
|
__reserved_4 : 28 __attribute__ ((packed));
|
__reserved_4 : 28 __attribute__ ((packed));
|
} MTRRphysMask __attribute__ ((packed));
|
} MTRRphysMask __attribute__ ((packed));
|
} MTRRvar_t __attribute__ ((packed));
|
} MTRRvar_t __attribute__ ((packed));
|
|
|
#define RAW_ACCESS64(data) (*(unsigned long long *)(&(data)))
|
#define RAW_ACCESS64(data) (*(unsigned long long *)(&(data)))
|
|
|
/*
|
/*
|
* MTRR configuration struct
|
* MTRR configuration struct
|
*/
|
*/
|
struct mtrr_cntl_t {
|
struct mtrr_cntl_t {
|
MTRRcap_t MTRRcap; /* MTRR capability register */
|
MTRRcap_t MTRRcap; /* MTRR capability register */
|
MTRRdefType_t MTRRdefType; /* MTRR default type register */
|
MTRRdefType_t MTRRdefType; /* MTRR default type register */
|
MTRRfix64K_t fixed64; /* fixed length entries (raw data) */
|
MTRRfix64K_t fixed64; /* fixed length entries (raw data) */
|
MTRRfix16K_t fixed16[2];
|
MTRRfix16K_t fixed16[2];
|
MTRRfix4K_t fixed4[8];
|
MTRRfix4K_t fixed4[8];
|
MTRRvar_t variable[0]; /* variable type entries */
|
MTRRvar_t variable[0]; /* variable type entries */
|
};
|
};
|
|
|
static struct mtrr_cntl_t *mtrrcntl = NULL;
|
static struct mtrr_cntl_t *mtrrcntl = NULL;
|
|
|
/*
|
/*
|
* Deletes the variable MTRR *MTRRvar
|
* Deletes the variable MTRR *MTRRvar
|
*/
|
*/
|
static inline void MTRRvar_delete(MTRRvar_t *MTRRvar)
|
static inline void MTRRvar_delete(MTRRvar_t *MTRRvar)
|
{
|
{
|
RAW_ACCESS64(MTRRvar->MTRRphysBase) = 0;
|
RAW_ACCESS64(MTRRvar->MTRRphysBase) = 0;
|
RAW_ACCESS64(MTRRvar->MTRRphysMask) = 0;
|
RAW_ACCESS64(MTRRvar->MTRRphysMask) = 0;
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* Sets the variable MTRR *MTRRvar
|
* Sets the variable MTRR *MTRRvar
|
*/
|
*/
|
static inline void MTRRvar_set(MTRRvar_t *MTRRvar, unsigned int type,
|
static inline void MTRRvar_set(MTRRvar_t *MTRRvar, unsigned int type,
|
unsigned long base, unsigned long size)
|
unsigned long base, unsigned long size)
|
{
|
{
|
unsigned long val;
|
unsigned long val;
|
base >>= 12;
|
base >>= 12;
|
size >>= 12;
|
size >>= 12;
|
|
|
MTRRvar->MTRRphysBase.Type = type;
|
MTRRvar->MTRRphysBase.Type = type;
|
MTRRvar->MTRRphysBase.PhysBase = base;
|
MTRRvar->MTRRphysBase.PhysBase = base;
|
|
|
MTRRvar->MTRRphysMask.V = 1;
|
MTRRvar->MTRRphysMask.V = 1;
|
val = 1<<25;
|
val = 1<<25;
|
while (0 == (val & size)) val |= (val>>1);
|
while (0 == (val & size)) val |= (val>>1);
|
MTRRvar->MTRRphysMask.PhysMask = val;
|
MTRRvar->MTRRphysMask.PhysMask = val;
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* returns 1 if the variable MTRR entry *MTRRvar is valid, 0 otherwise
|
* returns 1 if the variable MTRR entry *MTRRvar is valid, 0 otherwise
|
*/
|
*/
|
static inline int MTRRvar_is_valid(const MTRRvar_t *MTRRvar)
|
static inline int MTRRvar_is_valid(const MTRRvar_t *MTRRvar)
|
{
|
{
|
return MTRRvar->MTRRphysMask.V;
|
return MTRRvar->MTRRphysMask.V;
|
}
|
}
|
|
|
/*
|
/*
|
* returns the type of the variable MTRR entry *MTRRvar
|
* returns the type of the variable MTRR entry *MTRRvar
|
*/
|
*/
|
static inline int MTRRvar_get_type(const MTRRvar_t *MTRRvar)
|
static inline int MTRRvar_get_type(const MTRRvar_t *MTRRvar)
|
{
|
{
|
return MTRRvar->MTRRphysBase.Type;
|
return MTRRvar->MTRRphysBase.Type;
|
}
|
}
|
|
|
/*
|
/*
|
* returns the base of the variable MTRR entry *MTRRvar
|
* returns the base of the variable MTRR entry *MTRRvar
|
*/
|
*/
|
static inline unsigned long long MTRRvar_get_base(const MTRRvar_t *MTRRvar)
|
static inline unsigned long long MTRRvar_get_base(const MTRRvar_t *MTRRvar)
|
{
|
{
|
return ((unsigned long long)MTRRvar->MTRRphysBase.PhysBase) << 12;
|
return ((unsigned long long)MTRRvar->MTRRphysBase.PhysBase) << 12;
|
}
|
}
|
|
|
/*
|
/*
|
* returns the size of the variable MTRR entry *MTRRvar
|
* returns the size of the variable MTRR entry *MTRRvar
|
*/
|
*/
|
static inline unsigned long long MTRRvar_get_size(const MTRRvar_t *MTRRvar)
|
static inline unsigned long long MTRRvar_get_size(const MTRRvar_t *MTRRvar)
|
{
|
{
|
if (MTRRvar->MTRRphysMask.PhysMask == 0) {
|
if (MTRRvar->MTRRphysMask.PhysMask == 0) {
|
return 0;
|
return 0;
|
} else {
|
} else {
|
unsigned long size = 1;
|
unsigned long size = 1;
|
const unsigned long Mask = MTRRvar->MTRRphysMask.PhysMask;
|
const unsigned long Mask = MTRRvar->MTRRphysMask.PhysMask;
|
while (0 == (Mask & size)) size <<= 1;
|
while (0 == (Mask & size)) size <<= 1;
|
return ((unsigned long long)size) << 12;
|
return ((unsigned long long)size) << 12;
|
}
|
}
|
}
|
}
|
|
|
/*
|
/*
|
* returns the eflags register
|
* returns the eflags register
|
*/
|
*/
|
static inline int read_eflags(void)
|
static inline int read_eflags(void)
|
{
|
{
|
int ret;
|
int ret;
|
asm volatile (
|
asm volatile (
|
"pushfl\n\t"
|
"pushfl\n\t"
|
"popl %%eax\n\t"
|
"popl %%eax\n\t"
|
:"=a" (ret)
|
:"=a" (ret)
|
:
|
:
|
);
|
);
|
return ret;
|
return ret;
|
}
|
}
|
|
|
/*
|
/*
|
* writes the eflags register
|
* writes the eflags register
|
*/
|
*/
|
static inline void write_eflags(int flag)
|
static inline void write_eflags(int flag)
|
{
|
{
|
asm volatile (
|
asm volatile (
|
"pushl %%eax\n\t"
|
"pushl %%eax\n\t"
|
"popfl\n\t"
|
"popfl\n\t"
|
:
|
:
|
:"a" (flag)
|
:"a" (flag)
|
);
|
);
|
}
|
}
|
|
|
/*
|
/*
|
* returns 1 if the mtrr's are supported by the current processor, 0 otherwise
|
* returns 1 if the mtrr's are supported by the current processor, 0 otherwise
|
*/
|
*/
|
static inline int mtrr_detect(void) {
|
static inline int mtrr_detect(void) {
|
unsigned long flags;
|
unsigned long flags;
|
int eflags;
|
int eflags;
|
int val;
|
int val;
|
|
|
#define MSR_MASK 0x20
|
#define MSR_MASK 0x20
|
#define MTRR_MASK 0x1000
|
#define MTRR_MASK 0x1000
|
#define CPUID_MASK 0x200000
|
#define CPUID_MASK 0x200000
|
/* this function may be called before the cpu_data array has
|
/* this function may be called before the cpu_data array has
|
been initialized */
|
been initialized */
|
save_flags(flags); sti();
|
save_flags(flags); sti();
|
eflags = read_eflags();
|
eflags = read_eflags();
|
write_eflags(eflags ^ CPUID_MASK);
|
write_eflags(eflags ^ CPUID_MASK);
|
if (!((eflags ^ read_eflags()) & CPUID_MASK)) {
|
if (!((eflags ^ read_eflags()) & CPUID_MASK)) {
|
write_eflags(eflags);
|
write_eflags(eflags);
|
restore_flags(flags);
|
restore_flags(flags);
|
return 0;
|
return 0;
|
}
|
}
|
write_eflags(eflags);
|
write_eflags(eflags);
|
restore_flags(flags);
|
restore_flags(flags);
|
|
|
/* get the cpuid level */
|
/* get the cpuid level */
|
asm volatile (
|
asm volatile (
|
"xorl %%eax,%%eax\n\t"
|
"xorl %%eax,%%eax\n\t"
|
"cpuid"
|
"cpuid"
|
:"=a"(val)::"ebx","ecx","edx"
|
:"=a"(val)::"ebx","ecx","edx"
|
);
|
);
|
if (val < 1) return 0;
|
if (val < 1) return 0;
|
/* get the x86_capability value */
|
/* get the x86_capability value */
|
asm volatile (
|
asm volatile (
|
"movl $1,%%eax\n\t"
|
"movl $1,%%eax\n\t"
|
"cpuid"
|
"cpuid"
|
:"=d"(val)::"ebx","ecx","eax"
|
:"=d"(val)::"ebx","ecx","eax"
|
);
|
);
|
if (!(val & MSR_MASK)) return 0;
|
if (!(val & MSR_MASK)) return 0;
|
if (!(val & MTRR_MASK)) return 0;
|
if (!(val & MTRR_MASK)) return 0;
|
|
|
return 1;
|
return 1;
|
#undef MSR_MASK
|
#undef MSR_MASK
|
#undef MTRR_MASK
|
#undef MTRR_MASK
|
#undef CPUID_MASK
|
#undef CPUID_MASK
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* reads the mtrr configuration of the actual processor and returns
|
* reads the mtrr configuration of the actual processor and returns
|
* this configuration on sucess. returns NULL if an error occured or
|
* this configuration on sucess. returns NULL if an error occured or
|
* if mtrr's are not supported.
|
* if mtrr's are not supported.
|
*/
|
*/
|
static struct mtrr_cntl_t *read_mtrr_configuration (void) {
|
static struct mtrr_cntl_t *read_mtrr_configuration (void) {
|
struct mtrr_cntl_t *mtrrcntl;
|
struct mtrr_cntl_t *mtrrcntl;
|
int i;
|
int i;
|
size_t size;
|
size_t size;
|
MTRRcap_t MTRRcap;
|
MTRRcap_t MTRRcap;
|
|
|
if (!mtrr_detect()) {
|
if (!mtrr_detect()) {
|
printk("/proc/mtrr: MTRR's are NOT supported\n");
|
printk("/proc/mtrr: MTRR's are NOT supported\n");
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
RAW_ACCESS64(MTRRcap) = rdmsr(MTRR_CAP);
|
RAW_ACCESS64(MTRRcap) = rdmsr(MTRR_CAP);
|
|
|
/* #define DUMP_MTRR */
|
/* #define DUMP_MTRR */
|
#ifdef DUMP_MTRR
|
#ifdef DUMP_MTRR
|
{
|
{
|
/* Written for a bugreport to Gigabyte ... */
|
/* Written for a bugreport to Gigabyte ... */
|
inline void print_msr(int num) {
|
inline void print_msr(int num) {
|
unsigned long long tmp = rdmsr(num);
|
unsigned long long tmp = rdmsr(num);
|
printk("MSR #%#06x: 0x%08lx%08lx\n",
|
printk("MSR #%#06x: 0x%08lx%08lx\n",
|
num , (unsigned long)(tmp >> 32),
|
num , (unsigned long)(tmp >> 32),
|
(unsigned long)tmp);
|
(unsigned long)tmp);
|
}
|
}
|
|
|
print_msr(MTRR_CAP);
|
print_msr(MTRR_CAP);
|
/* all variable type */
|
/* all variable type */
|
for (i=0;i < MTRRcap.VCNT;i++) {
|
for (i=0;i < MTRRcap.VCNT;i++) {
|
print_msr(MTRR_VARIABLE+2*i);
|
print_msr(MTRR_VARIABLE+2*i);
|
print_msr(MTRR_VARIABLE+2*i+1);
|
print_msr(MTRR_VARIABLE+2*i+1);
|
}
|
}
|
/* all fixed type */
|
/* all fixed type */
|
print_msr(MTRR_FIXED64K);
|
print_msr(MTRR_FIXED64K);
|
print_msr(MTRR_FIXED16K);
|
print_msr(MTRR_FIXED16K);
|
print_msr(MTRR_FIXED16K+1);
|
print_msr(MTRR_FIXED16K+1);
|
for (i=0;i<8;i++)
|
for (i=0;i<8;i++)
|
print_msr(MTRR_FIXED4K+i);
|
print_msr(MTRR_FIXED4K+i);
|
print_msr(MTRR_DEFTYPE);
|
print_msr(MTRR_DEFTYPE);
|
}
|
}
|
#endif
|
#endif
|
|
|
size = sizeof(struct mtrr_cntl_t) + sizeof(MTRRvar_t)*MTRRcap.VCNT;
|
size = sizeof(struct mtrr_cntl_t) + sizeof(MTRRvar_t)*MTRRcap.VCNT;
|
if (NULL == (mtrrcntl = kmalloc(size, GFP_KERNEL))) return NULL;
|
if (NULL == (mtrrcntl = kmalloc(size, GFP_KERNEL))) return NULL;
|
memset(mtrrcntl, 0, size);
|
memset(mtrrcntl, 0, size);
|
|
|
/* read MTRRcap register */
|
/* read MTRRcap register */
|
mtrrcntl->MTRRcap = MTRRcap;
|
mtrrcntl->MTRRcap = MTRRcap;
|
|
|
/* read MTRRdefType register */
|
/* read MTRRdefType register */
|
RAW_ACCESS64(mtrrcntl->MTRRdefType) = rdmsr(MTRR_DEFTYPE);
|
RAW_ACCESS64(mtrrcntl->MTRRdefType) = rdmsr(MTRR_DEFTYPE);
|
|
|
/* read fixed length entries */
|
/* read fixed length entries */
|
if (mtrrcntl->MTRRdefType.E && mtrrcntl->MTRRdefType.FE) {
|
if (mtrrcntl->MTRRdefType.E && mtrrcntl->MTRRdefType.FE) {
|
mtrrcntl->fixed64.raw = rdmsr(MTRR_FIXED64K);
|
mtrrcntl->fixed64.raw = rdmsr(MTRR_FIXED64K);
|
mtrrcntl->fixed16[0].raw = rdmsr(MTRR_FIXED16K);
|
mtrrcntl->fixed16[0].raw = rdmsr(MTRR_FIXED16K);
|
mtrrcntl->fixed16[1].raw = rdmsr(MTRR_FIXED16K+1);
|
mtrrcntl->fixed16[1].raw = rdmsr(MTRR_FIXED16K+1);
|
for (i=0;i<8;i++)
|
for (i=0;i<8;i++)
|
mtrrcntl->fixed4[i].raw = rdmsr(MTRR_FIXED4K+i);
|
mtrrcntl->fixed4[i].raw = rdmsr(MTRR_FIXED4K+i);
|
}
|
}
|
|
|
/* read variable length entries */
|
/* read variable length entries */
|
if (mtrrcntl->MTRRdefType.E) {
|
if (mtrrcntl->MTRRdefType.E) {
|
const int vcnt = mtrrcntl->MTRRcap.VCNT;
|
const int vcnt = mtrrcntl->MTRRcap.VCNT;
|
for (i = 0 ; i < vcnt ; i++) {
|
for (i = 0 ; i < vcnt ; i++) {
|
RAW_ACCESS64(mtrrcntl->variable[i].MTRRphysBase) =
|
RAW_ACCESS64(mtrrcntl->variable[i].MTRRphysBase) =
|
rdmsr(MTRR_VARIABLE + 2*i);
|
rdmsr(MTRR_VARIABLE + 2*i);
|
RAW_ACCESS64(mtrrcntl->variable[i].MTRRphysMask) =
|
RAW_ACCESS64(mtrrcntl->variable[i].MTRRphysMask) =
|
rdmsr(MTRR_VARIABLE + 2*i + 1);
|
rdmsr(MTRR_VARIABLE + 2*i + 1);
|
}
|
}
|
}
|
}
|
|
|
return mtrrcntl;
|
return mtrrcntl;
|
}
|
}
|
|
|
/*
|
/*
|
* initializes the global mtrr configuration
|
* initializes the global mtrr configuration
|
*/
|
*/
|
/*__init_function(void init_mtrr_config(void)) FIXME*/
|
/*__init_function(void init_mtrr_config(void)) FIXME*/
|
void init_mtrr_config(void)
|
void init_mtrr_config(void)
|
{
|
{
|
mtrrcntl = read_mtrr_configuration();
|
mtrrcntl = read_mtrr_configuration();
|
}
|
}
|
|
|
|
|
/* write back and invalidate cache */
|
/* write back and invalidate cache */
|
static inline void wbinvd(void)
|
static inline void wbinvd(void)
|
{
|
{
|
asm volatile("wbinvd");
|
asm volatile("wbinvd");
|
}
|
}
|
|
|
/* flush tlb's */
|
/* flush tlb's */
|
static inline void flush__tlb(void)
|
static inline void flush__tlb(void)
|
{
|
{
|
asm volatile (
|
asm volatile (
|
"movl %%cr3, %%eax\n\t"
|
"movl %%cr3, %%eax\n\t"
|
"movl %%eax, %%cr3\n\t"
|
"movl %%eax, %%cr3\n\t"
|
:
|
:
|
:
|
:
|
: "memory", "eax");
|
: "memory", "eax");
|
}
|
}
|
|
|
/* clear page global enable and return previous value */
|
/* clear page global enable and return previous value */
|
static inline unsigned long clear_pge(void)
|
static inline unsigned long clear_pge(void)
|
{
|
{
|
unsigned long ret;
|
unsigned long ret;
|
asm volatile (
|
asm volatile (
|
"movl %%cr4, %%eax\n\t"
|
"movl %%cr4, %%eax\n\t"
|
"movl %%eax, %%edx\n\t"
|
"movl %%eax, %%edx\n\t"
|
"andl $0x7f, %%edx\n\t"
|
"andl $0x7f, %%edx\n\t"
|
"movl %%edx, %%cr4\n\t"
|
"movl %%edx, %%cr4\n\t"
|
: "=a" (ret)
|
: "=a" (ret)
|
:
|
:
|
: "memory", "cc", "eax", "edx");
|
: "memory", "cc", "eax", "edx");
|
return ret;
|
return ret;
|
}
|
}
|
|
|
/* restores page global enable bit */
|
/* restores page global enable bit */
|
static inline void restore_pge(unsigned long cr4)
|
static inline void restore_pge(unsigned long cr4)
|
{
|
{
|
asm volatile (
|
asm volatile (
|
"movl %0, %%cr4\n\t"
|
"movl %0, %%cr4\n\t"
|
:
|
:
|
: "r" (cr4)
|
: "r" (cr4)
|
: "memory");
|
: "memory");
|
}
|
}
|
|
|
/* ... */
|
/* ... */
|
static inline void disable_cache(void)
|
static inline void disable_cache(void)
|
{
|
{
|
asm volatile (
|
asm volatile (
|
"movl %%cr0, %%eax\n\t"
|
"movl %%cr0, %%eax\n\t"
|
"orl $0x40000000, %%eax\n\t"
|
"orl $0x40000000, %%eax\n\t"
|
"movl %%eax, %%cr0\n\t"
|
"movl %%eax, %%cr0\n\t"
|
:
|
:
|
:
|
:
|
:"memory", "cc", "eax");
|
:"memory", "cc", "eax");
|
}
|
}
|
|
|
/* ... */
|
/* ... */
|
static inline void enable_cache(void)
|
static inline void enable_cache(void)
|
{
|
{
|
asm volatile (
|
asm volatile (
|
"movl %%cr0, %%eax\n\t"
|
"movl %%cr0, %%eax\n\t"
|
"andl $0xbfffffff, %%eax\n\t"
|
"andl $0xbfffffff, %%eax\n\t"
|
"movl %%eax, %%cr0"
|
"movl %%eax, %%cr0"
|
:
|
:
|
:
|
:
|
:"memory", "cc", "eax");
|
:"memory", "cc", "eax");
|
}
|
}
|
|
|
/* clear the MTRRdefType.E and MTRRdefType.FE flag to disable these MTRR's */
|
/* clear the MTRRdefType.E and MTRRdefType.FE flag to disable these MTRR's */
|
static inline void disable_mtrr(void)
|
static inline void disable_mtrr(void)
|
{
|
{
|
MTRRdefType_t MTRRdefType;
|
MTRRdefType_t MTRRdefType;
|
|
|
RAW_ACCESS64(MTRRdefType) = rdmsr(MTRR_DEFTYPE);
|
RAW_ACCESS64(MTRRdefType) = rdmsr(MTRR_DEFTYPE);
|
MTRRdefType.E = 0;
|
MTRRdefType.E = 0;
|
MTRRdefType.FE = 0;
|
MTRRdefType.FE = 0;
|
wrmsr(MTRR_DEFTYPE, RAW_ACCESS64(MTRRdefType));
|
wrmsr(MTRR_DEFTYPE, RAW_ACCESS64(MTRRdefType));
|
}
|
}
|
|
|
/*
|
/*
|
* written from pseudocode from intel
|
* written from pseudocode from intel
|
* (PentiumPro Family Developers manual Volume 3, P 322)
|
* (PentiumPro Family Developers manual Volume 3, P 322)
|
*
|
*
|
*/
|
*/
|
static inline unsigned long pre_mtrr_change(void)
|
static inline unsigned long pre_mtrr_change(void)
|
{
|
{
|
unsigned long cr4;
|
unsigned long cr4;
|
|
|
cr4 = clear_pge();
|
cr4 = clear_pge();
|
|
|
wbinvd();
|
wbinvd();
|
|
|
disable_cache();
|
disable_cache();
|
|
|
wbinvd();
|
wbinvd();
|
|
|
flush__tlb();
|
flush__tlb();
|
|
|
disable_mtrr();
|
disable_mtrr();
|
|
|
return cr4;
|
return cr4;
|
}
|
}
|
|
|
/*
|
/*
|
* written from pseudocode from intel
|
* written from pseudocode from intel
|
* (PentiumPro Family Developers manual Volume 3, P 322)
|
* (PentiumPro Family Developers manual Volume 3, P 322)
|
*/
|
*/
|
static inline void post_mtrr_change(MTRRdefType_t MTRRdefType,unsigned long cr4)
|
static inline void post_mtrr_change(MTRRdefType_t MTRRdefType,unsigned long cr4)
|
{
|
{
|
wbinvd();
|
wbinvd();
|
|
|
flush__tlb();
|
flush__tlb();
|
|
|
wrmsr(MTRR_DEFTYPE, RAW_ACCESS64(MTRRdefType));
|
wrmsr(MTRR_DEFTYPE, RAW_ACCESS64(MTRRdefType));
|
|
|
enable_cache();
|
enable_cache();
|
|
|
restore_pge(cr4);
|
restore_pge(cr4);
|
}
|
}
|
|
|
/*
|
/*
|
* writes all fixed mtrr's
|
* writes all fixed mtrr's
|
*/
|
*/
|
static inline void set_mtrr_fixed(void) {
|
static inline void set_mtrr_fixed(void) {
|
int i;
|
int i;
|
|
|
wrmsr(MTRR_FIXED64K,mtrrcntl->fixed64.raw);
|
wrmsr(MTRR_FIXED64K,mtrrcntl->fixed64.raw);
|
wrmsr(MTRR_FIXED16K+0,mtrrcntl->fixed16[0].raw);
|
wrmsr(MTRR_FIXED16K+0,mtrrcntl->fixed16[0].raw);
|
wrmsr(MTRR_FIXED16K+1,mtrrcntl->fixed16[1].raw);
|
wrmsr(MTRR_FIXED16K+1,mtrrcntl->fixed16[1].raw);
|
for (i=0;i<8;i++)
|
for (i=0;i<8;i++)
|
wrmsr(MTRR_FIXED4K+i,mtrrcntl->fixed4[i].raw);
|
wrmsr(MTRR_FIXED4K+i,mtrrcntl->fixed4[i].raw);
|
}
|
}
|
|
|
/*
|
/*
|
* writes all variable mtrr's
|
* writes all variable mtrr's
|
*/
|
*/
|
static inline void set_mtrr_variable(void) {
|
static inline void set_mtrr_variable(void) {
|
int i;
|
int i;
|
const int vcnt = mtrrcntl->MTRRcap.VCNT;
|
const int vcnt = mtrrcntl->MTRRcap.VCNT;
|
|
|
for (i = 0 ; i < vcnt ; i++ ) {
|
for (i = 0 ; i < vcnt ; i++ ) {
|
wrmsr(MTRR_VARIABLE +2*i,
|
wrmsr(MTRR_VARIABLE +2*i,
|
RAW_ACCESS64(mtrrcntl->variable[i].MTRRphysBase));
|
RAW_ACCESS64(mtrrcntl->variable[i].MTRRphysBase));
|
wrmsr(MTRR_VARIABLE +2*i+1,
|
wrmsr(MTRR_VARIABLE +2*i+1,
|
RAW_ACCESS64(mtrrcntl->variable[i].MTRRphysMask));
|
RAW_ACCESS64(mtrrcntl->variable[i].MTRRphysMask));
|
}
|
}
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* compares the mtrr_cntl_t structure second with that set by
|
* compares the mtrr_cntl_t structure second with that set by
|
* the boot processor,
|
* the boot processor,
|
* returns 0 if equal,
|
* returns 0 if equal,
|
* -1 if the structs are not initialized,
|
* -1 if the structs are not initialized,
|
* 1 if they are different
|
* 1 if they are different
|
*
|
*
|
* the *second struct is assumed to be local, it is not locked!
|
* the *second struct is assumed to be local, it is not locked!
|
*/
|
*/
|
static inline int compare_mtrr_configuration(struct mtrr_cntl_t *second) {
|
static inline int compare_mtrr_configuration(struct mtrr_cntl_t *second) {
|
int i, result = 0;
|
int i, result = 0;
|
|
|
if (NULL == mtrrcntl) { result = -1; goto end; }
|
if (NULL == mtrrcntl) { result = -1; goto end; }
|
if (NULL == second) { result = -1; goto end; }
|
if (NULL == second) { result = -1; goto end; }
|
if (RAW_ACCESS64(mtrrcntl->MTRRcap)
|
if (RAW_ACCESS64(mtrrcntl->MTRRcap)
|
!= RAW_ACCESS64(second->MTRRcap)) {
|
!= RAW_ACCESS64(second->MTRRcap)) {
|
result = 1; goto end;
|
result = 1; goto end;
|
}
|
}
|
|
|
if (RAW_ACCESS64(mtrrcntl->MTRRdefType)
|
if (RAW_ACCESS64(mtrrcntl->MTRRdefType)
|
!= RAW_ACCESS64(second->MTRRdefType)) {
|
!= RAW_ACCESS64(second->MTRRdefType)) {
|
result = 1; goto end;
|
result = 1; goto end;
|
}
|
}
|
|
|
if (mtrrcntl->fixed64.raw != second->fixed64.raw) {
|
if (mtrrcntl->fixed64.raw != second->fixed64.raw) {
|
result = 1; goto end;
|
result = 1; goto end;
|
}
|
}
|
if (mtrrcntl->fixed16[0].raw != second->fixed16[0].raw) {
|
if (mtrrcntl->fixed16[0].raw != second->fixed16[0].raw) {
|
result = 1; goto end;
|
result = 1; goto end;
|
}
|
}
|
if (mtrrcntl->fixed16[1].raw != second->fixed16[1].raw) {
|
if (mtrrcntl->fixed16[1].raw != second->fixed16[1].raw) {
|
result = 1; goto end;
|
result = 1; goto end;
|
}
|
}
|
|
|
for (i=0;i<8;i++)
|
for (i=0;i<8;i++)
|
if (mtrrcntl->fixed4[i].raw != second->fixed4[i].raw) {
|
if (mtrrcntl->fixed4[i].raw != second->fixed4[i].raw) {
|
result = 1; goto end;
|
result = 1; goto end;
|
}
|
}
|
{
|
{
|
const int vcnt = mtrrcntl->MTRRcap.VCNT;
|
const int vcnt = mtrrcntl->MTRRcap.VCNT;
|
for (i = 0; i < vcnt; i++) {
|
for (i = 0; i < vcnt; i++) {
|
if (RAW_ACCESS64(mtrrcntl->variable[i].MTRRphysBase) !=
|
if (RAW_ACCESS64(mtrrcntl->variable[i].MTRRphysBase) !=
|
RAW_ACCESS64(second->variable[i].MTRRphysBase)) {
|
RAW_ACCESS64(second->variable[i].MTRRphysBase)) {
|
result = 1; goto end;
|
result = 1; goto end;
|
}
|
}
|
if (RAW_ACCESS64(mtrrcntl->variable[i].MTRRphysMask) !=
|
if (RAW_ACCESS64(mtrrcntl->variable[i].MTRRphysMask) !=
|
RAW_ACCESS64(second->variable[i].MTRRphysMask)) {
|
RAW_ACCESS64(second->variable[i].MTRRphysMask)) {
|
result = 1; goto end;
|
result = 1; goto end;
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
end:
|
end:
|
|
|
return result;
|
return result;
|
}
|
}
|
|
|
/*
|
/*
|
* compares the mtrr configuration of the current processor with the
|
* compares the mtrr configuration of the current processor with the
|
* main configuration and overwrites the mtrr's in the processor if they
|
* main configuration and overwrites the mtrr's in the processor if they
|
* differ. (fixes a bug in the GA-686DX mainboard BIOS)
|
* differ. (fixes a bug in the GA-686DX mainboard BIOS)
|
*/
|
*/
|
void check_mtrr_config(void) {
|
void check_mtrr_config(void) {
|
unsigned long cr4;
|
unsigned long cr4;
|
unsigned long flags;
|
unsigned long flags;
|
struct mtrr_cntl_t *this_cpu_setting;
|
struct mtrr_cntl_t *this_cpu_setting;
|
int result;
|
int result;
|
|
|
save_flags(flags); sti();
|
save_flags(flags); sti();
|
|
|
/* if global struct is not initialized return */
|
/* if global struct is not initialized return */
|
if (mtrrcntl == NULL) {
|
if (mtrrcntl == NULL) {
|
restore_flags(flags);
|
restore_flags(flags);
|
return;
|
return;
|
}
|
}
|
|
|
/* disable MTRR feature if this_cpu_setting == NULL */
|
/* disable MTRR feature if this_cpu_setting == NULL */
|
/* read mtrr configuration of this cpu */
|
/* read mtrr configuration of this cpu */
|
this_cpu_setting = read_mtrr_configuration();
|
this_cpu_setting = read_mtrr_configuration();
|
if (this_cpu_setting == NULL) {
|
if (this_cpu_setting == NULL) {
|
printk("/proc/mtrr: MTRR's are NOT supported by cpu %i.\n",
|
printk("/proc/mtrr: MTRR's are NOT supported by cpu %i.\n",
|
smp_processor_id());
|
smp_processor_id());
|
restore_flags(flags);
|
restore_flags(flags);
|
|
|
return;
|
return;
|
}
|
}
|
/* compare mtrr configuration */
|
/* compare mtrr configuration */
|
result = compare_mtrr_configuration(this_cpu_setting);
|
result = compare_mtrr_configuration(this_cpu_setting);
|
kfree(this_cpu_setting);
|
kfree(this_cpu_setting);
|
/* return if mtrr setting is correct */
|
/* return if mtrr setting is correct */
|
if (0 >= result) {
|
if (0 >= result) {
|
restore_flags(flags);
|
restore_flags(flags);
|
return;
|
return;
|
}
|
}
|
|
|
/* prepare cpu's for setting mtrr's */
|
/* prepare cpu's for setting mtrr's */
|
cr4 = pre_mtrr_change();
|
cr4 = pre_mtrr_change();
|
|
|
/* set all mtrr's */
|
/* set all mtrr's */
|
set_mtrr_fixed();
|
set_mtrr_fixed();
|
set_mtrr_variable();
|
set_mtrr_variable();
|
|
|
/* prepare cpu's for running */
|
/* prepare cpu's for running */
|
post_mtrr_change(mtrrcntl->MTRRdefType, cr4);
|
post_mtrr_change(mtrrcntl->MTRRdefType, cr4);
|
|
|
restore_flags(flags);
|
restore_flags(flags);
|
|
|
printk("\nBIOS bug workaround: MTRR configuration changed on cpu "
|
printk("\nBIOS bug workaround: MTRR configuration changed on cpu "
|
"%i.\n", smp_processor_id());
|
"%i.\n", smp_processor_id());
|
}
|
}
|
|
|
|
|