Linux移植之tag参数列表解析过程分析

发布者:SerendipityRose最新更新时间:2024-08-26 来源: cnblogs关键字:Linux移植  tag 手机看文章 扫描二维码
随时随地手机看文章

在Linux移植之内核启动过程start_kernel函数简析中已经指出了start_kernel函数的调用层次,这篇主要是对具体的tag参数列表进行解析。


1、内存参数ATAG_MEM参数解析


2、命令行参数ATAG_CMDLINE解析,以传入的命令参数bootargs=noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0为列:


  1)、noinitrd参数解析过程,当你没有使用ramdisk启动系统的时候,你需要使用noinitrd这个参数,但是如果使用了的话,就需要指定initrd=r_addr,size, r_addr表示initrd在内存中的位置,size表示initrd的大小。


  2)、root=/dev/mtdblock3参数解析过程


  3)、init=/linuxrc参数解析过程


  4)、 console=ttySAC0参数解析过程


start_kernel

    setup_arch                  //解析UBOOT传入的启动参数

    setup_command_line //解析UBOOT传入的启动参数

    do_early_param         //解析early参数,uboot中没传这个参数

    unknown_bootoption//解析到了命令行参数,saved_root_name在这块初始化

    console_init();//控制台初始化

    rest_init

        kernel_thread

            kernel_init

                prepare_namespace   //解析命令行参数解析成功挂接在哪个分区

                    mount_root//挂接根文件系统

                init_post

                    //执行应用程序


1、内存参数ATAG_MEM参数解析


看到archarmkernelSetup.c文件,在setup_arch函数里看到如下几行,首先根据内核启动时第一阶段得到的machine_arch_type,取得mdesc结构体,这个结构体在Linux移植之内核启动过程引导阶段分析已经介绍过,这里主要关心的是boot_params参数,里面存放的是tag参数列表的存放地址,然后将取得的物理地址转换为虚拟地址供后面使用tag。


776    console_init();//控制台初始化

777    archarmkernelSetup.c

778

779    setup_processor();//设置处理器相关的一些设置

780    mdesc = setup_machine(machine_arch_type);//获得开发板的machine_desc结构

781    machine_name = mdesc->name;//取得开发板的名称

782

783    if (mdesc->soft_reboot)

784        reboot_setup('s');

785

786    if (mdesc->boot_params)//确定uboot传入的启动参数的地址

787        tags = phys_to_virt(mdesc->boot_params);//将启动参数的物理地址转换为虚拟地址


setup_arch函数继续往下看


109    static struct meminfo meminfo __initdata = { 0, };


798    if (tags->hdr.tag == ATAG_CORE) {//ATAG_CORE为tag标记列表的开始

799        if (meminfo.nr_banks != 0)//如果已经在内核中定义了meminfo结构

780            squash_mem_tags(tags);//则忽略内存tag

781        parse_tags(tags);//解释每个tag

782    }


其中meminfo就是处理完ATAG_MEN参数后,将里面的内容放去meninfo中,它的结构定义在includeasm-armSetup.h 中


207    struct meminfo {

208        int nr_banks;

209        struct membank bank[NR_BANKS];

210    };

接着继续看parse_tags函数,它也位于archarmkernelSetup.c中



733    static void __init parse_tags(const struct tag *t)

734    {

735        for (; t->hdr.size; t = tag_next(t))//循环取出tag列表,然后处理

736            if (!parse_tag(t))                //处理取出的tag列表

737                printk(KERN_WARNING

738                    'Ignoring unrecognised tag 0x%08xn',

739                    t->hdr.tag);

740    }


接着分析parse_tag函数,它同样位于archarmkernelSetup.c中


715    static int __init parse_tag(const struct tag *tag)

716    {

717        extern struct tagtable __tagtable_begin, __tagtable_end;

718        struct tagtable *t;

719

720        for (t = &__tagtable_begin; t < &__tagtable_end; t++)//从.taglist.init段找出符合的处理tag列表的结构

721            if (tag->hdr.tag == t->tag) {//找到符合的tag

722                t->parse(tag);//调用相应的处理tag的函数处理

723                break;

724            }

725    

726        return t < &__tagtable_end;//t<&__tagtable_end说明找到了tag

727    }


