立即注册
查看: 656|回复: 0

[海思技术资料] 海思Hi3559A Linux 64位系统适配FAQ

已绑定手机
已实名认证
发表于 2021-9-18 11:25:08 | 显示全部楼层 |阅读模式 来自 广东省深圳市
1、概述
Linux ARM定义的 ARMv8,支持 AARCH32 模式和 AARCH64 模式。
-AARCH32 模式地址用 32 位表示,最大 4GB;
-AARCH64 模式地址用 64 位表示,但最多只有后 48 位是有效的地址位,即最大为2^48 = 256TB。
本文以 HI3559AV100ES 芯片为例,简述客户在 Linux ARMv8 架构中移植 C 语言代码遇到的问题及解决方法。

2、FAQ
2.1 Linux ARMv8 架构业务部署模式
Linux ARMv8 架构支持以下几种业务部署模式:
-内核态 64 位,用户态 64 位。
-内核态 64 位,用户态 32 位。
-内核态 32 位,用户态 32 位。

2.2 编译器对数据类型长度的修改
ARMv8 针对 aarch64 与 aarch32 环境,使用不同的编译器。aarch64 环境使用 64 位编译器 aarch64-hisiv610-linux-,aarch32 环境使用 32 位编译器 arm-hisiv610-linux-。64 位和32 位的编译器对数据类型位宽差异的影响如下表 2-1 所示:
Programming TypeSize in 32bit CompilerSize in 64bit Compiler
char8 bit8 bit
short16 bit16 bit
int32 bit32 bit
pointer32 bit64 bit
long32 bit64 bit
long long64 bit64 bit


2.3 C 语言移植修改注意事项
基本原则:同一份 C 代码需要能够支持 32bit 模式编译和 64bit 模式编译。32bit 和64bit 的版本代码是归一的。实在无法归一的代码,Linux 内核态处理统一采用 64bit 的宏:CONFIG_64BIT,用户态则需要用户根据选择的编译器位宽自定义相关的宏。

2.3.1 kernel 配置选项 CONFIG_COMPAT 和 compat_ioctl
kernel 配置选项 CONFIG_COMPAT 和 compat_ioctl。 z 内核态 64 位,用户态 64 位,用户态到内核态的系统调用 ioctl,在底层 kernel 驱动中最终调用到 unlocked_ioctl。 z 内核态 64 位,用户态 32 位,用户态到内核态的系统调用 ioctl,在底层 kernel 驱动中最终调用到 compat_ioctl。 z 内核态 32 位,用户态 32 位,用户态到内核态的系统调用 ioctl,在底层 kernel 驱动中最终调用到 unlocked_ioctl。
因此,在 kernel 驱动中除了提供原有的 unlocked_ioctl 外,还需提供 compat_ioctl。
代码示例:
static struct osal_fileops vdec_fops =
{
.open = vdec_open,
.release = vdec_close,
.mmap = NULL,
.poll = vdec_poll,
.unlocked_ioctl = vdec_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = vdec_compat_ioctl,
#endif
};

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,内核态地址传递到用户态不需要处理。

更多详细内容请下载附件查看
游客,如果您要查看本帖隐藏内容请回复
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

合作/建议

TEL: 19168984579

工作时间:
周一到周五 9:00-11:30 13:30-19:30
  • 扫一扫关注公众号
  • 扫一扫打开小程序
Copyright © 2013-2024 一牛网 版权所有 All Rights Reserved. 帮助中心|隐私声明|联系我们|手机版|粤ICP备13053961号|营业执照|EDI证
在本版发帖搜索
扫一扫添加微信客服
QQ客服返回顶部
快速回复 返回顶部 返回列表