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

因为有一些uboot机器的环境变量不一致,导致标准的distro安装不能通用,所以需要在uboot的shell界面设置一下变量,从而使得机器支持uboot正常安装和启动。这里分享如何自定义uboot启动来支持uboot安装镜像

一:查看bootcmd变量

进入uboot环境中,需要确定bootcmd变量是否为sysboot加载的extlinux文件,如果是,则无需修改,如果不是,则需要自行配置。

如:

distro_bootcmd=run load_kernel; run load_initrd; run load_fdt; run boot_os boot_os=bootm $kernel_addr -:- $ft_fdt_addr

上述启动方式为直接引导内核地址,initrd地址和fdt地址,然后调用bootm的方式直接启动。故此方式不是标准的distro系统启动方式,需要修改

如:

bootcmd=run distro_bootcmd; distro_bootcmd=for target in ${boot_targets}; do run bootcmd_${target}; done .....;. boot_extlinux=sysboot ${devtype} ${devnum}:${distro_bootpart} any ${scriptaddr} ${prefix}extlinux/extlinux.conf

则此方式为distro系统的uboot启动方式,uboot无需额外修改

二:为非distro启动方式新增distro启动

对于直接启动的方式,我们需要将其设置为标准distro方式启动。故需要如下设置, 20231027新增支持mmc安装,mmc启动优先级在scsi,nvme之前。

setenv uboot_env "setenv kernel_addr_r 0x90100000;setenv ramdisk_addr_r 0x95000000;setenv fdt_addr_r 0x90000000;" setenv find_and_boot 'if $devtype dev 0; then if fstype $devtype 0:1 bootfstype;then for prefix in / /boot/; do sysboot $devtype 0:1 any 0x90000000 $prefix/extlinux/extlinux.conf; done; fi; fi' setenv usb_boot "usb start; run uboot_env; setenv devtype usb; run find_and_boot" setenv scsi_boot "setenv devtype scsi; run find_and_boot" setenv nvme_boot "setenv devtype nvme; run find_and_boot" setenv mmc_boot "setenv devtype mmc; run find_and_boot" setenv bootcmd_kylin "setenv board e2000q-test-b-ddr4; run uboot_env; run usb_boot; run mmc_boot; run scsi_boot; run nvme_boot" setenv bootcmd "run bootcmd_kylin" saveenv

2.1 解析自定义的distro方式启动

uboot_env变量: 设置内核加载地址为0x90100000,ramdisk加载地址为0x95000000,设备树加载地址为0x90000000,此三个地址和直接启动方式地址一致 find_and_boot变量: 对每个类型(usb scsi nvme)的设备的第一个设备进行判断,如果其第一个分区是bootfstype(ext4、vfat)则遍历/和/boot目录,寻找其extlinux/extlinux.conf目录,如果存在,则通过sysboot加载extlinux.conf来加载uImage和uInitrd usb_boot变量:U盘启动盘的启动方式,uboot阶段打开usb,设置启动方式为usb后启动 mmc_boot变量:设置启动方式为mmc后启动 scsi_boot变量:设置启动方式为scsi后启动 nvme_boot变量:设置启动方式为nvme后启动 bootcmd_kylin变量:设置板卡为e2000q-test-b-ddr4(这里以32s的板卡为例),配置uboot环境,配置usb启动,配置scsi启动,配置nvme启动 bootcmd变量:修改当前的启动方式为bootcmd_kylin saveenv:保存当前配置信息,以便后续启动生效

三:启动方案介绍

通过如上信息可以知道,uboot本身可以直接通过地址引导,也就是如下

ext4load usb 0:1 $kernel_addr boot/uImage-5.4.18-63.52-e2000-rc15-generic; ext4load usb 0:1 $ft_fdt_addr boot/dtb/e2000q-test-b-ddr4.dtb; bootm $kernel_addr -:- $ft_fdt_addr

它通过ext4load的方式直接将内核,设备树加载到对应地址来启动。这也是通常uboot的启动方式。但它不适合常用的发行版系统的安装。

而通过extlinux方式启动能够为常用发行版安装提供良好的方式。

这里配置文件内容如下

