devmem读写物理内存和devkmem读取内核虚拟内存(5)

static ssize_t read_kmem(struct file *file, char __user *buf,
            size_t count, loff_t *ppos)
{
    unsigned long p = *ppos;
    ssize_t low_count, read, sz;
    char *kbuf; /* k-addr because vread() takes vmlist_lock rwlock */
    int err = 0;

read = 0;
    if (p < (unsigned long) high_memory) {---------------------------------------属于low_memory内存处理。
        low_count = count;
        if (count > (unsigned long)high_memory - p)
            low_count = (unsigned long)high_memory - p;--------------------------计算处于low_memory区域的内存大小。
...
        while (low_count > 0) {
            sz = size_inside_page(p, low_count);

kbuf = xlate_dev_kmem_ptr((void *)p);
            if (!virt_addr_valid(kbuf))------------------------------------------地址在PAGE_OFFSET和high_memory之间。
                return -ENXIO;

if (copy_to_user(buf, kbuf, sz))
                return -EFAULT;
            buf += sz;
            p += sz;
            read += sz;
            low_count -= sz;
            count -= sz;
        }
    }

if (count > 0) {-------------------------------------------------------------如果还有count没处理完,那么就属于high_memory。
        kbuf = (char *)__get_free_page(GFP_KERNEL);
        if (!kbuf)
            return -ENOMEM;
        while (count > 0) {
            sz = size_inside_page(p, count);-------------------------------------如果p+count不跨页,那么sz=count;否则sz只取p所在页面剩余部分大小。这样确保下面的copy_to_user()不跨页。
            if (!is_vmalloc_or_module_addr((void *)p)) {
                err = -ENXIO;
                break;
            }
            sz = vread(kbuf, (char *)p, sz);
            if (!sz)
                break;
            if (copy_to_user(buf, kbuf, sz)) {
                err = -EFAULT;
                break;
            }
            count -= sz;
            buf += sz;
            read += sz;
            p += sz;
        }
        free_page((unsigned long)kbuf);
    }
    *ppos = p;
    return read ? read : err;
}

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;

written = 0;
...
    while (count > 0) {
        void *ptr;

sz = size_inside_page(p, count);

ptr = xlate_dev_kmem_ptr((void *)p);
        if (!virt_addr_valid(ptr))
            return -ENXIO;

copied = copy_from_user(ptr, buf, sz);
        if (copied) {
            written += sz - copied;
            if (written)
                break;
            return -EFAULT;
        }
        buf += sz;
        p += sz;
        count -= sz;
        written += sz;
    }

*ppos += written;
    return written;
}

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/12046.html