1 /* SPDX-License-Identifier: BSD-3-Clause */
2 /* Copyright(c) 2007-2022 Intel Corporation */
3 /* $FreeBSD$ */
4 /**
5  *****************************************************************************
6  * @file dc_header_footer.c
7  *
8  * @ingroup Dc_DataCompression
9  *
10  * @description
11  *      Implementation of the Data Compression header and footer operations.
12  *
13  *****************************************************************************/
14 
15 /*
16  *******************************************************************************
17  * Include public/global header files
18  *******************************************************************************
19  */
20 #include "cpa.h"
21 #include "cpa_dc.h"
22 #include "icp_adf_init.h"
23 
24 /*
25  *******************************************************************************
26  * Include private header files
27  *******************************************************************************
28  */
29 #include "dc_header_footer.h"
30 #include "dc_session.h"
31 #include "dc_datapath.h"
32 
33 CpaStatus
34 cpaDcGenerateHeader(CpaDcSessionHandle pSessionHandle,
35 		    CpaFlatBuffer *pDestBuff,
36 		    Cpa32U *count)
37 {
38 	dc_session_desc_t *pSessionDesc = NULL;
39 
40 	LAC_CHECK_NULL_PARAM(pSessionHandle);
41 	LAC_CHECK_NULL_PARAM(pDestBuff);
42 	LAC_CHECK_NULL_PARAM(pDestBuff->pData);
43 	LAC_CHECK_NULL_PARAM(count);
44 
45 	pSessionDesc = DC_SESSION_DESC_FROM_CTX_GET(pSessionHandle);
46 
47 	if (NULL == pSessionDesc) {
48 		QAT_UTILS_LOG("Session handle not as expected\n");
49 		return CPA_STATUS_INVALID_PARAM;
50 	}
51 
52 	if (CPA_DC_DIR_DECOMPRESS == pSessionDesc->sessDirection) {
53 		QAT_UTILS_LOG("Invalid session direction\n");
54 		return CPA_STATUS_INVALID_PARAM;
55 	}
56 
57 	if (CPA_DC_DEFLATE == pSessionDesc->compType) {
58 		/* Adding a Gzip header */
59 		if (CPA_DC_CRC32 == pSessionDesc->checksumType) {
60 			Cpa8U *pDest = pDestBuff->pData;
61 
62 			if (pDestBuff->dataLenInBytes < DC_GZIP_HEADER_SIZE) {
63 				QAT_UTILS_LOG(
64 				    "The dataLenInBytes of the dest buffer is too small.\n");
65 				return CPA_STATUS_INVALID_PARAM;
66 			}
67 
68 			pDest[0] = DC_GZIP_ID1; /* ID1 */
69 			pDest[1] = DC_GZIP_ID2; /* ID2 */
70 			pDest[2] =
71 			    0x08; /* CM = 8 denotes "deflate" compression */
72 			pDest[3] = 0x00; /* FLG = 0 denotes "No extra fields" */
73 			pDest[4] = 0x00;
74 			pDest[5] = 0x00;
75 			pDest[6] = 0x00;
76 			pDest[7] = 0x00; /* MTIME = 0x00 means time stamp not
77 					    available */
78 
79 			/* XFL = 4 - compressor used fastest compression, */
80 			/* XFL = 2 - compressor used maximum compression. */
81 			pDest[8] = 0;
82 			if (CPA_DC_L1 == pSessionDesc->compLevel)
83 				pDest[8] = DC_GZIP_FAST_COMP;
84 			else if (CPA_DC_L4 >= pSessionDesc->compLevel)
85 				pDest[8] = DC_GZIP_MAX_COMP;
86 
87 			pDest[9] =
88 			    DC_GZIP_FILESYSTYPE; /* OS = 0 means FAT filesystem
89 				  (MS-DOS, OS/2, NT/Win32), 3 - Unix */
90 
91 			/* Set to the number of bytes added to the buffer */
92 			*count = DC_GZIP_HEADER_SIZE;
93 		}
94 
95 		/* Adding a Zlib header */
96 		else if (CPA_DC_ADLER32 == pSessionDesc->checksumType) {
97 			Cpa8U *pDest = pDestBuff->pData;
98 			Cpa16U header = 0, level = 0;
99 
100 			if (pDestBuff->dataLenInBytes < DC_ZLIB_HEADER_SIZE) {
101 				QAT_UTILS_LOG(
102 				    "The dataLenInBytes of the dest buffer is too small.\n");
103 				return CPA_STATUS_INVALID_PARAM;
104 			}
105 
106 			/*  CMF = CM | CMINFO.
107 			    CM = 8 denotes "deflate" compression,
108 			    CMINFO = 7 indicates a 32K window size */
109 			/* Depending on the device, at compression levels above
110 			   L1, the
111 			   window size can be 8 or 16K bytes.
112 			   The file will decompress ok if a greater window size
113 			   is specified
114 			   in the header. */
115 			header =
116 			    (DC_ZLIB_CM_DEFLATE +
117 			     (DC_32K_WINDOW_SIZE << DC_ZLIB_WINDOWSIZE_OFFSET))
118 			    << LAC_NUM_BITS_IN_BYTE;
119 
120 			switch (pSessionDesc->compLevel) {
121 			case CPA_DC_L1:
122 				level = DC_ZLIB_LEVEL_0;
123 				break;
124 			case CPA_DC_L2:
125 				level = DC_ZLIB_LEVEL_1;
126 				break;
127 			case CPA_DC_L3:
128 				level = DC_ZLIB_LEVEL_2;
129 				break;
130 			default:
131 				level = DC_ZLIB_LEVEL_3;
132 			}
133 
134 			/* Bits 6 - 7: FLEVEL, compression level */
135 			header |= level << DC_ZLIB_FLEVEL_OFFSET;
136 
137 			/* The header has to be a multiple of 31 */
138 			header += DC_ZLIB_HEADER_OFFSET -
139 			    (header % DC_ZLIB_HEADER_OFFSET);
140 
141 			pDest[0] = (Cpa8U)(header >> LAC_NUM_BITS_IN_BYTE);
142 			pDest[1] = (Cpa8U)header;
143 
144 			/* Set to the number of bytes added to the buffer */
145 			*count = DC_ZLIB_HEADER_SIZE;
146 		}
147 
148 		/* If deflate but no checksum required */
149 		else {
150 			*count = 0;
151 		}
152 	} else {
153 		/* There is no header for other compressed data */
154 		*count = 0;
155 	}
156 	return CPA_STATUS_SUCCESS;
157 }
158 
159 CpaStatus
160 cpaDcGenerateFooter(CpaDcSessionHandle pSessionHandle,
161 		    CpaFlatBuffer *pDestBuff,
162 		    CpaDcRqResults *pRes)
163 {
164 	dc_session_desc_t *pSessionDesc = NULL;
165 
166 	LAC_CHECK_NULL_PARAM(pSessionHandle);
167 	LAC_CHECK_NULL_PARAM(pDestBuff);
168 	LAC_CHECK_NULL_PARAM(pDestBuff->pData);
169 	LAC_CHECK_NULL_PARAM(pRes);
170 
171 	pSessionDesc = DC_SESSION_DESC_FROM_CTX_GET(pSessionHandle);
172 
173 	if (NULL == pSessionDesc) {
174 		QAT_UTILS_LOG("Session handle not as expected\n");
175 		return CPA_STATUS_INVALID_PARAM;
176 	}
177 
178 	if (CPA_DC_DIR_DECOMPRESS == pSessionDesc->sessDirection) {
179 		QAT_UTILS_LOG("Invalid session direction\n");
180 		return CPA_STATUS_INVALID_PARAM;
181 	}
182 
183 	if (CPA_DC_DEFLATE == pSessionDesc->compType) {
184 		if (CPA_DC_CRC32 == pSessionDesc->checksumType) {
185 			Cpa8U *pDest = pDestBuff->pData;
186 			Cpa32U crc32 = pRes->checksum;
187 			Cpa64U totalLenBeforeCompress =
188 			    pSessionDesc->cumulativeConsumedBytes;
189 
190 			if (pDestBuff->dataLenInBytes < DC_GZIP_FOOTER_SIZE) {
191 				QAT_UTILS_LOG(
192 				    "The dataLenInBytes of the dest buffer is too small.\n");
193 				return CPA_STATUS_INVALID_PARAM;
194 			}
195 
196 			/* Crc32 of the uncompressed data */
197 			pDest[0] = (Cpa8U)crc32;
198 			pDest[1] = (Cpa8U)(crc32 >> LAC_NUM_BITS_IN_BYTE);
199 			pDest[2] = (Cpa8U)(crc32 >> 2 * LAC_NUM_BITS_IN_BYTE);
200 			pDest[3] = (Cpa8U)(crc32 >> 3 * LAC_NUM_BITS_IN_BYTE);
201 
202 			/* Length of the uncompressed data */
203 			pDest[4] = (Cpa8U)totalLenBeforeCompress;
204 			pDest[5] = (Cpa8U)(totalLenBeforeCompress >>
205 					   LAC_NUM_BITS_IN_BYTE);
206 			pDest[6] = (Cpa8U)(totalLenBeforeCompress >>
207 					   2 * LAC_NUM_BITS_IN_BYTE);
208 			pDest[7] = (Cpa8U)(totalLenBeforeCompress >>
209 					   3 * LAC_NUM_BITS_IN_BYTE);
210 
211 			/* Increment produced by the number of bytes added to
212 			 * the buffer */
213 			pRes->produced += DC_GZIP_FOOTER_SIZE;
214 		} else if (CPA_DC_ADLER32 == pSessionDesc->checksumType) {
215 			Cpa8U *pDest = pDestBuff->pData;
216 			Cpa32U adler32 = pRes->checksum;
217 
218 			if (pDestBuff->dataLenInBytes < DC_ZLIB_FOOTER_SIZE) {
219 				QAT_UTILS_LOG(
220 				    "The dataLenInBytes of the dest buffer is too small.\n");
221 				return CPA_STATUS_INVALID_PARAM;
222 			}
223 
224 			/* Adler32 of the uncompressed data */
225 			pDest[0] = (Cpa8U)(adler32 >> 3 * LAC_NUM_BITS_IN_BYTE);
226 			pDest[1] = (Cpa8U)(adler32 >> 2 * LAC_NUM_BITS_IN_BYTE);
227 			pDest[2] = (Cpa8U)(adler32 >> LAC_NUM_BITS_IN_BYTE);
228 			pDest[3] = (Cpa8U)adler32;
229 
230 			/* Increment produced by the number of bytes added to
231 			 * the buffer */
232 			pRes->produced += DC_ZLIB_FOOTER_SIZE;
233 		}
234 	}
235 
236 	return CPA_STATUS_SUCCESS;
237 }
238