精华内容
下载资源
问答
  • bootz启动linux内核过程

    2021-09-24 14:25:05
  • uboot启动Linux内核

    2021-03-06 13:46:16
    2.uboot给内核提供启动参数,并执行bootcmd命令启动内核 多种启动方式: 1.从SD卡的kernel分区去读取内核镜像到DDR:命令:movi read kernel 30008000。 2.tftp、nfs等网络下载方式从远端服务器获取镜像 uboot还支持...


    前言

    uboot学习:个人觉得边看代码边总结会比较好。不纠结于细节,要想弄清楚uboot的目的,看代码的枝干就行。根据朱有鹏课程整理。

    uboot文章连载:
    1.uboot启动过程
    2.uboot命令体系
    3.uboot的环境变量
    4.uboot的驱动
    5.uboot启动Linux内核

    Linux文章连载


    前言:uboot启动过程

    1.uboot到Linux

    uboot帮助内核的两件事情:
    1.uboot帮助内核实现重定位(从SD卡到DDR)
    2.uboot给内核提供启动参数,并执行bootcmd命令启动内核

    多种启动方式:
    1.从SD卡的kernel分区去读取内核镜像到DDR:命令:movi read kernel 30008000。
    2.tftp、nfs等网络下载方式从远端服务器获取镜像
    uboot还支持远程启动:内核镜像放在主机的服务器中。
    (注:镜像要放在DDR的链接地址处,链接地址去内核源代码的链接脚本或者Makefile中去查找。X210中是0x30008000。)

    3.zImage和uImage的区别联系

    3.1、bootm命令对应do_bootm函数(uboot的cmd_bootm.c中)
    CONFIG_ZIMAGE_BOOT宏,用来支持zImage格式的内核启动。
    3.2、vmlinuz和zImage和uImage
    背景:
    (1)linux内核经过编译后也会生成一个elf格式的可执行程序,叫vmlinux或vmlinuz,这个就是原始的未经任何处理加工的原版内核elf文件;嵌入式系统部署时烧录的一般不是这个vmlinuz/vmlinux,而是要用objcopy工具去制作成烧录镜像格式(就是u-boot.bin这种,但是内核没有.bin后缀),经过制作加工成烧录镜像的文件就叫Image(制作把78M大的精简成了7.5M,因此这个制作烧录镜像主要目的就是缩减大小,节省磁盘)。
    (2)原则上Image就可以直接被烧录到Flash上进行启动执行(类似于u-boot.bin),但是实际上并不是这么简单。实际上linux的作者们觉得Image还是太大了所以对Image进行了压缩,并且在image压缩后的文件的前端附加了一部分解压缩代码。构成了一个压缩格式的镜像就叫zImage。(因为当年Image大小刚好比一张软盘(软盘有2种,1.2M的和1.44MB两种)大,为了节省1张软盘的钱于是乎设计了这种压缩Image成zImage的技术)。
    (3)uboot为了启动linux内核,还发明了一种内核格式叫uImage。uImage是由zImage加工得到的,uboot中有一个工具,可以将zImage加工生成uImage。注意:uImage不关linux内核的事,linux内核只管生成zImage即可,然后uboot中的mkimage工具再去由zImage加工生成uImage来给uboot启动。这个加工过程其实就是在zImage前面加上64字节的uImage的头信息即可。
    (4)原则上uboot启动时应该给他uImage格式的内核镜像,但是实际上uboot中也可以支持zImage,是否支持就看x210_sd.h中是否定义了LINUX_ZIMAGE_MAGIC这个宏。所以大家可以看出:有些uboot是支持zImage启动的,有些则不支持。但是所有的uboot肯定都支持uImage启动。

    3.3、编译内核得到uImage去启动
    (1)如果直接在kernel底下去make uImage会提示mkimage command not found。解决方案是去uboot/tools下cp mkimage /usr/local/bin/(在基础课中讲到在环境变量PATH中导出这个路径就可以往里放?),复制mkimage工具(加头校验信息)到系统目录下。再去make uImage即可。

    4.zImage启动细节

    (1)do_bootm函数中一直到397行的after_header_check这个符号处,都是在进行镜像的头部信息校验。校验时就要根据不同种类的image类型进行不同的校验。所以do_bootm函数的核心就是去分辨传进来的image到底是什么类型,然后按照这种类型的头信息格式去校验。
    4.1、LINUX_ZIMAGE_MAGIC
    (1)这个是一个定义的魔数,这个数等于0x016f2818,表示这个镜像是一个zImage。也就是说zImage格式的镜像中在头部的一个固定位置存放了这个数作为格式标记。如果我们拿到了一个image,去他的那个位置去取4字节判断它是否等于LINUX_ZIMAGE_MAGIC,则可以知道这个镜像是不是一个zImage。
    (2)命令 bootm 0x30008000,所以do_boom的argc=2,argv[0]=bootm argv[1]=0x30008000。但是实际bootm命令还可以不带参数执行。如果不带参数直接bootm,则会从CFG_LOAD_ADDR地址去执行(定义在x210_sd.h中)。
    (3)zImage头部开始的第37-40字节处存放着zImage标志魔数:if (*(ulong *)(addr + 9*4) == LINUX_ZIMAGE_MAGIC)。从这个位置取出然后对比LINUX_ZIMAGE_MAGIC。可以用二进制阅读软件来打开zImage查看,就可以证明。很多软件都可以打开二进制文件,如winhex、UltraEditor。第37字节其实就是36,转换成16进制数就是24,在UE中就可以查得魔数。
    4.2、image_header_t
    (1)这个数据结构是我们uboot启动内核使用的一个标准启动数据结构,zImage头信息也是一个image_header_t,但是在实际启动之前需要进行一些改造。
    hdr->ih_os = IH_OS_LINUX;
    hdr->ih_ep = ntohl(addr);这两句就是在进行改造。(213行)是zImage的头信息
    (2)images全局变量是do_bootm函数中使用,用来完成启动过程的,由zImage加工而来,是整个启动过程的头信息。zImage的校验过程其实就是先确认是不是zImage,确认后再修改zImage的头信息到合适,修改后用头信息去初始化images这个全局变量,然后就完成了校验。

    5.uImage启动

    5.1、uImage启动
    (1)LEGACY(遗留的),在do_bootm函数中,这种方式指的就是uImage的方式。
    (2)uImage方式是uboot本身发明的支持linux启动的镜像格式,但是后来这种方式被一种新的方式替代,这个新的方式就是设备树方式(在do_bootm方式中叫FIT)
    (3)uImage的启动校验主要在boot_get_kernel函数中,主要任务就是校验uImage的头信息,并且得到真正的kernel的起始位置去启动。
    5.2、设备树方式内核启动
    背景:uboot本身设计时只支持uImage启动,原来uboot的代码也是这样写的。后来有了fdt(设备树)方式之后,就把uImage方式命令为LEGACY方式,fdt方式命令为FIT方式,于是乎多了写#if #endif添加的代码。后来移植的人又为了省事添加了zImage启动的方式,又为了省事把zImage启动方式直接写在了uImage和fdt启动方式之前,于是又有了一对#if #endif。于是整体的代码看起来很恶心。
    总结:第二阶段校验头信息结束,下面进入第三阶段,第三阶段主要任务是启动linux内核,调用do_bootm_linux函数来完成。
    5.3、show_boot_progress (1)的作用:调试,打印一个启动阶段,函数启动时间太长,每隔一段代码插入show_boot_progress (1),如果出错可以知道是哪部分代码出错。
    5.4、319~371是uboot自带的解压缩代码,对kernel进行解压缩,但是我们现在不需要解压缩了,因为kernel中有自解压的代码,所以我们走的是IH_COMP_NONE(320行)这条路,早期是由uboot来解压的,所以后面还是保留了这些解压代码。

    6.do_bootm_linux函数

    6.1、找到do_bootm_linux函数
    (1)函数在uboot/lib_arm/bootm.c中。
    (2)SI找不到(是黑色的)不代表就没有,要搜索一下才能确定;搜索不到也不能代表就没有,因为我们在向SI工程中添加文件时,SI只会添加它能识别的文件格式的文件,有一些像Makefile、xx.conf等Makefile不识别的文件是没有被添加的。所以如果要搜索的关键字在makefile中或者脚本中,可能就是搜索不到的。(譬如TEXT_BASE)
    6.2、镜像的entrypoint
    (1)ep就是entrypoint的缩写,就是程序入口。一个镜像文件的起始执行部分不是在镜像的开头(镜像开头有n个字节的头信息),真正的镜像文件执行时第一句代码在镜像的中部某个字节处,相对于头是有一定的偏移量的。这个偏移量记录在头信息中。
    (2)一般执行一个镜像都是:第一步先读取头信息,然后在头信息的特定地址找MAGIC_NUM,由此来确定镜像种类;第二步对镜像进行校验;第三步再次读取头信息,由特定地址知道这个镜像的各种信息(镜像长度、镜像种类、入口地址);第四步就去entrypoint处开始执行镜像。
    (3)theKernel = (void (*)(int, int, uint))ep;将ep赋值给theKernel,则这个函数指向就指向了内存中加载的OS镜像的真正入口地址(就是操作系统的第一句执行的代码)。
    bootm.c158行theKernel (0, machid, bd->bi_boot_params);被调用就是uboot的最后一句了,去内核镜像执行了。
    6.3、机器码的再次确定
    (1)uboot在启动内核时,机器码要传给内核。uboot传给内核的机器码是怎么确定的?第一顺序备选是环境变量machid,第二顺序备选是gd->bd->bi_arch_num(x210_sd.h中硬编码配置的)
    6.4、传参并启动概述
    (1)从110行到144行就是uboot在给linux内核准备传递的参数处理。
    (2)Starting kernel … 这个是uboot中最后一句打印出来的东西。这句如果能出现,说明uboot整个是成功的,也成功的加载了内核镜像,也校验通过了,也找到入口地址了,也试图去执行了。如果这句后串口就没输出了,说明内核并没有被成功执行。原因一般是:传参(80%)、内核在DDR中的加载地址·······

    展开全文
  • do_bootm_linux函数时专门启动linux内核的,包括以下几个步骤: (1)确认当前的机器码; 启动内核入口的传参 do_bootm_linux函数源码 #define CONFIG_BOOTARGS "console=ttySAC2,115200 root=/dev/mmcblk0p2 rw ...

    1、do_bootm_linux函数解析

    do_bootm_linux函数是专门启动linux内核的,包括以下功能:
    (1)确认当前的机器码,可以从全局变量gd或者环境变量machid中获取,其中环境变量machid的优先级高于gd中的机器码;
    (2)计算出内核的入口地址;
    (3)准备给内核的传参;不清楚uboot给内核传参的看博客:《uboot中命令体系详解》
    (4)协处理器的相关操作,为启动内核初始化环境;
    (5)启动内核;

    2、启动内核入口的传参

    (1)theKernel (0, machid, bd->bi_boot_params);
    theKernel 是函数指针,指向内核的入口地址,也就是内核将要执行的第一句代码。其中要传三个参数,第一个参数固定为0,第二个参数是机器码,第三个参数是uboot传给内核参数所在的首地址。
    (2)机器码
    机器码可以算作是一块板子的id,嵌入式设备是高度定制的,内核也是可以高度裁剪的,所以每个版本的内核只能支持移植过开发板。在内核中维护有个表格,里面记录了支持的开发板的id,也就是机器码,如果启动内核时传入的机器码没有在表格中找到,说明内核不支持该开发板,启动失败。

    3、do_bootm_linux函数源码

    	#define CONFIG_BOOTARGS    	"console=ttySAC2,115200 root=/dev/mmcblk0p2 rw init=/linuxrc rootfstype=ext3"
    	
    	void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
    				 bootm_headers_t *images)
    	{
    		ulong	initrd_start, initrd_end;
    		ulong	ep = 0;
    		bd_t	*bd = gd->bd;
    		char	*s;
    		int	machid = bd->bi_arch_number; //从全局变量gd中获取机器码
    		void	(*theKernel)(int zero, int arch, uint params);
    		int	ret;
    
    	#ifdef CONFIG_CMDLINE_TAG
    		//对应宏:CONFIG_BOOTARGS,bootargs是启动内核的传的参数
    		char *commandline = getenv ("bootargs"); 
    	#endif
    
    		/* find kernel entry point */
    		if (images->legacy_hdr_valid) {
    			ep = image_get_ep (&images->legacy_hdr_os_copy); //得到内核的入口地址
    		} else {
    			puts ("Could not find kernel entry point!\n");
    			goto error;
    		}
    		//theKernel 是函数指针,指向内核的入口地址
    		theKernel = (void (*)(int, int, uint))ep;
    		
    		//从环境变量获取机器码,这里可以看出环境变量里的机器码优先级高于全局变量gd里的机器码
    		s = getenv ("machid"); 
    		if (s) {
    			machid = simple_strtoul (s, NULL, 16);
    			printf ("Using machid 0x%x from environment\n", machid);
    		}
    
    		ret = boot_get_ramdisk (argc, argv, images, IH_ARCH_ARM, //虚拟内存盘相关
    				&initrd_start, &initrd_end);
    		if (ret)
    			goto error;
    
    		show_boot_progress (15);
    
    		debug ("## Transferring control to Linux (at address %08lx) ...\n",
    			   (ulong) theKernel);
    			   
    	/*	下面都是在准备给内核的传参     */
    	#if defined (CONFIG_SETUP_MEMORY_TAGS) || \
    		defined (CONFIG_CMDLINE_TAG) || \
    		defined (CONFIG_INITRD_TAG) || \
    		defined (CONFIG_SERIAL_TAG) || \
    		defined (CONFIG_REVISION_TAG) || \
    		defined (CONFIG_LCD) || \
    		defined (CONFIG_VFD) || \
    		defined (CONFIG_MTDPARTITION)
    		setup_start_tag (bd); //传递给内核参数的起始tag结构体
    	#ifdef CONFIG_SERIAL_TAG
    		setup_serial_tag (&params);
    	#endif
    	#ifdef CONFIG_REVISION_TAG
    		setup_revision_tag (&params);
    	#endif
    	#ifdef CONFIG_SETUP_MEMORY_TAGS
    		setup_memory_tags (bd);
    	#endif
    	#ifdef CONFIG_CMDLINE_TAG
    		setup_commandline_tag (bd, commandline);
    	#endif
    	#ifdef CONFIG_INITRD_TAG
    		if (initrd_start && initrd_end)
    			setup_initrd_tag (bd, initrd_start, initrd_end);
    	#endif
    	#if defined (CONFIG_VFD) || defined (CONFIG_LCD)
    		setup_videolfb_tag ((gd_t *) gd);
    	#endif
    
    	#ifdef CONFIG_MTDPARTITION
    		setup_mtdpartition_tag();
    	#endif
    		//传递给内核参数的结束tag结构体
    		setup_end_tag (bd);
    	#endif
    
    		/* we assume that the kernel is in place */
    		printf ("\nStarting kernel ...\n\n");
    
    	#ifdef CONFIG_USB_DEVICE
    		{
    			extern void udc_disconnect (void);
    			udc_disconnect ();
    		}
    	#endif
    
    		/*启动内核前的设置,主要是协处理器的相关操作,包括关iCache和dCache等*/
    		cleanup_before_linux ();
    		
    		/*这句是真正启动内核的语句,到此uboot的使命就结束了;
    			theKernel是内核的入口地址,也就是内核执行的第一句代码;
    			第1个参数固定为0,第2个参数是机器码,第3个参数是传递给内存的传参tag的首地址*/
    		theKernel (0, machid, bd->bi_boot_params);
    		/* does not return */
    		return;
    
    	error:
    		do_reset (cmdtp, flag, argc, argv);
    		return;
    	}
    
    展开全文
  • vrf),如下所示:There is a running kernel module (netns\_vrf) in my Linux computer, like this:$ lsmod | grep vrfnetns_vrf 8388 0这个内核模块不是来自Linux发行版,而是来自第三方供应商,我不...

    我的Linux计算机中有一个正在运行的内核模块(netns\_vrf),如下所示:

    There is a running kernel module (netns\_vrf) in my Linux computer, like this:

    $ lsmod | grep vrf

    netns_vrf 8388 0

    这个内核模块不是来自Linux发行版,而是来自第三方供应商,我不会在这里说出它的名字。

    This kernel module is not from Linux distribution, it is from a third party vendor, I will not say its name here.

    $ modinfo netns_vrf

    filename: /lib/modules/4.4.96-pc64-distro.git-17.11.2-rcp1/net/netns-vrf.ko

    author: 《SOME COMPANY NAME》

    license: GPL

    depends:

    vermagic: 4.4.96-pc64-distro.git-17.11.2-rcp1 SMP mod_unload

    我的Linux是由systemd启动的,有没有办法知道哪个systemd服务器插入了这个内核模块? 我用谷歌搜索了一段时间,但找不到答案。

    My Linux was started by systemd, is there a way to know which systemd server insert this kernel module? I have googled a while, but could not find the answer.

    **已更新**:" google" 我的系统,找出插入内核模块的脚本。

    **Updated**: "google" my system, and find out the script who insert the kernel module.

    #cd /usr

    #sudo grep -R netns_vrf * 2》/dev/null

    展开全文
  • 老生长谈的内容了,就是自己编译内核,然后制作initramfs,在用qemu跑起来。不过在这之前先跑个helloworld玩玩。...编译内核# 建一个目录$ mkdir build# 首先當然是去下一個linux內核,地址, ...
  • 64位ARM Linux内核启动的环境要求 在64位ARM处理器上,Linux内核启动前,对设备的环境要求主要有以下几点: 内存(DDR)已初始化完成,禁用MMU,关闭数据缓存(dcache); 蔽屏CPU中断,关闭指令缓存(icache); ...
  • uboot启动linux内核

    2021-01-23 14:14:34
    在uboot进入命令模式,分别从网络获取内核和设备树,启动 获取内核 tftp 80800000 zImage 获取设备树 imx6ull-14x14-evk.dtb 启动内核 bootz 80800000 - 83000000 启动成功 2. 从NAND启动 烧录...
  • linux内核源码请自行下载了。下面开始编译Linux4.16.4的内核试试,进入内核根目录,先生成内核配置文件:make ARCH=arm vexpress_defconfig因为准备挂载ramdisk文件系统,所以这里还需要再配置一下内核,make ARCH=...
  • Linux内核文件重启

    2021-05-10 20:18:58
    kernel/reboot.c文件是重新启动过程的与体系结构无关的部分。arch/x86/kernel/reboot.c和所有其他arch/*/kernel/reboot.c是某些功能的体系结构特定版本,由kernel/reboot.c使用。例如,在arch/x86/kernel/reboot.c中...
  • linux内核启动流程

    2021-05-09 01:54:19
    描述Linux的启动代码真的挺大,从汇编到C,从Makefile到LDS文件,需要理解...Linux内核启动及文件系统加载过程当u-boot开始执行bootcmd命令,就进入Linux内核启动阶段,与u-boot类似,普通Linux内核启动过程也可以...
  • 很多嵌入式Linux操作系统由于没有在/dev目录下正确配置console设备,造成启动时发生诸如unable to open an initial console的错误。 1.10 init_modules() 模块初始化。如果编译内核时使能该选项,则内核支持模块化...
  • 内核的生成过程来看内核的链接主要有三步:第一步是把内核的源代码编译成.o文件,然后链接,这一步,链接的是arch/i386/kernel/head.S,生成的是vmlinux。注意的是这里的所有变量地址都是32位页寻址方式的保护模式...
  • ARM Linux内核启动流程

    2021-05-10 21:17:38
    操作ARM Linux内核主要分为哪几个步骤,下面杭州硕数就为大家讲解一下这个启动的流程。ARM Linux内核综述启动分两步,首先是硬件相关部分,入口是arch/arm/kernel/head.S代码文件中的ENTRY(stext)函数;然后是硬件...
  • 1. 查看当前默认启动内核[root@localhost yangkun]# grub2-editenv listsaved_entry=CentOS Linux, with Linux 3.10.0-123.el7.x86_642. 罗列所有内核[root@localhost yangkun]# cat /boot/grub2/grub.cfg | grep ...
  • 1.环境:Ubuntu 16.04Linux linuxidc 4.4.0-89-generic #112-Ubuntu SMP Mon Jul 31 19:38:41 UTC 2017 x86_64 ...查看当前linux内核启动参数:cat /proc/cmdline笔者的输出内容如下:BOOT_IMAGE=/boot/vmlinuz-4.4.0...
  • 1.做好内核分析的准备工作 1.1、删除无用文件 (1)官方版本的kernel中是支持各种硬件架构、各种开发板的,因此有很多文件夹和文件和我们无关,在建立SI工程前应该删掉。 (2)现在分析的是九鼎科技移植好的针对X210...
  • Linux内核启动显示时间信息Linux内核启动显示时间信息在最开始移植Linux内核的时候,发现自己配置的内核编译出来启动信息十分的杂乱无章。但是厂家提供的Linux镜像文件下载到开发板中,打印的信息十分清晰。它在打印...
  • 关注「嵌入式大杂烩」,选择「星标公众号」一起进步!01修改与编译内核前面小哥主要是跟大家讲解了uboot的烧录、使用等等,而对于嵌入式Linux环境而言其实主要是分为三大块 : uboot...
  • GRUB可用于选择操作系统分区上的不同内核,也可用于向这些内核传递启动参数。几乎所有人的Linux都是一个双系统,所以Grub也是几乎所有Linux用户熟知的东西。但很多原因都可以导致Linux无法启动,比...
  • 我已经从树上编译了Linux内核(稳定),并获得了initrd和bzImage.我尝试在qemu模拟器上运行它,但是在指定根文件系统分区时遇到问题. (我知道这是从中运行initrd加载的分区).我的系统是Windows上通过Wubi安装的Ubuntu ...
  • Linux系统的组成部分从运行状态角度来看 分为 内核+根文件系统从静态角度来看 分为 磁盘分区+相关文件内核调用第一个方式:调用内核过于复杂,所以有些内核开发人员创建了库文件,通过调用库文件来调用内核程序。...
  • 我试图了解linux内核中的init进程,这是第一个进程,并使用INIT_TASK宏进行静态初始化.161 #define INIT_TASK(tsk) \162 { \163 .state = 0, ...
  • 结果修复完之后默认启动内核版本变成了3.10的新版本,导致docker起不来。报错overlay2驱动不兼容。细想一下,之前遇到过docker起不来的原因,是内核版本不对。uname -a 查看版本,果然是3.10。问题简单了,...
  • linux内核相关视频解析: 5个方面分析linux内核架构,让你对内核不再陌生 90分钟了解Linux内存架构,numa的优势,slab的实现,vmalloc的原理 手把手带你实现一个Linux内核文件系统 简介 作用是将应用层序的请求传递...
  • Linux 内核之基于 Bootsplash 嵌入式 Linux 启动画面定制Linux 内核之基于 Bootsplash 嵌入式 Linux 启动画面定 制在基于 linux 的嵌入式仿真平台开发中,终端的美观和 可定制是一个重要的问题。开机时滚动在屏幕上...
  • Linux内核启动流程中设备树相关内容Linux 内核启动流程----设备树的识别 曹忠明ARM Linux 内核在 Linux-3.x 内核有了很大的变化,对一些新的平台的支持取消了传统的设备文件而用设备树取代,这里以 FS4412 设备树...
  • 1.查询系统内核有几个 [root@master ~]# cat /boot/grub2/grub.cfg | grep menuentry if [ x"${feature_menuentry_id}" = xy ]; then menuentry_id_option="--id" menuentry_id_option="" export menuentry_id_...
  • Linux修改内核启动顺序 一、centos6修改内核启动顺序 1、查看/etc/grub.conf文件,确认系统内核的情况,如下图所示系统存在2个内核的现象。从上往下内核版本依次是2.6.32-573.18.1.el6.x86_64和2.6.32-431.23.3.el6...
  • 最近使用centos 7 进行了update的命令来做更新操作。...linux使用update命令会进行内核更新,我们需要修改默认启动内核解决这个问题。centos 7 采用的是grub2进引导程序。一、查看具体内核数量:cat /boot/grub2/...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 393,648
精华内容 157,459
关键字:

启动linux内核

linux 订阅