nvmap.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. // Copyright 2018 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include <cstring>
  6. #include "common/assert.h"
  7. #include "common/logging/log.h"
  8. #include "core/hle/service/nvdrv/devices/nvmap.h"
  9. namespace Service::Nvidia::Devices {
  10. namespace NvErrCodes {
  11. enum {
  12. OperationNotPermitted = -1,
  13. InvalidValue = -22,
  14. };
  15. }
  16. nvmap::nvmap(Core::System& system) : nvdevice(system) {}
  17. nvmap::~nvmap() = default;
  18. VAddr nvmap::GetObjectAddress(u32 handle) const {
  19. auto object = GetObject(handle);
  20. ASSERT(object);
  21. ASSERT(object->status == Object::Status::Allocated);
  22. return object->addr;
  23. }
  24. u32 nvmap::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
  25. IoctlCtrl& ctrl) {
  26. switch (static_cast<IoctlCommand>(command.raw)) {
  27. case IoctlCommand::Create:
  28. return IocCreate(input, output);
  29. case IoctlCommand::Alloc:
  30. return IocAlloc(input, output);
  31. case IoctlCommand::GetId:
  32. return IocGetId(input, output);
  33. case IoctlCommand::FromId:
  34. return IocFromId(input, output);
  35. case IoctlCommand::Param:
  36. return IocParam(input, output);
  37. case IoctlCommand::Free:
  38. return IocFree(input, output);
  39. }
  40. UNIMPLEMENTED_MSG("Unimplemented ioctl");
  41. return 0;
  42. }
  43. u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) {
  44. IocCreateParams params;
  45. std::memcpy(&params, input.data(), sizeof(params));
  46. LOG_DEBUG(Service_NVDRV, "size=0x{:08X}", params.size);
  47. if (!params.size) {
  48. LOG_ERROR(Service_NVDRV, "Size is 0");
  49. return static_cast<u32>(NvErrCodes::InvalidValue);
  50. }
  51. // Create a new nvmap object and obtain a handle to it.
  52. auto object = std::make_shared<Object>();
  53. object->id = next_id++;
  54. object->size = params.size;
  55. object->status = Object::Status::Created;
  56. object->refcount = 1;
  57. u32 handle = next_handle++;
  58. handles[handle] = std::move(object);
  59. params.handle = handle;
  60. std::memcpy(output.data(), &params, sizeof(params));
  61. return 0;
  62. }
  63. u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
  64. IocAllocParams params;
  65. std::memcpy(&params, input.data(), sizeof(params));
  66. LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.addr);
  67. if (!params.handle) {
  68. LOG_ERROR(Service_NVDRV, "Handle is 0");
  69. return static_cast<u32>(NvErrCodes::InvalidValue);
  70. }
  71. if ((params.align - 1) & params.align) {
  72. LOG_ERROR(Service_NVDRV, "Incorrect alignment used, alignment={:08X}", params.align);
  73. return static_cast<u32>(NvErrCodes::InvalidValue);
  74. }
  75. const u32 min_alignment = 0x1000;
  76. if (params.align < min_alignment) {
  77. params.align = min_alignment;
  78. }
  79. auto object = GetObject(params.handle);
  80. if (!object) {
  81. LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
  82. return static_cast<u32>(NvErrCodes::InvalidValue);
  83. }
  84. if (object->status == Object::Status::Allocated) {
  85. LOG_ERROR(Service_NVDRV, "Object is already allocated, handle={:08X}", params.handle);
  86. return static_cast<u32>(NvErrCodes::OperationNotPermitted);
  87. }
  88. object->flags = params.flags;
  89. object->align = params.align;
  90. object->kind = params.kind;
  91. object->addr = params.addr;
  92. object->status = Object::Status::Allocated;
  93. std::memcpy(output.data(), &params, sizeof(params));
  94. return 0;
  95. }
  96. u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) {
  97. IocGetIdParams params;
  98. std::memcpy(&params, input.data(), sizeof(params));
  99. LOG_WARNING(Service_NVDRV, "called");
  100. if (!params.handle) {
  101. LOG_ERROR(Service_NVDRV, "Handle is zero");
  102. return static_cast<u32>(NvErrCodes::InvalidValue);
  103. }
  104. auto object = GetObject(params.handle);
  105. if (!object) {
  106. LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
  107. return static_cast<u32>(NvErrCodes::OperationNotPermitted);
  108. }
  109. params.id = object->id;
  110. std::memcpy(output.data(), &params, sizeof(params));
  111. return 0;
  112. }
  113. u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {
  114. IocFromIdParams params;
  115. std::memcpy(&params, input.data(), sizeof(params));
  116. LOG_WARNING(Service_NVDRV, "(STUBBED) called");
  117. auto itr = std::find_if(handles.begin(), handles.end(),
  118. [&](const auto& entry) { return entry.second->id == params.id; });
  119. if (itr == handles.end()) {
  120. LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
  121. return static_cast<u32>(NvErrCodes::InvalidValue);
  122. }
  123. auto& object = itr->second;
  124. if (object->status != Object::Status::Allocated) {
  125. LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle);
  126. return static_cast<u32>(NvErrCodes::InvalidValue);
  127. }
  128. itr->second->refcount++;
  129. // Return the existing handle instead of creating a new one.
  130. params.handle = itr->first;
  131. std::memcpy(output.data(), &params, sizeof(params));
  132. return 0;
  133. }
  134. u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {
  135. enum class ParamTypes { Size = 1, Alignment = 2, Base = 3, Heap = 4, Kind = 5, Compr = 6 };
  136. IocParamParams params;
  137. std::memcpy(&params, input.data(), sizeof(params));
  138. LOG_WARNING(Service_NVDRV, "(STUBBED) called type={}", params.param);
  139. auto object = GetObject(params.handle);
  140. if (!object) {
  141. LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
  142. return static_cast<u32>(NvErrCodes::InvalidValue);
  143. }
  144. if (object->status != Object::Status::Allocated) {
  145. LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle);
  146. return static_cast<u32>(NvErrCodes::OperationNotPermitted);
  147. }
  148. switch (static_cast<ParamTypes>(params.param)) {
  149. case ParamTypes::Size:
  150. params.result = object->size;
  151. break;
  152. case ParamTypes::Alignment:
  153. params.result = object->align;
  154. break;
  155. case ParamTypes::Heap:
  156. // TODO(Subv): Seems to be a hardcoded value?
  157. params.result = 0x40000000;
  158. break;
  159. case ParamTypes::Kind:
  160. params.result = object->kind;
  161. break;
  162. default:
  163. UNIMPLEMENTED();
  164. }
  165. std::memcpy(output.data(), &params, sizeof(params));
  166. return 0;
  167. }
  168. u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) {
  169. // TODO(Subv): These flags are unconfirmed.
  170. enum FreeFlags {
  171. Freed = 0,
  172. NotFreedYet = 1,
  173. };
  174. IocFreeParams params;
  175. std::memcpy(&params, input.data(), sizeof(params));
  176. LOG_WARNING(Service_NVDRV, "(STUBBED) called");
  177. auto itr = handles.find(params.handle);
  178. if (itr == handles.end()) {
  179. LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
  180. return static_cast<u32>(NvErrCodes::InvalidValue);
  181. }
  182. if (!itr->second->refcount) {
  183. LOG_ERROR(
  184. Service_NVDRV,
  185. "There is no references to this object. The object is already freed. handle={:08X}",
  186. params.handle);
  187. return static_cast<u32>(NvErrCodes::InvalidValue);
  188. }
  189. itr->second->refcount--;
  190. params.size = itr->second->size;
  191. if (itr->second->refcount == 0) {
  192. params.flags = Freed;
  193. // The address of the nvmap is written to the output if we're finally freeing it, otherwise
  194. // 0 is written.
  195. params.address = itr->second->addr;
  196. } else {
  197. params.flags = NotFreedYet;
  198. params.address = 0;
  199. }
  200. handles.erase(params.handle);
  201. std::memcpy(output.data(), &params, sizeof(params));
  202. return 0;
  203. }
  204. } // namespace Service::Nvidia::Devices