嵌入式3. U-Boot

【uboot本质】


(1)uboot的本质就是一个裸机程序,和我们裸机全集中写的那些裸机程序xx.bin并没有本质区别。
如果非说要有区别,那就是:我们写的大部分小于16KB,而uboot大于16KB(一般uboot在180k-400k之间)
(2)uboot本身是一个开源项目,由若干个.c文件和.h文件组成,
配置编译之后会生成一个uboot.bin,这就是uboot这个裸机程序的镜像文件。
然后这个镜像文件被合理的烧录到启动介质中拿给SoC去启动。也就是说uboot在没有运行时表现为uboot.bin,
一般躺在启动介质中。

U-boot的工作模式

  • 启动加载模式:

启动加载模式,为Bootloader正常工作模式,一款开发板,正常上电后,Bootloader将嵌入式操作系统==从FLASH中加载到SDRAM中==运行。

  • 下载模式:

下载模式,就是Bootloader通过通信,将内核镜像、根文件系统镜像从PC机直接下载到目标板的FLASH中

启动流程

编辑 播报

大多数BootLoader都分为stage1和stage2两大部分,U-boot也不例外。依赖于cpu体系结构的代码(如设备初始化代码等)通常都放在stage1且可以用汇编语言来实现,而stage2则通常用C语言来实现,这样可以实现复杂的功能,而且有更好的可读性和移植性。

1、 stage1(start.s代码结构)

U-boot的stage1代码通常放在start.s文件中,它用汇编语言写成,其主要代码部分如下:

(1) 定义入口。由于一个可执行的image必须有一个入口点,并且只能有一个全局入口,通常这个入口放在rom(Flash)的0x0地址,因此,必须通知编译器以使其知道这个入口,该工作可通过修改连接器脚本来完成。

(2)设置异常向量(exception vector)。

(3)设置CPU的速度、时钟频率及中断控制寄存器

(4)初始化内存控制器 。

(5)将rom中的程序复制到ram中。

(6)初始化堆栈 。

(7)转到ram中执行,该工作可使用指令ldrpc来完成。

2、 stage2(C语言代码部分)

lib_arm/board.c中的start armboot是C语言开始的函数,也是整个启动代码中C语言的主函数,同时还是整个u-boot(armboot)的主函数,该函数主要完成如下操作:

(1)调用一系列的初始化函数。

(2)初始化flash设备。

(3)初始化系统内存分配函数。

(4)如果目标系统拥有nand设备,则初始化nand设备。

(5)如果目标系统有显示设备,则初始化该类设备。

(6)初始化相关网络设备,填写ip,c地址等。

(7)进入命令循环(即整个boot的工作循环),接受用户从串口输入的命令,然后进行相应的工作。

我所接触过三个平台

MTK: boot rom -> preloader -> lk (可以理解是uboot) -> kernel

RK: bootrom -> spl(miniloader) -> uboot->trust (optee) -> kernel

NXP: bootrom -> bl2 -> ATF ->uboot->kernel

u-boot启动详细函数调用流程

