Data Types in the Kernel Sarah Diesburg COP
Data Types in the Kernel Sarah Diesburg COP 5641
Kernel Data Types n For portability ¡ n Should compile with –Wall –Wstrictprototypes flags Three main classes ¡ ¡ ¡ Standard C types (e. g. , int) Explicitly sized types (e. g. , u 32) Types for specific kernel objects (e. g. , pid_t)
Use of Standard C Types n n Normal C types are not the same size on all architectures Try misc-progs/datasize % misc-progs/datasize arch Size: char short int long ptr long-long u 8 u 16 u 32 u 64 i 686 1 2 4 4 4 8 1 2 4 8 n Try misc-modules/kdatasize to see kernel versions
Use of Standard C Types n 64 -bit platforms have different data type representations arch Size: char short int long ptr long-long u 8 u 16 u 32 u 64 i 386 1 2 4 4 4 8 1 2 4 8 alpha 1 2 4 8 8 8 1 2 4 8 armv 4 l 1 2 4 4 4 8 1 2 4 8 ia 64 1 2 4 8 8 8 1 2 4 8 m 68 k 1 2 4 4 4 8 1 2 4 8 mips 1 2 4 4 4 8 1 2 4 8 ppc 1 2 4 4 4 8 1 2 4 8 sparc 64 1 2 4 4 4 8 1 2 4 8 x 86_64 1 2 4 8 8 8 1 2 4 8
Use of Standard C Types n Knowing that pointers and long integers have the same size ¡ Using unsigned long for kernel addresses prevents unintended pointer dereferencing
Assigning an Explicit Size to Data Items n See <asm/types. h> ¡ ¡ n u 8; /* unsigned byte (8 -bits) */ u 16; /* unsigned word (16 -bits) */ u 32; /* unsigned 32 -bit value */ u 64; /* unsigned 64 -bit value */ If a user-space program needs to use these types, use __ prefix (e. g. , __u 8)
Assigning an Explicit Size to Data Items n Kernel also uses conventional types, such as unsigned int ¡ Usually done for backward compatibility
Interface-Specific Types n Interface-specific type: defined by a library to provide an interface to specific data structure (e. g. , pid_t)
Interface-Specific Types n Many _t types are defined in <linux/types. h> ¡ Problematic in printk statements ¡ One solution is to cast the value to the biggest possible type (e. g. , unsigned long) n n Avoids warning messages Will not lose data bits
Other Portability Issues n n Be suspicious of explicit constant values Most values are parameterized with preprocessor macros
Timer Intervals n Do not assume 1000 jiffies per second ¡ Scale times using HZ (number of interrupts per second) n n For example, check against a timeout of half a second, compare the elapsed time against HZ/2 Number of jiffies corresponding to msec second is always msec*HZ/1000
Page Size n Memory page is PAGE_SIZE bytes, not 4 KB ¡ ¡ Can vary from 4 KB to 64 KB PAGE_SHIFT contains the number of bits to shift an address to get its page number See <asm/page. h> User-space program can use getpagesize library function
Page Size n Example ¡ To allocate 16 KB n n Should not specify an order of 2 to __get_free_pages Use get_order #include <asm/page. h> int order = get_order(16*1024); buf = __get_free_pages(GFP_KERNEL, order);
Byte Order n n n PC stores multibyte values low-byte first (little-endian) Some platforms use big-endian Use predefined macros ¡ ¡ <linux/byteorder/big_endian. h> <linux/byteorder/little_endian. h>
Byte Order n Examples ¡ u 32 cpu_to_le 32(u 32); n n ¡ u 64 be 64_to_cpu(u 64); n ¡ cpu = internal CPU representation le = little endian be = big endian U 16 cpu_to_le 16 p(u 16); n p = pointer n Converts value pointed to by p
Data Alignment n How to read a 4 -byte value stored at an address that is not a multiple of 4 bytes? ¡ ¡ i 386 permits this kind of access Not all architectures permit it n Can raise exceptions
Data Alignment Example char wolf[] = “Like a wolf”; char *p = &wolf[1]; unsigned long l = *(unsigned long *)p; n Treats the pointer to a char as a pointer to an unsigned long, which might result in the 32 - or 64 bit unsigned long value being loaded from an address that is not a multiple of 4 or 8, respectively.
Data Alignment n Use the following typeless macros ¡ ¡ ¡ #include <asm/unaligned. h> get_unaligned(ptr); put_unaligned(val, ptr);
Data Alignment n Another issue is the portability of data structures ¡ ¡ Compiler rearranges structure fields to be aligned according to platform-specific conventions Automatically add padding to make things aligned n May no longer match the intended format
Data Alignment n For example, consider the following structure on a 32 -bit machine struct animal_struct { char dog; /* 1 byte */ unsigned long cat; /* 4 bytes */ unsigned short pig; /* 2 bytes */ char fox; /* 1 byte */ };
Data Alignment n Structure not laid out like that in memory ¡ n Natural alignment of structure’s members is inefficient Instead, complier creates padding struct animal_struct { char dog; /* 1 byte */ u 8 __pad 0[3]; /* 3 bytes */ unsigned long cat; /* 4 bytes */ unsigned short pig; /* 2 bytes */ char fox; /* 1 byte */ u 8 __pad 1; /* 1 byte */ };
Data Alignment n You can often rearrange the order of members in a structure to obviate the need for padding struct animal_struct { unsigned long cat; /* 4 bytes */ unsigned short pig; /* 2 bytes */ char dog; /* 1 byte */ char fox; /* 1 byte */ };
Data Alignment n n Another option is to tell the compiler to pack the data structure with no fillers added Example: <linux/edd. h> Without __attribute__ struct { u 16 id; u 64 lun; u 16 reserved 1; u 32 reserved 2; } __attribute__ ((packed)) scsi; ((packed)), lun would be preceded by 2 -6 bytes of fillers
Data Alignment n No compiler optimizations n Some compiler optimizations n __attribute__ ((packed))
Pointers and Error Values n Functions that return pointers cannot report negative error values ¡ n Return NULL on failure Some kernel interfaces encode error code in a pointer value ¡ Cannot be compared against NULL ¡ To use this feature, include <linux/err. h>
Pointers and Error Values n To return an error, use ¡ n To test whether a returned pointer is an error code, use ¡ n void *ERR_PTR(long error); long IS_ERR(const void *ptr); To access the error code, use ¡ long PTR_ERR(const void *ptr);
- Slides: 26