1. 如何调整linux内核启动中的驱动初始化顺序
【问题】 此处我要实现的是将芯片的ID用于网卡MAC地址,网卡驱动是enc28j60_init。 但是,读取芯片ID的函数,在as352x_afe_init模块中,所以要先初始化as352x_afe_init。 此处,内核编译完之后,在生成的system.map中可以看到, enc28j60_init在as352x_afe_init之前,所以,无法去读芯片ID。 所以我们的目标是,将as352x_afe_init驱动初始化放到enc28j60_init之前, 然后才能读取芯片ID,才能用于网卡初始化的时候的,将芯片ID设置成网卡MAC地址。
【解决过程】
【1】
最简单想到的,是内核里面的
archarmmach-as352xcore.c
中,去改devices设备列表中的顺序。
enc28j60_init对应的是ssp_device,因为网卡初始化用到的是SPI驱动去进行和通讯的。
as352x_afe_init对应的是afe_device。
原先是:
把afe改到最前面:
但是,实际结果是,没有任何影响,连systemp.map生成的,那么模块初始化顺序,都没有任何变化。 也就说明,想要实现驱动加载顺序的改变,改core.c里面的设备列表顺序是没有用的。
更多linux内核视频教程文档资料免费领取后台私信 【内核】 自行获取.
Linux内核源码/内存调优/文件系统/进程管理/设备驱动/网络协议栈-学习视频教程-腾讯课堂
【2】
在网上看到很多帖子,其说明的也很清楚了,就是:
Linux内核为不同驱动的加载顺序对应不同的优先级,定义了一些宏:
includelinuxinit.h
把自己的驱动的函数名用这些宏去定义之后, 就会对应不同的加载时候的优先级。
其中,我们写驱动中所用到的mole_init对应的是 #define mole_init(x) __initcall(x); 而 #define __initcall(fn) device_initcall(fn) 所以,驱动对应的加载的优先级为6
在上面的不同的优先级中, 数字越小,优先级越高。 同一等级的优先级的驱动,加载顺序是链接过程决定的,结果是不确定的,我们无法去手动设置谁先谁后。 不同等级的驱动加载的顺序是先优先级高,后优先级低,这是可以确定的。
所以,像我们之前在驱动中用:
所以,大家都是同一个优先级去初始化,
最后这些驱动加载的顺序,可以查看在根目录下,
生成的system.map:
此处就是由于 c0019920 t __initcall_i2c_dev_init6 c0019924 t __initcall_as352x_afe_i2c_init6 c0019928 t __initcall_as352x_afe_init6 在c00198e4 t __initcall_enc28j60_init6之前,所以我这里才要去改。。。 知道原理,能想到的,就是要么把as352x_afe_init改到enc28j60_init之前一级,即优先级为5。即在驱动中,调用:fs_initcall(as352x_afe_init);要么把enc28j60_init改到as352x_afe_init之后,即优先级为7即在驱动中,调用:late_initcall(enc28j60_init);但是,此处麻烦就麻烦在,如果把as352x_afe_init改到enc28j60_init之前一级,发现后面网卡初始化enc28j60_init中,虽然读取芯片ID对了,但是后面的IP-auto configure 有问题。所以放弃。 如果把enc28j60_init改到as352x_afe_init之后,但是,从system.map中看到的是,优先级为7的驱动中,明显有几个驱动,也是和网卡初始化相关的,所以,这样改,尝试后,还是失败了。 所以,没法简单的通过调整现有的驱动的顺序,去实现顺序的调整。最后,被逼无奈,想到了一个可以实现我们需求的办法,那就是,单独定义一个优先级,把afe相关的初始化都放到那里面去,这样,就可以保证,其他没什么相关的冲突了。最后证实,这样是可以实现目的的。
具体添加一个新的优先级的步骤如下: 1.定义新的优先级 includelinuxinit.h中:
2.用对应新的宏,定义我们的驱动:
做到这里,本以为可以了,但是编译后,在system.map中,发现之前优先级为7的那几个函数,被放到system.map最后了,而不是预想的,在优先级7之后,在
之前。最后,发现时没有把对应的链接文件中的宏加进去:
3.includeasm-genericvmlinux.lds.h
最后,再重新编译,就可以实现我们要的,和afe相关的驱动初始化,都在网卡enc28j60_init之前了。也就可以在网卡里面读芯片ID了。当然,对应编译生成的system.map文件中,对应的通过mole_init定义的驱动,优先级也都变成7了。而late_initcall对应优先级8了。 注:当前开发板arm的板子,所以,对应的load 脚本在:
linux-2.6.28.4archarmkernelvmlinux.lds 看起来,应该是这个文件: linux-2.6.28.4archarmkernelvmlinux.lds.S 生成上面那个脚本的。vmlinux.lds中的这一行:
就是将之前那些对应的init类型的函数,展开,放到这对应的位置。
【3】 不过,最后的最后,竟然发现网卡还是工作不正常,结果第二天,无意间发现是网卡地址设置导致网卡工作不正常的。 也就是说,实际是直接将afe设置到原先的优先级5就可以的,而不用这么麻烦去改系统的东西的...
不过,至少这也是一种办法,虽然不是那么的好...
2. Linux系统开机时启动内核步骤是什么
实模式,并开始执行位于地址0xFFFF0处
的代码,也就是ROM-BIOS起始位置的代码。BIOS先进行一系列的系统自检,然后初始化位
于地址0的中断向量表。最后BIOS将启动盘的第一个扇区装入到0x7C00,并开始执行此处
的代码。这就是对内核初始化过程的一个最简单的描述。
最初,linux核心的最开始部分是用8086汇编语言编写的。当开始运行时,核心将自
己装入到绝对地址0x90000,再将其后的2k字节装入到地址0x90200处,最后将核心的其余
部分装入到0x10000。
当系统装入时,会显示Loading...信息。装入完成后,控制转向另一个实模式下的汇
编语言代码boot/Setup.S。Setup部分首先设置一些系统的硬件设备,然后将核心从
0x10000处移至0x1000处。这时系统转入保护模式,开始执行位于0x1000处的代码。
接下来是内核的解压缩。0x1000处的代码来自于文件Boot/head.S,它用来初始化寄
存器和调用decompress_kernel( )程序。decompress_kernel( )程序由Boot/inflate.c,
Boot/unzip.c和Boot../misc.c组成。解压缩后的数据被装入到了0x100000处,这也是
linux不能在内存小于2M的环境下运行的主要原因。
解压后的代码在0x1010000处开始执行,紧接着所有的32位的设置都将完成: IDT、
GDT和LDT将被装入,处理器初始化完毕,设置好内存页面,最终调用start_kernel过程。
这大概是整个内核中最为复杂的部分。
[系统开始运行]
linux kernel 最早的C代码从汇编标记startup_32开始执行
startup_32:
start_kernel
lock_kernel
trap_init
init_IRQ
sched_init
softirq_init
time_init
console_init
#ifdef CONFIG_MODULES
init_moles
#endif
kmem_cache_init
sti
calibrate_delay
mem_init
kmem_cache_sizes_init
pgtable_cache_init
fork_init
proc_caches_init
vfs_caches_init
buffer_init
page_cache_init
signals_init
#ifdef CONFIG_PROC_FS
proc_root_init
#endif
#if defined(CONFIG_SYSVIPC)
ipc_init
#endif
check_bugs
smp_init
rest_init
kernel_thread
unlock_kernel
cpu_idle
・startup_32 [arch/i386/kernel/head.S]
・start_kernel [init/main.c]
・lock_kernel [include/asm/smplock.h]
・trap_init [arch/i386/kernel/traps.c]
・init_IRQ [arch/i386/kernel/i8259.c]
・sched_init [kernel/sched.c]
・softirq_init [kernel/softirq.c]
・time_init [arch/i386/kernel/time.c]
・console_init [drivers/char/tty_io.c]
・init_moles [kernel/mole.c]
・kmem_cache_init [mm/slab.c]
・sti [include/asm/system.h]
・calibrate_delay [init/main.c]
・mem_init [arch/i386/mm/init.c]
・kmem_cache_sizes_init [mm/slab.c]
・pgtable_cache_init [arch/i386/mm/init.c]
・fork_init [kernel/fork.c]
・proc_caches_init
・vfs_caches_init [fs/dcache.c]
・buffer_init [fs/buffer.c]
・page_cache_init [mm/filemap.c]
・signals_init [kernel/signal.c]
・proc_root_init [fs/proc/root.c]
・ipc_init [ipc/util.c]
・check_bugs [include/asm/bugs.h]
・smp_init [init/main.c]
・rest_init
・kernel_thread [arch/i386/kernel/process.c]
・unlock_kernel [include/asm/smplock.h]
・cpu_idle [arch/i386/kernel/process.c]
start_kernel( )程序用于初始化系统内核的各个部分,包括:
*设置内存边界,调用paging_init( )初始化内存页面。
*初始化陷阱,中断通道和调度。
*对命令行进行语法分析。
*初始化设备驱动程序和磁盘缓冲区。
*校对延迟循环。
最后的function'rest_init' 作了以下工作:
・开辟内核线程'init'
・调用unlock_kernel
・建立内核运行的cpu_idle环, 如果没有调度,就一直死循环
实际上start_kernel永远不能终止.它会无穷地循环执行cpu_idle.
最后,系统核心转向move_to_user_mode( ),以便创建初始化进程(init)。此后,进程0开始进入无限循环。
初始化进程开始执行/etc/init、/bin/init 或/sbin /init中的一个之后,系统内核就不再对程序进行直接控制了。之后系统内核的作用主要是给进程提供系统调用,以及提供异步中断事件的处理。多任务机制已经建立起来,并开始处理多个用户的登录和fork( )创建的进程。
[init]
init是第一个进程,或者说内核线程
init
lock_kernel
do_basic_setup
mtrr_init
sysctl_init
pci_init
sock_init
start_context_thread
do_init_calls
(*call())-> kswapd_init
prepare_namespace
free_initmem
unlock_kernel
execve
[目录]
--------------------------------------------------------------------------------
启动步骤
系统引导:
涉及的文件
./arch/$ARCH/boot/bootsect.s
./arch/$ARCH/boot/setup.s
bootsect.S
这个程序是linux kernel的第一个程序,包括了linux自己的bootstrap程序,
但是在说明这个程序前,必须先说明一般IBM PC开机时的动作(此处的开机是指
"打开PC的电源"):
一般PC在电源一开时,是由内存中地址FFFF:0000开始执行(这个地址一定
在ROM BIOS中,ROM BIOS一般是在FEOOOh到FFFFFh中),而此处的内容则是一个
jump指令,jump到另一个位于ROM BIOS中的位置,开始执行一系列的动作,包
括了检查RAM,keyboard,显示器,软硬磁盘等等,这些动作是由系统测试代码
(system test code)来执行的,随着制作BIOS厂商的不同而会有些许差异,但都
是大同小异,读者可自行观察自家机器开机时,萤幕上所显示的检查讯息。
紧接着系统测试码之后,控制权会转移给ROM中的启动程序
(ROM bootstrap routine),这个程序会将磁盘上的第零轨第零扇区读入
内存中(这就是一般所谓的boot sector,如果你曾接触过电脑病
毒,就大概听过它的大名),至于被读到内存的哪里呢? --绝对
位置07C0:0000(即07C00h处),这是IBM系列PC的特性。而位在linux开机
磁盘的boot sector上的正是linux的bootsect程序,也就是说,bootsect是
第一个被读入内存中并执行的程序。现在,我们可以开始来
看看到底bootsect做了什么。
第一步
首先,bootsect将它"自己"从被ROM BIOS载入的绝对地址0x7C00处搬到
0x90000处,然后利用一个jmpi(jump indirectly)的指令,跳到新位置的
jmpi的下一行去执行,
第二步
接着,将其他segment registers包括DS,ES,SS都指向0x9000这个位置,
与CS看齐。另外将SP及DX指向一任意位移地址( offset ),这个地址等一下
会用来存放磁盘参数表(disk para- meter table )
第三步
接着利用BIOS中断服务int 13h的第0号功能,重置磁盘控制器,使得刚才
的设定发挥功能。
第四步
完成重置磁盘控制器之后,bootsect就从磁盘上读入紧邻着bootsect的setup
程序,也就是setup.S,此读入动作是利用BIOS中断服务int 13h的第2号功能。
setup的image将会读入至程序所指定的内存绝对地址0x90200处,也就是在内存
中紧邻着bootsect 所在的位置。待setup的image读入内存后,利用BIOS中断服
务int 13h的第8号功能读取目前磁盘的参数。
第五步
再来,就要读入真正linux的kernel了,也就是你可以在linux的根目录下看
到的"vmlinuz" 。在读入前,将会先呼叫BIOS中断服务int 10h 的第3号功能,
读取游标位置,之后再呼叫BIOS 中断服务int 10h的第13h号功能,在萤幕上输
出字串"Loading",这个字串在boot linux时都会首先被看到,相信大家应该觉
得很眼熟吧。
第六步
接下来做的事是检查root device,之后就仿照一开始的方法,利用indirect
jump 跳至刚刚已读入的setup部份
第七步
setup.S完成在实模式下版本检查,并将硬盘,鼠标,内存参数写入到 INITSEG
中,并负责进入保护模式。
第八步
操作系统的初始化。
3. redhatenterpriselinux7的内核程序存储于那个目录
管理类文件夹: /boot 该目录默认下存放的是Linux的启动文件和内核,例如LILO或GRUB的文件。 /initrd 它的英文含义是boot loader initialized RAM disk,就是由boot loader初始化的内存盘。在linux内核启动前,boot loader会将存储介质(一般是硬盘)中的initrd文件加载到内存,内核启动时会在访问真正的根文件系统前先访问该内存中的initrd文件系统。 /bin 该目录中存放Linux的常用命令。 /sbin 该目录用来存放系统管理员使用的管理程序。 /var 该目录存放那些经常被修改的文件,包括各种日志、数据文件。如果做mail server,则需在Linux安装时将该目录设梁裂置为大空间。 /etc 该目录存放系统管理时要用到的各种配置文件和子目录,例如网络配置文件、文件系统、X系统配置文件、设备配置信息、设置用户信息等。如果做web server,则需在Linux安装时将该目录设置为大空间。 /dev 该目录包含了Linux系统中使用的纤携所有外部设备,它实际上是访问这些外部设备的端口,访问这些外部设备与访问一个文件或一个目录没有区别。例如在系统中键入“cd /dev/cdrom”就可以看到光驱中的文件。 /mnt 该目录默认下有2个分别对应光驱和软驱的文件夹cdrom和floppy。你可以临时将别的文件系统挂在该目录下,例如“挂载光驱mount/dev/cdrom /mnt/cdrom,查看光驱cd /mnt/cdrom”,养成良好习惯不使用时及时卸载“umount /mnt/cdrom”。 二、用户类文件夹: /root 如果你是以超级用户的身份登录的,这个就是超级用户的主目录。 /home 如果建立一个名为“xx”的用户,那么在/home目录下就有一个对应的“/home/xx”路径,用来存放该用户的主目录。
三、应用程序类文件夹: /usr 用户的应用程序和文件几乎都存放橡竖闭在该目录下。
4. linux安装了多个kernel,如何配置启动文件
2中方法:
开机的时候看到启动菜单的时候,按上下键侍皮来选择内核。
vi /boot/grub/grub.conf
default=0 改成对应锋谈正银悔的内核即可。default=1 (如果是第二套的话)
5. Linux系统启动的大致过程
Linux系统启动的大致过程
Linux操作系统是基于UNIX操作系统发展而来的一种克隆系统,它诞生于1991 年的 [Linux桌面] 10 月5 日。下面我准备了关于Linux系统启动的大致过程,提供给大家参考!
第一阶段:BIOS启动引导阶段;
在该过程中实现硬件的.初始化以及查找启动介质;
从MBR中装载启动引导管理器(GRUB)并运行该启动引导管理
第二阶段:GRUB启动引导阶段;
装载stage1
装载stage1.5
装载stage2
读取/boot/grub.conf文件并显示启动菜单;
装载所选的kernel和initrd文件到内存中
第三阶段:内核阶段:
运行内核启动参数;
解压initrd文件并挂载initd文件系统,装载必须的驱动;
挂载根文件系统
第四阶段:Sys V init初始化阶段:
启动/sbin/init程序;
运行rc.sysinit脚本,设置系统环境,启动swap分区,检查和挂载文件系统;
读取/etc/inittab文件,运行在/et/rc.d/rc<#>.d中定庆液义的不同运行级别的服务初始化脚本;
打开字清差睁符终端1-6号控制台/打开图形显示管理的7号控制台
同时在上述过程中各阶段所需要读取的文件和操作的对象:
BIOS启动引导阶段 GRUB启答岁动引导阶段 内核阶段 /init/sysinit阶段
====================================================================================
None /boot/grub/grub.conf /boot/vmlinuz- /etc/rc.d/rc.sysinit
/boot/grub/stage1_5 /boot/initrd- /etc/inittab
/boot/grub/stage2 /etc/rc.d/rc<#>.d
/etc/rc.d/init.d/*
;