KernelState should handle module launching
This commit is contained in:
parent
69be82c786
commit
a148b965f1
|
@ -53,6 +53,11 @@ struct elf32_phdr {
|
||||||
xe::be<uint32_t> p_align;
|
xe::be<uint32_t> p_align;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool ElfModule::is_executable() const {
|
||||||
|
auto hdr = reinterpret_cast<const elf32_ehdr*>(elf_header_mem_.data());
|
||||||
|
return hdr->e_entry != 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool ElfModule::Load(const std::string& name, const std::string& path,
|
bool ElfModule::Load(const std::string& name, const std::string& path,
|
||||||
const void* elf_addr, size_t elf_length) {
|
const void* elf_addr, size_t elf_length) {
|
||||||
name_ = name;
|
name_ = name;
|
||||||
|
|
|
@ -31,6 +31,7 @@ class ElfModule : public xe::cpu::Module {
|
||||||
bool loaded() const { return loaded_; }
|
bool loaded() const { return loaded_; }
|
||||||
uint32_t entry_point() const { return entry_point_; }
|
uint32_t entry_point() const { return entry_point_; }
|
||||||
const std::string& name() const override { return name_; }
|
const std::string& name() const override { return name_; }
|
||||||
|
bool is_executable() const override;
|
||||||
const std::string& path() const { return path_; }
|
const std::string& path() const { return path_; }
|
||||||
|
|
||||||
bool Load(const std::string& name, const std::string& path,
|
bool Load(const std::string& name, const std::string& path,
|
||||||
|
|
|
@ -34,6 +34,7 @@ class Module {
|
||||||
Memory* memory() const { return memory_; }
|
Memory* memory() const { return memory_; }
|
||||||
|
|
||||||
virtual const std::string& name() const = 0;
|
virtual const std::string& name() const = 0;
|
||||||
|
virtual bool is_executable() const = 0;
|
||||||
|
|
||||||
virtual bool ContainsAddress(uint32_t address);
|
virtual bool ContainsAddress(uint32_t address);
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,7 @@ class BuiltinModule : public Module {
|
||||||
: Module(processor), name_("builtin") {}
|
: Module(processor), name_("builtin") {}
|
||||||
|
|
||||||
const std::string& name() const override { return name_; }
|
const std::string& name() const override { return name_; }
|
||||||
|
bool is_executable() const override { return false; }
|
||||||
|
|
||||||
bool ContainsAddress(uint32_t address) override {
|
bool ContainsAddress(uint32_t address) override {
|
||||||
return (address & 0xFFFFFFF0) == 0xFFFFFFF0;
|
return (address & 0xFFFFFFF0) == 0xFFFFFFF0;
|
||||||
|
|
|
@ -29,7 +29,9 @@ class RawModule : public Module {
|
||||||
void SetAddressRange(uint32_t base_address, uint32_t size);
|
void SetAddressRange(uint32_t base_address, uint32_t size);
|
||||||
|
|
||||||
const std::string& name() const override { return name_; }
|
const std::string& name() const override { return name_; }
|
||||||
|
bool is_executable() const override { return is_executable_; }
|
||||||
void set_name(const std::string& name) { name_ = name; }
|
void set_name(const std::string& name) { name_ = name; }
|
||||||
|
void set_executable(bool is_executable) { is_executable_ = is_executable; }
|
||||||
|
|
||||||
bool ContainsAddress(uint32_t address) override;
|
bool ContainsAddress(uint32_t address) override;
|
||||||
|
|
||||||
|
@ -38,6 +40,7 @@ class RawModule : public Module {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string name_;
|
std::string name_;
|
||||||
|
bool is_executable_ = false;
|
||||||
uint32_t base_address_;
|
uint32_t base_address_;
|
||||||
uint32_t low_address_;
|
uint32_t low_address_;
|
||||||
uint32_t high_address_;
|
uint32_t high_address_;
|
||||||
|
|
|
@ -30,6 +30,7 @@ class TestModule : public Module {
|
||||||
~TestModule() override;
|
~TestModule() override;
|
||||||
|
|
||||||
const std::string& name() const override { return name_; }
|
const std::string& name() const override { return name_; }
|
||||||
|
bool is_executable() const override { return false; }
|
||||||
|
|
||||||
bool ContainsAddress(uint32_t address) override;
|
bool ContainsAddress(uint32_t address) override;
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,9 @@ class XexModule : public xe::cpu::Module {
|
||||||
bool Unload();
|
bool Unload();
|
||||||
|
|
||||||
const std::string& name() const override { return name_; }
|
const std::string& name() const override { return name_; }
|
||||||
|
bool is_executable() const override {
|
||||||
|
return (xex_header()->module_flags & XEX_MODULE_TITLE) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool ContainsAddress(uint32_t address) override;
|
bool ContainsAddress(uint32_t address) override;
|
||||||
|
|
||||||
|
|
|
@ -564,12 +564,10 @@ X_STATUS Emulator::CompleteLaunch(const std::wstring& path,
|
||||||
title_id_ = info->title_id;
|
title_id_ = info->title_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
kernel_state_->SetExecutableModule(module);
|
|
||||||
|
|
||||||
// Try and load the resource database (xex only).
|
// Try and load the resource database (xex only).
|
||||||
if (module->title_id()) {
|
if (module->title_id()) {
|
||||||
char title_id[9] = {0};
|
char title_id[9] = {0};
|
||||||
std::sprintf(title_id, "%08X", module->title_id());
|
std::snprintf(title_id, xe::countof(title_id), "%08X", module->title_id());
|
||||||
uint32_t resource_data = 0;
|
uint32_t resource_data = 0;
|
||||||
uint32_t resource_size = 0;
|
uint32_t resource_size = 0;
|
||||||
if (XSUCCEEDED(
|
if (XSUCCEEDED(
|
||||||
|
@ -586,7 +584,7 @@ X_STATUS Emulator::CompleteLaunch(const std::wstring& path,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto main_xthread = module->Launch();
|
auto main_xthread = kernel_state_->LaunchModule(module);
|
||||||
if (!main_xthread) {
|
if (!main_xthread) {
|
||||||
return X_STATUS_UNSUCCESSFUL;
|
return X_STATUS_UNSUCCESSFUL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,21 +64,6 @@ KernelState::KernelState(Emulator* emulator)
|
||||||
assert_null(shared_kernel_state_);
|
assert_null(shared_kernel_state_);
|
||||||
shared_kernel_state_ = this;
|
shared_kernel_state_ = this;
|
||||||
|
|
||||||
process_info_block_address_ = memory_->SystemHeapAlloc(0x60);
|
|
||||||
|
|
||||||
auto pib =
|
|
||||||
memory_->TranslateVirtual<ProcessInfoBlock*>(process_info_block_address_);
|
|
||||||
// TODO(benvanik): figure out what this list is.
|
|
||||||
pib->unk_04 = pib->unk_08 = 0;
|
|
||||||
pib->unk_0C = 0x0000007F;
|
|
||||||
pib->unk_10 = 0x001F0000;
|
|
||||||
pib->thread_count = 0;
|
|
||||||
pib->unk_1B = 0x06;
|
|
||||||
pib->kernel_stack_size = 16 * 1024;
|
|
||||||
pib->process_type = process_type_;
|
|
||||||
// TODO(benvanik): figure out what this list is.
|
|
||||||
pib->unk_54 = pib->unk_58 = 0;
|
|
||||||
|
|
||||||
// Hardcoded maximum of 2048 TLS slots.
|
// Hardcoded maximum of 2048 TLS slots.
|
||||||
tls_bitmap_.Resize(2048);
|
tls_bitmap_.Resize(2048);
|
||||||
|
|
||||||
|
@ -104,10 +89,6 @@ KernelState::~KernelState() {
|
||||||
// Shutdown apps.
|
// Shutdown apps.
|
||||||
app_manager_.reset();
|
app_manager_.reset();
|
||||||
|
|
||||||
if (process_info_block_address_) {
|
|
||||||
memory_->SystemHeapFree(process_info_block_address_);
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_true(shared_kernel_state_ == this);
|
assert_true(shared_kernel_state_ == this);
|
||||||
shared_kernel_state_ = nullptr;
|
shared_kernel_state_ = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -253,6 +234,43 @@ object_ref<XModule> KernelState::GetModule(const char* name, bool user_only) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object_ref<XThread> KernelState::LaunchModule(object_ref<UserModule> module) {
|
||||||
|
if (!module->is_executable()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetExecutableModule(module);
|
||||||
|
XELOGI("KernelState: Launching module...");
|
||||||
|
|
||||||
|
// Create a thread to run in.
|
||||||
|
// We start suspended so we can run the debugger prep.
|
||||||
|
auto thread = object_ref<XThread>(
|
||||||
|
new XThread(kernel_state(), module->stack_size(), 0,
|
||||||
|
module->entry_point(), 0, X_CREATE_SUSPENDED, true, true));
|
||||||
|
|
||||||
|
// We know this is the 'main thread'.
|
||||||
|
char thread_name[32];
|
||||||
|
std::snprintf(thread_name, xe::countof(thread_name), "Main XThread%08X",
|
||||||
|
thread->handle());
|
||||||
|
thread->set_name(thread_name);
|
||||||
|
|
||||||
|
X_STATUS result = thread->Create();
|
||||||
|
if (XFAILED(result)) {
|
||||||
|
XELOGE("Could not create launch thread: %.8X", result);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Waits for a debugger client, if desired.
|
||||||
|
emulator()->processor()->PreLaunch();
|
||||||
|
|
||||||
|
// Resume the thread now.
|
||||||
|
// If the debugger has requested a suspend this will just decrement the
|
||||||
|
// suspend count without resuming it until the debugger wants.
|
||||||
|
thread->Resume();
|
||||||
|
|
||||||
|
return thread;
|
||||||
|
}
|
||||||
|
|
||||||
object_ref<UserModule> KernelState::GetExecutableModule() {
|
object_ref<UserModule> KernelState::GetExecutableModule() {
|
||||||
if (!executable_module_) {
|
if (!executable_module_) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -269,6 +287,22 @@ void KernelState::SetExecutableModule(object_ref<UserModule> module) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert_zero(process_info_block_address_);
|
||||||
|
process_info_block_address_ = memory_->SystemHeapAlloc(0x60);
|
||||||
|
|
||||||
|
auto pib =
|
||||||
|
memory_->TranslateVirtual<ProcessInfoBlock*>(process_info_block_address_);
|
||||||
|
// TODO(benvanik): figure out what this list is.
|
||||||
|
pib->unk_04 = pib->unk_08 = 0;
|
||||||
|
pib->unk_0C = 0x0000007F;
|
||||||
|
pib->unk_10 = 0x001F0000;
|
||||||
|
pib->thread_count = 0;
|
||||||
|
pib->unk_1B = 0x06;
|
||||||
|
pib->kernel_stack_size = 16 * 1024;
|
||||||
|
pib->process_type = process_type_;
|
||||||
|
// TODO(benvanik): figure out what this list is.
|
||||||
|
pib->unk_54 = pib->unk_58 = 0;
|
||||||
|
|
||||||
xex2_opt_tls_info* tls_header = nullptr;
|
xex2_opt_tls_info* tls_header = nullptr;
|
||||||
executable_module_->GetOptHeader(XEX_HEADER_TLS_INFO, &tls_header);
|
executable_module_->GetOptHeader(XEX_HEADER_TLS_INFO, &tls_header);
|
||||||
if (tls_header) {
|
if (tls_header) {
|
||||||
|
@ -399,15 +433,9 @@ void KernelState::TerminateTitle() {
|
||||||
|
|
||||||
// Kill all guest threads.
|
// Kill all guest threads.
|
||||||
for (auto it = threads_by_id_.begin(); it != threads_by_id_.end();) {
|
for (auto it = threads_by_id_.begin(); it != threads_by_id_.end();) {
|
||||||
if (it->second->is_guest_thread()) {
|
if (!XThread::IsInThread(it->second) && it->second->is_guest_thread()) {
|
||||||
auto thread = it->second;
|
auto thread = it->second;
|
||||||
|
|
||||||
if (XThread::IsInThread(thread)) {
|
|
||||||
// Don't terminate ourselves.
|
|
||||||
++it;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (thread->is_running()) {
|
if (thread->is_running()) {
|
||||||
// Need to step the thread to a safe point (returns it to guest code
|
// Need to step the thread to a safe point (returns it to guest code
|
||||||
// so it's guaranteed to not be holding any locks / in host kernel
|
// so it's guaranteed to not be holding any locks / in host kernel
|
||||||
|
@ -447,6 +475,14 @@ void KernelState::TerminateTitle() {
|
||||||
// Clear the TLS map.
|
// Clear the TLS map.
|
||||||
tls_bitmap_.Reset();
|
tls_bitmap_.Reset();
|
||||||
|
|
||||||
|
// Unset the executable module.
|
||||||
|
executable_module_ = nullptr;
|
||||||
|
|
||||||
|
if (process_info_block_address_) {
|
||||||
|
memory_->SystemHeapFree(process_info_block_address_);
|
||||||
|
process_info_block_address_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (XThread::IsInThread()) {
|
if (XThread::IsInThread()) {
|
||||||
threads_by_id_.erase(XThread::GetCurrentThread()->thread_id());
|
threads_by_id_.erase(XThread::GetCurrentThread()->thread_id());
|
||||||
|
|
||||||
|
@ -461,9 +497,11 @@ void KernelState::RegisterThread(XThread* thread) {
|
||||||
auto global_lock = global_critical_region_.Acquire();
|
auto global_lock = global_critical_region_.Acquire();
|
||||||
threads_by_id_[thread->thread_id()] = thread;
|
threads_by_id_[thread->thread_id()] = thread;
|
||||||
|
|
||||||
|
/*
|
||||||
auto pib =
|
auto pib =
|
||||||
memory_->TranslateVirtual<ProcessInfoBlock*>(process_info_block_address_);
|
memory_->TranslateVirtual<ProcessInfoBlock*>(process_info_block_address_);
|
||||||
pib->thread_count = pib->thread_count + 1;
|
pib->thread_count = pib->thread_count + 1;
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void KernelState::UnregisterThread(XThread* thread) {
|
void KernelState::UnregisterThread(XThread* thread) {
|
||||||
|
@ -473,9 +511,11 @@ void KernelState::UnregisterThread(XThread* thread) {
|
||||||
threads_by_id_.erase(it);
|
threads_by_id_.erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
auto pib =
|
auto pib =
|
||||||
memory_->TranslateVirtual<ProcessInfoBlock*>(process_info_block_address_);
|
memory_->TranslateVirtual<ProcessInfoBlock*>(process_info_block_address_);
|
||||||
pib->thread_count = pib->thread_count - 1;
|
pib->thread_count = pib->thread_count - 1;
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void KernelState::OnThreadExecute(XThread* thread) {
|
void KernelState::OnThreadExecute(XThread* thread) {
|
||||||
|
|
|
@ -129,6 +129,7 @@ class KernelState {
|
||||||
bool IsKernelModule(const char* name);
|
bool IsKernelModule(const char* name);
|
||||||
object_ref<XModule> GetModule(const char* name, bool user_only = false);
|
object_ref<XModule> GetModule(const char* name, bool user_only = false);
|
||||||
|
|
||||||
|
object_ref<XThread> LaunchModule(object_ref<UserModule> module);
|
||||||
object_ref<UserModule> GetExecutableModule();
|
object_ref<UserModule> GetExecutableModule();
|
||||||
void SetExecutableModule(object_ref<UserModule> module);
|
void SetExecutableModule(object_ref<UserModule> module);
|
||||||
object_ref<UserModule> LoadUserModule(const char* name,
|
object_ref<UserModule> LoadUserModule(const char* name,
|
||||||
|
|
|
@ -299,38 +299,6 @@ X_STATUS UserModule::GetOptHeader(uint8_t* membase, const xex2_header* header,
|
||||||
return X_STATUS_SUCCESS;
|
return X_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
object_ref<XThread> UserModule::Launch(uint32_t flags) {
|
|
||||||
XELOGI("Launching module...");
|
|
||||||
|
|
||||||
// Create a thread to run in.
|
|
||||||
// We start suspended so we can run the debugger prep.
|
|
||||||
auto thread = object_ref<XThread>(
|
|
||||||
new XThread(kernel_state(), stack_size_, 0, entry_point_, 0,
|
|
||||||
X_CREATE_SUSPENDED, true, true));
|
|
||||||
|
|
||||||
// We know this is the 'main thread'.
|
|
||||||
char thread_name[32];
|
|
||||||
std::snprintf(thread_name, xe::countof(thread_name), "Main XThread%08X",
|
|
||||||
thread->handle());
|
|
||||||
thread->set_name(thread_name);
|
|
||||||
|
|
||||||
X_STATUS result = thread->Create();
|
|
||||||
if (XFAILED(result)) {
|
|
||||||
XELOGE("Could not create launch thread: %.8X", result);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Waits for a debugger client, if desired.
|
|
||||||
emulator()->processor()->PreLaunch();
|
|
||||||
|
|
||||||
// Resume the thread now.
|
|
||||||
// If the debugger has requested a suspend this will just decrement the
|
|
||||||
// suspend count without resuming it until the debugger wants.
|
|
||||||
thread->Resume();
|
|
||||||
|
|
||||||
return thread;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UserModule::Save(ByteStream* stream) {
|
bool UserModule::Save(ByteStream* stream) {
|
||||||
if (!XModule::Save(stream)) {
|
if (!XModule::Save(stream)) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -55,6 +55,7 @@ class UserModule : public XModule {
|
||||||
uint32_t guest_xex_header() const { return guest_xex_header_; }
|
uint32_t guest_xex_header() const { return guest_xex_header_; }
|
||||||
// The title ID in the xex header or 0 if this is not a xex.
|
// The title ID in the xex header or 0 if this is not a xex.
|
||||||
uint32_t title_id() const;
|
uint32_t title_id() const;
|
||||||
|
bool is_executable() const { return processor_module_->is_executable(); }
|
||||||
bool is_dll_module() const { return is_dll_module_; }
|
bool is_dll_module() const { return is_dll_module_; }
|
||||||
|
|
||||||
uint32_t entry_point() const { return entry_point_; }
|
uint32_t entry_point() const { return entry_point_; }
|
||||||
|
@ -85,8 +86,6 @@ class UserModule : public XModule {
|
||||||
xe_xex2_header_keys key,
|
xe_xex2_header_keys key,
|
||||||
uint32_t* out_header_guest_ptr);
|
uint32_t* out_header_guest_ptr);
|
||||||
|
|
||||||
object_ref<XThread> Launch(uint32_t flags = 0);
|
|
||||||
|
|
||||||
void Dump();
|
void Dump();
|
||||||
|
|
||||||
bool Save(ByteStream* stream) override;
|
bool Save(ByteStream* stream) override;
|
||||||
|
|
Loading…
Reference in New Issue