kernel——开发环境搭建
1. 基于zImage
1.1 zImage
修改kernel的Makefile
384 CROSS_COMPILE := arm-linux-gnueabi-
385 ARCH := arm
编译内核,模块,dtb文件
make vexpress_defconfig; make -j10 zImage
make modules -j10; make dtbs
为什么是 vexpress_defconfig呢
因为
ls arch/arm/mach-vexpress/
完成后输出文件在 arch/arm/boot/
1.2 制作根文件系统
1.2.1 什么是文件系统?
用于管理文件,包括访问,删除,新建等的结构化系统,
而其本身是文件,被应用程序读取,以实现管理文件。
在启动 zImage 后,内核需要挂载文件系统,并执行文件系统上的 init 程序。
所以使用 busybox 提供 init 程序和其他常用程序,并将其打包成文件系统,
1.2.2 编译常用应用程序
先修改 ARCH 和 CROSS_COMPILE
164 CROSS_COMPILE := arm-linux-gnueabi-
165 ARCH := arm
busybox 和板子无关,所以直接 defconfig 并 make
make defconfig; make; make install
把输出文件拷贝到 rootfs 目录下,拷贝c库,创建常用驱动的设备节点,这样应用程序就可以使用tty驱动
cp -r _install/* rootfs
cp -p /usr/arm-linux-gnueabi/lib/* rootfs/lib
mkdir -p rootfs/dev
mknod -n 666 tty1 c 4 1
mknod -n 666 tty2 c 4 2
mknod -n 666 tty3 c 4 3
mknod -n 666 tty4 c 4 4
mknod -n 666 tty5 c 4 5
mknod -n 666 console c 5 1
mknod -n 666 null c 1 3
1.2.2 构建文件系统
root@ubuntu:~/wlt# dd if=/dev/zero of=rootfs.ext3 bs=1M count=32
32+0 records in
32+0 records out
33554432 bytes (34 MB, 32 MiB) copied, 0.0208796 s, 1.6 GB/s
root@ubuntu:~/wlt# mkfs.ext3 rootfs.ext3
mke2fs 1.42.13 (17-May-2015)
Discarding device blocks: done
Creating filesystem with 32768 1k blocks and 8192 inodes
Filesystem UUID: 68483364-3a40-47f8-bbaa-2f2345cac918
Superblock backups stored on blocks:
8193, 24577
Allocating group tables: done
Writing inode tables: done
Creating journal (4096 blocks): done
Writing superblocks and filesystem accounting information: done
# 将文件系统挂载到 /mnt 目录
root@ubuntu:~/wlt# mount -t ext3 rootfs.ext3 /mnt/ -o loop
# 将busybox的程序拷贝到文件系统
root@ubuntu:~/wlt# cp rootfs/* /mnt/ -r
# 卸载
root@ubuntu:~/wlt# umount /dev/loop0
启动
qemu-system-arm \
-M vexpress-a9 \
-m 512M \
-kernel /root/wlt/image/zImage \
-dtb /root/wlt/image/vexpress-v2p-ca9.dtb \
-nographic \
-append "root=/dev/mmcblk0 rw console=ttyAMA0" \
-sd /root/wlt/rootfs.ext3
2. 基于uImage
2.1 uboot
显然基于zImage的镜像有个缺点,即 一级引导程序负责初始化硬件,并启动内核,导致一级引导程序大,
所以通常用二级引导。如uboot完成 初始化硬件,启动内核。
2.1.1 编译uboot
为了方便测试,静态修改环境变量
vi include/configs/vexpress_common.h
187 #define CONFIG_IPADDR 192.168.5.128
188 #define CONFIG_NETMASK 255.255.255.0
189 #define CONFIG_SERVERIP 192.168.5.129
190
191 #define BOOT_NFS
192 #undef BOOT_NFS
193 #ifndef BOOT_NFS
194
195 #define CONFIG_BOOTCOMMAND \
196 "tftp 0x60003000 uImage; tftp 0x60500000 vexpress-v2p-ca9.dtb; \
197 setenv bootargs 'root=/dev/mmcblk0 console=ttyAMA0'; \
198 bootm 0x60003000 - 0x60500000;"
199
200 #else
201
202 #define CONFIG_BOOTCOMMAND \
203 "tftp 0x60003000 uImage; tftp 0x60500000 vexpress-v2p-ca9.dtb; \
204 setenv bootargs 'root=/dev/nfs rw \
205 nfsroot=192.168.5.129:/root/wlt/rootfs \
206 ip=192.168.5.127 \
207 init=/linuxrc console=ttyAMA0'; \
208 bootm 0x60003000 - 0x60500000;"
209
210 #endif
uboot是板级相关的,所以要选择板子信息
make vexpress_ca9x4_defconfig
make
2.1.2 qemu和主机通网
添加虚拟网卡
modprobe tun
apt install uml-utilities
添加一个tap
tunctl -b
ip link set tap0 up
桥接
apt install bridge-utils
brctl addbr br0
brctl addif br0 ens33
ifconfig br0 192.168.5.133 netmask 255.255.255.0
brctl addif br0 tap0
如果ens33有ip则需要删除
ip -o -f inet addr show
删除ip
ip -f inet addr delete 10.0.64.102/32 dev ens33
添加qemu参数
-net nic -net tap,ifname=tap0
2.2 构建uImage
make LOADADDR=0x60003000 uImage
2.3 启动
qemu-system-arm \
-M vexpress-a9 \
-kernel /root/wlt/image/u-boot \
-nographic \
-net nic,vlan=0 -net tap,vlan=0,ifname=tap0 \
-sd /root/wlt/rootfs.ext3 \
-m 512M
2.4 使用nfs
2.4.1 主机配置nfs server
root@ubuntu:~/wlt# cat /etc/exports
# /etc/exports: the access control list for filesystems which may be exported
# to NFS clients. See exports(5).
#
# Example for NFSv2 and NFSv3:
# /srv/homes hostname1(rw,sync,no_subtree_check) hostname2(ro,sync,no_subtree_check)
#
# Example for NFSv4:
# /srv/nfs4 gss/krb5i(rw,sync,fsid=0,crossmnt,no_subtree_check)
# /srv/nfs4/homes gss/krb5i(rw,sync,no_subtree_check)
#
/root/wlt/rootfs *(rw,sync,no_subtree_check,no_root_squash)
/home/test/rootfs *(rw,sync,no_subtree_check,no_root_squash)
2.4.2 启动nfs服务器
root@ubuntu:~/wlt# /etc/init.d/rpcbind restart
[ ok ] Restarting rpcbind (via systemctl): rpcbind.service^[[A.
root@ubuntu:~/wlt# /etc/init.d/nfs-kernel-server restart
[ ok ] Restarting nfs-kernel-server (via systemctl): nfs-kernel-server.service.
2.4.3 内核配置nfs客户端
│ │ File systems --->
│ │ [] Network File Systems --->
│ │ <> NFS client support │ │
│ │ <> NFS client support for NFS version 2 │ │
│ │ <> NFS client support for NFS version 3 │ │
│ │ [] NFS client support for the NFSv3 ACL protocol extension
│ │ [] Root file system on NFS
2.4.4 设置uboot的启动参数为 nfs启动
vi include/configs/vexpress_common.h
187 #define CONFIG_IPADDR 192.168.5.128
188 #define CONFIG_NETMASK 255.255.255.0
189 #define CONFIG_SERVERIP 192.168.5.129
190
191 #define BOOT_NFS
193 #ifndef BOOT_NFS
194
195 #define CONFIG_BOOTCOMMAND \
196 "tftp 0x60003000 uImage; tftp 0x60500000 vexpress-v2p-ca9.dtb; \
197 setenv bootargs 'root=/dev/mmcblk0 console=ttyAMA0'; \
198 bootm 0x60003000 - 0x60500000;"
199
200 #else
201
202 #define CONFIG_BOOTCOMMAND \
203 "tftp 0x60003000 uImage; tftp 0x60500000 vexpress-v2p-ca9.dtb; \
204 setenv bootargs 'root=/dev/nfs rw \
205 nfsroot=192.168.5.129:/root/wlt/rootfs \
206 ip=192.168.5.127 \
207 init=/linuxrc console=ttyAMA0'; \
208 bootm 0x60003000 - 0x60500000;"
209
210 #endif
启动
qemu-system-arm \
-M vexpress-a9 \
-kernel /root/wlt/image/u-boot \
-nographic \
-net nic,vlan=0 -net tap,vlan=0,ifname=tap0 \
-sd /root/wlt/rootfs.ext3 \
-m 512M
3. 完善rootfs
root@ubuntu:~/wlt/rootfs# cat etc/fstab
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0
var /dev tmpfs defaults 0 0
ramfs /dev tmpfs defaults 0 0
root@ubuntu:~/wlt/rootfs# cat etc/inittab
::sysinit:/etc/init.d/rcS
#::respawn:-/bin/sh
#tty2::askfirst:-/bin/sh
#::ctrlaltdel:/bin/umount -a -r
console::askfirst:-/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
root@ubuntu:~/wlt/rootfs# cat etc/init.d/rcS
#! /bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
LD_LIBRARY_PATH=/lib
export PATH LD_LIBRARY_PATH
mount -a
mkdir -p /dev/pts
mount -t devpts devpts /dev/pts
mdev -s
mkdir -p /var/lock
echo "-----------------------------"
echo " welcome"
echo "-----------------------------"
root@ubuntu:~/wlt/rootfs# cat etc/profile
PS1='yangxr@vexpress:\w # '
export PS1
4. 加载地址
以下面的地址为例
"tftp 0x60000000 uImage; tftp 0x60500000 vexpress-v2p-ca9.dtb; \
setenv bootargs 'root=/dev/nfs rw \
nfsroot=192.168.5.129:/root/wlt/rootfs \
ip=192.168.5.127 \
init=/linuxrc console=ttyAMA0 \
hello.num=10'; \
bootm 0x60000000 - 0x60500000;"
uImage的大小:4.8MB
编译uImage的参数
make uImage LOADADDR=0x60002000
结合kernel的输出
## Booting kernel from Legacy Image at 60000000 ...
Image Name: Linux-5.16.2
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 5060064 Bytes = 4.8 MiB
Load Address: 60002000
Entry Point: 60002000
Verifying Checksum ... OK
## Flattened Device Tree blob at 60500000
Booting using the fdt blob at 0x60500000
Loading Kernel Image ... OK
Loading Device Tree to 7fef1000, end 7fef7700 ... OK
分析如下
所以使用 uImage 的好处之一,不论 tftp uImage到任意物理内存,uboot都会将uImage 重定位到 LOADADDR指定的地址。
这些地址理论上是任意的物理内存地址都可以用,注意uImage和 dtb 不要互相覆盖。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?