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

📄 mtrr.c

📁 这个linux源代码是很全面的~基本完整了~使用c编译的~由于时间问题我没有亲自测试~但就算用来做参考资料也是非常好的
💻 C
📖 第 1 页 / 共 3 页
字号:
	set_mtrr_prepare (&ctxt);	/* Notify master that I've flushed and disabled my cache  */	atomic_dec (&undone_count);	while (wait_barrier_execute)		barrier ();	/* The master has cleared me to execute  */	set_mtrr_up (data->smp_reg, data->smp_base, data->smp_size,			data->smp_type, FALSE);	/* Notify master CPU that I've executed the function  */	atomic_dec (&undone_count);	/* Wait for master to clear me to enable cache and return  */	while (wait_barrier_cache_enable)		barrier ();	set_mtrr_done (&ctxt);}static void set_mtrr_smp (unsigned int reg, u64 base, u32 size, mtrr_type type){	struct set_mtrr_data data;	struct set_mtrr_context ctxt;	data.smp_reg = reg;	data.smp_base = base;	data.smp_size = size;	data.smp_type = type;	wait_barrier_execute = TRUE;	wait_barrier_cache_enable = TRUE;	atomic_set (&undone_count, smp_num_cpus - 1);	/*  Start the ball rolling on other CPUs  */	if (smp_call_function (ipi_handler, &data, 1, 0) != 0)		panic ("mtrr: timed out waiting for other CPUs\n");	/* Flush and disable the local CPU's cache */	set_mtrr_prepare (&ctxt);	/*  Wait for all other CPUs to flush and disable their caches  */	while (atomic_read (&undone_count) > 0)		barrier ();	/* Set up for completion wait and then release other CPUs to change MTRRs */	atomic_set (&undone_count, smp_num_cpus - 1);	wait_barrier_execute = FALSE;	set_mtrr_up (reg, base, size, type, FALSE);	/*  Now wait for other CPUs to complete the function  */	while (atomic_read (&undone_count) > 0)		barrier ();	/*  Now all CPUs should have finished the function. Release the barrier to	   allow them to re-enable their caches and return from their interrupt,	   then enable the local cache and return  */	wait_barrier_cache_enable = FALSE;	set_mtrr_done (&ctxt);}/*  Some BIOS's are fucked and don't set all MTRRs the same!  */static void __init mtrr_state_warn (u32 mask){	if (!mask)		return;	if (mask & MTRR_CHANGE_MASK_FIXED)		printk (KERN_INFO "mtrr: your CPUs had inconsistent fixed MTRR settings\n");	if (mask & MTRR_CHANGE_MASK_VARIABLE)		printk (KERN_INFO "mtrr: your CPUs had inconsistent variable MTRR settings\n");	if (mask & MTRR_CHANGE_MASK_DEFTYPE)		printk (KERN_INFO "mtrr: your CPUs had inconsistent MTRRdefType settings\n");	printk (KERN_INFO "mtrr: probably your BIOS does not setup all CPUs\n");}#endif	/*  CONFIG_SMP  */static inline char * attrib_to_str (int x){	return (x <= 6) ? mtrr_strings[x] : "?";}static void __init init_table (void){	int i, max;	max = get_num_var_ranges ();	if ((usage_table = kmalloc (max * sizeof *usage_table, GFP_KERNEL))==NULL) {		printk ("mtrr: could not allocate\n");		return;	}	for (i = 0; i < max; i++)		usage_table[i] = 1;#ifdef USERSPACE_INTERFACE	if ((ascii_buffer = kmalloc (max * LINE_SIZE, GFP_KERNEL)) == NULL) {		printk ("mtrr: could not allocate\n");		return;	}	ascii_buf_bytes = 0;	compute_ascii ();#endif}/* * Get a free MTRR. * returns the index of the region on success, else -1 on error.*/static int get_free_region(void){	int i, max;	mtrr_type ltype;	u64 lbase;	u32 lsize;	max = get_num_var_ranges ();	for (i = 0; i < max; ++i) {		get_mtrr (i, &lbase, &lsize, &ltype);		if (lsize == 0)			return i;	}	return -ENOSPC;}/** *	mtrr_add_page - Add a memory type region *	@base: Physical base address of region in pages (4 KB) *	@size: Physical size of region in pages (4 KB) *	@type: Type of MTRR desired *	@increment: If this is true do usage counting on the region *	Returns The MTRR register on success, else a negative number *	indicating the error code. * *	Memory type region registers control the caching on newer *	processors. This function allows drivers to request an MTRR is added. *	The caller should expect to need to provide a power of two size on *	an equivalent power of two boundary. * *	If the region cannot be added either because all regions are in use *	or the CPU cannot support it a negative value is returned. On success *	the register number for this entry is returned, but should be treated *	as a cookie only. * *	On a multiprocessor machine the changes are made to all processors. * *	The available types are * *	%MTRR_TYPE_UNCACHABLE	-	No caching *	%MTRR_TYPE_WRBACK	-	Write data back in bursts whenever *	%MTRR_TYPE_WRCOMB	-	Write data back soon but allow bursts *	%MTRR_TYPE_WRTHROUGH	-	Cache reads but not writes * *	BUGS: Needs a quiet flag for the cases where drivers do not mind *	failures and do not wish system log messages to be sent. */int mtrr_add_page (u64 base, u32 size, unsigned int type, char increment){	int i, max;	mtrr_type ltype;	u64 lbase, last;	u32 lsize;	if (base + size < 0x100) {		printk (KERN_WARNING			"mtrr: cannot set region below 1 MiB (0x%Lx000,0x%x000)\n",			base, size);		return -EINVAL;	}#if 0 && defined(__x86_64__) && defined(CONFIG_AGP) 	{	agp_kern_info info; 	if (type != MTRR_TYPE_UNCACHABLE && agp_copy_info(&info) >= 0 && 	    base<<PAGE_SHIFT >= info.aper_base &&             (base<<PAGE_SHIFT)+(size<<PAGE_SHIFT) >= 			info.aper_base+info.aper_size*1024*1024)		printk(KERN_INFO "%s[%d] setting conflicting mtrr into agp aperture\n",current->comm,current->pid); 	}#endif	/*  Check upper bits of base and last are equal and lower bits are 0	   for base and 1 for last  */	last = base + size - 1;	for (lbase = base; !(lbase & 1) && (last & 1);	     lbase = lbase >> 1, last = last >> 1) ;	if (lbase != last) {		printk (KERN_WARNING			"mtrr: base(0x%Lx000) is not aligned on a size(0x%x000) boundary\n",			base, size);		return -EINVAL;	}	if (type >= MTRR_NUM_TYPES) {		printk ("mtrr: type: %u illegal\n", type);		return -EINVAL;	}	/*  If the type is WC, check that this processor supports it  */	if ((type == MTRR_TYPE_WRCOMB) && !have_wrcomb()) {		printk (KERN_WARNING			"mtrr: your processor doesn't support write-combining\n");		return -ENOSYS;	}	if (base & (size_or_mask>>PAGE_SHIFT)) {		printk (KERN_WARNING "mtrr: base(%Lx) exceeds the MTRR width(%Lx)\n",				base, (size_or_mask>>PAGE_SHIFT));		return -EINVAL;	}	if (size & (size_or_mask>>PAGE_SHIFT)) {		printk (KERN_WARNING "mtrr: size exceeds the MTRR width\n");		return -EINVAL;	}	increment = increment ? 1 : 0;	max = get_num_var_ranges ();	/*  Search for existing MTRR  */	down (&mtrr_lock);	for (i = 0; i < max; ++i) {		get_mtrr (i, &lbase, &lsize, &ltype);		if (base >= lbase + lsize)			continue;		if ((base < lbase) && (base + size <= lbase))			continue;		/*  At this point we know there is some kind of overlap/enclosure  */		if ((base < lbase) || (base + size > lbase + lsize)) {			up (&mtrr_lock);			printk (KERN_WARNING				"mtrr: 0x%Lx000,0x%x000 overlaps existing"				" 0x%Lx000,0x%x000\n", base, size, lbase, lsize);			return -EINVAL;		}		/*  New region is enclosed by an existing region  */		if (ltype != type) {			if (type == MTRR_TYPE_UNCACHABLE)				continue;			up (&mtrr_lock);			printk			    ("mtrr: type mismatch for %Lx000,%x000 old: %s new: %s\n",			     base, size,				 attrib_to_str (ltype),			     attrib_to_str (type));			return -EINVAL;		}		if (increment)			++usage_table[i];		compute_ascii ();		up (&mtrr_lock);		return i;	}	/*  Search for an empty MTRR  */	i = get_free_region();	if (i < 0) {		up (&mtrr_lock);		printk ("mtrr: no more MTRRs available\n");		return i;	}	set_mtrr (i, base, size, type);	usage_table[i] = 1;	compute_ascii ();	up (&mtrr_lock);	return i;}/** *	mtrr_add - Add a memory type region *	@base: Physical base address of region *	@size: Physical size of region *	@type: Type of MTRR desired *	@increment: If this is true do usage counting on the region *	Return the MTRR register on success, else a negative numbe *	indicating the error code. * *	Memory type region registers control the caching on newer processors. *	This function allows drivers to request an MTRR is added. *	The caller should expect to need to provide a power of two size on *	an equivalent power of two boundary. * *	If the region cannot be added either because all regions are in use *	or the CPU cannot support it a negative value is returned. On success *	the register number for this entry is returned, but should be treated *	as a cookie only. * *	On a multiprocessor machine the changes are made to all processors. *	This is required on x86 by the Intel processors. * *	The available types are * *	%MTRR_TYPE_UNCACHABLE	-	No caching *	%MTRR_TYPE_WRBACK	-	Write data back in bursts whenever *	%MTRR_TYPE_WRCOMB	-	Write data back soon but allow bursts *	%MTRR_TYPE_WRTHROUGH	-	Cache reads but not writes * *	BUGS: Needs a quiet flag for the cases where drivers do not mind *	failures and do not wish system log messages to be sent. */int mtrr_add (u64 base, u32 size, unsigned int type, char increment){	if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) {		printk ("mtrr: size and base must be multiples of 4 kiB\n");		printk ("mtrr: size: 0x%x  base: 0x%Lx\n", size, base);		return -EINVAL;	}	return mtrr_add_page (base >> PAGE_SHIFT, size >> PAGE_SHIFT, type,			      increment);}/** *	mtrr_del_page - delete a memory type region *	@reg: Register returned by mtrr_add *	@base: Physical base address *	@size: Size of region * *	If register is supplied then base and size are ignored. This is *	how drivers should call it. * *	Releases an MTRR region. If the usage count drops to zero the  *	register is freed and the region returns to default state. *	On success the register is returned, on failure a negative error *	code. */int mtrr_del_page (int reg, u64 base, u32 size){	int i, max;	mtrr_type ltype;	u64 lbase;	u32 lsize;	max = get_num_var_ranges ();	down (&mtrr_lock);	if (reg < 0) {		/*  Search for existing MTRR  */		for (i = 0; i < max; ++i) {			get_mtrr (i, &lbase, &lsize, &ltype);			if (lbase == base && lsize == size) {				reg = i;				break;			}		}		if (reg < 0) {			up (&mtrr_lock);			printk ("mtrr: no MTRR for %Lx000,%x000 found\n", base, size);			return -EINVAL;		}	}	if (reg >= max) {		up (&mtrr_lock);		printk ("mtrr: register: %d too big\n", reg);		return -EINVAL;	}	get_mtrr (reg, &lbase, &lsize, &ltype);	if (lsize < 1) {		up (&mtrr_lock);		printk ("mtrr: MTRR %d not used\n", reg);		return -EINVAL;	}	if (usage_table[reg] < 1) {		up (&mtrr_lock);		printk ("mtrr: reg: %d has count=0\n", reg);		return -EINVAL;	}	if (--usage_table[reg] < 1)		set_mtrr (reg, 0, 0, 0);	compute_ascii ();	up (&mtrr_lock);	return reg;}/** *	mtrr_del - delete a memory type region *	@reg: Register returned by mtrr_add *	@base: Physical base address *	@size: Size of region * *	If register is supplied then base and size are ignored. This is *	how drivers should call it. * *	Releases an MTRR region. If the usage count drops to zero the  *	register is freed and the region returns to default state. *	On success the register is returned, on failure a negative error *	code. */int mtrr_del (int reg, u64 base, u32 size){	if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) {		printk ("mtrr: size and base must be multiples of 4 kiB\n");		printk ("mtrr: size: 0x%x  base: 0x%Lx\n", size, base);		return -EINVAL;	}	return mtrr_del_page (reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT);}#ifdef USERSPACE_INTERFACEstatic int mtrr_file_add (u64 base, u32 size, unsigned int type,		struct file *file, int page){	int reg, max;	unsigned int *fcount = file->private_data;	max = get_num_var_ranges ();	if (fcount == NULL) {		if ((fcount =		     kmalloc (max * sizeof *fcount, GFP_KERNEL)) == NULL) {			printk ("mtrr: could not allocate\n");			return -ENOMEM;		}		memset (fcount, 0, max * sizeof *fcount);		file->private_data = fcount;	}	if (!page) {		if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) {			printk			    (KERN_INFO "mtrr: size and base must be multiples of 4 kiB\n");			printk (KERN_INFO "mtrr: size: 0x%x  base: 0x%Lx\n", size, base);			return -EINVAL;		}

⌨️ 快捷键说明

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