parse_tag会从.taglist.init段找出符合的tag,然后调用相应的处理函数处理。tagtable 的结构如下,它位于includeasm-armSetup.h 中


171    struct tagtable {

172        __u32 tag;//处理的tag值

173        int (*parse)(const struct tag *);//处理函数

174    };

我们需要的是处理ATAG_MEN参数的函数,搜搜ATAG_MEN,在archarmkernelSetup.c中找到了parse_tag_mem32处理ATAG_MEN参数的函数。它的功能就是取出内存的开始地址与大小信息后存放在meminfo结构中


614    static int __init parse_tag_mem32(const struct tag *tag)

615    {

616        if (meminfo.nr_banks >= NR_BANKS) {

617            printk(KERN_WARNING

618                   'Ignoring memory bank 0x%08x size %dKBn',

619                tag->u.mem.start, tag->u.mem.size / 1024);

620            return -EINVAL;

621        }

622        arm_add_memory(tag->u.mem.start, tag->u.mem.size);//取出内存的开始地址与大小信息后存放在meminfo结构中

623        return 0;

624    }

625

626    __tagtable(ATAG_MEM, parse_tag_mem32);//解析ATAG_MEM列表,函数为parse_tag_mem32


再看到__tagtable,同样位于includeasm-armSetup.h中。主要就是将tagtable 这个结构体放在.taglist.init段


188    #define __tag __used __attribute__((__section__('.taglist.init')))

189    #define __tagtable(tag, fn)

190    static struct tagtable __tagtable_##fn __tag = { tag, fn }

到这里就分析完了tag列表中ATAG_MEM参数的处理,接下去分析ATAG_CMDLINE参数的处理。


2、命令行参数ATAG_CMDLINE解析


找到与ATAG_CMDLINE参数的过程与前面ATAG_MEM参数一样的流程就不分析了,直接找到处理ATAG_CMDLINE参数的函数,它位于archarmkernelSetup.c中。它只是简单的将tag->u.cmdline.cmdline的内容复制到default_command_line中。


702    static int __init parse_tag_cmdline(const struct tag *tag)

703    {

704        strlcpy(default_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE);//简单的将tag的内容复制到字符串default_command_line中

705        return 0;

706    }

707

708    __tagtable(ATAG_CMDLINE, parse_tag_cmdline);


接着看到default_command_line,它定义在archarmkernelSetup.c中,它的大小为1024字节


114    static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;

它初始化为CONFIG_CMDLINE,位于includelinuxAutoconf.h中


374    #define CONFIG_CMDLINE 'root=/dev/hda1 ro init=/bin/bash console=ttySAC0'

所以拷贝之后


default_command_line[] = 'noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0'

继续往下看default_command_line,在archarmkernelSetup.c下的setup_arch函数中:其中parse_cmdline是对位于.early_param.init段的内容进行前期的初始化。相应的命令有:cachepolicy=、nocache、nowb、ecc=、initrd=、mem=等等,我们的参数没有涉及到这类命令,所以不去细细的分析这个函数了。


809    memcpy(boot_command_line, from, COMMAND_LINE_SIZE);//form指向default_command_line,将default_command_line中的内容拷贝到boot_command_line中

810    boot_command_line[COMMAND_LINE_SIZE-1] = '';//以''结束字符串

811    parse_cmdline(cmdline_p, from);//对位于.early_param.init段命令进行一些先期的处理

812    paging_init(&meminfo, mdesc);//重新初始化页表

813    request_standard_resources(&meminfo, mdesc);//资源的初始化

接着看到paging_init这个函数,这个函数调用了meminfo这个从ATAG_MEM取得的参数以及mdesc我们按照以下调用层次分析


paging_init

    devicemaps_init //设备maps初始化

        mdesc->map_io //调用map_io函数初始化

在archarmmach-s3c2440Mach-smdk2440.c中找到mdesc这个结构


339    MACHINE_START(S3C2440, 'SMDK2440')

340        /* Maintainer: Ben Dooks */

