diff options
Diffstat (limited to 'src/core')
25 files changed, 478 insertions, 26 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index ec011787e..1bc536075 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -12,6 +12,8 @@ add_library(core STATIC file_sys/filesystem.h file_sys/path_parser.cpp file_sys/path_parser.h + file_sys/program_metadata.cpp + file_sys/program_metadata.h file_sys/romfs_factory.cpp file_sys/romfs_factory.h file_sys/romfs_filesystem.cpp diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index 283d20831..e7f6bf8c2 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp @@ -6,6 +6,7 @@ #include <memory> #include <dynarmic/A64/a64.h> #include <dynarmic/A64/config.h> +#include "common/logging/log.h" #include "core/arm/dynarmic/arm_dynarmic.h" #include "core/core_timing.h" #include "core/hle/kernel/memory.h" @@ -53,6 +54,9 @@ public: } void InterpreterFallback(u64 pc, size_t num_instructions) override { + LOG_INFO(Core_ARM, "Unicorn fallback @ 0x%" PRIx64 " for %zu instructions (instr = %08x)", + pc, num_instructions, MemoryReadCode(pc)); + ARM_Interface::ThreadContext ctx; parent.SaveContext(ctx); parent.inner_unicorn.LoadContext(ctx); @@ -63,8 +67,17 @@ public: } void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override { - ASSERT_MSG(false, "ExceptionRaised(exception = %zu, pc = %" PRIx64 ")", - static_cast<size_t>(exception), pc); + switch (exception) { + case Dynarmic::A64::Exception::WaitForInterrupt: + case Dynarmic::A64::Exception::WaitForEvent: + case Dynarmic::A64::Exception::SendEvent: + case Dynarmic::A64::Exception::SendEventLocal: + case Dynarmic::A64::Exception::Yield: + return; + default: + ASSERT_MSG(false, "ExceptionRaised(exception = %zu, pc = %" PRIx64 ")", + static_cast<size_t>(exception), pc); + } } void CallSVC(u32 swi) override { @@ -81,11 +94,15 @@ public: u64 GetTicksRemaining() override { return ticks_remaining; } + u64 GetCNTPCT() override { + return CoreTiming::GetTicks(); + } ARM_Dynarmic& parent; size_t ticks_remaining = 0; size_t num_interpreted_instructions = 0; u64 tpidrro_el0 = 0; + u64 tpidr_el0 = 0; }; std::unique_ptr<Dynarmic::A64::Jit> MakeJit(const std::unique_ptr<ARM_Dynarmic_Callbacks>& cb) { @@ -94,10 +111,13 @@ std::unique_ptr<Dynarmic::A64::Jit> MakeJit(const std::unique_ptr<ARM_Dynarmic_C Dynarmic::A64::UserConfig config; config.callbacks = cb.get(); config.tpidrro_el0 = &cb->tpidrro_el0; + config.tpidr_el0 = &cb->tpidr_el0; config.dczid_el0 = 4; + config.ctr_el0 = 0x8444c004; config.page_table = reinterpret_cast<void**>(page_table); config.page_table_address_space_bits = Memory::ADDRESS_SPACE_BITS; config.silently_mirror_page_table = false; + return std::make_unique<Dynarmic::A64::Jit>(config); } diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index fd64eab39..5d2956bfd 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp @@ -52,7 +52,8 @@ static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int si void* user_data) { ARM_Interface::ThreadContext ctx{}; Core::CPU().SaveContext(ctx); - ASSERT_MSG(false, "Attempted to read from unmapped memory: 0x%llx", addr); + ASSERT_MSG(false, "Attempted to read from unmapped memory: 0x%llx, pc=0x%llx, lr=0x%llx", addr, + ctx.pc, ctx.cpu_registers[30]); return {}; } diff --git a/src/core/core.cpp b/src/core/core.cpp index 8c5dd3761..4fb035556 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -139,6 +139,8 @@ void System::Reschedule() { System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) { LOG_DEBUG(HW_Memory, "initialized OK"); + CoreTiming::Init(); + switch (Settings::values.cpu_core) { case Settings::CpuCore::Unicorn: cpu_core = std::make_shared<ARM_Unicorn>(); @@ -154,14 +156,13 @@ System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) { break; } - scheduler = std::make_unique<Kernel::Scheduler>(cpu_core.get()); gpu_core = std::make_unique<Tegra::GPU>(); telemetry_session = std::make_unique<Core::TelemetrySession>(); - CoreTiming::Init(); HW::Init(); Kernel::Init(system_mode); + scheduler = std::make_unique<Kernel::Scheduler>(cpu_core.get()); Service::Init(); GDBStub::Init(); @@ -189,15 +190,18 @@ void System::Shutdown() { perf_results.frametime * 1000.0); // Shutdown emulation session - GDBStub::Shutdown(); VideoCore::Shutdown(); + GDBStub::Shutdown(); Service::Shutdown(); + scheduler = nullptr; Kernel::Shutdown(); HW::Shutdown(); - CoreTiming::Shutdown(); + telemetry_session = nullptr; + gpu_core = nullptr; cpu_core = nullptr; + CoreTiming::Shutdown(); + app_loader = nullptr; - telemetry_session = nullptr; LOG_DEBUG(Core, "Shutdown OK"); } diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp new file mode 100644 index 000000000..a6dcebcc3 --- /dev/null +++ b/src/core/file_sys/program_metadata.cpp @@ -0,0 +1,114 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <cinttypes> +#include "common/file_util.h" +#include "common/logging/log.h" +#include "core/file_sys/program_metadata.h" +#include "core/loader/loader.h" + +namespace FileSys { + +Loader::ResultStatus ProgramMetadata::Load(const std::string& file_path) { + FileUtil::IOFile file(file_path, "rb"); + if (!file.IsOpen()) + return Loader::ResultStatus::Error; + + std::vector<u8> file_data(file.GetSize()); + + if (!file.ReadBytes(file_data.data(), file_data.size())) + return Loader::ResultStatus::Error; + + Loader::ResultStatus result = Load(file_data); + if (result != Loader::ResultStatus::Success) + LOG_ERROR(Service_FS, "Failed to load NPDM from file %s!", file_path.c_str()); + + return result; +} + +Loader::ResultStatus ProgramMetadata::Load(const std::vector<u8> file_data, size_t offset) { + size_t total_size = static_cast<size_t>(file_data.size() - offset); + if (total_size < sizeof(Header)) + return Loader::ResultStatus::Error; + + size_t header_offset = offset; + memcpy(&npdm_header, &file_data[offset], sizeof(Header)); + + size_t aci_offset = header_offset + npdm_header.aci_offset; + size_t acid_offset = header_offset + npdm_header.acid_offset; + memcpy(&aci_header, &file_data[aci_offset], sizeof(AciHeader)); + memcpy(&acid_header, &file_data[acid_offset], sizeof(AcidHeader)); + + size_t fac_offset = acid_offset + acid_header.fac_offset; + size_t fah_offset = aci_offset + aci_header.fah_offset; + memcpy(&acid_file_access, &file_data[fac_offset], sizeof(FileAccessControl)); + memcpy(&aci_file_access, &file_data[fah_offset], sizeof(FileAccessHeader)); + + return Loader::ResultStatus::Success; +} + +bool ProgramMetadata::Is64BitProgram() const { + return npdm_header.has_64_bit_instructions; +} + +ProgramAddressSpaceType ProgramMetadata::GetAddressSpaceType() const { + return npdm_header.address_space_type; +} + +u8 ProgramMetadata::GetMainThreadPriority() const { + return npdm_header.main_thread_priority; +} + +u8 ProgramMetadata::GetMainThreadCore() const { + return npdm_header.main_thread_cpu; +} + +u32 ProgramMetadata::GetMainThreadStackSize() const { + return npdm_header.main_stack_size; +} + +u64 ProgramMetadata::GetTitleID() const { + return aci_header.title_id; +} + +u64 ProgramMetadata::GetFilesystemPermissions() const { + return aci_file_access.permissions; +} + +void ProgramMetadata::Print() const { + LOG_DEBUG(Service_FS, "Magic: %.4s", npdm_header.magic.data()); + LOG_DEBUG(Service_FS, "Main thread priority: 0x%02x", npdm_header.main_thread_priority); + LOG_DEBUG(Service_FS, "Main thread core: %u", npdm_header.main_thread_cpu); + LOG_DEBUG(Service_FS, "Main thread stack size: 0x%x bytes", npdm_header.main_stack_size); + LOG_DEBUG(Service_FS, "Process category: %u", npdm_header.process_category); + LOG_DEBUG(Service_FS, "Flags: %02x", npdm_header.flags); + LOG_DEBUG(Service_FS, " > 64-bit instructions: %s", + npdm_header.has_64_bit_instructions ? "YES" : "NO"); + + auto address_space = "Unknown"; + switch (npdm_header.address_space_type) { + case ProgramAddressSpaceType::Is64Bit: + address_space = "64-bit"; + break; + case ProgramAddressSpaceType::Is32Bit: + address_space = "32-bit"; + break; + } + + LOG_DEBUG(Service_FS, " > Address space: %s\n", address_space); + + // Begin ACID printing (potential perms, signed) + LOG_DEBUG(Service_FS, "Magic: %.4s", acid_header.magic.data()); + LOG_DEBUG(Service_FS, "Flags: %02x", acid_header.flags); + LOG_DEBUG(Service_FS, " > Is Retail: %s", acid_header.is_retail ? "YES" : "NO"); + LOG_DEBUG(Service_FS, "Title ID Min: %016" PRIX64, acid_header.title_id_min); + LOG_DEBUG(Service_FS, "Title ID Max: %016" PRIX64, acid_header.title_id_max); + LOG_DEBUG(Service_FS, "Filesystem Access: %016" PRIX64 "\n", acid_file_access.permissions); + + // Begin ACI0 printing (actual perms, unsigned) + LOG_DEBUG(Service_FS, "Magic: %.4s", aci_header.magic.data()); + LOG_DEBUG(Service_FS, "Title ID: %016" PRIX64, aci_header.title_id); + LOG_DEBUG(Service_FS, "Filesystem Access: %016" PRIX64 "\n", aci_file_access.permissions); +} +} // namespace FileSys diff --git a/src/core/file_sys/program_metadata.h b/src/core/file_sys/program_metadata.h new file mode 100644 index 000000000..b80a08485 --- /dev/null +++ b/src/core/file_sys/program_metadata.h @@ -0,0 +1,154 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <array> +#include <string> +#include <vector> +#include "common/bit_field.h" +#include "common/common_types.h" +#include "common/swap.h" + +namespace Loader { +enum class ResultStatus; +} + +namespace FileSys { + +enum class ProgramAddressSpaceType : u8 { + Is64Bit = 1, + Is32Bit = 2, +}; + +enum class ProgramFilePermission : u64 { + MountContent = 1ULL << 0, + SaveDataBackup = 1ULL << 5, + SdCard = 1ULL << 21, + Calibration = 1ULL << 34, + Bit62 = 1ULL << 62, + Everything = 1ULL << 63, +}; + +/** + * Helper which implements an interface to parse Program Description Metadata (NPDM) + * Data can either be loaded from a file path or with data and an offset into it. + */ +class ProgramMetadata { +public: + Loader::ResultStatus Load(const std::string& file_path); + Loader::ResultStatus Load(const std::vector<u8> file_data, size_t offset = 0); + + bool Is64BitProgram() const; + ProgramAddressSpaceType GetAddressSpaceType() const; + u8 GetMainThreadPriority() const; + u8 GetMainThreadCore() const; + u32 GetMainThreadStackSize() const; + u64 GetTitleID() const; + u64 GetFilesystemPermissions() const; + + void Print() const; + +private: + struct Header { + std::array<char, 4> magic; + std::array<u8, 8> reserved; + union { + u8 flags; + + BitField<0, 1, u8> has_64_bit_instructions; + BitField<1, 3, ProgramAddressSpaceType> address_space_type; + BitField<4, 4, u8> reserved_2; + }; + u8 reserved_3; + u8 main_thread_priority; + u8 main_thread_cpu; + std::array<u8, 8> reserved_4; + u32_le process_category; + u32_le main_stack_size; + std::array<u8, 0x10> application_name; + std::array<u8, 0x40> reserved_5; + u32_le aci_offset; + u32_le aci_size; + u32_le acid_offset; + u32_le acid_size; + }; + + static_assert(sizeof(Header) == 0x80, "NPDM header structure size is wrong"); + + struct AcidHeader { + std::array<u8, 0x100> signature; + std::array<u8, 0x100> nca_modulus; + std::array<char, 4> magic; + u32_le nca_size; + std::array<u8, 0x4> reserved; + union { + u32 flags; + + BitField<0, 1, u32> is_retail; + BitField<1, 31, u32> flags_unk; + }; + u64_le title_id_min; + u64_le title_id_max; + u32_le fac_offset; + u32_le fac_size; + u32_le sac_offset; + u32_le sac_size; + u32_le kac_offset; + u32_le kac_size; + INSERT_PADDING_BYTES(0x8); + }; + + static_assert(sizeof(AcidHeader) == 0x240, "ACID header structure size is wrong"); + + struct AciHeader { + std::array<char, 4> magic; + std::array<u8, 0xC> reserved; + u64_le title_id; + INSERT_PADDING_BYTES(0x8); + u32_le fah_offset; + u32_le fah_size; + u32_le sac_offset; + u32_le sac_size; + u32_le kac_offset; + u32_le kac_size; + INSERT_PADDING_BYTES(0x8); + }; + + static_assert(sizeof(AciHeader) == 0x40, "ACI0 header structure size is wrong"); + +#pragma pack(push, 1) + + struct FileAccessControl { + u8 version; + INSERT_PADDING_BYTES(3); + u64_le permissions; + std::array<u8, 0x20> unknown; + }; + + static_assert(sizeof(FileAccessControl) == 0x2C, "FS access control structure size is wrong"); + + struct FileAccessHeader { + u8 version; + INSERT_PADDING_BYTES(3); + u64_le permissions; + u32_le unk_offset; + u32_le unk_size; + u32_le unk_offset_2; + u32_le unk_size_2; + }; + + static_assert(sizeof(FileAccessHeader) == 0x1C, "FS access header structure size is wrong"); + +#pragma pack(pop) + + Header npdm_header; + AciHeader aci_header; + AcidHeader acid_header; + + FileAccessControl acid_file_access; + FileAccessHeader aci_file_access; +}; + +} // namespace FileSys diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index cbd5b69aa..1ab8cbd88 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include <algorithm> +#include <cinttypes> #include "common/logging/log.h" #include "common/microprofile.h" @@ -443,6 +444,16 @@ static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 s return RESULT_SUCCESS; } +static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size) { + LOG_WARNING(Kernel_SVC, + "called, shared_memory_handle=0x%08X, addr=0x%" PRIx64 ", size=0x%" PRIx64 "", + shared_memory_handle, addr, size); + + SharedPtr<SharedMemory> shared_memory = g_handle_table.Get<SharedMemory>(shared_memory_handle); + + return shared_memory->Unmap(g_current_process.get(), addr); +} + /// Query process memory static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_info*/, Handle process_handle, u64 addr) { @@ -761,6 +772,16 @@ static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permiss return RESULT_SUCCESS; } +static ResultCode ClearEvent(Handle handle) { + LOG_TRACE(Kernel_SVC, "called, event=0xX", handle); + + SharedPtr<Event> evt = g_handle_table.Get<Event>(handle); + if (evt == nullptr) + return ERR_INVALID_HANDLE; + evt->Clear(); + return RESULT_SUCCESS; +} + namespace { struct FunctionDef { using Func = void(); @@ -790,9 +811,9 @@ static const FunctionDef SVC_Table[] = { {0x0F, SvcWrap<SetThreadCoreMask>, "SetThreadCoreMask"}, {0x10, SvcWrap<GetCurrentProcessorNumber>, "GetCurrentProcessorNumber"}, {0x11, nullptr, "SignalEvent"}, - {0x12, nullptr, "ClearEvent"}, + {0x12, SvcWrap<ClearEvent>, "ClearEvent"}, {0x13, SvcWrap<MapSharedMemory>, "MapSharedMemory"}, - {0x14, nullptr, "UnmapSharedMemory"}, + {0x14, SvcWrap<UnmapSharedMemory>, "UnmapSharedMemory"}, {0x15, SvcWrap<CreateTransferMemory>, "CreateTransferMemory"}, {0x16, SvcWrap<CloseHandle>, "CloseHandle"}, {0x17, SvcWrap<ResetSignal>, "ResetSignal"}, diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 7a165d8dc..b224f5e67 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -91,6 +91,11 @@ void SvcWrap() { FuncReturn(func((u32)PARAM(0), PARAM(1), PARAM(2), (u32)PARAM(3)).raw); } +template <ResultCode func(u32, u64, u64)> +void SvcWrap() { + FuncReturn(func((u32)PARAM(0), PARAM(1), PARAM(2)).raw); +} + template <ResultCode func(u32*, u64, u64, s64)> void SvcWrap() { u32 param_1 = 0; diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 03305814f..d3a674cf6 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -34,7 +34,38 @@ void IWindowController::AcquireForegroundRights(Kernel::HLERequestContext& ctx) rb.Push(RESULT_SUCCESS); } -IAudioController::IAudioController() : ServiceFramework("IAudioController") {} +IAudioController::IAudioController() : ServiceFramework("IAudioController") { + static const FunctionInfo functions[] = { + {0, &IAudioController::SetExpectedMasterVolume, "SetExpectedMasterVolume"}, + {1, &IAudioController::GetMainAppletExpectedMasterVolume, + "GetMainAppletExpectedMasterVolume"}, + {2, &IAudioController::GetLibraryAppletExpectedMasterVolume, + "GetLibraryAppletExpectedMasterVolume"}, + {3, nullptr, "ChangeMainAppletMasterVolume"}, + {4, nullptr, "SetTransparentVolumeRate"}, + }; + RegisterHandlers(functions); +} + +void IAudioController::SetExpectedMasterVolume(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void IAudioController::GetMainAppletExpectedMasterVolume(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push(volume); +} + +void IAudioController::GetLibraryAppletExpectedMasterVolume(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push(volume); +} IDisplayController::IDisplayController() : ServiceFramework("IDisplayController") {} @@ -46,6 +77,7 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger {1, &ISelfController::LockExit, "LockExit"}, {2, &ISelfController::UnlockExit, "UnlockExit"}, {9, &ISelfController::GetLibraryAppletLaunchableEvent, "GetLibraryAppletLaunchableEvent"}, + {10, &ISelfController::SetScreenShotPermission, "SetScreenShotPermission"}, {11, &ISelfController::SetOperationModeChangedNotification, "SetOperationModeChangedNotification"}, {12, &ISelfController::SetPerformanceModeChangedNotification, @@ -98,6 +130,13 @@ void ISelfController::SetPerformanceModeChangedNotification(Kernel::HLERequestCo LOG_WARNING(Service_AM, "(STUBBED) called flag=%u", static_cast<u32>(flag)); } +void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + + LOG_WARNING(Service_AM, "(STUBBED) called"); +} + void ISelfController::SetOperationModeChangedNotification(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 793ac6555..27dbd8c95 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -36,6 +36,13 @@ private: class IAudioController final : public ServiceFramework<IAudioController> { public: IAudioController(); + +private: + void SetExpectedMasterVolume(Kernel::HLERequestContext& ctx); + void GetMainAppletExpectedMasterVolume(Kernel::HLERequestContext& ctx); + void GetLibraryAppletExpectedMasterVolume(Kernel::HLERequestContext& ctx); + + u32 volume{100}; }; class IDisplayController final : public ServiceFramework<IDisplayController> { @@ -62,6 +69,7 @@ private: void UnlockExit(Kernel::HLERequestContext& ctx); void GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx); void CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx); + void SetScreenShotPermission(Kernel::HLERequestContext& ctx); std::shared_ptr<NVFlinger::NVFlinger> nvflinger; Kernel::SharedPtr<Kernel::Event> launchable_event; diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp index 430b2a7ad..8b55d2fcb 100644 --- a/src/core/hle/service/aoc/aoc_u.cpp +++ b/src/core/hle/service/aoc/aoc_u.cpp @@ -13,7 +13,7 @@ AOC_U::AOC_U() : ServiceFramework("aoc:u") { static const FunctionInfo functions[] = { {0, nullptr, "CountAddOnContentByApplicationId"}, {1, nullptr, "ListAddOnContentByApplicationId"}, - {2, nullptr, "CountAddOnContent"}, + {2, &AOC_U::CountAddOnContent, "CountAddOnContent"}, {3, &AOC_U::ListAddOnContent, "ListAddOnContent"}, {4, nullptr, "GetAddOnContentBaseIdByApplicationId"}, {5, nullptr, "GetAddOnContentBaseId"}, @@ -23,6 +23,13 @@ AOC_U::AOC_U() : ServiceFramework("aoc:u") { RegisterHandlers(functions); } +void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push<u64>(0); + LOG_WARNING(Service_AOC, "(STUBBED) called"); +} + void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 4}; rb.Push(RESULT_SUCCESS); diff --git a/src/core/hle/service/aoc/aoc_u.h b/src/core/hle/service/aoc/aoc_u.h index 4d6720a9d..6e0ba15a5 100644 --- a/src/core/hle/service/aoc/aoc_u.h +++ b/src/core/hle/service/aoc/aoc_u.h @@ -15,6 +15,7 @@ public: ~AOC_U() = default; private: + void CountAddOnContent(Kernel::HLERequestContext& ctx); void ListAddOnContent(Kernel::HLERequestContext& ctx); }; diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index 4efc789ac..dda135d18 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -178,10 +178,10 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { } void AudRenU::GetAudioRenderersProcessMasterVolume(Kernel::HLERequestContext& ctx) { - IPC::ResponseBuilder rb{ctx, 2}; + IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - + rb.Push<u32>(100); LOG_WARNING(Service_Audio, "(STUBBED) called"); } diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp index 290a2ee74..e6f05eae5 100644 --- a/src/core/hle/service/nifm/nifm.cpp +++ b/src/core/hle/service/nifm/nifm.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/event.h" #include "core/hle/service/nifm/nifm.h" #include "core/hle/service/nifm/nifm_a.h" #include "core/hle/service/nifm/nifm_s.h" @@ -28,9 +29,9 @@ class IRequest final : public ServiceFramework<IRequest> { public: explicit IRequest() : ServiceFramework("IRequest") { static const FunctionInfo functions[] = { - {0, nullptr, "GetRequestState"}, - {1, nullptr, "GetResult"}, - {2, nullptr, "GetSystemEventReadableHandles"}, + {0, &IRequest::GetRequestState, "GetRequestState"}, + {1, &IRequest::GetResult, "GetResult"}, + {2, &IRequest::GetSystemEventReadableHandles, "GetSystemEventReadableHandles"}, {3, nullptr, "Cancel"}, {4, nullptr, "Submit"}, {5, nullptr, "SetRequirement"}, @@ -55,7 +56,32 @@ public: {25, nullptr, "UnregisterSocketDescriptor"}, }; RegisterHandlers(functions); + + event1 = Kernel::Event::Create(Kernel::ResetType::OneShot, "IRequest:Event1"); + event2 = Kernel::Event::Create(Kernel::ResetType::OneShot, "IRequest:Event2"); + } + +private: + void GetRequestState(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_NIFM, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(0); } + void GetResult(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_NIFM, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(0); + } + void GetSystemEventReadableHandles(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_NIFM, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 2, 2}; + rb.Push(RESULT_SUCCESS); + rb.PushCopyObjects(event1, event2); + } + + Kernel::SharedPtr<Kernel::Event> event1, event2; }; class INetworkProfile final : public ServiceFramework<INetworkProfile> { diff --git a/src/core/hle/service/sockets/bsd_u.cpp b/src/core/hle/service/sockets/bsd_u.cpp index 629ffb040..2ca1000ca 100644 --- a/src/core/hle/service/sockets/bsd_u.cpp +++ b/src/core/hle/service/sockets/bsd_u.cpp @@ -17,6 +17,15 @@ void BSD_U::RegisterClient(Kernel::HLERequestContext& ctx) { rb.Push<u32>(0); // bsd errno } +void BSD_U::StartMonitoring(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(0); // bsd errno +} + void BSD_U::Socket(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; @@ -67,6 +76,7 @@ void BSD_U::Close(Kernel::HLERequestContext& ctx) { BSD_U::BSD_U() : ServiceFramework("bsd:u") { static const FunctionInfo functions[] = {{0, &BSD_U::RegisterClient, "RegisterClient"}, + {1, &BSD_U::StartMonitoring, "StartMonitoring"}, {2, &BSD_U::Socket, "Socket"}, {11, &BSD_U::SendTo, "SendTo"}, {14, &BSD_U::Connect, "Connect"}, diff --git a/src/core/hle/service/sockets/bsd_u.h b/src/core/hle/service/sockets/bsd_u.h index fde08a22b..4e1252e9d 100644 --- a/src/core/hle/service/sockets/bsd_u.h +++ b/src/core/hle/service/sockets/bsd_u.h @@ -17,6 +17,7 @@ public: private: void RegisterClient(Kernel::HLERequestContext& ctx); + void StartMonitoring(Kernel::HLERequestContext& ctx); void Socket(Kernel::HLERequestContext& ctx); void Connect(Kernel::HLERequestContext& ctx); void SendTo(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp index 364ddcea2..ad49f4265 100644 --- a/src/core/hle/service/time/time.cpp +++ b/src/core/hle/service/time/time.cpp @@ -146,6 +146,13 @@ void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_Time, "called"); } +void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<ISystemClock>(); + LOG_DEBUG(Service_Time, "called"); +} + Module::Interface::Interface(std::shared_ptr<Module> time, const char* name) : ServiceFramework(name), time(std::move(time)) {} diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h index 1cbbadb21..197029e7a 100644 --- a/src/core/hle/service/time/time.h +++ b/src/core/hle/service/time/time.h @@ -56,6 +56,7 @@ public: void GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx); void GetStandardSteadyClock(Kernel::HLERequestContext& ctx); void GetTimeZoneService(Kernel::HLERequestContext& ctx); + void GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx); protected: std::shared_ptr<Module> time; diff --git a/src/core/hle/service/time/time_s.cpp b/src/core/hle/service/time/time_s.cpp index 1634d3300..b172b2bd6 100644 --- a/src/core/hle/service/time/time_s.cpp +++ b/src/core/hle/service/time/time_s.cpp @@ -10,6 +10,10 @@ namespace Time { TIME_S::TIME_S(std::shared_ptr<Module> time) : Module::Interface(std::move(time), "time:s") { static const FunctionInfo functions[] = { {0, &TIME_S::GetStandardUserSystemClock, "GetStandardUserSystemClock"}, + {1, &TIME_S::GetStandardNetworkSystemClock, "GetStandardNetworkSystemClock"}, + {2, &TIME_S::GetStandardSteadyClock, "GetStandardSteadyClock"}, + {3, &TIME_S::GetTimeZoneService, "GetTimeZoneService"}, + {4, &TIME_S::GetStandardLocalSystemClock, "GetStandardLocalSystemClock"}, }; RegisterHandlers(functions); } diff --git a/src/core/hle/service/time/time_u.cpp b/src/core/hle/service/time/time_u.cpp index ae4f78adf..fc1ace325 100644 --- a/src/core/hle/service/time/time_u.cpp +++ b/src/core/hle/service/time/time_u.cpp @@ -13,6 +13,7 @@ TIME_U::TIME_U(std::shared_ptr<Module> time) : Module::Interface(std::move(time) {1, &TIME_U::GetStandardNetworkSystemClock, "GetStandardNetworkSystemClock"}, {2, &TIME_U::GetStandardSteadyClock, "GetStandardSteadyClock"}, {3, &TIME_U::GetTimeZoneService, "GetTimeZoneService"}, + {4, &TIME_U::GetStandardLocalSystemClock, "GetStandardLocalSystemClock"}, }; RegisterHandlers(functions); } diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 661803b5f..864cf25cd 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -53,6 +53,7 @@ AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileUti FileType AppLoader_DeconstructedRomDirectory::IdentifyType(FileUtil::IOFile& file, const std::string& filepath) { bool is_main_found{}; + bool is_npdm_found{}; bool is_rtld_found{}; bool is_sdk_found{}; @@ -67,6 +68,9 @@ FileType AppLoader_DeconstructedRomDirectory::IdentifyType(FileUtil::IOFile& fil // Verify filename if (Common::ToLower(virtual_name) == "main") { is_main_found = true; + } else if (Common::ToLower(virtual_name) == "main.npdm") { + is_npdm_found = true; + return true; } else if (Common::ToLower(virtual_name) == "rtld") { is_rtld_found = true; } else if (Common::ToLower(virtual_name) == "sdk") { @@ -83,14 +87,14 @@ FileType AppLoader_DeconstructedRomDirectory::IdentifyType(FileUtil::IOFile& fil } // We are done if we've found and verified all required NSOs - return !(is_main_found && is_rtld_found && is_sdk_found); + return !(is_main_found && is_npdm_found && is_rtld_found && is_sdk_found); }; // Search the directory recursively, looking for the required modules const std::string directory = filepath.substr(0, filepath.find_last_of("/\\")) + DIR_SEP; FileUtil::ForeachDirectoryEntry(nullptr, directory, callback); - if (is_main_found && is_rtld_found && is_sdk_found) { + if (is_main_found && is_npdm_found && is_rtld_found && is_sdk_found) { return FileType::DeconstructedRomDirectory; } @@ -108,14 +112,22 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load( process = Kernel::Process::Create("main"); + const std::string directory = filepath.substr(0, filepath.find_last_of("/\\")) + DIR_SEP; + const std::string npdm_path = directory + DIR_SEP + "main.npdm"; + + ResultStatus result = metadata.Load(npdm_path); + if (result != ResultStatus::Success) { + return result; + } + metadata.Print(); + // Load NSO modules VAddr next_load_addr{Memory::PROCESS_IMAGE_VADDR}; - const std::string directory = filepath.substr(0, filepath.find_last_of("/\\")) + DIR_SEP; for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3", "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) { const std::string path = directory + DIR_SEP + module; const VAddr load_addr = next_load_addr; - next_load_addr = AppLoader_NSO::LoadModule(path, load_addr); + next_load_addr = AppLoader_NSO::LoadModule(path, load_addr, metadata.GetTitleID()); if (next_load_addr) { LOG_DEBUG(Loader, "loaded module %s @ 0x%" PRIx64, module, load_addr); } else { @@ -127,7 +139,8 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load( process->address_mappings = default_address_mappings; process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); - process->Run(Memory::PROCESS_IMAGE_VADDR, 48, Kernel::DEFAULT_STACK_SIZE); + process->Run(Memory::PROCESS_IMAGE_VADDR, metadata.GetMainThreadPriority(), + metadata.GetMainThreadStackSize()); // Find the RomFS by searching for a ".romfs" file in this directory filepath_romfs = FindRomFS(directory); diff --git a/src/core/loader/deconstructed_rom_directory.h b/src/core/loader/deconstructed_rom_directory.h index 536a2dab7..23295d911 100644 --- a/src/core/loader/deconstructed_rom_directory.h +++ b/src/core/loader/deconstructed_rom_directory.h @@ -6,6 +6,7 @@ #include <string> #include "common/common_types.h" +#include "core/file_sys/program_metadata.h" #include "core/hle/kernel/kernel.h" #include "core/loader/loader.h" @@ -41,6 +42,7 @@ public: private: std::string filepath_romfs; std::string filepath; + FileSys::ProgramMetadata metadata; }; } // namespace Loader diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 407025da0..7f8d24dd6 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp @@ -92,7 +92,7 @@ static constexpr u32 PageAlignSize(u32 size) { return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; } -VAddr AppLoader_NSO::LoadModule(const std::string& path, VAddr load_base) { +VAddr AppLoader_NSO::LoadModule(const std::string& path, VAddr load_base, u64 tid) { FileUtil::IOFile file(path, "rb"); if (!file.IsOpen()) { return {}; @@ -109,7 +109,7 @@ VAddr AppLoader_NSO::LoadModule(const std::string& path, VAddr load_base) { } // Build program image - Kernel::SharedPtr<Kernel::CodeSet> codeset = Kernel::CodeSet::Create("", 0); + Kernel::SharedPtr<Kernel::CodeSet> codeset = Kernel::CodeSet::Create("", tid); std::vector<u8> program_image; for (int i = 0; i < nso_header.segments.size(); ++i) { std::vector<u8> data = @@ -158,7 +158,7 @@ ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr<Kernel::Process>& process) { process = Kernel::Process::Create("main"); // Load module - LoadModule(filepath, Memory::PROCESS_IMAGE_VADDR); + LoadModule(filepath, Memory::PROCESS_IMAGE_VADDR, 0); LOG_DEBUG(Loader, "loaded module %s @ 0x%" PRIx64, filepath.c_str(), Memory::PROCESS_IMAGE_VADDR); diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h index 1ae30a824..14eb1d87e 100644 --- a/src/core/loader/nso.h +++ b/src/core/loader/nso.h @@ -29,7 +29,7 @@ public: return IdentifyType(file, filepath); } - static VAddr LoadModule(const std::string& path, VAddr load_base); + static VAddr LoadModule(const std::string& path, VAddr load_base, u64 tid); ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; diff --git a/src/core/memory.cpp b/src/core/memory.cpp index cc1ed16b6..ce62666d7 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -118,6 +118,11 @@ boost::optional<T> ReadSpecial(VAddr addr); template <typename T> T Read(const VAddr vaddr) { + if ((vaddr >> PAGE_BITS) >= PAGE_TABLE_NUM_ENTRIES) { + LOG_ERROR(HW_Memory, "Read%lu after page table @ 0x%016" PRIX64, sizeof(T) * 8, vaddr); + return 0; + } + const PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; switch (type) { case PageType::Unmapped: @@ -146,6 +151,12 @@ bool WriteSpecial(VAddr addr, const T data); template <typename T> void Write(const VAddr vaddr, const T data) { + if ((vaddr >> PAGE_BITS) >= PAGE_TABLE_NUM_ENTRIES) { + LOG_ERROR(HW_Memory, "Write%lu after page table 0x%08X @ 0x%016" PRIX64, sizeof(data) * 8, + (u32)data, vaddr); + return; + } + const PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; switch (type) { case PageType::Unmapped: |