当前位置:文档之家› u-boot实现原理完全分析

u-boot实现原理完全分析

u-boot实现原理完全分析
u-boot实现原理完全分析

U-BOOT

作者:陈颖

邮箱:chxxxyg@https://www.doczj.com/doc/fc6720724.html,

博客:https://www.doczj.com/doc/fc6720724.html,/

目录

一U-BOOT目录结构 (1)

二U-BOOT的启动与内核引导 (3)

1、U-BOOT的启动分析 (3)

1.1设置异常向量表 (3)

1.2 U-BOOT的存储映射 (4)

1.3 硬件设备的初始化 (5)

1.4 硬件平台前期初始化 (9)

1.5代码重定位 (13)

1.6 硬件平台后期初始化 (16)

2、内核引导 (20)

2.1 u-boot命令实现原理 (20)

2.2内核引导 (24)

三U-BOOT编译流程分析 (35)

1、U-BOOT编译命令 (35)

2、U-BOOT配置流程 (35)

2.1环境初始化 (35)

2.2 make smdk2410_config命令的执行过程 (38)

2.3 make smdk2410命令的执行过程 (42)

2.4 U-BOOT的编译流程 (43)

U-BOOT原理分析

一U-BOOT目录结构

api

api目录对应于一些扩展应用的独立的api

arch

arch存放与CPU架构有关的目录,下面每一个目录就代表一种架构的CPU

board

board目录是与硬件平台相关的目录,特定于某种硬件平台的文件以子目录的形式存放在该目录下

common

common目录存放了u-boot所支持的所有命令

disk

disk目录存放了磁盘驱动和相关的代码

doc

doc目录存放了u-boot的参考文档

drivers

u-boot支持的所有驱动都存放在driver目录下,这些驱动大都根据linux驱动改写而来dts

dts目录包含一个平台设备树相关的makefile,可编译生成设备树镜像文件

examples

example下时一些在u-boot上运行的事例程序

fs

fs目录下是u-boot所支持的文件系统

include

include目录包含了u-boot的头文件以及各种硬件平台的系统配置文件

lib

lib目录下是u-boot的库文件

nand_spl

支持从nand flash启动的相关代码

net

u-boot的网络子系统

onenand_ipl

支持从onenand 启动的代码

post

Post下是支持上电自检功能的目录

spl

与nand_spl相关的makefile,编译支持从nand flash启动的u-boot二进制文件tools

tools目录下是u-boot的一些辅助工具,比如生成u-boot镜像文件等

二U-BOOT的启动与内核引导

1、U-BOOT的启动分析

u-boot支持多种架构类型的cpu,支持多种硬件平台,本文以smdk2410为例来讲解u-boot 的功能原理。

u-boot的入口在文件在arch/arm/cpu/arm920t/start.S中,因为在文件在链接文件arch/arm/cpu/u-boot.lds中被第一个链接,如下:

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")

OUTPUT_ARCH(arm)

ENTRY(_start)

SECTIONS

{

. = 0x00000000;

. = ALIGN(4);

.text :

{

__image_copy_start = .;

CPUDIR/start.o (.text) //start.o对应源代码就是start.S

*(.text)

}

…………

1.1设置异常向量表

.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

1)定义全局变量_start存储u-boot的起始地址,由链接文件arch/arm/cpu/u-boot.lds可知该值为0x0。

2).word定义一个4字节的变量并赋给一个初始值,

如:undefined_instruction: .word undefined_instruction

3)定义变量_undefined_instruction,并将未定义指令异常中断处理函数地址赋给它。

4).balignl 16, 0xdeadbeef

地址以16字节对其,不对齐的用常量0xdeadbeef来填充。

1.2 U-BOOT的存储映射

.globl _TEXT_BASE

_TEXT_BASE:

.word CONFIG_SYS_TEXT_BASE

//在配置文件include/configs/smdk2410.h中定义

#define CONFIG_SYS_TEXT_BASE 0x0

下面是定义了一些全局变量,这些全局变量存储了一些偏移地址或是栈地址,这些地址是根据链接文件arch/arm/cpu/u-boot.lds中对应段的地址计算出来的。

