/** ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** * Copyright 2013 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ #include #include #include #include #include #include #include #include #include #include #include #include #include namespace xe { using namespace xe::apu; using namespace xe::cpu; using namespace xe::gpu; using namespace xe::hid; using namespace xe::kernel; using namespace xe::kernel::fs; using namespace xe::ui; Emulator::Emulator(const std::wstring& command_line) : command_line_(command_line), main_window_(nullptr) {} Emulator::~Emulator() { // Note that we delete things in the reverse order they were initialized. auto ev = xdb::protocol::ProcessExitEvent::Append(memory()->trace_base()); if (ev) { ev->type = xdb::protocol::EventType::PROCESS_EXIT; } if (main_window_) { main_window_->Close(); } debug_agent_.reset(); xam_.reset(); xboxkrnl_.reset(); kernel_state_.reset(); file_system_.reset(); input_system_.reset(); // Give the systems time to shutdown before we delete them. graphics_system_->Shutdown(); audio_system_->Shutdown(); graphics_system_.reset(); audio_system_.reset(); processor_.reset(); export_resolver_.reset(); } X_STATUS Emulator::Setup() { X_STATUS result = X_STATUS_UNSUCCESSFUL; debug_agent_.reset(new DebugAgent(this)); result = debug_agent_->Initialize(); if (result) { return result; } // Create memory system first, as it is required for other systems. memory_ = std::make_unique(); result = memory_->Initialize(); if (result) { return result; } memory_->set_trace_base(debug_agent_->trace_base()); // Shared export resolver used to attach and query for HLE exports. export_resolver_ = std::make_unique(); // Initialize the CPU. processor_ = std::make_unique(memory_.get(), export_resolver_.get()); // Initialize the APU. audio_system_ = std::move(xe::apu::Create(this)); if (!audio_system_) { return X_STATUS_NOT_IMPLEMENTED; } // Initialize the GPU. graphics_system_ = std::move(xe::gpu::Create(this)); if (!graphics_system_) { return X_STATUS_NOT_IMPLEMENTED; } // Initialize the HID. input_system_ = std::move(xe::hid::Create(this)); if (!input_system_) { return X_STATUS_NOT_IMPLEMENTED; } // Setup the core components. result = processor_->Setup(); if (result) { return result; } result = audio_system_->Setup(); if (result) { return result; } result = graphics_system_->Setup(); if (result) { return result; } result = input_system_->Setup(); if (result) { return result; } // Bring up the virtual filesystem used by the kernel. file_system_ = std::make_unique(); // Shared kernel state. kernel_state_ = std::make_unique(this); // HLE kernel modules. xboxkrnl_ = std::make_unique(this, kernel_state_.get()); xam_ = std::make_unique(this, kernel_state_.get()); return result; } void Emulator::set_main_window(Window* window) { assert_null(main_window_); main_window_ = window; window->closed.AddListener([](UIEvent& e) { // TODO(benvanik): call module API to kill? this is a bad shutdown. exit(1); }); } X_STATUS Emulator::LaunchXexFile(const std::wstring& path) { // We create a virtual filesystem pointing to its directory and symlink // that to the game filesystem. // e.g., /my/files/foo.xex will get a local fs at: // \\Device\\Harddisk0\\Partition1 // and then get that symlinked to game:\, so // -> game:\foo.xex int result_code = file_system_->InitializeFromPath(FileSystemType::XEX_FILE, path); if (result_code) { return X_STATUS_INVALID_PARAMETER; } // Get just the filename (foo.xex). std::wstring file_name; auto last_slash = path.find_last_of(poly::path_separator); if (last_slash == std::string::npos) { // No slash found, whole thing is a file. file_name = path; } else { // Skip slash. file_name = path.substr(last_slash + 1); } // Launch the game. std::string fs_path = "game:\\" + poly::to_string(file_name); return CompleteLaunch(path, fs_path); } X_STATUS Emulator::LaunchDiscImage(const std::wstring& path) { int result_code = file_system_->InitializeFromPath(FileSystemType::DISC_IMAGE, path); if (result_code) { return X_STATUS_INVALID_PARAMETER; } // Launch the game. return CompleteLaunch(path, "game:\\default.xex"); } X_STATUS Emulator::LaunchSTFSTitle(const std::wstring& path) { int result_code = file_system_->InitializeFromPath(FileSystemType::STFS_TITLE, path); if (result_code) { return X_STATUS_INVALID_PARAMETER; } // Launch the game. return CompleteLaunch(path, "game:\\default.xex"); } X_STATUS Emulator::CompleteLaunch(const std::wstring& path, const std::string& module_path) { auto ev = xdb::protocol::ProcessStartEvent::Append(memory()->trace_base()); if (ev) { ev->type = xdb::protocol::EventType::PROCESS_START; ev->membase = reinterpret_cast(memory()->membase()); auto path_length = poly::to_string(path) .copy(ev->launch_path, sizeof(ev->launch_path) - 1); ev->launch_path[path_length] = 0; } return xboxkrnl_->LaunchModule(module_path.c_str()); } } // namespace xe