您的位置:首页 > 其它

基于s3c2410的uboot1.2.0的分析以及移植

2016-08-26 14:46 393 查看


基于s3c2410的uboot1.2.0的分析以及移植

工作环境:

uboot1.2.0

Ubuntu8.10

cross_compile3.3.2

1 绪论

描述当前嵌入式产品的发展现状;

描述sangsun公司的产品,简单介绍s3c2410,以及板载配置。

2 bootloader的介绍,不同种类优劣性比较

3 论文出发点:目前的论文主要是针对Uboot的编译与移植,侧重点在如何配置适合自己开发板的参数,并将它移植到开发板。但并没有对uboot的工作流程进行清晰的分析,如果能够从本质上掌握整个uboot的工作原理,开发嵌入式产品时的周期也将缩短。因此对uboot的分析是必要的。

4 uboot目录结构。u-boot的源码顶层目录说明

目 录 特 性 解 释 说 明

board 平台依赖 存放电路板相关的目录文件,

例如:RPXlite(mpc8xx)、

smdk2410(arm920t)、

sc520_cdp(x86) 等目录

cpu 平台依赖 存放CPU相关的目录文件

例如:mpc8xx、ppc4xx、

arm720t、arm920t、 xscale、i386等目录

lib_ppc 平台依赖 存放对PowerPC体系结构通用的文件,

主要用于实现PowerPC平台通用的函数

lib_arm 平台依赖 存放对ARM体系结构通用的文件,

主要用于实现ARM平台通用的函数

lib_i386 平台依赖 存放对X86体系结构通用的文件,

主要用于实现X86平台通用的函数

include 通用 头文件和开发板配置文件,

所有开发板的配置文件都在configs目录下

common 通用 通用的多功能函数实现

lib_generic 通用 通用库函数的实现

net  通用 存放网络的程序

fs  通用 存放文件系统的程序

post  通用 存放上电自检程序

drivers   通用 通用的设备驱动程序,主要有以太网接口的驱动

disk   通用 硬盘接口程序

rtc   通用 RTC的驱动程序

dtt   通用 数字温度测量器或者传感器的驱动

examples 应用例程 一些独立运行的应用程序的例子,例如helloworld

tools   工具 存放制作S-Record或者u-boot格式的映像等工具,

例如mkimage

doc   文档 开发使用文档

5 简单介绍一下makefile,开始着手于源码的Makefile分析。在整个uboot目录中,makefile可以分为三类,

(1)顶层makefile

(2)结构makefile

(3)子目录makefile

正式分析Makefile。makefile内容比较容易理解。

Uboot的makefile总共有50几页,但其中重要的内容折合起来也就十二三页。

6正式开始分析uboot源码。

根据/board/smdk2410目录下的u-boot.lds可知,函数入口处在/cpu/arm920t/start.S中的_start处,且从0x00000000地址处开始。

因此首先应该分析start.S文件,这是第一个执行的汇编文件,非常的重要。

(1) cpu/arm920t/start.S

uboot启动也分stage1和stage2两个阶段。Uboot加载流程。2410上电,nandflash前4kb的内容以硬件的方式被拷贝到SRAM中,SRAM是cpu核中与nandflash配合的芯片从而实现nandflash的自启动系统。在SRAM中的部分uboot代码执行并在第2阶段执行之前,将nandflash中的uboot的全部代码拷贝到SDRAM中运行。然后引导内核与文件系统。

由上可以看出,这4kb以内代码必须要能够完成一些初始化工作。其实这就是我们平时所说的Uboot运行两阶段中的第一阶段。这部分短小的代码用汇编语言编写而成,也就是我们的start.S了。下面是总结的一张流程图

.globl _start



1
_start: b reset 运行以后,先跳转到reset标签处

。。。。。。

reset:

从reset主要完成以下的功能。

首先切换到svc超级用户模式。在系统复位和软件中断时可以进入这种模式。

关闭看门狗。看门狗可以用作16位的定时器来请求中断服务。并在固定时钟内产生复位信号所以要关闭。

屏蔽所有的中断。通过设置INTMSK,INTSUBMSK寄存器来实现。

设置时钟。2410的时钟一般采用默认的,不用另外设置。

