“Qemu”的版本间的差异
Weidongshan(讨论 | 贡献) (→更新QEMU) |
Weidongshan(讨论 | 贡献) |
||
第763行: | 第763行: | ||
<div style="margin-left:0cm;margin-right:0cm;">理解了它的框架之后,添加新的外设并不困难。当然这需要你对外设的原理有清楚的认识。</div> | <div style="margin-left:0cm;margin-right:0cm;">理解了它的框架之后,添加新的外设并不困难。当然这需要你对外设的原理有清楚的认识。</div> | ||
− | <div style="margin-left:0cm;margin-right:0cm;">我们开发QEMU,要做的事情主要有3部分:</div># <span style="color:#ff0000;">'''添加外设'''</span> | + | <div style="margin-left:0cm;margin-right:0cm;">我们开发QEMU,要做的事情主要有3部分:</div> |
+ | # <span style="color:#ff0000;">'''添加外设'''</span> | ||
第813行: | 第814行: | ||
<div style="margin-left:0cm;margin-right:0cm;"></div> | <div style="margin-left:0cm;margin-right:0cm;"></div> | ||
− | == | + | == QEMU下载与编译 == |
− | === | + | === 源码下载 === |
<div style="margin-left:0cm;margin-right:0cm;">官方的QEMU对IMX6ULL的支持还太弱,没有更形象化的GUI,也没有更多的外设。我们对它进行了大量的改进。</div> | <div style="margin-left:0cm;margin-right:0cm;">官方的QEMU对IMX6ULL的支持还太弱,没有更形象化的GUI,也没有更多的外设。我们对它进行了大量的改进。</div> | ||
第832行: | 第833行: | ||
<div style="margin-left:0cm;margin-right:0cm;">你当然可以自行下载。在Ubuntu下,执行如下命令即可下载:</div> | <div style="margin-left:0cm;margin-right:0cm;">你当然可以自行下载。在Ubuntu下,执行如下命令即可下载:</div> | ||
− | + | <syntaxhighlight lang="bash"> | |
$ git clone [https://gitee.com/weidongshan/qemu.git https://gitee.com/weidongshan/qemu.git] | $ git clone [https://gitee.com/weidongshan/qemu.git https://gitee.com/weidongshan/qemu.git] | ||
− | + | </syntaxhighlight> | |
或 | 或 | ||
− | + | <syntaxhighlight lang="bash"> | |
$ git clone [https://github.com/100askTeam/qemu.git https://github.com/100askTeam/qemu.git] | $ git clone [https://github.com/100askTeam/qemu.git https://github.com/100askTeam/qemu.git] | ||
− | + | </syntaxhighlight> | |
<div style="margin-left:0cm;margin-right:0cm;">我们会不断更新QEMU,你下载过QEMU之后,可以进入qemu目录执行下述命令更新代码:</div> | <div style="margin-left:0cm;margin-right:0cm;">我们会不断更新QEMU,你下载过QEMU之后,可以进入qemu目录执行下述命令更新代码:</div> | ||
− | + | <syntaxhighlight lang="bash"> | |
$ git pull origin | $ git pull origin | ||
+ | </syntaxhighlight> | ||
− | + | === 配置、编译、安装 === | |
− | === | ||
<div style="margin-left:0cm;margin-right:0cm;">进入qemu目录,执行如下配置命令:</div> | <div style="margin-left:0cm;margin-right:0cm;">进入qemu目录,执行如下配置命令:</div> | ||
− | + | <syntaxhighlight lang="bash"> | |
./configure --prefix=$PWD/ --target-list="arm-softmmu arm-linux-user" --enable-debug --enable-sdl --enable-kvm --enable-tools --disable-curl | ./configure --prefix=$PWD/ --target-list="arm-softmmu arm-linux-user" --enable-debug --enable-sdl --enable-kvm --enable-tools --disable-curl | ||
− | + | </syntaxhighlight> | |
<div style="margin-left:0cm;margin-right:0cm;">编译、安装命令如下:</div> | <div style="margin-left:0cm;margin-right:0cm;">编译、安装命令如下:</div> | ||
− | + | <syntaxhighlight lang="bash"> | |
$ make | $ make | ||
− | |||
$ make install | $ make install | ||
− | + | </syntaxhighlight> | |
<div style="margin-left:0cm;margin-right:0cm;">如果一切正常,会在qemu源码目录下生成bin子目录,里面存放有各种可执行程序。</div> | <div style="margin-left:0cm;margin-right:0cm;">如果一切正常,会在qemu源码目录下生成bin子目录,里面存放有各种可执行程序。</div> | ||
第878行: | 第878行: | ||
<div style="margin-left:0cm;margin-right:0cm;">错误示例,提示信息如下:</div> | <div style="margin-left:0cm;margin-right:0cm;">错误示例,提示信息如下:</div> | ||
− | + | <syntaxhighlight lang="bash"> | |
ERROR: pixman >= 0.21.8 not present. | ERROR: pixman >= 0.21.8 not present. | ||
− | |||
Please install the pixman devel package. | Please install the pixman devel package. | ||
− | + | </syntaxhighlight> | |
<div style="margin-left:0cm;margin-right:0cm;">解决方法:</div> | <div style="margin-left:0cm;margin-right:0cm;">解决方法:</div> | ||
第889行: | 第888行: | ||
<div style="margin-left:0cm;margin-right:0cm;">执行如下命令:</div> | <div style="margin-left:0cm;margin-right:0cm;">执行如下命令:</div> | ||
− | + | <syntaxhighlight lang="bash"> | |
$ apt-cache search pixman | $ apt-cache search pixman | ||
− | |||
libpixman-1-0 - pixel-manipulation library for X and cairo | libpixman-1-0 - pixel-manipulation library for X and cairo | ||
− | |||
libpixman-1-dev - pixel-manipulation library for X and cairo (development files) | libpixman-1-dev - pixel-manipulation library for X and cairo (development files) | ||
− | + | </syntaxhighlight> | |
<div style="margin-left:0cm;margin-right:0cm;">根据输出信息,需要安装开发包(dev表示开发包): libpixman-1-dev。</div> | <div style="margin-left:0cm;margin-right:0cm;">根据输出信息,需要安装开发包(dev表示开发包): libpixman-1-dev。</div> | ||
第901行: | 第898行: | ||
② 安装开发包: | ② 安装开发包: | ||
− | + | <syntaxhighlight lang="bash"> | |
$ sudo apt-get install libpixman-1-dev | $ sudo apt-get install libpixman-1-dev | ||
− | + | </syntaxhighlight> | |
− | |||
<div style="margin-left:0cm;margin-right:0cm;">可能你的ubuntu中已经安装了某些开发包,下面列出一些必须的包:</div> | <div style="margin-left:0cm;margin-right:0cm;">可能你的ubuntu中已经安装了某些开发包,下面列出一些必须的包:</div> | ||
− | + | <syntaxhighlight lang="bash"> | |
$ sudo apt-get install pkg-config | $ sudo apt-get install pkg-config | ||
− | |||
$ sudo apt-get install libsdl2-dev | $ sudo apt-get install libsdl2-dev | ||
− | |||
$ sudo apt-get install libpixman-1-dev | $ sudo apt-get install libpixman-1-dev | ||
− | + | </syntaxhighlight> | |
<div style="margin-left:0cm;margin-right:0cm;">每次出错后,根据提示信息安装开发包,然后重新配置、编译、安装。 </div> | <div style="margin-left:0cm;margin-right:0cm;">每次出错后,根据提示信息安装开发包,然后重新配置、编译、安装。 </div> | ||
<div style="margin-left:0cm;margin-right:0cm;">如果一切正常,在当前目录下会生成bin子目录, 里面有生成的QEMU程序:</div> | <div style="margin-left:0cm;margin-right:0cm;">如果一切正常,在当前目录下会生成bin子目录, 里面有生成的QEMU程序:</div> | ||
− | + | <syntaxhighlight lang="bash"> | |
qemu-system-arm | qemu-system-arm | ||
+ | </syntaxhighlight> | ||
− | + | === 使用新的qemu-system-arm === | |
− | === | ||
<div style="margin-left:0cm;margin-right:0cm;">将上面编译出来的bin/qemu-system-arm 可执行文件复制到如下目录:</div> | <div style="margin-left:0cm;margin-right:0cm;">将上面编译出来的bin/qemu-system-arm 可执行文件复制到如下目录:</div> | ||
− | + | <syntaxhighlight lang="bash"> | |
ubuntu-18.04_imx6ul_qemu_system/qemu-system-arm/bin | ubuntu-18.04_imx6ul_qemu_system/qemu-system-arm/bin | ||
− | + | </syntaxhighlight> | |
或 | 或 | ||
− | + | <syntaxhighlight lang="bash"> | |
ubuntu-16.04_imx6ul_qemu_system/qemu-system-arm/bin | ubuntu-16.04_imx6ul_qemu_system/qemu-system-arm/bin | ||
− | + | </syntaxhighlight> | |
<div style="margin-left:0cm;margin-right:0cm;">我们也可能添加了更多的GUI显示,这些GUI所用图片位于源码目录的etc子目录下,这些图片也需要复制到如下目录去:</div> | <div style="margin-left:0cm;margin-right:0cm;">我们也可能添加了更多的GUI显示,这些GUI所用图片位于源码目录的etc子目录下,这些图片也需要复制到如下目录去:</div> | ||
− | + | <syntaxhighlight lang="bash"> | |
ubuntu-18.04_imx6ul_qemu_system/qemu-system-arm/etc | ubuntu-18.04_imx6ul_qemu_system/qemu-system-arm/etc | ||
− | + | </syntaxhighlight> | |
或 | 或 | ||
− | + | <syntaxhighlight lang="bash"> | |
ubuntu-16.04_imx6ul_qemu_system/qemu-system-arm/etc | ubuntu-16.04_imx6ul_qemu_system/qemu-system-arm/etc | ||
− | + | </syntaxhighlight> | |
<div style="margin-left:0cm;margin-right:0cm;">然后就可以执行 qemu-imx6ul-gui.sh 或 qemu-imx6ul-nogui.sh来使用您编译出来的QEMU了。</div> | <div style="margin-left:0cm;margin-right:0cm;">然后就可以执行 qemu-imx6ul-gui.sh 或 qemu-imx6ul-nogui.sh来使用您编译出来的QEMU了。</div> | ||
第950行: | 第944行: | ||
<div style="margin-left:0cm;margin-right:0cm;"></div> | <div style="margin-left:0cm;margin-right:0cm;"></div> | ||
− | === | + | === QEMU源码目录 === |
<div style="margin-left:0cm;margin-right:0cm;">我们只罗列出涉及的少许文件,一般来说一个.c文件会有一个.h文件,它们的目录类似。</div> | <div style="margin-left:0cm;margin-right:0cm;">我们只罗列出涉及的少许文件,一般来说一个.c文件会有一个.h文件,它们的目录类似。</div> | ||
第987行: | 第981行: | ||
<div style="margin-left:0cm;margin-right:0cm;"></div> | <div style="margin-left:0cm;margin-right:0cm;"></div> | ||
− | == | + | == QEMU的设备创建过程 == |
− | === | + | === 重要结构体TypeInfo === |
<div style="margin-left:0cm;margin-right:0cm;">一个板子上有很多硬件:IMX6ULL、LED、按键、LCD、触摸屏、网卡等等。</div> | <div style="margin-left:0cm;margin-right:0cm;">一个板子上有很多硬件:IMX6ULL、LED、按键、LCD、触摸屏、网卡等等。</div> | ||
第1,042行: | 第1,036行: | ||
<div style="margin-left:0cm;margin-right:0cm;">对于上述的type_init(imx_gpio_register_types),它的宏展开如下:</div> | <div style="margin-left:0cm;margin-right:0cm;">对于上述的type_init(imx_gpio_register_types),它的宏展开如下:</div> | ||
− | + | <syntaxhighlight lang="bash"> | |
static void __attribute__((constructor)) do_qemu_init_imx_gpio_register_types (void) \ | static void __attribute__((constructor)) do_qemu_init_imx_gpio_register_types (void) \ | ||
− | |||
{ \ | { \ | ||
− | |||
register_module_init(imx_gpio_register_types, MODULE_INIT_QOM); \ | register_module_init(imx_gpio_register_types, MODULE_INIT_QOM); \ | ||
− | |||
} | } | ||
− | + | </syntaxhighlight> | |
<div style="margin-left:0cm;margin-right:0cm;">这就得到了一个属性为“constructor”的函数do_qemu_init_imx_gpio_register_types,这个函数将在main函数之前被调用,它调用了register_module_init。</div> | <div style="margin-left:0cm;margin-right:0cm;">这就得到了一个属性为“constructor”的函数do_qemu_init_imx_gpio_register_types,这个函数将在main函数之前被调用,它调用了register_module_init。</div> | ||
第1,061行: | 第1,052行: | ||
<div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:图片 61.png|top]]</div> | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:图片 61.png|top]]</div> | ||
− | === | + | === 生成TypeImpl === |
<div style="margin-left:0cm;margin-right:0cm;">从名字上讲,TypeImpl就是TypeInfo的实现,就是使用TypeInfo的信息构造一个TypeImpl结构体。</div> | <div style="margin-left:0cm;margin-right:0cm;">从名字上讲,TypeImpl就是TypeInfo的实现,就是使用TypeInfo的信息构造一个TypeImpl结构体。</div> | ||
<div style="margin-left:0cm;margin-right:0cm;">在init_type_list[MODULE_INIT_QOM]链表中,有一系列的ModuleEntry结构体,每个ModuleEntry结构体中有一个init函数,它指向某个xxx_register_types,比如:</div> | <div style="margin-left:0cm;margin-right:0cm;">在init_type_list[MODULE_INIT_QOM]链表中,有一系列的ModuleEntry结构体,每个ModuleEntry结构体中有一个init函数,它指向某个xxx_register_types,比如:</div> | ||
− | + | <syntaxhighlight lang="bash"> | |
a15mp_register_types | a15mp_register_types | ||
− | |||
ask100fb_register_types | ask100fb_register_types | ||
− | + | </syntaxhighlight> | |
<div style="margin-left:0cm;margin-right:0cm;">这些ModuleEntry结构体中的init函数何时被调用?</div> | <div style="margin-left:0cm;margin-right:0cm;">这些ModuleEntry结构体中的init函数何时被调用?</div> | ||
<div style="margin-left:0cm;margin-right:0cm;">vl.c:</div> | <div style="margin-left:0cm;margin-right:0cm;">vl.c:</div> | ||
− | + | <syntaxhighlight lang="bash"> | |
main | main | ||
− | + | module_call_init(MODULE_INIT_QOM); | |
− | + | QTAILQ_FOREACH(e, l, node) { | |
− | + | e->init(); | |
− | + | } | |
− | + | </syntaxhighlight> | |
− | |||
− | |||
− | |||
− | |||
<div style="margin-left:0cm;margin-right:0cm;">这些xxx_register_types执行后,又得到了什么?</div> | <div style="margin-left:0cm;margin-right:0cm;">这些xxx_register_types执行后,又得到了什么?</div> | ||
第1,104行: | 第1,090行: | ||
<div style="margin-left:0cm;margin-right:0cm;"></div> | <div style="margin-left:0cm;margin-right:0cm;"></div> | ||
− | === | + | === 使用TypeImpl:实例化 === |
<div style="margin-left:0cm;margin-right:0cm;">在程序的type_table链表中,有很多TypeImpl结构体,比如CPU、GPIO、LED、LCD对应的TypeImpl结构体。</div> | <div style="margin-left:0cm;margin-right:0cm;">在程序的type_table链表中,有很多TypeImpl结构体,比如CPU、GPIO、LED、LCD对应的TypeImpl结构体。</div> | ||
第1,222行: | 第1,208行: | ||
<div style="margin-left:0cm;margin-right:0cm;"></div> | <div style="margin-left:0cm;margin-right:0cm;"></div> | ||
− | === | + | === 实例化方法1:qdev_create/qdev_init_nofail === |
<div style="margin-left:0cm;margin-right:0cm;">这2个函数是成对出现的,以hw/display/100ask_qemu_fb.c为例:</div> | <div style="margin-left:0cm;margin-right:0cm;">这2个函数是成对出现的,以hw/display/100ask_qemu_fb.c为例:</div> | ||
第1,233行: | 第1,219行: | ||
<div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:图片 60.png|top]]</div> | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:图片 60.png|top]]</div> | ||
− | ==== | + | ==== qdev_create分析 ==== |
① 第2个参数是name,会被用来找到对应的TypeInfo结构体 | ① 第2个参数是name,会被用来找到对应的TypeInfo结构体 | ||
第1,260行: | 第1,246行: | ||
<div style="margin-left:0.635cm;margin-right:0cm;"></div> | <div style="margin-left:0.635cm;margin-right:0cm;"></div> | ||
− | ==== | + | ==== qdev_init_nofail分析 ==== |
<div style="margin-left:0.63cm;margin-right:0cm;">qdev_init_nofail做的事情很简单:</div> | <div style="margin-left:0.63cm;margin-right:0cm;">qdev_init_nofail做的事情很简单:</div> | ||
第1,269行: | 第1,255行: | ||
− | ==== | + | ==== 总结:怎么创建设备 ==== |
<div style="margin-left:0.63cm;margin-right:0cm;">怎么定义一个设备?如下图:</div> | <div style="margin-left:0.63cm;margin-right:0cm;">怎么定义一个设备?如下图:</div> | ||
第1,312行: | 第1,298行: | ||
− | === | + | === 实例化方法2:object_initialize_child/object_property_set_bool === |
<div style="margin-left:0cm;margin-right:0cm;">参考hw/arm/fsl-imx6ul.c,里面大量的成对代码,比如:</div> | <div style="margin-left:0cm;margin-right:0cm;">参考hw/arm/fsl-imx6ul.c,里面大量的成对代码,比如:</div> | ||
第1,323行: | 第1,309行: | ||
[[Image:图片 69.png|top]] | [[Image:图片 69.png|top]] | ||
− | ==== | + | ==== object_initialize_child分析 ==== |
<div style="margin-left:0cm;margin-right:0cm;">该函数的第5个参数是type,表示type name,它会被用来找到对应的TypeImpl。</div> | <div style="margin-left:0cm;margin-right:0cm;">该函数的第5个参数是type,表示type name,它会被用来找到对应的TypeImpl。</div> | ||
第1,333行: | 第1,319行: | ||
<div style="margin-left:0cm;margin-right:0cm;">最后调用TypeImpl中的instance_init函数。</div> | <div style="margin-left:0cm;margin-right:0cm;">最后调用TypeImpl中的instance_init函数。</div> | ||
− | ==== | + | ==== object_property_set_bool分析 ==== |
<div style="margin-left:0.63cm;margin-right:0cm;">比如:</div> | <div style="margin-left:0.63cm;margin-right:0cm;">比如:</div> | ||
第1,342行: | 第1,328行: | ||
− | ==== | + | ==== 总结:怎么创建设备 ==== |
<div style="margin-left:0cm;margin-right:0cm;">怎么定义一个设备?如下图所示:</div> | <div style="margin-left:0cm;margin-right:0cm;">怎么定义一个设备?如下图所示:</div> | ||
第1,392行: | 第1,378行: | ||
<div style="margin-left:0cm;margin-right:0cm;"></div> | <div style="margin-left:0cm;margin-right:0cm;"></div> | ||
− | === | + | === 怎么创建设备 === |
<div style="margin-left:0cm;margin-right:0cm;">其实在2.4.3、2.5.3已经整理出来了,在这里只是再次总结一下。</div> | <div style="margin-left:0cm;margin-right:0cm;">其实在2.4.3、2.5.3已经整理出来了,在这里只是再次总结一下。</div> | ||
− | ==== | + | ==== 设置TypeInfo结构体 ==== |
<div style="margin-left:0cm;margin-right:0cm;">比如LCD:</div> | <div style="margin-left:0cm;margin-right:0cm;">比如LCD:</div> | ||
第1,407行: | 第1,393行: | ||
<div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:图片 73.png|top]]</div> | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:图片 73.png|top]]</div> | ||
− | ==== | + | ==== 注册TypeInfo结构体 ==== |
<div style="margin-left:0cm;margin-right:0cm;">比如:</div> | <div style="margin-left:0cm;margin-right:0cm;">比如:</div> | ||
第1,413行: | 第1,399行: | ||
<div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:图片 74.png|top]]</div> | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:图片 74.png|top]]</div> | ||
− | ==== | + | ==== 使用TypeInfo创建设备/设置设备的realized属性为true ==== |
<div style="margin-left:0cm;margin-right:0cm;">这有2种方法,前面介绍过:</div> | <div style="margin-left:0cm;margin-right:0cm;">这有2种方法,前面介绍过:</div> |
2019年11月25日 (一) 12:02的版本
目录
- 1 QEMU使用手册
-
2 QEMU开发手册
- 2.1 QEMU下载与编译
- 2.2 QEMU的设备创建过程
- 2.3 3. QEMU的设备模拟
- 2.4 4. 模拟LED
- 2.5 5. 模拟LCD
- 2.6 6. QEMU的输出:GUI系统
- 2.7 7. QEMU的输入:鼠标事件
- 2.8 8. 使用中断
- 2.9 9. 模拟按键
- 2.10 10. QEMU启动过程
- 2.11 11. 调试
QEMU使用手册
QEMU简介
还有很多模拟器,比如VMWare、Virtual Box等。但是VMWare、Virtual Box只能模拟x86、AMD64/Intel64等PC系统;
用户模式(User Mode)
$ gcc -o hello hello.c -static
$ ./hello // 这个hello程序是使用gcc给PC机编译的,可以直接运行
Hello, world!
$ arm-linux-gnueabihf-gcc -o hello hello.c -static // 它是给ARM板子编译的
$ ./hello // 所以无法在PC上运行
bash: ./hello: cannot execute binary file: Exec format error
$ ./qemu-arm ./hello // 我们可以用QEMU在PC上运行它
Hello, world!
- 你没有安装ARM交叉编译工具链
- 你没有安装QEMU
系统模式(System Mode)
我们做的改进
*
- 模拟网卡
- 模拟LCD显示功能
- 模拟led灯、按键
- 模拟at24cxx i2c存储芯片,直接可以通过用户态操作看到效果
- 增加逻辑分析仪显示功能
- 后续会逐渐增加更多的模拟硬件模块
QEMU快速使用
准备工作
- 一台可以上网的windows电脑
- 一个可以正常使用Ubuntu虚拟机VMWare系统,也要能上网
$ sudo apt-get update
$ sudo apt-get install qemu qemu-kvm libvirt-bin bridge-utils virt-manager
获取镜像
① ubuntu-18.04开发环境下qemu imx6ul系统镜像下载地址:
② ubuntu-16.04开发环境下qemu imx6ul系统镜像下载地址:
① ubuntu-16.04解压操作步骤
$ tar -xvf weidongshan-ubuntu-16.04_imx6ul_qemu_system-release.tgz
② ubuntu-18.04解压操作步骤
$ tar -xvf weidongshan-ubuntu-18.04_imx6ul_qemu_system-release.tgz
运行QEMU系统
首次运行需要安装SDL环境以及解压文件系统镜像:
$ ./install_sdl.sh // 提示输入用户密码,等待安装完成
运行带GUI的imx6ul模拟器
$ ./qemu-imx6ul-gui.sh // 启动后,登录名是root,无需密码
$ ./qemu-imx6ul-gui.sh fire // 启动后,登录名是root,无需密码
$ ./qemu-imx6ul-gui.sh atk // 启动后,登录名是root,无需密码
运行不带GUI的imx6ul模拟器
$ ./qemu-imx6ul-nogui.sh // 启动后,登录名是root,无需密码
参数讲解
-M mcimx6ul-evk
指定需要模拟的单板型号。
-m 512M
指定板子的内存大小。
-kernel zImage
指定使用的内核镜像文件。
-dtb 100ask_imx6ul_qemu.dtb
指定使用的设备树文件。
-display sdl
指定使用那种图形显示输出。
-serial mon:stdio
指定串口信息输出。
-drive file=rootfs.img,format=raw,id=mysdcard
名为mysdcard的drive,源为rootfs.img
-device sd-card,drive=mysdcard
添加一个sd-card设备,内容来自名为mysdcard的drive
-append “console=ttymxc0,115200 rootfstype=ext4 root=/dev/mmcblk1 rw rootwait init=/sbin/init loglevel=8”
指定内核的命令行参数
-nic user
指定网卡为user mode
百问网imx6ull-qemu开发板资料下载
QEMU操作示例
$ ./qemu-imx6ul-gui.sh // 启动后,登录名是root,无需密码
操作设备管理器
操作LCD
[root@qemu_imx6ul:~]# fb-test
或
[root@qemu_imx6ul:~]# myfb-test /dev/fb0
操作LED
[root@qemu_imx6ul:~]# cd led_driver_qemu/
[root@qemu_imx6ul:~/led_driver_qemu]# insmod 100ask_led.ko
[root@qemu_imx6ul:~/led_driver_qemu]# ./ledtest /dev/100ask_led0 off
[root@qemu_imx6ul:~/led_driver_qemu]# ./ledtest /dev/100ask_led0 on
使用按键来控制LED
[root@qemu_imx6ul:~]# cd led_driver_qemu/
[root@qemu_imx6ul:~/led_driver_qemu]# insmod 100ask_led.ko
[root@qemu_imx6ul:~/led_driver_qemu]# cd ../button_driver_qemu/
[root@qemu_imx6ul:~/button_driver_qemu]# insmod button_drv.ko
[root@qemu_imx6ul:~/button_driver_qemu]# insmod board_100ask_qemu_imx6u
[root@qemu_imx6ul:~/button_driver_qemu]# ./button_led_test
读写I2C EEPROM AT24C02
// 0x50是AT24C02的I2C设备地址
[root@qemu_imx6ul:~]# i2c_usr_test /dev/i2c-0 0x50 r 0 // 读地址0
data: , 0, 0x00
[root@qemu_imx6ul:~]# i2c_usr_test /dev/i2c-0 0x50 w 1 0x58 // 写地址1,写入0x58
使用QEMU进行嵌入式Linux开发
获取源码
设置git邮箱账号和用户名
book@100ask:~$ git config --global user.email "you@example.com"
book@100ask:~$ git config --global user.name "Your Name"
下载源码
book@100ask:~$ git clone https://git.dev.tencent.com/codebug8/repo.git
book@100ask:~$ mkdir -p 100ask_imx6ull-qemu && cd 100ask_imx6ull-qemu
book@100ask:~/100ask_imx6ull-qemu$ ../repo/repo init -u https://dev.tencent.com/u/weidongshan/p/manifests/git -b linux-sdk -m imx6ull/100ask-imx6ull_qemu_release_v1.0.xml --no-repo-verify
book@100ask:~/100ask_imx6ull-qemu$ ../repo/repo sync -j4
设置工具链
永久生效
book@100ask:~$ vi ~/.bashrc
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-
export PATH=$PATH:/home/book/100ask_imx6ull-qemu/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/bin
临时生效
book@100ask:~$ export PATH=$PATH:/home/book/100ask_imx6ull-qemu/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/bin
book@100ask:~$ export ARCH=arm
book@100ask:~$ export CROSS_COMPILE=arm-linux-gnueabihf-
手动指定
book@100ask:~$ export PATH=$PATH:/home/book/100ask_imx6ull-qemu/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/bin
book@100ask:~$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
编译内核及设备树
book@100ask:~/100ask_imx6ull-qemu$ cd linux-4.9.88
book@100ask:~/100ask_imx6ull-qemu/linux-4.9.88$ make mrproper
book@100ask:~/100ask_imx6ull-qemu/linux-4.9.88$ make 100ask_imx6ul_qemu_defconfig
book@100ask:~/100ask_imx6ull-qemu/linux-4.9.88$ make zImage -jN //编译zImage 内核镜像,其中N参数可以根据CPU个数,来加速编译系统。
book@100ask:~/100ask_imx6ull-qemu/linux-4.9.88$ make dtbs //编译设备树文件
arch/arm/boot/zImage // 内核
arch/arm/boot/dts/100ask_imx6ul_qemu.dtb // 设备树
修改文件系统
sudo mount -o loop rootfs.img /mnt
sudo umount /mnt
启动模拟器后使用NFS
$ ./qemu-imx6ul-gui.sh // 启动后,登录名是root,无需密码
在Ubuntu上安装、配置NFS服务
sudo apt-get install nfs-kernel-server
/home/book *(rw,nohide,insecure,no_subtree_check,async,no_root_squash)
/work *(rw,nohide,insecure,no_subtree_check,async,no_root_squash)
sudo /etc/init.d/nfs-kernel-server restart
sudo mount -t nfs -o nolock,vers=3 127.0.0.1:/home/book /mnt
ls /mnt
开发板获取IP地址
[root@qemu_imx6ul:~]# ifconfig eth0 10.0.2.15
挂载主机nfs目录
[root@qemu_imx6ul:~]# mount -t nfs -o nolock,vers=3 10.0.2.2:/home/book/nfs_rootfs /mnt
更新QEMU
随着我们课程的陆续发布,我们也会给QEMU添加更多的功能。
下载最新的release包
① ubuntu-18.04开发环境下qemu imx6ul系统镜像下载地址:
② ubuntu-16.04开发环境下qemu imx6ul系统镜像下载地址:
下载最新的qemu-system-arm可执行程序及配置文件
https://dev.tencent.com/u/weidongshan/p/ubuntu-16.04_imx6ul_qemu_system/git
https://dev.tencent.com/u/weidongshan/p/ubuntu-18.04_imx6ul_qemu_system/git
下载最新的qemu源码并编译
QEMU开发手册
- 添加外设
- 添加外设的GUI
- 在虚拟开发板上开发测试程序
QEMU下载与编译
源码下载
$ git clone [https://gitee.com/weidongshan/qemu.git https://gitee.com/weidongshan/qemu.git]
或
$ git clone [https://github.com/100askTeam/qemu.git https://github.com/100askTeam/qemu.git]
$ git pull origin
配置、编译、安装
./configure --prefix=$PWD/ --target-list="arm-softmmu arm-linux-user" --enable-debug --enable-sdl --enable-kvm --enable-tools --disable-curl
$ make
$ make install
ERROR: pixman >= 0.21.8 not present.
Please install the pixman devel package.
① 确定库的名称:
$ apt-cache search pixman
libpixman-1-0 - pixel-manipulation library for X and cairo
libpixman-1-dev - pixel-manipulation library for X and cairo (development files)
② 安装开发包:
$ sudo apt-get install libpixman-1-dev
$ sudo apt-get install pkg-config
$ sudo apt-get install libsdl2-dev
$ sudo apt-get install libpixman-1-dev
qemu-system-arm
使用新的qemu-system-arm
ubuntu-18.04_imx6ul_qemu_system/qemu-system-arm/bin
或
ubuntu-16.04_imx6ul_qemu_system/qemu-system-arm/bin
ubuntu-18.04_imx6ul_qemu_system/qemu-system-arm/etc
或
ubuntu-16.04_imx6ul_qemu_system/qemu-system-arm/etc
QEMU源码目录
QEMU的设备创建过程
重要结构体TypeInfo
static void __attribute__((constructor)) do_qemu_init_imx_gpio_register_types (void) \
{ \
register_module_init(imx_gpio_register_types, MODULE_INIT_QOM); \
}
生成TypeImpl
a15mp_register_types
ask100fb_register_types
main
module_call_init(MODULE_INIT_QOM);
QTAILQ_FOREACH(e, l, node) {
e->init();
}
① 分配一个TypeImpl结构体,使用TypeInfo来设置它:
② 把TypeImpl放入链表:type_table
使用TypeImpl:实例化
① 分配:
② 设置:
① qdev_create/qdev_init_nofail
② sysbus_init_child_obj/object_property_set_bool
实例化方法1:qdev_create/qdev_init_nofail
qdev_create分析
① 第2个参数是name,会被用来找到对应的TypeInfo结构体
② 分配instance_size大小的内存,即分配ASK100FbState结构体,这用来表示LCD
③ 调用TypeInfo结构体中的class_init函数
④ 调用TypeInfo结构体中的instance_init函数
qdev_init_nofail分析
总结:怎么创建设备
① 先定义一个TypeInfo结构体
② 注册这个TypeInfo结构体:
③ 使用type_init,把ask100fb_register_types函数放入链表中
④ 调用qdev_create创建设备,这会传入type name
⑤ 调用qdev_init_nofail设置设备的状态为realized,这会导致类别的realize函数被调用。
① TypeInfo中的class_init:它会设置dc->realize = 某个函数
② TypeInfo中instance_size大小的对象被malloc
③ TypeInfo中的instance_init函数被调用,它被用来初始化步骤②中malloc出来的结构体
④ dc->realize被调用
实例化方法2:object_initialize_child/object_property_set_bool
object_initialize_child分析
object_property_set_bool分析
总结:怎么创建设备
① 先定义一个TypeInfo结构体
② 注册这个TypeInfo结构体:
③ 使用type_init,把a15mp_register_types函数放入链表中
④ 调用object_initialize_child创建设备,这会传入type name
⑤ 调用object_property_set_bool设置设备的状态为realized,这会导致类别的realize函数被调用。
怎么创建设备
使用TypeInfo创建设备/设置设备的realized属性为true
qdev_create/qdev_init_nofail
object_initialize_child/object_property_set_bool
3. QEMU的设备模拟
3.1 QEMU模拟外设的原理
① CPU读某个地址时,QEMU模拟外设的行为,把数据返回给CPU
② CPU写某个地址时,QEMU获得数据,用来模拟外设的行为。
① 写LCD控制器,根据外接的LCD设置参数,比如分辨率、BPP、各种时序
② 从FrameBuffer中不断获得数据发给LCD,在LCD上显示出来。
① 写LCD控制器的相关寄存器
② 分配FrameBuffer,写FrameBuffer
① 记录驱动程序写寄存器的值,解析出分辨率等信息
② 记录FrameBuffer的地址,并持续不断地从中得到图像数据并显示出来
① 设置LCD控制器时:
qemu_a1a2_read
qemu_a1a2_write
② 写FrameBuffer时:
3.2 给某段地址提供读写函数
3.2.1 memory_region_init_io/memory_region_add_subregion
4. 模拟LED
4.1 主要函数
4.2 添加一段内存
IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3
5. 模拟LCD
common-obj-$(CONFIG_FSL_IMX6UL) += 100ask_qemu_fb.o
5.1 在Linux上编写LCD驱动程序
① 对于LCD控制器,只需要操作4个寄存器:
② 对于FrameBuffer:
5.3 重要函数分析
6. QEMU的输出:GUI系统
6.1 创建GUI Console
7. QEMU的输入:鼠标事件
common-obj-$(CONFIG_FSL_IMX6UL) += button_ui.o
7.3 输入事件处理流程
sdl2_2d_refresh
7.4 QEMU捕获的输入事件,可以作为ABS也可以作为REL事件上传
8. 使用中断
8.1 外设发出哪一个中断?
8.8.1 调用sysbus_init_irq初始化qemu_irq
① 它会给设备dev添加一个属性prop,prop的名字是“sysbus-irq[0]”或“sysbus-irq[1]”
② 会给这个prop添加一个link,link到&s->irq[0]或&s->irq[1]
8.8.2 调用sysbus_connect_irq连接中断
qdev_get_gpio_in(DEVICE(&s->a7mpcore), FSL_IMX6UL_I2Cn_IRQ[i])
8.2 中断触发
发出中断:
清除中断:
① 用户按下按键后,使用“qemu_set_irq(irq, 1)”发出中断
② 客户机的程序处理完中断后,它会写ISR寄存器来清除中断:
notify_imx_gpio_change
qemu_set_irq(s->irq[0], 1);
imx_gpio_write
9. 模拟按键
9.3 更新按键图片的同时
10. QEMU启动过程
10.1 各个模块的注册
#define type_init(function) module_init(function, MODULE_INIT_QOM)
#define module_init(function, type) \
static void __attribute__((constructor)) do_qemu_init_ ## function(void) \
{ \
register_dso_module_init(function, type); \
}
10.2 各个模块的初始化
main
① 分配一个TypeImpl结构体,使用TypeInfo来设置它:
② 把TypeImpl放入链表:type_table
10.5 CPU的初始化
10.6 在system memory中添加内存
11. 调试
11.1 要调试,运行gdb程序之前,必须先进入源码目录
11.2 调试QEMU本身
gdb --args /home/book/mywork/qemu/qemu_git/qemu/bin/qemu-system-arm -M \
mcimx6ul-evk -m 512M -kernel /home/book/nfs_rootfs/zImage \
-dtb /home/book/nfs_rootfs/mynet.dtb -serial stdio \
-drive file=/home/book/mywork/imx6ull_test_image/buildroot_rootfs.img,format=raw,id=mysdcard -device sd-card,drive=mysdcard \
-append "console=ttymxc0,115200 console=tty1 rootfstype=ext4 root=/dev/mmcblk1 rw rootwait init=/sbin/init loglevel=8" \
-nic user
11.3 调试之前就运行的QEMU
① 首先确定qemu-system-arm进程的PID
ps -A | grep qemu
② 在QEMU源码目录下执行如下命令:
sudo gdb -p 9527
11.4 调试客户机上的Linux内核
11.4.1 首先运行qemu-system-arm
gdb --args /home/book/mywork/qemu/qemu_git/qemu/bin/qemu-system-arm -M \
mcimx6ul-evk -m 512M -kernel /home/book/nfs_rootfs/zImage \
-dtb /home/book/nfs_rootfs/mynet.dtb -serial stdio \
-drive file=/home/book/mywork/imx6ull_test_image/buildroot_rootfs.img,format=raw,id=mysdcard -device sd-card,drive=mysdcard \
-append "console=ttymxc0,115200 console=tty1 rootfstype=ext4 root=/dev/mmcblk1 rw rootwait init=/sbin/init loglevel=8" \
-nic user -s -S