对于RK356x这样一个SoC,当然可以裸机跑一段程序,实现一些简单的功能,可这样太浪费它的性能了,将它跑Linux或鸿蒙这样的操作系统,以使其功能最大化,才是更好的使用。
因此,需要进行系统定制,APP,外部设备驱动等相关的开发。这是一个复杂的过程,得先知道从何入手,需要开发些什么?
首先要知道,从上电开始,系统在芯片上是怎样引导启动的?需要哪些部件,它们是如何组织的以及烧录和运行的?然后我们才可以分别对每一部分进行开发。
启动过程:
BootROM -> Preloader -> bootloader -> Kernel -> Rootfs -> APP
1. BootROM
1.1 在上电后,RK356x会从固化到芯片内部的BootROM开始启动,运行boot code,它是原厂写死在芯片内部的,无法进行再开发.
1.2 boot code从外部存储设备(eMMC、SPI NAND FLASH、SD卡)[顺序]中一个正确读取ID后,加载preloader(BL1)到SRAM,执行preloader。
1.3 当读取所有外部存器设备ID失败后,自动进入MaskRom模式,注意,上电时,如果MaskRom引脚被拉低(一般做成按键),则不从任何外设读取ID,直接进入MaskRom模式,该模式接收USB-c下载固件到eMMC等外部存储设备中。
2.Preloader
Preloader是miniloader(非开源),uboot spl和loader三个其中一个
初始化DDR,并加载bootloader(U-Boot)到DDR中,转到DDR执行bootloader
3.Bootloader(U-Boot)
3.1 进行各种硬件初始化,初始化电源并启动电源管理,串口初始化,设置系统频率,显示开机LOGO,设置环境变量,网络初始化等。
3.2 具有下载功能,当识别按键为loader模式时,它接受USB-C的数据下载固件到外部存储器中;当识别到recovery分区时,会跳到reovery分区,该分区可进行系统的恢复、重置等。
3.3 找到系统kernel的image(boot.img),并加载到DDR,然后跳转到kernel执行kernel。
4.Kernel
4.1 kernel是Linux系统特性的实现,负责进程管理,内存管理,系统调用,文件系统维护,驱动管理,网络通信协议栈,提供应用所需的Lib等
4.2 kernel启动在init/main.c中的函数start_kernel()函数,它先初始化各外设,定时器,系统时钟,中断向量表(及相关中关例程),内存管理,系统cache,进程通信机制等后,调用rest_init()来进行最后的初始化。
4.3 kernel挂载根文件系统rootfs,然后启动系统第一个进程init(systemd),该进程负责进一步的系统初始化操作。init进程是进程树的根,所有的进程都直接或者间接起源于该进程。
4.4 init父进程进一步fock出用户运行在Linux上的各类进程,即启动APP,这样,系统就启动了。
5.分区
5.1 BootROM固化在芯片内部一个专用的ROM区,是出厂就写好的,其它部分则存放在外部存储器中,RK默认分区如下图
5.2 16384(0x4000):preloader和bootloader通常被合并在这一个分区,镜像名为uboot.img
5.3 24576(0x6000):镜像名为misc.img,它是给recovery使用的
5.4 32768(0x8000):kernel分区,镜像名为boot.img
5.5 163840(0x28000):recovery分区,镜像名为recovery.img
5.6 294912(0x48000):备份分区,预留,暂不用
5.7 360448(0x58000):根文件系统分区,由buildroot,debian或yocto编译出的镜像rootfs.img
5.8 12943360(0xC58000):存放厂家的APP数据,通常挂载在/oem
5.9 13205504(0xC98000):用户APP数据区,通常挂载在/userdata