Linux内核(11) - 子系统的初始化之内核选项解析

首先感谢国家。其次感谢上大的钟莉颖,让我知道了大学不仅有校花,还有校鸡,而且很多时候这两者其实没什么差别。最后感谢清华女刘静,让我深刻体会到了素质教育的重要性,让我感到有责任写写子系统的初始化。

各个子系统的初始化是内核整个初始化过程必然要完成的基本任务,这些任务按照固定的模式来处理,可以归纳为两个部分:内核选项的解析以及那些子系统入口(初始化)函数的调用。

内核选项

Linux允许用户传递内核配置选项给内核,内核在初始化过程中调用parse_args函数对这些选项进行解析,并调用相应的处理函数。

parse_args函数能够解析形如“变量名=值”的字符串,在模块加载时,它也会被调用来解析模块参数。

内核选项的使用格式同样为“变量名=值”,打开系统的grub文件,然后找到kernel行,比如:

kernel  /boot/vmlinuz-2.6.18 root=/dev/sda1 ro splash=silent vga=0x314 pci=noacpi

其中的“pci=noacpi”等都表示内核选项。

内核选项不同于模块参数,模块参数通常在模块加载时通过“变量名=值”的形式指定,而不是内核启动时。如果希望在内核启动时使用模块参数,则必须添加模块名做为前缀,使用“模块名.参数=值”的形式,比如,使用下面的命令在加载usbcore时指定模块参数autosuspend的值为2。

$ modprobe usbcore autosuspend=2

若是在内核启动时指定,则必须使用下面的形式:

usbcore.autosuspend=2

从Documentation/kernel-parameters.txt文件里可以查询到某个子系统已经注册的内核选项,比如PCI子系统注册的内核选项为:
 pci=option[,option...] [PCI] various PCI subsystem options:
    off  [X86-32] don‘t probe for the PCI bus
    bios  [X86-32] force use of PCI BIOS, don‘t access
        the hardware directly. Use this if your machine
        has a non-standard PCI host bridge.
    nobios  [X86-32] disallow use of PCI BIOS, only direct
        hardware access methods are allowed. Use this
        if you experience crashes upon bootup and you
        suspect they are caused by the BIOS.
    conf1  [X86-32] Force use of PCI Configuration
        Mechanism 1.
    conf2  [X86-32] Force use of PCI Configuration
        Mechanism 2.
    nommconf [X86-32,X86_64] Disable use of MMCONFIG for PCI
        Configuration
    nomsi  [MSI] If the PCI_MSI kernel config parameter is
        enabled, this kernel boot option can be used to
        disable the use of MSI interrupts system-wide.
    nosort  [X86-32] Don‘t sort PCI devices according to
        order given by the PCI BIOS. This sorting is
        done to get a device order compatible with
        older kernels.
    biosirq  [X86-32] Use PCI BIOS calls to get the interrupt
        routing table. These calls are known to be buggy
        on several machines and they hang the machine
        when used, but on other computers it‘s the only
        way to get the interrupt routing table. Try
        this option if the kernel is unable to allocate
        IRQs or discover secondary PCI buses on your
        motherboard.
    rom  [X86-32] Assign address space to expansion ROMs.
        Use with caution as certain devices share
        address decoders between ROMs and other
        resources.
    irqmask=0xMMMM [X86-32] Set a bit mask of IRQs allowed to be
        assigned automatically to PCI devices. You can
        make the kernel exclude IRQs of your ISA cards
        this way.
    pirqaddr=0xAAAAA [X86-32] Specify the physical address
        of the PIRQ table (normally generated
        by the BIOS) if it is outside the
        F0000h-100000h range.
    lastbus=N [X86-32] Scan all buses thru bus #N. Can be
        useful if the kernel is unable to find your
        secondary buses and you want to tell it
        explicitly which ones they are.
    assign-busses [X86-32] Always assign all PCI bus
        numbers ourselves, overriding
        whatever the firmware may have done.
    usepirqmask [X86-32] Honor the possible IRQ mask stored
        in the BIOS $PIR table. This is needed on
        some systems with broken BIOSes, notably
        some HP Pavilion N5400 and Omnibook XE3
        notebooks. This will have no effect if ACPI
        IRQ routing is enabled.
    noacpi  [X86-32] Do not use ACPI for IRQ routing
        or for PCI scanning.
    routeirq Do IRQ routing for all PCI devices.
        This is normally done in pci_enable_device(),
        so this option is a temporary workaround
        for broken drivers that don‘t call it.
    firmware [ARM] Do not re-enumerate the bus but instead
        just use the configuration from the
        bootloader. This is currently used on
        IXP2000 systems where the bus has to be
        configured a certain way for adjunct CPUs.
    noearly  [X86] Don‘t do any early type 1 scanning.
        This might help on some broken boards which
        machine check when some devices‘ config space
        is read. But various workarounds are disabled
        and some IOMMU drivers will not work.
    bfsort  Sort PCI devices into breadth-first order.
        This sorting is done to get a device
        order compatible with older (<= 2.4) kernels.
    nobfsort Don‘t sort PCI devices into breadth-first order.
    cbiosize=nn[KMG] The fixed amount of bus space which is
        reserved for the CardBus bridge‘s IO window.
        The default value is 256 bytes.
    cbmemsize=nn[KMG] The fixed amount of bus space which is
        reserved for the CardBus bridge‘s memory
        window. The default value is 64 megabytes.

