编辑
2025-03-03
记录知识
0

随着AI智能的发展,继传统的CPU和GPU之后,又推出了许多更适用于AI学习的芯片,本文就NPU芯片如何在RK平台提供的SDK基础上开发做一个介绍。

一、NPU芯片简介

NPU全称为Neural network Processing Unit,即神经网络处理器。

二、RKNN使用方法

1.SDK下载及内容介绍

可以在110服务器获取 /home/develop/rk/project/Rockchip_RK356X_RKNN_SDK_V0.7.0_20210402

这里 RKNN_API_for_RK356X 里面主要包含了linux和android系统对于如何使用模型文件调用NPU进行AI运算的demo。

rknn-toolkit 是用于将其他神经网络训练架构模型如何转化为 rknn 架构模型的demo,它分为了docker和nodocker版本,建议使用docker版,因为nodeocker版本对于python-3和pip软件版本的要求比较严格,环境不太好搭建。

2.rknn-toolkit 工具使用

这里我使用含docker版本举例。

  • 首先进入rknn-toolkit2-0.7.0/docker/ 文件夹
  • 可以看到 rknn-toolkit2-0.7.0-docker.tar.gz 镜像文件
  • 使用 sudo docker load --input rknn-toolkit2-0.7.0-docker.tar.gz 命令加载镜像
  • 加载成功后,可以使用 sudo docker images 命令确认。

正常加载后,就可以进入docker环境 如下,

docker run -t -i --privileged -v /home/kylin/:/home/kylin/ rknn-toolkit2:0.7.0 /bin/bash

执行后命令行的前缀会改变。

进入docker环境后,进入 rknn-toolkit2-0.7.0/examples/ 目录下,可以看到包含了一些以比较常见的神经网络训练框架命名的文件夹。

这里我们以caffe为例,将 caffemodule 转换为 rknnmodule。

进入 caffe/vgg-ssd/ 文件夹,其是转换 caffemodule 的一个demo 。里面使用了 deploy_rm_detection_output.prototxt 文件中提供的图层模型,把 caffemodule 通过 rknn.api 转换为了 rknnmodule 。重点包含以下几个函数:

image.png

image.png 可以看到流程和RK给出的文档中一致,按照步骤操作即可。

这里会需要一个 caffemodule 的训练模型,可以通过

https://eyun.baidu.com/s/3jJhPRzo , password is rknn

进行下载。

然后执行 python test.py 运行脚本,执行成功后就可以看到文件夹中多了 .rknn 为后缀的文件,它就是rk平台的模型。 这里就完成了模型的转换,过程中可能会根据模型效率/准确度的需求修改一些参数,可以参考SDK中的文档进行调整。

3.RKNN模型使用

上面我们已经得到了后缀为 .rknn 的模型文件,现在我们就来讲解如何在RK平台使用模型通过NPU进行图像的解析操作。其实上面在转换模型时已经使用python脚本进行了图像解析的示例,本章介绍demo中通过C语言调用RKNN接口的过程。

进入 RKNN_API_for_RK356X_v0.7_20210402/examples/rknn_ssd_demo/ 文件夹,可以看到 我们先看看源码调用流程

image.png 跟文档流程一致,其中多了一步 postProcessSSD ,这是将结果中的值转换为图片中的坐标点,用于后面画框所用。

image.png 看完了源代码我们可以编译应用。这里的环境是rk3568开发板+麒麟v10系统,所以直接执行 build-linux.sh 脚本。

image.png 完成后可以看到生成了 rknn_ssd_demo 的二进制文件,接下来我们使用它看看效果。

image.png 执行

./build/build_linux_aarch64/rknn_ssd_demo ./model/ssd_inception_v2.rknn ./model/road.bmp

第一个参数是我们生成的二进制文件
第二个参数是 .rknn 为后缀的module模型文件
第三个参数是要被检测的图片。执行后在本地文件夹中生成了 out.jpg 图片
输出如下 image.png

image.png 可以看到,模型在上图中成功识别到了行人和车辆的位置。

三、NPU硬件信息查看

如何判断是否调用到了NPU去处理的上面图像呢。我们可以通过中断:

image.png 如果调用到NPU,中断号会增加。

内核中还提供了调整NPU频率的接口:

image.png 查看NPU支持的模式,默认为 simple_ondemand

image.png 查看NPU当前的频率

echo performance > /sys/devices/platform/fde40000.npu/devfreq/fde40000.npu/governor

调整NPU的工作模式为性能模式(保持最大频率)

image.png 查看NPU当前工作状态,@之前为占用率,之后为当前频率

