module_param_named 内核启动时模块参数实现原理

基于上节内核启动参数实现原理内容, 其中对early_param的实现流程做了分析, 已基本清晰. 但有不少的参数是在内核模块中声明的, 具体赋值流程也值得一探究竟.

nomodeset

装过Linux系统的同学可能多少有看到过nomodeset这个参数, 解决一些显卡点不亮Linux的问题.

那么这个nomodeset是怎么生效的呢?

在内核代码中查找一下:

[mxd@5 linux-4.19-loongson]$ grep nomodeset -rnIw drivers/video/
drivers/video/console/vgacon.c:116:	pr_warning("You have booted with nomodeset. This means your GPU drivers are DISABLED\n");
drivers/video/console/vgacon.c:118:	pr_warning("Unless you actually understand what nomodeset does, you should reboot without enabling it\n");
drivers/video/console/vgacon.c:124:__setup("nomodeset", text_mode);
drivers/video/fbdev/aty/radeon_base.c:263:static bool nomodeset = 0;
drivers/video/fbdev/aty/radeon_base.c:1472:	if (nomodeset)
drivers/video/fbdev/aty/radeon_base.c:2624:		} else if (!strncmp(this_opt, "nomodeset", 9)) {
drivers/video/fbdev/aty/radeon_base.c:2625:			nomodeset = 1;
drivers/video/fbdev/aty/radeon_base.c:2671:module_param(nomodeset, bool, 0);
drivers/video/fbdev/aty/radeon_base.c:2672:MODULE_PARM_DESC(nomodeset, "bool: disable actual setting of video mode");

drivers/video/console/vgacon.c中有相关声明:

static int __init text_mode(char *str)
{vgacon_text_mode_force = true;pr_warning("You have booted with nomodeset. This means your GPU drivers are DISABLED\n");pr_warning("Any video related functionality will be severely degraded, and you may not even be able to suspend the system properly\n");pr_warning("Unless you actually understand what nomodeset does, you should reboot without enabling it\n");return 1;
}/* force text mode - used by kernel modesetting */
__setup("nomodeset", text_mode);

而关于__setup的定义, 在上节中已经看到过了:

#ifndef MODULE
#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 }
#else /* MODULE */
#define __setup_param(str, unique_id, fn)   /* nothing */
#endif#define __setup(str, fn)                        \__setup_param(str, fn, fn, 0)

上节中的early_param是只在内核中用, 这个可就不好判断了呀.

看一下编译内容:

[mxd@5 linux-4.19-loongson]$ grep vgacon.o -rn drivers/video/console/Makefile
9:obj-$(CONFIG_VGA_CONSOLE)         += vgacon.o
[mxd@5 linux-4.19-loongson]$ cat .config | grep CONFIG_VGA_CONSOLE
CONFIG_VGA_CONSOLE=y

所以, 这个参数还是给内核用的, 但与early_param不同, 他的并不满足early_param的条件:

  1. 如果成员是early类型, 且成员中的变量名与传入的参数名一致
  2. 如果参数名是console, 且成员中的变量名是earlycon时.

还记得有一个obsolete_checksetup吗? 它是在参数未知的情况下注册的:

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;............
}asmlinkage __visible void __init start_kernel(void)
{char *command_line;char *after_dashes;............after_dashes = parse_args("Booting kernel",static_command_line, __start___param,__stop___param - __start___param,-1, -1, NULL, &unknown_bootoption);............
}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;
}

所以nomodeset是在start_kernel时初始化并调用的. 仍然属于内核参数.

radeon.modeset

nomodeset类似, radeon.modeset也是在搭配显卡时安装Linux黑屏的解决方案之一.

radeon的驱动中查找一下看看:

[mxd@5 linux-4.19-loongson]$ grep modeset -rnwI drivers/gpu/drm/radeon/ | grep -v include
drivers/gpu/drm/radeon/trinity_dpm.c:1983:	pi->voltage_drop_in_dce = false; /* need to restructure dpm/modeset interaction */
drivers/gpu/drm/radeon/radeon_kms.c:144:		dev_err(&dev->pdev->dev, "Fatal error during modeset init\n");
drivers/gpu/drm/radeon/radeon_kms.c:150:	/* Call ACPI methods: require modeset init
drivers/gpu/drm/radeon/radeon_connectors.c:195:			/* mode_clock is clock in kHz for mode to be modeset on this connector */
drivers/gpu/drm/radeon/radeon_drv.c:204:MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
drivers/gpu/drm/radeon/radeon_drv.c:205:module_param_named(modeset, radeon_modeset, int, 0400);
drivers/gpu/drm/radeon/radeon_pm.c:281:				/* This can fail if a modeset is in progress */
drivers/gpu/drm/radeon/radeon_pm.c:1565:				 * a modeset to call this.
drivers/gpu/drm/radeon/radeon_display.c:175:	/* XXX match this to the depth of the crtc fmt block, move to modeset? */

