文档库 最新最全的文档下载
当前位置:文档库 › uboot启动流程.doc

uboot启动流程.doc

uboot启动流程.doc
uboot启动流程.doc

U-Boot启动过程

(国嵌)

开发板上电后,执行U-Boot的第一条指令,然后顺序执行U-Boot启动函数。看一下board/smdk2410/u-boot.lds这个链接脚本,可以知道目标程序的各部分链接顺序。第一个要链接的是cpu/arm920t/start.o,那么U-Boot的入口指令一定位于这个程序中。下面分两阶段介绍启动流程:

第一阶段

1.cpu/arm920t/start.S

这个汇编程序是U-Boot的入口程序,开头就是复位向量的代码。

_start: b reset //复位向量

ldr pc, _undefined_instruction

ldr pc, _software_interrupt

ldr pc, _prefetch_abort

ldr pc, _data_abort

ldr pc, _not_used

ldr pc, _irq //中断向量

ldr pc, _fiq //中断向量

/* the actual reset code */

reset: //复位启动子程序

/* 设置CPU为SVC32模式 */

mrs r0,cpsr

bic r0,r0,#0x1f

orr r0,r0,#0xd3

msr cpsr,r0

/* 关闭看门狗 */

…… ……

relocate: /* 把U-Boot重新定位到RAM */

adr r0, _start /* r0是代码的当前位置 */

ldr r1, _TEXT_BASE /*_TEXT_BASE是RAM中的地址 */

cmp r0, r1 /* 比较r0和r1,判断当前是从Flash启动,还是RAM */

beq stack_setup /* 如果r0等于r1,跳过重定位代码 */

/* 准备重新定位代码 */

ldr r2, _armboot_start

ldr r3, _bss_start

sub r2, r3, r2 /* r2 得到armboot的大小 */

add r2, r0, r2 /* r2 得到要复制代码的末尾地址 */

copy_loop: /* 重新定位代码 */

ldmia r0!, {r3-r10} /*从源地址[r0]复制 */

stmia r1!, {r3-r10} /* 复制到目的地址[r1] */

cmp r0, r2 /* 复制数据块直到源数据末尾地址[r2] */

ble copy_loop

/* 初始化堆栈等 */

stack_setup:

ldr r0, _TEXT_BASE /* 上面是128 KiB重定位的u-boot */

sub r0, r0, #CFG_MALLOC_LEN /* 向下是内存分配空间 */

sub r0, r0, #CFG_GBL_DATA_SIZE /* 然后是bdinfo结构体地址空间 */

#ifdef CONFIG_USE_IRQ

sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)

#endif

sub sp, r0, #12 /* 为abort-stack预留3个字 */

clear_bss:

ldr r0, _bss_start /* 找到bss段起始地址 */

ldr r1, _bss_end /* bss段末尾地址 */

mov r2, #0x00000000 /* 清零 */

clbss_l:str r2, [r0]

/* bss段地址空间清零循环... */

add r0, r0, #4

cmp r0, r1

bne clbss_l

/* 跳转到start_armboot函数入口,_start_armboot字保存函数入口指针 */

ldr pc, _start_armboot

_start_armboot: .word start_armboot //start_armboot函数在lib_arm/board.c中实现

第二阶段

2.lib_arm/board.c

start_armboot是U-Boot执行的第一个C语言函数,完成系统初始化工作,进入主循环,处理用户输入的命令。

3.init_sequence[]

init_sequence[]数组保存着基本的初始化函数指针。

init_fnc_t *init_sequence[] = {

cpu_init, /* 基本的处理器相关配置 -- cpu/arm920t/cpu.c */

board_init, /* 基本的板级相关配置 -- board/smdk2410/smdk2410.c */

interrupt_init, /* 初始化中断处理 -- cpu/arm920t/s3c24x0/interrupt.c */

env_init, /* 初始化环境变量 -- common/cmd_flash.c */

init_baudrate, /* 初始化波特率设置 -- lib_arm/board.c */

serial_init, /* 串口通讯设置 -- cpu/arm920t/s3c24x0/serial.c */

console_init_f, /* 控制台初始化阶段1 -- common/console.c */

display_banner, /* 打印u-boot信息 -- lib_arm/board.c */

dram_init, /* 配置可用的RAM -- board/smdk2410/smdk2410.c */

display_dram_config, /* 显示RAM的配置大小 -- lib_arm/board.c */

NULL,

};

void start_armboot (void)

{

/* 顺序执行init_sequence数组中的初始化函数 */

for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {

if ((*init_fnc_ptr)() != 0) {

hang ();

}

}

/*配置可用的Flash */

size = flash_init ();

display_flash_config (size);

/* _armboot_start 在u-boot.lds链接脚本中定义 */

mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);

/* 配置环境变量*/

env_relocate ();

/* 从环境变量中获取IP地址 */

gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");

/* 以太网接口MAC 地址 */

……

devices_init (); /* 获取列表中的设备 */

jumptable_init ();

console_init_r (); /* 完整地初始化控制台设备 */

enable_interrupts (); /* 使能中断处理 */

/* 通过环境变量初始化 */

if ((s = getenv ("loadaddr")) != NULL) {

load_addr = simple_strtoul (s, NULL, 16);

}

/* main_loop()循环不断执行 */

for (;;)

{

main_loop (); /* 主循环函数处理执行用户命令 -- common/main.c */

}

命令实现

U-Boot作为Bootloader,具备多种引导内核启动的方式。常用的go和bootm命令可以直接引导内核映像启动。U-Boot与内核的关系主要是内核启动过程中参数的传递。

1.go命令的实现

/* common/cmd_boot.c */

int do_go (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])

{

ulong addr, rc;

int rcode = 0;

if (argc < 2) {

printf ("Usage:\n%s\n", cmdtp->usage);

return 1;

}

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

printf ("## Starting application at 0x%08lX ...\n", addr);

rc = ((ulong (*)(int, char []))addr) (--argc, &argv[1]); /* 运行程序 */

if (rc != 0) rcode = 1;

printf ("## Application terminated, rc = 0x%lX\n", rc); /*如果是运行linux,这条指令是否能运行?*/

return rcode;

}

go命令调用do_go()函数,跳转到某个地址执行的。如果在这个地址准备好了自引导的内核映像,就可以启动了。尽管go命令可以带变参,实际使用时不用来传递参数。

2.bootm命令的实现

/* common/cmd_bootm.c */

int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])

{

…… ……

/* 检查头部 */

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

puts ("Bad Header Checksum\n");

SHOW_BOOT_PROGRESS (-2);

return 1;

}

…… ……

/*解压缩*/

switch (hdr->ih_comp) {

case IH_COMP_NONE:

if(ntohl(hdr->ih_load) == addr) {

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 /* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */

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

#endif /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */

}

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

/*

* If we've got less than 4 MB of malloc() space,

* use slower decompression algorithm which requires

* at most 2300 KB of memory.

*/

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 /* CONFIG_BZIP2 */

default:

if (iflag)

enable_interrupts();

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

SHOW_BOOT_PROGRESS (-7);

return 1;

}

}

…… …… ……

switch (hdr->ih_os) {

default: /* handled by (original) Linux case */

case IH_OS_LINUX:

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;

case IH_OS_RTEMS:

do_bootm_rtems (cmdtp, flag, argc, argv,

addr, len_ptr, verify);

break;

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;

}

bootm命令调用do_bootm函数。这个函数专门用来引导各种操作系统映像,可以支持引导Linux、vxWorks、QNX等操作系统。引导Linux的时候,调用do_bootm_linux()函数。

3.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)

{

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

… … … …

/* we assume that the kernel is in place */

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

… … … …

theKernel (0, bd->bi_arch_number, bd->bi_boot_params); /*启动内核,传递启动参数*/ }

