Skip to content

Commit 5abcd50

Browse files
committed
[cpu] Upstream changes made from xenia-project#1339 and xenia-project#2228 back to canary builds. This fixes various emulation crashes caused from different calling conventions on System-V ABI platforms compared to the Windows standard.
1 parent 55bbb28 commit 5abcd50

File tree

2 files changed

+146
-5
lines changed

2 files changed

+146
-5
lines changed

src/xenia/base/memory_posix.cc

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,11 @@ void* AllocFixed(void* base_address, size_t length,
9292
flags = MAP_PRIVATE | MAP_ANONYMOUS;
9393
}
9494
void* result = mmap(base_address, length, prot,
95-
MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
96-
if (result == MAP_FAILED) {
97-
return nullptr;
98-
} else {
95+
flags, -1, 0);
96+
if (result != MAP_FAILED) {
9997
return result;
10098
}
99+
return nullptr;
101100
}
102101

103102
bool DeallocFixed(void* base_address, size_t length,

src/xenia/cpu/backend/x64/x64_backend.cc

Lines changed: 143 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
#include "xenia/cpu/backend/x64/x64_backend.h"
1111

12-
#include <stddef.h>
12+
#include <cstddef>
1313
#include <algorithm>
1414
#include "third_party/capstone/include/capstone/capstone.h"
1515
#include "third_party/capstone/include/capstone/x86.h"
@@ -629,6 +629,7 @@ void* X64HelperEmitter::EmitCurrentForOffsets(const _code_offsets& code_offsets,
629629
return fn;
630630
}
631631
HostToGuestThunk X64HelperEmitter::EmitHostToGuestThunk() {
632+
#ifdef XE_PLATFORM_WINDOWS
632633
// rcx = target
633634
// rdx = arg0 (context)
634635
// r8 = arg1 (guest return address)
@@ -666,6 +667,52 @@ HostToGuestThunk X64HelperEmitter::EmitHostToGuestThunk() {
666667
mov(rdx, qword[rsp + 8 * 2]);
667668
mov(r8, qword[rsp + 8 * 3]);
668669
ret();
670+
#elif XE_PLATFORM_LINUX || XE_PLATFORM_MAC
671+
// System-V ABI args:
672+
// rdi = target
673+
// rsi = arg0 (context)
674+
// rdx = arg1 (guest return address)
675+
676+
struct _code_offsets {
677+
size_t prolog;
678+
size_t prolog_stack_alloc;
679+
size_t body;
680+
size_t epilog;
681+
size_t tail;
682+
} code_offsets = {};
683+
684+
const size_t stack_size = StackLayout::THUNK_STACK_SIZE;
685+
686+
code_offsets.prolog = getSize();
687+
// rsp + 0 = return address
688+
mov(qword[rsp + 8 * 3], rdx);
689+
mov(qword[rsp + 8 * 2], rsi);
690+
mov(qword[rsp + 8 * 1], rdi);
691+
sub(rsp, stack_size);
692+
693+
code_offsets.prolog_stack_alloc = getSize();
694+
code_offsets.body = getSize();
695+
696+
// Save nonvolatile registers.
697+
EmitSaveNonvolatileRegs();
698+
699+
mov(rax, rdi);
700+
// mov(rsi, rsi); // context
701+
mov(rcx, rdx); // return address
702+
call(rax);
703+
704+
EmitLoadNonvolatileRegs();
705+
706+
code_offsets.epilog = getSize();
707+
708+
add(rsp, stack_size);
709+
mov(rdi, qword[rsp + 8 * 1]);
710+
mov(rsi, qword[rsp + 8 * 2]);
711+
mov(rdx, qword[rsp + 8 * 3]);
712+
ret();
713+
#else
714+
assert_always("Unknown platform ABI in host to guest thunk!");
715+
#endif
669716

670717
code_offsets.tail = getSize();
671718

@@ -685,6 +732,7 @@ HostToGuestThunk X64HelperEmitter::EmitHostToGuestThunk() {
685732
}
686733

687734
GuestToHostThunk X64HelperEmitter::EmitGuestToHostThunk() {
735+
#if XE_PLATFORM_WIN32
688736
// rcx = target function
689737
// rdx = arg0
690738
// r8 = arg1
@@ -716,6 +764,57 @@ GuestToHostThunk X64HelperEmitter::EmitGuestToHostThunk() {
716764

717765
add(rsp, stack_size);
718766
ret();
767+
#elif XE_PLATFORM_LINUX || XE_PLATFORM_MAC
768+
// This function is being called using the Microsoft ABI from CallNative
769+
// rcx = target function
770+
// rdx = arg0
771+
// r8 = arg1
772+
// r9 = arg2
773+
774+
// Must be translated to System-V ABI:
775+
// rdi = target function
776+
// rsi = arg0
777+
// rdx = arg1
778+
// rcx = arg2
779+
// r8, r9 - unused argument registers
780+
781+
struct _code_offsets {
782+
size_t prolog;
783+
size_t prolog_stack_alloc;
784+
size_t body;
785+
size_t epilog;
786+
size_t tail;
787+
} code_offsets = {};
788+
789+
const size_t stack_size = StackLayout::THUNK_STACK_SIZE;
790+
791+
code_offsets.prolog = getSize();
792+
793+
// rsp + 0 = return address
794+
sub(rsp, stack_size);
795+
796+
code_offsets.prolog_stack_alloc = getSize();
797+
code_offsets.body = getSize();
798+
799+
// Save off volatile registers.
800+
EmitSaveVolatileRegs();
801+
802+
mov(rax, rcx); // function
803+
mov(rdi, GetContextReg()); // context
804+
mov(rsi, rdx); // arg0
805+
mov(rdx, r8); // arg1
806+
mov(rcx, r9); // arg2
807+
call(rax);
808+
809+
EmitLoadVolatileRegs();
810+
811+
code_offsets.epilog = getSize();
812+
813+
add(rsp, stack_size);
814+
ret();
815+
#else
816+
assert_always("Unknown platform ABI in guest to host thunk!")
817+
#endif
719818

720819
code_offsets.tail = getSize();
721820

@@ -738,6 +837,7 @@ GuestToHostThunk X64HelperEmitter::EmitGuestToHostThunk() {
738837
uint64_t ResolveFunction(void* raw_context, uint64_t target_address);
739838

740839
ResolveFunctionThunk X64HelperEmitter::EmitResolveFunctionThunk() {
840+
#if XE_PLATFORM_WIN32
741841
// ebx = target PPC address
742842
// rcx = context
743843

@@ -767,6 +867,48 @@ ResolveFunctionThunk X64HelperEmitter::EmitResolveFunctionThunk() {
767867

768868
add(rsp, stack_size);
769869
jmp(rax);
870+
#elif XE_PLATFORM_LINUX || XE_PLATFORM_MAC
871+
// Function is called with the following params:
872+
// ebx = target PPC address
873+
// rsi = context
874+
875+
// System-V ABI args:
876+
// rdi = context
877+
// rsi = target PPC address
878+
879+
struct _code_offsets {
880+
size_t prolog;
881+
size_t prolog_stack_alloc;
882+
size_t body;
883+
size_t epilog;
884+
size_t tail;
885+
} code_offsets = {};
886+
const size_t stack_size = StackLayout::THUNK_STACK_SIZE;
887+
888+
code_offsets.prolog = getSize();
889+
890+
// rsp + 0 = return address
891+
sub(rsp, stack_size);
892+
893+
code_offsets.prolog_stack_alloc = getSize();
894+
code_offsets.body = getSize();
895+
896+
// Save volatile registers
897+
EmitSaveVolatileRegs();
898+
mov(rdi, rsi); // context
899+
mov(rsi, rbx); // target PPC address
900+
mov(rax, reinterpret_cast<uint64_t>(&ResolveFunction));
901+
call(rax);
902+
903+
EmitLoadVolatileRegs();
904+
905+
code_offsets.epilog = getSize();
906+
907+
add(rsp, stack_size);
908+
jmp(rax);
909+
#else
910+
assert_always("Unknown platform ABI in resolve function!");
911+
#endif
770912

771913
code_offsets.tail = getSize();
772914

0 commit comments

Comments
 (0)