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

📄 mtrr.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	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(&main_lock);	    printk (KERN_WARNING "mtrr: 0x%lx000,0x%lx000 overlaps existing"		    " 0x%lx000,0x%lx000\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(&main_lock);	    printk ( "mtrr: type mismatch for %lx000,%lx000 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(&main_lock);	return i;    }    /*  Search for an empty MTRR  */    i = (*get_free_region) (base, size);    if (i < 0)    {	up(&main_lock);	printk ("mtrr: no more MTRRs available\n");	return i;    }    set_mtrr (i, base, size, type);    usage_table[i] = 1;    compute_ascii ();    up(&main_lock);    return i;}   /*  End Function mtrr_add_page  *//** *	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 * *	Memory type region registers control the caching on newer Intel and *	non Intel processors. This function allows drivers to request an *	MTRR is added. The details and hardware specifics of each processor's *	implementation are hidden from the caller, but nevertheless 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_UNCACHEABLE	-	No caching * *	%MTRR_TYPE_WRITEBACK	-	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(unsigned long base, unsigned long size, unsigned int type, char increment){/*  [SUMMARY] Add an MTRR entry.    <base> The starting (base) address of the region.    <size> The size (in bytes) of the region.    <type> The type of the new region.    <increment> If true and the region already exists, the usage count will be    incremented.    [RETURNS] The MTRR register on success, else a negative number indicating    the error code.*/    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%lx  base: 0x%lx\n", size, base);	return -EINVAL;    }    return mtrr_add_page(base >> PAGE_SHIFT, size >> PAGE_SHIFT, type, increment);}   /*  End Function mtrr_add  *//** *	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, unsigned long base, unsigned long size)/*  [SUMMARY] Delete MTRR/decrement usage count.    <reg> The register. If this is less than 0 then <<base>> and <<size>> must    be supplied.    <base> The base address of the region. This is ignored if <<reg>> is >= 0.    <size> The size of the region. This is ignored if <<reg>> is >= 0.    [RETURNS] The register on success, else a negative number indicating    the error code.    [NOTE] This routine uses a spinlock.*/{    int i, max;    mtrr_type ltype;    unsigned long lbase, lsize;    if ( mtrr_if == MTRR_IF_NONE ) return -ENXIO;    max = get_num_var_ranges ();    down (&main_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(&main_lock);	    printk ("mtrr: no MTRR for %lx000,%lx000 found\n", base, size);	    return -EINVAL;	}    }    if (reg >= max)    {	up (&main_lock);	printk ("mtrr: register: %d too big\n", reg);	return -EINVAL;    }    if ( mtrr_if == MTRR_IF_CYRIX_ARR )    {	if ( (reg == 3) && arr3_protected )	{	    up (&main_lock);	    printk ("mtrr: ARR3 cannot be changed\n");	    return -EINVAL;	}    }    (*get_mtrr) (reg, &lbase, &lsize, &ltype);    if (lsize < 1)    {	up (&main_lock);	printk ("mtrr: MTRR %d not used\n", reg);	return -EINVAL;    }    if (usage_table[reg] < 1)    {	up (&main_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 (&main_lock);    return reg;}   /*  End Function mtrr_del_page  *//** *	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, unsigned long base, unsigned long size)/*  [SUMMARY] Delete MTRR/decrement usage count.    <reg> The register. If this is less than 0 then <<base>> and <<size>> must    be supplied.    <base> The base address of the region. This is ignored if <<reg>> is >= 0.    <size> The size of the region. This is ignored if <<reg>> is >= 0.    [RETURNS] The register on success, else a negative number indicating    the error code.*/{    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%lx  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 (unsigned long base, unsigned long size,			  unsigned int type, char increment, 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 ("mtrr: size and base must be multiples of 4 kiB\n");	    printk ("mtrr: size: 0x%lx  base: 0x%lx\n", size, base);	    return -EINVAL;	}	base >>= PAGE_SHIFT;	size >>= PAGE_SHIFT;    }    reg = mtrr_add_page (base, size, type, 1);    if (reg >= 0) ++fcount[reg];    return reg;}   /*  End Function mtrr_file_add  */static int mtrr_file_del (unsigned long base, unsigned long size,			  struct file *file, int page){    int reg;    unsigned int *fcount = file->private_data;    if (!page) {	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%lx  base: 0x%lx\n", size, base);	    return -EINVAL;	}	base >>= PAGE_SHIFT;	size >>= PAGE_SHIFT;    }    reg = mtrr_del_page (-1, base, size);    if (reg < 0) return reg;    if (fcount == NULL) return reg;    if (fcount[reg] < 1) return -EINVAL;    --fcount[reg];    return reg;}   /*  End Function mtrr_file_del  */static ssize_t mtrr_read (struct file *file, char *buf, size_t len,			  loff_t *ppos){    if (*ppos >= ascii_buf_bytes) return 0;    if (*ppos + len > ascii_buf_bytes) len = ascii_buf_bytes - *ppos;    if ( copy_to_user (buf, ascii_buffer + *ppos, len) ) return -EFAULT;    *ppos += len;    return len;}   /*  End Function mtrr_read  */static ssize_t mtrr_write (struct file *file, const char *buf, size_t len,			   loff_t *ppos)/*  Format of control line:    "base=%Lx size=%Lx type=%s"     OR:    "disable=%d"*/{    int i, err;    unsigned long reg;    unsigned long long base, size;    char *ptr;    char line[LINE_SIZE];    if ( !suser () ) return -EPERM;    /*  Can't seek (pwrite) on this device  */    if (ppos != &file->f_pos) return -ESPIPE;    memset (line, 0, LINE_SIZE);    if (len > LINE_SIZE) len = LINE_SIZE;    if ( copy_from_user (line, buf, len - 1) ) return -EFAULT;    ptr = line + strlen (line) - 1;    if (*ptr == '\n') *ptr = '\0';    if ( !strncmp (line, "disable=", 8) )    {	reg = simple_strtoul (line + 8, &ptr, 0);	err = mtrr_del_page (reg, 0, 0);	if (err < 0) return err;	return len;    }    if ( strncmp (line, "base=", 5) )    {	printk ("mtrr: no \"base=\" in line: \"%s\"\n", line);	return -EINVAL;    }    base = simple_strtoull (line + 5, &ptr, 0);    for (; isspace (*ptr); ++ptr);    if ( strncmp (ptr, "size=", 5) )    {	printk ("mtrr: no \"size=\" in line: \"%s\"\n", line);	return -EINVAL;    }    size = simple_strtoull (ptr + 5, &ptr, 0);    if ( (base & 0xfff) || (size & 0xfff) )    {	printk ("mtrr: size and base must be multiples of 4 kiB\n");	printk ("mtrr: size: 0x%Lx  base: 0x%Lx\n", size, base);	return -EINVAL;    }    for (; isspace (*ptr); ++ptr);    if ( strncmp (ptr, "type=", 5) )    {	printk ("mtrr: no \"type=\" in line: \"%s\"\n", line);	return -EINVAL;    }    ptr += 5;    for (; isspace (*ptr); ++ptr);    for (i = 0; i < MTRR_NUM_TYPES; ++i)    {	if ( strcmp (ptr, mtrr_strings[i]) ) continue;	base >>= PAGE_SHIFT;	size >>= PAGE_SHIFT;	err = mtrr_add_page ((unsigned long)base, (unsigned long)size, i, 1);	if (err < 0) return err;	return len;    }    printk ("mtrr: illegal type: \"%s\"\n", ptr);    return -EINVAL;}   /*  End Function mtrr_write  */static int mtrr_ioctl (struct inode *inode, struct file *file,		       unsigned int cmd, unsigned long arg){    int err;    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;

⌨️ 快捷键说明

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