do_bootm_linux()函数是专门引导Linux映像的函数,它还可以处理ramdisk文件系统的映像。这里引导的内核映像和ramdisk映像,必须是U-Boot格式的。U-Boot格式的映像可以通过mkimage工具来转换,其中包含了U-Boot可以识别的符号。

U-Boot启动过程完全分析

1.1U-Boot工作过程

U-Boot启动内核的过程可以分为两个阶段,两个阶段的功能如下:

(1)第一阶段的功能

?硬件设备初始化

?加载U-Boot第二阶段代码到RAM空间

?设置好栈

?跳转到第二阶段代码入口

(2)第二阶段的功能

?初始化本阶段使用的硬件设备

?检测系统内存映射

?将内核从Flash读取到RAM中

?为内核设置启动参数

?调用内核

1.1.1U-Boot启动第一阶段代码分析第一阶段对应的文件是cpu/arm920t/start.S和board/samsung/mini2440/lowlevel_init.S。

U-Boot启动第一阶段流程如下:

图 2.1 U-Boot启动第一阶段流程

根据cpu/arm920t/u-boot.lds中指定的连接方式:

ENTRY(_start)

SECTIONS

{

. = 0x00000000;

. = ALIGN(4);

.text :

{

cpu/arm920t/start.o (.text)

board/samsung/mini2440/lowlevel_init.o (.text)

board/samsung/mini2440/nand_read.o (.text)

*(.text)

}

……

}

第一个链接的是cpu/arm920t/start.o,因此u-boot.bin的入口代码在cpu/arm920t/start.o中,其源代码在cpu/arm920t/start.S中。下面我们来分析cpu/arm920t/start.S的执行。

1.硬件设备初始化

(1)设置异常向量

cpu/arm920t/start.S开头有如下的代码:

.globl _start

_start: b start_code /* 复位*/

ldr pc, _undefined_instruction /* 未定义指令向量*/

ldr pc, _software_interrupt /* 软件中断向量*/

ldr pc, _prefetch_abort /* 预取指令异常向量*/

ldr pc, _data_abort /* 数据操作异常向量*/

ldr pc, _not_used /* 未使用*/

ldr pc, _irq /* irq中断向量*/

ldr pc, _fiq /* fiq中断向量*/

/* 中断向量表入口地址*/

_undefined_instruction: .word undefined_instruction

_software_interrupt: .word software_interrupt

_prefetch_abort: .word prefetch_abort

_data_abort: .word data_abort

_not_used: .word not_used

_irq: .word irq

_fiq: .word fiq

.balignl 16,0xdeadbeef

以上代码设置了ARM异常向量表,各个异常向量介绍如下:

表 2.1 ARM异常向量表

在cpu/arm920t/start.S中还有这些异常对应的异常处理程序。当一个异常产生时,CPU根据异常号在异常向量表中找到对应的异常向量,然后执行异常向量处的跳转指令,CPU就跳转到对应的异常处理程序执行。

其中复位异常向量的指令“b start_code”决定了U-Boot启动后将自动跳转到标号“start_code”处执行。

(2)CPU进入SVC模式

start_code:

/*

* set the cpu to SVC32 mode

*/

mrs r0, cpsr

bic r0, r0, #0x1f /*工作模式位清零*/

orr r0, r0, #0xd3 /*工作模式位设置为“10011”(管理模式),并将中断禁止位和快中断禁止位置1 */

msr cpsr, r0

以上代码将CPU的工作模式位设置为管理模式,并将中断禁止位和快中断禁止位置一,从而屏蔽了IRQ和FIQ中断。

(3)设置控制寄存器地址

# if defined(CONFIG_S3C2400)

# define pWTCON 0x15300000

# define INTMSK 0x14400008

# define CLKDIVN 0x14800014

#else /* s3c2410与s3c2440下面4个寄存器地址相同*/

# define pWTCON 0x53000000 /* WATCHDOG控制寄存器地址*/

# define INTMSK 0x4A000008 /* INTMSK寄存器地址*/

# define INTSUBMSK 0x4A00001C /* INTSUBMSK寄存器地址*/

# define CLKDIVN 0x4C000014 /* CLKDIVN寄存器地址*/

# endif

对与s3c2440开发板,以上代码完成了WATCHDOG,INTMSK,INTSUBMSK,CLKDIVN四个寄存器的地址的设置。各个寄存器地址参见参考文献[4] 。

(4)关闭看门狗

ldr r0, =pWTCON

mov r1, #0x0

str r1, [r0] /* 看门狗控制器的最低位为0时,看门狗不输出复位信号*/

以上代码向看门狗控制寄存器写入0,关闭看门狗。否则在U-Boot启动过程中,CPU将不断重启。

(5)屏蔽中断

/*

* mask all IRQs by setting all bits in the INTMR - default

*/

mov r1, #0xffffffff /* 某位被置1则对应的中断被屏蔽*/

ldr r0, =INTMSK

str r1, [r0]

INTMSK是主中断屏蔽寄存器,每一位对应SRCPND(中断源引脚寄存器)中的一位,表明SRCPND相应位代表的中断请求是否被CPU所处理。

根据参考文献4,INTMSK寄存器是一个32位的寄存器,每位对应一个中断,向其中写入0xffffffff就将INTMSK寄存器全部位置一,从而屏蔽对应的中断。

# if defined(CONFIG_S3C2440)

ldr r1, =0x7fff

ldr r0, =INTSUBMSK

str r1, [r0]

# endif

INTSUBMSK每一位对应SUBSRCPND中的一位,表明SUBSRCPND相应位代表的中断请求是否被CPU所处理。

根据参考文献4,INTSUBMSK寄存器是一个32位的寄存器,但是只使用了低15位。向其中写入0x7fff就是将INTSUBMSK 寄存器全部有效位(低15位)置一,从而屏蔽对应的中断。

(6)设置MPLLCON,UPLLCON, CLKDIVN

# if defined(CONFIG_S3C2440)

#define MPLLCON 0x4C000004

#define UPLLCON 0x4C000008

ldr r0, =CLKDIVN

mov r1, #5

str r1, [r0]

ldr r0, =MPLLCON

ldr r1, =0x7F021

str r1, [r0]

ldr r0, =UPLLCON

ldr r1, =0x38022

str r1, [r0]

# else

/* FCLK:HCLK:PCLK = 1:2:4 */

/* default FCLK is 120 MHz ! */

ldr r0, =CLKDIVN

mov r1, #3

str r1, [r0]

#endif

CPU上电几毫秒后,晶振输出稳定,FCLK=Fin(晶振频率),CPU开始执行指令。但实际上,FCLK可以高于Fin,为了提高系统时钟,需要用软件来启用PLL。这就需要设置CLKDIVN,MPLLCON,UPLLCON这3个寄存器。

CLKDIVN寄存器用于设置FCLK,HCLK,PCLK三者间的比例,可以根据表2.2来设置。

表 2.2 S3C2440 的CLKDIVN寄存器格式

设置CLKDIVN为5,就将HDIVN设置为二进制的10,由于CAMDIVN[9]没有被改变过,取默认值0,因此HCLK = FCLK/4。PDIVN被设置为1,因此PCLK= HCLK/2。因此分频比FCLK:HCLK:PCLK = 1:4:8 。

MPLLCON寄存器用于设置FCLK与Fin的倍数。MPLLCON的位[19:12]称为MDIV,位[9:4]称为PDIV,位[1:0]称为SDIV。

对于S3C2440,FCLK与Fin的关系如下面公式:

MPLL(FCLK) = (2×m×Fin)/(p×)

其中:m=MDIC+8,p=PDIV+2,s=SDIV

MPLLCON与UPLLCON的值可以根据参考文献4中“PLL VALUE SELECTION TABLE”设置。该表部分摘录如下:

表 2.3 推荐PLL值

