static bool LoadRom(const std::string& fname, int size_in_words, u16 *rom) { File::IOFile pFile(fname, "rb"); const size_t size_in_bytes = size_in_words * sizeof(u16); if (pFile) { pFile.ReadArray(rom, size_in_words); pFile.Close(); // Byteswap the rom. for (int i = 0; i < size_in_words; i++) rom[i] = Common::swap16(rom[i]); // Always keep ROMs write protected. WriteProtectMemory(rom, size_in_bytes, false); return true; } PanicAlertT( "Failed to load DSP ROM:\t%s\n" "\n" "This file is required to use DSP LLE.\n" "It is not included with Dolphin as it contains copyrighted data.\n" "Use DSPSpy to dump the file from your physical console.\n" "\n" "You may use the DSP HLE engine which does not require ROM dumps.\n" "(Choose it from the \"Audio\" tab of the configuration dialog.)", fname.c_str()); return false; }
TEST(PageFault, PageFault) { EMM::InstallExceptionHandler(); void* data = AllocateMemoryPages(PAGE_GRAN); EXPECT_NE(data, nullptr); WriteProtectMemory(data, PAGE_GRAN, false); PageFaultFakeJit pfjit; jit = &pfjit; pfjit.m_data = data; auto start = std::chrono::high_resolution_clock::now(); *(volatile int*)data = 5; auto end = std::chrono::high_resolution_clock::now(); #define AS_NS(diff) \ ((unsigned long long)std::chrono::duration_cast<std::chrono::nanoseconds>(diff).count()) EMM::UninstallExceptionHandler(); jit = nullptr; printf("page fault timing:\n"); printf("start->HandleFault %llu ns\n", AS_NS(pfjit.m_pre_unprotect_time - start)); printf("UnWriteProtectMemory %llu ns\n", AS_NS(pfjit.m_post_unprotect_time - pfjit.m_pre_unprotect_time)); printf("HandleFault->end %llu ns\n", AS_NS(end - pfjit.m_post_unprotect_time)); printf("total %llu ns\n", AS_NS(end - start)); }
void DSPLLE::DoState(PointerWrap &p) { bool isHLE = false; p.Do(isHLE); if (isHLE != false && p.GetMode() == PointerWrap::MODE_READ) { Core::DisplayMessage("State is incompatible with current DSP engine. Aborting load state.", 3000); p.SetMode(PointerWrap::MODE_VERIFY); return; } p.Do(g_dsp.r); p.Do(g_dsp.pc); #if PROFILE p.Do(g_dsp.err_pc); #endif p.Do(g_dsp.cr); p.Do(g_dsp.reg_stack_ptr); p.Do(g_dsp.exceptions); p.Do(g_dsp.external_interrupt_waiting); for (int i = 0; i < 4; i++) { p.Do(g_dsp.reg_stack[i]); } p.Do(g_dsp.step_counter); p.Do(g_dsp.ifx_regs); p.Do(g_dsp.mbox[0]); p.Do(g_dsp.mbox[1]); UnWriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false); p.DoArray(g_dsp.iram, DSP_IRAM_SIZE); WriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false); if (p.GetMode() == PointerWrap::MODE_READ) DSPHost::CodeLoaded((const u8*)g_dsp.iram, DSP_IRAM_BYTE_SIZE); p.DoArray(g_dsp.dram, DSP_DRAM_SIZE); p.Do(cyclesLeft); p.Do(init_hax); p.Do(m_cycle_count); bool prevInitMixer = m_InitMixer; p.Do(m_InitMixer); if (prevInitMixer != m_InitMixer && p.GetMode() == PointerWrap::MODE_READ) { if (m_InitMixer) { InitMixer(); AudioCommon::PauseAndLock(true); } else { AudioCommon::PauseAndLock(false); soundStream->Stop(); delete soundStream; soundStream = nullptr; } } }
bool DSPCore_Init(const DSPInitOptions& opts) { g_dsp.step_counter = 0; g_cycles_left = 0; g_init_hax = false; g_dsp.irom = (u16*)AllocateMemoryPages(DSP_IROM_BYTE_SIZE); g_dsp.iram = (u16*)AllocateMemoryPages(DSP_IRAM_BYTE_SIZE); g_dsp.dram = (u16*)AllocateMemoryPages(DSP_DRAM_BYTE_SIZE); g_dsp.coef = (u16*)AllocateMemoryPages(DSP_COEF_BYTE_SIZE); memcpy(g_dsp.irom, opts.irom_contents.data(), DSP_IROM_BYTE_SIZE); memcpy(g_dsp.coef, opts.coef_contents.data(), DSP_COEF_BYTE_SIZE); // Try to load real ROM contents. if (!VerifyRoms()) { DSPCore_FreeMemoryPages(); return false; } memset(&g_dsp.r, 0, sizeof(g_dsp.r)); std::fill(std::begin(g_dsp.reg_stack_ptr), std::end(g_dsp.reg_stack_ptr), 0); for (size_t i = 0; i < ArraySize(g_dsp.reg_stack); i++) std::fill(std::begin(g_dsp.reg_stack[i]), std::end(g_dsp.reg_stack[i]), 0); // Fill IRAM with HALT opcodes. std::fill(g_dsp.iram, g_dsp.iram + DSP_IRAM_SIZE, 0x0021); // Just zero out DRAM. std::fill(g_dsp.dram, g_dsp.dram + DSP_DRAM_SIZE, 0); // Copied from a real console after the custom UCode has been loaded. // These are the indexing wrapping registers. std::fill(std::begin(g_dsp.r.wr), std::end(g_dsp.r.wr), 0xffff); g_dsp.r.sr |= SR_INT_ENABLE; g_dsp.r.sr |= SR_EXT_INT_ENABLE; g_dsp.cr = 0x804; gdsp_ifx_init(); // Mostly keep IRAM write protected. We unprotect only when DMA-ing // in new ucodes. WriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false); // Initialize JIT, if necessary if (opts.core_type == DSPInitOptions::CORE_JIT) g_dsp_jit = std::make_unique<DSPEmitter>(); g_dsp_cap.reset(opts.capture_logger); core_state = DSPCORE_RUNNING; return true; }
PVOID ProbeInvokeCreateProcessAddress() { PVOID Shell32, Shell32CreateProcessW, CreateProcessW; PLDR_MODULE Shell32Module, MainModule; SHELLEXECUTEINFOW ExecuteInfo; PIMAGE_NT_HEADERS NtHeaders; Shell32 = Ldr::LoadDll(L"Shell32.dll"); Shell32CreateProcessW = PtrAdd(Shell32, IATLookupRoutineRVAByHashNoFix(Shell32, KERNEL32_CreateProcessW)); MainModule = FindLdrModuleByHandle(nullptr); RtlDuplicateUnicodeString(RTL_DUPSTR_ADD_NULL, &MainModule->FullDllName, &ProbeApplicationName); RtlInitUnicodeString(&ProbeCommandLine, L"ML_PROBE_APPLICATION_COMMAMD_LINE"); ZeroMemory(&ExecuteInfo, sizeof(ExecuteInfo)); ExecuteInfo.cbSize = sizeof(ExecuteInfo); ExecuteInfo.fMask = SEE_MASK_NOASYNC | SEE_MASK_FLAG_NO_UI; ExecuteInfo.lpVerb = L"open"; ExecuteInfo.lpFile = ProbeApplicationName.Buffer; ExecuteInfo.lpParameters = ProbeCommandLine.Buffer; ExecuteInfo.lpDirectory = ProbeApplicationName.Buffer; ExecuteInfo.nShow = SW_SHOW; *(PVOID *)&Shell32CreateProcessWIAT = Shell32CreateProcessW; *(PVOID *)&Shell32CreateProcessWPtr = *(PVOID *)Shell32CreateProcessWIAT; CreateProcessW = ProbeInvokeCreateProcessW; WriteProtectMemory(CurrentProcess, Shell32CreateProcessW, &CreateProcessW, sizeof(CreateProcessW)); ShellExecuteExW(&ExecuteInfo); WriteProtectMemory(CurrentProcess, Shell32CreateProcessW, &Shell32CreateProcessWPtr, sizeof(Shell32CreateProcessWPtr)); RtlFreeUnicodeString(&ProbeApplicationName); NtHeaders = RtlImageNtHeader(Shell32); if (InvokeReturnAddress < Shell32 || InvokeReturnAddress > PtrAdd(Shell32, NtHeaders->OptionalHeader.SizeOfImage)) return nullptr; return InvokeReturnAddress; }
static const u8* gdsp_idma_in(u16 dsp_addr, u32 addr, u32 size) { UnWriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false); u8* dst = ((u8*)g_dsp.iram); for (u32 i = 0; i < size; i += 2) { *(u16*)&dst[dsp_addr + i] = Common::swap16(*(const u16*)&g_dsp.cpu_ram[(addr + i) & 0x0fffffff]); } WriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false); DSPHost::CodeLoaded((const u8*)g_dsp.iram + dsp_addr, size); NOTICE_LOG(DSPLLE, "*** Copy new UCode from 0x%08x to 0x%04x (crc: %8x)", addr, dsp_addr, g_dsp.iram_crc); return dst + dsp_addr; }
static void gdsp_idma_in(u16 dsp_addr, u32 addr, u32 size) { UnWriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false); u8* dst = ((u8*)g_dsp.iram); for (u32 i = 0; i < size; i += 2) { *(u16*)&dst[dsp_addr + i] = Common::swap16(*(const u16*)&g_dsp.cpu_ram[(addr + i) & 0x0fffffff]); } WriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false); g_dsp.iram_crc = DSPHost_CodeLoaded(g_dsp.cpu_ram + (addr & 0x0fffffff), size); NOTICE_LOG(DSPLLE, "*** Copy new UCode from 0x%08x to 0x%04x (crc: %8x)", addr, dsp_addr, g_dsp.iram_crc); if (dspjit) dspjit->ClearIRAM(); DSPAnalyzer::Analyze(); }
void DSPLLE::DoState(PointerWrap &p) { bool is_hle = false; p.Do(is_hle); if (is_hle && p.GetMode() == PointerWrap::MODE_READ) { Core::DisplayMessage("State is incompatible with current DSP engine. Aborting load state.", 3000); p.SetMode(PointerWrap::MODE_VERIFY); return; } p.Do(g_dsp.r); p.Do(g_dsp.pc); #if PROFILE p.Do(g_dsp.err_pc); #endif p.Do(g_dsp.cr); p.Do(g_dsp.reg_stack_ptr); p.Do(g_dsp.exceptions); p.Do(g_dsp.external_interrupt_waiting); for (int i = 0; i < 4; i++) { p.Do(g_dsp.reg_stack[i]); } p.Do(g_dsp.step_counter); p.DoArray(g_dsp.ifx_regs); p.Do(g_dsp.mbox[0]); p.Do(g_dsp.mbox[1]); UnWriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false); p.DoArray(g_dsp.iram, DSP_IRAM_SIZE); WriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false); if (p.GetMode() == PointerWrap::MODE_READ) DSPHost::CodeLoaded((const u8*)g_dsp.iram, DSP_IRAM_BYTE_SIZE); p.DoArray(g_dsp.dram, DSP_DRAM_SIZE); p.Do(g_cycles_left); p.Do(g_init_hax); p.Do(m_cycle_count); }
bool DSPCore_Init(const std::string& irom_filename, const std::string& coef_filename, bool bUsingJIT) { g_dsp.step_counter = 0; cyclesLeft = 0; init_hax = false; dspjit = nullptr; g_dsp.irom = (u16*)AllocateMemoryPages(DSP_IROM_BYTE_SIZE); g_dsp.iram = (u16*)AllocateMemoryPages(DSP_IRAM_BYTE_SIZE); g_dsp.dram = (u16*)AllocateMemoryPages(DSP_DRAM_BYTE_SIZE); g_dsp.coef = (u16*)AllocateMemoryPages(DSP_COEF_BYTE_SIZE); // Fill roms with zeros. memset(g_dsp.irom, 0, DSP_IROM_BYTE_SIZE); memset(g_dsp.coef, 0, DSP_COEF_BYTE_SIZE); // Try to load real ROM contents. if (!LoadRom(irom_filename, DSP_IROM_SIZE, g_dsp.irom) || !LoadRom(coef_filename, DSP_COEF_SIZE, g_dsp.coef) || !VerifyRoms(irom_filename, coef_filename)) { DSPCore_FreeMemoryPages(); return false; } memset(&g_dsp.r,0,sizeof(g_dsp.r)); for (int i = 0; i < 4; i++) { g_dsp.reg_stack_ptr[i] = 0; for (int j = 0; j < DSP_STACK_DEPTH; j++) { g_dsp.reg_stack[i][j] = 0; } } // Fill IRAM with HALT opcodes. for (int i = 0; i < DSP_IRAM_SIZE; i++) { g_dsp.iram[i] = 0x0021; // HALT opcode } // Just zero out DRAM. for (int i = 0; i < DSP_DRAM_SIZE; i++) { g_dsp.dram[i] = 0; } // Copied from a real console after the custom UCode has been loaded. // These are the indexing wrapping registers. g_dsp.r.wr[0] = 0xffff; g_dsp.r.wr[1] = 0xffff; g_dsp.r.wr[2] = 0xffff; g_dsp.r.wr[3] = 0xffff; g_dsp.r.sr |= SR_INT_ENABLE; g_dsp.r.sr |= SR_EXT_INT_ENABLE; g_dsp.cr = 0x804; gdsp_ifx_init(); // Mostly keep IRAM write protected. We unprotect only when DMA-ing // in new ucodes. WriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false); // Initialize JIT, if necessary if (bUsingJIT) dspjit = new DSPEmitter(); core_state = DSPCORE_RUNNING; return true; }
BOOL HookCallCreateProcessFast(PVOID InvokeReturnAddress) { PBYTE InvokeBuffer; PVOID *JumpAddressBegin, *JumpAddressEnd, HookRoutine; PIMAGE_NT_HEADERS NtHeaders; PLDR_MODULE Shell32; InvokeBuffer = (PBYTE)InvokeReturnAddress; LOOP_ONCE { if (*(PUSHORT)&InvokeBuffer[-6] != 0x15FF) continue; #if ML_X86 if (*(PULONG)&InvokeBuffer[-4] != (ULONG)Shell32CreateProcessWIAT) break; #elif ML_AMD64 if ((PVOID)PtrAdd(InvokeBuffer, *(PULONG)&InvokeBuffer[-4]) != Shell32CreateProcessWIAT) break; #endif // arch Shell32 = FindLdrModuleByName(&WCS2US(L"SHELL32.dll")); NtHeaders = RtlImageNtHeader(Shell32->DllBase); if (NtHeaders == nullptr) break; JumpAddressEnd = (PVOID *)PtrAdd(Shell32->DllBase, ROUND_UP(NtHeaders->OptionalHeader.SizeOfHeaders, NtHeaders->OptionalHeader.SectionAlignment)); JumpAddressBegin = (PVOID *)(IMAGE_FIRST_SECTION(NtHeaders) + NtHeaders->FileHeader.NumberOfSections); JumpAddressBegin = (PVOID *)ROUND_UP((ULONG_PTR)JumpAddressBegin, 16); while (JumpAddressBegin < JumpAddressEnd) { #if ML_X86 if ( JumpAddressBegin[0] == nullptr && JumpAddressBegin[1] == nullptr && JumpAddressBegin[2] == nullptr && JumpAddressBegin[3] == nullptr ) { break; } JumpAddressBegin += 4; #else if ( JumpAddressBegin[0] == nullptr && JumpAddressBegin[1] == nullptr ) { break; } JumpAddressBegin += 2; #endif } if (JumpAddressBegin >= JumpAddressEnd) break; HookRoutine = SpeedUpCreateProcessW; WriteProtectMemory(CurrentProcess, JumpAddressBegin, &HookRoutine, sizeof(HookRoutine)); #if ML_X86 WriteProtectMemory(CurrentProcess, &InvokeBuffer[-4], &JumpAddressBegin, sizeof(JumpAddressBegin)); #elif ML_AMD64 LONG64 RelateOffset; RelateOffset = (TYPE_OF(RelateOffset))PtrSub(JumpAddressBegin, InvokeBuffer); WriteProtectMemory(CurrentProcess, &InvokeBuffer[-4], &RelateOffset, sizeof(LONG)); #endif return TRUE; } return FALSE; }