1*f7d6b772SThomas Huth#!/usr/bin/env python3
2*f7d6b772SThomas Huth#
3*f7d6b772SThomas Huth# Functional test that boots a Linux kernel on a Banana Pi machine
4*f7d6b772SThomas Huth# and checks the console
5*f7d6b772SThomas Huth#
6*f7d6b772SThomas Huth# SPDX-License-Identifier: GPL-2.0-or-later
7*f7d6b772SThomas Huth
8*f7d6b772SThomas Huthimport os
9*f7d6b772SThomas Huth
10*f7d6b772SThomas Huthfrom qemu_test import LinuxKernelTest, exec_command_and_wait_for_pattern
11*f7d6b772SThomas Huthfrom qemu_test import Asset, interrupt_interactive_console_until_pattern
12*f7d6b772SThomas Huthfrom qemu_test.utils import archive_extract, gzip_uncompress, lzma_uncompress
13*f7d6b772SThomas Huthfrom qemu_test.utils import image_pow2ceil_expand
14*f7d6b772SThomas Huthfrom unittest import skipUnless
15*f7d6b772SThomas Huth
16*f7d6b772SThomas Huthclass BananaPiMachine(LinuxKernelTest):
17*f7d6b772SThomas Huth
18*f7d6b772SThomas Huth    ASSET_DEB = Asset(
19*f7d6b772SThomas Huth        ('https://apt.armbian.com/pool/main/l/linux-6.6.16/'
20*f7d6b772SThomas Huth         'linux-image-current-sunxi_24.2.1_armhf__6.6.16-Seb3e-D6b4a-P2359-Ce96bHfe66-HK01ba-V014b-B067e-R448a.deb'),
21*f7d6b772SThomas Huth        '3d968c15b121ede871dce49d13ee7644d6f74b6b121b84c9a40f51b0c80d6d22')
22*f7d6b772SThomas Huth
23*f7d6b772SThomas Huth    ASSET_INITRD = Asset(
24*f7d6b772SThomas Huth        ('https://github.com/groeck/linux-build-test/raw/'
25*f7d6b772SThomas Huth         '2eb0a73b5d5a28df3170c546ddaaa9757e1e0848/rootfs/'
26*f7d6b772SThomas Huth         'arm/rootfs-armv7a.cpio.gz'),
27*f7d6b772SThomas Huth        '2c8dbdb16ea7af2dfbcbea96044dde639fb07d09fd3c4fb31f2027ef71e55ddd')
28*f7d6b772SThomas Huth
29*f7d6b772SThomas Huth    ASSET_ROOTFS = Asset(
30*f7d6b772SThomas Huth        ('http://storage.kernelci.org/images/rootfs/buildroot/'
31*f7d6b772SThomas Huth         'buildroot-baseline/20230703.0/armel/rootfs.ext2.xz'),
32*f7d6b772SThomas Huth        '42b44a12965ac0afe9a88378527fb698a7dc76af50495efc2361ee1595b4e5c6')
33*f7d6b772SThomas Huth
34*f7d6b772SThomas Huth    ASSET_SD_IMAGE = Asset(
35*f7d6b772SThomas Huth        ('https://downloads.openwrt.org/releases/22.03.3/targets/sunxi/cortexa7/'
36*f7d6b772SThomas Huth         'openwrt-22.03.3-sunxi-cortexa7-sinovoip_bananapi-m2-ultra-ext4-sdcard.img.gz'),
37*f7d6b772SThomas Huth        '5b41b4e11423e562c6011640f9a7cd3bdd0a3d42b83430f7caa70a432e6cd82c')
38*f7d6b772SThomas Huth
39*f7d6b772SThomas Huth    def test_arm_bpim2u(self):
40*f7d6b772SThomas Huth        self.set_machine('bpim2u')
41*f7d6b772SThomas Huth        deb_path = self.ASSET_DEB.fetch()
42*f7d6b772SThomas Huth        kernel_path = self.extract_from_deb(deb_path,
43*f7d6b772SThomas Huth                                            '/boot/vmlinuz-6.6.16-current-sunxi')
44*f7d6b772SThomas Huth        dtb_path = ('/usr/lib/linux-image-6.6.16-current-sunxi/'
45*f7d6b772SThomas Huth                    'sun8i-r40-bananapi-m2-ultra.dtb')
46*f7d6b772SThomas Huth        dtb_path = self.extract_from_deb(deb_path, dtb_path)
47*f7d6b772SThomas Huth
48*f7d6b772SThomas Huth        self.vm.set_console()
49*f7d6b772SThomas Huth        kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
50*f7d6b772SThomas Huth                               'console=ttyS0,115200n8 '
51*f7d6b772SThomas Huth                               'earlycon=uart,mmio32,0x1c28000')
52*f7d6b772SThomas Huth        self.vm.add_args('-kernel', kernel_path,
53*f7d6b772SThomas Huth                         '-dtb', dtb_path,
54*f7d6b772SThomas Huth                         '-append', kernel_command_line)
55*f7d6b772SThomas Huth        self.vm.launch()
56*f7d6b772SThomas Huth        console_pattern = 'Kernel command line: %s' % kernel_command_line
57*f7d6b772SThomas Huth        self.wait_for_console_pattern(console_pattern)
58*f7d6b772SThomas Huth        os.remove(kernel_path)
59*f7d6b772SThomas Huth        os.remove(dtb_path)
60*f7d6b772SThomas Huth
61*f7d6b772SThomas Huth    def test_arm_bpim2u_initrd(self):
62*f7d6b772SThomas Huth        self.set_machine('bpim2u')
63*f7d6b772SThomas Huth        deb_path = self.ASSET_DEB.fetch()
64*f7d6b772SThomas Huth        kernel_path = self.extract_from_deb(deb_path,
65*f7d6b772SThomas Huth                                            '/boot/vmlinuz-6.6.16-current-sunxi')
66*f7d6b772SThomas Huth        dtb_path = ('/usr/lib/linux-image-6.6.16-current-sunxi/'
67*f7d6b772SThomas Huth                    'sun8i-r40-bananapi-m2-ultra.dtb')
68*f7d6b772SThomas Huth        dtb_path = self.extract_from_deb(deb_path, dtb_path)
69*f7d6b772SThomas Huth        initrd_path_gz = self.ASSET_INITRD.fetch()
70*f7d6b772SThomas Huth        initrd_path = os.path.join(self.workdir, 'rootfs.cpio')
71*f7d6b772SThomas Huth        gzip_uncompress(initrd_path_gz, initrd_path)
72*f7d6b772SThomas Huth
73*f7d6b772SThomas Huth        self.vm.set_console()
74*f7d6b772SThomas Huth        kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
75*f7d6b772SThomas Huth                               'console=ttyS0,115200 '
76*f7d6b772SThomas Huth                               'panic=-1 noreboot')
77*f7d6b772SThomas Huth        self.vm.add_args('-kernel', kernel_path,
78*f7d6b772SThomas Huth                         '-dtb', dtb_path,
79*f7d6b772SThomas Huth                         '-initrd', initrd_path,
80*f7d6b772SThomas Huth                         '-append', kernel_command_line,
81*f7d6b772SThomas Huth                         '-no-reboot')
82*f7d6b772SThomas Huth        self.vm.launch()
83*f7d6b772SThomas Huth        self.wait_for_console_pattern('Boot successful.')
84*f7d6b772SThomas Huth
85*f7d6b772SThomas Huth        exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
86*f7d6b772SThomas Huth                                                'Allwinner sun8i Family')
87*f7d6b772SThomas Huth        exec_command_and_wait_for_pattern(self, 'cat /proc/iomem',
88*f7d6b772SThomas Huth                                                'system-control@1c00000')
89*f7d6b772SThomas Huth        exec_command_and_wait_for_pattern(self, 'reboot',
90*f7d6b772SThomas Huth                                                'reboot: Restarting system')
91*f7d6b772SThomas Huth        # Wait for VM to shut down gracefully
92*f7d6b772SThomas Huth        self.vm.wait()
93*f7d6b772SThomas Huth        os.remove(kernel_path)
94*f7d6b772SThomas Huth        os.remove(dtb_path)
95*f7d6b772SThomas Huth        os.remove(initrd_path)
96*f7d6b772SThomas Huth
97*f7d6b772SThomas Huth    def test_arm_bpim2u_gmac(self):
98*f7d6b772SThomas Huth        self.set_machine('bpim2u')
99*f7d6b772SThomas Huth        self.require_netdev('user')
100*f7d6b772SThomas Huth
101*f7d6b772SThomas Huth        deb_path = self.ASSET_DEB.fetch()
102*f7d6b772SThomas Huth        kernel_path = self.extract_from_deb(deb_path,
103*f7d6b772SThomas Huth                                            '/boot/vmlinuz-6.6.16-current-sunxi')
104*f7d6b772SThomas Huth        dtb_path = ('/usr/lib/linux-image-6.6.16-current-sunxi/'
105*f7d6b772SThomas Huth                    'sun8i-r40-bananapi-m2-ultra.dtb')
106*f7d6b772SThomas Huth        dtb_path = self.extract_from_deb(deb_path, dtb_path)
107*f7d6b772SThomas Huth        rootfs_path_xz = self.ASSET_ROOTFS.fetch()
108*f7d6b772SThomas Huth        rootfs_path = os.path.join(self.workdir, 'rootfs.cpio')
109*f7d6b772SThomas Huth        lzma_uncompress(rootfs_path_xz, rootfs_path)
110*f7d6b772SThomas Huth        image_pow2ceil_expand(rootfs_path)
111*f7d6b772SThomas Huth
112*f7d6b772SThomas Huth        self.vm.set_console()
113*f7d6b772SThomas Huth        kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
114*f7d6b772SThomas Huth                               'console=ttyS0,115200 '
115*f7d6b772SThomas Huth                               'root=b300 rootwait rw '
116*f7d6b772SThomas Huth                               'panic=-1 noreboot')
117*f7d6b772SThomas Huth        self.vm.add_args('-kernel', kernel_path,
118*f7d6b772SThomas Huth                         '-dtb', dtb_path,
119*f7d6b772SThomas Huth                         '-drive', 'file=' + rootfs_path + ',if=sd,format=raw',
120*f7d6b772SThomas Huth                         '-net', 'nic,model=gmac,netdev=host_gmac',
121*f7d6b772SThomas Huth                         '-netdev', 'user,id=host_gmac',
122*f7d6b772SThomas Huth                         '-append', kernel_command_line,
123*f7d6b772SThomas Huth                         '-no-reboot')
124*f7d6b772SThomas Huth        self.vm.launch()
125*f7d6b772SThomas Huth        shell_ready = "/bin/sh: can't access tty; job control turned off"
126*f7d6b772SThomas Huth        self.wait_for_console_pattern(shell_ready)
127*f7d6b772SThomas Huth
128*f7d6b772SThomas Huth        exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
129*f7d6b772SThomas Huth                                                'Allwinner sun8i Family')
130*f7d6b772SThomas Huth        exec_command_and_wait_for_pattern(self, 'cat /proc/partitions',
131*f7d6b772SThomas Huth                                                'mmcblk')
132*f7d6b772SThomas Huth        exec_command_and_wait_for_pattern(self, 'ifconfig eth0 up',
133*f7d6b772SThomas Huth                                                 'eth0: Link is Up')
134*f7d6b772SThomas Huth        exec_command_and_wait_for_pattern(self, 'udhcpc eth0',
135*f7d6b772SThomas Huth            'udhcpc: lease of 10.0.2.15 obtained')
136*f7d6b772SThomas Huth        exec_command_and_wait_for_pattern(self, 'ping -c 3 10.0.2.2',
137*f7d6b772SThomas Huth            '3 packets transmitted, 3 packets received, 0% packet loss')
138*f7d6b772SThomas Huth        exec_command_and_wait_for_pattern(self, 'reboot',
139*f7d6b772SThomas Huth                                                'reboot: Restarting system')
140*f7d6b772SThomas Huth        # Wait for VM to shut down gracefully
141*f7d6b772SThomas Huth        self.vm.wait()
142*f7d6b772SThomas Huth        os.remove(kernel_path)
143*f7d6b772SThomas Huth        os.remove(dtb_path)
144*f7d6b772SThomas Huth        os.remove(rootfs_path)
145*f7d6b772SThomas Huth
146*f7d6b772SThomas Huth    @skipUnless(os.getenv('QEMU_TEST_ALLOW_LARGE_STORAGE'), 'storage limited')
147*f7d6b772SThomas Huth    def test_arm_bpim2u_openwrt_22_03_3(self):
148*f7d6b772SThomas Huth        self.set_machine('bpim2u')
149*f7d6b772SThomas Huth        # This test download a 8.9 MiB compressed image and expand it
150*f7d6b772SThomas Huth        # to 127 MiB.
151*f7d6b772SThomas Huth        image_path_gz = self.ASSET_SD_IMAGE.fetch()
152*f7d6b772SThomas Huth        image_path = os.path.join(self.workdir, 'sdcard.img')
153*f7d6b772SThomas Huth        gzip_uncompress(image_path_gz, image_path)
154*f7d6b772SThomas Huth        image_pow2ceil_expand(image_path)
155*f7d6b772SThomas Huth
156*f7d6b772SThomas Huth        self.vm.set_console()
157*f7d6b772SThomas Huth        self.vm.add_args('-drive', 'file=' + image_path + ',if=sd,format=raw',
158*f7d6b772SThomas Huth                         '-nic', 'user',
159*f7d6b772SThomas Huth                         '-no-reboot')
160*f7d6b772SThomas Huth        self.vm.launch()
161*f7d6b772SThomas Huth
162*f7d6b772SThomas Huth        kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
163*f7d6b772SThomas Huth                               'usbcore.nousb '
164*f7d6b772SThomas Huth                               'noreboot')
165*f7d6b772SThomas Huth
166*f7d6b772SThomas Huth        self.wait_for_console_pattern('U-Boot SPL')
167*f7d6b772SThomas Huth
168*f7d6b772SThomas Huth        interrupt_interactive_console_until_pattern(
169*f7d6b772SThomas Huth                self, 'Hit any key to stop autoboot:', '=>')
170*f7d6b772SThomas Huth        exec_command_and_wait_for_pattern(self, "setenv extraargs '" +
171*f7d6b772SThomas Huth                                                kernel_command_line + "'", '=>')
172*f7d6b772SThomas Huth        exec_command_and_wait_for_pattern(self, 'boot', 'Starting kernel ...');
173*f7d6b772SThomas Huth
174*f7d6b772SThomas Huth        self.wait_for_console_pattern(
175*f7d6b772SThomas Huth            'Please press Enter to activate this console.')
176*f7d6b772SThomas Huth
177*f7d6b772SThomas Huth        exec_command_and_wait_for_pattern(self, ' ', 'root@')
178*f7d6b772SThomas Huth
179*f7d6b772SThomas Huth        exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
180*f7d6b772SThomas Huth                                                'Allwinner sun8i Family')
181*f7d6b772SThomas Huth        exec_command_and_wait_for_pattern(self, 'cat /proc/iomem',
182*f7d6b772SThomas Huth                                                'system-control@1c00000')
183*f7d6b772SThomas Huth        os.remove(image_path)
184*f7d6b772SThomas Huth
185*f7d6b772SThomas Huthif __name__ == '__main__':
186*f7d6b772SThomas Huth    LinuxKernelTest.main()
187