Linux内核__setup()宏介绍

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux内核__setup()宏介绍相关的知识,希望对你有一定的参考价值。

参考技术A

Linux 内核中可使用宏 __setup() 处理内核的启动参数 cmdline 的解析。

文件: include/linux/init.h

定义:

通过宏展开可以看出:宏 __setup() 主要是定义了一个 obs_kernel_param 类型的结构体变量 __setup_fn 。

以 RockPI 4A 单板 Debian 系统 Linux 4.4 内核为例,介绍 init 参数的解析方法。

1、cmdline参数

在 Debian 系统中,通过 extlinux.conf 文件传递启动参数,其中 init=/sbin/init ,如下:

2、__setup()宏定义

在 Linux 内核中,解析 init 参数的 __setup() 实现如下:

3、__setup()宏展开

展开宏 __setup("init=", init_setup) ,即:

内核编译完成后,在内核符号表 System.map 文件中,可以看到 __setup_init_setup :

4、函数调用流程

内核启动后, init_setup() 函数的调用流程如下:

linux内核中的宏ffs(x)

转自:https://www.cnblogs.com/fengeryi/p/3449720.html

linux内核中ffs(x)宏是平台相关的宏,在arm平台,该宏定义在

arch/arm/include/asm/bitops.h

#define ffs(x) ({ unsigned long __t = (x); fls(__t & -__t); })
复制代码
static inline int fls(int x)
{
    int ret;

    if (__builtin_constant_p(x))
           return constant_fls(x);

    asm("clz\\t%0, %1" : "=r" (ret) : "r" (x) : "cc");
           ret = 32 - ret;
    return ret;
}
复制代码

__t & -__t   等于找到__t 第一个为1的位(从低位开始),并把该位保留为1其余位清0. 

例如 一32位整形数 6,用二进制表示它的低8位:00000110,  都知道负数为最高为1其余位取反加1.-6即 11111010

相与得 00000010,即6&-6. 把该值传递给函数fls().

再看fls函数.

if (__builtin_constant_p(x))
           return constant_fls(x);

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

如果是常数就用下面函数计算00000010中1的位置

复制代码
static inline int constant_fls(int x)
{
    int r = 32;

    if (!x)
        return 0;
    if (!(x & 0xffff0000u)) {
        x <<= 16;
        r -= 16;
    }
    if (!(x & 0xff000000u)) {
        x <<= 8;
        r -= 8;
    }
    if (!(x & 0xf0000000u)) {
        x <<= 4;
        r -= 4;
    }
    if (!(x & 0xc0000000u)) {
        x <<= 2;
        r -= 2;
    }
    if (!(x & 0x80000000u)) {
        x <<= 1;
        r -= 1;
    }
    return r;
}
复制代码

算法就是折半法,这个函数计算的是从高位起第一个1位的位置.00000010, r=2.  由于__t&-__t只有一个1,所以就是找到该1的位置.

如果输入参数是00001010 那么 r=4.

如果参数是变量,直接使用arm指令运算.

执行   asm("clz\\t%0, %1" : "=r" (ret) : "r" (x) : "cc");
           ret = 32 - ret;
CLZ(Count Leading Zeros)指令对Rm中值的高位(leading zeros)个数进行计数,结果放到Rd中。若源寄存器全为0,则结果为32。若[31]为1,则结果为0。

clz指令计算高位0的个数, 然后拿32-ret 算出1的位置.

 

所以,ffs(x)这个宏的值就是x的第一个1的位置(从低位开始,数值从1开始,0代表x全0).

 

 

另外,该文件中还有很多linux关于位操作的函数,可以作为自己写应用程序时的有用参考.

以上是关于Linux内核__setup()宏介绍的主要内容,如果未能解决你的问题,请参考以下文章

Linux __setup解析

Linux内核中的常用宏container_of

linux内核中的offsetof与container_of宏

linux内核段属性机制

Linux 内核中 likely 与 unlikely 的宏定义解析

内核中对cmdline的解析