暂时在用MPC8309,不太清楚大小端内核是什么时候给转的。

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

今天就主要来分析下readl/writel如何实现高效的数据swap和寄存器读写。我们就以readl为例,针对big-endian处理器,如何来对寄存器数据进行处理。

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

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

__raw_readl是最底层的寄存器读写函数,很简单,就从直接获取寄存器数据。来看__le32_to_cpu的实现,该函数针对字节序有不同的实现,对于小端处理器,在./include/linux/byteorder/little_endian.h中,如下:

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

相当于什么都没做。而对于大端处理器,在./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

*  arch/arm/include/asm/byteorder.h

*

* ARM Endian-ness.  In little endian mode, the data bus is connected such

* that byte accesses appear as:

*  0 = d0...d7, 1 = d8...d15, 2 = d16...d23, 3 = d24...d31

* and word accesses (data or instruction) appear as:

*  d0...d31

*

* When in big endian mode, byte accesses appear as:

*  0 = d24...d31, 1 = d16...d23, 2 = d8...d15, 3 = d0...d7

* and word accesses (data or instruction) appear as:

*  d0...d31

*/

#ifndef __ASM_ARM_BYTEORDER_H

#define __ASM_ARM_BYTEORDER_H

#ifdef __ARMEB__

#include

#else

#include

#endif

#endif

arch/mips/include/asm/byteorder.h

/*

* This file is subject to the terms and conditions of the GNU General Public

* License.  See the file "COPYING" in the main directory of this archive

* for more details.

*

* Copyright (C) 1996, 99, 2003 by Ralf Baechle

*/

#ifndef _ASM_BYTEORDER_H

#define _ASM_BYTEORDER_H

#if defined(__MIPSEB__)

#include

#elif defined(__MIPSEL__)

#include

#else

# error "MIPS, but neither __MIPSEB__, nor __MIPSEL__???"

#endif

#endif /* _ASM_BYTEORDER_H */

arch/powerpc/include/asm/byteorder.h

#ifndef _ASM_POWERPC_BYTEORDER_H

#define _ASM_POWERPC_BYTEORDER_H

/*

* This program is free software; you can redistribute it and/or

* modify it under the terms of the GNU General Public License

* as published by the Free Software Foundation; either version

* 2 of the License, or (at your option) any later version.

*/

#include

#endif /* _ASM_POWERPC_BYTEORDER_H */

可以看出arm mips在kernel下大小端都支持,arm mips也的确是可以选择处理器字节序。ppc仅支持big-endian。(其实ppc也是支持选择字节序的)

各个处理器平台的byteorder.h将littlie_endian.h/big_endian.h又包了一层,我们在编写driver时不需要关心处理器的字节序,只需要包含byteorder.h即可。

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

在include/linux/swab.h中

/**

* __swab32 - return a byteswapped 32-bit value

* @x: value to byteswap

*/

#define __swab32(x)             \

(__builtin_constant_p((__u32)(x)) ? \

___constant_swab32(x) :         \

__fswab32(x))

宏定义展开,是一个条件判断符。

__builtin_constant_p是一个gcc的内建函数, 用于判断一个值在编译时是否是常数,如果参数是常数,函数返回 1,否则返回 0。

如果数据是常数,则__constant_swab32,实现如下:

#define ___constant_swab32(x) ((__u32)(             \

(((__u32)(x) & (__u32)0x000000ffUL) <

(((__u32)(x) & (__u32)0x0000ff00UL) <

(((__u32)(x) & (__u32)0x00ff0000UL) >>  8) |        \

(((__u32)(x) & (__u32)0xff000000UL) >> 24)))

对于常数数据,采用的是普通的位移然后拼接的方法,对于常数,这样的消耗是有必要的(这是kernel的解释,不是很理解)

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

static inline __attribute_const__ __u32 __fswab32(__u32 val)

{

#ifdef __arch_swab32

return __arch_swab32(val);

#else

return ___constant_swab32(val);

#endif

}

如果未定义__arch_swab32,则还是采用__constant_swab32方法翻转数据,但是arm mips ppc都定义了各自平台的__arch_swab32,来实现一个针对自己平台的高效的swap,分别定义如下:

arch/arm/include/asm/swab.h

static inline __attribute_const__ __u32 __arch_swab32(__u32 x)

{

__asm__ ("rev %0, %1" : "=r" (x) : "r" (x));

return x;

}

arch/mips/include/asm/swab.h

static inline __attribute_const__ __u32 __arch_swab32(__u32 x)

{

__asm__(

"   wsbh    %0, %1          \n"

"   rotr    %0, %0, 16      \n"

: "=r" (x)

: "r" (x));

return x;

}

arch/powerpc/include/asm/swab.h

static inline __attribute_const__ __u32 __arch_swab32(__u32 value)

{

__u32 result;

__asm__("rlwimi %0,%1,24,16,23\n\t"

"rlwimi %0,%1,8,8,15\n\t"

"rlwimi %0,%1,24,0,7"

: "=r" (result)

: "r" (value), "0" (value >> 24));

return result;

}

可以看出,arm使用1条指令(rev数据翻转指令),mips使用2条指令(wsbh rotr数据交换指令),ppc使用3条指令(rlwimi数据位移指令),来完成了32 bit数据的翻转。这相对于普通的位移拼接的方法要高效的多!

