Home | History | Annotate | Download | only in s390x
      1 #include <stdio.h>
      2 #include <stdint.h>
      3 #include <inttypes.h>
      4 #include <assert.h>
      5 
      6 /* The golden logs were obtained by running this test natively. */
      7 
      8 /* The abstracted result of a CLCL insn */
      9 typedef struct {
     10   uint64_t addr1;
     11   uint32_t len1;
     12   uint64_t addr2;
     13   uint32_t len2;
     14   uint8_t  pad;
     15   uint32_t cc;
     16 } clcl_t;
     17 
     18 /* Register contents after CLCL insn */
     19 typedef struct {
     20   uint64_t r1;
     21   uint64_t r1p1;
     22   uint64_t r2;
     23   uint64_t r2p1;
     24   uint64_t cc;
     25 } clcl_regs;
     26 
     27 /* Run a single CLCL insn and return its raw result. */
     28 static clcl_regs
     29 do_clcl(uint64_t r1, uint64_t r1p1, uint64_t r2, uint64_t r2p1)
     30 {
     31   clcl_regs regs;
     32 
     33   register uint64_t a1 asm ("2") = r1;
     34   register uint64_t l1 asm ("3") = r1p1;
     35   register uint64_t a2 asm ("4") = r2;
     36   register uint64_t l2 asm ("5") = r2p1;
     37   register uint32_t cc asm ("7");
     38 
     39   asm volatile(	"0: clcl 2,4\n\t"
     40                 "jo 0b\n\t"
     41                 "ipm %0\n\t"
     42                 "srl %0,28\n\t"
     43                 :"=d" (cc), "+d" (a1),"+d" (l1), "+d" (a2), "+d" (l2)
     44                 : : "memory", "cc");
     45 
     46   regs.r1   = a1;
     47   regs.r1p1 = l1;
     48   regs.r2   = a2;
     49   regs.r2p1 = l2;
     50   regs.cc   = cc;
     51 
     52   return regs;
     53 }
     54 
     55 clcl_t
     56 result_from_regs(clcl_regs regs)
     57 {
     58   clcl_t result;
     59 
     60   result.addr1 = regs.r1;
     61   result.len1  = regs.r1p1 & 0xFFFFFF;
     62   result.addr2 = regs.r2;
     63   result.len2  = regs.r2p1 & 0xFFFFFF;
     64   result.pad   = (regs.r2p1 & 0xFF000000u) >> 24;
     65   result.cc    = regs.cc;
     66 
     67   return result;
     68 }
     69 
     70 /* Run CLCL twice using different fill bits for unused register bits.
     71    Results ought to be the same */
     72 static clcl_t
     73 clcl(void *addr1, uint32_t len1,
     74      void *addr2, uint32_t len2, uint32_t pad)
     75 {
     76   clcl_t result1, result2;
     77   clcl_regs regs;
     78   uint64_t r1, r1p1, r2, r2p1;
     79 
     80   /* Check input arguments */
     81   assert((pad & 0xFF) == pad);  /* an 8-byte value */
     82   assert((len1 & 0xFFFFFF) == len1);
     83   assert((len2 & 0xFFFFFF) == len2);
     84 
     85   /* Build up register contents setting unused bits to 0 */
     86   r1   = (uint64_t)addr1;
     87   r1p1 = len1;
     88   r2   = (uint64_t)addr2;
     89   r2p1 = len2 | (pad << 24);
     90 
     91   /* Run clcl */
     92   regs = do_clcl(r1, r1p1, r2, r2p1);
     93   result1 = result_from_regs(regs);
     94 
     95   /* Check unused bits */
     96   if ((regs.r1p1 >> 24) != 0)
     97     printf("FAIL: r1[0:39] modified (unused bits 0)\n");
     98   if ((regs.r2p1 >> 32) != 0)
     99     printf("FAIL: r2[0:31] modified (unused bits 0)\n");
    100 
    101   /* Check pad value */
    102   if (result1.pad != pad)
    103     printf("FAIL: pad byte modified (unused bits 0)\n");
    104 
    105   /* Build up register contents setting unused bits to 1 */
    106   r1p1 |= 0xFFFFFFFFFFull << 24;
    107   r2p1 |= ((uint64_t)0xFFFFFFFF) << 32;
    108 
    109   /* Run clcl again */
    110   regs = do_clcl(r1, r1p1, r2, r2p1);
    111   result2 = result_from_regs(regs);
    112 
    113   /* Check unused bits */
    114   if ((regs.r1p1 >> 24) != 0xFFFFFFFFFFull)
    115     printf("FAIL: r1[0:39] modified (unused bits 1)\n");
    116   if ((regs.r2p1 >> 32) != 0xFFFFFFFFu)
    117     printf("FAIL: r2[0:31] modified (unused bits 1)\n");
    118 
    119   /* Check pad value */
    120   if (result2.pad != pad)
    121     printf("FAIL: pad byte modified (unused bits 1)\n");
    122 
    123   /* Compare results */
    124   if (result1.addr1 != result2.addr1)
    125     printf("FAIL: addr1 result is different\n");
    126   if (result1.addr2 != result2.addr2)
    127     printf("FAIL: addr2 result is different\n");
    128   if (result1.len1 != result2.len1)
    129     printf("FAIL: len1 result is different\n");
    130   if (result1.len2 != result2.len2)
    131     printf("FAIL: len2 result is different\n");
    132   if (result1.pad != result2.pad)
    133     printf("FAIL: pad result is different\n");
    134   if (result1.cc != result2.cc)
    135     printf("FAIL: cc result is different\n");
    136 
    137   return result1;
    138 }
    139 
    140 void
    141 run_test(void *addr1, uint32_t len1, void *addr2, uint32_t len2, uint32_t pad)
    142 {
    143   clcl_t result;
    144 
    145   result = clcl(addr1, len1, addr2, len2, pad);
    146 
    147   printf("cc: %"PRIu32", len1: %"PRIu32", len2: %"PRIu32
    148          ", addr1 diff: %"PRId64", addr2 diff: %"PRId64"\n", result.cc,
    149          result.len1, result.len2, (int64_t)result.addr1 - (int64_t)addr1,
    150          (int64_t)result.addr2 - (int64_t)addr2);
    151 }
    152 
    153 int main()
    154 {
    155   uint8_t byte, byte1, byte2;
    156 
    157   /* Test 1: both lengths are 0; nothing loaded from memory */
    158   printf("--- test 1 ---\n");
    159   run_test(NULL, 0, NULL, 0, 0x00);
    160   run_test(NULL, 0, NULL, 0, 0xff);
    161 
    162   /* Test 2: Compare two single bytes */
    163   printf("--- test 2 ---\n");
    164   byte1 = 10;
    165   byte2 = 20;
    166   run_test(&byte1, 1, &byte2, 1, 0x00);  // first operand low
    167   run_test(&byte1, 1, &byte1, 1, 0x00);  // equal
    168   run_test(&byte2, 1, &byte1, 1, 0x00);  // first operand high
    169   run_test(&byte1, 1, &byte2, 1, 0xFF);  // first operand low
    170   run_test(&byte1, 1, &byte1, 1, 0xFF);  // equal
    171   run_test(&byte2, 1, &byte1, 1, 0xFF);  // first operand high
    172 
    173   /* Test 3: Compare a single byte against the pad byte */
    174   printf("--- test 3 ---\n");
    175   byte = 10;
    176   run_test(NULL, 0, &byte, 1, 10);  // equal
    177   run_test(NULL, 0, &byte, 1,  9);  // first operand low
    178   run_test(NULL, 0, &byte, 1, 11);  // first operand high
    179   /* Swap operands */
    180   run_test(&byte, 1, NULL, 0, 10);  // equal
    181   run_test(&byte, 1, NULL, 0,  9);  // first operand high
    182   run_test(&byte, 1, NULL, 0, 11);  // first operand low
    183 
    184   /* Test 4: Make sure pad byte is interpreted as unsigned value */
    185   printf("--- test 4 ---\n");
    186   byte = 10;
    187   run_test(&byte, 1, NULL, 0, 0xFF);  // first operand low
    188   byte = 0xFF;
    189   run_test(&byte, 1, NULL, 0, 0xFF);  // equal
    190 
    191   /* Test 5: Compare a buffer against the pad byte */
    192   printf("--- test 5 ---\n");
    193   uint8_t buf1[4] = "yyyy";
    194   run_test(buf1, 4, NULL, 0, 'y');    // equal
    195   run_test(buf1, 4, NULL, 0, 'x');    // greater
    196   run_test(buf1, 4, NULL, 0, 'z');    // less
    197 
    198   /* Test 6: Compare two buffers of same size (difference in 1st byte) */
    199   {
    200   printf("--- test 6 ---\n");
    201   uint8_t x[5] = "pqrst";
    202   uint8_t y[5] = "abcde";
    203   uint8_t z[5] = "abcde";
    204   run_test(x, 5, y, 5, 'a');   // first operand low
    205   run_test(y, 5, x, 5, 'a');   // first operand high
    206   run_test(y, 5, z, 5, 'q');   // equal
    207   }
    208 
    209   /* Test 7: Compare two buffers of same size (difference in last byte) */
    210   {
    211   printf("--- test 7 ---\n");
    212   uint8_t x[5] = "abcdd";
    213   uint8_t y[5] = "abcde";
    214   uint8_t z[5] = "abcdf";
    215   run_test(x, 5, y, 5, 'a');   // first operand low
    216   run_test(z, 5, z, 5, 'a');   // first operand high
    217   }
    218 
    219   /* Test 8: Compare two buffers of different size. The difference
    220      is past the end of the shorter string. */
    221   {
    222   printf("--- test 8 ---\n");
    223   uint8_t x[5] = "abcde";
    224   uint8_t y[7] = "abcdeff";
    225   run_test(x, 5, y, 7, 0);   // first operand low
    226   run_test(y, 7, x, 5, 0);   // first operand high
    227   run_test(x, 5, y, 7, 'f'); // equal
    228   run_test(y, 7, x, 5, 'f'); // equal
    229   }
    230 
    231   /* Test 9: Compare two buffers of different size. The difference
    232      is before the end of the shorter string. */
    233   {
    234   printf("--- test 9 ---\n");
    235   uint8_t x[5] = "abcab";
    236   uint8_t y[7] = "abcdeff";
    237   run_test(x, 5, y, 7, 0);   // first operand low
    238   run_test(y, 7, x, 5, 0);   // first operand high
    239   run_test(x, 5, y, 7, 'f'); // first operand low
    240   run_test(y, 7, x, 5, 'f'); // first operand high
    241   }
    242 
    243   return 0;
    244 }
    245