Merge branch 'memory'

This commit is contained in:
Ben Vanik
2015-05-19 20:29:00 -07:00
51 changed files with 1978 additions and 871 deletions

View File

@@ -140,9 +140,25 @@ X_STATUS HostPathEntry::Open(KernelState* kernel_state, Mode mode, bool async,
// TODO(benvanik): plumb through proper disposition/access mode.
DWORD desired_access =
is_read_only() ? GENERIC_READ : (GENERIC_READ | GENERIC_WRITE);
// mode == Mode::READ ? GENERIC_READ : (GENERIC_READ | GENERIC_WRITE);
if (mode == Mode::READ_APPEND) {
desired_access |= FILE_APPEND_DATA;
}
DWORD share_mode = FILE_SHARE_READ;
DWORD creation_disposition = mode == Mode::READ ? OPEN_EXISTING : OPEN_ALWAYS;
DWORD creation_disposition;
switch (mode) {
case Mode::READ:
creation_disposition = OPEN_EXISTING;
break;
case Mode::READ_WRITE:
creation_disposition = OPEN_ALWAYS;
break;
case Mode::READ_APPEND:
creation_disposition = OPEN_EXISTING;
break;
default:
assert_unhandled_case(mode);
break;
}
DWORD flags_and_attributes = async ? FILE_FLAG_OVERLAPPED : 0;
HANDLE file =
CreateFile(local_path_.c_str(), desired_access, share_mode, NULL,
@@ -150,7 +166,7 @@ X_STATUS HostPathEntry::Open(KernelState* kernel_state, Mode mode, bool async,
flags_and_attributes | FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (file == INVALID_HANDLE_VALUE) {
// TODO(benvanik): pick correct response.
return X_STATUS_ACCESS_DENIED;
return X_STATUS_NO_SUCH_FILE;
}
*out_file = new HostPathFile(kernel_state, mode, this, file);

View File

@@ -35,6 +35,7 @@ class Device;
enum class Mode {
READ,
READ_WRITE,
READ_APPEND,
};
class MemoryMapping {

View File

@@ -97,6 +97,19 @@ void KernelState::RegisterModule(XModule* module) {}
void KernelState::UnregisterModule(XModule* module) {}
bool KernelState::IsKernelModule(const char* name) {
if (!name) {
// executing module isn't a kernel module
return false;
} else if (strcasecmp(name, "xam.xex") == 0) {
return true;
} else if (strcasecmp(name, "xboxkrnl.exe") == 0) {
return true;
}
return false;
}
XModule* KernelState::GetModule(const char* name) {
if (!name) {
// NULL name = self.
@@ -114,7 +127,7 @@ XModule* KernelState::GetModule(const char* name) {
// Some games request this, for some reason. wtf.
return nullptr;
} else {
std::lock_guard<std::mutex> lock(object_mutex_);
std::lock_guard<std::recursive_mutex> lock(object_mutex_);
for (XUserModule* module : user_modules_) {
if ((strcasecmp(xe::find_name_from_path(module->path()).c_str(), name) ==
@@ -163,7 +176,7 @@ XUserModule* KernelState::LoadUserModule(const char* raw_name) {
XUserModule* module = nullptr;
{
std::lock_guard<std::mutex> lock(object_mutex_);
std::lock_guard<std::recursive_mutex> lock(object_mutex_);
// See if we've already loaded it
for (XUserModule* existing_module : user_modules_) {
@@ -205,12 +218,12 @@ XUserModule* KernelState::LoadUserModule(const char* raw_name) {
}
void KernelState::RegisterThread(XThread* thread) {
std::lock_guard<std::mutex> lock(object_mutex_);
std::lock_guard<std::recursive_mutex> lock(object_mutex_);
threads_by_id_[thread->thread_id()] = thread;
}
void KernelState::UnregisterThread(XThread* thread) {
std::lock_guard<std::mutex> lock(object_mutex_);
std::lock_guard<std::recursive_mutex> lock(object_mutex_);
auto it = threads_by_id_.find(thread->thread_id());
if (it != threads_by_id_.end()) {
threads_by_id_.erase(it);
@@ -218,7 +231,7 @@ void KernelState::UnregisterThread(XThread* thread) {
}
void KernelState::OnThreadExecute(XThread* thread) {
std::lock_guard<std::mutex> lock(object_mutex_);
std::lock_guard<std::recursive_mutex> lock(object_mutex_);
// Must be called on executing thread.
assert_true(XThread::GetCurrentThread() == thread);
@@ -241,7 +254,7 @@ void KernelState::OnThreadExecute(XThread* thread) {
}
void KernelState::OnThreadExit(XThread* thread) {
std::lock_guard<std::mutex> lock(object_mutex_);
std::lock_guard<std::recursive_mutex> lock(object_mutex_);
// Must be called on executing thread.
assert_true(XThread::GetCurrentThread() == thread);
@@ -264,7 +277,7 @@ void KernelState::OnThreadExit(XThread* thread) {
}
XThread* KernelState::GetThreadByID(uint32_t thread_id) {
std::lock_guard<std::mutex> lock(object_mutex_);
std::lock_guard<std::recursive_mutex> lock(object_mutex_);
XThread* thread = nullptr;
auto it = threads_by_id_.find(thread_id);
if (it != threads_by_id_.end()) {
@@ -276,7 +289,7 @@ XThread* KernelState::GetThreadByID(uint32_t thread_id) {
}
void KernelState::RegisterNotifyListener(XNotifyListener* listener) {
std::lock_guard<std::mutex> lock(object_mutex_);
std::lock_guard<std::recursive_mutex> lock(object_mutex_);
notify_listeners_.push_back(listener);
// Games seem to expect a few notifications on startup, only for the first
@@ -300,7 +313,7 @@ void KernelState::RegisterNotifyListener(XNotifyListener* listener) {
}
void KernelState::UnregisterNotifyListener(XNotifyListener* listener) {
std::lock_guard<std::mutex> lock(object_mutex_);
std::lock_guard<std::recursive_mutex> lock(object_mutex_);
for (auto it = notify_listeners_.begin(); it != notify_listeners_.end();
++it) {
if (*it == listener) {
@@ -311,7 +324,7 @@ void KernelState::UnregisterNotifyListener(XNotifyListener* listener) {
}
void KernelState::BroadcastNotification(XNotificationID id, uint32_t data) {
std::lock_guard<std::mutex> lock(object_mutex_);
std::lock_guard<std::recursive_mutex> lock(object_mutex_);
for (auto it = notify_listeners_.begin(); it != notify_listeners_.end();
++it) {
(*it)->EnqueueNotification(id, data);

View File

@@ -63,13 +63,14 @@ class KernelState {
ContentManager* content_manager() const { return content_manager_.get(); }
ObjectTable* object_table() const { return object_table_; }
std::mutex& object_mutex() { return object_mutex_; }
std::recursive_mutex& object_mutex() { return object_mutex_; }
uint32_t process_type() const { return process_type_; }
void set_process_type(uint32_t value) { process_type_ = value; }
void RegisterModule(XModule* module);
void UnregisterModule(XModule* module);
bool IsKernelModule(const char* name);
XModule* GetModule(const char* name);
XUserModule* GetExecutableModule();
void SetExecutableModule(XUserModule* module);
@@ -105,7 +106,7 @@ class KernelState {
std::unique_ptr<ContentManager> content_manager_;
ObjectTable* object_table_;
std::mutex object_mutex_;
std::recursive_mutex object_mutex_;
std::unordered_map<uint32_t, XThread*> threads_by_id_;
std::vector<XNotifyListener*> notify_listeners_;
bool has_notified_startup_;

View File

@@ -34,6 +34,7 @@ XThread::XThread(KernelState* kernel_state, uint32_t stack_size,
: XObject(kernel_state, kTypeThread),
thread_id_(++next_xthread_id),
thread_handle_(0),
pcr_address_(0),
thread_state_address_(0),
thread_state_(0),
event_(NULL),
@@ -76,7 +77,7 @@ XThread::~XThread() {
}
kernel_state()->memory()->SystemHeapFree(scratch_address_);
kernel_state()->memory()->SystemHeapFree(tls_address_);
kernel_state()->memory()->SystemHeapFree(thread_state_address_);
kernel_state()->memory()->SystemHeapFree(pcr_address_);
if (thread_handle_) {
// TODO(benvanik): platform kill
@@ -105,8 +106,8 @@ uint32_t XThread::GetCurrentThreadHandle() {
return thread->handle();
}
uint32_t XThread::GetCurrentThreadId(const uint8_t* thread_state_block) {
return xe::load_and_swap<uint32_t>(thread_state_block + 0x14C);
uint32_t XThread::GetCurrentThreadId(const uint8_t* pcr) {
return xe::load_and_swap<uint32_t>(pcr + 0x2D8 + 0x14C);
}
uint32_t XThread::last_error() {
@@ -137,14 +138,15 @@ X_STATUS XThread::Create() {
// 0x160: last error
// So, at offset 0x100 we have a 4b pointer to offset 200, then have the
// structure.
thread_state_address_ = memory()->SystemHeapAlloc(0xAB0);
pcr_address_ = memory()->SystemHeapAlloc(0x2D8 + 0xAB0);
thread_state_address_ = pcr_address_ + 0x2D8;
if (!thread_state_address_) {
XELOGW("Unable to allocate thread state block");
return X_STATUS_NO_MEMORY;
}
// Set native info.
SetNativePointer(thread_state_address_);
SetNativePointer(thread_state_address_, true);
XUserModule* module = kernel_state()->GetExecutableModule();
@@ -154,8 +156,12 @@ X_STATUS XThread::Create() {
scratch_address_ = memory()->SystemHeapAlloc(scratch_size_);
// Allocate TLS block.
const xe_xex2_header_t* header = module->xex_header();
uint32_t tls_size = header->tls_info.slot_count * header->tls_info.data_size;
uint32_t tls_size = 32; // Default 32 (is this OK?)
if (module && module->xex_header()) {
const xe_xex2_header_t* header = module->xex_header();
tls_size = header->tls_info.slot_count * header->tls_info.data_size;
}
tls_address_ = memory()->SystemHeapAlloc(tls_size);
if (!tls_address_) {
XELOGW("Unable to allocate thread local storage block");
@@ -163,9 +169,40 @@ X_STATUS XThread::Create() {
return X_STATUS_NO_MEMORY;
}
// Copy in default TLS info.
// TODO(benvanik): is this correct?
memory()->Copy(tls_address_, header->tls_info.raw_data_address, tls_size);
// Copy in default TLS info (or zero it out)
if (module && module->xex_header()) {
const xe_xex2_header_t* header = module->xex_header();
// Copy in default TLS info.
// TODO(benvanik): is this correct?
memory()->Copy(tls_address_, header->tls_info.raw_data_address, tls_size);
} else {
memory()->Fill(tls_address_, tls_size, 0);
}
if (module) {
module->Release();
}
// Allocate processor thread state.
// This is thread safe.
thread_state_ = new ThreadState(kernel_state()->processor(), thread_id_,
ThreadStackType::kUserStack, 0,
creation_params_.stack_size, pcr_address_);
XELOGI("XThread%04X (%X) Stack: %.8X-%.8X", handle(),
thread_state_->thread_id(), thread_state_->stack_limit(),
thread_state_->stack_base());
uint8_t* pcr = memory()->TranslateVirtual(pcr_address_);
std::memset(pcr, 0x0, 0x2D8 + 0xAB0); // Zero the PCR
xe::store_and_swap<uint32_t>(pcr + 0x000, tls_address_);
xe::store_and_swap<uint32_t>(pcr + 0x030, pcr_address_);
xe::store_and_swap<uint32_t>(pcr + 0x070, thread_state_->stack_address() +
thread_state_->stack_size());
xe::store_and_swap<uint32_t>(pcr + 0x074, thread_state_->stack_address());
xe::store_and_swap<uint32_t>(pcr + 0x100, thread_state_address_);
xe::store_and_swap<uint8_t> (pcr + 0x10C, 1); // Current CPU(?)
xe::store_and_swap<uint32_t>(pcr + 0x150, 0); // DPC active bool?
// Setup the thread state block (last error/etc).
uint8_t* p = memory()->TranslateVirtual(thread_state_address_);
@@ -180,6 +217,9 @@ X_STATUS XThread::Create() {
xe::store_and_swap<uint32_t>(p + 0x04C, thread_state_address_ + 0x018);
xe::store_and_swap<uint16_t>(p + 0x054, 0x102);
xe::store_and_swap<uint16_t>(p + 0x056, 1);
xe::store_and_swap<uint32_t>(
p + 0x05C, thread_state_->stack_address() + thread_state_->stack_size());
xe::store_and_swap<uint32_t>(p + 0x060, thread_state_->stack_address());
xe::store_and_swap<uint32_t>(p + 0x068, tls_address_);
xe::store_and_swap<uint8_t>(p + 0x06C, 0);
xe::store_and_swap<uint32_t>(p + 0x074, thread_state_address_ + 0x074);
@@ -192,7 +232,8 @@ X_STATUS XThread::Create() {
// A88 = APC
// 18 = timer
xe::store_and_swap<uint32_t>(p + 0x09C, 0xFDFFD7FF);
xe::store_and_swap<uint32_t>(p + 0x100, thread_state_address_);
xe::store_and_swap<uint32_t>(
p + 0x0D0, thread_state_->stack_address() + thread_state_->stack_size());
FILETIME t;
GetSystemTimeAsFileTime(&t);
xe::store_and_swap<uint64_t>(
@@ -200,32 +241,18 @@ X_STATUS XThread::Create() {
xe::store_and_swap<uint32_t>(p + 0x144, thread_state_address_ + 0x144);
xe::store_and_swap<uint32_t>(p + 0x148, thread_state_address_ + 0x144);
xe::store_and_swap<uint32_t>(p + 0x14C, thread_id_);
// TODO(benvanik): figure out why RtlGetLastError changes on this:
// xe::store_and_swap<uint32_t>(p + 0x150, creation_params_.start_address);
xe::store_and_swap<uint32_t>(p + 0x150, creation_params_.start_address);
xe::store_and_swap<uint32_t>(p + 0x154, thread_state_address_ + 0x154);
xe::store_and_swap<uint32_t>(p + 0x158, thread_state_address_ + 0x154);
xe::store_and_swap<uint32_t>(p + 0x160, 0); // last error
xe::store_and_swap<uint32_t>(p + 0x16C, creation_params_.creation_flags);
xe::store_and_swap<uint32_t>(p + 0x17C, 1);
// Allocate processor thread state.
// This is thread safe.
thread_state_ =
new ThreadState(kernel_state()->processor(), thread_id_, 0,
creation_params_.stack_size, thread_state_address_);
xe::store_and_swap<uint32_t>(
p + 0x05C, thread_state_->stack_address() + thread_state_->stack_size());
xe::store_and_swap<uint32_t>(p + 0x060, thread_state_->stack_address());
xe::store_and_swap<uint32_t>(
p + 0x0D0, thread_state_->stack_address() + thread_state_->stack_size());
SetNativePointer(thread_state_address_);
X_STATUS return_code = PlatformCreate();
if (XFAILED(return_code)) {
XELOGW("Unable to create platform thread (%.8X)", return_code);
module->Release();
return return_code;
}
@@ -238,7 +265,6 @@ X_STATUS XThread::Create() {
SetAffinity(proc_mask);
}
module->Release();
return X_STATUS_SUCCESS;
}
@@ -509,7 +535,19 @@ void XThread::RundownAPCs() {
int32_t XThread::QueryPriority() { return GetThreadPriority(thread_handle_); }
void XThread::SetPriority(int32_t increment) {
SetThreadPriority(thread_handle_, increment);
int target_priority = 0;
if (increment > 0x11) {
target_priority = THREAD_PRIORITY_HIGHEST;
} else if (increment > 0) {
target_priority = THREAD_PRIORITY_ABOVE_NORMAL;
} else if (increment < -0x22) {
target_priority = THREAD_PRIORITY_IDLE;
} else if (increment < -0x11) {
target_priority = THREAD_PRIORITY_LOWEST;
} else {
target_priority = THREAD_PRIORITY_NORMAL;
}
SetThreadPriority(thread_handle_, target_priority);
}
void XThread::SetAffinity(uint32_t affinity) {
@@ -583,5 +621,28 @@ X_STATUS XThread::Delay(uint32_t processor_mode, uint32_t alertable,
void* XThread::GetWaitHandle() { return event_->GetWaitHandle(); }
XHostThread::XHostThread(KernelState* kernel_state, uint32_t stack_size,
uint32_t creation_flags, std::function<int()> host_fn):
XThread(kernel_state, stack_size, 0, 0, 0, creation_flags),
host_fn_(host_fn) {
}
void XHostThread::Execute() {
XELOGKERNEL("XThread::Execute thid %d (handle=%.8X, '%s', native=%.8X, <host>)",
thread_id_, handle(), name_.c_str(),
xe::threading::current_thread_id());
// Let the kernel know we are starting.
kernel_state()->OnThreadExecute(this);
int ret = host_fn_();
// Let the kernel know we are exiting.
kernel_state()->OnThreadExit(this);
// Exit.
Exit(ret);
}
} // namespace kernel
} // namespace xe

View File

@@ -33,8 +33,9 @@ class XThread : public XObject {
static XThread* GetCurrentThread();
static uint32_t GetCurrentThreadHandle();
static uint32_t GetCurrentThreadId(const uint8_t* thread_state_block);
static uint32_t GetCurrentThreadId(const uint8_t* pcr);
uint32_t pcr_ptr() const { return pcr_address_; }
uint32_t thread_state_ptr() const { return thread_state_address_; }
cpu::ThreadState* thread_state() const { return thread_state_; }
uint32_t thread_id() const { return thread_id_; }
@@ -46,7 +47,7 @@ class XThread : public XObject {
X_STATUS Create();
X_STATUS Exit(int exit_code);
void Execute();
virtual void Execute();
static void EnterCriticalRegion();
static void LeaveCriticalRegion();
@@ -68,7 +69,7 @@ class XThread : public XObject {
virtual void* GetWaitHandle();
private:
protected:
X_STATUS PlatformCreate();
void PlatformDestroy();
X_STATUS PlatformExit(int exit_code);
@@ -89,6 +90,7 @@ class XThread : public XObject {
uint32_t scratch_address_;
uint32_t scratch_size_;
uint32_t tls_address_;
uint32_t pcr_address_;
uint32_t thread_state_address_;
cpu::ThreadState* thread_state_;
@@ -101,6 +103,17 @@ class XThread : public XObject {
XEvent* event_;
};
class XHostThread : public XThread {
public:
XHostThread(KernelState* kernel_state, uint32_t stack_size,
uint32_t creation_flags, std::function<int()> host_fn);
virtual void Execute();
private:
std::function<int()> host_fn_;
};
} // namespace kernel
} // namespace xe

View File

@@ -129,7 +129,7 @@ X_STATUS XUserModule::LoadFromMemory(const void* addr, const size_t length) {
// Prepare the module for execution.
// Runtime takes ownership.
auto xex_module = std::make_unique<XexModule>(processor);
auto xex_module = std::make_unique<XexModule>(processor, kernel_state());
if (!xex_module->Load(name_, path_, xex_)) {
return X_STATUS_UNSUCCESSFUL;
}
@@ -351,18 +351,38 @@ void XUserModule::Dump() {
int unimpl_count = 0;
for (size_t m = 0; m < import_info_count; m++) {
const xe_xex2_import_info_t* info = &import_infos[m];
KernelExport* kernel_export =
if (kernel_state_->IsKernelModule(library->name)) {
KernelExport* kernel_export =
export_resolver->GetExportByOrdinal(library->name, info->ordinal);
if (kernel_export) {
known_count++;
if (kernel_export->is_implemented) {
impl_count++;
if (kernel_export) {
known_count++;
if (kernel_export->is_implemented) {
impl_count++;
} else {
unimpl_count++;
}
} else {
unknown_count++;
unimpl_count++;
}
} else {
unknown_count++;
unimpl_count++;
// User module
XModule* module = kernel_state_->GetModule(library->name);
if (module) {
uint32_t export_addr =
module->GetProcAddressByOrdinal(info->ordinal);
if (export_addr) {
impl_count++;
known_count++;
} else {
unimpl_count++;
unknown_count++;
}
} else {
unimpl_count++;
unknown_count++;
}
}
}
printf(" Total: %4u\n", uint32_t(import_info_count));
@@ -377,13 +397,23 @@ void XUserModule::Dump() {
// Listing.
for (size_t m = 0; m < import_info_count; m++) {
const xe_xex2_import_info_t* info = &import_infos[m];
KernelExport* kernel_export =
export_resolver->GetExportByOrdinal(library->name, info->ordinal);
const char* name = "UNKNOWN";
bool implemented = false;
if (kernel_export) {
name = kernel_export->name;
implemented = kernel_export->is_implemented;
KernelExport* kernel_export;
if (kernel_state_->IsKernelModule(library->name)) {
kernel_export =
export_resolver->GetExportByOrdinal(library->name, info->ordinal);
if (kernel_export) {
name = kernel_export->name;
implemented = kernel_export->is_implemented;
}
} else {
XModule* module = kernel_state_->GetModule(library->name);
if (module && module->GetProcAddressByOrdinal(info->ordinal)) {
// TODO: Name lookup
implemented = true;
}
}
if (kernel_export && kernel_export->type == KernelExport::Variable) {
printf(" V %.8X %.3X (%3d) %s %s\n", info->value_address,

View File

@@ -536,8 +536,12 @@ int xe_xex2_read_image_uncompressed(const xe_xex2_header_t *header,
// Allocate in-place the XEX memory.
const uint32_t exe_length = xex_length - header->exe_offset;
uint32_t uncompressed_size = exe_length;
uint32_t alloc_result = memory->HeapAlloc(
header->exe_address, uncompressed_size, xe::MEMORY_FLAG_ZERO);
bool alloc_result =
memory->LookupHeap(header->exe_address)
->AllocFixed(
header->exe_address, uncompressed_size, 4096,
xe::kMemoryAllocationReserve | xe::kMemoryAllocationCommit,
xe::kMemoryProtectRead | xe::kMemoryProtectWrite);
if (!alloc_result) {
XELOGE("Unable to allocate XEX memory at %.8X-%.8X.", header->exe_address,
uncompressed_size);
@@ -588,22 +592,26 @@ int xe_xex2_read_image_basic_compressed(const xe_xex2_header_t *header,
// Calculate the total size of the XEX image from its headers.
uint32_t total_size = 0;
for (uint32_t i = 0; i < header->section_count; i++) {
xe_xex2_section_t& section = header->sections[i];
xe_xex2_section_t &section = header->sections[i];
total_size += section.info.page_count * section.page_size;
}
// Allocate in-place the XEX memory.
uint32_t alloc_result = memory->HeapAlloc(
header->exe_address, total_size, xe::MEMORY_FLAG_ZERO);
bool alloc_result =
memory->LookupHeap(header->exe_address)
->AllocFixed(
header->exe_address, total_size, 4096,
xe::kMemoryAllocationReserve | xe::kMemoryAllocationCommit,
xe::kMemoryProtectRead | xe::kMemoryProtectWrite);
if (!alloc_result) {
XELOGE("Unable to allocate XEX memory at %.8X-%.8X.", header->exe_address,
uncompressed_size);
return 1;
}
uint8_t *buffer = memory->TranslateVirtual(header->exe_address);
std::memset(buffer, 0, total_size); // Quickly zero the contents.
uint8_t *d = buffer;
std::memset(buffer, 0, uncompressed_size);
uint32_t rk[4 * (MAXNR + 1)];
uint8_t ivec[16] = {0};
@@ -731,8 +739,12 @@ int xe_xex2_read_image_compressed(const xe_xex2_header_t *header,
}
// Allocate in-place the XEX memory.
uint32_t alloc_result = memory->HeapAlloc(
header->exe_address, uncompressed_size, xe::MEMORY_FLAG_ZERO);
bool alloc_result =
memory->LookupHeap(header->exe_address)
->AllocFixed(
header->exe_address, uncompressed_size, 4096,
xe::kMemoryAllocationReserve | xe::kMemoryAllocationCommit,
xe::kMemoryProtectRead | xe::kMemoryProtectWrite);
if (!alloc_result) {
XELOGE("Unable to allocate XEX memory at %.8X-%.8X.", header->exe_address,
uncompressed_size);
@@ -1084,4 +1096,4 @@ uint32_t xe_xex2_lookup_export(xe_xex2_ref xex, uint16_t ordinal) {
// No match
return 0;
}
}

View File

@@ -41,7 +41,7 @@ SHIM_CALL XGetAVPack_shim(PPCContext* ppc_state, KernelState* state) {
SHIM_CALL XGetGameRegion_shim(PPCContext* ppc_state, KernelState* state) {
XELOGD("XGetGameRegion()");
SHIM_SET_RETURN_64(XEX_REGION_ALL);
SHIM_SET_RETURN_64(0xFFFF);
}
SHIM_CALL XGetLanguage_shim(PPCContext* ppc_state, KernelState* state) {

View File

@@ -81,6 +81,8 @@ XE_EXPORT(xam, 0x00000051, NetDll_XNetReplaceKey,
XE_EXPORT(xam, 0x00000052, NetDll_XNetGetXnAddrPlatform, Function, 0),
XE_EXPORT(xam, 0x00000053, NetDll_XNetGetSystemLinkPort, Function, 0),
XE_EXPORT(xam, 0x00000054, NetDll_XNetSetSystemLinkPort, Function, 0),
XE_EXPORT(xam, 0x00000055, xam_055, Function, 0),
XE_EXPORT(xam, 0x00000056, xam_056, Function, 0),
XE_EXPORT(xam, 0x00000065, NetDll_XnpLoadConfigParams, Function, 0),
XE_EXPORT(xam, 0x00000066, NetDll_XnpSaveConfigParams, Function, 0),
XE_EXPORT(xam, 0x00000067, NetDll_XnpConfigUPnP, Function, 0),
@@ -954,6 +956,7 @@ XE_EXPORT(xam, 0x0000048F, XuiSceneEnableTransitionDependency,
XE_EXPORT(xam, 0x00000490, XamVoiceGetMicArrayAudioEx, Function, 0),
XE_EXPORT(xam, 0x00000491, XamVoiceDisableMicArray, Function, 0),
XE_EXPORT(xam, 0x00000497, XamVoiceIsActiveProcess, Function, 0),
XE_EXPORT(xam, 0x0000049E, XGetVideoCapabilities, Function, 0),
XE_EXPORT(xam, 0x000004B0, XMPRegisterCodec, Function, 0),
XE_EXPORT(xam, 0x00000514, XamIsCurrentTitleIptv, Function, 0),
XE_EXPORT(xam, 0x00000515, XamIsIptvEnabled, Function, 0),

View File

@@ -108,10 +108,27 @@ SHIM_CALL XamShowMessageBoxUI_shim(PPCContext* ppc_state, KernelState* state) {
SHIM_SET_RETURN_32(X_ERROR_IO_PENDING);
}
SHIM_CALL XamShowDirtyDiscErrorUI_shim(PPCContext* ppc_state,
KernelState* state) {
uint32_t user_index = SHIM_GET_ARG_32(0);
XELOGD("XamShowDirtyDiscErrorUI(%d)", user_index);
int button_pressed = 0;
TaskDialog(state->emulator()->main_window()->hwnd(), GetModuleHandle(nullptr),
L"Disc Read Error",
L"Game is claiming to be unable to read game data!", nullptr,
TDCBF_CLOSE_BUTTON, TD_ERROR_ICON, &button_pressed);
// This is death, and should never return.
assert_always();
}
} // namespace kernel
} // namespace xe
void xe::kernel::xam::RegisterUIExports(
xe::cpu::ExportResolver* export_resolver, KernelState* state) {
SHIM_SET_MAPPING("xam.xex", XamShowMessageBoxUI, state);
SHIM_SET_MAPPING("xam.xex", XamShowDirtyDiscErrorUI, state);
}

View File

@@ -7,6 +7,7 @@
******************************************************************************
*/
#include "xenia/base/logging.h"
#include "xenia/kernel/kernel_state.h"
#include "xenia/kernel/util/shim_utils.h"
#include "xenia/kernel/xam_private.h"
@@ -20,13 +21,22 @@ void xeVdQueryVideoMode(X_VIDEO_MODE* video_mode);
SHIM_CALL XGetVideoMode_shim(PPCContext* ppc_state, KernelState* state) {
uint32_t video_mode_ptr = SHIM_GET_ARG_32(0);
X_VIDEO_MODE* video_mode = (X_VIDEO_MODE*)SHIM_MEM_ADDR(video_mode_ptr);
XELOGD("XGetVideoMode(%.8X)", video_mode_ptr);
xeVdQueryVideoMode(video_mode);
}
SHIM_CALL XGetVideoCapabilities_shim(PPCContext* ppc_state, KernelState* state) {
XELOGD("XGetVideoCapabilities()");
SHIM_SET_RETURN_32(0);
}
} // namespace kernel
} // namespace xe
void xe::kernel::xam::RegisterVideoExports(
xe::cpu::ExportResolver* export_resolver, KernelState* state) {
SHIM_SET_MAPPING("xam.xex", XGetVideoCapabilities, state);
SHIM_SET_MAPPING("xam.xex", XGetVideoMode, state);
}

View File

@@ -60,10 +60,13 @@ struct FileDisposition {
};
struct FileAccess {
static const uint32_t X_GENERIC_READ = 1 << 0;
static const uint32_t X_GENERIC_WRITE = 1 << 1;
static const uint32_t X_GENERIC_EXECUTE = 1 << 2;
static const uint32_t X_GENERIC_ALL = 1 << 3;
static const uint32_t X_GENERIC_READ = 0x80000000;
static const uint32_t X_GENERIC_WRITE = 0x40000000;
static const uint32_t X_GENERIC_EXECUTE = 0x20000000;
static const uint32_t X_GENERIC_ALL = 0x10000000;
static const uint32_t X_FILE_READ_DATA = 0x00000001;
static const uint32_t X_FILE_WRITE_DATA = 0x00000002;
static const uint32_t X_FILE_APPEND_DATA = 0x00000004;
};
X_STATUS NtCreateFile(PPCContext* ppc_state, KernelState* state,
@@ -100,9 +103,11 @@ X_STATUS NtCreateFile(PPCContext* ppc_state, KernelState* state,
entry = fs->ResolvePath(object_name);
}
if (creation_disposition != FileDisposition::X_FILE_OPEN ||
desired_access & FileAccess::X_GENERIC_WRITE ||
desired_access & FileAccess::X_GENERIC_ALL) {
bool wants_write = desired_access & FileAccess::X_GENERIC_WRITE ||
desired_access & FileAccess::X_GENERIC_ALL ||
desired_access & FileAccess::X_FILE_WRITE_DATA ||
desired_access & FileAccess::X_FILE_APPEND_DATA;
if (wants_write) {
if (entry && entry->is_read_only()) {
// We don't support any write modes.
XELOGW("Attempted to open the file/dir for create/write");
@@ -116,10 +121,15 @@ X_STATUS NtCreateFile(PPCContext* ppc_state, KernelState* state,
info = X_FILE_DOES_NOT_EXIST;
} else {
// Open the file/directory.
result = fs->Open(std::move(entry), state,
desired_access & FileAccess::X_GENERIC_WRITE
? fs::Mode::READ_WRITE
: fs::Mode::READ,
fs::Mode mode;
if (desired_access & FileAccess::X_FILE_APPEND_DATA) {
mode = fs::Mode::READ_APPEND;
} else if (wants_write) {
mode = fs::Mode::READ_WRITE;
} else {
mode = fs::Mode::READ;
}
result = fs->Open(std::move(entry), state, mode,
false, // TODO(benvanik): pick async mode, if needed.
&file);
}

View File

@@ -17,19 +17,55 @@
namespace xe {
namespace kernel {
uint32_t ToXdkProtectFlags(uint32_t protect) {
uint32_t result = 0;
if (!(protect & kMemoryProtectRead) && !(protect & kMemoryProtectWrite)) {
result = X_PAGE_NOACCESS;
} else if ((protect & kMemoryProtectRead) &&
!(protect & kMemoryProtectWrite)) {
result = X_PAGE_READONLY;
} else {
result = X_PAGE_READWRITE;
}
if (protect & kMemoryProtectNoCache) {
result = X_PAGE_NOCACHE;
}
if (protect & kMemoryProtectWriteCombine) {
result = X_PAGE_WRITECOMBINE;
}
return result;
}
uint32_t FromXdkProtectFlags(uint32_t protect) {
uint32_t result = 0;
if ((protect & X_PAGE_READONLY) | (protect & X_PAGE_EXECUTE_READ)) {
result |= kMemoryProtectRead;
} else if ((protect & X_PAGE_READWRITE) |
(protect & X_PAGE_EXECUTE_READWRITE)) {
result |= kMemoryProtectRead | kMemoryProtectWrite;
}
if (protect & X_PAGE_NOCACHE) {
result |= kMemoryProtectNoCache;
}
if (protect & X_PAGE_WRITECOMBINE) {
result |= kMemoryProtectWriteCombine;
}
return result;
}
SHIM_CALL NtAllocateVirtualMemory_shim(PPCContext* ppc_state,
KernelState* state) {
uint32_t base_addr_ptr = SHIM_GET_ARG_32(0);
uint32_t base_addr_value = SHIM_MEM_32(base_addr_ptr);
uint32_t region_size_ptr = SHIM_GET_ARG_32(1);
uint32_t region_size_value = SHIM_MEM_32(region_size_ptr);
uint32_t allocation_type = SHIM_GET_ARG_32(2); // X_MEM_* bitmask
uint32_t protect_bits = SHIM_GET_ARG_32(3); // X_PAGE_* bitmask
uint32_t alloc_type = SHIM_GET_ARG_32(2); // X_MEM_* bitmask
uint32_t protect_bits = SHIM_GET_ARG_32(3); // X_PAGE_* bitmask
uint32_t unknown = SHIM_GET_ARG_32(4);
XELOGD("NtAllocateVirtualMemory(%.8X(%.8X), %.8X(%.8X), %.8X, %.8X, %.8X)",
base_addr_ptr, base_addr_value, region_size_ptr, region_size_value,
allocation_type, protect_bits, unknown);
alloc_type, protect_bits, unknown);
// NTSTATUS
// _Inout_ PVOID *BaseAddress,
@@ -52,12 +88,12 @@ SHIM_CALL NtAllocateVirtualMemory_shim(PPCContext* ppc_state,
return;
}
// Check allocation type.
if (!(allocation_type & (X_MEM_COMMIT | X_MEM_RESET | X_MEM_RESERVE))) {
if (!(alloc_type & (X_MEM_COMMIT | X_MEM_RESET | X_MEM_RESERVE))) {
SHIM_SET_RETURN_32(X_STATUS_INVALID_PARAMETER);
return;
}
// If MEM_RESET is set only MEM_RESET can be set.
if (allocation_type & X_MEM_RESET && (allocation_type & ~X_MEM_RESET)) {
if (alloc_type & X_MEM_RESET && (alloc_type & ~X_MEM_RESET)) {
SHIM_SET_RETURN_32(X_STATUS_INVALID_PARAMETER);
return;
}
@@ -68,37 +104,60 @@ SHIM_CALL NtAllocateVirtualMemory_shim(PPCContext* ppc_state,
}
// Adjust size.
uint32_t adjusted_size = region_size_value;
// TODO(benvanik): adjust based on page size flags/etc?
// TODO(benvanik): support different allocation types.
// Right now we treat everything as a commit and ignore allocations that have
// already happened.
if (base_addr_value) {
// Having a pointer already means that this is likely a follow-on COMMIT.
assert_true(!(allocation_type & X_MEM_RESERVE) &&
(allocation_type & X_MEM_COMMIT));
SHIM_SET_MEM_32(base_addr_ptr, base_addr_value);
SHIM_SET_MEM_32(region_size_ptr, adjusted_size);
SHIM_SET_RETURN_32(X_STATUS_SUCCESS);
return;
uint32_t page_size = 4096;
if (alloc_type & X_MEM_LARGE_PAGES) {
page_size = 64 * 1024;
}
if (int32_t(region_size_value) < 0) {
// Some games pass in negative sizes.
region_size_value = -int32_t(region_size_value);
}
uint32_t adjusted_size = xe::round_up(region_size_value, page_size);
// Allocate.
uint32_t flags = (allocation_type & X_MEM_NOZERO) ? 0 : MEMORY_FLAG_ZERO;
uint32_t addr = (uint32_t)state->memory()->HeapAlloc(base_addr_value,
adjusted_size, flags);
if (!addr) {
uint32_t allocation_type = 0;
if (alloc_type & X_MEM_RESERVE) {
allocation_type |= kMemoryAllocationReserve;
}
if (alloc_type & X_MEM_COMMIT) {
allocation_type |= kMemoryAllocationCommit;
}
if (alloc_type & X_MEM_RESET) {
XELOGE("X_MEM_RESET not implemented");
assert_always();
}
uint32_t protect = FromXdkProtectFlags(protect_bits);
uint32_t address = 0;
if (base_addr_value) {
auto heap = state->memory()->LookupHeap(base_addr_value);
if (heap->AllocFixed(base_addr_value, adjusted_size, page_size,
allocation_type, protect)) {
address = base_addr_value;
}
} else {
bool top_down = !!(alloc_type & X_MEM_TOP_DOWN);
auto heap = state->memory()->LookupHeapByType(false, page_size);
heap->Alloc(adjusted_size, page_size, allocation_type, protect, top_down,
&address);
}
if (!address) {
// Failed - assume no memory available.
SHIM_SET_RETURN_32(X_STATUS_NO_MEMORY);
return;
}
XELOGD("NtAllocateVirtualMemory = %.8X", addr);
// Zero memory, if needed.
if (address && !(alloc_type & X_MEM_NOZERO)) {
if (alloc_type & X_MEM_COMMIT) {
state->memory()->Zero(address, adjusted_size);
}
}
XELOGD("NtAllocateVirtualMemory = %.8X", address);
// Stash back.
// Maybe set X_STATUS_ALREADY_COMMITTED if MEM_COMMIT?
SHIM_SET_MEM_32(base_addr_ptr, addr);
SHIM_SET_MEM_32(base_addr_ptr, address);
SHIM_SET_MEM_32(region_size_ptr, adjusted_size);
SHIM_SET_RETURN_32(X_STATUS_SUCCESS);
}
@@ -130,22 +189,24 @@ SHIM_CALL NtFreeVirtualMemory_shim(PPCContext* ppc_state, KernelState* state) {
return;
}
// TODO(benvanik): ignore decommits for now.
auto heap = state->memory()->LookupHeap(base_addr_value);
bool result = false;
if (free_type == X_MEM_DECOMMIT) {
SHIM_SET_RETURN_32(X_STATUS_SUCCESS);
return;
}
// If zero, we may need to query size (free whole region).
assert_not_zero(region_size_value);
// Free.
uint32_t flags = 0;
uint32_t freed_size = state->memory()->HeapFree(base_addr_value, flags);
if (!freed_size) {
region_size_value = xe::round_up(region_size_value, heap->page_size());
result = heap->Decommit(base_addr_value, region_size_value);
} else {
result = heap->Release(base_addr_value, &region_size_value);
}
if (!result) {
SHIM_SET_RETURN_32(X_STATUS_UNSUCCESSFUL);
return;
}
SHIM_SET_MEM_32(base_addr_ptr, base_addr_value);
SHIM_SET_MEM_32(region_size_ptr, freed_size);
SHIM_SET_MEM_32(region_size_ptr, region_size_value);
SHIM_SET_RETURN_32(X_STATUS_SUCCESS);
}
@@ -168,9 +229,9 @@ SHIM_CALL NtQueryVirtualMemory_shim(PPCContext* ppc_state, KernelState* state) {
XELOGD("NtQueryVirtualMemory(%.8X, %.8X)", base_address,
memory_basic_information_ptr);
AllocationInfo alloc_info;
size_t result = state->memory()->QueryInformation(base_address, &alloc_info);
if (!result) {
auto heap = state->memory()->LookupHeap(base_address);
HeapAllocationInfo alloc_info;
if (!heap->QueryRegionInfo(base_address, &alloc_info)) {
SHIM_SET_RETURN_32(X_STATUS_INVALID_PARAMETER);
return;
}
@@ -179,15 +240,21 @@ SHIM_CALL NtQueryVirtualMemory_shim(PPCContext* ppc_state, KernelState* state) {
static_cast<uint32_t>(alloc_info.base_address);
memory_basic_information->allocation_base =
static_cast<uint32_t>(alloc_info.allocation_base);
memory_basic_information->allocation_protect = alloc_info.allocation_protect;
memory_basic_information->allocation_protect =
ToXdkProtectFlags(alloc_info.allocation_protect);
memory_basic_information->region_size =
static_cast<uint32_t>(alloc_info.region_size);
memory_basic_information->state = alloc_info.state;
memory_basic_information->protect = alloc_info.protect;
uint32_t x_state = 0;
if (alloc_info.state & kMemoryAllocationReserve) {
x_state |= X_MEM_RESERVE;
}
if (alloc_info.state & kMemoryAllocationCommit) {
x_state |= X_MEM_COMMIT;
}
memory_basic_information->state = x_state;
memory_basic_information->protect = ToXdkProtectFlags(alloc_info.protect);
memory_basic_information->type = alloc_info.type;
XELOGE("NtQueryVirtualMemory NOT IMPLEMENTED");
SHIM_SET_RETURN_32(X_STATUS_SUCCESS);
}
@@ -242,27 +309,20 @@ SHIM_CALL MmAllocatePhysicalMemoryEx_shim(PPCContext* ppc_state,
assert_true(min_addr_range == 0);
assert_true(max_addr_range == 0xFFFFFFFF);
// Allocate.
uint32_t flags = MEMORY_FLAG_PHYSICAL;
uint32_t base_address = (uint32_t)state->memory()->HeapAlloc(
0, adjusted_size, flags, adjusted_alignment);
if (!base_address) {
uint32_t allocation_type = kMemoryAllocationReserve | kMemoryAllocationCommit;
uint32_t protect = FromXdkProtectFlags(protect_bits);
bool top_down = true;
auto heap = state->memory()->LookupHeapByType(true, page_size);
uint32_t base_address;
if (!heap->AllocRange(min_addr_range, max_addr_range, adjusted_size,
adjusted_alignment, allocation_type, protect, top_down,
&base_address)) {
// Failed - assume no memory available.
SHIM_SET_RETURN_32(0);
return;
}
XELOGD("MmAllocatePhysicalMemoryEx = %.8X", base_address);
// Move the address into the right range.
// if (protect_bits & X_MEM_LARGE_PAGES) {
// base_address += 0xA0000000;
//} else if (protect_bits & X_MEM_16MB_PAGES) {
// base_address += 0xC0000000;
//} else {
// base_address += 0xE0000000;
//}
base_address += 0xA0000000;
SHIM_SET_RETURN_64(base_address);
}
@@ -274,14 +334,10 @@ SHIM_CALL MmFreePhysicalMemory_shim(PPCContext* ppc_state, KernelState* state) {
// base_address = result of MmAllocatePhysicalMemory.
// Strip off physical bits before passing down.
base_address &= ~0xE0000000;
assert_true((base_address & 0x1F) == 0);
// TODO(benvanik): free memory.
XELOGE("xeMmFreePhysicalMemory NOT IMPLEMENTED");
// uint32_t size = ?;
// xe_memory_heap_free(
// state->memory(), base_address, size);
auto heap = state->memory()->LookupHeap(base_address);
heap->Release(base_address);
}
SHIM_CALL MmQueryAddressProtect_shim(PPCContext* ppc_state,
@@ -290,7 +346,12 @@ SHIM_CALL MmQueryAddressProtect_shim(PPCContext* ppc_state,
XELOGD("MmQueryAddressProtect(%.8X)", base_address);
uint32_t access = state->memory()->QueryProtect(base_address);
auto heap = state->memory()->LookupHeap(base_address);
uint32_t access;
if (!heap->QueryProtect(base_address, &access)) {
access = 0;
}
access = ToXdkProtectFlags(access);
SHIM_SET_RETURN_32(access);
}
@@ -301,9 +362,13 @@ SHIM_CALL MmQueryAllocationSize_shim(PPCContext* ppc_state,
XELOGD("MmQueryAllocationSize(%.8X)", base_address);
size_t size = state->memory()->QuerySize(base_address);
auto heap = state->memory()->LookupHeap(base_address);
uint32_t size;
if (!heap->QuerySize(base_address, &size)) {
size = 0;
}
SHIM_SET_RETURN_32(static_cast<uint32_t>(size));
SHIM_SET_RETURN_32(size);
}
SHIM_CALL MmQueryStatistics_shim(PPCContext* ppc_state, KernelState* state) {
@@ -372,19 +437,12 @@ SHIM_CALL MmGetPhysicalAddress_shim(PPCContext* ppc_state, KernelState* state) {
// );
// base_address = result of MmAllocatePhysicalMemory.
// We are always using virtual addresses, right now, since we don't need
// physical ones. We could munge up the address here to another mapped view
// of memory.
uint32_t physical_address = base_address & 0x1FFFFFFF;
if (base_address >= 0xE0000000) {
physical_address += 0x1000;
}
/*if (protect_bits & X_MEM_LARGE_PAGES) {
base_address |= 0xA0000000;
} else if (protect_bits & X_MEM_16MB_PAGES) {
base_address |= 0xC0000000;
} else {
base_address |= 0xE0000000;
}*/
SHIM_SET_RETURN_64(base_address);
SHIM_SET_RETURN_64(physical_address);
}
SHIM_CALL MmMapIoSpace_shim(PPCContext* ppc_state, KernelState* state) {

View File

@@ -83,6 +83,11 @@ SHIM_CALL ObReferenceObjectByHandle_shim(PPCContext* ppc_state,
} break;
}
} break;
case 0xD017BEEF: { // ExSemaphoreObjectType
// TODO(benvanik): implement.
assert_unhandled_case(object_type_ptr);
native_ptr = 0xDEADF00D;
} break;
case 0xD01BBEEF: { // ExThreadObjectType
XThread* thread = (XThread*)object;
native_ptr = thread->thread_state_ptr();

View File

@@ -522,8 +522,8 @@ SHIM_CALL RtlEnterCriticalSection_shim(PPCContext* ppc_state,
// XELOGD("RtlEnterCriticalSection(%.8X)", cs_ptr);
const uint8_t* thread_state_block = SHIM_MEM_ADDR(ppc_state->r[13]);
uint32_t thread_id = XThread::GetCurrentThreadId(thread_state_block);
const uint8_t* pcr = SHIM_MEM_ADDR(ppc_state->r[13]);
uint32_t thread_id = XThread::GetCurrentThreadId(pcr);
auto cs = (X_RTL_CRITICAL_SECTION*)SHIM_MEM_ADDR(cs_ptr);
@@ -564,8 +564,8 @@ SHIM_CALL RtlTryEnterCriticalSection_shim(PPCContext* ppc_state,
// XELOGD("RtlTryEnterCriticalSection(%.8X)", cs_ptr);
const uint8_t* thread_state_block = SHIM_MEM_ADDR(ppc_state->r[13]);
uint32_t thread_id = XThread::GetCurrentThreadId(thread_state_block);
const uint8_t* pcr = SHIM_MEM_ADDR(ppc_state->r[13]);
uint32_t thread_id = XThread::GetCurrentThreadId(pcr);
auto cs = (X_RTL_CRITICAL_SECTION*)SHIM_MEM_ADDR(cs_ptr);

View File

@@ -64,6 +64,9 @@ void AssertNoNameCollision(KernelState* state, uint32_t obj_attributes_ptr) {
// with a success of NAME_EXISTS.
// If the name exists and its type doesn't match, we do NAME_COLLISION.
// Otherwise, we add like normal.
if (!obj_attributes_ptr) {
return;
}
uint32_t name_str_ptr = xe::load_and_swap<uint32_t>(
state->memory()->TranslateVirtual(obj_attributes_ptr + 4));
if (name_str_ptr) {
@@ -460,9 +463,7 @@ SHIM_CALL NtCreateEvent_shim(PPCContext* ppc_state, KernelState* state) {
// TODO(benvanik): check for name collision. May return existing object if
// type matches.
if (obj_attributes_ptr) {
AssertNoNameCollision(state, obj_attributes_ptr);
}
AssertNoNameCollision(state, obj_attributes_ptr);
XEvent* ev = new XEvent(state);
ev->Initialize(!event_type, !!initial_state);
@@ -1304,6 +1305,35 @@ SHIM_CALL KeRemoveQueueDpc_shim(PPCContext* ppc_state, KernelState* state) {
SHIM_SET_RETURN_64(result ? 1 : 0);
}
std::mutex global_list_mutex_;
// http://www.nirsoft.net/kernel_struct/vista/SLIST_HEADER.html
SHIM_CALL InterlockedPopEntrySList_shim(PPCContext* ppc_state,
KernelState* state) {
uint32_t plist_ptr = SHIM_GET_ARG_32(0);
XELOGD("InterlockedPopEntrySList(%.8X)", plist_ptr);
std::lock_guard<std::mutex> lock(global_list_mutex_);
uint8_t* p = state->memory()->TranslateVirtual(plist_ptr);
auto first = xe::load_and_swap<uint32_t>(p);
if (first == 0) {
// List empty!
SHIM_SET_RETURN_32(0);
return;
}
uint8_t* p2 = state->memory()->TranslateVirtual(first);
auto second = xe::load_and_swap<uint32_t>(p2);
// Now drop the first element
xe::store_and_swap<uint32_t>(p, second);
// Return the one we popped
SHIM_SET_RETURN_32(first);
}
} // namespace kernel
} // namespace xe
@@ -1379,4 +1409,6 @@ void xe::kernel::xboxkrnl::RegisterThreadingExports(
SHIM_SET_MAPPING("xboxkrnl.exe", KeInitializeDpc, state);
SHIM_SET_MAPPING("xboxkrnl.exe", KeInsertQueueDpc, state);
SHIM_SET_MAPPING("xboxkrnl.exe", KeRemoveQueueDpc, state);
SHIM_SET_MAPPING("xboxkrnl.exe", InterlockedPopEntrySList, state);
}

View File

@@ -380,6 +380,11 @@ SHIM_CALL VdPersistDisplay_shim(PPCContext* ppc_state, KernelState* state) {
// unk1_ptr needs to be populated with a pointer passed to
// MmFreePhysicalMemory(1, *unk1_ptr).
auto heap = state->memory()->LookupHeapByType(true, 16 * 1024);
uint32_t unk1_value;
heap->Alloc(64, 32, kMemoryAllocationReserve | kMemoryAllocationCommit,
kMemoryProtectNoAccess, false, &unk1_value);
SHIM_SET_MEM_32(unk1_ptr, unk1_value);
// ?
SHIM_SET_RETURN_64(1);

View File

@@ -113,6 +113,7 @@ X_STATUS XObject::Wait(uint32_t wait_reason, uint32_t processor_mode,
// Or X_STATUS_ALERTED?
return X_STATUS_USER_APC;
case WAIT_TIMEOUT:
YieldProcessor();
return X_STATUS_TIMEOUT;
default:
case WAIT_FAILED:
@@ -151,13 +152,16 @@ X_STATUS XObject::WaitMultiple(uint32_t count, XObject** objects,
return result;
}
void XObject::SetNativePointer(uint32_t native_ptr) {
std::lock_guard<std::mutex> lock(kernel_state_->object_mutex());
void XObject::SetNativePointer(uint32_t native_ptr, bool uninitialized) {
std::lock_guard<std::recursive_mutex> lock(kernel_state_->object_mutex());
auto header =
kernel_state_->memory()->TranslateVirtual<DISPATCH_HEADER*>(native_ptr);
assert_true(!(header->wait_list_blink & 0x1));
// Memory uninitialized, so don't bother with the check.
if (!uninitialized) {
assert_true(!(header->wait_list_blink & 0x1));
}
// Stash pointer in struct.
uint64_t object_ptr = reinterpret_cast<uint64_t>(this);
@@ -177,7 +181,7 @@ XObject* XObject::GetObject(KernelState* kernel_state, void* native_ptr,
// We identify this by checking the low bit of wait_list_blink - if it's 1,
// we have already put our pointer in there.
std::lock_guard<std::mutex> lock(kernel_state->object_mutex());
std::lock_guard<std::recursive_mutex> lock(kernel_state->object_mutex());
auto header = reinterpret_cast<DISPATCH_HEADER*>(native_ptr);

View File

@@ -78,7 +78,7 @@ class XObject {
virtual void* GetWaitHandle() { return 0; }
protected:
void SetNativePointer(uint32_t native_ptr);
void SetNativePointer(uint32_t native_ptr, bool uninitialized = false);
static uint32_t TimeoutTicksToMs(int64_t timeout_ticks);