91在线观看视频-91在线观看视频-91在线观看免费视频-91在线观看免费-欧美第二页-欧美第1页

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Rockchip RK3588 - uboot引導(dǎo)方式介紹

瑞芯微方案開(kāi)發(fā)老王 ? 來(lái)源:h1654155861.7375 ? 作者:h1654155861.7375 ? 2025-02-15 10:24 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

開(kāi)發(fā)板 :RK3588 EVB開(kāi)發(fā)板
eMMC :256GB
LPDDR4 :16GB
顯示屏 :10.1英寸HDMI接口顯示屏
u-boot :2017.09
linux :6.1
----------------------------------------------------------------------------------------------------------------------------

在前面的文章我們對(duì)Rockhip Linux SDK進(jìn)行了深入分析,其中涉及到了SDK編譯過(guò)程、編譯源碼,具體可以參考:

Rockchip RK3588 - Rockchip Linux SDK編譯;(如需要此文檔的可以聯(lián)系博主獲取)

Rockchip RK3588 - Rockchip Linux SDK Buildroot文件系統(tǒng)構(gòu)建;(如需要此文檔的可以聯(lián)系博主獲取)

Rockchip RK3588 - Rockchip Linux SDK腳本分析。(如需要此文檔的可以聯(lián)系博主獲取)

此外,我們還是深入分析了Recovery模式下的系統(tǒng)升級(jí)功能,具體可參考:

Rockchip RK3588 - Rockchip Linux Recovery updateEngine源碼分析;(如需要此文檔的可以聯(lián)系博主獲取)

Rockchip RK3588 - Rockchip Linux Recovery updateEngine測(cè)試。 (如需要此文檔的可以聯(lián)系博主獲取)

接下來(lái)我們將嘗試在RK3588開(kāi)發(fā)板實(shí)現(xiàn)系統(tǒng)升級(jí)功能,當(dāng)然我們還期望當(dāng)根文件系統(tǒng)損壞時(shí),開(kāi)發(fā)板能夠通過(guò)按住GPIO口進(jìn)入到recovery系統(tǒng)恢復(fù)正常系統(tǒng)。

一、uboot啟動(dòng)方式

既然要實(shí)現(xiàn)在開(kāi)發(fā)板實(shí)現(xiàn)系統(tǒng)升級(jí)功能,我們就需要了解uboot啟動(dòng)內(nèi)核的方式,并制作以下分區(qū)鏡像;

misc.img:misc分區(qū)是一個(gè)沒(méi)有文件系統(tǒng)的分區(qū),用于存放一些引導(dǎo)配置參數(shù);

recovery.img:由kernel + dtb + ramdisk組成,主要用于升級(jí)操作;

uboot會(huì)根據(jù)misc分區(qū)存放的字段來(lái)判斷將要引導(dǎo)的系統(tǒng)是normal系統(tǒng)還是recovery系統(tǒng)。

1.1 系統(tǒng)固件

我們使用的是RK3588開(kāi)發(fā)板,這里我們就去下載官方提供的固件

這里我們選擇debian-bullseye-desktop-arm64-images.tgz作為測(cè)試使用的鏡像文件,將debian-bullseye-desktop-arm64-images.tgz(位于"?3_分區(qū)鏡像文件"目錄下,以實(shí)際下載的文件為準(zhǔn))拷貝到/work/sambashare/rk3588/friendly/sd-fuse_rk3588目錄下;

root@ubuntu:/work/sambashare/rk3588/friendly/sd-fuse_rk3588# ll debian*
-rwxrw-rw- 1 root root 1590466719 Dec  3 01:49 debian-bullseye-desktop-arm64-images.tgz*
-rwxrw-rw- 1 root root         75 Nov 18 19:05 debian-bullseye-desktop-arm64-images.tgz.hash.md5*
root@ubuntu:/work/sambashare/rk3588/friendly/sd-fuse_rk3588# tar -xvzf debian-bullseye-desktop-arm64-images.tgz

解壓得到debian-bullseye-desktop-arm64文件夾;

root@ubuntu:/work/sambashare/rk3588/friendly/sd-fuse_rk3588# ll debian-bullseye-desktop-arm64
-rw-r--r--  1 root root    8072140 May 28  2023 boot.img
-rw-r--r--  1 root root       1424 May 28  2023 dtbo.img
-rw-r--r--  1 root root     307200 Sep  8 23:33 idbloader.img
-rw-r--r--  1 root root         64 Nov 17 10:03 info.conf
-rw-r--r--  1 root root   35551252 Nov 16 16:17 kernel.img
-rw-r--r--  1 root root     471488 Sep  8 23:33 MiniLoaderAll.bin
-rw-r--r--  1 root root      49152 May 28  2023 misc.img
-rw-r--r--  1 root root        470 Nov 17 10:03 parameter.txt
-rw-r--r--  1 root root    6227456 Nov 16 16:17 resource.img
-rw-r--r--  1 root root 3992675220 Nov 17 10:03 rootfs.img
-rw-r--r--  1 root root    4194304 Sep  8 23:33 uboot.img
-rw-r--r--  1 root root     159868 Nov 17 10:03 userdata.img

可以看到解壓的文件已經(jīng)包含了misc.img,但是并沒(méi)有recovery.img。

1.1.1 系統(tǒng)分區(qū)介紹

parameter.txt保存著分區(qū)信息:

FIRMWARE_VER: 12.0
MACHINE_MODEL: RK3588
MACHINE_ID: 007
MANUFACTURER: RK3588
MAGIC: 0x5041524B
ATAG: 0x00200800
MACHINE: NanoPi6
CHECK_MASK: 0x80
PWR_HLD: 0,0,A,0,1
TYPE: GPT
CMDLINE: mtdparts=rk29xxnand:0x00002000@0x00004000(uboot),0x00002000@0x00006000(misc),0x00002000@0x00008000(dtbo),0x00008000@0x0000a000(resource),0x00014000@0x00012000(kernel),0x00010000@0x00026000(boot),0x00010000@0x00036000(recovery),0x007c0000@0x00046000(rootfs),-@0x00806000(userdata:grow)

解析信息如下:

Number Name 鏡像文件 Start (sector) End (sector) Size
1 uboot uboot.img 0x4000(16384) 0x5FFF 4M
2 misc misc.img 0x6000(24576) 0x7FFF 4M
3 dtbo dtbo.img 0x8000(32768) 0x9FFF 4M
4 resource resource.img 0xa000(40960) 0x11FFF 16MB
5 kernel kernel.img 0x12000(73728) 0x25FFF 40MB
6 boot boot.img 0x26000(155648) 0x35FFF 32MB
7 recovery recovery.img 0x36000(221184) 0x45FFF 32MB
8 rootfs rootfs.img 0x46000(286720) 0x804FFF 3.968GB
9 userdata userdata.img 0x806000(8413184) -

其中:

uboot分區(qū):供uboot編譯出來(lái)的uboot.img;

misc分區(qū):引導(dǎo)參數(shù)分區(qū),供misc.img,給recovery使用;

dtbo::供kernel編譯出來(lái)的dtbo.img;

resource:資源分區(qū),由設(shè)備樹(shù)、圖片資源文件組成,不包含內(nèi)核;

boot:供kernel編譯出來(lái)的boot.img(可能是FIT uImage鏡像格式,也有可能是Android bootimg鏡像格式);

kernel:供kernel編譯出來(lái)的kernel.img(由tools/mkkrnlimg工具編譯內(nèi)核鏡像Image文件得到);

recovery分區(qū):供recovery編譯出的recovery.img(kernel + dtb + ramdisk);

rootfs分區(qū):供buildroot、debian或yocto編出來(lái)的rootfs.img;

userdata分區(qū):供APP臨時(shí)生成文件或給最終用戶(hù)使用,掛載在/userdata目錄下。

從上面我們可以看到這里有兩個(gè)分區(qū)時(shí)存放了內(nèi)核鏡像,分別是boot和kernel,那問(wèn)題來(lái)了,uboot啟動(dòng)到底使用的是哪個(gè)內(nèi)核呢?

1.1.2 生成統(tǒng)一固件

將debian-bullseye-desktop-arm64目錄下的鏡像文件重新打包成SD卡固件:

root@@ubuntu:/work/sambashare/rk3588/friendly/sd-fuse_rk3588# sudo ./mk-sd-image.sh debian-bullseye-desktop-arm64/
Creating RAW image: out/rk3588-sd-debian-bullseye-desktop-6.1-arm64-20240714.img (7800 MB)
---------------------------------
記錄了0+0 的讀入
記錄了0+0 的寫(xiě)出
0字節(jié)已復(fù)制,0.0001181 s,0.0 kB/s
----------------------------------------------------------------
[out/rk3588-sd-debian-bullseye-desktop-6.1-arm64-20240714.img] capacity = 7438MB, 7799999488 bytes
current out/rk3588-sd-debian-bullseye-desktop-6.1-arm64-20240714.img partition:
----------------------------------------------------------------
parsing ./debian-bullseye-desktop-arm64//parameter.txt:
create new GPT 9:
----------------------------------------------------------------
copy from: ./debian-bullseye-desktop-arm64 to out/rk3588-sd-debian-bullseye-desktop-6.1-arm64-20240714.img
 [RAW. 0]:      300 KB | ./debian-bullseye-desktop-arm64/idbloader.img  > 100% : done.
 [RAW. 1]:     4096 KB | ./debian-bullseye-desktop-arm64/uboot.img      > 100% : done.
 [RAW. 2]:       48 KB | ./debian-bullseye-desktop-arm64/misc.img       > 100% : done.
 [RAW. 3]:        1 KB | ./debian-bullseye-desktop-arm64/dtbo.img       > 100% : done.
 [RAW. 4]:     2518 KB | ./debian-bullseye-desktop-arm64/resource.img   > 100% : done.
 [RAW. 5]:    34590 KB | ./debian-bullseye-desktop-arm64/kernel.img     > 100% : done.
 [RAW. 6]:     7882 KB | ./debian-bullseye-desktop-arm64/boot.img       > 100% : done.
 [RAW. 8]:  3907280 KB | ./debian-bullseye-desktop-arm64/rootfs.img     > 100% : done.
 [RAW. 9]:      156 KB | ./debian-bullseye-desktop-arm64/userdata.img   > 100% : done.
----------------------------------------------------------------
---------------------------------
RAW image successfully created (21:09:10).
-rw-r--r-- 1 root root 7799999488  7月 14 21:09 

該sh腳本內(nèi)部調(diào)用了Rockchip官方提供的打包工具sd_update生成的統(tǒng)一固件,由于打包工具并不開(kāi)源,所以無(wú)法研究源碼。

不過(guò)我們大致可以猜測(cè)出應(yīng)該就是做了一個(gè)鏡像文件,然后按照parameter.txt進(jìn)行劃分分區(qū),并將各個(gè)分區(qū)鏡像依次燒錄進(jìn)去。

View Code


1.1.3 制作

SD

啟動(dòng)卡

我們將SD卡插入PC上,在虛擬機(jī)ubuntu中運(yùn)行demsg查看新接入的設(shè)備;

[36809.524292] usb 2-1: USB disconnect, device number 2
[36813.382382] usb 2-1: new high-speed USB device number 3 using ehci-pci
[36813.657882] usb 2-1: New USB device found, idVendor=14cd, idProduct=1212, bcdDevice= 1.00
[36813.657887] usb 2-1: New USB device strings: Mfr=1, Product=3, SerialNumber=2
[36813.657889] usb 2-1: Product: Mass Storage Device
[36813.657890] usb 2-1: Manufacturer: Generic
[36813.657891] usb 2-1: SerialNumber: 121220160204
[36813.660529] usb-storage 2-1:1.0: USB Mass Storage device detected
[36813.661135] scsi host33: usb-storage 2-1:1.0
[36814.676011] scsi 33:0:0:0: Direct-Access     Mass     Storage Device   1.00 PQ: 0 ANSI: 0 CCS
[36814.677119] sd 33:0:0:0: Attached scsi generic sg2 type 0
[36814.681851] sd 33:0:0:0: [sdb] 62333952 512-byte logical blocks: (31.9 GB/29.7 GiB)
[36814.685829] sd 33:0:0:0: [sdb] Write Protect is off
[36814.685833] sd 33:0:0:0: [sdb] Mode Sense: 03 00 00 00
[36814.690127] sd 33:0:0:0: [sdb] No Caching mode page found
[36814.690132] sd 33:0:0:0: [sdb] Assuming drive cache: write through
[36814.713610]  sdb: sdb1
[36814.714055] sd 33:0:0:0: [sdb] Attached SCSI removable disk

可以看到SD卡對(duì)應(yīng)的設(shè)備節(jié)點(diǎn)為/dev/sdb,對(duì)應(yīng)1個(gè)分區(qū)sdb1;

root@@ubuntu:/work/sambashare/rk3588/friendly/sd-fuse_rk3588# sudo ls /dev/sdb*
/dev/sdb  /dev/sdb1
root@ubuntu:/work/sambashare/rk3588/friendly/sd-fuse_rk3588# df -hT
文件系統(tǒng)       類(lèi)型      容量  已用  可用 已用% 掛載點(diǎn)
udev           devtmpfs  3.9G     0  3.9G    0% /dev
tmpfs          tmpfs     791M  3.6M  787M    1% /run
/dev/sda5      ext4       98G   69G   24G   75% /
tmpfs          tmpfs     3.9G     0  3.9G    0% /dev/shm
tmpfs          tmpfs     5.0M  4.0K  5.0M    1% /run/lock
tmpfs          tmpfs     3.9G     0  3.9G    0% /sys/fs/cgroup
/dev/sda1      vfat      511M  4.0K  511M    1% /boot/efi
/dev/loop15    squashfs  497M  497M     0  100% /snap/gnome-42-2204/132
tmpfs          tmpfs     791M     0  791M    0% /run/user/0
tmpfs          tmpfs     791M   36K  791M    1% /run/user/1000
/dev/sdc2      ext4       11G  311M  9.8G    4% /media/zhengyang/userdata
/dev/sdc1      ext4      4.5G  4.4G   35M  100% /media/zhengyang/rootfs

開(kāi)始制作SD啟動(dòng)卡:

root@ubuntu:/work/sambashare/rk3588/friendly/sd-fuse_rk3588# sudo dd if=out/rk3588-sd-debian-bullseye-desktop-6.1-arm64-20240714.img of=/dev/sdb bs=4M status=progress

1.2 uboot環(huán)境變量

將SD卡插入到開(kāi)發(fā)板,并使用準(zhǔn)備好的USB轉(zhuǎn)串口適配器和連接線(需另購(gòu)),連接開(kāi)發(fā)板,給開(kāi)發(fā)板上電。在啟動(dòng)過(guò)程中按下CTRL+C進(jìn)入uboot命令行模式;

View Code


1.2.1 啟動(dòng)命令行

查看內(nèi)核啟動(dòng)命令;

=> print bootcmd
bootcmd=boot_fit;boot_android ${devtype} ${devnum};bootrkp;run distro_bootcmd;

1.2.2 啟動(dòng)參數(shù)

查看內(nèi)核啟動(dòng)參數(shù):

=> pri bootargs
bootargs=storagemedia=sd androidboot.storagemedia=sd androidboot.mode=normal androidboot.dtbo_idx=1

1.2.3 資源文件

uboot查看資源文件:

# 切換到SD卡所屬設(shè)備
==> mmc dev 1
switch to partitions #0, OK
mmc1 is current device

==> mmc info
Device: mmc@fe2c0000
Manufacturer ID: 3
OEM: 5344
Name: SD32G
Timing Interface: Legacy
Tran Speed: 52000000
Rd Block Len: 512
SD version 3.0
High Capacity: Yes
Capacity: 29.7 GiB
Bus Width: 4-bit
Erase Group Size: 512 Bytes

# 從resource分區(qū)讀取20個(gè)扇區(qū)數(shù)據(jù)
==> mmc read 0x10000000  0xa000 20
MMC read: dev # 1, block # 40960, count 32 ... 32 blocks read: OK

# 查看前兩個(gè)扇區(qū)數(shù)據(jù)
==> md.b 0x10000000 0x400
10000000: 52 53 43 45 00 00 00 00 01 01 01 00 18 00 00 00    RSCE............
10000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
......
10000200: 45 4e 54 52 72 6b 33 33 39 39 2d 6e 61 6e 6f 70    ENTRrk3399-nanop
10000210: 69 34 2d 72 65 76 30 30 2e 64 74 62 00 00 00 00    i4-rev00.dtb....
10000220: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
......
100002e0: 02 8a cd 4f a8 69 32 dd d0 bd de 09 34 59 ad 6e    ...O.i2.....4Y.n
100002f0: 7d 42 d6 ac 00 00 00 00 00 00 00 00 00 00 00 00    }B..............
......

