| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 |
- // Copyright 2018 yuzu emulator team
- // Licensed under GPLv2 or any later version
- // Refer to the license.txt file included.
- #include <algorithm>
- #include <cstring>
- #include "common/assert.h"
- #include "common/logging/log.h"
- #include "core/hle/service/nvdrv/devices/nvmap.h"
- namespace Service::Nvidia::Devices {
- nvmap::nvmap(Core::System& system) : nvdevice(system) {
- // Handle 0 appears to be used when remapping, so we create a placeholder empty nvmap object to
- // represent this.
- CreateObject(0);
- }
- nvmap::~nvmap() = default;
- NvResult nvmap::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
- switch (command.group) {
- case 0x1:
- switch (command.cmd) {
- case 0x1:
- return IocCreate(input, output);
- case 0x3:
- return IocFromId(input, output);
- case 0x4:
- return IocAlloc(input, output);
- case 0x5:
- return IocFree(input, output);
- case 0x9:
- return IocParam(input, output);
- case 0xe:
- return IocGetId(input, output);
- default:
- break;
- }
- break;
- default:
- break;
- }
- UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
- return NvResult::NotImplemented;
- }
- NvResult nvmap::Ioctl2(Ioctl command, const std::vector<u8>& input,
- const std::vector<u8>& inline_input, std::vector<u8>& output) {
- UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
- return NvResult::NotImplemented;
- }
- NvResult nvmap::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
- std::vector<u8>& inline_output) {
- UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
- return NvResult::NotImplemented;
- }
- VAddr nvmap::GetObjectAddress(u32 handle) const {
- auto object = GetObject(handle);
- ASSERT(object);
- ASSERT(object->status == Object::Status::Allocated);
- return object->addr;
- }
- u32 nvmap::CreateObject(u32 size) {
- // Create a new nvmap object and obtain a handle to it.
- auto object = std::make_shared<Object>();
- object->id = next_id++;
- object->size = size;
- object->status = Object::Status::Created;
- object->refcount = 1;
- const u32 handle = next_handle++;
- handles.insert_or_assign(handle, std::move(object));
- return handle;
- }
- NvResult nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) {
- IocCreateParams params;
- std::memcpy(¶ms, input.data(), sizeof(params));
- LOG_DEBUG(Service_NVDRV, "size=0x{:08X}", params.size);
- if (!params.size) {
- LOG_ERROR(Service_NVDRV, "Size is 0");
- return NvResult::BadValue;
- }
- params.handle = CreateObject(params.size);
- std::memcpy(output.data(), ¶ms, sizeof(params));
- return NvResult::Success;
- }
- NvResult nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
- IocAllocParams params;
- std::memcpy(¶ms, input.data(), sizeof(params));
- LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.addr);
- if (!params.handle) {
- LOG_ERROR(Service_NVDRV, "Handle is 0");
- return NvResult::BadValue;
- }
- if ((params.align - 1) & params.align) {
- LOG_ERROR(Service_NVDRV, "Incorrect alignment used, alignment={:08X}", params.align);
- return NvResult::BadValue;
- }
- const u32 min_alignment = 0x1000;
- if (params.align < min_alignment) {
- params.align = min_alignment;
- }
- auto object = GetObject(params.handle);
- if (!object) {
- LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
- return NvResult::BadValue;
- }
- if (object->status == Object::Status::Allocated) {
- LOG_ERROR(Service_NVDRV, "Object is already allocated, handle={:08X}", params.handle);
- return NvResult::InsufficientMemory;
- }
- object->flags = params.flags;
- object->align = params.align;
- object->kind = params.kind;
- object->addr = params.addr;
- object->status = Object::Status::Allocated;
- std::memcpy(output.data(), ¶ms, sizeof(params));
- return NvResult::Success;
- }
- NvResult nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) {
- IocGetIdParams params;
- std::memcpy(¶ms, input.data(), sizeof(params));
- LOG_WARNING(Service_NVDRV, "called");
- if (!params.handle) {
- LOG_ERROR(Service_NVDRV, "Handle is zero");
- return NvResult::BadValue;
- }
- auto object = GetObject(params.handle);
- if (!object) {
- LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
- return NvResult::BadValue;
- }
- params.id = object->id;
- std::memcpy(output.data(), ¶ms, sizeof(params));
- return NvResult::Success;
- }
- NvResult nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {
- IocFromIdParams params;
- std::memcpy(¶ms, input.data(), sizeof(params));
- LOG_WARNING(Service_NVDRV, "(STUBBED) called");
- auto itr = std::find_if(handles.begin(), handles.end(),
- [&](const auto& entry) { return entry.second->id == params.id; });
- if (itr == handles.end()) {
- LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
- return NvResult::BadValue;
- }
- auto& object = itr->second;
- if (object->status != Object::Status::Allocated) {
- LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle);
- return NvResult::BadValue;
- }
- itr->second->refcount++;
- // Return the existing handle instead of creating a new one.
- params.handle = itr->first;
- std::memcpy(output.data(), ¶ms, sizeof(params));
- return NvResult::Success;
- }
- NvResult nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {
- enum class ParamTypes { Size = 1, Alignment = 2, Base = 3, Heap = 4, Kind = 5, Compr = 6 };
- IocParamParams params;
- std::memcpy(¶ms, input.data(), sizeof(params));
- LOG_WARNING(Service_NVDRV, "(STUBBED) called type={}", params.param);
- auto object = GetObject(params.handle);
- if (!object) {
- LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
- return NvResult::BadValue;
- }
- if (object->status != Object::Status::Allocated) {
- LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle);
- return NvResult::BadValue;
- }
- switch (static_cast<ParamTypes>(params.param)) {
- case ParamTypes::Size:
- params.result = object->size;
- break;
- case ParamTypes::Alignment:
- params.result = object->align;
- break;
- case ParamTypes::Heap:
- // TODO(Subv): Seems to be a hardcoded value?
- params.result = 0x40000000;
- break;
- case ParamTypes::Kind:
- params.result = object->kind;
- break;
- default:
- UNIMPLEMENTED();
- }
- std::memcpy(output.data(), ¶ms, sizeof(params));
- return NvResult::Success;
- }
- NvResult nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) {
- // TODO(Subv): These flags are unconfirmed.
- enum FreeFlags {
- Freed = 0,
- NotFreedYet = 1,
- };
- IocFreeParams params;
- std::memcpy(¶ms, input.data(), sizeof(params));
- LOG_WARNING(Service_NVDRV, "(STUBBED) called");
- auto itr = handles.find(params.handle);
- if (itr == handles.end()) {
- LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
- return NvResult::BadValue;
- }
- if (!itr->second->refcount) {
- LOG_ERROR(
- Service_NVDRV,
- "There is no references to this object. The object is already freed. handle={:08X}",
- params.handle);
- return NvResult::BadValue;
- }
- itr->second->refcount--;
- params.size = itr->second->size;
- if (itr->second->refcount == 0) {
- params.flags = Freed;
- // The address of the nvmap is written to the output if we're finally freeing it, otherwise
- // 0 is written.
- params.address = itr->second->addr;
- } else {
- params.flags = NotFreedYet;
- params.address = 0;
- }
- handles.erase(params.handle);
- std::memcpy(output.data(), ¶ms, sizeof(params));
- return NvResult::Success;
- }
- } // namespace Service::Nvidia::Devices
|