From 01054550861c18a8d389d56c8765125268d1f9dd Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Mon, 9 Dec 2019 03:57:37 -0800 Subject: [PATCH] git subrepo clone https://github.com/Atmosphere-NX/Atmosphere-libs libraries subrepo: subdir: "libraries" merged: "07af583b" upstream: origin: "https://github.com/Atmosphere-NX/Atmosphere-libs" branch: "master" commit: "07af583b" git-subrepo: version: "0.4.0" origin: "https://github.com/ingydotnet/git-subrepo" commit: "5d6aba9" --- libraries/.gitignore | 74 + libraries/.gitmodules | 0 libraries/.gitrepo | 12 + libraries/LICENSE | 339 +++ libraries/Makefile | 10 + libraries/README.md | 30 + libraries/config/arch/arm64/arch.mk | 11 + .../config/board/nintendo/switch/board.mk | 5 + libraries/config/common.mk | 74 + libraries/config/os/horizon/os.mk | 5 + libraries/config/templates/stratosphere.mk | 52 + libraries/libstratosphere/Makefile | 140 ++ libraries/libstratosphere/README.md | 31 + .../libstratosphere/include/stratosphere.hpp | 58 + .../include/stratosphere/ams.hpp | 22 + .../stratosphere/ams/ams_emummc_api.hpp | 31 + .../stratosphere/ams/ams_environment.hpp | 25 + .../stratosphere/ams/ams_exosphere_api.hpp | 47 + .../include/stratosphere/ams/ams_types.hpp | 120 ++ .../include/stratosphere/boot2.hpp | 19 + .../include/stratosphere/boot2/boot2_api.hpp | 30 + .../include/stratosphere/cfg.hpp | 19 + .../include/stratosphere/cfg/cfg_api.hpp | 49 + .../stratosphere/cfg/cfg_locale_types.hpp | 27 + .../include/stratosphere/cfg/cfg_types.hpp | 62 + .../include/stratosphere/dd.hpp | 20 + .../stratosphere/dd/dd_io_mappings.hpp | 36 + .../stratosphere/dd/dd_process_handle.hpp | 24 + .../include/stratosphere/dmnt.hpp | 19 + .../stratosphere/dmnt/dmnt_cheat_types.hpp | 66 + .../include/stratosphere/fatal.hpp | 19 + .../stratosphere/fatal/fatal_types.hpp | 348 +++ .../include/stratosphere/fs.hpp | 28 + .../include/stratosphere/fs/fs_common.hpp | 27 + .../include/stratosphere/fs/fs_directory.hpp | 25 + .../include/stratosphere/fs/fs_file.hpp | 63 + .../stratosphere/fs/fs_file_storage.hpp | 56 + .../include/stratosphere/fs/fs_filesystem.hpp | 52 + .../include/stratosphere/fs/fs_istorage.hpp | 106 + .../stratosphere/fs/fs_operate_range.hpp | 28 + .../include/stratosphere/fs/fs_path_tool.hpp | 73 + .../include/stratosphere/fs/fs_path_utils.hpp | 48 + .../stratosphere/fs/fs_query_range.hpp | 45 + .../stratosphere/fs/fs_remote_filesystem.hpp | 179 ++ .../stratosphere/fs/fs_remote_storage.hpp | 60 + .../stratosphere/fs/fsa/fs_idirectory.hpp | 52 + .../include/stratosphere/fs/fsa/fs_ifile.hpp | 95 + .../stratosphere/fs/fsa/fs_ifilesystem.hpp | 191 ++ .../include/stratosphere/fssrv.hpp | 19 + .../fssrv/fssrv_interface_adapters.hpp | 18 + .../fssrv/fssrv_path_normalizer.hpp | 66 + .../stratosphere/fssrv/fssrv_sf_path.hpp | 50 + .../fssrv_filesystem_interface_adapter.hpp | 192 ++ .../fssrv_storage_interface_adapter.hpp | 78 + .../include/stratosphere/fssystem.hpp | 22 + ...ystem_directory_redirection_filesystem.hpp | 47 + ...fssystem_directory_savedata_filesystem.hpp | 64 + .../fssystem/fssystem_path_tool.hpp | 26 + .../fssystem_subdirectory_filesystem.hpp | 44 + .../fssystem/fssystem_utility.hpp | 169 ++ .../fssystem_path_resolution_filesystem.hpp | 194 ++ .../include/stratosphere/hid.hpp | 19 + .../include/stratosphere/hid/hid_api.hpp | 24 + .../include/stratosphere/hos.hpp | 20 + .../include/stratosphere/hos/hos_types.hpp | 39 + .../stratosphere/hos/hos_version_api.hpp | 25 + .../include/stratosphere/kvdb.hpp | 24 + .../stratosphere/kvdb/kvdb_archive.hpp | 64 + .../stratosphere/kvdb/kvdb_auto_buffer.hpp | 90 + .../stratosphere/kvdb/kvdb_bounded_string.hpp | 145 ++ .../kvdb/kvdb_file_key_value_cache.hpp | 391 ++++ .../kvdb/kvdb_file_key_value_store.hpp | 122 ++ .../kvdb/kvdb_memory_key_value_store.hpp | 525 +++++ .../include/stratosphere/ldr.hpp | 20 + .../include/stratosphere/ldr/ldr_pm_api.hpp | 33 + .../include/stratosphere/ldr/ldr_types.hpp | 242 +++ .../include/stratosphere/map.hpp | 20 + .../include/stratosphere/map/map_api.hpp | 28 + .../include/stratosphere/map/map_types.hpp | 122 ++ .../include/stratosphere/ncm.hpp | 19 + .../include/stratosphere/ncm/ncm_types.hpp | 447 ++++ .../include/stratosphere/os.hpp | 34 + .../stratosphere/os/os_common_types.hpp | 81 + .../include/stratosphere/os/os_condvar.hpp | 70 + .../include/stratosphere/os/os_event.hpp | 53 + .../stratosphere/os/os_interrupt_event.hpp | 49 + .../stratosphere/os/os_managed_handle.hpp | 82 + .../stratosphere/os/os_memory_common.hpp | 25 + .../stratosphere/os/os_message_queue.hpp | 89 + .../include/stratosphere/os/os_mutex.hpp | 101 + .../stratosphere/os/os_process_handle.hpp | 28 + .../include/stratosphere/os/os_rw_lock.hpp | 89 + .../include/stratosphere/os/os_semaphore.hpp | 56 + .../stratosphere/os/os_system_event.hpp | 80 + .../include/stratosphere/os/os_thread.hpp | 110 + .../stratosphere/os/os_timeout_helper.hpp | 63 + .../stratosphere/os/os_waitable_holder.hpp | 67 + .../stratosphere/os/os_waitable_manager.hpp | 51 + .../include/stratosphere/patcher.hpp | 19 + .../stratosphere/patcher/patcher_api.hpp | 26 + .../include/stratosphere/pm.hpp | 23 + .../stratosphere/pm/pm_boot_mode_api.hpp | 27 + .../include/stratosphere/pm/pm_dmnt_api.hpp | 32 + .../include/stratosphere/pm/pm_info_api.hpp | 37 + .../include/stratosphere/pm/pm_shell_api.hpp | 27 + .../include/stratosphere/pm/pm_types.hpp | 43 + .../include/stratosphere/reg.hpp | 70 + .../include/stratosphere/rnd.hpp | 19 + .../include/stratosphere/rnd/rnd_api.hpp | 27 + .../include/stratosphere/ro.hpp | 19 + .../include/stratosphere/ro/ro_types.hpp | 150 ++ .../include/stratosphere/settings.hpp | 21 + .../settings/settings_fwdbg_api.hpp | 28 + .../settings/settings_fwdbg_types.hpp | 38 + .../stratosphere/settings/settings_types.hpp | 223 ++ .../include/stratosphere/sf.hpp | 29 + .../sf/cmif/sf_cmif_domain_api.hpp | 68 + .../sf/cmif/sf_cmif_domain_manager.hpp | 128 ++ .../sf/cmif/sf_cmif_domain_service_object.hpp | 136 ++ .../sf/cmif/sf_cmif_pointer_and_size.hpp | 44 + .../cmif/sf_cmif_server_message_processor.hpp | 81 + .../sf/cmif/sf_cmif_service_dispatch.hpp | 150 ++ .../sf/cmif/sf_cmif_service_object_holder.hpp | 110 + .../stratosphere/sf/hipc/sf_hipc_api.hpp | 37 + .../sf_hipc_server_domain_session_manager.hpp | 37 + .../sf/hipc/sf_hipc_server_manager.hpp | 394 ++++ .../hipc/sf_hipc_server_session_manager.hpp | 182 ++ .../sf/impl/sf_impl_command_serialization.hpp | 1161 +++++++++++ .../stratosphere/sf/sf_buffer_tags.hpp | 30 + .../include/stratosphere/sf/sf_buffers.hpp | 301 +++ .../include/stratosphere/sf/sf_common.hpp | 21 + .../include/stratosphere/sf/sf_handles.hpp | 171 ++ .../stratosphere/sf/sf_mitm_dispatch.h | 100 + .../include/stratosphere/sf/sf_out.hpp | 76 + .../stratosphere/sf/sf_service_object.hpp | 62 + .../include/stratosphere/sm.hpp | 24 + .../include/stratosphere/sm/sm_api.hpp | 45 + .../stratosphere/sm/sm_manager_api.hpp | 33 + .../include/stratosphere/sm/sm_mitm_api.hpp | 31 + .../stratosphere/sm/sm_scoped_holder.hpp | 86 + .../include/stratosphere/sm/sm_types.hpp | 78 + .../include/stratosphere/spl.hpp | 21 + .../include/stratosphere/spl/smc/spl_smc.hpp | 73 + .../include/stratosphere/spl/spl_api.hpp | 29 + .../include/stratosphere/spl/spl_types.hpp | 192 ++ .../include/stratosphere/updater.hpp | 20 + .../stratosphere/updater/updater_api.hpp | 27 + .../stratosphere/updater/updater_types.hpp | 44 + .../include/stratosphere/util.hpp | 20 + .../stratosphere/util/util_compression.hpp | 28 + .../include/stratosphere/util/util_ini.hpp | 31 + .../libstratosphere/source/ams/ams_bpc.c | 46 + .../libstratosphere/source/ams/ams_bpc.h | 34 + .../source/ams/ams_emummc_api.cpp | 137 ++ .../source/ams/ams_environment.cpp | 176 ++ .../source/ams/ams_exosphere_api.cpp | 75 + .../source/boot2/boot2_api.cpp | 349 ++++ .../libstratosphere/source/cfg/cfg_flags.cpp | 72 + .../source/cfg/cfg_override.cpp | 308 +++ .../source/cfg/cfg_privileged_process.cpp | 87 + .../source/cfg/cfg_sd_card.cpp | 97 + .../source/dd/dd_io_mappings.cpp | 55 + .../libstratosphere/source/dmnt/dmntcht.c | 167 ++ .../libstratosphere/source/dmnt/dmntcht.h | 93 + .../source/fs/fs_file_storage.cpp | 93 + .../source/fs/fs_path_tool.cpp | 248 +++ .../source/fs/fs_path_utils.cpp | 47 + .../fssrv_filesystem_interface_adapter.cpp | 343 +++ .../source/fssrv/fssrv_path_normalizer.cpp | 77 + .../fssrv/fssrv_storage_interface_adapter.cpp | 94 + ...ystem_directory_redirection_filesystem.cpp | 119 ++ ...fssystem_directory_savedata_filesystem.cpp | 272 +++ .../fssystem_subdirectory_filesystem.cpp | 82 + .../source/fssystem/fssystem_utility.cpp | 118 ++ .../libstratosphere/source/hid/hid_api.cpp | 66 + .../source/hos/hos_version_api.cpp | 147 ++ .../source/kvdb/kvdb_archive.cpp | 168 ++ .../source/kvdb/kvdb_file_key_value_store.cpp | 318 +++ .../libstratosphere/source/ldr/ldr_ams.c | 48 + .../libstratosphere/source/ldr/ldr_ams.h | 27 + .../libstratosphere/source/ldr/ldr_pm_api.cpp | 54 + .../libstratosphere/source/map/map_api.cpp | 236 +++ .../source/os/impl/os_inter_process_event.cpp | 179 ++ .../source/os/impl/os_inter_process_event.hpp | 54 + .../os/impl/os_waitable_holder_base.hpp | 77 + .../os/impl/os_waitable_holder_impl.hpp | 56 + .../os/impl/os_waitable_holder_of_event.hpp | 52 + .../os/impl/os_waitable_holder_of_handle.hpp | 37 + ...waitable_holder_of_inter_process_event.hpp | 39 + .../os_waitable_holder_of_interrupt_event.hpp | 38 + .../os_waitable_holder_of_message_queue.hpp | 75 + .../impl/os_waitable_holder_of_semaphore.hpp | 52 + .../os/impl/os_waitable_holder_of_thread.hpp | 39 + .../os/impl/os_waitable_manager_impl.cpp | 177 ++ .../os/impl/os_waitable_manager_impl.hpp | 94 + .../os/impl/os_waitable_object_list.hpp | 53 + .../libstratosphere/source/os/os_event.cpp | 105 + .../source/os/os_interrupt_event.cpp | 111 + .../source/os/os_message_queue.cpp | 247 +++ .../source/os/os_process_handle.cpp | 44 + .../source/os/os_semaphore.cpp | 85 + .../source/os/os_system_event.cpp | 188 ++ .../source/os/os_waitable_holder.cpp | 116 + .../source/os/os_waitable_manager.cpp | 88 + .../source/patcher/patcher_api.cpp | 235 +++ libraries/libstratosphere/source/pm/pm_ams.c | 92 + libraries/libstratosphere/source/pm/pm_ams.h | 28 + .../source/pm/pm_boot_mode_api.cpp | 32 + .../libstratosphere/source/pm/pm_dmnt_api.cpp | 56 + .../libstratosphere/source/pm/pm_info_api.cpp | 93 + .../source/pm/pm_shell_api.cpp | 27 + .../source/result/result_on_assertion.cpp | 37 + .../libstratosphere/source/rnd/rnd_api.cpp | 129 ++ .../libstratosphere/source/service_guard.h | 64 + .../source/settings/settings_fwdbg_api.cpp | 35 + .../source/sf/cmif/sf_cmif_domain_manager.cpp | 158 ++ .../sf/cmif/sf_cmif_domain_service_object.cpp | 220 ++ .../sf/cmif/sf_cmif_service_dispatch.cpp | 107 + .../sf/cmif/sf_cmif_service_object_holder.cpp | 26 + .../source/sf/hipc/sf_hipc_api.cpp | 86 + .../source/sf/hipc/sf_hipc_mitm_query_api.cpp | 78 + .../source/sf/hipc/sf_hipc_mitm_query_api.hpp | 23 + .../sf_hipc_server_domain_session_manager.cpp | 174 ++ .../source/sf/hipc/sf_hipc_server_manager.cpp | 225 ++ .../hipc/sf_hipc_server_session_manager.cpp | 303 +++ libraries/libstratosphere/source/sm/sm_ams.c | 131 ++ libraries/libstratosphere/source/sm/sm_ams.h | 35 + .../libstratosphere/source/sm/sm_api.cpp | 63 + .../source/sm/sm_manager_api.cpp | 40 + .../libstratosphere/source/sm/sm_mitm_api.cpp | 57 + .../libstratosphere/source/sm/sm_utils.cpp | 42 + .../libstratosphere/source/sm/sm_utils.hpp | 70 + libraries/libstratosphere/source/sm/smm_ams.c | 49 + libraries/libstratosphere/source/sm/smm_ams.h | 25 + .../source/spl/smc/spl_smc.cpp | 378 ++++ .../libstratosphere/source/spl/spl_api.cpp | 75 + .../source/updater/updater_api.cpp | 530 +++++ .../source/updater/updater_bis_management.cpp | 149 ++ .../source/updater/updater_bis_management.hpp | 235 +++ .../source/updater/updater_bis_save.cpp | 62 + .../source/updater/updater_bis_save.hpp | 42 + .../source/updater/updater_files.cpp | 68 + .../source/updater/updater_files.hpp | 25 + .../source/updater/updater_paths.cpp | 110 + .../source/updater/updater_paths.hpp | 27 + libraries/libstratosphere/source/util/ini.c | 269 +++ libraries/libstratosphere/source/util/ini.h | 130 ++ libraries/libstratosphere/source/util/lz4.c | 1857 +++++++++++++++++ libraries/libstratosphere/source/util/lz4.h | 569 +++++ .../source/util/util_compression.cpp | 41 + .../libstratosphere/source/util/util_ini.cpp | 91 + .../libvapours/include/freebsd/sys/tree.h | 812 +++++++ libraries/libvapours/include/vapours.hpp | 23 + .../include/vapours/ams/ams_api_version.h | 26 + .../include/vapours/ams/ams_target_firmware.h | 34 + .../libvapours/include/vapours/ams_version.h | 19 + .../libvapours/include/vapours/defines.hpp | 46 + .../libvapours/include/vapours/includes.hpp | 67 + .../libvapours/include/vapours/results.hpp | 50 + .../include/vapours/results/cal_results.hpp | 26 + .../vapours/results/creport_results.hpp | 37 + .../include/vapours/results/debug_results.hpp | 28 + .../include/vapours/results/dmnt_results.hpp | 50 + .../include/vapours/results/err_results.hpp | 27 + .../vapours/results/exosphere_results.hpp | 30 + .../include/vapours/results/fatal_results.hpp | 31 + .../include/vapours/results/fs_results.hpp | 124 ++ .../include/vapours/results/hipc_results.hpp | 41 + .../include/vapours/results/i2c_results.hpp | 30 + .../include/vapours/results/kvdb_results.hpp | 33 + .../vapours/results/loader_results.hpp | 63 + .../include/vapours/results/lr_results.hpp | 34 + .../include/vapours/results/ncm_results.hpp | 55 + .../include/vapours/results/os_results.hpp | 32 + .../include/vapours/results/pm_results.hpp | 31 + .../vapours/results/results_common.hpp | 289 +++ .../include/vapours/results/ro_results.hpp | 45 + .../vapours/results/settings_results.hpp | 47 + .../include/vapours/results/sf_results.hpp | 54 + .../include/vapours/results/sm_results.hpp | 42 + .../include/vapours/results/spl_results.hpp | 42 + .../include/vapours/results/svc_results.hpp | 73 + .../vapours/results/updater_results.hpp | 30 + .../include/vapours/results/vi_results.hpp | 28 + libraries/libvapours/include/vapours/svc.hpp | 21 + .../include/vapours/svc/svc_types.hpp | 208 ++ libraries/libvapours/include/vapours/util.hpp | 25 + .../include/vapours/util/util_alignment.hpp | 75 + .../vapours/util/util_intrusive_list.hpp | 595 ++++++ .../util/util_intrusive_red_black_tree.hpp | 297 +++ .../vapours/util/util_parent_of_member.hpp | 77 + .../include/vapours/util/util_scope_guard.hpp | 58 + .../include/vapours/util/util_size.hpp | 37 + .../vapours/util/util_typed_storage.hpp | 49 + 294 files changed, 29915 insertions(+) create mode 100644 libraries/.gitignore create mode 100644 libraries/.gitmodules create mode 100644 libraries/.gitrepo create mode 100644 libraries/LICENSE create mode 100644 libraries/Makefile create mode 100644 libraries/README.md create mode 100644 libraries/config/arch/arm64/arch.mk create mode 100644 libraries/config/board/nintendo/switch/board.mk create mode 100644 libraries/config/common.mk create mode 100644 libraries/config/os/horizon/os.mk create mode 100644 libraries/config/templates/stratosphere.mk create mode 100644 libraries/libstratosphere/Makefile create mode 100644 libraries/libstratosphere/README.md create mode 100644 libraries/libstratosphere/include/stratosphere.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/ams.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/ams/ams_emummc_api.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/ams/ams_environment.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/ams/ams_exosphere_api.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/ams/ams_types.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/boot2.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/boot2/boot2_api.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/cfg.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/cfg/cfg_api.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/cfg/cfg_locale_types.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/cfg/cfg_types.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/dd.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/dd/dd_io_mappings.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/dd/dd_process_handle.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/dmnt.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/dmnt/dmnt_cheat_types.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/fatal.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/fatal/fatal_types.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/fs.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/fs/fs_common.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/fs/fs_directory.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/fs/fs_file.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/fs/fs_file_storage.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/fs/fs_filesystem.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/fs/fs_istorage.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/fs/fs_operate_range.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/fs/fs_path_tool.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/fs/fs_path_utils.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/fs/fs_query_range.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/fs/fs_remote_filesystem.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/fs/fs_remote_storage.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/fs/fsa/fs_idirectory.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/fs/fsa/fs_ifile.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/fs/fsa/fs_ifilesystem.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/fssrv.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/fssrv/fssrv_interface_adapters.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/fssrv/fssrv_path_normalizer.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/fssrv/fssrv_sf_path.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/fssrv/interface_adapters/fssrv_filesystem_interface_adapter.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/fssrv/interface_adapters/fssrv_storage_interface_adapter.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/fssystem.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/fssystem/fssystem_directory_redirection_filesystem.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/fssystem/fssystem_directory_savedata_filesystem.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/fssystem/fssystem_path_tool.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/fssystem/fssystem_subdirectory_filesystem.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/fssystem/fssystem_utility.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/fssystem/impl/fssystem_path_resolution_filesystem.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/hid.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/hid/hid_api.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/hos.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/hos/hos_types.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/hos/hos_version_api.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/kvdb.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/kvdb/kvdb_archive.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/kvdb/kvdb_auto_buffer.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/kvdb/kvdb_bounded_string.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/kvdb/kvdb_file_key_value_cache.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/kvdb/kvdb_file_key_value_store.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/kvdb/kvdb_memory_key_value_store.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/ldr.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/ldr/ldr_pm_api.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/ldr/ldr_types.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/map.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/map/map_api.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/map/map_types.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/ncm.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/ncm/ncm_types.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/os.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/os/os_common_types.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/os/os_condvar.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/os/os_event.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/os/os_interrupt_event.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/os/os_managed_handle.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/os/os_memory_common.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/os/os_message_queue.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/os/os_mutex.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/os/os_process_handle.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/os/os_rw_lock.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/os/os_semaphore.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/os/os_system_event.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/os/os_thread.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/os/os_timeout_helper.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/os/os_waitable_holder.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/os/os_waitable_manager.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/patcher.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/patcher/patcher_api.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/pm.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/pm/pm_boot_mode_api.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/pm/pm_dmnt_api.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/pm/pm_info_api.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/pm/pm_shell_api.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/pm/pm_types.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/reg.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/rnd.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/rnd/rnd_api.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/ro.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/ro/ro_types.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/settings.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/settings/settings_fwdbg_api.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/settings/settings_fwdbg_types.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/settings/settings_types.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/sf.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_domain_api.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_domain_manager.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_domain_service_object.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_pointer_and_size.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_server_message_processor.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_service_dispatch.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_service_object_holder.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_api.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_domain_session_manager.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_manager.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_session_manager.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/sf/impl/sf_impl_command_serialization.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/sf/sf_buffer_tags.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/sf/sf_buffers.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/sf/sf_common.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/sf/sf_handles.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/sf/sf_mitm_dispatch.h create mode 100644 libraries/libstratosphere/include/stratosphere/sf/sf_out.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/sf/sf_service_object.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/sm.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/sm/sm_api.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/sm/sm_manager_api.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/sm/sm_mitm_api.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/sm/sm_scoped_holder.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/sm/sm_types.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/spl.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/spl/smc/spl_smc.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/spl/spl_api.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/spl/spl_types.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/updater.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/updater/updater_api.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/updater/updater_types.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/util.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/util/util_compression.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/util/util_ini.hpp create mode 100644 libraries/libstratosphere/source/ams/ams_bpc.c create mode 100644 libraries/libstratosphere/source/ams/ams_bpc.h create mode 100644 libraries/libstratosphere/source/ams/ams_emummc_api.cpp create mode 100644 libraries/libstratosphere/source/ams/ams_environment.cpp create mode 100644 libraries/libstratosphere/source/ams/ams_exosphere_api.cpp create mode 100644 libraries/libstratosphere/source/boot2/boot2_api.cpp create mode 100644 libraries/libstratosphere/source/cfg/cfg_flags.cpp create mode 100644 libraries/libstratosphere/source/cfg/cfg_override.cpp create mode 100644 libraries/libstratosphere/source/cfg/cfg_privileged_process.cpp create mode 100644 libraries/libstratosphere/source/cfg/cfg_sd_card.cpp create mode 100644 libraries/libstratosphere/source/dd/dd_io_mappings.cpp create mode 100644 libraries/libstratosphere/source/dmnt/dmntcht.c create mode 100644 libraries/libstratosphere/source/dmnt/dmntcht.h create mode 100644 libraries/libstratosphere/source/fs/fs_file_storage.cpp create mode 100644 libraries/libstratosphere/source/fs/fs_path_tool.cpp create mode 100644 libraries/libstratosphere/source/fs/fs_path_utils.cpp create mode 100644 libraries/libstratosphere/source/fssrv/fssrv_filesystem_interface_adapter.cpp create mode 100644 libraries/libstratosphere/source/fssrv/fssrv_path_normalizer.cpp create mode 100644 libraries/libstratosphere/source/fssrv/fssrv_storage_interface_adapter.cpp create mode 100644 libraries/libstratosphere/source/fssystem/fssystem_directory_redirection_filesystem.cpp create mode 100644 libraries/libstratosphere/source/fssystem/fssystem_directory_savedata_filesystem.cpp create mode 100644 libraries/libstratosphere/source/fssystem/fssystem_subdirectory_filesystem.cpp create mode 100644 libraries/libstratosphere/source/fssystem/fssystem_utility.cpp create mode 100644 libraries/libstratosphere/source/hid/hid_api.cpp create mode 100644 libraries/libstratosphere/source/hos/hos_version_api.cpp create mode 100644 libraries/libstratosphere/source/kvdb/kvdb_archive.cpp create mode 100644 libraries/libstratosphere/source/kvdb/kvdb_file_key_value_store.cpp create mode 100644 libraries/libstratosphere/source/ldr/ldr_ams.c create mode 100644 libraries/libstratosphere/source/ldr/ldr_ams.h create mode 100644 libraries/libstratosphere/source/ldr/ldr_pm_api.cpp create mode 100644 libraries/libstratosphere/source/map/map_api.cpp create mode 100644 libraries/libstratosphere/source/os/impl/os_inter_process_event.cpp create mode 100644 libraries/libstratosphere/source/os/impl/os_inter_process_event.hpp create mode 100644 libraries/libstratosphere/source/os/impl/os_waitable_holder_base.hpp create mode 100644 libraries/libstratosphere/source/os/impl/os_waitable_holder_impl.hpp create mode 100644 libraries/libstratosphere/source/os/impl/os_waitable_holder_of_event.hpp create mode 100644 libraries/libstratosphere/source/os/impl/os_waitable_holder_of_handle.hpp create mode 100644 libraries/libstratosphere/source/os/impl/os_waitable_holder_of_inter_process_event.hpp create mode 100644 libraries/libstratosphere/source/os/impl/os_waitable_holder_of_interrupt_event.hpp create mode 100644 libraries/libstratosphere/source/os/impl/os_waitable_holder_of_message_queue.hpp create mode 100644 libraries/libstratosphere/source/os/impl/os_waitable_holder_of_semaphore.hpp create mode 100644 libraries/libstratosphere/source/os/impl/os_waitable_holder_of_thread.hpp create mode 100644 libraries/libstratosphere/source/os/impl/os_waitable_manager_impl.cpp create mode 100644 libraries/libstratosphere/source/os/impl/os_waitable_manager_impl.hpp create mode 100644 libraries/libstratosphere/source/os/impl/os_waitable_object_list.hpp create mode 100644 libraries/libstratosphere/source/os/os_event.cpp create mode 100644 libraries/libstratosphere/source/os/os_interrupt_event.cpp create mode 100644 libraries/libstratosphere/source/os/os_message_queue.cpp create mode 100644 libraries/libstratosphere/source/os/os_process_handle.cpp create mode 100644 libraries/libstratosphere/source/os/os_semaphore.cpp create mode 100644 libraries/libstratosphere/source/os/os_system_event.cpp create mode 100644 libraries/libstratosphere/source/os/os_waitable_holder.cpp create mode 100644 libraries/libstratosphere/source/os/os_waitable_manager.cpp create mode 100644 libraries/libstratosphere/source/patcher/patcher_api.cpp create mode 100644 libraries/libstratosphere/source/pm/pm_ams.c create mode 100644 libraries/libstratosphere/source/pm/pm_ams.h create mode 100644 libraries/libstratosphere/source/pm/pm_boot_mode_api.cpp create mode 100644 libraries/libstratosphere/source/pm/pm_dmnt_api.cpp create mode 100644 libraries/libstratosphere/source/pm/pm_info_api.cpp create mode 100644 libraries/libstratosphere/source/pm/pm_shell_api.cpp create mode 100644 libraries/libstratosphere/source/result/result_on_assertion.cpp create mode 100644 libraries/libstratosphere/source/rnd/rnd_api.cpp create mode 100644 libraries/libstratosphere/source/service_guard.h create mode 100644 libraries/libstratosphere/source/settings/settings_fwdbg_api.cpp create mode 100644 libraries/libstratosphere/source/sf/cmif/sf_cmif_domain_manager.cpp create mode 100644 libraries/libstratosphere/source/sf/cmif/sf_cmif_domain_service_object.cpp create mode 100644 libraries/libstratosphere/source/sf/cmif/sf_cmif_service_dispatch.cpp create mode 100644 libraries/libstratosphere/source/sf/cmif/sf_cmif_service_object_holder.cpp create mode 100644 libraries/libstratosphere/source/sf/hipc/sf_hipc_api.cpp create mode 100644 libraries/libstratosphere/source/sf/hipc/sf_hipc_mitm_query_api.cpp create mode 100644 libraries/libstratosphere/source/sf/hipc/sf_hipc_mitm_query_api.hpp create mode 100644 libraries/libstratosphere/source/sf/hipc/sf_hipc_server_domain_session_manager.cpp create mode 100644 libraries/libstratosphere/source/sf/hipc/sf_hipc_server_manager.cpp create mode 100644 libraries/libstratosphere/source/sf/hipc/sf_hipc_server_session_manager.cpp create mode 100644 libraries/libstratosphere/source/sm/sm_ams.c create mode 100644 libraries/libstratosphere/source/sm/sm_ams.h create mode 100644 libraries/libstratosphere/source/sm/sm_api.cpp create mode 100644 libraries/libstratosphere/source/sm/sm_manager_api.cpp create mode 100644 libraries/libstratosphere/source/sm/sm_mitm_api.cpp create mode 100644 libraries/libstratosphere/source/sm/sm_utils.cpp create mode 100644 libraries/libstratosphere/source/sm/sm_utils.hpp create mode 100644 libraries/libstratosphere/source/sm/smm_ams.c create mode 100644 libraries/libstratosphere/source/sm/smm_ams.h create mode 100644 libraries/libstratosphere/source/spl/smc/spl_smc.cpp create mode 100644 libraries/libstratosphere/source/spl/spl_api.cpp create mode 100644 libraries/libstratosphere/source/updater/updater_api.cpp create mode 100644 libraries/libstratosphere/source/updater/updater_bis_management.cpp create mode 100644 libraries/libstratosphere/source/updater/updater_bis_management.hpp create mode 100644 libraries/libstratosphere/source/updater/updater_bis_save.cpp create mode 100644 libraries/libstratosphere/source/updater/updater_bis_save.hpp create mode 100644 libraries/libstratosphere/source/updater/updater_files.cpp create mode 100644 libraries/libstratosphere/source/updater/updater_files.hpp create mode 100644 libraries/libstratosphere/source/updater/updater_paths.cpp create mode 100644 libraries/libstratosphere/source/updater/updater_paths.hpp create mode 100644 libraries/libstratosphere/source/util/ini.c create mode 100644 libraries/libstratosphere/source/util/ini.h create mode 100644 libraries/libstratosphere/source/util/lz4.c create mode 100644 libraries/libstratosphere/source/util/lz4.h create mode 100644 libraries/libstratosphere/source/util/util_compression.cpp create mode 100644 libraries/libstratosphere/source/util/util_ini.cpp create mode 100644 libraries/libvapours/include/freebsd/sys/tree.h create mode 100644 libraries/libvapours/include/vapours.hpp create mode 100644 libraries/libvapours/include/vapours/ams/ams_api_version.h create mode 100644 libraries/libvapours/include/vapours/ams/ams_target_firmware.h create mode 100644 libraries/libvapours/include/vapours/ams_version.h create mode 100644 libraries/libvapours/include/vapours/defines.hpp create mode 100644 libraries/libvapours/include/vapours/includes.hpp create mode 100644 libraries/libvapours/include/vapours/results.hpp create mode 100644 libraries/libvapours/include/vapours/results/cal_results.hpp create mode 100644 libraries/libvapours/include/vapours/results/creport_results.hpp create mode 100644 libraries/libvapours/include/vapours/results/debug_results.hpp create mode 100644 libraries/libvapours/include/vapours/results/dmnt_results.hpp create mode 100644 libraries/libvapours/include/vapours/results/err_results.hpp create mode 100644 libraries/libvapours/include/vapours/results/exosphere_results.hpp create mode 100644 libraries/libvapours/include/vapours/results/fatal_results.hpp create mode 100644 libraries/libvapours/include/vapours/results/fs_results.hpp create mode 100644 libraries/libvapours/include/vapours/results/hipc_results.hpp create mode 100644 libraries/libvapours/include/vapours/results/i2c_results.hpp create mode 100644 libraries/libvapours/include/vapours/results/kvdb_results.hpp create mode 100644 libraries/libvapours/include/vapours/results/loader_results.hpp create mode 100644 libraries/libvapours/include/vapours/results/lr_results.hpp create mode 100644 libraries/libvapours/include/vapours/results/ncm_results.hpp create mode 100644 libraries/libvapours/include/vapours/results/os_results.hpp create mode 100644 libraries/libvapours/include/vapours/results/pm_results.hpp create mode 100644 libraries/libvapours/include/vapours/results/results_common.hpp create mode 100644 libraries/libvapours/include/vapours/results/ro_results.hpp create mode 100644 libraries/libvapours/include/vapours/results/settings_results.hpp create mode 100644 libraries/libvapours/include/vapours/results/sf_results.hpp create mode 100644 libraries/libvapours/include/vapours/results/sm_results.hpp create mode 100644 libraries/libvapours/include/vapours/results/spl_results.hpp create mode 100644 libraries/libvapours/include/vapours/results/svc_results.hpp create mode 100644 libraries/libvapours/include/vapours/results/updater_results.hpp create mode 100644 libraries/libvapours/include/vapours/results/vi_results.hpp create mode 100644 libraries/libvapours/include/vapours/svc.hpp create mode 100644 libraries/libvapours/include/vapours/svc/svc_types.hpp create mode 100644 libraries/libvapours/include/vapours/util.hpp create mode 100644 libraries/libvapours/include/vapours/util/util_alignment.hpp create mode 100644 libraries/libvapours/include/vapours/util/util_intrusive_list.hpp create mode 100644 libraries/libvapours/include/vapours/util/util_intrusive_red_black_tree.hpp create mode 100644 libraries/libvapours/include/vapours/util/util_parent_of_member.hpp create mode 100644 libraries/libvapours/include/vapours/util/util_scope_guard.hpp create mode 100644 libraries/libvapours/include/vapours/util/util_size.hpp create mode 100644 libraries/libvapours/include/vapours/util/util_typed_storage.hpp diff --git a/libraries/.gitignore b/libraries/.gitignore new file mode 100644 index 000000000..f55c55a62 --- /dev/null +++ b/libraries/.gitignore @@ -0,0 +1,74 @@ +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp +*.lst + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Switch Executables +*.nso +*.nro +*.nacp +*.npdm +*.pfs0 +*.nsp +*.kip + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf + +# Distribution files +*.tgz +*.zip + +.**/ + +# NOTE: make sure to make exceptions to this pattern when needed! +*.bin + +**/out +**/build diff --git a/libraries/.gitmodules b/libraries/.gitmodules new file mode 100644 index 000000000..e69de29bb diff --git a/libraries/.gitrepo b/libraries/.gitrepo new file mode 100644 index 000000000..e8d98ca2a --- /dev/null +++ b/libraries/.gitrepo @@ -0,0 +1,12 @@ +; DO NOT EDIT (unless you know what you are doing) +; +; This subdirectory is a git "subrepo", and this file is maintained by the +; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme +; +[subrepo] + remote = https://github.com/Atmosphere-NX/Atmosphere-libs + branch = master + commit = 07af583bb81df9b40be5a54659ba598d8ce9d767 + parent = 71fd69eb5ac820a94d0098e9137394ef95cd837d + method = merge + cmdver = 0.4.0 diff --git a/libraries/LICENSE b/libraries/LICENSE new file mode 100644 index 000000000..ecbc05937 --- /dev/null +++ b/libraries/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. \ No newline at end of file diff --git a/libraries/Makefile b/libraries/Makefile new file mode 100644 index 000000000..05253b1de --- /dev/null +++ b/libraries/Makefile @@ -0,0 +1,10 @@ +ATMOSPHERE_LIBRARIES := libstratosphere + +TOPTARGETS := all clean + +$(TOPTARGETS): $(ATMOSPHERE_LIBRARIES) + +$(ATMOSPHERE_LIBRARIES): + $(MAKE) -C $@ $(MAKECMDGOALS) + +.PHONY: $(TOPTARGETS) $(ATMOSPHERE_LIBRARIES) \ No newline at end of file diff --git a/libraries/README.md b/libraries/README.md new file mode 100644 index 000000000..da207a789 --- /dev/null +++ b/libraries/README.md @@ -0,0 +1,30 @@ +![License](https://img.shields.io/badge/License-GPLv2-blue.svg) + +Atmosphere-libs is a collection of libraries for doing operating system development for the Nintendo Switch. + +Licensing +===== + +This software is licensed under the terms of the GPLv2, with exemptions for specific projects noted below. + +You can find a copy of the license in the [LICENSE file](LICENSE). + +Exemptions: +* The [yuzu emulator project](https://github.com/yuzu-emu/yuzu) is exempt from GPLv2 licensing and may (at its option) instead license any source code authored for the atmosphere-libs project as GPLv2 or later. + +Credits +===== + +Atmosphere-libs is currently being developed and maintained by __SciresM__.
+ +In addition to those credited in [Atmosphère's credits](https://github.com/Atmosphere-NX/Atmosphere/blob/master/README.md#Credits), we would like to thank for contributing to atmosphere-libs in some significant way: + +* @[devkitPro](https://github.com/devkitPro) +* @[yellows8](https://github.com/yellows8) +* @[qlutoo](https://github.com/plutooo) +* @[hedgeberg](https://github.com/hedgeberg) +* @[Nintendo](https://github.com/Nintendo) +* @[NVidia](https://github.com/NVidia) +* @[Kaphotics](https://github.com/kwsch) + +Additional credits may be found in the README.md for specific libraries. \ No newline at end of file diff --git a/libraries/config/arch/arm64/arch.mk b/libraries/config/arch/arm64/arch.mk new file mode 100644 index 000000000..191b2fe9f --- /dev/null +++ b/libraries/config/arch/arm64/arch.mk @@ -0,0 +1,11 @@ +ifeq ($(strip $(DEVKITPRO)),) +$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=/devkitpro") +endif + +include $(DEVKITPRO)/devkitA64/base_rules + +export ATMOSPHERE_DEFINES += -DATMOSPHERE_ARCH_ARM64 +export ATMOSPHERE_SETTINGS += -march=armv8-a -mtp=soft +export ATMOSPHERE_CFLAGS += +export ATMOSPHERE_CXXFLAGS += +export ATMOSPHERE_ASFLAGS += diff --git a/libraries/config/board/nintendo/switch/board.mk b/libraries/config/board/nintendo/switch/board.mk new file mode 100644 index 000000000..c3d3d10e5 --- /dev/null +++ b/libraries/config/board/nintendo/switch/board.mk @@ -0,0 +1,5 @@ +export ATMOSPHERE_DEFINES += -DATMOSPHERE_BOARD_NINTENDO_SWITCH -D__SWITCH__ +export ATMOSPHERE_SETTINGS += -mtune=cortex-a57 +export ATMOSPHERE_CFLAGS += +export ATMOSPHERE_CXXFLAGS += +export ATMOSPHERE_ASFLAGS += \ No newline at end of file diff --git a/libraries/config/common.mk b/libraries/config/common.mk new file mode 100644 index 000000000..91505afdc --- /dev/null +++ b/libraries/config/common.mk @@ -0,0 +1,74 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- + +export ATMOSPHERE_CONFIG_MAKE_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) +export ATMOSPHERE_LIBRARIES_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/.. + +ifeq ($(strip $(ATMOSPHERE_BOARD)),) +export ATMOSPHERE_BOARD := nx-hac-001 +endif + +export ATMOSPHERE_DEFINES := -DATMOSPHERE +export ATMOSPHERE_SETTINGS := -fPIE -g +export ATMOSPHERE_CFLAGS := -Wall -ffunction-sections -fdata-sections -fno-strict-aliasing -fwrapv \ + -fno-asynchronous-unwind-tables -fno-unwind-tables -fno-stack-protector +export ATMOSPHERE_CXXFLAGS := -fno-rtti -fno-exceptions -std=gnu++17 +export ATMOSPHERE_ASFLAGS := + + +ifeq ($(ATMOSPHERE_BOARD),nx-hac-001) +export ATMOSPHERE_ARCH_DIR := arch/arm64 +export ATMOSPHERE_BOARD_DIR := board/nintendo/switch +export ATMOSPHERE_OS_DIR := os/horizon + +export ATMOSPHERE_ARCH_NAME := arm64 +export ATMOSPHERE_BOARD_NAME := nintendo_switch +export ATMOSPHERE_OS_NAME := horizon +endif + + +export ATMOSPHERE_ARCH_MAKE_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/$(ATMOSPHERE_ARCH_DIR) +export ATMOSPHERE_BOARD_MAKE_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/$(ATMOSPHERE_BOARD_DIR) +export ATMOSPHERE_OS_MAKE_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/$(ATMOSPHERE_OS_DIR) + +include $(ATMOSPHERE_ARCH_MAKE_DIR)/arch.mk +include $(ATMOSPHERE_BOARD_MAKE_DIR)/board.mk +include $(ATMOSPHERE_OS_MAKE_DIR)/os.mk + +#--------------------------------------------------------------------------------- +# get atmosphere git revision information +#--------------------------------------------------------------------------------- +export ATMOSPHERE_GIT_BRANCH := $(shell git symbolic-ref --short HEAD) + +ifeq ($(strip $(shell git status --porcelain 2>/dev/null)),) +export ATMOSPHERE_GIT_REVISION := $(ATMOSPHERE_GIT_BRANCH)-$(shell git rev-parse --short HEAD) +else +export ATMOSPHERE_GIT_REVISION := $(ATMOSPHERE_GIT_BRANCH)-$(shell git rev-parse --short HEAD)-dirty +endif + +ATMOSPHERE_DEFINES += -DATMOSPHERE_GIT_BRANCH=\"$(ATMOSPHERE_GIT_BRANCH)\" -DATMOSPHERE_GIT_REVISION=\"$(ATMOSPHERE_GIT_REVISION)\" + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# SOURCES is a list of directories containing source code +# DATA is a list of directories containing data files +# INCLUDES is a list of directories containing header files +#--------------------------------------------------------------------------------- +export TARGET := $(notdir $(CURDIR)) +export BUILD := build +export DATA := data +export INCLUDES := include +export SOURCES ?= $(shell find source -type d \ + -not \( -path source/arch -prune \) \ + -not \( -path source/board -prune \) \) + +ifneq ($(strip $(wildcard source/$(ATMOSPHERE_ARCH_DIR)./.*)),) +SOURCES += $(shell find source/$(ATMOSPHERE_ARCH_DIR) -type d) +endif +ifneq ($(strip $(wildcard source/$(ATMOSPHERE_BOARD_DIR)./.*)),) +SOURCES += $(shell find source/$(ATMOSPHERE_BOARD_DIR) -type d) +endif +ifneq ($(strip $(wildcard source/$(ATMOSPHERE_OS_DIR)./.*)),) +SOURCES += $(shell find source/$(ATMOSPHERE_OS_DIR) -type d) +endif diff --git a/libraries/config/os/horizon/os.mk b/libraries/config/os/horizon/os.mk new file mode 100644 index 000000000..5c972b74b --- /dev/null +++ b/libraries/config/os/horizon/os.mk @@ -0,0 +1,5 @@ +export ATMOSPHERE_DEFINES += -DATMOSPHERE_OS_HORIZON +export ATMOSPHERE_SETTINGS += +export ATMOSPHERE_CFLAGS += +export ATMOSPHERE_CXXFLAGS += +export ATMOSPHERE_ASFLAGS += diff --git a/libraries/config/templates/stratosphere.mk b/libraries/config/templates/stratosphere.mk new file mode 100644 index 000000000..a876019d9 --- /dev/null +++ b/libraries/config/templates/stratosphere.mk @@ -0,0 +1,52 @@ +#--------------------------------------------------------------------------------- +# pull in common atmosphere configuration +#--------------------------------------------------------------------------------- +include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../common.mk + +#--------------------------------------------------------------------------------- +# pull in switch rules +#--------------------------------------------------------------------------------- +ifeq ($(strip $(DEVKITPRO)),) +$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=/devkitpro") +endif + +include $(DEVKITPRO)/libnx/switch_rules + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +export DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_STRATOSPHERE +export SETTINGS := $(ATMOSPHERE_SETTINGS) -O2 +export CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE) +export CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) +export ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) + +export CXXWRAPS := -Wl,--wrap,__cxa_pure_virtual \ + -Wl,--wrap,__cxa_throw \ + -Wl,--wrap,__cxa_rethrow \ + -Wl,--wrap,__cxa_allocate_exception \ + -Wl,--wrap,__cxa_free_exception \ + -Wl,--wrap,__cxa_begin_catch \ + -Wl,--wrap,__cxa_end_catch \ + -Wl,--wrap,__cxa_call_unexpected \ + -Wl,--wrap,__cxa_call_terminate \ + -Wl,--wrap,__gxx_personality_v0 \ + -Wl,--wrap,_Unwind_Resume \ + -Wl,--wrap,_ZSt19__throw_logic_errorPKc \ + -Wl,--wrap,_ZSt20__throw_length_errorPKc \ + -Wl,--wrap,_ZNSt11logic_errorC2EPKc + +export LDFLAGS := -specs=$(DEVKITPRO)/libnx/switch.specs $(SETTINGS) $(CXXWRAPS) -Wl,-Map,$(notdir $*.map) + +export LIBS := -lstratosphere -lnx + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +export LIBDIRS := $(PORTLIBS) $(LIBNX) $(ATMOSPHERE_LIBRARIES_DIR)/libvapours $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere + +#--------------------------------------------------------------------------------- +# stratosphere sysmodules may (but usually do not) have an exefs source dir +#--------------------------------------------------------------------------------- +export EXEFS_SRC := exefs_src \ No newline at end of file diff --git a/libraries/libstratosphere/Makefile b/libraries/libstratosphere/Makefile new file mode 100644 index 000000000..928fe0428 --- /dev/null +++ b/libraries/libstratosphere/Makefile @@ -0,0 +1,140 @@ +#--------------------------------------------------------------------------------- +# pull in common atmosphere configuration +#--------------------------------------------------------------------------------- +include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../config/common.mk + +#--------------------------------------------------------------------------------- +# pull in switch rules +#--------------------------------------------------------------------------------- +ifeq ($(strip $(DEVKITPRO)),) +$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=/devkitpro") +endif + +include $(DEVKITPRO)/libnx/switch_rules + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_STRATOSPHERE +SETTINGS := $(ATMOSPHERE_SETTINGS) -O2 +CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE) +CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -flto +ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) + +LDFLAGS := -specs=$(DEVKITPRO)/libnx/switch.specs $(SETTINGS) -Wl,-Map,$(notdir $*.map) + +LIBS := -lnx + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(PORTLIBS) $(LIBNX) $(ATMOSPHERE_LIBRARIES_DIR)/libvapours + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +CFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.c)) $(notdir $(wildcard $(dir)/*.board.*.c)) $(notdir $(wildcard $(dir)/*.os.*.c)), \ + $(notdir $(wildcard $(dir)/*.c)))) +CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).c))) +CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).c))) +CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).c))) + +CPPFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.cpp)) $(notdir $(wildcard $(dir)/*.board.*.cpp)) $(notdir $(wildcard $(dir)/*.os.*.cpp)), \ + $(notdir $(wildcard $(dir)/*.cpp)))) +CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).cpp))) +CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).cpp))) +CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).cpp))) + +SFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.s)) $(notdir $(wildcard $(dir)/*.board.*.s)) $(notdir $(wildcard $(dir)/*.os.*.s)), \ + $(notdir $(wildcard $(dir)/*.s)))) +SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).s))) +SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).s))) +SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).s))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES_BIN := $(addsuffix .o,$(BINFILES)) +export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +export OFILES := $(OFILES_BIN) $(OFILES_SRC) +export HFILES := $(addsuffix .h,$(subst .,_,$(BINFILES))) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I. + +.PHONY: clean all + +#--------------------------------------------------------------------------------- +all: lib/$(TARGET).a + +lib: + @[ -d $@ ] || mkdir -p $@ + +release: + @[ -d $@ ] || mkdir -p $@ + +lib/$(TARGET).a : lib release $(SOURCES) $(INCLUDES) + @$(MAKE) BUILD=release OUTPUT=$(CURDIR)/$@ \ + BUILD_CFLAGS="-DNDEBUG=1 -O2" \ + DEPSDIR=$(CURDIR)/release \ + --no-print-directory -C release \ + -f $(CURDIR)/Makefile + +dist-bin: all + @tar --exclude=*~ -cjf $(TARGET).tar.bz2 include lib + +dist-src: + @tar --exclude=*~ -cjf $(TARGET)-src.tar.bz2 include source Makefile + +dist: dist-src dist-bin + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr release lib *.bz2 + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT) : $(OFILES) + +$(OFILES_SRC) : $(HFILES) + +#--------------------------------------------------------------------------------- +%_bin.h %.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- + diff --git a/libraries/libstratosphere/README.md b/libraries/libstratosphere/README.md new file mode 100644 index 000000000..0dc7138b4 --- /dev/null +++ b/libraries/libstratosphere/README.md @@ -0,0 +1,31 @@ +![License](https://img.shields.io/badge/License-GPLv2-blue.svg) + +libstratosphere is a work-in-progress C++ library for development of system modules for the Nintendo Switch. + +It is built around extending [libnx](https://github.com/switchbrew/libnx). + +It also provides bindings for custom extensions to Horizon OS implemented by [Atmosphère](https://github.com/Atmosphere-NX). + +Licensing +===== + +This software is licensed under the terms of the GPLv2, with exemptions for specific projects noted below. + +You can find a copy of the license in the [LICENSE file](LICENSE). + +Exemptions: +* The [yuzu emulator project](https://github.com/yuzu-emu/yuzu) is exempt from GPLv2 licensing and may (at its option) instead license any source code authored for the libstratosphere project as GPLv2 or later. + +Credits +===== + +libstratosphere is currently being developed and maintained by __SciresM__.
+ +In addition to those credited in [Atmosphère's credits](https://github.com/Atmosphere-NX/Atmosphere/blob/master/README.md#Credits), we would like to thank for contributing to libstratosphere in some significant way: + +* __hthh__ +* __fincs__ +* __lioncash__ +* __misson20000__ +* __neobrain__ +* __yellows8__ diff --git a/libraries/libstratosphere/include/stratosphere.hpp b/libraries/libstratosphere/include/stratosphere.hpp new file mode 100644 index 000000000..aae1f69cd --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere.hpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +/* libvapours (pulls in util, svc, results). */ +#include + +/* Libstratosphere-only utility. */ +#include "stratosphere/util.hpp" + +/* Critical modules with no dependencies. */ +#include "stratosphere/ams.hpp" +#include "stratosphere/os.hpp" +#include "stratosphere/dd.hpp" + +/* Lots of things depend on NCM, for Program IDs. */ +#include "stratosphere/ncm.hpp" + +/* At this point, just include the rest alphabetically. */ +/* TODO: Figure out optimal order. */ +#include "stratosphere/boot2.hpp" +#include "stratosphere/cfg.hpp" +#include "stratosphere/dmnt.hpp" +#include "stratosphere/fatal.hpp" +#include "stratosphere/hid.hpp" +#include "stratosphere/hos.hpp" +#include "stratosphere/kvdb.hpp" +#include "stratosphere/ldr.hpp" +#include "stratosphere/map.hpp" +#include "stratosphere/patcher.hpp" +#include "stratosphere/pm.hpp" +#include "stratosphere/reg.hpp" +#include "stratosphere/rnd.hpp" +#include "stratosphere/ro.hpp" +#include "stratosphere/settings.hpp" +#include "stratosphere/sf.hpp" +#include "stratosphere/sm.hpp" +#include "stratosphere/spl.hpp" +#include "stratosphere/updater.hpp" + +/* Include FS last. */ +#include "stratosphere/fs.hpp" +#include "stratosphere/fssrv.hpp" +#include "stratosphere/fssystem.hpp" diff --git a/libraries/libstratosphere/include/stratosphere/ams.hpp b/libraries/libstratosphere/include/stratosphere/ams.hpp new file mode 100644 index 000000000..8abd99240 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/ams.hpp @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "ams/ams_types.hpp" +#include "ams/ams_exosphere_api.hpp" +#include "ams/ams_emummc_api.hpp" +#include "ams/ams_environment.hpp" diff --git a/libraries/libstratosphere/include/stratosphere/ams/ams_emummc_api.hpp b/libraries/libstratosphere/include/stratosphere/ams/ams_emummc_api.hpp new file mode 100644 index 000000000..e1d3d21ec --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/ams/ams_emummc_api.hpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "ams_types.hpp" + +namespace ams::emummc { + + /* Get whether emummc is active. */ + bool IsActive(); + + /* Get Nintendo redirection path. */ + const char *GetNintendoDirPath(); + + /* Get Emummc folderpath, NULL if not file-based. */ + const char *GetFilePath(); + +} diff --git a/libraries/libstratosphere/include/stratosphere/ams/ams_environment.hpp b/libraries/libstratosphere/include/stratosphere/ams/ams_environment.hpp new file mode 100644 index 000000000..d6138e1ca --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/ams/ams_environment.hpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "ams_types.hpp" + +namespace ams { + + /* Will be called by libstratosphere on crash. */ + void CrashHandler(ThreadExceptionDump *ctx); + +} diff --git a/libraries/libstratosphere/include/stratosphere/ams/ams_exosphere_api.hpp b/libraries/libstratosphere/include/stratosphere/ams/ams_exosphere_api.hpp new file mode 100644 index 000000000..1fc60aff9 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/ams/ams_exosphere_api.hpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "ams_types.hpp" + +namespace ams::exosphere { + + ApiInfo GetApiInfo(); + + void ForceRebootToRcm(); + void ForceRebootToIramPayload(); + void ForceShutdown(); + + bool IsRcmBugPatched(); + + void CopyToIram(uintptr_t iram_dst, const void *dram_src, size_t size); + void CopyFromIram(void *dram_dst, uintptr_t iram_src, size_t size); + +} + +namespace ams { + + /* Version checking utility. */ + inline void CheckApiVersion() { + const u32 runtime_version = exosphere::GetApiInfo().GetVersion(); + const u32 build_version = exosphere::GetVersion(ATMOSPHERE_RELEASE_VERSION); + + if (runtime_version < build_version) { + R_ASSERT(exosphere::ResultVersionMismatch()); + } + } + +} diff --git a/libraries/libstratosphere/include/stratosphere/ams/ams_types.hpp b/libraries/libstratosphere/include/stratosphere/ams/ams_types.hpp new file mode 100644 index 000000000..9ac1fdd35 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/ams/ams_types.hpp @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include "../sf/sf_buffer_tags.hpp" +#include "../hos.hpp" + +namespace ams::exosphere { + + #define AMS_DEFINE_TARGET_FIRMWARE_ENUM(n) TargetFirmware_##n = ATMOSPHERE_TARGET_FIRMWARE_##n + enum TargetFirmware : u32 { + AMS_DEFINE_TARGET_FIRMWARE_ENUM(100), + AMS_DEFINE_TARGET_FIRMWARE_ENUM(200), + AMS_DEFINE_TARGET_FIRMWARE_ENUM(300), + AMS_DEFINE_TARGET_FIRMWARE_ENUM(400), + AMS_DEFINE_TARGET_FIRMWARE_ENUM(500), + AMS_DEFINE_TARGET_FIRMWARE_ENUM(600), + AMS_DEFINE_TARGET_FIRMWARE_ENUM(620), + AMS_DEFINE_TARGET_FIRMWARE_ENUM(700), + AMS_DEFINE_TARGET_FIRMWARE_ENUM(800), + AMS_DEFINE_TARGET_FIRMWARE_ENUM(810), + AMS_DEFINE_TARGET_FIRMWARE_ENUM(900), + AMS_DEFINE_TARGET_FIRMWARE_ENUM(910), + }; + #undef AMS_DEFINE_TARGET_FIRMWARE_ENUM + + constexpr inline u32 GetVersion(u32 major, u32 minor, u32 micro) { + return (major << 16) | (minor << 8) | (micro); + } + + struct ApiInfo { + u32 major_version; + u32 minor_version; + u32 micro_version; + TargetFirmware target_firmware; + u32 master_key_revision; + + constexpr u32 GetVersion() const { + return ::ams::exosphere::GetVersion(this->major_version, this->minor_version, this->micro_version); + } + + constexpr TargetFirmware GetTargetFirmware() const { + return this->target_firmware; + } + + constexpr u32 GetMasterKeyRevision() const { + return this->master_key_revision; + } + }; + +} + +namespace ams { + + struct FatalErrorContext : sf::LargeData, sf::PrefersMapAliasTransferMode { + static constexpr size_t MaxStackTrace = 0x20; + static constexpr size_t MaxStackDumpSize = 0x100; + static constexpr size_t NumGprs = 29; + static constexpr uintptr_t StdAbortMagicAddress = 0x8; + static constexpr u64 StdAbortMagicValue = 0xA55AF00DDEADCAFEul; + static constexpr u32 StdAbortErrorDesc = 0xFFE; + static constexpr u32 DataAbortErrorDesc = 0x101; + static constexpr u32 Magic = 0x31454641; + + u32 magic; + u32 error_desc; + u64 program_id; + union { + u64 gprs[32]; + struct { + u64 _gprs[29]; + u64 fp; + u64 lr; + u64 sp; + }; + }; + u64 pc; + u64 module_base; + u32 pstate; + u32 afsr0; + u32 afsr1; + u32 esr; + u64 far; + u64 report_identifier; /* Normally just system tick. */ + u64 stack_trace_size; + u64 stack_dump_size; + u64 stack_trace[MaxStackTrace]; + u8 stack_dump[MaxStackDumpSize]; + }; + + static_assert(sizeof(FatalErrorContext) == 0x350, "sizeof(FatalErrorContext)"); + static_assert(std::is_pod::value, "FatalErrorContext"); + +#ifdef ATMOSPHERE_GIT_BRANCH + NX_CONSTEXPR const char *GetGitBranch() { + return ATMOSPHERE_GIT_BRANCH; + } +#endif + +#ifdef ATMOSPHERE_GIT_REVISION + NX_CONSTEXPR const char *GetGitRevision() { + return ATMOSPHERE_GIT_REVISION; + } +#endif + +} diff --git a/libraries/libstratosphere/include/stratosphere/boot2.hpp b/libraries/libstratosphere/include/stratosphere/boot2.hpp new file mode 100644 index 000000000..f75afe4b1 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/boot2.hpp @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "boot2/boot2_api.hpp" diff --git a/libraries/libstratosphere/include/stratosphere/boot2/boot2_api.hpp b/libraries/libstratosphere/include/stratosphere/boot2/boot2_api.hpp new file mode 100644 index 000000000..21e777254 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/boot2/boot2_api.hpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include + +namespace ams::boot2 { + + /* Boot2 API. */ + + /* Normally invoked by PM. */ + void LaunchPreSdCardBootProgramsAndBoot2(); + + /* Normally invoked by boot2. */ + void LaunchPostSdCardBootPrograms(); + +} diff --git a/libraries/libstratosphere/include/stratosphere/cfg.hpp b/libraries/libstratosphere/include/stratosphere/cfg.hpp new file mode 100644 index 000000000..6c9f85bfe --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/cfg.hpp @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "cfg/cfg_api.hpp" diff --git a/libraries/libstratosphere/include/stratosphere/cfg/cfg_api.hpp b/libraries/libstratosphere/include/stratosphere/cfg/cfg_api.hpp new file mode 100644 index 000000000..e111164a8 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/cfg/cfg_api.hpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "cfg_types.hpp" +#include "cfg_locale_types.hpp" +#include "../sm/sm_types.hpp" + +namespace ams::cfg { + + /* Privileged Process configuration. */ + bool IsInitialProcess(); + void GetInitialProcessRange(os::ProcessId *out_min, os::ProcessId *out_max); + + /* SD card configuration. */ + bool IsSdCardRequiredServicesReady(); + void WaitSdCardRequiredServicesReady(); + bool IsSdCardInitialized(); + void WaitSdCardInitialized(); + + /* Override key utilities. */ + OverrideStatus CaptureOverrideStatus(ncm::ProgramId program_id); + + /* Locale utilities. */ + OverrideLocale GetOverrideLocale(ncm::ProgramId program_id); + + /* Flag utilities. */ + bool HasFlag(const sm::MitmProcessInfo &process_info, const char *flag); + bool HasContentSpecificFlag(ncm::ProgramId program_id, const char *flag); + bool HasGlobalFlag(const char *flag); + + /* HBL Configuration utilities. */ + bool IsHblProgramId(ncm::ProgramId program_id); + bool HasHblFlag(const char *flag); + const char *GetHblPath(); + +} diff --git a/libraries/libstratosphere/include/stratosphere/cfg/cfg_locale_types.hpp b/libraries/libstratosphere/include/stratosphere/cfg/cfg_locale_types.hpp new file mode 100644 index 000000000..d281c6cfa --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/cfg/cfg_locale_types.hpp @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "cfg_types.hpp" +#include "../settings/settings_types.hpp" + +namespace ams::cfg { + + struct OverrideLocale { + settings::LanguageCode language_code; + settings::RegionCode region_code; + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/cfg/cfg_types.hpp b/libraries/libstratosphere/include/stratosphere/cfg/cfg_types.hpp new file mode 100644 index 000000000..71cf7e20a --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/cfg/cfg_types.hpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "../os/os_common_types.hpp" +#include "../ncm/ncm_types.hpp" + +namespace ams::cfg { + + namespace impl { + + enum OverrideStatusFlag : u64 { + OverrideStatusFlag_Hbl = BIT(0), + OverrideStatusFlag_ProgramSpecific = BIT(1), + OverrideStatusFlag_CheatEnabled = BIT(2), + }; + + } + + struct OverrideStatus { + u64 keys_held; + u64 flags; + + constexpr inline u64 GetKeysHeld() const { return this->keys_held; } + + #define DEFINE_FLAG_ACCESSORS(flag) \ + constexpr inline bool Is##flag() const { return this->flags & impl::OverrideStatusFlag_##flag; } \ + constexpr inline void Set##flag() { this->flags |= impl::OverrideStatusFlag_##flag; } \ + constexpr inline void Clear##flag() { this->flags &= ~u64(impl::OverrideStatusFlag_##flag); } + + DEFINE_FLAG_ACCESSORS(Hbl) + DEFINE_FLAG_ACCESSORS(ProgramSpecific) + DEFINE_FLAG_ACCESSORS(CheatEnabled) + + #undef DEFINE_FLAG_ACCESSORS + }; + + static_assert(sizeof(OverrideStatus) == 0x10, "sizeof(OverrideStatus)"); + static_assert(std::is_pod::value, "std::is_pod::value"); + + constexpr inline bool operator==(const OverrideStatus &lhs, const OverrideStatus &rhs) { + return std::memcmp(&lhs, &rhs, sizeof(lhs)) == 0; + } + + constexpr inline bool operator!=(const OverrideStatus &lhs, const OverrideStatus &rhs) { + return !(lhs == rhs); + } + +} diff --git a/libraries/libstratosphere/include/stratosphere/dd.hpp b/libraries/libstratosphere/include/stratosphere/dd.hpp new file mode 100644 index 000000000..d82cd8740 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/dd.hpp @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "dd/dd_io_mappings.hpp" +#include "dd/dd_process_handle.hpp" diff --git a/libraries/libstratosphere/include/stratosphere/dd/dd_io_mappings.hpp b/libraries/libstratosphere/include/stratosphere/dd/dd_io_mappings.hpp new file mode 100644 index 000000000..e2d79dd11 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/dd/dd_io_mappings.hpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include + +namespace ams::dd { + + uintptr_t QueryIoMapping(uintptr_t phys_addr, size_t size); + + u32 ReadRegister(uintptr_t phys_addr); + void WriteRegister(uintptr_t phys_addr, u32 value); + u32 ReadWriteRegister(uintptr_t phys_addr, u32 value, u32 mask); + + /* Convenience Helper. */ + + inline uintptr_t GetIoMapping(uintptr_t phys_addr, size_t size) { + const uintptr_t io_mapping = QueryIoMapping(phys_addr, size); + AMS_ASSERT(io_mapping); + return io_mapping; + } + +} diff --git a/libraries/libstratosphere/include/stratosphere/dd/dd_process_handle.hpp b/libraries/libstratosphere/include/stratosphere/dd/dd_process_handle.hpp new file mode 100644 index 000000000..8fa37ca61 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/dd/dd_process_handle.hpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include + +namespace ams::dd { + + ::Handle GetCurrentProcessHandle(); + +} diff --git a/libraries/libstratosphere/include/stratosphere/dmnt.hpp b/libraries/libstratosphere/include/stratosphere/dmnt.hpp new file mode 100644 index 000000000..a0d421b4b --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/dmnt.hpp @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "dmnt/dmnt_cheat_types.hpp" diff --git a/libraries/libstratosphere/include/stratosphere/dmnt/dmnt_cheat_types.hpp b/libraries/libstratosphere/include/stratosphere/dmnt/dmnt_cheat_types.hpp new file mode 100644 index 000000000..82062af91 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/dmnt/dmnt_cheat_types.hpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "../os/os_common_types.hpp" +#include "../ncm/ncm_types.hpp" +#include "../sf/sf_buffer_tags.hpp" + +namespace ams::dmnt::cheat { + + struct CheatProcessMetadata { + struct MemoryRegionExtents { + u64 base; + u64 size; + }; + + os::ProcessId process_id; + ncm::ProgramId program_id; + MemoryRegionExtents main_nso_extents; + MemoryRegionExtents heap_extents; + MemoryRegionExtents alias_extents; + MemoryRegionExtents aslr_extents; + u8 main_nso_build_id[0x20]; + }; + + static_assert(std::is_pod::value && sizeof(CheatProcessMetadata) == 0x70, "CheatProcessMetadata definition!"); + + struct CheatDefinition : sf::LargeData, sf::PrefersMapAliasTransferMode { + char readable_name[0x40]; + uint32_t num_opcodes; + uint32_t opcodes[0x100]; + }; + + struct CheatEntry : sf::LargeData, sf::PrefersMapAliasTransferMode { + bool enabled; + uint32_t cheat_id; + CheatDefinition definition; + }; + + static_assert(std::is_pod::value, "CheatDefinition"); + static_assert(std::is_pod::value, "CheatEntry"); + + struct FrozenAddressValue { + u64 value; + u8 width; + }; + + struct FrozenAddressEntry { + u64 address; + FrozenAddressValue value; + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/fatal.hpp b/libraries/libstratosphere/include/stratosphere/fatal.hpp new file mode 100644 index 000000000..de81dacf3 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fatal.hpp @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "fatal/fatal_types.hpp" diff --git a/libraries/libstratosphere/include/stratosphere/fatal/fatal_types.hpp b/libraries/libstratosphere/include/stratosphere/fatal/fatal_types.hpp new file mode 100644 index 000000000..d0740194a --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fatal/fatal_types.hpp @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include "../ncm/ncm_types.hpp" +#include "../sf/sf_buffer_tags.hpp" + +namespace ams::fatal { + + namespace aarch64 { + + enum RegisterName { + RegisterName_X0 = 0, + RegisterName_X1 = 1, + RegisterName_X2 = 2, + RegisterName_X3 = 3, + RegisterName_X4 = 4, + RegisterName_X5 = 5, + RegisterName_X6 = 6, + RegisterName_X7 = 7, + RegisterName_X8 = 8, + RegisterName_X9 = 9, + RegisterName_X10 = 10, + RegisterName_X11 = 11, + RegisterName_X12 = 12, + RegisterName_X13 = 13, + RegisterName_X14 = 14, + RegisterName_X15 = 15, + RegisterName_X16 = 16, + RegisterName_X17 = 17, + RegisterName_X18 = 18, + RegisterName_X19 = 19, + RegisterName_X20 = 20, + RegisterName_X21 = 21, + RegisterName_X22 = 22, + RegisterName_X23 = 23, + RegisterName_X24 = 24, + RegisterName_X25 = 25, + RegisterName_X26 = 26, + RegisterName_X27 = 27, + RegisterName_X28 = 28, + RegisterName_FP = 29, + RegisterName_LR = 30, + + RegisterName_SP = 31, + RegisterName_PC = 32, + + RegisterName_GeneralPurposeCount, + + RegisterName_PState = 33, + RegisterName_Afsr0 = 34, + RegisterName_Afsr1 = 35, + RegisterName_Esr = 36, + RegisterName_Far = 37, + + RegisterName_Count, + }; + + struct CpuContext { + using RegisterType = u64; + static constexpr size_t MaxStackTraceDepth = 0x20; + + static constexpr const char *RegisterNameStrings[RegisterName_Count] = { + u8"X0", + u8"X1", + u8"X2", + u8"X3", + u8"X4", + u8"X5", + u8"X6", + u8"X7", + u8"X8", + u8"X9", + u8"X10", + u8"X11", + u8"X12", + u8"X13", + u8"X14", + u8"X15", + u8"X16", + u8"X17", + u8"X18", + u8"X19", + u8"X20", + u8"X21", + u8"X22", + u8"X23", + u8"X24", + u8"X25", + u8"X26", + u8"X27", + u8"X28", + u8"FP", + u8"LR", + u8"SP", + u8"PC", + u8"PState", + u8"Afsr0", + u8"Afsr1", + u8"Esr", + u8"Far", + }; + + /* Registers, exception context. N left names for these fields in fatal .rodata. */ + union { + struct { + union { + RegisterType x[RegisterName_GeneralPurposeCount]; + struct { + RegisterType _x[RegisterName_FP]; + RegisterType fp; + RegisterType lr; + RegisterType sp; + RegisterType pc; + }; + }; + RegisterType pstate; + RegisterType afsr0; + RegisterType afsr1; + RegisterType esr; + RegisterType far; + }; + RegisterType registers[RegisterName_Count]; + }; + + /* Misc. */ + RegisterType stack_trace[MaxStackTraceDepth]; + RegisterType base_address; + RegisterType register_set_flags; + u32 stack_trace_size; + + void ClearState() { + std::memset(this, 0, sizeof(*this)); + } + + void SetProgramIdForAtmosphere(ncm::ProgramId program_id) { + /* Right now, we mux program ID in through afsr when creport. */ + /* TODO: Better way to do this? */ + this->afsr0 = static_cast(program_id); + } + + ncm::ProgramId GetProgramIdForAtmosphere() const { + return ncm::ProgramId{this->afsr0}; + } + + void SetRegisterValue(RegisterName name, RegisterType value) { + this->registers[name] = value; + this->register_set_flags |= (RegisterType(1) << name); + } + + bool HasRegisterValue(RegisterName name) const { + return this->register_set_flags & (RegisterType(1) << name); + } + + void SetBaseAddress(RegisterType base_addr) { + this->base_address = base_addr; + } + }; + + } + + namespace aarch32 { + + enum RegisterName { + RegisterName_R0 = 0, + RegisterName_R1 = 1, + RegisterName_R2 = 2, + RegisterName_R3 = 3, + RegisterName_R4 = 4, + RegisterName_R5 = 5, + RegisterName_R6 = 6, + RegisterName_R7 = 7, + RegisterName_R8 = 8, + RegisterName_R9 = 9, + RegisterName_R10 = 10, + RegisterName_FP = 11, + RegisterName_IP = 12, + RegisterName_LR = 13, + RegisterName_SP = 14, + RegisterName_PC = 15, + + RegisterName_GeneralPurposeCount, + + RegisterName_PState = 16, + RegisterName_Afsr0 = 17, + RegisterName_Afsr1 = 18, + RegisterName_Esr = 29, + RegisterName_Far = 20, + + RegisterName_Count, + }; + + struct CpuContext { + using RegisterType = u32; + static constexpr size_t MaxStackTraceDepth = 0x20; + + static constexpr const char *RegisterNameStrings[RegisterName_Count] = { + u8"R0", + u8"R1", + u8"R2", + u8"R3", + u8"R4", + u8"R5", + u8"R6", + u8"R7", + u8"R8", + u8"R9", + u8"R10", + u8"FP", + u8"IP", + u8"LR", + u8"SP", + u8"PC", + u8"PState", + u8"Afsr0", + u8"Afsr1", + u8"Esr", + u8"Far", + }; + + /* Registers, exception context. N left names for these fields in fatal .rodata. */ + union { + struct { + union { + RegisterType r[RegisterName_GeneralPurposeCount]; + struct { + RegisterType _x[RegisterName_FP]; + RegisterType fp; + RegisterType ip; + RegisterType lr; + RegisterType sp; + RegisterType pc; + }; + }; + RegisterType pstate; + RegisterType afsr0; + RegisterType afsr1; + RegisterType esr; + RegisterType far; + }; + RegisterType registers[RegisterName_Count]; + }; + + /* Misc. Yes, stack_trace_size is really laid out differently than aarch64... */ + RegisterType stack_trace[MaxStackTraceDepth]; + u32 stack_trace_size; + RegisterType base_address; + RegisterType register_set_flags; + + void ClearState() { + std::memset(this, 0, sizeof(*this)); + } + + void SetProgramIdForAtmosphere(ncm::ProgramId program_id) { + /* Right now, we mux program ID in through afsr when creport. */ + /* TODO: Better way to do this? */ + this->afsr0 = static_cast(static_cast(program_id) >> 0); + this->afsr1 = static_cast(static_cast(program_id) >> 32); + } + + ncm::ProgramId GetProgramIdForAtmosphere() const { + return ncm::ProgramId{(static_cast(this->afsr1) << 32ul) | (static_cast(this->afsr0) << 0ul)}; + } + + void SetRegisterValue(RegisterName name, RegisterType value) { + this->registers[name] = value; + this->register_set_flags |= (RegisterType(1) << name); + } + + bool HasRegisterValue(RegisterName name) const { + return this->register_set_flags & (RegisterType(1) << name); + } + + void SetBaseAddress(RegisterType base_addr) { + this->base_address = base_addr; + } + }; + + } + + struct CpuContext : sf::LargeData, sf::PrefersMapAliasTransferMode { + enum Architecture { + Architecture_Aarch64 = 0, + Architecture_Aarch32 = 1, + }; + + union { + aarch64::CpuContext aarch64_ctx; + aarch32::CpuContext aarch32_ctx; + }; + + Architecture architecture; + u32 type; + + void ClearState() { + std::memset(this, 0, sizeof(*this)); + } + }; + + static_assert(std::is_pod::value && sizeof(aarch64::CpuContext) == 0x248, "aarch64::CpuContext definition!"); + static_assert(std::is_pod::value && sizeof(aarch32::CpuContext) == 0xE0, "aarch32::CpuContext definition!"); + static_assert(std::is_pod::value && sizeof(CpuContext) == 0x250, "CpuContext definition!"); + + namespace srv { + + struct ThrowContext { + Result result; + ncm::ProgramId program_id; + char proc_name[0xD]; + bool is_creport; + CpuContext cpu_ctx; + bool generate_error_report; + Event erpt_event; + Event battery_event; + size_t stack_dump_size; + u8 stack_dump[0x100]; + + void ClearState() { + this->result = ResultSuccess(); + this->program_id = ncm::ProgramId::Invalid; + std::memset(this->proc_name, 0, sizeof(this->proc_name)); + this->is_creport = false; + std::memset(&this->cpu_ctx, 0, sizeof(this->cpu_ctx)); + this->generate_error_report = false; + std::memset(&this->erpt_event, 0, sizeof(this->erpt_event)); + std::memset(&this->battery_event, 0, sizeof(this->battery_event)); + this->stack_dump_size = 0; + std::memset(this->stack_dump, 0, sizeof(this->stack_dump)); + } + }; + + } + +} diff --git a/libraries/libstratosphere/include/stratosphere/fs.hpp b/libraries/libstratosphere/include/stratosphere/fs.hpp new file mode 100644 index 000000000..2e417f1a4 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fs.hpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "fs/fs_common.hpp" +#include "fs/fsa/fs_ifile.hpp" +#include "fs/fsa/fs_idirectory.hpp" +#include "fs/fsa/fs_ifilesystem.hpp" +#include "fs/fs_remote_filesystem.hpp" +#include "fs/fs_istorage.hpp" +#include "fs/fs_remote_storage.hpp" +#include "fs/fs_file_storage.hpp" +#include "fs/fs_query_range.hpp" +#include "fs/fs_path_tool.hpp" +#include "fs/fs_path_utils.hpp" diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_common.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_common.hpp new file mode 100644 index 000000000..6869939a9 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_common.hpp @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include "../os.hpp" +#include "../ncm.hpp" +#include "../sf.hpp" + +namespace ams::fs { + + /* TODO: Better place for this? */ + constexpr inline size_t MountNameLengthMax = 15; + +} diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_directory.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_directory.hpp new file mode 100644 index 000000000..723f0c9f9 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_directory.hpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "fs_common.hpp" + +namespace ams::fs { + + constexpr inline size_t EntryNameLengthMax = 0x300; + + using DirectoryEntry = ::FsDirectoryEntry; + +} diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_file.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_file.hpp new file mode 100644 index 000000000..f7872f512 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_file.hpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "fs_common.hpp" + +namespace ams::fs { + + struct ReadOption { + u32 value; + + static const ReadOption None; + }; + + inline constexpr const ReadOption ReadOption::None = {FsReadOption_None}; + + inline constexpr bool operator==(const ReadOption &lhs, const ReadOption &rhs) { + return lhs.value == rhs.value; + } + + inline constexpr bool operator!=(const ReadOption &lhs, const ReadOption &rhs) { + return !(lhs == rhs); + } + + static_assert(std::is_pod::value && sizeof(ReadOption) == sizeof(u32)); + + struct WriteOption { + u32 value; + + constexpr inline bool HasFlushFlag() const { + return this->value & FsWriteOption_Flush; + } + + static const WriteOption None; + static const WriteOption Flush; + }; + + inline constexpr const WriteOption WriteOption::None = {FsWriteOption_None}; + inline constexpr const WriteOption WriteOption::Flush = {FsWriteOption_Flush}; + + inline constexpr bool operator==(const WriteOption &lhs, const WriteOption &rhs) { + return lhs.value == rhs.value; + } + + inline constexpr bool operator!=(const WriteOption &lhs, const WriteOption &rhs) { + return !(lhs == rhs); + } + + static_assert(std::is_pod::value && sizeof(WriteOption) == sizeof(u32)); + +} diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_file_storage.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_file_storage.hpp new file mode 100644 index 000000000..892d3d3b4 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_file_storage.hpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "fs_common.hpp" +#include "fs_istorage.hpp" +#include "fsa/fs_ifile.hpp" + +namespace ams::fs { + + class FileStorage : public IStorage { + private: + static constexpr s64 InvalidSize = -1; + private: + std::unique_ptr unique_file; + std::shared_ptr shared_file; + fsa::IFile *base_file; + s64 size; + public: + FileStorage(fsa::IFile *f) : unique_file(f), size(InvalidSize) { + this->base_file = this->unique_file.get(); + } + + FileStorage(std::unique_ptr f) : unique_file(std::move(f)), size(InvalidSize) { + this->base_file = this->unique_file.get(); + } + + FileStorage(std::shared_ptr f) : shared_file(f), size(InvalidSize) { + this->base_file = this->shared_file.get(); + } + + virtual ~FileStorage() { /* ... */ } + protected: + Result UpdateSize(); + public: + virtual Result Read(s64 offset, void *buffer, size_t size) override; + virtual Result Write(s64 offset, const void *buffer, size_t size) override; + virtual Result Flush() override; + virtual Result GetSize(s64 *out_size) override; + virtual Result SetSize(s64 size) override; + virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override; + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_filesystem.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_filesystem.hpp new file mode 100644 index 000000000..e905d3743 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_filesystem.hpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "fs_common.hpp" + +namespace ams::fs { + + enum OpenMode { + OpenMode_Read = ::FsOpenMode_Read, + OpenMode_Write = ::FsOpenMode_Write, + OpenMode_Append = ::FsOpenMode_Append, + + OpenMode_ReadWrite = (OpenMode_Read | OpenMode_Write), + OpenMode_All = (OpenMode_ReadWrite | OpenMode_Append), + }; + + enum OpenDirectoryMode { + OpenDirectoryMode_Directory = ::FsDirOpenMode_ReadDirs, + OpenDirectoryMode_File = ::FsDirOpenMode_ReadFiles, + + OpenDirectoryMode_All = (OpenDirectoryMode_Directory | OpenDirectoryMode_File), + + /* TODO: Separate enum, like N? */ + OpenDirectoryMode_NotRequireFileSize = ::FsDirOpenMode_NoFileSize, + }; + + enum DirectoryEntryType { + DirectoryEntryType_Directory = ::FsDirEntryType_Dir, + DirectoryEntryType_File = ::FsDirEntryType_File, + }; + + enum CreateOption { + CreateOption_None = 0, + CreateOption_BigFile = ::FsCreateOption_BigFile, + }; + + using FileTimeStampRaw = ::FsTimeStampRaw; + +} diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_istorage.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_istorage.hpp new file mode 100644 index 000000000..8a462582f --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_istorage.hpp @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "fs_common.hpp" +#include "fs_file.hpp" +#include "fs_operate_range.hpp" + +namespace ams::fs { + + class IStorage { + public: + virtual ~IStorage() { /* ... */ } + + virtual Result Read(s64 offset, void *buffer, size_t size) = 0; + + virtual Result Write(s64 offset, const void *buffer, size_t size) { + return fs::ResultUnsupportedOperation(); + } + + virtual Result Flush() = 0; + + virtual Result SetSize(s64 size) { + return fs::ResultUnsupportedOperation(); + } + + virtual Result GetSize(s64 *out) = 0; + + virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) { + return fs::ResultUnsupportedOperation(); + } + + virtual Result OperateRange(OperationId op_id, s64 offset, s64 size) { + return this->OperateRange(nullptr, 0, op_id, offset, size, nullptr, 0); + } + public: + static inline bool IsRangeValid(s64 offset, s64 size, s64 total_size) { + return offset >= 0 && + size >= 0 && + size <= total_size && + offset <= (total_size - size); + } + + static inline bool IsRangeValid(s64 offset, size_t size, s64 total_size) { + return IsRangeValid(offset, static_cast(size), total_size); + } + + static inline bool IsOffsetAndSizeValid(s64 offset, s64 size) { + return offset >= 0 && + size >= 0 && + offset <= (offset + size); + } + + static inline bool IsOffsetAndSizeValid(s64 offset, size_t size) { + return IsOffsetAndSizeValid(offset, static_cast(size)); + } + }; + + class ReadOnlyStorageAdapter : public IStorage { + private: + std::shared_ptr shared_storage; + std::unique_ptr unique_storage; + IStorage *storage; + public: + ReadOnlyStorageAdapter(IStorage *s) : unique_storage(s) { + this->storage = this->unique_storage.get(); + } + ReadOnlyStorageAdapter(std::shared_ptr s) : shared_storage(s) { + this->storage = this->shared_storage.get(); + } + ReadOnlyStorageAdapter(std::unique_ptr s) : unique_storage(std::move(s)) { + this->storage = this->unique_storage.get(); + } + + virtual ~ReadOnlyStorageAdapter() { /* ... */ } + public: + virtual Result Read(s64 offset, void *buffer, size_t size) { + return this->storage->Read(offset, buffer, size); + } + + virtual Result Flush() { + return this->storage->Flush(); + } + + virtual Result GetSize(s64 *out) { + return this->storage->GetSize(out); + } + + virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override { + return this->storage->OperateRange(dst, dst_size, op_id, offset, size, src, src_size); + } + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_operate_range.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_operate_range.hpp new file mode 100644 index 000000000..3896da2e2 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_operate_range.hpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "fs_common.hpp" + +namespace ams::fs { + + enum class OperationId : u64 { + Clear = ::FsOperationId_Clear, + ClearSignature = ::FsOperationId_ClearSignature, + InvalidateCache = ::FsOperationId_InvalidateCache, + QueryRange = ::FsOperationId_QueryRange, + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_path_tool.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_path_tool.hpp new file mode 100644 index 000000000..3143ca65d --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_path_tool.hpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "fs_common.hpp" +#include "../fssrv/fssrv_sf_path.hpp" + +namespace ams::fs { + + namespace StringTraits { + + constexpr inline char DirectorySeparator = '/'; + constexpr inline char DriveSeparator = ':'; + constexpr inline char Dot = '.'; + constexpr inline char NullTerminator = '\x00'; + + } + + class PathTool { + public: + static constexpr const char RootPath[] = "/"; + public: + static constexpr inline bool IsSeparator(char c) { + return c == StringTraits::DirectorySeparator; + } + + static constexpr inline bool IsNullTerminator(char c) { + return c == StringTraits::NullTerminator; + } + + static constexpr inline bool IsDot(char c) { + return c == StringTraits::Dot; + } + + static constexpr inline bool IsWindowsDriveCharacter(char c) { + return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); + } + + static constexpr inline bool IsDriveSeparator(char c) { + return c == StringTraits::DriveSeparator; + } + + static constexpr inline bool IsWindowsAbsolutePath(const char *p) { + return IsWindowsDriveCharacter(p[0]) && IsDriveSeparator(p[1]); + } + + static constexpr inline bool IsCurrentDirectory(const char *p) { + return IsDot(p[0]) && (IsSeparator(p[1]) || IsNullTerminator(p[1])); + } + + static constexpr inline bool IsParentDirectory(const char *p) { + return IsDot(p[0]) && IsDot(p[1]) && (IsSeparator(p[2]) || IsNullTerminator(p[2])); + } + + static Result Normalize(char *out, size_t *out_len, const char *src, size_t max_out_size, bool unc_preserved = false); + static Result IsNormalized(bool *out, const char *path); + + static bool IsSubPath(const char *lhs, const char *rhs); + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_path_utils.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_path_utils.hpp new file mode 100644 index 000000000..f4598eb9d --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_path_utils.hpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "fs_common.hpp" +#include "../fssrv/fssrv_sf_path.hpp" + +namespace ams::fs { + + inline void Replace(char *dst, size_t dst_size, char old_char, char new_char) { + for (char *cur = dst; cur < dst + dst_size && *cur != '\x00'; cur++) { + if (*cur == old_char) { + *cur = new_char; + } + } + } + + inline Result FspPathPrintf(fssrv::sf::FspPath *dst, const char *format, ...) { + /* Format the path. */ + std::va_list va_list; + va_start(va_list, format); + const size_t len = std::vsnprintf(dst->str, sizeof(dst->str), format, va_list); + va_end(va_list); + + /* Validate length. */ + R_UNLESS(len < sizeof(dst->str), fs::ResultTooLongPath()); + + /* Fix slashes. */ + Replace(dst->str, sizeof(dst->str) - 1, '\\', '/'); + + return ResultSuccess(); + } + + Result VerifyPath(const char *path, size_t max_path_len, size_t max_name_len); + +} diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_query_range.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_query_range.hpp new file mode 100644 index 000000000..9bab0e67d --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_query_range.hpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "fs_common.hpp" + +namespace ams::fs { + + struct QueryRangeInfo { + u32 aes_ctr_key_type; + u32 speed_emulation_type; + u32 reserved[0x38 / sizeof(u32)]; + + void Clear() { + this->aes_ctr_key_type = 0; + this->speed_emulation_type = 0; + std::memset(this->reserved, 0, sizeof(this->reserved)); + } + + void Merge(const QueryRangeInfo &rhs) { + this->aes_ctr_key_type |= rhs.aes_ctr_key_type; + this->speed_emulation_type |= rhs.speed_emulation_type; + } + }; + + static_assert(std::is_pod::value); + static_assert(sizeof(QueryRangeInfo) == 0x40); + static_assert(sizeof(QueryRangeInfo) == sizeof(::FsRangeInfo)); + + using FileQueryRangeInfo = QueryRangeInfo; + using StorageQueryRangeInfo = QueryRangeInfo; + +} diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_remote_filesystem.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_remote_filesystem.hpp new file mode 100644 index 000000000..c5b2942f9 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_remote_filesystem.hpp @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "fs_common.hpp" +#include "fsa/fs_ifile.hpp" +#include "fsa/fs_idirectory.hpp" +#include "fsa/fs_ifilesystem.hpp" + +namespace ams::fs { + + class RemoteFile : public fsa::IFile { + private: + std::unique_ptr<::FsFile> base_file; + public: + RemoteFile(::FsFile *f) : base_file(f) { /* ... */ } + RemoteFile(std::unique_ptr<::FsFile> f) : base_file(std::move(f)) { /* ... */ } + RemoteFile(::FsFile f) { + this->base_file = std::make_unique<::FsFile>(f); + } + + virtual ~RemoteFile() { fsFileClose(this->base_file.get()); } + public: + virtual Result ReadImpl(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) override final { + return fsFileRead(this->base_file.get(), offset, buffer, size, option.value, out); + } + + virtual Result GetSizeImpl(s64 *out) override final { + return fsFileGetSize(this->base_file.get(), out); + } + + virtual Result FlushImpl() override final { + return fsFileFlush(this->base_file.get()); + } + + virtual Result WriteImpl(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) override final { + return fsFileWrite(this->base_file.get(), offset, buffer, size, option.value); + } + + virtual Result SetSizeImpl(s64 size) override final { + return fsFileSetSize(this->base_file.get(), size); + } + + virtual Result OperateRangeImpl(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override final { + /* TODO: How should this be handled? */ + return fs::ResultNotImplemented(); + } + public: + virtual sf::cmif::DomainObjectId GetDomainObjectId() const override { + return sf::cmif::DomainObjectId{serviceGetObjectId(&this->base_file->s)}; + } + }; + + class RemoteDirectory : public fsa::IDirectory { + private: + std::unique_ptr<::FsDir> base_dir; + public: + RemoteDirectory(::FsDir *d) : base_dir(d) { /* ... */ } + RemoteDirectory(std::unique_ptr<::FsDir> d) : base_dir(std::move(d)) { /* ... */ } + RemoteDirectory(::FsDir d) { + this->base_dir = std::make_unique<::FsDir>(d); + } + + virtual ~RemoteDirectory() { fsDirClose(this->base_dir.get()); } + public: + virtual Result ReadImpl(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries) override final { + return fsDirRead(this->base_dir.get(), out_count, max_entries, out_entries); + } + + virtual Result GetEntryCountImpl(s64 *out) override final { + return fsDirGetEntryCount(this->base_dir.get(), out); + } + public: + virtual sf::cmif::DomainObjectId GetDomainObjectId() const override { + return sf::cmif::DomainObjectId{serviceGetObjectId(&this->base_dir->s)}; + } + }; + + class RemoteFileSystem : public fsa::IFileSystem { + private: + std::unique_ptr<::FsFileSystem> base_fs; + public: + RemoteFileSystem(::FsFileSystem *fs) : base_fs(fs) { /* ... */ } + RemoteFileSystem(std::unique_ptr<::FsFileSystem> fs) : base_fs(std::move(fs)) { /* ... */ } + RemoteFileSystem(::FsFileSystem fs) { + this->base_fs = std::make_unique<::FsFileSystem>(fs); + } + + virtual ~RemoteFileSystem() { fsFsClose(this->base_fs.get()); } + public: + virtual Result CreateFileImpl(const char *path, s64 size, int flags) override final { + return fsFsCreateFile(this->base_fs.get(), path, size, flags); + } + + virtual Result DeleteFileImpl(const char *path) override final { + return fsFsDeleteFile(this->base_fs.get(), path); + } + + virtual Result CreateDirectoryImpl(const char *path) override final { + return fsFsCreateDirectory(this->base_fs.get(), path); + } + + virtual Result DeleteDirectoryImpl(const char *path) override final { + return fsFsDeleteDirectory(this->base_fs.get(), path); + } + + virtual Result DeleteDirectoryRecursivelyImpl(const char *path) override final { + return fsFsDeleteDirectoryRecursively(this->base_fs.get(), path); + } + + virtual Result RenameFileImpl(const char *old_path, const char *new_path) override final { + return fsFsRenameFile(this->base_fs.get(), old_path, new_path); + } + + virtual Result RenameDirectoryImpl(const char *old_path, const char *new_path) override final { + return fsFsRenameDirectory(this->base_fs.get(), old_path, new_path); + } + + virtual Result GetEntryTypeImpl(DirectoryEntryType *out, const char *path) override final { + static_assert(sizeof(::FsDirEntryType) == sizeof(DirectoryEntryType)); + return fsFsGetEntryType(this->base_fs.get(), path, reinterpret_cast<::FsDirEntryType *>(out)); + } + + virtual Result OpenFileImpl(std::unique_ptr *out_file, const char *path, OpenMode mode) override final { + FsFile f; + R_TRY(fsFsOpenFile(this->base_fs.get(), path, mode, &f)); + + *out_file = std::make_unique(f); + return ResultSuccess(); + } + + virtual Result OpenDirectoryImpl(std::unique_ptr *out_dir, const char *path, OpenDirectoryMode mode) override final { + FsDir d; + R_TRY(fsFsOpenDirectory(this->base_fs.get(), path, mode, &d)); + + *out_dir = std::make_unique(d); + return ResultSuccess(); + } + + virtual Result CommitImpl() override final { + return fsFsCommit(this->base_fs.get()); + } + + + virtual Result GetFreeSpaceSizeImpl(s64 *out, const char *path) { + return fsFsGetFreeSpace(this->base_fs.get(), path, out); + } + + virtual Result GetTotalSpaceSizeImpl(s64 *out, const char *path) { + return fsFsGetTotalSpace(this->base_fs.get(), path, out); + } + + virtual Result CleanDirectoryRecursivelyImpl(const char *path) { + return fsFsCleanDirectoryRecursively(this->base_fs.get(), path); + } + + virtual Result GetFileTimeStampRawImpl(FileTimeStampRaw *out, const char *path) { + static_assert(sizeof(FileTimeStampRaw) == sizeof(::FsTimeStampRaw)); + return fsFsGetFileTimeStampRaw(this->base_fs.get(), path, reinterpret_cast<::FsTimeStampRaw *>(out)); + } + + virtual Result QueryEntryImpl(char *dst, size_t dst_size, const char *src, size_t src_size, fsa::QueryId query, const char *path) { + return fsFsQueryEntry(this->base_fs.get(), dst, dst_size, src, src_size, path, static_cast(query)); + } + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_remote_storage.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_remote_storage.hpp new file mode 100644 index 000000000..2eb580f93 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_remote_storage.hpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "fs_common.hpp" +#include "fs_istorage.hpp" + +namespace ams::fs { + + class RemoteStorage : public IStorage { + private: + std::unique_ptr<::FsStorage> base_storage; + public: + RemoteStorage(::FsStorage *s) : base_storage(s) { /* ... */ } + RemoteStorage(std::unique_ptr<::FsStorage> s) : base_storage(std::move(s)) { /* ... */ } + RemoteStorage(::FsStorage s) { + this->base_storage = std::make_unique<::FsStorage>(s); + } + + virtual ~RemoteStorage() { fsStorageClose(this->base_storage.get()); } + public: + virtual Result Read(s64 offset, void *buffer, size_t size) override { + return fsStorageRead(this->base_storage.get(), offset, buffer, size); + }; + + virtual Result Write(s64 offset, const void *buffer, size_t size) override { + return fsStorageWrite(this->base_storage.get(), offset, buffer, size); + }; + + virtual Result Flush() override { + return fsStorageFlush(this->base_storage.get()); + }; + + virtual Result GetSize(s64 *out_size) override { + return fsStorageGetSize(this->base_storage.get(), out_size); + }; + + virtual Result SetSize(s64 size) override { + return fsStorageSetSize(this->base_storage.get(), size); + }; + + virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override { + /* TODO: How to deal with this? */ + return fs::ResultUnsupportedOperation(); + }; + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_idirectory.hpp b/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_idirectory.hpp new file mode 100644 index 000000000..335d7717f --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_idirectory.hpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "../fs_common.hpp" +#include "../fs_directory.hpp" + +namespace ams::fs::fsa { + + class IDirectory { + public: + virtual ~IDirectory() { /* ... */ } + + Result Read(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries) { + R_UNLESS(out_count != nullptr, fs::ResultNullptrArgument()); + if (max_entries == 0) { + *out_count = 0; + return ResultSuccess(); + } + R_UNLESS(out_entries != nullptr, fs::ResultNullptrArgument()); + R_UNLESS(max_entries > 0, fs::ResultInvalidArgument()); + return this->ReadImpl(out_count, out_entries, max_entries); + } + + Result GetEntryCount(s64 *out) { + R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); + return this->GetEntryCountImpl(out); + } + public: + /* TODO: This is a hack to allow the mitm API to work. Find a better way? */ + virtual sf::cmif::DomainObjectId GetDomainObjectId() const = 0; + protected: + /* ...? */ + private: + virtual Result ReadImpl(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries) = 0; + virtual Result GetEntryCountImpl(s64 *out) = 0; + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_ifile.hpp b/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_ifile.hpp new file mode 100644 index 000000000..3cafb2769 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_ifile.hpp @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "../fs_common.hpp" +#include "../fs_file.hpp" +#include "../fs_operate_range.hpp" + +namespace ams::fs::fsa { + + class IFile { + public: + virtual ~IFile() { /* ... */ } + + Result Read(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) { + R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); + if (size == 0) { + *out = 0; + return ResultSuccess(); + } + R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); + R_UNLESS(offset >= 0, fs::ResultOutOfRange()); + const s64 signed_size = static_cast(size); + R_UNLESS(signed_size >= 0, fs::ResultOutOfRange()); + R_UNLESS((std::numeric_limits::max() - offset) >= signed_size, fs::ResultOutOfRange()); + return this->ReadImpl(out, offset, buffer, size, option); + } + + Result Read(size_t *out, s64 offset, void *buffer, size_t size) { + return this->Read(out, offset, buffer, size, ReadOption::None); + } + + Result GetSize(s64 *out) { + R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); + return this->GetSizeImpl(out); + } + + Result Flush() { + return this->FlushImpl(); + } + + Result Write(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) { + if (size == 0) { + if (option.HasFlushFlag()) { + R_TRY(this->Flush()); + } + return ResultSuccess(); + } + R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); + R_UNLESS(offset >= 0, fs::ResultOutOfRange()); + const s64 signed_size = static_cast(size); + R_UNLESS(signed_size >= 0, fs::ResultOutOfRange()); + R_UNLESS((std::numeric_limits::max() - offset) >= signed_size, fs::ResultOutOfRange()); + return this->WriteImpl(offset, buffer, size, option); + } + + Result SetSize(s64 size) { + R_UNLESS(size >= 0, fs::ResultOutOfRange()); + return this->SetSizeImpl(size); + } + + Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) { + return this->OperateRangeImpl(dst, dst_size, op_id, offset, size, src, src_size); + } + + Result OperateRange(fs::OperationId op_id, s64 offset, s64 size) { + return this->OperateRangeImpl(nullptr, 0, op_id, offset, size, nullptr, 0); + } + public: + /* TODO: This is a hack to allow the mitm API to work. Find a better way? */ + virtual sf::cmif::DomainObjectId GetDomainObjectId() const = 0; + protected: + /* ...? */ + private: + virtual Result ReadImpl(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) = 0; + virtual Result GetSizeImpl(s64 *out) = 0; + virtual Result FlushImpl() = 0; + virtual Result WriteImpl(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) = 0; + virtual Result SetSizeImpl(s64 size) = 0; + virtual Result OperateRangeImpl(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) = 0; + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_ifilesystem.hpp b/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_ifilesystem.hpp new file mode 100644 index 000000000..815cc159b --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_ifilesystem.hpp @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "../fs_common.hpp" +#include "../fs_filesystem.hpp" + +namespace ams::fs::fsa { + + class IFile; + class IDirectory; + + enum class QueryId { + SetConcatenationFileAttribute = FsFileSystemQueryId_SetConcatenationFileAttribute + }; + + class IFileSystem { + public: + virtual ~IFileSystem() { /* ... */ } + + Result CreateFile(const char *path, s64 size, int option) { + R_UNLESS(path != nullptr, fs::ResultInvalidPath()); + R_UNLESS(size >= 0, fs::ResultOutOfRange()); + return this->CreateFileImpl(path, size, option); + } + + Result CreateFile(const char *path, s64 size) { + return this->CreateFile(path, size, 0); + } + + Result DeleteFile(const char *path) { + R_UNLESS(path != nullptr, fs::ResultInvalidPath()); + return this->DeleteFileImpl(path); + } + + Result CreateDirectory(const char *path) { + R_UNLESS(path != nullptr, fs::ResultInvalidPath()); + return this->CreateDirectoryImpl(path); + } + + Result DeleteDirectory(const char *path) { + R_UNLESS(path != nullptr, fs::ResultInvalidPath()); + return this->DeleteDirectoryImpl(path); + } + + Result DeleteDirectoryRecursively(const char *path) { + R_UNLESS(path != nullptr, fs::ResultInvalidPath()); + return this->DeleteDirectoryRecursivelyImpl(path); + } + + Result RenameFile(const char *old_path, const char *new_path) { + R_UNLESS(old_path != nullptr, fs::ResultInvalidPath()); + R_UNLESS(new_path != nullptr, fs::ResultInvalidPath()); + return this->RenameFileImpl(old_path, new_path); + } + + Result RenameDirectory(const char *old_path, const char *new_path) { + R_UNLESS(old_path != nullptr, fs::ResultInvalidPath()); + R_UNLESS(new_path != nullptr, fs::ResultInvalidPath()); + return this->RenameDirectoryImpl(old_path, new_path); + } + + Result GetEntryType(DirectoryEntryType *out, const char *path) { + R_UNLESS(path != nullptr, fs::ResultInvalidPath()); + R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); + return this->GetEntryTypeImpl(out, path); + } + + Result OpenFile(std::unique_ptr *out_file, const char *path, OpenMode mode) { + R_UNLESS(path != nullptr, fs::ResultInvalidPath()); + R_UNLESS(out_file != nullptr, fs::ResultNullptrArgument()); + R_UNLESS((mode & OpenMode_ReadWrite) != 0, fs::ResultInvalidArgument()); + R_UNLESS((mode & ~OpenMode_All) == 0, fs::ResultInvalidArgument()); + return this->OpenFileImpl(out_file, path, mode); + } + + Result OpenDirectory(std::unique_ptr *out_dir, const char *path, OpenDirectoryMode mode) { + R_UNLESS(path != nullptr, fs::ResultInvalidPath()); + R_UNLESS(out_dir != nullptr, fs::ResultNullptrArgument()); + R_UNLESS((mode & OpenDirectoryMode_All) != 0, fs::ResultInvalidArgument()); + R_UNLESS((mode & ~OpenDirectoryMode_All) == 0, fs::ResultInvalidArgument()); + return this->OpenDirectoryImpl(out_dir, path, mode); + } + + Result Commit() { + return this->CommitImpl(); + } + + Result GetFreeSpaceSize(s64 *out, const char *path) { + R_UNLESS(path != nullptr, fs::ResultInvalidPath()); + R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); + return this->GetFreeSpaceSizeImpl(out, path); + } + + Result GetTotalSpaceSize(s64 *out, const char *path) { + R_UNLESS(path != nullptr, fs::ResultInvalidPath()); + R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); + return this->GetTotalSpaceSizeImpl(out, path); + } + + Result CleanDirectoryRecursively(const char *path) { + R_UNLESS(path != nullptr, fs::ResultInvalidPath()); + return this->CleanDirectoryRecursivelyImpl(path); + } + + Result GetFileTimeStampRaw(FileTimeStampRaw *out, const char *path) { + R_UNLESS(path != nullptr, fs::ResultInvalidPath()); + R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); + return this->GetFileTimeStampRawImpl(out, path); + } + + Result QueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, QueryId query, const char *path) { + R_UNLESS(path != nullptr, fs::ResultInvalidPath()); + return this->QueryEntryImpl(dst, dst_size, src, src_size, query, path); + } + + /* These aren't accessible as commands. */ + + Result CommitProvisionally(s64 counter) { + return this->CommitProvisionallyImpl(counter); + } + + Result Rollback() { + return this->RollbackImpl(); + } + + Result Flush() { + return this->FlushImpl(); + } + + protected: + /* ...? */ + private: + virtual Result CreateFileImpl(const char *path, s64 size, int flags) = 0; + virtual Result DeleteFileImpl(const char *path) = 0; + virtual Result CreateDirectoryImpl(const char *path) = 0; + virtual Result DeleteDirectoryImpl(const char *path) = 0; + virtual Result DeleteDirectoryRecursivelyImpl(const char *path) = 0; + virtual Result RenameFileImpl(const char *old_path, const char *new_path) = 0; + virtual Result RenameDirectoryImpl(const char *old_path, const char *new_path) = 0; + virtual Result GetEntryTypeImpl(fs::DirectoryEntryType *out, const char *path) = 0; + virtual Result OpenFileImpl(std::unique_ptr *out_file, const char *path, fs::OpenMode mode) = 0; + virtual Result OpenDirectoryImpl(std::unique_ptr *out_dir, const char *path, fs::OpenDirectoryMode mode) = 0; + virtual Result CommitImpl() = 0; + + virtual Result GetFreeSpaceSizeImpl(s64 *out, const char *path) { + return fs::ResultNotImplemented(); + } + + virtual Result GetTotalSpaceSizeImpl(s64 *out, const char *path) { + return fs::ResultNotImplemented(); + } + + virtual Result CleanDirectoryRecursivelyImpl(const char *path) = 0; + + virtual Result GetFileTimeStampRawImpl(fs::FileTimeStampRaw *out, const char *path) { + return fs::ResultNotImplemented(); + } + + virtual Result QueryEntryImpl(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const char *path) { + return fs::ResultNotImplemented(); + } + + /* These aren't accessible as commands. */ + virtual Result CommitProvisionallyImpl(s64 counter) { + return fs::ResultNotImplemented(); + } + + virtual Result RollbackImpl() { + return fs::ResultNotImplemented(); + } + + virtual Result FlushImpl() { + return fs::ResultNotImplemented(); + } + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/fssrv.hpp b/libraries/libstratosphere/include/stratosphere/fssrv.hpp new file mode 100644 index 000000000..3f72bb4a9 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fssrv.hpp @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "fssrv/fssrv_sf_path.hpp" +#include "fssrv/fssrv_path_normalizer.hpp" diff --git a/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_interface_adapters.hpp b/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_interface_adapters.hpp new file mode 100644 index 000000000..52fbb7180 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_interface_adapters.hpp @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "interface_adapters/fssrv_storage_interface_adapter.hpp" +#include "interface_adapters/fssrv_filesystem_interface_adapter.hpp" diff --git a/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_path_normalizer.hpp b/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_path_normalizer.hpp new file mode 100644 index 000000000..3411d9611 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_path_normalizer.hpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "../fs/fs_common.hpp" + +namespace ams::fssrv { + + /* This is in fssrv::detail in official code. */ + /* TODO: Consider moving to ::impl? */ + + class PathNormalizer { + public: + enum Option : u32 { + Option_None = BIT(0), + Option_PreserveUnc = BIT(1), + Option_PreserveTailSeparator = BIT(2), + Option_HasMountName = BIT(3), + Option_AcceptEmpty = BIT(4), + }; + private: + using Buffer = std::unique_ptr; + private: + Buffer buffer; + const char *path; + Result result; + private: + static Result Normalize(const char **out_path, Buffer *out_buf, const char *path, bool preserve_unc, bool preserve_tail_sep, bool has_mount_name); + public: + explicit PathNormalizer(const char *p) : buffer(), path(nullptr), result(ResultSuccess()) { + this->result = Normalize(&this->path, &this->buffer, p, false, false, false); + } + + PathNormalizer(const char *p, u32 option) : buffer(), path(nullptr), result(ResultSuccess()) { + if ((option & Option_AcceptEmpty) && p[0] == '\x00') { + this->path = path; + } else { + const bool preserve_unc = (option & Option_PreserveUnc); + const bool preserve_tail_sep = (option & Option_PreserveTailSeparator); + const bool has_mount_name = (option & Option_HasMountName); + this->result = Normalize(&this->path, &this->buffer, p, preserve_unc, preserve_tail_sep, has_mount_name); + } + } + + inline Result GetResult() const { + return this->result; + } + + inline const char * GetPath() const { + return this->path; + } + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_sf_path.hpp b/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_sf_path.hpp new file mode 100644 index 000000000..a15c3fa55 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_sf_path.hpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "../fs/fs_common.hpp" +#include "../fs/fs_directory.hpp" +#include "../sf/sf_buffer_tags.hpp" + +namespace ams::fssrv::sf { + + struct Path : ams::sf::LargeData { + char str[fs::EntryNameLengthMax + 1]; + + static constexpr Path Encode(const char *p) { + Path path = {}; + for (size_t i = 0; i < sizeof(path) - 1; i++) { + path.str[i] = p[i]; + if (p[i] == '\x00') { + break; + } + } + return path; + } + + static constexpr size_t GetPathLength(const Path &path) { + size_t len = 0; + for (size_t i = 0; i < sizeof(path) - 1 && path.str[i] != '\x00'; i++) { + len++; + } + return len; + } + }; + + static_assert(std::is_pod::value && sizeof(Path) == FS_MAX_PATH); + + using FspPath = Path; + +} diff --git a/libraries/libstratosphere/include/stratosphere/fssrv/interface_adapters/fssrv_filesystem_interface_adapter.hpp b/libraries/libstratosphere/include/stratosphere/fssrv/interface_adapters/fssrv_filesystem_interface_adapter.hpp new file mode 100644 index 000000000..06f7b87f6 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fssrv/interface_adapters/fssrv_filesystem_interface_adapter.hpp @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "../../fs/fs_common.hpp" +#include "../../fs/fs_file.hpp" +#include "../../fs/fs_directory.hpp" +#include "../../fs/fs_filesystem.hpp" +#include "../../fs/fs_query_range.hpp" +#include "../../fssrv/fssrv_sf_path.hpp" +#include "../../fssystem/fssystem_utility.hpp" + +namespace ams::fs::fsa { + + class IFile; + class IDirectory; + class IFileSystem; + +} + +namespace ams::fssrv::impl { + + class FileSystemInterfaceAdapter; + + class FileInterfaceAdapter final : public ams::sf::IServiceObject { + NON_COPYABLE(FileInterfaceAdapter); + public: + enum class CommandId { + Read = 0, + Write = 1, + Flush = 2, + SetSize = 3, + GetSize = 4, + OperateRange = 5, + }; + private: + std::shared_ptr parent_filesystem; + std::unique_ptr base_file; + std::unique_lock open_count_semaphore; + public: + FileInterfaceAdapter(std::unique_ptr &&file, std::shared_ptr &&parent, std::unique_lock &&sema); + ~FileInterfaceAdapter(); + private: + void InvalidateCache(); + public: + /* Command API. */ + Result Read(ams::sf::Out out, s64 offset, const ams::sf::OutNonSecureBuffer &buffer, s64 size, fs::ReadOption option); + Result Write(s64 offset, const ams::sf::InNonSecureBuffer &buffer, s64 size, fs::WriteOption option); + Result Flush(); + Result SetSize(s64 size); + Result GetSize(ams::sf::Out out); + Result OperateRange(ams::sf::Out out, s32 op_id, s64 offset, s64 size); + public: + DEFINE_SERVICE_DISPATCH_TABLE { + /* 1.0.0- */ + MAKE_SERVICE_COMMAND_META(Read), + MAKE_SERVICE_COMMAND_META(Write), + MAKE_SERVICE_COMMAND_META(Flush), + MAKE_SERVICE_COMMAND_META(SetSize), + MAKE_SERVICE_COMMAND_META(GetSize), + + /* 4.0.0- */ + MAKE_SERVICE_COMMAND_META(OperateRange, hos::Version_400), + }; + }; + + class DirectoryInterfaceAdapter final : public ams::sf::IServiceObject { + NON_COPYABLE(DirectoryInterfaceAdapter); + public: + enum class CommandId { + Read = 0, + GetEntryCount = 1, + }; + private: + std::shared_ptr parent_filesystem; + std::unique_ptr base_dir; + std::unique_lock open_count_semaphore; + public: + DirectoryInterfaceAdapter(std::unique_ptr &&dir, std::shared_ptr &&parent, std::unique_lock &&sema); + ~DirectoryInterfaceAdapter(); + public: + /* Command API */ + Result Read(ams::sf::Out out, const ams::sf::OutBuffer &out_entries); + Result GetEntryCount(ams::sf::Out out); + public: + DEFINE_SERVICE_DISPATCH_TABLE { + MAKE_SERVICE_COMMAND_META(Read), + MAKE_SERVICE_COMMAND_META(GetEntryCount), + }; + }; + + class FileSystemInterfaceAdapter final : public std::enable_shared_from_this, public ams::sf::IServiceObject { + NON_COPYABLE(FileSystemInterfaceAdapter); + public: + enum class CommandId { + /* 1.0.0+ */ + CreateFile = 0, + DeleteFile = 1, + CreateDirectory = 2, + DeleteDirectory = 3, + DeleteDirectoryRecursively = 4, + RenameFile = 5, + RenameDirectory = 6, + GetEntryType = 7, + OpenFile = 8, + OpenDirectory = 9, + Commit = 10, + GetFreeSpaceSize = 11, + GetTotalSpaceSize = 12, + + /* 3.0.0+ */ + CleanDirectoryRecursively = 13, + GetFileTimeStampRaw = 14, + + /* 4.0.0+ */ + QueryEntry = 15, + }; + private: + std::shared_ptr base_fs; + std::unique_lock mount_count_semaphore; + os::ReadWriteLock invalidation_lock; + bool open_count_limited; + bool deep_retry_enabled = false; + public: + FileSystemInterfaceAdapter(std::shared_ptr &&fs, bool open_limited); + /* TODO: Other constructors. */ + + ~FileSystemInterfaceAdapter(); + public: + bool IsDeepRetryEnabled() const; + bool IsAccessFailureDetectionObserved() const; + std::optional> AcquireCacheInvalidationReadLock(); + os::ReadWriteLock &GetReadWriteLockForCacheInvalidation(); + public: + /* Command API. */ + Result CreateFile(const fssrv::sf::Path &path, s64 size, s32 option); + Result DeleteFile(const fssrv::sf::Path &path); + Result CreateDirectory(const fssrv::sf::Path &path); + Result DeleteDirectory(const fssrv::sf::Path &path); + Result DeleteDirectoryRecursively(const fssrv::sf::Path &path); + Result RenameFile(const fssrv::sf::Path &old_path, const fssrv::sf::Path &new_path); + Result RenameDirectory(const fssrv::sf::Path &old_path, const fssrv::sf::Path &new_path); + Result GetEntryType(ams::sf::Out out, const fssrv::sf::Path &path); + Result OpenFile(ams::sf::Out> out, const fssrv::sf::Path &path, u32 mode); + Result OpenDirectory(ams::sf::Out> out, const fssrv::sf::Path &path, u32 mode); + Result Commit(); + Result GetFreeSpaceSize(ams::sf::Out out, const fssrv::sf::Path &path); + Result GetTotalSpaceSize(ams::sf::Out out, const fssrv::sf::Path &path); + + Result CleanDirectoryRecursively(const fssrv::sf::Path &path); + Result GetFileTimeStampRaw(ams::sf::Out out, const fssrv::sf::Path &path); + + Result QueryEntry(const ams::sf::OutBuffer &out_buf, const ams::sf::InBuffer &in_buf, s32 query_id, const fssrv::sf::Path &path); + public: + DEFINE_SERVICE_DISPATCH_TABLE { + /* 1.0.0- */ + MAKE_SERVICE_COMMAND_META(CreateFile), + MAKE_SERVICE_COMMAND_META(DeleteFile), + MAKE_SERVICE_COMMAND_META(CreateDirectory), + MAKE_SERVICE_COMMAND_META(DeleteDirectory), + MAKE_SERVICE_COMMAND_META(DeleteDirectoryRecursively), + MAKE_SERVICE_COMMAND_META(RenameFile), + MAKE_SERVICE_COMMAND_META(RenameDirectory), + MAKE_SERVICE_COMMAND_META(GetEntryType), + MAKE_SERVICE_COMMAND_META(OpenFile), + MAKE_SERVICE_COMMAND_META(OpenDirectory), + MAKE_SERVICE_COMMAND_META(Commit), + MAKE_SERVICE_COMMAND_META(GetFreeSpaceSize), + MAKE_SERVICE_COMMAND_META(GetTotalSpaceSize), + + /* 3.0.0- */ + MAKE_SERVICE_COMMAND_META(CleanDirectoryRecursively, hos::Version_300), + MAKE_SERVICE_COMMAND_META(GetFileTimeStampRaw, hos::Version_300), + + /* 4.0.0- */ + MAKE_SERVICE_COMMAND_META(QueryEntry, hos::Version_400), + }; + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/fssrv/interface_adapters/fssrv_storage_interface_adapter.hpp b/libraries/libstratosphere/include/stratosphere/fssrv/interface_adapters/fssrv_storage_interface_adapter.hpp new file mode 100644 index 000000000..dc404085e --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fssrv/interface_adapters/fssrv_storage_interface_adapter.hpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "../../fs/fs_common.hpp" +#include "../../fs/fs_query_range.hpp" +#include "../../fssystem/fssystem_utility.hpp" + +namespace ams::fs { + + class IStorage; + +} + +namespace ams::fssrv::impl { + + class StorageInterfaceAdapter final : public ams::sf::IServiceObject { + NON_COPYABLE(StorageInterfaceAdapter); + public: + enum class CommandId { + Read = 0, + Write = 1, + Flush = 2, + SetSize = 3, + GetSize = 4, + OperateRange = 5, + }; + private: + /* TODO: Nintendo uses fssystem::AsynchronousAccessStorage here. */ + std::shared_ptr base_storage; + std::unique_lock open_count_semaphore; + os::ReadWriteLock invalidation_lock; + /* TODO: DataStorageContext. */ + bool deep_retry_enabled = false; + public: + StorageInterfaceAdapter(fs::IStorage *storage); + StorageInterfaceAdapter(std::unique_ptr storage); + explicit StorageInterfaceAdapter(std::shared_ptr &&storage); + /* TODO: Other constructors. */ + + ~StorageInterfaceAdapter(); + private: + std::optional> AcquireCacheInvalidationReadLock(); + private: + /* Command API. */ + Result Read(s64 offset, const ams::sf::OutNonSecureBuffer &buffer, s64 size); + Result Write(s64 offset, const ams::sf::InNonSecureBuffer &buffer, s64 size); + Result Flush(); + Result SetSize(s64 size); + Result GetSize(ams::sf::Out out); + Result OperateRange(ams::sf::Out out, s32 op_id, s64 offset, s64 size); + public: + DEFINE_SERVICE_DISPATCH_TABLE { + /* 1.0.0- */ + MAKE_SERVICE_COMMAND_META(Read), + MAKE_SERVICE_COMMAND_META(Write), + MAKE_SERVICE_COMMAND_META(Flush), + MAKE_SERVICE_COMMAND_META(SetSize), + MAKE_SERVICE_COMMAND_META(GetSize), + + /* 4.0.0- */ + MAKE_SERVICE_COMMAND_META(OperateRange, hos::Version_400), + }; + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/fssystem.hpp b/libraries/libstratosphere/include/stratosphere/fssystem.hpp new file mode 100644 index 000000000..d786b2e96 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fssystem.hpp @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "fssystem/fssystem_utility.hpp" +#include "fssystem/fssystem_path_tool.hpp" +#include "fssystem/fssystem_subdirectory_filesystem.hpp" +#include "fssystem/fssystem_directory_redirection_filesystem.hpp" +#include "fssystem/fssystem_directory_savedata_filesystem.hpp" diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_directory_redirection_filesystem.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_directory_redirection_filesystem.hpp new file mode 100644 index 000000000..80c1d1e36 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_directory_redirection_filesystem.hpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "impl/fssystem_path_resolution_filesystem.hpp" + +namespace ams::fssystem { + + class DirectoryRedirectionFileSystem : public impl::IPathResolutionFileSystem { + NON_COPYABLE(DirectoryRedirectionFileSystem); + private: + using PathResolutionFileSystem = impl::IPathResolutionFileSystem; + friend class impl::IPathResolutionFileSystem; + private: + char *before_dir; + size_t before_dir_len; + char *after_dir; + size_t after_dir_len; + public: + DirectoryRedirectionFileSystem(std::shared_ptr fs, const char *before, const char *after, bool unc = false); + DirectoryRedirectionFileSystem(std::unique_ptr fs, const char *before, const char *after, bool unc = false); + + virtual ~DirectoryRedirectionFileSystem(); + protected: + inline std::optional> GetAccessorLock() const { + /* No accessor lock is needed. */ + return std::nullopt; + } + private: + Result GetNormalizedDirectoryPath(char **out, size_t *out_size, const char *dir); + Result Initialize(const char *before, const char *after); + Result ResolveFullPath(char *out, size_t out_size, const char *relative_path); + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_directory_savedata_filesystem.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_directory_savedata_filesystem.hpp new file mode 100644 index 000000000..2014ea43d --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_directory_savedata_filesystem.hpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "impl/fssystem_path_resolution_filesystem.hpp" + +namespace ams::fssystem { + + class DirectorySaveDataFileSystem : public impl::IPathResolutionFileSystem { + NON_COPYABLE(DirectorySaveDataFileSystem); + private: + using PathResolutionFileSystem = impl::IPathResolutionFileSystem; + friend class impl::IPathResolutionFileSystem; + private: + os::Mutex accessor_mutex; + s32 open_writable_files; + public: + DirectorySaveDataFileSystem(std::shared_ptr fs); + DirectorySaveDataFileSystem(std::unique_ptr fs); + Result Initialize(); + + virtual ~DirectorySaveDataFileSystem(); + protected: + inline std::optional> GetAccessorLock() { + /* We have a real accessor lock that we want to use. */ + return std::make_optional>(this->accessor_mutex); + } + private: + Result AllocateWorkBuffer(std::unique_ptr *out, size_t *out_size, size_t ideal_size); + Result SynchronizeDirectory(const char *dst, const char *src); + Result ResolveFullPath(char *out, size_t out_size, const char *relative_path); + public: + void OnWritableFileClose(); + Result CopySaveFromFileSystem(fs::fsa::IFileSystem *save_fs); + public: + /* Overridden from IPathResolutionFileSystem */ + virtual Result OpenFileImpl(std::unique_ptr *out_file, const char *path, fs::OpenMode mode) override; + virtual Result CommitImpl() override; + + /* Overridden from IPathResolutionFileSystem but not commands. */ + virtual Result CommitProvisionallyImpl(s64 counter) override; + virtual Result RollbackImpl() override; + + /* Explicitly overridden to be not implemented. */ + virtual Result GetFreeSpaceSizeImpl(s64 *out, const char *path) override; + virtual Result GetTotalSpaceSizeImpl(s64 *out, const char *path) override; + virtual Result GetFileTimeStampRawImpl(fs::FileTimeStampRaw *out, const char *path) override; + virtual Result QueryEntryImpl(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const char *path) override; + virtual Result FlushImpl() override; + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_path_tool.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_path_tool.hpp new file mode 100644 index 000000000..2e50cce9b --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_path_tool.hpp @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "../fs/fs_common.hpp" +#include "../fs/fs_path_tool.hpp" + +namespace ams::fssystem { + + namespace StringTraits = ::ams::fs::StringTraits; + + using PathTool = ::ams::fs::PathTool; + +} diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_subdirectory_filesystem.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_subdirectory_filesystem.hpp new file mode 100644 index 000000000..549ceac6e --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_subdirectory_filesystem.hpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "impl/fssystem_path_resolution_filesystem.hpp" + +namespace ams::fssystem { + + class SubDirectoryFileSystem : public impl::IPathResolutionFileSystem { + NON_COPYABLE(SubDirectoryFileSystem); + private: + using PathResolutionFileSystem = impl::IPathResolutionFileSystem; + friend class impl::IPathResolutionFileSystem; + private: + char *base_path; + size_t base_path_len; + public: + SubDirectoryFileSystem(std::shared_ptr fs, const char *bp, bool unc = false); + SubDirectoryFileSystem(std::unique_ptr fs, const char *bp, bool unc = false); + + virtual ~SubDirectoryFileSystem(); + protected: + inline std::optional> GetAccessorLock() const { + /* No accessor lock is needed. */ + return std::nullopt; + } + private: + Result Initialize(const char *bp); + Result ResolveFullPath(char *out, size_t out_size, const char *relative_path); + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_utility.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_utility.hpp new file mode 100644 index 000000000..62aa3bf5d --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_utility.hpp @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "../fs/fs_common.hpp" +#include "../fs/fs_file.hpp" +#include "../fs/fs_directory.hpp" +#include "../fs/fs_filesystem.hpp" +#include "fssystem_path_tool.hpp" + +namespace ams::fssystem { + + namespace impl { + + /* Iteration. */ + template + Result IterateDirectoryRecursivelyImpl(fs::fsa::IFileSystem *fs, char *work_path, size_t work_path_size, fs::DirectoryEntry *dir_ent, OnEnterDir on_enter_dir, OnExitDir on_exit_dir, OnFile on_file) { + /* Open the directory. */ + std::unique_ptr dir; + R_TRY(fs->OpenDirectory(&dir, work_path, fs::OpenDirectoryMode_All)); + + const size_t parent_len = strnlen(work_path, work_path_size - 1); + + /* Read and handle entries. */ + while (true) { + /* Read a single entry. */ + s64 read_count = 0; + R_TRY(dir->Read(&read_count, dir_ent, 1)); + + /* If we're out of entries, we're done. */ + if (read_count == 0) { + break; + } + + /* Validate child path size. */ + const size_t child_name_len = strnlen(dir_ent->name, sizeof(dir_ent->name) - 1); + const bool is_dir = dir_ent->type == fs::DirectoryEntryType_Directory; + const size_t separator_size = is_dir ? 1 : 0; + R_UNLESS(parent_len + child_name_len + separator_size < work_path_size, fs::ResultTooLongPath()); + + /* Set child path. */ + std::strncat(work_path, dir_ent->name, work_path_size - parent_len - 1); + { + if (is_dir) { + /* Enter directory. */ + R_TRY(on_enter_dir(work_path, *dir_ent)); + + /* Append separator, recurse. */ + std::strncat(work_path, "/", work_path_size - (parent_len + child_name_len) - 1); + R_TRY(IterateDirectoryRecursivelyImpl(fs, work_path, work_path_size, dir_ent, on_enter_dir, on_exit_dir, on_file)); + + /* Exit directory. */ + R_TRY(on_exit_dir(work_path, *dir_ent)); + } else { + /* Call file handler. */ + R_TRY(on_file(work_path, *dir_ent)); + } + } + + /* Restore parent path. */ + work_path[parent_len] = StringTraits::NullTerminator; + } + + return ResultSuccess(); + } + + /* TODO: Cleanup. */ + + } + + /* Iteration API */ + template + Result IterateDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *root_path, char *work_path, size_t work_path_size, fs::DirectoryEntry *dir_ent_buf, OnEnterDir on_enter_dir, OnExitDir on_exit_dir, OnFile on_file) { + AMS_ASSERT(work_path_size >= fs::EntryNameLengthMax + 1); + + /* Get size of the root path. */ + size_t root_path_len = strnlen(root_path, fs::EntryNameLengthMax + 1); + R_UNLESS(root_path_len <= fs::EntryNameLengthMax, fs::ResultTooLongPath()); + + /* Copy root path in, add a / if necessary. */ + std::memcpy(work_path, root_path, root_path_len); + if (!PathTool::IsSeparator(work_path[root_path_len - 1])) { + work_path[root_path_len++] = StringTraits::DirectorySeparator; + } + + /* Make sure the result path is still valid. */ + R_UNLESS(root_path_len <= fs::EntryNameLengthMax, fs::ResultTooLongPath()); + work_path[root_path_len] = StringTraits::NullTerminator; + + return impl::IterateDirectoryRecursivelyImpl(fs, work_path, work_path_size, dir_ent_buf, on_enter_dir, on_exit_dir, on_file); + } + + template + Result IterateDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *root_path, OnEnterDir on_enter_dir, OnExitDir on_exit_dir, OnFile on_file) { + fs::DirectoryEntry dir_entry = {}; + char work_path[fs::EntryNameLengthMax + 1] = {}; + return IterateDirectoryRecursively(fs, root_path, work_path, sizeof(work_path), &dir_entry, on_enter_dir, on_exit_dir, on_file); + } + + template + Result IterateDirectoryRecursively(fs::fsa::IFileSystem *fs, OnEnterDir on_enter_dir, OnExitDir on_exit_dir, OnFile on_file) { + return IterateDirectoryRecursively(fs, PathTool::RootPath, on_enter_dir, on_exit_dir, on_file); + } + + /* TODO: Cleanup API */ + + /* Copy API. */ + Result CopyFile(fs::fsa::IFileSystem *dst_fs, fs::fsa::IFileSystem *src_fs, const char *dst_parent_path, const char *src_path, const fs::DirectoryEntry *dir_ent, void *work_buf, size_t work_buf_size); + NX_INLINE Result CopyFile(fs::fsa::IFileSystem *fs, const char *dst_parent_path, const char *src_path, const fs::DirectoryEntry *dir_ent, void *work_buf, size_t work_buf_size) { + return CopyFile(fs, fs, dst_parent_path, src_path, dir_ent, work_buf, work_buf_size); + } + + Result CopyDirectoryRecursively(fs::fsa::IFileSystem *dst_fs, fs::fsa::IFileSystem *src_fs, const char *dst_path, const char *src_path, void *work_buf, size_t work_buf_size); + NX_INLINE Result CopyDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *dst_path, const char *src_path, void *work_buf, size_t work_buf_size) { + return CopyDirectoryRecursively(fs, fs, dst_path, src_path, work_buf, work_buf_size); + } + + /* Semaphore adapter class. */ + class SemaphoreAdapter : public os::Semaphore { + public: + SemaphoreAdapter(int c, int mc) : os::Semaphore(c, mc) { /* ... */ } + + bool try_lock() { + return this->TryAcquire(); + } + + void unlock() { + this->Release(); + } + }; + + /* Other utility. */ + Result EnsureDirectoryExistsRecursively(fs::fsa::IFileSystem *fs, const char *path); + + template + NX_INLINE Result RetryFinitelyForTargetLocked(F f) { + /* Retry up to 10 times, 100ms between retries. */ + constexpr s32 MaxRetryCount = 10; + constexpr u64 RetryWaitTime = 100'000'000ul; + + s32 remaining_retries = MaxRetryCount; + while (true) { + R_TRY_CATCH(f()) { + R_CATCH(fs::ResultTargetLocked) { + R_UNLESS(remaining_retries > 0, fs::ResultTargetLocked()); + + remaining_retries--; + svcSleepThread(RetryWaitTime); + continue; + } + } R_END_TRY_CATCH; + + return ResultSuccess(); + } + } + +} diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/impl/fssystem_path_resolution_filesystem.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/impl/fssystem_path_resolution_filesystem.hpp new file mode 100644 index 000000000..1ba6a388d --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fssystem/impl/fssystem_path_resolution_filesystem.hpp @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "../../fs/fs_common.hpp" +#include "../../fs/fsa/fs_ifile.hpp" +#include "../../fs/fsa/fs_idirectory.hpp" +#include "../../fs/fsa/fs_ifilesystem.hpp" + +namespace ams::fssystem::impl { + + template + class IPathResolutionFileSystem : public fs::fsa::IFileSystem { + NON_COPYABLE(IPathResolutionFileSystem); + private: + std::shared_ptr shared_fs; + std::unique_ptr unique_fs; + bool unc_preserved; + protected: + fs::fsa::IFileSystem * const base_fs; + public: + IPathResolutionFileSystem(std::shared_ptr fs, bool unc = false) : shared_fs(std::move(fs)), unc_preserved(unc), base_fs(shared_fs.get()) { + /* ... */ + } + + IPathResolutionFileSystem(std::unique_ptr fs, bool unc = false) : unique_fs(std::move(fs)), unc_preserved(unc), base_fs(unique_fs.get()) { + /* ... */ + } + + virtual ~IPathResolutionFileSystem() { /* ... */ } + protected: + constexpr inline bool IsUncPreserved() const { + return this->unc_preserved; + } + public: + virtual Result CreateFileImpl(const char *path, s64 size, int option) override { + char full_path[fs::EntryNameLengthMax + 1]; + R_TRY(static_cast(this)->ResolveFullPath(full_path, sizeof(full_path), path)); + + std::optional optional_lock = static_cast(this)->GetAccessorLock(); + return this->base_fs->CreateFile(full_path, size, option); + } + + virtual Result DeleteFileImpl(const char *path) override { + char full_path[fs::EntryNameLengthMax + 1]; + R_TRY(static_cast(this)->ResolveFullPath(full_path, sizeof(full_path), path)); + + std::optional optional_lock = static_cast(this)->GetAccessorLock(); + return this->base_fs->DeleteFile(full_path); + } + + virtual Result CreateDirectoryImpl(const char *path) override { + char full_path[fs::EntryNameLengthMax + 1]; + R_TRY(static_cast(this)->ResolveFullPath(full_path, sizeof(full_path), path)); + + std::optional optional_lock = static_cast(this)->GetAccessorLock(); + return this->base_fs->CreateDirectory(full_path); + } + + virtual Result DeleteDirectoryImpl(const char *path) override { + char full_path[fs::EntryNameLengthMax + 1]; + R_TRY(static_cast(this)->ResolveFullPath(full_path, sizeof(full_path), path)); + + std::optional optional_lock = static_cast(this)->GetAccessorLock(); + return this->base_fs->DeleteDirectory(full_path); + } + + virtual Result DeleteDirectoryRecursivelyImpl(const char *path) override { + char full_path[fs::EntryNameLengthMax + 1]; + R_TRY(static_cast(this)->ResolveFullPath(full_path, sizeof(full_path), path)); + + std::optional optional_lock = static_cast(this)->GetAccessorLock(); + return this->base_fs->DeleteDirectoryRecursively(full_path); + } + + virtual Result RenameFileImpl(const char *old_path, const char *new_path) override { + char old_full_path[fs::EntryNameLengthMax + 1]; + char new_full_path[fs::EntryNameLengthMax + 1]; + R_TRY(static_cast(this)->ResolveFullPath(old_full_path, sizeof(old_full_path), old_path)); + R_TRY(static_cast(this)->ResolveFullPath(new_full_path, sizeof(new_full_path), new_path)); + + std::optional optional_lock = static_cast(this)->GetAccessorLock(); + return this->base_fs->RenameFile(old_full_path, new_full_path); + } + + virtual Result RenameDirectoryImpl(const char *old_path, const char *new_path) override { + char old_full_path[fs::EntryNameLengthMax + 1]; + char new_full_path[fs::EntryNameLengthMax + 1]; + R_TRY(static_cast(this)->ResolveFullPath(old_full_path, sizeof(old_full_path), old_path)); + R_TRY(static_cast(this)->ResolveFullPath(new_full_path, sizeof(new_full_path), new_path)); + + std::optional optional_lock = static_cast(this)->GetAccessorLock(); + return this->base_fs->RenameDirectory(old_full_path, new_full_path); + } + + virtual Result GetEntryTypeImpl(fs::DirectoryEntryType *out, const char *path) override { + char full_path[fs::EntryNameLengthMax + 1]; + R_TRY(static_cast(this)->ResolveFullPath(full_path, sizeof(full_path), path)); + + std::optional optional_lock = static_cast(this)->GetAccessorLock(); + return this->base_fs->GetEntryType(out, full_path); + } + + virtual Result OpenFileImpl(std::unique_ptr *out_file, const char *path, fs::OpenMode mode) override { + char full_path[fs::EntryNameLengthMax + 1]; + R_TRY(static_cast(this)->ResolveFullPath(full_path, sizeof(full_path), path)); + + std::optional optional_lock = static_cast(this)->GetAccessorLock(); + return this->base_fs->OpenFile(out_file, full_path, mode); + } + + virtual Result OpenDirectoryImpl(std::unique_ptr *out_dir, const char *path, fs::OpenDirectoryMode mode) override { + char full_path[fs::EntryNameLengthMax + 1]; + R_TRY(static_cast(this)->ResolveFullPath(full_path, sizeof(full_path), path)); + + std::optional optional_lock = static_cast(this)->GetAccessorLock(); + return this->base_fs->OpenDirectory(out_dir, full_path, mode); + } + + virtual Result CommitImpl() override { + std::optional optional_lock = static_cast(this)->GetAccessorLock(); + return this->base_fs->Commit(); + } + + virtual Result GetFreeSpaceSizeImpl(s64 *out, const char *path) override { + char full_path[fs::EntryNameLengthMax + 1]; + R_TRY(static_cast(this)->ResolveFullPath(full_path, sizeof(full_path), path)); + + std::optional optional_lock = static_cast(this)->GetAccessorLock(); + return this->base_fs->GetFreeSpaceSize(out, full_path); + } + + virtual Result GetTotalSpaceSizeImpl(s64 *out, const char *path) override { + char full_path[fs::EntryNameLengthMax + 1]; + R_TRY(static_cast(this)->ResolveFullPath(full_path, sizeof(full_path), path)); + + std::optional optional_lock = static_cast(this)->GetAccessorLock(); + return this->base_fs->GetTotalSpaceSize(out, full_path); + } + + virtual Result CleanDirectoryRecursivelyImpl(const char *path) override { + char full_path[fs::EntryNameLengthMax + 1]; + R_TRY(static_cast(this)->ResolveFullPath(full_path, sizeof(full_path), path)); + + std::optional optional_lock = static_cast(this)->GetAccessorLock(); + return this->base_fs->CleanDirectoryRecursively(full_path); + } + + virtual Result GetFileTimeStampRawImpl(fs::FileTimeStampRaw *out, const char *path) override { + char full_path[fs::EntryNameLengthMax + 1]; + R_TRY(static_cast(this)->ResolveFullPath(full_path, sizeof(full_path), path)); + + std::optional optional_lock = static_cast(this)->GetAccessorLock(); + return this->base_fs->GetFileTimeStampRaw(out, full_path); + } + + virtual Result QueryEntryImpl(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const char *path) override { + char full_path[fs::EntryNameLengthMax + 1]; + R_TRY(static_cast(this)->ResolveFullPath(full_path, sizeof(full_path), path)); + + std::optional optional_lock = static_cast(this)->GetAccessorLock(); + return this->base_fs->QueryEntry(dst, dst_size, src, src_size, query, full_path); + } + + /* These aren't accessible as commands. */ + virtual Result CommitProvisionallyImpl(s64 counter) override { + std::optional optional_lock = static_cast(this)->GetAccessorLock(); + return this->base_fs->CommitProvisionally(counter); + } + + virtual Result RollbackImpl() override { + std::optional optional_lock = static_cast(this)->GetAccessorLock(); + return this->base_fs->Rollback(); + } + + virtual Result FlushImpl() override { + std::optional optional_lock = static_cast(this)->GetAccessorLock(); + return this->base_fs->Flush(); + } + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/hid.hpp b/libraries/libstratosphere/include/stratosphere/hid.hpp new file mode 100644 index 000000000..6f6c15244 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/hid.hpp @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "hid/hid_api.hpp" \ No newline at end of file diff --git a/libraries/libstratosphere/include/stratosphere/hid/hid_api.hpp b/libraries/libstratosphere/include/stratosphere/hid/hid_api.hpp new file mode 100644 index 000000000..b9cb82516 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/hid/hid_api.hpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +namespace ams::hid { + + /* Key API. */ + Result GetKeysHeld(u64 *out); + +} diff --git a/libraries/libstratosphere/include/stratosphere/hos.hpp b/libraries/libstratosphere/include/stratosphere/hos.hpp new file mode 100644 index 000000000..530989193 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/hos.hpp @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "hos/hos_types.hpp" +#include "hos/hos_version_api.hpp" diff --git a/libraries/libstratosphere/include/stratosphere/hos/hos_types.hpp b/libraries/libstratosphere/include/stratosphere/hos/hos_types.hpp new file mode 100644 index 000000000..4e87b80cb --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/hos/hos_types.hpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include + +namespace ams::hos { + + enum Version : u16 { + Version_Min = 0, + Version_100 = Version_Min, + Version_200 = 1, + Version_300 = 2, + Version_400 = 3, + Version_500 = 4, + Version_600 = 5, + Version_700 = 6, + Version_800 = 7, + Version_810 = 8, + Version_900 = 9, + Version_910 = 10, + Version_Current = Version_910, + Version_Max = 32, + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/hos/hos_version_api.hpp b/libraries/libstratosphere/include/stratosphere/hos/hos_version_api.hpp new file mode 100644 index 000000000..3ccd99ac2 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/hos/hos_version_api.hpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "hos_types.hpp" + +namespace ams::hos { + + ::ams::hos::Version GetVersion(); + void SetVersionForLibnx(); + +} diff --git a/libraries/libstratosphere/include/stratosphere/kvdb.hpp b/libraries/libstratosphere/include/stratosphere/kvdb.hpp new file mode 100644 index 000000000..f600cdbe7 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/kvdb.hpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "kvdb/kvdb_auto_buffer.hpp" +#include "kvdb/kvdb_bounded_string.hpp" +#include "kvdb/kvdb_archive.hpp" +#include "kvdb/kvdb_memory_key_value_store.hpp" +#include "kvdb/kvdb_file_key_value_store.hpp" +#include "kvdb/kvdb_file_key_value_cache.hpp" diff --git a/libraries/libstratosphere/include/stratosphere/kvdb/kvdb_archive.hpp b/libraries/libstratosphere/include/stratosphere/kvdb/kvdb_archive.hpp new file mode 100644 index 000000000..b315de8cf --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/kvdb/kvdb_archive.hpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "kvdb_auto_buffer.hpp" + +namespace ams::kvdb { + + /* Functionality for parsing/generating a key value archive. */ + class ArchiveReader { + private: + AutoBuffer &buffer; + size_t offset; + public: + ArchiveReader(AutoBuffer &b) : buffer(b), offset(0) { /* ... */ } + private: + Result Peek(void *dst, size_t size); + Result Read(void *dst, size_t size); + public: + Result ReadEntryCount(size_t *out); + Result GetEntrySize(size_t *out_key_size, size_t *out_value_size); + Result ReadEntry(void *out_key, size_t key_size, void *out_value, size_t value_size); + }; + + class ArchiveWriter { + private: + AutoBuffer &buffer; + size_t offset; + public: + ArchiveWriter(AutoBuffer &b) : buffer(b), offset(0) { /* ... */ } + private: + Result Write(const void *src, size_t size); + public: + void WriteHeader(size_t entry_count); + void WriteEntry(const void *key, size_t key_size, const void *value, size_t value_size); + }; + + class ArchiveSizeHelper { + private: + size_t size; + public: + ArchiveSizeHelper(); + + void AddEntry(size_t key_size, size_t value_size); + + size_t GetSize() const { + return this->size; + } + }; + +} \ No newline at end of file diff --git a/libraries/libstratosphere/include/stratosphere/kvdb/kvdb_auto_buffer.hpp b/libraries/libstratosphere/include/stratosphere/kvdb/kvdb_auto_buffer.hpp new file mode 100644 index 000000000..e00b79d18 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/kvdb/kvdb_auto_buffer.hpp @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include + +namespace ams::kvdb { + + class AutoBuffer { + NON_COPYABLE(AutoBuffer); + private: + u8 *buffer; + size_t size; + public: + AutoBuffer() : buffer(nullptr), size(0) { /* ... */ } + + ~AutoBuffer() { + this->Reset(); + } + + AutoBuffer(AutoBuffer &&rhs) { + this->buffer = rhs.buffer; + this->size = rhs.size; + rhs.buffer = nullptr; + rhs.size = 0; + } + + AutoBuffer& operator=(AutoBuffer &&rhs) { + rhs.Swap(*this); + return *this; + } + + void Swap(AutoBuffer &rhs) { + std::swap(this->buffer, rhs.buffer); + std::swap(this->size, rhs.size); + } + + void Reset() { + if (this->buffer != nullptr) { + std::free(this->buffer); + this->buffer = nullptr; + this->size = 0; + } + } + + u8 *Get() const { + return this->buffer; + } + + size_t GetSize() const { + return this->size; + } + + Result Initialize(size_t size) { + /* Check that we're not already initialized. */ + AMS_ASSERT(this->buffer == nullptr); + + /* Allocate a buffer. */ + this->buffer = static_cast(std::malloc(size)); + if (this->buffer == nullptr) { + return ResultAllocationFailed(); + } + this->size = size; + return ResultSuccess(); + } + + Result Initialize(const void *buf, size_t size) { + /* Create a new buffer of the right size. */ + R_TRY(this->Initialize(size)); + + /* Copy the input data in. */ + std::memcpy(this->buffer, buf, size); + + return ResultSuccess(); + } + }; +} \ No newline at end of file diff --git a/libraries/libstratosphere/include/stratosphere/kvdb/kvdb_bounded_string.hpp b/libraries/libstratosphere/include/stratosphere/kvdb/kvdb_bounded_string.hpp new file mode 100644 index 000000000..aefd3de1e --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/kvdb/kvdb_bounded_string.hpp @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include + +namespace ams::kvdb { + + /* Represents a string with a backing buffer of N bytes. */ + template + class BoundedString { + static_assert(N > 0, "BoundedString requires non-zero backing buffer!"); + private: + char buffer[N]; + private: + /* Utility. */ + static inline void CheckLength(size_t len) { + AMS_ASSERT(len < N); + } + public: + /* Constructors. */ + constexpr BoundedString() { + buffer[0] = 0; + } + + explicit constexpr BoundedString(const char *s) { + this->Set(s); + } + + /* Static constructors. */ + static constexpr BoundedString Make(const char *s) { + return BoundedString(s); + } + + static constexpr BoundedString MakeFormat(const char *format, ...) __attribute__((format (printf, 1, 2))) { + BoundedString string; + + std::va_list args; + va_start(args, format); + CheckLength(std::vsnprintf(string.buffer, N, format, args)); + va_end(args); + + return string; + } + + /* Getters. */ + size_t GetLength() const { + return strnlen(this->buffer, N); + } + + const char *Get() const { + return this->buffer; + } + + operator const char *() const { + return this->buffer; + } + + /* Setters. */ + void Set(const char *s) { + /* Ensure string can fit in our buffer. */ + CheckLength(strnlen(s, N)); + std::strncpy(this->buffer, s, N); + } + + void SetFormat(const char *format, ...) __attribute__((format (printf, 2, 3))) { + /* Format into the buffer, abort if too large. */ + std::va_list args; + va_start(args, format); + CheckLength(std::vsnprintf(this->buffer, N, format, args)); + va_end(args); + } + + /* Append to existing. */ + void Append(const char *s) { + const size_t length = GetLength(); + CheckLength(length + strnlen(s, N)); + std::strncat(this->buffer, s, N - length - 1); + } + + void Append(char c) { + const size_t length = GetLength(); + CheckLength(length + 1); + this->buffer[length] = c; + this->buffer[length + 1] = 0; + } + + void AppendFormat(const char *format, ...) __attribute__((format (printf, 2, 3))) { + const size_t length = GetLength(); + std::va_list args; + va_start(args, format); + CheckLength(std::vsnprintf(this->buffer + length, N - length, format, args) + length); + va_end(args); + } + + /* Substring utilities. */ + void GetSubstring(char *dst, size_t dst_size, size_t offset, size_t length) const { + /* Make sure output buffer can hold the substring. */ + AMS_ASSERT(offset + length <= GetLength()); + AMS_ASSERT(dst_size > length); + /* Copy substring to dst. */ + std::strncpy(dst, this->buffer + offset, length); + dst[length] = 0; + } + + BoundedString GetSubstring(size_t offset, size_t length) const { + BoundedString string; + GetSubstring(string.buffer, N, offset, length); + return string; + } + + /* Comparison. */ + constexpr bool operator==(const BoundedString &rhs) const { + return std::strncmp(this->buffer, rhs.buffer, N) == 0; + } + + constexpr bool operator!=(const BoundedString &rhs) const { + return !(*this == rhs); + } + + bool EndsWith(const char *s, size_t offset) const { + return std::strncmp(this->buffer + offset, s, N - offset) == 0; + } + + bool EndsWith(const char *s) const { + const size_t suffix_length = strnlen(s, N); + const size_t length = GetLength(); + return suffix_length <= length && EndsWith(s, length - suffix_length); + } + }; + +} \ No newline at end of file diff --git a/libraries/libstratosphere/include/stratosphere/kvdb/kvdb_file_key_value_cache.hpp b/libraries/libstratosphere/include/stratosphere/kvdb/kvdb_file_key_value_cache.hpp new file mode 100644 index 000000000..d37c4710d --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/kvdb/kvdb_file_key_value_cache.hpp @@ -0,0 +1,391 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "kvdb_bounded_string.hpp" +#include "kvdb_file_key_value_store.hpp" + +namespace ams::kvdb { + + namespace impl { + + template + class LruList { + private: + /* Subtypes. */ + struct LruHeader { + u32 entry_count; + }; + public: + static constexpr size_t BufferSize = sizeof(Key) * Capacity; + static constexpr size_t FileSize = sizeof(LruHeader) + BufferSize; + using Path = FileKeyValueStore::Path; + private: + Path file_path; + Key *keys; + LruHeader header; + public: + static Result CreateNewList(const char *path) { + /* Create new lru_list.dat. */ + R_TRY(fsdevCreateFile(path, FileSize, 0)); + + /* Open the file. */ + FILE *fp = fopen(path, "r+b"); + R_UNLESS(fp != nullptr, fsdevGetLastResult()); + ON_SCOPE_EXIT { fclose(fp); }; + + /* Write new header with zero entries to the file. */ + LruHeader new_header = { .entry_count = 0, }; + R_UNLESS(fwrite(&new_header, sizeof(new_header), 1, fp) == 1, fsdevGetLastResult()); + + return ResultSuccess(); + } + private: + void RemoveIndex(size_t i) { + AMS_ASSERT(i < this->GetCount()); + std::memmove(this->keys + i, this->keys + i + 1, sizeof(*this->keys) * (this->GetCount() - (i + 1))); + this->DecrementCount(); + } + + void IncrementCount() { + this->header.entry_count++; + } + + void DecrementCount() { + this->header.entry_count--; + } + public: + LruList() : keys(nullptr), header({}) { /* ... */ } + + Result Initialize(const char *path, void *buf, size_t size) { + /* Only initialize once, and ensure we have sufficient memory. */ + AMS_ASSERT(this->keys == nullptr); + AMS_ASSERT(size >= BufferSize); + + /* Setup member variables. */ + this->keys = static_cast(buf); + this->file_path.Set(path); + std::memset(this->keys, 0, BufferSize); + + /* Open file. */ + FILE *fp = fopen(this->file_path, "rb"); + R_UNLESS(fp != nullptr, fsdevGetLastResult()); + ON_SCOPE_EXIT { fclose(fp); }; + + /* Read header. */ + R_UNLESS(fread(&this->header, sizeof(this->header), 1, fp) == 1, fsdevGetLastResult()); + + /* Read entries. */ + const size_t count = this->GetCount(); + if (count > 0) { + R_UNLESS(fread(this->keys, std::min(BufferSize, sizeof(Key) * count), 1, fp) == 1, fsdevGetLastResult()); + } + + return ResultSuccess(); + } + + Result Save() { + /* Open file. */ + FILE *fp = fopen(this->file_path, "r+b"); + R_UNLESS(fp != nullptr, fsdevGetLastResult()); + ON_SCOPE_EXIT { fclose(fp); }; + + /* Write header. */ + R_UNLESS(fwrite(&this->header, sizeof(this->header), 1, fp) == 1, fsdevGetLastResult()); + + /* Write entries. */ + R_UNLESS(fwrite(this->keys, BufferSize, 1, fp) == 1, fsdevGetLastResult()); + + /* Flush. */ + fflush(fp); + + return ResultSuccess(); + } + + size_t GetCount() const { + return this->header.entry_count; + } + + bool IsEmpty() const { + return this->GetCount() == 0; + } + + bool IsFull() const { + return this->GetCount() >= Capacity; + } + + Key Get(size_t i) const { + AMS_ASSERT(i < this->GetCount()); + return this->keys[i]; + } + + Key Peek() const { + AMS_ASSERT(!this->IsEmpty()); + return this->Get(0); + } + + void Push(const Key &key) { + AMS_ASSERT(!this->IsFull()); + this->keys[this->GetCount()] = key; + this->IncrementCount(); + } + + Key Pop() { + AMS_ASSERT(!this->IsEmpty()); + this->RemoveIndex(0); + } + + bool Remove(const Key &key) { + const size_t count = this->GetCount(); + + /* Iterate over the list, removing the last entry that matches the key. */ + for (size_t i = 0; i < count; i++) { + if (this->keys[count - 1 - i] == key) { + this->RemoveIndex(count - 1 - i); + return true; + } + } + + return false; + } + + bool Contains(const Key &key) const { + const size_t count = this->GetCount(); + + /* Iterate over the list, checking to see if we have the key. */ + for (size_t i = 0; i < count; i++) { + if (this->keys[count - 1 - i] == key) { + return true; + } + } + + return false; + } + + bool Update(const Key &key) { + if (this->Remove(key)) { + this->Push(key); + return true; + } + + return false; + } + }; + + } + + template + class FileKeyValueCache { + static_assert(std::is_pod::value, "FileKeyValueCache Key must be pod!"); + static_assert(sizeof(Key) <= FileKeyValueStore::MaxKeySize, "FileKeyValueCache Key is too big!"); + public: + using LeastRecentlyUsedList = impl::LruList; + /* Note: Nintendo code in NS uses Path = BoundedString<0x180> here. */ + /* It's unclear why, since they use 0x300 everywhere else. */ + /* We'll just use 0x300, since it shouldn't make a difference, */ + /* as FileKeyValueStore paths are limited to 0x100 anyway. */ + using Path = typename LeastRecentlyUsedList::Path; + private: + FileKeyValueStore kvs; + LeastRecentlyUsedList lru_list; + private: + static constexpr Path GetLeastRecentlyUsedListPath(const char *dir) { + return Path::MakeFormat("%s/%s", dir, "lru_list.dat"); + } + + static constexpr Path GetFileKeyValueStorePath(const char *dir) { + return Path::MakeFormat("%s/%s", dir, "kvs"); + } + + static Result Exists(bool *out, const char *path, bool is_dir) { + /* Set out to false initially. */ + *out = false; + + /* Check that the path exists, and that our entry type is correct. */ + { + struct stat st; + + if (stat(path, &st) != 0) { + R_TRY_CATCH(fsdevGetLastResult()) { + /* If the path doesn't exist, nothing has gone wrong. */ + R_CONVERT(fs::ResultPathNotFound, ResultSuccess()); + } R_END_TRY_CATCH; + } + + if (is_dir) { + R_UNLESS((S_ISDIR(st.st_mode)), ResultInvalidFilesystemState()); + } else { + R_UNLESS((S_ISREG(st.st_mode)), ResultInvalidFilesystemState()); + } + } + + *out = true; + return ResultSuccess(); + } + + static Result DirectoryExists(bool *out, const char *path) { + return Exists(out, path, true); + } + + static Result FileExists(bool *out, const char *path) { + return Exists(out, path, false); + } + public: + static Result CreateNewCache(const char *dir) { + /* Make a new key value store filesystem, and a new lru_list.dat. */ + R_TRY(LeastRecentlyUsedList::CreateNewList(GetLeastRecentlyUsedListPath(dir))); + R_UNLESS(mkdir(GetFileKeyValueStorePath(dir), 0) == 0, fsdevGetLastResult()); + + return ResultSuccess(); + } + + static Result ValidateExistingCache(const char *dir) { + /* Check for existence. */ + bool has_lru = false, has_kvs = false; + R_TRY(FileExists(&has_lru, GetLeastRecentlyUsedListPath(dir))); + R_TRY(DirectoryExists(&has_kvs, GetFileKeyValueStorePath(dir))); + + /* If neither exists, CreateNewCache was never called. */ + R_UNLESS(has_lru || has_kvs, ResultNotCreated()); + + /* If one exists but not the other, we have an invalid state. */ + R_UNLESS(has_lru && has_kvs, ResultInvalidFilesystemState()); + + return ResultSuccess(); + } + private: + void RemoveOldestKey() { + const Key &oldest_key = this->lru_list.Peek(); + this->lru_list.Pop(); + this->kvs.Remove(oldest_key); + } + public: + Result Initialize(const char *dir, void *buf, size_t size) { + /* Initialize list. */ + R_TRY(this->lru_list.Initialize(GetLeastRecentlyUsedListPath(dir), buf, size)); + + /* Initialize kvs. */ + /* NOTE: Despite creating the kvs folder and returning an error if it does not exist, */ + /* Nintendo does not use the kvs folder, and instead uses the passed dir. */ + /* This causes lru_list.dat to be in the same directory as the store's .val files */ + /* instead of in the same directory as a folder containing the store's .val files. */ + /* This is probably a Nintendo bug, but because system saves contain data in the wrong */ + /* layout it can't really be fixed without breaking existing devices... */ + R_TRY(this->kvs.Initialize(dir)); + + return ResultSuccess(); + } + + size_t GetCount() const { + return this->lru_list.GetCount(); + } + + size_t GetCapacity() const { + return Capacity; + } + + Key GetKey(size_t i) const { + return this->lru_list.Get(i); + } + + bool Contains(const Key &key) const { + return this->lru_list.Contains(key); + } + + Result Get(size_t *out_size, void *out_value, size_t max_out_size, const Key &key) { + /* Note that we accessed the key. */ + this->lru_list.Update(key); + return this->kvs.Get(out_size, out_value, max_out_size, key); + } + + template + Result Get(Value *out_value, const Key &key) { + /* Note that we accessed the key. */ + this->lru_list.Update(key); + return this->kvs.Get(out_value, key); + } + + Result GetSize(size_t *out_size, const Key &key) { + return this->kvs.GetSize(out_size, key); + } + + Result Set(const Key &key, const void *value, size_t value_size) { + if (this->lru_list.Update(key)) { + /* If an entry for the key exists, delete the existing value file. */ + this->kvs.Remove(key); + } else { + /* If the list is full, we need to remove the oldest key. */ + if (this->lru_list.IsFull()) { + this->RemoveOldestKey(); + } + + /* Add the key to the list. */ + this->lru_list.Push(key); + } + + /* Loop, trying to save the new value to disk. */ + while (true) { + /* Try to set the key. */ + R_TRY_CATCH(this->kvs.Set(key, value, value_size)) { + R_CATCH(fs::ResultNotEnoughFreeSpace) { + /* If our entry is the only thing in the Lru list, remove it. */ + if (this->lru_list.GetCount() == 1) { + this->lru_list.Pop(); + R_TRY(this->lru_list.Save()); + return fs::ResultNotEnoughFreeSpace(); + } + + /* Otherwise, remove the oldest element from the cache and try again. */ + this->RemoveOldestKey(); + continue; + } + } R_END_TRY_CATCH; + + /* If we got here, we succeeded. */ + break; + } + + /* Save the list. */ + R_TRY(this->lru_list.Save()); + + return ResultSuccess(); + } + + template + Result Set(const Key &key, const Value &value) { + return this->Set(key, &value, sizeof(Value)); + } + + Result Remove(const Key &key) { + /* Remove the key. */ + this->lru_list.Remove(key); + R_TRY(this->kvs.Remove(key)); + R_TRY(this->lru_list.Save()); + + return ResultSuccess(); + } + + Result RemoveAll() { + /* TODO: Nintendo doesn't check errors here. Should we? */ + while (!this->lru_list.IsEmpty()) { + this->RemoveOldestKey(); + } + R_TRY(this->lru_list.Save()); + + return ResultSuccess(); + } + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/kvdb/kvdb_file_key_value_store.hpp b/libraries/libstratosphere/include/stratosphere/kvdb/kvdb_file_key_value_store.hpp new file mode 100644 index 000000000..a53fca9f9 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/kvdb/kvdb_file_key_value_store.hpp @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "../os.hpp" +#include "kvdb_bounded_string.hpp" + +namespace ams::kvdb { + + class FileKeyValueStore { + NON_COPYABLE(FileKeyValueStore); + NON_MOVEABLE(FileKeyValueStore); + public: + static constexpr size_t MaxPathLength = 0x300; /* TODO: FS_MAX_PATH - 1? */ + static constexpr size_t MaxFileLength = 0xFF; + static constexpr char FileExtension[5] = ".val"; + static constexpr size_t FileExtensionLength = sizeof(FileExtension) - 1; + static constexpr size_t MaxKeySize = (MaxFileLength - FileExtensionLength) / 2; + using Path = kvdb::BoundedString; + using FileName = kvdb::BoundedString; + private: + /* Subtypes. */ + struct Entry { + u8 key[MaxKeySize]; + void *value; + size_t key_size; + size_t value_size; + }; + static_assert(std::is_pod::value, "FileKeyValueStore::Entry definition!"); + + class Cache { + private: + u8 *backing_buffer = nullptr; + size_t backing_buffer_size = 0; + size_t backing_buffer_free_offset = 0; + Entry *entries = nullptr; + size_t count = 0; + size_t capacity = 0; + private: + void *Allocate(size_t size); + + bool HasEntries() const { + return this->entries != nullptr && this->capacity != 0; + } + public: + Result Initialize(void *buffer, size_t buffer_size, size_t capacity); + void Invalidate(); + std::optional TryGet(void *out_value, size_t max_out_size, const void *key, size_t key_size); + std::optional TryGetSize(const void *key, size_t key_size); + void Set(const void *key, size_t key_size, const void *value, size_t value_size); + bool Contains(const void *key, size_t key_size); + }; + private: + os::Mutex lock; + Path dir_path; + Cache cache; + private: + Path GetPath(const void *key, size_t key_size); + Result GetKey(size_t *out_size, void *out_key, size_t max_out_size, const FileName &file_name); + public: + FileKeyValueStore() { /* ... */ } + + /* Basic accessors. */ + Result Initialize(const char *dir); + Result InitializeWithCache(const char *dir, void *cache_buffer, size_t cache_buffer_size, size_t cache_capacity); + Result Get(size_t *out_size, void *out_value, size_t max_out_size, const void *key, size_t key_size); + Result GetSize(size_t *out_size, const void *key, size_t key_size); + Result Set(const void *key, size_t key_size, const void *value, size_t value_size); + Result Remove(const void *key, size_t key_size); + + /* Niceties. */ + template + Result Get(size_t *out_size, void *out_value, size_t max_out_size, const Key &key) { + static_assert(std::is_pod::value && sizeof(Key) <= MaxKeySize, "Invalid FileKeyValueStore Key!"); + return this->Get(out_size, out_value, max_out_size, &key, sizeof(Key)); + } + + template + Result Get(Value *out_value, const Key &key) { + static_assert(std::is_pod::value && !std::is_pointer::value, "Invalid FileKeyValueStore Value!"); + size_t size = 0; + R_TRY(this->Get(&size, out_value, sizeof(Value), key)); + AMS_ASSERT(size >= sizeof(Value)); + return ResultSuccess(); + } + + template + Result GetSize(size_t *out_size, const Key &key) { + return this->GetSize(out_size, &key, sizeof(Key)); + } + + template + Result Set(const Key &key, const void *value, size_t value_size) { + static_assert(std::is_pod::value && sizeof(Key) <= MaxKeySize, "Invalid FileKeyValueStore Key!"); + return this->Set(&key, sizeof(Key), value, value_size); + } + + template + Result Set(const Key &key, const Value &value) { + static_assert(std::is_pod::value && !std::is_pointer::value, "Invalid FileKeyValueStore Value!"); + return this->Set(key, &value, sizeof(Value)); + } + + template + Result Remove(const Key &key) { + return this->Remove(&key, sizeof(Key)); + } + }; + +} \ No newline at end of file diff --git a/libraries/libstratosphere/include/stratosphere/kvdb/kvdb_memory_key_value_store.hpp b/libraries/libstratosphere/include/stratosphere/kvdb/kvdb_memory_key_value_store.hpp new file mode 100644 index 000000000..8627f3451 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/kvdb/kvdb_memory_key_value_store.hpp @@ -0,0 +1,525 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include "kvdb_auto_buffer.hpp" +#include "kvdb_archive.hpp" +#include "kvdb_bounded_string.hpp" + +namespace ams::kvdb { + + template + class MemoryKeyValueStore { + static_assert(std::is_pod::value, "KeyValueStore Keys must be pod!"); + NON_COPYABLE(MemoryKeyValueStore); + NON_MOVEABLE(MemoryKeyValueStore); + public: + /* Subtypes. */ + class Entry { + private: + Key key; + void *value; + size_t value_size; + public: + constexpr Entry(const Key &k, void *v, size_t s) : key(k), value(v), value_size(s) { /* ... */ } + + const Key &GetKey() const { + return this->key; + } + + template + Value *GetValuePointer() { + /* Size check. Note: Nintendo does not size check. */ + if constexpr (!std::is_same::value) { + AMS_ASSERT(sizeof(Value) <= this->value_size); + /* Ensure we only get pod. */ + static_assert(std::is_pod::value, "KeyValueStore Values must be pod"); + } + return reinterpret_cast(this->value); + } + + template + const Value *GetValuePointer() const { + /* Size check. Note: Nintendo does not size check. */ + if constexpr (!std::is_same::value) { + AMS_ASSERT(sizeof(Value) <= this->value_size); + /* Ensure we only get pod. */ + static_assert(std::is_pod::value, "KeyValueStore Values must be pod"); + } + return reinterpret_cast(this->value); + } + + template + Value &GetValue() { + return *(this->GetValuePointer()); + } + + template + const Value &GetValue() const { + return *(this->GetValuePointer()); + } + + size_t GetValueSize() const { + return this->value_size; + } + + constexpr inline bool operator<(const Key &rhs) const { + return key < rhs; + } + + constexpr inline bool operator==(const Key &rhs) const { + return key == rhs; + } + }; + + class Index { + private: + size_t count; + size_t capacity; + Entry *entries; + public: + Index() : count(0), capacity(0), entries(nullptr) { /* ... */ } + + ~Index() { + if (this->entries != nullptr) { + this->ResetEntries(); + std::free(this->entries); + this->entries = nullptr; + } + } + + size_t GetCount() const { + return this->count; + } + + size_t GetCapacity() const { + return this->capacity; + } + + void ResetEntries() { + for (size_t i = 0; i < this->count; i++) { + std::free(this->entries[i].GetValuePointer()); + } + this->count = 0; + } + + Result Initialize(size_t capacity) { + this->entries = reinterpret_cast(std::malloc(sizeof(Entry) * capacity)); + R_UNLESS(this->entries != nullptr, ResultAllocationFailed()); + this->capacity = capacity; + return ResultSuccess(); + } + + Result Set(const Key &key, const void *value, size_t value_size) { + /* Allocate new value. */ + void *new_value = std::malloc(value_size); + R_UNLESS(new_value != nullptr, ResultAllocationFailed()); + auto value_guard = SCOPE_GUARD { std::free(new_value); }; + std::memcpy(new_value, value, value_size); + + /* Find entry for key. */ + Entry *it = this->lower_bound(key); + if (it != this->end() && it->GetKey() == key) { + /* Entry already exists. Free old value. */ + std::free(it->GetValuePointer()); + } else { + /* We need to add a new entry. Check we have room, move future keys forward. */ + R_UNLESS(this->count < this->capacity, ResultOutOfKeyResource()); + std::memmove(it + 1, it, sizeof(*it) * (this->end() - it)); + this->count++; + } + + /* Save the new Entry in the map. */ + value_guard.Cancel(); + *it = Entry(key, new_value, value_size); + return ResultSuccess(); + } + + Result AddUnsafe(const Key &key, void *value, size_t value_size) { + R_UNLESS(this->count < this->capacity, ResultOutOfKeyResource()); + + this->entries[this->count++] = Entry(key, value, value_size); + return ResultSuccess(); + } + + Result Remove(const Key &key) { + /* Find entry for key. */ + Entry *it = this->find(key); + R_UNLESS(it != this->end(), ResultKeyNotFound()); + + /* Free the value, move entries back. */ + std::free(it->GetValuePointer()); + std::memmove(it, it + 1, sizeof(*it) * (this->end() - (it + 1))); + this->count--; + return ResultSuccess(); + } + + Entry *begin() { + return this->GetBegin(); + } + + const Entry *begin() const { + return this->GetBegin(); + } + + Entry *end() { + return this->GetEnd(); + } + + const Entry *end() const { + return this->GetEnd(); + } + + const Entry *cbegin() const { + return this->begin(); + } + + const Entry *cend() const { + return this->end(); + } + + Entry *lower_bound(const Key &key) { + return this->GetLowerBound(key); + } + + const Entry *lower_bound(const Key &key) const { + return this->GetLowerBound(key); + } + + Entry *find(const Key &key) { + return this->Find(key); + } + + const Entry *find(const Key &key) const { + return this->Find(key); + } + private: + Entry *GetBegin() { + return this->entries; + } + + const Entry *GetBegin() const { + return this->entries; + } + + Entry *GetEnd() { + return this->GetBegin() + this->count; + } + + const Entry *GetEnd() const { + return this->GetBegin() + this->count; + } + + Entry *GetLowerBound(const Key &key) { + return std::lower_bound(this->GetBegin(), this->GetEnd(), key); + } + + const Entry *GetLowerBound(const Key &key) const { + return std::lower_bound(this->GetBegin(), this->GetEnd(), key); + } + + Entry *Find(const Key &key) { + auto it = this->GetLowerBound(key); + auto end = this->GetEnd(); + if (it != end && it->GetKey() == key) { + return it; + } + return end; + } + + const Entry *Find(const Key &key) const { + auto it = this->GetLowerBound(key); + auto end = this->GetEnd(); + if (it != end && it->GetKey() == key) { + return it; + } + return end; + } + }; + private: + static constexpr size_t MaxPathLen = 0x300; /* TODO: FS_MAX_PATH - 1? */ + using Path = kvdb::BoundedString; + private: + Index index; + Path path; + Path temp_path; + public: + MemoryKeyValueStore() { /* ... */ } + + Result Initialize(const char *dir, size_t capacity) { + /* Ensure that the passed path is a directory. */ + { + struct stat st; + R_UNLESS(stat(dir, &st) == 0, fs::ResultPathNotFound()); + R_UNLESS((S_ISDIR(st.st_mode)), fs::ResultPathNotFound()); + } + + /* Set paths. */ + this->path.SetFormat("%s%s", dir, "/imkvdb.arc"); + this->temp_path.SetFormat("%s%s", dir, "/imkvdb.tmp"); + + /* Initialize our index. */ + R_TRY(this->index.Initialize(capacity)); + return ResultSuccess(); + } + + Result Initialize(size_t capacity) { + /* This initializes without an archive file. */ + /* A store initialized this way cannot have its contents loaded from or flushed to disk. */ + this->path.Set(""); + this->temp_path.Set(""); + + /* Initialize our index. */ + R_TRY(this->index.Initialize(capacity)); + return ResultSuccess(); + } + + size_t GetCount() const { + return this->index.GetCount(); + } + + size_t GetCapacity() const { + return this->index.GetCapacity(); + } + + Result Load() { + /* Reset any existing entries. */ + this->index.ResetEntries(); + + /* Try to read the archive -- note, path not found is a success condition. */ + /* This is because no archive file = no entries, so we're in the right state. */ + AutoBuffer buffer; + R_TRY_CATCH(this->ReadArchiveFile(&buffer)) { + R_CONVERT(fs::ResultPathNotFound, ResultSuccess()); + } R_END_TRY_CATCH; + + /* Parse entries from the buffer. */ + { + ArchiveReader reader(buffer); + + size_t entry_count = 0; + R_TRY(reader.ReadEntryCount(&entry_count)); + + for (size_t i = 0; i < entry_count; i++) { + /* Get size of key/value. */ + size_t key_size = 0, value_size = 0; + R_TRY(reader.GetEntrySize(&key_size, &value_size)); + + /* Allocate memory for value. */ + void *new_value = std::malloc(value_size); + R_UNLESS(new_value != nullptr, ResultAllocationFailed()); + auto value_guard = SCOPE_GUARD { std::free(new_value); }; + + /* Read key and value. */ + Key key; + R_TRY(reader.ReadEntry(&key, sizeof(key), new_value, value_size)); + R_TRY(this->index.AddUnsafe(key, new_value, value_size)); + + /* We succeeded, so cancel the value guard to prevent deallocation. */ + value_guard.Cancel(); + } + } + + return ResultSuccess(); + } + + Result Save() { + /* Create a buffer to hold the archive. */ + AutoBuffer buffer; + R_TRY(buffer.Initialize(this->GetArchiveSize())); + + /* Write the archive to the buffer. */ + { + ArchiveWriter writer(buffer); + writer.WriteHeader(this->GetCount()); + for (const auto &it : this->index) { + const auto &key = it.GetKey(); + writer.WriteEntry(&key, sizeof(Key), it.GetValuePointer(), it.GetValueSize()); + } + } + + /* Save the buffer to disk. */ + return this->Commit(buffer); + } + + Result Set(const Key &key, const void *value, size_t value_size) { + return this->index.Set(key, value, value_size); + } + + template + Result Set(const Key &key, const Value &value) { + /* Only allow setting pod. */ + static_assert(std::is_pod::value, "KeyValueStore Values must be pod"); + return this->Set(key, &value, sizeof(Value)); + } + + template + Result Set(const Key &key, const Value *value) { + /* Only allow setting pod. */ + static_assert(std::is_pod::value, "KeyValueStore Values must be pod"); + return this->Set(key, value, sizeof(Value)); + } + + Result Get(size_t *out_size, void *out_value, size_t max_out_size, const Key &key) { + /* Find entry. */ + auto it = this->find(key); + R_UNLESS(it != this->end(), ResultKeyNotFound()); + + size_t size = std::min(max_out_size, it->GetValueSize()); + std::memcpy(out_value, it->GetValuePointer(), size); + *out_size = size; + return ResultSuccess(); + } + + template + Result GetValuePointer(Value **out_value, const Key &key) { + /* Find entry. */ + auto it = this->find(key); + R_UNLESS(it != this->end(), ResultKeyNotFound()); + + *out_value = it->template GetValuePointer(); + return ResultSuccess(); + } + + template + Result GetValuePointer(const Value **out_value, const Key &key) const { + /* Find entry. */ + auto it = this->find(key); + R_UNLESS(it != this->end(), ResultKeyNotFound()); + + *out_value = it->template GetValuePointer(); + return ResultSuccess(); + } + + template + Result GetValue(Value *out_value, const Key &key) const { + /* Find entry. */ + auto it = this->find(key); + R_UNLESS(it != this->end(), ResultKeyNotFound()); + + *out_value = it->template GetValue(); + return ResultSuccess(); + } + + Result GetValueSize(size_t *out_size, const Key &key) const { + /* Find entry. */ + auto it = this->find(key); + R_UNLESS(it != this->end(), ResultKeyNotFound()); + + *out_size = it->GetValueSize(); + return ResultSuccess(); + } + + Result Remove(const Key &key) { + return this->index.Remove(key); + } + + Entry *begin() { + return this->index.begin(); + } + + const Entry *begin() const { + return this->index.begin(); + } + + Entry *end() { + return this->index.end(); + } + + const Entry *end() const { + return this->index.end(); + } + + const Entry *cbegin() const { + return this->index.cbegin(); + } + + const Entry *cend() const { + return this->index.cend(); + } + + Entry *lower_bound(const Key &key) { + return this->index.lower_bound(key); + } + + const Entry *lower_bound(const Key &key) const { + return this->index.lower_bound(key); + } + + Entry *find(const Key &key) { + return this->index.find(key); + } + + const Entry *find(const Key &key) const { + return this->index.find(key); + } + private: + Result Commit(const AutoBuffer &buffer) { + /* Try to delete temporary archive, but allow deletion failure (it may not exist). */ + std::remove(this->temp_path.Get()); + + /* Create new temporary archive. */ + R_TRY(fsdevCreateFile(this->temp_path.Get(), buffer.GetSize(), 0)); + + /* Write data to the temporary archive. */ + { + FILE *f = fopen(this->temp_path, "r+b"); + R_UNLESS(f != nullptr, fsdevGetLastResult()); + ON_SCOPE_EXIT { fclose(f); }; + + R_UNLESS(fwrite(buffer.Get(), buffer.GetSize(), 1, f) == 1, fsdevGetLastResult()); + } + + /* Try to delete the saved archive, but allow deletion failure. */ + std::remove(this->path.Get()); + + /* Rename the path. */ + R_UNLESS(std::rename(this->temp_path.Get(), this->path.Get()) == 0, fsdevGetLastResult()); + + return ResultSuccess(); + } + + size_t GetArchiveSize() const { + ArchiveSizeHelper size_helper; + + for (const auto &it : this->index) { + size_helper.AddEntry(sizeof(Key), it.GetValueSize()); + } + + return size_helper.GetSize(); + } + + Result ReadArchiveFile(AutoBuffer *dst) const { + /* Open the file. */ + FILE *f = fopen(this->path, "rb"); + R_UNLESS(f != nullptr, fsdevGetLastResult()); + ON_SCOPE_EXIT { fclose(f); }; + + /* Get the archive file size. */ + fseek(f, 0, SEEK_END); + const size_t archive_size = ftell(f); + fseek(f, 0, SEEK_SET); + + /* Make a new buffer, read the file. */ + R_TRY(dst->Initialize(archive_size)); + R_UNLESS(fread(dst->Get(), archive_size, 1, f) == 1, fsdevGetLastResult()); + + return ResultSuccess(); + } + }; + +} \ No newline at end of file diff --git a/libraries/libstratosphere/include/stratosphere/ldr.hpp b/libraries/libstratosphere/include/stratosphere/ldr.hpp new file mode 100644 index 000000000..5a4d6552f --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/ldr.hpp @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "ldr/ldr_types.hpp" +#include "ldr/ldr_pm_api.hpp" diff --git a/libraries/libstratosphere/include/stratosphere/ldr/ldr_pm_api.hpp b/libraries/libstratosphere/include/stratosphere/ldr/ldr_pm_api.hpp new file mode 100644 index 000000000..1eb6418d7 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/ldr/ldr_pm_api.hpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "ldr_types.hpp" + +namespace ams::ldr::pm { + + /* Process Manager API. */ + Result CreateProcess(Handle *out, PinId pin_id, u32 flags, Handle reslimit); + Result GetProgramInfo(ProgramInfo *out, const ncm::ProgramLocation &loc); + Result PinProgram(PinId *out, const ncm::ProgramLocation &loc); + Result UnpinProgram(PinId pin_id); + Result HasLaunchedProgram(bool *out, ncm::ProgramId program_id); + + /* Atmosphere extension API. */ + Result AtmosphereGetProgramInfo(ProgramInfo *out, cfg::OverrideStatus *out_status, const ncm::ProgramLocation &loc); + Result AtmospherePinProgram(PinId *out, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status); + +} diff --git a/libraries/libstratosphere/include/stratosphere/ldr/ldr_types.hpp b/libraries/libstratosphere/include/stratosphere/ldr/ldr_types.hpp new file mode 100644 index 000000000..6bad2790d --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/ldr/ldr_types.hpp @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include "../ncm/ncm_types.hpp" +#include "../sf/sf_buffer_tags.hpp" + +namespace ams::ldr { + + /* General types. */ + struct ProgramInfo : sf::LargeData { + u8 main_thread_priority; + u8 default_cpu_id; + u16 flags; + u32 main_thread_stack_size; + ncm::ProgramId program_id; + u32 acid_sac_size; + u32 aci_sac_size; + u32 acid_fac_size; + u32 aci_fah_size; + u8 ac_buffer[0x3E0]; + }; + static_assert(std::is_pod::value && sizeof(ProgramInfo) == 0x400, "ProgramInfo definition!"); + + enum ProgramInfoFlag { + ProgramInfoFlag_SystemModule = (0 << 0), + ProgramInfoFlag_Application = (1 << 0), + ProgramInfoFlag_Applet = (2 << 0), + ProgramInfoFlag_InvalidType = (3 << 0), + ProgramInfoFlag_ApplicationTypeMask = (3 << 0), + + ProgramInfoFlag_AllowDebug = (1 << 2), + }; + + enum CreateProcessFlag { + CreateProcessFlag_EnableDebug = (1 << 0), + CreateProcessFlag_DisableAslr = (1 << 1), + }; + + struct ProgramArguments { + u32 allocated_size; + u32 arguments_size; + u8 reserved[0x18]; + u8 arguments[]; + }; + static_assert(sizeof(ProgramArguments) == 0x20, "ProgramArguments definition!"); + + struct PinId { + u64 value; + }; + + inline bool operator==(const PinId &lhs, const PinId &rhs) { + return lhs.value == rhs.value; + } + + inline bool operator!=(const PinId &lhs, const PinId &rhs) { + return lhs.value != rhs.value; + } + static_assert(sizeof(PinId) == sizeof(u64) && std::is_pod::value, "PinId definition!"); + + /* Import ModuleInfo from libnx. */ + using ModuleInfo = ::LoaderModuleInfo; + + /* NSO types. */ + struct NsoHeader { + static constexpr u32 Magic = 0x304F534E; + enum Segment : size_t { + Segment_Text = 0, + Segment_Ro = 1, + Segment_Rw = 2, + Segment_Count, + }; + + enum Flag : u32 { + Flag_CompressedText = (1 << 0), + Flag_CompressedRo = (1 << 1), + Flag_CompressedRw = (1 << 2), + Flag_CheckHashText = (1 << 3), + Flag_CheckHashRo = (1 << 4), + Flag_CheckHashRw = (1 << 5), + }; + + struct SegmentInfo { + u32 file_offset; + u32 dst_offset; + u32 size; + u32 reserved; + }; + + u32 magic; + u32 version; + u32 reserved_08; + u32 flags; + union { + struct { + u32 text_file_offset; + u32 text_dst_offset; + u32 text_size; + u32 unk_file_offset; + u32 ro_file_offset; + u32 ro_dst_offset; + u32 ro_size; + u32 unk_size; + u32 rw_file_offset; + u32 rw_dst_offset; + u32 rw_size; + u32 bss_size; + }; + SegmentInfo segments[Segment_Count]; + }; + u8 build_id[sizeof(ModuleInfo::build_id)]; + union { + u32 compressed_sizes[Segment_Count]; + struct { + u32 text_compressed_size; + u32 ro_compressed_size; + u32 rw_compressed_size; + }; + }; + u8 reserved_6C[0x34]; + union { + u8 segment_hashes[Segment_Count][SHA256_HASH_SIZE]; + struct { + u8 text_hash[SHA256_HASH_SIZE]; + u8 ro_hash[SHA256_HASH_SIZE]; + u8 rw_hash[SHA256_HASH_SIZE]; + }; + }; + }; + static_assert(sizeof(NsoHeader) == 0x100 && std::is_pod::value, "NsoHeader definition!"); + + /* NPDM types. */ + struct Aci { + static constexpr u32 Magic = 0x30494341; + + u32 magic; + u8 reserved_04[0xC]; + ncm::ProgramId program_id; + u8 reserved_18[0x8]; + u32 fah_offset; + u32 fah_size; + u32 sac_offset; + u32 sac_size; + u32 kac_offset; + u32 kac_size; + u8 reserved_38[0x8]; + }; + static_assert(sizeof(Aci) == 0x40 && std::is_pod::value, "Aci definition!"); + + struct Acid { + static constexpr u32 Magic = 0x44494341; + + enum AcidFlag { + AcidFlag_Production = (1 << 0), + AcidFlag_UnqualifiedApproval = (1 << 1), + + AcidFlag_DeprecatedUseSecureMemory = (1 << 2), + + AcidFlag_PoolPartitionShift = 2, + AcidFlag_PoolPartitionMask = (3 << AcidFlag_PoolPartitionShift), + }; + + enum PoolPartition { + PoolPartition_Application = (svc::CreateProcessFlag_PoolPartitionApplication >> svc::CreateProcessFlag_PoolPartitionShift), + PoolPartition_Applet = (svc::CreateProcessFlag_PoolPartitionApplet >> svc::CreateProcessFlag_PoolPartitionShift), + PoolPartition_System = (svc::CreateProcessFlag_PoolPartitionSystem >> svc::CreateProcessFlag_PoolPartitionShift), + PoolPartition_SystemNonSecure = (svc::CreateProcessFlag_PoolPartitionSystemNonSecure >> svc::CreateProcessFlag_PoolPartitionShift), + }; + + u8 signature[0x100]; + u8 modulus[0x100]; + u32 magic; + u32 size; + u8 version; + u8 reserved_209[3]; + u32 flags; + ncm::ProgramId program_id_min; + ncm::ProgramId program_id_max; + u32 fac_offset; + u32 fac_size; + u32 sac_offset; + u32 sac_size; + u32 kac_offset; + u32 kac_size; + u8 reserved_238[0x8]; + }; + static_assert(sizeof(Acid) == 0x240 && std::is_pod::value, "Acid definition!"); + + struct Npdm { + static constexpr u32 Magic = 0x4154454D; + + enum MetaFlag { + MetaFlag_Is64Bit = (1 << 0), + + MetaFlag_AddressSpaceTypeShift = 1, + MetaFlag_AddressSpaceTypeMask = (7 << MetaFlag_AddressSpaceTypeShift), + + MetaFlag_OptimizeMemoryAllocation = (1 << 4), + }; + + enum AddressSpaceType { + AddressSpaceType_32Bit = (svc::CreateProcessFlag_AddressSpace32Bit >> svc::CreateProcessFlag_AddressSpaceShift), + AddressSpaceType_64BitDeprecated = (svc::CreateProcessFlag_AddressSpace64BitDeprecated >> svc::CreateProcessFlag_AddressSpaceShift), + AddressSpaceType_32BitWithoutAlias = (svc::CreateProcessFlag_AddressSpace32BitWithoutAlias >> svc::CreateProcessFlag_AddressSpaceShift), + AddressSpaceType_64Bit = (svc::CreateProcessFlag_AddressSpace64Bit >> svc::CreateProcessFlag_AddressSpaceShift), + }; + + u32 magic; + u8 reserved_04[8]; + u8 flags; + u8 reserved_0D; + u8 main_thread_priority; + u8 default_cpu_id; + u8 reserved_10[4]; + u32 system_resource_size; + u32 version; + u32 main_thread_stack_size; + char program_name[0x10]; + char product_code[0x10]; + u8 reserved_40[0x30]; + u32 aci_offset; + u32 aci_size; + u32 acid_offset; + u32 acid_size; + }; + static_assert(sizeof(Npdm) == 0x80 && std::is_pod::value, "Npdm definition!"); + +} diff --git a/libraries/libstratosphere/include/stratosphere/map.hpp b/libraries/libstratosphere/include/stratosphere/map.hpp new file mode 100644 index 000000000..3b34b2346 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/map.hpp @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "map/map_types.hpp" +#include "map/map_api.hpp" diff --git a/libraries/libstratosphere/include/stratosphere/map/map_api.hpp b/libraries/libstratosphere/include/stratosphere/map/map_api.hpp new file mode 100644 index 000000000..89f04b507 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/map/map_api.hpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "map_types.hpp" + +namespace ams::map { + + /* Public API. */ + Result GetProcessAddressSpaceInfo(AddressSpaceInfo *out, Handle process_h); + Result LocateMappableSpace(uintptr_t *out_address, size_t size); + Result MapCodeMemoryInProcess(MappedCodeMemory &out_mcm, Handle process_handle, uintptr_t base_address, size_t size); + bool CanAddGuardRegionsInProcess(Handle process_handle, uintptr_t address, size_t size); + +} diff --git a/libraries/libstratosphere/include/stratosphere/map/map_types.hpp b/libraries/libstratosphere/include/stratosphere/map/map_types.hpp new file mode 100644 index 000000000..99f4a02e5 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/map/map_types.hpp @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include + +namespace ams::map { + + /* Types. */ + struct AddressSpaceInfo { + uintptr_t heap_base; + size_t heap_size; + uintptr_t heap_end; + uintptr_t alias_base; + size_t alias_size; + uintptr_t alias_end; + uintptr_t aslr_base; + size_t aslr_size; + uintptr_t aslr_end; + }; + + static constexpr uintptr_t AslrBase32Bit = 0x0000200000ul; + static constexpr size_t AslrSize32Bit = 0x003FE00000ul; + static constexpr uintptr_t AslrBase64BitDeprecated = 0x0008000000ul; + static constexpr size_t AslrSize64BitDeprecated = 0x0078000000ul; + static constexpr uintptr_t AslrBase64Bit = 0x0008000000ul; + static constexpr size_t AslrSize64Bit = 0x7FF8000000ul; + + class AutoCloseMap { + private: + Handle process_handle; + Result result; + void *mapped_address; + uintptr_t base_address; + size_t size; + public: + AutoCloseMap(uintptr_t mp, Handle p_h, uintptr_t ba, size_t sz) : process_handle(p_h), mapped_address(reinterpret_cast(mp)), base_address(ba), size(sz) { + this->result = svcMapProcessMemory(this->mapped_address, this->process_handle, this->base_address, this->size); + } + + ~AutoCloseMap() { + if (this->process_handle != INVALID_HANDLE && R_SUCCEEDED(this->result)) { + R_ASSERT(svcUnmapProcessMemory(this->mapped_address, this->process_handle, this->base_address, this->size)); + } + } + + Result GetResult() const { + return this->result; + } + + bool IsSuccess() const { + return R_SUCCEEDED(this->result); + } + + void Invalidate() { + this->process_handle = INVALID_HANDLE; + } + }; + + class MappedCodeMemory { + private: + Handle process_handle; + Result result; + uintptr_t dst_address; + uintptr_t src_address; + size_t size; + public: + MappedCodeMemory(Result init_res) : process_handle(INVALID_HANDLE), result(init_res), dst_address(0), src_address(0), size(0) { + /* ... */ + } + + MappedCodeMemory(Handle p_h, uintptr_t dst, uintptr_t src, size_t sz) : process_handle(p_h), dst_address(dst), src_address(src), size(sz) { + this->result = svcMapProcessCodeMemory(this->process_handle, this->dst_address, this->src_address, this->size); + } + + ~MappedCodeMemory() { + if (this->process_handle != INVALID_HANDLE && R_SUCCEEDED(this->result) && this->size > 0) { + R_ASSERT(svcUnmapProcessCodeMemory(this->process_handle, this->dst_address, this->src_address, this->size)); + } + } + + uintptr_t GetDstAddress() const { + return this->dst_address; + } + + Result GetResult() const { + return this->result; + } + + bool IsSuccess() const { + return R_SUCCEEDED(this->result); + } + + void Invalidate() { + this->process_handle = INVALID_HANDLE; + } + + MappedCodeMemory &operator=(MappedCodeMemory &&o) { + this->process_handle = o.process_handle; + this->result = o.result; + this->dst_address = o.dst_address; + this->src_address = o.src_address; + this->size = o.size; + o.Invalidate(); + return *this; + } + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/ncm.hpp b/libraries/libstratosphere/include/stratosphere/ncm.hpp new file mode 100644 index 000000000..8f2d1084a --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/ncm.hpp @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "ncm/ncm_types.hpp" diff --git a/libraries/libstratosphere/include/stratosphere/ncm/ncm_types.hpp b/libraries/libstratosphere/include/stratosphere/ncm/ncm_types.hpp new file mode 100644 index 000000000..5f8af79b5 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/ncm/ncm_types.hpp @@ -0,0 +1,447 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include + +namespace ams::ncm { + + /* Storage IDs. */ + enum class StorageId : u8 { + #define DEFINE_ENUM_MEMBER(nm) nm = NcmStorageId_##nm + DEFINE_ENUM_MEMBER(None), + DEFINE_ENUM_MEMBER(Host), + DEFINE_ENUM_MEMBER(GameCard), + DEFINE_ENUM_MEMBER(BuiltInSystem), + DEFINE_ENUM_MEMBER(BuiltInUser), + DEFINE_ENUM_MEMBER(SdCard), + DEFINE_ENUM_MEMBER(Any), + #undef DEFINE_ENUM_MEMBER + }; + + /* Program IDs (Formerly: Title IDs). */ + struct ProgramId { + u64 value; + + inline explicit operator u64() const { + return this->value; + } + + /* Invalid Program ID. */ + static const ProgramId Invalid; + + /* System Modules. */ + static const ProgramId SystemStart; + + static const ProgramId Fs; + static const ProgramId Loader; + static const ProgramId Ncm; + static const ProgramId Pm; + static const ProgramId Sm; + static const ProgramId Boot; + static const ProgramId Usb; + static const ProgramId Tma; + static const ProgramId Boot2; + static const ProgramId Settings; + static const ProgramId Bus; + static const ProgramId Bluetooth; + static const ProgramId Bcat; + static const ProgramId Dmnt; + static const ProgramId Friends; + static const ProgramId Nifm; + static const ProgramId Ptm; + static const ProgramId Shell; + static const ProgramId BsdSockets; + static const ProgramId Hid; + static const ProgramId Audio; + static const ProgramId LogManager; + static const ProgramId Wlan; + static const ProgramId Cs; + static const ProgramId Ldn; + static const ProgramId NvServices; + static const ProgramId Pcv; + static const ProgramId Ppc; + static const ProgramId NvnFlinger; + static const ProgramId Pcie; + static const ProgramId Account; + static const ProgramId Ns; + static const ProgramId Nfc; + static const ProgramId Psc; + static const ProgramId CapSrv; + static const ProgramId Am; + static const ProgramId Ssl; + static const ProgramId Nim; + static const ProgramId Cec; + static const ProgramId Tspm; + static const ProgramId Spl; + static const ProgramId Lbl; + static const ProgramId Btm; + static const ProgramId Erpt; + static const ProgramId Time; + static const ProgramId Vi; + static const ProgramId Pctl; + static const ProgramId Npns; + static const ProgramId Eupld; + static const ProgramId Arp; + static const ProgramId Glue; + static const ProgramId Eclct; + static const ProgramId Es; + static const ProgramId Fatal; + static const ProgramId Grc; + static const ProgramId Creport; + static const ProgramId Ro; + static const ProgramId Profiler; + static const ProgramId Sdb; + static const ProgramId Migration; + static const ProgramId Jit; + static const ProgramId JpegDec; + static const ProgramId SafeMode; + static const ProgramId Olsc; + static const ProgramId Dt; + static const ProgramId Nd; + static const ProgramId Ngct; + + static const ProgramId SystemEnd; + + /* System Data Archives. */ + static const ProgramId ArchiveStart; + static const ProgramId ArchiveCertStore; + static const ProgramId ArchiveErrorMessage; + static const ProgramId ArchiveMiiModel; + static const ProgramId ArchiveBrowserDll; + static const ProgramId ArchiveHelp; + static const ProgramId ArchiveSharedFont; + static const ProgramId ArchiveNgWord; + static const ProgramId ArchiveSsidList; + static const ProgramId ArchiveDictionary; + static const ProgramId ArchiveSystemVersion; + static const ProgramId ArchiveAvatarImage; + static const ProgramId ArchiveLocalNews; + static const ProgramId ArchiveEula; + static const ProgramId ArchiveUrlBlackList; + static const ProgramId ArchiveTimeZoneBinar; + static const ProgramId ArchiveCertStoreCruiser; + static const ProgramId ArchiveFontNintendoExtension; + static const ProgramId ArchiveFontStandard; + static const ProgramId ArchiveFontKorean; + static const ProgramId ArchiveFontChineseTraditional; + static const ProgramId ArchiveFontChineseSimple; + static const ProgramId ArchiveFontBfcpx; + static const ProgramId ArchiveSystemUpdate; + + static const ProgramId ArchiveFirmwareDebugSettings; + static const ProgramId ArchiveBootImagePackage; + static const ProgramId ArchiveBootImagePackageSafe; + static const ProgramId ArchiveBootImagePackageExFat; + static const ProgramId ArchiveBootImagePackageExFatSafe; + static const ProgramId ArchiveFatalMessage; + static const ProgramId ArchiveControllerIcon; + static const ProgramId ArchivePlatformConfigIcosa; + static const ProgramId ArchivePlatformConfigCopper; + static const ProgramId ArchivePlatformConfigHoag; + static const ProgramId ArchiveControllerFirmware; + static const ProgramId ArchiveNgWord2; + static const ProgramId ArchivePlatformConfigIcosaMariko; + static const ProgramId ArchiveApplicationBlackList; + static const ProgramId ArchiveRebootlessSystemUpdateVersion; + static const ProgramId ArchiveContentActionTable; + + static const ProgramId ArchiveEnd; + + /* System Applets. */ + static const ProgramId AppletStart; + + static const ProgramId AppletQlaunch; + static const ProgramId AppletAuth; + static const ProgramId AppletCabinet; + static const ProgramId AppletController; + static const ProgramId AppletDataErase; + static const ProgramId AppletError; + static const ProgramId AppletNetConnect; + static const ProgramId AppletPlayerSelect; + static const ProgramId AppletSwkbd; + static const ProgramId AppletMiiEdit; + static const ProgramId AppletWeb; + static const ProgramId AppletShop; + static const ProgramId AppletOverlayDisp; + static const ProgramId AppletPhotoViewer; + static const ProgramId AppletSet; + static const ProgramId AppletOfflineWeb; + static const ProgramId AppletLoginShare; + static const ProgramId AppletWifiWebAuth; + static const ProgramId AppletStarter; + static const ProgramId AppletMyPage; + static const ProgramId AppletPlayReport; + static const ProgramId AppletMaintenanceMenu; + + static const ProgramId AppletGift; + static const ProgramId AppletDummyShop; + static const ProgramId AppletUserMigration; + static const ProgramId AppletEncounter; + + static const ProgramId AppletStory; + + static const ProgramId AppletEnd; + + /* Debug Applets. */ + + /* Debug Modules. */ + + /* Factory Setup. */ + + /* Applications. */ + static const ProgramId ApplicationStart; + static const ProgramId ApplicationEnd; + + /* Atmosphere Extensions. */ + static const ProgramId AtmosphereMitm; + }; + + /* Invalid Program ID. */ + inline constexpr const ProgramId ProgramId::Invalid = {}; + + inline constexpr const ProgramId InvalidProgramId = ProgramId::Invalid; + + /* System Modules. */ + inline constexpr const ProgramId ProgramId::SystemStart = { 0x0100000000000000ul }; + + inline constexpr const ProgramId ProgramId::Fs = { 0x0100000000000000ul }; + inline constexpr const ProgramId ProgramId::Loader = { 0x0100000000000001ul }; + inline constexpr const ProgramId ProgramId::Ncm = { 0x0100000000000002ul }; + inline constexpr const ProgramId ProgramId::Pm = { 0x0100000000000003ul }; + inline constexpr const ProgramId ProgramId::Sm = { 0x0100000000000004ul }; + inline constexpr const ProgramId ProgramId::Boot = { 0x0100000000000005ul }; + inline constexpr const ProgramId ProgramId::Usb = { 0x0100000000000006ul }; + inline constexpr const ProgramId ProgramId::Tma = { 0x0100000000000007ul }; + inline constexpr const ProgramId ProgramId::Boot2 = { 0x0100000000000008ul }; + inline constexpr const ProgramId ProgramId::Settings = { 0x0100000000000009ul }; + inline constexpr const ProgramId ProgramId::Bus = { 0x010000000000000Aul }; + inline constexpr const ProgramId ProgramId::Bluetooth = { 0x010000000000000Bul }; + inline constexpr const ProgramId ProgramId::Bcat = { 0x010000000000000Cul }; + inline constexpr const ProgramId ProgramId::Dmnt = { 0x010000000000000Dul }; + inline constexpr const ProgramId ProgramId::Friends = { 0x010000000000000Eul }; + inline constexpr const ProgramId ProgramId::Nifm = { 0x010000000000000Ful }; + inline constexpr const ProgramId ProgramId::Ptm = { 0x0100000000000010ul }; + inline constexpr const ProgramId ProgramId::Shell = { 0x0100000000000011ul }; + inline constexpr const ProgramId ProgramId::BsdSockets = { 0x0100000000000012ul }; + inline constexpr const ProgramId ProgramId::Hid = { 0x0100000000000013ul }; + inline constexpr const ProgramId ProgramId::Audio = { 0x0100000000000014ul }; + inline constexpr const ProgramId ProgramId::LogManager = { 0x0100000000000015ul }; + inline constexpr const ProgramId ProgramId::Wlan = { 0x0100000000000016ul }; + inline constexpr const ProgramId ProgramId::Cs = { 0x0100000000000017ul }; + inline constexpr const ProgramId ProgramId::Ldn = { 0x0100000000000018ul }; + inline constexpr const ProgramId ProgramId::NvServices = { 0x0100000000000019ul }; + inline constexpr const ProgramId ProgramId::Pcv = { 0x010000000000001Aul }; + inline constexpr const ProgramId ProgramId::Ppc = { 0x010000000000001Bul }; + inline constexpr const ProgramId ProgramId::NvnFlinger = { 0x010000000000001Cul }; + inline constexpr const ProgramId ProgramId::Pcie = { 0x010000000000001Dul }; + inline constexpr const ProgramId ProgramId::Account = { 0x010000000000001Eul }; + inline constexpr const ProgramId ProgramId::Ns = { 0x010000000000001Ful }; + inline constexpr const ProgramId ProgramId::Nfc = { 0x0100000000000020ul }; + inline constexpr const ProgramId ProgramId::Psc = { 0x0100000000000021ul }; + inline constexpr const ProgramId ProgramId::CapSrv = { 0x0100000000000022ul }; + inline constexpr const ProgramId ProgramId::Am = { 0x0100000000000023ul }; + inline constexpr const ProgramId ProgramId::Ssl = { 0x0100000000000024ul }; + inline constexpr const ProgramId ProgramId::Nim = { 0x0100000000000025ul }; + inline constexpr const ProgramId ProgramId::Cec = { 0x0100000000000026ul }; + inline constexpr const ProgramId ProgramId::Tspm = { 0x0100000000000027ul }; + inline constexpr const ProgramId ProgramId::Spl = { 0x0100000000000028ul }; + inline constexpr const ProgramId ProgramId::Lbl = { 0x0100000000000029ul }; + inline constexpr const ProgramId ProgramId::Btm = { 0x010000000000002Aul }; + inline constexpr const ProgramId ProgramId::Erpt = { 0x010000000000002Bul }; + inline constexpr const ProgramId ProgramId::Time = { 0x010000000000002Cul }; + inline constexpr const ProgramId ProgramId::Vi = { 0x010000000000002Dul }; + inline constexpr const ProgramId ProgramId::Pctl = { 0x010000000000002Eul }; + inline constexpr const ProgramId ProgramId::Npns = { 0x010000000000002Ful }; + inline constexpr const ProgramId ProgramId::Eupld = { 0x0100000000000030ul }; + inline constexpr const ProgramId ProgramId::Arp = { 0x0100000000000031ul }; + inline constexpr const ProgramId ProgramId::Glue = { 0x0100000000000031ul }; + inline constexpr const ProgramId ProgramId::Eclct = { 0x0100000000000032ul }; + inline constexpr const ProgramId ProgramId::Es = { 0x0100000000000033ul }; + inline constexpr const ProgramId ProgramId::Fatal = { 0x0100000000000034ul }; + inline constexpr const ProgramId ProgramId::Grc = { 0x0100000000000035ul }; + inline constexpr const ProgramId ProgramId::Creport = { 0x0100000000000036ul }; + inline constexpr const ProgramId ProgramId::Ro = { 0x0100000000000037ul }; + inline constexpr const ProgramId ProgramId::Profiler = { 0x0100000000000038ul }; + inline constexpr const ProgramId ProgramId::Sdb = { 0x0100000000000039ul }; + inline constexpr const ProgramId ProgramId::Migration = { 0x010000000000003Aul }; + inline constexpr const ProgramId ProgramId::Jit = { 0x010000000000003Bul }; + inline constexpr const ProgramId ProgramId::JpegDec = { 0x010000000000003Cul }; + inline constexpr const ProgramId ProgramId::SafeMode = { 0x010000000000003Dul }; + inline constexpr const ProgramId ProgramId::Olsc = { 0x010000000000003Eul }; + inline constexpr const ProgramId ProgramId::Dt = { 0x010000000000003Ful }; + inline constexpr const ProgramId ProgramId::Nd = { 0x0100000000000040ul }; + inline constexpr const ProgramId ProgramId::Ngct = { 0x0100000000000041ul }; + + inline constexpr const ProgramId ProgramId::SystemEnd = { 0x01000000000007FFul }; + + /* System Data Archives. */ + inline constexpr const ProgramId ProgramId::ArchiveStart = { 0x0100000000000800ul }; + inline constexpr const ProgramId ProgramId::ArchiveCertStore = { 0x0100000000000800ul }; + inline constexpr const ProgramId ProgramId::ArchiveErrorMessage = { 0x0100000000000801ul }; + inline constexpr const ProgramId ProgramId::ArchiveMiiModel = { 0x0100000000000802ul }; + inline constexpr const ProgramId ProgramId::ArchiveBrowserDll = { 0x0100000000000803ul }; + inline constexpr const ProgramId ProgramId::ArchiveHelp = { 0x0100000000000804ul }; + inline constexpr const ProgramId ProgramId::ArchiveSharedFont = { 0x0100000000000805ul }; + inline constexpr const ProgramId ProgramId::ArchiveNgWord = { 0x0100000000000806ul }; + inline constexpr const ProgramId ProgramId::ArchiveSsidList = { 0x0100000000000807ul }; + inline constexpr const ProgramId ProgramId::ArchiveDictionary = { 0x0100000000000808ul }; + inline constexpr const ProgramId ProgramId::ArchiveSystemVersion = { 0x0100000000000809ul }; + inline constexpr const ProgramId ProgramId::ArchiveAvatarImage = { 0x010000000000080Aul }; + inline constexpr const ProgramId ProgramId::ArchiveLocalNews = { 0x010000000000080Bul }; + inline constexpr const ProgramId ProgramId::ArchiveEula = { 0x010000000000080Cul }; + inline constexpr const ProgramId ProgramId::ArchiveUrlBlackList = { 0x010000000000080Dul }; + inline constexpr const ProgramId ProgramId::ArchiveTimeZoneBinar = { 0x010000000000080Eul }; + inline constexpr const ProgramId ProgramId::ArchiveCertStoreCruiser = { 0x010000000000080Ful }; + inline constexpr const ProgramId ProgramId::ArchiveFontNintendoExtension = { 0x0100000000000810ul }; + inline constexpr const ProgramId ProgramId::ArchiveFontStandard = { 0x0100000000000811ul }; + inline constexpr const ProgramId ProgramId::ArchiveFontKorean = { 0x0100000000000812ul }; + inline constexpr const ProgramId ProgramId::ArchiveFontChineseTraditional = { 0x0100000000000813ul }; + inline constexpr const ProgramId ProgramId::ArchiveFontChineseSimple = { 0x0100000000000814ul }; + inline constexpr const ProgramId ProgramId::ArchiveFontBfcpx = { 0x0100000000000815ul }; + inline constexpr const ProgramId ProgramId::ArchiveSystemUpdate = { 0x0100000000000816ul }; + + inline constexpr const ProgramId ProgramId::ArchiveFirmwareDebugSettings = { 0x0100000000000818ul }; + inline constexpr const ProgramId ProgramId::ArchiveBootImagePackage = { 0x0100000000000819ul }; + inline constexpr const ProgramId ProgramId::ArchiveBootImagePackageSafe = { 0x010000000000081Aul }; + inline constexpr const ProgramId ProgramId::ArchiveBootImagePackageExFat = { 0x010000000000081Bul }; + inline constexpr const ProgramId ProgramId::ArchiveBootImagePackageExFatSafe = { 0x010000000000081Cul }; + inline constexpr const ProgramId ProgramId::ArchiveFatalMessage = { 0x010000000000081Dul }; + inline constexpr const ProgramId ProgramId::ArchiveControllerIcon = { 0x010000000000081Eul }; + inline constexpr const ProgramId ProgramId::ArchivePlatformConfigIcosa = { 0x010000000000081Ful }; + inline constexpr const ProgramId ProgramId::ArchivePlatformConfigCopper = { 0x0100000000000820ul }; + inline constexpr const ProgramId ProgramId::ArchivePlatformConfigHoag = { 0x0100000000000821ul }; + inline constexpr const ProgramId ProgramId::ArchiveControllerFirmware = { 0x0100000000000822ul }; + inline constexpr const ProgramId ProgramId::ArchiveNgWord2 = { 0x0100000000000823ul }; + inline constexpr const ProgramId ProgramId::ArchivePlatformConfigIcosaMariko = { 0x0100000000000824ul }; + inline constexpr const ProgramId ProgramId::ArchiveApplicationBlackList = { 0x0100000000000825ul }; + inline constexpr const ProgramId ProgramId::ArchiveRebootlessSystemUpdateVersion = { 0x0100000000000826ul }; + inline constexpr const ProgramId ProgramId::ArchiveContentActionTable = { 0x0100000000000827ul }; + + inline constexpr const ProgramId ProgramId::ArchiveEnd = { 0x0100000000000FFFul }; + + /* System Applets. */ + inline constexpr const ProgramId ProgramId::AppletStart = { 0x0100000000001000ul }; + + inline constexpr const ProgramId ProgramId::AppletQlaunch = { 0x0100000000001000ul }; + inline constexpr const ProgramId ProgramId::AppletAuth = { 0x0100000000001001ul }; + inline constexpr const ProgramId ProgramId::AppletCabinet = { 0x0100000000001002ul }; + inline constexpr const ProgramId ProgramId::AppletController = { 0x0100000000001003ul }; + inline constexpr const ProgramId ProgramId::AppletDataErase = { 0x0100000000001004ul }; + inline constexpr const ProgramId ProgramId::AppletError = { 0x0100000000001005ul }; + inline constexpr const ProgramId ProgramId::AppletNetConnect = { 0x0100000000001006ul }; + inline constexpr const ProgramId ProgramId::AppletPlayerSelect = { 0x0100000000001007ul }; + inline constexpr const ProgramId ProgramId::AppletSwkbd = { 0x0100000000001008ul }; + inline constexpr const ProgramId ProgramId::AppletMiiEdit = { 0x0100000000001009ul }; + inline constexpr const ProgramId ProgramId::AppletWeb = { 0x010000000000100Aul }; + inline constexpr const ProgramId ProgramId::AppletShop = { 0x010000000000100Bul }; + inline constexpr const ProgramId ProgramId::AppletOverlayDisp = { 0x010000000000100Cul }; + inline constexpr const ProgramId ProgramId::AppletPhotoViewer = { 0x010000000000100Dul }; + inline constexpr const ProgramId ProgramId::AppletSet = { 0x010000000000100Eul }; + inline constexpr const ProgramId ProgramId::AppletOfflineWeb = { 0x010000000000100Ful }; + inline constexpr const ProgramId ProgramId::AppletLoginShare = { 0x0100000000001010ul }; + inline constexpr const ProgramId ProgramId::AppletWifiWebAuth = { 0x0100000000001011ul }; + inline constexpr const ProgramId ProgramId::AppletStarter = { 0x0100000000001012ul }; + inline constexpr const ProgramId ProgramId::AppletMyPage = { 0x0100000000001013ul }; + inline constexpr const ProgramId ProgramId::AppletPlayReport = { 0x0100000000001014ul }; + inline constexpr const ProgramId ProgramId::AppletMaintenanceMenu = { 0x0100000000001015ul }; + + inline constexpr const ProgramId ProgramId::AppletGift = { 0x010000000000101Aul }; + inline constexpr const ProgramId ProgramId::AppletDummyShop = { 0x010000000000101Bul }; + inline constexpr const ProgramId ProgramId::AppletUserMigration = { 0x010000000000101Cul }; + inline constexpr const ProgramId ProgramId::AppletEncounter = { 0x010000000000101Dul }; + + inline constexpr const ProgramId ProgramId::AppletStory = { 0x0100000000001020ul }; + + inline constexpr const ProgramId ProgramId::AppletEnd = { 0x0100000000001FFFul }; + + /* Debug Applets. */ + + /* Debug Modules. */ + + /* Factory Setup. */ + + /* Applications. */ + inline constexpr const ProgramId ProgramId::ApplicationStart = { 0x0100000000010000ul }; + inline constexpr const ProgramId ProgramId::ApplicationEnd = { 0x01FFFFFFFFFFFFFFul }; + + /* Atmosphere Extensions. */ + inline constexpr const ProgramId ProgramId::AtmosphereMitm = { 0x010041544D530000ul }; + + inline constexpr bool operator==(const ProgramId &lhs, const ProgramId &rhs) { + return lhs.value == rhs.value; + } + + inline constexpr bool operator!=(const ProgramId &lhs, const ProgramId &rhs) { + return lhs.value != rhs.value; + } + + inline constexpr bool operator<(const ProgramId &lhs, const ProgramId &rhs) { + return lhs.value < rhs.value; + } + + inline constexpr bool operator<=(const ProgramId &lhs, const ProgramId &rhs) { + return lhs.value <= rhs.value; + } + + inline constexpr bool operator>(const ProgramId &lhs, const ProgramId &rhs) { + return lhs.value > rhs.value; + } + + inline constexpr bool operator>=(const ProgramId &lhs, const ProgramId &rhs) { + return lhs.value >= rhs.value; + } + + inline constexpr bool IsSystemProgramId(const ProgramId &program_id) { + return ProgramId::SystemStart <= program_id && program_id <= ProgramId::SystemEnd; + } + + inline constexpr bool IsArchiveProgramId(const ProgramId &program_id) { + return ProgramId::ArchiveStart <= program_id && program_id <= ProgramId::ArchiveEnd; + } + + inline constexpr bool IsAppletProgramId(const ProgramId &program_id) { + return ProgramId::AppletStart <= program_id && program_id <= ProgramId::AppletEnd; + } + + inline constexpr bool IsApplicationProgramId(const ProgramId &program_id) { + return ProgramId::ApplicationStart <= program_id && program_id <= ProgramId::ApplicationEnd; + } + + inline constexpr bool IsWebAppletProgramId(const ProgramId &program_id) { + return program_id == ProgramId::AppletWeb || + program_id == ProgramId::AppletShop || + program_id == ProgramId::AppletOfflineWeb || + program_id == ProgramId::AppletLoginShare || + program_id == ProgramId::AppletWifiWebAuth; + } + + static_assert(sizeof(ProgramId) == sizeof(u64) && std::is_pod::value, "ProgramId definition!"); + + /* Program Location. */ + struct ProgramLocation { + ProgramId program_id; + u8 storage_id; + + static constexpr ProgramLocation Make(ProgramId program_id, StorageId storage_id) { + return { .program_id = program_id, .storage_id = static_cast(storage_id), }; + } + }; + + static_assert(sizeof(ProgramLocation) == 0x10 && std::is_pod::value, "ProgramLocation definition!"); + static_assert(sizeof(ProgramLocation) == sizeof(::NcmProgramLocation) && alignof(ProgramLocation) == alignof(::NcmProgramLocation), "ProgramLocation Libnx Compatibility"); + +} diff --git a/libraries/libstratosphere/include/stratosphere/os.hpp b/libraries/libstratosphere/include/stratosphere/os.hpp new file mode 100644 index 000000000..21e54e43d --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os.hpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "os/os_common_types.hpp" +#include "os/os_memory_common.hpp" +#include "os/os_managed_handle.hpp" +#include "os/os_process_handle.hpp" +#include "os/os_mutex.hpp" +#include "os/os_condvar.hpp" +#include "os/os_rw_lock.hpp" +#include "os/os_semaphore.hpp" +#include "os/os_timeout_helper.hpp" +#include "os/os_event.hpp" +#include "os/os_system_event.hpp" +#include "os/os_interrupt_event.hpp" +#include "os/os_thread.hpp" +#include "os/os_message_queue.hpp" +#include "os/os_waitable_holder.hpp" +#include "os/os_waitable_manager.hpp" diff --git a/libraries/libstratosphere/include/stratosphere/os/os_common_types.hpp b/libraries/libstratosphere/include/stratosphere/os/os_common_types.hpp new file mode 100644 index 000000000..a3fba5a93 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_common_types.hpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::os { + + enum class TriBool { + False = 0, + True = 1, + Undefined = 2, + }; + + enum class MessageQueueWaitKind { + ForNotEmpty, + ForNotFull, + }; + + struct ProcessId { + u64 value; + + inline constexpr explicit operator u64() const { + return this->value; + } + + /* Invalid Process ID. */ + static const ProcessId Invalid; + }; + + inline constexpr const ProcessId ProcessId::Invalid = {static_cast(-1ull)}; + + inline constexpr const ProcessId InvalidProcessId = ProcessId::Invalid; + + NX_INLINE Result TryGetProcessId(os::ProcessId *out, ::Handle process_handle) { + return svcGetProcessId(&out->value, process_handle); + } + + NX_INLINE os::ProcessId GetProcessId(::Handle process_handle) { + os::ProcessId process_id; + R_ASSERT(TryGetProcessId(&process_id, process_handle)); + return process_id; + } + + inline constexpr bool operator==(const ProcessId &lhs, const ProcessId &rhs) { + return lhs.value == rhs.value; + } + + inline constexpr bool operator!=(const ProcessId &lhs, const ProcessId &rhs) { + return lhs.value != rhs.value; + } + + inline constexpr bool operator<(const ProcessId &lhs, const ProcessId &rhs) { + return lhs.value < rhs.value; + } + + inline constexpr bool operator<=(const ProcessId &lhs, const ProcessId &rhs) { + return lhs.value <= rhs.value; + } + + inline constexpr bool operator>(const ProcessId &lhs, const ProcessId &rhs) { + return lhs.value > rhs.value; + } + + inline constexpr bool operator>=(const ProcessId &lhs, const ProcessId &rhs) { + return lhs.value >= rhs.value; + } + +} diff --git a/libraries/libstratosphere/include/stratosphere/os/os_condvar.hpp b/libraries/libstratosphere/include/stratosphere/os/os_condvar.hpp new file mode 100644 index 000000000..26b18bf5c --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_condvar.hpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "os_mutex.hpp" + +namespace ams::os { + + enum class ConditionVariableStatus { + TimedOut = 0, + Success = 1, + }; + + class ConditionVariable { + NON_COPYABLE(ConditionVariable); + NON_MOVEABLE(ConditionVariable); + private: + CondVar cv; + public: + ConditionVariable() { + condvarInit(&cv); + } + + ConditionVariableStatus TimedWait(::Mutex *m, u64 timeout) { + if (timeout > 0) { + /* Abort on any error other than timed out/success. */ + R_TRY_CATCH(condvarWaitTimeout(&this->cv, m, timeout)) { + R_CATCH(svc::ResultTimedOut) { return ConditionVariableStatus::TimedOut; } + } R_END_TRY_CATCH_WITH_ASSERT; + + return ConditionVariableStatus::Success; + } + return ConditionVariableStatus::TimedOut; + } + + void Wait(::Mutex *m) { + R_ASSERT(condvarWait(&this->cv, m)); + } + + ConditionVariableStatus TimedWait(os::Mutex *m, u64 timeout) { + return this->TimedWait(m->GetMutex(), timeout); + } + + void Wait(os::Mutex *m) { + return this->Wait(m->GetMutex()); + } + + void Signal() { + condvarWakeOne(&this->cv); + } + + void Broadcast() { + condvarWakeAll(&this->cv); + } + }; + +} \ No newline at end of file diff --git a/libraries/libstratosphere/include/stratosphere/os/os_event.hpp b/libraries/libstratosphere/include/stratosphere/os/os_event.hpp new file mode 100644 index 000000000..b19ce3a69 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_event.hpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "os_mutex.hpp" +#include "os_condvar.hpp" +#include "os_timeout_helper.hpp" + +namespace ams::os { + + namespace impl { + + class WaitableObjectList; + class WaitableHolderOfEvent; + + } + + class Event { + friend class impl::WaitableHolderOfEvent; + NON_COPYABLE(Event); + NON_MOVEABLE(Event); + private: + util::TypedStorage waitable_object_list_storage; + Mutex lock; + ConditionVariable cv; + u64 counter = 0; + bool auto_clear; + bool signaled; + public: + Event(bool a = true, bool s = false); + ~Event(); + + void Signal(); + void Reset(); + void Wait(); + bool TryWait(); + bool TimedWait(u64 ns); + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/os/os_interrupt_event.hpp b/libraries/libstratosphere/include/stratosphere/os/os_interrupt_event.hpp new file mode 100644 index 000000000..ccfd97910 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_interrupt_event.hpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "os_managed_handle.hpp" + +namespace ams::os { + + namespace impl { + + class WaitableHolderOfInterruptEvent; + + } + + class InterruptEvent { + friend class impl::WaitableHolderOfInterruptEvent; + NON_COPYABLE(InterruptEvent); + NON_MOVEABLE(InterruptEvent); + private: + ManagedHandle handle; + bool auto_clear; + bool is_initialized; + public: + InterruptEvent() : auto_clear(true), is_initialized(false) { } + InterruptEvent(u32 interrupt_id, bool autoclear = true); + + Result Initialize(u32 interrupt_id, bool autoclear = true); + void Finalize(); + + void Reset(); + void Wait(); + bool TryWait(); + bool TimedWait(u64 ns); + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/os/os_managed_handle.hpp b/libraries/libstratosphere/include/stratosphere/os/os_managed_handle.hpp new file mode 100644 index 000000000..72ecda111 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_managed_handle.hpp @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "os_common_types.hpp" + +namespace ams::os { + + class ManagedHandle { + NON_COPYABLE(ManagedHandle); + private: + Handle hnd; + public: + ManagedHandle() : hnd(INVALID_HANDLE) { /* ... */ } + ManagedHandle(Handle h) : hnd(h) { /* ... */ } + ~ManagedHandle() { + if (this->hnd != INVALID_HANDLE) { + R_ASSERT(svcCloseHandle(this->hnd)); + this->hnd = INVALID_HANDLE; + } + } + + ManagedHandle(ManagedHandle&& rhs) { + this->hnd = rhs.hnd; + rhs.hnd = INVALID_HANDLE; + } + + ManagedHandle& operator=(ManagedHandle&& rhs) { + rhs.Swap(*this); + return *this; + } + + explicit operator bool() const { + return this->hnd != INVALID_HANDLE; + } + + void Swap(ManagedHandle& rhs) { + std::swap(this->hnd, rhs.hnd); + } + + Handle Get() const { + return this->hnd; + } + + Handle *GetPointer() { + return &this->hnd; + } + + Handle *GetPointerAndClear() { + this->Clear(); + return this->GetPointer(); + } + + Handle Move() { + const Handle h = this->hnd; + this->hnd = INVALID_HANDLE; + return h; + } + + void Reset(Handle h) { + ManagedHandle(h).Swap(*this); + } + + void Clear() { + this->Reset(INVALID_HANDLE); + } + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/os/os_memory_common.hpp b/libraries/libstratosphere/include/stratosphere/os/os_memory_common.hpp new file mode 100644 index 000000000..a7da8adf7 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_memory_common.hpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::os { + + constexpr inline size_t MemoryPageSize = 0x1000; + + constexpr inline size_t MemoryBlockUnitSize = 0x200000; + +} diff --git a/libraries/libstratosphere/include/stratosphere/os/os_message_queue.hpp b/libraries/libstratosphere/include/stratosphere/os/os_message_queue.hpp new file mode 100644 index 000000000..ab0733e34 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_message_queue.hpp @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "os_mutex.hpp" +#include "os_condvar.hpp" + +namespace ams::os { + + namespace impl { + + class WaitableObjectList; + + template + class WaitableHolderOfMessageQueue; + + } + + class MessageQueue { + template + friend class impl::WaitableHolderOfMessageQueue; + NON_COPYABLE(MessageQueue); + NON_MOVEABLE(MessageQueue); + private: + util::TypedStorage waitlist_not_empty; + util::TypedStorage waitlist_not_full; + Mutex queue_lock; + ConditionVariable cv_not_full; + ConditionVariable cv_not_empty; + std::unique_ptr buffer; + size_t capacity; + + size_t count; + size_t offset; + private: + constexpr inline bool IsFull() const { + return this->count >= this->capacity; + } + + constexpr inline bool IsEmpty() const { + return this->count == 0; + } + + void SendInternal(uintptr_t data); + void SendNextInternal(uintptr_t data); + uintptr_t ReceiveInternal(); + uintptr_t PeekInternal(); + public: + MessageQueue(std::unique_ptr buf, size_t c); + ~MessageQueue(); + + /* For convenience. */ + MessageQueue(size_t c) : MessageQueue(std::make_unique(c), c) { /* ... */ } + + /* Sending (FIFO functionality) */ + void Send(uintptr_t data); + bool TrySend(uintptr_t data); + bool TimedSend(uintptr_t data, u64 timeout); + + /* Sending (LIFO functionality) */ + void SendNext(uintptr_t data); + bool TrySendNext(uintptr_t data); + bool TimedSendNext(uintptr_t data, u64 timeout); + + /* Receive functionality */ + void Receive(uintptr_t *out); + bool TryReceive(uintptr_t *out); + bool TimedReceive(uintptr_t *out, u64 timeout); + + /* Peek functionality */ + void Peek(uintptr_t *out); + bool TryPeek(uintptr_t *out); + bool TimedPeek(uintptr_t *out, u64 timeout); + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/os/os_mutex.hpp b/libraries/libstratosphere/include/stratosphere/os/os_mutex.hpp new file mode 100644 index 000000000..26ba66c2e --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_mutex.hpp @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "os_common_types.hpp" + +namespace ams::os { + + class ConditionVariable; + + class Mutex { + NON_COPYABLE(Mutex); + NON_MOVEABLE(Mutex); + friend class ams::os::ConditionVariable; + private: + ::Mutex m; + private: + ::Mutex *GetMutex() { + return &this->m; + } + public: + Mutex() { + mutexInit(GetMutex()); + } + + void lock() { + mutexLock(GetMutex()); + } + + void unlock() { + mutexUnlock(GetMutex()); + } + + bool try_lock() { + return mutexTryLock(GetMutex()); + } + + void Lock() { + lock(); + } + + void Unlock() { + unlock(); + } + + bool TryLock() { + return try_lock(); + } + }; + + class RecursiveMutex { + private: + ::RMutex m; + private: + ::RMutex *GetMutex() { + return &this->m; + } + public: + RecursiveMutex() { + rmutexInit(GetMutex()); + } + + void lock() { + rmutexLock(GetMutex()); + } + + void unlock() { + rmutexUnlock(GetMutex()); + } + + bool try_lock() { + return rmutexTryLock(GetMutex()); + } + + void Lock() { + lock(); + } + + void Unlock() { + unlock(); + } + + bool TryLock() { + return try_lock(); + } + }; + +} \ No newline at end of file diff --git a/libraries/libstratosphere/include/stratosphere/os/os_process_handle.hpp b/libraries/libstratosphere/include/stratosphere/os/os_process_handle.hpp new file mode 100644 index 000000000..1b5eac0a6 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_process_handle.hpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "os_managed_handle.hpp" + +namespace ams::os { + + ::Handle GetCurrentProcessHandle(); + + NX_INLINE ProcessId GetCurrentProcessId() { + return GetProcessId(GetCurrentProcessHandle()); + } + +} diff --git a/libraries/libstratosphere/include/stratosphere/os/os_rw_lock.hpp b/libraries/libstratosphere/include/stratosphere/os/os_rw_lock.hpp new file mode 100644 index 000000000..674d056ee --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_rw_lock.hpp @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "os_common_types.hpp" + +namespace ams::os { + + class ReadWriteLock { + NON_COPYABLE(ReadWriteLock); + NON_MOVEABLE(ReadWriteLock); + private: + ::RwLock r; + public: + ReadWriteLock() { + rwlockInit(&this->r); + } + + bool IsWriteLockHeldByCurrentThread() const { + return rwlockIsWriteLockHeldByCurrentThread(const_cast<::RwLock *>(&this->r)); + } + + bool IsLockOwner() const { + return rwlockIsOwnedByCurrentThread(const_cast<::RwLock *>(&this->r)); + } + + void AcquireReadLock() { + rwlockReadLock(&this->r); + } + + void ReleaseReadLock() { + rwlockReadUnlock(&this->r); + } + + bool TryAcquireReadLock() { + return rwlockTryReadLock(&this->r); + } + + void AcquireWriteLock() { + rwlockWriteLock(&this->r); + } + + void ReleaseWriteLock() { + rwlockWriteUnlock(&this->r); + } + + bool TryAcquireWriteLock() { + return rwlockTryWriteLock(&this->r); + } + + void lock_shared() { + this->AcquireReadLock(); + } + + void unlock_shared() { + this->ReleaseReadLock(); + } + + bool try_lock_shared() { + return this->TryAcquireReadLock(); + } + + void lock() { + this->AcquireWriteLock(); + } + + void unlock() { + this->ReleaseWriteLock(); + } + + bool try_lock() { + return this->TryAcquireWriteLock(); + } + }; + +} \ No newline at end of file diff --git a/libraries/libstratosphere/include/stratosphere/os/os_semaphore.hpp b/libraries/libstratosphere/include/stratosphere/os/os_semaphore.hpp new file mode 100644 index 000000000..0941ce5cb --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_semaphore.hpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "os_mutex.hpp" +#include "os_condvar.hpp" + +namespace ams::os { + + namespace impl { + + class WaitableObjectList; + class WaitableHolderOfSemaphore; + + } + + class Semaphore { + friend class impl::WaitableHolderOfSemaphore; + NON_COPYABLE(Semaphore); + NON_MOVEABLE(Semaphore); + private: + util::TypedStorage waitlist; + os::Mutex mutex; + os::ConditionVariable condvar; + int count; + int max_count; + public: + explicit Semaphore(int c, int mc); + ~Semaphore(); + + void Acquire(); + bool TryAcquire(); + bool TimedAcquire(u64 timeout); + + void Release(); + void Release(int count); + + constexpr inline int GetCurrentCount() const { + return this->count; + } + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/os/os_system_event.hpp b/libraries/libstratosphere/include/stratosphere/os/os_system_event.hpp new file mode 100644 index 000000000..290bfe52c --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_system_event.hpp @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "os_event.hpp" + +namespace ams::os { + + class WaitableHolder; + + namespace impl { + + class InterProcessEvent; + + } + + enum class SystemEventState { + Uninitialized, + Event, + InterProcessEvent, + }; + + class SystemEvent { + friend class WaitableHolder; + NON_COPYABLE(SystemEvent); + NON_MOVEABLE(SystemEvent); + private: + union { + util::TypedStorage storage_for_event; + util::TypedStorage storage_for_inter_process_event; + }; + SystemEventState state; + private: + Event &GetEvent(); + const Event &GetEvent() const; + impl::InterProcessEvent &GetInterProcessEvent(); + const impl::InterProcessEvent &GetInterProcessEvent() const; + public: + SystemEvent() : state(SystemEventState::Uninitialized) { /* ... */ } + SystemEvent(bool inter_process, bool autoclear = true); + SystemEvent(Handle read_handle, bool manage_read_handle, Handle write_handle, bool manage_write_handle, bool autoclear = true); + SystemEvent(Handle read_handle, bool manage_read_handle, bool autoclear = true) : SystemEvent(read_handle, manage_read_handle, INVALID_HANDLE, false, autoclear) { /* ... */ } + ~SystemEvent(); + + Result InitializeAsEvent(bool autoclear = true); + Result InitializeAsInterProcessEvent(bool autoclear = true); + void AttachHandles(Handle read_handle, bool manage_read_handle, Handle write_handle, bool manage_write_handle, bool autoclear = true); + void AttachReadableHandle(Handle read_handle, bool manage_read_handle, bool autoclear = true); + void AttachWritableHandle(Handle write_handle, bool manage_write_handle, bool autoclear = true); + Handle DetachReadableHandle(); + Handle DetachWritableHandle(); + Handle GetReadableHandle() const; + Handle GetWritableHandle() const; + void Finalize(); + + SystemEventState GetState() const { + return this->state; + } + + void Signal(); + void Reset(); + void Wait(); + bool TryWait(); + bool TimedWait(u64 ns); + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/os/os_thread.hpp b/libraries/libstratosphere/include/stratosphere/os/os_thread.hpp new file mode 100644 index 000000000..a3e809e0b --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_thread.hpp @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "os_common_types.hpp" +#include "os_memory_common.hpp" + +namespace ams::os { + + class Thread { + NON_COPYABLE(Thread); + NON_MOVEABLE(Thread); + private: + ::Thread thr; + public: + constexpr Thread() : thr{} { /* ... */ } + + Result Initialize(ThreadFunc entry, void *arg, void *stack_mem, size_t stack_sz, int prio, int cpuid = -2) { + return threadCreate(&this->thr, entry, arg, stack_mem, stack_sz, prio, cpuid); + } + + Result Initialize(ThreadFunc entry, void *arg, size_t stack_sz, int prio, int cpuid = -2) { + return threadCreate(&this->thr, entry, arg, nullptr, stack_sz, prio, cpuid); + } + + Handle GetHandle() const { + return this->thr.handle; + } + + Result Start() { + return threadStart(&this->thr); + } + + Result Wait() { + return threadWaitForExit(&this->thr); + } + + Result Join() { + R_TRY(threadWaitForExit(&this->thr)); + R_TRY(threadClose(&this->thr)); + return ResultSuccess(); + } + + Result CancelSynchronization() { + return svcCancelSynchronization(this->thr.handle); + } + }; + + template + class StaticThread { + NON_COPYABLE(StaticThread); + NON_MOVEABLE(StaticThread); + static_assert(util::IsAligned(StackSize, os::MemoryPageSize), "StaticThread must have aligned resource size"); + private: + alignas(os::MemoryPageSize) u8 stack_mem[StackSize]; + ::Thread thr; + public: + constexpr StaticThread() : stack_mem{}, thr{} { /* ... */ } + + constexpr StaticThread(ThreadFunc entry, void *arg, int prio, int cpuid = -2) : StaticThread() { + R_ASSERT(this->Initialize(entry, arg, prio, cpuid)); + } + + Result Initialize(ThreadFunc entry, void *arg, int prio, int cpuid = -2) { + return threadCreate(&this->thr, entry, arg, this->stack_mem, StackSize, prio, cpuid); + } + + Handle GetHandle() const { + return this->thr.handle; + } + + Result Start() { + return threadStart(&this->thr); + } + + Result Wait() { + return threadWaitForExit(&this->thr); + } + + Result Join() { + R_TRY(threadWaitForExit(&this->thr)); + R_TRY(threadClose(&this->thr)); + return ResultSuccess(); + } + + Result CancelSynchronization() { + return svcCancelSynchronization(this->thr.handle); + } + }; + + NX_INLINE u32 GetCurrentThreadPriority() { + u32 prio; + R_ASSERT(svcGetThreadPriority(&prio, CUR_THREAD_HANDLE)); + return prio; + } + +} diff --git a/libraries/libstratosphere/include/stratosphere/os/os_timeout_helper.hpp b/libraries/libstratosphere/include/stratosphere/os/os_timeout_helper.hpp new file mode 100644 index 000000000..5f5bf408e --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_timeout_helper.hpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "os_common_types.hpp" + +namespace ams::os { + + class TimeoutHelper { + private: + u64 end_tick; + public: + TimeoutHelper(u64 ns) { + /* Special case zero-time timeouts. */ + if (ns == 0) { + end_tick = 0; + return; + } + + u64 cur_tick = armGetSystemTick(); + this->end_tick = cur_tick + NsToTick(ns) + 1; + } + + static constexpr inline u64 NsToTick(u64 ns) { + return (ns * 12) / 625; + } + + static constexpr inline u64 TickToNs(u64 tick) { + return (tick * 625) / 12; + } + + inline bool TimedOut() const { + if (this->end_tick == 0) { + return true; + } + + return armGetSystemTick() >= this->end_tick; + } + + inline u64 NsUntilTimeout() const { + u64 diff = TickToNs(this->end_tick - armGetSystemTick()); + + if (this->TimedOut()) { + return 0; + } + + return diff; + } + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/os/os_waitable_holder.hpp b/libraries/libstratosphere/include/stratosphere/os/os_waitable_holder.hpp new file mode 100644 index 000000000..03c9dcf0e --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_waitable_holder.hpp @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "os_common_types.hpp" + +namespace ams::os { + + class WaitableManager; + + class Event; + class SystemEvent; + class InterruptEvent; + class Thread; + class MessageQueue; + class Semaphore; + + namespace impl { + + class WaitableHolderImpl; + + } + + class WaitableHolder { + friend class WaitableManager; + NON_COPYABLE(WaitableHolder); + NON_MOVEABLE(WaitableHolder); + private: + util::TypedStorage impl_storage; + uintptr_t user_data; + public: + static constexpr size_t ImplStorageSize = sizeof(impl_storage); + public: + WaitableHolder(Handle handle); + WaitableHolder(Event *event); + WaitableHolder(SystemEvent *event); + WaitableHolder(InterruptEvent *event); + WaitableHolder(Thread *thread); + WaitableHolder(Semaphore *semaphore); + WaitableHolder(MessageQueue *message_queue, MessageQueueWaitKind wait_kind); + + ~WaitableHolder(); + + void SetUserData(uintptr_t data) { + this->user_data = data; + } + + uintptr_t GetUserData() const { + return this->user_data; + } + + void UnlinkFromWaitableManager(); + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/os/os_waitable_manager.hpp b/libraries/libstratosphere/include/stratosphere/os/os_waitable_manager.hpp new file mode 100644 index 000000000..90e912e14 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_waitable_manager.hpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "os_mutex.hpp" + +namespace ams::os { + + class WaitableHolder; + + namespace impl { + + class WaitableManagerImpl; + + } + + class WaitableManager { + NON_COPYABLE(WaitableManager); + NON_MOVEABLE(WaitableManager); + private: + util::TypedStorage impl_storage; + public: + static constexpr size_t ImplStorageSize = sizeof(impl_storage); + public: + WaitableManager(); + ~WaitableManager(); + + /* Wait. */ + WaitableHolder *WaitAny(); + WaitableHolder *TryWaitAny(); + WaitableHolder *TimedWaitAny(u64 timeout); + + /* Link. */ + void LinkWaitableHolder(WaitableHolder *holder); + void UnlinkAll(); + void MoveAllFrom(WaitableManager *other); + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/patcher.hpp b/libraries/libstratosphere/include/stratosphere/patcher.hpp new file mode 100644 index 000000000..deafa05cd --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/patcher.hpp @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "patcher/patcher_api.hpp" diff --git a/libraries/libstratosphere/include/stratosphere/patcher/patcher_api.hpp b/libraries/libstratosphere/include/stratosphere/patcher/patcher_api.hpp new file mode 100644 index 000000000..16735500f --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/patcher/patcher_api.hpp @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "../ro/ro_types.hpp" + +namespace ams::patcher { + + /* Helper for applying to code binaries. */ + void LocateAndApplyIpsPatchesToModule(const char *patch_dir, size_t protected_size, size_t offset, const ro::ModuleId *module_id, u8 *mapped_module, size_t mapped_size); + +} diff --git a/libraries/libstratosphere/include/stratosphere/pm.hpp b/libraries/libstratosphere/include/stratosphere/pm.hpp new file mode 100644 index 000000000..7593c5b69 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/pm.hpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "pm/pm_types.hpp" +#include "pm/pm_boot_mode_api.hpp" +#include "pm/pm_info_api.hpp" +#include "pm/pm_shell_api.hpp" +#include "pm/pm_dmnt_api.hpp" \ No newline at end of file diff --git a/libraries/libstratosphere/include/stratosphere/pm/pm_boot_mode_api.hpp b/libraries/libstratosphere/include/stratosphere/pm/pm_boot_mode_api.hpp new file mode 100644 index 000000000..326dc12ee --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/pm/pm_boot_mode_api.hpp @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "pm_types.hpp" + +namespace ams::pm::bm { + + /* Boot Mode API. */ + BootMode GetBootMode(); + void SetMaintenanceBoot(); + +} diff --git a/libraries/libstratosphere/include/stratosphere/pm/pm_dmnt_api.hpp b/libraries/libstratosphere/include/stratosphere/pm/pm_dmnt_api.hpp new file mode 100644 index 000000000..616e4d9c1 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/pm/pm_dmnt_api.hpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "../ldr.hpp" +#include "pm_types.hpp" + +namespace ams::pm::dmnt { + + /* Debug Monitor API. */ + Result StartProcess(os::ProcessId process_id); + Result GetProcessId(os::ProcessId *out_process_id, const ncm::ProgramId program_id); + Result GetApplicationProcessId(os::ProcessId *out_process_id); + Result HookToCreateApplicationProcess(Handle *out_handle); + Result AtmosphereGetProcessInfo(Handle *out_handle, ncm::ProgramLocation *out_loc, cfg::OverrideStatus *out_status, os::ProcessId process_id); + Result AtmosphereGetCurrentLimitInfo(u64 *out_current_value, u64 *out_limit_value, ResourceLimitGroup group, LimitableResource resource); + +} diff --git a/libraries/libstratosphere/include/stratosphere/pm/pm_info_api.hpp b/libraries/libstratosphere/include/stratosphere/pm/pm_info_api.hpp new file mode 100644 index 000000000..6a56b13df --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/pm/pm_info_api.hpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "pm_types.hpp" +#include "../ncm/ncm_types.hpp" + +namespace ams::pm::info { + + /* Information API. */ + Result GetProgramId(ncm::ProgramId *out_program_id, os::ProcessId process_id); + Result GetProcessId(os::ProcessId *out_process_id, ncm::ProgramId program_id); + Result HasLaunchedProgram(bool *out, ncm::ProgramId program_id); + + Result GetProcessInfo(ncm::ProgramLocation *out_loc, cfg::OverrideStatus *out_status, os::ProcessId process_id); + + /* Information convenience API. */ + bool HasLaunchedProgram(ncm::ProgramId program_id); + + Result IsHblProcessId(bool *out, os::ProcessId process_id); + Result IsHblProgramId(bool *out, ncm::ProgramId program_id); + +} diff --git a/libraries/libstratosphere/include/stratosphere/pm/pm_shell_api.hpp b/libraries/libstratosphere/include/stratosphere/pm/pm_shell_api.hpp new file mode 100644 index 000000000..72ff790ca --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/pm/pm_shell_api.hpp @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "../ldr.hpp" +#include "pm_types.hpp" + +namespace ams::pm::shell { + + /* Shell API. */ + Result LaunchProgram(os::ProcessId *out_process_id, const ncm::ProgramLocation &loc, u32 launch_flags); + +} diff --git a/libraries/libstratosphere/include/stratosphere/pm/pm_types.hpp b/libraries/libstratosphere/include/stratosphere/pm/pm_types.hpp new file mode 100644 index 000000000..a40eee8f3 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/pm/pm_types.hpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "../os/os_common_types.hpp" + +namespace ams::pm { + + enum class BootMode { + Normal = 0, + Maintenance = 1, + SafeMode = 2, + }; + + enum ResourceLimitGroup { + ResourceLimitGroup_System = 0, + ResourceLimitGroup_Application = 1, + ResourceLimitGroup_Applet = 2, + ResourceLimitGroup_Count, + }; + + using LimitableResource = ::LimitableResource; + + struct ProcessEventInfo { + u32 event; + os::ProcessId process_id; + }; + static_assert(sizeof(ProcessEventInfo) == 0x10 && std::is_pod::value, "ProcessEventInfo definition!"); + +} diff --git a/libraries/libstratosphere/include/stratosphere/reg.hpp b/libraries/libstratosphere/include/stratosphere/reg.hpp new file mode 100644 index 000000000..aa96d9177 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/reg.hpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include + +namespace ams::reg { + + inline void Write(volatile u32 *reg, u32 val) { + *reg = val; + } + + inline void Write(uintptr_t reg, u32 val) { + Write(reinterpret_cast(reg), val); + } + + inline u32 Read(volatile u32 *reg) { + return *reg; + } + + inline u32 Read(uintptr_t reg) { + return Read(reinterpret_cast(reg)); + } + + inline void SetBits(volatile u32 *reg, u32 mask) { + *reg |= mask; + } + + inline void SetBits(uintptr_t reg, u32 mask) { + SetBits(reinterpret_cast(reg), mask); + } + + inline void ClearBits(volatile u32 *reg, u32 mask) { + *reg &= ~mask; + } + + inline void ClearBits(uintptr_t reg, u32 mask) { + ClearBits(reinterpret_cast(reg), mask); + } + + inline void MaskBits(volatile u32 *reg, u32 mask) { + *reg &= mask; + } + + inline void MaskBits(uintptr_t reg, u32 mask) { + MaskBits(reinterpret_cast(reg), mask); + } + + inline void ReadWrite(volatile u32 *reg, u32 val, u32 mask) { + *reg = (*reg & (~mask)) | (val & mask); + } + + inline void ReadWrite(uintptr_t reg, u32 val, u32 mask) { + ReadWrite(reinterpret_cast(reg), val, mask); + } + +} \ No newline at end of file diff --git a/libraries/libstratosphere/include/stratosphere/rnd.hpp b/libraries/libstratosphere/include/stratosphere/rnd.hpp new file mode 100644 index 000000000..a11eba7b2 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/rnd.hpp @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "rnd/rnd_api.hpp" diff --git a/libraries/libstratosphere/include/stratosphere/rnd/rnd_api.hpp b/libraries/libstratosphere/include/stratosphere/rnd/rnd_api.hpp new file mode 100644 index 000000000..bd3e1ef9b --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/rnd/rnd_api.hpp @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include + +namespace ams::rnd { + + /* Random utilities. */ + void GenerateRandomBytes(void* out, size_t size); + u32 GenerateRandomU32(u32 max = std::numeric_limits::max()); + u64 GenerateRandomU64(u64 max = std::numeric_limits::max()); + +} diff --git a/libraries/libstratosphere/include/stratosphere/ro.hpp b/libraries/libstratosphere/include/stratosphere/ro.hpp new file mode 100644 index 000000000..c5835d46a --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/ro.hpp @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "ro/ro_types.hpp" diff --git a/libraries/libstratosphere/include/stratosphere/ro/ro_types.hpp b/libraries/libstratosphere/include/stratosphere/ro/ro_types.hpp new file mode 100644 index 000000000..15de65d8c --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/ro/ro_types.hpp @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include "../ncm/ncm_types.hpp" + +namespace ams::ro { + + enum class ModuleType : u8 { + ForSelf = 0, + ForOthers = 1, + Count + }; + + struct ModuleId { + u8 build_id[0x20]; + }; + static_assert(sizeof(ModuleId) == sizeof(LoaderModuleInfo::build_id), "ModuleId definition!"); + + class NrrHeader { + public: + static constexpr u32 Magic = 0x3052524E; + private: + u32 magic; + u8 reserved_04[0xC]; + u64 program_id_mask; + u64 program_id_pattern; + u8 reserved_20[0x10]; + u8 modulus[0x100]; + u8 fixed_key_signature[0x100]; + u8 nrr_signature[0x100]; + ncm::ProgramId program_id; + u32 size; + u8 type; /* 7.0.0+ */ + u8 reserved_33D[3]; + u32 hashes_offset; + u32 num_hashes; + u8 reserved_348[8]; + public: + bool IsMagicValid() const { + return this->magic == Magic; + } + + bool IsProgramIdValid() const { + return (static_cast(this->program_id) & this->program_id_mask) == this->program_id_pattern; + } + + ModuleType GetType() const { + const ModuleType type = static_cast(this->type); + AMS_ASSERT(type < ModuleType::Count); + return type; + } + + ncm::ProgramId GetProgramId() const { + return this->program_id; + } + + u32 GetSize() const { + return this->size; + } + + u32 GetNumHashes() const { + return this->num_hashes; + } + + uintptr_t GetHashes() const { + return reinterpret_cast(this) + this->hashes_offset; + } + }; + static_assert(sizeof(NrrHeader) == 0x350, "NrrHeader definition!"); + + class NroHeader { + public: + static constexpr u32 Magic = 0x304F524E; + private: + u32 entrypoint_insn; + u32 mod_offset; + u8 reserved_08[0x8]; + u32 magic; + u8 reserved_14[0x4]; + u32 size; + u8 reserved_1C[0x4]; + u32 text_offset; + u32 text_size; + u32 ro_offset; + u32 ro_size; + u32 rw_offset; + u32 rw_size; + u32 bss_size; + u8 reserved_3C[0x4]; + ModuleId module_id; + u8 reserved_60[0x20]; + public: + bool IsMagicValid() const { + return this->magic == Magic; + } + + u32 GetSize() const { + return this->size; + } + + u32 GetTextOffset() const { + return this->text_offset; + } + + u32 GetTextSize() const { + return this->text_size; + } + + u32 GetRoOffset() const { + return this->ro_offset; + } + + u32 GetRoSize() const { + return this->ro_size; + } + + u32 GetRwOffset() const { + return this->rw_offset; + } + + u32 GetRwSize() const { + return this->rw_size; + } + + u32 GetBssSize() const { + return this->bss_size; + } + + const ModuleId *GetModuleId() const { + return &this->module_id; + } + }; + static_assert(sizeof(NroHeader) == 0x80, "NroHeader definition!"); + +} diff --git a/libraries/libstratosphere/include/stratosphere/settings.hpp b/libraries/libstratosphere/include/stratosphere/settings.hpp new file mode 100644 index 000000000..66b9bf023 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/settings.hpp @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "settings/settings_types.hpp" +#include "settings/settings_fwdbg_types.hpp" +#include "settings/settings_fwdbg_api.hpp" diff --git a/libraries/libstratosphere/include/stratosphere/settings/settings_fwdbg_api.hpp b/libraries/libstratosphere/include/stratosphere/settings/settings_fwdbg_api.hpp new file mode 100644 index 000000000..aaa40bf60 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/settings/settings_fwdbg_api.hpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include "settings_fwdbg_types.hpp" + +namespace ams::settings::fwdbg { + + bool IsDebugModeEnabled(); + + size_t GetSettingsItemValueSize(const char *name, const char *key); + size_t GetSettingsItemValue(void *dst, size_t dst_size, const char *name, const char *key); + +} diff --git a/libraries/libstratosphere/include/stratosphere/settings/settings_fwdbg_types.hpp b/libraries/libstratosphere/include/stratosphere/settings/settings_fwdbg_types.hpp new file mode 100644 index 000000000..5a5c95441 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/settings/settings_fwdbg_types.hpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include "../sf/sf_buffer_tags.hpp" + +namespace ams::settings::fwdbg { + + constexpr size_t SettingsNameLengthMax = 0x40; + constexpr size_t SettingsItemKeyLengthMax = 0x40; + + struct SettingsName : sf::LargeData { + char value[util::AlignUp(SettingsNameLengthMax + 1, alignof(u64))]; + }; + + static_assert(std::is_pod::value && sizeof(SettingsName) > SettingsNameLengthMax); + + struct SettingsItemKey : sf::LargeData { + char value[util::AlignUp(SettingsItemKeyLengthMax + 1, alignof(u64))]; + }; + + static_assert(std::is_pod::value && sizeof(SettingsItemKey) > SettingsItemKeyLengthMax); + +} diff --git a/libraries/libstratosphere/include/stratosphere/settings/settings_types.hpp b/libraries/libstratosphere/include/stratosphere/settings/settings_types.hpp new file mode 100644 index 000000000..f0d347abb --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/settings/settings_types.hpp @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include + +namespace ams::settings { + + enum Language { + Language_Japanese, + Language_AmericanEnglish, + Language_French, + Language_German, + Language_Italian, + Language_Spanish, + Language_Chinese, + Language_Korean, + Language_Dutch, + Language_Portuguese, + Language_Russian, + Language_Taiwanese, + Language_BritishEnglish, + Language_CanadianFrench, + Language_LatinAmericanSpanish, + /* 4.0.0+ */ + Language_SimplifiedChinese, + Language_TraditionalChinese, + + Language_Count, + }; + + struct LanguageCode { + static constexpr size_t MaxLength = 8; + + char name[MaxLength]; + + static constexpr LanguageCode Encode(const char *name, size_t name_size) { + LanguageCode out{}; + for (size_t i = 0; i < MaxLength && i < name_size; i++) { + out.name[i] = name[i]; + } + return out; + } + + static constexpr LanguageCode Encode(const char *name) { + return Encode(name, std::strlen(name)); + } + + template + static constexpr inline LanguageCode EncodeLanguage = [] { + if constexpr (false) { /* ... */ } + #define AMS_MATCH_LANGUAGE(lang, enc) else if constexpr (Lang == Language_##lang) { return LanguageCode::Encode(enc); } + AMS_MATCH_LANGUAGE(Japanese, "ja") + AMS_MATCH_LANGUAGE(AmericanEnglish, "en-US") + AMS_MATCH_LANGUAGE(French, "fr") + AMS_MATCH_LANGUAGE(German, "de") + AMS_MATCH_LANGUAGE(Italian, "it") + AMS_MATCH_LANGUAGE(Spanish, "es") + AMS_MATCH_LANGUAGE(Chinese, "zh-CN") + AMS_MATCH_LANGUAGE(Korean, "ko") + AMS_MATCH_LANGUAGE(Dutch, "nl") + AMS_MATCH_LANGUAGE(Portuguese, "pt") + AMS_MATCH_LANGUAGE(Russian, "ru") + AMS_MATCH_LANGUAGE(Taiwanese, "zh-TW") + AMS_MATCH_LANGUAGE(BritishEnglish, "en-GB") + AMS_MATCH_LANGUAGE(CanadianFrench, "fr-CA") + AMS_MATCH_LANGUAGE(LatinAmericanSpanish, "es-419") + /* 4.0.0+ */ + AMS_MATCH_LANGUAGE(SimplifiedChinese, "zh-Hans") + AMS_MATCH_LANGUAGE(TraditionalChinese, "zh-Hant") + #undef AMS_MATCH_LANGUAGE + else { static_assert(Lang != Language_Japanese); } + }(); + + static constexpr inline LanguageCode Encode(const Language language) { + constexpr LanguageCode EncodedLanguages[Language_Count] = { + EncodeLanguage, + EncodeLanguage, + EncodeLanguage, + EncodeLanguage, + EncodeLanguage, + EncodeLanguage, + EncodeLanguage, + EncodeLanguage, + EncodeLanguage, + EncodeLanguage, + EncodeLanguage, + EncodeLanguage, + EncodeLanguage, + EncodeLanguage, + EncodeLanguage, + /* 4.0.0+ */ + EncodeLanguage, + EncodeLanguage, + }; + return EncodedLanguages[language]; + } + + }; + + constexpr inline bool operator==(const LanguageCode &lhs, const LanguageCode &rhs) { + return std::strncmp(lhs.name, rhs.name, sizeof(lhs)) == 0; + } + + constexpr inline bool operator!=(const LanguageCode &lhs, const LanguageCode &rhs) { + return !(lhs == rhs); + } + + constexpr inline bool operator==(const LanguageCode &lhs, const Language &rhs) { + return lhs == LanguageCode::Encode(rhs); + } + + constexpr inline bool operator!=(const LanguageCode &lhs, const Language &rhs) { + return !(lhs == rhs); + } + + constexpr inline bool operator==(const Language &lhs, const LanguageCode &rhs) { + return rhs == lhs; + } + + constexpr inline bool operator!=(const Language &lhs, const LanguageCode &rhs) { + return !(lhs == rhs); + } + + namespace impl { + + template + constexpr inline bool IsValidLanguageCode(const LanguageCode &lc, std::index_sequence) { + return ((lc == LanguageCode::Encode(static_cast(Is))) || ...); + } + + } + + constexpr inline bool IsValidLanguageCodeDeprecated(const LanguageCode &lc) { + return impl::IsValidLanguageCode(lc, std::make_index_sequence{}); + } + + constexpr inline bool IsValidLanguageCode(const LanguageCode &lc) { + return impl::IsValidLanguageCode(lc, std::make_index_sequence{}); + } + + static_assert(std::is_pod::value); + static_assert(sizeof(LanguageCode) == sizeof(u64)); + + /* Not an official type, but convenient. */ + enum RegionCode : s32 { + RegionCode_Japan, + RegionCode_America, + RegionCode_Europe, + RegionCode_Australia, + RegionCode_China, + RegionCode_Korea, + RegionCode_Taiwan, + + RegionCode_Count, + }; + + constexpr inline bool IsValidRegionCode(const RegionCode rc) { + return 0 <= rc && rc < RegionCode_Count; + } + + /* This needs to be defined separately from libnx's so that it can inherit from sf::LargeData. */ + + struct FirmwareVersion : public sf::LargeData { + u8 major; + u8 minor; + u8 micro; + u8 padding1; + u8 revision_major; + u8 revision_minor; + u8 padding2; + u8 padding3; + char platform[0x20]; + char version_hash[0x40]; + char display_version[0x18]; + char display_title[0x80]; + + constexpr inline u32 GetVersion() const { + return (static_cast(major) << 16) | (static_cast(minor) << 8) | (static_cast(micro) << 0); + } + }; + + static_assert(std::is_pod::value); + static_assert(sizeof(FirmwareVersion) == sizeof(::SetSysFirmwareVersion)); + + constexpr inline bool operator==(const FirmwareVersion &lhs, const FirmwareVersion &rhs) { + return lhs.GetVersion() == rhs.GetVersion(); + } + + constexpr inline bool operator!=(const FirmwareVersion &lhs, const FirmwareVersion &rhs) { + return !(lhs == rhs); + } + + constexpr inline bool operator<(const FirmwareVersion &lhs, const FirmwareVersion &rhs) { + return lhs.GetVersion() < rhs.GetVersion(); + } + + constexpr inline bool operator>=(const FirmwareVersion &lhs, const FirmwareVersion &rhs) { + return !(lhs < rhs); + } + + constexpr inline bool operator<=(const FirmwareVersion &lhs, const FirmwareVersion &rhs) { + return lhs.GetVersion() <= rhs.GetVersion(); + } + + constexpr inline bool operator>(const FirmwareVersion &lhs, const FirmwareVersion &rhs) { + return !(lhs <= rhs); + } + +} diff --git a/libraries/libstratosphere/include/stratosphere/sf.hpp b/libraries/libstratosphere/include/stratosphere/sf.hpp new file mode 100644 index 000000000..c37ef3aad --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/sf.hpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "sf/sf_common.hpp" +#include "sf/sf_service_object.hpp" +#include "sf/hipc/sf_hipc_server_session_manager.hpp" + +#include "sf/sf_out.hpp" +#include "sf/sf_buffers.hpp" +#include "sf/impl/sf_impl_command_serialization.hpp" + +#include "sf/hipc/sf_hipc_server_manager.hpp" + +#include "sf/sf_mitm_dispatch.h" diff --git a/libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_domain_api.hpp b/libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_domain_api.hpp new file mode 100644 index 000000000..9e792d1b0 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_domain_api.hpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "../sf_common.hpp" +#include "sf_cmif_service_object_holder.hpp" + +namespace ams::sf::cmif { + + struct DomainObjectId { + u32 value; + + constexpr void SetValue(u32 new_value) { this->value = new_value; } + }; + + static_assert(std::is_trivial::value && sizeof(DomainObjectId) == sizeof(u32), "DomainObjectId"); + + inline constexpr bool operator==(const DomainObjectId &lhs, const DomainObjectId &rhs) { + return lhs.value == rhs.value; + } + + inline constexpr bool operator!=(const DomainObjectId &lhs, const DomainObjectId &rhs) { + return lhs.value != rhs.value; + } + + inline constexpr bool operator<(const DomainObjectId &lhs, const DomainObjectId &rhs) { + return lhs.value < rhs.value; + } + + inline constexpr bool operator<=(const DomainObjectId &lhs, const DomainObjectId &rhs) { + return lhs.value <= rhs.value; + } + + inline constexpr bool operator>(const DomainObjectId &lhs, const DomainObjectId &rhs) { + return lhs.value > rhs.value; + } + + inline constexpr bool operator>=(const DomainObjectId &lhs, const DomainObjectId &rhs) { + return lhs.value >= rhs.value; + } + + constexpr inline const DomainObjectId InvalidDomainObjectId = { .value = 0 }; + + class ServerDomainBase { + public: + virtual Result ReserveIds(DomainObjectId *out_ids, size_t count) = 0; + virtual void ReserveSpecificIds(const DomainObjectId *ids, size_t count) = 0; + virtual void UnreserveIds(const DomainObjectId *ids, size_t count) = 0; + virtual void RegisterObject(DomainObjectId id, ServiceObjectHolder &&obj) = 0; + + virtual ServiceObjectHolder UnregisterObject(DomainObjectId id) = 0; + virtual ServiceObjectHolder GetObject(DomainObjectId id) = 0; + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_domain_manager.hpp b/libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_domain_manager.hpp new file mode 100644 index 000000000..0627aed2c --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_domain_manager.hpp @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "../sf_common.hpp" +#include "sf_cmif_domain_api.hpp" +#include "sf_cmif_domain_service_object.hpp" + +namespace ams::sf::cmif { + + class ServerDomainManager { + NON_COPYABLE(ServerDomainManager); + NON_MOVEABLE(ServerDomainManager); + private: + class Domain; + + struct Entry { + NON_COPYABLE(Entry); + NON_MOVEABLE(Entry); + + util::IntrusiveListNode free_list_node; + util::IntrusiveListNode domain_list_node; + Domain *owner; + ServiceObjectHolder object; + + explicit Entry() : owner(nullptr) { /* ... */ } + }; + + class Domain final : public DomainServiceObject { + NON_COPYABLE(Domain); + NON_MOVEABLE(Domain); + private: + using EntryList = typename util::IntrusiveListMemberTraits<&Entry::domain_list_node>::ListType; + private: + ServerDomainManager *manager; + EntryList entries; + public: + explicit Domain(ServerDomainManager *m) : manager(m) { /* ... */ } + ~Domain(); + + void DestroySelf(); + + virtual ServerDomainBase *GetServerDomain() override final { + return static_cast(this); + } + + virtual Result ReserveIds(DomainObjectId *out_ids, size_t count) override final; + virtual void ReserveSpecificIds(const DomainObjectId *ids, size_t count) override final; + virtual void UnreserveIds(const DomainObjectId *ids, size_t count) override final; + virtual void RegisterObject(DomainObjectId id, ServiceObjectHolder &&obj) override final; + + virtual ServiceObjectHolder UnregisterObject(DomainObjectId id) override final; + virtual ServiceObjectHolder GetObject(DomainObjectId id) override final; + }; + public: + using DomainEntryStorage = TYPED_STORAGE(Entry); + using DomainStorage = TYPED_STORAGE(Domain); + private: + class EntryManager { + private: + using EntryList = typename util::IntrusiveListMemberTraits<&Entry::free_list_node>::ListType; + private: + os::Mutex lock; + EntryList free_list; + Entry *entries; + size_t num_entries; + public: + EntryManager(DomainEntryStorage *entry_storage, size_t entry_count); + ~EntryManager(); + Entry *AllocateEntry(); + void FreeEntry(Entry *); + + void AllocateSpecificEntries(const DomainObjectId *ids, size_t count); + + inline DomainObjectId GetId(Entry *e) { + const size_t index = e - this->entries; + AMS_ASSERT(index < this->num_entries); + return DomainObjectId{ u32(index + 1) }; + } + + inline Entry *GetEntry(DomainObjectId id) { + if (id == InvalidDomainObjectId) { + return nullptr; + } + const size_t index = id.value - 1; + if (!(index < this->num_entries)) { + return nullptr; + } + return this->entries + index; + } + }; + private: + os::Mutex entry_owner_lock; + EntryManager entry_manager; + private: + virtual void *AllocateDomain() = 0; + virtual void FreeDomain(void *) = 0; + protected: + ServerDomainManager(DomainEntryStorage *entry_storage, size_t entry_count) : entry_manager(entry_storage, entry_count) { /* ... */ } + + inline DomainServiceObject *AllocateDomainServiceObject() { + void *storage = this->AllocateDomain(); + if (storage == nullptr) { + return nullptr; + } + return new (storage) Domain(this); + } + public: + static void DestroyDomainServiceObject(DomainServiceObject *obj) { + static_cast(obj)->DestroySelf(); + } + }; + + +} diff --git a/libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_domain_service_object.hpp b/libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_domain_service_object.hpp new file mode 100644 index 000000000..d5f86dd28 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_domain_service_object.hpp @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "sf_cmif_service_dispatch.hpp" +#include "sf_cmif_domain_api.hpp" +#include "sf_cmif_server_message_processor.hpp" + +namespace ams::sf::cmif { + + class DomainServiceObjectDispatchTable : public impl::ServiceDispatchTableBase { + private: + Result ProcessMessageImpl(ServiceDispatchContext &ctx, ServerDomainBase *domain, const cmif::PointerAndSize &in_raw_data) const; + Result ProcessMessageForMitmImpl(ServiceDispatchContext &ctx, ServerDomainBase *domain, const cmif::PointerAndSize &in_raw_data) const; + public: + Result ProcessMessage(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) const; + Result ProcessMessageForMitm(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) const; + }; + + + class DomainServiceObjectProcessor : public ServerMessageProcessor { + private: + ServerMessageProcessor *impl_processor; + ServerDomainBase *domain; + DomainObjectId *in_object_ids; + DomainObjectId *out_object_ids; + size_t num_in_objects; + ServerMessageRuntimeMetadata impl_metadata; + public: + DomainServiceObjectProcessor(ServerDomainBase *d, DomainObjectId *in_obj_ids, size_t num_in_objs) : domain(d), in_object_ids(in_obj_ids), num_in_objects(num_in_objs) { + AMS_ASSERT(this->domain != nullptr); + AMS_ASSERT(this->in_object_ids != nullptr); + this->impl_processor = nullptr; + this->out_object_ids = nullptr; + this->impl_metadata = {}; + } + + constexpr size_t GetInObjectCount() const { + return this->num_in_objects; + } + + constexpr size_t GetOutObjectCount() const { + return this->impl_metadata.GetOutObjectCount(); + } + + constexpr size_t GetImplOutHeadersSize() const { + return this->impl_metadata.GetOutHeadersSize(); + } + + constexpr size_t GetImplOutDataTotalSize() const { + return this->impl_metadata.GetOutDataSize() + this->impl_metadata.GetOutHeadersSize(); + } + public: + /* Used to enabled templated message processors. */ + virtual void SetImplementationProcessor(ServerMessageProcessor *impl) override final { + if (this->impl_processor == nullptr) { + this->impl_processor = impl; + } else { + this->impl_processor->SetImplementationProcessor(impl); + } + + this->impl_metadata = this->impl_processor->GetRuntimeMetadata(); + } + + virtual const ServerMessageRuntimeMetadata GetRuntimeMetadata() const override final { + const auto runtime_metadata = this->impl_processor->GetRuntimeMetadata(); + + return ServerMessageRuntimeMetadata { + .in_data_size = static_cast(runtime_metadata.GetInDataSize() + runtime_metadata.GetInObjectCount() * sizeof(DomainObjectId)), + .out_data_size = static_cast(runtime_metadata.GetOutDataSize() + runtime_metadata.GetOutObjectCount() * sizeof(DomainObjectId)), + .in_headers_size = static_cast(runtime_metadata.GetInHeadersSize() + sizeof(CmifDomainInHeader)), + .out_headers_size = static_cast(runtime_metadata.GetOutHeadersSize() + sizeof(CmifDomainOutHeader)), + .in_object_count = 0, + .out_object_count = 0, + }; + } + + virtual Result PrepareForProcess(const ServiceDispatchContext &ctx, const ServerMessageRuntimeMetadata runtime_metadata) const override final; + virtual Result GetInObjects(ServiceObjectHolder *in_objects) const override final; + virtual HipcRequest PrepareForReply(const cmif::ServiceDispatchContext &ctx, PointerAndSize &out_raw_data, const ServerMessageRuntimeMetadata runtime_metadata) override final; + virtual void PrepareForErrorReply(const cmif::ServiceDispatchContext &ctx, PointerAndSize &out_raw_data, const ServerMessageRuntimeMetadata runtime_metadata) override final; + virtual void SetOutObjects(const cmif::ServiceDispatchContext &ctx, const HipcRequest &response, ServiceObjectHolder *out_objects, DomainObjectId *ids) override final; + }; + + class DomainServiceObject : public IServiceObject, public ServerDomainBase { + friend class DomainServiceObjectDispatchTable; + public: + static constexpr inline DomainServiceObjectDispatchTable s_CmifServiceDispatchTable{}; + private: + virtual ServerDomainBase *GetServerDomain() = 0; + public: + /* TODO: Implement to use domain object processor. */ + }; + + class MitmDomainServiceObject : public DomainServiceObject{}; + + static_assert(sizeof(DomainServiceObject) == sizeof(MitmDomainServiceObject)); + + template<> + struct ServiceDispatchTraits { + static_assert(std::is_base_of::value, "DomainServiceObject must derive from sf::IServiceObject"); + static_assert(!std::is_base_of::value, "DomainServiceObject must not derive from sf::IMitmServiceObject"); + using ProcessHandlerType = decltype(ServiceDispatchMeta::ProcessHandler); + + using DispatchTableType = DomainServiceObjectDispatchTable; + static constexpr ProcessHandlerType ProcessHandlerImpl = &impl::ServiceDispatchTableBase::ProcessMessage; + + static constexpr inline ServiceDispatchMeta Meta{&DomainServiceObject::s_CmifServiceDispatchTable, ProcessHandlerImpl}; + }; + + template<> + struct ServiceDispatchTraits { + static_assert(std::is_base_of::value, "MitmDomainServiceObject must derive from DomainServiceObject"); + using ProcessHandlerType = decltype(ServiceDispatchMeta::ProcessHandler); + + using DispatchTableType = DomainServiceObjectDispatchTable; + static constexpr ProcessHandlerType ProcessHandlerImpl = &impl::ServiceDispatchTableBase::ProcessMessageForMitm; + + static constexpr inline ServiceDispatchMeta Meta{&DomainServiceObject::s_CmifServiceDispatchTable, ProcessHandlerImpl}; + }; + + +} diff --git a/libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_pointer_and_size.hpp b/libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_pointer_and_size.hpp new file mode 100644 index 000000000..e957b1942 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_pointer_and_size.hpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "../sf_common.hpp" + +namespace ams::sf::cmif { + + class PointerAndSize { + private: + uintptr_t pointer; + size_t size; + public: + constexpr PointerAndSize() : pointer(0), size(0) { /* ... */ } + constexpr PointerAndSize(uintptr_t ptr, size_t sz) : pointer(ptr), size(sz) { /* ... */ } + constexpr PointerAndSize(void *ptr, size_t sz) : PointerAndSize(reinterpret_cast(ptr), sz) { /* ... */ } + + constexpr void *GetPointer() const { + return reinterpret_cast(this->pointer); + } + + constexpr uintptr_t GetAddress() const { + return this->pointer; + } + + constexpr size_t GetSize() const { + return this->size; + } + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_server_message_processor.hpp b/libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_server_message_processor.hpp new file mode 100644 index 000000000..4f97cf448 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_server_message_processor.hpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "../sf_service_object.hpp" +#include "sf_cmif_pointer_and_size.hpp" + +namespace ams::sf::cmif { + + /* Forward declare ServiceDispatchContext, ServiceObjectHolder. */ + struct ServiceDispatchContext; + class ServiceObjectHolder; + struct DomainObjectId; + + /* This is needed for non-templated domain message processing. */ + struct ServerMessageRuntimeMetadata { + u16 in_data_size; + u16 out_data_size; + u8 in_headers_size; + u8 out_headers_size; + u8 in_object_count; + u8 out_object_count; + + constexpr size_t GetInDataSize() const { + return size_t(this->in_data_size); + } + + constexpr size_t GetOutDataSize() const { + return size_t(this->out_data_size); + } + + constexpr size_t GetInHeadersSize() const { + return size_t(this->in_headers_size); + } + + constexpr size_t GetOutHeadersSize() const { + return size_t(this->out_headers_size); + } + + constexpr size_t GetInObjectCount() const { + return size_t(this->in_object_count); + } + + constexpr size_t GetOutObjectCount() const { + return size_t(this->out_object_count); + } + + constexpr size_t GetUnfixedOutPointerSizeOffset() const { + return this->GetInDataSize() + this->GetInHeadersSize() + 0x10 /* padding. */; + } + }; + + static_assert(std::is_pod::value, "std::is_pod::value"); + static_assert(sizeof(ServerMessageRuntimeMetadata) == sizeof(u64), "sizeof(ServerMessageRuntimeMetadata)"); + + class ServerMessageProcessor { + public: + /* Used to enabled templated message processors. */ + virtual void SetImplementationProcessor(ServerMessageProcessor *impl) = 0; + virtual const ServerMessageRuntimeMetadata GetRuntimeMetadata() const = 0; + + virtual Result PrepareForProcess(const ServiceDispatchContext &ctx, const ServerMessageRuntimeMetadata runtime_metadata) const = 0; + virtual Result GetInObjects(ServiceObjectHolder *in_objects) const = 0; + virtual HipcRequest PrepareForReply(const cmif::ServiceDispatchContext &ctx, PointerAndSize &out_raw_data, const ServerMessageRuntimeMetadata runtime_metadata) = 0; + virtual void PrepareForErrorReply(const cmif::ServiceDispatchContext &ctx, PointerAndSize &out_raw_data, const ServerMessageRuntimeMetadata runtime_metadata) = 0; + virtual void SetOutObjects(const cmif::ServiceDispatchContext &ctx, const HipcRequest &response, ServiceObjectHolder *out_objects, DomainObjectId *ids) = 0; + }; +} diff --git a/libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_service_dispatch.hpp b/libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_service_dispatch.hpp new file mode 100644 index 000000000..c146d8aa5 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_service_dispatch.hpp @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "../sf_service_object.hpp" +#include "sf_cmif_pointer_and_size.hpp" +#include "sf_cmif_server_message_processor.hpp" + +namespace ams::sf::hipc { + + class ServerSessionManager; + class ServerSession; + +} + +namespace ams::sf::cmif { + + class ServerMessageProcessor; + + struct HandlesToClose { + Handle handles[8]; + size_t num_handles; + }; + + struct ServiceDispatchContext { + sf::IServiceObject *srv_obj; + hipc::ServerSessionManager *manager; + hipc::ServerSession *session; + ServerMessageProcessor *processor; + HandlesToClose *handles_to_close; + const PointerAndSize pointer_buffer; + const PointerAndSize in_message_buffer; + const PointerAndSize out_message_buffer; + const HipcParsedRequest request; + }; + + struct ServiceCommandMeta { + hos::Version hosver_low; + hos::Version hosver_high; + u32 cmd_id; + Result (*handler)(CmifOutHeader **out_header_ptr, ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data); + + constexpr inline bool Matches(u32 cmd_id, hos::Version hosver) const { + return this->cmd_id == cmd_id && this->hosver_low <= hosver && hosver <= this->hosver_high; + } + + constexpr inline decltype(handler) GetHandler() const { + return this->handler; + } + }; + static_assert(std::is_pod::value && sizeof(ServiceCommandMeta) == 0x10, "sizeof(ServiceCommandMeta)"); + + namespace impl { + + class ServiceDispatchTableBase { + protected: + Result ProcessMessageImpl(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data, const ServiceCommandMeta *entries, const size_t entry_count) const; + Result ProcessMessageForMitmImpl(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data, const ServiceCommandMeta *entries, const size_t entry_count) const; + public: + /* CRTP. */ + template + Result ProcessMessage(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) const { + static_assert(std::is_base_of::value, "ServiceDispatchTableBase::Process"); + return static_cast(this)->ProcessMessage(ctx, in_raw_data); + } + + template + Result ProcessMessageForMitm(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) const { + static_assert(std::is_base_of::value, "ServiceDispatchTableBase::ProcessForMitm"); + return static_cast(this)->ProcessMessageForMitm(ctx, in_raw_data); + } + }; + + template> + class ServiceDispatchTableImpl; + + template + class ServiceDispatchTableImpl> : public ServiceDispatchTableBase { + private: + template + using EntryType = ServiceCommandMeta; + private: + const std::array entries; + public: + explicit constexpr ServiceDispatchTableImpl(EntryType... args) : entries { args... } { /* ... */ } + + Result ProcessMessage(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) const { + return this->ProcessMessageImpl(ctx, in_raw_data, this->entries.data(), this->entries.size()); + } + + Result ProcessMessageForMitm(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) const { + return this->ProcessMessageForMitmImpl(ctx, in_raw_data, this->entries.data(), this->entries.size()); + } + }; + + } + + template + class ServiceDispatchTable : public impl::ServiceDispatchTableImpl { + public: + explicit constexpr ServiceDispatchTable(Entries... entries) : impl::ServiceDispatchTableImpl(entries...) { /* ... */ } + }; + + #define DEFINE_SERVICE_DISPATCH_TABLE \ + template \ + static constexpr inline ::ams::sf::cmif::ServiceDispatchTable s_CmifServiceDispatchTable + + struct ServiceDispatchMeta { + const impl::ServiceDispatchTableBase *DispatchTable; + Result (impl::ServiceDispatchTableBase::*ProcessHandler)(ServiceDispatchContext &, const cmif::PointerAndSize &) const; + + constexpr uintptr_t GetServiceId() const { + return reinterpret_cast(this->DispatchTable); + } + }; + + template + struct ServiceDispatchTraits { + static_assert(std::is_base_of::value, "ServiceObjects must derive from sf::IServiceObject"); + + using ProcessHandlerType = decltype(ServiceDispatchMeta::ProcessHandler); + + static constexpr inline auto DispatchTable = T::template s_CmifServiceDispatchTable; + using DispatchTableType = decltype(DispatchTable); + + static constexpr ProcessHandlerType ProcessHandlerImpl = ServiceObjectTraits::IsMitmServiceObject ? (&impl::ServiceDispatchTableBase::ProcessMessageForMitm) + : (&impl::ServiceDispatchTableBase::ProcessMessage); + + static constexpr inline ServiceDispatchMeta Meta{&DispatchTable, ProcessHandlerImpl}; + }; + + template + NX_CONSTEXPR const ServiceDispatchMeta *GetServiceDispatchMeta() { + return &ServiceDispatchTraits::Meta; + } + +} diff --git a/libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_service_object_holder.hpp b/libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_service_object_holder.hpp new file mode 100644 index 000000000..12c8969b9 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_service_object_holder.hpp @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "../sf_service_object.hpp" +#include "sf_cmif_service_dispatch.hpp" + +namespace ams::sf::cmif { + + class ServiceObjectHolder { + private: + std::shared_ptr srv; + const ServiceDispatchMeta *dispatch_meta; + private: + /* Copy constructor. */ + ServiceObjectHolder(const ServiceObjectHolder &o) : srv(o.srv), dispatch_meta(o.dispatch_meta) { /* ... */ } + ServiceObjectHolder &operator=(const ServiceObjectHolder &o) = delete; + public: + /* Default constructor, null all members. */ + ServiceObjectHolder() : srv(nullptr), dispatch_meta(nullptr) { /* ... */ } + + ~ServiceObjectHolder() { + this->dispatch_meta = nullptr; + } + + /* Ensure correct type id at runtime through template constructor. */ + template + constexpr explicit ServiceObjectHolder(std::shared_ptr &&s) { + this->srv = std::move(s); + this->dispatch_meta = GetServiceDispatchMeta(); + } + + /* Move constructor, assignment operator. */ + ServiceObjectHolder(ServiceObjectHolder &&o) : srv(std::move(o.srv)), dispatch_meta(std::move(o.dispatch_meta)) { + o.dispatch_meta = nullptr; + } + + ServiceObjectHolder &operator=(ServiceObjectHolder &&o) { + ServiceObjectHolder tmp(std::move(o)); + tmp.Swap(*this); + return *this; + } + + /* State management. */ + void Swap(ServiceObjectHolder &o) { + std::swap(this->srv, o.srv); + std::swap(this->dispatch_meta, o.dispatch_meta); + } + + void Reset() { + this->srv = nullptr; + this->dispatch_meta = nullptr; + } + + ServiceObjectHolder Clone() const { + return ServiceObjectHolder(*this); + } + + /* Boolean operators. */ + explicit constexpr operator bool() const { + return this->dispatch_meta != nullptr; + } + + constexpr bool operator!() const { + return this->dispatch_meta == nullptr; + } + + /* Getters. */ + constexpr uintptr_t GetServiceId() const { + if (this->dispatch_meta) { + return this->dispatch_meta->GetServiceId(); + } + return 0; + } + + template + constexpr inline bool IsServiceObjectValid() const { + return this->GetServiceId() == GetServiceDispatchMeta()->GetServiceId(); + } + + template + inline std::shared_ptr GetServiceObject() const { + if (this->GetServiceId() == GetServiceDispatchMeta()->GetServiceId()) { + return std::static_pointer_cast(this->srv); + } + return nullptr; + } + + inline sf::IServiceObject *GetServiceObjectUnsafe() const { + return this->srv.get(); + } + + /* Processing. */ + Result ProcessMessage(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) const; + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_api.hpp b/libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_api.hpp new file mode 100644 index 000000000..cd4b3535f --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_api.hpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "../sf_common.hpp" +#include "../cmif/sf_cmif_pointer_and_size.hpp" + +namespace ams::sf::hipc { + + constexpr size_t TlsMessageBufferSize = 0x100; + + enum class ReceiveResult { + Success, + Closed, + NeedsRetry, + }; + + Result Receive(ReceiveResult *out_recv_result, Handle session_handle, const cmif::PointerAndSize &message_buffer); + Result Receive(bool *out_closed, Handle session_handle, const cmif::PointerAndSize &message_buffer); + Result Reply(Handle session_handle, const cmif::PointerAndSize &message_buffer); + + Result CreateSession(Handle *out_server_handle, Handle *out_client_handle); + +} diff --git a/libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_domain_session_manager.hpp b/libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_domain_session_manager.hpp new file mode 100644 index 000000000..38cdd574c --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_domain_session_manager.hpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "sf_hipc_server_session_manager.hpp" +#include "../cmif/sf_cmif_domain_manager.hpp" + +namespace ams::sf::hipc { + + class ServerDomainSessionManager : public ServerSessionManager, private cmif::ServerDomainManager { + protected: + using cmif::ServerDomainManager::DomainEntryStorage; + using cmif::ServerDomainManager::DomainStorage; + protected: + virtual Result DispatchManagerRequest(ServerSession *session, const cmif::PointerAndSize &in_message, const cmif::PointerAndSize &out_message) override final; + public: + ServerDomainSessionManager(DomainEntryStorage *entry_storage, size_t entry_count) : ServerDomainManager(entry_storage, entry_count) { /* ... */ } + + inline cmif::DomainServiceObject *AllocateDomainServiceObject() { + return cmif::ServerDomainManager::AllocateDomainServiceObject(); + } + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_manager.hpp b/libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_manager.hpp new file mode 100644 index 000000000..04cbd79c4 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_manager.hpp @@ -0,0 +1,394 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "sf_hipc_server_domain_session_manager.hpp" +#include "../../sm.hpp" + +namespace ams::sf::hipc { + + struct DefaultServerManagerOptions { + static constexpr size_t PointerBufferSize = 0; + static constexpr size_t MaxDomains = 0; + static constexpr size_t MaxDomainObjects = 0; + }; + + static constexpr size_t ServerSessionCountMax = 0x40; + static_assert(ServerSessionCountMax == 0x40, "ServerSessionCountMax isn't 0x40 somehow, this assert is a reminder that this will break lots of things"); + + template + class ServerManager; + + class ServerManagerBase : public ServerDomainSessionManager { + NON_COPYABLE(ServerManagerBase); + NON_MOVEABLE(ServerManagerBase); + public: + using MitmQueryFunction = bool (*)(const sm::MitmProcessInfo &); + private: + enum class UserDataTag : uintptr_t { + Server = 1, + Session = 2, + MitmServer = 3, + }; + protected: + using ServerDomainSessionManager::DomainEntryStorage; + using ServerDomainSessionManager::DomainStorage; + private: + class ServerBase : public os::WaitableHolder { + friend class ServerManagerBase; + template + friend class ServerManager; + NON_COPYABLE(ServerBase); + NON_MOVEABLE(ServerBase); + protected: + cmif::ServiceObjectHolder static_object; + ::Handle port_handle; + sm::ServiceName service_name; + bool service_managed; + public: + ServerBase(Handle ph, sm::ServiceName sn, bool m, cmif::ServiceObjectHolder &&sh) : + os::WaitableHolder(ph), static_object(std::move(sh)), port_handle(ph), service_name(sn), service_managed(m) + { + /* ... */ + } + + virtual ~ServerBase() = 0; + virtual void CreateSessionObjectHolder(cmif::ServiceObjectHolder *out_obj, std::shared_ptr<::Service> *out_fsrv) const = 0; + }; + + template> + class Server : public ServerBase { + NON_COPYABLE(Server); + NON_MOVEABLE(Server); + private: + static constexpr bool IsMitmServer = ServiceObjectTraits::IsMitmServiceObject; + public: + Server(Handle ph, sm::ServiceName sn, bool m, cmif::ServiceObjectHolder &&sh) : ServerBase(ph, sn, m, std::forward(sh)) { + /* ... */ + } + + virtual ~Server() override { + if (this->service_managed) { + if constexpr (IsMitmServer) { + R_ASSERT(sm::mitm::UninstallMitm(this->service_name)); + } else { + R_ASSERT(sm::UnregisterService(this->service_name)); + } + R_ASSERT(svcCloseHandle(this->port_handle)); + } + } + + virtual void CreateSessionObjectHolder(cmif::ServiceObjectHolder *out_obj, std::shared_ptr<::Service> *out_fsrv) const override final { + /* If we're serving a static object, use it. */ + if (this->static_object) { + *out_obj = std::move(this->static_object.Clone()); + *out_fsrv = nullptr; + return; + } + + /* Otherwise, we're either a mitm session or a non-mitm session. */ + if constexpr (IsMitmServer) { + /* Custom deleter ensures that nothing goes awry. */ + /* TODO: Should this just be a custom wrapper object? */ + std::shared_ptr<::Service> forward_service = std::move(ServerSession::CreateForwardService()); + + /* Get mitm forward session. */ + sm::MitmProcessInfo client_info; + R_ASSERT(sm::mitm::AcknowledgeSession(forward_service.get(), &client_info, this->service_name)); + + *out_obj = std::move(cmif::ServiceObjectHolder(std::move(MakeShared(std::shared_ptr<::Service>(forward_service), client_info)))); + *out_fsrv = std::move(forward_service); + } else { + *out_obj = std::move(cmif::ServiceObjectHolder(std::move(MakeShared()))); + *out_fsrv = nullptr; + } + } + }; + private: + /* Management of waitables. */ + os::WaitableManager waitable_manager; + os::Event request_stop_event; + os::WaitableHolder request_stop_event_holder; + os::Event notify_event; + os::WaitableHolder notify_event_holder; + + os::Mutex waitable_selection_mutex; + + os::Mutex waitlist_mutex; + os::WaitableManager waitlist; + + os::Mutex deferred_session_mutex; + using DeferredSessionList = typename util::IntrusiveListMemberTraits<&ServerSession::deferred_list_node>::ListType; + DeferredSessionList deferred_session_list; + private: + virtual void RegisterSessionToWaitList(ServerSession *session) override final; + void RegisterToWaitList(os::WaitableHolder *holder); + void ProcessWaitList(); + + bool WaitAndProcessImpl(); + + Result ProcessForServer(os::WaitableHolder *holder); + Result ProcessForMitmServer(os::WaitableHolder *holder); + Result ProcessForSession(os::WaitableHolder *holder); + + void ProcessDeferredSessions(); + + template> + void RegisterServerImpl(Handle port_handle, sm::ServiceName service_name, bool managed, cmif::ServiceObjectHolder &&static_holder) { + /* Allocate server memory. */ + auto *server = this->AllocateServer(); + AMS_ASSERT(server != nullptr); + new (server) Server(port_handle, service_name, managed, std::forward(static_holder)); + + if constexpr (!ServiceObjectTraits::IsMitmServiceObject) { + /* Non-mitm server. */ + server->SetUserData(static_cast(UserDataTag::Server)); + } else { + /* Mitm server. */ + server->SetUserData(static_cast(UserDataTag::MitmServer)); + } + + this->waitable_manager.LinkWaitableHolder(server); + } + + template + static constexpr inline std::shared_ptr MakeSharedMitm(std::shared_ptr<::Service> &&s, const sm::MitmProcessInfo &client_info) { + return std::make_shared(std::forward>(s), client_info); + } + + Result InstallMitmServerImpl(Handle *out_port_handle, sm::ServiceName service_name, MitmQueryFunction query_func); + protected: + virtual ServerBase *AllocateServer() = 0; + virtual void DestroyServer(ServerBase *server) = 0; + public: + ServerManagerBase(DomainEntryStorage *entry_storage, size_t entry_count) : + ServerDomainSessionManager(entry_storage, entry_count), + request_stop_event(false), request_stop_event_holder(&request_stop_event), + notify_event(false), notify_event_holder(¬ify_event) + { + /* Link waitables. */ + this->waitable_manager.LinkWaitableHolder(&this->request_stop_event_holder); + this->waitable_manager.LinkWaitableHolder(&this->notify_event_holder); + } + + template> + void RegisterServer(Handle port_handle, std::shared_ptr static_object = nullptr) { + static_assert(!ServiceObjectTraits::IsMitmServiceObject, "RegisterServer requires non-mitm object. Use RegisterMitmServer instead."); + /* Register server. */ + cmif::ServiceObjectHolder static_holder; + if (static_object != nullptr) { + static_holder = cmif::ServiceObjectHolder(std::move(static_object)); + } + this->RegisterServerImpl(port_handle, sm::InvalidServiceName, false, std::move(static_holder)); + } + + template> + Result RegisterServer(sm::ServiceName service_name, size_t max_sessions, std::shared_ptr static_object = nullptr) { + static_assert(!ServiceObjectTraits::IsMitmServiceObject, "RegisterServer requires non-mitm object. Use RegisterMitmServer instead."); + + /* Register service. */ + Handle port_handle; + R_TRY(sm::RegisterService(&port_handle, service_name, max_sessions, false)); + + /* Register server. */ + cmif::ServiceObjectHolder static_holder; + if (static_object != nullptr) { + static_holder = cmif::ServiceObjectHolder(std::move(static_object)); + } + this->RegisterServerImpl(port_handle, service_name, true, std::move(static_holder)); + return ResultSuccess(); + } + + template> + Result RegisterMitmServer(sm::ServiceName service_name) { + static_assert(ServiceObjectTraits::IsMitmServiceObject, "RegisterMitmServer requires mitm object. Use RegisterServer instead."); + + /* Install mitm service. */ + Handle port_handle; + R_TRY(this->InstallMitmServerImpl(&port_handle, service_name, &ServiceImpl::ShouldMitm)); + + this->RegisterServerImpl(port_handle, service_name, true, cmif::ServiceObjectHolder()); + return ResultSuccess(); + } + + /* Processing. */ + os::WaitableHolder *WaitSignaled(); + + void ResumeProcessing(); + void RequestStopProcessing(); + void AddUserWaitableHolder(os::WaitableHolder *waitable); + + Result Process(os::WaitableHolder *waitable); + void WaitAndProcess(); + void LoopProcess(); + }; + + template + class ServerManager : public ServerManagerBase { + NON_COPYABLE(ServerManager); + NON_MOVEABLE(ServerManager); + static_assert(MaxServers <= ServerSessionCountMax, "MaxServers can never be larger than ServerSessionCountMax (0x40)."); + static_assert(MaxSessions <= ServerSessionCountMax, "MaxSessions can never be larger than ServerSessionCountMax (0x40)."); + static_assert(MaxServers + MaxSessions <= ServerSessionCountMax, "MaxServers + MaxSessions can never be larger than ServerSessionCountMax (0x40)."); + private: + static constexpr inline bool DomainCountsValid = [] { + if constexpr (ManagerOptions::MaxDomains > 0) { + return ManagerOptions::MaxDomainObjects > 0; + } else { + return ManagerOptions::MaxDomainObjects == 0; + } + }(); + static_assert(DomainCountsValid, "Invalid Domain Counts"); + protected: + using ServerManagerBase::DomainEntryStorage; + using ServerManagerBase::DomainStorage; + private: + /* Resource storage. */ + os::Mutex resource_mutex; + TYPED_STORAGE(ServerBase) server_storages[MaxServers]; + bool server_allocated[MaxServers]; + TYPED_STORAGE(ServerSession) session_storages[MaxSessions]; + bool session_allocated[MaxSessions]; + u8 pointer_buffer_storage[0x10 + (MaxSessions * ManagerOptions::PointerBufferSize)]; + u8 saved_message_storage[0x10 + (MaxSessions * hipc::TlsMessageBufferSize)]; + uintptr_t pointer_buffers_start; + uintptr_t saved_messages_start; + + /* Domain resources. */ + DomainStorage domain_storages[ManagerOptions::MaxDomains]; + bool domain_allocated[ManagerOptions::MaxDomains]; + DomainEntryStorage domain_entry_storages[ManagerOptions::MaxDomainObjects]; + private: + constexpr inline size_t GetServerIndex(const ServerBase *server) const { + const size_t i = server - GetPointer(this->server_storages[0]); + AMS_ASSERT(i < MaxServers); + return i; + } + + constexpr inline size_t GetSessionIndex(const ServerSession *session) const { + const size_t i = session - GetPointer(this->session_storages[0]); + AMS_ASSERT(i < MaxSessions); + return i; + } + + constexpr inline cmif::PointerAndSize GetObjectBySessionIndex(const ServerSession *session, uintptr_t start, size_t size) const { + return cmif::PointerAndSize(start + this->GetSessionIndex(session) * size, size); + } + protected: + virtual ServerSession *AllocateSession() override final { + std::scoped_lock lk(this->resource_mutex); + for (size_t i = 0; i < MaxSessions; i++) { + if (!this->session_allocated[i]) { + this->session_allocated[i] = true; + return GetPointer(this->session_storages[i]); + } + } + return nullptr; + } + + virtual void FreeSession(ServerSession *session) override final { + std::scoped_lock lk(this->resource_mutex); + const size_t index = this->GetSessionIndex(session); + AMS_ASSERT(this->session_allocated[index]); + this->session_allocated[index] = false; + } + + virtual ServerBase *AllocateServer() override final { + std::scoped_lock lk(this->resource_mutex); + for (size_t i = 0; i < MaxServers; i++) { + if (!this->server_allocated[i]) { + this->server_allocated[i] = true; + return GetPointer(this->server_storages[i]); + } + } + return nullptr; + } + + virtual void DestroyServer(ServerBase *server) override final { + std::scoped_lock lk(this->resource_mutex); + const size_t index = this->GetServerIndex(server); + AMS_ASSERT(this->server_allocated[index]); + server->~ServerBase(); + this->server_allocated[index] = false; + } + + virtual void *AllocateDomain() override final { + std::scoped_lock lk(this->resource_mutex); + for (size_t i = 0; i < ManagerOptions::MaxDomains; i++) { + if (!this->domain_allocated[i]) { + this->domain_allocated[i] = true; + return GetPointer(this->domain_storages[i]); + } + } + return nullptr; + } + + virtual void FreeDomain(void *domain) override final { + std::scoped_lock lk(this->resource_mutex); + DomainStorage *ptr = static_cast(domain); + const size_t index = ptr - this->domain_storages; + AMS_ASSERT(index < ManagerOptions::MaxDomains); + AMS_ASSERT(this->domain_allocated[index]); + this->domain_allocated[index] = false; + } + + virtual cmif::PointerAndSize GetSessionPointerBuffer(const ServerSession *session) const override final { + if constexpr (ManagerOptions::PointerBufferSize > 0) { + return this->GetObjectBySessionIndex(session, this->pointer_buffers_start, ManagerOptions::PointerBufferSize); + } else { + return cmif::PointerAndSize(); + } + } + + virtual cmif::PointerAndSize GetSessionSavedMessageBuffer(const ServerSession *session) const override final { + return this->GetObjectBySessionIndex(session, this->saved_messages_start, hipc::TlsMessageBufferSize); + } + public: + ServerManager() : ServerManagerBase(this->domain_entry_storages, ManagerOptions::MaxDomainObjects) { + /* Clear storages. */ + #define SF_SM_MEMCLEAR(obj) if constexpr (sizeof(obj) > 0) { std::memset(obj, 0, sizeof(obj)); } + SF_SM_MEMCLEAR(this->server_storages); + SF_SM_MEMCLEAR(this->server_allocated); + SF_SM_MEMCLEAR(this->session_storages); + SF_SM_MEMCLEAR(this->session_allocated); + SF_SM_MEMCLEAR(this->pointer_buffer_storage); + SF_SM_MEMCLEAR(this->saved_message_storage); + SF_SM_MEMCLEAR(this->domain_allocated); + #undef SF_SM_MEMCLEAR + + /* Set resource starts. */ + this->pointer_buffers_start = util::AlignUp(reinterpret_cast(this->pointer_buffer_storage), 0x10); + this->saved_messages_start = util::AlignUp(reinterpret_cast(this->saved_message_storage), 0x10); + } + + ~ServerManager() { + /* Close all sessions. */ + for (size_t i = 0; i < MaxSessions; i++) { + if (this->session_allocated[i]) { + this->CloseSessionImpl(GetPointer(this->session_storages[i])); + } + } + + /* Close all servers. */ + for (size_t i = 0; i < MaxServers; i++) { + if (this->server_allocated[i]) { + this->DestroyServer(GetPointer(this->server_storages[i])); + } + } + } + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_session_manager.hpp b/libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_session_manager.hpp new file mode 100644 index 000000000..bc3da6fa6 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_session_manager.hpp @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "../sf_common.hpp" +#include "../sf_service_object.hpp" +#include "../cmif/sf_cmif_pointer_and_size.hpp" +#include "../cmif/sf_cmif_service_object_holder.hpp" +#include "sf_hipc_api.hpp" + +namespace ams::sf::cmif { + + struct ServiceDispatchContext; + +} + +namespace ams::sf::hipc { + + class ServerSessionManager; + class ServerManagerBase; + + namespace impl { + + class HipcManager; + + } + + class ServerSession : public os::WaitableHolder { + friend class ServerSessionManager; + friend class ServerManagerBase; + friend class impl::HipcManager; + NON_COPYABLE(ServerSession); + NON_MOVEABLE(ServerSession); + private: + util::IntrusiveListNode deferred_list_node; + cmif::ServiceObjectHolder srv_obj_holder; + cmif::PointerAndSize pointer_buffer; + cmif::PointerAndSize saved_message; + std::shared_ptr<::Service> forward_service; + Handle session_handle; + bool is_closed; + bool has_received; + public: + ServerSession(Handle h, cmif::ServiceObjectHolder &&obj) : WaitableHolder(h), srv_obj_holder(std::move(obj)), session_handle(h) { + this->is_closed = false; + this->has_received = false; + this->forward_service = nullptr; + AMS_ASSERT(!this->IsMitmSession()); + } + + ServerSession(Handle h, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv) : WaitableHolder(h), srv_obj_holder(std::move(obj)), session_handle(h) { + this->is_closed = false; + this->has_received = false; + this->forward_service = std::move(fsrv); + AMS_ASSERT(this->IsMitmSession()); + } + + bool IsMitmSession() const { + return this->forward_service != nullptr; + } + + Result ForwardRequest(const cmif::ServiceDispatchContext &ctx) const; + + static inline void ForwardServiceDeleter(Service *srv) { + serviceClose(srv); + delete srv; + } + + static inline std::shared_ptr<::Service> CreateForwardService() { + return std::shared_ptr<::Service>(new ::Service(), ForwardServiceDeleter); + } + }; + + class ServerSessionManager { + private: + template + Result CreateSessionImpl(ServerSession **out, const Constructor &ctor) { + /* Allocate session. */ + ServerSession *session_memory = this->AllocateSession(); + R_UNLESS(session_memory != nullptr, sf::hipc::ResultOutOfSessionMemory()); + /* Register session. */ + bool succeeded = false; + ON_SCOPE_EXIT { + if (!succeeded) { + this->DestroySession(session_memory); + } + }; + R_TRY(ctor(session_memory)); + /* Save new session to output. */ + succeeded = true; + *out = session_memory; + return ResultSuccess(); + } + void DestroySession(ServerSession *session); + + Result ProcessRequestImpl(ServerSession *session, const cmif::PointerAndSize &in_message, const cmif::PointerAndSize &out_message); + virtual void RegisterSessionToWaitList(ServerSession *session) = 0; + protected: + Result DispatchRequest(cmif::ServiceObjectHolder &&obj, ServerSession *session, const cmif::PointerAndSize &in_message, const cmif::PointerAndSize &out_message); + virtual Result DispatchManagerRequest(ServerSession *session, const cmif::PointerAndSize &in_message, const cmif::PointerAndSize &out_message); + protected: + virtual ServerSession *AllocateSession() = 0; + virtual void FreeSession(ServerSession *session) = 0; + virtual cmif::PointerAndSize GetSessionPointerBuffer(const ServerSession *session) const = 0; + virtual cmif::PointerAndSize GetSessionSavedMessageBuffer(const ServerSession *session) const = 0; + + Result ReceiveRequestImpl(ServerSession *session, const cmif::PointerAndSize &message); + void CloseSessionImpl(ServerSession *session); + Result RegisterSessionImpl(ServerSession *session_memory, Handle session_handle, cmif::ServiceObjectHolder &&obj); + Result AcceptSessionImpl(ServerSession *session_memory, Handle port_handle, cmif::ServiceObjectHolder &&obj); + Result RegisterMitmSessionImpl(ServerSession *session_memory, Handle mitm_session_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv); + Result AcceptMitmSessionImpl(ServerSession *session_memory, Handle mitm_port_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv); + + Result ReceiveRequest(ServerSession *session, const cmif::PointerAndSize &message) { + return this->ReceiveRequestImpl(session, message); + } + + Result RegisterSession(ServerSession **out, Handle session_handle, cmif::ServiceObjectHolder &&obj) { + auto ctor = [&](ServerSession *session_memory) -> Result { + return this->RegisterSessionImpl(session_memory, session_handle, std::forward(obj)); + }; + return this->CreateSessionImpl(out, ctor); + } + + Result AcceptSession(ServerSession **out, Handle port_handle, cmif::ServiceObjectHolder &&obj) { + auto ctor = [&](ServerSession *session_memory) -> Result { + return this->AcceptSessionImpl(session_memory, port_handle, std::forward(obj)); + }; + return this->CreateSessionImpl(out, ctor); + } + + Result RegisterMitmSession(ServerSession **out, Handle mitm_session_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv) { + auto ctor = [&](ServerSession *session_memory) -> Result { + return this->RegisterMitmSessionImpl(session_memory, mitm_session_handle, std::forward(obj), std::forward>(fsrv)); + }; + return this->CreateSessionImpl(out, ctor); + } + + Result AcceptMitmSession(ServerSession **out, Handle mitm_port_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv) { + auto ctor = [&](ServerSession *session_memory) -> Result { + return this->AcceptMitmSessionImpl(session_memory, mitm_port_handle, std::forward(obj), std::forward>(fsrv)); + }; + return this->CreateSessionImpl(out, ctor); + } + public: + Result RegisterSession(Handle session_handle, cmif::ServiceObjectHolder &&obj); + Result AcceptSession(Handle port_handle, cmif::ServiceObjectHolder &&obj); + Result RegisterMitmSession(Handle session_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv); + Result AcceptMitmSession(Handle mitm_port_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv); + + template + Result AcceptSession(Handle port_handle, std::shared_ptr obj) { + return this->AcceptSession(port_handle, cmif::ServiceObjectHolder(std::move(obj))); + } + + template + Result AcceptMitmSession(Handle mitm_port_handle, std::shared_ptr obj, std::shared_ptr<::Service> &&fsrv) { + return this->AcceptMitmSession(mitm_port_handle, cmif::ServiceObjectHolder(std::move(obj)), std::forward>(fsrv)); + } + + Result ProcessRequest(ServerSession *session, const cmif::PointerAndSize &message); + + virtual ServerSessionManager *GetSessionManagerByTag(u32 tag) { + /* This is unused. */ + return this; + } + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/sf/impl/sf_impl_command_serialization.hpp b/libraries/libstratosphere/include/stratosphere/sf/impl/sf_impl_command_serialization.hpp new file mode 100644 index 000000000..794aae6df --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/sf/impl/sf_impl_command_serialization.hpp @@ -0,0 +1,1161 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "../sf_common.hpp" +#include "../sf_service_object.hpp" +#include "../sf_out.hpp" +#include "../sf_buffers.hpp" +#include "../sf_handles.hpp" +#include "../cmif/sf_cmif_pointer_and_size.hpp" +#include "../cmif/sf_cmif_service_dispatch.hpp" +#include "../cmif/sf_cmif_service_object_holder.hpp" +#include "../cmif/sf_cmif_domain_api.hpp" +#include "../hipc/sf_hipc_api.hpp" +#include "../hipc/sf_hipc_server_session_manager.hpp" + +/* Serialization classes. */ +namespace ams::sf { + + namespace impl { + + struct ProcessIdHolder { + os::ProcessId process_id; + + constexpr explicit operator os::ProcessId() const { return this->process_id; } + constexpr os::ProcessId GetValue() const { return this->process_id; } + constexpr void SetValue(const os::ProcessId &p) { this->process_id = p; } + }; + + } + + struct ClientProcessId : public impl::ProcessIdHolder {}; + static_assert(std::is_trivial::value && sizeof(ClientProcessId) == sizeof(os::ProcessId), "ClientProcessId"); + + struct ClientAppletResourceUserId : public impl::ProcessIdHolder {}; + static_assert(std::is_trivial::value && sizeof(ClientAppletResourceUserId ) == sizeof(os::ProcessId), "ClientAppletResourceUserId"); + + namespace impl { + + constexpr inline Result MarshalProcessId(ClientProcessId &client, const os::ProcessId &client_process_id) { + client.SetValue(client_process_id); + return ResultSuccess(); + } + + constexpr inline Result MarshalProcessId(ClientAppletResourceUserId &client, const os::ProcessId &client_process_id) { + if (client.GetValue() != client_process_id && client.GetValue() != os::ProcessId{}) { + return sf::ResultPreconditionViolation(); + } + return ResultSuccess(); + } + + } + + namespace impl { + + struct OutObjectTag{}; + + } + + template + class IsOutForceEnabled> : public std::true_type{}; + + template + class Out> : public impl::OutObjectTag { + static_assert(std::is_base_of::value, "Out> requires ServiceObject base."); + + template + friend class Out; + + public: + using ServiceImplType = ServiceImpl; + private: + cmif::ServiceObjectHolder *srv; + cmif::DomainObjectId *object_id; + public: + Out(cmif::ServiceObjectHolder *s, cmif::DomainObjectId *o) : srv(s), object_id(o) { /* ... */ } + + void SetValue(std::shared_ptr &&s, cmif::DomainObjectId new_object_id = cmif::InvalidDomainObjectId) { + *this->srv = cmif::ServiceObjectHolder(std::move(s)); + if (new_object_id != cmif::InvalidDomainObjectId) { + *this->object_id = new_object_id; + } + } + }; + +} + + +namespace ams::sf::impl { + + /* Machinery for filtering type lists. */ + template + struct TupleCat; + + template + struct TupleCat, std::tuple> { + using type = std::tuple; + }; + + template