当mini2440系统主频设置为405MHZ,USB时钟频率设置为48MHZ时,系统可以稳定运行,因此设置MPLLCON与UPLLCON为:

MPLLCON=(0x7f<<12) | (0x02<<4) | (0x01) = 0x7f021

UPLLCON=(0x38<<12) | (0x02<<4) | (0x02) = 0x38022

(7)关闭MMU,cache

接着往下看:

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

bl cpu_init_crit

#endif

cpu_init_crit这段代码在U-Boot正常启动时才需要执行,若将U-Boot从RAM中启动则应该注释掉这段代码。

下面分析一下cpu_init_crit到底做了什么:

320 #ifndef CONFIG_SKIP_LOWLEVEL_INIT

321 cpu_init_crit:

322 /*

323 * 使数据cache与指令cache无效*/

324 */

325 mov r0, #0

326 mcr p15, 0, r0, c7, c7, 0 /* 向c7写入0将使ICache与DCache无效*/

327 mcr p15, 0, r0, c8, c7, 0 /* 向c8写入0将使TLB失效*/

328

329 /*

330 * disable MMU stuff and caches

331 */

332 mrc p15, 0, r0, c1, c0, 0 /* 读出控制寄存器到r0中*/

333 bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)

334 bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)

335 orr r0, r0, #0x00000002 @ set bit 2 (A) Align

336 orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache

337 mcr p15, 0, r0, c1, c0, 0 /* 保存r0到控制寄存器*/

338

339 /*

340 * before relocating, we have to setup RAM timing

341 * because memory timing is board-dependend, you will

342 * find a lowlevel_init.S in your board directory.

343 */

344 mov ip, lr

345

346 bl lowlevel_init

347

348 mov lr, ip

349 mov pc, lr

350 #endif /* CONFIG_SKIP_LOWLEVEL_INIT */

代码中的c0,c1,c7,c8都是ARM920T的协处理器CP15的寄存器。其中c7是cache控制寄存器,c8是TLB控制寄存器。325~327行代码将0写入c7、c8,使Cache,TLB内容无效。

第332~337行代码关闭了MMU。这是通过修改CP15的c1寄存器来实现的,先看CP15的c1寄存器的格式(仅列出代码中用到的位):

表 2.3 CP15的c1寄存器格式(部分)

各个位的意义如下:

V : 表示异常向量表所在的位置,0:异常向量在0x00000000;1:异常向量在0xFFFF0000

I : 0 :关闭ICaches;1 :开启ICaches

R、S : 用来与页表中的描述符一起确定内存的访问权限

B : 0 :CPU为小字节序;1 :CPU为大字节序

C : 0:关闭DCaches;1:开启DCaches

A : 0:数据访问时不进行地址对齐检查;1:数据访问时进行地址对齐检查

M : 0:关闭MMU;1:开启MMU

332~337行代码将c1的M位置零,关闭了MMU。

(8)初始化RAM控制寄存器

其中的lowlevel_init就完成了内存初始化的工作,由于内存初始化是依赖于开发板的,因此lowlevel_init的代码一般放在board下面相应的目录中。对于mini2440,lowlevel_init在board/samsung/mini2440/lowlevel_init.S中定义如下:

45 #define BWSCON 0x48000000 /* 13个存储控制器的开始地址*/

……

129 _TEXT_BASE:

130 .word TEXT_BASE

131

132 .globl lowlevel_init

133 lowlevel_init:

134 /* memory control configuration */

135 /* make r0 relative the current location so that it */

136 /* reads SMRDATA out of FLASH rather than memory ! */

137 ldr r0, =SMRDATA

138 ldr r1, _TEXT_BASE

139 sub r0, r0, r1 /* SMRDATA减_TEXT_BASE就是13个寄存器的偏移地址*/

140 ldr r1, =BWSCON /* Bus Width Status Controller */

141 add r2, r0, #13*4

142 0:

143 ldr r3, [r0], #4 /*将13个寄存器的值逐一赋值给对应的寄存器*/

144 str r3, [r1], #4

145 cmp r2, r0

146 bne 0b

147

148 /* everything is fine now */

149 mov pc, lr

150

151 .ltorg

152 /* the literal pools origin */

153

154 SMRDATA: /* 下面是13个寄存器的值*/

155 .word ……

156 .word ……

……

lowlevel_init初始化了13个寄存器来实现RAM时钟的初始化。lowlevel_init函数对于U-Boot从NAND Flash或NOR

Flash启动的情况都是有效的。

U-Boot.lds链接脚本有如下代码:

.text :

{

cpu/arm920t/start.o (.text)

board/samsung/mini2440/lowlevel_init.o (.text)

board/samsung/mini2440/nand_read.o (.text)

……

}

board/samsung/mini2440/lowlevel_init.o将被链接到cpu/arm920t/start.o后面,因此

board/samsung/mini2440/lowlevel_init.o也在U-Boot的前4KB的代码中。

U-Boot在NAND Flash启动时,lowlevel_init.o将自动被读取到CPU内部4KB的内部RAM中。因此第137~146行的代码将从CPU内部RAM中复制寄存器的值到相应的寄存器中。

对于U-Boot在NOR Flash启动的情况,由于U-Boot连接时确定的地址是U-Boot在内存中的地址,而此时U-Boot 还在NOR Flash中,因此还需要在NOR Flash中读取数据到RAM中。

由于NOR Flash的开始地址是0,而U-Boot的加载到内存的起始地址是TEXT_BASE,SMRDATA标号在Flash的地址就是SMRDATA-TEXT_BASE。

综上所述,lowlevel_init的作用就是将SMRDATA开始的13个值复制给开始地址[BWSCON]的13个寄存器,从而完成了存储控制器的设置。

(9)复制U-Boot第二阶段代码到RAM

cpu/arm920t/start.S原来的代码是只支持从NOR Flash启动的,经过修改现在U-Boot在NOR Flash和NAND Flash 上都能启动了,实现的思路是这样的:

bl bBootFrmNORFlash /* 判断U-Boot是在NAND Flash还是NOR Flash启动*/

cmp r0, #0 /* r0存放bBootFrmNORFlash函数返回值,若返回0表示NAND Flash启动,否则表示在NOR Flash启动*/

beq nand_boot /* 跳转到NAND Flash启动代码*/

/* NOR Flash启动的代码*/

b stack_setup /* 跳过NAND Flash启动的代码*/

nand_boot:

/* NAND Flash启动的代码*/

stack_setup:

/* 其他代码*/

其中bBootFrmNORFlash函数作用是判断U-Boot是在NAND Flash启动还是NOR Flash启动,若在NOR Flash启动则返回1,否则返回0。根据ATPCS规则,函数返回值会被存放在r0寄存器中,因此调用bBootFrmNORFlash函数后根据r0的值就可以判断U-Boot在NAND Flash启动还是NOR Flash启动。bBootFrmNORFlash函数在

board/samsung/mini2440/nand_read.c中定义如下:

int bBootFrmNORFlash(void)

{

volatile unsigned int *pdw = (volatile unsigned int *)0;

unsigned int dwVal;

dwVal = *pdw; /* 先记录下原来的数据*/

*pdw = 0x12345678;

if (*pdw != 0x12345678) /* 写入失败,说明是在NOR Flash启动*/

{

return 1;

}

else /* 写入成功,说明是在NAND Flash启动*/

{

*pdw = dwVal; /* 恢复原来的数据*/

return 0;

}

}

无论是从NOR Flash还是从NAND Flash启动,地址0处为U-Boot的第一条指令“ b start_code”。

对于从NAND Flash启动的情况,其开始4KB的代码会被自动复制到CPU内部4K内存中,因此可以通过直接赋值的方法来修改。

