第五讲 TI嵌入式处理器的启动及uBOOT分析
嵌入式启动流程 汇编代码解析
嵌入式启动流程:汇编代码解析1.加载引导程序嵌入式系统在加电后,第一个执行的程序通常是引导程序(Bootloader)。
它负责从存储设备中加载并执行后续的程序。
引导程序通常在启动时进行硬件设备的自检,然后从特定的存储位置(如闪存或RAM)加载后续程序。
引导程序通常使用汇编语言编写,因为它需要在硬件级别进行操作。
它负责初始化CPU、内存、硬盘等硬件设备,并确保系统环境满足后续程序的要求。
2.初始化硬件设备在引导程序之后,接下来的任务是初始化硬件设备。
这包括初始化CPU、内存、硬盘、显示器等设备。
初始化硬件设备的过程包括设置设备的寄存器、配置设备的接口等。
在这个过程中,硬件设备被配置为适合后续程序运行的状态。
3.设置内存管理器在硬件设备初始化完成后,接下来需要设置内存管理器。
内存管理器负责管理系统的内存资源,包括内存的分配、释放和保护。
内存管理器通常由操作系统内核提供,因此在加载操作系统内核之前,需要先初始化内存管理器。
4.加载操作系统内核在内存管理器初始化完成后,可以加载操作系统内核。
操作系统内核是系统的核心部分,负责管理系统资源、调度应用程序的运行等。
操作系统内核通常被压缩并保存在存储设备中,因此需要先解压缩并加载到内存中。
然后,内核会进行自身的初始化,包括设置系统时钟、配置设备驱动等。
5.启动内核并初始化系统服务在操作系统内核加载并初始化完成后,可以启动内核并初始化系统服务。
系统服务是指为应用程序提供支持的底层服务,如文件系统、网络服务等。
启动内核后,会执行一系列的系统初始化过程,包括设置系统环境变量、加载系统服务等。
这些过程完成后,系统就可以接受应用程序的请求并为其提供服务。
6.加载文件系统和应用程序在系统服务初始化完成后,可以加载文件系统和应用程序。
文件系统是存储和管理文件数据的系统,应用程序则是为用户提供服务的程序。
文件系统通常被加载到内存中,并初始化为可用的状态。
然后,可以按需加载应用程序到内存中并执行。
嵌入式linux系统的启动流程
嵌入式linux系统的启动流程
嵌入式Linux系统的启动流程一般包括以下几个步骤:
1.硬件初始化:首先会对硬件进行初始化,例如设置时钟、中
断控制等。
这一步骤通常是由硬件自身进行初始化,也受到系统的BIOS或Bootloader的控制。
2.Bootloader引导:接下来,系统会从存储介质(如闪存、SD
卡等)的Bootloader区域读取引导程序。
Bootloader是一段程序,可以从存储介质中加载内核镜像和根文件系统,它负责进行硬件初始化、进行引导选项的选择,以及加载内核到内存中。
3.Linux内核加载:Bootloader会将内核镜像从存储介质中加载到系统内存中。
内核镜像是包含操作系统核心的一个二进制文件,它由开发者编译并与设备硬件特定的驱动程序进行连接。
4.内核初始化:一旦内核被加载到内存中,系统会进入内核初
始化阶段。
在这个阶段,内核会初始化设备驱动程序、文件系统、网络协议栈等系统核心。
5.启动用户空间:在内核初始化完毕后,系统将启动第一个用
户空间进程(init进程)。
init进程会读取并解析配置文件(如
/etc/inittab)来决定如何启动其他系统服务和应用程序。
6.启动其他系统服务和应用程序:在用户空间启动后,init进
程会根据配置文件启动其他系统服务和应用程序。
这些服务和应用程序通常运行在用户空间,提供各种功能和服务。
以上是嵌入式Linux系统的基本启动流程,不同的嵌入式系统可能会有一些差异。
同时,一些特定的系统也可以添加其他的启动流程步骤,如初始化设备树、加载设备固件文件等。
《嵌入式ARM教案》课件
《嵌入式ARM教案》PPT课件第一章:嵌入式系统概述1.1 嵌入式系统的定义介绍嵌入式系统的概念、特点和应用领域强调嵌入式系统与传统计算机系统的区别1.2 嵌入式系统的发展回顾嵌入式系统的发展历程探讨未来嵌入式系统的发展趋势1.3 嵌入式系统的组成部分介绍嵌入式系统的硬件和软件组成解释嵌入式系统中的核心部件:中央处理器(CPU)第二章:ARM处理器简介2.1 ARM处理器的发展历程介绍ARM公司的成立和发展历程讲解ARM处理器的命名规则和版本更新2.2 ARM处理器的特点阐述ARM处理器的架构和指令集特点强调ARM处理器的功耗、性能和成本优势2.3 ARM处理器的应用领域分析ARM处理器在不同领域的应用案例展望ARM处理器在未来的应用前景第三章:ARM指令集和编程3.1 ARM指令集概述介绍ARM指令集的分类和特点讲解ARM指令的格式和操作码3.2 ARM指令的执行过程分析ARM指令的取指、译码、执行和写回过程解释ARM指令的流水线结构和流水线优化3.3 ARM编程实例介绍ARM编程的基本方法和技巧提供简单的ARM编程实例,让学员了解编程过程第四章:嵌入式系统设计和开发流程4.1 嵌入式系统设计原则讲解嵌入式系统设计的关键原则强调嵌入式系统设计的灵活性和可扩展性4.2 嵌入式系统开发流程介绍嵌入式系统开发的各个阶段阐述各阶段的主要任务和注意事项4.3 嵌入式系统开发工具和环境讲解常用的嵌入式系统开发工具和软件介绍嵌入式系统开发环境搭建的步骤和方法第五章:嵌入式系统硬件设计5.1 嵌入式系统硬件设计概述介绍嵌入式系统硬件设计的基本要求强调嵌入式系统硬件设计的可靠性和稳定性5.2 嵌入式系统硬件模块设计讲解嵌入式系统中的主要硬件模块分析各个模块的功能和相互之间的关系5.3 嵌入式系统硬件设计实例提供嵌入式系统硬件设计实例让学员了解硬件设计过程和注意事项第六章:嵌入式系统软件开发6.1 嵌入式操作系统概述介绍嵌入式操作系统的概念和分类强调嵌入式操作系统在嵌入式系统中的重要性6.2 嵌入式操作系统原理讲解嵌入式操作系统的核心组件和工作原理解释嵌入式操作系统的任务调度和资源管理6.3 嵌入式软件开发介绍嵌入式软件开发的基本方法和技巧提供嵌入式软件开发实例,让学员了解开发过程第七章:嵌入式系统应用案例分析7.1 嵌入式系统在工业控制中的应用分析嵌入式系统在工业控制领域的应用案例强调嵌入式系统在提高工业生产效率方面的作用7.2 嵌入式系统在消费电子中的应用讲解嵌入式系统在消费电子领域的应用案例探讨嵌入式系统在智能家居、可穿戴设备等领域的应用前景7.3 嵌入式系统在其他领域的应用介绍嵌入式系统在医疗、交通、教育等领域的应用案例展望嵌入式系统在未来各个领域的发展趋势第八章:嵌入式系统安全与防护8.1 嵌入式系统安全概述讲解嵌入式系统安全的重要性介绍嵌入式系统面临的安全威胁和攻击手段8.2 嵌入式系统安全防护策略阐述嵌入式系统安全防护的技术和方法强调安全防护策略在提高嵌入式系统安全性方面的作用8.3 嵌入式系统安全案例分析分析典型的嵌入式系统安全案例让学员了解嵌入式系统安全防护的实践应用第九章:嵌入式系统发展趋势与挑战9.1 嵌入式系统技术发展趋势分析嵌入式系统技术的发展趋势强调创新技术和新兴领域对嵌入式系统的影响9.2 嵌入式系统面临的挑战讲解嵌入式系统在发展过程中面临的挑战探讨应对挑战的方法和策略9.3 我国嵌入式系统发展现状与展望介绍我国嵌入式系统发展的现状展望我国嵌入式系统未来的发展前景第十章:总结与展望10.1 课程回顾总结本课程的主要内容和知识点强调嵌入式ARM教案在实际应用中的重要性10.2 实践与思考鼓励学员在实际工作中运用嵌入式ARM教案的知识提出针对性的思考题,引导学员深入思考和探索10.3 未来展望展望嵌入式系统领域的未来发展趋势强调继续学习和不断提升自身能力的重要性重点解析本文教案主要围绕嵌入式ARM系统进行讲解,涵盖了嵌入式系统的概述、ARM 处理器简介、ARM指令集和编程、嵌入式系统设计和开发流程、嵌入式系统硬件设计、嵌入式系统软件开发、嵌入式系统应用案例分析、嵌入式系统安全与防护、嵌入式系统发展趋势与挑战以及课程总结与展望等内容。
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中还有这些异常对应的异常处理程序。
arm cortex 的启动流程
arm cortex 的启动流程ARM Cortex是一种高性能的处理器架构,广泛应用于各种嵌入式系统中。
在使用ARM Cortex处理器时,启动流程是非常重要的一步,它决定了系统的稳定性和可靠性。
下面我们来详细了解一下ARM Cortex的启动流程。
ARM Cortex处理器的启动流程可以分为两个阶段:复位阶段和启动阶段。
在复位阶段,处理器会执行一系列的初始化操作,包括清除寄存器、初始化时钟、设置中断向量表等。
在启动阶段,处理器会加载操作系统或应用程序,并开始执行。
在复位阶段,处理器会首先执行复位向量,这是一个特殊的地址,指向处理器的复位程序。
复位程序会执行一系列的初始化操作,包括清除寄存器、初始化时钟、设置中断向量表等。
其中,中断向量表是一个非常重要的数据结构,它包含了所有中断的入口地址。
在初始化时,处理器会将中断向量表加载到内存中,并设置中断向量表的地址。
在启动阶段,处理器会加载操作系统或应用程序,并开始执行。
在ARM Cortex处理器中,启动代码通常是由Bootloader程序完成的。
Bootloader程序是一个小型的程序,它负责加载操作系统或应用程序,并将控制权转交给它们。
在启动过程中,Bootloader程序会执行一系列的初始化操作,包括初始化内存、初始化外设等。
然后,它会加载操作系统或应用程序,并将控制权转交给它们。
在ARM Cortex处理器中,启动代码通常是由汇编语言编写的。
汇编语言是一种低级语言,它可以直接操作处理器的寄存器和内存。
在编写启动代码时,需要非常小心,确保代码的正确性和可靠性。
同时,还需要考虑处理器的架构和特性,以便充分发挥处理器的性能和功能。
ARM Cortex处理器的启动流程是非常重要的一步,它决定了系统的稳定性和可靠性。
在编写启动代码时,需要非常小心,确保代码的正确性和可靠性。
同时,还需要考虑处理器的架构和特性,以便充分发挥处理器的性能和功能。
UBOOT源码分析
UBOOT源码分析UBOOT是一种开放源码的引导加载程序。
作为嵌入式系统启动的第一阶段,它负责初始化硬件设备、设置系统环境变量、加载内核镜像以及跳转到内核开始执行。
Uboot的源码是开放的,让我们可以深入了解其内部工作机制和自定义一些功能。
Uboot源码的文件组织结构非常清晰,主要分为三个大类:目录、文件和配置。
其中目录包含了一系列相关的文件,文件存放具体的源码实现代码,配置文件包含了针对特定硬件平台的配置选项。
Uboot源码的核心部分是启动代码,位于arch目录下的CPU架构相关目录中。
不同的CPU架构拥有不同的启动代码实现,如arm、x86等。
这些启动代码主要包括以下几个关键功能:1. 初始化硬件设备:Uboot首先需要初始化硬件设备,例如设置时钟、中断控制器、串口等设备。
这些初始化操作是在启动代码中完成的。
通过查看该部分代码,我们可以了解硬件的初始化过程,以及如何配置相关寄存器。
2. 设置启动参数:Uboot启动参数存储在一个称为"bd_info"的数据结构中,它包含了一些关键的设备和内存信息,例如DRAM大小、Flash 大小等。
这些参数是在启动代码中设置的,以便内核启动时能够正确识别硬件情况。
3. 加载内核镜像:Uboot负责加载内核镜像到内存中,以便内核可以正确执行。
在启动代码中,会通过读取Flash设备或者网络等方式,将内核镜像加载到指定的内存地址处。
加载过程中,可能会进行一些校验和修正操作,以确保内核数据的完整性。
4. 启动内核:在内核镜像加载完成后,Uboot会设置一些寄存器的值,并执行一个汇编指令,跳转到内核开始执行。
此时,Uboot的使命即结束,控制权交由内核处理。
除了启动代码,Uboot源码中还包含了许多其他功能模块,如命令行解析器、存储设备驱动、网络协议栈等。
这些功能模块可以根据需求进行配置和编译,以满足不同平台的需求。
例如,可以通过配置文件选择启用一些功能模块,或者自定义一些新的功能。
arm版本linux系统的启动流程
arm版本linux系统的启动流程ARM架构是一种常见的处理器架构,被广泛应用于嵌入式设备和移动设备中。
在ARM版本的Linux系统中,启动流程是非常重要的,它决定了系统如何从开机到正常运行。
本文将详细介绍ARM版本Linux系统的启动流程。
一、引导加载程序(Bootloader)引导加载程序是系统启动的第一阶段,它位于系统的固化存储器中,比如ROM或Flash。
在ARM版本的Linux系统中,常用的引导加载程序有U-Boot和GRUB等。
引导加载程序的主要功能是加载内核镜像到内存中,并将控制权转交给内核。
二、内核初始化引导加载程序将内核镜像加载到内存后,控制权被转交给内核。
内核初始化是系统启动的第二阶段,它主要完成以下几个步骤:1. 设置异常向量表:ARM架构中,异常是指硬件产生的中断或故障,比如系统调用、中断请求等。
内核需要设置异常向量表,以便正确处理异常。
2. 初始化处理器:内核对处理器进行初始化,包括设置页表、启用缓存、初始化中断控制器等。
3. 启动第一个进程:内核创建第一个用户进程(一般是init进程),并将控制权转交给它。
init进程是系统中所有其他进程的父进程,负责系统的初始化工作。
三、设备树(Device Tree)设备树是ARM版本Linux系统中的一种机制,用于描述硬件设备的相关信息。
在内核初始化过程中,内核会解析设备树,并建立设备树对象,以便后续的设备驱动程序使用。
设备树描述了硬件设备的类型、地址、中断等信息,以及设备之间的连接关系。
它使得内核能够在运行时自动识别和配置硬件设备,大大提高了系统的可移植性和灵活性。
四、启动初始化(Init)启动初始化是系统启动的第三阶段,它是用户空间的第一个进程(init进程)接管系统控制权后的操作。
启动初始化主要完成以下几个任务:1. 挂载根文件系统:启动初始化会挂载根文件系统,使得用户可以访问文件系统中的文件和目录。
2. 加载系统服务:启动初始化会加载并启动系统服务,比如网络服务、日志服务、时间同步服务等。
U-BOOT介绍以及常用U-bot命令介绍
U-BOOT介绍以及常用U-bot命令介绍一. BootLoader简介在专用的嵌入式板子运行GNU/Linux系统已经变得越来越流行。
一个嵌入式Linux系统从软件的角度看通常可以分为四个层次:1、引导加载程序。
包括固化在固件(firmware)中的boot代码(可选),和BootLoader两大部分。
2、 Linux内核。
特定于嵌入式板子的定制内核以及内核的启动参数。
3、文件系统。
包括根文件系统和建立于Flash内存设备之上文件系统。
通常用ramdisk来作为rootfs。
4、用户应用程序。
特定于用户的应用程序。
有时在用户应用程序和内核层之间可能还会包括一个嵌入式图形用户界面。
常用的嵌入式GUI有:MicroWindows和MiniGUI懂。
引导加载程序是系统加电后运行的第一段软件代码。
PC机中的引导加载程序由BIOS(其本质就是一段固件程序)和位于硬盘MBR中的OS BootLoader(比如,LILO和GRUB等)一起组成。
BIOS在完成硬件检测和资源分配后,将硬盘MBR中的BootLoader读到系统的RAM中,然后将控制权交给OS BootLoader。
BootLoader的主要运行任务就是将内核映象从硬盘上读到 RAM 中,然后跳转到内核的入口点去运行,也即开始启动操作系统。
而在嵌入式系统中,通常并没有像BIOS那样的固件程序(注,有的嵌入式CPU也会内嵌一段短小的启动程序),因此整个系统的加载启动任务就完全由BootLoader来完成。
比如在一个基于ARM7TDMI core的嵌入式系统中,系统在上电或复位时通常都从地址0x00000000处开始执行,而在这个地址处安排的通常就是系统的BootLoader程序。
简单地说,BootLoader就是在操作系统内核运行之前运行的一段小程序。
通过这段小程序,我们可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核准备好正确的环境。
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/中还有这些异常对应的异常处理程序。
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 等操作系统的引导。
嵌入式程序执行流程
嵌入式程序执行流程嵌入式系统是一种专门设计用于特定应用领域的计算机系统,它通常被嵌入到各种设备中,如手机、汽车、家电等。
嵌入式系统的核心是嵌入式程序,它负责控制设备的各种功能和操作。
在嵌入式系统中,程序的执行流程是至关重要的,它直接影响着设备的性能和稳定性。
嵌入式程序执行流程通常包括以下几个关键步骤:1. 启动和初始化,当嵌入式系统上电或者重启时,首先会执行启动和初始化的过程。
这个过程包括硬件初始化、内存分配、外设初始化等操作,确保系统能够正常工作。
2. 软件加载,一旦系统初始化完成,嵌入式程序会被加载到系统中。
通常,嵌入式程序会被存储在闪存或者EEPROM等非易失性存储器中,然后通过引导程序加载到系统的内存中。
3. 程序执行,一旦程序被加载到内存中,CPU开始执行程序的指令。
程序的执行流程包括各种操作,如数据处理、控制流程、输入输出等,以实现设备的各种功能。
4. 中断处理,在程序执行的过程中,设备可能会产生各种中断,如定时器中断、外部设备中断等。
嵌入式系统需要及时响应这些中断,并执行相应的中断服务程序。
5. 系统关闭,当设备需要关闭时,嵌入式程序会执行相应的关闭操作,如保存数据、关闭外设等,最终将系统关闭。
嵌入式程序执行流程的设计和优化对于嵌入式系统的性能和稳定性至关重要。
合理的程序结构、高效的算法和良好的中断处理能力都是影响程序执行流程的关键因素。
同时,对于不同的嵌入式系统,其程序执行流程可能会有所不同,需要根据具体的应用需求进行定制和优化。
总之,嵌入式程序执行流程是嵌入式系统运行的核心,它直接关系到设备的功能实现和性能表现。
因此,在嵌入式系统设计和开发过程中,需要充分考虑和优化程序执行流程,以确保系统的稳定性和高效性。
uboot 代码运行流程
uboot 代码运行流程U-Boot代码运行流程U-Boot(Universal Bootloader)是一个开源的引导加载程序,广泛应用于嵌入式系统中。
它负责在系统上电后初始化硬件并加载操作系统内核,是系统启动的重要一环。
下面将从U-Boot代码的运行流程方面进行介绍。
1. 启动阶段当系统上电后,处理器会从预定义的存储器地址开始运行代码。
U-Boot的启动代码通常存放在ROM中,处理器会从ROM的起始地址开始执行。
启动代码负责初始化处理器和一些外设,然后跳转到U-Boot的入口点。
2. 入口点U-Boot的入口点是指U-Boot的main()函数。
在启动代码的最后,会调用main()函数,从而进入U-Boot的主循环。
U-Boot的主循环负责处理用户输入的命令,并根据命令执行相应的操作。
3. 硬件初始化在main()函数中,首先会进行硬件的初始化工作。
这包括初始化串口、初始化存储器控制器、初始化网络接口等。
硬件初始化的目的是为了确保系统能够正常运行,并为后续的操作做好准备。
4. 系统启动硬件初始化完成后,U-Boot会尝试从存储设备(如闪存、SD卡)中加载操作系统内核镜像。
U-Boot会根据预定义的启动命令(例如bootcmd)来确定从哪个设备加载内核镜像,并执行相应的加载操作。
加载完成后,U-Boot会将控制权交给操作系统内核,进入操作系统的启动阶段。
5. 用户交互一般情况下,U-Boot会在系统启动后进入命令行界面,等待用户输入命令。
用户可以通过串口、网络等方式与U-Boot进行交互,执行各种操作,例如烧写固件、修改配置等。
U-Boot提供了丰富的命令集,可以满足不同的需求。
6. 系统重启当用户输入重启命令或系统发生异常时,U-Boot会执行系统重启操作。
重启操作包括重新初始化硬件、重新加载内核镜像等步骤,以重新启动系统。
U-Boot会将控制权交给重新加载的内核,然后进入内核的启动流程。
总结:U-Boot代码的运行流程包括启动阶段、入口点、硬件初始化、系统启动、用户交互和系统重启等几个关键步骤。
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处继续执行。
[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二进制结构U-Boot二进制结构U-Boot是一个开源的引导加载程序,常用于嵌入式系统中。
它的二进制结构是由一系列特定格式的数据组成,这些数据用于实现引导加载、初始化硬件和启动操作系统等功能。
本文将详细介绍U-Boot 二进制结构的各个部分。
1. 引导代码段(Boot Code)引导代码段是U-Boot二进制结构中的第一部分,它负责初始化处理器和外设,并加载后续的引导阶段所需的代码和数据。
引导代码段通常由汇编语言编写,它包含了一系列底层的初始化和配置代码。
在引导过程中,处理器会首先执行引导代码段。
2. 配置数据段(Configuration Data)配置数据段是U-Boot二进制结构中的第二部分,它包含了U-Boot 的配置信息,如启动参数、设备树(Device Tree)等。
启动参数是一组用于指定启动参数的字节序列,包括启动命令、内核镜像地址、根文件系统地址等。
设备树是一种描述硬件设备和系统配置的数据结构,它提供了硬件设备的详细信息,如设备类型、中断号、寄存器地址等。
3. 命令解析器(Command Interpreter)命令解析器是U-Boot二进制结构中的第三部分,它负责解析用户输入的命令,并执行相应的操作。
U-Boot提供了丰富的命令集,用户可以通过命令解析器来执行各种操作,如加载内核镜像、启动操作系统、修改配置参数等。
命令解析器使用类似于Shell的语法,用户可以通过命令行交互式地与U-Boot进行操作。
4. 设备驱动程序(Device Drivers)设备驱动程序是U-Boot二进制结构中的第四部分,它负责管理和操作硬件设备。
U-Boot提供了各种设备驱动程序,如串口驱动程序、网络驱动程序等,用于与外部设备进行通信。
设备驱动程序通过与硬件设备的接口交互,实现了对硬件设备的控制和管理。
5. 文件系统支持(Filesystem Support)文件系统支持是U-Boot二进制结构中的第五部分,它提供了对各种文件系统的支持。
uboot启动流程
uboot启动流程U-Boot是一款开源的嵌入式引导加载程序(bootloader),主要用于嵌入式系统的引导启动。
它是一个跨平台的引导加载程序,可以在不同的处理器架构和操作系统上运行。
下面将介绍U-Boot的启动流程。
U-Boot启动流程主要包括三个阶段:启动ROM代码、启动SPL(Secondary Program Loader)和启动U-Boot。
首先,当嵌入式设备上电后,处理器会首先执行固定在芯片内部的启动ROM代码。
这些代码主要完成一些基本的硬件初始化工作,例如设置栈指针、初始化外设等。
然后,启动ROM 代码会从预定义的启动设备(例如闪存、SD卡等)中加载SPL。
接下来,SPL(Secondary Program Loader)被加载到内存中执行。
SPL是一个较小的引导加载程序,主要作用是完成一些必要的初始化和硬件配置。
SPL会初始化内存控制器、外设等,并加载U-Boot镜像到内存中。
最后,U-Boot被加载到内存中执行。
U-Boot是一个功能强大的引导加载程序,拥有丰富的命令和功能。
它可以根据不同的系统配置进行配置和扩展,并提供了丰富的调试和测试功能。
U-Boot的启动流程主要可以分为以下几个步骤:1. CPU初始化:U-Boot开始执行后,首先进行CPU的初始化工作,包括设置栈指针、cache的初始化等。
2. 设备初始化:接下来,U-Boot会初始化外设设备,例如串口、网络接口等。
这些设备的初始化是为了后续的调试和配置工作做准备。
3. 系统环境的初始化:U-Boot会读取存储在非易失性存储设备(例如NAND闪存、SD卡等)中的环境变量,根据这些变量进行系统的初始化配置。
4. 设备驱动的加载:U-Boot会加载并初始化必要的设备驱动程序,以便后续的硬件操作可以正常进行。
5. 启动命令的执行:U-Boot会根据配置文件中的设置,执行预定义的启动命令。
这些命令可以是启动操作系统、加载应用程序等。
嵌入式系统BootLoader的设131页PPT
① 设置中断向量表
1
设置
中断向量表
2
最小硬件 初始化
RTOS运行环境
3
初始化
最 小 启从 0x00000000开始的8*4个字节的连续存储 空间中,其作用是指定了各种异常中断 处理程序的入口地址。
22
嵌入式系统的初始化流程(2)
硬件初始化阶段
② 最小硬件初始化
BootLoader是系统加电(或复位)后运行的第一段软件 代码。通过这段代码,我们可以初始化系统硬件设备、建 立内存空间的映射图,从而将系统的软硬件环境带到一个 合适的状态,以便最终调用操作系统内核。
简单地说,BootLoader就是在操作系统内核运行之前运 行的一段初始化程序。
15
BootLoader的特点
6 启动RTOS
phase2
运行优先级最高的就绪任务; 启动RTOS时钟中断。
27
嵌入式系统的初始化流程(7)
用户程序初始化阶段
⑦ 用户程序初始化
用户程序
7
初始化
用户程序
用户程序正常运行所进行的初始化。
28
Phase 2 操作系统移植
1 BootLoader 2 系统初始化流程 3 最小启动代码编写 4 µC/OS-II相关文件修改
20
嵌入式系统的初始化流程
硬件 初始化
1
设置 中断向量表
2
最小硬件 初始化
3
RTOS运行环境 初始化
最 小 启 动 phase1 代 码
4 硬件抽象层 初始化
RTOS 初始化
5
RTOS 初始化
phase2
6 启动RTOS
软件 初始化
7
用户程序 初始化
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。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
2012/11/16
美国德州仪器
15
基于Beagle Board嵌入式处理器的系统开发
4、头文件
头文件位于源码树下的include中,其中各种主板的配置文 件位于include/configs文件夹中,比如omap730主板的配置 文件为include/configs/omap730.h。 目录include/asm-***是一些比较底层的头文件,编译时会 根据不同的配置与include/configs/asm建立一个符号链接。
UBL函数入口点是flash_utils目录下的 Common/arch/arm926ejs/start.S。 程序首先设置了堆栈 指针寄存器,然后将 main_entry地址赋值给 r0寄存器,也就是 main的入口点赋值给 r0寄存器,然后将pc 指针指向main入口点, 程序跳到main函数执 行。
9
基于Beagle Board嵌入式处理器的系统开发
二、U-Boot源码框架内容分析
uBoot源码各个目录和代码结构。 uBoot的启动过程分析。 uBoot如何实现自定义的命令。 uBoot如何将参数传递给内核进行解析。
2012/11/16
美国德州仪器
10
基于Beagle Board嵌入式处理器的系统开发
第二类命令是“有去无回”的命令,类似于bootm 0x8000000或者go 0x8000000,这类指令最终将去启动 内核,以此系统将不再返回。
2012/11/16
美国德州仪器
25
基于Beagle Board嵌入式处理器的系统开发
网络传输代码位于目录net下面,arp.c,bootp.c,eth.c, tftp.c等都在这里,BOOTP,TFTP,以太网初始化等功能的实 现也是由这些代码完成的。
2012/11/16 美国德州仪器 22
基于Beagle Board嵌入式处理器的系统开发
在该无限循环中,首先调用readline(CFG_PROMPT)从终端获取相应 的命令。然后判断命令长度,若终端输入的仅仅是一个回车的操作符时, u-boot将把其解释成重复上次操作的命令,因此置位相应的flag位 “flag|=CMD_FLAG_REPEAT;”
3、与CPU相关的代码
cpu相关的代码位于cpu目录下,在该目录下,列出 了当前版本的u-boot所能支持的所有cpu类型。和目 标板相关的代码类似,该目录的每个子目录都对应 一种具体的cpu类型。
2012/11/16
美国德州仪器
13
基于Beagle Board嵌入式处理器的系统开发
uboot所支持的cpu类型
2012/11/16 美国德州仪器 6
基于Beagle Board嵌入式处理器的系统开发
根据不同的boot模式,执行将uboot镜像从不同存储设备拷 贝到内存的操作,此处通过NANDBOOT_copy来简单分析。
2012/11/16
美国德州仪器
7
基于Beagle Board嵌入式处理器的系统开发
2012/11/16 美国德州仪器 24
基于Beagle Board嵌入式处理器的系统开发
调用run_command()去解析执行相应的命令。对于 U-Boot而言总共有两类命令,一类命令执行后能够返 回的,对于此类命令,该处还将判断返回值,若返回 值不对,证明这是一条无效的命令,把全局变量 lastcommand置为空,因此下次若想再以回车来执行无 效命令时,就不会再去执行一遍无效命令
NANDBOOT_copy函数最后将uboot的入口点赋值给 gEntryPoint,该变量是在main函数上定义的全局变量,该 变量在main函数最后当做一个函数指针来执行,也就是跳 转到DDR的uboot起始地址处执行,至此,UBL工作完毕, 控制权交给了uboot。
2012/11/16
美国德州仪器
基于Beagle Board嵌入式处理器的系统开发
TI嵌入式处理器的启动以及 uBOOT分析
2012/11/16
美国德州仪器
1
基于Beagle Board嵌入式处理器的系统开发
一、UBL源码结构分析
二
2012/11/16
美国德州仪器
2012/11/16
美国德州仪器
5
基于Beagle Board嵌入式处理器的系统开发
LOCAL_boot中,首先判断板子启动模式,也就是板子上 的拨码开关的设置,DEVICE_bootMode通过读取SYSTEM 控制寄存器来获取拨码开关的信息。 执行DEVICE_init执行板级初始化,包括电源、时钟、 DDR、EMIF、UART、I2C、TIMER等。
环境变量文件:包括environment.c和所有以env_打头的文件, 其中environment.c是环境变量相关的入口文件。 C函数入口文件main.c:当cpu和板级初始化后,将调用 main_loop()进入一个无限循环,等待界面发出命令或者直 接执行虚设的某些命令 命令解析文件:命令解析文件包含command.c和所有以cmd_ 打头的文件,其中command.c是所有以cmd_打头的命令文 件的入口文件。
2012/11/16
美国德州仪器
26
基于Beagle Board嵌入式处理器的系统开发
三、U-Boot 启动流程简要分析
U-Boot 启动内核的过程可以分为两个阶段,两个阶段功能如下:
第一阶段的功能 Ø 硬件设备初始化 Ø 加载U-Boot第二阶段代码到RAM空间 Ø 设置栈 Ø 跳转到第二阶段代码入口 第二阶段的功能 Ø 初始化本阶段使用的硬件设备 Ø 检测系统内存映射 Ø 将内核从Flash读取到RAM中 Ø 为内核设置启动参数 Ø 调用内核 下面我们以DM365为例对启动过程进行说明:
2012/11/16 美国德州仪器 14
基于Beagle Board嵌入式处理器的系统开发
由上图可以看出,该U-boot版本已经支持多种系 列的cpu,可以看出u-boot是一种被广泛使用的 bootloader。 在具体cpu对应的目录中,一般包含以下文件: Config.mk,该文件主要包含一些编译选项,该 文件将被相同目录下的Makefile所引用。 Makefie,程序编译规则。 Start.S,启动代码,真正U-Boot映像的入口点。 其它一些cpu初始化代码。
2012/11/16
美国德州仪器
18
基于Beagle Board嵌入式处理器的系统开发
5、公共代码
该目录下的代码构成了uboot的基本框架,也是u-boot的精 髓所在,因为板级相关的代码和cpu相关的代码往往都是 由cpu厂商按u-boot的规则提供的,目的是推广目标板或芯 片,但这些公共的代码则是由Denx项目组成员开发和维护 的。其目的是提供一套不同目标板的共性,比如在引导时 与目标板的信息交互、环境变量的设置等,这样就可以省 去具体BSP包开发人员很多的工作量。而且U-Boot中这些 公共文件做的非常完善,应该能够满足大部分嵌入式系统 开发的要求,比如支持各式各样的命令,这些都是u-boot 非常突出的优点。
1、Uboot目录结构图:
• • • • • • • • • • • • • 与目标板相关的代码,对应board目录。 公共代码,对应于common目录。 与cpu相关的代码,对应于cpu目录。 磁盘驱动和磁盘分区相关的处理代码,对 应于disk目录。 说明文档,对应于doc目录。 关键的驱动程序,对应于drivers目录。 简单的应用历程,对应于example目录。 头文件,对应于include目录。 体系结构相关的代码,对应于lib_arm等目 录。 体系结构无关的代码,对应于lib_generic目 录。 网络传输代码,对应于net目录。 上电自检代码对应于post目录。 U-Boot常用工具,对应于tools目录。
2012/11/16
美国德州仪器
21
基于Beagle Board嵌入式处理器的系统开发
首先获取环境变量中有关bootdelay的定义。此参数说明了启动时预留的人工干预 时间,若在指定的时间内无人干预,那么U-Boot将执行默认的启动命令序列,即执 行环境变量中“bootcmd”中相关的设置。当然,若“bootcmd”没有定义时,系统 将打印提示符界面,等待用户输入具体的指令去干预系统的行为。 通过调用getenv(“bootcmd”)获取环境变量中“bootcmd”相关的设置,然后调用 run_command()去执行相应的启动命令序列。
2012/11/16 美国德州仪器 23
基于Beagle Board嵌入式处理器的系统开发
但并未改变全局变量lastcommand。当命令的长度不为0时,意味着用 户确实输入了相应的命令,因此将调用strcpy(lastcommad, console_buffer)把全局变量置位为当前的命令,以此实现了命令的更替。
2012/11/16
美国德州仪器
11
基于Beagle Board嵌入式处理器的系统开发
2、与目标板相关的代码
在U-Boot中,目标板相关的代码都位于board目录,在该目录下,列 出了当前版本的U-Boot所能支持的所有目标板。目前U-Boot支持大 多数比较常见的目标板,如Motorola的FADS板,TI的Omap系列等。 源码树中board目录下的每个文件夹对应一个目标板,比如 board/fads,board/omap730p2。在该版本(1.3.4)中共有250个文件夹, 说明支持250种常用的目标板。 在每个目标板对应的目录中,一般至少包含以下文件:
NANDBOOT_copy函数首先执行NAND初始化,然后从 Nand中读取页面信息,查找uboot开始位置,由magicNum 的检测可以看出,确定uboot的位置是通过maginNum来进 行的,最后将uboot拷贝到DDR中。