image.png 根据内核log,可以判断NPU是否被加载成功,从中也可以看出NPU包含了iommu模块,对内存读写进行了优化。

编辑
2025-03-03
记录知识
0

瑞芯微平台通常通过烧录的方式来更新系统,但是在一些项目评估的过程中,客户经常需要要求能够安装系统,为了让RK平台支持U盘安装,需要稍微在uboot进行修改,使得uboot阶段能够正常的加载到U盘的uImage,uInitrd,dtb文件即可。主要介绍如下

一、 文件列表

image.png

这里是U盘安装内U盘文件内容,主要分为

boot目录 内包含uboot启动所需要的uImage和uInitrd以及sysboot启动需要的extlinux.conf。主要用于启动安装系统 casper目录 内包含rockchip平台所需要的镜像文件 logo.bmp和logo_kernel.bmp 是安装中所需要的开机图片,如果需要使用其他开机图片,可以单独修改替换此图片即可 autorun.inf 和 kylin.ico 是U盘自动运行文件和U盘图标文件

1.1、extlinux.conf

文件内容如下

default install menu title Installer prompt 0 timeout 10 label install menu label kylinos installer linux /boot/uImage initrd /boot/uInitrd append console=tty0 loglevel=0

这里设置默认启动了uImage和uInitrd

1.2、 parameter-kylin.txt

文件内容如下

FIRMWARE_VER: 1.0 MACHINE_MODEL: RK3588 MACHINE_ID: 007 MANUFACTURER: RK3588 MAGIC: 0x5041524B ATAG: 0x00200800 MACHINE: 0xffffffff CHECK_MASK: 0x80 PWR_HLD: 0,0,A,0,1 TYPE: GPT CMDLINE: mtdparts=rk29xxnand:0x00004000@0x00004000(uboot),0x00002000@0x00008000(misc),0x00080000@0x0000a000(boot:bootable),0x00800000@0x0008a000(backup),0x01400000@0x0088a000(rootfs),-@0x01c8a000(userdata:grow) uuid:rootfs=614e0000-0000-4b53-8000-1d28000054a9

这里是安装过程中,需要对系统分区的描述文件。同RK平台的parameter.txt文件

1.3、 uboot-usb.img

这是支持机器的uboot通过默认usb启动的uboot镜像,如果需要使用U盘安装,则需要更新原先uboot镜像为此镜像。此镜像基于uboot额外做了如下措施

uboot内置设备树,确保uboot下usb功能正常 uboot内默认usb启动优先 uboot内默认支持u盘内开机图片显示

1.4、 idblock.bin/rk3588_spl_loader_xxx.bin

这是RK平台的loader 二进制文件,这里需要放置两个文件,安装时是用的idblock.bin,烧录的时候是用的rk3588_spl_loader_xxx.bin。

二、 启动修改点

2.1 uboot配置

diff --git a/configs/rockchip-linux.config b/configs/rockchip-linux.config index 3003d81..cee40ce 100644 --- a/configs/rockchip-linux.config +++ b/configs/rockchip-linux.config @@ -5,3 +5,6 @@ CONFIG_DM_PCA953X=y CONFIG_SPL_FIT_IMAGE_KB=4096 CONFIG_CHECK_VERSION_CHOOSE_DTB=y CONFIG_PHY_ROCKCHIP_NANENG_COMBOPHY=y +CONFIG_EMBED_KERNEL_DTB=y +CONFIG_EMBED_KERNEL_DTB_PATH="dts/rockchip-evb_rk3588.dtb" +CONFIG_EMBED_KERNEL_DTB_ALWAYS=n 2.2 开机显示特定logo diff --git a/include/config_distro_bootcmd.h b/include/config_distro_bootcmd.h index 9ed6b98..c1ec5e2 100644 --- a/include/config_distro_bootcmd.h +++ b/include/config_distro_bootcmd.h @@ -29,6 +29,7 @@ #define BOOTENV_SHARED_BLKDEV_BODY(devtypel) \ "if " #devtypel " dev ${devnum}; then " \ "setenv devtype " #devtypel "; " \ + "rockchip_show_logo;" \ "run scan_dev_for_boot_part; " \ "fi\0"

2.3 默认启动usb

