KernelState should handle module launching

This commit is contained in:
Dr. Chat 2016-10-24 11:00:22 -05:00
parent 69be82c786
commit a148b965f1
12 changed files with 85 additions and 64 deletions

View File

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

View File

@ -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,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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,

View File

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

View File

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