分析树莓派3b+上电启动流程

2020-03-17 14:54:30 浏览数 (1)

最近在玩树莓派,觉得这个树莓派的启动过程有点意思。所以在收集很多信息之后,个人也进行了一些实验和总结。先看一段原始资料:

This is an in-detail account of the Raspberry Pi boot process collected from various sources, mainly from the official forums. First, you need to know the RPi does not boot up like a conventional desktop computer. The VideoCore a.k.a the Graphics processor actually boots before the ARM CPU! Anyway, before we get into the details here’s a diagram of the RPi highlighting the Broadcom BCM2835 SoC. The SoC (or System-on-Chip) contains the ARM CPU, the VideoCore Graphics Processor, ROM (Read-Only-Memory) chips, the SDRAM and so many other things. Basically, think of a SoC as your Motherboard and CPU compressed together into a single chip. When you power on your Raspberry Pi, the first bits of code to run is stored in a ROM chip in the SoC and is built into the Pi during manufacture! This is the called the first-stage bootloader. The SoC is hardwired to run this code on startup on a small RISC Core (Reduced Instruction Set Computer). It is used to mount the FAT32 boot partition in your SDCard so that the second-stage bootloader can be accessed. So what is this ‘second-stage bootloader’ stored in the SD Card? It’s ‘bootcode.bin’. You might have seen this file if you had mounted the SD Card in Windows. Now here’s something tricky. The first-stage bootloader has not yet initialized your ARM CPU (meaning CPU is in reset) or your RAM. So, the second-stage bootloader also has to run on the GPU. The bootloader.bin file is loaded into the 128K 4 way set associative L2 cache of the GPU and then executed. This enables the RAM and loads start.elf which is also in your SD Card. This is the third-stage bootloader and is also the most important. It is the firmware for the GPU, meaning it contains the settings or in our case, has instructions to load the settings from config.txt which is also in the SD Card. You can think of the config.txt as the ‘BIOS settings’ (as is mentioned in the forum). Some of the settings you can control are (thanks to dom): arm_freq : frequency of ARM in MHz. Default 700. gpu_freq : Sets core_freq, h264_freq, isp_freq, v3d_freq together. core_freq : frequency of GPU processor core in MHz. Default 250. h264_freq: frequency of hardware video block in MHz. Default 250. isp_freq: frequency of image sensor pipeline block in MHz. Default 250. v3d_freq: frequency of 3D block in MHz. Default 250. sdram_freq: frequency of SDRAM in MHz. Default 400. The start.elf also splits the RAM between your GPU and the ARM CPU. The ARM only has access the to the address space left over by the GPU address space. For example, if the GPU was allocated addresses from 0x000F000 – 0x0000FFFF, the ARM has access to addresses from 0×00000000 – 0x0000EFFF. (These are not real address ranges. It’s just for demonstration purposes). Now what’s even funnier is that the ARM core perceives 0×00005001 as it’s beginning address 0×00000000. In other words, if the ARM core requests the address 0×0000000, the actual address in RAM is 0×00005001. Edit: The physical addresses perceived by the ARM core is actually mapped to another address in the VideoCore (0xC0000000 and beyond) by the MMU (Memory Management Unit) of the VideoCore. The config.txt is loaded after the split is done so you cannot specify the splitting amounts in the config.txt. However, different .elf files having different splits exist in the SD Card. So, depending on your requirement, you can rename those files to start.elf and boot the Pi. (The forums mention of having this functionality in a dynamic fashion, but I don’t know whether they have implemented it yet) In the Pi, the GPU is King! Other than loading config.txt and splitting RAM, the start.elf also loads cmdline.txt if it exists. It contains the command line parameters for whatever kernel that is to be loaded. This brings us to the final stage of the boot process. The start.elf finally loads kernel.img which is the binary file containing the OS kernel (DUH!?) and releases the reset on the CPU. The ARM CPU then executes whatever instructions in the kernel.img thereby loading the operating system. After starting the operating system, the GPU code is not unloaded. In fact, start.elf is not just firmware for the GPU, It is a proprietary operating system called VideoCore OS. When the normal OS (Linux) requires an element not directly accessible to it, Linux communicates with VCOS using the mailbox messaging system. Note: Special thanks to user dom in the official RPi forums and the community behind the official wiki.