u-boot:启动详细的代码调用流程
u-boot.lds:(arch/arm/cpu/u-boot.lds)
    |-->_start:(arch/arm/lib/vectors.S)
        |-->reset(arch/arm/cpu/armv7/start.S)    
            |-->save_boot_params(arch/arm/cpu/armv7/start.S)/*将引导参数保存到内存中*/
                |-->save_boot_params_ret(arch/arm/cpu/armv7/start.S)
                    |-->cpu_init_cp15(arch/arm/cpu/armv7/start.S)/*初始化*/
                    |-->cpu_init_crit(arch/arm/cpu/armv7/start.S)
                        |-->lowlevel_init(arch/arm/cpu/armv7/lowlevel_init.S)
                    |-->_main(arch/arm/lib/crt0.S)
                        |-->board_init_f_alloc_reserve(common/init/board_init.c)/*为u-boot的gd结构体分配空间*/
                        |-->board_init_f_init_reserve(common/init/board_init.c)    /*将gd结构体清零*/
                        |-->board_init_f(common/board_f.c)
                            |-->initcall_run_list(include/initcall.h)    /*初始化序列函数*/
                                |-->init_sequence_f[](common/board_f.c)    /* 初始化序列函数数组 */
                                    |-->board_early_init_f(board/freescale/mx6ull_toto/mx6ull_toto.c)/*初始化串口的IO配置*/
                                    |-->timer_init(arch/arm/imx-common/timer.c)    /*初始化内核定时器,为uboot提供时钟节拍*/
                                    |-->init_baud_rate(common/board_f.c)        /*初始化波特率*/
                                    |-->serial_init(drivers/serial/serial.c)    /*初始化串口通信设置*/
                                    |-->console_init_f(common/console.c)        /*初始化控制台*/
                                    |-->...
                        |-->relocate_code(arch/arm/lib/relocate.S)    /*主要完成镜像拷贝和重定位*/
                        |-->relocate_vectors(arch/arm/lib/relocate.S)/*重定位向量表*/
                        |-->board_init_r(common/board_r.c)/*板级初始化*/
                            |-->initcall_run_list(include/initcall.h)/*初始化序列函数*/
                                |-->init_sequence_r[](common/board_f.c)/*序列函数*/
                                    |-->initr_reloc(common/board_r.c)    /*设置 gd->flags,标记重定位完成*/
                                    |-->serial_initialize(drivers/serial/serial-uclass.c)/*初始化串口*/
                                        |-->serial_init(drivers/serial/serial-uclass.c)     /*初始化串口*/
                                    |-->initr_mmc(common/board_r.c)                         /*初始化emmc*/
                                        |-->mmc_initialize(drivers/mmc/mmc.c)
                                            |-->mmc_do_preinit(drivers/mmc/mmc.c)
                                                |-->mmc_start_init(drivers/mmc/mmc.c)
                                    |-->console_init_r(common/console.c)                /*初始化控制台*/
                                    |-->interrupt_init(arch/arm/lib/interrupts.c)        /*初始化中断*/
                                    |-->initr_net(common/board_r.c)                        /*初始化网络设备*/
                                        |-->eth_initialize(net/eth-uclass.c)
                                            |-->eth_common_init(net/eth_common.c)
                                                |-->phy_init(drivers/net/phy/phy.c)
                                            |-->uclass_first_device_check(drivers/core/uclass.c)
                                                |-->uclass_find_first_device(drivers/core/uclass.c)
                                                |-->device_probe(drivers/core/device.c)
                                                    |-->device_of_to_plat(drivers/core/device.c)
                                                        |-->drv->of_to_plat
                                                            |-->fecmxc_of_to_plat(drivers/net/fec_mxc.c)/*解析设备树信息*/
                                                    |-->device_get_uclass_id(drivers/core/device.c)
                                                    |-->uclass_pre_probe_device(drivers/core/uclass.c)
                                                    |-->drv->probe(dev)
                                                        /*drivers/net/fec_mxc.c*/
                                                        U_BOOT_DRIVER(fecmxc_gem) = {
                                                            .name    = "fecmxc",
                                                            .id    = UCLASS_ETH,
                                                            .of_match = fecmxc_ids,
                                                            .of_to_plat = fecmxc_of_to_plat,
                                                            .probe    = fecmxc_probe,
                                                            .remove    = fecmxc_remove,
                                                            .ops    = &fecmxc_ops,
                                                            .priv_auto    = sizeof(struct fec_priv),
                                                            .plat_auto    = sizeof(struct eth_pdata),
                                                        };
                                                        |-->fecmxc_probe(drivers/net/fec_mxc.c)/*探测和初始化*/
                                                            |-->fec_get_miibus(drivers/net/fec_mxc.c)
                                                                |-->mdio_alloc(drivers/net/fec_mxc.c)
                                                                |-->bus->read = fec_phy_read;
                                                                |-->bus->write = fec_phy_write;
                                                                |-->mdio_register(common/miiphyutil.c)
                                                                |-->fec_mii_setspeed(drivers/net/fec_mxc.c)
                                                            |-->fec_phy_init(drivers/net/fec_mxc.c)
                                                                |-->device_get_phy_addr(drivers/net/fec_mxc.c)
                                                                |-->phy_connect(drivers/net/phy/phy.c)
                                                                    |-->phy_find_by_mask(drivers/net/phy/phy.c)
                                                                        |-->bus->reset(bus)
                                                                        |-->get_phy_device_by_mask(drivers/net/phy/phy.c)
                                                                            |-->create_phy_by_mask(drivers/net/phy/phy.c)
                                                                                |-->phy_device_create(drivers/net/phy/phy.c)
                                                                                    |-->phy_probe(drivers/net/phy/phy.c)
                                                                    |-->phy_connect_dev(drivers/net/phy/phy.c)
                                                                        |-->phy_reset(drivers/net/phy/phy.c)
                                                                |-->phy_config(drivers/net/phy/phy.c)
                                                                    |-->board_phy_config(drivers/net/phy/phy.c)
                                                                        |-->phydev->drv->config(phydev)
                                                                            /*drivers/net/phy/smsc.c*/
                                                                            static struct phy_driver lan8710_driver = {
                                                                                .name = "SMSC LAN8710/LAN8720",
                                                                                .uid = 0x0007c0f0,
                                                                                .mask = 0xffff0,
                                                                                .features = PHY_BASIC_FEATURES,
                                                                                .config = &genphy_config_aneg,
                                                                                .startup = &genphy_startup,
                                                                                .shutdown = &genphy_shutdown,
                                                                            };
                                                                            |-->genphy_config_aneg(drivers/net/phy/phy.c)
                                                                                |-->phy_reset(需要手动调用)(drivers/net/phy/phy.c)
                                                                                |-->genphy_setup_forced(drivers/net/phy/phy.c)
                                                                                |-->genphy_config_advert(drivers/net/phy/phy.c)
                                                                                |-->genphy_restart_aneg(drivers/net/phy/phy.c)
                                                    |-->uclass_post_probe_device(drivers/core/uclass.c)
                                                        |-->uc_drv->post_probe(drivers/core/uclass.c)
                                                            /*net/eth-uclass.c*/
                                                            UCLASS_DRIVER(ethernet) = {
                                                                .name        = "ethernet",
                                                                .id        = UCLASS_ETH,
                                                                .post_bind    = eth_post_bind,
                                                                .pre_unbind    = eth_pre_unbind,
                                                                .post_probe    = eth_post_probe,
                                                                .pre_remove    = eth_pre_remove,
                                                                .priv_auto    = sizeof(struct eth_uclass_priv),
                                                                .per_device_auto    = sizeof(struct eth_device_priv),
                                                                .flags        = DM_UC_FLAG_SEQ_ALIAS,
                                                            };
                                                            |-->eth_post_probe(net/eth-uclass.c)
                                                                |-->eth_write_hwaddr(drivers/core/uclass.c)
                                    |-->...
                                    |-->run_main_loop(common/board_r.c)/*主循环,处理命令*/
                                        |-->main_loop(common/main.c)
                                            |-->bootdelay_process(common/autoboot.c)    /*读取环境变量bootdelay和bootcmd的内容*/
                                            |-->autoboot_command(common/autoboot.c)        /*倒计时按下执行,没有操作执行bootcmd的参数*/
                                                |-->abortboot(common/autoboot.c)
                                                    |-->printf("Hit any key to stop autoboot: %2d ", bootdelay);
                                                    /*到这里就是我们看到uboot延时3s启动内核的地方*/
                                            |-->cli_loop(common/cli.c)    /*倒计时按下space键,执行用户输入命令*/