3
#ifndef CONFIG_SKIP_LOWLEVEL_INIT 跳转到cpu_init_crit处

bl
cpu_init_crit

#endif 接下来跳转到cpu_init_crit处。Bl指令是带返回的。PC值将指向下一条指令。

cpu_init_crit:从注释中可以了解到。它主要来设置一些重要的寄存器和内存时钟的设置。

MCR.MRC指令统称为协处理器寄存器传送指令。

MCR{cond} coproc,opcode1,Rd,CRn,CRm,{,opcode2}

Coproc:指令操作的协处理器名。标准名为pn,n为0~15

mcr p15, 0, r0, c7, c7, 0 例如这条指令就是将寄存器r0中的值送到协处理器p15中c7中去。

mrc即是将协处理中的寄存器的内容送到外部的寄存器中。

在重定位之前,我们必须设置内存时序,因为内存时钟是依赖于开发版的。在lowlevel_init.S文件里可以得到解释。lowlevel_init.S主要定义了各Bank的内钟等等

之后mov
ip, lr //保存当前的lr。即是当前的pc值,因为再下一条指令又要进行跳转了。。

bl
lowlevel_init//同样,这是条带返回的跳转。指向下一条指令。

mov lr, ip

mov pc, lr

因为lowevel_init被声明为.globl,可以全局使用,虽然不在start.S文件中定义。因此可以直接跳转到/board/smdk2410/lowlevel.S中来执行这个命令了。

它主要完成内存控制的配置,设置当前的PC为nandflash的起始位置。

下面是Lowlevel_init中的部分代码

BWSCON:BUS
WIDTH&WAIT CONTROL REGISTER 0x48000000

可以来选择哪个BANK

ldr
r0, =SMRDATA //SMRDATA的地址传到r0中。

ldr
r1, _TEXT_BASE //通过将_TEXT_BASE中的值加载到r1中

sub r0, r0, r1 //r0=r0-r1??

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

add
r2, r0, #13*4//SMRDATA共13条指令。

0:

ldr
r3, [r0], #4//将SMDDATA中的值循环。主要是涉及了BAND0~7的时钟啊,内存刷新什么的

str r3, [r1], #4

cmp r2, r0

bne 0b

/* everything is fine now */

mov
pc, lr//返回到cpu_init_crit

这样返回到了cup_init_crit中,

.....

mov
ip,lr //ip中保存了reset中调用cpu_init_crit的下一条指令地址

bl lowlevel_init

mov
lr, ip //Lowlevel_init返回后,执行这条指令。将ip传给lr

mov
pc, l //再传给pc,这样就回到了reset的下一条指令处

#endif /* CONFIG_SKIP_LOWLEVEL_INIT */

返回到reset处吧~~#endif等着我们,到这里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

定义各种异常模式。每种异常模式都有对应的pc来存储异常指令地址。接着继续执行这条指令以后的汇编代码,具体还是要结合start.S源码看的。

另外在/board/smdk2410/config,mk目录下存储着这样的信息。

# SMDK2410 has 1 bank of 64 MB DRAM

#

# 3000'0000 to 3400'0000

#

# Linux-Kernel is expected to be at 3000'8000, entry 3000'8000

# optionally with a ramdisk at 3080'0000

#

# we load ourself to 33F8'0000

#

# download area is 3300'0000

#

TEXT_BASE = 0x33F80000

定义了TEXT_BASE的地址。另外UBOOT_RAM_BASE
_armboot_start 都是这个地址

Start.S继续向下执行,到达relocate代码段

relocate那段代码只针对从norflash中启动的设备有效,可要可不要,因此要是设备支持从nandflash启动,需要添加能将uboot拷贝到RAM中的代码。start.S本身是在SRAM中运行的,添加的这部分拷贝代码就是用来将剩余的内容全部拷贝到RAM中去了。

我们这里只是分析阶段。具体怎么在这里添加拷贝代码,参考第二部分 正式移植

在添加的拷贝代码中,执行了一条跳转到nand_read_ll的指令。此函数在board/smdk2410/nand_read,c中定义了。但是uboot的源码包中没有这个函数,我们可以从vivi中获取这个函数~通过这个函数来将uboot读取到RAM中。

