290 lines
7.6 KiB
Text
290 lines
7.6 KiB
Text
|
--- mtrr.c.org Fri Apr 21 15:15:24 2000
|
||
|
+++ mtrr.c Fri Apr 21 15:18:59 2000
|
||
|
@@ -482,11 +482,113 @@
|
||
|
return 0;
|
||
|
} /* End Function have_wrcomb */
|
||
|
|
||
|
+static void intel_get_fixed_mtrr (unsigned int reg, unsigned long *base,
|
||
|
+ unsigned long *size, mtrr_type *type)
|
||
|
+{
|
||
|
+ unsigned long lo, hi, calc_base, calc_size;
|
||
|
+ unsigned long msr_num;
|
||
|
+
|
||
|
+ reg-=get_num_var_ranges();
|
||
|
+
|
||
|
+ if (reg>=NUM_FIXED_RANGES) {
|
||
|
+ /* Invalid num. */
|
||
|
+ *base = 0;
|
||
|
+ *size = 0;
|
||
|
+ *type = 0;
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ switch(reg>>3){
|
||
|
+ case 0:
|
||
|
+ msr_num=MTRRfix64K_00000_MSR;
|
||
|
+ calc_base=0;
|
||
|
+ calc_size=65536;
|
||
|
+ break;
|
||
|
+ case 1:
|
||
|
+ msr_num=MTRRfix16K_80000_MSR;
|
||
|
+ calc_base=0x80000;
|
||
|
+ calc_size=16384;
|
||
|
+ break;
|
||
|
+ case 2:
|
||
|
+ msr_num=MTRRfix16K_A0000_MSR;
|
||
|
+ calc_base=0xA0000;
|
||
|
+ calc_size=16384;
|
||
|
+ break;
|
||
|
+ case 3:
|
||
|
+ msr_num=MTRRfix4K_C0000_MSR;
|
||
|
+ calc_base=0xC0000;
|
||
|
+ calc_size=4096;
|
||
|
+ break;
|
||
|
+ case 4:
|
||
|
+ msr_num=MTRRfix4K_C8000_MSR;
|
||
|
+ calc_base=0xC8000;
|
||
|
+ calc_size=4096;
|
||
|
+ break;
|
||
|
+ case 5:
|
||
|
+ msr_num=MTRRfix4K_D0000_MSR;
|
||
|
+ calc_base=0xD0000;
|
||
|
+ calc_size=4096;
|
||
|
+ break;
|
||
|
+ case 6:
|
||
|
+ msr_num=MTRRfix4K_D8000_MSR;
|
||
|
+ calc_base=0xD8000;
|
||
|
+ calc_size=4096;
|
||
|
+ break;
|
||
|
+ case 7:
|
||
|
+ msr_num=MTRRfix4K_E0000_MSR;
|
||
|
+ calc_base=0xE0000;
|
||
|
+ calc_size=4096;
|
||
|
+ break;
|
||
|
+ case 8:
|
||
|
+ msr_num=MTRRfix4K_E8000_MSR;
|
||
|
+ calc_base=0xE8000;
|
||
|
+ calc_size=4096;
|
||
|
+ break;
|
||
|
+ case 9:
|
||
|
+ msr_num=MTRRfix4K_F0000_MSR;
|
||
|
+ calc_base=0xF0000;
|
||
|
+ calc_size=4096;
|
||
|
+ break;
|
||
|
+ case 10:
|
||
|
+ msr_num=MTRRfix4K_F8000_MSR;
|
||
|
+ calc_base=0xF8000;
|
||
|
+ calc_size=4096;
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ msr_num=0;
|
||
|
+ calc_base=0;
|
||
|
+ calc_size=0;
|
||
|
+ break;
|
||
|
+ };
|
||
|
+
|
||
|
+ if (msr_num==0) {
|
||
|
+ /* Invalid num. */
|
||
|
+ *base = 0;
|
||
|
+ *size = 0;
|
||
|
+ *type = 0;
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ rdmsr(msr_num, lo, hi);
|
||
|
+
|
||
|
+ if(reg&4)lo=hi;
|
||
|
+ lo>>=8*(reg&3);
|
||
|
+
|
||
|
+ *type = (lo & 0xff);
|
||
|
+ *size=calc_size;
|
||
|
+ *base=calc_base+(reg&7)*calc_size;
|
||
|
+}
|
||
|
+
|
||
|
static void intel_get_mtrr (unsigned int reg, unsigned long *base,
|
||
|
unsigned long *size, mtrr_type *type)
|
||
|
{
|
||
|
unsigned long dummy, mask_lo, base_lo;
|
||
|
|
||
|
+ if(reg>=get_num_var_ranges()){
|
||
|
+ intel_get_fixed_mtrr(reg,base,size,type);
|
||
|
+ return;
|
||
|
+ };
|
||
|
+
|
||
|
rdmsr (MTRRphysMask_MSR(reg), mask_lo, dummy);
|
||
|
if ( (mask_lo & 0x800) == 0 )
|
||
|
{
|
||
|
@@ -624,6 +726,71 @@
|
||
|
static void (*get_mtrr) (unsigned int reg, unsigned long *base,
|
||
|
unsigned long *size, mtrr_type *type) = NULL;
|
||
|
|
||
|
+static int intel_set_fixed_mtrr (unsigned int reg, unsigned long base,
|
||
|
+ unsigned long size, mtrr_type type)
|
||
|
+/* currently, ignore size, only set the fixed mtrr that includes base */
|
||
|
+{
|
||
|
+ unsigned long lo, hi, mask, calc_size;
|
||
|
+ unsigned long msr_num, tmp_base;
|
||
|
+ int place;
|
||
|
+
|
||
|
+ if((size==0)&&(base==0)&&(type==0)) {
|
||
|
+ int max=get_num_var_ranges ();
|
||
|
+ intel_get_fixed_mtrr(reg,&base,&size,&type);
|
||
|
+ if(reg<max+16)type=6;
|
||
|
+ if(reg>=max+16)type=0;
|
||
|
+ };
|
||
|
+
|
||
|
+ if(size==0) {
|
||
|
+ size=0x1000;
|
||
|
+ type=0;
|
||
|
+ };
|
||
|
+
|
||
|
+ while(size>0)
|
||
|
+ {
|
||
|
+ if (base>=0x100000) return -EFAULT;
|
||
|
+ tmp_base = base >> 12 ;
|
||
|
+
|
||
|
+ if(tmp_base<128) {
|
||
|
+ msr_num=MTRRfix64K_00000_MSR;
|
||
|
+ place=tmp_base>>4;
|
||
|
+ calc_size=65536;
|
||
|
+ } else
|
||
|
+ if(tmp_base<192) {
|
||
|
+ msr_num=MTRRfix16K_80000_MSR+(tmp_base>=160);
|
||
|
+ place=(tmp_base>>2)&7l;
|
||
|
+ calc_size=16384;
|
||
|
+ } else {
|
||
|
+ msr_num=MTRRfix4K_C0000_MSR+((tmp_base&0x3f)>>3);
|
||
|
+ place=tmp_base&7;
|
||
|
+ calc_size=4096;
|
||
|
+ };
|
||
|
+
|
||
|
+ rdmsr(msr_num, lo, hi);
|
||
|
+
|
||
|
+ mask=0xff<<((place&3)<<3);
|
||
|
+
|
||
|
+ if(place&4) {
|
||
|
+ hi&=~mask;
|
||
|
+ hi|=type<<((place&3)<<3);
|
||
|
+ } else {
|
||
|
+ lo &=~mask;
|
||
|
+ lo|=type<<(place<<3);
|
||
|
+ };
|
||
|
+
|
||
|
+ wrmsr(msr_num, lo, hi);
|
||
|
+
|
||
|
+ if(size<calc_size)size=0;
|
||
|
+ else
|
||
|
+ {
|
||
|
+ size -= calc_size;
|
||
|
+ base += calc_size;
|
||
|
+ };
|
||
|
+ };
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
static void intel_set_mtrr_up (unsigned int reg, unsigned long base,
|
||
|
unsigned long size, mtrr_type type, int do_safe)
|
||
|
/* [SUMMARY] Set variable MTRR register on the local CPU.
|
||
|
@@ -637,15 +804,21 @@
|
||
|
*/
|
||
|
{
|
||
|
struct set_mtrr_context ctxt;
|
||
|
+ int max=get_num_var_ranges ();
|
||
|
|
||
|
if (do_safe) set_mtrr_prepare (&ctxt);
|
||
|
- if (size == 0)
|
||
|
+ if ((size == 0) && (reg<=max))
|
||
|
{
|
||
|
/* The invalid bit is kept in the mask, so we simply clear the
|
||
|
relevant mask register to disable a range. */
|
||
|
wrmsr (MTRRphysMask_MSR (reg), 0, 0);
|
||
|
}
|
||
|
else
|
||
|
+ if(base<0x100000)
|
||
|
+ {
|
||
|
+ intel_set_fixed_mtrr(reg,base,size,type);
|
||
|
+ }
|
||
|
+ else
|
||
|
{
|
||
|
wrmsr (MTRRphysBase_MSR (reg), base | type, 0);
|
||
|
wrmsr (MTRRphysMask_MSR (reg), ~(size - 1) | 0x800, 0);
|
||
|
@@ -1052,7 +1225,7 @@
|
||
|
[RETURNS] The index of the region on success, else -1 on error.
|
||
|
*/
|
||
|
{
|
||
|
- int i, max;
|
||
|
+ int i=0, max, fixed=0;
|
||
|
mtrr_type ltype;
|
||
|
unsigned long lbase, lsize;
|
||
|
|
||
|
@@ -1177,6 +1350,12 @@
|
||
|
if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
|
||
|
{
|
||
|
/* For Intel PPro stepping <= 7, must be 4 MiB aligned */
|
||
|
+ if (base + size < 0x100000)
|
||
|
+ {
|
||
|
+ fixed=1;
|
||
|
+ i=get_num_var_ranges ();
|
||
|
+ }
|
||
|
+ else
|
||
|
if ( (boot_cpu_data.x86 == 6) && (boot_cpu_data.x86_model == 1) &&
|
||
|
(boot_cpu_data.x86_mask <= 7) && ( base & ( (1 << 22) -1 ) ) )
|
||
|
{
|
||
|
@@ -1201,7 +1380,7 @@
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
}
|
||
|
- else if (base + size < 0x100000)
|
||
|
+ else if (!fixed && (base + size < 0x100000))
|
||
|
{
|
||
|
printk (KERN_WARNING "mtrr: cannot set region below 1 MiB (0x%lx,0x%lx)\n",
|
||
|
base, size);
|
||
|
@@ -1238,6 +1417,8 @@
|
||
|
max = get_num_var_ranges ();
|
||
|
/* Search for existing MTRR */
|
||
|
down(&main_lock);
|
||
|
+ if(!fixed)
|
||
|
+ {
|
||
|
for (i = 0; i < max; ++i)
|
||
|
{
|
||
|
(*get_mtrr) (i, &lbase, &lsize, <ype);
|
||
|
@@ -1273,6 +1454,7 @@
|
||
|
printk ("mtrr: no more MTRRs available\n");
|
||
|
return i;
|
||
|
}
|
||
|
+ }
|
||
|
set_mtrr (i, base, size, type);
|
||
|
usage_table[i] = 1;
|
||
|
compute_ascii ();
|
||
|
@@ -1516,7 +1698,9 @@
|
||
|
case MTRRIOC_GET_ENTRY:
|
||
|
if ( copy_from_user (&gentry, (void *) arg, sizeof gentry) )
|
||
|
return -EFAULT;
|
||
|
+/* This check should be done by get_mtrr.
|
||
|
if ( gentry.regnum >= get_num_var_ranges () ) return -EINVAL;
|
||
|
+*/
|
||
|
(*get_mtrr) (gentry.regnum, &gentry.base, &gentry.size, &type);
|
||
|
gentry.type = type;
|
||
|
if ( copy_to_user ( (void *) arg, &gentry, sizeof gentry) )
|
||
|
@@ -1597,6 +1781,19 @@
|
||
|
ascii_buf_bytes += strlen (ascii_buffer + ascii_buf_bytes);
|
||
|
}
|
||
|
}
|
||
|
+ if(boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
|
||
|
+ for (i = max; i < max+NUM_FIXED_RANGES; i++)
|
||
|
+ {
|
||
|
+ (*get_mtrr) (i, &base, &size, &type);
|
||
|
+ if(((i<max+16)&&(type!=6))||((i>=max+16)&&(type!=0)))
|
||
|
+ {
|
||
|
+ sprintf
|
||
|
+ (ascii_buffer + ascii_buf_bytes,
|
||
|
+ "reg%02i: base=0x%08lx (%4likB), size=%4likB: %s, count=%d\n",
|
||
|
+ i, base, base>>10, size>>10, attrib_to_str (type), 1);
|
||
|
+ ascii_buf_bytes += strlen (ascii_buffer + ascii_buf_bytes);
|
||
|
+ }
|
||
|
+ }
|
||
|
devfs_set_file_size (devfs_handle, ascii_buf_bytes);
|
||
|
# ifdef CONFIG_PROC_FS
|
||
|
proc_root_mtrr->size = ascii_buf_bytes;
|