程序入口

U-Boot 源码文件众多,我们如何知道最开始的启动文件(程序入口)是哪个呢?程序的链接是由链接脚本来决定的,所以通过链接脚本可以找到程序的入口,链接脚本为arch/arm/cpu/u-boot.lds,它描述了如何生成最终的二进制文件,其中就包含程序入口。

参考: u-boot启动流程分析-史上最全最详细 - 知乎 (zhihu.com)

链接脚本 u-boot.lds 详解

u-boot.lds

u-boot.lds:文件所在位置arch/arm/cpu/u-boot.lds

/* SPDX-License-Identifier: GPL-2.0+ */
/*
 * Copyright (c) 2004-2008 Texas Instruments
 *
 * (C) Copyright 2002
 * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
 */

#include <config.h>
#include <asm/psci.h>

/* 指定输出可执行文件: "elf 32位 小端格式 arm指令" */
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
/* 指定输出可执行文件的目标架构:"arm" */
OUTPUT_ARCH(arm)
/* 指定输出可执行文件的起始地址为:"_start" */
ENTRY(_start)
SECTIONS
{
#ifndef CONFIG_CMDLINE
    /DISCARD/ : { *(__u_boot_list_2_cmd_*) }
#endif
#if defined(CONFIG_ARMV7_SECURE_BASE) && defined(CONFIG_ARMV7_NONSEC)
    /*
     * If CONFIG_ARMV7_SECURE_BASE is true, secure code will not
     * bundle with u-boot, and code offsets are fixed. Secure zone
     * only needs to be copied from the loading address to
     * CONFIG_ARMV7_SECURE_BASE, which is the linking and running
     * address for secure code.
     *
     * If CONFIG_ARMV7_SECURE_BASE is undefined, the secure zone will
     * be included in u-boot address space, and some absolute address
     * were used in secure code. The absolute addresses of the secure
     * code also needs to be relocated along with the accompanying u-boot
     * code.
     *
     * So DISCARD is only for CONFIG_ARMV7_SECURE_BASE.
     */
    /DISCARD/ : { *(.rel._secure*) }
#endif
    /* 
     * 指定可执行文件(image)的全局入口地址,通常都放在ROM(flash)0x0位置
     * 设置 0 的原因是 arm 内核的处理器,上电后默认是从 0x00000000 处启动
     */
    . = 0x00000000;

    . = ALIGN(4);                     ``````````/* 中断向量表 */
    .text :
    {
        *(.__image_copy_start)         /* u-boot 的设计中需要将 u-boot 的镜像拷贝到 ram(sdram,ddr....)中执行,这里表示复制的开始地址 */
        *(.vectors)                    /* 中断向量表 */
        CPUDIR/start.o (.text*)        /* CPUDIR/start.o 中的所有.text 段 */
    }

    /* This needs to come before *(.text*) */
    .__efi_runtime_start : {
        *(.__efi_runtime_start)
    }

    .efi_runtime : {
        *(.text.efi_runtime*)
        *(.rodata.efi_runtime*)
        *(.data.efi_runtime*)
    }

    .__efi_runtime_stop : {
        *(.__efi_runtime_stop)
    }

    .text_rest :
    {
        *(.text*)
    }

#ifdef CONFIG_ARMV7_NONSEC

    /* Align the secure section only if we're going to use it in situ */
    .__secure_start
#ifndef CONFIG_ARMV7_SECURE_BASE
        ALIGN(CONSTANT(COMMONPAGESIZE))
#endif
    : {
        KEEP(*(.__secure_start))
    }

#ifndef CONFIG_ARMV7_SECURE_BASE
#define CONFIG_ARMV7_SECURE_BASE
#define __ARMV7_PSCI_STACK_IN_RAM
#endif

    .secure_text CONFIG_ARMV7_SECURE_BASE :
        AT(ADDR(.__secure_start) + SIZEOF(.__secure_start))
    {
        *(._secure.text)
    }

    .secure_data : AT(LOADADDR(.secure_text) + SIZEOF(.secure_text))
    {
        *(._secure.data)
    }

#ifdef CONFIG_ARMV7_PSCI
    .secure_stack ALIGN(ADDR(.secure_data) + SIZEOF(.secure_data),
                CONSTANT(COMMONPAGESIZE)) (NOLOAD) :
#ifdef __ARMV7_PSCI_STACK_IN_RAM
        AT(ADDR(.secure_stack))
#else
        AT(LOADADDR(.secure_data) + SIZEOF(.secure_data))
#endif
    {
        KEEP(*(.__secure_stack_start))

        /* Skip addreses for stack */
        . = . + CONFIG_ARMV7_PSCI_NR_CPUS * ARM_PSCI_STACK_SIZE;

        /* Align end of stack section to page boundary */
        . = ALIGN(CONSTANT(COMMONPAGESIZE));

        KEEP(*(.__secure_stack_end))

#ifdef CONFIG_ARMV7_SECURE_MAX_SIZE
        /*
         * We are not checking (__secure_end - __secure_start) here,
         * as these are the load addresses, and do not include the
         * stack section. Instead, use the end of the stack section
         * and the start of the text section.
         */
        ASSERT((. - ADDR(.secure_text)) <= CONFIG_ARMV7_SECURE_MAX_SIZE,
               "Error: secure section exceeds secure memory size");
#endif
    }

#ifndef __ARMV7_PSCI_STACK_IN_RAM
    /* Reset VMA but don't allocate space if we have secure SRAM */
    . = LOADADDR(.secure_stack);
#endif

#endif

    .__secure_end : AT(ADDR(.__secure_end)) {
        *(.__secure_end)
        LONG(0x1d1071c);    /* Must output something to reset LMA */
    }
#endif
    /* 
     * .rodata 段,确保是以4字节对齐 
     */
    . = ALIGN(4);
    .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }

    /* 
     * data段,确保是以4字节对齐
     */
    . = ALIGN(4);
    .data : {
        *(.data*)
    }

    . = ALIGN(4);

    . = .;

    /* 
     * u_boot_list 段,确保是以 4 字节对齐 
     * 这里存放的都是 u_boot_list 中的函数
     */
    . = ALIGN(4);
    __u_boot_list : {
        KEEP(*(SORT(__u_boot_list*)));
    }

    . = ALIGN(4);

    .efi_runtime_rel_start :
    {
        *(.__efi_runtime_rel_start)
    }

    .efi_runtime_rel : {
        *(.rel*.efi_runtime)
        *(.rel*.efi_runtime.*)
    }

    .efi_runtime_rel_stop :
    {
        *(.__efi_runtime_rel_stop)
    }

    /* 
     * __image_copy_end 也是个符号表示一个结束地址,确保是以4字节对齐 
     */
    . = ALIGN(4);

    .image_copy_end :        /* u-boot 的设计中需要将 u-boot 的镜像拷贝到ram(sdram,ddr....)中执行,这里表示复制的结束地址 */
    {
        *(.__image_copy_end)
    }

    .rel_dyn_start :        /*  .rel.dyn 段起始地址 */
    {
        *(.__rel_dyn_start)
    }

    .rel.dyn : {
        *(.rel*)
    }

    .rel_dyn_end :            /*  .rel.dyn 段结束地址 */
    {
        *(.__rel_dyn_end)
    }

    .end :
    {
        *(.__end)
    }

    _image_binary_end = .;    /* bin文件结束地址 */

    /*
     * Deprecated: this MMU section is used by pxa at present but
     * should not be used by new boards/CPUs.
     */
    . = ALIGN(4096);
    .mmutable : {
        *(.mmutable)
    }

