Merge pull request #2608 from ogniK5377/Time_GetSharedMemoryNativeHandle

Implement Time::GetSharedMemoryNativeHandle
This commit is contained in:
Zach Hilman 2019-07-03 20:22:23 -04:00 committed by GitHub
commit e86af37ecb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 260 additions and 28 deletions

View file

@ -430,6 +430,8 @@ add_library(core STATIC
hle/service/time/interface.h hle/service/time/interface.h
hle/service/time/time.cpp hle/service/time/time.cpp
hle/service/time/time.h 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.cpp
hle/service/usb/usb.h hle/service/usb/usb.h
hle/service/vi/display/vi_display.cpp hle/service/vi/display/vi_display.cpp

View file

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

View file

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

View file

@ -8,9 +8,12 @@
namespace Service::Time { namespace Service::Time {
class SharedMemory;
class Time final : public Module::Interface { class Time final : public Module::Interface {
public: 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; ~Time() override;
}; };

View file

@ -13,6 +13,7 @@
#include "core/hle/kernel/client_session.h" #include "core/hle/kernel/client_session.h"
#include "core/hle/service/time/interface.h" #include "core/hle/service/time/interface.h"
#include "core/hle/service/time/time.h" #include "core/hle/service/time/time.h"
#include "core/hle/service/time/time_sharedmemory.h"
#include "core/settings.h" #include "core/settings.h"
namespace Service::Time { namespace Service::Time {
@ -61,9 +62,18 @@ static u64 CalendarToPosix(const CalendarTime& calendar_time,
return static_cast<u64>(epoch_time); return static_cast<u64>(epoch_time);
} }
enum class ClockContextType {
StandardSteady,
StandardUserSystem,
StandardNetworkSystem,
StandardLocalSystem,
};
class ISystemClock final : public ServiceFramework<ISystemClock> { class ISystemClock final : public ServiceFramework<ISystemClock> {
public: 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[] = { static const FunctionInfo functions[] = {
{0, &ISystemClock::GetCurrentTime, "GetCurrentTime"}, {0, &ISystemClock::GetCurrentTime, "GetCurrentTime"},
{1, nullptr, "SetCurrentTime"}, {1, nullptr, "SetCurrentTime"},
@ -72,6 +82,8 @@ public:
}; };
RegisterHandlers(functions); RegisterHandlers(functions);
UpdateSharedMemoryContext(system_clock_context);
} }
private: private:
@ -87,34 +99,63 @@ private:
void GetSystemClockContext(Kernel::HLERequestContext& ctx) { void GetSystemClockContext(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_Time, "(STUBBED) called"); 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}; IPC::ResponseBuilder rb{ctx, (sizeof(SystemClockContext) / 4) + 2};
rb.Push(RESULT_SUCCESS); 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> { class ISteadyClock final : public ServiceFramework<ISteadyClock> {
public: public:
ISteadyClock() : ServiceFramework("ISteadyClock") { ISteadyClock(std::shared_ptr<SharedMemory> shared_memory)
: ServiceFramework("ISteadyClock"), shared_memory(shared_memory) {
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, &ISteadyClock::GetCurrentTimePoint, "GetCurrentTimePoint"}, {0, &ISteadyClock::GetCurrentTimePoint, "GetCurrentTimePoint"},
}; };
RegisterHandlers(functions); RegisterHandlers(functions);
shared_memory->SetStandardSteadyClockTimepoint(GetCurrentTimePoint());
} }
private: private:
void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) { void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called"); LOG_DEBUG(Service_Time, "called");
const auto& core_timing = Core::System::GetInstance().CoreTiming(); const auto time_point = GetCurrentTimePoint();
const auto ms = Core::Timing::CyclesToMs(core_timing.GetTicks()); // TODO(ogniK): This should be updated periodically
const SteadyClockTimePoint steady_clock_time_point{static_cast<u64_le>(ms.count() / 1000), shared_memory->SetStandardSteadyClockTimepoint(time_point);
{}};
IPC::ResponseBuilder rb{ctx, (sizeof(SteadyClockTimePoint) / 4) + 2}; IPC::ResponseBuilder rb{ctx, (sizeof(SteadyClockTimePoint) / 4) + 2};
rb.Push(RESULT_SUCCESS); 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> { class ITimeZoneService final : public ServiceFramework<ITimeZoneService> {
@ -233,7 +274,7 @@ void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ct
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISystemClock>(); rb.PushIpcInterface<ISystemClock>(shared_memory, ClockContextType::StandardUserSystem);
} }
void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx) { void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx) {
@ -241,7 +282,7 @@ void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext&
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISystemClock>(); rb.PushIpcInterface<ISystemClock>(shared_memory, ClockContextType::StandardNetworkSystem);
} }
void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) { 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}; IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISteadyClock>(); rb.PushIpcInterface<ISteadyClock>(shared_memory);
} }
void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) { 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}; IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISystemClock>(); rb.PushIpcInterface<ISystemClock>(shared_memory, ClockContextType::StandardLocalSystem);
} }
void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) { void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
@ -333,16 +374,52 @@ void Module::Interface::CalculateStandardUserSystemClockDifferenceByUser(
rb.PushRaw<u64>(difference); rb.PushRaw<u64>(difference);
} }
Module::Interface::Interface(std::shared_ptr<Module> time, const char* name) void Module::Interface::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
: ServiceFramework(name), time(std::move(time)) {} 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; Module::Interface::~Interface() = default;
void InstallInterfaces(SM::ServiceManager& service_manager) { void InstallInterfaces(Core::System& system) {
auto time = std::make_shared<Module>(); auto time = std::make_shared<Module>();
std::make_shared<Time>(time, "time:a")->InstallAsService(service_manager); auto shared_mem = std::make_shared<SharedMemory>(system);
std::make_shared<Time>(time, "time:s")->InstallAsService(service_manager);
std::make_shared<Time>(time, "time:u")->InstallAsService(service_manager); 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 } // namespace Service::Time

View file

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

View file

@ -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

View file

@ -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