diff --git a/include/configs/rockchip-common.h b/include/configs/rockchip-common.h index 002dcd6..0566ece 100644 --- a/include/configs/rockchip-common.h +++ b/include/configs/rockchip-common.h @@ -162,7 +162,14 @@ "setenv devtype ramdisk; setenv devnum 0;" \ "fi; \0" -#if defined(CONFIG_AVB_VBMETA_PUBLIC_KEY_VALIDATE) +#if defined(CONFIG_EMBED_KERNEL_DTB) +#define RKIMG_BOOTCOMMAND \ + "run usb_boot;" \ + "boot_android ${devtype} ${devnum};" \ + "boot_fit;" \ + "bootrkp;" \ + "run distro_bootcmd;" +#elif defined(CONFIG_AVB_VBMETA_PUBLIC_KEY_VALIDATE)

2.4 字符终端字体

修改: drivers/tty/vt/selection.c 修改: drivers/tty/vt/vt.c 修改: drivers/video/fbdev/core/bitblit.c 修改: drivers/video/fbdev/core/fbcon.c 修改: drivers/video/fbdev/core/fbcon.h 修改: drivers/video/fbdev/core/fbcon_ccw.c 修改: drivers/video/fbdev/core/fbcon_cw.c 修改: drivers/video/fbdev/core/fbcon_rotate.c 修改: drivers/video/fbdev/core/fbcon_ud.c 修改: include/linux/fb.h 修改: include/linux/font.h 修改: lib/fonts/Kconfig 修改: lib/fonts/Makefile 新文件: lib/fonts/font_cjk_16x16.c 新文件: lib/fonts/font_cjk_16x16.h 新文件: lib/fonts/font_cjk_32x32.c 新文件: lib/fonts/font_cjk_32x32.h 修改: lib/fonts/fonts.c

2.5 日志默认屏幕而非串口

diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-pc.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s-pc.dtsi index e49f5fa..ff182b1 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-pc.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588s-pc.dtsi @@ -10,7 +10,7 @@ / { chosen: chosen { - bootargs = "earlycon=uart8250,mmio32,0xfeb50000 console=ttyFIQ0 irqchip.gicv3_pseudo_nmi=0 root=PARTLABEL=rootfs rootfstype=ext4 ro rootwait overlayroot=device:dev=PARTLABEL=userdata,fstype=ext4,mkfs=1 coherent_pool=1m systemd.gpt_auto=0 cgroup_enable=memory swapaccount=1 net.ifnames=0"; + bootargs = "earlycon=uart8250,mmio32,0xfeb50000 irqchip.gicv3_pseudo_nmi=0 root=PARTLABEL=rootfs rootfstype=ext4 ro rootwait overlayroot=device:dev=PARTLABEL=userdata,fstype=ext4,mkfs=1 coherent_pool=1m systemd.gpt_auto=0 cgroup_enable=memory swapaccount=1 net.ifnames=0"; };

2.6 支持exfat

diff --git a/arch/arm64/configs/linux.config b/arch/arm64/configs/linux.config index 9a23fc2..6c569cd 100644 --- a/arch/arm64/configs/linux.config +++ b/arch/arm64/configs/linux.config @@ -6,6 +6,7 @@ CONFIG_TOUCHSCREEN_HX83102=y CONFIG_CAN=y CONFIG_CANFD_ROCKCHIP=y CONFIG_OVERLAY_FS=y +CONFIG_EXFAT_FS=y CONFIG_SND_SOC_FIREFLY_MULTICODECS=y

2.7 fit支持ramdisk打包

diff --git a/boot.its b/boot.its index 755005c..885bfd1 100644 --- a/boot.its +++ b/boot.its @@ -45,6 +45,21 @@ algo = "sha256"; }; }; + + ramdisk { + description = "Compressed Initramfs"; + data = /incbin/("ramdisk"); + type = "ramdisk"; + arch = "arm64"; + os = "linux"; + compression = "none"; + load = <0x00000000>; + entry = <0x00000000>; + + hash { + algo = "sha256"; + }; + }; }; configurations { @@ -55,6 +70,7 @@ fdt = "fdt"; kernel = "kernel"; multi = "resource"; + ramdisk = "ramdisk";

三、 开机脚本

参考仓库 https://gitlab2.kylin.com/shanghai-team/ramdisk/-/tree/ramdisk-trial

开机运行如下

function start_install() { parse_cmdline prepare_iso if [ "${TRIAL}" == "true" ];then overlay_start return 0 fi while true do clear info "感谢使用麒麟系统,请选择安装模式" info "1) 试用" info "2) 安装" info "3) 调试" info "4) 重启" info "请输入:" read -s -n1 -t 30 -r option case ${option} in 1) overlay_start return 0 ;; 2) _start_install ;; 3) debug_shell ;; 4) echo b > /proc/sysrq-trigger info "你的系统不支持重启" ;; *) [ -z ${option} ] && _start_install ;; esac done }