/*
 * Compiler-generated __bss_start and __bss_end, see arch/arm/lib/bss.c
 * __bss_base and __bss_limit are for linker only (overlay ordering)
 */

    .bss_start __rel_dyn_start (OVERLAY) : {    /* .bss段起始地址 */
        KEEP(*(.__bss_start));
        __bss_base = .;
    }

    .bss __bss_base (OVERLAY) : {
        *(.bss*)
         . = ALIGN(4);
         __bss_limit = .;
    }

    .bss_end __bss_limit (OVERLAY) : {            /* .bss段结束地址 */
        KEEP(*(.__bss_end));
    }

    .dynsym _image_binary_end : { *(.dynsym) }
    .dynbss : { *(.dynbss) }
    .dynstr : { *(.dynstr*) }
    .dynamic : { *(.dynamic*) }
    .plt : { *(.plt*) }
    .interp : { *(.interp*) }
    .gnu.hash : { *(.gnu.hash) }
    .gnu : { *(.gnu*) }
    .ARM.exidx : { *(.ARM.exidx*) }
    .gnu.linkonce.armexidx : { *(.gnu.linkonce.armexidx.*) }
}

通过上面的分析可以看出: 由于在链接脚本中规定了文件start.o(对应于start.S)作为整个uboot的起始点,因此启动uboot时会执行首先执行start.S。 一般来说,内存空间可分为代码段、数据段、全局变量段、未初始化变量区、栈区、堆区等.其中,栈区由指针SP决定,堆区实质上是由C代码实现的,其它段则由编译器决定.从上面的分析可以看出,从0x00000000地址开始,编译器首先将代码段放在最开始的位置,然后是数据段,然后是bss段(未初始化变量区)。

