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

Last change on this file since 3712 was 3712, checked in by matszpk, 3 years ago

CLRadeonExtender: AmdCL2: Handle vectypehint and work_group_size_hint in kernel metadata. Add '.vectypehint' and '.work_group_size_hint' pseudo-ops
to AmdCL2 format handling. Add new pseudo-ops to editor's syntaxes.

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