這里我們讀取resource分區(qū)的數(shù)據(jù),也就是resource.img鏡像,可以看到以上輸出內(nèi)容中包含了設(shè)備樹(shù)文件的數(shù)據(jù)。

1.2.4 設(shè)備樹(shù)

查看設(shè)備樹(shù):

=> print dtb_name
dtb_name=rk3588-nano0pi6-rev01.dtb

1.3 啟動(dòng)內(nèi)核

當(dāng)我們?cè)趗boot命令行執(zhí)行了boot命令時(shí),uboot會(huì)獲取bootcmd環(huán)境變量的內(nèi)容,然后執(zhí)行bootcmd中保存的啟動(dòng)命令。

接下來(lái)我們來(lái)分析一下bootcmd默認(rèn)配置,在默認(rèn)環(huán)境變量default_environment(位于uboot-rockchip/include/env_default.h)中定義有,其內(nèi)容大致如下:

const uchar default_environment[] = {
	"bootcmd="      CONFIG_BOOTCOMMAND              "?"
    "bootdelay="    __stringify(CONFIG_BOOTDELAY)    "?"
    "baudrate="    __stringify(CONFIG_BAUDRATE)    "?"
    "ipaddr="    __stringify(CONFIG_IPADDR)    "?"
    "serverip="    __stringify(CONFIG_SERVERIP)    "?"
    "netmask="    __stringify(CONFIG_NETMASK)    "?"
    ......
#ifdef  CONFIG_EXTRA_ENV_SETTINGS
        CONFIG_EXTRA_ENV_SETTINGS
#endif
        "?"
};

默認(rèn)啟動(dòng)命令CONFIG_BOOTCOMMAND定義在uboot-rockchip/include/configs/nanopi6.h,該文件存放著開(kāi)發(fā)板配置信息,被uboot-rockchip/include/config.h文件引入。

#include 

/* Remove or override few declarations from rk3588-common.h */
#undef CONFIG_BOOTCOMMAND
#undef CONFIG_DISPLAY_BOARDINFO_LATE
#undef RKIMG_DET_BOOTDEV
#undef RKIMG_BOOTCOMMAND

#define CONFIG_SYS_MMC_ENV_DEV          0
#define CONFIG_SYS_MMC_MAX_BLK_COUNT    32768

#define CONFIG_MISC_INIT_R
#define CONFIG_SERIAL_TAG

#ifndef CONFIG_SPL_BUILD

#define ROCKCHIP_DEVICE_SETTINGS 
        "stdout=serial,vidconsole?" 
        "stderr=serial,vidconsole?"

#define RKIMG_DET_BOOTDEV 
        "rkimg_bootdev=" 
        "if mmc dev 1 && rkimgtest mmc 1; then " 
                "setenv devtype mmc; setenv devnum 1; echo Boot from SDcard;" 
        "elif mmc dev 0; then " 
                "setenv devtype mmc; setenv devnum 0;" 
        "elif rksfc dev 1; then " 
                "setenv devtype spinor; setenv devnum 1;" 
        "fi; ?"

#define RKIMG_BOOTCOMMAND 
        "boot_fit;" 
        "boot_android ${devtype} ${devnum};" 
        "bootrkp;" 
        "run distro_bootcmd;"

#define CONFIG_BOOTCOMMAND              RKIMG_BOOTCOMMAND

#endif

這里引入了uboot-rockchip/include/configs/rk3588_common.h,而該文件又引入了uboot-rockchip/include/configs/rockchip-common.h。

這里支持了內(nèi)核的4種引導(dǎo)方式:

boot_fit:從eMMC中boot/recovery分區(qū)(如果進(jìn)入的是normal系統(tǒng),則為boot分區(qū);如果進(jìn)入的是recovery系統(tǒng),則為recovery分區(qū))加載FIT uImage鏡像文件(通常由kernel + dtb + ramdisk組成)到內(nèi)存,然后啟動(dòng)內(nèi)核 ;

boot_android:?jiǎn)?dòng)Android內(nèi)核鏡像;

bootrkp:通常用于Rockchip平臺(tái)上的特定啟動(dòng)操作,可能用于啟動(dòng)特定的固件或者特殊的操作模式;

distro_bootcmd:運(yùn)行uboot環(huán)境中定義的 distro_bootcmd,這是一個(gè)uboot環(huán)境變量,通常包含了一系列的啟動(dòng)命令,比如嘗試從網(wǎng)絡(luò)引導(dǎo)、從存儲(chǔ)設(shè)備引導(dǎo)等;

其中boot_fit、distro_bootcmd啟動(dòng)方式我們?cè)凇?Rockchip RK3399 - 移植linux 5.2.8》中有過(guò)介紹。

1.3.1 內(nèi)核啟動(dòng)日志

輸入boot命令啟動(dòng)內(nèi)核:

=> boot
## Booting FIT Image FIT: No fit blob           # 命令boot_fit
FIT: No FIT image
ANDROID: reboot reason: "(none)"                # 命令boot_android
Not AVB images, AVB skip
No valid android hdr
Android image load failed
Android boot failed, error -1.

## Booting Rockchip Format Image                # 命令bootrkp 
fdt      @ 0x08300000 (0x000421b2)              # fdt加載到內(nèi)存的地址
kernel   @ 0x00400000 (0x021c7808)              # kernel加載到內(nèi)存的地址
ramdisk  @ 0x0a200000 (0x007b2bc0)              # ramdisk加載到內(nèi)存的地址
Fdt Ramdisk skip relocation
## Flattened Device Tree blob at 0x08300000
   Booting using the fdt blob at 0x08300000
   Using Device Tree in place at 0000000008300000, end 00000000083451b1
## reserved-memory:
  cma: addr=10000000 size=8000000
  drm-logo@00000000: addr=edf00000 size=468000
  vendor-storage-rm@00000000: addr=ebcd3000 size=10000
  ramoops@110000: addr=110000 size=e0000
Adding bank: 0x00200000 - 0x08400000 (size: 0x08200000)
Adding bank: 0x09400000 - 0xf0000000 (size: 0xe6c00000)
Adding bank: 0x100000000 - 0x3fc000000 (size: 0x2fc000000)
Adding bank: 0x3fc500000 - 0x3fff00000 (size: 0x03a00000)
Adding bank: 0x4f0000000 - 0x500000000 (size: 0x10000000)
Total: 10246.299/11135.828 ms

Starting kernel ...

[   11.146608] Booting Linux on physical CPU 0x0000000000 [0x412fd050]
[   11.146631] Linux version 6.1.25 (root@ubuntu) (aarch64-linux-gnu-gcc (Ubuntu 10.5.0-1ubuntu1~20.04) 10.5.0, GNU ld (GNU Binutils for Ubuntu) 2.34) #1 SMP Wed Dec 27 21:53:18 CST 2023
[   11.153743] Machine model: FriendlyElec NanoPC-T6
......
[   11.510154] Kernel command line: storagemedia=sd androidboot.storagemedia=sd androidboot.mode=normal androidboot.dtbo_idx=1 androidboot.verifiedbootstate=orange earlycon=uart8250,mmio32,0xfeb50000 console=ttyFIQ0 coherent_pool=1m irqchip.gicv3_pseudo_nmi=0 rw root=/dev/mmcblk0p8 rootfstype=ext4 data=/dev/mmcblk0p9 consoleblank=0 cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory swapaccount=1
......
Debian GNU/Linux 11 NanoPC-T6 ttyFIQ0

NanoPC-T6 login: [   20.885195] systemd-journald[409]: File /var/log/journal/b9164042f80842f6968af54e1d15c9af/user-1000.journal corrupted or uncleanly shut down, renaming and replacing.
[   21.783657] rk_hdmirx fdee0000.hdmirx-controller: hdmirx_audio_startup: device is no connected or audio is off
[   26.433687] platform mtd_vendor_storage: deferred probe pending

NanoPC-T6 login:

(1) 首先執(zhí)行boot_fit命令,對(duì)于FIT uImage,其中地址范圍0x00000000~0x00000027表示的是fdt_header結(jié)構(gòu)體的成員信息。

因此會(huì)調(diào)用fit_get_blob函數(shù)獲取boot/recovery分區(qū)(如果進(jìn)入的是normal系統(tǒng),則獲取boot分區(qū);如果進(jìn)入的是recovery系統(tǒng),則獲取recovery分區(qū))第一個(gè)扇區(qū)數(shù)據(jù),并對(duì)fdt_header結(jié)構(gòu)體進(jìn)行校驗(yàn)判斷是不是FIT uImage。

