📄 mtrr.c
字号:
mtrr_type type; struct mtrr_sentry sentry; struct mtrr_gentry gentry; switch (cmd) { default: return -ENOIOCTLCMD; case MTRRIOC_ADD_ENTRY: if ( !suser () ) return -EPERM; if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) ) return -EFAULT; err = mtrr_file_add (sentry.base, sentry.size, sentry.type, 1, file, 0); if (err < 0) return err; break; case MTRRIOC_SET_ENTRY: if ( !suser () ) return -EPERM; if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) ) return -EFAULT; err = mtrr_add (sentry.base, sentry.size, sentry.type, 0); if (err < 0) return err; break; case MTRRIOC_DEL_ENTRY: if ( !suser () ) return -EPERM; if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) ) return -EFAULT; err = mtrr_file_del (sentry.base, sentry.size, file, 0); if (err < 0) return err; break; case MTRRIOC_KILL_ENTRY: if ( !suser () ) return -EPERM; if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) ) return -EFAULT; err = mtrr_del (-1, sentry.base, sentry.size); if (err < 0) return err; break; case MTRRIOC_GET_ENTRY: if ( copy_from_user (&gentry, (void *) arg, sizeof gentry) ) return -EFAULT; if ( gentry.regnum >= get_num_var_ranges () ) return -EINVAL; (*get_mtrr) (gentry.regnum, &gentry.base, &gentry.size, &type); /* Hide entries that go above 4GB */ if (gentry.base + gentry.size > 0x100000 || gentry.size == 0x100000) gentry.base = gentry.size = gentry.type = 0; else { gentry.base <<= PAGE_SHIFT; gentry.size <<= PAGE_SHIFT; gentry.type = type; } if ( copy_to_user ( (void *) arg, &gentry, sizeof gentry) ) return -EFAULT; break; case MTRRIOC_ADD_PAGE_ENTRY: if ( !suser () ) return -EPERM; if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) ) return -EFAULT; err = mtrr_file_add (sentry.base, sentry.size, sentry.type, 1, file, 1); if (err < 0) return err; break; case MTRRIOC_SET_PAGE_ENTRY: if ( !suser () ) return -EPERM; if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) ) return -EFAULT; err = mtrr_add_page (sentry.base, sentry.size, sentry.type, 0); if (err < 0) return err; break; case MTRRIOC_DEL_PAGE_ENTRY: if ( !suser () ) return -EPERM; if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) ) return -EFAULT; err = mtrr_file_del (sentry.base, sentry.size, file, 1); if (err < 0) return err; break; case MTRRIOC_KILL_PAGE_ENTRY: if ( !suser () ) return -EPERM; if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) ) return -EFAULT; err = mtrr_del_page (-1, sentry.base, sentry.size); if (err < 0) return err; break; case MTRRIOC_GET_PAGE_ENTRY: if ( copy_from_user (&gentry, (void *) arg, sizeof gentry) ) return -EFAULT; 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) ) return -EFAULT; break; } return 0;} /* End Function mtrr_ioctl */static int mtrr_close (struct inode *ino, struct file *file){ int i, max; unsigned int *fcount = file->private_data; if (fcount == NULL) return 0; lock_kernel(); max = get_num_var_ranges (); for (i = 0; i < max; ++i) { while (fcount[i] > 0) { if (mtrr_del (i, 0, 0) < 0) printk ("mtrr: reg %d not used\n", i); --fcount[i]; } } unlock_kernel(); kfree (fcount); file->private_data = NULL; return 0;} /* End Function mtrr_close */static struct file_operations mtrr_fops ={ owner: THIS_MODULE, read: mtrr_read, write: mtrr_write, ioctl: mtrr_ioctl, release: mtrr_close,};# ifdef CONFIG_PROC_FSstatic struct proc_dir_entry *proc_root_mtrr;# endif /* CONFIG_PROC_FS */static devfs_handle_t devfs_handle;static void compute_ascii (void){ char factor; int i, max; mtrr_type type; unsigned long base, size; ascii_buf_bytes = 0; max = get_num_var_ranges (); for (i = 0; i < max; i++) { (*get_mtrr) (i, &base, &size, &type); if (size == 0) usage_table[i] = 0; else { if (size < (0x100000 >> PAGE_SHIFT)) { /* less than 1MB */ factor = 'K'; size <<= PAGE_SHIFT - 10; } else { factor = 'M'; size >>= 20 - PAGE_SHIFT; } sprintf (ascii_buffer + ascii_buf_bytes, "reg%02i: base=0x%05lx000 (%4liMB), size=%4li%cB: %s, count=%d\n", i, base, base >> (20 - PAGE_SHIFT), size, factor, attrib_to_str (type), usage_table[i]); ascii_buf_bytes += strlen (ascii_buffer + ascii_buf_bytes); } } devfs_set_file_size (devfs_handle, ascii_buf_bytes);# ifdef CONFIG_PROC_FS if (proc_root_mtrr) proc_root_mtrr->size = ascii_buf_bytes;# endif /* CONFIG_PROC_FS */} /* End Function compute_ascii */#endif /* USERSPACE_INTERFACE */EXPORT_SYMBOL(mtrr_add);EXPORT_SYMBOL(mtrr_del);#ifdef CONFIG_SMPtypedef struct{ unsigned long base; unsigned long size; mtrr_type type;} arr_state_t;arr_state_t arr_state[8] __initdata ={ {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}};unsigned char ccr_state[7] __initdata = { 0, 0, 0, 0, 0, 0, 0 };static void __init cyrix_arr_init_secondary(void){ struct set_mtrr_context ctxt; int i; set_mtrr_prepare (&ctxt); /* flush cache and enable MAPEN */ /* the CCRs are not contiguous */ for(i=0; i<4; i++) setCx86(CX86_CCR0 + i, ccr_state[i]); for( ; i<7; i++) setCx86(CX86_CCR4 + i, ccr_state[i]); for(i=0; i<8; i++) cyrix_set_arr_up(i, arr_state[i].base, arr_state[i].size, arr_state[i].type, FALSE); set_mtrr_done (&ctxt); /* flush cache and disable MAPEN */} /* End Function cyrix_arr_init_secondary */#endif/* * On Cyrix 6x86(MX) and M II the ARR3 is special: it has connection * with the SMM (System Management Mode) mode. So we need the following: * Check whether SMI_LOCK (CCR3 bit 0) is set * if it is set, write a warning message: ARR3 cannot be changed! * (it cannot be changed until the next processor reset) * if it is reset, then we can change it, set all the needed bits: * - disable access to SMM memory through ARR3 range (CCR1 bit 7 reset) * - disable access to SMM memory (CCR1 bit 2 reset) * - disable SMM mode (CCR1 bit 1 reset) * - disable write protection of ARR3 (CCR6 bit 1 reset) * - (maybe) disable ARR3 * Just to be sure, we enable ARR usage by the processor (CCR5 bit 5 set) */static void __init cyrix_arr_init(void){ struct set_mtrr_context ctxt; unsigned char ccr[7]; int ccrc[7] = { 0, 0, 0, 0, 0, 0, 0 };#ifdef CONFIG_SMP int i;#endif set_mtrr_prepare (&ctxt); /* flush cache and enable MAPEN */ /* Save all CCRs locally */ ccr[0] = getCx86 (CX86_CCR0); ccr[1] = getCx86 (CX86_CCR1); ccr[2] = getCx86 (CX86_CCR2); ccr[3] = ctxt.ccr3; ccr[4] = getCx86 (CX86_CCR4); ccr[5] = getCx86 (CX86_CCR5); ccr[6] = getCx86 (CX86_CCR6); if (ccr[3] & 1) { ccrc[3] = 1; arr3_protected = 1; } else { /* Disable SMM mode (bit 1), access to SMM memory (bit 2) and * access to SMM memory through ARR3 (bit 7). */ if (ccr[1] & 0x80) { ccr[1] &= 0x7f; ccrc[1] |= 0x80; } if (ccr[1] & 0x04) { ccr[1] &= 0xfb; ccrc[1] |= 0x04; } if (ccr[1] & 0x02) { ccr[1] &= 0xfd; ccrc[1] |= 0x02; } arr3_protected = 0; if (ccr[6] & 0x02) { ccr[6] &= 0xfd; ccrc[6] = 1; /* Disable write protection of ARR3 */ setCx86 (CX86_CCR6, ccr[6]); } /* Disable ARR3. This is safe now that we disabled SMM. */ /* cyrix_set_arr_up (3, 0, 0, 0, FALSE); */ } /* If we changed CCR1 in memory, change it in the processor, too. */ if (ccrc[1]) setCx86 (CX86_CCR1, ccr[1]); /* Enable ARR usage by the processor */ if (!(ccr[5] & 0x20)) { ccr[5] |= 0x20; ccrc[5] = 1; setCx86 (CX86_CCR5, ccr[5]); }#ifdef CONFIG_SMP for(i=0; i<7; i++) ccr_state[i] = ccr[i]; for(i=0; i<8; i++) cyrix_get_arr(i, &arr_state[i].base, &arr_state[i].size, &arr_state[i].type);#endif set_mtrr_done (&ctxt); /* flush cache and disable MAPEN */ if ( ccrc[5] ) printk ("mtrr: ARR usage was not enabled, enabled manually\n"); if ( ccrc[3] ) printk ("mtrr: ARR3 cannot be changed\n");/* if ( ccrc[1] & 0x80) printk ("mtrr: SMM memory access through ARR3 disabled\n"); if ( ccrc[1] & 0x04) printk ("mtrr: SMM memory access disabled\n"); if ( ccrc[1] & 0x02) printk ("mtrr: SMM mode disabled\n");*/ if ( ccrc[6] ) printk ("mtrr: ARR3 was write protected, unprotected\n");} /* End Function cyrix_arr_init *//* * Initialise the later (saner) Winchip MCR variant. In this version * the BIOS can pass us the registers it has used (but not their values) * and the control register is read/write */ static void __init centaur_mcr1_init(void){ unsigned i; u32 lo, hi; /* Unfortunately, MCR's are read-only, so there is no way to * find out what the bios might have done. */ rdmsr(MSR_IDT_MCR_CTRL, lo, hi); if(((lo>>17)&7)==1) /* Type 1 Winchip2 MCR */ { lo&= ~0x1C0; /* clear key */ lo|= 0x040; /* set key to 1 */ wrmsr(MSR_IDT_MCR_CTRL, lo, hi); /* unlock MCR */ } centaur_mcr_type = 1; /* * Clear any unconfigured MCR's. */ for (i = 0; i < 8; ++i) { if(centaur_mcr[i]. high == 0 && centaur_mcr[i].low == 0) { if(!(lo & (1<<(9+i)))) wrmsr (MSR_IDT_MCR0 + i , 0, 0); else /* * If the BIOS set up an MCR we cannot see it * but we don't wish to obliterate it */ centaur_mcr_reserved |= (1<<i); } } /* * Throw the main write-combining switch... * However if OOSTORE is enabled then people have already done far * cleverer things and we should behave. */ lo |= 15; /* Write combine enables */ wrmsr(MSR_IDT_MCR_CTRL, lo, hi);} /* End Function centaur_mcr1_init *//* * Initialise the original winchip with read only MCR registers * no used bitmask for the BIOS to pass on and write only control */ static void __init centaur_mcr0_init(void){ unsigned i; /* Unfortunately, MCR's are read-only, so there is no way to * find out what the bios might have done. */ /* Clear any unconfigured MCR's. * This way we are sure that the centaur_mcr array contains the actual * values. The disadvantage is that any BIOS tweaks are thus undone. * */ for (i = 0; i < 8; ++i) { if(centaur_mcr[i]. high == 0 && centaur_mcr[i].low == 0) wrmsr (MSR_IDT_MCR0 + i , 0, 0); } wrmsr(MSR_IDT_MCR_CTRL, 0x01F0001F, 0); /* Write only */} /* End Function centaur_mcr0_init *//* * Initialise Winchip series MCR registers */ static void __init centaur_mcr_init(void){ struct set_mtrr_context ctxt; set_mtrr_prepare (&ctxt); if(boot_cpu_data.x86_model==4) centaur_mcr0_init(); else if(boot_cpu_data.x86_model==8 || boot_cpu_data.x86_model == 9) centaur_mcr1_init(); set_mtrr_done (&ctxt);} /* End Function centaur_mcr_init */static int __init mtrr_setup(void){ if ( test_bit(X86_FEATURE_MTRR, &boot_cpu_data.x86_capability) ) { /* Intel (P6) standard MTRRs */ mtrr_if = MTRR_IF_INTEL; get_mtrr = intel_get_mtrr; set_mtrr_up = intel_set_mtrr_up; switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: /* The original Athlon docs said that total addressable memory is 44 bits wide. It was not really clear whether its MTRRs follow this or not. (Read: 44 or 36 bits). However, "x86-64_overview.pdf" explicitly states that "previous implementations support 36 bit MTRRs" and also provides a way to query the width (in bits) of the physical addressable memor
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -