diff --git a/src/xenia/cpu/ppc/ppc_emit_memory.cc b/src/xenia/cpu/ppc/ppc_emit_memory.cc index c1507cb4c..36fb1d392 100644 --- a/src/xenia/cpu/ppc/ppc_emit_memory.cc +++ b/src/xenia/cpu/ppc/ppc_emit_memory.cc @@ -14,7 +14,9 @@ #include "xenia/cpu/ppc/ppc_context.h" #include "xenia/cpu/ppc/ppc_hir_builder.h" -DEFINE_bool(UE_HACK, true, "Hack for Unreal Engine 3 titles to run", "CPU"); +DEFINE_bool(UE_Workaround, true, + "Workaround for Unreal Engine 3 titles to run, try disabling if other games have problems", + "CPU"); namespace xe { namespace cpu { @@ -1083,7 +1085,7 @@ int InstrEmit_stfsx(PPCHIRBuilder& f, const InstrData& i) { int InstrEmit_dcbf(PPCHIRBuilder& f, const InstrData& i) { //UE Hack - if ((i.X.RB == 11) && (cvars::UE_HACK) && (f.CompareEQ(f.LoadGPR(i.X.RB), f.LoadConstantUint16(0xFEED)))) { + if ((i.X.RB == 11) && (cvars::UE_Workaround) && (f.CompareEQ(f.LoadGPR(i.X.RB), f.LoadConstantUint16(0xFEED)))) { Value* val = f.Sub(f.LoadGPR(i.X.RB), f.LoadConstantUint64(0x0004)); f.StoreGPR(i.X.RB, val); } else { diff --git a/src/xenia/emulator.cc b/src/xenia/emulator.cc index 1ca699e24..dff59f963 100644 --- a/src/xenia/emulator.cc +++ b/src/xenia/emulator.cc @@ -659,6 +659,7 @@ X_STATUS Emulator::CompleteLaunch(const std::wstring& path, module->GetOptHeader(XEX_HEADER_EXECUTION_INFO, &info); if (info) { title_id_ = info->title_id; + xe::LogLineFormat(xe::LogLevel::Error, 'i', "Title ID : %.8X\n", title_id_); } // Try and load the resource database (xex only). diff --git a/src/xenia/kernel/user_module.cc.orig b/src/xenia/kernel/user_module.cc.orig deleted file mode 100644 index 3e4cbbcfd..000000000 --- a/src/xenia/kernel/user_module.cc.orig +++ /dev/null @@ -1,856 +0,0 @@ -/** - ****************************************************************************** - * 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 "xenia/kernel/user_module.h" - -#include - -#include "xenia/base/byte_stream.h" -#include "xenia/base/logging.h" -#include "xenia/cpu/elf_module.h" -#include "xenia/cpu/processor.h" -#include "xenia/cpu/xex_module.h" -#include "xenia/emulator.h" -#include "xenia/kernel/xfile.h" -#include "xenia/kernel/xthread.h" -#include "xenia/vfs/devices/stfs_container_device.h" - -DEFINE_bool(xex_apply_patches, true, "Apply XEX patches.", "Kernel"); - -namespace xe { -namespace kernel { - -UserModule::UserModule(KernelState* kernel_state) - : XModule(kernel_state, ModuleType::kUserModule) {} - -UserModule::~UserModule() { Unload(); } - -uint32_t UserModule::title_id() const { - if (module_format_ != kModuleFormatXex) { - return 0; - } - auto header = xex_header(); - for (uint32_t i = 0; i < header->header_count; i++) { - auto& opt_header = header->headers[i]; - if (opt_header.key == XEX_HEADER_EXECUTION_INFO) { - auto opt_header_ptr = - reinterpret_cast(header) + opt_header.offset; - auto opt_exec_info = - reinterpret_cast(opt_header_ptr); - return static_cast(opt_exec_info->title_id); - } - } - return 0; -} - -X_STATUS UserModule::LoadFromFile(std::string path) { - X_STATUS result = X_STATUS_UNSUCCESSFUL; - - auto file_system = kernel_state()->file_system(); - - // Resolve the file to open. - // TODO(benvanik): make this code shared? - auto fs_entry = file_system->ResolvePath(path); - if (!fs_entry) { - XELOGE("File not found: %s", path.c_str()); - return X_STATUS_NO_SUCH_FILE; - } - - path_ = fs_entry->absolute_path(); - name_ = NameFromPath(path_); - - // If the FS supports mapping, map the file in and load from that. - if (fs_entry->can_map()) { - // Map. - auto mmap = fs_entry->OpenMapped(MappedMemory::Mode::kRead); - if (!mmap) { - return result; - } - - // Load the module. - result = LoadFromMemory(mmap->data(), mmap->size()); - } else { - std::vector buffer(fs_entry->size()); - - // Open file for reading. - vfs::File* file = nullptr; - result = fs_entry->Open(vfs::FileAccess::kGenericRead, &file); - if (XFAILED(result)) { - return result; - } - - // Read entire file into memory. - // Ugh. - size_t bytes_read = 0; - result = file->ReadSync(buffer.data(), buffer.size(), 0, &bytes_read); - if (XFAILED(result)) { - return result; - } - - // Load the module. - result = LoadFromMemory(buffer.data(), bytes_read); - - // Close the file. - file->Destroy(); - } - - // Only XEX returns X_STATUS_PENDING - if (result != X_STATUS_PENDING) { - return result; - } - -<<<<<<< HEAD - if (cvars::xex_apply_patches) { - // Search for xexp patch file - auto patch_entry = kernel_state()->file_system()->ResolvePath(path_ + "p"); -======= - if (!FLAGS_xex_apply_patches) { - return LoadXexContinue(); - } - - auto module_path = fs_entry->path(); - - auto content_manager = kernel_state()->content_manager(); - - if (!file_system->IsSymbolicLink("update:")) { - // update:\\ path isn't symlinked, try searching for an update package ->>>>>>> emoose/title-updates - - xex2_opt_execution_info* exec_info = 0; - xex_module()->GetOptHeader(XEX_HEADER_EXECUTION_INFO, &exec_info); - - if (exec_info) { - content_manager->SetTitleIdOverride(exec_info->title_id); - - auto update_packages = content_manager->ListContent( - 0, (uint32_t)vfs::StfsContentType::kInstaller); - - for (auto& update : update_packages) { - auto result = content_manager->OpenContent("update", update); - - if (!file_system->ResolvePath("update:\\" + module_path + "p")) { - // XEXP/DLLP doesn't exist in this package, lets just close it - content_manager->CloseContent("update"); - continue; - } else { - // XEXP/DLLP found, break out of package loop - // TODO: verify XEXP/DLLP works first? - break; - } - } - } - } - - // Unset content_manager title ID override - content_manager->SetTitleIdOverride(0); - - // First try checking update:\ root for patch, otherwise try same path as XEX - auto patch_entry = file_system->ResolvePath("update:\\" + module_path + "p"); - if (!patch_entry) { - patch_entry = file_system->ResolvePath(path_ + "p"); - } - if (patch_entry) { - auto patch_path = patch_entry->absolute_path(); - - XELOGI("Loading XEX patch from %s", patch_path.c_str()); - - auto patch_module = object_ref(new UserModule(kernel_state_)); - result = patch_module->LoadFromFile(patch_path); - if (!result) { - result = patch_module->xex_module()->ApplyPatch(xex_module()); - if (result) { - XELOGE("Failed to apply XEX patch, code: %d", result); - } - } else { - XELOGE("Failed to load XEX patch, code: %d", result); - } - - if (result) { - return X_STATUS_UNSUCCESSFUL; - } - } - - return LoadXexContinue(); -} - -X_STATUS UserModule::LoadFromMemory(const void* addr, const size_t length) { - auto processor = kernel_state()->processor(); - - auto magic = xe::load_and_swap(addr); - if (magic == 'XEX2') { - module_format_ = kModuleFormatXex; - } else if (magic == 0x7F454C46 /* 0x7F 'ELF' */) { - module_format_ = kModuleFormatElf; - } else { - auto magic16 = xe::load_and_swap(addr); - if (magic16 == 0x4D5A) { - XELOGE("XNA executables are not yet implemented"); - return X_STATUS_NOT_IMPLEMENTED; - } else { - XELOGE("Unknown module magic: %.8X", magic); - return X_STATUS_NOT_IMPLEMENTED; - } - } - - if (module_format_ == kModuleFormatXex) { - // Prepare the module for execution. - // Runtime takes ownership. - auto xex_module = - std::make_unique(processor, kernel_state()); - if (!xex_module->Load(name_, path_, addr, length)) { - return X_STATUS_UNSUCCESSFUL; - } - processor_module_ = xex_module.get(); - if (!processor->AddModule(std::move(xex_module))) { - return X_STATUS_UNSUCCESSFUL; - } - - // Only XEX headers + image are loaded right now - // Caller will have to call LoadXexContinue after they've loaded in a patch - // (or after patch isn't found anywhere) - // or if this is an XEXP being loaded return success since there's nothing - // else to load - return this->xex_module()->is_patch() ? X_STATUS_SUCCESS : X_STATUS_PENDING; - - } else if (module_format_ == kModuleFormatElf) { - auto elf_module = - std::make_unique(processor, kernel_state()); - if (!elf_module->Load(name_, path_, addr, length)) { - return X_STATUS_UNSUCCESSFUL; - } - - entry_point_ = elf_module->entry_point(); - stack_size_ = 1024 * 1024; // 1 MB - is_dll_module_ = false; // Hardcoded not a DLL (for now) - - processor_module_ = elf_module.get(); - if (!processor->AddModule(std::move(elf_module))) { - return X_STATUS_UNSUCCESSFUL; - } - } - - OnLoad(); - - return X_STATUS_SUCCESS; -} - -X_STATUS UserModule::LoadXexContinue() { - // LoadXexContinue: finishes loading XEX after a patch has been applied (or - // patch wasn't found) - - if (!this->xex_module()) { - return X_STATUS_UNSUCCESSFUL; - } - - // If guest_xex_header is set we must have already loaded the XEX - if (guest_xex_header_) { - return X_STATUS_SUCCESS; - } - - // Finish XexModule load (PE sections/imports/symbols...) - if (!xex_module()->LoadContinue()) { - return X_STATUS_UNSUCCESSFUL; - } - - // Copy the xex2 header into guest memory. - auto header = this->xex_module()->xex_header(); - auto security_header = this->xex_module()->xex_security_info(); - guest_xex_header_ = memory()->SystemHeapAlloc(header->header_size); - - uint8_t* xex_header_ptr = memory()->TranslateVirtual(guest_xex_header_); - std::memcpy(xex_header_ptr, header, header->header_size); - - // Cache some commonly used headers... - this->xex_module()->GetOptHeader(XEX_HEADER_ENTRY_POINT, &entry_point_); - this->xex_module()->GetOptHeader(XEX_HEADER_DEFAULT_STACK_SIZE, &stack_size_); - is_dll_module_ = !!(header->module_flags & XEX_MODULE_DLL_MODULE); - - // Setup the loader data entry - auto ldr_data = - memory()->TranslateVirtual(hmodule_ptr_); - - ldr_data->dll_base = 0; // GetProcAddress will read this. - ldr_data->xex_header_base = guest_xex_header_; - ldr_data->full_image_size = security_header->image_size; - ldr_data->image_base = this->xex_module()->base_address(); - ldr_data->entry_point = entry_point_; - - OnLoad(); - - return X_STATUS_SUCCESS; -} - -X_STATUS UserModule::Unload() { - if (module_format_ == kModuleFormatXex && - (!processor_module_ || !xex_module()->loaded())) { - // Quick abort. - return X_STATUS_SUCCESS; - } - - if (module_format_ == kModuleFormatXex && processor_module_ && - xex_module()->Unload()) { - OnUnload(); - return X_STATUS_SUCCESS; - } - - return X_STATUS_UNSUCCESSFUL; -} - -uint32_t UserModule::GetProcAddressByOrdinal(uint16_t ordinal) { - return xex_module()->GetProcAddress(ordinal); -} - -uint32_t UserModule::GetProcAddressByName(const char* name) { - return xex_module()->GetProcAddress(name); -} - -X_STATUS UserModule::GetSection(const char* name, uint32_t* out_section_data, - uint32_t* out_section_size) { - xex2_opt_resource_info* resource_header = nullptr; - if (!cpu::XexModule::GetOptHeader(xex_header(), XEX_HEADER_RESOURCE_INFO, - &resource_header)) { - // No resources. - return X_STATUS_NOT_FOUND; - } - - uint32_t count = (resource_header->size - 4) / sizeof(xex2_resource); - for (uint32_t i = 0; i < count; i++) { - auto& res = resource_header->resources[i]; - if (std::strncmp(name, res.name, 8) == 0) { - // Found! - *out_section_data = res.address; - *out_section_size = res.size; - - return X_STATUS_SUCCESS; - } - } - - return X_STATUS_NOT_FOUND; -} - -X_STATUS UserModule::GetOptHeader(xex2_header_keys key, void** out_ptr) { - assert_not_null(out_ptr); - - if (module_format_ == kModuleFormatElf) { - // Quick die. - return X_STATUS_UNSUCCESSFUL; - } - - bool ret = xex_module()->GetOptHeader(key, out_ptr); - if (!ret) { - return X_STATUS_NOT_FOUND; - } - - return X_STATUS_SUCCESS; -} - -X_STATUS UserModule::GetOptHeader(xex2_header_keys key, - uint32_t* out_header_guest_ptr) { - if (module_format_ == kModuleFormatElf) { - // Quick die. - return X_STATUS_UNSUCCESSFUL; - } - - auto header = - memory()->TranslateVirtual(guest_xex_header_); - if (!header) { - return X_STATUS_UNSUCCESSFUL; - } - return GetOptHeader(memory(), header, key, out_header_guest_ptr); -} - -X_STATUS UserModule::GetOptHeader(const Memory* memory, - const xex2_header* header, - xex2_header_keys key, - uint32_t* out_header_guest_ptr) { - assert_not_null(out_header_guest_ptr); - uint32_t field_value = 0; - bool field_found = false; - for (uint32_t i = 0; i < header->header_count; i++) { - auto& opt_header = header->headers[i]; - if (opt_header.key != key) { - continue; - } - field_found = true; - switch (opt_header.key & 0xFF) { - case 0x00: - // Return data stored in header value. - field_value = opt_header.value; - break; - case 0x01: - // Return pointer to data stored in header value. - field_value = memory->HostToGuestVirtual(&opt_header.value); - break; - default: - // Data stored at offset to header. - field_value = memory->HostToGuestVirtual(header) + opt_header.offset; - break; - } - break; - } - *out_header_guest_ptr = field_value; - if (!field_found) { - return X_STATUS_NOT_FOUND; - } - return X_STATUS_SUCCESS; -} - -bool UserModule::Save(ByteStream* stream) { - if (!XModule::Save(stream)) { - return false; - } - - // A lot of the information stored on this class can be reconstructed at - // runtime. - - return true; -} - -object_ref UserModule::Restore(KernelState* kernel_state, - ByteStream* stream, - std::string path) { - auto module = new UserModule(kernel_state); - - // XModule::Save took care of this earlier... - // TODO: Find a nicer way to represent that here. - if (!module->RestoreObject(stream)) { - return nullptr; - } - - auto result = module->LoadFromFile(path); - if (XFAILED(result)) { - XELOGD("UserModule::Restore LoadFromFile(%s) FAILED - code %.8X", - path.c_str(), result); - return nullptr; - } - - if (!kernel_state->RegisterUserModule(retain_object(module))) { - // Already loaded? - assert_always(); - } - - return object_ref(module); -} - -void UserModule::Dump() { - if (module_format_ == kModuleFormatElf) { - // Quick die. - return; - } - - StringBuffer sb; - - xe::cpu::ExportResolver* export_resolver = - kernel_state_->emulator()->export_resolver(); - auto header = xex_header(); - - // XEX header. - sb.AppendFormat("Module %s:\n", path_.c_str()); - sb.AppendFormat(" Module Flags: %.8X\n", (uint32_t)header->module_flags); - - // Security header - auto security_info = xex_module()->xex_security_info(); - sb.AppendFormat("Security Header:\n"); - sb.AppendFormat(" Image Flags: %.8X\n", - (uint32_t)security_info->image_flags); - sb.AppendFormat(" Load Address: %.8X\n", - (uint32_t)security_info->load_address); - sb.AppendFormat(" Image Size: %.8X\n", - (uint32_t)security_info->image_size); - sb.AppendFormat(" Export Table: %.8X\n", - (uint32_t)security_info->export_table); - - // Optional headers - sb.AppendFormat("Optional Header Count: %d\n", - (uint32_t)header->header_count); - - for (uint32_t i = 0; i < header->header_count; i++) { - auto& opt_header = header->headers[i]; - - // Stash a pointer (although this isn't used in every case) - auto opt_header_ptr = - reinterpret_cast(header) + opt_header.offset; - switch (opt_header.key) { - case XEX_HEADER_RESOURCE_INFO: { - sb.AppendFormat(" XEX_HEADER_RESOURCE_INFO:\n"); - auto opt_resource_info = - reinterpret_cast(opt_header_ptr); - - uint32_t count = (opt_resource_info->size - 4) / 16; - for (uint32_t j = 0; j < count; j++) { - auto& res = opt_resource_info->resources[j]; - - // Manually NULL-terminate the name. - char name[9]; - std::memcpy(name, res.name, sizeof(res.name)); - name[8] = 0; - - sb.AppendFormat( - " %-8s %.8X-%.8X, %db\n", name, (uint32_t)res.address, - (uint32_t)res.address + (uint32_t)res.size, (uint32_t)res.size); - } - } break; - case XEX_HEADER_FILE_FORMAT_INFO: { - sb.AppendFormat(" XEX_HEADER_FILE_FORMAT_INFO (TODO):\n"); - } break; - case XEX_HEADER_DELTA_PATCH_DESCRIPTOR: { - sb.AppendFormat(" XEX_HEADER_DELTA_PATCH_DESCRIPTOR (TODO):\n"); - } break; - case XEX_HEADER_BOUNDING_PATH: { - auto opt_bound_path = - reinterpret_cast(opt_header_ptr); - sb.AppendFormat(" XEX_HEADER_BOUNDING_PATH: %s\n", - opt_bound_path->path); - } break; - case XEX_HEADER_ORIGINAL_BASE_ADDRESS: { - sb.AppendFormat(" XEX_HEADER_ORIGINAL_BASE_ADDRESS: %.8X\n", - (uint32_t)opt_header.value); - } break; - case XEX_HEADER_ENTRY_POINT: { - sb.AppendFormat(" XEX_HEADER_ENTRY_POINT: %.8X\n", - (uint32_t)opt_header.value); - } break; - case XEX_HEADER_IMAGE_BASE_ADDRESS: { - sb.AppendFormat(" XEX_HEADER_IMAGE_BASE_ADDRESS: %.8X\n", - (uint32_t)opt_header.value); - } break; - case XEX_HEADER_IMPORT_LIBRARIES: { - sb.AppendFormat(" XEX_HEADER_IMPORT_LIBRARIES:\n"); - auto opt_import_libraries = - reinterpret_cast(opt_header_ptr); - - // FIXME: Don't know if 32 is the actual limit, but haven't seen more - // than 2. - const char* string_table[32]; - std::memset(string_table, 0, sizeof(string_table)); - - // Parse the string table - for (size_t j = 0, o = 0; j < opt_import_libraries->string_table.size && - o < opt_import_libraries->string_table.count; - o++) { - assert_true(o < xe::countof(string_table)); - const char* str = &opt_import_libraries->string_table.data[j]; - - string_table[o] = str; - j += std::strlen(str) + 1; - - // Padding - if ((j % 4) != 0) { - j += 4 - (j % 4); - } - } - - auto library_data = - reinterpret_cast(opt_import_libraries); - uint32_t library_offset = opt_import_libraries->string_table.size + 12; - while (library_offset < opt_import_libraries->size) { - auto library = reinterpret_cast( - library_data + library_offset); - if (!library->size) { - break; - } - auto name = string_table[library->name_index & 0xFF]; - assert_not_null(name); - sb.AppendFormat(" %s - %d imports\n", name, - (uint16_t)library->count); - - // Manually byteswap these because of the bitfields. - xex2_version version, version_min; - version.value = xe::byte_swap(library->version.value); - version_min.value = - xe::byte_swap(library->version_min.value); - sb.AppendFormat(" Version: %d.%d.%d.%d\n", version.major, - version.minor, version.build, version.qfe); - sb.AppendFormat(" Min Version: %d.%d.%d.%d\n", version_min.major, - version_min.minor, version_min.build, - version_min.qfe); - - library_offset += library->size; - } - } break; - case XEX_HEADER_CHECKSUM_TIMESTAMP: { - sb.AppendFormat(" XEX_HEADER_CHECKSUM_TIMESTAMP (TODO):\n"); - } break; - case XEX_HEADER_ORIGINAL_PE_NAME: { - auto opt_pe_name = - reinterpret_cast(opt_header_ptr); - sb.AppendFormat(" XEX_HEADER_ORIGINAL_PE_NAME: %s\n", - opt_pe_name->name); - } break; - case XEX_HEADER_STATIC_LIBRARIES: { - sb.AppendFormat(" XEX_HEADER_STATIC_LIBRARIES:\n"); - auto opt_static_libraries = - reinterpret_cast(opt_header_ptr); - - uint32_t count = (opt_static_libraries->size - 4) / 0x10; - for (uint32_t l = 0; l < count; l++) { - auto& library = opt_static_libraries->libraries[l]; - sb.AppendFormat(" %-8s : %d.%d.%d.%d\n", library.name, - static_cast(library.version_major), - static_cast(library.version_minor), - static_cast(library.version_build), - static_cast(library.version_qfe)); - } - } break; - case XEX_HEADER_TLS_INFO: { - sb.AppendFormat(" XEX_HEADER_TLS_INFO:\n"); - auto opt_tls_info = - reinterpret_cast(opt_header_ptr); - - sb.AppendFormat(" Slot Count: %d\n", - static_cast(opt_tls_info->slot_count)); - sb.AppendFormat(" Raw Data Address: %.8X\n", - static_cast(opt_tls_info->raw_data_address)); - sb.AppendFormat(" Data Size: %d\n", - static_cast(opt_tls_info->data_size)); - sb.AppendFormat(" Raw Data Size: %d\n", - static_cast(opt_tls_info->raw_data_size)); - } break; - case XEX_HEADER_DEFAULT_STACK_SIZE: { - sb.AppendFormat(" XEX_HEADER_DEFAULT_STACK_SIZE: %d\n", - static_cast(opt_header.value)); - } break; - case XEX_HEADER_DEFAULT_FILESYSTEM_CACHE_SIZE: { - sb.AppendFormat(" XEX_HEADER_DEFAULT_FILESYSTEM_CACHE_SIZE: %d\n", - static_cast(opt_header.value)); - } break; - case XEX_HEADER_DEFAULT_HEAP_SIZE: { - sb.AppendFormat(" XEX_HEADER_DEFAULT_HEAP_SIZE: %d\n", - static_cast(opt_header.value)); - } break; - case XEX_HEADER_PAGE_HEAP_SIZE_AND_FLAGS: { - sb.AppendFormat(" XEX_HEADER_PAGE_HEAP_SIZE_AND_FLAGS (TODO):\n"); - } break; - case XEX_HEADER_SYSTEM_FLAGS: { - sb.AppendFormat(" XEX_HEADER_SYSTEM_FLAGS: %.8X\n", - static_cast(opt_header.value)); - } break; - case XEX_HEADER_EXECUTION_INFO: { - sb.AppendFormat(" XEX_HEADER_EXECUTION_INFO:\n"); - auto opt_exec_info = - reinterpret_cast(opt_header_ptr); - - sb.AppendFormat(" Media ID: %.8X\n", - static_cast(opt_exec_info->media_id)); - sb.AppendFormat(" Title ID: %.8X\n", - static_cast(opt_exec_info->title_id)); - sb.AppendFormat(" Savegame ID: %.8X\n", - static_cast(opt_exec_info->title_id)); - sb.AppendFormat(" Disc Number / Total: %d / %d\n", - opt_exec_info->disc_number, opt_exec_info->disc_count); - } break; - case XEX_HEADER_TITLE_WORKSPACE_SIZE: { - sb.AppendFormat(" XEX_HEADER_TITLE_WORKSPACE_SIZE: %d\n", - uint32_t(opt_header.value)); - } break; - case XEX_HEADER_GAME_RATINGS: { - sb.AppendFormat(" XEX_HEADER_GAME_RATINGS (TODO):\n"); - } break; - case XEX_HEADER_LAN_KEY: { - sb.AppendFormat(" XEX_HEADER_LAN_KEY:"); - auto opt_lan_key = - reinterpret_cast(opt_header_ptr); - - for (int l = 0; l < 16; l++) { - sb.AppendFormat(" %.2X", opt_lan_key->key[l]); - } - sb.Append("\n"); - } break; - case XEX_HEADER_XBOX360_LOGO: { - sb.AppendFormat(" XEX_HEADER_XBOX360_LOGO (TODO):\n"); - } break; - case XEX_HEADER_MULTIDISC_MEDIA_IDS: { - sb.AppendFormat(" XEX_HEADER_MULTIDISC_MEDIA_IDS (TODO):\n"); - } break; - case XEX_HEADER_ALTERNATE_TITLE_IDS: { - sb.AppendFormat(" XEX_HEADER_ALTERNATE_TITLE_IDS (TODO):\n"); - } break; - case XEX_HEADER_ADDITIONAL_TITLE_MEMORY: { - sb.AppendFormat(" XEX_HEADER_ADDITIONAL_TITLE_MEMORY: %d\n", - uint32_t(opt_header.value)); - } break; - case XEX_HEADER_EXPORTS_BY_NAME: { - sb.AppendFormat(" XEX_HEADER_EXPORTS_BY_NAME:\n"); - auto dir = - reinterpret_cast(opt_header_ptr); - - auto exe_address = xex_module()->base_address(); - auto e = memory()->TranslateVirtual( - exe_address + dir->offset); - auto e_base = reinterpret_cast(e); - - // e->AddressOfX RVAs are relative to the IMAGE_EXPORT_DIRECTORY! - auto function_table = - reinterpret_cast(e_base + e->AddressOfFunctions); - // Names relative to directory. - auto name_table = - reinterpret_cast(e_base + e->AddressOfNames); - // Table of ordinals (by name). - auto ordinal_table = reinterpret_cast( - e_base + e->AddressOfNameOrdinals); - for (uint32_t n = 0; n < e->NumberOfNames; n++) { - auto name = reinterpret_cast(e_base + name_table[n]); - uint16_t ordinal = ordinal_table[n]; - uint32_t addr = exe_address + function_table[ordinal]; - sb.AppendFormat(" %-28s - %.3X - %.8X\n", name, ordinal, addr); - } - } break; - default: { - sb.AppendFormat(" Unknown Header %.8X\n", (uint32_t)opt_header.key); - } break; - } - } - - sb.AppendFormat("Sections:\n"); - for (uint32_t i = 0, page = 0; i < security_info->page_descriptor_count; - i++) { - // Manually byteswap the bitfield data. - xex2_page_descriptor page_descriptor; - page_descriptor.value = - xe::byte_swap(security_info->page_descriptors[i].value); - - const char* type = "UNKNOWN"; - switch (page_descriptor.info) { - case XEX_SECTION_CODE: - type = "CODE "; - break; - case XEX_SECTION_DATA: - type = "RWDATA "; - break; - case XEX_SECTION_READONLY_DATA: - type = "RODATA "; - break; - } - - const uint32_t page_size = - xex_module()->base_address() < 0x90000000 ? 64 * 1024 : 4 * 1024; - uint32_t start_address = xex_module()->base_address() + (page * page_size); - uint32_t end_address = - start_address + (page_descriptor.page_count * page_size); - - sb.AppendFormat(" %3u %s %3u pages %.8X - %.8X (%d bytes)\n", page, - type, page_descriptor.page_count, start_address, - end_address, page_descriptor.page_count * page_size); - page += page_descriptor.page_count; - } - - // Print out imports. - - auto import_libs = xex_module()->import_libraries(); - - sb.AppendFormat("Imports:\n"); - for (std::vector::const_iterator library = - import_libs->begin(); - library != import_libs->end(); ++library) { - if (library->imports.size() > 0) { - sb.AppendFormat(" %s - %lld imports\n", library->name.c_str(), - library->imports.size()); - sb.AppendFormat(" Version: %d.%d.%d.%d\n", library->version.major, - library->version.minor, library->version.build, - library->version.qfe); - sb.AppendFormat(" Min Version: %d.%d.%d.%d\n", - library->min_version.major, library->min_version.minor, - library->min_version.build, library->min_version.qfe); - sb.AppendFormat("\n"); - - // Counts. - int known_count = 0; - int unknown_count = 0; - int impl_count = 0; - int unimpl_count = 0; - - for (std::vector::const_iterator info = - library->imports.begin(); - info != library->imports.end(); ++info) { - if (kernel_state_->IsKernelModule(library->name.c_str())) { - auto kernel_export = export_resolver->GetExportByOrdinal( - library->name.c_str(), info->ordinal); - if (kernel_export) { - known_count++; - if (kernel_export->is_implemented()) { - impl_count++; - } else { - unimpl_count++; - } - } else { - unknown_count++; - unimpl_count++; - } - } else { - auto module = kernel_state_->GetModule(library->name.c_str()); - if (module) { - uint32_t export_addr = - module->GetProcAddressByOrdinal(info->ordinal); - if (export_addr) { - impl_count++; - known_count++; - } else { - unimpl_count++; - unknown_count++; - } - } else { - unimpl_count++; - unknown_count++; - } - } - } - float total_count = static_cast(library->imports.size()) / 100.0f; - sb.AppendFormat(" Total: %4llu\n", library->imports.size()); - sb.AppendFormat(" Known: %3d%% (%d known, %d unknown)\n", - static_cast(known_count / total_count), known_count, - unknown_count); - sb.AppendFormat( - " Implemented: %3d%% (%d implemented, %d unimplemented)\n", - static_cast(impl_count / total_count), impl_count, unimpl_count); - sb.AppendFormat("\n"); - - // Listing. - for (std::vector::const_iterator info = - library->imports.begin(); - info != library->imports.end(); ++info) { - const char* name = "UNKNOWN"; - bool implemented = false; - - cpu::Export* kernel_export = nullptr; - if (kernel_state_->IsKernelModule(library->name.c_str())) { - kernel_export = export_resolver->GetExportByOrdinal( - library->name.c_str(), info->ordinal); - if (kernel_export) { - name = kernel_export->name; - implemented = kernel_export->is_implemented(); - } - } else { - auto module = kernel_state_->GetModule(library->name.c_str()); - if (module && module->GetProcAddressByOrdinal(info->ordinal)) { - // TODO(benvanik): name lookup. - implemented = true; - } - } - if (kernel_export && - kernel_export->type == cpu::Export::Type::kVariable) { - sb.AppendFormat(" V %.8X %.3X (%4d) %s %s\n", - info->value_address, info->ordinal, info->ordinal, - implemented ? " " : "!!", name); - } else if (info->thunk_address) { - sb.AppendFormat(" F %.8X %.8X %.3X (%4d) %s %s\n", - info->value_address, info->thunk_address, - info->ordinal, info->ordinal, - implemented ? " " : "!!", name); - } - } - } - - sb.AppendFormat("\n"); - } - - xe::LogLine(xe::LogLevel::Info, 'i', sb.GetString()); -} - -} // namespace kernel -} // namespace xe diff --git a/src/xenia/kernel/xam/apps/xgi_app.cc b/src/xenia/kernel/xam/apps/xgi_app.cc index 627e8b390..88fcd573c 100644 --- a/src/xenia/kernel/xam/apps/xgi_app.cc +++ b/src/xenia/kernel/xam/apps/xgi_app.cc @@ -110,7 +110,7 @@ X_RESULT XgiApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, } case 0x000B0011: { // TODO(PermaNull): reverse buffer contents. - //TEST + // TEST XELOGD("XGISessionDelete"); return X_STATUS_SUCCESS; } @@ -128,12 +128,12 @@ X_RESULT XgiApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, return X_STATUS_SUCCESS; } case 0x000B0014: { - //TEST Gets Jetpac XBLA in game + // TEST Gets Jetpac XBLA in game XELOGD("XGI_unknown"); return X_STATUS_SUCCESS; } case 0x000B0015: { - //TEST Gets Jetpac XBLA in game + // TEST Gets Jetpac XBLA in game XELOGD("XGI_unknown"); return X_STATUS_SUCCESS; } diff --git a/src/xenia/kernel/xam/content_manager.cc b/src/xenia/kernel/xam/content_manager.cc index 36becce37..c2ee72858 100644 --- a/src/xenia/kernel/xam/content_manager.cc +++ b/src/xenia/kernel/xam/content_manager.cc @@ -28,9 +28,6 @@ constexpr const wchar_t* const ContentManager::kStfsHeadersExtension; static const wchar_t* kGameUserContentDirName = L"profile"; -static int content_device_id_ = 0; - - ContentManager::ContentManager(KernelState* kernel_state, std::wstring root_path) : kernel_state_(kernel_state), root_path_(std::move(root_path)) {} @@ -54,6 +51,30 @@ std::wstring ContentManager::ResolvePackageRoot(uint32_t content_type) { wchar_t content_type_str[9] = L"00000000"; std::swprintf(content_type_str, 9, L"%.8X", content_type); + std::wstring type_name; + switch (content_type) { + case 1: + // Save games. + type_name = L"00000001"; + break; + case 2: + // DLC from the marketplace. + type_name = L"00000002"; + break; + case 3: + // Publisher content? + type_name = L"00000003"; + break; + case 0x000D0000: + // ??? + type_name = L"000D0000"; + break; + default: + type_name = L"00000000"; + //assert_unhandled_case(data.content_type); + //return nullptr; + } + // Package root path: // content_root/title_id/type_name/ auto package_root = xe::join_paths( diff --git a/src/xenia/kernel/xam/content_manager.cc.orig b/src/xenia/kernel/xam/content_manager.cc.orig deleted file mode 100644 index 608d018b6..000000000 --- a/src/xenia/kernel/xam/content_manager.cc.orig +++ /dev/null @@ -1,354 +0,0 @@ -/** - ****************************************************************************** - * Xenia : Xbox 360 Emulator Research Project * - ****************************************************************************** - * Copyright 2015 Ben Vanik. All rights reserved. * - * Released under the BSD license - see LICENSE in the root for more details. * - ****************************************************************************** - */ - -#include "xenia/kernel/xam/content_manager.h" - -#include - -#include "xenia/base/filesystem.h" -#include "xenia/base/string.h" -#include "xenia/kernel/kernel_state.h" -<<<<<<< HEAD -#include "xenia/kernel/user_module.h" -======= -#include "xenia/kernel/xam/content_package.h" ->>>>>>> emoose/stfs-packages -#include "xenia/kernel/xobject.h" -#include "xenia/vfs/devices/host_path_device.h" -#include "xenia/vfs/devices/stfs_container_device.h" - -namespace xe { -namespace kernel { -namespace xam { - -constexpr const wchar_t* const ContentManager::kStfsHeadersExtension; - -static const wchar_t* kGameUserContentDirName = L"profile"; - -<<<<<<< HEAD -static int content_device_id_ = 0; - -ContentPackage::ContentPackage(KernelState* kernel_state, std::string root_name, - const XCONTENT_DATA& data, - std::wstring package_path) - : kernel_state_(kernel_state), root_name_(std::move(root_name)) { - device_path_ = std::string("\\Device\\Content\\") + - std::to_string(++content_device_id_) + "\\"; - - auto fs = kernel_state_->file_system(); - - std::unique_ptr device; - - // If this isn't a folder try mounting as STFS package - // Otherwise mount as a local host path - if (filesystem::PathExists(package_path) && - !filesystem::IsFolder(package_path)) { - device = - std::make_unique(device_path_, package_path); - } else { - device = std::make_unique(device_path_, package_path, - false); - } - - device->Initialize(); - fs->RegisterDevice(std::move(device)); - fs->RegisterSymbolicLink(root_name_ + ":", device_path_); -} - -ContentPackage::~ContentPackage() { - auto fs = kernel_state_->file_system(); - fs->UnregisterSymbolicLink(root_name_ + ":"); - fs->UnregisterDevice(device_path_); -} - -======= ->>>>>>> emoose/stfs-packages -ContentManager::ContentManager(KernelState* kernel_state, - std::wstring root_path) - : kernel_state_(kernel_state), root_path_(std::move(root_path)) {} - -ContentManager::~ContentManager() = default; - -uint32_t ContentManager::title_id() { - if (title_id_override_) { - return title_id_override_; - } - if (!kernel_state_->GetExecutableModule()) { - return -1; - } - return kernel_state_->title_id(); -} - -std::wstring ContentManager::ResolvePackageRoot(uint32_t content_type) { - wchar_t title_id_str[9] = L"00000000"; - std::swprintf(title_id_str, 9, L"%.8X", title_id()); - - wchar_t content_type_str[9] = L"00000000"; - std::swprintf(content_type_str, 9, L"%.8X", content_type); - - // Package root path: - // content_root/title_id/type_name/ - auto package_root = xe::join_paths( - root_path_, xe::join_paths(title_id_str, content_type_str)); - return package_root + xe::kWPathSeparator; -} - -std::wstring ContentManager::ResolvePackagePath(const XCONTENT_DATA& data) { - // Content path: - // content_root/title_id/type_name/data_file_name/ - auto package_root = ResolvePackageRoot(data.content_type); - auto package_path = - xe::join_paths(package_root, xe::to_wstring(data.file_name)); -<<<<<<< HEAD - - // Add slash to end of path if this is a folder - // (or package doesn't exist, meaning we're creating a new folder) - if (!xe::filesystem::PathExists(package_path) || - xe::filesystem::IsFolder(package_path)) { - package_path += xe::kPathSeparator; - } -======= ->>>>>>> emoose/stfs-packages - return package_path; -} - -std::vector ContentManager::ListContent(uint32_t device_id, - uint32_t content_type) { - std::vector result; - - // StfsHeader is a huge class - alloc on heap instead of stack - vfs::StfsHeader* header = new vfs::StfsHeader(); - - // Search path: - // content_root/title_id/type_name/* - auto package_root = ResolvePackageRoot(content_type); - auto file_infos = xe::filesystem::ListFiles(package_root); - for (const auto& file_info : file_infos) { - XCONTENT_DATA content_data; - content_data.device_id = device_id; - content_data.content_type = content_type; - content_data.display_name = file_info.name; - content_data.file_name = xe::to_string(file_info.name); - - auto headers_path = file_info.path + file_info.name; - if (file_info.type == xe::filesystem::FileInfo::Type::kDirectory) { - headers_path = headers_path + ContentManager::kStfsHeadersExtension; - } - - if (xe::filesystem::PathExists(headers_path)) { - // File is either package or directory that has .headers file - - if (file_info.type != xe::filesystem::FileInfo::Type::kDirectory) { - // Not a directory so must be a package, verify size to make sure - if (file_info.total_size <= vfs::StfsHeader::kHeaderLength) { - continue; // Invalid package (maybe .headers.bin) - } - } - - auto map = MappedMemory::Open(headers_path, MappedMemory::Mode::kRead, 0, - vfs::StfsHeader::kHeaderLength); - if (map) { - if (header->Read(map->data())) { - content_data.content_type = - static_cast(header->content_type); - content_data.display_name = header->display_names; - // TODO: select localized display name - // some games may expect different ones depending on language setting. - } - map->Close(); - } - } - - result.emplace_back(std::move(content_data)); - } - - delete header; - - return result; -} - -ContentPackage* ContentManager::ResolvePackage(const XCONTENT_DATA& data) { - auto package_path = ResolvePackagePath(data); - if (!xe::filesystem::PathExists(package_path)) { - return nullptr; - } - - auto global_lock = global_critical_region_.Acquire(); - - for (auto package : open_packages_) { - if (package->package_path() == package_path) { - return package; - } - } - - std::unique_ptr package; - - // Open as FolderContentPackage if the package is a folder or doesn't exist - if (xe::filesystem::IsFolder(package_path) || - !xe::filesystem::PathExists(package_path)) { - package = std::make_unique(kernel_state_, data, - package_path); - } else { - package = - std::make_unique(kernel_state_, data, package_path); - } - - return package.release(); -} - -bool ContentManager::ContentExists(const XCONTENT_DATA& data) { - auto path = ResolvePackagePath(data); - return xe::filesystem::PathExists(path); -} - -X_RESULT ContentManager::CreateContent(std::string root_name, - const XCONTENT_DATA& data) { - auto global_lock = global_critical_region_.Acquire(); - - auto package_path = ResolvePackagePath(data); - if (xe::filesystem::PathExists(package_path)) { - // Exists, must not! - return X_ERROR_ALREADY_EXISTS; - } - - for (auto package : open_packages_) { - if (package->package_path() == package_path) { - return X_ERROR_ALREADY_EXISTS; - } - } - - if (!xe::filesystem::CreateFolder(package_path)) { - return X_ERROR_ACCESS_DENIED; - } - - auto package = ResolvePackage(data); - if (!package) { - return X_ERROR_FUNCTION_FAILED; // Failed to create directory? - } - - if (!package->Mount(root_name)) { - return X_ERROR_DEVICE_NOT_CONNECTED; - } - - open_packages_.push_back(package); - - return X_ERROR_SUCCESS; -} - -X_RESULT ContentManager::OpenContent(std::string root_name, - const XCONTENT_DATA& data) { - auto global_lock = global_critical_region_.Acquire(); - - auto package = ResolvePackage(data); - if (!package) { - return X_ERROR_FILE_NOT_FOUND; - } - - if (!package->Mount(root_name)) { - return X_ERROR_DEVICE_NOT_CONNECTED; - } - - open_packages_.push_back(package); - - return X_ERROR_SUCCESS; -} - -X_RESULT ContentManager::CloseContent(std::string root_name) { - auto global_lock = global_critical_region_.Acquire(); - - for (auto it = open_packages_.begin(); it != open_packages_.end(); ++it) { - auto& root_names = (*it)->root_names(); - auto root = std::find(root_names.begin(), root_names.end(), root_name); - if (root != root_names.end()) { - if ((*it)->Unmount(root_name)) { - delete *it; - open_packages_.erase(it); - } - - return X_ERROR_SUCCESS; - } - } - - return X_ERROR_FILE_NOT_FOUND; -} - -X_RESULT ContentManager::GetContentThumbnail(const XCONTENT_DATA& data, - std::vector* buffer) { - auto global_lock = global_critical_region_.Acquire(); - - auto package = ResolvePackage(data); - if (!package) { - return X_ERROR_FILE_NOT_FOUND; - } - - return package->GetThumbnail(buffer); -} - -X_RESULT ContentManager::SetContentThumbnail(const XCONTENT_DATA& data, - std::vector buffer) { - auto global_lock = global_critical_region_.Acquire(); - - auto package = ResolvePackage(data); - if (!package) { - return X_ERROR_FILE_NOT_FOUND; - } - - return package->SetThumbnail(buffer); -} - -X_RESULT ContentManager::DeleteContent(const XCONTENT_DATA& data) { - auto global_lock = global_critical_region_.Acquire(); - -<<<<<<< HEAD - auto package_path = ResolvePackagePath(data); - if (xe::filesystem::PathExists(package_path)) { - if (xe::filesystem::IsFolder(package_path)) { - xe::filesystem::DeleteFolder(package_path); - } else { - // TODO: delete STFS package? - } - return X_ERROR_SUCCESS; - } else { -======= - auto package = ResolvePackage(data); - if (!package) { ->>>>>>> emoose/stfs-packages - return X_ERROR_FILE_NOT_FOUND; - } - - auto result = package->Delete(); - if (XSUCCEEDED(result)) { - auto it = std::find(open_packages_.begin(), open_packages_.end(), package); - if (it != open_packages_.end()) { - open_packages_.erase(it); - } - - delete package; - } - - return result; -} - -std::wstring ContentManager::ResolveGameUserContentPath() { - wchar_t title_id[9] = L"00000000"; - std::swprintf(title_id, 9, L"%.8X", kernel_state_->title_id()); - auto user_name = xe::to_wstring(kernel_state_->user_profile()->name()); - - // Per-game per-profile data location: - // content_root/title_id/profile/user_name - auto package_root = xe::join_paths( - root_path_, - xe::join_paths(title_id, - xe::join_paths(kGameUserContentDirName, user_name))); - return package_root + xe::kWPathSeparator; -} - -} // namespace xam -} // namespace kernel -} // namespace xe diff --git a/src/xenia/kernel/xam/content_manager.h b/src/xenia/kernel/xam/content_manager.h index 89c1b3cd9..1099314e2 100644 --- a/src/xenia/kernel/xam/content_manager.h +++ b/src/xenia/kernel/xam/content_manager.h @@ -30,8 +30,6 @@ namespace xe { namespace kernel { namespace xam { -class ContentPackage; - struct XCONTENT_DATA { static const size_t kSize = 4 + 4 + 128 * 2 + 42 + 2; // = 306 + 2b padding uint32_t device_id; diff --git a/src/xenia/kernel/xam/content_manager.h.orig b/src/xenia/kernel/xam/content_manager.h.orig deleted file mode 100644 index 260d47877..000000000 --- a/src/xenia/kernel/xam/content_manager.h.orig +++ /dev/null @@ -1,108 +0,0 @@ -/** - ****************************************************************************** - * Xenia : Xbox 360 Emulator Research Project * - ****************************************************************************** - * Copyright 2015 Ben Vanik. All rights reserved. * - * Released under the BSD license - see LICENSE in the root for more details. * - ****************************************************************************** - */ - -#ifndef XENIA_KERNEL_XAM_CONTENT_MANAGER_H_ -#define XENIA_KERNEL_XAM_CONTENT_MANAGER_H_ - -#include -#include -#include -#include - -#include "xenia/base/memory.h" -#include "xenia/base/mutex.h" -#include "xenia/xbox.h" - -namespace xe { -namespace kernel { -class KernelState; -} // namespace kernel -} // namespace xe - -namespace xe { -namespace kernel { -namespace xam { - -class ContentPackage; - -struct XCONTENT_DATA { - static const size_t kSize = 4 + 4 + 128 * 2 + 42 + 2; // = 306 + 2b padding - uint32_t device_id; - uint32_t content_type; - std::wstring display_name; // 128 chars - std::string file_name; - - XCONTENT_DATA() = default; - explicit XCONTENT_DATA(const uint8_t* ptr) { - device_id = xe::load_and_swap(ptr + 0); - content_type = xe::load_and_swap(ptr + 4); - display_name = xe::load_and_swap(ptr + 8); - file_name = xe::load_and_swap(ptr + 8 + 128 * 2); - } - - void Write(uint8_t* ptr) { - xe::store_and_swap(ptr + 0, device_id); - xe::store_and_swap(ptr + 4, content_type); - xe::store_and_swap(ptr + 8, display_name); - xe::store_and_swap(ptr + 8 + 128 * 2, file_name); - } -}; - -class ContentManager { - public: - // Extension to append to folder path when searching for STFS headers - static constexpr const wchar_t* const kStfsHeadersExtension = L".headers.bin"; - - ContentManager(KernelState* kernel_state, std::wstring root_path); - ~ContentManager(); - - std::vector ListContent(uint32_t device_id, - uint32_t content_type); - - ContentPackage* ResolvePackage(const XCONTENT_DATA& data); - - bool ContentExists(const XCONTENT_DATA& data); - X_RESULT CreateContent(std::string root_name, const XCONTENT_DATA& data); - X_RESULT OpenContent(std::string root_name, const XCONTENT_DATA& data); - X_RESULT CloseContent(std::string root_name); - X_RESULT GetContentThumbnail(const XCONTENT_DATA& data, - std::vector* buffer); - X_RESULT SetContentThumbnail(const XCONTENT_DATA& data, - std::vector buffer); - X_RESULT DeleteContent(const XCONTENT_DATA& data); - std::wstring ResolveGameUserContentPath(); - - void SetTitleIdOverride(uint32_t title_id) { title_id_override_ = title_id; } - - private: - uint32_t title_id(); - - std::wstring ResolvePackageRoot(uint32_t content_type); - std::wstring ResolvePackagePath(const XCONTENT_DATA& data); - - KernelState* kernel_state_; - std::wstring root_path_; - - // TODO(benvanik): remove use of global lock, it's bad here! - xe::global_critical_region global_critical_region_; -<<<<<<< HEAD - std::unordered_map open_packages_; - - uint32_t title_id_override_ = - 0; // can be used for games/apps that request content for other IDs -======= - std::vector open_packages_; ->>>>>>> emoose/stfs-packages -}; - -} // namespace xam -} // namespace kernel -} // namespace xe - -#endif // XENIA_KERNEL_XAM_CONTENT_MANAGER_H_ diff --git a/src/xenia/kernel/xam/user_profile.cc b/src/xenia/kernel/xam/user_profile.cc index da1631fc2..1eaf5947b 100644 --- a/src/xenia/kernel/xam/user_profile.cc +++ b/src/xenia/kernel/xam/user_profile.cc @@ -11,9 +11,7 @@ #include "xenia/kernel/kernel_state.h" #include "xenia/kernel/util/shim_utils.h" - -#include - +#include "xenia/base/cvar.h" #include "xenia/base/clock.h" #include "xenia/base/filesystem.h" #include "xenia/base/logging.h" @@ -21,14 +19,12 @@ #include "xenia/kernel/util/crypto_utils.h" #include "xenia/kernel/xam/user_profile.h" -DEFINE_string(profile_name, "XeniaUser", "Gamertag", "General"); - namespace xe { namespace kernel { namespace xam { DEFINE_string(profile_directory, "Content\\Profile\\", - "The directory to store profile data inside"); + "The directory to store profile data inside", "Kernel"); constexpr uint32_t kDashboardID = 0xFFFE07D1; @@ -108,7 +104,7 @@ void UserProfile::EncryptAccountFile(const X_XAMACCOUNTINFO* input, UserProfile::UserProfile() : dash_gpd_(kDashboardID) { account_.xuid_online = 0xE000BABEBABEBABE; - wcscpy_s(account_.gamertag, cvars::profile_name); + wcscpy_s(account_.gamertag, L"XeniaUser"); // https://cs.rin.ru/forum/viewtopic.php?f=38&t=60668&hilit=gfwl+live&start=195 // https://github.com/arkem/py360/blob/master/py360/constants.py @@ -181,11 +177,11 @@ UserProfile::UserProfile() : dash_gpd_(kDashboardID) { void UserProfile::LoadProfile() { auto mmap_ = - MappedMemory::Open(xe::to_wstring(FLAGS_profile_directory) + L"Account", + MappedMemory::Open(xe::to_wstring(cvars::profile_directory) + L"Account", MappedMemory::Mode::kRead); if (mmap_) { - XELOGI("Loading Account file from path %sAccount", - FLAGS_profile_directory.c_str()); + XELOGI("Loading Account file from path %SAccount", + xe::to_wstring(cvars::profile_directory).c_str()); X_XAMACCOUNTINFO tmp_acct; bool success = DecryptAccountFile(mmap_->data(), &tmp_acct); @@ -203,10 +199,10 @@ void UserProfile::LoadProfile() { mmap_->Close(); } - XELOGI("Loading profile GPDs from path %s", FLAGS_profile_directory.c_str()); + XELOGI("Loading profile GPDs from path %S", xe::to_wstring(cvars::profile_directory).c_str()); mmap_ = MappedMemory::Open( - xe::to_wstring(FLAGS_profile_directory) + L"FFFE07D1.gpd", + xe::to_wstring(cvars::profile_directory) + L"FFFE07D1.gpd", MappedMemory::Mode::kRead); if (!mmap_) { XELOGW( @@ -223,7 +219,7 @@ void UserProfile::LoadProfile() { for (auto title : titles) { wchar_t fname[256]; _swprintf(fname, L"%X.gpd", title.title_id); - mmap_ = MappedMemory::Open(xe::to_wstring(FLAGS_profile_directory) + fname, + mmap_ = MappedMemory::Open(xe::to_wstring(cvars::profile_directory) + fname, MappedMemory::Mode::kRead); if (!mmap_) { XELOGE("Failed to open GPD for title %X (%s)!", title.title_id, @@ -451,16 +447,16 @@ bool UserProfile::UpdateGpd(uint32_t title_id, xdbf::GpdFile& gpd_data) { return false; } - if (!filesystem::PathExists(xe::to_wstring(FLAGS_profile_directory))) { - filesystem::CreateFolder(xe::to_wstring(FLAGS_profile_directory)); + if (!filesystem::PathExists(xe::to_wstring(cvars::profile_directory))) { + filesystem::CreateFolder(xe::to_wstring(cvars::profile_directory)); } wchar_t fname[256]; _swprintf(fname, L"%X.gpd", title_id); - filesystem::CreateFile(xe::to_wstring(FLAGS_profile_directory) + fname); + filesystem::CreateFile(xe::to_wstring(cvars::profile_directory) + fname); auto mmap_ = - MappedMemory::Open(xe::to_wstring(FLAGS_profile_directory) + fname, + MappedMemory::Open(xe::to_wstring(cvars::profile_directory) + fname, MappedMemory::Mode::kReadWrite, 0, gpd_length); if (!mmap_) { XELOGE("Failed to open %X.gpd for writing!", title_id); diff --git a/src/xenia/kernel/xam/user_profile.h b/src/xenia/kernel/xam/user_profile.h index 76ad5f696..c30c838b3 100644 --- a/src/xenia/kernel/xam/user_profile.h +++ b/src/xenia/kernel/xam/user_profile.h @@ -313,7 +313,7 @@ class UserProfile { uint64_t xuid() const { return account_.xuid_online; } std::string name() const { return account_.GetGamertagString(); } - uint32_t signin_state() const { return 1; } + // uint32_t signin_state() const { return 1; } void AddSetting(std::unique_ptr setting); Setting* GetSetting(uint32_t setting_id); diff --git a/src/xenia/kernel/xam/xam_info.cc b/src/xenia/kernel/xam/xam_info.cc index dfb78654c..db882bacb 100644 --- a/src/xenia/kernel/xam/xam_info.cc +++ b/src/xenia/kernel/xam/xam_info.cc @@ -290,7 +290,9 @@ void XamLoaderLaunchTitle(lpstring_t raw_name, dword_t flags) { auto& loader_data = xam->loader_data(); loader_data.launch_flags = flags; - + XELOGI( + "XamLoaderLaunchTitle launching: (%S) with flags (%d)", + std::string(raw_name), flags); // Translate the launch path to a full path. if (raw_name && raw_name.value() == "") { loader_data.launch_path = "game:\\default.xex"; diff --git a/src/xenia/kernel/xam/xam_input.cc b/src/xenia/kernel/xam/xam_input.cc index 7aead257d..eb83d27a9 100644 --- a/src/xenia/kernel/xam/xam_input.cc +++ b/src/xenia/kernel/xam/xam_input.cc @@ -182,7 +182,7 @@ X_HRESULT_result_t XamUserGetDeviceContext(dword_t user_index, dword_t unk, // Games check the result - usually with some masking. // If this function fails they assume zero, so let's fail AND // set zero just to be safe. - *out_ptr = 0; + //*out_ptr = 0; if (!user_index || (user_index & 0xFF) == 0xFF) { return X_E_SUCCESS; } else { diff --git a/src/xenia/kernel/xam/xam_net.cc b/src/xenia/kernel/xam/xam_net.cc index d0a3d70c3..5a9034e36 100644 --- a/src/xenia/kernel/xam/xam_net.cc +++ b/src/xenia/kernel/xam/xam_net.cc @@ -461,7 +461,7 @@ DECLARE_XAM_EXPORT1(NetDll_XNetXnAddrToMachineId, kNetworking, kStub); void NetDll_XNetInAddrToString(dword_t caller, dword_t in_addr, lpstring_t string_out, dword_t string_size) { - strncpy(string_out, "666.666.666.666", string_size); + strncpy(string_out, "127.0.0.1", string_size); } DECLARE_XAM_EXPORT1(NetDll_XNetInAddrToString, kNetworking, kStub); diff --git a/src/xenia/kernel/xam/xam_notify.cc b/src/xenia/kernel/xam/xam_notify.cc index 6f6b229bf..56ff5dc2d 100644 --- a/src/xenia/kernel/xam/xam_notify.cc +++ b/src/xenia/kernel/xam/xam_notify.cc @@ -18,7 +18,10 @@ namespace xe { namespace kernel { namespace xam { -dword_result_t XamNotifyCreateListenerInternal(qword_t mask) { +dword_result_t XamNotifyCreateListenerInternal(qword_t mask, dword_t unk, + dword_t one) { + // r4=1 may indicate user process? + auto listener = object_ref(new XNotifyListener(kernel_state())); listener->Initialize(mask); @@ -28,10 +31,11 @@ dword_result_t XamNotifyCreateListenerInternal(qword_t mask) { return handle; } -DECLARE_XAM_EXPORT1(XamNotifyCreateListenerInternal, kNone, kImplemented); +DECLARE_XAM_EXPORT2(XamNotifyCreateListenerInternal, kNone, kImplemented, + kSketchy); -dword_result_t XamNotifyCreateListener(qword_t mask) { - return XamNotifyCreateListenerInternal(mask); +dword_result_t XamNotifyCreateListener(qword_t mask, dword_t one) { + return XamNotifyCreateListenerInternal(mask, 0, one); } DECLARE_XAM_EXPORT1(XamNotifyCreateListener, kNone, kImplemented); @@ -56,6 +60,9 @@ dword_result_t XNotifyGetNext(dword_t handle, dword_t match_id, // Asking for a specific notification id = match_id; dequeued = listener->DequeueNotification(match_id, ¶m); + // TODO(Gliniak): Requires research. There is no such match_id! + if (!dequeued && !param) + dequeued = listener->DequeueNotification(&id, ¶m); } else { // Just get next. dequeued = listener->DequeueNotification(&id, ¶m); @@ -71,7 +78,7 @@ dword_result_t XNotifyGetNext(dword_t handle, dword_t match_id, return dequeued ? 1 : 0; } -DECLARE_XAM_EXPORT1(XNotifyGetNext, kNone, kImplemented); +DECLARE_XAM_EXPORT2(XNotifyGetNext, kNone, kImplemented, kHighFrequency); dword_result_t XNotifyDelayUI(dword_t delay_ms) { // Ignored. diff --git a/src/xenia/kernel/xam/xam_user.cc b/src/xenia/kernel/xam/xam_user.cc index 3ce0190d0..f32e98738 100644 --- a/src/xenia/kernel/xam/xam_user.cc +++ b/src/xenia/kernel/xam/xam_user.cc @@ -16,6 +16,11 @@ #include "xenia/kernel/xenumerator.h" #include "xenia/kernel/xthread.h" #include "xenia/xbox.h" +#include "xenia/base/cvar.h" + + +DEFINE_bool(signin_state, true, + "User signed in", "Kernel"); namespace xe { namespace kernel { @@ -121,7 +126,7 @@ dword_result_t XamUserGetSigninState(dword_t user_index) { if (user_index == 0 || (user_index & 0xFF) == 0xFF) { const auto& user_profile = kernel_state()->user_profile(); - return user_profile->signin_state(); + return ((cvars::signin_state) ? 1 : 0); } else { return 0; } @@ -152,7 +157,7 @@ X_HRESULT_result_t XamUserGetSigninInfo(dword_t user_index, dword_t flags, const auto& user_profile = kernel_state()->user_profile(); info->xuid = user_profile->xuid(); - info->signin_state = user_profile->signin_state(); + info->signin_state = ((cvars::signin_state) ? 1 : 0); std::strncpy(info->name, user_profile->name().data(), 15); return X_E_SUCCESS; } @@ -502,7 +507,7 @@ dword_result_t XamUserAreUsersFriends(dword_t user_index, dword_t unk1, X_RESULT result = X_ERROR_SUCCESS; const auto& user_profile = kernel_state()->user_profile(); - if (user_profile->signin_state() == 0) { + if (((cvars::signin_state) ? 1 : 0) == 0) { result = X_ERROR_NOT_LOGGED_ON; } else { // No friends! diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_crypt.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_crypt.cc index 88a1907c4..48cd004d1 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_crypt.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_crypt.cc @@ -434,17 +434,75 @@ void XeCryptHmacSha(lpvoid_t key, dword_t key_size_in, lpvoid_t inp_1, dword_t inp_1_size, lpvoid_t inp_2, dword_t inp_2_size, lpvoid_t inp_3, dword_t inp_3_size, lpvoid_t out, dword_t out_size) { - util::HmacSha(key, key_size_in, inp_1, inp_1_size, inp_2, inp_2_size, inp_3, - inp_3_size, out, out_size); + uint32_t key_size = key_size_in; + sha1::SHA1 sha; + uint8_t kpad_i[0x40]; + uint8_t kpad_o[0x40]; + uint8_t tmp_key[0x40]; + std::memset(kpad_i, 0x36, 0x40); + std::memset(kpad_o, 0x5C, 0x40); + + // Setup HMAC key + // If > block size, use its hash + if (key_size > 0x40) { + sha1::SHA1 sha_key; + sha_key.processBytes(key, key_size); + sha_key.finalize((uint8_t*)tmp_key); + + key_size = 0x14u; + } else { + std::memcpy(tmp_key, key, key_size); + } + + for (uint32_t i = 0; i < key_size; i++) { + kpad_i[i] = tmp_key[i] ^ 0x36; + kpad_o[i] = tmp_key[i] ^ 0x5C; + } + + // Inner + sha.processBytes(kpad_i, 0x40); + + if (inp_1_size) { + sha.processBytes(inp_1, inp_1_size); + } + + if (inp_2_size) { + sha.processBytes(inp_2, inp_2_size); + } + + if (inp_3_size) { + sha.processBytes(inp_3, inp_3_size); + } + + uint8_t digest[0x14]; + sha.finalize(digest); + sha.reset(); + + // Outer + sha.processBytes(kpad_o, 0x40); + sha.processBytes(digest, 0x14); + sha.finalize(digest); + + std::memcpy(out, digest, std::min((uint32_t)out_size, 0x14u)); } DECLARE_XBOXKRNL_EXPORT1(XeCryptHmacSha, kNone, kImplemented); +// Keys +// TODO: Array of keys we need + +// Retail key 0x19 +static const uint8_t key19[] = {0xE1, 0xBC, 0x15, 0x9C, 0x73, 0xB1, 0xEA, 0xE9, + 0xAB, 0x31, 0x70, 0xF3, 0xAD, 0x47, 0xEB, 0xF3}; + dword_result_t XeKeysHmacSha(dword_t key_num, lpvoid_t inp_1, dword_t inp_1_size, lpvoid_t inp_2, dword_t inp_2_size, lpvoid_t inp_3, dword_t inp_3_size, lpvoid_t out, dword_t out_size) { - const uint8_t* key = util::GetXeKey(key_num); + const uint8_t* key = nullptr; + if (key_num == 0x19) { + key = key19; + } if (key) { XeCryptHmacSha((void*)key, 0x10, inp_1, inp_1_size, inp_2, inp_2_size, diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_debug.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_debug.cc index 6a490677e..575496726 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_debug.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_debug.cc @@ -136,8 +136,9 @@ DECLARE_XBOXKRNL_EXPORT2(RtlRaiseException, kDebug, kStub, kImportant); void KeBugCheckEx(dword_t code, dword_t param1, dword_t param2, dword_t param3, dword_t param4) { - XELOGD("*** STOP: 0x%.8X (0x%.8X, 0x%.8X, 0x%.8X, 0x%.8X)", code, param1, + XELOGE("*** STOP: 0x%.8X (0x%.8X, 0x%.8X, 0x%.8X, 0x%.8X)", code, param1, param2, param3, param4); + XELOGE(" ### GUEST RAISE EXCEPTION - should have crashed here ###"); fflush(stdout); //xe::debugging::Break(); assert_always(); diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_modules.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_modules.cc index cd7dd6b75..0aa6b4549 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_modules.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_modules.cc @@ -14,14 +14,15 @@ #include "xenia/kernel/util/shim_utils.h" #include "xenia/kernel/xboxkrnl/xboxkrnl_private.h" #include "xenia/xbox.h" +#include "xenia/base/cvar.h" + +DEFINE_bool(xconfig_initial_setup, false, + "Enable the dashboard initial setup/OOBE", "Kernel"); DEFINE_int32(game_language, 1, "The language for the game to run in. 1=EN / 2=JP / 3=DE / 4=FR / " "5=ES / 6=IT / 7=KR / 8=CN", "General"); - -DEFINE_bool(xconfig_initial_setup, false, - "Enable the dashboard initial setup/OOBE", "Kernel"); namespace xe { namespace kernel { @@ -90,7 +91,7 @@ X_STATUS xeExGetXConfigSetting(uint16_t category, uint16_t setting, break; case 0x000F: // XCONFIG_USER_PC_FLAGS (parental control?) setting_size = 1; - value[0] = 0; + xe::store_and_swap(value, 0); break; case 0x0010: // XCONFIG_USER_SMB_CONFIG (0x100 byte string) // Just set the start of the buffer to 0 so that callers diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_modules.cc.orig b/src/xenia/kernel/xboxkrnl/xboxkrnl_modules.cc.orig deleted file mode 100644 index 2e0794874..000000000 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_modules.cc.orig +++ /dev/null @@ -1,318 +0,0 @@ -/** - ****************************************************************************** - * 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 "xenia/base/logging.h" -#include "xenia/cpu/processor.h" -#include "xenia/kernel/kernel_state.h" -#include "xenia/kernel/user_module.h" -#include "xenia/kernel/util/shim_utils.h" -#include "xenia/kernel/xboxkrnl/xboxkrnl_private.h" -#include "xenia/xbox.h" - -<<<<<<< HEAD -DEFINE_int32(game_language, 1, - "The language for the game to run in. 1=EN / 2=JP / 3=DE / 4=FR / " - "5=ES / 6=IT / 7=KR / 8=CN", - "General"); -======= -DEFINE_bool(xconfig_initial_setup, false, - "Enable the dashboard initial setup/OOBE", "Kernel"); ->>>>>>> emoose/dashboard - -namespace xe { -namespace kernel { -namespace xboxkrnl { - -X_STATUS xeExGetXConfigSetting(uint16_t category, uint16_t setting, - void* buffer, uint16_t buffer_size, - uint16_t* required_size) { - uint16_t setting_size = 0; - alignas(uint32_t) uint8_t value[4]; - - // TODO(benvanik): have real structs here that just get copied from. - // https://free60project.github.io/wiki/XConfig.html - // https://github.com/oukiar/freestyledash/blob/master/Freestyle/Tools/Generic/ExConfig.h - switch (category) { - case 0x0002: - // XCONFIG_SECURED_CATEGORY - switch (setting) { - case 0x0001: // XCONFIG_SECURED_MAC_ADDRESS (6 bytes) - return X_STATUS_SUCCESS; // Just return, easier than setting up code - // for different size configs - case 0x0002: // XCONFIG_SECURED_AV_REGION - setting_size = 4; - xe::store_and_swap(value, 0x00001000); // USA/Canada - break; - default: - assert_unhandled_case(setting); - return X_STATUS_INVALID_PARAMETER_2; - } - break; - case 0x0003: - // XCONFIG_USER_CATEGORY - switch (setting) { - case 0x0001: // XCONFIG_USER_TIME_ZONE_BIAS - case 0x0002: // XCONFIG_USER_TIME_ZONE_STD_NAME - case 0x0003: // XCONFIG_USER_TIME_ZONE_DLT_NAME - case 0x0004: // XCONFIG_USER_TIME_ZONE_STD_DATE - case 0x0005: // XCONFIG_USER_TIME_ZONE_DLT_DATE - case 0x0006: // XCONFIG_USER_TIME_ZONE_STD_BIAS - case 0x0007: // XCONFIG_USER_TIME_ZONE_DLT_BIAS - setting_size = 4; - // TODO(benvanik): get this value. - xe::store_and_swap(value, 0); - break; - case 0x0009: // XCONFIG_USER_LANGUAGE - setting_size = 4; - xe::store_and_swap(value, cvars::game_language); // English - break; - case 0x000A: // XCONFIG_USER_VIDEO_FLAGS - setting_size = 4; - xe::store_and_swap(value, 0x00040000); - break; - case 0x000C: // XCONFIG_USER_RETAIL_FLAGS - setting_size = 4; - // TODO(benvanik): get this value. - - // 0x40 = dashboard initial setup complete - xe::store_and_swap(value, - cvars::xconfig_initial_setup ? 0 : 0x40); - break; - case 0x000E: // XCONFIG_USER_COUNTRY - // Halo: Reach sub_82804888 - min 0x5, max 0x6E. - setting_size = 1; - // TODO(benvanik): get this value. - value[0] = 5; - break; - case 0x000F: // XCONFIG_USER_PC_FLAGS (parental control?) - setting_size = 1; - value[0] = 0; - break; - case 0x0010: // XCONFIG_USER_SMB_CONFIG (0x100 byte string) - // Just set the start of the buffer to 0 so that callers - // don't error from an un-inited buffer - setting_size = 4; - xe::store_and_swap(value, 0); - break; - default: - assert_unhandled_case(setting); - return X_STATUS_INVALID_PARAMETER_2; - } - break; - default: - assert_unhandled_case(category); - return X_STATUS_INVALID_PARAMETER_1; - } - - if (buffer) { - if (buffer_size < setting_size) { - return X_STATUS_BUFFER_TOO_SMALL; - } - std::memcpy(buffer, value, setting_size); - } else { - if (buffer_size) { - return X_STATUS_INVALID_PARAMETER_3; - } - } - if (required_size) { - *required_size = setting_size; - } - - return X_STATUS_SUCCESS; -} - -dword_result_t ExGetXConfigSetting(word_t category, word_t setting, - lpdword_t buffer_ptr, word_t buffer_size, - lpword_t required_size_ptr) { - uint16_t required_size = 0; - X_STATUS result = xeExGetXConfigSetting(category, setting, buffer_ptr, - buffer_size, &required_size); - - if (required_size_ptr) { - *required_size_ptr = required_size; - } - - return result; -} -DECLARE_XBOXKRNL_EXPORT1(ExGetXConfigSetting, kModules, kImplemented); - -dword_result_t XexCheckExecutablePrivilege(dword_t privilege) { - // BOOL - // DWORD Privilege - - // Privilege is bit position in xe_xex2_system_flags enum - so: - // Privilege=6 -> 0x00000040 -> XEX_SYSTEM_INSECURE_SOCKETS - uint32_t mask = 1 << privilege; - - auto module = kernel_state()->GetExecutableModule(); - if (!module) { - return 0; - } - - uint32_t flags = 0; - module->GetOptHeader(XEX_HEADER_SYSTEM_FLAGS, &flags); - - return (flags & mask) > 0; -} -DECLARE_XBOXKRNL_EXPORT1(XexCheckExecutablePrivilege, kModules, kImplemented); - -dword_result_t XexGetModuleHandle(lpstring_t module_name, - lpdword_t hmodule_ptr) { - object_ref module; - - if (!module_name) { - module = kernel_state()->GetExecutableModule(); - } else { - module = kernel_state()->GetModule(module_name); - } - - if (!module) { - *hmodule_ptr = 0; - return X_ERROR_NOT_FOUND; - } - - // NOTE: we don't retain the handle for return. - *hmodule_ptr = module->hmodule_ptr(); - - return X_ERROR_SUCCESS; -} -DECLARE_XBOXKRNL_EXPORT1(XexGetModuleHandle, kModules, kImplemented); - -dword_result_t XexGetModuleSection(lpvoid_t hmodule, lpstring_t name, - lpdword_t data_ptr, lpdword_t size_ptr) { - X_STATUS result = X_STATUS_SUCCESS; - - auto module = XModule::GetFromHModule(kernel_state(), hmodule); - if (module) { - uint32_t section_data = 0; - uint32_t section_size = 0; - result = module->GetSection(name, §ion_data, §ion_size); - if (XSUCCEEDED(result)) { - *data_ptr = section_data; - *size_ptr = section_size; - } - } else { - result = X_STATUS_INVALID_HANDLE; - } - - return result; -} -DECLARE_XBOXKRNL_EXPORT1(XexGetModuleSection, kModules, kImplemented); - -dword_result_t XexLoadImage(lpstring_t module_name, dword_t module_flags, - dword_t min_version, lpdword_t hmodule_ptr) { - X_STATUS result = X_STATUS_NO_SUCH_FILE; - - uint32_t hmodule = 0; - auto module = kernel_state()->GetModule(module_name); - if (module) { - // Existing module found. - hmodule = module->hmodule_ptr(); - result = X_STATUS_SUCCESS; - } else { - // Not found; attempt to load as a user module. - auto user_module = kernel_state()->LoadUserModule(module_name); - if (user_module) { - user_module->Retain(); - hmodule = user_module->hmodule_ptr(); - result = X_STATUS_SUCCESS; - } - } - - // Increment the module's load count. - if (hmodule) { - auto ldr_data = - kernel_memory()->TranslateVirtual(hmodule); - ldr_data->load_count++; - } - - *hmodule_ptr = hmodule; - - return result; -} -DECLARE_XBOXKRNL_EXPORT1(XexLoadImage, kModules, kImplemented); - -dword_result_t XexUnloadImage(lpvoid_t hmodule) { - auto module = XModule::GetFromHModule(kernel_state(), hmodule); - if (!module) { - return X_STATUS_INVALID_HANDLE; - } - - // Can't unload kernel modules from user code. - if (module->module_type() != XModule::ModuleType::kKernelModule) { - auto ldr_data = hmodule.as(); - if (--ldr_data->load_count == 0) { - // No more references, free it. - module->Release(); - kernel_state()->object_table()->RemoveHandle(module->handle()); - } - } - - return X_STATUS_SUCCESS; -} -DECLARE_XBOXKRNL_EXPORT1(XexUnloadImage, kModules, kImplemented); - -dword_result_t XexGetProcedureAddress(lpvoid_t hmodule, dword_t ordinal, - lpdword_t out_function_ptr) { - // May be entry point? - assert_not_zero(ordinal); - - bool is_string_name = (ordinal & 0xFFFF0000) != 0; - auto string_name = - reinterpret_cast(kernel_memory()->TranslateVirtual(ordinal)); - - X_STATUS result = X_STATUS_INVALID_HANDLE; - - object_ref module; - if (!hmodule) { - module = kernel_state()->GetExecutableModule(); - } else { - module = XModule::GetFromHModule(kernel_state(), hmodule); - } - if (module) { - uint32_t ptr; - if (is_string_name) { - ptr = module->GetProcAddressByName(string_name); - } else { - ptr = module->GetProcAddressByOrdinal(ordinal); - } - if (ptr) { - *out_function_ptr = ptr; - result = X_STATUS_SUCCESS; - } else { - XELOGW("ERROR: XexGetProcedureAddress ordinal not found!"); - *out_function_ptr = 0; - result = X_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND; - } - } - - return result; -} -DECLARE_XBOXKRNL_EXPORT1(XexGetProcedureAddress, kModules, kImplemented); - -void ExRegisterTitleTerminateNotification( - pointer_t reg, dword_t create) { - if (create) { - // Adding. - kernel_state()->RegisterTitleTerminateNotification( - reg->notification_routine, reg->priority); - } else { - // Removing. - kernel_state()->RemoveTitleTerminateNotification(reg->notification_routine); - } -} -DECLARE_XBOXKRNL_EXPORT1(ExRegisterTitleTerminateNotification, kModules, - kImplemented); - -void RegisterModuleExports(xe::cpu::ExportResolver* export_resolver, - KernelState* kernel_state) {} - -} // namespace xboxkrnl -} // namespace kernel -} // namespace xe diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc index c601b51da..220a2d4a0 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc @@ -137,6 +137,9 @@ dword_result_t ExCreateThread(lpdword_t handle_ptr, dword_t stack_size, if (handle_ptr) { if (creation_flags & 0x80) { *handle_ptr = thread->guest_object(); + } else if (!*handle_ptr && (creation_flags == X_CREATE_SUSPENDED)) { + // TODO(Gliniak): Temporary solution, requires more research // && !stack_size + *handle_ptr = thread->handle(); } else { thread->RetainHandle(); *handle_ptr = thread->handle(); diff --git a/src/xenia/kernel/xobject.cc b/src/xenia/kernel/xobject.cc index 7f615ef4b..01e333a63 100644 --- a/src/xenia/kernel/xobject.cc +++ b/src/xenia/kernel/xobject.cc @@ -68,7 +68,7 @@ Emulator* XObject::emulator() const { return kernel_state_->emulator_; } KernelState* XObject::kernel_state() const { return kernel_state_; } Memory* XObject::memory() const { return kernel_state_->memory(); } -XObject::Type XObject::type() const { return type_; } +XObject::Type XObject::type() { return type_; } void XObject::RetainHandle() { kernel_state_->object_table()->RetainHandle(handles_[0]); diff --git a/src/xenia/kernel/xobject.h b/src/xenia/kernel/xobject.h index 23ab38d6e..280250ca5 100644 --- a/src/xenia/kernel/xobject.h +++ b/src/xenia/kernel/xobject.h @@ -134,7 +134,7 @@ class XObject { KernelState* kernel_state() const; Memory* memory() const; - Type type() const; + Type type(); // Returns the primary handle of this object. X_HANDLE handle() const { return handles_[0]; } diff --git a/src/xenia/vfs/virtual_file_system.cc b/src/xenia/vfs/virtual_file_system.cc index aad0356de..d6b3a250a 100644 --- a/src/xenia/vfs/virtual_file_system.cc +++ b/src/xenia/vfs/virtual_file_system.cc @@ -85,7 +85,6 @@ bool VirtualFileSystem::UnregisterSymbolicLink(const std::string& path) { symlinks_.erase(it); return true; } - bool VirtualFileSystem::IsSymbolicLink(const std::string& path) { auto global_lock = global_critical_region_.Acquire(); auto it = symlinks_.find(path); diff --git a/src/xenia/vfs/virtual_file_system.h b/src/xenia/vfs/virtual_file_system.h index b41f7d385..6c20a3d08 100644 --- a/src/xenia/vfs/virtual_file_system.h +++ b/src/xenia/vfs/virtual_file_system.h @@ -34,7 +34,7 @@ class VirtualFileSystem { bool RegisterSymbolicLink(const std::string& path, const std::string& target); bool UnregisterSymbolicLink(const std::string& path); - bool VirtualFileSystem::IsSymbolicLink(const std::string& path); + bool IsSymbolicLink(const std::string& path); bool FindSymbolicLink(const std::string& path, std::string& target); Entry* ResolvePath(const std::string& path);