[爆卦]qemu使用是什麼?優點缺點精華區懶人包

為什麼這篇qemu使用鄉民發文收入到精華區:因為在qemu使用這個討論話題中,有許多相關的文章在討論,這篇最有參考價值!作者LoganChien (簡子翔)看板b97902HW標題[教學] 用 qemu + chroot...


用 qemu + chroot 編譯與測試 Linux Kernel

聽說有人光是編譯 Linux Kernel 就編譯了 4 個小時,
也就是說若以 10/28 為 deadline 各位只剩下 42 次
修改檔案的機會...。
-- 來自地下室的哀號


序言

我個人非常不喜歡編譯 kernel,因為 kernel 是作業系統當中最重要
的部分。如果 kernel 編壞了可能無法開機,而且可能弄亂原有的作業
系統。

如果萬不得已要自己編譯,我通常會使用 fakeroot make-kpkg 之類
的指令把 kernel 編譯成 Debian 套件,再用 dpkg -i 安裝。日後要
移除也比較容易。

然而我日常的作業系統就是 Ubuntu,我不希望 OS Project 1 染指我
每天要使用的系統。而且一直重新開機測試修改成果也非常累,所以
我還是比較想要使用虛擬機器 (Virtual Machine)。

我這次要介紹二個工具:qemu-kvm 與 chroot,這二個工具都是用來
創造和原本作業系統相互隔離的環境,也各有長處與短處,所以我的
攻略會交互使用二個工具。

- qemu / qemu-kvm

這是一個虛擬機器,就像 VMWare, Virtual Box, Virtual PC 等軟體,
可以用來模擬一台虛擬的電腦。

qemu 是使用 Dynamic Recompilation 模擬 CPU,不過這種技術執行速
度約為 Host CPU 的 20%。而 qemu-kvm 使用 paravirtualization,會
利用 Intel/Amd CPU 提供的虛擬機制加快模擬速度,執行速度約為 50~
80%。

- chroot

這個是 Linux 之下的一個程式,可以幫我們把根目錄替換成另一個目錄,
就好像使用不同的 Linux(gcc、bash 甚至是 mv cp 等指令都會被換掉)。
在 chroot 環境下執行程式與一般環境執行程式無異,所以速度是 100%。
然而 chroot 不能完全隔離所有操作,所以要小心使用(避免使用 root
身分,或者是 sudo),以免影響原有的作業系統。



準備工作

1. 先有一套 Linux(推薦使用 Ubuntu Linux 或 Debian Linux)
以便使如 qemu-kvm 與 chroot

2. 準備一份 Linux 安裝光碟映像檔(我自己是用 Ubuntu 10.10)

3. 取得 qemu 與 qemu-kvm,在 Ubuntu Linux 之下,可以使用以
下指令取得:

$ sudo apt-get install qemu qemu-kvm

4. 取得一份 Linux Kernel source code(我是用 2.6.36)
http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.36.tar.bz2


準備子系統

1. 建立虛擬機器的硬碟檔案(至少要 10Gb)

$ dd if=/dev/zero of=disk.img bs=1 count=1 seek=10737418239

稍微說明一下:為了使用 chroot,我們不使用 qemu 特有可以動
態成長的硬碟格式。不過這裡還是使用了一個小技巧:直接把檔
案 seek 到 10Gb - 1byte 的地方,寫入一個 byte 以節省時間。

2. 用 qemu 開啟子系統

$ qemu -hda disk.img -m 1024 \
-cdrom ubuntu10.10.iso -boot d

參數說明:

-hda 以此檔案為主硬碟
-cdrom 以此檔案為光碟映像檔
-boot 開機選項 (c) 硬碟 (d) 光碟
-m 虛擬機器要有多少記憶體 (MB)


3. 依指示安裝作業系統。不過要注意:在割硬碟的時候,把整塊都割
給 root (/),不要留 swap。(要選「專家模式」然後手動切割)

4. 關機時,要我們取出光碟,此時就可以把 qemu 關掉了!

5. 重新開機

$ qemu -hda disk.img -m 1024

6. 在子系統安裝必要的軟體(打開「應用程式->附屬應用程式->終端機」)

\> sudo apt-get build-dep linux # 編譯 linux 必備
\> sudo apt-get install libncurses5-dev # menuconfig 必備

7. 關機



在主系統掛載子系統的分割區

我想在主系統編譯 kernel,所以我要把子系統的分割區掛載到主系
統上,再使用 chroot 把 root 切換到這一個分割區。

1. 先檢查分割表計算分割區的 offset:

$ sudo losetup /dev/loop0 disk.img
$ sudo fdisk /dev/loop0

Command (m for help): p # 用 p 列出分割表的資訊

Disk /dev/loop0: 8589 MB, 8589934592 bytes
255 heads, 63 sectors/track, 1044 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes # 記住 sector 的大小
I/O size (minimum/optimal): 512 bytes / 512 bytes

Command (m for help): x # 進入專家模式

Expert command (m for help): p # 再列出分割表的資訊

Disk /dev/loop0: 255 heads, 63 sectors, 1044 cylinders

Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID
1 80 32 33 0 86 53 993 2048 15955968 83 # 記住 start

Expert command (m for help): q


$ sudo losetup -d /dev/loop0

透過以上步驟,我們知道一個 sector 的大小是 512byte,另外
子系統的 root partition 是在 2048 個 sector,所以 offset
是 512 * 2048 = 1048576 (請根據你自己的情況加以修改)


2. 掛載子系統的 root 分割區

$ mkdir partition

$ sudo losetup --offset 1048576 /dev/loop0 disk.img # 把檔案當 loop device

備註:如果這一步有問題,可以試不同的 loop device:loop0 ~ loop7。

$ sudo mount /dev/loop0 partition # 掛載檔案系統

備註:如果這一步有問題,大概是你的 offset 算錯了!


3. 解壓縮 Linux Kernel 的原始碼

$ sudo chown username:username partition/usr/src

備註:暫時修改資料夾的權限。username 是你主系統檔中
uid 為 1000 的使用者。一般來說應該就是你自己。

$ tar jxf linux-2.6.36.tar.bz2 -C partition/usr/src

說明:解壓縮 Linux Kernel source code 到 partition/usr/src
資料夾之下。

$ sudo chown root:root partition/usr/src

備註:把權限改回來。



編譯 linux 核心

1. 使用 chroot 進入子系統。要小心,chroot 的隔離不是絕對
安全的!只要有 root 權限,隨時可以離開 chroot 的隔離
環境,所以要避免使用 root。

$ sudo chroot partition env -i TERM=xterm su username

參數說明:partition 是子系統的根目錄,也就是我們要切換
的目標,後面是緊接著要執行的指令。

env -i 會把不相關的環境變數清掉。而 TERM=xterm 是因為
menuconfig 需要這個環境變數。

su 是把使用者切換成 username。這個 username 是子系統的
user,應該是你安裝子系統時填入的名字。

2. 複製 Linux Kernel 設定檔

\> cp /boot/config-2.6.35-22-generic .config

3. 執行 menuconfig。不用調整任何選項,直接 Exit 就可以了。

\> make menuconfig

4. 開始編譯 Kernel 與模組

\> make -j4 bzImage modules

備註:根據每個人電腦的不同,要使用不同的 -jN。我的電
腦是雙核心的 cpu,所以我覺得 -j4 很適合我。大家的電腦
應該都比我好,可以用更大的數字(但適量就好,並不是越大
越快)。

備註:用筆電的人記得把電源接上,讓 CPU 可以全速工作。

備註:在我的筆電上這一步大概要 50 分鐘到 1 小時。



安裝新核心

編譯完成之後,我們要安裝核心。不過要安裝核心,必需要有 sudo
的權限,所以在 chroot 的環境下不太安全,所以我們還是要改用
qemu 開機。

1. 離開 chroot 環境,並卸載子系統的分割區。

\> exit # 離開 chroot 環境
$ sudo umount partition # 卸載檔案系統 (這可能會有一點久)
$ sudo losetup -d /dev/loop0 # 解除檔案與 loop device 之間的關連

2. 使用 qemu 開機

$ qemu -hda disk.img -m 1024

3. 開啟終端機,依序執行以下指令

\> cd /usr/src/linux-2.6.36
\> sudo make modules_install install
\> sudo mkinitramfs -o /boot/initrd.img-2.6.36 2.6.36

4. 修改 grub2 設定檔,在 GRUB_HIDDEN_TIMEOUT=0 的前面加上 '#'。

\> sudo vi /etc/default/grub
:%s/GRUB_HIDDEN_TIMEOUT=0/#GRUB_HIDDEN_TIMEOUT=0/g
:wq

5. 更新開機選單

\> sudo update-grub2

6. 重新開機



小結

我們使用了二種創造隔離環境的方法:(1) 使用 qemu 當做我們的
虛擬機器 (2) 使用 chroot 隔離主系統與子系統。前者比較安全,
不過比較慢;後者比較快,但是比較不安全。

