Merge pull request #93 from chrisps/canary_experimental
add some missing kthread fields, fix assert eval in release
This commit is contained in:
@@ -20,9 +20,32 @@ namespace xe {
|
|||||||
static_assert(sizeof(type) == size, \
|
static_assert(sizeof(type) == size, \
|
||||||
"bad definition for " #type ": must be " #size " bytes")
|
"bad definition for " #type ": must be " #size " bytes")
|
||||||
|
|
||||||
// We rely on assert being compiled out in NDEBUG.
|
/*
|
||||||
|
* chrispy: we need to ensure our expression is not eliminated by the
|
||||||
|
* preprocessor before the compiler runs, otherwise clang & gcc will warn about
|
||||||
|
* unused variables and terminate compilation
|
||||||
|
*
|
||||||
|
* Initial approach was to do "#define xenia_assert static_cast<void>" in
|
||||||
|
* release, however, code is generated in this case for the expression, which
|
||||||
|
* isnt desirable (we have assert expressions w/ side effects in a few places)
|
||||||
|
*
|
||||||
|
* so instead, when compiling for msvc we do __noop (which takes varargs and
|
||||||
|
* generates no code), and under clang/gcc we do __builtin_constant_p, which
|
||||||
|
* also does not evaluate the args
|
||||||
|
*
|
||||||
|
*/
|
||||||
#if defined(NDEBUG)
|
#if defined(NDEBUG)
|
||||||
|
|
||||||
|
#if XE_COMPILER_MSVC == 1
|
||||||
|
#define xenia_assert __noop
|
||||||
|
#elif XE_COMPILER_HAS_GNU_EXTENSIONS == 1
|
||||||
|
#define xenia_assert __builtin_constant_p
|
||||||
|
#else
|
||||||
|
#warning \
|
||||||
|
"Compiler does not have MSVC or GNU extensions, falling back to static_cast<void> for assert expr which may cause expressions with sideeffects to be evaluated"
|
||||||
#define xenia_assert static_cast<void>
|
#define xenia_assert static_cast<void>
|
||||||
|
#endif
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define xenia_assert assert
|
#define xenia_assert assert
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -377,6 +377,9 @@ typedef struct alignas(64) PPCContext_s {
|
|||||||
uint64_t r[32]; // 0x20 General purpose registers
|
uint64_t r[32]; // 0x20 General purpose registers
|
||||||
uint64_t ctr; // 0x18 Count register
|
uint64_t ctr; // 0x18 Count register
|
||||||
uint64_t lr; // 0x10 Link register
|
uint64_t lr; // 0x10 Link register
|
||||||
|
|
||||||
|
uint64_t msr; //machine state register
|
||||||
|
|
||||||
double f[32]; // 0x120 Floating-point registers
|
double f[32]; // 0x120 Floating-point registers
|
||||||
vec128_t v[128]; // 0x220 VMX128 vector registers
|
vec128_t v[128]; // 0x220 VMX128 vector registers
|
||||||
vec128_t vscr_vec;
|
vec128_t vscr_vec;
|
||||||
|
|||||||
@@ -789,34 +789,24 @@ int InstrEmit_mtspr(PPCHIRBuilder& f, const InstrData& i) {
|
|||||||
// code requires it. Sequences of mtmsr/lwar/stcw/mtmsr come up a lot, and
|
// code requires it. Sequences of mtmsr/lwar/stcw/mtmsr come up a lot, and
|
||||||
// without the lock here threads can livelock.
|
// without the lock here threads can livelock.
|
||||||
|
|
||||||
|
|
||||||
|
//0x400 = debug singlestep i think
|
||||||
|
//ive seen 0x8000 used in kernel code
|
||||||
int InstrEmit_mfmsr(PPCHIRBuilder& f, const InstrData& i) {
|
int InstrEmit_mfmsr(PPCHIRBuilder& f, const InstrData& i) {
|
||||||
// bit 48 = EE; interrupt enabled
|
// bit 48 = EE; interrupt enabled
|
||||||
// bit 62 = RI; recoverable interrupt
|
// bit 62 = RI; recoverable interrupt
|
||||||
// return 8000h if unlocked (interrupts enabled), else 0
|
// return 8000h if unlocked (interrupts enabled), else 0
|
||||||
#if 0
|
f.StoreGPR(i.X.RT, f.LoadContext(offsetof(PPCContext, msr), INT64_TYPE));
|
||||||
f.MemoryBarrier();
|
|
||||||
if (cvars::disable_global_lock || true) {
|
|
||||||
f.StoreGPR(i.X.RT, f.LoadConstantUint64(0));
|
|
||||||
|
|
||||||
} else {
|
|
||||||
f.CallExtern(f.builtins()->check_global_lock);
|
|
||||||
f.StoreGPR(i.X.RT,
|
|
||||||
f.LoadContext(offsetof(PPCContext, scratch), INT64_TYPE));
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
f.StoreGPR(i.X.RT, f.LoadConstantUint64(0));
|
|
||||||
#endif
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int InstrEmit_mtmsr(PPCHIRBuilder& f, const InstrData& i) {
|
int InstrEmit_mtmsr(PPCHIRBuilder& f, const InstrData& i) {
|
||||||
f.StoreContext(
|
f.StoreContext(offsetof(PPCContext, msr), f.LoadGPR(i.X.RT));
|
||||||
offsetof(PPCContext, scratch),
|
|
||||||
f.ZeroExtend(f.ZeroExtend(f.LoadGPR(i.X.RT), INT64_TYPE), INT64_TYPE));
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int InstrEmit_mtmsrd(PPCHIRBuilder& f, const InstrData& i) {
|
int InstrEmit_mtmsrd(PPCHIRBuilder& f, const InstrData& i) {
|
||||||
|
//todo: this is moving msr under a mask, so only writing EE and RI
|
||||||
f.StoreContext(offsetof(PPCContext, scratch),
|
f.StoreContext(offsetof(PPCContext, scratch),
|
||||||
f.ZeroExtend(f.LoadGPR(i.X.RT), INT64_TYPE));
|
f.ZeroExtend(f.LoadGPR(i.X.RT), INT64_TYPE));
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -263,6 +263,12 @@ Function* Processor::ResolveFunction(uint32_t address) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!DemandFunction(function)) {
|
||||||
|
entry->status = Entry::STATUS_FAILED;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
//only add it to the list of resolved functions if resolving succeeded
|
||||||
auto module_for = function->module();
|
auto module_for = function->module();
|
||||||
|
|
||||||
auto xexmod = dynamic_cast<XexModule*>(module_for);
|
auto xexmod = dynamic_cast<XexModule*>(module_for);
|
||||||
@@ -273,10 +279,6 @@ Function* Processor::ResolveFunction(uint32_t address) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!DemandFunction(function)) {
|
|
||||||
entry->status = Entry::STATUS_FAILED;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
entry->function = function;
|
entry->function = function;
|
||||||
entry->end_address = function->end_address();
|
entry->end_address = function->end_address();
|
||||||
status = entry->status = Entry::STATUS_READY;
|
status = entry->status = Entry::STATUS_READY;
|
||||||
|
|||||||
@@ -1328,6 +1328,7 @@ void XexInfoCache::Init(XexModule* xexmod) {
|
|||||||
if (cvars::disable_instruction_infocache) {
|
if (cvars::disable_instruction_infocache) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto emu = xexmod->kernel_state_->emulator();
|
auto emu = xexmod->kernel_state_->emulator();
|
||||||
std::filesystem::path infocache_path = emu->cache_root();
|
std::filesystem::path infocache_path = emu->cache_root();
|
||||||
|
|
||||||
@@ -1341,13 +1342,16 @@ void XexInfoCache::Init(XexModule* xexmod) {
|
|||||||
unsigned num_codebytes = xexmod->high_address_ - xexmod->low_address_;
|
unsigned num_codebytes = xexmod->high_address_ - xexmod->low_address_;
|
||||||
num_codebytes += 3; // round up to nearest multiple of 4
|
num_codebytes += 3; // round up to nearest multiple of 4
|
||||||
num_codebytes &= ~3;
|
num_codebytes &= ~3;
|
||||||
|
|
||||||
bool did_exist = true;
|
bool did_exist = true;
|
||||||
if (!std::filesystem::exists(infocache_path)) {
|
if (!std::filesystem::exists(infocache_path)) {
|
||||||
|
recreate:
|
||||||
xe::filesystem::CreateEmptyFile(infocache_path);
|
xe::filesystem::CreateEmptyFile(infocache_path);
|
||||||
did_exist = false;
|
did_exist = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: prepopulate with stuff from pdata, dll exports
|
// todo: prepopulate with stuff from pdata, dll exports
|
||||||
|
|
||||||
this->executable_addr_flags_ = std::move(xe::MappedMemory::Open(
|
this->executable_addr_flags_ = std::move(xe::MappedMemory::Open(
|
||||||
infocache_path, xe::MappedMemory::Mode::kReadWrite, 0,
|
infocache_path, xe::MappedMemory::Mode::kReadWrite, 0,
|
||||||
sizeof(InfoCacheFlagsHeader) +
|
sizeof(InfoCacheFlagsHeader) +
|
||||||
@@ -1355,11 +1359,17 @@ void XexInfoCache::Init(XexModule* xexmod) {
|
|||||||
(num_codebytes /
|
(num_codebytes /
|
||||||
4)))); // one infocacheflags entry for each PPC instr-sized addr
|
4)))); // one infocacheflags entry for each PPC instr-sized addr
|
||||||
|
|
||||||
if (did_exist) {
|
if (!did_exist) {
|
||||||
xexmod->PrecompileKnownFunctions();
|
GetHeader()->version = CURRENT_INFOCACHE_VERSION;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (GetHeader()->version != CURRENT_INFOCACHE_VERSION) {
|
||||||
|
this->executable_addr_flags_->Close();
|
||||||
|
std::filesystem::remove(infocache_path);
|
||||||
|
goto recreate;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InfoCacheFlags* XexModule::GetInstructionAddressFlags(uint32_t guest_addr) {
|
InfoCacheFlags* XexModule::GetInstructionAddressFlags(uint32_t guest_addr) {
|
||||||
if (guest_addr < low_address_ || guest_addr > high_address_) {
|
if (guest_addr < low_address_ || guest_addr > high_address_) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -1371,7 +1381,7 @@ InfoCacheFlags* XexModule::GetInstructionAddressFlags(uint32_t guest_addr) {
|
|||||||
}
|
}
|
||||||
void XexModule::PrecompileDiscoveredFunctions() {
|
void XexModule::PrecompileDiscoveredFunctions() {
|
||||||
if (cvars::disable_early_precompilation) {
|
if (cvars::disable_early_precompilation) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto others = PreanalyzeCode();
|
auto others = PreanalyzeCode();
|
||||||
|
|
||||||
@@ -1396,7 +1406,7 @@ void XexModule::PrecompileKnownFunctions() {
|
|||||||
if (!flags) {
|
if (!flags) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//maybe should pre-acquire global crit?
|
// maybe should pre-acquire global crit?
|
||||||
for (uint32_t i = 0; i < end; i++) {
|
for (uint32_t i = 0; i < end; i++) {
|
||||||
if (flags[i].was_resolved) {
|
if (flags[i].was_resolved) {
|
||||||
uint32_t addr = low_address_ + (i * 4);
|
uint32_t addr = low_address_ + (i * 4);
|
||||||
@@ -1425,8 +1435,20 @@ static bool IsOpcodeBL(unsigned w) {
|
|||||||
|
|
||||||
std::vector<uint32_t> XexModule::PreanalyzeCode() {
|
std::vector<uint32_t> XexModule::PreanalyzeCode() {
|
||||||
uint32_t low_8_aligned = xe::align<uint32_t>(low_address_, 8);
|
uint32_t low_8_aligned = xe::align<uint32_t>(low_address_, 8);
|
||||||
uint32_t high_8_aligned = high_address_ & ~(8U - 1);
|
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t highest_exec_addr = 0;
|
||||||
|
|
||||||
|
for (auto&& sec : pe_sections_) {
|
||||||
|
if ((sec.flags & kXEPESectionContainsCode)) {
|
||||||
|
|
||||||
|
|
||||||
|
highest_exec_addr =
|
||||||
|
std::max<uint32_t>(highest_exec_addr, sec.address + sec.size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint32_t high_8_aligned = highest_exec_addr & ~(8U - 1);
|
||||||
uint32_t n_possible_8byte_addresses = (high_8_aligned - low_8_aligned) / 8;
|
uint32_t n_possible_8byte_addresses = (high_8_aligned - low_8_aligned) / 8;
|
||||||
uint32_t* funcstart_candidate_stack =
|
uint32_t* funcstart_candidate_stack =
|
||||||
new uint32_t[n_possible_8byte_addresses];
|
new uint32_t[n_possible_8byte_addresses];
|
||||||
@@ -1453,6 +1475,10 @@ std::vector<uint32_t> XexModule::PreanalyzeCode() {
|
|||||||
|
|
||||||
uint32_t mfspr_r12_lr32 =
|
uint32_t mfspr_r12_lr32 =
|
||||||
*reinterpret_cast<const uint32_t*>(&mfspr_r12_lr[0]);
|
*reinterpret_cast<const uint32_t*>(&mfspr_r12_lr[0]);
|
||||||
|
|
||||||
|
auto add_new_func = [funcstart_candidate_stack, &stack_pos](uint32_t addr) {
|
||||||
|
funcstart_candidate_stack[stack_pos++] = addr;
|
||||||
|
};
|
||||||
/*
|
/*
|
||||||
First pass: detect save of the link register at an eight byte
|
First pass: detect save of the link register at an eight byte
|
||||||
aligned address
|
aligned address
|
||||||
@@ -1462,10 +1488,10 @@ std::vector<uint32_t> XexModule::PreanalyzeCode() {
|
|||||||
if (*first_pass == mfspr_r12_lr32) {
|
if (*first_pass == mfspr_r12_lr32) {
|
||||||
// Push our newly discovered function start into our list
|
// Push our newly discovered function start into our list
|
||||||
// All addresses in the list are sorted until the second pass
|
// All addresses in the list are sorted until the second pass
|
||||||
funcstart_candidate_stack[stack_pos++] =
|
add_new_func(
|
||||||
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(first_pass) -
|
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(first_pass) -
|
||||||
reinterpret_cast<uintptr_t>(range_start)) +
|
reinterpret_cast<uintptr_t>(range_start)) +
|
||||||
low_8_aligned;
|
low_8_aligned);
|
||||||
} else if (first_pass[-1] == 0 && *first_pass != 0) {
|
} else if (first_pass[-1] == 0 && *first_pass != 0) {
|
||||||
// originally i checked for blr followed by 0, but some functions are
|
// originally i checked for blr followed by 0, but some functions are
|
||||||
// actually aligned to greater boundaries. something that appears to be
|
// actually aligned to greater boundaries. something that appears to be
|
||||||
@@ -1478,10 +1504,10 @@ std::vector<uint32_t> XexModule::PreanalyzeCode() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
XE_LIKELY_IF(*check_iter == blr32) {
|
XE_LIKELY_IF(*check_iter == blr32) {
|
||||||
funcstart_candidate_stack[stack_pos++] =
|
add_new_func(
|
||||||
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(first_pass) -
|
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(first_pass) -
|
||||||
reinterpret_cast<uintptr_t>(range_start)) +
|
reinterpret_cast<uintptr_t>(range_start)) +
|
||||||
low_8_aligned;
|
low_8_aligned);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1494,8 +1520,14 @@ std::vector<uint32_t> XexModule::PreanalyzeCode() {
|
|||||||
uint32_t current_call = xe::byte_swap(*second_pass);
|
uint32_t current_call = xe::byte_swap(*second_pass);
|
||||||
|
|
||||||
if (IsOpcodeBL(current_call)) {
|
if (IsOpcodeBL(current_call)) {
|
||||||
funcstart_candidate_stack[stack_pos++] = GetBLCalledFunction(
|
uint32_t called_function = GetBLCalledFunction(
|
||||||
this, current_guestaddr, ppc::PPCOpcodeBits{current_call});
|
this, current_guestaddr, ppc::PPCOpcodeBits{current_call});
|
||||||
|
// must be 8 byte aligned and in range
|
||||||
|
if ((called_function & (8 - 1)) == 0 &&
|
||||||
|
called_function >= low_address_ &&
|
||||||
|
called_function < high_address_) {
|
||||||
|
add_new_func(called_function);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1509,8 +1541,8 @@ std::vector<uint32_t> XexModule::PreanalyzeCode() {
|
|||||||
|
|
||||||
for (uint32_t i = 0; i < n_pdata_entries; ++i) {
|
for (uint32_t i = 0; i < n_pdata_entries; ++i) {
|
||||||
uint32_t funcaddr = xe::load_and_swap<uint32_t>(&pdata_base[i * 2]);
|
uint32_t funcaddr = xe::load_and_swap<uint32_t>(&pdata_base[i * 2]);
|
||||||
if (funcaddr >= low_address_ && funcaddr <= high_address_) {
|
if (funcaddr >= low_address_ && funcaddr <= highest_exec_addr) {
|
||||||
funcstart_candidate_stack[stack_pos++] = funcaddr;
|
add_new_func(funcaddr);
|
||||||
} else {
|
} else {
|
||||||
// we hit 0 for func addr, that means we're done
|
// we hit 0 for func addr, that means we're done
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ constexpr fourcc_t kXEX1Signature = make_fourcc("XEX1");
|
|||||||
constexpr fourcc_t kXEX2Signature = make_fourcc("XEX2");
|
constexpr fourcc_t kXEX2Signature = make_fourcc("XEX2");
|
||||||
constexpr fourcc_t kElfSignature = make_fourcc(0x7F, 'E', 'L', 'F');
|
constexpr fourcc_t kElfSignature = make_fourcc(0x7F, 'E', 'L', 'F');
|
||||||
|
|
||||||
|
|
||||||
class Runtime;
|
class Runtime;
|
||||||
struct InfoCacheFlags {
|
struct InfoCacheFlags {
|
||||||
uint32_t was_resolved : 1; // has this address ever been called/requested
|
uint32_t was_resolved : 1; // has this address ever been called/requested
|
||||||
@@ -38,8 +39,13 @@ struct InfoCacheFlags {
|
|||||||
uint32_t reserved : 29;
|
uint32_t reserved : 29;
|
||||||
};
|
};
|
||||||
struct XexInfoCache {
|
struct XexInfoCache {
|
||||||
|
//increment this to invalidate all user infocaches
|
||||||
|
static constexpr uint32_t CURRENT_INFOCACHE_VERSION = 1;
|
||||||
|
|
||||||
struct InfoCacheFlagsHeader {
|
struct InfoCacheFlagsHeader {
|
||||||
unsigned char reserved[256]; // put xenia version here
|
uint32_t version;
|
||||||
|
|
||||||
|
unsigned char reserved[252];
|
||||||
|
|
||||||
InfoCacheFlags* LookupFlags(unsigned offset) {
|
InfoCacheFlags* LookupFlags(unsigned offset) {
|
||||||
return &reinterpret_cast<InfoCacheFlags*>(&this[1])[offset];
|
return &reinterpret_cast<InfoCacheFlags*>(&this[1])[offset];
|
||||||
@@ -51,6 +57,18 @@ struct XexInfoCache {
|
|||||||
std::unique_ptr<MappedMemory> executable_addr_flags_;
|
std::unique_ptr<MappedMemory> executable_addr_flags_;
|
||||||
|
|
||||||
void Init(class XexModule*);
|
void Init(class XexModule*);
|
||||||
|
InfoCacheFlagsHeader* GetHeader() {
|
||||||
|
if (!executable_addr_flags_) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
uint8_t* data = executable_addr_flags_->data();
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return reinterpret_cast<InfoCacheFlagsHeader*>(data);
|
||||||
|
}
|
||||||
|
|
||||||
InfoCacheFlags* LookupFlags(unsigned offset) {
|
InfoCacheFlags* LookupFlags(unsigned offset) {
|
||||||
offset /= 4;
|
offset /= 4;
|
||||||
if (!executable_addr_flags_) {
|
if (!executable_addr_flags_) {
|
||||||
|
|||||||
@@ -518,7 +518,7 @@ void KernelState::UnloadUserModule(const object_ref<UserModule>& module,
|
|||||||
return e->path() == module->path();
|
return e->path() == module->path();
|
||||||
}) == user_modules_.end());
|
}) == user_modules_.end());
|
||||||
|
|
||||||
object_table()->ReleaseHandle(module->handle());
|
object_table()->ReleaseHandleInLock(module->handle());
|
||||||
}
|
}
|
||||||
|
|
||||||
void KernelState::TerminateTitle() {
|
void KernelState::TerminateTitle() {
|
||||||
|
|||||||
@@ -149,7 +149,7 @@ X_STATUS ObjectTable::DuplicateHandle(X_HANDLE handle, X_HANDLE* out_handle) {
|
|||||||
X_STATUS ObjectTable::RetainHandle(X_HANDLE handle) {
|
X_STATUS ObjectTable::RetainHandle(X_HANDLE handle) {
|
||||||
auto global_lock = global_critical_region_.Acquire();
|
auto global_lock = global_critical_region_.Acquire();
|
||||||
|
|
||||||
ObjectTableEntry* entry = LookupTable(handle);
|
ObjectTableEntry* entry = LookupTableInLock(handle);
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
return X_STATUS_INVALID_HANDLE;
|
return X_STATUS_INVALID_HANDLE;
|
||||||
}
|
}
|
||||||
@@ -161,7 +161,10 @@ X_STATUS ObjectTable::RetainHandle(X_HANDLE handle) {
|
|||||||
X_STATUS ObjectTable::ReleaseHandle(X_HANDLE handle) {
|
X_STATUS ObjectTable::ReleaseHandle(X_HANDLE handle) {
|
||||||
auto global_lock = global_critical_region_.Acquire();
|
auto global_lock = global_critical_region_.Acquire();
|
||||||
|
|
||||||
ObjectTableEntry* entry = LookupTable(handle);
|
return ReleaseHandleInLock(handle);
|
||||||
|
}
|
||||||
|
X_STATUS ObjectTable::ReleaseHandleInLock(X_HANDLE handle) {
|
||||||
|
ObjectTableEntry* entry = LookupTableInLock(handle);
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
return X_STATUS_INVALID_HANDLE;
|
return X_STATUS_INVALID_HANDLE;
|
||||||
}
|
}
|
||||||
@@ -175,7 +178,6 @@ X_STATUS ObjectTable::ReleaseHandle(X_HANDLE handle) {
|
|||||||
// (but not a failure code)
|
// (but not a failure code)
|
||||||
return X_STATUS_SUCCESS;
|
return X_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
X_STATUS ObjectTable::RemoveHandle(X_HANDLE handle) {
|
X_STATUS ObjectTable::RemoveHandle(X_HANDLE handle) {
|
||||||
X_STATUS result = X_STATUS_SUCCESS;
|
X_STATUS result = X_STATUS_SUCCESS;
|
||||||
|
|
||||||
@@ -183,13 +185,13 @@ X_STATUS ObjectTable::RemoveHandle(X_HANDLE handle) {
|
|||||||
if (!handle) {
|
if (!handle) {
|
||||||
return X_STATUS_INVALID_HANDLE;
|
return X_STATUS_INVALID_HANDLE;
|
||||||
}
|
}
|
||||||
|
auto global_lock = global_critical_region_.Acquire();
|
||||||
|
|
||||||
ObjectTableEntry* entry = LookupTable(handle);
|
ObjectTableEntry* entry = LookupTableInLock(handle);
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
return X_STATUS_INVALID_HANDLE;
|
return X_STATUS_INVALID_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto global_lock = global_critical_region_.Acquire();
|
|
||||||
if (entry->object) {
|
if (entry->object) {
|
||||||
auto object = entry->object;
|
auto object = entry->object;
|
||||||
entry->object = nullptr;
|
entry->object = nullptr;
|
||||||
@@ -246,13 +248,16 @@ void ObjectTable::PurgeAllObjects() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ObjectTable::ObjectTableEntry* ObjectTable::LookupTable(X_HANDLE handle) {
|
ObjectTable::ObjectTableEntry* ObjectTable::LookupTable(X_HANDLE handle) {
|
||||||
|
auto global_lock = global_critical_region_.Acquire();
|
||||||
|
return LookupTableInLock(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectTable::ObjectTableEntry* ObjectTable::LookupTableInLock(X_HANDLE handle) {
|
||||||
handle = TranslateHandle(handle);
|
handle = TranslateHandle(handle);
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto global_lock = global_critical_region_.Acquire();
|
|
||||||
|
|
||||||
// Lower 2 bits are ignored.
|
// Lower 2 bits are ignored.
|
||||||
uint32_t slot = GetHandleSlot(handle);
|
uint32_t slot = GetHandleSlot(handle);
|
||||||
if (slot <= table_capacity_) {
|
if (slot <= table_capacity_) {
|
||||||
@@ -264,8 +269,8 @@ ObjectTable::ObjectTableEntry* ObjectTable::LookupTable(X_HANDLE handle) {
|
|||||||
|
|
||||||
// Generic lookup
|
// Generic lookup
|
||||||
template <>
|
template <>
|
||||||
object_ref<XObject> ObjectTable::LookupObject<XObject>(
|
object_ref<XObject> ObjectTable::LookupObject<XObject>(X_HANDLE handle,
|
||||||
X_HANDLE handle, bool already_locked) {
|
bool already_locked) {
|
||||||
auto object = ObjectTable::LookupObject(handle, already_locked);
|
auto object = ObjectTable::LookupObject(handle, already_locked);
|
||||||
auto result = object_ref<XObject>(reinterpret_cast<XObject*>(object));
|
auto result = object_ref<XObject>(reinterpret_cast<XObject*>(object));
|
||||||
return result;
|
return result;
|
||||||
@@ -320,15 +325,14 @@ void ObjectTable::GetObjectsByType(XObject::Type type,
|
|||||||
}
|
}
|
||||||
|
|
||||||
X_HANDLE ObjectTable::TranslateHandle(X_HANDLE handle) {
|
X_HANDLE ObjectTable::TranslateHandle(X_HANDLE handle) {
|
||||||
if (handle == 0xFFFFFFFF) {
|
// chrispy: reordered these by likelihood, most likely case is that handle is
|
||||||
// CurrentProcess
|
// not a special handle
|
||||||
// assert_always();
|
XE_LIKELY_IF(handle < 0xFFFFFFFE) { return handle; }
|
||||||
|
else if (handle == 0xFFFFFFFF) {
|
||||||
return 0;
|
return 0;
|
||||||
} else if (handle == 0xFFFFFFFE) {
|
}
|
||||||
// CurrentThread
|
else {
|
||||||
return XThread::GetCurrentThreadHandle();
|
return XThread::GetCurrentThreadHandle();
|
||||||
} else {
|
|
||||||
return handle;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ class ObjectTable {
|
|||||||
X_STATUS DuplicateHandle(X_HANDLE orig, X_HANDLE* out_handle);
|
X_STATUS DuplicateHandle(X_HANDLE orig, X_HANDLE* out_handle);
|
||||||
X_STATUS RetainHandle(X_HANDLE handle);
|
X_STATUS RetainHandle(X_HANDLE handle);
|
||||||
X_STATUS ReleaseHandle(X_HANDLE handle);
|
X_STATUS ReleaseHandle(X_HANDLE handle);
|
||||||
|
X_STATUS ReleaseHandleInLock(X_HANDLE handle);
|
||||||
X_STATUS RemoveHandle(X_HANDLE handle);
|
X_STATUS RemoveHandle(X_HANDLE handle);
|
||||||
|
|
||||||
bool Save(ByteStream* stream);
|
bool Save(ByteStream* stream);
|
||||||
@@ -87,7 +88,7 @@ class ObjectTable {
|
|||||||
int handle_ref_count = 0;
|
int handle_ref_count = 0;
|
||||||
XObject* object = nullptr;
|
XObject* object = nullptr;
|
||||||
};
|
};
|
||||||
|
ObjectTableEntry* LookupTableInLock(X_HANDLE handle);
|
||||||
ObjectTableEntry* LookupTable(X_HANDLE handle);
|
ObjectTableEntry* LookupTable(X_HANDLE handle);
|
||||||
XObject* LookupObject(X_HANDLE handle, bool already_locked);
|
XObject* LookupObject(X_HANDLE handle, bool already_locked);
|
||||||
void GetObjectsByType(XObject::Type type,
|
void GetObjectsByType(XObject::Type type,
|
||||||
|
|||||||
@@ -19,8 +19,13 @@ namespace xe {
|
|||||||
namespace kernel {
|
namespace kernel {
|
||||||
namespace xboxkrnl {
|
namespace xboxkrnl {
|
||||||
|
|
||||||
void KeEnableFpuExceptions_entry(dword_t enabled) {
|
void KeEnableFpuExceptions_entry(
|
||||||
|
const ppc_context_t& ctx) { // dword_t enabled) {
|
||||||
// TODO(benvanik): can we do anything about exceptions?
|
// TODO(benvanik): can we do anything about exceptions?
|
||||||
|
// theres a lot more thats supposed to happen here, the floating point state has to be saved to kthread, the irql changes, the machine state register is changed to enable exceptions
|
||||||
|
|
||||||
|
X_KTHREAD* kthread = ctx->TranslateVirtualGPR<X_KTHREAD*>(ctx->r[13]);
|
||||||
|
kthread->fpu_exceptions_on = static_cast<uint32_t>(ctx->r[3]) != 0;
|
||||||
}
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT1(KeEnableFpuExceptions, kNone, kStub);
|
DECLARE_XBOXKRNL_EXPORT1(KeEnableFpuExceptions, kNone, kStub);
|
||||||
#if 0
|
#if 0
|
||||||
|
|||||||
@@ -717,6 +717,9 @@ void XThread::RundownAPCs() {
|
|||||||
int32_t XThread::QueryPriority() { return thread_->priority(); }
|
int32_t XThread::QueryPriority() { return thread_->priority(); }
|
||||||
|
|
||||||
void XThread::SetPriority(int32_t increment) {
|
void XThread::SetPriority(int32_t increment) {
|
||||||
|
if (is_guest_thread()) {
|
||||||
|
guest_object<X_KTHREAD>()->priority = static_cast<uint8_t>(increment);
|
||||||
|
}
|
||||||
priority_ = increment;
|
priority_ = increment;
|
||||||
int32_t target_priority = 0;
|
int32_t target_priority = 0;
|
||||||
if (increment > 0x22) {
|
if (increment > 0x22) {
|
||||||
|
|||||||
@@ -101,7 +101,12 @@ struct X_KTHREAD {
|
|||||||
xe::be<uint32_t> stack_kernel; // 0x64
|
xe::be<uint32_t> stack_kernel; // 0x64
|
||||||
xe::be<uint32_t> tls_address; // 0x68
|
xe::be<uint32_t> tls_address; // 0x68
|
||||||
uint8_t unk_6C; // 0x6C
|
uint8_t unk_6C; // 0x6C
|
||||||
uint8_t unk_6D[0x7]; // 0x6D
|
//0x70 = priority?
|
||||||
|
uint8_t unk_6D[0x3]; // 0x6D
|
||||||
|
uint8_t priority; // 0x70
|
||||||
|
uint8_t fpu_exceptions_on; // 0x71
|
||||||
|
uint8_t unk_72;
|
||||||
|
uint8_t unk_73;
|
||||||
xe::be<uint32_t> unk_74; // 0x74
|
xe::be<uint32_t> unk_74; // 0x74
|
||||||
xe::be<uint32_t> unk_78; // 0x78
|
xe::be<uint32_t> unk_78; // 0x78
|
||||||
xe::be<uint32_t> unk_7C; // 0x7C
|
xe::be<uint32_t> unk_7C; // 0x7C
|
||||||
|
|||||||
Reference in New Issue
Block a user