feat(p2p): Port overrides for Splatoon and MK8
Some checks are pending
Inkay-CI / build-inkay (push) Waiting to run

This commit is contained in:
Ash Logan 2024-11-29 21:39:50 +11:00
parent 727f11d04d
commit a6b91be935
4 changed files with 78 additions and 14 deletions

View File

@ -22,9 +22,56 @@
#include "utils/replace_mem.h"
#include <optional>
#include <algorithm>
#include <string_view>
using namespace std::string_view_literals;
static struct {
std::array<uint64_t, 3> tid;
uint32_t min_port_addr;
uint32_t max_port_addr;
std::string_view rpx;
} generic_patch_games [] = {
{ // MARIO KART 8
{ 0x00050000'1010ec00, 0x00050000'1010ed00, 0x00050000'1010eb00 },
0x101a9a52,
0x101a9a54,
"Turbo.rpx"sv,
},
{ // Splatoon
{ 0x00050000'10176900, 0x00050000'10176a00, 0x00050000'10162b00 },
0x101e8952,
0x101e8954,
"Gambit.rpx"sv,
},
};
static void generic_peertopeer_patch() {
uint64_t tid = OSGetTitleID();
for (const auto& patch : generic_patch_games) {
if (std::ranges::find(patch.tid, tid) == patch.tid.end()) continue;
std::optional<OSDynLoad_NotifyData> game = search_for_rpl(patch.rpx);
if (!game) {
DEBUG_FUNCTION_LINE("Couldn't find game rpx! (%s)", patch.rpx.data());
return;
}
auto port = get_console_peertopeer_port();
DEBUG_FUNCTION_LINE_VERBOSE("Will use port %d. %08x", port, game->textAddr);
auto target = (uint16_t *)rpl_addr(*game, patch.min_port_addr);
replace_unsigned<uint16_t>(target, 0xc000, port);
target = (uint16_t *)rpl_addr(*game, patch.max_port_addr);
replace_unsigned<uint16_t>(target, 0xffff, port);
break;
}
}
static void minecraft_peertopeer_patch() {
std::optional<OSDynLoad_NotifyData> minecraft = search_for_rpl("Minecraft.Client.rpx");
std::optional<OSDynLoad_NotifyData> minecraft = search_for_rpl("Minecraft.Client.rpx"sv);
if (!minecraft) {
DEBUG_FUNCTION_LINE("Couldn't find minecraft rpx!");
return;
@ -33,12 +80,12 @@ static void minecraft_peertopeer_patch() {
auto port = get_console_peertopeer_port();
DEBUG_FUNCTION_LINE_VERBOSE("Will use port %d. %08x", port, minecraft->textAddr);
uint32_t *target_func = rpl_addr(*minecraft, 0x03579530);
auto target_func = (uint32_t *)rpl_addr(*minecraft, 0x03579530);
replace_instruction(&target_func[0], 0x3c600001, 0x3c600000); // li r3, 0
replace_instruction(&target_func[1], 0x3863c000, 0x60630000 | port); // ori r3, r3, port
// blr
target_func = rpl_addr(*minecraft, 0x0357953c);
target_func = (uint32_t *)rpl_addr(*minecraft, 0x0357953c);
replace_instruction(&target_func[0], 0x3c600001, 0x3c600000); // li r3, 0
replace_instruction(&target_func[1], 0x3863ffff, 0x60630000 | port); // ori r3, r3, port
// blr
@ -56,6 +103,6 @@ void peertopeer_patch() {
minecraft_peertopeer_patch();
} else {
DEBUG_FUNCTION_LINE_VERBOSE("Game has no p2p patches, will skip.\n");
generic_peertopeer_patch();
}
}

View File

@ -73,17 +73,30 @@ void replaceBulk(uint32_t start, uint32_t size, std::span<const replacement> rep
#endif
}
bool replace_instruction(uint32_t *inst, uint32_t orignal_value, uint32_t new_value) {
if (*inst != orignal_value) return false;
template <typename U>
requires std::integral<U>
bool replace_unsigned(U *addr, U original_value, U new_value) {
if (*addr != original_value) return false;
KernelCopyData(
OSEffectiveToPhysical((uint32_t) inst),
OSEffectiveToPhysical((uint32_t) addr),
OSEffectiveToPhysical((uint32_t) &new_value),
sizeof(new_value)
);
DCFlushRange(inst, sizeof(new_value));
ICInvalidateRange(inst, sizeof(new_value));
DCFlushRange(addr, sizeof(new_value));
DEBUG_FUNCTION_LINE_VERBOSE("%08x is now %08x", inst, *inst);
return *inst == new_value;
return *addr == new_value;
}
template bool replace_unsigned<uint64_t>(uint64_t *, uint64_t, uint64_t);
template bool replace_unsigned<uint32_t>(uint32_t *, uint32_t, uint32_t);
template bool replace_unsigned<uint16_t>(uint16_t *, uint16_t, uint16_t);
template bool replace_unsigned<uint8_t>(uint8_t *, uint8_t, uint8_t);
bool replace_instruction(uint32_t *inst, uint32_t original_value, uint32_t new_value) {
bool res = replace_unsigned<uint32_t>(inst, original_value, new_value);
if (!res) return res;
ICInvalidateRange(inst, sizeof(new_value));
return true;
}

View File

@ -28,4 +28,8 @@ struct replacement {
void replaceBulk(uint32_t start, uint32_t size, std::span<const replacement> replacements);
bool replace_instruction(uint32_t *inst, uint32_t orignal_value, uint32_t new_value);
template <typename U>
requires std::integral<U>
bool replace_unsigned(U *addr, U original_value, U new_value);
bool replace_instruction(uint32_t *inst, uint32_t original_value, uint32_t new_value);

View File

@ -19,10 +19,10 @@
std::optional<OSDynLoad_NotifyData> search_for_rpl(std::string_view name);
constexpr uint32_t *rpl_addr(OSDynLoad_NotifyData rpl, uint32_t cemu_addr) {
constexpr void *rpl_addr(OSDynLoad_NotifyData rpl, uint32_t cemu_addr) {
if (cemu_addr < 0x1000'0000) {
return (uint32_t *)(rpl.textAddr + cemu_addr - 0x0200'0000);
return (void *)(rpl.textAddr + cemu_addr - 0x0200'0000);
} else {
return (uint32_t *)(rpl.dataAddr + cemu_addr - 0x1000'0000);
return (void *)(rpl.dataAddr + cemu_addr - 0x1000'0000);
}
}