| /* | |
| * Copyright (c) 2012-2015 Advanced Micro Devices, Inc. | |
| * All rights reserved. | |
| * | |
| * For use for simulation and test purposes only | |
| * | |
| * Redistribution and use in source and binary forms, with or without | |
| * modification, are permitted provided that the following conditions are met: | |
| * | |
| * 1. Redistributions of source code must retain the above copyright notice, | |
| * this list of conditions and the following disclaimer. | |
| * | |
| * 2. Redistributions in binary form must reproduce the above copyright notice, | |
| * this list of conditions and the following disclaimer in the documentation | |
| * and/or other materials provided with the distribution. | |
| * | |
| * 3. Neither the name of the copyright holder nor the names of its contributors | |
| * may be used to endorse or promote products derived from this software | |
| * without specific prior written permission. | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| * POSSIBILITY OF SUCH DAMAGE. | |
| * | |
| * Author: Anthony Gutierrez | |
| */ | |
| #include "gpu-compute/cl_driver.hh" | |
| #include <memory> | |
| #include "base/intmath.hh" | |
| #include "cpu/thread_context.hh" | |
| #include "gpu-compute/dispatcher.hh" | |
| #include "gpu-compute/hsa_code.hh" | |
| #include "gpu-compute/hsa_kernel_info.hh" | |
| #include "gpu-compute/hsa_object.hh" | |
| #include "params/ClDriver.hh" | |
| #include "sim/process.hh" | |
| #include "sim/syscall_emul_buf.hh" | |
| ClDriver::ClDriver(ClDriverParams *p) | |
| : EmulatedDriver(p), hsaCode(0) | |
| { | |
| for (const auto &codeFile : p->codefile) | |
| codeFiles.push_back(&codeFile); | |
| maxFuncArgsSize = 0; | |
| for (int i = 0; i < codeFiles.size(); ++i) { | |
| HsaObject *obj = HsaObject::createHsaObject(*codeFiles[i]); | |
| for (int k = 0; k < obj->numKernels(); ++k) { | |
| assert(obj->getKernel(k)); | |
| kernels.push_back(obj->getKernel(k)); | |
| kernels.back()->setReadonlyData((uint8_t*)obj->readonlyData); | |
| int kern_funcargs_size = kernels.back()->funcarg_size; | |
| maxFuncArgsSize = maxFuncArgsSize < kern_funcargs_size ? | |
| kern_funcargs_size : maxFuncArgsSize; | |
| } | |
| } | |
| int name_offs = 0; | |
| int code_offs = 0; | |
| for (int i = 0; i < kernels.size(); ++i) { | |
| kernelInfo.push_back(HsaKernelInfo()); | |
| HsaCode *k = kernels[i]; | |
| k->generateHsaKernelInfo(&kernelInfo[i]); | |
| kernelInfo[i].name_offs = name_offs; | |
| kernelInfo[i].code_offs = code_offs; | |
| name_offs += k->name().size() + 1; | |
| code_offs += k->numInsts() * sizeof(TheGpuISA::RawMachInst); | |
| } | |
| } | |
| void | |
| ClDriver::handshake(GpuDispatcher *_dispatcher) | |
| { | |
| dispatcher = _dispatcher; | |
| dispatcher->setFuncargsSize(maxFuncArgsSize); | |
| } | |
| int | |
| ClDriver::open(ThreadContext *tc, int mode, int flags) | |
| { | |
| auto p = tc->getProcessPtr(); | |
| std::shared_ptr<DeviceFDEntry> fdp; | |
| fdp = std::make_shared<DeviceFDEntry>(this, filename); | |
| int tgt_fd = p->fds->allocFD(fdp); | |
| return tgt_fd; | |
| } | |
| int | |
| ClDriver::ioctl(ThreadContext *tc, unsigned req) | |
| { | |
| int index = 2; | |
| auto process = tc->getProcessPtr(); | |
| Addr buf_addr = process->getSyscallArg(tc, index); | |
| switch (req) { | |
| case HSA_GET_SIZES: | |
| { | |
| TypedBufferArg<HsaDriverSizes> sizes(buf_addr); | |
| sizes->num_kernels = kernels.size(); | |
| sizes->string_table_size = 0; | |
| sizes->code_size = 0; | |
| sizes->readonly_size = 0; | |
| if (kernels.size() > 0) { | |
| // all kernels will share the same read-only memory | |
| sizes->readonly_size = | |
| kernels[0]->getSize(HsaCode::MemorySegment::READONLY); | |
| // check our assumption | |
| for (int i = 1; i<kernels.size(); ++i) { | |
| assert(sizes->readonly_size == | |
| kernels[i]->getSize(HsaCode::MemorySegment::READONLY)); | |
| } | |
| } | |
| for (int i = 0; i < kernels.size(); ++i) { | |
| HsaCode *k = kernels[i]; | |
| // add one for terminating '\0' | |
| sizes->string_table_size += k->name().size() + 1; | |
| sizes->code_size += | |
| k->numInsts() * sizeof(TheGpuISA::RawMachInst); | |
| } | |
| sizes.copyOut(tc->getVirtProxy()); | |
| } | |
| break; | |
| case HSA_GET_KINFO: | |
| { | |
| TypedBufferArg<HsaKernelInfo> | |
| kinfo(buf_addr, sizeof(HsaKernelInfo) * kernels.size()); | |
| for (int i = 0; i < kernels.size(); ++i) { | |
| HsaKernelInfo *ki = &kinfo[i]; | |
| ki->name_offs = kernelInfo[i].name_offs; | |
| ki->code_offs = kernelInfo[i].code_offs; | |
| ki->sRegCount = kernelInfo[i].sRegCount; | |
| ki->dRegCount = kernelInfo[i].dRegCount; | |
| ki->cRegCount = kernelInfo[i].cRegCount; | |
| ki->static_lds_size = kernelInfo[i].static_lds_size; | |
| ki->private_mem_size = kernelInfo[i].private_mem_size; | |
| ki->spill_mem_size = kernelInfo[i].spill_mem_size; | |
| } | |
| kinfo.copyOut(tc->getVirtProxy()); | |
| } | |
| break; | |
| case HSA_GET_STRINGS: | |
| { | |
| int string_table_size = 0; | |
| for (int i = 0; i < kernels.size(); ++i) { | |
| HsaCode *k = kernels[i]; | |
| string_table_size += k->name().size() + 1; | |
| } | |
| BufferArg buf(buf_addr, string_table_size); | |
| char *bufp = (char*)buf.bufferPtr(); | |
| for (int i = 0; i < kernels.size(); ++i) { | |
| HsaCode *k = kernels[i]; | |
| const char *n = k->name().c_str(); | |
| // idiomatic string copy | |
| while ((*bufp++ = *n++)); | |
| } | |
| assert(bufp - (char *)buf.bufferPtr() == string_table_size); | |
| buf.copyOut(tc->getVirtProxy()); | |
| } | |
| break; | |
| case HSA_GET_READONLY_DATA: | |
| { | |
| // we can pick any kernel --- they share the same | |
| // readonly segment (this assumption is checked in GET_SIZES) | |
| uint64_t size = | |
| kernels.back()->getSize(HsaCode::MemorySegment::READONLY); | |
| BufferArg data(buf_addr, size); | |
| char *datap = (char *)data.bufferPtr(); | |
| memcpy(datap, | |
| kernels.back()->readonly_data, | |
| size); | |
| data.copyOut(tc->getVirtProxy()); | |
| } | |
| break; | |
| case HSA_GET_CODE: | |
| { | |
| // set hsaCode pointer | |
| hsaCode = buf_addr; | |
| int code_size = 0; | |
| for (int i = 0; i < kernels.size(); ++i) { | |
| HsaCode *k = kernels[i]; | |
| code_size += k->numInsts() * sizeof(TheGpuISA::RawMachInst); | |
| } | |
| TypedBufferArg<TheGpuISA::RawMachInst> buf(buf_addr, code_size); | |
| TheGpuISA::RawMachInst *bufp = buf; | |
| int buf_idx = 0; | |
| for (int i = 0; i < kernels.size(); ++i) { | |
| HsaCode *k = kernels[i]; | |
| for (int j = 0; j < k->numInsts(); ++j) { | |
| bufp[buf_idx] = k->insts()->at(j); | |
| ++buf_idx; | |
| } | |
| } | |
| buf.copyOut(tc->getVirtProxy()); | |
| } | |
| break; | |
| case HSA_GET_CU_CNT: | |
| { | |
| BufferArg buf(buf_addr, sizeof(uint32_t)); | |
| *((uint32_t*)buf.bufferPtr()) = dispatcher->getNumCUs(); | |
| buf.copyOut(tc->getVirtProxy()); | |
| } | |
| break; | |
| case HSA_GET_VSZ: | |
| { | |
| BufferArg buf(buf_addr, sizeof(uint32_t)); | |
| *((uint32_t*)buf.bufferPtr()) = dispatcher->wfSize(); | |
| buf.copyOut(tc->getVirtProxy()); | |
| } | |
| break; | |
| case HSA_GET_HW_STATIC_CONTEXT_SIZE: | |
| { | |
| BufferArg buf(buf_addr, sizeof(uint32_t)); | |
| *((uint32_t*)buf.bufferPtr()) = dispatcher->getStaticContextSize(); | |
| buf.copyOut(tc->getVirtProxy()); | |
| } | |
| break; | |
| default: | |
| fatal("ClDriver: bad ioctl %d\n", req); | |
| } | |
| return 0; | |
| } | |
| const char* | |
| ClDriver::codeOffToKernelName(uint64_t code_ptr) | |
| { | |
| assert(hsaCode); | |
| uint32_t code_offs = code_ptr - hsaCode; | |
| for (int i = 0; i < kernels.size(); ++i) { | |
| if (code_offs == kernelInfo[i].code_offs) { | |
| return kernels[i]->name().c_str(); | |
| } | |
| } | |
| return nullptr; | |
| } | |
| ClDriver* | |
| ClDriverParams::create() | |
| { | |
| return new ClDriver(this); | |
| } |