qemu使用uboot通过网络加载 linux kernel。


原理图:

通过网桥,将OS镜像(uImage),通过网络协议下载到U-Boot中,从而通过U-Boot启动OS:

qemu uboot qemu uboot kernel_#define

 

如果有人出现了uboot第一次执行下载时失败,但后面正常,则可以参考我这里对.h代码的修改,即执行下载命令前,先ping一下。

1 #!/bin/sh
  2 
  3 
  4 
  5 # 1.
  6 # 修改busybox的Makefile的两个变量为:
  7 #   ARCH ?= arm
  8 #   CROSS_COMPILE ?= arm-linux-gnueabi-
  9 #
 10 cd u-boot-2022.10/
 11 vim Makefile
 12 
 13 
 14 
 15 
 16 
 17 # 2.
 18 # 编译, 如果出现错误, 安装: sudo apt install libssl-dev
 19 make vexpress_ca9x4_defconfig
 20 make -j 4
 21 
 22 
 23 
 24 
 25 
 26 # 3.
 27 # 使用qemu启动u-boot进行测试
 28 sh testiboot/test_uboot.sh
 29 #       test_uboot.sh内容
 30 #       #!/bin/sh
 31 #       # 测试u-boot
 32 #       # 上级路径
 33 #       top_path="/home/thinks2/ProgramProject/qemu_study/"
 34 #       src_path="tftpboot/u-boot"
 35 #       # 内核文件路径
 36 #       kernel_path=${top_path}${src_path}
 37 #       qemu-system-arm \
 38 #           -M vexpress-a9 \
 39 #           -m 512M \
 40 #           -kernel ${kernel_path} \
 41 #           -sd rootfs.ext3 \
 42 #           -nographic \
 43 
 44 
 45 
 46 
 47 
 48 # 4. 
 49 # 准备uImage内核, 指定加载地址, 编译uImage
 50 cd ..
 51 cd linux-4.19.269/
 52 make LOADADDR=0x60003000 uImage  -j 4
 53 
 54 
 55 
 56 
 57 
 58 # 5.
 59 # 细心的朋友发现, 目前加载u-boot的方法使用还是-kernel选项, 也就是把u-boot当做内核挂载的,
 60 # 而真实的系统启动, 不可能同时挂载两个内核启动(只能选择一个启动). 那么, 如何来模拟呢?
 61 #
 62 # u-boot实体机中, 我们常常采用tftp引导内核, 我们也可以在启动u-boot以后, 让u-boot通过tftp引导内核.
 63 # 需要做两件事情:
 64 #   1.搭建好tftp环境
 65 #   2.构建网桥, 让qemu可以访问, 从而让qemu和ubuntu之间可以通过该网桥来访问
 66 
 67 
 68 
 69 # 安装tftp和相关依赖, 设置好路径
 70 sudo apt install tftp-hpa tftpd-hpa xinetd uml-utilities bridge-utils
 71 
 72 
 73 
 74 # 设置tftp配置路径文件
 75 sudo vim /etc/default/tftpd-hpa
 76 # 将下面的内容复制近来
 77 TFTP_USERNAME="tftp"
 78 TFTP_DIRECTORY="/home/thinks2/ProgramProject/qemu_study/tftpboot" # 该路径即为tftp可以访问到的路径
 79 TFTP_ADDRESS=":69"
 80 TFTP_OPTIONS="--secure"
 81 # 重启tftp服务
 82 sudo /etc/init.d/tftpd-hpa restart
 83 
 84 
 85 
 86 # 配置完以后, 创建tftp目录, 给最高权限. 把内核, 设备树, 根文件系统,u-boot全部复制到这里
 87 cd ..
 88 mkdir tftpboot
 89 cd tftpboot
 90 cp ../u-boot-2022.10/u-boot ./
 91 cp ../linux-4.19.269/arch/arm/boot/uImage ./
 92 cp ../linux-4.19.269/arch/arm/boot/dts/vexpress-v2p-ca9.dtb ./
 93 
 94 
 95 
 96 
 97 
 98 # 6.
 99 # 修改网卡信息, 设置桥接
