diff options
29 files changed, 346 insertions, 93 deletions
diff --git a/src/core/hle/ipc.h b/src/core/hle/ipc.h index ef6595550..c9257de77 100644 --- a/src/core/hle/ipc.h +++ b/src/core/hle/ipc.h @@ -32,6 +32,8 @@ enum class CommandType : u32 { Close = 2, Request = 4, Control = 5, + RequestWithContext = 6, + ControlWithContext = 7, Unspecified, }; diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 349bc11df..01904467e 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -110,7 +110,9 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) { // Padding to align to 16 bytes rp.AlignWithPadding(); - if (Session()->IsDomain() && (command_header->type == IPC::CommandType::Request || !incoming)) { + if (Session()->IsDomain() && ((command_header->type == IPC::CommandType::Request || + command_header->type == IPC::CommandType::RequestWithContext) || + !incoming)) { // If this is an incoming message, only CommandType "Request" has a domain header // All outgoing domain messages have the domain header, if only incoming has it if (incoming || domain_message_header) { diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 63733ad79..bc144f3de 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -104,7 +104,6 @@ ResultCode Mutex::Release(VAddr address) { // There are no more threads waiting for the mutex, release it completely. if (thread == nullptr) { - ASSERT(GetCurrentThread()->wait_mutex_threads.empty()); Memory::Write32(address, 0); return RESULT_SUCCESS; } diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 052f49979..e3eda4f54 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -42,41 +42,75 @@ enum class ErrorModule : u32 { PM = 15, NS = 16, HTC = 18, + NCMContent = 20, SM = 21, RO = 22, SDMMC = 24, + OVLN = 25, SPL = 26, ETHC = 100, I2C = 101, + GPIO = 102, + UART = 103, Settings = 105, + WLAN = 107, + XCD = 108, NIFM = 110, - Display = 114, - NTC = 116, + Hwopus = 111, + Bluetooth = 113, + VI = 114, + NFP = 115, + Time = 116, FGM = 117, - PCIE = 120, + PCIe = 120, Friends = 121, + BCAT = 122, SSL = 123, Account = 124, + News = 125, Mii = 126, + NFC = 127, AM = 128, PlayReport = 129, + AHID = 130, + Qlaunch = 132, PCV = 133, OMM = 134, + BPC = 135, + PSM = 136, NIM = 137, PSC = 138, + TC = 139, USB = 140, + NSD = 141, + PCTL = 142, BTM = 143, + ETicket = 145, + NGC = 146, ERPT = 147, APM = 148, + ErrorUpload = 151, + Audio = 153, NPNS = 154, + NPNSHTTPSTREAM = 155, ARP = 157, BOOT = 158, - NFC = 161, + NFCMifare = 161, UserlandAssert = 162, + Fatal = 163, + NIMShop = 164, + SPSM = 165, + BGTC = 167, UserlandCrash = 168, - HID = 203, + SREPO = 180, + HID = 202, + LDN = 203, + Irsensor = 205, Capture = 206, - TC = 651, + Manu = 208, + GRC = 212, + Migration = 216, + MigrationLdcServ = 217, GeneralWebApplet = 800, WifiWebAuthApplet = 809, WhitelistedApplet = 810, diff --git a/src/core/hle/service/audio/audin_u.cpp b/src/core/hle/service/audio/audin_u.cpp index dca2bfb92..cbc49e55e 100644 --- a/src/core/hle/service/audio/audin_u.cpp +++ b/src/core/hle/service/audio/audin_u.cpp @@ -35,10 +35,8 @@ public: AudInU::AudInU() : ServiceFramework("audin:u") { static const FunctionInfo functions[] = { - {0, nullptr, "ListAudioIns"}, - {1, nullptr, "OpenAudioIn"}, - {3, nullptr, "OpenAudioInAuto"}, - {4, nullptr, "ListAudioInsAuto"}, + {0, nullptr, "ListAudioIns"}, {1, nullptr, "OpenAudioIn"}, {2, nullptr, "Unknown"}, + {3, nullptr, "OpenAudioInAuto"}, {4, nullptr, "ListAudioInsAuto"}, }; RegisterHandlers(functions); } diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index fa3728672..402eaa306 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp @@ -196,10 +196,10 @@ void AudOutU::OpenAudioOut(Kernel::HLERequestContext& ctx) { } AudOutU::AudOutU() : ServiceFramework("audout:u") { - static const FunctionInfo functions[] = {{0x00000000, &AudOutU::ListAudioOuts, "ListAudioOuts"}, - {0x00000001, &AudOutU::OpenAudioOut, "OpenAudioOut"}, - {0x00000002, nullptr, "ListAudioOutsAuto"}, - {0x00000003, nullptr, "OpenAudioOutAuto"}}; + static const FunctionInfo functions[] = {{0, &AudOutU::ListAudioOuts, "ListAudioOuts"}, + {1, &AudOutU::OpenAudioOut, "OpenAudioOut"}, + {2, nullptr, "ListAudioOutsAuto"}, + {3, nullptr, "OpenAudioOutAuto"}}; RegisterHandlers(functions); } diff --git a/src/core/hle/service/audio/audrec_u.cpp b/src/core/hle/service/audio/audrec_u.cpp index b2be10919..74909415c 100644 --- a/src/core/hle/service/audio/audrec_u.cpp +++ b/src/core/hle/service/audio/audrec_u.cpp @@ -20,6 +20,7 @@ public: {4, nullptr, "RegisterBufferEvent"}, {5, nullptr, "GetReleasedFinalOutputRecorderBuffer"}, {6, nullptr, "ContainsFinalOutputRecorderBuffer"}, + {7, nullptr, "Unknown"}, {8, nullptr, "AppendFinalOutputRecorderBufferAuto"}, {9, nullptr, "GetReleasedFinalOutputRecorderBufferAuto"}, }; @@ -30,7 +31,7 @@ public: AudRecU::AudRecU() : ServiceFramework("audrec:u") { static const FunctionInfo functions[] = { - {0x00000000, nullptr, "OpenFinalOutputRecorder"}, + {0, nullptr, "OpenFinalOutputRecorder"}, }; RegisterHandlers(functions); } diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index 0d6eb1d51..38bc65d95 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -156,19 +156,20 @@ class IAudioDevice final : public ServiceFramework<IAudioDevice> { public: IAudioDevice() : ServiceFramework("IAudioDevice") { static const FunctionInfo functions[] = { - {0x0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"}, - {0x1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"}, - {0x2, nullptr, "GetAudioDeviceOutputVolume"}, - {0x3, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceName"}, - {0x4, &IAudioDevice::QueryAudioDeviceSystemEvent, "QueryAudioDeviceSystemEvent"}, - {0x5, &IAudioDevice::GetActiveChannelCount, "GetActiveChannelCount"}, - {0x6, &IAudioDevice::ListAudioDeviceName, + {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"}, + {1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"}, + {2, nullptr, "GetAudioDeviceOutputVolume"}, + {3, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceName"}, + {4, &IAudioDevice::QueryAudioDeviceSystemEvent, "QueryAudioDeviceSystemEvent"}, + {5, &IAudioDevice::GetActiveChannelCount, "GetActiveChannelCount"}, + {6, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceNameAuto"}, // TODO(ogniK): Confirm if autos are identical to non auto - {0x7, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolumeAuto"}, - {0x8, nullptr, "GetAudioDeviceOutputVolumeAuto"}, - {0xa, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceNameAuto"}, - {0xb, nullptr, "QueryAudioDeviceInputEvent"}, - {0xc, nullptr, "QueryAudioDeviceOutputEvent"}}; + {7, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolumeAuto"}, + {8, nullptr, "GetAudioDeviceOutputVolumeAuto"}, + {10, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceNameAuto"}, + {11, nullptr, "QueryAudioDeviceInputEvent"}, + {12, nullptr, "QueryAudioDeviceOutputEvent"}, + }; RegisterHandlers(functions); buffer_event = diff --git a/src/core/hle/service/audio/codecctl.cpp b/src/core/hle/service/audio/codecctl.cpp index ba0f1d228..212c8d448 100644 --- a/src/core/hle/service/audio/codecctl.cpp +++ b/src/core/hle/service/audio/codecctl.cpp @@ -11,19 +11,19 @@ namespace Service::Audio { CodecCtl::CodecCtl() : ServiceFramework("codecctl") { static const FunctionInfo functions[] = { - {0x00000000, nullptr, "InitializeCodecController"}, - {0x00000001, nullptr, "FinalizeCodecController"}, - {0x00000002, nullptr, "SleepCodecController"}, - {0x00000003, nullptr, "WakeCodecController"}, - {0x00000004, nullptr, "SetCodecVolume"}, - {0x00000005, nullptr, "GetCodecVolumeMax"}, - {0x00000006, nullptr, "GetCodecVolumeMin"}, - {0x00000007, nullptr, "SetCodecActiveTarget"}, - {0x00000008, nullptr, "Unknown"}, - {0x00000009, nullptr, "BindCodecHeadphoneMicJackInterrupt"}, - {0x00000010, nullptr, "IsCodecHeadphoneMicJackInserted"}, - {0x00000011, nullptr, "ClearCodecHeadphoneMicJackInterrupt"}, - {0x00000012, nullptr, "IsCodecDeviceRequested"}, + {0, nullptr, "InitializeCodecController"}, + {1, nullptr, "FinalizeCodecController"}, + {2, nullptr, "SleepCodecController"}, + {3, nullptr, "WakeCodecController"}, + {4, nullptr, "SetCodecVolume"}, + {5, nullptr, "GetCodecVolumeMax"}, + {6, nullptr, "GetCodecVolumeMin"}, + {7, nullptr, "SetCodecActiveTarget"}, + {8, nullptr, "GetCodecActiveTarget"}, + {9, nullptr, "BindCodecHeadphoneMicJackInterrupt"}, + {10, nullptr, "IsCodecHeadphoneMicJackInserted"}, + {11, nullptr, "ClearCodecHeadphoneMicJackInterrupt"}, + {12, nullptr, "IsCodecDeviceRequested"}, }; RegisterHandlers(functions); } diff --git a/src/core/hle/service/fatal/fatal.cpp b/src/core/hle/service/fatal/fatal.cpp index bb75e7314..2d4282209 100644 --- a/src/core/hle/service/fatal/fatal.cpp +++ b/src/core/hle/service/fatal/fatal.cpp @@ -13,7 +13,7 @@ namespace Service::Fatal { Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) : ServiceFramework(name), module(std::move(module)) {} -void Module::Interface::FatalSimple(Kernel::HLERequestContext& ctx) { +void Module::Interface::ThrowFatalWithPolicy(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx); u32 error_code = rp.Pop<u32>(); NGLOG_WARNING(Service_Fatal, "(STUBBED) called, error_code=0x{:X}", error_code); @@ -21,7 +21,7 @@ void Module::Interface::FatalSimple(Kernel::HLERequestContext& ctx) { rb.Push(RESULT_SUCCESS); } -void Module::Interface::TransitionToFatalError(Kernel::HLERequestContext& ctx) { +void Module::Interface::ThrowFatalWithCpuContext(Kernel::HLERequestContext& ctx) { NGLOG_WARNING(Service_Fatal, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); diff --git a/src/core/hle/service/fatal/fatal.h b/src/core/hle/service/fatal/fatal.h index 2d8d08320..5bd111a14 100644 --- a/src/core/hle/service/fatal/fatal.h +++ b/src/core/hle/service/fatal/fatal.h @@ -14,8 +14,8 @@ public: public: Interface(std::shared_ptr<Module> module, const char* name); - void FatalSimple(Kernel::HLERequestContext& ctx); - void TransitionToFatalError(Kernel::HLERequestContext& ctx); + void ThrowFatalWithPolicy(Kernel::HLERequestContext& ctx); + void ThrowFatalWithCpuContext(Kernel::HLERequestContext& ctx); protected: std::shared_ptr<Module> module; diff --git a/src/core/hle/service/fatal/fatal_u.cpp b/src/core/hle/service/fatal/fatal_u.cpp index 26aa9f3b7..f0631329e 100644 --- a/src/core/hle/service/fatal/fatal_u.cpp +++ b/src/core/hle/service/fatal/fatal_u.cpp @@ -8,8 +8,9 @@ namespace Service::Fatal { Fatal_U::Fatal_U(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "fatal:u") { static const FunctionInfo functions[] = { - {1, &Fatal_U::FatalSimple, "FatalSimple"}, - {2, &Fatal_U::TransitionToFatalError, "TransitionToFatalError"}, + {0, nullptr, "ThrowFatal"}, + {1, &Fatal_U::ThrowFatalWithPolicy, "ThrowFatalWithPolicy"}, + {2, &Fatal_U::ThrowFatalWithCpuContext, "ThrowFatalWithCpuContext"}, }; RegisterHandlers(functions); } diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index cc0247881..2af4465de 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp @@ -17,30 +17,30 @@ public: IUser() : ServiceFramework("IUser") { static const FunctionInfo functions[] = { {0, &IUser::Initialize, "Initialize"}, - {1, nullptr, "Unknown1"}, - {2, nullptr, "Unknown2"}, - {3, nullptr, "Unknown3"}, - {4, nullptr, "Unknown4"}, - {5, nullptr, "Unknown5"}, - {6, nullptr, "Unknown6"}, - {7, nullptr, "Unknown7"}, - {8, nullptr, "Unknown8"}, - {9, nullptr, "Unknown9"}, - {10, nullptr, "Unknown10"}, - {11, nullptr, "Unknown11"}, - {12, nullptr, "Unknown12"}, - {13, nullptr, "Unknown13"}, - {14, nullptr, "Unknown14"}, - {15, nullptr, "Unknown15"}, - {16, nullptr, "Unknown16"}, - {17, nullptr, "Unknown17"}, - {18, nullptr, "Unknown18"}, - {19, nullptr, "Unknown19"}, - {20, nullptr, "Unknown20"}, - {21, nullptr, "Unknown21"}, - {22, nullptr, "Unknown22"}, - {23, nullptr, "Unknown23"}, - {24, nullptr, "Unknown24"}, + {1, nullptr, "Finalize"}, + {2, nullptr, "ListDevices"}, + {3, nullptr, "StartDetection"}, + {4, nullptr, "StopDetection"}, + {5, nullptr, "Mount"}, + {6, nullptr, "Unmount"}, + {7, nullptr, "OpenApplicationArea"}, + {8, nullptr, "GetApplicationArea"}, + {9, nullptr, "SetApplicationArea"}, + {10, nullptr, "Flush"}, + {11, nullptr, "Restore"}, + {12, nullptr, "CreateApplicationArea"}, + {13, nullptr, "GetTagInfo"}, + {14, nullptr, "GetRegisterInfo"}, + {15, nullptr, "GetCommonInfo"}, + {16, nullptr, "GetModelInfo"}, + {17, nullptr, "AttachActivateEvent"}, + {18, nullptr, "AttachDeactivateEvent"}, + {19, nullptr, "GetState"}, + {20, nullptr, "GetDeviceState"}, + {21, nullptr, "GetNpadId"}, + {22, nullptr, "GetApplicationArea2"}, + {23, nullptr, "AttachAvailabilityChangeEvent"}, + {24, nullptr, "RecreateApplicationArea"}, }; RegisterHandlers(functions); } 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 cb4913b07..c1eea861d 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -26,6 +26,8 @@ u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vecto return BindChannel(input, output); case IoctlCommand::IocGetVaRegionsCommand: return GetVARegions(input, output); + case IoctlCommand::IocUnmapBufferCommand: + return UnmapBuffer(input, output); } if (static_cast<IoctlCommand>(command.cmd.Value()) == IoctlCommand::IocRemapCommand) @@ -125,6 +127,37 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou params.offset = gpu.memory_manager->MapBufferEx(object->addr, object->size); } + // Create a new mapping entry for this operation. + ASSERT_MSG(buffer_mappings.find(params.offset) == buffer_mappings.end(), + "Offset is already mapped"); + + BufferMapping mapping{}; + mapping.nvmap_handle = params.nvmap_handle; + mapping.offset = params.offset; + mapping.size = object->size; + + buffer_mappings[params.offset] = mapping; + + std::memcpy(output.data(), ¶ms, output.size()); + return 0; +} + +u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { + IoctlUnmapBuffer params{}; + std::memcpy(¶ms, input.data(), input.size()); + + NGLOG_DEBUG(Service_NVDRV, "called, offset=0x{:X}", params.offset); + + auto& gpu = Core::System::GetInstance().GPU(); + + auto itr = buffer_mappings.find(params.offset); + + ASSERT_MSG(itr != buffer_mappings.end(), "Tried to unmap invalid mapping"); + + params.offset = gpu.memory_manager->UnmapBuffer(params.offset, itr->second.size); + + buffer_mappings.erase(itr->second.offset); + std::memcpy(output.data(), ¶ms, output.size()); return 0; } 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 f2dd0c3b3..d4c4b4db3 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h @@ -5,6 +5,7 @@ #pragma once #include <memory> +#include <unordered_map> #include <utility> #include <vector> #include "common/common_types.h" @@ -30,6 +31,7 @@ private: IocMapBufferExCommand = 0xC0284106, IocBindChannelCommand = 0x40044101, IocGetVaRegionsCommand = 0xC0404108, + IocUnmapBufferCommand = 0xC0084105, }; struct IoctlInitalizeEx { @@ -76,6 +78,11 @@ private: }; static_assert(sizeof(IoctlMapBufferEx) == 40, "IoctlMapBufferEx is incorrect size"); + struct IoctlUnmapBuffer { + u64_le offset; + }; + static_assert(sizeof(IoctlUnmapBuffer) == 8, "IoctlUnmapBuffer is incorrect size"); + struct IoctlBindChannel { u32_le fd; }; @@ -98,12 +105,22 @@ private: static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(IoctlVaRegion) * 2, "IoctlGetVaRegions is incorrect size"); + struct BufferMapping { + u64 offset; + u64 size; + u32 nvmap_handle; + }; + + /// Map containing the nvmap object mappings in GPU memory. + std::unordered_map<u64, BufferMapping> buffer_mappings; + u32 channel{}; 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 BindChannel(const std::vector<u8>& input, std::vector<u8>& output); u32 GetVARegions(const std::vector<u8>& input, std::vector<u8>& output); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 25e3ccef6..03126aeee 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -32,6 +32,8 @@ u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u return AllocGPFIFOEx2(input, output); case IoctlCommand::IocAllocObjCtxCommand: return AllocateObjectContext(input, output); + case IoctlCommand::IocChannelGetWaitbaseCommand: + return GetWaitbase(input, output); } if (command.group == NVGPU_IOCTL_MAGIC) { @@ -138,4 +140,13 @@ u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& outp return 0; } +u32 nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) { + IoctlGetWaitbase params{}; + std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase)); + NGLOG_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; +} + } // 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 703c36bbb..beb1c4970 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h @@ -33,6 +33,7 @@ private: IocChannelSetPriorityCommand = 0x4004480D, IocAllocGPFIFOEx2Command = 0xC020481A, IocAllocObjCtxCommand = 0xC0104809, + IocChannelGetWaitbaseCommand = 0xC0080003, }; enum class CtxObjects : u32_le { @@ -117,7 +118,13 @@ private: IoctlFence fence_out; // returned new fence object for others to wait on }; static_assert(sizeof(IoctlSubmitGpfifo) == 16 + sizeof(IoctlFence), - "submit_gpfifo is incorrect size"); + "IoctlSubmitGpfifo is incorrect size"); + + struct IoctlGetWaitbase { + u32 unknown; // seems to be ignored? Nintendo added this + u32 value; + }; + static_assert(sizeof(IoctlGetWaitbase) == 8, "IoctlGetWaitbase is incorrect size"); u32_le nvmap_fd{}; u64_le user_data{}; @@ -133,6 +140,7 @@ private: u32 AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output); u32 AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output); u32 SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output); + u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); std::shared_ptr<nvmap> nvmap_dev; }; diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index 8d883209f..d66fb3a9c 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp @@ -30,6 +30,8 @@ u32 nvmap::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& o return IocFromId(input, output); case IoctlCommand::Param: return IocParam(input, output); + case IoctlCommand::Free: + return IocFree(input, output); } UNIMPLEMENTED_MSG("Unimplemented ioctl"); @@ -45,6 +47,7 @@ u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) { object->id = next_id++; object->size = params.size; object->status = Object::Status::Created; + object->refcount = 1; u32 handle = next_handle++; handles[handle] = std::move(object); @@ -101,6 +104,8 @@ u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) { [&](const auto& entry) { return entry.second->id == params.id; }); ASSERT(itr != handles.end()); + itr->second->refcount++; + // Return the existing handle instead of creating a new one. params.handle = itr->first; @@ -142,4 +147,34 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) { return 0; } +u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) { + enum FreeFlags { + Freed = 0, + NotFreedYet = 1, + }; + + IocFreeParams params; + std::memcpy(¶ms, input.data(), sizeof(params)); + + NGLOG_WARNING(Service_NVDRV, "(STUBBED) called"); + + auto itr = handles.find(params.handle); + ASSERT(itr != handles.end()); + + itr->second->refcount--; + + params.refcount = itr->second->refcount; + params.size = itr->second->size; + + if (itr->second->refcount == 0) + params.flags = Freed; + else + params.flags = NotFreedYet; + + handles.erase(params.handle); + + std::memcpy(output.data(), ¶ms, sizeof(params)); + return 0; +} + } // 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 431eb3773..5a3044167 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.h +++ b/src/core/hle/service/nvdrv/devices/nvmap.h @@ -34,6 +34,7 @@ public: u8 kind; VAddr addr; Status status; + u32 refcount; }; std::shared_ptr<Object> GetObject(u32 handle) const { @@ -59,7 +60,8 @@ private: FromId = 0xC0080103, Alloc = 0xC0200104, Param = 0xC00C0109, - GetId = 0xC008010E + GetId = 0xC008010E, + Free = 0xC0180105, }; struct IocCreateParams { @@ -102,11 +104,21 @@ private: u32_le value; }; + struct IocFreeParams { + u32_le handle; + INSERT_PADDING_BYTES(4); + u64_le refcount; + u32_le size; + u32_le flags; + }; + static_assert(sizeof(IocFreeParams) == 24, "IocFreeParams has wrong 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); }; } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index dc30702c6..5b91089cf 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -144,10 +144,12 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co rb.Push(RESULT_SUCCESS); return ResultCode(ErrorModule::HIPC, ErrorDescription::RemoteProcessDead); } + case IPC::CommandType::ControlWithContext: case IPC::CommandType::Control: { Core::System::GetInstance().ServiceManager().InvokeControlRequest(context); break; } + case IPC::CommandType::RequestWithContext: case IPC::CommandType::Request: { InvokeRequest(context); break; diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index e1ceec268..8ea26c9c1 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h @@ -193,6 +193,11 @@ union Instruction { BitField<50, 1, u64> abs_d; BitField<56, 1, u64> negate_imm; + union { + BitField<39, 3, u64> pred; + BitField<42, 1, u64> negate_pred; + } fmnmx; + float GetImm20_19() const { float result{}; u32 imm{static_cast<u32>(imm20_19)}; @@ -320,6 +325,7 @@ public: ISETP_C, ISETP_IMM, ISETP_R, + PSETP, }; enum class Type { @@ -331,6 +337,7 @@ public: FloatSet, FloatSetPredicate, IntegerSetPredicate, + PredicateSetPredicate, Conversion, Unknown, }; @@ -477,6 +484,7 @@ private: INST("010010110110----", Id::ISETP_C, Type::IntegerSetPredicate, "ISETP_C"), INST("010110110110----", Id::ISETP_R, Type::IntegerSetPredicate, "ISETP_R"), INST("0011011-0110----", Id::ISETP_IMM, Type::IntegerSetPredicate, "ISETP_IMM"), + INST("0101000010010---", Id::PSETP, Type::PredicateSetPredicate, "PSETP"), }; #undef INST std::stable_sort(table.begin(), table.end(), [](const auto& a, const auto& b) { diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp index 25984439d..5cefce9fc 100644 --- a/src/video_core/memory_manager.cpp +++ b/src/video_core/memory_manager.cpp @@ -58,6 +58,25 @@ GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, GPUVAddr gpu_addr, u64 size) return gpu_addr; } +GPUVAddr MemoryManager::UnmapBuffer(GPUVAddr gpu_addr, u64 size) { + ASSERT((gpu_addr & PAGE_MASK) == 0); + + for (u64 offset = 0; offset < size; offset += PAGE_SIZE) { + ASSERT(PageSlot(gpu_addr + offset) != static_cast<u64>(PageStatus::Allocated) && + PageSlot(gpu_addr + offset) != static_cast<u64>(PageStatus::Unmapped)); + PageSlot(gpu_addr + offset) = static_cast<u64>(PageStatus::Unmapped); + } + + // Delete the region mappings that are contained within the unmapped region + mapped_regions.erase(std::remove_if(mapped_regions.begin(), mapped_regions.end(), + [&](const MappedRegion& region) { + return region.gpu_addr <= gpu_addr && + region.gpu_addr + region.size < gpu_addr + size; + }), + mapped_regions.end()); + return gpu_addr; +} + boost::optional<GPUVAddr> MemoryManager::FindFreeBlock(u64 size, u64 align) { GPUVAddr gpu_addr = 0; u64 free_space = 0; diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h index 08140c83a..86765e72a 100644 --- a/src/video_core/memory_manager.h +++ b/src/video_core/memory_manager.h @@ -25,6 +25,7 @@ public: GPUVAddr AllocateSpace(GPUVAddr gpu_addr, u64 size, u64 align); GPUVAddr MapBufferEx(VAddr cpu_addr, u64 size); GPUVAddr MapBufferEx(VAddr cpu_addr, GPUVAddr gpu_addr, u64 size); + GPUVAddr UnmapBuffer(GPUVAddr gpu_addr, u64 size); boost::optional<VAddr> GpuToCpuAddress(GPUVAddr gpu_addr); std::vector<GPUVAddr> CpuToGpuAddress(VAddr cpu_addr) const; diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 907236136..35c1b1890 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -75,14 +75,11 @@ RasterizerOpenGL::RasterizerOpenGL() { // Clipping plane 0 is always enabled for PICA fixed clip plane z <= 0 state.clip_distance[0] = true; - // Generate VBO, VAO and UBO - vertex_buffer = OGLStreamBuffer::MakeBuffer(GLAD_GL_ARB_buffer_storage, GL_ARRAY_BUFFER); - vertex_buffer->Create(VERTEX_BUFFER_SIZE, VERTEX_BUFFER_SIZE / 2); + // Generate VAO and UBO sw_vao.Create(); uniform_buffer.Create(); state.draw.vertex_array = sw_vao.handle; - state.draw.vertex_buffer = vertex_buffer->GetHandle(); state.draw.uniform_buffer = uniform_buffer.handle; state.Apply(); @@ -90,7 +87,6 @@ RasterizerOpenGL::RasterizerOpenGL() { framebuffer.Create(); hw_vao.Create(); - hw_vao_enabled_attributes.fill(false); stream_buffer = OGLStreamBuffer::MakeBuffer(has_ARB_buffer_storage, GL_ARRAY_BUFFER); stream_buffer->Create(STREAM_BUFFER_SIZE, STREAM_BUFFER_SIZE / 2); @@ -181,8 +177,6 @@ std::pair<u8*, GLintptr> RasterizerOpenGL::SetupVertexArrays(u8* array_ptr, glVertexAttribFormat(index, attrib.ComponentCount(), MaxwellToGL::VertexType(attrib), attrib.IsNormalized() ? GL_TRUE : GL_FALSE, attrib.offset); glVertexAttribBinding(index, attrib.buffer); - - hw_vao_enabled_attributes[index] = true; } return {array_ptr, buffer_offset}; diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 9709e595e..4b915c76a 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -134,21 +134,17 @@ private: std::unique_ptr<GLShader::ProgramManager> shader_program_manager; OGLVertexArray sw_vao; OGLVertexArray hw_vao; - std::array<bool, 16> hw_vao_enabled_attributes; std::array<SamplerInfo, GLShader::NumTextureSamplers> texture_samplers; std::array<std::array<OGLBuffer, Tegra::Engines::Maxwell3D::Regs::MaxConstBuffers>, Tegra::Engines::Maxwell3D::Regs::MaxShaderStage> ssbos; - static constexpr size_t VERTEX_BUFFER_SIZE = 128 * 1024 * 1024; - std::unique_ptr<OGLStreamBuffer> vertex_buffer; + static constexpr size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024; + std::unique_ptr<OGLStreamBuffer> stream_buffer; OGLBuffer uniform_buffer; OGLFramebuffer framebuffer; - static constexpr size_t STREAM_BUFFER_SIZE = 4 * 1024 * 1024; - std::unique_ptr<OGLStreamBuffer> stream_buffer; - size_t CalculateVertexArraysSize() const; std::pair<u8*, GLintptr> SetupVertexArrays(u8* array_ptr, GLintptr buffer_offset); diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index abbf0893d..1aa24da46 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -580,14 +580,17 @@ private: * @param instr Instruction to generate the if condition for. * @returns string containing the predicate condition. */ - std::string GetPredicateCondition(Instruction instr) const { + std::string GetPredicateCondition(u64 index, bool negate) const { using Tegra::Shader::Pred; - ASSERT(instr.pred.pred_index != static_cast<u64>(Pred::UnusedIndex)); + std::string variable; - std::string variable = - 'p' + std::to_string(static_cast<u64>(instr.pred.pred_index.Value())); + // Index 7 is used as an 'Always True' condition. + if (index == static_cast<u64>(Pred::UnusedIndex)) + variable = "true"; + else + variable = 'p' + std::to_string(index); - if (instr.negate_pred) { + if (negate) { return "!(" + variable + ')'; } @@ -634,7 +637,9 @@ private: "NeverExecute predicate not implemented"); if (instr.pred.pred_index != static_cast<u64>(Pred::UnusedIndex)) { - shader.AddLine("if (" + GetPredicateCondition(instr) + ')'); + shader.AddLine("if (" + + GetPredicateCondition(instr.pred.pred_index, instr.negate_pred != 0) + + ')'); shader.AddLine('{'); ++shader.scope; } @@ -730,6 +735,16 @@ private: } break; } + case OpCode::Id::FMNMX: { + std::string condition = + GetPredicateCondition(instr.alu.fmnmx.pred, instr.alu.fmnmx.negate_pred != 0); + std::string parameters = op_a + ',' + op_b; + regs.SetRegisterToFloat(instr.gpr0, 0, + '(' + condition + ") ? min(" + parameters + ") : max(" + + parameters + ')', + 1, 1); + break; + } case OpCode::Id::RRO: { NGLOG_DEBUG(HW_GPU, "Skipping RRO instruction"); break; diff --git a/src/video_core/renderer_opengl/gl_shader_util.h b/src/video_core/renderer_opengl/gl_shader_util.h index a1fa9e814..2036a06a9 100644 --- a/src/video_core/renderer_opengl/gl_shader_util.h +++ b/src/video_core/renderer_opengl/gl_shader_util.h @@ -4,6 +4,7 @@ #pragma once +#include <string> #include <vector> #include <glad/glad.h> #include "common/assert.h" @@ -12,6 +13,27 @@ namespace GLShader { /** + * Utility function to log the source code of a list of shaders. + * @param shaders The OpenGL shaders whose source we will print. + */ +template <typename... T> +void LogShaderSource(T... shaders) { + auto shader_list = {shaders...}; + + for (const auto& shader : shader_list) { + if (shader == 0) + continue; + + GLint source_length; + glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &source_length); + + std::string source(source_length, ' '); + glGetShaderSource(shader, source_length, nullptr, &source[0]); + NGLOG_INFO(Render_OpenGL, "Shader source {}", source); + } +} + +/** * Utility function to create and compile an OpenGL GLSL shader * @param source String of the GLSL shader program * @param type Type of the shader (GL_VERTEX_SHADER, GL_GEOMETRY_SHADER or GL_FRAGMENT_SHADER) @@ -55,6 +77,11 @@ GLuint LoadProgram(bool separable_program, T... shaders) { } } + if (result == GL_FALSE) { + // There was a problem linking the shader, print the source for debugging purposes. + LogShaderSource(shaders...); + } + ASSERT_MSG(result == GL_TRUE, "Shader not linked"); ((shaders == 0 ? (void)0 : glDetachShader(program_id, shaders)), ...); diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index 8b074db5a..017bef13c 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp @@ -98,6 +98,30 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeMutexInfo::GetChildren() cons return list; } +WaitTreeCallstack::WaitTreeCallstack(const Kernel::Thread& thread) : thread(thread) {} + +QString WaitTreeCallstack::GetText() const { + return tr("Call stack"); +} + +std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() const { + std::vector<std::unique_ptr<WaitTreeItem>> list; + + constexpr size_t BaseRegister = 29; + u64 base_pointer = thread.context.cpu_registers[BaseRegister]; + + while (base_pointer != 0) { + u64 lr = Memory::Read64(base_pointer + sizeof(u64)); + if (lr == 0) + break; + list.push_back( + std::make_unique<WaitTreeText>(tr("0x%1").arg(lr - sizeof(u32), 16, 16, QChar('0')))); + base_pointer = Memory::Read64(base_pointer); + } + + return list; +} + WaitTreeWaitObject::WaitTreeWaitObject(const Kernel::WaitObject& o) : object(o) {} bool WaitTreeExpandableItem::IsExpandable() const { @@ -269,6 +293,8 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const { thread.IsSleepingOnWaitAll())); } + list.push_back(std::make_unique<WaitTreeCallstack>(thread)); + return list; } diff --git a/src/yuzu/debugger/wait_tree.h b/src/yuzu/debugger/wait_tree.h index 300ba9ae4..10fc9e968 100644 --- a/src/yuzu/debugger/wait_tree.h +++ b/src/yuzu/debugger/wait_tree.h @@ -73,6 +73,17 @@ private: Kernel::SharedPtr<Kernel::Thread> owner; }; +class WaitTreeCallstack : public WaitTreeExpandableItem { + Q_OBJECT +public: + explicit WaitTreeCallstack(const Kernel::Thread& thread); + QString GetText() const override; + std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override; + +private: + const Kernel::Thread& thread; +}; + class WaitTreeWaitObject : public WaitTreeExpandableItem { Q_OBJECT public: |