目錄
解決SSH遠程登錄Linux Server沒有GUI界面的問題
爲什麼選擇QEMU
QEMU(Quick Emulator)是個模擬器(官網鏈接:https://www.qemu.org),它能夠動態模擬特定架構的CPU指令,如X86,ARM,RSIC等。
如上圖所示,QEMU模擬系統架構稱爲TARGET,運行 QEMU的系統架稱爲HOST,QEMU的核心模塊是微型代碼生成器(TCG),它用來將TARGET系統上的代碼動態翻譯成HOST系統的代碼,QEMU的工作原理就是不斷提取TARGET代碼並且翻譯成HOST代碼。整個翻譯分爲兩個部分:第一個部分是將做TARGET代碼(TB)轉化成TCG中間代碼,然後再將中間代碼轉化成HOST代碼。
Linux Kerenl 涉及到具體硬件driver適配,選擇QEMU將Linux 模擬爲TARGET上的GUEST OS系統,運行在HOST的開發機(通常是X86 window/MacOS/Ubuntu OS)上,可以避免做硬件driver適配的時間與人力投入,大大提升學習kernel的效率。
資源下載
Linux Kernel
- Source Code Archives: https://www.kernel.org/
- master branch github: https://github.com/torvalds/linux
- Documentation: https://www.kernel.org/doc/html/latest/
QEMU
- Source Code Archives: https://www.qemu.org/download/#source
- mast branch github: https://github.com/qemu/qemu
Busybox
- Source Code Archives: https://busybox.net/downloads/
環境配置
Linux Kernel
- HOST OS開發環境: Linux version 4.10.0-28-generic (gcc version 5.4.0 20160609 (ubuntu~16.04.4) ) #32~16.04.2
- 下載Linux Kernel linux-3.16.84 https://cdn.kernel.org/pub/linux/kernel/v3.x/linux-3.16.84.tar.xz (選擇老版本避免太多的編譯依賴問題)
- cd linux-3.16.84
- make menuconfig (默認配置exit 生成.config)
- make -j24
- 編譯成功後可以在arch目錄下看到壓縮後的Linux Kernel Image: bzImage
QEMU編譯
- Host OS開發環境:同上
- 下載QEMU 最新master代碼:git clone https://github.com/qemu/qemu.git
- 編譯
- cd qemu
- make build
- cd build
- ../configure
- 注意:一定要確認configure的結果中"SDL support“ 爲yes,否則QEMU運行無法正常顯示Linux終端窗口(參考”SSH遠程登錄Linux Server沒有GUI界面的問題“章節)
- make -j24
- 編譯成功後生成QEMU執行程序:qemu/build/x86_64-softmmu/qemu-system-x86_64
Busybox編譯與rootfs
- Host OS開發環境:同上
- 下載Busybox 代碼:https://busybox.net/downloads/busybox-1.30.0.tar.bz2 (下載哪個版本取決與開發環境的編譯依賴)
- 編譯Busybox
- cd busybox-1.30.0
- make menuconfig (記得打開靜態編譯busybox選項,否則後續busybox作爲QEMU虛擬機中的linux的init進程啓動會由於找不到鏈接庫出現kernel panic)
- make -j24
- 編譯成功後可以在當前目錄下看到生成了busybox
- make install 生成_install目錄以及必須的rootfs 目錄結構
- 創建rootfs
- cd busybox-1.30.0/_install
- mkdir proc sys dev etc etc/init.d (創建Linux系統運行時的必須目錄,/proc用於掛載proc系統,/sys用於掛載sys系統,dev用於mdev創建設備節點,etc/init.d爲放置busybox啓動腳本的目錄)
- vim etc/init.d/rcS
- chmod +x etc/init.d/rcS (確保rcS有執行權限)
#!/bin/sh
#將proc文件系統掛載到/proc目錄,因爲很多應用程序會使用到/proc中的信息,不掛載會導致各種異常
mount -t proc none /proc
#將sys文件系統掛載到/sys目錄,因爲很多應用程序會使用到/sys中的信息,不掛載會導致各種異常
mount -t sysfs none /sys
#mdev是busybox自帶的一個udev,用於系統啓動和熱插拔或動態加載驅動程序時,自動產生設備節點,這句話如果不加上則需要手動mknod來掛載設備節點
/sbin/mdev -s
Linux第一個啓動的進程是init(通過busybox生成的rootfs中sbin/init其實是指向busybox的連接,所以第一個啓動的就是busybox),通過該腳本指定init使用的啓動腳本爲/etc/init.d/rcS,該路徑被聲明在 busybox-1.30.0/init/init.c當中
- 創建rootfs鏡像img
-
find . | cpio -o --format=newc > rootfs.img
-
gzip -c rootfs.img > rootfs.img.gz
QEMU運行Linux
- cd qemu/build/x86_64-softmmu/
- ./qemu-system-x86_64 -kernel <path to linux kernel image>/bzImage -initrd <path to rootfs img>/rootfs.img.gz -append "root=/dev/ram rdinit=sbin/init noapic"
鏡像文件
vmlinux 編譯出來的最原始的內核文件,未壓縮
zImage 由mlinux經過gzip壓縮後的文件
bzImage big zImage。 zImage解壓縮內核到低端內存(640K),bzImage解壓縮內核到高端內存(1M以上)。如果內核比較小,採用zImage或者bzImage都行,如果比較大應該用bzImage
uImage U-boot專用的映像文件,它是在zImage之前加上一個長度爲0x40的tag
vmlinuz 是zImage/bzImage文件的拷貝或者是指向zImage/bzImage的鏈接
initrd initial ramdisk。linux系統引導過程當中掛載的一個臨時根文件系統,被掛載於/dev/ram,它用於支持Linux第二階段的引導過程。它是使用gzip進行壓縮的cpio文件
QEMU
qemu-system-i386 QEMU 模擬i386指令CPU的模擬器
qemu-system-x86_64 QEMU 模擬x86_64指令CPU的模擬器
qemu -kernel 參數,使用bzimage作爲linux內核
qemu -initrd 參數,指定initrd鏡像
qemu -append 參數,附加內核啓動參數
內核啓動參數
root= 使用哪個設備作爲根文件系統。
rdinit= 內核加載完畢之後,即運行initrd中指定路徑的程序,來創建linux的第一個進程
init= 內核加載完畢之後,即運行initramfs中指定路徑的程序,來創建linux的第一個進程
noapic apic,高級可編程中斷控制器。這裏用於防止發生MP-BIOS BUG 8254 timer not connected
- 如果HOST 系統是通過ssh 遠程登錄的,那麼大概率會遇到QEMU卡死在下面的提示信息,看不到Linux啓動的終端GUI界面
VNC server running on 127.0.0.1:5900
解決SSH遠程登錄Linux Server沒有GUI界面的問題
如上圖所示,完整的Linux Host OS中有完整的X11 Window System顯示系統,作爲X11 Client的應用程序(比如 QEMU)可以正常連接到X11 Server 顯示它的終端GUI 窗口,但是SSH 遠程登錄某個Linux Host OS後是沒有X11 Server支持的,所以會出現QEMU無法顯示終端GUI界面的問題
如上圖所示,通過將SSH遠程登錄的Host OS上對X11的調用Forward到支持X11 顯示系統的本地OS,就可以解決該問題
以遠程Host OS爲ubuntu,本地OS爲MacOS爲例,做如下配置:
- Server = ”SSH遠程登錄Host OS爲ubuntu系統“
- Client = ”本地OS爲MacOS“
- Client與Server端修改/etc/ssh/ssh_config
- X11Forwarding yes
- ForwardAgent yes
- Client
- xhost + # 允許任何機器連接
- ssh -X 用戶名@ip -p 22 # 連接遠程服務器
- Server
- export $(cat /proc/1/environ |tr '\0' '\n' | xargs) (如果是docker容器需要設置和主進程相同的環境變量)
- 運行xclock 測試程序確認看到GUI界面證明X11的forward已經成功
如下圖所示,再次運行./qemu-system-x86_64 -kernel <path to linux kernel image>/bzImage -initrd <path to rootfs img>/rootfs.img.gz -append "root=/dev/ram rdinit=sbin/init noapic" 可以看到QEMU的GUI正常顯示,如果Linux 啓動一切順利就可以進入到busybox的shell環境,通過在/目錄執行ls -l 命令可以看到rootfs就是我們在<host os>/busybox-1.30.0/_install 目錄中手工創建的rootfs目錄結構