⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mtrr.c

📁 这个linux源代码是很全面的~基本完整了~使用c编译的~由于时间问题我没有亲自测试~但就算用来做参考资料也是非常好的
💻 C
📖 第 1 页 / 共 3 页
字号:
/*  x86-64 MTRR (Memory Type Range Register) driver.	Based largely upon arch/i386/kernel/mtrr.c	Copyright (C) 1997-2000  Richard Gooch	Copyright (C) 2002 Dave Jones.	This library is free software; you can redistribute it and/or	modify it under the terms of the GNU Library General Public	License as published by the Free Software Foundation; either	version 2 of the License, or (at your option) any later version.	This library is distributed in the hope that it will be useful,	but WITHOUT ANY WARRANTY; without even the implied warranty of	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU	Library General Public License for more details.	You should have received a copy of the GNU Library General Public	License along with this library; if not, write to the Free	Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.	(For earlier history, see arch/i386/kernel/mtrr.c)	v2.00	September 2001	Dave Jones <davej@suse.de>	  Initial rewrite for x86-64.	  Removal of non-Intel style MTRR code.	v2.01  June 2002  Dave Jones <davej@suse.de>	  Removal of redundant abstraction layer.	  64-bit fixes.	v2.02  July 2002  Dave Jones <davej@suse.de>	  Fix gentry inconsistencies between kernel/userspace.	  More casts to clean up warnings.*/#include <linux/types.h>#include <linux/errno.h>#include <linux/sched.h>#include <linux/tty.h>#include <linux/timer.h>#include <linux/config.h>#include <linux/kernel.h>#include <linux/wait.h>#include <linux/string.h>#include <linux/slab.h>#include <linux/ioport.h>#include <linux/delay.h>#include <linux/fs.h>#include <linux/ctype.h>#include <linux/proc_fs.h>#include <linux/devfs_fs_kernel.h>#include <linux/mm.h>#include <linux/module.h>#define MTRR_NEED_STRINGS#include <asm/mtrr.h>#include <linux/init.h>#include <linux/smp.h>#include <linux/smp_lock.h>#include <linux/agp_backend.h>#include <asm/uaccess.h>#include <asm/io.h>#include <asm/processor.h>#include <asm/system.h>#include <asm/pgtable.h>#include <asm/segment.h>#include <asm/bitops.h>#include <asm/atomic.h>#include <asm/msr.h>#include <asm/hardirq.h>#include <linux/irq.h>#define MTRR_VERSION "2.02 (20020716)"#undef Dprintk#define Dprintk(...) #define TRUE  1#define FALSE 0#define MSR_MTRRphysBase(reg) (0x200 + 2 * (reg))#define MSR_MTRRphysMask(reg) (0x200 + 2 * (reg) + 1)#define NUM_FIXED_RANGES 88#define MTRR_CHANGE_MASK_FIXED 0x01#define MTRR_CHANGE_MASK_VARIABLE 0x02#define MTRR_CHANGE_MASK_DEFTYPE 0x04typedef u8 mtrr_type;#define LINE_SIZE 80#ifdef CONFIG_SMP#define set_mtrr(reg,base,size,type) set_mtrr_smp (reg, base, size, type)#else#define set_mtrr(reg,base,size,type) set_mtrr_up (reg, base, size, type, TRUE)#endif#if defined(CONFIG_PROC_FS) || defined(CONFIG_DEVFS_FS)#define USERSPACE_INTERFACE#endif#ifdef USERSPACE_INTERFACEstatic char *ascii_buffer;static unsigned int ascii_buf_bytes;static void compute_ascii (void);#else#define compute_ascii() while (0)#endifstatic unsigned int *usage_table;static DECLARE_MUTEX (mtrr_lock);struct set_mtrr_context {	u32 deftype_lo;	u32 deftype_hi;	unsigned long flags;	u64 cr4val;};/*  Put the processor into a state where MTRRs can be safely set  */static void set_mtrr_prepare (struct set_mtrr_context *ctxt){	u64 cr0;	/* Disable interrupts locally */	__save_flags(ctxt->flags);	__cli();	/* Save value of CR4 and clear Page Global Enable (bit 7) */	if (test_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability)) {		ctxt->cr4val = read_cr4();		write_cr4(ctxt->cr4val & ~(1UL << 7));	}	/* Disable and flush caches. Note that wbinvd flushes the TLBs as	   a side-effect */	cr0 = read_cr0() | 0x40000000;	wbinvd();	write_cr0(cr0);	wbinvd();	/* Disable MTRRs, and set the default type to uncached */	rdmsr(MSR_MTRRdefType, ctxt->deftype_lo, ctxt->deftype_hi);	wrmsr(MSR_MTRRdefType, ctxt->deftype_lo & 0xf300UL, ctxt->deftype_hi);}/* Restore the processor after a set_mtrr_prepare */static void set_mtrr_done (struct set_mtrr_context *ctxt){	/* Flush caches and TLBs */	wbinvd();	/* Restore MTRRdefType */	wrmsr(MSR_MTRRdefType, ctxt->deftype_lo, ctxt->deftype_hi);	/* Enable caches */	write_cr0(read_cr0() & 0xbfffffff);	/* Restore value of CR4 */	if (test_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability))		write_cr4 (ctxt->cr4val);	/* Re-enable interrupts locally (if enabled previously) */	__restore_flags(ctxt->flags);}/*  This function returns the number of variable MTRRs  */static unsigned int get_num_var_ranges (void){	u32 config, dummy;	rdmsr (MSR_MTRRcap, config, dummy);	return (config & 0xff);}/*  Returns non-zero if we have the write-combining memory type  */static int have_wrcomb (void){	u32 config, dummy;	rdmsr (MSR_MTRRcap, config, dummy);	return (config & (1 << 10));}static u64 size_or_mask, size_and_mask;static void get_mtrr (unsigned int reg, u64 *base, u32 *size, mtrr_type * type){	u32 mask_lo, mask_hi, base_lo, base_hi;	u64 newsize;	rdmsr (MSR_MTRRphysMask(reg), mask_lo, mask_hi);	if ((mask_lo & 0x800) == 0) {		/*  Invalid (i.e. free) range  */		*base = 0;		*size = 0;		*type = 0;		return;	}	rdmsr (MSR_MTRRphysBase(reg), base_lo, base_hi);	/* Work out the shifted address mask. */	newsize = (u64) mask_hi << 32 | (mask_lo & ~0x800);	newsize = ~newsize+1;	*size = (u32) newsize >> PAGE_SHIFT;	*base = base_hi << (32 - PAGE_SHIFT) | base_lo >> PAGE_SHIFT;	*type = base_lo & 0xff;}/* * Set variable MTRR register on the local CPU. *  <reg> The register to set. *  <base> The base address of the region. *  <size> The size of the region. If this is 0 the region is disabled. *  <type> The type of the region. *  <do_safe> If TRUE, do the change safely. If FALSE, safety measures should *  be done externally. */static void set_mtrr_up (unsigned int reg, u64 base,		   u32 size, mtrr_type type, int do_safe){	struct set_mtrr_context ctxt;	u64 base64;	u64 size64;	if (do_safe)		set_mtrr_prepare (&ctxt);	if (size == 0) {		/* The invalid bit is kept in the mask, so we simply clear the		   relevant mask register to disable a range. */		wrmsr (MSR_MTRRphysMask(reg), 0, 0);	} else {		base64 = (base << PAGE_SHIFT) & size_and_mask;		wrmsr (MSR_MTRRphysBase(reg), base64 | type, base64 >> 32);		size64 = ~((size << PAGE_SHIFT) - 1);		size64 = size64 & size_and_mask;		wrmsr (MSR_MTRRphysMask(reg), (u32) (size64 | 0x800), (u32) (size64 >> 32));	}	if (do_safe)		set_mtrr_done (&ctxt);}#ifdef CONFIG_SMPstruct mtrr_var_range {	u32 base_lo;	u32 base_hi;	u32 mask_lo;	u32 mask_hi;};/*  Get the MSR pair relating to a var range  */static void __init get_mtrr_var_range (unsigned int index,		struct mtrr_var_range *vr){	rdmsr (MSR_MTRRphysBase(index), vr->base_lo, vr->base_hi);	rdmsr (MSR_MTRRphysMask(index), vr->mask_lo, vr->mask_hi);}/*  Set the MSR pair relating to a var range. Returns TRUE if    changes are made  */static int __init set_mtrr_var_range_testing (unsigned int index,		struct mtrr_var_range *vr){	u32 lo, hi;	int changed = FALSE;	rdmsr (MSR_MTRRphysBase(index), lo, hi);	if ((vr->base_lo & 0xfffff0ff) != (lo & 0xfffff0ff) ||		(vr->base_hi & 0x000fffff) != (hi & 0x000fffff)) {		wrmsr (MSR_MTRRphysBase(index), vr->base_lo, vr->base_hi);		changed = TRUE;	}	rdmsr (MSR_MTRRphysMask(index), lo, hi);	if ((vr->mask_lo & 0xfffff800) != (lo & 0xfffff800) ||		(vr->mask_hi & 0x000fffff) != (hi & 0x000fffff)) {		wrmsr (MSR_MTRRphysMask(index), vr->mask_lo, vr->mask_hi);		changed = TRUE;	}	return changed;}static void __init get_fixed_ranges (mtrr_type * frs){	u32 *p = (u32 *) frs;	int i;	rdmsr (MSR_MTRRfix64K_00000, p[0], p[1]);	for (i = 0; i < 2; i++)		rdmsr (MSR_MTRRfix16K_80000 + i, p[2 + i * 2], p[3 + i * 2]);	for (i = 0; i < 8; i++)		rdmsr (MSR_MTRRfix4K_C0000 + i, p[6 + i * 2], p[7 + i * 2]);}static int __init set_fixed_ranges_testing (mtrr_type * frs){	u32 *p = (u32 *) frs;	int changed = FALSE;	int i;	u32 lo, hi;	Dprintk (KERN_INFO "mtrr: rdmsr 64K_00000\n");	rdmsr (MSR_MTRRfix64K_00000, lo, hi);	if (p[0] != lo || p[1] != hi) {		Dprintk (KERN_INFO "mtrr: Writing %x:%x to 64K MSR. lohi were %x:%x\n", p[0], p[1], lo, hi);		wrmsr (MSR_MTRRfix64K_00000, p[0], p[1]);		changed = TRUE;	}	Dprintk (KERN_INFO "mtrr: rdmsr 16K_80000\n");	for (i = 0; i < 2; i++) {		rdmsr (MSR_MTRRfix16K_80000 + i, lo, hi);		if (p[2 + i * 2] != lo || p[3 + i * 2] != hi) {			Dprintk (KERN_INFO "mtrr: Writing %x:%x to 16K MSR%d. lohi were %x:%x\n", p[2 + i * 2], p[3 + i * 2], i, lo, hi );			wrmsr (MSR_MTRRfix16K_80000 + i, p[2 + i * 2], p[3 + i * 2]);			changed = TRUE;		}	}	Dprintk (KERN_INFO "mtrr: rdmsr 4K_C0000\n");	for (i = 0; i < 8; i++) {		rdmsr (MSR_MTRRfix4K_C0000 + i, lo, hi);		Dprintk (KERN_INFO "mtrr: MTRRfix4K_C0000+%d = %x:%x\n", i, lo, hi);		if (p[6 + i * 2] != lo || p[7 + i * 2] != hi) {			Dprintk (KERN_INFO "mtrr: Writing %x:%x to 4K MSR%d. lohi were %x:%x\n", p[6 + i * 2], p[7 + i * 2], i, lo, hi);			wrmsr (MSR_MTRRfix4K_C0000 + i, p[6 + i * 2], p[7 + i * 2]);			changed = TRUE;		}	}	return changed;}struct mtrr_state {	unsigned int num_var_ranges;	struct mtrr_var_range *var_ranges;	mtrr_type fixed_ranges[NUM_FIXED_RANGES];	mtrr_type def_type;	unsigned char enabled;};/*  Grab all of the MTRR state for this CPU into *state  */static void __init get_mtrr_state (struct mtrr_state *state){	unsigned int nvrs, i;	struct mtrr_var_range *vrs;	u32 lo, dummy;	nvrs = state->num_var_ranges = get_num_var_ranges();	vrs = state->var_ranges	    = kmalloc (nvrs * sizeof (struct mtrr_var_range), GFP_KERNEL);	if (vrs == NULL)		nvrs = state->num_var_ranges = 0;	for (i = 0; i < nvrs; i++)		get_mtrr_var_range (i, &vrs[i]);	get_fixed_ranges (state->fixed_ranges);	rdmsr (MSR_MTRRdefType, lo, dummy);	state->def_type = (lo & 0xff);	state->enabled = (lo & 0xc00) >> 10;}/*  Free resources associated with a struct mtrr_state  */static void __init finalize_mtrr_state (struct mtrr_state *state){	if (state->var_ranges)		kfree (state->var_ranges);}/* * Set the MTRR state for this CPU. *  <state> The MTRR state information to read. *  <ctxt> Some relevant CPU context. *  [NOTE] The CPU must already be in a safe state for MTRR changes. *  [RETURNS] 0 if no changes made, else a mask indication what was changed. */static u64 __init set_mtrr_state (struct mtrr_state *state,		struct set_mtrr_context *ctxt){	unsigned int i;	u64 change_mask = 0;	for (i = 0; i < state->num_var_ranges; i++)		if (set_mtrr_var_range_testing (i, &state->var_ranges[i]))			change_mask |= MTRR_CHANGE_MASK_VARIABLE;	if (set_fixed_ranges_testing (state->fixed_ranges))		change_mask |= MTRR_CHANGE_MASK_FIXED;	/* Set_mtrr_restore restores the old value of MTRRdefType,	   so to set it we fiddle with the saved value  */	if ((ctxt->deftype_lo & 0xff) != state->def_type	    || ((ctxt->deftype_lo & 0xc00) >> 10) != state->enabled) {		ctxt->deftype_lo |= (state->def_type | state->enabled << 10);		change_mask |= MTRR_CHANGE_MASK_DEFTYPE;	}	return change_mask;}static atomic_t undone_count;static volatile int wait_barrier_execute = FALSE;static volatile int wait_barrier_cache_enable = FALSE;struct set_mtrr_data {	u64 smp_base;	u32 smp_size;	unsigned int smp_reg;	mtrr_type smp_type;};/* * Synchronisation handler. Executed by "other" CPUs. */static void ipi_handler (void *info){	struct set_mtrr_data *data = info;	struct set_mtrr_context ctxt;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -