2.3.2 谨慎使用可变位宽的数据类型
内核态和用户态共用的变量类型定义不能使用 long 和 size_t。
从表 2-1 可知,如果内核态、用户态共用的变量类型定义有 long 和 size_t,那么当内核态 64 位、用户态 32 位模式下,它们的数据位宽是不一样的,当有数据需要在用户态、内核态之间相互传递时由于数据位宽不一样导致拷贝数据时无论是按照用户态长度拷贝还是按照内核态长度拷贝都是错误的。
-内核态和用户态共用的变量类型定义不能使用 long 和 size_t,使用 long 和 size_t定义的变量统一修改为 long long。
-HiSilicon SDK 对以下数据类型进行了重定义。
typedef unsigned long long HI_U64;
typedef long long HI_S64;
typedef unsigned long HI_UL;
typedef signed long HI_SL;
2.3.3 指针的处理
如果内核态和用户态共用的结构体、联合体里面定义了指针变量,那么在内核态 64位、用户态 32 位模式下,这些结构体、联合体的长度由于有指针变量的存在,在内核态和用户态的长度是不一样的。
可以把整个系统里面内核态和用户态共用的结构体、联合体里面的指针变量替换为long long 变量,在具体使用时再强制类型转换为指针变量,但是这种修改方法工作量大,而且使用 long long 记录地址不如直接使用指针直观。
下面介绍一种修改工作量小的指针处理方法。
-使用 GCC 编译器指令__attribute__ ((aligned (8)))对指针和紧挨着指针后面的变量单独进行首地址 8 bytes 对齐。
注意:__attribute__ ((aligned (8)))只能对单个指针进行首地址 8 bytes 对齐,不能对指针数组的每一个指针元素进行首地址 8 bytes 对齐。指针数组需要拆成每一个独立的指针变量或者使用 long long 数组替换。
-compat_ioctl 从用户态把结构体数据 copy_from_user 到内核态之后,在进行正常业务处理之前把指针的高 32bit 赋 0。
注意:结构体里面的指针变量是用户态地址传递到内核态的才需要把指针的高32bit 赋 0,内核态地址传递到用户态不需要处理。