四、适配流程

  • 获取RK3588产品版本镜像
  • 通过任意方式制作U盘启动盘
  • 将待更新机器uboot通过rkdevtool烧录为uboot_usb.img,以支持USB启动
  • 将U盘插入设备上开机--→等待机器亮屏显示绿色字符“感谢使用麒麟系统,请选择安装模式”
  • 选择1即可试用,选择2即可安装,选择3即可调试,选择4即可重启

五、研发流程

  • 获取设备uboot代码
  • 将设备树内置在dtb目录下
  • 修改CONFIG_EMBED_KERNEL_DTB_PATH变量为指定的dtb
  • 将uboot编译为uboot-usb.img,以待usb启动版uboot使用
  • 将原生loader.bin编译成idblock.img和rkxxx.bin
  • 内核内打包ramdisk.img
  • 克隆ramdisk.git仓库编译出ramdisk.img/initrd.lz/initrd.img/uInitrd
  • 将内核编译为boot.img/uImage
  • 将开机图片置于启动盘根目录logo_kernel.bmp/logo.bmp
  • 为项目编写parameter-kylin.txt
  • 打包ISO

六、 结语

至此,已经可以获得基于RK3588上使用U盘安装系统的全套方案。客户如果需要设备支持U盘安装,则只需要设备的uboot代码和kernel代码即可正常配置。下面链接版本是支持一款板卡的uboot安装ISO镜像。

https://builder.kylin.com/kybuilder/build/view/49340

编辑
2025-03-03
记录知识
0

随着git项目越来越多,每次环境部署的时候,不可能一个一个去clone仓库,这样太费事了。为了偷懒,我借鉴了android的repo机制,这样可以自行对自己的git仓库搭建一个简单的repo,之后使用这个repo就能方便的管理多个git仓库了。

一:环境搭建

1.1 克隆repo

git clone https://gerrit.googlesource.com/git-repo

如果上网不方便,可以克隆本地仓库。

git clone http://10.3.4.182/arm-embedded/git-repo.git -b kylin-server-130-31

由于repo会把repo url默认到 https://gerrit.googlesource.com/git-repo。这里修改成130.31的本地git地址。也可修改成gitlab地址。

如:REPO_URL = 'http://10.3.4.182/arm-embedded/git-repo.git'

[root@localhost git-repo]# git diff diff --git a/repo b/repo index 3a51cce..c084b65 100755 --- a/repo +++ b/repo @@ -142,8 +142,6 @@ if __name__ == '__main__': REPO_URL = os.environ.get('REPO_URL', None) if not REPO_URL: REPO_URL = 'https://gerrit.googlesource.com/git-repo' +# kylin local repo url + REPO_URL = 'root@172.25.130.31:/root/work2/git/git-repo.git' REPO_REV = os.environ.get('REPO_REV') if not REPO_REV: REPO_REV = 'stable'

如果不做上述修改,则需要在repo init的时候,加入 --repo-url http://10.3.4.182/arm-embedded/git-repo.git

将git仓库里的repo更新到/usr/bin下。如下:

[ ! -f /usr/bin/repo ] && ln -s `pwd`/git-repo/repo /usr/bin/repo

输入 repo version 如果正常返回,则repo不存在问题

1.2 创建测试的git仓库

cd /root/work2/git git init --bare test1.git git init --bare test2.git git init --bare test3.git git clone /root/work2/git/test1.git git clone /root/work2/git/test2.git git clone /root/work2/git/test3.git cd test1 && echo "hello world" > Readme && git add . && git commit -m "first commit" && git push && cd - cd test2 && echo "hello world" > Readme && git add . && git commit -m "first commit" && git push && cd - cd test3 && echo "hello world" > Readme && git add . && git commit -m "first commit" && git push && cd -

如果本身就有仓库,就无需创建,直接用即可。这里仅做测试验证

因为测试使用的服务器,为了ssh免密处理,这里需要把公钥拷过去

ssh-copy-id root@172.25.130.31

repo并不是在所有环境都能正常运行,它需要满足python到3.7及以上。

所以如果repo运行异常,则需要更新系统python到3.7及以上

1.3 repo设置

git init --bare manifests.git git clone /root/work2/git/manifests.git vim manifests.git <?xml version="1.0" encoding="UTF-8"?> <manifest> <remote fetch="ssh://root@172.25.130.31/root/work2/git" name="origin"/> <default remote="origin" revision="master" sync-j="4"/> <project name="test1" path="test1"/> <project name="test2" path="test2"/> <project name="test3" path="test3"/> </manifest> git add . && git commit -m "first commit" && git push

这里通过编写xml,设置远端的git仓库为root@172.25.130.31/root/work2/git, 远端的分支名字为origin,默认的remote为origin,版本分支为master,一共三个工程,分别为test1 test2 test3,并在本地创建同样的目录名字。

这样即可编写一个最简单的manifests.xml。后续可以使用这个xml来管理整个git仓库

二: repo使用

2.1 拉取repo仓库

repo init -u root@172.25.130.31:/root/work2/git/manifests.git repo sync

此时可以看到三个仓库被正常的拉取。

[root@localhost 3]# ls test1 test2 test3

2.2 设置快照

在repo不断更新的过程中,可以生成快照,实际上就是生成一个xml文件,它保持了当时的repo状态,可供其他人使用。

这个类似于git tag。当需要整体出一个版本的时候,可以直接生成快照。

例如:

repo manifest -r -o tag_v1.0.xml <?xml version="1.0" encoding="UTF-8"?> <manifest> <remote fetch="ssh://root@172.25.130.31/root/work2/git" name="origin"/> <default remote="origin" revision="master" sync-j="4"/> <project dest-branch="master" name="test1" revision="831a146ccf46fe060c74f15354e9d68c3e0afbcb" upstream="master"/> <project dest-branch="master" name="test2" revision="829b53cce4538d5ae5919bc42bea7254bc1dcd9b" upstream="master"/> <project dest-branch="master" name="test3" revision="750f8d272da0b85a7bb7c42427fe9f0c72d416be" upstream="master"/> </manifest>

这里就比较显而易见了,快照保持了每个分支的分支信息,commit信息和上游信息

2.3 基本使用

查看分支状态

repo status

为某个分支创建新的branch

repo start bug_1.2 test1

上面这个命令等同于

git checkout -b bug_1.4

查看分支信息

repo branch

查看所有分支的diff

repo diff

其他就不列举了。因为repo实际就是git命令的封装,有时间可能在仓库里面直接运行git会更加方便。

三:manifests仓库的xml解释

3.1 标准头

默认的xml头

<?xml version="1.0" encoding="UTF-8"?>

顶层manifest元素

<manifest> </manifest>

3.2 remote 元素

<remote />
name 这里的name是git remote的那个远程名字,默认是origin。如果是git的remote是其他的,这里填写对应即可 fetch 这里是git的地址,如果是ssh可以是:ssh://root@172.25.130.31/root/work2/git 如果是http或者git,就是github/gitlab上的地址 pushurl 这里是push的地址,当指定该属性的时候,这个值会和<project>标签中的name属性拼成完整的push url路径,这样当我们使用git push命令的时候,就会使用该url。如果不指定该属性,则pushurl和fetch一样。 revision 这里是默认的git branch名字。可以是master或者其他

3.3 default 元素

<default />
remote 这里是remote设置的名字,代表repo拉的分支默认使用哪个remote上的 revision 当一个<project>不指定revision的时候使用该值 dest-branch 默认创建的本地分支,如果不指定,就是revision默认创建的分支 sync-j repo sync的并行数目 sync-c 如果设置为true,则只同步指定的分支(revision 属性指定),而不是所有的ref内容 sync-s 如果设置为true,则会同步git的子项目 sync-tags

3.4 project 元素

<project />
name: 这里是工程名也就是哪个仓库 ${remote_fetch}/${project_name}.git path: 显式声明的存放文件路径 remote: 这里指定的远程分支名字 revision: 这里指定需要获取的git提交点,可以是master, refs/heads/master, tag或者SHA-1值。如果不设置的话,默认下载当前project,当前分支上的最新代码。 upstream: 在哪个git分支可以找到一个SHA1。用于同步revision锁定的manifest(-c 模式)。该模式可以避免同步整个ref空间。

3.5 include 元素

xml可以直接include子xml。通过如下方式

<manifest> <include name="default.xml" /> </manifest>

3.6 linkfile和copyfile属性

<project name="test1" path="test1"> <linkfile dest="Readme" src="Readme"/> <copyfile dest="Readme.md1" src="Readme.md"/> </project>

在project下面设置可以设置软连接和拷贝。实际上等效于如下

ln -s test1/Readme Readme cp test1/Readme.md Readme.md1

四:参考链接:

https://gerrit-googlesource.proxy.ustclug.org/git-repo

https://gerrit.googlesource.com/git-repo/+/master/docs/manifest-format.md

编辑
2025-03-03
记录知识
0