其实从函数名__fswab也可以看出是要实现fast swap的。

原文:http://www.cnblogs.com/yangv/p/5553717.html

Linux内核判断大小端,linux kernel 如何处理大小端相关推荐

  1. linux内核 lts长期演进,Linux Kernel 4.19 将成为下一个LTS(长期支持)系列

    最近Linux内核开发人员和维护人员Greg Kroah-Hartman透露,Linux Kernel 4.19将下一个长期支持的Linux内核系列. 现在Linux Kernel 4.17已经达到使 ...

  2. Linux内核开发_1_编译LInux内核

    目录 1. 准备工作 1.1 学习环境 1.2 下载Linux内核源码 1.3 解压Linux内核 1.4 目录结构介绍 2. Linux内核配置 2.1 配置选项 1. make config 2. ...

  3. 一文了解linux内核,一文了解Linux的系统结构

    什么是 Linux ? 如果你以前从未接触过Linux,可能就不清楚为什么会有这么多不同的Linux发行版.在查看Linux软件包时,你肯定被发行版.LiveCD和GNU之类的术语搞晕过.初次进入Li ...

  4. Linux内核入门-如何获取Linux内核源代码、生成配置内核

    如何获取Linux内核源代码 如何获取Linux内核源代码 下载Linux内核当然要去官方网站了,网站提供了两种文件下载,一种是完整的Linux内核,另一种是内核增量补丁,它们都是tar归档压缩包.除 ...

  5. 搭建《深入Linux内核架构》的Linux环境

    搭建<深入Linux内核架构>的Linux环境 阅读目录(Content) 作者 软件 概述 正文 一.安装GCC 二.编译Linux内核 三.制作跟文件系统 四.运行qemu 五.启动l ...

  6. linux内核启动分析 三,Linux内核分析 实验三:跟踪分析Linux内核的启动过程

    贺邦 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 一. 实验过程 ...

  7. 查看linux内核的编译时间,linux内核编译步骤

    linux内核编译步骤 对于linux新手来说,编译内核相对有一些难度,甚至不知道如何入手,我通过在网上收集这方面的资料,最终编译成功.现在我归纳了一下,写出这一篇还算比较详细的步骤,希望能对各位新手 ...

  8. 【Linux 内核 内存管理】Linux 内核堆内存管理 ① ( 堆内存管理 | 内存描述符 mm_struct 结构体 | mm_struct 结构体中的 start_brk、brk 成员 )

    文章目录 一.堆内存管理 二.内存描述符 mm_struct 结构体 三.mm_struct 结构体中的 start_brk.brk 成员 一.堆内存管理 Linux 操作系统中的 " 堆内 ...

  9. 【Linux 内核】进程管理 ( Linux 内核中的进程状态 | TASK_RUNNING | TASK_INTERRUPTIBLE | __TASK_STOPPED | EXIT_ZOMBIE )

    文章目录 一.Linux 内核中的进程状态 二.TASK_RUNNING 状态 三.TASK_RUNNING 状态 四.TASK_UNINTERRUPTIBLE 状态 五.__TASK_STOPPED ...

  10. linux内核学习之三:linux中的32位与64位

    linux内核学习之三:linux中的"32位"与"64位" 在通用PC领域,不论是windows还是linux界,我们都会经常听到"32位" ...

最新文章

  1. 关于静态方法的使用方式
  2. Oracle10g 64bit CentOS5.2_x64 安装手记
  3. leetcode71
  4. 希尔排序(shellsort)算法实现
  5. 微软推Windows 10新内测版 仍以“修复”为特色
  6. memset()函数的赋值问题
  7. linux_base-f10-10_7 linuxulator is not (kld)loaded
  8. Git学习的最佳教程
  9. mysql 表结构监控_性能测试之mysql监控、优化
  10. 如何找到下一个快手头条?赚他个1000万!
  11. pareto解是什么意思_Pareto是什么意思
  12. myeclipse9.1 安装svn(图)
  13. 2021牛客暑期多校训练营3,签到题BEFJ
  14. gvim 命令行粘贴_vim-如何在光标所在的行中粘贴?
  15. php xml 怎么去掉头,PHP如何删除xml某条数据
  16. 错误使用 eig 输入矩阵包含 nan 或 inf_特斯拉AI主管提醒你神经网络的几大常见错误...
  17. alisql mysql_alisql安装步骤
  18. 谈一谈 IPA 上传到 App Store Connect 的几种方法
  19. 基站安全监控管理系统方案
  20. 超级简单的HTML圆形头像css

热门文章

  1. 音视频技术下一个风口在哪里——LiveVideoStackCon 音视频技术大会 2022 上海站演讲剧透...
  2. 高性能视频推理引擎优化技术
  3. 【直播预告 | 今天10:30】多媒体技术 PI 第一期:OSS圆桌
  4. 【大会】技术决策背后的商业逻辑
  5. 音视频技术开发周刊 77期
  6. Java基础之正则表达式
  7. 数据结构与算法之二叉树的序列化和反序列化及判断一棵树是否为平衡二叉树
  8. Ansible之Playbook详解、案例
  9. Vmware Ubuntu 自适应屏幕 进入全屏模式
  10. 【Git】Git 修改刚提交的 commit message