1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun
3*4882a593Smuzhiyun /* P9 gzip sample code for demonstrating the P9 NX hardware interface.
4*4882a593Smuzhiyun * Not intended for productive uses or for performance or compression
5*4882a593Smuzhiyun * ratio measurements. For simplicity of demonstration, this sample
6*4882a593Smuzhiyun * code compresses in to fixed Huffman blocks only (Deflate btype=1)
7*4882a593Smuzhiyun * and has very simple memory management. Dynamic Huffman blocks
8*4882a593Smuzhiyun * (Deflate btype=2) are more involved as detailed in the user guide.
9*4882a593Smuzhiyun * Note also that /dev/crypto/gzip, VAS and skiboot support are
10*4882a593Smuzhiyun * required.
11*4882a593Smuzhiyun *
12*4882a593Smuzhiyun * Copyright 2020 IBM Corp.
13*4882a593Smuzhiyun *
14*4882a593Smuzhiyun * https://github.com/libnxz/power-gzip for zlib api and other utils
15*4882a593Smuzhiyun *
16*4882a593Smuzhiyun * Author: Bulent Abali <abali@us.ibm.com>
17*4882a593Smuzhiyun *
18*4882a593Smuzhiyun * Definitions of acronyms used here. See
19*4882a593Smuzhiyun * P9 NX Gzip Accelerator User's Manual for details:
20*4882a593Smuzhiyun * https://github.com/libnxz/power-gzip/blob/develop/doc/power_nx_gzip_um.pdf
21*4882a593Smuzhiyun *
22*4882a593Smuzhiyun * adler/crc: 32 bit checksums appended to stream tail
23*4882a593Smuzhiyun * ce: completion extension
24*4882a593Smuzhiyun * cpb: coprocessor parameter block (metadata)
25*4882a593Smuzhiyun * crb: coprocessor request block (command)
26*4882a593Smuzhiyun * csb: coprocessor status block (status)
27*4882a593Smuzhiyun * dht: dynamic huffman table
28*4882a593Smuzhiyun * dde: data descriptor element (address, length)
29*4882a593Smuzhiyun * ddl: list of ddes
30*4882a593Smuzhiyun * dh/fh: dynamic and fixed huffman types
31*4882a593Smuzhiyun * fc: coprocessor function code
32*4882a593Smuzhiyun * histlen: history/dictionary length
33*4882a593Smuzhiyun * history: sliding window of up to 32KB of data
34*4882a593Smuzhiyun * lzcount: Deflate LZ symbol counts
35*4882a593Smuzhiyun * rembytecnt: remaining byte count
36*4882a593Smuzhiyun * sfbt: source final block type; last block's type during decomp
37*4882a593Smuzhiyun * spbc: source processed byte count
38*4882a593Smuzhiyun * subc: source unprocessed bit count
39*4882a593Smuzhiyun * tebc: target ending bit count; valid bits in the last byte
40*4882a593Smuzhiyun * tpbc: target processed byte count
41*4882a593Smuzhiyun * vas: virtual accelerator switch; the user mode interface
42*4882a593Smuzhiyun */
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun #define _ISOC11_SOURCE // For aligned_alloc()
45*4882a593Smuzhiyun #define _DEFAULT_SOURCE // For endian.h
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun #include <stdio.h>
48*4882a593Smuzhiyun #include <stdlib.h>
49*4882a593Smuzhiyun #include <string.h>
50*4882a593Smuzhiyun #include <unistd.h>
51*4882a593Smuzhiyun #include <stdint.h>
52*4882a593Smuzhiyun #include <sys/types.h>
53*4882a593Smuzhiyun #include <sys/stat.h>
54*4882a593Smuzhiyun #include <sys/time.h>
55*4882a593Smuzhiyun #include <sys/fcntl.h>
56*4882a593Smuzhiyun #include <sys/mman.h>
57*4882a593Smuzhiyun #include <endian.h>
58*4882a593Smuzhiyun #include <bits/endian.h>
59*4882a593Smuzhiyun #include <sys/ioctl.h>
60*4882a593Smuzhiyun #include <assert.h>
61*4882a593Smuzhiyun #include <errno.h>
62*4882a593Smuzhiyun #include <signal.h>
63*4882a593Smuzhiyun #include "nxu.h"
64*4882a593Smuzhiyun #include "nx.h"
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun int nx_dbg;
67*4882a593Smuzhiyun FILE *nx_gzip_log;
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun #define NX_MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
70*4882a593Smuzhiyun #define FNAME_MAX 1024
71*4882a593Smuzhiyun #define FEXT ".nx.gz"
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun /*
74*4882a593Smuzhiyun * LZ counts returned in the user supplied nx_gzip_crb_cpb_t structure.
75*4882a593Smuzhiyun */
compress_fht_sample(char * src,uint32_t srclen,char * dst,uint32_t dstlen,int with_count,struct nx_gzip_crb_cpb_t * cmdp,void * handle)76*4882a593Smuzhiyun static int compress_fht_sample(char *src, uint32_t srclen, char *dst,
77*4882a593Smuzhiyun uint32_t dstlen, int with_count,
78*4882a593Smuzhiyun struct nx_gzip_crb_cpb_t *cmdp, void *handle)
79*4882a593Smuzhiyun {
80*4882a593Smuzhiyun uint32_t fc;
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun assert(!!cmdp);
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun put32(cmdp->crb, gzip_fc, 0); /* clear */
85*4882a593Smuzhiyun fc = (with_count) ? GZIP_FC_COMPRESS_RESUME_FHT_COUNT :
86*4882a593Smuzhiyun GZIP_FC_COMPRESS_RESUME_FHT;
87*4882a593Smuzhiyun putnn(cmdp->crb, gzip_fc, fc);
88*4882a593Smuzhiyun putnn(cmdp->cpb, in_histlen, 0); /* resuming with no history */
89*4882a593Smuzhiyun memset((void *) &cmdp->crb.csb, 0, sizeof(cmdp->crb.csb));
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun /* Section 6.6 programming notes; spbc may be in two different
92*4882a593Smuzhiyun * places depending on FC.
93*4882a593Smuzhiyun */
94*4882a593Smuzhiyun if (!with_count)
95*4882a593Smuzhiyun put32(cmdp->cpb, out_spbc_comp, 0);
96*4882a593Smuzhiyun else
97*4882a593Smuzhiyun put32(cmdp->cpb, out_spbc_comp_with_count, 0);
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun /* Figure 6-3 6-4; CSB location */
100*4882a593Smuzhiyun put64(cmdp->crb, csb_address, 0);
101*4882a593Smuzhiyun put64(cmdp->crb, csb_address,
102*4882a593Smuzhiyun (uint64_t) &cmdp->crb.csb & csb_address_mask);
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun /* Source direct dde (scatter-gather list) */
105*4882a593Smuzhiyun clear_dde(cmdp->crb.source_dde);
106*4882a593Smuzhiyun putnn(cmdp->crb.source_dde, dde_count, 0);
107*4882a593Smuzhiyun put32(cmdp->crb.source_dde, ddebc, srclen);
108*4882a593Smuzhiyun put64(cmdp->crb.source_dde, ddead, (uint64_t) src);
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun /* Target direct dde (scatter-gather list) */
111*4882a593Smuzhiyun clear_dde(cmdp->crb.target_dde);
112*4882a593Smuzhiyun putnn(cmdp->crb.target_dde, dde_count, 0);
113*4882a593Smuzhiyun put32(cmdp->crb.target_dde, ddebc, dstlen);
114*4882a593Smuzhiyun put64(cmdp->crb.target_dde, ddead, (uint64_t) dst);
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun /* Submit the crb, the job descriptor, to the accelerator */
117*4882a593Smuzhiyun return nxu_submit_job(cmdp, handle);
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun /*
121*4882a593Smuzhiyun * Prepares a blank no filename no timestamp gzip header and returns
122*4882a593Smuzhiyun * the number of bytes written to buf.
123*4882a593Smuzhiyun * Gzip specification at https://tools.ietf.org/html/rfc1952
124*4882a593Smuzhiyun */
gzip_header_blank(char * buf)125*4882a593Smuzhiyun int gzip_header_blank(char *buf)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun int i = 0;
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun buf[i++] = 0x1f; /* ID1 */
130*4882a593Smuzhiyun buf[i++] = 0x8b; /* ID2 */
131*4882a593Smuzhiyun buf[i++] = 0x08; /* CM */
132*4882a593Smuzhiyun buf[i++] = 0x00; /* FLG */
133*4882a593Smuzhiyun buf[i++] = 0x00; /* MTIME */
134*4882a593Smuzhiyun buf[i++] = 0x00; /* MTIME */
135*4882a593Smuzhiyun buf[i++] = 0x00; /* MTIME */
136*4882a593Smuzhiyun buf[i++] = 0x00; /* MTIME */
137*4882a593Smuzhiyun buf[i++] = 0x04; /* XFL 4=fastest */
138*4882a593Smuzhiyun buf[i++] = 0x03; /* OS UNIX */
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun return i;
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun /* Caller must free the allocated buffer return nonzero on error. */
read_alloc_input_file(char * fname,char ** buf,size_t * bufsize)144*4882a593Smuzhiyun int read_alloc_input_file(char *fname, char **buf, size_t *bufsize)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun struct stat statbuf;
147*4882a593Smuzhiyun FILE *fp;
148*4882a593Smuzhiyun char *p;
149*4882a593Smuzhiyun size_t num_bytes;
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun if (stat(fname, &statbuf)) {
152*4882a593Smuzhiyun perror(fname);
153*4882a593Smuzhiyun return(-1);
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun fp = fopen(fname, "r");
156*4882a593Smuzhiyun if (fp == NULL) {
157*4882a593Smuzhiyun perror(fname);
158*4882a593Smuzhiyun return(-1);
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun assert(NULL != (p = (char *) malloc(statbuf.st_size)));
161*4882a593Smuzhiyun num_bytes = fread(p, 1, statbuf.st_size, fp);
162*4882a593Smuzhiyun if (ferror(fp) || (num_bytes != statbuf.st_size)) {
163*4882a593Smuzhiyun perror(fname);
164*4882a593Smuzhiyun return(-1);
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun *buf = p;
167*4882a593Smuzhiyun *bufsize = num_bytes;
168*4882a593Smuzhiyun return 0;
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun /* Returns nonzero on error */
write_output_file(char * fname,char * buf,size_t bufsize)172*4882a593Smuzhiyun int write_output_file(char *fname, char *buf, size_t bufsize)
173*4882a593Smuzhiyun {
174*4882a593Smuzhiyun FILE *fp;
175*4882a593Smuzhiyun size_t num_bytes;
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun fp = fopen(fname, "w");
178*4882a593Smuzhiyun if (fp == NULL) {
179*4882a593Smuzhiyun perror(fname);
180*4882a593Smuzhiyun return(-1);
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun num_bytes = fwrite(buf, 1, bufsize, fp);
183*4882a593Smuzhiyun if (ferror(fp) || (num_bytes != bufsize)) {
184*4882a593Smuzhiyun perror(fname);
185*4882a593Smuzhiyun return(-1);
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun fclose(fp);
188*4882a593Smuzhiyun return 0;
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun /*
192*4882a593Smuzhiyun * Z_SYNC_FLUSH as described in zlib.h.
193*4882a593Smuzhiyun * Returns number of appended bytes
194*4882a593Smuzhiyun */
append_sync_flush(char * buf,int tebc,int final)195*4882a593Smuzhiyun int append_sync_flush(char *buf, int tebc, int final)
196*4882a593Smuzhiyun {
197*4882a593Smuzhiyun uint64_t flush;
198*4882a593Smuzhiyun int shift = (tebc & 0x7);
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun if (tebc > 0) {
201*4882a593Smuzhiyun /* Last byte is partially full */
202*4882a593Smuzhiyun buf = buf - 1;
203*4882a593Smuzhiyun *buf = *buf & (unsigned char) ((1<<tebc)-1);
204*4882a593Smuzhiyun } else
205*4882a593Smuzhiyun *buf = 0;
206*4882a593Smuzhiyun flush = ((0x1ULL & final) << shift) | *buf;
207*4882a593Smuzhiyun shift = shift + 3; /* BFINAL and BTYPE written */
208*4882a593Smuzhiyun shift = (shift <= 8) ? 8 : 16;
209*4882a593Smuzhiyun flush |= (0xFFFF0000ULL) << shift; /* Zero length block */
210*4882a593Smuzhiyun shift = shift + 32;
211*4882a593Smuzhiyun while (shift > 0) {
212*4882a593Smuzhiyun *buf++ = (unsigned char) (flush & 0xffULL);
213*4882a593Smuzhiyun flush = flush >> 8;
214*4882a593Smuzhiyun shift = shift - 8;
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun return(((tebc > 5) || (tebc == 0)) ? 5 : 4);
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun /*
220*4882a593Smuzhiyun * Final deflate block bit. This call assumes the block
221*4882a593Smuzhiyun * beginning is byte aligned.
222*4882a593Smuzhiyun */
set_bfinal(void * buf,int bfinal)223*4882a593Smuzhiyun static void set_bfinal(void *buf, int bfinal)
224*4882a593Smuzhiyun {
225*4882a593Smuzhiyun char *b = buf;
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun if (bfinal)
228*4882a593Smuzhiyun *b = *b | (unsigned char) 0x01;
229*4882a593Smuzhiyun else
230*4882a593Smuzhiyun *b = *b & (unsigned char) 0xfe;
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun
compress_file(int argc,char ** argv,void * handle)233*4882a593Smuzhiyun int compress_file(int argc, char **argv, void *handle)
234*4882a593Smuzhiyun {
235*4882a593Smuzhiyun char *inbuf, *outbuf, *srcbuf, *dstbuf;
236*4882a593Smuzhiyun char outname[FNAME_MAX];
237*4882a593Smuzhiyun uint32_t srclen, dstlen;
238*4882a593Smuzhiyun uint32_t flushlen, chunk;
239*4882a593Smuzhiyun size_t inlen, outlen, dsttotlen, srctotlen;
240*4882a593Smuzhiyun uint32_t crc, spbc, tpbc, tebc;
241*4882a593Smuzhiyun int lzcounts = 0;
242*4882a593Smuzhiyun int cc;
243*4882a593Smuzhiyun int num_hdr_bytes;
244*4882a593Smuzhiyun struct nx_gzip_crb_cpb_t *cmdp;
245*4882a593Smuzhiyun uint32_t pagelen = 65536;
246*4882a593Smuzhiyun int fault_tries = NX_MAX_FAULTS;
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun cmdp = (void *)(uintptr_t)
249*4882a593Smuzhiyun aligned_alloc(sizeof(struct nx_gzip_crb_cpb_t),
250*4882a593Smuzhiyun sizeof(struct nx_gzip_crb_cpb_t));
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun if (argc != 2) {
253*4882a593Smuzhiyun fprintf(stderr, "usage: %s <fname>\n", argv[0]);
254*4882a593Smuzhiyun exit(-1);
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun if (read_alloc_input_file(argv[1], &inbuf, &inlen))
257*4882a593Smuzhiyun exit(-1);
258*4882a593Smuzhiyun fprintf(stderr, "file %s read, %ld bytes\n", argv[1], inlen);
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun /* Generous output buffer for header/trailer */
261*4882a593Smuzhiyun outlen = 2 * inlen + 1024;
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun assert(NULL != (outbuf = (char *)malloc(outlen)));
264*4882a593Smuzhiyun nxu_touch_pages(outbuf, outlen, pagelen, 1);
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun /* Compress piecemeal in smallish chunks */
267*4882a593Smuzhiyun chunk = 1<<22;
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun /* Write the gzip header to the stream */
270*4882a593Smuzhiyun num_hdr_bytes = gzip_header_blank(outbuf);
271*4882a593Smuzhiyun dstbuf = outbuf + num_hdr_bytes;
272*4882a593Smuzhiyun outlen = outlen - num_hdr_bytes;
273*4882a593Smuzhiyun dsttotlen = num_hdr_bytes;
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun srcbuf = inbuf;
276*4882a593Smuzhiyun srctotlen = 0;
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun /* Init the CRB, the coprocessor request block */
279*4882a593Smuzhiyun memset(&cmdp->crb, 0, sizeof(cmdp->crb));
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun /* Initial gzip crc32 */
282*4882a593Smuzhiyun put32(cmdp->cpb, in_crc, 0);
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun while (inlen > 0) {
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun /* Submit chunk size source data per job */
287*4882a593Smuzhiyun srclen = NX_MIN(chunk, inlen);
288*4882a593Smuzhiyun /* Supply large target in case data expands */
289*4882a593Smuzhiyun dstlen = NX_MIN(2*srclen, outlen);
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun /* Page faults are handled by the user code */
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun /* Fault-in pages; an improved code wouldn't touch so
294*4882a593Smuzhiyun * many pages but would try to estimate the
295*4882a593Smuzhiyun * compression ratio and adjust both the src and dst
296*4882a593Smuzhiyun * touch amounts.
297*4882a593Smuzhiyun */
298*4882a593Smuzhiyun nxu_touch_pages(cmdp, sizeof(struct nx_gzip_crb_cpb_t), pagelen,
299*4882a593Smuzhiyun 1);
300*4882a593Smuzhiyun nxu_touch_pages(srcbuf, srclen, pagelen, 0);
301*4882a593Smuzhiyun nxu_touch_pages(dstbuf, dstlen, pagelen, 1);
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun cc = compress_fht_sample(
304*4882a593Smuzhiyun srcbuf, srclen,
305*4882a593Smuzhiyun dstbuf, dstlen,
306*4882a593Smuzhiyun lzcounts, cmdp, handle);
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun if (cc != ERR_NX_OK && cc != ERR_NX_TPBC_GT_SPBC &&
309*4882a593Smuzhiyun cc != ERR_NX_AT_FAULT) {
310*4882a593Smuzhiyun fprintf(stderr, "nx error: cc= %d\n", cc);
311*4882a593Smuzhiyun exit(-1);
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun /* Page faults are handled by the user code */
315*4882a593Smuzhiyun if (cc == ERR_NX_AT_FAULT) {
316*4882a593Smuzhiyun NXPRT(fprintf(stderr, "page fault: cc= %d, ", cc));
317*4882a593Smuzhiyun NXPRT(fprintf(stderr, "try= %d, fsa= %08llx\n",
318*4882a593Smuzhiyun fault_tries,
319*4882a593Smuzhiyun (unsigned long long) cmdp->crb.csb.fsaddr));
320*4882a593Smuzhiyun fault_tries--;
321*4882a593Smuzhiyun if (fault_tries > 0) {
322*4882a593Smuzhiyun continue;
323*4882a593Smuzhiyun } else {
324*4882a593Smuzhiyun fprintf(stderr, "error: cannot progress; ");
325*4882a593Smuzhiyun fprintf(stderr, "too many faults\n");
326*4882a593Smuzhiyun exit(-1);
327*4882a593Smuzhiyun };
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun fault_tries = NX_MAX_FAULTS; /* Reset for the next chunk */
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun inlen = inlen - srclen;
333*4882a593Smuzhiyun srcbuf = srcbuf + srclen;
334*4882a593Smuzhiyun srctotlen = srctotlen + srclen;
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun /* Two possible locations for spbc depending on the function
337*4882a593Smuzhiyun * code.
338*4882a593Smuzhiyun */
339*4882a593Smuzhiyun spbc = (!lzcounts) ? get32(cmdp->cpb, out_spbc_comp) :
340*4882a593Smuzhiyun get32(cmdp->cpb, out_spbc_comp_with_count);
341*4882a593Smuzhiyun assert(spbc == srclen);
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun /* Target byte count */
344*4882a593Smuzhiyun tpbc = get32(cmdp->crb.csb, tpbc);
345*4882a593Smuzhiyun /* Target ending bit count */
346*4882a593Smuzhiyun tebc = getnn(cmdp->cpb, out_tebc);
347*4882a593Smuzhiyun NXPRT(fprintf(stderr, "compressed chunk %d ", spbc));
348*4882a593Smuzhiyun NXPRT(fprintf(stderr, "to %d bytes, tebc= %d\n", tpbc, tebc));
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun if (inlen > 0) { /* More chunks to go */
351*4882a593Smuzhiyun set_bfinal(dstbuf, 0);
352*4882a593Smuzhiyun dstbuf = dstbuf + tpbc;
353*4882a593Smuzhiyun dsttotlen = dsttotlen + tpbc;
354*4882a593Smuzhiyun outlen = outlen - tpbc;
355*4882a593Smuzhiyun /* Round up to the next byte with a flush
356*4882a593Smuzhiyun * block; do not set the BFINAqL bit.
357*4882a593Smuzhiyun */
358*4882a593Smuzhiyun flushlen = append_sync_flush(dstbuf, tebc, 0);
359*4882a593Smuzhiyun dsttotlen = dsttotlen + flushlen;
360*4882a593Smuzhiyun outlen = outlen - flushlen;
361*4882a593Smuzhiyun dstbuf = dstbuf + flushlen;
362*4882a593Smuzhiyun NXPRT(fprintf(stderr, "added sync_flush %d bytes\n",
363*4882a593Smuzhiyun flushlen));
364*4882a593Smuzhiyun } else { /* Done */
365*4882a593Smuzhiyun /* Set the BFINAL bit of the last block per Deflate
366*4882a593Smuzhiyun * specification.
367*4882a593Smuzhiyun */
368*4882a593Smuzhiyun set_bfinal(dstbuf, 1);
369*4882a593Smuzhiyun dstbuf = dstbuf + tpbc;
370*4882a593Smuzhiyun dsttotlen = dsttotlen + tpbc;
371*4882a593Smuzhiyun outlen = outlen - tpbc;
372*4882a593Smuzhiyun }
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun /* Resuming crc32 for the next chunk */
375*4882a593Smuzhiyun crc = get32(cmdp->cpb, out_crc);
376*4882a593Smuzhiyun put32(cmdp->cpb, in_crc, crc);
377*4882a593Smuzhiyun crc = be32toh(crc);
378*4882a593Smuzhiyun }
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun /* Append crc32 and ISIZE to the end */
381*4882a593Smuzhiyun memcpy(dstbuf, &crc, 4);
382*4882a593Smuzhiyun memcpy(dstbuf+4, &srctotlen, 4);
383*4882a593Smuzhiyun dsttotlen = dsttotlen + 8;
384*4882a593Smuzhiyun outlen = outlen - 8;
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun assert(FNAME_MAX > (strlen(argv[1]) + strlen(FEXT)));
387*4882a593Smuzhiyun strcpy(outname, argv[1]);
388*4882a593Smuzhiyun strcat(outname, FEXT);
389*4882a593Smuzhiyun if (write_output_file(outname, outbuf, dsttotlen)) {
390*4882a593Smuzhiyun fprintf(stderr, "write error: %s\n", outname);
391*4882a593Smuzhiyun exit(-1);
392*4882a593Smuzhiyun }
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun fprintf(stderr, "compressed %ld to %ld bytes total, ", srctotlen,
395*4882a593Smuzhiyun dsttotlen);
396*4882a593Smuzhiyun fprintf(stderr, "crc32 checksum = %08x\n", crc);
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun if (inbuf != NULL)
399*4882a593Smuzhiyun free(inbuf);
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun if (outbuf != NULL)
402*4882a593Smuzhiyun free(outbuf);
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun return 0;
405*4882a593Smuzhiyun }
406*4882a593Smuzhiyun
main(int argc,char ** argv)407*4882a593Smuzhiyun int main(int argc, char **argv)
408*4882a593Smuzhiyun {
409*4882a593Smuzhiyun int rc;
410*4882a593Smuzhiyun struct sigaction act;
411*4882a593Smuzhiyun void *handle;
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun nx_dbg = 0;
414*4882a593Smuzhiyun nx_gzip_log = NULL;
415*4882a593Smuzhiyun act.sa_handler = 0;
416*4882a593Smuzhiyun act.sa_sigaction = nxu_sigsegv_handler;
417*4882a593Smuzhiyun act.sa_flags = SA_SIGINFO;
418*4882a593Smuzhiyun act.sa_restorer = 0;
419*4882a593Smuzhiyun sigemptyset(&act.sa_mask);
420*4882a593Smuzhiyun sigaction(SIGSEGV, &act, NULL);
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun handle = nx_function_begin(NX_FUNC_COMP_GZIP, 0);
423*4882a593Smuzhiyun if (!handle) {
424*4882a593Smuzhiyun fprintf(stderr, "Unable to init NX, errno %d\n", errno);
425*4882a593Smuzhiyun exit(-1);
426*4882a593Smuzhiyun }
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun rc = compress_file(argc, argv, handle);
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun nx_function_end(handle);
431*4882a593Smuzhiyun
432*4882a593Smuzhiyun return rc;
433*4882a593Smuzhiyun }
434