#include <linux/mm.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/mman.h>
#include <linux/random.h>
#include <linux/init.h>
#include <linux/tty.h>
#include <linux/capability.h>
#include <linux/ptrace.h>
#include <linux/device.h>
#include <linux/highmem.h>
#include <linux/backing-dev.h>
#include <linux/shmem_fs.h>
#include <linux/splice.h>
#include <linux/pfn.h>
#include <linux/export.h>
#include <linux/io.h>
#include <linux/uio.h>
#include <linux/uaccess.h>
#include <linux/security.h>
#define DEVMEM_MINOR …
#define DEVPORT_MINOR …
static inline unsigned long size_inside_page(unsigned long start,
unsigned long size)
{ … }
#ifndef ARCH_HAS_VALID_PHYS_ADDR_RANGE
static inline int valid_phys_addr_range(phys_addr_t addr, size_t count)
{
return addr + count <= __pa(high_memory);
}
static inline int valid_mmap_phys_addr_range(unsigned long pfn, size_t size)
{
return 1;
}
#endif
#ifdef CONFIG_STRICT_DEVMEM
static inline int page_is_allowed(unsigned long pfn)
{ … }
static inline int range_is_allowed(unsigned long pfn, unsigned long size)
{ … }
#else
static inline int page_is_allowed(unsigned long pfn)
{
return 1;
}
static inline int range_is_allowed(unsigned long pfn, unsigned long size)
{
return 1;
}
#endif
static inline bool should_stop_iteration(void)
{ … }
static ssize_t read_mem(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{ … }
static ssize_t write_mem(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{ … }
int __weak phys_mem_access_prot_allowed(struct file *file,
unsigned long pfn, unsigned long size, pgprot_t *vma_prot)
{ … }
#ifndef __HAVE_PHYS_MEM_ACCESS_PROT
#ifdef pgprot_noncached
static int uncached_access(struct file *file, phys_addr_t addr)
{
if (file->f_flags & O_DSYNC)
return 1;
return addr >= __pa(high_memory);
}
#endif
static pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
unsigned long size, pgprot_t vma_prot)
{
#ifdef pgprot_noncached
phys_addr_t offset = pfn << PAGE_SHIFT;
if (uncached_access(file, offset))
return pgprot_noncached(vma_prot);
#endif
return vma_prot;
}
#endif
#ifndef CONFIG_MMU
static unsigned long get_unmapped_area_mem(struct file *file,
unsigned long addr,
unsigned long len,
unsigned long pgoff,
unsigned long flags)
{
if (!valid_mmap_phys_addr_range(pgoff, len))
return (unsigned long) -EINVAL;
return pgoff << PAGE_SHIFT;
}
static unsigned memory_mmap_capabilities(struct file *file)
{
return NOMMU_MAP_DIRECT |
NOMMU_MAP_READ | NOMMU_MAP_WRITE | NOMMU_MAP_EXEC;
}
static unsigned zero_mmap_capabilities(struct file *file)
{
return NOMMU_MAP_COPY;
}
static inline int private_mapping_ok(struct vm_area_struct *vma)
{
return is_nommu_shared_mapping(vma->vm_flags);
}
#else
static inline int private_mapping_ok(struct vm_area_struct *vma)
{ … }
#endif
static const struct vm_operations_struct mmap_mem_ops = …;
static int mmap_mem(struct file *file, struct vm_area_struct *vma)
{ … }
#ifdef CONFIG_DEVPORT
static ssize_t read_port(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{ … }
static ssize_t write_port(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{ … }
#endif
static ssize_t read_null(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{ … }
static ssize_t write_null(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{ … }
static ssize_t read_iter_null(struct kiocb *iocb, struct iov_iter *to)
{ … }
static ssize_t write_iter_null(struct kiocb *iocb, struct iov_iter *from)
{ … }
static int pipe_to_null(struct pipe_inode_info *info, struct pipe_buffer *buf,
struct splice_desc *sd)
{ … }
static ssize_t splice_write_null(struct pipe_inode_info *pipe, struct file *out,
loff_t *ppos, size_t len, unsigned int flags)
{ … }
static int uring_cmd_null(struct io_uring_cmd *ioucmd, unsigned int issue_flags)
{ … }
static ssize_t read_iter_zero(struct kiocb *iocb, struct iov_iter *iter)
{ … }
static ssize_t read_zero(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{ … }
static int mmap_zero(struct file *file, struct vm_area_struct *vma)
{ … }
static unsigned long get_unmapped_area_zero(struct file *file,
unsigned long addr, unsigned long len,
unsigned long pgoff, unsigned long flags)
{ … }
static ssize_t write_full(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{ … }
static loff_t null_lseek(struct file *file, loff_t offset, int orig)
{ … }
static loff_t memory_lseek(struct file *file, loff_t offset, int orig)
{ … }
static int open_port(struct inode *inode, struct file *filp)
{ … }
#define zero_lseek …
#define full_lseek …
#define write_zero …
#define write_iter_zero …
#define splice_write_zero …
#define open_mem …
static const struct file_operations __maybe_unused mem_fops = …;
static const struct file_operations null_fops = …;
#ifdef CONFIG_DEVPORT
static const struct file_operations port_fops = …;
#endif
static const struct file_operations zero_fops = …;
static const struct file_operations full_fops = …;
static const struct memdev { … } devlist[] = …;
static int memory_open(struct inode *inode, struct file *filp)
{ … }
static const struct file_operations memory_fops = …;
static char *mem_devnode(const struct device *dev, umode_t *mode)
{ … }
static const struct class mem_class = …;
static int __init chr_dev_init(void)
{ … }
fs_initcall(chr_dev_init);