1559eaa1eSDavid Hildenbrand /* 2559eaa1eSDavid Hildenbrand * Emulator tests - for s390x CPU instructions that are usually interpreted 3559eaa1eSDavid Hildenbrand * by the hardware 4559eaa1eSDavid Hildenbrand * 5559eaa1eSDavid Hildenbrand * Copyright (c) 2017 Red Hat Inc 6559eaa1eSDavid Hildenbrand * 7559eaa1eSDavid Hildenbrand * Authors: 8559eaa1eSDavid Hildenbrand * David Hildenbrand <david@redhat.com> 9559eaa1eSDavid Hildenbrand * 10559eaa1eSDavid Hildenbrand * This code is free software; you can redistribute it and/or modify it 11559eaa1eSDavid Hildenbrand * under the terms of the GNU Library General Public License version 2. 12559eaa1eSDavid Hildenbrand */ 13559eaa1eSDavid Hildenbrand #include <libcflat.h> 1440c8f4ceSDavid Hildenbrand #include <asm/cpacf.h> 1540c8f4ceSDavid Hildenbrand #include <asm/interrupt.h> 162d0d5f41SDavid Hildenbrand #include <asm/float.h> 17*c2f4799aSClaudio Imbrenda #include <linux/compiler.h> 182d0d5f41SDavid Hildenbrand 192d0d5f41SDavid Hildenbrand struct lowcore *lc = NULL; 20559eaa1eSDavid Hildenbrand 21559eaa1eSDavid Hildenbrand static inline void __test_spm_ipm(uint8_t cc, uint8_t key) 22559eaa1eSDavid Hildenbrand { 23559eaa1eSDavid Hildenbrand uint64_t in = (cc << 28) | (key << 24); 24559eaa1eSDavid Hildenbrand uint64_t out = ~0ULL; 25559eaa1eSDavid Hildenbrand 26559eaa1eSDavid Hildenbrand report_prefix_pushf("cc=%d,key=%x", cc, key); 27559eaa1eSDavid Hildenbrand 28559eaa1eSDavid Hildenbrand asm volatile ("spm %1\n" 29559eaa1eSDavid Hildenbrand "ipm %0\n" 30559eaa1eSDavid Hildenbrand : "+r"(out) : "r"(in) : "cc"); 31559eaa1eSDavid Hildenbrand 32a299895bSThomas Huth report(!(out & 0xc0000000UL), "bit 32 and 33 set to zero"); 33a299895bSThomas Huth report((out & ~0xff000000ULL) == ~0xff000000ULL, 34a299895bSThomas Huth "bit 0-31, 40-63 unchanged"); 35a299895bSThomas Huth report(!((in ^ out) & 0x3f000000UL), "cc and key applied"); 36559eaa1eSDavid Hildenbrand 37559eaa1eSDavid Hildenbrand report_prefix_pop(); 38559eaa1eSDavid Hildenbrand } 39559eaa1eSDavid Hildenbrand 40559eaa1eSDavid Hildenbrand /* Test the SET PROGRAM PARAMETER and INSERT PROGRAM PARAMETER instruction */ 41559eaa1eSDavid Hildenbrand static void test_spm_ipm(void) 42559eaa1eSDavid Hildenbrand { 43559eaa1eSDavid Hildenbrand __test_spm_ipm(0, 0xf); 44559eaa1eSDavid Hildenbrand __test_spm_ipm(1, 0x9); 45559eaa1eSDavid Hildenbrand __test_spm_ipm(2, 0x5); 46559eaa1eSDavid Hildenbrand __test_spm_ipm(3, 0x3); 47559eaa1eSDavid Hildenbrand __test_spm_ipm(0, 0); 48559eaa1eSDavid Hildenbrand } 49559eaa1eSDavid Hildenbrand 50*c2f4799aSClaudio Imbrenda static __always_inline void __test_cpacf(unsigned int opcode, unsigned long func, 5140c8f4ceSDavid Hildenbrand unsigned int r1, unsigned int r2, 5240c8f4ceSDavid Hildenbrand unsigned int r3) 5340c8f4ceSDavid Hildenbrand { 5440c8f4ceSDavid Hildenbrand register unsigned long gr0 asm("0") = func; 5540c8f4ceSDavid Hildenbrand cpacf_mask_t mask; 5640c8f4ceSDavid Hildenbrand register unsigned long gr1 asm("1") = (unsigned long)&mask; 5740c8f4ceSDavid Hildenbrand 5840c8f4ceSDavid Hildenbrand asm volatile(".insn rrf,%[opc] << 16,%[r1],%[r2],%[r3],0\n" 5940c8f4ceSDavid Hildenbrand : : "d" (gr0), "d" (gr1), [opc] "i" (opcode), 6040c8f4ceSDavid Hildenbrand [r1] "i" (r1), [r2] "i" (r2), [r3] "i" (r3)); 6140c8f4ceSDavid Hildenbrand } 6240c8f4ceSDavid Hildenbrand 63*c2f4799aSClaudio Imbrenda static __always_inline void __test_cpacf_r1_odd(unsigned int opcode) 6440c8f4ceSDavid Hildenbrand { 6540c8f4ceSDavid Hildenbrand report_prefix_push("r1 odd"); 6640c8f4ceSDavid Hildenbrand expect_pgm_int(); 6740c8f4ceSDavid Hildenbrand __test_cpacf(opcode, 0, 1, 4, 6); 6840c8f4ceSDavid Hildenbrand check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 6940c8f4ceSDavid Hildenbrand report_prefix_pop(); 7040c8f4ceSDavid Hildenbrand } 7140c8f4ceSDavid Hildenbrand 72*c2f4799aSClaudio Imbrenda static __always_inline void __test_cpacf_r1_null(unsigned int opcode) 7340c8f4ceSDavid Hildenbrand { 7440c8f4ceSDavid Hildenbrand report_prefix_push("r1 null"); 7540c8f4ceSDavid Hildenbrand expect_pgm_int(); 7640c8f4ceSDavid Hildenbrand __test_cpacf(opcode, 0, 0, 4, 6); 7740c8f4ceSDavid Hildenbrand check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 7840c8f4ceSDavid Hildenbrand report_prefix_pop(); 7940c8f4ceSDavid Hildenbrand } 8040c8f4ceSDavid Hildenbrand 81*c2f4799aSClaudio Imbrenda static __always_inline void __test_cpacf_r2_odd(unsigned int opcode) 8240c8f4ceSDavid Hildenbrand { 8340c8f4ceSDavid Hildenbrand report_prefix_push("r2 odd"); 8440c8f4ceSDavid Hildenbrand expect_pgm_int(); 8540c8f4ceSDavid Hildenbrand __test_cpacf(opcode, 0, 2, 3, 6); 8640c8f4ceSDavid Hildenbrand check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 8740c8f4ceSDavid Hildenbrand report_prefix_pop(); 8840c8f4ceSDavid Hildenbrand } 8940c8f4ceSDavid Hildenbrand 90*c2f4799aSClaudio Imbrenda static __always_inline void __test_cpacf_r2_null(unsigned int opcode) 9140c8f4ceSDavid Hildenbrand { 9240c8f4ceSDavid Hildenbrand report_prefix_push("r2 null"); 9340c8f4ceSDavid Hildenbrand expect_pgm_int(); 9440c8f4ceSDavid Hildenbrand __test_cpacf(opcode, 0, 2, 0, 6); 9540c8f4ceSDavid Hildenbrand check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 9640c8f4ceSDavid Hildenbrand report_prefix_pop(); 9740c8f4ceSDavid Hildenbrand } 9840c8f4ceSDavid Hildenbrand 99*c2f4799aSClaudio Imbrenda static __always_inline void __test_cpacf_r3_odd(unsigned int opcode) 10040c8f4ceSDavid Hildenbrand { 10140c8f4ceSDavid Hildenbrand report_prefix_push("r3 odd"); 10240c8f4ceSDavid Hildenbrand expect_pgm_int(); 10340c8f4ceSDavid Hildenbrand __test_cpacf(opcode, 0, 2, 4, 5); 10440c8f4ceSDavid Hildenbrand check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 10540c8f4ceSDavid Hildenbrand report_prefix_pop(); 10640c8f4ceSDavid Hildenbrand } 10740c8f4ceSDavid Hildenbrand 108*c2f4799aSClaudio Imbrenda static __always_inline void __test_cpacf_r3_null(unsigned int opcode) 10940c8f4ceSDavid Hildenbrand { 11040c8f4ceSDavid Hildenbrand report_prefix_push("r3 null"); 11140c8f4ceSDavid Hildenbrand expect_pgm_int(); 11240c8f4ceSDavid Hildenbrand __test_cpacf(opcode, 0, 2, 4, 0); 11340c8f4ceSDavid Hildenbrand check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 11440c8f4ceSDavid Hildenbrand report_prefix_pop(); 11540c8f4ceSDavid Hildenbrand } 11640c8f4ceSDavid Hildenbrand 117*c2f4799aSClaudio Imbrenda static __always_inline void __test_cpacf_mod_bit(unsigned int opcode) 11840c8f4ceSDavid Hildenbrand { 11940c8f4ceSDavid Hildenbrand report_prefix_push("mod bit"); 12040c8f4ceSDavid Hildenbrand expect_pgm_int(); 12140c8f4ceSDavid Hildenbrand __test_cpacf(opcode, CPACF_DECRYPT, 2, 4, 6); 12240c8f4ceSDavid Hildenbrand check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 12340c8f4ceSDavid Hildenbrand report_prefix_pop(); 12440c8f4ceSDavid Hildenbrand } 12540c8f4ceSDavid Hildenbrand 126*c2f4799aSClaudio Imbrenda static __always_inline void __test_cpacf_invalid_func(unsigned int opcode) 12740c8f4ceSDavid Hildenbrand { 12840c8f4ceSDavid Hildenbrand report_prefix_push("invalid subfunction"); 12940c8f4ceSDavid Hildenbrand expect_pgm_int(); 13040c8f4ceSDavid Hildenbrand /* 127 is unassigned for now. We don't simply use any, as HW 13140c8f4ceSDavid Hildenbrand * might simply mask valid codes in query but they might still work */ 13240c8f4ceSDavid Hildenbrand if (cpacf_query_func(opcode, 127)) { 13340c8f4ceSDavid Hildenbrand report_skip("127 not invalid"); 13440c8f4ceSDavid Hildenbrand } else { 13540c8f4ceSDavid Hildenbrand __test_cpacf(opcode, 127, 2, 4, 6); 13640c8f4ceSDavid Hildenbrand } 13740c8f4ceSDavid Hildenbrand check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 13840c8f4ceSDavid Hildenbrand report_prefix_pop(); 13940c8f4ceSDavid Hildenbrand } 14040c8f4ceSDavid Hildenbrand 141*c2f4799aSClaudio Imbrenda static __always_inline void __test_cpacf_invalid_parm(unsigned int opcode) 14240c8f4ceSDavid Hildenbrand { 14340c8f4ceSDavid Hildenbrand report_prefix_push("invalid parm address"); 14440c8f4ceSDavid Hildenbrand expect_pgm_int(); 14540c8f4ceSDavid Hildenbrand __cpacf_query(opcode, (void *) -1); 14640c8f4ceSDavid Hildenbrand check_pgm_int_code(PGM_INT_CODE_ADDRESSING); 14740c8f4ceSDavid Hildenbrand report_prefix_pop(); 14840c8f4ceSDavid Hildenbrand } 14940c8f4ceSDavid Hildenbrand 150*c2f4799aSClaudio Imbrenda static __always_inline void __test_cpacf_protected_parm(unsigned int opcode) 15140c8f4ceSDavid Hildenbrand { 15240c8f4ceSDavid Hildenbrand report_prefix_push("protected parm address"); 15340c8f4ceSDavid Hildenbrand expect_pgm_int(); 15440c8f4ceSDavid Hildenbrand low_prot_enable(); 15540c8f4ceSDavid Hildenbrand __cpacf_query(opcode, (void *) 8); 15640c8f4ceSDavid Hildenbrand low_prot_disable(); 15740c8f4ceSDavid Hildenbrand check_pgm_int_code(PGM_INT_CODE_PROTECTION); 15840c8f4ceSDavid Hildenbrand report_prefix_pop(); 15940c8f4ceSDavid Hildenbrand } 16040c8f4ceSDavid Hildenbrand 161*c2f4799aSClaudio Imbrenda static __always_inline void __test_basic_cpacf_opcode(unsigned int opcode) 16240c8f4ceSDavid Hildenbrand { 16340c8f4ceSDavid Hildenbrand bool mod_bit_allowed = false; 16440c8f4ceSDavid Hildenbrand 16540c8f4ceSDavid Hildenbrand if (!__cpacf_check_opcode(opcode)) { 16640c8f4ceSDavid Hildenbrand report_skip("not available"); 16740c8f4ceSDavid Hildenbrand return; 16840c8f4ceSDavid Hildenbrand } 169a299895bSThomas Huth report(cpacf_query_func(opcode, 0), "query indicated in query"); 17040c8f4ceSDavid Hildenbrand 17140c8f4ceSDavid Hildenbrand switch (opcode) { 17240c8f4ceSDavid Hildenbrand case CPACF_KMCTR: 17340c8f4ceSDavid Hildenbrand __test_cpacf_r3_odd(opcode); 17440c8f4ceSDavid Hildenbrand __test_cpacf_r3_null(opcode); 17540c8f4ceSDavid Hildenbrand /* FALL THROUGH */ 17640c8f4ceSDavid Hildenbrand case CPACF_PRNO: 17740c8f4ceSDavid Hildenbrand case CPACF_KMF: 17840c8f4ceSDavid Hildenbrand case CPACF_KMC: 17940c8f4ceSDavid Hildenbrand case CPACF_KMO: 18040c8f4ceSDavid Hildenbrand case CPACF_KM: 18140c8f4ceSDavid Hildenbrand __test_cpacf_r1_odd(opcode); 18240c8f4ceSDavid Hildenbrand __test_cpacf_r1_null(opcode); 18340c8f4ceSDavid Hildenbrand mod_bit_allowed = true; 18440c8f4ceSDavid Hildenbrand /* FALL THROUGH */ 18540c8f4ceSDavid Hildenbrand case CPACF_KMAC: 18640c8f4ceSDavid Hildenbrand case CPACF_KIMD: 18740c8f4ceSDavid Hildenbrand case CPACF_KLMD: 18840c8f4ceSDavid Hildenbrand __test_cpacf_r2_odd(opcode); 18940c8f4ceSDavid Hildenbrand __test_cpacf_r2_null(opcode); 19040c8f4ceSDavid Hildenbrand break; 19140c8f4ceSDavid Hildenbrand } 19240c8f4ceSDavid Hildenbrand if (!mod_bit_allowed) 19340c8f4ceSDavid Hildenbrand __test_cpacf_mod_bit(opcode); 19440c8f4ceSDavid Hildenbrand __test_cpacf_invalid_func(opcode); 19540c8f4ceSDavid Hildenbrand __test_cpacf_invalid_parm(opcode); 19640c8f4ceSDavid Hildenbrand __test_cpacf_protected_parm(opcode); 19740c8f4ceSDavid Hildenbrand } 19840c8f4ceSDavid Hildenbrand 19940c8f4ceSDavid Hildenbrand /* COMPUTE MESSAGE AUTHENTICATION CODE */ 20040c8f4ceSDavid Hildenbrand static void test_kmac(void) 20140c8f4ceSDavid Hildenbrand { 20240c8f4ceSDavid Hildenbrand __test_basic_cpacf_opcode(CPACF_KMAC); 20340c8f4ceSDavid Hildenbrand } 20440c8f4ceSDavid Hildenbrand 20540c8f4ceSDavid Hildenbrand /* CIPHER MESSAGE */ 20640c8f4ceSDavid Hildenbrand static void test_km(void) 20740c8f4ceSDavid Hildenbrand { 20840c8f4ceSDavid Hildenbrand __test_basic_cpacf_opcode(CPACF_KM); 20940c8f4ceSDavid Hildenbrand } 21040c8f4ceSDavid Hildenbrand /* CIPHER MESSAGE WITH CHAINING */ 21140c8f4ceSDavid Hildenbrand static void test_kmc(void) 21240c8f4ceSDavid Hildenbrand { 21340c8f4ceSDavid Hildenbrand __test_basic_cpacf_opcode(CPACF_KMC); 21440c8f4ceSDavid Hildenbrand } 21540c8f4ceSDavid Hildenbrand 21640c8f4ceSDavid Hildenbrand /* COMPUTE INTERMEDIATE MESSAGE DIGEST */ 21740c8f4ceSDavid Hildenbrand static void test_kimd(void) 21840c8f4ceSDavid Hildenbrand { 21940c8f4ceSDavid Hildenbrand __test_basic_cpacf_opcode(CPACF_KIMD); 22040c8f4ceSDavid Hildenbrand } 22140c8f4ceSDavid Hildenbrand 22240c8f4ceSDavid Hildenbrand /* COMPUTE LAST MESSAGE DIGEST */ 22340c8f4ceSDavid Hildenbrand static void test_klmd(void) 22440c8f4ceSDavid Hildenbrand { 22540c8f4ceSDavid Hildenbrand __test_basic_cpacf_opcode(CPACF_KLMD); 22640c8f4ceSDavid Hildenbrand } 22740c8f4ceSDavid Hildenbrand 22840c8f4ceSDavid Hildenbrand /* PERFORM CRYPTOGRAPHIC KEY MANAGEMENT OPERATION */ 22940c8f4ceSDavid Hildenbrand static void test_pckmo(void) 23040c8f4ceSDavid Hildenbrand { 23140c8f4ceSDavid Hildenbrand __test_basic_cpacf_opcode(CPACF_PCKMO); 23240c8f4ceSDavid Hildenbrand } 23340c8f4ceSDavid Hildenbrand 23440c8f4ceSDavid Hildenbrand /* CIPHER MESSAGE WITH CIPHER FEEDBACK */ 23540c8f4ceSDavid Hildenbrand static void test_kmf(void) 23640c8f4ceSDavid Hildenbrand { 23740c8f4ceSDavid Hildenbrand __test_basic_cpacf_opcode(CPACF_KMF); 23840c8f4ceSDavid Hildenbrand } 23940c8f4ceSDavid Hildenbrand 24040c8f4ceSDavid Hildenbrand /* PERFORM CRYPTOGRAPHIC KEY MANAGEMENT OPERATION */ 24140c8f4ceSDavid Hildenbrand static void test_kmo(void) 24240c8f4ceSDavid Hildenbrand { 24340c8f4ceSDavid Hildenbrand __test_basic_cpacf_opcode(CPACF_KMO); 24440c8f4ceSDavid Hildenbrand } 24540c8f4ceSDavid Hildenbrand 24640c8f4ceSDavid Hildenbrand /* PERFORM CRYPTOGRAPHIC COMPUTATION */ 24740c8f4ceSDavid Hildenbrand static void test_pcc(void) 24840c8f4ceSDavid Hildenbrand { 24940c8f4ceSDavid Hildenbrand __test_basic_cpacf_opcode(CPACF_PCC); 25040c8f4ceSDavid Hildenbrand } 25140c8f4ceSDavid Hildenbrand 25240c8f4ceSDavid Hildenbrand /* CIPHER MESSAGE WITH COUNTER */ 25340c8f4ceSDavid Hildenbrand static void test_kmctr(void) 25440c8f4ceSDavid Hildenbrand { 25540c8f4ceSDavid Hildenbrand __test_basic_cpacf_opcode(CPACF_KMCTR); 25640c8f4ceSDavid Hildenbrand } 25740c8f4ceSDavid Hildenbrand 25840c8f4ceSDavid Hildenbrand /* PERFORM RANDOM NUMBER OPERATION (formerly PPNO) */ 25940c8f4ceSDavid Hildenbrand static void test_prno(void) 26040c8f4ceSDavid Hildenbrand { 26140c8f4ceSDavid Hildenbrand __test_basic_cpacf_opcode(CPACF_PRNO); 26240c8f4ceSDavid Hildenbrand } 26340c8f4ceSDavid Hildenbrand 2642d0d5f41SDavid Hildenbrand static void test_dxc(void) 2652d0d5f41SDavid Hildenbrand { 2662d0d5f41SDavid Hildenbrand /* DXC (0xff) is to be stored in LC and FPC on a trap (CRT) with AFP */ 2672d0d5f41SDavid Hildenbrand lc->dxc_vxc = 0x12345678; 2682d0d5f41SDavid Hildenbrand set_fpc_dxc(0); 2692d0d5f41SDavid Hildenbrand 27099ee877dSJanosch Frank report_prefix_push("afp"); 2712d0d5f41SDavid Hildenbrand expect_pgm_int(); 2722d0d5f41SDavid Hildenbrand asm volatile(" .insn rrf,0xb9600000,%0,%0,8,0\n" 2732d0d5f41SDavid Hildenbrand : : "r"(0) : "memory"); 2742d0d5f41SDavid Hildenbrand check_pgm_int_code(PGM_INT_CODE_DATA); 2752d0d5f41SDavid Hildenbrand 276a299895bSThomas Huth report(lc->dxc_vxc == 0xff, "dxc in LC"); 277a299895bSThomas Huth report(get_fpc_dxc() == 0xff, "dxc in FPC"); 27899ee877dSJanosch Frank report_prefix_pop(); 2792d0d5f41SDavid Hildenbrand 2802d0d5f41SDavid Hildenbrand /* DXC (0xff) is to be stored in LC only on a trap (CRT) without AFP */ 2812d0d5f41SDavid Hildenbrand lc->dxc_vxc = 0x12345678; 2822d0d5f41SDavid Hildenbrand set_fpc_dxc(0); 2832d0d5f41SDavid Hildenbrand 28499ee877dSJanosch Frank report_prefix_push("no-afp"); 2852d0d5f41SDavid Hildenbrand expect_pgm_int(); 2862d0d5f41SDavid Hildenbrand /* temporarily disable AFP */ 2872d0d5f41SDavid Hildenbrand afp_disable(); 2882d0d5f41SDavid Hildenbrand asm volatile(" .insn rrf,0xb9600000,%0,%0,8,0\n" 2892d0d5f41SDavid Hildenbrand : : "r"(0) : "memory"); 2902d0d5f41SDavid Hildenbrand afp_enable(); 2912d0d5f41SDavid Hildenbrand check_pgm_int_code(PGM_INT_CODE_DATA); 2922d0d5f41SDavid Hildenbrand 293a299895bSThomas Huth report(lc->dxc_vxc == 0xff, "dxc in LC"); 294a299895bSThomas Huth report(get_fpc_dxc() == 0, "dxc not in FPC"); 29599ee877dSJanosch Frank report_prefix_pop(); 2962d0d5f41SDavid Hildenbrand } 2972d0d5f41SDavid Hildenbrand 298559eaa1eSDavid Hildenbrand static struct { 299559eaa1eSDavid Hildenbrand const char *name; 300559eaa1eSDavid Hildenbrand void (*func)(void); 301559eaa1eSDavid Hildenbrand } tests[] = { 302559eaa1eSDavid Hildenbrand { "spm/ipm", test_spm_ipm }, 30340c8f4ceSDavid Hildenbrand { "kmac", test_kmac }, 30440c8f4ceSDavid Hildenbrand { "km", test_km }, 30540c8f4ceSDavid Hildenbrand { "kmc", test_kmc }, 30640c8f4ceSDavid Hildenbrand { "kimd", test_kimd }, 30740c8f4ceSDavid Hildenbrand { "klmd", test_klmd }, 30840c8f4ceSDavid Hildenbrand { "pckmo", test_pckmo }, 30940c8f4ceSDavid Hildenbrand { "kmf", test_kmf }, 31040c8f4ceSDavid Hildenbrand { "kmo", test_kmo }, 31140c8f4ceSDavid Hildenbrand { "pcc", test_pcc }, 31240c8f4ceSDavid Hildenbrand { "kmctr", test_kmctr }, 31340c8f4ceSDavid Hildenbrand { "prno", test_prno }, 3142d0d5f41SDavid Hildenbrand { "dxc", test_dxc }, 315559eaa1eSDavid Hildenbrand { NULL, NULL } 316559eaa1eSDavid Hildenbrand }; 317559eaa1eSDavid Hildenbrand 318559eaa1eSDavid Hildenbrand int main(int argc, char**argv) 319559eaa1eSDavid Hildenbrand { 320559eaa1eSDavid Hildenbrand int i; 321559eaa1eSDavid Hildenbrand 322559eaa1eSDavid Hildenbrand report_prefix_push("emulator"); 323559eaa1eSDavid Hildenbrand for (i = 0; tests[i].name; i++) { 324559eaa1eSDavid Hildenbrand report_prefix_push(tests[i].name); 325559eaa1eSDavid Hildenbrand tests[i].func(); 326559eaa1eSDavid Hildenbrand report_prefix_pop(); 327559eaa1eSDavid Hildenbrand } 328559eaa1eSDavid Hildenbrand report_prefix_pop(); 329559eaa1eSDavid Hildenbrand 330559eaa1eSDavid Hildenbrand return report_summary(); 331559eaa1eSDavid Hildenbrand } 332