[PATCH 8/8] tests/functional: Add a hexagon minivm test

Brian Cain posted 8 patches 3 days, 9 hours ago
[PATCH 8/8] tests/functional: Add a hexagon minivm test
Posted by Brian Cain 3 days, 9 hours ago
From: Brian Cain <bcain@quicinc.com>

Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 MAINTAINERS                             |  1 +
 tests/functional/meson.build            |  8 +++++
 tests/functional/test_hexagon_minivm.py | 42 +++++++++++++++++++++++++
 3 files changed, 51 insertions(+)
 create mode 100755 tests/functional/test_hexagon_minivm.py

diff --git a/MAINTAINERS b/MAINTAINERS
index deeb7878c8..48a5e7c005 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -247,6 +247,7 @@ F: gdb-xml/hexagon*.xml
 F: docs/system/target-hexagon.rst
 F: docs/devel/hexagon-sys.rst
 F: docs/devel/hexagon-l2vic.rst
+F: tests/functional/test_hexagon_minivm.py
 T: git https://github.com/quic/qemu.git hex-next
 
 Hexagon idef-parser
diff --git a/tests/functional/meson.build b/tests/functional/meson.build
index 111d8bab26..78b42e58f9 100644
--- a/tests/functional/meson.build
+++ b/tests/functional/meson.build
@@ -135,6 +135,14 @@ tests_i386_system_quick = [
   'migration',
 ]
 
+test_timeouts += {
+  'hexagon_minivm': 180,
+}
+
+tests_hexagon_system_quick = [
+  'hexagon_minivm',
+]
+
 tests_i386_system_thorough = [
   'i386_tuxrun',
 ]
diff --git a/tests/functional/test_hexagon_minivm.py b/tests/functional/test_hexagon_minivm.py
new file mode 100755
index 0000000000..2ba92bcce3
--- /dev/null
+++ b/tests/functional/test_hexagon_minivm.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python3
+#
+# Copyright(c) 2024-2025 Qualcomm Innovation Center, Inc. All Rights Reserved.
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+from glob import glob
+from qemu_test import QemuSystemTest, Asset
+from qemu_test import wait_for_console_pattern
+
+class MiniVMTest(QemuSystemTest):
+
+    timeout = 180
+    GUEST_ENTRY = 0xc0000000
+
+    REPO = 'https://artifacts.codelinaro.org/artifactory'
+    ASSET_TARBALL = \
+        Asset(f'{REPO}/codelinaro-toolchain-for-hexagon/'
+               '19.1.5/hexagon_minivm_2024_Dec_15.tar.gz',
+        'd7920b5ff14bed5a10b23ada7d4eb927ede08635281f25067e0d5711feee2c2a')
+
+    def test_minivm(self):
+        self.set_machine('virt')
+        self.archive_extract(self.ASSET_TARBALL)
+        rootfs_path = f'{self.workdir}/hexagon-unknown-linux-musl-rootfs'
+        kernel_path = f'{rootfs_path}/boot/minivm'
+
+        assert(os.path.exists(kernel_path))
+        for test_bin_path in glob(f'{rootfs_path}/boot/test_*'):
+            print(f'# Testing "{os.path.basename(test_bin_path)}"')
+
+            vm = self.get_vm()
+            vm.add_args('-kernel', kernel_path,
+                  '-device',
+                  f'loader,addr={hex(self.GUEST_ENTRY)},file={test_bin_path}')
+            vm.launch()
+            vm.wait()
+            self.assertEqual(vm.exitcode(), 0)
+
+if __name__ == '__main__':
+    QemuSystemTest.main()
-- 
2.34.1

Re: [PATCH 8/8] tests/functional: Add a hexagon minivm test
Posted by Philippe Mathieu-Daudé 10 hours ago
Hi Brian,

On 1/3/25 18:20, Brian Cain wrote:
> From: Brian Cain <bcain@quicinc.com>

A bit opaque...

> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> ---
>   MAINTAINERS                             |  1 +
>   tests/functional/meson.build            |  8 +++++
>   tests/functional/test_hexagon_minivm.py | 42 +++++++++++++++++++++++++
>   3 files changed, 51 insertions(+)
>   create mode 100755 tests/functional/test_hexagon_minivm.py
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index deeb7878c8..48a5e7c005 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -247,6 +247,7 @@ F: gdb-xml/hexagon*.xml
>   F: docs/system/target-hexagon.rst
>   F: docs/devel/hexagon-sys.rst
>   F: docs/devel/hexagon-l2vic.rst
> +F: tests/functional/test_hexagon_minivm.py
>   T: git https://github.com/quic/qemu.git hex-next
>   
>   Hexagon idef-parser
> diff --git a/tests/functional/meson.build b/tests/functional/meson.build
> index 111d8bab26..78b42e58f9 100644
> --- a/tests/functional/meson.build
> +++ b/tests/functional/meson.build
> @@ -135,6 +135,14 @@ tests_i386_system_quick = [
>     'migration',
>   ]
>   
> +test_timeouts += {
> +  'hexagon_minivm': 180,
> +}
> +
> +tests_hexagon_system_quick = [
> +  'hexagon_minivm',
> +]
> +
>   tests_i386_system_thorough = [
>     'i386_tuxrun',
>   ]
> diff --git a/tests/functional/test_hexagon_minivm.py b/tests/functional/test_hexagon_minivm.py
> new file mode 100755
> index 0000000000..2ba92bcce3
> --- /dev/null
> +++ b/tests/functional/test_hexagon_minivm.py
> @@ -0,0 +1,42 @@
> +#!/usr/bin/env python3
> +#
> +# Copyright(c) 2024-2025 Qualcomm Innovation Center, Inc. All Rights Reserved.
> +#
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +
> +import os
> +from glob import glob
> +from qemu_test import QemuSystemTest, Asset
> +from qemu_test import wait_for_console_pattern
> +
> +class MiniVMTest(QemuSystemTest):
> +
> +    timeout = 180
> +    GUEST_ENTRY = 0xc0000000
> +
> +    REPO = 'https://artifacts.codelinaro.org/artifactory'
> +    ASSET_TARBALL = \
> +        Asset(f'{REPO}/codelinaro-toolchain-for-hexagon/'
> +               '19.1.5/hexagon_minivm_2024_Dec_15.tar.gz',
> +        'd7920b5ff14bed5a10b23ada7d4eb927ede08635281f25067e0d5711feee2c2a')
> +
> +    def test_minivm(self):
> +        self.set_machine('virt')
> +        self.archive_extract(self.ASSET_TARBALL)
> +        rootfs_path = f'{self.workdir}/hexagon-unknown-linux-musl-rootfs'
> +        kernel_path = f'{rootfs_path}/boot/minivm'

$ readelf -h hexagon-unknown-linux-musl-rootfs/boot/minivm
   Entry point address:               0xffff0000

I suppose this is a bootloader which runs guest code at
GUEST_ENTRY = 0xc0000000.

> +
> +        assert(os.path.exists(kernel_path))
> +        for test_bin_path in glob(f'{rootfs_path}/boot/test_*'):
> +            print(f'# Testing "{os.path.basename(test_bin_path)}"')

$ ls -1 hexagon-unknown-linux-musl-rootfs/boot/test_*
hexagon-unknown-linux-musl-rootfs/boot/test_interrupts
hexagon-unknown-linux-musl-rootfs/boot/test_mmu
hexagon-unknown-linux-musl-rootfs/boot/test_processors

I'd rather 1 test per binary to easily see which one failed.

> +
> +            vm = self.get_vm()
> +            vm.add_args('-kernel', kernel_path,
> +                  '-device',
> +                  f'loader,addr={hex(self.GUEST_ENTRY)},file={test_bin_path}')
> +            vm.launch()
> +            vm.wait()
> +            self.assertEqual(vm.exitcode(), 0)

