diff --git a/src/aarch64-linux-flush-dcache/mod_entry.c b/src/aarch64-linux-flush-dcache/mod_entry.c index 1e2c554..ded20ca 100644 --- a/src/aarch64-linux-flush-dcache/mod_entry.c +++ b/src/aarch64-linux-flush-dcache/mod_entry.c @@ -6,7 +6,6 @@ #include "linux/gfp_types.h" #include "linux/rcupdate.h" #include -#include #include #include #include @@ -23,6 +22,7 @@ module_param_named(pid, param_pid, int, 0644); static unsigned long param_vmaddr; module_param_named(addr, param_vmaddr, ulong, 0644); +static void **page_addrs; static void *page_addr = NULL; /* Design: @@ -121,7 +121,7 @@ int _flush_dcache_init_devfs(void) } -int _flush_dcache_init_backend(void) +int _flush_dcache_alloc_pages(int page_nr) { page_addr = alloc_page(GFP_USER); if (!page_addr) @@ -133,13 +133,13 @@ ret_err_alloc_failed: return -ENOMEM; } -static int flush_dcache_open(struct inode *inode, struct file *filp) +static int flush_dcache_fops_open(struct inode *inode, struct file *filp) { filp->f_mode |= FMODE_CAN_ODIRECT; return generic_file_open(inode, filp); } -static int flush_dcache_mmap(struct file *filp, struct vm_area_struct *vma) +static int flush_dcache_fops_mmap(struct file *filp, struct vm_area_struct *vma) { /* Check if vma has mm backing -- e.g., non-kthread */ if (!vma->vm_mm) @@ -171,8 +171,8 @@ ret_err_wrong_size: const struct file_operations flush_dcache_fops = { .owner = THIS_MODULE, - .open = flush_dcache_open, - .mmap = flush_dcache_mmap + .open = flush_dcache_fops_open, + .mmap = flush_dcache_fops_mmap }; // const struct vm_operations_struct flush_dcache_vmops = { diff --git a/src/aarch64-linux-flush-dcache/mod_entry_1.c b/src/aarch64-linux-flush-dcache/mod_entry_1.c new file mode 100644 index 0000000..9c9b739 --- /dev/null +++ b/src/aarch64-linux-flush-dcache/mod_entry_1.c @@ -0,0 +1,163 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct my_shmem_page { + struct page *page; + struct list_head list; +}; +static DEFINE_MUTEX(my_shmem_pages_mtx); + +/* [!] READ/WRITE UNDER LOCK */ +static LIST_HEAD(my_shmem_pages); + +/* [!] READ/WRITE UNDER LOCK */ +static size_t my_shmem_page_count = 0; + +/* Virtual Memory Area Operations... + * ============================================================================ + */ +static vm_fault_t my_shmem_vmops_fault(struct vm_fault *vmf) +{ + pgoff_t page_offset = vmf->pgoff; + phys_addr_t _phys; + size_t old_shmem_page_count; + + mutex_lock(&my_shmem_pages_mtx); + old_shmem_page_count = READ_ONCE(my_shmem_page_count); + if (unlikely(page_offset > old_shmem_page_count)) { + /* IMPOSSIBLE -- programming error or wrong assumption... */ + mutex_unlock(&my_shmem_pages_mtx); + goto err_ret_impossible_count; + } + + if (page_offset < old_shmem_page_count) { + /* Offset in range, return existing page */ + pr_info("[%s] Found remappable page offset %lu.", + __func__, page_offset); + + // We won't delete elements from list here! + struct my_shmem_page *page_entry; + list_for_each_entry(page_entry, &my_shmem_pages, list) { + if (!page_offset) + break; + page_offset--; + } + // Found correct page entry, remap + get_page(page_entry->page); + vmf->page = page_entry->page; + _phys = page_to_phys(page_entry->page); + + mutex_unlock(&my_shmem_pages_mtx); + goto ok_ret_remapped; + } + + /* Otherwise, allocate the new page */ + for (int i = 0; i < page_offset - old_shmem_page_count; i++) + { + /* The loop is misleading -- this loops exactly once! */ + // Allocate page handle in kernel + struct my_shmem_page *new_page = kzalloc( + sizeof(struct my_shmem_page), GFP_KERNEL); + if (!new_page) { + mutex_unlock(&my_shmem_pages_mtx); + goto err_ret_no_kmem; + } + + // Allocate page in virtual memory + void *addr = vmalloc_user(PAGE_SIZE); + if (!addr) { + mutex_unlock(&my_shmem_pages_mtx); + goto err_ret_no_vmem; + } + new_page->page = vmalloc_to_page(addr); + + // List maintenance: add and incr. size + list_add(&new_page->list, &my_shmem_pages); + my_shmem_page_count++; + + // Fill in allocated page entry + get_page(new_page->page); + vmf->page = new_page->page; + _phys = page_to_phys(new_page->page); + } + mutex_unlock(&my_shmem_pages_mtx); + goto ok_ret_allocated; + +err_ret_impossible_count: + pr_crit("[%s] IMPOSSIBLE list count %ld > %ld " + "-- no way one fault services multiple page!!!", + __func__, page_offset, old_shmem_page_count); + return VM_FAULT_ERROR; +err_ret_no_kmem: + pr_err("[%s] Cannot allocate `struct my_shmem_page` in kernel memory.", + __func__); + return VM_FAULT_OOM; +err_ret_no_vmem: + pr_err("[%s] Cannot allocate requested page for virtual memory.", + __func__); + return VM_FAULT_OOM; +ok_ret_remapped: + if (vmf->vma->vm_mm) { + rcu_read_lock(); + struct task_struct *fault_owner = vmf->vma->vm_mm->owner; + pr_info("[%s] Remapped phys: 0x%llx -> virt@PID(%d): 0x%lx.", + __func__, _phys, fault_owner->pid, vmf->address); + rcu_read_unlock(); + } + return 0; +ok_ret_allocated: + if (vmf->vma->vm_mm){ + rcu_read_lock(); + struct task_struct *fault_owner = vmf->vma->vm_mm->owner; + pr_info("[%s] Allocated phys: 0x%llx -> virt@PID(%d): 0x%lx.", + __func__, _phys, fault_owner->pid, vmf->address); + rcu_read_unlock(); + } + return 0; +} + +static const struct vm_operations_struct my_shmem_vmops = { + .fault = my_shmem_vmops_fault, +}; + +/* File Operations... + * ============================================================================ + */ +// static int my_shmem_fops_open(struct inode *inode, struct file *filp); + +static int my_shmem_fops_mmap(struct file *filp, struct vm_area_struct *vma) +{ + vma->vm_ops = &my_shmem_vmops; + return 0; +} + +static const struct file_operations my_shmem_fops = { + .owner = THIS_MODULE, + .mmap = my_shmem_fops_mmap, + .fsync = noop_fsync, +}; + +/* Module init & exit... + * ============================================================================ + */ +static int __init my_shmem_init(void) +{ + int reg_cdev_ret = register_chrdev(0, "my_shmem", &my_shmem_fops); + if (reg_cdev_ret != 0) + goto err_ret_cdev_reg_failed; + return 0; + +err_ret_cdev_reg_failed: + pr_err("[%s] Cannot register character dev -- error code %d.", + __func__, reg_cdev_ret); + return reg_cdev_ret; +} \ No newline at end of file