default install menu title Installer prompt 0 timeout 10 label install menu label kylinos installer linux /boot/uImage initrd /boot/uInitrd fdtdir /boot/dtb append root=LABEL=kylinos earlycon=pl011,0x2800d000 console=ttyAMA1,115200 rw boot=vkylin uboottype cma=96M security=none audit=1

上述配置步骤概述如下:

  • 开机默认开启usb控制器
  • 对usb的第一个分区进行查询,判断是否存在/extlinux/extlinux.conf或/boot/extlinux/extlinux.conf目录
  • 通过sysboot加载extlinux.conf文件
  • extlinux.conf文件描述了uImage和uInitrd的位置,这里位置默认在/boot/uImage,/boot/uInitrd,/boot/dtb目录下
  • sysboot会直接启动uImage和uInitrd来运行安装界面
  • 安装完成之后,拔掉u盘,下次启动会遍历usb,scsi,nvme来加载系统,这时因为安装过程会把系统安装到scsi或nvme上,则系统会正常启动

3.1 加载启动成功日志

starting USB... Bus usb3@31a00000: Register 2000110 NbrPorts 2 Starting the controller USB XHCI 1.10 Bus usb3@31a20000: Register 2000110 NbrPorts 2 Starting the controller USB XHCI 1.10 scanning bus usb3@31a00000 for devices... 2 USB Device(s) found scanning bus usb3@31a20000 for devices... 4 USB Device(s) found scanning usb for storage devices... 1 Storage Device(s) found Device 0: Vendor: Kingston Rev: PMAP Prod: DataTraveler 3.0 Type: Removable Hard Disk Capacity: 14784.0 MB = 14.4 GB (30277632 x 512) ... is now current device Scanning usb 0:1... Found /boot/extlinux/extlinux.conf Retrieving file: /boot/extlinux/extlinux.conf 1: kylinos installer Retrieving file: /boot/uInitrd Retrieving file: /boot/uImage append: root=LABEL=kylinos earlycon=pl011,0x2800d000 console=tty0,115200 rw boot=vkylin uboottype cma=96M security=none audit=1 Retrieving file: /boot/dtb/e2000q-test-b-ddr4.dtb ## Booting kernel from Legacy Image at 90100000 ... Image Name: Linux-5.4.18-63.52-e2000-rc17-ge Image Type: AArch64 Linux Kernel Image (uncompressed) Data Size: 25207296 Bytes = 24 MiB Load Address: 80080000 Entry Point: 80080000 Verifying Checksum ... OK ## Loading init Ramdisk from Legacy Image at 95000000 ... Image Name: uInitrd Image Type: ARM Linux RAMDisk Image (gzip compressed) Data Size: 103216845 Bytes = 98.4 MiB Load Address: 00000000 Entry Point: 00000000 Verifying Checksum ... OK ## Flattened Device Tree blob at 90000000 Booting using the fdt blob at 0x90000000 Loading Kernel Image Loading Ramdisk to f39ca000, end f9c396cd ... OK Loading Device Tree to 00000000f39c1000, end 00000000f39c975a ... OK run in ft_board_setup fdt_addr 00000000f39c1000 N: Phytium System Service Call: 0xc2000005 mb_count = 0x2 mb_blocks[0].mb_size = 0x7c000000 mb_blocks[1].mb_size = 0x80000000 fdt : can not find /memory@01 node fdt : add node memory@01 fdt : dram size 0x100000000 update successfully Starting kernel ...

通过上述可以判断其正常加载了uImage,uInitrd,dtb。

四、注意事项

4.1 设备树匹配

uboot启动需要设备树完全匹配,这里设备树分安装时需要的设备树和启动时需要的设备树。

安装时的设备树需要放在iso的boot/dtb目录下存在和板子要求设备树一致的

板子设备树可以通过如下查询:

print board

这里会提供设备树名字,如e2000q-test-b-ddr4,此时需要在u盘的boot/dtb/e2000q-test-b-ddr4.dtb文件保证存在,否则U盘无法启动

启动时的设备树需要放在系统的/boot/dtb/下,如果系统安装在nvme下,则需要在nvme的下的boot分区内有/dtb/e2000q-test-b-ddr4.dtb。否则安装了也无法启动

记住,这里board对应的设备树需要和机器硬件功能完全一致

4.2 启动缺陷

4.2.1 仅能安装在第一个设备上