可见在drivers/gpu/drm/radeon/radeon_drv.c中通过module_param_namedMODULE_PARM_DESC声明和描述了这个参数.

看看代码:

#define __MODULE_INFO(tag, name, info)                    \
static const char __UNIQUE_ID(name)[]                     \__used __attribute__((section(".modinfo"), unused, aligned(1)))     \= __stringify(tag) "=" info#define __MODULE_PARM_TYPE(name, _type)                   \__MODULE_INFO(parmtype, name##type, #name ":" _type)/* One for each parameter, describing how to use it.  Some files domultiple of these per line, so can't just use MODULE_INFO. */
#define MODULE_PARM_DESC(_parm, desc) \__MODULE_INFO(parm, _parm, #_parm ":" desc)#define module_param_cb(name, ops, arg, perm)                     \__module_param_call(MODULE_PARAM_PREFIX, name, ops, arg, perm, -1, 0)#define __module_param_call(prefix, name, ops, arg, perm, level, flags) \/* Default value instead of permissions? */         \static const char __param_str_##name[] = prefix #name;      \static struct kernel_param __moduleparam_const __param_##name   \__used                              \__attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \= { __param_str_##name, THIS_MODULE, ops,           \VERIFY_OCTAL_PERMISSIONS(perm), level, flags, { arg } }#define module_param_named(name, value, type, perm)            \param_check_##type(name, &(value));                \module_param_cb(name, &param_ops_##type, &value, perm);        \__MODULE_PARM_TYPE(name, #type)

所以radeon.modeset的声明实体就是:

param_check_int(modeset, &(radeon_modeset));
static const char __param_str_modeset[] = radeon.modeset;
static struct kernel_param __moduleparam_const __param_modeset__used __attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) = {__param_str_modeset,radeon,&param_ops_int,VERIFY_OCTAL_PERMISSIONS(0400),-1,0,{&(radeon_modeset)}};
static const char __UNIQUE_ID(modesettype)[]__used __attribute__((section(".modinfo"), unused, aligned(1))) = "parmtype=modeset:int";

类似的, 也是将相关的参数存入指定的section中, 在加载modules时进行初始化及调用. 原理同early_param类似, 所以不再细说.

AI

学习的时候, 没必要把代码全都看得这么细, 除非对算法有研究. 在AI时代, 借助AI分析, 并掌握一个大项目的实现策略的优先级是更高的. 看看AI的说法:

MODULE_PARM_DESC有什么用?

MODULE_PARM_DESC 是 Linux 内核模块编程中的一个宏,用于描述模块参数的意义和用途。当你在内核模块中定义了一个可以由用户空间程序修改的参数时,使用 MODULE_PARM_DESC 宏可以帮助记录这个参数的描述性信息。

当你在模块中定义一个参数时,通常会使用 module_param 或 module_param_array 宏来声明这个参数,并指定它的类型和权限。接着,你可以在同一地方使用 MODULE_PARM_DESC 宏来添加对该参数的描述。

例如:

#include <linux/module.h>
#include <linux/kernel.h>int myparam = 10;
module_param(myparam, int, 0644);
MODULE_PARM_DESC(myparam, "This is a description of the parameter myparam.");

在这个例子中,myparam 参数被声明为整型,权限为 0644(读写权限对所有用户开放),并且有一个描述,告诉用户这个参数的含义。

当你使用 modinfo 命令查询模块信息时,MODULE_PARM_DESC 提供的描述会被显示出来,帮助用户理解参数的作用。这对于调试和配置模块时非常有用,因为用户可以更容易地理解每个参数的功能。

例如,如果你有一个名为 example.ko 的模块,你可以使用以下命令来查看参数信息:

