首页
社区
课程
招聘
[翻译]NEXX:arm架构下的虚拟化工具
2016-11-18 09:08 7289

[翻译]NEXX:arm架构下的虚拟化工具

2016-11-18 09:08
7289
简介
NEXX是一个小的(不完整)的arm虚拟化工具,可以用来充当硬件和运行linux系统。通过这个工具,可以很好的学习操作系统内部的运行原理和硬件编程。
我仅仅花了三个月的时间构建了NEXX用于学习。代码质量不在关注范围之内,当然结果是代码很乱。但是我依然把它开源,因为从2011年之后,可能我就没有时间来继续做这件事情了。在这三个月中我做了一下的相关工作:
1.从头构建arm虚拟化:
引导并执行分区(包括寄存器、异常等)
隔离了时间和空间(硬件和软件编程)
激活用于linux虚拟内存与物理内存的MMU
实现一些例如nexx_write_console的超级调用(硬件编程)
2.NAL库(NEXX的抽象层)
支持c运行独立分区(boot.S,linker.lds,etc,.)
抽象库执行超级调用是分开的(c和汇编)
3.对linux打补丁,使其运行在NEXX的虚拟架构上
为linux创建一个新的平台
修改linux的引导程序
创建一个早期的用于打印的控制台
建立一个小的initramfs (rdinit=/init)
提供linux配置文件(.config)
4.加载
解压驻留程序
加载NEXX和二进制分区
检查加载进ARM内存(md5)
跳转到虚拟机加载的位置
获得并解压NEXX ARM虚拟机的源码
在我的博客可以下载NEXX 0.0.1版本的源代码,通过运行以下命令可以下载和解压代码:
   $ mkdir $HOME/nexx
   $ cd $HOME/nexx
   $ wget http://hmarco.org/virtualisation/nexx/nexx-0.0.1-sources.tgz
   $ cd NEXX-hypervisor
   $ tar xvf nexx-sources.tgz
代码包含下面的文件夹:
core:NEXX的代码(boot.S,linker.lds,head.S,etc,.)
user/bin:提取分区信息的脚本
user/libnal:用于导出超级调用的简单库(libnal.a)
user/partitions:辅助构建分区(boot.S,linker.lds,partition0.c)
准备编译NEXX
在进行构建管理程序,分区和linux之前,我们需要使用arm的gcc编译工具来从源代码上构建管理程序。
1.下载并在/opt目录下安装gcc arm编译器
NEXX编译阶段使用none eabi gcc cross编译器。通过下面的命令把gcc编译器安装到了/opt目录下。在配置文件中会用到这个目录。
 $ cd /tmp
 $ wget "https://sourcery.mentor.com/sgpp/lite/arm/portal/package9740/public/arm-none-eabi/arm-20\11.09-69-arm-none-eabi-i686-pc-linux-gnu.tar.bz2"
 $ cd /opt
 $ sudo tar xvf /tmp/arm-2011.09-69-arm-none-eabi-i686-pc-linux-gnu.tar.bz2
2.在目标机器上初始一些依赖包
为了操作arm格式的elf文件、创建和运行虚拟机、分区、linux内核,我们需要在ubuntu上运行下面的命令:
   $ sudo apt-get install binutils-multiarch make qemu-system
在NEXX虚拟机上编译和运行NEXX虚拟机
NEXX虚拟机上可以运行bare分区。下面是一个关于bare分区的简单例子。
1.编译和测试例子
在目录/usr/partitions下包含两个分区的简单例子,分别是"partition0.c"和"partition1.c"。它们通过调用NEXX_write_console()函数来简单打印"I am partition 0"和"I am partition 1"。通过执行下面的指令运行:
$make bare
$make test
执行上面的指令之后,qemu会启动并打印以下信息:
[Loader] PackedMemory used: [0x0]--[0xA000]
 [Loader] Loading NEXX hypervisor ...
 [Loader] NEXX [0x608000]--[0x60C060]
 [Loader] Loading Partitions ...
 [Loader] P1 [0xA00000]--[0xA00298]
 [Loader] P2 [0xB00000]--[0xB00298]
 NEXX_MD5(608000 , 16480, hash);
 RAM MD5 [6DC677DC22A278715CA795FC76F8450]
 [Loader] Starting NEXX at 0x608000...
 
 [NEXX] Starting NEXX Hypervisor ...
 [NEXX] CPU ID:41069265
 [NEXX] CR:90078
 [NEXX] PGT [0x400000]-[0x404000]
 [NEXX] PGT [0xAFC000]-[0xB00000]
 [NEXX] PGT [0xBFC000]-[0xC00000]
 [NEXX] Calling scheduler()
 Run partition id:0
 I am partition 0
 I am partition 0
 I am partition 0
 I am partition 0
 I am partition 0
 
 [NEXX-LOG] timerIrqHandler(). Context switch ... 
 
 Run partition id:1
 I am partition 1
 I am partition 1
 I am partition 1
 I am partition 1
 I am partition 1
 
 [NEXX-LOG] timerIrqHandler(). Context switch ... 

 Run partition id:0
 I am partition 0
 I am partition 0
 I am partition 0
 ... ...