如上述配置可以发现,这里遍历无论是usb,scsi还是nvme,都是选择第一个设备来启动,如果系统存在多个usb,scsi,nvme设备,则需要安装系统到第一个设备上,否则启动不了。

对于此缺陷,可以尝试修复,主要方式为遍历所有的存储设备,而不是指定设备号为0

4.2.2 仅能启动第一个分区

如上述配置可以发现,只能启动0:1分区的内容,也就是boot分区必须要在第一个分区。如果系统存在多个分区,启动分区不在第一个,则系统启动不了

对于此缺陷,可以尝试修复,主要方式为通过part list devtype{devtype} {devnum} -bootable devplist 来遍历所有的分区,然后对每个分区来进行for循环查找extlinux文件

4.2.3 mmc系统优于scsi系统并优于nvme

如上述配置可以发现,usb>mmc>scsi>nvme,usb优先主要用于安装,mmc>scsi>nvme是默认配置的,如果mmc,scsi和nvme上都有系统,则默认启动mmc的系统

对于此缺陷,可以尝试修复,调整bootcmd_kylin的启动顺序即可

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

在debian package编译包的过程中,有时候需要使用dch来直接提供一个模板编写changlog文件,默认的dch命令填充的是ubuntu和UNRELEASED字段,这些字段对于我们经常需要额外修改。这里为了更方便一点,默认了一下字段,从而使得dch修改changlog更加方便。

一、原始dch样式

在源码目录输入dch,自动填充如下

libdrm (2.4.101-2kylin1rk3ubuntu1) UNRELEASED; urgency=medium * -- root <root@Kylin> Wed, 22 Nov 2023 10:46:31 +0800

这里可以看到,版本号默认添加的是ubuntu1,代号模式是UNRELEASED,提交者是root,提交者邮箱是主机的hosts。这四个地方需要每次额外的修改。

二、期望dch样式

libdrm (2.4.101-2kylin1rk4) v101; urgency=medium * -- tangfeng <tangfeng@kylinos.cn> Wed, 22 Nov 2023 10:50:11 +0800

期望得到的是如有版本后缀则自动填充,如无版本后缀则自动追加kylin1,或可自定义,代号默认为v101。并且提交者和邮箱地址是本人真实地址。

三、修改devscripts的版本

这里修改了devscript来实现上述期望的dch样式,包如下链接

https://dev.kylinos.cn/~rk3588/+archive/kylin-desktop/common/+packages

版本如下

devscripts (2.20.2kylin3rk1) v101; urgency=medium * Make dch easy to use -- tangfeng <tangfeng@kylinos.cn> Tue, 21 Nov 2023 14:14:36 +0800

四、配合的修改

为了达到期望的changlog样式,这里需要自行设置两个环境变量

export EMAIL=tangfeng@kylinos.cn >> ~/.bashrc export DEBFULLNAME=tangfeng >> ~/.bashrc source ~/.bashrc

如自己的环境则按照自己的条件配置,配置EMAIL和DEBFULLNAME后,dch默认填充的changlog会按照此变量修改

五、使用方法

dch有如下四个通常命令,分别介绍如下

dch dch -m dch -U dch -l

5.1 命令:dch

直接输入dch会默认填充changlog,如果不加参数,这里默认直接填充kylin1字段,如下

devscripts (2.20.2kylin1) v101; urgency=medium * -- tangfeng <tangfeng@kylinos.cn> Wed, 22 Nov 2023 11:02:39 +0800

这里会在2.20.2版本上追加kylin1版本后缀,比较适合第一次编译给版本加上kylin1后缀

5.2 命令:dch -m

-m会默认复用上次提交的maintainer的信息

devscripts (2.20.2kylin1) v101; urgency=medium * -- Xie Wei <xiewei@kylinos.cn> Wed, 22 Nov 2023 11:07:06 +0800

这里不修改上次提交者(maintainer)的修改细节。上次是xiewei提交的,这里不会再复写成tangfeng

5.3 命令:dch -U

-U会自动对版本后缀追加1

devscripts (2.20.2kylin3rk2) v101; urgency=medium * -- tangfeng <tangfeng@kylinos.cn> Wed, 22 Nov 2023 11:08:25 +0800 devscripts (2.20.2kylin3rk1) v101; urgency=medium

这里会自动把版本追加1,原来是rk1,现在是rk2

5.4 命令:dch -l

-l 后添加字串是新增版本后缀,如果如下

dch -l ft 这里后面追加后缀ft1,如下所示

devscripts (2.20.2kylin3rk1ft1) v101; urgency=medium * -- tangfeng <tangfeng@kylinos.cn> Wed, 22 Nov 2023 11:10:00 +0800

这里从原始版本2.20.2kylin3rk1上追加了ft1字段后缀。

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

有些项目需要做根文件系统只读,也需要保证系统本身是可写的。这里通过使用联合文件系统overlayfs来处理这种需求。

同样的,客户还需要做U盘更新,备份,还原等操作。为了方便处理,这些操作均通过ramdisk里的overlayfs脚本来实现。这里简单讲一下实现步骤

一:功能开启

1.1 内核功能

功能主要为两个地方,一个是支持ramdisk/initrd,一个是支持overlayfs

其次需要开启的为各类挂载系统的功能支持,如ext4,ntfs,exfat,squashfs,以及U盘的识别

如下所示:

CONFIG_BLK_DEV_INITRD CONFIG_OVERLAY_FS CONFIG_EXT4_FS CONFIG_NTFS_FS CONFIG_FAT_FS CONFIG_VFAT_FS CONFIG_SQUASHFS CONFIG_USB_STORAGE CONFIG_SCSI CONFIG_BLK_DEV_SD

1.2 开机参数

我们知道,系统开机由内核的cmdline来体现,为了使能overlayfs,可以显示的将overlayfs的配置体现在cmdline。如下

root=PARTLABEL=rootfs rootfstype=squashfs rw overlayroot=device:dev=PARTLABEL=userdata,fstype=ext4,mkfs=1

可以知道如下信息:

a.root分区默认挂载在PARTLABEL=rootfs,类型为squashfs b.overlayroot分区默认一个设备,为PARTLABEL=userdata,类型为ext4

1.3 ramdisk脚本

ramdisk脚本可以通过如下获取

https://gitlab2.kylin.com/shanghai-team/ramdisk/-/blob/ramdisk-reduce/ramdisk/scripts/init-bottom/kylinoverlay

脚本在init-bottom下运行,需要在ORDER下追加

/scripts/init-bottom/kylinoverlay "$@"

这样在系统加载ramdisk/initrd时,kylinoverlay运行会通过mount命令,将原始的root挂载修改为overlay挂载

如直接克隆ramdisk参考,上述步骤无需关心

二:启动效果

2.1 挂载情况

root@kylin:~# lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT mmcblk0 179:0 0 29.1G 0 disk ├─mmcblk0p3 179:3 0 10.5G 0 part /media/root-ro └─mmcblk0p6 179:6 0 13G 0 part /media/root-rw

其中 /media/root-ro 和 /media/root-rw 是对应的root和userdata分区

root@kylin:~# blkid /dev/mmcblk0p3: TYPE="squashfs" PARTLABEL="rootfs" PARTUUID="614e0000-0000-4b53-8000-1d28000054a9" /dev/mmcblk0p6: PARTLABEL="userdata" UUID="62af73c5-bd8c-4cc0-af0a-10abc9574f21" TYPE="ext4" PARTLABEL="userdata" PARTUUID="2d1d0000-0000-4e74-8000-770200003b4e" overlay的挂载情况 root@kylin:~# mount /dev/mmcblk0p3 on /media/root-ro type squashfs (ro,relatime) /dev/mmcblk0p6 on /media/root-rw type ext4 (rw,relatime) overlayroot on / type overlay (rw,relatime,lowerdir=/media/root-rw/commit:/media/root-ro,upperdir=/media/root-rw/rootfs_overlay,workdir=/media/root-rw/rootfs_overlay-workdir/_)

这里把commit和root-ro作为lower,root-ro是最底层,rootfs_overlay作为upper,rootfs_overlay-workdir作为work

这里需要说明的是:

overlayfs是将多个分区/目录进行联合挂载,对挂载点进行分层,作为lower层的只读,upper层的可写,从而合并成overlayroot目录作为根文件系统,在根文件系统上的读写实际上是通过读写upper层的内容。

三:追加功能

3.1 自动清理

rm -rf "${root_rw}/${dir_prefix}/*"

