简图记录-linux驱动32位移植64位

简图记录学习~

一、概念

1、移植目的:64位 内核/驱动 可同时支持32位/64位库和应用执行,这是64位驱动的一大优势。同时当应用要使用多余4G内存、大于2G文件、进行密级浮点运算或64位库时,也必须要求64位驱动环境。

2、对64位驱动要求:同一份C代码必须同时支持32位/64位编译,无法归一处使用系统宏统一管理

3、ARM支持:ARMv8支持按64位架构AArch64和32位架构AArch32编译

AArch32:普通32位编译架构,通用寄存器和PC、SP、LR都为32位

AArch64:31个64位通用寄存器、PC SP LR也为64位,有四中例外工作模式(EL0:应用 EL1:内核 特权模式 EL2:hyspevisor模式 EL3:安全模式) 


二、移植及编码注意点

1、基本类型长度变化

C语言在ANSIC只定义了char类型长度一定是1字节、其他类型在不同系统上长度都可能变化,如:

系统类型 char类型 short类型 int类型 long类型 longlong类型 point类型
LP64(64位 Unix、linux、OsX) 1 2 4 64 64 64
LLP64(64位Ms windows) 1 2 4 32 64 64
ILP32(32位操作系统) 1 2 4 32 64 32
编码建议:建议使用系统定义的定长类型方便移植(如 u32、s32),尽量不使用long除非是系统接口指定如中断flag,不要使用其他类型存储指针(防止截断)

2、复合类型数据对齐

自然对齐:变量内存地址正好是该变量长度整数倍。(非自然对齐 会导致RISC系统陷入可处理错误、降低读写性能)

编译器如gcc会完成自然对齐(通过增加reserve数据),方式如下:

(1)联合体 按最大数据类型对齐 (2)数组 按成员类型对齐 (3)结构体 每个成员都要求自然对齐,导致不同排序size不同

编码建议:结构体中尽可能不包含32/64位下长度可变类型,注意成员的排序对size影响。

3、不透明类型处理

C语言常用typedef去隐藏数据类型,如time_t在32位下是32位、64位下是64位,pid_t在早期Unix版本为short后来改为int。

编码建议:不要假定一个内核隐藏类型的长度,更不要把隐藏类型强转后在使用。

4、常量长度类型指定

一般长度在int范围内的常量,系统都默认是int'类型。

编码建议:如果可能超出32位必须使用指定类型。(也可加后缀如 long型1L、无符号long型1UL、1ULL)

如:longlong value = (long long)1 << bitNum,如果不加类型指定最大也只有1<<31。

5、类型转化

当发生以下情况时,会发生类型转化(后三类为隐式强转):

(1)不同类型算术运算 (2)赋值表达式 左右类型不同 (3)函数传参 实参形参类型不同 (4)函数返回值和接收值类型不同

算术运算类型转化规律:低类型到高类型 char->short->int->long->double;float->double,有符号转无符号

编码建议:尽量避免不同类型特别是有符号和无符号之间运算和转化,防止溢出、截断问题。不用指针以外的类型传递指针,虚拟地址用指针存储。

6、格式化输出

编程建议:指针使用%p输出、long类型使用%ld打印(否则在64bit系统上会发生截断)

7、用户态和内核态交互数据结构

用户与内核交互接口io_ctrl的命令号是在驱动头文件通过 宏 以 模块名、命令序号、输入输出方向、交互结构size合成,如果数据结构在32bit和64bit下有差异,那么最终编译出的命令号是不同的,导致驱动无法识别。

编码建议:1、结构体避免包含 指针和long类型 2、当传递地址时优先u32传递物理地址,必须传递虚拟地址时可以通过添加reverse成员 保证应用32位和64位编译是数据结构长度一致。如int a;int reverse;char *p中间插入的reverse可以保证对齐过程使长度一致。

8、其他移植过程其他注意事项

(1)大小端字节序 的 影响

(2)页长度不同的影响

(3)定时器节拍率HZ不同的影响

(4)SMP并发影响(注意锁的使用)

(5)编译器对部分处理器的指令重新排序提升执行效率(可用屏障防止重排:读写mb();读rmb();写wmb90)

简图记录-linux驱动32位移植64位_第1张图片

你可能感兴趣的:(linux学习类)