source: CLRX/CLRadeonExtender/trunk/amdbin/AmdCL2Binaries.cpp @ 3112

Last change on this file since 3112 was 3112, checked in by matszpk, 2 years ago

CLRadeonExtender: AmdCL2Bin: fix for GFX900.

File size: 40.9 KB
Line 
1/*
2 *  CLRadeonExtender - Unofficial OpenCL Radeon Extensions Library
3 *  Copyright (C) 2014-2017 Mateusz Szpakowski
4 *
5 *  This library is free software; you can redistribute it and/or
6 *  modify it under the terms of the GNU Lesser General Public
7 *  License as published by the Free Software Foundation; either
8 *  version 2.1 of the License, or (at your option) any later version.
9 *
10 *  This library is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 *  Lesser General Public License for more details.
14 *
15 *  You should have received a copy of the GNU Lesser General Public
16 *  License along with this library; if not, write to the Free Software
17 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19
20#include <CLRX/Config.h>
21#include <cstdlib>
22#include <cstring>
23#include <climits>
24#include <cstdint>
25#include <utility>
26#include <vector>
27#include <CLRX/amdbin/Elf.h>
28#include <CLRX/utils/Utilities.h>
29#include <CLRX/utils/MemAccess.h>
30#include <CLRX/utils/GPUId.h>
31#include <CLRX/amdbin/AmdCL2Binaries.h>
32
33using namespace CLRX;
34
35/* class AmdCL2InnerGPUBinaryBase */
36
37AmdCL2InnerGPUBinaryBase::~AmdCL2InnerGPUBinaryBase()
38{ }
39
40const AmdCL2GPUKernel& AmdCL2InnerGPUBinaryBase::getKernelData(const char* name) const
41{
42    KernelDataMap::const_iterator it = binaryMapFind(
43            kernelDataMap.begin(), kernelDataMap.end(), name);
44    if (it == kernelDataMap.end())
45        throw Exception("Can't find kernel name");
46    return kernels[it->second];
47}
48
49/* AmdCL2OldInnerGPUBinary */
50
51template<typename Types>
52AmdCL2OldInnerGPUBinary::AmdCL2OldInnerGPUBinary(ElfBinaryTemplate<Types>* mainBinary,
53            size_t binaryCodeSize, cxbyte* binaryCode, Flags _creationFlags)
54        : creationFlags(_creationFlags), binarySize(binaryCodeSize), binary(binaryCode)
55{
56    if ((creationFlags & (AMDCL2BIN_CREATE_KERNELDATA|AMDCL2BIN_CREATE_KERNELSTUBS)) == 0)
57        return; // nothing to initialize
58    uint16_t textIndex = SHN_UNDEF;
59    try
60    { textIndex = mainBinary->getSectionIndex(".text"); }
61    catch(const Exception& ex)
62    { }
63    // find symbols of ISA kernel binary
64    std::vector<size_t> choosenSyms;
65    const size_t symbolsNum = mainBinary->getSymbolsNum();
66    for (size_t i = 0; i < symbolsNum; i++)
67    {
68        const char* symName = mainBinary->getSymbolName(i);
69        const size_t len = ::strlen(symName);
70        if (len < 30 || ::strncmp(symName, "__ISA_&__OpenCL_", 16) != 0 ||
71            ::strcmp(symName+len-14, "_kernel_binary") != 0) // not binary, skip
72            continue;
73        choosenSyms.push_back(i);
74    }
75    // allocate structures
76    if (hasKernelData())
77        kernels.resize(choosenSyms.size());
78    if (hasKernelStubs())
79        kernelStubs.reset(new AmdCL2GPUKernelStub[choosenSyms.size()]);
80    if (hasKernelDataMap())
81        kernelDataMap.resize(choosenSyms.size());
82   
83    size_t ki = 0;
84    // main loop for kernel data and stub getting
85    for (size_t index: choosenSyms)
86    {
87        const typename Types::Sym& sym = mainBinary->getSymbol(index);
88        const char* symName = mainBinary->getSymbolName(index);
89        const size_t binOffset = ULEV(sym.st_value);
90        const size_t binSize = ULEV(sym.st_size);
91        /// check conditions for symbol
92        if (textIndex != ULEV(sym.st_shndx))
93            throw Exception("Kernel symbol outside text section");
94        if (binOffset >= binaryCodeSize)
95            throw Exception("Kernel binary code offset out of range");
96        if (usumGt(binOffset, binSize, binaryCodeSize))
97            throw Exception("Kernel binary code offset and size out of range");
98        if (binSize < 256+192)
99            throw Exception("Kernel binary code size is too short");
100       
101        AmdCL2GPUKernelStub kernelStub;
102        AmdCL2GPUKernel kernelData;
103        // set data for stub
104        kernelStub.data = binaryCode + binOffset;
105        const size_t setupOffset = ULEV(*reinterpret_cast<uint32_t*>(kernelStub.data));
106        if (setupOffset >= binSize)
107            throw Exception("Kernel setup offset out of range");
108        kernelStub.size = setupOffset;
109        kernelData.setup = kernelStub.data + setupOffset;
110        // get size of setup (offset 16 of setup)
111        const size_t textOffset = ULEV(*reinterpret_cast<uint32_t*>(kernelData.setup+16));
112        if (usumGe(textOffset, setupOffset, binSize))
113            throw Exception("Kernel text offset out of range");
114        kernelData.setupSize = textOffset;
115        kernelData.code = kernelData.setup + textOffset;
116        kernelData.codeSize = binSize - (kernelData.code - kernelStub.data);
117        const size_t len = ::strlen(symName);
118        const CString kernelName = CString(symName+16, symName+len-14);
119        kernelData.kernelName = kernelName;
120        // fill kernel data map and kernel stup info
121        if (hasKernelDataMap()) // kernel data map
122            kernelDataMap[ki] = std::make_pair(kernelName, ki);
123       
124        if (hasKernelStubs())
125            kernelStubs[ki] = kernelStub;
126        // put to kernels table
127        if (hasKernelData())
128            kernels[ki] = kernelData;
129        ki++;
130    }
131    if (hasKernelDataMap())
132        mapSort(kernelDataMap.begin(), kernelDataMap.end());
133}
134
135const AmdCL2GPUKernelStub& AmdCL2OldInnerGPUBinary::getKernelStub(const char* name) const
136{
137    KernelDataMap::const_iterator it = binaryMapFind(
138            kernelDataMap.begin(), kernelDataMap.end(), name);
139    if (it == kernelDataMap.end())
140        throw Exception("Can't find kernel name");
141    return kernelStubs[it->second];
142}
143
144/* AmdCL2InnerGPUBinary */
145
146AmdCL2InnerGPUBinary::AmdCL2InnerGPUBinary(size_t binaryCodeSize, cxbyte* binaryCode,
147            Flags creationFlags): ElfBinary64(binaryCodeSize, binaryCode, creationFlags),
148            globalDataSize(0), globalData(nullptr), rwDataSize(0), rwData(nullptr),
149            bssAlignment(0), bssSize(0), samplerInitSize(0), samplerInit(nullptr),
150            textRelsNum(0), textRelEntrySize(0), textRela(nullptr),
151            globalDataRelsNum(0), globalDataRelEntrySize(0), globalDataRela(nullptr)
152{
153    if (hasKernelData())
154    {   // get kernel datas and kernel stubs
155        std::vector<size_t> choosenSyms;
156        const size_t symbolsNum = getSymbolsNum();
157        for (size_t i = 0; i < symbolsNum; i++)
158        {
159            const char* symName = getSymbolName(i);
160            const size_t len = ::strlen(symName);
161            if (len < 17 || ::strncmp(symName, "&__OpenCL_", 10) != 0 ||
162                ::strcmp(symName+len-7, "_kernel") != 0) // not binary, skip
163                continue;
164            choosenSyms.push_back(i);
165        }
166       
167        size_t ki = 0;
168        kernels.resize(choosenSyms.size());
169        if (hasKernelDataMap())
170            kernelDataMap.resize(choosenSyms.size());
171       
172        // main loop for kernel data getting
173        for (size_t index: choosenSyms)
174        {
175            const Elf64_Sym& sym = getSymbol(index);
176            const Elf64_Shdr& dataShdr = getSectionHeader(ULEV(sym.st_shndx));
177            if (ULEV(sym.st_shndx) >= getSectionHeadersNum())
178                throw Exception("Kernel section index out of range");
179            const char* symName = getSymbolName(index);
180            const size_t binOffset = ULEV(sym.st_value);
181            const size_t binSize = ULEV(sym.st_size);
182            /// check conditions for symbol
183            if (binOffset >= ULEV(dataShdr.sh_size))
184                throw Exception("Kernel binary code offset out of range");
185            if (usumGt(binOffset, binSize, ULEV(dataShdr.sh_size)))
186                throw Exception("Kernel binary code offset and size out of range");
187            if (binSize < 192)
188                throw Exception("Kernel binary code size is too short");
189           
190            kernels[ki].setup = binaryCode + ULEV(dataShdr.sh_offset) + binOffset;
191            // get size of setup (offset 16 of setup)
192            const size_t textOffset = ULEV(*reinterpret_cast<uint32_t*>(
193                            kernels[ki].setup+16));
194           
195            if (textOffset >= binSize)
196                throw Exception("Kernel text offset out of range");
197            kernels[ki].setupSize = textOffset;
198            kernels[ki].code = kernels[ki].setup + textOffset;
199            kernels[ki].codeSize = binSize-textOffset;
200            const size_t len = ::strlen(symName);
201            kernels[ki].kernelName = CString(symName+10, symName+len-7);
202            if (hasKernelDataMap()) // kernel data map
203                kernelDataMap[ki] = std::make_pair(kernels[ki].kernelName, ki);
204            ki++;
205        }
206        // sort kernel data map
207        if (hasKernelDataMap())
208            mapSort(kernelDataMap.begin(), kernelDataMap.end());
209    }
210    // get global data - from section
211    try
212    {
213        const Elf64_Shdr& gdataShdr = getSectionHeader(".hsadata_readonly_agent");
214        globalDataSize = ULEV(gdataShdr.sh_size);
215        globalData = binaryCode + ULEV(gdataShdr.sh_offset);
216    }
217    catch(const Exception& ex)
218    { }
219   
220    try
221    {
222        const Elf64_Shdr& rwShdr = getSectionHeader(".hsadata_global_agent");
223        rwDataSize = ULEV(rwShdr.sh_size);
224        rwData = binaryCode + ULEV(rwShdr.sh_offset);
225    }
226    catch(const Exception& ex)
227    { }
228   
229    try
230    {
231        const Elf64_Shdr& bssShdr = getSectionHeader(".hsabss_global_agent");
232        bssSize = ULEV(bssShdr.sh_size);
233        bssAlignment = ULEV(bssShdr.sh_addralign);
234    }
235    catch(const Exception& ex)
236    { }
237   
238    try
239    {
240        const Elf64_Shdr& dataShdr = getSectionHeader(".hsaimage_samplerinit");
241        samplerInitSize = ULEV(dataShdr.sh_size);
242        samplerInit = binaryCode + ULEV(dataShdr.sh_offset);
243    }
244    catch(const Exception& ex)
245    { }
246   
247    try
248    {
249        const Elf64_Shdr& relaShdr = getSectionHeader(".rela.hsatext");
250        textRelEntrySize = ULEV(relaShdr.sh_entsize);
251        if (textRelEntrySize==0)
252            textRelEntrySize = sizeof(Elf64_Rela);
253        textRelsNum = ULEV(relaShdr.sh_size)/textRelEntrySize;
254        textRela = binaryCode + ULEV(relaShdr.sh_offset);
255    }
256    catch(const Exception& ex)
257    { }
258   
259    try
260    {
261        const Elf64_Shdr& relaShdr = getSectionHeader(".rela.hsadata_readonly_agent");
262        globalDataRelEntrySize = ULEV(relaShdr.sh_entsize);
263        if (globalDataRelEntrySize==0)
264            globalDataRelEntrySize = sizeof(Elf64_Rela);
265        globalDataRelsNum = ULEV(relaShdr.sh_size)/globalDataRelEntrySize;
266        globalDataRela = binaryCode + ULEV(relaShdr.sh_offset);
267    }
268    catch(const Exception& ex)
269    { }
270}
271
272/* AmdCL2MainGPUBinary64 */
273
274static const KernelArgType cl20ArgTypeVectorTable[] =
275{
276    KernelArgType::CHAR,
277    KernelArgType::CHAR2,
278    KernelArgType::CHAR3,
279    KernelArgType::CHAR4,
280    KernelArgType::CHAR8,
281    KernelArgType::CHAR16,
282    KernelArgType::SHORT,
283    KernelArgType::SHORT2,
284    KernelArgType::SHORT3,
285    KernelArgType::SHORT4,
286    KernelArgType::SHORT8,
287    KernelArgType::SHORT16,
288    KernelArgType::INT,
289    KernelArgType::INT2,
290    KernelArgType::INT3,
291    KernelArgType::INT4,
292    KernelArgType::INT8,
293    KernelArgType::INT16,
294    KernelArgType::LONG,
295    KernelArgType::LONG2,
296    KernelArgType::LONG3,
297    KernelArgType::LONG4,
298    KernelArgType::LONG8,
299    KernelArgType::LONG16,
300    KernelArgType::VOID,
301    KernelArgType::VOID,
302    KernelArgType::VOID,
303    KernelArgType::VOID,
304    KernelArgType::VOID,
305    KernelArgType::VOID,
306    KernelArgType::FLOAT,
307    KernelArgType::FLOAT2,
308    KernelArgType::FLOAT3,
309    KernelArgType::FLOAT4,
310    KernelArgType::FLOAT8,
311    KernelArgType::FLOAT16,
312    KernelArgType::DOUBLE,
313    KernelArgType::DOUBLE2,
314    KernelArgType::DOUBLE3,
315    KernelArgType::DOUBLE4,
316    KernelArgType::DOUBLE8,
317    KernelArgType::DOUBLE16
318};
319
320static const cxuint vectorIdTable[17] =
321{ UINT_MAX, 0, 1, 2, 3, UINT_MAX, UINT_MAX, UINT_MAX, 4,
322  UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX, 5 };
323
324template<typename Types>
325static void getCL2KernelInfo(size_t metadataSize, cxbyte* metadata,
326             KernelInfo& kernelInfo, AmdGPUKernelHeader& kernelHeader, bool& crimson16)
327{
328    crimson16 = false;
329    if (metadataSize < 8+32+32)
330        throw Exception("Kernel metadata is too short");
331   
332    const typename Types::MetadataHeader* hdrStruc =
333            reinterpret_cast<const typename Types::MetadataHeader*>(metadata);
334    kernelHeader.size = ULEV(hdrStruc->size);
335    if (kernelHeader.size >= metadataSize)
336        throw Exception("Metadata header size out of range");
337    if (kernelHeader.size < sizeof(typename Types::MetadataHeader))
338        throw Exception("Metadata header is too short");
339    kernelHeader.data = metadata;
340    const uint32_t argsNum = ULEV(hdrStruc->argsNum);
341   
342    if (usumGt(ULEV(hdrStruc->firstNameLength), ULEV(hdrStruc->secondNameLength),
343                metadataSize-kernelHeader.size-2))
344        throw Exception("KernelArgEntries offset out of range");
345   
346    size_t argOffset = kernelHeader.size +
347            ULEV(hdrStruc->firstNameLength)+ULEV(hdrStruc->secondNameLength)+2;
348    // fix for latest Crimson drivers
349    if (ULEV(*(const uint32_t*)(metadata+argOffset)) ==
350                (sizeof(typename Types::KernelArgEntry)<<8))
351    {
352        crimson16 = true;
353        argOffset++;
354    }
355    const typename Types::KernelArgEntry* argPtr = reinterpret_cast<
356            const typename Types::KernelArgEntry*>(metadata + argOffset);
357   
358    if(usumGt(argOffset, sizeof(typename Types::KernelArgEntry)*argsNum, metadataSize))
359        throw Exception("Number of arguments out of range");
360   
361    const char* strBase = (const char*)metadata;
362    size_t strOffset = argOffset + sizeof(typename Types::KernelArgEntry)*(argsNum+1);
363   
364    kernelInfo.argInfos.resize(argsNum);
365    for (uint32_t i = 0; i < argsNum; i++, argPtr++)
366    {
367        AmdKernelArg& arg = kernelInfo.argInfos[i];
368        if (ULEV(argPtr->size)!=sizeof(typename Types::KernelArgEntry))
369            throw Exception("Kernel ArgEntry size doesn't match");
370        // get name of argument
371        size_t nameSize = ULEV(argPtr->argNameSize);
372        if (usumGt(strOffset, nameSize+1, metadataSize))
373            throw Exception("Kernel ArgEntry name size out of range");
374        arg.argName.assign(strBase+strOffset, nameSize);
375        // get name of type of argument
376        strOffset += nameSize+1;
377        nameSize = ULEV(argPtr->typeNameSize);
378        if (usumGt(strOffset, nameSize+1, metadataSize))
379            throw Exception("Kernel ArgEntry typename size out of range");
380        arg.typeName.assign(strBase+strOffset, nameSize);
381        strOffset += nameSize+1;
382       
383        /// determine arg type
384        uint32_t vectorSize = ULEV(argPtr->vectorLength);
385        uint32_t argType = ULEV(argPtr->argType);
386        uint32_t kindOfType = ULEV(argPtr->kindOfType);
387        arg.ptrSpace = KernelPtrSpace::NONE;
388        arg.ptrAccess = KARG_PTR_NORMAL;
389        arg.argType = KernelArgType::VOID;
390       
391        if (!ULEV(argPtr->isPointerOrPipe))
392            // if not point or pipe (get regular type: scalar, image, sampler,...)
393            switch(argType)
394            {
395                case 0:
396                    if (kindOfType!=1) // not sampler
397                        throw Exception("Wrong kernel argument type");
398                    arg.argType = KernelArgType::SAMPLER;
399                    break;
400                case 1:  // read_only image
401                case 2:  // write_only image
402                case 3:  // read_write image
403                    if (kindOfType==2) // not image
404                    {
405                        arg.argType = KernelArgType::IMAGE;
406                        arg.ptrAccess = (argType==1) ? KARG_PTR_READ_ONLY : (argType==2) ?
407                                 KARG_PTR_WRITE_ONLY : KARG_PTR_READ_WRITE;
408                        arg.ptrSpace = KernelPtrSpace::GLOBAL;
409                    }
410                    else if (argType==2 || argType == 3)
411                    {
412                        if (kindOfType!=4) // not scalar
413                            throw Exception("Wrong kernel argument type");
414                        arg.argType = (argType==3) ?
415                            KernelArgType::SHORT : KernelArgType::CHAR;
416                    }
417                    else
418                        throw Exception("Wrong kernel argument type");
419                    break;
420                case 4: // int
421                case 5: // long
422                    if (kindOfType!=4) // not scalar
423                        throw Exception("Wrong kernel argument type");
424                    arg.argType = (argType==5) ?
425                        KernelArgType::LONG : KernelArgType::INT;
426                    break;
427                case 6: // char
428                case 7: // short
429                case 8: // int
430                case 9: // long
431                case 11: // float
432                case 12: // double
433                {
434                    if (kindOfType!=4) // not scalar
435                        throw Exception("Wrong kernel argument type");
436                    const cxuint vectorId = vectorIdTable[vectorSize];
437                    if (vectorId == UINT_MAX)
438                        throw Exception("Wrong vector size");
439                    arg.argType = cl20ArgTypeVectorTable[(argType-6)*6 + vectorId];
440                    break;
441                }
442                case 15:
443                    if (kindOfType!=4) // not scalar
444                        throw Exception("Wrong kernel argument type");
445                    arg.argType = KernelArgType::STRUCTURE;
446                    break;
447                case 18:
448                    if (kindOfType!=7) // not scalar
449                        throw Exception("Wrong kernel argument type");
450                    arg.argType = KernelArgType::CMDQUEUE;
451                    break;
452                default:
453                    throw Exception("Wrong kernel argument type");
454                    break;
455            }
456        else // otherwise is pointer or pipe
457        {
458            uint32_t ptrSpace = ULEV(argPtr->ptrSpace);
459            if (argType == 7) // pointer
460                arg.argType = (argPtr->isPipe==0) ? KernelArgType::POINTER :
461                    KernelArgType::PIPE;
462            else if (argType == 15)
463                arg.argType = KernelArgType::POINTER;
464            if (arg.argType == KernelArgType::POINTER)
465            {   // if pointer
466                if (ptrSpace==3)
467                    arg.ptrSpace = KernelPtrSpace::LOCAL;
468                else if (ptrSpace==4)
469                    arg.ptrSpace = KernelPtrSpace::GLOBAL;
470                else if (ptrSpace==5)
471                    arg.ptrSpace = KernelPtrSpace::CONSTANT;
472                else
473                    throw Exception("Illegal pointer space");
474                // set access qualifiers (volatile, restrict, const)
475                arg.ptrAccess = KARG_PTR_NORMAL;
476                if (ULEV(argPtr->isConst))
477                    arg.ptrAccess |= KARG_PTR_CONST;
478                if (argPtr->isRestrict)
479                    arg.ptrAccess |= KARG_PTR_RESTRICT;
480                if (argPtr->isVolatile)
481                    arg.ptrAccess |= KARG_PTR_VOLATILE;
482            }
483            else
484            {
485                if (ptrSpace!=4)
486                    throw Exception("Illegal pipe space");
487                arg.ptrSpace = KernelPtrSpace::GLOBAL;
488            }
489        }
490    }
491}
492
493struct CLRX_INTERNAL AmdCL2Types32 : Elf32Types
494{
495    typedef ElfBinary32 ElfBinary;
496    typedef AmdCL2GPUMetadataHeader32 MetadataHeader;
497    typedef AmdCL2GPUKernelArgEntry32 KernelArgEntry;
498};
499
500struct CLRX_INTERNAL AmdCL2Types64 : Elf64Types
501{
502    typedef ElfBinary64 ElfBinary;
503    typedef AmdCL2GPUMetadataHeader64 MetadataHeader;
504    typedef AmdCL2GPUKernelArgEntry64 KernelArgEntry;
505};
506
507/* AMD CL2 GPU Binary base class */
508
509AmdCL2MainGPUBinaryBase::AmdCL2MainGPUBinaryBase(AmdMainType mainType)
510        : AmdMainBinaryBase(mainType), driverVersion(180005),
511          kernelsNum(0)
512{ }
513
514const AmdCL2GPUKernelMetadata& AmdCL2MainGPUBinaryBase::getMetadataEntry(
515                    const char* name) const
516{
517    auto it = binaryMapFind(kernelInfosMap.begin(), kernelInfosMap.end(), name);
518    if (it == kernelInfosMap.end())
519        throw Exception("Can't find kernel metadata by name");
520    return metadatas[it->second];
521}
522
523const AmdCL2GPUKernelMetadata& AmdCL2MainGPUBinaryBase::getISAMetadataEntry(
524                    const char* name) const
525{
526    auto it = binaryMapFind(isaMetadataMap.begin(), isaMetadataMap.end(), name);
527    if (it == isaMetadataMap.end())
528        throw Exception("Can't find kernel ISA metadata by name");
529    return isaMetadatas[it->second];
530}
531
532template<typename Types>
533void AmdCL2MainGPUBinaryBase::initMainGPUBinary(typename Types::ElfBinary& elfBin)
534{
535    std::vector<size_t> choosenMetadataSyms;
536    std::vector<size_t> choosenISAMetadataSyms;
537    std::vector<size_t> choosenBinSyms;
538   
539    Flags creationFlags = elfBin.getCreationFlags();
540    cxbyte* binaryCode = elfBin.getBinaryCode();
541   
542    const size_t symbolsNum = elfBin.getSymbolsNum();
543   
544    if ((creationFlags & AMDBIN_CREATE_INFOSTRINGS) != 0)
545        /// get info strings if needed
546        for (size_t i = 0; i < symbolsNum; i++)
547        {
548            const char* symName = elfBin.getSymbolName(i);
549            if (::strcmp(symName, "__OpenCL_compiler_options")==0)
550            {   // compile options
551                const typename Types::Sym& sym = elfBin.getSymbol(i);
552                if (ULEV(sym.st_shndx) >= elfBin.getSectionHeadersNum())
553                    throw Exception("Compiler options section header out of range");
554                const typename Types::Shdr& shdr =
555                            elfBin.getSectionHeader(ULEV(sym.st_shndx));
556                const size_t coOffset = ULEV(sym.st_value);
557                const size_t coSize = ULEV(sym.st_size);
558                if (coOffset >= ULEV(shdr.sh_size))
559                    throw Exception("Compiler options offset out of range");
560                if (usumGt(coOffset, coSize, ULEV(shdr.sh_size)))
561                    throw Exception("Compiler options offset and size out of range");
562               
563                const char* coData = reinterpret_cast<const char*>(binaryCode) +
564                            ULEV(shdr.sh_offset) + coOffset;
565                compileOptions.assign(coData, coData + coSize);
566            }
567            else if (::strcmp(symName, "acl_version_string")==0)
568            {   // acl version string
569                const typename Types::Sym& sym = elfBin.getSymbol(i);
570                if (ULEV(sym.st_shndx) >= elfBin.getSectionHeadersNum())
571                    throw Exception("AclVersionString section header out of range");
572                const typename Types::Shdr& shdr =
573                        elfBin.getSectionHeader(ULEV(sym.st_shndx));
574                const size_t aclOffset = ULEV(sym.st_value);
575                const size_t aclSize = ULEV(sym.st_size);
576                if (aclOffset >= ULEV(shdr.sh_size))
577                    throw Exception("AclVersionString offset out of range");
578                if (usumGt(aclOffset, aclSize, ULEV(shdr.sh_size)))
579                    throw Exception("AclVersionString offset and size out of range");
580               
581                const char* aclVersionData = reinterpret_cast<const char*>(binaryCode) +
582                            ULEV(shdr.sh_offset) + aclOffset;
583                aclVersionString.assign(aclVersionData, aclVersionData + aclSize);
584            }
585        }
586   
587    // find symbol of kernel metadata, ISA metadata and binary
588    for (size_t i = 0; i < symbolsNum; i++)
589    {
590        const char* symName = elfBin.getSymbolName(i);
591        const size_t len = ::strlen(symName);
592        if (len >= 35 && (::strncmp(symName, "__OpenCL_&__OpenCL_", 19) == 0 &&
593                ::strcmp(symName+len-16, "_kernel_metadata") == 0)) // if metadata
594            choosenMetadataSyms.push_back(i);
595        else if (::strncmp(symName, "__ISA_&__OpenCL_", 16) == 0)
596        {
597            if (len >= 30 && ::strcmp(symName+len-14, "_kernel_binary") == 0)
598                choosenBinSyms.push_back(i); //  if binary
599            else if (len >= 32 && ::strcmp(symName+len-16, "_kernel_metadata") == 0)
600                choosenISAMetadataSyms.push_back(i); // if ISA metadata
601        }
602    }
603   
604    const bool newInnerBinary = choosenBinSyms.empty();
605    uint16_t textIndex = SHN_UNDEF;
606    driverVersion = newInnerBinary ? 191205: 180005;
607    try
608    { textIndex = elfBin.getSectionIndex(".text"); }
609    catch(const Exception& ex)
610    {
611        if (!choosenMetadataSyms.empty())
612            throw;  // throw exception if least one kernel is present
613        else // old driver version
614            driverVersion = 180005;
615    }
616    if (textIndex != SHN_UNDEF)
617    {
618        const typename Types::Shdr& textShdr = elfBin.getSectionHeader(textIndex);
619        if (newInnerBinary)
620        {
621            innerBinary.reset(new AmdCL2InnerGPUBinary(ULEV(textShdr.sh_size),
622                           binaryCode + ULEV(textShdr.sh_offset),
623                           creationFlags >> AMDBIN_INNER_SHIFT));
624            // detect new format from Crimson 16.4
625            const auto& innerBin = getInnerBinary();
626            driverVersion = (innerBin.getSymbolsNum()!=0 &&
627                    innerBin.getSymbolName(0)[0]==0) ? 200406 : 191205;
628            try
629            {
630                const Elf64_Shdr& noteShdr = innerBin.getSectionHeader(".note");
631                const cxbyte* noteContent = innerBin.getSectionContent(".note");
632                const size_t noteSize = ULEV(noteShdr.sh_size);
633                if (noteSize == 200 && noteContent[197]!=0)
634                    driverVersion = 203603;
635            }
636            catch(const Exception& ex)
637            { }
638        }
639        else // old driver
640            innerBinary.reset(new AmdCL2OldInnerGPUBinary(&elfBin, ULEV(textShdr.sh_size),
641                           binaryCode + ULEV(textShdr.sh_offset),
642                           creationFlags >> AMDBIN_INNER_SHIFT));
643    }
644   
645    // get metadata
646    if ((creationFlags & AMDBIN_CREATE_KERNELINFO) != 0)
647    {
648        kernelInfos.resize(choosenMetadataSyms.size());
649        kernelHeaders.reset(new AmdGPUKernelHeader[choosenMetadataSyms.size()]);
650        if ((creationFlags & AMDBIN_CREATE_KERNELINFOMAP) != 0)
651        {
652            kernelInfosMap.resize(choosenMetadataSyms.size());
653            isaMetadataMap.resize(choosenISAMetadataSyms.size());
654        }
655        metadatas.reset(new AmdCL2GPUKernelMetadata[kernelInfos.size()]);
656        isaMetadatas.resize(choosenISAMetadataSyms.size());
657        size_t ki = 0;
658        // main loop
659        for (size_t index: choosenMetadataSyms)
660        {
661            const typename Types::Sym& mtsym = elfBin.getSymbol(index);
662            const char* mtName = elfBin.getSymbolName(index);
663            if (ULEV(mtsym.st_shndx) >= elfBin.getSectionHeadersNum())
664                throw Exception("Kernel Metadata section header out of range");
665            const typename Types::Shdr& shdr =
666                    elfBin.getSectionHeader(ULEV(mtsym.st_shndx));
667            const size_t mtOffset = ULEV(mtsym.st_value);
668            const size_t mtSize = ULEV(mtsym.st_size);
669            /// offset and size verifying
670            if (mtOffset >= ULEV(shdr.sh_size))
671                throw Exception("Kernel Metadata offset out of range");
672            if (usumGt(mtOffset, mtSize, ULEV(shdr.sh_size)))
673                throw Exception("Kernel Metadata offset and size out of range");
674           
675            cxbyte* metadata = binaryCode + ULEV(shdr.sh_offset) + mtOffset;
676            bool crimson16 = false;
677            getCL2KernelInfo<Types>(mtSize, metadata, kernelInfos[ki],
678                                        kernelHeaders[ki], crimson16);
679            size_t len = ::strlen(mtName);
680            // set kernel name from symbol name (__OpenCL_&__OpenCL_[name]_kernel_metadata)
681            kernelHeaders[ki].kernelName = kernelInfos[ki].kernelName =
682                        CString(mtName+19, mtName+len-16);
683            if ((creationFlags & AMDBIN_CREATE_KERNELINFOMAP) != 0)
684                kernelInfosMap[ki] = std::make_pair(kernelInfos[ki].kernelName, ki);
685            metadatas[ki] = { kernelInfos[ki].kernelName, mtSize, metadata };
686            ki++;
687            if (crimson16 && driverVersion < 200406) // if AMD Crimson 16
688                driverVersion = 200406;
689        }
690       
691        ki = 0;
692        for (size_t index: choosenISAMetadataSyms)
693        {
694            const typename Types::Sym& mtsym = elfBin.getSymbol(index);
695            const char* mtName = elfBin.getSymbolName(index);
696            if (ULEV(mtsym.st_shndx) >= elfBin.getSectionHeadersNum())
697                throw Exception("Kernel ISAMetadata section header out of range");
698            const typename Types::Shdr& shdr =
699                        elfBin.getSectionHeader(ULEV(mtsym.st_shndx));
700            const size_t mtOffset = ULEV(mtsym.st_value);
701            const size_t mtSize = ULEV(mtsym.st_size);
702            /// offset and size verifying
703            if (mtOffset >= ULEV(shdr.sh_size))
704                throw Exception("Kernel ISAMetadata offset out of range");
705            if (usumGt(mtOffset, mtSize, ULEV(shdr.sh_size)))
706                throw Exception("Kernel ISAMetadata offset and size out of range");
707           
708            cxbyte* metadata = binaryCode + ULEV(shdr.sh_offset) + mtOffset;
709            size_t len = ::strlen(mtName);
710            CString kernelName = CString(mtName+16, mtName+len-16);
711            isaMetadatas[ki] = { kernelName, mtSize, metadata };
712            if ((creationFlags & AMDBIN_CREATE_KERNELINFOMAP) != 0)
713                isaMetadataMap[ki] = std::make_pair(kernelName, ki);
714            ki++;
715        }
716       
717        if ((creationFlags & AMDBIN_CREATE_KERNELINFOMAP) != 0)
718        {
719            mapSort(kernelInfosMap.begin(), kernelInfosMap.end());
720            mapSort(isaMetadataMap.begin(), isaMetadataMap.end());
721        }
722    }
723}
724
725/* helpers for determing gpu device type */
726
727struct CLRX_INTERNAL CL2GPUDeviceCodeEntry
728{
729    uint32_t elfFlags;
730    GPUDeviceType deviceType;
731};
732
733/* 1912.05 driver device table list */
734static const CL2GPUDeviceCodeEntry cl2GpuDeviceCodeTable[] =
735{
736    { 1, GPUDeviceType::SPECTRE },
737    { 2, GPUDeviceType::SPOOKY },
738    { 3, GPUDeviceType::KALINDI },
739    { 4, GPUDeviceType::MULLINS },
740    { 6, GPUDeviceType::BONAIRE },
741    { 7, GPUDeviceType::HAWAII },
742    { 8, GPUDeviceType::ICELAND },
743    { 9, GPUDeviceType::TONGA },
744    { 15, GPUDeviceType::DUMMY },
745    { 16, GPUDeviceType::CARRIZO },
746    { 17, GPUDeviceType::FIJI }
747};
748
749/* 2004.06 driver device table list */
750static const CL2GPUDeviceCodeEntry cl2_16_3GpuDeviceCodeTable[] =
751{
752    { 1, GPUDeviceType::SPECTRE },
753    { 2, GPUDeviceType::SPOOKY },
754    { 3, GPUDeviceType::KALINDI },
755    { 4, GPUDeviceType::MULLINS },
756    { 6, GPUDeviceType::BONAIRE },
757    { 7, GPUDeviceType::HAWAII },
758    { 8, GPUDeviceType::ICELAND },
759    { 9, GPUDeviceType::TONGA },
760    { 12, GPUDeviceType::HORSE },
761    { 13, GPUDeviceType::GOOSE },
762    { 15, GPUDeviceType::CARRIZO },
763    { 16, GPUDeviceType::FIJI },
764    { 17, GPUDeviceType::STONEY }
765};
766
767/* 1801.05 driver device table list */
768static const CL2GPUDeviceCodeEntry cl2_15_7GpuDeviceCodeTable[] =
769{
770    { 1, GPUDeviceType::SPECTRE },
771    { 2, GPUDeviceType::SPOOKY },
772    { 3, GPUDeviceType::KALINDI },
773    { 4, GPUDeviceType::MULLINS },
774    { 6, GPUDeviceType::BONAIRE },
775    { 7, GPUDeviceType::HAWAII },
776    { 8, GPUDeviceType::ICELAND },
777    { 9, GPUDeviceType::TONGA },
778    { 15, GPUDeviceType::CARRIZO },
779    { 16, GPUDeviceType::FIJI }
780};
781
782/* driver version: 2036.3 */
783static const CL2GPUDeviceCodeEntry cl2GPUPROGpuDeviceCodeTable[] =
784{
785    { 1, GPUDeviceType::SPECTRE },
786    { 2, GPUDeviceType::SPOOKY },
787    { 3, GPUDeviceType::KALINDI },
788    { 4, GPUDeviceType::MULLINS },
789    { 6, GPUDeviceType::BONAIRE },
790    { 7, GPUDeviceType::HAWAII },
791    { 8, GPUDeviceType::ICELAND },
792    { 9, GPUDeviceType::TONGA },
793    { 13, GPUDeviceType::CARRIZO },
794    { 14, GPUDeviceType::FIJI },
795    { 15, GPUDeviceType::STONEY },
796    { 16, GPUDeviceType::BAFFIN },
797    { 17, GPUDeviceType::ELLESMERE }
798};
799
800static const CL2GPUDeviceCodeEntry cl2_2236GpuDeviceCodeTable[] =
801{
802    { 1, GPUDeviceType::SPECTRE },
803    { 2, GPUDeviceType::SPOOKY },
804    { 3, GPUDeviceType::KALINDI },
805    { 4, GPUDeviceType::MULLINS },
806    { 6, GPUDeviceType::BONAIRE },
807    { 7, GPUDeviceType::HAWAII },
808    { 8, GPUDeviceType::ICELAND },
809    { 9, GPUDeviceType::TONGA },
810    { 12, GPUDeviceType::CARRIZO },
811    { 13, GPUDeviceType::FIJI },
812    { 14, GPUDeviceType::STONEY },
813    { 15, GPUDeviceType::BAFFIN },
814    { 16, GPUDeviceType::ELLESMERE },
815    { 17, GPUDeviceType::GFX900 },
816    { 18, GPUDeviceType::GFX804 }
817};
818
819static const CL2GPUDeviceCodeEntry cl2_2264GpuDeviceCodeTable[] =
820{
821    { 1, GPUDeviceType::SPECTRE },
822    { 2, GPUDeviceType::SPOOKY },
823    { 3, GPUDeviceType::KALINDI },
824    { 4, GPUDeviceType::MULLINS },
825    { 6, GPUDeviceType::BONAIRE },
826    { 7, GPUDeviceType::HAWAII },
827    { 8, GPUDeviceType::ICELAND },
828    { 9, GPUDeviceType::TONGA },
829    { 13, GPUDeviceType::CARRIZO },
830    { 14, GPUDeviceType::FIJI },
831    { 15, GPUDeviceType::STONEY },
832    { 16, GPUDeviceType::BAFFIN },
833    { 17, GPUDeviceType::ELLESMERE },
834    { 18, GPUDeviceType::GFX804 },
835    { 19, GPUDeviceType::GFX900 }
836};
837
838static const CL2GPUDeviceCodeEntry cl2_2348GpuDeviceCodeTable[] =
839{
840    { 1, GPUDeviceType::SPECTRE },
841    { 2, GPUDeviceType::SPOOKY },
842    { 3, GPUDeviceType::KALINDI },
843    { 4, GPUDeviceType::MULLINS },
844    { 6, GPUDeviceType::BONAIRE },
845    { 7, GPUDeviceType::HAWAII },
846    { 8, GPUDeviceType::ICELAND },
847    { 9, GPUDeviceType::TONGA },
848    { 14, GPUDeviceType::CARRIZO },
849    { 15, GPUDeviceType::FIJI },
850    { 16, GPUDeviceType::STONEY },
851    { 17, GPUDeviceType::BAFFIN },
852    { 18, GPUDeviceType::ELLESMERE },
853    { 19, GPUDeviceType::GFX804 },
854    { 20, GPUDeviceType::GFX900 }
855};
856
857struct CLRX_INTERNAL CL2GPUCodeTable
858{
859    cxuint toDriverVersion;   // to driver version
860    const CL2GPUDeviceCodeEntry* table;
861    size_t tableSize;
862};
863
864static const CL2GPUCodeTable cl2CodeTables[] =
865{
866    { 191205U, cl2_15_7GpuDeviceCodeTable,
867        sizeof(cl2_15_7GpuDeviceCodeTable)/sizeof(CL2GPUDeviceCodeEntry) },
868    { 200406U, cl2GpuDeviceCodeTable,
869        sizeof(cl2GpuDeviceCodeTable)/sizeof(CL2GPUDeviceCodeEntry) },
870    { 203603U, cl2_16_3GpuDeviceCodeTable,
871        sizeof(cl2_16_3GpuDeviceCodeTable)/sizeof(CL2GPUDeviceCodeEntry) },
872    { 223600U, cl2GPUPROGpuDeviceCodeTable,
873        sizeof(cl2GPUPROGpuDeviceCodeTable)/sizeof(CL2GPUDeviceCodeEntry) },
874    { 226400U, cl2_2236GpuDeviceCodeTable,
875        sizeof(cl2_2236GpuDeviceCodeTable)/sizeof(CL2GPUDeviceCodeEntry) },
876    { 234800U, cl2_2264GpuDeviceCodeTable,
877        sizeof(cl2_2264GpuDeviceCodeTable)/sizeof(CL2GPUDeviceCodeEntry) },
878    { UINT_MAX, cl2_2348GpuDeviceCodeTable,
879        sizeof(cl2_2348GpuDeviceCodeTable)/sizeof(CL2GPUDeviceCodeEntry) }
880};
881
882template<typename Types>
883GPUDeviceType AmdCL2MainGPUBinaryBase::determineGPUDeviceTypeInt(
884        const typename Types::ElfBinary& binary, uint32_t& outArchMinor,
885        uint32_t& outArchStepping, cxuint inDriverVersion) const
886{
887    const uint32_t elfFlags = ULEV(binary.getHeader().e_flags);
888   
889    // detect GPU device from elfMachine field from ELF header
890    cxuint entriesNum = 0;
891    const CL2GPUDeviceCodeEntry* gpuCodeTable = nullptr;
892    cxuint inputDriverVersion = 0;
893    if (inDriverVersion == 0)
894        inputDriverVersion = this->driverVersion;
895    else
896        inputDriverVersion = inDriverVersion;
897   
898    const size_t codeTablesNum = sizeof(cl2CodeTables)/sizeof(CL2GPUCodeTable);
899    auto ctit = std::upper_bound(cl2CodeTables, cl2CodeTables+codeTablesNum,
900                CL2GPUCodeTable{ inputDriverVersion },
901                [](const CL2GPUCodeTable& a, const CL2GPUCodeTable& b)
902                { return a.toDriverVersion < b.toDriverVersion; });
903    if (ctit == cl2CodeTables+codeTablesNum)
904        ctit--; // to previous table
905    //std::cout << "ctitver: " << ctit->toDriverVersion << "\n";
906    gpuCodeTable = ctit->table;
907    entriesNum = ctit->tableSize;
908   
909    cxuint index = binaryFind(gpuCodeTable, gpuCodeTable + entriesNum, { elfFlags },
910              [] (const CL2GPUDeviceCodeEntry& l, const CL2GPUDeviceCodeEntry& r)
911              { return l.elfFlags < r.elfFlags; }) - gpuCodeTable;
912    bool knownGPUType = index != entriesNum;
913   
914    GPUDeviceType deviceType = GPUDeviceType::CAPE_VERDE;
915    GPUArchitecture arch = GPUArchitecture::GCN1_1;
916    if (knownGPUType)
917    {
918        deviceType = gpuCodeTable[index].deviceType;
919        arch = getGPUArchitectureFromDeviceType(deviceType);
920    }
921    uint32_t archMinor = 0;
922    uint32_t archStepping = 0;
923   
924    bool isInnerNewBinary = hasInnerBinary() && this->driverVersion>=191205;
925    if (isInnerNewBinary)
926    {
927        const AmdCL2InnerGPUBinary& innerBin = getInnerBinary();
928       
929        const cxbyte* noteContent = (const cxbyte*)innerBin.getNotes();
930        if (noteContent==nullptr)
931            throw Exception("Missing notes in inner binary!");
932        size_t notesSize = innerBin.getNotesSize();
933        // find note about AMDGPU
934        for (size_t offset = 0; offset < notesSize; )
935        {
936            const typename Types::Nhdr* nhdr =
937                        (const typename Types::Nhdr*)(noteContent + offset);
938            size_t namesz = ULEV(nhdr->n_namesz);
939            size_t descsz = ULEV(nhdr->n_descsz);
940            if (usumGt(offset, namesz+descsz, notesSize))
941                throw Exception("Note offset+size out of range");
942            if (ULEV(nhdr->n_type) == 0x3 && namesz==4 && descsz>=0x1a &&
943                ::strcmp((const char*)noteContent+offset+
944                            sizeof(typename Types::Nhdr), "AMD")==0)
945            {    // AMDGPU type
946                const uint32_t* content = (const uint32_t*)
947                        (noteContent+offset+sizeof(typename Types::Nhdr) + 4);
948                uint32_t major = ULEV(content[1]);
949                if (knownGPUType)
950                {
951                    if ((arch==GPUArchitecture::GCN1_2 && major<8) ||
952                        (arch==GPUArchitecture::GCN1_1 && major!=7))
953                        throw Exception("Wrong arch major for GPU architecture");
954                    // fix for GFX900 - we don't know what is type of device
955                    if (arch==GPUArchitecture::GCN1_2 && major!=8)
956                        knownGPUType = false;
957                }
958                else if (major != 9 && major != 8 && major != 7)
959                    throw Exception("Unknown arch major");
960               
961                if (!knownGPUType)
962                {
963                    arch = (major == 7) ? GPUArchitecture::GCN1_1 :
964                            ((major == 8) ? GPUArchitecture::GCN1_2 :
965                            GPUArchitecture::GCN1_4);
966                    deviceType = getLowestGPUDeviceTypeFromArchitecture(arch);
967                    knownGPUType = true;
968                }
969                archMinor = ULEV(content[2]);
970                archStepping = ULEV(content[3]);
971            }
972            size_t align = (((namesz+descsz)&3)!=0) ? 4-((namesz+descsz)&3) : 0;
973            offset += sizeof(typename Types::Nhdr) + namesz + descsz + align;
974        }
975    }
976   
977    if (!knownGPUType)
978        throw Exception("Can't determine GPU device type");
979   
980    outArchMinor = archMinor;
981    outArchStepping = archStepping;
982    return deviceType;
983}
984
985/* AMD CL2 32-bit */
986
987AmdCL2MainGPUBinary32::AmdCL2MainGPUBinary32(size_t binaryCodeSize, cxbyte* binaryCode,
988            Flags creationFlags) : AmdCL2MainGPUBinaryBase(AmdMainType::GPU_CL2_BINARY),
989            ElfBinary32(binaryCodeSize, binaryCode, creationFlags)
990{
991    initMainGPUBinary<AmdCL2Types32>(*this);
992}
993
994GPUDeviceType AmdCL2MainGPUBinary32::determineGPUDeviceType(uint32_t& archMinor,
995                uint32_t& archStepping, cxuint driverVersion) const
996{
997    return determineGPUDeviceTypeInt<AmdCL2Types32>(*this,
998                    archMinor, archStepping, driverVersion);
999}
1000
1001/* AMD CL2 64-bit */
1002
1003AmdCL2MainGPUBinary64::AmdCL2MainGPUBinary64(size_t binaryCodeSize, cxbyte* binaryCode,
1004            Flags creationFlags) : AmdCL2MainGPUBinaryBase(AmdMainType::GPU_CL2_64_BINARY),
1005            ElfBinary64(binaryCodeSize, binaryCode, creationFlags)
1006{
1007    initMainGPUBinary<AmdCL2Types64>(*this);
1008}
1009
1010GPUDeviceType AmdCL2MainGPUBinary64::determineGPUDeviceType(uint32_t& archMinor,
1011                uint32_t& archStepping, cxuint driverVersion) const
1012{
1013    return determineGPUDeviceTypeInt<AmdCL2Types64>(*this,
1014                    archMinor, archStepping, driverVersion);
1015}
1016
1017
1018AmdCL2MainGPUBinaryBase* CLRX::createAmdCL2BinaryFromCode(
1019            size_t binaryCodeSize, cxbyte* binaryCode, Flags creationFlags)
1020{
1021    if (binaryCode[EI_CLASS] == ELFCLASS32)
1022        return new AmdCL2MainGPUBinary32(binaryCodeSize, binaryCode, creationFlags);
1023    else
1024        return new AmdCL2MainGPUBinary64(binaryCodeSize, binaryCode, creationFlags);
1025}
1026
1027bool CLRX::isAmdCL2Binary(size_t binarySize, const cxbyte* binary)
1028{
1029    if (!isElfBinary(binarySize, binary))
1030        return false;
1031    if (binary[EI_CLASS] == ELFCLASS32)
1032    {
1033        const Elf32_Ehdr* ehdr = reinterpret_cast<const Elf32_Ehdr*>(binary);
1034        if (ULEV(ehdr->e_machine) != 0xaf5a || ULEV(ehdr->e_flags)==0)
1035            return false;
1036    }
1037    else
1038    {
1039        const Elf64_Ehdr* ehdr = reinterpret_cast<const Elf64_Ehdr*>(binary);
1040        if (ULEV(ehdr->e_machine) != 0xaf5b || ULEV(ehdr->e_flags)==0)
1041            return false;
1042    }
1043    return true;
1044}
Note: See TracBrowser for help on using the repository browser.