Openharmony4.0的版本在内核上不支持rk8602的regulator驱动,这就导致两路cpu大核无法正常上电,npu无法正常上电,因为rk860x给cpu和npu提供了真实的regulator。
在rk3588s上,我们可以通过设备树知道cpub0和cpub1以及npu的供电情况如下:
&rknpu { rknpu-supply = <&vdd_npu_s0>; mem-supply = <&vdd_npu_mem_s0>; }; &cpu_b0 { cpu-supply = <&vdd_cpu_big0_s0>; mem-supply = <&vdd_cpu_big0_mem_s0>; }; &cpu_b2 { cpu-supply = <&vdd_cpu_big1_s0>; mem-supply = <&vdd_cpu_big1_mem_s0>; };
对于此,我们可以知道npu和cpu上都需要两路实际的电源供应,对于驱动,则需要如下获取regulator的引用节点
rknpu_supply = devm_regulator_get(&pdev->dev, "rknpu"); cpu_supply = devm_regulator_get(&pdev->dev, "cpu"); mem_supply = devm_regulator_get(&pdev->dev, "mem");
然后再通过上电时机将此路电源打开
ret = regulator_enable(rknpu_supply); ret = regulator_enable(cpu_supply); ret = regulator_enable(mem_supply);
基于此,我们可以知道,对于rk3588s而言,这类regulartor是核心的上电要求,所以我们不能忽略,如下可以找到regulator的设备树定义
vdd_cpu_big0_s0: vdd_cpu_big0_mem_s0: rk8602@42 { compatible = "rockchip,rk8602"; reg = <0x42>; vin-supply = <&vcc5v0_sys>; regulator-compatible = "rk860x-reg"; regulator-name = "vdd_cpu_big0_s0"; regulator-min-microvolt = <550000>; regulator-max-microvolt = <1050000>; regulator-ramp-delay = <2300>; rockchip,suspend-voltage-selector = <1>; regulator-boot-on; regulator-always-on; regulator-state-mem { regulator-off-in-suspend; }; }; vdd_cpu_big1_s0: vdd_cpu_big1_mem_s0: rk8603@43 { compatible = "rockchip,rk8603"; reg = <0x43>; vin-supply = <&vcc5v0_sys>; regulator-compatible = "rk860x-reg"; regulator-name = "vdd_cpu_big1_s0"; regulator-min-microvolt = <550000>; regulator-max-microvolt = <1050000>; regulator-ramp-delay = <2300>; rockchip,suspend-voltage-selector = <1>; regulator-boot-on; regulator-always-on; regulator-state-mem { regulator-off-in-suspend; }; }; vdd_npu_s0: vdd_npu_mem_s0: rk8602@42 { compatible = "rockchip,rk8602"; reg = <0x42>; vin-supply = <&vcc5v0_sys>; regulator-compatible = "rk860x-reg"; regulator-name = "vdd_npu_s0"; regulator-min-microvolt = <550000>; regulator-max-microvolt = <950000>; regulator-ramp-delay = <2300>; rockchip,suspend-voltage-selector = <1>; regulator-boot-on; regulator-always-on; regulator-state-mem { regulator-off-in-suspend; }; };
根据上述可以知道,我们必须要使能这个regulator电,并且此电的设备树节点是rk8602,rk8603.故需要移植驱动
针对此,可以找到驱动文件drivers/regulator/rk860x-regulator.c,其相关的compatible如下
static const struct of_device_id rk860x_dt_ids[] = { { .compatible = "rockchip,rk8600", .data = (void *)RK860X_CHIP_ID_00 }, { .compatible = "rockchip,rk8601", .data = (void *)RK860X_CHIP_ID_01 }, { .compatible = "rockchip,rk8602", .data = (void *)RK860X_CHIP_ID_02 }, { .compatible = "rockchip,rk8603", .data = (void *)RK860X_CHIP_ID_03 }, { } };
这里可以知道,一份驱动对应了多个compatible,可以实现多个节点的不同配置。这样我们可以确定移植此驱动即可。
对于vendor/drivers/regulator/Makefile 添加如下
obj-$(CONFIG_REGULATOR_RK860X) += rk860x-regulator.o
对于vendor/drivers/regulator/Kconfig 添加如下
config REGULATOR_RK860X tristate "Rockchip RK860X Regulator" depends on I2C select REGMAP_I2C help This driver supports Rockchip RK860X Digitally Programmable Buck Regulator. The RK860X is a step-down switching voltage regulator that delivers a digitally programmable output from an input voltage supply of 2.5V to 5.5V. The output voltage is programmed through an I2C interface.
对于arch/arm64/configs/rockchip_linux_defconfig添加如下
CONFIG_REGULATOR_RK860X=y
至此,两路cpu大核和npu的电即可正常输出
我们适配的板子,没办法使用hdc命令,这导致我们调试很不方便,这里提供了修改方法,打开了内核的设备树配置,从而上层能够使用hdc,本文用作记录方法。
我们知道usb需要支持org,那么我们需要将其功能正常打开,这里typec对于usb3,所以如下修改:
diff --git a/rk3588/kernel/arch/arm64/boot/dts/rockchip/rk3588-tianqi-linux.dts b/rk3588/kernel/arch/arm64/boot/dts/rockchip/rk3588-tianqi-linux.dts index cbfdae3..c1c4403 100755 --- a/rk3588/kernel/arch/arm64/boot/dts/rockchip/rk3588-tianqi-linux.dts +++ b/rk3588/kernel/arch/arm64/boot/dts/rockchip/rk3588-tianqi-linux.dts @@ -61,20 +61,22 @@ }; &usbdrd3_0 { - status = "disable"; + status = "okay"; }; &usbdrd_dwc3_0 { dr_mode = "otg"; - status = "disable"; + status = "okay"; + usb-role-switch; }; &usbhost3_0 { - status = "disabled"; + status = "okay"; }; &usbhost_dwc3_0 { - status = "disabled"; + status = "okay"; };
这里可以很清楚的知道需要打开typec对应的usb即可。这里usb-role-switch对照代码看一下就明白了,没什么好讲的。
根据板子的配置,我们可以跳到内核目录下,直接编译即可
cd out/kernel/src_tmp/linux-5.10 && ./make-ohos.sh TQ3588
这里直接烧录boot_linux分区即可,如果不想手动做上述操作,可以这个位置(10.3.3.110)拿一下内核
/home/develop/product/embedded/01-openharmony/01-version/2024-11-05-天启板子支持hdc/boot_linux.img
这样,hdc能够正常的list
C:\>hdc list targets 9b01005932503033320045da20422900
hdc能够正常进入
C:\>hdc shell # ls / bin data etc lost+found storage tmp chip_prod dev init mnt sys updater chipset eng_chipset lib module_update sys_prod vendor config eng_system lib64 proc system
我们在做openharmony版本的weekly build的时候,需要使用kyPacker来打包update镜像,本文介绍kypacker的使用
kypacker仓库地址如下:
https://gitlab2.kylin.com/sh-product-Embedded/openharmony/kypacker
获取仓库后,我们可以先运行一下make,这样能够获取平台相关的crc32库librkcrc32.so,如果不执行make,则使用python实现的crc32.
为了能够让kypacker正常工作,需要package-file文件,此文件需要描述文件名字和文件位置,举例如下
package-file package-file bootloader Image/rk3588_spl_loader_v1.11.112.bin parameter Image/parameter.txt uboot Image/uboot.img boot Image/boot.img rootfs Image/rootfs.img userdata Image/userdata.img
根据package-file,我们需要将文件放在Image目录下的位置,举例如下
-rwxrwx--- 1 root vboxsf 100M 12月 26 09:36 boot.img -rwxrwx--- 1 root vboxsf 369 12月 21 17:15 parameter.txt -rwxrwx--- 1 root vboxsf 457K 12月 26 09:24 rk3588_spl_loader_v1.11.112.bin -rwxrwx--- 1 root vboxsf 100M 12月 26 09:36 rootfs.img -rwxrwx--- 1 root vboxsf 4.0M 12月 22 14:38 uboot.img -rwxrwx--- 1 root vboxsf 100M 12月 26 09:36 userdata.img
在打包update之前,我们需要打包firmware固件,通过如下命令
kyPacker.py afptool pack ./tests ./tests/Image/firmware.img
至此,可以在./tests/Image/firmware.img查看firmware.img文件
如果firmware.img生成成功,则可以打包update.img,如下命令
kyPacker.py imgmker pack RK3588 ./tests/Image/bootloader.img ./tests/Image/firmware.img -os_type androidos
至此,可以在当前目录上发现update.img文件,打包update.img成功。
为了更加了解kypacker的工作方式,可以参考仓库的readme.md,如下
https://gitlab2.kylin.com/sh-product-Embedded/openharmony/kypacker
为了调试内核,我们经常会使用kprobe来调试程序,目前的kprobe挂在了ftrace框架下,所以我们有必要讲一下kprobe/kretprobe,它非常有助于我们调试内核。本文以一个例子来展示kprobe/kretprobe的使用,从而让大家具备调试内核的基本能力
kprobe是能够动态的进入内核收集函数基本信息的工具,它通过替换指令的方式替换指令的方式,将原本运行在某函数的栈跳到了kprobe的栈,故kprobe能够收集函数的入参,调用栈等基本信息
而kretprobe是改进的kprobe,顾名思义,它可以用于获取函数的返回值信息
所以,kprobe/kretprobe能够获取:
p[:[GRP/][EVENT]] [MOD:]SYM[+offs]|MEMADDR [FETCHARGS] : Set a probe r[MAXACTIVE][:[GRP/][EVENT]] [MOD:]SYM[+0] [FETCHARGS] : Set a return probe p[:[GRP/][EVENT]] [MOD:]SYM[+0]%return [FETCHARGS] : Set a return probe -:[GRP/][EVENT] : Clear a probe GRP : Group name. If omitted, use "kprobes" for it. EVENT : Event name. If omitted, the event name is generated based on SYM+offs or MEMADDR. MOD : Module name which has given SYM. SYM[+offs] : Symbol+offset where the probe is inserted. SYM%return : Return address of the symbol MEMADDR : Address where the probe is inserted. MAXACTIVE : Maximum number of instances of the specified function that can be probed simultaneously, or 0 for the default value as defined in Documentation/trace/kprobes.rst section 1.3.1. FETCHARGS : Arguments. Each probe can have up to 128 args. %REG : Fetch register REG @ADDR : Fetch memory at ADDR (ADDR should be in kernel) @SYM[+|-offs] : Fetch memory at SYM +|- offs (SYM should be a data symbol) $stackN : Fetch Nth entry of stack (N >= 0) $stack : Fetch stack address. $argN : Fetch the Nth function argument. (N >= 1) (\*1) $retval : Fetch return value.(\*2) $comm : Fetch current task comm. +|-[u]OFFS(FETCHARG) : Fetch memory at FETCHARG +|- OFFS address.(\*3)(\*4) \IMM : Store an immediate value to the argument. NAME=FETCHARG : Set NAME as the argument name of FETCHARG. FETCHARG:TYPE : Set TYPE as the type of FETCHARG. Currently, basic types (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal types (x8/x16/x32/x64), VFS layer common type(%pd/%pD), "char", "string", "ustring", "symbol", "symstr" and bitfield are supported. (\*1) only for the probe on function entry (offs == 0). Note, this argument access is best effort, because depending on the argument type, it may be passed on the stack. But this only support the arguments via registers. (\*2) only for return probe. Note that this is also best effort. Depending on the return value type, it might be passed via a pair of registers. But this only accesses one register. (\*3) this is useful for fetching a field of data structures. (\*4) "u" means user-space dereference. See :ref:`user_mem_access`.
上面的描述,大家可以看看,具体内容直接试试即可。
为了能够正常操作kprobe,我们关注如下几个文件:
/sys/kernel/debug/tracing/kprobe_events /sys/kernel/debug/tracing/events/kprobes /sys/kernel/debug/kprobes/list
这三个文件分别为:
这里直接以系统调用open为例,方便大家理解
我们知道一个open事件对应内核是do_sys_openat2,所以查看声明如下:
static long do_sys_openat2(int dfd, const char __user *filename, struct open_how *how)
基于此,我们直接打印arg2即可,这里是char *,我们可以通过string打印,如下
echo 'p:kylin do_sys_openat2 filename=+0($arg2):string' > /sys/kernel/debug/tracing/kprobe_events
然后打开trace信息如下:
echo 1 > events/kprobes/kylin/enable
此时日志如下:
systemd-journal-311 [003] d... 394.007790: kylin: (do_sys_openat2+0x0/0x2d0) filename="/run/log/journal/150c911f73834975b41af71e80344144/system.journal" systemd-journal-311 [003] d... 394.576585: kylin: (do_sys_openat2+0x0/0x2d0) filename="/run/log/journal/150c911f73834975b41af71e80344144/system.journal" systemd-journal-311 [003] d... 394.576798: kylin: (do_sys_openat2+0x0/0x2d0) filename="/run/log/journal/150c911f73834975b41af71e80344144/system.journal"
如果无需继续trace,关闭方法如下:
echo 0 > /sys/kernel/debug/tracing/events/kprobes/kylin/enable echo > /sys/kernel/debug/tracing/kprobe_events
我们知道系统所有的openat系统调用到内核都是调用的do_sys_openat2,而在do_sys_openat2中存在getname函数,其函数声明如下:
struct filename *getname(const char __user *);
此函数返回一个struct filename,而这个结构如下:
struct filename { const char *name; /* pointer to actual string */ const __user char *uptr; /* original userland pointer */ int refcnt; struct audit_names *aname; const char iname[]; };
所以我们可以编写kprobe_events如下:
echo 'r:kprobes/kylin getname arg1=+0($retval):string[1]' > kprobe_events
这里值得注意的是 string[1]的编写,可以参考如下:
The string array type is a bit different from other types. For other base types, <base-type>[1] is equal to <base-type> (e.g. +0(%di):x32[1] is same as +0(%di):x32.) But string[1] is not equal to string. The string type itself represents “char array”, but string array type represents “char * array”. So, for example, +0(%di):string[1] is equal to +0(+0(%di)):string. Bitfield is another special type, which takes 3 parameters, bit-width, bit- offset, and container-size (usually 32). The syntax is: b<bit-width>@<bit-offset>/<container-size>
所以我们直接拿到了char* name字段。此时我们打开kprobe即可,如下:
echo 1 > /sys/kernel/debug/tracing/events/kprobes/kylin/enable
然后我们直接读取ftrace的pipe即可
cat /sys/kernel/tracing/trace_pipe
我截取了一部分输出,以systemd的journal 服务,可以发现如下日志
systemd-journal-308 [001] d... 58935.290005: kylin: (do_sys_openat2+0x18c/0x2d0 <- getname) arg1={"/run/log/journal/150c911f73834975b41af71e80344144/system.journal"} systemd-journal-308 [001] d... 58935.290339: kylin: (do_sys_openat2+0x18c/0x2d0 <- getname) arg1={"/run/log/journal/150c911f73834975b41af71e80344144/system.journal"} systemd-journal-308 [001] d... 58935.290542: kylin: (do_sys_openat2+0x18c/0x2d0 <- getname) arg1={"/run/log/journal/150c911f73834975b41af71e80344144/system.journal"} systemd-journal-308 [001] d... 58935.290740: kylin: (do_sys_openat2+0x18c/0x2d0 <- getname) arg1={"/run/log/journal/150c911f73834975b41af71e80344144/system.journal"}
这里直接打印了openat的name字段是/run/log/journal/150c911f73834975b41af71e80344144/system.journal
至此,我从如何使用上解释了kprobe和kretprobe,相信大家具备基于kprobe的调试基本能力了,如果需要了解原文的,可以查看如下:
https://www.kernel.org/doc/html/latest/trace/kprobetrace.html https://www.kernel.org/doc/html/latest/trace/kprobes.html
如果大家还想深入的,可以查看如下文章:
An introduction to KProbes [LWN.net]
https://lwn.net/Articles/132196/
图示如下:

根据上次描述的kgdb在arm64的使用,我们可以直接在arm64的机器上运行kgdb了,但是考虑到大家并不是每个人都有arm64的机器,故,这里基于windows的wsl2来实现kgdb连接,方便大家调试。
关于kgdb功能打开,如下:
CONFIG_KGDB CONFIG_KGDB_SERIAL_CONSOLE
默认的gdb不支持1500000波特率,需要合并补丁如下补丁:
https://gitlab.com/gnutools/binutils-gdb/-/commit/78d16865df671f80da8d0a97b18596ef8a3feae3
主要步骤如下:
wget https://launchpad.net/ubuntu/+archive/primary/+sourcefiles/gdb/8.1-0ubuntu3/gdb_8.1-0ubuntu3.dsc https://launchpad.net/ubuntu/+archive/primary/+sourcefiles/gdb/8.1-0ubuntu3/gdb_8.1-0ubuntu3.debian.tar.xz https://launchpad.net/ubuntu/+archive/primary/+sourcefiles/gdb/8.1-0ubuntu3/gdb_8.1.orig.tar.xz dpkg-source -x *.dsc apt-get build-dep . patch -p1 < 0001-78d16865df671f80da8d0a97b18596ef8a3feae3.patch DEB_BUILD_OPTIONS=nocheck dpkg-buildpackage -uc -us
然后安装即可
dpkg -i ../*.deb
关于在wsl2中支持usb serial的方式,可以参考如下:
https://learn.microsoft.com/en-us/windows/wsl/connect-usb
主要步骤如下:
我们要保证wsl的版本是2,内核大于5.10.60.1,如下
wsl --status 默认分发:Ubuntu 默认版本:2 适用于 Linux 的 Windows 子系统最后更新于 2023/11/13 适用于 Linux 的 Windows 子系统内核可以使用“wsl --update”手动更新,但由于你的系统设置,无法进行自动更新。 若要接收自动内核更新,请启用 Windows 更新设置:“在更新 Windows 时接收其他 Microsoft 产品的更新”。 有关详细信息,请访问https://aka.ms/wsl2kernel。 内核版本: 5.10.102.1
直接到如下网址下载msi文件安装
https://github.com/dorssel/usbipd-win/releases
当前版本是usbipd-win_4.3.0.msi
此时我们需要administrator权限的powershell,运行如下:
PS C:\> usbipd list Connected: BUSID VID:PID DEVICE STATE 1-10 1ea7:0064 USB 输入设备 Not shared 1-11 0603:0351 USB 输入设备 Not shared 1-12 1840:13fd USB Attached SCSI (UAS) 大容量存储设备 Not shared 1-21 0bc2:ac31 USB Attached SCSI (UAS) 大容量存储设备 Not shared 1-23 1d5c:2000 FrescoLogic FL2000 USB Display Adapter Not shared 1-24 2207:0006 Android ADB Interface Not shared 3-2 0403:6001 USB Serial Converter Shared Persisted: GUID DEVICE
我们看到了我的串口是在3-2的设备上
如下命令直接绑定即可:
PS C:\> usbipd bind --busid 3-2 PS C:\> usbipd attach --wsl --busid 3-2 usbipd: info: Using WSL distribution 'Ubuntu' to attach; the device will be available in all WSL 2 distributions. usbipd: info: Using IP address 172.20.64.1 to reach the host.
此时我们在wsl可以看到日志如下:
[85304.990343] usb 1-1: new full-speed USB device number 3 using vhci_hcd [85305.180488] usb 1-1: SetAddress Request (3) to port 0 [85305.243206] usb 1-1: New USB device found, idVendor=0403, idProduct=6001, bcdDevice= 6.00 [85305.243249] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3 [85305.243293] usb 1-1: Product: FT232R USB UART [85305.259943] usb 1-1: Manufacturer: FTDI [85305.259961] usb 1-1: SerialNumber: A5XK3RJT [85305.300748] ftdi_sio 1-1:1.0: FTDI USB Serial Device converter detected [85305.300921] usb 1-1: Detected FT232RL [85305.302620] usb 1-1: FTDI USB Serial Device converter now attached to ttyUSB0
如下:
# ls /dev/ttyUSB0 /dev/ttyUSB0
然后直接minicom连接串口看是否正常即可:
minicom /dev/ttyUSB0 -s
正常就能操作串口了
Welcome to minicom 2.7.1 OPTIONS: I18n Compiled on Aug 13 2017, 15:25:34. Port /dev/ttyUSB0, 10:33:22 Press CTRL-A Z for help on special keys
如不用了记得主动断开。
usbipd detach --busid <busid>
这时候我们在机器内,命令如下:
echo ttyFIQ0 > /sys/module/kgdboc/parameters/kgdboc echo g > /proc/sysrq-trigger
这时候机器在Debug状态了,所以退出串口,拿gdb去连接它
在连接之前,我们需要一份内核vmlinux和源码,方便调试,而通常我们的代码在服务器,所以需要sshfs
sshfs root@172.25.130.130:/root/public-workspace/tf/01-3588-x11/squashfs-root/root/kernel/ ~/sshfs
为了gdb能够ss调试,我们需要合一下不规范的补丁
https://patchwork.kernel.org/project/linux-arm-kernel/patch/20170523043058.5463-3-takahiro.akashi@linaro.org/
然后直接使用gdb,如下:
root@9:~/sshfs/# gdb-multiarch vmlinux GNU gdb (Ubuntu 8.1-0ubuntu3) 8.1.0.20180409-git Copyright (C) 2018 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from vmlinux...done. (gdb) set serial baud 1500000 (gdb) set architecture aarch64 The target architecture is assumed to be aarch64 (gdb) target remote /dev/ttyUSB0 Remote debugging using /dev/ttyUSB0 arch_kgdb_breakpoint () at ./arch/arm64/include/asm/kgdb.h:21 21 asm ("brk %0" : : "I" (KGDB_COMPILED_DBG_BRK_IMM)); (gdb)
搞定