u-boot与linux内核交互,U-Boot与Linux内核的交互

说明:本文所使用的U-Boot的版本是1.1.6,平台是S3C2440。

目录

一、简介

1.1标记列表

二、设置标记存放的地址

2.1相关的结构体定义

2.2标记存放地址的设定

三、标记的设置

3.1设置标记ATAG_CORE

3.2设置内存标记ATAG_MEM

3.3设置命令行标记ATAG_CMDLINE

3.4设置ATAG_NONE

一、简介

U-Boot与Linux内核的交互是单向的,U-Boot将各类参数传递给讷河。由于他们不能同时运行,传递办法只能有一个个:U-Boot将参数放在某个约定的地方之后,在启动内核,内核启动后从这个地方获得参数。

1.1标记列表

除了约定好参数存放的地方外,还要规定参数的结构。Linux2.4.x以后的内核都以标记列表(tagged

list)的形式来传递参数。标记就是一种数据结构;标记列表就是挨着存放的多个标记。标记列表以标记ATAG_CORE开始,以ATAGE_NONE结束。

标记的数据结构为tag,它是偶一个tag_header结构和一个联合体(union)组成。tag_header结构体表示标记的类型及长度,比如是表示内存还是表示命令行参数等。对于不同类型的标记使用不同的联合体,比如表示内存=时使用tag_men32,表示命令行时使用tag_cmdline。其定定义在include/asm-arm/setup.c文件中。

/*

* The new way of passing information: a list of tagged entries

*/

/* The list ends with an ATAG_NONE node. */

#define ATAG_NONE   0x00000000

struct tag_header {

u32 size;

u32 tag;

};

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

#define ATAG_CORE   0x54410001

struct tag_core {

u32 flags;      /* bit 0 = read-only */

u32 pagesize;

u32 rootdev;

};

/* it is allowed to have multiple ATAG_MEM nodes */

#define ATAG_MEM    0x54410002

struct tag_mem32 {

u32 size;

u32 start;  /* physical start address */

};

/* VGA text type displays */

#define ATAG_VIDEOTEXT  0x54410003

struct tag_videotext {

u8      x;

u8      y;

u16     video_page;

u8      video_mode;

u8      video_cols;

u16     video_ega_bx;

u8      video_lines;

u8      video_isvga;

u16     video_points;

};

/* describes how the ramdisk will be used in kernel */

#define ATAG_RAMDISK    0x54410004

struct tag_ramdisk {

u32 flags;  /* bit 0 = load, bit 1 = prompt */

u32 size;   /* decompressed ramdisk size in _kilo_ bytes */

u32 start;  /* starting block of floppy-based RAM disk image */

};

/* describes where the compressed ramdisk image lives (virtual address) */

/*

* this one accidentally used virtual addresses - as such,

* its depreciated.

*/

#define ATAG_INITRD 0x54410005

/* describes where the compressed ramdisk image lives (physical address) */

#define ATAG_INITRD2    0x54420005

struct tag_initrd {

u32 start;  /* physical start address */

u32 size;   /* size of compressed ramdisk image in bytes */

};

/* board serial number. "64 bits should be enough for everybody" */

#define ATAG_SERIAL 0x54410006

struct tag_serialnr {

u32 low;

u32 high;

};

/* board revision */

#define ATAG_REVISION   0x54410007

struct tag_revision {

u32 rev;

};

/* initial values for vesafb-type framebuffers. see struct screen_info

* in include/linux/tty.h

*/

#define ATAG_VIDEOLFB   0x54410008

struct tag_videolfb {

u16     lfb_width;

u16     lfb_height;

u16     lfb_depth;

u16     lfb_linelength;

u32     lfb_base;

u32     lfb_size;

u8      red_size;

u8      red_pos;

u8      green_size;

u8      green_pos;

u8      blue_size;

u8      blue_pos;

u8      rsvd_size;

u8      rsvd_pos;

};

/* command line: \0 terminated string */

#define ATAG_CMDLINE    0x54410009

struct tag_cmdline {

char    cmdline[1]; /* this is the minimum size */

};