u-boot.map

u-boot.map 是uboot的映射文件,可以从此文件看到某个文件或者函数链接到了哪个地址,下面打开 u-boot.map,查看各个段的起始地址和结束分别是多少;

从u-boot.map映射文件种,可以知道__image_copy_start为0X87800000,而.text的起始地址也是0X87800000,vectors 段的起始地址也是0X87800000,可以得出各个段的地址关系表,如下;

变量名地址描述
__image_copy_start0x87800000u-boot拷贝的起始地址
__image_copy_end0x87850ff0u-boot拷贝的结束地址
.vectors0x87800000中断向量表的起始地址
.text0x878002e8.text段的起始地址
__rel_dyn_start0x87850ff0.rel_dyn段的起始地址
__rel_dyn_end0x8785cf30.rel_dyn段的结束地址
_image_binary_end0x8785cf30镜像结束地址
__bss_start0x87850ff0.bss段的起始地址
__bss_end0x878585c0.bss段的结束地址

注:表中的变量除了__image_copy_start以外,其他的变量值每次编译的时候可能会变化。修改uboot 代码、配置等都会影响到这些值。所以,一切以实际值为准!

uboot的简化版启动流程:

1、设置状态寄存器 cpsr ,使CPU进入 SVC 特权模式,并且禁止 FIQ 和 IRQ;

