1 /*
2 * Copyright (c) 2022, Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 */
22 //!
23 //! \file vp_visa.cpp
24 //! \brief Contains ISAfile definitions
25 //!
26
27 #include "vp_visa.h"
28 #include <fstream>
29 #include "mos_utilities.h"
30
31 using namespace vp::vISA;
32
ISAfile(const uint8_t * data,unsigned size)33 ISAfile::ISAfile(const uint8_t *data, unsigned size) : version(0), data(data), end(data + size),
34 size(size), error(0), errorIndex(0), header(0), kernel_data_loaded(false), function_data_loaded(false) { }
35
ISAfile(const ISAfile & other)36 ISAfile::ISAfile(const ISAfile& other) {
37 version = other.version;
38 data = other.data;
39 end = other.end;
40 size = other.size;
41 int error_length = std::strlen(other.error);
42 error = new char[error_length + 1];
43 if (nullptr == error)
44 {
45 MOS_OS_ASSERTMESSAGE("create array failed!");
46 return;
47 }
48 char *perror = const_cast<char*>(error);
49 perror[error_length] = '\0';
50 MOS_SecureMemcpy(perror, error_length + 1, other.error, error_length);
51 kernel_data_loaded = other.kernel_data_loaded;
52 function_data_loaded = other.function_data_loaded;
53 errorIndex = other.errorIndex;
54 header = new Header(other.version);
55 *header = *other.header;
56 for (KernelBody *kb : other.kernel_data) {
57 KernelBody *kb2 = new KernelBody(other.version);
58 *kb2 = *kb;
59 kernel_data.push_back(kb2);
60 }
61 for (FunctionBody *fb : other.function_data) {
62 FunctionBody *fb2 = new FunctionBody(other.version);
63 *fb2 = *fb;
64 function_data.push_back(fb2);
65 }
66 }
67
operator =(const ISAfile & other)68 ISAfile& ISAfile::operator= (const ISAfile& other) {
69 if (this != &other) {
70 version = other.version;
71 data = other.data;
72 end = other.end;
73 size = other.size;
74 delete[] error;
75 int error_length = std::strlen(other.error);
76 error = new char[error_length + 1];
77 if (nullptr == error)
78 {
79 MOS_OS_ASSERTMESSAGE("create array failed!");
80 return *this;
81 }
82 char *perror = const_cast<char *>(error);
83 perror[error_length] = '\0';
84 MOS_SecureMemcpy(perror, error_length + 1, other.error, error_length);
85 kernel_data_loaded = other.kernel_data_loaded;
86 function_data_loaded = other.function_data_loaded;
87 errorIndex = other.errorIndex;
88 *header = *other.header;
89 for (KernelBody *kb : kernel_data)
90 delete kb;
91 for (FunctionBody *fb : function_data)
92 delete fb;
93 for (KernelBody *kb : other.kernel_data)
94 kernel_data.push_back(&*kb);
95 for (FunctionBody *fb : other.function_data)
96 function_data.push_back(&*fb);
97 }
98 return *this;
99 }
100
~ISAfile()101 ISAfile::~ISAfile() {
102 delete header;
103 for (KernelBody *kb : kernel_data)
104 delete kb;
105 for (FunctionBody *f : function_data)
106 delete f;
107 if (error)
108 {
109 delete[] error;
110 error = nullptr;
111 }
112 }
113
readFile()114 bool ISAfile::readFile() {
115 bool status = true;
116 status &= loadHeader();
117 if (version < 302)
118 return false;
119 status &= loadKernelData();
120 status &= loadFunctionData();
121 return status;
122 }
123
loadHeader()124 bool ISAfile::loadHeader() {
125 header = new Header(version);
126 const uint8_t *p = header->parse(data, end, this);
127 if (!p) {
128 delete header;
129 return false; //error loading header
130 }
131 return true;
132 }
133
loadKernelData()134 bool ISAfile::loadKernelData() {
135 const uint8_t *p = 0;
136 for (Kernel *k : header->getKernelInfo()) {
137 KernelBody *kb = new KernelBody(version);
138 p = kb->parse(data + k->getOffset(), end, this);
139 if (!p) {
140 delete kb;
141 return false; //error loading kernel_data
142 }
143 kernel_data.push_back(kb);
144 }
145 kernel_data_loaded = true;
146 return true;
147 }
148
loadFunctionData()149 bool ISAfile::loadFunctionData() {
150 const uint8_t *p = 0;
151 for (Function *f : header->getFunctionInfo()) {
152 FunctionBody *fb = new FunctionBody(version);
153 p = fb->parse(data + f->getOffset(), end, this);
154 if (!p) {
155 delete fb;
156 return false; //error loading kernel_data
157 }
158 function_data.push_back(fb);
159 }
160 function_data_loaded = true;
161 return true;
162 }
163
getKernelsData()164 std::vector<KernelBody*> &ISAfile::getKernelsData() {
165 if (!kernel_data_loaded) loadKernelData();
166 return kernel_data;
167 }
168
getFunctionsData()169 std::vector<FunctionBody*> &ISAfile::getFunctionsData() {
170 if (!function_data_loaded) loadFunctionData();
171 return function_data;
172 }
173
readField(const uint8_t * p,const uint8_t * buffEnd,Field & field,unsigned dataSize)174 const uint8_t* ISAfile::readField(const uint8_t *p, const uint8_t *buffEnd,
175 Field &field, unsigned dataSize) {
176 switch (field.type) {
177 case Datatype::ONE: field.number8 = *((int8_t *)p); p++; break;
178 case Datatype::TWO: field.number16 = *((int16_t *)p); p += 2; break;
179 case Datatype::FOUR: field.number32 = *((int32_t *)p); p += 4; break;
180 case Datatype::EIGHT: field.number64 = *((int64_t *)p); p += 8; break;
181 case Datatype::VARCHAR:
182 {
183 if (p + dataSize > buffEnd) {
184 // error: truncated
185 p = 0;
186 return 0;
187 }
188 char *string = new char[dataSize + 1];
189 MOS_SecureMemcpy(string, dataSize + 1, p, dataSize);
190 string[dataSize] = '\0';
191 field.size = dataSize;
192 field.varchar = string;
193 p += dataSize;
194 break;
195 }
196 case Datatype::VARCHAR_POOL:
197 {
198 const uint8_t *strEnd = (const uint8_t *)std::memchr(p, 0, end - p);
199 auto len = strEnd - p;
200 char *string = new char[len + 1];
201 MOS_SecureMemcpy(string, len + 1, p, len);
202 string[len] = '\0';
203 field.size = (uint32_t)len + 1;
204 field.varchar = string;
205 p = strEnd + 1;
206 break;
207 }
208 case Datatype::GDATA:
209 {
210 // copy only if no out of bound.
211 if (p + dataSize < end) {
212 uint8_t *gdata = new uint8_t[dataSize];
213 MOS_SecureMemcpy(gdata, dataSize , p, dataSize);
214 field.gdata = gdata;
215 field.size = dataSize;
216 p += dataSize;
217 } else {
218 field.gdata = nullptr;
219 field.size = 0;
220 }
221 break;
222 }
223 default: break;
224 }
225 return p;
226 }
227
setError(const char * e,unsigned index)228 const uint8_t *ISAfile::setError(const char * e, unsigned index) {
229 error = e;
230 errorIndex = index;
231 return 0;
232 }
233
writeToFile(const char * filename,std::vector<uint8_t> & originalBuffer)234 bool ISAfile::writeToFile(const char *filename, std::vector<uint8_t> &originalBuffer) {
235 if (!header) {
236 setError("Header not loaded", 0);
237 return false;
238 }
239 if (!kernel_data_loaded)
240 loadKernelData();
241 if (!function_data_loaded)
242 loadFunctionData();
243
244 std::ofstream newFile(filename, std::ios::out | std::ios::binary);
245 if (!newFile) {
246 setError("Error creating new file ", 0);
247 return false;
248 }
249
250 // buffer
251 std::vector<char> buffer;
252 // header
253 header->addToBuffer(buffer, this);
254
255 // kernel body
256 for (KernelBody* k : kernel_data) {
257 k->addToBuffer(buffer, this);
258 }
259
260 // function body
261 for (FunctionBody* f : function_data) {
262 f->addToBuffer(buffer, this);
263 }
264
265 // gen binaries for this kernel
266 for (Kernel *k : header->getKernelInfo()) {
267 for (GenBinary *g : k->getGenBinaryInfo()) {
268 uint32_t offset = g->getBinaryOffset();
269 if (offset > originalBuffer.size()) {
270 setError("Error writing GEN binary into ISA file, bad offset from original file", 0);
271 return false;
272 }
273 for (uint32_t b = 0; b < g->getBinarySize(); b++) {
274 buffer.push_back(static_cast<char>(originalBuffer[offset + b]));
275 }
276 }
277 }
278
279 newFile.write(buffer.data(), buffer.size());
280 newFile.close();
281 return true;
282 }
283
addToBuffer(Field & field,std::vector<char> & buffer)284 void ISAfile::addToBuffer(Field &field, std::vector<char> &buffer) {
285 switch (field.type) {
286 case Datatype::ONE: buffer.push_back(field.ui8[0]); break;
287 case Datatype::TWO: buffer.push_back(field.ui8[0]); buffer.push_back(field.ui8[1]); break;
288 case Datatype::FOUR: buffer.push_back(field.ui8[0]); buffer.push_back(field.ui8[1]);
289 buffer.push_back(field.ui8[2]); buffer.push_back(field.ui8[3]); break;
290 case Datatype::EIGHT: buffer.push_back(field.ui8[0]); buffer.push_back(field.ui8[1]);
291 buffer.push_back(field.ui8[2]); buffer.push_back(field.ui8[3]);
292 buffer.push_back(field.ui8[4]); buffer.push_back(field.ui8[5]);
293 buffer.push_back(field.ui8[6]); buffer.push_back(field.ui8[7]); break;
294 case Datatype::VARCHAR:
295 {
296 for (unsigned i = 0; i < field.size; i++) {
297 buffer.push_back(static_cast<char>(field.varchar[i]));
298 }
299 break;
300 }
301 case Datatype::VARCHAR_POOL:
302 {
303 for (unsigned i = 0; i < field.size; i++) {
304 buffer.push_back(static_cast<char>(field.varchar[i]));
305 }
306 break;
307 }
308 case Datatype::GDATA:
309 {
310 for (unsigned i = 0; i < field.size; i++) {
311 buffer.push_back(static_cast<char>(field.gdata[i]));
312 }
313 break;
314 }
315 default: break;
316 }
317 }
318