| 1 | |
| 2 | #ifndef DFLTCC_UTIL_H
|
| 3 | #define DFLTCC_UTIL_H
|
| 4 |
|
| 5 | #include "dfltcc.h"
|
| 6 | #include <linux/kmsan-checks.h>
|
| 7 | #include <linux/zutil.h>
|
| 8 |
|
| 9 | |
| 10 | * C wrapper for the DEFLATE CONVERSION CALL instruction.
|
| 11 |
|
| 12 | typedef enum {
|
| 13 | DFLTCC_CC_OK = 0,
|
| 14 | DFLTCC_CC_OP1_TOO_SHORT = 1,
|
| 15 | DFLTCC_CC_OP2_TOO_SHORT = 2,
|
| 16 | DFLTCC_CC_OP2_CORRUPT = 2,
|
| 17 | DFLTCC_CC_AGAIN = 3,
|
| 18 | } dfltcc_cc;
|
| 19 |
|
| 20 | #define DFLTCC_QAF 0
|
| 21 | #define DFLTCC_GDHT 1
|
| 22 | #define DFLTCC_CMPR 2
|
| 23 | #define DFLTCC_XPND 4
|
| 24 | #define HBT_CIRCULAR (1 << 7)
|
| 25 | #define DFLTCC_FN_MASK ((1 << 7) - 1)
|
| 26 | #define HB_BITS 15
|
| 27 | #define HB_SIZE (1 << HB_BITS)
|
| 28 |
|
| 29 | static inline dfltcc_cc dfltcc(
|
| 30 | int fn,
|
| 31 | void *param,
|
| 32 | Byte **op1,
|
| 33 | size_t *len1,
|
| 34 | const Byte **op2,
|
| 35 | size_t *len2,
|
| 36 | void *hist
|
| 37 | )
|
| 38 | {
|
| 39 | Byte *t2 = op1 ? *op1 : NULL;
|
| 40 | unsigned char *orig_t2 = t2;
|
| 41 | size_t t3 = len1 ? *len1 : 0;
|
| 42 | const Byte *t4 = op2 ? *op2 : NULL;
|
| 43 | size_t t5 = len2 ? *len2 : 0;
|
| 44 | register int r0 __asm__("r0") = fn;
|
| 45 | register void *r1 __asm__("r1") = param;
|
| 46 | register Byte *r2 __asm__("r2") = t2;
|
| 47 | register size_t r3 __asm__("r3") = t3;
|
| 48 | register const Byte *r4 __asm__("r4") = t4;
|
| 49 | register size_t r5 __asm__("r5") = t5;
|
| 50 | int cc;
|
| 51 |
|
| 52 | __asm__ volatile(
|
| 53 | ".insn rrf,0xb9390000,%[r2],%[r4],%[hist],0\n"
|
| 54 | "ipm %[cc]\n"
|
| 55 | : [r2] "+r" (r2)
|
| 56 | , [r3] "+r" (r3)
|
| 57 | , [r4] "+r" (r4)
|
| 58 | , [r5] "+r" (r5)
|
| 59 | , [cc] "=r" (cc)
|
| 60 | : [r0] "r" (r0)
|
| 61 | , [r1] "r" (r1)
|
| 62 | , [hist] "r" (hist)
|
| 63 | : "cc", "memory");
|
| 64 | t2 = r2; t3 = r3; t4 = r4; t5 = r5;
|
| 65 |
|
| 66 | |
| 67 | * Unpoison the parameter block and the output buffer.
|
| 68 | * This is a no-op in non-KMSAN builds.
|
| 69 |
|
| 70 | switch (fn & DFLTCC_FN_MASK) {
|
| 71 | case DFLTCC_QAF:
|
| 72 | kmsan_unpoison_memory(param, sizeof(struct dfltcc_qaf_param));
|
| 73 | break;
|
| 74 | case DFLTCC_GDHT:
|
| 75 | kmsan_unpoison_memory(param, offsetof(struct dfltcc_param_v0, csb));
|
| 76 | break;
|
| 77 | case DFLTCC_CMPR:
|
| 78 | kmsan_unpoison_memory(param, sizeof(struct dfltcc_param_v0));
|
| 79 | kmsan_unpoison_memory(
|
| 80 | orig_t2,
|
| 81 | t2 - orig_t2 +
|
| 82 | (((struct dfltcc_param_v0 *)param)->sbb == 0 ? 0 : 1));
|
| 83 | break;
|
| 84 | case DFLTCC_XPND:
|
| 85 | kmsan_unpoison_memory(param, sizeof(struct dfltcc_param_v0));
|
| 86 | kmsan_unpoison_memory(orig_t2, t2 - orig_t2);
|
| 87 | break;
|
| 88 | }
|
| 89 |
|
| 90 | if (op1)
|
| 91 | *op1 = t2;
|
| 92 | if (len1)
|
| 93 | *len1 = t3;
|
| 94 | if (op2)
|
| 95 | *op2 = t4;
|
| 96 | if (len2)
|
| 97 | *len2 = t5;
|
| 98 | return (cc >> 28) & 3;
|
| 99 | }
|
| 100 |
|
| 101 | static inline int is_bit_set(
|
| 102 | const char *bits,
|
| 103 | int n
|
| 104 | )
|
| 105 | {
|
| 106 | return bits[n / 8] & (1 << (7 - (n % 8)));
|
| 107 | }
|
| 108 |
|
| 109 | static inline void turn_bit_off(
|
| 110 | char *bits,
|
| 111 | int n
|
| 112 | )
|
| 113 | {
|
| 114 | bits[n / 8] &= ~(1 << (7 - (n % 8)));
|
| 115 | }
|
| 116 |
|
| 117 | static inline int dfltcc_are_params_ok(
|
| 118 | int level,
|
| 119 | uInt window_bits,
|
| 120 | int strategy,
|
| 121 | uLong level_mask
|
| 122 | )
|
| 123 | {
|
| 124 | return (level_mask & (1 << level)) != 0 &&
|
| 125 | (window_bits == HB_BITS) &&
|
| 126 | (strategy == Z_DEFAULT_STRATEGY);
|
| 127 | }
|
| 128 |
|
| 129 | char *oesc_msg(char *buf, int oesc);
|
| 130 |
|
| 131 | #endif
|