Skip to content

Commit cec5fcf

Browse files
author
guccigang420
committed
Added System-V ABI support in x64 backend & fixed mmap usage
1 parent c5e6352 commit cec5fcf

File tree

3 files changed

+152
-2
lines changed

3 files changed

+152
-2
lines changed

src/xenia/base/mapped_memory_posix.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ class PosixMappedMemory : public MappedMemory {
5656
map_length = size_t(file_stat.st_size);
5757
}
5858

59+
// Ensure that the file is large enough.
60+
ftruncate(file_descriptor, map_length);
61+
5962
void* data =
6063
mmap(0, map_length, protection, MAP_SHARED, file_descriptor, offset);
6164
if (!data) {

src/xenia/base/memory_posix.cc

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,11 @@ void* AllocFixed(void* base_address, size_t length,
8585
AllocationType allocation_type, PageAccess access) {
8686
// mmap does not support reserve / commit, so ignore allocation_type.
8787
uint32_t prot = ToPosixProtectFlags(access);
88-
void* result = mmap(base_address, length, prot,
89-
MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
88+
int flags = MAP_PRIVATE | MAP_ANONYMOUS;
89+
if (base_address != nullptr) {
90+
flags |= MAP_FIXED;
91+
}
92+
void* result = mmap(base_address, length, prot, flags, -1, 0);
9093
if (result == MAP_FAILED) {
9194
return nullptr;
9295
} else {

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

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,7 @@ X64ThunkEmitter::X64ThunkEmitter(X64Backend* backend, XbyakAllocator* allocator)
418418
X64ThunkEmitter::~X64ThunkEmitter() {}
419419

420420
HostToGuestThunk X64ThunkEmitter::EmitHostToGuestThunk() {
421+
#if XE_PLATFORM_WIN32
421422
// rcx = target
422423
// rdx = arg0 (context)
423424
// r8 = arg1 (guest return address)
@@ -460,6 +461,53 @@ HostToGuestThunk X64ThunkEmitter::EmitHostToGuestThunk() {
460461
mov(rdx, qword[rsp + 8 * 2]);
461462
mov(r8, qword[rsp + 8 * 3]);
462463
ret();
464+
#elif XE_PLATFORM_LINUX || XE_PLATFORM_MAC
465+
// System-V ABI args:
466+
// rdi = target
467+
// rsi = arg0 (context)
468+
// rdx = arg1 (guest return address)
469+
470+
struct _code_offsets {
471+
size_t prolog;
472+
size_t prolog_stack_alloc;
473+
size_t body;
474+
size_t epilog;
475+
size_t tail;
476+
} code_offsets = {};
477+
478+
const size_t stack_size = StackLayout::THUNK_STACK_SIZE;
479+
480+
code_offsets.prolog = getSize();
481+
482+
// rsp + 0 = return address
483+
mov(qword[rsp + 8 * 3], rdx);
484+
mov(qword[rsp + 8 * 2], rsi);
485+
mov(qword[rsp + 8 * 1], rdi);
486+
sub(rsp, stack_size);
487+
488+
code_offsets.prolog_stack_alloc = getSize();
489+
code_offsets.body = getSize();
490+
491+
// Save nonvolatile registers.
492+
EmitSaveNonvolatileRegs();
493+
494+
mov(rax, rdi);
495+
// mov(rsi, rsi); // context
496+
mov(rcx, rdx); // return address
497+
call(rax);
498+
499+
EmitLoadNonvolatileRegs();
500+
501+
code_offsets.epilog = getSize();
502+
503+
add(rsp, stack_size);
504+
mov(rdi, qword[rsp + 8 * 1]);
505+
mov(rsi, qword[rsp + 8 * 2]);
506+
mov(rdx, qword[rsp + 8 * 3]);
507+
ret();
508+
#else
509+
assert_always("Unknown platform ABI in host to guest thunk!");
510+
#endif
463511

464512
code_offsets.tail = getSize();
465513

@@ -479,6 +527,7 @@ HostToGuestThunk X64ThunkEmitter::EmitHostToGuestThunk() {
479527
}
480528

481529
GuestToHostThunk X64ThunkEmitter::EmitGuestToHostThunk() {
530+
#if XE_PLATFORM_WIN32
482531
// rcx = target function
483532
// rdx = arg0
484533
// r8 = arg1
@@ -515,6 +564,57 @@ GuestToHostThunk X64ThunkEmitter::EmitGuestToHostThunk() {
515564

516565
add(rsp, stack_size);
517566
ret();
567+
#elif XE_PLATFORM_LINUX || XE_PLATFORM_MAC
568+
// This function is being called using the Microsoft ABI from CallNative
569+
// rcx = target function
570+
// rdx = arg0
571+
// r8 = arg1
572+
// r9 = arg2
573+
574+
// Must be translated to System-V ABI:
575+
// rdi = target function
576+
// rsi = arg0
577+
// rdx = arg1
578+
// rcx = arg2
579+
// r8, r9 - unused argument registers
580+
581+
struct _code_offsets {
582+
size_t prolog;
583+
size_t prolog_stack_alloc;
584+
size_t body;
585+
size_t epilog;
586+
size_t tail;
587+
} code_offsets = {};
588+
589+
const size_t stack_size = StackLayout::THUNK_STACK_SIZE;
590+
591+
code_offsets.prolog = getSize();
592+
593+
// rsp + 0 = return address
594+
sub(rsp, stack_size);
595+
596+
code_offsets.prolog_stack_alloc = getSize();
597+
code_offsets.body = getSize();
598+
599+
// Save off volatile registers.
600+
EmitSaveVolatileRegs();
601+
602+
mov(rax, rcx); // function
603+
mov(rdi, GetContextReg()); // context
604+
mov(rsi, rdx); // arg0
605+
mov(rdx, r8); // arg1
606+
mov(rcx, r9); // arg2
607+
call(rax);
608+
609+
EmitLoadVolatileRegs();
610+
611+
code_offsets.epilog = getSize();
612+
613+
add(rsp, stack_size);
614+
ret();
615+
#else
616+
assert_always("Unknown platform ABI in guest to host thunk!")
617+
#endif
518618

519619
code_offsets.tail = getSize();
520620

@@ -537,6 +637,7 @@ GuestToHostThunk X64ThunkEmitter::EmitGuestToHostThunk() {
537637
uint64_t ResolveFunction(void* raw_context, uint64_t target_address);
538638

539639
ResolveFunctionThunk X64ThunkEmitter::EmitResolveFunctionThunk() {
640+
#if XE_PLATFORM_WIN32
540641
// ebx = target PPC address
541642
// rcx = context
542643

@@ -572,6 +673,49 @@ ResolveFunctionThunk X64ThunkEmitter::EmitResolveFunctionThunk() {
572673

573674
add(rsp, stack_size);
574675
jmp(rax);
676+
#elif XE_PLATFORM_LINUX || XE_PLATFORM_MAC
677+
// Function is called with the following params:
678+
// ebx = target PPC address
679+
// rsi = context
680+
681+
// System-V ABI args:
682+
// rdi = context
683+
// rsi = target PPC address
684+
685+
struct _code_offsets {
686+
size_t prolog;
687+
size_t prolog_stack_alloc;
688+
size_t body;
689+
size_t epilog;
690+
size_t tail;
691+
} code_offsets = {};
692+
693+
const size_t stack_size = StackLayout::THUNK_STACK_SIZE;
694+
695+
code_offsets.prolog = getSize();
696+
697+
// rsp + 0 = return address
698+
sub(rsp, stack_size);
699+
700+
code_offsets.prolog_stack_alloc = getSize();
701+
code_offsets.body = getSize();
702+
703+
// Save volatile registers
704+
EmitSaveVolatileRegs();
705+
mov(rdi, rsi); // context
706+
mov(rsi, rbx); // target PPC address
707+
mov(rax, reinterpret_cast<uint64_t>(&ResolveFunction));
708+
call(rax);
709+
710+
EmitLoadVolatileRegs();
711+
712+
code_offsets.epilog = getSize();
713+
714+
add(rsp, stack_size);
715+
jmp(rax);
716+
#else
717+
assert_always("Unknown platform ABI in resolve function!");
718+
#endif
575719

576720
code_offsets.tail = getSize();
577721

0 commit comments

Comments
 (0)