diff --git a/Source/Core/Common/Src/ABI.cpp b/Source/Core/Common/Src/ABI.cpp
index 04aafa0bf2..034c2b77e3 100644
--- a/Source/Core/Common/Src/ABI.cpp
+++ b/Source/Core/Common/Src/ABI.cpp
@@ -100,6 +100,7 @@ void ABI_CallFunctionAC(void *func, const Gen::OpArg &arg1, u32 param2)
}
#ifdef _WIN32
+
// Win64 Specific Code
// ====================================
void ABI_PushAllCalleeSavedRegsAndAdjustStack() {
@@ -107,27 +108,54 @@ void ABI_PushAllCalleeSavedRegsAndAdjustStack() {
PUSH(RBX);
PUSH(RSI);
PUSH(RDI);
- //PUSH(RBP);
+ PUSH(RBP);
PUSH(R12);
PUSH(R13);
PUSH(R14);
PUSH(R15);
//TODO: Also preserve XMM0-3?
- SUB(64, R(RSP), Imm8(0x20));
+ SUB(64, R(RSP), Imm8(0x28));
}
void ABI_PopAllCalleeSavedRegsAndAdjustStack() {
- ADD(64, R(RSP), Imm8(0x20));
+ ADD(64, R(RSP), Imm8(0x28));
POP(R15);
POP(R14);
POP(R13);
POP(R12);
- //POP(RBP);
+ POP(RBP);
POP(RDI);
POP(RSI);
POP(RBX);
}
+// Win64 Specific Code
+// ====================================
+void ABI_PushAllCallerSavedRegsAndAdjustStack() {
+ PUSH(RCX);
+ PUSH(RDX);
+ PUSH(RSI);
+ PUSH(RDI);
+ PUSH(R8);
+ PUSH(R9);
+ PUSH(R10);
+ PUSH(R11);
+ //TODO: Also preserve XMM0-15?
+ SUB(64, R(RSP), Imm8(0x28));
+}
+
+void ABI_PopAllCallerSavedRegsAndAdjustStack() {
+ ADD(64, R(RSP), Imm8(0x28));
+ POP(R11);
+ POP(R10);
+ POP(R9);
+ POP(R8);
+ POP(RDI);
+ POP(RSI);
+ POP(RDX);
+ POP(RCX);
+}
+
#else
// Unix64 Specific Code
// ====================================
@@ -151,6 +179,16 @@ void ABI_PopAllCalleeSavedRegsAndAdjustStack() {
POP(RBX);
}
+void ABI_PushAllCallerSavedRegsAndAdjustStack() {
+ INT3();
+ //not yet supported
+}
+
+void ABI_PopAllCallerSavedRegsAndAdjustStack() {
+ INT3();
+ //not yet supported
+}
+
#endif
#endif
diff --git a/Source/Core/Common/Src/ABI.h b/Source/Core/Common/Src/ABI.h
index 632df334ef..feb4431531 100644
--- a/Source/Core/Common/Src/ABI.h
+++ b/Source/Core/Common/Src/ABI.h
@@ -92,8 +92,17 @@ void ABI_CallFunctionAC(void *func, const Gen::OpArg &arg1, u32 param2);
void ABI_CallFunctionR(void *func, Gen::X64Reg reg1);
void ABI_CallFunctionRR(void *func, Gen::X64Reg reg1, Gen::X64Reg reg2);
+// A function that doesn't have any control over what it will do to regs,
+// such as the dispatcher, should be surrounded by these.
void ABI_PushAllCalleeSavedRegsAndAdjustStack();
void ABI_PopAllCalleeSavedRegsAndAdjustStack();
+// A function that doesn't know anything about it's surroundings, should
+// be surrounded by these to establish a safe environment, where it can roam free.
+// An example is a backpatch injected function.
+void ABI_PushAllCallerSavedRegsAndAdjustStack();
+void ABI_PopAllCallerSavedRegsAndAdjustStack();
+
+
#endif // _JIT_ABI_H
diff --git a/Source/Core/Common/Src/x64Analyzer.cpp b/Source/Core/Common/Src/x64Analyzer.cpp
index c1e0b5f2dd..07434757b8 100644
--- a/Source/Core/Common/Src/x64Analyzer.cpp
+++ b/Source/Core/Common/Src/x64Analyzer.cpp
@@ -26,6 +26,9 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc
//Check for regular prefix
info.operandSize = 4;
info.zeroExtend = false;
+ info.signExtend = false;
+ info.hasImmediate = false;
+ info.isMemoryWrite = false;
int addressSize = 8;
u8 modRMbyte = 0;
@@ -33,7 +36,6 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc
bool hasModRM = false;
bool hasSIBbyte = false;
bool hasDisplacement = false;
- info.hasImmediate = false;
int displacementSize = 0;
@@ -136,6 +138,7 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc
if (accessType == 1)
{
+ info.isMemoryWrite = true;
//Write access
switch (codeByte)
{
@@ -179,7 +182,9 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc
}
else
{
- //mov eax,dword ptr [rax] == 8b 00
+ // Memory read
+
+ //mov eax, dword ptr [rax] == 8b 00
switch (codeByte)
{
case 0x0F:
@@ -193,6 +198,14 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc
info.zeroExtend = true;
info.operandSize = 2;
break;
+ case 0xBE: //movsx on byte
+ info.signExtend = true;
+ info.operandSize = 1;
+ break;
+ case 0xBF:
+ info.signExtend = true;
+ info.operandSize = 2;
+ break;
default:
return false;
}
diff --git a/Source/Core/Common/Src/x64Analyzer.h b/Source/Core/Common/Src/x64Analyzer.h
index 3dd00f6c7c..68c52ca932 100644
--- a/Source/Core/Common/Src/x64Analyzer.h
+++ b/Source/Core/Common/Src/x64Analyzer.h
@@ -27,7 +27,9 @@ struct InstructionInfo
int otherReg;
int scaledReg;
bool zeroExtend;
+ bool signExtend;
bool hasImmediate;
+ bool isMemoryWrite;
u64 immediate;
s32 displacement;
};
diff --git a/Source/Core/Core/Core.vcproj b/Source/Core/Core/Core.vcproj
index 582d1e93d1..ef32602182 100644
--- a/Source/Core/Core/Core.vcproj
+++ b/Source/Core/Core/Core.vcproj
@@ -879,6 +879,10 @@
RelativePath=".\Src\PowerPC\Jit64\Jit_LoadStore.cpp"
>
+
+
diff --git a/Source/Core/Core/Src/Boot/Boot.cpp b/Source/Core/Core/Src/Boot/Boot.cpp
index c17d76fe66..507b31da8d 100644
--- a/Source/Core/Core/Src/Boot/Boot.cpp
+++ b/Source/Core/Core/Src/Boot/Boot.cpp
@@ -185,10 +185,7 @@ void CBoot::EmulatedBIOS(bool _bDebug)
// return
PC = PowerPC::ppcState.gpr[3];
- //
// --- preinit some stuff from bios ---
- //
-
// Bus Clock Speed
Memory::Write_U32(0x09a7ec80, 0x800000F8);
diff --git a/Source/Core/Core/Src/Core.cpp b/Source/Core/Core/Src/Core.cpp
index 716237a17d..01cf7f3e35 100644
--- a/Source/Core/Core/Src/Core.cpp
+++ b/Source/Core/Core/Src/Core.cpp
@@ -186,9 +186,16 @@ THREAD_RETURN CpuThread(void *pArg)
if (_CoreParameter.bLockThreads)
Common::Thread::SetCurrentThreadAffinity(1); //Force to first core
- // Let's run under memory watch
- EMM::InstallExceptionHandler();
- // StartConsoleThread();
+ if (_CoreParameter.bUseFastMem)
+ {
+#ifdef _M_X64
+ // Let's run under memory watch
+ EMM::InstallExceptionHandler();
+#else
+ PanicAlert("32-bit platforms do not support fastmem yet. Report this bug.");
+#endif
+ }
+
CCPU::Run();
if (_CoreParameter.bRunCompareServer || _CoreParameter.bRunCompareClient)
diff --git a/Source/Core/Core/Src/HW/Memmap.cpp b/Source/Core/Core/Src/HW/Memmap.cpp
index 31d2d92d30..3d67e37da9 100644
--- a/Source/Core/Core/Src/HW/Memmap.cpp
+++ b/Source/Core/Core/Src/HW/Memmap.cpp
@@ -144,7 +144,7 @@ template void HWCALL HW_Write_Memory(T _Data, const u32 _Addres
void InitHWMemFuncs()
{
- for (int i=0; i;
hwWrite16[i] = HW_Default_Write;
@@ -156,7 +156,7 @@ void InitHWMemFuncs()
hwRead64 [i] = HW_Default_Read;
}
- for (int i=0; i
-
#include
#include "Common.h"
@@ -32,179 +31,6 @@
namespace EMM
{
-/* DESIGN
-
-THIS IS NOT THE CURRENT STATE OF THIS FILE - IT'S UNFINISHED
-
-We grab 4GB of virtual address space, and locate memories in there. The memories are either
-VirtualAlloc or mapped swapfile.
-
-I/O areas are mapped into the virtual memspace, and VirtualProtected where necessary.
-
-Every chunk is mapped twice into memory, once into the virtual memspace, and once elsewhere.
-This second mapping is used when a "read+writable" pointer is requested for a region. This
-would generally be for internal use by IO functions, and for actually performing the writes
-and reads after detecting them.
-
-There is individual read and write protection for each chunk of memory.
-
-Every region has a default read-write handler. If an exception is caught, this is executed.
-
-The default read-write handlers use the "writable" pointers.
-
-There should be a method to mark a region for "write notification". Dynarecs can use this
-to flush their code caches if a region is written to.
-
-At this moment, there can only be one wrapped memspace at a time.
-*/
-
-DWORD_PTR memspaceBottom = 0;
-DWORD_PTR memspaceTop = 0;
-
-enum MSFlags
-{
- MEMSPACE_MIRROR_FIRST_PART = 1,
- MEMSPACE_MIRROR_OF_PREVIOUS = 2,
- MEMSPACE_MAPPED_HARDWARE = 4,
-};
-
-struct MemSpaceEntry
-{
- u64 emulatedBase;
- u64 emulatedSize;
- u32 flags;
-};
-
-#define MEGABYTE 1024*1024
-
-const MemSpaceEntry GCMemSpace[] =
-{
- {0x80000000, 24*MEGABYTE, MEMSPACE_MIRROR_FIRST_PART},
- {0xC0000000, 24*MEGABYTE, MEMSPACE_MIRROR_OF_PREVIOUS},
- {0xCC000000, 0x10000, MEMSPACE_MAPPED_HARDWARE},
- {0xE0000000, 0x4000, 0}, //cache
-};
-
-struct Watch
-{
- int ID;
- EAddr startAddr;
- EAddr endAddr;
- WR watchFor;
- WatchCallback callback;
- WatchType type;
- u64 userData;
-};
-
-std::vector watches;
-
-void UpdateProtection(EAddr startAddr, EAddr endAddr)
-{
-
-}
-
-int AddWatchRegion(EAddr startAddr, EAddr endAddr, WR watchFor, WatchType type, WatchCallback callback, u64 userData)
-{
- static int watchIDGen = 0;
-
- Watch watch;
- watch.ID = watchIDGen++;
- watch.startAddr = startAddr;
- watch.endAddr = endAddr;
- watch.watchFor = watchFor;
- watch.callback = callback;
- watch.userData = userData;
- watch.type = type;
- watches.push_back(watch);
- UpdateProtection(startAddr, endAddr);
-
- return watch.ID;
-}
-
-void Notify(EAddr address, WR action)
-{
- for (std::vector::iterator iter = watches.begin(); iter != watches.end(); ++iter)
- {
- if (action & iter->type)
- {
- if (address >= iter->startAddr && address < iter->endAddr)
- {
- //Alright!
- iter->callback(address, Access32 /*TODO*/, action, iter->ID);
- }
- }
- }
-}
-
-
-class MemSpace
-{
- MemSpaceEntry *entries;
-
- u64 emulatedBottom;
- u64 emulatedTop;
- u64 emulatedSize;
-
- void *virtualBase;
-
-public:
-
- void Init(const MemSpaceEntry *e, int count)
- {
- /*
- //first pass: figure out minimum address, and total amount of allocated memory
- emulatedBase = 0xFFFFFFFFFFFFFFFFL;
- emulatedTop = 0;
-
- u64 mappedTotal = 0;
- for (int i=0; i emulatedTop)
- emulatedTop = e[i].emulatedBase+e[i].emulatedSize;
- if (e[i].flags & MEMSPACE_MIRROR_FIRST_PART)
- {
- mappedTotal += e[i].emulatedSize;
- }
- }
- emulatedSize = emulatedTop - emulatedBase;
-
- // The above stuff is not used atm - we just grab 4G
-
- //second pass: grab 4G of virtual address space
- virtualBase = VirtualAlloc(0, 0x100000000L, MEM_RESERVE, PAGE_READWRITE);
-
- //also grab a bunch of virtual memory while we're at it
-
-
- //Release the 4G space!
- //Let's hope no weirdo thread klomps in here and grabs it
- VirtualFree(base, 0, MEM_RELEASE);
-
- for (int i=0; i %s\n", strings[i]);
+ free(strings);
+}
+
+void sigsegv_handler(int signal, int siginfo_t *info, void *raw_context)
+{
+ if (signal != SIGSEGV)
+ {
+ // We are not interested in other signals - handle it as usual.
+ return;
+ }
+ ucontext_t *context = (ucontext_t)raw_context;
+ int si_code = info->si_code;
+ if (si_code != SEGV_MAPERR)
+ {
+ // Huh? Return.
+ return;
+ }
+ mcontext_t *ctx = &context->uc_mcontext;
+ void *fault_memory_ptr = (void *)info->si_addr;
+ void *fault_instruction_ptr = (void *)ctx->mc_rip;
+
+ if (!Jit64::IsInJitCode(fault_instruction_ptr)) {
+ // Let's not prevent debugging.
+ return;
+ }
+
+ u64 memspaceBottom = (u64)Memory::base;
+ if (badAddress < memspaceBottom) {
+ PanicAlert("Exception handler - access below memory space. %08x%08x",
+ badAddress >> 32, badAddress);
+ }
+ u32 emAddress = (u32)(badAddress - memspaceBottom);
+
+ // Backpatch time.
+ Jit64::BackPatch(fault_instruction_ptr, accessType, emAddress);
+}
+
+#endif
+
void InstallExceptionHandler()
{
-/*
+#ifdef _M_IX86
+ PanicAlert("InstallExceptionHandler called, but this platform does not yet support it.");
+ return;
+#endif
+
+#if 0
+ sighandler_t old_signal_handler = signal(SIGSEGV , sigsegv_handler);
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = sigsegv_handler;
+ sa.sa_flags = SA_SIGINFO;
+ sigemptyset(&sa.sa_mask);
+ sigaction(SIGSEGV, &sa, NULL);
+#endif
+
+ /*
* signal(xyz);
*/
}
diff --git a/Source/Core/Core/Src/MemTools.h b/Source/Core/Core/Src/MemTools.h
index 903e9c3aa7..c3d847bbcf 100644
--- a/Source/Core/Core/Src/MemTools.h
+++ b/Source/Core/Core/Src/MemTools.h
@@ -69,4 +69,3 @@ void WriteHandler32(EAddr address, u32 value);
void WriteHandler64(EAddr address, u64 value);
#endif
-
diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit.h b/Source/Core/Core/Src/PowerPC/Jit64/Jit.h
index 01cfb6fe2c..ed5f7bc49a 100644
--- a/Source/Core/Core/Src/PowerPC/Jit64/Jit.h
+++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit.h
@@ -24,6 +24,7 @@
#include "../PPCAnalyst.h"
#include "JitCache.h"
+#include "x64Emitter.h"
namespace Jit64
{
@@ -85,6 +86,7 @@ namespace Jit64
void FlushRegCaches();
+ void SafeLoadRegToEAX(Gen::X64Reg reg, int accessSize, s32 offset);
void addx(UGeckoInstruction inst);
void orx(UGeckoInstruction inst);
diff --git a/Source/Core/Core/Src/PowerPC/Jit64/JitAsm.cpp b/Source/Core/Core/Src/PowerPC/Jit64/JitAsm.cpp
index 204188e658..166864f3ee 100644
--- a/Source/Core/Core/Src/PowerPC/Jit64/JitAsm.cpp
+++ b/Source/Core/Core/Src/PowerPC/Jit64/JitAsm.cpp
@@ -14,6 +14,8 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
+
+#include "ABI.h"
#include "x64Emitter.h"
#include "../../HW/Memmap.h"
diff --git a/Source/Core/Core/Src/PowerPC/Jit64/JitBackpatch.cpp b/Source/Core/Core/Src/PowerPC/Jit64/JitBackpatch.cpp
index c6b5b76b56..48c3ff56bb 100644
--- a/Source/Core/Core/Src/PowerPC/Jit64/JitBackpatch.cpp
+++ b/Source/Core/Core/Src/PowerPC/Jit64/JitBackpatch.cpp
@@ -1,3 +1,20 @@
+// Copyright (C) 2003-2008 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
#include
#include "Common.h"
@@ -36,6 +53,10 @@ void BackPatchError(const std::string &text, u8 *codePtr, u32 emAddress) {
return;
}
+// This generates some fairly heavy trampolines, but:
+// 1) It's really necessary. We don't know anything about the context.
+// 2) It doesn't really hurt. Only instructions that access I/O will get these, and there won't be
+// that many of them in a typical program/game.
void BackPatch(u8 *codePtr, int accessType, u32 emAddress)
{
if (!IsInJitCode(codePtr))
@@ -48,6 +69,10 @@ void BackPatch(u8 *codePtr, int accessType, u32 emAddress)
if (!DisassembleMov(codePtr, info, accessType)) {
BackPatchError("BackPatch - failed to disassemble MOV instruction", codePtr, emAddress);
}
+ if (info.isMemoryWrite) {
+ BackPatchError("BackPatch - determined that MOV is write, not yet supported and should have been caught before",
+ codePtr, emAddress);
+ }
if (info.operandSize != 4) {
BackPatchError(StringFromFormat("BackPatch - no support for operand size %i", info.operandSize), codePtr, emAddress);
}
@@ -70,19 +95,10 @@ void BackPatch(u8 *codePtr, int accessType, u32 emAddress)
u8 *trampoline = trampolineCodePtr;
SetCodePtr(trampolineCodePtr);
// * Save all volatile regs
- PUSH(RCX);
- PUSH(RDX);
- PUSH(RSI);
- PUSH(RDI);
- PUSH(R8);
- PUSH(R9);
- PUSH(R10);
- PUSH(R11);
- //TODO: Also preserve XMM0-3?
- SUB(64, R(RSP), Imm8(0x20));
+ ABI_PushAllCallerSavedRegsAndAdjustStack();
// * Set up stack frame.
// * Call ReadMemory32
- //LEA(32, ECX, MDisp((X64Reg)addrReg, info.displacement));
+ //LEA(32, ABI_PARAM1, MDisp((X64Reg)addrReg, info.displacement));
MOV(32, R(ABI_PARAM1), R((X64Reg)addrReg));
if (info.displacement) {
ADD(32, R(ABI_PARAM1), Imm32(info.displacement));
@@ -91,7 +107,8 @@ void BackPatch(u8 *codePtr, int accessType, u32 emAddress)
//case 1:
// CALL((void *)&Memory::Read_U8);
// break;
- case 4:
+ case 4:
+ // THIS FUNCTION CANNOT TOUCH FLOATING POINT REGISTERS.
CALL((void *)&Memory::Read_U32);
break;
default:
@@ -99,15 +116,7 @@ void BackPatch(u8 *codePtr, int accessType, u32 emAddress)
break;
}
// * Tear down stack frame.
- ADD(64, R(RSP), Imm8(0x20));
- POP(R11);
- POP(R10);
- POP(R9);
- POP(R8);
- POP(RDI);
- POP(RSI);
- POP(RDX);
- POP(RCX);
+ ABI_PopAllCallerSavedRegsAndAdjustStack();
MOV(32, R(dataReg), R(EAX));
RET();
trampolineCodePtr = GetWritableCodePtr();
diff --git a/Source/Core/Core/Src/PowerPC/Jit64/JitBackpatch.h b/Source/Core/Core/Src/PowerPC/Jit64/JitBackpatch.h
index 1cf07196ab..e64439983c 100644
--- a/Source/Core/Core/Src/PowerPC/Jit64/JitBackpatch.h
+++ b/Source/Core/Core/Src/PowerPC/Jit64/JitBackpatch.h
@@ -1,3 +1,20 @@
+// Copyright (C) 2003-2008 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
#ifndef _JITBACKPATCH_H
#define _JITBACKPATCH_H
diff --git a/Source/Core/Core/Src/PowerPC/Jit64/JitCache.cpp b/Source/Core/Core/Src/PowerPC/Jit64/JitCache.cpp
index 709ce123d3..b058a79316 100644
--- a/Source/Core/Core/Src/PowerPC/Jit64/JitCache.cpp
+++ b/Source/Core/Core/Src/PowerPC/Jit64/JitCache.cpp
@@ -17,6 +17,7 @@
#include