/* acorn RiscPC specific information */

#define ATAG_ACORN  0x41000101

struct tag_acorn {

u32 memc_control_reg;

u32 vram_pages;

u8 sounddefault;

u8 adfsdrives;

};

/* footbridge memory clock, see arch/arm/mach-footbridge/arch.c */

#define ATAG_MEMCLK 0x41000402

struct tag_memclk {

u32 fmemclk;

};

struct tag {

struct tag_header hdr;

union {

struct tag_core     core;

struct tag_mem32    mem;

struct tag_videotext    videotext;

struct tag_ramdisk  ramdisk;

struct tag_initrd   initrd;

struct tag_serialnr serialnr;

struct tag_revision revision;

struct tag_videolfb videolfb;

struct tag_cmdline  cmdline;

/*

* Acorn specific

*/

struct tag_acorn    acorn;

/*

* DC21285 specific

*/

struct tag_memclk   memclk;

} u;

};

#define tag_next(t)((struct tag *)((u32 *)(t) + (t)->hdr.size))

#define tag_size(type)((sizeof(struct tag_header) + sizeof(struct type)) >> 2) //???/*

* The new way of passing information: a list of tagged entries

*/

/* The list ends with an ATAG_NONE node. */

#define ATAG_NONE0x00000000

struct tag_header {

u32 size;

u32 tag;

};

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

#define ATAG_CORE0x54410001

struct tag_core {

u32 flags;/* bit 0 = read-only */

u32 pagesize;

u32 rootdev;

};

/* it is allowed to have multiple ATAG_MEM nodes */

#define ATAG_MEM0x54410002

struct tag_mem32 {

u32size;

u32start;/* physical start address */

};

/* VGA text type displays */

#define ATAG_VIDEOTEXT0x54410003

struct tag_videotext {

u8x;

u8y;

u16video_page;

u8video_mode;

u8video_cols;

u16video_ega_bx;

u8video_lines;

u8video_isvga;

u16video_points;

};

/* describes how the ramdisk will be used in kernel */

#define ATAG_RAMDISK0x54410004

struct tag_ramdisk {

u32 flags;/* bit 0 = load, bit 1 = prompt */

u32 size;/* decompressed ramdisk size in _kilo_ bytes */

u32 start;/* starting block of floppy-based RAM disk image */

};

/* describes where the compressed ramdisk image lives (virtual address) */

/*

* this one accidentally used virtual addresses - as such,

* its depreciated.

*/

#define ATAG_INITRD0x54410005

/* describes where the compressed ramdisk image lives (physical address) */

#define ATAG_INITRD20x54420005

struct tag_initrd {

u32 start;/* physical start address */

u32 size;/* size of compressed ramdisk image in bytes */

};

/* board serial number. "64 bits should be enough for everybody" */

#define ATAG_SERIAL0x54410006

struct tag_serialnr {

u32 low;

u32 high;

};

/* board revision */

#define ATAG_REVISION0x54410007

struct tag_revision {

u32 rev;

};

/* initial values for vesafb-type framebuffers. see struct screen_info

* in include/linux/tty.h

*/

#define ATAG_VIDEOLFB0x54410008

struct tag_videolfb {

u16lfb_width;

u16lfb_height;

u16lfb_depth;

u16lfb_linelength;

u32lfb_base;

u32lfb_size;

u8red_size;

u8red_pos;

u8green_size;

u8green_pos;

u8blue_size;

u8blue_pos;

u8rsvd_size;

u8rsvd_pos;

};

/* command line: \0 terminated string */

#define ATAG_CMDLINE0x54410009

struct tag_cmdline {

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

};

/* acorn RiscPC specific information */

#define ATAG_ACORN0x41000101

struct tag_acorn {

u32 memc_control_reg;

u32 vram_pages;

u8 sounddefault;

u8 adfsdrives;

};

/* footbridge memory clock, see arch/arm/mach-footbridge/arch.c */

#define ATAG_MEMCLK0x41000402

struct tag_memclk {

u32 fmemclk;

};

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;

};

#define tag_next(t)((struct tag *)((u32 *)(t) + (t)->hdr.size))

