Chapter 10. Judicious Use of Data Types

Before we go on to more advanced topics, we need to stop for a quick note on portability issues. The difference between versions 1.2 and 2.0 of Linux lies in the addition of multiplatform capabilities; as a result, most source-level portability problems have been eliminated. This means that a serious Linux driver should be multiplatform as well.

But a core issue with kernel code is being able to both access data items of known length (for example, filesystem data structures or registers on device boards) and to exploit the capabilities of different processors (32-bit and 64-bit architectures, and possibly 16-bit as well).

Several problems encountered by kernel developers while porting x86 code to new architectures have been related to incorrect data typing. Adherence to strict data typing and compiling with the -Wall -Wstrict-prototypes flags can prevent most bugs.

Data types used by kernel data are divided into three main classes: standard C types like int, explicitly sized types like u32, and interface-specific types, like pid_t. We are going to see when and how each of the three typing classes should be used. The final sections of the chapter talk about some other typical problems you might run into when porting driver code from the x86 to other platforms.

If you follow the guidelines I provide, your driver will compile and run even on platforms where you are unable to test it.

Use of Standard C Types

While most programmers are accustomed to freely using standard types like int and long, writing device drivers requires some care to avoid typing conflicts and obscure bugs.

The problem is that you can’t use the standard types when you need ``a 2-byte filler'' or ``something representing a 4-byte string'' because the normal C data types are not the same size on all architectures. For example, long integers and pointers are a different size on the x86 than on the Alpha, as shown by the following screen snapshots:

morgana% ./datasize
system/machine: Linux i486
sizeof(char) =     1
sizeof(short) =    2
sizeof(int) =      4
sizeof(long) =     4
sizeof(longlong) = 8
sizeof(pointer) =  4

wolf% ./datasize
system/machine: Linux alpha
sizeof(char) =     1
sizeof(short) =    2
sizeof(int) =      4
sizeof(long) =     8
sizeof(longlong) = 8
sizeof(pointer) =  8

sandra% ./datasize
system/machine: Linux sparc
sizeof(char) =     1
sizeof(short) =    2
sizeof(int) =      4
sizeof(long) =     4
sizeof(longlong) = 8
sizeof(pointer) =  4

The datasize program is a short program available in the files provided on the O’Reilly FTP site, in the directory misc-progs.

While you must be careful when mixing int and long, sometimes there are good reasons to do so. One such situation is for memory addresses, which are special as far as the kernel is concerned. Although conceptually addresses are pointers, memory administration is better accomplished by using an integer type; the kernel treats physical memory like a huge array, and a memory address is just an index into the array. Furthermore, a pointer is easily dereferenced, and using integers for memory addresses prevents them from being dereferenced, which is what you want. Therefore, addresses in the kernel are unsigned long, exploiting the fact that pointers and long integers are always the same size, at least on all the platforms curently supported by Linux. We’ll have to wait and see what happens when Linux is ported to a platform breaking this rule.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.19.31.73