u-boot 启动过程 —— 基于S3C2410

程序员通勤双肩包,下单送全年 CSDN 会员 防泼水面料电脑包,保护笔记本电脑,背负轻便,下单再赠 Coding Plan,看技术干货、查文档、下载源码,一站式搞定学习需求 立即抢购

本文以流行的Samsung公司的S3C2410,openmoko平台和u-boot-1.3.2(2008.5 发布)为例,介绍如何在ZIX嵌入式开发环境下探索u-boot启动过程。

虽然u-boot已经广泛应用,由于其相对的复杂性使用户在了解其内部机理和进行u-boot的移植工作时还是会碰到困难。u-boot已有一些分析文档,但多数和真正的代码不能同步或者版本老旧,难以将概念和现实的代码匹配——即硬件板上跑的代码在文档资料中却看不到,更无法紧密的跟踪。本文涉及的代码基于在s3c2410硬件运行的成熟u-boot-1.3.2代码,版本较新,提供的特性非常丰富,而且在forum.linuxbj.com可以自由浏览下载。此u-boot代表了业界的较高水平,可以直接构建新版的嵌入式产品设计,有较高的应用价值。

u-boot总的启动流程如下
->reset
-> 设置CPU模式
-> 关闭看门狗/中断
-> 设置处理器时钟/片上总线
-> 初始化调试串口
-> MMU/外部总线/SDRAM等初始化
-> rom代码/数据搬移到ram
-> 初始化函数调用栈
-> 初始化外围设备/参数
-> 启动完毕,进入main_loop循环

嵌入式系统离不开bootloader初始化硬件以及引导操作系统。
现在,专用的嵌入式板子运行嵌入式Linux系统已经变得非常流行,u-boot是一种非常适合此类系统的bootloader。

u-boot主要提供以下功能:

  • 设置目标板硬件参数并初始化;
  • 为操作系统传递必要信息;
  • 执行交互式的底层操作;
  • 智能化装载操作系统;
  • 引导和运行的固件程序;
  • 支持大容量存储和USB接口

 

利用ZIX开发环境,能够通过比较直观的方式观察u-boot内部,而且可以将代码调试和分析同时进行,是一种了解、移植u-boot的强大工具。

使用arm工具链编译u-boot源代码,得到可以烧录的u-boot.bin文件。
在ZIX开发环境里,可以将u-boot.bin载入s3c2410板运行,并利用gdb调试。

gdb能通过JTAG接口访问硬件,也可以通过TCP/IP访问虚拟硬件。 建立好调试连接,即可通过gdb操纵u-boot启动过程,下面可以跟随代码的执行顺序,了解从上点开始,究竟哪些操作被执行。

s3c2410复位之后,pc指针会指向0x0地址。在u-boot代码中,该0x0地址是一个向量表,
第一条指令跳转branch到复位代码start_code。 位于cpu/arm920t/start.S汇编语言文件第53行:

.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 ldr pc, _fiq

复位指令跳转之后来到第154行,开始执行arm920t处理器的基本初始化。
首先修改当前程序状态寄存器CPSR,使处理器进入Supervisor|32 bit ARM模式,
并关闭ARM9TDMI中断和快速中断,这是通过设置CPSR相应掩码实现的:

start_code:
/*
* set the cpu to SVC32 mode
*/
mrs r0,cpsr
bic r0,r0,#0x1f
orr r0,r0,#0xd3
msr cpsr,r0

紧接着,将S3C2410特有的WTCON寄存器清零,此举仅为关闭看门狗,代码位置是234行

ldr r0, =pWTCON
mov r1, #0x0
str r1, [r0]

然后在241行,将S3C2410中断控制器INTMSK寄存器置为全1,
INTSUBMSK置为0x7ff,禁止全部中断源。S3C2410手册358页起对此有详细描述:

mov r1, #0xffffffff
ldr r0, =INTMSK
str r1, [r0]
# if defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442) || /
defined(CONFIG_S3C2443)
ldr r1, =INTSUBMSK_val
ldr r0, =INTSUBMSK
str r1, [r0]
# endif

接下来在259行,访问arm920t控制寄存器CP15,并置位最高两位[31,30]。
此两位置为0b11后,处理器时钟被设置为异步模式,允许处理器异步访问总线:

mrc p15, 0, r1, c1, c0, 0
orr r1, r1, #0xc0000000
mcr p15, 0, r1, c1, c0, 0

至此arm920t相关的配置完成,后面开始设定S3C2410时钟合成参数。
通过设置UPLL,MPLL和CLKDIVN三个寄存器(在S3C2410手册237页起讲述),
得到需要的处理器工作频率,分别在308行

ldr r0, =UPLLCON
ldr r1, =UPLLCON_val
str r1, [r0]

321行

ldr r1, =MPLLCON_val
str r1, [r0, #-4] /* MPLLCON */

/* FCLK:HCLK:PCLK = 1:2:4 */
ldr r0, =CLKDIVN
mov r1, #CLKDIVN_val
str r1, [r0]

S3C2410的UART0得到初始化,以便于尽早通过UART0打印信息。
此段代码从332行开始,其中涉及到的寄存器读者可参考S3C2410手册293页起:

/* enable uart */
ldr r0, =0x4c00000c /* clkcon */
ldr r1, =0x7fff0 /* all clocks on */
str r1, [r0]
/* gpio UART0 init */
ldr r0, =0x56000070
mov r1, #0xaa
str r1, [r0]
/* init uart */
ldr r0, =0x50000000
mov r1, #0x03
str r1, [r0]
ldr r1, =0x245
str r1, [r0, #0x04]
mov r1, #0x01
str r1, [r0, #0x08]
mov r1, #0x00
str r1, [r0, #0x0c]
mov r1, #0x1a
str r1, [r0, #0x28]

完成UART0设置之后,根据不同的编译时选项和运行时参数,代码会在360行进入相应的分支,分别是

  1. 从nand启动,代码执行lowlevel_init,主要是清除cpu cache,以及关闭mmu和i-cache,
    并且根据板极硬件配置初始化外部存储器总线和GPIO,最后把代码从nand flash中拷贝到ram中并继续执行。
  2. 从nor启动,与第1种情况相比,仅仅把代码拷贝部分简化,将DATA段从flash中拷贝到ram中,其余相同
  3. 从ram启动,因为u-boot已经处于配置好的ram中,
    所以会跳过所有cache,mmu,sdram,nand和nor相关代码,跳转到done_relocate执行

下面以最复杂的nand启动情况为例分析。首先会跳转到572行执行cpu_init_crit,
通过操作CP15完成flush处理器arm920t的cache和tlb,并关闭mmu和i-cache:

cpu_init_crit:
/*
* flush v4 I/D caches
*/
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

然后跳转到board/neo1973/common/lowlevel_init.S文件的139行执行,
进行总线数据宽度、时序、SDRAM控制、GPIO等配置,配置完毕后会返回start.S继续执行。
因为该代码是与板相关,故放在board目录里面。由于代码较多,只粘贴开始部分:

/* memory control configuration */
/* make r0 relative the current location so that it */
/* reads SMRDATA out of FLASH rather than memory ! */
adr r0, SMRDATA
ldr r1, =BWSCON /* Bus Width Status Controller */
add r2, r0, #13*4

完成板级设置后,在cpu/arm920t/start.S的373行判断代码自身的执行位置。如果从stepping stone内执行,
并且u-boot配置为nand boot模式,则跳转到nand_load拷贝代码:

ldr r1, =BWSCON /* Z = CPU booted from NAND */
ldr r1, [r1]
tst r1, #6 /* BWSCON[2:1] = OM[1:0] */
teqeq r0, #0 /* Z &= running at address 0 */
beq nand_load

417行是nand_load代码,首先会跳转到614行执行may_resume
以检测系统是从待机模式唤醒还是上电启动。如果唤醒,则会根据之前保存的现场进行相应处理,
本文不做更多叙述;如果是启动,则会返回nand_load继续执行。在nand_load里初始化s3c2410的nand controller,
涉及存储器映射和寄存器NFCONF等,参见S3C2410手册215页起。同样,仅粘贴开始部分的代码: 

mov r1, #S3C2410_NAND_BASE
ldr r2, =0xf842 @ initial value enable tacls=3,rph0=6,rph1=0
str r2, [r1, #oNFCONF]
ldr r2, [r1, #oNFCONF]
bic r2, r2, #0x800 @ enable chip

451行继续根据配置设定栈指针,为后面调用C函数执行拷贝作准备:

ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
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 /* leave 3 words for abort-stack */

然后在460行,将SDRAM中的目标地址存入r0,0x0地址存入r1,u-boot长度存入r2,
跳入cpu/arm920t/s3c24x0/nand_read.c文件第154行执行nand_read_ll函数,该函数接受前面3个寄存器中的值作为参数,并将返回值放回r0:

ldr r0, _TEXT_BASE
mov r1, #0x0
mov r2, #CFG_UBOOT_SIZE
bl nand_read_ll

在nand_read_ll函数中实现了nand flash访问代码,并且支持自动跳过坏块的特性,函数循环执行nand页面读取并存入SDRAM,直到u-boot全部拷贝完,并返回0,该C代码留给读者自己阅读。nand_read_ll返回0后,会跳转到ok_nand_read,并482行对拷贝的头4K字节进行校验:

@ verify
mov r0, #0
@ldr r1, =0x33f00000
ldr r1, _TEXT_BASE
mov r2, #0x400 @ 4 bytes * 1024 = 4K-bytes
go_next:
ldr r3, [r0], #4
ldr r4, [r1], #4
teq r3, r4
bne notmatch
subs r2, r2, #4
beq done_nand_read
bne go_next

校验通过后代码506行,在地址为_booted_from_nand的SDRAM位置保存1,以便告诉上层软件本次启动是从nand引导:

done_nand_read:
ldr r0, _booted_from_nand
mov r1, #1
strb r1, [r0]

然后在518行,将中断向量表拷贝到0x0: 

mov r0, #0
ldr r1, _TEXT_BASE
mov r2, #0x40
irqvec_cpy_next:
ldr r3, [r1], #4
str r3, [r0], #4
subs r2, r2, #4
bne irqvec_cpy_next

532行,设置栈指针: 

ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
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 /* leave 3 words for abort-stack */

541行,清除bss段并跳转到真正的C函数start_armboot,进入更高级的硬件初始化代码,汇编初始化部分也全部完成使命: 

ldr r0, _bss_start /* find start of bss segment */
ldr r1, _bss_end /* stop here */
mov r2, #0x00000000 /* clear */
clbss_l:
str r2, [r0] /* clear loop... */
add r0, r0, #4
cmp r0, r1
ble clbss_l
ldr pc, _start_armboot

start_armboot函数位于lib_arm/board.c文件第277行,首先初始化globel_data类型的变量gd。该变量是一个结构,其成员大多是板子的一些基本设置,如序列号、ip地址、mac地址等(欲知结构的原型可参考include/asm-arm/globel_data.h和include/asm-arm/u-boot.h): 

gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
/* compiler optimization barrier needed for GCC >= 3.4 */
__asm__ __volatile__("": : :"memory");

memset ((void*)gd, 0, sizeof (gd_t));
gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
memset (gd->bd, 0, sizeof (bd_t));

然后在一个for循环中从init_sequence地址开始,逐个调用初始化C函数至NULL为止。这些routine函数按调用顺序分别是

  1. cpu_init() ——在common/main.c文件,执行初始化中断栈操作
  2. board_init() ——在board/neo1973/gta01/gta01.c文件中,执行板级初始化,主要是更新GPIO和PLL设置
  3. interrupt_init() ——在/cpu/arm920t/s3c24x0/interrupts.c文件中,执行时钟中断初始化
  4. env_init() ——在common/env_nand.c文件中,设置缺省环境变量
  5. init_baudrate() ——在lib_arm/board.c文件中,将环境变量中的baudrate存入bd_info结构bd
  6. serial_init() ——在common/serial.c文件中,调用驱动中真正的init()初始化串口
  7. console_init_f() ——在common/console.c文件中,更新global_data结构gd的have_console标记为1
  8. display_banner() ——在lib_arm/board.c文件中,打印u-boot banner,输出版本、运行地址等信息。比如在控制台看到的
  9. init_func_i2c() ——在lib_arm/board.c文件中,初始化i2c总线
  10. dram_init() ——在board/neo1973/gta01/gta01.c文件中,填充bd->bi_dram[0]的start和size成员,用来描述u-boot可用的ram
  11. display_dram_config() ——在board/neo1973/gta01/gta01.c文件中,打印当前ram配置。在控制台能够看到相应的 DRAM:  128 MB

利用gdb可以清晰的看到调用过程:

for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}

接着是一些可选外设的初始化,如显示屏、nor、nand、dataflash、网卡等,此过程执行后全部初始化工作完成。下面仅粘贴nor代码:

#ifndef CFG_NO_FLASH
/* configure available FLASH banks */
size = flash_init ();
display_flash_config (size);
#endif /* CFG_NO_FLASH */

之后在457行进入无限循环,调用common/main.c文件的278行main_loop()函数,u-boot完成启动过程。main_loop提供一个交互式命令行,可通过串口或usb控制台操作,也可以进一步引导操作系统:

for (;;) {
main_loop ();
}

 

U-boot下进行gdb 调试 1、编译选项设置 添加调试选项-g 保留调试信息,否则不能使用GDB进行调试。 例如,对test.c 文件进行调试编译 test.c : int main() { return 0; }; gcc test.c -o test -g 在 u-boot 中需要在Makefile 中打开 -g 编译选项 生成的debug 信息如下, 可以通过 readelf -S u-boot|grep debug 来查看。其中 .debug_xxxx 存放的就是调试信息, .rela.debug_xxxx 是记 阅读详情

相关推荐

uboot移植s3c2410详解

很详细的移植过程,一起人从头开始,包括uboot启动过程分析

U-boot启动流程分析(基于三星S3C2440)

U-boot启动流程分析

m0_62055248的博客 399

学习资料,uboot移植详解

uboot移植的详细介绍,按照此文档移植已经成功!

调试U-BOOT----让GDB更好地调试

     好久没有更新blog了。今天有空就上来更新吧。    最近又拿起u-boot来调,虽然说之前移植、调试成功,但是那个苦啊,GDB的光标跳来跳去,而且变量根本无法跟踪,只能靠猜,或者用串口output出来。考虑了一下,应该是编译的时候使用了优化选项,所以只要把GCC的优化选项去掉,或者选择不优化,就可以顺利进行调试了。不讲太多,动手吧!    在uboot根目录打开config.m

Ken Wu的专栏 4249

s3c2440_uboot移植(一)s3c2410的uboot源码分析

进行uboot移植之前,我们需要对uboot有一个较为详细的了解,详细可以看这篇文章:uboot启动流程分析_Bin Watson的博客-CSDN博客​ 同启动流程,s3c2410的uboot的源码内容和启动流程中的4410的uboot大同小异,现在我们需要深入细节进行分析。我们依然从start.S开始分析: 顺着start_code入口标号,我们一路往下可以看到,在上图中的start_code前部分代码进行的操作有:沿start_code继续往下追踪: 我们可以看到cpu_init_crit,在启动

Bin_Watson的博客 694

U-Boot启动过程完全分析

1.1       U-Boot工作过程   U-Boot启动内核的过程可以分为两个阶段,两个阶段的功能如下:        (1)第一阶段的功能 Ø  硬件设备初始化 Ø  加载U-Boot第二阶段代码到RAM空间 Ø  设置好栈 Ø  跳转到第二阶段代码入口        (2)第二阶段的功能 Ø  初始化本阶段使用的硬件设备 Ø  检测系统内存映射 Ø  将内核从Fla

^_虫虫_^的专栏 1525

u-boot 启动过程 (基于S3C2410) 和uImage zImage 启动分析

本文以流行的Samsung公司的S3C2410,openmoko平台和u-boot-1.3.2(2008.5 发布)为例,介绍如何在ZIX嵌入式开发环境下探索u-boot启动过程。 虽然u-boot已经广泛应用,由于其相对的复杂性使用户在了解其内部机理和进行u-boot的移植工作时还是会碰到困难。u-boot已有一些分析文档,但多数和真正的代码不能同步或者版本老旧,难以将概念和现实的代码匹配

slj_win的专栏 5509

u-boot 启动过程 —— 基于S3C2410 --转载自周明

 文章来源:http://forum.linuxbj.com/node/2    u-boot是广泛应用于嵌入式系统的bootloader,该软件主页是http://www.denx.de/wiki/U-Boot 解压缩开代码包后,以下几个目录中分类存放了主要的源码board目录——用于放置板支持代码,相当于bootloader级的BSP。与特定板相关的代码包括频率合成、G

嵌入式开发小站 1007

s3c2410 u-boot启动过程

开发板上电后,执行U-Boot的第一条指令,然后顺序执行U-Boot启动函数。函数调用顺序如图6.3所示。看一下board/smsk2410/u-boot.lds这个链接脚本,可以知道目标程序的各部分链接顺序。第一个要链接的是cpu/arm920t/start.o,那么U-Boot的入口指令一定位于这个程序中。下面详细分析一下程序跳转和函数的调用关系以及函数实现。1.cpu/arm920t

intint的专栏 2204

U-Boot在S3C2410上的移植

引言   U-Boot是用于初始化目标板硬件,为嵌入式操作系统提供目标板硬件配置信息,完成嵌入式操作系统装载、引导和运行的固件程序。它能够将系统的软硬件紧密衔接在一起。S3C2410是三星公司的一款基于ARM920T核的嵌入式通用处理器。本文将详细介绍U-Boot在S3C2410开发板上的移植与运行。   U-BOOT简介    U-Boot支持ARM、 PowerPC等多种架构的处理器,也支持L

民工甲的专栏 1259

s3c2410开发板u-boot移植详细配置nandflash启动

s3c2410开发板u-boot移植详细配置nandflash启动

支持s3c2410,s3c2440d uboot

自动识别s3c2410,s3c2440 实现usb烧写nand flash.

s3c2410uboot移植实验

基于三星的ARM S3C2410的UBOOT移植实验文档

u-boot-2016.01分析s3c2410启动过程

首先从u-boot官网下载u-boot-2016.01.tar.gz的源码。解压然后配置顶层Makefile中的CROSS_COMPILE=”你的交叉编译器路径”后执行如下命令开始编译:make smdk2410_defconfig make 编译成功后会在你的u-boot-2016.01文件夹下面生成u-boot.bin U-boot.lds等文件。注意在新版u-boot中还有一个文件叫Conf

zhuczloveai910的博客 1395

关于S3C2440从NAND Flash启动的问题

本文来自:http://blog.chinaunix.net/u2/69674/showart_1212448.html用的是S3C2410.见附件start.s 其中关于nand flash启动的那一段一直百思不得其解,按说从NAND FLASH启动时,应该是前4KB映射到NGCS0,其中的代码将NAND中存放的程序拷贝到RAM中,但该文件提供的程序好象是先从NAND拷贝 128K的代码到R

Stoneboy 2011

s3c2410 u-boot 之 stage1

转自http://blog.csdn.net/flickedball/article/details/4869044 s3c2410 u-boot 之 stage1 前言          本文主要是基于大家比较熟悉的 s3c2410 ,对移植 u-boot 时 stage1 过程进行一个分析,网上关于之方面的资料很多,但是几乎都只是对代码作注解,容易让人产生知其一不知其二的感觉,在这里,我

yongyici123的专栏 835

从Nand Flash启动U-BOOT的基本原理

前4K的问题    如果S3C2410被配置成从Nand Flash启动(配置由硬件工程师在电路板设置), S3C2410的Nand Flash控制器有一个特殊的功能,在S3C2410上电后,Nand Flash控制器会自动的把Nand Flash上的前4K数据搬移到4K内部RAM中,并把0x00000000设置内部RAM的起始地址,CPU从内部RAM的0x00000000位置开始启动。这个过程

wiserstar的专栏 1364

U-boot在SBC2410上的移植

U-Boot是用于初始化目标板硬件,为嵌入式操作系统提供目标板硬件配置信息,完成嵌入式操作系统装载、引导和运行的固件程序。它能够将系统的软硬件紧密衔接在一起。S3C2410是三星公司的一款基于ARM920T核的嵌入式通用处理器。本文将详细介绍U-Boot在S3C2410开发板上的移植与运行。 U-BOOT简介 U-Boot支持ARM、 PowerPC 等多种架构的处理器,也支持Linux、Ne

hecant的专栏 1158
上一篇: linux2.6.29 启动过程详细分析
下一篇: u-boot 结构分析 —— 基于S3C2410
jun2ran
博客等级 码龄18年 102粉丝 183原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值