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)