一、创建空磁盘
qemu-img create -f raw gf.os 100M
hexdump -C -n 512 gf.os #可以看到每个字节都是0,也就是空白磁盘
二、用空磁盘启动
qemu-system-x86_64 -hda gf.os -nographic
打印信息如下
SeaBIOS (version 1.13.0-2.el8)
iPXE (http://ipxe.org) 00:03.0 CA00 PCI2.10 PnP PMM+07F90A50+07ED0A50 CA00
Booting from Hard Disk...
Boot failed: not a bootable disk
Booting from Floppy...
Boot failed: could not read the boot disk
Booting from DVD/CD...
Boot failed: Could not read from CDROM (code 0003)
Booting from ROM...
iPXE (PCI 00:03.0) starting execution...ok
iPXE initialising devices...ok
iPXE 1.0.0+ -- Open Source Network Boot Firmware -- http://ipxe.org
Features: DNS HTTP iSCSI TFTP VLAN AoE ELF MBOOT PXE bzImage Menu PXEXT
net0: 52:54:00:12:34:56 using 82540em on 0000:00:03.0 (open)
[Link:up, TX:0 TXE:0 RX:0 RXE:0]
Configuring (net0 52:54:00:12:34:56).............. ok
net0: 10.0.2.15/255.255.255.0 gw 10.0.2.2
net0: fec0::5054:ff:fe12:3456/64 gw fe80::2
net0: fe80::5054:ff:fe12:3456/64
Nothing to boot: No such file or directory (http://ipxe.org/2d03e13b)
No more network devices
No bootable device.
另起一个终端,杀掉qemu
pkill -9 qemu-system
三、对磁盘做一下分区。
从前面的信息看,默认走的是bios启动
fdisk默认也是bios分区,如果要创建gpt分区,需要先敲m帮助看一下,g是设置为gpt分区格式,后面创建分区,都是同样的命令n,创建出来的结果也可以对比一下,有一点差别。
用n创建分区,创建一个主分区即可,w保存并退出。
hexdump -C -n 512 gf.os 可以查看fdisk到底写入了啥,就是在0扇区写了分区信息,以及0分区最后的魔数 55aa
四、再次启动qemu
qemu-system-x86_64 -hda gf.os -nographic
打印信息如下
SeaBIOS (version 1.13.0-2.el8)
iPXE (http://ipxe.org) 00:03.0 CA00 PCI2.10 PnP PMM+07F90A50+07ED0A50 CA00
Booting from Hard Disk...
五、格式化文件系统,安装grub
sudo losetup -f --show gf.os
# 输出为 /dev/loop0
sudo kpartx -av /dev/loop0
# 此时会生成 /dev/mapper/loop0p1
# 不用时,可以通过下面的命令释放
# sudo kpartx -d /dev/loop0
# sudo losetup -d /dev/loop0
sudo mkdir -p /mnt/rootfs
sudo mount /dev/mapper/loop0p1 /mnt/rootfs
sudo mkfs.ext4 /dev/mapper/loop0p1
sudo grub2-install --target=i386-pc --root-directory=/mnt/rootfs --boot-directory=/mnt/rootfs/boot /dev/loop0
--此时,grub 写了0扇区,2~63扇区, 还有文件系统中的grub2目录 /mnt/rootfs/boot/grub2
sudo umount /mnt/rootfs
六、再次启动qemu
qemu-system-x86_64 -hda gf.os -nographic
打印信息如下
SeaBIOS (version 1.13.0-2.el8)
iPXE (http://ipxe.org) 00:03.0 CA00 PCI2.10 PnP PMM+07F90A50+07ED0A50 CA00
Booting from Hard Disk...
..
error: ../../grub-core/disk/i386/pc/biosdisk.c:546:failure reading sector 0x0 fr
om `fd0'.
error: ../../grub-core/kern/disk.c:237:disk `lvmid/IQGNsA-CSsQ-2A7y-rNYy-VbQx-tj
WB-S12NQ8/VYObIf-KSbT-k4Mi-gFY9-sPDE-3YE8-wjpdkY' not found.
Entering rescue mode...
grub rescue>
grub rescue>
grub rescue>
七、拷贝本机内核,编辑grub.cfg
sudo mount /dev/mapper/loop0p1 /mnt/rootfs
下面拷贝内核,编辑grub.cfg
sudo cp /boot/vmlinuz-4.19.112-2.el8.x86_64 /mnt/rootfs/boot/
sudo vi /mnt/rootfs/boot/grub2/grub.cfg
menuentry "My GF OS" {
set root=(hd0,msdos1)
linux /boot/vmlinuz-4.19.112-2.el8.x86_64 root=/dev/sda1 rw console=ttyS0
}
sync
sudo umount /mnt/rootfs
八、再次启动qemu
qemu-system-x86_64 -hda gf.os -nographic
内核启动了,打印信息如下,缺少init
5.979636 ---[ end Kernel panic - not syncing: No working init found.
九、拷贝busybox
sudo mount /dev/mapper/loop0p1 /mnt/rootfs
ls code/gitcode/busybox/gfos
bin sbin usr
cp -r code/gitcode/busybox/gfos/* /mnt/rootfs/
rm /mnt/rootfs/sbin/init #删除这个init程序后,内核会把shell当做init
sudo umount /mnt/rootfs
十、再次启动qemu
qemu-system-x86_64 -hda gf.os -nographic
打印如下
[ 5.401956] x86/mm: Checked W+X mappings: passed, no W+X pages found.
[ 5.403218] rodata_test: all tests were successful
[ 5.403786] Run /sbin/init as init process
[ 5.407514] Run /etc/init as init process
[ 5.408012] Run /bin/init as init process
[ 5.411401] Run /bin/sh as init process
/bin/sh: can't access tty; job control turned off
~ # ls
bin boot lost+found sbin usr
~ # ps
PID USER TIME COMMAND
ps: can't open '/proc': No such file or directory
~ #
#ls命令可以使用,ps命令不能使用
#手工创建 /proc文件夹,然后挂载 mount -t proc none /proc
#ls /proc 就可以看到进程信息了, ps 也可以看到进程了。top命令也可以用了。
~ # mkdir /sys
~ # mount -t sysfs none /sys
~ # ls /sys
block class devices fs kernel power
bus dev firmware hypervisor module
~ # mkdir dev
~ # mount -t devtmpfs devtmpfs /dev
~ # ls /dev
autofs tty22 tty7
bsg tty23 tty8
console tty24 tty9
cpu tty25 ttyS0
cpu_dma_latency tty26 ttyS1
full tty27 ttyS10
hpet tty28 ttyS11
hwrng tty29 ttyS12
input tty3 ttyS13
kmsg tty30 ttyS14
mapper tty31 ttyS15
mcelog tty32 ttyS16
md0 tty33 ttyS17
mem tty34 ttyS18
memory_bandwidth tty35 ttyS19
network_latency tty36 ttyS2
network_throughput tty37 ttyS20
null tty38 ttyS21
nvram tty39 ttyS22
port tty4 ttyS23
ptmx tty40 ttyS24
random tty41 ttyS25
raw tty42 ttyS26
rtc0 tty43 ttyS27
sda tty44 ttyS28
sda1 tty45 ttyS29
sg0 tty46 ttyS3
sg1 tty47 ttyS30
snapshot tty48 ttyS31
sr0 tty49 ttyS4
tty tty5 ttyS5
tty0 tty50 ttyS6
tty1 tty51 ttyS7
tty10 tty52 ttyS8
tty11 tty53 ttyS9
tty12 tty54 urandom
tty13 tty55 usbmon0
tty14 tty56 vcs
tty15 tty57 vcs1
tty16 tty58 vcsa
tty17 tty59 vcsa1
tty18 tty6 vcsu
tty19 tty60 vcsu1
tty2 tty61 vga_arbiter
tty20 tty62 zero
tty21 tty63
~ # df
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/root 94069 18027 68947 21% /
devtmpfs 48644 0 48644 0% /dev
十一、优化
到上一步,这个系统已经可以基本运行了。
但是挂载的动作是手工做的,init也是用sh代替的。
下面启动真的init
sudo mount /dev/mapper/loop0p1 /mnt/rootfs
# 创建inittab,在表中第一行配置要先启动/etc/init.d/rcS脚本
vi etc/inittab
# 系统启动时最先执行一次,阻塞后续动作
::sysinit:/etc/init.d/rcS
# 在控制台提供一个交互式 Shell,崩溃或退出后自动重启
# 因为你用了 -nographic,所以指定 ttyS0 作为控制台
#::respawn:/sbin/getty -L ttyS0 115200 vt100
ttyS0::respawn:/bin/sh
# 按下 Ctrl+Alt+Del 时重启
::ctrlaltdel:/sbin/reboot
# 系统关机时执行的操作
::shutdown:/bin/umount -a -r
# 创建启动脚本
vi etc/init.d/rcS
#!/bin/sh
# 挂载虚拟文件系统(让内核和用户空间能沟通)
mount -t proc none /proc
mount -t sysfs none /sys
# 动态创建设备节点(强烈建议加上,这样就不需要手动 mknod 了)
mount -t devtmpfs devtmpfs /dev
# 设置主机名
hostname gf-os
# 打印启动成功信息
echo "GF-OS is up and running!"
最后,要给这个脚本设置权限
chmod +x etc/init.d/rcS
sudo umount /mnt/rootfs
这次启动,各项功能就正常了。
ps、vi、reboot、poweroff 都可以使用
十二、再优化(支持登陆)
sudo mount /dev/mapper/loop0p1 /mnt/rootfs
1、
inittab中,改为首先启动getty,这个命令会调用login,以及sh
::respawn:/sbin/getty -L ttyS0 115200 vt100
#ttyS0::respawn:/bin/sh
2、创建root用户的目录,把root的密码设置为空
mkdir /mnt/rootfs/root 目录
echo 'root:x:0:root' > /mnt/rootfs/etc/group
echo 'root:x:0:0:root:/root:/bin/sh'>/mnt/rootfs/etc/passwd
echo 'root::20634:0:99999:7:::'>/mnt/rootfs/etc/shadow
chmod 600 /etc/shadow
sudo umount /mnt/rootfs
然后启动qemu进入linux系统后,就会提示输入登陆用户名和密码
然后可以在linux中用passwd命令修改root密码。
十三、网络
下载linux内核,使用默认配置(默认也会编译这个网卡)
make defconfig
Device Drivers -> Network device support -> Ethernet driver support -> Intel devices
找到 Intel® PRO/1000 PCI-Express Gigabit Ethernet support
make -j$(nproc)
编译好的内核拷贝到磁盘镜像中
sudo cp arch/x86/boot/bzImage /mnt/rootfs/boot/
启动qemu
qemu-system-x86_64 -hda gf.os -nographic -netdev user,id=net0 -device e1000,netdev=net0
进去后可以看到三个网卡(一个环回网卡,一个eth0,还有一个sit0)
但网卡都没有启动,且无ip地址
ip link set lo up
ip addr add 127.0.0.1/8 dev lo
ip link set eth0 up
ip addr add 10.0.2.15/24 dev eth0
ip route add default via 10.0.2.2 dev eth0
然后就可以ping通127.0.0.1和10.0.2.15, 另外网关10.0.2.2也可以ping通
但宿主机10.137.239.107和其它机器还是ping不通,提示
宿主机理论上是不通的,因为qemu默认是nat模式
其它机器也不通,就不知道原因了,AI也没有分析出来