The Nineth day of the 10-day learning Linux kernel---Add code to the kernel

Source: Internet
Author: User

10 days to learn the Nineth day of the Linux kernel---Add code to the kernel

Sleep a good sleep, very late, for a long time not so comfortable, today's task is not heavy, so the pressure is not big, oh, the weather is really cold, but the laboratory has air conditioning, I still like to stay here, there is a different feeling, after writing so many days, I do not understand the page gradually enlightened, And also made some friends, really very happy ah. Today will introduce you to add code to the kernel, take a look at it ~

First to familiarize yourself with the file system, through/dev can access the Linux device, we use the men device driver as an example to see how the random number is generated, the source code on the DIRVERS/CHAR/MEM.C can be viewed

Static intMemory_open (structInode * Inode * inode,structFile *Filp) {    Switch(Iminor (inode)) {//switch Statement initializes the driver's data structure based on the device number Case 1:    ...         Case 8: Filp->f_op = &Random_fops;  Break;  Case 9: Filp->f_op = &Urandom_fops;  Break;

So what are the Filps and FOP of the above procedure? In fact, FILP is just a pointer to a file structure, and FOP is a file_operations structure pointer, the kernel uses the File_operations structure to determine the function to invoke when manipulating the file, the File_ The operations structure is used for random device driven parts, and the code can be viewed on include/linux/fs.h:

struct file {    struct  list_head f_list;    struct dentry *f_dentry;     struct vfsmount *f_vfsmnt;     struct file_operations *f_op;    atomic_t F_count;     int f_flags,     ..... struct address_space *f_mapping;};

The functions implemented by the Q driver must conform to the function prototypes listed in the file_operations structure, and the code can be viewed on DIRVERS/CHAR/RANDOM.C:

  {. read  = Random_read,. Write  = Random_write,. Poll  = Random_poll  , the//poll operation allows an operation to see if the operation is blocked. IOCTL  = Random_ioctl,}; The operation provided by the random device has the above  struct  file_operations urandom_fops = {. read  = Random_read,. Write  = Random_w Rite,. IOCTL  = Random_ioctl,}; The operation provided by the URANDOM device has the above   

If the device driver is running inside the kernel space, but the buffer is in the user space, how can we secure access to the data in buf, the secret between the data in the user space and the kernel space below, the Copy_to_user () and the Copy_from_user that Linux provides () allows the driver to pass data on the kernel space and user space, in Read_random (), through the Extract_entropy () function, the following code can be viewed on DIRVERS/CHAR/RANDOM.C ( The following code does not finish, the main is not very understand, hope the great God advice)

static ssize_t extract_entropy (struct entract_syore *r,void *buf,size_t nbytes,int  flags) {... {    static ssize_t extract_entropy (struct entropy_store *r,void *buf,size_t nbytes,int  flags) {...

Kernel space and user space programs may need to use random numbers that have already been obtained, and kernel space programs can avoid the extra overhead of function copyto_user () by not setting a flag bit. In addition to adding code to the kernel through device drivers, there are other ways in which user space can be used to access kernel service programs and system hardware through system transfers, and there is no explanation for this.

Let's look at how to write the source code , when we go to write a complex device driver, we might want to output some of the drivers defined in the match, so that the kernel other modules to use, which is often used in low-level drivers, In order to build more advanced drivers based on these basic functions, in the Linux2.6 kernel, code monkey can output symbols with the following two macros, which are viewed in include/linux/module.h:

#define Export_symbol (sym)    "")#define EXPORT_SYMBOL_GPL (sym)    "  _GPL")

So far, the device drivers we've introduced are active, or read and write to the device's data, so what happens when it does more than that? In Linux, the typical way for device drivers to solve these problems is to use the IOCTL. The IOCTL is a function of the device driver to manage the I/O channel of the device. The so-called management of the I/O channel is to control some features of the device, such as the transmission of the serial port baud rate, the speed of the motor and so on.

The number of calls is as follows:

int IOCTL (int FD, ind cmd, ...) ;

Where FD is the user program to open the device using the Open function to return the file identifier, CMD is the User Program Control command of the device, as for the following ellipsis, which is a number of supplementary parameters, generally up to one, with or without the meaning of the CMD is related. The IOCTL function is an attribute component in the file structure, meaning that if your driver provides support for the IOCTL, the user can use the IOCTL function in the user program to control the I/O channel of the device.

IOCTL command number:

Dir

Represents the direction of data transmission, accounting for 2 bits, can be _ioc_none (no data transfer, 0U), _ioc_write (write data to device, 1U) or _ioc_read (read data from device, 2U) or their logic or combination, of course only _ioc_write and _IOC_ Read is logical or meaningful.

Type

describes the type of IOCTL command, 8 bits. Each device or system can specify its own type number, which is used by the IOCTL to represent the device or driver to which the IOCTL command belongs. It is generally denoted by ASCII code characters, such as ' a '.

  Nr:

the IOCTL command sequence number, usually 8 bits. For a specified device driver, a sequential encoding of its IOCTL commands can be made, typically starting from zero, which is the ordinal of the IOCTL command.

  Size

The parameter size of the IOCTL command, typically 14 bits. This data member of the IOCTL command number is not mandatory and you can not use it, but we recommend that you specify this data member, which allows us to check the size of the user's spatial data to avoid incorrect data manipulation, or to implement an old version of the IOCTL command.

IOCTL return value:

The return value of the IOCTL function is a value of type integer, and if the command executes successfully, the IOCTL returns zero, and if an error occurs, the IOCTL function should return a negative value. This negative value is fed back to the user-space program that called the IOCTL as a errno. Refer to <linux/errno.h> and <asm/errno.h> header files for specific meanings of return values.

IOCTL parameters:

First of all to show that this parameter is a user-space program passed over, so this pointer to the address is the user space address, in Linux, the user space address is a virtual address, in the kernel space is not directly used it. To resolve data that uses user-space addresses in kernel space, the Linux kernel provides the following functions, which are used to access the data in the user space in the kernel space, defined in the <asm/uaccess.h> header file:

Long __must_check copy_to_user (void __user *to,constvoid * from  Longlong __must_check copy_from_user (void *to,const  void __user *fromlong N);

Copy_from_user and Copy_to_user are commonly used for complex or big data exchanges, and for simple data types such as int or char, the kernel provides a simple macro to implement this function:

#define get_user (x,ptr)#define put_user (x,ptr)//X is the simple data type address of the kernel space, and PTR is the user-space address pointer. 

  

How the cmd parameter is derived:

A cmd parameter is divided into 4 paragraphs, each paragraph has its special meaning, the cmd parameter in the user program driven by some macros based on the device type, serial number, direction of transmission, data size and other generated, this integer through the system call to the kernel driver, and then by the driver using decoding macros from this integer to get the type of device, The serial number, direction of delivery, data size, and so on, and then the corresponding operation through the switch{case} structure. Explain four parts, all in <asm-generic/ioctl.h> and ioctl-number.txt these two documents are described.

1) Magic number: said the more beautiful name is only a 0~0xff number, accounting for 8bit (_ioc_typebits). This number is used to differentiate between different drivers, like when the device number is applied, and the kernel has a document that gives some of the magic numbers that are recommended or used

2) Ordinal: Use this number to give your own command number, accounting for 8bit (_ioc_nrbits), my program starting from 1 to sort.

3) data transmission direction: accounted for 2bit (_ioc_dirbits). If a reference is involved, the kernel requires a description of the direction of the transmission, and the direction of transmission is described in terms of the application layer.

    • _ioc_none: A value of 0, no data transfer.
    • _ioc_read: The value is 1, which reads data from the device driver.
    • _ioc_write: A value of 2 to write data to the device driver.
    • _ioc_read|_ioc_write: Bidirectional data transfer.

4) Data size: related to architecture, Arm occupies 14bit (_ioc_sizebits), if the data is int, the value assigned by the kernel is sizeof (int).

How the IOCTL is implemented:

In the driver implementation of the IOCTL function in vivo, there is actually a switch{case} structure, each case corresponding to a command code, to make some corresponding operation. How to do this, this is every programmer's own thing, because the device is specific, it is impossible to say here, the key is how to organize the command code, because in the IOCTL command code is the only way to contact the user Program command and driver support.

The organization of the command code is somewhat fastidious, as we must make sure that the command and the device are one by one corresponding so that the correct command is not sent to the wrong device, or the wrong command is sent to the correct device, or the wrong command is sent to the wrong device. These mistakes can lead to unpredictable things, and when programmers find these strange things, it's very difficult to debug the program to find the wrong thing.

So defining a command code in the Linux kernel is this:

____________________________________

| Device Type | Serial number | Direction | data Size |

|----------|--------|------|--------|

|  8 bit | 8 bit bit| bit |8~14

|----------|--------|------|--------|

In this way, a command becomes an integer-like command code. However, the command code is very non-intuitive, so Linux kernel provides a number of macros, these macros can be generated according to the easy-to-understand string command code, or from the command code to get some user-understandable string to indicate the command corresponding device type, device serial number, data transmission direction and transmission size.

There is no direct access to the user-space address data in the kernel. Therefore, it is important to use the functions provided by the kernel to access the pointer data that is passed from the user space. It is important to emphasize again that in the kernel module or driver writing, we strongly recommend that you use the interface provided by the kernel to generate and manipulate the IOCTL command number, which gives the command number a specific meaning, makes our program more robust, and, on the other hand, improves the portability of the program.

Finally, we introduce the compilation and debugging after adding code, after adding the code in the kernel, we need to run, fix the error, we know that when read and write to the/proc file system, every node of it is linked to a kernel function. In the Linux2.6 kernel, in order for your device to be accessible, you first need to create a portal in the/proc file system, which can be implemented by Creat_proc_read_entry (), and the code is INCLUDE/LINUX/PROC_ View on Fs.h:

Static struct proc_dir_entry *create_proc_read_entry (constChar *name,    mode_t mode,  struct proc_dir_entry *base,    *read_proc,void * data)

*name is the node in the/proc file system, *base points to the target path of the SET proc file, if its value is NULL, indicates that the file is in the/proc directory, read the file can invoke *read_proc point to the function. Here is not more explanation, the whole is a very simple process.

 Summary

Today's focus is the IOTCL function, which there are many to the kernel to add the details of the code is not mentioned, mainly these are involved in too many operations, you need to look at the source code and more hands on the Linux operation to fully grasp, today wrote some also borrowed some Daniel's article, in short, a lot of harvest, The last few days, really is very happy, and everyone to share really very happy ~ ~

All rights reserved, reprint please specify reprint address: http://www.cnblogs.com/lihuidashen/p/4255826.html

10 days the nineth day of learning the Linux kernel---Add code to the kernel

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.