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;
|
||||
};
|
||||
|
||||
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,
|
||||
const void* elf_addr, size_t elf_length) {
|
||||
name_ = name;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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<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.
|
||||
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<XModule> KernelState::GetModule(const char* name, bool user_only) {
|
|||
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() {
|
||||
if (!executable_module_) {
|
||||
return nullptr;
|
||||
|
@ -269,6 +287,22 @@ void KernelState::SetExecutableModule(object_ref<UserModule> module) {
|
|||
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;
|
||||
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<ProcessInfoBlock*>(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<ProcessInfoBlock*>(process_info_block_address_);
|
||||
pib->thread_count = pib->thread_count - 1;
|
||||
*/
|
||||
}
|
||||
|
||||
void KernelState::OnThreadExecute(XThread* thread) {
|
||||
|
|
|
@ -129,6 +129,7 @@ class KernelState {
|
|||
bool IsKernelModule(const char* name);
|
||||
object_ref<XModule> GetModule(const char* name, bool user_only = false);
|
||||
|
||||
object_ref<XThread> LaunchModule(object_ref<UserModule> module);
|
||||
object_ref<UserModule> GetExecutableModule();
|
||||
void SetExecutableModule(object_ref<UserModule> module);
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
if (!XModule::Save(stream)) {
|
||||
return false;
|
||||
|
|
|
@ -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<XThread> Launch(uint32_t flags = 0);
|
||||
|
||||
void Dump();
|
||||
|
||||
bool Save(ByteStream* stream) override;
|
||||
|
|
Loading…
Reference in New Issue