类型
驱动移植的许多问题都是数据类型导致的,同样的数据类型在不同的平台上可能有不同的位宽。内核将内存看做一个巨型数组看看待,但是内核中表示地址往往用的unsigned long
,这可以防止一些错误的解指针。同时在当前支持linux的各个平台上,long的位宽和指针位宽总是相同的。内核提供可移植类型定义,下面这个头文件包含u8
、u16
、u32
和u64
Linux专用数据类型。
1
| #include <linux/types.h>
|
内存
对内核的页面大小不要有任何假定,不要认为内核页面一定是4KB的。具体可以通过PAGE_SIZE
判断。如果是用户态,可以用getpagesize
库来获得页面大小。对于需要用页面幂次分配内存的参数,可以用get_order获得正确的幂次。
1 2 3
| #include <asm/page.h> int order = get_order(16*1024); buf = get_free_pages(GFP_KERNEL, order);
|
字节序
内核提供宏让内核代码判断当前平台是大端序还是小端序
1 2 3 4 5 6 7 8 9
| #include <asm/byteorder.h>
#ifdef __LITTLE_ENDIAN ... #endif
#ifdef __BIG_ENDIAN ... #endif
|
有类似于u32 e32_to_le32(u32)
这样的函数来保证将处理器类型转换为所需类型,完整列表见内核代码。
数据对齐
某些平台不能直接访问未对齐的数据,而是由异常处理机制处理,非常影响性能。内核提供接口辅助对非对齐数据的访问
1 2 3
| #include <asm/unaligned.h> get_unaligned(ptr); put_unaligned(val, ptr);
|
同时,在需要精准的控制数据结构对齐的时候,可以手动填充占位符或者用编译器内建属性标签
1 2 3
| struct { ... } __attribute__ ((packed)) xxxx;
|
返回指针的函
返回指针的函同样可以报告具体错误编码,将错误码编码在指针中即可。为了帮助内核代码编写,内核提供了辅助函数
1 2 3 4 5 6 7 8
| void *ERR_PTR(long error);
long IS_ERR(const void *ptr)
long PTR_ERR(const void *ptr);
|
链表
链表是内核经常需要用到的一种数据结构,所以内核实现了一套通用代码可以实现内核链表增删查改等。此外,内核这套链表都是循环的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| struct list_head todo_list; INIT_LIST_HEAD(&todo_list); LIST_HEAD(todo_list);
list_add(struct list_head *new, struct list_head *head); list_add_tail(struct list_head *new, struct list_head *head); list_del(struct list_head *entry); list_del_init(struct list_head *entry); list_move(struct list_head *entry, struct list_head *head); list_move_tail(struct list_head *entry, struct list_head *head); list_empty(struct list_head *head); list_splice(struct list_head *list, struct list_head *head); list_entry(struct list_head *ptr, type_of_struct, field_name);
list_for_each(struct list_head *cursor, struct list_head *list) list_for_each_prev(struct list_head *cursor, struct list_head *list)
list_for_each_safe(struct list_head *cursor, struct list_head *next, struct list_head *list);
list_for_each_entry(type *cursor, struct list_head *list, member); list_for_each_entry_safe(type *cursor, type *next, struct list_head *list, member);
void iteration_of_lsit(void) { struct list_head *ptr; struct todo_struct *entry; for (ptr = todo_list.next; ptr != &todo_list; ptr = ptr->next) { entry = list_entry(ptr, struct todo_struct, list); ... } }
void iteration_of_lsit(struct todo_struct *new) { struct list_head *ptr; struct todo_struct *entry; list_for_each(ptr, &todo_list) { entry = list_entry(ptr, struct todo_struct, list); ... } }
|