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