另外,一般我們要進入 chroot 的環境,我們要 losetup、mount、
chroot,使用完必之後,要再 exit、umount、losetup -d。程序
很煩鎖,而且如果沒有 umount、losetup -d,就執行 qemu 就會
有很可怕的結果(很可怕不要問)。所以我寫了一個 shell script
自動執行這些步驟:

http://w.csie.org/~b97073/B/enter-partition.sh.txt

下載後,修改 USERNAME、PARTITION_OFFSET 再 chmod +x,即可
使用 ./enter-partition.sh.txt。看到 leaving successfully
才是正常結束。



修改作業系統與重新安裝

1. $ ./enter-partition.sh # 進入 chroot

2. \> cd /usr/src/linux-2.6.36 # 進入 source code 的資料夾

3. 修改 kernel 的 source code。

(1) kernel 資料夾之下建立 myservice.c 這個檔案,並輸入
助教給的程式:

#include <linux/linkage.h>
#include <linux/kernel.h>

asmlinkage int sys_myservice(int arg1) {
printk("my service is invoked!\n");
return arg1 * 10;
}

(2) 打開 arch/x86/include/asm/unistd_32.h 找到最後一個 #define __NR_...
在它的最面加上 #define __NR_myservice 341 。然後把下面的 NR_syscalls
改成 342。

(3) 打開 arch/x86/kernel/syscall_table_32.S,直接移到
最後一行,加上 .long sys_myservice

(4) 打開 include/linux/syscalls.h,移到最後,#endif 之前,加上
asmlinkage int sys_myservice(int arg1);

(5) 打開 kernel/Makefile,在一開始的地方加上
obj-y += myservice.o

4. \> make -j4 bzImage modules

備註:如果有修改 arch/x86/include/asm/unistd_32.h,
那幾乎所有的 source code (bzImage 與 modules) 都要重
新編譯,又是一個小時... ,所以要儘量避免。

備註:如果只改 kernel/myservice.c kernel/signal.c
include/linux/syscalls.h 重新編譯的時間不超過 10 分鐘。

備註:沒事千萬不要 make clean!!

5. \> exit # 離開 chroot

6. $ qemu -hda disk.img -m 1024

7. \> cd usr/src/linux-2.6.36
\> sudo make modules_install install # 安裝新的 os
\> sudo update-initramfs -u -k 2.6.36 # 更新 initramfs
\> sudo reboot

8. 寫一個測試用的程式:

#include <stdio.h>
#include <stdlib.h>

#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>

#define __NR_myservice 341

int main(int argc, char *argv[])
{
int num = (argc > 1) ? atoi(argv[1]) : 1234;
printf("%d\n", (int)syscall(__NR_myservice, num));
return EXIT_SUCCESS;
}

然後懷著敬畏的心情,compile 並執行它!祝你好運!

9. Project 1 的部分,就如投影片所說,要在 SYSCALL_DEFINE2(kill
加料,而 sent signal 可以在 __send_signal 加料。



Q & A

Q: 喂 logan,我裝了 qemu-kvm 之後,Virtual Box 就壞掉了,
你要負責!

A: qemu-kvm 相衝!所以如果你要用 Virtual Box 必需要把
qemu 與 qemu-kvm 移除。

$ sudo apt-get purge qemu qemu-kvm


Q: 怎麼看 printk 的結果?

A: sudo dmesg | tail -n 10


Q: 為什麼我按下 Alt-F4 之後,qemu 就關掉了,我要關的是裡面的
視窗呀!

A: 按下左方的 Ctrl+Alt 可以鎖定鍵盤還有滑鼠。



結語

這份作業蠻有趣的!

如果有人在結報上提到這篇文章我會很高興的。 ^^

\

--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 140.112.30.131
※ 編輯: LoganChien 來自: 140.112.30.131 (10/22 06:19)
purincess:推一個! 10/22 07:32
davidpanda:L大強者救援文出現了 @.@! 10/22 08:18
fereshte:大強者!!! 10/22 09:28
jimmyken793:Q&A第一個的暫時性解法:sudo rmmod kvm-intel 10/22 09:33
jimmyken793:如果是intel cpu的話 10/22 09:34
jlg79531:謝謝Logan!! 10/22 10:18
lmr3796:救援來了! 10/22 11:03
hanabi:有看有推!! 10/22 18:56
andy74139:推!! :) 10/23 09:49
※ 編輯: LoganChien 來自: 61.224.103.133 (10/23 12:03)
averangeall:有看有推!!! 12/16 12:43

你可能也想看看

搜尋相關網站