由于正常情況下我們進(jìn)入的是normal系統(tǒng),則從boot分區(qū)加載boot.img數(shù)據(jù),從輸出的日志信息可以看出我們燒錄的boot.img并不是FIT uIamge。

(2) 接著執(zhí)行boot_android命令,從輸出日志可以看到應(yīng)該也是引導(dǎo)失敗了。

(3) 執(zhí)行bootrkp命令。

(4) 執(zhí)行distro_bootcmd命令。

有關(guān)bootrkp和distro_bootcmd啟動(dòng)方式,我們接下來(lái)詳細(xì)介紹。

1.3.2 加載命令行

不知道你有沒(méi)有留意內(nèi)核啟動(dòng)輸出命令行信息;

[   11.510154] Kernel command line: storagemedia=sd androidboot.storagemedia=sd androidboot.mode=normal androidboot.dtbo_idx=1 androidboot.verifiedbootstate=orange earlycon=uart8250,mmio32,0xfeb50000 console=ttyFIQ0 coherent_pool=1m irqchip.gicv3_pseudo_nmi=0 rw root=/dev/mmcblk0p8 rootfstype=ext4 data=/dev/mmcblk0p9 consoleblank=0 cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory swapaccount=1

這里輸出的信息為啥和bootargs環(huán)境變量以及arch/arm64/boot/dts/rockchip/rk3588-nanopi6-common.dtsi內(nèi)容不一樣呢?

=> pri bootargs
bootargs=storagemedia=sd androidboot.storagemedia=sd androidboot.mode=normal androidboot.dtbo_idx=1


# 設(shè)備樹(shù)設(shè)備節(jié)點(diǎn)內(nèi)容
chosen: chosen {
	bootargs = "earlycon=uart8250,mmio32,0xfeb50000 console=ttyFIQ0 coherent_pool=1m irqchip.gicv3_pseudo_nmi=0";
};

那么我們不得不介紹內(nèi)核啟動(dòng)后是如何獲取到啟動(dòng)參數(shù)。對(duì)于ARM64來(lái)說(shuō),uboot在啟動(dòng)內(nèi)核時(shí)會(huì)將r2設(shè)置為dtb文件的開(kāi)始地址。

1.3.2.1 內(nèi)核

bootargs

來(lái)源

對(duì)于開(kāi)發(fā)板開(kāi)發(fā)板而言,r2設(shè)置為了rk3588-nanopi6-rev01.dtb加載到內(nèi)存的地址。

這里我們直接從內(nèi)核start_kernel函數(shù)開(kāi)始說(shuō)起,其位于init/main.c文件,函數(shù)調(diào)用棧如下;

#char __initdata boot_command_line[COMMAND_LINE_SIZE];   // 全局變量,定義在init/main.c

start_kernel()  // init/main.c
    char *command_line;	
	.......
	setup_arch(&command_line);  // arch/arm64/kernel/setup.c
		  ......
		  *cmdline_p = boot_command_line;
		  ......
          // __fdt_pointer:dtb所在的物理地址,由bootloader通過(guò)x0寄存器傳遞過(guò)來(lái)
		  setup_machine_fdt(__fdt_pointer);      // arch/arm64/kernel/setup.c
				// 返回dtb所在的虛擬地址dt_virt
		  		void *dt_virt = fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL)
				if (!dt_virt || !early_init_dt_scan(dt_virt)) {
                    ........
                }
                name = of_flat_dt_get_machine_name();
				pr_info("Machine model: %sn", name);
	 machine_desc = mdesc;
	......

這里我們重點(diǎn)關(guān)注early_init_dt_scan函數(shù),early_init_dt_scan主要是對(duì)dtb進(jìn)行早期的掃描工作,下面是簡(jiǎn)要介紹函數(shù)的調(diào)用流程和實(shí)現(xiàn)細(xì)節(jié):

early_init_dt_scan(dt_virt)                // drivers/of/fdt.c  
    // 對(duì)dtb頭進(jìn)行檢查
	early_init_dt_verify(dt_virt)
   	early_init_dt_scan_nodes()   // 遍歷設(shè)備樹(shù)的節(jié)點(diǎn),解析出重要的信息用于內(nèi)核啟動(dòng)
        /* Retrieve various information from the /chosen node */
        of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);
        /* Initialize {size,address}-cells info */
        of_scan_flat_dt(early_init_dt_scan_root, NULL);
        /* Setup memory, calling early_init_dt_add_memory_arch */
        of_scan_flat_dt(early_init_dt_scan_memory, NULL);

of_scan_flat_dt對(duì)dtb里面的所有節(jié)點(diǎn)進(jìn)行掃描,用提供的回調(diào)函數(shù)循環(huán)處理節(jié)點(diǎn)信息,回調(diào)函數(shù)返回0繼續(xù)掃描,返回非0結(jié)束掃描,當(dāng)掃描到最后一個(gè)節(jié)點(diǎn)也會(huì)結(jié)束掃描;

/**
 * of_scan_flat_dt - scan flattened tree blob and call callback on each.
 * @it: callback function
 * @data: context data pointer
 *
 * This function is used to scan the flattened device-tree, it is
 * used to extract the memory information at boot before we can
 * unflatten the tree
 */
int __init of_scan_flat_dt(int (*it)(unsigned long node,
                                     const char *uname, int depth,
                                     void *data),
                           void *data)
{
    	//dtb數(shù)據(jù)的地址,也就是根節(jié)點(diǎn)的地址
        const void *blob = initial_boot_params;
        const char *pathp;
        int offset, rc = 0, depth = -1;

        if (!blob)
                return 0;

    	// 從根節(jié)點(diǎn)遍歷dtb中每個(gè)節(jié)點(diǎn),返回的offset就是每個(gè)節(jié)點(diǎn)的地址
        // offset:表示節(jié)點(diǎn)的地址相對(duì)于根節(jié)點(diǎn)的偏移量,也是節(jié)點(diǎn)數(shù)據(jù)所在地址
        // depth:代表節(jié)點(diǎn)相對(duì)于根節(jié)點(diǎn)的深度,比如根節(jié)點(diǎn)深度是0,/chosen節(jié)點(diǎn)是1
        for (offset = fdt_next_node(blob, -1, &depth);
             offset >= 0 && depth >= 0 && !rc;
             offset = fdt_next_node(blob, offset, &depth)) {

            	// 解析出節(jié)點(diǎn)名稱(chēng)
                pathp = fdt_get_name(blob, offset, NULL);
                if (*pathp == '/')
                        pathp = kbasename(pathp);
            	// 回調(diào)函數(shù)解析節(jié)點(diǎn),it是傳遞進(jìn)來(lái)的設(shè)備樹(shù)節(jié)點(diǎn)的解析函數(shù),需要解析什么消息就傳遞進(jìn)來(lái)相應(yīng)的節(jié)點(diǎn)解析函數(shù)
                rc = it(offset, pathp, depth, data);
        }
        return rc;
}

early_init_dt_scan_chosen用于掃描chosen節(jié)點(diǎn),并把bootargs屬性值拷貝到boot_command_line中,如果內(nèi)核定義了CONFIG_CMDLINE這個(gè)宏,則把配置的命令行參數(shù)也拷貝到boot_command_line;

/*
 * Convert configs to something easy to use in C code
 */
#if defined(CONFIG_CMDLINE_FORCE)
static const int overwrite_incoming_cmdline = 1;
static const int read_dt_cmdline;
static const int concat_cmdline;
#elif defined(CONFIG_CMDLINE_EXTEND)
static const int overwrite_incoming_cmdline;
static const int read_dt_cmdline = 1;
static const int concat_cmdline = 1;
#else /* CMDLINE_FROM_BOOTLOADER */             // 走這里
static const int overwrite_incoming_cmdline;
static const int read_dt_cmdline = 1;
static const int concat_cmdline;
#endif

#ifdef CONFIG_CMDLINE
static const char *config_cmdline = CONFIG_CMDLINE;
#else
static const char *config_cmdline = "";
#endif


