LCOV - code coverage report
Current view: top level - kernel/bpf - tnum.c (source / functions) Hit Total Coverage
Test: Real Lines: 30 82 36.6 %
Date: 2020-10-17 15:46:43 Functions: 0 17 0.0 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /* tnum: tracked (or tristate) numbers
       3                 :            :  *
       4                 :            :  * A tnum tracks knowledge about the bits of a value.  Each bit can be either
       5                 :            :  * known (0 or 1), or unknown (x).  Arithmetic operations on tnums will
       6                 :            :  * propagate the unknown bits such that the tnum result represents all the
       7                 :            :  * possible results for possible values of the operands.
       8                 :            :  */
       9                 :            : #include <linux/kernel.h>
      10                 :            : #include <linux/tnum.h>
      11                 :            : 
      12                 :            : #define TNUM(_v, _m)    (struct tnum){.value = _v, .mask = _m}
      13                 :            : /* A completely unknown value */
      14                 :            : const struct tnum tnum_unknown = { .value = 0, .mask = -1 };
      15                 :            : 
      16                 :          3 : struct tnum tnum_const(u64 value)
      17                 :            : {
      18                 :          3 :         return TNUM(value, 0);
      19                 :            : }
      20                 :            : 
      21                 :          3 : struct tnum tnum_range(u64 min, u64 max)
      22                 :            : {
      23                 :          3 :         u64 chi = min ^ max, delta;
      24                 :          3 :         u8 bits = fls64(chi);
      25                 :            : 
      26                 :            :         /* special case, needed because 1ULL << 64 is undefined */
      27                 :          3 :         if (bits > 63)
      28                 :          0 :                 return tnum_unknown;
      29                 :            :         /* e.g. if chi = 4, bits = 3, delta = (1<<3) - 1 = 7.
      30                 :            :          * if chi = 0, bits = 0, delta = (1<<0) - 1 = 0, so we return
      31                 :            :          *  constant min (since min == max).
      32                 :            :          */
      33                 :          3 :         delta = (1ULL << bits) - 1;
      34                 :          3 :         return TNUM(min & ~delta, delta);
      35                 :            : }
      36                 :            : 
      37                 :          0 : struct tnum tnum_lshift(struct tnum a, u8 shift)
      38                 :            : {
      39                 :          0 :         return TNUM(a.value << shift, a.mask << shift);
      40                 :            : }
      41                 :            : 
      42                 :          0 : struct tnum tnum_rshift(struct tnum a, u8 shift)
      43                 :            : {
      44                 :          0 :         return TNUM(a.value >> shift, a.mask >> shift);
      45                 :            : }
      46                 :            : 
      47                 :          0 : struct tnum tnum_arshift(struct tnum a, u8 min_shift, u8 insn_bitness)
      48                 :            : {
      49                 :            :         /* if a.value is negative, arithmetic shifting by minimum shift
      50                 :            :          * will have larger negative offset compared to more shifting.
      51                 :            :          * If a.value is nonnegative, arithmetic shifting by minimum shift
      52                 :            :          * will have larger positive offset compare to more shifting.
      53                 :            :          */
      54                 :          0 :         if (insn_bitness == 32)
      55                 :          0 :                 return TNUM((u32)(((s32)a.value) >> min_shift),
      56                 :            :                             (u32)(((s32)a.mask)  >> min_shift));
      57                 :            :         else
      58                 :          0 :                 return TNUM((s64)a.value >> min_shift,
      59                 :            :                             (s64)a.mask  >> min_shift);
      60                 :            : }
      61                 :            : 
      62                 :          3 : struct tnum tnum_add(struct tnum a, struct tnum b)
      63                 :            : {
      64                 :            :         u64 sm, sv, sigma, chi, mu;
      65                 :            : 
      66                 :          3 :         sm = a.mask + b.mask;
      67                 :          3 :         sv = a.value + b.value;
      68                 :          3 :         sigma = sm + sv;
      69                 :          3 :         chi = sigma ^ sv;
      70                 :          3 :         mu = chi | a.mask | b.mask;
      71                 :          3 :         return TNUM(sv & ~mu, mu);
      72                 :            : }
      73                 :            : 
      74                 :          0 : struct tnum tnum_sub(struct tnum a, struct tnum b)
      75                 :            : {
      76                 :            :         u64 dv, alpha, beta, chi, mu;
      77                 :            : 
      78                 :          0 :         dv = a.value - b.value;
      79                 :          0 :         alpha = dv + a.mask;
      80                 :          0 :         beta = dv - b.mask;
      81                 :          0 :         chi = alpha ^ beta;
      82                 :          0 :         mu = chi | a.mask | b.mask;
      83                 :          0 :         return TNUM(dv & ~mu, mu);
      84                 :            : }
      85                 :            : 
      86                 :          0 : struct tnum tnum_and(struct tnum a, struct tnum b)
      87                 :            : {
      88                 :            :         u64 alpha, beta, v;
      89                 :            : 
      90                 :          0 :         alpha = a.value | a.mask;
      91                 :          0 :         beta = b.value | b.mask;
      92                 :          0 :         v = a.value & b.value;
      93                 :          0 :         return TNUM(v, alpha & beta & ~v);
      94                 :            : }
      95                 :            : 
      96                 :          0 : struct tnum tnum_or(struct tnum a, struct tnum b)
      97                 :            : {
      98                 :            :         u64 v, mu;
      99                 :            : 
     100                 :          0 :         v = a.value | b.value;
     101                 :          0 :         mu = a.mask | b.mask;
     102                 :          0 :         return TNUM(v, mu & ~v);
     103                 :            : }
     104                 :            : 
     105                 :          0 : struct tnum tnum_xor(struct tnum a, struct tnum b)
     106                 :            : {
     107                 :            :         u64 v, mu;
     108                 :            : 
     109                 :          0 :         v = a.value ^ b.value;
     110                 :          0 :         mu = a.mask | b.mask;
     111                 :          0 :         return TNUM(v & ~mu, mu);
     112                 :            : }
     113                 :            : 
     114                 :            : /* half-multiply add: acc += (unknown * mask * value).
     115                 :            :  * An intermediate step in the multiply algorithm.
     116                 :            :  */
     117                 :            : static struct tnum hma(struct tnum acc, u64 value, u64 mask)
     118                 :            : {
     119                 :          0 :         while (mask) {
     120                 :          0 :                 if (mask & 1)
     121                 :            :                         acc = tnum_add(acc, TNUM(0, value));
     122                 :          0 :                 mask >>= 1;
     123                 :          0 :                 value <<= 1;
     124                 :            :         }
     125                 :          0 :         return acc;
     126                 :            : }
     127                 :            : 
     128                 :          0 : struct tnum tnum_mul(struct tnum a, struct tnum b)
     129                 :            : {
     130                 :            :         struct tnum acc;
     131                 :            :         u64 pi;
     132                 :            : 
     133                 :          0 :         pi = a.value * b.value;
     134                 :          0 :         acc = hma(TNUM(pi, 0), a.mask, b.mask | b.value);
     135                 :          0 :         return hma(acc, b.mask, a.value);
     136                 :            : }
     137                 :            : 
     138                 :            : /* Note that if a and b disagree - i.e. one has a 'known 1' where the other has
     139                 :            :  * a 'known 0' - this will return a 'known 1' for that bit.
     140                 :            :  */
     141                 :          3 : struct tnum tnum_intersect(struct tnum a, struct tnum b)
     142                 :            : {
     143                 :            :         u64 v, mu;
     144                 :            : 
     145                 :          3 :         v = a.value | b.value;
     146                 :          3 :         mu = a.mask & b.mask;
     147                 :          3 :         return TNUM(v & ~mu, mu);
     148                 :            : }
     149                 :            : 
     150                 :          3 : struct tnum tnum_cast(struct tnum a, u8 size)
     151                 :            : {
     152                 :          3 :         a.value &= (1ULL << (size * 8)) - 1;
     153                 :          3 :         a.mask &= (1ULL << (size * 8)) - 1;
     154                 :          3 :         return a;
     155                 :            : }
     156                 :            : 
     157                 :          3 : bool tnum_is_aligned(struct tnum a, u64 size)
     158                 :            : {
     159                 :          3 :         if (!size)
     160                 :            :                 return true;
     161                 :          3 :         return !((a.value | a.mask) & (size - 1));
     162                 :            : }
     163                 :            : 
     164                 :          3 : bool tnum_in(struct tnum a, struct tnum b)
     165                 :            : {
     166                 :          3 :         if (b.mask & ~a.mask)
     167                 :            :                 return false;
     168                 :          3 :         b.value &= ~a.mask;
     169                 :          3 :         return a.value == b.value;
     170                 :            : }
     171                 :            : 
     172                 :          0 : int tnum_strn(char *str, size_t size, struct tnum a)
     173                 :            : {
     174                 :          0 :         return snprintf(str, size, "(%#llx; %#llx)", a.value, a.mask);
     175                 :            : }
     176                 :            : EXPORT_SYMBOL_GPL(tnum_strn);
     177                 :            : 
     178                 :          0 : int tnum_sbin(char *str, size_t size, struct tnum a)
     179                 :            : {
     180                 :            :         size_t n;
     181                 :            : 
     182                 :          0 :         for (n = 64; n; n--) {
     183                 :          0 :                 if (n < size) {
     184                 :          0 :                         if (a.mask & 1)
     185                 :          0 :                                 str[n - 1] = 'x';
     186                 :          0 :                         else if (a.value & 1)
     187                 :          0 :                                 str[n - 1] = '1';
     188                 :            :                         else
     189                 :          0 :                                 str[n - 1] = '0';
     190                 :            :                 }
     191                 :          0 :                 a.mask >>= 1;
     192                 :          0 :                 a.value >>= 1;
     193                 :            :         }
     194                 :          0 :         str[min(size - 1, (size_t)64)] = 0;
     195                 :          0 :         return 64;
     196                 :            : }
    

Generated by: LCOV version 1.14