为什么我能够在 Linux 内核模块内执行浮点运算?

2024-10-21 09:14:00
admin
原创
114
摘要:问题描述:我在 x86 CentOS 6.3(内核 v2.6.32)系统上运行。我将下面的函数编译成一个简单的字符驱动模块,作为实验来查看 Linux 内核对浮点运算的反应。static unsigned floatstuff(void){ float x = 3.14; x *= 2.5; ...

问题描述:

我在 x86 CentOS 6.3(内核 v2.6.32)系统上运行。

我将下面的函数编译成一个简单的字符驱动模块,作为实验来查看 Linux 内核对浮点运算的反应。

static unsigned floatstuff(void){
    float x = 3.14;
    x *= 2.5;
    return x;
}

...

printk(KERN_INFO "x: %u", x);

代码编译成功(这是意料之外的),因此我插入模块并用 检查了日志dmesg。日志显示:x: 7

这看起来很奇怪;我以为你不能在 Linux 内核中执行浮点运算——除了一些例外,例如kernel_fpu_begin()。模块如何执行浮点运算?

这是因为我使用的是 x86 处理器吗?


解决方案 1:

我以为你不能在 Linux 内核中执行浮点运算

您不能安全地:使用kernel_fpu_begin()/失败kernel_fpu_end()并不意味着 FPU 指令会出现故障(至少在 x86 上不会)。

相反,它会悄悄破坏用户空间的 FPU 状态。这很糟糕;不要这样做。

编译器不知道这是什么kernel_fpu_begin()意思,所以它无法检查/警告在 FPU 开始区域之外编译为 FPU 指令的代码。

可能存在一种调试模式,其中内核确实禁用kernel_fpu_begin/end区域之外的 SSE、x87 和 MMX 指令,但这会比较慢并且默认情况下不会执行。

但这是可能的:设置CR0::TS = 1会导致 x87 指令出错,因此延迟的 FPU 上下文切换是可能的,并且还有其他用于 SSE 和 AVX 的位。


内核代码存在许多缺陷,可能导致严重问题。这只是众多问题之一。在 C 语言中,您几乎总是知道何时使用浮点数(除非拼写错误导致常量1.或实际编译上下文中的某些内容)。


为什么FP架构状态与整数不同?

jmpLinux 每次进入/退出内核时都必须保存/恢复整数状态。所有代码都需要使用整数寄存器(除了以而不是retret修改)结尾的 FPU 计算的巨大直线块rsp)。

但是内核代码通常会避免使用 FPU,因此 Linux 在系统调用进入时不会保存 FPU 状态,仅在实际上下文切换到不同的用户空间进程或之前保存kernel_fpu_begin。否则,通常会返回到同一核心上的同一用户空间进程,因此不需要恢复 FPU 状态,因为内核没有触及它。(如果内核任务确实修改了 FPU 状态,就会发生损坏。我认为这是双向的:用户空间也可能破坏您的FPU 状态)。

整数状态相当小,只有 16x 64 位寄存器 + RFLAGS 和段寄存器。即使没有 AVX,FPU 状态也是两倍多:8x 80 位 x87 寄存器,16x XMM 或 YMM,或 32x ZMM 寄存器(+ MXCSR,以及 x87 状态 + 控制字)。此外,MPXbnd0-4寄存器与“FPU”合并在一起。此时,“FPU 状态”仅表示所有非整数寄存器。在我的 Skylake 上,dmesg显示x86/fpu: Enabled xstate features 0x1f, context size is 960 bytes, using 'compacted' format.

请参阅了解 Linux 内核中的 FPU 使用情况;现代 Linux 默认不会对上下文切换执行惰性 FPU 上下文切换(仅对内核/用户转换执行惰性 FPU 上下文切换)。(但那篇文章解释了什么是惰性。)

大多数进程使用 SSE 来复制/清零编译器生成的代码中的小块内存,并且大多数库字符串/memcpy/memset 实现都使用 SSE/SSE2。此外,硬件支持的优化保存/恢复现在已成为现实(xsaveopt/xrstor),因此如果某些/所有 FP 寄存器实际上没有被使用,“急切的”FPU 保存/恢复实际上可能做的工作更少。例如,如果 YMM 寄存器的低 128b 被清零,则仅保存它们,vzeroupper以便 CPU 知道它们是干净的。(并在保存格式中仅用一位标记该事实。)

通过“急切”的上下文切换,FPU 指令始终保持启用状态,因此错误的内核代码可能随时破坏它们。

解决方案 2:

不要这样做!

在内核空间中,FPU 模式由于以下几个原因而被禁用:

  • 它允许 Linux 在没有 FPU 的架构中运行

  • 它避免在每次内核/用户空间转换时保存和恢复整个寄存器集(它可能会使上下文切换的时间加倍)

  • 基本上所有的内核函数都使用整数来表示十进制数 - >你可能不需要浮点数

  • 在 Linux 中,当内核空间以 FPU 模式运行时,抢占被禁用

  • 浮点数是邪恶的,可能会产生非常糟糕的意外行为

如果您确实想使用 FP 数字(而您不应该这样做),那么您必须使用kernel_fpu_beginkernel_fpu_end原语来避免破坏用户空间寄存器,并且您应该考虑处理 FP 数字时可能出现的所有问题(包括安全性)。

解决方案 3:

不确定这种看法从何而来。但内核与用户模式代码在同一个处理器上执行,因此可以访问相同的指令集。如果处理器可以执行浮点运算(直接或通过协处理器),那么内核也可以。

也许你正在考虑在软件中模拟浮点运算的情况。但即便如此,它仍可在内核中使用(除非以某种方式禁用)。

我很好奇,这种看法从何而来?也许我忽略了什么。

找到了这个。似乎是一个很好的解释。

解决方案 4:

操作系统内核可能只是在内核模式下关闭 FPU。

当FPU运行时,浮点运算时内核会打开FPU,然后关闭FPU。

但你不能打印它。

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用