[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/emulator.h"
#include "xenia/kernel/kernel_state.h"
#include "xenia/kernel/user_module.h"
#include "xenia/kernel/xmodule.h"
#include "third_party/crypto/TinySHA1.hpp"
@ -1062,6 +1063,15 @@ bool XexModule::LoadContinue() {
opt_import_libraries->string_table.count);
assert_not_null(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);
library_offset += library->size;
}

View File

@ -217,6 +217,28 @@ bool KernelState::IsKernelModule(const std::string_view name) {
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(
const std::string_view name) {
assert_true(IsKernelModule(name));
@ -431,9 +453,14 @@ object_ref<UserModule> KernelState::LoadUserModule(
auto name = xe::utf8::find_name_from_guest_path(raw_name);
std::string path(raw_name);
if (name == raw_name) {
assert_not_null(executable_module_);
path = xe::utf8::join_guest_paths(
xe::utf8::find_base_guest_path(executable_module_->path()), name);
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(
xe::utf8::find_base_guest_path(executable_module_->path()), name);
}
}
object_ref<UserModule> module;
@ -521,6 +548,9 @@ X_RESULT KernelState::FinishLoadingUserModule(
1, // DLL_PROCESS_ATTACH
0, // 0 because always dynamic
};
module->is_attached_ = true;
auto thread_state = XThread::GetCurrentThread()->thread_state();
processor()->Execute(thread_state, module->entry_point(), args,
xe::countof(args));
@ -808,9 +838,16 @@ void KernelState::OnThreadExecute(XThread* thread) {
if (user_module->is_dll_module() && user_module->entry_point()) {
uint64_t args[] = {
user_module->handle(),
2, // DLL_THREAD_ATTACH
0, // 0 because always dynamic
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
};
user_module->is_attached_ = true;
processor()->Execute(thread_state, user_module->entry_point(), args,
xe::countof(args));
}

View File

@ -226,6 +226,7 @@ class KernelState {
bool RegisterUserModule(object_ref<UserModule> module);
void UnregisterUserModule(UserModule* module);
bool IsKernelModule(const std::string_view name);
bool IsModuleLoaded(const std::string_view name);
object_ref<XModule> GetModule(const std::string_view name,
bool user_only = false);

View File

@ -108,6 +108,11 @@ class UserModule : public XModule {
ByteStream* stream,
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:
void CalculateHash();