Qemu模拟ARM之制作根文件系统
系统:Ubuntu16.04.4 32bit
交叉编译器:arm-linux-gnueabihf-gcc
VMware:VMware Workstation 14 Pro
u-boot:u-boot-2018.03
linux:linux-4.16.2
1.下载busybox
cd ~/qemu
wget http://busybox.net/downloads/busybox-1.28.3.tar.bz2
2.配置busybox
tar xvf busybox-1.28.3.tar.bz2
cd busybox-1.28.3
make menuconfig
遇到上面错误,由于缺少相应的库导致的
#libncursesw5-dev
sudo apt-get install libncurses5-dev
在这里选择编译编译静态库不依赖与任何动态链接库
Settings —>
交叉编译工具链的选择
Settings —>
安装目录的选择
Settings —>
支持vi风格的命令行
Settings—>
3.编译安装
make -j4
make install
4.构建根文件系统
mkdir ~/qemu/rootfs
cd ~/qemu/rootfs
创建根文件系统的目录
mkdir bin etc dev home lib mnt opt proc root sbin sys tmp usr var
拷贝busybox安装目录下的文件到rootfs中
sudo cp -a ~/qemu/busybox-1.28.3/_install/* ./
拷贝交叉编译器动态库到rootfs/lib目录下
cp -a /opt/gcc-linaro-7.2.1-2017.11-i686_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/lib/* ./lib/
对库文件进行瘦身(去除符号表和调试信息):
arm-linux-gnueabihf-strip ./lib/*
将busybox源码里的etc拷贝到rootfs目录下的etc下
cp -a ~/qemu/busybox-1.28.3/examples/bootfloppy/etc/* ./etc
在dev目录下创建设备节点
sudo mknod -m 666 ./dev/console c 5 1
sudo mknod -m 666 ./dev/null c 5 1
拷贝宿主机/etc/passwd,/etc/group,/etc/shadow到rootfs的etc下
sudo cp /etc/passwd ./etc
sudo cp /etc/group ./etc
sudo cp /etc/shadow ./etc
把passwd文件中的第一行:root:x:0:0:root:/root:/bin/bash中的/bin/bash,改成/bin/sh.因为文件系统的bin目录下没有bash这个命令,而是用sh代替bash,所以在用用户名密码登录时候(如telnet),会出现“cannot run /bin/bash:No such file or directory”的错误。
如果修改目录/root为/,那么root用户登陆的时候不会进入root目录下而是进入根目录。
init进程解析的配置文件,通过这个配置文件决定执行哪个进程
修改etc/inittab文件:
内容如下:
console::sysinit:/etc/init.d/rcS
#::respawn:-/bin/sh #之前由于启动了两个sh,所以执行命令是会出错(两个sh抢着执行)
ttyAMA0::askfirst:-/bin/sh #"-"表示该shell为 login shell
::once:/usr/sbin/telnetd -l /bin/login
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
::restart:/sbin/init
项 | 描述 |
---|---|
<id> |
进程要使用的控制台,不设置则使用和init一样的控制台 |
<runlevels> |
对于Busybox提供init程序,此字段可省略 |
<action> |
表示init进程如何控制该子进程 |
<process> |
要执行的程序或脚本 |
活动名称 | 含义 |
---|---|
Sysinit | 为init程序提供初始化命令脚本的路径 |
Wait | 告诉init程序必须等待相应程序执行完后才能继续执行 |
Once | 程序只执行一次,且不会等待它执行完成 |
Respawn | 当程序终止执行时,重新启动该程序 |
Askfirst | 和respawn类似,不过init程序先输出”Please press Enter to active this console”,等待用户按回车键后,才启动子进程 |
Shutdown | 系统关机时执行相应的程序 |
Restart | 当init程序重启时,执行相应程序,通常是init程序本身 |
Ctrlatldel | 按下Ctrl + Alt + Delete组合键时,执行相应程序 |
fstab中是存放系统中文件系统的信息,这些信息是用来控制mount命令的行为
要挂载的设备 | 挂载点 | 文件系统的类型 | 挂载参数 | dump(备份程序) | fsckorder(检查磁盘程序) |
---|---|---|---|---|---|
proc | /proc | proc | defaults | 0 | 0 |
修改etc/fstab文件,内容如下:
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /dev tmpfs defaults 0 0
var /dev tmpfs defaults 0 0
修改etc/init.d/rcS文件(系统最先执行的,也可称为初始化脚本)
内容如下:
#!/bin/sh
PATH=/bin:/sbin:/usr/bin:/usr/sbin
runlevel=S
prevlevel=N
umask 022
export PATH runlevel prevlevel
mount -a
mkdir /dev/pts #dev/pts用来支持外部网络连接(telnet)的虚拟终端
mount -t devpts devpts /dev/pts
echo /sbin/mdev > /proc/sys/kernel/hotplug #设置内核,当有设备插拔时调用/sbin/mdev程序
mdev -s #在/dev目录下生成内核支持所有设备的结点
mkdir -p /var/lock
/bin/hostname -F/etc/sysconfig/HOSTNAME
#设置ip
ifconfig lo 127.0.0.1
ifconfig eth0 192.168.1.222
其中HOSTNAME即命令提示符前面所显示的名字[root@hostname]中的hostname。而在init.d/rcS脚本中/bin/hostname -F /etc/sysconfig/HOSTNAME
指定到/etc/sysconfig/HOSTNAME
中找这个名称。
所以在/etc下新建sysconfig文件夹,在里面新建HOSTNAME文件,内容为:qemu
umask
- umask是022的时候,默认touch创建一个文件的权限是644
- umask是044的时候,默认touch创建一个文件的权限是622
- umask是444的时候,默认touch创建一个文件的权限是222
Linux系统有7个运行级别(runlevel)
- 运行级别0:系统停机状态,系统默认运行级别不能设为0,否则不能正常启动
- 运行级别1:单用户工作状态,root权限,用于系统维护,禁止远程登陆
- 运行级别2:多用户状态(没有NFS)
- 运行级别3:完全的多用户状态(有NFS),登陆后进入控制台命令行模式
- 运行级别4:系统未使用,保留
- 运行级别5:X11控制台,登陆后进入图形GUI模式
- 运行级别6:系统正常关闭并重启,默认运行级别不能设为6,否则不能正常启动
运行级别的原理:
- 在目录/etc/rc.d/init.d下有许多服务器脚本程序,一般称为服务(service)
- 在/etc/rc.d下有7个名为rcN.d的目录,对应系统的7个运行级别
- rcN.d目录下都是一些符号链接文件,这些链接文件都指向init.d目录下的service脚本文件,命名规则为K+nn+服务名或S+nn+服务名,其中nn为两位数字。
系统会根据指定的运行级别进入对应的rcN.d目录,并按照文件名顺序检索目录下的链接文件
- 对于以K开头的文件,系统将终止对应的服务
- 对于以S开头的文件,系统将启动对应的服务
查看运行级别用:runlevel
- 进入其它运行级别用:(sudo) init N
- 另外init0为关机,init 6为重启系统
另外,当使用runlevel查看运行级别时,结果会显示前一次的运行级别和现在的运行级别,如果前次的运行级别为N,那么说明前次没有运行级别(可能刚刚power on)
修改etc/profile文件(也是个脚本文件,不过是我们按下回车后才执行的)
内容如下:
#sh profile
#vim: syntax=sh
#NO core files by default
#ulimit -S -c 0 > /dev/null 2>&1
USER="'id-un'" #/*双引号,单引号-单引号,双引号*/
LOGNAME=$USER
PS1='[\u@\h \W]#'
PATH=$PATH
HOSTNAME='/bin/hostname'
echo "Processing /etc/profile..." #这两句可以改成你自己的信息
echo "*******************************************************"
echo "* *"
echo "* made by xxxxxxxxxxxx *"
echo "* 2018.4.28 *"
echo "* *"
echo "*******************************************************"
export USER LOGNAME PS1 PATH
5.制作ext3文件系统
#生成镜像 count自定文件系统大小这里设置256M
cd ~/qemu
dd if=/dev/zero of=rootfs.ext3 bs=1M count=512
#格式化生成ext3文件系统
mkfs.ext3 rootfs.ext3
#将文件复制到镜像中
sudo mkdir tmpfs
sudo mount -t ext3 rootfs.ext3 tmpfs/ -o loop
sudo cp -r rootfs/* tmpfs/
sudo umount tmpfs
6.测试文件系统
cd ~/qemu/tftpboot
qemu-system-arm -M vexpress-a9 -nographic -kernel u-boot -net nic,macaddr=52:54:00:11:22:33 -net tap,ifname=tap0,script=no,downscript=no -sd ~/qemu/rootfs.ext3
tftp 0x60003000 uImage
tftp 0x66000000 vexpress-v2p-ca9.dtb
setenv bootargs 'root=/dev/mmcblk0 rw console=ttyAMA0'
bootm 0x60003000 - 0x66000000
7.增加登陆界面
在linux启动后首先设置root的登陆密码
#设置密码为root
passwd root
修改/etc/inittab
#删除
ttyAMA0::askfirst:-/bin/sh
#增加
ttyAMA0::respawn:/sbin/getty -L ttyAMA0 115200 vt100
重启后就会出现登陆界面