2、关闭看门狗、中断、MMU、Cache;

3、初始化部分寄存器和外设(时钟、串口、Flash、内存);

4、自搬移uboot到内存中运行;

5、设置栈空间并初始化global_data;

6、剩余大部分硬件的初始化;

7、搬移Linux内核到内存;

如何编译Uboot

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CORSS_COMPILE=arm-linux-gnueabihf- colibri-imx6ull_defconfig
make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j8

ARCH=arm:arm架构

CROSS_COMPILE:使用的交叉编译器

如果编译出错,your compile older 6.0,可以参考【 1

colibri-imx6ull_defconfig:指定一个config文件,作为相关版型的配置信息

V=1:这个选项能显示出编译过程中的详细信息,即是verbose编译模式

-j8:多核并行编译,可以提高编译速度,受硬件限制

U-boot的存放位置

嵌入式系统,一般使用Flash来作为启动设备,Flash上存储着U-boot、环境变量、内核映像、文件系统等。U-boot存放于Flash的起始地址,所在扇区由Soc规定。

掌握uboot使用的2个关键点:命令和环境变量

环境变量值得注意的有两个:bootcmd和bootargs。

bootcmd:自动启动时执行的命令

uboot上电启动后会自动倒数bootdelay秒,如果没有人按下回车打断启动,则uboot会自动执行bootcmd启动命令来启动内核。

例如:bootcmd=boot_logo;nand read 1000000 3c0000 300000;bootm 1000000

意思是启动u-boot后,执行boot_logo显示logo信息,然后从nand flash中读内核映像到内存,然后启动内核。

bootargs:传递给内核的启动参数

这个参数也比较重要,如果没有设置对,内核很有可能启动不起来,报Not init found之类的日志。还有之前说的Uboot支持多种启动方式也是通过这个bootargs来区分到底是什么方式启动内核的。

下面介绍一下bootargs常用参数,bootargs的种类非常的多,而且随着kernel的发展会出现一些新的参数,使得设置会更加灵活多样。

A. root

用来指定rootfs的位置, 常见的情况有:

root=/dev/ram rw
root=/dev/ram0 rw

请注意上面的这两种设置情况是通用的。

root=/dev/mtdx rw
root=/dev/mtdblockx rw
root=/dev/mtdblock/x rw

上面的这几个在一定情况下是通用的,当然这要看你当前的系统是否支持,不过mtd是字符设备,而mtdblock是块设备,有时候你的挨个的试到底当前的系统支持上面那种情况下,不过root=/dev/mtdblockx rw比较通用。

root=/dev/nfs

在文件系统为基于nfs的文件系统的时候使用。当然指定root=/dev/nfs之后,还需要指定nfsroot=serverip:nfs_dir,即指明文件系统存在那个主机的那个目录下面。

B console

console=tty使用虚拟串口终端设备.