#define tag_size(type)((sizeof(struct tag_header) + sizeof(struct type)) >> 2) //???

二、设置标记存放的地址

2.1相关的结构体定义

结构体bd中保存了标记存放的地址。bd结构体是gd结构体的一项,我们先看gd结构体,其定义在include/asm-arm/global_data.h文件中:

typedef struct  global_data {

bd_t        *bd;//开发板相关参数 ,结构体变量,参考u-boot.h

unsigned long   flags;//指示标志,如设备已经初始化标志等

unsigned long   baudrate;//串行口通讯速率

unsigned long   have_console;

/* serial_init() was called 如果执行了该函数,则设置为1 */

unsigned long   reloc_off;

/*

*Relocation Offset 重定位偏移,就是实际定向的位置与编译连接时指定的位置之差,一般为0

*/

unsigned long   env_addr;   /* 环境参数地址*/

unsigned long   env_valid;  /* 环境参数CRC检验有效标志*/

unsigned long   fb_base;    /*帧缓冲区基地址*/

#ifdef CONFIG_VFD

unsigned char   vfd_type;   /* 显示类型*/

#endif

#if 0

unsigned long   cpu_clk;    /*cpu时钟*/

unsigned long   bus_clk;    //总线时钟

unsigned long   ram_size;   /* RAM size */

unsigned long   reset_status;   /* reset status register at boot */

#endif

void        **jt;   /* jump table 跳转表,用来登记"函数调用地址"*/

} gd_t;typedefstructglobal_data {

bd_t*bd;//开发板相关参数 ,结构体变量,参考u-boot.h

unsigned longflags;//指示标志,如设备已经初始化标志等

unsigned longbaudrate;//串行口通讯速率

unsigned longhave_console;

/* serial_init() was called 如果执行了该函数,则设置为1 */

unsigned longreloc_off;

/*

*Relocation Offset 重定位偏移,就是实际定向的位置与编译连接时指定的位置之差,一般为0

*/

unsigned longenv_addr;/* 环境参数地址*/

unsigned longenv_valid;/* 环境参数CRC检验有效标志*/

unsigned longfb_base;/*帧缓冲区基地址*/

#ifdef CONFIG_VFD

unsigned charvfd_type;/* 显示类型*/

#endif

#if 0

unsigned longcpu_clk;/*cpu时钟*/

unsigned longbus_clk; //总线时钟

unsigned longram_size;/* RAM size */

unsigned longreset_status;/* reset status register at boot */

#endif

void**jt;/* jump table 跳转表,用来登记"函数调用地址"*/

} gd_t;

接来下我们来看一下bd结构体,这个结构体定义在include/asm-arm/u-boot.h文件中:

typedef struct bd_info {

int         bi_baudrate;    /* 串口波特率*/

unsigned long   bi_ip_addr; /*  IP 地址*/

unsigned char   bi_enetaddr[6]; /* MAC地址*/

struct environment_s           *bi_env;

ulong           bi_arch_number; /*  板子的id*/

ulong           bi_boot_params; /* 启动参数*/

struct              /* RAM 配置*/

{

ulong start;

ulong size;

}bi_dram[CONFIG_NR_DRAM_BANKS];

#ifdef CONFIG_HAS_ETH1

/* second onboard ethernet port */

unsigned char   bi_enet1addr[6];

#endif

} bd_t;typedef struct bd_info {

intbi_baudrate;/* 串口波特率*/

unsigned longbi_ip_addr;/* IP 地址*/

unsigned charbi_enetaddr[6]; /* MAC地址*/

struct environment_s *bi_env;

ulong bi_arch_number;/* 板子的id*/

ulong bi_boot_params;/* 启动参数*/

struct/* RAM 配置*/

{

ulong start;

ulong size;

}bi_dram[CONFIG_NR_DRAM_BANKS];

#ifdef CONFIG_HAS_ETH1

/* second onboard ethernet port */

unsigned char bi_enet1addr[6];

#endif

} bd_t;

2.2标记存放地址的设定

在board/smdk2410/smdk2410.c的board_init

