From eda46af01a51ffcc7fcf70366072f5d42e600fcc Mon Sep 17 00:00:00 2001 From: "Troy D. Hanson" Date: Thu, 5 Mar 2015 09:24:51 -0500 Subject: [PATCH] nopage is obsolete in vm_operations_struct, saving --- .gitignore | 3 ++ 205.fault/Makefile | 14 +++++++ 205.fault/README.md | 47 +++++++++++++++++++++++ 205.fault/build.sh | 10 +++++ 205.fault/kex.c | 93 +++++++++++++++++++++++++++++++++++++++++++++ 205.fault/rig.c | 48 +++++++++++++++++++++++ README.md | 6 ++- 7 files changed, 220 insertions(+), 1 deletion(-) create mode 100644 205.fault/Makefile create mode 100644 205.fault/README.md create mode 100755 205.fault/build.sh create mode 100644 205.fault/kex.c create mode 100644 205.fault/rig.c diff --git a/.gitignore b/.gitignore index edf6645..74dd063 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,6 @@ *.i*86 *.x86_64 *.hex + +# editor +*.swp diff --git a/205.fault/Makefile b/205.fault/Makefile new file mode 100644 index 0000000..a18d812 --- /dev/null +++ b/205.fault/Makefile @@ -0,0 +1,14 @@ +# invoke as +# +# make -C /path/to/kernel/source SUBDIRS=$PWD modules +# +# e.g., +# make -C /lib/modules/3.13.0-24-generic/build/ SUBDIRS=$PWD modules +# + +obj-m := kex.o + +rig: rig.c + +clean: + rm -f rig diff --git a/205.fault/README.md b/205.fault/README.md new file mode 100644 index 0000000..70d7bb7 --- /dev/null +++ b/205.fault/README.md @@ -0,0 +1,47 @@ +Pagefault +vma ops + +This kex module implements mmap and includes a test rig to exercise it. +When the test rig invokes mmap on the device, kex uses alloc_page +to get as many pages as the rig requested. It uses vm_insert_page on +each page to map it into rig's address space. These pages, while +physically disjoint, appear as a single contiguous virtual memory area +(VMA) inside the rig address space. The VMA is visible using pmap: + +``` + % ./build.sh + % sudo insmod kex.ko + % cat /proc/devices | grep kex +250 kex + % sudo mknod dev c 250 0 + % sudo chmod a+rw dev + % ./rig dev 1 +pid: 10195 +press a key to exercise memory write +``` + +Leave the rig waiting. In another terminal run pmap. See the dev VMA: + +``` + % pmap -x 10195 +Address Kbytes RSS Dirty Mode Mapping +00007fd0125b6000 4 4 0 rw-s- dev +``` + +It's 4kb because rig asked for one page (the final argument), which is 4kb. +Now we can ask rig to write to this memory. In the original terminal, press +enter. Then re-run pmap in the second terminal: + +``` +Address Kbytes RSS Dirty Mode Mapping +00007fd0125b6000 4 4 4 rw-s- dev +``` + +Notice that the Dirty column now shows the mapped page is Dirty. (TODO: is +this an MMU flag set on write to the page?). Press enter to terminate rig. + +Clean up: + + % rm dev + % sudo rmmod kex + % ./build.sh clean diff --git a/205.fault/build.sh b/205.fault/build.sh new file mode 100755 index 0000000..5f23c85 --- /dev/null +++ b/205.fault/build.sh @@ -0,0 +1,10 @@ +#!/bin/bash +KERNELHEADERS=/lib/modules/$(uname -r)/build/ +make -C ${KERNELHEADERS} SUBDIRS=$PWD $1 + +if [ "$1" == "clean" ] +then + make clean +else + make rig +fi diff --git a/205.fault/kex.c b/205.fault/kex.c new file mode 100644 index 0000000..a9778f3 --- /dev/null +++ b/205.fault/kex.c @@ -0,0 +1,93 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +/* module information */ +MODULE_AUTHOR("Troy D. Hanson"); +MODULE_DESCRIPTION("Example of character device"); +MODULE_LICENSE("Dual BSD/GPL"); + +#define NUM_MINORS 1 + +DEFINE_MUTEX(mutex); + +struct chardev_t { + dev_t dev; /* has major and minor bits */ + struct cdev cdev; /* has our ops, owner, etc */ +} c; + +static +struct page *fault(struct vm_area_struct *vma, unsigned long addr, int *type) { + struct page *page=NULL; + //get_page(); + if (type) *type=VM_FAULT_MINOR; + return page; +} + +/* ops for VMA open, close and fault. See Linux Device Drivers, 3rd ed, p427. */ +static struct vm_operations_struct vm_ops = { + .nopage = fault, /* page fault handler */ +}; + +int _mmap(struct file *f, struct vm_area_struct *vma) { + unsigned long pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; + int rc=-ENODEV; + printk(KERN_DEBUG "vma->vm_end %lu vm_start %lu len %lu pages %lu vm_pgoff %lu\n", + vma->vm_end, vma->vm_start, vma->vm_end - vma->vm_start, pages, vma->vm_pgoff); + + if (0) goto done; + vma->vm_ops = &vm_ops; + vma->vm_private_data = (void*)0xa1fa1fa; /* could store private data here */ + + rc = 0; + + done: + return rc; +} + +struct file_operations ops = { + .mmap = _mmap +}; + +int __init chardev_init(void) { + int rc; + + /* ask for a dynamic major */ + rc = alloc_chrdev_region(&c.dev, 0, NUM_MINORS, "kex"); + if (rc) { + rc = -ENODEV; + goto done; + } + + /* init the struct cdev */ + cdev_init(&c.cdev, &ops); + c.cdev.owner = THIS_MODULE; + + /* make device live */ + rc = cdev_add(&c.cdev, c.dev, NUM_MINORS); + if (rc) { + rc = -ENODEV; + printk(KERN_WARNING "cdev_add: can't add device\n"); + unregister_chrdev_region(c.dev, NUM_MINORS); + cdev_del(&c.cdev); + goto done; + } + + rc = 0; + + done: + return rc; +} + +void __exit chardev_cleanup(void) { + cdev_del(&c.cdev); + unregister_chrdev_region(c.dev, NUM_MINORS); +} + +module_init(chardev_init); +module_exit(chardev_cleanup); diff --git a/205.fault/rig.c b/205.fault/rig.c new file mode 100644 index 0000000..4bdad4b --- /dev/null +++ b/205.fault/rig.c @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +int main(int argc, char * argv[]) { + char *file = (argc > 1) ? argv[1] : "dev"; + int npages = (argc > 2) ? atoi(argv[2]) : 1; + int fd,rc=-1; + char *buf, *b, unused; + size_t len = 4096 * npages; // FIXME getpagesz + + fprintf(stderr,"pid: %u\n", (int)getpid()); + + if ( (fd = open(file, O_RDWR)) == -1) { + fprintf(stderr,"can't open %s: %s\n", file, strerror(errno)); + goto done; + } + + buf = mmap(0, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + if (buf == MAP_FAILED) { + fprintf(stderr, "failed to mmap %s: %s\n", file, strerror(errno)); + goto done; + } + + rc = 0; + + /* make the program block so we can examine it */ + + fprintf(stderr,"press a key to exercise memory write\n"); + read(STDIN_FILENO,&unused,sizeof(unused)); + for(b=buf; b < buf+len; b++) *b=1; + + fprintf(stderr,"press a key to terminate\n"); + read(STDIN_FILENO,&unused,sizeof(unused)); + + + done: + munmap(buf, len); + close(fd); + return rc; +} diff --git a/README.md b/README.md index 57cd604..20ef789 100644 --- a/README.md +++ b/README.md @@ -14,4 +14,8 @@ TODO * ops: poll, mmap * kernel linked list, kfifo * pci, usb - +* kgdb +* initramfs +* kvm +* net nic +* waitqueues