1 #include <stddef.h>
2 #include <stdint.h>
3 #include <stdio.h>
4
5 #ifdef HAVE_SYS_SDT_H
6 #include <sys/sdt.h>
7 #endif
8
9 /*
10 Tuning parameters.
11 */
12 #ifndef DFLTCC_LEVEL_MASK
13 #define DFLTCC_LEVEL_MASK 0x2
14 #endif
15 #ifndef DFLTCC_BLOCK_SIZE
16 #define DFLTCC_BLOCK_SIZE 1048576
17 #endif
18 #ifndef DFLTCC_FIRST_FHT_BLOCK_SIZE
19 #define DFLTCC_FIRST_FHT_BLOCK_SIZE 4096
20 #endif
21 #ifndef DFLTCC_DHT_MIN_SAMPLE_SIZE
22 #define DFLTCC_DHT_MIN_SAMPLE_SIZE 4096
23 #endif
24 #ifndef DFLTCC_RIBM
25 #define DFLTCC_RIBM 0
26 #endif
27
28 /*
29 C wrapper for the DEFLATE CONVERSION CALL instruction.
30 */
31 typedef enum {
32 DFLTCC_CC_OK = 0,
33 DFLTCC_CC_OP1_TOO_SHORT = 1,
34 DFLTCC_CC_OP2_TOO_SHORT = 2,
35 DFLTCC_CC_OP2_CORRUPT = 2,
36 DFLTCC_CC_AGAIN = 3,
37 } dfltcc_cc;
38
39 #define DFLTCC_QAF 0
40 #define DFLTCC_GDHT 1
41 #define DFLTCC_CMPR 2
42 #define DFLTCC_XPND 4
43 #define HBT_CIRCULAR (1 << 7)
44 #define HB_BITS 15
45 #define HB_SIZE (1 << HB_BITS)
46 #define DFLTCC_FACILITY 151
47
dfltcc(int fn,void * param,unsigned char ** op1,size_t * len1,const unsigned char ** op2,size_t * len2,void * hist)48 static inline dfltcc_cc dfltcc(int fn, void *param,
49 unsigned char **op1, size_t *len1, const unsigned char **op2, size_t *len2, void *hist) {
50 unsigned char *t2 = op1 ? *op1 : NULL;
51 size_t t3 = len1 ? *len1 : 0;
52 const unsigned char *t4 = op2 ? *op2 : NULL;
53 size_t t5 = len2 ? *len2 : 0;
54 Z_REGISTER int r0 __asm__("r0") = fn;
55 Z_REGISTER void *r1 __asm__("r1") = param;
56 Z_REGISTER unsigned char *r2 __asm__("r2") = t2;
57 Z_REGISTER size_t r3 __asm__("r3") = t3;
58 Z_REGISTER const unsigned char *r4 __asm__("r4") = t4;
59 Z_REGISTER size_t r5 __asm__("r5") = t5;
60 int cc;
61
62 __asm__ volatile(
63 #ifdef HAVE_SYS_SDT_H
64 STAP_PROBE_ASM(zlib, dfltcc_entry, STAP_PROBE_ASM_TEMPLATE(5))
65 #endif
66 ".insn rrf,0xb9390000,%[r2],%[r4],%[hist],0\n"
67 #ifdef HAVE_SYS_SDT_H
68 STAP_PROBE_ASM(zlib, dfltcc_exit, STAP_PROBE_ASM_TEMPLATE(5))
69 #endif
70 "ipm %[cc]\n"
71 : [r2] "+r" (r2)
72 , [r3] "+r" (r3)
73 , [r4] "+r" (r4)
74 , [r5] "+r" (r5)
75 , [cc] "=r" (cc)
76 : [r0] "r" (r0)
77 , [r1] "r" (r1)
78 , [hist] "r" (hist)
79 #ifdef HAVE_SYS_SDT_H
80 , STAP_PROBE_ASM_OPERANDS(5, r2, r3, r4, r5, hist)
81 #endif
82 : "cc", "memory");
83 t2 = r2; t3 = r3; t4 = r4; t5 = r5;
84
85 if (op1)
86 *op1 = t2;
87 if (len1)
88 *len1 = t3;
89 if (op2)
90 *op2 = t4;
91 if (len2)
92 *len2 = t5;
93 return (cc >> 28) & 3;
94 }
95
96 /*
97 Parameter Block for Query Available Functions.
98 */
99 #define static_assert(c, msg) __attribute__((unused)) static char static_assert_failed_ ## msg[c ? 1 : -1]
100
101 struct dfltcc_qaf_param {
102 char fns[16];
103 char reserved1[8];
104 char fmts[2];
105 char reserved2[6];
106 };
107
108 static_assert(sizeof(struct dfltcc_qaf_param) == 32, sizeof_struct_dfltcc_qaf_param_is_32);
109
is_bit_set(const char * bits,int n)110 static inline int is_bit_set(const char *bits, int n) {
111 return bits[n / 8] & (1 << (7 - (n % 8)));
112 }
113
clear_bit(char * bits,int n)114 static inline void clear_bit(char *bits, int n) {
115 bits[n / 8] &= ~(1 << (7 - (n % 8)));
116 }
117
118 #define DFLTCC_FMT0 0
119
120 /*
121 Parameter Block for Generate Dynamic-Huffman Table, Compress and Expand.
122 */
123 #define CVT_CRC32 0
124 #define CVT_ADLER32 1
125 #define HTT_FIXED 0
126 #define HTT_DYNAMIC 1
127
128 struct dfltcc_param_v0 {
129 uint16_t pbvn; /* Parameter-Block-Version Number */
130 uint8_t mvn; /* Model-Version Number */
131 uint8_t ribm; /* Reserved for IBM use */
132 uint32_t reserved32 : 31;
133 uint32_t cf : 1; /* Continuation Flag */
134 uint8_t reserved64[8];
135 uint32_t nt : 1; /* New Task */
136 uint32_t reserved129 : 1;
137 uint32_t cvt : 1; /* Check Value Type */
138 uint32_t reserved131 : 1;
139 uint32_t htt : 1; /* Huffman-Table Type */
140 uint32_t bcf : 1; /* Block-Continuation Flag */
141 uint32_t bcc : 1; /* Block Closing Control */
142 uint32_t bhf : 1; /* Block Header Final */
143 uint32_t reserved136 : 1;
144 uint32_t reserved137 : 1;
145 uint32_t dhtgc : 1; /* DHT Generation Control */
146 uint32_t reserved139 : 5;
147 uint32_t reserved144 : 5;
148 uint32_t sbb : 3; /* Sub-Byte Boundary */
149 uint8_t oesc; /* Operation-Ending-Supplemental Code */
150 uint32_t reserved160 : 12;
151 uint32_t ifs : 4; /* Incomplete-Function Status */
152 uint16_t ifl; /* Incomplete-Function Length */
153 uint8_t reserved192[8];
154 uint8_t reserved256[8];
155 uint8_t reserved320[4];
156 uint16_t hl; /* History Length */
157 uint32_t reserved368 : 1;
158 uint16_t ho : 15; /* History Offset */
159 uint32_t cv; /* Check Value */
160 uint32_t eobs : 15; /* End-of-block Symbol */
161 uint32_t reserved431: 1;
162 uint8_t eobl : 4; /* End-of-block Length */
163 uint32_t reserved436 : 12;
164 uint32_t reserved448 : 4;
165 uint16_t cdhtl : 12; /* Compressed-Dynamic-Huffman Table
166 Length */
167 uint8_t reserved464[6];
168 uint8_t cdht[288];
169 uint8_t reserved[32];
170 uint8_t csb[1152];
171 };
172
173 static_assert(sizeof(struct dfltcc_param_v0) == 1536, sizeof_struct_dfltcc_param_v0_is_1536);
174
oesc_msg(char * buf,int oesc)175 static inline const char *oesc_msg(char *buf, int oesc) {
176 if (oesc == 0x00)
177 return NULL; /* Successful completion */
178 else {
179 sprintf(buf, "Operation-Ending-Supplemental Code is 0x%.2X", oesc);
180 return buf;
181 }
182 }
183
184 /*
185 Extension of inflate_state and deflate_state. Must be doubleword-aligned.
186 */
187 struct dfltcc_state {
188 struct dfltcc_param_v0 param; /* Parameter block. */
189 struct dfltcc_qaf_param af; /* Available functions. */
190 uint16_t level_mask; /* Levels on which to use DFLTCC */
191 uint32_t block_size; /* New block each X bytes */
192 size_t block_threshold; /* New block after total_in > X */
193 uint32_t dht_threshold; /* New block only if avail_in >= X */
194 char msg[64]; /* Buffer for strm->msg */
195 };
196
197 #define ALIGN_UP(p, size) (__typeof__(p))(((uintptr_t)(p) + ((size) - 1)) & ~((size) - 1))
198
199 #define GET_DFLTCC_STATE(state) ((struct dfltcc_state *)((char *)(state) + ALIGN_UP(sizeof(*state), 8)))
200