[Kernel] Added support for loading modules before main

This commit is contained in:
Gliniak 2025-07-28 21:23:51 +02:00 committed by Radosław Gliński
parent 70364e73ae
commit 2969a04145
4 changed files with 58 additions and 5 deletions

View file

@ -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;
} }

View file

@ -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));
} }

View file

@ -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);

View file

@ -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();