Merge yuzu-emu#12915
This commit is contained in:
		| @@ -9,6 +9,7 @@ | |||||||
| #include "core/core_timing.h" | #include "core/core_timing.h" | ||||||
| #include "core/hle/kernel/k_page_table.h" | #include "core/hle/kernel/k_page_table.h" | ||||||
| #include "core/hle/kernel/k_process.h" | #include "core/hle/kernel/k_process.h" | ||||||
|  | #include "core/hle/kernel/k_process_page_table.h" | ||||||
| #include "core/hle/service/hid/hid_server.h" | #include "core/hle/service/hid/hid_server.h" | ||||||
| #include "core/hle/service/sm/sm.h" | #include "core/hle/service/sm/sm.h" | ||||||
| #include "core/memory.h" | #include "core/memory.h" | ||||||
| @@ -85,8 +86,12 @@ VAddr StandardVmCallbacks::SanitizeAddress(VAddr in) const { | |||||||
|     if ((in < metadata.main_nso_extents.base || |     if ((in < metadata.main_nso_extents.base || | ||||||
|          in >= metadata.main_nso_extents.base + metadata.main_nso_extents.size) && |          in >= metadata.main_nso_extents.base + metadata.main_nso_extents.size) && | ||||||
|         (in < metadata.heap_extents.base || |         (in < metadata.heap_extents.base || | ||||||
|          in >= metadata.heap_extents.base + metadata.heap_extents.size)) { |          in >= metadata.heap_extents.base + metadata.heap_extents.size) && | ||||||
|         LOG_ERROR(CheatEngine, |         (in < metadata.alias_extents.base || | ||||||
|  |          in >= metadata.heap_extents.base + metadata.alias_extents.size) && | ||||||
|  |         (in < metadata.aslr_extents.base || | ||||||
|  |          in >= metadata.heap_extents.base + metadata.aslr_extents.size)) { | ||||||
|  |         LOG_DEBUG(CheatEngine, | ||||||
|                   "Cheat attempting to access memory at invalid address={:016X}, if this " |                   "Cheat attempting to access memory at invalid address={:016X}, if this " | ||||||
|                   "persists, " |                   "persists, " | ||||||
|                   "the cheat may be incorrect. However, this may be normal early in execution if " |                   "the cheat may be incorrect. However, this may be normal early in execution if " | ||||||
| @@ -211,16 +216,14 @@ void CheatEngine::Initialize() { | |||||||
|         .base = GetInteger(page_table.GetHeapRegionStart()), |         .base = GetInteger(page_table.GetHeapRegionStart()), | ||||||
|         .size = page_table.GetHeapRegionSize(), |         .size = page_table.GetHeapRegionSize(), | ||||||
|     }; |     }; | ||||||
|  |     metadata.aslr_extents = { | ||||||
|     metadata.address_space_extents = { |  | ||||||
|         .base = GetInteger(page_table.GetAddressSpaceStart()), |  | ||||||
|         .size = page_table.GetAddressSpaceSize(), |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     metadata.alias_extents = { |  | ||||||
|         .base = GetInteger(page_table.GetAliasCodeRegionStart()), |         .base = GetInteger(page_table.GetAliasCodeRegionStart()), | ||||||
|         .size = page_table.GetAliasCodeRegionSize(), |         .size = page_table.GetAliasCodeRegionSize(), | ||||||
|     }; |     }; | ||||||
|  |     metadata.alias_extents = { | ||||||
|  |         .base = GetInteger(page_table.GetAliasRegionStart()), | ||||||
|  |         .size = page_table.GetAliasRegionSize(), | ||||||
|  |     }; | ||||||
|  |  | ||||||
|     is_pending_reload.exchange(true); |     is_pending_reload.exchange(true); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -37,7 +37,7 @@ private: | |||||||
|     VAddr SanitizeAddress(VAddr address) const; |     VAddr SanitizeAddress(VAddr address) const; | ||||||
|  |  | ||||||
|     const CheatProcessMetadata& metadata; |     const CheatProcessMetadata& metadata; | ||||||
|     System& system; |     Core::System& system; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| // Intermediary class that parses a text file or other disk format for storing cheats into a | // Intermediary class that parses a text file or other disk format for storing cheats into a | ||||||
|   | |||||||
| @@ -18,7 +18,7 @@ struct CheatProcessMetadata { | |||||||
|     MemoryRegionExtents main_nso_extents{}; |     MemoryRegionExtents main_nso_extents{}; | ||||||
|     MemoryRegionExtents heap_extents{}; |     MemoryRegionExtents heap_extents{}; | ||||||
|     MemoryRegionExtents alias_extents{}; |     MemoryRegionExtents alias_extents{}; | ||||||
|     MemoryRegionExtents address_space_extents{}; |     MemoryRegionExtents aslr_extents{}; | ||||||
|     std::array<u8, 0x20> main_nso_build_id{}; |     std::array<u8, 0x20> main_nso_build_id{}; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -322,8 +322,9 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) { | |||||||
|     } break; |     } break; | ||||||
|     case CheatVmOpcodeType::EndConditionalBlock: { |     case CheatVmOpcodeType::EndConditionalBlock: { | ||||||
|         // 20000000 |         // 20000000 | ||||||
|         // There's actually nothing left to process here! |         opcode.opcode = EndConditionalOpcode{ | ||||||
|         opcode.opcode = EndConditionalOpcode{}; |             .is_else = ((first_dword >> 24) & 0xf) == 1, | ||||||
|  |         }; | ||||||
|     } break; |     } break; | ||||||
|     case CheatVmOpcodeType::ControlLoop: { |     case CheatVmOpcodeType::ControlLoop: { | ||||||
|         // 300R0000 VVVVVVVV |         // 300R0000 VVVVVVVV | ||||||
| @@ -555,6 +556,18 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) { | |||||||
|             .idx = first_dword & 0xF, |             .idx = first_dword & 0xF, | ||||||
|         }; |         }; | ||||||
|     } break; |     } break; | ||||||
|  |     case CheatVmOpcodeType::PauseProcess: { | ||||||
|  |         /* FF0????? */ | ||||||
|  |         /* FF0 = opcode 0xFF0 */ | ||||||
|  |         /* Pauses the current process. */ | ||||||
|  |         opcode.opcode = PauseProcessOpcode{}; | ||||||
|  |     } break; | ||||||
|  |     case CheatVmOpcodeType::ResumeProcess: { | ||||||
|  |         /* FF0????? */ | ||||||
|  |         /* FF0 = opcode 0xFF0 */ | ||||||
|  |         /* Pauses the current process. */ | ||||||
|  |         opcode.opcode = ResumeProcessOpcode{}; | ||||||
|  |     } break; | ||||||
|     case CheatVmOpcodeType::DebugLog: { |     case CheatVmOpcodeType::DebugLog: { | ||||||
|         // FFFTIX## |         // FFFTIX## | ||||||
|         // FFFTI0Ma aaaaaaaa |         // FFFTI0Ma aaaaaaaa | ||||||
| @@ -621,7 +634,7 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) { | |||||||
|     return valid; |     return valid; | ||||||
| } | } | ||||||
|  |  | ||||||
| void DmntCheatVm::SkipConditionalBlock() { | void DmntCheatVm::SkipConditionalBlock(bool is_if) { | ||||||
|     if (condition_depth > 0) { |     if (condition_depth > 0) { | ||||||
|         // We want to continue until we're out of the current block. |         // We want to continue until we're out of the current block. | ||||||
|         const std::size_t desired_depth = condition_depth - 1; |         const std::size_t desired_depth = condition_depth - 1; | ||||||
| @@ -637,8 +650,12 @@ void DmntCheatVm::SkipConditionalBlock() { | |||||||
|             // We also support nesting of conditional blocks, and Gateway does not. |             // We also support nesting of conditional blocks, and Gateway does not. | ||||||
|             if (skip_opcode.begin_conditional_block) { |             if (skip_opcode.begin_conditional_block) { | ||||||
|                 condition_depth++; |                 condition_depth++; | ||||||
|             } else if (std::holds_alternative<EndConditionalOpcode>(skip_opcode.opcode)) { |             } else if (auto end_cond = std::get_if<EndConditionalOpcode>(&skip_opcode.opcode)) { | ||||||
|  |                 if (!end_cond->is_else) { | ||||||
|                     condition_depth--; |                     condition_depth--; | ||||||
|  |                 } else if (is_if && condition_depth - 1 == desired_depth) { | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } else { |     } else { | ||||||
| @@ -675,6 +692,10 @@ u64 DmntCheatVm::GetCheatProcessAddress(const CheatProcessMetadata& metadata, | |||||||
|         return metadata.main_nso_extents.base + rel_address; |         return metadata.main_nso_extents.base + rel_address; | ||||||
|     case MemoryAccessType::Heap: |     case MemoryAccessType::Heap: | ||||||
|         return metadata.heap_extents.base + rel_address; |         return metadata.heap_extents.base + rel_address; | ||||||
|  |     case MemoryAccessType::Alias: | ||||||
|  |         return metadata.alias_extents.base + rel_address; | ||||||
|  |     case MemoryAccessType::Aslr: | ||||||
|  |         return metadata.aslr_extents.base + rel_address; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -682,7 +703,6 @@ void DmntCheatVm::ResetState() { | |||||||
|     registers.fill(0); |     registers.fill(0); | ||||||
|     saved_values.fill(0); |     saved_values.fill(0); | ||||||
|     loop_tops.fill(0); |     loop_tops.fill(0); | ||||||
|     static_registers.fill(0); |  | ||||||
|     instruction_ptr = 0; |     instruction_ptr = 0; | ||||||
|     condition_depth = 0; |     condition_depth = 0; | ||||||
|     decode_success = true; |     decode_success = true; | ||||||
| @@ -794,14 +814,19 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) { | |||||||
|             } |             } | ||||||
|             // Skip conditional block if condition not met. |             // Skip conditional block if condition not met. | ||||||
|             if (!cond_met) { |             if (!cond_met) { | ||||||
|                 SkipConditionalBlock(); |                 SkipConditionalBlock(true); | ||||||
|             } |             } | ||||||
|         } else if (std::holds_alternative<EndConditionalOpcode>(cur_opcode.opcode)) { |         } else if (auto end_cond = std::get_if<EndConditionalOpcode>(&cur_opcode.opcode)) { | ||||||
|             // Decrement the condition depth. |             if (end_cond->is_else) { | ||||||
|             // We will assume, graciously, that mismatched conditional block ends are a nop. |                 /* Skip to the end of the conditional block. */ | ||||||
|  |                 this->SkipConditionalBlock(false); | ||||||
|  |             } else { | ||||||
|  |                 /* Decrement the condition depth. */ | ||||||
|  |                 /* We will assume, graciously, that mismatched conditional block ends are a nop. */ | ||||||
|                 if (condition_depth > 0) { |                 if (condition_depth > 0) { | ||||||
|                     condition_depth--; |                     condition_depth--; | ||||||
|                 } |                 } | ||||||
|  |             } | ||||||
|         } else if (auto ctrl_loop = std::get_if<ControlLoopOpcode>(&cur_opcode.opcode)) { |         } else if (auto ctrl_loop = std::get_if<ControlLoopOpcode>(&cur_opcode.opcode)) { | ||||||
|             if (ctrl_loop->start_loop) { |             if (ctrl_loop->start_loop) { | ||||||
|                 // Start a loop. |                 // Start a loop. | ||||||
| @@ -908,7 +933,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) { | |||||||
|             // Check for keypress. |             // Check for keypress. | ||||||
|             if ((begin_keypress_cond->key_mask & kDown) != begin_keypress_cond->key_mask) { |             if ((begin_keypress_cond->key_mask & kDown) != begin_keypress_cond->key_mask) { | ||||||
|                 // Keys not pressed. Skip conditional block. |                 // Keys not pressed. Skip conditional block. | ||||||
|                 SkipConditionalBlock(); |                 SkipConditionalBlock(true); | ||||||
|             } |             } | ||||||
|         } else if (auto perform_math_reg = |         } else if (auto perform_math_reg = | ||||||
|                        std::get_if<PerformArithmeticRegisterOpcode>(&cur_opcode.opcode)) { |                        std::get_if<PerformArithmeticRegisterOpcode>(&cur_opcode.opcode)) { | ||||||
| @@ -1116,7 +1141,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) { | |||||||
|  |  | ||||||
|             // Skip conditional block if condition not met. |             // Skip conditional block if condition not met. | ||||||
|             if (!cond_met) { |             if (!cond_met) { | ||||||
|                 SkipConditionalBlock(); |                 SkipConditionalBlock(true); | ||||||
|             } |             } | ||||||
|         } else if (auto save_restore_reg = |         } else if (auto save_restore_reg = | ||||||
|                        std::get_if<SaveRestoreRegisterOpcode>(&cur_opcode.opcode)) { |                        std::get_if<SaveRestoreRegisterOpcode>(&cur_opcode.opcode)) { | ||||||
| @@ -1178,6 +1203,10 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) { | |||||||
|                 // Store a register to a static register. |                 // Store a register to a static register. | ||||||
|                 static_registers[rw_static_reg->static_idx] = registers[rw_static_reg->idx]; |                 static_registers[rw_static_reg->static_idx] = registers[rw_static_reg->idx]; | ||||||
|             } |             } | ||||||
|  |         } else if (std::holds_alternative<PauseProcessOpcode>(cur_opcode.opcode)) { | ||||||
|  |             // TODO: Pause cheat process | ||||||
|  |         } else if (std::holds_alternative<ResumeProcessOpcode>(cur_opcode.opcode)) { | ||||||
|  |             // TODO: Resume cheat process | ||||||
|         } else if (auto debug_log = std::get_if<DebugLogOpcode>(&cur_opcode.opcode)) { |         } else if (auto debug_log = std::get_if<DebugLogOpcode>(&cur_opcode.opcode)) { | ||||||
|             // Read value from memory. |             // Read value from memory. | ||||||
|             u64 log_value = 0; |             u64 log_value = 0; | ||||||
|   | |||||||
| @@ -42,12 +42,16 @@ enum class CheatVmOpcodeType : u32 { | |||||||
|     DoubleExtendedWidth = 0xF0, |     DoubleExtendedWidth = 0xF0, | ||||||
|  |  | ||||||
|     // Double-extended width opcodes. |     // Double-extended width opcodes. | ||||||
|  |     PauseProcess = 0xFF0, | ||||||
|  |     ResumeProcess = 0xFF1, | ||||||
|     DebugLog = 0xFFF, |     DebugLog = 0xFFF, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| enum class MemoryAccessType : u32 { | enum class MemoryAccessType : u32 { | ||||||
|     MainNso = 0, |     MainNso = 0, | ||||||
|     Heap = 1, |     Heap = 1, | ||||||
|  |     Alias = 2, | ||||||
|  |     Aslr = 3, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| enum class ConditionalComparisonType : u32 { | enum class ConditionalComparisonType : u32 { | ||||||
| @@ -131,7 +135,9 @@ struct BeginConditionalOpcode { | |||||||
|     VmInt value{}; |     VmInt value{}; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| struct EndConditionalOpcode {}; | struct EndConditionalOpcode { | ||||||
|  |     bool is_else; | ||||||
|  | }; | ||||||
|  |  | ||||||
| struct ControlLoopOpcode { | struct ControlLoopOpcode { | ||||||
|     bool start_loop{}; |     bool start_loop{}; | ||||||
| @@ -222,6 +228,10 @@ struct ReadWriteStaticRegisterOpcode { | |||||||
|     u32 idx{}; |     u32 idx{}; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | struct PauseProcessOpcode {}; | ||||||
|  |  | ||||||
|  | struct ResumeProcessOpcode {}; | ||||||
|  |  | ||||||
| struct DebugLogOpcode { | struct DebugLogOpcode { | ||||||
|     u32 bit_width{}; |     u32 bit_width{}; | ||||||
|     u32 log_id{}; |     u32 log_id{}; | ||||||
| @@ -244,8 +254,8 @@ struct CheatVmOpcode { | |||||||
|                  PerformArithmeticStaticOpcode, BeginKeypressConditionalOpcode, |                  PerformArithmeticStaticOpcode, BeginKeypressConditionalOpcode, | ||||||
|                  PerformArithmeticRegisterOpcode, StoreRegisterToAddressOpcode, |                  PerformArithmeticRegisterOpcode, StoreRegisterToAddressOpcode, | ||||||
|                  BeginRegisterConditionalOpcode, SaveRestoreRegisterOpcode, |                  BeginRegisterConditionalOpcode, SaveRestoreRegisterOpcode, | ||||||
|                  SaveRestoreRegisterMaskOpcode, ReadWriteStaticRegisterOpcode, DebugLogOpcode, |                  SaveRestoreRegisterMaskOpcode, ReadWriteStaticRegisterOpcode, PauseProcessOpcode, | ||||||
|                  UnrecognizedInstruction> |                  ResumeProcessOpcode, DebugLogOpcode, UnrecognizedInstruction> | ||||||
|         opcode{}; |         opcode{}; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @@ -296,7 +306,7 @@ private: | |||||||
|     std::array<std::size_t, NumRegisters> loop_tops{}; |     std::array<std::size_t, NumRegisters> loop_tops{}; | ||||||
|  |  | ||||||
|     bool DecodeNextOpcode(CheatVmOpcode& out); |     bool DecodeNextOpcode(CheatVmOpcode& out); | ||||||
|     void SkipConditionalBlock(); |     void SkipConditionalBlock(bool is_if); | ||||||
|     void ResetState(); |     void ResetState(); | ||||||
|  |  | ||||||
|     // For implementing the DebugLog opcode. |     // For implementing the DebugLog opcode. | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user