Skip to content

Commit 3e2ed9e

Browse files
committed
Separate segment and function addresses in PPU LLVM
1 parent 96e1f82 commit 3e2ed9e

4 files changed

Lines changed: 54 additions & 37 deletions

File tree

‎rpcs3/Emu/Cell/PPUThread.cpp‎

Lines changed: 34 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -225,13 +225,13 @@ const auto ppu_gateway = build_function_asm<void(*)(ppu_thread*)>("ppu_gateway",
225225
c.mov(x86::rbp, args[0]);
226226
c.mov(x86::edx, x86::dword_ptr(x86::rbp, ::offset32(&ppu_thread::cia))); // Load PC
227227

228-
c.mov(x86::rax, x86::qword_ptr(x86::r13, x86::edx, 1, 0)); // Load call target
229-
c.mov(x86::rdx, x86::rax);
230-
c.shl(x86::rax, 16);
231-
c.shr(x86::rax, 16);
232-
c.shr(x86::rdx, 48);
228+
c.mov(x86::rax, x86::qword_ptr(x86::r13, x86::rdx, 1, 0)); // Load call target
229+
c.movabs(x86::r12, vm::g_exec_addr_seg_offset);
230+
c.add(x86::r12, x86::r13);
231+
c.shr(x86::edx, 1);
232+
c.mov(x86::edx, x86::word_ptr(x86::r12, x86::edx)); // Load relocation base
233233
c.shl(x86::edx, 13);
234-
c.mov(x86::r12d, x86::edx); // Load relocation base
234+
c.mov(x86::r12d, x86::edx); // Set relocation base
235235

236236
c.movabs(x86::rbx, reinterpret_cast<u64>(&vm::g_base_addr));
237237
c.mov(x86::rbx, x86::qword_ptr(x86::rbx));
@@ -348,14 +348,11 @@ const auto ppu_gateway = build_function_asm<void(*)(ppu_thread*)>("ppu_gateway",
348348
c.ldr(call_target, arm::Mem(a64::x19, pc));
349349
// Compute REG_Hp
350350
const arm::GpX reg_hp = a64::x21;
351-
c.mov(reg_hp, call_target);
352-
c.lsr(reg_hp, reg_hp, 48);
351+
c.mov(reg_hp, Imm(vm::g_exec_addr_seg_offset));
352+
c.add(reg_hp, reg_hp, pc, arm::Shift(arm::ShiftOp::kLSR, 2));
353+
c.ldrh(reg_hp.w(), arm::Mem(a64::x19, reg_hp));
353354
c.lsl(reg_hp.w(), reg_hp.w(), 13);
354355

355-
// Zero top 16 bits of call target
356-
c.lsl(call_target, call_target, Imm(16));
357-
c.lsr(call_target, call_target, Imm(16));
358-
359356
// Load registers
360357
c.mov(a64::x22, Imm(reinterpret_cast<u64>(&vm::g_base_addr)));
361358
c.ldr(a64::x22, arm::Mem(a64::x22));
@@ -475,6 +472,11 @@ static inline u8* ppu_ptr(u32 addr)
475472
return vm::g_exec_addr + u64{addr} * 2;
476473
}
477474

475+
static inline u8* ppu_seg_ptr(u32 addr)
476+
{
477+
return vm::g_exec_addr + vm::g_exec_addr_seg_offset + (addr >> 1);
478+
}
479+
478480
static inline ppu_intrp_func_t ppu_read(u32 addr)
479481
{
480482
return read_from_ptr<ppu_intrp_func_t>(ppu_ptr(addr));
@@ -520,7 +522,7 @@ void ppu_recompiler_fallback(ppu_thread& ppu)
520522

521523
while (true)
522524
{
523-
if (uptr func = uptr(ppu_read(ppu.cia)); (func << 16 >> 16) != reinterpret_cast<uptr>(ppu_recompiler_fallback_ghc))
525+
if (uptr func = uptr(ppu_read(ppu.cia)); func != reinterpret_cast<uptr>(ppu_recompiler_fallback_ghc))
524526
{
525527
// We found a recompiler function at cia, return
526528
break;
@@ -775,6 +777,9 @@ extern void ppu_register_range(u32 addr, u32 size)
775777
utils::memory_commit(ppu_ptr(addr), u64{size} * 2, utils::protection::rw);
776778
ensure(vm::page_protect(addr, size, 0, vm::page_executable));
777779

780+
// Segment data
781+
utils::memory_commit(ppu_seg_ptr(addr), size >> 1, utils::protection::rw);
782+
778783
if (g_cfg.core.ppu_debug)
779784
{
780785
utils::memory_commit(vm::g_stat_addr + addr, size);
@@ -787,12 +792,13 @@ extern void ppu_register_range(u32 addr, u32 size)
787792
if (g_cfg.core.ppu_decoder == ppu_decoder_type::llvm)
788793
{
789794
// Assume addr is the start of first segment of PRX
790-
const uptr entry_value = reinterpret_cast<uptr>(ppu_recompiler_fallback_ghc) | (seg_base << (32 + 3));
791-
write_to_ptr<uptr>(ppu_ptr(addr), entry_value);
795+
write_to_ptr<uptr>(ppu_ptr(addr), std::bit_cast<uptr>(ppu_recompiler_fallback_ghc));
796+
write_to_ptr<u16>(ppu_seg_ptr(addr), static_cast<u16>(seg_base >> 13));
792797
}
793798
else
794799
{
795800
write_to_ptr<ppu_intrp_func_t>(ppu_ptr(addr), ppu_fallback);
801+
write_to_ptr<u16>(ppu_seg_ptr(addr), 0);
796802
}
797803

798804
addr += 4;
@@ -807,7 +813,7 @@ extern void ppu_register_function_at(u32 addr, u32 size, ppu_intrp_func_t ptr =
807813
// Initialize specific function
808814
if (ptr)
809815
{
810-
write_to_ptr<uptr>(ppu_ptr(addr), (reinterpret_cast<uptr>(ptr) & 0xffff'ffff'ffffu) | (uptr(ppu_read(addr)) & ~0xffff'ffff'ffffu));
816+
write_to_ptr<uptr>(ppu_ptr(addr), std::bit_cast<uptr>(ptr));
811817
return;
812818
}
813819

@@ -5087,14 +5093,14 @@ bool ppu_initialize(const ppu_module<lv2_obj>& info, bool check_only, u64 file_s
50875093
c.mov(x86::rax, x86::qword_ptr(x86::rax));
50885094
c.mov(x86::dword_ptr(x86::rbp, ::offset32(&ppu_thread::cia)), x86::edx);
50895095

5090-
c.mov(x86::rax, x86::qword_ptr(x86::rax, x86::rdx, 1, 0)); // Load call target
5091-
c.mov(x86::rdx, x86::rax);
5092-
c.shl(x86::rax, 16);
5093-
c.shr(x86::rax, 16);
5094-
c.shr(x86::rdx, 48);
5096+
c.mov(x86::rcx, x86::qword_ptr(x86::rax, x86::rdx, 1, 0)); // Load call target
5097+
c.movabs(x86::r12, vm::g_exec_addr_seg_offset);
5098+
c.add(x86::rax, x86::r12);
5099+
c.shr(x86::edx, 1);
5100+
c.mov(x86::edx, x86::word_ptr(x86::rax, x86::edx)); // Load relocation base
50955101
c.shl(x86::edx, 13);
5096-
c.mov(x86::r12d, x86::edx); // Load relocation base
5097-
c.jmp(x86::rax);
5102+
c.mov(x86::r12d, x86::edx); // Set relocation base
5103+
c.jmp(x86::rcx);
50985104
#else
50995105
// Load REG_Base - use absolute jump target to bypass rel jmp range limits
51005106
// X19 contains vm::g_exec_addr
@@ -5130,14 +5136,11 @@ bool ppu_initialize(const ppu_module<lv2_obj>& info, bool check_only, u64 file_s
51305136

51315137
// Compute REG_Hp
51325138
const arm::GpX reg_hp = a64::x21;
5133-
c.mov(reg_hp, call_target);
5134-
c.lsr(reg_hp, reg_hp, 48);
5139+
c.mov(reg_hp, Imm(vm::g_exec_addr_seg_offset));
5140+
c.add(reg_hp, reg_hp, pc, arm::Shift(arm::ShiftOp::kLSR, 2));
5141+
c.ldrh(reg_hp.w(), arm::Mem(exec_addr, reg_hp));
51355142
c.lsl(reg_hp.w(), reg_hp.w(), 13);
51365143

5137-
// Zero top 16 bits of call target
5138-
c.lsl(call_target, call_target, 16);
5139-
c.lsr(call_target, call_target, 16);
5140-
51415144
// Execute LLE call
51425145
c.br(call_target);
51435146
#endif
@@ -5405,7 +5408,7 @@ bool ppu_initialize(const ppu_module<lv2_obj>& info, bool check_only, u64 file_s
54055408
settings += ppu_settings::contains_symbol_resolver; // Avoid invalidating all modules for this purpose
54065409

54075410
// Write version, hash, CPU, settings
5408-
fmt::append(obj_name, "v6-kusa-%s-%s-%s.obj", fmt::base57(output, 16), fmt::base57(settings), jit_compiler::cpu(g_cfg.core.llvm_cpu));
5411+
fmt::append(obj_name, "v7-kusa-%s-%s-%s.obj", fmt::base57(output, 16), fmt::base57(settings), jit_compiler::cpu(g_cfg.core.llvm_cpu));
54095412
}
54105413

54115414
if (cpu ? cpu->state.all_of(cpu_flag::exit) : Emu.IsStopped())
@@ -5717,7 +5720,7 @@ bool ppu_initialize(const ppu_module<lv2_obj>& info, bool check_only, u64 file_s
57175720

57185721
for (u32 addr = info.segs[0].addr; addr < info.segs[0].addr + info.segs[0].size; addr += 4, inst_ptr++)
57195722
{
5720-
if (*inst_ptr == ppu_instructions::BLR() && (reinterpret_cast<uptr>(ppu_read(addr)) << 16 >> 16) == reinterpret_cast<uptr>(ppu_recompiler_fallback_ghc))
5723+
if (*inst_ptr == ppu_instructions::BLR() && reinterpret_cast<uptr>(ppu_read(addr)) == reinterpret_cast<uptr>(ppu_recompiler_fallback_ghc))
57215724
{
57225725
write_to_ptr<ppu_intrp_func_t>(ppu_ptr(addr), BLR_func);
57235726
}

‎rpcs3/Emu/Cell/PPUTranslator.cpp‎

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -411,12 +411,19 @@ Function* PPUTranslator::GetSymbolResolver(const ppu_module<lv2_obj>& info)
411411

412412
const auto faddr = m_ir->CreateLoad(ptr_inst->getResultElementType(), ptr_inst);
413413
const auto faddr_int = m_ir->CreatePtrToInt(faddr, get_type<uptr>());
414-
const auto fval = m_ir->CreateOr(m_ir->CreateShl(m_seg0, 32 + 3), faddr_int);
415-
const auto pos = m_ir->CreateShl(m_reloc ? m_ir->CreateAdd(func_pc, m_seg0) : func_pc, 1);
414+
const auto pos_32 = m_reloc ? m_ir->CreateAdd(func_pc, m_seg0) : func_pc;
415+
const auto pos = m_ir->CreateShl(pos_32, 1);
416416
const auto ptr = dyn_cast<GetElementPtrInst>(m_ir->CreateGEP(get_type<u8>(), m_exec, pos));
417417

418+
const auto seg_base_ptr = m_ir->CreateIntToPtr(m_ir->CreateAdd(
419+
m_ir->CreatePtrToInt(m_exec, get_type<u64>()), m_ir->getInt64(vm::g_exec_addr_seg_offset)), m_exec->getType());
420+
const auto seg_pos = m_ir->CreateLShr(pos_32, 1);
421+
const auto seg_ptr = dyn_cast<GetElementPtrInst>(m_ir->CreateGEP(get_type<u8>(), seg_base_ptr, seg_pos));
422+
const auto seg_val = m_ir->CreateTrunc(m_ir->CreateLShr(m_seg0, 13), get_type<u16>());
423+
418424
// Store to jumptable
419-
m_ir->CreateStore(fval, ptr);
425+
m_ir->CreateStore(faddr_int, ptr);
426+
m_ir->CreateStore(seg_val, seg_ptr);
420427

421428
// Increment index and branch back to loop
422429
const auto post_add = m_ir->CreateAdd(index_value, m_ir->getInt64(1));
@@ -605,10 +612,15 @@ void PPUTranslator::CallFunction(u64 target, Value* indirect)
605612
const auto pos = m_ir->CreateShl(indirect, 1);
606613
const auto ptr = dyn_cast<GetElementPtrInst>(m_ir->CreateGEP(get_type<u8>(), m_exec, pos));
607614
const auto val = m_ir->CreateLoad(get_type<u64>(), ptr);
608-
callee = FunctionCallee(type, m_ir->CreateIntToPtr(m_ir->CreateAnd(val, 0xffff'ffff'ffff), type->getPointerTo()));
615+
callee = FunctionCallee(type, m_ir->CreateIntToPtr(val, type->getPointerTo()));
609616

610617
// Load new segment address
611-
seg0 = m_ir->CreateShl(m_ir->CreateLShr(val, 48), 13);
618+
const auto seg_base_ptr = m_ir->CreateIntToPtr(m_ir->CreateAdd(
619+
m_ir->CreatePtrToInt(m_exec, get_type<u64>()), m_ir->getInt64(vm::g_exec_addr_seg_offset)), m_exec->getType());
620+
const auto seg_pos = m_ir->CreateLShr(indirect, 1);
621+
const auto seg_ptr = dyn_cast<GetElementPtrInst>(m_ir->CreateGEP(get_type<u8>(), seg_base_ptr, seg_pos));
622+
const auto seg_val = m_ir->CreateZExt(m_ir->CreateLoad(get_type<u16>(), seg_ptr), get_type<u64>());
623+
seg0 = m_ir->CreateShl(seg_val, 13);
612624
}
613625

614626
m_ir->SetInsertPoint(block);

‎rpcs3/Emu/Memory/vm.cpp‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ namespace vm
4747
u8* const g_sudo_addr = g_base_addr + 0x1'0000'0000;
4848

4949
// Auxiliary virtual memory for executable areas
50-
u8* const g_exec_addr = memory_reserve_4GiB(g_sudo_addr, 0x200000000);
50+
u8* const g_exec_addr = memory_reserve_4GiB(g_sudo_addr, 0x300000000);
5151

5252
// Hooks for memory R/W interception (default: zero offset to some function with only ret instructions)
5353
u8* const g_hook_addr = memory_reserve_4GiB(g_exec_addr, 0x800000000);

‎rpcs3/Emu/Memory/vm.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ namespace vm
3434
extern u8* const g_free_addr;
3535
extern u8 g_reservations[65536 / 128 * 64];
3636

37+
static constexpr u64 g_exec_addr_seg_offset = 0x2'0000'0000ULL;
38+
3739
struct writer_lock;
3840

3941
enum memory_location_t : uint

0 commit comments

Comments
 (0)