int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
                                     int depth, void *data)
{
        int l = 0;
        const char *p = NULL;
        char *cmdline = data;     // 即boot_command_line
        const void *rng_seed;

        pr_debug("search "chosen", depth: %d, uname: %sn", depth, uname);

    	// 節(jié)點(diǎn)的深度要為1,數(shù)據(jù)不能使NULL,同時(shí)節(jié)點(diǎn)名字是"chosen"或者"chosen@0"
        if (depth != 1 || !cmdline ||
            (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0))
                return 0;

    	// 解析initrd相關(guān)
        early_init_dt_check_for_initrd(node);

        /* Put CONFIG_CMDLINE in if forced or if data had nothing in it to start */
        if (overwrite_incoming_cmdline || !cmdline[0])  // 進(jìn)入
                strlcpy(cmdline, config_cmdline, COMMAND_LINE_SIZE);

        /* Retrieve command line unless forcing */
        if (read_dt_cmdline)   // 從chosen節(jié)點(diǎn)中解析出bootargs屬性
                p = of_get_flat_dt_prop(node, "bootargs", &l);

        if (p != NULL && l > 0) {
                if (concat_cmdline) {
                        int cmdline_len;
                        int copy_len;
                        strlcat(cmdline, " ", COMMAND_LINE_SIZE);
                        cmdline_len = strlen(cmdline);
                        copy_len = COMMAND_LINE_SIZE - cmdline_len - 1;
                        copy_len = min((int)l, copy_len);
                        strncpy(cmdline + cmdline_len, p, copy_len);
                        cmdline[cmdline_len + copy_len] = '?';
                } else {   // 追加bootargs參數(shù)到boot_command_line
                        strlcpy(cmdline, p, min((int)l, COMMAND_LINE_SIZE));
                }
        }

        pr_debug("Command line is: %sn", (char*)data);

        rng_seed = of_get_flat_dt_prop(node, "rng-seed", &l);
        if (rng_seed && l > 0) {
                add_bootloader_randomness(rng_seed, l);

                /* try to clear seed so it won't be found. */
                fdt_nop_property(initial_boot_params, node, "rng-seed");

                /* update CRC check value */
                of_fdt_crc32 = crc32_be(~0, initial_boot_params,
                                fdt_totalsize(initial_boot_params));
        }

        /* break now */
        return 1;
}

如果想查看內(nèi)核debug級(jí)別日志可以配置:

# arch/arm64/configs/nanopi6_linux_defconfig
Kernel hacking  --->
    printk and dmesg options  --->
        (8) Default console loglevel (1-15)   # CONFIG_CONSOLE_LOGLEVEL_DEFAULT
        
# 修改drivers/of/fdt.c  即在需要輸出debug級(jí)別日志的文件頭部定義如下宏
#define DEBUG

通過(guò)追加日志,我們重新編譯并燒錄會(huì)發(fā)現(xiàn)啟動(dòng)命令行的確是如下這個(gè)內(nèi)容:

[    0.000000] OF: fdt: search "chosen", depth: 1, uname: chosen
[    0.000000] OF: fdt: Looking for initrd properties...
[    0.000000] OF: fdt: initrd_start=0xa200000  initrd_end=0xa9b2bc0
[    0.000000] OF: fdt: Command line is: storagemedia=sd androidboot.storagemedia=sd androidboot.mode=normal androidboot.dtbo_idx=1 androidboot.verifiedbootstate=orange earlycon=uart8250,mmio32,0xfeb50000 console=ttyFIQ0 coherent_pool=1m irqchip.gicv3_pseudo_nmi=0 rw root=/dev/mmcblk0p8 rootfstype=ext4 data=/dev/mmcblk0p9 consoleblank=0 cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory swapaccount=1

1.3.2.2

dtb

bootargs

來(lái)源

實(shí)際上dtb中的bootargs的來(lái)源有如下幾種;

內(nèi)核啟動(dòng)參數(shù)bootargs保存在dts的chosen節(jié)點(diǎn)的bootargs屬性,這里就是arch/arm64/boot/dts/rockchip/rk3588-nanopi6-common.dtsi這個(gè)設(shè)備樹(shù)源文件;

bootargs數(shù)據(jù)可以是在dts源文件中定義,也可以是uboot啟動(dòng)內(nèi)核時(shí)傳遞給內(nèi)核;

其中uboot傳遞的bootargs參數(shù)優(yōu)先級(jí)高于設(shè)備樹(shù)中定義的bootargs,如果是uboot傳遞的bootargs,在內(nèi)核啟動(dòng)階段就會(huì)調(diào)用fdt_chosen函數(shù)將環(huán)境變量中的bootargs參數(shù)寫(xiě)進(jìn)dtb數(shù)據(jù)中;

既然uboot傳遞了bootargs參數(shù),那么內(nèi)核將會(huì)使用uboot傳遞過(guò)來(lái)的bootargs參數(shù),不過(guò)該參數(shù)為何和內(nèi)核啟動(dòng)輸出的不太一樣呢?為此我們不得不去研究bootrkp啟動(dòng)是否追加了啟動(dòng)參數(shù);

boot_rockchip_image(dev_desc, &part)   // bootrkp啟動(dòng)方式
	......
    // 設(shè)置內(nèi)核加載地址(Image鏡像)
	images.ep = kernel_addr_r;
	images.initrd_start = ramdisk_addr_r;
	images.initrd_end = ramdisk_addr_r + ramdisk_size;
	// 設(shè)置設(shè)備樹(shù)加載地址
	images.ft_addr = (void *)fdt_addr_r;
    // 設(shè)備樹(shù)長(zhǎng)度
	images.ft_len = fdt_totalsize(fdt_addr_r);
	do_bootm_linux(0, 0, NULL, &images);      // arch/arm/lib/bootm.c
		boot_prep_linux(images);              // arch/arm/lib/bootm.c
			image_setup_linux(images)         // common/image.c 
                ulong of_size = images->ft_len;
                char **of_flat_tree = &images->ft_addr;	
				struct lmb *lmb = &images->lmb;
                boot_fdt_add_mem_rsv_regions(lmb, *of_flat_tree);	
				boot_get_cmdline(lmb, &images->cmdline_start,
                                &images->cmdline_end);
 				boot_relocate_fdt(lmb, of_flat_tree, &of_size);
				image_setup_libfdt(images, *of_flat_tree, of_size, lmb); // common/image-fdt.c
            ......    
        ......
                
# 可以通過(guò)如下代碼輸出啟動(dòng)參數(shù)
char *commandline = env_get("bootargs");
printf("%s %d:%sn", __func__, __LINE__, commandline);

重點(diǎn)關(guān)注image_setup_libfdt,定義在common/image-fdt.c;

int image_setup_libfdt(bootm_headers_t *images, void *blob,
                       int of_size, struct lmb *lmb)
{
        ulong *initrd_start = &images->initrd_start;
        ulong *initrd_end = &images->initrd_end;
        int ret = -EPERM;
        int fdt_ret;

    	// 進(jìn)行架構(gòu)特定的設(shè)備樹(shù)修正
        if (arch_fixup_fdt(blob) < 0) {
                printf("ERROR: arch-specific fdt fixup failedn");
                goto err;
        }

#if defined(CONFIG_PASS_DEVICE_SERIAL_BY_FDT)     // 定義
    	// 配置根節(jié)點(diǎn)
        if (fdt_root(blob) < 0) {
                printf("ERROR: root node setup failedn");
                goto err;
        }
#endif
    	// 創(chuàng)建/chosen節(jié)點(diǎn)
        if (fdt_chosen(blob) < 0) {
                printf("ERROR: /chosen node create failedn");
                goto err;
        }

        /* Update ethernet nodes */
        fdt_fixup_ethernet(blob);
        if (IMAGE_OF_BOARD_SETUP) {
                fdt_ret = ft_board_setup(blob, gd-?>bd);
                if (fdt_ret) {
                        printf("ERROR: board-specific fdt fixup failed: %sn",
                               fdt_strerror(fdt_ret));
                        goto err;
                }
        }
        if (IMAGE_OF_SYSTEM_SETUP) {
                fdt_ret = ft_system_setup(blob, gd->bd);
                if (fdt_ret) {
                        printf("ERROR: system-specific fdt fixup failed: %sn",
                               fdt_strerror(fdt_ret));
                        goto err;
                }
        }

        /* Delete the old LMB reservation */
        if (lmb)
                lmb_free(lmb, (phys_addr_t)(u32)(uintptr_t)blob,
                         (phys_size_t)fdt_totalsize(blob));

        ret = fdt_shrink_to_minimum(blob, 0);
        if (ret < 0)
                goto err;
        of_size = ret;

        if (*initrd_start && *initrd_end) {
                of_size += FDT_RAMDISK_OVERHEAD;
                fdt_set_totalsize(blob, of_size);
        }
        /* Create a new LMB reservation */
        if (lmb)
                lmb_reserve(lmb, (ulong)blob, of_size);

        fdt_initrd(blob, *initrd_start, *initrd_end);
        if (!ft_verify_fdt(blob))
                goto err;
#if defined(CONFIG_SOC_KEYSTONE)
        if (IMAGE_OF_BOARD_SETUP)
                ft_board_setup_ex(blob, gd-?>bd);
#endif

        return 0;
err:
        printf(" - must RESET the board to recover.nn");

        return ret;
}

