uboot引导linux内核,uboot启动linux内核代码分析

uboot启动内核时候依赖于两条代码:

s=getev("bootcmd")

run_command(s,?)

s=nand read.jffs2 0x30007fc0 kernel;

从nandflash读出内核,

从哪里读?从kernel分区读,pc的每块硬盘的开始多有该硬盘的分区表,而nandflash是没有分区表的,但是开发人员头脑中要有一个存储器大致划分概念

|uboot分区|uboot的环境变量|kernel分区|root分区也即文件系统|,既然没有分区表那么存储区域的划分只能是在源代码中固定。所以我们关心的是各个分区的起始地址。例如韦东山是在100ask24x0.h文件中用一个宏定义,#define

MTDPARTS_DEFAULT

"mtdparts=nandflash0:256K@0(bootloader),"\也即从0到256K为bootloader

"128k(params),"\接下来的128K放的是uboot的环境变量

"2m(kernel),"\ 2M空间放的是kernel

"-(root)" 剩下的是root分区

读到哪里去?-----0x30007fc0

具体地址从uboot菜单中输入mtd命令即可。下面的这个图是我的四个分区:

a4c26d1e5885305701be709a3d33442f.png

所以 nand read.jffs2 0x30007fc0 kernel = nand read.jffs2 0x30007fc0

0x00060000 0x0x00200000

下面分析一下如何读,如何把2M的内核读到0x30007fc0处????

因为启动时do_bootm,所以可以猜测nand read 应该是do_nand函数。

---------------------------do_nand函数开始----------------------------

int do_nand(cmd_tbl_t * cmdtp, int flag, int

argc, char *argv[])