对于从NOR Flash启动的情况,NOR Flash的开始地址即为0,必须通过一定的命令序列才能向NOR Flash中写数据,所以可以根据这点差别来分辨是从NAND Flash还是NOR Flash启动:向地址0写入一个数据,然后读出来,如果发现写入失败的就是NOR Flash,否则就是NAND Flash。

下面来分析NOR Flash启动部分代码:

208 adr r0, _start /* r0 <- current position of code */

209 ldr r1, _TEXT_BASE /* test if we run from flash or RAM */

/* 判断U-Boot是否是下载到RAM中运行,若是,则不用再复制到RAM中了,这种情况通常在调试U-Boot时才发生*/ 210 cmp r0, r1 /*_start等于_TEXT_BASE说明是下载到RAM中运行*/

211 beq stack_setup

212 /* 以下直到nand_boot标号前都是NOR Flash启动的代码*/

213 ldr r2, _armboot_start

214 ldr r3, _bss_start

215 sub r2, r3, r2 /* r2 <- size of armboot */

216 add r2, r0, r2 /* r2 <- source end address */

217 /* 搬运U-Boot自身到RAM中*/

218 copy_loop:

219 ldmia r0!, {r3-r10} /* 从地址为[r0]的NOR Flash中读入8个字的数据*/

220 stmia r1!, {r3-r10} /* 将r3至r10寄存器的数据复制给地址为[r1]的内存*/

221 cmp r0, r2 /* until source end addreee [r2] */

222 ble copy_loop

223 b stack_setup /* 跳过NAND Flash启动的代码*/

下面再来分析NAND Flash启动部分代码:

nand_boot:

mov r1, #NAND_CTL_BASE

ldr r2, =( (7<<12)|(7<<8)|(7<<4)|(0<<0) )

str r2, [r1, #oNFCONF] /* 设置NFCONF寄存器*/

/* 设置NFCONT,初始化ECC编/解码器,禁止NAND Flash片选*/

ldr r2, =( (1<<4)|(0<<1)|(1<<0) )

str r2, [r1, #oNFCONT]

ldr r2, =(0x6) /* 设置NFSTAT */

str r2, [r1, #oNFSTAT]

/* 复位命令,第一次使用NAND Flash前复位*/

mov r2, #0xff

strb r2, [r1, #oNFCMD]

mov r3, #0

/* 为调用C函数nand_read_ll准备堆栈*/

ldr sp, DW_STACK_START

mov fp, #0

/* 下面先设置r0至r2,然后调用nand_read_ll函数将U-Boot读入RAM */

ldr r0, =TEXT_BASE /* 目的地址:U-Boot在RAM的开始地址*/

mov r1, #0x0 /* 源地址:U-Boot在NAND Flash中的开始地址*/

mov r2, #0x30000 /* 复制的大小,必须比u-boot.bin文件大,并且必须是NAND Flash块大小的整数倍,这里设置为0x30000(192KB)*/

bl nand_read_ll /* 跳转到nand_read_ll函数,开始复制U-Boot到RAM */

tst r0, #0x0 /* 检查返回值是否正确*/

beq stack_setup

bad_nand_read:

loop2: b loop2 //infinite loop

.align 2

DW_STACK_START: .word STACK_BASE+STACK_SIZE-4

其中NAND_CTL_BASE,oNFCONF等在include/configs/mini2440.h中定义如下:

#define NAND_CTL_BASE 0x4E000000 // NAND Flash控制寄存器基址

#define STACK_BASE 0x33F00000 //base address of stack

#define STACK_SIZE 0x8000 //size of stack

#define oNFCONF 0x00 /* NFCONF相对于NAND_CTL_BASE偏移地址*/

#define oNFCONT 0x04 /* NFCONT相对于NAND_CTL_BASE偏移地址*/

#define oNFADDR 0x0c /* NFADDR相对于NAND_CTL_BASE偏移地址*/

#define oNFDATA 0x10 /* NFDATA相对于NAND_CTL_BASE偏移地址*/

#define oNFCMD 0x08 /* NFCMD相对于NAND_CTL_BASE偏移地址*/

#define oNFSTAT 0x20 /* NFSTAT相对于NAND_CTL_BASE偏移地址*/

#define oNFECC 0x2c /* NFECC相对于NAND_CTL_BASE偏移地址*/

NAND Flash各个控制寄存器的设置在S3C2440的数据手册有详细说明,这里就不介绍了。

代码中nand_read_ll函数的作用是在NAND Flash中搬运U-Boot到RAM,该函数在

board/samsung/mini2440/nand_read.c中定义。

NAND Flash根据page大小可分为2种:512B/page和2048B/page的。这两种NAND Flash的读操作是不同的。因此就需要U-Boot识别到NAND Flash的类型,然后采用相应的读操作,也就是说nand_read_ll函数要能自动适应两种NAND Flash。

参考S3C2440的数据手册可以知道:根据NFCONF寄存器的Bit3(AdvFlash (Read only))和Bit2 (PageSize (Read only))可以判断NAND Flash的类型。Bit2、Bit3与NAND Flash的block类型的关系如下表所示:

2.4 NFCONF的Bit3、Bit2与NAND Flash的关系

由于的NAND Flash只有512B/page和2048 B/page这两种,因此根据NFCONF寄存器的Bit3即可区分这两种NAND Flash了。

完整代码见board/samsung/mini2440/nand_read.c中的nand_read_ll函数,这里给出伪代码:

int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)

{

//根据NFCONF寄存器的Bit3来区分2种NAND Flash

if( NFCONF & 0x8 ) /* Bit是1,表示是2KB/page的NAND Flash */

{

////////////////////////////////////

读取2K block 的NAND Flash

////////////////////////////////////

}

else /* Bit是0,表示是512B/page的NAND Flash */

{

/////////////////////////////////////

读取512B block 的NAND Flash

u-boot启动分析

背景: Board →ar7240(ap93) Cpu →mips 1、首先弄清楚什么是u-boot Uboot是德国DENX小组的开发,它用于多种嵌入式CPU的bootloader程序, uboot不仅支持嵌入式linux系统的引导,当前,它还支持其他的很多嵌入式操作系统。 除了PowerPC系列,还支持MIPS,x86,ARM,NIOS,XScale。 2、下载完uboot后解压,在根目录下,有如下重要的信息(目录或者文件): 以下为为每个目录的说明: Board:和一些已有开发板有关的文件。每一个开发板都以一个子目录出现在当前目录中,子目录存放和开发板相关的配置文件。它的每个子文件夹里都有如下文件(以ar7240/ap93为例): Makefile Config.mk Ap93.c 和板子相关的代码 Flash.c Flash操作代码 u-boot.lds 对应的链接文件 common:实现uboot命令行下支持的命令,每一条命令都对应一个文件。例如bootm命令对应就是cmd_bootm.c cpu:与特定CPU架构相关目录,每一款Uboot下支持的CPU在该目录下对应一个子目录,比如有子目录mips等。它的每个子文件夹里都有入下文件: Makefile Config.mk Cpu.c 和处理器相关的代码s Interrupts.c 中断处理代码 Serial.c 串口初始化代码 Start.s 全局开始启动代码 Disk:对磁盘的支持

Doc:文档目录。Uboot有非常完善的文档。 Drivers:Uboot支持的设备驱动程序都放在该目录,比如网卡,支持CFI的Flash,串口和USB等。 Fs:支持的文件系统,Uboot现在支持cramfs、fat、fdos、jffs2和registerfs。 Include:Uboot使用的头文件,还有对各种硬件平台支持的汇编文件,系统的配置文件和对文件系统支持的文件。该目下configs目录有与开发板相关的配置文件,如 ar7240_soc.h。该目录下的asm目录有与CPU体系结构相关的头文件,比如说mips 对应的有asm-mips。 Lib_xxx:与体系结构相关的库文件。如与ARM相关的库放在lib_arm中。 Net:与网络协议栈相关的代码,BOOTP协议、TFTP协议、RARP协议和NFS文件系统的实现。 Tools:生成Uboot的工具,如:mkimage等等。 3、mips架构u-boot启动流程 u-boot的启动过程大致做如下工作: 1、cpu初始化 2、时钟、串口、内存(ddr ram)初始化 3、内存划分、分配栈、数据、配置参数、以及u-boot代码在内存中的位置。 4、对u-boot代码作relocate 5、初始化malloc、flash、pci以及外设(比如,网口) 6、进入命令行或者直接启动Linux kernel 刚一开始由于参考网上代码,我一个劲的对基于smdk2410的板子,arm926ejs的cpu看了N 久,启动过程和这个大致相同。 整个启动中要涉及到四个文件: Start.S →cpu/mips/start.S Cache.S →cpu/mips/cache.S Lowlevel_init.S →board/ar7240/common/lowlevel_init.S Board.c →lib_mips/board.c 整个启动过程分为两个阶段来看: Stage1:系统上电后通过汇编执行代码 Stage2:通过一些列设置搭建了C环境,通过汇编指令跳转到C语言执行. Stage1: 程序从Start.S的_start开始执行.(至于为什么,参考u-boot.lds分析.doc) 先查看start.S文件吧!~ 从_start标记开始会看到一长串莫名奇妙的代码:

UBOOT命令详解

常用U-boot命令详解(z) 2010-09-30 15:05:52| 分类:学习心得体会|字号订阅 U-boot发展到现在,他的命令行模式已经非常接近Linux下的shell了,在我编译的 U-boot-2009.11中的命令行模式模式下支持“Tab”键的命令补全和命令的历史记录功能。而且如果你输入的命令的前几个字符和别的命令不重复,那么你就只需要打这几个字符即可,比如我想看这个U-boot的版本号,命令就是“ version”,但是在所有的命令中没有其他任何一个的命令是由“v”开头的,所以只需要输入“v”即可。 [u-boot@MINI2440]# version U-Boot 2009.11 ( 4月04 2010 - 12:09:25) [u-boot@MINI2440]# v U-Boot 2009.11 ( 4月04 2010 - 12:09:25) [u-boot@MINI2440]# base Base Address: 0x00000000 [u-boot@MINI2440]# ba Base Address: 0x00000000 由于U-boot支持的命令实在太多,一个一个细讲不现实,也没有必要。所以下面我挑一些烧写和引导常用命令介绍一下,其他的命令大家就举一反三,或者“help”吧! (1)获取帮助 命令:help 或? 功能:查看当前U-boot版本中支持的所有命令。 [u-boot@MINI2440]#help ?- alias for'help' askenv - get environment variables from stdin base - print or set address offset bdinfo - print Board Info structure bmp - manipulate BMP image data boot - boot default, i.e., run 'bootcmd' bootd - boot default, i.e., run 'bootcmd' bootelf - Boot from an ELF image in memory bootm - boot application image from memory bootp - boot image via network using BOOTP/TFTP protocol

Tiny6410_Uboot移植步骤详解

Uboot_for_Tiny6410_移植步骤详解 一、设计要求 1.目的 1)掌握U-boot剪裁编写 2)掌握交叉编译环境的配置 3)掌握U-boot的移植 2.实现的功能 1)U-boot编译成功 2)移植U-boot,使系统支持从NAND FLASH启动 二、设计方案 1.硬件资源 1)ARM处理器:ARM11芯片(Samsung S3C6410A),基于ARM1176JZF-S核设 计,运行频率533Mhz,最高可达 667Mhz 2)存储器:128M DDR RAM,可升级至 256M;MLC NAND Flash(2GB) 3)其他资源:具有三LCD接口、4线电阻 触摸屏接口、100M标准网络接口、标准DB9 五线串口、Mini USB2.0接口、USB Host 1.1、3.5mm音频输入输出口、标准TV-OUT

