1 // SPDX-License-Identifier: Zlib 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 /* DFLTCC_UTIL_H */ 132