注册内核选项

就像我们不需要明白钟莉颖是如何走上校鸡的修炼之道,我们也不必理解parse_args函数的实现细节。但我们必须知道如何注册内核选项:模块参数使用module_param系列的宏注册,内核选项则使用__setup宏来注册。

__setup宏在include/linux/init.h文件中定义。

171 #define __setup(str, fn)     /
172   __setup_param(str, fn, fn, 0)

__setup需要两个参数,其中str是内核选项的名字,fn是该内核选项关联的处理函数。__setup宏告诉内核,在启动时如果检测到内核选项str,则执行函数fn。str除了包括内核选项名字之外,必须以“=”字符结束。

不同的内核选项可以关联相同的处理函数,比如内核选项netdev和ether都关联了netdev_boot_setup函数。

除了__setup宏之外,还可以使用early_param宏注册内核选项。它们的使用方式相同,不同的是,early_param宏注册的内核选项必须要在其他内核选项之前被处理。

两次解析

相应于__setup宏和early_param宏两种注册形式,内核在初始化时,调用了两次parse_args函数进行解析。

parse_early_param();
parse_args("Booting kernel", static_command_line, __start___param,
    __stop___param - __start___param,
           &unknown_bootoption);

parse_args的第一次调用就在parse_early_param函数里面,为什么会出现两次调用parse_args的情况?这是因为内核选项又分成了两种,就像现实世界中的我们,一种是普普通通的,一种是有特权的,有特权的需要在普通选项之前进行处理。

现实生活中特权的定义好像很模糊,不同的人有不同的诠释,比如哈医大二院的纪委书记在接受央视的采访“老人住院费550万元”时如是说:“我们就是一所人民医院……就是一所贫下中农的医院,从来不用特权去索取自己身外的任何利益……我们不但没有多收钱还少收了。”
人生就是如此的复杂和奇怪。内核选项相对来说就要单纯得多,特权都是阳光下的,不会藏着掖着,直接使用early_param宏去声明,让你一眼就看出它是有特权的。使用early_param声明的那些选项就会首先由parse_early_param去解析。

原文地址:https://www.cnblogs.com/alantu2018/p/8448813.html

时间: 2024-10-07 07:56:29

Linux内核(11) - 子系统的初始化之内核选项解析的相关文章

Linux内核(12) - 子系统的初始化之那些入口函数

内核选项的解析完成之后,各个子系统的初始化即进入第二部分-入口函数的调用.通常USB.PCI这样的子系统都会有一个名为subsys_initcall的入口,如果你选择它们作为研究内核的切入点,那么就请首先找到它. 朱德庸在<关于上班这件事>里说,要花前半生找入口,花后半生找出口.可见寻找入口对于咱们这一生,对于看内核代码这件事儿都是无比重要的. 但是很多时候,入口并不仅仅只有subsys_initcall一个,比如PCI. 117 #define pure_initcall(fn)      

Linux内核(13) - 子系统的初始化之以PCI子系统为例

由Kconfig这张地图的分布来看,PCI这块儿的代码应该分布在两个地方,drivers/pci和arch/i386/pci,两岸三地都属于一个中国,不管是drivers/pci那儿的,还是arch/i386/pci那儿的,也都只属于一个PCI子系统,本着一个中国的原则,咱们要统筹的全面的考察分析位于两个地方的代码,于是,这些远远突破了五位数的代码左看右看横看竖看都显得那么的阴森恐怖,不过人家咋说也是整个一PCI子系统,就像走在T台上的芙蓉姐姐和杨二车那姆一样,看起来恐怖但也是很有内涵的,岂能够

