#include #include #include #include #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(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(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(state.nce->GetRegister(wreg::w0))); if (object->type == type::KObjectType::KThread) { std::static_pointer_cast(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(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(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(state.nce->GetRegister(wreg::w0))); if (object->type == type::KObjectType::KThread) { std::static_pointer_cast(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(state.nce->GetRegister(wreg::w0))); switch (object->type) { case (type::KObjectType::KThread): state.os->KillThread(std::static_pointer_cast(object)->pid); break; case (type::KObjectType::KProcess): state.os->KillThread(std::static_pointer_cast(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(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); } }