{

int i, dev, ret;

ulong addr, off, size;

char *cmd, *s;

nand_info_t *nand;

int quiet = 0;

const char *quiet_str = getenv("quiet");

if (argc < 2)

goto usage;

if (quiet_str)

quiet =

simple_strtoul(quiet_str, NULL, 0) != 0;

cmd = argv[1];

if (strcmp(cmd, "info") == 0) {

putc('\n');

for (i = 0; i <

CFG_MAX_NAND_DEVICE; i++) {

if

(nand_info[i].name)

printf("Device

%d: %s, sector size %lu KiB\n",

i,

nand_info[i].name,

nand_info[i].erasesize

>> 10);

}

return 0;

}

if (strcmp(cmd, "device") == 0) {

if (argc < 3)

{

if

((nand_curr_device < 0) ||

(nand_curr_device >= CFG_MAX_NAND_DEVICE))

puts("\nno

devices available\n");

else

printf("\nDevice

%d: %s\n", nand_curr_device,

nand_info[nand_curr_device].name);

return

0;

}

dev =

(int)simple_strtoul(argv[2], NULL, 10);

if (dev < 0 ||

dev >= CFG_MAX_NAND_DEVICE || !nand_info[dev].name)

{

puts("No such

device\n");

return

1;

}

printf("Device %d: %s", dev,

nand_info[dev].name);

puts("... is now current

device\n");

nand_curr_device = dev;

#ifdef CFG_NAND_SELECT_DEVICE

board_nand_select_device(nand_info[dev].priv,

dev);

#endif

return 0;

}

if (strcmp(cmd, "bad") != 0

&& strcmp(cmd, "erase") != 0

&&

strncmp(cmd, "dump", 4) != 0

&&

strncmp(cmd, "read", 4) != 0 &&

strncmp(cmd, "write", 5) != 0

&&

strcmp(cmd, "scrub") != 0 &&

strcmp(cmd, "markbad") != 0

&&

strcmp(cmd, "biterr") != 0 &&

strcmp(cmd, "lock") != 0 &&

strcmp(cmd, "unlock") != 0 )

goto usage;

if (nand_curr_device < 0 ||

nand_curr_device >= CFG_MAX_NAND_DEVICE ||

!nand_info[nand_curr_device].name) {

puts("\nno devices

available\n");

return 1;

}

nand =

&nand_info[nand_curr_device];

if (strcmp(cmd, "bad") == 0) {

printf("\nDevice %d bad

blocks:\n", nand_curr_device);

for (off = 0; off

< nand->size; off +=

nand->erasesize)

if

(nand_block_isbad(nand, off))

printf(" x\n", off);

return 0;

}

if (strcmp(cmd, "erase") == 0 || strcmp(cmd,

"scrub") == 0) {

nand_erase_options_t

opts;

int clean = argc

> 2 &&

!strcmp("clean", argv[2]);

int o = clean ? 3 : 2;

int scrub = !strcmp(cmd,

"scrub");

printf("\nNAND %s: ", scrub

? "scrub" : "erase");

if (arg_off_size(argc - o, argv

+ o, nand, &off, &size) != 0)

return 1;

memset(&opts,

0, sizeof(opts));

opts.offset = off;

opts.length = size;

opts.jffs2 =

clean;

opts.quiet =

quiet;

if (scrub) {

puts("Warning:

"

"scrub option will erase all factory set "

"bad blocks!\n"

" "

"There is no reliable way to recover them.\n"

" "

"Use this command only for testing purposes "

"if you\n"

" "

"are sure of what you are doing!\n"

"\nReally scrub this NAND flash?

\n");

if (getc()

== 'y' && getc() == '\r') {

opts.scrub

= 1;

} else

{

puts("scrub

aborted\n");

return

-1;

}

}

ret = nand_erase_opts(nand,

&opts);

printf("%s\n", ret ? "ERROR" :

"OK");

return ret == 0 ? 0 :

1;

}

if (strncmp(cmd, "dump", 4) == 0)

{这个是用来显示nandflash的数据的

if (argc <

3)

goto

usage;

s = strchr(cmd, '.');

off =

(int)simple_strtoul(argv[2], NULL, 16);

if (s != NULL

&& strcmp(s, ".oob") == 0)

ret =

nand_dump_oob(nand, off);

else

ret =

nand_dump(nand, off);

return ret == 0 ? 1 : 0;

}

if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd,

"write", 5) == 0) {

int read;

if (argc <

4)

goto

usage;

addr =

(ulong)simple_strtoul(argv[2], NULL, 16);

read = strncmp(cmd, "read",

4) == 0;

printf("\nNAND %s: ", read ?

"read" : "write");

if (arg_off_size(argc - 3, argv

+ 3, nand, &off, &size) != 0)

return 1;

s = strchr(cmd, '.');

if (s != NULL

&&

(!strcmp(s, ".jffs2") || !strcmp(s, ".e") || !strcmp(s, ".i")))

{这里用jffs2文件格式,其实没有牵扯到文件格式,但是用这个的话不用考虑页或者块对齐,其他格式得考虑。

if (read)

{

nand_read_options_t

opts;

memset(&opts,

0, sizeof(opts));

opts.buffer =

(u_char*) addr;

opts.length =

size;

opts.offset =

off;

opts.quiet = quiet;

ret

= nand_read_opts(nand,

&opts);最终调用这个函数具体实现先不看。

} else

{

nand_write_options_t

opts;

memset(&opts,

0, sizeof(opts));

opts.buffer =

(u_char*) addr;

opts.length =

size;

opts.offset =

off;

opts.pad =

1;

opts.blockalign

= 1;

opts.quiet = quiet;

ret

= nand_write_opts(nand, &opts);

}

} else {

if

(read)

ret

= nand_read(nand, off, &size, (u_char

*)addr);

else

ret

= nand_write(nand, off, &size, (u_char

*)addr);

}

printf(" %d bytes %s: %s\n",

size,

read ? "read" : "written", ret ? "ERROR" : "OK");

return ret == 0 ? 0 :

1;

}

if (strcmp(cmd, "markbad") == 0) {

addr =

(ulong)simple_strtoul(argv[2], NULL, 16);

int ret =

nand->block_markbad(nand, addr);

if (ret == 0) {

printf("block

0xlx successfully marked as bad\n",

(ulong) addr);

return

0;

} else {

printf("block

0xlx NOT marked as bad! ERROR %d\n",

(ulong) addr, ret);

}

return 1;

}

if (strcmp(cmd, "biterr") == 0) {

return 1;

}

if (strcmp(cmd, "lock") == 0) {

int tight =

0;

int status = 0;

if (argc == 3) {

if

(!strcmp("tight", argv[2]))

tight

= 1;

if

(!strcmp("status", argv[2]))

status

= 1;

}

if (status) {

ulong

block_start = 0;

ulong

off;

int

last_status = -1;

struct

nand_chip *nand_chip = nand->priv;

nand_chip->cmdfunc

(nand, NAND_CMD_STATUS, -1, -1);

printf("device

is %swrite protected\n",

(nand_chip->read_byte(nand) & 0x80

?

"NOT

" : "" ) );

for (off =

0; off < nand->size; off +=

nand->oobblock) {

int

s = nand_get_lock_status(nand, off);

if

(off == nand->size -

nand->oobblock

|| (s != last_status && off !=

0)) {

printf("x

- x: � pages %s%s%s\n",

block_start,

off-1,

(off-block_start)/nand->oobblock,

((last_status & NAND_LOCK_STATUS_TIGHT) ? "TIGHT "

: ""),

((last_status & NAND_LOCK_STATUS_LOCK) ? "LOCK " :

""),

((last_status & NAND_LOCK_STATUS_UNLOCK) ? "UNLOCK

" : ""));

}

last_status

= s;

}

} else {

if

(!nand_lock(nand, tight)) {

puts("NAND

flash successfully locked\n");

} else

{

puts("Error

locking NAND flash\n");

return

1;

}

}

return 0;

}

if (strcmp(cmd, "unlock") == 0) {

if (arg_off_size(argc - 2, argv

+ 2, nand, &off, &size)

< 0)

return 1;

if (!nand_unlock(nand, off,

size)) {

puts("NAND

flash successfully unlocked\n");

} else {

puts("Error

unlocking NAND flash, "

"write and erase will probably fail\n");

return

1;

}

return 0;

}

usage:

printf("Usage:\n%s\n",

cmdtp->usage);

return 1;

}

---------------------------do_nand函数结束----------------------------

bootm 0x30007fc0

--------------------以上分析了uboot读出内核,下面要开始分析如何启动内核-----------------------

主要是do_bootm函数,flash上存储的内核是uImage格式(头部+真正的内核)

-----------------------do_bootm函数开始----------------------------

int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char

*argv[])

{

ulong iflag;

ulong addr;

ulong data, len, checksum;

ulong *len_ptr;

uint unc_len =

CFG_BOOTM_LEN;

int i, verify;

char *name, *s;

int (*appl)(int, char

*[]);

image_header_t *hdr =

&header;

注释开始

这里就是uimage的头部,是一个结构体

typedef struct image_header {

uint32_t ih_magic; uint32_t ih_hcrc; uint32_t ih_time; uint32_t ih_size; uint32_t ih_load; 表示内核运行的时候你要把它放在哪里。

uint32_t ih_ep; 运行内核的时候入口地址,之前设置的是0x30007fc0,只要不破坏uboot内存使用分配即可,因为sp后面还有几十M的空间。正是因为uimage中有个header,header结构体中有一个loadaddress。我们把uimage放在某个地址,bootm加上这个地址,去读出头部中的in_load,如果发现内核不在加载地址中,则需要把内核移动到这个加载地址中去,最后跳到in_ep去执行。

uint32_t ih_dcrc; uint8_t ih_os; uint8_t ih_arch; uint8_t ih_type; uint8_t ih_comp; uint8_t ih_name[IH_NMLEN]; } image_header_t;

注释结束

s = getenv ("verify");

verify = (s &&

(*s == 'n')) ? 0 : 1;

if (argc < 2) {

addr = load_addr;

} else {

addr = simple_strtoul(argv[1],

NULL, 16);

}

SHOW_BOOT_PROGRESS (1);

printf ("## Booting image at lx ...\n",

addr);

#ifdef CONFIG_HAS_DATAFLASH

if (addr_dataflash(addr)){

read_dataflash(addr,

sizeof(image_header_t), (char *)&header);

} else

#endif

memmove (&header, (char *)addr,

sizeof(image_header_t));

if (ntohl(hdr->ih_magic) !=

IH_MAGIC) {

#ifdef __I386__ if (fake_header(hdr,

(void*)addr, -1) != NULL) {

addr -=

sizeof(image_header_t);

verify =

0;

} else

#endif {

puts ("Bad Magic

Number\n");

SHOW_BOOT_PROGRESS (-1);

return 1;

}

}

SHOW_BOOT_PROGRESS (2);

data = (ulong)&header;

len =

sizeof(image_header_t);

checksum =

ntohl(hdr->ih_hcrc);

hdr->ih_hcrc = 0;

if (crc32 (0, (uchar *)data, len) != checksum)

{

puts ("Bad Header

Checksum\n");

SHOW_BOOT_PROGRESS (-2);

return 1;

}

SHOW_BOOT_PROGRESS (3);

#ifdef CONFIG_HAS_DATAFLASH

if (addr_dataflash(addr)){

len =

ntohl(hdr->ih_size) + sizeof(image_header_t);

read_dataflash(addr, len, (char

*)CFG_LOAD_ADDR);

addr = CFG_LOAD_ADDR;

}

#endif

print_image_hdr ((image_header_t *)addr);

data = addr + sizeof(image_header_t);

len =

ntohl(hdr->ih_size);

if (verify) {

puts

(" Verifying Checksum ...

");

if (crc32 (0, (uchar *)data,

len) != ntohl(hdr->ih_dcrc)) {

printf ("Bad

Data CRC\n");

SHOW_BOOT_PROGRESS

(-3);

return

1;

}

puts ("OK\n");

}

SHOW_BOOT_PROGRESS (4);

len_ptr = (ulong *)data;

#if defined(__PPC__)

if (hdr->ih_arch !=

IH_CPU_PPC)

#elif defined(__ARM__)

if (hdr->ih_arch !=

IH_CPU_ARM)

#elif defined(__I386__)

if (hdr->ih_arch !=

IH_CPU_I386)

#elif defined(__mips__)

if (hdr->ih_arch !=

IH_CPU_MIPS)

#elif defined(__nios__)

if (hdr->ih_arch !=

IH_CPU_NIOS)

#elif defined(__M68K__)

if (hdr->ih_arch !=

IH_CPU_M68K)

#elif defined(__microblaze__)

if (hdr->ih_arch !=

IH_CPU_MICROBLAZE)

#elif defined(__nios2__)

if (hdr->ih_arch !=

IH_CPU_NIOS2)

#elif defined(__blackfin__)

if (hdr->ih_arch !=

IH_CPU_BLACKFIN)

#elif defined(__avr32__)

if (hdr->ih_arch !=

IH_CPU_AVR32)

#else

# error Unknown CPU type

#endif

{

printf ("Unsupported

Architecture 0x%x\n", hdr->ih_arch);

SHOW_BOOT_PROGRESS (-4);

return 1;

}

SHOW_BOOT_PROGRESS (5);

switch (hdr->ih_type) {

case IH_TYPE_STANDALONE:

name = "Standalone

Application";

if (argc > 2)

{

hdr->ih_load

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

}

break;

case IH_TYPE_KERNEL:

name = "Kernel Image";

break;

case IH_TYPE_MULTI:

name = "Multi-File

Image";

len =

ntohl(len_ptr[0]);

data += 8;

for (i=1; len_ptr[i];

++i)

data +=

4;

break;

default: printf ("Wrong Image Type for %s

command\n", cmdtp->name);

SHOW_BOOT_PROGRESS (-5);

return 1;

}

SHOW_BOOT_PROGRESS (6);

iflag = disable_interrupts();

#ifdef CONFIG_AMIGAONEG3SE

icache_disable();

invalidate_l1_instruction_cache();

flush_data_cache();

dcache_disable();

#endif

switch (hdr->ih_comp) {

case IH_COMP_NONE:

if(ntohl(hdr->ih_load)

== addr) {如果ih_load==addr,则打印xip

printf

(" XIP %s ... ", name);

} else {

#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)

size_t l =

len;

void *to =

(void *)ntohl(hdr->ih_load);

void *from =

(void *)data;

printf

(" Loading %s ... ", name);

while (l

> 0) {

size_t

tail = (l > CHUNKSZ) ? CHUNKSZ : l;

WATCHDOG_RESET();

memmove

(to, from, tail);

to

+= tail;

from

+= tail;

l

-= tail;

}

#else 否则就要移动真正的内核

memmove

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

len);这里就是把真正内核开始的data移动到ih_load加载地址中去。韦东山开发板的内核真正地址为0x30008000,而内核头部的起始地址是0x30007fc0,两者相差64字节,正好是头部的长度,这样就不用做搬运真正的内核的工作了。可以加快启动速度。

#endif }

break;

case IH_COMP_GZIP:

printf

(" Uncompressing %s ... ",

name);

if (gunzip ((void

*)ntohl(hdr->ih_load), unc_len,

(uchar *)data, &len) != 0) {

puts ("GUNZIP

ERROR - must RESET board to recover\n");

SHOW_BOOT_PROGRESS

(-6);

do_reset

(cmdtp, flag, argc, argv);

}

break;

#ifdef CONFIG_BZIP2

case IH_COMP_BZIP2:

printf

(" Uncompressing %s ... ",

name);

i = BZ2_bzBuffToBuffDecompress

((char*)ntohl(hdr->ih_load),

&unc_len,

(char *)data, len,

CFG_MALLOC_LEN

< (4096 * 1024), 0);

if (i != BZ_OK) {

printf

("BUNZIP2 ERROR %d - must RESET board to recover\n", i);

SHOW_BOOT_PROGRESS

(-6);

udelay(100000);

do_reset

(cmdtp, flag, argc, argv);

}

break;

#endif

default:

if (iflag)

enable_interrupts();

printf ("Unimplemented

compression type %d\n", hdr->ih_comp);

SHOW_BOOT_PROGRESS (-7);

return 1;

}

puts ("OK\n");

SHOW_BOOT_PROGRESS (7);

switch (hdr->ih_type) {

case IH_TYPE_STANDALONE:

if (iflag)

enable_interrupts();

if (((s = getenv("autostart"))

!= NULL) && (strcmp(s,"no") == 0))

{

char

buf[32];

sprintf(buf,

"%lX", len);

setenv("filesize",

buf);

return

0;

}

appl = (int (*)(int, char

*[]))ntohl(hdr->ih_ep);

(*appl)(argc-1,

&argv[1]);

return 0;

case IH_TYPE_KERNEL:

case IH_TYPE_MULTI:

break;

default:

if (iflag)

enable_interrupts();

printf ("Can't boot image type

%d\n", hdr->ih_type);

SHOW_BOOT_PROGRESS (-8);

return 1;

}

SHOW_BOOT_PROGRESS (8);

switch (hdr->ih_os) {

default: case IH_OS_LINUX:

#ifdef CONFIG_SILENT_CONSOLE

fixup_silent_linux();

#endif

do_bootm_linux (cmdtp, flag, argc, argv,

addr, len_ptr, verify);

break;

case IH_OS_NETBSD:

do_bootm_netbsd (cmdtp, flag, argc, argv,

addr, len_ptr, verify);

break;

#ifdef CONFIG_LYNXKDI

case IH_OS_LYNXOS:

do_bootm_lynxkdi (cmdtp, flag, argc, argv,

addr, len_ptr, verify);

break;

#endif

case IH_OS_RTEMS:

do_bootm_rtems (cmdtp, flag, argc, argv,

addr, len_ptr, verify);

break;

#if (CONFIG_COMMANDS & CFG_CMD_ELF)

case IH_OS_VXWORKS:

do_bootm_vxworks (cmdtp, flag, argc, argv,

addr, len_ptr, verify);

break;

case IH_OS_QNX:

do_bootm_qnxelf (cmdtp, flag, argc, argv,

addr, len_ptr, verify);

break;

#endif

#ifdef CONFIG_ARTOS

case IH_OS_ARTOS:

do_bootm_artos (cmdtp, flag, argc, argv,

addr, len_ptr, verify);

break;

#endif

}

SHOW_BOOT_PROGRESS (-9);

#ifdef DEBUG

puts ("\n## Control returned to monitor -

resetting...\n");

do_reset (cmdtp, flag, argc, argv);

#endif

return 1;

}

-----------------------do_bootm函数结束----------------------------

do_bootm有两个作用:

作用1:读取内核头部将内核移动到合适地方,还有一些校验

作用2:启动内核,用的是do_bootm_linux函数。在跳到ih_ep入口之前还要uboot设置内核启动参数,然后才是跳到ih_ep启动内核。

------------------do_bootm_linux函数开始----------------------------

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

if (argc >= 3) {

SHOW_BOOT_PROGRESS (9);

addr = simple_strtoul

(argv[2], NULL, 16);

printf ("## Loading Ramdisk

Image at lx ...\n", addr);

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

memmove ((void *)

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

data =

ntohl(hdr->ih_load);

#endif

} else if ((hdr->ih_type ==

IH_TYPE_MULTI) && (len_ptr[1]))

{

ulong tail = ntohl (len_ptr[0])

% 4;

int i;

SHOW_BOOT_PROGRESS (13);

data = (ulong)

(&len_ptr[2]);

for (i = 1; len_ptr[i];

++i)

data +=

4;

data += ntohl

(len_ptr[0]);

if (tail) {

data += 4 -

tail;

}

len = ntohl

(len_ptr[1]);

} else {

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 lx) ...\n",

(ulong) theKernel);

#if defined (CONFIG_SETUP_MEMORY_TAGS) || \ uboot设置参数在这里

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

#ifdef CONFIG_SERIAL_TAG

setup_serial_tag (&params);

#endif

#ifdef CONFIG_REVISION_TAG

setup_revision_tag

(&params);

#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

printf ("\nStarting kernel ...\n\n");

#ifdef CONFIG_USB_DEVICE

{

extern void udc_disconnect

(void);

udc_disconnect ();

}

#endif

cleanup_before_linux ();

theKernel (0,

bd->bi_arch_number,

bd->bi_boot_params);启动内核在这里

}

------------------do_bootm_linux函数结束----------------------------

do_bootm_linux

作用1:设置内核启动参数,参数的格式是tag,对于韦东山的开发板地址是0x30000100,下面分析两个参数,其中setup_start_tag和setup_end_tag是必须的。

static void setup_start_tag (bd_t *bd)

{

params = (struct tag *)

bd->bi_boot_params;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);

}

作用2:跳到入口地址去是

theKernel = (void (*)(int, int,

uint))ntohl(hdr->ih_ep);

theKernel (0, bd->bi_arch_number,

bd->bi_boot_params);

这样就启动内核了!!!

具体bi_boot_params是多少搜索代码可以知道,其实韦东山是在自己的100ask24x0.c中自己定义的。

setup_start_tag之后我们得到:

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

}

0x30000100|size|tag|flag|page_size|root_dev|

其中header_size=sizeof(struct tag_header) + (sizeof(struct type)

>> 2)

也就是说执行完这个函数之后,要明白在内核启动参数区域都放了大小是多少的参数。

执行完setup_memory_tag函数之后:

#ifdef CONFIG_SETUP_MEMORY_TAGS

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

}

}

#endif

这时存储内核启动参数的区域类似于setup_start_tag

开始是size|tag|size|start|

下面是start_commandline_tag

static void setup_commandline_tag (bd_t *bd, char

*commandline)

{

char *p;

if (!commandline)

return;

把命令前面的空格给干掉

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

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

}

commandline被传入一个参数*commandline,而这个参数是getev("bootargs"),用print命令在uboot命令行中查看bootargs,其中包括了内核的console的信息从哪里打印出来,是同ttyssa0也即串口0打出来。

size|tag|bootargs

-------------------最后一个是setup_end_tag--------------------

static void setup_end_tag (bd_t *bd)

{

params->hdr.tag = ATAG_NONE;

params->hdr.size = 0;

}

这两个参数全是0。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值