diff --git a/src/citra_qt/debugger/callstack.cpp b/src/citra_qt/debugger/callstack.cpp index 793944639..1a3077495 100644 --- a/src/citra_qt/debugger/callstack.cpp +++ b/src/citra_qt/debugger/callstack.cpp @@ -37,10 +37,13 @@ void CallstackWidget::OnDebugModeEntered() int counter = 0; for (u32 addr = 0x10000000; addr >= sp; addr -= 4) { + if (!Memory::IsValidVirtualAddress(addr)) + break; + const u32 ret_addr = Memory::Read32(addr); const u32 call_addr = ret_addr - 4; //get call address??? - if (Memory::GetPointer(call_addr) == nullptr) + if (!Memory::IsValidVirtualAddress(call_addr)) break; /* TODO (mattvail) clean me, move to debugger interface */ diff --git a/src/core/file_sys/archive_backend.cpp b/src/core/file_sys/archive_backend.cpp index 97adf0e12..cc0aa7022 100644 --- a/src/core/file_sys/archive_backend.cpp +++ b/src/core/file_sys/archive_backend.cpp @@ -19,22 +19,22 @@ Path::Path(LowPathType type, u32 size, u32 pointer) : type(type) { switch (type) { case Binary: { - u8* data = Memory::GetPointer(pointer); - binary = std::vector(data, data + size); + binary.resize(size); + Memory::ReadBlock(pointer, binary.data(), binary.size()); break; } case Char: { - const char* data = reinterpret_cast(Memory::GetPointer(pointer)); - string = std::string(data, size - 1); // Data is always null-terminated. + string.resize(size - 1); // Data is always null-terminated. + Memory::ReadBlock(pointer, &string[0], string.size()); break; } case Wchar: { - const char16_t* data = reinterpret_cast(Memory::GetPointer(pointer)); - u16str = std::u16string(data, size/2 - 1); // Data is always null-terminated. + u16str.resize(size / 2 - 1); // Data is always null-terminated. + Memory::ReadBlock(pointer, &u16str[0], u16str.size() * sizeof(char16_t)); break; } diff --git a/src/core/hle/applets/mii_selector.cpp b/src/core/hle/applets/mii_selector.cpp index bf39eca22..77f01d208 100644 --- a/src/core/hle/applets/mii_selector.cpp +++ b/src/core/hle/applets/mii_selector.cpp @@ -32,9 +32,9 @@ ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& p // The LibAppJustStarted message contains a buffer with the size of the framebuffer shared memory. // Create the SharedMemory that will hold the framebuffer data Service::APT::CaptureBufferInfo capture_info; - ASSERT(sizeof(capture_info) == parameter.buffer_size); + ASSERT(sizeof(capture_info) == parameter.buffer.size()); - memcpy(&capture_info, parameter.data, sizeof(capture_info)); + memcpy(&capture_info, parameter.buffer.data(), sizeof(capture_info)); using Kernel::MemoryPermission; // Allocate a heap block of the required size for this applet. @@ -47,8 +47,7 @@ ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& p // Send the response message with the newly created SharedMemory Service::APT::MessageParameter result; result.signal = static_cast(Service::APT::SignalType::LibAppFinished); - result.data = nullptr; - result.buffer_size = 0; + result.buffer.clear(); result.destination_id = static_cast(Service::APT::AppletId::Application); result.sender_id = static_cast(id); result.object = framebuffer_memory; @@ -63,15 +62,17 @@ ResultCode MiiSelector::StartImpl(const Service::APT::AppletStartupParameter& pa // TODO(Subv): Set the expected fields in the response buffer before resending it to the application. // TODO(Subv): Reverse the parameter format for the Mii Selector - if(parameter.buffer_size >= sizeof(u32)) { - // TODO: defaults return no error, but garbage in other unknown fields - memset(parameter.data, 0, sizeof(u32)); - } + memcpy(&config, parameter.buffer.data(), parameter.buffer.size()); + + // TODO(Subv): Find more about this structure, result code 0 is enough to let most games continue. + MiiResult result; + memset(&result, 0, sizeof(result)); + result.result_code = 0; // Let the application know that we're closing Service::APT::MessageParameter message; - message.buffer_size = parameter.buffer_size; - message.data = parameter.data; + message.buffer.resize(sizeof(MiiResult)); + std::memcpy(message.buffer.data(), &result, message.buffer.size()); message.signal = static_cast(Service::APT::SignalType::LibAppClosed); message.destination_id = static_cast(Service::APT::AppletId::Application); message.sender_id = static_cast(id); diff --git a/src/core/hle/applets/mii_selector.h b/src/core/hle/applets/mii_selector.h index be6b04642..24e8e721d 100644 --- a/src/core/hle/applets/mii_selector.h +++ b/src/core/hle/applets/mii_selector.h @@ -24,7 +24,7 @@ struct MiiConfig { u8 unk_004; INSERT_PADDING_BYTES(3); u16 unk_008; - INSERT_PADDING_BYTES(0x8C - 0xA); + INSERT_PADDING_BYTES(0x82); u8 unk_08C; INSERT_PADDING_BYTES(3); u16 unk_090; @@ -75,6 +75,8 @@ public: /// Whether this applet is currently running instead of the host application or not. bool started; + + MiiConfig config; }; } diff --git a/src/core/hle/applets/swkbd.cpp b/src/core/hle/applets/swkbd.cpp index 90c6adc65..d87bf3d57 100644 --- a/src/core/hle/applets/swkbd.cpp +++ b/src/core/hle/applets/swkbd.cpp @@ -35,9 +35,9 @@ ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter con // The LibAppJustStarted message contains a buffer with the size of the framebuffer shared memory. // Create the SharedMemory that will hold the framebuffer data Service::APT::CaptureBufferInfo capture_info; - ASSERT(sizeof(capture_info) == parameter.buffer_size); + ASSERT(sizeof(capture_info) == parameter.buffer.size()); - memcpy(&capture_info, parameter.data, sizeof(capture_info)); + memcpy(&capture_info, parameter.buffer.data(), sizeof(capture_info)); using Kernel::MemoryPermission; // Allocate a heap block of the required size for this applet. @@ -50,8 +50,7 @@ ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter con // Send the response message with the newly created SharedMemory Service::APT::MessageParameter result; result.signal = static_cast(Service::APT::SignalType::LibAppFinished); - result.data = nullptr; - result.buffer_size = 0; + result.buffer.clear(); result.destination_id = static_cast(Service::APT::AppletId::Application); result.sender_id = static_cast(id); result.object = framebuffer_memory; @@ -61,9 +60,9 @@ ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter con } ResultCode SoftwareKeyboard::StartImpl(Service::APT::AppletStartupParameter const& parameter) { - ASSERT_MSG(parameter.buffer_size == sizeof(config), "The size of the parameter (SoftwareKeyboardConfig) is wrong"); + ASSERT_MSG(parameter.buffer.size() == sizeof(config), "The size of the parameter (SoftwareKeyboardConfig) is wrong"); - memcpy(&config, parameter.data, parameter.buffer_size); + memcpy(&config, parameter.buffer.data(), parameter.buffer.size()); text_memory = boost::static_pointer_cast(parameter.object); // TODO(Subv): Verify if this is the correct behavior @@ -99,7 +98,7 @@ void SoftwareKeyboard::DrawScreenKeyboard() { auto info = bottom_screen->framebuffer_info[bottom_screen->index]; // TODO(Subv): Draw the HLE keyboard, for now just zero-fill the framebuffer - memset(Memory::GetPointer(info.address_left), 0, info.stride * 320); + Memory::ZeroBlock(info.address_left, info.stride * 320); GSP_GPU::SetBufferSwap(1, info); } @@ -107,8 +106,8 @@ void SoftwareKeyboard::DrawScreenKeyboard() { void SoftwareKeyboard::Finalize() { // Let the application know that we're closing Service::APT::MessageParameter message; - message.buffer_size = sizeof(SoftwareKeyboardConfig); - message.data = reinterpret_cast(&config); + message.buffer.resize(sizeof(SoftwareKeyboardConfig)); + std::memcpy(message.buffer.data(), &config, message.buffer.size()); message.signal = static_cast(Service::APT::SignalType::LibAppClosed); message.destination_id = static_cast(Service::APT::AppletId::Application); message.sender_id = static_cast(id); diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 43def6146..3f6bec5fa 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -403,7 +403,7 @@ ResultVal> Thread::Create(std::string name, VAddr entry_point, priority = new_priority; } - if (!Memory::GetPointer(entry_point)) { + if (!Memory::IsValidVirtualAddress(entry_point)) { LOG_ERROR(Kernel_SVC, "(name=%s): invalid entry %08x", name.c_str(), entry_point); // TODO: Verify error return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index bbf170b71..1e54a53dd 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp @@ -180,12 +180,12 @@ void SendParameter(Service::Interface* self) { } MessageParameter param; - param.buffer_size = buffer_size; param.destination_id = dst_app_id; param.sender_id = src_app_id; param.object = Kernel::g_handle_table.GetGeneric(handle); param.signal = signal_type; - param.data = Memory::GetPointer(buffer); + param.buffer.resize(buffer_size); + Memory::ReadBlock(buffer, param.buffer.data(), param.buffer.size()); cmd_buff[1] = dest_applet->ReceiveParameter(param).raw; @@ -203,16 +203,15 @@ void ReceiveParameter(Service::Interface* self) { cmd_buff[1] = RESULT_SUCCESS.raw; // No error cmd_buff[2] = next_parameter.sender_id; cmd_buff[3] = next_parameter.signal; // Signal type - cmd_buff[4] = next_parameter.buffer_size; // Parameter buffer size + cmd_buff[4] = next_parameter.buffer.size(); // Parameter buffer size cmd_buff[5] = 0x10; cmd_buff[6] = 0; if (next_parameter.object != nullptr) cmd_buff[6] = Kernel::g_handle_table.Create(next_parameter.object).MoveFrom(); - cmd_buff[7] = (next_parameter.buffer_size << 14) | 2; + cmd_buff[7] = (next_parameter.buffer.size() << 14) | 2; cmd_buff[8] = buffer; - if (next_parameter.data) - memcpy(Memory::GetPointer(buffer), next_parameter.data, std::min(buffer_size, next_parameter.buffer_size)); + Memory::WriteBlock(buffer, next_parameter.buffer.data(), next_parameter.buffer.size()); LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); } @@ -226,16 +225,15 @@ void GlanceParameter(Service::Interface* self) { cmd_buff[1] = RESULT_SUCCESS.raw; // No error cmd_buff[2] = next_parameter.sender_id; cmd_buff[3] = next_parameter.signal; // Signal type - cmd_buff[4] = next_parameter.buffer_size; // Parameter buffer size + cmd_buff[4] = next_parameter.buffer.size(); // Parameter buffer size cmd_buff[5] = 0x10; cmd_buff[6] = 0; if (next_parameter.object != nullptr) cmd_buff[6] = Kernel::g_handle_table.Create(next_parameter.object).MoveFrom(); - cmd_buff[7] = (next_parameter.buffer_size << 14) | 2; + cmd_buff[7] = (next_parameter.buffer.size() << 14) | 2; cmd_buff[8] = buffer; - if (next_parameter.data) - memcpy(Memory::GetPointer(buffer), next_parameter.data, std::min(buffer_size, next_parameter.buffer_size)); + Memory::WriteBlock(buffer, next_parameter.buffer.data(), std::min(static_cast(buffer_size), next_parameter.buffer.size())); LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); } @@ -373,10 +371,13 @@ void StartLibraryApplet(Service::Interface* self) { return; } + size_t buffer_size = cmd_buff[2]; + VAddr buffer_addr = cmd_buff[6]; + AppletStartupParameter parameter; - parameter.buffer_size = cmd_buff[2]; parameter.object = Kernel::g_handle_table.GetGeneric(cmd_buff[4]); - parameter.data = Memory::GetPointer(cmd_buff[6]); + parameter.buffer.resize(buffer_size); + Memory::ReadBlock(buffer_addr, parameter.buffer.data(), parameter.buffer.size()); cmd_buff[1] = applet->Start(parameter).raw; } diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h index ed7c47cca..76b3a3807 100644 --- a/src/core/hle/service/apt/apt.h +++ b/src/core/hle/service/apt/apt.h @@ -20,16 +20,14 @@ struct MessageParameter { u32 sender_id = 0; u32 destination_id = 0; u32 signal = 0; - u32 buffer_size = 0; Kernel::SharedPtr object = nullptr; - u8* data = nullptr; + std::vector buffer; }; /// Holds information about the parameters used in StartLibraryApplet struct AppletStartupParameter { - u32 buffer_size = 0; Kernel::SharedPtr object = nullptr; - u8* data = nullptr; + std::vector buffer; }; /// Used by the application to pass information about the current framebuffer to applets. diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp index acc509cb0..e067db645 100644 --- a/src/core/hle/service/cfg/cfg.cpp +++ b/src/core/hle/service/cfg/cfg.cpp @@ -196,28 +196,32 @@ void GetConfigInfoBlk2(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 size = cmd_buff[1]; u32 block_id = cmd_buff[2]; - u8* data_pointer = Memory::GetPointer(cmd_buff[4]); + VAddr data_pointer = cmd_buff[4]; - if (data_pointer == nullptr) { + if (!Memory::IsValidVirtualAddress(data_pointer)) { cmd_buff[1] = -1; // TODO(Subv): Find the right error code return; } - cmd_buff[1] = Service::CFG::GetConfigInfoBlock(block_id, size, 0x2, data_pointer).raw; + std::vector data(size); + cmd_buff[1] = Service::CFG::GetConfigInfoBlock(block_id, size, 0x2, data.data()).raw; + Memory::WriteBlock(data_pointer, data.data(), data.size()); } void GetConfigInfoBlk8(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 size = cmd_buff[1]; u32 block_id = cmd_buff[2]; - u8* data_pointer = Memory::GetPointer(cmd_buff[4]); + VAddr data_pointer = cmd_buff[4]; - if (data_pointer == nullptr) { + if (!Memory::IsValidVirtualAddress(data_pointer)) { cmd_buff[1] = -1; // TODO(Subv): Find the right error code return; } - cmd_buff[1] = Service::CFG::GetConfigInfoBlock(block_id, size, 0x8, data_pointer).raw; + std::vector data(size); + cmd_buff[1] = Service::CFG::GetConfigInfoBlock(block_id, size, 0x8, data.data()).raw; + Memory::WriteBlock(data_pointer, data.data(), data.size()); } void UpdateConfigNANDSavegame(Service::Interface* self) { diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp index 10730d7ac..c8aadd9db 100644 --- a/src/core/hle/service/dsp_dsp.cpp +++ b/src/core/hle/service/dsp_dsp.cpp @@ -140,12 +140,15 @@ static void LoadComponent(Service::Interface* self) { // TODO(bunnei): Implement real DSP firmware loading - ASSERT(Memory::GetPointer(buffer) != nullptr); - ASSERT(size > 0x37C); + ASSERT(Memory::IsValidVirtualAddress(buffer)); - LOG_INFO(Service_DSP, "Firmware hash: %#" PRIx64, Common::ComputeHash64(Memory::GetPointer(buffer), size)); + std::vector component_data(size); + Memory::ReadBlock(buffer, component_data.data(), component_data.size()); + + LOG_INFO(Service_DSP, "Firmware hash: %#" PRIx64, Common::ComputeHash64(component_data.data(), component_data.size())); // Some versions of the firmware have the location of DSP structures listed here. - LOG_INFO(Service_DSP, "Structures hash: %#" PRIx64, Common::ComputeHash64(Memory::GetPointer(buffer) + 0x340, 60)); + ASSERT(size > 0x37C); + LOG_INFO(Service_DSP, "Structures hash: %#" PRIx64, Common::ComputeHash64(component_data.data() + 0x340, 60)); LOG_WARNING(Service_DSP, "(STUBBED) called size=0x%X, prog_mask=0x%08X, data_mask=0x%08X, buffer=0x%08X", size, prog_mask, data_mask, buffer); @@ -285,7 +288,7 @@ static void WriteProcessPipe(Service::Interface* self) { return; } - ASSERT_MSG(Memory::GetPointer(buffer) != nullptr, "Invalid Buffer: pipe=%u, size=0x%X, buffer=0x%08X", pipe_index, size, buffer); + ASSERT_MSG(Memory::IsValidVirtualAddress(buffer), "Invalid Buffer: pipe=%u, size=0x%X, buffer=0x%08X", pipe, size, buffer); std::vector message(size); for (u32 i = 0; i < size; i++) { @@ -324,7 +327,7 @@ static void ReadPipeIfPossible(Service::Interface* self) { DSP::HLE::DspPipe pipe = static_cast(pipe_index); - ASSERT_MSG(Memory::GetPointer(addr) != nullptr, "Invalid addr: pipe=%u, unknown=0x%08X, size=0x%X, buffer=0x%08X", pipe_index, unknown, size, addr); + ASSERT_MSG(Memory::IsValidVirtualAddress(addr), "Invalid addr: pipe=0x%08X, unknown=0x%08X, size=0x%X, buffer=0x%08X", pipe, unknown, size, addr); cmd_buff[0] = IPC::MakeHeader(0x10, 1, 2); cmd_buff[1] = RESULT_SUCCESS.raw; // No error @@ -364,7 +367,7 @@ static void ReadPipe(Service::Interface* self) { DSP::HLE::DspPipe pipe = static_cast(pipe_index); - ASSERT_MSG(Memory::GetPointer(addr) != nullptr, "Invalid addr: pipe=%u, unknown=0x%08X, size=0x%X, buffer=0x%08X", pipe_index, unknown, size, addr); + ASSERT_MSG(Memory::IsValidVirtualAddress(addr), "Invalid addr: pipe=0x%08X, unknown=0x%08X, size=0x%X, buffer=0x%08X", pipe, unknown, size, addr); if (DSP::HLE::GetPipeReadableSize(pipe) >= size) { std::vector response = DSP::HLE::PipeRead(pipe, size); diff --git a/src/core/hle/service/frd/frd.cpp b/src/core/hle/service/frd/frd.cpp index 15d604bb6..29d144365 100644 --- a/src/core/hle/service/frd/frd.cpp +++ b/src/core/hle/service/frd/frd.cpp @@ -23,7 +23,7 @@ void GetMyPresence(Service::Interface* self) { ASSERT(shifted_out_size == ((sizeof(MyPresence) << 14) | 2)); - Memory::WriteBlock(my_presence_addr, reinterpret_cast(&my_presence), sizeof(MyPresence)); + Memory::WriteBlock(my_presence_addr, &my_presence, sizeof(MyPresence)); cmd_buff[1] = RESULT_SUCCESS.raw; // No error @@ -39,8 +39,7 @@ void GetFriendKeyList(Service::Interface* self) { FriendKey zero_key = {}; for (u32 i = 0; i < frd_count; ++i) { - Memory::WriteBlock(frd_key_addr + i * sizeof(FriendKey), - reinterpret_cast(&zero_key), sizeof(FriendKey)); + Memory::WriteBlock(frd_key_addr + i * sizeof(FriendKey), &zero_key, sizeof(FriendKey)); } cmd_buff[1] = RESULT_SUCCESS.raw; // No error @@ -58,8 +57,7 @@ void GetFriendProfile(Service::Interface* self) { Profile zero_profile = {}; for (u32 i = 0; i < count; ++i) { - Memory::WriteBlock(profiles_addr + i * sizeof(Profile), - reinterpret_cast(&zero_profile), sizeof(Profile)); + Memory::WriteBlock(profiles_addr + i * sizeof(Profile), &zero_profile, sizeof(Profile)); } cmd_buff[1] = RESULT_SUCCESS.raw; // No error @@ -88,7 +86,7 @@ void GetMyFriendKey(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[1] = RESULT_SUCCESS.raw; // No error - Memory::WriteBlock(cmd_buff[2], reinterpret_cast(&my_friend_key), sizeof(FriendKey)); + Memory::WriteBlock(cmd_buff[2], &my_friend_key, sizeof(FriendKey)); LOG_WARNING(Service_FRD, "(STUBBED) called"); } diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index cc51ede0c..81b9abe4c 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -108,13 +108,14 @@ ResultVal File::SyncRequest() { offset, length, backend->GetSize()); } - ResultVal read = backend->Read(offset, length, Memory::GetPointer(address)); + std::vector data(length); + ResultVal read = backend->Read(offset, data.size(), data.data()); if (read.Failed()) { cmd_buff[1] = read.Code().raw; return read.Code(); } + Memory::WriteBlock(address, data.data(), *read); cmd_buff[2] = static_cast(*read); - Memory::RasterizerFlushAndInvalidateRegion(Memory::VirtualToPhysicalAddress(address), length); break; } @@ -128,7 +129,9 @@ ResultVal File::SyncRequest() { LOG_TRACE(Service_FS, "Write %s %s: offset=0x%llx length=%d address=0x%x, flush=0x%x", GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush); - ResultVal written = backend->Write(offset, length, flush != 0, Memory::GetPointer(address)); + std::vector data(length); + Memory::ReadBlock(address, data.data(), data.size()); + ResultVal written = backend->Write(offset, data.size(), flush != 0, data.data()); if (written.Failed()) { cmd_buff[1] = written.Code().raw; return written.Code(); @@ -216,12 +219,14 @@ ResultVal Directory::SyncRequest() { { u32 count = cmd_buff[1]; u32 address = cmd_buff[3]; - auto entries = reinterpret_cast(Memory::GetPointer(address)); + std::vector entries(count); LOG_TRACE(Service_FS, "Read %s %s: count=%d", GetTypeName().c_str(), GetName().c_str(), count); // Number of entries actually read - cmd_buff[2] = backend->Read(count, entries); + u32 read = backend->Read(entries.size(), entries.data()); + cmd_buff[2] = read; + Memory::WriteBlock(address, entries.data(), read * sizeof(FileSys::Entry)); break; } @@ -456,11 +461,12 @@ ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, VAddr icon if (result.IsError()) return result; - u8* smdh_icon = Memory::GetPointer(icon_buffer); - if (!smdh_icon) + if (!Memory::IsValidVirtualAddress(icon_buffer)) return ResultCode(-1); // TODO(Subv): Find the right error code - ext_savedata->WriteIcon(path, smdh_icon, icon_size); + std::vector smdh_icon(icon_size); + Memory::ReadBlock(icon_buffer, smdh_icon.data(), smdh_icon.size()); + ext_savedata->WriteIcon(path, smdh_icon.data(), smdh_icon.size()); return RESULT_SUCCESS; } diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp index 8ded9b09b..f3c7b7df3 100644 --- a/src/core/hle/service/gsp_gpu.cpp +++ b/src/core/hle/service/gsp_gpu.cpp @@ -65,15 +65,27 @@ static inline InterruptRelayQueue* GetInterruptRelayQueue(u32 thread_id) { return reinterpret_cast(ptr); } +/** + * Writes a single GSP GPU hardware registers with a single u32 value + * (For internal use.) + * + * @param base_address The address of the register in question + * @param data Data to be written + */ +static void WriteSingleHWReg(u32 base_address, u32 data) { + DEBUG_ASSERT_MSG((base_address & 3) == 0 && base_address < 0x420000, "Write address out of range or misaligned"); + HW::Write(base_address + REGS_BEGIN, data); +} + /** * Writes sequential GSP GPU hardware registers using an array of source data * * @param base_address The address of the first register in the sequence * @param size_in_bytes The number of registers to update (size of data) - * @param data A pointer to the source data + * @param data_vaddr A pointer to the source data * @return RESULT_SUCCESS if the parameters are valid, error code otherwise */ -static ResultCode WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) { +static ResultCode WriteHWRegs(u32 base_address, u32 size_in_bytes, VAddr data_vaddr) { // This magic number is verified to be done by the gsp module const u32 max_size_in_bytes = 0x80; @@ -87,10 +99,10 @@ static ResultCode WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* da return ERR_GSP_REGS_MISALIGNED; } else { while (size_in_bytes > 0) { - HW::Write(base_address + REGS_BEGIN, *data); + WriteSingleHWReg(base_address, Memory::Read32(data_vaddr)); size_in_bytes -= 4; - ++data; + data_vaddr += 4; base_address += 4; } return RESULT_SUCCESS; @@ -112,7 +124,7 @@ static ResultCode WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* da * @param masks A pointer to the masks * @return RESULT_SUCCESS if the parameters are valid, error code otherwise */ -static ResultCode WriteHWRegsWithMask(u32 base_address, u32 size_in_bytes, const u32* data, const u32* masks) { +static ResultCode WriteHWRegsWithMask(u32 base_address, u32 size_in_bytes, VAddr data_vaddr, VAddr masks_vaddr) { // This magic number is verified to be done by the gsp module const u32 max_size_in_bytes = 0x80; @@ -131,14 +143,17 @@ static ResultCode WriteHWRegsWithMask(u32 base_address, u32 size_in_bytes, const u32 reg_value; HW::Read(reg_value, reg_address); - // Update the current value of the register only for set mask bits - reg_value = (reg_value & ~*masks) | (*data | *masks); + u32 data = Memory::Read32(data_vaddr); + u32 mask = Memory::Read32(masks_vaddr); - HW::Write(reg_address, reg_value); + // Update the current value of the register only for set mask bits + reg_value = (reg_value & ~mask) | (data | mask); + + WriteSingleHWReg(base_address, reg_value); size_in_bytes -= 4; - ++data; - ++masks; + data_vaddr += 4; + masks_vaddr += 4; base_address += 4; } return RESULT_SUCCESS; @@ -164,8 +179,7 @@ static void WriteHWRegs(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 reg_addr = cmd_buff[1]; u32 size = cmd_buff[2]; - - u32* src = (u32*)Memory::GetPointer(cmd_buff[4]); + VAddr src = cmd_buff[4]; cmd_buff[1] = WriteHWRegs(reg_addr, size, src).raw; } @@ -186,8 +200,8 @@ static void WriteHWRegsWithMask(Service::Interface* self) { u32 reg_addr = cmd_buff[1]; u32 size = cmd_buff[2]; - u32* src_data = (u32*)Memory::GetPointer(cmd_buff[4]); - u32* mask_data = (u32*)Memory::GetPointer(cmd_buff[6]); + VAddr src_data = cmd_buff[4]; + VAddr mask_data = cmd_buff[6]; cmd_buff[1] = WriteHWRegsWithMask(reg_addr, size, src_data, mask_data).raw; } @@ -210,13 +224,16 @@ static void ReadHWRegs(Service::Interface* self) { return; } - u32* dst = (u32*)Memory::GetPointer(cmd_buff[0x41]); + VAddr dst_vaddr = cmd_buff[0x41]; while (size > 0) { - HW::Read(*dst, reg_addr + REGS_BEGIN); + u32 value; + HW::Read(value, reg_addr + REGS_BEGIN); + + Memory::Write32(dst_vaddr, value); size -= 4; - ++dst; + dst_vaddr += 4; reg_addr += 4; } } @@ -226,22 +243,22 @@ ResultCode SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) { PAddr phys_address_left = Memory::VirtualToPhysicalAddress(info.address_left); PAddr phys_address_right = Memory::VirtualToPhysicalAddress(info.address_right); if (info.active_fb == 0) { - WriteHWRegs(base_address + 4 * static_cast(GPU_REG_INDEX(framebuffer_config[screen_id].address_left1)), - 4, &phys_address_left); - WriteHWRegs(base_address + 4 * static_cast(GPU_REG_INDEX(framebuffer_config[screen_id].address_right1)), - 4, &phys_address_right); + WriteSingleHWReg(base_address + 4 * static_cast(GPU_REG_INDEX(framebuffer_config[screen_id].address_left1)), + phys_address_left); + WriteSingleHWReg(base_address + 4 * static_cast(GPU_REG_INDEX(framebuffer_config[screen_id].address_right1)), + phys_address_right); } else { - WriteHWRegs(base_address + 4 * static_cast(GPU_REG_INDEX(framebuffer_config[screen_id].address_left2)), - 4, &phys_address_left); - WriteHWRegs(base_address + 4 * static_cast(GPU_REG_INDEX(framebuffer_config[screen_id].address_right2)), - 4, &phys_address_right); + WriteSingleHWReg(base_address + 4 * static_cast(GPU_REG_INDEX(framebuffer_config[screen_id].address_left2)), + phys_address_left); + WriteSingleHWReg(base_address + 4 * static_cast(GPU_REG_INDEX(framebuffer_config[screen_id].address_right2)), + phys_address_right); } - WriteHWRegs(base_address + 4 * static_cast(GPU_REG_INDEX(framebuffer_config[screen_id].stride)), - 4, &info.stride); - WriteHWRegs(base_address + 4 * static_cast(GPU_REG_INDEX(framebuffer_config[screen_id].color_format)), - 4, &info.format); - WriteHWRegs(base_address + 4 * static_cast(GPU_REG_INDEX(framebuffer_config[screen_id].active_fb)), - 4, &info.shown_fb); + WriteSingleHWReg(base_address + 4 * static_cast(GPU_REG_INDEX(framebuffer_config[screen_id].stride)), + info.stride); + WriteSingleHWReg(base_address + 4 * static_cast(GPU_REG_INDEX(framebuffer_config[screen_id].color_format)), + info.format); + WriteSingleHWReg(base_address + 4 * static_cast(GPU_REG_INDEX(framebuffer_config[screen_id].active_fb)), + info.shown_fb); if (Pica::g_debug_context) Pica::g_debug_context->OnEvent(Pica::DebugContext::Event::BufferSwapped, nullptr); @@ -432,9 +449,9 @@ static void ExecuteCommand(const Command& command, u32 thread_id) { Memory::RasterizerFlushAndInvalidateRegion(Memory::VirtualToPhysicalAddress(command.dma_request.dest_address), command.dma_request.size); - memcpy(Memory::GetPointer(command.dma_request.dest_address), - Memory::GetPointer(command.dma_request.source_address), - command.dma_request.size); + // TODO(Subv): These memory accesses should not go through the application's memory mapping. + // They should go through the GSP module's memory mapping. + Memory::CopyBlock(command.dma_request.dest_address, command.dma_request.source_address, command.dma_request.size); SignalInterrupt(InterruptId::DMA); break; } diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp index d3e5d4bca..9b285567b 100644 --- a/src/core/hle/service/soc_u.cpp +++ b/src/core/hle/service/soc_u.cpp @@ -373,14 +373,18 @@ static void Bind(Service::Interface* self) { u32* cmd_buffer = Kernel::GetCommandBuffer(); u32 socket_handle = cmd_buffer[1]; u32 len = cmd_buffer[2]; - CTRSockAddr* ctr_sock_addr = reinterpret_cast(Memory::GetPointer(cmd_buffer[6])); - if (ctr_sock_addr == nullptr) { + // Virtual address of the sock_addr structure + VAddr sock_addr_addr = cmd_buffer[6]; + if (!Memory::IsValidVirtualAddress(sock_addr_addr)) { cmd_buffer[1] = -1; // TODO(Subv): Correct code return; } - sockaddr sock_addr = CTRSockAddr::ToPlatform(*ctr_sock_addr); + CTRSockAddr ctr_sock_addr; + Memory::ReadBlock(sock_addr_addr, reinterpret_cast(&ctr_sock_addr), sizeof(CTRSockAddr)); + + sockaddr sock_addr = CTRSockAddr::ToPlatform(ctr_sock_addr); int res = ::bind(socket_handle, &sock_addr, std::max(sizeof(sock_addr), len)); @@ -496,7 +500,7 @@ static void Accept(Service::Interface* self) { result = TranslateError(GET_ERRNO); } else { CTRSockAddr ctr_addr = CTRSockAddr::FromPlatform(addr); - Memory::WriteBlock(cmd_buffer[0x104 >> 2], (const u8*)&ctr_addr, max_addr_len); + Memory::WriteBlock(cmd_buffer[0x104 >> 2], &ctr_addr, sizeof(ctr_addr)); } cmd_buffer[0] = IPC::MakeHeader(4, 2, 2); @@ -547,20 +551,31 @@ static void SendTo(Service::Interface* self) { u32 flags = cmd_buffer[3]; u32 addr_len = cmd_buffer[4]; - u8* input_buff = Memory::GetPointer(cmd_buffer[8]); - CTRSockAddr* ctr_dest_addr = reinterpret_cast(Memory::GetPointer(cmd_buffer[10])); - - if (ctr_dest_addr == nullptr) { + VAddr input_buff_address = cmd_buffer[8]; + if (!Memory::IsValidVirtualAddress(input_buff_address)) { cmd_buffer[1] = -1; // TODO(Subv): Find the right error code return; } + // Memory address of the dest_addr structure + VAddr dest_addr_addr = cmd_buffer[10]; + if (!Memory::IsValidVirtualAddress(dest_addr_addr)) { + cmd_buffer[1] = -1; // TODO(Subv): Find the right error code + return; + } + + std::vector input_buff(len); + Memory::ReadBlock(input_buff_address, input_buff.data(), input_buff.size()); + + CTRSockAddr ctr_dest_addr; + Memory::ReadBlock(dest_addr_addr, &ctr_dest_addr, sizeof(ctr_dest_addr)); + int ret = -1; if (addr_len > 0) { - sockaddr dest_addr = CTRSockAddr::ToPlatform(*ctr_dest_addr); - ret = ::sendto(socket_handle, (const char*)input_buff, len, flags, &dest_addr, sizeof(dest_addr)); + sockaddr dest_addr = CTRSockAddr::ToPlatform(ctr_dest_addr); + ret = ::sendto(socket_handle, reinterpret_cast(input_buff.data()), len, flags, &dest_addr, sizeof(dest_addr)); } else { - ret = ::sendto(socket_handle, (const char*)input_buff, len, flags, nullptr, 0); + ret = ::sendto(socket_handle, reinterpret_cast(input_buff.data()), len, flags, nullptr, 0); } int result = 0; @@ -591,14 +606,24 @@ static void RecvFrom(Service::Interface* self) { std::memcpy(&buffer_parameters, &cmd_buffer[64], sizeof(buffer_parameters)); - u8* output_buff = Memory::GetPointer(buffer_parameters.output_buffer_addr); + if (!Memory::IsValidVirtualAddress(buffer_parameters.output_buffer_addr)) { + cmd_buffer[1] = -1; // TODO(Subv): Find the right error code + return; + } + + if (!Memory::IsValidVirtualAddress(buffer_parameters.output_src_address_buffer)) { + cmd_buffer[1] = -1; // TODO(Subv): Find the right error code + return; + } + + std::vector output_buff(len); sockaddr src_addr; socklen_t src_addr_len = sizeof(src_addr); - int ret = ::recvfrom(socket_handle, (char*)output_buff, len, flags, &src_addr, &src_addr_len); + int ret = ::recvfrom(socket_handle, reinterpret_cast(output_buff.data()), len, flags, &src_addr, &src_addr_len); if (ret >= 0 && buffer_parameters.output_src_address_buffer != 0 && src_addr_len > 0) { - CTRSockAddr* ctr_src_addr = reinterpret_cast(Memory::GetPointer(buffer_parameters.output_src_address_buffer)); - *ctr_src_addr = CTRSockAddr::FromPlatform(src_addr); + CTRSockAddr ctr_src_addr = CTRSockAddr::FromPlatform(src_addr); + Memory::WriteBlock(buffer_parameters.output_src_address_buffer, &ctr_src_addr, sizeof(ctr_src_addr)); } int result = 0; @@ -606,6 +631,9 @@ static void RecvFrom(Service::Interface* self) { if (ret == SOCKET_ERROR_VALUE) { result = TranslateError(GET_ERRNO); total_received = 0; + } else { + // Write only the data we received to avoid overwriting parts of the buffer with zeros + Memory::WriteBlock(buffer_parameters.output_buffer_addr, output_buff.data(), total_received); } cmd_buffer[1] = result; @@ -617,18 +645,28 @@ static void Poll(Service::Interface* self) { u32* cmd_buffer = Kernel::GetCommandBuffer(); u32 nfds = cmd_buffer[1]; int timeout = cmd_buffer[2]; - CTRPollFD* input_fds = reinterpret_cast(Memory::GetPointer(cmd_buffer[6])); - CTRPollFD* output_fds = reinterpret_cast(Memory::GetPointer(cmd_buffer[0x104 >> 2])); + + VAddr input_fds_addr = cmd_buffer[6]; + VAddr output_fds_addr = cmd_buffer[0x104 >> 2]; + if (!Memory::IsValidVirtualAddress(input_fds_addr) || !Memory::IsValidVirtualAddress(output_fds_addr)) { + cmd_buffer[1] = -1; // TODO(Subv): Find correct error code. + return; + } + + std::vector ctr_fds(nfds); + Memory::ReadBlock(input_fds_addr, ctr_fds.data(), nfds * sizeof(CTRPollFD)); // The 3ds_pollfd and the pollfd structures may be different (Windows/Linux have different sizes) // so we have to copy the data std::vector platform_pollfd(nfds); - std::transform(input_fds, input_fds + nfds, platform_pollfd.begin(), CTRPollFD::ToPlatform); + std::transform(ctr_fds.begin(), ctr_fds.end(), platform_pollfd.begin(), CTRPollFD::ToPlatform); const int ret = ::poll(platform_pollfd.data(), nfds, timeout); // Now update the output pollfd structure - std::transform(platform_pollfd.begin(), platform_pollfd.end(), output_fds, CTRPollFD::FromPlatform); + std::transform(platform_pollfd.begin(), platform_pollfd.end(), ctr_fds.begin(), CTRPollFD::FromPlatform); + + Memory::WriteBlock(output_fds_addr, ctr_fds.data(), nfds * sizeof(CTRPollFD)); int result = 0; if (ret == SOCKET_ERROR_VALUE) @@ -643,14 +681,16 @@ static void GetSockName(Service::Interface* self) { u32 socket_handle = cmd_buffer[1]; socklen_t ctr_len = cmd_buffer[2]; - CTRSockAddr* ctr_dest_addr = reinterpret_cast(Memory::GetPointer(cmd_buffer[0x104 >> 2])); + // Memory address of the ctr_dest_addr structure + VAddr ctr_dest_addr_addr = cmd_buffer[0x104 >> 2]; sockaddr dest_addr; socklen_t dest_addr_len = sizeof(dest_addr); int ret = ::getsockname(socket_handle, &dest_addr, &dest_addr_len); - if (ctr_dest_addr != nullptr) { - *ctr_dest_addr = CTRSockAddr::FromPlatform(dest_addr); + if (ctr_dest_addr_addr != 0 && Memory::IsValidVirtualAddress(ctr_dest_addr_addr)) { + CTRSockAddr ctr_dest_addr = CTRSockAddr::FromPlatform(dest_addr); + Memory::WriteBlock(ctr_dest_addr_addr, &ctr_dest_addr, sizeof(ctr_dest_addr)); } else { cmd_buffer[1] = -1; // TODO(Subv): Verify error return; @@ -682,14 +722,16 @@ static void GetPeerName(Service::Interface* self) { u32 socket_handle = cmd_buffer[1]; socklen_t len = cmd_buffer[2]; - CTRSockAddr* ctr_dest_addr = reinterpret_cast(Memory::GetPointer(cmd_buffer[0x104 >> 2])); + // Memory address of the ctr_dest_addr structure + VAddr ctr_dest_addr_addr = cmd_buffer[0x104 >> 2]; sockaddr dest_addr; socklen_t dest_addr_len = sizeof(dest_addr); int ret = ::getpeername(socket_handle, &dest_addr, &dest_addr_len); - if (ctr_dest_addr != nullptr) { - *ctr_dest_addr = CTRSockAddr::FromPlatform(dest_addr); + if (ctr_dest_addr_addr != 0 && Memory::IsValidVirtualAddress(ctr_dest_addr_addr)) { + CTRSockAddr ctr_dest_addr = CTRSockAddr::FromPlatform(dest_addr); + Memory::WriteBlock(ctr_dest_addr_addr, &ctr_dest_addr, sizeof(ctr_dest_addr)); } else { cmd_buffer[1] = -1; return; @@ -711,13 +753,17 @@ static void Connect(Service::Interface* self) { u32 socket_handle = cmd_buffer[1]; socklen_t len = cmd_buffer[2]; - CTRSockAddr* ctr_input_addr = reinterpret_cast(Memory::GetPointer(cmd_buffer[6])); - if (ctr_input_addr == nullptr) { + // Memory address of the ctr_input_addr structure + VAddr ctr_input_addr_addr = cmd_buffer[6]; + if (!Memory::IsValidVirtualAddress(ctr_input_addr_addr)) { cmd_buffer[1] = -1; // TODO(Subv): Verify error return; } - sockaddr input_addr = CTRSockAddr::ToPlatform(*ctr_input_addr); + CTRSockAddr ctr_input_addr; + Memory::ReadBlock(ctr_input_addr_addr, &ctr_input_addr, sizeof(ctr_input_addr)); + + sockaddr input_addr = CTRSockAddr::ToPlatform(ctr_input_addr); int ret = ::connect(socket_handle, &input_addr, sizeof(input_addr)); int result = 0; if (ret != 0) diff --git a/src/core/hle/service/ssl_c.cpp b/src/core/hle/service/ssl_c.cpp index 14a4e98ec..a8aff1abf 100644 --- a/src/core/hle/service/ssl_c.cpp +++ b/src/core/hle/service/ssl_c.cpp @@ -31,7 +31,6 @@ static void GenerateRandomData(Service::Interface* self) { u32 size = cmd_buff[1]; VAddr address = cmd_buff[3]; - u8* output_buff = Memory::GetPointer(address); // Fill the output buffer with random data. u32 data = 0; @@ -44,13 +43,13 @@ static void GenerateRandomData(Service::Interface* self) { if (size > 4) { // Use up the entire 4 bytes of the random data for as long as possible - *(u32*)(output_buff + i) = data; + Memory::Write32(address + i, data); i += 4; } else if (size == 2) { - *(u16*)(output_buff + i) = (u16)(data & 0xffff); + Memory::Write16(address + i, static_cast(data & 0xffff)); i += 2; } else { - *(u8*)(output_buff + i) = (u8)(data & 0xff); + Memory::Write8(address + i, static_cast(data & 0xff)); i++; } } diff --git a/src/core/memory.cpp b/src/core/memory.cpp index ee9b69f81..8c9e5d46d 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -246,6 +246,26 @@ void Write(const VAddr vaddr, const T data) { } } +bool IsValidVirtualAddress(const VAddr vaddr) { + const u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; + if (page_pointer) + return true; + + if (current_page_table->attributes[vaddr >> PAGE_BITS] != PageType::Special) + return false; + + MMIORegionPointer mmio_region = GetMMIOHandler(vaddr); + if (mmio_region) { + return mmio_region->IsValidAddress(vaddr); + } + + return false; +} + +bool IsValidPhysicalAddress(const PAddr paddr) { + return IsValidVirtualAddress(PhysicalToVirtualAddress(paddr)); +} + u8* GetPointer(const VAddr vaddr) { u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; if (page_pointer) { @@ -261,6 +281,7 @@ u8* GetPointer(const VAddr vaddr) { } u8* GetPhysicalPointer(PAddr address) { + // TODO(Subv): This call should not go through the application's memory mapping. return GetPointer(PhysicalToVirtualAddress(address)); } @@ -343,6 +364,59 @@ u64 Read64(const VAddr addr) { return Read(addr); } +void ReadBlock(const VAddr src_addr, void* dest_buffer, const size_t size) { + size_t remaining_size = size; + size_t page_index = src_addr >> PAGE_BITS; + size_t page_offset = src_addr & PAGE_MASK; + + while (remaining_size > 0) { + const size_t copy_amount = std::min(PAGE_SIZE - page_offset, remaining_size); + const VAddr current_vaddr = (page_index << PAGE_BITS) + page_offset; + + switch (current_page_table->attributes[page_index]) { + case PageType::Unmapped: { + LOG_ERROR(HW_Memory, "unmapped ReadBlock @ 0x%08X (start address = 0x%08X, size = %zu)", current_vaddr, src_addr, size); + std::memset(dest_buffer, 0, copy_amount); + break; + } + case PageType::Memory: { + DEBUG_ASSERT(current_page_table->pointers[page_index]); + + const u8* src_ptr = current_page_table->pointers[page_index] + page_offset; + std::memcpy(dest_buffer, src_ptr, copy_amount); + break; + } + case PageType::Special: { + DEBUG_ASSERT(GetMMIOHandler(current_vaddr)); + + GetMMIOHandler(current_vaddr)->ReadBlock(current_vaddr, dest_buffer, copy_amount); + break; + } + case PageType::RasterizerCachedMemory: { + RasterizerFlushRegion(VirtualToPhysicalAddress(current_vaddr), copy_amount); + + std::memcpy(dest_buffer, GetPointerFromVMA(current_vaddr), copy_amount); + break; + } + case PageType::RasterizerCachedSpecial: { + DEBUG_ASSERT(GetMMIOHandler(current_vaddr)); + + RasterizerFlushRegion(VirtualToPhysicalAddress(current_vaddr), copy_amount); + + GetMMIOHandler(current_vaddr)->ReadBlock(current_vaddr, dest_buffer, copy_amount); + break; + } + default: + UNREACHABLE(); + } + + page_index++; + page_offset = 0; + dest_buffer = static_cast(dest_buffer) + copy_amount; + remaining_size -= copy_amount; + } +} + void Write8(const VAddr addr, const u8 data) { Write(addr, data); } @@ -359,9 +433,165 @@ void Write64(const VAddr addr, const u64 data) { Write(addr, data); } -void WriteBlock(const VAddr addr, const u8* data, const size_t size) { - for (u32 offset = 0; offset < size; offset++) { - Write8(addr + offset, data[offset]); +void WriteBlock(const VAddr dest_addr, const void* src_buffer, const size_t size) { + size_t remaining_size = size; + size_t page_index = dest_addr >> PAGE_BITS; + size_t page_offset = dest_addr & PAGE_MASK; + + while (remaining_size > 0) { + const size_t copy_amount = std::min(PAGE_SIZE - page_offset, remaining_size); + const VAddr current_vaddr = (page_index << PAGE_BITS) + page_offset; + + switch (current_page_table->attributes[page_index]) { + case PageType::Unmapped: { + LOG_ERROR(HW_Memory, "unmapped WriteBlock @ 0x%08X (start address = 0x%08X, size = %zu)", current_vaddr, dest_addr, size); + break; + } + case PageType::Memory: { + DEBUG_ASSERT(current_page_table->pointers[page_index]); + + u8* dest_ptr = current_page_table->pointers[page_index] + page_offset; + std::memcpy(dest_ptr, src_buffer, copy_amount); + break; + } + case PageType::Special: { + DEBUG_ASSERT(GetMMIOHandler(current_vaddr)); + + GetMMIOHandler(current_vaddr)->WriteBlock(current_vaddr, src_buffer, copy_amount); + break; + } + case PageType::RasterizerCachedMemory: { + RasterizerFlushAndInvalidateRegion(VirtualToPhysicalAddress(current_vaddr), copy_amount); + + std::memcpy(GetPointerFromVMA(current_vaddr), src_buffer, copy_amount); + break; + } + case PageType::RasterizerCachedSpecial: { + DEBUG_ASSERT(GetMMIOHandler(current_vaddr)); + + RasterizerFlushAndInvalidateRegion(VirtualToPhysicalAddress(current_vaddr), copy_amount); + + GetMMIOHandler(current_vaddr)->WriteBlock(current_vaddr, src_buffer, copy_amount); + break; + } + default: + UNREACHABLE(); + } + + page_index++; + page_offset = 0; + src_buffer = static_cast(src_buffer) + copy_amount; + remaining_size -= copy_amount; + } +} + +void ZeroBlock(const VAddr dest_addr, const size_t size) { + size_t remaining_size = size; + size_t page_index = dest_addr >> PAGE_BITS; + size_t page_offset = dest_addr & PAGE_MASK; + + static const std::array zeros = {}; + + while (remaining_size > 0) { + const size_t copy_amount = std::min(PAGE_SIZE - page_offset, remaining_size); + const VAddr current_vaddr = (page_index << PAGE_BITS) + page_offset; + + switch (current_page_table->attributes[page_index]) { + case PageType::Unmapped: { + LOG_ERROR(HW_Memory, "unmapped ZeroBlock @ 0x%08X (start address = 0x%08X, size = %zu)", current_vaddr, dest_addr, size); + break; + } + case PageType::Memory: { + DEBUG_ASSERT(current_page_table->pointers[page_index]); + + u8* dest_ptr = current_page_table->pointers[page_index] + page_offset; + std::memset(dest_ptr, 0, copy_amount); + break; + } + case PageType::Special: { + DEBUG_ASSERT(GetMMIOHandler(current_vaddr)); + + GetMMIOHandler(current_vaddr)->WriteBlock(current_vaddr, zeros.data(), copy_amount); + break; + } + case PageType::RasterizerCachedMemory: { + RasterizerFlushAndInvalidateRegion(VirtualToPhysicalAddress(current_vaddr), copy_amount); + + std::memset(GetPointerFromVMA(current_vaddr), 0, copy_amount); + break; + } + case PageType::RasterizerCachedSpecial: { + DEBUG_ASSERT(GetMMIOHandler(current_vaddr)); + + RasterizerFlushAndInvalidateRegion(VirtualToPhysicalAddress(current_vaddr), copy_amount); + + GetMMIOHandler(current_vaddr)->WriteBlock(current_vaddr, zeros.data(), copy_amount); + break; + } + default: + UNREACHABLE(); + } + + page_index++; + page_offset = 0; + remaining_size -= copy_amount; + } +} + +void CopyBlock(VAddr dest_addr, VAddr src_addr, const size_t size) { + size_t remaining_size = size; + size_t page_index = src_addr >> PAGE_BITS; + size_t page_offset = src_addr & PAGE_MASK; + + while (remaining_size > 0) { + const size_t copy_amount = std::min(PAGE_SIZE - page_offset, remaining_size); + const VAddr current_vaddr = (page_index << PAGE_BITS) + page_offset; + + switch (current_page_table->attributes[page_index]) { + case PageType::Unmapped: { + LOG_ERROR(HW_Memory, "unmapped CopyBlock @ 0x%08X (start address = 0x%08X, size = %zu)", current_vaddr, src_addr, size); + ZeroBlock(dest_addr, copy_amount); + break; + } + case PageType::Memory: { + DEBUG_ASSERT(current_page_table->pointers[page_index]); + const u8* src_ptr = current_page_table->pointers[page_index] + page_offset; + WriteBlock(dest_addr, src_ptr, copy_amount); + break; + } + case PageType::Special: { + DEBUG_ASSERT(GetMMIOHandler(current_vaddr)); + + std::vector buffer(copy_amount); + GetMMIOHandler(current_vaddr)->ReadBlock(current_vaddr, buffer.data(), buffer.size()); + WriteBlock(dest_addr, buffer.data(), buffer.size()); + break; + } + case PageType::RasterizerCachedMemory: { + RasterizerFlushRegion(VirtualToPhysicalAddress(current_vaddr), copy_amount); + + WriteBlock(dest_addr, GetPointerFromVMA(current_vaddr), copy_amount); + break; + } + case PageType::RasterizerCachedSpecial: { + DEBUG_ASSERT(GetMMIOHandler(current_vaddr)); + + RasterizerFlushRegion(VirtualToPhysicalAddress(current_vaddr), copy_amount); + + std::vector buffer(copy_amount); + GetMMIOHandler(current_vaddr)->ReadBlock(current_vaddr, buffer.data(), buffer.size()); + WriteBlock(dest_addr, buffer.data(), buffer.size()); + break; + } + default: + UNREACHABLE(); + } + + page_index++; + page_offset = 0; + dest_addr += copy_amount; + src_addr += copy_amount; + remaining_size -= copy_amount; } } diff --git a/src/core/memory.h b/src/core/memory.h index 126d60471..ae5588dee 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -110,6 +110,9 @@ enum : VAddr { NEW_LINEAR_HEAP_VADDR_END = NEW_LINEAR_HEAP_VADDR + NEW_LINEAR_HEAP_SIZE, }; +bool IsValidVirtualAddress(const VAddr addr); +bool IsValidPhysicalAddress(const PAddr addr); + u8 Read8(VAddr addr); u16 Read16(VAddr addr); u32 Read32(VAddr addr); @@ -120,7 +123,10 @@ void Write16(VAddr addr, u16 data); void Write32(VAddr addr, u32 data); void Write64(VAddr addr, u64 data); -void WriteBlock(VAddr addr, const u8* data, size_t size); +void ReadBlock(const VAddr src_addr, void* dest_buffer, size_t size); +void WriteBlock(const VAddr dest_addr, const void* src_buffer, size_t size); +void ZeroBlock(const VAddr dest_addr, const size_t size); +void CopyBlock(VAddr dest_addr, VAddr src_addr, size_t size); u8* GetPointer(VAddr virtual_address); diff --git a/src/core/mmio.h b/src/core/mmio.h index 06b555e98..d76f005d8 100644 --- a/src/core/mmio.h +++ b/src/core/mmio.h @@ -18,15 +18,21 @@ class MMIORegion { public: virtual ~MMIORegion() = default; + virtual bool IsValidAddress(VAddr addr) = 0; + virtual u8 Read8(VAddr addr) = 0; virtual u16 Read16(VAddr addr) = 0; virtual u32 Read32(VAddr addr) = 0; virtual u64 Read64(VAddr addr) = 0; + virtual bool ReadBlock(VAddr src_addr, void* dest_buffer, size_t size) = 0; + virtual void Write8(VAddr addr, u8 data) = 0; virtual void Write16(VAddr addr, u16 data) = 0; virtual void Write32(VAddr addr, u32 data) = 0; virtual void Write64(VAddr addr, u64 data) = 0; + + virtual bool WriteBlock(VAddr dest_addr, const void* src_buffer, size_t size) = 0; }; using MMIORegionPointer = std::shared_ptr;