這里我們只需要關(guān)注fdt_chosen函數(shù),定義在common/fdt_support.c;其中rk3399和rk3588 SDK的u-boot源碼是不一樣的;

以rk3588為例:

int fdt_chosen(void *fdt)
{
        int   nodeoffset;
        int   err;
        char  *str;             /* used to set string properties */

    	// 檢查設(shè)備樹(shù)頭部是否有效
        err = fdt_check_header(fdt);
        if (err < 0) {
                printf("fdt_chosen: %sn", fdt_strerror(err));
                return err;
        }

        /* find or create "/chosen" node.  查找或創(chuàng)建/chosen節(jié)點(diǎn) */
        nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen");
        if (nodeoffset < 0)
                return nodeoffset;

    	// 獲取環(huán)境變量bootargs的值
        str = board_fdt_chosen_bootargs(fdt);
        if (str) {
            	// 設(shè)置設(shè)備樹(shù)中的bootargs屬性
                err = fdt_setprop(fdt, nodeoffset, "bootargs", str,
                                  strlen(str) + 1);
                if (err < 0) {
                        printf("WARNING: could not set bootargs %s.n",
                               fdt_strerror(err));
                        return err;
                }
        }

        return fdt_fixup_stdout(fdt, nodeoffset);
}

其中board_fdt_chosen_bootargs定義在arch/arm/mach-rockchip/board.c:

char *board_fdt_chosen_bootargs(void *fdt)
{
        /* bootargs_ext is used when dtbo is applied. */
        const char *arr_bootargs[] = { "bootargs", "bootargs_ext" };
        const char *bootargs;
        int nodeoffset;
        int i, dump;
        char *msg = "kernel";

        /* debug */
        hotkey_run(HK_INITCALL);
        dump = is_hotkey(HK_CMDLINE);
        if (dump)
                printf("## bootargs(u-boot): %snn", env_get("bootargs"));

        /* find or create "/chosen" node. */
        nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen");
        if (nodeoffset < 0)
                return NULL;

    	// 遍歷arr_bootargs,檢查設(shè)備樹(shù)中是否已有相關(guān)的bootargs
        for (i = 0; i < ARRAY_SIZE(arr_bootargs); i++) {
            	// 獲取/chosen節(jié)點(diǎn)的bootargs、bootargs_ext屬性值
                bootargs = fdt_getprop(fdt, nodeoffset, arr_bootargs[i], NULL);
                if (!bootargs)
                        continue;
                if (dump)
                        printf("## bootargs(%s-%s): %snn",
                               msg, arr_bootargs[i], bootargs);
                /*
                 * Append kernel bootargs
                 * If use AB system, delete default "root=" which route
                 * to rootfs. Then the ab bootctl will choose the
                 * high priority system to boot and add its UUID
                 * to cmdline. The format is "roo=PARTUUID=xxxx...".
                 */
#ifdef CONFIG_ANDROID_AB
                env_update_filter("bootargs", bootargs, "root=");
#else
            	// 進(jìn)入,更新bootargs環(huán)境變量,追加設(shè)備樹(shù)中配置的bootargs	
                env_update("bootargs", bootargs);
#endif
        }

#ifdef CONFIG_VENDOR_FRIENDLYELEC // 針對(duì)FriendlyELEC板卡的處理,進(jìn)入
        char *panel = board_get_panel_name();
    	// 如果設(shè)置了panel,更新bootargs環(huán)境變量,比如追加lcd=HD702E,213dpi
        if (panel) {
                char lcdinfo[128] = { 0 };
                strcpy(lcdinfo, "lcd=");
                strncat(lcdinfo, panel, sizeof(lcdinfo) - 5);
                env_update("bootargs", lcdinfo);
        }
#endif
#if defined(CONFIG_ENVF) || defined(CONFIG_ENV_PARTITION)  
        ......
#endif

#ifdef CONFIG_MTD_BLK
        ......
#endif

#ifdef CONFIG_ANDROID_AB
        ab_update_root_partition();
#endif
        /*
         * Initrd fixup: remove unused "initrd=0x...,0x...",
         * this for compatible with legacy parameter.txt
         */
        env_delete("bootargs", "initrd=", 0);

        /*
         * If uart is required to be disabled during
         * power on, it would be not initialized by
         * any pre-loader and U-Boot.
         *
         * If we don't remove earlycon from commandline,
         * kernel hangs while using earlycon to putc/getc
         * which may dead loop for waiting uart status.
         * (It seems the root cause is baundrate is not
         * initilalized)
         *
         * So let's remove earlycon from commandline.
         */
        if (gd-?>flags & GD_FLG_DISABLE_CONSOLE)
                env_delete("bootargs", "earlycon=", 0);

        /* Android header v4+ need this handle */
#ifdef CONFIG_ANDROID_BOOT_IMAGE
        struct andr_img_hdr *hdr;

        hdr = (void *)env_get_ulong("android_addr_r", 16, 0);
        if (hdr && !android_image_check_header(hdr) && hdr->header_version >= 4) {
                if (env_update_extract_subset("bootargs", "andr_bootargs", "androidboot."))
                        printf("extract androidboot.xxx errorn");
                if (dump)
                        printf("## bootargs(android): %snn", env_get("andr_bootargs"));
        }
#endif
        bootargs = env_get("bootargs");
        if (dump)
                printf("## bootargs(merged): %snn", bootargs);

        return (char *)bootargs;
}

以rk3399為例:

int fdt_chosen(void *fdt)
{
        /*
         * "bootargs_ext" is used when dtbo is applied.
         */
        const char *arr_bootargs[] = { "bootargs", "bootargs_ext" };
        int   nodeoffset;
        int   err;
        int   i;
        char  *str;             /* used to set string properties */
        int dump;

    	// 判斷HK_CMDLINE是否是熱鍵,返回false
        dump = is_hotkey(HK_CMDLINE);

    	// 檢查設(shè)備樹(shù)頭部是否有效
        err = fdt_check_header(fdt);
        if (err < 0) {
                printf("fdt_chosen: %sn", fdt_strerror(err));
                return err;
        }

        /* find or create "/chosen" node.  查找或創(chuàng)建/chosen節(jié)點(diǎn) */
        nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen");
        if (nodeoffset < 0)
                return nodeoffset;

    	// 獲取環(huán)境變量bootargs的值
        str = env_get("bootargs");
        if (str) {  // 如果環(huán)境變量配置了bootargs
#ifdef CONFIG_ARCH_ROCKCHIP       // 針對(duì)Rockchip架構(gòu)的處理
                const char *bootargs;

                if (dump)
                        printf("## U-Boot bootargs: %sn", str);

            	// 遍歷arr_bootargs,檢查設(shè)備樹(shù)中是否已有相關(guān)的bootargs
                for (i = 0; i < ARRAY_SIZE(arr_bootargs); i++) {
                    	// 獲取/chosen節(jié)點(diǎn)的bootargs、bootargs_ext屬性值
                        bootargs = fdt_getprop(fdt, nodeoffset,
                                               arr_bootargs[i], NULL);
                    	// 1. fdt_chosen 389:earlycon=uart8250,mmio32,0xff1a0000 swiotlb=1 coherent_pool=1m
                    	// 2. fdt_chosen 389:root=/dev/mmcblk2p8 rw rootfstype=ext4 rootflags=discard data=/dev/mmcblk2p9 console=ttyFIQ0 consoleblank=0 cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory swapaccount=1
						printf("%s %d:%sn", __func__, __LINE__, bootargs);
                        // 如果存在,更新環(huán)境變量bootargs
                        if (bootargs) {
                                if (dump)
                                        printf("## Kernel %s: %sn",
                                               arr_bootargs[i], bootargs);
                                /*
                                 * Append kernel bootargs
                                 * If use AB system, delete default "root=" which route
                                 * to rootfs. Then the ab bootctl will choose the
                                 * high priority system to boot and add its UUID
                                 * to cmdline. The format is "roo=PARTUUID=xxxx...".
                                 */
                                hotkey_run(HK_INITCALL);
#ifdef CONFIG_ANDROID_AB       // 未定義
                                env_update_filter("bootargs", bootargs, "root=");
#else                           // 進(jìn)入,更新bootargs環(huán)境變量,追加設(shè)備樹(shù)中配置的bootargs
                                env_update("bootargs", bootargs);
#endif
#ifdef CONFIG_MTD_BLK          // 未定義
                                char *mtd_par_info = mtd_part_parse();

                                if (mtd_par_info) {
                                        if (memcmp(env_get("devtype"), "mtd", 3) == 0)
                                                env_update("bootargs", mtd_par_info);
                                }
#endif
                                /*
                                 * Initrd fixup: remove unused "initrd=0x...,0x...",
                                 * this for compatible with legacy parameter.txt
                                 */
                                env_delete("bootargs", "initrd=", 0);

                                /*
                                 * If uart is required to be disabled during
                                 * power on, it would be not initialized by
                                 * any pre-loader and U-Boot.
                                 *
                                 * If we don't remove earlycon from commandline,
                                 * kernel hangs while using earlycon to putc/getc
                                 * which may dead loop for waiting uart status.
                                 * (It seems the root cause is baundrate is not
                                 * initilalized)
                                 *
                                 * So let's remove earlycon from commandline.
                                 */
                                if (gd-?>flags & GD_FLG_DISABLE_CONSOLE)
                                        env_delete("bootargs", "earlycon=", 0);
                        }
                }
#endif

#ifdef CONFIG_VENDOR_FRIENDLYELEC        // 針對(duì)FriendlyELEC板卡的處理,進(jìn)入
                char *panel = board_get_panel_name();
            	// 如果設(shè)置了panel,更新bootargs環(huán)境變量,比如追加lcd=HD702E,213dpi
                if (panel) {
                        char lcdinfo[128] = { 0 };
                        strcpy(lcdinfo, "lcd=");
                        strncat(lcdinfo, panel, sizeof(lcdinfo) - 5);
                        env_update("bootargs", lcdinfo);
                }
#endif
				// 獲取更新后的bootargs環(huán)境變量,并設(shè)置設(shè)備樹(shù)中的bootargs屬性
                str = env_get("bootargs");
            	// fdt_chosen 451:storagemedia=emmc androidboot.storagemedia=emmc androidboot.mode=normal androidboot.dtbo_idx=0 earlycon=uart8250,mmio32,0xff1a0000 swiotlb=1 coherent_pool=1m rw root=/dev/mmcblk2p8 rootfstype=ext4 rootflags=discard data=/dev/mmcblk2p9 console=ttyFIQ0 consoleblank=0 cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory swapaccount=1 lcd=HD702E,213dpi
                printf("%s %d:%sn", __func__, __LINE__, str);
                err = fdt_setprop(fdt, nodeoffset, "bootargs", str,
                                  strlen(str) + 1);
                if (err < 0) {
                        printf("WARNING: could not set bootargs %s.n",
                               fdt_strerror(err));
                        return err;
                }
        }

        if (dump)
                printf("## Merged bootargs: %sn", env_get("bootargs"));

        return fdt_fixup_stdout(fdt, nodeoffset);
}

