[Linux driver] Chapter 1 kernel data types

Source: Internet
Author: User

I. kernel data types

It can be divided into the Standard C language type, the determined size type, and the type of the specific kernel object.

1) Standard C language type

When "A 2-byte padding character" or "representing something with a 4-byte string" is required, the standard C language type cannot be used, because in different architectures, the data types in C Language occupy different sizes. For example, long occupies different bytes in 32-bit and 64-bit systems.

In some architectures, the size of C data types in kernel space and user space may be different. The kdatasize module displays the space occupied by the C data type in the kernel space of the current module.

Although the address is a pointer, you can use an unsigned integer to better manage the memory. The kernel regards the physical memory as a giant array, and the memory address is the index of the array. We can easily value the pointer, but when we directly process the memory address, we almost never value it in this way. This value is avoided by using an integer type, thus avoiding bugs. Therefore, use at least on all platforms currently supported by Linux,Pointer and long integer are always the same sizeThe fact,The memory address in the kernel is often
Unsigned long
.

2) determine the size type

When you need to know the size of your defined data, you can use the following data types provided by the kernel (all data declarations are in <ASM/types. h>, included in <Linux/types. h> ):

U8;/* unsigned byte (8 bits )*/

2010;/* unsigned word (16 bits )*/

U32;/* unsigned 32-bit value */

U64;/* unsigned 64-bit value */
/* Though fewSigned typeBut if needed, use s instead of u */

If oneUser spaceThe program needs to use these types. You can add a Double underline before the symbol: _ u8 and other types are independent of _ KERNEL.

These types are Linux-specific and they prevent porting software to other UNIX machines.

The new compiler system supports c99-standard types, such as uint8_t and uint32_t. Considering portability, using these types is better than using specific Linux variants.

3) interface-specific type (_ T type)

The most common data types in the kernel are declared by their own typedef, blocking any portability issues. "Interface-specific" is a data type defined by a database to provide interfaces for a specific data structure. Many _ T types are defined in <Linux/types. h>.

Note: Recently, few new interface-specific types have been defined. Many kernel developers no longer like to use typedef statements. They prefer to see the real type information directly used in the code. Many old interface-specific types are retained in the kernel and they will not disappear soon.

Even if no specific interface type is defined, it should always be the same and appropriate data type as other parts of the kernel. As long as the driver uses this "Custom" type function, but does not comply with the conventions, the compiler will issue a warning, then use the-wall compiler option and be careful to remove all warnings, you can be sure that the code is portable.

The main problem with the _ T type is that it is often difficult to select the correct printk or printf format when printing them. The best way to print interface-specific data is to forcibly convert it to the maximum possible type (often long or unsigned long) and print it in the corresponding format.

2. Other portability Problems

A common porting rule is: Avoid usingExplicit Constant ValueTo usePreprocessing macroParameterization of constant values.

1) Time Interval

During the processing interval, do not assume the number of jiffies per second, not every LINUX Platform runs at a fixed speed. when calculating the time interval, use Hz (the number of timer interruptions per second) to calibrate your time. By default, the Hz value of S3C2410 is 200.

2) page size

When using memory, remember that a memory page is page_size byte, not 4 kb. The related macro definitions are page_size and page_shit (including the number of digits that shift an address to obtain its page number), which are defined in <ASM/page. h>. If the user space program needs this information, you can use the getpagesize library function.

If a driver needs to store data in 16 KB, get_order is a portable solution:

# Include <ASM/page. h>
Int order = fig (16*1024 );
Buf = get_free_pages (gfp_kernel, order);/* The get_order parameter must be a power of 2 */
3) byte order

Do not assume the byte order. The Code should be written in byte order independent of the operated data.

Header file <ASM/byteorder. h> definition:

# Ifdef _ armeb __

# Include <Linux/byteorder/big_endian.h> // Large End

# Else

# Include <Linux/byteorder/little_endian.h> // Small End

# Endif
In <Linux/byteorder/big_endian.h>, _ big_endian is defined. in <Linux/byteorder/little_endian.h>, _ little_endian is defined, when dealing with the bytecode issue, these dependent processors need to encode a bunch of conditional statements similar to # ifdef _ litttle_endian.

But there is a better way: the Linux kernel has a set of macro definitions to process the conversion between the processor's byte order and the specific byte order. For example:

U32 cpu_to_le32 (u32 );

U32 le32_to_cpu (u32 );

/* These macro definitions convert a CPU usage value into an unsigned 32-bit small header value, whether the CPU is a large or small end, or whether it is a 32-bit processor. If no conversion is required, an unmodified value is returned. */

/* Many similar functions are defined in <Linux/byteorder/big_endian.h> and <Linux/byteorder/little_endian.h> */
 
3) Data Alignment

The last question worth considering when writing portable code is how to access non-aligned data. The following macros should be used to access non-alignment data:

# Include <ASM/unaligned. h> // not aligned

