mirror of
https://github.com/xenia-project/xenia.git
synced 2025-12-06 07:12:03 +01:00
[Kernel] Added support for loading modules before main
This commit is contained in:
parent
70364e73ae
commit
2969a04145
|
|
@ -24,6 +24,7 @@
|
||||||
#include "xenia/cpu/processor.h"
|
#include "xenia/cpu/processor.h"
|
||||||
#include "xenia/emulator.h"
|
#include "xenia/emulator.h"
|
||||||
#include "xenia/kernel/kernel_state.h"
|
#include "xenia/kernel/kernel_state.h"
|
||||||
|
#include "xenia/kernel/user_module.h"
|
||||||
#include "xenia/kernel/xmodule.h"
|
#include "xenia/kernel/xmodule.h"
|
||||||
|
|
||||||
#include "third_party/crypto/TinySHA1.hpp"
|
#include "third_party/crypto/TinySHA1.hpp"
|
||||||
|
|
@ -1062,6 +1063,15 @@ bool XexModule::LoadContinue() {
|
||||||
opt_import_libraries->string_table.count);
|
opt_import_libraries->string_table.count);
|
||||||
assert_not_null(string_table[library_name_index]);
|
assert_not_null(string_table[library_name_index]);
|
||||||
auto library_name = std::string(string_table[library_name_index]);
|
auto library_name = std::string(string_table[library_name_index]);
|
||||||
|
|
||||||
|
if (!kernel_state_->IsModuleLoaded(library_name)) {
|
||||||
|
if (auto module = kernel_state_->LoadUserModule(library_name)) {
|
||||||
|
if (kernel_state_->FinishLoadingUserModule(module, false)) {
|
||||||
|
library_name = module->path();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SetupLibraryImports(library_name, library);
|
SetupLibraryImports(library_name, library);
|
||||||
library_offset += library->size;
|
library_offset += library->size;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -217,6 +217,28 @@ bool KernelState::IsKernelModule(const std::string_view name) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool KernelState::IsModuleLoaded(const std::string_view name) {
|
||||||
|
if (name.empty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto kernel_module : kernel_modules_) {
|
||||||
|
if (kernel_module->Matches(name)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto global_lock = global_critical_region_.Acquire();
|
||||||
|
|
||||||
|
for (auto user_module : user_modules_) {
|
||||||
|
if (user_module->Matches(name)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
object_ref<KernelModule> KernelState::GetKernelModule(
|
object_ref<KernelModule> KernelState::GetKernelModule(
|
||||||
const std::string_view name) {
|
const std::string_view name) {
|
||||||
assert_true(IsKernelModule(name));
|
assert_true(IsKernelModule(name));
|
||||||
|
|
@ -431,10 +453,15 @@ object_ref<UserModule> KernelState::LoadUserModule(
|
||||||
auto name = xe::utf8::find_name_from_guest_path(raw_name);
|
auto name = xe::utf8::find_name_from_guest_path(raw_name);
|
||||||
std::string path(raw_name);
|
std::string path(raw_name);
|
||||||
if (name == raw_name) {
|
if (name == raw_name) {
|
||||||
assert_not_null(executable_module_);
|
if (!executable_module_) {
|
||||||
|
path = xe::utf8::join_guest_paths(
|
||||||
|
xe::utf8::find_base_guest_path((*user_modules_.cbegin())->path()),
|
||||||
|
name);
|
||||||
|
} else {
|
||||||
path = xe::utf8::join_guest_paths(
|
path = xe::utf8::join_guest_paths(
|
||||||
xe::utf8::find_base_guest_path(executable_module_->path()), name);
|
xe::utf8::find_base_guest_path(executable_module_->path()), name);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
object_ref<UserModule> module;
|
object_ref<UserModule> module;
|
||||||
{
|
{
|
||||||
|
|
@ -521,6 +548,9 @@ X_RESULT KernelState::FinishLoadingUserModule(
|
||||||
1, // DLL_PROCESS_ATTACH
|
1, // DLL_PROCESS_ATTACH
|
||||||
0, // 0 because always dynamic
|
0, // 0 because always dynamic
|
||||||
};
|
};
|
||||||
|
|
||||||
|
module->is_attached_ = true;
|
||||||
|
|
||||||
auto thread_state = XThread::GetCurrentThread()->thread_state();
|
auto thread_state = XThread::GetCurrentThread()->thread_state();
|
||||||
processor()->Execute(thread_state, module->entry_point(), args,
|
processor()->Execute(thread_state, module->entry_point(), args,
|
||||||
xe::countof(args));
|
xe::countof(args));
|
||||||
|
|
@ -808,9 +838,16 @@ void KernelState::OnThreadExecute(XThread* thread) {
|
||||||
if (user_module->is_dll_module() && user_module->entry_point()) {
|
if (user_module->is_dll_module() && user_module->entry_point()) {
|
||||||
uint64_t args[] = {
|
uint64_t args[] = {
|
||||||
user_module->handle(),
|
user_module->handle(),
|
||||||
2, // DLL_THREAD_ATTACH
|
user_module->is_attached_
|
||||||
|
? static_cast<uint64_t>(2) // DLL_THREAD_ATTACH - Used to call
|
||||||
|
// DLL for each thread created.
|
||||||
|
: static_cast<uint64_t>(1), // DLL_PROCESS_ATTACH - Used only
|
||||||
|
// once for initialization.
|
||||||
0, // 0 because always dynamic
|
0, // 0 because always dynamic
|
||||||
};
|
};
|
||||||
|
|
||||||
|
user_module->is_attached_ = true;
|
||||||
|
|
||||||
processor()->Execute(thread_state, user_module->entry_point(), args,
|
processor()->Execute(thread_state, user_module->entry_point(), args,
|
||||||
xe::countof(args));
|
xe::countof(args));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -226,6 +226,7 @@ class KernelState {
|
||||||
bool RegisterUserModule(object_ref<UserModule> module);
|
bool RegisterUserModule(object_ref<UserModule> module);
|
||||||
void UnregisterUserModule(UserModule* module);
|
void UnregisterUserModule(UserModule* module);
|
||||||
bool IsKernelModule(const std::string_view name);
|
bool IsKernelModule(const std::string_view name);
|
||||||
|
bool IsModuleLoaded(const std::string_view name);
|
||||||
object_ref<XModule> GetModule(const std::string_view name,
|
object_ref<XModule> GetModule(const std::string_view name,
|
||||||
bool user_only = false);
|
bool user_only = false);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,11 @@ class UserModule : public XModule {
|
||||||
ByteStream* stream,
|
ByteStream* stream,
|
||||||
const std::string_view path);
|
const std::string_view path);
|
||||||
|
|
||||||
|
// TODO(Gliniak): This shouldn't be required. It is used for initial DLL
|
||||||
|
// initialization. Which should happen on main thread before main execution
|
||||||
|
// which isn't really possible right now.
|
||||||
|
bool is_attached_ = false;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void CalculateHash();
|
void CalculateHash();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue