New flag: disable_global_lock - Disables global lock usage in guest code.
This commit is contained in:
parent
a5b37dce1d
commit
bd6bf16bd1
|
@ -28,6 +28,10 @@ DEFINE_bool(trace_function_references, false,
|
||||||
DEFINE_bool(trace_function_data, false,
|
DEFINE_bool(trace_function_data, false,
|
||||||
"Generate tracing for function result data.");
|
"Generate tracing for function result data.");
|
||||||
|
|
||||||
|
DEFINE_bool(
|
||||||
|
disable_global_lock, false,
|
||||||
|
"Disables global lock usage in guest code. Does not affect host code.");
|
||||||
|
|
||||||
DEFINE_bool(validate_hir, false,
|
DEFINE_bool(validate_hir, false,
|
||||||
"Perform validation checks on the HIR during compilation.");
|
"Perform validation checks on the HIR during compilation.");
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,8 @@ DECLARE_bool(trace_function_coverage);
|
||||||
DECLARE_bool(trace_function_references);
|
DECLARE_bool(trace_function_references);
|
||||||
DECLARE_bool(trace_function_data);
|
DECLARE_bool(trace_function_data);
|
||||||
|
|
||||||
|
DECLARE_bool(disable_global_lock);
|
||||||
|
|
||||||
DECLARE_bool(validate_hir);
|
DECLARE_bool(validate_hir);
|
||||||
|
|
||||||
DECLARE_uint64(break_on_instruction);
|
DECLARE_uint64(break_on_instruction);
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "xenia/cpu/ppc/ppc_emit-private.h"
|
#include "xenia/cpu/ppc/ppc_emit-private.h"
|
||||||
|
|
||||||
#include "xenia/base/assert.h"
|
#include "xenia/base/assert.h"
|
||||||
|
#include "xenia/cpu/cpu_flags.h"
|
||||||
#include "xenia/cpu/ppc/ppc_context.h"
|
#include "xenia/cpu/ppc/ppc_context.h"
|
||||||
#include "xenia/cpu/ppc/ppc_frontend.h"
|
#include "xenia/cpu/ppc/ppc_frontend.h"
|
||||||
#include "xenia/cpu/ppc/ppc_hir_builder.h"
|
#include "xenia/cpu/ppc/ppc_hir_builder.h"
|
||||||
|
@ -725,11 +726,15 @@ int InstrEmit_mtmsr(PPCHIRBuilder& f, const InstrData& i) {
|
||||||
f.ZeroExtend(f.ZeroExtend(f.LoadGPR(i.X.RT), INT64_TYPE), INT64_TYPE));
|
f.ZeroExtend(f.ZeroExtend(f.LoadGPR(i.X.RT), INT64_TYPE), INT64_TYPE));
|
||||||
if (i.X.RT == 13) {
|
if (i.X.RT == 13) {
|
||||||
// iff storing from r13 we are taking a lock (disable interrupts).
|
// iff storing from r13 we are taking a lock (disable interrupts).
|
||||||
|
if (!FLAGS_disable_global_lock) {
|
||||||
f.CallExtern(f.builtins()->enter_global_lock);
|
f.CallExtern(f.builtins()->enter_global_lock);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Otherwise we are restoring interrupts (probably).
|
// Otherwise we are restoring interrupts (probably).
|
||||||
|
if (!FLAGS_disable_global_lock) {
|
||||||
f.CallExtern(f.builtins()->leave_global_lock);
|
f.CallExtern(f.builtins()->leave_global_lock);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
// L = 0
|
// L = 0
|
||||||
|
@ -746,11 +751,15 @@ int InstrEmit_mtmsrd(PPCHIRBuilder& f, const InstrData& i) {
|
||||||
f.ZeroExtend(f.LoadGPR(i.X.RT), INT64_TYPE));
|
f.ZeroExtend(f.LoadGPR(i.X.RT), INT64_TYPE));
|
||||||
if (i.X.RT == 13) {
|
if (i.X.RT == 13) {
|
||||||
// iff storing from r13 we are taking a lock (disable interrupts).
|
// iff storing from r13 we are taking a lock (disable interrupts).
|
||||||
|
if (!FLAGS_disable_global_lock) {
|
||||||
f.CallExtern(f.builtins()->enter_global_lock);
|
f.CallExtern(f.builtins()->enter_global_lock);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Otherwise we are restoring interrupts (probably).
|
// Otherwise we are restoring interrupts (probably).
|
||||||
|
if (!FLAGS_disable_global_lock) {
|
||||||
f.CallExtern(f.builtins()->leave_global_lock);
|
f.CallExtern(f.builtins()->leave_global_lock);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
// L = 0
|
// L = 0
|
||||||
|
|
|
@ -702,6 +702,9 @@ int InstrEmit_stdcx(PPCHIRBuilder& f, const InstrData& i) {
|
||||||
// NOTE: we assume we are within a global lock.
|
// NOTE: we assume we are within a global lock.
|
||||||
// As we have been exclusively executing this entire time, we assume that no
|
// As we have been exclusively executing this entire time, we assume that no
|
||||||
// one else could have possibly touched the memory and must always succeed.
|
// one else could have possibly touched the memory and must always succeed.
|
||||||
|
// We use atomic compare exchange here to support reserved load/store without
|
||||||
|
// being under the global lock (flag disable_global_lock - see mtmsr/mtmsrd).
|
||||||
|
// This will always succeed if under the global lock, however.
|
||||||
|
|
||||||
Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB);
|
Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB);
|
||||||
Value* rt = f.ByteSwap(f.LoadGPR(i.X.RT));
|
Value* rt = f.ByteSwap(f.LoadGPR(i.X.RT));
|
||||||
|
@ -732,6 +735,9 @@ int InstrEmit_stwcx(PPCHIRBuilder& f, const InstrData& i) {
|
||||||
// NOTE: we assume we are within a global lock.
|
// NOTE: we assume we are within a global lock.
|
||||||
// As we have been exclusively executing this entire time, we assume that no
|
// As we have been exclusively executing this entire time, we assume that no
|
||||||
// one else could have possibly touched the memory and must always succeed.
|
// one else could have possibly touched the memory and must always succeed.
|
||||||
|
// We use atomic compare exchange here to support reserved load/store without
|
||||||
|
// being under the global lock (flag disable_global_lock - see mtmsr/mtmsrd).
|
||||||
|
// This will always succeed if under the global lock, however.
|
||||||
|
|
||||||
Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB);
|
Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB);
|
||||||
Value* rt = f.ByteSwap(f.Truncate(f.LoadGPR(i.X.RT), INT32_TYPE));
|
Value* rt = f.ByteSwap(f.Truncate(f.LoadGPR(i.X.RT), INT32_TYPE));
|
||||||
|
|
|
@ -1251,22 +1251,20 @@ pointer_result_t InterlockedPushEntrySList(
|
||||||
assert_not_null(plist_ptr);
|
assert_not_null(plist_ptr);
|
||||||
assert_not_null(entry);
|
assert_not_null(entry);
|
||||||
|
|
||||||
// Hold a global lock during this method. Once in the lock we assume we have
|
|
||||||
// exclusive access to the structure.
|
|
||||||
auto global_lock = xe::global_critical_region::AcquireDirect();
|
|
||||||
|
|
||||||
alignas(8) X_SLIST_HEADER old_hdr = *plist_ptr;
|
alignas(8) X_SLIST_HEADER old_hdr = *plist_ptr;
|
||||||
alignas(8) X_SLIST_HEADER new_hdr = {0};
|
alignas(8) X_SLIST_HEADER new_hdr = {0};
|
||||||
|
uint32_t old_head = 0;
|
||||||
|
do {
|
||||||
|
old_hdr = *plist_ptr;
|
||||||
new_hdr.depth = old_hdr.depth + 1;
|
new_hdr.depth = old_hdr.depth + 1;
|
||||||
new_hdr.sequence = old_hdr.sequence + 1;
|
new_hdr.sequence = old_hdr.sequence + 1;
|
||||||
|
|
||||||
uint32_t old_head = old_hdr.next.next;
|
uint32_t old_head = old_hdr.next.next;
|
||||||
entry->next = old_hdr.next.next;
|
entry->next = old_hdr.next.next;
|
||||||
new_hdr.next.next = entry.guest_address();
|
new_hdr.next.next = entry.guest_address();
|
||||||
|
} while (
|
||||||
*reinterpret_cast<uint64_t*>(plist_ptr.host_address()) =
|
!xe::atomic_cas(*(uint64_t*)(&old_hdr), *(uint64_t*)(&new_hdr),
|
||||||
*reinterpret_cast<uint64_t*>(&new_hdr);
|
reinterpret_cast<uint64_t*>(plist_ptr.host_address())));
|
||||||
xe::threading::SyncMemory();
|
|
||||||
|
|
||||||
return old_head;
|
return old_head;
|
||||||
}
|
}
|
||||||
|
@ -1276,14 +1274,11 @@ DECLARE_XBOXKRNL_EXPORT(InterlockedPushEntrySList,
|
||||||
pointer_result_t InterlockedPopEntrySList(pointer_t<X_SLIST_HEADER> plist_ptr) {
|
pointer_result_t InterlockedPopEntrySList(pointer_t<X_SLIST_HEADER> plist_ptr) {
|
||||||
assert_not_null(plist_ptr);
|
assert_not_null(plist_ptr);
|
||||||
|
|
||||||
// Hold a global lock during this method. Once in the lock we assume we have
|
|
||||||
// exclusive access to the structure.
|
|
||||||
auto global_lock = xe::global_critical_region::AcquireDirect();
|
|
||||||
|
|
||||||
uint32_t popped = 0;
|
uint32_t popped = 0;
|
||||||
|
alignas(8) X_SLIST_HEADER old_hdr = {0};
|
||||||
alignas(8) X_SLIST_HEADER old_hdr = *plist_ptr;
|
|
||||||
alignas(8) X_SLIST_HEADER new_hdr = {0};
|
alignas(8) X_SLIST_HEADER new_hdr = {0};
|
||||||
|
do {
|
||||||
|
old_hdr = *plist_ptr;
|
||||||
auto next = kernel_memory()->TranslateVirtual<X_SINGLE_LIST_ENTRY*>(
|
auto next = kernel_memory()->TranslateVirtual<X_SINGLE_LIST_ENTRY*>(
|
||||||
old_hdr.next.next);
|
old_hdr.next.next);
|
||||||
if (!old_hdr.next.next) {
|
if (!old_hdr.next.next) {
|
||||||
|
@ -1294,10 +1289,9 @@ pointer_result_t InterlockedPopEntrySList(pointer_t<X_SLIST_HEADER> plist_ptr) {
|
||||||
new_hdr.depth = old_hdr.depth - 1;
|
new_hdr.depth = old_hdr.depth - 1;
|
||||||
new_hdr.next.next = next->next;
|
new_hdr.next.next = next->next;
|
||||||
new_hdr.sequence = old_hdr.sequence;
|
new_hdr.sequence = old_hdr.sequence;
|
||||||
|
} while (
|
||||||
*reinterpret_cast<uint64_t*>(plist_ptr.host_address()) =
|
!xe::atomic_cas(*(uint64_t*)(&old_hdr), *(uint64_t*)(&new_hdr),
|
||||||
*reinterpret_cast<uint64_t*>(&new_hdr);
|
reinterpret_cast<uint64_t*>(plist_ptr.host_address())));
|
||||||
xe::threading::SyncMemory();
|
|
||||||
|
|
||||||
return popped;
|
return popped;
|
||||||
}
|
}
|
||||||
|
@ -1307,20 +1301,18 @@ DECLARE_XBOXKRNL_EXPORT(InterlockedPopEntrySList,
|
||||||
pointer_result_t InterlockedFlushSList(pointer_t<X_SLIST_HEADER> plist_ptr) {
|
pointer_result_t InterlockedFlushSList(pointer_t<X_SLIST_HEADER> plist_ptr) {
|
||||||
assert_not_null(plist_ptr);
|
assert_not_null(plist_ptr);
|
||||||
|
|
||||||
// Hold a global lock during this method. Once in the lock we assume we have
|
|
||||||
// exclusive access to the structure.
|
|
||||||
auto global_lock = xe::global_critical_region::AcquireDirect();
|
|
||||||
|
|
||||||
alignas(8) X_SLIST_HEADER old_hdr = *plist_ptr;
|
alignas(8) X_SLIST_HEADER old_hdr = *plist_ptr;
|
||||||
alignas(8) X_SLIST_HEADER new_hdr = {0};
|
alignas(8) X_SLIST_HEADER new_hdr = {0};
|
||||||
uint32_t first = old_hdr.next.next;
|
uint32_t first = 0;
|
||||||
|
do {
|
||||||
|
old_hdr = *plist_ptr;
|
||||||
|
first = old_hdr.next.next;
|
||||||
new_hdr.next.next = 0;
|
new_hdr.next.next = 0;
|
||||||
new_hdr.depth = 0;
|
new_hdr.depth = 0;
|
||||||
new_hdr.sequence = 0;
|
new_hdr.sequence = 0;
|
||||||
|
} while (
|
||||||
*reinterpret_cast<uint64_t*>(plist_ptr.host_address()) =
|
!xe::atomic_cas(*(uint64_t*)(&old_hdr), *(uint64_t*)(&new_hdr),
|
||||||
*reinterpret_cast<uint64_t*>(&new_hdr);
|
reinterpret_cast<uint64_t*>(plist_ptr.host_address())));
|
||||||
xe::threading::SyncMemory();
|
|
||||||
|
|
||||||
return first;
|
return first;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue