“Qemu”的版本间的差异
Weidongshan(讨论 | 贡献) |
Weidongshan(讨论 | 贡献) |
||
第345行: | 第345行: | ||
<div style="margin-left:0cm;margin-right:0cm;">它会弹出一个开发板的界面,并且运行该开发板的Linux系统,你可以在终端中操作该开发板:</div> | <div style="margin-left:0cm;margin-right:0cm;">它会弹出一个开发板的界面,并且运行该开发板的Linux系统,你可以在终端中操作该开发板:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_001.png|top]]</div> |
<div style="margin-left:0cm;margin-right:0cm;"><span style="color:#ff0000;">注意</span>:当你的鼠标点击QEMU的GUI界面时,鼠标将无法移出这个GUI界面。这时可以通过快捷键“Ctrl+Alt+g”把鼠标从GUI界面中退出来。</div> | <div style="margin-left:0cm;margin-right:0cm;"><span style="color:#ff0000;">注意</span>:当你的鼠标点击QEMU的GUI界面时,鼠标将无法移出这个GUI界面。这时可以通过快捷键“Ctrl+Alt+g”把鼠标从GUI界面中退出来。</div> | ||
第355行: | 第355行: | ||
<div style="margin-left:0cm;margin-right:0cm;">所以我们实现了一个“设备管理”,如下所示。可以点击它上面的某个按钮,显示或隐藏某个外设的GUI界面。</div> | <div style="margin-left:0cm;margin-right:0cm;">所以我们实现了一个“设备管理”,如下所示。可以点击它上面的某个按钮,显示或隐藏某个外设的GUI界面。</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_002.png|top]]</div> |
第381行: | 第381行: | ||
<div style="margin-left:0cm;margin-right:0cm;">效果如下:</div> | <div style="margin-left:0cm;margin-right:0cm;">效果如下:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_003.png|top]]</div> |
第398行: | 第398行: | ||
<div style="margin-left:0cm;margin-right:0cm;">效果如下:</div> | <div style="margin-left:0cm;margin-right:0cm;">效果如下:</div> | ||
− | <div style="text-align:center;">[[Image: | + | <div style="text-align:center;">[[Image:100ask_imx6ull_qemu_004.png|top]]</div> |
==== 使用按键来控制LED ==== | ==== 使用按键来控制LED ==== | ||
第416行: | 第416行: | ||
<div style="margin-left:0cm;margin-right:0cm;">效果如下图(只实现了左边的2个按键,右边的2个按键留待以后实现其他目的):</div> | <div style="margin-left:0cm;margin-right:0cm;">效果如下图(只实现了左边的2个按键,右边的2个按键留待以后实现其他目的):</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_005.png|top]]</div> |
第457行: | 第457行: | ||
<div style="margin-left:0cm;margin-right:0cm;">效果如下图:</div> | <div style="margin-left:0cm;margin-right:0cm;">效果如下图:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_006.png|top]]</div> |
第536行: | 第536行: | ||
<div style="margin-left:0cm;margin-right:0cm;">如果一切正常,你在/home/book目录下创建了一个100ask_imx6ull-qemu目录,里有如下内容:</div> | <div style="margin-left:0cm;margin-right:0cm;">如果一切正常,你在/home/book目录下创建了一个100ask_imx6ull-qemu目录,里有如下内容:</div> | ||
− | <div style="margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_007.png|top]]</div> |
第617行: | 第617行: | ||
<div style="margin-left:0cm;margin-right:0cm;">一般位于imx6ul-system-image目录下:</div> | <div style="margin-left:0cm;margin-right:0cm;">一般位于imx6ul-system-image目录下:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_008.png|top]]</div> |
第624行: | 第624行: | ||
<div style="margin-left:0cm;margin-right:0cm;">安装好我们提供的QEMU后,你可以得到一个imx6ul-system-image目录,里面有名为rootfs.img的文件,它就是根文件系统:</div> | <div style="margin-left:0cm;margin-right:0cm;">安装好我们提供的QEMU后,你可以得到一个imx6ul-system-image目录,里面有名为rootfs.img的文件,它就是根文件系统:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_009.png|top]]</div> |
<div style="margin-left:0cm;margin-right:0cm;">你可以在Ubuntu下直接修改rootfs.img,不过要先挂载,执行以下命令:</div> | <div style="margin-left:0cm;margin-right:0cm;">你可以在Ubuntu下直接修改rootfs.img,不过要先挂载,执行以下命令:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_010.png|top]]</div> |
<div style="margin-left:0cm;margin-right:0cm;">主要命令就是:</div> | <div style="margin-left:0cm;margin-right:0cm;">主要命令就是:</div> | ||
第731行: | 第731行: | ||
<div style="margin-left:0cm;margin-right:0cm;">以ubuntu 18.04为例,进入下图所示的bin、etc目录:</div> | <div style="margin-left:0cm;margin-right:0cm;">以ubuntu 18.04为例,进入下图所示的bin、etc目录:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_011.png|top]]</div> |
<div style="margin-left:0cm;margin-right:0cm;">对于bin目录,只需要下载其中的qemu-sysmte-arm;对于etc目录,里面所有的bmp文件都要下载。</div> | <div style="margin-left:0cm;margin-right:0cm;">对于bin目录,只需要下载其中的qemu-sysmte-arm;对于etc目录,里面所有的bmp文件都要下载。</div> | ||
第829行: | 第829行: | ||
<div style="margin-left:0cm;margin-right:0cm;">实际上,如果你之前根据《使用手册:3. 使用QEMU进行嵌入式Linux开发》里的说明使用repo下载过源码,那么在下图中的qemu目录就是源码了:</div> | <div style="margin-left:0cm;margin-right:0cm;">实际上,如果你之前根据《使用手册:3. 使用QEMU进行嵌入式Linux开发》里的说明使用repo下载过源码,那么在下图中的qemu目录就是源码了:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_012.png|top]]</div> |
第950行: | 第950行: | ||
<div style="margin-left:0cm;margin-right:0cm;">比如hw/gpio/imx_gpio.c对应的头文件为include/hw/gpio/imx_gpio.h</div> | <div style="margin-left:0cm;margin-right:0cm;">比如hw/gpio/imx_gpio.c对应的头文件为include/hw/gpio/imx_gpio.h</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_013.png|top]]</div> |
第996行: | 第996行: | ||
<div style="margin-left:0cm;margin-right:0cm;">比如对于CPU,有这样的结构体(hw/cpu/a15mpcore.c):</div> | <div style="margin-left:0cm;margin-right:0cm;">比如对于CPU,有这样的结构体(hw/cpu/a15mpcore.c):</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_014.png|top]]</div> |
<div style="margin-left:0cm;margin-right:0cm;">对于LCD,有这样的结构体(hw/display/100ask_qemu_fb.c):</div> | <div style="margin-left:0cm;margin-right:0cm;">对于LCD,有这样的结构体(hw/display/100ask_qemu_fb.c):</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_015.png|top]]</div> |
<div style="margin-left:0cm;margin-right:0cm;">对于GPIO,也有这样的结构体(hw/gpio/imx_gpio.c):</div> | <div style="margin-left:0cm;margin-right:0cm;">对于GPIO,也有这样的结构体(hw/gpio/imx_gpio.c):</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_016.png|top]]</div> |
第1,026行: | 第1,026行: | ||
<div style="margin-left:0cm;margin-right:0cm;">怎么注册这些TypeInfo结构体呢?不需要我们去调用注册函数,以GPIO为例,在hw/gpio/imx_gpio.c中有如下代码:</div> | <div style="margin-left:0cm;margin-right:0cm;">怎么注册这些TypeInfo结构体呢?不需要我们去调用注册函数,以GPIO为例,在hw/gpio/imx_gpio.c中有如下代码:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_017.png|top]]</div> |
<div style="margin-left:0cm;margin-right:0cm;">关键点在于type_init,这个宏在include/qemu/module.h中定义:</div> | <div style="margin-left:0cm;margin-right:0cm;">关键点在于type_init,这个宏在include/qemu/module.h中定义:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_018.png|top]]</div> |
<div style="margin-left:0cm;margin-right:0cm;">对于属性为“constructor”函数,它在main函数之前被调用。</div> | <div style="margin-left:0cm;margin-right:0cm;">对于属性为“constructor”函数,它在main函数之前被调用。</div> | ||
第1,046行: | 第1,046行: | ||
<div style="margin-left:0cm;margin-right:0cm;">register_module_init中构造了一个ModuleEntry结构体,并把它添加进某个链表里,这个链表是init_type_list[MODULE_INIT_QOM]:</div> | <div style="margin-left:0cm;margin-right:0cm;">register_module_init中构造了一个ModuleEntry结构体,并把它添加进某个链表里,这个链表是init_type_list[MODULE_INIT_QOM]:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_019.png|top]]</div> |
<div style="margin-left:0cm;margin-right:0cm;">这样就得到了一个链表:</div> | <div style="margin-left:0cm;margin-right:0cm;">这样就得到了一个链表:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_020.png|top]]</div> |
=== 生成TypeImpl === | === 生成TypeImpl === | ||
第1,077行: | 第1,077行: | ||
① 分配一个TypeImpl结构体,使用TypeInfo来设置它: | ① 分配一个TypeImpl结构体,使用TypeInfo来设置它: | ||
− | <div style="text-align:center;">[[Image: | + | <div style="text-align:center;">[[Image:100ask_imx6ull_qemu_021.png|top]]</div> |
② 把TypeImpl放入链表:type_table | ② 把TypeImpl放入链表:type_table | ||
第1,083行: | 第1,083行: | ||
<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;">[[Image: | + | <div style="margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_022.png|top]]</div> |
第1,099行: | 第1,099行: | ||
<div style="margin-left:0cm;margin-right:0cm;">以CPU为例,代码为hw/cpu/a15mpcore.c,里面声明了一个A15MPPrivState结构体,还定义了一个TypeInfo结构体:</div> | <div style="margin-left:0cm;margin-right:0cm;">以CPU为例,代码为hw/cpu/a15mpcore.c,里面声明了一个A15MPPrivState结构体,还定义了一个TypeInfo结构体:</div> | ||
− | <div style="margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_023.png|top]]</div> |
第1,117行: | 第1,117行: | ||
<div style="margin-left:0cm;margin-right:0cm;">所以,可以得到下面的图:</div> | <div style="margin-left:0cm;margin-right:0cm;">所以,可以得到下面的图:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_024.png|top]]</div> |
第1,212行: | 第1,212行: | ||
<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> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_025.png|top]]</div> |
<div style="margin-left:0cm;margin-right:0cm;">这2个函数的作用如下图所示:</div> | <div style="margin-left:0cm;margin-right:0cm;">这2个函数的作用如下图所示:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_026.png|top]]</div> |
==== qdev_create分析 ==== | ==== qdev_create分析 ==== | ||
第1,231行: | 第1,231行: | ||
<div style="margin-left:0cm;margin-right:0cm;">这些class_init函数都很类似,都是设置dc->realize函数,比如:</div> | <div style="margin-left:0cm;margin-right:0cm;">这些class_init函数都很类似,都是设置dc->realize函数,比如:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_027.png|top]]</div> |
④ 调用TypeInfo结构体中的instance_init函数 | ④ 调用TypeInfo结构体中的instance_init函数 | ||
第1,250行: | 第1,250行: | ||
<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> | ||
− | <div style="text-align:center;margin-left:0.635cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0.635cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_028.png|top]]</div> |
<div style="margin-left:0.63cm;margin-right:0cm;">只是把设备的realized属性设置为true,表示可以对它进行realize(变为现实)了。这会导致dc->realize函数被调用,即设备的类里的realize函数被调用。</div> | <div style="margin-left:0.63cm;margin-right:0cm;">只是把设备的realized属性设置为true,表示可以对它进行realize(变为现实)了。这会导致dc->realize函数被调用,即设备的类里的realize函数被调用。</div> | ||
第1,259行: | 第1,259行: | ||
<div style="margin-left:0.63cm;margin-right:0cm;">怎么定义一个设备?如下图:</div> | <div style="margin-left:0.63cm;margin-right:0cm;">怎么定义一个设备?如下图:</div> | ||
− | <div style="text-align:center;margin-left:0.63cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0.63cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_029.png|top]]</div> |
① 先定义一个TypeInfo结构体 | ① 先定义一个TypeInfo结构体 | ||
第1,302行: | 第1,302行: | ||
<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> | ||
− | [[Image: | + | [[Image:100ask_imx6ull_qemu_030.png|top]] |
<div style="margin-left:0cm;margin-right:0cm;">上述函数的内部调用过程,跟qdev_create/qdev_init_nofail是类似的:</div> | <div style="margin-left:0cm;margin-right:0cm;">上述函数的内部调用过程,跟qdev_create/qdev_init_nofail是类似的:</div> | ||
− | [[Image: | + | [[Image:100ask_imx6ull_qemu_031.png|top]] |
==== object_initialize_child分析 ==== | ==== object_initialize_child分析 ==== | ||
第1,323行: | 第1,323行: | ||
<div style="margin-left:0.63cm;margin-right:0cm;">比如:</div> | <div style="margin-left:0.63cm;margin-right:0cm;">比如:</div> | ||
− | <div style="margin-left:0.63cm;margin-right:0cm;">[[Image: | + | <div style="margin-left:0.63cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_032.png|top]]</div> |
<div style="margin-left:0.63cm;margin-right:0cm;">只是把设备的realized属性设置为true,表示可以对它进行realize(变为现实)了。这会导致dc->realize函数被调用,即设备的类里的realize函数被调用。</div> | <div style="margin-left:0.63cm;margin-right:0cm;">只是把设备的realized属性设置为true,表示可以对它进行realize(变为现实)了。这会导致dc->realize函数被调用,即设备的类里的realize函数被调用。</div> | ||
第1,332行: | 第1,332行: | ||
<div style="margin-left:0cm;margin-right:0cm;">怎么定义一个设备?如下图所示:</div> | <div style="margin-left:0cm;margin-right:0cm;">怎么定义一个设备?如下图所示:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_033.png|top]]</div> |
① 先定义一个TypeInfo结构体 | ① 先定义一个TypeInfo结构体 | ||
第1,387行: | 第1,387行: | ||
<div style="margin-left:0cm;margin-right:0cm;">比如LCD:</div> | <div style="margin-left:0cm;margin-right:0cm;">比如LCD:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_034.png|top]]</div> |
<div style="margin-left:0cm;margin-right:0cm;">要注意到,里面有一个ASK100FbState结构体,这个结构体由我们自己设置。但是它的格式有一定要求:</div> | <div style="margin-left:0cm;margin-right:0cm;">要注意到,里面有一个ASK100FbState结构体,这个结构体由我们自己设置。但是它的格式有一定要求:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_035.png|top]]</div> |
==== 注册TypeInfo结构体 ==== | ==== 注册TypeInfo结构体 ==== | ||
第1,397行: | 第1,397行: | ||
<div style="margin-left:0cm;margin-right:0cm;">比如:</div> | <div style="margin-left:0cm;margin-right:0cm;">比如:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_036.png|top]]</div> |
==== 使用TypeInfo创建设备/设置设备的realized属性为true ==== | ==== 使用TypeInfo创建设备/设置设备的realized属性为true ==== | ||
第1,426行: | 第1,426行: | ||
<div style="margin-left:0cm;margin-right:0cm;">以GPIO为例:</div> | <div style="margin-left:0cm;margin-right:0cm;">以GPIO为例:</div> | ||
− | <div style="margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_037.png|top]]</div> |
第1,468行: | 第1,468行: | ||
<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;">[[Image: | + | <div style="margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_038.png|top]]</div> |
第1,522行: | 第1,522行: | ||
<div style="margin-left:0cm;margin-right:0cm;">比如:</div> | <div style="margin-left:0cm;margin-right:0cm;">比如:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_039.png|top]]</div> |
<div style="margin-left:0cm;margin-right:0cm;">上图中memory_region_init_io被用来初始化一块内存s->iomem,指定了它的读写函数、大小。</div> | <div style="margin-left:0cm;margin-right:0cm;">上图中memory_region_init_io被用来初始化一块内存s->iomem,指定了它的读写函数、大小。</div> | ||
第1,535行: | 第1,535行: | ||
<div style="margin-left:0cm;margin-right:0cm;">以hw/net/smc91c111.c为例:</div> | <div style="margin-left:0cm;margin-right:0cm;">以hw/net/smc91c111.c为例:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_040.png|top]]</div> |
第1,564行: | 第1,564行: | ||
<div style="margin-left:0cm;margin-right:0cm;">对应的write函数如下:</div> | <div style="margin-left:0cm;margin-right:0cm;">对应的write函数如下:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_041.png|top]]</div> |
第1,578行: | 第1,578行: | ||
<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> | ||
− | <div style="margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_042.png|top]]</div> |
第1,629行: | 第1,629行: | ||
<div style="margin-left:0cm;margin-right:0cm;">部分代码如下,其他的时钟使能、GPIO设置等等都不再需要:</div> | <div style="margin-left:0cm;margin-right:0cm;">部分代码如下,其他的时钟使能、GPIO设置等等都不再需要:</div> | ||
− | <div style="margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_043.png|top]]</div> |
=== 5.2 在QEMU中创建LCD控制器的设备 === | === 5.2 在QEMU中创建LCD控制器的设备 === | ||
− | <div style="text-align:center;">[[Image: | + | <div style="text-align:center;">[[Image:100ask_imx6ull_qemu_044.png|top]]</div> |
第1,646行: | 第1,646行: | ||
==== 5.3.1 给LCD控制器的寄存器提供回调函数 ==== | ==== 5.3.1 给LCD控制器的寄存器提供回调函数 ==== | ||
− | <div style="text-align:center;">[[Image: | + | <div style="text-align:center;">[[Image:100ask_imx6ull_qemu_045.png|top]]</div> |
− | <div style="margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_046.png|top]]</div> |
==== 5.3.2 给FrameBuffer提供更新函数 ==== | ==== 5.3.2 给FrameBuffer提供更新函数 ==== | ||
− | <div style="text-align:center;">[[Image: | + | <div style="text-align:center;">[[Image:100ask_imx6ull_qemu_047.png|top]]</div> |
==== 5.3.3 更新函数 ==== | ==== 5.3.3 更新函数 ==== | ||
− | <div style="margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_048.png|top]]</div> |
第1,687行: | 第1,687行: | ||
<div style="margin-left:0cm;margin-right:0cm;">LCD代码如下,主要是graphic_console_init函数:</div> | <div style="margin-left:0cm;margin-right:0cm;">LCD代码如下,主要是graphic_console_init函数:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_049.png|top]]</div> |
<div style="margin-left:0cm;margin-right:0cm;">调用graphic_console_init时,要传入一个GraphicHwOps结构体,如下:</div> | <div style="margin-left:0cm;margin-right:0cm;">调用graphic_console_init时,要传入一个GraphicHwOps结构体,如下:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_050.png|top]]</div> |
第1,721行: | 第1,721行: | ||
<div style="margin-left:0cm;margin-right:0cm;">ask100fb_update函数被GUI系统周期性地调用:</div> | <div style="margin-left:0cm;margin-right:0cm;">ask100fb_update函数被GUI系统周期性地调用:</div> | ||
− | <div style="margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_051.png|top]]</div> |
第1,728行: | 第1,728行: | ||
<div style="margin-left:0cm;margin-right:0cm;">效果如下:</div> | <div style="margin-left:0cm;margin-right:0cm;">效果如下:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_052.png|top]]</div> |
第1,749行: | 第1,749行: | ||
==== 6.3.1 解析BMP文件得到RGB数据 ==== | ==== 6.3.1 解析BMP文件得到RGB数据 ==== | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_053.png|top]]</div> |
==== 6.3.2 显示RGB数据 ==== | ==== 6.3.2 显示RGB数据 ==== | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_054.png|top]]</div> |
==== 6.3.3 显示LCD数据 ==== | ==== 6.3.3 显示LCD数据 ==== | ||
− | <div style="margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_055.png|top]]</div> |
第1,766行: | 第1,766行: | ||
<div style="margin-left:0cm;margin-right:0cm;">点击buttons界面时,对应的按钮会被按下或松开:</div> | <div style="margin-left:0cm;margin-right:0cm;">点击buttons界面时,对应的按钮会被按下或松开:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_056.png|top]]</div> |
<div style="margin-left:0cm;margin-right:0cm;">这是怎么实现的?</div> | <div style="margin-left:0cm;margin-right:0cm;">这是怎么实现的?</div> | ||
第1,777行: | 第1,777行: | ||
=== 7.1 分配、设置、注册QemuInputHandler === | === 7.1 分配、设置、注册QemuInputHandler === | ||
− | <div style="text-align:center;">[[Image: | + | <div style="text-align:center;">[[Image:100ask_imx6ull_qemu_057.png|top]]</div> |
第1,808行: | 第1,808行: | ||
=== 7.2 QemuInputHandler处理函数分析 === | === 7.2 QemuInputHandler处理函数分析 === | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_058.png|top]]</div> |
第1,815行: | 第1,815行: | ||
<div style="margin-left:0cm;margin-right:0cm;">输入事件的处理源头是sdl2_2d_refresh函数:</div> | <div style="margin-left:0cm;margin-right:0cm;">输入事件的处理源头是sdl2_2d_refresh函数:</div> | ||
− | <div style="margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_059.png|top]]</div> |
sdl2_2d_refresh | sdl2_2d_refresh | ||
第1,842行: | 第1,842行: | ||
<div style="margin-left:0cm;margin-right:0cm;">作为哪类事件上传,取决于qemu_input_is_absolute()的返回值:</div> | <div style="margin-left:0cm;margin-right:0cm;">作为哪类事件上传,取决于qemu_input_is_absolute()的返回值:</div> | ||
− | <div style="text-align:center;">[[Image: | + | <div style="text-align:center;">[[Image:100ask_imx6ull_qemu_060.png|top]]</div> |
第1,849行: | 第1,849行: | ||
<div style="margin-left:0cm;margin-right:0cm;">对应的QemuInputHandler的mask必须设置为INPUT_EVENT_MASK_ABS:</div> | <div style="margin-left:0cm;margin-right:0cm;">对应的QemuInputHandler的mask必须设置为INPUT_EVENT_MASK_ABS:</div> | ||
− | <div style="text-align:center;">[[Image: | + | <div style="text-align:center;">[[Image:100ask_imx6ull_qemu_061.png|top]]</div> |
第1,884行: | 第1,884行: | ||
<div style="margin-left:0cm;margin-right:0cm;">先看看硬件框架:</div> | <div style="margin-left:0cm;margin-right:0cm;">先看看硬件框架:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_062.png|top]]</div> |
第1,895行: | 第1,895行: | ||
<div style="margin-left:0cm;margin-right:0cm;">在include/hw/arm/fsl-imx6ul.h中列出了各个中断源,如下:</div> | <div style="margin-left:0cm;margin-right:0cm;">在include/hw/arm/fsl-imx6ul.h中列出了各个中断源,如下:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_063.png|top]]</div> |
第1,909行: | 第1,909行: | ||
<div style="margin-left:0cm;margin-right:0cm;">以GPIO为例,代码在hw/gpio/imx_gpio.c中:</div> | <div style="margin-left:0cm;margin-right:0cm;">以GPIO为例,代码在hw/gpio/imx_gpio.c中:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_064.png|top]]</div> |
第1,922行: | 第1,922行: | ||
<div style="margin-left:0cm;margin-right:0cm;">在hw/arm/fsl-imx6ul.c中,给GPIO模块和GIC建立联系:</div> | <div style="margin-left:0cm;margin-right:0cm;">在hw/arm/fsl-imx6ul.c中,给GPIO模块和GIC建立联系:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_065.png|top]]</div> |
第2,035行: | 第2,035行: | ||
=== 9.1 按键GUI === | === 9.1 按键GUI === | ||
− | <div style="margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_066.png|top]]</div> |
第2,076行: | 第2,076行: | ||
=== 9.2 点击按键 === | === 9.2 点击按键 === | ||
− | <div style="text-align:center;">[[Image: | + | <div style="text-align:center;">[[Image:100ask_imx6ull_qemu_067.png|top]]</div> |
=== 9.3 更新按键图片的同时 === | === 9.3 更新按键图片的同时 === | ||
− | <div style="margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_068.png|top]]</div> |
=== 9.4 单板的代码怎么处理按键 === | === 9.4 单板的代码怎么处理按键 === | ||
第2,087行: | 第2,087行: | ||
<div style="margin-left:0cm;margin-right:0cm;">对应的代码在hw/gpio/100ask_imx6ull_buttons.c中:</div> | <div style="margin-left:0cm;margin-right:0cm;">对应的代码在hw/gpio/100ask_imx6ull_buttons.c中:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_069.png|top]]</div> |
=== 9.5 IMX6ULL的代码怎么处理输入引脚 === | === 9.5 IMX6ULL的代码怎么处理输入引脚 === | ||
第2,093行: | 第2,093行: | ||
<div style="margin-left:0cm;margin-right:0cm;">对应的代码在hw/gpio/imx_gpio.c中:</div> | <div style="margin-left:0cm;margin-right:0cm;">对应的代码在hw/gpio/imx_gpio.c中:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_070.png|top]]</div> |
第2,148行: | 第2,148行: | ||
<div style="margin-left:0cm;margin-right:0cm;">各个模块都定义了一个TypeInfo结构体,比如LCD:</div> | <div style="margin-left:0cm;margin-right:0cm;">各个模块都定义了一个TypeInfo结构体,比如LCD:</div> | ||
− | <div style="text-align:center;">[[Image: | + | <div style="text-align:center;">[[Image:100ask_imx6ull_qemu_071.png|top]]</div> |
第2,165行: | 第2,165行: | ||
} | } | ||
− | <div style="margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_072.png|top]]</div> |
<div style="margin-left:0cm;margin-right:0cm;">这些属性为<span style="color:#ff0000;">constructor</span>的函数会在main函数之前被调用,这样就得到了一个链表:</div> | <div style="margin-left:0cm;margin-right:0cm;">这些属性为<span style="color:#ff0000;">constructor</span>的函数会在main函数之前被调用,这样就得到了一个链表:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_073.png|top]]</div> |
第2,202行: | 第2,202行: | ||
① 分配一个TypeImpl结构体,使用TypeInfo来设置它: | ① 分配一个TypeImpl结构体,使用TypeInfo来设置它: | ||
− | <div style="text-align:center;">[[Image: | + | <div style="text-align:center;">[[Image:100ask_imx6ull_qemu_074.png|top]]</div> |
② 把TypeImpl放入链表:type_table | ② 把TypeImpl放入链表:type_table | ||
第2,208行: | 第2,208行: | ||
<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;">[[Image: | + | <div style="margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_075.png|top]]</div> |
第2,234行: | 第2,234行: | ||
<div style="margin-left:0cm;margin-right:0cm;">启动qemu时,会传入参数“-M mcimx6ul-evk”,对应的文件为:hw/arm/mcimx6ul-evk.c</div> | <div style="margin-left:0cm;margin-right:0cm;">启动qemu时,会传入参数“-M mcimx6ul-evk”,对应的文件为:hw/arm/mcimx6ul-evk.c</div> | ||
− | <div style="margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_076.png|top]]</div> |
=== 10.4 选择CPU === | === 10.4 选择CPU === | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_077.png|top]]</div> |
<div style="margin-left:0cm;margin-right:0cm;">CPU在中hw/arm/fsl-imx6ul.c定义:</div> | <div style="margin-left:0cm;margin-right:0cm;">CPU在中hw/arm/fsl-imx6ul.c定义:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_078.png|top]]</div> |
第2,261行: | 第2,261行: | ||
<div style="margin-left:0cm;margin-right:0cm;">hw/arm/mcimx6ul-evk.c mcimx6ul_evk_init:</div> | <div style="margin-left:0cm;margin-right:0cm;">hw/arm/mcimx6ul-evk.c mcimx6ul_evk_init:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_079.png|top]]</div> |
<div style="margin-left:0cm;margin-right:0cm;">这会导致hw/arm/fsl-imx6ul.c中fsl_imx6ul_init函数被调用:</div> | <div style="margin-left:0cm;margin-right:0cm;">这会导致hw/arm/fsl-imx6ul.c中fsl_imx6ul_init函数被调用:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_080.png|top]]</div> |
<div style="margin-left:0cm;margin-right:0cm;">在fsl_imx6ul_init函数中,会去创建名为a7mpcore的设备,它的类型是TYPE_A15MPCORE_PRIV:</div> | <div style="margin-left:0cm;margin-right:0cm;">在fsl_imx6ul_init函数中,会去创建名为a7mpcore的设备,它的类型是TYPE_A15MPCORE_PRIV:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_081.png|top]]</div> |
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_082.png|top]]</div> |
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_083.png|top]]</div> |
<div style="margin-left:0cm;margin-right:0cm;">a7mpcore设备对应的realize函数被调用时,里面会实例化GIC等。</div> | <div style="margin-left:0cm;margin-right:0cm;">a7mpcore设备对应的realize函数被调用时,里面会实例化GIC等。</div> | ||
第2,284行: | 第2,284行: | ||
<div style="margin-left:0cm;margin-right:0cm;">分配system memory,代码为hw/arm/mcimx6ul-evk.c中的mcimx6ul_evk_init函数:</div> | <div style="margin-left:0cm;margin-right:0cm;">分配system memory,代码为hw/arm/mcimx6ul-evk.c中的mcimx6ul_evk_init函数:</div> | ||
− | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="text-align:center;margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_084.png|top]]</div> |
第2,435行: | 第2,435行: | ||
==== 14.4.2 进入内核源码目录,运行arm-xxx-gdb vmlinux ==== | ==== 14.4.2 进入内核源码目录,运行arm-xxx-gdb vmlinux ==== | ||
− | <div style="margin-left:0cm;margin-right:0cm;">[[Image: | + | <div style="margin-left:0cm;margin-right:0cm;">[[Image:100ask_imx6ull_qemu_085.png|top]]</div> |
2019年11月25日 (一) 15:16的版本
目录
- 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
使用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的设备创建过程
重要结构体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函数被调用。
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 主要函数
5. 模拟LCD
common-obj-$(CONFIG_FSL_IMX6UL) += 100ask_qemu_fb.o
5.1 在Linux上编写LCD驱动程序
① 对于LCD控制器,只需要操作4个寄存器:
② 对于FrameBuffer:
6. QEMU的输出:GUI系统
6.1 创建GUI Console
7. QEMU的输入:鼠标事件
common-obj-$(CONFIG_FSL_IMX6UL) += button_ui.o
7.3 输入事件处理流程
sdl2_2d_refresh
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.2 中断触发
发出中断:
清除中断:
① 用户按下按键后,使用“qemu_set_irq(irq, 1)”发出中断
② 客户机的程序处理完中断后,它会写ISR寄存器来清除中断:
notify_imx_gpio_change
qemu_set_irq(s->irq[0], 1);
imx_gpio_write
9. 模拟按键
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