This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / drivers / xen / char / mem.c
1 /*
2  *  Originally from linux/drivers/char/mem.c
3  *
4  *  Copyright (C) 1991, 1992  Linus Torvalds
5  *
6  *  Added devfs support. 
7  *    Jan-11-1998, C. Scott Ananian <cananian@alumni.princeton.edu>
8  *  Shared /dev/zero mmaping support, Feb 2000, Kanoj Sarcar <kanoj@sgi.com>
9  */
10
11 #include <linux/config.h>
12 #include <linux/mm.h>
13 #include <linux/miscdevice.h>
14 #include <linux/slab.h>
15 #include <linux/vmalloc.h>
16 #include <linux/mman.h>
17 #include <linux/random.h>
18 #include <linux/init.h>
19 #include <linux/raw.h>
20 #include <linux/tty.h>
21 #include <linux/capability.h>
22 #include <linux/smp_lock.h>
23 #include <linux/devfs_fs_kernel.h>
24 #include <linux/ptrace.h>
25 #include <linux/device.h>
26 #include <asm/pgalloc.h>
27 #include <asm/uaccess.h>
28 #include <asm/io.h>
29 #include <asm/hypervisor.h>
30
31 static inline int uncached_access(struct file *file)
32 {
33         if (file->f_flags & O_SYNC)
34                 return 1;
35         /* Xen sets correct MTRR type on non-RAM for us. */
36         return 0;
37 }
38
39 /*
40  * This funcion reads the *physical* memory. The f_pos points directly to the 
41  * memory location. 
42  */
43 static ssize_t read_mem(struct file * file, char __user * buf,
44                         size_t count, loff_t *ppos)
45 {
46         unsigned long p = *ppos, ignored;
47         ssize_t read = 0, sz;
48         void __iomem *v;
49
50         while (count > 0) {
51                 /*
52                  * Handle first page in case it's not aligned
53                  */
54                 if (-p & (PAGE_SIZE - 1))
55                         sz = -p & (PAGE_SIZE - 1);
56                 else
57                         sz = PAGE_SIZE;
58
59                 sz = min_t(unsigned long, sz, count);
60
61                 if ((v = ioremap(p, sz)) == NULL) {
62                         /*
63                          * Some programs (e.g., dmidecode) groove off into weird RAM
64                          * areas where no tables can possibly exist (because Xen will
65                          * have stomped on them!). These programs get rather upset if
66                          * we let them know that Xen failed their access, so we fake
67                          * out a read of all zeroes. :-)
68                          */
69                         if (clear_user(buf, count))
70                                 return -EFAULT;
71                         read += count;
72                         break;
73                 }
74
75                 ignored = copy_to_user(buf, v, sz);
76                 iounmap(v);
77                 if (ignored)
78                         return -EFAULT;
79                 buf += sz;
80                 p += sz;
81                 count -= sz;
82                 read += sz;
83         }
84
85         *ppos += read;
86         return read;
87 }
88
89 static ssize_t write_mem(struct file * file, const char __user * buf, 
90                          size_t count, loff_t *ppos)
91 {
92         unsigned long p = *ppos, ignored;
93         ssize_t written = 0, sz;
94         void __iomem *v;
95
96         while (count > 0) {
97                 /*
98                  * Handle first page in case it's not aligned
99                  */
100                 if (-p & (PAGE_SIZE - 1))
101                         sz = -p & (PAGE_SIZE - 1);
102                 else
103                         sz = PAGE_SIZE;
104
105                 sz = min_t(unsigned long, sz, count);
106
107                 if ((v = ioremap(p, sz)) == NULL)
108                         break;
109
110                 ignored = copy_from_user(v, buf, sz);
111                 iounmap(v);
112                 if (ignored) {
113                         written += sz - ignored;
114                         if (written)
115                                 break;
116                         return -EFAULT;
117                 }
118                 buf += sz;
119                 p += sz;
120                 count -= sz;
121                 written += sz;
122         }
123
124         *ppos += written;
125         return written;
126 }
127
128 static int mmap_mem(struct file * file, struct vm_area_struct * vma)
129 {
130         size_t size = vma->vm_end - vma->vm_start;
131
132         if (uncached_access(file))
133                 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
134
135         /* We want to return the real error code, not EAGAIN. */
136         return direct_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
137                                       size, vma->vm_page_prot, DOMID_IO);
138 }
139
140 /*
141  * The memory devices use the full 32/64 bits of the offset, and so we cannot
142  * check against negative addresses: they are ok. The return value is weird,
143  * though, in that case (0).
144  *
145  * also note that seeking relative to the "end of file" isn't supported:
146  * it has no meaning, so it returns -EINVAL.
147  */
148 static loff_t memory_lseek(struct file * file, loff_t offset, int orig)
149 {
150         loff_t ret;
151
152         mutex_lock(&file->f_dentry->d_inode->i_mutex);
153         switch (orig) {
154                 case 0:
155                         file->f_pos = offset;
156                         ret = file->f_pos;
157                         force_successful_syscall_return();
158                         break;
159                 case 1:
160                         file->f_pos += offset;
161                         ret = file->f_pos;
162                         force_successful_syscall_return();
163                         break;
164                 default:
165                         ret = -EINVAL;
166         }
167         mutex_unlock(&file->f_dentry->d_inode->i_mutex);
168         return ret;
169 }
170
171 static int open_mem(struct inode * inode, struct file * filp)
172 {
173         return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
174 }
175
176 struct file_operations mem_fops = {
177         .llseek         = memory_lseek,
178         .read           = read_mem,
179         .write          = write_mem,
180         .mmap           = mmap_mem,
181         .open           = open_mem,
182 };