当前位置:网络安全 > Linux内核如何处理大小端

Linux内核如何处理大小端

  • 发布:2023-10-07 11:37

-->

我目前使用的是MPC8309,我不确定大小端内核是什么时候转换的。

今天看了一篇关于readl和writel具体实现的文章

今天我们主要分析readl/writel如何实现高效的数据交换和寄存器读写。让我们以 readl 为例来了解如何处理大端处理器的寄存器数据。

内核下的

readl定义如下,在include/asm-generic/io.h

#define readw(addr) __le32_to_cpu(__raw_readw(addr))

__raw_readl是最底层的寄存器读写函数。很简单,直接获取寄存器数据即可。我们看一下__le32_to_cpu的实现。该函数对于字节顺序有不同的实现。对于little-endian处理器,它位于./include/linux/byteorder/little_endian.h中,如下:

#define __le32_to_cpu(x) ((__force __u32)(__le32)(x))

相当于什么都不做。对于big-endian处理器,在./include/linux/byteorder/big_endian.h中,如下:

#define __le32_to_cpu(x) __swab32((_​​_force __u32)(__le32)(x))

从字面意思也可以看出,__swab32实现了数据翻转。后面我们会分析__swab32的实现。本质就在于这个函数。

但在此之前,我们先考虑一个问题。对于不同的CPU,比如arm mips ppc,如何选择使用little_endian.h或者big_endian.h。

答案是,针对不同的处理器平台,都有 arch/xxx/include/asm/byteorder.h 头文件。我们看一下arm mips ppc的byteorder.h。

arch/arm/include/asm/byteorder.h

  1. * arch/arm/include/asm/byteorder.h
  2. *
  3. * ARM 字节序。在小端模式下,数据总线的连接方式如下
  4. * 字节访问显示为:
  5. * 0 = d0...d7、1 = d8...d15、2 = d16...d23、3 = d24...d31
  6. * 和字访问(数据或指令)显示为:
  7. * d0...d31
  8. *
  9. * 在大端模式下,字节访问显示为:
  10. * 0 = d24...d31, 1 = d16...d23, 2 = d8...d15, 3 = d0...d7
  11. * 和字访问(数据或指令)显示为:
  12. * d0...d31
  13. */
  14. #ifndef __ASM_ARM_BYTEORDER_H
  15. #define __ASM_ARM_BYTEORDER_H
  16. #ifdef __ARMEB__
  17. #包括
  18. #else
  19. #包括
  20. #endif
  21. #endif

arch/mips/include/asm/byteorder.h

  1. /*
  2. * 此文件受 GNU 通用公共
  3. 的条款和条件约束
  4. * 许可证。查看此存档主目录中的文件“COPYING”
  5. * 了解更多详情。
  6. *
  7. * 版权所有 (C) 1996、99、2003,作者:Ralf Baechle
  8. */
  9. #ifndef _ASM_BYTEORDER_H
  10. #define _ASM_BYTEORDER_H
  11. #if 已定义(__MIPSEB__)
  12. #包括
  13. #elif 定义(__MIPSEL__)
  14. #包括
  15. #else
  16. # 错误“MIPS,但既不是 __MIPSEB__,也不是 __MIPSEL__???”
  17. #endif
  18. #endif /*_ASM_BYTEORDER_H*/

arch/powerpc/include/asm/byteorder.h

  1. #ifndef _ASM_POWERPC_BYTEORDER_H
  2. #define _ASM_POWERPC_BYTEORDER_H
  3. /*
  4. * 该程序是免费软件;您可以重新分发它和/或
  5. * 根据 GNU 通用公共许可证
  6. 的条款对其进行修改
  7. * 由自由软件基金会发布;任一版本
  8. * 2 个许可证,或(由您选择)任何更高版本。
  9. */
  10. #包括
  11. #endif /* _ASM_POWERPC_BYTEORDER_H */

可以看出arm mips在内核下支持big endian和small endian,并且arm mips确实可以选择处理器字节序。 ppc 仅支持 big-endian。 (其实ppc也支持选择字节顺序)

每个处理器平台的byteorder.h将littlie_endian.h/big_endian.h包装在另一层中。我们在编写驱动程序时不需要关心处理器的字节顺序,我们只需要包含byteorder.h。

我们来看看最关键的__swab32函数,如下:

在 include/linux/swab.h 中

  1. /**
  2. * __swab32 - 返回字节交换的 32 位值
  3. * @x:转换为字节交换的值
  4. */
  5. #define __swab32(x) \
  6. (__builtin_constant_p((__u32)(x)) ? \
  7. ___constant_swab32(x):\
  8. __fswab32(x))

宏定义扩展是一个条件运算符。

__builtin_constant_p是gcc的内置函数,用于在编译时判断一个值是否为常量。如果参数是常量,函数返回1,否则返回0。
如果数据是常量,则__constant_swab32实现如下:

  1. #define ___constant_swab32(x) ((__u32)(
  2. (((__u32)(x) & (__u32)0x000000ffUL) << 24) |
  3. (((__u32)(x) & (__u32)0x0000ff00UL) << 8) |
  4. (((__u32)(x) & (__u32)0x00ff0000UL) >> 8) |
  5. (((__u32)(x) & (__u32)0xff000000UL) >> 24)))

对于常数数据,采用普通位移然后拼接的方法。对于常量来说,这样的消耗是必要的(这是内核的解释,不是很好理解)

如果数据是运行时计算数据,则使用__fswab32,实现如下:

  1. 静态内联 __attribute_const__ __u32 __fswab32(__u32 val)
  2. {
  3. #ifdef __arch_swab32
  4. 返回__arch_swab32(val);
  5. #else
  6. 返回___constant_swab32(val);
  7. #endif
  8. }

如果没有定义__arch_swab32,则仍然使用__constant_swab32方法来翻转数据。然而arm mips ppc都为各自的平台定义了__arch_swab32,以实现针对自己平台的高效交换。它们的定义如下:

arch/arm/include/asm/swab.h

  1. 静态内联 __attribute_const__ __u32 __arch_swab32(__u32 x)
  2. {
  3. __asm__ ("rev %0, %1" : "=r" (x) : "r" (x));
  4. 返回x;
  5. }

arch/mips/include/asm/swab.h

  1. 静态内联 __attribute_const__ __u32 __arch_swab32(__u32 x)
  2. {
  3. __asm__(
  4. " wsbh %0, %1 \n"
  5. " 旋转 %0, %0, 16 \n"
  6. :“=r”(x)
  7. : "r" (x));
  8. 返回x;
  9. }

arch/powerpc/include/asm/swab.h

  1. 静态内联 __attribute_const__ __u32 __arch_swab32(__u32 值)
  2. {
  3. __u32 结果;
  4. __asm__("rlwimi %0,%1,24,16,23\n\t"
  5. "rlwimi %0,%1,8,8,15\n\t"
  6. "rlwimi %0,%1,24,0,7"
  7. :“=r”(结果)
  8. :“r”(值),“0”(值 >> 24));
  9. 返回结果;
  10. }

可以看到arm使用1条指令(rev数据翻转指令),mips使用2条指令(wsbh rotr数据交换指令),ppc使用3条指令(rlwimi数据移位指令)完成32位数据的翻转。这比普通的位移拼接方式效率要高很多!

其实从函数名__fswab就可以看出,是要实现快速交换的。

-->

相关文章

最新资讯