2.修改分区部分的c代码
你可以通过新的代码来建立bare分区。示例代码可以在解压的代码中找到。文件"usr/partitions/partitions0.c"和“usr/partitions/partitions1.c”分别是分区1和分区2的代码。
在分区中第一个调用的函数是PartitionMain()函数,这个函数不需要任何的参数。你可以把这份代码加入到你自己的函数中来创建新的分区。
在NEXX上编译,运行linux系统,并对系统打补丁
NEXX仅仅实现了一些超级调用。这些调用是移植linux kernel到NEXX根据需要实现的。为了在虚拟机上运行liunx内核,我们需要对内核打补丁,因为NEXX是一个半虚拟化的管理工具。
我开始深入研究引导顺序和linux内核的其它部分,以此了解它实际是如何工作的。之后,我就可以创建一个新的系统。当时Linux内核的版本是3.1.1。
在NEXX上运行linux系统步骤如下:
1.下载linux源码并解压:
   $ mkdir $HOME/linux-sources
   $ cd $HOME/linux-sources
   $ wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.1.1.tar.xz
   $ tar xvf linux-3.1.1.tar.xz  
2.patch linux内核
 $ wget http://hmarco.org/virtualisation/nexx/linux-3.1.1-nexx.patch
   $ cd linux-3.1.1
   $ patch -p2 < ../linux-3.1.1-nexx.patch
3.  正确配置linux内核
   $ wget http://hmarco.org/virtualisation/nexx/linux-3.1.1-nexx.config
   $ mv linux-3.1.1-nexx.config .config
4. 为了编译可以在arm-x86_64位下linux运行的程序,我们需要gcc-arm-linux-gnueabi。在ubuntu下我们可以使用apt-get install命令来获得这个程序。
 $ sudo apt-get install gcc-arm-linux-gnueabi
5.创建一个简单的initramfs和 输出"Hello world"的初始程序。尽管我们对系统的patch没有完全完成,但是我们patched的linux程序依然可以运行这个初始程序。我们可以通过跟踪init程序来对继续对系统进行打补丁。因此我们使用一个输出"Hello world"的程序来替换init进程。为了实现这一点,我们需要执行下面的命令:
   $ mkdir $HOME/initrd
   $ cd $HOME/initrd
   $ wget http://hmarco.org/virtualisation/nexx/init.c
   $ arm-linux-gnueabi-gcc -static init.c -o init
6.编译patched过的linux内核
 $ cd $HOME/linux-sources/linux-3.1.1
   $ export ARCH=arm
   $ export CROSS_COMPILE=arm-linux-gnueabi-
   $ make vmlinux
7.编译NEXX并测试编译好的内核
 $ cd $HOME/nexx/NEXX-hypervisor
   $ make linux
   $ make test
