1. 程式人生 > >面向移動及嵌入式平臺的輕量級開源ARMv8-A Hypervisor

面向移動及嵌入式平臺的輕量級開源ARMv8-A Hypervisor

Minos - Type 1 Hypervisor for ARMv8-A

Minos是一款輕量級的面向移動及嵌入式系統的開源Type 1 Hypervisor, 直接運行於裸機環境。Minos實現了一套完整的虛擬化框架,可以在同一硬體平臺上同時執行多個不同作業系統的VM(Linux or RTOS). Minos提供了包括CPU虛擬化; 中斷虛擬化; 記憶體虛擬化; Timer虛擬化; 以及一些常用外設虛擬化的支援。

Minos提供一個運行於VM0上的應用程式"mvm"來支援Guest VM的管理。同時mvm提供基於virtio的半虛擬化解決方案, 支援virtio-console, virtio-blk(測試中),virtio-net(測試中)等裝置。

Minos適用於移動及嵌入式平臺,目前只支援ARMv8-A架構。硬體上支援Marvell的Esspressobin開發板,且理論上ARMv8-A + GICV3組合的硬體平臺都可以被支援。軟體除錯平臺支援ARM官方的Fix Virtual Platform (簡稱FVP), 開發者可以用ARM DS5工具來進行模擬和除錯。

Download Source Code And Tools for Minos

  1. 建立工作目錄

     # mkdir ~/minos-workspace
     # cd ~/minos-workspace
    
  2. 安裝gcc交叉編譯工具

     # wget https://releases.linaro.org/components/toolchain/binaries/latest/aarch64-linux-gnu/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu.tar.xz
     # tar xjf gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu.tar.xz
     # sudo mv gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu /opt
     # echo "export PATH=/opt/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin:$PATH" >> ~/.bashrc
     # source ~/.bashrc
    
  3. 安裝abootimg工具

     # sudo apt-get install abootimg
    

    abootimg 工具用來製作Linux VM的bootimge,mvm使用此格式image來載入linux核心,ramdisk和dtb檔案

  4. 安裝device tree程式碼編譯工具

     # sudo apt-get install device-tree-compiler
    
  5. 下載Minos sample

     # git clone https://github.com/minos-project/minos-samples.git
    

    minos-sample提供了Guest VM的dts/dtb檔案,以及製作好的Guest VM boot.img檔案

  6. 下載Minos hypervisor 原始碼

     # git clone https://github.com/minos-project/minos-hypervisor.git
    
  7. 下載Linux Kernel 原始碼

     # git clone https://github.com/minos-project/linux-marvell.git
     # cd linux-marvell
     # git checkout -b minos origin/minos
    

    預設下載的是添加了Minos驅動的Marvell平臺的Linux Kernel, 如果用的是別的硬體平臺,只需要新增Minos驅動就行,下面命令可以獲取Minos驅動以及必要的Kernel Patch

     # git clone  https://github.com/minos-project/minos-linux-driver.git
    
  8. 下載ATF原始碼

     # git clone https://github.com/ARM-software/arm-trusted-firmware.git
    

    在FVP上執行和除錯Minos時需要用到

Run Minos on Marvell Esspressobin

  1. 編譯Minos

     # cd ~/minos-workspace/minos
     # make
    

    Minos預設平臺為Marvel Esspressobin,編譯完成後會在 hypervisor/out目錄下生成minos.bin以及在mvm目錄下生成mvm應用程式

  2. 編譯Marvell Linux Kernel

     # cd ~/minos-workspace/linux-marvell
     # export ARCH=arm64
     # export CROSS_COMPILE=aarch64-linux-gnu-
     # make mvebu_v8_lsp_defconfig
     # make -j4
    

    編譯完成後會在arch/arm64/boot目錄下生成Image核心二進位制檔案。

  3. Esspressobin預設的核心存放在開發板的/boot目錄下,把minos.bin和新的Kernel Image拷貝到/boot目錄下, 並把mvm應用拷貝到開發板的使用者根目錄下。

  4. 更新開發板Uboot啟動設定

    啟動開發板到命令列狀態,執行以下命令更新Uboot啟動設定(這裡以EMMC版本的Esspressobin開發板舉例,採用SD卡方式啟動的開發板,方法類似)

     # setenv bootcmd “mmc dev 1; ext4load mmc 1:1 0x3c000000 boot/minos.bin; ext4load mmc 1:1 0x280000 boot/Image; ext4load mmc 1:1 0xfe00000 boot/armada-3720-community-v5.dtb; setenv bootargs console=ttyMV0,115200 earlycon=ar3700_uart,0xd0012000 root=PARTUUID=89708921-01 rw rootwait net.ifnames=0 biosdevname=0; booti 0x3c000000 - 0xfe00000”
     # saveenv
    
  5. 設定完之後重啟開發板,之後每次開機將會先跳轉到Minos執行hypervisor相關設定,然後再啟動VM0

    提示: 如果因為Minos程式碼錯誤導致系統啟動不了,只需要用原來的啟動引數先啟動到非虛擬化環境,然後把能正常執行的minos.bin替換到/boot目錄下就可以

     # mmc dev 1; ext4load mmc 1:1 $kernel_addr $image_name; ext4load mmc 1:1 $fdt_addr $fdt_name; setenv bootargs $console root=PARTUUID=89708921-01 rw rootwait net.ifnames=0 biosdevname=0; booti $kernel_addr - $fdt_addr
    

