printk
(which serves as a replacement for printf
) and kmalloc
(works like malloc
), you are mostly left alone with the hardware. In addition, after unloading the module, it should be completely cleaned after itself. There is no garbage collection. apt-get install build-essential linux-headers-`uname -r`
mkdir ~/src/lkm_example cd ~/src/lkm_example
lkm_example.c
following content: #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> MODULE_LICENSE(“GPL”); MODULE_AUTHOR(“Robert W. Oliver II”); MODULE_DESCRIPTION(“A simple example Linux module.”); MODULE_VERSION(“0.01”); static int __init lkm_example_init(void) { printk(KERN_INFO “Hello, World!\n”); return 0; } static void __exit lkm_example_exit(void) { printk(KERN_INFO “Goodbye, World!\n”); } module_init(lkm_example_init); module_exit(lkm_example_exit);
include
lists the header files needed for developing the Linux kernel.MODULE_LICENSE
can set different values ​​in MODULE_LICENSE
, depending on the license of the module. To view the full list, run: grep “MODULE_LICENSE” -B 27 /usr/src/linux-headers-`uname -r`/include/linux/module.h
init
(load) and exit
(unload) as static functions that return integers.printk
instead of printf
. Also the printk
parameters are different from printf
. For example, the KERN_INFO flag for declaring journaling priority for a specific row is specified without a comma. The kernel deals with these things inside the printk
function to save stack memory.module_init
and module_exit
and specify the load and unload functions. This allows arbitrary naming of functions.make
very picky about spaces and tabs, so make sure you use tabs instead of spaces where appropriate. obj-m += lkm_example.o all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
make
, it should successfully compile our module. The result will be the lkm_example.ko
file. If any errors pop up, check that the quotes in the source code are set correctly, and not randomly in UTF-8. sudo insmod lkm_example.ko
printk
function does not output to the console, but to the kernel log. To view you need to run: sudo dmesg
lsmod | grep “lkm_example”
sudo rmmod lkm_example
test: sudo dmesg -C sudo insmod lkm_example.ko sudo rmmod lkm_example.ko dmesg
make test
/dev/zero
, /dev/null
and the like interact with zero and null devices that return the expected values. #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <asm/uaccess.h> MODULE_LICENSE(“GPL”); MODULE_AUTHOR(“Robert W. Oliver II”); MODULE_DESCRIPTION(“A simple example Linux module.”); MODULE_VERSION(“0.01”); #define DEVICE_NAME “lkm_example” #define EXAMPLE_MSG “Hello, World!\n” #define MSG_BUFFER_LEN 15 /* Prototypes for device functions */ static int device_open(struct inode *, struct file *); static int device_release(struct inode *, struct file *); static ssize_t device_read(struct file *, char *, size_t, loff_t *); static ssize_t device_write(struct file *, const char *, size_t, loff_t *); static int major_num; static int device_open_count = 0; static char msg_buffer[MSG_BUFFER_LEN]; static char *msg_ptr; /* This structure points to all of the device functions */ static struct file_operations file_ops = { .read = device_read, .write = device_write, .open = device_open, .release = device_release }; /* When a process reads from our device, this gets called. */ static ssize_t device_read(struct file *flip, char *buffer, size_t len, loff_t *offset) { int bytes_read = 0; /* If we're at the end, loop back to the beginning */ if (*msg_ptr == 0) { msg_ptr = msg_buffer; } /* Put data in the buffer */ while (len && *msg_ptr) { /* Buffer is in user data, not kernel, so you can't just reference * with a pointer. The function put_user handles this for us */ put_user(*(msg_ptr++), buffer++); len--; bytes_read++; } return bytes_read; } /* Called when a process tries to write to our device */ static ssize_t device_write(struct file *flip, const char *buffer, size_t len, loff_t *offset) { /* This is a read-only device */ printk(KERN_ALERT “This operation is not supported.\n”); return -EINVAL; } /* Called when a process opens our device */ static int device_open(struct inode *inode, struct file *file) { /* If device is open, return busy */ if (device_open_count) { return -EBUSY; } device_open_count++; try_module_get(THIS_MODULE); return 0; } /* Called when a process closes our device */ static int device_release(struct inode *inode, struct file *file) { /* Decrement the open counter and usage count. Without this, the module would not unload. */ device_open_count--; module_put(THIS_MODULE); return 0; } static int __init lkm_example_init(void) { /* Fill buffer with our message */ strncpy(msg_buffer, EXAMPLE_MSG, MSG_BUFFER_LEN); /* Set the msg_ptr to the buffer */ msg_ptr = msg_buffer; /* Try to register character device */ major_num = register_chrdev(0, “lkm_example”, &file_ops); if (major_num < 0) { printk(KERN_ALERT “Could not register device: %d\n”, major_num); return major_num; } else { printk(KERN_INFO “lkm_example module loaded with device major number %d\n”, major_num); return 0; } } static void __exit lkm_example_exit(void) { /* Remember — we have to clean up after ourselves. Unregister the character device. */ unregister_chrdev(major_num, DEVICE_NAME); printk(KERN_INFO “Goodbye, World!\n”); } /* Register module functions */ module_init(lkm_example_init); module_exit(lkm_example_exit);
obj-m += lkm_example.o all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean test: # We put a — in front of the rmmod command to tell make to ignore # an error in case the module isn't loaded. -sudo rmmod lkm_example # Clear the kernel log without echo sudo dmesg -C # Insert the module sudo insmod lkm_example.ko # Display the kernel log dmesg
make test
you will see the output of the highest device number. In our example, it is automatically assigned by the kernel. However, this number is needed to create a new device.make test
and use it to create a device file so that you can communicate with our kernel module from user space. sudo mknod /dev/lkm_example c MAJOR 0
make test
or dmesg
)c
parameter in the mknod
command tells mknod that we need to create a character device file. cat /dev/lkm_example
dd
: dd if=/dev/lkm_example of=test bs=14 count=100
sudo rm /dev/lkm_example sudo rmmod lkm_example
Source: https://habr.com/ru/post/343828/
All Articles