<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Linux利器:QEMU!用它模擬開發(fā)板能替代真開發(fā)板?

          共 6591字,需瀏覽 14分鐘

           ·

          2020-09-29 17:48


          不想錯過我的推送,記得右上角-查看公眾號-設(shè)為星標(biāo),摘下星星送給我!


          QEMU,搞嵌入式開發(fā)的一定不陌生,最近各大群里都討論瘋了,說它是Linux利器一點(diǎn)也不夸張。它是一款知名的而且開源的模擬器(官網(wǎng):https://www.qemu.org/),它能在 X86 PC 上運(yùn)行(其實(shí)它也可以在你的 Arm 開發(fā)板上運(yùn)行,我們今天先不討論這種場景),能夠模擬 ArmMIPSRISC-V 等各種 CPU 和開發(fā)板,以及 網(wǎng)卡、聲卡、鍵盤、sdcard、emmcusb等各種外設(shè)。

          你可以把它當(dāng)作一塊召之即來的開發(fā)板,在上面運(yùn)行 U-BootLinux Kernel、甚至 Ubuntu 等各種軟件和操作系統(tǒng)。

          有時候我們想體驗(yàn)一下 mainline 上最新的 U-Boot 或者 Linux Kernel,可是卻發(fā)現(xiàn)手邊沒有合適的板子,或者手邊的板子搭載的 U-Boot Linux Kernel 版本都比較低,這時候 QEMU 可以幫你迅速實(shí)現(xiàn)這一愿望。

          我是Andy, Linux內(nèi)核開發(fā)者。現(xiàn)從事Arm芯片上Linux 系統(tǒng)移植和優(yōu)化工作,并向 u-boot 和 linux kernel開源社區(qū)貢獻(xiàn)了大量補(bǔ)丁。從 Cortex-M3 到 Arm64,RT-Thread 到 Linux kernel, hack 不止,其樂無窮。受達(dá)爾聞邀約為嵌入式開發(fā)愛好者分享這篇好文,更多我的文章,可以關(guān)注我的公眾號:HackforFun
          接下來我?guī)ьI(lǐng)大家一起來感受一下QEMU的強(qiáng)大和樂趣:手把手教你在 Ubuntu 系統(tǒng)中通過 QEMU 來運(yùn)行基于 Arm CPU Linux系統(tǒng)吧。



          QEMU安裝





          我們安裝的是 Arm 版本的 QEMU,如果直接在 Ubuntu 上用sudo apt install qemu-system-arm命令安裝的話,得到的 QEMU 版本比較舊,最好直接通過源碼去編譯。

          我在 Ubuntu 18.04 系統(tǒng)上發(fā)現(xiàn)系統(tǒng)默認(rèn)安裝的 QEMU 在圖形模式(不帶 -nographic 參數(shù))下無法啟動。


          參考上面步驟編譯成功后,得到:qemu-system-arm和qemu-system-aarch64。
          前者用來模擬 32 位的 Arm cpu,比如 Arm9 /Arm11、 Cortex-A7/A9/A15 。
          后者用來模擬 64 位的 Arm cpu,比如 Arm Cortex A53,A57。
          可以用qemu-system-arm -machine help命令來查看所支持的開發(fā)板:


          是不是有很多熟悉的開發(fā)板都在里面,i.MX、EXYNOS 這些知名的芯片都有包含。


          這里我們使用 vexpress-a9 這款開發(fā)板。vexpress-a9 是 Arm 公司自己設(shè)計(jì)的一款 4 核 Cortex-A9 開發(fā)板,U-Boot、Linux Kernel 和 QEMU 對這款開發(fā)板都做了完整的支持。




          編譯U-Boot





          第一步:U-Boot 代碼下載:


          git clone https://gitlab.denx.de/u-boot/u-boot.git
          下載完后,可以看到 configs 目錄下有針對這款開發(fā)板的配置文件:
          vexpress_ca9x4_defconfig


          第二步:編譯


          make vexpress_ca9x4_defconfigmake?CROSS_COMPILE=arm-linux-gnueabihf-?all



          最終編譯生成 elf 格式的可執(zhí)行文件 u-boot 和純二進(jìn)制文件u-boot.bin,其中 QEMU 可以啟動的為 elf 格式的可執(zhí)行文件 u-boot。







          編譯 Buildroot




          啟動一個 Arm Linux 系統(tǒng),一般都要必須的三件套:Bootloader、Linux Kernel、rootfs(根文件系統(tǒng))。
          在很久以前,制作 rootfs 是一件很麻煩的事情:交叉編譯 busybox,然后手動建立標(biāo)準(zhǔn)的 Linux 系統(tǒng)目錄,再把編譯 busybox 生成的各種文件和庫拷貝過來。如果還需要其他的模塊,再交叉編譯。如果交叉編譯的某個模塊依賴其他的庫,還想要辦法解決這個依賴關(guān)系。最后還要手動建立設(shè)備節(jié)點(diǎn),設(shè)置對應(yīng)的權(quán)限。一步一步做下去,任意一個環(huán)節(jié)都不能出錯。否則啟動的時候不知道會遇到什么莫名其妙的問題。

          Buildroot 項(xiàng)目出現(xiàn)之后,如同它的 Slogan:MakingEmbedded Linux Easy,構(gòu)建 rootfs 就變得輕松了許多,用一個群友的話說:
          自從用了buildroot,我就告別了刀耕火種的野蠻生活。那種文件系統(tǒng)自己定制,需要任何工具都要自己下源碼交叉編譯然后被各種庫問題搞的焦頭爛額的時代一去不復(fù)返了。



          ◆?代碼下載:
          git clone git://git.buildroot.net/buildroot
          Buildroot 代碼倉庫默認(rèn)只包含一個編譯框架,所以代碼量很小,下載起來很快。真正構(gòu)建 rootfs需要的各種代碼包是根據(jù)你的配置選項(xiàng),在編譯的時候才開始下載的。
          ◆?配置:
          Buildroot 提供了和 U-Boot、Linux Kernel 等主流開源項(xiàng)目一樣的 menucoinfig 配置接口,可以通過make help來查詢所支持的各種命令:



          開發(fā)者只要執(zhí)行make menuconfig命令,就能通過這個熟悉的界面去選擇自己需要的各種組件,定制自己的 rootfs:
          首先要配置的是 Target options 選項(xiàng):

          大部分 Arm 都是小端模式,所以選上 little endian
          這款開發(fā)板的 CPU 是 cortex-A9。我們將使用 Linaro GCC 進(jìn)行編譯,Linaro 的 GCC 默認(rèn)都打開了 hardfloat 的支持,所以選上 VFP extension 和 EABIhf
          交叉編譯工具 Linaro GCC 的安裝可以參考前面的文章:一次搞定 Arm Linux 交叉編譯
          Build options選項(xiàng):



          第一個選項(xiàng)是設(shè)置最后生成的配置文件的保存路徑,buildroot 可以針對不同的板子生成特定的 defconfig 文件,默認(rèn)保存在 configs 目錄下。
          自己修改各項(xiàng)配置后,執(zhí)行make savedefconfig命令,就會生成新的 defconfig 文件:




          下次編譯之前,可以直接執(zhí)行make ca9_mini_defconfig命令來加載已有的配置。
          第二個選項(xiàng)設(shè)置 buildroot 下載的各種第三方包的存儲路徑,默認(rèn)在 dl 目錄下:




          設(shè)置 Toolchain




          因?yàn)檫@里使用電腦上自己安裝的 toolchain,所以我們這里選 External toolchainCustom toolchain
          然后在 Toolchain path 中填寫 toolchian 在電腦上安裝的位置,如果不知道具體位置,用which命令查看:




          另外要注意 Toolchain prefix 這個前綴別寫錯。
          設(shè)置 toolchain 的版本和用來編譯這個 toolchain 的內(nèi)核頭文件的內(nèi)核的版本:
          Toolchain 的版本我們根據(jù) Toolchain 的名字或者通過arm-linux-gnueabihf-gcc ?-v 命令就可以查到。
          編譯 Toolchain 的內(nèi)核頭文件對應(yīng)的內(nèi)核的版本是什么呢?
          我們在這個選項(xiàng)上敲 h 鍵,會看到下面的幫助選項(xiàng):



          原來這個版本可以在 toolchain 里面的 version.h 這個文件查到:
          打開這個文件:
          arm-linux-gnueabihf/libc/usr/include/linux/version.h


          263680 對應(yīng)的十六進(jìn)制為 0x40600,右移 16 位,得到的版本號為 4。這就是上面 4.0.x 的由來。
          這里也教給了大家一個小竅門:當(dāng)我們在 make menuconfig 做配置的時候,如果遇到了看不懂的選項(xiàng),直接在這個選項(xiàng)上敲 h 鍵,會看到一些有用的幫助信息,對這個選項(xiàng)做進(jìn)一步解釋。
          因?yàn)?vexpress_a9 內(nèi)核啟動的控制臺的名字叫做 ttyAMA0,所以我們還要在 :System configuration->Run a getty(login prompt)?after boot選項(xiàng)中配置 TTY Port 為 ttyAMA0。否則文件系統(tǒng)掛載后無法進(jìn)入控制臺。



          我們把編譯的 rootfs 以 initramfs 的形式和 Linux Kernel 鏈接在一起,為了讓根文件系統(tǒng)鏡像盡量小,可以對文件系統(tǒng)采用 lz4 壓縮,所以 Filesystem images 還要做如下配置:




          到這里一個最精簡的 buildroot 已經(jīng)配置完成。
          如果還需要其他的命令或者工具,可以在 Target Packages 下面開啟:
          如果你需要的某個模塊,buildroot 里面沒有,還可以自己添加:
          比如加入上面這個補(bǔ)丁,就可以讓 buildroot 在編譯的時候自動下載 https://github.com/rockchip-linux/io.git 并編譯。
          退出執(zhí)行make命令開始編譯。
          Buildroot 編譯的過程中會自動通過網(wǎng)絡(luò)下載需要的各種包,所以要保證網(wǎng)絡(luò)暢通。
          編譯完成后輸入信息如下圖:




          編譯Linux Kernel




          1)代碼下載
          git clone https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
          Linux mainline 已經(jīng)有了對 vexpress_a9 這塊板子的支持:




          這里面的 ca 就是 Cortex-a 的簡寫,所以 ca9 就是 Cortex-A9,ca15 就是 Cortex-A15.
          2)配置
          把前面 buildroot 編譯的 rootfs.cpio.lz4 拷貝到 linux kernel 根目錄下:
          cp../buildroot/output/images/rootfs.cpio.lz4 .make?ARCH=arm vexpress_defconfig
          執(zhí)行make ARCH=arm menuconfig命令,我們修改一些基本的配置:
          General setup->Initramfs source file處填寫 rootfs.cpio.lz4, 就是我們前面從 Buildroot 拷貝過來的 rootfs,這里面我們把它和內(nèi)核編譯在一起,當(dāng)然,rootfs也可以單獨(dú)作為一個文件,放在獨(dú)立的分區(qū)去加載,這種方式我們可以留在以后去嘗試。
          ?


          在 Kernel hacking->printk and dmesg options選項(xiàng)中選中第一項(xiàng),這樣打印的內(nèi)核 log 前面會附帶有時間戳信息,比較好看。



          退出,保存,然后編譯:
          make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-  -j8
          編譯完成。
          如果在編譯 Linux kernel 或者 u-boot 的過程中,遇到什么錯誤,可以參考我之前的文章:LinuxKernel 和 U-Boot 編譯的那些事




          啟動QEMU




          前面說了,QEMU 可以模擬 sd 卡等外設(shè)。我們就把編譯好的固件放在一個模塊的 sdcard 上,讓 QEMU 從這張模擬的 sd 卡上啟動 Linux 系統(tǒng):
          制作 sd 卡鏡像,并將它格式化成 fat 格式:
          dd if=/dev/zero of=sd.img bs=4096 count=4096mkfs.vfat sd.img
          把編譯好的 kernel zImage 和 dtb 文件拷貝到 sd.img 中
          sudo?mount?sd.img?/mnt/?-o?loop,rwsudo?cp?arch/arm/boot/zImage?/mnt/sudo?cp?arch/arm/boot/dts/vexpress-v2p-ca9.dtb?/mnt/sudo?umount?/mnt
          啟動 QEMU
          sudo qemu-system-arm -M vexpress-a9 -m 512M -kernel ../uboot-imx/u-boot-nographic  -sd sd.img



          -M 參數(shù)指定啟動的板子為 vexpress-a9。
          -m 指定這塊板子的內(nèi)存為 512MB。
          -kernel 指定 QEMU 啟動時首先執(zhí)行的程序,我們這里指定為前面編譯好的 u-boot 可以執(zhí)行文件。
          -sd 參數(shù)指定前面制作的 sd.img。
          因?yàn)槲覀冞@里是從命令行啟動,所以加了 nographic 參數(shù)。
          可以看到 u-boot 已經(jīng)順利啟動并進(jìn)入命令,下面我們來啟動 Linux Kernel。
          首先通過 fatload 命令把 sd.img 里面的 zImage 和 dtb 文件讀到開發(fā)板的內(nèi)存中:
          fatload?mmc?0:0 0x62008000?zImagefatload?mmc?0:0?0x64008000?vexpress-v2p-ca9.dtb
          這里面的 0x62008000 和 0x64008000 分別對應(yīng) zImage 和 dtb 文件在內(nèi)存中的加載地址,這兩個地址是怎么來的呢:
          在 Linux Kernel 中,有如下定義:?
          這個 textofs 定義的就是 Linux kernel zImage 執(zhí)行地址對應(yīng)的內(nèi)存偏移地址,默認(rèn)偏移為 0x8000。
          在 u-boot 命令行中輸入bdinfo命令,可以查到這塊開發(fā)板內(nèi)存的起始地址:
          可以看到這塊開發(fā)板的內(nèi)存其實(shí)地址為 0x60000000,所以對應(yīng)內(nèi)核的起始地址為:0x62008000
          dtb 的加載地址沒有特別的要求,一般注意和 Linux Kernel Image 避開,不要重疊即可。
          通過 bootz 命令啟動 Linux Kernel:
          bootz 0x62008000 - 0x64008000
          ?
          啟動到最后輸入root就可以進(jìn)入命令行控制臺。
          到這里,我們就順利的在 QEMU 上把 Arm linux 運(yùn)行起來了。




          QEMU 能否完全替代開發(fā)板?




          QEMU 是一個模擬器,它和真正的開發(fā)板還是有一定的區(qū)別:
          它無法完全模擬真實(shí)的硬件行為,也很難模擬一個 gpio 讓你去拉高拉低或去點(diǎn)一個 led 燈,又或者去模擬 dram,一個 LCD 接口,讓你去接一個顯示屏….看起來它不能模擬的東西太多了,那它到底有什么用呢?
          它的強(qiáng)項(xiàng)是模擬實(shí)現(xiàn)那些不涉及具體硬件外設(shè)的場景,比如:
          你想快速體驗(yàn)一下最新的 u-boot 和 linux kernel,它拿過來就能跑。
          你想在 Arm 上運(yùn)行 Ubuntu、Debian 這些時髦的 Linux 發(fā)行版,用它就行。
          你想研究u-boot 或者 linux kernel 的啟動流程,它也很合適。我有時候在具體的開發(fā)板上移植 Linux 內(nèi)核的時候,發(fā)現(xiàn)某個流程跑的很異常,我又不確定正常的流程是什么樣的時候,我就直接拿 QEMU 來跑一下做對比。
          你想了解文件系統(tǒng)的掛載過程,它很合適。
          你想學(xué)習(xí) Arm 匯編,完全可以在 QEMU 上跑,配合 GDB 就能單步調(diào)試?yán)病?/span>
          你想學(xué)習(xí)?Linux 設(shè)備樹,它可以拿來做實(shí)驗(yàn)….
          再或者你想編譯某個開源的項(xiàng)目在 Arm 開發(fā)板上運(yùn)行,而交叉編譯比較困難,就可以考慮直接在 QEMU 上運(yùn)行一個 Arm Ubuntu 來編譯,也許會簡單很多。
          假設(shè)你以前一直玩單片機(jī)、做硬件,也想體驗(yàn)下 Arm Linux 開發(fā),用 QEMU 試試再適合不過了。用在對的場景,QEMU 就是一款召之即來的利器!
          END

          ? 推薦閱讀:
          ? ??專輯|Linux文章匯總
          ? ??專輯|程序人生
          ? ??專輯|C語言


          嵌入式Linux
          微信掃描二維碼,關(guān)注我的公眾號?
          瀏覽 123
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  一级操逼视频看看 | 逼特逼在线播放 | 成人H动漫精品一区二区无码软件 | 99视频自拍 | 麻豆成人传媒网,一区二区三区四区 |