函数设置了bi_boot_params 参数:

int board_init (void)

{

S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();//获取时钟和电源配置寄存器的第一个寄存器的地址,寄存器的地上是连续的

S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();//获取GPIO配置寄存器的第一个寄存器的地址

/* to reduce PLL lock time, adjust the LOCKTIME register */

clk_power->LOCKTIME = 0xFFFFFF;

/* configure MPLL */

clk_power->MPLLCON = ((M_MDIV <

/* some delay between MPLL and UPLL */

delay (4000);

/* configure UPLL */

clk_power->UPLLCON = ((U_M_MDIV <

/* some delay between MPLL and UPLL */

delay (8000);

/* set up the I/O ports */

gpio->GPACON = 0x007FFFFF;

gpio->GPBCON = 0x00044555;

gpio->GPBUP = 0x000007FF;

gpio->GPCCON = 0xAAAAAAAA;

gpio->GPCUP = 0x0000FFFF;

gpio->GPDCON = 0xAAAAAAAA;

gpio->GPDUP = 0x0000FFFF;

gpio->GPECON = 0xAAAAAAAA;

gpio->GPEUP = 0x0000FFFF;

gpio->GPFCON = 0x000055AA;

gpio->GPFUP = 0x000000FF;

gpio->GPGCON = 0xFF95FFBA;

gpio->GPGUP = 0x0000FFFF;

gpio->GPHCON = 0x002AFAAA;

gpio->GPHUP = 0x000007FF;

/* arch number of SMDK2410-Board */

gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;

/* adress of boot parameters */

gd->bd->bi_boot_params = 0x30000100;

icache_enable();  //调用cpu/arm920t/cpu.c中的函数

dcache_enable();

return 0;

}int board_init (void)

{

S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();//获取时钟和电源配置寄存器的第一个寄存器的地址,寄存器的地上是连续的

S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();//获取GPIO配置寄存器的第一个寄存器的地址

/* to reduce PLL lock time, adjust the LOCKTIME register */

clk_power->LOCKTIME = 0xFFFFFF;

/* configure MPLL */

clk_power->MPLLCON = ((M_MDIV << 12) + (M_PDIV << 4) + M_SDIV);

/* some delay between MPLL and UPLL */

delay (4000);

/* configure UPLL */

clk_power->UPLLCON = ((U_M_MDIV << 12) + (U_M_PDIV << 4) + U_M_SDIV);

/* some delay between MPLL and UPLL */

delay (8000);

/* set up the I/O ports */

gpio->GPACON = 0x007FFFFF;

gpio->GPBCON = 0x00044555;

gpio->GPBUP = 0x000007FF;

gpio->GPCCON = 0xAAAAAAAA;

gpio->GPCUP = 0x0000FFFF;

gpio->GPDCON = 0xAAAAAAAA;

gpio->GPDUP = 0x0000FFFF;

gpio->GPECON = 0xAAAAAAAA;

gpio->GPEUP = 0x0000FFFF;

gpio->GPFCON = 0x000055AA;

gpio->GPFUP = 0x000000FF;

gpio->GPGCON = 0xFF95FFBA;

gpio->GPGUP = 0x0000FFFF;

gpio->GPHCON = 0x002AFAAA;

gpio->GPHUP = 0x000007FF;

/* arch number of SMDK2410-Board */

gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;

/* adress of boot parameters */

gd->bd->bi_boot_params = 0x30000100;

icache_enable(); //调用cpu/arm920t/cpu.c中的函数

dcache_enable();

return 0;

}

三、标记的设置

U-Boot通过bootm命令引导Linux内核,bootm命令对吼调用do_bootm_linux函数来引导内核。在do_bootm_linux函数就设置了标记,该函数的定义在lib_arm/armlinux.c中:

void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],

ulong addr, ulong *len_ptr, int verify)

{

ulong len = 0, checksum;

ulong initrd_start, initrd_end;

ulong data;

void (*theKernel)(int zero, int arch, uint params);

image_header_t *hdr = &header;

bd_t *bd = gd->bd;

#ifdef CONFIG_CMDLINE_TAG

char *commandline = getenv ("bootargs");

#endif

theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);

设置kernal加载地址

/*

* Check if there is an initrd image

*/

用户自定义了initrd之后需要加载进来,整个过程需要进行头部以及整个数据内部校,类似于内核的加载校验,这里省略了。

initial RAM disk  Linux初始 RAM磁盘(initrd)是在系统引导过程中挂载的一个临时根文件系统,用来支持两阶段的引导过程。initrd文件中包含了各种可执行程序和驱动程序,它们可以用来挂载实际的根文件系统,然后再将这个 initrd RAM 磁盘卸载,并释放内存。在很多嵌入式Linux 系统中,initrd 就是最终的根文件系统。

if (argc >= 3) {

SHOW_BOOT_PROGRESS (9);

addr = simple_strtoul (argv[2], NULL, 16);

printf ("## Loading Ramdisk Image at %08lx ...\n", addr);

/* Copy header so we can blank CRC field for re-calculation */

#ifdef CONFIG_HAS_DATAFLASH

if (addr_dataflash (addr)) {

read_dataflash (addr, sizeof (image_header_t),

(char *) &header);

} else

#endif

memcpy (&header, (char *) addr,

sizeof (image_header_t));

if (ntohl (hdr->ih_magic) != IH_MAGIC) {

printf ("Bad Magic Number\n");

SHOW_BOOT_PROGRESS (-10);

do_reset (cmdtp, flag, argc, argv);

}

data = (ulong) & header;

len = sizeof (image_header_t);

checksum = ntohl (hdr->ih_hcrc);

hdr->ih_hcrc = 0;

if (crc32 (0, (unsigned char *) data, len) != checksum) {

printf ("Bad Header Checksum\n");

SHOW_BOOT_PROGRESS (-11);

do_reset (cmdtp, flag, argc, argv);

}

SHOW_BOOT_PROGRESS (10);

print_image_hdr (hdr);

data = addr + sizeof (image_header_t);

len = ntohl (hdr->ih_size);

#ifdef CONFIG_HAS_DATAFLASH

if (addr_dataflash (addr)) {

read_dataflash (data, len, (char *) CFG_LOAD_ADDR);

data = CFG_LOAD_ADDR;

}

#endif

if (verify) {

ulong csum = 0;

printf ("   Verifying Checksum ... ");

csum = crc32 (0, (unsigned char *) data, len);

if (csum != ntohl (hdr->ih_dcrc)) {

printf ("Bad Data CRC\n");

SHOW_BOOT_PROGRESS (-12);

do_reset (cmdtp, flag, argc, argv);

}

printf ("OK\n");

}

SHOW_BOOT_PROGRESS (11);

if ((hdr->ih_os != IH_OS_LINUX) ||

(hdr->ih_arch != IH_CPU_ARM) ||

(hdr->ih_type != IH_TYPE_RAMDISK)) {

printf ("No Linux ARM Ramdisk Image\n");

SHOW_BOOT_PROGRESS (-13);

do_reset (cmdtp, flag, argc, argv);

}

#if defined(CONFIG_B2) || defined(CONFIG_EVB4510) || defined(CONFIG_ARMADILLO)

/*

*we need to copy the ramdisk to SRAM to let Linux boot

*/

memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len);

data = ntohl(hdr->ih_load);

#endif /* CONFIG_B2 || CONFIG_EVB4510 */

/*

* Now check if we have a multifile image

*/

} else if ((hdr->ih_type == IH_TYPE_MULTI) && (len_ptr[1])) {

ulong tail = ntohl (len_ptr[0]) % 4;

int i;

SHOW_BOOT_PROGRESS (13);

/* skip kernel length and terminator */

data = (ulong) (&len_ptr[2]);

/* skip any additional image length fields */

for (i = 1; len_ptr[i]; ++i)

data += 4;

/* add kernel length, and align */

data += ntohl (len_ptr[0]);

if (tail) {

data += 4 - tail;

}

len = ntohl (len_ptr[1]);

} else {

/*

* no initrd image

*/

SHOW_BOOT_PROGRESS (14);

len = data = 0;

}

#ifdef  DEBUG

if (!data) {

printf ("No initrd\n");

}

#endif

if (data) {

initrd_start = data;

initrd_end = initrd_start + len;

} else {

initrd_start = 0;

initrd_end = 0;

}

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)

