/ src / core / core.h
core.h
  1  // Copyright 2014 Citra Emulator Project
  2  // Licensed under GPLv2 or any later version
  3  // Refer to the license.txt file included.
  4  
  5  #pragma once
  6  
  7  #include <atomic>
  8  #include <memory>
  9  #include <mutex>
 10  #include <string>
 11  #include <boost/optional.hpp>
 12  #include <boost/serialization/version.hpp>
 13  #include "common/common_types.h"
 14  #include "core/arm/arm_interface.h"
 15  #include "core/cheats/cheats.h"
 16  #include "core/hle/service/apt/applet_manager.h"
 17  #include "core/hle/service/plgldr/plgldr.h"
 18  #include "core/movie.h"
 19  #include "core/perf_stats.h"
 20  
 21  namespace Frontend {
 22  class EmuWindow;
 23  class ImageInterface;
 24  class MiiSelector;
 25  class SoftwareKeyboard;
 26  } // namespace Frontend
 27  
 28  namespace Memory {
 29  class MemorySystem;
 30  }
 31  
 32  namespace AudioCore {
 33  class DspInterface;
 34  }
 35  
 36  namespace Core::RPC {
 37  class Server;
 38  }
 39  
 40  namespace Service {
 41  namespace SM {
 42  class ServiceManager;
 43  }
 44  namespace FS {
 45  class ArchiveManager;
 46  }
 47  } // namespace Service
 48  
 49  namespace Kernel {
 50  class KernelSystem;
 51  struct New3dsHwCapabilities;
 52  enum class MemoryMode : u8;
 53  } // namespace Kernel
 54  
 55  namespace VideoDumper {
 56  class Backend;
 57  }
 58  
 59  namespace VideoCore {
 60  class CustomTexManager;
 61  class GPU;
 62  } // namespace VideoCore
 63  
 64  namespace Pica {
 65  class DebugContext;
 66  }
 67  
 68  namespace Loader {
 69  class AppLoader;
 70  }
 71  
 72  namespace Core {
 73  
 74  class ARM_Interface;
 75  class TelemetrySession;
 76  class ExclusiveMonitor;
 77  class Timing;
 78  
 79  class System {
 80  public:
 81      /**
 82       * Gets the instance of the System singleton class.
 83       * @returns Reference to the instance of the System singleton class.
 84       */
 85      [[nodiscard]] static System& GetInstance() {
 86          return s_instance;
 87      }
 88  
 89      /// Enumeration representing the return values of the System Initialize and Load process.
 90      enum class ResultStatus : u32 {
 91          Success,                    ///< Succeeded
 92          ErrorNotInitialized,        ///< Error trying to use core prior to initialization
 93          ErrorGetLoader,             ///< Error finding the correct application loader
 94          ErrorSystemMode,            ///< Error determining the system mode
 95          ErrorLoader,                ///< Error loading the specified application
 96          ErrorLoader_ErrorEncrypted, ///< Error loading the specified application due to encryption
 97          ErrorLoader_ErrorInvalidFormat, ///< Error loading the specified application due to an
 98                                          /// invalid format
 99          ErrorLoader_ErrorGbaTitle, ///< Error loading the specified application as it is GBA Virtual
100                                     ///< Console
101          ErrorSystemFiles,          ///< Error in finding system files
102          ErrorSavestate,            ///< Error saving or loading
103          ShutdownRequested,         ///< Emulated program requested a system shutdown
104          ErrorUnknown               ///< Any other error
105      };
106  
107      explicit System();
108      ~System();
109  
110      /**
111       * Run the core CPU loop
112       * This function runs the core for the specified number of CPU instructions before trying to
113       * update hardware. This is much faster than SingleStep (and should be equivalent), as the CPU
114       * is not required to do a full dispatch with each instruction. NOTE: the number of instructions
115       * requested is not guaranteed to run, as this will be interrupted preemptively if a hardware
116       * update is requested (e.g. on a thread switch).
117       * @param tight_loop If false, the CPU single-steps.
118       * @return Result status, indicating whethor or not the operation succeeded.
119       */
120      [[nodiscard]] ResultStatus RunLoop(bool tight_loop = true);
121  
122      /**
123       * Step the CPU one instruction
124       * @return Result status, indicating whethor or not the operation succeeded.
125       */
126      [[nodiscard]] ResultStatus SingleStep();
127  
128      /// Shutdown the emulated system.
129      void Shutdown(bool is_deserializing = false);
130  
131      /// Shutdown and then load again
132      void Reset();
133  
134      enum class Signal : u32 { None, Shutdown, Reset, Save, Load };
135  
136      bool SendSignal(Signal signal, u32 param = 0);
137  
138      /// Request reset of the system
139      void RequestReset(const std::string& chainload = "") {
140          m_chainloadpath = chainload;
141          SendSignal(Signal::Reset);
142      }
143  
144      /// Request shutdown of the system
145      void RequestShutdown() {
146          SendSignal(Signal::Shutdown);
147      }
148  
149      /**
150       * Load an executable application.
151       * @param emu_window Reference to the host-system window used for video output and keyboard
152       *                   input.
153       * @param filepath String path to the executable application to load on the host file system.
154       * @returns ResultStatus code, indicating if the operation succeeded.
155       */
156      [[nodiscard]] ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath,
157                                      Frontend::EmuWindow* secondary_window = {});
158  
159      /**
160       * Indicates if the emulated system is powered on (all subsystems initialized and able to run an
161       * application).
162       * @returns True if the emulated system is powered on, otherwise false.
163       */
164      [[nodiscard]] bool IsPoweredOn() const {
165          return is_powered_on;
166      }
167  
168      /**
169       * Returns a reference to the telemetry session for this emulation session.
170       * @returns Reference to the telemetry session.
171       */
172      [[nodiscard]] Core::TelemetrySession& TelemetrySession() const {
173          return *telemetry_session;
174      }
175  
176      /// Prepare the core emulation for a reschedule
177      void PrepareReschedule();
178  
179      [[nodiscard]] PerfStats::Results GetAndResetPerfStats();
180  
181      [[nodiscard]] PerfStats::Results GetLastPerfStats();
182  
183      /**
184       * Gets a reference to the emulated CPU.
185       * @returns A reference to the emulated CPU.
186       */
187  
188      [[nodiscard]] ARM_Interface& GetRunningCore() {
189          return *running_core;
190      };
191  
192      /**
193       * Gets a reference to the emulated CPU.
194       * @param core_id The id of the core requested.
195       * @returns A reference to the emulated CPU.
196       */
197  
198      [[nodiscard]] ARM_Interface& GetCore(u32 core_id) {
199          return *cpu_cores[core_id];
200      };
201  
202      [[nodiscard]] const ARM_Interface& GetCore(u32 core_id) const {
203          return *cpu_cores[core_id];
204      };
205  
206      [[nodiscard]] u32 GetNumCores() const {
207          return static_cast<u32>(cpu_cores.size());
208      }
209  
210      void InvalidateCacheRange(u32 start_address, std::size_t length) {
211          for (const auto& cpu : cpu_cores) {
212              cpu->InvalidateCacheRange(start_address, length);
213          }
214      }
215  
216      /**
217       * Gets a reference to the emulated DSP.
218       * @returns A reference to the emulated DSP.
219       */
220      [[nodiscard]] AudioCore::DspInterface& DSP() {
221          return *dsp_core;
222      }
223  
224      [[nodiscard]] VideoCore::GPU& GPU();
225  
226      /**
227       * Gets a reference to the service manager.
228       * @returns A reference to the service manager.
229       */
230      [[nodiscard]] Service::SM::ServiceManager& ServiceManager();
231  
232      /**
233       * Gets a const reference to the service manager.
234       * @returns A const reference to the service manager.
235       */
236      [[nodiscard]] const Service::SM::ServiceManager& ServiceManager() const;
237  
238      /// Gets a reference to the archive manager
239      [[nodiscard]] Service::FS::ArchiveManager& ArchiveManager();
240  
241      /// Gets a const reference to the archive manager
242      [[nodiscard]] const Service::FS::ArchiveManager& ArchiveManager() const;
243  
244      /// Gets a reference to the kernel
245      [[nodiscard]] Kernel::KernelSystem& Kernel();
246  
247      /// Gets a const reference to the kernel
248      [[nodiscard]] const Kernel::KernelSystem& Kernel() const;
249  
250      /// Get kernel is running
251      [[nodiscard]] bool KernelRunning();
252  
253      /// Gets a reference to the timing system
254      [[nodiscard]] Timing& CoreTiming();
255  
256      /// Gets a const reference to the timing system
257      [[nodiscard]] const Timing& CoreTiming() const;
258  
259      /// Gets a reference to the memory system
260      [[nodiscard]] Memory::MemorySystem& Memory();
261  
262      /// Gets a const reference to the memory system
263      [[nodiscard]] const Memory::MemorySystem& Memory() const;
264  
265      /// Gets a reference to the cheat engine
266      [[nodiscard]] Cheats::CheatEngine& CheatEngine();
267  
268      /// Gets a const reference to the cheat engine
269      [[nodiscard]] const Cheats::CheatEngine& CheatEngine() const;
270  
271      /// Gets a reference to the custom texture cache system
272      [[nodiscard]] VideoCore::CustomTexManager& CustomTexManager();
273  
274      /// Gets a const reference to the custom texture cache system
275      [[nodiscard]] const VideoCore::CustomTexManager& CustomTexManager() const;
276  
277      /// Gets a reference to the movie recorder
278      [[nodiscard]] Core::Movie& Movie();
279  
280      /// Gets a const reference to the movie recorder
281      [[nodiscard]] const Core::Movie& Movie() const;
282  
283      /// Video Dumper interface
284  
285      void RegisterVideoDumper(std::shared_ptr<VideoDumper::Backend> video_dumper);
286  
287      [[nodiscard]] std::shared_ptr<VideoDumper::Backend> GetVideoDumper() const {
288          return video_dumper;
289      }
290  
291      std::unique_ptr<PerfStats> perf_stats;
292      FrameLimiter frame_limiter;
293  
294      void SetStatus(ResultStatus new_status, const char* details = nullptr) {
295          status = new_status;
296          if (details) {
297              status_details = details;
298          }
299      }
300  
301      [[nodiscard]] const std::string& GetStatusDetails() const {
302          return status_details;
303      }
304  
305      [[nodiscard]] Loader::AppLoader& GetAppLoader() const {
306          return *app_loader;
307      }
308  
309      /// Frontend Applets
310  
311      void RegisterMiiSelector(std::shared_ptr<Frontend::MiiSelector> mii_selector);
312  
313      void RegisterSoftwareKeyboard(std::shared_ptr<Frontend::SoftwareKeyboard> swkbd);
314  
315      [[nodiscard]] std::shared_ptr<Frontend::MiiSelector> GetMiiSelector() const {
316          return registered_mii_selector;
317      }
318  
319      [[nodiscard]] std::shared_ptr<Frontend::SoftwareKeyboard> GetSoftwareKeyboard() const {
320          return registered_swkbd;
321      }
322  
323      /// Image interface
324  
325      void RegisterImageInterface(std::shared_ptr<Frontend::ImageInterface> image_interface);
326  
327      [[nodiscard]] std::shared_ptr<Frontend::ImageInterface> GetImageInterface() const {
328          return registered_image_interface;
329      }
330  
331      /// Function for checking OS microphone permissions.
332  
333      void RegisterMicPermissionCheck(const std::function<bool()>& permission_func) {
334          mic_permission_func = permission_func;
335      }
336  
337      [[nodiscard]] bool HasMicPermission() {
338          return !mic_permission_func || mic_permission_granted ||
339                 (mic_permission_granted = mic_permission_func());
340      }
341  
342      void SaveState(u32 slot) const;
343  
344      void LoadState(u32 slot);
345  
346      /// Self delete ncch
347      bool SetSelfDelete(const std::string& file) {
348          if (m_filepath == file) {
349              self_delete_pending = true;
350              return true;
351          }
352          return false;
353      }
354  
355      /// Applies any changes to settings to this core instance.
356      void ApplySettings();
357  
358  private:
359      /**
360       * Initialize the emulated system.
361       * @param emu_window Reference to the host-system window used for video output and keyboard
362       *                   input.
363       * @param system_mode The system mode.
364       * @return ResultStatus code, indicating if the operation succeeded.
365       */
366      [[nodiscard]] ResultStatus Init(Frontend::EmuWindow& emu_window,
367                                      Frontend::EmuWindow* secondary_window,
368                                      Kernel::MemoryMode memory_mode,
369                                      const Kernel::New3dsHwCapabilities& n3ds_hw_caps,
370                                      u32 num_cores);
371  
372      /// Reschedule the core emulation
373      void Reschedule();
374  
375      /// AppLoader used to load the current executing application
376      std::unique_ptr<Loader::AppLoader> app_loader;
377  
378      /// ARM11 CPU core
379      std::vector<std::shared_ptr<ARM_Interface>> cpu_cores;
380      ARM_Interface* running_core = nullptr;
381  
382      /// DSP core
383      std::unique_ptr<AudioCore::DspInterface> dsp_core;
384  
385      /// When true, signals that a reschedule should happen
386      bool reschedule_pending{};
387  
388      /// Telemetry session for this emulation session
389      std::unique_ptr<Core::TelemetrySession> telemetry_session;
390  
391      std::unique_ptr<VideoCore::GPU> gpu;
392  
393      /// Service manager
394      std::unique_ptr<Service::SM::ServiceManager> service_manager;
395  
396      /// Frontend applets
397      std::shared_ptr<Frontend::MiiSelector> registered_mii_selector;
398      std::shared_ptr<Frontend::SoftwareKeyboard> registered_swkbd;
399  
400      /// Movie recorder
401      Core::Movie movie;
402  
403      /// Cheats manager
404      Cheats::CheatEngine cheat_engine;
405  
406      /// Video dumper backend
407      std::shared_ptr<VideoDumper::Backend> video_dumper;
408  
409      /// Custom texture cache system
410      std::unique_ptr<VideoCore::CustomTexManager> custom_tex_manager;
411  
412      /// Image interface
413      std::shared_ptr<Frontend::ImageInterface> registered_image_interface;
414  
415  #ifdef ENABLE_SCRIPTING
416      /// RPC Server for scripting support
417      std::unique_ptr<RPC::Server> rpc_server;
418  #endif
419  
420      std::unique_ptr<Service::FS::ArchiveManager> archive_manager;
421  
422      std::unique_ptr<Memory::MemorySystem> memory;
423      std::unique_ptr<Kernel::KernelSystem> kernel;
424      std::unique_ptr<Timing> timing;
425  
426      std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor;
427  
428  private:
429      static System s_instance;
430  
431      std::atomic_bool is_powered_on{};
432  
433      ResultStatus status = ResultStatus::Success;
434      std::string status_details = "";
435      /// Saved variables for reset
436      Frontend::EmuWindow* m_emu_window;
437      Frontend::EmuWindow* m_secondary_window;
438      std::string m_filepath;
439      std::string m_chainloadpath;
440      u64 title_id;
441      bool self_delete_pending;
442  
443      std::mutex signal_mutex;
444      Signal current_signal;
445      u32 signal_param;
446  
447      std::function<bool()> mic_permission_func;
448      bool mic_permission_granted = false;
449  
450      boost::optional<Service::APT::DeliverArg> restore_deliver_arg;
451      boost::optional<Service::PLGLDR::PLG_LDR::PluginLoaderContext> restore_plugin_context;
452  
453      friend class boost::serialization::access;
454      template <typename Archive>
455      void serialize(Archive& ar, const unsigned int file_version);
456  };
457  
458  [[nodiscard]] inline ARM_Interface& GetRunningCore() {
459      return System::GetInstance().GetRunningCore();
460  }
461  
462  [[nodiscard]] inline ARM_Interface& GetCore(u32 core_id) {
463      return System::GetInstance().GetCore(core_id);
464  }
465  
466  [[nodiscard]] inline u32 GetNumCores() {
467      return System::GetInstance().GetNumCores();
468  }
469  
470  } // namespace Core
471  
472  BOOST_CLASS_VERSION(Core::System, 1)