Merge pull request #328 from DrChat/xam_loader
Implement XamLoaderLaunchTitle/XamLoaderTerminateTitle
This commit is contained in:
commit
b09ab1f886
|
@ -43,7 +43,8 @@ XexModule::XexModule(Processor* processor, KernelState* kernel_state)
|
|||
xex_(nullptr),
|
||||
base_address_(0),
|
||||
low_address_(0),
|
||||
high_address_(0) {}
|
||||
high_address_(0),
|
||||
loaded_(false) {}
|
||||
|
||||
XexModule::~XexModule() { xe_xex2_dealloc(xex_); }
|
||||
|
||||
|
@ -80,7 +81,7 @@ bool XexModule::GetOptHeader(const xex2_header* header, xe_xex2_header_keys key,
|
|||
}
|
||||
|
||||
bool XexModule::GetOptHeader(xe_xex2_header_keys key, void** out_ptr) const {
|
||||
return XexModule::GetOptHeader(xex_header_, key, out_ptr);
|
||||
return XexModule::GetOptHeader(xex_header(), key, out_ptr);
|
||||
}
|
||||
|
||||
const xex2_security_info* XexModule::GetSecurityInfo(
|
||||
|
@ -198,17 +199,20 @@ bool XexModule::Load(const std::string& name, const std::string& path,
|
|||
|
||||
// Make a copy of the xex header.
|
||||
auto src_header = reinterpret_cast<const xex2_header*>(xex_addr);
|
||||
xex_header_ = (xex2_header*)new char[src_header->header_size];
|
||||
xex_header_mem_.resize(src_header->header_size);
|
||||
|
||||
std::memcpy(xex_header_, src_header, src_header->header_size);
|
||||
std::memcpy(xex_header_mem_.data(), src_header, src_header->header_size);
|
||||
|
||||
return Load(name, path, xex_);
|
||||
}
|
||||
|
||||
bool XexModule::Load(const std::string& name, const std::string& path,
|
||||
xe_xex2_ref xex) {
|
||||
assert_false(loaded_);
|
||||
loaded_ = true;
|
||||
xex_ = xex;
|
||||
auto header = xex_header_;
|
||||
|
||||
auto header = xex_header();
|
||||
auto old_header = xe_xex2_get_header(xex_);
|
||||
|
||||
// Setup debug info.
|
||||
|
@ -287,6 +291,23 @@ bool XexModule::Load(const std::string& name, const std::string& path,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool XexModule::Unload() {
|
||||
if (!loaded_) {
|
||||
return true;
|
||||
}
|
||||
loaded_ = false;
|
||||
|
||||
// Just deallocate the memory occupied by the exe
|
||||
xe::be<uint32_t>* exe_address = 0;
|
||||
GetOptHeader(XEX_HEADER_IMAGE_BASE_ADDRESS, &exe_address);
|
||||
assert_not_zero(exe_address);
|
||||
|
||||
memory()->LookupHeap(*exe_address)->Release(*exe_address);
|
||||
xex_header_mem_.resize(0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool XexModule::SetupLibraryImports(const char* name,
|
||||
const xex2_import_library* library) {
|
||||
ExportResolver* kernel_resolver = nullptr;
|
||||
|
|
|
@ -33,9 +33,12 @@ class XexModule : public xe::cpu::Module {
|
|||
virtual ~XexModule();
|
||||
|
||||
xe_xex2_ref xex() const { return xex_; }
|
||||
const xex2_header* xex_header() const { return xex_header_; }
|
||||
bool loaded() const { return loaded_; }
|
||||
const xex2_header* xex_header() const {
|
||||
return reinterpret_cast<const xex2_header*>(xex_header_mem_.data());
|
||||
}
|
||||
const xex2_security_info* xex_security_info() const {
|
||||
return GetSecurityInfo(xex_header_);
|
||||
return GetSecurityInfo(xex_header());
|
||||
}
|
||||
|
||||
// Gets an optional header. Returns NULL if not found.
|
||||
|
@ -68,6 +71,7 @@ class XexModule : public xe::cpu::Module {
|
|||
bool Load(const std::string& name, const std::string& path,
|
||||
const void* xex_addr, size_t xex_length);
|
||||
bool Load(const std::string& name, const std::string& path, xe_xex2_ref xex);
|
||||
bool Unload();
|
||||
|
||||
const std::string& name() const override { return name_; }
|
||||
|
||||
|
@ -84,7 +88,8 @@ class XexModule : public xe::cpu::Module {
|
|||
std::string name_;
|
||||
std::string path_;
|
||||
xe_xex2_ref xex_;
|
||||
xex2_header* xex_header_;
|
||||
std::vector<uint8_t> xex_header_mem_; // Holds the xex header
|
||||
bool loaded_; // Loaded into memory?
|
||||
|
||||
uint32_t base_address_;
|
||||
uint32_t low_address_;
|
||||
|
|
|
@ -58,7 +58,8 @@ Breakpoint::~Breakpoint() = default;
|
|||
Debugger::Debugger(Emulator* emulator)
|
||||
: emulator_(emulator),
|
||||
listen_socket_(INVALID_SOCKET),
|
||||
client_socket_(INVALID_SOCKET) {
|
||||
client_socket_(INVALID_SOCKET),
|
||||
accept_thread_running_(false) {
|
||||
WSADATA wsa_data;
|
||||
WSAStartup(MAKEWORD(2, 2), &wsa_data);
|
||||
}
|
||||
|
@ -134,67 +135,70 @@ void SendResponse(SOCKET client_socket, flatbuffers::FlatBufferBuilder& fbb,
|
|||
}
|
||||
|
||||
void Debugger::PreLaunch() {
|
||||
accept_thread_ = std::thread([this]() {
|
||||
xe::threading::set_name("Debugger Server");
|
||||
if (!accept_thread_running_) {
|
||||
accept_thread_running_ = true;
|
||||
accept_thread_ = std::thread([this]() {
|
||||
xe::threading::set_name("Debugger Server");
|
||||
|
||||
while (listen_socket_ != INVALID_SOCKET) {
|
||||
sockaddr_in6 client_addr;
|
||||
int client_count = sizeof(client_addr);
|
||||
SOCKET client_socket_id =
|
||||
accept(listen_socket_, reinterpret_cast<sockaddr*>(&client_addr),
|
||||
&client_count);
|
||||
if (client_socket_id == INVALID_SOCKET) {
|
||||
XELOGE("Failed to accept socket");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only one debugger at a time.
|
||||
if (client_socket_ != INVALID_SOCKET) {
|
||||
XELOGW("Ignoring debugger connection as one is already connected");
|
||||
closesocket(client_socket_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Setup recv thread.
|
||||
client_socket_ = client_socket_id;
|
||||
receive_thread_ = std::thread([this]() {
|
||||
xe::threading::set_name("Debugger Connection");
|
||||
|
||||
while (client_socket_ != INVALID_SOCKET) {
|
||||
// Read length prefix.
|
||||
uint32_t length = 0;
|
||||
int r = recv(client_socket_, reinterpret_cast<char*>(&length), 4,
|
||||
MSG_WAITALL);
|
||||
if (r != 4) {
|
||||
// Failed?
|
||||
XELOGE("Failed to recv debug data length - dead connection?");
|
||||
if (FLAGS_exit_with_debugger) {
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Read body.
|
||||
std::vector<uint8_t> body(length);
|
||||
r = recv(client_socket_, reinterpret_cast<char*>(body.data()), length,
|
||||
MSG_WAITALL);
|
||||
if (r != length) {
|
||||
// Failed?
|
||||
XELOGE("Failed to recv debug data body - dead connection?");
|
||||
if (FLAGS_exit_with_debugger) {
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Read message contents and dispatch.
|
||||
OnMessage(std::move(body));
|
||||
while (listen_socket_ != INVALID_SOCKET) {
|
||||
sockaddr_in6 client_addr;
|
||||
int client_count = sizeof(client_addr);
|
||||
SOCKET client_socket_id =
|
||||
accept(listen_socket_, reinterpret_cast<sockaddr*>(&client_addr),
|
||||
&client_count);
|
||||
if (client_socket_id == INVALID_SOCKET) {
|
||||
XELOGE("Failed to accept socket");
|
||||
continue;
|
||||
}
|
||||
});
|
||||
|
||||
// This will WaitForClient if it was waiting.
|
||||
}
|
||||
});
|
||||
// Only one debugger at a time.
|
||||
if (client_socket_ != INVALID_SOCKET) {
|
||||
XELOGW("Ignoring debugger connection as one is already connected");
|
||||
closesocket(client_socket_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Setup recv thread.
|
||||
client_socket_ = client_socket_id;
|
||||
receive_thread_ = std::thread([this]() {
|
||||
xe::threading::set_name("Debugger Connection");
|
||||
|
||||
while (client_socket_ != INVALID_SOCKET) {
|
||||
// Read length prefix.
|
||||
uint32_t length = 0;
|
||||
int r = recv(client_socket_, reinterpret_cast<char*>(&length), 4,
|
||||
MSG_WAITALL);
|
||||
if (r != 4) {
|
||||
// Failed?
|
||||
XELOGE("Failed to recv debug data length - dead connection?");
|
||||
if (FLAGS_exit_with_debugger) {
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Read body.
|
||||
std::vector<uint8_t> body(length);
|
||||
r = recv(client_socket_, reinterpret_cast<char*>(body.data()),
|
||||
length, MSG_WAITALL);
|
||||
if (r != length) {
|
||||
// Failed?
|
||||
XELOGE("Failed to recv debug data body - dead connection?");
|
||||
if (FLAGS_exit_with_debugger) {
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Read message contents and dispatch.
|
||||
OnMessage(std::move(body));
|
||||
}
|
||||
});
|
||||
|
||||
// This will WaitForClient if it was waiting.
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (FLAGS_wait_for_debugger) {
|
||||
// Wait for the first client.
|
||||
|
|
|
@ -111,6 +111,7 @@ class Debugger {
|
|||
Emulator* emulator_;
|
||||
|
||||
uintptr_t listen_socket_;
|
||||
bool accept_thread_running_;
|
||||
std::thread accept_thread_;
|
||||
xe::threading::Fence accept_fence_;
|
||||
uintptr_t client_socket_;
|
||||
|
|
|
@ -274,10 +274,25 @@ X_STATUS Emulator::LaunchStfsContainer(std::wstring path) {
|
|||
|
||||
X_STATUS Emulator::CompleteLaunch(const std::wstring& path,
|
||||
const std::string& module_path) {
|
||||
auto xboxkrnl_module = kernel_state_->GetModule("xboxkrnl.exe");
|
||||
auto xboxkrnl = kernel::object_ref<kernel::XboxkrnlModule>(
|
||||
reinterpret_cast<kernel::XboxkrnlModule*>(xboxkrnl_module.release()));
|
||||
int result = xboxkrnl->LaunchModule(module_path.c_str());
|
||||
// Allow xam to request module loads.
|
||||
auto xam = kernel_state()->GetKernelModule<kernel::XamModule>("xam.xex");
|
||||
auto xboxkrnl =
|
||||
kernel_state()->GetKernelModule<kernel::XboxkrnlModule>("xboxkrnl.exe");
|
||||
|
||||
int result = 0;
|
||||
auto next_module = module_path;
|
||||
while (next_module != "") {
|
||||
XELOGI("Launching module %s", next_module.c_str());
|
||||
result = xboxkrnl->LaunchModule(next_module.c_str());
|
||||
|
||||
// Check xam and see if they want us to load another module.
|
||||
auto& loader_data = xam->loader_data();
|
||||
next_module = loader_data.launch_path;
|
||||
|
||||
// And blank out the launch path to avoid an infinite loop.
|
||||
loader_data.launch_path = "";
|
||||
}
|
||||
|
||||
if (result == 0) {
|
||||
return X_STATUS_SUCCESS;
|
||||
} else {
|
||||
|
|
|
@ -161,6 +161,18 @@ bool KernelState::IsKernelModule(const char* name) {
|
|||
return false;
|
||||
}
|
||||
|
||||
object_ref<XKernelModule> KernelState::GetKernelModule(const char* name) {
|
||||
assert_true(IsKernelModule(name));
|
||||
|
||||
for (auto kernel_module : kernel_modules_) {
|
||||
if (kernel_module->Matches(name)) {
|
||||
return retain_object(kernel_module.get());
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
object_ref<XModule> KernelState::GetModule(const char* name) {
|
||||
if (!name) {
|
||||
// NULL name = self.
|
||||
|
@ -223,26 +235,27 @@ void KernelState::SetExecutableModule(object_ref<XUserModule> module) {
|
|||
// Spin up deferred dispatch worker.
|
||||
// TODO(benvanik): move someplace more appropriate (out of ctor, but around
|
||||
// here).
|
||||
assert_false(dispatch_thread_running_);
|
||||
dispatch_thread_running_ = true;
|
||||
dispatch_thread_ =
|
||||
object_ref<XHostThread>(new XHostThread(this, 128 * 1024, 0, [this]() {
|
||||
while (dispatch_thread_running_) {
|
||||
std::unique_lock<std::mutex> lock(dispatch_mutex_);
|
||||
if (dispatch_queue_.empty()) {
|
||||
dispatch_cond_.wait(lock);
|
||||
if (!dispatch_thread_running_) {
|
||||
break;
|
||||
if (!dispatch_thread_running_) {
|
||||
dispatch_thread_running_ = true;
|
||||
dispatch_thread_ =
|
||||
object_ref<XHostThread>(new XHostThread(this, 128 * 1024, 0, [this]() {
|
||||
while (dispatch_thread_running_) {
|
||||
std::unique_lock<std::mutex> lock(dispatch_mutex_);
|
||||
if (dispatch_queue_.empty()) {
|
||||
dispatch_cond_.wait(lock);
|
||||
if (!dispatch_thread_running_) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
auto fn = std::move(dispatch_queue_.front());
|
||||
dispatch_queue_.pop_front();
|
||||
fn();
|
||||
}
|
||||
auto fn = std::move(dispatch_queue_.front());
|
||||
dispatch_queue_.pop_front();
|
||||
fn();
|
||||
}
|
||||
return 0;
|
||||
}));
|
||||
dispatch_thread_->set_name("Kernel Dispatch Thread");
|
||||
dispatch_thread_->Create();
|
||||
return 0;
|
||||
}));
|
||||
dispatch_thread_->set_name("Kernel Dispatch Thread");
|
||||
dispatch_thread_->Create();
|
||||
}
|
||||
}
|
||||
|
||||
void KernelState::LoadKernelModule(object_ref<XKernelModule> kernel_module) {
|
||||
|
@ -255,6 +268,7 @@ object_ref<XUserModule> KernelState::LoadUserModule(const char* raw_name) {
|
|||
std::string name = xe::find_name_from_path(raw_name);
|
||||
std::string path(raw_name);
|
||||
if (name == raw_name) {
|
||||
assert_not_null(executable_module_);
|
||||
path = xe::join_paths(xe::find_base_path(executable_module_->path()), name);
|
||||
}
|
||||
|
||||
|
@ -284,7 +298,7 @@ object_ref<XUserModule> KernelState::LoadUserModule(const char* raw_name) {
|
|||
|
||||
module->Dump();
|
||||
|
||||
if (module->entry_point()) {
|
||||
if (module->dll_module() && module->entry_point()) {
|
||||
// Call DllMain(DLL_PROCESS_ATTACH):
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583%28v=vs.85%29.aspx
|
||||
uint64_t args[] = {
|
||||
|
@ -300,6 +314,52 @@ object_ref<XUserModule> KernelState::LoadUserModule(const char* raw_name) {
|
|||
return module;
|
||||
}
|
||||
|
||||
void KernelState::TerminateTitle(bool from_guest_thread) {
|
||||
std::lock_guard<xe::recursive_mutex> lock(object_mutex_);
|
||||
|
||||
// First: Kill all guest threads.
|
||||
for (auto it = threads_by_id_.begin(); it != threads_by_id_.end();) {
|
||||
if (it->second->guest_thread()) {
|
||||
auto thread = it->second;
|
||||
|
||||
if (from_guest_thread && XThread::IsInThread(thread)) {
|
||||
// Don't terminate ourselves.
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (it->second->running()) {
|
||||
thread->Terminate(0);
|
||||
}
|
||||
|
||||
// Erase it from the thread list.
|
||||
it = threads_by_id_.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
// Second: Unload all user modules (including the executable)
|
||||
for (int i = 0; i < user_modules_.size(); i++) {
|
||||
X_STATUS status = user_modules_[i]->Unload();
|
||||
assert_true(XSUCCEEDED(status));
|
||||
|
||||
object_table_->RemoveHandle(user_modules_[i]->handle());
|
||||
}
|
||||
user_modules_.clear();
|
||||
|
||||
if (from_guest_thread) {
|
||||
threads_by_id_.erase(XThread::GetCurrentThread()->thread_id());
|
||||
|
||||
// Now commit suicide (using Terminate, because we can't call into guest
|
||||
// code anymore)
|
||||
// Also, manually invoke the lock guard's destructor, because Terminate
|
||||
// does not return.
|
||||
lock.~lock_guard();
|
||||
XThread::GetCurrentThread()->Terminate(0);
|
||||
}
|
||||
}
|
||||
|
||||
void KernelState::RegisterThread(XThread* thread) {
|
||||
std::lock_guard<xe::recursive_mutex> lock(object_mutex_);
|
||||
threads_by_id_[thread->thread_id()] = thread;
|
||||
|
@ -331,7 +391,7 @@ void KernelState::OnThreadExecute(XThread* thread) {
|
|||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583%28v=vs.85%29.aspx
|
||||
auto thread_state = thread->thread_state();
|
||||
for (auto user_module : user_modules_) {
|
||||
if (user_module->entry_point()) {
|
||||
if (user_module->dll_module() && user_module->entry_point()) {
|
||||
uint64_t args[] = {
|
||||
user_module->handle(),
|
||||
2, // DLL_THREAD_ATTACH
|
||||
|
@ -353,7 +413,7 @@ void KernelState::OnThreadExit(XThread* thread) {
|
|||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583%28v=vs.85%29.aspx
|
||||
auto thread_state = thread->thread_state();
|
||||
for (auto user_module : user_modules_) {
|
||||
if (user_module->entry_point()) {
|
||||
if (user_module->dll_module() && user_module->entry_point()) {
|
||||
uint64_t args[] = {
|
||||
user_module->handle(),
|
||||
3, // DLL_THREAD_DETACH
|
||||
|
|
|
@ -112,15 +112,26 @@ class KernelState {
|
|||
void UnregisterModule(XModule* module);
|
||||
bool IsKernelModule(const char* name);
|
||||
object_ref<XModule> GetModule(const char* name);
|
||||
|
||||
object_ref<XUserModule> GetExecutableModule();
|
||||
void SetExecutableModule(object_ref<XUserModule> module);
|
||||
object_ref<XUserModule> LoadUserModule(const char* name);
|
||||
|
||||
object_ref<XKernelModule> GetKernelModule(const char* name);
|
||||
template <typename T>
|
||||
object_ref<XKernelModule> LoadKernelModule() {
|
||||
auto kernel_module = object_ref<XKernelModule>(new T(emulator_, this));
|
||||
LoadKernelModule(kernel_module);
|
||||
return kernel_module;
|
||||
}
|
||||
object_ref<XUserModule> LoadUserModule(const char* name);
|
||||
template <typename T>
|
||||
object_ref<T> GetKernelModule(const char* name) {
|
||||
auto module = GetKernelModule(name);
|
||||
return object_ref<T>(reinterpret_cast<T*>(module.release()));
|
||||
}
|
||||
|
||||
// Terminates a title: Unloads all modules, and kills all guest threads.
|
||||
void TerminateTitle(bool from_guest_thread = false);
|
||||
|
||||
void RegisterThread(XThread* thread);
|
||||
void UnregisterThread(XThread* thread);
|
||||
|
|
|
@ -67,6 +67,8 @@ bool XModule::Matches(const std::string& name) const {
|
|||
|
||||
void XModule::OnLoad() { kernel_state_->RegisterModule(this); }
|
||||
|
||||
void XModule::OnUnload() { kernel_state_->UnregisterModule(this); }
|
||||
|
||||
X_STATUS XModule::GetSection(const char* name, uint32_t* out_section_data,
|
||||
uint32_t* out_section_size) {
|
||||
return X_STATUS_UNSUCCESSFUL;
|
||||
|
|
|
@ -86,6 +86,7 @@ class XModule : public XObject {
|
|||
|
||||
protected:
|
||||
void OnLoad();
|
||||
void OnUnload();
|
||||
|
||||
ModuleType module_type_;
|
||||
std::string name_;
|
||||
|
|
|
@ -41,7 +41,8 @@ xe::mutex critical_region_;
|
|||
|
||||
XThread::XThread(KernelState* kernel_state, uint32_t stack_size,
|
||||
uint32_t xapi_thread_startup, uint32_t start_address,
|
||||
uint32_t start_context, uint32_t creation_flags)
|
||||
uint32_t start_context, uint32_t creation_flags,
|
||||
bool guest_thread)
|
||||
: XObject(kernel_state, kTypeThread),
|
||||
thread_id_(++next_xthread_id),
|
||||
thread_handle_(0),
|
||||
|
@ -50,7 +51,9 @@ XThread::XThread(KernelState* kernel_state, uint32_t stack_size,
|
|||
thread_state_(0),
|
||||
priority_(0),
|
||||
affinity_(0),
|
||||
irql_(0) {
|
||||
irql_(0),
|
||||
guest_thread_(guest_thread),
|
||||
running_(false) {
|
||||
creation_params_.stack_size = stack_size;
|
||||
creation_params_.xapi_thread_startup = xapi_thread_startup;
|
||||
creation_params_.start_address = start_address;
|
||||
|
@ -67,9 +70,6 @@ XThread::XThread(KernelState* kernel_state, uint32_t stack_size,
|
|||
|
||||
apc_list_ = new NativeList(kernel_state->memory());
|
||||
|
||||
event_ = object_ref<XEvent>(new XEvent(kernel_state));
|
||||
event_->Initialize(true, false);
|
||||
|
||||
char thread_name[32];
|
||||
snprintf(thread_name, xe::countof(thread_name), "XThread%04X", handle());
|
||||
set_name(thread_name);
|
||||
|
@ -84,8 +84,6 @@ XThread::~XThread() {
|
|||
|
||||
delete apc_list_;
|
||||
|
||||
event_.reset();
|
||||
|
||||
PlatformDestroy();
|
||||
|
||||
if (thread_state_) {
|
||||
|
@ -335,12 +333,11 @@ X_STATUS XThread::Create() {
|
|||
}
|
||||
|
||||
X_STATUS XThread::Exit(int exit_code) {
|
||||
assert_true(XThread::GetCurrentThread() == this);
|
||||
|
||||
// TODO(benvanik): set exit code in thread state block
|
||||
|
||||
// TODO(benvanik); dispatch events? waiters? etc?
|
||||
if (event_) {
|
||||
event_->Set(0, false);
|
||||
}
|
||||
RundownAPCs();
|
||||
|
||||
kernel_state()->OnThreadExit(this);
|
||||
|
@ -349,6 +346,7 @@ X_STATUS XThread::Exit(int exit_code) {
|
|||
current_thread_tls = nullptr;
|
||||
xe::Profiler::ThreadExit();
|
||||
|
||||
running_ = false;
|
||||
Release();
|
||||
X_STATUS return_code = PlatformExit(exit_code);
|
||||
if (XFAILED(return_code)) {
|
||||
|
@ -357,6 +355,19 @@ X_STATUS XThread::Exit(int exit_code) {
|
|||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
X_STATUS XThread::Terminate(int exit_code) {
|
||||
// TODO: Inform the profiler that this thread is exiting.
|
||||
|
||||
running_ = false;
|
||||
Release();
|
||||
X_STATUS status = PlatformTerminate(exit_code);
|
||||
if (XFAILED(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#if XE_PLATFORM_WIN32
|
||||
|
||||
static uint32_t __stdcall XThreadStartCallbackWin32(void* param) {
|
||||
|
@ -404,6 +415,14 @@ X_STATUS XThread::PlatformExit(int exit_code) {
|
|||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
X_STATUS XThread::PlatformTerminate(int exit_code) {
|
||||
if (!TerminateThread(thread_handle_, exit_code)) {
|
||||
return X_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void* XThreadStartCallbackPthreads(void* param) {
|
||||
|
@ -463,12 +482,18 @@ X_STATUS XThread::PlatformExit(int exit_code) {
|
|||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
X_STATUS XThread::PlatformTerminate(int exit_code) {
|
||||
// TODO!
|
||||
assert_always();
|
||||
}
|
||||
|
||||
#endif // WIN32
|
||||
|
||||
void XThread::Execute() {
|
||||
XELOGKERNEL("XThread::Execute thid %d (handle=%.8X, '%s', native=%.8X)",
|
||||
thread_id_, handle(), name_.c_str(),
|
||||
xe::threading::current_thread_id());
|
||||
running_ = true;
|
||||
|
||||
// Let the kernel know we are starting.
|
||||
kernel_state()->OnThreadExecute(this);
|
||||
|
@ -498,6 +523,7 @@ void XThread::Execute() {
|
|||
// Treat the return code as an implicit exit code.
|
||||
}
|
||||
|
||||
running_ = false;
|
||||
Exit(exit_code);
|
||||
}
|
||||
|
||||
|
@ -754,11 +780,11 @@ X_STATUS XThread::Delay(uint32_t processor_mode, uint32_t alertable,
|
|||
}
|
||||
}
|
||||
|
||||
void* XThread::GetWaitHandle() { return event_->GetWaitHandle(); }
|
||||
void* XThread::GetWaitHandle() { return thread_handle_; }
|
||||
|
||||
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),
|
||||
: XThread(kernel_state, stack_size, 0, 0, 0, creation_flags, false),
|
||||
host_fn_(host_fn) {}
|
||||
|
||||
void XHostThread::Execute() {
|
||||
|
|
|
@ -81,7 +81,7 @@ class XThread : public XObject {
|
|||
public:
|
||||
XThread(KernelState* kernel_state, uint32_t stack_size,
|
||||
uint32_t xapi_thread_startup, uint32_t start_address,
|
||||
uint32_t start_context, uint32_t creation_flags);
|
||||
uint32_t start_context, uint32_t creation_flags, bool guest_thread);
|
||||
virtual ~XThread();
|
||||
|
||||
static bool IsInThread(XThread* other);
|
||||
|
@ -92,6 +92,8 @@ class XThread : public XObject {
|
|||
uint32_t tls_ptr() const { return tls_address_; }
|
||||
uint32_t pcr_ptr() const { return pcr_address_; }
|
||||
uint32_t thread_state_ptr() const { return thread_state_address_; }
|
||||
bool guest_thread() const { return guest_thread_; }
|
||||
bool running() const { return running_; }
|
||||
|
||||
cpu::ThreadState* thread_state() const { return thread_state_; }
|
||||
uint32_t thread_id() const { return thread_id_; }
|
||||
|
@ -102,6 +104,7 @@ class XThread : public XObject {
|
|||
|
||||
X_STATUS Create();
|
||||
X_STATUS Exit(int exit_code);
|
||||
X_STATUS Terminate(int exit_code);
|
||||
|
||||
virtual void Execute();
|
||||
|
||||
|
@ -136,6 +139,7 @@ class XThread : public XObject {
|
|||
X_STATUS PlatformCreate();
|
||||
void PlatformDestroy();
|
||||
X_STATUS PlatformExit(int exit_code);
|
||||
X_STATUS PlatformTerminate(int exit_code);
|
||||
|
||||
static void DeliverAPCs(void* data);
|
||||
void RundownAPCs();
|
||||
|
@ -156,6 +160,8 @@ class XThread : public XObject {
|
|||
uint32_t pcr_address_;
|
||||
uint32_t thread_state_address_;
|
||||
cpu::ThreadState* thread_state_;
|
||||
bool guest_thread_; // Launched into guest code?
|
||||
bool running_;
|
||||
|
||||
std::string name_;
|
||||
|
||||
|
@ -165,8 +171,6 @@ class XThread : public XObject {
|
|||
std::atomic<uint32_t> irql_;
|
||||
xe::mutex apc_lock_;
|
||||
NativeList* apc_list_;
|
||||
|
||||
object_ref<XEvent> event_;
|
||||
};
|
||||
|
||||
class XHostThread : public XThread {
|
||||
|
|
|
@ -24,7 +24,7 @@ using namespace xe::cpu;
|
|||
XUserModule::XUserModule(KernelState* kernel_state, const char* path)
|
||||
: XModule(kernel_state, ModuleType::kUserModule, path) {}
|
||||
|
||||
XUserModule::~XUserModule() {}
|
||||
XUserModule::~XUserModule() { Unload(); }
|
||||
|
||||
X_STATUS XUserModule::LoadFromFile(std::string path) {
|
||||
X_STATUS result = X_STATUS_UNSUCCESSFUL;
|
||||
|
@ -104,12 +104,27 @@ X_STATUS XUserModule::LoadFromMemory(const void* addr, const size_t length) {
|
|||
// Cache some commonly used headers...
|
||||
this->xex_module()->GetOptHeader(XEX_HEADER_ENTRY_POINT, &entry_point_);
|
||||
this->xex_module()->GetOptHeader(XEX_HEADER_DEFAULT_STACK_SIZE, &stack_size_);
|
||||
dll_module_ = !!(header->module_flags & XEX_MODULE_DLL_MODULE);
|
||||
|
||||
OnLoad();
|
||||
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
X_STATUS XUserModule::Unload() {
|
||||
if (!xex_module()->loaded()) {
|
||||
// Quick abort.
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (xex_module()->Unload()) {
|
||||
OnUnload();
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return X_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
uint32_t XUserModule::GetProcAddressByOrdinal(uint16_t ordinal) {
|
||||
return xex_module()->GetProcAddress(ordinal);
|
||||
}
|
||||
|
@ -201,11 +216,10 @@ X_STATUS XUserModule::GetOptHeader(uint8_t* membase, const xex2_header* header,
|
|||
|
||||
X_STATUS XUserModule::Launch(uint32_t flags) {
|
||||
XELOGI("Launching module...");
|
||||
Dump();
|
||||
|
||||
// Create a thread to run in.
|
||||
auto thread = object_ref<XThread>(
|
||||
new XThread(kernel_state(), stack_size_, 0, entry_point_, 0, 0));
|
||||
new XThread(kernel_state(), stack_size_, 0, entry_point_, 0, 0, true));
|
||||
|
||||
X_STATUS result = thread->Create();
|
||||
if (XFAILED(result)) {
|
||||
|
|
|
@ -29,15 +29,20 @@ class XUserModule : public XModule {
|
|||
const xe::cpu::XexModule* xex_module() const {
|
||||
return reinterpret_cast<xe::cpu::XexModule*>(processor_module_);
|
||||
}
|
||||
xe::cpu::XexModule* xex_module() {
|
||||
return reinterpret_cast<xe::cpu::XexModule*>(processor_module_);
|
||||
}
|
||||
|
||||
const xex2_header* xex_header() const { return xex_module()->xex_header(); }
|
||||
uint32_t guest_xex_header() const { return guest_xex_header_; }
|
||||
bool dll_module() const { return dll_module_; }
|
||||
|
||||
uint32_t entry_point() const { return entry_point_; }
|
||||
uint32_t stack_size() const { return stack_size_; }
|
||||
|
||||
X_STATUS LoadFromFile(std::string path);
|
||||
X_STATUS LoadFromMemory(const void* addr, const size_t length);
|
||||
X_STATUS Unload();
|
||||
|
||||
uint32_t GetProcAddressByOrdinal(uint16_t ordinal) override;
|
||||
uint32_t GetProcAddressByName(const char* name) override;
|
||||
|
@ -67,6 +72,7 @@ class XUserModule : public XModule {
|
|||
private:
|
||||
uint32_t guest_xex_header_;
|
||||
|
||||
bool dll_module_;
|
||||
uint32_t entry_point_;
|
||||
uint32_t stack_size_;
|
||||
};
|
||||
|
|
|
@ -11,8 +11,10 @@
|
|||
#include "xenia/kernel/kernel_state.h"
|
||||
#include "xenia/kernel/objects/xenumerator.h"
|
||||
#include "xenia/kernel/objects/xuser_module.h"
|
||||
#include "xenia/kernel/objects/xthread.h"
|
||||
#include "xenia/kernel/util/shim_utils.h"
|
||||
#include "xenia/kernel/util/xex2.h"
|
||||
#include "xenia/kernel/xam_module.h"
|
||||
#include "xenia/kernel/xam_private.h"
|
||||
#include "xenia/xbox.h"
|
||||
|
||||
|
@ -90,53 +92,84 @@ SHIM_CALL XamGetExecutionId_shim(PPCContext* ppc_context,
|
|||
SHIM_SET_RETURN_32(X_STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
SHIM_CALL XamLoaderSetLaunchData_shim(PPCContext* ppc_context,
|
||||
KernelState* kernel_state) {
|
||||
uint32_t data_ptr = SHIM_GET_ARG_32(0);
|
||||
uint32_t data_size = SHIM_GET_ARG_32(1);
|
||||
dword_result_t XamLoaderSetLaunchData(lpvoid_t data, dword_t size) {
|
||||
auto xam = kernel_state()->GetKernelModule<kernel::XamModule>("xam.xex");
|
||||
|
||||
XELOGD("XamLoaderSetLaunchData(%.8X, %d)", data_ptr, data_size);
|
||||
auto& loader_data = xam->loader_data();
|
||||
if (loader_data.launch_data_ptr) {
|
||||
kernel_memory()->SystemHeapFree(loader_data.launch_data_ptr);
|
||||
}
|
||||
|
||||
// Unknown return value.
|
||||
SHIM_SET_RETURN_32(0);
|
||||
loader_data.launch_data_ptr = kernel_memory()->SystemHeapAlloc(size);
|
||||
loader_data.launch_data_size = size;
|
||||
|
||||
std::memcpy(kernel_memory()->TranslateVirtual(loader_data.launch_data_ptr),
|
||||
data, size);
|
||||
|
||||
// FIXME: Unknown return value.
|
||||
return 0;
|
||||
}
|
||||
DECLARE_XAM_EXPORT(XamLoaderSetLaunchData, ExportTag::kSketchy);
|
||||
|
||||
SHIM_CALL XamLoaderGetLaunchDataSize_shim(PPCContext* ppc_context,
|
||||
KernelState* kernel_state) {
|
||||
uint32_t size_ptr = SHIM_GET_ARG_32(0);
|
||||
dword_result_t XamLoaderGetLaunchDataSize(lpdword_t size_ptr) {
|
||||
auto xam = kernel_state()->GetKernelModule<kernel::XamModule>("xam.xex");
|
||||
|
||||
XELOGD("XamLoaderGetLaunchDataSize(%.8X)", size_ptr);
|
||||
*size_ptr = xam->loader_data().launch_data_size;
|
||||
|
||||
SHIM_SET_MEM_32(size_ptr, 0);
|
||||
|
||||
SHIM_SET_RETURN_32(1);
|
||||
return 0;
|
||||
}
|
||||
DECLARE_XAM_EXPORT(XamLoaderGetLaunchDataSize, ExportTag::kSketchy);
|
||||
|
||||
SHIM_CALL XamLoaderGetLaunchData_shim(PPCContext* ppc_context,
|
||||
KernelState* kernel_state) {
|
||||
uint32_t buffer_ptr = SHIM_GET_ARG_32(0);
|
||||
uint32_t buffer_size = SHIM_GET_ARG_32(1);
|
||||
dword_result_t XamLoaderGetLaunchData(lpvoid_t buffer_ptr,
|
||||
dword_t buffer_size) {
|
||||
auto xam = kernel_state()->GetKernelModule<kernel::XamModule>("xam.xex");
|
||||
|
||||
XELOGD("XamLoaderGetLaunchData(%.8X, %d)", buffer_ptr, buffer_size);
|
||||
auto& loader_data = xam->loader_data();
|
||||
if (loader_data.launch_data_ptr) {
|
||||
uint8_t* loader_buffer_ptr =
|
||||
kernel_memory()->TranslateVirtual(loader_data.launch_data_ptr);
|
||||
|
||||
SHIM_SET_RETURN_32(0);
|
||||
uint32_t copy_size =
|
||||
std::min(loader_data.launch_data_size, (uint32_t)buffer_size);
|
||||
|
||||
std::memcpy(buffer_ptr, loader_buffer_ptr, copy_size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
DECLARE_XAM_EXPORT(XamLoaderGetLaunchData, ExportTag::kSketchy);
|
||||
|
||||
SHIM_CALL XamLoaderLaunchTitle_shim(PPCContext* ppc_context,
|
||||
KernelState* kernel_state) {
|
||||
uint32_t name_ptr = SHIM_GET_ARG_32(0);
|
||||
const char* name = (const char*)SHIM_MEM_ADDR(name_ptr);
|
||||
uint32_t flags = SHIM_GET_ARG_32(1);
|
||||
void XamLoaderLaunchTitle(lpstring_t raw_name, dword_t flags) {
|
||||
auto xam = kernel_state()->GetKernelModule<kernel::XamModule>("xam.xex");
|
||||
|
||||
XELOGD("XamLoaderLaunchTitle(%.8X(%s), %.8X)", name_ptr, name, flags);
|
||||
assert_always();
|
||||
auto& loader_data = xam->loader_data();
|
||||
loader_data.launch_flags = flags;
|
||||
|
||||
// Translate the launch path to a full path.
|
||||
if (raw_name) {
|
||||
std::string name = xe::find_name_from_path(std::string(raw_name));
|
||||
std::string path(raw_name);
|
||||
if (name == std::string(raw_name)) {
|
||||
path = xe::join_paths(
|
||||
xe::find_base_path(kernel_state()->GetExecutableModule()->path()),
|
||||
name);
|
||||
}
|
||||
|
||||
loader_data.launch_path = path;
|
||||
} else {
|
||||
assert_always("Game requested exit to dashboard via XamLoaderLaunchTitle");
|
||||
}
|
||||
|
||||
// This function does not return.
|
||||
kernel_state()->TerminateTitle(true);
|
||||
}
|
||||
DECLARE_XAM_EXPORT(XamLoaderLaunchTitle, ExportTag::kSketchy);
|
||||
|
||||
SHIM_CALL XamLoaderTerminateTitle_shim(PPCContext* ppc_context,
|
||||
KernelState* kernel_state) {
|
||||
XELOGD("XamLoaderTerminateTitle()");
|
||||
assert_always();
|
||||
void XamLoaderTerminateTitle() {
|
||||
// This function does not return.
|
||||
kernel_state()->TerminateTitle(true);
|
||||
}
|
||||
DECLARE_XAM_EXPORT(XamLoaderTerminateTitle, ExportTag::kSketchy);
|
||||
|
||||
SHIM_CALL XamAlloc_shim(PPCContext* ppc_context, KernelState* kernel_state) {
|
||||
uint32_t unk = SHIM_GET_ARG_32(0);
|
||||
|
@ -223,12 +256,6 @@ void xe::kernel::xam::RegisterInfoExports(
|
|||
|
||||
SHIM_SET_MAPPING("xam.xex", XamGetExecutionId, state);
|
||||
|
||||
SHIM_SET_MAPPING("xam.xex", XamLoaderSetLaunchData, state);
|
||||
SHIM_SET_MAPPING("xam.xex", XamLoaderGetLaunchDataSize, state);
|
||||
SHIM_SET_MAPPING("xam.xex", XamLoaderGetLaunchData, state);
|
||||
SHIM_SET_MAPPING("xam.xex", XamLoaderLaunchTitle, state);
|
||||
SHIM_SET_MAPPING("xam.xex", XamLoaderTerminateTitle, state);
|
||||
|
||||
SHIM_SET_MAPPING("xam.xex", XamAlloc, state);
|
||||
SHIM_SET_MAPPING("xam.xex", XamFree, state);
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace xe {
|
|||
namespace kernel {
|
||||
|
||||
XamModule::XamModule(Emulator* emulator, KernelState* kernel_state)
|
||||
: XKernelModule(kernel_state, "xe:\\xam.xex") {
|
||||
: XKernelModule(kernel_state, "xe:\\xam.xex"), loader_data_() {
|
||||
RegisterExportTable(export_resolver_);
|
||||
|
||||
// Register all exported functions.
|
||||
|
|
|
@ -24,7 +24,18 @@ class XamModule : public XKernelModule {
|
|||
|
||||
static void RegisterExportTable(xe::cpu::ExportResolver* export_resolver);
|
||||
|
||||
struct LoaderData {
|
||||
uint32_t launch_data_ptr = 0;
|
||||
uint32_t launch_data_size = 0;
|
||||
uint32_t launch_flags = 0;
|
||||
std::string launch_path; // Full path to next xex
|
||||
};
|
||||
|
||||
const LoaderData& loader_data() const { return loader_data_; }
|
||||
LoaderData& loader_data() { return loader_data_; }
|
||||
|
||||
private:
|
||||
LoaderData loader_data_;
|
||||
};
|
||||
|
||||
} // namespace kernel
|
||||
|
|
|
@ -824,6 +824,9 @@ SHIM_CALL NtFlushBuffersFile_shim(PPCContext* ppc_context,
|
|||
SHIM_SET_RETURN_32(result);
|
||||
}
|
||||
|
||||
dword_result_t FscGetCacheElementCount(dword_t r3) { return 0; }
|
||||
DECLARE_XBOXKRNL_EXPORT(FscGetCacheElementCount, ExportTag::kStub);
|
||||
|
||||
SHIM_CALL FscSetCacheElementCount_shim(PPCContext* ppc_context,
|
||||
KernelState* kernel_state) {
|
||||
uint32_t unk_0 = SHIM_GET_ARG_32(0);
|
||||
|
|
|
@ -177,14 +177,7 @@ XboxkrnlModule::~XboxkrnlModule() {
|
|||
int XboxkrnlModule::LaunchModule(const char* path) {
|
||||
// Create and register the module. We keep it local to this function and
|
||||
// dispose it on exit.
|
||||
auto module = object_ref<XUserModule>(new XUserModule(kernel_state_, path));
|
||||
|
||||
// Load the module into memory from the filesystem.
|
||||
X_STATUS result_code = module->LoadFromFile(path);
|
||||
if (XFAILED(result_code)) {
|
||||
XELOGE("Failed to load module %s: %.8X", path, result_code);
|
||||
return 1;
|
||||
}
|
||||
auto module = kernel_state_->LoadUserModule(path);
|
||||
|
||||
// Set as the main module, while running.
|
||||
kernel_state_->SetExecutableModule(module);
|
||||
|
@ -196,7 +189,10 @@ int XboxkrnlModule::LaunchModule(const char* path) {
|
|||
|
||||
// Launch the module.
|
||||
// NOTE: this won't return until the module exits.
|
||||
result_code = module->Launch(0);
|
||||
X_STATUS result_code = module->Launch(0);
|
||||
|
||||
// Main thread exited. Terminate the title.
|
||||
kernel_state_->TerminateTitle();
|
||||
kernel_state_->SetExecutableModule(NULL);
|
||||
if (XFAILED(result_code)) {
|
||||
XELOGE("Failed to launch module %s: %.8X", path, result_code);
|
||||
|
|
|
@ -221,6 +221,7 @@ SHIM_CALL XexLoadImage_shim(PPCContext* ppc_context,
|
|||
if (module) {
|
||||
// Existing module found.
|
||||
hmodule = module->hmodule_ptr();
|
||||
result = X_STATUS_SUCCESS;
|
||||
} else {
|
||||
// Not found; attempt to load as a user module.
|
||||
auto user_module = kernel_state->LoadUserModule(module_name);
|
||||
|
@ -232,9 +233,11 @@ SHIM_CALL XexLoadImage_shim(PPCContext* ppc_context,
|
|||
}
|
||||
|
||||
// Increment the module's load count.
|
||||
auto ldr_data =
|
||||
kernel_memory()->TranslateVirtual<X_LDR_DATA_TABLE_ENTRY*>(hmodule);
|
||||
ldr_data->load_count++;
|
||||
if (hmodule) {
|
||||
auto ldr_data =
|
||||
kernel_memory()->TranslateVirtual<X_LDR_DATA_TABLE_ENTRY*>(hmodule);
|
||||
ldr_data->load_count++;
|
||||
}
|
||||
|
||||
SHIM_SET_MEM_32(hmodule_ptr, hmodule);
|
||||
|
||||
|
@ -253,12 +256,15 @@ SHIM_CALL XexUnloadImage_shim(PPCContext* ppc_context,
|
|||
return;
|
||||
}
|
||||
|
||||
auto ldr_data =
|
||||
kernel_state->memory()->TranslateVirtual<X_LDR_DATA_TABLE_ENTRY*>(
|
||||
hmodule);
|
||||
if (ldr_data->load_count-- <= 0) {
|
||||
// No more references, free it.
|
||||
kernel_state->object_table()->RemoveHandle(module->handle());
|
||||
// Can't unload kernel modules from user code.
|
||||
if (module->module_type() != XModule::ModuleType::kKernelModule) {
|
||||
auto ldr_data =
|
||||
kernel_state->memory()->TranslateVirtual<X_LDR_DATA_TABLE_ENTRY*>(
|
||||
hmodule);
|
||||
if (--ldr_data->load_count == 0) {
|
||||
// No more references, free it.
|
||||
kernel_state->object_table()->RemoveHandle(module->handle());
|
||||
}
|
||||
}
|
||||
|
||||
SHIM_SET_RETURN_32(X_STATUS_SUCCESS);
|
||||
|
|
|
@ -117,7 +117,7 @@ SHIM_CALL ExCreateThread_shim(PPCContext* ppc_context,
|
|||
|
||||
auto thread = object_ref<XThread>(
|
||||
new XThread(kernel_state, stack_size, xapi_thread_startup, start_address,
|
||||
start_context, creation_flags));
|
||||
start_context, creation_flags, true));
|
||||
|
||||
X_STATUS result = thread->Create();
|
||||
if (XFAILED(result)) {
|
||||
|
@ -1348,38 +1348,31 @@ SHIM_CALL KeRemoveQueueDpc_shim(PPCContext* ppc_context,
|
|||
|
||||
xe::mutex global_list_mutex_;
|
||||
|
||||
// http://www.nirsoft.net/kernel_struct/vista/SLIST_HEADER.html
|
||||
struct SLIST_HEADER {
|
||||
xe::be<uint32_t> next;
|
||||
xe::be<uint16_t> depth;
|
||||
xe::be<uint16_t> sequence;
|
||||
};
|
||||
|
||||
pointer_result_t InterlockedPopEntrySList(pointer_t<SLIST_HEADER> plist_ptr) {
|
||||
pointer_result_t InterlockedPopEntrySList(pointer_t<X_SLIST_HEADER> plist_ptr) {
|
||||
std::lock_guard<xe::mutex> lock(global_list_mutex_);
|
||||
|
||||
uint32_t first = plist_ptr->next;
|
||||
if (first == 0) {
|
||||
if (plist_ptr->next.next == 0) {
|
||||
// List empty!
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get the second element.
|
||||
uint8_t* p = kernel_memory()->TranslateVirtual(first);
|
||||
auto second = xe::load_and_swap<uint32_t>(p);
|
||||
// Get the first element.
|
||||
auto result = kernel_memory()->TranslateVirtual<X_SINGLE_LIST_ENTRY*>(
|
||||
plist_ptr->next.next);
|
||||
|
||||
plist_ptr->next = second;
|
||||
uint32_t popped = plist_ptr->next.next;
|
||||
plist_ptr->next.next = result->next;
|
||||
|
||||
// Return the one we popped
|
||||
return first;
|
||||
return popped;
|
||||
}
|
||||
DECLARE_XBOXKRNL_EXPORT(InterlockedPopEntrySList, ExportTag::kImplemented);
|
||||
|
||||
pointer_result_t InterlockedFlushSList(pointer_t<SLIST_HEADER> plist_ptr) {
|
||||
pointer_result_t InterlockedFlushSList(pointer_t<X_SLIST_HEADER> plist_ptr) {
|
||||
std::lock_guard<xe::mutex> lock(global_list_mutex_);
|
||||
|
||||
uint32_t next = plist_ptr->next;
|
||||
plist_ptr->next = 0;
|
||||
uint32_t next = plist_ptr->next.next;
|
||||
plist_ptr->next.next = 0;
|
||||
|
||||
return next;
|
||||
}
|
||||
|
|
|
@ -280,9 +280,9 @@ struct X_ANSI_STRING {
|
|||
};
|
||||
|
||||
struct X_UNICODE_STRING {
|
||||
xe::be<uint16_t> length;
|
||||
xe::be<uint16_t> maximum_length;
|
||||
xe::be<uint32_t> pointer;
|
||||
xe::be<uint16_t> length; // 0x0
|
||||
xe::be<uint16_t> maximum_length; // 0x2
|
||||
xe::be<uint32_t> pointer; // 0x4
|
||||
|
||||
void reset() {
|
||||
length = 0;
|
||||
|
@ -322,9 +322,28 @@ static_assert_size(X_VIDEO_MODE, 48);
|
|||
struct X_LIST_ENTRY {
|
||||
be<uint32_t> flink_ptr; // next entry / head
|
||||
be<uint32_t> blink_ptr; // previous entry / head
|
||||
|
||||
// Assumes X_LIST_ENTRY is within guest memory!
|
||||
void initialize(uint8_t* virtual_membase) {
|
||||
flink_ptr = (uint32_t)((uint8_t*)this - virtual_membase);
|
||||
blink_ptr = (uint32_t)((uint8_t*)this - virtual_membase);
|
||||
}
|
||||
};
|
||||
static_assert_size(X_LIST_ENTRY, 8);
|
||||
|
||||
struct X_SINGLE_LIST_ENTRY {
|
||||
be<uint32_t> next; // 0x0 pointer to next entry
|
||||
};
|
||||
static_assert_size(X_SINGLE_LIST_ENTRY, 4);
|
||||
|
||||
// http://www.nirsoft.net/kernel_struct/vista/SLIST_HEADER.html
|
||||
struct X_SLIST_HEADER {
|
||||
X_SINGLE_LIST_ENTRY next; // 0x0
|
||||
be<uint16_t> depth; // 0x4
|
||||
be<uint16_t> sequence; // 0x6
|
||||
};
|
||||
static_assert_size(X_SLIST_HEADER, 8);
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
} // namespace xe
|
||||
|
|
Loading…
Reference in New Issue