开机自动清理即直接删除upper层的所有文件内容

3.2 提交改动

cp -rpf ${root_rw}/${dir_prefix}/* ${root_rw}/commit/ rm -rf ${root_rw}/${dir_prefix}/*

提交改动即将overlay_root目录的内容,原封不动拷贝到commit下。

值得注意的是,overlay会标记已删除的文件和目录为字符文件,需要针对其做如下处理

先遍历dir_prefix的字符文件,然后跑到commit下删掉 再遍历commit的字符文件,然后跑到dir_prefix下删掉

3.3 系统还原

func_restore(){ rm -rf ${root_rw}/* mkdir -p ${root_rw}/${dir_prefix} mkdir -p $workdir mkdir -p ${root_rw}/commit }

系统还原即删除所有root-rw目录的内容,并重新创建upper层,work层,和lower层的commit 目录

3.4 U盘更新

umount ${root_ro} umount ${root_rw} rootfs=`blkid -s PARTLABEL | grep PARTLABEL=\"rootfs\" | awk -F: '{print $1}'` userdata=`blkid -s PARTLABEL | grep PARTLABEL=\"userdata\" | awk -F: '{print $1}'` dd if=/update/filesystem.squashfs of=${rootfs} dd if=/update/ghost.squashfs of=${rootfs} dd if=/update/overlay.ext4 of=${userdata} mount ${rootfs} ${root_ro} mount ${userdata} ${root_rw}

U盘更新即找到U盘后,卸载root-rw和root-ro,将分区进行dd到系统上,然后再重新mount起来

因为直接使用的dd,所以dd时不能断电和拔出U盘,否则系统会变砖,后续可以考虑,系统变砖后,自动恢复rootfs的功能

3.5 备份系统

mksquashfs ${root_ro}/ /ghost/ghost.squashfs commit_size=`/usr/bin/du --block-size=1M -s ${root_rw}/commit/ | awk '{print $1}'` commit_size=$(($commit_size+100)) dd if=/dev/zero of=/ghost/overlay.ext4 bs=512 count=2048 mkfs.ext4 -F /ghost/overlay.ext4 resize2fs /ghost/overlay.ext4 ${commit_size}M inode=`expr ${commit_size} \* 1024 / 16` mkfs.ext4 -F -L userdata -N ${inode} /ghost/overlay.ext4 cp -rpf ${root_rw}/commit/ /tmp umount /tmp sync -f /ghost/overlay.ext4 e2fsck -f /ghost/overlay.ext4 resize2fs /ghost/overlay.ext4 -M

备份系统即打包root分区和打包overlay分区下的commit目录。生成ghost.squashfs和overlay.ext4

四:使用

4.1 脚本

使用通过overlaymanager.sh脚本,通过内置到操作系统下即可使用,具体操作情况如下

usage(){ info "Usage: " info " $0 -commit/-c #提交" info " $0 -ghost/-g #一键ghost" info " $0 -restore/-r #系统还原" info " $0 -update/-u #更新系统" info " $0 -y #打开自动清理" info " $0 -n #关闭自动清理" info " $0 -boot/-b #升级内核" }
编辑
2025-03-03
记录知识
0

GPT全称是GUID Partition Table,它是一个分区表,用于描述系统内分区信息情况。通常的,机器在上电启动后,首先加载自己芯片本身的romcode,或者BIOS代码,然后由这些代码直接读取存储器上的gpt或mbr分区信息。在有了分区信息之后,代码就能正常的跳转到存储器的分区地址进行真正的引导(因为romcode会实现对gpt的解析),跳到存储器上运行的第一个程序,也就是bootloader或者grub。然后再由bootloader引导Linux内核再到系统上。

一:GPT的分布

image.png

1.1 LBA0

查看原始数据

root@kylin:~# dd if=/dev/mmcblk1 count=1 2>/dev/zero | hexdump -C 00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 000001c0 00 00 ee 00 00 00 01 00 00 00 ff ff ff ff 00 00 |................| 000001d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 000001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa |..............U.|

GPT的第一个逻辑块叫做保护MBR,用于防止基于 MBR 的引导程序的错误识别。也就是说,一些引导程序还是通过首先检查MBR分区来识别分区类型。

MBR的主要分布如下:

image.png

可以看到下面数据属于第一个分区条目

00 00 00 00 ee 00 00 00 01 00 00 00 ff ff ff ff

关于分区条目如下描述

image.png

由上可以知道,第一个0xee实际上就是分区种类,在《https://en.wikipedia.org/wiki/Partition_type#PID_EEh》可以查到

image.png

也就是说,GPT会被MBR识别程序通过0x1c2地址上的值为0xee识别为GPT的保护MBR

同样,01 00 00 00 是分区中第一个绝对扇区的LBA。ff ff ff ff 是该分区的扇区数目,55 aa 是MBR的最后签名。

1.2 LBA1

查看原始数据

root@kylin:~# dd if=/dev/mmcblk1 count=1 skip=1 2>/dev/zero | hexdump -C 00000000 45 46 49 20 50 41 52 54 00 00 01 00 5c 00 00 00 |EFI PART....\...| 00000010 63 0f bd fd 00 00 00 00 01 00 00 00 00 00 00 00 |c...............| 00000020 ff ef d1 01 00 00 00 00 22 00 00 00 00 00 00 00 |........".......| 00000030 de ef d1 01 00 00 00 00 00 00 47 f9 00 00 53 41 |..........G...SA| 00000040 80 00 24 75 00 00 12 a2 02 00 00 00 00 00 00 00 |..$u............| 00000050 80 00 00 00 80 00 00 00 fa d0 f2 c2 00 00 00 00 |................| 00000060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|

image.png

需要留意:

备份分区地址: ff ef d1 01 00 00 00 00 也就是0x01d1efff,而最后一个可用LBA是 de ef d1 01 00 00 00 00 也就是 0x01d1efde。把这两者相减可得,最后留了34个扇区
root@kylin:~# echo $((0x01d1efff-0x01d1efde+1)) 34

dd可以查看备份LBA的GPT头如下

root@kylin:~# dd if=/dev/mmcblk1 skip=$((0x01d1efff)) count=1 2>/dev/null| hexdump -C 00000000 45 46 49 20 50 41 52 54 00 00 01 00 5c 00 00 00 |EFI PART....\...| 00000010 8d 9a 64 6b 00 00 00 00 ff ef d1 01 00 00 00 00 |..dk............| 00000020 01 00 00 00 00 00 00 00 22 00 00 00 00 00 00 00 |........".......| 00000030 de ef d1 01 00 00 00 00 00 00 47 f9 00 00 53 41 |..........G...SA| 00000040 80 00 24 75 00 00 12 a2 df ef d1 01 00 00 00 00 |..$u............| 00000050 80 00 00 00 80 00 00 00 fa d0 f2 c2 00 00 00 00 |................| 00000060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|

结合GPT分区的分布如下:

image.png

也就是说,最后从-1到-34个扇区,是备份的GPT分区。

磁盘UUID在0x38-0x48。也就是如下数据

00 00 47 f9 00 00 53 41 80 00 24 75 00 00 12 a2

在上层可以通过命令对应起来

root@kylin:~# gdisk /dev/mmcblk1 -l 2>/dev/zero| grep GUID | awk -F : '{print $2}' | sed "s/ //g" F9470000-0000-4153-8000-2475000012A2

1.3 LBA2-33

查看原始数据

root@kylin:~# dd if=/dev/mmcblk1 skip=2 count=32 2>/dev/null | hexdump -C 00000000 00 00 23 6e 00 00 42 49 80 00 37 43 00 00 53 af |..#n..BI..7C..S.| 00000010 00 00 7f 46 00 00 28 4f 80 00 35 3d 00 00 04 d9 |...F..(O..5=....| 00000020 00 80 00 00 00 00 00 00 ff 7f 02 00 00 00 00 00 |................| 00000030 00 00 00 00 00 00 00 00 62 00 6f 00 6f 00 74 00 |........b.o.o.t.| 00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00000080 00 00 1c e2 00 00 08 43 80 00 0e 64 00 00 41 73 |.......C...d..As| 00000090 00 00 4e 61 00 00 53 4b 80 00 1d 28 00 00 54 a9 |..Na..SK...(..T.| 000000a0 00 80 03 00 00 00 00 00 de ef d1 01 00 00 00 00 |................| 000000b0 00 00 00 00 00 00 00 00 72 00 6f 00 6f 00 74 00 |........r.o.o.t.| 000000c0 66 00 73 00 00 00 00 00 00 00 00 00 00 00 00 00 |f.s.............| 000000d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|

相信从右边的ascii可以大概猜得出来了,这就是真正的具体分区内容了。其中具体信息解析如下:

image.png

首先的16字节是分区的GUID,这个是用来标识分区类型的ID,是标准分配的。

第二个16字节是分区存在于系统中的GUID,可以与如下命令对应

root@kylin:~# ls -lh /dev/disk/by-partuuid/ | grep mmcblk1p1 | awk '{print $9}' 467f0000-0000-4f28-8000-353d000004d9

接下来16字节是 LBA的开始和结束地址

00 80 00 00 00 00 00 00 ff 7f 02 00 00 00 00 00

这里可以看到起始地址为0x00008000,结束地址为0x00027fff

root@kylin:~# gdisk -l /dev/mmcblk1 2>/dev/null | grep Number -A2 | tail -n 2 1 32768 163839 64.0 MiB FFFF boot 2 229376 30535646 14.5 GiB FFFF rootfs

这里boot分区的起始扇区和结束扇区是对应的。

root@kylin:~# echo $((0x8000)) $((0x00027fff)) 32768 163839

最后从0x38开始的72字节为分区的名字。这里可以直接通过ascii查看到。

image.png

二:Uboot中操作GPT

2.1 修改分区信息

env set partitions "name=boot,size=64M,start=16M;name=rootfs,start=112M,size=-,uuid=614e0000-0000-4b53-8000-1d28000054a9;" gpt write mmc 0 $partitions gpt verify mmc 0 $partitions

设置两个分区,boot分区从16M开始大小为64M,rootfs分区从112M开始,大小为分区的所有空间,uuid为614e0000-0000

修改后,uboot读取gpt分区信息如下。

=> part list mmc 0 Partition Map for MMC device 0 -- Partition Type: EFI Part Start LBA End LBA Name Attributes Type GUID Partition GUID 1 0x00008000 0x00027fff "boot" attrs: 0x0000000000000000 type: ebd0a0a2-b9e5-4433-87c0-68b6b72699c7 guid: da6ed6e6-16f0-415f-95bf-e0721f8721ea 2 0x00038000 0x01d1efde "rootfs" attrs: 0x0000000000000000 type: ebd0a0a2-b9e5-4433-87c0-68b6b72699c7 guid: 614e0000-0000-4b53-8000-1d28000054a9

上述操作对应的RK paramter分区表为如下:

CMDLINE:mtdparts=rk29xxnand:0x0020000@0x00008000(boot),-@0x00038000(rootfs:grow) uuid:rootfs=614e0000-0000-4b53-8000-1d28000054a9

三: Linux中操作GPT

3.1 修改分区名字

cat /proc/cmdline storagemedia=emmc androidboot.storagemedia=emmc androidboot.mode=normal androidboot.verifiedbootstate=orange androidboot.slot_suffix= androidboot.serialno=42036bf58040a13f rw rootwait earlycon=uart8250,mmio32,0xff1a0000 swiotlb=1 console=tty0 console=ttyFIQ0 root=PARTUUID=614e0000-0000 rootfstype=ext4 coherent_pool=1m

可以发现系统启动通过root=PARTUUID=614e0000-0000,所以修改分区名字不会导致系统无法正常启动

gdisk /dev/mmcblk1 Command (? for help): c Partition number (1-2): 2 Enter name: test_rootfs Command (? for help): p Disk /dev/mmcblk1: 30535680 sectors, 14.6 GiB Sector size (logical/physical): 512/512 bytes Disk identifier (GUID): E3550000-0000-443E-8000-27FC000002AA Partition table holds up to 128 entries Main partition table begins at sector 2 and ends at sector 33 First usable sector is 34, last usable sector is 30535646 Partitions will be aligned on 2048-sector boundaries Total free space is 98270 sectors (48.0 MiB) Number Start (sector) End (sector) Size Code Name 1 32768 163839 64.0 MiB FFFF boot 2 229376 30535646 14.5 GiB FFFF test_rootfs Command (? for help): w Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING PARTITIONS!! Do you want to proceed? (Y/N): y OK; writing new GUID partition table (GPT) to /dev/mmcblk1. Warning: The kernel is still using the old partition table. The new table will be used at the next reboot or after you run partprobe(8) or kpartx(8) The operation has completed successfully. partprobe /dev/mmcblk1

重启后,查看分区名字信息

root@kylin:/home/kylin# gdisk -l /dev/mmcblk1 GPT fdisk (gdisk) version 1.0.5 Partition table scan: MBR: protective BSD: not present APM: not present GPT: present Found valid GPT with protective MBR; using GPT. Disk /dev/mmcblk1: 30535680 sectors, 14.6 GiB Sector size (logical/physical): 512/512 bytes Disk identifier (GUID): E3550000-0000-443E-8000-27FC000002AA Partition table holds up to 128 entries Main partition table begins at sector 2 and ends at sector 33 First usable sector is 34, last usable sector is 30535646 Partitions will be aligned on 2048-sector boundaries Total free space is 98270 sectors (48.0 MiB) Number Start (sector) End (sector) Size Code Name 1 32768 163839 64.0 MiB FFFF boot 2 229376 30535646 14.5 GiB FFFF test_rootfs

除了可以修改名字之外,实际上还可以修改,分区大小,分区UUID等各种处理。但这些处理并不能保证系统在修改之后仍可以无故障的启动。这里不做演示了。

四:参考链接:

GPT的wiki:https://en.wikipedia.org/wiki/GUID_Partition_Table

Uboot中对gpt的描述:https://github.com/u-boot/u-boot/blob/master/doc/README.gpt

RK平台本身的GPT描述:http://opensource.rock-chips.com/wiki_Partitions

MBR格式介绍:https://wiki.osdev.org/MBR_(x86)

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

Perf是Linux内核自带的调试工具,在分析Linux系统的性能的时候,需要用到这个工具。下面从编译和基本使用的角度来了解perf

一:基本环境

1.1 安装包

apt install binutils elfutils libasm1 zlib1g

1.2 内核工程

git clone http://10.3.4.182/arm-embedded/stable-4.4.194-rk3399-linux.git (这里只要是你板子上匹配的内核即可)

1.3 火焰图

git clone https://github.com/brendangregg/FlameGraph.git

1.4 编译

cd tools/perf/ && ARCH=arm64 WERROR=0 NO_LIBPERL=1 NO_LIBPYTHON=1 make -f Makefile.perf perf

perf建议在arm上编译,交叉编译容易出问题

二:基本使用

2.1 用户使用perf的权限

echo -1 > /proc/sys/kernel/perf_event_paranoid

2.2 去掉内核指针打印保护

echo 0 > /proc/sys/kernel/kptr_restrict

2.3 查看版本

kylin@kylin:~$ ./perf -v perf version 4.4.194.g9ca7d7

2.4 实时分析

./perf top -d 2 -p 528

2.5 支持的事件

./perf list

2.5.1 关于事件类型的解释

Hardware [Cache] Events: These instrument low-level processor activity based on CPU performance counters. For example, CPU cycles, instructions retired, memory stall cycles, level 2 cache misses, etc. Some will be listed as Hardware Cache Events. Software Events: These are low level events based on kernel counters. For example, CPU migrations, minor faults, major faults, etc. Tracepoint Events: This are kernel-level events based on the ftrace framework. These tracepoints are placed in interesting and logical locations of the kernel, so that higher-level behavior can be easily traced. For example, system calls, TCP events, file system I/O, disk I/O, etc. These are grouped into libraries of tracepoints; eg, "sock:" for socket events, "sched:" for CPU scheduler events. Dynamic Tracing: Software can be dynamically instrumented, creating events in any location. For kernel software, this uses the kprobes framework. For user-level software, uprobes. Timed Profiling: Snapshots can be collected at an arbitrary frequency, using perf record -FHz. This is commonly used for CPU usage profiling, and works by creating custom timed interrupt events.

image.png

2.6 统计信息

./perf stat -p 528

2.7 收集perf数据

./perf record -g -p 528 -o perf.data

2.8 分析perf数据

./perf report -i perf.data

2.9 火焰图

./perf script -i perf.data | FlameGraph/stackcollapse-perf.pl | FlameGraph/flamegraph.pl > flame.html

image.png

2.10 简单分析

perf record -a -g -p 1 perf report -g --tui