mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-30 17:46:48 +01:00
83c5446d85
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.
186 lines
4.5 KiB
C++
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
|