.globl _bss_start_ofs //bss数据区相对于起始位置的偏移

_bss_start_ofs:

.word __bss_start - _start

.globl _bss_end_ofs //bss数据区结束处相对于起始位置的偏移

_bss_end_ofs:

.word __bss_end__ - _start

.globl _end_ofs

_end_ofs:

.word _end - _start

#ifdef CONFIG_USE_IRQ

.globl IRQ_STACK_START //IRQ的栈地址,在运行时计算,现在赋初值0x0badc0de IRQ_STACK_START:

.word 0x0badc0de

.globl FIQ_STACK_START

FIQ_STACK_START: //FIQ的栈地址,在运行时计算,现在赋初值0x0badc0de .word 0x0badc0de

#endif

.globl IRQ_STACK_START_IN

IRQ_STACK_START_IN:

//该变量存储IRQ的栈地址+8字节的位置,在运行时计算,现在赋初值0x0badc0de .word 0x0badc0de

对于u-boot存储映射有一张很经典的图描述了u-boot运行中,在内存中的映射关系。U-boot在启动的初始阶段的主要工作就是,将自己从存储设备中搬移到内存中,并摆出如下布局:

1.3 硬件设备的初始化

(1)CPU进入SVC模式

start_code:

mrs r0, cpsr

bic r0, r0, #0x1f

orr r0, r0, #0xd3

msr cpsr, r0

当系统复位时程序就跳转到start_code处执行,上面的代码将CPU的工作模式位设置为管理模式,并将中断禁止位和快中断禁止位置一,从而屏蔽IRQ和FIQ中断。

(2)关闭看门狗

#ifdef CONFIG_S3C24X0

# if defined(CONFIG_S3C2400)

# define pWTCON 0x15300000

# define INTMSK 0x14400008 /* Interrupt-Controller base addresses */

# define CLKDIVN 0x14800014 /* clock divisor register */

#else

# define pWTCON 0x53000000

# define INTMSK 0x4A000008 /* Interrupt-Controller base addresses */

# define INTSUBMSK 0x4A00001C

# define CLKDIVN 0x4C000014 /* clock divisor register */

# endif

设置一些寄存器的地址

ldr r0, =pWTCON

mov r1, #0x0

str r1, [r0]

系统启动时看门狗寄存器是使能的,如果不按时喂狗系统就会复位,所以这里要关掉看门狗。

(3)禁止所有中断

mov r1, #0xffffffff

ldr r0, =INTMSK

str r1, [r0]

# if defined(CONFIG_S3C2410)

ldr r1, =0x3ff

ldr r0, =INTSUBMSK

str r1, [r0]

# endif

INTMSK是主中断屏蔽寄存器,INTSUBMSK是子中断屏蔽寄存器,只要相应位被置一,对应的中断请求就得不到处理。上面代码即是屏蔽所有中断以及子中断。

(4)设置时钟除数寄存器

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

/* default FCLK is 120 MHz ! */

ldr r0, =CLKDIVN

mov r1, #3

str r1, [r0]

#endif /* CONFIG_S3C24X0 */

CLKDIVN寄存器用于设置FCLK,HCLK,PCLK三者间的比例。

1)CLKDIVN位[2:1]用于设置FCLK和HCLK的比例,设置的值和对应比例如下:

00 : HCLK = FCLK/1.

01 : HCLK = FCLK/2.

10 : HCLK = FCLK/4

2)CLKDIVN位的第0位用于设置HCLK和PCLK的比例,设置的值和对应比例如下:0: PCLK = HCLK/1

1:PCLK = HCLK/2

(5)关闭MMU与cache

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

bl cpu_init_crit

#endif

//调用函数cpu_init_crit,使指令cache与数据cache无效,使TLB无效。

该函数在arch/arm/cpu/arm920t/start.S中实现,如下:

cpu_init_crit:

mov r0, #0

mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */

mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */

/*

* disable MMU stuff and caches

*/

mrc p15, 0, r0, c1, c0, 0

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

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

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

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

mcr p15, 0, r0, c1, c0, 0

//上面代码是禁止MMU

mov ip, lr

