--- 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=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= 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!=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); } }