diff options
Diffstat (limited to '')
-rw-r--r-- | src/core/file_sys/system_archive/ng_word.cpp | 41 | ||||
-rw-r--r-- | src/core/file_sys/system_archive/ng_word.h | 1 | ||||
-rw-r--r-- | src/core/file_sys/system_archive/system_archive.cpp | 7 | ||||
-rw-r--r-- | src/core/hle/kernel/object.cpp | 2 | ||||
-rw-r--r-- | src/core/hle/kernel/process.cpp | 42 | ||||
-rw-r--r-- | src/core/hle/kernel/process.h | 30 | ||||
-rw-r--r-- | src/core/hle/kernel/readable_event.cpp | 12 | ||||
-rw-r--r-- | src/core/hle/kernel/readable_event.h | 11 | ||||
-rw-r--r-- | src/core/hle/kernel/svc.cpp | 15 | ||||
-rw-r--r-- | src/core/hle/service/ldr/ldr.cpp | 10 | ||||
-rw-r--r-- | src/core/memory.cpp | 8 |
11 files changed, 155 insertions, 24 deletions
diff --git a/src/core/file_sys/system_archive/ng_word.cpp b/src/core/file_sys/system_archive/ng_word.cpp index d0acdbd49..f4443784d 100644 --- a/src/core/file_sys/system_archive/ng_word.cpp +++ b/src/core/file_sys/system_archive/ng_word.cpp @@ -26,7 +26,7 @@ constexpr std::array<u8, 30> WORD_TXT{ VirtualDir NgWord1() { std::vector<VirtualFile> files(NgWord1Data::NUMBER_WORD_TXT_FILES); - for (std::size_t i = 0; i < NgWord1Data::NUMBER_WORD_TXT_FILES; ++i) { + for (std::size_t i = 0; i < files.size(); ++i) { files[i] = std::make_shared<ArrayVfsFile<NgWord1Data::WORD_TXT.size()>>( NgWord1Data::WORD_TXT, fmt::format("{}.txt", i)); } @@ -39,4 +39,43 @@ VirtualDir NgWord1() { return std::make_shared<VectorVfsDirectory>(files, std::vector<VirtualDir>{}, "data"); } +namespace NgWord2Data { + +constexpr std::size_t NUMBER_AC_NX_FILES = 0x10; + +// Should this archive replacement mysteriously not work on a future game, consider updating. +constexpr std::array<u8, 4> VERSION_DAT{0x0, 0x0, 0x0, 0x15}; // 5.1.0 System Version + +constexpr std::array<u8, 0x2C> AC_NX_DATA{ + 0x1F, 0x8B, 0x08, 0x08, 0xD5, 0x2C, 0x09, 0x5C, 0x04, 0x00, 0x61, 0x63, 0x72, 0x61, 0x77, + 0x00, 0xED, 0xC1, 0x01, 0x0D, 0x00, 0x00, 0x00, 0xC2, 0x20, 0xFB, 0xA7, 0xB6, 0xC7, 0x07, + 0x0C, 0x00, 0x00, 0x00, 0xC8, 0x3B, 0x11, 0x00, 0x1C, 0xC7, 0x00, 0x10, 0x00, 0x00, +}; // Deserializes to no bad words + +} // namespace NgWord2Data + +VirtualDir NgWord2() { + std::vector<VirtualFile> files(NgWord2Data::NUMBER_AC_NX_FILES * 3); + + for (std::size_t i = 0; i < NgWord2Data::NUMBER_AC_NX_FILES; ++i) { + files[3 * i] = std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>( + NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_b1_nx", i)); + files[3 * i + 1] = std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>( + NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_b2_nx", i)); + files[3 * i + 2] = std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>( + NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_not_b_nx", i)); + } + + files.push_back(std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>( + NgWord2Data::AC_NX_DATA, "ac_common_b1_nx")); + files.push_back(std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>( + NgWord2Data::AC_NX_DATA, "ac_common_b2_nx")); + files.push_back(std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>( + NgWord2Data::AC_NX_DATA, "ac_common_not_b_nx")); + files.push_back(std::make_shared<ArrayVfsFile<NgWord2Data::VERSION_DAT.size()>>( + NgWord2Data::VERSION_DAT, "version.dat")); + + return std::make_shared<VectorVfsDirectory>(files, std::vector<VirtualDir>{}, "data"); +} + } // namespace FileSys::SystemArchive diff --git a/src/core/file_sys/system_archive/ng_word.h b/src/core/file_sys/system_archive/ng_word.h index f4bc67344..cd81e0abb 100644 --- a/src/core/file_sys/system_archive/ng_word.h +++ b/src/core/file_sys/system_archive/ng_word.h @@ -9,5 +9,6 @@ namespace FileSys::SystemArchive { VirtualDir NgWord1(); +VirtualDir NgWord2(); } // namespace FileSys::SystemArchive diff --git a/src/core/file_sys/system_archive/system_archive.cpp b/src/core/file_sys/system_archive/system_archive.cpp index c9c40a07d..e3e79f40a 100644 --- a/src/core/file_sys/system_archive/system_archive.cpp +++ b/src/core/file_sys/system_archive/system_archive.cpp @@ -2,7 +2,6 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include <functional> #include "common/logging/log.h" #include "core/file_sys/romfs.h" #include "core/file_sys/system_archive/ng_word.h" @@ -13,7 +12,7 @@ namespace FileSys::SystemArchive { constexpr u64 SYSTEM_ARCHIVE_BASE_TITLE_ID = 0x0100000000000800; constexpr std::size_t SYSTEM_ARCHIVE_COUNT = 0x28; -using SystemArchiveSupplier = std::function<VirtualDir()>; +using SystemArchiveSupplier = VirtualDir (*)(); struct SystemArchiveDescriptor { u64 title_id; @@ -21,7 +20,7 @@ struct SystemArchiveDescriptor { SystemArchiveSupplier supplier; }; -const std::array<SystemArchiveDescriptor, SYSTEM_ARCHIVE_COUNT> SYSTEM_ARCHIVES = {{ +constexpr std::array<SystemArchiveDescriptor, SYSTEM_ARCHIVE_COUNT> SYSTEM_ARCHIVES{{ {0x0100000000000800, "CertStore", nullptr}, {0x0100000000000801, "ErrorMessage", nullptr}, {0x0100000000000802, "MiiModel", nullptr}, @@ -57,7 +56,7 @@ const std::array<SystemArchiveDescriptor, SYSTEM_ARCHIVE_COUNT> SYSTEM_ARCHIVES {0x0100000000000820, "PlatformConfigCopper", nullptr}, {0x0100000000000821, "PlatformConfigHoag", nullptr}, {0x0100000000000822, "ControllerFirmware", nullptr}, - {0x0100000000000823, "NgWord2", nullptr}, + {0x0100000000000823, "NgWord2", &NgWord2}, {0x0100000000000824, "PlatformConfigIcosaMariko", nullptr}, {0x0100000000000825, "ApplicationBlackList", nullptr}, {0x0100000000000826, "RebootlessSystemUpdateVersion", nullptr}, diff --git a/src/core/hle/kernel/object.cpp b/src/core/hle/kernel/object.cpp index bb1b68778..0ea851a74 100644 --- a/src/core/hle/kernel/object.cpp +++ b/src/core/hle/kernel/object.cpp @@ -15,6 +15,7 @@ bool Object::IsWaitable() const { switch (GetHandleType()) { case HandleType::ReadableEvent: case HandleType::Thread: + case HandleType::Process: case HandleType::Timer: case HandleType::ServerPort: case HandleType::ServerSession: @@ -23,7 +24,6 @@ bool Object::IsWaitable() const { case HandleType::Unknown: case HandleType::WritableEvent: case HandleType::SharedMemory: - case HandleType::Process: case HandleType::AddressArbiter: case HandleType::ResourceLimit: case HandleType::ClientPort: diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 4ecb8c926..211bf6686 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -9,6 +9,7 @@ #include "common/logging/log.h" #include "core/core.h" #include "core/file_sys/program_metadata.h" +#include "core/hle/kernel/errors.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/resource_limit.h" @@ -48,6 +49,21 @@ SharedPtr<ResourceLimit> Process::GetResourceLimit() const { return resource_limit; } +ResultCode Process::ClearSignalState() { + if (status == ProcessStatus::Exited) { + LOG_ERROR(Kernel, "called on a terminated process instance."); + return ERR_INVALID_STATE; + } + + if (!is_signaled) { + LOG_ERROR(Kernel, "called on a process instance that isn't signaled."); + return ERR_INVALID_STATE; + } + + is_signaled = false; + return RESULT_SUCCESS; +} + void Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) { program_id = metadata.GetTitleID(); is_64bit_process = metadata.Is64BitProgram(); @@ -137,13 +153,13 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) { .Unwrap(); vm_manager.LogLayout(); - status = ProcessStatus::Running; + ChangeStatus(ProcessStatus::Running); Kernel::SetupMainThread(kernel, entry_point, main_thread_priority, *this); } void Process::PrepareForTermination() { - status = ProcessStatus::Exited; + ChangeStatus(ProcessStatus::Exiting); const auto stop_threads = [this](const std::vector<SharedPtr<Thread>>& thread_list) { for (auto& thread : thread_list) { @@ -167,6 +183,8 @@ void Process::PrepareForTermination() { stop_threads(system.Scheduler(1).GetThreadList()); stop_threads(system.Scheduler(2).GetThreadList()); stop_threads(system.Scheduler(3).GetThreadList()); + + ChangeStatus(ProcessStatus::Exited); } /** @@ -265,7 +283,25 @@ ResultCode Process::UnmapMemory(VAddr dst_addr, VAddr /*src_addr*/, u64 size) { return vm_manager.UnmapRange(dst_addr, size); } -Kernel::Process::Process(KernelCore& kernel) : Object{kernel} {} +Kernel::Process::Process(KernelCore& kernel) : WaitObject{kernel} {} Kernel::Process::~Process() {} +void Process::Acquire(Thread* thread) { + ASSERT_MSG(!ShouldWait(thread), "Object unavailable!"); +} + +bool Process::ShouldWait(Thread* thread) const { + return !is_signaled; +} + +void Process::ChangeStatus(ProcessStatus new_status) { + if (status == new_status) { + return; + } + + status = new_status; + is_signaled = true; + WakeupAllWaitingThreads(); +} + } // namespace Kernel diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 49345aa66..bcb9ac4b8 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -14,9 +14,10 @@ #include "common/bit_field.h" #include "common/common_types.h" #include "core/hle/kernel/handle_table.h" -#include "core/hle/kernel/object.h" #include "core/hle/kernel/thread.h" #include "core/hle/kernel/vm_manager.h" +#include "core/hle/kernel/wait_object.h" +#include "core/hle/result.h" namespace FileSys { class ProgramMetadata; @@ -117,7 +118,7 @@ struct CodeSet final { VAddr entrypoint = 0; }; -class Process final : public Object { +class Process final : public WaitObject { public: static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4; @@ -212,6 +213,16 @@ public: return random_entropy.at(index); } + /// Clears the signaled state of the process if and only if it's signaled. + /// + /// @pre The process must not be already terminated. If this is called on a + /// terminated process, then ERR_INVALID_STATE will be returned. + /// + /// @pre The process must be in a signaled state. If this is called on a + /// process instance that is not signaled, ERR_INVALID_STATE will be + /// returned. + ResultCode ClearSignalState(); + /** * Loads process-specifics configuration info with metadata provided * by an executable. @@ -260,6 +271,17 @@ private: explicit Process(KernelCore& kernel); ~Process() override; + /// Checks if the specified thread should wait until this process is available. + bool ShouldWait(Thread* thread) const override; + + /// Acquires/locks this process for the specified thread if it's available. + void Acquire(Thread* thread) override; + + /// Changes the process status. If the status is different + /// from the current process status, then this will trigger + /// a process signal. + void ChangeStatus(ProcessStatus new_status); + /// Memory manager for this process. Kernel::VMManager vm_manager; @@ -305,6 +327,10 @@ private: /// specified by metadata provided to the process during loading. bool is_64bit_process = true; + /// Whether or not this process is signaled. This occurs + /// upon the process changing to a different state. + bool is_signaled = false; + /// Total running time for the process in ticks. u64 total_process_running_time_ticks = 0; diff --git a/src/core/hle/kernel/readable_event.cpp b/src/core/hle/kernel/readable_event.cpp index 92e16b4e6..ba01f495c 100644 --- a/src/core/hle/kernel/readable_event.cpp +++ b/src/core/hle/kernel/readable_event.cpp @@ -4,10 +4,10 @@ #include <algorithm> #include "common/assert.h" +#include "core/hle/kernel/errors.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/readable_event.h" #include "core/hle/kernel/thread.h" -#include "core/hle/kernel/writable_event.h" namespace Kernel { @@ -34,6 +34,16 @@ void ReadableEvent::Clear() { signaled = false; } +ResultCode ReadableEvent::Reset() { + if (!signaled) { + return ERR_INVALID_STATE; + } + + Clear(); + + return RESULT_SUCCESS; +} + void ReadableEvent::WakeupAllWaitingThreads() { WaitObject::WakeupAllWaitingThreads(); diff --git a/src/core/hle/kernel/readable_event.h b/src/core/hle/kernel/readable_event.h index 867ff3051..80b3b0aba 100644 --- a/src/core/hle/kernel/readable_event.h +++ b/src/core/hle/kernel/readable_event.h @@ -7,6 +7,8 @@ #include "core/hle/kernel/object.h" #include "core/hle/kernel/wait_object.h" +union ResultCode; + namespace Kernel { class KernelCore; @@ -39,8 +41,17 @@ public: void WakeupAllWaitingThreads() override; + /// Unconditionally clears the readable event's state. void Clear(); + /// Clears the readable event's state if and only if it + /// has already been signaled. + /// + /// @pre The event must be in a signaled state. If this event + /// is in an unsignaled state and this function is called, + /// then ERR_INVALID_STATE will be returned. + ResultCode Reset(); + private: explicit ReadableEvent(KernelCore& kernel); diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index e6c77f9db..84df2040e 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1433,17 +1433,24 @@ static ResultCode CloseHandle(Handle handle) { return handle_table.Close(handle); } -/// Reset an event +/// Clears the signaled state of an event or process. static ResultCode ResetSignal(Handle handle) { LOG_DEBUG(Kernel_SVC, "called handle 0x{:08X}", handle); const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); + auto event = handle_table.Get<ReadableEvent>(handle); + if (event) { + return event->Reset(); + } - ASSERT(event != nullptr); + auto process = handle_table.Get<Process>(handle); + if (process) { + return process->ClearSignalState(); + } - event->Clear(); - return RESULT_SUCCESS; + LOG_ERROR(Kernel_SVC, "Invalid handle (0x{:08X})", handle); + return ERR_INVALID_HANDLE; } /// Creates a TransferMemory object diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index ca119dd3a..453d90a22 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp @@ -335,10 +335,7 @@ public: vm_manager.ReprotectRange(*map_address + header.rw_offset, header.rw_size, Kernel::VMAPermission::ReadWrite); - Core::System::GetInstance().ArmInterface(0).ClearInstructionCache(); - Core::System::GetInstance().ArmInterface(1).ClearInstructionCache(); - Core::System::GetInstance().ArmInterface(2).ClearInstructionCache(); - Core::System::GetInstance().ArmInterface(3).ClearInstructionCache(); + Core::System::GetInstance().InvalidateCpuInstructionCaches(); nro.insert_or_assign(*map_address, NROInfo{hash, nro_size + bss_size}); @@ -391,10 +388,7 @@ public: Kernel::MemoryState::ModuleCodeStatic) == RESULT_SUCCESS); ASSERT(process->UnmapMemory(mapped_addr, 0, nro_size) == RESULT_SUCCESS); - Core::System::GetInstance().ArmInterface(0).ClearInstructionCache(); - Core::System::GetInstance().ArmInterface(1).ClearInstructionCache(); - Core::System::GetInstance().ArmInterface(2).ClearInstructionCache(); - Core::System::GetInstance().ArmInterface(3).ClearInstructionCache(); + Core::System::GetInstance().InvalidateCpuInstructionCaches(); nro.erase(iter); IPC::ResponseBuilder rb{ctx, 2}; diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 70abd856a..41fd2a6a0 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -53,6 +53,14 @@ void PageTable::Resize(std::size_t address_space_width_in_bits) { pointers.resize(num_page_table_entries); attributes.resize(num_page_table_entries); + + // The default is a 39-bit address space, which causes an initial 1GB allocation size. If the + // vector size is subsequently decreased (via resize), the vector might not automatically + // actually reallocate/resize its underlying allocation, which wastes up to ~800 MB for + // 36-bit titles. Call shrink_to_fit to reduce capacity to what's actually in use. + + pointers.shrink_to_fit(); + attributes.shrink_to_fit(); } static void MapPages(PageTable& page_table, VAddr base, u64 size, u8* memory, PageType type) { |