Linux application access character device driver detailed process parsing

Source: Internet
Author: User

Let's start with a well-written kernel driver module to experience the following character device drivers

You can temporarily ignore the following code implementation!

Memdev.c

#include <linux/module.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/cdev.h > #include <asm/uaccess.h>int dev1_registers[5];int dev2_registers[5];struct cdev Cdev; dev_t devno;/* File Open function */int mem_open (struct inode *inode, struct file *filp) {/* Get secondary device number */int num = MINOR (inode-&gt        ; i_rdev);    if (num==0) filp->private_data = dev1_registers;    else if (num = = 1) filp->private_data = dev2_registers;  else Return-enodev; Invalid secondary device number return 0; }/* file Release function */int mem_release (struct inode *inode, struct file *filp) {return 0;}   /* Read function */static ssize_t mem_read (struct file *filp, char __user *buf, size_t size, loff_t *ppos) {unsigned long p = *ppos;  unsigned int count = size;  int ret = 0; int *register_addr = filp->private_data;  /* Obtain the device's register base address */* To determine if the read position is valid */if (P >= 5*sizeof (int)) return 0;  if (Count > 5*sizeof (int)-P) Count = 5*sizeof (int)-p; /* Read data to User space */if (Copy_to_user (buf, RegiSter_addr+p, Count)) {ret =-efault;    } else {*ppos + = count;  ret = count; } return ret;}  /* Write function */static ssize_t mem_write (struct file *filp, const char __user *buf, size_t size, loff_t *ppos) {unsigned long p =  *ppos;  unsigned int count = size;  int ret = 0; int *register_addr = filp->private_data;  /* Get the device's register address */* parse and get valid write length */if (P >= 5*sizeof (int)) return 0;      if (Count > 5*sizeof (int)-P) Count = 5*sizeof (int)-p;  /* Write data from user space */if (Copy_from_user (Register_addr + p, buf, count)) ret =-efault;    else {*ppos + = count;  ret = count; } return ret;}    /* Seek file Locator function */static loff_t mem_llseek (struct file *filp, loff_t offset, int whence) {loff_t newpos;        Switch (whence) {case seek_set:newpos = offset;      Break        Case Seek_cur:newpos = Filp->f_pos + offset;      Break        Case seek_end:newpos = 5*sizeof (int)-1 + offset;      Break    Default:return-einval; } if ((newpos<0) | |    (newpos>5*sizeof (int)))        Return-einval;    Filp->f_pos = Newpos; return newpos;}  /* File operation struct */static const struct file_operations mem_fops ={. Llseek = Mem_llseek,. Read = Mem_read,. Write = Mem_write, . open = Mem_open,. Release = mem_release,};/* device driver module load function */static int memdev_init (void) {/* Initialize CDEV structure */Cdev_init (&AMP;CD    EV, &AMP;MEM_FOPS);  /* Register character device */alloc_chrdev_region (&AMP;DEVNO, 0, 2, "Memdev"); Cdev_add (&cdev, Devno, 2);}   /* Module unload function */static void memdev_exit (void) {Cdev_del (&cdev); /* Unregister device */Unregister_chrdev_region (DEVNO, 2); /* Release device number */}module_license ("GPL"); Module_init (Memdev_init); Module_exit (Memdev_exit);


1. Compile/install drivers: in Linux systems, drivers are usually encoded using the kernel module's program structure, so compiling and installing a driver is essentially compiling/installing a kernel module.

2. Create a Device file


How the application accesses the device driver interface through the character device files, that is, the character device driver access to the big secret , the following is a small example of the application: ( How the application is to find the device driver portal through the system call and then let the device driver work )

Read-mem.c

#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>int main () { int FD = 0;int DST = 0;/* to open the device file */FD = open ("/dev/memdev0", O_RDWR);/* Write Data */read (FD, &DST, sizeof (int));p rintf ("DST is% D\n ", DST);/* close Device */close (FD); return 0;}


The above files are statically compiled under Linux (taking into account that some libraries previously ported on the board have not yet been added) to generate the Read-mem target file, then disassemble and import the disassembled files into the dump in the current directory.

Vim Open dump file, search/main can see this section of assembly code


You can see that the read () function in the application actually calls the __libc_read function and then continues to search for the __libc_read function in dump


Here the red arrow pointing to the two lines is the more important two lines, the 3 passed to R7, and then use the SVC system call instruction, the PC pointer from the user space into the kernel space (through a fixed entrance), the second step will take the R7 register value 3, Then check a table based on this value to determine which system call to invoke (that is, the kernel code for 3 system calls). This opens the kernel source project and opens a file:

Entry-comon. S (under/arch/arm/kernel directory)


The kernel code section above VECTOR_SWI is the fixed entry, the second arrow part is the second step above, the third step in this part of the code here is not cut so much (that is, according to the number table)

Enable_irqget_thread_info tskadrtbl, <span style= "color: #ff0000;" >sys_call_table</span>@ Load syscall Table pointer
Search sys_call_table, see what this watch is?


View calls. S file


System is to enter the kernel space through a fixed entry, then take out the system call number, use the number to find the above table, and then remove the kernel in the above user space of the Read implementation function! ( This is an analysis of how user-space read is the process of finding the sys_read of the kernel space .)

Here's a look at the kernel code implementation of Sys_read: In the read_write.c file in the/fs directory

Syscall_define3 (read, unsigned int, FD, char __user *, buf, size_t, count) {struct file *file;ssize_t ret =-ebadf;int fput _needed;file = Fget_light (fd, &fput_needed); if (file) {loff_t pos = file_pos_read (file); ret = vfs_read (file, buf, Coun T, &pos); File_pos_write (file, POS); fput_light (file, fput_needed);} return ret;}
Each open file will have a struct file corresponding to it! From the function above, we can see that the corresponding struct file can be found by the incoming FD parameter.

The Vfs_read () function is then called through file. Let's look at the internal implementation of the function.



Red Arrow Part! F_op part is the driver inside the custom structure, through the F_OP structure to find the device reading Method!

That's it:

/* File operation struct */static const struct file_operations mem_fops ={  . Llseek = Mem_llseek,  . Read = Mem_read,  . Write = M Em_write,  . Open = Mem_open,  . Release = Mem_release,};




Linux application access character device driver detailed process parsing

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.