执行完这个函数以后,接着从copy_myself返回!!!检验一下是否将uboot已全部读取到TEXT_BASE中,如果成功,则继续执行下一条关键指令!!

即ldr
pc,_start_armboot 将这个函数的地址值赋给PC,直接实现跳转!

_start_armboot: .word start_armboot !

开始跳转到/lib_arm/board.c中定义的start_armboot函数中执行了。到现在为止就是第2阶段正式开始了。Start.S文件分析也到此结束!!

2board.c也非常重要,并且start_armboot()函数定义lib_arm/board.c文件中。

board.c是个非常重要的文件。包括了CS8900网卡驱动函数的声明、内存函数初始化的函数mem_malloc_init、nandflash初始化、波特率初始化函数、输出一些硬件信息....start_armboot本身主要完成网络的设置等,并最终进入到main_loop()函数。即循环等待。下面先介绍几个重要的数据结构。

1初始化函数序列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/env_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,

};

2 全局数据结构

typedef
struct global_data {全局数据

bd_t *bd; //板子数据指针

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

unsigned long baudrate;//波特率定义

unsigned long have_console; /* serial_init() was called 串口初始化*/

unsigned long reloc_off; /* Relocation Offset */

unsigned long env_addr; /* Address of Environment struct 环境参数地址*/

unsigned long env_valid; /* Checksum of Environment valid? 环境参数CRC检验有效标志*/

unsigned long fb_base; /* base address of frame buffer 帧地址*/

#ifdef CONFIG_VFD

unsigned char vfd_type; /* display type */

#endif

#if 0

unsigned
long cpu_clk; /* CPU clock in Hz! */

unsigned long bus_clk;

unsigned long ram_size; /* RAM size */

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

#endif

void **jt; /* jump table */

} gd_t; include/asm-arm/Global_data.h中定义。全局数据变量指针,它保存了U-boot运行时需要的全局数据。

3 开发板数据结构

typedef struct bd_info {

int bi_baudrate; /* serial console baudrate */

unsigned long bi_ip_addr; /* IP Address */

unsigned char bi_enetaddr[6]; /* Ethernet adress即网卡地址 */

struct environment_s *bi_env;

ulong bi_arch_number; /* unique id for this board */

ulong bi_boot_params; /* where this board expects params启动参数 */

struct /* RAM configuration */

{

ulong start;

ulong size;

} bi_dram[CONFIG_NR_DRAM_BANKS];

#ifdef CONFIG_HAS_ETH1

/* second onboard ethernet port */

unsigned char bi_enet1addr[6];

#endif

} bd_t; include/asm-arm/u-boot.h中定义。描述开发板的数据结构。

4
voidstart_armboot (void)
函数分析

{

//全局数据变量指针gd占用r8。

DECLARE_GLOBAL_DATA_PTR;

/* 给全局数据变量gd安排空间*/

gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));

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

/* 给板子数据变量gd->bd安排空间*/

gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));

memset (gd->bd, 0, sizeof (bd_t));

monitor_flash_len = _bss_start - _armboot_start;//取u-boot的长度。

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

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

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

hang ();

}

}

/*配置可用的Flash
*/

size = flash_init ();

 ……

/* 初始化堆空间 */

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-arm.h中定义了这个变量。

extern ulong _armboot_start; /* code start */

extern ulong _bss_start; /* code + data end == BSS start */

extern ulong _bss_end; /* BSS end */

extern ulong IRQ_STACK_START; /* top of IRQ stack */

extern ulong FIQ_STACK_START; /* top of FIQ stack */

分析完start_armboot函数后,下面再分析几个比较重要的文件。

1include/configs/smdk2410.h

主要是定义了一些宏。用来选择处理器,设置时钟,定义内存池的大小。设置网卡CS8900,还有串口与时钟的设置。

一些命令的定义。主要是CONFIG_COMMANDS宏中。看名称就能猜到是定义命令的意思了。包括CFG_CMD_CACHE命令等等,如果要设置nandflash启动,那么必须要使CFG_CMD_NAND、CFG_CMD_PING、CFG_CMD_NET三个选项有效。接下去的程序就定义了一些关于IP地址,网关的设置。以及关于内存起始地址CFG_MEMTEST_START,CFG_MEMTEST_END的定义。还有一些栈的设置。包含了许多宏地址的定义。因此这个文件很重要!!最后一些就包括了FLASH的环境设置。要进行修改。将SDRAM的起始地址0x30000000与flash的bank1
0x00000000 联系起来。下表是一些比较重要的宏定义。