Run Minos on Marvell Board

Run Minos on ARM FVP

  1. 下載ARM FVP,建立工作目錄

     # mkdir ~/minos-workspace/arm-fvp
    

    FVP可以在ARM的官網下載,Minos支援FVP_Base_AEMv8A 以及FVP_Base_Cortex-A57x2-A53x4 ,這裡我們預設使用FVP_Base_AEMv8A來進行測試。另外如果想基於Minos做相關開發,也可以直接安裝ARM DS5除錯工具,安裝完之後自帶以上兩個FVP。以下是安裝使用DS5的相關教程

  1. 編譯Minos

     # cd ~/minos-workspace/minos
     # make distclean  (每次改變編譯target前需要執行 make distclean)
     # make PLATFORM=fvp
    
  2. 編譯FVP Kernel

     # cd ~/minos-workspace/minos
     # make ARCH=arm64 defconfig && make ARCH=arm64 -j8 Image
    
  3. 編譯ARM Trusted Firmware

     # cd ~/minos-workspace/arm-trusted-firmware
     # make PLAT=fvp RESET_TO_BL31=1 ARM_LINUX_KERNEL_AS_BL33=1 PRELOADED_BL33_BASE=0xc0000000 ARM_PRELOADED_DTB_BASE=0x83e00000
    
  4. 下載ARM64 virtio-block image

     # cd ~/minos-workspace
     # wget https://releases.linaro.org/archive/14.07/openembedded/aarch64/vexpress64-openembedded_minimal-armv8-gcc-4.9_20140727-682.img.gz
     # gunzip vexpress64-openembedded_minimal-armv8-gcc-4.9_20140727-682.img.gz
     # mv vexpress64-openembedded_minimal-armv8-gcc-4.9_20140727-682.img sd.img
    
  5. 執行FVP

     # cd ~/minos-workspace/arm-fvp
     # ln -s ~/minos-workspace/sd.img sd.img
     # ln -s ~/minos-workspace/arm-trusted-firmware/build/fvp/release/bl31.bin bl31.bin
     # ln -s ~/minos-workspace/linux-marvell/arch/arm64/boot/Image Image
     # ln -s ~/minos-workspace/minos-sample/foundation-v8-gicv3.dtb fdt.dtb
     # ln -s ~/minos-workspace/minos/hypervisor/out/minos.bin minos.bin
    
     # /usr/local/DS-5_v5.27.0/bin/FVP_Base_AEMv8A               \
     -C pctl.startup=0.0.0.0                                     \
     -C bp.secure_memory=0                                       \
     -C cluster0.NUM_CORES=4                                     \
     -C cache_state_modelled=1                                   \
     -C cluster0.cpu0.RVBAR=0x04020000                           \
     -C cluster0.cpu1.RVBAR=0x04020000                           \
     -C cluster0.cpu2.RVBAR=0x04020000                           \
     -C cluster0.cpu3.RVBAR=0x04020000                           \
     -C bp.hostbridge.userNetPorts="8022=22"                     \
     -C bp.hostbridge.userNetworking=true                        \
     -C bp.dram_size=8                                           \
     -C bp.smsc_91c111.enabled=true                              \
     -C bp.virtioblockdevice.image_path=sd.img                   \
     --data [email protected]                    \
     --data [email protected]                     \
     --data [email protected]                       \
     --data [email protected]
    
  6. 啟動FVP之後,可以在主機上執行以下命令通過ssh來登入FVP

     # ssh -p 8022 [email protected]
    

Run Minos on FVP

mvm使用方法

Minos提供兩種方式來建立VM, 一種是使用Minos原始碼下的JSON檔案(例如hypervisor/config/fvp/fvp.json.cc),通過建立一個vmtag的json成員來建立對應的VM,且這種VM的記憶體, IRQ等硬體資源都是通過對應的json檔案來管理的,此方式適合用來建立嵌入式系統中擁有真實硬體許可權的VM, Minos支援將特定的硬體裝置分配給特定的VM。通過這種方式建立的VM當前沒法被mvm管理。

