scripts/qemustart: add riscv64 support
[openwrt/staging/yousong.git] / scripts / qemustart
1 #!/usr/bin/env bash
2
3 SELF="$0"
4
5 # Linux bridge for connecting lan and wan network of guest machines
6 BR_LAN="${BR_LAN:-br-lan}"
7 BR_WAN="${BR_WAN:-br-wan}"
8
9 # Host network interface providing internet access for guest machines
10 IF_INET="${IF_INET:-eth0}"
11
12 # qemu-bridge-helper does two things here
13 #
14 # - create tap interface
15 # - add the tap interface to bridge
16 #
17 # as such it requires CAP_NET_ADMIN to do its job. It will be convenient to
18 # have it as a root setuid program. Be aware of the security risks implied
19 #
20 # the helper has an acl list which defaults to deny all bridge. we need to add
21 # $BR_LAN and $BR_WAN to its allow list
22 #
23 # # sudo vim /etc/qemu/bridge.conf
24 # allow br-lan
25 # allow br-wan
26 #
27 # Other allowed directives can be 'allow all', 'deny all', 'include xxx', See
28 # qemu-bridge-helper.c of qemu source code for details.
29 #
30 # The helper can be provided by package qemu-system-common on debian, or
31 # qemu-kvm-common on rhel
32 #
33 HELPER="${HELPER:-/usr/libexec/qemu-bridge-helper}"
34
35 ### end of global settings
36
37 __errmsg() {
38 echo "$*" >&2
39 }
40
41 do_setup() {
42 # setup bridge for LAN network
43 sudo ip link add dev "$BR_LAN" type bridge
44 sudo ip link set dev "$BR_LAN" up
45 sudo ip addr add 192.168.1.3/24 dev "$BR_LAN"
46
47 # setup bridge for WAN network
48 #
49 # minimal dnsmasq config for configuring guest wan network with dhcp
50 #
51 # # sudo apt-get install dnsmasq
52 # # sudo vi /etc/dnsmasq.conf
53 # interface=br-wan
54 # dhcp-range=192.168.7.50,192.168.7.150,255.255.255.0,30m
55 #
56 sudo ip link add dev "$BR_WAN" type bridge
57 sudo ip link set dev "$BR_WAN" up
58 sudo ip addr add 192.168.7.1/24 dev "$BR_WAN"
59
60 # guest internet access
61 sudo sysctl -w "net.ipv4.ip_forward=1"
62 sudo sysctl -w "net.ipv4.conf.$BR_WAN.proxy_arp=1"
63 while sudo iptables -t nat -D POSTROUTING -o "$IF_INET" -j MASQUERADE 2>/dev/null; do true; done
64 sudo iptables -t nat -A POSTROUTING -o "$IF_INET" -j MASQUERADE
65 }
66
67 check_setup_() {
68 ip link show "$BR_LAN" >/dev/null || return 1
69 ip link show "$BR_WAN" >/dev/null || return 1
70 [ -x "$HELPER" ] || {
71 __errmsg "helper $HELPER is not an executable"
72 return 1
73 }
74 }
75
76 check_setup() {
77 [ -n "$o_network" ] || return 0
78 check_setup_ || {
79 __errmsg "please check the script content to see the environment requirement"
80 return 1
81 }
82 }
83 #do_setup; check_setup; exit $?
84
85 usage() {
86 cat >&2 <<EOF
87 Usage: $SELF [-h|--help]
88 $SELF <target>
89 [<subtarget> [<extra-qemu-options>]]
90 [--kernel <kernel>]
91 [--rootfs <rootfs>]
92 [--machine <machine>]
93 [-n|--network]
94
95 <subtarget> will default to "generic" and must be specified if
96 <extra-qemu-options> are present
97
98 e.g. <subtarget> for malta can be le, be, le64, be64, le-glibc, le64-glibc, etc
99
100 <kernel>, <rootfs> can be required or optional arguments to qemu depending on
101 the actual <target> in use. They will default to files under bin/targets/
102
103 Examples
104
105 $SELF x86 64
106 $SELF x86 64 --machine q35,accel=kvm -device virtio-balloon-pci
107 $SELF x86 64 -incoming tcp:0:4444
108 $SELF x86 64-glibc
109 $SELF malta be -m 64
110 $SELF malta le64
111 $SELF malta be-glibc
112 $SELF armvirt 32 \\
113 --machine virt,highmem=off \\
114 --kernel bin/targets/armvirt/32/openwrt-armvirt-32-zImage \\
115 --rootfs bin/targets/armvirt/32/openwrt-armvirt-32-root.ext4
116 EOF
117 }
118
119 rand_mac() {
120 hexdump -n 3 -e '"52:54:00" 3/1 ":%02x"' /dev/urandom
121 }
122
123 parse_args() {
124 o_network=
125 o_qemu_extra=()
126 while [ "$#" -gt 0 ]; do
127 # Cmdline options for the script itself SHOULD try to be
128 # prefixed with two dashes to distinguish them from those for
129 # qemu executables.
130 #
131 # Also note that qemu accepts both --opt and -opt
132 case "$1" in
133 --kernel) o_kernel="$2"; shift 2 ;;
134 --rootfs) o_rootfs="$2"; shift 2 ;;
135 --machine|-machine|-M) o_mach="$2"; shift 2 ;;
136 --network|-n) o_network=1; shift ;;
137 --help|-h)
138 usage
139 exit 0
140 ;;
141 *)
142 if [ -z "$o_target" ]; then
143 o_target="$1"
144 elif [ -z "$o_subtarget" ]; then
145 o_subtarget="$1"
146 else
147 o_qemu_extra+=("$1")
148 fi
149 shift
150 ;;
151 esac
152 done
153
154 MAC_LAN="$(rand_mac)"
155 MAC_WAN="$(rand_mac)"
156 [ -n "$o_target" ] || {
157 usage
158 return 1
159 }
160 [ -n "$o_subtarget" ] || o_subtarget="generic"
161 o_bindir="bin/targets/$o_target/$o_subtarget"
162 }
163
164 start_qemu_armvirt() {
165 local kernel="$o_kernel"
166 local rootfs="$o_rootfs"
167 local mach="${o_mach:-virt}"
168 local cpu
169 local qemu_exe
170
171 case "${o_subtarget%-*}" in
172 32)
173 qemu_exe="qemu-system-arm"
174 cpu="cortex-a15"
175 [ -n "$kernel" ] || kernel="$o_bindir/openwrt-$o_target-${o_subtarget%-*}-zImage-initramfs"
176 ;;
177 64)
178 qemu_exe="qemu-system-aarch64"
179 cpu="cortex-a57"
180 [ -n "$kernel" ] || kernel="$o_bindir/openwrt-$o_target-${o_subtarget%-*}-Image-initramfs"
181 ;;
182 *)
183 __errmsg "target $o_target: unknown subtarget $o_subtarget"
184 return 1
185 ;;
186 esac
187 [ -z "$rootfs" ] || {
188 if [ ! -f "$rootfs" -a -s "$rootfs.gz" ]; then
189 gunzip "$rootfs.gz"
190 fi
191 o_qemu_extra+=( \
192 "-drive" "file=$rootfs,format=raw,if=virtio" \
193 "-append" "root=/dev/vda rootwait" \
194 )
195 }
196
197 [ -z "$o_network" ] || {
198 o_qemu_extra+=( \
199 "-netdev" "bridge,id=lan,br=$BR_LAN,helper=$HELPER" \
200 "-device" "virtio-net-pci,id=devlan,netdev=lan,mac=$MAC_LAN" \
201 "-netdev" "bridge,id=wan,br=$BR_WAN,helper=$HELPER" "-device" \
202 "virtio-net-pci,id=devwan,netdev=wan,mac=$MAC_WAN" \
203 )
204 }
205
206 "$qemu_exe" -machine "$mach" -cpu "$cpu" -nographic \
207 -kernel "$kernel" \
208 "${o_qemu_extra[@]}"
209 }
210
211 start_qemu_malta() {
212 local is64
213 local isel
214 local qemu_exe
215 local rootfs="$o_rootfs"
216 local kernel="$o_kernel"
217 local mach="${o_mach:-malta}"
218
219 # o_subtarget can be le, be, le64, be64, le-glibc, le64-glibc, etc..
220 is64="$(echo $o_subtarget | grep -o 64)"
221 [ "$(echo "$o_subtarget" | grep -o '^..')" = "le" ] && isel="el"
222 qemu_exe="qemu-system-mips$is64$isel"
223
224 [ -n "$kernel" ] || kernel="$o_bindir/openwrt-malta-${o_subtarget%-*}-vmlinux-initramfs.elf"
225
226 [ -z "$rootfs" ] || {
227 if [ ! -f "$rootfs" -a -s "$rootfs.gz" ]; then
228 gunzip "$rootfs.gz"
229 fi
230 o_qemu_extra+=( \
231 "-drive" "file=$rootfs,format=raw" \
232 "-append" "root=/dev/sda rootwait" \
233 )
234 }
235
236 # NOTE: order of wan, lan -device arguments matters as it will affect which
237 # one will be actually used as the wan, lan network interface inside the
238 # guest machine
239 [ -z "$o_network" ] || {
240 o_qemu_extra+=(
241 -netdev bridge,id=wan,br="$BR_WAN,helper=$HELPER" -device pcnet,netdev=wan,mac="$MAC_WAN"
242 -netdev bridge,id=lan,br="$BR_LAN,helper=$HELPER" -device pcnet,netdev=lan,mac="$MAC_LAN"
243 )
244 }
245
246 "$qemu_exe" -machine "$mach" -nographic \
247 -kernel "$kernel" \
248 "${o_qemu_extra[@]}"
249 }
250
251 start_qemu_riscv() {
252 local is64
253 local qemu_exe
254 local rootfs="$o_rootfs"
255 local kernel="$o_kernel"
256 local mach="${o_mach:-virt}"
257
258 # o_subtarget can be xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, etc..
259 is64="$(echo $o_subtarget | grep -o 64)"
260 qemu_exe="qemu-system-riscv$is64"
261
262 [ -n "$kernel" ] || kernel="$o_bindir/openwrt-riscv64-${o_subtarget%-*}-vmlinux-initramfs.elf"
263
264 [ -z "$rootfs" ] || {
265 if [ ! -f "$rootfs" -a -s "$rootfs.gz" ]; then
266 gunzip "$rootfs.gz"
267 fi
268 o_qemu_extra+=( \
269 "-drive" "file=$rootfs,format=raw" \
270 "-append" "root=/dev/sda rootwait" \
271 )
272 }
273
274 [ -z "$o_network" ] || {
275 o_qemu_extra+=(
276 -netdev bridge,id=wan,br="$BR_WAN,helper=$HELPER" -device pcnet,netdev=wan,mac="$MAC_WAN"
277 -netdev bridge,id=lan,br="$BR_LAN,helper=$HELPER" -device pcnet,netdev=lan,mac="$MAC_LAN"
278 )
279 }
280
281 "$qemu_exe" -machine "$mach" -nographic \
282 -kernel "$kernel" \
283 "${o_qemu_extra[@]}"
284 }
285
286 start_qemu_x86() {
287 local qemu_exe
288 local kernel="$o_kernel"
289 local rootfs="$o_rootfs"
290 local mach="${o_mach:-pc}"
291
292 [ -n "$rootfs" ] || {
293 rootfs="$o_bindir/openwrt-$o_target-${o_subtarget%-*}-combined-ext4.img"
294 if [ ! -f "$rootfs" -a -s "$rootfs.gz" ]; then
295 gunzip "$rootfs.gz"
296 fi
297 }
298 #
299 # generic: 32-bit, pentium4 (CONFIG_MPENTIUM4), kvm guest, virtio
300 # legacy: 32-bit, i486 (CONFIG_M486)
301 # 64: 64-bit, kvm guest, virtio
302 #
303 case "${o_subtarget%-*}" in
304 legacy) qemu_exe="qemu-system-i386" ;;
305 generic|64) qemu_exe="qemu-system-x86_64" ;;
306 *)
307 __errmsg "target $o_target: unknown subtarget $o_subtarget"
308 return 1
309 ;;
310 esac
311
312 [ -n "$kernel" ] && {
313 o_qemu_extra+=( \
314 "-kernel" "$kernel" \
315 "-append" "root=/dev/vda console=ttyS0 rootwait" \
316 )
317 }
318
319 [ -z "$o_network" ] || {
320 case "${o_subtarget%-*}" in
321 legacy)
322 o_qemu_extra+=(
323 -netdev "bridge,id=lan,br=$BR_LAN,helper=$HELPER" -device "e1000,id=devlan,netdev=lan,mac=$MAC_LAN"
324 -netdev "bridge,id=wan,br=$BR_WAN,helper=$HELPER" -device "e1000,id=devwan,netdev=wan,mac=$MAC_WAN"
325 )
326 ;;
327 generic|64)
328 o_qemu_extra+=(
329 -netdev "bridge,id=lan,br=$BR_LAN,helper=$HELPER" -device "virtio-net-pci,id=devlan,netdev=lan,mac=$MAC_LAN"
330 -netdev "bridge,id=wan,br=$BR_WAN,helper=$HELPER" -device "virtio-net-pci,id=devwan,netdev=wan,mac=$MAC_WAN"
331 )
332 ;;
333 esac
334 }
335
336 case "${o_subtarget%-*}" in
337 legacy)
338 # use IDE (PATA) disk instead of AHCI (SATA). Refer to link
339 # [1] for related discussions
340 #
341 # To use AHCI interface
342 #
343 # -device ich9-ahci,id=ahci \
344 # -device ide-drive,drive=drv0,bus=ahci.0 \
345 # -drive "file=$rootfs,format=raw,id=drv0,if=none" \
346 #
347 # [1] https://dev.openwrt.org/ticket/17947
348 "$qemu_exe" -machine "$mach" -nographic \
349 -device ide-drive,drive=drv0 \
350 -drive "file=$rootfs,format=raw,id=drv0,if=none" \
351 "${o_qemu_extra[@]}"
352 ;;
353 generic|64)
354 "$qemu_exe" -machine "$mach" -nographic \
355 -drive "file=$rootfs,format=raw,if=virtio" \
356 "${o_qemu_extra[@]}"
357 ;;
358 esac
359 }
360
361 start_qemu() {
362 case "$o_target" in
363 armvirt) start_qemu_armvirt ;;
364 malta) start_qemu_malta ;;
365 riscv) start_qemu_riscv ;;
366 x86) start_qemu_x86 ;;
367 *)
368 __errmsg "target $o_target is not supported yet"
369 return 1
370 ;;
371 esac
372 }
373
374 parse_args "$@" \
375 && check_setup \
376 && start_qemu