Przeglądaj źródła

Merge pull request #2608 from ogniK5377/Time_GetSharedMemoryNativeHandle

Implement Time::GetSharedMemoryNativeHandle
Zach Hilman 7 lat temu
rodzic
commit
e86af37ecb

+ 2 - 0
src/core/CMakeLists.txt

@@ -430,6 +430,8 @@ add_library(core STATIC
     hle/service/time/interface.h
     hle/service/time/time.cpp
     hle/service/time/time.h
+    hle/service/time/time_sharedmemory.cpp
+    hle/service/time/time_sharedmemory.h
     hle/service/usb/usb.cpp
     hle/service/usb/usb.h
     hle/service/vi/display/vi_display.cpp

+ 1 - 1
src/core/hle/service/service.cpp

@@ -249,7 +249,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system,
     Sockets::InstallInterfaces(*sm);
     SPL::InstallInterfaces(*sm);
     SSL::InstallInterfaces(*sm);
-    Time::InstallInterfaces(*sm);
+    Time::InstallInterfaces(system);
     USB::InstallInterfaces(*sm);
     VI::InstallInterfaces(*sm, nv_flinger);
     WLAN::InstallInterfaces(*sm);

+ 6 - 5
src/core/hle/service/time/interface.cpp

@@ -6,8 +6,9 @@
 
 namespace Service::Time {
 
-Time::Time(std::shared_ptr<Module> time, const char* name)
-    : Module::Interface(std::move(time), name) {
+Time::Time(std::shared_ptr<Module> time, std::shared_ptr<SharedMemory> shared_memory,
+           const char* name)
+    : Module::Interface(std::move(time), std::move(shared_memory), name) {
     // clang-format off
     static const FunctionInfo functions[] = {
         {0, &Time::GetStandardUserSystemClock, "GetStandardUserSystemClock"},
@@ -16,12 +17,12 @@ Time::Time(std::shared_ptr<Module> time, const char* name)
         {3, &Time::GetTimeZoneService, "GetTimeZoneService"},
         {4, &Time::GetStandardLocalSystemClock, "GetStandardLocalSystemClock"},
         {5, nullptr, "GetEphemeralNetworkSystemClock"},
-        {20, nullptr, "GetSharedMemoryNativeHandle"},
+        {20, &Time::GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"},
         {30, nullptr, "GetStandardNetworkClockOperationEventReadableHandle"},
         {31, nullptr, "GetEphemeralNetworkClockOperationEventReadableHandle"},
         {50, nullptr, "SetStandardSteadyClockInternalOffset"},
-        {100, nullptr, "IsStandardUserSystemClockAutomaticCorrectionEnabled"},
-        {101, nullptr, "SetStandardUserSystemClockAutomaticCorrectionEnabled"},
+        {100, &Time::IsStandardUserSystemClockAutomaticCorrectionEnabled, "IsStandardUserSystemClockAutomaticCorrectionEnabled"},
+        {101, &Time::SetStandardUserSystemClockAutomaticCorrectionEnabled, "SetStandardUserSystemClockAutomaticCorrectionEnabled"},
         {102, nullptr, "GetStandardUserSystemClockInitialYear"},
         {200, nullptr, "IsStandardNetworkSystemClockAccuracySufficient"},
         {201, nullptr, "GetStandardUserSystemClockAutomaticCorrectionUpdatedTime"},

+ 4 - 1
src/core/hle/service/time/interface.h

@@ -8,9 +8,12 @@
 
 namespace Service::Time {
 
+class SharedMemory;
+
 class Time final : public Module::Interface {
 public:
-    explicit Time(std::shared_ptr<Module> time, const char* name);
+    explicit Time(std::shared_ptr<Module> time, std::shared_ptr<SharedMemory> shared_memory,
+                  const char* name);
     ~Time() override;
 };
 

+ 96 - 19
src/core/hle/service/time/time.cpp

@@ -13,6 +13,7 @@
 #include "core/hle/kernel/client_session.h"
 #include "core/hle/service/time/interface.h"
 #include "core/hle/service/time/time.h"
+#include "core/hle/service/time/time_sharedmemory.h"
 #include "core/settings.h"
 
 namespace Service::Time {
@@ -61,9 +62,18 @@ static u64 CalendarToPosix(const CalendarTime& calendar_time,
     return static_cast<u64>(epoch_time);
 }
 
+enum class ClockContextType {
+    StandardSteady,
+    StandardUserSystem,
+    StandardNetworkSystem,
+    StandardLocalSystem,
+};
+
 class ISystemClock final : public ServiceFramework<ISystemClock> {
 public:
-    ISystemClock() : ServiceFramework("ISystemClock") {
+    ISystemClock(std::shared_ptr<Service::Time::SharedMemory> shared_memory,
+                 ClockContextType clock_type)
+        : ServiceFramework("ISystemClock"), shared_memory(shared_memory), clock_type(clock_type) {
         static const FunctionInfo functions[] = {
             {0, &ISystemClock::GetCurrentTime, "GetCurrentTime"},
             {1, nullptr, "SetCurrentTime"},
@@ -72,6 +82,8 @@ public:
 
         };
         RegisterHandlers(functions);
+
+        UpdateSharedMemoryContext(system_clock_context);
     }
 
 private:
@@ -87,34 +99,63 @@ private:
     void GetSystemClockContext(Kernel::HLERequestContext& ctx) {
         LOG_WARNING(Service_Time, "(STUBBED) called");
 
-        SystemClockContext system_clock_ontext{};
+        // TODO(ogniK): This should be updated periodically however since we have it stubbed we'll
+        // only update when we get a new context
+        UpdateSharedMemoryContext(system_clock_context);
+
         IPC::ResponseBuilder rb{ctx, (sizeof(SystemClockContext) / 4) + 2};
         rb.Push(RESULT_SUCCESS);
-        rb.PushRaw(system_clock_ontext);
+        rb.PushRaw(system_clock_context);
     }
+
+    void UpdateSharedMemoryContext(const SystemClockContext& clock_context) {
+        switch (clock_type) {
+        case ClockContextType::StandardLocalSystem:
+            shared_memory->SetStandardLocalSystemClockContext(clock_context);
+            break;
+        case ClockContextType::StandardNetworkSystem:
+            shared_memory->SetStandardNetworkSystemClockContext(clock_context);
+            break;
+        }
+    }
+
+    SystemClockContext system_clock_context{};
+    std::shared_ptr<Service::Time::SharedMemory> shared_memory;
+    ClockContextType clock_type;
 };
 
 class ISteadyClock final : public ServiceFramework<ISteadyClock> {
 public:
-    ISteadyClock() : ServiceFramework("ISteadyClock") {
+    ISteadyClock(std::shared_ptr<SharedMemory> shared_memory)
+        : ServiceFramework("ISteadyClock"), shared_memory(shared_memory) {
         static const FunctionInfo functions[] = {
             {0, &ISteadyClock::GetCurrentTimePoint, "GetCurrentTimePoint"},
         };
         RegisterHandlers(functions);
+
+        shared_memory->SetStandardSteadyClockTimepoint(GetCurrentTimePoint());
     }
 
 private:
     void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) {
         LOG_DEBUG(Service_Time, "called");
 
-        const auto& core_timing = Core::System::GetInstance().CoreTiming();
-        const auto ms = Core::Timing::CyclesToMs(core_timing.GetTicks());
-        const SteadyClockTimePoint steady_clock_time_point{static_cast<u64_le>(ms.count() / 1000),
-                                                           {}};
+        const auto time_point = GetCurrentTimePoint();
+        // TODO(ogniK): This should be updated periodically
+        shared_memory->SetStandardSteadyClockTimepoint(time_point);
+
         IPC::ResponseBuilder rb{ctx, (sizeof(SteadyClockTimePoint) / 4) + 2};
         rb.Push(RESULT_SUCCESS);
-        rb.PushRaw(steady_clock_time_point);
+        rb.PushRaw(time_point);
     }
+
+    SteadyClockTimePoint GetCurrentTimePoint() const {
+        const auto& core_timing = Core::System::GetInstance().CoreTiming();
+        const auto ms = Core::Timing::CyclesToMs(core_timing.GetTicks());
+        return {static_cast<u64_le>(ms.count() / 1000), {}};
+    }
+
+    std::shared_ptr<SharedMemory> shared_memory;
 };
 
 class ITimeZoneService final : public ServiceFramework<ITimeZoneService> {
@@ -233,7 +274,7 @@ void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ct
 
     IPC::ResponseBuilder rb{ctx, 2, 0, 1};
     rb.Push(RESULT_SUCCESS);
-    rb.PushIpcInterface<ISystemClock>();
+    rb.PushIpcInterface<ISystemClock>(shared_memory, ClockContextType::StandardUserSystem);
 }
 
 void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx) {
@@ -241,7 +282,7 @@ void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext&
 
     IPC::ResponseBuilder rb{ctx, 2, 0, 1};
     rb.Push(RESULT_SUCCESS);
-    rb.PushIpcInterface<ISystemClock>();
+    rb.PushIpcInterface<ISystemClock>(shared_memory, ClockContextType::StandardNetworkSystem);
 }
 
 void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) {
@@ -249,7 +290,7 @@ void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) {
 
     IPC::ResponseBuilder rb{ctx, 2, 0, 1};
     rb.Push(RESULT_SUCCESS);
-    rb.PushIpcInterface<ISteadyClock>();
+    rb.PushIpcInterface<ISteadyClock>(shared_memory);
 }
 
 void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) {
@@ -265,7 +306,7 @@ void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& c
 
     IPC::ResponseBuilder rb{ctx, 2, 0, 1};
     rb.Push(RESULT_SUCCESS);
-    rb.PushIpcInterface<ISystemClock>();
+    rb.PushIpcInterface<ISystemClock>(shared_memory, ClockContextType::StandardLocalSystem);
 }
 
 void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
@@ -333,16 +374,52 @@ void Module::Interface::CalculateStandardUserSystemClockDifferenceByUser(
     rb.PushRaw<u64>(difference);
 }
 
-Module::Interface::Interface(std::shared_ptr<Module> time, const char* name)
-    : ServiceFramework(name), time(std::move(time)) {}
+void Module::Interface::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
+    LOG_DEBUG(Service_Time, "called");
+    IPC::ResponseBuilder rb{ctx, 2, 1};
+    rb.Push(RESULT_SUCCESS);
+    rb.PushCopyObjects(shared_memory->GetSharedMemoryHolder());
+}
+
+void Module::Interface::IsStandardUserSystemClockAutomaticCorrectionEnabled(
+    Kernel::HLERequestContext& ctx) {
+    // ogniK(TODO): When clock contexts are implemented, the value should be read from the context
+    // instead of our shared memory holder
+    LOG_DEBUG(Service_Time, "called");
+
+    IPC::ResponseBuilder rb{ctx, 3};
+    rb.Push(RESULT_SUCCESS);
+    rb.Push<u8>(shared_memory->GetStandardUserSystemClockAutomaticCorrectionEnabled());
+}
+
+void Module::Interface::SetStandardUserSystemClockAutomaticCorrectionEnabled(
+    Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto enabled = rp.Pop<u8>();
+
+    LOG_WARNING(Service_Time, "(PARTIAL IMPLEMENTATION) called");
+
+    // TODO(ogniK): Update clock contexts and correct timespans
+
+    shared_memory->SetStandardUserSystemClockAutomaticCorrectionEnabled(enabled > 0);
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
+
+Module::Interface::Interface(std::shared_ptr<Module> time,
+                             std::shared_ptr<SharedMemory> shared_memory, const char* name)
+    : ServiceFramework(name), time(std::move(time)), shared_memory(std::move(shared_memory)) {}
 
 Module::Interface::~Interface() = default;
 
-void InstallInterfaces(SM::ServiceManager& service_manager) {
+void InstallInterfaces(Core::System& system) {
     auto time = std::make_shared<Module>();
-    std::make_shared<Time>(time, "time:a")->InstallAsService(service_manager);
-    std::make_shared<Time>(time, "time:s")->InstallAsService(service_manager);
-    std::make_shared<Time>(time, "time:u")->InstallAsService(service_manager);
+    auto shared_mem = std::make_shared<SharedMemory>(system);
+
+    std::make_shared<Time>(time, shared_mem, "time:a")->InstallAsService(system.ServiceManager());
+    std::make_shared<Time>(time, shared_mem, "time:s")->InstallAsService(system.ServiceManager());
+    std::make_shared<Time>(std::move(time), shared_mem, "time:u")
+        ->InstallAsService(system.ServiceManager());
 }
 
 } // namespace Service::Time

+ 9 - 2
src/core/hle/service/time/time.h

@@ -10,6 +10,8 @@
 
 namespace Service::Time {
 
+class SharedMemory;
+
 struct LocationName {
     std::array<u8, 0x24> name;
 };
@@ -77,7 +79,8 @@ class Module final {
 public:
     class Interface : public ServiceFramework<Interface> {
     public:
-        explicit Interface(std::shared_ptr<Module> time, const char* name);
+        explicit Interface(std::shared_ptr<Module> time,
+                           std::shared_ptr<SharedMemory> shared_memory, const char* name);
         ~Interface() override;
 
         void GetStandardUserSystemClock(Kernel::HLERequestContext& ctx);
@@ -87,13 +90,17 @@ public:
         void GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx);
         void GetClockSnapshot(Kernel::HLERequestContext& ctx);
         void CalculateStandardUserSystemClockDifferenceByUser(Kernel::HLERequestContext& ctx);
+        void GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx);
+        void IsStandardUserSystemClockAutomaticCorrectionEnabled(Kernel::HLERequestContext& ctx);
+        void SetStandardUserSystemClockAutomaticCorrectionEnabled(Kernel::HLERequestContext& ctx);
 
     protected:
         std::shared_ptr<Module> time;
+        std::shared_ptr<SharedMemory> shared_memory;
     };
 };
 
 /// Registers all Time services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager);
+void InstallInterfaces(Core::System& system);
 
 } // namespace Service::Time

+ 68 - 0
src/core/hle/service/time/time_sharedmemory.cpp

@@ -0,0 +1,68 @@
+// Copyright 2019 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/core.h"
+#include "core/hle/service/time/time_sharedmemory.h"
+
+namespace Service::Time {
+const std::size_t SHARED_MEMORY_SIZE = 0x1000;
+
+SharedMemory::SharedMemory(Core::System& system) : system(system) {
+    shared_memory_holder = Kernel::SharedMemory::Create(
+        system.Kernel(), nullptr, SHARED_MEMORY_SIZE, Kernel::MemoryPermission::ReadWrite,
+        Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "Time:SharedMemory");
+
+    // Seems static from 1.0.0 -> 8.1.0. Specific games seem to check this value and crash
+    // if it's set to anything else
+    shared_memory_format.format_version = 14;
+    std::memcpy(shared_memory_holder->GetPointer(), &shared_memory_format, sizeof(Format));
+}
+
+SharedMemory::~SharedMemory() = default;
+
+Kernel::SharedPtr<Kernel::SharedMemory> SharedMemory::GetSharedMemoryHolder() const {
+    return shared_memory_holder;
+}
+
+void SharedMemory::SetStandardSteadyClockTimepoint(const SteadyClockTimePoint& timepoint) {
+    shared_memory_format.standard_steady_clock_timepoint.StoreData(
+        shared_memory_holder->GetPointer(), timepoint);
+}
+
+void SharedMemory::SetStandardLocalSystemClockContext(const SystemClockContext& context) {
+    shared_memory_format.standard_local_system_clock_context.StoreData(
+        shared_memory_holder->GetPointer(), context);
+}
+
+void SharedMemory::SetStandardNetworkSystemClockContext(const SystemClockContext& context) {
+    shared_memory_format.standard_network_system_clock_context.StoreData(
+        shared_memory_holder->GetPointer(), context);
+}
+
+void SharedMemory::SetStandardUserSystemClockAutomaticCorrectionEnabled(bool enabled) {
+    shared_memory_format.standard_user_system_clock_automatic_correction.StoreData(
+        shared_memory_holder->GetPointer(), enabled);
+}
+
+SteadyClockTimePoint SharedMemory::GetStandardSteadyClockTimepoint() {
+    return shared_memory_format.standard_steady_clock_timepoint.ReadData(
+        shared_memory_holder->GetPointer());
+}
+
+SystemClockContext SharedMemory::GetStandardLocalSystemClockContext() {
+    return shared_memory_format.standard_local_system_clock_context.ReadData(
+        shared_memory_holder->GetPointer());
+}
+
+SystemClockContext SharedMemory::GetStandardNetworkSystemClockContext() {
+    return shared_memory_format.standard_network_system_clock_context.ReadData(
+        shared_memory_holder->GetPointer());
+}
+
+bool SharedMemory::GetStandardUserSystemClockAutomaticCorrectionEnabled() {
+    return shared_memory_format.standard_user_system_clock_automatic_correction.ReadData(
+        shared_memory_holder->GetPointer());
+}
+
+} // namespace Service::Time

+ 74 - 0
src/core/hle/service/time/time_sharedmemory.h

@@ -0,0 +1,74 @@
+// Copyright 2019 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common_types.h"
+#include "core/hle/kernel/shared_memory.h"
+#include "core/hle/service/time/time.h"
+
+namespace Service::Time {
+class SharedMemory {
+public:
+    explicit SharedMemory(Core::System& system);
+    ~SharedMemory();
+
+    // Return the shared memory handle
+    Kernel::SharedPtr<Kernel::SharedMemory> GetSharedMemoryHolder() const;
+
+    // Set memory barriers in shared memory and update them
+    void SetStandardSteadyClockTimepoint(const SteadyClockTimePoint& timepoint);
+    void SetStandardLocalSystemClockContext(const SystemClockContext& context);
+    void SetStandardNetworkSystemClockContext(const SystemClockContext& context);
+    void SetStandardUserSystemClockAutomaticCorrectionEnabled(bool enabled);
+
+    // Pull from memory barriers in the shared memory
+    SteadyClockTimePoint GetStandardSteadyClockTimepoint();
+    SystemClockContext GetStandardLocalSystemClockContext();
+    SystemClockContext GetStandardNetworkSystemClockContext();
+    bool GetStandardUserSystemClockAutomaticCorrectionEnabled();
+
+    // TODO(ogniK): We have to properly simulate memory barriers, how are we going to do this?
+    template <typename T, std::size_t Offset>
+    struct MemoryBarrier {
+        static_assert(std::is_trivially_constructible_v<T>, "T must be trivially constructable");
+        u32_le read_attempt{};
+        std::array<T, 2> data{};
+
+        // These are not actually memory barriers at the moment as we don't have multicore and all
+        // HLE is mutexed. This will need to properly be implemented when we start updating the time
+        // points on threads. As of right now, we'll be updated both values synchronously and just
+        // incrementing the read_attempt to indicate that we waited.
+        void StoreData(u8* shared_memory, T data_to_store) {
+            std::memcpy(this, shared_memory + Offset, sizeof(*this));
+            read_attempt++;
+            data[read_attempt & 1] = data_to_store;
+            std::memcpy(shared_memory + Offset, this, sizeof(*this));
+        }
+
+        // For reading we're just going to read the last stored value. If there was no value stored
+        // it will just end up reading an empty value as intended.
+        T ReadData(u8* shared_memory) {
+            std::memcpy(this, shared_memory + Offset, sizeof(*this));
+            return data[(read_attempt - 1) & 1];
+        }
+    };
+
+    // Shared memory format
+    struct Format {
+        MemoryBarrier<SteadyClockTimePoint, 0x0> standard_steady_clock_timepoint;
+        MemoryBarrier<SystemClockContext, 0x38> standard_local_system_clock_context;
+        MemoryBarrier<SystemClockContext, 0x80> standard_network_system_clock_context;
+        MemoryBarrier<bool, 0xc8> standard_user_system_clock_automatic_correction;
+        u32_le format_version;
+    };
+    static_assert(sizeof(Format) == 0xd8, "Format is an invalid size");
+
+private:
+    Kernel::SharedPtr<Kernel::SharedMemory> shared_memory_holder{};
+    Core::System& system;
+    Format shared_memory_format{};
+};
+
+} // namespace Service::Time