$ modinfo example.ko
filename:       /lib/modules/$(uname -r)/kernel/drivers/example.ko
license:        GPL
description:    Example kernel module
author:         Your Name
srcversion:     1234567890abcdef...
depends:
retpoline:      Y
name:           example
vermagic:       4.19.0-xyz SMP mod_unload
parm:           myparam:This is a description of the parameter myparam. (int)

在 parm: 行中,你会看到 myparam 参数的描述。这样,当用户使用 modprobe 加载模块或使用 insmod 命令手动加载模块并设置参数时,他们可以根据描述来正确地设置参数值。

module_param_named和模块初始化代码的调用顺序是怎样的

在Linux内核模块中,module_param_named宏的使用和模块初始化函数的调用顺序是非常关键的,因为它们决定了模块参数如何被内核识别和处理。以下是典型的调用顺序和工作流程:

模块参数声明与注册:
在模块的源文件中,你需要使用module_param_named(或其他module_param_*宏)来声明模块参数。这些宏会在编译时生成相应的代码,注册参数,并将其关联到一个特定的回调函数,该函数用于处理模块加载或卸载时的参数设置。
这些宏的执行是在编译阶段完成的,它们生成的代码会被链接到模块的.init.text和.data段中。
模块初始化:
模块初始化函数(如init_module或自定义命名的初始化函数)会在模块加载到内核时由内核自动调用。在这之前,内核已经解析了模块信息段(.modinfo),包括所有由module_param_*宏注册的参数信息。
初始化函数可以访问通过module_param_*宏注册的所有参数。这意味着你可以在这个函数中使用这些参数来初始化模块的状态或者配置模块的行为。
参数解析与应用:
当模块加载时,内核会读取传递给模块的命令行参数,并尝试匹配这些参数与模块参数。如果找到了匹配,内核会调用相应的回调函数来设置参数值。
这一过程发生在模块初始化函数被调用之前。因此,当你的模块初始化代码执行时,所有通过命令行传递的参数值已经被设置好了。
模块清理:
类似地,当模块被卸载时,模块的清理函数(如cleanup_module)会被调用。此时,module_param_*宏所注册的参数仍然可用,直到模块完全从内核中移除。
总结来说,module_param_named宏的调用应该在模块初始化函数的定义之前,这样在模块加载时,内核就能正确地解析和设置参数。而模块初始化函数则会在参数设置完成后被调用,此时就可以使用这些参数来配置模块了。

使用

借助modinfo命令:

[root@mxd ~]# modinfo /lib/modules/6.8.6-2/kernel/drivers/gpu/drm/radeon/radeon.ko.zst
......
name:           radeon
vermagic:       6.8.6-2 SMP preempt mod_unload modversions LOONGARCH 64BIT
parm:           no_wb:Disable AGP writeback for scratch registers (int)
parm:           modeset:Disable/Enable modesetting (int)
parm:           dynclks:Disable/Enable dynamic clocks (int)
parm:           r4xx_atom:Enable ATOMBIOS modesetting for R4xx (int)
parm:           vramlimit:Restrict VRAM for testing, in megabytes (int)
......

所以在内核启动时, 可以通过radeon.modeset=0的方式禁用radeon驱动的modesetting.

龙芯的GPU也有相似的功能:

