365 lines
9.4 KiB
Text
365 lines
9.4 KiB
Text
|
--- mtrr.c.orig Thu May 4 10:59:14 2000
|
||
|
+++ linux/arch/i386/kernel/mtrr.c Thu May 4 11:06:10 2000
|
||
|
@@ -464,11 +464,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) {
|
||
|
/* Invalid (i.e. free) range. */
|
||
|
@@ -614,6 +716,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.
|
||
|
@@ -627,15 +794,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);
|
||
|
@@ -1005,7 +1178,7 @@
|
||
|
|
||
|
static void init_table (void)
|
||
|
{
|
||
|
- int i, max;
|
||
|
+ int i, max ;
|
||
|
|
||
|
max = get_num_var_ranges ();
|
||
|
if ( ( usage_table = kmalloc (max * sizeof *usage_table, GFP_KERNEL) )
|
||
|
@@ -1015,15 +1188,6 @@
|
||
|
return;
|
||
|
}
|
||
|
for (i = 0; i < max; i++) usage_table[i] = 1;
|
||
|
-#ifdef CONFIG_PROC_FS
|
||
|
- if ( ( ascii_buffer = kmalloc (max * LINE_SIZE, GFP_KERNEL) ) == NULL )
|
||
|
- {
|
||
|
- printk ("mtrr: could not allocate\n");
|
||
|
- return;
|
||
|
- }
|
||
|
- ascii_buf_bytes = 0;
|
||
|
- compute_ascii ();
|
||
|
-#endif
|
||
|
} /* End Function init_table */
|
||
|
|
||
|
static int generic_get_free_region (unsigned long base, unsigned long size)
|
||
|
@@ -1091,9 +1255,10 @@
|
||
|
[NOTE] This routine uses a spinlock.
|
||
|
*/
|
||
|
{
|
||
|
- int i, max;
|
||
|
+ int i=0, max;
|
||
|
mtrr_type ltype;
|
||
|
unsigned long lbase, lsize, last;
|
||
|
+ int fixed=0;
|
||
|
|
||
|
if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return -ENODEV;
|
||
|
if (type >= MTRR_NUM_TYPES)
|
||
|
@@ -1126,6 +1291,11 @@
|
||
|
printk ("mtrr: base(0x%lx) is not 4 MiB aligned\n", base);
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
+ if (base + size < 0x100000)
|
||
|
+ {
|
||
|
+ fixed=1;
|
||
|
+ i=get_num_var_ranges ();
|
||
|
+ };
|
||
|
/* Fall through */
|
||
|
case X86_VENDOR_CYRIX:
|
||
|
case X86_VENDOR_CENTAUR:
|
||
|
@@ -1142,7 +1312,7 @@
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
}
|
||
|
- else if (base + size < 0x100000) /* Cyrix */
|
||
|
+ else if ((!fixed) && (base + size < 0x100000))
|
||
|
{
|
||
|
printk ("mtrr: cannot set region below 1 MiB (0x%lx,0x%lx)\n",
|
||
|
base, size);
|
||
|
@@ -1174,6 +1344,8 @@
|
||
|
max = get_num_var_ranges ();
|
||
|
/* Search for existing MTRR */
|
||
|
spin_lock_reschedule (&main_lock);
|
||
|
+ if(!fixed)
|
||
|
+ {
|
||
|
for (i = 0; i < max; ++i)
|
||
|
{
|
||
|
(*get_mtrr) (i, &lbase, &lsize, <ype);
|
||
|
@@ -1210,9 +1382,12 @@
|
||
|
printk ("mtrr: no more MTRRs available\n");
|
||
|
return i;
|
||
|
}
|
||
|
+ }
|
||
|
set_mtrr (i, base, size, type);
|
||
|
+ if(!fixed)
|
||
|
+ {
|
||
|
usage_table[i] = 1;
|
||
|
- compute_ascii ();
|
||
|
+ };
|
||
|
spin_unlock (&main_lock);
|
||
|
return i;
|
||
|
} /* End Function mtrr_add */
|
||
|
@@ -1274,7 +1449,6 @@
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
if (--usage_table[reg] < 1) set_mtrr (reg, 0, 0, 0);
|
||
|
- compute_ascii ();
|
||
|
spin_unlock (&main_lock);
|
||
|
return reg;
|
||
|
} /* End Function mtrr_del */
|
||
|
@@ -1319,11 +1493,30 @@
|
||
|
|
||
|
static ssize_t mtrr_read (struct file *file, char *buf, size_t len,
|
||
|
loff_t *ppos)
|
||
|
-{
|
||
|
- if (*ppos >= ascii_buf_bytes) return 0;
|
||
|
+{ int size;
|
||
|
+
|
||
|
+ size=get_num_var_ranges()+NUM_FIXED_RANGES;
|
||
|
+ if ( ( ascii_buffer = kmalloc (size * LINE_SIZE, GFP_KERNEL) ) == NULL )
|
||
|
+ {
|
||
|
+ printk ("mtrr: could not allocate\n");
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+ ascii_buf_bytes = 0;
|
||
|
+ compute_ascii ();
|
||
|
+
|
||
|
+ if (*ppos >= ascii_buf_bytes)
|
||
|
+ {
|
||
|
+ kfree(ascii_buffer);
|
||
|
+ return 0;
|
||
|
+ };
|
||
|
if (*ppos + len > ascii_buf_bytes) len = ascii_buf_bytes - *ppos;
|
||
|
- if ( copy_to_user (buf, ascii_buffer + *ppos, len) ) return -EFAULT;
|
||
|
+ if ( copy_to_user (buf, ascii_buffer + *ppos, len) )
|
||
|
+ {
|
||
|
+ kfree(ascii_buffer);
|
||
|
+ return -EFAULT;
|
||
|
+ };
|
||
|
*ppos += len;
|
||
|
+ kfree(ascii_buffer);
|
||
|
return len;
|
||
|
} /* End Function mtrr_read */
|
||
|
|
||
|
@@ -1429,7 +1622,9 @@
|
||
|
case MTRRIOC_GET_ENTRY:
|
||
|
if ( copy_from_user (&gentry, (void *) arg, sizeof gentry) )
|
||
|
return -EFAULT;
|
||
|
+#if 0 /* this should be done by the called function */
|
||
|
if ( gentry.regnum >= get_num_var_ranges () ) return -EINVAL;
|
||
|
+#endif
|
||
|
(*get_mtrr) (gentry.regnum, &gentry.base, &gentry.size, &type);
|
||
|
gentry.type = type;
|
||
|
if ( copy_to_user ( (void *) arg, &gentry, sizeof gentry) )
|
||
|
@@ -1542,6 +1737,19 @@
|
||
|
"reg%02i: base=0x%08lx (%4liMB), size=%4li%cB: %s, count=%d\n",
|
||
|
i, base, base>>20, size, factor,
|
||
|
attrib_to_str (type), usage_table[i]);
|
||
|
+ 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);
|
||
|
}
|
||
|
}
|