Home | History | Annotate | Download | only in s390x
      1 #include <stdio.h>
      2 #include <assert.h>
      3 #include <stdlib.h>
      4 #include <string.h>
      5 #include <stdint.h>
      6 #include <inttypes.h>
      7 
      8 /* The abstracted result of an MVCL 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 } mvcl_t;
     17 
     18 /* Register contents after executing an MVCL 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 } mvcl_regs;
     26 
     27 
     28 /* Run a single MVCL insn and return its raw result. */
     29 static mvcl_regs
     30 do_mvcl(uint64_t r1, uint64_t r1p1, uint64_t r2, uint64_t r2p1)
     31 {
     32   mvcl_regs regs;
     33 
     34   register uint64_t a1 asm ("2") = r1;
     35   register uint64_t l1 asm ("3") = r1p1;
     36   register uint64_t a2 asm ("4") = r2;
     37   register uint64_t l2 asm ("5") = r2p1;
     38   register uint32_t cc asm ("7");
     39 
     40   asm volatile( "mvcl %1,%3\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                 :
     45                 : "memory", "cc");
     46 
     47   regs.r1   = a1;
     48   regs.r1p1 = l1;
     49   regs.r2   = a2;
     50   regs.r2p1 = l2;
     51   regs.cc   = cc;
     52 
     53   return regs;
     54 }
     55 
     56 mvcl_t
     57 result_from_regs(mvcl_regs regs)
     58 {
     59   mvcl_t result;
     60 
     61   result.addr1 = regs.r1;
     62   result.len1  = regs.r1p1 & 0xFFFFFF;
     63   result.addr2 = regs.r2;
     64   result.len2  = regs.r2p1 & 0xFFFFFF;
     65   result.pad   = (regs.r2p1 & 0xFF000000u) >> 24;
     66   result.cc    = regs.cc;
     67 
     68   return result;
     69 }
     70 
     71 /* Run MVCL twice using different fill bits for unused register bits.
     72    Results ought to be the same */
     73 static mvcl_t
     74 mvcl(void *addr1, uint32_t len1,
     75      void *addr2, uint32_t len2, uint32_t pad)
     76 {
     77   mvcl_t result1, result2;
     78   mvcl_regs regs;
     79   uint64_t r1, r1p1, r2, r2p1;
     80 
     81   /* Check input arguments */
     82   assert((pad & 0xFF) == pad);  /* an 8-byte value */
     83   assert((len1 & 0xFFFFFF) == len1);
     84   assert((len2 & 0xFFFFFF) == len2);
     85 
     86   /* Make a copy of the input buffer */
     87   void *copy = memcpy(malloc(len1), addr1, len1);
     88 
     89   /* Build up register contents setting unused bits to 0 */
     90   r1   = (uint64_t)addr1;
     91   r1p1 = len1;
     92   r2   = (uint64_t)addr2;
     93   r2p1 = len2 | (pad << 24);
     94 
     95   /* Run mvcl */
     96   regs = do_mvcl(r1, r1p1, r2, r2p1);
     97   result1 = result_from_regs(regs);
     98 
     99   /* Check unused bits */
    100   if ((regs.r1p1 >> 24) != 0)
    101     printf("FAIL: r1[0:39] modified (unused bits 0)\n");
    102   if ((regs.r2p1 >> 32) != 0)
    103     printf("FAIL: r2[0:31] modified (unused bits 0)\n");
    104 
    105   /* Check pad value */
    106   if (result1.pad != pad)
    107     printf("FAIL: pad byte modified (unused bits 0)\n");
    108 
    109   /* Build up register contents setting unused bits to 1 */
    110   memcpy(addr1, copy, len1);
    111   r1p1 |= 0xFFFFFFFFFFULL << 24;
    112   r2p1 |= ((uint64_t)0xFFFFFFFF) << 32;
    113 
    114   /* Run mvcl again */
    115   regs = do_mvcl(r1, r1p1, r2, r2p1);
    116   result2 = result_from_regs(regs);
    117 
    118   /* Check unused bits */
    119   if ((regs.r1p1 >> 24) != 0xFFFFFFFFFFull)
    120     printf("FAIL: r1[0:39] modified (unused bits 1)\n");
    121   if ((regs.r2p1 >> 32) != 0xFFFFFFFFu)
    122     printf("FAIL: r2[0:31] modified (unused bits 1)\n");
    123 
    124   /* Check pad value */
    125   if (result2.pad != pad)
    126     printf("FAIL: pad byte modified (unused bits 1)\n");
    127 
    128   /* Compare results */
    129   if (result1.addr1 != result2.addr1)
    130     printf("FAIL: addr1 result is different\n");
    131   if (result1.addr2 != result2.addr2)
    132     printf("FAIL: addr2 result is different\n");
    133   if (result1.len1 != result2.len1)
    134     printf("FAIL: len1 result is different\n");
    135   if (result1.len2 != result2.len2)
    136     printf("FAIL: len2 result is different\n");
    137   if (result1.pad != result2.pad)
    138     printf("FAIL: pad result is different\n");
    139   if (result1.cc != result2.cc)
    140     printf("FAIL: cc result is different\n");
    141 
    142   return result1;
    143 }
    144 
    145 void
    146 print_buf(const char *prefix, char *buf, uint32_t len)
    147 {
    148   uint32_t i;
    149 
    150   if (len > 0) {
    151     printf("%s |", prefix);
    152     for (i = 0; i < len; ++i)
    153       putchar(buf[i]);
    154     printf("|\n");
    155   }
    156 }
    157 
    158 void
    159 run_test(void *dst, uint32_t dst_len, void *src, uint32_t src_len, uint32_t pad)
    160 {
    161   mvcl_t result;
    162 
    163   result = mvcl(dst, dst_len, src, src_len, pad);
    164 
    165   printf("cc: %"PRIu32", len1: %"PRIu32", len2: %"PRIu32
    166          ", addr1 diff: %"PRId64", addr2 diff: %"PRId64"\n", result.cc,
    167          result.len1, result.len2, (int64_t)result.addr1 - (int64_t)dst,
    168          (int64_t)result.addr2 - (int64_t)src);
    169   print_buf("dst buffer:", dst, dst_len);
    170 }
    171 
    172 int main()
    173 {
    174   uint8_t byte, buf[10], small[5], i;
    175   uint32_t dst_offset, dst_len, src_offset, src_len;
    176 
    177   /* Test 1: len1 == 0 */
    178   printf("--- test 1 ---\n");
    179   run_test(NULL, 0, NULL, 0, 0x00);
    180   run_test(NULL, 0, NULL, 0, 0xFF);
    181   run_test(NULL, 0, NULL, 5, 0x00);
    182   run_test(NULL, 0, NULL, 5, 0xFF);
    183   run_test(NULL, 0, buf,  sizeof buf, 0x00);
    184   run_test(NULL, 0, buf,  sizeof buf, 0xFF);
    185 
    186   /* Test 2: len1 != 0, len2 == 0 */
    187   printf("--- test 2 ---\n");
    188   run_test(&byte, 1, NULL, 0, 'a');
    189   memset(buf, 'x', sizeof buf);
    190   run_test(buf, sizeof buf, NULL, 0, 'a');
    191 
    192   /* In the following: len1 != 0, len2 != 0 */
    193 
    194   /* Test 3: src == dst */
    195   printf("--- test 3 ---\n");
    196   byte = 'x';
    197   run_test(&byte, 1, &byte, 1, 'a');
    198   memset(buf, 'x', sizeof buf);
    199   for (i = 0; i <= sizeof buf; ++i)
    200     run_test(buf, i, buf, sizeof buf, 'a');
    201 
    202   /* Test 4: len1 > len2, no buffer overlap */
    203   printf("--- test 4 ---\n");
    204   memset(buf, 'b', sizeof buf);
    205   memset(small, 's', sizeof small);
    206   run_test(buf, sizeof buf, small, sizeof small, 'a');
    207 
    208   /* Test 5: len1 < len2, no buffer overlap */
    209   printf("--- test 5 ---\n");
    210   memset(buf, 'b', sizeof buf);
    211   memset(small, 's', sizeof small);
    212   run_test(small, sizeof small, buf, sizeof buf, 'a');
    213 
    214   /* Test 6: len1 > len2, non-destructive overlap */
    215   printf("--- test 6 ---\n");
    216   memcpy(buf, "0123456789", 10);
    217   run_test(buf, sizeof buf, buf + 5, 5, 'x');
    218 
    219   /* Test 7: len1 < len2, non-destructive overlap */
    220   printf("--- test 7 ---\n");
    221   memcpy(buf, "0123456789", 10);
    222   run_test(buf, 5, buf + 4, 3, 'x');
    223 
    224   /* Test 8: Misc checks for testing destructive overlap
    225      Pad byte unused */
    226   printf("--- test 8 ---\n");
    227   memcpy(buf, "0123456789", 10);
    228   run_test(buf + 3, 1, buf, 10, 'x');   // non-destructive
    229   memcpy(buf, "0123456789", 10);
    230   run_test(buf + 3, 2, buf, 10, 'x');   // non-destructive
    231   memcpy(buf, "0123456789", 10);
    232   run_test(buf + 3, 3, buf, 10, 'x');   // non-destructive
    233   memcpy(buf, "0123456789", 10);
    234   run_test(buf + 3, 4, buf, 10, 'x');   // destructive
    235   memcpy(buf, "0123456789", 10);
    236   run_test(buf + 3, 5, buf, 10, 'x');   // destructive
    237   memcpy(buf, "0123456789", 10);
    238   run_test(buf + 3, 6, buf, 10, 'x');   // destructive
    239   memcpy(buf, "0123456789", 10);
    240   run_test(buf + 3, 7, buf, 10, 'x');   // destructive
    241 
    242   /* Test 9: More checks for testing destructive overlap
    243      Pad byte used; len2 == 0 */
    244   printf("--- test 9 ---\n");
    245   memcpy(buf, "0123456789", 10);
    246   run_test(buf + 3, 1, buf, 0, 'x');   // non-destructive
    247   memcpy(buf, "0123456789", 10);
    248   run_test(buf + 3, 2, buf, 0, 'x');   // non-destructive
    249   memcpy(buf, "0123456789", 10);
    250   run_test(buf + 3, 3, buf, 0, 'x');   // non-destructive
    251   memcpy(buf, "0123456789", 10);
    252   run_test(buf + 3, 4, buf, 0, 'x');   // non-destructive
    253   memcpy(buf, "0123456789", 10);
    254   run_test(buf + 3, 4, buf, 0, 'x');   // non-destructive
    255   memcpy(buf, "0123456789", 10);
    256   run_test(buf + 3, 5, buf, 0, 'x');   // non-destructive
    257   memcpy(buf, "0123456789", 10);
    258   run_test(buf + 3, 6, buf, 0, 'x');   // non-destructive
    259   memcpy(buf, "0123456789", 10);
    260   run_test(buf + 3, 7, buf, 0, 'x');   // non-destructive
    261 
    262   /* Test 10; what the heck... Just try all combinations. */
    263   printf("--- test 9 ---\n");
    264   for (dst_offset = 0; dst_offset < sizeof buf; ++dst_offset)
    265     for (dst_len = 0; dst_len <= sizeof buf - dst_offset; ++dst_len)
    266       for (src_offset = 0; src_offset < sizeof buf; ++src_offset)
    267         for (src_len = 0; src_len <= sizeof buf - src_offset; ++src_len)
    268           run_test(buf + dst_offset, dst_len, buf + src_offset, src_len, 'x');
    269 
    270   return 0;
    271 }
    272 
    273