A:UBOOT向LINUX内核传递参数的原理



(其中就指定了我们用那个串口来输出调试信息,一般CPU都有几路串口,LINUX内核中会按照CPU介绍手册中分配的顺序来列出串口序号,根据UBOOT传入参数来决定调用那几路)

UBOOT版本:uboot-2010.12.

相关函数调用简略关系:

do_bootm_linux->setup_commandline_tag->kernel_entry

 

do_bootm_linux/arch/arm/lib/bottm.c

当采用bootm来引导LINUX时在执行到引导LINUX流程时会执行到do_bootm_linux()函数(UBOOT使用BOOTM来引导LINUX的原理不在本节分析范围内,本节只分析传参原理)。

Do_bootm->do_bootm_linux:

 

#define DECLARE_GLOBAL_DATA_PTR     register volatile gd_t *gd asm ("r8")

 

bd_t*bd = gd->bd;

 

#ifdef CONFIG_CMDLINE_TAG

char *commandline = getenv ("bootargs");//获取传入的引导参数,我们参入的参数为:

Android-CommandLine = console=ttySAC0,115200n8 androidboot.console=ttySAC0 ctp=2 skipcali=y vmalloc=384m ethmac=1C:6F:65:34:51:7E androidboot.selinux=permissive

#endif

s = getenv ("machid");//获得机器码

machid = simple_strtoul (s, NULL, 16);

#if defined (CONFIG_SETUP_MEMORY_TAGS) || \

    defined (CONFIG_CMDLINE_TAG) || \

    defined (CONFIG_INITRD_TAG) || \

    defined (CONFIG_SERIAL_TAG) || \

    defined (CONFIG_REVISION_TAG)

setup_start_tag (bd); //params变量指向(struct tag *) bd->bi_boot_params;params指向一个tag地址,后面在对params的操作就是对tag的操作

#ifdef CONFIG_SERIAL_TAG

setup_serial_tag (¶ms);

/*

static void setup_start_tag (bd_t *bd)

{

params = (struct tag *) bd->bi_boot_params;//params指向

//gd->bd->bi_boot_params = (PHYS_SDRAM_1+0x100)=0x40000100;//在机器的板级引导文件中初始化

/arh/arm/board/厂家/具体CPU型号文件。

/* DRAM Base */

#define PHYS_SDRAM_1            CONFIG_SYS_SDRAM_BASE /* SDRAM Bank #1 */

 

#define CONFIG_SYS_SDRAM_BASE0x40000000

 

params->hdr.tag = ATAG_CORE; //

/* The list must start with an ATAG_CORE node */

#define ATAG_CORE0x54410001UBOOT传入参数时TAG标记的地址处第一个标记码必须在此是固定的,因为LINUX在解析是会判断这个地址处的这个值,相当才会解析的

params->hdr.size = tag_size (tag_core);

 

params->u.core.flags = 0;

params->u.core.pagesize = 0;

params->u.core.rootdev = 0;

 

params = tag_next (params);

params = tag_next (params);//params是一个链表,及是多个TAG结构体的结合,也就说明了UBOOT可以传入多种参数,操控台参数仅仅是其中一种,bd->bi_boot_params是开始地址,是传入LINXU的始地址,但传入不同的参数TAG时这个变量不能更改,但又为了传入多个值则必须由另一个变量来递增

}

*/

#endif

#ifdef CONFIG_REVISION_TAG

setup_revision_tag (¶ms);

#endif

#ifdef CONFIG_SETUP_MEMORY_TAGS

setup_memory_tags (bd);

#endif

#ifdef CONFIG_CMDLINE_TAG

setup_commandline_tag (bd, commandline);//把传入的命令行放入TAG

/*

static void setup_commandline_tag (bd_t *bd, char *commandline)

{

char *p;

 

if (!commandline)

return;

/* eat leading white space */

for (p = commandline; *p == ' '; p++);

/* skip non-existent command lines so the kernel will still

 * use its default command line.

 */

if (*p == '\0')

return;

params->hdr.tag = ATAG_CMDLINE;

///* command line: \0 terminated string */

#define ATAG_CMDLINE0x54410009对于传入的命令行参数的tag类型必须是唯一的,这儿应当在LINUX解析命令行参数时会判断的,不能错。

 

params->hdr.size =

(sizeof (struct tag_header) + strlen (p) + 1 + 4) >> 2;

 

strcpy (params->u.cmdline.cmdline, p);

 //struct tag_cmdline {

charcmdline[1];/* this is the minimum size */

};//把传入的参数存储在tag结构中的tag_cmdline数组中。提取时需要在儿去取

 

params = tag_next (params);

}

*/

#endif

