1 /*
2 * Copyright (c) 2017, 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 cm_visa.cpp
24 //! \brief Contains ISAfile definitions
25 //!
26
27 #include "cm_visa.h"
28 #include "cm_def_os.h"
29 #include <fstream>
30 #include "mos_utilities.h"
31
32 using namespace vISA;
33
ISAfile(const uint8_t * data,unsigned size)34 ISAfile::ISAfile(const uint8_t *data, unsigned size) : version(0), data(data), end(data + size),
35 size(size), error(0), errorIndex(0), header(0), kernel_data_loaded(false), function_data_loaded(false) { }
36
ISAfile(const ISAfile & other)37 ISAfile::ISAfile(const ISAfile& other) {
38 version = other.version;
39 data = other.data;
40 end = other.end;
41 size = other.size;
42 unsigned int error_length = std::strlen(other.error) + 1;
43 char *perror = new char[error_length];
44 MOS_SecureMemcpy(perror, error_length, other.error, error_length);
45 error = perror;
46 kernel_data_loaded = other.kernel_data_loaded;
47 function_data_loaded = other.function_data_loaded;
48 errorIndex = other.errorIndex;
49 header = new Header(other.version);
50 *header = *other.header;
51 for (KernelBody *kb : other.kernel_data) {
52 KernelBody *kb2 = new KernelBody(other.version);
53 *kb2 = *kb;
54 kernel_data.push_back(kb2);
55 }
56 for (FunctionBody *fb : other.function_data) {
57 FunctionBody *fb2 = new FunctionBody(other.version);
58 *fb2 = *fb;
59 function_data.push_back(fb2);
60 }
61 }
62
operator =(const ISAfile & other)63 ISAfile& ISAfile::operator= (const ISAfile& other) {
64 if (this != &other) {
65 version = other.version;
66 data = other.data;
67 end = other.end;
68 size = other.size;
69 delete[] error;
70 unsigned int error_length = std::strlen(other.error) + 1;
71 char *perror = new char[error_length];
72 MOS_SecureMemcpy(perror, error_length, other.error, error_length);
73 error = perror;
74 kernel_data_loaded = other.kernel_data_loaded;
75 function_data_loaded = other.function_data_loaded;
76 errorIndex = other.errorIndex;
77 *header = *other.header;
78 for (KernelBody *kb : kernel_data)
79 delete kb;
80 for (FunctionBody *fb : function_data)
81 delete fb;
82 for (KernelBody *kb : other.kernel_data)
83 kernel_data.push_back(&*kb);
84 for (FunctionBody *fb : other.function_data)
85 function_data.push_back(&*fb);
86 }
87 return *this;
88 }
89
~ISAfile()90 ISAfile::~ISAfile() {
91 delete header;
92 delete[] error;
93 for (KernelBody *kb : kernel_data)
94 delete kb;
95 for (FunctionBody *f : function_data)
96 delete f;
97 }
98
readFile()99 bool ISAfile::readFile() {
100 bool status = true;
101 status &= loadHeader();
102 if (version < 302)
103 return false;
104 status &= loadKernelData();
105 status &= loadFunctionData();
106 return status;
107 }
108
loadHeader()109 bool ISAfile::loadHeader() {
110 header = new Header(version);
111 const uint8_t *p = header->parse(data, end, this);
112 if (!p) {
113 delete header;
114 return false; //error loading header
115 }
116 return true;
117 }
118
loadKernelData()119 bool ISAfile::loadKernelData() {
120 const uint8_t *p = 0;
121 for (Kernel *k : header->getKernelInfo()) {
122 KernelBody *kb = new KernelBody(version);
123 p = kb->parse(data + k->getOffset(), end, this);
124 if (!p) {
125 delete kb;
126 return false; //error loading kernel_data
127 }
128 kernel_data.push_back(kb);
129 }
130 kernel_data_loaded = true;
131 return true;
132 }
133
loadFunctionData()134 bool ISAfile::loadFunctionData() {
135 const uint8_t *p = 0;
136 for (Function *f : header->getFunctionInfo()) {
137 FunctionBody *fb = new FunctionBody(version);
138 p = fb->parse(data + f->getOffset(), end, this);
139 if (!p) {
140 delete fb;
141 return false; //error loading kernel_data
142 }
143 function_data.push_back(fb);
144 }
145 function_data_loaded = true;
146 return true;
147 }
148
getKernelsData()149 std::vector<KernelBody*> &ISAfile::getKernelsData() {
150 if (!kernel_data_loaded) loadKernelData();
151 return kernel_data;
152 }
153
getFunctionsData()154 std::vector<FunctionBody*> &ISAfile::getFunctionsData() {
155 if (!function_data_loaded) loadFunctionData();
156 return function_data;
157 }
158
readField(const uint8_t * p,const uint8_t * buffEnd,Field & field,unsigned dataSize)159 const uint8_t* ISAfile::readField(const uint8_t *p, const uint8_t *buffEnd,
160 Field &field, unsigned dataSize) {
161 switch (field.type) {
162 case Datatype::ONE: field.number8 = *((int8_t *)p); p++; break;
163 case Datatype::TWO: field.number16 = *((int16_t *)p); p += 2; break;
164 case Datatype::FOUR: field.number32 = *((int32_t *)p); p += 4; break;
165 case Datatype::EIGHT: field.number64 = *((int64_t *)p); p += 8; break;
166 case Datatype::VARCHAR:
167 {
168 if (p + dataSize > buffEnd) {
169 // error: truncated
170 p = 0;
171 return 0;
172 }
173 char *string = new char[dataSize + 1];
174 MOS_SecureMemcpy(string, dataSize + 1, p, dataSize);
175 string[dataSize] = '\0';
176 field.size = dataSize;
177 field.varchar = string;
178 p += dataSize;
179 break;
180 }
181 case Datatype::VARCHAR_POOL:
182 {
183 const uint8_t *strEnd = (const uint8_t *)std::memchr(p, 0, end - p);
184 auto len = strEnd - p;
185 char *string = new char[len + 1];
186 MOS_SecureMemcpy(string, len + 1, p, len);
187 string[len] = '\0';
188 field.size = (uint32_t)len + 1;
189 field.varchar = string;
190 p = strEnd + 1;
191 break;
192 }
193 case Datatype::GDATA:
194 {
195 // copy only if no out of bound.
196 if (p + dataSize < end) {
197 uint8_t *gdata = new uint8_t[dataSize];
198 MOS_SecureMemcpy(gdata, dataSize , p, dataSize);
199 field.gdata = gdata;
200 field.size = dataSize;
201 p += dataSize;
202 } else {
203 field.gdata = nullptr;
204 field.size = 0;
205 }
206 break;
207 }
208 default: break;
209 }
210 return p;
211 }
212
setError(const char * e,unsigned index)213 const uint8_t *ISAfile::setError(const char * e, unsigned index) {
214 error = e;
215 errorIndex = index;
216 return 0;
217 }
218
writeToFile(const char * filename,std::vector<uint8_t> & originalBuffer)219 bool ISAfile::writeToFile(const char *filename, std::vector<uint8_t> &originalBuffer) {
220 if (!header) {
221 setError("Header not loaded", 0);
222 return false;
223 }
224 if (!kernel_data_loaded)
225 loadKernelData();
226 if (!function_data_loaded)
227 loadFunctionData();
228
229 std::ofstream newFile(filename, std::ios::out | std::ios::binary);
230 if (!newFile) {
231 setError("Error creating new file ", 0);
232 return false;
233 }
234
235 // buffer
236 std::vector<char> buffer;
237 // header
238 header->addToBuffer(buffer, this);
239
240 // kernel body
241 for (KernelBody* k : kernel_data) {
242 k->addToBuffer(buffer, this);
243 }
244
245 // function body
246 for (FunctionBody* f : function_data) {
247 f->addToBuffer(buffer, this);
248 }
249
250 // gen binaries for this kernel
251 for (Kernel *k : header->getKernelInfo()) {
252 for (GenBinary *g : k->getGenBinaryInfo()) {
253 uint32_t offset = g->getBinaryOffset();
254 if (offset > originalBuffer.size()) {
255 setError("Error writing GEN binary into ISA file, bad offset from original file", 0);
256 return false;
257 }
258 for (uint32_t b = 0; b < g->getBinarySize(); b++) {
259 buffer.push_back(static_cast<char>(originalBuffer[offset + b]));
260 }
261 }
262 }
263
264 newFile.write(buffer.data(), buffer.size());
265 newFile.close();
266 return true;
267 }
268
addToBuffer(Field & field,std::vector<char> & buffer)269 void ISAfile::addToBuffer(Field &field, std::vector<char> &buffer) {
270 switch (field.type) {
271 case Datatype::ONE: buffer.push_back(field.ui8[0]); break;
272 case Datatype::TWO: buffer.push_back(field.ui8[0]); buffer.push_back(field.ui8[1]); break;
273 case Datatype::FOUR: buffer.push_back(field.ui8[0]); buffer.push_back(field.ui8[1]);
274 buffer.push_back(field.ui8[2]); buffer.push_back(field.ui8[3]); break;
275 case Datatype::EIGHT: buffer.push_back(field.ui8[0]); buffer.push_back(field.ui8[1]);
276 buffer.push_back(field.ui8[2]); buffer.push_back(field.ui8[3]);
277 buffer.push_back(field.ui8[4]); buffer.push_back(field.ui8[5]);
278 buffer.push_back(field.ui8[6]); buffer.push_back(field.ui8[7]); break;
279 case Datatype::VARCHAR:
280 {
281 for (unsigned i = 0; i < field.size; i++) {
282 buffer.push_back(static_cast<char>(field.varchar[i]));
283 }
284 break;
285 }
286 case Datatype::VARCHAR_POOL:
287 {
288 for (unsigned i = 0; i < field.size; i++) {
289 buffer.push_back(static_cast<char>(field.varchar[i]));
290 }
291 break;
292 }
293 case Datatype::GDATA:
294 {
295 for (unsigned i = 0; i < field.size; i++) {
296 buffer.push_back(static_cast<char>(field.gdata[i]));
297 }
298 break;
299 }
300 default: break;
301 }
302 }
303