Ver código fonte

Merge pull request #2840 from Subv/apt_parameter

Services/APT: Corrected the behavior of the Receive/Send/Glance/CancelParameter functions
bunnei 9 anos atrás
pai
commit
f15e5522dc
2 arquivos alterados com 105 adições e 33 exclusões
  1. 99 33
      src/core/hle/service/apt/apt.cpp
  2. 6 0
      src/core/hle/service/apt/apt.h

+ 99 - 33
src/core/hle/service/apt/apt.cpp

@@ -2,6 +2,7 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include <boost/optional.hpp>
 #include "common/common_paths.h"
 #include "common/file_util.h"
 #include "common/logging/log.h"
@@ -44,7 +45,7 @@ static u8 unknown_ns_state_field;
 static ScreencapPostPermission screen_capture_post_permission;
 
 /// Parameter data to be returned in the next call to Glance/ReceiveParameter
-static MessageParameter next_parameter;
+static boost::optional<MessageParameter> next_parameter;
 
 void SendParameter(const MessageParameter& parameter) {
     next_parameter = parameter;
@@ -189,8 +190,20 @@ void SendParameter(Service::Interface* self) {
     std::shared_ptr<HLE::Applets::Applet> dest_applet =
         HLE::Applets::Applet::Get(static_cast<AppletId>(dst_app_id));
 
+    LOG_DEBUG(Service_APT,
+              "called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X,"
+              "buffer_size=0x%08X, handle=0x%08X, size=0x%08zX, in_param_buffer_ptr=0x%08X",
+              src_app_id, dst_app_id, signal_type, buffer_size, handle, size, buffer);
+
     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
 
+    // A new parameter can not be sent if the previous one hasn't been consumed yet
+    if (next_parameter) {
+        rb.Push(ResultCode(ErrCodes::ParameterPresent, ErrorModule::Applet,
+                           ErrorSummary::InvalidState, ErrorLevel::Status));
+        return;
+    }
+
     if (dest_applet == nullptr) {
         LOG_ERROR(Service_APT, "Unknown applet id=0x%08X", dst_app_id);
         rb.Push<u32>(-1); // TODO(Subv): Find the right error code
@@ -206,11 +219,6 @@ void SendParameter(Service::Interface* self) {
     Memory::ReadBlock(buffer, param.buffer.data(), param.buffer.size());
 
     rb.Push(dest_applet->ReceiveParameter(param));
-
-    LOG_WARNING(Service_APT,
-                "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X,"
-                "buffer_size=0x%08X, handle=0x%08X, size=0x%08zX, in_param_buffer_ptr=0x%08X",
-                src_app_id, dst_app_id, signal_type, buffer_size, handle, size, buffer);
 }
 
 void ReceiveParameter(Service::Interface* self) {
@@ -226,21 +234,40 @@ void ReceiveParameter(Service::Interface* self) {
             "buffer_size is bigger than the size in the buffer descriptor (0x%08X > 0x%08zX)",
             buffer_size, static_buff_size);
 
+    LOG_DEBUG(Service_APT, "called app_id=0x%08X, buffer_size=0x%08zX", app_id, buffer_size);
+
+    if (!next_parameter) {
+        IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+        rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::Applet,
+                           ErrorSummary::InvalidState, ErrorLevel::Status));
+        return;
+    }
+
+    if (next_parameter->destination_id != app_id) {
+        IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+        rb.Push(ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound,
+                           ErrorLevel::Status));
+        return;
+    }
+
     IPC::RequestBuilder rb = rp.MakeBuilder(4, 4);
+
     rb.Push(RESULT_SUCCESS); // No error
-    rb.Push(next_parameter.sender_id);
-    rb.Push(next_parameter.signal); // Signal type
-    ASSERT_MSG(next_parameter.buffer.size() <= buffer_size, "Input static buffer is too small !");
-    rb.Push(static_cast<u32>(next_parameter.buffer.size())); // Parameter buffer size
+    rb.Push(next_parameter->sender_id);
+    rb.Push(next_parameter->signal); // Signal type
+    ASSERT_MSG(next_parameter->buffer.size() <= buffer_size, "Input static buffer is too small !");
+    rb.Push(static_cast<u32>(next_parameter->buffer.size())); // Parameter buffer size
 
-    rb.PushMoveHandles((next_parameter.object != nullptr)
-                           ? Kernel::g_handle_table.Create(next_parameter.object).Unwrap()
+    rb.PushMoveHandles((next_parameter->object != nullptr)
+                           ? Kernel::g_handle_table.Create(next_parameter->object).Unwrap()
                            : 0);
-    rb.PushStaticBuffer(buffer, static_cast<u32>(next_parameter.buffer.size()), 0);
 
-    Memory::WriteBlock(buffer, next_parameter.buffer.data(), next_parameter.buffer.size());
+    rb.PushStaticBuffer(buffer, static_cast<u32>(next_parameter->buffer.size()), 0);
 
-    LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08zX", app_id, buffer_size);
+    Memory::WriteBlock(buffer, next_parameter->buffer.data(), next_parameter->buffer.size());
+
+    // Clear the parameter
+    next_parameter = boost::none;
 }
 
 void GlanceParameter(Service::Interface* self) {
@@ -256,37 +283,74 @@ void GlanceParameter(Service::Interface* self) {
             "buffer_size is bigger than the size in the buffer descriptor (0x%08X > 0x%08zX)",
             buffer_size, static_buff_size);
 
+    LOG_DEBUG(Service_APT, "called app_id=0x%08X, buffer_size=0x%08zX", app_id, buffer_size);
+
+    if (!next_parameter) {
+        IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+        rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::Applet,
+                           ErrorSummary::InvalidState, ErrorLevel::Status));
+        return;
+    }
+
+    if (next_parameter->destination_id != app_id) {
+        IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+        rb.Push(ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound,
+                           ErrorLevel::Status));
+        return;
+    }
+
     IPC::RequestBuilder rb = rp.MakeBuilder(4, 4);
     rb.Push(RESULT_SUCCESS); // No error