#ifdef CONFIG_INITRD_TAG

if (images->rd_start && images->rd_end)

setup_initrd_tag (bd, images->rd_start, images->rd_end);

#endif

setup_end_tag(bd);

/*

static void setup_end_tag (bd_t *bd)

{

params->hdr.tag = ATAG_NONE;//TAG结束标记,在LINUX解析时解析到此变量说明传入的参数结束了,不再继续解析了。判断此内存处的变量值。

params->hdr.size = 0;

}

*/

#endif

上面代码中用一个gd,它是由一个DECLARE_GLOBAL_DATA_PTR在申明的,注册了一个寄存器变量gd,它代表寄存器r8,同时r8指向的是gd_t结构体变量,这个结构中存的是板级设备信息/arch/arm/include/asm/global_data.hbd指向gd->bd.通过上面代码我们要传入LINUX的参数存存储在了0x40000100开始的tag结构类型的一个链表中(可以传内存信息 初始化信息等TAG)。上面代码用的两个非常重要结构体如下:

struct tag {

struct tag_header hdr;

union {

struct tag_corecore;

struct tag_mem32mem;

struct tag_videotextvideotext;

struct tag_ramdiskramdisk;

struct tag_initrdinitrd;

struct tag_serialnrserialnr;

struct tag_revisionrevision;

struct tag_videolfbvideolfb;

struct tag_cmdlinecmdline;

/*

 * Acorn specific

 */

struct tag_acornacorn;

 

/*

 * DC21285 specific

 */

struct tag_memclkmemclk;

} u;

};//TAG结构体中列出了UBOOT可以传入LINUX的参数类型,看u共用体

 

typedefstructglobal_data {

bd_t*bd;

unsigned longflags;

unsigned longbaudrate;

unsigned longhave_console;/* serial_init() was called */

unsigned longenv_addr;/* Address  of Environment struct */

unsigned longenv_valid;/* Checksum of Environment valid? */

unsigned longfb_base;/* base address of frame buffer */

#ifdef CONFIG_VFD

unsigned charvfd_type;/* display type */

#endif

#ifdef CONFIG_FSL_ESDHC

unsigned longsdhc_clk;

#endif

#ifdef CONFIG_AT91FAMILY

/* "static data" needed by at91's clock.c */

unsigned longcpu_clk_rate_hz;

unsigned longmain_clk_rate_hz;

unsigned longmck_rate_hz;

unsigned longplla_rate_hz;

unsigned longpllb_rate_hz;

unsigned longat91_pllb_usb_init;

#endif

#ifdef CONFIG_ARM

/* "static data" needed by most of timer.c on ARM platforms */

unsigned longtimer_rate_hz;

unsigned longtbl;

unsigned longtbu;

unsigned long longtimer_reset_value;

unsigned longlastinc;

#endif

unsigned longrelocaddr;/* Start address of U-Boot in RAM */

phys_size_tram_size;/* RAM size */

unsigned longmon_len;/* monitor len */

unsigned longirq_sp;/* irq stack pointer */

unsigned longstart_addr_sp;/* start_addr_stackpointer */

unsigned longreloc_off;

#if !(defined(CONFIG_SYS_NO_ICACHE) && defined(CONFIG_SYS_NO_DCACHE))

unsigned longtlb_addr;

#endif

void**jt;/* jump table */

charenv_buf[32];/* buffer for getenv() before reloc. */

} gd_t; //这个结构体是定义的全局寄存器变量的类型结构本。说了我们定义全局寄存变量的类型为它。

通过上面代码我们要传入LINUX的参数存存储在了0x40000100开始的tag结构类型的一个链表中(可以传内存信息 初始化信息等TAG),由下面函数传入LINUX中。

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

R0=0,r1=machid,r2=0x40000100.

kernel_entry大致实现原理(具体细节不在本节分析范畴)

movpc CONFIG_PHY_UBOOT_BASE

#define CONFIG_PHY_UBOOT_BASECONFIG_SYS_SDRAM_BASE + 0x3e00000

/* DRAM Base */

#define CONFIG_SYS_SDRAM_BASE0x40000000

CONFIG_PHY_UBOOT_BASE=0x40000000+0x3e00000=0x43e00 0000//Linux内核代码的存放地址

通过上面调转就进入LINUX中了。

其中传和的参数分别为R0=0,r1=machid,r2=0x40000100.

同时0X40000100存放的内容为:

Android-CommandLine =console=ttySAC0,115200n8 androidboot.console=ttySAC0 ctp=2 skipcali=y vmalloc=384m ethmac=1C:6F:65:34:51:7E androidboot.selinux=permissive】黑体字为我们在LINUX中要观注的,其它的暂时不分析

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值