通過(guò)分析,可以了解到fdt_chosen 函數(shù)主要完成了以下任務(wù):

確保設(shè)備樹(shù)的 /chosen 節(jié)點(diǎn)存在;

從環(huán)境變量中獲取和處理啟動(dòng)參數(shù) bootargs;

根據(jù)不同的硬件配置(如Rockchip架構(gòu)或FriendlyELEC板卡)調(diào)整啟動(dòng)參數(shù);

更新設(shè)備樹(shù)中的 bootargs 屬性,確保內(nèi)核可以正確獲得啟動(dòng)參數(shù);

修正標(biāo)準(zhǔn)輸出設(shè)備配置。

在上面代碼執(zhí)行過(guò)程中我們輸出了/chosen節(jié)點(diǎn)的bootargs、bootargs_ext屬性值,其中bootargs_ext屬性值哪里來(lái)的呢?

root=/dev/mmcblk2p8 rw rootfstype=ext4 rootflags=discard data=/dev/mmcblk2p9 console=ttyFIQ0 consoleblank=0 cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory swapaccount=1

這個(gè)值實(shí)際上配置在dtbo.img鏡像中,具體可以參考android_fdt_overlay_apply函數(shù),這個(gè)我們?cè)诮酉聛?lái)的內(nèi)容會(huì)介紹到。

1.4 uboot編譯和燒錄

1.4.1 編譯

如果我們對(duì)uboot源碼有改動(dòng),執(zhí)行如下命令進(jìn)行編譯;

root@ubuntu:/work/sambashare/rk3588/friendly/sd-fuse_rk3588# UBOOT_SRC=$PWD/uboot-rockchip ./build-uboot.sh debian-bullseye-desktop-arm64

編譯完成后debian-bullseye-desktop-arm64目錄下的uboot.img被更新了。

1.4.2

dd

燒錄

由于uboot.img占用的分區(qū)是uboot分區(qū),假設(shè)SD/TF Card設(shè)備節(jié)點(diǎn)為/dev/mmcblk0。

我們?cè)趗buntu開(kāi)啟http下載服務(wù),或者使用scp將鏡像文件發(fā)送到開(kāi)發(fā)版;

root@ubuntu:/work/sambashare/rk3588/friendly/sd-fuse_rk3588/debian-bullseye-desktop-arm64$ python3 -m http.server 8080

開(kāi)發(fā)板下載uboot.img,然后使用如下命令燒錄;

root@linaro-alip:/opt# sudo wget 192.168.0.200:8080/uboot.img
root@linaro-alip:/opt# sudo dd if=uboot.img of=/dev/mmcblk0p1 bs=1M

同樣如果我們修改了resource.img,也可以使用如下命令燒錄;

root@linaro-alip:/opt# sudo wget 192.168.0.200:8080/resource.img
root@linaro-alip:/opt# sudo dd if=resource.img of=/dev/mmcblk0p4 bs=1M

1.5 補(bǔ)充

新創(chuàng)云RK3588核心板介紹

1.1 適用范圍

產(chǎn)品采用核心板加底板方式,核心板主要集成四大主件(分別為主控,內(nèi)存,存儲(chǔ)和電源管理),核心板安裝可方便拆卸,客戶(hù)可以快速進(jìn)行二次開(kāi)發(fā),主要應(yīng)用于工業(yè)控制,商顯,智能家居汽車(chē)電子,醫(yī)療設(shè)備,產(chǎn)品形態(tài)有,廣告機(jī),無(wú)人值守機(jī)器人,送餐機(jī)器人,工業(yè)應(yīng)用機(jī)器人,平板電腦,學(xué)習(xí)機(jī),匝機(jī)通道,客流統(tǒng)計(jì),車(chē)牌識(shí)別,數(shù)字標(biāo)牌、智能自助終端、智能零售終端等相關(guān)產(chǎn)品。

1.2 產(chǎn)品概述

核心板采用 ROCKCHIP 八核 RK3588 四核 A76+四核 A55,搭載Android/Linux+QT/Ubuntu 系 統(tǒng) ,A76 主 頻 2.4GHz , A55 主 頻1.8G,采用 Mali-G610 MP4 GPU,內(nèi)置 6T 算力 NPU,內(nèi)存最大支持16GB,支持市面上通用顯示屏接口,支持多屏異顯,核心板接口豐富,引出全部功能引腳,支持多款外設(shè)擴(kuò)展,是您在人機(jī)交互、工控項(xiàng)目上的最佳選擇。

1.3 產(chǎn)品特點(diǎn)

◆ BDB 板對(duì)板連接器可拆卸式核心板,引腳高達(dá) 320P,引出全部功能。

◆ 支持 2 路 HDMI 輸出,2 路 MIPI 顯示屏,2 路 EDP 顯示屏,支持多屏異顯。

◆ 內(nèi)置 6T 算力 NPU。

◆ 最大支持 16GB 內(nèi)存。

◆ 支持 Android/Linux+QT/麒麟信安、鴻蒙系統(tǒng)定制,提供系統(tǒng)調(diào)用接口 API 參考代碼,完美支持客戶(hù)上層應(yīng)用 APP 開(kāi)發(fā)及SDK。

wKgZO2ev-l-AFls3AAmjrQA1k3c116.png

