diff --git a/src/xenia/cpu/elf_module.cc b/src/xenia/cpu/elf_module.cc index 5fb0d223f..1732cff03 100644 --- a/src/xenia/cpu/elf_module.cc +++ b/src/xenia/cpu/elf_module.cc @@ -53,6 +53,11 @@ struct elf32_phdr { xe::be p_align; }; +bool ElfModule::is_executable() const { + auto hdr = reinterpret_cast(elf_header_mem_.data()); + return hdr->e_entry != 0; +} + bool ElfModule::Load(const std::string& name, const std::string& path, const void* elf_addr, size_t elf_length) { name_ = name; diff --git a/src/xenia/cpu/elf_module.h b/src/xenia/cpu/elf_module.h index 470b9671f..c8bbd3cb0 100644 --- a/src/xenia/cpu/elf_module.h +++ b/src/xenia/cpu/elf_module.h @@ -31,6 +31,7 @@ class ElfModule : public xe::cpu::Module { bool loaded() const { return loaded_; } uint32_t entry_point() const { return entry_point_; } const std::string& name() const override { return name_; } + bool is_executable() const override; const std::string& path() const { return path_; } bool Load(const std::string& name, const std::string& path, diff --git a/src/xenia/cpu/module.h b/src/xenia/cpu/module.h index ba7ae2477..f958b4309 100644 --- a/src/xenia/cpu/module.h +++ b/src/xenia/cpu/module.h @@ -34,6 +34,7 @@ class Module { Memory* memory() const { return memory_; } virtual const std::string& name() const = 0; + virtual bool is_executable() const = 0; virtual bool ContainsAddress(uint32_t address); diff --git a/src/xenia/cpu/processor.cc b/src/xenia/cpu/processor.cc index 19e9dfaeb..3c6341088 100644 --- a/src/xenia/cpu/processor.cc +++ b/src/xenia/cpu/processor.cc @@ -60,6 +60,7 @@ class BuiltinModule : public Module { : Module(processor), name_("builtin") {} const std::string& name() const override { return name_; } + bool is_executable() const override { return false; } bool ContainsAddress(uint32_t address) override { return (address & 0xFFFFFFF0) == 0xFFFFFFF0; diff --git a/src/xenia/cpu/raw_module.h b/src/xenia/cpu/raw_module.h index d743f15e2..d7687643e 100644 --- a/src/xenia/cpu/raw_module.h +++ b/src/xenia/cpu/raw_module.h @@ -29,7 +29,9 @@ class RawModule : public Module { void SetAddressRange(uint32_t base_address, uint32_t size); 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_executable(bool is_executable) { is_executable_ = is_executable; } bool ContainsAddress(uint32_t address) override; @@ -38,6 +40,7 @@ class RawModule : public Module { private: std::string name_; + bool is_executable_ = false; uint32_t base_address_; uint32_t low_address_; uint32_t high_address_; diff --git a/src/xenia/cpu/test_module.h b/src/xenia/cpu/test_module.h index dfce7b731..c745a55f9 100644 --- a/src/xenia/cpu/test_module.h +++ b/src/xenia/cpu/test_module.h @@ -30,6 +30,7 @@ class TestModule : public Module { ~TestModule() override; const std::string& name() const override { return name_; } + bool is_executable() const override { return false; } bool ContainsAddress(uint32_t address) override; diff --git a/src/xenia/cpu/xex_module.h b/src/xenia/cpu/xex_module.h index 4ac52cd66..483945e08 100644 --- a/src/xenia/cpu/xex_module.h +++ b/src/xenia/cpu/xex_module.h @@ -75,6 +75,9 @@ class XexModule : public xe::cpu::Module { bool Unload(); 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; diff --git a/src/xenia/emulator.cc b/src/xenia/emulator.cc index 77c08217b..d5d68e588 100644 --- a/src/xenia/emulator.cc +++ b/src/xenia/emulator.cc @@ -564,12 +564,10 @@ X_STATUS Emulator::CompleteLaunch(const std::wstring& path, title_id_ = info->title_id; } - kernel_state_->SetExecutableModule(module); - // Try and load the resource database (xex only). if (module->title_id()) { 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_size = 0; 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) { return X_STATUS_UNSUCCESSFUL; } diff --git a/src/xenia/kernel/kernel_state.cc b/src/xenia/kernel/kernel_state.cc index c8314228b..0fa321c63 100644 --- a/src/xenia/kernel/kernel_state.cc +++ b/src/xenia/kernel/kernel_state.cc @@ -64,21 +64,6 @@ KernelState::KernelState(Emulator* emulator) assert_null(shared_kernel_state_); shared_kernel_state_ = this; - process_info_block_address_ = memory_->SystemHeapAlloc(0x60); - - auto pib = - memory_->TranslateVirtual(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. tls_bitmap_.Resize(2048); @@ -104,10 +89,6 @@ KernelState::~KernelState() { // Shutdown apps. app_manager_.reset(); - if (process_info_block_address_) { - memory_->SystemHeapFree(process_info_block_address_); - } - assert_true(shared_kernel_state_ == this); shared_kernel_state_ = nullptr; } @@ -253,6 +234,43 @@ object_ref KernelState::GetModule(const char* name, bool user_only) { return nullptr; } +object_ref KernelState::LaunchModule(object_ref 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( + 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 KernelState::GetExecutableModule() { if (!executable_module_) { return nullptr; @@ -269,6 +287,22 @@ void KernelState::SetExecutableModule(object_ref module) { return; } + assert_zero(process_info_block_address_); + process_info_block_address_ = memory_->SystemHeapAlloc(0x60); + + auto pib = + memory_->TranslateVirtual(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; executable_module_->GetOptHeader(XEX_HEADER_TLS_INFO, &tls_header); if (tls_header) { @@ -399,15 +433,9 @@ void KernelState::TerminateTitle() { // Kill all guest threads. 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; - if (XThread::IsInThread(thread)) { - // Don't terminate ourselves. - ++it; - continue; - } - if (thread->is_running()) { // 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 @@ -447,6 +475,14 @@ void KernelState::TerminateTitle() { // Clear the TLS map. 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()) { threads_by_id_.erase(XThread::GetCurrentThread()->thread_id()); @@ -461,9 +497,11 @@ void KernelState::RegisterThread(XThread* thread) { auto global_lock = global_critical_region_.Acquire(); threads_by_id_[thread->thread_id()] = thread; + /* auto pib = memory_->TranslateVirtual(process_info_block_address_); pib->thread_count = pib->thread_count + 1; + */ } void KernelState::UnregisterThread(XThread* thread) { @@ -473,9 +511,11 @@ void KernelState::UnregisterThread(XThread* thread) { threads_by_id_.erase(it); } + /* auto pib = memory_->TranslateVirtual(process_info_block_address_); pib->thread_count = pib->thread_count - 1; + */ } void KernelState::OnThreadExecute(XThread* thread) { diff --git a/src/xenia/kernel/kernel_state.h b/src/xenia/kernel/kernel_state.h index 691444aad..8ff2ec493 100644 --- a/src/xenia/kernel/kernel_state.h +++ b/src/xenia/kernel/kernel_state.h @@ -129,6 +129,7 @@ class KernelState { bool IsKernelModule(const char* name); object_ref GetModule(const char* name, bool user_only = false); + object_ref LaunchModule(object_ref module); object_ref GetExecutableModule(); void SetExecutableModule(object_ref module); object_ref LoadUserModule(const char* name, diff --git a/src/xenia/kernel/user_module.cc b/src/xenia/kernel/user_module.cc index 6674aeceb..93d05df8c 100644 --- a/src/xenia/kernel/user_module.cc +++ b/src/xenia/kernel/user_module.cc @@ -299,38 +299,6 @@ X_STATUS UserModule::GetOptHeader(uint8_t* membase, const xex2_header* header, return X_STATUS_SUCCESS; } -object_ref 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( - 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) { if (!XModule::Save(stream)) { return false; diff --git a/src/xenia/kernel/user_module.h b/src/xenia/kernel/user_module.h index d066288e7..36c88309b 100644 --- a/src/xenia/kernel/user_module.h +++ b/src/xenia/kernel/user_module.h @@ -55,6 +55,7 @@ class UserModule : public XModule { 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. uint32_t title_id() const; + bool is_executable() const { return processor_module_->is_executable(); } bool is_dll_module() const { return is_dll_module_; } uint32_t entry_point() const { return entry_point_; } @@ -85,8 +86,6 @@ class UserModule : public XModule { xe_xex2_header_keys key, uint32_t* out_header_guest_ptr); - object_ref Launch(uint32_t flags = 0); - void Dump(); bool Save(ByteStream* stream) override;