err = -EFAULT; if (allowed == 2) { /* Show zeros for restricted memory. */
remaining = clear_user(buf, sz);
} else { /* * 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) goto failed;
if (!valid_phys_addr_range(p, count)) return -EFAULT;
written = 0;
#ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED /* we don't have page 0 mapped on sparc and m68k.. */ if (p < PAGE_SIZE) {
sz = size_inside_page(p, count); /* Hmm. Do something? */
buf += sz;
p += sz;
count -= sz;
written += sz;
} #endif
while (count > 0) { int allowed;
sz = size_inside_page(p, count);
allowed = page_is_allowed(p >> PAGE_SHIFT); if (!allowed) return -EPERM;
/* Skip actual writing when a page is marked as restricted. */ if (allowed == 1) { /* * 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) { if (written) break; return -EFAULT;
}
copied = copy_from_user(ptr, buf, sz);
unxlate_dev_mem_ptr(p, ptr); if (copied) {
written += sz - copied; if (written) break; return -EFAULT;
}
}
buf += sz;
p += sz;
count -= sz;
written += sz; if (should_stop_iteration()) break;
}
/* * Architectures vary in how they handle caching for addresses * outside of main memory. *
*/ #ifdef pgprot_noncached staticint uncached_access(struct file *file, phys_addr_t addr)
{ /* * 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
/* Remap-pfn-range will mark the range VM_IO */ if (remap_pfn_range(vma,
vma->vm_start,
vma->vm_pgoff,
size,
vma->vm_page_prot)) { return -EAGAIN;
} return 0;
}
while (iov_iter_count(iter)) {
size_t chunk = iov_iter_count(iter), n;
if (chunk > PAGE_SIZE)
chunk = PAGE_SIZE; /* Just for latency reasons */
n = iov_iter_zero(chunk, iter); if (!n && iov_iter_count(iter)) return written ? written : -EFAULT;
written += n; if (signal_pending(current)) return written ? written : -ERESTARTSYS; if (!need_resched()) continue; if (iocb->ki_flags & IOCB_NOWAIT) return written ? written : -EAGAIN;
cond_resched();
} return written;
}
staticunsignedlong get_unmapped_area_zero(struct file *file, unsignedlong addr, unsignedlong len, unsignedlong pgoff, unsignedlong flags)
{ #ifdef CONFIG_MMU if (flags & MAP_SHARED) { /* * mmap_zero() will call shmem_zero_setup() to create a file, * so use shmem's get_unmapped_area in case it can be huge; * and pass NULL for file as in mmap.c's get_unmapped_area(), * so as not to confuse shmem with our handle on "/dev/zero".
*/ return shmem_get_unmapped_area(NULL, addr, len, pgoff, flags);
}
/* Otherwise flags & MAP_PRIVATE: with no shmem object beneath it */ return mm_get_unmapped_area(current->mm, file, addr, len, pgoff, flags); #else return -ENOSYS; #endif
}
/* * Special lseek() function for /dev/null and /dev/zero. Most notably, you * 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)
{ return file->f_pos = 0;
}
/* * The memory devices use the full 32/64 bits of the offset, and so we cannot * check against negative addresses: they are ok. The return value is weird, * though, in that case (0). * * 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)
{
loff_t ret;
inode_lock(file_inode(file)); switch (orig) { case SEEK_CUR:
offset += file->f_pos;
fallthrough; case SEEK_SET: /* to avoid userland mistaking f_pos=-9 as -EBADF=-9 */ if ((unsignedlonglong)offset >= -MAX_ERRNO) {
ret = -EOVERFLOW; break;
}
file->f_pos = offset;
ret = file->f_pos;
force_successful_syscall_return(); break; default:
ret = -EINVAL;
}
inode_unlock(file_inode(file)); return ret;
}
staticint open_port(struct inode *inode, struct file *filp)
{ int rc;
if (!capable(CAP_SYS_RAWIO)) return -EPERM;
rc = security_locked_down(LOCKDOWN_DEV_MEM); if (rc) return rc;
if (iminor(inode) != DEVMEM_MINOR) return 0;
/* * Use a unified address space to have a single point to manage * revocations when drivers want to take over a /dev/mem mapped * range.
*/
filp->f_mapping = iomem_get_mapping();
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.