Get_unaligned (PTR );

Put_unaligned (Val, PTR );

These macros are non-typed and valid for each total data item, either 1, 2, 4, or 8 bytes, and are defined in all kernel versions.

Another issue about alignment is the cross-platform portability of data structures. The same data structure may be compiled differently on different platforms. In order to write data structures that can be transplanted across systems, the natural alignment of data items should always be enforced.

Natural alignment)It refers to an integer multiple of the data items stored on the address. The padding character should be used to prevent the compiler from moving fields in the data structure when the natural alignment is forced, leaving holes in the data structure.
The dataalign program experiment shows how the compiler enforces alignment.

For the good performance of the target processor, the compiler may insertFill characterTo ensure that each member is aligned. If you define a structure that matches the structure required by the device, the auto-padding will destroy this intent. The solution to this problem is to tell the compiler that the structure must be "Compact" and there is no padding. For example, the following definition:

struct{        u16 id;        u64 lun;        u16 reserved1;        u32 reserved2;}

_ Attribute _ (packed) SCSI;

/* If this structure is compiled on the 64-bit platform, if _ attribute _ (packed) is not found )), two or six padding characters may be added to the Lun member. Pointer and error value */
You can also find the practical application of this method in the spcaframe. h header file of the servfox source code that uses the video capture using the arm9-and USB cameras:

struct frame_t{    char header[5];    int nbframe;    double seqtimes;    int deltatimes;    int w;    int h;    int size;    int format;    unsigned short bright;    unsigned short contrast;    unsigned short colors;    unsigned short exposure;    unsigned char wakeup;    int acknowledge;    } __attribute__ ((packed)); struct client_t{    char message[4];    unsigned char x;    unsigned char y;    unsigned char fps;    unsigned char updobright;    unsigned char updocontrast;    unsigned char updocolors;    unsigned char updoexposure;    unsigned char updosize;    unsigned char sleepon;    } __attribute__ ((packed));

 

4) pointer and error value

Many kernel interfaces return error messages by encoding error values to pointer values. Such information must be used with caution because their return values cannot be simply compared with null. To help you create and use such interfaces, <Linux/err. h> provides the following functions:

Void * err_ptr (long error);/* encode the error value to the pointer value. error is a common negative error code */

Long is_err (const void * PTR);/* test whether the returned pointer is an error code */

Long ptr_err (const void * PTR);/* extract the actual error code, which is used only when is_err returns a true value. Otherwise, a valid pointer */

3. Linked List

The operating system kernel usually needs to maintain a linked list of data structures. The Linux kernel has several linked list implementations at the same time. To reduce the number of code copies, the kernel has already created a standard annular two-way linked list, and encourages people who need to operate the linked list to use this facility.
When using the linked list interface, remember that the list function is not locked. If the driver may perform concurrent operations on the same list, a lock scheme must be implemented.

To use the Linked List mechanism, the driver must contain a file <Linux/list. h>, which defines a simple list_head type structure:

Struct list_head {

Struct list_head * Next, * Prev;

};

The linked list used in the actual code is almost always composed of a certain structure type. Each structure describes one of the linked lists. To use a Linux linked list, you only need to embed a list_head in the structure of the linked list. The linked list header is often an independent list_head structure. Shows how this simple struct list_head is used to maintain a list of data structures.

 
The linked list header must be initialized before use. There are two forms:

First, the runtime initialization:

Struct list_head todo_list;

Init_list_head (& todo_list );

Second, compile-time initialization:

List_head (todo_list );

List_add (struct list_head * New, struct list_head * head );

Add a new item next to the head of the linked list. Note: The head does not need to be a nominal head of the linked list; if you pass a list_head structure, it is in the middle of a chain table, and the new item is closely behind it. Because the Linux linked list is circular, the linked list header is usually no different from any other items.

List_add_tail (struct list_head * New, struct list_head * head); // Add a new item before the given chain table header, that is, add a new item at the end of the chain table.

List_del (struct list_head * entry );

List_del_init (struct list_head * entry );

Remove the specified item from the queue. If the entry item may be registered in another linked list, you should use list_del_init to reinitialize the linked list pointer.

List_move (struct list_head * entry, struct list_head * head );

List_move_tail (struct list_head * entry, struct list_head * head );

The given entry is removed from its current linked list and added to the beginning of the head. Use list_move_tail to place the entry at the end of the new linked list.

List_empty (struct list_head * head );

If the given linked list is empty, a non-zero value is returned.

List_splice (struct list_head * List, struct list_head * head );
Connect two linked lists following the head.

List_entry is to convert a list_head structure pointer to a pointer pointing to a struct containing it. After reading the source code, you will find that you are familiar with it. Yes. In fact, container_of has been used in the module's open method. There are many variants of list_entry. You can see the source code.

# Define list_entry (PTR, type, member )\
Container_of (PTR, type, member)

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.