如何在 aarch64 上检测 crc32
How to detect crc32 on aarch64
aarch64 上的 user 程序是否可以检测 crc32 指令是否可用?我发现 references to kernel support 用于此类检测,这意味着包含有关哪些指令将在用户模式下工作的信息的寄存器在用户模式下不可用 (!)。
是这样吗?或者是否有一种可移植的方法来确定 crc32 指令是否可用?
注意:我所说的 "user program" 和 "portable" 是一种不需要特权指令或特定于操作系统的调用或文件(例如 /proc/cpuinfo)的方法。代码本身需要能够检测指令是否可用,如果可用则使用它们,如果不可用则退回到替代方案。例如,Intel 处理器具有用于此目的的 cpuid
指令。
更新:
翻阅 ARM 架构描述,我发现了一个用户级寄存器 PMCR_EL0
,它为处理器提供了一个 8 位实现代码和一个 8 位 ID 代码。也许如果我能找到这些代码的列表,我可能更接近我正在寻找的东西。
更新 2:
但是,当我尝试读取该寄存器时,出现非法指令异常。所以即使是 EL0 寄存器也需要特权访问?
更新:原来的答案没有回答这个问题,因为它的作者想要一些通用代码 运行 在 EL0 能够确定是否存在 CRC32 功能而不对操作系统有任何要求或正在使用裸机环境。
我的理解是这样的代码需要访问 ID_AA64ISAR0_EL1,并且由于 EL0 中的代码 运行 无法访问它,无论如何都需要切换到更高特权的异常级别。
以同样的方式,使用 'portable' 代码段捕获非法指令需要访问 VBAR_ELx 寄存器,而这不能从 EL0 的程序 运行 实现不会依赖任何基础操作 system/privileged 监视器。
因此,我对问题"Is that the case?"的回答是:是的,就是EL0的portable/universal段代码运行无法确定CRC32特性是否可用与否。
也就是说,问题中文档 referenced 中提供的示例代码在 Expressobin 运行 aarch64 linux 4.14.80 上运行良好,应该优先于出于内核文档中解释的原因使用 getauxval()。
这可能无法直接访问;但是 ARM
将为每个处理器提供 specifications - 因此有机会创建一个图表,可用于按型号名称查找 CPU 功能。
/proc/cpuinfo
是 Linux 具体的; Windows 等价于 WMI
; OSX 在 ARM
上没有 运行(据我所知)。除非它是完全绕过操作系统的 1 型管理程序,否则必须有 OS 特定代码(用户也可以禁用 VT
)。
据我所知不是。
我在 Chromium 的 zlib 中实现它的方式是使用可用的 OS 功能:
https://cs.chromium.org/chromium/src/third_party/zlib/arm_features.c?l=29
另外值得一提的是,ARMv8 上的 crc32 指令是密码扩展的一部分,在 ARMv8 上是可选的,在 ARMv8-1 上是强制性的。这也意味着运行时间特征检测是必要的,更多细节请查看:
https://cs.chromium.org/chromium/src/third_party/zlib/BUILD.gn?l=64
我会避免直接从 /proc/cpuinfo 阅读,因为在某些情况下这可能不可用(也取决于 Android 风格,它可能是假阴性)。
在 Chromium 中,zlib 将 运行 在特权上下文(即主浏览器进程中的网络代码的一部分)和沙盒上下文(即选项卡中 RendererProcess 的一部分)中。在 RendererProcess 中,读取 /proc/cpuinfo 应该会失败。
一个大锤方法是安装一个信号处理程序并使用内联汇编执行指令,如果指令不可用(并且可能被处理程序捕获),这将导致错误。不过不推荐。
上述示例 (https://github.com/torvalds/linux/blob/master/Documentation/arm64/cpu-feature-registers.txt) 在我测试过的 1 个 ARM 开发板 (MachiatoBin) 中工作,但在另外 2 个(rock64 和 nanopi m4)中失败。
Chromium 中实现的方法适用于所有主板(以及我测试过的一些手机)。
关于 getauxval 的另一个细节:如果 运行在 32 位或 64 位上使用,正确的标志将会改变。所以在 64 位中它将是 HWCAP_CRC32,而在 32 位中它将是 HWCAP2_CRC32.
关于 sledgehammer 方法:信号容易出现竞争条件,而且您仍然需要使用 OS 特定的 API(即安装信号处理程序) .
最后,根据上下文,如果给定任务崩溃(即使是设计并与执行上下文隔离),它将触发危险信号。
这是 x86 上的生活更轻松的一点(即功能检测)。
话虽如此,依赖 OS 功能可能是一个可以接受的妥协。自发布 M66(当前稳定版为 M72)以来,我们一直在 Chromium 中发布链接代码,大约一年前首次登陆,没有任何不良报告。
对 Android 的一个考虑是,NDK 可能在内部使用 dlopen()/dlsym() 实现 android_getCpuFeatures() 并且在第一次启动时可以增加大约 500us 到 1000us,这是为什么我们缓存 CPU 特征检测的结果。
多线程应用程序(如 Chromium)的另一个考虑因素是需要线程屏障(即 pthread_once_t)以避免在执行 CPU 功能检测时出现竞争条件。
aarch64 上的 user 程序是否可以检测 crc32 指令是否可用?我发现 references to kernel support 用于此类检测,这意味着包含有关哪些指令将在用户模式下工作的信息的寄存器在用户模式下不可用 (!)。
是这样吗?或者是否有一种可移植的方法来确定 crc32 指令是否可用?
注意:我所说的 "user program" 和 "portable" 是一种不需要特权指令或特定于操作系统的调用或文件(例如 /proc/cpuinfo)的方法。代码本身需要能够检测指令是否可用,如果可用则使用它们,如果不可用则退回到替代方案。例如,Intel 处理器具有用于此目的的 cpuid
指令。
更新:
翻阅 ARM 架构描述,我发现了一个用户级寄存器 PMCR_EL0
,它为处理器提供了一个 8 位实现代码和一个 8 位 ID 代码。也许如果我能找到这些代码的列表,我可能更接近我正在寻找的东西。
更新 2:
但是,当我尝试读取该寄存器时,出现非法指令异常。所以即使是 EL0 寄存器也需要特权访问?
更新:原来的答案没有回答这个问题,因为它的作者想要一些通用代码 运行 在 EL0 能够确定是否存在 CRC32 功能而不对操作系统有任何要求或正在使用裸机环境。
我的理解是这样的代码需要访问 ID_AA64ISAR0_EL1,并且由于 EL0 中的代码 运行 无法访问它,无论如何都需要切换到更高特权的异常级别。
以同样的方式,使用 'portable' 代码段捕获非法指令需要访问 VBAR_ELx 寄存器,而这不能从 EL0 的程序 运行 实现不会依赖任何基础操作 system/privileged 监视器。
因此,我对问题"Is that the case?"的回答是:是的,就是EL0的portable/universal段代码运行无法确定CRC32特性是否可用与否。
也就是说,问题中文档 referenced 中提供的示例代码在 Expressobin 运行 aarch64 linux 4.14.80 上运行良好,应该优先于出于内核文档中解释的原因使用 getauxval()。
这可能无法直接访问;但是 ARM
将为每个处理器提供 specifications - 因此有机会创建一个图表,可用于按型号名称查找 CPU 功能。
/proc/cpuinfo
是 Linux 具体的; Windows 等价于 WMI
; OSX 在 ARM
上没有 运行(据我所知)。除非它是完全绕过操作系统的 1 型管理程序,否则必须有 OS 特定代码(用户也可以禁用 VT
)。
据我所知不是。
我在 Chromium 的 zlib 中实现它的方式是使用可用的 OS 功能: https://cs.chromium.org/chromium/src/third_party/zlib/arm_features.c?l=29
另外值得一提的是,ARMv8 上的 crc32 指令是密码扩展的一部分,在 ARMv8 上是可选的,在 ARMv8-1 上是强制性的。这也意味着运行时间特征检测是必要的,更多细节请查看: https://cs.chromium.org/chromium/src/third_party/zlib/BUILD.gn?l=64
我会避免直接从 /proc/cpuinfo 阅读,因为在某些情况下这可能不可用(也取决于 Android 风格,它可能是假阴性)。
在 Chromium 中,zlib 将 运行 在特权上下文(即主浏览器进程中的网络代码的一部分)和沙盒上下文(即选项卡中 RendererProcess 的一部分)中。在 RendererProcess 中,读取 /proc/cpuinfo 应该会失败。
一个大锤方法是安装一个信号处理程序并使用内联汇编执行指令,如果指令不可用(并且可能被处理程序捕获),这将导致错误。不过不推荐。
上述示例 (https://github.com/torvalds/linux/blob/master/Documentation/arm64/cpu-feature-registers.txt) 在我测试过的 1 个 ARM 开发板 (MachiatoBin) 中工作,但在另外 2 个(rock64 和 nanopi m4)中失败。
Chromium 中实现的方法适用于所有主板(以及我测试过的一些手机)。
关于 getauxval 的另一个细节:如果 运行在 32 位或 64 位上使用,正确的标志将会改变。所以在 64 位中它将是 HWCAP_CRC32,而在 32 位中它将是 HWCAP2_CRC32.
关于 sledgehammer 方法:信号容易出现竞争条件,而且您仍然需要使用 OS 特定的 API(即安装信号处理程序) .
最后,根据上下文,如果给定任务崩溃(即使是设计并与执行上下文隔离),它将触发危险信号。
这是 x86 上的生活更轻松的一点(即功能检测)。
话虽如此,依赖 OS 功能可能是一个可以接受的妥协。自发布 M66(当前稳定版为 M72)以来,我们一直在 Chromium 中发布链接代码,大约一年前首次登陆,没有任何不良报告。
对 Android 的一个考虑是,NDK 可能在内部使用 dlopen()/dlsym() 实现 android_getCpuFeatures() 并且在第一次启动时可以增加大约 500us 到 1000us,这是为什么我们缓存 CPU 特征检测的结果。
多线程应用程序(如 Chromium)的另一个考虑因素是需要线程屏障(即 pthread_once_t)以避免在执行 CPU 功能检测时出现竞争条件。