在调试linux时,经常需要翻阅串口的信息,而串口通常需要串口线引出来,而整机一般情况下串口是封闭的。为了调试更好的看的串口信息,可以借助netconsole功能。

一:uboot使用

1.1 配置添加

CONFIG_NETCONSOLE=y

1.2 添加默认cmd

这里默认对serverip进行ping操作,如果serverip在线,则自动开始netconsole,否则正常流程boot

setenv serverip 172.25.80.123 setenv ipaddr 172.25.80.124 setenv if_netconsole 'ping $serverip' setenv start_netconsole 'setenv ncip $serverip; setenv stdin nc; setenv stdout nc; setenv stderr nc;' run if_netconsole start_netconsole

1.3 服务器命令

netconsole命令来自uboot源码tools/netconsole。

./netconsole 172.25.80.124 6666

1.4 作用

在某些情况下,如果linux内核破坏,uboot正常。系统无法开机,并且uboot的下载按键无法使用时。可以通过默认的服务器ip地址来对uboot进行命令行调试。例如download命令进入下载模式。

但是在一般情况下,只要保证uboot的下载按键正常时,此方法并无大用。仅留作备选方案之一考虑

二:Linux使用

2.1 配置添加

CONFIG_NETCONSOLE=m CONFIG_NETCONSOLE_DYNAMIC=y

编译的netconsole.ko,在需要使用的时候,有两种方式来使用

2.2 加载ko时带参数

insmod netconsole.ko netconsole=6666@172.25.80.125/eth0,6666@172.25.80.123/00:0c:29:d7:44:0b

这里netconsole参数需要带如下几个信息

netconsole=[+][src-port]@[src-ip]/[<dev>],[tgt-port]@<tgt-ip>/[tgt-macaddr] where + if present, enable extended console support src-port source for UDP packets (defaults to 6665) src-ip source IP to use (interface address) dev network interface (eth0) tgt-port port for logging agent (6666) tgt-ip IP address for logging agent tgt-macaddr ethernet MAC address for logging agent (broadcast)

通俗点也就是

端口地址@本机IP地址/网卡名称,端口地址@服务器IP地址/MAC地址 这里 本地IP为172.25.80.125,网卡名称为eth0,默认使用端口6666,远程IP为172.25.80.123,网卡mac地址为00:0c:29:d7:44:0b,默认使用端口为6666

2.3 动态加载netconsole

cd /sys/kernel/config/netconsole/ mkdir target echo 6666 > local_port echo 172.25.80.125 > local_ip echo eth0 > dev_name echo 6666 > remote_port echo 172.25.80.123 > remote_ip echo 00:0c:29:d7:44:0b > remote_mac echo 1 > enabled

卸载

echo 0 > enabled rmdir target rmmod netconsole

2.4 打开日志等级

默认内核的cmdline没有指定loglevel的情况下,可以通过dmesg手动调试日志

dmesg -n 8

这样在netconsole就能看的内核日志信息了

2.5 如何获取服务器mac地址

在设备上,如果不想登录服务器地址,可以通过arp查看mac

ping -c 1 172.25.80.123 ; /sbin/arp -n | grep 172.25.80.123

2.6 作用

nc -lup 6666

内核打开netconsole的作用比较明显,内核本身的/var/log/kern.log带缓冲,信息不及时。串口接出来不方便。但是需要实时的查看内核日志的时候,可以使用这个办法

三: 参考链接

https://github.com/u-boot/u-boot/blob/master/doc/usage/netconsole.rst https://www.kernel.org/doc/html/latest/networking/netconsole.html

编辑
2025-03-03
记录知识
0

在新的内核中,可以发现在RK平台上出现了打包成fit格式的内核镜像。在盛博的项目中,我们内核提供了标准的安卓打包方式,但是客户SDK通过fit打包,导致我们支持overlayfs的ramdisk.img无法正常打包。其主要原因是fit打包的内核没有把ramdisk打包进来。再者,内核boot更换了打包方式,居然无需修改uboot启动方式即可正常启动,于是抱着一定的兴趣追了一下代码,再参考了一下官方文档,了解了fit镜像的制作,引导过程。这里分享出来

一、 fit image说明

在说fit image之前,有必要简单带过一下传统的uboot image引导。通常我们知道uboot 的引导过程是需要知道三个条件的

kernel addr fdt addr ramdisk addr(非必须)

然后再根据booti/bootm启动内核。

所以一般调试linux系统的第一步,就是想方设法将内核,设备树,initrd加载到内存地址上,然后通过bootm A B C 的方式直接加载内存地址,或者通过booti 加载uimage的方式。