100 ifconfig    # 查看网卡名
101 
102 
103 
104 # 修改/etc/netplan/01-network-manager-all.yaml的信息配置:
105 sudo vim /etc/netplan/01-network-manager-all.yaml
106 # t添加以下内容:
107 ethernets:
108   # 这里设置的是你还需要上网的网卡, ifconfig查看
109   wlp0s20f3:
110     dhcp4: yes
111  
112   # 这里设置的是网桥br0需要接入的网卡, 进行静态IP设置, ifconfig查看
113   enp0s31f6:
114     dhcp4: no
115     addresses: [192.168.70.50/24]
116 
117 
118 
119 bridges:
120   #这里设置的是br0网桥, 进行静态IP设置
121   br0:
122     dhcp4: no
123     interfaces:
124       # 声明br0网桥接入的网卡是enp0s31f6
125       - enp0s31f6
126     addresses: [192.168.70.30/24]
127 
128 
129 
130 # 输入sudo netplan apply使其生效, 再输入ifconfig查看网卡信息
131 sudo netplan apply
132 ifconfig
133 
134 
135 
136 
137 
138 # 7.
139 # 修改/etc/qemu-ifdown信息配置
140 sudo vim /etc/qemu-ifdown
141 # 添加以下内容:
142 echo sudo brctl delif br0 $1
143 sudo brctl delif br0 $1
144 
145 
146 
147 echo sudo tunctl -d $1
148 sudo tunctl -d $1
149 
150 
151 
152 echo brctl show
153 brctl show
154 
155 
156 
157 
158 
159 # 8.
160 # 修改/etc/qemu-ifup信息配置
161 sudo vim /etc/qemu-ifup
162 # 添加以下内容:
163 echo sudo tunctl -u $(id -un) -t $1
164 sudo tunctl -u $(id -un) -t $1
165 
166 
167 
168 echo sudo ifconfig $1 0.0.0.0 promisc up
169 sudo ifconfig $1 0.0.0.0 promisc up
170 
171 
172 
173 echo sudo brctl addif br0 $1
174 sudo brctl addif br0 $1
175 
176 
177 
178 echo brctl show
179 brctl show
180 
181 
182 
183 # 这里设置的是网桥br0的地址: 该地址不能与宿主机的ip相同
184 sudo ifconfig br0 192.168.70.30
185 
186 
187 
188 
189 
190 # 9.
191 # 给 u-boot-2022.10/include/configs/vexpress_common.h添加代码:
192 #     /*
193 #         1. 设置u-boot这边的地址(和br0同一网段即可)
194 #         CONFIG_IPADDR   192.168.70.40
195 #     
196 #         2. 设置服务器地址(即br0网桥的地址)
197 #         CONFIG_SERVERIP 192.168.70.30
198 #     */
199 #     #define CONFIG_IPADDR   192.168.70.40
200 #     #define CONFIG_SERVERIP 192.168.70.30
201 #     #define CONFIG_NETMASK  255.255.255.0
202 #
203 #
204 #     /*
205 #       必须: make menuconfig -> Boot options -> 勾除Enable a default value or bootcmd
206 #         1. 从tft下载uImage
207 #         tftp 0x60003000 uImage
208 #     
209 #         2. 从tftp下载设备树
210 #         tftp 0x60500000 vexpress-v2p-ca9.dtb
211 #     
212 #         3. 设置根文件系统挂载位置、权限、控制台设备
213 #         setenv bootargs "root=/dev/mmcblk0 rw console=ttyAMA0"
214 #     
215 #         4. 设置启动地址
216 #         bootm 0x60003000-0x60500000
217 #     */
218 #
219 #
220 #     *********** 这里需要注意: ***********
221 #     新版本的uboot有一个配置u-boot启动时是否执行指令的选项: make menuconfig -> Boot options -> Enable a default value or bootcmd
222 #     1. 当勾选该选项后, 在.config文件中, 会出现一个参数: CONFIG_BOOTCOMMAND
223 #        这时, 修改.config文件中的该参数: .config -> CONFIG_BOOTCOMMAND 为命令字符串(以一行的格式)
224 #        .config会在make的时候, 自动生存autocfg.h文件, 这个头文件里会进行宏定义CONFIG_BOOTCOMMAND
225 #       
226 #     2. 如果不想修改.config文件, 需要勾除该选项,
227 #        勾除该选项后, 在.config文件中, 会删掉参数: CONFIG_BOOTCOMMAND
228 #        这时, 可以在u-boot-2022.10/include/configs/vexpress_common.h代码中添加下面的头文件定义即可
229 #
230 #     图方便的话, 建议使用方法2
231 #     ************************************
232 #
233 #     /* 必须: make menuconfig -> Boot options -> 勾除Enable a default value or bootcmd */
234 #     #ifndef CONFIG_BOOTCOMMAND
235 #     #define PING_COMMAND "ping 192.168.70.30;"
236 #     #define CONFIG_BOOTCOMMAND \
237 #         PING_COMMAND \
238 #         "tftp 0x60003000 uImage;" \
239 #         "tftp 0x60500000 vexpress-v2p-ca9.dtb;" \
240 #         "setenv bootargs 'root=/dev/mmcblk0 rw console=ttyAMA0';" \
241 #         "bootm 0x60003000 - 0x60500000;"
242 #     #endif
243 #
244 #     如果是在新版本的u-boot上, 可能使用上面的写法无法设置ipaddr, serverip, 则使用下面的代码:
245 #
246 #     #ifndef CONFIG_BOOTCOMMAND
247 #     
248 #     #define SET_IPADDR "setenv ipaddr 192.168.131.130;"
249 #     #define SET_SERVERIP "setenv serverip 192.168.131.100;"
250 #     #define PING_COMMAND "ping 192.168.131.100;"
251 #     
252 #     #define CONFIG_BOOTCOMMAND \
253 #         SET_IPADDR \
254 #         SET_SERVERIP \
255 #         PING_COMMAND \
256 #         "tftp 0x60003000 uImage;" \
257 #         "tftp 0x60500000 vexpress-v2p-ca9.dtb;" \
258 #         "setenv bootargs 'root=/dev/mmcblk0 rw console=ttyAMA0';" \
259 #         "bootm 0x60003000 - 0x60500000;"
260 #     #endif
261 #
262 cd ..
263 cd u-boot-2022.10/
264 vim include/configs/vexpress_common.h
265 
266 
267 
268 # 重新编译u-boot
269 make -j 4
270 
271 
272 
273 # 将编译好的u-boot镜像复制到tftpboot里
274 cd ..
275 cp u-boot-2022.10/u-boot tftpboot/
276 
277 
278 
279 #
280 # 手动设置:
281 # # 设置u-boot这边的地址(和br0同一网段即可)
282 # setenv ipaddr   192.168.70.40
283 # # 设置服务器地址(br0网桥的地址: 该地址不能与宿主机的ip相同)
284 # setenv serverip 192.168.70.30
285 # # 从tft下载uImage
286 # tftp 0x60003000 uImage
287 # # 从tftp下载设备树
288 # tftp 0x60500000 vexpress-v2p-ca9.dtb
289 # # 设置根文件系统挂载位置、权限、控制台设备
290 # setenv bootargs "root=/dev/mmcblk0 rw console=ttyAMA0"
291 # # 设置启动地址
292 # bootm 0x60003000 - 0x60500000
293 #
294 
295 
296 
297 
298 # 10.
299 # 修改test_uboot.sh, 添加:
300 #   -nic tap,ifname=tap0 \
301 #   -append "root=/dev/mmcblk0 rw console=ttyAMA0" \
302 vim test_uboot.sh
303 # 输入启动指令, 需要以sudo方式启动test_uboot.sh再启动
304 sudo sh test_uboot.sh
305 #       test_uboot.sh内容:
306 #       #!/bin/sh
307 #       # 测试u-boot
308 #       # 上级路径
309 #       top_path="/home/thinks2/ProgramProject/qemu_study/"
310 #       src_path="tftpboot/u-boot"
311 #       # 内核文件路径
312 #       kernel_path=${top_path}${src_path}
313 #       qemu-system-arm \
314 #           -M vexpress-a9 \
315 #           -m 512M \
316 #           -kernel ${kernel_path} \
317 #           -nic tap,ifname=tap0 \
318 #           -append "root=/dev/mmcblk0 rw console=ttyAMA0" \
319 #           -sd rootfs.ext3 \
320 #           -nographic \

 

 

最终的qemu的加载运行脚本test_uboot.sh:

 

1 #!/bin/sh
 2 
 3 
 4 
 5 # 测试u-boot
 6 
 7 
 8 
 9 # 上级路径
10 top_path="/home/thinks2/ProgramProject/qemu_study/"
11 src_path="tftpboot/u-boot"
12 
13 
14 
15 # 内核文件路径
16 kernel_path=${top_path}${src_path}
17 
18 
19 
20 qemu-system-arm \
21     -M vexpress-a9 \
22     -m 512M \
23     -kernel ${kernel_path} \
24     -nic tap,ifname=tap0 \
25     -append "root=/dev/mmcblk0 rw console=ttyAMA0" \
26     -sd rootfs.ext3 \
27     -nographic \