From 383a810799ceba58803953c79bd64334c63821a9 Mon Sep 17 00:00:00 2001 From: Vasiliy Ulyanov Date: Mon, 4 Mar 2013 09:37:35 +0400 Subject: [PATCH] Add buffer char device skeleton --- buffer/Kbuild | 4 + buffer/Makefile.am | 34 +++++++ buffer/buffer.c | 285 +++++++++++++++++++++++++++++++++++++++++++++++++++++ buffer/buffer.h | 9 ++ 4 files changed, 332 insertions(+) create mode 100644 buffer/Kbuild create mode 100644 buffer/Makefile.am create mode 100644 buffer/buffer.c create mode 100644 buffer/buffer.h diff --git a/buffer/Kbuild b/buffer/Kbuild new file mode 100644 index 0000000..34c249a --- /dev/null +++ b/buffer/Kbuild @@ -0,0 +1,4 @@ +EXTRA_CFLAGS := $(extra_cflags) + +obj-m := swap_buffer.o +swap_buffer-y := buffer.o diff --git a/buffer/Makefile.am b/buffer/Makefile.am new file mode 100644 index 0000000..4e45043 --- /dev/null +++ b/buffer/Makefile.am @@ -0,0 +1,34 @@ +if DEBUG +debug_opt = -D__DEBUG +endif + +if SPARSE +sparse_output = C=2 +endif + +board_opt = -DBOARD_@BOARD@ + +target_kernel_src = @KERNEL@ +target_arch = @ARCH@ +module_dir = $(realpath $(srcdir)) +module_name = swap_buffer +cross_compiler = $(subst gcc,,$(CC)) + +inlude_opt = -I$(top_srcdir)/src/modules/ksyms -I$(top_srcdir)/src/common -I$(top_srcdir)/src/profile +extra_cflags = "$(inlude_opt) -DEC_ARCH_$(ARCH) $(debug_opt) $(board_opt)" + +#bin_SCRIPTS = patchko.sh insmod.sh + +all-local: + cp $(top_srcdir)/src/modules/kprobe/Module.symvers $(module_dir) + $(MAKE) CROSS_COMPILE=$(cross_compiler) ARCH=$(target_arch) extra_cflags=$(extra_cflags) $(AM_MAKEFLAGS) -C $(target_kernel_src) $(sparse_output) M=$(module_dir) modules + + echo "generate data for version patching <$(OBJDUMP)><$(READELF)>" + $(top_srcdir)/src/modules/driver/patchko.sh -g $(module_dir)/$(module_name).ko $(OBJDUMP) $(READELF) + +clean-local: + $(MAKE) CROSS_COMPILE=$(cross_compiler) ARCH=$(target_arch) $(AM_MAKEFLAGS) -C $(target_kernel_src) M=$(module_dir) clean + +install-exec-local: + install -m 644 $(module_dir)/$(module_name).ko $(prefix) + install -m 644 $(module_dir)/$(module_name).ko.addr $(prefix) diff --git a/buffer/buffer.c b/buffer/buffer.c new file mode 100644 index 0000000..419dc47 --- /dev/null +++ b/buffer/buffer.c @@ -0,0 +1,285 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "buffer.h" + +#define BUF_DEBUG + +#ifdef BUF_DEBUG +#define DPRINTF(format, args...) \ + do { \ + char *f = strrchr(__FILE__, '/'); \ + printk("%s[%s:%u:%s]: " format "\n", BUF_DEVICE, f ? f + 1: __FILE__, \ + __LINE__, __FUNCTION__, ##args); \ + } while (0) +#else /* !BUF_DEBUG */ +#define DPRINTF(format, args...) +#endif /* BUF_DEBUG */ + +#define EPRINTF(format, args...) \ + do { \ + printk("%s: " format "\n", BUF_DEVICE, ##args); \ + } while (0) + +struct chunk { + struct list_head list; + unsigned long size; + void *payload; +}; + +struct buffer_device { + struct list_head free_chunks; + struct list_head used_chunks; + spinlock_t lock; + struct cdev cdev; + dev_t dev; + unsigned long size; + unsigned long chunk_size; + char *buf; +}; + +static int buf_open(struct inode *, struct file *); +static int buf_release(struct inode *, struct file *); +static int buf_mmap(struct file *, struct vm_area_struct *); +static ssize_t buf_read(struct file *, char __user *, size_t, loff_t *); +static ssize_t buf_write(struct file *, const char __user *, size_t, loff_t *); +static long buf_ioctl(struct file *, unsigned int, unsigned long); +static unsigned int buf_poll(struct file *, struct poll_table_struct *); +static ssize_t buf_splice_read(struct file *, loff_t *, + struct pipe_inode_info *, size_t, unsigned int); +static ssize_t buf_splice_write(struct pipe_inode_info *, struct file *, + loff_t *, size_t, unsigned int); + +static struct file_operations buf_fops = { + .owner = THIS_MODULE, + .open = buf_open, + .release = buf_release, + .mmap = buf_mmap, + .read = buf_read, + .write = buf_write, + .unlocked_ioctl = buf_ioctl, + .poll = buf_poll, + .splice_read = buf_splice_read, + .splice_write = buf_splice_write +}; + +static struct buffer_device bdevice = { + .free_chunks = LIST_HEAD_INIT(bdevice.free_chunks), + .used_chunks = LIST_HEAD_INIT(bdevice.used_chunks), + .lock = __SPIN_LOCK_UNLOCKED(bdevice.lock), + .dev = MKDEV(BUF_DEFAULT_MAJOR, BUF_DEFAULT_MAJOR), + .size = 0, + .chunk_size = 0, + .buf = NULL +}; + +/* --- chunks manipulation routines --- */ +static inline void *buf_get_free_chunk(void) +{ + if (!list_empty(&bdevice.free_chunks)) + return list_first_entry(&bdevice.free_chunks, struct chunk, list); + + return NULL; +} + +static inline void *buf_get_used_chunk(void) +{ + if (!list_empty(&bdevice.used_chunks)) + return list_first_entry(&bdevice.used_chunks, struct chunk, list); + + return NULL; +} + +static inline void buf_free_chunk(struct chunk *chunk) +{ + list_move_tail(&chunk->list, &bdevice.free_chunks); + chunk->size = 0; +} + +static inline void buf_use_chunk(struct chunk *chunk) +{ + list_move_tail(&chunk->list, &bdevice.used_chunks); + chunk->size = 0; +} + +static inline void buf_check_chunk_size(struct chunk *chunk, unsigned long size) +{ + return (bdevice.chunk_size - chunk->size <= size); +} + +static inline unsigned long buf_copy_to_chunk(struct chunk *chunk, + const char __user *buf, size_t length) +{ + return copy_from_user(chunk->payload, buf, length); +} + +static inline unsigned long buf_copy_from_chunk(struct chunk *chunk, + char __user *buf, size_t length) +{ + return copy_to_user(buf, chunk->payload, length); +} + +/* --- buffer manipulation routines */ +static inline void *buf_get_chunk(int i) +{ + return (((struct chunk *)bdevice.buf) + i); //TODO FIXME!!!! +} + +static int buf_init(unsigned long size, unsigned long chunk_size) +{ + int retval = 0; + + INIT_LIST_HEAD(&bdevice.free_chunks); + INIT_LIST_HEAD(&bdevice.used_chunks); + bdevice.size = 0; + bdevice.chunk_size = 0; + + bdevice.buf = vmalloc(size); + if (!bdevice.buf) { + retval = -ENOMEM; + goto out; + } + + /*for (;;) { //TODO + struct chunk *chunk = buf_get_chunk(i); //TODO + list_add_tail(&chunk->list, &bdevice.free_chunks); + }*/ + +out: + return retval; +} + +static int buf_free(void) +{ + INIT_LIST_HEAD(&bdevice.free_chunks); + INIT_LIST_HEAD(&bdevice.used_chunks); + bdevice.size = 0; + bdevice.chunk_size = 0; + + if (bdevice.buf) + vfree(bdevice.buf); + bdevice.buf = NULL; + + return 0; +} + +/* --- char dev file operations --- */ +static int buf_open(struct inode *inode, struct file *filp) +{ + /*struct buffer_device *dev = NULL; //TODO + + if (filp->f_flags & O_WRONLY) { + } + + if ((filp->f_flags & O_ACCMODE) == O_WRONLY) { + } + + if (!atomic_dec_and_test()) { + //TODO + return -EBUSY; + } + + filp->private_data = dev;*/ + DPRINTF(""); + return 0; +} + +static int buf_release(struct inode *inode, struct file *filp) +{ + DPRINTF(""); + return 0; +} + +static int buf_mmap(struct file *filp, struct vm_area_struct *vma) +{ + EPRINTF("mmap() operation is not supported"); + return -ENODEV; +} + +static ssize_t buf_read(struct file *filp, char __user *buf, size_t length, + loff_t *offset) +{ + DPRINTF(""); + return 0; +} + +static ssize_t buf_write(struct file *filp, const char __user *buf, + size_t length, loff_t *offset) +{ + DPRINTF(""); + return length; +} + +static long buf_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + DPRINTF(""); + return 0; +} + +static unsigned int buf_poll(struct file *filp, struct poll_table_struct *table) +{ + DPRINTF(""); + return 0; +} + +static ssize_t buf_splice_read(struct file *filp, loff_t *offset, + struct pipe_inode_info *pipe, size_t length, unsigned int flags) +{ + DPRINTF(""); + return 0; +} + +static ssize_t buf_splice_write(struct pipe_inode_info *pipe, struct file *filp, + loff_t *offset, size_t length, unsigned int flags) +{ + DPRINTF(""); + return 0; +} + +/* --- module init/exit routines --- */ +static int __init buf_module_init(void) +{ + int retval = 0; + + bdevice.dev = MKDEV(BUF_DEFAULT_MAJOR, BUF_DEFAULT_MINOR); + + retval = alloc_chrdev_region(&bdevice.dev, BUF_DEFAULT_MINOR, + BUF_NUM_DEVICES, BUF_DEVICE); + if (retval < 0) { + EPRINTF("(%d) - alloc_chrdev_region", retval); + goto out; + } + + cdev_init(&bdevice.cdev, &buf_fops); + bdevice.cdev.owner = THIS_MODULE; + bdevice.cdev.ops = &buf_fops; + + retval = cdev_add(&bdevice.cdev, bdevice.dev, BUF_NUM_DEVICES); + if (retval < 0) { + EPRINTF("(%d) - cdev_add", retval); + goto out; + } + +out: + DPRINTF("major = %d", MAJOR(bdevice.dev)); + return retval; +} + +static void __exit buf_module_exit(void) +{ + DPRINTF("major = %d", MAJOR(bdevice.dev)); + cdev_del(&bdevice.cdev); + unregister_chrdev_region(bdevice.dev, BUF_NUM_DEVICES); +} + +module_init(buf_module_init); +module_exit(buf_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SWAP buffer module"); diff --git a/buffer/buffer.h b/buffer/buffer.h new file mode 100644 index 0000000..8285777 --- /dev/null +++ b/buffer/buffer.h @@ -0,0 +1,9 @@ +#ifndef BUFFER_H +#define BUFFER_H + +#define BUF_DEFAULT_MAJOR 0 +#define BUF_DEFAULT_MINOR 0 +#define BUF_NUM_DEVICES 1 +#define BUF_DEVICE "swap_buffer" + +#endif /* BUFFER_H */ -- 2.7.4