这些动作通常要么是uboot内指定写死,要么是手动uboot写好,然后通过saveenv的命令保存来确保下次正常启动。

但是发现了没有,这种方式它不灵活,如果我更换内核,设备树,initrd的话,只能通过同名的文件替换来实现。加载步骤是不能变化的。

如果有一个新的启动方式,它能在嵌入式设备中灵活的选择任意的内核,设备树,initrd是不是更好。

结合上面的需求,uboot开发了新的image格式方式加载(uImage.FIT is the new format used for uImage payloads developed by U-boot.)。

二、 uboot使能fit

CONFIG_FIT=y CONFIG_CMD_BOOT_FIT=y

上面打开uboot支持fit启动,下一个打开boot_fit命令,实际上如果boot_fit命令不打开也可以手动bootm启动。

对应在bootcmd中,需要添加boot_fit命令,可以安排启动顺序如下:

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

这样机器默认先找安卓打包方式的内核,再找fit方式的内核。也就解释了为什么内核更换打包方式无需做修改就能直接启动了

三:its文件

its文件即描述多个镜像启动的配置文件,其语法本质就是设备树fdt,所以直接按照设备树语法编写即可

RK平台默认的its文件如下

/* * Copyright (C) 2021 Rockchip Electronics Co., Ltd * * SPDX-License-Identifier: GPL-2.0 */ /dts-v1/; / { description = "FIT image with Linux kernel, FDT blob and resource"; images { fdt { data = /incbin/("fdt"); type = "flat_dt"; arch = ""; compression = "none"; load = <0xffffff00>; hash { algo = "sha256"; }; }; kernel { data = /incbin/("kernel"); type = "kernel"; arch = ""; os = "linux"; compression = ""; entry = <0xffffff01>; load = <0xffffff01>; hash { algo = "sha256"; }; }; resource { data = /incbin/("resource"); type = "multi"; arch = ""; compression = "none"; hash { algo = "sha256"; }; }; ramdisk { description = "Compressed Initramfs"; data = /incbin/("ramdisk"); type = "ramdisk"; arch = "arm64"; os = "linux"; compression = "none"; load = <0x00000000>; entry = <0x00000000>; hash { algo = "sha256"; }; }; }; configurations { default = "conf"; conf { rollback-index = <0x00>; fdt = "fdt"; kernel = "kernel"; multi = "resource"; ramdisk = "ramdisk"; signature { algo = "sha256,rsa2048"; padding = "pss"; key-name-hint = "dev"; sign-images = "fdt", "kernel", "multi"; }; }; }; };

可以留意到的是,这个文件就两个node,一个是images,一个是configurations

其实通过英文就能大概猜到了。images描述了镜像(多个),configurations描述了配置(多个),那么就意味着可以针对多个镜像来搭配出多个配置,每种配置均可通过uboot的boot_fit启动。

3.1、 默认支持ramdisk

下面支持ramdisk打包的its修改方法。这里load和entry填写0是因为uboot会根据实际地址ramdisk_addr_r来复写。所以没有关系

kernel# git diff HEAD boot.its diff --git a/boot.its b/boot.its index 755005c..885bfd1 100644 --- a/boot.its +++ b/boot.its @@ -45,6 +45,21 @@ algo = "sha256"; }; }; + + ramdisk { + description = "Compressed Initramfs"; + data = /incbin/("ramdisk"); + type = "ramdisk"; + arch = "arm64"; + os = "linux"; + compression = "none"; + load = <0x00000000>; + entry = <0x00000000>; + + hash { + algo = "sha256"; + }; + }; }; configurations { @@ -55,6 +70,7 @@ fdt = "fdt"; kernel = "kernel"; multi = "resource"; + ramdisk = "ramdisk"; signature { algo = "sha256,rsa2048";

3.2 编译its

mkimage -E -p 0x800 -f out/boot.its boot.img

通过如上命令即可将its打包到boot镜像内,这样在uboot的boot_fit命令就可以直接找到boot.img内的boot.itb文件

3.3 查看加载信息