setup_start_tag (bd);设置各种tag,用于传递参数给Linux

#ifdef CONFIG_SERIAL_TAG

setup_serial_tag (¶ms);

#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);

#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

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

cleanup_before_linux ();启动之前先做一些清理工作cpu/arm920t/cpu.c

调用内核需要传递的参数如下:

R0:必须为0

R1:机器类型ID,本机为ARM(bd->bi_arch_number)

R2:启动参数列表在内存中的位置(bd->bi_boot_params)

theKernel (0, bd->bi_arch_number, bd->bi_boot_params);

}void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],

ulong addr, ulong *len_ptr, int verify)

{

ulong len = 0, checksum;

ulong initrd_start, initrd_end;

ulong data;

void (*theKernel)(int zero, int arch, uint params);

image_header_t *hdr = &header;

bd_t *bd = gd->bd;

#ifdef CONFIG_CMDLINE_TAG

char *commandline = getenv ("bootargs");

#endif

theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);

设置kernal加载地址

/*

* Check if there is an initrd image

*/

用户自定义了initrd之后需要加载进来,整个过程需要进行头部以及整个数据内部校,类似于内核的加载校验,这里省略了。

initial RAM disk  Linux初始 RAM磁盘(initrd)是在系统引导过程中挂载的一个临时根文件系统,用来支持两阶段的引导过程。initrd文件中包含了各种可执行程序和驱动程序,它们可以用来挂载实际的根文件系统,然后再将这个 initrd RAM 磁盘卸载,并释放内存。在很多嵌入式Linux 系统中,initrd 就是最终的根文件系统。