-    rb.Push(next_parameter.sender_id);
-    rb.Push(next_parameter.signal); // Signal type
-    ASSERT_MSG(next_parameter.buffer.size() <= buffer_size, "Input static buffer is too small !");
-    rb.Push(static_cast<u32>(next_parameter.buffer.size())); // Parameter buffer size
+    rb.Push(next_parameter->sender_id);
+    rb.Push(next_parameter->signal); // Signal type
+    ASSERT_MSG(next_parameter->buffer.size() <= buffer_size, "Input static buffer is too small !");
+    rb.Push(static_cast<u32>(next_parameter->buffer.size())); // Parameter buffer size
 
-    rb.PushCopyHandles((next_parameter.object != nullptr)
-                           ? Kernel::g_handle_table.Create(next_parameter.object).Unwrap()
+    rb.PushMoveHandles((next_parameter->object != nullptr)
+                           ? Kernel::g_handle_table.Create(next_parameter->object).Unwrap()
                            : 0);
-    rb.PushStaticBuffer(buffer, static_cast<u32>(next_parameter.buffer.size()), 0);
 
-    Memory::WriteBlock(buffer, next_parameter.buffer.data(), next_parameter.buffer.size());
+    rb.PushStaticBuffer(buffer, static_cast<u32>(next_parameter->buffer.size()), 0);
 
-    LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08zX", app_id, buffer_size);
+    Memory::WriteBlock(buffer, next_parameter->buffer.data(), next_parameter->buffer.size());
+
+    // Note: The NS module always clears the DSPSleep and DSPWakeup signals even in GlanceParameter.
+    if (next_parameter->signal == static_cast<u32>(SignalType::DspSleep) ||
+        next_parameter->signal == static_cast<u32>(SignalType::DspWakeup))
+        next_parameter = boost::none;
 }
 
 void CancelParameter(Service::Interface* self) {
     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xF, 4, 0); // 0xF0100
 
-    u32 check_sender = rp.Pop<u32>();
+    bool check_sender = rp.Pop<bool>();
     u32 sender_appid = rp.Pop<u32>();
-    u32 check_receiver = rp.Pop<u32>();
+    bool check_receiver = rp.Pop<bool>();
     u32 receiver_appid = rp.Pop<u32>();
+
+    bool cancellation_success = true;
+
+    if (!next_parameter) {
+        cancellation_success = false;
+    } else {
+        if (check_sender && next_parameter->sender_id != sender_appid)
+            cancellation_success = false;
+
+        if (check_receiver && next_parameter->destination_id != receiver_appid)
+            cancellation_success = false;
+    }
+
+    if (cancellation_success)
+        next_parameter = boost::none;
+
     IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
+
     rb.Push(RESULT_SUCCESS); // No error
-    rb.Push(true);           // Set to Success
+    rb.Push(cancellation_success);
 
-    LOG_WARNING(Service_APT, "(STUBBED) called check_sender=0x%08X, sender_appid=0x%08X, "
-                             "check_receiver=0x%08X, receiver_appid=0x%08X",
-                check_sender, sender_appid, check_receiver, receiver_appid);
+    LOG_DEBUG(Service_APT, "called check_sender=%u, sender_appid=0x%08X, "
+                           "check_receiver=%u, receiver_appid=0x%08X",
+              check_sender, sender_appid, check_receiver, receiver_appid);
 }
 
 void PrepareToStartApplication(Service::Interface* self) {
@@ -800,8 +864,10 @@ void Init() {
     notification_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "APT_U:Notification");
     parameter_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "APT_U:Start");
 
-    next_parameter.signal = static_cast<u32>(SignalType::Wakeup);
-    next_parameter.destination_id = 0x300;
+    // Initialize the parameter to wake up the application.
+    next_parameter.emplace();
+    next_parameter->signal = static_cast<u32>(SignalType::Wakeup);
+    next_parameter->destination_id = static_cast<u32>(AppletId::Application);
 }
 
 void Shutdown() {
@@ -812,7 +878,7 @@ void Shutdown() {
     notification_event = nullptr;
     parameter_event = nullptr;
 
-    next_parameter.object = nullptr;
+    next_parameter = boost::none;
 
     HLE::Applets::Shutdown();
 }

+ 6 - 0
src/core/hle/service/apt/apt.h

@@ -116,6 +116,12 @@ enum class ScreencapPostPermission : u32 {
     DisableScreenshotPostingToMiiverse = 3
 };
 
+namespace ErrCodes {
+enum {
+    ParameterPresent = 2,
+};
+}
+
 /// Send a parameter to the currently-running application, which will read it via ReceiveParameter
 void SendParameter(const MessageParameter& parameter);