diff options
| author | bunnei <bunneidev@gmail.com> | 2020-11-20 22:15:44 -0800 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-11-20 22:15:44 -0800 | 
| commit | afd0e2ee87c0a786e1a21c08689f3b016aa7b83f (patch) | |
| tree | 2ca2468750b9e96eb938473f0b021c938f8f86fb /src/core/hle | |
| parent | d88baa746bc10df1afadd90f5149a29abc3e4ace (diff) | |
| parent | fc4d692c503ca11a9339f0464520caf88d8474de (diff) | |
Merge pull request #4907 from ogniK5377/nvdrv-cleanup
core: Make nvservices more standardized
Diffstat (limited to 'src/core/hle')
26 files changed, 1220 insertions, 898 deletions
| diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h index 0240d6643..5681599ba 100644 --- a/src/core/hle/service/nvdrv/devices/nvdevice.h +++ b/src/core/hle/service/nvdrv/devices/nvdevice.h @@ -24,25 +24,37 @@ public:      explicit nvdevice(Core::System& system) : system{system} {}      virtual ~nvdevice() = default; -    union Ioctl { -        u32_le raw; -        BitField<0, 8, u32> cmd; -        BitField<8, 8, u32> group; -        BitField<16, 14, u32> length; -        BitField<30, 1, u32> is_in; -        BitField<31, 1, u32> is_out; -    }; +    /** +     * Handles an ioctl1 request. +     * @param command The ioctl command id. +     * @param input A buffer containing the input data for the ioctl. +     * @param output A buffer where the output data will be written to. +     * @returns The result code of the ioctl. +     */ +    virtual NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, +                            std::vector<u8>& output) = 0; + +    /** +     * Handles an ioctl2 request. +     * @param command The ioctl command id. +     * @param input A buffer containing the input data for the ioctl. +     * @param inline_input A buffer containing the input data for the ioctl which has been inlined. +     * @param output A buffer where the output data will be written to. +     * @returns The result code of the ioctl. +     */ +    virtual NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, +                            const std::vector<u8>& inline_input, std::vector<u8>& output) = 0;      /** -     * Handles an ioctl request. +     * Handles an ioctl3 request.       * @param command The ioctl command id.       * @param input A buffer containing the input data for the ioctl.       * @param output A buffer where the output data will be written to. +     * @param inline_output A buffer where the inlined output data will be written to.       * @returns The result code of the ioctl.       */ -    virtual u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -                      std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -                      IoctlVersion version) = 0; +    virtual NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, +                            std::vector<u8>& inline_output) = 0;  protected:      Core::System& system; diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index 3f7b8e670..ce615c758 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp @@ -18,11 +18,22 @@ nvdisp_disp0::nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_de      : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}  nvdisp_disp0 ::~nvdisp_disp0() = default; -u32 nvdisp_disp0::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -                        std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -                        IoctlVersion version) { -    UNIMPLEMENTED_MSG("Unimplemented ioctl"); -    return 0; +NvResult nvdisp_disp0::Ioctl1(Ioctl command, const std::vector<u8>& input, +                              std::vector<u8>& output) { +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented; +} + +NvResult nvdisp_disp0::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 nvdisp_disp0::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;  }  void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h index 6fcdeee84..55a33b7e4 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h @@ -20,9 +20,11 @@ public:      explicit nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);      ~nvdisp_disp0() override; -    u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -              std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -              IoctlVersion version) override; +    NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; +    NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, +                    const std::vector<u8>& inline_input, std::vector<u8>& output) override; +    NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, +                    std::vector<u8>& inline_output) override;      /// Performs a screen flip, drawing the buffer pointed to by the handle.      void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride, diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index f2529a12e..6b062e10e 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -17,59 +17,77 @@  namespace Service::Nvidia::Devices { -namespace NvErrCodes { -constexpr u32 Success{}; -constexpr u32 OutOfMemory{static_cast<u32>(-12)}; -constexpr u32 InvalidInput{static_cast<u32>(-22)}; -} // namespace NvErrCodes -  nvhost_as_gpu::nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev)      : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}  nvhost_as_gpu::~nvhost_as_gpu() = default; -u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -                         std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -                         IoctlVersion version) { -    LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", -              command.raw, input.size(), output.size()); - -    switch (static_cast<IoctlCommand>(command.raw)) { -    case IoctlCommand::IocInitalizeExCommand: -        return InitalizeEx(input, output); -    case IoctlCommand::IocAllocateSpaceCommand: -        return AllocateSpace(input, output); -    case IoctlCommand::IocMapBufferExCommand: -        return MapBufferEx(input, output); -    case IoctlCommand::IocBindChannelCommand: -        return BindChannel(input, output); -    case IoctlCommand::IocGetVaRegionsCommand: -        return GetVARegions(input, output); -    case IoctlCommand::IocUnmapBufferCommand: -        return UnmapBuffer(input, output); -    case IoctlCommand::IocFreeSpaceCommand: -        return FreeSpace(input, output); +NvResult nvhost_as_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input, +                               std::vector<u8>& output) { +    switch (command.group) { +    case 'A': +        switch (command.cmd) { +        case 0x1: +            return BindChannel(input, output); +        case 0x2: +            return AllocateSpace(input, output); +        case 0x3: +            return FreeSpace(input, output); +        case 0x5: +            return UnmapBuffer(input, output); +        case 0x6: +            return MapBufferEx(input, output); +        case 0x8: +            return GetVARegions(input, output); +        case 0x9: +            return InitalizeEx(input, output); +        case 0x14: +            return Remap(input, output); +        default: +            break; +        } +        break;      default:          break;      } -    if (static_cast<IoctlCommand>(command.cmd.Value()) == IoctlCommand::IocRemapCommand) { -        return Remap(input, output); -    } +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented; +} + +NvResult nvhost_as_gpu::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; +} -    UNIMPLEMENTED_MSG("Unimplemented ioctl command"); -    return 0; +NvResult nvhost_as_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, +                               std::vector<u8>& inline_output) { +    switch (command.group) { +    case 'A': +        switch (command.cmd) { +        case 0x8: +            return GetVARegions(input, output, inline_output); +        default: +            break; +        } +        break; +    default: +        break; +    } +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented;  } -u32 nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlInitalizeEx params{};      std::memcpy(¶ms, input.data(), input.size());      LOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size); -    return 0; +    return NvResult::Success;  } -u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlAllocSpace params{};      std::memcpy(¶ms, input.data(), input.size()); @@ -83,17 +101,17 @@ u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>&          params.offset = system.GPU().MemoryManager().Allocate(size, params.align);      } -    auto result{NvErrCodes::Success}; +    auto result = NvResult::Success;      if (!params.offset) {          LOG_CRITICAL(Service_NVDRV, "allocation failed for size {}", size); -        result = NvErrCodes::OutOfMemory; +        result = NvResult::InsufficientMemory;      }      std::memcpy(output.data(), ¶ms, output.size());      return result;  } -u32 nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlFreeSpace params{};      std::memcpy(¶ms, input.data(), input.size()); @@ -104,15 +122,15 @@ u32 nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>& outp                                         static_cast<std::size_t>(params.pages) * params.page_size);      std::memcpy(output.data(), ¶ms, output.size()); -    return NvErrCodes::Success; +    return NvResult::Success;  } -u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) {      const auto num_entries = input.size() / sizeof(IoctlRemapEntry);      LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", num_entries); -    auto result{NvErrCodes::Success}; +    auto result = NvResult::Success;      std::vector<IoctlRemapEntry> entries(num_entries);      std::memcpy(entries.data(), input.data(), input.size()); @@ -123,7 +141,7 @@ u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output)          const auto object{nvmap_dev->GetObject(entry.nvmap_handle)};          if (!object) {              LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", entry.nvmap_handle); -            result = NvErrCodes::InvalidInput; +            result = NvResult::InvalidState;              break;          } @@ -134,7 +152,7 @@ u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output)          if (!addr) {              LOG_CRITICAL(Service_NVDRV, "map returned an invalid address!"); -            result = NvErrCodes::InvalidInput; +            result = NvResult::InvalidState;              break;          }      } @@ -143,7 +161,7 @@ u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output)      return result;  } -u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlMapBufferEx params{};      std::memcpy(¶ms, input.data(), input.size()); @@ -157,7 +175,7 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou      if (!object) {          LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", params.nvmap_handle);          std::memcpy(output.data(), ¶ms, output.size()); -        return NvErrCodes::InvalidInput; +        return NvResult::InvalidState;      }      // The real nvservices doesn't make a distinction between handles and ids, and @@ -184,16 +202,16 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou                               params.mapping_size, params.offset);                  std::memcpy(output.data(), ¶ms, output.size()); -                return NvErrCodes::InvalidInput; +                return NvResult::InvalidState;              }              std::memcpy(output.data(), ¶ms, output.size()); -            return NvErrCodes::Success; +            return NvResult::Success;          } else {              LOG_CRITICAL(Service_NVDRV, "address not mapped offset={}", params.offset);              std::memcpy(output.data(), ¶ms, output.size()); -            return NvErrCodes::InvalidInput; +            return NvResult::InvalidState;          }      } @@ -213,10 +231,10 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou          params.offset = gpu.MemoryManager().Map(physical_address, params.offset, size);      } -    auto result{NvErrCodes::Success}; +    auto result = NvResult::Success;      if (!params.offset) {          LOG_CRITICAL(Service_NVDRV, "failed to map size={}", size); -        result = NvErrCodes::InvalidInput; +        result = NvResult::InvalidState;      } else {          AddBufferMap(params.offset, size, physical_address, is_alloc);      } @@ -225,7 +243,7 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou      return result;  } -u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlUnmapBuffer params{};      std::memcpy(¶ms, input.data(), input.size()); @@ -238,20 +256,42 @@ u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& ou      }      std::memcpy(output.data(), ¶ms, output.size()); -    return NvErrCodes::Success; +    return NvResult::Success;  } -u32 nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlBindChannel params{};      std::memcpy(¶ms, input.data(), input.size()); - -    LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd); +    LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}", params.fd);      channel = params.fd; -    return 0; +    return NvResult::Success; +} + +NvResult nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output) { +    IoctlGetVaRegions params{}; +    std::memcpy(¶ms, input.data(), input.size()); + +    LOG_WARNING(Service_NVDRV, "(STUBBED) called, buf_addr={:X}, buf_size={:X}", params.buf_addr, +                params.buf_size); + +    params.buf_size = 0x30; +    params.regions[0].offset = 0x04000000; +    params.regions[0].page_size = 0x1000; +    params.regions[0].pages = 0x3fbfff; + +    params.regions[1].offset = 0x04000000; +    params.regions[1].page_size = 0x10000; +    params.regions[1].pages = 0x1bffff; + +    // TODO(ogniK): This probably can stay stubbed but should add support way way later + +    std::memcpy(output.data(), ¶ms, output.size()); +    return NvResult::Success;  } -u32 nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output, +                                     std::vector<u8>& inline_output) {      IoctlGetVaRegions params{};      std::memcpy(¶ms, input.data(), input.size()); @@ -270,7 +310,8 @@ u32 nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& o      // TODO(ogniK): This probably can stay stubbed but should add support way way later      std::memcpy(output.data(), ¶ms, output.size()); -    return 0; +    std::memcpy(inline_output.data(), ¶ms.regions, inline_output.size()); +    return NvResult::Success;  }  std::optional<nvhost_as_gpu::BufferMap> nvhost_as_gpu::FindBufferMap(GPUVAddr gpu_addr) const { diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h index fcdb40d93..08035fa0e 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h @@ -30,9 +30,11 @@ public:      explicit nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);      ~nvhost_as_gpu() override; -    u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -              std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -              IoctlVersion version) override; +    NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; +    NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, +                    const std::vector<u8>& inline_input, std::vector<u8>& output) override; +    NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, +                    std::vector<u8>& inline_output) override;  private:      class BufferMap final { @@ -74,32 +76,21 @@ private:          bool is_allocated{};      }; -    enum class IoctlCommand : u32_le { -        IocInitalizeExCommand = 0x40284109, -        IocAllocateSpaceCommand = 0xC0184102, -        IocRemapCommand = 0x00000014, -        IocMapBufferExCommand = 0xC0284106, -        IocBindChannelCommand = 0x40044101, -        IocGetVaRegionsCommand = 0xC0404108, -        IocUnmapBufferCommand = 0xC0084105, -        IocFreeSpaceCommand = 0xC0104103, -    }; -      struct IoctlInitalizeEx { -        u32_le big_page_size; // depends on GPU's available_big_page_sizes; 0=default -        s32_le as_fd;         // ignored; passes 0 -        u32_le flags;         // passes 0 -        u32_le reserved;      // ignored; passes 0 -        u64_le unk0; -        u64_le unk1; -        u64_le unk2; +        u32_le big_page_size{}; // depends on GPU's available_big_page_sizes; 0=default +        s32_le as_fd{};         // ignored; passes 0 +        u32_le flags{};         // passes 0 +        u32_le reserved{};      // ignored; passes 0 +        u64_le unk0{}; +        u64_le unk1{}; +        u64_le unk2{};      };      static_assert(sizeof(IoctlInitalizeEx) == 40, "IoctlInitalizeEx is incorrect size");      struct IoctlAllocSpace { -        u32_le pages; -        u32_le page_size; -        AddressSpaceFlags flags; +        u32_le pages{}; +        u32_le page_size{}; +        AddressSpaceFlags flags{};          INSERT_PADDING_WORDS(1);          union {              u64_le offset; @@ -109,70 +100,73 @@ private:      static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitalizeEx is incorrect size");      struct IoctlFreeSpace { -        u64_le offset; -        u32_le pages; -        u32_le page_size; +        u64_le offset{}; +        u32_le pages{}; +        u32_le page_size{};      };      static_assert(sizeof(IoctlFreeSpace) == 16, "IoctlFreeSpace is incorrect size");      struct IoctlRemapEntry { -        u16_le flags; -        u16_le kind; -        u32_le nvmap_handle; -        u32_le map_offset; -        u32_le offset; -        u32_le pages; +        u16_le flags{}; +        u16_le kind{}; +        u32_le nvmap_handle{}; +        u32_le map_offset{}; +        u32_le offset{}; +        u32_le pages{};      };      static_assert(sizeof(IoctlRemapEntry) == 20, "IoctlRemapEntry is incorrect size");      struct IoctlMapBufferEx { -        AddressSpaceFlags flags; // bit0: fixed_offset, bit2: cacheable -        u32_le kind;             // -1 is default -        u32_le nvmap_handle; -        u32_le page_size; // 0 means don't care -        s64_le buffer_offset; -        u64_le mapping_size; -        s64_le offset; +        AddressSpaceFlags flags{}; // bit0: fixed_offset, bit2: cacheable +        u32_le kind{};             // -1 is default +        u32_le nvmap_handle{}; +        u32_le page_size{}; // 0 means don't care +        s64_le buffer_offset{}; +        u64_le mapping_size{}; +        s64_le offset{};      };      static_assert(sizeof(IoctlMapBufferEx) == 40, "IoctlMapBufferEx is incorrect size");      struct IoctlUnmapBuffer { -        s64_le offset; +        s64_le offset{};      };      static_assert(sizeof(IoctlUnmapBuffer) == 8, "IoctlUnmapBuffer is incorrect size");      struct IoctlBindChannel { -        u32_le fd; +        s32_le fd{};      };      static_assert(sizeof(IoctlBindChannel) == 4, "IoctlBindChannel is incorrect size");      struct IoctlVaRegion { -        u64_le offset; -        u32_le page_size; +        u64_le offset{}; +        u32_le page_size{};          INSERT_PADDING_WORDS(1); -        u64_le pages; +        u64_le pages{};      };      static_assert(sizeof(IoctlVaRegion) == 24, "IoctlVaRegion is incorrect size");      struct IoctlGetVaRegions { -        u64_le buf_addr; // (contained output user ptr on linux, ignored) -        u32_le buf_size; // forced to 2*sizeof(struct va_region) -        u32_le reserved; -        IoctlVaRegion regions[2]; +        u64_le buf_addr{}; // (contained output user ptr on linux, ignored) +        u32_le buf_size{}; // forced to 2*sizeof(struct va_region) +        u32_le reserved{}; +        IoctlVaRegion regions[2]{};      };      static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(IoctlVaRegion) * 2,                    "IoctlGetVaRegions is incorrect size"); -    u32 channel{}; +    s32 channel{}; + +    NvResult InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult Remap(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult FreeSpace(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult BindChannel(const std::vector<u8>& input, std::vector<u8>& output); -    u32 InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output); -    u32 AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output); -    u32 Remap(const std::vector<u8>& input, std::vector<u8>& output); -    u32 MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output); -    u32 UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output); -    u32 FreeSpace(const std::vector<u8>& input, std::vector<u8>& output); -    u32 BindChannel(const std::vector<u8>& input, std::vector<u8>& output); -    u32 GetVARegions(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult GetVARegions(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult GetVARegions(const std::vector<u8>& input, std::vector<u8>& output, +                          std::vector<u8>& inline_output);      std::optional<BufferMap> FindBufferMap(GPUVAddr gpu_addr) const;      void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index 8356a8139..d90cf90a8 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -20,41 +20,54 @@ nvhost_ctrl::nvhost_ctrl(Core::System& system, EventInterface& events_interface,      : nvdevice(system), events_interface{events_interface}, syncpoint_manager{syncpoint_manager} {}  nvhost_ctrl::~nvhost_ctrl() = default; -u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -                       std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -                       IoctlVersion version) { -    LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", -              command.raw, input.size(), output.size()); - -    switch (static_cast<IoctlCommand>(command.raw)) { -    case IoctlCommand::IocGetConfigCommand: -        return NvOsGetConfigU32(input, output); -    case IoctlCommand::IocCtrlEventWaitCommand: -        return IocCtrlEventWait(input, output, false, ctrl); -    case IoctlCommand::IocCtrlEventWaitAsyncCommand: -        return IocCtrlEventWait(input, output, true, ctrl); -    case IoctlCommand::IocCtrlEventRegisterCommand: -        return IocCtrlEventRegister(input, output); -    case IoctlCommand::IocCtrlEventUnregisterCommand: -        return IocCtrlEventUnregister(input, output); -    case IoctlCommand::IocCtrlClearEventWaitCommand: -        return IocCtrlClearEventWait(input, output); +NvResult nvhost_ctrl::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { +    switch (command.group) { +    case 0x0: +        switch (command.cmd) { +        case 0x1b: +            return NvOsGetConfigU32(input, output); +        case 0x1c: +            return IocCtrlClearEventWait(input, output); +        case 0x1d: +            return IocCtrlEventWait(input, output, false); +        case 0x1e: +            return IocCtrlEventWait(input, output, true); +        case 0x1f: +            return IocCtrlEventRegister(input, output); +        case 0x20: +            return IocCtrlEventUnregister(input, output); +        } +        break;      default: -        UNIMPLEMENTED_MSG("Unimplemented ioctl"); -        return 0; +        break;      } + +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented; +} + +NvResult nvhost_ctrl::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 nvhost_ctrl::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;  } -u32 nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output) {      IocGetConfigParams params{};      std::memcpy(¶ms, input.data(), sizeof(params));      LOG_TRACE(Service_NVDRV, "called, setting={}!{}", params.domain_str.data(),                params.param_str.data()); -    return 0x30006; // Returns error on production mode +    return NvResult::ConfigVarNotFound; // Returns error on production mode  } -u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, -                                  bool is_async, IoctlCtrl& ctrl) { +NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, +                                       bool is_async) {      IocCtrlEventWaitParams params{};      std::memcpy(¶ms, input.data(), sizeof(params));      LOG_DEBUG(Service_NVDRV, "syncpt_id={}, threshold={}, timeout={}, is_async={}", @@ -126,10 +139,7 @@ u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>&          params.value |= event_id;          event.event.writable->Clear();          gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value); -        if (!is_async && ctrl.fresh_call) { -            ctrl.must_delay = true; -            ctrl.timeout = params.timeout; -            ctrl.event_id = event_id; +        if (!is_async) {              return NvResult::Timeout;          }          std::memcpy(output.data(), ¶ms, sizeof(params)); @@ -139,7 +149,7 @@ u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>&      return NvResult::BadParameter;  } -u32 nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output) {      IocCtrlEventRegisterParams params{};      std::memcpy(¶ms, input.data(), sizeof(params));      const u32 event_id = params.user_event_id & 0x00FF; @@ -154,7 +164,8 @@ u32 nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<      return NvResult::Success;  } -u32 nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input, +                                             std::vector<u8>& output) {      IocCtrlEventUnregisterParams params{};      std::memcpy(¶ms, input.data(), sizeof(params));      const u32 event_id = params.user_event_id & 0x00FF; @@ -169,7 +180,7 @@ u32 nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input, std::vecto      return NvResult::Success;  } -u32 nvhost_ctrl::IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_ctrl::IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output) {      IocCtrlEventSignalParams params{};      std::memcpy(¶ms, input.data(), sizeof(params)); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h index 24ad96cb9..c5aa1362a 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h @@ -18,132 +18,113 @@ public:                           SyncpointManager& syncpoint_manager);      ~nvhost_ctrl() override; -    u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -              std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -              IoctlVersion version) override; +    NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; +    NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, +                    const std::vector<u8>& inline_input, std::vector<u8>& output) override; +    NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, +                    std::vector<u8>& inline_output) override;  private: -    enum class IoctlCommand : u32_le { -        IocSyncptReadCommand = 0xC0080014, -        IocSyncptIncrCommand = 0x40040015, -        IocSyncptWaitCommand = 0xC00C0016, -        IocModuleMutexCommand = 0x40080017, -        IocModuleRegRDWRCommand = 0xC0180018, -        IocSyncptWaitexCommand = 0xC0100019, -        IocSyncptReadMaxCommand = 0xC008001A, -        IocGetConfigCommand = 0xC183001B, -        IocCtrlClearEventWaitCommand = 0xC004001C, -        IocCtrlEventWaitCommand = 0xC010001D, -        IocCtrlEventWaitAsyncCommand = 0xC010001E, -        IocCtrlEventRegisterCommand = 0xC004001F, -        IocCtrlEventUnregisterCommand = 0xC0040020, -        IocCtrlEventKillCommand = 0x40080021, -    };      struct IocSyncptReadParams { -        u32_le id; -        u32_le value; +        u32_le id{}; +        u32_le value{};      };      static_assert(sizeof(IocSyncptReadParams) == 8, "IocSyncptReadParams is incorrect size");      struct IocSyncptIncrParams { -        u32_le id; +        u32_le id{};      };      static_assert(sizeof(IocSyncptIncrParams) == 4, "IocSyncptIncrParams is incorrect size");      struct IocSyncptWaitParams { -        u32_le id; -        u32_le thresh; -        s32_le timeout; +        u32_le id{}; +        u32_le thresh{}; +        s32_le timeout{};      };      static_assert(sizeof(IocSyncptWaitParams) == 12, "IocSyncptWaitParams is incorrect size");      struct IocModuleMutexParams { -        u32_le id; -        u32_le lock; // (0 = unlock and 1 = lock) +        u32_le id{}; +        u32_le lock{}; // (0 = unlock and 1 = lock)      };      static_assert(sizeof(IocModuleMutexParams) == 8, "IocModuleMutexParams is incorrect size");      struct IocModuleRegRDWRParams { -        u32_le id; -        u32_le num_offsets; -        u32_le block_size; -        u32_le offsets; -        u32_le values; -        u32_le write; +        u32_le id{}; +        u32_le num_offsets{}; +        u32_le block_size{}; +        u32_le offsets{}; +        u32_le values{}; +        u32_le write{};      };      static_assert(sizeof(IocModuleRegRDWRParams) == 24, "IocModuleRegRDWRParams is incorrect size");      struct IocSyncptWaitexParams { -        u32_le id; -        u32_le thresh; -        s32_le timeout; -        u32_le value; +        u32_le id{}; +        u32_le thresh{}; +        s32_le timeout{}; +        u32_le value{};      };      static_assert(sizeof(IocSyncptWaitexParams) == 16, "IocSyncptWaitexParams is incorrect size");      struct IocSyncptReadMaxParams { -        u32_le id; -        u32_le value; +        u32_le id{}; +        u32_le value{};      };      static_assert(sizeof(IocSyncptReadMaxParams) == 8, "IocSyncptReadMaxParams is incorrect size");      struct IocGetConfigParams { -        std::array<char, 0x41> domain_str; -        std::array<char, 0x41> param_str; -        std::array<char, 0x101> config_str; +        std::array<char, 0x41> domain_str{}; +        std::array<char, 0x41> param_str{}; +        std::array<char, 0x101> config_str{};      };      static_assert(sizeof(IocGetConfigParams) == 387, "IocGetConfigParams is incorrect size");      struct IocCtrlEventSignalParams { -        u32_le event_id; +        u32_le event_id{};      };      static_assert(sizeof(IocCtrlEventSignalParams) == 4,                    "IocCtrlEventSignalParams is incorrect size");      struct IocCtrlEventWaitParams { -        u32_le syncpt_id; -        u32_le threshold; -        s32_le timeout; -        u32_le value; +        u32_le syncpt_id{}; +        u32_le threshold{}; +        s32_le timeout{}; +        u32_le value{};      };      static_assert(sizeof(IocCtrlEventWaitParams) == 16, "IocCtrlEventWaitParams is incorrect size");      struct IocCtrlEventWaitAsyncParams { -        u32_le syncpt_id; -        u32_le threshold; -        u32_le timeout; -        u32_le value; +        u32_le syncpt_id{}; +        u32_le threshold{}; +        u32_le timeout{}; +        u32_le value{};      };      static_assert(sizeof(IocCtrlEventWaitAsyncParams) == 16,                    "IocCtrlEventWaitAsyncParams is incorrect size");      struct IocCtrlEventRegisterParams { -        u32_le user_event_id; +        u32_le user_event_id{};      };      static_assert(sizeof(IocCtrlEventRegisterParams) == 4,                    "IocCtrlEventRegisterParams is incorrect size");      struct IocCtrlEventUnregisterParams { -        u32_le user_event_id; +        u32_le user_event_id{};      };      static_assert(sizeof(IocCtrlEventUnregisterParams) == 4,                    "IocCtrlEventUnregisterParams is incorrect size");      struct IocCtrlEventKill { -        u64_le user_events; +        u64_le user_events{};      };      static_assert(sizeof(IocCtrlEventKill) == 8, "IocCtrlEventKill is incorrect size"); -    u32 NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output); - -    u32 IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, bool is_async, -                         IoctlCtrl& ctrl); - -    u32 IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output); - -    u32 IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output); - -    u32 IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, bool is_async); +    NvResult IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output);      EventInterface& events_interface;      SyncpointManager& syncpoint_manager; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index fba89e7a6..2d7ea433c 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp @@ -15,39 +15,66 @@ namespace Service::Nvidia::Devices {  nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system) : nvdevice(system) {}  nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default; -u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, -                           const std::vector<u8>& input2, std::vector<u8>& output, -                           std::vector<u8>& output2, IoctlCtrl& ctrl, IoctlVersion version) { -    LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", -              command.raw, input.size(), output.size()); - -    switch (static_cast<IoctlCommand>(command.raw)) { -    case IoctlCommand::IocGetCharacteristicsCommand: -        return GetCharacteristics(input, output, output2, version); -    case IoctlCommand::IocGetTPCMasksCommand: -        return GetTPCMasks(input, output, output2, version); -    case IoctlCommand::IocGetActiveSlotMaskCommand: -        return GetActiveSlotMask(input, output); -    case IoctlCommand::IocZcullGetCtxSizeCommand: -        return ZCullGetCtxSize(input, output); -    case IoctlCommand::IocZcullGetInfo: -        return ZCullGetInfo(input, output); -    case IoctlCommand::IocZbcSetTable: -        return ZBCSetTable(input, output); -    case IoctlCommand::IocZbcQueryTable: -        return ZBCQueryTable(input, output); -    case IoctlCommand::IocFlushL2: -        return FlushL2(input, output); -    case IoctlCommand::IocGetGpuTime: -        return GetGpuTime(input, output); +NvResult nvhost_ctrl_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input, +                                 std::vector<u8>& output) { +    switch (command.group) { +    case 'G': +        switch (command.cmd) { +        case 0x1: +            return ZCullGetCtxSize(input, output); +        case 0x2: +            return ZCullGetInfo(input, output); +        case 0x3: +            return ZBCSetTable(input, output); +        case 0x4: +            return ZBCQueryTable(input, output); +        case 0x5: +            return GetCharacteristics(input, output); +        case 0x6: +            return GetTPCMasks(input, output); +        case 0x7: +            return FlushL2(input, output); +        case 0x14: +            return GetActiveSlotMask(input, output); +        case 0x1c: +            return GetGpuTime(input, output); +        default: +            break; +        } +        break; +    } +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented; +} + +NvResult nvhost_ctrl_gpu::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 nvhost_ctrl_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input, +                                 std::vector<u8>& output, std::vector<u8>& inline_output) { +    switch (command.group) { +    case 'G': +        switch (command.cmd) { +        case 0x5: +            return GetCharacteristics(input, output, inline_output); +        case 0x6: +            return GetTPCMasks(input, output, inline_output); +        default: +            break; +        } +        break;      default: -        UNIMPLEMENTED_MSG("Unimplemented ioctl"); -        return 0; +        break;      } +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented;  } -u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output, -                                        std::vector<u8>& output2, IoctlVersion version) { +NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, +                                             std::vector<u8>& output) {      LOG_DEBUG(Service_NVDRV, "called");      IoctlCharacteristics params{};      std::memcpy(¶ms, input.data(), input.size()); @@ -88,36 +115,83 @@ u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vecto      params.gc.gr_compbit_store_base_hw = 0x0;      params.gpu_characteristics_buf_size = 0xA0;      params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED) +    std::memcpy(output.data(), ¶ms, output.size()); +    return NvResult::Success; +} -    if (version == IoctlVersion::Version3) { -        std::memcpy(output.data(), input.data(), output.size()); -        std::memcpy(output2.data(), ¶ms.gc, output2.size()); -    } else { -        std::memcpy(output.data(), ¶ms, output.size()); -    } -    return 0; +NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output, +                                             std::vector<u8>& inline_output) { +    LOG_DEBUG(Service_NVDRV, "called"); +    IoctlCharacteristics params{}; +    std::memcpy(¶ms, input.data(), input.size()); +    params.gc.arch = 0x120; +    params.gc.impl = 0xb; +    params.gc.rev = 0xa1; +    params.gc.num_gpc = 0x1; +    params.gc.l2_cache_size = 0x40000; +    params.gc.on_board_video_memory_size = 0x0; +    params.gc.num_tpc_per_gpc = 0x2; +    params.gc.bus_type = 0x20; +    params.gc.big_page_size = 0x20000; +    params.gc.compression_page_size = 0x20000; +    params.gc.pde_coverage_bit_count = 0x1B; +    params.gc.available_big_page_sizes = 0x30000; +    params.gc.gpc_mask = 0x1; +    params.gc.sm_arch_sm_version = 0x503; +    params.gc.sm_arch_spa_version = 0x503; +    params.gc.sm_arch_warp_count = 0x80; +    params.gc.gpu_va_bit_count = 0x28; +    params.gc.reserved = 0x0; +    params.gc.flags = 0x55; +    params.gc.twod_class = 0x902D; +    params.gc.threed_class = 0xB197; +    params.gc.compute_class = 0xB1C0; +    params.gc.gpfifo_class = 0xB06F; +    params.gc.inline_to_memory_class = 0xA140; +    params.gc.dma_copy_class = 0xB0B5; +    params.gc.max_fbps_count = 0x1; +    params.gc.fbp_en_mask = 0x0; +    params.gc.max_ltc_per_fbp = 0x2; +    params.gc.max_lts_per_ltc = 0x1; +    params.gc.max_tex_per_tpc = 0x0; +    params.gc.max_gpc_count = 0x1; +    params.gc.rop_l2_en_mask_0 = 0x21D70; +    params.gc.rop_l2_en_mask_1 = 0x0; +    params.gc.chipname = 0x6230326D67; +    params.gc.gr_compbit_store_base_hw = 0x0; +    params.gpu_characteristics_buf_size = 0xA0; +    params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED) + +    std::memcpy(output.data(), input.data(), output.size()); +    std::memcpy(inline_output.data(), ¶ms.gc, inline_output.size()); +    return NvResult::Success;  } -u32 nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output, -                                 std::vector<u8>& output2, IoctlVersion version) { +NvResult nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlGpuGetTpcMasksArgs params{};      std::memcpy(¶ms, input.data(), input.size());      LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size);      if (params.mask_buffer_size != 0) {          params.tcp_mask = 3;      } +    std::memcpy(output.data(), ¶ms, output.size()); +    return NvResult::Success; +} -    if (version == IoctlVersion::Version3) { -        std::memcpy(output.data(), input.data(), output.size()); -        std::memcpy(output2.data(), ¶ms.tcp_mask, output2.size()); -    } else { -        std::memcpy(output.data(), ¶ms, output.size()); +NvResult nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output, +                                      std::vector<u8>& inline_output) { +    IoctlGpuGetTpcMasksArgs params{}; +    std::memcpy(¶ms, input.data(), input.size()); +    LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size); +    if (params.mask_buffer_size != 0) { +        params.tcp_mask = 3;      } - -    return 0; +    std::memcpy(output.data(), ¶ms, output.size()); +    std::memcpy(inline_output.data(), ¶ms.tcp_mask, inline_output.size()); +    return NvResult::Success;  } -u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) {      LOG_DEBUG(Service_NVDRV, "called");      IoctlActiveSlotMask params{}; @@ -127,10 +201,10 @@ u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector      params.slot = 0x07;      params.mask = 0x01;      std::memcpy(output.data(), ¶ms, output.size()); -    return 0; +    return NvResult::Success;  } -u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) {      LOG_DEBUG(Service_NVDRV, "called");      IoctlZcullGetCtxSize params{}; @@ -139,10 +213,10 @@ u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u      }      params.size = 0x1;      std::memcpy(output.data(), ¶ms, output.size()); -    return 0; +    return NvResult::Success;  } -u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) {      LOG_DEBUG(Service_NVDRV, "called");      IoctlNvgpuGpuZcullGetInfoArgs params{}; @@ -162,47 +236,47 @@ u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>&      params.subregion_height_align_pixels = 0x40;      params.subregion_count = 0x10;      std::memcpy(output.data(), ¶ms, output.size()); -    return 0; +    return NvResult::Success;  } -u32 nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output) {      LOG_WARNING(Service_NVDRV, "(STUBBED) called");      IoctlZbcSetTable params{};      std::memcpy(¶ms, input.data(), input.size());      // TODO(ogniK): What does this even actually do?      std::memcpy(output.data(), ¶ms, output.size()); -    return 0; +    return NvResult::Success;  } -u32 nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) {      LOG_WARNING(Service_NVDRV, "(STUBBED) called");      IoctlZbcQueryTable params{};      std::memcpy(¶ms, input.data(), input.size());      // TODO : To implement properly      std::memcpy(output.data(), ¶ms, output.size()); -    return 0; +    return NvResult::Success;  } -u32 nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) {      LOG_WARNING(Service_NVDRV, "(STUBBED) called");      IoctlFlushL2 params{};      std::memcpy(¶ms, input.data(), input.size());      // TODO : To implement properly      std::memcpy(output.data(), ¶ms, output.size()); -    return 0; +    return NvResult::Success;  } -u32 nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output) {      LOG_DEBUG(Service_NVDRV, "called");      IoctlGetGpuTime params{};      std::memcpy(¶ms, input.data(), input.size());      params.gpu_time = static_cast<u64_le>(system.CoreTiming().GetGlobalTimeNs().count());      std::memcpy(output.data(), ¶ms, output.size()); -    return 0; +    return NvResult::Success;  }  } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h index ef60f72ce..137b88238 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h @@ -16,32 +16,13 @@ public:      explicit nvhost_ctrl_gpu(Core::System& system);      ~nvhost_ctrl_gpu() override; -    u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -              std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -              IoctlVersion version) override; +    NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; +    NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, +                    const std::vector<u8>& inline_input, std::vector<u8>& output) override; +    NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, +                    std::vector<u8>& inline_output) override;  private: -    enum class IoctlCommand : u32_le { -        IocGetCharacteristicsCommand = 0xC0B04705, -        IocGetTPCMasksCommand = 0xC0184706, -        IocGetActiveSlotMaskCommand = 0x80084714, -        IocZcullGetCtxSizeCommand = 0x80044701, -        IocZcullGetInfo = 0x80284702, -        IocZbcSetTable = 0x402C4703, -        IocZbcQueryTable = 0xC0344704, -        IocFlushL2 = 0x40084707, -        IocInvalICache = 0x4008470D, -        IocSetMmudebugMode = 0x4008470E, -        IocSetSmDebugMode = 0x4010470F, -        IocWaitForPause = 0xC0084710, -        IocGetTcpExceptionEnStatus = 0x80084711, -        IocNumVsms = 0x80084712, -        IocVsmsMapping = 0xC0044713, -        IocGetErrorChannelUserData = 0xC008471B, -        IocGetGpuTime = 0xC010471C, -        IocGetCpuTimeCorrelationInfo = 0xC108471D, -    }; -      struct IoctlGpuCharacteristics {          u32_le arch;                       // 0x120 (NVGPU_GPU_ARCH_GM200)          u32_le impl;                       // 0xB (NVGPU_GPU_IMPL_GM20B) @@ -159,17 +140,21 @@ private:      };      static_assert(sizeof(IoctlGetGpuTime) == 0x10, "IoctlGetGpuTime is incorrect size"); -    u32 GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output, -                           std::vector<u8>& output2, IoctlVersion version); -    u32 GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output, std::vector<u8>& output2, -                    IoctlVersion version); -    u32 GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output); -    u32 ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output); -    u32 ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output); -    u32 ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output); -    u32 ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output); -    u32 FlushL2(const std::vector<u8>& input, std::vector<u8>& output); -    u32 GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output, +                                std::vector<u8>& inline_output); + +    NvResult GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output, +                         std::vector<u8>& inline_output); + +    NvResult GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult FlushL2(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output);  };  } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index b1d9d55b5..af8b3d9f1 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -23,107 +23,132 @@ nvhost_gpu::nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,  nvhost_gpu::~nvhost_gpu() = default; -u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -                      std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -                      IoctlVersion version) { -    LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", -              command.raw, input.size(), output.size()); - -    switch (static_cast<IoctlCommand>(command.raw)) { -    case IoctlCommand::IocSetNVMAPfdCommand: -        return SetNVMAPfd(input, output); -    case IoctlCommand::IocSetClientDataCommand: -        return SetClientData(input, output); -    case IoctlCommand::IocGetClientDataCommand: -        return GetClientData(input, output); -    case IoctlCommand::IocZCullBind: -        return ZCullBind(input, output); -    case IoctlCommand::IocSetErrorNotifierCommand: -        return SetErrorNotifier(input, output); -    case IoctlCommand::IocChannelSetPriorityCommand: -        return SetChannelPriority(input, output); -    case IoctlCommand::IocAllocGPFIFOEx2Command: -        return AllocGPFIFOEx2(input, output); -    case IoctlCommand::IocAllocObjCtxCommand: -        return AllocateObjectContext(input, output); -    case IoctlCommand::IocChannelGetWaitbaseCommand: -        return GetWaitbase(input, output); -    case IoctlCommand::IocChannelSetTimeoutCommand: -        return ChannelSetTimeout(input, output); -    case IoctlCommand::IocChannelSetTimeslice: -        return ChannelSetTimeslice(input, output); -    default: +NvResult nvhost_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { +    switch (command.group) { +    case 0x0: +        switch (command.cmd) { +        case 0x3: +            return GetWaitbase(input, output); +        default: +            break; +        } +        break; +    case 'H': +        switch (command.cmd) { +        case 0x1: +            return SetNVMAPfd(input, output); +        case 0x3: +            return ChannelSetTimeout(input, output); +        case 0x8: +            return SubmitGPFIFOBase(input, output, false); +        case 0x9: +            return AllocateObjectContext(input, output); +        case 0xb: +            return ZCullBind(input, output); +        case 0xc: +            return SetErrorNotifier(input, output); +        case 0xd: +            return SetChannelPriority(input, output); +        case 0x1a: +            return AllocGPFIFOEx2(input, output); +        case 0x1b: +            return SubmitGPFIFOBase(input, output, true); +        case 0x1d: +            return ChannelSetTimeslice(input, output); +        default: +            break; +        } +        break; +    case 'G': +        switch (command.cmd) { +        case 0x14: +            return SetClientData(input, output); +        case 0x15: +            return GetClientData(input, output); +        default: +            break; +        }          break;      } +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented; +}; -    if (command.group == NVGPU_IOCTL_MAGIC) { -        if (command.cmd == NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO) { -            return SubmitGPFIFO(input, output); -        } -        if (command.cmd == NVGPU_IOCTL_CHANNEL_KICKOFF_PB) { -            return KickoffPB(input, output, input2, version); +NvResult nvhost_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input, +                            const std::vector<u8>& inline_input, std::vector<u8>& output) { +    switch (command.group) { +    case 'H': +        switch (command.cmd) { +        case 0x1b: +            return SubmitGPFIFOBase(input, inline_input, output);          } +        break;      } +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented; +} -    UNIMPLEMENTED_MSG("Unimplemented ioctl"); -    return 0; -}; +NvResult nvhost_gpu::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; +} -u32 nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlSetNvmapFD params{};      std::memcpy(¶ms, input.data(), input.size());      LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);      nvmap_fd = params.nvmap_fd; -    return 0; +    return NvResult::Success;  } -u32 nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& output) {      LOG_DEBUG(Service_NVDRV, "called");      IoctlClientData params{};      std::memcpy(¶ms, input.data(), input.size());      user_data = params.data; -    return 0; +    return NvResult::Success;  } -u32 nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& output) {      LOG_DEBUG(Service_NVDRV, "called");      IoctlClientData params{};      std::memcpy(¶ms, input.data(), input.size());      params.data = user_data;      std::memcpy(output.data(), ¶ms, output.size()); -    return 0; +    return NvResult::Success;  } -u32 nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& output) {      std::memcpy(&zcull_params, input.data(), input.size());      LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va,                zcull_params.mode);      std::memcpy(output.data(), &zcull_params, output.size()); -    return 0; +    return NvResult::Success;  } -u32 nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlSetErrorNotifier params{};      std::memcpy(¶ms, input.data(), input.size());      LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset,                  params.size, params.mem);      std::memcpy(output.data(), ¶ms, output.size()); -    return 0; +    return NvResult::Success;  } -u32 nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) {      std::memcpy(&channel_priority, input.data(), input.size());      LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority); -    return 0; +    return NvResult::Success;  } -u32 nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlAllocGpfifoEx2 params{};      std::memcpy(¶ms, input.data(), input.size());      LOG_WARNING(Service_NVDRV, @@ -137,10 +162,10 @@ u32 nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& ou      params.fence_out = channel_fence;      std::memcpy(output.data(), ¶ms, output.size()); -    return 0; +    return NvResult::Success;  } -u32 nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlAllocObjCtx params{};      std::memcpy(¶ms, input.data(), input.size());      LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num, @@ -148,7 +173,7 @@ u32 nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<      params.obj_id = 0x0;      std::memcpy(output.data(), ¶ms, output.size()); -    return 0; +    return NvResult::Success;  }  static std::vector<Tegra::CommandHeader> BuildWaitCommandList(Fence fence) { @@ -192,8 +217,8 @@ static std::vector<Tegra::CommandHeader> BuildIncrementWithWfiCommandList(Fence      return result;  } -u32 nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output, -                                 Tegra::CommandList&& entries) { +NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output, +                                      Tegra::CommandList&& entries) {      LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address,                params.num_entries, params.flags.raw); @@ -227,69 +252,70 @@ u32 nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& out      }      std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmitGpfifo)); -    return 0; +    return NvResult::Success;  } -u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_gpu::SubmitGPFIFOBase(const std::vector<u8>& input, std::vector<u8>& output, +                                      bool kickoff) {      if (input.size() < sizeof(IoctlSubmitGpfifo)) {          UNIMPLEMENTED(); +        return NvResult::InvalidSize;      }      IoctlSubmitGpfifo params{};      std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo)); -      Tegra::CommandList entries(params.num_entries); -    std::memcpy(entries.command_lists.data(), &input[sizeof(IoctlSubmitGpfifo)], -                params.num_entries * sizeof(Tegra::CommandListHeader)); + +    if (kickoff) { +        system.Memory().ReadBlock(params.address, entries.command_lists.data(), +                                  params.num_entries * sizeof(Tegra::CommandListHeader)); +    } else { +        std::memcpy(entries.command_lists.data(), &input[sizeof(IoctlSubmitGpfifo)], +                    params.num_entries * sizeof(Tegra::CommandListHeader)); +    }      return SubmitGPFIFOImpl(params, output, std::move(entries));  } -u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output, -                          const std::vector<u8>& input2, IoctlVersion version) { +NvResult nvhost_gpu::SubmitGPFIFOBase(const std::vector<u8>& input, +                                      const std::vector<u8>& input_inline, +                                      std::vector<u8>& output) {      if (input.size() < sizeof(IoctlSubmitGpfifo)) {          UNIMPLEMENTED(); +        return NvResult::InvalidSize;      }      IoctlSubmitGpfifo params{};      std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo)); -      Tegra::CommandList entries(params.num_entries); -    if (version == IoctlVersion::Version2) { -        std::memcpy(entries.command_lists.data(), input2.data(), -                    params.num_entries * sizeof(Tegra::CommandListHeader)); -    } else { -        system.Memory().ReadBlock(params.address, entries.command_lists.data(), -                                  params.num_entries * sizeof(Tegra::CommandListHeader)); -    } - +    std::memcpy(entries.command_lists.data(), input_inline.data(), input_inline.size());      return SubmitGPFIFOImpl(params, output, std::move(entries));  } -u32 nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlGetWaitbase params{};      std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase));      LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);      params.value = 0; // Seems to be hard coded at 0      std::memcpy(output.data(), ¶ms, output.size()); -    return 0; +    return NvResult::Success;  } -u32 nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlChannelSetTimeout params{};      std::memcpy(¶ms, input.data(), sizeof(IoctlChannelSetTimeout));      LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout); -    return 0; +    return NvResult::Success;  } -u32 nvhost_gpu::ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_gpu::ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlSetTimeslice params{};      std::memcpy(¶ms, input.data(), sizeof(IoctlSetTimeslice));      LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice);      channel_timeslice = params.timeslice; -    return 0; +    return NvResult::Success;  }  } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h index a252fc06d..e0298b4fe 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h @@ -20,43 +20,19 @@ class SyncpointManager;  namespace Service::Nvidia::Devices {  class nvmap; -constexpr u32 NVGPU_IOCTL_MAGIC('H'); -constexpr u32 NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO(0x8); -constexpr u32 NVGPU_IOCTL_CHANNEL_KICKOFF_PB(0x1b); -  class nvhost_gpu final : public nvdevice {  public:      explicit nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,                          SyncpointManager& syncpoint_manager);      ~nvhost_gpu() override; -    u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -              std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -              IoctlVersion version) override; +    NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; +    NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, +                    const std::vector<u8>& inline_input, std::vector<u8>& output) override; +    NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, +                    std::vector<u8>& inline_output) override;  private: -    enum class IoctlCommand : u32_le { -        IocSetNVMAPfdCommand = 0x40044801, -        IocAllocGPFIFOCommand = 0x40084805, -        IocSetClientDataCommand = 0x40084714, -        IocGetClientDataCommand = 0x80084715, -        IocZCullBind = 0xc010480b, -        IocSetErrorNotifierCommand = 0xC018480C, -        IocChannelSetPriorityCommand = 0x4004480D, -        IocEnableCommand = 0x0000480E, -        IocDisableCommand = 0x0000480F, -        IocPreemptCommand = 0x00004810, -        IocForceResetCommand = 0x00004811, -        IocEventIdControlCommand = 0x40084812, -        IocGetErrorNotificationCommand = 0xC0104817, -        IocAllocGPFIFOExCommand = 0x40204818, -        IocAllocGPFIFOEx2Command = 0xC020481A, -        IocAllocObjCtxCommand = 0xC0104809, -        IocChannelGetWaitbaseCommand = 0xC0080003, -        IocChannelSetTimeoutCommand = 0x40044803, -        IocChannelSetTimeslice = 0xC004481D, -    }; -      enum class CtxObjects : u32_le {          Ctx2D = 0x902D,          Ctx3D = 0xB197, @@ -67,63 +43,63 @@ private:      };      struct IoctlSetNvmapFD { -        u32_le nvmap_fd; +        s32_le nvmap_fd{};      };      static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");      struct IoctlChannelSetTimeout { -        u32_le timeout; +        u32_le timeout{};      };      static_assert(sizeof(IoctlChannelSetTimeout) == 4, "IoctlChannelSetTimeout is incorrect size");      struct IoctlAllocGPFIFO { -        u32_le num_entries; -        u32_le flags; +        u32_le num_entries{}; +        u32_le flags{};      };      static_assert(sizeof(IoctlAllocGPFIFO) == 8, "IoctlAllocGPFIFO is incorrect size");      struct IoctlClientData { -        u64_le data; +        u64_le data{};      };      static_assert(sizeof(IoctlClientData) == 8, "IoctlClientData is incorrect size");      struct IoctlZCullBind { -        u64_le gpu_va; -        u32_le mode; // 0=global, 1=no_ctxsw, 2=separate_buffer, 3=part_of_regular_buf +        u64_le gpu_va{}; +        u32_le mode{}; // 0=global, 1=no_ctxsw, 2=separate_buffer, 3=part_of_regular_buf          INSERT_PADDING_WORDS(1);      };      static_assert(sizeof(IoctlZCullBind) == 16, "IoctlZCullBind is incorrect size");      struct IoctlSetErrorNotifier { -        u64_le offset; -        u64_le size; -        u32_le mem; // nvmap object handle +        u64_le offset{}; +        u64_le size{}; +        u32_le mem{}; // nvmap object handle          INSERT_PADDING_WORDS(1);      };      static_assert(sizeof(IoctlSetErrorNotifier) == 24, "IoctlSetErrorNotifier is incorrect size");      struct IoctlChannelSetPriority { -        u32_le priority; +        u32_le priority{};      };      static_assert(sizeof(IoctlChannelSetPriority) == 4,                    "IoctlChannelSetPriority is incorrect size");      struct IoctlSetTimeslice { -        u32_le timeslice; +        u32_le timeslice{};      };      static_assert(sizeof(IoctlSetTimeslice) == 4, "IoctlSetTimeslice is incorrect size");      struct IoctlEventIdControl { -        u32_le cmd; // 0=disable, 1=enable, 2=clear -        u32_le id; +        u32_le cmd{}; // 0=disable, 1=enable, 2=clear +        u32_le id{};      };      static_assert(sizeof(IoctlEventIdControl) == 8, "IoctlEventIdControl is incorrect size");      struct IoctlGetErrorNotification { -        u64_le timestamp; -        u32_le info32; -        u16_le info16; -        u16_le status; // always 0xFFFF +        u64_le timestamp{}; +        u32_le info32{}; +        u16_le info16{}; +        u16_le status{}; // always 0xFFFF      };      static_assert(sizeof(IoctlGetErrorNotification) == 16,                    "IoctlGetErrorNotification is incorrect size"); @@ -131,39 +107,39 @@ private:      static_assert(sizeof(Fence) == 8, "Fence is incorrect size");      struct IoctlAllocGpfifoEx { -        u32_le num_entries; -        u32_le flags; -        u32_le unk0; -        u32_le unk1; -        u32_le unk2; -        u32_le unk3; -        u32_le unk4; -        u32_le unk5; +        u32_le num_entries{}; +        u32_le flags{}; +        u32_le unk0{}; +        u32_le unk1{}; +        u32_le unk2{}; +        u32_le unk3{}; +        u32_le unk4{}; +        u32_le unk5{};      };      static_assert(sizeof(IoctlAllocGpfifoEx) == 32, "IoctlAllocGpfifoEx is incorrect size");      struct IoctlAllocGpfifoEx2 { -        u32_le num_entries; // in -        u32_le flags;       // in -        u32_le unk0;        // in (1 works) -        Fence fence_out;    // out -        u32_le unk1;        // in -        u32_le unk2;        // in -        u32_le unk3;        // in +        u32_le num_entries{}; // in +        u32_le flags{};       // in +        u32_le unk0{};        // in (1 works) +        Fence fence_out{};    // out +        u32_le unk1{};        // in +        u32_le unk2{};        // in +        u32_le unk3{};        // in      };      static_assert(sizeof(IoctlAllocGpfifoEx2) == 32, "IoctlAllocGpfifoEx2 is incorrect size");      struct IoctlAllocObjCtx { -        u32_le class_num; // 0x902D=2d, 0xB197=3d, 0xB1C0=compute, 0xA140=kepler, 0xB0B5=DMA, -                          // 0xB06F=channel_gpfifo -        u32_le flags; -        u64_le obj_id; // (ignored) used for FREE_OBJ_CTX ioctl, which is not supported +        u32_le class_num{}; // 0x902D=2d, 0xB197=3d, 0xB1C0=compute, 0xA140=kepler, 0xB0B5=DMA, +                            // 0xB06F=channel_gpfifo +        u32_le flags{}; +        u64_le obj_id{}; // (ignored) used for FREE_OBJ_CTX ioctl, which is not supported      };      static_assert(sizeof(IoctlAllocObjCtx) == 16, "IoctlAllocObjCtx is incorrect size");      struct IoctlSubmitGpfifo { -        u64_le address;     // pointer to gpfifo entry structs -        u32_le num_entries; // number of fence objects being submitted +        u64_le address{};     // pointer to gpfifo entry structs +        u32_le num_entries{}; // number of fence objects being submitted          union {              u32_le raw;              BitField<0, 1, u32_le> add_wait;      // append a wait sync_point to the list @@ -172,7 +148,7 @@ private:              BitField<4, 1, u32_le> suppress_wfi;  // suppress wait for interrupt              BitField<8, 1, u32_le> increment;     // increment the returned fence          } flags; -        Fence fence_out; // returned new fence object for others to wait on +        Fence fence_out{}; // returned new fence object for others to wait on          u32 AddIncrementValue() const {              return flags.add_increment.Value() << 1; @@ -182,33 +158,34 @@ private:                    "IoctlSubmitGpfifo is incorrect size");      struct IoctlGetWaitbase { -        u32 unknown; // seems to be ignored? Nintendo added this -        u32 value; +        u32 unknown{}; // seems to be ignored? Nintendo added this +        u32 value{};      };      static_assert(sizeof(IoctlGetWaitbase) == 8, "IoctlGetWaitbase is incorrect size"); -    u32_le nvmap_fd{}; +    s32_le nvmap_fd{};      u64_le user_data{};      IoctlZCullBind zcull_params{};      u32_le channel_priority{};      u32_le channel_timeslice{}; -    u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output); -    u32 SetClientData(const std::vector<u8>& input, std::vector<u8>& output); -    u32 GetClientData(const std::vector<u8>& input, std::vector<u8>& output); -    u32 ZCullBind(const std::vector<u8>& input, std::vector<u8>& output); -    u32 SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output); -    u32 SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output); -    u32 AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output); -    u32 AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output); -    u32 SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output, -                         Tegra::CommandList&& entries); -    u32 SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output); -    u32 KickoffPB(const std::vector<u8>& input, std::vector<u8>& output, -                  const std::vector<u8>& input2, IoctlVersion version); -    u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); -    u32 ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output); -    u32 ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult SetClientData(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult GetClientData(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult ZCullBind(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output, +                              Tegra::CommandList&& entries); +    NvResult SubmitGPFIFOBase(const std::vector<u8>& input, std::vector<u8>& output, +                              bool kickoff = false); +    NvResult SubmitGPFIFOBase(const std::vector<u8>& input, const std::vector<u8>& input_inline, +                              std::vector<u8>& output); +    NvResult GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output);      std::shared_ptr<nvmap> nvmap_dev;      SyncpointManager& syncpoint_manager; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index b6df48360..d8735491c 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp @@ -15,46 +15,58 @@ nvhost_nvdec::nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_de      : nvhost_nvdec_common(system, std::move(nvmap_dev)) {}  nvhost_nvdec::~nvhost_nvdec() = default; -u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -                        std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -                        IoctlVersion version) { -    LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", -              command.raw, input.size(), output.size()); - -    switch (static_cast<IoctlCommand>(command.raw)) { -    case IoctlCommand::IocSetNVMAPfdCommand: -        return SetNVMAPfd(input); -    case IoctlCommand::IocSubmit: -        return Submit(input, output); -    case IoctlCommand::IocGetSyncpoint: -        return GetSyncpoint(input, output); -    case IoctlCommand::IocGetWaitbase: -        return GetWaitbase(input, output); -    case IoctlCommand::IocMapBuffer: -    case IoctlCommand::IocMapBuffer2: -    case IoctlCommand::IocMapBuffer3: -    case IoctlCommand::IocMapBufferEx: -        return MapBuffer(input, output); -    case IoctlCommand::IocUnmapBufferEx: { -        // This command is sent when the video stream has ended, flush all video contexts -        // This is usually sent in the folowing order: vic, nvdec, vic. -        // Inform the GPU to clear any remaining nvdec buffers when this is detected. -        LOG_INFO(Service_NVDRV, "NVDEC video stream ended"); -        Tegra::ChCommandHeaderList cmdlist(1); -        cmdlist[0] = Tegra::ChCommandHeader{0xDEADB33F}; -        system.GPU().PushCommandBuffer(cmdlist); -        [[fallthrough]]; // fallthrough to unmap buffers -    }; -    case IoctlCommand::IocUnmapBuffer: -    case IoctlCommand::IocUnmapBuffer2: -    case IoctlCommand::IocUnmapBuffer3: -        return UnmapBuffer(input, output); -    case IoctlCommand::IocSetSubmitTimeout: -        return SetSubmitTimeout(input, output); +NvResult nvhost_nvdec::Ioctl1(Ioctl command, const std::vector<u8>& input, +                              std::vector<u8>& output) { +    switch (command.group) { +    case 0x0: +        switch (command.cmd) { +        case 0x1: +            return Submit(input, output); +        case 0x2: +            return GetSyncpoint(input, output); +        case 0x3: +            return GetWaitbase(input, output); +        case 0x7: +            return SetSubmitTimeout(input, output); +        case 0x9: +            return MapBuffer(input, output); +        case 0xa: { +            if (command.length == 0x1c) { +                LOG_INFO(Service_NVDRV, "NVDEC video stream ended"); +                Tegra::ChCommandHeaderList cmdlist(1); +                cmdlist[0] = Tegra::ChCommandHeader{0xDEADB33F}; +                system.GPU().PushCommandBuffer(cmdlist); +            } +            return UnmapBuffer(input, output); +        } +        default: +            break; +        } +        break; +    case 'H': +        switch (command.cmd) { +        case 0x1: +            return SetNVMAPfd(input); +        default: +            break; +        } +        break;      } -    UNIMPLEMENTED_MSG("Unimplemented ioctl 0x{:X}", command.raw); -    return 0; +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented; +} + +NvResult nvhost_nvdec::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 nvhost_nvdec::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;  }  } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h index 102777ddd..79b8b6de1 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h @@ -14,26 +14,11 @@ public:      explicit nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);      ~nvhost_nvdec() override; -    u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -              std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -              IoctlVersion version) override; - -private: -    enum class IoctlCommand : u32_le { -        IocSetNVMAPfdCommand = 0x40044801, -        IocSubmit = 0xC0400001, -        IocGetSyncpoint = 0xC0080002, -        IocGetWaitbase = 0xC0080003, -        IocMapBuffer = 0xC01C0009, -        IocMapBuffer2 = 0xC16C0009, -        IocMapBuffer3 = 0xC15C0009, -        IocMapBufferEx = 0xC0A40009, -        IocUnmapBuffer = 0xC0A4000A, -        IocUnmapBuffer2 = 0xC16C000A, -        IocUnmapBufferEx = 0xC01C000A, -        IocUnmapBuffer3 = 0xC15C000A, -        IocSetSubmitTimeout = 0x40040007, -    }; +    NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; +    NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, +                    const std::vector<u8>& inline_input, std::vector<u8>& output) override; +    NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, +                    std::vector<u8>& inline_output) override;  };  } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp index 30f03f845..b49cecb42 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp @@ -36,26 +36,20 @@ std::size_t WriteVectors(std::vector<u8>& dst, const std::vector<T>& src, std::s  }  } // Anonymous namespace -namespace NvErrCodes { -constexpr u32 Success{}; -[[maybe_unused]] constexpr u32 OutOfMemory{static_cast<u32>(-12)}; -constexpr u32 InvalidInput{static_cast<u32>(-22)}; -} // namespace NvErrCodes -  nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system, std::shared_ptr<nvmap> nvmap_dev)      : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}  nvhost_nvdec_common::~nvhost_nvdec_common() = default; -u32 nvhost_nvdec_common::SetNVMAPfd(const std::vector<u8>& input) { +NvResult nvhost_nvdec_common::SetNVMAPfd(const std::vector<u8>& input) {      IoctlSetNvmapFD params{};      std::memcpy(¶ms, input.data(), sizeof(IoctlSetNvmapFD));      LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);      nvmap_fd = params.nvmap_fd; -    return 0; +    return NvResult::Success;  } -u32 nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlSubmit params{};      std::memcpy(¶ms, input.data(), sizeof(IoctlSubmit));      LOG_DEBUG(Service_NVDRV, "called NVDEC Submit, cmd_buffer_count={}", params.cmd_buffer_count); @@ -83,12 +77,12 @@ u32 nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& o      for (const auto& cmd_buffer : command_buffers) {          auto object = nvmap_dev->GetObject(cmd_buffer.memory_id); -        ASSERT_OR_EXECUTE(object, return NvErrCodes::InvalidInput;); +        ASSERT_OR_EXECUTE(object, return NvResult::InvalidState;);          const auto map = FindBufferMap(object->dma_map_addr);          if (!map) {              LOG_ERROR(Service_NVDRV, "Tried to submit an invalid offset 0x{:X} dma 0x{:X}",                        object->addr, object->dma_map_addr); -            return 0; +            return NvResult::Success;          }          Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count);          gpu.MemoryManager().ReadBlock(map->StartAddr() + cmd_buffer.offset, cmdlist.data(), @@ -105,10 +99,10 @@ u32 nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& o      offset = WriteVectors(output, syncpt_increments, offset);      offset = WriteVectors(output, wait_checks, offset); -    return NvErrCodes::Success; +    return NvResult::Success;  } -u32 nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlGetSyncpoint params{};      std::memcpy(¶ms, input.data(), sizeof(IoctlGetSyncpoint));      LOG_DEBUG(Service_NVDRV, "called GetSyncpoint, id={}", params.param); @@ -118,18 +112,18 @@ u32 nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::vector<      params.value = 0;      std::memcpy(output.data(), ¶ms, sizeof(IoctlGetSyncpoint)); -    return NvErrCodes::Success; +    return NvResult::Success;  } -u32 nvhost_nvdec_common::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_nvdec_common::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlGetWaitbase params{};      std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase));      params.value = 0; // Seems to be hard coded at 0      std::memcpy(output.data(), ¶ms, sizeof(IoctlGetWaitbase)); -    return 0; +    return NvResult::Success;  } -u32 nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlMapBuffer params{};      std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer));      std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries); @@ -143,7 +137,7 @@ u32 nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8>          if (!object) {              LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmf_buff.map_handle);              std::memcpy(output.data(), ¶ms, output.size()); -            return NvErrCodes::InvalidInput; +            return NvResult::InvalidState;          }          if (object->dma_map_addr == 0) {              // NVDEC and VIC memory is in the 32-bit address space @@ -165,10 +159,10 @@ u32 nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8>      std::memcpy(output.data() + sizeof(IoctlMapBuffer), cmd_buffer_handles.data(),                  cmd_buffer_handles.size() * sizeof(MapBufferEntry)); -    return NvErrCodes::Success; +    return NvResult::Success;  } -u32 nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlMapBuffer params{};      std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer));      std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries); @@ -181,7 +175,7 @@ u32 nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u          if (!object) {              LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmf_buff.map_handle);              std::memcpy(output.data(), ¶ms, output.size()); -            return NvErrCodes::InvalidInput; +            return NvResult::InvalidState;          }          if (const auto size{RemoveBufferMap(object->dma_map_addr)}; size) {              gpu.MemoryManager().Unmap(object->dma_map_addr, *size); @@ -193,13 +187,14 @@ u32 nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u          object->dma_map_addr = 0;      }      std::memset(output.data(), 0, output.size()); -    return NvErrCodes::Success; +    return NvResult::Success;  } -u32 nvhost_nvdec_common::SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_nvdec_common::SetSubmitTimeout(const std::vector<u8>& input, +                                               std::vector<u8>& output) {      std::memcpy(&submit_timeout, input.data(), input.size());      LOG_WARNING(Service_NVDRV, "(STUBBED) called"); -    return NvErrCodes::Success; +    return NvResult::Success;  }  std::optional<nvhost_nvdec_common::BufferMap> nvhost_nvdec_common::FindBufferMap( diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h index c249c5349..86ba3a4d1 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h @@ -18,9 +18,37 @@ public:      explicit nvhost_nvdec_common(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);      ~nvhost_nvdec_common() override; -    virtual u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -                      std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -                      IoctlVersion version) = 0; +    /** +     * Handles an ioctl1 request. +     * @param command The ioctl command id. +     * @param input A buffer containing the input data for the ioctl. +     * @param output A buffer where the output data will be written to. +     * @returns The result code of the ioctl. +     */ +    virtual NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, +                            std::vector<u8>& output) = 0; + +    /** +     * Handles an ioctl2 request. +     * @param command The ioctl command id. +     * @param input A buffer containing the input data for the ioctl. +     * @param inline_input A buffer containing the input data for the ioctl which has been inlined. +     * @param output A buffer where the output data will be written to. +     * @returns The result code of the ioctl. +     */ +    virtual NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, +                            const std::vector<u8>& inline_input, std::vector<u8>& output) = 0; + +    /** +     * Handles an ioctl3 request. +     * @param command The ioctl command id. +     * @param input A buffer containing the input data for the ioctl. +     * @param output A buffer where the output data will be written to. +     * @param inline_output A buffer where the inlined output data will be written to. +     * @returns The result code of the ioctl. +     */ +    virtual NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, +                            std::vector<u8>& inline_output) = 0;  protected:      class BufferMap final { @@ -63,102 +91,102 @@ protected:      };      struct IoctlSetNvmapFD { -        u32_le nvmap_fd; +        s32_le nvmap_fd{};      };      static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");      struct IoctlSubmitCommandBuffer { -        u32_le id; -        u32_le offset; -        u32_le count; +        u32_le id{}; +        u32_le offset{}; +        u32_le count{};      };      static_assert(sizeof(IoctlSubmitCommandBuffer) == 0xC,                    "IoctlSubmitCommandBuffer is incorrect size");      struct IoctlSubmit { -        u32_le cmd_buffer_count; -        u32_le relocation_count; -        u32_le syncpoint_count; -        u32_le fence_count; +        u32_le cmd_buffer_count{}; +        u32_le relocation_count{}; +        u32_le syncpoint_count{}; +        u32_le fence_count{};      };      static_assert(sizeof(IoctlSubmit) == 0x10, "IoctlSubmit has incorrect size");      struct CommandBuffer { -        s32 memory_id; -        u32 offset; -        s32 word_count; +        s32 memory_id{}; +        u32 offset{}; +        s32 word_count{};      };      static_assert(sizeof(CommandBuffer) == 0xC, "CommandBuffer has incorrect size");      struct Reloc { -        s32 cmdbuffer_memory; -        s32 cmdbuffer_offset; -        s32 target; -        s32 target_offset; +        s32 cmdbuffer_memory{}; +        s32 cmdbuffer_offset{}; +        s32 target{}; +        s32 target_offset{};      };      static_assert(sizeof(Reloc) == 0x10, "CommandBuffer has incorrect size");      struct SyncptIncr { -        u32 id; -        u32 increments; +        u32 id{}; +        u32 increments{};      };      static_assert(sizeof(SyncptIncr) == 0x8, "CommandBuffer has incorrect size");      struct Fence { -        u32 id; -        u32 value; +        u32 id{}; +        u32 value{};      };      static_assert(sizeof(Fence) == 0x8, "CommandBuffer has incorrect size");      struct IoctlGetSyncpoint {          // Input -        u32_le param; +        u32_le param{};          // Output -        u32_le value; +        u32_le value{};      };      static_assert(sizeof(IoctlGetSyncpoint) == 8, "IocGetIdParams has wrong size");      struct IoctlGetWaitbase { -        u32_le unknown; // seems to be ignored? Nintendo added this -        u32_le value; +        u32_le unknown{}; // seems to be ignored? Nintendo added this +        u32_le value{};      };      static_assert(sizeof(IoctlGetWaitbase) == 0x8, "IoctlGetWaitbase is incorrect size");      struct IoctlMapBuffer { -        u32_le num_entries; -        u32_le data_address; // Ignored by the driver. -        u32_le attach_host_ch_das; +        u32_le num_entries{}; +        u32_le data_address{}; // Ignored by the driver. +        u32_le attach_host_ch_das{};      };      static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size");      struct IocGetIdParams {          // Input -        u32_le param; +        u32_le param{};          // Output -        u32_le value; +        u32_le value{};      };      static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size");      // Used for mapping and unmapping command buffers      struct MapBufferEntry { -        u32_le map_handle; -        u32_le map_address; +        u32_le map_handle{}; +        u32_le map_address{};      };      static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size");      /// Ioctl command implementations -    u32 SetNVMAPfd(const std::vector<u8>& input); -    u32 Submit(const std::vector<u8>& input, std::vector<u8>& output); -    u32 GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output); -    u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); -    u32 MapBuffer(const std::vector<u8>& input, std::vector<u8>& output); -    u32 UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output); -    u32 SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult SetNVMAPfd(const std::vector<u8>& input); +    NvResult Submit(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult MapBuffer(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output);      std::optional<BufferMap> FindBufferMap(GPUVAddr gpu_addr) const;      void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated);      std::optional<std::size_t> RemoveBufferMap(GPUVAddr gpu_addr); -    u32_le nvmap_fd{}; +    s32_le nvmap_fd{};      u32_le submit_timeout{};      std::shared_ptr<nvmap> nvmap_dev; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp index 96e7b7dab..2d06955c0 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp @@ -13,28 +13,44 @@ namespace Service::Nvidia::Devices {  nvhost_nvjpg::nvhost_nvjpg(Core::System& system) : nvdevice(system) {}  nvhost_nvjpg::~nvhost_nvjpg() = default; -u32 nvhost_nvjpg::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -                        std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -                        IoctlVersion version) { -    LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", -              command.raw, input.size(), output.size()); - -    switch (static_cast<IoctlCommand>(command.raw)) { -    case IoctlCommand::IocSetNVMAPfdCommand: -        return SetNVMAPfd(input, output); +NvResult nvhost_nvjpg::Ioctl1(Ioctl command, const std::vector<u8>& input, +                              std::vector<u8>& output) { +    switch (command.group) { +    case 'H': +        switch (command.cmd) { +        case 0x1: +            return SetNVMAPfd(input, output); +        default: +            break; +        } +        break; +    default: +        break;      } -    UNIMPLEMENTED_MSG("Unimplemented ioctl"); -    return 0; +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented;  } -u32 nvhost_nvjpg::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvhost_nvjpg::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 nvhost_nvjpg::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; +} + +NvResult nvhost_nvjpg::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {      IoctlSetNvmapFD params{};      std::memcpy(¶ms, input.data(), input.size());      LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);      nvmap_fd = params.nvmap_fd; -    return 0; +    return NvResult::Success;  }  } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h index 98dcac52f..43948d18d 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h @@ -16,23 +16,21 @@ public:      explicit nvhost_nvjpg(Core::System& system);      ~nvhost_nvjpg() override; -    u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -              std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -              IoctlVersion version) override; +    NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; +    NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, +                    const std::vector<u8>& inline_input, std::vector<u8>& output) override; +    NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, +                    std::vector<u8>& inline_output) override;  private: -    enum class IoctlCommand : u32_le { -        IocSetNVMAPfdCommand = 0x40044801, -    }; -      struct IoctlSetNvmapFD { -        u32_le nvmap_fd; +        s32_le nvmap_fd{};      };      static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size"); -    u32_le nvmap_fd{}; +    s32_le nvmap_fd{}; -    u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);  };  } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp index 60db54d00..805fe86ae 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp @@ -15,36 +15,50 @@ nvhost_vic::nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev)  nvhost_vic::~nvhost_vic() = default; -u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -                      std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -                      IoctlVersion version) { -    LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", -              command.raw, input.size(), output.size()); - -    switch (static_cast<IoctlCommand>(command.raw)) { -    case IoctlCommand::IocSetNVMAPfdCommand: -        return SetNVMAPfd(input); -    case IoctlCommand::IocSubmit: -        return Submit(input, output); -    case IoctlCommand::IocGetSyncpoint: -        return GetSyncpoint(input, output); -    case IoctlCommand::IocGetWaitbase: -        return GetWaitbase(input, output); -    case IoctlCommand::IocMapBuffer: -    case IoctlCommand::IocMapBuffer2: -    case IoctlCommand::IocMapBuffer3: -    case IoctlCommand::IocMapBuffer4: -    case IoctlCommand::IocMapBufferEx: -        return MapBuffer(input, output); -    case IoctlCommand::IocUnmapBuffer: -    case IoctlCommand::IocUnmapBuffer2: -    case IoctlCommand::IocUnmapBuffer3: -    case IoctlCommand::IocUnmapBufferEx: -        return UnmapBuffer(input, output); +NvResult nvhost_vic::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { +    switch (command.group) { +    case 0x0: +        switch (command.cmd) { +        case 0x1: +            return Submit(input, output); +        case 0x2: +            return GetSyncpoint(input, output); +        case 0x3: +            return GetWaitbase(input, output); +        case 0x9: +            return MapBuffer(input, output); +        case 0xa: +            return UnmapBuffer(input, output); +        default: +            break; +        } +        break; +    case 'H': +        switch (command.cmd) { +        case 0x1: +            return SetNVMAPfd(input); +        default: +            break; +        } +        break; +    default: +        break;      } -    UNIMPLEMENTED_MSG("Unimplemented ioctl 0x{:X}", command.raw); -    return 0; +    UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); +    return NvResult::NotImplemented; +} + +NvResult nvhost_vic::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 nvhost_vic::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;  }  } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h index f975b190c..b2e11f4d4 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h @@ -13,25 +13,11 @@ class nvhost_vic final : public nvhost_nvdec_common {  public:      explicit nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);      ~nvhost_vic(); -    u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -              std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -              IoctlVersion version) override; -private: -    enum class IoctlCommand : u32_le { -        IocSetNVMAPfdCommand = 0x40044801, -        IocSubmit = 0xC0400001, -        IocGetSyncpoint = 0xC0080002, -        IocGetWaitbase = 0xC0080003, -        IocMapBuffer = 0xC01C0009, -        IocMapBuffer2 = 0xC0340009, -        IocMapBuffer3 = 0xC0140009, -        IocMapBuffer4 = 0xC00C0009, -        IocMapBufferEx = 0xC03C0009, -        IocUnmapBuffer = 0xC03C000A, -        IocUnmapBuffer2 = 0xC034000A, -        IocUnmapBuffer3 = 0xC00C000A, -        IocUnmapBufferEx = 0xC01C000A, -    }; +    NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; +    NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, +                    const std::vector<u8>& inline_input, std::vector<u8>& output) override; +    NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, +                    std::vector<u8>& inline_output) override;  };  } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index 9436e16ad..4015a2740 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp @@ -11,13 +11,6 @@  namespace Service::Nvidia::Devices { -namespace NvErrCodes { -enum { -    OperationNotPermitted = -1, -    InvalidValue = -22, -}; -} -  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. @@ -26,6 +19,46 @@ nvmap::nvmap(Core::System& system) : nvdevice(system) {  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); @@ -33,28 +66,6 @@ VAddr nvmap::GetObjectAddress(u32 handle) const {      return object->addr;  } -u32 nvmap::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -                 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -                 IoctlVersion version) { -    switch (static_cast<IoctlCommand>(command.raw)) { -    case IoctlCommand::Create: -        return IocCreate(input, output); -    case IoctlCommand::Alloc: -        return IocAlloc(input, output); -    case IoctlCommand::GetId: -        return IocGetId(input, output); -    case IoctlCommand::FromId: -        return IocFromId(input, output); -    case IoctlCommand::Param: -        return IocParam(input, output); -    case IoctlCommand::Free: -        return IocFree(input, output); -    } - -    UNIMPLEMENTED_MSG("Unimplemented ioctl"); -    return 0; -} -  u32 nvmap::CreateObject(u32 size) {      // Create a new nvmap object and obtain a handle to it.      auto object = std::make_shared<Object>(); @@ -70,35 +81,35 @@ u32 nvmap::CreateObject(u32 size) {      return handle;  } -u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) { +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 static_cast<u32>(NvErrCodes::InvalidValue); +        return NvResult::BadValue;      }      params.handle = CreateObject(params.size);      std::memcpy(output.data(), ¶ms, sizeof(params)); -    return 0; +    return NvResult::Success;  } -u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) { +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 static_cast<u32>(NvErrCodes::InvalidValue); +        return NvResult::BadValue;      }      if ((params.align - 1) & params.align) {          LOG_ERROR(Service_NVDRV, "Incorrect alignment used, alignment={:08X}", params.align); -        return static_cast<u32>(NvErrCodes::InvalidValue); +        return NvResult::BadValue;      }      const u32 min_alignment = 0x1000; @@ -109,12 +120,12 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {      auto object = GetObject(params.handle);      if (!object) {          LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); -        return static_cast<u32>(NvErrCodes::InvalidValue); +        return NvResult::BadValue;      }      if (object->status == Object::Status::Allocated) {          LOG_ERROR(Service_NVDRV, "Object is already allocated, handle={:08X}", params.handle); -        return static_cast<u32>(NvErrCodes::OperationNotPermitted); +        return NvResult::InsufficientMemory;      }      object->flags = params.flags; @@ -124,10 +135,10 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {      object->status = Object::Status::Allocated;      std::memcpy(output.data(), ¶ms, sizeof(params)); -    return 0; +    return NvResult::Success;  } -u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) {      IocGetIdParams params;      std::memcpy(¶ms, input.data(), sizeof(params)); @@ -135,22 +146,22 @@ u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) {      if (!params.handle) {          LOG_ERROR(Service_NVDRV, "Handle is zero"); -        return static_cast<u32>(NvErrCodes::InvalidValue); +        return NvResult::BadValue;      }      auto object = GetObject(params.handle);      if (!object) {          LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); -        return static_cast<u32>(NvErrCodes::OperationNotPermitted); +        return NvResult::BadValue;      }      params.id = object->id;      std::memcpy(output.data(), ¶ms, sizeof(params)); -    return 0; +    return NvResult::Success;  } -u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {      IocFromIdParams params;      std::memcpy(¶ms, input.data(), sizeof(params)); @@ -160,13 +171,13 @@ u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {                              [&](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 static_cast<u32>(NvErrCodes::InvalidValue); +        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 static_cast<u32>(NvErrCodes::InvalidValue); +        return NvResult::BadValue;      }      itr->second->refcount++; @@ -175,10 +186,10 @@ u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {      params.handle = itr->first;      std::memcpy(output.data(), ¶ms, sizeof(params)); -    return 0; +    return NvResult::Success;  } -u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) { +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; @@ -189,12 +200,12 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {      auto object = GetObject(params.handle);      if (!object) {          LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); -        return static_cast<u32>(NvErrCodes::InvalidValue); +        return NvResult::BadValue;      }      if (object->status != Object::Status::Allocated) {          LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle); -        return static_cast<u32>(NvErrCodes::OperationNotPermitted); +        return NvResult::BadValue;      }      switch (static_cast<ParamTypes>(params.param)) { @@ -216,10 +227,10 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {      }      std::memcpy(output.data(), ¶ms, sizeof(params)); -    return 0; +    return NvResult::Success;  } -u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) { +NvResult nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) {      // TODO(Subv): These flags are unconfirmed.      enum FreeFlags {          Freed = 0, @@ -234,14 +245,14 @@ u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) {      auto itr = handles.find(params.handle);      if (itr == handles.end()) {          LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); -        return static_cast<u32>(NvErrCodes::InvalidValue); +        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 static_cast<u32>(NvErrCodes::InvalidValue); +        return NvResult::BadValue;      }      itr->second->refcount--; @@ -261,7 +272,7 @@ u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) {      handles.erase(params.handle);      std::memcpy(output.data(), ¶ms, sizeof(params)); -    return 0; +    return NvResult::Success;  }  } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h index 04b9ef540..4484bd79f 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.h +++ b/src/core/hle/service/nvdrv/devices/nvmap.h @@ -19,13 +19,15 @@ public:      explicit nvmap(Core::System& system);      ~nvmap() override; +    NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; +    NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, +                    const std::vector<u8>& inline_input, std::vector<u8>& output) override; +    NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, +                    std::vector<u8>& inline_output) override; +      /// Returns the allocated address of an nvmap object given its handle.      VAddr GetObjectAddress(u32 handle) const; -    u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, -              std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -              IoctlVersion version) override; -      /// Represents an nvmap object.      struct Object {          enum class Status { Created, Allocated }; @@ -58,76 +60,68 @@ private:      /// Mapping of currently allocated handles to the objects they represent.      std::unordered_map<u32, std::shared_ptr<Object>> handles; -    enum class IoctlCommand : u32 { -        Create = 0xC0080101, -        FromId = 0xC0080103, -        Alloc = 0xC0200104, -        Free = 0xC0180105, -        Param = 0xC00C0109, -        GetId = 0xC008010E, -    };      struct IocCreateParams {          // Input -        u32_le size; +        u32_le size{};          // Output -        u32_le handle; +        u32_le handle{};      };      static_assert(sizeof(IocCreateParams) == 8, "IocCreateParams has wrong size");      struct IocFromIdParams {          // Input -        u32_le id; +        u32_le id{};          // Output -        u32_le handle; +        u32_le handle{};      };      static_assert(sizeof(IocFromIdParams) == 8, "IocFromIdParams has wrong size");      struct IocAllocParams {          // Input -        u32_le handle; -        u32_le heap_mask; -        u32_le flags; -        u32_le align; -        u8 kind; +        u32_le handle{}; +        u32_le heap_mask{}; +        u32_le flags{}; +        u32_le align{}; +        u8 kind{};          INSERT_PADDING_BYTES(7); -        u64_le addr; +        u64_le addr{};      };      static_assert(sizeof(IocAllocParams) == 32, "IocAllocParams has wrong size");      struct IocFreeParams { -        u32_le handle; +        u32_le handle{};          INSERT_PADDING_BYTES(4); -        u64_le address; -        u32_le size; -        u32_le flags; +        u64_le address{}; +        u32_le size{}; +        u32_le flags{};      };      static_assert(sizeof(IocFreeParams) == 24, "IocFreeParams has wrong size");      struct IocParamParams {          // Input -        u32_le handle; -        u32_le param; +        u32_le handle{}; +        u32_le param{};          // Output -        u32_le result; +        u32_le result{};      };      static_assert(sizeof(IocParamParams) == 12, "IocParamParams has wrong size");      struct IocGetIdParams {          // Output -        u32_le id; +        u32_le id{};          // Input -        u32_le handle; +        u32_le handle{};      };      static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size");      u32 CreateObject(u32 size); -    u32 IocCreate(const std::vector<u8>& input, std::vector<u8>& output); -    u32 IocAlloc(const std::vector<u8>& input, std::vector<u8>& output); -    u32 IocGetId(const std::vector<u8>& input, std::vector<u8>& output); -    u32 IocFromId(const std::vector<u8>& input, std::vector<u8>& output); -    u32 IocParam(const std::vector<u8>& input, std::vector<u8>& output); -    u32 IocFree(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult IocCreate(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult IocAlloc(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult IocGetId(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult IocFromId(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult IocParam(const std::vector<u8>& input, std::vector<u8>& output); +    NvResult IocFree(const std::vector<u8>& input, std::vector<u8>& output);  };  } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp index 88fbfa9b0..f6c38e853 100644 --- a/src/core/hle/service/nvdrv/interface.cpp +++ b/src/core/hle/service/nvdrv/interface.cpp @@ -23,124 +23,170 @@ void NVDRV::SignalGPUInterruptSyncpt(const u32 syncpoint_id, const u32 value) {  void NVDRV::Open(Kernel::HLERequestContext& ctx) {      LOG_DEBUG(Service_NVDRV, "called"); +    if (!is_initialized) { +        ServiceError(ctx, NvResult::NotInitialized); +        LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); +        return; +    } +      const auto& buffer = ctx.ReadBuffer(); -    std::string device_name(buffer.begin(), buffer.end()); +    const std::string device_name(buffer.begin(), buffer.end()); +    DeviceFD fd = nvdrv->Open(device_name); -    u32 fd = nvdrv->Open(device_name);      IPC::ResponseBuilder rb{ctx, 4};      rb.Push(RESULT_SUCCESS); -    rb.Push<u32>(fd); -    rb.Push<u32>(0); +    rb.Push<DeviceFD>(fd); +    rb.PushEnum(fd != INVALID_NVDRV_FD ? NvResult::Success : NvResult::FileOperationFailed); +} + +void NVDRV::ServiceError(Kernel::HLERequestContext& ctx, NvResult result) { +    IPC::ResponseBuilder rb{ctx, 3}; +    rb.Push(RESULT_SUCCESS); +    rb.PushEnum(result);  } -void NVDRV::IoctlBase(Kernel::HLERequestContext& ctx, IoctlVersion version) { +void NVDRV::Ioctl1(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx}; -    u32 fd = rp.Pop<u32>(); -    u32 command = rp.Pop<u32>(); - -    /// Ioctl 3 has 2 outputs, first in the input params, second is the result -    std::vector<u8> output(ctx.GetWriteBufferSize(0)); -    std::vector<u8> output2; -    if (version == IoctlVersion::Version3) { -        output2.resize((ctx.GetWriteBufferSize(1))); +    const auto fd = rp.Pop<DeviceFD>(); +    const auto command = rp.PopRaw<Ioctl>(); +    LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw); + +    if (!is_initialized) { +        ServiceError(ctx, NvResult::NotInitialized); +        LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); +        return;      } -    /// Ioctl2 has 2 inputs. It's used to pass data directly instead of providing a pointer. -    /// KickOfPB uses this -    auto input = ctx.ReadBuffer(0); +    // Check device +    std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0)); +    const auto input_buffer = ctx.ReadBuffer(0); -    std::vector<u8> input2; -    if (version == IoctlVersion::Version2) { -        input2 = ctx.ReadBuffer(1); -    } +    const auto nv_result = nvdrv->Ioctl1(fd, command, input_buffer, output_buffer); -    IoctlCtrl ctrl{}; - -    u32 result = nvdrv->Ioctl(fd, command, input, input2, output, output2, ctrl, version); - -    if (ctrl.must_delay) { -        ctrl.fresh_call = false; -        ctx.SleepClientThread( -            "NVServices::DelayedResponse", ctrl.timeout, -            [=, this](std::shared_ptr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx_, -                      Kernel::ThreadWakeupReason reason) { -                IoctlCtrl ctrl2{ctrl}; -                std::vector<u8> tmp_output = output; -                std::vector<u8> tmp_output2 = output2; -                const u32 ioctl_result = nvdrv->Ioctl(fd, command, input, input2, tmp_output, -                                                      tmp_output2, ctrl2, version); -                ctx_.WriteBuffer(tmp_output, 0); -                if (version == IoctlVersion::Version3) { -                    ctx_.WriteBuffer(tmp_output2, 1); -                } -                IPC::ResponseBuilder rb{ctx_, 3}; -                rb.Push(RESULT_SUCCESS); -                rb.Push(ioctl_result); -            }, -            nvdrv->GetEventWriteable(ctrl.event_id)); -    } else { -        ctx.WriteBuffer(output); -        if (version == IoctlVersion::Version3) { -            ctx.WriteBuffer(output2, 1); -        } +    if (command.is_out != 0) { +        ctx.WriteBuffer(output_buffer);      } +      IPC::ResponseBuilder rb{ctx, 3};      rb.Push(RESULT_SUCCESS); -    rb.Push(result); -} - -void NVDRV::Ioctl(Kernel::HLERequestContext& ctx) { -    LOG_DEBUG(Service_NVDRV, "called"); -    IoctlBase(ctx, IoctlVersion::Version1); +    rb.PushEnum(nv_result);  }  void NVDRV::Ioctl2(Kernel::HLERequestContext& ctx) { -    LOG_DEBUG(Service_NVDRV, "called"); -    IoctlBase(ctx, IoctlVersion::Version2); +    IPC::RequestParser rp{ctx}; +    const auto fd = rp.Pop<DeviceFD>(); +    const auto command = rp.PopRaw<Ioctl>(); +    LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw); + +    if (!is_initialized) { +        ServiceError(ctx, NvResult::NotInitialized); +        LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); +        return; +    } + +    const auto input_buffer = ctx.ReadBuffer(0); +    const auto input_inlined_buffer = ctx.ReadBuffer(1); +    std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0)); + +    const auto nv_result = +        nvdrv->Ioctl2(fd, command, input_buffer, input_inlined_buffer, output_buffer); + +    if (command.is_out != 0) { +        ctx.WriteBuffer(output_buffer); +    } + +    IPC::ResponseBuilder rb{ctx, 3}; +    rb.Push(RESULT_SUCCESS); +    rb.PushEnum(nv_result);  }  void NVDRV::Ioctl3(Kernel::HLERequestContext& ctx) { -    LOG_DEBUG(Service_NVDRV, "called"); -    IoctlBase(ctx, IoctlVersion::Version3); +    IPC::RequestParser rp{ctx}; +    const auto fd = rp.Pop<DeviceFD>(); +    const auto command = rp.PopRaw<Ioctl>(); +    LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw); + +    if (!is_initialized) { +        ServiceError(ctx, NvResult::NotInitialized); +        LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); +        return; +    } + +    const auto input_buffer = ctx.ReadBuffer(0); +    std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0)); +    std::vector<u8> output_buffer_inline(ctx.GetWriteBufferSize(1)); + +    const auto nv_result = +        nvdrv->Ioctl3(fd, command, input_buffer, output_buffer, output_buffer_inline); + +    if (command.is_out != 0) { +        ctx.WriteBuffer(output_buffer, 0); +        ctx.WriteBuffer(output_buffer_inline, 1); +    } + +    IPC::ResponseBuilder rb{ctx, 3}; +    rb.Push(RESULT_SUCCESS); +    rb.PushEnum(nv_result);  }  void NVDRV::Close(Kernel::HLERequestContext& ctx) {      LOG_DEBUG(Service_NVDRV, "called"); -    IPC::RequestParser rp{ctx}; -    u32 fd = rp.Pop<u32>(); +    if (!is_initialized) { +        ServiceError(ctx, NvResult::NotInitialized); +        LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); +        return; +    } -    auto result = nvdrv->Close(fd); +    IPC::RequestParser rp{ctx}; +    const auto fd = rp.Pop<DeviceFD>(); +    const auto result = nvdrv->Close(fd); -    IPC::ResponseBuilder rb{ctx, 2}; -    rb.Push(result); +    IPC::ResponseBuilder rb{ctx, 3}; +    rb.Push(RESULT_SUCCESS); +    rb.PushEnum(result);  }  void NVDRV::Initialize(Kernel::HLERequestContext& ctx) {      LOG_WARNING(Service_NVDRV, "(STUBBED) called"); +    is_initialized = true; +      IPC::ResponseBuilder rb{ctx, 3};      rb.Push(RESULT_SUCCESS); -    rb.Push<u32>(0); +    rb.PushEnum(NvResult::Success);  }  void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx}; -    u32 fd = rp.Pop<u32>(); -    // TODO(Blinkhawk): Figure the meaning of the flag at bit 16 -    u32 event_id = rp.Pop<u32>() & 0x000000FF; +    const auto fd = rp.Pop<DeviceFD>(); +    const auto event_id = rp.Pop<u32>() & 0x00FF;      LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}, event_id={:X}", fd, event_id); -    IPC::ResponseBuilder rb{ctx, 3, 1}; -    rb.Push(RESULT_SUCCESS); +    if (!is_initialized) { +        ServiceError(ctx, NvResult::NotInitialized); +        LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); +        return; +    } + +    const auto nv_result = nvdrv->VerifyFD(fd); +    if (nv_result != NvResult::Success) { +        LOG_ERROR(Service_NVDRV, "Invalid FD specified DeviceFD={}!", fd); +        ServiceError(ctx, nv_result); +        return; +    } +      if (event_id < MaxNvEvents) { +        IPC::ResponseBuilder rb{ctx, 3, 1}; +        rb.Push(RESULT_SUCCESS);          auto event = nvdrv->GetEvent(event_id);          event->Clear();          rb.PushCopyObjects(event); -        rb.Push<u32>(NvResult::Success); +        rb.PushEnum(NvResult::Success);      } else { -        rb.Push<u32>(0); -        rb.Push<u32>(NvResult::BadParameter); +        IPC::ResponseBuilder rb{ctx, 3}; +        rb.Push(RESULT_SUCCESS); +        rb.PushEnum(NvResult::BadParameter);      }  } @@ -151,7 +197,7 @@ void NVDRV::SetAruid(Kernel::HLERequestContext& ctx) {      IPC::ResponseBuilder rb{ctx, 3};      rb.Push(RESULT_SUCCESS); -    rb.Push<u32>(0); +    rb.PushEnum(NvResult::Success);  }  void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx) { @@ -164,8 +210,9 @@ void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ct  void NVDRV::GetStatus(Kernel::HLERequestContext& ctx) {      LOG_WARNING(Service_NVDRV, "(STUBBED) called"); -    IPC::ResponseBuilder rb{ctx, 2}; +    IPC::ResponseBuilder rb{ctx, 3};      rb.Push(RESULT_SUCCESS); +    rb.PushEnum(NvResult::Success);  }  void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) { @@ -181,7 +228,7 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name)      : ServiceFramework(name), nvdrv(std::move(nvdrv)) {      static const FunctionInfo functions[] = {          {0, &NVDRV::Open, "Open"}, -        {1, &NVDRV::Ioctl, "Ioctl"}, +        {1, &NVDRV::Ioctl1, "Ioctl"},          {2, &NVDRV::Close, "Close"},          {3, &NVDRV::Initialize, "Initialize"},          {4, &NVDRV::QueryEvent, "QueryEvent"}, diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h index 72e17a728..e05f905ae 100644 --- a/src/core/hle/service/nvdrv/interface.h +++ b/src/core/hle/service/nvdrv/interface.h @@ -23,7 +23,7 @@ public:  private:      void Open(Kernel::HLERequestContext& ctx); -    void Ioctl(Kernel::HLERequestContext& ctx); +    void Ioctl1(Kernel::HLERequestContext& ctx);      void Ioctl2(Kernel::HLERequestContext& ctx);      void Ioctl3(Kernel::HLERequestContext& ctx);      void Close(Kernel::HLERequestContext& ctx); @@ -33,11 +33,13 @@ private:      void SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx);      void GetStatus(Kernel::HLERequestContext& ctx);      void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx); -    void IoctlBase(Kernel::HLERequestContext& ctx, IoctlVersion version); + +    void ServiceError(Kernel::HLERequestContext& ctx, NvResult result);      std::shared_ptr<Module> nvdrv;      u64 pid{}; +    bool is_initialized{};  };  } // namespace Service::Nvidia diff --git a/src/core/hle/service/nvdrv/nvdata.h b/src/core/hle/service/nvdrv/nvdata.h index 529b03471..3294bc0e7 100644 --- a/src/core/hle/service/nvdrv/nvdata.h +++ b/src/core/hle/service/nvdrv/nvdata.h @@ -1,12 +1,16 @@  #pragma once  #include <array> +#include "common/bit_field.h"  #include "common/common_types.h"  namespace Service::Nvidia {  constexpr u32 MaxSyncPoints = 192;  constexpr u32 MaxNvEvents = 64; +using DeviceFD = s32; + +constexpr DeviceFD INVALID_NVDRV_FD = -1;  struct Fence {      s32 id; @@ -20,11 +24,61 @@ struct MultiFence {      std::array<Fence, 4> fences;  }; -enum NvResult : u32 { -    Success = 0, -    BadParameter = 4, -    Timeout = 5, -    ResourceError = 15, +enum class NvResult : u32 { +    Success = 0x0, +    NotImplemented = 0x1, +    NotSupported = 0x2, +    NotInitialized = 0x3, +    BadParameter = 0x4, +    Timeout = 0x5, +    InsufficientMemory = 0x6, +    ReadOnlyAttribute = 0x7, +    InvalidState = 0x8, +    InvalidAddress = 0x9, +    InvalidSize = 0xA, +    BadValue = 0xB, +    AlreadyAllocated = 0xD, +    Busy = 0xE, +    ResourceError = 0xF, +    CountMismatch = 0x10, +    OverFlow = 0x11, +    InsufficientTransferMemory = 0x1000, +    InsufficientVideoMemory = 0x10000, +    BadSurfaceColorScheme = 0x10001, +    InvalidSurface = 0x10002, +    SurfaceNotSupported = 0x10003, +    DispInitFailed = 0x20000, +    DispAlreadyAttached = 0x20001, +    DispTooManyDisplays = 0x20002, +    DispNoDisplaysAttached = 0x20003, +    DispModeNotSupported = 0x20004, +    DispNotFound = 0x20005, +    DispAttachDissallowed = 0x20006, +    DispTypeNotSupported = 0x20007, +    DispAuthenticationFailed = 0x20008, +    DispNotAttached = 0x20009, +    DispSamePwrState = 0x2000A, +    DispEdidFailure = 0x2000B, +    DispDsiReadAckError = 0x2000C, +    DispDsiReadInvalidResp = 0x2000D, +    FileWriteFailed = 0x30000, +    FileReadFailed = 0x30001, +    EndOfFile = 0x30002, +    FileOperationFailed = 0x30003, +    DirOperationFailed = 0x30004, +    EndOfDirList = 0x30005, +    ConfigVarNotFound = 0x30006, +    InvalidConfigVar = 0x30007, +    LibraryNotFound = 0x30008, +    SymbolNotFound = 0x30009, +    MemoryMapFailed = 0x3000A, +    IoctlFailed = 0x3000F, +    AccessDenied = 0x30010, +    DeviceNotFound = 0x30011, +    KernelDriverNotFound = 0x30012, +    FileNotFound = 0x30013, +    PathAlreadyExists = 0x30014, +    ModuleNotPresent = 0xA000E,  };  enum class EventState { @@ -34,21 +88,13 @@ enum class EventState {      Busy = 3,  }; -enum class IoctlVersion : u32 { -    Version1, -    Version2, -    Version3, -}; - -struct IoctlCtrl { -    // First call done to the servioce for services that call itself again after a call. -    bool fresh_call{true}; -    // Tells the Ioctl Wrapper that it must delay the IPC response and send the thread to sleep -    bool must_delay{}; -    // Timeout for the delay -    s64 timeout{}; -    // NV Event Id -    s32 event_id{-1}; +union Ioctl { +    u32_le raw; +    BitField<0, 8, u32> cmd; +    BitField<8, 8, u32> group; +    BitField<16, 14, u32> length; +    BitField<30, 1, u32> is_in; +    BitField<31, 1, u32> is_out;  };  } // namespace Service::Nvidia diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 046a1f28c..bdbbedd0d 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -62,36 +62,101 @@ Module::Module(Core::System& system) : syncpoint_manager{system.GPU()} {  Module::~Module() = default; -u32 Module::Open(const std::string& device_name) { -    ASSERT_MSG(devices.find(device_name) != devices.end(), "Trying to open unknown device {}", -               device_name); +NvResult Module::VerifyFD(DeviceFD fd) const { +    if (fd < 0) { +        LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); +        return NvResult::InvalidState; +    } + +    if (open_files.find(fd) == open_files.end()) { +        LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd); +        return NvResult::NotImplemented; +    } + +    return NvResult::Success; +} + +DeviceFD Module::Open(const std::string& device_name) { +    if (devices.find(device_name) == devices.end()) { +        LOG_ERROR(Service_NVDRV, "Trying to open unknown device {}", device_name); +        return INVALID_NVDRV_FD; +    }      auto device = devices[device_name]; -    const u32 fd = next_fd++; +    const DeviceFD fd = next_fd++;      open_files[fd] = std::move(device);      return fd;  } -u32 Module::Ioctl(u32 fd, u32 command, const std::vector<u8>& input, const std::vector<u8>& input2, -                  std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -                  IoctlVersion version) { -    auto itr = open_files.find(fd); -    ASSERT_MSG(itr != open_files.end(), "Tried to talk to an invalid device"); +NvResult Module::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, +                        std::vector<u8>& output) { +    if (fd < 0) { +        LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); +        return NvResult::InvalidState; +    } -    auto& device = itr->second; -    return device->ioctl({command}, input, input2, output, output2, ctrl, version); +    const auto itr = open_files.find(fd); + +    if (itr == open_files.end()) { +        LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd); +        return NvResult::NotImplemented; +    } + +    return itr->second->Ioctl1(command, input, output);  } -ResultCode Module::Close(u32 fd) { -    auto itr = open_files.find(fd); -    ASSERT_MSG(itr != open_files.end(), "Tried to talk to an invalid device"); +NvResult Module::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, +                        const std::vector<u8>& inline_input, std::vector<u8>& output) { +    if (fd < 0) { +        LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); +        return NvResult::InvalidState; +    } + +    const auto itr = open_files.find(fd); + +    if (itr == open_files.end()) { +        LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd); +        return NvResult::NotImplemented; +    } + +    return itr->second->Ioctl2(command, input, inline_input, output); +} + +NvResult Module::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, +                        std::vector<u8>& output, std::vector<u8>& inline_output) { +    if (fd < 0) { +        LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); +        return NvResult::InvalidState; +    } + +    const auto itr = open_files.find(fd); + +    if (itr == open_files.end()) { +        LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd); +        return NvResult::NotImplemented; +    } + +    return itr->second->Ioctl3(command, input, output, inline_output); +} + +NvResult Module::Close(DeviceFD fd) { +    if (fd < 0) { +        LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); +        return NvResult::InvalidState; +    } + +    const auto itr = open_files.find(fd); + +    if (itr == open_files.end()) { +        LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd); +        return NvResult::NotImplemented; +    }      open_files.erase(itr); -    // TODO(flerovium): return correct result code if operation failed. -    return RESULT_SUCCESS; +    return NvResult::Success;  }  void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) { diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index f3d863dac..7654bb026 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -112,14 +112,23 @@ public:          return std::static_pointer_cast<T>(itr->second);      } +    NvResult VerifyFD(DeviceFD fd) const; +      /// Opens a device node and returns a file descriptor to it. -    u32 Open(const std::string& device_name); +    DeviceFD Open(const std::string& device_name); +      /// Sends an ioctl command to the specified file descriptor. -    u32 Ioctl(u32 fd, u32 command, const std::vector<u8>& input, const std::vector<u8>& input2, -              std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, -              IoctlVersion version); +    NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, +                    std::vector<u8>& output); + +    NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, +                    const std::vector<u8>& inline_input, std::vector<u8>& output); + +    NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, +                    std::vector<u8>& output, std::vector<u8>& inline_output); +      /// Closes a device file descriptor and returns operation success. -    ResultCode Close(u32 fd); +    NvResult Close(DeviceFD fd);      void SignalSyncpt(const u32 syncpoint_id, const u32 value); @@ -132,10 +141,10 @@ private:      SyncpointManager syncpoint_manager;      /// Id to use for the next open file descriptor. -    u32 next_fd = 1; +    DeviceFD next_fd = 1;      /// Mapping of file descriptors to the devices they reference. -    std::unordered_map<u32, std::shared_ptr<Devices::nvdevice>> open_files; +    std::unordered_map<DeviceFD, std::shared_ptr<Devices::nvdevice>> open_files;      /// Mapping of device node names to their implementation.      std::unordered_map<std::string, std::shared_ptr<Devices::nvdevice>> devices; | 