输出:
 [Loader] PackedMemory used: [0x0]--[0x36C500]
 [Loader] Loading NEXX hypervisor ...
 [Loader] NEXX [0x608000]--[0x60BFF8]
 [Loader] Loading Partitions ...
 [Loader] P1 [0xA00000]--[0xA00298]
 [Loader] P2 [0xB00000]--[0xB00298]
 [Loader] Linux ...
 [Loader] Linux [0xC08000]--[0xF6A484]
 NEXX_MD5(608000 , 16376, hash);
 RAM MD5 [3043D7C239ADCD2BF153B50BA388798]
 [Loader] Starting NEXX at 0x608000...
 
 [NEXX] Starting NEXX Hypervisor ...
 [NEXX] CPU ID:41069265
 [NEXX] CR:90078
 [NEXX] PGT [0x400000]-[0x404000]
 [NEXX] Calling scheduler()
 Run partition id:0
 console [nex2] enabled
 NEX_read_cpuid == 0x41069265
 Linux version 3.1.1 (work@work-pc) (gcc version 4.7.3 (Ubuntu/Linaro 4.7.3-1ubuntu1) )
 CPU: ARM926EJ-S [41069265] revision 5 (ARMv5TEJ), cr=00000000
 CPU: VIVT data cache, VIVT instruction cache
 WARNING !!!!: NOT setup stacks for re-entrant exception handlers
 __atags_pointer -> c0000100
 To execute setup_machine_tags(machine_arch_type(183))
 Machine: Virtualized ARM-Versatile PB
 Memory policy: ECC disabled, Data cache writeback
 Kernel command line1: mem=64M console=tty root=/dev/ram
 Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 16256
 Kernel command line: mem=64M console=tty root=/dev/ram
 PID hash table entries: 256 (order: -2, 1024 bytes)
 Dentry cache hash table entries: 8192 (order: 3, 32768 bytes)
 Inode-cache hash table entries: 4096 (order: 2, 16384 bytes)
 Memory: 64MB = 64MB total
 Memory: 61308k/61308k available, 4228k reserved, 0K highmem
 Virtual kernel memory layout:
     vector  : 0xffff0000 - 0xffff1000   (   4 kB)
     fixmap  : 0xfff00000 - 0xfffe0000   ( 896 kB)
     DMA     : 0xffc00000 - 0xffe00000   (   2 MB)
     vmalloc : 0xc4800000 - 0xd8000000   ( 312 MB)
     lowmem  : 0xc0000000 - 0xc4000000   (  64 MB)
     modules : 0xbf000000 - 0xc0000000   (  16 MB)
       .text : 0xc0008000 - 0xc02f0144   (2977 kB)
       .init : 0xc02f1000 - 0xc0350000   ( 380 kB)
       .data : 0xc0350000 - 0xc036a460   ( 106 kB)
        .bss : 0xc036a484 - 0xc0384100   ( 104 kB)
 start_kernel(): bug: interrupts were enabled *very* early, fixing it
 NR_IRQS:192
 NEX nex_init_irq
 NEX nex_timer_init
 start_kernel(): bug: interrupts were enabled early
 console_init !!!
 
 Console: colour dummy device 80x30
 console [tty0] enabled
 pid_max: default: 32768 minimum: 301
 Mount-cache hash table entries: 512
 NET: Registered protocol family 16
 NEX versatile_pb_init
 bio: create slab <bio-0> at 0
 **** [log punxos]  tty_init ****
 NET: Registered protocol family 2
 IP route cache hash table entries: 1024 (order: 0, 4096 bytes)
 TCP established hash table entries: 2048 (order: 2, 16384 bytes)
 TCP bind hash table entries: 2048 (order: 1, 8192 bytes)
 TCP: Hash tables configured (established 2048 bind 2048)
 TCP reno registered
 UDP hash table entries: 256 (order: 0, 4096 bytes)
 UDP-Lite hash table entries: 256 (order: 0, 4096 bytes)
 NET: Registered protocol family 1
 RPC: Registered named UNIX socket transport module.
 RPC: Registered udp transport module.
 RPC: Registered tcp transport module.
 RPC: Registered tcp NFSv4.1 backchannel transport module.
 NetWinder Floating Point Emulator V0.97 (double precision)
 Installing knfsd (copyright (C) 1996 okir@monad.swb.de).
 JFFS2 version 2.2. (NAND) © 2001-2006 Red Hat, Inc.
 ROMFS MTD (C) 2007 Red Hat, Inc.
 msgmni has been set to 119
 Block layer SCSI generic (bsg) driver version 0.4 loaded (major 254)
 io scheduler noop registered
 io scheduler deadline registered
 io scheduler cfq registered (default)
 brd: module loaded
 mousedev: PS/2 mouse device common for all mice
 TCP cubic registered
 NET: Registered protocol family 17
 VFP support v0.3: implementor 41 architecture 1 part 10 variant 9 rev 0
 Warning: unable to open an initial console.
 [NEX-linux log] Exec ... /init
 sys_access(/init) returned: 0
 
 [NEX-Linux log]
 Ok, we have completed the initial bootup, and
 we're essentially up and running. Get rid of the
 initmem segments and start the user-mode stuff..
 
 [Nex-Linux log] Halt hypervisor => While(1)
 
总结
我从头创建了一个用于ARM架构的概念型虚拟化管理工具。在处理裸机分区这一块需要解决一些问题比如需要一个有效的栈、内存映射、物理内存、建立新的库.....
现在的系统Linux内核补丁没有完成,这将是一个很有挑战性的工作。值得一提的是linux arm下缺乏虚拟化的架构使得工作会更有趣。
总而言之,我成功解决了很多有挑战的工作。所以,我可以自豪的说我完成了我的目标。

原文地址:http://hmarco.org/virtualisation/nexx/NEXX_ARM_hypervisor.html

[培训]科锐软件逆向50期预科班报名即将截止,速来!!! 50期正式班报名火爆招生中!!!

收藏
免费 2
打赏
分享
最新回复 (3)
雪    币: 7076
活跃值: (3478)
能力值: ( LV12,RANK:340 )
在线值:
发帖
回帖
粉丝
bxc 6 2016-11-18 09:44
2
0
感谢分享,ARM虚拟化的中文资料确实不多呢。
雪    币: 124
活跃值: (364)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
topofall 2016-11-18 10:30
3
0
初次翻译,可能有很多不足。。。。。
雪    币: 7877
活跃值: (2376)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
option 2016-11-18 12:22
4
0
感谢分享,虚心学习中。
游客
登录 | 注册 方可回帖
返回