341        .phys_io    = S3C2410_PA_UART,

342        .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,

343        .boot_params    = S3C2410_SDRAM_PA + 0x100,

344

345        .init_irq    = s3c24xx_init_irq,

346        .map_io        = smdk2440_map_io,

347        .init_machine    = smdk2440_machine_init,

348        .timer        = &s3c24xx_timer,

349    MACHINE_END


其中smdk2440_map_io就等要调用的函数,它同样位于archarmmach-s3c2440Mach-smdk2440.c下,可以看到这里修改过晶振的值。


324    static void __init smdk2440_map_io(void)

325    {

326        s3c24xx_init_io(smdk2440_iodesc, ARRAY_SIZE(smdk2440_iodesc));

327        s3c24xx_init_clocks(12000000);//根据开发板合适的晶振配置

328        s3c24xx_init_uarts(smdk2440_uartcfgs, ARRAY_SIZE(smdk2440_uartcfgs));

329    }


继续分析UBOOT传入的需要解析的参数:


1)、noinitrd参数解析过程


当没有使用ramdisk启动系统的时候,你需要使用noinitrd这个参数,但是如果使用了的话,就需要指定initrd=r_addr,size, r_addr表示initrd在内存中的位置,size表示initrd的大小。看到代码里面,位于initDo_mounts_initrd.c下,可以看到处理函数只是简单的将mount_initrd 置为0,说明不支持ramdisk启动。


19    static int __init no_initrd(char *str)

20    {

21        mount_initrd = 0;

22        return 1;

23    }

24

25    __setup('noinitrd', no_initrd);


接着分析一下__setup的定义,看到includelinuxInit.h里面有它的定义。


160    #define __setup_param(str, unique_id, fn, early)           

161        static char __setup_str_##unique_id[] __initdata = str;   

162        static struct obs_kernel_param __setup_##unique_id   

163            __attribute_used__               

164            __attribute__((__section__('.init.setup')))   

165            __attribute__((aligned((sizeof(long)))))   

