| 1 | #!/usr/bin/env python3 |
| 2 | # |
| 3 | # Copyright (c) 2025 MIPS |
| 4 | # |
| 5 | # SPDX-License-Identifier: GPL-2.0-or-later |
| 6 | # |
| 7 | """ |
| 8 | Boston board test for RISC-V P8700 processor by MIPS |
| 9 | """ |
| 10 | |
| 11 | from subprocess import run |
| 12 | |
| 13 | from qemu_test import QemuSystemTest, Asset |
| 14 | from qemu_test import wait_for_console_pattern |
| 15 | |
| 16 | |
| 17 | class RiscvBostonTest(QemuSystemTest): |
| 18 | """ |
| 19 | Test the boston-aia board with P8700 processor |
| 20 | """ |
| 21 | |
| 22 | ASSET_FW_PAYLOAD = Asset( |
| 23 | 'https://github.com/MIPS/linux-test-downloads/raw/main/p8700/fw_payload.bin', |
| 24 | 'd6f4ae14d0c178c1d0bb38ddf64557536ca8602a588b220729a8aa17caa383aa') |
| 25 | |
| 26 | ASSET_ROOTFS = Asset( |
| 27 | 'https://github.com/MIPS/linux-test-downloads/raw/main/p8700/rootfs.ext2', |
| 28 | 'f937e21b588f0d1d17d10a063053979686897bbbbc5e9617a5582f7c1f48e565') |
| 29 | |
| 30 | def _boot_linux_test(self, smp_count): |
| 31 | """Common setup and boot test for Linux on Boston board |
| 32 | |
| 33 | Args: |
| 34 | smp_count: Number of CPUs to use for SMP |
| 35 | """ |
| 36 | self.set_machine('boston-aia') |
| 37 | fw_payload_path = self.ASSET_FW_PAYLOAD.fetch() |
| 38 | rootfs_path = self.ASSET_ROOTFS.fetch() |
| 39 | |
| 40 | self.vm.add_args('-cpu', 'mips-p8700') |
| 41 | self.vm.add_args('-m', '2G') |
| 42 | self.vm.add_args('-smp', str(smp_count)) |
| 43 | self.vm.add_args('-kernel', fw_payload_path) |
| 44 | self.vm.add_args('-drive', f'file={rootfs_path},format=raw,snapshot=on') |
| 45 | |
| 46 | self.vm.set_console() |
| 47 | self.vm.launch() |
| 48 | |
| 49 | # Wait for OpenSBI |
| 50 | wait_for_console_pattern(self, 'OpenSBI') |
| 51 | |
| 52 | # Wait for Linux kernel boot |
| 53 | wait_for_console_pattern(self, 'Linux version') |
| 54 | wait_for_console_pattern(self, 'Machine model: MIPS P8700') |
| 55 | |
| 56 | # Test e1000e network card functionality |
| 57 | wait_for_console_pattern(self, 'e1000e') |
| 58 | wait_for_console_pattern(self, 'Network Connection') |
| 59 | |
| 60 | # Wait for boot to complete - system reaches login prompt |
| 61 | wait_for_console_pattern(self, 'Run /sbin/init as init process') |
| 62 | |
| 63 | def test_boston_boot_linux_min_cpus(self): |
| 64 | """ |
| 65 | Test Linux kernel boot with minimum CPU count (2) |
| 66 | """ |
| 67 | self._boot_linux_test(smp_count=2) |
| 68 | |
| 69 | def test_boston_boot_linux_max_cpus(self): |
| 70 | """ |
| 71 | Test Linux kernel boot with maximum supported CPU count (64) |
| 72 | """ |
| 73 | self._boot_linux_test(smp_count=64) |
| 74 | |
| 75 | def test_boston_invalid_cpu_count(self): |
| 76 | """ |
| 77 | Test that 65 CPUs is rejected as invalid (negative test case) |
| 78 | """ |
| 79 | |
| 80 | fw_payload_path = self.ASSET_FW_PAYLOAD.fetch() |
| 81 | rootfs_path = self.ASSET_ROOTFS.fetch() |
| 82 | |
| 83 | cmd = [ |
| 84 | self.qemu_bin, |
| 85 | '-M', 'boston-aia', |
| 86 | '-cpu', 'mips-p8700', |
| 87 | '-m', '2G', |
| 88 | '-smp', '65', |
| 89 | '-kernel', fw_payload_path, |
| 90 | '-drive', f'file={rootfs_path},format=raw,snapshot=on', |
| 91 | '-nographic' |
| 92 | ] |
| 93 | |
| 94 | # Run QEMU and expect it to fail immediately. |
| 95 | result = run(cmd, capture_output=True, text=True, timeout=5, |
| 96 | check=False) |
| 97 | |
| 98 | # Check that QEMU exited with error code 1 |
| 99 | self.assertEqual(result.returncode, 1, |
| 100 | "QEMU should exit with code 1 for invalid SMP count") |
| 101 | |
| 102 | # Check error message |
| 103 | self.assertIn('Invalid SMP CPUs 65', result.stderr, |
| 104 | "Error message should indicate invalid SMP CPU count") |
| 105 | |
| 106 | if __name__ == '__main__': |
| 107 | QemuSystemTest.main() |