接口、SD卡座、红外接收等常用接口;另外 还引出4路TTL串口,另1路TV-OUT、 SDIO2接口(可接SD WiFi)接口等;在板的 还有蜂鸣器、I2C-EEPROM、备份电池、A D 可调电阻、8个中断式按键等。 2.软件资源 1)arm-linux-gcc-4.5.1(交叉编译) 2)u-boot-2010.09.tar.gz arm-linux-gcc-4.5.1-v6-vfp-20101103.t gz 三、移植过程 1.环境搭建 1)建立交叉编译环境 2)去这2个网站随便下载都可以下载得到最 新或者你想要的u-boot。( https://www.wendangku.net/doc/e318850351.html,/batch.viewl ink.php?itemid=1694 ftp://ftp.denx.de/pub/u-boot/ )

AM335x uboot spl分析

AM335x uboot spl分析 芯片到uboot启动流程 ROM → SPL→ uboot.img 简介 在335x 中ROM code是第一级的bootlader。mpu上电后将会自动执行这里的代码,完成部分初始化和引导第二级的bootlader,第二级的bootlader引导第三级bootader,在 ti官方上对于第二级和第三级的bootlader由uboot提供。 SPL To unify all existing implementations for a secondary program loader (SPL) and to allow simply adding of new implementations this generic SPL framework has been created. With this framework almost all source files for a board can be reused. No code duplication or symlinking is necessary anymore. 1> Basic ARM initialization 2> UART console initialization 3> Clocks and DPLL locking (minimal) 4> SDRAM initialization 5> Mux (minimal) 6> BootDevice initialization(based on where we are booting from.MMC1/MMC2/Nand/Onenand) 7> Bootloading real u-boot from the BootDevice and passing control to it. uboot spl源代码分析 一、makefile分析 打开spl文件夹只有一个makefile 可见spl都是复用uboot原先的代码。 主要涉及的代码文件为u-boot-2011.09-psp04.06.00.03/arch/arm/cpu/armv7 u-boot-2011.09-psp04.06.00.03/arch/arm/lib u-boot-2011.09-psp04.06.00.03/drivers LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot-spl.lds 这个为链接脚本 __image_copy_end _end 三、代码解析 __start 为程序开始(arch/arm/cpu/armv7/start.S) .globl _start 这是在定义u-boot的启动定义入口点,汇编程序的缺省入口是 start 标号,用户也可以在连接脚本文件中用ENTRY标志指明其它入口点。

UBoot移植详解

u-boot 移植步骤详解 1 U-Boot简介 U-Boot,全称Universal Boot Loader,是遵循GPL条款的开放源码项目。从FADSROM、8xxROM、PPCBOOT逐步发展演化而来。其源码目录、编译形式与Linux内核很相似,事实上,不少U-Boot源码就是相应的Linux内核源程序的简化,尤其是一些设备的驱动程序,这从U-Boot源码的注释中能体现这一点。但是U-Boot不仅仅支持嵌入式Linux 系统的引导,当前,它还支持NetBSD, VxWorks, QNX, RTEMS, ARTOS, LynxOS嵌入式操作系统。其目前要支持的目标操作系统是OpenBSD, NetBSD, FreeBSD,4.4BSD, Linux, SVR4, Esix, Solaris, Irix, SCO, Dell, NCR, VxWorks, LynxOS, pSOS, QNX, RTEMS, ARTOS。这是U-Boot中Universal的一层含义,另外一层含义则是U-Boot除了支持PowerPC系列的处理器外,还能支持MIPS、x86、ARM、NIOS、XScale等诸多常用系列的处理器。这两个特点正是U-Boot项目的开发目标,即支持尽可能多的嵌入式处理器和嵌入式操作系统。就目前来看,U-Boot对PowerPC系列处理器支持最为丰富,对Linux的支持最完善。其它系列的处理器和操作系统基本是在2002年11 月PPCBOOT 改名为U-Boot后逐步扩充的。从PPCBOOT向U-Boot的顺利过渡,很大程度上归功于U-Boot的维护人德国DENX软件工程中心Wolfgang Denk[以下简称W.D]本人精湛专业水平和持着不懈的努力。当前,U-Boot项目正在他的领军之下,众多有志于开放源码BOOT LOADER移植工作的嵌入式开发人员正如火如荼地将各个不同系列嵌入式处理器的移植工作不断展开和深入,以支持更多的嵌入式操作系统的装载与引导。 选择U-Boot的理由: ①开放源码; ②支持多种嵌入式操作系统内核,如Linux、NetBSD, VxWorks, QNX, RTEMS, ARTOS, LynxOS; ③支持多个处理器系列,如PowerPC、ARM、x86、MIPS、XScale; ④较高的可靠性和稳定性; ④较高的可靠性和稳定性; ⑤高度灵活的功能设置,适合U-Boot调试、操作系统不同引导要求、产品发布等; ⑥丰富的设备驱动源码,如串口、以太网、SDRAM、FLASH、LCD、NVRAM、EEPROM、RTC、键盘等; ⑦较为丰富的开发调试文档与强大的网络技术支持; 2 U-Boot主要目录结构 - board 目标板相关文件,主要包含SDRAM、FLASH驱动; - common 独立于处理器体系结构的通用代码,如内存大小探测与故障检测;

i.MX6UL -- Linux系统移植过程详解(最新的长期支持版本)

i.MX6UL -- Linux系统移植过程详解(最新的长期支持版本) ?开发平台:i.MX 6UL ?最新系统: u-boot2015.04 + Linux4.1.15_1.2.0 ?交叉编译工具:dchip-linaro-toolchain.tar.bz2 源码下载地址: U-Boot: (选择rel_imx_4.1.15_1.2.0_ga.tar.bz2) https://www.wendangku.net/doc/e318850351.html,/git/cgit.cgi/imx/uboot-imx.git/ Kernel: (选择rel_imx_4.1.15_1.2.0_ga.tar.bz2) https://www.wendangku.net/doc/e318850351.html,/git/cgit.cgi/imx/linux-2.6-imx.git/ 源码移植过程: 1、将linux内核及uBoot源码拷贝到Ubuntu12.04系统中的dchip_imx6ul目录下; 2、使用tar命令分别将uboot和kernel解压到dchip_imx6ul目录下; 3、解压后进入uboot目录下,新建文件make_dchip_imx6ul_uboot201504.sh,且文件内容如下: ################################################################### # Build U-Boot.2015.04 For D518--i.MX6UL By FRESXC # ################################################################### #!/bin/bash export ARCH=arm export CROSS_COMPILE=/dchip-linaro-toolchain/bin/arm-none-linux-gnueabi - make mrproper # means CLEAN make mx6ul_14x14_evk_defconfig make2>&1|tee built_dchip_imx6ul_uboot201504.out 4进入kernel目录下,新建文件make_dchip_imx6ul_linux4115120.sh,且文件内容如下: ###################################################################

uboot版本文件结构

uboot版本文件结构的更新改变 分类:ARM2011-09-22 12:57 339人阅读评论(0) 收藏举报本来是开始分析uboot代码的,但是无论是教材还是网上资料都对于我最新下的uboot原码结构不同,对于还是小白的我不容易找到相应的文件,下面是uboot版本中文件组织结构的改变,,,,, u-boot版本情况 网站:http://ftp.denx.de/pub/u-boot/ 1、版本号变化: 2008年8月及以前 按版本号命名:u-boot-1.3.4.tar.bz2(2008年8月更新) 2008年8月以后均按日期命名。 目前最新版本:u-boot-2011.06.tar.bz2(2011年6月更新) 2、目录结构变化: u-boot目录结构主要经历过2次变化,u-boot版本第一次从u-boot-1.3.2开始发生变化,主要增加了api的内容;变化最大的是第二次,从2010.6版本开始。 u-boot-2010.03及以前版本 ├── api存放uboot提供的接口函数 ├── board根据不同开发板定制的代码,代码也不少 ├── common通用的代码,涵盖各个方面,已命令行处理为主 ├── cpu与体系结构相关的代码,uboot的重头戏 ├── disk磁盘分区相关代码 ├── doc文档,一堆README开头的文件 ├── drivers驱动,很丰富,每种类型的设备驱动占用一个子目录 ├── examples示例程序 ├── fs文件系统,支持嵌入式开发板常见的文件系统 ├── include头文件,已通用的头文件为主 ├── lib_【arch】与体系结构相关的通用库文件 ├── nand_spl NAND存储器相关代码 ├── net网络相关代码,小型的协议栈 ├── onenand_ipl

uboot环境变量总结

Common目录下面与环境变量有关的文件有以下几个:env_common.c,env_dataflash.c,env_eeprom.c,env_flash.c,env_nand.c,env_nowhere.c,env_nvram.c,environment.c。 env_common.c中包含的是default_environment[]的定义; env_dataflash.c,env_eeprom.c,env_flash.c,env_nand.c, env_nvram.c 中包含的是相应存储器与环境变量有关的函数:env_init(void),saveenv(void),env_relocate_spec (void),env_relocate_spec (void),use_default()。至于env_nowhere.c,因为我们没有定义CFG_ENV_IS_NOWHERE,所以这个文件实际上没有用。 environment.c这个文件时是我真正理解环境变量的一个关键。在这个文件里定义了一个完整的环境变量的结构体,即包含了这两个ENV_CRC(用于CRC校验),Flags(标志有没有环境变量的备份,根据CFG_REDUNDAND_ENVIRONMENT这个宏定义判断)。定义这个环境变量结构体的时候还有一个非常重要的关键字: __PPCENV__,而__PPCENV__在该.c文件中好像说是gnu c编译器的属性,如下: # define __PPCENV__ __attribute__ ((section(".text"))) 意思是把这个环境变量表作为代码段,所以在编译完UBOOT后,UBOOT的代码段就会有环境变量表。当然,这要在我们定义了ENV_IS_EMBEDDED之后才行,具体而言,环境变量表会在以下几个地方出现(以nand flash为例): 1、UBOOT中的代码段(定义了ENV_IS_EMBEDDED), 2、UBOOT中的默认环 境变量, 3、紧接UBOOT(0x0 ~ 0x1ffff)后面:0x20000 ~ 0x3ffff 之间,包括备份的环境变量,我们读取,保存也是对这个区域(即参数区)进行的。3、SDRAM中的UBOOT中,包括代码段部分和默认部分,4、SDRAM中的melloc分配的内存空间中。 Environment.c代码如下: env_t environment __PPCENV__ = { ENV_CRC, /* CRC Sum */ #ifdef CFG_REDUNDAND_ENVIRONMENT 1, /* Flags: valid */ #endif { #if defined(CONFIG_BOOTARGS) "bootargs=" CONFIG_BOOTARGS "\0" #endif #if defined(CONFIG_BOOTCOMMAND) "bootcmd=" CONFIG_BOOTCOMMAND "\0" #endif #if defined(CONFIG_RAMBOOTCOMMAND) "ramboot=" CONFIG_RAMBOOTCOMMAND "\0"

U_Boot第一启动阶段Uboot启动分析笔记-----Stage1(start.S与lowlevel_init.S详解)

Uboot启动分析笔记-----Stage1(start.S与lowlevel_init.S详解) Uboot启动分析笔记-----Stage1(start.S与lowlevel_init.S详解) 1 u-boot.lds 首先了解uboot的链接脚本board/my2410/u-boot.lds,它定义了目标程序各部分的链接顺序。OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") /*指定输出可执行文件为ELF格式,32为,ARM小端*/ OUTPUT_ARCH(arm) /*指定输出可执行文件为ARM平台*/ ENTRY(_start) /*起始代码段为_start*/ SECTIONS { /* 指定可执行image文件的全局入口点,通常这个地址都放在ROM(flash)0x0位置*、. = 0x00000000;从0x0位置开始 . = ALIGN(4); 4字节对齐 .text : {

cpu/arm920t/start.o (.text) board/my2440/lowlevel_init.o (.text) *(.text) } . = ALIGN(4); .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } . = ALIGN(4); .data : { *(.data) } /* 只读数据段,所有的只读数据段都放在这个位置*/ . = ALIGN(4); .got : { *(.got) } /*指定got段, got段式是uboot自定义的一个段, 非标准段*/ . = .; __u_boot_cmd_start = .; /*把__u_boot_cmd_start赋值为当前位置, 即起始位置*/ .u_boot_cmd : { *(.u_boot_cmd) } /* u_boot_cmd段,所有的u-boot命令相关的定义都放在这个位置,因为每个命令定义等长,所以只要以__u_boot_cmd_start为起始地址进行查找就可以很快查找到某一个命令的定义,并依据定义的命令指针调用相应的函数进行处理用户的任务*/ __u_boot_cmd_end = .; /* u_boot_cmd段结束位置,由此可以看出,这段空间的长度并没有严格限制,用户可以添加一些u-boot的命令,最终都会在连接是存放在这个位置。*/