//lr寄存器保存了调用子程序时当前地址,以便子程序调用结束时返回。这里处于子程//序中又将再次调用下一级子程序,所以这里保存上一次调用是保存在lr中的值。

bl lowlevel_init

mov lr, ip

mov pc, lr

//函数lowlevel_init是在文件board/samsung/smdk2410/lowlevel_init.S中定义的,主要实

现ram控制寄存器的初始化。函数结束时将保存在ip中的地址恢复到lr中然后让pc指向lr中的地址处(子程序返回)。

#endif /* CONFIG_SKIP_LOWLEVEL_INIT */

代码中的c0,c1,c7,c8都是ARM920T的协处理器CP15的寄存器。其中c7是cache 控制寄存器,c8是TLB控制寄存器。关闭MMU是通过修改CP15的c1寄存器来实现的。下面是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: 关闭MM; 1:开启MMU

(6)RAM控制寄存器的初始化

_TEXT_BASE:

.word CONFIG_SYS_TEXT_BASE

.globl lowlevel_init

lowlevel_init:

ldr r0, =SMRDATA

ldr r1, _TEXT_BASE

sub r0, r0, r1

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

add r2, r0, #13*4

0:

ldr r3, [r0], #4

str r3, [r1], #4

cmp r2, r0

bne 0b

mov pc, lr

.ltorg

SMRDATA:

.word(0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)

+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28)) .word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4) +(B0_Tacp<<2)+(B0_PMC))

.word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4) +(B1_Tacp<<2)+(B1_PMC))

.word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4) +(B2_Tacp<<2)+(B2_PMC))

.word((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4) +(B3_Tacp<<2)+(B3_PMC))

.word((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4) +(B4_Tacp<<2)+(B4_PMC))

.word((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4) +(B5_Tacp<<2)+(B5_PMC))

.word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))

.word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))

.word((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT) .word 0x32

.word 0x30

.word 0x30

这段RAM控制寄存器配置程序在文件board/samsung/smdk2410/lowlevel_init.S中实现。关键字.ltorg定义了一个文字池,其中存储了RAM的13个寄存器对应的值。上面那段汇编代码便是将这文字池中的数据存入RAM对应的寄存器中。

1.4 硬件平台前期初始化

call_board_init_f:

ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)

bic sp, sp, #7 /* 8-byte alignment for ABI compliance */

ldr r0,=0x00000000

bl board_init_f

初始化栈指针为调用C程序做准备

(CONFIG_SYS_INIT_SP_ADDR在文件include/configs/smdk2410.h中定义)。

栈指针8字节对齐,r0中的值为函数board_init_f的参数。

函数board_init_f在文件arch/arm/lib/board.c中定义如下:

void board_init_f(ulong bootflag)

{

......

//记录启动到了哪一步。

bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_F, "board_init_f");

//gd_t是一个包含了很多全局数据的结构体,gd是一个指向这个全局数据结构体的指针,该指针是通过宏DECLARE_GLOBAL_DATA_PTR来定义的。在文件

arch/arm/include/asm/global_data.h中宏DECLARE_GLOBAL_DATA_PTR的定义如下:#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8")

指针gd存放在指定的寄存器r8中。这个声明可避免编译器把r8分配给其它的变量。

任何想要访问全局数据结构体的代码,只要代码开头加入

“DECLARE_GLOBAL_DATA_PTR”一行代码,

然后就可以使用gd指针来访问全局数据区了。

gd = (gd_t *) ((CONFIG_SYS_INIT_SP_ADDR) & ~0x07);

//下面一行内嵌汇编的作用是,告诉编译器内存被修改过了。

__asm__ __volatile__("": : :"memory");

memset((void *)gd, 0, sizeof(gd_t));

//gd->mon_len保存U-BOOT镜像的长度

gd->mon_len = _bss_end_ofs;

.....

//通过一个循环依次调用数组init_sequence中的各个函数,对平台做一些早期的初始化,后面将会做进一步讲解。

【1】for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {

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

hang ();

}

}

......

//CONFIG_SYS_SDRAM_BASE是内存在CPU地址空间中的起始位子在文件