#include "fvp_config.h"
{
	"version": "0.0.1",
	"platform": "armv8-fvp",

	"vmtags": [
	{
			"vmid": 0,
			"name": "linux-01",
			"type": "linux",
			"nr_vcpu": 1,
			"entry": "0x80080000",
			"setup_data": "0x83e00000",
			"vcpu0_affinity": 0,
			"vcpu1_affinity": 1,
			"vcpu2_affinity": 2,
			"vcpu3_affinity": 3,
			"cmdline": "",
			"bit64": 1
		}
	],
	#include "fvp_irq.json.cc"
	#include "fvp_mem.json.cc"

	"others" : {
		"comments": "minos virtualization config json data"
	}
}

另外一種方式就是通過Minos提供的VM管理工具mvm來配置, 當前mvm已經支援了VM的建立,銷燬,重啟和關機操作。

    Usage: mvm [options]

    -c <vcpu_count>            (set the vcpu numbers of the vm)
    -m <mem_size_in_MB>        (set the memsize of the vm - 2M align)
    -i <boot or kernel image>  (the kernel or bootimage to use)
    -s <mem_start>             (set the membase of the vm if not a boot.img)
    -n <vm name>               (the name of the vm)
    -t <vm type>               (the os type of the vm )
    -b <32 or 64>              (32bit or 64 bit )
    -r                         (do not load ramdisk image)
    -v                         (verbose print debug information)
    -d                         (run as a daemon process)
    -D                         (device argument)
    -C                         (set the cmdline for the os)

例如以下命令用來建立一個擁有 2 個vcpu, 84M記憶體, bootimage為boot.img以及帶有virtio-console裝置的64位的(當前Minos只支援64位VM)Linux虛擬機器.

    #./mvm -c 2 -m 84M -i boot.img -n elinux -t linux -b 64 -v -d -C "console=hvc0 loglevel=8 consolelog=9 loglevel=8 consolelog=9" -D virtio_console,@pty:

建立成功的話會有以下log輸出

    [INFO ] no rootfs is point using ramdisk if exist
    [email protected]:~# [INFO ] boot image infomation :
    [INFO ] magic        - ANDROID!
    [INFO ] kernel_size  - 0x877800
    [INFO ] kernel_addr  - 0x80080000
    [INFO ] ramdisk_size - 0x104e21
    [INFO ] ramdisk_addr - 0x83000000
    [INFO ] dtb_size     - 0xcc4
    [INFO ] dtb_addr     - 0x83e00000
    [INFO ] tags_addr    - 0x0
    [INFO ] page_size    - 0x800
    [INFO ] name         -
    [INFO ] cmdline      - console=hvc0 loglevel=8 consolelog=9
    [INFO ] create new vm *
    [INFO ]         -name       : elinux
    [INFO ]         -os_type    : linux
    [INFO ]         -nr_vcpus   : 2
    [INFO ]         -bit64      : 1
    [INFO ]         -mem_size   : 0x5400000
    [INFO ]         -mem_start  : 0x80000000
    [INFO ]         -entry      : 0x80080000
    [INFO ]         -setup_data : 0x83e00000
    [DEBUG] load kernel image: 0x80000 0x800 0x877800
    [DEBUG] load ramdisk image:0x3000000 0x878000 0x104e21
    [DEBUG] vdev : irq-32 gpa-0x7fad895000 gva-0x40000000
    [INFO ] ***********************************************
    [INFO ] virt-console backend redirected to /dev/pts/1
    [INFO ] ***********************************************
    [INFO ] add cmdline - console=hvc0 loglevel=8 consolelog=9 loglevel=8 consolelog=9
    [INFO ]         - delete [email protected]
    [INFO ]         - delete [email protected]
    [INFO ]         - delete [email protected]
    [INFO ]         - delete [email protected]
    [INFO ]         - delete [email protected]
    [INFO ]         - delete [email protected]
    [DEBUG] found 1 rsv memory region
    [DEBUG] add rsv memory region : 0x80000000 0x10000
    [INFO ] setup memory 0x0 0x80 0x0 0x4005
    [INFO ] set ramdisk : 0x83000000 0x104e21
    [INFO ] add vdev success addr-0x40000000 virq-32

Minos當前已經支援virtio-console後端驅動,建立完VM之後可以用minicom等終端工具登入VM

    # minicom /dev/pts/1

minicom to connect VM

製作自定義bootimage

Minos預設提供的boot.img的ramdisk.img基於busybox預設rootfs配置,如果需要自定義自己定製ramdisk,也很簡單,只需要將製作好ramdisk.img和Image以及dtb檔案重新打包:

    # dtc -I dts -O dtb -o guest-vm.dtb guest-vm.dts
    # abootimg --create boot.img -c kerneladdr=0x80080000 -c ramdiskaddr=0x83000000 -c secondaddr=0x83e00000 -c cmdline="console=hvc0 loglevel=8 consolelog=9" -k Image -s guest-vm.dtb -r ramdisk.img