if (argc >= 3) {

SHOW_BOOT_PROGRESS (9);

addr = simple_strtoul (argv[2], NULL, 16);

printf ("## Loading Ramdisk Image at %08lx ...\n", addr);

/* Copy header so we can blank CRC field for re-calculation */

#ifdef CONFIG_HAS_DATAFLASH

if (addr_dataflash (addr)) {

read_dataflash (addr, sizeof (image_header_t),

(char *) &header);

} else

#endif

memcpy (&header, (char *) addr,

sizeof (image_header_t));

if (ntohl (hdr->ih_magic) != IH_MAGIC) {

printf ("Bad Magic Number\n");

SHOW_BOOT_PROGRESS (-10);

do_reset (cmdtp, flag, argc, argv);

}

data = (ulong) & header;

len = sizeof (image_header_t);

checksum = ntohl (hdr->ih_hcrc);

hdr->ih_hcrc = 0;

if (crc32 (0, (unsigned char *) data, len) != checksum) {

printf ("Bad Header Checksum\n");

SHOW_BOOT_PROGRESS (-11);

do_reset (cmdtp, flag, argc, argv);

}

SHOW_BOOT_PROGRESS (10);

print_image_hdr (hdr);

data = addr + sizeof (image_header_t);

len = ntohl (hdr->ih_size);

#ifdef CONFIG_HAS_DATAFLASH

if (addr_dataflash (addr)) {

read_dataflash (data, len, (char *) CFG_LOAD_ADDR);

data = CFG_LOAD_ADDR;

}

#endif

if (verify) {

ulong csum = 0;

printf (" Verifying Checksum ... ");

csum = crc32 (0, (unsigned char *) data, len);

if (csum != ntohl (hdr->ih_dcrc)) {

printf ("Bad Data CRC\n");

SHOW_BOOT_PROGRESS (-12);

do_reset (cmdtp, flag, argc, argv);

}

printf ("OK\n");

}

SHOW_BOOT_PROGRESS (11);

if ((hdr->ih_os != IH_OS_LINUX) ||

(hdr->ih_arch != IH_CPU_ARM) ||

(hdr->ih_type != IH_TYPE_RAMDISK)) {

printf ("No Linux ARM Ramdisk Image\n");

SHOW_BOOT_PROGRESS (-13);

do_reset (cmdtp, flag, argc, argv);

}

#if defined(CONFIG_B2) || defined(CONFIG_EVB4510) || defined(CONFIG_ARMADILLO)

/*

*we need to copy the ramdisk to SRAM to let Linux boot

*/

memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len);