...
----------------
IN:
0xc0000000:  0x6a09c019 { R25 = C9/pc }
0xc0000004:  0x00004040 { immext(#0x1000)
0xc0000008:  0x7800c018  R24 = ##0x1000 }
0xc000000c:  0xf318d918 { R24 = add(R24,R25) }
0xc0000010:  0x00004000 { immext(#0x0)
0xc0000014:  0x7800c03a  R26 = ##0x1 }
0xc0000018:  0x0c004000 { immext(#0xc0000000)
0xc000001c:  0x7800c001  R1 = ##0xc0000000 }
0xc0000020:  0x0ffc4000 { immext(#0xffc00000)
0xc0000024:  0x7601c001  R1 = and(R1,##0xffc00000) }
0xc0000028:  0x8c01d622 { R2 = lsr(R1,#0x16) }
0xc000002c:  0xc402d840 { R0 = addasl(R24,R2,#0x2) }
0xc0000030:  0xb0e1f8a1 { R1 = add(R1,#0xfc5) }
0xc0000034:  0x00044000 { immext(#0x400000)
0xc0000038:  0x7800c002  R2 = ##0x400000 }
0xc000003c:  0x601ac008 { loop0(PC+4,R26) }
0xc0000040:  0xab80c108 { memw(R0++#0x4) = R1 }
0xc0000044:  0xf3018201 { R1 = add(R1,R2)
0xc0000048:  0x7f00c000  nop }  :endloop0
...
do_raise_exception: 0x00000002, @ 20000090
  hexagon_cpu_do_interrupt: event 0x2:(null), cause 0x25(37)
  hexagon_cpu_do_interrupt: event 0x9:HEX_EVENT_TRAP1, cause 0x1(1)
0x20000104:  0x5400c000 { trap0(#0x0) }

  hexagon_cpu_do_interrupt: event 0x8:HEX_EVENT_TRAP0, cause 0x0(0)
  hexagon_cpu_do_interrupt: event 0x9:HEX_EVENT_TRAP1, cause 0x1(1)

0xc00002a0:  0x7060c002 { R2 = R0 }
0xc00002a4:  0x5480c20c { trap1(R0,#0x13) }

  hexagon_cpu_do_interrupt: event 0x9:HEX_EVENT_TRAP1, cause 0x13(19)
0xffff0518:  0x5800c02a { jump PC+84 }
0xffff056c:  0x6460c000 { stop(R0) }

How can we be sure errors won't exit(0) or hang?

(qemu) info mtree
address-space: memory
   0000000000000000-ffffffffffffffff (prio 0, i/o): system
     0000000000000000-00000000ffffffff (prio 0, ram): ddr.ram
     0000000010000000-0000000010000fff (prio 0, i/o): pl011
     0000000011000000-00000000110001ff (prio 0, i/o): virtio-mmio
     0000000012000000-00000000120001ff (prio 0, i/o): virtio-mmio
     00000000d81e0000-00000000d81effff (prio 0, i/o): fast
     00000000d8400000-00000000d87fffff (prio 0, ram): vtcm.ram
     00000000de000000-00000000de0001ff (prio 0, rom): config_table.rom
     00000000fc910000-00000000fc910fff (prio 0, i/o): l2vic

Could we have minimal debug output on the console?

> +
> +if __name__ == '__main__':
> +    QemuSystemTest.main()

Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org>


Re: [PATCH 8/8] tests/functional: Add a hexagon minivm test
Posted by Brian Cain 10 hours ago
On 3/4/2025 9:46 AM, Philippe Mathieu-Daudé wrote:
> Hi Brian,
>
> On 1/3/25 18:20, Brian Cain wrote:
>> From: Brian Cain <bcain@quicinc.com>
>
> A bit opaque...
>
Whoops -- will fix it.
>> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
>> ---
>>   MAINTAINERS                             |  1 +
>>   tests/functional/meson.build            |  8 +++++
>>   tests/functional/test_hexagon_minivm.py | 42 +++++++++++++++++++++++++
>>   3 files changed, 51 insertions(+)
>>   create mode 100755 tests/functional/test_hexagon_minivm.py
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index deeb7878c8..48a5e7c005 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -247,6 +247,7 @@ F: gdb-xml/hexagon*.xml
>>   F: docs/system/target-hexagon.rst
>>   F: docs/devel/hexagon-sys.rst
>>   F: docs/devel/hexagon-l2vic.rst
>> +F: tests/functional/test_hexagon_minivm.py
>>   T: git https://github.com/quic/qemu.git hex-next
>>     Hexagon idef-parser
>> diff --git a/tests/functional/meson.build b/tests/functional/meson.build
>> index 111d8bab26..78b42e58f9 100644
>> --- a/tests/functional/meson.build
>> +++ b/tests/functional/meson.build
>> @@ -135,6 +135,14 @@ tests_i386_system_quick = [
>>     'migration',
>>   ]
>>   +test_timeouts += {
>> +  'hexagon_minivm': 180,
>> +}
>> +
>> +tests_hexagon_system_quick = [
>> +  'hexagon_minivm',
>> +]
>> +
>>   tests_i386_system_thorough = [
>>     'i386_tuxrun',
>>   ]
>> diff --git a/tests/functional/test_hexagon_minivm.py 
>> b/tests/functional/test_hexagon_minivm.py
>> new file mode 100755
>> index 0000000000..2ba92bcce3
>> --- /dev/null
>> +++ b/tests/functional/test_hexagon_minivm.py
>> @@ -0,0 +1,42 @@
>> +#!/usr/bin/env python3
>> +#
>> +# Copyright(c) 2024-2025 Qualcomm Innovation Center, Inc. All Rights 
>> Reserved.
>> +#
>> +# SPDX-License-Identifier: GPL-2.0-or-later
>> +
>> +import os
>> +from glob import glob
>> +from qemu_test import QemuSystemTest, Asset
>> +from qemu_test import wait_for_console_pattern
>> +
>> +class MiniVMTest(QemuSystemTest):
>> +
>> +    timeout = 180
>> +    GUEST_ENTRY = 0xc0000000
>> +
>> +    REPO = 'https://artifacts.codelinaro.org/artifactory'
>> +    ASSET_TARBALL = \
>> +        Asset(f'{REPO}/codelinaro-toolchain-for-hexagon/'
>> +               '19.1.5/hexagon_minivm_2024_Dec_15.tar.gz',
>> + 'd7920b5ff14bed5a10b23ada7d4eb927ede08635281f25067e0d5711feee2c2a')
>> +
>> +    def test_minivm(self):
>> +        self.set_machine('virt')
>> +        self.archive_extract(self.ASSET_TARBALL)
>> +        rootfs_path = 
>> f'{self.workdir}/hexagon-unknown-linux-musl-rootfs'
>> +        kernel_path = f'{rootfs_path}/boot/minivm'
>
> $ readelf -h hexagon-unknown-linux-musl-rootfs/boot/minivm
>   Entry point address:               0xffff0000
>
> I suppose this is a bootloader which runs guest code at
> GUEST_ENTRY = 0xc0000000.
>
Yes, this is indeed the case.  The source for minivm and the test cases 
is found at https://github.com/quic/hexagonMVM
>> +
>> +        assert(os.path.exists(kernel_path))
>> +        for test_bin_path in glob(f'{rootfs_path}/boot/test_*'):
>> +            print(f'# Testing "{os.path.basename(test_bin_path)}"')
>
> $ ls -1 hexagon-unknown-linux-musl-rootfs/boot/test_*
> hexagon-unknown-linux-musl-rootfs/boot/test_interrupts
> hexagon-unknown-linux-musl-rootfs/boot/test_mmu
> hexagon-unknown-linux-musl-rootfs/boot/test_processors
>
> I'd rather 1 test per binary to easily see which one failed.
>
Okay, I'll make that change.
>> +
>> +            vm = self.get_vm()
>> +            vm.add_args('-kernel', kernel_path,
>> +                  '-device',
>> + f'loader,addr={hex(self.GUEST_ENTRY)},file={test_bin_path}')
>> +            vm.launch()
>> +            vm.wait()
>> +            self.assertEqual(vm.exitcode(), 0)
>
> ...
> ----------------
> IN:
> 0xc0000000:  0x6a09c019 { R25 = C9/pc }
> 0xc0000004:  0x00004040 { immext(#0x1000)
> 0xc0000008:  0x7800c018  R24 = ##0x1000 }
> 0xc000000c:  0xf318d918 { R24 = add(R24,R25) }
> 0xc0000010:  0x00004000 { immext(#0x0)
> 0xc0000014:  0x7800c03a  R26 = ##0x1 }
> 0xc0000018:  0x0c004000 { immext(#0xc0000000)
> 0xc000001c:  0x7800c001  R1 = ##0xc0000000 }
> 0xc0000020:  0x0ffc4000 { immext(#0xffc00000)
> 0xc0000024:  0x7601c001  R1 = and(R1,##0xffc00000) }
> 0xc0000028:  0x8c01d622 { R2 = lsr(R1,#0x16) }
> 0xc000002c:  0xc402d840 { R0 = addasl(R24,R2,#0x2) }
> 0xc0000030:  0xb0e1f8a1 { R1 = add(R1,#0xfc5) }
> 0xc0000034:  0x00044000 { immext(#0x400000)
> 0xc0000038:  0x7800c002  R2 = ##0x400000 }
> 0xc000003c:  0x601ac008 { loop0(PC+4,R26) }
> 0xc0000040:  0xab80c108 { memw(R0++#0x4) = R1 }
> 0xc0000044:  0xf3018201 { R1 = add(R1,R2)
> 0xc0000048:  0x7f00c000  nop }  :endloop0
> ...
> do_raise_exception: 0x00000002, @ 20000090
>  hexagon_cpu_do_interrupt: event 0x2:(null), cause 0x25(37)
>  hexagon_cpu_do_interrupt: event 0x9:HEX_EVENT_TRAP1, cause 0x1(1)
> 0x20000104:  0x5400c000 { trap0(#0x0) }
>
>  hexagon_cpu_do_interrupt: event 0x8:HEX_EVENT_TRAP0, cause 0x0(0)
>  hexagon_cpu_do_interrupt: event 0x9:HEX_EVENT_TRAP1, cause 0x1(1)
>
> 0xc00002a0:  0x7060c002 { R2 = R0 }
> 0xc00002a4:  0x5480c20c { trap1(R0,#0x13) }
>
>  hexagon_cpu_do_interrupt: event 0x9:HEX_EVENT_TRAP1, cause 0x13(19)
> 0xffff0518:  0x5800c02a { jump PC+84 }
> 0xffff056c:  0x6460c000 { stop(R0) }
>
> How can we be sure errors won't exit(0) or hang?
>
The most likely failure mode for errors seems like a hang to me. Which 
is good that it's at least detected but I would agree that it would be 
preferable to
> (qemu) info mtree
> address-space: memory
>   0000000000000000-ffffffffffffffff (prio 0, i/o): system
>     0000000000000000-00000000ffffffff (prio 0, ram): ddr.ram
>     0000000010000000-0000000010000fff (prio 0, i/o): pl011
>     0000000011000000-00000000110001ff (prio 0, i/o): virtio-mmio
>     0000000012000000-00000000120001ff (prio 0, i/o): virtio-mmio
>     00000000d81e0000-00000000d81effff (prio 0, i/o): fast
>     00000000d8400000-00000000d87fffff (prio 0, ram): vtcm.ram
>     00000000de000000-00000000de0001ff (prio 0, rom): config_table.rom
>     00000000fc910000-00000000fc910fff (prio 0, i/o): l2vic
>
> Could we have minimal debug output on the console?
>
Hmm - there's no UART support in minivm nor its tests.  But it is easy 
enough to add debug output via semihosting.  Since semihosting spec is 
still under review, I've omitted that from these initial series.


How about we revise the minivm tests to emit some debug output and we 
can also use that kind of thing to verify correctness?  But would it 
suffice to land the test design as-is and follow up after semihosting 
lands?  Or would you prefer to see semihosting be included

>> +
>> +if __name__ == '__main__':
>> +    QemuSystemTest.main()
>
> Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org>
>

Re: [PATCH 8/8] tests/functional: Add a hexagon minivm test
Posted by Brian Cain 5 hours ago
On 3/4/2025 10:15 AM, Brian Cain wrote:
>
> On 3/4/2025 9:46 AM, Philippe Mathieu-Daudé wrote:
>> Hi Brian,
>>
>> On 1/3/25 18:20, Brian Cain wrote:
>>> From: Brian Cain <bcain@quicinc.com>
>>
>> A bit opaque...
>>
> Whoops -- will fix it.
>>> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
>>> ---
>>>   MAINTAINERS                             |  1 +
>>>   tests/functional/meson.build            |  8 +++++
>>>   tests/functional/test_hexagon_minivm.py | 42 
>>> +++++++++++++++++++++++++
>>>   3 files changed, 51 insertions(+)
>>>   create mode 100755 tests/functional/test_hexagon_minivm.py
>>>
>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>> index deeb7878c8..48a5e7c005 100644
>>> --- a/MAINTAINERS
>>> +++ b/MAINTAINERS
>>> @@ -247,6 +247,7 @@ F: gdb-xml/hexagon*.xml
>>>   F: docs/system/target-hexagon.rst
>>>   F: docs/devel/hexagon-sys.rst
>>>   F: docs/devel/hexagon-l2vic.rst
>>> +F: tests/functional/test_hexagon_minivm.py
>>>   T: git https://github.com/quic/qemu.git hex-next
>>>     Hexagon idef-parser
>>> diff --git a/tests/functional/meson.build 
>>> b/tests/functional/meson.build
>>> index 111d8bab26..78b42e58f9 100644
>>> --- a/tests/functional/meson.build
>>> +++ b/tests/functional/meson.build
>>> @@ -135,6 +135,14 @@ tests_i386_system_quick = [
>>>     'migration',
>>>   ]
>>>   +test_timeouts += {
>>> +  'hexagon_minivm': 180,
>>> +}
>>> +
>>> +tests_hexagon_system_quick = [
>>> +  'hexagon_minivm',
>>> +]
>>> +
>>>   tests_i386_system_thorough = [
>>>     'i386_tuxrun',
>>>   ]
>>> diff --git a/tests/functional/test_hexagon_minivm.py 
>>> b/tests/functional/test_hexagon_minivm.py
>>> new file mode 100755
>>> index 0000000000..2ba92bcce3
>>> --- /dev/null
>>> +++ b/tests/functional/test_hexagon_minivm.py
>>> @@ -0,0 +1,42 @@
>>> +#!/usr/bin/env python3
>>> +#
>>> +# Copyright(c) 2024-2025 Qualcomm Innovation Center, Inc. All 
>>> Rights Reserved.
>>> +#
>>> +# SPDX-License-Identifier: GPL-2.0-or-later
>>> +
>>> +import os
>>> +from glob import glob
>>> +from qemu_test import QemuSystemTest, Asset
>>> +from qemu_test import wait_for_console_pattern
>>> +
>>> +class MiniVMTest(QemuSystemTest):
>>> +
>>> +    timeout = 180
>>> +    GUEST_ENTRY = 0xc0000000
>>> +
>>> +    REPO = 'https://artifacts.codelinaro.org/artifactory'
>>> +    ASSET_TARBALL = \
>>> +        Asset(f'{REPO}/codelinaro-toolchain-for-hexagon/'
>>> +               '19.1.5/hexagon_minivm_2024_Dec_15.tar.gz',
>>> + 'd7920b5ff14bed5a10b23ada7d4eb927ede08635281f25067e0d5711feee2c2a')
>>> +
>>> +    def test_minivm(self):
>>> +        self.set_machine('virt')
>>> +        self.archive_extract(self.ASSET_TARBALL)
>>> +        rootfs_path = 
>>> f'{self.workdir}/hexagon-unknown-linux-musl-rootfs'
>>> +        kernel_path = f'{rootfs_path}/boot/minivm'
>>
>> $ readelf -h hexagon-unknown-linux-musl-rootfs/boot/minivm
>>   Entry point address:               0xffff0000
>>
>> I suppose this is a bootloader which runs guest code at
>> GUEST_ENTRY = 0xc0000000.
>>
> Yes, this is indeed the case.  The source for minivm and the test 
> cases is found at https://github.com/quic/hexagonMVM
>>> +
>>> +        assert(os.path.exists(kernel_path))
>>> +        for test_bin_path in glob(f'{rootfs_path}/boot/test_*'):
>>> +            print(f'# Testing "{os.path.basename(test_bin_path)}"')
>>
>> $ ls -1 hexagon-unknown-linux-musl-rootfs/boot/test_*
>> hexagon-unknown-linux-musl-rootfs/boot/test_interrupts
>> hexagon-unknown-linux-musl-rootfs/boot/test_mmu
>> hexagon-unknown-linux-musl-rootfs/boot/test_processors
>>
>> I'd rather 1 test per binary to easily see which one failed.
>>
> Okay, I'll make that change.
>>> +
>>> +            vm = self.get_vm()
>>> +            vm.add_args('-kernel', kernel_path,
>>> +                  '-device',
>>> + f'loader,addr={hex(self.GUEST_ENTRY)},file={test_bin_path}')
>>> +            vm.launch()
>>> +            vm.wait()
>>> +            self.assertEqual(vm.exitcode(), 0)
>>
>> ...
>> ----------------
>> IN:
>> 0xc0000000:  0x6a09c019 { R25 = C9/pc }
>> 0xc0000004:  0x00004040 { immext(#0x1000)
>> 0xc0000008:  0x7800c018  R24 = ##0x1000 }
>> 0xc000000c:  0xf318d918 { R24 = add(R24,R25) }
>> 0xc0000010:  0x00004000 { immext(#0x0)
>> 0xc0000014:  0x7800c03a  R26 = ##0x1 }
>> 0xc0000018:  0x0c004000 { immext(#0xc0000000)
>> 0xc000001c:  0x7800c001  R1 = ##0xc0000000 }
>> 0xc0000020:  0x0ffc4000 { immext(#0xffc00000)
>> 0xc0000024:  0x7601c001  R1 = and(R1,##0xffc00000) }
>> 0xc0000028:  0x8c01d622 { R2 = lsr(R1,#0x16) }
>> 0xc000002c:  0xc402d840 { R0 = addasl(R24,R2,#0x2) }
>> 0xc0000030:  0xb0e1f8a1 { R1 = add(R1,#0xfc5) }
>> 0xc0000034:  0x00044000 { immext(#0x400000)
>> 0xc0000038:  0x7800c002  R2 = ##0x400000 }
>> 0xc000003c:  0x601ac008 { loop0(PC+4,R26) }
>> 0xc0000040:  0xab80c108 { memw(R0++#0x4) = R1 }
>> 0xc0000044:  0xf3018201 { R1 = add(R1,R2)
>> 0xc0000048:  0x7f00c000  nop }  :endloop0
>> ...
>> do_raise_exception: 0x00000002, @ 20000090
>>  hexagon_cpu_do_interrupt: event 0x2:(null), cause 0x25(37)
>>  hexagon_cpu_do_interrupt: event 0x9:HEX_EVENT_TRAP1, cause 0x1(1)
>> 0x20000104:  0x5400c000 { trap0(#0x0) }
>>
>>  hexagon_cpu_do_interrupt: event 0x8:HEX_EVENT_TRAP0, cause 0x0(0)
>>  hexagon_cpu_do_interrupt: event 0x9:HEX_EVENT_TRAP1, cause 0x1(1)
>>
>> 0xc00002a0:  0x7060c002 { R2 = R0 }
>> 0xc00002a4:  0x5480c20c { trap1(R0,#0x13) }
>>
>>  hexagon_cpu_do_interrupt: event 0x9:HEX_EVENT_TRAP1, cause 0x13(19)
>> 0xffff0518:  0x5800c02a { jump PC+84 }
>> 0xffff056c:  0x6460c000 { stop(R0) }
>>
>> How can we be sure errors won't exit(0) or hang?
>>
> The most likely failure mode for errors seems like a hang to me. Which 
> is good that it's at least detected but I would agree that it would be 
> preferable to
>> (qemu) info mtree
>> address-space: memory
>>   0000000000000000-ffffffffffffffff (prio 0, i/o): system
>>     0000000000000000-00000000ffffffff (prio 0, ram): ddr.ram
>>     0000000010000000-0000000010000fff (prio 0, i/o): pl011
>>     0000000011000000-00000000110001ff (prio 0, i/o): virtio-mmio
>>     0000000012000000-00000000120001ff (prio 0, i/o): virtio-mmio
>>     00000000d81e0000-00000000d81effff (prio 0, i/o): fast
>>     00000000d8400000-00000000d87fffff (prio 0, ram): vtcm.ram
>>     00000000de000000-00000000de0001ff (prio 0, rom): config_table.rom
>>     00000000fc910000-00000000fc910fff (prio 0, i/o): l2vic
>>
>> Could we have minimal debug output on the console?
>>
> Hmm - there's no UART support in minivm nor its tests.  But it is easy 
> enough to add debug output via semihosting.  Since semihosting spec is 
> still under review, I've omitted that from these initial series.
>
>
> How about we revise the minivm tests to emit some debug output and we 
> can also use that kind of thing to verify correctness?  But would it 
> suffice to land the test design as-is and follow up after semihosting 
> lands?  Or would you prefer to see semihosting be included
>

Oh - I see these tests do already emit `PASS` or `FAIL` via 
semihosting.  See 
https://github.com/quic/hexagonMVM/blob/ca5704e8fd7aa0b856c947933fca045ff7a9dadd/tests/test_processors.S#L109-L116 
for an example.

Would it be okay to just check for this output after that semihosting 
lands?  And do you prefer more detailed debug output beyond PASS/FAIL?


>>> +
>>> +if __name__ == '__main__':
>>> +    QemuSystemTest.main()
>>
>> Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org>
>>

Re: [PATCH 8/8] tests/functional: Add a hexagon minivm test
Posted by Brian Cain 10 hours ago
On 3/4/2025 9:46 AM, Philippe Mathieu-Daudé wrote:
> Hi Brian,
>
> On 1/3/25 18:20, Brian Cain wrote:
>> From: Brian Cain <bcain@quicinc.com>
>
> A bit opaque...
>
Whoops -- will fix it.
>> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
>> ---
>>   MAINTAINERS                             |  1 +
>>   tests/functional/meson.build            |  8 +++++
>>   tests/functional/test_hexagon_minivm.py | 42 +++++++++++++++++++++++++
>>   3 files changed, 51 insertions(+)
>>   create mode 100755 tests/functional/test_hexagon_minivm.py
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index deeb7878c8..48a5e7c005 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -247,6 +247,7 @@ F: gdb-xml/hexagon*.xml
>>   F: docs/system/target-hexagon.rst
>>   F: docs/devel/hexagon-sys.rst
>>   F: docs/devel/hexagon-l2vic.rst
>> +F: tests/functional/test_hexagon_minivm.py
>>   T: git https://github.com/quic/qemu.git hex-next
>>     Hexagon idef-parser
>> diff --git a/tests/functional/meson.build b/tests/functional/meson.build
>> index 111d8bab26..78b42e58f9 100644
>> --- a/tests/functional/meson.build
>> +++ b/tests/functional/meson.build
>> @@ -135,6 +135,14 @@ tests_i386_system_quick = [
>>     'migration',
>>   ]
>>   +test_timeouts += {
>> +  'hexagon_minivm': 180,
>> +}
>> +
>> +tests_hexagon_system_quick = [
>> +  'hexagon_minivm',
>> +]
>> +
>>   tests_i386_system_thorough = [
>>     'i386_tuxrun',
>>   ]
>> diff --git a/tests/functional/test_hexagon_minivm.py 
>> b/tests/functional/test_hexagon_minivm.py
>> new file mode 100755
>> index 0000000000..2ba92bcce3
>> --- /dev/null
>> +++ b/tests/functional/test_hexagon_minivm.py
>> @@ -0,0 +1,42 @@
>> +#!/usr/bin/env python3
>> +#
>> +# Copyright(c) 2024-2025 Qualcomm Innovation Center, Inc. All Rights 
>> Reserved.
>> +#
>> +# SPDX-License-Identifier: GPL-2.0-or-later
>> +
>> +import os
>> +from glob import glob
>> +from qemu_test import QemuSystemTest, Asset
>> +from qemu_test import wait_for_console_pattern
>> +
>> +class MiniVMTest(QemuSystemTest):
>> +
>> +    timeout = 180
>> +    GUEST_ENTRY = 0xc0000000
>> +
>> +    REPO = 'https://artifacts.codelinaro.org/artifactory'
>> +    ASSET_TARBALL = \
>> +        Asset(f'{REPO}/codelinaro-toolchain-for-hexagon/'
>> +               '19.1.5/hexagon_minivm_2024_Dec_15.tar.gz',
>> + 'd7920b5ff14bed5a10b23ada7d4eb927ede08635281f25067e0d5711feee2c2a')
>> +
>> +    def test_minivm(self):
>> +        self.set_machine('virt')
>> +        self.archive_extract(self.ASSET_TARBALL)
>> +        rootfs_path = 
>> f'{self.workdir}/hexagon-unknown-linux-musl-rootfs'
>> +        kernel_path = f'{rootfs_path}/boot/minivm'
>
> $ readelf -h hexagon-unknown-linux-musl-rootfs/boot/minivm
>   Entry point address:               0xffff0000
>
> I suppose this is a bootloader which runs guest code at
> GUEST_ENTRY = 0xc0000000.
>
Yes, this is indeed the case.  The source for minivm and the test cases 
is found at https://github.com/quic/hexagonMVM
>> +
>> +        assert(os.path.exists(kernel_path))
>> +        for test_bin_path in glob(f'{rootfs_path}/boot/test_*'):
>> +            print(f'# Testing "{os.path.basename(test_bin_path)}"')
>
> $ ls -1 hexagon-unknown-linux-musl-rootfs/boot/test_*
> hexagon-unknown-linux-musl-rootfs/boot/test_interrupts
> hexagon-unknown-linux-musl-rootfs/boot/test_mmu
> hexagon-unknown-linux-musl-rootfs/boot/test_processors
>
> I'd rather 1 test per binary to easily see which one failed.
>
Okay, I'll make that change.
>> +
>> +            vm = self.get_vm()
>> +            vm.add_args('-kernel', kernel_path,
>> +                  '-device',
>> + f'loader,addr={hex(self.GUEST_ENTRY)},file={test_bin_path}')
>> +            vm.launch()
>> +            vm.wait()
>> +            self.assertEqual(vm.exitcode(), 0)
>
> ...
> ----------------
> IN:
> 0xc0000000:  0x6a09c019 { R25 = C9/pc }
> 0xc0000004:  0x00004040 { immext(#0x1000)
> 0xc0000008:  0x7800c018  R24 = ##0x1000 }
> 0xc000000c:  0xf318d918 { R24 = add(R24,R25) }
> 0xc0000010:  0x00004000 { immext(#0x0)
> 0xc0000014:  0x7800c03a  R26 = ##0x1 }
> 0xc0000018:  0x0c004000 { immext(#0xc0000000)
> 0xc000001c:  0x7800c001  R1 = ##0xc0000000 }
> 0xc0000020:  0x0ffc4000 { immext(#0xffc00000)
> 0xc0000024:  0x7601c001  R1 = and(R1,##0xffc00000) }
> 0xc0000028:  0x8c01d622 { R2 = lsr(R1,#0x16) }
> 0xc000002c:  0xc402d840 { R0 = addasl(R24,R2,#0x2) }
> 0xc0000030:  0xb0e1f8a1 { R1 = add(R1,#0xfc5) }
> 0xc0000034:  0x00044000 { immext(#0x400000)
> 0xc0000038:  0x7800c002  R2 = ##0x400000 }
> 0xc000003c:  0x601ac008 { loop0(PC+4,R26) }
> 0xc0000040:  0xab80c108 { memw(R0++#0x4) = R1 }
> 0xc0000044:  0xf3018201 { R1 = add(R1,R2)
> 0xc0000048:  0x7f00c000  nop }  :endloop0
> ...
> do_raise_exception: 0x00000002, @ 20000090
>  hexagon_cpu_do_interrupt: event 0x2:(null), cause 0x25(37)
>  hexagon_cpu_do_interrupt: event 0x9:HEX_EVENT_TRAP1, cause 0x1(1)
> 0x20000104:  0x5400c000 { trap0(#0x0) }
>
>  hexagon_cpu_do_interrupt: event 0x8:HEX_EVENT_TRAP0, cause 0x0(0)
>  hexagon_cpu_do_interrupt: event 0x9:HEX_EVENT_TRAP1, cause 0x1(1)
>
> 0xc00002a0:  0x7060c002 { R2 = R0 }
> 0xc00002a4:  0x5480c20c { trap1(R0,#0x13) }
>
>  hexagon_cpu_do_interrupt: event 0x9:HEX_EVENT_TRAP1, cause 0x13(19)
> 0xffff0518:  0x5800c02a { jump PC+84 }
> 0xffff056c:  0x6460c000 { stop(R0) }
>
> How can we be sure errors won't exit(0) or hang?
>
The most likely failure mode for errors seems like a hang to me. Which 
is good that it's at least detected but I would agree that it would be 
preferable to
> (qemu) info mtree
> address-space: memory
>   0000000000000000-ffffffffffffffff (prio 0, i/o): system
>     0000000000000000-00000000ffffffff (prio 0, ram): ddr.ram
>     0000000010000000-0000000010000fff (prio 0, i/o): pl011
>     0000000011000000-00000000110001ff (prio 0, i/o): virtio-mmio
>     0000000012000000-00000000120001ff (prio 0, i/o): virtio-mmio
>     00000000d81e0000-00000000d81effff (prio 0, i/o): fast
>     00000000d8400000-00000000d87fffff (prio 0, ram): vtcm.ram
>     00000000de000000-00000000de0001ff (prio 0, rom): config_table.rom
>     00000000fc910000-00000000fc910fff (prio 0, i/o): l2vic
>
> Could we have minimal debug output on the console?
>
Hmm - there's no UART support in minivm nor its tests.  But it is easy 
enough to add debug output via semihosting.  Since semihosting spec is 
still under review, I've omitted that from these initial series.


How about we revise the minivm tests to emit some debug output and we 
can also use that kind of thing to verify correctness?  But would it 
suffice to land the test design as-is and follow up after semihosting 
lands?  Or would you prefer to see semihosting be included here before 
this test is enabled?

>> +
>> +if __name__ == '__main__':
>> +    QemuSystemTest.main()
>
> Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org>
>