From 8abc5525be98854abecee14046d8e175a8b68b79 Mon Sep 17 00:00:00 2001 From: Hamish Milne Date: Sun, 12 Jan 2020 00:24:44 +0000 Subject: [PATCH] Added Signals; more runtime fixes --- src/citra_qt/main.cpp | 11 ++---- src/common/thread_queue_list.h | 30 ++++++++++++---- src/core/arm/arm_interface.h | 2 +- src/core/core.cpp | 50 +++++++++++++++++++++----- src/core/core.h | 11 +++--- src/core/core_timing.cpp | 12 +++---- src/core/file_sys/ivfc_archive.cpp | 1 + src/core/file_sys/ivfc_archive.h | 12 +++++++ src/core/hle/kernel/kernel.cpp | 5 ++- src/core/hle/kernel/kernel.h | 7 ++-- src/core/hle/kernel/memory.cpp | 16 ++++----- src/core/hle/kernel/process.h | 2 +- src/core/hle/kernel/shared_memory.cpp | 4 +-- src/core/hle/kernel/thread.cpp | 4 +-- src/core/hle/service/gsp/gsp_gpu.cpp | 4 --- src/core/hle/service/gsp/gsp_gpu.h | 2 +- src/core/hle/service/ldr_ro/ldr_ro.cpp | 1 + 17 files changed, 118 insertions(+), 56 deletions(-) diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 08e3cac02..7fe4936f5 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -1504,19 +1504,12 @@ void GMainWindow::OnCheats() { } void GMainWindow::OnSave() { - Core::System& system{Core::System::GetInstance()}; - auto fs = std::ofstream("save0.citrasave"); - emu_thread->SetRunning(false); - Core::System::GetInstance().Save(fs); - emu_thread->SetRunning(true); + Core::System::GetInstance().SendSignal(Core::System::Signal::Save); } void GMainWindow::OnLoad() { if (QFileInfo("save0.citrasave").exists()) { - auto fs = std::ifstream("save0.citrasave"); - emu_thread->SetRunning(false); - Core::System::GetInstance().Load(fs); - emu_thread->SetRunning(true); + Core::System::GetInstance().SendSignal(Core::System::Signal::Load); } } diff --git a/src/common/thread_queue_list.h b/src/common/thread_queue_list.h index 093d86781..f5db59f05 100644 --- a/src/common/thread_queue_list.h +++ b/src/common/thread_queue_list.h @@ -160,15 +160,33 @@ private: // The priority level queues of thread ids. std::array queues; + s32 ToIndex(Queue* q) const { + if (q == nullptr) { + return -2; + } else if (q == UnlinkedTag()) { + return -1; + } else { + return static_cast(q - &queues[0]); + } + } + + Queue* ToPointer(s32 idx) { + if (idx == -1) { + return UnlinkedTag(); + } else if (idx < 0) { + return nullptr; + } else { + return &queues[idx]; + } + } + friend class boost::serialization::access; template void save(Archive& ar, const unsigned int file_version) const { - s32 idx = first == UnlinkedTag() ? -1 : static_cast(first - &queues[0]); + s32 idx = ToIndex(first); ar << idx; for (auto i = 0; i < NUM_QUEUES; i++) { - s32 idx1 = first == UnlinkedTag() - ? -1 - : static_cast(queues[i].next_nonempty - &queues[0]); + s32 idx1 = ToIndex(queues[i].next_nonempty); ar << idx1; ar << queues[i].data; } @@ -178,10 +196,10 @@ private: void load(Archive& ar, const unsigned int file_version) { s32 idx; ar >> idx; - first = idx < 0 ? UnlinkedTag() : &queues[idx]; + first = ToPointer(idx); for (auto i = 0; i < NUM_QUEUES; i++) { ar >> idx; - queues[i].next_nonempty = idx < 0 ? UnlinkedTag() : &queues[idx]; + queues[i].next_nonempty = ToPointer(idx); ar >> queues[i].data; } } diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index be30499d1..e416a5f4c 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h @@ -264,7 +264,7 @@ private: ar >> r; SetCP15Register(static_cast(i), r); } - // TODO: Clear caches etc? + ClearInstructionCache(); } BOOST_SERIALIZATION_SPLIT_MEMBER() diff --git a/src/core/core.cpp b/src/core/core.cpp index 20a8f32fe..fcd1268da 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include #include #include #include @@ -103,15 +104,38 @@ System::ResultStatus System::RunLoop(bool tight_loop) { HW::Update(); Reschedule(); - if (reset_requested.exchange(false)) { + auto signal = current_signal.exchange(Signal::None); + switch (signal) { + case Signal::Reset: Reset(); - } else if (shutdown_requested.exchange(false)) { + break; + case Signal::Shutdown: return ResultStatus::ShutdownRequested; + break; + case Signal::Load: { + auto stream = std::ifstream("save0.citrasave", std::fstream::binary); + System::Load(stream); + } break; + case Signal::Save: { + auto stream = std::ofstream("save0.citrasave", std::fstream::binary); + System::Save(stream); + } break; + default: + break; } return status; } +bool System::SendSignal(System::Signal signal) { + auto prev = System::Signal::None; + if (!current_signal.compare_exchange_strong(prev, signal)) { + LOG_ERROR(Core, "Unable to {} as {} is ongoing", signal, prev); + return false; + } + return true; +} + System::ResultStatus System::SingleStep() { return RunLoop(false); } @@ -216,8 +240,8 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mo timing = std::make_unique(); - kernel = std::make_unique( - *memory, *timing, [this] { PrepareReschedule(); }, system_mode); + kernel = std::make_unique(*memory, *timing, + [this] { PrepareReschedule(); }, system_mode); if (Settings::values.use_cpu_jit) { #ifdef ARCHITECTURE_x86_64 @@ -409,6 +433,7 @@ void System::Reset() { template void System::serialize(Archive& ar, const unsigned int file_version) { + Memory::RasterizerFlushAndInvalidateRegion(0, 0xFFFFFFFF); ar&* cpu_core.get(); ar&* service_manager.get(); ar& GPU::g_regs; @@ -436,11 +461,20 @@ void System::Save(std::ostream& stream) const { } void System::Load(std::istream& stream) { - { - iarchive ia{stream}; - ia&* this; + try { + + { + iarchive ia{stream}; + ia&* this; + } + VideoCore::Load(stream); + + // Flush state through: + Kernel().SetCurrentProcess(Kernel().GetCurrentProcess()); + + } catch (const std::exception& e) { + LOG_ERROR(Core, "Error loading: {}", e.what()); } - VideoCore::Load(stream); } } // namespace Core diff --git a/src/core/core.h b/src/core/core.h index 75e0e1a54..a3b2f5cdd 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -116,14 +116,18 @@ public: /// Shutdown and then load again void Reset(); + enum class Signal : u32 { None, Shutdown, Reset, Save, Load }; + + bool SendSignal(Signal signal); + /// Request reset of the system void RequestReset() { - reset_requested = true; + SendSignal(Signal::Reset); } /// Request shutdown of the system void RequestShutdown() { - shutdown_requested = true; + SendSignal(Signal::Shutdown); } /** @@ -341,8 +345,7 @@ private: Frontend::EmuWindow* m_emu_window; std::string m_filepath; - std::atomic reset_requested; - std::atomic shutdown_requested; + std::atomic current_signal; friend class boost::serialization::access; template diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index df355ab27..976a6f3ba 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp @@ -23,14 +23,10 @@ bool Timing::Event::operator<(const Event& right) const { TimingEventType* Timing::RegisterEvent(const std::string& name, TimedCallback callback) { // check for existing type with same name. // we want event type names to remain unique so that we can use them for serialization. - ASSERT_MSG(event_types.find(name) == event_types.end(), - "CoreTiming Event \"{}\" is already registered. Events should only be registered " - "during Init to avoid breaking save states.", - name); - - auto info = event_types.emplace(name, TimingEventType{callback, nullptr}); + auto info = event_types.emplace(name, TimingEventType{}); TimingEventType* event_type = &info.first->second; event_type->name = &info.first->first; + event_type->callback = callback; return event_type; } @@ -129,6 +125,10 @@ void Timing::Advance() { Event evt = std::move(event_queue.front()); std::pop_heap(event_queue.begin(), event_queue.end(), std::greater<>()); event_queue.pop_back(); + if (event_types.find(*evt.type->name) == event_types.end()) { + LOG_ERROR(Core, "Unknown queued event"); + continue; + } evt.type->callback(evt.userdata, global_timer - evt.time); } diff --git a/src/core/file_sys/ivfc_archive.cpp b/src/core/file_sys/ivfc_archive.cpp index 3dbef7049..10d085164 100644 --- a/src/core/file_sys/ivfc_archive.cpp +++ b/src/core/file_sys/ivfc_archive.cpp @@ -14,6 +14,7 @@ // FileSys namespace SERIALIZE_EXPORT_IMPL(FileSys::IVFCFile) +SERIALIZE_EXPORT_IMPL(FileSys::IVFCFileInMemory) SERIALIZE_EXPORT_IMPL(FileSys::IVFCDelayGenerator) SERIALIZE_EXPORT_IMPL(FileSys::RomFSDelayGenerator) SERIALIZE_EXPORT_IMPL(FileSys::ExeFSDelayGenerator) diff --git a/src/core/file_sys/ivfc_archive.h b/src/core/file_sys/ivfc_archive.h index 3926f5229..145fabb98 100644 --- a/src/core/file_sys/ivfc_archive.h +++ b/src/core/file_sys/ivfc_archive.h @@ -176,11 +176,23 @@ private: std::vector romfs_file; u64 data_offset; u64 data_size; + + IVFCFileInMemory() = default; + + template + void serialize(Archive& ar, const unsigned int) { + ar& boost::serialization::base_object(*this); + ar& romfs_file; + ar& data_offset; + ar& data_size; + } + friend class boost::serialization::access; }; } // namespace FileSys BOOST_CLASS_EXPORT_KEY(FileSys::IVFCFile) +BOOST_CLASS_EXPORT_KEY(FileSys::IVFCFileInMemory) BOOST_CLASS_EXPORT_KEY(FileSys::IVFCDelayGenerator) BOOST_CLASS_EXPORT_KEY(FileSys::RomFSDelayGenerator) BOOST_CLASS_EXPORT_KEY(FileSys::ExeFSDelayGenerator) diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 968e905ac..3c3dfc6c6 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -23,6 +23,9 @@ KernelSystem::KernelSystem(Memory::MemorySystem& memory, Core::Timing& timing, std::function prepare_reschedule_callback, u32 system_mode) : memory(memory), timing(timing), prepare_reschedule_callback(std::move(prepare_reschedule_callback)) { + for (auto i = 0; i < memory_regions.size(); i++) { + memory_regions[i] = std::make_shared(); + } MemoryInit(system_mode); resource_limits = std::make_unique(*this); @@ -107,7 +110,7 @@ template void KernelSystem::serialize(Archive& ar, const unsigned int file_version) { ar& memory_regions; ar& named_ports; - ar&* current_cpu.get(); + // current_cpu set externally // NB: subsystem references and prepare_reschedule_callback are constant ar&* resource_limits.get(); ar& next_object_id; diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index e7b7314d6..41ef5272b 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -134,7 +134,8 @@ public: */ ResultVal> CreateThread(std::string name, VAddr entry_point, u32 priority, u32 arg, s32 processor_id, - VAddr stack_top, std::shared_ptr owner_process); + VAddr stack_top, + std::shared_ptr owner_process); /** * Creates a semaphore. @@ -232,11 +233,11 @@ public: IPCDebugger::Recorder& GetIPCRecorder(); const IPCDebugger::Recorder& GetIPCRecorder() const; - MemoryRegionInfo* GetMemoryRegion(MemoryRegion region); + std::shared_ptr GetMemoryRegion(MemoryRegion region); void HandleSpecialMapping(VMManager& address_space, const AddressMapping& mapping); - std::array memory_regions; + std::array, 3> memory_regions{}; /// Adds a port to the named port table void AddNamedPort(std::string name, std::shared_ptr port); diff --git a/src/core/hle/kernel/memory.cpp b/src/core/hle/kernel/memory.cpp index 04d09fa46..f8db3c31e 100644 --- a/src/core/hle/kernel/memory.cpp +++ b/src/core/hle/kernel/memory.cpp @@ -49,9 +49,9 @@ void KernelSystem::MemoryInit(u32 mem_type) { // the sizes specified in the memory_region_sizes table. VAddr base = 0; for (int i = 0; i < 3; ++i) { - memory_regions[i].Reset(base, memory_region_sizes[mem_type][i]); + memory_regions[i]->Reset(base, memory_region_sizes[mem_type][i]); - base += memory_regions[i].size; + base += memory_regions[i]->size; } // We must've allocated the entire FCRAM by the end @@ -63,20 +63,20 @@ void KernelSystem::MemoryInit(u32 mem_type) { // app_mem_malloc does not always match the configured size for memory_region[0]: in case the // n3DS type override is in effect it reports the size the game expects, not the real one. config_mem.app_mem_alloc = memory_region_sizes[mem_type][0]; - config_mem.sys_mem_alloc = memory_regions[1].size; - config_mem.base_mem_alloc = memory_regions[2].size; + config_mem.sys_mem_alloc = memory_regions[1]->size; + config_mem.base_mem_alloc = memory_regions[2]->size; shared_page_handler = std::make_shared(timing); } -MemoryRegionInfo* KernelSystem::GetMemoryRegion(MemoryRegion region) { +std::shared_ptr KernelSystem::GetMemoryRegion(MemoryRegion region) { switch (region) { case MemoryRegion::APPLICATION: - return &memory_regions[0]; + return memory_regions[0]; case MemoryRegion::SYSTEM: - return &memory_regions[1]; + return memory_regions[1]; case MemoryRegion::BASE: - return &memory_regions[2]; + return memory_regions[2]; default: UNREACHABLE(); } diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 576cf7e15..6eb79d227 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -200,7 +200,7 @@ public: u32 memory_used = 0; - MemoryRegionInfo* memory_region = nullptr; + std::shared_ptr memory_region = nullptr; /// The Thread Local Storage area is allocated as processes create threads, /// each TLS area is 0x200 bytes, so one page (0x1000) is split up in 8 parts, and each part diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index 23f67f733..47c966fec 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp @@ -42,7 +42,7 @@ ResultVal> KernelSystem::CreateSharedMemory( if (address == 0) { // We need to allocate a block from the Linear Heap ourselves. // We'll manually allocate some memory from the linear heap in the specified region. - MemoryRegionInfo* memory_region = GetMemoryRegion(region); + auto memory_region = GetMemoryRegion(region); auto offset = memory_region->LinearAllocate(size); ASSERT_MSG(offset, "Not enough space in region to allocate shared memory!"); @@ -79,7 +79,7 @@ std::shared_ptr KernelSystem::CreateSharedMemoryForApplet( auto shared_memory{std::make_shared(*this)}; // Allocate memory in heap - MemoryRegionInfo* memory_region = GetMemoryRegion(MemoryRegion::SYSTEM); + auto memory_region = GetMemoryRegion(MemoryRegion::SYSTEM); auto backing_blocks = memory_region->HeapAllocate(size); ASSERT_MSG(!backing_blocks.empty(), "Not enough space in region to allocate shared memory!"); shared_memory->holding_memory = backing_blocks; diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index f7379f50d..5382f9ec8 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -32,7 +32,7 @@ namespace Kernel { template void Thread::serialize(Archive& ar, const unsigned int file_version) { - ar& boost::serialization::base_object(*this); + ar& boost::serialization::base_object(*this); ar&* context.get(); ar& thread_id; ar& status; @@ -363,7 +363,7 @@ ResultVal> KernelSystem::CreateThread( if (needs_allocation) { // There are no already-allocated pages with free slots, lets allocate a new one. // TLS pages are allocated from the BASE region in the linear heap. - MemoryRegionInfo* memory_region = GetMemoryRegion(MemoryRegion::BASE); + auto memory_region = GetMemoryRegion(MemoryRegion::BASE); // Allocate some memory from the end of the linear heap for this region. auto offset = memory_region->LinearAllocate(Memory::PAGE_SIZE); diff --git a/src/core/hle/service/gsp/gsp_gpu.cpp b/src/core/hle/service/gsp/gsp_gpu.cpp index 78d84499b..5a41f5ca0 100644 --- a/src/core/hle/service/gsp/gsp_gpu.cpp +++ b/src/core/hle/service/gsp/gsp_gpu.cpp @@ -824,10 +824,6 @@ std::unique_ptr GSP_GPU::MakeSes return std::make_unique(this); } -SessionData::SessionData() { - UNREACHABLE(); -} - SessionData::SessionData(GSP_GPU* gsp) : gsp(gsp) { // Assign a new thread id to this session when it connects. Note: In the real GSP service this // is done through a real thread (svcCreateThread) but we have to simulate it since our HLE diff --git a/src/core/hle/service/gsp/gsp_gpu.h b/src/core/hle/service/gsp/gsp_gpu.h index a97aee278..82ecf2480 100644 --- a/src/core/hle/service/gsp/gsp_gpu.h +++ b/src/core/hle/service/gsp/gsp_gpu.h @@ -187,7 +187,7 @@ class GSP_GPU; class SessionData : public Kernel::SessionRequestHandler::SessionDataBase { public: - SessionData(); + SessionData() = default; SessionData(GSP_GPU* gsp); ~SessionData(); diff --git a/src/core/hle/service/ldr_ro/ldr_ro.cpp b/src/core/hle/service/ldr_ro/ldr_ro.cpp index 0a61f4c23..8ac6f1068 100644 --- a/src/core/hle/service/ldr_ro/ldr_ro.cpp +++ b/src/core/hle/service/ldr_ro/ldr_ro.cpp @@ -15,6 +15,7 @@ SERVICE_CONSTRUCT_IMPL(Service::LDR::RO) SERIALIZE_EXPORT_IMPL(Service::LDR::RO) +SERIALIZE_EXPORT_IMPL(Service::LDR::ClientSlot) namespace Service::LDR {