【米尔 NXP i.MX93 开发板评测】RAMDISK实践
# RAMDISK实践> 编译开发板自带的内核源码,制作一个`RAMDISK`,放到SD卡中加载测试内核;由于UBOOT功能有限,可以使用ramdisk添加更高级的维护功能,比如设备升级与工厂生产刷机。后面我们实现升级功能时会用到。
## 制作RAMDISK
使用`busybox`生成一个精简`initramdisk`
### 内核编译
参考米尔文档 《MYD-LMX9X_Linux软件开发指南.pdf》
```bash
# 配置交叉编译器
source /opt/fsl-imx-xwayland/6.1-mickledore/environment-setuparmv8a-poky-linux
cd MYD-LMX9X-Linux-L6.1.55-V1.0.0
./build-linux-zh.sh
# 选择编译线程数,等待一会儿编译成功后会生成output目录
cd output
output$ ll -h
总计 65M
drwxrwxr-x 2 bruce bruce 4.0K Aug 11 06:42 ./
drwxrwxr-x 4 bruce bruce 4.0K Aug 11 06:31 ../
-rw-rw-r-- 1 bruce bruce34M Aug 11 06:42 Image
-rw-rw-r-- 1 bruce bruce31M Aug 11 06:42 modules.tar.gz
-rw-rw-r-- 1 bruce bruce45K Aug 11 06:42 myir-imx93-11x11.dtb
-rw-rw-r-- 1 bruce bruce47K Aug 11 06:42 myir-imx93-11x11-lvds-10-1.dtb
-rw-rw-r-- 1 bruce bruce46K Aug 11 06:42 myir-imx93-11x11-lvds.dtb
-rw-rw-r-- 1 bruce bruce46K Aug 11 06:42 myir-imx93-11x11-RGB.dtb
-rw-rw-r-- 1 bruce bruce45K Aug 11 06:42 myir-imx93-11x11-root.dtb
```
重新配置内核,支持`RAM block device`
```bash
# 进入内核源代码目录
cd myir-imx-linux
# 配置
make menuconfig
# 将RAM block驱动编译进内核
Device Drivers--->
Block devices--->
<*> RAM block device support
(1) Default number of RAM disks
(65536) Default RAM disk size (kbytes)
make
# 生成我们需要的 arch/arm64/boot/Image
```
**注意:**这里不能使用`./build-linux-zh.sh`,脚本编译时会再次使用DEFCONFIG生成配置文件`.config`,会将我们设置好的配置清除掉。如果想用,可以重新拷贝一份deconfig,配置好`RAM DISK`,然后替代这里的 `DEFCONFIG="imx_v8_defconfig"`
```shell
DEFCONFIG="imx_v8_defconfig"
compile_linux(){
echo "开始配置内核"
cd ${LOACL_PATH}/${LINUX_NAME}
make ${DEFCONFIG} > /dev/null 2>&1
echo "开始编译内核"
LDFLAGS="" CC="$CC" make -j ${THREAD_NUM}> /dev/null 2>&1 &
make_pid=$!
bar_test ${make_pid}
echo "编译完成"
}
```
### update.sh
编写刷机脚本 `update.sh`,需要添加执行权限
```bash
#!/bin/sh
# eMMC device node
node=/dev/mmcblk0
# size in MB
BOOT_ROM_SIZE=8
ROOT_FS_SIZE=5120
PARAM_FS_SIZE=128
APP_FS_START=5416
mount -o remount,rw /
# wait for the SD/MMC device node ready
while [ ! -e ${node} ]
do
sleep 1
echo "wait for ${node} appear"
done
# TODO: check eMMC partitions
EMMC_PARTITIONS=("/dev/mmcblk0p1" "/dev/mmcblk0p2" "/dev/mmcblk0p3")
for PARTITION in "${EMMC_PARTITIONS[@]}"; do
if [ -e "$PARTITION" ]; then
echo "$PARTITION exist."
else
echo "$PARTITION not exist."
fi
done
# call sfdisk to create partition table
# destroy the partition table
dd if=/dev/zero of=${node} bs=1024 count=1
# p1 8M ~ 128M FAT(120MB)
# p2 128M~ 5248MROOTFS(5GB)
# p3 5248M ~ 5376 PARAM(128MB)
# p4 5376~ END APP(left)
echo ">>> sfdisk ${node}"
sfdisk --force ${node} << EOF
${BOOT_ROM_SIZE}M,120M,0c
,${ROOT_FS_SIZE}M,83
,${PARAM_FS_SIZE}M,83
${APP_FS_START}M,,83
EOF
if [ -b /dev/mmcblk1p1 ]
then
echo ">>> mount SD /dev/mmcblk1p1 -> /mnt"
mount /dev/mmcblk1p1 /mnt
elif [ -b /dev/sda1 ]
then
echo ">>> mount SD /dev/sda1 -> /mnt"
mount /dev/sda1 /mnt
else
echo "ERROR: The /dev/sda1 of the sd card was not found."
exit 1
fi
# burn uboot
if [ -f /mnt/flash/flash.bin ]
then
echo ">>> burn flash.bin -> /dev/mmcblk0boot0"
echo 0 > /sys/block/mmcblk0boot0/force_ro
dd if=/mnt/flash/flash.bin of=/dev/mmcblk0boot0 conv=fsync
echo 1 > /sys/block/mmcblk0boot0/force_ro
mmc bootpart enable 1 1 /dev/mmcblk0
fi
while [ ! -e /dev/mmcblk0p1 ]
do
sleep 1
echo "waiting... /dev/mmcblk0p1"
done
# burn dtb and Image
if [ -f /mnt/flash/Image ]
then
echo ">>> copy dtb and Image -> /dev/mmcblk0p1"
mkfs.vfat /dev/mmcblk0p1
mkdir -p /tmp/kernel
mount -t vfat /dev/mmcblk0p1 /tmp/kernel
cp /mnt/flash/Image /tmp/kernel
cp /mnt/flash/imx93-11x11-atk.dtb /tmp/kernel
cp /mnt/flash/ramdisk.img.gz /tmp/kernel
sync
umount /tmp/kernel
fi
# burn rootfs
if [ -f /mnt/flash/rootfs.tar ]
then
echo ">>> burn rootfs -> /dev/mmcblk0p2"
# mkfs.ext4 -F -E nodiscard /dev/mmcblk0p2
mkfs.ext4 -F /dev/mmcblk0p2
mkdir -p /tmp/rootfs
mount -t ext4 /dev/mmcblk0p2 /tmp/rootfs
tar -xf /mnt/flash/rootfs.tar -C /tmp/rootfs
sync
umount /tmp/rootfs
fi
# parameter: 128MB
mkfs.ext4 -F -E nodiscard /dev/mmcblk0p3
# APP: using left space
mkfs.ext4 -F -E nodiscard /dev/mmcblk0p4
sync
sleep 1
echo ">>>>>>>>>>> DONE <<<<<<<<<<<"
```
### 编译busybox
```bash
# 下载 busybox 源码
wget https://busybox.net/downloads/busybox-1.36.1.tar.bz2
# 解压
tar -xf busybox-1.36.1.tar.bz2
# 进入 busybox 目录
cd busybox-1.36.1
# 使用默认配置
make menuconfig
# 配置静态编译、交叉编译器前缀、安装路径;
Settings--->
[*] Build static binary (no shared libs)
(aarch64-none-linux-gnu-) Cross compiler prefix
(../ramdisk) Destination path for 'make install'
# 在配置了交叉编译器的前提下
make -j8
# 安装 busybox 文件
make install
# 进入安装目录,创建一些必须的配置文件
cd ../ramdisk/
mkdir -p mnt tmp var usr sys proc etc lib dev bin sbin root home
mkdir -p usr/lib lib/modules
# 创建设备节点,一个 console,一个 null
cd dev/
sudo mknod -m 666 console c 5 1
sudo mknod -m 666 null c 1 3
cd ../
# 复制 busybox 中的 examples/bootfloppy/etc 的文件
cp ../busybox-1.36.1/examples/bootfloppy/etc ./ -a
# 复制之前静态编译的 mke2fs 到 bin 目录,并重命名为 mkfs.ext4
cp ../e2fsprogs-1.47.0/misc/mke2fs ./bin/mkfs.ext4
# 复制之前静态编译的 resize2fs 到 bin 目录
cp ../e2fsprogs-1.47.0/resize/resize2fs ./bin/resize2fs
# 复制之前静态编译的 sfdisk.static 到 bin 目录,并重命名为 sfdisk
cp ../util-linux-2.40/sfdisk.static ./bin/sfdisk
# 复制之前静态编译的 mmc 到 bin 目录
cp ../mmc-utils/mmc ./bin/mmc
# 对 etc/fstab 文件添加一行,挂载 sysfs 文件系统,修改后如下
$ cat etc/fstab
proc /proc proc defaults 0 0
sysfs /sys sysfs defaults 0 0
```
/etc/init.d/rcS
```shell
#!/bin/sh
/bin/mount -a
/bin/hostname imx93
ifconfig eth0 up
sleep 1
udhcpc &
sleep 2
for initscript in /etc/init.d/S*
do
if [ -x $initscript ] ;
then
echo ": $initscript"
$initscript
fi
done
```
/etc/profile
```shell
PATH=/bin:/sbin:/usr/bin:/usr/sbin
PS1='/$ '
HOSTNAME='/bin/hostname'
export PATH HOSTNAME PS1
alias l.='ls -d .* --color=tty'
alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'
```
### 打包
将`update.sh`和其他需要的程序可以可以一起放到文件系统中
```bash
# 在 etc/init.d/rcS 中添加一行 update.sh 脚本的调用
$cat etc/init.d/rcS
#! /bin/sh
/bin/mount -a
/update.sh &
# 修改文件的用户与用户组为 root
sudo chown root:root -R ramdisk/*
# 如果genext2fs没安装,先安装
apt-get install genext2fs
# 制作一个8MB大小的ramdisk,需要小于在内核中配置的Default RAM disk size
genext2fs -b 8192 -d ramdisk ramdisk.img
# 压缩成ramdisk.img.gz
gzip ramdisk.img
```
### 加载测试
```bash
fatload mmc 1:1 0x80400000 Image
fatload mmc 1:1 0x83000000 myir-imx93-11x11.dtb
fatload mmc 1:1 0x84000000 ramdisk.img.gz
setenv bootargs 'console=ttyLP0,115200 earlycon initrd=0x84000000,0x800000 root=/dev/ram0 rw rootfstype=ext4 rootwait'
booti 0x80400000 - 0x83000000
```
只需要两秒多就加载成功了
### 网络配置
开发板启动通过DHCP获取IP
创建文件 `/etc/network/interfaces`
```shell
auto eth0
```
### udhcpc测试
编译busybox时已经添加了`udhcpc`
在ramdisk中添加 `/usr/share/udhcpc/default.script`
```shell
#!/bin/sh
# udhcpc script edited by Tim Riker <Tim@Rikers.org>
RESOLV_CONF="/etc/resolv.conf"
[ -n "$1" ] || { echo "Error: should be called from udhcpc"; exit 1; }
NETMASK=""
if command -v ip >/dev/null; then
[ -n "$subnet" ] && NETMASK="/$subnet"
else
[ -n "$subnet" ] && NETMASK="netmask $subnet"
fi
BROADCAST="broadcast +"
[ -n "$broadcast" ] && BROADCAST="broadcast $broadcast"
case "$1" in
deconfig)
echo "Clearing IP addresses on $interface, upping it"
if command -v ip >/dev/null; then
ip -4 addr flush dev $interface
ip link set dev $interface up
else
ifconfig $interface 0.0.0.0
fi
;;
renew|bound)
echo "Setting IP address $ip on $interface"
if command -v ip >/dev/null; then
ip addr add $ip$NETMASK $BROADCAST dev $interface
else
ifconfig $interface $ip $NETMASK $BROADCAST
fi
if [ -n "$router" ] ; then
echo "Deleting routers"
while route del default gw 0.0.0.0 dev $interface ; do
:
done
metric=0
for i in $router ; do
echo "Adding router $i"
if [ "$subnet" = "255.255.255.255" ]; then
# special case for /32 subnets:
# /32 instructs kernel to always use routing for all outgoing packets
# (they can never be sent to local subnet - there is no local subnet for /32).
# Used in datacenters, avoids the need for private ip-addresses between two hops.
ip route add $i dev $interface
fi
route add default gw $i dev $interface metric $((metric++))
done
fi
# If the file is a symlink somewhere (like /etc/resolv.conf
# pointing to /run/resolv.conf), make sure things work.
if test -L "$RESOLV_CONF"; then
# If it's a dangling symlink, try to create the target.
test -e "$RESOLV_CONF" || touch "$RESOLV_CONF"
fi
realconf=$(readlink -f "$RESOLV_CONF" 2>/dev/null || echo "$RESOLV_CONF")
echo "Recreating $realconf"
tmpfile="$realconf-$$"
> "$tmpfile"
[ -n "$domain" ] && echo "search $domain" >> "$tmpfile"
for i in $dns ; do
echo " Adding DNS server $i"
echo "nameserver $i" >> "$tmpfile"
done
mv "$tmpfile" "$realconf"
;;
esac
exit 0
```
**注意:** 这个脚本需要添加执行权限,否则获取不到IP地址
```bash
chmod +x default.script
```
运行测试,成功拿到IP地址
```bash
/usr/share/udhcpc # chmod +x default.script
/usr/share/udhcpc # ls
default.script
/usr/share/udhcpc # udhcpc -v
udhcpc: started, v1.36.1
udhcpc: executing /usr/share/udhcpc/default.script deconfig
Clearing IP addresses on eth0, upping it
udhcpc: entering listen mode: raw
udhcpc: broadcasting discover
udhcpc: waiting 3 seconds
udhcpc: received offer of 172.20.10.10
udhcpc: broadcasting select for 172.20.10.10, server 172.20.10.1
udhcpc: waiting 3 seconds
udhcpc: entering listen mode: none
udhcpc: lease of 172.20.10.10 obtained from 172.20.10.1, lease time 86400
udhcpc: executing /usr/share/udhcpc/default.script bound
Setting IP address 172.20.10.10 on eth0
Deleting routers
route: SIOCDELRT: No such process
Adding router 172.20.10.1
Recreating /etc/resolv.conf
Adding DNS server 172.20.10.1
```
页:
[1]