include/configs/smdk2410.h中配置,gd->ram_size中保存了内存的大小,所以addr指向内存的最高地址处。

addr = CONFIG_SYS_SDRAM_BASE + gd->ram_size;

......

//如果使用了指令cache与数据cache就分配16K空间用于建立块表。

#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF)) /* reserve TLB table */

addr -= (4096 * 4);

/* round down to next 64 kB limit */

addr &= ~(0x10000 - 1);

gd->tlb_addr = addr;

debug("TLB table at: %08lx\n", addr);

#endif

addr &= ~(4096 - 1);

//如果配置了CONFIG_LCD就分配一块空间作为LCD数据缓存区

#ifdef CONFIG_LCD

#ifdef CONFIG_FB_ADDR

gd->fb_base = CONFIG_FB_ADDR;

#else

/* reserve memory for LCD display (always full pages) */

addr = lcd_setmem(addr);

gd->fb_base = addr;

#endif /* CONFIG_FB_ADDR */

#endif /* CONFIG_LCD */

//gd->mon_len保存着u-boot镜像大小,下面代码是分配一个区域用于保存u-boot镜像addr -= gd->mon_len;

addr &= ~(4096 - 1);

debug("Reserving %ldk for U-Boot at: %08lx\n", gd->mon_len >> 10, addr);

#ifndef CONFIG_SPL_BUILD

//分配堆区,TOTAL_MALLOC_LEN在的大小最终在include/configs/smdk2410.h中配置addr_sp = addr - TOTAL_MALLOC_LEN;

debug("Reserving %dk for malloc() at: %08lx\n",

TOTAL_MALLOC_LEN >> 10, addr_sp);

//结构体bd_t用于存储一些平台信息,可通过全局结构体的字段gd->bd来访问addr_sp -= sizeof (bd_t);

bd = (bd_t *) addr_sp;

gd->bd = bd;

......

//为全局结构体gd_t分配空间,上面只是将它保存在一个临时的位置,后面将会把那个临时的gd_t内容拷贝到现在分配的存储空间里。

addr_sp -= sizeof (gd_t);

id = (gd_t *) addr_sp;

//将IRQ栈顶地址保存到gd->irq_sp中

gd->irq_sp = addr_sp;

//分配IRQ和FIQ栈空间

#ifdef CONFIG_USE_IRQ

addr_sp -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ);

debug("Reserving %zu Bytes for IRQ stack at: %08lx\n",

CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ, addr_sp);

#endif

/* leave 3 words for abort-stack */

addr_sp -= 12;

/* 8-byte alignment for ABI compliance */

addr_sp &= ~0x07;

#else

addr_sp += 128; /* leave 32 words for abort-stack */

gd->irq_sp = addr_sp;

#endif

//上电自检相关代码

#ifdef CONFIG_POST

post_bootmode_init();

post_run(NULL, POST_ROM | post_bootmode_get(0));

#endif

//保存一些平台相关的信息,串口波特率,内存起始地址和大小。

gd->bd->bi_baudrate = gd->baudrate;

dram_init_banksize();

display_dram_config(); /* and display it */

//保存代码重定位的起始位置,用户栈的栈顶地址,代码重定位的偏移量。将全局数据//结构体从临时存放位置拷贝到上面分配的地址处。

gd->relocaddr = addr;

gd->start_addr_sp = addr_sp;

gd->reloc_off = addr - _TEXT_BASE;

debug("relocation Offset is: %08lx\n", gd->reloc_off);

memcpy(id, (void *)gd, sizeof(gd_t));

//调用函数relocate_code进行代码重定位。传入的参数为用户栈地址,全局数据结构体//地址,和代码重定位的起始地址。这三个参数分别保存在寄存器R0,R1,R2中。

//函数relocate_code用汇编实现,在文件arch/arm/cpu/arm920t/start.S中实现。

relocate_code(addr_sp, id, addr);

/* NOTREACHED - relocate_code() does not return */

}

/****************************************【1】***************************************/ 下面将对标号【1】处做进一步的分析