Uboot如何向内核传递参数

Uboot如何向内核传递参数 一:启动参数的传递过程 启动参数是包装在数据结构里的,在linux kernel启动的时候,bootloader把这个数据结构拷贝到某个地址, 在改动PC跳向内核接口的同时,通过通用寄存器R2来传递这个地址的值,下面这句话就是uboot跳向linux kernel的代码(bootm命令) theKernel (0, bd->bi_arch_number, bd->bi_boot_params); thekernel其实不是个函数,而是指向内核入口地址的指针,把它强行转化为带三个参数的函数指针,会把三个 参数保存到通用寄存器中,实现了向kernel传递信息的功能,在这个例子里,会把R0赋值为0,R1赋值为机器号 R2赋值为启动参数数据结构的首地址 因此,要向内核传递参数很简单,只要把启动参数封装在linux预定好的数据结构里,拷贝到某个地址(一般约定俗成是内存首地址+100dex) 二:启动参数的数据结构 启动参数可保存在两种数据结构中,param_struct和tag,前者是2.4内核用的,后者是2.6以后的内核更期望用的 但是,到目前为止,2.6的内核也可以兼容前一种结构,两种数据结构具体定义如下(arm cpu): struct param_struct { union { struct { unsigned long page_size; /* 0 */ unsigned long nr_pages; /* 4 */ unsigned long ramdisk_size; /* 8 */ unsigned long flags; /* 12 */ #define FLAG_READONLY 1 #define FLAG_RDLOAD 4 #define FLAG_RDPROMPT 8 unsigned long rootdev; /* 16 */ unsigned long video_num_cols; /* 20 */ unsigned long video_num_rows; /* 24 */ unsigned long video_x; /* 28 */ unsigned long video_y; /* 32 */ unsigned long memc_control_reg; /* 36 */ unsigned char sounddefault; /* 40 */ unsigned char adfsdrives; /* 41 */ unsigned char bytes_per_char_h; /* 42 */ unsigned char bytes_per_char_v; /* 43 */ unsigned long pages_in_bank[4]; /* 44 */ unsigned long pages_in_vram; /* 60 */

UBoot源码分析1

?UBoot源码解析(一)

主要内容 ?分析UBoot是如何引导Linux内核 ?UBoot源码的一阶段解析

BootLoader概念?Boot Loader 就是在操作系统内核运行之前运行 的一段小程序。通过这段小程序,我们可以初始 化硬件设备、建立内存空间的映射图,从而将系 统的软硬件环境带到一个合适的状态,以便为最 终调用操作系统内核准备好正确的环境 ?通常,Boot Loader 是严重地依赖于硬件而实现 的,特别是在嵌入式世界。因此,在嵌入式世界 里建立一个通用的Boot Loader 几乎是不可能的。 尽管如此,我们仍然可以对Boot Loader 归纳出 一些通用的概念来,以指导用户特定的Boot Loader 设计与实现。

UBoot来源?U-Boot 是 Das U-Boot 的简称,其含义是 Universal Boot Loader,是遵循 GPL 条款的开放源码项目。最早德国 DENX 软件工程中心的 Wolfgang Denk 基于 8xxROM 和 FADSROM 的源码创建了 PPCBoot 工程项目,此后不断 添加处理器的支持。而后,Sysgo Gmbh 把 PPCBoot 移 植到 ARM 平台上,创建了 ARMBoot 工程项目。最终, 以 PPCBoot 工程和 ARMBoot 工程为基础,创建了 U- Boot 工程。 ?而今,U-Boot 作为一个主流、通用的 BootLoader,成功地被移植到包括 PowerPC、ARM、X86 、MIPS、NIOS、XScale 等主流体系结构上的百种开发板,成为功能最多、 灵活性最强,并且开发最积极的开源 BootLoader。目前。 U-Boot 仍然由 DENX 的 Wolfgang Denk 维护

嵌入式Linux之我行 史上最牛最详细的uboot移植,不看别后悔

嵌入式Linux之我行——u-boot-2009.08在2440上的移植详解(一) 嵌入式Linux之我行,主要讲述和总结了本人在学习嵌入式linux中的每个步骤。一为总结经验,二希望能给想入门嵌入式Linux 的朋友提供方便。如有错误之处,谢请指正。 ?共享资源,欢迎转载:https://www.wendangku.net/doc/e318850351.html, 一、移植环境 ?主机: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/start.S文件中,他用汇编语言写成;u-boot的stage2代码通常放在lib_xxxx/board.c文件中,他用C语言写成。各个部分的流程图如下:

2. 建立自己的开发板项目并测试编译。 目前u-boot对很多CPU直接支持,可以查看board目录的一些子目录,如:board/samsung/目录下就是对三星一些ARM 处理器的支持,有smdk2400、smdk2410和smdk6400,但没有2440,所以我们就在这里建立自己的开发板项目。 1)因2440和2410的资源差不多,主频和外设有点差别,所以我们就在board/samsung/下建立自己开发板的项目,取名叫my2440 2)因2440和2410的资源差不多,所以就以2410项目的代码作为模板,以后再修改

关于uboot移植 CAMDIVN与时钟

关于uboot移植 CAMDIVN与时钟 2010-03-09 19:57 在该文件的122行附近有这样一个结构体 typedef struct { S3C24X0_REG32 LOCKTIME; S3C24X0_REG32 MPLLCON; S3C24X0_REG32 UPLLCON; S3C24X0_REG32 CLKCON; S3C24X0_REG32 CLKSLOW; S3C24X0_REG32 CLKDIVN; } /*__attribute__((__packed__))*/ S3C24X0_CLOCK_POWER; 是用来封装时钟寄存器的,我们要在其中增加一项S3C24X0_REG32 CAMDIVN,为什么加这么一个呢?因为这个寄存器是2410所没有的,而2440在配置时钟的时候又必须用到,看名字我们就知道是用来配置CAMERA时钟的,也就是配置摄像头的时钟的。 貌似和配置uboot启动的时钟没有关系?其实不然,我们在修改下一个文件的时候就可以看到其用途了, 此结构体修改后的结果为 typedef struct { S3C24X0_REG32 LOCKTIME; S3C24X0_REG32 MPLLCON; S3C24X0_REG32 UPLLCON; S3C24X0_REG32 CLKCON; S3C24X0_REG32 CLKSLOW; S3C24X0_REG32 CLKDIVN; S3C24X0_REG32 CAMDIVN; } /*__attribute__((__packed__))*/ S3C24X0_CLOCK_POWER; 第二个文件..\cpu\arm920t\s3c24x0\speed.c 在这个文件中需要修改两个函数 第一个函数在54行附近:static ulong get_PLLCLK(int pllreg) 由于S3C2410和S3C2440的MPLL、UPLL计算公式不一样,所以get_PLLCLK 函数也需要修改:

经典=Uboot-2-命令详解(bootm)

bootm命令中地址参数,内核加载地址以及内核入口地址 分类:u-boot2010-11-04 10:472962人阅读评论(0)收藏举报downloadlinuxbytecmdheaderimage bootm命令只能用来引导经过mkimage构建了镜像头的内核镜像文件以及根文件镜像,对于没有用mkimage对内核进行处理的话,那直接把内核下载到连接脚本中指定的加载地址0x30008000再运行就行,内核会自解压运行(不过内核运行需要一个tag来传递参数,而这个tag是由bootloader提供的,在u-boot下默认是由bootm命令建立的)。 通过mkimage可以给内核镜像或根文件系统镜像加入一个用来记录镜像的各种信息的头。同样通过mkimage也可以将内核镜像进行一次压缩(指定-C none/gzip/bzip2),所以这里也就引申出了两个阶段的解压缩过程:第一个阶段是u-boot里面的解压缩,也就是将由mkimage压缩的镜像解压缩得到原始的没加镜像头的内核镜像。第二个阶段是内核镜像的自解压,u-boot 里面的解压实际上是bootm 实现的,把mkimage -C bzip2或者gzip 生成的uImage进行解压;而kernel的自解压是对zImage进行解压,发生在bootm解压之后。 下面通过cmd_bootm.c文件中对bootm命令进行解析以及执行的过程来分析,这三种不同地址的区别: ulong load_addr = CFG_LOAD_ADDR; /* Default Load Address */ int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { ...... if (argc < 2) { addr = load_addr;//当bootm命令后面不带地址参数时,将默认的加载地址赋值给addr } else { addr = simple_strtoul(argv[1], NULL, 16); //如果bootm命令后面带了加载地址,则将该地址赋值给addr,所以最终有用的地址还是bootm命令后附带的地址 } ...... //

uboot启动常见的错误汇总

【uboot启动常见的错误汇总】 1. operating at 100M full duplex mode *** ERROR: `ethaddr' not set dm9000 i/o: 0x5000000, id: 0x90000a46 DM9000: running in 16 bit mode MAC: 00:00:00:00:00:00 operating at 100M full duplex mode Wrong Image Format for bootm command ERROR: can't get kernel image! 原因是:没有设置mac地址,需要重新设置 setenv ethaddr 01:02:03:04:05:06 saveenv/save 2.在开发板上ping ubuntu的ip地址ping不通 1.网线没插 2.ubuntu没有打开 3.ping 的过程中,ubuntu会扫描ip地址,会一直去获取ip地址,但是开发板没有分配ip地址的权利,也就是ubuntu获取不了ip地址,同时查看ubuntu 的ip地址是没有的。 1.设置临时的ip地址 sudo ifconfig eth0 192.168.1.* 2.永久生效 在ubuntu的右上角添加静态ip地址。 3.发现ubuntu的右上角网络图标类似于wifi的图标,如何将这个图标改成网络的 图标 sudo /etc//init.d/network-manager restart 如何执行之后,还是wifi图标 sudo vi /etc/NetworkManager/NetworkManager.conf managed=false false --->true sudo /etc//init.d/network-manager restart 如果执行之后,还是wifi图标 重启系统 4.你的pc电脑已经打开wifi网,需要将无线网关闭 5.虚拟机网卡设置出错,需要将nat设置为桥接 6.换开发板

iTop4412的uboot第一阶段

2 uboo t 源码分析 2.5.1.star t.S 2.5.1.star t.S 引入引入 2.5.1.1、u-boot.lds中找到start.S入口 (1)在C语言中整个项目的入口就是 main函数(这是 个.c文件的项目,第一个要分析的文件就是包含了C语言规定的),所以譬如说一 个有 main函数的那个文件。 10000 ( 2 方。ENTRY(_start)因此 _start 符号所在的文件就是整个程序的起始文 件, _sta rt 所在处的 代码就是整个程序的起始代码。 2.5.1.2、SourceInsight中如何找到 文件 (1)当前状况:我们知道在uboot中的1000多个文件中有一个符号 叫 _start,但是我们不知道 这个符号在哪个文件中。这种情况下要查找一个符号在所有项目中文件中的引用,要使用SourceInsight的搜索功能。 (2)start.s 在cpu/arm_cortexa9/start.s (3)然后进入start.S文件中,发现 个uboot的入口代码,就是第57 57行中就 是行。_sta rt 标号的定义处,于是乎我们就找到了整 2.5.1.3、SI中找文件技巧 (1)以上,找到了start.S文件,下面我们就从start.S文件开始分析uboot第一阶段。 (2)在SI中,如果我们知道我们要找的文件的名字,但是我们又不知道他在哪个目录下,我 们要怎样找到并打开这个文件?方法是在 SI中先打开右边的工程项目管理栏目,然后点击 最左边那个(这个是以文件为单位来浏览的),然后在上面输入栏中输入要找的文件的名 字。我们在输入的时候,SI在不断帮我们进行匹配,即使你不记得文件的全名只是大概记 得名字,也能帮助你找到你要找的文件。 2.5.2.start.S解析1 2.5.2.1、不简单的头文件包含

uboot调试指南

Uboot调试参考指南 一、调试目的 Uboot的调试旨在通过观察uboot运行时状态来测试硬件问题。 二、调试步骤 1.修改代码 在uboot代码路径下,编辑uboot代码,需要做以下修改; a.修改config.mk文件,添加以下两行内容: AFLAGS += -Wa,-gdwarf2 CFLAGS += -g2 -gdwarf-2 b.修改. /arch/powerpc/lib/board.c文件 debug("Now running in RAM - U-Boot at: %08lx\n", dest_addr); printf("Now running in RAM - U-Boot at: %08lx\n", dest_addr); 将debug改为printf,如上所示。 2.编译uboot 执行make BSC9131RDB_SYSCLK100_NAND,编译uboot 3.将编译好的u-boot-nand.bin(uboot image格式)及u-boot(elf格式文件)文件拷 贝出来 4.烧录uboot 将步骤3中保存的u-boot-nand.bin烧录到目标板中,烧录过程略。 5.建立工程 a.在cw界面,点击file->import, 选择code warrior -> Power architecture ELF executable,如图1所示: 图1 建立elf工程 b.选择步骤3中保存的u-boot(elf格式文件),toolchain选择bareboard application, target OS选择none,工程名字请根据需要设置,比如我的机器上设置为example, 点击next,如图2所示:

uboot_freescale_imx51_start.s_详解

/* * *Purpose: the document is used to learn detailed information aboutimx51 cpu start.S, *referring to some documents on websites. *file address: U-boot-2009.08/Cpu/Arm_cortexa8/start.S * * writer: xfhai 2011.7.22 * *Instruction: *1.@xxxx : indicates annotation *2./***** *** *****/ : stand for code in my files *3.instructions refers to code not included in my file * */ Section 1: uboot overview 大多数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中执行,该工作可使用指令ldr pc来完成。 2、Stage2 C语言代码部分 lib_arm/board.c中的start arm boot是C语言开始的函数也是整个启动代码中C语言的主函数,同时还是整个u-boot(armboot)的主函数,该函数只要完成如下操作: ==>(1)调用一系列的初始化函数。 ==>(2)初始化Flash设备。 ==>(3)初始化系统内存分配函数。 ==>(4)如果目标系统拥有NAND设备,则初始化NAND设备。 ==>(5)如果目标系统有显示设备,则初始化该类设备。 ==>(6)初始化相关网络设备,填写IP、MAC地址等。 ==>(7)进去命令循环(即整个boot的工作循环),接受用户从串口输入的命令,然后进行相应的工作。

相关文档
相关文档 最新文档