dolphin/Source/Core/Core/IOS/DolphinDevice.cpp
Léo Lam 83c5446d85
Fix static initialisation order fiasco issue for Version variables
Fixes a crash that could occur if the static constructor function for
the MainSettings.cpp TU happened to run before the variables in
Common/Version.cpp are initialised. (This is known as the static
initialisation order fiasco.)

By using wrapper functions, those variables are now guaranteed to be
constructed on first use.
2022-01-14 00:04:22 +01:00

186 lines
4.5 KiB
C++

// Copyright 2019 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "Core/IOS/DolphinDevice.h"
#include <algorithm>
#include <cstring>
#include "Common/CommonPaths.h"
#include "Common/FileUtil.h"
#include "Common/IOFile.h"
#include "Common/Logging/Log.h"
#include "Common/NandPaths.h"
#include "Common/SettingsHandler.h"
#include "Common/Timer.h"
#include "Common/Version.h"
#include "Core/Config/MainSettings.h"
#include "Core/Core.h"
#include "Core/HW/Memmap.h"
namespace IOS::HLE
{
namespace
{
enum
{
IOCTL_DOLPHIN_GET_SYSTEM_TIME = 0x01,
IOCTL_DOLPHIN_GET_VERSION = 0x02,
IOCTL_DOLPHIN_GET_SPEED_LIMIT = 0x03,
IOCTL_DOLPHIN_SET_SPEED_LIMIT = 0x04,
IOCTL_DOLPHIN_GET_CPU_SPEED = 0x05,
IOCTL_DOLPHIN_GET_REAL_PRODUCTCODE = 0x06,
};
IPCReply GetSystemTime(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(0, 1))
{
return IPCReply(IPC_EINVAL);
}
if (request.io_vectors[0].size != 4)
{
return IPCReply(IPC_EINVAL);
}
const u32 milliseconds = Common::Timer::GetTimeMs();
Memory::Write_U32(milliseconds, request.io_vectors[0].address);
return IPCReply(IPC_SUCCESS);
}
IPCReply GetVersion(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(0, 1))
{
return IPCReply(IPC_EINVAL);
}
const auto length = std::min(size_t(request.io_vectors[0].size), Common::GetScmDescStr().size());
Memory::Memset(request.io_vectors[0].address, 0, request.io_vectors[0].size);
Memory::CopyToEmu(request.io_vectors[0].address, Common::GetScmDescStr().data(), length);
return IPCReply(IPC_SUCCESS);
}
IPCReply GetCPUSpeed(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(0, 1))
{
return IPCReply(IPC_EINVAL);
}
if (request.io_vectors[0].size != 4)
{
return IPCReply(IPC_EINVAL);
}
const bool overclock_enabled = Config::Get(Config::MAIN_OVERCLOCK_ENABLE);
const float oc = overclock_enabled ? Config::Get(Config::MAIN_OVERCLOCK) : 1.0f;
const u32 core_clock = u32(float(SystemTimers::GetTicksPerSecond()) * oc);
Memory::Write_U32(core_clock, request.io_vectors[0].address);
return IPCReply(IPC_SUCCESS);
}
IPCReply GetSpeedLimit(const IOCtlVRequest& request)
{
// get current speed limit
if (!request.HasNumberOfValidVectors(0, 1))
{
return IPCReply(IPC_EINVAL);
}
if (request.io_vectors[0].size != 4)
{
return IPCReply(IPC_EINVAL);
}
const u32 speed_percent = Config::Get(Config::MAIN_EMULATION_SPEED) * 100;
Memory::Write_U32(speed_percent, request.io_vectors[0].address);
return IPCReply(IPC_SUCCESS);
}
IPCReply SetSpeedLimit(const IOCtlVRequest& request)
{
// set current speed limit
if (!request.HasNumberOfValidVectors(1, 0))
{
return IPCReply(IPC_EINVAL);
}
if (request.in_vectors[0].size != 4)
{
return IPCReply(IPC_EINVAL);
}
const float speed = float(Memory::Read_U32(request.in_vectors[0].address)) / 100.0f;
Config::SetCurrent(Config::MAIN_EMULATION_SPEED, speed);
return IPCReply(IPC_SUCCESS);
}
IPCReply GetRealProductCode(const IOCtlVRequest& request)
{
if (!request.HasNumberOfValidVectors(0, 1))
{
return IPCReply(IPC_EINVAL);
}
const std::string backup_file_path = File::GetUserPath(D_BACKUP_IDX) + DIR_SEP + WII_SETTING;
File::IOFile file(backup_file_path, "rb");
if (!file)
return IPCReply(IPC_ENOENT);
Common::SettingsHandler::Buffer data;
if (!file.ReadBytes(data.data(), data.size()))
return IPCReply(IPC_ENOENT);
Common::SettingsHandler gen;
gen.SetBytes(std::move(data));
const std::string code = gen.GetValue("CODE");
const size_t length = std::min<size_t>(request.io_vectors[0].size, code.length());
if (length == 0)
return IPCReply(IPC_ENOENT);
Memory::Memset(request.io_vectors[0].address, 0, request.io_vectors[0].size);
Memory::CopyToEmu(request.io_vectors[0].address, code.c_str(), length);
return IPCReply(IPC_SUCCESS);
}
} // namespace
std::optional<IPCReply> DolphinDevice::IOCtlV(const IOCtlVRequest& request)
{
if (Core::WantsDeterminism())
return IPCReply(IPC_EACCES);
switch (request.request)
{
case IOCTL_DOLPHIN_GET_SYSTEM_TIME:
return GetSystemTime(request);
case IOCTL_DOLPHIN_GET_VERSION:
return GetVersion(request);
case IOCTL_DOLPHIN_GET_SPEED_LIMIT:
return GetSpeedLimit(request);
case IOCTL_DOLPHIN_SET_SPEED_LIMIT:
return SetSpeedLimit(request);
case IOCTL_DOLPHIN_GET_CPU_SPEED:
return GetCPUSpeed(request);
case IOCTL_DOLPHIN_GET_REAL_PRODUCTCODE:
return GetRealProductCode(request);
default:
return IPCReply(IPC_EINVAL);
}
}
} // namespace IOS::HLE