init_fnc_t *init_sequence[] = {

......

//配置mpllcon 和upllcon还有对IO口做初始化配置

#if defined(CONFIG_BOARD_EARLY_INIT_F)

board_early_init_f,

#endif

.....

//初始化平台时钟

timer_init, /* initialize timer */

//环境变量初始化。假设代码是从nand flash启动的,如果配置了ENV_IS_EMBEDDED //表明环境变量是嵌在U-BOOT镜像中的,代码就做一些crc检查。实际上一般不做这//项配置,所以函数env_init要做的就是将gd->env_addr指向数组default_environment, //这个数组中保//存了一些常用的环境变量,比如,启动参数,串口波特率,IP地址等。//另外,函数还将标//识环境变量有效gd->env_valid = 1,这将在环境变量重定位函数//env_relocate中检测。

env_init, /* initialize environment */

//从环境变量中获取串口波特率。

init_baudrate, /* initialze baudrate settings */

//串口设备初始化,对于s3c2410来说最终将调用文件drivers/serial/serial_s3c24x0.c中函数serial_init_dev来做硬件初始化。

serial_init, /* serial communications setup */

//下面函数所做的主要工作就是gd->have_console = 1;表明支持控制台操作。如果配置了CONFIG_PRE_CONSOLE_BUFFER还将初始化控制台缓存。

console_init_f, /* stage 1 init of console */

//现在可以打印一些信息了。

display_banner, /* say that we are here */

......

//获取内存大小gd->ram_size = PHYS_SDRAM_1_SIZE,PHYS_SDRAM_1_SIZE在文件include/configs/smdk2410.h中配置。

dram_init, /* configure available RAM banks */

NULL,

};

/*************************************************************************************/ 1.5代码重定位

.globl relocate_code

relocate_code:

mov r4, r0 /* save addr_sp */

mov r5, r1 /* save addr of gd */

mov r6, r2 /* save addr of destination */

//代码重定位函数relocate_code在文件arch/arm/cpu/arm920t/start.S中以汇编形式实现,//它有三个参数,用户栈地址,全局数据结构体地址,和代码重定位的起始地址,分别保存在寄//存器R0,R1,R2中,在函数开头将这三个参数保存起来。

stack_setup:

mov sp, r4

adr r0, _start

cmp r0, r6

beq clear_bss /* skip relocation */

mov r1, r6 /* r1 <- scratch for copy_loop */

ldr r3, _bss_start_ofs

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

copy_loop:

ldmia r0!, {r9-r10} /* copy from source address [r0] */

stmia r1!, {r9-r10} /* copy to target address [r1] */

cmp r0, r2 /* until source end address [r2] */

blo copy_loop

//这段代码实现了将u-boot镜像搬移到内存中指定地址(r6中存储地址处)。首

//先判断u-boot是否已经重定位,通过将u-boot的入口_start与重定位地址(r6)进

//行比较,如果不相等就将u-boot镜像拷贝到r6指定地址处,

//否则直接跳到clear_bss处,因为此时u-boot引进重定位。

#ifndef CONFIG_SPL_BUILD

ldr r0, _TEXT_BASE /* r0 <- Text base */

sub r9, r6, r0 /* r9 <- relocation offset */

ldr r10, _dynsym_start_ofs /* r10 <- sym table ofs */

add r10, r10, r0 /* r10 <- sym table in FLASH */

ldr r2, _rel_dyn_start_ofs /* r2 <- rel dyn start ofs */

add r2, r2, r0 /* r2 <- rel dyn start in FLASH */

ldr r3, _rel_dyn_end_ofs /* r3 <- rel dyn end ofs */

add r3, r3, r0 /* r3 <- rel dyn end in FLASH */

fixloop:

ldr r0, [r2] /* r0 <- location to fix up, IN FLASH! */

add r0, r0, r9 /* r0 <- location to fix up in RAM */

