Linux内核判断大小端,linux kernel 如何处理大小端
暂时在用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 如何处理大小端相关推荐
- linux内核 lts长期演进,Linux Kernel 4.19 将成为下一个LTS(长期支持)系列
最近Linux内核开发人员和维护人员Greg Kroah-Hartman透露,Linux Kernel 4.19将下一个长期支持的Linux内核系列. 现在Linux Kernel 4.17已经达到使 ...
- Linux内核开发_1_编译LInux内核
目录 1. 准备工作 1.1 学习环境 1.2 下载Linux内核源码 1.3 解压Linux内核 1.4 目录结构介绍 2. Linux内核配置 2.1 配置选项 1. make config 2. ...
- 一文了解linux内核,一文了解Linux的系统结构
什么是 Linux ? 如果你以前从未接触过Linux,可能就不清楚为什么会有这么多不同的Linux发行版.在查看Linux软件包时,你肯定被发行版.LiveCD和GNU之类的术语搞晕过.初次进入Li ...
- Linux内核入门-如何获取Linux内核源代码、生成配置内核
如何获取Linux内核源代码 如何获取Linux内核源代码 下载Linux内核当然要去官方网站了,网站提供了两种文件下载,一种是完整的Linux内核,另一种是内核增量补丁,它们都是tar归档压缩包.除 ...
- 搭建《深入Linux内核架构》的Linux环境
搭建<深入Linux内核架构>的Linux环境 阅读目录(Content) 作者 软件 概述 正文 一.安装GCC 二.编译Linux内核 三.制作跟文件系统 四.运行qemu 五.启动l ...
- linux内核启动分析 三,Linux内核分析 实验三:跟踪分析Linux内核的启动过程
贺邦 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 一. 实验过程 ...
- 查看linux内核的编译时间,linux内核编译步骤
linux内核编译步骤 对于linux新手来说,编译内核相对有一些难度,甚至不知道如何入手,我通过在网上收集这方面的资料,最终编译成功.现在我归纳了一下,写出这一篇还算比较详细的步骤,希望能对各位新手 ...
- 【Linux 内核 内存管理】Linux 内核堆内存管理 ① ( 堆内存管理 | 内存描述符 mm_struct 结构体 | mm_struct 结构体中的 start_brk、brk 成员 )
文章目录 一.堆内存管理 二.内存描述符 mm_struct 结构体 三.mm_struct 结构体中的 start_brk.brk 成员 一.堆内存管理 Linux 操作系统中的 " 堆内 ...
- 【Linux 内核】进程管理 ( Linux 内核中的进程状态 | TASK_RUNNING | TASK_INTERRUPTIBLE | __TASK_STOPPED | EXIT_ZOMBIE )
文章目录 一.Linux 内核中的进程状态 二.TASK_RUNNING 状态 三.TASK_RUNNING 状态 四.TASK_UNINTERRUPTIBLE 状态 五.__TASK_STOPPED ...
- linux内核学习之三:linux中的32位与64位
linux内核学习之三:linux中的"32位"与"64位" 在通用PC领域,不论是windows还是linux界,我们都会经常听到"32位" ...
最新文章
- 关于静态方法的使用方式
- Oracle10g 64bit CentOS5.2_x64 安装手记
- leetcode71
- 希尔排序(shellsort)算法实现
- 微软推Windows 10新内测版 仍以“修复”为特色
- memset()函数的赋值问题
- linux_base-f10-10_7 linuxulator is not (kld)loaded
- Git学习的最佳教程
- mysql 表结构监控_性能测试之mysql监控、优化
- 如何找到下一个快手头条?赚他个1000万!
- pareto解是什么意思_Pareto是什么意思
- myeclipse9.1 安装svn(图)
- 2021牛客暑期多校训练营3,签到题BEFJ
- gvim 命令行粘贴_vim-如何在光标所在的行中粘贴?
- php xml 怎么去掉头,PHP如何删除xml某条数据
- 错误使用 eig 输入矩阵包含 nan 或 inf_特斯拉AI主管提醒你神经网络的几大常见错误...
- alisql mysql_alisql安装步骤
- 谈一谈 IPA 上传到 App Store Connect 的几种方法
- 基站安全监控管理系统方案
- 超级简单的HTML圆形头像css