166            = { __setup_str_##unique_id, fn, early }

167

168    #define __setup_null_param(str, unique_id)           

169        __setup_param(str, unique_id, NULL, 0)

170

171    #define __setup(str, fn)                   

[1] [2] [3]
关键字:Linux移植  tag 引用地址:Linux移植之tag参数列表解析过程分析

上一篇:一、编写 s3c24x0 的 bootloader——介绍、看门狗及时钟设置
下一篇:Linux移植之内核启动过程start_kernel函数简析

推荐阅读最新更新时间:2024-11-12 18:06

【ARM】Linux驱动移植
#1驱动模块移植过程 ##1.1模块的第一种编译方法——改kconfig 第一步:改kconfig 文件在:Drivers/char/kconfig; tristate三态表示可以编译在模块 M ; bool表示只能被选择编 或不编 。 第二步:配置内核 make menuconfig后会自动生成供编译的.config文件。 wuchengbing@ubuntu:~/linux/kernel-2.6.13$ make menuconfig Device Drivers --- Character devices --- S3C2410 RTC Driver │ │
[单片机]
【ARM】<font color='red'>Linux</font>驱动<font color='red'>移植</font>
Linux-2.6.32.2内核在mini2440上的移植(十四)---移植看门狗驱动
移植环境 1,主机环境:VMare下CentOS 5.5 ,1G内存。 2,集成开发环境:Elipse IDE 3,编译编译环境:arm-linux-gcc v4.4.3,arm-none-linux-gnueabi-gcc v4.5.1。 4,开发板:mini2440,2M nor flash,128M nand flash。 5,u-boot版本:u-boot-2009.08 6,linux 版本:linux-2.6.32.2 7,参考文章: 嵌入式linux应用开发完全手册,韦东山,编著。 Mini2440 之Linux 移植开发实战指南 Linux-2.6.32.2 内核具有完善的S3C2440 的看梦狗驱动,我们只需配
[单片机]
嵌入式Linux之我行——u-boot-2009.08在2440上的移植详解(一)
一、移植环境 主 机:VMWare--Fedora 9 开发板:Mini2440--64MB Nand, Kernel:2.6.30.4 编译器: arm-linux-gcc-4.3.2.tgz u-boot: u-boot-2009.08.tar.bz2 二、移植步骤 本次移植的功能特点包括: 支持Nand Flash读写 支持从Nor/Nand Flash启动 支持CS8900或者DM9000网卡 支持Yaffs文件系统 支持USB下载(还未实现) 1. 了解u-boot主要的目录结构和启动流程,如下图。 u-boot的stage1代码通常放在cpu/xxxx/sta
[单片机]
嵌入式<font color='red'>Linux</font>之我行——u-boot-2009.08在2440上的<font color='red'>移植</font>详解(一)
ARM9:如何将linux2.6.38内核移植到TQ2440
  下面是linux2.6.38内核移植到TQ2440的具体步骤:   1.修改根目录的Makefile中的ARCH=arm,CROSS-COMPILE=arm-linux-   2.在arch/arm/mach-s3c2440/mach-smdk2440.c中,将163行的s3c24xx_init_clocks(16934400)改为s3c24xx_init_clocks(12000000)。   3.修改arch/arm/tools/mach-types中379行的362改为168,因为uboot中定义的机器码是168.   4.修改arch/arm/boot/中的Makefile文件,在58行添加@cp -f
[单片机]
linux-2.6.32在mini2440开发板上移植-配置USB外设
编者:因为LINUX内核对S3C2440的Host驱动的已经支持,而且支持的外设相当的丰富,所以这一部分只是进行配置就可以使用。因为配置的东西较多,没有给出详细的截图,看手册上介绍的就很明白。需要手册的请留下邮箱索取。 1 配置和测试USB 键盘、扫描器和鼠标 在内核源代码目录的终端输入:make menuconfig,依次选择如下子菜单项: Device Drivers --- HID Devices --- 按空格键选中“USB Human Interface Device (full HID) support”,这样就配置好了USB键盘和鼠标项。 提示:这里的配置选项对应的内核源代码目录是:linux-
[单片机]
Boa服务器在ARM+Linux上的移植
一、Boa服务器介绍 Boa是一种非常小巧的Web服务器,其可执行代码只有大约60KB左右。 作为一种单任务Web服务器,Boa只能依次完成用户的请求,而不会fork出新的进程来处理并发连接请求。但Boa支持CGI,能够为CGI程序fork出一个进程来执行。Boa的设计目标是速度和安全。 二、移植环境 (1) 源码的获取 Boa的源码可以从网站www.boa.org获取 (2) Boa移植平台 n PC机(RedHat9.0操作系统) n 交叉编译工具,arm-linux,最好是2.9的 三、移植步骤 (1) 解压源码$ tar xzvf boa-0.94-14.tar.gz (2) $cd boa-0.
[单片机]
移植标准Linux 操作系统到S3C2410
1 前 言 目前 , 在嵌入式系统里基于ARM核的嵌入式处理器已经成为市场主流。随着ARM技术的广泛应用 , 建立面向ARM构架的嵌入式操作系统也就成为当前研究的热点。S3C2410是SAMSUNG公司基于ARM920T处理器内核开发的一款16/32位嵌入式处理器,运行 频率 高达200多M,具有MMU和高速缓存等丰富片上资源,是目前基于ARM920T内核的出货量最大的一款芯片。目前嵌入式操作系统也较多,如 Tor2nado 的VxWork、微软的 Windows CE等等。大量开发人员选择的却都是Linux,这是因为它源代码开放,可以轻松修改移植到自己的目标平台系统里使用。并且事实证明,效果令人满意。两者的结合必将在嵌入
[单片机]
S3C2440 Linux驱动移植——NAND驱动
1. 修改分区表 打开文件arch/arm/plat-s3c24xx/common-smdk.c,修改mtd_partition结构体数组。 修改后如下: view plain copy static struct mtd_partition smdk_default_nand_part = { = { .name = Uboot , .size = 0x00040000, .offset = 0x00000000, }, = { .name = K
[单片机]
S3C2440 <font color='red'>Linux</font>驱动<font color='red'>移植</font>——NAND驱动
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved