diff options
Diffstat (limited to 'drivers/char/mem.c')
-rw-r--r-- | drivers/char/mem.c | 387 |
1 files changed, 176 insertions, 211 deletions
diff --git a/drivers/char/mem.c b/drivers/char/mem.c index a074fceb67d3..f54dab8acdcd 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c | |||
@@ -3,9 +3,9 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) 1991, 1992 Linus Torvalds | 4 | * Copyright (C) 1991, 1992 Linus Torvalds |
5 | * | 5 | * |
6 | * Added devfs support. | 6 | * Added devfs support. |
7 | * Jan-11-1998, C. Scott Ananian <cananian@alumni.princeton.edu> | 7 | * Jan-11-1998, C. Scott Ananian <cananian@alumni.princeton.edu> |
8 | * Shared /dev/zero mmaping support, Feb 2000, Kanoj Sarcar <kanoj@sgi.com> | 8 | * Shared /dev/zero mmapping support, Feb 2000, Kanoj Sarcar <kanoj@sgi.com> |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/mm.h> | 11 | #include <linux/mm.h> |
@@ -26,7 +26,6 @@ | |||
26 | #include <linux/bootmem.h> | 26 | #include <linux/bootmem.h> |
27 | #include <linux/splice.h> | 27 | #include <linux/splice.h> |
28 | #include <linux/pfn.h> | 28 | #include <linux/pfn.h> |
29 | #include <linux/smp_lock.h> | ||
30 | 29 | ||
31 | #include <asm/uaccess.h> | 30 | #include <asm/uaccess.h> |
32 | #include <asm/io.h> | 31 | #include <asm/io.h> |
@@ -35,34 +34,14 @@ | |||
35 | # include <linux/efi.h> | 34 | # include <linux/efi.h> |
36 | #endif | 35 | #endif |
37 | 36 | ||
38 | /* | 37 | static inline unsigned long size_inside_page(unsigned long start, |
39 | * Architectures vary in how they handle caching for addresses | 38 | unsigned long size) |
40 | * outside of main memory. | ||
41 | * | ||
42 | */ | ||
43 | static inline int uncached_access(struct file *file, unsigned long addr) | ||
44 | { | 39 | { |
45 | #if defined(CONFIG_IA64) | 40 | unsigned long sz; |
46 | /* | ||
47 | * On ia64, we ignore O_SYNC because we cannot tolerate memory attribute aliases. | ||
48 | */ | ||
49 | return !(efi_mem_attributes(addr) & EFI_MEMORY_WB); | ||
50 | #elif defined(CONFIG_MIPS) | ||
51 | { | ||
52 | extern int __uncached_access(struct file *file, | ||
53 | unsigned long addr); | ||
54 | 41 | ||
55 | return __uncached_access(file, addr); | 42 | sz = PAGE_SIZE - (start & (PAGE_SIZE - 1)); |
56 | } | 43 | |
57 | #else | 44 | return min(sz, size); |
58 | /* | ||
59 | * Accessing memory above the top the kernel knows about or through a file pointer | ||
60 | * that was marked O_SYNC will be done non-cached. | ||
61 | */ | ||
62 | if (file->f_flags & O_SYNC) | ||
63 | return 1; | ||
64 | return addr >= __pa(high_memory); | ||
65 | #endif | ||
66 | } | 45 | } |
67 | 46 | ||
68 | #ifndef ARCH_HAS_VALID_PHYS_ADDR_RANGE | 47 | #ifndef ARCH_HAS_VALID_PHYS_ADDR_RANGE |
@@ -106,15 +85,15 @@ static inline int range_is_allowed(unsigned long pfn, unsigned long size) | |||
106 | } | 85 | } |
107 | #endif | 86 | #endif |
108 | 87 | ||
109 | void __attribute__((weak)) unxlate_dev_mem_ptr(unsigned long phys, void *addr) | 88 | void __weak unxlate_dev_mem_ptr(unsigned long phys, void *addr) |
110 | { | 89 | { |
111 | } | 90 | } |
112 | 91 | ||
113 | /* | 92 | /* |
114 | * This funcion reads the *physical* memory. The f_pos points directly to the | 93 | * This funcion reads the *physical* memory. The f_pos points directly to the |
115 | * memory location. | 94 | * memory location. |
116 | */ | 95 | */ |
117 | static ssize_t read_mem(struct file * file, char __user * buf, | 96 | static ssize_t read_mem(struct file *file, char __user *buf, |
118 | size_t count, loff_t *ppos) | 97 | size_t count, loff_t *ppos) |
119 | { | 98 | { |
120 | unsigned long p = *ppos; | 99 | unsigned long p = *ppos; |
@@ -127,49 +106,39 @@ static ssize_t read_mem(struct file * file, char __user * buf, | |||
127 | #ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED | 106 | #ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED |
128 | /* we don't have page 0 mapped on sparc and m68k.. */ | 107 | /* we don't have page 0 mapped on sparc and m68k.. */ |
129 | if (p < PAGE_SIZE) { | 108 | if (p < PAGE_SIZE) { |
130 | sz = PAGE_SIZE - p; | 109 | sz = size_inside_page(p, count); |
131 | if (sz > count) | ||
132 | sz = count; | ||
133 | if (sz > 0) { | 110 | if (sz > 0) { |
134 | if (clear_user(buf, sz)) | 111 | if (clear_user(buf, sz)) |
135 | return -EFAULT; | 112 | return -EFAULT; |
136 | buf += sz; | 113 | buf += sz; |
137 | p += sz; | 114 | p += sz; |
138 | count -= sz; | 115 | count -= sz; |
139 | read += sz; | 116 | read += sz; |
140 | } | 117 | } |
141 | } | 118 | } |
142 | #endif | 119 | #endif |
143 | 120 | ||
144 | while (count > 0) { | 121 | while (count > 0) { |
145 | /* | 122 | unsigned long remaining; |
146 | * Handle first page in case it's not aligned | ||
147 | */ | ||
148 | if (-p & (PAGE_SIZE - 1)) | ||
149 | sz = -p & (PAGE_SIZE - 1); | ||
150 | else | ||
151 | sz = PAGE_SIZE; | ||
152 | 123 | ||
153 | sz = min_t(unsigned long, sz, count); | 124 | sz = size_inside_page(p, count); |
154 | 125 | ||
155 | if (!range_is_allowed(p >> PAGE_SHIFT, count)) | 126 | if (!range_is_allowed(p >> PAGE_SHIFT, count)) |
156 | return -EPERM; | 127 | return -EPERM; |
157 | 128 | ||
158 | /* | 129 | /* |
159 | * On ia64 if a page has been mapped somewhere as | 130 | * On ia64 if a page has been mapped somewhere as uncached, then |
160 | * uncached, then it must also be accessed uncached | 131 | * it must also be accessed uncached by the kernel or data |
161 | * by the kernel or data corruption may occur | 132 | * corruption may occur. |
162 | */ | 133 | */ |
163 | ptr = xlate_dev_mem_ptr(p); | 134 | ptr = xlate_dev_mem_ptr(p); |
164 | if (!ptr) | 135 | if (!ptr) |
165 | return -EFAULT; | 136 | return -EFAULT; |
166 | 137 | ||
167 | if (copy_to_user(buf, ptr, sz)) { | 138 | remaining = copy_to_user(buf, ptr, sz); |
168 | unxlate_dev_mem_ptr(p, ptr); | ||
169 | return -EFAULT; | ||
170 | } | ||
171 | |||
172 | unxlate_dev_mem_ptr(p, ptr); | 139 | unxlate_dev_mem_ptr(p, ptr); |
140 | if (remaining) | ||
141 | return -EFAULT; | ||
173 | 142 | ||
174 | buf += sz; | 143 | buf += sz; |
175 | p += sz; | 144 | p += sz; |
@@ -181,7 +150,7 @@ static ssize_t read_mem(struct file * file, char __user * buf, | |||
181 | return read; | 150 | return read; |
182 | } | 151 | } |
183 | 152 | ||
184 | static ssize_t write_mem(struct file * file, const char __user * buf, | 153 | static ssize_t write_mem(struct file *file, const char __user *buf, |
185 | size_t count, loff_t *ppos) | 154 | size_t count, loff_t *ppos) |
186 | { | 155 | { |
187 | unsigned long p = *ppos; | 156 | unsigned long p = *ppos; |
@@ -197,9 +166,7 @@ static ssize_t write_mem(struct file * file, const char __user * buf, | |||
197 | #ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED | 166 | #ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED |
198 | /* we don't have page 0 mapped on sparc and m68k.. */ | 167 | /* we don't have page 0 mapped on sparc and m68k.. */ |
199 | if (p < PAGE_SIZE) { | 168 | if (p < PAGE_SIZE) { |
200 | unsigned long sz = PAGE_SIZE - p; | 169 | sz = size_inside_page(p, count); |
201 | if (sz > count) | ||
202 | sz = count; | ||
203 | /* Hmm. Do something? */ | 170 | /* Hmm. Do something? */ |
204 | buf += sz; | 171 | buf += sz; |
205 | p += sz; | 172 | p += sz; |
@@ -209,23 +176,15 @@ static ssize_t write_mem(struct file * file, const char __user * buf, | |||
209 | #endif | 176 | #endif |
210 | 177 | ||
211 | while (count > 0) { | 178 | while (count > 0) { |
212 | /* | 179 | sz = size_inside_page(p, count); |
213 | * Handle first page in case it's not aligned | ||
214 | */ | ||
215 | if (-p & (PAGE_SIZE - 1)) | ||
216 | sz = -p & (PAGE_SIZE - 1); | ||
217 | else | ||
218 | sz = PAGE_SIZE; | ||
219 | |||
220 | sz = min_t(unsigned long, sz, count); | ||
221 | 180 | ||
222 | if (!range_is_allowed(p >> PAGE_SHIFT, sz)) | 181 | if (!range_is_allowed(p >> PAGE_SHIFT, sz)) |
223 | return -EPERM; | 182 | return -EPERM; |
224 | 183 | ||
225 | /* | 184 | /* |
226 | * On ia64 if a page has been mapped somewhere as | 185 | * On ia64 if a page has been mapped somewhere as uncached, then |
227 | * uncached, then it must also be accessed uncached | 186 | * it must also be accessed uncached by the kernel or data |
228 | * by the kernel or data corruption may occur | 187 | * corruption may occur. |
229 | */ | 188 | */ |
230 | ptr = xlate_dev_mem_ptr(p); | 189 | ptr = xlate_dev_mem_ptr(p); |
231 | if (!ptr) { | 190 | if (!ptr) { |
@@ -235,16 +194,14 @@ static ssize_t write_mem(struct file * file, const char __user * buf, | |||
235 | } | 194 | } |
236 | 195 | ||
237 | copied = copy_from_user(ptr, buf, sz); | 196 | copied = copy_from_user(ptr, buf, sz); |
197 | unxlate_dev_mem_ptr(p, ptr); | ||
238 | if (copied) { | 198 | if (copied) { |
239 | written += sz - copied; | 199 | written += sz - copied; |
240 | unxlate_dev_mem_ptr(p, ptr); | ||
241 | if (written) | 200 | if (written) |
242 | break; | 201 | break; |
243 | return -EFAULT; | 202 | return -EFAULT; |
244 | } | 203 | } |
245 | 204 | ||
246 | unxlate_dev_mem_ptr(p, ptr); | ||
247 | |||
248 | buf += sz; | 205 | buf += sz; |
249 | p += sz; | 206 | p += sz; |
250 | count -= sz; | 207 | count -= sz; |
@@ -255,13 +212,48 @@ static ssize_t write_mem(struct file * file, const char __user * buf, | |||
255 | return written; | 212 | return written; |
256 | } | 213 | } |
257 | 214 | ||
258 | int __attribute__((weak)) phys_mem_access_prot_allowed(struct file *file, | 215 | int __weak phys_mem_access_prot_allowed(struct file *file, |
259 | unsigned long pfn, unsigned long size, pgprot_t *vma_prot) | 216 | unsigned long pfn, unsigned long size, pgprot_t *vma_prot) |
260 | { | 217 | { |
261 | return 1; | 218 | return 1; |
262 | } | 219 | } |
263 | 220 | ||
264 | #ifndef __HAVE_PHYS_MEM_ACCESS_PROT | 221 | #ifndef __HAVE_PHYS_MEM_ACCESS_PROT |
222 | |||
223 | /* | ||
224 | * Architectures vary in how they handle caching for addresses | ||
225 | * outside of main memory. | ||
226 | * | ||
227 | */ | ||
228 | #ifdef pgprot_noncached | ||
229 | static int uncached_access(struct file *file, unsigned long addr) | ||
230 | { | ||
231 | #if defined(CONFIG_IA64) | ||
232 | /* | ||
233 | * On ia64, we ignore O_DSYNC because we cannot tolerate memory | ||
234 | * attribute aliases. | ||
235 | */ | ||
236 | return !(efi_mem_attributes(addr) & EFI_MEMORY_WB); | ||
237 | #elif defined(CONFIG_MIPS) | ||
238 | { | ||
239 | extern int __uncached_access(struct file *file, | ||
240 | unsigned long addr); | ||
241 | |||
242 | return __uncached_access(file, addr); | ||
243 | } | ||
244 | #else | ||
245 | /* | ||
246 | * Accessing memory above the top the kernel knows about or through a | ||
247 | * file pointer | ||
248 | * that was marked O_DSYNC will be done non-cached. | ||
249 | */ | ||
250 | if (file->f_flags & O_DSYNC) | ||
251 | return 1; | ||
252 | return addr >= __pa(high_memory); | ||
253 | #endif | ||
254 | } | ||
255 | #endif | ||
256 | |||
265 | static pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, | 257 | static pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, |
266 | unsigned long size, pgprot_t vma_prot) | 258 | unsigned long size, pgprot_t vma_prot) |
267 | { | 259 | { |
@@ -307,7 +299,7 @@ static const struct vm_operations_struct mmap_mem_ops = { | |||
307 | #endif | 299 | #endif |
308 | }; | 300 | }; |
309 | 301 | ||
310 | static int mmap_mem(struct file * file, struct vm_area_struct * vma) | 302 | static int mmap_mem(struct file *file, struct vm_area_struct *vma) |
311 | { | 303 | { |
312 | size_t size = vma->vm_end - vma->vm_start; | 304 | size_t size = vma->vm_end - vma->vm_start; |
313 | 305 | ||
@@ -342,7 +334,7 @@ static int mmap_mem(struct file * file, struct vm_area_struct * vma) | |||
342 | } | 334 | } |
343 | 335 | ||
344 | #ifdef CONFIG_DEVKMEM | 336 | #ifdef CONFIG_DEVKMEM |
345 | static int mmap_kmem(struct file * file, struct vm_area_struct * vma) | 337 | static int mmap_kmem(struct file *file, struct vm_area_struct *vma) |
346 | { | 338 | { |
347 | unsigned long pfn; | 339 | unsigned long pfn; |
348 | 340 | ||
@@ -350,9 +342,9 @@ static int mmap_kmem(struct file * file, struct vm_area_struct * vma) | |||
350 | pfn = __pa((u64)vma->vm_pgoff << PAGE_SHIFT) >> PAGE_SHIFT; | 342 | pfn = __pa((u64)vma->vm_pgoff << PAGE_SHIFT) >> PAGE_SHIFT; |
351 | 343 | ||
352 | /* | 344 | /* |
353 | * RED-PEN: on some architectures there is more mapped memory | 345 | * RED-PEN: on some architectures there is more mapped memory than |
354 | * than available in mem_map which pfn_valid checks | 346 | * available in mem_map which pfn_valid checks for. Perhaps should add a |
355 | * for. Perhaps should add a new macro here. | 347 | * new macro here. |
356 | * | 348 | * |
357 | * RED-PEN: vmalloc is not supported right now. | 349 | * RED-PEN: vmalloc is not supported right now. |
358 | */ | 350 | */ |
@@ -402,43 +394,35 @@ static ssize_t read_oldmem(struct file *file, char __user *buf, | |||
402 | /* | 394 | /* |
403 | * This function reads the *virtual* memory as seen by the kernel. | 395 | * This function reads the *virtual* memory as seen by the kernel. |
404 | */ | 396 | */ |
405 | static ssize_t read_kmem(struct file *file, char __user *buf, | 397 | static ssize_t read_kmem(struct file *file, char __user *buf, |
406 | size_t count, loff_t *ppos) | 398 | size_t count, loff_t *ppos) |
407 | { | 399 | { |
408 | unsigned long p = *ppos; | 400 | unsigned long p = *ppos; |
409 | ssize_t low_count, read, sz; | 401 | ssize_t low_count, read, sz; |
410 | char * kbuf; /* k-addr because vread() takes vmlist_lock rwlock */ | 402 | char * kbuf; /* k-addr because vread() takes vmlist_lock rwlock */ |
403 | int err = 0; | ||
411 | 404 | ||
412 | read = 0; | 405 | read = 0; |
413 | if (p < (unsigned long) high_memory) { | 406 | if (p < (unsigned long) high_memory) { |
414 | low_count = count; | 407 | low_count = count; |
415 | if (count > (unsigned long) high_memory - p) | 408 | if (count > (unsigned long)high_memory - p) |
416 | low_count = (unsigned long) high_memory - p; | 409 | low_count = (unsigned long)high_memory - p; |
417 | 410 | ||
418 | #ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED | 411 | #ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED |
419 | /* we don't have page 0 mapped on sparc and m68k.. */ | 412 | /* we don't have page 0 mapped on sparc and m68k.. */ |
420 | if (p < PAGE_SIZE && low_count > 0) { | 413 | if (p < PAGE_SIZE && low_count > 0) { |
421 | size_t tmp = PAGE_SIZE - p; | 414 | sz = size_inside_page(p, low_count); |
422 | if (tmp > low_count) tmp = low_count; | 415 | if (clear_user(buf, sz)) |
423 | if (clear_user(buf, tmp)) | ||
424 | return -EFAULT; | 416 | return -EFAULT; |
425 | buf += tmp; | 417 | buf += sz; |
426 | p += tmp; | 418 | p += sz; |
427 | read += tmp; | 419 | read += sz; |
428 | low_count -= tmp; | 420 | low_count -= sz; |
429 | count -= tmp; | 421 | count -= sz; |
430 | } | 422 | } |
431 | #endif | 423 | #endif |
432 | while (low_count > 0) { | 424 | while (low_count > 0) { |
433 | /* | 425 | sz = size_inside_page(p, low_count); |
434 | * Handle first page in case it's not aligned | ||
435 | */ | ||
436 | if (-p & (PAGE_SIZE - 1)) | ||
437 | sz = -p & (PAGE_SIZE - 1); | ||
438 | else | ||
439 | sz = PAGE_SIZE; | ||
440 | |||
441 | sz = min_t(unsigned long, sz, low_count); | ||
442 | 426 | ||
443 | /* | 427 | /* |
444 | * On ia64 if a page has been mapped somewhere as | 428 | * On ia64 if a page has been mapped somewhere as |
@@ -462,32 +446,32 @@ static ssize_t read_kmem(struct file *file, char __user *buf, | |||
462 | if (!kbuf) | 446 | if (!kbuf) |
463 | return -ENOMEM; | 447 | return -ENOMEM; |
464 | while (count > 0) { | 448 | while (count > 0) { |
465 | int len = count; | 449 | sz = size_inside_page(p, count); |
466 | 450 | if (!is_vmalloc_or_module_addr((void *)p)) { | |
467 | if (len > PAGE_SIZE) | 451 | err = -ENXIO; |
468 | len = PAGE_SIZE; | ||
469 | len = vread(kbuf, (char *)p, len); | ||
470 | if (!len) | ||
471 | break; | 452 | break; |
472 | if (copy_to_user(buf, kbuf, len)) { | ||
473 | free_page((unsigned long)kbuf); | ||
474 | return -EFAULT; | ||
475 | } | 453 | } |
476 | count -= len; | 454 | sz = vread(kbuf, (char *)p, sz); |
477 | buf += len; | 455 | if (!sz) |
478 | read += len; | 456 | break; |
479 | p += len; | 457 | if (copy_to_user(buf, kbuf, sz)) { |
458 | err = -EFAULT; | ||
459 | break; | ||
460 | } | ||
461 | count -= sz; | ||
462 | buf += sz; | ||
463 | read += sz; | ||
464 | p += sz; | ||
480 | } | 465 | } |
481 | free_page((unsigned long)kbuf); | 466 | free_page((unsigned long)kbuf); |
482 | } | 467 | } |
483 | *ppos = p; | 468 | *ppos = p; |
484 | return read; | 469 | return read ? read : err; |
485 | } | 470 | } |
486 | 471 | ||
487 | 472 | ||
488 | static inline ssize_t | 473 | static ssize_t do_write_kmem(unsigned long p, const char __user *buf, |
489 | do_write_kmem(void *p, unsigned long realp, const char __user * buf, | 474 | size_t count, loff_t *ppos) |
490 | size_t count, loff_t *ppos) | ||
491 | { | 475 | { |
492 | ssize_t written, sz; | 476 | ssize_t written, sz; |
493 | unsigned long copied; | 477 | unsigned long copied; |
@@ -495,14 +479,11 @@ do_write_kmem(void *p, unsigned long realp, const char __user * buf, | |||
495 | written = 0; | 479 | written = 0; |
496 | #ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED | 480 | #ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED |
497 | /* we don't have page 0 mapped on sparc and m68k.. */ | 481 | /* we don't have page 0 mapped on sparc and m68k.. */ |
498 | if (realp < PAGE_SIZE) { | 482 | if (p < PAGE_SIZE) { |
499 | unsigned long sz = PAGE_SIZE - realp; | 483 | sz = size_inside_page(p, count); |
500 | if (sz > count) | ||
501 | sz = count; | ||
502 | /* Hmm. Do something? */ | 484 | /* Hmm. Do something? */ |
503 | buf += sz; | 485 | buf += sz; |
504 | p += sz; | 486 | p += sz; |
505 | realp += sz; | ||
506 | count -= sz; | 487 | count -= sz; |
507 | written += sz; | 488 | written += sz; |
508 | } | 489 | } |
@@ -510,22 +491,15 @@ do_write_kmem(void *p, unsigned long realp, const char __user * buf, | |||
510 | 491 | ||
511 | while (count > 0) { | 492 | while (count > 0) { |
512 | char *ptr; | 493 | char *ptr; |
513 | /* | ||
514 | * Handle first page in case it's not aligned | ||
515 | */ | ||
516 | if (-realp & (PAGE_SIZE - 1)) | ||
517 | sz = -realp & (PAGE_SIZE - 1); | ||
518 | else | ||
519 | sz = PAGE_SIZE; | ||
520 | 494 | ||
521 | sz = min_t(unsigned long, sz, count); | 495 | sz = size_inside_page(p, count); |
522 | 496 | ||
523 | /* | 497 | /* |
524 | * On ia64 if a page has been mapped somewhere as | 498 | * On ia64 if a page has been mapped somewhere as uncached, then |
525 | * uncached, then it must also be accessed uncached | 499 | * it must also be accessed uncached by the kernel or data |
526 | * by the kernel or data corruption may occur | 500 | * corruption may occur. |
527 | */ | 501 | */ |
528 | ptr = xlate_dev_kmem_ptr(p); | 502 | ptr = xlate_dev_kmem_ptr((char *)p); |
529 | 503 | ||
530 | copied = copy_from_user(ptr, buf, sz); | 504 | copied = copy_from_user(ptr, buf, sz); |
531 | if (copied) { | 505 | if (copied) { |
@@ -536,7 +510,6 @@ do_write_kmem(void *p, unsigned long realp, const char __user * buf, | |||
536 | } | 510 | } |
537 | buf += sz; | 511 | buf += sz; |
538 | p += sz; | 512 | p += sz; |
539 | realp += sz; | ||
540 | count -= sz; | 513 | count -= sz; |
541 | written += sz; | 514 | written += sz; |
542 | } | 515 | } |
@@ -545,29 +518,24 @@ do_write_kmem(void *p, unsigned long realp, const char __user * buf, | |||
545 | return written; | 518 | return written; |
546 | } | 519 | } |
547 | 520 | ||
548 | |||
549 | /* | 521 | /* |
550 | * This function writes to the *virtual* memory as seen by the kernel. | 522 | * This function writes to the *virtual* memory as seen by the kernel. |
551 | */ | 523 | */ |
552 | static ssize_t write_kmem(struct file * file, const char __user * buf, | 524 | static ssize_t write_kmem(struct file *file, const char __user *buf, |
553 | size_t count, loff_t *ppos) | 525 | size_t count, loff_t *ppos) |
554 | { | 526 | { |
555 | unsigned long p = *ppos; | 527 | unsigned long p = *ppos; |
556 | ssize_t wrote = 0; | 528 | ssize_t wrote = 0; |
557 | ssize_t virtr = 0; | 529 | ssize_t virtr = 0; |
558 | ssize_t written; | ||
559 | char * kbuf; /* k-addr because vwrite() takes vmlist_lock rwlock */ | 530 | char * kbuf; /* k-addr because vwrite() takes vmlist_lock rwlock */ |
531 | int err = 0; | ||
560 | 532 | ||
561 | if (p < (unsigned long) high_memory) { | 533 | if (p < (unsigned long) high_memory) { |
562 | 534 | unsigned long to_write = min_t(unsigned long, count, | |
563 | wrote = count; | 535 | (unsigned long)high_memory - p); |
564 | if (count > (unsigned long) high_memory - p) | 536 | wrote = do_write_kmem(p, buf, to_write, ppos); |
565 | wrote = (unsigned long) high_memory - p; | 537 | if (wrote != to_write) |
566 | 538 | return wrote; | |
567 | written = do_write_kmem((void*)p, p, buf, wrote, ppos); | ||
568 | if (written != wrote) | ||
569 | return written; | ||
570 | wrote = written; | ||
571 | p += wrote; | 539 | p += wrote; |
572 | buf += wrote; | 540 | buf += wrote; |
573 | count -= wrote; | 541 | count -= wrote; |
@@ -578,45 +546,44 @@ static ssize_t write_kmem(struct file * file, const char __user * buf, | |||
578 | if (!kbuf) | 546 | if (!kbuf) |
579 | return wrote ? wrote : -ENOMEM; | 547 | return wrote ? wrote : -ENOMEM; |
580 | while (count > 0) { | 548 | while (count > 0) { |
581 | int len = count; | 549 | unsigned long sz = size_inside_page(p, count); |
582 | 550 | unsigned long n; | |
583 | if (len > PAGE_SIZE) | 551 | |
584 | len = PAGE_SIZE; | 552 | if (!is_vmalloc_or_module_addr((void *)p)) { |
585 | if (len) { | 553 | err = -ENXIO; |
586 | written = copy_from_user(kbuf, buf, len); | 554 | break; |
587 | if (written) { | 555 | } |
588 | if (wrote + virtr) | 556 | n = copy_from_user(kbuf, buf, sz); |
589 | break; | 557 | if (n) { |
590 | free_page((unsigned long)kbuf); | 558 | err = -EFAULT; |
591 | return -EFAULT; | 559 | break; |
592 | } | ||
593 | } | 560 | } |
594 | len = vwrite(kbuf, (char *)p, len); | 561 | vwrite(kbuf, (char *)p, sz); |
595 | count -= len; | 562 | count -= sz; |
596 | buf += len; | 563 | buf += sz; |
597 | virtr += len; | 564 | virtr += sz; |
598 | p += len; | 565 | p += sz; |
599 | } | 566 | } |
600 | free_page((unsigned long)kbuf); | 567 | free_page((unsigned long)kbuf); |
601 | } | 568 | } |
602 | 569 | ||
603 | *ppos = p; | 570 | *ppos = p; |
604 | return virtr + wrote; | 571 | return virtr + wrote ? : err; |
605 | } | 572 | } |
606 | #endif | 573 | #endif |
607 | 574 | ||
608 | #ifdef CONFIG_DEVPORT | 575 | #ifdef CONFIG_DEVPORT |
609 | static ssize_t read_port(struct file * file, char __user * buf, | 576 | static ssize_t read_port(struct file *file, char __user *buf, |
610 | size_t count, loff_t *ppos) | 577 | size_t count, loff_t *ppos) |
611 | { | 578 | { |
612 | unsigned long i = *ppos; | 579 | unsigned long i = *ppos; |
613 | char __user *tmp = buf; | 580 | char __user *tmp = buf; |
614 | 581 | ||
615 | if (!access_ok(VERIFY_WRITE, buf, count)) | 582 | if (!access_ok(VERIFY_WRITE, buf, count)) |
616 | return -EFAULT; | 583 | return -EFAULT; |
617 | while (count-- > 0 && i < 65536) { | 584 | while (count-- > 0 && i < 65536) { |
618 | if (__put_user(inb(i),tmp) < 0) | 585 | if (__put_user(inb(i), tmp) < 0) |
619 | return -EFAULT; | 586 | return -EFAULT; |
620 | i++; | 587 | i++; |
621 | tmp++; | 588 | tmp++; |
622 | } | 589 | } |
@@ -624,22 +591,22 @@ static ssize_t read_port(struct file * file, char __user * buf, | |||
624 | return tmp-buf; | 591 | return tmp-buf; |
625 | } | 592 | } |
626 | 593 | ||
627 | static ssize_t write_port(struct file * file, const char __user * buf, | 594 | static ssize_t write_port(struct file *file, const char __user *buf, |
628 | size_t count, loff_t *ppos) | 595 | size_t count, loff_t *ppos) |
629 | { | 596 | { |
630 | unsigned long i = *ppos; | 597 | unsigned long i = *ppos; |
631 | const char __user * tmp = buf; | 598 | const char __user * tmp = buf; |
632 | 599 | ||
633 | if (!access_ok(VERIFY_READ,buf,count)) | 600 | if (!access_ok(VERIFY_READ, buf, count)) |
634 | return -EFAULT; | 601 | return -EFAULT; |
635 | while (count-- > 0 && i < 65536) { | 602 | while (count-- > 0 && i < 65536) { |
636 | char c; | 603 | char c; |
637 | if (__get_user(c, tmp)) { | 604 | if (__get_user(c, tmp)) { |
638 | if (tmp > buf) | 605 | if (tmp > buf) |
639 | break; | 606 | break; |
640 | return -EFAULT; | 607 | return -EFAULT; |
641 | } | 608 | } |
642 | outb(c,i); | 609 | outb(c, i); |
643 | i++; | 610 | i++; |
644 | tmp++; | 611 | tmp++; |
645 | } | 612 | } |
@@ -648,13 +615,13 @@ static ssize_t write_port(struct file * file, const char __user * buf, | |||
648 | } | 615 | } |
649 | #endif | 616 | #endif |
650 | 617 | ||
651 | static ssize_t read_null(struct file * file, char __user * buf, | 618 | static ssize_t read_null(struct file *file, char __user *buf, |
652 | size_t count, loff_t *ppos) | 619 | size_t count, loff_t *ppos) |
653 | { | 620 | { |
654 | return 0; | 621 | return 0; |
655 | } | 622 | } |
656 | 623 | ||
657 | static ssize_t write_null(struct file * file, const char __user * buf, | 624 | static ssize_t write_null(struct file *file, const char __user *buf, |
658 | size_t count, loff_t *ppos) | 625 | size_t count, loff_t *ppos) |
659 | { | 626 | { |
660 | return count; | 627 | return count; |
@@ -666,13 +633,13 @@ static int pipe_to_null(struct pipe_inode_info *info, struct pipe_buffer *buf, | |||
666 | return sd->len; | 633 | return sd->len; |
667 | } | 634 | } |
668 | 635 | ||
669 | static ssize_t splice_write_null(struct pipe_inode_info *pipe,struct file *out, | 636 | static ssize_t splice_write_null(struct pipe_inode_info *pipe, struct file *out, |
670 | loff_t *ppos, size_t len, unsigned int flags) | 637 | loff_t *ppos, size_t len, unsigned int flags) |
671 | { | 638 | { |
672 | return splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_null); | 639 | return splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_null); |
673 | } | 640 | } |
674 | 641 | ||
675 | static ssize_t read_zero(struct file * file, char __user * buf, | 642 | static ssize_t read_zero(struct file *file, char __user *buf, |
676 | size_t count, loff_t *ppos) | 643 | size_t count, loff_t *ppos) |
677 | { | 644 | { |
678 | size_t written; | 645 | size_t written; |
@@ -703,7 +670,7 @@ static ssize_t read_zero(struct file * file, char __user * buf, | |||
703 | return written ? written : -EFAULT; | 670 | return written ? written : -EFAULT; |
704 | } | 671 | } |
705 | 672 | ||
706 | static int mmap_zero(struct file * file, struct vm_area_struct * vma) | 673 | static int mmap_zero(struct file *file, struct vm_area_struct *vma) |
707 | { | 674 | { |
708 | #ifndef CONFIG_MMU | 675 | #ifndef CONFIG_MMU |
709 | return -ENOSYS; | 676 | return -ENOSYS; |
@@ -713,7 +680,7 @@ static int mmap_zero(struct file * file, struct vm_area_struct * vma) | |||
713 | return 0; | 680 | return 0; |
714 | } | 681 | } |
715 | 682 | ||
716 | static ssize_t write_full(struct file * file, const char __user * buf, | 683 | static ssize_t write_full(struct file *file, const char __user *buf, |
717 | size_t count, loff_t *ppos) | 684 | size_t count, loff_t *ppos) |
718 | { | 685 | { |
719 | return -ENOSPC; | 686 | return -ENOSPC; |
@@ -724,8 +691,7 @@ static ssize_t write_full(struct file * file, const char __user * buf, | |||
724 | * can fopen() both devices with "a" now. This was previously impossible. | 691 | * can fopen() both devices with "a" now. This was previously impossible. |
725 | * -- SRB. | 692 | * -- SRB. |
726 | */ | 693 | */ |
727 | 694 | static loff_t null_lseek(struct file *file, loff_t offset, int orig) | |
728 | static loff_t null_lseek(struct file * file, loff_t offset, int orig) | ||
729 | { | 695 | { |
730 | return file->f_pos = 0; | 696 | return file->f_pos = 0; |
731 | } | 697 | } |
@@ -738,24 +704,26 @@ static loff_t null_lseek(struct file * file, loff_t offset, int orig) | |||
738 | * also note that seeking relative to the "end of file" isn't supported: | 704 | * also note that seeking relative to the "end of file" isn't supported: |
739 | * it has no meaning, so it returns -EINVAL. | 705 | * it has no meaning, so it returns -EINVAL. |
740 | */ | 706 | */ |
741 | static loff_t memory_lseek(struct file * file, loff_t offset, int orig) | 707 | static loff_t memory_lseek(struct file *file, loff_t offset, int orig) |
742 | { | 708 | { |
743 | loff_t ret; | 709 | loff_t ret; |
744 | 710 | ||
745 | mutex_lock(&file->f_path.dentry->d_inode->i_mutex); | 711 | mutex_lock(&file->f_path.dentry->d_inode->i_mutex); |
746 | switch (orig) { | 712 | switch (orig) { |
747 | case 0: | 713 | case SEEK_CUR: |
748 | file->f_pos = offset; | 714 | offset += file->f_pos; |
749 | ret = file->f_pos; | 715 | case SEEK_SET: |
750 | force_successful_syscall_return(); | 716 | /* to avoid userland mistaking f_pos=-9 as -EBADF=-9 */ |
717 | if ((unsigned long long)offset >= ~0xFFFULL) { | ||
718 | ret = -EOVERFLOW; | ||
751 | break; | 719 | break; |
752 | case 1: | 720 | } |
753 | file->f_pos += offset; | 721 | file->f_pos = offset; |
754 | ret = file->f_pos; | 722 | ret = file->f_pos; |
755 | force_successful_syscall_return(); | 723 | force_successful_syscall_return(); |
756 | break; | 724 | break; |
757 | default: | 725 | default: |
758 | ret = -EINVAL; | 726 | ret = -EINVAL; |
759 | } | 727 | } |
760 | mutex_unlock(&file->f_path.dentry->d_inode->i_mutex); | 728 | mutex_unlock(&file->f_path.dentry->d_inode->i_mutex); |
761 | return ret; | 729 | return ret; |
@@ -839,7 +807,7 @@ static const struct file_operations oldmem_fops = { | |||
839 | }; | 807 | }; |
840 | #endif | 808 | #endif |
841 | 809 | ||
842 | static ssize_t kmsg_write(struct file * file, const char __user * buf, | 810 | static ssize_t kmsg_write(struct file *file, const char __user *buf, |
843 | size_t count, loff_t *ppos) | 811 | size_t count, loff_t *ppos) |
844 | { | 812 | { |
845 | char *tmp; | 813 | char *tmp; |
@@ -861,7 +829,7 @@ static ssize_t kmsg_write(struct file * file, const char __user * buf, | |||
861 | } | 829 | } |
862 | 830 | ||
863 | static const struct file_operations kmsg_fops = { | 831 | static const struct file_operations kmsg_fops = { |
864 | .write = kmsg_write, | 832 | .write = kmsg_write, |
865 | }; | 833 | }; |
866 | 834 | ||
867 | static const struct memdev { | 835 | static const struct memdev { |
@@ -892,33 +860,27 @@ static int memory_open(struct inode *inode, struct file *filp) | |||
892 | { | 860 | { |
893 | int minor; | 861 | int minor; |
894 | const struct memdev *dev; | 862 | const struct memdev *dev; |
895 | int ret = -ENXIO; | ||
896 | |||
897 | lock_kernel(); | ||
898 | 863 | ||
899 | minor = iminor(inode); | 864 | minor = iminor(inode); |
900 | if (minor >= ARRAY_SIZE(devlist)) | 865 | if (minor >= ARRAY_SIZE(devlist)) |
901 | goto out; | 866 | return -ENXIO; |
902 | 867 | ||
903 | dev = &devlist[minor]; | 868 | dev = &devlist[minor]; |
904 | if (!dev->fops) | 869 | if (!dev->fops) |
905 | goto out; | 870 | return -ENXIO; |
906 | 871 | ||
907 | filp->f_op = dev->fops; | 872 | filp->f_op = dev->fops; |
908 | if (dev->dev_info) | 873 | if (dev->dev_info) |
909 | filp->f_mapping->backing_dev_info = dev->dev_info; | 874 | filp->f_mapping->backing_dev_info = dev->dev_info; |
910 | 875 | ||
911 | if (dev->fops->open) | 876 | if (dev->fops->open) |
912 | ret = dev->fops->open(inode, filp); | 877 | return dev->fops->open(inode, filp); |
913 | else | 878 | |
914 | ret = 0; | 879 | return 0; |
915 | out: | ||
916 | unlock_kernel(); | ||
917 | return ret; | ||
918 | } | 880 | } |
919 | 881 | ||
920 | static const struct file_operations memory_fops = { | 882 | static const struct file_operations memory_fops = { |
921 | .open = memory_open, | 883 | .open = memory_open, |
922 | }; | 884 | }; |
923 | 885 | ||
924 | static char *mem_devnode(struct device *dev, mode_t *mode) | 886 | static char *mem_devnode(struct device *dev, mode_t *mode) |
@@ -939,10 +901,13 @@ static int __init chr_dev_init(void) | |||
939 | if (err) | 901 | if (err) |
940 | return err; | 902 | return err; |
941 | 903 | ||
942 | if (register_chrdev(MEM_MAJOR,"mem",&memory_fops)) | 904 | if (register_chrdev(MEM_MAJOR, "mem", &memory_fops)) |
943 | printk("unable to get major %d for memory devs\n", MEM_MAJOR); | 905 | printk("unable to get major %d for memory devs\n", MEM_MAJOR); |
944 | 906 | ||
945 | mem_class = class_create(THIS_MODULE, "mem"); | 907 | mem_class = class_create(THIS_MODULE, "mem"); |
908 | if (IS_ERR(mem_class)) | ||
909 | return PTR_ERR(mem_class); | ||
910 | |||
946 | mem_class->devnode = mem_devnode; | 911 | mem_class->devnode = mem_devnode; |
947 | for (minor = 1; minor < ARRAY_SIZE(devlist); minor++) { | 912 | for (minor = 1; minor < ARRAY_SIZE(devlist); minor++) { |
948 | if (!devlist[minor].name) | 913 | if (!devlist[minor].name) |