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