diff options
Diffstat (limited to 'drivers/char/mem.c')
| -rw-r--r-- | drivers/char/mem.c | 197 | 
1 files changed, 102 insertions, 95 deletions
diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 48788db4e28..f54dab8acdc 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -3,7 +3,7 @@   *   *  Copyright (C) 1991, 1992  Linus Torvalds   * - *  Added devfs support.  + *  Added devfs support.   *    Jan-11-1998, C. Scott Ananian <cananian@alumni.princeton.edu>   *  Shared /dev/zero mmapping support, Feb 2000, Kanoj Sarcar <kanoj@sgi.com>   */ @@ -44,36 +44,6 @@ static inline unsigned long size_inside_page(unsigned long start,  	return min(sz, size);  } -/* - * Architectures vary in how they handle caching for addresses - * outside of main memory. - * - */ -static inline int uncached_access(struct file *file, unsigned long addr) -{ -#if defined(CONFIG_IA64) -	/* -	 * On ia64, we ignore O_DSYNC because we cannot tolerate memory attribute aliases. -	 */ -	return !(efi_mem_attributes(addr) & EFI_MEMORY_WB); -#elif defined(CONFIG_MIPS) -	{ -		extern int __uncached_access(struct file *file, -					     unsigned long addr); - -		return __uncached_access(file, addr); -	} -#else -	/* -	 * Accessing memory above the top the kernel knows about or through a file pointer -	 * that was marked O_DSYNC will be done non-cached. -	 */ -	if (file->f_flags & O_DSYNC) -		return 1; -	return addr >= __pa(high_memory); -#endif -} -  #ifndef ARCH_HAS_VALID_PHYS_ADDR_RANGE  static inline int valid_phys_addr_range(unsigned long addr, size_t count)  { @@ -115,15 +85,15 @@ static inline int range_is_allowed(unsigned long pfn, unsigned long size)  }  #endif -void __attribute__((weak)) unxlate_dev_mem_ptr(unsigned long phys, void *addr) +void __weak unxlate_dev_mem_ptr(unsigned long phys, void *addr)  {  }  /* - * This funcion reads the *physical* memory. The f_pos points directly to the  - * memory location.  + * This funcion reads the *physical* memory. The f_pos points directly to the + * memory location.   */ -static ssize_t read_mem(struct file * file, char __user * buf, +static ssize_t read_mem(struct file *file, char __user *buf,  			size_t count, loff_t *ppos)  {  	unsigned long p = *ppos; @@ -140,10 +110,10 @@ static ssize_t read_mem(struct file * file, char __user * buf,  		if (sz > 0) {  			if (clear_user(buf, sz))  				return -EFAULT; -			buf += sz;  -			p += sz;  -			count -= sz;  -			read += sz;  +			buf += sz; +			p += sz; +			count -= sz; +			read += sz;  		}  	}  #endif @@ -157,9 +127,9 @@ static ssize_t read_mem(struct file * file, char __user * buf,  			return -EPERM;  		/* -		 * On ia64 if a page has been mapped somewhere as -		 * uncached, then it must also be accessed uncached -		 * by the kernel or data corruption may occur +		 * On ia64 if a page has been mapped somewhere as uncached, then +		 * it must also be accessed uncached by the kernel or data +		 * corruption may occur.  		 */  		ptr = xlate_dev_mem_ptr(p);  		if (!ptr) @@ -180,7 +150,7 @@ static ssize_t read_mem(struct file * file, char __user * buf,  	return read;  } -static ssize_t write_mem(struct file * file, const char __user * buf,  +static ssize_t write_mem(struct file *file, const char __user *buf,  			 size_t count, loff_t *ppos)  {  	unsigned long p = *ppos; @@ -212,9 +182,9 @@ static ssize_t write_mem(struct file * file, const char __user * buf,  			return -EPERM;  		/* -		 * On ia64 if a page has been mapped somewhere as -		 * uncached, then it must also be accessed uncached -		 * by the kernel or data corruption may occur +		 * On ia64 if a page has been mapped somewhere as uncached, then +		 * it must also be accessed uncached by the kernel or data +		 * corruption may occur.  		 */  		ptr = xlate_dev_mem_ptr(p);  		if (!ptr) { @@ -242,13 +212,48 @@ static ssize_t write_mem(struct file * file, const char __user * buf,  	return written;  } -int __attribute__((weak)) phys_mem_access_prot_allowed(struct file *file, +int __weak phys_mem_access_prot_allowed(struct file *file,  	unsigned long pfn, unsigned long size, pgprot_t *vma_prot)  {  	return 1;  }  #ifndef __HAVE_PHYS_MEM_ACCESS_PROT + +/* + * Architectures vary in how they handle caching for addresses + * outside of main memory. + * + */ +#ifdef pgprot_noncached +static int uncached_access(struct file *file, unsigned long addr) +{ +#if defined(CONFIG_IA64) +	/* +	 * On ia64, we ignore O_DSYNC because we cannot tolerate memory +	 * attribute aliases. +	 */ +	return !(efi_mem_attributes(addr) & EFI_MEMORY_WB); +#elif defined(CONFIG_MIPS) +	{ +		extern int __uncached_access(struct file *file, +					     unsigned long addr); + +		return __uncached_access(file, addr); +	} +#else +	/* +	 * Accessing memory above the top the kernel knows about or through a +	 * file pointer +	 * that was marked O_DSYNC will be done non-cached. +	 */ +	if (file->f_flags & O_DSYNC) +		return 1; +	return addr >= __pa(high_memory); +#endif +} +#endif +  static pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,  				     unsigned long size, pgprot_t vma_prot)  { @@ -294,7 +299,7 @@ static const struct vm_operations_struct mmap_mem_ops = {  #endif  }; -static int mmap_mem(struct file * file, struct vm_area_struct * vma) +static int mmap_mem(struct file *file, struct vm_area_struct *vma)  {  	size_t size = vma->vm_end - vma->vm_start; @@ -329,7 +334,7 @@ static int mmap_mem(struct file * file, struct vm_area_struct * vma)  }  #ifdef CONFIG_DEVKMEM -static int mmap_kmem(struct file * file, struct vm_area_struct * vma) +static int mmap_kmem(struct file *file, struct vm_area_struct *vma)  {  	unsigned long pfn; @@ -337,9 +342,9 @@ static int mmap_kmem(struct file * file, struct vm_area_struct * vma)  	pfn = __pa((u64)vma->vm_pgoff << PAGE_SHIFT) >> PAGE_SHIFT;  	/* -	 * RED-PEN: on some architectures there is more mapped memory -	 * than available in mem_map which pfn_valid checks -	 * for. Perhaps should add a new macro here. +	 * RED-PEN: on some architectures there is more mapped memory than +	 * available in mem_map which pfn_valid checks for. Perhaps should add a +	 * new macro here.  	 *  	 * RED-PEN: vmalloc is not supported right now.  	 */ @@ -389,7 +394,7 @@ static ssize_t read_oldmem(struct file *file, char __user *buf,  /*   * This function reads the *virtual* memory as seen by the kernel.   */ -static ssize_t read_kmem(struct file *file, char __user *buf,  +static ssize_t read_kmem(struct file *file, char __user *buf,  			 size_t count, loff_t *ppos)  {  	unsigned long p = *ppos; @@ -400,8 +405,8 @@ static ssize_t read_kmem(struct file *file, char __user *buf,  	read = 0;  	if (p < (unsigned long) high_memory) {  		low_count = count; -		if (count > (unsigned long) high_memory - p) -			low_count = (unsigned long) high_memory - p; +		if (count > (unsigned long)high_memory - p) +			low_count = (unsigned long)high_memory - p;  #ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED  		/* we don't have page 0 mapped on sparc and m68k.. */ @@ -465,9 +470,8 @@ static ssize_t read_kmem(struct file *file, char __user *buf,  } -static inline ssize_t -do_write_kmem(unsigned long p, const char __user *buf, -	      size_t count, loff_t *ppos) +static ssize_t do_write_kmem(unsigned long p, const char __user *buf, +				size_t count, loff_t *ppos)  {  	ssize_t written, sz;  	unsigned long copied; @@ -491,9 +495,9 @@ do_write_kmem(unsigned long p, const char __user *buf,  		sz = size_inside_page(p, count);  		/* -		 * On ia64 if a page has been mapped somewhere as -		 * uncached, then it must also be accessed uncached -		 * by the kernel or data corruption may occur +		 * On ia64 if a page has been mapped somewhere as uncached, then +		 * it must also be accessed uncached by the kernel or data +		 * corruption may occur.  		 */  		ptr = xlate_dev_kmem_ptr((char *)p); @@ -514,11 +518,10 @@ do_write_kmem(unsigned long p, const char __user *buf,  	return written;  } -  /*   * This function writes to the *virtual* memory as seen by the kernel.   */ -static ssize_t write_kmem(struct file * file, const char __user * buf,  +static ssize_t write_kmem(struct file *file, const char __user *buf,  			  size_t count, loff_t *ppos)  {  	unsigned long p = *ppos; @@ -570,17 +573,17 @@ static ssize_t write_kmem(struct file * file, const char __user * buf,  #endif  #ifdef CONFIG_DEVPORT -static ssize_t read_port(struct file * file, char __user * buf, +static ssize_t read_port(struct file *file, char __user *buf,  			 size_t count, loff_t *ppos)  {  	unsigned long i = *ppos;  	char __user *tmp = buf;  	if (!access_ok(VERIFY_WRITE, buf, count)) -		return -EFAULT;  +		return -EFAULT;  	while (count-- > 0 && i < 65536) { -		if (__put_user(inb(i),tmp) < 0)  -			return -EFAULT;   +		if (__put_user(inb(i), tmp) < 0) +			return -EFAULT;  		i++;  		tmp++;  	} @@ -588,22 +591,22 @@ static ssize_t read_port(struct file * file, char __user * buf,  	return tmp-buf;  } -static ssize_t write_port(struct file * file, const char __user * buf, +static ssize_t write_port(struct file *file, const char __user *buf,  			  size_t count, loff_t *ppos)  {  	unsigned long i = *ppos;  	const char __user * tmp = buf; -	if (!access_ok(VERIFY_READ,buf,count)) +	if (!access_ok(VERIFY_READ, buf, count))  		return -EFAULT;  	while (count-- > 0 && i < 65536) {  		char c;  		if (__get_user(c, tmp)) {  			if (tmp > buf)  				break; -			return -EFAULT;  +			return -EFAULT;  		} -		outb(c,i); +		outb(c, i);  		i++;  		tmp++;  	} @@ -612,13 +615,13 @@ static ssize_t write_port(struct file * file, const char __user * buf,  }  #endif -static ssize_t read_null(struct file * file, char __user * buf, +static ssize_t read_null(struct file *file, char __user *buf,  			 size_t count, loff_t *ppos)  {  	return 0;  } -static ssize_t write_null(struct file * file, const char __user * buf, +static ssize_t write_null(struct file *file, const char __user *buf,  			  size_t count, loff_t *ppos)  {  	return count; @@ -630,13 +633,13 @@ static int pipe_to_null(struct pipe_inode_info *info, struct pipe_buffer *buf,  	return sd->len;  } -static ssize_t splice_write_null(struct pipe_inode_info *pipe,struct file *out, +static ssize_t splice_write_null(struct pipe_inode_info *pipe, struct file *out,  				 loff_t *ppos, size_t len, unsigned int flags)  {  	return splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_null);  } -static ssize_t read_zero(struct file * file, char __user * buf,  +static ssize_t read_zero(struct file *file, char __user *buf,  			 size_t count, loff_t *ppos)  {  	size_t written; @@ -667,7 +670,7 @@ static ssize_t read_zero(struct file * file, char __user * buf,  	return written ? written : -EFAULT;  } -static int mmap_zero(struct file * file, struct vm_area_struct * vma) +static int mmap_zero(struct file *file, struct vm_area_struct *vma)  {  #ifndef CONFIG_MMU  	return -ENOSYS; @@ -677,7 +680,7 @@ static int mmap_zero(struct file * file, struct vm_area_struct * vma)  	return 0;  } -static ssize_t write_full(struct file * file, const char __user * buf, +static ssize_t write_full(struct file *file, const char __user *buf,  			  size_t count, loff_t *ppos)  {  	return -ENOSPC; @@ -688,8 +691,7 @@ static ssize_t write_full(struct file * file, const char __user * buf,   * can fopen() both devices with "a" now.  This was previously impossible.   * -- SRB.   */ - -static loff_t null_lseek(struct file * file, loff_t offset, int orig) +static loff_t null_lseek(struct file *file, loff_t offset, int orig)  {  	return file->f_pos = 0;  } @@ -702,24 +704,26 @@ static loff_t null_lseek(struct file * file, loff_t offset, int orig)   * also note that seeking relative to the "end of file" isn't supported:   * it has no meaning, so it returns -EINVAL.   */ -static loff_t memory_lseek(struct file * file, loff_t offset, int orig) +static loff_t memory_lseek(struct file *file, loff_t offset, int orig)  {  	loff_t ret;  	mutex_lock(&file->f_path.dentry->d_inode->i_mutex);  	switch (orig) { -		case 0: -			file->f_pos = offset; -			ret = file->f_pos; -			force_successful_syscall_return(); -			break; -		case 1: -			file->f_pos += offset; -			ret = file->f_pos; -			force_successful_syscall_return(); +	case SEEK_CUR: +		offset += file->f_pos; +	case SEEK_SET: +		/* to avoid userland mistaking f_pos=-9 as -EBADF=-9 */ +		if ((unsigned long long)offset >= ~0xFFFULL) { +			ret = -EOVERFLOW;  			break; -		default: -			ret = -EINVAL; +		} +		file->f_pos = offset; +		ret = file->f_pos; +		force_successful_syscall_return(); +		break; +	default: +		ret = -EINVAL;  	}  	mutex_unlock(&file->f_path.dentry->d_inode->i_mutex);  	return ret; @@ -803,7 +807,7 @@ static const struct file_operations oldmem_fops = {  };  #endif -static ssize_t kmsg_write(struct file * file, const char __user * buf, +static ssize_t kmsg_write(struct file *file, const char __user *buf,  			  size_t count, loff_t *ppos)  {  	char *tmp; @@ -825,7 +829,7 @@ static ssize_t kmsg_write(struct file * file, const char __user * buf,  }  static const struct file_operations kmsg_fops = { -	.write =	kmsg_write, +	.write = kmsg_write,  };  static const struct memdev { @@ -876,7 +880,7 @@ static int memory_open(struct inode *inode, struct file *filp)  }  static const struct file_operations memory_fops = { -	.open		= memory_open, +	.open = memory_open,  };  static char *mem_devnode(struct device *dev, mode_t *mode) @@ -897,10 +901,13 @@ static int __init chr_dev_init(void)  	if (err)  		return err; -	if (register_chrdev(MEM_MAJOR,"mem",&memory_fops)) +	if (register_chrdev(MEM_MAJOR, "mem", &memory_fops))  		printk("unable to get major %d for memory devs\n", MEM_MAJOR);  	mem_class = class_create(THIS_MODULE, "mem"); +	if (IS_ERR(mem_class)) +		return PTR_ERR(mem_class); +  	mem_class->devnode = mem_devnode;  	for (minor = 1; minor < ARRAY_SIZE(devlist); minor++) {  		if (!devlist[minor].name)  |