./mkimage -l boot.img FIT description: FIT image with Linux kernel, FDT blob and resource Created: Thu Nov 2 18:41:56 2023 Image 0 (fdt) Description: unavailable Created: Thu Nov 2 18:41:56 2023 Type: Flat Device Tree Compression: uncompressed Data Size: 151491 Bytes = 147.94 KiB = 0.14 MiB Architecture: AArch64 Load Address: 0xffffff00 Hash algo: sha256 Hash value: cedd1011209678d3b1acbe79ecb93c869f716df3e43049722c5c83b4382bab41 Image 1 (kernel) Description: unavailable Created: Thu Nov 2 18:41:56 2023 Type: Kernel Image Compression: lz4 compressed Data Size: 18758725 Bytes = 18319.07 KiB = 17.89 MiB Architecture: AArch64 OS: Linux Load Address: 0xffffff01 Entry Point: 0xffffff01 Hash algo: sha256 Hash value: e363a997ae83daeb70c130c30b32c1b00655a515d2a5b96ea251884c00655d9c Image 2 (resource) Description: unavailable Created: Thu Nov 2 18:41:56 2023 Type: Multi-File Image Compression: uncompressed Data Size: 793600 Bytes = 775.00 KiB = 0.76 MiB Hash algo: sha256 Hash value: bfb3aaf4cf63f736406e5e3cf54a0924056cf1e16d35eceb1f7ce041777f12b6 Image 3 (ramdisk) Description: Compressed Initramfs Created: Thu Nov 2 18:41:56 2023 Type: RAMDisk Image Compression: uncompressed Data Size: 5188818 Bytes = 5067.21 KiB = 4.95 MiB Architecture: AArch64 OS: Linux Load Address: 0x00000000 Entry Point: 0x00000000 Hash algo: sha256 Hash value: 4cfac4cf0b7fdee76a2b3ef847cedaacdd1ab28b290faff9164fbbef051b6d57 Default Configuration: 'conf' Configuration 0 (conf) Description: unavailable Kernel: kernel Init Ramdisk: ramdisk FDT: fdt

这里可以看到,boot.img内正常包含所以需要its启动的文件和itb文件

3.4 直接引导

如果its想要验证,可在uboot中直接引导,如下方式, 前置条件是需要提前将boot.its描述的文件加载到内存。否则找不到文件的

tftp 0X10000000 boot.its bootm 0X10000000

四、 启动过程

这里展示fit格式的镜像启动日志,如下

=> boot_fit ## Booting FIT Image at 0xea3eff40 with size 0x01209600 ## Loading kernel from FIT Image at ea3eff40 ... Using 'conf' configuration optee api revision: 2.0 TEEC: Waring: Could not find security partition ## Verified-boot: 0 Trying 'kernel' kernel subimage Description: unavailable Type: Kernel Image Compression: lz4 compressed Data Start: 0xea415740 Data Size: 18758725 Bytes = 17.9 MiB Architecture: AArch64 OS: Linux Load Address: 0x00400000 Entry Point: 0x00400000 Hash algo: sha256 Hash value: e363a997ae83daeb70c130c30b32c1b00655a515d2a5b96ea251884c00655d9c Verifying Hash Integrity ... sha256+ OK ## Loading fdt from FIT Image at ea3eff40 ... Using 'conf' configuration Trying 'fdt' fdt subimage Description: unavailable Type: Flat Device Tree Compression: uncompressed Data Start: 0xea3f0740 Data Size: 151448 Bytes = 147.9 KiB Architecture: AArch64 Load Address: 0x08300000 Hash algo: sha256 Hash value: c49109c3ca4ebe1d68c2da345e1737e92adc5ff0bfc05ab2c20a2184a927b600 Verifying Hash Integrity ... sha256+ OK Loading fdt from 0x08300000 to 0x08300000 Booting using the fdt blob at 0x08300000 Uncompressing LZ4 Kernel Image from 0xea415740 to 0x00400000 ... with 029cea00 bytes OK kernel loaded at 0x00400000, end = 0x02dcea00 Using Device Tree in place at 0000000008300000, end 0000000008327f97 WARNING: could not set reg FDT_ERR_BADOFFSET. ## reserved-memory: drm-logo@00000000: addr=edf00000 size=136000 ramoops@110000: addr=110000 size=f0000 Adding bank: 0x00200000 - 0x08400000 (size: 0x08200000) Adding bank: 0x09400000 - 0xf0000000 (size: 0xe6c00000) Adding bank: 0x1f0000000 - 0x200000000 (size: 0x10000000) Total: 382304.976/382374.272 ms Starting kernel ...

这里默认加载了名字为conf的配置,也就加载了conf配置中指定的文件,至此fit image正常启动。

五、引用

为何启动fit image如此轻松,主要原因是fit image已经合入主线,linux和uboot都默认支持fit。下面是参考文档

  1. embendded linux wiki :https://elinux.org/images/f/f4/Elc2013_Fernandes.pdf

  2. uboot doc:https://github.com/u-boot/u-boot/blob/97962260cb93e74e3a8cbbb62e7581830503810a/doc/usage/fit/howto.rst