Linux 内核无线子系统

Linux 内核无线子系统 浅谈 Linux 内核无线子系统 Table of Contents 1. 全局概览 2. 模块间接口 3. 数据路径与管理路径 4. 数据包是如何被发送? 5. 谈谈管理路径 6. 数据包又是如何被接收? 7. 总结一下 Linux 内核是如何实现无线网络接口呢?数据包是通过怎样的方式被发送和接收呢?刚开始工作接触 Linux 无线网络时,我曾迷失在浩瀚的基础代码中,寻找具有介绍性的材料来回答如上面提到的那些高层次的问题.跟踪探索了一段时间的源代码后,我写下了这篇总

linux内核DCB子系统

网络设备是怎么利用linux内核的DCB子系统,来达到融合网络流量的各种各样的QoS需求的?融合网卡或者存储流量是否也可以使用到DCB子系统的,他们是怎样工作的?本文将对上面这两个问题进行解答:本文首先大体介绍了DCB机制和它的使用环境:然后介绍一个使用DCB的应用程序lldpad的例子:再然后介绍一个DCB子系统中重要的数据结构:最后介绍DCB内核模块和驱动的具体实现. Overview 在整个DCB过程中,是要把各种各样的流量,可能是FCoE流量,可能是一般的TCP流量,还可能是其他的视频流

Linux 0.11 内核学习之main.c

1.之所以选择这么低的版本学习,答案是简单,高版本的代码量太大,对于我这样的初学者来说,就是瞎子摸象不会有什么感觉.开始吧! 2首先你需要在一个地方下载源码:OldLinux 3.分析: 1 /* 2 * linux/init/main.c 3 * 4 * (C) 1991 Linus Torvalds 5 */ 6 7 #define __LIBRARY__ //在unistd.h中,使用了#ifndef __LIBRARY__ 8 #include <unistd.h> //包含units

(转)浅谈 Linux 内核无线子系统

前言 Linux 内核是如何实现无线网络接口呢?数据包是通过怎样的方式被发送和接收呢? 刚开始工作接触 Linux 无线网络时,我曾迷失在浩瀚的基础代码中,寻找具有介绍性的材料来回答如上面提到的那些高层次的问题. 跟踪探索了一段时间的源代码后,我写下了这篇总结,希望在 Linux 无线网络的工作原理上,读者能从这篇文章获得一个具有帮助性的概览. 1.全局概览 在开始探索 Linux 无线具体细节之前,让我们先来把握一下 Linux 无线子系统整体结构.如图1,展示了 Linux 无线子系统各个模

ubuntn 内核升级到LINUX v4.11.8:

升级到LINUX v4.11.8: http://kernel.ubuntu.com/~kernel-ppa/mainline/v4.11.8/linux-headers-4.11.8-041108_4.11.8-041108.201706290836_all.deb http://kernel.ubuntu.com/~kernel-ppa/mainline/v4.11.8/linux-headers-4.11.8-041108-generic_4.11.8-041108.20170629083

linux子系统的初始化_subsys_initcall()【转】

转自:http://my.oschina.net/u/572632/blog/305492 目录[-] 概述 section的声明 注册 调用 IN BUILDING 概述 内核选项的解析完成之后,各个子系统的初始化即进入第二部分—入口函数的调用.通常USB.PCI这样的子系统都会有一个名为subsys_initcall的入口,如果你选择它们作为研究内核的切入点,那么就请首先找到它. section的声明 C 语言中attribute属性的section是在目标文件链接时可以用于主动定制代码的位

linux子系统的初始化_subsys_initcall():那些入口函数【转】

内核选项的解析完成之后,各个子系统的初始化即进入第二部分—入口函数的调用.通常USB.PCI这样的子系统都会有一个名为subsys_initcall的入口,如果你选择它们作为研究内核的切入点,那么就请首先找到它. 朱德庸在<关于上班这件事>里说,要花前半生找入口,花后半生找出口.可见寻找入口对于咱们这一生,对于看内核代码这件事儿都是无比重要的. 但是很多时候,入口并不仅仅只有subsys_initcall一个,比如PCI. 以下代码来自 linux内核源码中 include/linux/ini