console=ttyS[,options]使用特定的串口,options可以是这样的形式bbbbpnx,这里bbbb是指串口的波特率,p是奇偶位(从来没有看过使用过),n是指的bits。

console=ttySAC[,options]同上面。

console=ttyS0,115200 

上面是使用特定的串口

C. mem

mem=xxM

指定内核使用内存的大小,不是必须的。

比如物理内存是1024M, mem=1000M,那么最后保留的24M不被内核使用。这种方法适用于没有DTS的Linux版本,kernle的参数通过cmdline传递过去。

对于有DTS的Linux版本,kernel的参数是通过设备树传入的,因此需要修改设备树的reserved-memory来保留预留内存,所以目前这个方法用的比较多

D. ramdisk_size

ramdisk=xxxxx不推荐
ramdisk_size=xxxxx推荐

上面这两个都可以告诉ramdisk驱动,创建的ramdisk的size,默认情况下是4m(s390默认8M),你可以查看Documentation/ramdisk.txt找到相关的描述,不过ramdisk=xxxxx在新版的内核都已经没有提了,不推荐使用。

E. initrd, noinitrd

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

用bootz和booti (kernel_addr_r)(initrd) (fdt_addr_r)命令启动内核时,就要指定initrd内存地址,不然一般用-表示不用initrd内存地址

F. init

init指定的是内核启起来后,进入系统中运行的第一个脚本,一般init=/linuxr。/linuxrc指的是/目录下面的linuxrc脚本,一般是一个连接罢了

G. mtdparts

mtdparts=fc000000.nor_flash:1920k(linux),128k(fdt),20M(ramdisk),4M(jffs2),38272k(user),256k(env),384k(uboot)

要想这个参数起作用,内核中的mtd驱动必须要支持,即内核配置时需要选上Device Drivers ---> Memory Technology Device (MTD) support ---> Command line partition table parsing

mtdparts的格式如下:

mtdparts=[;
:= :[,]
:= [@offset][][ro]
:= unique id used in mapping driver/device
:= standard linux memsize OR "-" to denote all remaining space
:= (NAME)


因此你在使用的时候需要按照下面的格式来设置:
mtdparts=mtd-id:@(),@()
这里面有几个必须要注意的:
a. mtd-id 必须要跟你当前平台的flash的mtd-id一致,不然整个mtdparts会失效
b. size在设置的时候可以为实际的size(xxM,xxk,xx),也可以为'-'这表示剩余的所有空间。
举例:
假设flash 的mtd-id是sa1100,那么你可以使用下面的方式来设置:
mtdparts=sa1100:- → 只有一个分区
mtdparts=sa1100:256k(ARMboot)ro,-(root) → 有两个分区
可以查看drivers/mtd/cmdlinepart.c中的注释找到相关描述。

说完常见的几种bootargs,那么我们来讨论平常我经常使用的几种组合:
1). 假设文件系统是ramdisk,且直接就在内存中,bootargs的设置应该如下:

setenv bootargs ‘initrd=0x32000000,0xa00000 root=/dev/ram0 console=ttySAC0 mem=64M init=/linuxrc’

2). 假设文件系统是ramdisk,且在flash中,bootargs的设置应该如下:

setenv bootargs ‘mem=32M console=ttyS0,115200 root=/dev/ram rw init=/linuxrc’

注意这种情况下你应该要在bootm命令中指定ramdisk在flash中的地址,如bootm kernel_addr ramdisk_addr (fdt_addr)

3). 假设文件系统是jffs2类型的,且在flash中,bootargs的设置应该如下

setenv bootargs ‘mem=32M console=ttyS0,115200 noinitrd root=/dev/mtdblock2 rw rootfstype=jffs2 init=/linuxrc’

4).假设文件系统是基于nfs的,bootargs的设置应该如下

setenv bootargs ‘noinitrd mem=64M console=ttySAC0 root=/dev/nfs nfsroot=192.168.0.3:/nfs ip=192.168.0.5:192.168.0.3:192.168.0.3:255.255.255.0::eth0:off’
或者
setenv bootargs ‘noinitrd mem=64M console=ttySAC0 root=/dev/nfs nfsroot=192.168.0.3:/nfs ip=192.168.0.5’

下面是指rootfs在EMMC第三分区里启动

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值