1/* 2 * Copyright (c) 2012-2015 Advanced Micro Devices, Inc. 3 * All rights reserved. 4 * 5 * For use for simulation and test purposes only 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright notice, 11 * this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright notice, 14 * this list of conditions and the following disclaimer in the documentation 15 * and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the copyright holder nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 * 33 * Author: Steve Reinhardt, Anthony Gutierrez 34 */ 35 36#include "gpu-compute/brig_object.hh" 37 38#include <fcntl.h> 39#include <sys/mman.h> 40#include <sys/types.h> 41#include <unistd.h> 42 43#include <cassert> 44#include <cstddef> 45#include <cstdlib> 46 47#include "arch/hsail/Brig.h" 48#include "base/logging.hh" 49#include "base/trace.hh" 50#include "debug/BRIG.hh" 51#include "debug/HSAILObject.hh" 52#include "debug/HSALoader.hh" 53 54using namespace Brig; 55 56std::vector<std::function<HsaObject*(const std::string&, int, uint8_t*)>> 57 HsaObject::tryFileFuncs = { BrigObject::tryFile }; 58 59extern int getBrigDataTypeBytes(BrigType16_t t); 60 61const char *BrigObject::sectionNames[] = 62{ 63 "hsa_data", 64 "hsa_code", 65 "hsa_operand", 66 ".shstrtab" 67}; 68 69const char *segmentNames[] = 70{ 71 "none", 72 "flat", 73 "global", 74 "readonly", 75 "kernarg", 76 "group", 77 "private", 78 "spill", 79 "args" 80}; 81 82const uint8_t* 83BrigObject::getSectionOffset(enum SectionIndex sec, int offs) const 84{ 85 // allow offs == size for dummy end pointers 86 assert(offs <= sectionInfo[sec].size); 87 88 return sectionInfo[sec].ptr + offs; 89} 90 91const char* 92BrigObject::getString(int offs) const 93{ 94 return (const char*)(getSectionOffset(DataSectionIndex, offs) + 4); 95} 96 97const BrigBase* 98BrigObject::getCodeSectionEntry(int offs) const 99{ 100 return (const BrigBase*)getSectionOffset(CodeSectionIndex, offs); 101} 102 103const BrigData* 104BrigObject::getBrigBaseData(int offs) const 105{ 106 return (Brig::BrigData*)(getSectionOffset(DataSectionIndex, offs)); 107} 108 109const uint8_t* 110BrigObject::getData(int offs) const 111{ 112 return getSectionOffset(DataSectionIndex, offs); 113} 114 115const BrigOperand* 116BrigObject::getOperand(int offs) const 117{ 118 return (const BrigOperand*)getSectionOffset(OperandsSectionIndex, offs); 119} 120 121unsigned 122BrigObject::getOperandPtr(int offs, int index) const 123{ 124 unsigned *op_offs = (unsigned*)(getData(offs + 4 * (index + 1))); 125 126 return *op_offs; 127} 128 129const BrigInstBase* 130BrigObject::getInst(int offs) const 131{ 132 return (const BrigInstBase*)getSectionOffset(CodeSectionIndex, offs); 133} 134 135HsaCode* 136BrigObject::getKernel(const std::string &name) const 137{ 138 return nullptr; 139} 140 141HsaCode* 142BrigObject::getFunction(const std::string &name) const 143{ 144 for (int i = 0; i < functions.size(); ++i) { 145 if (functions[i]->name() == name) { 146 return functions[i]; 147 } 148 } 149 150 return nullptr; 151} 152 153void 154BrigObject::processDirectives(const BrigBase *dirPtr, const BrigBase *endPtr, 155 StorageMap *storageMap) 156{ 157 while (dirPtr < endPtr) { 158 if (!dirPtr->byteCount) { 159 fatal("Bad directive size 0\n"); 160 } 161 162 // calculate next pointer now so we can override it if needed 163 const BrigBase *nextDirPtr = brigNext(dirPtr); 164 165 DPRINTF(HSAILObject, "Code section entry kind: #%x, byte count: %d\n", 166 dirPtr->kind, dirPtr->byteCount); 167 168 switch (dirPtr->kind) { 169 case BRIG_KIND_DIRECTIVE_FUNCTION: 170 { 171 const BrigDirectiveExecutable *p M5_VAR_USED = 172 reinterpret_cast<const BrigDirectiveExecutable*>(dirPtr); 173 174 DPRINTF(HSAILObject,"DIRECTIVE_FUNCTION: %s offset: " 175 "%d next: %d\n", getString(p->name), 176 p->firstCodeBlockEntry, p->nextModuleEntry); 177 178 if (p->firstCodeBlockEntry != p->nextModuleEntry) { 179 // Function calls are not supported. We allow the BRIG 180 // object file to create stubs, but the function calls will 181 // not work properly if the application makes use of them. 182 warn("HSA function invocations are unsupported.\n"); 183 184 const char *name = getString(p->name); 185 186 HsailCode *code_obj = nullptr; 187 188 for (int i = 0; i < functions.size(); ++i) { 189 if (functions[i]->name() == name) { 190 code_obj = functions[i]; 191 break; 192 } 193 } 194 195 if (!code_obj) { 196 // create new local storage map for kernel-local symbols 197 code_obj = new HsailCode(name, p, this, 198 new StorageMap(storageMap)); 199 functions.push_back(code_obj); 200 } else { 201 panic("Multiple definition of Function!!: %s\n", 202 getString(p->name)); 203 } 204 } 205 206 nextDirPtr = getCodeSectionEntry(p->nextModuleEntry); 207 } 208 break; 209 210 case BRIG_KIND_DIRECTIVE_KERNEL: 211 { 212 const BrigDirectiveExecutable *p = 213 reinterpret_cast<const BrigDirectiveExecutable*>(dirPtr); 214 215 DPRINTF(HSAILObject,"DIRECTIVE_KERNEL: %s offset: %d count: " 216 "next: %d\n", getString(p->name), 217 p->firstCodeBlockEntry, p->nextModuleEntry); 218 219 const char *name = getString(p->name); 220 221 if (name[0] == '&') 222 name++; 223 224 std::string str = name; 225 char *temp; 226 int len = str.length(); 227 228 if (str[len - 1] >= 'a' && str[len - 1] <= 'z') { 229 temp = new char[str.size() + 1]; 230 std::copy(str.begin(), str.end() , temp); 231 temp[str.size()] = '\0'; 232 } else { 233 temp = new char[str.size()]; 234 std::copy(str.begin(), str.end() - 1 , temp); 235 temp[str.size() - 1 ] = '\0'; 236 } 237 238 std::string kernel_name = temp; 239 delete[] temp; 240 241 HsailCode *code_obj = nullptr; 242 243 for (const auto &kernel : kernels) { 244 if (kernel->name() == kernel_name) { 245 code_obj = kernel; 246 break; 247 } 248 } 249 250 if (!code_obj) { 251 // create new local storage map for kernel-local symbols 252 code_obj = new HsailCode(kernel_name, p, this, 253 new StorageMap(storageMap)); 254 255 kernels.push_back(code_obj); 256 } 257 258 nextDirPtr = getCodeSectionEntry(p->nextModuleEntry); 259 } 260 break; 261 262 case BRIG_KIND_DIRECTIVE_VARIABLE: 263 { 264 const BrigDirectiveVariable *p = 265 reinterpret_cast<const BrigDirectiveVariable*>(dirPtr); 266 267 uint64_t readonlySize_old = 268 storageMap->getSize(BRIG_SEGMENT_READONLY); 269 270 StorageElement* se = storageMap->addSymbol(p, this); 271 272 DPRINTF(HSAILObject, "DIRECTIVE_VARIABLE, symbol %s\n", 273 getString(p->name)); 274 275 if (p->segment == BRIG_SEGMENT_READONLY) { 276 // readonly memory has initialization data 277 uint8_t* readonlyData_old = readonlyData; 278 279 readonlyData = 280 new uint8_t[storageMap->getSize(BRIG_SEGMENT_READONLY)]; 281 282 if (p->init) { 283 if ((p->type == BRIG_TYPE_ROIMG) || 284 (p->type == BRIG_TYPE_WOIMG) || 285 (p->type == BRIG_TYPE_SAMP) || 286 (p->type == BRIG_TYPE_SIG32) || 287 (p->type == BRIG_TYPE_SIG64)) { 288 panic("Read only data type not supported: %s\n", 289 getString(p->name)); 290 } 291 292 const BrigOperand *brigOp = getOperand(p->init); 293 assert(brigOp->kind == 294 BRIG_KIND_OPERAND_CONSTANT_BYTES); 295 296 const Brig::BrigData *operand_data M5_VAR_USED = 297 getBrigBaseData(((BrigOperandConstantBytes*) 298 brigOp)->bytes); 299 300 assert((operand_data->byteCount / 4) > 0); 301 302 uint8_t *symbol_data = 303 (uint8_t*)getData(((BrigOperandConstantBytes*) 304 brigOp)->bytes + 4); 305 306 // copy the old data and add the new data 307 if (readonlySize_old > 0) { 308 memcpy(readonlyData, readonlyData_old, 309 readonlySize_old); 310 } 311 312 memcpy(readonlyData + se->offset, symbol_data, 313 se->size); 314 315 delete[] readonlyData_old; 316 } 317 } 318 } 319 break; 320 321 case BRIG_KIND_DIRECTIVE_LABEL: 322 { 323 const BrigDirectiveLabel M5_VAR_USED *p = 324 reinterpret_cast<const BrigDirectiveLabel*>(dirPtr); 325 326 panic("Label directives cannot be at the module level: %s\n", 327 getString(p->name)); 328 329 } 330 break; 331 332 case BRIG_KIND_DIRECTIVE_COMMENT: 333 { 334 const BrigDirectiveComment M5_VAR_USED *p = 335 reinterpret_cast<const BrigDirectiveComment*>(dirPtr); 336 337 DPRINTF(HSAILObject, "DIRECTIVE_COMMENT: %s\n", 338 getString(p->name)); 339 } 340 break; 341 342 case BRIG_KIND_DIRECTIVE_LOC: 343 { 344 DPRINTF(HSAILObject, "BRIG_DIRECTIVE_LOC\n"); 345 } 346 break; 347 348 case BRIG_KIND_DIRECTIVE_MODULE: 349 { 350 const BrigDirectiveModule M5_VAR_USED *p = 351 reinterpret_cast<const BrigDirectiveModule*>(dirPtr); 352 353 DPRINTF(HSAILObject, "BRIG_DIRECTIVE_MODULE: %s\n", 354 getString(p->name)); 355 } 356 break; 357 358 case BRIG_KIND_DIRECTIVE_CONTROL: 359 { 360 DPRINTF(HSAILObject, "DIRECTIVE_CONTROL\n"); 361 } 362 break; 363 364 case BRIG_KIND_DIRECTIVE_PRAGMA: 365 { 366 DPRINTF(HSAILObject, "DIRECTIVE_PRAGMA\n"); 367 } 368 break; 369 370 case BRIG_KIND_DIRECTIVE_EXTENSION: 371 { 372 DPRINTF(HSAILObject, "DIRECTIVE_EXTENSION\n"); 373 } 374 break; 375 376 case BRIG_KIND_DIRECTIVE_ARG_BLOCK_START: 377 { 378 DPRINTF(HSAILObject, "DIRECTIVE_ARG_BLOCK_START\n"); 379 } 380 break; 381 382 case BRIG_KIND_DIRECTIVE_ARG_BLOCK_END: 383 { 384 DPRINTF(HSAILObject, "DIRECTIVE_ARG_BLOCK_END\n"); 385 } 386 break; 387 default: 388 if (dirPtr->kind >= BRIG_KIND_INST_BEGIN && 389 dirPtr->kind <= BRIG_KIND_INST_END) 390 break; 391 392 if (dirPtr->kind >= BRIG_KIND_OPERAND_BEGIN && 393 dirPtr->kind <= BRIG_KIND_OPERAND_END) 394 break; 395 396 warn("Unknown Brig directive kind: %d\n", dirPtr->kind); 397 break; 398 } 399 400 dirPtr = nextDirPtr; 401 } 402} 403 404HsaObject* 405BrigObject::tryFile(const std::string &fname, int len, uint8_t *fileData) 406{ 407 const char *brig_ident = "HSA BRIG"; 408 409 if (memcmp(brig_ident, fileData, MODULE_IDENTIFICATION_LENGTH)) 410 return nullptr; 411 412 return new BrigObject(fname, len, fileData); 413} 414 415BrigObject::BrigObject(const std::string &fname, int len, uint8_t *fileData) 416 : HsaObject(fname), storageMap(new StorageMap()) 417{ 418 const char *brig_ident = "HSA BRIG"; 419 BrigModuleHeader *mod_hdr = (BrigModuleHeader*)fileData; 420 421 fatal_if(memcmp(brig_ident, mod_hdr, MODULE_IDENTIFICATION_LENGTH), 422 "%s is not a BRIG file\n", fname); 423 424 if (mod_hdr->brigMajor != BRIG_VERSION_BRIG_MAJOR || 425 mod_hdr->brigMinor != BRIG_VERSION_BRIG_MINOR) { 426 fatal("%s: BRIG version mismatch, %d.%d != %d.%d\n", 427 fname, mod_hdr->brigMajor, mod_hdr->brigMinor, 428 BRIG_VERSION_BRIG_MAJOR, BRIG_VERSION_BRIG_MINOR); 429 } 430 431 fatal_if(mod_hdr->sectionCount != NumSectionIndices, "%s: BRIG section " 432 "count (%d) != expected value (%d)\n", fname, 433 mod_hdr->sectionCount, NumSectionIndices); 434 435 for (int i = 0; i < NumSectionIndices; ++i) { 436 sectionInfo[i].ptr = nullptr; 437 } 438 439 uint64_t *sec_idx_table = (uint64_t*)(fileData + mod_hdr->sectionIndex); 440 for (int sec_idx = 0; sec_idx < mod_hdr->sectionCount; ++sec_idx) { 441 uint8_t *sec_hdr_byte_ptr = fileData + sec_idx_table[sec_idx]; 442 BrigSectionHeader *sec_hdr = (BrigSectionHeader*)sec_hdr_byte_ptr; 443 444 // It doesn't look like cprintf supports string precision values, 445 // but if this breaks, the right answer is to fix that 446 DPRINTF(HSAILObject, "found section %.*s\n", sec_hdr->nameLength, 447 sec_hdr->name); 448 449 sectionInfo[sec_idx].ptr = new uint8_t[sec_hdr->byteCount]; 450 memcpy(sectionInfo[sec_idx].ptr, sec_hdr_byte_ptr, sec_hdr->byteCount); 451 sectionInfo[sec_idx].size = sec_hdr->byteCount; 452 } 453 454 BrigSectionHeader *code_hdr = 455 (BrigSectionHeader*)sectionInfo[CodeSectionIndex].ptr; 456 457 DPRINTF(HSAILObject, "Code section hdr, count: %d, hdr count: %d, " 458 "name len: %d\n", code_hdr->byteCount, code_hdr->headerByteCount, 459 code_hdr->nameLength); 460 461 // start at offset 4 to skip initial null entry (see Brig spec) 462 processDirectives(getCodeSectionEntry(code_hdr->headerByteCount), 463 getCodeSectionEntry(sectionInfo[CodeSectionIndex].size), 464 storageMap); 465 466 delete[] fileData; 467 468 DPRINTF(HSALoader, "BRIG object %s loaded.\n", fname); 469} 470 471BrigObject::~BrigObject() 472{ 473 for (int i = 0; i < NumSectionIndices; ++i) 474 if (sectionInfo[i].ptr) 475 delete[] sectionInfo[i].ptr; 476} 477