当前位置: 首页 > news >正文

Linux内核__setup 宏的作用及分析

目录

简介:

一、__setup() 分析

1、__setup() 展开

2、init.setup 段定义

3、init.setup 段内容如何被调用

4、Linux中如何使用 __setup()

二、__setup() 示例


简介:


        __setup 宏的作用是将命令行参数与处理函数绑定,在Linux启动时匹配 cmdline 命令行参数则调用绑定的函数处理这些参数。‌

一、__setup() 分析


1、__setup() 展开


Linux中__setup()宏源码如下:

/* 路径:include/linux/init.h */
struct obs_kernel_param {const char *str;int (*setup_func)(char *);int early;
};/** Only for really core code.  See moduleparam.h for the normal way.** Force the alignment so the compiler doesn't space elements of the* obs_kernel_param "array" too far apart in .init.setup.*/
#define __setup_param(str, unique_id, fn, early)			\static const char __setup_str_##unique_id[] __initconst		\__aligned(1) = str; 					\static struct obs_kernel_param __setup_##unique_id		\__used __section(.init.setup)				\__attribute__((aligned((sizeof(long)))))		\= { __setup_str_##unique_id, fn, early }#define __setup(str, fn)						\__setup_param(str, fn, fn, 0)

以 __setup("test_setup=", test_setup_cmdline) 为例,展开后:

static const char __setup_str_test_setup_cmdline[] __initconst __aligned(1) = "test_setup=";       
static struct obs_kernel_param __setup_test_setup_cmdline __used __section(.init.setup) __attribute__((aligned((sizeof(long))))) = { __setup_str_test_setup_cmdline, test_setup_cmdline, 0 }

其实就是在 init.setup 段中定义了 static struct obs_kernel_param 结构体,如下:

/* init.setup段定义此结构体 */
static struct obs_kernel_param __setup_test_setup_cmdline = {.str = "test_setup=",.setup_func = __setup_str_test_setup_cmdline,.early = 0,
}

2、init.setup 段定义


init.setup段定义在 include/asm-generic/vmlinux.lds.h 文件中

#define INIT_SETUP(initsetup_align)					\. = ALIGN(initsetup_align);				\__setup_start = .;					\KEEP(*(.init.setup))					\__setup_end = .;

init.setup段位于 __setup_start 到 __setup_end 之间。

3、init.setup 段内容如何被调用


Linux启动后代码运行流程如下:

/* 路径:init/main.c */
start_kernel()
--->parse_early_param()
--->parse_args()
--->--->parse_one()
--->--->--->unknown_bootoption()
--->--->--->--->obsolete_checksetup()
--->--->--->--->--->setup_func()   //调用obs_kernel_param定义的setup_func(),即init_setup()
--->--->--->--->--->--->init_setup()

__setup() 设置 obs_kernel_param.early 为0,因此不会被 parse_early_param() 解析。init.setup段数据在 parse_args() 函数中被处理,直接看下 parse_one() 会调用 unknown_bootoption 处理 __setup() 定义的数据。

/* parse_args 调用 parse_one()函数 */
after_dashes = parse_args("Booting kernel",static_command_line, __start___param,__stop___param - __start___param,-1, -1, NULL, &unknown_bootoption);/* kernel/params.c */
static int parse_one(char *param,char *val,const char *doing,const struct kernel_param *params,unsigned num_params,s16 min_level,s16 max_level,void *arg,int (*handle_unknown)(char *param, char *val,const char *doing, void *arg))
{unsigned int i;int err;/* 处理 __start___param - __stop___param 段的数据 */for (i = 0; i < num_params; i++) {if (parameq(param, params[i].name)) {if (params[i].level < min_level|| params[i].level > max_level)return 0;/* No one handled NULL, so do it here. */if (!val &&!(params[i].ops->flags & KERNEL_PARAM_OPS_FL_NOARG))return -EINVAL;pr_debug("handling %s with %p\n", param,params[i].ops->set);kernel_param_lock(params[i].mod);if (param_check_unsafe(&params[i]))err = params[i].ops->set(val, &params[i]);elseerr = -EPERM;kernel_param_unlock(params[i].mod);return err;}}/* 处理其他数据 */if (handle_unknown) {pr_debug("doing %s: %s='%s'\n", doing, param, val);return handle_unknown(param, val, doing, arg);}pr_debug("Unknown argument '%s'\n", param);return -ENOENT;
}

因为 __setup() 定义的 struct obs_kernel_param 结构体放在 __setup_start - __setup_end,因此最终__setup() 的内容由 unknown_bootoption() 函数处理。

