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