主要硬件指標(biāo)
CPU ROCKCHIP RK3588 八核 A76+A55
NPU 6 TOPS
GPU Mali G61 MP4
DDR LPDDR4x 可選配 4G/8G/16G
EMMC EMMC 5.1 標(biāo)配 8GB 選配 32G/64G/128G
工作電壓 3.4-5.5V 5A 以上
工作溫度 -10 到+60 度
連接方式 板對(duì)板連接器
尺寸 60mm 長(zhǎng)*50mm 寬*4.2mm 高
壽命 連續(xù)運(yùn)行壽命大于 5 年以上

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 開(kāi)發(fā)板
    +關(guān)注

    關(guān)注

    25

    文章

    5679

    瀏覽量

    104629
  • Uboot
    +關(guān)注

    關(guān)注

    4

    文章

    129

    瀏覽量

    29089
  • RK3588
    +關(guān)注

    關(guān)注

    7

    文章

    419

    瀏覽量

    5901
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    香蕉派瑞芯微 Rockchip RK3588 開(kāi)發(fā)板套件主要硬件規(guī)格

    香蕉派(Banana Pi) 瑞芯微 Rockchip RK3588 開(kāi)發(fā)板套件,支持8G內(nèi)存,32G eMMC存儲(chǔ)
    的頭像 發(fā)表于 03-03 09:18 ?1.1w次閱讀
    香蕉派瑞芯微 <b class='flag-5'>Rockchip</b> <b class='flag-5'>RK3588</b> 開(kāi)發(fā)板套件主要硬件規(guī)格

    瑞芯微RK3588開(kāi)發(fā)板RK3588 EVB和RK3588S EVB解讀

    瑞芯微RK3588開(kāi)發(fā)板RK3588 EVB和RK3588S EVB解讀 瑞芯微旗艦芯RK3588系列開(kāi)發(fā)板受到廣大開(kāi)發(fā)者伙伴的關(guān)注和問(wèn)詢(xún)。針對(duì)相關(guān)的開(kāi)發(fā)板功能、操作指南等問(wèn)題,我們一
    的頭像 發(fā)表于 09-22 15:54 ?2w次閱讀
    瑞芯微<b class='flag-5'>RK3588</b>開(kāi)發(fā)板<b class='flag-5'>RK3588</b> EVB和<b class='flag-5'>RK3588</b>S EVB解讀

    RK3588 Android+Linux雙系統(tǒng)方案的實(shí)現(xiàn)

    RK3588雙系統(tǒng)啟動(dòng)流程如下圖 ? uboot根據(jù)按鍵來(lái)識(shí)別要啟動(dòng)的系統(tǒng),這里可以使用撥碼開(kāi)關(guān)來(lái)代替。 uboot在加載分區(qū)的時(shí)根據(jù)分區(qū)名字來(lái)區(qū)分加載android或者linux的分區(qū),所以在
    的頭像 發(fā)表于 10-10 14:25 ?9776次閱讀
    <b class='flag-5'>RK3588</b> Android+Linux雙系統(tǒng)方案的實(shí)現(xiàn)

    RK3588 SDK編譯與固件燒寫(xiě)步驟

    ; make ARCH=arm64 rk3588sevb1-lp4x-v10.img -j24  單獨(dú)編譯uboot  $ 。/make.sh rk3588  2、固件燒寫(xiě)  升級(jí)工具
    發(fā)表于 08-31 17:45

    RK3588 Android 12.0 SDK編譯步驟分享

    rk3588sevb1-lp4x-v10.img -j24單獨(dú)編譯uboot$ ./make.sh rk35882、固件燒寫(xiě)升級(jí)工具版本:AndroidTool_Release_v2.84USB驅(qū)動(dòng)版本:Driver
    發(fā)表于 09-20 17:11

    【LGA封裝RK3588核心板】基于RK3588,小而強(qiáng)大的ArmSom-W3 CORE BOARD

    Armsom-RK3588 LGA Core board 是一款基于Rockchip RK3588芯片平臺(tái),采用LGA(506pin)封裝設(shè)計(jì)的一款極小尺寸的RK3588核心板。
    的頭像 發(fā)表于 07-03 16:08 ?2485次閱讀
    【LGA封裝<b class='flag-5'>RK3588</b>核心板】基于<b class='flag-5'>RK3588</b>,小而強(qiáng)大的ArmSom-W3 CORE BOARD

    rk3588rk3588s的區(qū)別

    高性能、低功耗的處理器,是針對(duì)不同市場(chǎng)設(shè)計(jì)的不同版本。這篇文章將介紹這兩種處理器的區(qū)別。 RK3588RK3588S的概述 - RK3588 RK
    的頭像 發(fā)表于 08-15 16:44 ?1.8w次閱讀

    rk3588rk3399的區(qū)別

    rk3588rk3399的區(qū)別 Rockchip是一家位于中國(guó)深圳的芯片設(shè)計(jì)公司,已經(jīng)發(fā)布了一系列的處理器芯片。其中,Rockchip RK358
    的頭像 發(fā)表于 08-15 16:44 ?4715次閱讀

    RK3588RK3066哪個(gè)好?

    RK3588RK3066哪個(gè)好? Rockchip是一家中國(guó)的半導(dǎo)體公司,專(zhuān)注于提供高性能低成本的芯片解決方案。在Rockchip的產(chǎn)品線中,RK
    的頭像 發(fā)表于 08-15 16:44 ?1824次閱讀

    RK35883588s的區(qū)別

    RK35883588s的區(qū)別 Rockchip RK3588RK3588s是兩種功能強(qiáng)大且廣受歡迎的片上系統(tǒng)(SoC)解決方案,用于一系
    的頭像 發(fā)表于 08-15 17:03 ?2.7w次閱讀

    RK3588系列有多少型號(hào)?

    和多種應(yīng)用的功能而受到廣泛的認(rèn)可。但是,對(duì)于普通用戶(hù)而言,RK3588系列又分別有多少型號(hào)呢?下面就詳細(xì)介紹RK3588系列的各種型號(hào)及其功能。 RK3588系列主要有以下幾種型號(hào):
    的頭像 發(fā)表于 08-15 17:04 ?5221次閱讀

    rk3588是什么類(lèi)型的芯片?

    rk3588是什么類(lèi)型的芯片? RK3588是一款高性能的處理器芯片,屬于Rockchip(瑞芯微電子)推出的第四代芯片產(chǎn)品。作為Rockchip旗下最頂級(jí)的處理器芯片,
    的頭像 發(fā)表于 08-15 17:04 ?7247次閱讀

    rk3588參數(shù)詳解 rk3588芯片參數(shù)

    rk3588參數(shù)詳解 rk3588芯片參數(shù) Rockchip官方已經(jīng)推出了全新一代的高端芯片RK3588,作為旗艦芯片,其蘊(yùn)含的高性能與先進(jìn)科技引起了廣泛關(guān)注。本篇文章將詳細(xì)
    的頭像 發(fā)表于 08-21 17:16 ?4.1w次閱讀

    rk3588是armv8嗎?rk3588硬件資料

    rk3588是armv8嗎?rk3588 硬件資料 RK3588是一款高性能處理器,是Rockchip公司推出的最新芯片。本文將詳細(xì)介紹
    的頭像 發(fā)表于 08-21 17:32 ?4876次閱讀

    迅為電子RK3588S與RK3588硬件性能區(qū)別及板卡選型

    迅為電子RK3588S與RK3588硬件性能區(qū)別及板卡選型
    的頭像 發(fā)表于 06-25 15:30 ?4974次閱讀
    迅為電子<b class='flag-5'>RK3588</b>S與<b class='flag-5'>RK3588</b>硬件性能區(qū)別及板卡選型
    主站蜘蛛池模板: 日本三级带日本三级带黄首页 | 国产资源免费观看 | 免费欧美黄色 | 国产免费一区二区三区 | 理论视频在线观看 | 狂捣猛撞侍卫攻双性王爷受 | 夜夜操网站 | h在线免费观看 | 六月婷婷激情综合 | 精品一级毛片 | 欧美高清a | 国产1卡2卡三卡四卡网站 | 天堂资源在线官网bt | 欧美经典三级春潮烂漫海棠红 | 夜夜骑日日操 | 把小嫩嫩曰出白浆 | 男男生子大肚play做到生 | 啪啪啦资源站永久 | 好大好硬好深好爽想要免费视频 | 一道精品一区二区三区 | 18美女扒开尿口无遮挡 | 人人天天夜夜 | 狠狠干狠狠操视频 | 女色专区 | 亚洲欧美卡通 动漫 丝袜 | 精品国产理论在线观看不卡 | 久久精品国产亚洲片 | 爱射综合 | 色天使久久 | 夜夜橹橹网站夜夜橹橹 | 日本成人小视频 | 久久99精品久久久久久牛牛影视 | 婷婷丁香六月天 | 在线午夜影院 | good韩国理论在线三级 | 亚洲欧美综合一区二区三区四区 | 国语自产免费精品视频一区二区 | 免费一级毛片视频 | 亚洲国产情侣偷自在线二页 | 啪啪在线视频 | 国产欧美乱码在线看 |