/** Unknown boot options get handed to init, unless they look like* unused parameters (modprobe will find them in /proc/cmdline).*/
static int __init unknown_bootoption(char *param, char *val,const char *unused, void *arg)
{repair_env_string(param, val, unused, NULL);/* Handle obsolete-style parameters */if (obsolete_checksetup(param))return 0;/* Unused module parameter. */if (strchr(param, '.') && (!val || strchr(param, '.') < val))return 0;if (panic_later)return 0;if (val) {/* Environment option */unsigned int i;for (i = 0; envp_init[i]; i++) {if (i == MAX_INIT_ENVS) {panic_later = "env";panic_param = param;}if (!strncmp(param, envp_init[i], val - param))break;}envp_init[i] = param;} else {/* Command line option */unsigned int i;for (i = 0; argv_init[i]; i++) {if (i == MAX_INIT_ARGS) {panic_later = "init";panic_param = param;}}argv_init[i] = param;}return 0;
}

unknown_bootoption() 调用 obsolete_checksetup() 处理 __setup() 的内容。

static bool __init obsolete_checksetup(char *line)
{const struct obs_kernel_param *p;bool had_early_param = false;p = __setup_start;do {int n = strlen(p->str);if (parameqn(line, p->str, n)) {if (p->early) {/* Already done in parse_early_param?* (Needs exact match on param part).* Keep iterating, as we can have early* params and __setups of same names 8( */if (line[n] == '\0' || line[n] == '=')had_early_param = true;} else if (!p->setup_func) {pr_warn("Parameter %s is obsolete, ignored\n",p->str);return true;} else if (p->setup_func(line + n))return true;}p++;} while (p < __setup_end);return had_early_param;
}

obsolete_checksetup() 会遍历 __setup_start 到 __setup_end 保存的 obs_kernel_param 结构体,将 obs_kernel_param.str 和 cmdline中的参数进行匹配,相等就调用 obs_kernel_param.setup_func()。

4、Linux中如何使用 __setup()


cmdline 中的 "console=ttyS0" 表示使用 ttyS0 作为控制台。在 kernel/printk/printk.c 中调用了

__setup("console=", console_setup);

Linux内核启动时,如果命令行中出现 console= 参数,内核就会调用 console_setup 函数来处理这个参数。例如,如果命令行为 console=ttyS0,115200n8 内核就会将控制台设置为 ttyS0,并设置相应的波特率和参数‌。

二、__setup() 示例


Linux内核中模块使用 __setup() 可以解析 cmdline 传递的参数信息,进而对模块功能进行定制化的配置。

static int test_setup_value = 0;
static __init int test_setup_cmdline(char *str)
{if (!str)return -EINVAL;if (!strncmp(str, "ON", 2)) {test_setup_value = 1;} else if (!strncmp(str, "OFF", 3)) {test_setup_value = 0;}pr_info("test_setup_value = %d\n", test_setup_value);return 1;
}__setup("test_setup=", test_setup_cmdline);

如果cmdline命令行中含有 "test_setup=ON" 内容,会执行 test_setup_cmdline()函数,将 "test_setup=" 后面的 "ON" 作为 test_setup_cmdline() 函数的入参。



http://www.mrgr.cn/news/79120.html

相关文章:

  • CNCF云原生生态版图
  • Linux——进程控制模拟shell
  • Nginx 缓存那些事儿:原理、配置和最佳实践
  • linux快捷命令收集
  • leetcode108.将有序数组转换为二叉搜索树
  • 深入解析下oracle的number底层存储格式
  • [go-redis]客户端的创建与配置说明
  • ansible自动化运维(二)ad-hoc模式
  • 网络层总结
  • 基于TensorFlow框架的线性回归实现
  • AI处理器组合--华为OD机试2024年E卷
  • 两个畸变矩阵相乘后还是一个2*2的矩阵,有四个畸变元素。1、畸变矩阵吸收了法拉第矩阵。2、畸变矩阵也给法拉第旋转角带来模糊(求解有多种可能)
  • Scala:正则表达式
  • Transformers在计算机视觉领域中的应用【第3篇:Swin Transformer——多层次的Vision Transformer】
  • 快速上手 RabbitMQ:使用 Docker 轻松搭建消息队列系统
  • JS中的浅拷贝,深拷贝和引用
  • 【JuMP.jl】非线性规划
  • 项目开发之Jenkins
  • React第十二节组件之间通讯之发布订阅模式(使用pubsub-js插件)
  • FFmpeg:强大的音视频处理工具指南
  • 鸿蒙 Next 可兼容运行 Android App,还支持出海 GMS?
  • 每日速记10道java面试题13
  • 365天深度学习训练营-第P7周:马铃薯病害识别(VGG-16复现)
  • 知乎大数据开发面试题及参考答案
  • AI大模型原理
  • 重生之我在异世界学编程之C语言:选择结构与循环结构篇