2023-07-13 02:54:02 +01:00
|
|
|
// Copyright 2019 Citra Emulator Project
|
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
2018-09-11 21:00:12 +01:00
|
|
|
#include "common/logging/log.h"
|
|
|
|
#include "core/core.h"
|
|
|
|
#include "core/memory.h"
|
|
|
|
#include "core/rpc/packet.h"
|
|
|
|
#include "core/rpc/rpc_server.h"
|
|
|
|
|
2023-07-13 02:54:02 +01:00
|
|
|
namespace Core::RPC {
|
2018-09-11 21:00:12 +01:00
|
|
|
|
2023-07-13 02:54:02 +01:00
|
|
|
RPCServer::RPCServer(Core::System& system_) : system{system_}, server{*this} {
|
|
|
|
LOG_INFO(RPC_Server, "Starting RPC server.");
|
|
|
|
request_handler_thread =
|
|
|
|
std::jthread([this](std::stop_token stop_token) { HandleRequestsLoop(stop_token); });
|
2018-09-11 21:00:12 +01:00
|
|
|
}
|
|
|
|
|
2023-07-13 02:54:02 +01:00
|
|
|
RPCServer::~RPCServer() = default;
|
2018-09-11 21:00:12 +01:00
|
|
|
|
|
|
|
void RPCServer::HandleReadMemory(Packet& packet, u32 address, u32 data_size) {
|
|
|
|
if (data_size > MAX_READ_SIZE) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Note: Memory read occurs asynchronously from the state of the emulator
|
2023-07-13 02:54:02 +01:00
|
|
|
system.Memory().ReadBlock(address, packet.GetPacketData().data(), data_size);
|
2018-09-11 21:00:12 +01:00
|
|
|
packet.SetPacketDataSize(data_size);
|
|
|
|
packet.SendReply();
|
|
|
|
}
|
|
|
|
|
2023-07-06 23:52:40 +01:00
|
|
|
void RPCServer::HandleWriteMemory(Packet& packet, u32 address, std::span<const u8> data) {
|
2018-09-11 21:00:12 +01:00
|
|
|
// Only allow writing to certain memory regions
|
|
|
|
if ((address >= Memory::PROCESS_IMAGE_VADDR && address <= Memory::PROCESS_IMAGE_VADDR_END) ||
|
|
|
|
(address >= Memory::HEAP_VADDR && address <= Memory::HEAP_VADDR_END) ||
|
|
|
|
(address >= Memory::N3DS_EXTRA_RAM_VADDR && address <= Memory::N3DS_EXTRA_RAM_VADDR_END)) {
|
|
|
|
// Note: Memory write occurs asynchronously from the state of the emulator
|
2023-07-13 02:54:02 +01:00
|
|
|
system.Memory().WriteBlock(address, data.data(), data.size());
|
2018-09-11 21:00:12 +01:00
|
|
|
// If the memory happens to be executable code, make sure the changes become visible
|
2020-02-21 18:31:32 +00:00
|
|
|
|
|
|
|
// Is current core correct here?
|
2023-07-13 02:54:02 +01:00
|
|
|
system.InvalidateCacheRange(address, data.size());
|
2018-09-11 21:00:12 +01:00
|
|
|
}
|
|
|
|
packet.SetPacketDataSize(0);
|
|
|
|
packet.SendReply();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RPCServer::ValidatePacket(const PacketHeader& packet_header) {
|
|
|
|
if (packet_header.version <= CURRENT_VERSION) {
|
|
|
|
switch (packet_header.packet_type) {
|
|
|
|
case PacketType::ReadMemory:
|
|
|
|
case PacketType::WriteMemory:
|
|
|
|
if (packet_header.packet_size >= (sizeof(u32) * 2)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void RPCServer::HandleSingleRequest(std::unique_ptr<Packet> request_packet) {
|
|
|
|
bool success = false;
|
2023-07-13 02:54:02 +01:00
|
|
|
const auto packet_data = request_packet->GetPacketData();
|
2018-09-11 21:00:12 +01:00
|
|
|
|
|
|
|
if (ValidatePacket(request_packet->GetHeader())) {
|
|
|
|
// Currently, all request types use the address/data_size wire format
|
|
|
|
u32 address = 0;
|
|
|
|
u32 data_size = 0;
|
2023-07-06 23:52:40 +01:00
|
|
|
std::memcpy(&address, packet_data.data(), sizeof(address));
|
|
|
|
std::memcpy(&data_size, packet_data.data() + sizeof(address), sizeof(data_size));
|
2018-09-11 21:00:12 +01:00
|
|
|
|
|
|
|
switch (request_packet->GetPacketType()) {
|
|
|
|
case PacketType::ReadMemory:
|
|
|
|
if (data_size > 0 && data_size <= MAX_READ_SIZE) {
|
|
|
|
HandleReadMemory(*request_packet, address, data_size);
|
|
|
|
success = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PacketType::WriteMemory:
|
|
|
|
if (data_size > 0 && data_size <= MAX_PACKET_DATA_SIZE - (sizeof(u32) * 2)) {
|
2023-07-13 02:54:02 +01:00
|
|
|
const auto data = packet_data.subspan(sizeof(u32) * 2, data_size);
|
2023-07-06 23:52:40 +01:00
|
|
|
HandleWriteMemory(*request_packet, address, data);
|
2018-09-11 21:00:12 +01:00
|
|
|
success = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!success) {
|
|
|
|
// Send an empty reply, so as not to hang the client
|
|
|
|
request_packet->SetPacketDataSize(0);
|
|
|
|
request_packet->SendReply();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-13 02:54:02 +01:00
|
|
|
void RPCServer::HandleRequestsLoop(std::stop_token stop_token) {
|
2018-09-11 21:00:12 +01:00
|
|
|
std::unique_ptr<RPC::Packet> request_packet;
|
|
|
|
|
|
|
|
LOG_INFO(RPC_Server, "Request handler started.");
|
|
|
|
|
2023-07-13 02:54:02 +01:00
|
|
|
while ((request_packet = request_queue.PopWait(stop_token))) {
|
2018-09-11 21:00:12 +01:00
|
|
|
HandleSingleRequest(std::move(request_packet));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void RPCServer::QueueRequest(std::unique_ptr<RPC::Packet> request) {
|
|
|
|
request_queue.Push(std::move(request));
|
|
|
|
}
|
|
|
|
|
2023-07-13 02:54:02 +01:00
|
|
|
}; // namespace Core::RPC
|