linux-3.2.36内核启动1-启动参数(arm平台 启动参数的获取和处理,分析setup_arch)

本文主要介绍了Linux内核启动过程中的启动参数处理,包括标签列表(tagged list)和设备树(devicetree)。内容涵盖了从引导程序如何约定内存地址传递参数,到内核如何解析这些参数,特别是标签列表的格式和解析过程。文章通过代码示例和调试打印,详细解释了内存信息、cmdline参数的处理,并探讨了不同平台的差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近公司要求调试一个内核,启动时有问题,所以就花了一点时间看看内核启动。

看的过程中总结了一点东西,希望可以帮助大家调试内核。

当我开始看的时候,第一件事是从网上搜集资料,不看不知道,一看吓一跳!牛人太多了,像这种内核启动的上古代码早就被人分析的彻彻底底。这注定我写的只能是烂微博了。

为了此微博有存在的必要,我会显示内核启动打印的代码位置(用绿色表示)及出现错误打印的原因(用红色表示),同时我会尽力用添加打印(用蓝色字,同时给出对应于本人平台的打印结果)或实例来说明一些细节


注意我的是linux-3.2.36,有的老版本machine的判断位置不一样。

首先看启动参数

http://blog.chinaunix.net/uid-20543672-id-3151113.html

有两种启动参数

标签列表(taggedlist)或设备树(devicetree)。

引导程序和内核约定r2寄存器中存放的数据所指向的内存地址。

说设备树的微博,可以看看下面这个

http://blog.youkuaiyun.com/21cnbao/article/details/8457546

这两个注意:

标签列表必须置于内核自解压和initrd'bootp'程序都不会覆盖的内存区。建议放在RAM的头16KiB中。

设备树必须置于内核自解压不会覆盖的内存区。建议将其放置于RAM的头16KiB中

我简单介绍标签列表格式

·  基地址 -> +-----------+

·           | ATAG_CORE | |

·          +-----------+  |

·           | ATAG_MEM |  | 地址增长方向

·          +-----------+  |

·           | ATAG_NONE | |

·          +-----------+  v

viarch/arm/include/asm/setup.h

struct tag_header {

      __u32size; //标签总大小(包括tag_header)

      __u32tag; //标签标识

};

上面的图就是要linux获取的第一个tag的头的__u32 tag要是ATAG_CORE

最后一个是ATAG_NONE。

struct tag {

        structtag_header hdr;

        union {

                struct tag_core         core;// 标签列表开始                struct tag_mem32        mem;// 内存信息标签(可以有多个标签,以标识多个内存区块)

               struct tag_videotext    videotext;// VGA文本显示参数标签

               struct tag_ramdisk      ramdisk;// ramdisk参数标签(位置、大小等)

               struct tag_initrd       initrd;// 压缩的ramdisk参数标签

               struct tag_serialnr     serialnr;// 板子串号标签

               struct tag_revision     revision;// 板子版本号标签

               struct tag_videolfb     videolfb;// 帧缓冲初始化参数标签

               struct tag_cmdline      cmdline;//就是uboot的bootargs

 

                /*

                 *Acorn specific

                 */

               struct tag_acorn        acorn;

 

                /*

                 *DC21285 specific

                 */

               struct tag_memclk       memclk;

        } u;

};

先简单的解释一下cmdline,你可以在用户态下cat /proc/cmdline

看到,就是uboot的bootargs。

上面的微博有有对bootm分析,我只说一点

setup_start_tag (bd);  //设置ATAG_CORE,这里面有params = (struct tag *) bd->bi_boot_params;

参数地址

 

kernel_entry(0, machid, bd->bi_boot_params);

r0 = 0 r1 = machid r2 = bd->bi_boot_params)

bd->bi_boot_params在board下对应的板子目录下

我的

bd->bi_boot_params = 0x30000100 我的ram开始是0x30000000

内核的建议

建议放在RAM的头16KiB中,还有一句是:但是不可将其放置于“0”物理地址处,因为内核认为:r2中为0,意味着没有标签列表和dtb传递过来。这在启动是的汇编代码可以看到。

 

Bootloader到内核的start_kernel之间还有自解压和一些汇编代码,这个我会在下一篇博客分析,现在主要是从setup_arch开始。这也是自解压之后,我们能看到内核打印开始的地方。

下面我们进入内核,看看内核如何获取这些启动参数

init/main.c

asmlinkage void __init start_kernel(void)

{

       ……

       printk(KERN_NOTICE"%s", linux_banner);//这个就是我们linux启动时打印的版本信息,我的:Linux version 3.2.0(root@localhost.localdomain) (gcc version 4.4.3 (ctng-1.6.1) ) #70 Thu Jun 2010:50:51 CST 2013

 

       setup_arch(&command_line);

……

下面是我们的主机

蓝色的字为我添加的调试打印,将在后面调试时开出来

arch/arm/kernel/setup.c

void __init setup_arch(char **cmdline_p)

{

       struct machine_desc *mdesc;

 

       setup_processor();

根据读出的cpuid,进行匹配,在汇编代码中有也有判断,我简单说一下,一个是从cpu读的id(cp15协处理器),一个是从arch/arm/mm/ proc-armXXX.c读的,例如我的arm920t

__arm920_proc_info:

        .long   0x41009200

就是这个id,如果不匹配,while(1)死循环。

cpu信息就在这里打印,我的:

CPU: ARM920T [41129200] revision 0 (ARMv4T), cr=c0007177

CPU: VIVT data cache, VIVT instruction cache

如果你没有那么是你的cpu类型选的不对,但是cpu类型一般是和machine一起选的,所以还是看下面的

 

        //wxl 添加

        printk(KERN_NOTICE “__atags_pointer: %lx\n”, (unsigned long)__atags_pointer);

        打印为__atags_pointer : 30000100

        还记得uboot的

        bd->bi_boot_params= 0x30000100

 

       mdesc = setup_machine_fdt(__atags_pointer);这个函数时获取设备树的信息,我的没有,会返回NULL

       if (!mdesc)

                mdesc =setup_machine_tags(machine_arch_type);

这个是处理tagged_list的主要函数,在下面,我没有放这里,你先看看它在向下看。

       machine_desc = mdesc;

       machine_name = mdesc->name;这是MINI2440

 

#ifdef CONFIG_ZONE_DMA

       if (mdesc->dma_zone_size) {

                extern unsigned longarm_dma_zone_size;

                arm_dma_zone_size =mdesc->dma_zone_size;DMA区域大小

        }

#endif

       if (mdesc->soft_reboot)

                reboot_setup("s");

       这个是重启方式,”s”为软件,”h”为硬件,最终重启调用arch_reset(mode,cmd);这个函数成功就重启不会返回,如果没有成功,你会看到Reboot failed --System halted打印;这个函数由平台提供,samsung没有什么软件重启模式,mach-ebsa110</

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值