精华内容
下载资源
问答
  • 而在嵌入式系统中,通常并没有像 BIOS 那样的固件程序,启动时用于完成初始化操作的这段代码被称为Bootloader程序,因此整个系统的加载启动任务就完全由Bootloader 来完成。简单地说,通过这段程序,可以初始化硬件...
  • 大多数Bootloader 都包含两种不同的操作模式: “启动加载”模式和“下载”模式,这种区别仅对于开发人员才有意义。 启动加载模式:这种模式也称为“自主”模式。也就是 Bootloader 从目标机上的某...

    1.概述

    Bootloader,简而言之就是:它是一段小程序,在系统上电时开始执行,主要功能是初始化硬件设备、准备好软件环境,最后调用操作系统内核。

    Bootloader 的操作模式。大多数Bootloader 都包含两种不同的操作模式: “启动加载”模式和“下载”模式,这种区别仅对于开发人员才有意义。 

    启动加载模式:这种模式也称为“自主”模式。也就是 Bootloader 从目标机上的某个固态存储设备上将操作系统加载到 RAM 中运行,整个过程并没有用户的介入。这种模式是嵌入式产品发布时的通用模式。工作在启动加载模式时,uboot会自动执行bootcmd命令,比如:bootcmd=“nand read 0x100000 0x80000000 0x300000; bootm 0x80000000”。

    下载模式:在这种模式下,目标机上的 Bootloader 将通过串口连接或网络连接等通信手段从主机(Host)下载文件,比如:下载内核映像和根文件系统映像等。从主机下载的文件通常首先被 Bootloader 保存到目标机的 RAM 中,然后再被 Bootloader 写到目标机上的FLASH 类固态存储设备中。Bootloader 的这种模系统是在更新时使用。工作于这种模式下的Bootloader 通常都会向它的终端用户提供一个简单的命令行接口。Bootloader 与主机之间进行文件传输常通过以太网连接并借助TFTP协议来下载文件。Ps:tftp a0000000 uImage;tftp b0000000 ramdisk.bin;tftp 90000000 fsl-ls1046a-rdb.dtb

    2.Bootloader中典型分区结构图

     

    1.标Bootloader中典型分区结构图题
    • Bootloader上电后的第一个程序。
    • Boot parameteres分区中可设置的参数(IP,串口,传递给内核的命令行参数)。
    • DTB设备数文件
    • Rootfs文件系统

    3.Bootloader启动流程

    Bootloader的启动流程一般分两个阶段:

    Stage1(阶段一主要通过汇编语言实现,依赖cpu体系结构初始化

    • 进行硬件的初始化(watchdog,ram初始化)。
    • 为Stage2加载代码准备RAM空间。
    • 复制Stage2阶段代码到RAM空间。
    • 设置好栈。
    • 跳转到第二阶段代码的入口点。

    Stage2(阶段2主要通过c语言实现,具有好的可读性和移植性)

    • 初始化该阶段所用到的硬件设备。
    • 检测系统内存映射。
    • 将uImage ,Rootfs,dtb文件从flash读取到RAM内存中。
    • 设置内核启动参数。(如通过寄存器传递设备树文件的内存地址)

     

     

    展开全文
  • bootloader启动流程

    2018-09-10 10:56:45
    bootloader启动流程
  • 一个嵌入式 Linux 系统从软件角度看可以分为四个部分:引导加载程序(Bootloader), Linux 内核,文件系统,应用程序。当系统首次引导时,或系统被重置时,处理器会执行一个位于Flash/ROM中的已知位置处的代码,...

    一个嵌入式 Linux 系统从软件角度看可以分为四个部分:引导加载程序(Bootloader), Linux 内核,文件系统,应用程序。

    当系统首次引导时,或系统被重置时,处理器会执行一个位于Flash/ROM中的已知位置处的代码,Bootloader就是这第一段代码。它主要用来初始化处理器及外设,然后调用 Linux 内核。Linux 内核在完成系统的初始化之后需要挂载某个文件系统作为根文件系统(Root Filesystem),然后加载必要的内核模块,启动应用程序。这就是嵌入式Linux系统启动过程 Linux 引导的整个过程。

    根文件系统是 Linux 系统的核心组成部分,它可以作为Linux 系统中文件和数据的存储区域,通常它还包括系统配置文件和运行应用软件所需要的库。应用程序可以说是嵌入式系统的“灵魂”,它所实现的功能通常就是设计该嵌入式系统所要达到的目标。如果没有应用程序的支持,任何硬件上设计精良的嵌入式系统都没有实用意义。

    从以上分析可以看出 Bootloader在运行过程中虽然具有初始化系统和执行用户输入的命令等作用,但它最根本的功能就是为了启动 Linux 内核,让我们进一步分析 Bootloader 和 Linux 内核在嵌入式系统中的关系和作用。

    934d4203e4117f50b607f9a4e0320560.png

    Bootloader启动的两个阶段

    从操作系统的角度看,Bootloader的总目标就是正确地调用内核来执行。另外,由于Bootloader的实现依赖于CPU的体系结构,因此大多数Bootloader都分为stage1和stage2两大部分,以便使Bootloader的功能更加强大和提供更加良好的移植性能。

    stage1主要是一些依赖于CPU体系结构的代码,比如硬件设备初始化代码等。这一阶段的代码主要是通过汇编来实现的,已达到短小精悍和高效的目的。stage1为位置无关代码,通常在Flash中运行。所以有的指令为相对寻址,可以在任何位置运行。

    stage1负责的主要任务有:

    ① 硬件设备初始化包括:关闭Watchdog、关闭中断、设置CPU的速度和时钟频率、配置SDRAM存储控制器及IO、关闭处理器内部指令/数据Cache等;

    ② 为加载Bootloader的stage2代码准备RAM空间(这个地址由链接脚本指定为运行域地址,通常为RAM的高端地址)测试内存空间是否有效;

    ③ 复制Bootloader的stage2代码到RAM空间中;

    ④ 设置好堆栈;

    ⑤ 跳转到stage2的C函数入口点。stage2则是通常用C语言来实现,这样可以实现更复杂的功能,而且代码会具有更好的可读性和可移植性。

    stage2负责的主要任务有:

    ① 初始化本阶段要使到的硬件设备(如串口、Flash和网卡等);

    \

    ② 检测系统内存映射;

    ③ 没有用户干预时将内核映像从Flash读到RAM空间中;

    ④ 为内核设置启动参数;

    ⑤ 调用内核。

    Bootloader 的启动方式

    1.网络启动方式

    这种方式的开发板不需要较大的存储介质,跟无盘工作站有点类似,但是使用这种启动方式之前,需要把Bootloader安装到板上的EPROM或者Flash中。Bootloader通过以太网接口远程下载Linux内核映像或者文件系统。Bootloader下载文件一般都使用TFTP网络协议,还可以通过DHCP的方式动态配置IP地址。

    2.硬盘启动方式

    传统的Linux系统运行在台式机或者服务器上,这些计算机一般都使用BIOS引导,并使用磁盘作为存储介质。Linux传统上是LILO (Linux Loader) 引导,后来又出现了GUN的软件 (Grand Unified Bootloader) 。 这两种Bootloader广泛应用在X86的Linux系统上。

    3. Flash启动方式

    大多数嵌入式系统上都使用Flash存储介质。Flash有很多类型,包括NOR Flash、NAND Flash和其它半导体盘。它们之间的不同在于: NOR Flash 支持芯片内执行(XIP, eXecute In Place),这样代码可以在Flash上直接执行而不必拷贝到RAM中去执行。而NAND Flash并不支持XIP,所以要想执行 NAND Flash 上的代码,必须先将其拷贝到 RAM中去,然后跳到 RAM 中去执行。NOR Flash 使用最为普遍。Bootloader一般放在Flash的底端或者顶端,这需要根据处理器的复位向量来进行设置。可以配置成MTD设备来访问Flash分区

    展开全文
  • 简单bootloader制作
  • Bootloader启动流程

    2019-05-24 15:52:52
    学习Bootloader. 1.Bootloader   Microprocessors can execute only code that exists in memory (either ROM or RAM), while operating systems normally reside in large-capacity devices such as hard disks,...
    • 学习Bootloader.

    1.Bootloader

      Microprocessors can execute only code that exists in memory (either ROM or RAM), while operating systems normally reside in large-capacity devices such as hard disks, CD-ROMs, USB disks, network servers, and other permanent storage media.

      When the processor is powered on, the memory doesn’t hold an operating system, so special software is needed to bring the OS into memory from the media on which it resides. This software is normally a small piece of code called the boot loader. On a desktop PC, the boot loader resides on the master boot record (MBR) of the hard drive and is executed after the PC’s basic input output system (BIOS) performs system initialization tasks.

    1.1.What does a bootloader do

      In an embedded Linux system, the bootloader has two main jobs: basic system initialization and the loading of the kernel. In fact, the frst job is somewhat subsidiary to the second in that it is only necessary to get as much of the system working as is needed to load the kernel.

      When the frst lines of bootloader code are executed, following power-on or a reset,the system is in a very minimal state. The DRAM controller will not have been set up so main memory is not accessible, likewise other interfaces will not have been confgured so storage accessed via NAND flash controllers, MMC controllers, and
    so on, are also not usable. Typically, the only resources operational at the beginning
    are a single CPU core and some on-chip static memory. As a result, system bootstrap
    consists of several phases of code, each bringing more of the system into operation.

      At a minimum, a boot loader for an embedded system performs these functions:

    • Initializing the hardware, especially the memory controller
    • Providing boot parameters for the OS
    • Starting the OS

      Most boot loaders provide features that simplify developing and updating firmware; for example:

    • Reading and writing arbitrary memory locations
    • Uploading new binary images to the board’s RAM from mass storage devices
    • Copying binary images from RAM into flash

    1.2.Choosing a bootloader
    在这里插入图片描述

    2.U-Boot

      U-Boot is an open-source, cross-platform boot loader that provides out-of-box support for hundreds of embedded boards and many CPUs, including PowerPC, ARM, XScale, MIPS, Coldfire, NIOS, Microblaze, and x86.

    3.The boot sequence

    3.1.Phase 1 – ROM code

      In the absence of reliable external memory, the code that runs immediately after a reset or power-on has to be stored on-chip in the SoC; this is known as ROM code. It is programmed into the chip when it is manufactured, hence ROM code is proprietary and cannot be replaced by an open source equivalent.

      The only RAM that the ROM code has access to is the small amount of static RAM (SRAM) found in most SoC designs. The size of the SRAM varies from as little as 4 KiB up to a few hundred KiB.

      The ROM code function includes:

    • Loading a small chunk of code from one of several preprogrammed locations into the SRAM.

      In SoCs where the SRAM is not large enough to load a full bootloader like U-Boot, there has to be an intermediate loader called the secondary program loader, or SPL.

      At the end of the second phase, the third stage loader is present in DRAM, and the SPL can make a jump to that area.
    在这里插入图片描述

    3.2.Phase 2 – SPL

      SPL (Secondary Program Loader) is a small binary, generated from U-Boot source, that fits in the SRAM and loads the main U-Boot into system RAM.

      The SPL functions includes:

    • set up the memory controller
    • loading the third stage program loader (TPL) into main memory(DRAM)

      The functionality of the SPL is limited by its size. It can read a program from a list of storage devices, as can the ROM code, once again using preprogrammed offsets from the start of a flash device, or a well known fle name such as u-boot.bin. The following diagram explains the phase 2 architecture:
    在这里插入图片描述

    3.3.Phase 3: TPL

       we are running a full bootloader like U-Boot. Usually, there is a simple command-line user interface that will let you perform maintenance tasks such as loading new boot and kernel images into flash storage, loading and booting a kernel, and there is a way to load the kernel automatically without user intervention.

    The following diagram explains the phase 3 architecture:在这里插入图片描述
      At the end of the third phase, there is a kernel in memory, waiting to be started. Embedded bootloaders usually disappear from memory once the kernel is running and perform no further part in the operation of the system.

    4.The boot process
      After power-up or reset, the processor loads the U-Boot boot loader in several steps.

      The processor does these steps:

    • Executes a primary bootstrap that configures the interrupt and exception vectors, clocks, and SDRAM
    • Decompresses the U-Boot code from flash to RAM
    • Passes execution control to the U-Boot

      U-Boot does these steps:

    • Configures the Ethernet MAC address, flash, and, serial console
    • Loads the settings stored as environment variables in non-volatile memory
    • After a few seconds (a length of time you can program), automatically boots the preinstalled kernel

    5.Moving from bootloader to kernel

      When the bootloader passes control to the kernel it has to pass some basic information to the kernel, which may include:

    • A number unique to the type of the SoC
    • Basic details of the hardware detected including at least the size and
      location of the physical RAM, and the CPU clock speed
    • The kernel command line
    • Optionally, the location and size of a device tree binary
    • Optionally, the location and size of an initial RAM disk

    How to move the information form the bootloader to the kernel?

      The way this information is passed includes:

    • PowerPC, the bootloader simply used to pass a pointer to a board information structure, whereas, with ARM, it passed a pointer to a list of “A tags”.
      Note:In both cases, the amount of information passed was very limited, leaving the bulk of it to be discovered at runtime or hard-coded into the kernel as “platform data”.
    • A better way was needed, the device tree.

    6.小结:
    在这里插入图片描述

    展开全文
  • bootloader启动过程分析

    2013-03-31 21:07:33
    本文详细讲解了bootloader启动过程,对深入理解bootloader和对自己写bootloader有很大帮助。
  • BootLoader启动过程分析

    千次阅读 2014-03-20 00:35:20
    BootLoader启动过程分析  一、 Boot Loader的概念和功能 1、嵌入式Linux软件结构与分布在一般情况下嵌入式Linux系统中的软件主要分为以下及部分: (1)引导加载程序:其中包括内部ROM中的固化启动代码和Boot ...

    BootLoader启动过程分析 


    一、    Boot Loader的概念和功能

    1、嵌入式Linux软件结构与分布在一般情况下嵌入式Linux系统中的软件主要分为以下及部分:

    (1)引导加载程序:其中包括内部ROM中的固化启动代码和Boot Loader两部分。而这个内部固化ROM是厂家在芯片生产时候固化的,作用基本上是引导Boot Loader。有的芯片比较复杂,比如Omap3,他在flash中没有代码的时候有许多启动方式:USB、UART或以太网等等。而S3C24x0则很简单,只有Norboot和Nandboot。

    (2)Linux kernel 和drivers。

    (3)文件系统。包括根文件系统和建立于Flash内存设备之上的文件系统(EXT4、UBI、CRAMFS等等)。它是提供管理系统的各种配置文件以及系统执行用户应用程序的良好运行环境的载体。

    (4)应用程序。用户自定义的应用程序,存放于文件系统之中。
    在Flash 存储器中,他们的 一般分布如下:

     

    但是以上只是大部分情况下的分布,也有一些可能根文件系统是initramfs,被一起压缩到了内核映像里,或者没有Bootloader参数区,等等。

    2、在嵌入式Linux中为什么要有BootLoader
    在linux内核的启动运行除了内核映像必须在主存的适当位置,CPU还必须具备一定的条件:

    【1】CPU寄存器设置:

    R0=0;

    R1=Machine ID(即Machine Type Number,定义在linux/arch/arm/tools/mach-types);

    R2=内核启动参数在RAM中起始基地址;

    【2】CPU模式:

    必须禁止中断(IRQs和FIQs);

    CPU 必须工作在是超级保护模式(SVC) 模式;

    【3】Cache和MMU的设置:

    MMU 必须关闭;

    指令Cache可以打开也可以关闭;

    数据Cache必须关闭;

    但是在CPU刚上电启动的时候,一般连内存控制器都没有配置过,根本无法在内存中运行程序,更不可能处在Linux内核的启动环境中。为了初始化CPU及其他外设,使得Linux内核可以在系统主存中跑起来,并让系统符合Linux内核启动的必备条件,必须要有一个先于内核运行的程序,他就是所谓的引导加载程序(Boot Loader)。

    而Boot Loader并不是Linux才需要,是几乎所有的运行操作系统的设备都具备的。我们的PC的BOIS就是Boot Loader的一部分(只是前期引导,后面一般还有外存中的各种Boot Loader),对于Linux PC来说,Boot Loader = BIOS + GRUB/LILO。

    正如前面所述,Boot Loader是在操作系统内核运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核准备好正确的环境,最后从别处(Flash、以太网、UART)载入内核映像并跳到入口地址。

    由于BootLoader直接操作硬件,所以她严重依赖于硬件,而且依据所引导的操作系统的不同。

    二、Boot Loader的工作模式

    大多数 Boot Loader 都包含两种不同的操作模式:“启动加载”模式和“下载”模式,这种区别仅对于开发人员才有意义。但从最终用户的角度看,Boot Loader 的作用就是用来加载操作系统,而并不存在所谓的启动加载模式与下载工作模式的区别。

    启动加载(Boot loading)模式:

    这种模式也称为"自主"(Autonomous)模式。也即 Boot Loader 从目标机上的某个固态存储设备上将操作系统加载到 RAM 中运行,整个过程并没有用户的介入。这种模式是 Boot Loader 的正常工作模式,因此在嵌入式产品发布的时侯,Boot Loader 显然必须工作在这种模式下。

    下载(Downloading)模式:

    在这种模式下,目标机上的 Boot Loader 将通过串口连接或网络连接等通信手段从主机(Host)下载文件,比如:下载内核映像和根文件系统映像等。从主机下载的文件通常首先被 Boot Loader 保存到目标机的 RAM 中,然后再被 Boot Loader 写到目标机上的FLASH 类固态存储设备中。Boot Loader 的这种模式通常在第一次安装内核与根文件系统时被使用;此外,以后的系统更新也会使用 Boot Loader 的这种工作模式。工作于这种模式下的 Boot Loader 通常都会向它的终端用户提供一个简单的命令行接口。

     象Blob 或U-Boot 等这样功能强大的Boot Loader 通常同时支持这两种工作模式,而且允许用户在这两种工作模式之间进行切换。比如,Blob 在启动时处于正常的启动加载模式,但是它会延时10 秒等待终端用户按下任意键而将 blob 切换到下载模式。如果在 10 秒内没有用户按键,则 blob 继续启动 Linux 内核。

    三、Boot Loader 与主机之间进行文件传输协议

    最常见的情况就是,目标机上的 Boot Loader 通过串口与主机之间进行文件传输,传输协议通常是 xmodem/ymodem/zmodem 协议中的一种。但是,串口传输的速度是有限的,因此通过以太网连接并借助 TFTP 协议来下载文件是个更好的选择。

    此外,在论及这个话题时,主机方所用的软件也要考虑。比如,在通过以太网连接和TFTP 协议来下载文件时,主机方必须有一个软件用来的提供 TFTP 服务。

    四、Bootloader的工作流程

    由于Boot Loader的实现依赖与CPU的体系结构,因此大多数的Boot Loader都分为stage1和stage2两个阶段:

    1,Bootloader 的第一阶段(Stage1),工作流程

    ·            硬件设备初始化

    ·            代码重定位,为加载 Boot Loader 的 stage2 准备 RAM 空间

    ·            加载t第二阶段代码到RAM空间

    ·            设置堆栈跳转到第二阶段代码入口

    1.1,硬件设备初始化通常包括如下步骤:(按先后顺序执行):

    【1】复位(reset)

    【2】设置CPU为超级保护模式(SVC) 即特权模式(Supervisor)

    【3】关闭看门狗,不必附加喂狗代码。

    【4】屏蔽所有中断,为中断提供服务通常是OS设备驱动程序的责任,因此在 Boot Loader 的执行全过程中可以不必响应任何中断。中断屏蔽可以通过写CPU的中断屏蔽寄存器或状态寄存器(比如 ARM 的 CPSR 寄存器)来完成。

    【5】设置系统时钟频率。

    【6】初始化内存控制器,包括正确地设置系统的内存控制器的功能寄存器以及各内存库控制寄存器等。

    【7】初始化串口等,典型地,初始化UART并向串口打印相关字符信息。

    【8】初始化LED。典型地,通过GPIO 来驱动LED,其目的是表明系统的状态是 OK 还是 Error。如果板子上没有 LED,那么也可以通过初始化 UART 向串口打印 Boot Loader 的Logo 字符信息来完成这一点。

    【9】关闭 CPU 内部指令/数据 cache。

    1.2,代码重定位主要检查自己是否在内存中。如果是跳到堆栈段(stack_setup代码段)设置堆栈,不是就加载自己到RAM空间。

    为了获得更快的执行速度,通常把 stage2 加载到 RAM 空间中来执行,因此必须为加载 Boot Loader 的 stage2 准备好一段可用的 RAM 空间范围。

    由于 stage2 通常是 C 语言执行代码,因此在考虑空间大小时,除了 stage2 可执行映象的大小外,还必须把堆栈空间也考虑进来。此外,空间大小最好是 memory page 大小(通常是 4KB)的倍数。一般而言,1M 的 RAM 空间已经足够了。具体的地址范围可以任意安排,比如 blob 就将它的 stage2 可执行映像安排到从系统 RAM 起始地址 0xc0200000 开始的 1M 空间内执行。但是,将 stage2 安排到整个 RAM 空间的最顶 1MB(也即(RamEnd-1MB) - RamEnd)是一种值得推荐的方法。

    为了后面的叙述方便,这里把所安排的RAM 空间范围的大小记为:stage2_size(字节),把起始地址和终止地址分别记为:stage2_start 和 stage2_end(这两个地址均以 4 字节边界对齐)。因此:

    stage2_end = stage2_start +stage2_size

    另外,还必须确保所安排的地址范围的的确确是可读写的RAM 空间,因此,必须对你所安排的地址范围进行测试。具体的测试方法可以采用类似于blob 的方法,也即:以 memory page 为被测试单位,测试每个 memory page 开始的两个字是否是可读写的。为了后面叙述的方便,我们记这个检测算法为:test_mempage,其具体步骤如下:

     【1】先保存 memory page 一开始两个字的内容。

     【2】向这两个字中写入任意的数字。比如:向第一个字写入 0x55,第 2 个字写入 0xaa。

     【3】 然后,立即将这两个字的内容读回。显然,我们读到的内容应该分别是 0x55 和 0xaa。如果不是,则说明这个 memory page 所占据的地址范围不是一段有效的 RAM 空间。

     【4】再向这两个字中写入任意的数字。比如:向第一个字写入 0xaa,第 2 个字中写入 0x55。

     【5】然后,立即将这两个字的内容立即读回。显然,我们读到的内容应该分别是 0xaa 和 0x55。如果不是,则说明这个 memory page 所占据的地址范围不是一段有效的 RAM 空间。

     【6】恢复这两个字的原始内容。测试完毕。

    为了得到一段干净的RAM 空间范围,我们也可以将所安排的 RAM 空间范围进行清零操作。

    1.3,加载Bootloader第二阶段代码到RAM空间,拷贝时要确定两点:(1) stage2 的可执行映象在固态存储设备的存放起始地址和终止地址;(2) RAM 空间的起始地址。



    1.4,设置好堆栈,强调下堆和栈的区别:栈区(stack) 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈;堆区(heap) 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。程序的局部变量存在于(栈)中,全局变量存在于(静态区 )中,动态申请数据存在于( 堆)中全局变量实际上是存在一个(一般来说正常的编译器)可读可写的内存空间,这个空间是在你写程序编译好的空间地址(由编译器决定),是固定的。

    堆栈指针的设置是为了执行 C 语言代码作好准备。通常我们可以把 sp 的值设置为(stage2_end-4),因为栈是向下生长的,所以通常把栈指针设在1MB空间的最顶端。此外,在设置堆栈之前,也可以把指示用的LED灯关闭,以提示用户跳转到Stage2。经过以上步骤设置以后,系统的物理内存布局应该如图所示。

    1.5,跳转到第二阶段(Stage2)代码入口,在上述一切就绪后,就可以跳转到Boot Loader的Stage2执行了,在ARM系统中是通过修改PC寄存器为合适的地址来实现的。如U-Boot中是这样实现的:

    ldr pc, _start_armboot
    start_armboot是第二阶段(Stage2)的C程序的入口点。start_armboot是U-Boot执行的第一个C语言函数,完成系统初始化工作,进入主循环,处理用户输入的命令。

    2,Bootloader的第二阶段(Stage2)工作流程

    ·        初始化本阶段要使用到的硬件设备

    ·        检测系统内存映射

    ·        加载内核映像和根文件系统映像

    ·        设置内核的启动参数

    ·        启动内核

    2.1,初始化本阶段要使用到的硬件设备,这通常包括:

    (1)设置时钟、初始化至少一个串口,以便和终端用户进行 I/O 输出信息;(2)初始化计时器等。在初始化这些设备之前,也可以重新把 LED 灯点亮,以表明我们已经进入 main_loop() 函数执行。

    board_init函数设置MPLL、改变系统时钟,它是开发板相关的函数,在board/samsung/smdk2440/smdk2440.c中实现。值得注意的是board_init函数还保存了机器类型ID,这将在调用内核的时候传递给内核。代码如下:

    gd->bd->bi_arch_number = MACH_TYPE_S3C2440;  //值为362

    串口的初始化函数主要是serial_init,它设置UART控制器,是CPU相关的函数。

    2.2,检测系统内存映射(memory map)

    所谓内存映射就是指在整个4GB 物理地址空间中有哪些地址范围被分配用来寻址系统的RAM 单元。比如,在SA-1100 CPU 中,从0xC000,0000 开始的512M 地址空间被用作系统的RAM 地址空间,而在Samsung S3C44B0X CPU 中,从 0x0c00,0000 到 0x1000,0000 之间的 64M 地址空间被用作系统的 RAM 地址空间。虽然CPU 通常预留出一大段足够的地址空间给系统 RAM,但是在搭建具体的嵌入式系统时却不一定会实现 CPU 预留的全部 RAM 地址空间。也就是说,具体的嵌入式系统往往只把 CPU 预留的全部 RAM 地址空间中的一部分映射到 RAM 单元上,而让剩下的那部分预留 RAM 地址空间处于未使用状态。由于上述这个事实,因此 Boot Loader 的 stage2 必须在它想干点什么 (比如,将存储在 flash 上的内核映像读到 RAM 空间中) 之前检测整个系统的内存映射情况,也即它必须知道 CPU 预留的全部 RAM 地址空间中的哪些被真正映射到 RAM 地址单元,哪些是处于 "unused" 状态的。

    对于smdk2440的开发板,其内存分布是明确的,一般内存起始地址为0x3000 0000,大小为64M = 0x0400 0000。代码如下:

    int dram_init(void)

    {

        gd->bd->bi_dram[0] . start = PHYS_SDRAM_1;          //即0x3000 0000

        gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;  //即0x0400 0000

    //这两个值都定义在include/configs/smdk2440.h中

    }

    2.3,将内核映像和根文件系统映像从Flash上读到RAM空间中。

    【1】 规划内存占用的布局

    这里包括两个方面:(1)内核映像所占用的内存范围;(2)根文件系统所占用的内存范围。在规划内存占用的布局时,主要考虑基地址和映像的大小两个方面。

    对于内核映像,一般将其拷贝到从(MEM_START+0x8000) 这个基地址开始的大约1MB大小的内存范围内(嵌入式 Linux 的内核一般都不操过 1MB)。为什么要把从 MEM_START 到 MEM_START+0x8000 这段 32KB 大小的内存空出来呢?这是因为 Linux 内核要在这段内存中放置一些全局数据结构,如:启动参数和内核页表等信息。

    而对于根文件系统映像,则一般将其拷贝到 MEM_START+0x0010,0000 开始的地方。如果用 Ramdisk 作为根文件系统映像,则其解压后的大小一般是1MB。

    【2】从 Flash 上拷贝

    由于像 ARM 这样的嵌入式 CPU 通常都是在统一的内存地址空间中寻址 Flash 等固态存储设备的,因此从 Flash 上读取数据与从 RAM 单元中读取数据并没有什么不同。用一个简单的循环就可以完成从 Flash 设备上拷贝映像的工作:

    while(count) {

    *dest++ = *src++; /* they are all aligned with word boundary*/

    count -= 4; /* byte number */

    };

    2.4,为内核设置启动参数。

    应该说,在将内核映像和根文件系统映像拷贝到 RAM 空间中后,就可以准备启动 Linux 内核了。但是在调用内核之前,应该作一步准备工作,即:设置 Linux 内核的启动参数。

    U-Boot 是通过标记列表向内核传递参数。

    setup_memory_tags

    setup_commandline_tag

    这两个标记列表定义在arch/arm/lib/bootm.c中,需要在定义命令的文件include/configs/smdk2440.h中定义两个命令

    #define CONFIG_SETUP_MEMORY_TAGS  1

    #define CONFIG_CMDLINE_TAG                  1

    Linux 2.4.x 以后的内核都期望以标记列表(tagged list)的形式来传递启动参数。启动参数标记列表以标记ATAG_CORE 开始,以标记 ATAG_NONE 结束。每个标记由标识被传递参数的 tag_header 结构以及随后的参数值数据结构来组成。数据结构 tag 和 tag_header 定义在 Linux 内核源码的/arch/arm/include/asm/setup.h头文件中: 

    /* The list ends with an ATAG_NONE node. */

    #define ATAG_NONE 0x00000000

    struct tag_header {

    u32 size;/* 注意,这里size是字数为单位的 */

    u32 tag;

    };

    ……

    struct tag {

    struct tag_header hdr;

    union {

    struct tag_core  core;

    struct tag_mem32 mem;

    struct tag_videotext videotext;

    struct tag_ramdisk ramdisk;

    struct tag_initrd initrd;

    struct tag_serialnr serialnr;

    struct tag_revision revision;

    struct tag_videolfb videolfb;

    struct tag_cmdline cmdline;

      /*
       * Acorn specific
       */
      struct tag_acorn acorn;

      /*
       * DC21285 specific
       */

    struct tag_memclk memclk;


     } u;

    }; 

    在嵌入式 Linux 系统中,通常需要由 Boot Loader 设置的常见启动参数有:ATAG_CORE、ATAG_MEM、ATAG_CMDLINE、ATAG_RAMDISK、ATAG_INITRD等。比如,设置 ATAG_CORE 的代码如下:

    params = (struct tag *)BOOT_PARAMS;

    params->hdr.tag = ATAG_CORE;

    params->hdr.size = tag_size(tag_core);

    params->u.core.flags = 0;

    params->u.core.pagesize = 0;

    params->u.core.rootdev = 0;

    params = tag_next(params);  

    其中,BOOT_PARAMS 表示内核启动参数在内存中的起始基地址,指针 params 是一个 struct tag 类型的指针。宏 tag_next() 将以指向当前标记的指针为参数,计算紧临当前标记的下一个标记的起始地址。注意,内核的根文件系统所在的设备ID就是在这里设置的。

    下面是设置内存映射情况的示例代码: 

    for(i = 0; i < NUM_MEM_AREAS; i++) {

    if(memory_map[i].used) {

    params->hdr.tag = ATAG_MEM;

    params->hdr.size = tag_size(tag_mem32);

    params->u.mem.start = memory_map[i].start;

    params->u.mem.size = memory_map[i].size;

    params = tag_next(params);
      }

    }

    可以看出,在 memory_map[]数组中,每一个有效的内存段都对应一个 ATAG_MEM 参数标记。 Linux 内核在启动时可以以命令行参数的形式来接收信息,利用这一点我们可以向内核提供那些内核不能自己检测的硬件参数信息,或者重载(override)内核自己检测到的信息。比如,我们用这样一个命令行参数字符串"console=ttyS0,115200n8"来通知内核以 ttyS0 作为控制台,且串口采用 "115200bps、无奇偶校验、8位数据位"这样的设置。下面是一段设置调用内核命令行参数字符串的示例代码: 

    char *p;

     /* eat leading whitespace */

     for(p = commandline;*p == ' '; p++)

      ;

     /* skip non-existentcommand lines so the kernel will still

      * use its defaultcommand line.

     */

     if(*p == '\0')

     return;

     params->hdr.tag =ATAG_CMDLINE;

     params->hdr.size =(sizeof(struct tag_header) + strlen(p) + 1 + 4) >> 2;

     strcpy(params->u.cmdline.cmdline, p);

     params =tag_next(params);

     

    请注意在上述代码中,设置 tag_header 的大小时,必须包括字符串的终止符'\0',此外还要将字节数向上圆整4个字节,因为 tag_header 结构中的size 成员表示的是字数。

    下面是设置 ATAG_INITRD 的示例代码,它告诉内核在 RAM 中的什么地方可以找到 initrd 映象(压缩格式)以及它的大小:

    params->hdr.tag = ATAG_INITRD2;

    params->hdr.size = tag_size(tag_initrd);

    params->u.initrd.start = RAMDISK_RAM_BASE;

    params->u.initrd.size = INITRD_LEN;

    params = tag_next(params);

     
    下面是设置 ATAG_RAMDISK 的示例代码,它告诉内核解压后的 Ramdisk 有多大(单位是KB):

     

    params->hdr.tag = ATAG_RAMDISK;

    params->hdr.size = tag_size(tag_ramdisk);

    params->u.ramdisk.start = 0;

    params->u.ramdisk.size = RAMDISK_SIZE;/* 请注意,单位是KB */

    params->u.ramdisk.flags = 1; /* automatically loadramdisk */

    params = tag_next(params);

     
    最后,设置 ATAG_NONE 标记,结束整个启动参数列表:

    static void setup_end_tag(void)

    {

    params->hdr.tag = ATAG_NONE;

    params->hdr.size = 0;

    }

    2.5,启动内核

    Boot Loader 调用 Linux 内核的方法是直接跳转到内核的第一条指令处,也即直接跳转到 MEM_START+0x8000 地址处。在跳转时,下列条件要满足:

    【1】CPU 寄存器的设置:

    R0=0;

    注:

    @R1=机器类型 ID;关于 Machine Type Number,可以参见 linux/arch/arm/tools/mach-types。

    @R2=启动参数标记列表在 RAM 中起始基地址;

    【2】CPU 模式:

    必须禁止中断(IRQs和FIQs);

    CPU 必须 SVC 模式;

    【3】Cache 和 MMU 的设置:

    MMU 必须关闭;

    指令 Cache 可以打开也可以关闭;

    数据 Cache 必须关闭;

    如果用 C 语言,可以像下列示例代码这样来调用内核:

    void (*theKernel)(int zero, int arch, u32 params_addr)
                 = (void (*)(int, int, u32))KERNEL_RAM_BASE;

    ……

    theKernel(0, ARCH_NUMBER, (u32) kernel_params_start);
    注意,theKernel()函数调用应该永远不返回的。如果这个调用返回,则说明出错。

    对于ARM构架的CPU来说,都是通过../lib_arm/bootm.c中的do_bootm_linux函数来启动内核的。这个函数中,设置标记列表,最后通过

    theKernel = (void (*)(int, int, uint))images->ep;

    调用内核。其中,theKernel 指向内核存放的地址(对于ARM构架的CPU,通常这个地址是0x3000 8000)。传递的3个参数如下:

    void (*theKernel)(int zero, int arch, uint params);

    R0: 0

    R1: 机器类型ID -- gd->bd->bi_arch_number = MACH_TYPE_S3C2440;   //值为362

    R2: 启动参数标记列表在RAM中的起始地址 0x3000 0100

    五、 关于串口终端

    在 boot loader 程序的设计与实现中,没有什么能够比从串口终端正确地收到打印信息能更令人激动了。此外,向串口终端打印信息也是一个非常重要而又有效的调试手段。但是,我们经常会碰到串口终端显示乱码或根本没有显示的问题。造成这个问题主要有两种原因:(1) boot loader 对串口的初始化设置不正确。(2) 运行在 host 端的终端仿真程序对串口的设置不正确,这包括:波特率、奇偶校验、数据位和停止位等方面的设置。

    此外,有时也会碰到这样的问题,那就是:在 boot loader 的运行过程中我们可以正确地向串口终端输出信息,但当 boot loader 启动内核后却无法看到内核的启动输出信息。对这一问题的原因可以从以下几个方面来考虑:

    (1) 首先请确认你的内核在编译时配置了对串口终端的支持,并配置了正确的串口驱动程序。

    (2) 你的 boot loader 对串口的初始化设置可能会和内核对串口的初始化设置不一致。此外,对于诸如 s3c44b0x 这样的 CPU,CPU 时钟频率的设置也会影响串口,因此如果 boot loader 和内核对其 CPU 时钟频率的设置不一致,也会使串口终端无法正确显示信息。

    (3) 最后,还要确认 boot loader 所用的内核基地址必须和内核映像在编译时所用的运行基地址一致,尤其是对于 uClinux 而言。假设你的内核映像在编译时用的基地址是 0xc0008000,但你的 boot loader 却将它加载到 0xc0010000 处去执行,那么内核映像当然不能正确地执行了。

    六、 结束语

    Boot Loader 的设计与实现是一个非常复杂的过程。如果能从串口收到那激动人心的

    "uncompressing linux

    .................. done,

    booting the kernel……"

    内核启动信息,说明boot loader 已经成功地转起来了!。

     

    本文部分内容来自参考文章

    http://www.ibm.com/developerworks/cn/linux/l-btloader/

    http://wenku.baidu.com/view/26f587c608a1284ac8504326.html

    http://www.cnblogs.com/heaad/archive/2010/07/17/1779829.html

    http://www.limofans.com/forum.php?mod=viewthread&tid=8970

    展开全文
  • Bootloader 启动流程和概念介绍》

    千次阅读 2018-02-02 10:44:57
    Bootloader 启动流程 和 概念 介绍1.概念 简单地说,Bootloader 就是在操作系统内核运行之前运行的一段程序,它类似于 PC机中的 BIOS 程序。通过这段程序,可以完成硬件设备的初始化,并建立内存空间的映射图的功能...
  • 讲述android 开机流程 从boot rom---bootloader---init--zygote---systemserver---ams 并附上自己整理的每个流程流程图 ,清晰熟悉android 启动流程
  • [Android]高通平台BootLoader启动流程

    千次阅读 2018-11-22 00:10:19
    一、什么是BootLoader BootLoader代码是芯片...BootLoder主要的启动流程可以概括为:PBL阶段、SBL阶段、LK阶段。之后会加载并启动kernel。 二、名词解释 5个处理器:  APPS :Cortex A53 core(MSM8953),运...
  • bootloader启动流程分析

    千次阅读 2016-09-09 09:01:43
    bootloader启动流程分析 1、Bootloader的概念和作用 Bootloader是嵌入式系统的引导加载程序,它是系统上电后运行的第一段程序。在完成对系统的初始化任务之后,它会将Flash中的Linux内核拷贝到 RAM 中去,跳转到...
  • 今天早上看了一上午的bootloader简单源码,终于捋顺了bootloader的执行过程,之前只是知道bootloader代码会先被irom中的代码拷贝到iram中一部分,然后执行这部分代码,会把整个bootloader代码拷贝到sdram中,最终在...
  • bootloader 启动过程详细说明

    千次阅读 2015-01-06 11:14:29
    今天早上看了一上午的bootloader简单源码,终于捋顺了bootloader的执行过程,之前只是知道bootloader代码会先被irom中的代码拷贝到iram中一部分,然后执行这部分代码,会把整个bootloader代码拷贝到sdram中,最终在...
  • 最近工作中遇到一些问题:需进入fastboot模式,然后通过执行fastboot命令、并借助其他的一些脚本,来分析系统的运行状态以及当前系统当前处的状态等,借此了解了下fastboot模式的启动流程; 通过查找资料,发现一个...
  • bootloader 启动过程

    2018-03-18 23:02:09
    一、S5PV210 采用iROM(Nand Flash、SD卡等)方式启动1、处理器上电,将iROM映射到BL0(0地址处),执行iROM中的固化代码固化代码两个作用 1. 初始化硬件 2.拷贝BootLoader2、固化代码将BL1、BL2拷贝到SRAM(垫脚石)...
  • 一、Bootloader 当系统首次引导时,或系统被重置时,处理器会...Linux 内核在完成系统的初始化之后需要挂载某个文件系统作为根文件系统(RootFilesystem),然后加载必要的内核模块,启动应用程序。(一个嵌入式...
  • 一、linux启动流程 1.运行bios开机自检 2.根据MBR指引运行bootloader(PC内核引导程序常用LILO和GRUB,嵌入式常用UBOOT) 3.加载内核 4.运行initrd驱动,挂载根文件系统 5.运行init进程(进程编号为1),使用inittab...
  • 基于at91sam9260的嵌入式系统的Bootloader启动流程分析,程前,陈永泰,Bootloader是上电后,应用程序或操作系统运行前对处理器及内部功能模块的初始化,以及引导内核过程的一段启动代码。本文根据at91sam9260的�
  • MTK bootloader 启动过程

    千次阅读 2017-07-02 18:23:31
    1、bootloader到kernel启动总逻辑流程图 ARM架构中,EL0/EL1是必须实现,EL2/EL3是选配,ELx跟层级对应关系: EL0 -- app EL1 -- Linux kernel 、lk EL2 -- hypervisor(虚拟化) EL3 -- ARM trust...
  • BootLoader与MCU启动过程

    2020-11-19 14:18:13
    ARM之Cortex M3的启动过程 目前,多数MCU厂商都提供一个启动文件。当然,编程者也可以自己编写启动文件,具体编写要求ARM的网站上都有相关文档进行说明。下面分析一下STM32启动文件startup_stm32f407xx.s STM32...
  • 文章目录Bootloader启动流程分析Bootloader第一阶段的功能硬件设备初始化为加载 Bootloader的第二阶段代码准备RAM空间(初始化nandflash)复制 Bootloader的第二阶段代码到SDRAM空间中(重定位)设置好栈跳转到第二...
  • 关于bootloader和U-BOOT的基础描述,希望可以帮助到初学者。
  • BootLoader启动代码分析

    2018-03-22 10:17:19
    uboot代码详细分析,学习嵌入式开发绕不开的要点,结合硬件原理分析上电启动过程
  • NRF52832的BootLoader移植过程中缺少uEcc模块的解决办法,项目基于Keil
  • bootloader启动内核过程

    2019-10-06 22:20:09
    内核一般是由bootloader来引导的,通过bootloader启动内核一般要传递三个参数, 第一个参数放在寄存器0中,一般都为0,r0 = 0; 第二个参数放在寄存器1中,是机器类型id,r1 = Machine Type Number; 第三个参数放在...
  • 汽车Bootloader流程

    2020-12-20 23:56:01
    根据ISO14229-1 写的汽车行业 Bootloader流程 1:编程前 → 先读取软硬件版本号 22 F1 XX 软件信息 22 F1 XX 硬件信息 → 进入扩展会话extend diagnostic sessions 功能寻址 10 03 → 编程条件检测routine ...
  • CPU上电后,会在某个地址开始执行,比如...而Bootloader就存在这个地址的开始处,这样一上电后就会从这个地址处执行。Bootloader执行后从板子上的某个固态存储设备上将操作系统OS加载到RAM中运行。(一些功能强大的B...
  • Bootloader启动过程

    2015-04-23 20:12:59
    在完成对系统的初始化任务后,它会将非易失性存储器(通常是FLASH)中的Linux内核拷贝到RAM中,然后跳转到内核的第一条指令处继续执行,从而启动Linux内核。 2、功能 实际应用中的Bootloader根据所需功能的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 31,887
精华内容 12,754
关键字:

bootloader启动流程