U_Boot第一启动阶段Uboot启动分析笔记-----Stage1(start.S与lowlevel_init.S详解)
U-BOOT启动过程
U-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中还有这些异常对应的异常处理程序。
uboot启动流程
U-Boot工作过程U-Boot启动内核的过程可以分为两个阶段,两个阶段的功能如下:(1)第一阶段的功能硬件设备初始化加载U-Boot第二阶段代码到RAM空间设置好栈跳转到第二阶段代码入口(2)第二阶段的功能初始化本阶段使用的硬件设备检测系统内存映射将内核从Flash读取到RAM中为内核设置启动参数调用内核1.1.1 U-Boot启动第一阶段代码分析第一阶段对应的文件是cpu/arm920t/和board/samsung/mini2440/。
U-Boot启动第一阶段流程如下:图 U-Boot启动第一阶段流程根据cpu/arm920t/中指定的连接方式:ENTRY(_start)SECTIONS{. = 0x00000000;. = ALIGN(4);.text :{cpu/arm920t/ (.text)board/samsung/mini2440/ (.text)board/samsung/mini2440/ (.text)*(.text)}… …}第一个链接的是cpu/arm920t/,因此的入口代码在cpu/arm920t/中,其源代码在cpu/arm920t/中。
下面我们来分析cpu/arm920t/的执行。
1. 硬件设备初始化(1)设置异常向量cpu/arm920t/开头有如下的代码:.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异常向量表,各个异常向量介绍如下:表 ARM异常向量表在cpu/arm920t/中还有这些异常对应的异常处理程序。
BOOT详解
1 U-Boot简介U-Boot,全称Universal BootLoader,是遵循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软件工程中心WolfgangDenk[以下简称W.D]本人精湛专业水平和持着不懈的努力。
当前,U-Boot项目正在他的领军之下,众多有志于开放源码BOOTLOADER移植工作的嵌入式开发人员正如火如荼地将各个不同系列嵌入式处理器的移植工作不断展开和深入,以支持更多的嵌入式操作系统的装载与引导。
am335xu-boot启动过程分析
am335xu-boot启动过程分析 u-boot属于两阶段的bootloader,第⼀阶段的⽂件为 arch/arm/cpu/armv7/start.S 和 arch/arm/cpu/armv7/lowlevel_init.S,前者是平台相关的,后者是开发板相关的。
1. u-boot第⼀阶段代码分析 (1)硬件设备初始化 将CPU的⼯作模式设为管理模式(SVC); 关闭中断; 禁⽤MMU,TLB ; 板级初始化; (2)为加载Bootloader的第⼆阶段代码准备RAM空间 加载u-boot.img,跳转到u-boot.img; 上述⼯作,也就是uboot-spl代码流程的核⼼。
代码如下:arch/arm/cpu/armv7/start.S1/*2 * the actual reset code3*/4reset:5 bl save_boot_params6/*7 * disable interrupts (FIQ and IRQ), also set the cpu to SVC32 mode,8 * except if in HYP mode already9*/10 mrs r0, cpsr11 and r1, r0, #0x1f @ mask mode bits12 teq r1, #0x1a @ test for HYP mode13 bicne r0, r0, #0x1f @ clear all mode bits14 orrne r0, r0, #0x13 @ set SVC mode15 orr r0, r0, #0xc0 @ disable FIQ and IRQ16 msr cpsr,r017@@ 以上通过设置CPSR寄存器⾥设置CPU为SVC模式,禁⽌中断18@@ 具体操作可以参考《[kernel 启动流程] (第⼆章)第⼀阶段之——设置SVC、关闭中断》的分析1920/* the mask ROM code should have PLL and others stable */21#ifndef CONFIG_SKIP_LOWLEVEL_INIT22 bl cpu_init_cp1523@@ 调⽤cpu_init_cp15,初始化协处理器CP15,从⽽禁⽤MMU和TLB。
Uboot启动流程分析和移植介绍
基于MPC83xx 的U-boot 启动流程分析和移植董 闯北京邮电大学信息与通信工程学院,北京(100876)E-mail :donix.dong@摘 要:本文首先引入Bootloader 的概念,接着介绍U-boot 这种引导程序,并以Freescale 32位微处理器MPC83xx 为例,结合代码详细分析了U-boot 的启动的各个阶段及最终引导Linux 内核的过程,最后,建立交叉编译环境,针对TC8313E 目标板,给出U-boot 移植与编译的基本步骤。
关键词:U-boot;MPC83xx;交叉编译;移植;嵌入式系统中图分类号:TP393.051.引言引导程序(Bootloader)是系统加电后运行的第一段软件代码,类似于PC 机中的引导加载程序BIOS 。
虽然引导程序仅在系统启动时运行非常短的时间,但对于嵌入式系统来说,这是一个非常重要的组成部分。
通过这段小程序,初始化必要的硬件设备,创建内核需要的一些信息并将这些信息传递给内核,从而将系统的软、硬件环境配置到一个合适的状态,最终调用操作系统内核,真正起到引导和加载内核的作用。
2. U-boot 介绍目前,嵌入式领域里出现了很多种类的Bootloader ,如Armboot 、Blob 、Redboot 、vivi 和U-boot 等,其中U-boot 是使用最广泛,功能最完善的。
U-boot (Universal Boot Loader)是从PPCBOOT 发展演化而来[1],其源码目录、编译形式与Linux 内核很相似,事实上,不少U-boot 源码就是相应的Linux 内核源程序的简化,尤其是一些设备的驱动程序,这从U-boot 源码的注释中就能体现。
U-boot 中Universal 有两层含义,一是U-boot 除了支持PowerPC 系列的处理器外,还能支持MIPS 、x86、ARM 、NIOS 、XScale 等诸多常用系列的处理器;另外一层含义则是U-boot 不仅仅支持嵌入式Linux 操作系统的引导,还支持OpenBSD, NetBSD, FreeBSD, SVR4, Solaris, VxWorks, LynxOS, pSOS, lrix, RTEMS, QNX, ARTOS 等操作系统的引导。
uboot分析之bootm
uboot分析之bootmbootm命令执⾏过程中调⽤了bootm_start函数,这个函数⽐较重要,所以先分析它。
mon/cmd_bootm.cCpp代码1. static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])2. {3. void *os_hdr;4. int ret;5. memset ((void *)&images, 0, sizeof (images));//images是⼀个bootm_headers_t类型的全局变量。
见下⾯的分析。
6. images.verify = getenv_yesno ("verify");//从环境变量中检查是否要对镜像的数据(不是镜像头)进⾏校验。
7. bootm_start_lmb();//不做任何有意义的⼯作,除了定义# define lmb_reserve(lmb, base, size)8. /* get kernel image header, start address and length */寻找可⽤的内核镜像,见下⾯的分析。
主要根据传⼊的参数检查镜像的合法性并获取信息。
9. os_hdr = boot_get_kernel (cmdtp, flag, argc, argv,10. &images, &images.os.image_start, &images.os.image_len);//返回指向内存中镜像头的指针11. if (images.os.image_len == 0) {12. puts ("ERROR: can't get kernel image!\n");13. return 1;14. }15. /* get image parameters */16. switch (genimg_get_format (os_hdr)) {//根据镜像魔数获取镜像类型17. case IMAGE_FORMAT_LEGACY:18. images.os.type = image_get_type (os_hdr);//镜像类型19. p = image_get_comp (os_hdr);//压缩类型20. images.os.os = image_get_os (os_hdr);//操作系统类型21. images.os.end = image_get_image_end (os_hdr);//当前镜像的尾地址22. images.os.load = image_get_load (os_hdr);//镜像数据的载⼊地址23. break;24. default:25. puts ("ERROR: unknown image format type!\n");26. return 1;27. }28. /* find kernel entry point */29. if (images.legacy_hdr_valid) {//如果镜像已经通过验证30. images.ep = image_get_ep (&images.legacy_hdr_os_copy);//获取⼊⼝地址,填充images.ep 。
uboot分析和笔记
uboot一、uboot是ppcboot和armboot合并而成,现在主流的bootloader为uboot和redboot二、bootm addr_kernel addr_initrd三、移植uboot时最好(一定)要找到一个自己板子的原形(即自己的板子是在这个板子上做一些修改而来的)的版本,这样就可以事半功倍。
这样要修改的地方就比较少,也比较容易了。
uboot支持很多平台,与一个具体平台相关的主要有三个地方:1、./include/configs/xxxxx.h, 主要定义了flash、sdram的起始地址等信息,一般要修改flash的起始地址、大小,有时候会有位宽等。
2、./board/xxxxx/*,这个目录下主要有两三个.c文件,主要为该平台的初始化和flash操作的函数。
有时候flash的操作需要修改,不过一般都是找一个现有的支持该flash的驱动,一般情况在uboot 别的./board/平台下就会有现成的,拷贝过了就可以了。
3、./cpu/xxxxxx/arch_xxx/xxxxxx/*, 一般是此cpu的初始等函数。
四、具体移植的时候最多涉及到的会是./include/configs/xxxx.h,如果有现成的平台(uboot现在支持绝大部分我们常用的平台),可能只需要对着原来的xxxx.h文件,修改几个我们在硬件上修改了的地方,一般会是flash的起始地址、大小;内存大小(内存的起始地址应该都是0);uboot设置信息保存的地址和长度;console 口和它的波特率;默认的设置;uboot的入口地址等(具体情况可能会有一些变化),如果不是从相同的平台移植,可能会比较麻烦,因为这时候要修改一些和此cpu相关的一些寄存器、频率和内存等硬件方面的东西了(也在这个xxxx.h中),虽然这时改动的地方也不多,但是会很痛苦,因为经常不知道要改哪里或者改为多少。
所以可能需要参考cpu的datasheet和到网上找一些资料了并且慢慢试了。
U-Boot启动过程--详细版的完全分析
(一)U-Boot启动过程--详细版的完全分析我们知道,bootloader是系统上电后最初加载运行的代码。
它提供了处理器上电复位后最开始需要执行的初始化代码。
在PC机上引导程序一般由BIOS开始执行,然后读取硬盘中位于MBR(Main Boot Record,主引导记录)中的Bootloader(例如LILO或GRUB),并进一步引导操作系统的启动。
然而在嵌入式系统中通常没有像BIOS那样的固件程序,因此整个系统的加载启动就完全由bootloader来完成。
它主要的功能是加载与引导内核映像一个嵌入式的存储设备通过通常包括四个分区:第一分区:存放的当然是u-boot第二个分区:存放着u-boot要传给系统内核的参数第三个分区:是系统内核(kernel)第四个分区:则是根文件系统如下图所示:u-boot是一种普遍用于嵌入式系统中的Bootloader。
Bootloader介绍Bootloader是进行嵌入式开发必然会接触的一个概念,它是嵌入式学院<嵌入式工程师职业培训班>二期课程中嵌入式linux系统开发方面的重要内容。
本篇文章主要讲解Bootloader 的基本概念以及内部原理,这部分内容的掌握将对嵌入式linux系统开发的学习非常有帮助!Bootloader的定义:Bootloader是在操作系统运行之前执行的一小段程序,通过这一小段程序,我们可以初始化硬件设备、建立内存空间的映射表,从而建立适当的系统软硬件环境,为最终调用操作系统内核做好准备。
意思就是说如果我们要想让一个操作系统在我们的板子上运转起来,我们就必须首先对我们的板子进行一些基本配置和初始化,然后才可以将操作系统引导进来运行。
具体在Bootloader中完成了哪些操作我们会在后面分析到,这里我们先来回忆一下PC的体系结构:PC机中的引导加载程序是由BIOS和位于硬盘MBR中的OS Boot Loader(比如LILO和GRUB等)一起组成的,BIOS在完成硬件检测和资源分配后,将硬盘MBR中的Boot Loader读到系统的RAM中,然后将控制权交给OS Boot Loader。
UBOOT从NAND FLASH启动分析
UBOOT从NAND FLASH启动分析UBOOT从NAND FLASH启动分析在分析启动代码之前先看一下S3C2440的NAND启动:在配置NAND启动模式之后,S3C2440上电会先将NAND中的0x0 - 0x1000共4096字节的数据拷贝到位于Bank0中的Boot Internal SRAM上Bank0如下图:可以看出Boot Internal SRAM为4KB大小,也正是因为Boot Internal SRAM只有4KB 大小,所以只能从NAND中拷贝4K的内容= 3= 这个Boot Internal SRAM是配置为NAND FLASH启动模式才有的这4K内容是什么呢?~ 这就要看Uboot的镜像文件中是如何进行连接的了~连接脚本在board/smdk2440/u-boot.lds中,如下SECTIONS{. = 0x00000000;. = ALIGN(4);.text :{cpu/arm920t/start.o (.text)cpu/arm920t/s3c24x0/nand_read.o (.text)*(.text)}. = ALIGN(4);.rodata : { *(.rodata) }. = ALIGN(4);.data : { *(.data) }. = ALIGN(4);.got : { *(.got) }. = .;__u_boot_cmd_start = .;.u_boot_cmd : { *(.u_boot_cmd) }__u_boot_cmd_end = .;. = ALIGN(4);__bss_start = .;.bss : { *(.bss) }_end = .;}.text为代码段,可以看出cpu/arm920t/start.o在代码段的最前面,所以会先执行start.o 中的代码连接完成后的镜像文件的前4K如下cpu/arm920t/start.o(.text).text 0x33f80000 0x4e0 cpu/arm920t/start.o0x33f80050 IRQ_STACK_START0x33f80048 _bss_start0x33f8004c _bss_end0x33f80044 _armboot_start0x33f80000 _start0x33f80054 FIQ_STACK_STARTcpu/arm920t/s3c24x0/nand_read.o(.text).text 0x33f804e0 0x1b8 cpu/arm920t/s3c24x0/nand_read.o0x33f804e0 nand_read_ll*(.text).text 0x33f80698 0x64 board/smdk2440/libsmdk2440.a(lowlevel_init.o)0x33f8069c lowlevel_init.text 0x33f806fc 0x280 cpu/arm920t/libarm920t.a(interrupts.o)0x33f80934 do_fiq0x33f80880 do_undefined_instruction0x33f80744 show_regs0x33f80958 do_irq0x33f80728 bad_mode0x33f808c8 do_prefetch_abort0x33f8070c disable_interrupts0x33f80910 do_not_used0x33f808ec do_data_abort0x33f808a4 do_software_interrupt0x33f806fc enable_interrupts.text 0x33f8097c 0x250 cpu/arm920t/s3c24x0/libs3c24x0.a(interrupts.o)0x33f80aa4 set_timer0x33f80a20 reset_timer0x33f8097c interrupt_init0x33f80ba0 get_tbclk0x33f80a90 get_timer0x33f809f0 reset_timer_masked0x33f80a24 get_timer_masked0x33f80ab4 udelay0x33f80b10 udelay_masked0x33f80bac reset_cpu0x33f80b8c get_ticks.text 0x33f80bcc 0x150 cpu/arm920t/s3c24x0/libs3c24x0.a(speed.o)0x33f80c4c get_HCLK0x33f80cec get_PCLK0x33f80c44 get_FCLK0x33f80d14 get_UCLK.text 0x33f80d1c 0x1e8 cpu/arm920t/s3c24x0/libs3c24x0.a(cmd_s3c24xx.o) 0x33f80d8c do_s3c24xx.text 0x33f80f04 0xdc cpu/arm920t/s3c24x0/libs3c24x0.a(serial.o)0x33f80f04 serial_setbrg0x33f80fa8 serial_tstc0x33f80f80 serial_putc0x33f80f58 serial_init0x33f80fb8 serial_puts0x33f80f68 serial_getc.text 0x33f80fe0 0x140 lib_arm/libarm.a(_divsi3.o)0x33f80fe0 __divsi3如何设置从0x33f80000开始呢?~这是链接的时候指定的在根目录下面的config.mk中有下面一句LDFLAGS += -Bstatic -T $(LDSCRIPT) -Ttext $(TEXT_BASE) $(PLATFORM_LDFLAGS)关键就是其中的-Ttext $(TEXT_BASE),这句指明了代码段的起始地址而TEXT_BASE在board/smdk2440/config.mk中定义TEXT_BASE = 0x33F8 0000 为什么是0x33F8 0000呢?~这是将NAND中Uboot拷贝到RAM中的起始地址,所以在代码拷贝到RAM之前不能使用绝对地址来寻址数据,只能用相对地址在以下将用虚拟地址来指Uboot在RAM中的地址,也就是0x33F8 0000现在来看代码cpu/arm920t/start.S_start: ;异常处理向量表b start_codeldr pc, _undefined_instruction ;未定义指令异常:0x00000004ldr pc, _software_interrupt ;软中断异常:0x00000008ldr pc, _prefetch_abort ;预取异常:0x0000000Cldr pc, _data_abort ;数据异常:0x00000010ldr pc, _not_used ;未使用:0x00000014ldr pc, _irq ;外部中断请求IRQ:0x00000018ldr pc, _fiq ;快束中断请求FIQ:0x0000001Cb start_code在虚拟地址0x33F8 0000处, 拷贝到Boot Internal SRAM后则位于0x0处,所以b start_code是第一条执行的指令,start_code在cpu/arm920t/start.S中代码如下://读取CPSR寄存器的内容到R0mrs r0,cpsr//清除R0中的0 - 4 这5个位后保存到R0中//也就是清除用户模式位bic r0,r0,#0x1f//置R0的0 1 4 6 7 位为真//也就是选择SVC模式,同时IRQ和FIQ被禁止,处理器处于ARM状态//关闭中断和快速中断orr r0,r0,#0xd3//将R0中的值保存到CPSR上msr cpsr,r0# define pWTCON 0x53000000 ;看门狗控制寄存器WTCON# define INTMSK 0x4A000008 ;中断屏蔽寄存器INTMSK# define INTSUBMSK 0x4A00001C ;辅助中断屏蔽寄存器,由于外设中断源太多,要用此寄存器屏蔽剩余的中断源# define LOCKTIME 0x4c000000 ;PLL锁定时间计数寄存器# define MPLLCON 0x4c000004 ;主时钟锁相环控制寄存器# define UPLLCON 0x4c000008# define CLKDIVN 0x4C000014 ;时钟分频寄存器/* clock divisor register */# define INTSUBMSK_val 0xffff# define MPLLCON_val ((184 12) + (2 4) + 2) /*406M*/# define UPLLCON_val ((60 12) + (4 4) + 2) /* 47M */# define CLKDIVN_val 7 /* FCLK:HCLK:PCLK = 1:3:6 */# define CAMDIVN 0x4C000018//取得看门狗寄存器的地址ldr r0, =pWTCON//将R1寄存器清0mov r1, #0x0//将看门狗寄存器清0,即将看门狗禁止,包括定时器定时,溢出中断及溢出复位等str r1, [r0]/** mask all IRQs by setting all bits in the INTMR - default*///设R1寄存器为0xFFFF FFFFmov r1, #0xffffffff//读取中断屏蔽寄存器的地址ldr r0, =INTMSK//将中断屏蔽寄存器中的位全设1,屏蔽所有中断str r1, [r0]//# define INTSUBMSK_val 0xffff//设R1寄存器为0xFFFFldr r1, =INTSUBMSK_val//读取辅助中断屏蔽寄存器的地址ldr r0, =INTSUBMSK//将辅助中断屏蔽寄中的11个中断信号屏蔽掉,本人觉得INTSUBMS_val应设成7ff str r1, [r0]//# define LOCKTIME 0x4c000000//读取PLL锁频计数器寄存器地址到R0中ldr r0,=LOCKTIME//将R1设为0x00FF FFFFldr r1,=0xffffff//M_LTIME为最大的0xFFF//U_LTIME为最大的0xFFFstr r1,[r0] ;0xfff=4096>1800,远远满足锁定要求/* FCLK:HCLK:PCLK = 1:2:4 *//* default FCLK is 120 MHz ! *///# define CLKDIVN 0x4C000014 /* clock divisor register *///读取时钟分频寄存器的地址ldr r0, =CLKDIVN//# define CLKDIVN_val 7 /* FCLK:HCLK:PCLK = 1:3:6 *///将R1设为0x7mov r1, #CLKDIVN_va//PDIVN - 1: PCLK has the clock same as the HCLK/2.//HDIVN - 11 : HCLK = FCLK/3 when CAMDIVN[8] = 0.// HCLK = FCLK/6 when CAMDIVN[8] = 1.str r1, [r0]/* Make sure we get FCLK:HCLK:PCLK = 1:3:6 *///# define CAMDIVN 0x4C000018//读取摄像头时钟分频寄存器的地址ldr r0, =CAMDIVN//将R1设为0mov r1, #0//将摄像头时钟分频寄存器清0str r1, [r0]/* Clock asynchronous mode *///MRC p15, 0, Rd, c1, c0, 0 ; read control register//读取控制寄存器中的值到R1中mrc p15, 0, r1, c1, c0, 0 ;将协处理器p15的寄存器c1和c0的值传到arm处理器的R1寄存器中//31 iA bit Asynchronous clock select//30 nF bit notFastBus selectorr r1, r1, #0xc0000000 ;将最高两位置1//MCR p15, 0, Rd, c1, c0, 0 ; write control register//将R1中的值写到控制寄存器中mcr p15, 0, r1, c1, c0, 0 将arm的寄存器R1的32位数据传到协处理器p15的两个16位寄存器c1和c0//# define UPLLCON 0x4c000008//读取UPLL设置寄存器的地址到R0中ldr r0,=UPLLCON//# define UPLLCON_val ((60ldr r1,=UPLLCON_val//将R1中的值写入UPLL设置寄存器中str r1,[r0]//ARM920T为5级流水线,需要至少5个周期来让指令生效nopnopnopnopnopnopnopnop//读取MPLL设置寄存器的地址到R0中ldr r0,=MPLLCON//# define MPLLCON_val ((184ldr r1,=MPLLCON_val//将R1中的值写入MPLL设置寄存器中str r1,[r0]#define GPJCON 0x560000D0#define GPJDAT 0x560000D4#define GPJUP 0x560000D8//跳转到cpu_init_crit处执行//并将下一条指令的地址写入LR寄存器中bl cpu_init_critcpu_init_crit在cpu/arm920t/start.S中代码如下:cpu_init_crit:/** flush v4 I/D caches*///将R0寄存器置0mov r0, #0//Invalidate ICache and DCache SBZ MCR p15,0,Rd,c7,c7,0 //禁止指令和数据cachemcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache *///Invalidate TLB(s) SBZ MCR p15,0,Rd,c8,c7,0mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB *//** disable MMU stuff and caches*///MRC p15, 0, Rd, c1, c0, 0 ; read control registermrc p15, 0, r0, c1, c0, 0//清除[8] [9] [13] 这3个位//8 - System protection//9 - ROM protection//13 - Base location of exception registers - 0 = Low addresses = 0x00000000. bic r0, r0, #0x00002300 // clear bits 13, 9:8 (--V- --RS)//清除[0] [1] [2] [7] 这4个位// 0 - MMU enable - 0 = MMU disabled.// 1 - Alignment fault enable - 0 = Fault checking disabled.// 2 - DCache enable - 0 = DCache disabled.// 7 - Endianness - 0 = Little-endian operation.bic r0, r0, #0x00000087 // clear bits 7, 2:0 (B--- -CAM)//设置位[1]为真// 1 - Alignment fault enable - 1 = Fault checking enabled.orr r0, r0, #0x00000002 // set bit 2 (A) Align//设置位[12]为真//12 - ICache enable - 1 = ICache enabled.orr r0, r0, #0x00001000 // set bit 12 (I) I-Cache//MCR p15, 0, Rd, c1, c0, 0 ; write control registermcr p15, 0, r0, c1, c0, 0//将返回地址保存到IP中mov ip, lr//跳转到lowlevel_init中执行bl lowlevel_initcpu_init_crit在cpu/arm920t/start.S中代码如下:.globl lowlevel_init//读取下面标号为SMRDATA处的地址到R0中ldr r0, =SMRDATA//读取上面标号为_TEXT_BASE处的地址内容到R1中//也就是取得TEXT_BASE的值到R1中ldr r1, _TEXT_BASE//计算SMRDATA的相对地址保存到R0中//SMRDATA为虚拟地址,而TEXT_BASE为虚拟地址的起始地址//而现在Uboot的起始地址并不为虚拟地址//TEXT_BASE为0x33F8 0000,SMRDATA为0x33F8 06C8//而现在程序运行在起始地址为0x0000 0000的地方//所以需要计算以0x0000 0000为标准的相对地址sub r0, r0, r1//取得带宽与等待状态控制寄存器地址到R1中ldr r1, =BWSCON /* Bus Width Status Controller *///一共需要设置13个寄存器,每个寄存器4字节add r2, r0, #13*40://读取R0所指的项的值到R3中后R0自加4字节ldr r3, [r0], #4//将R3中的值保存到R1所指的地址中后R1自加4字节str r3, [r1], #4//比较R0和R2是否相等,相等则说明13个寄存器全部设置完毕cmp r2, r0//不等则跳转到上面标号为0处的地址继续执行bne 0b//跳回到返回地址中继续执行mov pc, lr.ltorg/* the literal pools origin */SMRDATA:.word(0+(B1_BWSCON4)+(B2_BWSCON8)+(B3_BWSCON12)+(B4_BWSCON16)+( B5_BWSCON20)+(B6_BWSCON24)+(B7_BWSCON28)).word((B0_Tacs13)+(B0_Tcos11)+(B0_T acc8)+(B0_Tcoh6)+(B0_T ah4)+(B0_T acp2) +(B0_PMC)).word((B1_Tacs13)+(B1_Tcos11)+(B1_T acc8)+(B1_Tcoh6)+(B1_T ah4)+(B1_T acp2) +(B1_PMC)).word((B2_Tacs13)+(B2_Tcos11)+(B2_T acc8)+(B2_Tcoh6)+(B2_T ah4)+(B2_T acp2) +(B2_PMC)).word((B3_Tacs13)+(B3_Tcos11)+(B3_T acc8)+(B3_Tcoh6)+(B3_T ah4)+(B3_T acp2) +(B3_PMC)).word((B4_Tacs13)+(B4_Tcos11)+(B4_T acc8)+(B4_Tcoh6)+(B4_T ah4)+(B4_T acp2) +(B4_PMC)).word((B5_Tacs13)+(B5_Tcos11)+(B5_T acc8)+(B5_Tcoh6)+(B5_T ah4)+(B5_T acp2) +(B5_PMC)).word ((B6_MT15)+(B6_Trcd2)+(B6_SCAN)).word ((B7_MT15)+(B7_Trcd2)+(B7_SCAN)).word ((REFEN23)+(TREFMD22)+(Trp20)+(Trc18)+(Tchr16)+REFCNT).word 0x32.word 0x30.word 0x30执行mov pc, lr后将返回到cpu_init_crit中剩下来还有2条指令//恢复返回地址到LRmov lr, ip//跳转到返回地址mov pc, lr执行完毕之后将返回到start_code中执行接下来的代码代码如下://#define GPJCON 0x560000D0//取得J端口控制寄存器的地址到R0中LDR R0, = GPJCON//将R1设置为0x1 5555LDR R1, = 0x15555//将R1中的值保存到J端口控制寄存器//GPJ0 - 01 - Output//GPJ1 - 01 - Output//GPJ2 - 01 - Output//GPJ3 - 01 - Output//GPJ4 - 01 - OutputSTR R1, [R0]//#define GPJUP 0x560000D8//取得J端口上拉功能寄存器的地址到R0中LDR R0, = GPJUP//将R1设置为0x1FLDR R1, = 0x1f//将R1中的值保存到J端口上拉功能寄存器//禁止GPJ0 - GPJ4的上拉功能STR R1, [R0]//#define GPJDAT 0x560000D4//取得J端口数据寄存器的地址到R0中LDR R0, = GPJDAT//将R1设为0x0LDR R1, = 0x00//将R1中的值保存到J端口数据寄存器//将J端口数据寄存器清0STR R1, [R0]//下面是NAND数据拷贝过程//relocate:copy_myself://#define S3C2440_NAND_BASE 0x4E000000//取得Nand Flash设置寄存器的地址mov r1, #S3C2440_NAND_BASE//将R2设为0xFFF0ldr r2, =0xfff0 // initial value tacls=3,rph0=7,rph1=7 //#define oNFCONF 0x00//读取Nand Flash设置寄存器中的值到R3中ldr r3, [r1, #oNFCONF]//将R3或上R2后保存到R3中orr r3, r3, r2//将R3中的值保存到Nand Flash设置寄存器中//TWRPH0 - 111 - Duration = HCLK * (TWRPH0 + 1) //TACLS - 11 - Duration = HCLK * TACLSstr r3, [r1, #oNFCONF]//#define oNFCONT 0x04//读取Nand Flash控制寄存器中的值到R3中ldr r3, [r1, #oNFCONT]//将R3的[0]位置1orr r3, r3, #1 // enable nand controller//将R3中的值保存到Nand Flash控制寄存器中//Mode - 1:Nand Flash Controller Enablestr r3, [r1, #oNFCONT]//读取虚拟起始地址到R0中ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot *///预留malloc所需要的空间sub r0, r0, #CFG_MALLOC_LEN /* malloc area *///预留bdinfo所需要的空间sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo *///预留中断和快速中断向量表空间sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)//预留12字节给中断栈sub sp, r0, #12 /* leave 3 words for abort-stack */// copy u-boot to RAM//读取虚拟起始地址到R0中,作为目标地址ldr r0, _TEXT_BASE//将R1设为0,作为源地址mov r1, #0x0//将UBOOT大小的值保存在R2中,作为数据大小mov r2, #CFG_UBOOT_SIZE//跳转到nand_read_ll处执行//并将下一条指令的地址保存在LR中bl nand_read_llnand_read_ll的原型为int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size) 之前设置的R0 R1 R2为它的3个参数R0 - bufR1 - start_addrR2 - sizenand_read_ll的代码在cpu/arm920t/s3c24x0/nand_read.c中int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size) {int i, j;//检测源地址和大小是否在NandFlash的边界上if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) //不在边界上则返回-1表示出错return -1; /* invalid alignment *//* chip Enable */// #define nand_select() (NFCONT &= ~(1//置NAND Flash控制寄存器中除Reg_nCE外所有的位为1//Reg_nCE - NAND FLASH Memory nFCE signal control//0 - Force nFCE to low (Enable chip select)nand_select();// #define nand_clear_RnB() (NFSTAT |= (1//置NAND Flash操作状态寄存器中的RnB_TransDetect位为1//When RnB low to high transition is occurred, this value set and issue interrupt if enabled.//To clear this value write '1'//1: RnB transition is detectednand_clear_RnB();for (i=0; i10; i++);//从源地址的首地址开始历便所要拷贝的数据大小for (i=start_addr; i (start_addr + size);){//检测地址是否在NAND Flash的边界上if (start_addr % NAND_BLOCK_SIZE == 0){//检测是否为坏块if (is_bad_block(i)){/* Bad block *///向后延伸一个存储块i += NAND_BLOCK_SIZE;size += NAND_BLOCK_SIZE;//跳到下一块continue;}}j = nand_read_page_ll(buf, i);//指向下一块i += j;buf += j;// LED_FLASH();}/* chip Disable */// #define nand_deselect() (NFCONT |= (1//置Reg_nCE位为1//NAND Flash Memory nFCE signal control//1: Force nFCE to High(Disable chip select)nand_deselect();return 0;}nand_read_ll将Uboot从NAND中拷贝到RAM中拷贝完成后将返回到start_code接下来的代码如下://检测R0是否为0,R0为nand_read_ll的返回值tst r0, #0x0//为0则说明无错,跳转到ok_nand_read处执行beq ok_nand_readok_nand_read://将R0设为0mov r0, #0//ldr r1, =0x33f00000//将R1设为虚拟地址起始处ldr r1, _TEXT_BASE//检测0x400个字节mov r2, #0x400 // 4 bytes * 1024 = 4K-bytesgo_next://读取R0处地址的数据到R3中//然后R0自加4字节ldr r3, [r0], #4//读取R1处地址的数据到R4中//然后R1自加4字节ldr r4, [r1], #4//比较R3和R4的数据是否相等//也就是检测Boot Internal SRAM和RAM中的数据是否相等//以保证数据无错teq r3, r4//不等则跳转到notmatchbne notmatch//相等则R2自减4subs r2, r2, #4//当R2为0则跳转到done_nand_readbeq done_nand_read//R2不为0则跳转回go_next继续检测bne go_nextdone_nand_read:LDR R0, = GPJDATLDR R1, = 0x2STR R1, [R0]stack_setup://读取虚拟起始地址到R0中ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */ //预留malloc所需要的空间sub r0, r0, #CFG_MALLOC_LEN /* malloc area *///预留bdinfo所需要的空间sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo *///预留中断和快速中断向量表空间sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)//预留12字节给中断栈sub sp, r0, #12 /* leave 3 words for abort-stack */clear_bss://读取BSS段的起始地址ldr r0, _bss_start /* find start of bss segment *///读取BSS段的结束地址ldr r1, _bss_end /* stop here *///将R2设为0x0mov r2, #0x00000000 /* clear */clbss_l://将R2中的值保存在R0所指的地址str r2, [r0] /* clear loop... *///R0自加4字节add r0, r0, #4//比较R0和R1是否相等cmp r0, r1//不等则说明清0还没结束ble clbss_lLDR R0, = GPJDATLDR R1, = 0x1STR R1, [R0]//跳转到start_armboot处执行ldr pc, _start_armboot_start_armboot: .word start_armboot这里start_armboot是一个绝对地址,在朗成所修改的这个Uboot中为0x33F8 13F4 执行ldr pc, _start_armboot之后将会跳到RAM中的绝对地址继续执行整理了一个流程图,分为3个存储器:1 Boot Internal SRAM , 接在BANK0,起始地址为0x02 RAM , 接在BANK6,起始地址为0x3000 00003 NAND FLASH,为单独寻址流程如下图:红字为流程序号:1. 首先将NAND FLASH中的前0x1000字节内容拷贝到Boot Internal SRAM中2. 从Boot Internal SRAM的0x0地址处开始执行指令3. 将Uboot从Flash拷贝到RAM中4. 执行ldr pc, _start_armboot从Boot Internal SRAM中跳转到RAM中的绝对地址0x33F8 13F4处继续执行。
u-boot设计文档
u-boot 设计文档1. 引言u-boot是bootloader成员中一种应用普遍,功能强大,极具代表意义的引导程序。
在嵌入式开发中起着举足轻重的作用。
U-boot是一段运行于内核之前的代码,为内核的启动初始化硬件环境并提供必需的参数,引导内核运行。
总之,u-boot的基本工作就是能够成功得引导内核运行。
一般情况下u-boot映像,内核和根文件系统映像都存储在Flash上。
也就是说开发板是从Nor Flash启动的。
但考虑到Nor flash容量小,价格高的因素,而Nand Flash 有更高的性价比,增加了从Nand Flash启动的功能。
2. 目标实现初始化开发板硬件环境,为启动内核提供硬件平台参数,引导内核启动的基本功能。
实现Nor/Nand Flash两种启动模式。
3. u-boot启动流程分析为了能够更好的移植u-boot到新的开发板上,有必要掌握u-boot的启动流程。
借助u-boot 启动流程图,简单介绍u-boot的启动过程。
考虑到执行效率和代码的扩展性和灵活性,一般情况把u-boot启动过程分为两个阶段。
第一阶段代码由汇编实现,这是u-boot一开始就执行的操作,其目的是为第二阶段的执行以及随后的kernel 的执行准备好一些基本的硬件环境。
通常包括以下步骤:硬件设备初始化;为加载u-boot第二阶段准备RAM 空间;拷贝u-boot第二阶段代码到RAM空间中;设置好堆栈;跳转到第二阶段的C 入口点。
第二阶段用c语言编写,用以实现复杂的功能。
通常包括以下步骤:初始化本阶段要使用到的硬件设备;检测系统内存映射(memory map);将kernel 映像和根文件系统映像从flash上读到RAM 空间中;为内核设置启动参数;调用内核。
4. u-boot移植U-Boot能够支持多种体系结构的处理器,支持的开发板也越来越多。
因为系统引导程序是完全依赖硬件平台的,所以在新电路板上需要移植U-Boot程序。
[uboot](第五章)uboot流程——uboot启动流程
[uboot](第五章)uboot流程——uboot启动流程/ooonebook/article/details/53070065以下例⼦都以project X项⽬tiny210(s5pv210平台,armv7)为例[uboot] uboot流程系列:建议先看《[project X] tiny210(s5pv210)上电启动流程(BL0-BL2)》,根据例⼦了解⼀下上电之后的BL0\BL1\BL2阶段,以及各个阶段的运⾏位置,功能。
建议可以和《[uboot] (番外篇)global_data介绍》和《[uboot] (番外篇)uboot relocation介绍》结合起来看。
=================================================================================⼀、uboot说明1、uboot要做的事情CPU初始刚上电的状态。
需要⼩⼼的设置好很多状态,包括cpu状态、中断状态、MMU状态等等。
其次,就是要根据硬件资源进⾏板级的初始化,代码重定向等等。
最后,就是进⼊命令⾏状态,等待处理命令。
在armv7架构的uboot,主要需要做如下事情arch级的初始化关闭中断,设置svc模式禁⽤MMU、TLB关键寄存器的设置,包括时钟、看门狗的寄存器板级的初始化堆栈环境的设置代码重定向之前的板级初始化,包括串⼝、定时器、环境变量、I2C\SPI等等的初始化进⾏代码重定向代码重定向之后的板级初始化,包括板级代码中定义的初始化操作、emmc、nand flash、⽹络、中断等等的初始化。
进⼊命令⾏状态,等待终端输⼊命令以及对命令进⾏处理上述⼯作,也就是uboot流程的核⼼。
2、疑问在前⾯的⽂章中虽然已经说明了,在spl的阶段中已经对arch级进⾏了初始化了,为什么uboot⾥⾯还要对arch再初始化⼀遍?回答:spl对于启动uboot来说并不是必须的,在某些情况下,上电之后uboot可能在ROM上或者flash上开始执⾏⽽并没有使⽤spl。
uboot代码详细分析
uboot启动阶段修改启动参数方法及分析
uboot启动阶段修改启动参数⽅法及分析作者:围补本来启动⽅式这节不是什么复杂的事⼉,不过想简单的说清楚明⽩,还真是不知道怎么组织。
毕竟⽂字跟有声语⾔表达有别。
但愿简单的东西别让我讲的太复杂!Arm板系统⽂件⼀般有三个——bootloader(uboot)、kernel(uImage)及根⽂件系统(rootfs)。
在arm板上电后,按uboot->kernel->rootfs的顺序依次启动。
由于开发板上有多种存储介质,三个⽂件可以放在任何可以存储的介质上,因此也就导致⽂件的多种启动⽅式。
本⽂就来讨论,以上三个⽂件对应不通存放位置的不同启动配置。
⼀般开发板上会有flash(Nor or NAND),mmc,emmc,sd卡等。
系统⽂件可以烧写在其中的任意⼀种上,因此也就对应不通的启动。
在开发过程中,有时经常需要改动内核,或者修改应⽤程序,如果每次都修改后都重新烧写到板上的存储介质,会⽐较⿇烦。
因此,为⽅便调试,uImage和rootfs还可以从⽹络启动,即nfs启动。
但uboot只能从板上介质启动。
启动过程其实是先将要启动的⽂件从存储位置拷贝到内存空间,再在内存中运⾏。
因此所谓不同位置启动,也就是从不同位置拷贝⽽已。
下⾯我们以开发板启动为例,分别介绍三个⽂件从不同位置启动的过程⽅法。
我使⽤的开发板上有emmc和两个sd卡。
我们按照启动顺序,依次介绍。
⾸先是uboot启动。
Uboot是三个系统⽂件中第⼀个启动的,对它的拷贝⼯作由cpu中的固件决定。
固件中⽀持从⼏个位置拷贝uboot,它就能存放在⼏个位置上。
⾄于每次启动具体从其中的哪⾥开始,硬件拨码开关决定,对应拨码在开发板⼿册上能查到。
启动之前,先将uboot的⼆进制⽂件拷贝到对应介质。
有两种不同⽅法烧写,如下:1. uboot⼆进制⽂件拷贝到emmc,是通过芯⽚供应商的下载⼯具软件烧写完成;2. 拷贝到sd卡是在linux下,通过dd命令完成的。
Uboot启动分析笔记Stage1(start.S与lowlevel_init.S详解)
/* These are defined in the board-specific linker script.*/ .globl _bss_start _bss_start: .word __bss_start .globl _bss_end _bss_end: .word _end #ifdef CONFIG_USE_IRQ /* IRQ stack memory (calculated at run-time) */ .globl IRQ_STACK_START IRQ_STACK_START: .word 0x0badc0de /* IRQ stack memory (calculated at run-time) */ .globl FIQ_STACK_START FIQ_STACK_START: .word 0x0badc0de #endif /* the actual reset code*/ /* 系统的复位代码。系统一上电,就跳到这里运行 */
*********************************************************/
U-boot2009.08基本的寄存器设置
嵌入式Linux之我行——u-boot-2009.08在2440上的移植详解嵌入式Linux之我行,主要讲述和总结了本人在学习嵌入式linux中的每个步骤。
一为总结经验,二希望能给想入门嵌入式Linux的朋友提供方便。
如有错误之处,谢请指正。
∙共享资源,欢迎转载:一、移植环境∙主机: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/下建立自己开发板的项2)因2440和2410的资源差不多,所以就以2410项目的代码作为模板,以后再修改3)修改u-boot跟目录下的Makefile文件。
查找到smdk2410_config的地方,在他下面按照smdk2410_config到此为止,u-boot对自己的my2440开发板还没有任何用处,以上的移植只是搭建了一个my2440开发板u-boot 的框架,要使其功能实现,还要根据my2440开发板的具体资源情况来对u-boot源码进行修改。
Tiny4412u-boot分析(2)u-boot启动流程
Tiny4412u-boot分析(2)u-boot启动流程从⼤⽅⾯来说,u-boot的启动分成两个阶段,第⼀个阶段主要的职责是准备初始化的环境,主要有以下⼏点①设置异常向量表②把CPU的⼯作模式设置为SVC32模式③关闭中断、MMU和cache④关闭看门狗⑤初始化内存、时钟、串⼝⑥设置堆栈⑦代码搬移⑧清bss段⑨跳转到c语⾔中执⾏(第⼆阶段)此时系统还没有进⼊C语⾔的运⾏阶段,并没有堆栈,也就不需要额外的RAM。
第⼆阶段在上⼀段建⽴好C语⾔运⾏环境的基础上,进⾏各种外设的初始化,并循环执⾏⽤户命令。
主要流程图如下当我们执⾏make命令来构建u-boot时,它的构建过程是:⾸先使⽤交叉编译⼯具将各⽬录下的源⽂件⽣成⽬标⽂件(*.o),⽬标⽂件⽣成后,会将若⼲个⽬标⽂件组合成静态库⽂件(*.a),最后通过链接各个静态库⽂件⽣成ELF格式的可执⾏⽂件。
在链接的过程中,需要根据链接脚本(⼀般是各个以lds为后缀的⽂本⽂件),确定⽬标⽂件的各个段,链接⽂件通常是board/<board>/⽬录中的u-boot.lds⽂件。
⼀般在链接脚本中通过ENTRY(_start)来指定⼊⼝为_start标号,通过⽂本段(.text)的第⼀个⽬标来制定u-boot⼊⼝⽂件。
所以我们通过这个链接脚本⽂件可以确定u-boot执⾏的⼊⼝。
Tiny4412 u-boot的链接脚本内容为// board/samsung/tiny4412/u-boot.ldsOUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")OUTPUT_ARCH(arm)ENTRY(_start)SECTIONS{. = 0x00000000;. = ALIGN(4);.text :{arch/arm/cpu/armv7/start.o (.text)board/samsung/tiny4412/libtiny4412.o (.text)arch/arm/cpu/armv7/exynos/libexynos.o (.text)*(.text)}. = ALIGN(4);.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }. = ALIGN(4);.data : {*(.data)}. = ALIGN(4);. = .;__u_boot_cmd_start = .;.u_boot_cmd : { *(.u_boot_cmd) }__u_boot_cmd_end = .;. = ALIGN(4);.rel.dyn : {__rel_dyn_start = .;*(.rel*)__rel_dyn_end = .;}.dynsym : {__dynsym_start = .;*(.dynsym)}.bss __rel_dyn_start (OVERLAY) : {__bss_start = .;_end = .;}/DISCARD/ : { *(.dynstr*) }/DISCARD/ : { *(.dynamic*) }/DISCARD/ : { *(.plt*) }/DISCARD/ : { *(.interp*) }/DISCARD/ : { *(.gnu*) }}在本链接脚本⽂件中,定义了起始地址为0x00000000,每个段使⽤4字节对齐(.ALIGN(4)),⼏个段分别为代码段(.text)、只读数据段(.rodata)、数据段(.data)其中,代码段的第⼀个⽬标为arch/arm/cpu/armv7/start.o,在其中定义了映像⽂件的⼊⼝_start。
uboot调试指南
Uboot调试参考指南一、调试目的Uboot的调试旨在通过观察uboot运行时状态来测试硬件问题。
二、调试步骤1.修改代码在uboot代码路径下,编辑uboot代码,需要做以下修改;a.修改config.mk文件,添加以下两行内容:AFLAGS += -Wa,-gdwarf2CFLAGS += -g2 -gdwarf-2b.修改. /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,编译uboot3.将编译好的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 ELFexecutable,如图1所示:图1 建立elf工程b.选择步骤3中保存的u-boot(elf格式文件),toolchain选择bareboard application,target OS选择none,工程名字请根据需要设置,比如我的机器上设置为example,点击next,如图2所示:图2 载入elf文件c.选择处理器,9131,如图3所示图3 选择处理器d.选择调试链接使用硬件,如图4所示图4 选择调试链接使用硬件e.配置硬件连接特性,图5所示图5 配置工程连接特性f.完成工程创建6.匹配源代码Uboot调试工程创建完成后,通过在修改uboot代码编译的uboot elf文件中已经包含符号表信息,其对应的源代码信息已经包含着elf文件中,因为我们的uboot编译是在linux服务器上执行,而cw的调试是在Windows机器上,因此,需要将uboot elf中的代码信息链接到windows的代码中。
4.3.1U-Boot代码结构分析
4.3.1U-Boot代码结构分析4.3 Bootloader之U-BootU-Boot是在PPC-Boot的基础上进化⽽来的⼀个开放源码的嵌⼊式BootROM程序,本⼩节将使⽤1.1.4版本的代码来分析U-Boot的代码结构,以及如何将它移植到基于S3C2410X的开发板上来。
4.3.1 U-Boot代码结构分析U-Boot4-9所⽰。
board:这个⽬录存放了所有U-Boot⽀持的⽬标板的⼦⽬录,如board/smdk2410/*就和我们的开发平台fs2410相类似。
要将U-Boot移植到⾃⼰的S3C2410X⽬标板上,必须参考这个⽬录下的内容,⽐如对Flash 以及Flash宽度和⼤⼩的定制等就要修改其中的flash.c。
cpu:这个⽬录存放了U-Boot⽀持的CPU类型,因为我们的开发平台是S3C2410X,所以只关⼼cpu/arm920t,CPU相关的⽂件主要是初始化⼀个执⾏环境,包括中断的初始化;start.S是整个u-boot.bin ⽬标可执⾏代码的第⼀段代码,它们是从Flash开始运⾏的,其主要⼯作就是对整个U-Boot⽬标代码的重定位,即将U-Boot转移到内存中去运⾏。
common:这个⽬录存放了U-Boot的⼀些公共命令的实现,像那些以cmd_*.c为名字的⽂件就是对应U-Boot的每个命令的实现代码,我们通常关⼼cmd_boot.c和cmd_bootm.c(它们和内核的引导相关)。
drivers:这个⽬录中存放了各种外设接⼝的驱动程序。
fs:这个⽬录中存放了U-Boot⽀持的⽂件系统。
lib_arm:这个⽬录存放了ARM平台公共的接⼝代码。
include:这个⽬录存放头⽂件的公共⽬录,其中的include/configs/smdk2410.h定义了所有和S3C2410X 相关的资源的配置参数,我们往往只需修改这个⽂件就可以配置⽬标板的参数,如波特率、引导参数、物理内存映射等。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
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的命令,最终都会在连接是存放在这个位置。
*/. = ALIGN(4);__bss_start = .; /*把__bss_start赋值为当前位置,即bss段的开始位置*/.bss (NOLOAD) : { *(.bss) . = ALIGN(4); } /*指定bss段,这里NOLOAD的意思是这段不需装载,仅在执行域中才会有这段*/_end = .; /*把_end赋值为当前位置,即bss段的结束位置*/}第一个链接的是cpu/board/start.o,也即Uboot的入口指令在start中,下面详细分析程序的跳转和函数调用关系。
2 Stage1 : cpu/arm920t/start.S这个汇编程序时UBoot的入口程序,以复位向量开头。
reset↓cpu_init_crit↓relocate↓stack_setup↓start_armboot()↓init_sequence[]↓getenv()↓main_loop()其中前面4步为Stage1下面来详细分析一下cpu/arm920t/start.S这里以ARM9 2410为例,2440移植时需要修改一些配置,具体的再后面的移植中介绍. /* 这段代码的主要作用:进入SVC模式关闭看门狗屏蔽所有IRG掩码设置时钟频率 FCLK HCLK PCLK清楚I/D Cache禁止MMU和CACHE配置memory control重定位:如果代码不在指定的地址上需要把uboot从当前位置copy到RAM指定位置上建立堆栈,为进入C函数做准备清0 .bss段跳入start_armboot函数进入stage2(lib_arm/board.c)*/.globl _start_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 /* 快速中断异常向量 */_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/**ARM9支持7种异常。
下面是异常的响应过程*第一个复位异常,它放在0x0的位置,一上电就执行它,而且我们的程序总是从复位异常处理程序* 开始执行的,因此复位异常处理程序不需要返回。
*其他异常处理的如下:*当一个异常出现以后,ARM会自动执行以下几个步骤:*(1) 把下一条指令的地址放到连接寄存器LR(通常是R14),这样就能够在处理异常返回时从正确的位置继续执行。
*(2) 将相应的CPSR(当前程序状态寄存器)复制到SPSR(备份的程序状态寄存器)中。
从异常退出的时候,就可以由SPSR来恢复CPSR。
*(3) 根据异常类型,强制设置CPSR的运行模式位。
*(4) PC(程序计数器)被强制成相关异常向量处理函数地址,从而跳转到相应的异常处理程序中。
* 当异常处理完毕后,ARM会执行以下几步操作从异常返回:*(1)将连接寄存器LR的值减去相应的偏移量后送到PC中*(2) 将SPSR复制回CPSR中*(3) 若在进入异常处理时设置了中断禁止位,要在此清除** ARM规定了异常向量的地址:* b reset ;复位 0x0* ldr pc, _undefined_instruction ;未定义的指令异常 0x4* ldr pc, _software_interrupt ;软件中断异常 0x8* ldr pc, _prefetch_abort ;预取指令 0xc* ldr pc, _data_abort ;数据 0x10* ldr pc, _not_used ;未使用 0x14* ldr pc, _irq ;慢速中断异常 0x18* ldr pc, _fiq ;快速中断异常 0x1c* 当处理器碰到异常时,PC会被强制设置为对应的异常向量,从而跳转到* 相应的处理程序,然后再返回到主程序继续执行。
* .balignl 16,0xdeadbeef, 将地址对齐到16的倍数,如果地址寄存器的值(PC)跳过4个字节才是16的倍数,* 则使用0xdeadbeef填充这4个字节,如果它跳过1、2、3个字节,则填充值不确定。
如果地址寄存器的值(PC)是16的倍数,则无需移动。
********************//************************************************************************** Startup Code (reset vector) ………………….*************************************************************************/ /* 保存变量的数据区 */_TEXT_BASE:.word TEXT_BASE ;定义一个字并分配空间 4bytes.globl _armboot_start_armboot_start:.word _start ;声明一个全局的,并用 _start 初始化它, 在u-boot.lds中定义/* These are defined in the board-specific linker script.*/.globl _bss_start_bss_start:.word __bss_start.globl _bss_end_bss_end:.word _end#ifdef CONFIG_USE_IRQ/* IRQ stack memory (calculated at run-time) */.globl IRQ_STACK_STARTIRQ_STACK_START:.word 0x0badc0de/* IRQ stack memory (calculated at run-time) */.globl FIQ_STACK_STARTFIQ_STACK_START:.word 0x0badc0de#endif/* the actual reset code*//* 系统的复位代码。
系统一上电,就跳到这里运行 */reset:mrs r0,cpsr /* 取得当前程序状态寄存器cpsr到r0 */bic r0,r0,#0x1f /* 这里使用位清除指令,把中断全部清除,只置位模式控制位为中断提供服务通常是 OS设备驱动程序的责任,因此在 Boot Loader 的执行全过程中可以不必响应任何中断*/orr r0,r0,#0xd3 /* 计算为超级保护模式,并disable IRQ和FIQ */msr cpsr,r0 /* 设置cpsr为超级保护模式 *//******************CPSR 的底8位为I F T M4 M3 M2 M1 M0 IRQdisable FIQdisable StateBitSVC[M4~M0] = 10011StateBit = set:THUMB state, others:ARM state* 设置cpu运行在SVC32模式。
ARM9共有7种模式:* 用户模式(usr): arm处理器正常的程序执行状态* 快速中断模式(fiq):用于高速数据传输或通道处理* 外部中断模式(irq):用于通用的中断处理* 超级保护模式(svc):操作系统使用的保护模式* 数据访问终止模式(abt):当数据或指令预取终止时进入该模式,可用于虚拟存储及存储保护* 系统模式(sys):运行具有特权的操作系统任务* 未定义指令中止模式(und):当未定义的指令执行时进入该模式,可用于支持硬件协处理器的软件仿真* 通过设置ARM的CPSR寄存器,让CPU运行在操作系统保护模式,为后面进行其它操作作好准备了。