表1

PHY_FLASH_1
0X00000000
CFG_FLASH_BASE
PHY_FLASH_1
CFG_PROMPT
“SMDK2410#” 开发板的用户名称
CFG_MEMTEST_START
0X30000000
CFG_MEMTEST_END
0X33F00000
CFG_LOAD_ADDR
0X33000000默认的加载地址
PHYS_SDRAM_1
OX30000000 SDRAM bank1
PHYS_SDRAM_1_SIZE
0X04000000
CFG_ENV_IS_IN_FLASH
1
CFG_ENV_SIZE
0X10000 64K
这个文件的主要功能就分析完了。我对源码做了比较好的分析,这里就不一一列举了。利用source insight进行查看。

2/include/Cmd_confdefs.h 这个文件包含了全部命令的宏定义,好像是定义宏的地址~~~~在smdk2410.h定义部分命令后,则必须将这个头文件include 进来。

3/include/s3c2410.h/include/s3c24x0.h

首先先分析s3c24x0.h文件。这个文件中定义了所有的硬件资源寄存器。包括内存控制,USB控制,中断、DMA等等。主要是通过这些结构体定义的对象与s3c2410.h中定义的SFR基地址结合,定义这个某个寄存器有哪些状态寄存器。

该文件中。主要定义了特殊寄存的基地址。SFR的范围0x48000000~0x5A000000

如s3c24x0.h中的部分内容

typedef struct {

S3C24X0_REG32 BWSCON;

S3C24X0_REG32 BANKCON[8];

S3C24X0_REG32 REFRESH;

S3C24X0_REG32 BANKSIZE;

S3C24X0_REG32 MRSRB6;

S3C24X0_REG32 MRSRB7;

} /*__attribute__((__packed__))*/ S3C24X0_MEMCTL

定义一个s3c24x0_MEMCTL对象,这个结构体中都是内存的相关寄存器。

下面是s3c2410.h中的部分代码。利用24x0中的对象来获取基地址。两者结合~

static inline S3C24X0_MEMCTL * const S3C24X0_GetBase_MEMCTL(void)

{

return (S3C24X0_MEMCTL * const)S3C24X0_MEMCTL_BASE;

先定义S3C24X0_MEMCTL结构体对象,
再在s3c2410.h中定义一个const函数,表示这个函数的返回值是不变的。

(4)/include/common.h、 /common/cmd_nand.c、 /common/command.c
common目录下包括一些通用的函数、如网络、硬盘、串口、nandflash等等.

这个文件主要定义了uboot的所有命令的形式。

#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help)
\cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage, help}每个命令就是一个cmd_tbl_t的对象。即每个命令都有一个结构体来描述。包括命令名字、参数的最大个数、重复数、命令执行函数、用法、帮助。从控制台中输入的命令是又command.c完成的,而find_cmd函数用来匹配具体的某个命令。

7内存分布情况从高到低分配。

对于smdk2410,RAM范围从0x30000000~0x34000000.
u-boot
占用高端内存区的1M大小。从前面的分析可知内存分配大致如下:



内存图的分析:在start.S中

gd和bd共占128个字节的大小。在给malloc区和bd数据结构分配后,如果定义了IRQ,则给栈分配IRQ+FIQ占8K大小的区。CONFIG_STACKSIZE_IRQ=4K。如果没有定义,则至少保存12个字节。在smdk2410.h有定义。从0x33f0000到0x34000000的1M地址,是留给uboot使用的。下面是从代码中总结出的信息,不知道对不对。需要进一步验证。DW_STACK_START,建立堆栈,栈起点0x33f00000,大小为0x8000
32K大小的栈?UBOOT_RAM_BASE 与_TEXT_BASE相同0x33f80000
_arm_boot_start也为0x33f80000.uboot源码分析暂到此结束。其实还是有许多不明白的地方。以后发现什么新的了再添加吧
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: