Citation: We know that every character device has a CDEV structure in the kernel that describes it, and one of the more important members of this structure is
Const struct file_operations *ops;
The function of this structure is to match the system call in the user program with the specific implementation function one by one in the driver. When invoking a system call to a character device file in a user program, you know which specific function to invoke for this character device, but the problem is that the following two function prototypes are shown:
// This is the prototype of the read system call ssize_t Read (intvoid *buf, size_t count);
// This is the function prototype ssize_t (*read) that corresponds to read in file_operations (structchar __user *, size_t, loff_t *);
As can be seen, the interface of the two functions is not the same, so from the system call to the specific implementation of the driver, the kernel must have done some hands and feet, the following we will be through the code to analyze from the system call to drive the implementation of the actual function of the process.
//This is a simple program to read the data from the file, we mainly through it to analyze the process of the read system call#include <stdio.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include<unistd.h>intMainintargcChar Const*argv[]) { intFD; inttemp; if(FD = open ("/dev/memdev0", o_rdwr)) = =-1) printf ("Open failed at line%d\n", __line__); Read (FD,&temp,sizeof(int)); printf ("Read failed at line%d\n", __line__); printf ("buffer is%d\n", temp); Close (FD); return 0;}
Compile the above code, note that you must use static compilation, otherwise you will lose important information in later disassembly.
Then disassembly, import a dump file below is the assembly code corresponding to the Read function
sizeof (int)); 8268: e24b300c Sub R3, FP, # 0xc 826c: e51b0008 Ldr r0, [FP, #-8] 8270: e1a01003 mov R1, R3 8274: e3a02004 mov r2, #4 0x4 8278: eb0028e8 bl 12620 <__libc_read>
Start is the parameter, the last sentence to jump to the __libc_read label, continue to follow
00012620<__libc_read>:12620: e51fc028 ldr IP, [PC, #- +];12600 <__libc_close+0x70> 12624: e79fc00c ldr IP, [PC, IP]12628: e33c0000 TEQ IP, #0 ;0x01262C:1a000006 bne 1264c <__libc_read+0x2c>12630: e1a0c007movIP, R712634: e3a07003movR7, #3 ;0x3 12638: ef000000 svc 0x00000000 1263C:e1a0700cmovR7, IP12640: E3700a01 cmn R0, #4096 ;0x1000 12644: 312fff1e bxcc LR12648: Ea0008b4 b14920<__syscall_error> 1264C:e92d408fPush{r0, r1, R2, R3, R7, LR}12650: eb0003b9 bl 1353c <__libc_enable_asynccancel>12654: e1a0c000movIP, R012658: e8bd000fPop{r0, r1, R2, R3} 1265 c:e3a07003 mov r7, #3; 0x3 12660:ef000000 svc 0x0000000012664: e1a07000movR7, R012668: e1a0000cmovr0, IP 1266C:eb000396 bl 134cc <__libc_disable_asynccancel>12670: e1a00007movR0, R712674: e8bd4080Pop{R7, LR}12678: E3700a01 cmn R0, #4096 ;0x10001267C:312fff1e bxcc LR12680: Ea0008a6 b14920<__syscall_error>12684: e1a00000NOP(movr0,r0)12688: e1a00000NOP(movr0,r0) 1268C:e1a00000NOP(movR0,R0)
A lot of code, but only two important lines, has been highlighted in red, the specific thing is to put 3 into the R7 register, and then through the SVC instructions to the PC pointer from a fixed entrance to the kernel space, after the kernel according to the number in the R7, check the table after the corresponding system call. In the linux2.6.39 version of the kernel, the table is located in the Calls.s file
0 */call (sys_restart_syscall )call(sys_exit )call (sys_fork_wrapper) call (sys_read) Call (sys_write)
Read in user space is actually called the kernel space in the Sys_read function, the implementation code of the function is as follows
Syscall_define3 (read, unsigned int , FD, __user * 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, Count, &pos); File_pos_write (file, POS); Fput_light (file, fput_needed); return ret;}
Analysis: We know that none of the open files have a file structure in the kernel to maintain, this calls fget_light through the Read function provided by the FD to get the file structure, and then called the Vfs_read function
ssize_t Vfs_read (structFile *file,Char__user *buf, size_t count, loff_t *POS) {ssize_t ret; if(! (File->f_mode &fmode_read)) return-EBADF; if(!file->f_op | | (!file->f_op->read &&!file->f_op->aio_read)) return-EINVAL; if(Unlikely (!Access_ok (Verify_write, buf, Count))) return-Efault; RET=Rw_verify_area (READ, file, POS, count); if(Ret >=0) {Count=ret; if(file->f_op->Read) ret = file->f_op->read (file, buf, Count, POS); Elseret=do_sync_read (file, buf, Count, POS); if(Ret >0) {fsnotify_access (file); Add_rchar (current, ret); } INC_SYSCR (current); } returnret;}
Again, the most important code has been highlighted, which is the most important sentence of the whole process, which calls the member function f_op->read in file. at the time of the driver initialization, the file_operations struct is assigned to the member F_op of the device file, so the specific implementation function in the final driver is dropped: Xxx_read. In fact, the red words I can not find the kernel code to prove that, but the logic is this, and as a novice in the learning-driven period do not overdo to see the kernel code, not worth the candle. But if the great God can find the relevant code, thank you!
If you have any questions or errors, you are welcome to discuss! Reprint please specify the source!
The specific implementation of character device driver from system call to driver in user program