SvgaLib/kernel/patch.mtrr.2.3.99

290 lines
7.6 KiB
Text
Raw Normal View History

--- 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, &ltype);
@@ -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;