data = ntohl(hdr->ih_load);

#endif /* CONFIG_B2 || CONFIG_EVB4510 */

/*

* Now check if we have a multifile image

*/

} else if ((hdr->ih_type == IH_TYPE_MULTI) && (len_ptr[1])) {

ulong tail = ntohl (len_ptr[0]) % 4;

int i;

SHOW_BOOT_PROGRESS (13);

/* skip kernel length and terminator */

data = (ulong) (&len_ptr[2]);

/* skip any additional image length fields */

for (i = 1; len_ptr[i]; ++i)

data += 4;

/* add kernel length, and align */

data += ntohl (len_ptr[0]);

if (tail) {

data += 4 - tail;

}

len = ntohl (len_ptr[1]);

} else {

/*

* no initrd image

*/

SHOW_BOOT_PROGRESS (14);

len = data = 0;

}

#ifdefDEBUG

if (!data) {

printf ("No initrd\n");

}

#endif

if (data) {

initrd_start = data;

initrd_end = initrd_start + len;

} else {

initrd_start = 0;

initrd_end = 0;

}

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)

setup_start_tag (bd);设置各种tag,用于传递参数给Linux

#ifdef CONFIG_SERIAL_TAG

setup_serial_tag (¶ms);

#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);

#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

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

cleanup_before_linux ();启动之前先做一些清理工作cpu/arm920t/cpu.c

调用内核需要传递的参数如下:

R0:必须为0

R1:机器类型ID,本机为ARM(bd->bi_arch_number)

R2:启动参数列表在内存中的位置(bd->bi_boot_params)

theKernel (0, bd->bi_arch_number, bd->bi_boot_params);

}

3.1设置标记ATAG_CORE

标记列表以标记ATAG_CORE开始

static void setup_start_tag (bd_t *bd)

{

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

params->hdr.tag = ATAG_CORE;

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);//指向当前标记的末尾

}static void setup_start_tag (bd_t *bd)

{

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

params->hdr.tag = ATAG_CORE;

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);//指向当前标记的末尾

}

3.2设置内存标记ATAG_MEM

在board/smdk2410/smdk2410.c的dram_init函数设置了bd的bi_dram结构体:

int dram_init (void)

{

gd->bd->bi_dram[0].start = PHYS_SDRAM_1;

gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;

return 0;

}int dram_init (void)

{

gd->bd->bi_dram[0].start = PHYS_SDRAM_1;

gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;

return 0;

}

下面是这边内存标记的结构体:

static void setup_memory_tags (bd_t *bd)

{

int i;

for (i = 0; i

params->hdr.tag = ATAG_MEM;

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

params->u.mem.start = bd->bi_dram[i].start;

params->u.mem.size = bd->bi_dram[i].size;

params = tag_next (params);

}

}static void setup_memory_tags (bd_t *bd)

{

int i;

for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {

params->hdr.tag = ATAG_MEM;

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

params->u.mem.start = bd->bi_dram[i].start;

params->u.mem.size = bd->bi_dram[i].size;

params = tag_next (params);

}

}

3.3设置命令行标记ATAG_CMDLINE

命令行就是一个字符串,用来控制内核的一些行为。比如“root=/dev/mtdblock2

init=/linuxrc console=ttySAC0 ”表示根文件系统在MTD2分区上系统启动后执行的第一个程序为/linuxrc,控制台是ttySAC0

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;

params->hdr.size =

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

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

params = tag_next (params);

}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;

params->hdr.size =

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

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

params = tag_next (params);

}

3.4设置ATAG_NONE

标记列表以标记ATAG_NONE介绍。

static void setup_end_tag (bd_t *bd)

{

params->hdr.tag = ATAG_NONE;

params->hdr.size = 0;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值