390 lines
11 KiB
C++
390 lines
11 KiB
C++
/*
|
|
* Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms and conditions of the GNU General Public License,
|
|
* version 2, as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
/* --------------------------------------------------------------------------
|
|
* "THE BEER-WARE LICENSE" (Revision 42):
|
|
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
|
|
* wrote this file. As long as you retain this notice you can do whatever you
|
|
* want with this stuff. If you meet any of us some day, and you think this
|
|
* stuff is worth it, you can buy us a beer in return. - The sys-clk authors
|
|
* --------------------------------------------------------------------------
|
|
*/
|
|
|
|
|
|
#include "ipc_service.h"
|
|
#include <cstring>
|
|
#include <switch.h>
|
|
#include "file_utils.h"
|
|
#include "errors.h"
|
|
#include "clock_manager.h"
|
|
IpcService::IpcService(ClockManager* clockMgr)
|
|
{
|
|
std::int32_t priority;
|
|
Result rc = svcGetThreadPriority(&priority, CUR_THREAD_HANDLE);
|
|
ASSERT_RESULT_OK(rc, "svcGetThreadPriority");
|
|
rc = ipcServerInit(&this->server, SYSCLK_IPC_SERVICE_NAME, 42);
|
|
ASSERT_RESULT_OK(rc, "ipcServerInit");
|
|
rc = threadCreate(&this->thread, &IpcService::ProcessThreadFunc, this, NULL, 0x2000, priority, -2);
|
|
ASSERT_RESULT_OK(rc, "threadCreate");
|
|
|
|
this->running = false;
|
|
this->clockMgr = clockMgr;
|
|
|
|
}
|
|
|
|
void IpcService::SetRunning(bool running)
|
|
{
|
|
std::scoped_lock lock{this->threadMutex};
|
|
if(this->running == running)
|
|
{
|
|
return;
|
|
}
|
|
|
|
this->running = running;
|
|
|
|
if(running)
|
|
{
|
|
Result rc = threadStart(&this->thread);
|
|
ASSERT_RESULT_OK(rc, "threadStart");
|
|
}
|
|
else
|
|
{
|
|
svcCancelSynchronization(this->thread.handle);
|
|
threadWaitForExit(&this->thread);
|
|
}
|
|
}
|
|
|
|
IpcService::~IpcService()
|
|
{
|
|
this->SetRunning(false);
|
|
Result rc = threadClose(&this->thread);
|
|
ASSERT_RESULT_OK(rc, "threadClose");
|
|
rc = ipcServerExit(&this->server);
|
|
ASSERT_RESULT_OK(rc, "ipcServerExit");
|
|
}
|
|
|
|
void IpcService::ProcessThreadFunc(void* arg)
|
|
{
|
|
Result rc;
|
|
IpcService* ipcSrv = (IpcService*)arg;
|
|
while(true)
|
|
{
|
|
rc = ipcServerProcess(&ipcSrv->server, &IpcService::ServiceHandlerFunc, arg);
|
|
if(R_FAILED(rc))
|
|
{
|
|
if(rc == KERNELRESULT(Cancelled))
|
|
{
|
|
return;
|
|
}
|
|
if(rc != KERNELRESULT(ConnectionClosed))
|
|
{
|
|
FileUtils::LogLine("[ipc] ipcServerProcess: [0x%x] %04d-%04d", rc, R_MODULE(rc), R_DESCRIPTION(rc));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Result IpcService::ServiceHandlerFunc(void* arg, const IpcServerRequest* r, u8* out_data, size_t* out_dataSize)
|
|
{
|
|
IpcService* ipcSrv = (IpcService*)arg;
|
|
|
|
switch(r->data.cmdId)
|
|
{
|
|
case SysClkIpcCmd_GetApiVersion:
|
|
*out_dataSize = sizeof(u32);
|
|
return ipcSrv->GetApiVersion((u32*)out_data);
|
|
|
|
case SysClkIpcCmd_GetVersionString:
|
|
if(r->hipc.meta.num_recv_buffers >= 1)
|
|
{
|
|
return ipcSrv->GetVersionString(
|
|
(char*)hipcGetBufferAddress(r->hipc.data.recv_buffers),
|
|
hipcGetBufferSize(r->hipc.data.recv_buffers)
|
|
);
|
|
}
|
|
break;
|
|
|
|
case SysClkIpcCmd_GetCurrentContext:
|
|
*out_dataSize = sizeof(SysClkContext);
|
|
return ipcSrv->GetCurrentContext((SysClkContext*)out_data);
|
|
|
|
case SysClkIpcCmd_Exit:
|
|
return ipcSrv->Exit();
|
|
|
|
case SysClkIpcCmd_GetProfileCount:
|
|
if(r->data.size >= sizeof(std::uint64_t))
|
|
{
|
|
*out_dataSize = sizeof(std::uint8_t);
|
|
return ipcSrv->GetProfileCount((std::uint64_t*)r->data.ptr, (std::uint8_t*)out_data);
|
|
}
|
|
break;
|
|
|
|
case SysClkIpcCmd_GetProfiles:
|
|
if(r->data.size >= sizeof(std::uint64_t) && r->hipc.meta.num_recv_buffers >= 1)
|
|
{
|
|
size_t bufSize = hipcGetBufferSize(r->hipc.data.recv_buffers);
|
|
if(bufSize >= sizeof(SysClkTitleProfileList))
|
|
{
|
|
return ipcSrv->GetProfiles((std::uint64_t*)r->data.ptr, (SysClkTitleProfileList*)hipcGetBufferAddress(r->hipc.data.recv_buffers));
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SysClkIpcCmd_SetProfiles:
|
|
if(r->data.size >= sizeof(SysClkIpc_SetProfiles_Args))
|
|
{
|
|
return ipcSrv->SetProfiles((SysClkIpc_SetProfiles_Args*)r->data.ptr);
|
|
}
|
|
break;
|
|
|
|
case SysClkIpcCmd_SetEnabled:
|
|
if(r->data.size >= sizeof(std::uint8_t))
|
|
{
|
|
return ipcSrv->SetEnabled((std::uint8_t*)r->data.ptr);
|
|
}
|
|
break;
|
|
|
|
case SysClkIpcCmd_SetOverride:
|
|
if(r->data.size >= sizeof(SysClkIpc_SetOverride_Args))
|
|
{
|
|
return ipcSrv->SetOverride((SysClkIpc_SetOverride_Args*)r->data.ptr);
|
|
}
|
|
break;
|
|
|
|
case SysClkIpcCmd_GetConfigValues:
|
|
if(r->hipc.meta.num_recv_buffers >= 1)
|
|
{
|
|
size_t bufSize = hipcGetBufferSize(r->hipc.data.recv_buffers);
|
|
if(bufSize >= sizeof(SysClkConfigValueList))
|
|
{
|
|
return ipcSrv->GetConfigValues((SysClkConfigValueList*)hipcGetBufferAddress(r->hipc.data.recv_buffers));
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SysClkIpcCmd_SetConfigValues:
|
|
if(r->hipc.meta.num_send_buffers >= 1)
|
|
{
|
|
size_t bufSize = hipcGetBufferSize(r->hipc.data.send_buffers);
|
|
if(bufSize >= sizeof(SysClkConfigValueList))
|
|
{
|
|
return ipcSrv->SetConfigValues((SysClkConfigValueList*)hipcGetBufferAddress(r->hipc.data.send_buffers));
|
|
}
|
|
}
|
|
break;
|
|
case SysClkIpcCmd_GetFreqList:
|
|
if(r->data.size >= sizeof(SysClkIpc_GetFreqList_Args) && r->hipc.meta.num_recv_buffers >= 1)
|
|
{
|
|
*out_dataSize = sizeof(std::uint32_t);
|
|
return ipcSrv->GetFreqList(
|
|
(SysClkIpc_GetFreqList_Args*)r->data.ptr,
|
|
(std::uint32_t*)hipcGetBufferAddress(r->hipc.data.recv_buffers),
|
|
hipcGetBufferSize(r->hipc.data.recv_buffers),
|
|
(std::uint32_t*)out_data
|
|
);
|
|
}
|
|
break;
|
|
case SysClkIpcCmd_SetReverseNXRTMode:
|
|
if (r->data.size >= sizeof(ReverseNXMode)) {
|
|
ReverseNXMode mode = *((ReverseNXMode*)r->data.ptr);
|
|
return ipcSrv->SetReverseNXRTMode(mode);
|
|
}
|
|
break;
|
|
case HocClkIpcCmd_SetKipData:
|
|
if (r->data.size >= 0) {
|
|
return ipcSrv->SetKipData();
|
|
}
|
|
break;
|
|
case HocClkIpcCmd_UpdateEmcRegs:
|
|
if (r->data.size >= 0) {
|
|
return ipcSrv->UpdateEmcRegs();
|
|
}
|
|
break;
|
|
}
|
|
|
|
return SYSCLK_ERROR(Generic);
|
|
}
|
|
|
|
Result IpcService::GetApiVersion(u32* out_version)
|
|
{
|
|
*out_version = SYSCLK_IPC_API_VERSION;
|
|
|
|
return 0;
|
|
}
|
|
|
|
Result IpcService::GetVersionString(char* out_buf, size_t bufSize)
|
|
{
|
|
if(bufSize)
|
|
{
|
|
strncpy(out_buf, TARGET_VERSION, bufSize-1);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
Result IpcService::GetCurrentContext(SysClkContext* out_ctx)
|
|
{
|
|
*out_ctx = this->clockMgr->GetCurrentContext();
|
|
|
|
return 0;
|
|
}
|
|
|
|
Result IpcService::Exit()
|
|
{
|
|
this->clockMgr->SetRunning(false);
|
|
|
|
return 0;
|
|
}
|
|
|
|
Result IpcService::GetProfileCount(std::uint64_t* tid, std::uint8_t* out_count)
|
|
{
|
|
Config* config = this->clockMgr->GetConfig();
|
|
if(!config->HasProfilesLoaded())
|
|
{
|
|
return SYSCLK_ERROR(ConfigNotLoaded);
|
|
}
|
|
|
|
*out_count = config->GetProfileCount(*tid);
|
|
|
|
return 0;
|
|
}
|
|
|
|
Result IpcService::GetProfiles(std::uint64_t* tid, SysClkTitleProfileList* out_profiles)
|
|
{
|
|
Config* config = this->clockMgr->GetConfig();
|
|
if(!config->HasProfilesLoaded())
|
|
{
|
|
return SYSCLK_ERROR(ConfigNotLoaded);
|
|
}
|
|
|
|
config->GetProfiles(*tid, out_profiles);
|
|
|
|
return 0;
|
|
}
|
|
|
|
Result IpcService::SetProfiles(SysClkIpc_SetProfiles_Args* args)
|
|
{
|
|
Config* config = this->clockMgr->GetConfig();
|
|
if(!config->HasProfilesLoaded())
|
|
{
|
|
return SYSCLK_ERROR(ConfigNotLoaded);
|
|
}
|
|
|
|
SysClkTitleProfileList profiles = args->profiles;
|
|
|
|
if(!config->SetProfiles(args->tid, &profiles, true))
|
|
{
|
|
return SYSCLK_ERROR(ConfigSaveFailed);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
Result IpcService::SetEnabled(std::uint8_t* enabled)
|
|
{
|
|
Config* config = this->clockMgr->GetConfig();
|
|
config->SetEnabled(*enabled);
|
|
|
|
return 0;
|
|
}
|
|
|
|
Result IpcService::SetOverride(SysClkIpc_SetOverride_Args* args)
|
|
{
|
|
SysClkModule module = args->module;
|
|
std::uint32_t hz = args->hz;
|
|
|
|
if(!SYSCLK_ENUM_VALID(SysClkModule, args->module))
|
|
{
|
|
return SYSCLK_ERROR(Generic);
|
|
}
|
|
|
|
Config* config = this->clockMgr->GetConfig();
|
|
config->SetOverrideHz(module, hz);
|
|
|
|
return 0;
|
|
}
|
|
|
|
Result IpcService::GetConfigValues(SysClkConfigValueList* out_configValues)
|
|
{
|
|
Config* config = this->clockMgr->GetConfig();
|
|
if(!config->HasProfilesLoaded())
|
|
{
|
|
return SYSCLK_ERROR(ConfigNotLoaded);
|
|
}
|
|
|
|
config->GetConfigValues(out_configValues);
|
|
|
|
return 0;
|
|
}
|
|
|
|
Result IpcService::SetConfigValues(SysClkConfigValueList* configValues)
|
|
{
|
|
Config* config = this->clockMgr->GetConfig();
|
|
if(!config->HasProfilesLoaded())
|
|
{
|
|
return SYSCLK_ERROR(ConfigNotLoaded);
|
|
}
|
|
|
|
SysClkConfigValueList configValuesCopy = *configValues;
|
|
|
|
if(!config->SetConfigValues(&configValuesCopy, true))
|
|
{
|
|
return SYSCLK_ERROR(ConfigSaveFailed);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
Result IpcService::GetFreqList(SysClkIpc_GetFreqList_Args* args, std::uint32_t* out_list, std::size_t size, std::uint32_t* out_count)
|
|
{
|
|
if(!SYSCLK_ENUM_VALID(SysClkModule, args->module))
|
|
{
|
|
return SYSCLK_ERROR(Generic);
|
|
}
|
|
|
|
if(args->maxCount != size/sizeof(*out_list))
|
|
{
|
|
return SYSCLK_ERROR(Generic);
|
|
}
|
|
|
|
this->clockMgr->GetFreqList(args->module, out_list, args->maxCount, out_count);
|
|
|
|
return 0;
|
|
}
|
|
|
|
Result IpcService::SetReverseNXRTMode(ReverseNXMode mode) {
|
|
return 0;
|
|
}
|
|
|
|
Result IpcService::SetKipData() {
|
|
this->clockMgr->SetKipData();
|
|
|
|
return 0;
|
|
}
|
|
|
|
Result IpcService::GetKipData() {
|
|
this->clockMgr->GetKipData();
|
|
|
|
return 0;
|
|
}
|
|
|
|
Result IpcService::UpdateEmcRegs() {
|
|
this->clockMgr->UpdateRamTimings();
|
|
|
|
return 0;
|
|
}
|