root@loongson-pc:/home/loongson# modinfo /lib/modules/4.19.0-19-loongson-3/kernel/drivers/gpu/drm/gsgpu/gpu/gsgpu.ko
filename:       /lib/modules/4.19.0-19-loongson-3/kernel/drivers/gpu/drm/gsgpu/gpu/gsgpu.ko
license:        GPL and additional rights
description:    GS GPU Driver
author:         Loongson graphics driver team
firmware:       loongson/lg100_cp.bin
alias:          pci:v00000014d00007A25sv*sd*bc*sc*i*
depends:        gpu-sched
intree:         Y
name:           gsgpu
vermagic:       4.19.0-19-loongson-3 SMP mod_unload modversions LOONGARCH 64BIT
parm:           LG100_support:LG100 support (1 = enabled (default), 0 = disabled (int)
parm:           vramlimit:Restrict VRAM for testing, in megabytes (int)
parm:           vis_vramlimit:Restrict visible VRAM for testing, in megabytes (int)
parm:           gartsize:Size of GART to setup in megabytes (32, 64, etc., -1=auto) (uint)
parm:           gttsize:Size of the GTT domain in megabytes (-1 = auto) (int)
parm:           moverate:Maximum buffer migration rate in MB/s. (32, 64, etc., -1=auto, 0=1=disabled) (int)
parm:           benchmark:Run benchmark (int)

所以当龙芯的板卡出问题时, 可以通过gsgpu.LG100_support=0来禁用gsgpu功能.

参考文献

  1. 内核源码
  2. 通义千问

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/41541.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI绘画Stable Diffusion 新手入门教程:万字长文解析Lora模型的使用,快速上手Lora模型!

大家好&#xff0c;我是设计师阿威 今天给大家讲解一下AI绘画Stable Diffusion 中的一个重要模型—Lora模型&#xff0c;如果还有小伙伴没有SD安装包的&#xff0c;可以看我往期入门教程2024最新超强AI绘画Stable Diffusion整合包安装教程&#xff0c;零基础入门必备&#xff…

React Hooks --- 分享自己开发中常用的自定义的Hooks (1)

为什么要使用自定义 Hooks 自定义 Hooks 是 React 中一种复用逻辑的机制&#xff0c;通过它们可以抽离组件中的逻辑&#xff0c;使代码更加简洁、易读、易维护。它们可以在多个组件中复用相同的逻辑&#xff0c;减少重复代码。 1、useThrottle 代码 import React,{ useRef,…

三叶青图像识别研究简概

三叶青图像识别研究总概 文章目录 前言一、整体目录介绍二、前期安排三、构建图像分类数据集四、模型训练准备五、迁移学习模型六、在测试集上评估模型精度七、可解释性分析、显著性分析八、图像分类部署九、树莓派部署十、相关补充总结 前言 本系列文章为近期所做项目研究而作…

工作助手VB开发笔记(2)

今天继续讲功能 2.功能 2.9开机自启 设置程序随windows系统启动&#xff0c;其实就是就是将程序加载到注册表 Public Sub StartRunRegHKLM()REM HKEY_LOCAL_MACHINE \ SOFTWARE \ WOW6432Node \ Microsoft \ Windows \ CurrentVersion \ RunDim strName As String Applicat…

教师商调函流程详解

作为一名教师&#xff0c;您是否曾面临过工作调动的困惑&#xff1f;当您决定迈向新的教育环境&#xff0c;是否清楚整个商调函流程的每一个细节&#xff1f;今天&#xff0c;就让我们一起来探讨这一过程&#xff0c;确保您能够顺利地完成工作调动。 首先需要确定新调入的学校已…

裁员风波中的项目经理,如何自洽?

最近都在担心企业裁员&#xff0c;那么项目经理会不会也有被优化的风险呢&#xff1f; 答案是&#xff0c;一定会&#xff01; 今天从3个方面给大家阐述一下项目经理岗位的发展现状以及未来的趋势 01 项目经理被优化的可能性大吗&#xff1f; 02 哪一类项目经理会被最先裁员…

CSDN导入本地md文件图片不能正常回显问题

标题 搭建图像仓库获取图片URL 路径替换 因为服务器读取不到本地图片&#xff0c;故不能正常回显&#xff0c;因此想要正常回显图片&#xff0c;我们首先要做的就是搭建一个可以存放图片的服务器&#xff0c;像你可以选择购买一个云服务器、FastDFS图片服务器、Minio多云对象存…

信息收集-arping

信息收集-arping 简介 arping 是一个用于发送 ARP 请求和接收 ARP 回复的工具。它通常用于检查网络中的 IP 地址是否被使用&#xff0c;或发现网络中的重复 IP 地址。arping 工具类似于 ping 命令&#xff0c;但它使用的是 ARP 协议而不是 ICMP 协议。在 Kali Linux 中&#…

娱乐圈惊爆已婚男星刘端端深夜幽会

【娱乐圈惊爆&#xff01;已婚男星刘端端深夜幽会&#xff0c;竟是《庆余年》二皇子“戏外风云”】在这个信息爆炸的时代&#xff0c;娱乐圈的每一次风吹草动都能瞬间点燃公众的热情。今日&#xff0c;知名娱乐博主刘大锤的一则预告如同投入湖中的巨石&#xff0c;激起了层层涟…

纸电混合阶段,如何在线上实现纸电会档案的协同管理?

随着国家政策的出台和引导&#xff0c;电子会计档案的管理越来越规范&#xff0c;电子会计档案建设成为打通财务数字化最后一公里的重要一环。但是&#xff0c;当前很多企业的财务管理仍处于电子档案和纸质档案并行的阶段&#xff0c;如何能将其建立合理清晰关联&#xff0c;统…

《数字图像处理-OpenCV/Python》第17章:图像的特征描述

《数字图像处理-OpenCV/Python》第17章&#xff1a;图像的特征描述 本书京东 优惠购书链接 https://item.jd.com/14098452.html 本书CSDN 独家连载专栏 https://blog.csdn.net/youcans/category_12418787.html 第17章&#xff1a;图像的特征描述 特征检测与匹配是计算机视觉的…

javascript v8编译器的使用记录

我的机器是MacOS Mx系列。 一、v8源码下载构建 1.1 下载并更新depot_tools git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git export PATH/path/to/depot_tools:$PATH 失败的话可能是网络问题&#xff0c;可以试一下是否能ping通&#xff0c;连…

【代码随想录_Day25】452. 用最少数量的箭引爆气球 435. 无重叠区间 763. 划分字母区间

Day25 OK&#xff0c;今日份的打卡&#xff01;第二十五天 以下是今日份的总结用最少数量的箭引爆气球无重叠区间划分字母区间 以下是今日份的总结 用最少数量的箭引爆气球无重叠区间划分字母区间 今天的题目难度不低&#xff0c;而且非常的有意思&#xff0c;尽量还是写一些…

imx6ull/linux应用编程学习(11)CAN应用编程基础

关于裸机的can通信&#xff0c;会在其他文章发&#xff0c;这里主要讲讲linux上的can通信。 与I2C,SPI等同步通讯方式不同&#xff0c;CAN通讯是异步通讯&#xff0c;也就是没有时钟信号线来保持信号接收同步&#xff0c;也就是所说的半双工&#xff0c;无法同时发送与接收&…

python项目常见使用的传参调试方法

简介 你是否经常遇到下载的github开源知名项目&#xff0c;不知如何调试&#xff1f;只知道按说明的命令行运行&#xff1f;遇到异常或想改造也无从下手&#xff1f;这篇文档章将指导你如何入手调试别人的大型开源项目。 常见项目使用说明及代码如何调试 常见情况一 使用说…

16.【C语言】初识常见关键字 上

1.关键字由C语言自带&#xff0c;不能自创 2.关键字不作变量名 3.关键字举例&#xff1a; auto自动&#xff1a;每个局部变量都由auto修饰&#xff0c;含义&#xff1a;自动创建&#xff0c;自动销毁 auto int a0;等价于int a0; exturn:申明外部符号 register:寄存器关键字…

数据治理的制胜法宝:筛斗数据技术在现代企业管理中的应用

数据治理的制胜法宝&#xff1a;筛斗数据技术在现代企业管理中的应用 在当今这个数据驱动的时代&#xff0c;企业管理的效率和竞争力越来越依赖于对数据的精准把握和高效利用。然而&#xff0c;随着企业规模的扩大和业务复杂度的增加&#xff0c;数据治理成为了一个亟需解决的…

EasyExcel 单元格根据图片数量动态设置宽度

在使用 EasyExcel 导出 Excel 时&#xff0c;如果某个单元格是图片内容&#xff0c;且存在多张图片&#xff0c;此时就需要单元格根据图片数量动态设置宽度。 经过自己的研究和实验&#xff0c;导出效果如下&#xff1a; 具体代码如下&#xff1a; EasyExcel 版本 <depen…

Haxm安装失败的解决办法

确认你的处理器是否是Intel的&#xff0c;如果是AMD那就无法安装&#xff0c;如果是Intel的&#xff0c;再确认是否支持V1T 如果处理器是Intel的且支持VT&#xff0c;在开机时进入BIOS界面&#xff0c;不同的品牌进入BIOS的方法各不相同&#xff0c;通常是F2/F12/delete些&…

Python爬虫零基础实战,简洁实用!

1.爬虫简介 简单来讲&#xff0c;爬虫就是一个探测机器&#xff0c;它的基本操作就是模拟人的行为去各个网站溜达&#xff0c;点点按钮&#xff0c;查查数据&#xff0c;或者把看到的信息背回来。就像一只虫子在一幢楼里不知疲倦地爬来爬去。 你可以简单地想象&#xff1a;每个…