这是Herman Hermitage大神分享出来的资料。

我来按照理解分析一下这个过程:

当给树莓派加电后,最先执行保存在ROM中的代码,这些代码是芯片出厂的时候就设定的,通常被称为 first-stage bootloader,这些代码固化硬件内部,可以认为是SoC硬件的一部分。这部分代码通常都是固化的,不可以修改也不可以进行读取。

first-stage bootloader的主要工作是加载位于SD卡上第一个分区的bootloader(称为second-stage bootloader ),也就是SD卡的第一个FAT32分区的根目录下寻找一个叫bootcode.bin的二进制文件。那么这个时候,其实CPU并没有启动,执行这个动作的其实是SOC封装里的GPU。这就是非常奇怪的地方!一般来说我们理解都是CPU负责产生数据,然后交给GPU去做运算,怎么GPU倒反客为主了呢?但是树莓派就是这样设定的!并且GPU性能可以超过CPU。接着GPU将bootcode.bin读取到128KB大小的二级缓存(L2 Cache),并开始执行bootcode.bin。这是第二阶段。

当然当然,这还没有结束,紧接着,执行第三阶段。bootcode.bin的主要工作是初始化ram,并把start.elf(也位于SD卡的第一分区)加载到内存中。start.elf就是third-stage bootloader。那么第三阶段结束。

第三阶段载入运行的start.elf的功能就是加载位于SD卡中的config.txt。该文件可以理解为BISO,详细记录了配置信息。

arm_freq : frequency of ARM in MHz. Default 700. gpu_freq : Sets core_freq, h264_freq, isp_freq, v3d_freq together. core_freq : frequency of GPU processor core in MHz. Default 250. h264_freq: frequency of hardware video block in MHz. Default 250. isp_freq: frequency of image sensor pipeline block in MHz. Default 250. v3d_freq: frequency of 3D block in MHz. Default 250. sdram_freq: frequency of SDRAM in MHz. Default 400. start.elf把ram空间划分为2部分:CPU访问空间和GPU访问空间。SoC芯片只访问属于GPU地址空间的内存区,例如,GPU的物理内存地址空间为0x000F000 – 0x0000FFFF,CPU的物理内存地址空间为0x00000000 – 0x0000EFFF,如果GPU访问0x0000008,那么它访问的物理地址为0x000F008。(实际上,ARM处理器的mmu部件把GPU的内存空间映射到0xC0000000 开始)。config.txt在内存地址空间分配完成后才加载,因此,不可以在config.txt中更改内存地址的配置。然而,可以通过配置多个elf文件来让start.elf和config.txt支持多种配置空间。start.elf还从SD卡的第一个分区中加载cmdline.txt(如果cmdline.txt存在的话)。该文件保存的是启动kernel(不一定是Linux的内核)的参数。至此,SoC进入了boot的最后阶段,start.efl把kernel.img,ramdisk,dtb加载到内存的预定地址,然后向cpu发出重启信号,因此cpu就可以从内存的预定地址执行kernel的代码,就进入了软件定义的系统启动流程。

分析树莓派的启动过程也是非常有意思的。一般玩过嵌入式Linux的都知道,一般的启动流程都是在CPU中进行:

第一阶段:bootloader(固化代码,引导Uboot)

第二阶段:Uboot(初始化必要的外设,并引导启动kernel)

第三阶段:kernel(初始化外设,进入文件系统rootfs)

然而BCM2835 SoC整个过程都是GPU来办事,启动过程为:

第一阶段:bootloader(固化代码,加载sd卡中的bootcode.bin文件)

第二阶段:bootcode.bin(初始化ram,并加载SD卡中的start.elf文件)

第三阶段: start.elf(配置CPU与GPU的地址空间,主频,并加载Linux内核)

特别说明一下:GPU

GPU(Graphics Processing Unit)是图形处理单元,一般是用来加速处理图像算法的,可以进行复杂运算,需要配合CPU来使用。CPU负责提供数据,传递给GPU计算,然后再收集GPU的计算结果。GPU一般是不能独立执行代码的。但是Broadcom已经做到第五代了叫VideoCore IV。是具有代码处理能力的。由此,个人觉得GPU迟早一天要取代CPU或者两者进行融合,充分体现处理器的价值!

0 人点赞