1 2 /* 3 gcc -g -o v8memory_a -march=armv8-a -mfpu=crypto-neon-fp-armv8 \ 4 none/tests/arm/v8memory.c -I. -Wall -marm 5 6 gcc -g -o v8memory_t -march=armv8-a -mfpu=crypto-neon-fp-armv8 \ 7 none/tests/arm/v8memory.c -I. -Wall -mthumb 8 */ 9 10 /* These tests unfortunately are unable to check the relative 11 placement (or, even, presence) of the required memory fences 12 relative to the store/load required. They only verify the 13 data-movement component. */ 14 15 #include <stdio.h> 16 #include <malloc.h> // memalign 17 #include <string.h> // memset 18 #include "tests/malloc.h" 19 #include <assert.h> 20 21 typedef unsigned char UChar; 22 typedef unsigned short int UShort; 23 typedef unsigned int UInt; 24 typedef signed int Int; 25 typedef unsigned char UChar; 26 typedef signed long long int Long; 27 typedef unsigned long long int ULong; 28 29 typedef unsigned char Bool; 30 #define False ((Bool)0) 31 #define True ((Bool)1) 32 33 static inline UChar randUChar ( void ) 34 { 35 static UInt seed = 90210; // Somewhere in Beverly Hills, allegedly. 36 seed = 1103515245 * seed + 12345; 37 return (seed >> 17) & 0xFF; 38 } 39 40 static UInt randUInt ( void ) 41 { 42 Int i; 43 UInt r = 0; 44 for (i = 0; i < 4; i++) { 45 r = (r << 8) | (UInt)(0xFF & randUChar()); 46 } 47 return r; 48 } 49 50 static void show_block_xor ( UChar* block1, UChar* block2, Int n ) 51 { 52 Int i; 53 printf(" "); 54 for (i = 0; i < n; i++) { 55 if (i > 0 && 0 == (i & 15)) printf("\n "); 56 if (0 == (i & 15)) printf("[%3d] ", i); 57 UInt diff = 0xFF & (UInt)(block1[i] - block2[i]); 58 if (diff == 0) 59 printf(".. "); 60 else 61 printf("%02x ", diff); 62 } 63 printf("\n"); 64 } 65 66 67 // INSN may mention the following regs as containing load/store data: 68 // r2 r3 r6 r9 69 // INSN must mention the following reg as containing the EA: r10 70 // 71 // INSN can use r4 and r5 as scratch 72 // 73 // In: rand: memory area (128 bytes), r2, r3, r6, r9 74 // r10 pointing to middle of memory area 75 // 76 // Out: memory area, r2, r3, r6, r9, r10 77 // 78 // What is printed out: the XOR of the new and old versions of the 79 // following: 80 // the memory area 81 // r2, r3 r6 r9 r10 82 83 #define MEM_TEST(INSN) { \ 84 int i; \ 85 const int N = 128; \ 86 UChar* area1 = memalign16(N); \ 87 UChar* area2 = memalign16(N); \ 88 for (i = 0; i < N; i++) area1[i] = area2[i] = randUChar(); \ 89 UInt block1[5]; \ 90 UInt block2[5]; \ 91 /* 0:r2 1:r3 2:r6 3:r9 4:r10 */ \ 92 for (i = 0; i < 5; i++) block1[i] = block2[i] = randUInt(); \ 93 block1[4] = block2[4] = (UInt)(&area1[N/2]); \ 94 __asm__ __volatile__( \ 95 "ldr r2, [%0, #0] ; " \ 96 "ldr r3, [%0, #4] ; " \ 97 "ldr r6, [%0, #8] ; " \ 98 "ldr r9, [%0, #12] ; " \ 99 "ldr r10, [%0, #16] ; " \ 100 INSN " ; " \ 101 "str r2, [%0, #0] ; " \ 102 "str r3, [%0, #4] ; " \ 103 "str r6, [%0, #8] ; " \ 104 "str r9, [%0, #12] ; " \ 105 "str r10, [%0, #16] ; " \ 106 : : "r"(&block1[0]) : "r2", "r3", "r4", "r5", "r6", "r9", "r10", \ 107 "memory", "cc" \ 108 ); \ 109 printf("%s with r10 = middle_of_block\n", INSN); \ 110 show_block_xor(&area1[0], &area2[0], N); \ 111 printf(" %08x r2 (xor, data intreg #1)\n", block1[0] ^ block2[0]); \ 112 printf(" %08x r3 (xor, data intreg #2)\n", block1[1] ^ block2[1]); \ 113 printf(" %08x r6 (xor, data intreg #3)\n", block1[2] ^ block2[2]); \ 114 printf(" %08x r9 (xor, data intreg #4)\n", block1[3] ^ block2[3]); \ 115 printf(" %08x r10 (xor, addr intreg #1)\n", block1[4] ^ block2[4]); \ 116 printf("\n"); \ 117 free(area1); free(area2); \ 118 } 119 120 121 int main ( void ) 122 { 123 //////////////////////////////////////////////////////////////// 124 printf("LDA{,B,H} (reg)\n\n"); 125 MEM_TEST("lda r6, [r10]") 126 MEM_TEST("ldab r9, [r10]") 127 MEM_TEST("ldah r3, [r10]") 128 129 //////////////////////////////////////////////////////////////// 130 printf("STL{,B,H} (reg)\n\n"); 131 MEM_TEST("stl r6, [r10]") 132 MEM_TEST("stlb r9, [r10]") 133 MEM_TEST("stlh r3, [r10]") 134 135 //////////////////////////////////////////////////////////////// 136 printf("LDAEX{,B,H,D} (reg)\n\n"); 137 MEM_TEST("ldaex r6, [r10]") 138 MEM_TEST("ldaexb r9, [r10]") 139 MEM_TEST("ldaexh r3, [r10]") 140 MEM_TEST("ldaexd r2, r3, [r10]") 141 142 //////////////////////////////////////////////////////////////// 143 // These verify that stlex* do notice a cleared (missing) reservation. 144 printf("STLEX{,B,H,D} (reg) -- expected to fail\n\n"); 145 MEM_TEST("clrex; stlex r9, r6, [r10]") 146 MEM_TEST("clrex; stlexb r9, r6, [r10]") 147 MEM_TEST("clrex; stlexh r9, r3, [r10]") 148 MEM_TEST("clrex; stlexd r9, r2, r3, [r10]") 149 150 //////////////////////////////////////////////////////////////// 151 // These verify that stlex* do notice a successful reservation. 152 // By using ldaex* to create the reservation in the first place, 153 // they also verify that ldaex* actually create a reservation. 154 printf("STLEX{,B,H,D} (reg) -- expected to succeed\n\n"); 155 MEM_TEST("ldaex r2, [r10] ; stlex r9, r6, [r10]") 156 MEM_TEST("ldaexb r2, [r10] ; stlexb r9, r6, [r10]") 157 MEM_TEST("ldaexh r2, [r10] ; stlexh r9, r3, [r10]") 158 MEM_TEST("mov r4, r2 ; mov r5, r3 ; " // preserve r2/r3 around the ldrexd 159 "ldaexd r2, r3, [r10] ; " 160 "mov r2, r4 ; mov r3, r5 ; " 161 "stlexd r9, r2, r3, [r10]") 162 163 return 0; 164 } 165