ldr r1, [r2, #4]

and r7, r1, #0xff

cmp r7, #23 /* relative fixup? */

beq fixrel

cmp r7, #2 /* absolute fixup? */

beq fixabs

/* ignore unknown type of fixup */

b fixnext

fixabs:

/* absolute fix: set location to (offset) symbol value */ mov r1, r1, LSR #4 /* r1 <- symbol index in .dynsym */

add r1, r10, r1 /* r1 <- address of symbol in table */

ldr r1, [r1, #4] /* r1 <- symbol value */

add r1, r1, r9 /* r1 <- relocated sym addr */

b fixnext

fixrel:

/* relative fix: increase location by offset */ ldr r1, [r0]

add r1, r1, r9

fixnext:

str r1, [r0]

add r2, r2, #8 /* each rel.dyn entry is 8 bytes */

cmp r2, r3

blo fixloop

#endif

在链接文件/arch/arm/cpu/u-boot.lds中有两个段:.dynsym 动态符号表,.rel.dyn动态重定位表。上面程序的主要工作就是将.dynsym和.rel.dyn重定位,并遍历.rel.dyn,根据重定位表中的信息将符号表中的函数地址等进行重定位。

clear_bss:

#ifndef CONFIG_SPL_BUILD

ldr r0, _bss_start_ofs

ldr r1, _bss_end_ofs

mov r4, r6 /* reloc addr */

add r0, r0, r4

add r1, r1, r4

mov r2, #0x00000000 /* clear */

clbss_l:cmp r0, r1 /* clear loop... */

bhs clbss_e /* if reached end of bss, exit */

str r2, [r0]

add r0, r0, #4

b clbss_l

clbss_e:

bl coloured_LED_init

bl red_led_on

#endif

//找到BSS段的起始地址与结束地址,然后循环清零整个BSS段。

1.6 硬件平台后期初始化

ldr r0, _board_init_r_ofs

adr r1, _start

add lr, r0, r1

add lr, lr, r9

/* setup parameters for board_init_r */

mov r0, r5 /* gd_t */

mov r1, r6 /* dest_addr */

/* jump to it ... */

mov pc, lr

_board_init_r_ofs:

.word board_init_r - _start

首先找到函数board_init_r重定位后的位置,然后将全局数据结构体gd_t 和重定位目标地址存分别入r0和r1中,作为函数board_init_r的参数。跳到C函数board_init_r 处执行,该函数在文件/arch/arm/lib/board.c中实现,如下:

void board_init_r(gd_t *id, ulong dest_addr)

{

//让gd指向全局数据结构体。

gd = id;

gd->flags |= GD_FLG_RELOC; /* tell others: relocation done */

bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_R, "board_init_r");

//将u-boot二进制文件长度保存在monitor_flash_len中。

monitor_flash_len = _end_ofs;

//使能缓存功能

enable_caches();

//函数board_init主要做了下面几件事:将平台机器码保存在gd->bd->bi_arch_number //中;在gd->bd->bi_boot_params中设置传递给内核的参数的起始地址。使能指令cache //和数据cache。

board_init(); /* Setup chipselects */

......

//分配堆区存储空间,并将该区域清零。

malloc_start = dest_addr - TOTAL_MALLOC_LEN;

mem_malloc_init (malloc_start, TOTAL_MALLOC_LEN);

......

//配置可用的flash区

flash_size = flash_init();

.....

//初始化nandflash的控制寄存器,获取芯片的类型和相关参数,初始化一些结构体成员//建立起相关数据结构。

#if defined(CONFIG_CMD_NAND)

puts("NAND: ");

nand_init(); /* go init the NAND */

#endif

.....

//环境变量重定位。在函数env_relocate中首先检测gd->env_valid,在之前的函数env_init //中已经将它置1,所以函数将会把保存在nandflash(假设环境变量保存在nandflash中)//中的环境变量读入内存中然后加入哈希表中。

env_relocate();

......

//在函数stdio_init中将函数I2C,LCD,KEYBOARD等设备封装成设备stdio_dev,然后将//其注册到链表devs上。

stdio_init(); /* get the devices list going. */

//初始化u-boot的应用函数集

jumptable_init();

.....

//函数console_init_r中,首先尝试从环境变量中获取标准输入、标准输出、标准错误输//出的设备名,然后到设备链表devs中区搜索同名的设备,如果没有找到就到devs中找//名为"serial"的设备,最后将找到的设备存入stdio_devices数组中。

console_init_r(); /* fully init console as a device */

......

//在文件/arch/arm/cpu/arm920t/start.S中定义了三个全局变量:

//IRQ_STACK_START,IRQ_STACK_START_IN和FIQ_STACK_START,

//下面函数就是对这三个变量赋值。

interrupt_init();

/* enable exceptions */

//能使IRQ中断

enable_interrupts();

......

//从环境变量中获取内核镜像的加载地址

load_addr = getenv_ulong("loadaddr", 16, load_addr);

.....

//网卡接口控制器的初始化

#if defined(CONFIG_CMD_NET)

puts("Net: ");

eth_initialize(gd->bd);

#endif

/上电自检程序

#ifdef CONFIG_POST

post_run(NULL, POST_RAM | post_bootmode_get(0));

#endif

......

//进入命令循环函数

for (;;) {

main_loop();

}

}

//函数main_loop在文件/common/main.c中实现,该函数中如果配置了系统启动命令,//则直接启动系统,否则进入U-BOOT命令行等待用户输入u-boot命令。

void main_loop (void)

{

......

//记录启动次数,获取启动次数的最大限制

#ifdef CONFIG_BOOTCOUNT_LIMIT

bootcount = bootcount_load();

bootcount++;

bootcount_store (bootcount);

sprintf (bcs_set, "%lu", bootcount);

setenv ("bootcount", bcs_set);

bcs = getenv ("bootlimit");

bootlimit = bcs ? simple_strtoul (bcs, NULL, 10) : 0;

#endif /* CONFIG_BOOTCOUNT_LIMIT */

......

//如果配置了延时启动则从环境变量中获取延时的秒数

#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) s = getenv ("bootdelay");

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 移植步骤详解 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 独立于处理器体系结构的通用代码,如内存大小探测与故障检测;

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

uboot2013.07lds分析

uboot 2013.07 lds 分析 转载自: uboot 2013.07 lds 分 析 .OUTPUT_FORMAT("elf32-littlearm", "elf32- littlearm", //指定输出可执行文件是 elf 格式 ,32 位 ARM 指令 ,小端 OUTPUT_ARCH(arm) //指定输出可执行 文件的平台为 ARMENTRY(_start) // 指定函数入口点为 _start 。 cpu/arm920t/start.S 0x00000000; // 指定可执行 image 文件的全局入口点,通常 这个地址都放在 ROM(flash)0x0 位置。必须使编译器知道这 以4 字节对齐 .text : //代码段 00000000 T __image_copy_start 见 __image_copy_start 等同于 _start CPUDIR/start.o (.text*) // 代码段的第一个代码部分 ALIGN(4); .rodata : "elf32-littlearm") 中定义 SECTIONS{ 个地址,通常都是修改此处来完成 . = ALIGN(4); // 代码 *(.__image_copy_start) // 在 System.map 匚=f 00000000 T _start, *(.text*) //其它代码部分

{ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } 对应原来的 U_BOOT_CMD 对于那个的段 . KEEP(*(SORT(.u_boot_list*))); * 在 System.map 中 0006f52c D _u_boot_list_2_env_clbk_2_flags 0006f534 D _u_boot_list_2_env_clbk_2_loadaddr 0006f53c B __bss_base 0006f53c B __bss_start 0006f53c B monitor_flash_len 0006f53c D __image_copy_end 0006f53c D __rel_dyn_start //指定只读数据段 . = ALIGN(4); .data : { // 指定读 / 写数据段 *(.data*) ALIGN(4); . = ALIGN(4); .u_boot_list : { // } . = ALIGN(4);/*

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源码分析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.doczj.com/doc/fc6720724.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版本文件结构

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

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、不简单的头文件包含

xilinx uboot网卡驱动分析和一些概念扫盲

xilinx uboot网卡驱动分析和一些概念扫盲 1、MAC控制器、网卡、PHY、MDIO、mii、gmii、rgmii概念扫盲 网卡在功能上包含OSI模型的两个层,数据链路层和物理层。物理层定义了数据传送与接收所需要的电与光信号、线路状态、时钟基准、数据编码和电路等,并向数据链路层设备提供标准接口。数据链路层则提供寻址机构、数据帧的构建、数据差错检查、传送控制、向网络层提供标准的数据接口等功能。网卡中负责数据链路的芯片叫做MAC控制器,负责物理层的芯片叫做PHY。所以,一个网卡由MAC控制器和PHY组成。 MAC控制器与PHY连接使用MII(Medium independent interface)媒体独立接口,这个接口是IEEE-802.3定义的以太网行业标准定义的接口,包括一个数据接口和一个MAC和PHY之间的管理接口即MDIO。MII标准接口用于连接MAC和PHY,媒体独立表示不对MAC硬件重新设计或替换的情况下,任何类型的PHY设备接到当前MAC控制器上都可以正常工作。 MII支持10M和100M的网络速率,由于网卡的速率不同,所以在其他速率下工作的与MII等效的接口有:AUI(10M以太网)、GMII(Gigabit以太网)和XAUI(10-Gigabit 以太网)。此外还有RMII、RGMII、SMII、SGMII等。所有这些接口都是由MII而来。MII支持10兆和100兆的操作,一个接口由14根线组成。RMII是简化的MII接口,在数据的收发上它比MII接口少了一倍的信号线。SMII是由思科提出的一种媒体接口,它有比RMII更少的信号线数目,S表示串行的意思。因为它只用一根信号线传送发送数据,一根信号线传输接受数据,所以在时钟上为了满足100的需求,它的时钟频率很高,达到了125兆,为什么用125兆,是因为数据线里面会传送一些控制信息。GMII采用8位接口数据,工作时钟125MHz,因此传输速率可达1000Mbps。同时兼容MII所规定的10/100 Mbps工作方式。RGMII又是GMII接口的精简版。SGMII又是GMII的串行版。 MAC控制器和PHY除了数据传输的交流外,MAC和PHY控制信息的交流通过MDIO(管理数据输入输出)接口来完成。具体MAC控制器进行PHY检测、MAC控制器回去PHY 当前状态、MAC控制器控制PHY速率等操作就通过MDIO来完成。

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移植实验

一、移植环境 ?主机:UBUNTU ?开发板:飞凌2440 ?编译器:arm-linux-gcc-4.3.2.tgz ?u-boot:u-boot-2009.03.tar.bz2

3)修改u-boot根目录下的Makefile文件。查找到smdk2410_config的地方,在他下面按照smdk2410_config的格式建立mini2440_config的编译选项,另外还要指定交叉编译器 4)测试编译新建的mini2440开发板项目

到此为止,u-boot对自己的mini2440开发板还没有任何用处,以上的移植只是搭建了一个mini2440开发板u-boot的框架,要使其功能实现,还要根据mini2440开发板的具体资源情况来对u-boot源码进行修改。 3. 根据u-boot启动流程图的步骤来分析或者修改添加u-boot源码,使之适合mini2440开发板(注:修改或添加的地方都用红色表示)。 1)mini2440开发板u-boot的stage1入口点分析。 一般在嵌入式系统软件开发中,在所有源码文件编译完成之后,链接器要读取一个链接分配文件,在该文件中定义了程序的入口点,代码段、数据段等分配情况等。那么我们的my2440开发板u-boot的这个链接文件就是cpu/arm920t/u-boot.lds,打开该文件部分代码如下:

知道了程序的入口点是_start,那么我们就打开mini2440开发板u-boot第一个要运行的程序cpu/arm920t/start.S(即u-boot的stage1部分),查找到_start的位置如下: 从这个汇编代码可以看到程序又跳转到start_code处开始执行,那么再查找到start_code 处的代码如下:

关于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_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的工作循环),接受用户从串口输入的命令,然后进行相应的工作。

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详细解读

大多数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的工作循环),接受用户从串口输入的命令,然后进行相应的工作。 3、U-Boot的启动顺序(示例,其他u-boot版本类似) cpu/arm920t/start.S @文件包含处理 #include @由顶层的mkconfig生成,其中只包含了一个文件:configs/<顶层makefile中6个参数的第1个参数>.h #include #include

相关主题
文本预览
相关文档 最新文档