skyline/app/src/main/cpp/switch/kernel/svc.cpp
◱ PixelyIon a54f5ff578 Milestone 2 - Memory & IPC Marshalling
This commit introduces a new memory model that supports true shared memory with separate permissions for remote and local processes, implements svcQueryMemory and completes svcGetInfo further, adds IPC support with the IpcRequest and IpcResponse classes.
2019-09-25 02:28:25 +05:30

175 lines
9.3 KiB
C++

#include <cstdint>
#include <string>
#include <syslog.h>
#include <utility>
#include "svc.h"
namespace lightSwitch::kernel::svc {
void SetHeapSize(device_state &state) {
auto heap = state.this_process->MapPrivateRegion(0, state.nce->GetRegister(wreg::w1), {true, true, false}, Memory::Type::Heap, Memory::Region::heap);
state.nce->SetRegister(wreg::w0, constant::status::success);
state.nce->SetRegister(xreg::x1, heap->address);
state.logger->Write(Logger::DEBUG, "Heap size was set to 0x{:X}", state.nce->GetRegister(wreg::w1));
}
void QueryMemory(device_state &state) {
Memory::MemoryInfo mem_inf;
u64 addr = state.nce->GetRegister(xreg::x2);
if (state.nce->memory_map.count(addr)) {
mem_inf = state.nce->memory_map.at(addr)->GetInfo(state.this_process->main_thread);
} else if (state.this_process->memory_map.count(addr)) {
mem_inf = state.this_process->memory_map.at(addr)->GetInfo();
} else {
state.nce->SetRegister(wreg::w0, constant::status::inv_address);
return;
}
state.this_process->WriteMemory<Memory::MemoryInfo>(mem_inf, state.nce->GetRegister(xreg::x0));
state.nce->SetRegister(wreg::w0, constant::status::success);
}
void CreateThread(device_state &state) {
// TODO: Check if the values supplied by the process are actually valid & Support Core Mask potentially ?
auto thread = state.this_process->CreateThread(state.nce->GetRegister(xreg::x1), state.nce->GetRegister(xreg::x2), state.nce->GetRegister(xreg::x3), static_cast<u8>(state.nce->GetRegister(wreg::w4)));
state.nce->SetRegister(wreg::w0, constant::status::success);
state.nce->SetRegister(wreg::w1, thread->handle);
}
void StartThread(device_state &state) {
auto &object = state.this_process->handle_table.at(static_cast<const unsigned int &>(state.nce->GetRegister(wreg::w0)));
if (object->type == type::KObjectType::KThread) {
std::static_pointer_cast<type::KThread>(object)->Start();
} else
throw exception("StartThread was called on a non-KThread object");
}
void ExitThread(device_state &state) {
state.os->KillThread(state.this_thread->pid);
}
void GetThreadPriority(device_state &state) {
auto &object = state.this_process->handle_table.at(static_cast<const unsigned int &>(state.nce->GetRegister(wreg::w0)));
if (object->type == type::KObjectType::KThread) {
state.nce->SetRegister(wreg::w0, constant::status::success);
state.nce->SetRegister(wreg::w1, std::static_pointer_cast<type::KThread>(object)->priority);
} else
throw exception("GetThreadPriority was called on a non-KThread object");
}
void SetThreadPriority(device_state &state) {
auto &object = state.this_process->handle_table.at(static_cast<const unsigned int &>(state.nce->GetRegister(wreg::w0)));
if (object->type == type::KObjectType::KThread) {
std::static_pointer_cast<type::KThread>(object)->Start();
} else
throw exception("SetThreadPriority was called on a non-KThread object");
}
void CloseHandle(device_state &state) {
auto &object = state.this_process->handle_table.at(static_cast<const unsigned int &>(state.nce->GetRegister(wreg::w0)));
switch (object->type) {
case (type::KObjectType::KThread):
state.os->KillThread(std::static_pointer_cast<type::KThread>(object)->pid);
break;
case (type::KObjectType::KProcess):
state.os->KillThread(std::static_pointer_cast<type::KProcess>(object)->main_thread);
break;
default:
state.nce->SetRegister(wreg::w0, constant::status::inv_handle);
return;
}
state.nce->SetRegister(wreg::w0, constant::status::success);
}
void ConnectToNamedPort(device_state &state) {
char port[constant::port_size]{0};
state.os->this_process->ReadMemory(port, state.nce->GetRegister(xreg::x1), constant::port_size);
if (std::strcmp(port, "sm:") == 0)
state.nce->SetRegister(wreg::w1, constant::sm_handle);
else
throw exception(fmt::format("svcConnectToNamedPort tried connecting to invalid port: \"{}\"", port));
state.nce->SetRegister(wreg::w0, constant::status::success);
}
void SendSyncRequest(device_state &state) {
state.logger->Write(Logger::DEBUG, "----------------------------svcSendSyncRequest Start-----------------------");
state.logger->Write(Logger::DEBUG, "svcSendSyncRequest called for handle 0x{:X}.", state.nce->GetRegister(xreg::x0));
state.os->IpcHandler(static_cast<handle_t>(state.nce->GetRegister(xreg::x0)));
state.nce->SetRegister(wreg::w0, constant::status::success);
state.nce->SetRegister(wreg::w19, constant::status::success);
state.logger->Write(Logger::DEBUG, "----------------------------svcSendSyncRequest End-------------------------");
}
void OutputDebugString(device_state &state) {
std::string debug(state.nce->GetRegister(xreg::x1), '\0');
state.os->this_process->ReadMemory((void *) debug.data(), state.nce->GetRegister(xreg::x0), state.nce->GetRegister(xreg::x1));
state.logger->Write(Logger::INFO, "svcOutputDebugString: {}", debug.c_str());
state.nce->SetRegister(wreg::w0, 0);
}
void GetInfo(device_state &state) {
state.logger->Write(Logger::DEBUG, "svcGetInfo called with ID0: {}, ID1: {}", state.nce->GetRegister(wreg::w1), state.nce->GetRegister(xreg::x3));
switch (state.nce->GetRegister(wreg::w1)) {
case constant::infoState::AllowedCpuIdBitmask:
case constant::infoState::AllowedThreadPriorityMask:
case constant::infoState::IsCurrentProcessBeingDebugged:
case constant::infoState::TitleId:
case constant::infoState::PrivilegedProcessId:
state.nce->SetRegister(xreg::x1, 0);
break;
case constant::infoState::AliasRegionBaseAddr:
state.nce->SetRegister(xreg::x1, constant::map_addr);
break;
case constant::infoState::AliasRegionSize:
state.nce->SetRegister(xreg::x1, constant::map_size);
break;
case constant::infoState::HeapRegionBaseAddr:
state.nce->SetRegister(xreg::x1, state.os->this_process->memory_region_map.at(Memory::Region::heap)->address);
break;
case constant::infoState::HeapRegionSize:
state.nce->SetRegister(xreg::x1, state.os->this_process->memory_region_map.at(Memory::Region::heap)->size);
break;
case constant::infoState::TotalMemoryAvailable:
state.nce->SetRegister(xreg::x1, constant::total_phy_mem);
break;
case constant::infoState::TotalMemoryUsage:
state.nce->SetRegister(xreg::x1, state.os->this_process->memory_region_map.at(Memory::Region::heap)->address + state.this_process->main_thread_stack_sz + state.nce->GetSharedSize());
break;
case constant::infoState::AddressSpaceBaseAddr:
state.nce->SetRegister(xreg::x1, constant::base_addr);
break;
case constant::infoState::AddressSpaceSize:
state.nce->SetRegister(xreg::x1, constant::base_size);
break;
case constant::infoState::StackRegionBaseAddr:
state.nce->SetRegister(xreg::x1, state.this_thread->stack_top);
break;
case constant::infoState::StackRegionSize:
state.nce->SetRegister(xreg::x1, state.this_process->main_thread_stack_sz);
break;
case constant::infoState::PersonalMmHeapSize:
state.nce->SetRegister(xreg::x1, constant::total_phy_mem);
break;
case constant::infoState::PersonalMmHeapUsage:
state.nce->SetRegister(xreg::x1, state.os->this_process->memory_region_map.at(Memory::Region::heap)->address + state.this_process->main_thread_stack_sz);
break;
case constant::infoState::TotalMemoryAvailableWithoutMmHeap:
state.nce->SetRegister(xreg::x1, constant::total_phy_mem); // TODO: NPDM specifies SystemResourceSize, subtract that from this
break;
case constant::infoState::TotalMemoryUsedWithoutMmHeap:
state.nce->SetRegister(xreg::x1, state.os->this_process->memory_region_map.at(Memory::Region::heap)->address + state.this_process->main_thread_stack_sz); // TODO: Same as above
break;
case constant::infoState::UserExceptionContextAddr:
state.nce->SetRegister(xreg::x1, state.this_process->tls_pages[0]->Get(0));
break;
default:
state.logger->Write(Logger::WARN, "Unimplemented svcGetInfo with ID0: {}, ID1: {}", state.nce->GetRegister(wreg::w1), state.nce->GetRegister(xreg::x3));
state.nce->SetRegister(wreg::w0, constant::status::unimpl);
return;
}
state.nce->SetRegister(wreg::w0, constant::status::success);
}
void ExitProcess(device_state &state) {
state.os->KillThread(state.this_process->main_thread);
}
}