diff --git a/.gitignore b/.gitignore index 92af657b0..e4678951a 100644 --- a/.gitignore +++ b/.gitignore @@ -84,6 +84,9 @@ dkms.conf .**/ +# macOS horseshittery +.DS_Store + # NOTE: make sure to make exceptions to this pattern when needed! *.bin *.enc diff --git a/Makefile b/Makefile index 80b4e1e1d..d85056f77 100644 --- a/Makefile +++ b/Makefile @@ -1,186 +1,42 @@ -ifeq ($(strip $(DEVKITPRO)),) -$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=devkitPro) -endif +ATMOSPHERE_BUILD_CONFIGS := +all: nx_release +clean: clean-nx_release -include $(DEVKITPRO)/devkitA64/base_tools +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) -TOPTARGETS := all clean dist-no-debug dist -AMSBRANCH := $(shell git symbolic-ref --short HEAD) -AMSHASH := $(shell git rev-parse --short HEAD) -AMSREV := $(AMSBRANCH)-$(AMSHASH) +define ATMOSPHERE_ADD_TARGET -ifneq (, $(strip $(shell git status --porcelain 2>/dev/null))) - AMSREV := $(AMSREV)-dirty -endif +ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -COMPONENTS := fusee stratosphere mesosphere exosphere emummc thermosphere troposphere libraries +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/atmosphere.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -all: $(COMPONENTS) - $(eval MAJORVER = $(shell grep 'define ATMOSPHERE_RELEASE_VERSION_MAJOR\b' libraries/libvapours/include/vapours/ams/ams_api_version.h \ - | tr -s [:blank:] \ - | cut -d' ' -f3)) - $(eval MINORVER = $(shell grep 'define ATMOSPHERE_RELEASE_VERSION_MINOR\b' libraries/libvapours/include/vapours/ams/ams_api_version.h \ - | tr -s [:blank:] \ - | cut -d' ' -f3)) - $(eval MICROVER = $(shell grep 'define ATMOSPHERE_RELEASE_VERSION_MICRO\b' libraries/libvapours/include/vapours/ams/ams_api_version.h \ - | tr -s [:blank:] \ - | cut -d' ' -f3)) - $(eval S_MAJORVER = $(shell grep 'define ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR\b' libraries/libvapours/include/vapours/ams/ams_api_version.h \ - | tr -s [:blank:] \ - | cut -d' ' -f3)) - $(eval S_MINORVER = $(shell grep 'define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR\b' libraries/libvapours/include/vapours/ams/ams_api_version.h \ - | tr -s [:blank:] \ - | cut -d' ' -f3)) - $(eval S_MICROVER = $(shell grep 'define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO\b' libraries/libvapours/include/vapours/ams/ams_api_version.h \ - | tr -s [:blank:] \ - | cut -d' ' -f3)) - @python fusee/build_package3.py $(CURDIR) release $(AMSHASH) $(MAJORVER) $(MINORVER) $(MICROVER) 0 $(S_MAJORVER) $(S_MINORVER) $(S_MICROVER) 0 - @echo "Built package3!" +clean-$(strip $1): + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/atmosphere.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -thermosphere: - $(MAKE) -C thermosphere all +endef -exosphere: thermosphere - $(MAKE) -C exosphere all +define ATMOSPHERE_ADD_TARGETS -stratosphere: exosphere libraries - $(MAKE) -C stratosphere all +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ +)) -mesosphere: exosphere libraries - $(MAKE) -C mesosphere all +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ +)) -troposphere: stratosphere - $(MAKE) -C troposphere all +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ +)) -emummc: - $(MAKE) -C emummc all +endef -fusee: exosphere mesosphere stratosphere - $(MAKE) -C $@ all +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) -libraries: - $(MAKE) -C libraries all +clean-all: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) -clean: - $(MAKE) -C fusee clean - $(MAKE) -C emummc clean - $(MAKE) -C libraries clean - $(MAKE) -C exosphere clean - $(MAKE) -C thermosphere clean - $(MAKE) -C mesosphere clean - $(MAKE) -C stratosphere clean - rm -rf out - -dist-no-debug: all - $(eval MAJORVER = $(shell grep 'define ATMOSPHERE_RELEASE_VERSION_MAJOR\b' libraries/libvapours/include/vapours/ams/ams_api_version.h \ - | tr -s [:blank:] \ - | cut -d' ' -f3)) - $(eval MINORVER = $(shell grep 'define ATMOSPHERE_RELEASE_VERSION_MINOR\b' libraries/libvapours/include/vapours/ams/ams_api_version.h \ - | tr -s [:blank:] \ - | cut -d' ' -f3)) - $(eval MICROVER = $(shell grep 'define ATMOSPHERE_RELEASE_VERSION_MICRO\b' libraries/libvapours/include/vapours/ams/ams_api_version.h \ - | tr -s [:blank:] \ - | cut -d' ' -f3)) - $(eval AMSVER = $(MAJORVER).$(MINORVER).$(MICROVER)-$(AMSREV)) - rm -rf atmosphere-$(AMSVER) - rm -rf out - mkdir atmosphere-$(AMSVER) - mkdir atmosphere-$(AMSVER)/atmosphere - mkdir atmosphere-$(AMSVER)/switch - mkdir -p atmosphere-$(AMSVER)/atmosphere/fatal_errors - mkdir -p atmosphere-$(AMSVER)/atmosphere/config_templates - mkdir -p atmosphere-$(AMSVER)/atmosphere/config - mkdir -p atmosphere-$(AMSVER)/atmosphere/flags - cp fusee/fusee.bin atmosphere-$(AMSVER)/atmosphere/reboot_payload.bin - cp fusee/package3 atmosphere-$(AMSVER)/atmosphere/package3 - cp config_templates/stratosphere.ini atmosphere-$(AMSVER)/atmosphere/config_templates/stratosphere.ini - cp config_templates/override_config.ini atmosphere-$(AMSVER)/atmosphere/config_templates/override_config.ini - cp config_templates/system_settings.ini atmosphere-$(AMSVER)/atmosphere/config_templates/system_settings.ini - cp config_templates/exosphere.ini atmosphere-$(AMSVER)/atmosphere/config_templates/exosphere.ini - mkdir -p config_templates/kip_patches - cp -r config_templates/kip_patches atmosphere-$(AMSVER)/atmosphere/kip_patches - cp -r config_templates/hbl_html atmosphere-$(AMSVER)/atmosphere/hbl_html - mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000008 - mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000000D - mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000017 - mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000002B - mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000032 - mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000034 - mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000036 - mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000037 - mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000003C - mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000042 - mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000420 - mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000B240 - mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000D609 - mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000D623 - cp stratosphere/boot2/boot2.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000008/exefs.nsp - cp stratosphere/dmnt/dmnt.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000000D/exefs.nsp - cp stratosphere/cs/cs.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000017/exefs.nsp - cp stratosphere/erpt/erpt.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000002B/exefs.nsp - cp stratosphere/eclct.stub/eclct.stub.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000032/exefs.nsp - cp stratosphere/fatal/fatal.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000034/exefs.nsp - cp stratosphere/creport/creport.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000036/exefs.nsp - cp stratosphere/ro/ro.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000037/exefs.nsp - cp stratosphere/jpegdec/jpegdec.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000003C/exefs.nsp - cp stratosphere/pgl/pgl.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000042/exefs.nsp - cp stratosphere/LogManager/LogManager.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000420/exefs.nsp - cp stratosphere/htc/htc.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000B240/exefs.nsp - cp stratosphere/dmnt.gen2/dmnt.gen2.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000D609/exefs.nsp - cp stratosphere/TioServer/TioServer.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000D623/exefs.nsp - @build_romfs atmosphere-$(AMSVER)/stratosphere_romfs atmosphere-$(AMSVER)/atmosphere/stratosphere.romfs - rm -r atmosphere-$(AMSVER)/stratosphere_romfs - cp troposphere/reboot_to_payload/reboot_to_payload.nro atmosphere-$(AMSVER)/switch/reboot_to_payload.nro - cp troposphere/daybreak/daybreak.nro atmosphere-$(AMSVER)/switch/daybreak.nro - cd atmosphere-$(AMSVER); zip -r ../atmosphere-$(AMSVER).zip ./*; cd ../; - rm -rf atmosphere-$(AMSVER) - mkdir out - mv atmosphere-$(AMSVER).zip out/atmosphere-$(AMSVER).zip - cp fusee/fusee.bin out/fusee.bin - -dist: dist-no-debug - $(eval MAJORVER = $(shell grep 'define ATMOSPHERE_RELEASE_VERSION_MAJOR\b' libraries/libvapours/include/vapours/ams/ams_api_version.h \ - | tr -s [:blank:] \ - | cut -d' ' -f3)) - $(eval MINORVER = $(shell grep 'define ATMOSPHERE_RELEASE_VERSION_MINOR\b' libraries/libvapours/include/vapours/ams/ams_api_version.h \ - | tr -s [:blank:] \ - | cut -d' ' -f3)) - $(eval MICROVER = $(shell grep 'define ATMOSPHERE_RELEASE_VERSION_MICRO\b' libraries/libvapours/include/vapours/ams/ams_api_version.h \ - | tr -s [:blank:] \ - | cut -d' ' -f3)) - $(eval AMSVER = $(MAJORVER).$(MINORVER).$(MICROVER)-$(AMSREV)) - rm -rf atmosphere-$(AMSVER)-debug - mkdir atmosphere-$(AMSVER)-debug - cp fusee/loader_stub/loader_stub.elf atmosphere-$(AMSVER)-debug/fusee-loader-stub.elf - cp fusee/program/program.elf atmosphere-$(AMSVER)-debug/fusee-program.elf - cp exosphere/loader_stub/loader_stub.elf atmosphere-$(AMSVER)-debug/exosphere-loader-stub.elf - cp exosphere/program/program.elf atmosphere-$(AMSVER)-debug/exosphere-program.elf - cp exosphere/warmboot/warmboot.elf atmosphere-$(AMSVER)-debug/exosphere-warmboot.elf - cp exosphere/mariko_fatal/mariko_fatal.elf atmosphere-$(AMSVER)-debug/exosphere-mariko-fatal.elf - cp exosphere/program/sc7fw/sc7fw.elf atmosphere-$(AMSVER)-debug/exosphere-sc7fw.elf - cp exosphere/program/rebootstub/rebootstub.elf atmosphere-$(AMSVER)-debug/exosphere-rebootstub.elf - cp mesosphere/kernel_ldr/kernel_ldr.elf atmosphere-$(AMSVER)-debug/kernel_ldr.elf - cp mesosphere/kernel/kernel.elf atmosphere-$(AMSVER)-debug/kernel.elf - cp stratosphere/ams_mitm/ams_mitm.elf atmosphere-$(AMSVER)-debug/ams_mitm.elf - cp stratosphere/boot/boot.elf atmosphere-$(AMSVER)-debug/boot.elf - cp stratosphere/boot2/boot2.elf atmosphere-$(AMSVER)-debug/boot2.elf - cp stratosphere/creport/creport.elf atmosphere-$(AMSVER)-debug/creport.elf - cp stratosphere/dmnt/dmnt.elf atmosphere-$(AMSVER)-debug/dmnt.elf - cp stratosphere/eclct.stub/eclct.stub.elf atmosphere-$(AMSVER)-debug/eclct.stub.elf - cp stratosphere/erpt/erpt.elf atmosphere-$(AMSVER)-debug/erpt.elf - cp stratosphere/fatal/fatal.elf atmosphere-$(AMSVER)-debug/fatal.elf - cp stratosphere/jpegdec/jpegdec.elf atmosphere-$(AMSVER)-debug/jpegdec.elf - cp stratosphere/loader/loader.elf atmosphere-$(AMSVER)-debug/loader.elf - cp stratosphere/ncm/ncm.elf atmosphere-$(AMSVER)-debug/ncm.elf - cp stratosphere/pgl/pgl.elf atmosphere-$(AMSVER)-debug/pgl.elf - cp stratosphere/pm/pm.elf atmosphere-$(AMSVER)-debug/pm.elf - cp stratosphere/ro/ro.elf atmosphere-$(AMSVER)-debug/ro.elf - cp stratosphere/sm/sm.elf atmosphere-$(AMSVER)-debug/sm.elf - cp stratosphere/spl/spl.elf atmosphere-$(AMSVER)-debug/spl.elf - cp troposphere/daybreak/daybreak.elf atmosphere-$(AMSVER)-debug/daybreak.elf - cd atmosphere-$(AMSVER)-debug; zip -r ../atmosphere-$(AMSVER)-debug.zip ./*; cd ../; - rm -r atmosphere-$(AMSVER)-debug - mv atmosphere-$(AMSVER)-debug.zip out/atmosphere-$(AMSVER)-debug.zip - - -.PHONY: $(TOPTARGETS) $(COMPONENTS) +.PHONY: all clean clean-all $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/atmosphere.mk b/atmosphere.mk new file mode 100644 index 000000000..89b8c5778 --- /dev/null +++ b/atmosphere.mk @@ -0,0 +1,167 @@ +#--------------------------------------------------------------------------------- +# pull in common atmosphere configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(CURRENT_DIRECTORY)/libraries/config/common.mk + +# Get Atmosphere version fields +ATMOSPHERE_MAJOR_VERSION := $(shell grep 'define ATMOSPHERE_RELEASE_VERSION_MAJOR\b' $(ATMOSPHERE_LIBRARIES_DIR)/libvapours/include/vapours/ams/ams_api_version.h | tr -s [:blank:] | cut -d' ' -f3) +ATMOSPHERE_MINOR_VERSION := $(shell grep 'define ATMOSPHERE_RELEASE_VERSION_MINOR\b' $(ATMOSPHERE_LIBRARIES_DIR)/libvapours/include/vapours/ams/ams_api_version.h | tr -s [:blank:] | cut -d' ' -f3) +ATMOSPHERE_MICRO_VERSION := $(shell grep 'define ATMOSPHERE_RELEASE_VERSION_MICRO\b' $(ATMOSPHERE_LIBRARIES_DIR)/libvapours/include/vapours/ams/ams_api_version.h | tr -s [:blank:] | cut -d' ' -f3) +ATMOSPHERE_SUPPORTED_HOS_MAJOR_VERSION := $(shell grep 'define ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR\b' $(ATMOSPHERE_LIBRARIES_DIR)/libvapours/include/vapours/ams/ams_api_version.h | tr -s [:blank:] | cut -d' ' -f3) +ATMOSPHERE_SUPPORTED_HOS_MINOR_VERSION := $(shell grep 'define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR\b' $(ATMOSPHERE_LIBRARIES_DIR)/libvapours/include/vapours/ams/ams_api_version.h | tr -s [:blank:] | cut -d' ' -f3) +ATMOSPHERE_SUPPORTED_HOS_MICRO_VERSION := $(shell grep 'define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO\b' $(ATMOSPHERE_LIBRARIES_DIR)/libvapours/include/vapours/ams/ams_api_version.h | tr -s [:blank:] | cut -d' ' -f3) + +ATMOSPHERE_VERSION := $(ATMOSPHERE_MAJOR_VERSION).$(ATMOSPHERE_MINOR_VERSION).$(ATMOSPHERE_MICRO_VERSION)-$(ATMOSPHERE_GIT_REVISION) + +dist: dist-no-debug + $(eval DIST_DIR = $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/atmosphere-$(ATMOSPHERE_VERSION)-debug) + rm -rf $(DIST_DIR) + mkdir $(DIST_DIR) + cp $(CURRENT_DIRECTORY)/fusee/loader_stub/$(ATMOSPHERE_BOOT_OUT_DIR)/loader_stub.elf $(DIST_DIR)/fusee-loader-stub.elf + cp $(CURRENT_DIRECTORY)/fusee/program/$(ATMOSPHERE_BOOT_OUT_DIR)/program.elf $(DIST_DIR)/fusee-program.elf + cp $(CURRENT_DIRECTORY)/exosphere/loader_stub/$(ATMOSPHERE_OUT_DIR)/loader_stub.elf $(DIST_DIR)/exosphere-loader-stub.elf + cp $(CURRENT_DIRECTORY)/exosphere/program/$(ATMOSPHERE_OUT_DIR)/program.elf $(DIST_DIR)/exosphere-program.elf + cp $(CURRENT_DIRECTORY)/exosphere/warmboot/$(ATMOSPHERE_BOOT_OUT_DIR)/warmboot.elf $(DIST_DIR)/exosphere-warmboot.elf + cp $(CURRENT_DIRECTORY)/exosphere/mariko_fatal/$(ATMOSPHERE_OUT_DIR)/mariko_fatal.elf $(DIST_DIR)/exosphere-mariko-fatal.elf + cp $(CURRENT_DIRECTORY)/exosphere/program/sc7fw/$(ATMOSPHERE_BOOT_OUT_DIR)/sc7fw.elf $(DIST_DIR)/exosphere-sc7fw.elf + cp $(CURRENT_DIRECTORY)/exosphere/program/rebootstub/$(ATMOSPHERE_BOOT_OUT_DIR)/rebootstub.elf $(DIST_DIR)/exosphere-rebootstub.elf + cp $(CURRENT_DIRECTORY)/mesosphere/kernel_ldr/$(ATMOSPHERE_OUT_DIR)/kernel_ldr.elf $(DIST_DIR)/kernel_ldr.elf + cp $(CURRENT_DIRECTORY)/mesosphere/kernel/$(ATMOSPHERE_OUT_DIR)/kernel.elf $(DIST_DIR)/kernel.elf + cp $(CURRENT_DIRECTORY)/stratosphere/ams_mitm/$(ATMOSPHERE_OUT_DIR)/ams_mitm.elf $(DIST_DIR)/ams_mitm.elf + cp $(CURRENT_DIRECTORY)/stratosphere/boot/$(ATMOSPHERE_OUT_DIR)/boot.elf $(DIST_DIR)/boot.elf + cp $(CURRENT_DIRECTORY)/stratosphere/boot2/$(ATMOSPHERE_OUT_DIR)/boot2.elf $(DIST_DIR)/boot2.elf + cp $(CURRENT_DIRECTORY)/stratosphere/creport/$(ATMOSPHERE_OUT_DIR)/creport.elf $(DIST_DIR)/creport.elf + cp $(CURRENT_DIRECTORY)/stratosphere/cs/$(ATMOSPHERE_OUT_DIR)/cs.elf $(DIST_DIR)/cs.elf + cp $(CURRENT_DIRECTORY)/stratosphere/dmnt/$(ATMOSPHERE_OUT_DIR)/dmnt.elf $(DIST_DIR)/dmnt.elf + cp $(CURRENT_DIRECTORY)/stratosphere/dmnt.gen2/$(ATMOSPHERE_OUT_DIR)/dmnt.gen2.elf $(DIST_DIR)/dmnt.gen2.elf + cp $(CURRENT_DIRECTORY)/stratosphere/eclct.stub/$(ATMOSPHERE_OUT_DIR)/eclct.stub.elf $(DIST_DIR)/eclct.stub.elf + cp $(CURRENT_DIRECTORY)/stratosphere/erpt/$(ATMOSPHERE_OUT_DIR)/erpt.elf $(DIST_DIR)/erpt.elf + cp $(CURRENT_DIRECTORY)/stratosphere/fatal/$(ATMOSPHERE_OUT_DIR)/fatal.elf $(DIST_DIR)/fatal.elf + cp $(CURRENT_DIRECTORY)/stratosphere/htc/$(ATMOSPHERE_OUT_DIR)/htc.elf $(DIST_DIR)/htc.elf + cp $(CURRENT_DIRECTORY)/stratosphere/jpegdec/$(ATMOSPHERE_OUT_DIR)/jpegdec.elf $(DIST_DIR)/jpegdec.elf + cp $(CURRENT_DIRECTORY)/stratosphere/loader/$(ATMOSPHERE_OUT_DIR)/loader.elf $(DIST_DIR)/loader.elf + cp $(CURRENT_DIRECTORY)/stratosphere/LogManager/$(ATMOSPHERE_OUT_DIR)/LogManager.elf $(DIST_DIR)/LogManager.elf + cp $(CURRENT_DIRECTORY)/stratosphere/ncm/$(ATMOSPHERE_OUT_DIR)/ncm.elf $(DIST_DIR)/ncm.elf + cp $(CURRENT_DIRECTORY)/stratosphere/pgl/$(ATMOSPHERE_OUT_DIR)/pgl.elf $(DIST_DIR)/pgl.elf + cp $(CURRENT_DIRECTORY)/stratosphere/pm/$(ATMOSPHERE_OUT_DIR)/pm.elf $(DIST_DIR)/pm.elf + cp $(CURRENT_DIRECTORY)/stratosphere/ro/$(ATMOSPHERE_OUT_DIR)/ro.elf $(DIST_DIR)/ro.elf + cp $(CURRENT_DIRECTORY)/stratosphere/sm/$(ATMOSPHERE_OUT_DIR)/sm.elf $(DIST_DIR)/sm.elf + cp $(CURRENT_DIRECTORY)/stratosphere/spl/$(ATMOSPHERE_OUT_DIR)/spl.elf $(DIST_DIR)/spl.elf + cp $(CURRENT_DIRECTORY)/stratosphere/TioServer/$(ATMOSPHERE_OUT_DIR)/TioServer.elf $(DIST_DIR)/TioServer.elf + cp $(CURRENT_DIRECTORY)/troposphere/daybreak/daybreak.elf $(DIST_DIR)/daybreak.elf + cd $(DIST_DIR); zip -r ../atmosphere-$(ATMOSPHERE_VERSION)-debug.zip ./*; cd ../; + rm -rf $(DIST_DIR) + +dist-no-debug: package3 $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR) + $(eval DIST_DIR = $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/atmosphere-$(ATMOSPHERE_VERSION)) + rm -rf $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/* + rm -rf $(DIST_DIR) + mkdir $(DIST_DIR) + mkdir $(DIST_DIR)/atmosphere + mkdir $(DIST_DIR)/switch + mkdir -p $(DIST_DIR)/atmosphere/fatal_errors + mkdir -p $(DIST_DIR)/atmosphere/config_templates + mkdir -p $(DIST_DIR)/atmosphere/config + mkdir -p $(DIST_DIR)/atmosphere/flags + cp fusee/$(ATMOSPHERE_BOOT_OUT_DIR)/fusee.bin $(DIST_DIR)/atmosphere/reboot_payload.bin + cp fusee/$(ATMOSPHERE_BOOT_OUT_DIR)/package3 $(DIST_DIR)/atmosphere/package3 + cp config_templates/stratosphere.ini $(DIST_DIR)/atmosphere/config_templates/stratosphere.ini + cp config_templates/override_config.ini $(DIST_DIR)/atmosphere/config_templates/override_config.ini + cp config_templates/system_settings.ini $(DIST_DIR)/atmosphere/config_templates/system_settings.ini + cp config_templates/exosphere.ini $(DIST_DIR)/atmosphere/config_templates/exosphere.ini + mkdir -p config_templates/kip_patches + cp -r config_templates/kip_patches $(DIST_DIR)/atmosphere/kip_patches + cp -r config_templates/hbl_html $(DIST_DIR)/atmosphere/hbl_html + mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000008 + mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000000D + mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000017 + mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000002B + mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000032 + mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000034 + mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000036 + mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000037 + mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000003C + mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000042 + mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000420 + mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000B240 + mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000D609 + mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000D623 + cp stratosphere/boot2/$(ATMOSPHERE_OUT_DIR)/boot2.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000008/exefs.nsp + cp stratosphere/dmnt/$(ATMOSPHERE_OUT_DIR)/dmnt.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000000D/exefs.nsp + cp stratosphere/cs/$(ATMOSPHERE_OUT_DIR)/cs.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000017/exefs.nsp + cp stratosphere/erpt/$(ATMOSPHERE_OUT_DIR)/erpt.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000002B/exefs.nsp + cp stratosphere/eclct.stub/$(ATMOSPHERE_OUT_DIR)/eclct.stub.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000032/exefs.nsp + cp stratosphere/fatal/$(ATMOSPHERE_OUT_DIR)/fatal.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000034/exefs.nsp + cp stratosphere/creport/$(ATMOSPHERE_OUT_DIR)/creport.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000036/exefs.nsp + cp stratosphere/ro/$(ATMOSPHERE_OUT_DIR)/ro.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000037/exefs.nsp + cp stratosphere/jpegdec/$(ATMOSPHERE_OUT_DIR)/jpegdec.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000003C/exefs.nsp + cp stratosphere/pgl/$(ATMOSPHERE_OUT_DIR)/pgl.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000042/exefs.nsp + cp stratosphere/LogManager/$(ATMOSPHERE_OUT_DIR)/LogManager.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000420/exefs.nsp + cp stratosphere/htc/$(ATMOSPHERE_OUT_DIR)/htc.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000B240/exefs.nsp + cp stratosphere/dmnt.gen2/$(ATMOSPHERE_OUT_DIR)/dmnt.gen2.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000D609/exefs.nsp + cp stratosphere/TioServer/$(ATMOSPHERE_OUT_DIR)/TioServer.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000D623/exefs.nsp + @build_romfs $(DIST_DIR)/stratosphere_romfs $(DIST_DIR)/atmosphere/stratosphere.romfs + rm -r $(DIST_DIR)/stratosphere_romfs + cp troposphere/reboot_to_payload/reboot_to_payload.nro $(DIST_DIR)/switch/reboot_to_payload.nro + cp troposphere/daybreak/daybreak.nro $(DIST_DIR)/switch/daybreak.nro + cd $(DIST_DIR); zip -r ../atmosphere-$(ATMOSPHERE_VERSION).zip ./*; cd ../; + rm -rf $(DIST_DIR) + cp fusee/$(ATMOSPHERE_BOOT_OUT_DIR)/fusee.bin $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/fusee.bin + +package3: emummc fusee stratosphere mesosphere exosphere troposphere + @python fusee/build_package3.py $(CURRENT_DIRECTORY) $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BOOT_OUT_DIR) $(ATMOSPHERE_GIT_HASH) $(ATMOSPHERE_MAJOR_VERSION) $(ATMOSPHERE_MINOR_VERSION) $(ATMOSPHERE_MICRO_VERSION) 0 $(ATMOSPHERE_SUPPORTED_HOS_MAJOR_VERSION) $(ATMOSPHERE_SUPPORTED_HOS_MINOR_VERSION) $(ATMOSPHERE_SUPPORTED_HOS_MICRO_VERSION) 0 + @echo "Built package3!" + +emummc: + $(MAKE) -C $(CURRENT_DIRECTORY)/emummc all + +fusee: libexosphere_boot + @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/fusee -f $(CURRENT_DIRECTORY)/fusee/fusee.mk ATMOSPHERE_CPU="$(strip $(ATMOSPHERE_BOOT_CPU))" + +exosphere: libexosphere libexosphere_boot + @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/exosphere -f $(CURRENT_DIRECTORY)/exosphere/exosphere.mk ATMOSPHERE_CHECKED_LIBEXOSPHERE=1 ATMOSPHERE_CHECKED_BOOT_LIBEXOSPHERE=1 + +stratosphere: fusee libstratosphere + @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/stratosphere -f $(CURRENT_DIRECTORY)/stratosphere/stratosphere.mk ATMOSPHERE_CHECKED_LIBSTRATOSPHERE=1 ATMOSPHERE_CHECKED_FUSEE=1 + +mesosphere: libmesosphere + @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/mesosphere -f $(CURRENT_DIRECTORY)/mesosphere/mesosphere.mk ATMOSPHERE_CHECKED_LIBMESOSPHERE=1 + +troposphere: + $(MAKE) -C $(CURRENT_DIRECTORY)/troposphere all + +libexosphere: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk + +ifneq ($(strip $(ATMOSPHERE_LIBRARY_DIR)),$(strip $(ATMOSPHERE_BOOT_LIBRARY_DIR))) +libexosphere_boot: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk ATMOSPHERE_CPU="$(strip $(ATMOSPHERE_BOOT_CPU))" +else +libexosphere_boot: libexosphere +endif + +libmesosphere: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libmesosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libmesosphere/libmesosphere.mk + +libstratosphere: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/libstratosphere.mk + +clean: + $(MAKE) -C $(CURRENT_DIRECTORY)/fusee -f $(CURRENT_DIRECTORY)/fusee/fusee.mk clean ATMOSPHERE_CPU="$(strip $(ATMOSPHERE_BOOT_CPU))" + $(MAKE) -C $(CURRENT_DIRECTORY)/emummc clean + $(MAKE) -C $(CURRENT_DIRECTORY)/exosphere -f $(CURRENT_DIRECTORY)/exosphere/exosphere.mk clean + $(MAKE) -C $(CURRENT_DIRECTORY)/mesosphere -f $(CURRENT_DIRECTORY)/mesosphere/mesosphere.mk clean + $(MAKE) -C $(CURRENT_DIRECTORY)/stratosphere -f $(CURRENT_DIRECTORY)/stratosphere/stratosphere.mk clean + $(MAKE) -C $(CURRENT_DIRECTORY)/troposphere clean + $(MAKE) -C $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/libstratosphere.mk clean + $(MAKE) -C $(ATMOSPHERE_LIBRARIES_DIR)/libmesosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libmesosphere/libmesosphere.mk clean + $(MAKE) -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk clean + $(MAKE) -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk clean ATMOSPHERE_CPU="$(strip $(ATMOSPHERE_BOOT_CPU))" + rm -rf $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR) + +$(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR) $(CURRENT_DIRECTORY)/$(ATMOSPHERE_BUILD_DIR): + @[ -d $@ ] || mkdir -p $@ + +.PHONY: dist dist-no-debug clean package3 emummc fusee stratosphere mesosphere exosphere troposphere diff --git a/exosphere/Makefile b/exosphere/Makefile index 2a69bda57..87603f7c7 100644 --- a/exosphere/Makefile +++ b/exosphere/Makefile @@ -1,75 +1,41 @@ ATMOSPHERE_BUILD_CONFIGS := -all: release +all: nx_release + +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) define ATMOSPHERE_ADD_TARGET ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -$(strip $1): exosphere$(strip $2).bin warmboot$(strip $2).bin mariko_fatal$(strip $2).bin +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/exosphere.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -exosphere$(strip $2).bin: loader_stub/loader_stub$(strip $2).bin - @cp loader_stub/loader_stub$(strip $2).bin exosphere$(strip $2).bin - @printf LENY >> exosphere$(strip $2).bin - @echo "Built exosphere$(strip $2).bin..." - -warmboot$(strip $2).bin: warmboot/warmboot$(strip $2).bin - @cp warmboot/warmboot$(strip $2).bin warmboot$(strip $2).bin - @echo "Built warmboot$(strip $2).bin..." - -mariko_fatal$(strip $2).bin: mariko_fatal/mariko_fatal$(strip $2).bin - @cp mariko_fatal/mariko_fatal$(strip $2).bin mariko_fatal$(strip $2).bin - @echo "Built mariko_fatal$(strip $2).bin..." - -check_program_$(strip $1): - @$$(MAKE) -C program $(strip $1) - -check_warmboot_$(strip $1): - @$$(MAKE) -C warmboot $(strip $1) - -check_mariko_fatal_$(strip $1): - @$$(MAKE) -C mariko_fatal $(strip $1) - -loader_stub/loader_stub$(strip $2).bin: check_program_$(strip $1) - @$$(MAKE) -C loader_stub $(strip $1) - -warmboot/warmboot$(strip $2).bin: check_warmboot_$(strip $1) - -mariko_fatal/mariko_fatal$(strip $2).bin: check_mariko_fatal_$(strip $1) - -clean-$(strip $1): clean-program-$(strip $1) clean-loader_stub-$(strip $1) clean-warmboot-$(strip $1) clean-mariko_fatal-$(strip $1) - @rm -rf exosphere$(strip $2).bin warmboot$(strip $2).bin mariko_fatal$(strip $2).bin - -clean-program-$(strip $1): - @$$(MAKE) -C program clean-$(strip $1) - -clean-loader_stub-$(strip $1): - @$$(MAKE) -C loader_stub clean-$(strip $1) - -clean-warmboot-$(strip $1): - @$$(MAKE) -C warmboot clean-$(strip $1) - -clean-mariko_fatal-$(strip $1): - @$$(MAKE) -C mariko_fatal clean-$(strip $1) +clean-$(strip $1): + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/exosphere.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) endef -$(eval $(call ATMOSPHERE_ADD_TARGET, release, )) -$(eval $(call ATMOSPHERE_ADD_TARGET, debug, _debug)) -$(eval $(call ATMOSPHERE_ADD_TARGET, audit, _audit)) +define ATMOSPHERE_ADD_TARGETS -clean: clean-program clean-loader_stub clean-warmboot - @rm -rf exosphere*.bin warmboot*.bin mariko_fatal*.bin +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ +)) -clean-program: - @$(MAKE) -C program clean +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ +)) -clean-loader_stub: - @$(MAKE) -C loader_stub clean +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ +)) -clean-warmboot: - @$(MAKE) -C warmboot clean +endef -clean-mariko_fatal: - @$(MAKE) -C mariko_fatal clean +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) -.PHONY: all clean clean-program clean-loader_stub clean-warmboot $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),check_program_$(config) check_warmboot_$(strip $1) clean-$(config) clean-program-$(config) clean-loader_stub-$(config) clean-warmboot-$(config)) +clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) + +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/exosphere/exosphere.mk b/exosphere/exosphere.mk new file mode 100644 index 000000000..80c65f90e --- /dev/null +++ b/exosphere/exosphere.mk @@ -0,0 +1,75 @@ +#--------------------------------------------------------------------------------- +# pull in common atmosphere configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(CURRENT_DIRECTORY)/../libraries/config/common.mk + +all: $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/exosphere.bin $(CURRENT_DIRECTORY)/warmboot/$(ATMOSPHERE_BOOT_OUT_DIR)/warmboot.bin $(CURRENT_DIRECTORY)/mariko_fatal/$(ATMOSPHERE_OUT_DIR)/mariko_fatal.bin + +$(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/exosphere.bin: $(CURRENT_DIRECTORY)/loader_stub/$(ATMOSPHERE_OUT_DIR)/loader_stub.bin $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR) + @cp $(CURRENT_DIRECTORY)/loader_stub/$(ATMOSPHERE_OUT_DIR)/loader_stub.bin $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/exosphere.bin + @printf LENY >> $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/exosphere.bin + @echo "Built exosphere.bin..." + +$(CURRENT_DIRECTORY)/loader_stub/$(ATMOSPHERE_OUT_DIR)/loader_stub.bin: check_loader_stub + @$(SILENTCMD)echo "Checked loader stub." + +$(CURRENT_DIRECTORY)/program/$(ATMOSPHERE_OUT_DIR)/program.lz4: check_program + @$(SILENTCMD)echo "Checked program." + +$(CURRENT_DIRECTORY)/warmboot/$(ATMOSPHERE_BOOT_OUT_DIR)/warmboot.bin: check_warmboot + @$(SILENTCMD)echo "Checked warmboot." + +$(CURRENT_DIRECTORY)/mariko_fatal/$(ATMOSPHERE_OUT_DIR)/mariko_fatal.bin: check_mariko_fatal + @$(SILENTCMD)echo "Checked mariko fatal." + +$(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a: check_lib + @$(SILENTCMD)echo "Checked library." + +ifneq ($(strip $(ATMOSPHERE_LIBRARY_DIR)),$(strip $(ATMOSPHERE_BOOT_LIBRARY_DIR))) +$(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_BOOT_LIBRARY_DIR)/libexosphere.a: check_boot_lib + @$(SILENTCMD)echo "Checked boot library." +endif + +check_loader_stub: $(CURRENT_DIRECTORY)/program/$(ATMOSPHERE_OUT_DIR)/program.lz4 + @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/loader_stub -f $(CURRENT_DIRECTORY)/loader_stub/loader_stub.mk ATMOSPHERE_CHECKED_LIBEXOSPHERE=1 ATMOSPHERE_CHECKED_BOOT_LIBEXOSPHERE=1 ATMOSPHERE_CHECKED_EXOSPHERE_PROGRAM=1 + +check_program: $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_BOOT_LIBRARY_DIR)/libexosphere.a + @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/program -f $(CURRENT_DIRECTORY)/program/program.mk ATMOSPHERE_CHECKED_LIBEXOSPHERE=1 ATMOSPHERE_CHECKED_BOOT_LIBEXOSPHERE=1 + +check_mariko_fatal: $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a + @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/mariko_fatal -f $(CURRENT_DIRECTORY)/mariko_fatal/mariko_fatal.mk ATMOSPHERE_CHECKED_LIBEXOSPHERE=1 ATMOSPHERE_CHECKED_BOOT_LIBEXOSPHERE=1 + +check_warmboot: $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_BOOT_LIBRARY_DIR)/libexosphere.a + @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/warmboot -f $(CURRENT_DIRECTORY)/warmboot/warmboot.mk ATMOSPHERE_CHECKED_LIBEXOSPHERE=1 ATMOSPHERE_CHECKED_BOOT_LIBEXOSPHERE=1 ATMOSPHERE_CPU="$(strip $(ATMOSPHERE_BOOT_CPU))" + +ifeq ($(ATMOSPHERE_CHECKED_LIBEXOSPHERE),1) +check_lib: +else +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk +endif + +ifeq ($(ATMOSPHERE_CHECKED_BOOT_LIBEXOSPHERE),1) +check_boot_lib: +else +check_boot_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk ATMOSPHERE_CPU="$(strip $(ATMOSPHERE_BOOT_CPU))" +endif + +$(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR): + @[ -d $@ ] || mkdir -p $@ + +clean: + @echo clean ... + @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/loader_stub -f $(CURRENT_DIRECTORY)/loader_stub/loader_stub.mk clean + @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/program -f $(CURRENT_DIRECTORY)/program/program.mk clean + @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/mariko_fatal -f $(CURRENT_DIRECTORY)/mariko_fatal/mariko_fatal.mk clean + @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/warmboot -f $(CURRENT_DIRECTORY)/warmboot/warmboot.mk clean ATMOSPHERE_CPU="$(strip $(ATMOSPHERE_BOOT_CPU))" + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk clean + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk clean ATMOSPHERE_CPU="$(strip $(ATMOSPHERE_BOOT_CPU))" + @rm -fr $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR) + @for i in $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR); do [ -d $$i ] && rmdir --ignore-fail-on-non-empty $$i || true; done + +.PHONY: all clean check_lib check_boot_lib check_loader_stub check_program check_mariko_fatal check_warmboot \ No newline at end of file diff --git a/exosphere/loader_stub/Makefile b/exosphere/loader_stub/Makefile index 4087e941f..54bd31680 100644 --- a/exosphere/loader_stub/Makefile +++ b/exosphere/loader_stub/Makefile @@ -1,158 +1,41 @@ -#--------------------------------------------------------------------------------- -# Define the atmosphere board and cpu -#--------------------------------------------------------------------------------- -export ATMOSPHERE_BOARD := nx-hac-001 -export ATMOSPHERE_CPU := arm-cortex-a57 +ATMOSPHERE_BUILD_CONFIGS := +all: nx_release -#--------------------------------------------------------------------------------- -# pull in common atmosphere configuration -#--------------------------------------------------------------------------------- THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) -include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/exosphere.mk - -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(__RECURSIVE__),1) -#--------------------------------------------------------------------------------- - -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) - -CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) -CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) -SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) -BINFILES := - -#--------------------------------------------------------------------------------- -# use CXX for linking C++ projects, CC for standard C -#--------------------------------------------------------------------------------- -ifeq ($(strip $(CPPFILES)),) -#--------------------------------------------------------------------------------- - export LD := $(CC) -#--------------------------------------------------------------------------------- -else -#--------------------------------------------------------------------------------- - export LD := $(CXX) -#--------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------- - -export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) -export OFILES := $(OFILES_SRC) program.lz4.o boot_code.lz4.o - -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I. - -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) - -export TOPDIR := $(CURRENT_DIRECTORY) - -OUTPUT_BASE := $(TOPDIR)/$(notdir $(TOPDIR)) - -#--------------------------------------------------------------------------------- - -ATMOSPHERE_BUILD_CONFIGS := -all: release define ATMOSPHERE_ADD_TARGET ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -$(strip $1): check_libexo_$(strip $1) $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) - @$$(MAKE) __RECURSIVE__=1 OUTPUT=$$(OUTPUT_BASE)$(strip $2) $(3) \ - ATMOSPHERE_BUILD_TARGET_IDENTIFIER=$(strip $1)\ - ATMOSPHERE_BUILD_TARGET_BINARY_SUFFIX=$(strip $2)\ - DEPSDIR=$$(CURDIR)/$$(ATMOSPHERE_BUILD_DIR)/$(strip $1) \ - LIBEXOSPHERE_NAME=exosphere$(strip $2) \ - --no-print-directory -C $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) \ - -f $$(THIS_MAKEFILE) - -check_libexo_$(strip $1): - @$$(MAKE) --no-print-directory -C $$(ATMOSPHERE_LIBRARIES_DIR)/libexosphere $$(ATMOSPHERE_ARCH_NAME)-$(strip $1) +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/loader_stub.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) clean-$(strip $1): - @echo clean $(strip $1) ... - @rm -fr $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) $$(OUTPUT_BASE)$(strip $2).bin $$(OUTPUT_BASE)$(strip $2).elf $$(OUTPUT_BASE)$(strip $2).lz4 boot_code$(strip $2).lz4 + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/loader_stub.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) endef -$(eval $(call ATMOSPHERE_ADD_TARGET, release, , \ - ATMOSPHERE_BUILD_SETTINGS="-DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS" \ +define ATMOSPHERE_ADD_TARGETS + +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ )) -$(eval $(call ATMOSPHERE_ADD_TARGET, debug, _debug, \ - ATMOSPHERE_BUILD_SETTINGS="-DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS -DAMS_BUILD_FOR_DEBUGGING" \ +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ )) -$(eval $(call ATMOSPHERE_ADD_TARGET, audit, _audit, \ - ATMOSPHERE_BUILD_SETTINGS="-DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS -DAMS_BUILD_FOR_AUDITING" \ +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ )) -$(ATMOSPHERE_BUILD_DIR)/%: - @[ -d $@ ] || mkdir -p $@ +endef + +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) -#--------------------------------------------------------------------------------- clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) -.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),$(config) clean-$(config)) - -#--------------------------------------------------------------------------------- -else - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- - -$(OUTPUT).bin : $(OUTPUT).elf - $(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@ - @echo built ... $(notdir $@) - -$(OUTPUT).elf : $(OFILES) - -$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/lib$(LIBEXOSPHERE_NAME).a - - -program.lz4.o: program_lz4.h - -program_lz4.h: $(TOPDIR)/../program/program$(ATMOSPHERE_BUILD_TARGET_BINARY_SUFFIX).lz4 - @echo $(notdir $<) - @rm -rf tmp_program_$(ATMOSPHERE_BUILD_TARGET_IDENTIFIER) - @mkdir -p tmp_program_$(ATMOSPHERE_BUILD_TARGET_IDENTIFIER) - @cp $(TOPDIR)/../program/program$(ATMOSPHERE_BUILD_TARGET_BINARY_SUFFIX).lz4 tmp_program_$(ATMOSPHERE_BUILD_TARGET_IDENTIFIER)/program.lz4 - @bin2s -a 8 -H program_lz4.h tmp_program_$(ATMOSPHERE_BUILD_TARGET_IDENTIFIER)/program.lz4 | $(AS) -o program.lz4.o - @rm -rf tmp_program_$(ATMOSPHERE_BUILD_TARGET_IDENTIFIER) - -$(TOPDIR)/../program/program$(ATMOSPHERE_BUILD_TARGET_BINARY_SUFFIX).lz4: - @$(MAKE) __RECURSIVE__=0 --no-print-directory -C $(TOPDIR)/../program $(ATMOSPHERE_BUILD_TARGET_IDENTIFIER) - -boot_code.lz4.o: boot_code_lz4.h - -boot_code_lz4.h: $(TOPDIR)/../program/boot_code$(ATMOSPHERE_BUILD_TARGET_BINARY_SUFFIX).lz4 - @echo $(notdir $<) - @rm -rf tmp_boot_code_$(ATMOSPHERE_BUILD_TARGET_IDENTIFIER) - @mkdir -p tmp_boot_code_$(ATMOSPHERE_BUILD_TARGET_IDENTIFIER) - @cp $(TOPDIR)/../program/boot_code$(ATMOSPHERE_BUILD_TARGET_BINARY_SUFFIX).lz4 tmp_boot_code_$(ATMOSPHERE_BUILD_TARGET_IDENTIFIER)/boot_code.lz4 - @bin2s -a 8 -H boot_code_lz4.h tmp_boot_code_$(ATMOSPHERE_BUILD_TARGET_IDENTIFIER)/boot_code.lz4 | $(AS) -o boot_code.lz4.o - @rm -rf tmp_boot_code_$(ATMOSPHERE_BUILD_TARGET_IDENTIFIER) - -$(TOPDIR)/../program/boot_code$(ATMOSPHERE_BUILD_TARGET_BINARY_SUFFIX).lz4: $(TOPDIR)/../program/program$(ATMOSPHERE_BUILD_TARGET_BINARY_SUFFIX).lz4 - -%.elf: - @echo linking $(notdir $@) - $(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ - @$(NM) -CSn $@ > $(notdir $*.lst) - -$(OFILES_SRC) : program_lz4.h boot_code_lz4.h - - --include $(DEPENDS) - -#--------------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------------- +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/exosphere/loader_stub/loader_stub.mk b/exosphere/loader_stub/loader_stub.mk new file mode 100644 index 000000000..df737a370 --- /dev/null +++ b/exosphere/loader_stub/loader_stub.mk @@ -0,0 +1,132 @@ +#--------------------------------------------------------------------------------- +# pull in common atmosphere configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(CURRENT_DIRECTORY)/../../libraries/config/templates/exosphere.mk + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(__RECURSIVE__),1) +#--------------------------------------------------------------------------------- + +export ATMOSPHERE_TOPDIR := $(CURRENT_DIRECTORY) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) \ + $(CURRENT_DIRECTORY)/../program/$(ATMOSPHERE_OUT_DIR) + +CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) +CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) +SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) +BINFILES := program.lz4 boot_code.lz4 + +#--------------------------------------------------------------------------------- +# 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_BIN := $(addsuffix .h,$(subst .,_,$(subst -,_,$(BINFILES)))) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I. + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) + +.PHONY: clean all check_lib check_exo_program + +#--------------------------------------------------------------------------------- +all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a $(CURRENT_DIRECTORY)/../program/$(ATMOSPHERE_OUT_DIR)/program.lz4 + @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/$(notdir $(ATMOSPHERE_TOPDIR)) \ + DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ + --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ + -f $(THIS_MAKEFILE) + +$(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a: check_lib + @$(SILENTCMD)echo "Checked library." + +$(CURRENT_DIRECTORY)/../program/$(ATMOSPHERE_OUT_DIR)/program.lz4: check_exo_program + @$(SILENTCMD)echo "Checked exosphere program." + +ifeq ($(ATMOSPHERE_CHECKED_EXOSPHERE_PROGRAM),1) +check_exo_program: +else +check_exo_program: check_lib + @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/../program -f $(CURRENT_DIRECTORY)/../program/program.mk ATMOSPHERE_CHECKED_LIBEXOSPHERE=1 +endif + +ifeq ($(ATMOSPHERE_CHECKED_LIBEXOSPHERE),1) +check_lib: +else +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk +endif + +$(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): + @[ -d $@ ] || mkdir -p $@ + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_OUT_DIR) + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- + +$(OUTPUT).bin : $(OUTPUT).elf + $(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@ + @echo built ... $(notdir $@) + +$(OUTPUT).elf : $(OFILES) + +$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a + +program.lz4.o: program.lz4 + @echo $(notdir $<) + @$(bin2o) + +boot_code.lz4.o: boot_code.lz4 + @echo $(notdir $<) + @$(bin2o) + +%.elf: + @echo linking $(notdir $@) + $(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ + @$(NM) -CSn $@ > $(notdir $*.lst) + +$(OFILES_SRC) : $(OFILES_BIN) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o %_bin.h: %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/exosphere/loader_stub/loader_stub.specs b/exosphere/loader_stub/loader_stub.specs index 261cffccd..7326f34de 100644 --- a/exosphere/loader_stub/loader_stub.specs +++ b/exosphere/loader_stub/loader_stub.specs @@ -1,4 +1,4 @@ %rename link old_link *link: -%(old_link) -T %:getenv(TOPDIR /loader_stub.ld) --gc-sections --nmagic \ No newline at end of file +%(old_link) -T %:getenv(ATMOSPHERE_TOPDIR /loader_stub.ld) --gc-sections --nmagic \ No newline at end of file diff --git a/exosphere/mariko_fatal/Makefile b/exosphere/mariko_fatal/Makefile index c1a6e3abf..8cda1a757 100644 --- a/exosphere/mariko_fatal/Makefile +++ b/exosphere/mariko_fatal/Makefile @@ -1,141 +1,41 @@ -#--------------------------------------------------------------------------------- -# Define the atmosphere board and cpu -#--------------------------------------------------------------------------------- -export ATMOSPHERE_BOARD := nx-hac-001 -export ATMOSPHERE_CPU := arm-cortex-a57 +ATMOSPHERE_BUILD_CONFIGS := +all: nx_release -#--------------------------------------------------------------------------------- -# pull in common atmosphere configuration -#--------------------------------------------------------------------------------- THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) -include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/exosphere.mk - -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(__RECURSIVE__),1) -#--------------------------------------------------------------------------------- - -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) - -CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) -CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) -SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) -BINFILES := - -#--------------------------------------------------------------------------------- -# 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_BIN := $(addsuffix .h,$(subst .,_,$(subst -,_,$(BINFILES)))) - -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I. - -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) - -export TOPDIR := $(CURRENT_DIRECTORY) - -OUTPUT_BASE := $(TOPDIR)/$(notdir $(TOPDIR)) - -#--------------------------------------------------------------------------------- - -ATMOSPHERE_BUILD_CONFIGS := -all: release define ATMOSPHERE_ADD_TARGET ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -$(strip $1): check_libexo_$(strip $1) $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) - @$$(MAKE) __RECURSIVE__=1 OUTPUT=$$(OUTPUT_BASE)$(strip $2) $(3) \ - DEPSDIR=$$(CURDIR)/$$(ATMOSPHERE_BUILD_DIR)/$(strip $1) \ - LIBEXOSPHERE_NAME=exosphere$(strip $2) \ - --no-print-directory -C $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) \ - -f $$(THIS_MAKEFILE) - -check_libexo_$(strip $1): - @$$(MAKE) --no-print-directory -C $$(ATMOSPHERE_LIBRARIES_DIR)/libexosphere $$(ATMOSPHERE_ARCH_NAME)-$(strip $1) +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/mariko_fatal.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) clean-$(strip $1): - @echo clean $(strip $1) ... - @rm -fr $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) $$(OUTPUT_BASE)$(strip $2).bin $$(OUTPUT_BASE)$(strip $2).elf + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/mariko_fatal.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) endef -$(eval $(call ATMOSPHERE_ADD_TARGET, release, , \ - ATMOSPHERE_BUILD_SETTINGS="-DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS" \ +define ATMOSPHERE_ADD_TARGETS + +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ )) -$(eval $(call ATMOSPHERE_ADD_TARGET, debug, _debug, \ - ATMOSPHERE_BUILD_SETTINGS="-DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS -DAMS_BUILD_FOR_DEBUGGING" \ +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ )) -$(eval $(call ATMOSPHERE_ADD_TARGET, audit, _audit, \ - ATMOSPHERE_BUILD_SETTINGS="-DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS -DAMS_BUILD_FOR_AUDITING" \ +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ )) -$(ATMOSPHERE_BUILD_DIR)/%: - @[ -d $@ ] || mkdir -p $@ +endef + +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) -#--------------------------------------------------------------------------------- clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) -.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),$(config) clean-$(config)) - -#--------------------------------------------------------------------------------- -else - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- - -$(OUTPUT).bin : $(OUTPUT).elf - $(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@ - @echo built ... $(notdir $@) - -$(OUTPUT).elf : $(OFILES) - -$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/lib$(LIBEXOSPHERE_NAME).a - -%.elf: - @echo linking $(notdir $@) - $(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ - @$(NM) -CSn $@ > $(notdir $*.lst) - -diskio.o ff.o: CFLAGS += -Wno-error - -$(OFILES_SRC) : $(HFILES_BIN) - -#--------------------------------------------------------------------------------- -# you need a rule like this for each extension you use as binary data -#--------------------------------------------------------------------------------- -%.bin.o %_bin.h: %.bin -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) - --include $(DEPENDS) - -#--------------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------------- +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/exosphere/mariko_fatal/mariko_fatal.mk b/exosphere/mariko_fatal/mariko_fatal.mk new file mode 100644 index 000000000..3e37b939e --- /dev/null +++ b/exosphere/mariko_fatal/mariko_fatal.mk @@ -0,0 +1,115 @@ +#--------------------------------------------------------------------------------- +# pull in common atmosphere configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(CURRENT_DIRECTORY)/../../libraries/config/templates/exosphere.mk + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(__RECURSIVE__),1) +#--------------------------------------------------------------------------------- + +export ATMOSPHERE_TOPDIR := $(CURRENT_DIRECTORY) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) +CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) +SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) +BINFILES := + +#--------------------------------------------------------------------------------- +# 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_BIN := $(addsuffix .h,$(subst .,_,$(subst -,_,$(BINFILES)))) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I. + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) + +.PHONY: clean all check_lib + +#--------------------------------------------------------------------------------- +all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a + @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/$(notdir $(ATMOSPHERE_TOPDIR)) \ + DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ + --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ + -f $(THIS_MAKEFILE) + +$(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a: check_lib + @$(SILENTCMD)echo "Checked library." + +ifeq ($(ATMOSPHERE_CHECKED_LIBEXOSPHERE),1) +check_lib: +else +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk +endif + +$(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): + @[ -d $@ ] || mkdir -p $@ + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_OUT_DIR) + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- + +$(OUTPUT).bin : $(OUTPUT).elf + $(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@ + @echo built ... $(notdir $@) + +$(OUTPUT).elf : $(OFILES) + +$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a + +%.elf: + @echo linking $(notdir $@) + $(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ + @$(NM) -CSn $@ > $(notdir $*.lst) + +$(OFILES_SRC) : $(HFILES_BIN) + +diskio.o ff.o: CFLAGS += -Wno-error -Wno-unused-parameter -Wno-implicit-fallthrough + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o %_bin.h: %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/exosphere/mariko_fatal/mariko_fatal.specs b/exosphere/mariko_fatal/mariko_fatal.specs index 71d294c07..dec84676d 100644 --- a/exosphere/mariko_fatal/mariko_fatal.specs +++ b/exosphere/mariko_fatal/mariko_fatal.specs @@ -1,4 +1,4 @@ %rename link old_link *link: -%(old_link) -T %:getenv(TOPDIR /mariko_fatal.ld) --gc-sections --nmagic \ No newline at end of file +%(old_link) -T %:getenv(ATMOSPHERE_TOPDIR /mariko_fatal.ld) --gc-sections --nmagic \ No newline at end of file diff --git a/exosphere/program/Makefile b/exosphere/program/Makefile index 0f029acc0..e704021f7 100644 --- a/exosphere/program/Makefile +++ b/exosphere/program/Makefile @@ -1,163 +1,41 @@ -#--------------------------------------------------------------------------------- -# Define the atmosphere board and cpu -#--------------------------------------------------------------------------------- -export ATMOSPHERE_BOARD := nx-hac-001 -export ATMOSPHERE_CPU := arm-cortex-a57 +ATMOSPHERE_BUILD_CONFIGS := +all: nx_release -#--------------------------------------------------------------------------------- -# pull in common atmosphere configuration -#--------------------------------------------------------------------------------- THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) -include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/exosphere.mk - -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(__RECURSIVE__),1) -#--------------------------------------------------------------------------------- - -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) - -CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) -CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) -SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) - -#--------------------------------------------------------------------------------- -# use CXX for linking C++ projects, CC for standard C -#--------------------------------------------------------------------------------- -ifeq ($(strip $(CPPFILES)),) -#--------------------------------------------------------------------------------- - export LD := $(CC) -#--------------------------------------------------------------------------------- -else -#--------------------------------------------------------------------------------- - export LD := $(CXX) -#--------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------- - -export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) -export OFILES := $(OFILES_SRC) rebootstub.bin.o sc7fw.bin.o - -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I. - -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) - -export TOPDIR := $(CURRENT_DIRECTORY) - -OUTPUT_BASE := $(TOPDIR)/$(notdir $(TOPDIR)) - -#--------------------------------------------------------------------------------- - -ATMOSPHERE_BUILD_CONFIGS := -all: release define ATMOSPHERE_ADD_TARGET ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -$(strip $1): check_libexo_$(strip $1) $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) - @$$(MAKE) __RECURSIVE__=1 OUTPUT=$$(OUTPUT_BASE)$(strip $2) $(3) \ - ATMOSPHERE_BUILD_TARGET_IDENTIFIER=$(strip $1)\ - ATMOSPHERE_BUILD_TARGET_BINARY_SUFFIX=$(strip $2)\ - DEPSDIR=$$(CURDIR)/$$(ATMOSPHERE_BUILD_DIR)/$(strip $1) \ - LIBEXOSPHERE_NAME=exosphere$(strip $2) \ - --no-print-directory -C $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) \ - -f $$(THIS_MAKEFILE) - -check_libexo_$(strip $1): - @$$(MAKE) --no-print-directory -C $$(ATMOSPHERE_LIBRARIES_DIR)/libexosphere $$(ATMOSPHERE_ARCH_NAME)-$(strip $1) +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/program.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) clean-$(strip $1): - @echo clean $(strip $1) ... - @rm -fr $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) $$(OUTPUT_BASE)$(strip $2).bin $$(OUTPUT_BASE)$(strip $2).elf $$(OUTPUT_BASE)$(strip $2).lz4 boot_code$(strip $2).lz4 + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/program.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) endef -$(eval $(call ATMOSPHERE_ADD_TARGET, release, , \ - ATMOSPHERE_BUILD_SETTINGS="-DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS" \ +define ATMOSPHERE_ADD_TARGETS + +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ )) -$(eval $(call ATMOSPHERE_ADD_TARGET, debug, _debug, \ - ATMOSPHERE_BUILD_SETTINGS="-DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS -DAMS_BUILD_FOR_DEBUGGING" \ +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ )) -$(eval $(call ATMOSPHERE_ADD_TARGET, audit, _audit, \ - ATMOSPHERE_BUILD_SETTINGS="-DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS -DAMS_BUILD_FOR_AUDITING" \ +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ )) -$(ATMOSPHERE_BUILD_DIR)/%: - @[ -d $@ ] || mkdir -p $@ +endef + +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) -#--------------------------------------------------------------------------------- clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) -.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),$(config) clean-$(config)) - -#--------------------------------------------------------------------------------- -else - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- - -$(OUTPUT).lz4 : $(OUTPUT).bin - @python $(TOPDIR)/split_program.py $(OUTPUT).bin "$(ATMOSPHERE_BUILD_TARGET_BINARY_SUFFIX)" $(dir $(OUTPUT)) - @echo built ... $(notdir $@) - -$(OUTPUT).bin : $(OUTPUT).elf - $(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@ - @echo built ... $(notdir $@) - -$(OUTPUT).elf : $(OFILES) - -$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/lib$(LIBEXOSPHERE_NAME).a - -secmon_crt0_cpp.o secmon_make_page_table.o : CFLAGS += -fno-builtin - -rebootstub.bin.o: rebootstub_bin.h - -rebootstub_bin.h: $(TOPDIR)/rebootstub/rebootstub$(ATMOSPHERE_BUILD_TARGET_BINARY_SUFFIX).bin - @echo $(notdir $<) - @rm -rf tmp_rebootstub_$(ATMOSPHERE_BUILD_TARGET_IDENTIFIER) - @mkdir -p tmp_rebootstub_$(ATMOSPHERE_BUILD_TARGET_IDENTIFIER) - @cp $(TOPDIR)/rebootstub/rebootstub$(ATMOSPHERE_BUILD_TARGET_BINARY_SUFFIX).bin tmp_rebootstub_$(ATMOSPHERE_BUILD_TARGET_IDENTIFIER)/rebootstub.bin - @bin2s -a 8 -H rebootstub_bin.h tmp_rebootstub_$(ATMOSPHERE_BUILD_TARGET_IDENTIFIER)/rebootstub.bin | $(AS) -o rebootstub.bin.o - @rm -rf tmp_rebootstub_$(ATMOSPHERE_BUILD_TARGET_IDENTIFIER) - -$(TOPDIR)/rebootstub/rebootstub$(ATMOSPHERE_BUILD_TARGET_BINARY_SUFFIX).bin: - @$(MAKE) __RECURSIVE__=0 --no-print-directory -C $(TOPDIR)/rebootstub $(ATMOSPHERE_BUILD_TARGET_IDENTIFIER) - -sc7fw.bin.o: sc7fw_bin.h - -sc7fw.bin.o sc7fw_bin.h: $(TOPDIR)/sc7fw/sc7fw$(ATMOSPHERE_BUILD_TARGET_BINARY_SUFFIX).bin - @echo $(notdir $<) - @rm -rf tmp_sc7fw_$(ATMOSPHERE_BUILD_TARGET_IDENTIFIER) - @mkdir -p tmp_sc7fw_$(ATMOSPHERE_BUILD_TARGET_IDENTIFIER) - @cp $(TOPDIR)/sc7fw/sc7fw$(ATMOSPHERE_BUILD_TARGET_BINARY_SUFFIX).bin tmp_sc7fw_$(ATMOSPHERE_BUILD_TARGET_IDENTIFIER)/sc7fw.bin - @bin2s -a 8 -H sc7fw_bin.h tmp_sc7fw_$(ATMOSPHERE_BUILD_TARGET_IDENTIFIER)/sc7fw.bin | $(AS) -o sc7fw.bin.o - @rm -rf tmp_sc7fw_$(ATMOSPHERE_BUILD_TARGET_IDENTIFIER) - -$(TOPDIR)/sc7fw/sc7fw$(ATMOSPHERE_BUILD_TARGET_BINARY_SUFFIX).bin: - @$(MAKE) __RECURSIVE__=0 --no-print-directory -C $(TOPDIR)/sc7fw $(ATMOSPHERE_BUILD_TARGET_IDENTIFIER) - -%.elf: - @echo linking $(notdir $@) - $(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ - @$(NM) -CSn $@ > $(notdir $*.lst) - -$(OFILES_SRC) : rebootstub_bin.h sc7fw_bin.h - - --include $(DEPENDS) - -#--------------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------------- +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/exosphere/program/program.mk b/exosphere/program/program.mk new file mode 100644 index 000000000..519f777ab --- /dev/null +++ b/exosphere/program/program.mk @@ -0,0 +1,162 @@ +#--------------------------------------------------------------------------------- +# pull in common atmosphere configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(CURRENT_DIRECTORY)/../../libraries/config/templates/exosphere.mk + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(__RECURSIVE__),1) +#--------------------------------------------------------------------------------- + +export ATMOSPHERE_TOPDIR := $(CURRENT_DIRECTORY) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) \ + $(CURRENT_DIRECTORY)/sc7fw/$(ATMOSPHERE_BOOT_OUT_DIR) \ + $(CURRENT_DIRECTORY)/rebootstub/$(ATMOSPHERE_BOOT_OUT_DIR) + +CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) +CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) +SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) +BINFILES := sc7fw.bin rebootstub.bin + +#--------------------------------------------------------------------------------- +# 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_BIN := $(addsuffix .h,$(subst .,_,$(subst -,_,$(BINFILES)))) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I. + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) + +.PHONY: clean all check_lib check_boot_lib check_sc7fw check_rebootstub + +#--------------------------------------------------------------------------------- +all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a $(CURRENT_DIRECTORY)/sc7fw/$(ATMOSPHERE_BOOT_OUT_DIR)/sc7fw.bin $(CURRENT_DIRECTORY)/rebootstub/$(ATMOSPHERE_BOOT_OUT_DIR)/rebootstub.bin + @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/$(notdir $(ATMOSPHERE_TOPDIR)) \ + DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ + --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ + -f $(THIS_MAKEFILE) + +$(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a: check_lib + @$(SILENTCMD)echo "Checked library." + + +ifneq ($(strip $(ATMOSPHERE_LIBRARY_DIR)),$(strip $(ATMOSPHERE_BOOT_LIBRARY_DIR))) +$(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_BOOT_LIBRARY_DIR)/libexosphere.a: check_boot_lib + @$(SILENTCMD)echo "Checked boot library." +endif + +$(CURRENT_DIRECTORY)/sc7fw/$(ATMOSPHERE_BOOT_OUT_DIR)/sc7fw.bin: check_sc7fw + +$(CURRENT_DIRECTORY)/rebootstub/$(ATMOSPHERE_BOOT_OUT_DIR)/rebootstub.bin: check_rebootstub + +ifeq ($(ATMOSPHERE_CHECKED_SC7FW),1) +check_sc7fw: +else +check_sc7fw: $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_BOOT_LIBRARY_DIR)/libexosphere.a + @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/sc7fw -f $(CURRENT_DIRECTORY)/sc7fw/sc7fw.mk ATMOSPHERE_CPU="$(strip $(ATMOSPHERE_BOOT_CPU))" ATMOSPHERE_CHECKED_LIBEXOSPHERE=1 ATMOSPHERE_CHECKED_BOOT_LIBEXOSPHERE=1 +endif + +ifeq ($(ATMOSPHERE_CHECKED_REBOOTSTUB),1) +check_rebootstub: +else +check_rebootstub: $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_BOOT_LIBRARY_DIR)/libexosphere.a + @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/rebootstub -f $(CURRENT_DIRECTORY)/rebootstub/rebootstub.mk ATMOSPHERE_CPU="$(strip $(ATMOSPHERE_BOOT_CPU))" ATMOSPHERE_CHECKED_LIBEXOSPHERE=1 ATMOSPHERE_CHECKED_BOOT_LIBEXOSPHERE=1 +endif + +ifeq ($(ATMOSPHERE_CHECKED_LIBEXOSPHERE),1) +check_lib: +else +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk +endif + +ifeq ($(ATMOSPHERE_CHECKED_BOOT_LIBEXOSPHERE),1) +check_boot_lib: +else +check_boot_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk ATMOSPHERE_CPU="$(strip $(ATMOSPHERE_BOOT_CPU))" +endif + +$(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): + @[ -d $@ ] || mkdir -p $@ + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/rebootstub -f $(CURRENT_DIRECTORY)/rebootstub/rebootstub.mk clean ATMOSPHERE_CPU="$(strip $(ATMOSPHERE_BOOT_CPU))" + @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/sc7fw -f $(CURRENT_DIRECTORY)/sc7fw/sc7fw.mk clean ATMOSPHERE_CPU="$(strip $(ATMOSPHERE_BOOT_CPU))" + @rm -fr $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_OUT_DIR) + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- + +$(OUTPUT).lz4 : $(OUTPUT).bin + @python $(CURRENT_DIRECTORY)/split_program.py $(OUTPUT).bin $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR) + @echo built ... $(notdir $@) + +$(OUTPUT).bin : $(OUTPUT).elf + $(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@ + @echo built ... $(notdir $@) + +$(OUTPUT).elf : $(OFILES) + +$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a + +secmon_crt0_cpp.o secmon_make_page_table.o : CFLAGS += -fno-builtin + +sc7fw.bin.o: sc7fw.bin + @echo $(notdir $<) + @$(bin2o) + +rebootstub.bin.o: rebootstub.bin + @echo $(notdir $<) + @$(bin2o) + +%.elf: + @echo linking $(notdir $@) + $(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ + @$(NM) -CSn $@ > $(notdir $*.lst) + +$(OFILES_SRC) : $(OFILES_BIN) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o %_bin.h: %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/exosphere/program/program.specs b/exosphere/program/program.specs index 7d174b721..a1f8ae653 100644 --- a/exosphere/program/program.specs +++ b/exosphere/program/program.specs @@ -1,4 +1,4 @@ %rename link old_link *link: -%(old_link) -T %:getenv(TOPDIR /program.ld) --gc-sections --nmagic \ No newline at end of file +%(old_link) -T %:getenv(ATMOSPHERE_TOPDIR /program.ld) --gc-sections --nmagic \ No newline at end of file diff --git a/exosphere/program/rebootstub/Makefile b/exosphere/program/rebootstub/Makefile index 67a33cd70..dab7f522a 100644 --- a/exosphere/program/rebootstub/Makefile +++ b/exosphere/program/rebootstub/Makefile @@ -1,139 +1,41 @@ -#--------------------------------------------------------------------------------- -# Define the atmosphere board and cpu -#--------------------------------------------------------------------------------- -export ATMOSPHERE_BOARD := nx-hac-001 -export ATMOSPHERE_CPU := arm7tdmi +ATMOSPHERE_BUILD_CONFIGS := +all: nx_release -#--------------------------------------------------------------------------------- -# pull in common atmosphere configuration -#--------------------------------------------------------------------------------- THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) -include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../../libraries/config/templates/exosphere.mk - -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(__RECURSIVE__),1) -#--------------------------------------------------------------------------------- - -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) - -CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) -CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) -SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) -BINFILES := - -#--------------------------------------------------------------------------------- -# 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_BIN := $(addsuffix .h,$(subst .,_,$(subst -,_,$(BINFILES)))) - -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I. - -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) - -export TOPDIR := $(CURRENT_DIRECTORY) - -OUTPUT_BASE := $(TOPDIR)/$(notdir $(TOPDIR)) - -#--------------------------------------------------------------------------------- - -ATMOSPHERE_BUILD_CONFIGS := -all: release define ATMOSPHERE_ADD_TARGET ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -$(strip $1): check_libexo_$(strip $1) $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) - @$$(MAKE) __RECURSIVE__=1 OUTPUT=$$(OUTPUT_BASE)$(strip $2) $(3) \ - DEPSDIR=$$(CURDIR)/$$(ATMOSPHERE_BUILD_DIR)/$(strip $1) \ - LIBEXOSPHERE_NAME=exosphere$(strip $2) \ - --no-print-directory -C $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) \ - -f $$(THIS_MAKEFILE) - -check_libexo_$(strip $1): - @$$(MAKE) --no-print-directory -C $$(ATMOSPHERE_LIBRARIES_DIR)/libexosphere $$(ATMOSPHERE_ARCH_NAME)-$(strip $1) +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/rebootstub.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) clean-$(strip $1): - @echo clean $(strip $1) ... - @rm -fr $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) $$(OUTPUT_BASE)$(strip $2).bin $$(OUTPUT_BASE)$(strip $2).elf + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/rebootstub.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) endef -$(eval $(call ATMOSPHERE_ADD_TARGET, release, , \ - ATMOSPHERE_BUILD_SETTINGS="-DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS" \ +define ATMOSPHERE_ADD_TARGETS + +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ )) -$(eval $(call ATMOSPHERE_ADD_TARGET, debug, _debug, \ - ATMOSPHERE_BUILD_SETTINGS="-DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS -DAMS_BUILD_FOR_DEBUGGING" \ +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ )) -$(eval $(call ATMOSPHERE_ADD_TARGET, audit, _audit, \ - ATMOSPHERE_BUILD_SETTINGS="-DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS -DAMS_BUILD_FOR_AUDITING" \ +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ )) -$(ATMOSPHERE_BUILD_DIR)/%: - @[ -d $@ ] || mkdir -p $@ +endef + +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm7tdmi,)) -#--------------------------------------------------------------------------------- clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) -.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),$(config) clean-$(config)) - -#--------------------------------------------------------------------------------- -else - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- - -$(OUTPUT).bin : $(OUTPUT).elf - $(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@ - @echo built ... $(notdir $@) - -$(OUTPUT).elf : $(OFILES) - -$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/lib$(LIBEXOSPHERE_NAME).a - -%.elf: - @echo linking $(notdir $@) - $(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ - @$(NM) -CSn $@ > $(notdir $*.lst) - -$(OFILES_SRC) : $(HFILES_BIN) - -#--------------------------------------------------------------------------------- -# you need a rule like this for each extension you use as binary data -#--------------------------------------------------------------------------------- -%.bin.o %_bin.h: %.bin -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) - --include $(DEPENDS) - -#--------------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------------- +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/exosphere/program/rebootstub/rebootstub.mk b/exosphere/program/rebootstub/rebootstub.mk new file mode 100644 index 000000000..7ab59a955 --- /dev/null +++ b/exosphere/program/rebootstub/rebootstub.mk @@ -0,0 +1,113 @@ +#--------------------------------------------------------------------------------- +# pull in common atmosphere configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(CURRENT_DIRECTORY)/../../../libraries/config/templates/exosphere.mk + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(__RECURSIVE__),1) +#--------------------------------------------------------------------------------- + +export ATMOSPHERE_TOPDIR := $(CURRENT_DIRECTORY) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) +CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) +SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) +BINFILES := + +#--------------------------------------------------------------------------------- +# 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_BIN := $(addsuffix .h,$(subst .,_,$(subst -,_,$(BINFILES)))) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I. + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) + +.PHONY: clean all check_lib + +#--------------------------------------------------------------------------------- +all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a + @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/$(notdir $(ATMOSPHERE_TOPDIR)) \ + DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ + --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ + -f $(THIS_MAKEFILE) + +$(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a: check_lib + @$(SILENTCMD)echo "Checked library." + +ifeq ($(ATMOSPHERE_CHECKED_LIBEXOSPHERE),1) +check_lib: +else +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk +endif + +$(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): + @[ -d $@ ] || mkdir -p $@ + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_OUT_DIR) + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- + +$(OUTPUT).bin : $(OUTPUT).elf + $(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@ + @echo built ... $(notdir $@) + +$(OUTPUT).elf : $(OFILES) + +$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a + +%.elf: + @echo linking $(notdir $@) + $(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ + @$(NM) -CSn $@ > $(notdir $*.lst) + +$(OFILES_SRC) : $(HFILES_BIN) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o %_bin.h: %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/exosphere/program/rebootstub/rebootstub.specs b/exosphere/program/rebootstub/rebootstub.specs index 59b3762e3..e480720e7 100644 --- a/exosphere/program/rebootstub/rebootstub.specs +++ b/exosphere/program/rebootstub/rebootstub.specs @@ -1,4 +1,4 @@ %rename link old_link *link: -%(old_link) -T %:getenv(TOPDIR /rebootstub.ld) --gc-sections --nmagic \ No newline at end of file +%(old_link) -T %:getenv(ATMOSPHERE_TOPDIR /rebootstub.ld) --gc-sections --nmagic \ No newline at end of file diff --git a/exosphere/program/sc7fw/Makefile b/exosphere/program/sc7fw/Makefile index 67a33cd70..76641d72b 100644 --- a/exosphere/program/sc7fw/Makefile +++ b/exosphere/program/sc7fw/Makefile @@ -1,139 +1,41 @@ -#--------------------------------------------------------------------------------- -# Define the atmosphere board and cpu -#--------------------------------------------------------------------------------- -export ATMOSPHERE_BOARD := nx-hac-001 -export ATMOSPHERE_CPU := arm7tdmi +ATMOSPHERE_BUILD_CONFIGS := +all: nx_release -#--------------------------------------------------------------------------------- -# pull in common atmosphere configuration -#--------------------------------------------------------------------------------- THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) -include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../../libraries/config/templates/exosphere.mk - -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(__RECURSIVE__),1) -#--------------------------------------------------------------------------------- - -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) - -CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) -CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) -SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) -BINFILES := - -#--------------------------------------------------------------------------------- -# 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_BIN := $(addsuffix .h,$(subst .,_,$(subst -,_,$(BINFILES)))) - -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I. - -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) - -export TOPDIR := $(CURRENT_DIRECTORY) - -OUTPUT_BASE := $(TOPDIR)/$(notdir $(TOPDIR)) - -#--------------------------------------------------------------------------------- - -ATMOSPHERE_BUILD_CONFIGS := -all: release define ATMOSPHERE_ADD_TARGET ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -$(strip $1): check_libexo_$(strip $1) $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) - @$$(MAKE) __RECURSIVE__=1 OUTPUT=$$(OUTPUT_BASE)$(strip $2) $(3) \ - DEPSDIR=$$(CURDIR)/$$(ATMOSPHERE_BUILD_DIR)/$(strip $1) \ - LIBEXOSPHERE_NAME=exosphere$(strip $2) \ - --no-print-directory -C $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) \ - -f $$(THIS_MAKEFILE) - -check_libexo_$(strip $1): - @$$(MAKE) --no-print-directory -C $$(ATMOSPHERE_LIBRARIES_DIR)/libexosphere $$(ATMOSPHERE_ARCH_NAME)-$(strip $1) +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/sc7fw.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) clean-$(strip $1): - @echo clean $(strip $1) ... - @rm -fr $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) $$(OUTPUT_BASE)$(strip $2).bin $$(OUTPUT_BASE)$(strip $2).elf + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/sc7fw.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) endef -$(eval $(call ATMOSPHERE_ADD_TARGET, release, , \ - ATMOSPHERE_BUILD_SETTINGS="-DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS" \ +define ATMOSPHERE_ADD_TARGETS + +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ )) -$(eval $(call ATMOSPHERE_ADD_TARGET, debug, _debug, \ - ATMOSPHERE_BUILD_SETTINGS="-DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS -DAMS_BUILD_FOR_DEBUGGING" \ +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ )) -$(eval $(call ATMOSPHERE_ADD_TARGET, audit, _audit, \ - ATMOSPHERE_BUILD_SETTINGS="-DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS -DAMS_BUILD_FOR_AUDITING" \ +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ )) -$(ATMOSPHERE_BUILD_DIR)/%: - @[ -d $@ ] || mkdir -p $@ +endef + +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm7tdmi,)) -#--------------------------------------------------------------------------------- clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) -.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),$(config) clean-$(config)) - -#--------------------------------------------------------------------------------- -else - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- - -$(OUTPUT).bin : $(OUTPUT).elf - $(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@ - @echo built ... $(notdir $@) - -$(OUTPUT).elf : $(OFILES) - -$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/lib$(LIBEXOSPHERE_NAME).a - -%.elf: - @echo linking $(notdir $@) - $(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ - @$(NM) -CSn $@ > $(notdir $*.lst) - -$(OFILES_SRC) : $(HFILES_BIN) - -#--------------------------------------------------------------------------------- -# you need a rule like this for each extension you use as binary data -#--------------------------------------------------------------------------------- -%.bin.o %_bin.h: %.bin -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) - --include $(DEPENDS) - -#--------------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------------- +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/exosphere/program/sc7fw/sc7fw.mk b/exosphere/program/sc7fw/sc7fw.mk new file mode 100644 index 000000000..7ab59a955 --- /dev/null +++ b/exosphere/program/sc7fw/sc7fw.mk @@ -0,0 +1,113 @@ +#--------------------------------------------------------------------------------- +# pull in common atmosphere configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(CURRENT_DIRECTORY)/../../../libraries/config/templates/exosphere.mk + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(__RECURSIVE__),1) +#--------------------------------------------------------------------------------- + +export ATMOSPHERE_TOPDIR := $(CURRENT_DIRECTORY) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) +CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) +SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) +BINFILES := + +#--------------------------------------------------------------------------------- +# 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_BIN := $(addsuffix .h,$(subst .,_,$(subst -,_,$(BINFILES)))) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I. + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) + +.PHONY: clean all check_lib + +#--------------------------------------------------------------------------------- +all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a + @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/$(notdir $(ATMOSPHERE_TOPDIR)) \ + DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ + --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ + -f $(THIS_MAKEFILE) + +$(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a: check_lib + @$(SILENTCMD)echo "Checked library." + +ifeq ($(ATMOSPHERE_CHECKED_LIBEXOSPHERE),1) +check_lib: +else +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk +endif + +$(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): + @[ -d $@ ] || mkdir -p $@ + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_OUT_DIR) + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- + +$(OUTPUT).bin : $(OUTPUT).elf + $(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@ + @echo built ... $(notdir $@) + +$(OUTPUT).elf : $(OFILES) + +$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a + +%.elf: + @echo linking $(notdir $@) + $(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ + @$(NM) -CSn $@ > $(notdir $*.lst) + +$(OFILES_SRC) : $(HFILES_BIN) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o %_bin.h: %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/exosphere/program/sc7fw/sc7fw.specs b/exosphere/program/sc7fw/sc7fw.specs index 6275fb4d3..8b876c978 100644 --- a/exosphere/program/sc7fw/sc7fw.specs +++ b/exosphere/program/sc7fw/sc7fw.specs @@ -1,4 +1,4 @@ %rename link old_link *link: -%(old_link) -T %:getenv(TOPDIR /sc7fw.ld) --gc-sections --nmagic \ No newline at end of file +%(old_link) -T %:getenv(ATMOSPHERE_TOPDIR /sc7fw.ld) --gc-sections --nmagic \ No newline at end of file diff --git a/exosphere/program/source/smc/secmon_smc_power_management.cpp b/exosphere/program/source/smc/secmon_smc_power_management.cpp index c976ff7bf..7747bb090 100644 --- a/exosphere/program/source/smc/secmon_smc_power_management.cpp +++ b/exosphere/program/source/smc/secmon_smc_power_management.cpp @@ -408,6 +408,7 @@ namespace ams::secmon::smc { /* Log our suspension. */ /* NOTE: Nintendo only does this on dev, but we will always do it. */ if (true /* !pkg1::IsProduction() */) { + log::Initialize(secmon::GetLogPort(), secmon::GetLogBaudRate(), secmon::GetLogFlags()); log::SendText("OYASUMI\n", 8); log::Flush(); } diff --git a/exosphere/program/split_program.py b/exosphere/program/split_program.py index a9c70a8d7..ec4e74c37 100644 --- a/exosphere/program/split_program.py +++ b/exosphere/program/split_program.py @@ -20,17 +20,17 @@ def split_binary(data): #print ('%X %X %X %X' % (START, BOOT_CODE_START, BOOT_CODE_END, PROGRAM_START)) boot_code = data[BOOT_CODE_START - START:BOOT_CODE_END - BOOT_CODE_START] program = data[PROGRAM_START - START:] - return [('boot_code%s.lz4', lz4_compress(boot_code)), ('program%s.lz4', lz4_compress(program))] + return [('boot_code.lz4', lz4_compress(boot_code)), ('program.lz4', lz4_compress(program))] def main(argc, argv): - if argc != 4: - print('Usage: %s in suffix outdir' % argv[0]) + if argc != 3: + print('Usage: %s in outdir' % argv[0]) return 1 with open(argv[1], 'rb') as f: data = f.read() assert len(data) >= 0x40 for (fn, fdata) in split_binary(data): - with open('%s/%s' % (argv[3], fn % argv[2]), 'wb') as f: + with open('%s/%s' % (argv[2], fn), 'wb') as f: f.write(fdata) return 0 diff --git a/exosphere/warmboot/Makefile b/exosphere/warmboot/Makefile index 38f82fa70..94881dc4b 100644 --- a/exosphere/warmboot/Makefile +++ b/exosphere/warmboot/Makefile @@ -1,139 +1,41 @@ -#--------------------------------------------------------------------------------- -# Define the atmosphere board and cpu -#--------------------------------------------------------------------------------- -export ATMOSPHERE_BOARD := nx-hac-001 -export ATMOSPHERE_CPU := arm7tdmi +ATMOSPHERE_BUILD_CONFIGS := +all: nx_release -#--------------------------------------------------------------------------------- -# pull in common atmosphere configuration -#--------------------------------------------------------------------------------- THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) -include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/exosphere.mk - -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(__RECURSIVE__),1) -#--------------------------------------------------------------------------------- - -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) - -CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) -CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) -SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) -BINFILES := - -#--------------------------------------------------------------------------------- -# 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_BIN := $(addsuffix .h,$(subst .,_,$(subst -,_,$(BINFILES)))) - -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I. - -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) - -export TOPDIR := $(CURRENT_DIRECTORY) - -OUTPUT_BASE := $(TOPDIR)/$(notdir $(TOPDIR)) - -#--------------------------------------------------------------------------------- - -ATMOSPHERE_BUILD_CONFIGS := -all: release define ATMOSPHERE_ADD_TARGET ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -$(strip $1): check_libexo_$(strip $1) $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) - @$$(MAKE) __RECURSIVE__=1 OUTPUT=$$(OUTPUT_BASE)$(strip $2) $(3) \ - DEPSDIR=$$(CURDIR)/$$(ATMOSPHERE_BUILD_DIR)/$(strip $1) \ - LIBEXOSPHERE_NAME=exosphere$(strip $2) \ - --no-print-directory -C $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) \ - -f $$(THIS_MAKEFILE) - -check_libexo_$(strip $1): - @$$(MAKE) --no-print-directory -C $$(ATMOSPHERE_LIBRARIES_DIR)/libexosphere $$(ATMOSPHERE_ARCH_NAME)-$(strip $1) +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/warmboot.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) clean-$(strip $1): - @echo clean $(strip $1) ... - @rm -fr $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) $$(OUTPUT_BASE)$(strip $2).bin $$(OUTPUT_BASE)$(strip $2).elf + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/warmboot.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) endef -$(eval $(call ATMOSPHERE_ADD_TARGET, release, , \ - ATMOSPHERE_BUILD_SETTINGS="-DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS" \ +define ATMOSPHERE_ADD_TARGETS + +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ )) -$(eval $(call ATMOSPHERE_ADD_TARGET, debug, _debug, \ - ATMOSPHERE_BUILD_SETTINGS="-DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS -DAMS_BUILD_FOR_DEBUGGING" \ +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ )) -$(eval $(call ATMOSPHERE_ADD_TARGET, audit, _audit, \ - ATMOSPHERE_BUILD_SETTINGS="-DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS -DAMS_BUILD_FOR_AUDITING" \ +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ )) -$(ATMOSPHERE_BUILD_DIR)/%: - @[ -d $@ ] || mkdir -p $@ +endef + +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm7tdmi,)) -#--------------------------------------------------------------------------------- clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) -.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),$(config) clean-$(config)) - -#--------------------------------------------------------------------------------- -else - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- - -$(OUTPUT).bin : $(OUTPUT).elf - $(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@ - @echo built ... $(notdir $@) - -$(OUTPUT).elf : $(OFILES) - -$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/lib$(LIBEXOSPHERE_NAME).a - -%.elf: - @echo linking $(notdir $@) - $(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ - @$(NM) -CSn $@ > $(notdir $*.lst) - -$(OFILES_SRC) : $(HFILES_BIN) - -#--------------------------------------------------------------------------------- -# you need a rule like this for each extension you use as binary data -#--------------------------------------------------------------------------------- -%.bin.o %_bin.h: %.bin -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) - --include $(DEPENDS) - -#--------------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------------- +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/exosphere/warmboot/warmboot.mk b/exosphere/warmboot/warmboot.mk new file mode 100644 index 000000000..104130b75 --- /dev/null +++ b/exosphere/warmboot/warmboot.mk @@ -0,0 +1,113 @@ +#--------------------------------------------------------------------------------- +# pull in common atmosphere configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(CURRENT_DIRECTORY)/../../libraries/config/templates/exosphere.mk + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(__RECURSIVE__),1) +#--------------------------------------------------------------------------------- + +export ATMOSPHERE_TOPDIR := $(CURRENT_DIRECTORY) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) +CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) +SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) +BINFILES := + +#--------------------------------------------------------------------------------- +# 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_BIN := $(addsuffix .h,$(subst .,_,$(subst -,_,$(BINFILES)))) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I. + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) + +.PHONY: clean all check_lib + +#--------------------------------------------------------------------------------- +all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a + @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/$(notdir $(ATMOSPHERE_TOPDIR)) \ + DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ + --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ + -f $(THIS_MAKEFILE) + +$(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a: check_lib + @$(SILENTCMD)echo "Checked library." + +ifeq ($(ATMOSPHERE_CHECKED_LIBEXOSPHERE),1) +check_lib: +else +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk +endif + +$(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): + @[ -d $@ ] || mkdir -p $@ + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_OUT_DIR) + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- + +$(OUTPUT).bin : $(OUTPUT).elf + $(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@ + @echo built ... $(notdir $@) + +$(OUTPUT).elf : $(OFILES) + +$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a + +%.elf: + @echo linking $(notdir $@) + $(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ + @$(NM) -CSn $@ > $(notdir $*.lst) + +$(OFILES_SRC) : $(HFILES_BIN) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o %_bin.h: %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/exosphere/warmboot/warmboot.specs b/exosphere/warmboot/warmboot.specs index 67747462e..d496f5670 100644 --- a/exosphere/warmboot/warmboot.specs +++ b/exosphere/warmboot/warmboot.specs @@ -1,4 +1,4 @@ %rename link old_link *link: -%(old_link) -T %:getenv(TOPDIR /warmboot.ld) --gc-sections --nmagic \ No newline at end of file +%(old_link) -T %:getenv(ATMOSPHERE_TOPDIR /warmboot.ld) --gc-sections --nmagic \ No newline at end of file diff --git a/fusee/Makefile b/fusee/Makefile index 3656e7fee..120342c8b 100644 --- a/fusee/Makefile +++ b/fusee/Makefile @@ -1,44 +1,41 @@ ATMOSPHERE_BUILD_CONFIGS := -all: release +all: nx_release + +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) define ATMOSPHERE_ADD_TARGET ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -$(strip $1): fusee$(strip $2).bin +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/fusee.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -fusee$(strip $2).bin: loader_stub/loader_stub$(strip $2).bin - @cp loader_stub/loader_stub$(strip $2).bin fusee$(strip $2).bin - @echo "Built fusee$(strip $2).bin..." - -check_program_$(strip $1): - @$$(MAKE) -C program $(strip $1) - -loader_stub/loader_stub$(strip $2).bin: check_program_$(strip $1) - @$$(MAKE) -C loader_stub $(strip $1) - -clean-$(strip $1): clean-program-$(strip $1) clean-loader_stub-$(strip $1) - @rm -rf fusee$(strip $2).bin - -clean-program-$(strip $1): - @$$(MAKE) -C program clean-$(strip $1) - -clean-loader_stub-$(strip $1): - @$$(MAKE) -C loader_stub clean-$(strip $1) +clean-$(strip $1): + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/fusee.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) endef -$(eval $(call ATMOSPHERE_ADD_TARGET, release, )) -$(eval $(call ATMOSPHERE_ADD_TARGET, debug, _debug)) -$(eval $(call ATMOSPHERE_ADD_TARGET, audit, _audit)) +define ATMOSPHERE_ADD_TARGETS -clean: clean-program clean-loader_stub - @rm -rf fusee*.bin package3* +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ +)) -clean-program: - @$(MAKE) -C program clean +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ +)) -clean-loader_stub: - @$(MAKE) -C loader_stub clean +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ +)) -.PHONY: all clean clean-program clean-loader_stub $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),check_program_$(config) check_warmboot_$(strip $1) clean-$(config) clean-program-$(config) clean-loader_stub-$(config) clean-warmboot-$(config)) +endef + +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm7tdmi,)) + +clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) + +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/fusee/build_package3.py b/fusee/build_package3.py index 5bbc7340a..d4d8bed16 100644 --- a/fusee/build_package3.py +++ b/fusee/build_package3.py @@ -22,15 +22,15 @@ def get_overlay(program, i): KIP_NAMES = [b'Loader', b'NCM', b'ProcessManager', b'sm', b'boot', b'spl', b'ams_mitm'] -def get_kips(ams_dir): +def get_kips(ams_dir, build_out_dir): emummc = read_file(os.path.join(ams_dir, 'emummc/emummc_unpacked.kip')) - loader = read_file(os.path.join(ams_dir, 'stratosphere/loader/loader.kip')) - ncm = read_file(os.path.join(ams_dir, 'stratosphere/ncm/ncm.kip')) - pm = read_file(os.path.join(ams_dir, 'stratosphere/pm/pm.kip')) - sm = read_file(os.path.join(ams_dir, 'stratosphere/sm/sm.kip')) - boot = read_file(os.path.join(ams_dir, 'stratosphere/boot/boot.kip')) - spl = read_file(os.path.join(ams_dir, 'stratosphere/spl/spl.kip')) - ams_mitm = read_file(os.path.join(ams_dir, 'stratosphere/ams_mitm/ams_mitm.kip')) + loader = read_file(os.path.join(ams_dir, 'stratosphere/loader/%s/loader.kip' % build_out_dir)) + ncm = read_file(os.path.join(ams_dir, 'stratosphere/ncm/%s/ncm.kip' % build_out_dir)) + pm = read_file(os.path.join(ams_dir, 'stratosphere/pm/%s/pm.kip' % build_out_dir)) + sm = read_file(os.path.join(ams_dir, 'stratosphere/sm/%s/sm.kip' % build_out_dir)) + boot = read_file(os.path.join(ams_dir, 'stratosphere/boot/%s/boot.kip' % build_out_dir)) + spl = read_file(os.path.join(ams_dir, 'stratosphere/spl/%s/spl.kip' % build_out_dir)) + ams_mitm = read_file(os.path.join(ams_dir, 'stratosphere/ams_mitm/%s/ams_mitm.kip' % build_out_dir)) return (emummc, { b'Loader' : loader, b'NCM' : ncm, @@ -134,39 +134,40 @@ def write_kips(f, all_kips): f.write(b'\xCC' * (0x300000 - tot)) def main(argc, argv): - if argc != 12: - print('Usage: %s ams_dir target revision major minor micro relstep s_major s_minor s_micro s_relstep' % argv[0]) + if argc != 13: + print('Usage: %s ams_dir build_out_dir build_boot_out_dir revision major minor micro relstep s_major s_minor s_micro s_relstep' % argv[0]) return 1 # Parse arguments - ams_dir = argv[1] - target = '' if argv[2] == 'release' else ('_%s' % argv[2]) - revision = int(argv[3][:8], 16) - major = int(argv[4]) - minor = int(argv[5]) - micro = int(argv[6]) - relstep = int(argv[7]) - s_major = int(argv[8]) - s_minor = int(argv[9]) - s_micro = int(argv[10]) - s_relstep = int(argv[11]) + ams_dir = argv[1] + build_out_dir = argv[2] + build_boot_out_dir = argv[3] + revision = int(argv[4][:8], 16) + major = int(argv[5]) + minor = int(argv[6]) + micro = int(argv[7]) + relstep = int(argv[8]) + s_major = int(argv[9]) + s_minor = int(argv[10]) + s_micro = int(argv[11]) + s_relstep = int(argv[12]) # Read/parse fusee - fusee_program = read_file(os.path.join(ams_dir, 'fusee/program/program%s.bin' % target)) - fusee_bin = read_file(os.path.join(ams_dir, 'fusee/fusee%s.bin' % target)) + fusee_program = read_file(os.path.join(ams_dir, 'fusee/program/%s/program.bin' % build_boot_out_dir)) + fusee_bin = read_file(os.path.join(ams_dir, 'fusee/%s/fusee.bin' % build_boot_out_dir)) erista_mtc = get_overlay(fusee_program, 1) mariko_mtc = get_overlay(fusee_program, 2) erista_hsh = hashlib.sha256(erista_mtc[:-4]).digest()[:4] mariko_hsh = hashlib.sha256(mariko_mtc[:-4]).digest()[:4] # Read other files - exosphere = read_file(os.path.join(ams_dir, 'exosphere/exosphere%s.bin' % target)) - warmboot = read_file(os.path.join(ams_dir, 'exosphere/warmboot%s.bin' % target)) - mariko_fatal = read_file(os.path.join(ams_dir, 'exosphere/mariko_fatal%s.bin' % target)) - rebootstub = read_file(os.path.join(ams_dir, 'exosphere/program/rebootstub/rebootstub%s.bin' % target)) - mesosphere = read_file(os.path.join(ams_dir, 'mesosphere/mesosphere%s.bin' % target)) - all_kips = get_kips(ams_dir) + exosphere = read_file(os.path.join(ams_dir, 'exosphere/%s/exosphere.bin' % build_out_dir)) + warmboot = read_file(os.path.join(ams_dir, 'exosphere/warmboot/%s/warmboot.bin' % build_boot_out_dir)) + mariko_fatal = read_file(os.path.join(ams_dir, 'exosphere/mariko_fatal/%s/mariko_fatal.bin' % build_out_dir)) + rebootstub = read_file(os.path.join(ams_dir, 'exosphere/program/rebootstub/%s/rebootstub.bin' % build_boot_out_dir)) + mesosphere = read_file(os.path.join(ams_dir, 'mesosphere/%s/mesosphere.bin' % build_out_dir)) + all_kips = get_kips(ams_dir, build_out_dir) tsec_keygen = read_file(os.path.join(ams_dir, 'fusee/program/tsec_keygen/tsec_keygen.bin')) splash_bin = read_file(os.path.join(ams_dir, 'img/splash.bin')) assert len(splash_bin) == 0x3C0000 - with open(os.path.join(ams_dir, 'fusee/package3%s' % target), 'wb') as f: + with open(os.path.join(ams_dir, 'fusee/%s/package3' % build_boot_out_dir), 'wb') as f: # Write header write_header(f, all_kips, len(warmboot), len(tsec_keygen), len(mariko_fatal), len(exosphere), len(mesosphere), len(fusee_bin), len(rebootstub), revision, major, minor, micro, relstep, s_major, s_minor, s_micro, s_relstep) # Write warmboot diff --git a/fusee/fusee.mk b/fusee/fusee.mk new file mode 100644 index 000000000..998d3c1e5 --- /dev/null +++ b/fusee/fusee.mk @@ -0,0 +1,48 @@ +#--------------------------------------------------------------------------------- +# pull in common atmosphere configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(CURRENT_DIRECTORY)/../libraries/config/common.mk + +all: $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/fusee.bin + +$(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/fusee.bin: $(CURRENT_DIRECTORY)/loader_stub/$(ATMOSPHERE_OUT_DIR)/loader_stub.bin $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR) + @cp $(CURRENT_DIRECTORY)/loader_stub/$(ATMOSPHERE_OUT_DIR)/loader_stub.bin $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/fusee.bin + @echo "Built fusee.bin..." + +$(CURRENT_DIRECTORY)/loader_stub/$(ATMOSPHERE_OUT_DIR)/loader_stub.bin: check_loader_stub + @$(SILENTCMD)echo "Checked loader stub." + +$(CURRENT_DIRECTORY)/program/$(ATMOSPHERE_OUT_DIR)/program.bin: check_program + @$(SILENTCMD)echo "Checked program." + +$(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a: check_lib + @$(SILENTCMD)echo "Checked library." + +check_loader_stub: $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a $(CURRENT_DIRECTORY)/program/$(ATMOSPHERE_OUT_DIR)/program.bin + @$(SILENTCMD)echo "Checking loader stub..." + @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/loader_stub -f $(CURRENT_DIRECTORY)/loader_stub/loader_stub.mk ATMOSPHERE_CHECKED_LIBEXOSPHERE=1 ATMOSPHERE_CHECKED_FUSEE_PROGRAM=1 + +check_program: $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a + @$(SILENTCMD)echo "Checking program..." + @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/program -f $(CURRENT_DIRECTORY)/program/program.mk ATMOSPHERE_CHECKED_LIBEXOSPHERE=1 + +ifeq ($(ATMOSPHERE_CHECKED_LIBEXOSPHERE),1) +check_lib: +else +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk +endif + +$(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR): + @[ -d $@ ] || mkdir -p $@ + +clean: + @echo clean ... + @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/loader_stub -f $(CURRENT_DIRECTORY)/loader_stub/loader_stub.mk clean + @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/program -f $(CURRENT_DIRECTORY)/program/program.mk clean + @rm -fr $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR) + @for i in $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR); do [ -d $$i ] && rmdir --ignore-fail-on-non-empty $$i || true; done + +.PHONY: all clean check_lib check_loader_stub check_program \ No newline at end of file diff --git a/fusee/loader_stub/Makefile b/fusee/loader_stub/Makefile index 8cd08d11f..af41919d6 100644 --- a/fusee/loader_stub/Makefile +++ b/fusee/loader_stub/Makefile @@ -1,154 +1,41 @@ -#--------------------------------------------------------------------------------- -# Define the atmosphere board and cpu -#--------------------------------------------------------------------------------- -export ATMOSPHERE_BOARD := nx-hac-001 -export ATMOSPHERE_CPU := arm7tdmi +ATMOSPHERE_BUILD_CONFIGS := +all: nx_release -#--------------------------------------------------------------------------------- -# pull in common atmosphere configuration -#--------------------------------------------------------------------------------- THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) -include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/exosphere.mk - -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(__RECURSIVE__),1) -#--------------------------------------------------------------------------------- - -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) - -CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) -CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) -SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) -BINFILES := - -#--------------------------------------------------------------------------------- -# 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) program.lz4.o -export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(subst -,_,$(BINFILES)))) - -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I. - -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) - -export TOPDIR := $(CURRENT_DIRECTORY) - -OUTPUT_BASE := $(TOPDIR)/$(notdir $(TOPDIR)) - -#--------------------------------------------------------------------------------- - -ATMOSPHERE_BUILD_CONFIGS := -all: release define ATMOSPHERE_ADD_TARGET ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -$(strip $1): check_libexo_$(strip $1) $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) - @$$(MAKE) __RECURSIVE__=1 OUTPUT=$$(OUTPUT_BASE)$(strip $2) $(3) \ - ATMOSPHERE_BUILD_TARGET_IDENTIFIER=$(strip $1) \ - ATMOSPHERE_BUILD_TARGET_BINARY_SUFFIX=$(strip $2) \ - DEPSDIR=$$(CURDIR)/$$(ATMOSPHERE_BUILD_DIR)/$(strip $1) \ - LIBEXOSPHERE_NAME=exosphere$(strip $2) \ - --no-print-directory -C $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) \ - -f $$(THIS_MAKEFILE) - -check_libexo_$(strip $1): - @$$(MAKE) --no-print-directory -C $$(ATMOSPHERE_LIBRARIES_DIR)/libexosphere $$(ATMOSPHERE_ARCH_NAME)-$(strip $1) +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/loader_stub.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) clean-$(strip $1): - @echo clean $(strip $1) ... - @rm -fr $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) $$(OUTPUT_BASE)$(strip $2).bin $$(OUTPUT_BASE)$(strip $2).elf + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/loader_stub.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) endef -$(eval $(call ATMOSPHERE_ADD_TARGET, release, , \ - ATMOSPHERE_BUILD_SETTINGS="-DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS" \ +define ATMOSPHERE_ADD_TARGETS + +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ )) -$(eval $(call ATMOSPHERE_ADD_TARGET, debug, _debug, \ - ATMOSPHERE_BUILD_SETTINGS="-DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS -DAMS_BUILD_FOR_DEBUGGING" \ +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ )) -$(eval $(call ATMOSPHERE_ADD_TARGET, audit, _audit, \ - ATMOSPHERE_BUILD_SETTINGS="-DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS -DAMS_BUILD_FOR_AUDITING" \ +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ )) -$(ATMOSPHERE_BUILD_DIR)/%: - @[ -d $@ ] || mkdir -p $@ +endef + +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm7tdmi,)) -#--------------------------------------------------------------------------------- clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) -.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),$(config) clean-$(config)) - -#--------------------------------------------------------------------------------- -else - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- - -$(OUTPUT).bin : $(OUTPUT).elf - $(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@ - @echo built ... $(notdir $@) - -$(OUTPUT).elf : $(OFILES) - -$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/lib$(LIBEXOSPHERE_NAME).a - -program.lz4.o: program_lz4.h - -program_lz4.h: $(TOPDIR)/../program/program$(ATMOSPHERE_BUILD_TARGET_BINARY_SUFFIX).lz4 - @echo $(notdir $<) - @rm -rf tmp_program_$(ATMOSPHERE_BUILD_TARGET_IDENTIFIER) - @mkdir -p tmp_program_$(ATMOSPHERE_BUILD_TARGET_IDENTIFIER) - @cp $(TOPDIR)/../program/program$(ATMOSPHERE_BUILD_TARGET_BINARY_SUFFIX).lz4 tmp_program_$(ATMOSPHERE_BUILD_TARGET_IDENTIFIER)/program.lz4 - @bin2s -a 8 -H program_lz4.h tmp_program_$(ATMOSPHERE_BUILD_TARGET_IDENTIFIER)/program.lz4 | $(AS) -o program.lz4.o - @rm -rf tmp_program_$(ATMOSPHERE_BUILD_TARGET_IDENTIFIER) - -$(TOPDIR)/../program/program$(ATMOSPHERE_BUILD_TARGET_BINARY_SUFFIX).lz4: - @$(MAKE) __RECURSIVE__=0 --no-print-directory -C $(TOPDIR)/../program $(ATMOSPHERE_BUILD_TARGET_IDENTIFIER) - -%.elf: - @echo linking $(notdir $@) - $(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ - @$(NM) -CSn $@ > $(notdir $*.lst) - -$(OFILES_SRC) : $(HFILES_BIN) program_lz4.h - -#--------------------------------------------------------------------------------- -# you need a rule like this for each extension you use as binary data -#--------------------------------------------------------------------------------- -%.bin.o %_bin.h: %.bin -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) - --include $(DEPENDS) - -#--------------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------------- +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/fusee/loader_stub/loader_stub.mk b/fusee/loader_stub/loader_stub.mk new file mode 100644 index 000000000..7cc7f7a35 --- /dev/null +++ b/fusee/loader_stub/loader_stub.mk @@ -0,0 +1,127 @@ +#--------------------------------------------------------------------------------- +# pull in common atmosphere configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(CURRENT_DIRECTORY)/../../libraries/config/templates/exosphere.mk + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(__RECURSIVE__),1) +#--------------------------------------------------------------------------------- + +export ATMOSPHERE_TOPDIR := $(CURRENT_DIRECTORY) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) $(CURRENT_DIRECTORY)/../program/$(ATMOSPHERE_OUT_DIR) + +CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) +CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) +SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) +BINFILES := program.lz4 + +#--------------------------------------------------------------------------------- +# 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_BIN := $(addsuffix .h,$(subst .,_,$(subst -,_,$(BINFILES)))) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I. + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) + +.PHONY: clean all check_lib + +#--------------------------------------------------------------------------------- +all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a $(CURRENT_DIRECTORY)/../program/$(ATMOSPHERE_OUT_DIR)/program.lz4 + @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/$(notdir $(ATMOSPHERE_TOPDIR)) \ + DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ + --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ + -f $(THIS_MAKEFILE) + +$(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a: check_lib + @$(SILENTCMD)echo "Checked library." + +$(CURRENT_DIRECTORY)/../program/$(ATMOSPHERE_OUT_DIR)/program.lz4: check_fusee_program + @$(SILENTCMD)echo "Checked fusee program." + +ifeq ($(ATMOSPHERE_CHECKED_LIBEXOSPHERE),1) +check_lib: +else +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk +endif + +ifeq ($(ATMOSPHERE_CHECKED_FUSEE_PROGRAM),1) +check_fusee_program: +else +check_fusee_program: check_lib + @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/../program -f $(CURRENT_DIRECTORY)/../program/program.mk ATMOSPHERE_CHECKED_LIBEXOSPHERE=1 +endif + +$(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): + @[ -d $@ ] || mkdir -p $@ + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_OUT_DIR) + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- + +$(OUTPUT).bin : $(OUTPUT).elf + $(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@ + @echo built ... $(notdir $@) + +$(OUTPUT).elf : $(OFILES) + +$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a + +%.elf: + @echo linking $(notdir $@) + $(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ + @$(NM) -CSn $@ > $(notdir $*.lst) + +program.lz4.o: program.lz4 + @echo $(notdir $<) + @$(bin2o) + +$(OFILES_SRC) : $(OFILES_BIN) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o %_bin.h: %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/fusee/loader_stub/loader_stub.specs b/fusee/loader_stub/loader_stub.specs index 261cffccd..7326f34de 100644 --- a/fusee/loader_stub/loader_stub.specs +++ b/fusee/loader_stub/loader_stub.specs @@ -1,4 +1,4 @@ %rename link old_link *link: -%(old_link) -T %:getenv(TOPDIR /loader_stub.ld) --gc-sections --nmagic \ No newline at end of file +%(old_link) -T %:getenv(ATMOSPHERE_TOPDIR /loader_stub.ld) --gc-sections --nmagic \ No newline at end of file diff --git a/fusee/program/Makefile b/fusee/program/Makefile index 2c4b9a425..7e5fde265 100644 --- a/fusee/program/Makefile +++ b/fusee/program/Makefile @@ -1,144 +1,41 @@ -#--------------------------------------------------------------------------------- -# Define the atmosphere board and cpu -#--------------------------------------------------------------------------------- -export ATMOSPHERE_BOARD := nx-hac-001 -export ATMOSPHERE_CPU := arm7tdmi +ATMOSPHERE_BUILD_CONFIGS := +all: nx_release -#--------------------------------------------------------------------------------- -# pull in common atmosphere configuration -#--------------------------------------------------------------------------------- THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) -include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/exosphere.mk - -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(__RECURSIVE__),1) -#--------------------------------------------------------------------------------- - -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) - -CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) -CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) -SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) -BINFILES := - -#--------------------------------------------------------------------------------- -# 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_BIN := $(addsuffix .h,$(subst .,_,$(subst -,_,$(BINFILES)))) - -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I. - -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) - -export TOPDIR := $(CURRENT_DIRECTORY) - -OUTPUT_BASE := $(TOPDIR)/$(notdir $(TOPDIR)) - -#--------------------------------------------------------------------------------- - -ATMOSPHERE_BUILD_CONFIGS := -all: release define ATMOSPHERE_ADD_TARGET ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -$(strip $1): check_libexo_$(strip $1) $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) - @$$(MAKE) __RECURSIVE__=1 OUTPUT=$$(OUTPUT_BASE)$(strip $2) $(3) \ - ATMOSPHERE_BUILD_TARGET=$(strip $2) \ - DEPSDIR=$$(CURDIR)/$$(ATMOSPHERE_BUILD_DIR)/$(strip $1) \ - LIBEXOSPHERE_NAME=exosphere$(strip $2) \ - --no-print-directory -C $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) \ - -f $$(THIS_MAKEFILE) - -check_libexo_$(strip $1): - @$$(MAKE) --no-print-directory -C $$(ATMOSPHERE_LIBRARIES_DIR)/libexosphere $$(ATMOSPHERE_ARCH_NAME)-$(strip $1) +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/program.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) clean-$(strip $1): - @echo clean $(strip $1) ... - @rm -fr $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) $$(OUTPUT_BASE)$(strip $2).bin $$(OUTPUT_BASE)$(strip $2).lz4 $$(OUTPUT_BASE)$(strip $2).elf + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/program.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) endef -$(eval $(call ATMOSPHERE_ADD_TARGET, release, , \ - ATMOSPHERE_BUILD_SETTINGS="-DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS" \ +define ATMOSPHERE_ADD_TARGETS + +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ )) -$(eval $(call ATMOSPHERE_ADD_TARGET, debug, _debug, \ - ATMOSPHERE_BUILD_SETTINGS="-DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS -DAMS_BUILD_FOR_DEBUGGING" \ +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ )) -$(eval $(call ATMOSPHERE_ADD_TARGET, audit, _audit, \ - ATMOSPHERE_BUILD_SETTINGS="-DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS -DAMS_BUILD_FOR_AUDITING" \ +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ )) -$(ATMOSPHERE_BUILD_DIR)/%: - @[ -d $@ ] || mkdir -p $@ +endef + +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm7tdmi,)) -#--------------------------------------------------------------------------------- clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) -.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),$(config) clean-$(config)) - -#--------------------------------------------------------------------------------- -else - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- - -$(OUTPUT).lz4 : $(OUTPUT).bin - @python $(TOPDIR)/lz4_compress.py $(OUTPUT).bin $(OUTPUT).lz4 - @echo built ... $(notdir $@) - -$(OUTPUT).bin : $(OUTPUT).elf - $(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@ - @echo built ... $(notdir $@) - -$(OUTPUT).elf : $(OFILES) - -$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/lib$(LIBEXOSPHERE_NAME).a - -%.elf: - @echo linking $(notdir $@) - $(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ - @$(NM) -CSn $@ > $(notdir $*.lst) - -$(OFILES_SRC) : $(HFILES_BIN) - -#--------------------------------------------------------------------------------- -# you need a rule like this for each extension you use as binary data -#--------------------------------------------------------------------------------- -%.bin.o %_bin.h: %.bin -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) - --include $(DEPENDS) - -#--------------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------------- +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/fusee/program/program.mk b/fusee/program/program.mk new file mode 100644 index 000000000..63ad5385b --- /dev/null +++ b/fusee/program/program.mk @@ -0,0 +1,117 @@ +#--------------------------------------------------------------------------------- +# pull in common atmosphere configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(CURRENT_DIRECTORY)/../../libraries/config/templates/exosphere.mk + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(__RECURSIVE__),1) +#--------------------------------------------------------------------------------- + +export ATMOSPHERE_TOPDIR := $(CURRENT_DIRECTORY) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) +CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) +SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) +BINFILES := + +#--------------------------------------------------------------------------------- +# 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_BIN := $(addsuffix .h,$(subst .,_,$(subst -,_,$(BINFILES)))) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I. + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) + +.PHONY: clean all check_lib + +#--------------------------------------------------------------------------------- +all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a + @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/$(notdir $(ATMOSPHERE_TOPDIR)) \ + DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ + --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ + -f $(THIS_MAKEFILE) + +$(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a: check_lib + @$(SILENTCMD)echo "Checked library." + +ifeq ($(ATMOSPHERE_CHECKED_LIBEXOSPHERE),1) +check_lib: +else +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk +endif + +$(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): + @[ -d $@ ] || mkdir -p $@ + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_OUT_DIR) + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- + +$(OUTPUT).lz4 : $(OUTPUT).bin + @python $(CURRENT_DIRECTORY)/lz4_compress.py $(OUTPUT).bin $(OUTPUT).lz4 + @echo built ... $(notdir $@) + +$(OUTPUT).bin : $(OUTPUT).elf + $(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@ + @echo built ... $(notdir $@) + +$(OUTPUT).elf : $(OFILES) + +$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a + +%.elf: + @echo linking $(notdir $@) + $(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ + @$(NM) -CSn $@ > $(notdir $*.lst) + +$(OFILES_SRC) : $(HFILES_BIN) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o %_bin.h: %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/fusee/program/program.specs b/fusee/program/program.specs index 6940a62b1..1a9458f92 100644 --- a/fusee/program/program.specs +++ b/fusee/program/program.specs @@ -1,4 +1,4 @@ %rename link old_link *link: -%(old_link) -T %:getenv(TOPDIR /program_ovl.ld) -T %:getenv(TOPDIR /program.ld) --gc-sections --nmagic \ No newline at end of file +%(old_link) -T %:getenv(ATMOSPHERE_TOPDIR /program_ovl.ld) -T %:getenv(ATMOSPHERE_TOPDIR /program.ld) --gc-sections --nmagic \ No newline at end of file diff --git a/fusee/program/source/fusee_exception_handler.cpp b/fusee/program/source/fusee_exception_handler.cpp index 40059df3b..eaff48a0a 100644 --- a/fusee/program/source/fusee_exception_handler.cpp +++ b/fusee/program/source/fusee_exception_handler.cpp @@ -49,6 +49,22 @@ namespace ams::diag { nxboot::ShowFatalError("Abort called, lr=%p\n", reinterpret_cast(lr)); } + NORETURN void AssertionFailureImpl(const char *file, int line, const char *func, const char *expr, u64 value) { + AMS_UNUSED(file, line, func, expr, value); + + u32 lr; + __asm__ __volatile__("mov %0, lr" : "=r"(lr) :: "memory"); + nxboot::ShowFatalError("Assert called, lr=%p\n", reinterpret_cast(lr)); + } + + NORETURN void AssertionFailureImpl(const char *file, int line, const char *func, const char *expr, u64 value, const char *format, ...) { + AMS_UNUSED(file, line, func, expr, value, format); + + u32 lr; + __asm__ __volatile__("mov %0, lr" : "=r"(lr) :: "memory"); + nxboot::ShowFatalError("Assert called, lr=%p\n", reinterpret_cast(lr)); + } + } namespace ams::result::impl { diff --git a/libraries/Makefile b/libraries/Makefile deleted file mode 100644 index 55a46de01..000000000 --- a/libraries/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -ATMOSPHERE_LIBRARIES := libmesosphere libstratosphere libexosphere - -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/config/arch/arm64/arch.mk b/libraries/config/arch/arm64/arch.mk index 468ae233b..307f669f3 100644 --- a/libraries/config/arch/arm64/arch.mk +++ b/libraries/config/arch/arm64/arch.mk @@ -1,11 +1,23 @@ +ifeq ($(strip $(ATMOSPHERE_OS_NAME)),horizon) + ifeq ($(strip $(DEVKITPRO)),) $(error "Please set DEVKITPRO in your environment. export DEVKITPRO=/devkitpro") endif include $(DEVKITPRO)/devkitA64/base_rules +else + +include $(ATMOSPHERE_ARCH_MAKE_DIR)/base_rules + +endif + export ATMOSPHERE_DEFINES += -DATMOSPHERE_ARCH_ARM64 -export ATMOSPHERE_SETTINGS += -mtp=soft +export ATMOSPHERE_SETTINGS += export ATMOSPHERE_CFLAGS += export ATMOSPHERE_CXXFLAGS += export ATMOSPHERE_ASFLAGS += + +ifeq ($(strip $(ATMOSPHERE_OS_NAME)),horizon) +export ATMOSPHERE_SETTINGS += -mtp=soft +endif \ No newline at end of file diff --git a/libraries/config/arch/arm64/base_rules b/libraries/config/arch/arm64/base_rules new file mode 100644 index 000000000..f84585219 --- /dev/null +++ b/libraries/config/arch/arm64/base_rules @@ -0,0 +1,28 @@ +include $(ATMOSPHERE_ARCH_MAKE_DIR)/base_tools + +#--------------------------------------------------------------------------------- +%.a: +#--------------------------------------------------------------------------------- + $(SILENTMSG) $(notdir $@) + @rm -f $@ + $(SILENTCMD)$(AR) -rc $@ $^ + +#--------------------------------------------------------------------------------- +%.o: %.cpp + $(SILENTMSG) $(notdir $<) + $(SILENTCMD)$(CXX) -MMD -MP -MF $(DEPSDIR)/$*.d $(CXXFLAGS) -c $< -o $@ $(ERROR_FILTER) + +#--------------------------------------------------------------------------------- +%.o: %.c + $(SILENTMSG) $(notdir $<) + $(SILENTCMD)$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d $(CFLAGS) -c $< -o $@ $(ERROR_FILTER) + +#--------------------------------------------------------------------------------- +%.o: %.s + @echo $(notdir $<) + $(SILENTCMD)$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@ $(ERROR_FILTER) + +#--------------------------------------------------------------------------------- +%.o: %.S + $(SILENTMSG) $(notdir $<) + $(SILENTCMD)$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@ $(ERROR_FILTER) diff --git a/libraries/config/arch/arm64/base_tools b/libraries/config/arch/arm64/base_tools new file mode 100644 index 000000000..4cfd84c56 --- /dev/null +++ b/libraries/config/arch/arm64/base_tools @@ -0,0 +1,52 @@ +#--------------------------------------------------------------------------------- +# the prefix on the compiler executables +#--------------------------------------------------------------------------------- +PREFIX := + +ifeq ($(strip $(ATMOSPHERE_COMPILER_NAME)),gcc) + +export CC := gcc +export CXX := g++ +export AS := as +export AR := gcc-ar +export OBJCOPY := objcopy +export STRIP := strip +export NM := gcc-nm +export RANLIB := gcc-ranlib + +else ifeq ($(strip $(ATMOSPHERE_COMPILER_NAME)),clang) + +export CC := clang +export CXX := clang++ +export AS := llvm-as +export AR := llvm-ar +export OBJCOPY := llvm-objcopy +export STRIP := llvm-strip +export NM := llvm-nm +export RANLIB := llvm-ranlib + +endif + +ISVC=$(or $(VCBUILDHELPER_COMMAND),$(MSBUILDEXTENSIONSPATH32),$(MSBUILDEXTENSIONSPATH)) + +ifneq (,$(ISVC)) + ERROR_FILTER := 2>&1 | sed -e 's/\(.[a-zA-Z]\+\):\([0-9]\+\):/\1(\2):/g' +endif + +#--------------------------------------------------------------------------------- +# allow seeing compiler command lines with make V=1 (similar to autotools' silent) +#--------------------------------------------------------------------------------- +ifeq ($(V),1) + SILENTMSG := @true + SILENTCMD := +else + SILENTMSG := @echo + SILENTCMD := @ +endif + +#--------------------------------------------------------------------------------- +# canned command sequence for binary data +#--------------------------------------------------------------------------------- +define bin2o + bin2s -a 8 -H `(echo $(&1 | sed -e 's/\(.[a-zA-Z]\+\):\([0-9]\+\):/\1(\2):/g' +endif + +#--------------------------------------------------------------------------------- +# allow seeing compiler command lines with make V=1 (similar to autotools' silent) +#--------------------------------------------------------------------------------- +ifeq ($(V),1) + SILENTMSG := @true + SILENTCMD := +else + SILENTMSG := @echo + SILENTCMD := @ +endif + +#--------------------------------------------------------------------------------- +# canned command sequence for binary data +#--------------------------------------------------------------------------------- +define bin2o + bin2s -a 8 -H `(echo $(/devkitpro") -endif +define ATMOSPHERE_ADD_TARGET -include $(DEVKITPRO)/libnx/switch_rules +ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -#--------------------------------------------------------------------------------- -# options for code generation -#--------------------------------------------------------------------------------- -PRECOMPILED_HEADERS := $(CURRENT_DIRECTORY)/include/stratosphere.hpp -#PRECOMPILED_HEADERS := +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/libstratosphere.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_STRATOSPHERE -D_GNU_SOURCE -SETTINGS := $(ATMOSPHERE_SETTINGS) -O2 -Wextra -Werror -Wno-missing-field-initializers -flto -CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE) -CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) +clean-$(strip $1): + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/libstratosphere.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -LDFLAGS := -specs=$(DEVKITPRO)/libnx/switch.specs $(SETTINGS) -Wl,-Map,$(notdir $*.map) +endef -SOURCES += $(call ALL_SOURCE_DIRS,../libvapours/source) -SOURCES += $(call UNFILTERED_SOURCE_DIRS,source/os) +define ATMOSPHERE_ADD_TARGETS -LIBS := -lnx +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, $(strip $2)release, $(strip $3), $(strip $4), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $5)" $(strip $6) \ +)) -#--------------------------------------------------------------------------------- -# list of directories containing libraries, this must be the top level containing -# include and lib -#--------------------------------------------------------------------------------- -LIBDIRS := $(PORTLIBS) $(LIBNX) $(ATMOSPHERE_LIBRARIES_DIR)/libvapours +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, $(strip $2)debug, $(strip $3), $(strip $4), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $5) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 $(strip $6) \ +)) -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(BUILD),$(notdir $(CURDIR))) -#--------------------------------------------------------------------------------- +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, $(strip $2)audit, $(strip $3), $(strip $4), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $5) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 $(strip $6) \ +)) -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) +endef -CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) -CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) -SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, , nx-hac-001, arm-cortex-a57,,)) -#--------------------------------------------------------------------------------- -# use CXX for linking C++ projects, CC for standard C -#--------------------------------------------------------------------------------- -ifeq ($(strip $(CPPFILES)),) -#--------------------------------------------------------------------------------- - export LD := $(CC) -#--------------------------------------------------------------------------------- -else -#--------------------------------------------------------------------------------- - export LD := $(CXX) -#--------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------- +$(eval $(call ATMOSPHERE_ADD_TARGETS, win_x64, , generic_windows, generic_x64,,)) -export OFILES_BIN := $(addsuffix .o,$(BINFILES)) -export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) -export GCH_FILES := $(PRECOMPILED_HEADERS:.hpp=.hpp.gch) -export OFILES := $(OFILES_BIN) $(OFILES_SRC) -export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES))) +$(eval $(call ATMOSPHERE_ADD_TARGETS, linux_x64, , generic_linux, generic_x64,,)) +$(eval $(call ATMOSPHERE_ADD_TARGETS, linux_x64_clang, clang_, generic_linux, generic_x64,, ATMOSPHERE_COMPILER_NAME="clang")) +$(eval $(call ATMOSPHERE_ADD_TARGETS, linux_arm64_clang, clang_, generic_linux, generic_arm64,, ATMOSPHERE_COMPILER_NAME="clang")) -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I. +$(eval $(call ATMOSPHERE_ADD_TARGETS, macos_x64, , generic_macos, generic_x64,,)) +$(eval $(call ATMOSPHERE_ADD_TARGETS, macos_arm64, , generic_macos, generic_arm64,,)) -.PHONY: clean all lib/$(TARGET).a - -#--------------------------------------------------------------------------------- -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 $(GCH_FILES) - -#--------------------------------------------------------------------------------- -else - -DEPENDS := $(OFILES:.o=.d) $(foreach hdr,$(GCH_FILES:.hpp.gch=.d),$(notdir $(hdr))) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- -$(OUTPUT) : $(OFILES) - -$(OFILES) : $(GCH_FILES) - -$(OFILES_SRC) : $(HFILES_BIN) - -ams_environment_weak.o: CXXFLAGS += -fno-lto -hos_version_api_weak_for_unit_test.o: CXXFLAGS += -fno-lto -pm_info_api_weak.o: CXXFLAGS += -fno-lto -hos_stratosphere_api.o: CXXFLAGS += -fno-lto - -init_operator_new.o: CXXFLAGS += -fno-lto -init_libnx_shim.os.horizon.o: CXXFLAGS += -fno-lto - -#--------------------------------------------------------------------------------- -%_bin.h %.bin.o : %.bin -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) - - --include $(DEPENDS) - -#--------------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------------- +clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/libraries/libstratosphere/include/stratosphere.hpp b/libraries/libstratosphere/include/stratosphere.hpp index 3bd4ed1ee..332a3a757 100644 --- a/libraries/libstratosphere/include/stratosphere.hpp +++ b/libraries/libstratosphere/include/stratosphere.hpp @@ -16,9 +16,18 @@ #pragma once +/* Ensure that on windows we use lean-windows headers. */ +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif + /* libvapours (pulls in util, svc, results). */ #include +#if defined(ATMOSPHERE_OS_WINDOWS) +#include +#endif + /* Libstratosphere diagnostics. */ #include diff --git a/libraries/libstratosphere/include/stratosphere/ams/ams_environment.hpp b/libraries/libstratosphere/include/stratosphere/ams/ams_environment.hpp index 08c46a2ec..71a5f8860 100644 --- a/libraries/libstratosphere/include/stratosphere/ams/ams_environment.hpp +++ b/libraries/libstratosphere/include/stratosphere/ams/ams_environment.hpp @@ -20,7 +20,9 @@ namespace ams { /* Will be called by libstratosphere on crash. */ + #if defined(ATMOSPHERE_OS_HORIZON) void CrashHandler(ThreadExceptionDump *ctx); + #endif /* API for boot sysmodule. */ void InitializeForBoot(); diff --git a/libraries/libstratosphere/include/stratosphere/ams/ams_exosphere_api.hpp b/libraries/libstratosphere/include/stratosphere/ams/ams_exosphere_api.hpp index 2880b8b9a..84cdfe9a9 100644 --- a/libraries/libstratosphere/include/stratosphere/ams/ams_exosphere_api.hpp +++ b/libraries/libstratosphere/include/stratosphere/ams/ams_exosphere_api.hpp @@ -21,6 +21,7 @@ namespace ams::exosphere { ApiInfo GetApiInfo(); + #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) void ForceRebootToRcm(); void ForceRebootToIramPayload(); void ForceRebootToFatalError(); @@ -35,6 +36,7 @@ namespace ams::exosphere { 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); + #endif } diff --git a/libraries/libstratosphere/include/stratosphere/capsrv/capsrv_screen_shot_decode_option.hpp b/libraries/libstratosphere/include/stratosphere/capsrv/capsrv_screen_shot_decode_option.hpp index 1c252a19c..6102811c4 100644 --- a/libraries/libstratosphere/include/stratosphere/capsrv/capsrv_screen_shot_decode_option.hpp +++ b/libraries/libstratosphere/include/stratosphere/capsrv/capsrv_screen_shot_decode_option.hpp @@ -40,7 +40,10 @@ namespace ams::capsrv { } }; static_assert(sizeof(ScreenShotDecodeOption) == 0x20); - static_assert(sizeof(ScreenShotDecodeOption) == sizeof(::CapsScreenShotDecodeOption)); static_assert(util::is_pod::value); + #if defined(ATMOSPHERE_OS_HORIZON) + static_assert(sizeof(ScreenShotDecodeOption) == sizeof(::CapsScreenShotDecodeOption)); + #endif + } diff --git a/libraries/libstratosphere/include/stratosphere/cfg/cfg_types.hpp b/libraries/libstratosphere/include/stratosphere/cfg/cfg_types.hpp index 8c8ee368e..dd898a96f 100644 --- a/libraries/libstratosphere/include/stratosphere/cfg/cfg_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/cfg/cfg_types.hpp @@ -30,10 +30,12 @@ namespace ams::cfg { OverrideStatusFlag_AddressSpaceShift = 3, OverrideStatusFlag_AddressSpaceMask = ((1u << 2) - 1) << OverrideStatusFlag_AddressSpaceShift, + #if defined(ATMOSPHERE_OS_HORIZON) OverrideStatusFlag_AddressSpace32Bit = (svc::CreateProcessFlag_AddressSpace32Bit >> svc::CreateProcessFlag_AddressSpaceShift) << OverrideStatusFlag_AddressSpaceShift, OverrideStatusFlag_AddressSpace64BitDeprecated = (svc::CreateProcessFlag_AddressSpace64BitDeprecated >> svc::CreateProcessFlag_AddressSpaceShift) << OverrideStatusFlag_AddressSpaceShift, OverrideStatusFlag_AddressSpace32BitWithoutAlias = (svc::CreateProcessFlag_AddressSpace32BitWithoutAlias >> svc::CreateProcessFlag_AddressSpaceShift) << OverrideStatusFlag_AddressSpaceShift, OverrideStatusFlag_AddressSpace64Bit = (svc::CreateProcessFlag_AddressSpace64Bit >> svc::CreateProcessFlag_AddressSpaceShift) << OverrideStatusFlag_AddressSpaceShift, + #endif }; } @@ -63,7 +65,11 @@ namespace ams::cfg { static_assert(util::is_pod::value, "util::is_pod::value"); constexpr inline bool operator==(const OverrideStatus &lhs, const OverrideStatus &rhs) { - return std::memcmp(std::addressof(lhs), std::addressof(rhs), sizeof(lhs)) == 0; + if (std::is_constant_evaluated()) { + return lhs.keys_held == rhs.keys_held && lhs.flags == rhs.flags; + } else { + return std::memcmp(std::addressof(lhs), std::addressof(rhs), sizeof(lhs)) == 0; + } } constexpr inline bool operator!=(const OverrideStatus &lhs, const OverrideStatus &rhs) { diff --git a/libraries/libstratosphere/include/stratosphere/dd/dd_device_address_space_common.hpp b/libraries/libstratosphere/include/stratosphere/dd/dd_device_address_space_common.hpp index 6b3226715..69332a811 100644 --- a/libraries/libstratosphere/include/stratosphere/dd/dd_device_address_space_common.hpp +++ b/libraries/libstratosphere/include/stratosphere/dd/dd_device_address_space_common.hpp @@ -19,8 +19,12 @@ namespace ams::dd { + #if defined(ATMOSPHERE_OS_HORIZON) using DeviceName = ::ams::svc::DeviceName; using enum ::ams::svc::DeviceName; + #else + enum DeviceName { }; + #endif constexpr inline u64 DeviceAddressSpaceMemoryRegionAlignment = 4_KB; diff --git a/libraries/libstratosphere/include/stratosphere/ddsf/ddsf_i_device.hpp b/libraries/libstratosphere/include/stratosphere/ddsf/ddsf_i_device.hpp index 0bd8d7b2d..62812b07b 100644 --- a/libraries/libstratosphere/include/stratosphere/ddsf/ddsf_i_device.hpp +++ b/libraries/libstratosphere/include/stratosphere/ddsf/ddsf_i_device.hpp @@ -81,7 +81,7 @@ namespace ams::ddsf { m_session_list.clear(); } protected: - ~IDevice() { + virtual ~IDevice() { m_session_list.clear(); } public: diff --git a/libraries/libstratosphere/include/stratosphere/ddsf/ddsf_i_driver.hpp b/libraries/libstratosphere/include/stratosphere/ddsf/ddsf_i_driver.hpp index ace3266a4..3532504d8 100644 --- a/libraries/libstratosphere/include/stratosphere/ddsf/ddsf_i_driver.hpp +++ b/libraries/libstratosphere/include/stratosphere/ddsf/ddsf_i_driver.hpp @@ -40,7 +40,7 @@ namespace ams::ddsf { m_device_list.clear(); } protected: - ~IDriver() { + virtual ~IDriver() { m_device_list.clear(); } public: diff --git a/libraries/libstratosphere/include/stratosphere/ddsf/ddsf_i_event_handler.hpp b/libraries/libstratosphere/include/stratosphere/ddsf/ddsf_i_event_handler.hpp index f3be5e105..e9d9634af 100644 --- a/libraries/libstratosphere/include/stratosphere/ddsf/ddsf_i_event_handler.hpp +++ b/libraries/libstratosphere/include/stratosphere/ddsf/ddsf_i_event_handler.hpp @@ -53,7 +53,7 @@ namespace ams::ddsf { public: IEventHandler() : m_holder(), m_user_data(0), m_is_initialized(false), m_is_registered(false) { /* ... */ } - ~IEventHandler() { + virtual ~IEventHandler() { if (this->IsRegistered()) { this->Unlink(); } diff --git a/libraries/libstratosphere/include/stratosphere/ddsf/ddsf_i_session.hpp b/libraries/libstratosphere/include/stratosphere/ddsf/ddsf_i_session.hpp index b5ade44c1..146b17dd5 100644 --- a/libraries/libstratosphere/include/stratosphere/ddsf/ddsf_i_session.hpp +++ b/libraries/libstratosphere/include/stratosphere/ddsf/ddsf_i_session.hpp @@ -58,7 +58,7 @@ namespace ams::ddsf { public: ISession() : m_list_node(), m_device(nullptr), m_access_mode() { /* ... */ } protected: - ~ISession() { this->DetachDevice(); AMS_ASSERT(!this->IsOpen()); } + virtual ~ISession() { this->DetachDevice(); AMS_ASSERT(!this->IsOpen()); } public: void AddTo(List &list) { list.push_back(*this); diff --git a/libraries/libstratosphere/include/stratosphere/ddsf/impl/ddsf_type_tag.hpp b/libraries/libstratosphere/include/stratosphere/ddsf/impl/ddsf_type_tag.hpp index bd1ede04a..b521f3852 100644 --- a/libraries/libstratosphere/include/stratosphere/ddsf/impl/ddsf_type_tag.hpp +++ b/libraries/libstratosphere/include/stratosphere/ddsf/impl/ddsf_type_tag.hpp @@ -42,13 +42,13 @@ namespace ams::ddsf::impl { public: #if !(defined(AMS_BUILD_FOR_DEBUGGING) || defined(AMS_BUILD_FOR_AUDITING)) constexpr TypeTag() : m_class_name(nullptr), m_base(nullptr) { /* ... */} - constexpr TypeTag(const TypeTag &b) : m_class_name(nullptr), m_base(std::addressof(b)) { AMS_ASSERT(this != m_base); } + constexpr TypeTag(const TypeTag &b) : m_class_name(nullptr), m_base(std::addressof(b)) { if (!std::is_constant_evaluated()) { AMS_ASSERT(this != m_base); } } constexpr TypeTag(const char *c) : m_class_name(nullptr), m_base(nullptr) { AMS_UNUSED(c); } - constexpr TypeTag(const char *c, const TypeTag &b) : m_class_name(nullptr), m_base(std::addressof(b)) { AMS_UNUSED(c); AMS_ASSERT(this != m_base); } + constexpr TypeTag(const char *c, const TypeTag &b) : m_class_name(nullptr), m_base(std::addressof(b)) { if (!std::is_constant_evaluated()) { AMS_UNUSED(c); AMS_ASSERT(this != m_base); } } #else constexpr TypeTag(const char *c) : m_class_name(c), m_base(nullptr) { /* ... */ } - constexpr TypeTag(const char *c, const TypeTag &b) : m_class_name(c), m_base(std::addressof(b)) { AMS_ASSERT(this != m_base); } + constexpr TypeTag(const char *c, const TypeTag &b) : m_class_name(c), m_base(std::addressof(b)) { if (!std::is_constant_evaluated()) { AMS_ASSERT(this != m_base); } } #endif constexpr const char * GetClassName() const { return m_class_name; } diff --git a/libraries/libstratosphere/include/stratosphere/fatal/fatal_types.hpp b/libraries/libstratosphere/include/stratosphere/fatal/fatal_types.hpp index 6d5f0d580..67d464cab 100644 --- a/libraries/libstratosphere/include/stratosphere/fatal/fatal_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/fatal/fatal_types.hpp @@ -21,6 +21,13 @@ namespace ams::fatal { + enum FatalPolicy { + FatalPolicy_ErrorReportAndErrorScreen = 0, + FatalPolicy_ErrorReport = 1, + FatalPolicy_ErrorScreen = 2 + }; + + #if defined(ATMOSPHERE_ARCH_ARM64) namespace aarch64 { enum RegisterName { @@ -150,7 +157,7 @@ namespace ams::fatal { 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); + this->afsr0 = static_cast(program_id.value); } ncm::ProgramId GetProgramIdForAtmosphere() const { @@ -172,7 +179,9 @@ namespace ams::fatal { }; } + #endif + #if defined(ATMOSPHERE_ARCH_ARM64) || defined(ATMOSPHERE_ARCH_ARM) namespace aarch32 { enum RegisterName { @@ -268,8 +277,8 @@ namespace ams::fatal { 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); + this->afsr0 = static_cast(static_cast(program_id.value) >> 0); + this->afsr1 = static_cast(static_cast(program_id.value) >> 32); } ncm::ProgramId GetProgramIdForAtmosphere() const { @@ -291,16 +300,158 @@ namespace ams::fatal { }; } + #endif + + #if defined(ATMOSPHERE_ARCH_X64) + namespace x64 { + + enum RegisterName { + /* TODO */ + RegisterName_Count, + }; + + struct CpuContext { + using RegisterType = u64; + static constexpr size_t MaxStackTraceDepth = 0x20; + + static constexpr const char *RegisterNameStrings[RegisterName_Count] = { + /* TODO */ + }; + + /* Registers, exception context. N left names for these fields in fatal .rodata. */ + union { + // struct { + // /* TODO */ + // }; + 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) { + AMS_UNUSED(program_id); + AMS_ABORT("TODO"); + } + + ncm::ProgramId GetProgramIdForAtmosphere() const { + AMS_ABORT("TODO"); + } + + 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; + } + }; + + } + #endif + + #if defined(ATMOSPHERE_ARCH_X64) || defined(ATMOSPHERE_ARCH_X86) + namespace x86 { + + enum RegisterName { + /* TODO */ + RegisterName_Count, + }; + + struct CpuContext { + using RegisterType = u32; + static constexpr size_t MaxStackTraceDepth = 0x20; + + static constexpr const char *RegisterNameStrings[RegisterName_Count] = { + /* TODO */ + }; + + /* Registers, exception context. N left names for these fields in fatal .rodata. */ + union { + // struct { + // /* TODO */ + // }; + 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) { + AMS_UNUSED(program_id); + AMS_ABORT("TODO"); + } + + ncm::ProgramId GetProgramIdForAtmosphere() const { + AMS_ABORT("TODO"); + } + + 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; + } + }; + + } + #endif struct CpuContext : sf::LargeData, sf::PrefersMapAliasTransferMode { enum Architecture { - Architecture_Aarch64 = 0, - Architecture_Aarch32 = 1, + #if defined(ATMOSPHERE_ARCH_ARM64) + Architecture_Aarch64, + #endif + #if defined(ATMOSPHERE_ARCH_ARM64) || defined(ATMOSPHERE_ARCH_ARM) + Architecture_Aarch32, + #endif + #if defined(ATMOSPHERE_X64) + Architecture_X64, + #endif + #if defined(ATMOSPHERE_X64) || defined(ATMOSPHERE_ARCH_X86) + Architecture_X86, + #endif }; union { + #if defined(ATMOSPHERE_ARCH_ARM64) aarch64::CpuContext aarch64_ctx; + #endif + #if defined(ATMOSPHERE_ARCH_ARM64) || defined(ATMOSPHERE_ARCH_ARM) aarch32::CpuContext aarch32_ctx; + #endif + #if defined(ATMOSPHERE_X64) + aarch64::CpuContext x64_ctx; + #endif + #if defined(ATMOSPHERE_X64) || defined(ATMOSPHERE_ARCH_X86) + aarch64::CpuContext x86_ctx; + #endif + u8 raw_storage[0x248]; }; Architecture architecture; @@ -311,8 +462,12 @@ namespace ams::fatal { } }; + #if defined(ATMOSPHERE_ARCH_ARM64) static_assert(util::is_pod::value && sizeof(aarch64::CpuContext) == 0x248, "aarch64::CpuContext definition!"); + #endif + #if defined(ATMOSPHERE_ARCH_ARM64) || defined(ATMOSPHERE_ARCH_ARM) static_assert(util::is_pod::value && sizeof(aarch32::CpuContext) == 0xE0, "aarch32::CpuContext definition!"); + #endif static_assert(util::is_pod::value && sizeof(CpuContext) == 0x250, "CpuContext definition!"); namespace srv { diff --git a/libraries/libstratosphere/include/stratosphere/fatal/impl/fatal_i_service.hpp b/libraries/libstratosphere/include/stratosphere/fatal/impl/fatal_i_service.hpp index 03a5895cb..c8406fe28 100644 --- a/libraries/libstratosphere/include/stratosphere/fatal/impl/fatal_i_service.hpp +++ b/libraries/libstratosphere/include/stratosphere/fatal/impl/fatal_i_service.hpp @@ -20,8 +20,8 @@ #include #define AMS_FATAL_I_SERVICE_INTERFACE_INFO(C, H) \ - AMS_SF_METHOD_INFO(C, H, 0, Result, ThrowFatal, (Result error, const sf::ClientProcessId &client_pid), (error, client_pid)) \ - AMS_SF_METHOD_INFO(C, H, 1, Result, ThrowFatalWithPolicy, (Result error, const sf::ClientProcessId &client_pid, FatalPolicy policy), (error, client_pid, policy)) \ - AMS_SF_METHOD_INFO(C, H, 2, Result, ThrowFatalWithCpuContext, (Result error, const sf::ClientProcessId &client_pid, FatalPolicy policy, const fatal::CpuContext &cpu_ctx), (error, client_pid, policy, cpu_ctx)) + AMS_SF_METHOD_INFO(C, H, 0, Result, ThrowFatal, (Result error, const sf::ClientProcessId &client_pid), (error, client_pid)) \ + AMS_SF_METHOD_INFO(C, H, 1, Result, ThrowFatalWithPolicy, (Result error, const sf::ClientProcessId &client_pid, fatal::FatalPolicy policy), (error, client_pid, policy)) \ + AMS_SF_METHOD_INFO(C, H, 2, Result, ThrowFatalWithCpuContext, (Result error, const sf::ClientProcessId &client_pid, fatal::FatalPolicy policy, const fatal::CpuContext &cpu_ctx), (error, client_pid, policy, cpu_ctx)) AMS_SF_DEFINE_INTERFACE(ams::fatal::impl, IService, AMS_FATAL_I_SERVICE_INTERFACE_INFO) diff --git a/libraries/libstratosphere/include/stratosphere/fs.hpp b/libraries/libstratosphere/include/stratosphere/fs.hpp index 231180ac4..a250fe332 100644 --- a/libraries/libstratosphere/include/stratosphere/fs.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs.hpp @@ -41,7 +41,9 @@ #include #include #include -#include +#include +#include +#include #include #include #include @@ -50,8 +52,9 @@ #include #include #include -#include #include +#include +#include #include #include #include diff --git a/libraries/libstratosphere/include/stratosphere/fs/common/fs_directory_path_parser.hpp b/libraries/libstratosphere/include/stratosphere/fs/common/fs_directory_path_parser.hpp new file mode 100644 index 000000000..0f7cdd7d5 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fs/common/fs_directory_path_parser.hpp @@ -0,0 +1,124 @@ +/* + * Copyright (c) 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 + +namespace ams::fs { + + class DirectoryPathParser { + NON_COPYABLE(DirectoryPathParser); + NON_MOVEABLE(DirectoryPathParser); + private: + char *m_buffer; + char m_replaced_char; + s32 m_position; + fs::Path m_current_path; + public: + DirectoryPathParser() : m_buffer(nullptr), m_replaced_char(StringTraits::NullTerminator), m_position(0), m_current_path() { /* ... */ } + + const fs::Path &GetCurrentPath() const { + return m_current_path; + } + + Result Initialize(fs::Path *path) { + /* Declare a default buffer, in case the path has no write buffer. */ + static constinit char EmptyBuffer[1] = ""; + + /* Get a usable buffer. */ + char *buf = path->GetWriteBufferLength() > 0 ? path->GetWriteBuffer() : EmptyBuffer; + + /* Get the windows skip length. */ + const auto windows_skip_len = fs::GetWindowsSkipLength(buf); + + /* Set our buffer. */ + m_buffer = buf + windows_skip_len; + + /* Set up our initial state. */ + if (windows_skip_len) { + R_TRY(m_current_path.InitializeWithNormalization(buf, windows_skip_len + 1)); + } else { + if (char * const first = this->ReadNextImpl(); first != nullptr) { + R_TRY(m_current_path.InitializeWithNormalization(first)); + } + } + + R_SUCCEED(); + } + + Result ReadNext(bool *out_finished) { + /* Default to not finished. */ + *out_finished = false; + + /* Get the next child component. */ + if (auto * const child = this->ReadNextImpl(); child != nullptr) { + /* Append the child component to our current path. */ + R_TRY(m_current_path.AppendChild(child)); + } else { + /* We have no child component, so we're finished. */ + *out_finished = true; + } + + R_SUCCEED(); + } + private: + char *ReadNextImpl() { + /* Check that we have characters to read. */ + if (m_position < 0 || m_buffer[0] == StringTraits::NullTerminator) { + return nullptr; + } + + /* If we have a replaced character, restore it. */ + if (m_replaced_char != StringTraits::NullTerminator) { + m_buffer[m_position] = m_replaced_char; + if (m_replaced_char == StringTraits::DirectorySeparator) { + ++m_position; + } + } + + /* If we're at the start of a root-relative path, begin by returning the root. */ + if (m_position == 0 && m_buffer[0] == StringTraits::DirectorySeparator) { + m_replaced_char = m_buffer[1]; + m_buffer[1] = StringTraits::NullTerminator; + m_position = 1; + return m_buffer; + } + + /* Otherwise, find the end of the next path component. */ + s32 i; + for (i = m_position; m_buffer[i] != StringTraits::DirectorySeparator; ++i) { + if (m_buffer[i] == StringTraits::NullTerminator) { + if (i == m_position) { + m_position = -1; + return nullptr; + } + } + } + + /* Sanity check that we're not ending on a separator. */ + AMS_ASSERT(m_buffer[i + 1] != StringTraits::NullTerminator); + + char * const ret = m_buffer + m_position; + + m_replaced_char = StringTraits::DirectorySeparator; + m_buffer[i] = 0; + m_position = i; + + return ret; + } + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/fs/common/fs_file_storage.hpp b/libraries/libstratosphere/include/stratosphere/fs/common/fs_file_storage.hpp index 4d470db4f..c38fe1fd4 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/common/fs_file_storage.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/common/fs_file_storage.hpp @@ -82,7 +82,7 @@ namespace ams::fs { public: constexpr FileStorageBasedFileSystem() : FileStorage(), m_base_file_system(nullptr) { /* ... */ } - Result Initialize(std::shared_ptr base_file_system, const char *path, fs::OpenMode mode); + Result Initialize(std::shared_ptr base_file_system, const fs::Path &path, fs::OpenMode mode); }; class FileHandleStorage : public IStorage, public impl::Newable { diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_directory.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_directory.hpp index bc93f4eea..9f7ccd2a2 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_directory.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_directory.hpp @@ -20,7 +20,13 @@ namespace ams::fs { constexpr inline size_t EntryNameLengthMax = 0x300; - using DirectoryEntry = ::FsDirectoryEntry; + struct DirectoryEntry { + char name[EntryNameLengthMax + 1]; + char pad[3]; + s8 type; + u8 pad2[3]; + s64 file_size; + }; struct DirectoryHandle { void *handle; diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_file.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_file.hpp index 898aeb7e2..6cd229027 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_file.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_file.hpp @@ -24,7 +24,11 @@ namespace ams::fs { static const ReadOption None; }; - inline constexpr const ReadOption ReadOption::None = {FsReadOption_None}; + enum ReadOptionFlag : u32 { + ReadOptionFlag_None = (0 << 0), + }; + + inline constexpr const ReadOption ReadOption::None = {ReadOptionFlag_None}; inline constexpr bool operator==(const ReadOption &lhs, const ReadOption &rhs) { return lhs._value == rhs._value; @@ -36,19 +40,24 @@ namespace ams::fs { static_assert(util::is_pod::value && sizeof(ReadOption) == sizeof(u32)); + enum WriteOptionFlag : u32 { + WriteOptionFlag_None = (0 << 0), + WriteOptionFlag_Flush = (1 << 0), + }; + struct WriteOption { u32 _value; constexpr inline bool HasFlushFlag() const { - return _value & FsWriteOption_Flush; + return _value & WriteOptionFlag_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 const WriteOption WriteOption::None = {WriteOptionFlag_None}; + inline constexpr const WriteOption WriteOption::Flush = {WriteOptionFlag_Flush}; inline constexpr bool operator==(const WriteOption &lhs, const WriteOption &rhs) { return lhs._value == rhs._value; diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_filesystem.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_filesystem.hpp index a56608fe6..86e384214 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_filesystem.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_filesystem.hpp @@ -25,8 +25,8 @@ namespace ams::fs { } enum OpenMode { - OpenMode_Read = (1 << 0), - OpenMode_Write = (1 << 1), + OpenMode_Read = (1 << 0), + OpenMode_Write = (1 << 1), OpenMode_AllowAppend = (1 << 2), OpenMode_ReadWrite = (OpenMode_Read | OpenMode_Write), @@ -34,23 +34,23 @@ namespace ams::fs { }; enum OpenDirectoryMode { - OpenDirectoryMode_Directory = ::FsDirOpenMode_ReadDirs, - OpenDirectoryMode_File = ::FsDirOpenMode_ReadFiles, + OpenDirectoryMode_Directory = (1 << 0), + OpenDirectoryMode_File = (1 << 1), OpenDirectoryMode_All = (OpenDirectoryMode_Directory | OpenDirectoryMode_File), /* TODO: Separate enum, like N? */ - OpenDirectoryMode_NotRequireFileSize = ::FsDirOpenMode_NoFileSize, + OpenDirectoryMode_NotRequireFileSize = (1 << 31), }; enum DirectoryEntryType { - DirectoryEntryType_Directory = ::FsDirEntryType_Dir, - DirectoryEntryType_File = ::FsDirEntryType_File, + DirectoryEntryType_Directory = 0, + DirectoryEntryType_File = 1, }; enum CreateOption { - CreateOption_None = 0, - CreateOption_BigFile = ::FsCreateOption_BigFile, + CreateOption_None = (0 << 0), + CreateOption_BigFile = (1 << 0), }; struct FileHandle; diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_filesystem_for_debug.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_filesystem_for_debug.hpp index 9bd34b407..9431814c5 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_filesystem_for_debug.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_filesystem_for_debug.hpp @@ -16,10 +16,37 @@ #pragma once #include #include +#include namespace ams::fs { - using FileTimeStampRaw = ::FsTimeStampRaw; + struct FileTimeStamp { + time::PosixTime create; + time::PosixTime modify; + time::PosixTime access; + bool is_local_time; + char pad[7]; + }; + static_assert(util::is_pod::value && sizeof(FileTimeStamp) == 0x20); + + struct FileTimeStampRaw { + s64 create; + s64 modify; + s64 access; + bool is_local_time; + char pad[7]; + }; + static_assert(util::is_pod::value && sizeof(FileTimeStampRaw) == 0x20); + + static_assert(__builtin_offsetof(FileTimeStampRaw, create) == __builtin_offsetof(FileTimeStampRaw, create)); + static_assert(__builtin_offsetof(FileTimeStampRaw, modify) == __builtin_offsetof(FileTimeStampRaw, modify)); + static_assert(__builtin_offsetof(FileTimeStampRaw, access) == __builtin_offsetof(FileTimeStampRaw, access)); + static_assert(__builtin_offsetof(FileTimeStampRaw, is_local_time) == __builtin_offsetof(FileTimeStampRaw, is_local_time)); + static_assert(__builtin_offsetof(FileTimeStampRaw, pad) == __builtin_offsetof(FileTimeStampRaw, pad)); + + #if defined(ATMOSPHERE_OS_HORIZON) + static_assert(sizeof(FileTimeStampRaw) == sizeof(::FsTimeStampRaw)); + #endif namespace impl { @@ -27,6 +54,6 @@ namespace ams::fs { } - Result GetFileTimeStampRawForDebug(FileTimeStampRaw *out, const char *path); + Result GetFileTimeStamp(FileTimeStamp *out, const char *path); } diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_filesystem_utils.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_filesystem_utils.hpp index 321ed05d4..860d9c996 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_filesystem_utils.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_filesystem_utils.hpp @@ -21,8 +21,8 @@ namespace ams::fs { /* Common utilities. */ - Result EnsureDirectoryRecursively(const char *path); - Result EnsureParentDirectoryRecursively(const char *path); + Result EnsureDirectory(const char *path); + Result EnsureParentDirectory(const char *path); Result HasFile(bool *out, const char *path); Result HasDirectory(bool *out, const char *path); diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_host.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_host.hpp new file mode 100644 index 000000000..07673afc0 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_host.hpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) 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 +#include + +namespace ams::fs { + + enum MountHostOptionFlag : u32 { + MountHostOptionFlag_None = (0 << 0), + MountHostOptionFlag_PseudoCaseSensitive = (1 << 0), + }; + + struct MountHostOption { + u32 _value; + + constexpr inline bool HasPseudoCaseSensitiveFlag() const { + return _value & MountHostOptionFlag_PseudoCaseSensitive; + } + + static const MountHostOption None; + static const MountHostOption PseudoCaseSensitive; + }; + + inline constexpr const MountHostOption MountHostOption::None = {MountHostOptionFlag_None}; + inline constexpr const MountHostOption MountHostOption::PseudoCaseSensitive = {MountHostOptionFlag_PseudoCaseSensitive}; + + inline constexpr bool operator==(const MountHostOption &lhs, const MountHostOption &rhs) { + return lhs._value == rhs._value; + } + + inline constexpr bool operator!=(const MountHostOption &lhs, const MountHostOption &rhs) { + return !(lhs == rhs); + } + + Result MountHost(const char *name, const char *root_path); + Result MountHost(const char *name, const char *root_path, const MountHostOption &option); + + Result MountHostRoot(); + Result MountHostRoot(const MountHostOption &option); + + void UnmountHostRoot(); + +} diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_istorage.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_istorage.hpp index 139bf552d..aaf3534d6 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_istorage.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_istorage.hpp @@ -68,13 +68,13 @@ namespace ams::fs { std::unique_ptr m_unique_storage; IStorage *m_storage; public: - ReadOnlyStorageAdapter(IStorage *s) : m_unique_storage(s) { + explicit ReadOnlyStorageAdapter(IStorage *s) : m_unique_storage(s) { m_storage = m_unique_storage.get(); } - ReadOnlyStorageAdapter(std::shared_ptr s) : m_shared_storage(s) { + explicit ReadOnlyStorageAdapter(std::shared_ptr s) : m_shared_storage(s) { m_storage = m_shared_storage.get(); } - ReadOnlyStorageAdapter(std::unique_ptr s) : m_unique_storage(std::move(s)) { + explicit ReadOnlyStorageAdapter(std::unique_ptr s) : m_unique_storage(std::move(s)) { m_storage = m_unique_storage.get(); } diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_path.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_path.hpp new file mode 100644 index 000000000..a3f5a85b5 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_path.hpp @@ -0,0 +1,582 @@ +/* + * Copyright (c) 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 +#include +#include + +namespace ams::fs { + + class DirectoryPathParser; + + class Path { + NON_COPYABLE(Path); + NON_MOVEABLE(Path); + private: + static constexpr const char *EmptyPath = ""; + static constexpr size_t WriteBufferAlignmentLength = 8; + private: + friend class DirectoryPathParser; + private: + using WriteBuffer = std::unique_ptr; + private: + const char *m_str; + util::TypedStorage m_write_buffer; + size_t m_write_buffer_length; + bool m_is_normalized; + public: + Path() : m_str(EmptyPath), m_write_buffer_length(0), m_is_normalized(false) { + util::ConstructAt(m_write_buffer, nullptr); + } + + constexpr Path(const char *s, util::ConstantInitializeTag) : m_str(s), m_write_buffer(), m_write_buffer_length(0), m_is_normalized(true) { + /* ... */ + } + + constexpr ~Path() { + if (!std::is_constant_evaluated()) { + util::DestroyAt(m_write_buffer); + } + } + + WriteBuffer ReleaseBuffer() { + /* Check pre-conditions. */ + AMS_ASSERT(util::GetReference(m_write_buffer) != nullptr); + + /* Reset. */ + m_str = EmptyPath; + m_write_buffer_length = 0; + + /* Return our write buffer. */ + return std::move(util::GetReference(m_write_buffer)); + } + + constexpr Result SetShallowBuffer(const char *buffer) { + /* Check pre-conditions. */ + AMS_ASSERT(m_write_buffer_length == 0); + + /* Check the buffer is valid. */ + R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); + + /* Set buffer. */ + this->SetReadOnlyBuffer(buffer); + + /* Note that we're normalized. */ + m_is_normalized = true; + + R_SUCCEED(); + } + + const char *GetString() const { + /* Check pre-conditions. */ + AMS_ASSERT(m_is_normalized); + + return m_str; + } + + size_t GetLength() const { + return std::strlen(this->GetString()); + } + + bool IsEmpty() const { + return *m_str == '\x00'; + } + + bool IsMatchHead(const char *p, size_t len) const { + return util::Strncmp(this->GetString(), p, len) == 0; + } + + Result Initialize(const Path &rhs) { + /* Check the other path is normalized. */ + R_UNLESS(rhs.m_is_normalized, fs::ResultNotNormalized()); + + /* Allocate buffer for our path. */ + const auto len = rhs.GetLength(); + R_TRY(this->Preallocate(len + 1)); + + /* Copy the path. */ + const size_t copied = util::Strlcpy(util::GetReference(m_write_buffer).get(), rhs.GetString(), len + 1); + R_UNLESS(copied == len, fs::ResultUnexpectedInPathA()); + + /* Set normalized. */ + m_is_normalized = rhs.m_is_normalized; + R_SUCCEED(); + } + + Result Initialize(const char *path, size_t len) { + /* Check the path is valid. */ + R_UNLESS(path != nullptr, fs::ResultNullptrArgument()); + + /* Initialize. */ + R_TRY(this->InitializeImpl(path, len)); + + /* Set not normalized. */ + m_is_normalized = false; + + R_SUCCEED(); + } + + Result Initialize(const char *path) { + /* Check the path is valid. */ + R_UNLESS(path != nullptr, fs::ResultNullptrArgument()); + + return this->Initialize(path, std::strlen(path)); + } + + Result InitializeWithFormat(const char *fmt, ...) __attribute__((format (printf, 2, 3))) { + /* Check the format string is valid. */ + R_UNLESS(fmt != nullptr, fs::ResultNullptrArgument()); + + /* Create the va_list for formatting. */ + std::va_list vl; + va_start(vl, fmt); + + /* Determine how big the string will be. */ + char dummy; + const auto len = util::VSNPrintf(std::addressof(dummy), 0, fmt, vl); + + /* Allocate buffer for our path. */ + R_TRY(this->Preallocate(len + 1)); + + /* Format our path into our new buffer. */ + const auto real_len = util::VSNPrintf(util::GetReference(m_write_buffer).get(), m_write_buffer_length, fmt, vl); + AMS_ASSERT(real_len == len); + AMS_UNUSED(real_len); + + /* Finish the va_list. */ + va_end(vl); + + /* Set not normalized. */ + m_is_normalized = false; + + R_SUCCEED(); + } + + Result InitializeWithReplaceBackslash(const char *path) { + /* Check the path is valid. */ + R_UNLESS(path != nullptr, fs::ResultNullptrArgument()); + + /* Initialize. */ + R_TRY(this->InitializeImpl(path, std::strlen(path))); + + /* Replace slashes as desired. */ + if (m_write_buffer_length > 1) { + fs::Replace(this->GetWriteBuffer(), m_write_buffer_length - 1, '\\', '/'); + } + + /* Set not normalized. */ + m_is_normalized = false; + + R_SUCCEED(); + } + + Result InitializeWithReplaceForwardSlashes(const char *path) { + /* Check the path is valid. */ + R_UNLESS(path != nullptr, fs::ResultNullptrArgument()); + + /* Initialize. */ + R_TRY(this->InitializeImpl(path, std::strlen(path))); + + /* Replace slashes as desired. */ + if (m_write_buffer_length > 1) { + if (auto *p = this->GetWriteBuffer(); p[0] == '/' && p[1] == '/') { + p[0] = '\\'; + p[1] = '\\'; + } + } + + /* Set not normalized. */ + m_is_normalized = false; + + R_SUCCEED(); + } + + Result InitializeWithReplaceUnc(const char *path) { + /* Check the path is valid. */ + R_UNLESS(path != nullptr, fs::ResultNullptrArgument()); + + /* Initialize. */ + R_TRY(this->InitializeImpl(path, std::strlen(path))); + + /* Set not normalized. */ + m_is_normalized = false; + + /* Replace unc as desired. */ + if (m_str[0]) { + auto *p = this->GetWriteBuffer(); + + /* Replace :/// -> \\ as needed. */ + if (auto *sep = std::strstr(p, ":///"); sep != nullptr) { + sep[0] = '\\'; + sep[1] = '\\'; + } + + /* Edit path prefix. */ + if (!util::Strncmp(p, AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME AMS_FS_IMPL_MOUNT_NAME_DELIMITER "/", AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME_LEN + AMS_FS_IMPL_MOUNT_NAME_DELIMITER_LEN + 1)) { + static_assert((AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME AMS_FS_IMPL_MOUNT_NAME_DELIMITER)[AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME_LEN + AMS_FS_IMPL_MOUNT_NAME_DELIMITER_LEN - 1] == '/'); + + p[AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME_LEN + AMS_FS_IMPL_MOUNT_NAME_DELIMITER_LEN - 1] = '\\'; + p[AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME_LEN + AMS_FS_IMPL_MOUNT_NAME_DELIMITER_LEN - 0] = '\\'; + } + + if (p[0] == '/' && p[1] == '/') { + p[0] = '\\'; + p[1] = '\\'; + } + } + + R_SUCCEED(); + } + + Result InitializeWithNormalization(const char *path, size_t size) { + /* Check the path is valid. */ + R_UNLESS(path != nullptr, fs::ResultNullptrArgument()); + + /* Initialize. */ + R_TRY(this->InitializeImpl(path, size)); + + /* Set not normalized. */ + m_is_normalized = false; + + /* Perform normalization. */ + fs::PathFlags path_flags; + if (fs::IsPathRelative(m_str)) { + path_flags.AllowRelativePath(); + } else if (fs::IsWindowsPath(m_str, true)) { + path_flags.AllowWindowsPath(); + } else { + /* NOTE: In this case, Nintendo checks is normalized, then sets is normalized, then returns success. */ + /* This seems like a bug. */ + size_t dummy; + R_TRY(PathFormatter::IsNormalized(std::addressof(m_is_normalized), std::addressof(dummy), m_str)); + + m_is_normalized = true; + R_SUCCEED(); + } + + /* Normalize. */ + R_TRY(this->Normalize(path_flags)); + + m_is_normalized = true; + R_SUCCEED(); + } + + Result InitializeWithNormalization(const char *path) { + /* Check the path is valid. */ + R_UNLESS(path != nullptr, fs::ResultNullptrArgument()); + + R_RETURN(this->InitializeWithNormalization(path, std::strlen(path))); + } + + Result InitializeAsEmpty() { + /* Clear our buffer. */ + this->ClearBuffer(); + + /* Set normalized. */ + m_is_normalized = true; + + R_SUCCEED(); + } + + Result AppendChild(const char *child) { + /* Check the path is valid. */ + R_UNLESS(child != nullptr, fs::ResultNullptrArgument()); + + /* Basic checks. If we hvea a path and the child is empty, we have nothing to do. */ + const char *c = child; + if (m_str[0]) { + /* Skip an early separator. */ + if (*c == '/') { + ++c; + } + + R_SUCCEED_IF(*c == '\x00'); + } + + /* If we don't have a string, we can just initialize. */ + auto cur_len = std::strlen(m_str); + if (cur_len == 0) { + R_RETURN(this->Initialize(child)); + } + + /* Remove a trailing separator. */ + if (m_str[cur_len - 1] == '/' || m_str[cur_len - 1] == '\\') { + --cur_len; + } + + /* Get the child path's length. */ + auto child_len = std::strlen(c); + + /* Reset our write buffer. */ + WriteBuffer old_write_buffer; + if (util::GetReference(m_write_buffer) != nullptr) { + old_write_buffer = std::move(util::GetReference(m_write_buffer)); + this->ClearBuffer(); + } + + /* Pre-allocate the new buffer. */ + R_TRY(this->Preallocate(cur_len + 1 + child_len + 1)); + + /* Get our write buffer. */ + auto *dst = this->GetWriteBuffer(); + if (old_write_buffer != nullptr && cur_len > 0) { + util::Strlcpy(dst, old_write_buffer.get(), cur_len + 1); + } + + /* Add separator. */ + dst[cur_len] = '/'; + + /* Copy the child path. */ + const size_t copied = util::Strlcpy(dst + cur_len + 1, c, child_len + 1); + R_UNLESS(copied == child_len, fs::ResultUnexpectedInPathA()); + + R_SUCCEED(); + } + + Result AppendChild(const Path &rhs) { + R_RETURN(this->AppendChild(rhs.GetString())); + } + + Result Combine(const Path &parent, const Path &child) { + /* Get the lengths. */ + const auto p_len = parent.GetLength(); + const auto c_len = child.GetLength(); + + /* Allocate our buffer. */ + R_TRY(this->Preallocate(p_len + c_len + 1)); + + /* Initialize as parent. */ + R_TRY(this->Initialize(parent)); + + /* If we're empty, we can just initialize as child. */ + if (this->IsEmpty()) { + R_TRY(this->Initialize(child)); + } else { + /* Otherwise, we should append the child. */ + R_TRY(this->AppendChild(child)); + } + + R_SUCCEED(); + } + + Result RemoveChild() { + /* If we don't have a write-buffer, ensure that we have one. */ + if (util::GetReference(m_write_buffer) == nullptr) { + if (const auto len = std::strlen(m_str); len > 0) { + R_TRY(this->Preallocate(len)); + util::Strlcpy(util::GetReference(m_write_buffer).get(), m_str, len + 1); + } + } + + /* Check that it's possible for us to remove a child. */ + auto *p = this->GetWriteBuffer(); + s32 len = std::strlen(p); + R_UNLESS(len != 1 || (p[0] != '/' && p[0] != '.'), fs::ResultNotImplemented()); + + /* Handle a trailing separator. */ + if (len > 0 && (p[len - 1] == '\\' || p[len - 1] == '/')) { + --len; + } + + /* Remove the child path segment. */ + while ((--len) >= 0 && p[len]) { + if (p[len] == '/' || p[len] == '\\') { + if (len > 0) { + p[len] = 0; + } else { + p[1] = 0; + len = 1; + } + break; + } + } + + /* Check that length remains > 0. */ + R_UNLESS(len > 0, fs::ResultNotImplemented()); + + R_SUCCEED(); + } + + Result Normalize(const PathFlags &flags) { + /* If we're already normalized, nothing to do. */ + R_SUCCEED_IF(m_is_normalized); + + /* Check if we're normalized. */ + bool normalized; + size_t dummy; + R_TRY(PathFormatter::IsNormalized(std::addressof(normalized), std::addressof(dummy), m_str, flags)); + + /* If we're not normalized, normalize. */ + if (!normalized) { + /* Determine necessary buffer length. */ + auto len = m_write_buffer_length; + if (flags.IsRelativePathAllowed() && fs::IsPathRelative(m_str)) { + len += 2; + } + if (flags.IsWindowsPathAllowed() && fs::IsWindowsPath(m_str, true)) { + len += 1; + } + + /* Allocate a new buffer. */ + const size_t size = util::AlignUp(len, WriteBufferAlignmentLength); + auto buf = fs::impl::MakeUnique(size); + R_UNLESS(buf != nullptr, fs::ResultAllocationFailureInMakeUnique()); + + /* Normalize into it. */ + R_TRY(PathFormatter::Normalize(buf.get(), size, util::GetReference(m_write_buffer).get(), m_write_buffer_length, flags)); + + /* Set the normalized buffer as our buffer. */ + this->SetModifiableBuffer(std::move(buf), size); + } + + /* Set normalized. */ + m_is_normalized = true; + R_SUCCEED(); + } + private: + void ClearBuffer() { + util::GetReference(m_write_buffer).reset(); + m_write_buffer_length = 0; + m_str = EmptyPath; + } + + void SetModifiableBuffer(WriteBuffer &&buffer, size_t size) { + /* Check pre-conditions. */ + AMS_ASSERT(buffer.get() != nullptr); + AMS_ASSERT(size > 0); + AMS_ASSERT(util::IsAligned(size, WriteBufferAlignmentLength)); + + /* Set write buffer. */ + util::GetReference(m_write_buffer) = std::move(buffer); + m_write_buffer_length = size; + m_str = util::GetReference(m_write_buffer).get(); + } + + constexpr void SetReadOnlyBuffer(const char *buffer) { + m_str = buffer; + if (!std::is_constant_evaluated()) { + util::GetReference(m_write_buffer) = nullptr; + m_write_buffer_length = 0; + } + } + + Result Preallocate(size_t length) { + /* Allocate additional space, if needed. */ + if (length > m_write_buffer_length) { + /* Allocate buffer. */ + const size_t size = util::AlignUp(length, WriteBufferAlignmentLength); + auto buf = fs::impl::MakeUnique(size); + R_UNLESS(buf != nullptr, fs::ResultAllocationFailureInMakeUnique()); + + /* Set write buffer. */ + this->SetModifiableBuffer(std::move(buf), size); + } + + R_SUCCEED(); + } + + Result InitializeImpl(const char *path, size_t size) { + if (size > 0 && path[0]) { + /* Pre allocate a buffer for the path. */ + R_TRY(this->Preallocate(size + 1)); + + /* Copy the path. */ + const size_t copied = util::Strlcpy(this->GetWriteBuffer(), path, size + 1); + R_UNLESS(copied >= size, fs::ResultUnexpectedInPathA()); + } else { + /* We can just clear the buffer. */ + this->ClearBuffer(); + } + + R_SUCCEED(); + } + + char *GetWriteBuffer() { + AMS_ASSERT(util::GetReference(m_write_buffer) != nullptr); + return util::GetReference(m_write_buffer).get(); + } + + size_t GetWriteBufferLength() const { + return m_write_buffer_length; + } + public: + ALWAYS_INLINE bool operator==(const fs::Path &rhs) const { return std::strcmp(this->GetString(), rhs.GetString()) == 0; } + ALWAYS_INLINE bool operator!=(const fs::Path &rhs) const { return !(*this == rhs); } + ALWAYS_INLINE bool operator==(const char *p) const { return std::strcmp(this->GetString(), p) == 0; } + ALWAYS_INLINE bool operator!=(const char *p) const { return !(*this == p); } + }; + + consteval fs::Path MakeConstantPath(const char *s) { return fs::Path(s, util::ConstantInitializeTag{}); } + + inline Result SetUpFixedPath(fs::Path *out, const char *s) { + /* Verify the path is normalized. */ + bool normalized; + size_t dummy; + R_TRY(PathNormalizer::IsNormalized(std::addressof(normalized), std::addressof(dummy), s)); + + R_UNLESS(normalized, fs::ResultInvalidPathFormat()); + + /* Set the fixed path. */ + R_RETURN(out->SetShallowBuffer(s)); + } + + inline Result SetUpFixedPathSingleEntry(fs::Path *out, char *buf, size_t buf_size, const char *e) { + /* Print the path into the buffer. */ + const size_t len = util::TSNPrintf(buf, buf_size, "/%s", e); + R_UNLESS(len < buf_size, fs::ResultInvalidArgument()); + + /* Set up the path. */ + R_RETURN(SetUpFixedPath(out, buf)); + } + + inline Result SetUpFixedPathDoubleEntry(fs::Path *out, char *buf, size_t buf_size, const char *e, const char *e2) { + /* Print the path into the buffer. */ + const size_t len = util::TSNPrintf(buf, buf_size, "/%s/%s", e, e2); + R_UNLESS(len < buf_size, fs::ResultInvalidArgument()); + + /* Set up the path. */ + R_RETURN(SetUpFixedPath(out, buf)); + } + + inline Result SetUpFixedPathSaveId(fs::Path *out, char *buf, size_t buf_size, u64 id) { + /* Print the path into the buffer. */ + const size_t len = util::TSNPrintf(buf, buf_size, "/%016" PRIx64 "", id); + R_UNLESS(len < buf_size, fs::ResultInvalidArgument()); + + /* Set up the path. */ + R_RETURN(SetUpFixedPath(out, buf)); + } + + inline Result SetUpFixedPathSaveMetaName(fs::Path *out, char *buf, size_t buf_size, u32 type) { + /* Print the path into the buffer. */ + const size_t len = util::TSNPrintf(buf, buf_size, "/%08" PRIx32 ".meta", type); + R_UNLESS(len < buf_size, fs::ResultInvalidArgument()); + + /* Set up the path. */ + R_RETURN(SetUpFixedPath(out, buf)); + } + + inline Result SetUpFixedPathSaveMetaDir(fs::Path *out, char *buf, size_t buf_size, u64 id) { + /* Print the path into the buffer. */ + const size_t len = util::TSNPrintf(buf, buf_size, "/saveMeta/%016" PRIx64 "", id); + R_UNLESS(len < buf_size, fs::ResultInvalidArgument()); + + /* Set up the path. */ + R_RETURN(SetUpFixedPath(out, buf)); + } + +} diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_path_utility.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_path_utility.hpp new file mode 100644 index 000000000..b3fc273eb --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_path_utility.hpp @@ -0,0 +1,1210 @@ +/* + * Copyright (c) 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 + +namespace ams::fs { + + namespace StringTraits { + + constexpr inline char DirectorySeparator = '/'; + constexpr inline char DriveSeparator = ':'; + constexpr inline char Dot = '.'; + constexpr inline char NullTerminator = '\x00'; + + constexpr inline char AlternateDirectorySeparator = '\\'; + + constexpr inline const char InvalidCharacters[6] = { ':', '*', '?', '<', '>', '|' }; + constexpr inline const char InvalidCharactersForHostName[6] = { ':', '*', '<', '>', '|', '$' }; + constexpr inline const char InvalidCharactersForMountName[5] = { '*', '?', '<', '>', '|' }; + + namespace impl { + + template + consteval u64 MakeInvalidCharacterMask(size_t n) { + u64 mask = 0; + for (size_t i = 0; i < NumInvalidCharacters; ++i) { + if ((static_cast(InvalidCharacterSet[i]) >> 6) == n) { + mask |= static_cast(1) << (static_cast(InvalidCharacterSet[i]) & 0x3F); + } + } + return mask; + } + + template + constexpr ALWAYS_INLINE bool IsInvalidCharacterImpl(char c) { + constexpr u64 Masks[4] = { + MakeInvalidCharacterMask(0), + MakeInvalidCharacterMask(1), + MakeInvalidCharacterMask(2), + MakeInvalidCharacterMask(3) + }; + + return (Masks[static_cast(c) >> 6] & (static_cast(1) << (static_cast(c) & 0x3F))) != 0; + } + + } + + constexpr ALWAYS_INLINE bool IsInvalidCharacter(char c) { return impl::IsInvalidCharacterImpl(c); } + constexpr ALWAYS_INLINE bool IsInvalidCharacterForHostName(char c) { return impl::IsInvalidCharacterImpl(c); } + constexpr ALWAYS_INLINE bool IsInvalidCharacterForMountName(char c) { return impl::IsInvalidCharacterImpl(c); } + + } + + constexpr inline size_t WindowsDriveLength = 2; + constexpr inline size_t UncPathPrefixLength = 2; + constexpr inline size_t DosDevicePathPrefixLength = 4; + + class PathFlags { + private: + static constexpr u32 WindowsPathFlag = (1 << 0); + static constexpr u32 RelativePathFlag = (1 << 1); + static constexpr u32 EmptyPathFlag = (1 << 2); + static constexpr u32 MountNameFlag = (1 << 3); + static constexpr u32 BackslashFlag = (1 << 4); + static constexpr u32 AllCharactersFlag = (1 << 5); + private: + u32 m_value; + public: + constexpr ALWAYS_INLINE PathFlags() : m_value(0) { /* ... */ } + + #define DECLARE_PATH_FLAG_HANDLER(__WHICH__) \ + constexpr ALWAYS_INLINE bool Is ## __WHICH__ ##Allowed() const { return (m_value & __WHICH__ ## Flag) != 0; } \ + constexpr ALWAYS_INLINE void Allow ## __WHICH__ () { m_value |= __WHICH__ ## Flag; } + + DECLARE_PATH_FLAG_HANDLER(WindowsPath) + DECLARE_PATH_FLAG_HANDLER(RelativePath) + DECLARE_PATH_FLAG_HANDLER(EmptyPath) + DECLARE_PATH_FLAG_HANDLER(MountName) + DECLARE_PATH_FLAG_HANDLER(Backslash) + DECLARE_PATH_FLAG_HANDLER(AllCharacters) + + #undef DECLARE_PATH_FLAG_HANDLER + }; + + template requires (std::same_as || std::same_as) + constexpr inline bool IsDosDevicePath(const T *path) { + AMS_ASSERT(path != nullptr); + + using namespace StringTraits; + + return path[0] == AlternateDirectorySeparator && path[1] == AlternateDirectorySeparator && (path[2] == Dot || path[2] == '?') && (path[3] == DirectorySeparator || path[3] == AlternateDirectorySeparator); + } + + template requires (std::same_as || std::same_as) + constexpr inline bool IsUncPath(const T *path, bool allow_forward_slash = true, bool allow_back_slash = true) { + AMS_ASSERT(path != nullptr); + + using namespace StringTraits; + + return (allow_forward_slash && path[0] == DirectorySeparator && path[1] == DirectorySeparator) || (allow_back_slash && path[0] == AlternateDirectorySeparator && path[1] == AlternateDirectorySeparator); + } + + constexpr inline bool IsWindowsDrive(const char *path) { + AMS_ASSERT(path != nullptr); + + return (('a' <= path[0] && path[0] <= 'z') || ('A' <= path[0] && path[0] <= 'Z')) && path[1] == StringTraits::DriveSeparator; + } + + constexpr inline bool IsWindowsPath(const char *path, bool allow_forward_slash_unc) { + return IsWindowsDrive(path) || IsDosDevicePath(path) || IsUncPath(path, allow_forward_slash_unc, true); + } + + constexpr inline int GetWindowsSkipLength(const char *path) { + if (IsDosDevicePath(path)) { + return DosDevicePathPrefixLength; + } else if (IsWindowsDrive(path)) { + return WindowsDriveLength; + } else if (IsUncPath(path)) { + return UncPathPrefixLength; + } else { + return 0; + } + } + + constexpr inline bool IsPathAbsolute(const char *path) { + return IsWindowsPath(path, false) || path[0] == StringTraits::DirectorySeparator; + } + + constexpr inline bool IsPathRelative(const char *path) { + return path[0] && !IsPathAbsolute(path); + } + + constexpr inline bool IsCurrentDirectory(const char *path) { + return path[0] == StringTraits::Dot && (path[1] == StringTraits::NullTerminator || path[1] == StringTraits::DirectorySeparator); + } + + constexpr inline bool IsParentDirectory(const char *path) { + return path[0] == StringTraits::Dot && path[1] == StringTraits::Dot && (path[2] == StringTraits::NullTerminator || path[2] == StringTraits::DirectorySeparator); + } + + constexpr inline bool IsPathStartWithCurrentDirectory(const char *path) { + return IsCurrentDirectory(path) || IsParentDirectory(path); + } + + constexpr inline bool IsSubPath(const char *lhs, const char *rhs) { + /* Check pre-conditions. */ + AMS_ASSERT(lhs != nullptr); + AMS_ASSERT(rhs != nullptr); + + /* Import StringTraits names for current scope. */ + using namespace StringTraits; + + /* Special case certain paths. */ + if (IsUncPath(lhs) && !IsUncPath(rhs)) { + return false; + } + if (!IsUncPath(lhs) && IsUncPath(rhs)) { + return false; + } + + if (lhs[0] == DirectorySeparator && lhs[1] == NullTerminator && rhs[0] == DirectorySeparator && rhs[1] != NullTerminator) { + return true; + } + if (rhs[0] == DirectorySeparator && rhs[1] == NullTerminator && lhs[0] == DirectorySeparator && lhs[1] != NullTerminator) { + return true; + } + + /* Check subpath. */ + for (size_t i = 0; /* ... */; ++i) { + if (lhs[i] == NullTerminator) { + return rhs[i] == DirectorySeparator; + } else if (rhs[i] == NullTerminator) { + return lhs[i] == DirectorySeparator; + } else if (lhs[i] != rhs[i]) { + return false; + } + } + } + + /* Path utilities. */ + constexpr inline void Replace(char *dst, size_t dst_size, char old_char, char new_char) { + AMS_ASSERT(dst != nullptr); + for (char *cur = dst; cur < dst + dst_size && *cur; ++cur) { + if (*cur == old_char) { + *cur = new_char; + } + } + } + + constexpr inline Result CheckUtf8(const char *s) { + /* Check pre-conditions. */ + AMS_ASSERT(s != nullptr); + + /* Iterate, checking for utf8-validity. */ + while (*s) { + char utf8_buf[4] = {}; + + const auto pick_res = util::PickOutCharacterFromUtf8String(utf8_buf, std::addressof(s)); + R_UNLESS(pick_res == util::CharacterEncodingResult_Success, fs::ResultInvalidPathFormat()); + + u32 dummy; + const auto cvt_res = util::ConvertCharacterUtf8ToUtf32(std::addressof(dummy), utf8_buf); + R_UNLESS(cvt_res == util::CharacterEncodingResult_Success, fs::ResultInvalidPathFormat()); + } + + R_SUCCEED(); + } + + /* Path formatting. */ + class PathNormalizer { + private: + enum class PathState { + Start, + Normal, + FirstSeparator, + Separator, + CurrentDir, + ParentDir, + }; + private: + static constexpr void ReplaceParentDirectoryPath(char *dst, const char *src) { + /* Use StringTraits names for remainder of scope. */ + using namespace StringTraits; + + /* Start with a dir-separator. */ + dst[0] = DirectorySeparator; + + auto i = 1; + while (src[i] != NullTerminator) { + if ((src[i - 1] == DirectorySeparator || src[i - 1] == AlternateDirectorySeparator) && src[i + 0] == Dot && src[i + 1] == Dot && (src[i + 2] == DirectorySeparator || src[i + 2] == AlternateDirectorySeparator)) { + dst[i - 1] = DirectorySeparator; + dst[i + 0] = Dot; + dst[i + 1] = Dot; + dst[i + 2] = DirectorySeparator; + i += 3; + } else { + if (src[i - 1] == AlternateDirectorySeparator && src[i + 0] == Dot && src[i + 1] == Dot && src[i + 2] == NullTerminator) { + dst[i - 1] = DirectorySeparator; + dst[i + 0] = Dot; + dst[i + 1] = Dot; + i += 2; + break; + } + + dst[i] = src[i]; + ++i; + } + } + + dst[i] = StringTraits::NullTerminator; + } + public: + static constexpr bool IsParentDirectoryPathReplacementNeeded(const char *path) { + /* Use StringTraits names for remainder of scope. */ + using namespace StringTraits; + + if (path[0] != DirectorySeparator && path[0] != AlternateDirectorySeparator) { + return false; + } + + /* Check to find a parent reference using alternate separators. */ + if (path[0] != NullTerminator && path[1] != NullTerminator && path[2] != NullTerminator) { + size_t i; + for (i = 0; path[i + 3] != NullTerminator; ++path) { + if (path[i + 1] != Dot || path[i + 2] != Dot) { + continue; + } + + const char c0 = path[i + 0]; + const char c3 = path[i + 3]; + + if (c0 == AlternateDirectorySeparator && (c3 == DirectorySeparator || c3 == AlternateDirectorySeparator || c3 == NullTerminator)) { + return true; + } + + if (c3 == AlternateDirectorySeparator && (c0 == DirectorySeparator || c0 == AlternateDirectorySeparator)) { + return true; + } + } + + if (path[i + 0] == AlternateDirectorySeparator && path[i + 1] == Dot && path[i + 2] == Dot /* && path[i + 3] == NullTerminator */) { + return true; + } + } + + return false; + } + + static constexpr Result IsNormalized(bool *out, size_t *out_len, const char *path, bool allow_all_characters = false) { + /* Use StringTraits names for remainder of scope. */ + using namespace StringTraits; + + /* Parse the path. */ + auto state = PathState::Start; + size_t len = 0; + while (path[len] != NullTerminator) { + /* Get the current character. */ + const char c = path[len++]; + + /* Check the current character is valid. */ + if (!allow_all_characters && state != PathState::Start) { + R_UNLESS(!IsInvalidCharacter(c), fs::ResultInvalidCharacter()); + } + + /* Process depending on current state. */ + switch (state) { + /* Import the PathState enums for convenience. */ + using enum PathState; + + case Start: + R_UNLESS(c == DirectorySeparator, fs::ResultInvalidPathFormat()); + state = FirstSeparator; + break; + case Normal: + if (c == DirectorySeparator) { + state = Separator; + } + break; + case FirstSeparator: + case Separator: + if (c == DirectorySeparator) { + *out = false; + R_SUCCEED(); + } + + if (c == Dot) { + state = CurrentDir; + } else { + state = Normal; + } + break; + case CurrentDir: + if (c == DirectorySeparator) { + *out = false; + R_SUCCEED(); + } + + if (c == Dot) { + state = ParentDir; + } else { + state = Normal; + } + break; + case ParentDir: + if (c == DirectorySeparator) { + *out = false; + R_SUCCEED(); + } + + state = Normal; + break; + AMS_UNREACHABLE_DEFAULT_CASE(); + } + } + + /* Check the final state. */ + switch (state) { + /* Import the PathState enums for convenience. */ + using enum PathState; + case Start: + R_THROW(fs::ResultInvalidPathFormat()); + case Normal: + case FirstSeparator: + *out = true; + break; + case Separator: + case CurrentDir: + case ParentDir: + *out = false; + break; + AMS_UNREACHABLE_DEFAULT_CASE(); + } + + /* Set the output length. */ + *out_len = len; + R_SUCCEED(); + } + + static constexpr Result Normalize(char *dst, size_t *out_len, const char *path, size_t max_out_size, bool is_windows_path, bool is_drive_relative_path, bool allow_all_characters = false) { + /* Use StringTraits names for remainder of scope. */ + using namespace StringTraits; + + /* Prepare to iterate. */ + const char *cur_path = path; + size_t total_len = 0; + + /* If path begins with a separator, check that we're not drive relative. */ + if (cur_path[0] != DirectorySeparator) { + R_UNLESS(is_drive_relative_path, fs::ResultInvalidPathFormat()); + + dst[total_len++] = DirectorySeparator; + } + + /* We're going to need to do path replacement, potentially. */ + char *replacement_path = nullptr; + size_t replacement_path_size = 0; + ON_SCOPE_EXIT { + if (replacement_path != nullptr) { + if (std::is_constant_evaluated()) { + delete[] replacement_path; + } else { + ::ams::fs::impl::Deallocate(replacement_path, replacement_path_size); + } + } + }; + + /* Perform path replacement, if necessary. */ + if (IsParentDirectoryPathReplacementNeeded(cur_path)) { + if (std::is_constant_evaluated()) { + replacement_path_size = fs::EntryNameLengthMax + 1; + replacement_path = new char[replacement_path_size]; + } else { + replacement_path_size = fs::EntryNameLengthMax + 1; + replacement_path = static_cast(::ams::fs::impl::Allocate(replacement_path_size)); + } + + ReplaceParentDirectoryPath(replacement_path, cur_path); + + cur_path = replacement_path; + } + + /* Iterate, normalizing path components. */ + bool skip_next_sep = false; + size_t i = 0; + + while (cur_path[i] != NullTerminator) { + /* Process a directory separator, if we run into one. */ + if (cur_path[i] == DirectorySeparator) { + /* Swallow separators. */ + do { ++i; } while (cur_path[i] == DirectorySeparator); + + /* Check if we hit end of string. */ + if (cur_path[i] == NullTerminator) { + break; + } + + /* If we aren't skipping the separator, write it, checking that we remain in bounds. */ + if (!skip_next_sep) { + if (total_len + 1 == max_out_size) { + dst[total_len] = NullTerminator; + *out_len = total_len; + R_THROW(fs::ResultTooLongPath()); + } + + dst[total_len++] = DirectorySeparator; + } + + /* Don't skip the next separator. */ + skip_next_sep = false; + } + + /* Get the length of the current directory component. */ + size_t dir_len = 0; + while (cur_path[i + dir_len] != DirectorySeparator && cur_path[i + dir_len] != NullTerminator) { + /* Check for validity. */ + if (!allow_all_characters) { + R_UNLESS(!IsInvalidCharacter(cur_path[i + dir_len]), fs::ResultInvalidCharacter()); + } + + ++dir_len; + } + + /* Handle the current dir component. */ + if (IsCurrentDirectory(cur_path + i)) { + skip_next_sep = true; + } else if (IsParentDirectory(cur_path + i)) { + /* We should have just written a separator. */ + AMS_ASSERT(dst[total_len - 1] == DirectorySeparator); + + /* We should have started with a separator, for non-windows paths. */ + if (!is_windows_path) { + AMS_ASSERT(dst[0] == DirectorySeparator); + } + + /* Remove the previous component. */ + if (total_len == 1) { + R_UNLESS(is_windows_path, fs::ResultDirectoryUnobtainable()); + + --total_len; + } else { + total_len -= 2; + + do { + if (dst[total_len] == DirectorySeparator) { + break; + } + } while ((--total_len) != 0); + } + + /* We should be pointing to a directory separator, for non-windows paths. */ + if (!is_windows_path) { + AMS_ASSERT(dst[total_len] == DirectorySeparator); + } + + /* We should remain in bounds. */ + AMS_ASSERT(total_len < max_out_size); + } else { + /* Copy, possibly truncating. */ + if (total_len + dir_len + 1 > max_out_size) { + const size_t copy_len = max_out_size - (total_len + 1); + + for (size_t j = 0; j < copy_len; ++j) { + dst[total_len++] = cur_path[i + j]; + } + + dst[total_len] = NullTerminator; + *out_len = total_len; + R_THROW(fs::ResultTooLongPath()); + } + + for (size_t j = 0; j < dir_len; ++j) { + dst[total_len++] = cur_path[i + j]; + } + } + + /* Advance past the current directory component. */ + i += dir_len; + } + + if (skip_next_sep) { + --total_len; + } + + if (total_len == 0 && max_out_size != 0) { + total_len = 1; + dst[0] = DirectorySeparator; + } + + /* NOTE: Probable nintendo bug, as max_out_size must be at least total_len + 1 for the null terminator. */ + R_UNLESS(max_out_size >= total_len - 1, fs::ResultTooLongPath()); + + dst[total_len] = NullTerminator; + + /* Check that the result path is normalized. */ + bool is_normalized; + size_t dummy; + R_TRY(IsNormalized(std::addressof(is_normalized), std::addressof(dummy), dst, allow_all_characters)); + + /* Assert that the result path is normalized. */ + AMS_ASSERT(is_normalized); + + /* Set the output length. */ + *out_len = total_len; + R_SUCCEED(); + } + }; + + class PathFormatter { + private: + static constexpr ALWAYS_INLINE Result CheckSharedName(const char *name, size_t len) { + /* Use StringTraits names for remainder of scope. */ + using namespace StringTraits; + + if (len == 1) { + R_UNLESS(name[0] != Dot, fs::ResultInvalidPathFormat()); + } else if (len == 2) { + R_UNLESS(name[0] != Dot || name[1] != Dot, fs::ResultInvalidPathFormat()); + } + + for (size_t i = 0; i < len; ++i) { + R_UNLESS(!IsInvalidCharacter(name[i]), fs::ResultInvalidCharacter()); + } + + R_SUCCEED(); + } + + static constexpr ALWAYS_INLINE Result CheckHostName(const char *name, size_t len) { + /* Use StringTraits names for remainder of scope. */ + using namespace StringTraits; + + if (len == 2) { + R_UNLESS(name[0] != Dot || name[1] != Dot, fs::ResultInvalidPathFormat()); + } + + for (size_t i = 0; i < len; ++i) { + R_UNLESS(!IsInvalidCharacterForHostName(name[i]), fs::ResultInvalidCharacter()); + } + + R_SUCCEED(); + } + + static constexpr Result CheckInvalidBackslash(bool *out_contains_backslash, const char *path, bool allow_backslash) { + /* Use StringTraits names for remainder of scope. */ + using namespace StringTraits; + + /* Default to no backslashes, so we can just write if we see one. */ + *out_contains_backslash = false; + + while (*path != NullTerminator) { + if (*(path++) == AlternateDirectorySeparator) { + *out_contains_backslash = true; + + R_UNLESS(allow_backslash, fs::ResultInvalidCharacter()); + } + } + + R_SUCCEED(); + } + public: + static constexpr ALWAYS_INLINE Result CheckPathFormat(const char *path, const PathFlags &flags) { + bool normalized; + size_t len; + R_RETURN(IsNormalized(std::addressof(normalized), std::addressof(len), path, flags)); + } + + static constexpr ALWAYS_INLINE Result SkipMountName(const char **out, size_t *out_len, const char *path) { + return ParseMountName(out, out_len, nullptr, 0, path); + } + + static constexpr Result ParseMountName(const char **out, size_t *out_len, char *out_mount_name, size_t out_mount_name_buffer_size, const char *path) { + /* Check pre-conditions. */ + AMS_ASSERT(path != nullptr); + AMS_ASSERT(out_len != nullptr); + AMS_ASSERT(out != nullptr); + AMS_ASSERT((out_mount_name == nullptr) == (out_mount_name_buffer_size == 0)); + + /* Use StringTraits names for remainder of scope. */ + using namespace StringTraits; + + /* Determine max mount length. */ + const auto max_mount_len = out_mount_name_buffer_size == 0 ? MountNameLengthMax + 1 : std::min(MountNameLengthMax + 1, out_mount_name_buffer_size); + + /* Parse the path until we see a drive separator. */ + size_t mount_len = 0; + for (/* ... */; mount_len < max_mount_len && path[mount_len]; ++mount_len) { + const char c = path[mount_len]; + + /* If we see a drive separator, advance, then we're done with the pre-drive separator part of the mount. */ + if (c == DriveSeparator) { + ++mount_len; + break; + } + + /* If we see a directory separator, we're not in a mount name. */ + if (c == DirectorySeparator || c == AlternateDirectorySeparator) { + *out = path; + *out_len = 0; + R_SUCCEED(); + } + } + + + /* Check to be sure we're actually looking at a mount name. */ + if (mount_len <= 2 || path[mount_len - 1] != DriveSeparator) { + *out = path; + *out_len = 0; + R_SUCCEED(); + } + + /* Check that all characters in the mount name are allowable. */ + for (size_t i = 0; i < mount_len; ++i) { + R_UNLESS(!IsInvalidCharacterForMountName(path[i]), fs::ResultInvalidCharacter()); + } + + /* Copy out the mount name. */ + if (out_mount_name_buffer_size > 0) { + R_UNLESS(mount_len < out_mount_name_buffer_size, fs::ResultTooLongPath()); + + for (size_t i = 0; i < mount_len; ++i) { + out_mount_name[i] = path[i]; + } + out_mount_name[mount_len] = NullTerminator; + } + + /* Set the output. */ + *out = path + mount_len; + *out_len = mount_len; + R_SUCCEED(); + } + + static constexpr ALWAYS_INLINE Result SkipRelativeDotPath(const char **out, size_t *out_len, const char *path) { + return ParseRelativeDotPath(out, out_len, nullptr, 0, path); + } + + static constexpr Result ParseRelativeDotPath(const char **out, size_t *out_len, char *out_relative, size_t out_relative_buffer_size, const char *path) { + /* Check pre-conditions. */ + AMS_ASSERT(path != nullptr); + AMS_ASSERT(out_len != nullptr); + AMS_ASSERT(out != nullptr); + AMS_ASSERT((out_relative == nullptr) == (out_relative_buffer_size == 0)); + + /* Use StringTraits names for remainder of scope. */ + using namespace StringTraits; + + /* Initialize the output buffer, if we have one. */ + if (out_relative_buffer_size > 0) { + out_relative[0] = NullTerminator; + } + + /* Check if the path is relative. */ + if (path[0] == Dot && (path[1] == NullTerminator || path[1] == DirectorySeparator || path[1] == AlternateDirectorySeparator)) { + if (out_relative_buffer_size > 0) { + R_UNLESS(out_relative_buffer_size >= 2, fs::ResultTooLongPath()); + + out_relative[0] = Dot; + out_relative[1] = NullTerminator; + } + + *out = path + 1; + *out_len = 1; + R_SUCCEED(); + } + + /* Ensure the path isn't a parent directory. */ + R_UNLESS(!(path[0] == Dot && path[1] == Dot), fs::ResultDirectoryUnobtainable()); + + /* There was no relative dot path. */ + *out = path; + *out_len = 0; + R_SUCCEED(); + } + + static constexpr Result SkipWindowsPath(const char **out, size_t *out_len, bool *out_normalized, const char *path, bool has_mount_name) { + /* We're normalized if and only if the parsing doesn't throw ResultNotNormalized(). */ + *out_normalized = true; + + R_TRY_CATCH(ParseWindowsPath(out, out_len, nullptr, 0, path, has_mount_name)) { + R_CATCH(fs::ResultNotNormalized) { *out_normalized = false; } + } R_END_TRY_CATCH; + ON_RESULT_INCLUDED(fs::ResultNotNormalized) { *out_normalized = false; }; + + R_SUCCEED(); + } + + static constexpr Result ParseWindowsPath(const char **out, size_t *out_len, char *out_win, size_t out_win_buffer_size, const char *path, bool has_mount_name) { + /* Check pre-conditions. */ + AMS_ASSERT(path != nullptr); + AMS_ASSERT(out_len != nullptr); + AMS_ASSERT(out != nullptr); + AMS_ASSERT((out_win == nullptr) == (out_win_buffer_size == 0)); + + /* Use StringTraits names for remainder of scope. */ + using namespace StringTraits; + + /* Initialize the output buffer, if we have one. */ + if (out_win_buffer_size > 0) { + out_win[0] = NullTerminator; + } + + /* Handle path start. */ + const char *cur_path = path; + if (has_mount_name && path[0] == DirectorySeparator) { + if (path[1] == AlternateDirectorySeparator && path[2] == AlternateDirectorySeparator) { + R_UNLESS(out_win_buffer_size > 0, fs::ResultNotNormalized()); + + ++cur_path; + } else if (IsWindowsDrive(path + 1)) { + R_UNLESS(out_win_buffer_size > 0, fs::ResultNotNormalized()); + + ++cur_path; + } + } + + /* Handle windows drive. */ + if (IsWindowsDrive(cur_path)) { + /* Parse up to separator. */ + size_t win_path_len = WindowsDriveLength; + for (/* ... */; cur_path[win_path_len] != NullTerminator; ++win_path_len) { + R_UNLESS(!IsInvalidCharacter(cur_path[win_path_len]), fs::ResultInvalidCharacter()); + + if (cur_path[win_path_len] == DirectorySeparator || cur_path[win_path_len] == AlternateDirectorySeparator) { + break; + } + } + + /* Ensure that we're normalized, if we're required to be. */ + if (out_win_buffer_size == 0) { + for (size_t i = 0; i < win_path_len; ++i) { + R_UNLESS(cur_path[i] != AlternateDirectorySeparator, fs::ResultNotNormalized()); + } + } else { + /* Ensure we can copy into the normalized buffer. */ + R_UNLESS(win_path_len < out_win_buffer_size, fs::ResultTooLongPath()); + + for (size_t i = 0; i < win_path_len; ++i) { + out_win[i] = cur_path[i]; + } + out_win[win_path_len] = NullTerminator; + + fs::Replace(out_win, win_path_len, AlternateDirectorySeparator, DirectorySeparator); + } + + *out = cur_path + win_path_len; + *out_len = win_path_len; + R_SUCCEED(); + } + + /* Handle DOS device. */ + if (IsDosDevicePath(cur_path)) { + size_t dos_prefix_len = DosDevicePathPrefixLength; + + if (IsWindowsDrive(cur_path + dos_prefix_len)) { + dos_prefix_len += WindowsDriveLength; + } else { + --dos_prefix_len; + } + + if (out_win_buffer_size > 0) { + /* Ensure we can copy into the normalized buffer. */ + R_UNLESS(dos_prefix_len < out_win_buffer_size, fs::ResultTooLongPath()); + + for (size_t i = 0; i < dos_prefix_len; ++i) { + out_win[i] = cur_path[i]; + } + out_win[dos_prefix_len] = NullTerminator; + + fs::Replace(out_win, dos_prefix_len, DirectorySeparator, AlternateDirectorySeparator); + } + + *out = cur_path + dos_prefix_len; + *out_len = dos_prefix_len; + R_SUCCEED(); + } + + /* Handle UNC path. */ + if (IsUncPath(cur_path, false, true)) { + const char *final_path = cur_path; + + R_UNLESS(cur_path[UncPathPrefixLength] != DirectorySeparator, fs::ResultInvalidPathFormat()); + R_UNLESS(cur_path[UncPathPrefixLength] != AlternateDirectorySeparator, fs::ResultInvalidPathFormat()); + + size_t cur_component_offset = 0; + size_t pos = UncPathPrefixLength; + for (/* ... */; cur_path[pos] != NullTerminator; ++pos) { + if (cur_path[pos] == DirectorySeparator || cur_path[pos] == AlternateDirectorySeparator) { + if (cur_component_offset != 0) { + R_TRY(CheckSharedName(cur_path + cur_component_offset, pos - cur_component_offset)); + + final_path = cur_path + pos; + break; + } + + R_UNLESS(cur_path[pos + 1] != DirectorySeparator, fs::ResultInvalidPathFormat()); + R_UNLESS(cur_path[pos + 1] != AlternateDirectorySeparator, fs::ResultInvalidPathFormat()); + + R_TRY(CheckHostName(cur_path + 2, pos - 2)); + + cur_component_offset = pos + 1; + } + } + + R_UNLESS(cur_component_offset != pos, fs::ResultInvalidPathFormat()); + + if (cur_component_offset != 0 && final_path == cur_path) { + R_TRY(CheckSharedName(cur_path + cur_component_offset, pos - cur_component_offset)); + + final_path = cur_path + pos; + } + + size_t unc_prefix_len = final_path - cur_path; + + /* Ensure that we're normalized, if we're required to be. */ + if (out_win_buffer_size == 0) { + for (size_t i = 0; i < unc_prefix_len; ++i) { + R_UNLESS(cur_path[i] != DirectorySeparator, fs::ResultNotNormalized()); + } + } else { + /* Ensure we can copy into the normalized buffer. */ + R_UNLESS(unc_prefix_len < out_win_buffer_size, fs::ResultTooLongPath()); + + for (size_t i = 0; i < unc_prefix_len; ++i) { + out_win[i] = cur_path[i]; + } + out_win[unc_prefix_len] = NullTerminator; + + fs::Replace(out_win, unc_prefix_len, DirectorySeparator, AlternateDirectorySeparator); + } + + *out = cur_path + unc_prefix_len; + *out_len = unc_prefix_len; + R_SUCCEED(); + } + + /* There's no windows path to parse. */ + *out = path; + *out_len = 0; + R_SUCCEED(); + } + + static constexpr Result IsNormalized(bool *out, size_t *out_len, const char *path, const PathFlags &flags = {}) { + /* Ensure nothing is null. */ + R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); + R_UNLESS(out_len != nullptr, fs::ResultNullptrArgument()); + R_UNLESS(path != nullptr, fs::ResultNullptrArgument()); + + /* Verify that the path is valid utf-8. */ + R_TRY(fs::CheckUtf8(path)); + + /* Use StringTraits names for remainder of scope. */ + using namespace StringTraits; + + /* Handle the case where the path is empty. */ + if (path[0] == NullTerminator) { + R_UNLESS(flags.IsEmptyPathAllowed(), fs::ResultInvalidPathFormat()); + + *out = true; + *out_len = 0; + R_SUCCEED(); + } + + /* All normalized paths start with a directory separator...unless they're windows paths, relative paths, or have mount names. */ + if (path[0] != DirectorySeparator) { + R_UNLESS(flags.IsWindowsPathAllowed() || flags.IsRelativePathAllowed() || flags.IsMountNameAllowed(), fs::ResultInvalidPathFormat()); + } + + /* Check that the path is allowed to be a windows path, if it is. */ + if (fs::IsWindowsPath(path, false)) { + R_UNLESS(flags.IsWindowsPathAllowed(), fs::ResultInvalidPathFormat()); + } + + /* Skip past the mount name, if one is present. */ + size_t total_len = 0; + size_t mount_name_len = 0; + R_TRY(SkipMountName(std::addressof(path), std::addressof(mount_name_len), path)); + + /* If we had a mount name, check that that was allowed. */ + if (mount_name_len > 0) { + R_UNLESS(flags.IsMountNameAllowed(), fs::ResultInvalidPathFormat()); + + total_len += mount_name_len; + } + + /* Check that the path starts as a normalized path should. */ + if (path[0] != DirectorySeparator && !IsPathStartWithCurrentDirectory(path) && !IsWindowsPath(path, false)) { + R_UNLESS(flags.IsRelativePathAllowed(), fs::ResultInvalidPathFormat()); + R_UNLESS(!IsInvalidCharacter(path[0]), fs::ResultInvalidPathFormat()); + + *out = false; + R_SUCCEED(); + } + + /* Process relative path. */ + size_t relative_len = 0; + R_TRY(SkipRelativeDotPath(std::addressof(path), std::addressof(relative_len), path)); + + /* If we have a relative path, check that was allowed. */ + if (relative_len > 0) { + R_UNLESS(flags.IsRelativePathAllowed(), fs::ResultInvalidPathFormat()); + + total_len += relative_len; + + if (path[0] == NullTerminator) { + *out = true; + *out_len = total_len; + R_SUCCEED(); + } + } + + /* Process windows path. */ + size_t windows_len = 0; + bool normalized_win = false; + R_TRY(SkipWindowsPath(std::addressof(path), std::addressof(windows_len), std::addressof(normalized_win), path, mount_name_len > 0)); + + /* If the windows path wasn't normalized, we're not normalized. */ + if (!normalized_win) { + R_UNLESS(flags.IsWindowsPathAllowed(), fs::ResultInvalidPathFormat()); + + *out = false; + R_SUCCEED(); + } + + /* If we had a windows path, check that was allowed. */ + if (windows_len > 0) { + R_UNLESS(flags.IsWindowsPathAllowed(), fs::ResultInvalidPathFormat()); + + total_len += windows_len; + + /* We can't have both a relative path and a windows path. */ + R_UNLESS(relative_len == 0, fs::ResultInvalidPathFormat()); + + /* A path ending in a windows path isn't normalized. */ + if (path[0] == NullTerminator) { + *out = false; + R_SUCCEED(); + } + + /* Check that there are no windows directory separators in the path. */ + for (size_t i = 0; path[i] != NullTerminator; ++i) { + if (path[i] == AlternateDirectorySeparator) { + *out = false; + R_SUCCEED(); + } + } + } + + /* Check that parent directory replacement is not needed if backslashes are allowed. */ + if (flags.IsBackslashAllowed() && PathNormalizer::IsParentDirectoryPathReplacementNeeded(path)) { + *out = false; + R_SUCCEED(); + } + + /* Check that the backslash state is valid. */ + bool is_backslash_contained = false; + R_TRY(CheckInvalidBackslash(std::addressof(is_backslash_contained), path, flags.IsWindowsPathAllowed() || flags.IsBackslashAllowed())); + + /* Check that backslashes are contained only if allowed. */ + if (is_backslash_contained && !flags.IsBackslashAllowed()) { + *out = false; + R_SUCCEED(); + } + + /* Check that the final result path is normalized. */ + size_t normal_len = 0; + R_TRY(PathNormalizer::IsNormalized(out, std::addressof(normal_len), path, flags.IsAllCharactersAllowed())); + + /* Add the normal length. */ + total_len += normal_len; + + /* Set the output length. */ + *out_len = total_len; + R_SUCCEED(); + } + + static constexpr Result Normalize(char *dst, size_t dst_size, const char *path, size_t path_len, const PathFlags &flags) { + /* Use StringTraits names for remainder of scope. */ + using namespace StringTraits; + + /* Prepare to iterate. */ + const char *src = path; + size_t cur_pos = 0; + bool is_windows_path = false; + + /* Check if the path is empty. */ + if (src[0] == NullTerminator) { + if (dst_size != 0) { + dst[0] = NullTerminator; + } + + R_UNLESS(flags.IsEmptyPathAllowed(), fs::ResultInvalidPathFormat()); + + R_SUCCEED(); + } + + /* Handle a mount name. */ + size_t mount_name_len = 0; + if (flags.IsMountNameAllowed()) { + R_TRY(ParseMountName(std::addressof(src), std::addressof(mount_name_len), dst + cur_pos, dst_size - cur_pos, src)); + + cur_pos += mount_name_len; + } + + /* Handle a drive-relative prefix. */ + bool is_drive_relative = false; + if (src[0] != DirectorySeparator && !IsPathStartWithCurrentDirectory(src) && !IsWindowsPath(src, false)) { + R_UNLESS(flags.IsRelativePathAllowed(), fs::ResultInvalidPathFormat()); + R_UNLESS(!IsInvalidCharacter(src[0]), fs::ResultInvalidPathFormat()); + + dst[cur_pos++] = Dot; + is_drive_relative = true; + } + + size_t relative_len = 0; + if (flags.IsRelativePathAllowed()) { + R_UNLESS(cur_pos < dst_size, fs::ResultTooLongPath()); + + R_TRY(ParseRelativeDotPath(std::addressof(src), std::addressof(relative_len), dst + cur_pos, dst_size - cur_pos, src)); + + cur_pos += relative_len; + + if (src[0] == NullTerminator) { + R_UNLESS(cur_pos < dst_size, fs::ResultTooLongPath()); + + dst[cur_pos] = NullTerminator; + R_SUCCEED(); + } + } + + /* Handle a windows path. */ + if (flags.IsWindowsPathAllowed()) { + const char * const orig = src; + + R_UNLESS(cur_pos < dst_size, fs::ResultTooLongPath()); + + size_t windows_len = 0; + R_TRY(ParseWindowsPath(std::addressof(src), std::addressof(windows_len), dst + cur_pos, dst_size - cur_pos, src, mount_name_len != 0)); + + cur_pos += windows_len; + + if (src[0] == NullTerminator) { + /* NOTE: Bug in original code here repeated, should be checking cur_pos + 2. */ + R_UNLESS(cur_pos + 1 < dst_size, fs::ResultTooLongPath()); + + dst[cur_pos + 0] = DirectorySeparator; + dst[cur_pos + 1] = NullTerminator; + R_SUCCEED(); + } + + if ((src - orig) > 0) { + is_windows_path = true; + } + } + + /* Check for invalid backslash. */ + bool backslash_contained = false; + R_TRY(CheckInvalidBackslash(std::addressof(backslash_contained), src, flags.IsWindowsPathAllowed() || flags.IsBackslashAllowed())); + + /* Handle backslash replacement as necessary. */ + if (backslash_contained && flags.IsWindowsPathAllowed()) { + /* Create a temporary buffer holding a slash-replaced version of the path. */ + /* NOTE: Nintendo unnecessarily allocates and replaces here a fully copy of the path, despite having skipped some of it already. */ + const size_t replaced_src_len = path_len - (src - path); + + char *replaced_src = nullptr; + ON_SCOPE_EXIT { + if (replaced_src != nullptr) { + if (std::is_constant_evaluated()) { + delete[] replaced_src; + } else { + ::ams::fs::impl::Deallocate(replaced_src, replaced_src_len); + } + } + }; + + if (std::is_constant_evaluated()) { + replaced_src = new char[replaced_src_len]; + } else { + replaced_src = static_cast(::ams::fs::impl::Allocate(replaced_src_len)); + } + + util::Strlcpy(replaced_src, src, replaced_src_len); + + fs::Replace(replaced_src, replaced_src_len, AlternateDirectorySeparator, DirectorySeparator); + + size_t dummy; + R_TRY(PathNormalizer::Normalize(dst + cur_pos, std::addressof(dummy), replaced_src, dst_size - cur_pos, is_windows_path, is_drive_relative, flags.IsAllCharactersAllowed())); + } else { + /* We can just do normalization. */ + size_t dummy; + R_TRY(PathNormalizer::Normalize(dst + cur_pos, std::addressof(dummy), src, dst_size - cur_pos, is_windows_path, is_drive_relative, flags.IsAllCharactersAllowed())); + } + + R_SUCCEED(); + } + }; + + inline Result ConvertToFspPath(fssrv::sf::FspPath *out, const char *src) { + /* Check pre-conditions. */ + AMS_ASSERT(out != nullptr); + AMS_ASSERT(src != nullptr); + + /* Copy the path. */ + const size_t len = util::Strlcpy(out->str, src, sizeof(out->str)); + R_UNLESS(len < sizeof(out->str), fs::ResultTooLongPath()); + + /* Skip mount name. */ + const char *path_split_mount_name; + size_t skip_len; + R_TRY(PathFormatter::SkipMountName(std::addressof(path_split_mount_name), std::addressof(skip_len), src)); + + /* Perform further validation. */ + if (fs::IsWindowsPath(path_split_mount_name, true)) { + if ((skip_len == 0 || !util::Strncmp(src, AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME ":", AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME_LEN + 1)) && fs::IsUncPath(out->str + skip_len, true, false)) { + out->str[skip_len + 0] = '\\'; + out->str[skip_len + 1] = '\\'; + } + } else { + fs::Replace(out->str, sizeof(out->str) - 1, '\\', '/'); + } + + R_SUCCEED(); + } + + Result FormatToFspPath(fssrv::sf::FspPath *out, const char *fmt, ...) __attribute__((format(printf, 2, 3))); + + inline Result FormatToFspPath(fssrv::sf::FspPath *out, const char *fmt, ...) { + /* Check pre-conditions. */ + AMS_ASSERT(out != nullptr); + AMS_ASSERT(fmt != nullptr); + + /* Format the path. */ + std::va_list vl; + va_start(vl, fmt); + const size_t len = util::VSNPrintf(out->str, sizeof(out->str), fmt, vl); + va_end(vl); + + R_UNLESS(len < sizeof(out->str), fs::ResultTooLongPath()); + + /* Skip mount name. */ + const char *path_split_mount_name; + size_t skip_len; + R_TRY(PathFormatter::SkipMountName(std::addressof(path_split_mount_name), std::addressof(skip_len), out->str)); + + /* Perform further validation. */ + if (fs::IsWindowsPath(path_split_mount_name, true)) { + if ((skip_len == 0 || !util::Strncmp(out->str, AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME ":", AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME_LEN + 1)) && fs::IsUncPath(out->str + skip_len, true, false)) { + out->str[skip_len + 0] = '\\'; + out->str[skip_len + 1] = '\\'; + } + } else { + fs::Replace(out->str, sizeof(out->str) - 1, '\\', '/'); + } + + R_SUCCEED(); + } + +} diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_path_utils.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_path_utils.hpp deleted file mode 100644 index 60a10d271..000000000 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_path_utils.hpp +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 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 - -namespace ams::fs { - - namespace StringTraits { - - constexpr inline char DirectorySeparator = '/'; - constexpr inline char DriveSeparator = ':'; - constexpr inline char Dot = '.'; - constexpr inline char NullTerminator = '\x00'; - - constexpr inline char AlternateDirectorySeparator = '\\'; - - } - - /* Windows path utilities. */ - constexpr inline bool IsWindowsDrive(const char *path) { - AMS_ASSERT(path != nullptr); - - const char c = path[0]; - return (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')) && path[1] == StringTraits::DriveSeparator; - } - - constexpr inline bool IsUnc(const char *path) { - return (path[0] == StringTraits::DirectorySeparator && path[1] == StringTraits::DirectorySeparator) || - (path[0] == StringTraits::AlternateDirectorySeparator && path[1] == StringTraits::AlternateDirectorySeparator); - } - - constexpr inline s64 GetWindowsPathSkipLength(const char *path) { - if (IsWindowsDrive(path)) { - return 2; - } - if (IsUnc(path)) { - for (s64 i = 2; path[i] != StringTraits::NullTerminator; ++i) { - if (path[i] == '$' || path[i] == ':') { - return i + 1; - } - } - } - return 0; - } - - /* Path utilities. */ - inline void Replace(char *dst, size_t dst_size, char old_char, char new_char) { - AMS_ASSERT(dst != nullptr); - for (char *cur = dst; cur < dst + dst_size && *cur != StringTraits::NullTerminator; ++cur) { - if (*cur == old_char) { - *cur = new_char; - } - } - } - - Result FspPathPrintf(fssrv::sf::FspPath *dst, const char *format, ...) __attribute__((format(printf, 2, 3))); - - inline Result FspPathPrintf(fssrv::sf::FspPath *dst, const char *format, ...) { - AMS_ASSERT(dst != nullptr); - - /* Format the path. */ - std::va_list va_list; - va_start(va_list, format); - const size_t len = util::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, int max_path_len, int max_name_len); - - bool IsSubPath(const char *lhs, const char *rhs); - - /* Path normalization. */ - class PathNormalizer { - public: - static constexpr const char RootPath[] = "/"; - public: - static constexpr inline bool IsSeparator(char c) { - return c == StringTraits::DirectorySeparator; - } - - static constexpr inline bool IsAnySeparator(char c) { - return c == StringTraits::DirectorySeparator || c == StringTraits::AlternateDirectorySeparator; - } - - static constexpr inline bool IsNullTerminator(char c) { - return c == StringTraits::NullTerminator; - } - - static constexpr inline bool IsCurrentDirectory(const char *p) { - return p[0] == StringTraits::Dot && (IsSeparator(p[1]) || IsNullTerminator(p[1])); - } - - static constexpr inline bool IsParentDirectory(const char *p) { - return p[0] == StringTraits::Dot && p[1] == StringTraits::Dot && (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, bool has_mount_name = false); - static Result IsNormalized(bool *out, const char *path, bool unc_preserved = false, bool has_mount_name = false); - }; - -} diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_query_range.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_query_range.hpp index 026d98440..03b5d52f4 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_query_range.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_query_range.hpp @@ -38,7 +38,10 @@ namespace ams::fs { static_assert(util::is_pod::value); static_assert(sizeof(QueryRangeInfo) == 0x40); + + #if defined(ATMOSPHERE_OS_HORIZON) static_assert(sizeof(QueryRangeInfo) == sizeof(::FsRangeInfo)); + #endif using FileQueryRangeInfo = QueryRangeInfo; using StorageQueryRangeInfo = QueryRangeInfo; diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_read_only_filesystem.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_read_only_filesystem.hpp index 32fa79012..647ee0bcc 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_read_only_filesystem.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_read_only_filesystem.hpp @@ -30,7 +30,7 @@ namespace ams::fs { private: std::unique_ptr m_base_file; public: - explicit ReadOnlyFile(std::unique_ptr &&f) : m_base_file(std::move(f)) { /* ... */ } + explicit ReadOnlyFile(std::unique_ptr &&f) : m_base_file(std::move(f)) { AMS_ASSERT(m_base_file != nullptr); } virtual ~ReadOnlyFile() { /* ... */ } private: virtual Result DoRead(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) override final { @@ -46,12 +46,17 @@ namespace ams::fs { } virtual Result DoWrite(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) override final { - AMS_UNUSED(offset, buffer, size, option); + bool need_append; + R_TRY(this->DryWrite(std::addressof(need_append), offset, size, option, fs::OpenMode_Read)); + + AMS_ASSERT(!need_append); + + AMS_UNUSED(buffer); return fs::ResultUnsupportedOperationInReadOnlyFileA(); } virtual Result DoSetSize(s64 size) override final { - AMS_UNUSED(size); + R_TRY(this->DrySetSize(size, fs::OpenMode_Read)); return fs::ResultUnsupportedOperationInReadOnlyFileA(); } @@ -82,7 +87,7 @@ namespace ams::fs { explicit ReadOnlyFileSystemTemplate(T &&fs) : m_base_fs(std::move(fs)) { /* ... */ } virtual ~ReadOnlyFileSystemTemplate() { /* ... */ } private: - virtual Result DoOpenFile(std::unique_ptr *out_file, const char *path, OpenMode mode) override final { + virtual Result DoOpenFile(std::unique_ptr *out_file, const fs::Path &path, OpenMode mode) override final { /* Only allow opening files with mode = read. */ R_UNLESS((mode & fs::OpenMode_All) == fs::OpenMode_Read, fs::ResultInvalidOpenMode()); @@ -96,11 +101,11 @@ namespace ams::fs { return ResultSuccess(); } - virtual Result DoOpenDirectory(std::unique_ptr *out_dir, const char *path, OpenDirectoryMode mode) override final { + virtual Result DoOpenDirectory(std::unique_ptr *out_dir, const fs::Path &path, OpenDirectoryMode mode) override final { return m_base_fs->OpenDirectory(out_dir, path, mode); } - virtual Result DoGetEntryType(DirectoryEntryType *out, const char *path) override final { + virtual Result DoGetEntryType(DirectoryEntryType *out, const fs::Path &path) override final { return m_base_fs->GetEntryType(out, path); } @@ -108,52 +113,52 @@ namespace ams::fs { return ResultSuccess(); } - virtual Result DoCreateFile(const char *path, s64 size, int flags) override final { + virtual Result DoCreateFile(const fs::Path &path, s64 size, int flags) override final { AMS_UNUSED(path, size, flags); return fs::ResultUnsupportedOperationInReadOnlyFileSystemTemplateA(); } - virtual Result DoDeleteFile(const char *path) override final { + virtual Result DoDeleteFile(const fs::Path &path) override final { AMS_UNUSED(path); return fs::ResultUnsupportedOperationInReadOnlyFileSystemTemplateA(); } - virtual Result DoCreateDirectory(const char *path) override final { + virtual Result DoCreateDirectory(const fs::Path &path) override final { AMS_UNUSED(path); return fs::ResultUnsupportedOperationInReadOnlyFileSystemTemplateA(); } - virtual Result DoDeleteDirectory(const char *path) override final { + virtual Result DoDeleteDirectory(const fs::Path &path) override final { AMS_UNUSED(path); return fs::ResultUnsupportedOperationInReadOnlyFileSystemTemplateA(); } - virtual Result DoDeleteDirectoryRecursively(const char *path) override final { + virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) override final { AMS_UNUSED(path); return fs::ResultUnsupportedOperationInReadOnlyFileSystemTemplateA(); } - virtual Result DoRenameFile(const char *old_path, const char *new_path) override final { + virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) override final { AMS_UNUSED(old_path, new_path); return fs::ResultUnsupportedOperationInReadOnlyFileSystemTemplateA(); } - virtual Result DoRenameDirectory(const char *old_path, const char *new_path) override final { + virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) override final { AMS_UNUSED(old_path, new_path); return fs::ResultUnsupportedOperationInReadOnlyFileSystemTemplateA(); } - virtual Result DoCleanDirectoryRecursively(const char *path) override final { + virtual Result DoCleanDirectoryRecursively(const fs::Path &path) override final { AMS_UNUSED(path); return fs::ResultUnsupportedOperationInReadOnlyFileSystemTemplateA(); } - virtual Result DoGetFreeSpaceSize(s64 *out, const char *path) override final { + virtual Result DoGetFreeSpaceSize(s64 *out, const fs::Path &path) override final { AMS_UNUSED(out, path); return fs::ResultUnsupportedOperationInReadOnlyFileSystemTemplateB(); } - virtual Result DoGetTotalSpaceSize(s64 *out, const char *path) override final { + virtual Result DoGetTotalSpaceSize(s64 *out, const fs::Path &path) override final { AMS_UNUSED(out, path); return fs::ResultUnsupportedOperationInReadOnlyFileSystemTemplateB(); } diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_remote_filesystem.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_remote_filesystem.hpp index cb8c2cb91..83a4d36d4 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_remote_filesystem.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_remote_filesystem.hpp @@ -20,11 +20,13 @@ #include #include #include -#include namespace ams::fs { + #if defined(ATMOSPHERE_OS_HORIZON) class RemoteFile : public fsa::IFile, public impl::Newable { + NON_COPYABLE(RemoteFile); + NON_MOVEABLE(RemoteFile); private: ::FsFile m_base_file; public: @@ -67,6 +69,8 @@ namespace ams::fs { }; class RemoteDirectory : public fsa::IDirectory, public impl::Newable { + NON_COPYABLE(RemoteDirectory); + NON_MOVEABLE(RemoteDirectory); private: ::FsDir m_base_dir; public: @@ -75,7 +79,8 @@ namespace ams::fs { virtual ~RemoteDirectory() { fsDirClose(std::addressof(m_base_dir)); } public: virtual Result DoRead(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries) override final { - return fsDirRead(std::addressof(m_base_dir), out_count, max_entries, out_entries); + static_assert(sizeof(*out_entries) == sizeof(::FsDirectoryEntry)); + return fsDirRead(std::addressof(m_base_dir), out_count, max_entries, reinterpret_cast<::FsDirectoryEntry *>(out_entries)); } virtual Result DoGetEntryCount(s64 *out) override final { @@ -88,6 +93,8 @@ namespace ams::fs { }; class RemoteFileSystem : public fsa::IFileSystem, public impl::Newable { + NON_COPYABLE(RemoteFileSystem); + NON_MOVEABLE(RemoteFileSystem); private: ::FsFileSystem m_base_fs; public: @@ -95,52 +102,51 @@ namespace ams::fs { virtual ~RemoteFileSystem() { fsFsClose(std::addressof(m_base_fs)); } private: - Result GetPathForServiceObject(fssrv::sf::Path *out_path, const char *path) { - /* Copy and null terminate. */ - std::strncpy(out_path->str, path, sizeof(out_path->str) - 1); - out_path->str[sizeof(out_path->str) - 1] = '\x00'; + Result GetPathForServiceObject(fssrv::sf::Path *out_path, const fs::Path &path) { + /* Copy, ensuring length is in bounds. */ + const size_t len = util::Strlcpy(out_path->str, path.GetString(), sizeof(out_path->str)); + R_UNLESS(len < sizeof(out_path->str), fs::ResultTooLongPath()); /* Replace directory separators. */ - fs::Replace(out_path->str, sizeof(out_path->str) - 1, StringTraits::AlternateDirectorySeparator, StringTraits::DirectorySeparator); + /* TODO: Is this still necessary? We originally had it to not break things on low firmware. */ + #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) + fs::Replace(out_path->str, sizeof(out_path->str) - 1, '\\', '/'); + #endif - /* Get lengths. */ - const auto skip_len = fs::GetWindowsPathSkipLength(path); - const auto rel_path = out_path->str + skip_len; - const auto max_len = fs::EntryNameLengthMax - skip_len; - return VerifyPath(rel_path, max_len, max_len); + R_SUCCEED(); } public: - virtual Result DoCreateFile(const char *path, s64 size, int flags) override final { + virtual Result DoCreateFile(const fs::Path &path, s64 size, int flags) override final { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); return fsFsCreateFile(std::addressof(m_base_fs), sf_path.str, size, flags); } - virtual Result DoDeleteFile(const char *path) override final { + virtual Result DoDeleteFile(const fs::Path &path) override final { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); return fsFsDeleteFile(std::addressof(m_base_fs), sf_path.str); } - virtual Result DoCreateDirectory(const char *path) override final { + virtual Result DoCreateDirectory(const fs::Path &path) override final { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); return fsFsCreateDirectory(std::addressof(m_base_fs), sf_path.str); } - virtual Result DoDeleteDirectory(const char *path) override final { + virtual Result DoDeleteDirectory(const fs::Path &path) override final { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); return fsFsDeleteDirectory(std::addressof(m_base_fs), sf_path.str); } - virtual Result DoDeleteDirectoryRecursively(const char *path) override final { + virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) override final { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); return fsFsDeleteDirectoryRecursively(std::addressof(m_base_fs), sf_path.str); } - virtual Result DoRenameFile(const char *old_path, const char *new_path) override final { + virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) override final { fssrv::sf::Path old_sf_path; fssrv::sf::Path new_sf_path; R_TRY(GetPathForServiceObject(std::addressof(old_sf_path), old_path)); @@ -148,7 +154,7 @@ namespace ams::fs { return fsFsRenameFile(std::addressof(m_base_fs), old_sf_path.str, new_sf_path.str); } - virtual Result DoRenameDirectory(const char *old_path, const char *new_path) override final { + virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) override final { fssrv::sf::Path old_sf_path; fssrv::sf::Path new_sf_path; R_TRY(GetPathForServiceObject(std::addressof(old_sf_path), old_path)); @@ -156,7 +162,7 @@ namespace ams::fs { return fsFsRenameDirectory(std::addressof(m_base_fs), old_sf_path.str, new_sf_path.str); } - virtual Result DoGetEntryType(DirectoryEntryType *out, const char *path) override final { + virtual Result DoGetEntryType(DirectoryEntryType *out, const fs::Path &path) override final { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); @@ -164,7 +170,7 @@ namespace ams::fs { return fsFsGetEntryType(std::addressof(m_base_fs), sf_path.str, reinterpret_cast<::FsDirEntryType *>(out)); } - virtual Result DoOpenFile(std::unique_ptr *out_file, const char *path, OpenMode mode) override final { + virtual Result DoOpenFile(std::unique_ptr *out_file, const fs::Path &path, OpenMode mode) override final { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); @@ -178,7 +184,7 @@ namespace ams::fs { return ResultSuccess(); } - virtual Result DoOpenDirectory(std::unique_ptr *out_dir, const char *path, OpenDirectoryMode mode) override final { + virtual Result DoOpenDirectory(std::unique_ptr *out_dir, const fs::Path &path, OpenDirectoryMode mode) override final { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); @@ -196,37 +202,37 @@ namespace ams::fs { return fsFsCommit(std::addressof(m_base_fs)); } - - virtual Result DoGetFreeSpaceSize(s64 *out, const char *path) { + virtual Result DoGetFreeSpaceSize(s64 *out, const fs::Path &path) { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); return fsFsGetFreeSpace(std::addressof(m_base_fs), sf_path.str, out); } - virtual Result DoGetTotalSpaceSize(s64 *out, const char *path) { + virtual Result DoGetTotalSpaceSize(s64 *out, const fs::Path &path) { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); return fsFsGetTotalSpace(std::addressof(m_base_fs), sf_path.str, out); } - virtual Result DoCleanDirectoryRecursively(const char *path) { + virtual Result DoCleanDirectoryRecursively(const fs::Path &path) { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); return fsFsCleanDirectoryRecursively(std::addressof(m_base_fs), sf_path.str); } - virtual Result DoGetFileTimeStampRaw(FileTimeStampRaw *out, const char *path) { + virtual Result DoGetFileTimeStampRaw(FileTimeStampRaw *out, const fs::Path &path) { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); static_assert(sizeof(FileTimeStampRaw) == sizeof(::FsTimeStampRaw)); return fsFsGetFileTimeStampRaw(std::addressof(m_base_fs), sf_path.str, reinterpret_cast<::FsTimeStampRaw *>(out)); } - virtual Result DoQueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fsa::QueryId query, const char *path) { + virtual Result DoQueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fsa::QueryId query, const fs::Path &path) { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); return fsFsQueryEntry(std::addressof(m_base_fs), dst, dst_size, src, src_size, sf_path.str, static_cast(query)); } }; + #endif } diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_remote_storage.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_remote_storage.hpp index 949468983..7a9490f25 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_remote_storage.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_remote_storage.hpp @@ -20,35 +20,35 @@ namespace ams::fs { + #if defined(ATMOSPHERE_OS_HORIZON) class RemoteStorage : public IStorage, public impl::Newable { + NON_COPYABLE(RemoteStorage); + NON_MOVEABLE(RemoteStorage); private: - std::unique_ptr<::FsStorage, impl::Deleter> m_base_storage; + ::FsStorage m_base_storage; public: - RemoteStorage(::FsStorage &s) { - m_base_storage = impl::MakeUnique<::FsStorage>(); - *m_base_storage = s; - } + RemoteStorage(::FsStorage &s) : m_base_storage(s) { /* ... */} - virtual ~RemoteStorage() { fsStorageClose(m_base_storage.get()); } + virtual ~RemoteStorage() { fsStorageClose(std::addressof(m_base_storage)); } public: virtual Result Read(s64 offset, void *buffer, size_t size) override { - return fsStorageRead(m_base_storage.get(), offset, buffer, size); + return fsStorageRead(std::addressof(m_base_storage), offset, buffer, size); }; virtual Result Write(s64 offset, const void *buffer, size_t size) override { - return fsStorageWrite(m_base_storage.get(), offset, buffer, size); + return fsStorageWrite(std::addressof(m_base_storage), offset, buffer, size); }; virtual Result Flush() override { - return fsStorageFlush(m_base_storage.get()); + return fsStorageFlush(std::addressof(m_base_storage)); }; virtual Result GetSize(s64 *out_size) override { - return fsStorageGetSize(m_base_storage.get(), out_size); + return fsStorageGetSize(std::addressof(m_base_storage), out_size); }; virtual Result SetSize(s64 size) override { - return fsStorageSetSize(m_base_storage.get(), size); + return fsStorageSetSize(std::addressof(m_base_storage), 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 { @@ -57,5 +57,6 @@ namespace ams::fs { return fs::ResultUnsupportedOperation(); }; }; + #endif } diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_romfs_filesystem.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_romfs_filesystem.hpp index b64e06348..c68c3c387 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_romfs_filesystem.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_romfs_filesystem.hpp @@ -51,20 +51,20 @@ namespace ams::fs { RomFileTable *GetRomFileTable(); Result GetFileBaseOffset(s64 *out, const char *path); public: - virtual Result DoCreateFile(const char *path, s64 size, int flags) override; - virtual Result DoDeleteFile(const char *path) override; - virtual Result DoCreateDirectory(const char *path) override; - virtual Result DoDeleteDirectory(const char *path) override; - virtual Result DoDeleteDirectoryRecursively(const char *path) override; - virtual Result DoRenameFile(const char *old_path, const char *new_path) override; - virtual Result DoRenameDirectory(const char *old_path, const char *new_path) override; - virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const char *path) override; - virtual Result DoOpenFile(std::unique_ptr *out_file, const char *path, fs::OpenMode mode) override; - virtual Result DoOpenDirectory(std::unique_ptr *out_dir, const char *path, fs::OpenDirectoryMode mode) override; + virtual Result DoCreateFile(const fs::Path &path, s64 size, int flags) override; + virtual Result DoDeleteFile(const fs::Path &path) override; + virtual Result DoCreateDirectory(const fs::Path &path) override; + virtual Result DoDeleteDirectory(const fs::Path &path) override; + virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) override; + virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) override; + virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) override; + virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const fs::Path &path) override; + virtual Result DoOpenFile(std::unique_ptr *out_file, const fs::Path &path, fs::OpenMode mode) override; + virtual Result DoOpenDirectory(std::unique_ptr *out_dir, const fs::Path &path, fs::OpenDirectoryMode mode) override; virtual Result DoCommit() override; - virtual Result DoGetFreeSpaceSize(s64 *out, const char *path) override; - virtual Result DoGetTotalSpaceSize(s64 *out, const char *path) override; - virtual Result DoCleanDirectoryRecursively(const char *path) override; + virtual Result DoGetFreeSpaceSize(s64 *out, const fs::Path &path) override; + virtual Result DoGetTotalSpaceSize(s64 *out, const fs::Path &path) override; + virtual Result DoCleanDirectoryRecursively(const fs::Path &path) override; /* These aren't accessible as commands. */ virtual Result DoCommitProvisionally(s64 counter) override; diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_save_data_types.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_save_data_types.hpp index b2bad88d8..559b4ae71 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_save_data_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_save_data_types.hpp @@ -82,6 +82,20 @@ namespace ams::fs { SaveDataFlags_NeedsSecureDelete = (1 << 3), }; + enum class SaveDataMetaType : u8 { + None = 0, + Thumbnail = 1, + ExtensionContext = 2, + }; + + struct SaveDataMetaInfo { + u32 size; + SaveDataMetaType type; + u8 reserved[0xB]; + }; + static_assert(util::is_pod::value); + static_assert(sizeof(SaveDataMetaInfo) == 0x10); + struct SaveDataCreationInfo { s64 size; s64 journal_size; diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_sd_card.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_sd_card.hpp index 633a9ce21..780d10efa 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_sd_card.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_sd_card.hpp @@ -20,6 +20,12 @@ namespace ams::fs { class IEventNotifier; + struct EncryptionSeed { + char value[0x10]; + }; + static_assert(util::is_pod::value); + static_assert(sizeof(EncryptionSeed) == 0x10); + Result MountSdCard(const char *name); Result MountSdCardErrorReportDirectoryForAtmosphere(const char *name); diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_shared_filesystem_holder.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_shared_filesystem_holder.hpp index 058e7b310..04ce32dfd 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_shared_filesystem_holder.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_shared_filesystem_holder.hpp @@ -30,20 +30,20 @@ namespace ams::fs { public: SharedFileSystemHolder(std::shared_ptr f) : m_fs(std::move(f)) { /* ... */ } public: - virtual Result DoCreateFile(const char *path, s64 size, int flags) override { return m_fs->CreateFile(path, size, flags); } - virtual Result DoDeleteFile(const char *path) override { return m_fs->DeleteFile(path); } - virtual Result DoCreateDirectory(const char *path) override { return m_fs->CreateDirectory(path); } - virtual Result DoDeleteDirectory(const char *path) override { return m_fs->DeleteDirectory(path); } - virtual Result DoDeleteDirectoryRecursively(const char *path) override { return m_fs->DeleteDirectoryRecursively(path); } - virtual Result DoRenameFile(const char *old_path, const char *new_path) override { return m_fs->RenameFile(old_path, new_path); } - virtual Result DoRenameDirectory(const char *old_path, const char *new_path) override { return m_fs->RenameDirectory(old_path, new_path); } - virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const char *path) override { return m_fs->GetEntryType(out, path); } - virtual Result DoOpenFile(std::unique_ptr *out_file, const char *path, fs::OpenMode mode) override { return m_fs->OpenFile(out_file, path, mode); } - virtual Result DoOpenDirectory(std::unique_ptr *out_dir, const char *path, fs::OpenDirectoryMode mode) override { return m_fs->OpenDirectory(out_dir, path, mode); } + virtual Result DoCreateFile(const fs::Path &path, s64 size, int flags) override { return m_fs->CreateFile(path, size, flags); } + virtual Result DoDeleteFile(const fs::Path &path) override { return m_fs->DeleteFile(path); } + virtual Result DoCreateDirectory(const fs::Path &path) override { return m_fs->CreateDirectory(path); } + virtual Result DoDeleteDirectory(const fs::Path &path) override { return m_fs->DeleteDirectory(path); } + virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) override { return m_fs->DeleteDirectoryRecursively(path); } + virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) override { return m_fs->RenameFile(old_path, new_path); } + virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) override { return m_fs->RenameDirectory(old_path, new_path); } + virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const fs::Path &path) override { return m_fs->GetEntryType(out, path); } + virtual Result DoOpenFile(std::unique_ptr *out_file, const fs::Path &path, fs::OpenMode mode) override { return m_fs->OpenFile(out_file, path, mode); } + virtual Result DoOpenDirectory(std::unique_ptr *out_dir, const fs::Path &path, fs::OpenDirectoryMode mode) override { return m_fs->OpenDirectory(out_dir, path, mode); } virtual Result DoCommit() override { return m_fs->Commit(); } - virtual Result DoGetFreeSpaceSize(s64 *out, const char *path) override { return m_fs->GetFreeSpaceSize(out, path); } - virtual Result DoGetTotalSpaceSize(s64 *out, const char *path) override { return m_fs->GetTotalSpaceSize(out, path); } - virtual Result DoCleanDirectoryRecursively(const char *path) override { return m_fs->CleanDirectoryRecursively(path); } + virtual Result DoGetFreeSpaceSize(s64 *out, const fs::Path &path) override { return m_fs->GetFreeSpaceSize(out, path); } + virtual Result DoGetTotalSpaceSize(s64 *out, const fs::Path &path) override { return m_fs->GetTotalSpaceSize(out, path); } + virtual Result DoCleanDirectoryRecursively(const fs::Path &path) override { return m_fs->CleanDirectoryRecursively(path); } /* These aren't accessible as commands. */ virtual Result DoCommitProvisionally(s64 counter) override { return m_fs->CommitProvisionally(counter); } diff --git a/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_idirectory.hpp b/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_idirectory.hpp index d528f154d..f7b59a920 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_idirectory.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_idirectory.hpp @@ -31,13 +31,13 @@ namespace ams::fs::fsa { return ResultSuccess(); } R_UNLESS(out_entries != nullptr, fs::ResultNullptrArgument()); - R_UNLESS(max_entries > 0, fs::ResultInvalidArgument()); - return this->DoRead(out_count, out_entries, max_entries); + R_UNLESS(max_entries > 0, fs::ResultInvalidArgument()); + R_RETURN(this->DoRead(out_count, out_entries, max_entries)); } Result GetEntryCount(s64 *out) { R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); - return this->DoGetEntryCount(out); + R_RETURN(this->DoGetEntryCount(out)); } public: /* TODO: This is a hack to allow the mitm API to work. Find a better way? */ diff --git a/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_ifile.hpp b/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_ifile.hpp index fb9f1c58b..9ca61db0d 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_ifile.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_ifile.hpp @@ -26,58 +26,69 @@ namespace ams::fs::fsa { virtual ~IFile() { /* ... */ } Result Read(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) { + /* Check that we have an output pointer. */ R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); + + /* If we have nothing to read, just succeed. */ if (size == 0) { *out = 0; - return ResultSuccess(); + R_SUCCEED(); } - R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); - R_UNLESS(offset >= 0, fs::ResultOutOfRange()); + + /* Check that the read is valid. */ + R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); + R_UNLESS(offset >= 0, fs::ResultOutOfRange()); + R_UNLESS(util::IsIntValueRepresentable(size), 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->DoRead(out, offset, buffer, size, option); + + /* Do the read. */ + R_RETURN(this->DoRead(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); - } + ALWAYS_INLINE Result Read(size_t *out, s64 offset, void *buffer, size_t size) { R_RETURN(this->Read(out, offset, buffer, size, ReadOption::None)); } Result GetSize(s64 *out) { R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); - return this->DoGetSize(out); + R_RETURN(this->DoGetSize(out)); } Result Flush() { - return this->DoFlush(); + R_RETURN(this->DoFlush()); } Result Write(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) { + /* Handle the zero-size case. */ if (size == 0) { if (option.HasFlushFlag()) { R_TRY(this->Flush()); } - return ResultSuccess(); + R_SUCCEED(); } - R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); - R_UNLESS(offset >= 0, fs::ResultOutOfRange()); + + /* Check the write is valid. */ + R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); + R_UNLESS(offset >= 0, fs::ResultOutOfRange()); + R_UNLESS(util::IsIntValueRepresentable(size), 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->DoWrite(offset, buffer, size, option); + + R_RETURN(this->DoWrite(offset, buffer, size, option)); } Result SetSize(s64 size) { R_UNLESS(size >= 0, fs::ResultOutOfRange()); - return this->DoSetSize(size); + R_RETURN(this->DoSetSize(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->DoOperateRange(dst, dst_size, op_id, offset, size, src, src_size); + R_RETURN(this->DoOperateRange(dst, dst_size, op_id, offset, size, src, src_size)); } Result OperateRange(fs::OperationId op_id, s64 offset, s64 size) { - return this->DoOperateRange(nullptr, 0, op_id, offset, size, nullptr, 0); + R_RETURN(this->DoOperateRange(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? */ @@ -91,21 +102,19 @@ namespace ams::fs::fsa { /* Get the file size, and validate our offset. */ s64 file_size = 0; - R_TRY(this->GetSize(&file_size)); + R_TRY(this->DoGetSize(std::addressof(file_size))); R_UNLESS(offset <= file_size, fs::ResultOutOfRange()); *out = static_cast(std::min(file_size - offset, static_cast(size))); - return ResultSuccess(); + R_SUCCEED(); } Result DrySetSize(s64 size, fs::OpenMode open_mode) { - /* Check that we can write. */ - R_UNLESS((open_mode & OpenMode_Write) != 0, fs::ResultWriteNotPermitted()); - - AMS_ASSERT(size >= 0); AMS_UNUSED(size); - return ResultSuccess(); + /* Check that we can write. */ + R_UNLESS((open_mode & OpenMode_Write) != 0, fs::ResultWriteNotPermitted()); + R_SUCCEED(); } Result DryWrite(bool *out_append, s64 offset, size_t size, const fs::WriteOption &option, fs::OpenMode open_mode) { @@ -116,17 +125,16 @@ namespace ams::fs::fsa { /* Get the file size. */ s64 file_size = 0; - R_TRY(this->GetSize(&file_size)); + R_TRY(this->DoGetSize(&file_size)); /* Determine if we need to append. */ - if (file_size < offset + static_cast(size)) { + *out_append = false; + if (file_size < offset + static_cast(size)) { R_UNLESS((open_mode & OpenMode_AllowAppend) != 0, fs::ResultFileExtensionWithoutOpenModeAllowAppend()); *out_append = true; - } else { - *out_append = false; } - return ResultSuccess(); + R_SUCCEED(); } private: virtual Result DoRead(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) = 0; diff --git a/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_ifilesystem.hpp b/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_ifilesystem.hpp index fbf1ad690..ebc945efa 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_ifilesystem.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_ifilesystem.hpp @@ -18,6 +18,7 @@ #include #include #include +#include namespace ams::fs::fsa { @@ -26,172 +27,156 @@ namespace ams::fs::fsa { enum class QueryId { SetConcatenationFileAttribute = 0, + UpdateMac = 1, IsSignedSystemPartitionOnSdCardValid = 2, + QueryUnpreparedFileInformation = 3, }; 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->DoCreateFile(path, size, option); + Result CreateFile(const fs::Path &path, s64 size, int option) { + R_UNLESS(size >= 0, fs::ResultOutOfRange()); + R_RETURN(this->DoCreateFile(path, size, option)); } - Result CreateFile(const char *path, s64 size) { - return this->CreateFile(path, size, 0); + Result CreateFile(const fs::Path &path, s64 size) { + R_RETURN(this->CreateFile(path, size, fs::CreateOption_None)); } - Result DeleteFile(const char *path) { - R_UNLESS(path != nullptr, fs::ResultInvalidPath()); - return this->DoDeleteFile(path); + Result DeleteFile(const fs::Path &path) { + R_RETURN(this->DoDeleteFile(path)); } - Result CreateDirectory(const char *path) { - R_UNLESS(path != nullptr, fs::ResultInvalidPath()); - return this->DoCreateDirectory(path); + Result CreateDirectory(const fs::Path &path) { + R_RETURN(this->DoCreateDirectory(path)); } - Result DeleteDirectory(const char *path) { - R_UNLESS(path != nullptr, fs::ResultInvalidPath()); - return this->DoDeleteDirectory(path); + Result DeleteDirectory(const fs::Path &path) { + R_RETURN(this->DoDeleteDirectory(path)); } - Result DeleteDirectoryRecursively(const char *path) { - R_UNLESS(path != nullptr, fs::ResultInvalidPath()); - return this->DoDeleteDirectoryRecursively(path); + Result DeleteDirectoryRecursively(const fs::Path &path) { + R_RETURN(this->DoDeleteDirectoryRecursively(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->DoRenameFile(old_path, new_path); + Result RenameFile(const fs::Path &old_path, const fs::Path &new_path) { + R_RETURN(this->DoRenameFile(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->DoRenameDirectory(old_path, new_path); + Result RenameDirectory(const fs::Path &old_path, const fs::Path &new_path) { + R_RETURN(this->DoRenameDirectory(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->DoGetEntryType(out, path); + Result GetEntryType(DirectoryEntryType *out, const fs::Path &path) { + R_RETURN(this->DoGetEntryType(out, path)); } - Result OpenFile(std::unique_ptr *out_file, const char *path, OpenMode mode) { - R_UNLESS(path != nullptr, fs::ResultInvalidPath()); + Result OpenFile(std::unique_ptr *out_file, const fs::Path &path, OpenMode mode) { R_UNLESS(out_file != nullptr, fs::ResultNullptrArgument()); R_UNLESS((mode & OpenMode_ReadWrite) != 0, fs::ResultInvalidOpenMode()); R_UNLESS((mode & ~OpenMode_All) == 0, fs::ResultInvalidOpenMode()); - return this->DoOpenFile(out_file, path, mode); + R_RETURN(this->DoOpenFile(out_file, path, mode)); } - Result OpenDirectory(std::unique_ptr *out_dir, const char *path, OpenDirectoryMode mode) { - R_UNLESS(path != nullptr, fs::ResultInvalidPath()); + Result OpenDirectory(std::unique_ptr *out_dir, const fs::Path &path, OpenDirectoryMode mode) { R_UNLESS(out_dir != nullptr, fs::ResultNullptrArgument()); R_UNLESS((mode & OpenDirectoryMode_All) != 0, fs::ResultInvalidOpenMode()); R_UNLESS((mode & ~(OpenDirectoryMode_All | OpenDirectoryMode_NotRequireFileSize)) == 0, fs::ResultInvalidOpenMode()); - return this->DoOpenDirectory(out_dir, path, mode); + R_RETURN(this->DoOpenDirectory(out_dir, path, mode)); } Result Commit() { - return this->DoCommit(); + R_RETURN(this->DoCommit()); } - Result GetFreeSpaceSize(s64 *out, const char *path) { - R_UNLESS(path != nullptr, fs::ResultInvalidPath()); + Result GetFreeSpaceSize(s64 *out, const fs::Path &path) { R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); - return this->DoGetFreeSpaceSize(out, path); + R_RETURN(this->DoGetFreeSpaceSize(out, path)); } - Result GetTotalSpaceSize(s64 *out, const char *path) { - R_UNLESS(path != nullptr, fs::ResultInvalidPath()); + Result GetTotalSpaceSize(s64 *out, const fs::Path &path) { R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); - return this->DoGetTotalSpaceSize(out, path); + R_RETURN(this->DoGetTotalSpaceSize(out, path)); } - Result CleanDirectoryRecursively(const char *path) { - R_UNLESS(path != nullptr, fs::ResultInvalidPath()); - return this->DoCleanDirectoryRecursively(path); + Result CleanDirectoryRecursively(const fs::Path &path) { + R_RETURN(this->DoCleanDirectoryRecursively(path)); } - Result GetFileTimeStampRaw(FileTimeStampRaw *out, const char *path) { - R_UNLESS(path != nullptr, fs::ResultInvalidPath()); + Result GetFileTimeStampRaw(FileTimeStampRaw *out, const fs::Path &path) { R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); - return this->DoGetFileTimeStampRaw(out, path); + R_RETURN(this->DoGetFileTimeStampRaw(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->DoQueryEntry(dst, dst_size, src, src_size, query, path); + Result QueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, QueryId query, const fs::Path &path) { + R_RETURN(this->DoQueryEntry(dst, dst_size, src, src_size, query, path)); } /* These aren't accessible as commands. */ Result CommitProvisionally(s64 counter) { - return this->DoCommitProvisionally(counter); + R_RETURN(this->DoCommitProvisionally(counter)); } Result Rollback() { - return this->DoRollback(); + R_RETURN(this->DoRollback()); } Result Flush() { - return this->DoFlush(); + R_RETURN(this->DoFlush()); } protected: /* ...? */ private: - virtual Result DoCreateFile(const char *path, s64 size, int flags) = 0; - virtual Result DoDeleteFile(const char *path) = 0; - virtual Result DoCreateDirectory(const char *path) = 0; - virtual Result DoDeleteDirectory(const char *path) = 0; - virtual Result DoDeleteDirectoryRecursively(const char *path) = 0; - virtual Result DoRenameFile(const char *old_path, const char *new_path) = 0; - virtual Result DoRenameDirectory(const char *old_path, const char *new_path) = 0; - virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const char *path) = 0; - virtual Result DoOpenFile(std::unique_ptr *out_file, const char *path, fs::OpenMode mode) = 0; - virtual Result DoOpenDirectory(std::unique_ptr *out_dir, const char *path, fs::OpenDirectoryMode mode) = 0; + virtual Result DoCreateFile(const fs::Path &path, s64 size, int flags) = 0; + virtual Result DoDeleteFile(const fs::Path &path) = 0; + virtual Result DoCreateDirectory(const fs::Path &path) = 0; + virtual Result DoDeleteDirectory(const fs::Path &path) = 0; + virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) = 0; + virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) = 0; + virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) = 0; + virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const fs::Path &path) = 0; + virtual Result DoOpenFile(std::unique_ptr *out_file, const fs::Path &path, fs::OpenMode mode) = 0; + virtual Result DoOpenDirectory(std::unique_ptr *out_dir, const fs::Path &path, fs::OpenDirectoryMode mode) = 0; virtual Result DoCommit() = 0; - virtual Result DoGetFreeSpaceSize(s64 *out, const char *path) { + virtual Result DoGetFreeSpaceSize(s64 *out, const fs::Path &path) { AMS_UNUSED(out, path); - return fs::ResultNotImplemented(); + R_THROW(fs::ResultNotImplemented()); } - virtual Result DoGetTotalSpaceSize(s64 *out, const char *path) { + virtual Result DoGetTotalSpaceSize(s64 *out, const fs::Path &path) { AMS_UNUSED(out, path); - return fs::ResultNotImplemented(); + R_THROW(fs::ResultNotImplemented()); } - virtual Result DoCleanDirectoryRecursively(const char *path) = 0; + virtual Result DoCleanDirectoryRecursively(const fs::Path &path) = 0; - virtual Result DoGetFileTimeStampRaw(fs::FileTimeStampRaw *out, const char *path) { + virtual Result DoGetFileTimeStampRaw(fs::FileTimeStampRaw *out, const fs::Path &path) { AMS_UNUSED(out, path); - return fs::ResultNotImplemented(); + R_THROW(fs::ResultNotImplemented()); } - virtual Result DoQueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const char *path) { + virtual Result DoQueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const fs::Path &path) { AMS_UNUSED(dst, dst_size, src, src_size, query, path); - return fs::ResultNotImplemented(); + R_THROW(fs::ResultNotImplemented()); } /* These aren't accessible as commands. */ virtual Result DoCommitProvisionally(s64 counter) { AMS_UNUSED(counter); - return fs::ResultNotImplemented(); + R_THROW(fs::ResultNotImplemented()); } virtual Result DoRollback() { - return fs::ResultNotImplemented(); + R_THROW(fs::ResultNotImplemented()); } virtual Result DoFlush() { - return fs::ResultNotImplemented(); + R_THROW(fs::ResultNotImplemented()); } }; diff --git a/libraries/libstratosphere/include/stratosphere/fs/impl/fs_access_log_impl.hpp b/libraries/libstratosphere/include/stratosphere/fs/impl/fs_access_log_impl.hpp index ab48bb117..fe8de1c76 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/impl/fs_access_log_impl.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/impl/fs_access_log_impl.hpp @@ -83,6 +83,8 @@ namespace ams::fs::impl { } } + static_assert(sizeof(size_t) == sizeof(u64)); + } /* Access log result name. */ @@ -91,19 +93,41 @@ namespace ams::fs::impl { #define AMS_FS_IMPL_ACCESS_LOG_DEREFERENCE_OUT_VALUE(__VALUE__) ::ams::fs::impl::DereferenceOutValue(__VALUE__, AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME) /* Access log components. */ -#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_SIZE ", size: %" PRId64 "" -#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_READ_SIZE ", read_size: %zu" -#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_OFFSET_AND_SIZE ", offset: %" PRId64 ", size: %zu" -#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_THREAD_ID ", thread_id: %" PRIu64 "" -#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT ", name: \"%s\"" -#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_ENTRY_COUNT ", entry_count: %" PRId64 "" -#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_ENTRY_BUFFER_COUNT ", entry_buffer_count: %" PRId64 "" -#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_OPEN_MODE ", open_mode: 0x%" PRIX32 "" -#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH ", path: \"%s\"" -#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH_AND_SIZE ", path: \"%s\", size: %" PRId64 "" -#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH_AND_OPEN_MODE ", path: \"%s\", open_mode: 0x%" PRIX32 "" -#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_RENAME ", path: \"%s\", new_path: \"%s\"" -#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_DIRECTORY_ENTRY_TYPE ", entry_type: %s" +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_SIZE ", size: %" PRId64 "" +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_READ_SIZE ", read_size: %" PRIuZ "" +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_QUERY_SIZE ", read_size: %" PRIuZ "" +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_OFFSET_AND_SIZE ", offset: %" PRId64 ", size: %" PRIuZ "" +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_THREAD_ID ", thread_id: %" PRIu64 "" +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT ", name: \"%s\"" +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_ENTRY_COUNT ", entry_count: %" PRId64 "" +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_ENTRY_BUFFER_COUNT ", entry_buffer_count: %" PRId64 "" +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_OPEN_MODE ", open_mode: 0x%" PRIX32 "" +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH ", path: \"%s\"" +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH_AND_SIZE ", path: \"%s\", size: %" PRId64 "" +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH_AND_OPEN_MODE ", path: \"%s\", open_mode: 0x%" PRIX32 "" +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_RENAME ", path: \"%s\", new_path: \"%s\"" +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_DIRECTORY_ENTRY_TYPE ", entry_type: %s" +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_CONTENT_TYPE ", content_type: %s" +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_OPTION ", mount_host_option: %s" +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_ROOT_PATH ", root_path: %s" + +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_APPLICATION_ID ", applicationid: 0x%" PRIx64 "" +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_BIS_PARTITION_ID ", bispartitionid: %s" +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_CONTENT_STORAGE_ID ", contentstorageid: %s" +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_SYSTEM_DATA_ID ", systemdataid: 0x%" PRIx64 "" +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_DATA_ID ", dataid: 0x%" PRIx64 "" +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_GAME_CARD_HANDLE ", gamecard_handle: 0x%" PRIX32 "" +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_GAME_CARD_PARTITION ", gamecard_partition: %s" +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_IMAGE_DIRECTORY_ID ", imagedirectoryid: %s" +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_PROGRAM_ID ", programid: 0x%" PRIx64 "" +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_ID ", savedataid: 0x%" PRIx64 "" +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_SPACE_ID ", savedataspaceid: %s" +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_OWNER_ID ", save_data_owner_id: 0x%" PRIx64 "" +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_USER_ID ", userid: 0x%016" PRIx64 "%016" PRIx64 "" + +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_FLAGS ", save_data_flags: 0x%08" PRIX32 "" +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_JOURNAL_SIZE ", save_data_journal_size: %" PRId64 "" +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_SIZE ", save_data_size: %" PRId64 "" /* Access log formats. */ #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_NONE "" @@ -130,62 +154,135 @@ namespace ams::fs::impl { #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_GET_SPACE_SIZE(__OUT_SIZE__, __NAME__) \ AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_SIZE, __NAME__, AMS_FS_IMPL_ACCESS_LOG_DEREFERENCE_OUT_VALUE(__OUT_SIZE__) +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_APPLICATION_PACKAGE(__NAME__, __PATH__) \ + AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH, (__NAME__), (__PATH__) + +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_BIS(__NAME__, __ID__, __PATH__) \ + AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_BIS_PARTITION_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH, (__NAME__), ::ams::fs::impl::IdString().ToString(__ID__), (__PATH__) + +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CODE(__NAME__, __PATH__, __ID__) \ + AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH AMS_FS_IMPL_ACCESS_LOG_FORMAT_PROGRAM_ID, (__NAME__), (__PATH__), (__ID__).value + +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CONTENT_PATH(__NAME__, __PATH__, __TYPE__) \ + AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH AMS_FS_IMPL_ACCESS_LOG_FORMAT_CONTENT_TYPE, (__NAME__), (__PATH__), ::ams::fs::impl::IdString().ToString(__TYPE__) + +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CONTENT_PROGRAM_ID(__NAME__, __ID__, __TYPE__) \ + AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_PROGRAM_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_CONTENT_TYPE, (__NAME__), (__ID__), ::ams::fs::impl::IdString().ToString(__TYPE__) + +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CONTENT_PATH_AND_PROGRAM_ID(__NAME__, __PATH__, __ID__, __TYPE__) \ + AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH AMS_FS_IMPL_ACCESS_LOG_FORMAT_PROGRAM_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_CONTENT_TYPE, (__NAME__), (__PATH__), (__ID__).value, ::ams::fs::impl::IdString().ToString(__TYPE__) + +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CONTENT_PATH_AND_DATA_ID(__NAME__, __PATH__, __ID__, __TYPE__) \ + AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH AMS_FS_IMPL_ACCESS_LOG_FORMAT_DATA_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_CONTENT_TYPE, (__NAME__), (__PATH__), (__ID__).value, ::ams::fs::impl::IdString().ToString(__TYPE__) + +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CONTENT_STORAGE(__NAME__, __ID__) \ + AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_CONTENT_STORAGE_ID, (__NAME__), ::ams::fs::impl::IdString().ToString(__ID__) + +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_DEVICE_SAVE_DATA_APPLICATION_ID(__NAME__, __ID__) \ + AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_APPLICATION_ID, (__NAME__), (__ID__).value + +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_GAME_CARD_PARTITION(__NAME__, __GCHANDLE__, __PARTITION__) \ + AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_GAME_CARD_HANDLE AMS_FS_IMPL_ACCESS_LOG_FORMAT_GAME_CARD_PARTITION, (__NAME__), __GCHANDLE__, ::ams::fs::impl::IdString().ToString(__PARTITION__) + +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_ROOT() \ + AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT, (AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME) + +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_ROOT_WITH_OPTION(__OPTION__) \ + AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_OPTION, (AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME), ::ams::fs::impl::IdString().ToString(__OPTION__) + +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST(__NAME__, __ROOT_PATH__) \ + AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_ROOT_PATH, (__NAME__), (__ROOT_PATH__) + +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_WITH_OPTION(__NAME__, __ROOT_PATH__, __OPTION__) \ + AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_ROOT_PATH AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_OPTION, (__NAME__), (__ROOT_PATH__), ::ams::fs::impl::IdString().ToString(__OPTION__) + +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_IMAGE_DIRECTORY(__NAME__, __ID__) \ + AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_IMAGE_DIRECTORY_ID, (__NAME__), ::ams::fs::impl::IdString().ToString(__ID__) + +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_SYSTEM_DATA(__NAME__, __ID__) \ + AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_SYSTEM_DATA_ID, (__NAME__), (__ID__).value + +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_SYSTEM_SAVE_DATA(__NAME__, __SPACE__, __SAVE__, __USER__) \ + AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_SPACE_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_USER_ID, \ + (__NAME__), ::ams::fs::impl::IdString().ToString(__SPACE__), (__SAVE__), (__USER__).data[0], (__USER__).data[1] + +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_CREATE_SYSTEM_SAVE_DATA(__SPACE__, __SAVE__, __USER__, __OWNER__, __SIZE__, __JOURNAL_SIZE__, __FLAGS__) \ + AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_SPACE_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_USER_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_OWNER_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_SIZE AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_JOURNAL_SIZE AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_FLAGS, \ + ::ams::fs::impl::IdString().ToString(__SPACE__), (__SAVE__), (__USER__).data[0], (__USER__).data[1], (__OWNER__), (__SIZE__), (__JOURNAL_SIZE__), (__FLAGS__) + +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_DELETE_SAVE_DATA(__SPACE__, __SAVE__) \ + AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_SPACE_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_ID, \ + ::ams::fs::impl::IdString().ToString(__SPACE__), (__SAVE__) + +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_DELETE_SYSTEM_SAVE_DATA(__SPACE__, __SAVE__, __USER__) \ + AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_SPACE_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_USER_ID, \ + ::ams::fs::impl::IdString().ToString(__SPACE__), (__SAVE__), (__USER__).data[0], (__USER__).data[1] + +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_EXTEND_SAVE_DATA(__SPACE__, __SAVE__, __SIZE__, __JOURNAL_SIZE__) \ + AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_SPACE_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_SIZE AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_JOURNAL_SIZE, \ + ::ams::fs::impl::IdString().ToString(__SPACE__), (__SAVE__), (__SIZE__), (__JOURNAL_SIZE__) + +#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_QUERY_MOUNT_SYSTEM_DATA_CACHE_SIZE(__ID__, __SIZE__) \ + AMS_FS_IMPL_ACCESS_LOG_FORMAT_SYSTEM_DATA_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_QUERY_SIZE, (__ID__).value, AMS_FS_IMPL_ACCESS_LOG_DEREFERENCE_OUT_VALUE(__SIZE__) + /* Access log invocation lambdas. */ -#define AMS_FS_IMPL_ACCESS_LOG_IMPL(__EXPR__, __HANDLE__, __ENABLED__, __NAME__, ...) \ - [&](const char *name) -> Result { \ - if (!(__ENABLED__)) { \ - return (__EXPR__); \ - } else { \ - const ::ams::os::Tick start = ::ams::os::GetSystemTick(); \ - const auto AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME = (__EXPR__); \ - const ::ams::os::Tick end = ::ams::os::GetSystemTick(); \ - ::ams::fs::impl::OutputAccessLog(AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME, start, end, name, __HANDLE__, __VA_ARGS__); \ - return AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME; \ - } \ +#define AMS_FS_IMPL_ACCESS_LOG_IMPL(__EXPR__, __HANDLE__, __ENABLED__, __NAME__, ...) \ + [&](const char *__fs_func_name_) -> Result { \ + if (!(__ENABLED__)) { \ + R_RETURN(__EXPR__); \ + } else { \ + const ::ams::os::Tick __fs_start_tick = ::ams::os::GetSystemTick(); \ + const auto AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME = (__EXPR__); \ + const ::ams::os::Tick __fs_end_tick = ::ams::os::GetSystemTick(); \ + ::ams::fs::impl::OutputAccessLog(AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME, __fs_start_tick, __fs_end_tick, __fs_func_name_, __HANDLE__, __VA_ARGS__); \ + R_RETURN( AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME ); \ + } \ }(__NAME__) -#define AMS_FS_IMPL_ACCESS_LOG_WITH_PRIORITY_IMPL(__EXPR__, __PRIORITY__, __HANDLE__, __ENABLED__, __NAME__, ...) \ - [&](const char *name) -> Result { \ - if (!(__ENABLED__)) { \ - return (__EXPR__); \ - } else { \ - const ::ams::os::Tick start = ::ams::os::GetSystemTick(); \ - const auto AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME = (__EXPR__); \ - const ::ams::os::Tick end = ::ams::os::GetSystemTick(); \ - ::ams::fs::impl::OutputAccessLog(AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME, __PRIORITY__, start, end, name, __HANDLE__, __VA_ARGS__); \ - return AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME; \ - } \ +#define AMS_FS_IMPL_ACCESS_LOG_WITH_PRIORITY_IMPL(__EXPR__, __PRIORITY__, __HANDLE__, __ENABLED__, __NAME__, ...) \ + [&](const char *__fs_func_name_) -> Result { \ + if (!(__ENABLED__)) { \ + R_RETURN(__EXPR__); \ + } else { \ + const ::ams::os::Tick __fs_start_tick = ::ams::os::GetSystemTick(); \ + const auto AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME = (__EXPR__); \ + const ::ams::os::Tick __fs_end_tick = ::ams::os::GetSystemTick(); \ + ::ams::fs::impl::OutputAccessLog(AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME, __PRIORITY__, __fs_start_tick, __fs_end_tick, __fs_func_name_, __HANDLE__, __VA_ARGS__); \ + R_RETURN( AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME ); \ + } \ }(__NAME__) -#define AMS_FS_IMPL_ACCESS_LOG_EXPLICIT_IMPL(__RESULT__, __START__, __END__, __HANDLE__, __ENABLED__, __NAME__, ...) \ - [&](const char *name) -> Result { \ - if (!(__ENABLED__)) { \ - return __RESULT__; \ - } else { \ - const auto AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME = (__RESULT__); \ - ::ams::fs::impl::OutputAccessLog(AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME, __START__, __END__, name, __HANDLE__, __VA_ARGS__); \ - return AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME; \ - } \ +#define AMS_FS_IMPL_ACCESS_LOG_EXPLICIT_IMPL(__RESULT__, __START__, __END__, __HANDLE__, __ENABLED__, __NAME__, ...) \ + [&](const char *__fs_func_name_) -> Result { \ + if (!(__ENABLED__)) { \ + R_RETURN(__RESULT__); \ + } else { \ + const auto AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME = (__RESULT__); \ + ::ams::fs::impl::OutputAccessLog(AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME, __START__, __END__, __fs_func_name_, __HANDLE__, __VA_ARGS__); \ + R_RETURN( AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME ); \ + } \ }(__NAME__) -#define AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED_IMPL(__EXPR__, __ENABLED__, __NAME__, ...) \ - [&](const char *name) -> Result { \ - if (!(__ENABLED__)) { \ - return (__EXPR__); \ - } else { \ - const ::ams::os::Tick start = ::ams::os::GetSystemTick(); \ - const auto AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME = (__EXPR__); \ - const ::ams::os::Tick end = ::ams::os::GetSystemTick(); \ - ::ams::fs::impl::OutputAccessLogUnlessResultSuccess(AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME, start, end, name, nullptr, __VA_ARGS__); \ - return AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME; \ - } \ +#define AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED_IMPL(__EXPR__, __ENABLED__, __NAME__, ...) \ + [&](const char *__fs_func_name_) -> Result { \ + if (!(__ENABLED__)) { \ + R_RETURN(__EXPR__); \ + } else { \ + const ::ams::os::Tick __fs_start_tick = ::ams::os::GetSystemTick(); \ + const auto AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME = (__EXPR__); \ + const ::ams::os::Tick __fs_end_tick = ::ams::os::GetSystemTick(); \ + ::ams::fs::impl::OutputAccessLogUnlessResultSuccess(AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME, __fs_start_tick, __fs_end_tick, __fs_func_name_, nullptr, __VA_ARGS__); \ + R_RETURN( AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME ); \ + } \ }(__NAME__) - /* Access log api. */ #define AMS_FS_IMPL_ACCESS_LOG(__EXPR__, __HANDLE__, ...) \ AMS_FS_IMPL_ACCESS_LOG_IMPL((__EXPR__), __HANDLE__, ::ams::fs::impl::IsEnabledAccessLog() && ::ams::fs::impl::IsEnabledHandleAccessLog(__HANDLE__), AMS_CURRENT_FUNCTION_NAME, __VA_ARGS__) +#define AMS_FS_IMPL_ACCESS_LOG_SYSTEM(__EXPR__, __HANDLE__, ...) \ + AMS_FS_IMPL_ACCESS_LOG_IMPL((__EXPR__), __HANDLE__, ::ams::fs::impl::IsEnabledAccessLog(::ams::fs::impl::AccessLogTarget_System) && ::ams::fs::impl::IsEnabledHandleAccessLog(__HANDLE__), AMS_CURRENT_FUNCTION_NAME, __VA_ARGS__) + #define AMS_FS_IMPL_ACCESS_LOG_WITH_NAME(__EXPR__, __HANDLE__, __NAME__, ...) \ AMS_FS_IMPL_ACCESS_LOG_IMPL((__EXPR__), __HANDLE__, ::ams::fs::impl::IsEnabledAccessLog() && ::ams::fs::impl::IsEnabledHandleAccessLog(__HANDLE__), __NAME__, __VA_ARGS__) @@ -195,6 +292,37 @@ namespace ams::fs::impl { #define AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED(__EXPR__, ...) \ AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED_IMPL((__EXPR__), ::ams::fs::impl::IsEnabledAccessLog(), AMS_CURRENT_FUNCTION_NAME, __VA_ARGS__) +/* FS Accessor logging. */ +#define AMS_FS_IMPL_ACCESS_LOG_FS_ACCESSOR_ENABLE_IMPL(__NAME__, __ENABLED__) \ + do { \ + if (static_cast(__ENABLED__)) { \ + ::ams::fs::impl::EnableFileSystemAccessorAccessLog((__NAME__)); \ + } \ + } while (false) + +#define AMS_FS_IMPL_ACCESS_LOG_FS_ACCESSOR_ENABLE(__NAME__) \ + AMS_FS_IMPL_ACCESS_LOG_FS_ACCESSOR_ENABLE_IMPL((__NAME__), ::ams::fs::impl::IsEnabledAccessLog(::ams::fs::impl::AccessLogTarget_Application)) + +// DEBUG +#define AMS_FS_FORCE_ENABLE_SYSTEM_MOUNT_ACCESS_LOG + +/* System access log api. */ +#if defined(AMS_BUILD_FOR_DEBUGGING) || defined(AMS_BUILD_FOR_AUDITING) || defined(AMS_FS_FORCE_ENABLE_SYSTEM_MOUNT_ACCESS_LOG) + +#define AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(__EXPR__, __NAME__, ...) \ + AMS_FS_IMPL_ACCESS_LOG_IMPL((__EXPR__), nullptr, ::ams::fs::impl::IsEnabledAccessLog(::ams::fs::impl::AccessLogTarget_System), AMS_CURRENT_FUNCTION_NAME, __VA_ARGS__) + +#define AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(__NAME__) \ + AMS_FS_IMPL_ACCESS_LOG_FS_ACCESSOR_ENABLE_IMPL((__NAME__), ::ams::fs::impl::IsEnabledAccessLog(::ams::fs::impl::AccessLogTarget_System)) + +#else + +#define AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(__EXPR__, __NAME__, ...) (__EXPR__) + +#define AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(__NAME__) static_cast(0) + +#endif + /* Specific utilities. */ #define AMS_FS_IMPL_ACCESS_LOG_FILESYSTEM(__EXPR__, __HANDLE__, __FILESYSTEM__, ...) \ AMS_FS_IMPL_ACCESS_LOG_IMPL((__EXPR__), __HANDLE__, ::ams::fs::impl::IsEnabledAccessLog() && (__FILESYSTEM__)->IsEnabledAccessLog(), AMS_CURRENT_FUNCTION_NAME, __VA_ARGS__) @@ -202,5 +330,11 @@ namespace ams::fs::impl { #define AMS_FS_IMPL_ACCESS_LOG_FILESYSTEM_WITH_NAME(__EXPR__, __HANDLE__, __FILESYSTEM__, __NAME__, ...) \ AMS_FS_IMPL_ACCESS_LOG_IMPL((__EXPR__), __HANDLE__, ::ams::fs::impl::IsEnabledAccessLog() && (__FILESYSTEM__)->IsEnabledAccessLog(), __NAME__, __VA_ARGS__) +#define AMS_FS_IMPL_ACCESS_LOG_MOUNT(__EXPR__, __NAME__, ...) \ + AMS_FS_IMPL_ACCESS_LOG_IMPL((__EXPR__), nullptr, ::ams::fs::impl::IsEnabledAccessLog(::ams::fs::impl::AccessLogTarget_Application), AMS_CURRENT_FUNCTION_NAME, __VA_ARGS__) + +#define AMS_FS_IMPL_ACCESS_LOG_MOUNT_UNLESS_R_SUCCEEDED(__EXPR__, __NAME__, ...) \ + AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED_IMPL((__EXPR__), ::ams::fs::impl::IsEnabledAccessLog(::ams::fs::impl::AccessLogTarget_Application), AMS_CURRENT_FUNCTION_NAME, __VA_ARGS__) + #define AMS_FS_IMPL_ACCESS_LOG_UNMOUNT(__EXPR__, __MOUNT_NAME__, ...) \ AMS_FS_IMPL_ACCESS_LOG_IMPL((__EXPR__), nullptr, ::ams::fs::impl::IsEnabledAccessLog() && ::ams::fs::impl::IsEnabledFileSystemAccessorAccessLog(__MOUNT_NAME__), AMS_CURRENT_FUNCTION_NAME, __VA_ARGS__) diff --git a/libraries/libstratosphere/include/stratosphere/fs/impl/fs_common_mount_name.hpp b/libraries/libstratosphere/include/stratosphere/fs/impl/fs_common_mount_name.hpp index 6a0357775..37e12e750 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/impl/fs_common_mount_name.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/impl/fs_common_mount_name.hpp @@ -19,10 +19,17 @@ namespace ams::fs::impl { /* Delimiting of mount names. */ constexpr inline const char ReservedMountNamePrefixCharacter = '@'; - constexpr inline const char * const MountNameDelimiter = ":/"; + + #define AMS_FS_IMPL_MOUNT_NAME_DELIMITER ":/" + #define AMS_FS_IMPL_MOUNT_NAME_DELIMITER_LEN 2 + constexpr inline const char * const MountNameDelimiter = AMS_FS_IMPL_MOUNT_NAME_DELIMITER; /* Filesystem names. */ - constexpr inline const char * const HostRootFileSystemMountName = "@Host"; + #define AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME "@Host" + #define AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME_LEN 5 + + constexpr inline const char * const HostRootFileSystemMountName = AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME; + constexpr inline const char * const SdCardFileSystemMountName = "@Sdcard"; constexpr inline const char * const GameCardFileSystemMountName = "@Gc"; diff --git a/libraries/libstratosphere/include/stratosphere/fs/impl/fs_priority_utils.hpp b/libraries/libstratosphere/include/stratosphere/fs/impl/fs_priority_utils.hpp index 384160d91..b9a2f2553 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/impl/fs_priority_utils.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/impl/fs_priority_utils.hpp @@ -27,11 +27,13 @@ namespace ams::fs::impl { TlsIoPriority_Background = 3, }; + #if defined(ATMOSPHERE_OS_HORIZON) /* Ensure that TlsIo priority matches libnx priority. */ static_assert(TlsIoPriority_Normal == static_cast(::FsPriority_Normal)); static_assert(TlsIoPriority_Realtime == static_cast(::FsPriority_Realtime)); static_assert(TlsIoPriority_Low == static_cast(::FsPriority_Low)); static_assert(TlsIoPriority_Background == static_cast(::FsPriority_Background)); + #endif constexpr inline Result ConvertFsPriorityToTlsIoPriority(u8 *out, PriorityRaw priority) { AMS_ASSERT(out != nullptr); diff --git a/libraries/libstratosphere/include/stratosphere/fs/impl/fs_result_utils.hpp b/libraries/libstratosphere/include/stratosphere/fs/impl/fs_result_utils.hpp index e74e609e4..772c02e43 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/impl/fs_result_utils.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/impl/fs_result_utils.hpp @@ -55,7 +55,7 @@ namespace ams::fs::impl { ({ \ const ::ams::Result __tmp_fs_result = (__RESULT__); \ AMS_FS_R_CHECK_ABORT_IMPL(__tmp_fs_result, false); \ - return __tmp_fs_result; \ + R_THROW(__tmp_fs_result); \ }) #define AMS_FS_R_UNLESS(__EXPR__, __RESULT__) \ diff --git a/libraries/libstratosphere/include/stratosphere/fssrv.hpp b/libraries/libstratosphere/include/stratosphere/fssrv.hpp index 79fcd2bff..512e5aa48 100644 --- a/libraries/libstratosphere/include/stratosphere/fssrv.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssrv.hpp @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -28,8 +27,12 @@ #include #include #include +#include +#include +#include #include #include +#include #include #include -#include +#include diff --git a/libraries/libstratosphere/include/stratosphere/fssrv/fscreator/fssrv_local_file_system_creator.hpp b/libraries/libstratosphere/include/stratosphere/fssrv/fscreator/fssrv_local_file_system_creator.hpp new file mode 100644 index 000000000..6570f4e4b --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fssrv/fscreator/fssrv_local_file_system_creator.hpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 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 + +namespace ams::fssrv::fscreator { + + class LocalFileSystemCreator final : public ILocalFileSystemCreator { + NON_COPYABLE(LocalFileSystemCreator); + NON_MOVEABLE(LocalFileSystemCreator); + private: + bool m_is_development; + public: + explicit LocalFileSystemCreator(bool dev) : m_is_development(dev) { /* ... */ } + + virtual Result Create(std::shared_ptr *out, const fs::Path &path, bool case_sensitive, bool ensure_root, Result on_path_not_found) override; + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/fssrv/fscreator/fssrv_subdirectory_file_system_creator.hpp b/libraries/libstratosphere/include/stratosphere/fssrv/fscreator/fssrv_subdirectory_file_system_creator.hpp new file mode 100644 index 000000000..95a835738 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fssrv/fscreator/fssrv_subdirectory_file_system_creator.hpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 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 + +namespace ams::fssrv::fscreator { + + class SubDirectoryFileSystemCreator final : public ISubDirectoryFileSystemCreator { + NON_COPYABLE(SubDirectoryFileSystemCreator); + NON_MOVEABLE(SubDirectoryFileSystemCreator); + public: + explicit SubDirectoryFileSystemCreator() { /* ... */ } + + virtual Result Create(std::shared_ptr *out, std::shared_ptr base_fs, const fs::Path &path) override; + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_file_system_proxy_api.hpp b/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_file_system_proxy_api.hpp index 17a1a925d..8f01e3b8a 100644 --- a/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_file_system_proxy_api.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_file_system_proxy_api.hpp @@ -22,15 +22,43 @@ namespace ams::fssrv::fscreator { } -namespace ams::fssystem { +namespace ams::fssrv { - class IBufferManager; + class BaseStorageServiceImpl; + class BaseFileSystemServiceImpl; + class NcaFileSystemServiceImpl; + class SaveDataFileSystemServiceImpl; + class AccessFailureManagementServiceImpl; + class TimeServiceImpl; + class StatusReportServiceImpl; + class ProgramRegistryServiceImpl; + class AccessLogServiceImpl; + class DebugConfigurationServiceImpl; + + struct FileSystemProxyConfiguration { + fscreator::FileSystemCreatorInterfaces *m_fs_creator_interfaces; + BaseStorageServiceImpl *m_base_storage_service_impl; + BaseFileSystemServiceImpl *m_base_file_system_service_impl; + NcaFileSystemServiceImpl *m_nca_file_system_service_impl; + SaveDataFileSystemServiceImpl *m_save_data_file_system_service_impl; + AccessFailureManagementServiceImpl *m_access_failure_management_service_impl; + TimeServiceImpl *m_time_service_impl; + StatusReportServiceImpl *m_status_report_service_impl; + ProgramRegistryServiceImpl *m_program_registry_service_impl; + AccessLogServiceImpl *m_access_log_service_impl; + DebugConfigurationServiceImpl *m_debug_configuration_service_impl; + }; + + struct InternalProgramIdRangeForSpeedEmulation { + u64 program_id_value_min; + u64 program_id_value_max; + }; } namespace ams::fssrv { - void InitializeForFileSystemProxy(fscreator::FileSystemCreatorInterfaces *fs_creator_interfaces, fssystem::IBufferManager *buffer_manager, bool is_development_function_enabled); + void InitializeForFileSystemProxy(const FileSystemProxyConfiguration &config); void InitializeFileSystemProxyServer(int threads); diff --git a/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_file_system_proxy_impl.hpp b/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_file_system_proxy_impl.hpp index 58b1b0e79..9afa198a8 100644 --- a/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_file_system_proxy_impl.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_file_system_proxy_impl.hpp @@ -43,13 +43,106 @@ namespace ams::fssrv { ~FileSystemProxyImpl(); /* TODO */ - + public: + /* fsp-srv */ + Result OpenFileSystem(ams::sf::Out> out, const fssrv::sf::FspPath &path, u32 type); + Result SetCurrentProcess(const ams::sf::ClientProcessId &client_pid); + Result OpenDataFileSystemByCurrentProcess(ams::sf::Out> out); + Result OpenFileSystemWithPatch(ams::sf::Out> out, ncm::ProgramId program_id, u32 type); + Result OpenFileSystemWithId(ams::sf::Out> out, const fssrv::sf::FspPath &path, u64 program_id, u32 type); + Result OpenDataFileSystemByProgramId(ams::sf::Out> out, ncm::ProgramId program_id); + Result OpenBisFileSystem(ams::sf::Out> out, const fssrv::sf::FspPath &path, u32 id); + Result OpenBisStorage(ams::sf::Out> out, u32 id); + Result InvalidateBisCache(); + Result OpenHostFileSystem(ams::sf::Out> out, const fssrv::sf::FspPath &path); + Result OpenSdCardFileSystem(ams::sf::Out> out); + Result FormatSdCardFileSystem(); + Result DeleteSaveDataFileSystem(u64 save_data_id); + Result CreateSaveDataFileSystem(const fs::SaveDataAttribute &attribute, const fs::SaveDataCreationInfo &creation_info, const fs::SaveDataMetaInfo &meta_info); + Result CreateSaveDataFileSystemBySystemSaveDataId(const fs::SaveDataAttribute &attribute, const fs::SaveDataCreationInfo &creation_info); + Result RegisterSaveDataFileSystemAtomicDeletion(const ams::sf::InBuffer &save_data_ids); + Result DeleteSaveDataFileSystemBySaveDataSpaceId(u8 indexer_space_id, u64 save_data_id); + Result FormatSdCardDryRun(); + Result IsExFatSupported(ams::sf::Out out); + Result DeleteSaveDataFileSystemBySaveDataAttribute(u8 space_id, const fs::SaveDataAttribute &attribute); + Result OpenGameCardStorage(ams::sf::Out> out, u32 handle, u32 partition); + Result OpenGameCardFileSystem(ams::sf::Out> out, u32 handle, u32 partition); + Result ExtendSaveDataFileSystem(u8 space_id, u64 save_data_id, s64 available_size, s64 journal_size); + Result DeleteCacheStorage(u16 index); + Result GetCacheStorageSize(ams::sf::Out out_size, ams::sf::Out out_journal_size, u16 index); + Result CreateSaveDataFileSystemWithHashSalt(const fs::SaveDataAttribute &attribute, const fs::SaveDataCreationInfo &creation_info, const fs::SaveDataMetaInfo &meta_info, const fs::HashSalt &salt); + Result OpenHostFileSystemWithOption(ams::sf::Out> out, const fssrv::sf::FspPath &path, u32 option); + Result OpenSaveDataFileSystem(ams::sf::Out> out, u8 space_id, const fs::SaveDataAttribute &attribute); + Result OpenSaveDataFileSystemBySystemSaveDataId(ams::sf::Out> out, u8 space_id, const fs::SaveDataAttribute &attribute); + Result OpenReadOnlySaveDataFileSystem(ams::sf::Out> out, u8 space_id, const fs::SaveDataAttribute &attribute); + Result ReadSaveDataFileSystemExtraDataBySaveDataSpaceId(const ams::sf::OutBuffer &buffer, u8 space_id, u64 save_data_id); + Result ReadSaveDataFileSystemExtraData(const ams::sf::OutBuffer &buffer, u64 save_data_id); + Result WriteSaveDataFileSystemExtraData(u64 save_data_id, u8 space_id, const ams::sf::InBuffer &buffer); + /* ... */ + Result OpenImageDirectoryFileSystem(ams::sf::Out> out, u32 id); + /* ... */ + Result OpenContentStorageFileSystem(ams::sf::Out> out, u32 id); + /* ... */ + Result OpenDataStorageByCurrentProcess(ams::sf::Out> out); + Result OpenDataStorageByProgramId(ams::sf::Out> out, ncm::ProgramId program_id); + Result OpenDataStorageByDataId(ams::sf::Out> out, ncm::DataId data_id, u8 storage_id); + Result OpenPatchDataStorageByCurrentProcess(ams::sf::Out> out); + Result OpenDataFileSystemWithProgramIndex(ams::sf::Out> out, u8 index); + Result OpenDataStorageWithProgramIndex(ams::sf::Out> out, u8 index); + Result OpenDataStorageByPath(ams::sf::Out> out, const fssrv::sf::FspPath &path, u32 type); + Result OpenDeviceOperator(ams::sf::Out> out); + Result OpenSdCardDetectionEventNotifier(ams::sf::Out> out); + Result OpenGameCardDetectionEventNotifier(ams::sf::Out> out); + Result OpenSystemDataUpdateEventNotifier(ams::sf::Out> out); + Result NotifySystemDataUpdateEvent(); + /* ... */ + Result SetCurrentPosixTime(s64 posix_time); + /* ... */ + Result GetRightsId(ams::sf::Out out, ncm::ProgramId program_id, ncm::StorageId storage_id); + Result RegisterExternalKey(const fs::RightsId &rights_id, const spl::AccessKey &access_key); + Result UnregisterAllExternalKey(); + Result GetRightsIdByPath(ams::sf::Out out, const fssrv::sf::FspPath &path); + Result GetRightsIdAndKeyGenerationByPath(ams::sf::Out out, ams::sf::Out out_key_generation, const fssrv::sf::FspPath &path); + Result SetCurrentPosixTimeWithTimeDifference(s64 posix_time, s32 time_difference); + Result GetFreeSpaceSizeForSaveData(ams::sf::Out out, u8 space_id); + Result VerifySaveDataFileSystemBySaveDataSpaceId(); + Result CorruptSaveDataFileSystemBySaveDataSpaceId(); + Result QuerySaveDataInternalStorageTotalSize(); + Result GetSaveDataCommitId(); + Result UnregisterExternalKey(const fs::RightsId &rights_id); + Result SetSdCardEncryptionSeed(const fs::EncryptionSeed &seed); + Result SetSdCardAccessibility(bool accessible); + Result IsSdCardAccessible(ams::sf::Out out); + Result IsSignedSystemPartitionOnSdCardValid(ams::sf::Out out); + Result OpenAccessFailureDetectionEventNotifier(); + /* ... */ + Result RegisterProgramIndexMapInfo(const ams::sf::InBuffer &buffer, s32 count); + Result SetBisRootForHost(u32 id, const fssrv::sf::FspPath &path); + Result SetSaveDataSize(s64 size, s64 journal_size); + Result SetSaveDataRootPath(const fssrv::sf::FspPath &path); + Result DisableAutoSaveDataCreation(); + Result SetGlobalAccessLogMode(u32 mode); + Result GetGlobalAccessLogMode(ams::sf::Out out); + Result OutputAccessLogToSdCard(const ams::sf::InBuffer &buf); + Result RegisterUpdatePartition(); + Result OpenRegisteredUpdatePartition(ams::sf::Out> out); + /* ... */ + Result GetProgramIndexForAccessLog(ams::sf::Out out_idx, ams::sf::Out out_count); + Result GetFsStackUsage(ams::sf::Out out, u32 type); + Result UnsetSaveDataRootPath(); + Result OutputMultiProgramTagAccessLog(); + Result FlushAccessLogOnSdCard(); + Result OutputApplicationInfoAccessLog(); + Result RegisterDebugConfiguration(u32 key, s64 value); + Result UnregisterDebugConfiguration(u32 key); + Result OverrideSaveDataTransferTokenSignVerificationKey(const ams::sf::InBuffer &buf); + Result CorruptSaveDataFileSystemByOffset(u8 space_id, u64 save_data_id, s64 offset); + /* ... */ public: /* fsp-ldr */ Result OpenCodeFileSystemDeprecated(ams::sf::Out> out_fs, const fssrv::sf::Path &path, ncm::ProgramId program_id); Result OpenCodeFileSystem(ams::sf::Out> out_fs, ams::sf::Out out_verif, const fssrv::sf::Path &path, ncm::ProgramId program_id); Result IsArchivedProgram(ams::sf::Out out, u64 process_id); - Result SetCurrentProcess(const ams::sf::ClientProcessId &client_pid); }; static_assert(sf::IsIFileSystemProxy); static_assert(sf::IsIFileSystemProxyForLoader); diff --git a/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_i_file_system_creator.hpp b/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_i_file_system_creator.hpp index 88eb794fe..eccd74aa4 100644 --- a/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_i_file_system_creator.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_i_file_system_creator.hpp @@ -22,6 +22,8 @@ namespace ams::fs { class IStorage; enum class BisPartitionId; + class Path; + namespace fsa { class IFileSystem; @@ -67,7 +69,24 @@ namespace ams::fssrv::fscreator { virtual Result CreateNcaReader(std::shared_ptr *out, std::shared_ptr storage) = 0; }; + class ILocalFileSystemCreator { + public: + virtual Result Create(std::shared_ptr *out, const fs::Path &path, bool case_sensitive, bool ensure_root, Result on_path_not_found) = 0; + public: + Result Create(std::shared_ptr *out, const fs::Path &path, bool case_sensitive) { + R_RETURN(this->Create(out, path, case_sensitive, false, ResultSuccess())); + } + }; + + class ISubDirectoryFileSystemCreator { + public: + virtual Result Create(std::shared_ptr *out, std::shared_ptr base_fs, const fs::Path &path) = 0; + }; + struct FileSystemCreatorInterfaces { + ILocalFileSystemCreator *local_fs_creator; + ISubDirectoryFileSystemCreator *subdir_fs_creator; + /* TODO: These don't exist any more, and should be refactored out. */ IRomFileSystemCreator *rom_fs_creator; IPartitionFileSystemCreator *partition_fs_creator; IStorageOnNcaCreator *storage_on_nca_creator; diff --git a/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_memory_resource_from_standard_allocator.hpp b/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_memory_resource_from_standard_allocator.hpp index f80a2ccf6..5c1ac8acd 100644 --- a/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_memory_resource_from_standard_allocator.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_memory_resource_from_standard_allocator.hpp @@ -34,6 +34,7 @@ namespace ams::fssrv { size_t m_peak_allocated_size; public: explicit MemoryResourceFromStandardAllocator(mem::StandardAllocator *allocator); + constexpr virtual ~MemoryResourceFromStandardAllocator() = default; public: size_t GetPeakFreeSize() const { return m_peak_free_size; } size_t GetCurrentFreeSize() const { return m_current_free_size; } diff --git a/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_nca_file_system_service_impl.hpp b/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_nca_file_system_service_impl.hpp new file mode 100644 index 000000000..843faea15 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_nca_file_system_service_impl.hpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 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 +#include + +namespace ams::fssrv { + + class BaseFileSystemServiceImpl; + class ProgramRegistryServiceImpl; + class AccessFailureManagementServiceImpl; + + + namespace fscreator { + + class LocalFileSystemCreator; + class TargetManagerFileSystemCreator; + class PartitionFileSystemCreator; + class IRomFileSystemCreator; + class StorageOnNcaCreator; + class SubDirectoryFileSystemCreator; + class EncryptedFileSystemCreator; + class INspRootFileSystemCreator; + + } + + namespace impl { + + class UpdatePartitionPath; + class ExternalKeyManager; + class LocationResolverSet; + class SystemDataUpdateEventManager; + + } + + class NcaFileSystemServiceImpl { + public: + struct Configuration { + BaseFileSystemServiceImpl *base_fs_service; + fscreator::LocalFileSystemCreator *local_fs_creator; + fscreator::TargetManagerFileSystemCreator *tm_fs_creator; + fscreator::PartitionFileSystemCreator *partition_fs_creator; + fscreator::IRomFileSystemCreator *rom_fs_creator; + fscreator::StorageOnNcaCreator *storage_on_nca_creator; + fscreator::SubDirectoryFileSystemCreator *subdir_fs_creator; + fscreator::EncryptedFileSystemCreator *encrypted_fs_creator; + fscreator::INspRootFileSystemCreator *nsp_root_fs_creator; + ProgramRegistryServiceImpl *program_registry_service; + AccessFailureManagementServiceImpl *access_failure_management_service; + InternalProgramIdRangeForSpeedEmulation program_id_range_for_speed_emulation; + }; + private: + struct MountInfo { + bool is_game_card; + u32 gc_handle; + bool is_host_fs; + bool can_mount_nca; + }; + private: + Configuration m_config; + fssystem::Pimpl m_update_partition_path; + fssystem::Pimpl m_external_key_manager; + fssystem::Pimpl m_location_resolver_set; + fssystem::Pimpl m_system_data_update_event_manager; + fs::EncryptionSeed m_encryption_seed; + int m_romfs_remount_for_data_corruption_count; + int m_romfs_unrecoverable_data_corruption_by_remount_count; + int m_romfs_recovered_by_invalidate_cache_count; + os::SdkMutex m_romfs_count_mutex; + public: + NcaFileSystemServiceImpl(const Configuration &cfg) : m_config(cfg) { /* ... */ } + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_path_normalizer.hpp b/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_path_normalizer.hpp deleted file mode 100644 index d206f5b22..000000000 --- a/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_path_normalizer.hpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 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::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 m_buffer; - const char *m_path; - Result m_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: - /* TODO: Remove non-option constructor. */ - explicit PathNormalizer(const char *p) : m_buffer(), m_path(nullptr), m_result(ResultSuccess()) { - m_result = Normalize(std::addressof(m_path), std::addressof(m_buffer), p, false, false, false); - } - - PathNormalizer(const char *p, u32 option) : m_buffer(), m_path(nullptr), m_result(ResultSuccess()) { - if ((option & Option_AcceptEmpty) && p[0] == '\x00') { - m_path = p; - } else { - const bool preserve_unc = (option & Option_PreserveUnc); - const bool preserve_tail_sep = (option & Option_PreserveTailSeparator); - const bool has_mount_name = (option & Option_HasMountName); - m_result = Normalize(std::addressof(m_path), std::addressof(m_buffer), p, preserve_unc, preserve_tail_sep, has_mount_name); - } - } - - Result GetResult() const { - return m_result; - } - - const char *GetPath() const { - return m_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 index ac4a06dda..5d0bc0aee 100644 --- 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 @@ -39,13 +39,13 @@ namespace ams::fssrv::impl { class FileInterfaceAdapter { NON_COPYABLE(FileInterfaceAdapter); + NON_MOVEABLE(FileInterfaceAdapter); private: ams::sf::SharedPointer m_parent_filesystem; std::unique_ptr m_base_file; - util::unique_lock m_open_count_semaphore; + bool m_allow_all_operations; public: - FileInterfaceAdapter(std::unique_ptr &&file, FileSystemInterfaceAdapter *parent, util::unique_lock &&sema); - ~FileInterfaceAdapter(); + FileInterfaceAdapter(std::unique_ptr &&file, FileSystemInterfaceAdapter *parent, bool allow_all); private: void InvalidateCache(); public: @@ -62,13 +62,13 @@ namespace ams::fssrv::impl { class DirectoryInterfaceAdapter { NON_COPYABLE(DirectoryInterfaceAdapter); + NON_MOVEABLE(DirectoryInterfaceAdapter); private: ams::sf::SharedPointer m_parent_filesystem; std::unique_ptr m_base_dir; - util::unique_lock m_open_count_semaphore; + bool m_allow_all_operations; public: - DirectoryInterfaceAdapter(std::unique_ptr &&dir, FileSystemInterfaceAdapter *parent, util::unique_lock &&sema); - ~DirectoryInterfaceAdapter(); + DirectoryInterfaceAdapter(std::unique_ptr &&dir, FileSystemInterfaceAdapter *parent, bool allow_all); public: /* Command API */ Result Read(ams::sf::Out out, const ams::sf::OutBuffer &out_entries); @@ -78,22 +78,26 @@ namespace ams::fssrv::impl { class FileSystemInterfaceAdapter : public ams::sf::ISharedObject { NON_COPYABLE(FileSystemInterfaceAdapter); + NON_MOVEABLE(FileSystemInterfaceAdapter); private: std::shared_ptr m_base_fs; - util::unique_lock m_mount_count_semaphore; - os::ReaderWriterLock m_invalidation_lock; - bool m_open_count_limited; - bool m_deep_retry_enabled = false; + fs::PathFlags m_path_flags; + bool m_allow_all_operations; + bool m_is_mitm_interface; public: - FileSystemInterfaceAdapter(std::shared_ptr &&fs, bool open_limited); - /* TODO: Other constructors. */ + FileSystemInterfaceAdapter(std::shared_ptr &&fs, const fs::PathFlags &flags, bool allow_all, bool is_mitm_interface = false) + : m_base_fs(std::move(fs)), m_path_flags(flags), m_allow_all_operations(allow_all), m_is_mitm_interface(is_mitm_interface) + { + /* ... */ + } - ~FileSystemInterfaceAdapter(); - public: - bool IsDeepRetryEnabled() const; - bool IsAccessFailureDetectionObserved() const; - util::optional> AcquireCacheInvalidationReadLock(); - os::ReaderWriterLock &GetReaderWriterLockForCacheInvalidation(); + FileSystemInterfaceAdapter(std::shared_ptr &&fs, bool allow_all, bool is_mitm_interface = false) + : m_base_fs(std::move(fs)), m_path_flags(), m_allow_all_operations(allow_all), m_is_mitm_interface(is_mitm_interface) + { + /* ... */ + } + private: + Result SetUpPath(fs::Path *out, const fssrv::sf::Path &sf_path); public: /* Command API. */ Result CreateFile(const fssrv::sf::Path &path, s64 size, s32 option); @@ -116,4 +120,143 @@ namespace ams::fssrv::impl { Result QueryEntry(const ams::sf::OutBuffer &out_buf, const ams::sf::InBuffer &in_buf, s32 query_id, const fssrv::sf::Path &path); }; + #if defined(ATMOSPHERE_OS_HORIZON) + class RemoteFile { + NON_COPYABLE(RemoteFile); + NON_MOVEABLE(RemoteFile); + private: + ::FsFile m_base_file; + public: + RemoteFile(::FsFile &s) : m_base_file(s) { /* ... */} + + virtual ~RemoteFile() { fsFileClose(std::addressof(m_base_file)); } + public: + Result Read(ams::sf::Out out, s64 offset, const ams::sf::OutNonSecureBuffer &buffer, s64 size, fs::ReadOption option) { + return fsFileRead(std::addressof(m_base_file), offset, buffer.GetPointer(), size, option._value, reinterpret_cast(out.GetPointer())); + } + + Result Write(s64 offset, const ams::sf::InNonSecureBuffer &buffer, s64 size, fs::WriteOption option) { + return fsFileWrite(std::addressof(m_base_file), offset, buffer.GetPointer(), size, option._value); + } + + Result Flush(){ + return fsFileFlush(std::addressof(m_base_file)); + } + + Result SetSize(s64 size) { + return fsFileSetSize(std::addressof(m_base_file), size); + } + + Result GetSize(ams::sf::Out out) { + return fsFileGetSize(std::addressof(m_base_file), out.GetPointer()); + } + + Result OperateRange(ams::sf::Out out, s32 op_id, s64 offset, s64 size) { + static_assert(sizeof(::FsRangeInfo) == sizeof(fs::FileQueryRangeInfo)); + return fsFileOperateRange(std::addressof(m_base_file), static_cast<::FsOperationId>(op_id), offset, size, reinterpret_cast<::FsRangeInfo *>(out.GetPointer())); + } + + Result OperateRangeWithBuffer(const ams::sf::OutNonSecureBuffer &out_buf, const ams::sf::InNonSecureBuffer &in_buf, s32 op_id, s64 offset, s64 size) { + AMS_UNUSED(out_buf, in_buf, op_id, offset, size); + AMS_ABORT("TODO"); + } + }; + static_assert(fssrv::sf::IsIFile); + + class RemoteDirectory { + NON_COPYABLE(RemoteDirectory); + NON_MOVEABLE(RemoteDirectory); + private: + ::FsDir m_base_dir; + public: + RemoteDirectory(::FsDir &s) : m_base_dir(s) { /* ... */} + + virtual ~RemoteDirectory() { fsDirClose(std::addressof(m_base_dir)); } + public: + Result Read(ams::sf::Out out, const ams::sf::OutBuffer &out_entries) { + static_assert(sizeof(::FsDirectoryEntry) == sizeof(fs::DirectoryEntry)); + return fsDirRead(std::addressof(m_base_dir), out.GetPointer(), out_entries.GetSize() / sizeof(fs::DirectoryEntry), reinterpret_cast<::FsDirectoryEntry *>(out_entries.GetPointer())); + } + + Result GetEntryCount(ams::sf::Out out) { + return fsDirGetEntryCount(std::addressof(m_base_dir), out.GetPointer()); + } + }; + static_assert(fssrv::sf::IsIDirectory); + + class RemoteFileSystem { + NON_COPYABLE(RemoteFileSystem); + NON_MOVEABLE(RemoteFileSystem); + private: + ::FsFileSystem m_base_fs; + public: + RemoteFileSystem(::FsFileSystem &s) : m_base_fs(s) { /* ... */} + + virtual ~RemoteFileSystem() { fsFsClose(std::addressof(m_base_fs)); } + public: + /* Command API. */ + Result CreateFile(const fssrv::sf::Path &path, s64 size, s32 option) { + return fsFsCreateFile(std::addressof(m_base_fs), path.str, size, option); + } + + Result DeleteFile(const fssrv::sf::Path &path) { + return fsFsDeleteFile(std::addressof(m_base_fs), path.str); + } + + Result CreateDirectory(const fssrv::sf::Path &path) { + return fsFsCreateDirectory(std::addressof(m_base_fs), path.str); + } + + Result DeleteDirectory(const fssrv::sf::Path &path) { + return fsFsDeleteDirectory(std::addressof(m_base_fs), path.str); + } + + Result DeleteDirectoryRecursively(const fssrv::sf::Path &path) { + return fsFsDeleteDirectoryRecursively(std::addressof(m_base_fs), path.str); + } + + Result RenameFile(const fssrv::sf::Path &old_path, const fssrv::sf::Path &new_path) { + return fsFsRenameFile(std::addressof(m_base_fs), old_path.str, new_path.str); + } + + Result RenameDirectory(const fssrv::sf::Path &old_path, const fssrv::sf::Path &new_path) { + return fsFsRenameDirectory(std::addressof(m_base_fs), old_path.str, new_path.str); + } + + Result GetEntryType(ams::sf::Out out, const fssrv::sf::Path &path) { + static_assert(sizeof(::FsDirEntryType) == sizeof(u32)); + return fsFsGetEntryType(std::addressof(m_base_fs), path.str, reinterpret_cast<::FsDirEntryType *>(out.GetPointer())); + } + + Result Commit() { + return fsFsCommit(std::addressof(m_base_fs)); + } + + Result GetFreeSpaceSize(ams::sf::Out out, const fssrv::sf::Path &path) { + return fsFsGetFreeSpace(std::addressof(m_base_fs), path.str, out.GetPointer()); + } + + Result GetTotalSpaceSize(ams::sf::Out out, const fssrv::sf::Path &path) { + return fsFsGetTotalSpace(std::addressof(m_base_fs), path.str, out.GetPointer()); + } + + Result CleanDirectoryRecursively(const fssrv::sf::Path &path) { + return fsFsCleanDirectoryRecursively(std::addressof(m_base_fs), path.str); + } + + Result GetFileTimeStampRaw(ams::sf::Out out, const fssrv::sf::Path &path) { + static_assert(sizeof(fs::FileTimeStampRaw) == sizeof(::FsTimeStampRaw)); + return fsFsGetFileTimeStampRaw(std::addressof(m_base_fs), path.str, reinterpret_cast<::FsTimeStampRaw *>(out.GetPointer())); + } + + Result QueryEntry(const ams::sf::OutBuffer &out_buf, const ams::sf::InBuffer &in_buf, s32 query_id, const fssrv::sf::Path &path) { + return fsFsQueryEntry(std::addressof(m_base_fs), out_buf.GetPointer(), out_buf.GetSize(), in_buf.GetPointer(), in_buf.GetSize(), path.str, static_cast(query_id)); + } + + 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); + }; + static_assert(fssrv::sf::IsIFileSystem); + #endif + } 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 index dfe09a837..73e0d6b07 100644 --- 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 @@ -30,21 +30,9 @@ namespace ams::fssrv::impl { class StorageInterfaceAdapter { NON_COPYABLE(StorageInterfaceAdapter); private: - /* TODO: Nintendo uses fssystem::AsynchronousAccessStorage here. */ std::shared_ptr m_base_storage; - util::unique_lock m_open_count_semaphore; - os::ReaderWriterLock m_invalidation_lock; - /* TODO: DataStorageContext. */ - bool m_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: - util::optional> AcquireCacheInvalidationReadLock(); + explicit StorageInterfaceAdapter(std::shared_ptr &&storage) : m_base_storage(std::move(storage)) { /* ... */ } public: /* Command API. */ Result Read(s64 offset, const ams::sf::OutNonSecureBuffer &buffer, s64 size); @@ -56,4 +44,43 @@ namespace ams::fssrv::impl { }; static_assert(fssrv::sf::IsIStorage); + #if defined(ATMOSPHERE_OS_HORIZON) + class RemoteStorage { + NON_COPYABLE(RemoteStorage); + NON_MOVEABLE(RemoteStorage); + private: + ::FsStorage m_base_storage; + public: + RemoteStorage(::FsStorage &s) : m_base_storage(s) { /* ... */} + + virtual ~RemoteStorage() { fsStorageClose(std::addressof(m_base_storage)); } + public: + Result Read(s64 offset, const ams::sf::OutNonSecureBuffer &buffer, s64 size) { + return fsStorageRead(std::addressof(m_base_storage), offset, buffer.GetPointer(), size); + } + + Result Write(s64 offset, const ams::sf::InNonSecureBuffer &buffer, s64 size) { + return fsStorageWrite(std::addressof(m_base_storage), offset, buffer.GetPointer(), size); + } + + Result Flush(){ + return fsStorageFlush(std::addressof(m_base_storage)); + } + + Result SetSize(s64 size) { + return fsStorageSetSize(std::addressof(m_base_storage), size); + } + + Result GetSize(ams::sf::Out out) { + return fsStorageGetSize(std::addressof(m_base_storage), out.GetPointer()); + } + + Result OperateRange(ams::sf::Out out, s32 op_id, s64 offset, s64 size) { + static_assert(sizeof(::FsRangeInfo) == sizeof(fs::StorageQueryRangeInfo)); + return fsStorageOperateRange(std::addressof(m_base_storage), static_cast<::FsOperationId>(op_id), offset, size, reinterpret_cast<::FsRangeInfo *>(out.GetPointer())); + } + }; + static_assert(fssrv::sf::IsIStorage); + #endif + } diff --git a/libraries/libstratosphere/include/stratosphere/fssrv/sf/fssrv_sf_i_device_operator.hpp b/libraries/libstratosphere/include/stratosphere/fssrv/sf/fssrv_sf_i_device_operator.hpp new file mode 100644 index 000000000..05a7962d8 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fssrv/sf/fssrv_sf_i_device_operator.hpp @@ -0,0 +1,26 @@ +/* + * Copyright (c) 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 + +/* TODO */ +#define AMS_FSSRV_I_DEVICE_OPERATOR_INTERFACE_INFO(C, H) \ + AMS_SF_METHOD_INFO(C, H, 0, Result, IsSdCardInserted, (ams::sf::Out out), (out)) \ + AMS_SF_METHOD_INFO(C, H, 200, Result, IsGameCardInserted, (ams::sf::Out out), (out)) \ + AMS_SF_METHOD_INFO(C, H, 202, Result, GetGameCardHandle, (ams::sf::Out out), (out)) + +AMS_SF_DEFINE_INTERFACE(ams::fssrv::sf, IDeviceOperator, AMS_FSSRV_I_DEVICE_OPERATOR_INTERFACE_INFO) diff --git a/libraries/libstratosphere/include/stratosphere/fssrv/sf/fssrv_sf_i_file_system_proxy.hpp b/libraries/libstratosphere/include/stratosphere/fssrv/sf/fssrv_sf_i_file_system_proxy.hpp index 7d313a33c..d8e7e2a43 100644 --- a/libraries/libstratosphere/include/stratosphere/fssrv/sf/fssrv_sf_i_file_system_proxy.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssrv/sf/fssrv_sf_i_file_system_proxy.hpp @@ -17,130 +17,133 @@ #include #include #include +#include +#include +#include -#define AMS_FSSRV_I_FILE_SYSTEM_PROXY_INTERFACE_INFO(C, H) \ - /* AMS_SF_METHOD_INFO(C, H, 0, Result, OpenFileSystem, (TODO), (TODO), hos::Version_Min, hos::Version_1_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 1, Result, SetCurrentProcess, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 2, Result, OpenDataFileSystemByCurrentProcess, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 7, Result, OpenFileSystemWithPatch, (TODO), (TODO), hos::Version_2_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 8, Result, OpenFileSystemWithId, (TODO), (TODO), hos::Version_2_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 9, Result, OpenDataFileSystemByProgramId, (TODO), (TODO), hos::Version_3_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 11, Result, OpenBisFileSystem, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 12, Result, OpenBisStorage, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 13, Result, InvalidateBisCache, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 17, Result, OpenHostFileSystem, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 18, Result, OpenSdCardFileSystem, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 19, Result, FormatSdCardFileSystem, (TODO), (TODO), hos::Version_2_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 21, Result, DeleteSaveDataFileSystem, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 22, Result, CreateSaveDataFileSystem, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 23, Result, CreateSaveDataFileSystemBySystemSaveDataId, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 24, Result, RegisterSaveDataFileSystemAtomicDeletion, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 25, Result, DeleteSaveDataFileSystemBySaveDataSpaceId, (TODO), (TODO), hos::Version_2_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 26, Result, FormatSdCardDryRun, (TODO), (TODO), hos::Version_2_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 27, Result, IsExFatSupported, (TODO), (TODO), hos::Version_2_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 28, Result, DeleteSaveDataFileSystemBySaveDataAttribute, (TODO), (TODO), hos::Version_4_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 30, Result, OpenGameCardStorage, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 31, Result, OpenGameCardFileSystem, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 32, Result, ExtendSaveDataFileSystem, (TODO), (TODO), hos::Version_3_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 33, Result, DeleteCacheStorage, (TODO), (TODO), hos::Version_5_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 34, Result, GetCacheStorageSize, (TODO), (TODO), hos::Version_5_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 35, Result, CreateSaveDataFileSystemWithHashSalt, (TODO), (TODO), hos::Version_6_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 36, Result, OpenHostFileSystemWithOption, (TODO), (TODO), hos::Version_9_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 51, Result, OpenSaveDataFileSystem, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 52, Result, OpenSaveDataFileSystemBySystemSaveDataId, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 53, Result, OpenReadOnlySaveDataFileSystem, (TODO), (TODO), hos::Version_2_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 57, Result, ReadSaveDataFileSystemExtraDataBySaveDataSpaceId, (TODO), (TODO), hos::Version_3_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 58, Result, ReadSaveDataFileSystemExtraData, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 59, Result, WriteSaveDataFileSystemExtraData, (TODO), (TODO), hos::Version_2_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 60, Result, OpenSaveDataInfoReader, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 61, Result, OpenSaveDataInfoReaderBySaveDataSpaceId, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 62, Result, OpenSaveDataInfoReaderOnlyCacheStorage, (TODO), (TODO), hos::Version_5_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 64, Result, OpenSaveDataInternalStorageFileSystem, (TODO), (TODO), hos::Version_5_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 65, Result, UpdateSaveDataMacForDebug, (TODO), (TODO), hos::Version_5_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 66, Result, WriteSaveDataFileSystemExtraDataWithMask, (TODO), (TODO), hos::Version_5_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 67, Result, FindSaveDataWithFilter, (TODO), (TODO), hos::Version_6_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 68, Result, OpenSaveDataInfoReaderWithFilter, (TODO), (TODO), hos::Version_6_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 69, Result, ReadSaveDataFileSystemExtraDataBySaveDataAttribute, (TODO), (TODO), hos::Version_8_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 70, Result, WriteSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute, (TODO), (TODO), hos::Version_8_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 71, Result, ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute, (TODO), (TODO), hos::Version_10_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 80, Result, OpenSaveDataMetaFile, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 81, Result, OpenSaveDataTransferManager, (TODO), (TODO), hos::Version_4_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 82, Result, OpenSaveDataTransferManagerVersion2, (TODO), (TODO), hos::Version_5_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 83, Result, OpenSaveDataTransferProhibiter, (TODO), (TODO), hos::Version_6_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 84, Result, ListAccessibleSaveDataOwnerId, (TODO), (TODO), hos::Version_6_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 85, Result, OpenSaveDataTransferManagerForSaveDataRepair, (TODO), (TODO), hos::Version_9_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 86, Result, OpenSaveDataMover, (TODO), (TODO), hos::Version_10_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 87, Result, OpenSaveDataTransferManagerForRepair, (TODO), (TODO), hos::Version_11_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 100, Result, OpenImageDirectoryFileSystem, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 101, Result, OpenBaseFileSystem, (TODO), (TODO), hos::Version_11_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 102, Result, FormatBaseFileSystem, (TODO), (TODO), hos::Version_12_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 110, Result, OpenContentStorageFileSystem, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 120, Result, OpenCloudBackupWorkStorageFileSystem, (TODO), (TODO), hos::Version_6_0_0, hos::Version_9_2_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 130, Result, OpenCustomStorageFileSystem, (TODO), (TODO), hos::Version_7_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 200, Result, OpenDataStorageByCurrentProcess, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 201, Result, OpenDataStorageByProgramId, (TODO), (TODO), hos::Version_3_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 202, Result, OpenDataStorageByDataId, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 203, Result, OpenPatchDataStorageByCurrentProcess, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 204, Result, OpenDataFileSystemWithProgramIndex, (TODO), (TODO), hos::Version_7_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 205, Result, OpenDataStorageWithProgramIndex, (TODO), (TODO), hos::Version_7_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 206, Result, OpenDataStorageByPath, (TODO), (TODO), hos::Version_13_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 400, Result, OpenDeviceOperator, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 500, Result, OpenSdCardDetectionEventNotifier, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 501, Result, OpenGameCardDetectionEventNotifier, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 510, Result, OpenSystemDataUpdateEventNotifier, (TODO), (TODO), hos::Version_5_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 511, Result, NotifySystemDataUpdateEvent, (TODO), (TODO), hos::Version_5_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 520, Result, SimulateDeviceDetectionEvent, (TODO), (TODO), hos::Version_6_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 600, Result, SetCurrentPosixTime, (TODO), (TODO), hos::Version_Min, hos::Version_3_0_2) */ \ - /* AMS_SF_METHOD_INFO(C, H, 601, Result, QuerySaveDataTotalSize, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 602, Result, VerifySaveDataFileSystem, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 603, Result, CorruptSaveDataFileSystem, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 604, Result, CreatePaddingFile, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 605, Result, DeleteAllPaddingFiles, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 606, Result, GetRightsId, (TODO), (TODO), hos::Version_2_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 607, Result, RegisterExternalKey, (TODO), (TODO), hos::Version_2_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 608, Result, UnregisterAllExternalKey, (TODO), (TODO), hos::Version_2_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 609, Result, GetRightsIdByPath, (TODO), (TODO), hos::Version_2_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 610, Result, GetRightsIdAndKeyGenerationByPath, (TODO), (TODO), hos::Version_3_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 611, Result, SetCurrentPosixTimeWithTimeDifference, (TODO), (TODO), hos::Version_4_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 612, Result, GetFreeSpaceSizeForSaveData, (TODO), (TODO), hos::Version_4_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 613, Result, VerifySaveDataFileSystemBySaveDataSpaceId, (TODO), (TODO), hos::Version_4_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 614, Result, CorruptSaveDataFileSystemBySaveDataSpaceId, (TODO), (TODO), hos::Version_4_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 615, Result, QuerySaveDataInternalStorageTotalSize, (TODO), (TODO), hos::Version_5_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 616, Result, GetSaveDataCommitId, (TODO), (TODO), hos::Version_6_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 617, Result, UnregisterExternalKey, (TODO), (TODO), hos::Version_7_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 620, Result, SetSdCardEncryptionSeed, (TODO), (TODO), hos::Version_2_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 630, Result, SetSdCardAccessibility, (TODO), (TODO), hos::Version_4_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 631, Result, IsSdCardAccessible, (TODO), (TODO), hos::Version_4_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 640, Result, IsSignedSystemPartitionOnSdCardValid, (TODO), (TODO), hos::Version_4_0_0, hos::Version_7_0_1) */ \ - /* AMS_SF_METHOD_INFO(C, H, 700, Result, OpenAccessFailureDetectionEventNotifier, (TODO), (TODO), hos::Version_5_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 701, Result, GetAccessFailureDetectionEvent, (TODO), (TODO), hos::Version_5_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 702, Result, IsAccessFailureDetected, (TODO), (TODO), hos::Version_5_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 710, Result, ResolveAccessFailure, (TODO), (TODO), hos::Version_5_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 720, Result, AbandonAccessFailure, (TODO), (TODO), hos::Version_5_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 800, Result, GetAndClearErrorInfo, (TODO), (TODO), hos::Version_2_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 810, Result, RegisterProgramIndexMapInfo, (TODO), (TODO), hos::Version_7_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 1000, Result, SetBisRootForHost, (TODO), (TODO), hos::Version_Min, hos::Version_9_2_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 1001, Result, SetSaveDataSize, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 1002, Result, SetSaveDataRootPath, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 1003, Result, DisableAutoSaveDataCreation, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 1004, Result, SetGlobalAccessLogMode, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 1005, Result, GetGlobalAccessLogMode, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 1006, Result, OutputAccessLogToSdCard, (TODO), (TODO)) */ \ - /* AMS_SF_METHOD_INFO(C, H, 1007, Result, RegisterUpdatePartition, (TODO), (TODO), hos::Version_4_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 1008, Result, OpenRegisteredUpdatePartition, (TODO), (TODO), hos::Version_4_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 1009, Result, GetAndClearMemoryReportInfo, (TODO), (TODO), hos::Version_4_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 1010, Result, SetDataStorageRedirectTarget, (TODO), (TODO), hos::Version_5_1_0, hos::Version_6_2_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 1011, Result, GetProgramIndexForAccessLog, (TODO), (TODO), hos::Version_7_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 1012, Result, GetFsStackUsage, (TODO), (TODO), hos::Version_9_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 1013, Result, UnsetSaveDataRootPath, (TODO), (TODO), hos::Version_9_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 1014, Result, OutputMultiProgramTagAccessLog, (TODO), (TODO), hos::Version_10_0_0, hos::Version_10_2_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 1016, Result, FlushAccessLogOnSdCard, (TODO), (TODO), hos::Version_11_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 1017, Result, OutputApplicationInfoAccessLog, (TODO), (TODO), hos::Version_11_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 1018, Result, SetDebugOption, (TODO), (TODO), hos::Version_13_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 1019, Result, UnsetDebugOption, (TODO), (TODO), hos::Version_13_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 1100, Result, OverrideSaveDataTransferTokenSignVerificationKey, (TODO), (TODO), hos::Version_4_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 1110, Result, CorruptSaveDataFileSystemByOffset, (TODO), (TODO), hos::Version_6_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 1200, Result, OpenMultiCommitManager, (TODO), (TODO), hos::Version_6_0_0) */ \ - /* AMS_SF_METHOD_INFO(C, H, 1300, Result, OpenBisWiper, (TODO), (TODO), hos::Version_10_0_0) */ +#define AMS_FSSRV_I_FILE_SYSTEM_PROXY_INTERFACE_INFO(C, H) \ + AMS_SF_METHOD_INFO(C, H, 0, Result, OpenFileSystem, (ams::sf::Out> out, const fssrv::sf::FspPath &path, u32 type), (out, path, type), hos::Version_Min, hos::Version_1_0_0) \ + AMS_SF_METHOD_INFO(C, H, 1, Result, SetCurrentProcess, (const ams::sf::ClientProcessId &client_pid), (client_pid)) \ + AMS_SF_METHOD_INFO(C, H, 2, Result, OpenDataFileSystemByCurrentProcess, (ams::sf::Out> out), (out)) \ + AMS_SF_METHOD_INFO(C, H, 7, Result, OpenFileSystemWithPatch, (ams::sf::Out> out, ncm::ProgramId program_id, u32 type), (out, program_id, type), hos::Version_2_0_0) \ + AMS_SF_METHOD_INFO(C, H, 8, Result, OpenFileSystemWithId, (ams::sf::Out> out, const fssrv::sf::FspPath &path, u64 program_id, u32 type), (out, path, program_id, type), hos::Version_2_0_0) \ + AMS_SF_METHOD_INFO(C, H, 9, Result, OpenDataFileSystemByProgramId, (ams::sf::Out> out, ncm::ProgramId program_id), (out, program_id), hos::Version_3_0_0) \ + AMS_SF_METHOD_INFO(C, H, 11, Result, OpenBisFileSystem, (ams::sf::Out> out, const fssrv::sf::FspPath &path, u32 id), (out, path, id)) \ + AMS_SF_METHOD_INFO(C, H, 12, Result, OpenBisStorage, (ams::sf::Out> out, u32 id), (out, id)) \ + AMS_SF_METHOD_INFO(C, H, 13, Result, InvalidateBisCache, (), ()) \ + AMS_SF_METHOD_INFO(C, H, 17, Result, OpenHostFileSystem, (ams::sf::Out> out, const fssrv::sf::FspPath &path), (out, path)) \ + AMS_SF_METHOD_INFO(C, H, 18, Result, OpenSdCardFileSystem, (ams::sf::Out> out), (out)) \ + AMS_SF_METHOD_INFO(C, H, 19, Result, FormatSdCardFileSystem, (), (), hos::Version_2_0_0) \ + AMS_SF_METHOD_INFO(C, H, 21, Result, DeleteSaveDataFileSystem, (u64 save_data_id), (save_data_id)) \ + AMS_SF_METHOD_INFO(C, H, 22, Result, CreateSaveDataFileSystem, (const fs::SaveDataAttribute &attribute, const fs::SaveDataCreationInfo &creation_info, const fs::SaveDataMetaInfo &meta_info), (attribute, creation_info, meta_info)) \ + AMS_SF_METHOD_INFO(C, H, 23, Result, CreateSaveDataFileSystemBySystemSaveDataId, (const fs::SaveDataAttribute &attribute, const fs::SaveDataCreationInfo &creation_info), (attribute, creation_info)) \ + AMS_SF_METHOD_INFO(C, H, 24, Result, RegisterSaveDataFileSystemAtomicDeletion, (const ams::sf::InBuffer &save_data_ids), (save_data_ids)) \ + AMS_SF_METHOD_INFO(C, H, 25, Result, DeleteSaveDataFileSystemBySaveDataSpaceId, (u8 indexer_space_id, u64 save_data_id), (indexer_space_id, save_data_id), hos::Version_2_0_0) \ + AMS_SF_METHOD_INFO(C, H, 26, Result, FormatSdCardDryRun, (), (), hos::Version_2_0_0) \ + AMS_SF_METHOD_INFO(C, H, 27, Result, IsExFatSupported, (ams::sf::Out out), (out), hos::Version_2_0_0) \ + AMS_SF_METHOD_INFO(C, H, 28, Result, DeleteSaveDataFileSystemBySaveDataAttribute, (u8 space_id, const fs::SaveDataAttribute &attribute), (space_id, attribute), hos::Version_4_0_0) \ + AMS_SF_METHOD_INFO(C, H, 30, Result, OpenGameCardStorage, (ams::sf::Out> out, u32 handle, u32 partition), (out, handle, partition)) \ + AMS_SF_METHOD_INFO(C, H, 31, Result, OpenGameCardFileSystem, (ams::sf::Out> out, u32 handle, u32 partition), (out, handle, partition)) \ + AMS_SF_METHOD_INFO(C, H, 32, Result, ExtendSaveDataFileSystem, (u8 space_id, u64 save_data_id, s64 available_size, s64 journal_size), (space_id, save_data_id, available_size, journal_size), hos::Version_3_0_0) \ + AMS_SF_METHOD_INFO(C, H, 33, Result, DeleteCacheStorage, (u16 index), (index), hos::Version_5_0_0) \ + AMS_SF_METHOD_INFO(C, H, 34, Result, GetCacheStorageSize, (ams::sf::Out out_size, ams::sf::Out out_journal_size, u16 index), (out_size, out_journal_size, index), hos::Version_5_0_0) \ + AMS_SF_METHOD_INFO(C, H, 35, Result, CreateSaveDataFileSystemWithHashSalt, (const fs::SaveDataAttribute &attribute, const fs::SaveDataCreationInfo &creation_info, const fs::SaveDataMetaInfo &meta_info, const fs::HashSalt &salt), (attribute, creation_info, meta_info, salt), hos::Version_6_0_0) \ + AMS_SF_METHOD_INFO(C, H, 36, Result, OpenHostFileSystemWithOption, (ams::sf::Out> out, const fssrv::sf::FspPath &path, u32 option), (out, path, option), hos::Version_9_0_0) \ + AMS_SF_METHOD_INFO(C, H, 51, Result, OpenSaveDataFileSystem, (ams::sf::Out> out, u8 space_id, const fs::SaveDataAttribute &attribute), (out, space_id, attribute)) \ + AMS_SF_METHOD_INFO(C, H, 52, Result, OpenSaveDataFileSystemBySystemSaveDataId, (ams::sf::Out> out, u8 space_id, const fs::SaveDataAttribute &attribute), (out, space_id, attribute)) \ + AMS_SF_METHOD_INFO(C, H, 53, Result, OpenReadOnlySaveDataFileSystem, (ams::sf::Out> out, u8 space_id, const fs::SaveDataAttribute &attribute), (out, space_id, attribute), hos::Version_2_0_0) \ + AMS_SF_METHOD_INFO(C, H, 57, Result, ReadSaveDataFileSystemExtraDataBySaveDataSpaceId, (const ams::sf::OutBuffer &buffer, u8 space_id, u64 save_data_id), (buffer, space_id, save_data_id), hos::Version_3_0_0) \ + AMS_SF_METHOD_INFO(C, H, 58, Result, ReadSaveDataFileSystemExtraData, (const ams::sf::OutBuffer &buffer, u64 save_data_id), (buffer, save_data_id)) \ + AMS_SF_METHOD_INFO(C, H, 59, Result, WriteSaveDataFileSystemExtraData, (u64 save_data_id, u8 space_id, const ams::sf::InBuffer &buffer), (save_data_id, space_id, buffer), hos::Version_2_0_0) \ + /* AMS_SF_METHOD_INFO(C, H, 60, Result, OpenSaveDataInfoReader, (), ()) */ \ + /* AMS_SF_METHOD_INFO(C, H, 61, Result, OpenSaveDataInfoReaderBySaveDataSpaceId, (), ()) */ \ + /* AMS_SF_METHOD_INFO(C, H, 62, Result, OpenSaveDataInfoReaderOnlyCacheStorage, (), (), hos::Version_5_0_0) */ \ + /* AMS_SF_METHOD_INFO(C, H, 64, Result, OpenSaveDataInternalStorageFileSystem, (), (), hos::Version_5_0_0) */ \ + /* AMS_SF_METHOD_INFO(C, H, 65, Result, UpdateSaveDataMacForDebug, (), (), hos::Version_5_0_0) */ \ + /* AMS_SF_METHOD_INFO(C, H, 66, Result, WriteSaveDataFileSystemExtraDataWithMask, (), (), hos::Version_5_0_0) */ \ + /* AMS_SF_METHOD_INFO(C, H, 67, Result, FindSaveDataWithFilter, (), (), hos::Version_6_0_0) */ \ + /* AMS_SF_METHOD_INFO(C, H, 68, Result, OpenSaveDataInfoReaderWithFilter, (), (), hos::Version_6_0_0) */ \ + /* AMS_SF_METHOD_INFO(C, H, 69, Result, ReadSaveDataFileSystemExtraDataBySaveDataAttribute, (), (), hos::Version_8_0_0) */ \ + /* AMS_SF_METHOD_INFO(C, H, 70, Result, WriteSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute, (), (), hos::Version_8_0_0) */ \ + /* AMS_SF_METHOD_INFO(C, H, 71, Result, ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute, (), (), hos::Version_10_0_0) */ \ + /* AMS_SF_METHOD_INFO(C, H, 80, Result, OpenSaveDataMetaFile, (), ()) */ \ + /* AMS_SF_METHOD_INFO(C, H, 81, Result, OpenSaveDataTransferManager, (), (), hos::Version_4_0_0) */ \ + /* AMS_SF_METHOD_INFO(C, H, 82, Result, OpenSaveDataTransferManagerVersion2, (), (), hos::Version_5_0_0) */ \ + /* AMS_SF_METHOD_INFO(C, H, 83, Result, OpenSaveDataTransferProhibiter, (), (), hos::Version_6_0_0) */ \ + /* AMS_SF_METHOD_INFO(C, H, 84, Result, ListAccessibleSaveDataOwnerId, (), (), hos::Version_6_0_0) */ \ + /* AMS_SF_METHOD_INFO(C, H, 85, Result, OpenSaveDataTransferManagerForSaveDataRepair, (), (), hos::Version_9_0_0) */ \ + /* AMS_SF_METHOD_INFO(C, H, 86, Result, OpenSaveDataMover, (), (), hos::Version_10_0_0) */ \ + /* AMS_SF_METHOD_INFO(C, H, 87, Result, OpenSaveDataTransferManagerForRepair, (), (), hos::Version_11_0_0) */ \ + AMS_SF_METHOD_INFO(C, H, 100, Result, OpenImageDirectoryFileSystem, (ams::sf::Out> out, u32 id), (out, id)) \ + /* AMS_SF_METHOD_INFO(C, H, 101, Result, OpenBaseFileSystem, (), (), hos::Version_11_0_0) */ \ + /* AMS_SF_METHOD_INFO(C, H, 102, Result, FormatBaseFileSystem, (), (), hos::Version_12_0_0) */ \ + AMS_SF_METHOD_INFO(C, H, 110, Result, OpenContentStorageFileSystem, (ams::sf::Out> out, u32 id), (out, id)) \ + /* AMS_SF_METHOD_INFO(C, H, 120, Result, OpenCloudBackupWorkStorageFileSystem, (), (), hos::Version_6_0_0, hos::Version_9_2_0) */ \ + /* AMS_SF_METHOD_INFO(C, H, 130, Result, OpenCustomStorageFileSystem, (), (), hos::Version_7_0_0) */ \ + AMS_SF_METHOD_INFO(C, H, 200, Result, OpenDataStorageByCurrentProcess, (ams::sf::Out> out), (out)) \ + AMS_SF_METHOD_INFO(C, H, 201, Result, OpenDataStorageByProgramId, (ams::sf::Out> out, ncm::ProgramId program_id), (out, program_id), hos::Version_3_0_0) \ + AMS_SF_METHOD_INFO(C, H, 202, Result, OpenDataStorageByDataId, (ams::sf::Out> out, ncm::DataId data_id, u8 storage_id), (out, data_id, storage_id)) \ + AMS_SF_METHOD_INFO(C, H, 203, Result, OpenPatchDataStorageByCurrentProcess, (ams::sf::Out> out), (out)) \ + AMS_SF_METHOD_INFO(C, H, 204, Result, OpenDataFileSystemWithProgramIndex, (ams::sf::Out> out, u8 index), (out, index), hos::Version_7_0_0) \ + AMS_SF_METHOD_INFO(C, H, 205, Result, OpenDataStorageWithProgramIndex, (ams::sf::Out> out, u8 index), (out, index), hos::Version_7_0_0) \ + AMS_SF_METHOD_INFO(C, H, 206, Result, OpenDataStorageByPath, (ams::sf::Out> out, const fssrv::sf::FspPath &path, u32 type), (out, path, type), hos::Version_13_0_0) \ + AMS_SF_METHOD_INFO(C, H, 400, Result, OpenDeviceOperator, (ams::sf::Out> out), (out)) \ + AMS_SF_METHOD_INFO(C, H, 500, Result, OpenSdCardDetectionEventNotifier, (ams::sf::Out> out), (out)) \ + AMS_SF_METHOD_INFO(C, H, 501, Result, OpenGameCardDetectionEventNotifier, (ams::sf::Out> out), (out)) \ + AMS_SF_METHOD_INFO(C, H, 510, Result, OpenSystemDataUpdateEventNotifier, (ams::sf::Out> out), (out), hos::Version_5_0_0) \ + AMS_SF_METHOD_INFO(C, H, 511, Result, NotifySystemDataUpdateEvent, (), (), hos::Version_5_0_0) \ + /* AMS_SF_METHOD_INFO(C, H, 520, Result, SimulateDeviceDetectionEvent, (), (), hos::Version_6_0_0) */ \ + AMS_SF_METHOD_INFO(C, H, 600, Result, SetCurrentPosixTime, (s64 posix_time), (posix_time), hos::Version_Min, hos::Version_3_0_2) \ + /* AMS_SF_METHOD_INFO(C, H, 601, Result, QuerySaveDataTotalSize, (), ()) */ \ + /* AMS_SF_METHOD_INFO(C, H, 602, Result, VerifySaveDataFileSystem, (), ()) */ \ + /* AMS_SF_METHOD_INFO(C, H, 603, Result, CorruptSaveDataFileSystem, (), ()) */ \ + /* AMS_SF_METHOD_INFO(C, H, 604, Result, CreatePaddingFile, (), ()) */ \ + /* AMS_SF_METHOD_INFO(C, H, 605, Result, DeleteAllPaddingFiles, (), ()) */ \ + AMS_SF_METHOD_INFO(C, H, 606, Result, GetRightsId, (ams::sf::Out out, ncm::ProgramId program_id, ncm::StorageId storage_id), (out, program_id, storage_id), hos::Version_2_0_0) \ + AMS_SF_METHOD_INFO(C, H, 607, Result, RegisterExternalKey, (const fs::RightsId &rights_id, const spl::AccessKey &access_key), (rights_id, access_key), hos::Version_2_0_0) \ + AMS_SF_METHOD_INFO(C, H, 608, Result, UnregisterAllExternalKey, (), (), hos::Version_2_0_0) \ + AMS_SF_METHOD_INFO(C, H, 609, Result, GetRightsIdByPath, (ams::sf::Out out, const fssrv::sf::FspPath &path), (out, path), hos::Version_2_0_0) \ + AMS_SF_METHOD_INFO(C, H, 610, Result, GetRightsIdAndKeyGenerationByPath, (ams::sf::Out out, ams::sf::Out out_key_generation, const fssrv::sf::FspPath &path), (out, out_key_generation, path), hos::Version_3_0_0) \ + AMS_SF_METHOD_INFO(C, H, 611, Result, SetCurrentPosixTimeWithTimeDifference, (s64 posix_time, s32 time_difference), (posix_time, time_difference), hos::Version_4_0_0) \ + AMS_SF_METHOD_INFO(C, H, 612, Result, GetFreeSpaceSizeForSaveData, (ams::sf::Out out, u8 space_id), (out, space_id), hos::Version_4_0_0) \ + AMS_SF_METHOD_INFO(C, H, 613, Result, VerifySaveDataFileSystemBySaveDataSpaceId, (), (), hos::Version_4_0_0) \ + AMS_SF_METHOD_INFO(C, H, 614, Result, CorruptSaveDataFileSystemBySaveDataSpaceId, (), (), hos::Version_4_0_0) \ + AMS_SF_METHOD_INFO(C, H, 615, Result, QuerySaveDataInternalStorageTotalSize, (), (), hos::Version_5_0_0) \ + AMS_SF_METHOD_INFO(C, H, 616, Result, GetSaveDataCommitId, (), (), hos::Version_6_0_0) \ + AMS_SF_METHOD_INFO(C, H, 617, Result, UnregisterExternalKey, (const fs::RightsId &rights_id), (rights_id), hos::Version_7_0_0) \ + AMS_SF_METHOD_INFO(C, H, 620, Result, SetSdCardEncryptionSeed, (const fs::EncryptionSeed &seed), (seed), hos::Version_2_0_0) \ + AMS_SF_METHOD_INFO(C, H, 630, Result, SetSdCardAccessibility, (bool accessible), (accessible), hos::Version_4_0_0) \ + AMS_SF_METHOD_INFO(C, H, 631, Result, IsSdCardAccessible, (ams::sf::Out out), (out), hos::Version_4_0_0) \ + AMS_SF_METHOD_INFO(C, H, 640, Result, IsSignedSystemPartitionOnSdCardValid, (ams::sf::Out out), (out), hos::Version_4_0_0, hos::Version_7_0_1) \ + AMS_SF_METHOD_INFO(C, H, 700, Result, OpenAccessFailureDetectionEventNotifier, (), (), hos::Version_5_0_0) \ + /* AMS_SF_METHOD_INFO(C, H, 701, Result, GetAccessFailureDetectionEvent, (), (), hos::Version_5_0_0) */ \ + /* AMS_SF_METHOD_INFO(C, H, 702, Result, IsAccessFailureDetected, (), (), hos::Version_5_0_0) */ \ + /* AMS_SF_METHOD_INFO(C, H, 710, Result, ResolveAccessFailure, (), (), hos::Version_5_0_0) */ \ + /* AMS_SF_METHOD_INFO(C, H, 720, Result, AbandonAccessFailure, (), (), hos::Version_5_0_0) */ \ + /* AMS_SF_METHOD_INFO(C, H, 800, Result, GetAndClearErrorInfo, (), (), hos::Version_2_0_0) */ \ + AMS_SF_METHOD_INFO(C, H, 810, Result, RegisterProgramIndexMapInfo, (const ams::sf::InBuffer &buffer, s32 count), (buffer, count), hos::Version_7_0_0) \ + AMS_SF_METHOD_INFO(C, H, 1000, Result, SetBisRootForHost, (u32 id, const fssrv::sf::FspPath &path), (id, path), hos::Version_Min, hos::Version_9_2_0) \ + AMS_SF_METHOD_INFO(C, H, 1001, Result, SetSaveDataSize, (s64 size, s64 journal_size), (size, journal_size)) \ + AMS_SF_METHOD_INFO(C, H, 1002, Result, SetSaveDataRootPath, (const fssrv::sf::FspPath &path), (path)) \ + AMS_SF_METHOD_INFO(C, H, 1003, Result, DisableAutoSaveDataCreation, (), ()) \ + AMS_SF_METHOD_INFO(C, H, 1004, Result, SetGlobalAccessLogMode, (u32 mode), (mode)) \ + AMS_SF_METHOD_INFO(C, H, 1005, Result, GetGlobalAccessLogMode, (ams::sf::Out out), (out)) \ + AMS_SF_METHOD_INFO(C, H, 1006, Result, OutputAccessLogToSdCard, (const ams::sf::InBuffer &buf), (buf)) \ + AMS_SF_METHOD_INFO(C, H, 1007, Result, RegisterUpdatePartition, (), (), hos::Version_4_0_0) \ + AMS_SF_METHOD_INFO(C, H, 1008, Result, OpenRegisteredUpdatePartition, (ams::sf::Out> out), (out), hos::Version_4_0_0) \ + /* AMS_SF_METHOD_INFO(C, H, 1009, Result, GetAndClearMemoryReportInfo, (ams::sf::Out out), (out), hos::Version_4_0_0) */ \ + /* AMS_SF_METHOD_INFO(C, H, 1010, Result, SetDataStorageRedirectTarget, (), (), hos::Version_5_1_0, hos::Version_6_2_0) */ \ + AMS_SF_METHOD_INFO(C, H, 1011, Result, GetProgramIndexForAccessLog, (ams::sf::Out out_idx, ams::sf::Out out_count), (out_idx, out_count), hos::Version_7_0_0) \ + AMS_SF_METHOD_INFO(C, H, 1012, Result, GetFsStackUsage, (ams::sf::Out out, u32 type), (out, type), hos::Version_9_0_0) \ + AMS_SF_METHOD_INFO(C, H, 1013, Result, UnsetSaveDataRootPath, (), (), hos::Version_9_0_0) \ + AMS_SF_METHOD_INFO(C, H, 1014, Result, OutputMultiProgramTagAccessLog, (), (), hos::Version_10_0_0, hos::Version_10_2_0) \ + AMS_SF_METHOD_INFO(C, H, 1016, Result, FlushAccessLogOnSdCard, (), (), hos::Version_11_0_0) \ + AMS_SF_METHOD_INFO(C, H, 1017, Result, OutputApplicationInfoAccessLog, (), (), hos::Version_11_0_0) \ + AMS_SF_METHOD_INFO(C, H, 1018, Result, RegisterDebugConfiguration, (u32 key, s64 value), (key, value), hos::Version_13_0_0) \ + AMS_SF_METHOD_INFO(C, H, 1019, Result, UnregisterDebugConfiguration, (u32 key), (key), hos::Version_13_0_0) \ + AMS_SF_METHOD_INFO(C, H, 1100, Result, OverrideSaveDataTransferTokenSignVerificationKey, (const ams::sf::InBuffer &buf), (buf), hos::Version_4_0_0) \ + AMS_SF_METHOD_INFO(C, H, 1110, Result, CorruptSaveDataFileSystemByOffset, (u8 space_id, u64 save_data_id, s64 offset), (space_id, save_data_id, offset), hos::Version_6_0_0) \ + /* AMS_SF_METHOD_INFO(C, H, 1200, Result, OpenMultiCommitManager, (), (), hos::Version_6_0_0) */ \ + /* AMS_SF_METHOD_INFO(C, H, 1300, Result, OpenBisWiper, (), (), hos::Version_10_0_0) */ AMS_SF_DEFINE_INTERFACE(ams::fssrv::sf, IFileSystemProxy, AMS_FSSRV_I_FILE_SYSTEM_PROXY_INTERFACE_INFO) diff --git a/libraries/libstratosphere/include/stratosphere/fssrv/sf/fssrv_sf_path.hpp b/libraries/libstratosphere/include/stratosphere/fssrv/sf/fssrv_sf_path.hpp index d5b3be6d4..2d53471bf 100644 --- a/libraries/libstratosphere/include/stratosphere/fssrv/sf/fssrv_sf_path.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssrv/sf/fssrv_sf_path.hpp @@ -42,8 +42,11 @@ namespace ams::fssrv::sf { return len; } }; + static_assert(util::is_pod::value); - static_assert(util::is_pod::value && sizeof(Path) == FS_MAX_PATH); + #if defined(ATMOSPHERE_OS_HORIZON) + static_assert(sizeof(Path) == FS_MAX_PATH); + #endif using FspPath = Path; diff --git a/libraries/libstratosphere/include/stratosphere/fssystem.hpp b/libraries/libstratosphere/include/stratosphere/fssystem.hpp index 3e79e01b1..658d8db30 100644 --- a/libraries/libstratosphere/include/stratosphere/fssystem.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssystem.hpp @@ -49,4 +49,5 @@ #include #include #include -#include \ No newline at end of file +#include +#include diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/buffers/fssystem_i_buffer_manager.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/buffers/fssystem_i_buffer_manager.hpp index c13dcfa62..057fcfcc3 100644 --- a/libraries/libstratosphere/include/stratosphere/fssystem/buffers/fssystem_i_buffer_manager.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssystem/buffers/fssystem_i_buffer_manager.hpp @@ -80,8 +80,8 @@ namespace ams::fssystem { return this->GetRetriedCountImpl(); } - void ClearPeak() const { - return this->ClearPeak(); + void ClearPeak() { + return this->ClearPeakImpl(); } protected: virtual const std::pair AllocateBufferImpl(size_t size, const BufferAttribute &attr) = 0; diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_directory_redirection_filesystem.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_directory_redirection_filesystem.hpp index b531cca72..bb0c9318c 100644 --- a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_directory_redirection_filesystem.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_directory_redirection_filesystem.hpp @@ -14,34 +14,166 @@ * along with this program. If not, see . */ #pragma once -#include +#include +#include +#include +#include +#include namespace ams::fssystem { - class DirectoryRedirectionFileSystem : public impl::IPathResolutionFileSystem { + class DirectoryRedirectionFileSystem : public fs::fsa::IFileSystem, public fs::impl::Newable { NON_COPYABLE(DirectoryRedirectionFileSystem); private: - using PathResolutionFileSystem = impl::IPathResolutionFileSystem; - friend class impl::IPathResolutionFileSystem; - private: - char *m_before_dir; - size_t m_before_dir_len; - char *m_after_dir; - size_t m_after_dir_len; + std::unique_ptr m_base_fs; + fs::Path m_before_dir; + fs::Path m_after_dir; 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); + DirectoryRedirectionFileSystem(std::unique_ptr fs) : m_base_fs(std::move(fs)), m_before_dir(), m_after_dir() { + /* ... */ + } - virtual ~DirectoryRedirectionFileSystem(); - protected: - inline util::optional> GetAccessorLock() const { - /* No accessor lock is needed. */ - return util::nullopt; + Result InitializeWithFixedPath(const char *before, const char *after) { + R_TRY(fs::SetUpFixedPath(std::addressof(m_before_dir), before)); + R_TRY(fs::SetUpFixedPath(std::addressof(m_after_dir), after)); + R_SUCCEED(); } 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); + Result ResolveFullPath(fs::Path *out, const fs::Path &path) { + if (path.IsMatchHead(m_before_dir.GetString(), m_before_dir.GetLength())) { + R_TRY(out->InitializeWithFormat("%s%s", m_after_dir.GetString(), path.GetString() + m_before_dir.GetLength())); + R_TRY(out->Normalize(fs::PathFlags{})); + } else { + R_TRY(out->Initialize(path)); + } + R_SUCCEED(); + } + public: + virtual Result DoCreateFile(const fs::Path &path, s64 size, int option) override { + fs::Path full_path; + R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); + + R_RETURN(m_base_fs->CreateFile(full_path, size, option)); + } + + virtual Result DoDeleteFile(const fs::Path &path) override { + fs::Path full_path; + R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); + + R_RETURN(m_base_fs->DeleteFile(full_path)); + } + + virtual Result DoCreateDirectory(const fs::Path &path) override { + fs::Path full_path; + R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); + + R_RETURN(m_base_fs->CreateDirectory(full_path)); + } + + virtual Result DoDeleteDirectory(const fs::Path &path) override { + fs::Path full_path; + R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); + + R_RETURN(m_base_fs->DeleteDirectory(full_path)); + } + + virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) override { + fs::Path full_path; + R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); + + R_RETURN(m_base_fs->DeleteDirectoryRecursively(full_path)); + } + + virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) override { + fs::Path old_full_path; + fs::Path new_full_path; + R_TRY(this->ResolveFullPath(std::addressof(old_full_path), old_path)); + R_TRY(this->ResolveFullPath(std::addressof(new_full_path), new_path)); + + R_RETURN(m_base_fs->RenameFile(old_full_path, new_full_path)); + } + + virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) override { + fs::Path old_full_path; + fs::Path new_full_path; + R_TRY(this->ResolveFullPath(std::addressof(old_full_path), old_path)); + R_TRY(this->ResolveFullPath(std::addressof(new_full_path), new_path)); + + R_RETURN(m_base_fs->RenameDirectory(old_full_path, new_full_path)); + } + + virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const fs::Path &path) override { + fs::Path full_path; + R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); + + R_RETURN(m_base_fs->GetEntryType(out, full_path)); + } + + virtual Result DoOpenFile(std::unique_ptr *out_file, const fs::Path &path, fs::OpenMode mode) override { + fs::Path full_path; + R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); + + R_RETURN(m_base_fs->OpenFile(out_file, full_path, mode)); + } + + virtual Result DoOpenDirectory(std::unique_ptr *out_dir, const fs::Path &path, fs::OpenDirectoryMode mode) override { + fs::Path full_path; + R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); + + R_RETURN(m_base_fs->OpenDirectory(out_dir, full_path, mode)); + } + + virtual Result DoCommit() override { + R_RETURN(m_base_fs->Commit()); + } + + virtual Result DoGetFreeSpaceSize(s64 *out, const fs::Path &path) override { + fs::Path full_path; + R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); + + R_RETURN(m_base_fs->GetFreeSpaceSize(out, full_path)); + } + + virtual Result DoGetTotalSpaceSize(s64 *out, const fs::Path &path) override { + fs::Path full_path; + R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); + + R_RETURN(m_base_fs->GetTotalSpaceSize(out, full_path)); + } + + virtual Result DoCleanDirectoryRecursively(const fs::Path &path) override { + fs::Path full_path; + R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); + + R_RETURN(m_base_fs->CleanDirectoryRecursively(full_path)); + } + + virtual Result DoGetFileTimeStampRaw(fs::FileTimeStampRaw *out, const fs::Path &path) override { + fs::Path full_path; + R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); + + R_RETURN(m_base_fs->GetFileTimeStampRaw(out, full_path)); + } + + virtual Result DoQueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const fs::Path &path) override { + fs::Path full_path; + R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); + + R_RETURN(m_base_fs->QueryEntry(dst, dst_size, src, src_size, query, full_path)); + } + + /* These aren't accessible as commands. */ + virtual Result DoCommitProvisionally(s64 counter) override { + R_RETURN(m_base_fs->CommitProvisionally(counter)); + } + + virtual Result DoRollback() override { + R_RETURN(m_base_fs->Rollback()); + } + + virtual Result DoFlush() override { + R_RETURN(m_base_fs->Flush()); + } }; } diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_directory_savedata_filesystem.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_directory_savedata_filesystem.hpp index dd32a611c..40282685a 100644 --- a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_directory_savedata_filesystem.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_directory_savedata_filesystem.hpp @@ -14,51 +14,56 @@ * along with this program. If not, see . */ #pragma once -#include +#include +#include +#include +#include +#include namespace ams::fssystem { - class DirectorySaveDataFileSystem : public impl::IPathResolutionFileSystem { + class DirectorySaveDataFileSystem : public fs::fsa::IFileSystem, public fs::impl::Newable { NON_COPYABLE(DirectorySaveDataFileSystem); private: - using PathResolutionFileSystem = impl::IPathResolutionFileSystem; - friend class impl::IPathResolutionFileSystem; - private: - os::SdkMutex m_accessor_mutex; - s32 m_open_writable_files; - public: - DirectorySaveDataFileSystem(std::shared_ptr fs); - DirectorySaveDataFileSystem(std::unique_ptr fs); - Result Initialize(); + std::unique_ptr m_unique_fs; + fs::fsa::IFileSystem * const m_base_fs; + os::SdkMutex m_accessor_mutex = {}; + s32 m_open_writable_files = 0; + bool m_is_journaling_supported = false; + bool m_is_multi_commit_supported = false; + bool m_is_journaling_enabled = false; - virtual ~DirectorySaveDataFileSystem(); - protected: - inline util::optional> GetAccessorLock() { - /* We have a real accessor lock that we want to use. */ - return util::make_optional>(m_accessor_mutex); - } + /* Extension member to ensure proper savedata locking. */ + std::unique_ptr m_lock_file = nullptr; + public: + DirectorySaveDataFileSystem(std::unique_ptr fs) : m_unique_fs(std::move(fs)), m_base_fs(m_unique_fs.get()) { /* ... */ } + DirectorySaveDataFileSystem(fs::fsa::IFileSystem *fs) : m_unique_fs(), m_base_fs(fs) { /* ... */ } + Result Initialize(bool journaling_supported, bool multi_commit_enabled, bool journaling_enabled); 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); + Result SynchronizeDirectory(const fs::Path &dst, const fs::Path &src); + Result ResolvePath(fs::Path *out, const fs::Path &path); + Result AcquireLockFile(); public: - void OnWritableFileClose(); - Result CopySaveFromFileSystem(fs::fsa::IFileSystem *save_fs); + void DecrementWriteOpenFileCount(); public: - /* Overridden from IPathResolutionFileSystem */ - virtual Result DoOpenFile(std::unique_ptr *out_file, const char *path, fs::OpenMode mode) override; + virtual Result DoCreateFile(const fs::Path &path, s64 size, int option) override; + virtual Result DoDeleteFile(const fs::Path &path) override; + virtual Result DoCreateDirectory(const fs::Path &path) override; + virtual Result DoDeleteDirectory(const fs::Path &path) override; + virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) override; + virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) override; + virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) override; + virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const fs::Path &path) override; + virtual Result DoOpenFile(std::unique_ptr *out_file, const fs::Path &path, fs::OpenMode mode) override; + virtual Result DoOpenDirectory(std::unique_ptr *out_dir, const fs::Path &path, fs::OpenDirectoryMode mode) override; virtual Result DoCommit() override; + virtual Result DoGetFreeSpaceSize(s64 *out, const fs::Path &path) override; + virtual Result DoGetTotalSpaceSize(s64 *out, const fs::Path &path) override; + virtual Result DoCleanDirectoryRecursively(const fs::Path &path) override; - /* Overridden from IPathResolutionFileSystem but not commands. */ + /* These aren't accessible as commands. */ virtual Result DoCommitProvisionally(s64 counter) override; virtual Result DoRollback() override; - - /* Explicitly overridden to be not implemented. */ - virtual Result DoGetFreeSpaceSize(s64 *out, const char *path) override; - virtual Result DoGetTotalSpaceSize(s64 *out, const char *path) override; - virtual Result DoGetFileTimeStampRaw(fs::FileTimeStampRaw *out, const char *path) override; - virtual Result DoQueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const char *path) override; - virtual Result DoFlush() override; }; } diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_local_file_system.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_local_file_system.hpp new file mode 100644 index 000000000..cd0f8f3e7 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_local_file_system.hpp @@ -0,0 +1,85 @@ +/* + * Copyright (c) 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 +#include +#include + +namespace ams::fssystem { + + /* TODO: Put this in its own header? */ + enum PathCaseSensitiveMode { + PathCaseSensitiveMode_CaseInsensitive = 0, + PathCaseSensitiveMode_CaseSensitive = 1, + }; + + + class LocalFileSystem : public fs::fsa::IFileSystem, public fs::impl::Newable { + NON_COPYABLE(LocalFileSystem); + NON_MOVEABLE(LocalFileSystem); + private: + #if defined(ATMOSPHERE_OS_WINDOWS) + using NativeCharacterType = wchar_t; + #else + using NativeCharacterType = char; + #endif + + using NativePathBuffer = std::unique_ptr; + private: + fs::Path m_root_path; + fssystem::PathCaseSensitiveMode m_case_sensitive_mode; + NativePathBuffer m_native_path_buffer; + int m_native_path_length; + bool m_use_posix_time; + public: + LocalFileSystem(bool posix_time = true) : m_root_path(), m_native_path_buffer(), m_native_path_length(0), m_use_posix_time(posix_time) { + /* ... */ + } + + Result Initialize(const fs::Path &root_path, fssystem::PathCaseSensitiveMode case_sensitive_mode); + + Result GetCaseSensitivePath(int *out_size, char *dst, size_t dst_size, const char *path, const char *work_path); + private: + Result CheckPathCaseSensitively(const NativeCharacterType *path, const NativeCharacterType *root_path, NativeCharacterType *cs_buf, size_t cs_size, bool check_case_sensitivity); + Result ResolveFullPath(NativePathBuffer *out, const fs::Path &path, int max_len, int min_len, bool check_case_sensitivity); + public: + virtual Result DoCreateFile(const fs::Path &path, s64 size, int flags) override; + virtual Result DoDeleteFile(const fs::Path &path) override; + virtual Result DoCreateDirectory(const fs::Path &path) override; + virtual Result DoDeleteDirectory(const fs::Path &path) override; + virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) override; + virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) override; + virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) override; + virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const fs::Path &path) override; + virtual Result DoOpenFile(std::unique_ptr *out_file, const fs::Path &path, fs::OpenMode mode) override; + virtual Result DoOpenDirectory(std::unique_ptr *out_dir, const fs::Path &path, fs::OpenDirectoryMode mode) override; + virtual Result DoCommit() override; + virtual Result DoGetFreeSpaceSize(s64 *out, const fs::Path &path) override; + virtual Result DoGetTotalSpaceSize(s64 *out, const fs::Path &path) override; + virtual Result DoCleanDirectoryRecursively(const fs::Path &path) override; + virtual Result DoGetFileTimeStampRaw(fs::FileTimeStampRaw *out, const fs::Path &path) override; + virtual Result DoQueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const fs::Path &path) override; + + /* These aren't accessible as commands. */ + virtual Result DoCommitProvisionally(s64 counter) override; + virtual Result DoRollback() override; + public: + Result DoGetDiskFreeSpace(s64 *out_free, s64 *out_total, s64 *out_total_free, const fs::Path &path); + Result DeleteDirectoryRecursivelyInternal(const NativeCharacterType *path, bool delete_top); + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_partition_file_system.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_partition_file_system.hpp index f87c9a715..6df57428e 100644 --- a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_partition_file_system.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_partition_file_system.hpp @@ -49,18 +49,18 @@ namespace ams::fssystem { Result GetFileBaseOffset(s64 *out_offset, const char *path); - virtual Result DoCreateFile(const char *path, s64 size, int option) override; - virtual Result DoDeleteFile(const char *path) override; - virtual Result DoCreateDirectory(const char *path) override; - virtual Result DoDeleteDirectory(const char *path) override; - virtual Result DoDeleteDirectoryRecursively(const char *path) override; - virtual Result DoRenameFile(const char *old_path, const char *new_path) override; - virtual Result DoRenameDirectory(const char *old_path, const char *new_path) override; - virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const char *path) override; - virtual Result DoOpenFile(std::unique_ptr *out_file, const char *path, fs::OpenMode mode) override; - virtual Result DoOpenDirectory(std::unique_ptr *out_dir, const char *path, fs::OpenDirectoryMode mode) override; + virtual Result DoCreateFile(const fs::Path &path, s64 size, int option) override; + virtual Result DoDeleteFile(const fs::Path &path) override; + virtual Result DoCreateDirectory(const fs::Path &path) override; + virtual Result DoDeleteDirectory(const fs::Path &path) override; + virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) override; + virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) override; + virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) override; + virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const fs::Path &path) override; + virtual Result DoOpenFile(std::unique_ptr *out_file, const fs::Path &path, fs::OpenMode mode) override; + virtual Result DoOpenDirectory(std::unique_ptr *out_dir, const fs::Path &path, fs::OpenDirectoryMode mode) override; virtual Result DoCommit() override; - virtual Result DoCleanDirectoryRecursively(const char *path) override; + virtual Result DoCleanDirectoryRecursively(const fs::Path &path) override; /* These aren't accessible as commands. */ virtual Result DoCommitProvisionally(s64 counter) override; diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_pimpl.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_pimpl.hpp index c007a94f1..abc900ea7 100644 --- a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_pimpl.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_pimpl.hpp @@ -31,10 +31,18 @@ namespace ams::fssystem { template class Pimpl { private: - alignas(0x10) u8 m_storage[Size]; + #if defined(ATMOSPHERE_OS_HORIZON) || defined(ATMOSPHERE_OS_WINDOWS) || defined(ATMOSPHERE_OS_LINUX) + static constexpr size_t ExtraSizeToEnsureCompatibility = 0; + #elif defined(ATMOSPHERE_OS_MACOS) + static constexpr size_t ExtraSizeToEnsureCompatibility = 0x20; + #endif + + static constexpr size_t StorageSize = Size + ExtraSizeToEnsureCompatibility; + private: + alignas(0x10) u8 m_storage[StorageSize]; public: - ALWAYS_INLINE Pimpl() { impl::PimplHelper::Construct(m_storage); } - ALWAYS_INLINE ~Pimpl() { impl::PimplHelper::Destroy(m_storage); } + ALWAYS_INLINE Pimpl() { impl::PimplHelper::Construct(m_storage); } + ALWAYS_INLINE ~Pimpl() { impl::PimplHelper::Destroy(m_storage); } ALWAYS_INLINE T *Get() { return reinterpret_cast(m_storage + 0); } ALWAYS_INLINE T *operator->() { return reinterpret_cast(m_storage + 0); } diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_romfs_file_system.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_romfs_file_system.hpp index b2a173666..b3c16a7e8 100644 --- a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_romfs_file_system.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_romfs_file_system.hpp @@ -37,6 +37,13 @@ namespace ams::fssystem { s64 m_entry_size; private: Result GetFileInfo(RomFileTable::FileInfo *out, const char *path); + Result GetFileInfo(RomFileTable::FileInfo *out, const fs::Path &path) { + R_RETURN(this->GetFileInfo(out, path.GetString())); + } + + Result CheckPathFormat(const fs::Path &path) const { + R_RETURN(fs::PathFormatter::CheckPathFormat(path.GetString(), fs::PathFlags{})); + } public: static Result GetRequiredWorkingMemorySize(size_t *out, fs::IStorage *storage); public: @@ -48,21 +55,21 @@ namespace ams::fssystem { fs::IStorage *GetBaseStorage(); RomFileTable *GetRomFileTable(); - Result GetFileBaseOffset(s64 *out, const char *path); + Result GetFileBaseOffset(s64 *out, const fs::Path &path); public: - virtual Result DoCreateFile(const char *path, s64 size, int flags) override; - virtual Result DoDeleteFile(const char *path) override; - virtual Result DoCreateDirectory(const char *path) override; - virtual Result DoDeleteDirectory(const char *path) override; - virtual Result DoDeleteDirectoryRecursively(const char *path) override; - virtual Result DoRenameFile(const char *old_path, const char *new_path) override; - virtual Result DoRenameDirectory(const char *old_path, const char *new_path) override; - virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const char *path) override; - virtual Result DoOpenFile(std::unique_ptr *out_file, const char *path, fs::OpenMode mode) override; - virtual Result DoOpenDirectory(std::unique_ptr *out_dir, const char *path, fs::OpenDirectoryMode mode) override; + virtual Result DoCreateFile(const fs::Path &path, s64 size, int flags) override; + virtual Result DoDeleteFile(const fs::Path &path) override; + virtual Result DoCreateDirectory(const fs::Path &path) override; + virtual Result DoDeleteDirectory(const fs::Path &path) override; + virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) override; + virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) override; + virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) override; + virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const fs::Path &path) override; + virtual Result DoOpenFile(std::unique_ptr *out_file, const fs::Path &path, fs::OpenMode mode) override; + virtual Result DoOpenDirectory(std::unique_ptr *out_dir, const fs::Path &path, fs::OpenDirectoryMode mode) override; virtual Result DoCommit() override; - virtual Result DoGetFreeSpaceSize(s64 *out, const char *path) override; - virtual Result DoCleanDirectoryRecursively(const char *path) override; + virtual Result DoGetFreeSpaceSize(s64 *out, const fs::Path &path) override; + virtual Result DoCleanDirectoryRecursively(const fs::Path &path) override; /* These aren't accessible as commands. */ virtual Result DoCommitProvisionally(s64 counter) override; diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_sha256_hash_generator.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_sha256_hash_generator.hpp index 4d168995f..16cf1b453 100644 --- a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_sha256_hash_generator.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_sha256_hash_generator.hpp @@ -51,7 +51,7 @@ namespace ams::fssystem { } virtual void DoGenerateHash(void *dst, size_t dst_size, const void *src, size_t src_size) override { - crypto::GenerateSha256Hash(dst, dst_size, src, src_size); + crypto::GenerateSha256(dst, dst_size, src, src_size); } }; diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_subdirectory_filesystem.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_subdirectory_filesystem.hpp index fb48cc01e..00c81435e 100644 --- a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_subdirectory_filesystem.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_subdirectory_filesystem.hpp @@ -14,31 +14,162 @@ * along with this program. If not, see . */ #pragma once -#include +#include +#include +#include +#include +#include namespace ams::fssystem { - class SubDirectoryFileSystem : public impl::IPathResolutionFileSystem { + class SubDirectoryFileSystem : public fs::fsa::IFileSystem, public fs::impl::Newable { NON_COPYABLE(SubDirectoryFileSystem); private: - using PathResolutionFileSystem = impl::IPathResolutionFileSystem; - friend class impl::IPathResolutionFileSystem; - private: - char *m_base_path; - size_t m_base_path_len; + std::shared_ptr m_shared_fs; + fs::fsa::IFileSystem * const m_base_fs; + fs::Path m_root_path; public: - SubDirectoryFileSystem(std::shared_ptr fs, const char *bp, bool unc = false); - SubDirectoryFileSystem(std::unique_ptr fs, const char *bp, bool unc = false); + SubDirectoryFileSystem(std::shared_ptr fs) : m_shared_fs(std::move(fs)), m_base_fs(m_shared_fs.get()), m_root_path() { + /* ... */ + } - virtual ~SubDirectoryFileSystem(); - protected: - inline util::optional> GetAccessorLock() const { - /* No accessor lock is needed. */ - return util::nullopt; + SubDirectoryFileSystem(fs::fsa::IFileSystem *fs) : m_shared_fs(), m_base_fs(fs), m_root_path() { + /* ... */ + } + + Result Initialize(const fs::Path &path) { + R_RETURN(m_root_path.Initialize(path)); } private: - Result Initialize(const char *bp); - Result ResolveFullPath(char *out, size_t out_size, const char *relative_path); + Result ResolveFullPath(fs::Path *out, const fs::Path &path) { + R_RETURN(out->Combine(m_root_path, path)); + } + public: + virtual Result DoCreateFile(const fs::Path &path, s64 size, int option) override { + fs::Path full_path; + R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); + + R_RETURN(m_base_fs->CreateFile(full_path, size, option)); + } + + virtual Result DoDeleteFile(const fs::Path &path) override { + fs::Path full_path; + R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); + + R_RETURN(m_base_fs->DeleteFile(full_path)); + } + + virtual Result DoCreateDirectory(const fs::Path &path) override { + fs::Path full_path; + R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); + + R_RETURN(m_base_fs->CreateDirectory(full_path)); + } + + virtual Result DoDeleteDirectory(const fs::Path &path) override { + fs::Path full_path; + R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); + + R_RETURN(m_base_fs->DeleteDirectory(full_path)); + } + + virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) override { + fs::Path full_path; + R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); + + R_RETURN(m_base_fs->DeleteDirectoryRecursively(full_path)); + } + + virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) override { + fs::Path old_full_path; + fs::Path new_full_path; + R_TRY(this->ResolveFullPath(std::addressof(old_full_path), old_path)); + R_TRY(this->ResolveFullPath(std::addressof(new_full_path), new_path)); + + R_RETURN(m_base_fs->RenameFile(old_full_path, new_full_path)); + } + + virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) override { + fs::Path old_full_path; + fs::Path new_full_path; + R_TRY(this->ResolveFullPath(std::addressof(old_full_path), old_path)); + R_TRY(this->ResolveFullPath(std::addressof(new_full_path), new_path)); + + R_RETURN(m_base_fs->RenameDirectory(old_full_path, new_full_path)); + } + + virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const fs::Path &path) override { + fs::Path full_path; + R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); + + R_RETURN(m_base_fs->GetEntryType(out, full_path)); + } + + virtual Result DoOpenFile(std::unique_ptr *out_file, const fs::Path &path, fs::OpenMode mode) override { + fs::Path full_path; + R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); + + R_RETURN(m_base_fs->OpenFile(out_file, full_path, mode)); + } + + virtual Result DoOpenDirectory(std::unique_ptr *out_dir, const fs::Path &path, fs::OpenDirectoryMode mode) override { + fs::Path full_path; + R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); + + R_RETURN(m_base_fs->OpenDirectory(out_dir, full_path, mode)); + } + + virtual Result DoCommit() override { + R_RETURN(m_base_fs->Commit()); + } + + virtual Result DoGetFreeSpaceSize(s64 *out, const fs::Path &path) override { + fs::Path full_path; + R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); + + R_RETURN(m_base_fs->GetFreeSpaceSize(out, full_path)); + } + + virtual Result DoGetTotalSpaceSize(s64 *out, const fs::Path &path) override { + fs::Path full_path; + R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); + + R_RETURN(m_base_fs->GetTotalSpaceSize(out, full_path)); + } + + virtual Result DoCleanDirectoryRecursively(const fs::Path &path) override { + fs::Path full_path; + R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); + + R_RETURN(m_base_fs->CleanDirectoryRecursively(full_path)); + } + + virtual Result DoGetFileTimeStampRaw(fs::FileTimeStampRaw *out, const fs::Path &path) override { + fs::Path full_path; + R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); + + R_RETURN(m_base_fs->GetFileTimeStampRaw(out, full_path)); + } + + virtual Result DoQueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const fs::Path &path) override { + fs::Path full_path; + R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); + + R_RETURN(m_base_fs->QueryEntry(dst, dst_size, src, src_size, query, full_path)); + } + + /* These aren't accessible as commands. */ + virtual Result DoCommitProvisionally(s64 counter) override { + R_RETURN(m_base_fs->CommitProvisionally(counter)); + } + + virtual Result DoRollback() override { + R_RETURN(m_base_fs->Rollback()); + } + + virtual Result DoFlush() override { + R_RETURN(m_base_fs->Flush()); + } }; } diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_utility.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_utility.hpp index 827f094f9..77d72cc95 100644 --- a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_utility.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_utility.hpp @@ -18,21 +18,24 @@ #include #include #include -#include +#include namespace ams::fssystem { namespace impl { + template + concept IterateDirectoryHandler = requires (F f, const fs::Path &path, const fs::DirectoryEntry &entry) { + { f(path, entry) } -> std::convertible_to<::ams::Result>; + }; + /* 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) { + template + Result IterateDirectoryRecursivelyImpl(fs::fsa::IFileSystem *fs, fs::Path &work_path, 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(std::addressof(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. */ @@ -44,22 +47,15 @@ namespace ams::fssystem { 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); + /* Append child path. */ + R_TRY(work_path.AppendChild(dir_ent->name)); { - if (is_dir) { + if (dir_ent->type == fs::DirectoryEntryType_Directory) { /* 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)); + /* Recurse. */ + R_TRY(IterateDirectoryRecursivelyImpl(fs, work_path, dir_ent, on_enter_dir, on_exit_dir, on_file)); /* Exit directory. */ R_TRY(on_exit_dir(work_path, *dir_ent)); @@ -68,12 +64,10 @@ namespace ams::fssystem { R_TRY(on_file(work_path, *dir_ent)); } } - - /* Restore parent path. */ - work_path[parent_len] = fs::StringTraits::NullTerminator; + R_TRY(work_path.RemoveChild()); } - return ResultSuccess(); + R_SUCCEED(); } /* TODO: Cleanup. */ @@ -81,50 +75,39 @@ namespace ams::fssystem { } /* 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_ABORT_UNLESS(work_path_size >= fs::EntryNameLengthMax + 1); + template + Result IterateDirectoryRecursively(fs::fsa::IFileSystem *fs, const fs::Path &root_path, fs::DirectoryEntry *dir_ent_buf, OnEnterDir on_enter_dir, OnExitDir on_exit_dir, OnFile on_file) { + /* Create work path from the root path. */ + fs::Path work_path; + R_TRY(work_path.Initialize(root_path)); - /* 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 (!fs::PathNormalizer::IsSeparator(work_path[root_path_len - 1])) { - work_path[root_path_len++] = fs::StringTraits::DirectorySeparator; - } - - /* Make sure the result path is still valid. */ - R_UNLESS(root_path_len <= fs::EntryNameLengthMax, fs::ResultTooLongPath()); - work_path[root_path_len] = fs::StringTraits::NullTerminator; - - return impl::IterateDirectoryRecursivelyImpl(fs, work_path, work_path_size, dir_ent_buf, on_enter_dir, on_exit_dir, on_file); + R_RETURN(impl::IterateDirectoryRecursivelyImpl(fs, work_path, 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) { + template + Result IterateDirectoryRecursively(fs::fsa::IFileSystem *fs, const fs::Path &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), std::addressof(dir_entry), on_enter_dir, on_exit_dir, on_file); + return IterateDirectoryRecursively(fs, root_path, std::addressof(dir_entry), on_enter_dir, on_exit_dir, on_file); } - template + template Result IterateDirectoryRecursively(fs::fsa::IFileSystem *fs, OnEnterDir on_enter_dir, OnExitDir on_exit_dir, OnFile on_file) { - return IterateDirectoryRecursively(fs, fs::PathNormalizer::RootPath, on_enter_dir, on_exit_dir, on_file); + return IterateDirectoryRecursively(fs, fs::MakeConstantPath("/"), 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); - ALWAYS_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 CopyFile(fs::fsa::IFileSystem *dst_fs, fs::fsa::IFileSystem *src_fs, const fs::Path &dst_path, const fs::Path &src_path, void *work_buf, size_t work_buf_size); + + ALWAYS_INLINE Result CopyFile(fs::fsa::IFileSystem *fs, const fs::Path &dst_path, const fs::Path &src_path, void *work_buf, size_t work_buf_size) { + return CopyFile(fs, fs, dst_path, src_path, 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); - ALWAYS_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); + Result CopyDirectoryRecursively(fs::fsa::IFileSystem *dst_fs, fs::fsa::IFileSystem *src_fs, const fs::Path &dst_path, const fs::Path &src_path, fs::DirectoryEntry *entry, void *work_buf, size_t work_buf_size); + + ALWAYS_INLINE Result CopyDirectoryRecursively(fs::fsa::IFileSystem *fs, const fs::Path &dst_path, const fs::Path &src_path, fs::DirectoryEntry *entry, void *work_buf, size_t work_buf_size) { + return CopyDirectoryRecursively(fs, fs, dst_path, src_path, entry, work_buf, work_buf_size); } /* Semaphore adapter class. */ @@ -142,32 +125,27 @@ namespace ams::fssystem { }; /* Other utility. */ - Result HasFile(bool *out, fs::fsa::IFileSystem *fs, const char *path); - Result HasDirectory(bool *out, fs::fsa::IFileSystem *fs, const char *path); + Result HasFile(bool *out, fs::fsa::IFileSystem *fs, const fs::Path &path); + Result HasDirectory(bool *out, fs::fsa::IFileSystem *fs, const fs::Path &path); - Result EnsureDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *path); - Result EnsureParentDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *path); + Result EnsureDirectory(fs::fsa::IFileSystem *fs, const fs::Path &path); - template + template ALWAYS_INLINE Result RetryFinitelyForTargetLocked(auto f) { - /* Retry up to 10 times, 100ms between retries. */ - constexpr s32 MaxRetryCount = 10; + /* Retry sleeping between retries. */ constexpr TimeSpan RetryWaitTime = TimeSpan::FromMilliSeconds(RetryMilliSeconds); - s32 remaining_retries = MaxRetryCount; - while (true) { - R_TRY_CATCH(f()) { - R_CATCH(fs::ResultTargetLocked) { - R_UNLESS(remaining_retries > 0, fs::ResultTargetLocked()); - - remaining_retries--; - os::SleepThread(RetryWaitTime); - continue; - } - } R_END_TRY_CATCH; - - return ResultSuccess(); + Result result = f(); + for (int i = 0; i < MaxTryCount && fs::ResultTargetLocked::Includes(result); ++i) { + os::SleepThread(RetryWaitTime); + result = f(); } + + R_RETURN(result); + } + + ALWAYS_INLINE Result RetryToAvoidTargetLocked(auto f) { + return RetryFinitelyForTargetLocked<2, 25>(f); } void AddCounter(void *counter, size_t counter_size, u64 value); 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 deleted file mode 100644 index af0cec1be..000000000 --- a/libraries/libstratosphere/include/stratosphere/fssystem/impl/fssystem_path_resolution_filesystem.hpp +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (c) 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 -#include -#include -#include - -namespace ams::fssystem::impl { - - template - class IPathResolutionFileSystem : public fs::fsa::IFileSystem, public fs::impl::Newable { - NON_COPYABLE(IPathResolutionFileSystem); - private: - std::shared_ptr m_shared_fs; - std::unique_ptr m_unique_fs; - bool m_unc_preserved; - protected: - fs::fsa::IFileSystem * const m_base_fs; - public: - IPathResolutionFileSystem(std::shared_ptr fs, bool unc = false) : m_shared_fs(std::move(fs)), m_unc_preserved(unc), m_base_fs(m_shared_fs.get()) { - /* ... */ - } - - IPathResolutionFileSystem(std::unique_ptr fs, bool unc = false) : m_unique_fs(std::move(fs)), m_unc_preserved(unc), m_base_fs(m_unique_fs.get()) { - /* ... */ - } - - virtual ~IPathResolutionFileSystem() { /* ... */ } - protected: - constexpr inline bool IsUncPreserved() const { - return m_unc_preserved; - } - public: - virtual Result DoCreateFile(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)); - - util::optional optional_lock = static_cast(this)->GetAccessorLock(); - return m_base_fs->CreateFile(full_path, size, option); - } - - virtual Result DoDeleteFile(const char *path) override { - char full_path[fs::EntryNameLengthMax + 1]; - R_TRY(static_cast(this)->ResolveFullPath(full_path, sizeof(full_path), path)); - - util::optional optional_lock = static_cast(this)->GetAccessorLock(); - return m_base_fs->DeleteFile(full_path); - } - - virtual Result DoCreateDirectory(const char *path) override { - char full_path[fs::EntryNameLengthMax + 1]; - R_TRY(static_cast(this)->ResolveFullPath(full_path, sizeof(full_path), path)); - - util::optional optional_lock = static_cast(this)->GetAccessorLock(); - return m_base_fs->CreateDirectory(full_path); - } - - virtual Result DoDeleteDirectory(const char *path) override { - char full_path[fs::EntryNameLengthMax + 1]; - R_TRY(static_cast(this)->ResolveFullPath(full_path, sizeof(full_path), path)); - - util::optional optional_lock = static_cast(this)->GetAccessorLock(); - return m_base_fs->DeleteDirectory(full_path); - } - - virtual Result DoDeleteDirectoryRecursively(const char *path) override { - char full_path[fs::EntryNameLengthMax + 1]; - R_TRY(static_cast(this)->ResolveFullPath(full_path, sizeof(full_path), path)); - - util::optional optional_lock = static_cast(this)->GetAccessorLock(); - return m_base_fs->DeleteDirectoryRecursively(full_path); - } - - virtual Result DoRenameFile(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)); - - util::optional optional_lock = static_cast(this)->GetAccessorLock(); - return m_base_fs->RenameFile(old_full_path, new_full_path); - } - - virtual Result DoRenameDirectory(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)); - - util::optional optional_lock = static_cast(this)->GetAccessorLock(); - return m_base_fs->RenameDirectory(old_full_path, new_full_path); - } - - virtual Result DoGetEntryType(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)); - - util::optional optional_lock = static_cast(this)->GetAccessorLock(); - return m_base_fs->GetEntryType(out, full_path); - } - - virtual Result DoOpenFile(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)); - - util::optional optional_lock = static_cast(this)->GetAccessorLock(); - return m_base_fs->OpenFile(out_file, full_path, mode); - } - - virtual Result DoOpenDirectory(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)); - - util::optional optional_lock = static_cast(this)->GetAccessorLock(); - return m_base_fs->OpenDirectory(out_dir, full_path, mode); - } - - virtual Result DoCommit() override { - util::optional optional_lock = static_cast(this)->GetAccessorLock(); - return m_base_fs->Commit(); - } - - virtual Result DoGetFreeSpaceSize(s64 *out, const char *path) override { - char full_path[fs::EntryNameLengthMax + 1]; - R_TRY(static_cast(this)->ResolveFullPath(full_path, sizeof(full_path), path)); - - util::optional optional_lock = static_cast(this)->GetAccessorLock(); - return m_base_fs->GetFreeSpaceSize(out, full_path); - } - - virtual Result DoGetTotalSpaceSize(s64 *out, const char *path) override { - char full_path[fs::EntryNameLengthMax + 1]; - R_TRY(static_cast(this)->ResolveFullPath(full_path, sizeof(full_path), path)); - - util::optional optional_lock = static_cast(this)->GetAccessorLock(); - return m_base_fs->GetTotalSpaceSize(out, full_path); - } - - virtual Result DoCleanDirectoryRecursively(const char *path) override { - char full_path[fs::EntryNameLengthMax + 1]; - R_TRY(static_cast(this)->ResolveFullPath(full_path, sizeof(full_path), path)); - - util::optional optional_lock = static_cast(this)->GetAccessorLock(); - return m_base_fs->CleanDirectoryRecursively(full_path); - } - - virtual Result DoGetFileTimeStampRaw(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)); - - util::optional optional_lock = static_cast(this)->GetAccessorLock(); - return m_base_fs->GetFileTimeStampRaw(out, full_path); - } - - virtual Result DoQueryEntry(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)); - - util::optional optional_lock = static_cast(this)->GetAccessorLock(); - return m_base_fs->QueryEntry(dst, dst_size, src, src_size, query, full_path); - } - - /* These aren't accessible as commands. */ - virtual Result DoCommitProvisionally(s64 counter) override { - util::optional optional_lock = static_cast(this)->GetAccessorLock(); - return m_base_fs->CommitProvisionally(counter); - } - - virtual Result DoRollback() override { - util::optional optional_lock = static_cast(this)->GetAccessorLock(); - return m_base_fs->Rollback(); - } - - virtual Result DoFlush() override { - util::optional optional_lock = static_cast(this)->GetAccessorLock(); - return m_base_fs->Flush(); - } - }; - -} diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/save/fssystem_hierarchical_integrity_verification_storage.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/save/fssystem_hierarchical_integrity_verification_storage.hpp index 29d9ffd06..1ba245e06 100644 --- a/libraries/libstratosphere/include/stratosphere/fssystem/save/fssystem_hierarchical_integrity_verification_storage.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssystem/save/fssystem_hierarchical_integrity_verification_storage.hpp @@ -105,7 +105,7 @@ namespace ams::fssystem::save { NON_COPYABLE(HierarchicalIntegrityVerificationStorage); NON_MOVEABLE(HierarchicalIntegrityVerificationStorage); private: - friend class HierarchicalIntegrityVerificationMetaInformation; + friend struct HierarchicalIntegrityVerificationMetaInformation; protected: static constexpr s64 HashSize = crypto::Sha256Generator::HashSize; static constexpr size_t MaxLayers = IntegrityMaxLayerCount; diff --git a/libraries/libstratosphere/include/stratosphere/gpio/driver/gpio_i_gpio_driver.hpp b/libraries/libstratosphere/include/stratosphere/gpio/driver/gpio_i_gpio_driver.hpp index 07258b424..29dfb96e6 100644 --- a/libraries/libstratosphere/include/stratosphere/gpio/driver/gpio_i_gpio_driver.hpp +++ b/libraries/libstratosphere/include/stratosphere/gpio/driver/gpio_i_gpio_driver.hpp @@ -59,7 +59,7 @@ namespace ams::gpio::driver { virtual Result SetDebounceTime(Pad *pad, s32 ms) = 0; virtual Result GetUnknown22(u32 *out) = 0; - virtual void Unknown23(); + virtual void Unknown23() = 0; virtual Result SetValueForSleepState(Pad *pad, GpioValue value) = 0; virtual Result IsWakeEventActive(bool *out, Pad *pad) const = 0; diff --git a/libraries/libstratosphere/include/stratosphere/gpio/driver/gpio_select_driver_api.hpp b/libraries/libstratosphere/include/stratosphere/gpio/driver/gpio_select_driver_api.hpp index 7b35dacac..2d9cd9bbe 100644 --- a/libraries/libstratosphere/include/stratosphere/gpio/driver/gpio_select_driver_api.hpp +++ b/libraries/libstratosphere/include/stratosphere/gpio/driver/gpio_select_driver_api.hpp @@ -32,7 +32,7 @@ #else - #error "Unknown board for ams::gpio::driver::" + // TODO: #error "Unknown board for ams::gpio::driver::" #endif diff --git a/libraries/libstratosphere/include/stratosphere/gpio/gpio_pad_name.generic.hpp b/libraries/libstratosphere/include/stratosphere/gpio/gpio_pad_name.generic.hpp new file mode 100644 index 000000000..03347e9fc --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/gpio/gpio_pad_name.generic.hpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 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 + +namespace ams::gpio { + + enum GpioPadName : u32 { + GpioPadName_EnableSdCardPower = 2, + }; + constexpr inline const DeviceCode DeviceCode_EnableSdCardPower = 0x3C000001; + + constexpr inline GpioPadName ConvertToGpioPadName(DeviceCode dc) { + switch (dc.GetInternalValue()) { + case DeviceCode_EnableSdCardPower.GetInternalValue(): return GpioPadName_EnableSdCardPower; + AMS_UNREACHABLE_DEFAULT_CASE(); + } + } + + constexpr inline DeviceCode ConvertToDeviceCode(GpioPadName gpn) { + switch (gpn) { + case GpioPadName_EnableSdCardPower: return DeviceCode_EnableSdCardPower; + AMS_UNREACHABLE_DEFAULT_CASE(); + } + } + +} diff --git a/libraries/libstratosphere/include/stratosphere/gpio/gpio_select_pad_name.hpp b/libraries/libstratosphere/include/stratosphere/gpio/gpio_select_pad_name.hpp index e8e096c75..6cd60806a 100644 --- a/libraries/libstratosphere/include/stratosphere/gpio/gpio_select_pad_name.hpp +++ b/libraries/libstratosphere/include/stratosphere/gpio/gpio_select_pad_name.hpp @@ -20,5 +20,5 @@ #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) #include #else - /* Error? */ + #include #endif diff --git a/libraries/libstratosphere/include/stratosphere/i2c/driver/i2c_select_driver_api.hpp b/libraries/libstratosphere/include/stratosphere/i2c/driver/i2c_select_driver_api.hpp index 0436b6d20..e678bdaa8 100644 --- a/libraries/libstratosphere/include/stratosphere/i2c/driver/i2c_select_driver_api.hpp +++ b/libraries/libstratosphere/include/stratosphere/i2c/driver/i2c_select_driver_api.hpp @@ -31,7 +31,7 @@ #else - #error "Unknown board for ams::i2c::driver::" + // TODO: #error "Unknown board for ams::i2c::driver::" #endif diff --git a/libraries/libstratosphere/include/stratosphere/i2c/i2c_device_name.generic.hpp b/libraries/libstratosphere/include/stratosphere/i2c/i2c_device_name.generic.hpp new file mode 100644 index 000000000..0a39dea3c --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/i2c/i2c_device_name.generic.hpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) 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 + +namespace ams::i2c { + + enum I2cBus { + I2cBus_I2c1 = 0, + }; + + constexpr inline const DeviceCode DeviceCode_I2c1 = 0x02000001; + + constexpr inline DeviceCode ConvertToDeviceCode(I2cBus bus) { + switch (bus) { + case I2cBus_I2c1: return DeviceCode_I2c1; + AMS_UNREACHABLE_DEFAULT_CASE(); + } + } + + constexpr inline DeviceCode ConvertToI2cBus(DeviceCode dc) { + switch (dc.GetInternalValue()) { + case DeviceCode_I2c1.GetInternalValue(): return I2cBus_I2c1; + AMS_UNREACHABLE_DEFAULT_CASE(); + } + } + + enum I2cDevice : u32 { + I2cDevice_ClassicController = 0, + }; + + /* TODO: Better place for this? */ + constexpr inline const DeviceCode DeviceCode_ClassicController = 0x350000C9; + + constexpr inline DeviceCode ConvertToDeviceCode(I2cDevice dv) { + switch (dv) { + case I2cDevice_ClassicController: return DeviceCode_ClassicController; + AMS_UNREACHABLE_DEFAULT_CASE(); + } + } + + constexpr inline I2cDevice ConvertToI2cDevice(DeviceCode dc) { + switch (dc.GetInternalValue()) { + case DeviceCode_ClassicController.GetInternalValue(): return I2cDevice_ClassicController; + AMS_UNREACHABLE_DEFAULT_CASE(); + } + } + + constexpr bool IsPowerBusDeviceCode(DeviceCode device_code) { + switch (device_code.GetInternalValue()) { + default: + return false; + } + } + +} diff --git a/libraries/libstratosphere/include/stratosphere/i2c/i2c_select_device_name.hpp b/libraries/libstratosphere/include/stratosphere/i2c/i2c_select_device_name.hpp index b0c31a8fe..cb9a6321f 100644 --- a/libraries/libstratosphere/include/stratosphere/i2c/i2c_select_device_name.hpp +++ b/libraries/libstratosphere/include/stratosphere/i2c/i2c_select_device_name.hpp @@ -20,5 +20,5 @@ #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) #include #else - /* Error? */ + #include #endif diff --git a/libraries/libstratosphere/include/stratosphere/ldr/ldr_types.hpp b/libraries/libstratosphere/include/stratosphere/ldr/ldr_types.hpp index 6a7bf6e81..6cc5f9d14 100644 --- a/libraries/libstratosphere/include/stratosphere/ldr/ldr_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/ldr/ldr_types.hpp @@ -138,11 +138,11 @@ namespace ams::ldr { }; u8 reserved_6C[0x34]; union { - u8 segment_hashes[Segment_Count][SHA256_HASH_SIZE]; + u8 segment_hashes[Segment_Count][crypto::Sha256Generator::HashSize]; struct { - u8 text_hash[SHA256_HASH_SIZE]; - u8 ro_hash[SHA256_HASH_SIZE]; - u8 rw_hash[SHA256_HASH_SIZE]; + u8 text_hash[crypto::Sha256Generator::HashSize]; + u8 ro_hash[crypto::Sha256Generator::HashSize]; + u8 rw_hash[crypto::Sha256Generator::HashSize]; }; }; }; @@ -180,12 +180,19 @@ namespace ams::ldr { }; 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), + PoolPartition_Application = 0, + PoolPartition_Applet = 1, + PoolPartition_System = 2, + PoolPartition_SystemNonSecure = 3, }; + #if defined(ATMOSPHERE_OS_HORIZON) + static_assert(PoolPartition_Application == (svc::CreateProcessFlag_PoolPartitionApplication >> svc::CreateProcessFlag_PoolPartitionShift)); + static_assert(PoolPartition_Applet == (svc::CreateProcessFlag_PoolPartitionApplet >> svc::CreateProcessFlag_PoolPartitionShift)); + static_assert(PoolPartition_System == (svc::CreateProcessFlag_PoolPartitionSystem >> svc::CreateProcessFlag_PoolPartitionShift)); + static_assert(PoolPartition_SystemNonSecure == (svc::CreateProcessFlag_PoolPartitionSystemNonSecure >> svc::CreateProcessFlag_PoolPartitionShift)); + #endif + u8 signature[0x100]; u8 modulus[0x100]; u32 magic; @@ -219,12 +226,19 @@ namespace ams::ldr { }; 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), + AddressSpaceType_32Bit = 0, + AddressSpaceType_64BitDeprecated = 1, + AddressSpaceType_32BitWithoutAlias = 2, + AddressSpaceType_64Bit = 3, }; + #if defined(ATMOSPHERE_OS_HORIZON) + static_assert(AddressSpaceType_32Bit == (svc::CreateProcessFlag_AddressSpace32Bit >> svc::CreateProcessFlag_AddressSpaceShift)); + static_assert(AddressSpaceType_64BitDeprecated == (svc::CreateProcessFlag_AddressSpace64BitDeprecated >> svc::CreateProcessFlag_AddressSpaceShift)); + static_assert(AddressSpaceType_32BitWithoutAlias == (svc::CreateProcessFlag_AddressSpace32BitWithoutAlias >> svc::CreateProcessFlag_AddressSpaceShift)); + static_assert(AddressSpaceType_64Bit == (svc::CreateProcessFlag_AddressSpace64Bit >> svc::CreateProcessFlag_AddressSpaceShift)); + #endif + u32 magic; u32 signature_key_generation; u8 reserved_08[4]; diff --git a/libraries/libstratosphere/include/stratosphere/lr/lr_add_on_content_location_resolver.hpp b/libraries/libstratosphere/include/stratosphere/lr/lr_add_on_content_location_resolver.hpp index 18e4f686e..060a77f79 100644 --- a/libraries/libstratosphere/include/stratosphere/lr/lr_add_on_content_location_resolver.hpp +++ b/libraries/libstratosphere/include/stratosphere/lr/lr_add_on_content_location_resolver.hpp @@ -43,12 +43,12 @@ namespace ams::lr { public: /* Actual commands. */ Result ResolveAddOnContentPath(Path *out, ncm::DataId id) { - AMS_ASSERT(m_interface); + AMS_ASSERT(m_interface != nullptr); return m_interface->ResolveAddOnContentPath(out, id); } Result RegisterAddOnContentStorage(ncm::DataId id, ncm::ApplicationId application_id, ncm::StorageId storage_id) { - AMS_ASSERT(m_interface); + AMS_ASSERT(m_interface != nullptr); if (hos::GetVersion() >= hos::Version_9_0_0) { return m_interface->RegisterAddOnContentStorage(id, application_id, storage_id); } else { @@ -57,17 +57,17 @@ namespace ams::lr { } Result UnregisterAllAddOnContentPath() { - AMS_ASSERT(m_interface); + AMS_ASSERT(m_interface != nullptr); return m_interface->UnregisterAllAddOnContentPath(); } Result RefreshApplicationAddOnContent(const ncm::ApplicationId *ids, size_t num_ids) { - AMS_ASSERT(m_interface); + AMS_ASSERT(m_interface != nullptr); return m_interface->RefreshApplicationAddOnContent(sf::InArray(ids, num_ids)); } Result UnregisterApplicationAddOnContent(ncm::ApplicationId id) { - AMS_ASSERT(m_interface); + AMS_ASSERT(m_interface != nullptr); return m_interface->UnregisterApplicationAddOnContent(id); } }; diff --git a/libraries/libstratosphere/include/stratosphere/lr/lr_registered_location_resolver.hpp b/libraries/libstratosphere/include/stratosphere/lr/lr_registered_location_resolver.hpp index 127056fb7..7369c45db 100644 --- a/libraries/libstratosphere/include/stratosphere/lr/lr_registered_location_resolver.hpp +++ b/libraries/libstratosphere/include/stratosphere/lr/lr_registered_location_resolver.hpp @@ -43,12 +43,12 @@ namespace ams::lr { public: /* Actual commands. */ Result ResolveProgramPath(Path *out, ncm::ProgramId id) { - AMS_ASSERT(m_interface); + AMS_ASSERT(m_interface != nullptr); return m_interface->ResolveProgramPath(out, id); } Result RegisterProgramPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) { - AMS_ASSERT(m_interface); + AMS_ASSERT(m_interface != nullptr); if (hos::GetVersion() >= hos::Version_9_0_0) { return m_interface->RegisterProgramPath(path, id, owner_id); } else { @@ -57,12 +57,12 @@ namespace ams::lr { } Result UnregisterProgramPath(ncm::ProgramId id) { - AMS_ASSERT(m_interface); + AMS_ASSERT(m_interface != nullptr); return m_interface->UnregisterProgramPath(id); } void RedirectProgramPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) { - AMS_ASSERT(m_interface); + AMS_ASSERT(m_interface != nullptr); if (hos::GetVersion() >= hos::Version_9_0_0) { R_ABORT_UNLESS(m_interface->RedirectProgramPath(path, id, owner_id)); } else { @@ -71,12 +71,12 @@ namespace ams::lr { } Result ResolveHtmlDocumentPath(Path *out, ncm::ProgramId id) { - AMS_ASSERT(m_interface); + AMS_ASSERT(m_interface != nullptr); return m_interface->ResolveHtmlDocumentPath(out, id); } Result RegisterHtmlDocumentPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) { - AMS_ASSERT(m_interface); + AMS_ASSERT(m_interface != nullptr); if (hos::GetVersion() >= hos::Version_9_0_0) { return m_interface->RegisterHtmlDocumentPath(path, id, owner_id); } else { @@ -85,12 +85,12 @@ namespace ams::lr { } Result UnregisterHtmlDocumentPath(ncm::ProgramId id) { - AMS_ASSERT(m_interface); + AMS_ASSERT(m_interface != nullptr); return m_interface->UnregisterHtmlDocumentPath(id); } void RedirectHtmlDocumentPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) { - AMS_ASSERT(m_interface); + AMS_ASSERT(m_interface != nullptr); if (hos::GetVersion() >= hos::Version_9_0_0) { R_ABORT_UNLESS(m_interface->RedirectHtmlDocumentPath(path, id, owner_id)); } else { @@ -99,12 +99,12 @@ namespace ams::lr { } Result Refresh() { - AMS_ASSERT(m_interface); + AMS_ASSERT(m_interface != nullptr); return m_interface->Refresh(); } Result RefreshExcluding(const ncm::ProgramId *excluding_ids, size_t num_ids) { - AMS_ASSERT(m_interface); + AMS_ASSERT(m_interface != nullptr); return m_interface->RefreshExcluding(sf::InArray(excluding_ids, num_ids)); } diff --git a/libraries/libstratosphere/include/stratosphere/mem/impl/heap/mem_impl_heap_central_heap.hpp b/libraries/libstratosphere/include/stratosphere/mem/impl/heap/mem_impl_heap_central_heap.hpp index 0a8b46a49..2b66ce657 100644 --- a/libraries/libstratosphere/include/stratosphere/mem/impl/heap/mem_impl_heap_central_heap.hpp +++ b/libraries/libstratosphere/include/stratosphere/mem/impl/heap/mem_impl_heap_central_heap.hpp @@ -57,8 +57,6 @@ namespace ams::mem::impl::heap { errno_t WalkAllocatedPointers(HeapWalkCallback callback, void *user_data); errno_t QueryV(int query, std::va_list vl); errno_t Query(int query, ...); - private: - errno_t QueryVImpl(int query, std::va_list *vl_ptr); }; static_assert(sizeof(CentralHeap) <= sizeof(::ams::mem::impl::InternalCentralHeapStorage)); diff --git a/libraries/libstratosphere/include/stratosphere/ncm/ncm_program_id.hpp b/libraries/libstratosphere/include/stratosphere/ncm/ncm_program_id.hpp index 42da56128..ec3d22997 100644 --- a/libraries/libstratosphere/include/stratosphere/ncm/ncm_program_id.hpp +++ b/libraries/libstratosphere/include/stratosphere/ncm/ncm_program_id.hpp @@ -21,10 +21,12 @@ namespace ams::ncm { struct ProgramId { u64 value; + #if defined(ATMOSPHERE_OS_HORIZON) inline explicit operator svc::ProgramId() const { static_assert(sizeof(value) == sizeof(svc::ProgramId)); return { this->value }; } + #endif }; inline constexpr bool operator==(const ProgramId &lhs, const ProgramId &rhs) { diff --git a/libraries/libstratosphere/include/stratosphere/ncm/ncm_program_location.hpp b/libraries/libstratosphere/include/stratosphere/ncm/ncm_program_location.hpp index fd092650c..9dd88dc61 100644 --- a/libraries/libstratosphere/include/stratosphere/ncm/ncm_program_location.hpp +++ b/libraries/libstratosphere/include/stratosphere/ncm/ncm_program_location.hpp @@ -28,7 +28,9 @@ namespace ams::ncm { } }; static_assert(sizeof(ProgramLocation) == 0x10 && util::is_pod::value); - static_assert(sizeof(ProgramLocation) == sizeof(::NcmProgramLocation) && alignof(ProgramLocation) == alignof(::NcmProgramLocation), "ProgramLocation Libnx Compatibility"); + #if defined(ATMOSPHERE_OS_HORIZON) + static_assert(sizeof(ProgramLocation) == sizeof(::NcmProgramLocation) && alignof(ProgramLocation) == alignof(::NcmProgramLocation), "ProgramLocation Libnx Compatibility"); + #endif } diff --git a/libraries/libstratosphere/include/stratosphere/os.hpp b/libraries/libstratosphere/include/stratosphere/os.hpp index 42ab77ea8..3c4e84b27 100644 --- a/libraries/libstratosphere/include/stratosphere/os.hpp +++ b/libraries/libstratosphere/include/stratosphere/os.hpp @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include diff --git a/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_busy_mutex.hpp b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_busy_mutex.hpp index 9a5341213..7e827eb71 100644 --- a/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_busy_mutex.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_busy_mutex.hpp @@ -19,6 +19,8 @@ #if defined(ATMOSPHERE_OS_HORIZON) #include +#elif defined(ATMOSPHERE_OS_WINDOWS) || defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS) + #include #else #error "Unknown OS for ams::os::impl::InternalBusyMutexImpl" #endif @@ -31,10 +33,10 @@ namespace ams::os::impl { public: constexpr InternalBusyMutex() : m_impl() { /* ... */ } - constexpr void Initialize() { m_impl.Initialize(); } - constexpr void Finalize() { m_impl.Finalize(); } + ALWAYS_INLINE void Initialize() { m_impl.Initialize(); } + ALWAYS_INLINE void Finalize() { m_impl.Finalize(); } - bool IsLocked() const { return m_impl.IsLocked(); } + ALWAYS_INLINE bool IsLocked() const { return m_impl.IsLocked(); } ALWAYS_INLINE void Lock() { return m_impl.Lock(); } ALWAYS_INLINE bool TryLock() { return m_impl.TryLock(); } diff --git a/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_busy_mutex_impl.os.generic.hpp b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_busy_mutex_impl.os.generic.hpp new file mode 100644 index 000000000..3355eb36e --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_busy_mutex_impl.os.generic.hpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 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::impl { + + + class InternalBusyMutexImpl { + private: + std::atomic m_value{false}; + u8 m_padding[3]{}; + public: + constexpr InternalBusyMutexImpl() = default; + + ALWAYS_INLINE void Initialize() { m_value.store(false, std::memory_order_relaxed); } + + ALWAYS_INLINE void Finalize() { /* ... */ } + + ALWAYS_INLINE bool IsLocked() const { return m_value.load(std::memory_order_acquire); } + + ALWAYS_INLINE bool TryLock() { + bool expected = false; + return m_value.compare_exchange_weak(expected, true, std::memory_order_acquire, std::memory_order_acquire); + + } + + ALWAYS_INLINE void Lock() { + while (!this->TryLock()) { + #if defined(ATMOSPHERE_ARCH_X64) || defined(ATMOSPHERE_ARCH_X86) + _mm_pause(); + #elif defined(ATMOSPHERE_ARCH_ARM64) || defined(ATMOSPHERE_ARCH_ARM) + __asm__ __volatile__("yield" ::: "memory"); + #else + #error "InternalBusyMutex requires yield intrinsics" + #endif + } + } + + ALWAYS_INLINE void Unlock() { + m_value.store(false, std::memory_order_release); + } + }; + static_assert(sizeof(InternalBusyMutexImpl) == sizeof(u32)); + + #define AMS_OS_INTERNAL_BUSY_MUTEX_IMPL_CONSTANT_INITIALIZE_ARRAY_VALUES 0 + +} diff --git a/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_busy_mutex_impl.os.horizon.hpp b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_busy_mutex_impl.os.horizon.hpp index 860152fc9..b7caf76fa 100644 --- a/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_busy_mutex_impl.os.horizon.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_busy_mutex_impl.os.horizon.hpp @@ -35,4 +35,6 @@ namespace ams::os::impl { void Unlock(); }; + #define AMS_OS_INTERNAL_BUSY_MUTEX_IMPL_CONSTANT_INITIALIZE_ARRAY_VALUES 0 + } diff --git a/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_condition_variable.hpp b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_condition_variable.hpp index bfd3f462f..5d126e0e5 100644 --- a/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_condition_variable.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_condition_variable.hpp @@ -18,8 +18,12 @@ #include #include -#if defined(ATMOSPHERE_OS_HORIZON) +#if defined(AMS_OS_IMPL_USE_PTHREADS) + #include +#elif defined(ATMOSPHERE_OS_HORIZON) #include +#elif defined(ATMOSPHERE_OS_WINDOWS) + #include #else #error "Unknown OS for ams::os::impl::InternalConditionVariableImpl" #endif @@ -32,10 +36,14 @@ namespace ams::os::impl { public: constexpr InternalConditionVariable() : m_impl() { /* ... */ } - constexpr void Initialize() { + void Initialize() { m_impl.Initialize(); } + void Finalize() { + m_impl.Finalize(); + } + void Signal() { m_impl.Signal(); } diff --git a/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_condition_variable_impl.os.horizon.hpp b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_condition_variable_impl.os.horizon.hpp index 2ea11557d..3adc45f6f 100644 --- a/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_condition_variable_impl.os.horizon.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_condition_variable_impl.os.horizon.hpp @@ -32,6 +32,7 @@ namespace ams::os::impl { constexpr void Initialize() { m_value = 0; } + constexpr void Finalize() { /* ... */ } void Signal(); void Broadcast(); @@ -40,4 +41,8 @@ namespace ams::os::impl { ConditionVariableStatus TimedWait(InternalCriticalSection *cs, const TimeoutHelper &timeout_helper); }; + using InternalConditionVariableStorageTypeForConstantInitialize = u32; + + #define AMS_OS_INTERNAL_CONDITION_VARIABLE_IMPL_CONSTANT_INITIALIZER {0} + } diff --git a/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_condition_variable_impl.os.windows.hpp b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_condition_variable_impl.os.windows.hpp new file mode 100644 index 000000000..f0a5e8679 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_condition_variable_impl.os.windows.hpp @@ -0,0 +1,67 @@ +/* + * Copyright (c) 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 +#include + +namespace ams::os::impl { + + class TimeoutHelper; + + struct WindowsConditionVariable; + + using WindowsConditionVariableStorage = util::TypedStorage; + + #if defined(ATMOSPHERE_ARCH_X64) + #define AMS_OS_WINDOWS_CONDITION_VARIABLE_CONSTANT_INITIALIZE_ARRAY_VALUES 0, 0 + #elif defined(ATMOSPHERE_ARCH_X86) + #define AMS_OS_WINDOWS_CONDITION_VARIABLE_CONSTANT_INITIALIZE_ARRAY_VALUES 0 + #else + #error "Unknown architecture for WindowsConditionVariable initializer" + #endif + + class InternalConditionVariableImpl { + private: + u32 m_value; + public: + union { + s32 _arr[sizeof(WindowsConditionVariableStorage) / sizeof(s32)]; + WindowsConditionVariableStorage m_windows_cv_storage; + }; + constexpr InternalConditionVariableImpl() : _arr{AMS_OS_WINDOWS_CONDITION_VARIABLE_CONSTANT_INITIALIZE_ARRAY_VALUES} { /* ... */ } + constexpr ~InternalConditionVariableImpl() { + if (!std::is_constant_evaluated()) { + this->Finalize(); + } + } + + void Initialize(); + void Finalize(); + + void Signal(); + void Broadcast(); + + void Wait(InternalCriticalSection *cs); + ConditionVariableStatus TimedWait(InternalCriticalSection *cs, const TimeoutHelper &timeout_helper); + }; + + struct InternalConditionVariableStorageTypeForConstantInitialize { s32 _arr[sizeof(WindowsConditionVariableStorage) / sizeof(s32)]; }; + + #define AMS_OS_INTERNAL_CONDITION_VARIABLE_IMPL_CONSTANT_INITIALIZER { AMS_OS_WINDOWS_CONDITION_VARIABLE_CONSTANT_INITIALIZE_ARRAY_VALUES } + +} diff --git a/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_condition_variable_impl.pthread.hpp b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_condition_variable_impl.pthread.hpp new file mode 100644 index 000000000..a791d7de5 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_condition_variable_impl.pthread.hpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 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 +#include + +namespace ams::os::impl { + + class TimeoutHelper; + + class InternalConditionVariableImpl { + private: + pthread_cond_t m_pthread_cond = PTHREAD_COND_INITIALIZER; + public: + constexpr InternalConditionVariableImpl() = default; + + constexpr ~InternalConditionVariableImpl() { + if (!std::is_constant_evaluated()) { + this->Finalize(); + } + } + + void Initialize(); + void Finalize(); + + void Signal(); + void Broadcast(); + + void Wait(InternalCriticalSection *cs); + ConditionVariableStatus TimedWait(InternalCriticalSection *cs, const TimeoutHelper &timeout_helper); + }; + + using InternalConditionVariableStorageTypeForConstantInitialize = pthread_cond_t; + + #define AMS_OS_INTERNAL_CONDITION_VARIABLE_IMPL_CONSTANT_INITIALIZER ._storage_for_constant_initialize = PTHREAD_COND_INITIALIZER + +} diff --git a/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_critical_section.hpp b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_critical_section.hpp index 89688a913..6335f3a80 100644 --- a/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_critical_section.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_critical_section.hpp @@ -17,8 +17,12 @@ #pragma once #include -#if defined(ATMOSPHERE_OS_HORIZON) +#if defined(AMS_OS_IMPL_USE_PTHREADS) + #include +#elif defined(ATMOSPHERE_OS_HORIZON) #include +#elif defined(ATMOSPHERE_OS_WINDOWS) + #include #else #error "Unknown OS for ams::os::impl::InternalCriticalSectionImpl" #endif @@ -31,14 +35,16 @@ namespace ams::os::impl { public: constexpr InternalCriticalSection() : m_impl() { /* ... */ } - constexpr void Initialize() { m_impl.Initialize(); } - constexpr void Finalize() { m_impl.Finalize(); } + void Initialize() { m_impl.Initialize(); } + void Finalize() { m_impl.Finalize(); } void Enter() { return m_impl.Enter(); } bool TryEnter() { return m_impl.TryEnter(); } void Leave() { return m_impl.Leave(); } + #if defined(AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD) bool IsLockedByCurrentThread() const { return m_impl.IsLockedByCurrentThread(); } + #endif ALWAYS_INLINE void Lock() { return this->Enter(); } ALWAYS_INLINE bool TryLock() { return this->TryEnter(); } diff --git a/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_critical_section_impl.os.horizon.hpp b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_critical_section_impl.os.horizon.hpp index e9f49d219..81e997672 100644 --- a/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_critical_section_impl.os.horizon.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_critical_section_impl.os.horizon.hpp @@ -55,4 +55,10 @@ namespace ams::os::impl { ALWAYS_INLINE void unlock() { return this->Unlock(); } }; + using InternalCriticalSectionStorageTypeForConstantInitialize = u32; + + #define AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CONSTANT_INITIALIZER {0} + + #define AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD + } diff --git a/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_critical_section_impl.os.windows.hpp b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_critical_section_impl.os.windows.hpp new file mode 100644 index 000000000..221b99fba --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_critical_section_impl.os.windows.hpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 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::impl { + + class InternalConditionVariableImpl; + + struct WindowsCriticalSection; + + using WindowsCriticalSectionStorage = util::TypedStorage; + + #if defined(ATMOSPHERE_ARCH_X64) + #define AMS_OS_WINDOWS_CRITICAL_SECTION_CONSTANT_INITIALIZE_ARRAY_VALUES -1, -1, -1, 0, 0, 0, 0, 0, 0, 0 + #elif defined(ATMOSPHERE_ARCH_X86) + #define AMS_OS_WINDOWS_CRITICAL_SECTION_CONSTANT_INITIALIZE_ARRAY_VALUES -1, -1, 0, 0, 0, 0 + #else + #error "Unknown architecture for WindowsCriticalSection initializer" + #endif + + class InternalCriticalSectionImpl { + private: + friend class InternalConditionVariableImpl; + private: + union { + s32 _arr[sizeof(WindowsCriticalSectionStorage) / sizeof(s32)]; + WindowsCriticalSectionStorage m_windows_critical_section_storage; + }; + public: + constexpr InternalCriticalSectionImpl() : _arr{AMS_OS_WINDOWS_CRITICAL_SECTION_CONSTANT_INITIALIZE_ARRAY_VALUES} { /* ... */ } + constexpr ~InternalCriticalSectionImpl() { + if (!std::is_constant_evaluated()) { + this->Finalize(); + } + } + + void Initialize(); + void Finalize(); + + void Enter(); + bool TryEnter(); + void Leave(); + + bool IsLockedByCurrentThread() const; + + ALWAYS_INLINE void Lock() { return this->Enter(); } + ALWAYS_INLINE bool TryLock() { return this->TryEnter(); } + ALWAYS_INLINE void Unlock() { return this->Leave(); } + + ALWAYS_INLINE void lock() { return this->Lock(); } + ALWAYS_INLINE bool try_lock() { return this->TryLock(); } + ALWAYS_INLINE void unlock() { return this->Unlock(); } + }; + + struct InternalCriticalSectionStorageTypeForConstantInitialize { s32 _arr[sizeof(WindowsCriticalSectionStorage) / sizeof(s32)]; }; + + #define AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CONSTANT_INITIALIZER { AMS_OS_WINDOWS_CRITICAL_SECTION_CONSTANT_INITIALIZE_ARRAY_VALUES } + + #define AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD + +} diff --git a/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_critical_section_impl.pthread.hpp b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_critical_section_impl.pthread.hpp new file mode 100644 index 000000000..61f918104 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_critical_section_impl.pthread.hpp @@ -0,0 +1,75 @@ +/* + * Copyright (c) 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 + +namespace ams::os::impl { + + class InternalConditionVariableImpl; + + /* NOTE: macOS (and possibly other targets) do not provide adaptive mutex. */ + #if defined(PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP) + #define AMS_OS_IMPL_PTHREAD_MUTEX_INITIALIZER PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP + #else + #define AMS_OS_IMPL_PTHREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER + #endif + + #if defined(ATMOSPHERE_OS_LINUX) + #define AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD + #else + //#define AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD + #endif + + class InternalCriticalSectionImpl { + private: + friend class InternalConditionVariableImpl; + private: + pthread_mutex_t m_pthread_mutex = AMS_OS_IMPL_PTHREAD_MUTEX_INITIALIZER; + public: + constexpr InternalCriticalSectionImpl() = default; + constexpr ~InternalCriticalSectionImpl() { + if (!std::is_constant_evaluated()) { + this->Finalize(); + } + } + + void Initialize(); + void Finalize(); + + void Enter(); + bool TryEnter(); + void Leave(); + + #if defined(AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD) + bool IsLockedByCurrentThread() const; + #endif + + ALWAYS_INLINE void Lock() { return this->Enter(); } + ALWAYS_INLINE bool TryLock() { return this->TryEnter(); } + ALWAYS_INLINE void Unlock() { return this->Leave(); } + + ALWAYS_INLINE void lock() { return this->Lock(); } + ALWAYS_INLINE bool try_lock() { return this->TryLock(); } + ALWAYS_INLINE void unlock() { return this->Unlock(); } + }; + + using InternalCriticalSectionStorageTypeForConstantInitialize = pthread_mutex_t; + + #define AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CONSTANT_INITIALIZER ._storage_for_constant_initialize = AMS_OS_IMPL_PTHREAD_MUTEX_INITIALIZER + +} diff --git a/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_light_event.hpp b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_light_event.hpp index ea691de0c..c0d2e0d4e 100644 --- a/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_light_event.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_light_event.hpp @@ -19,6 +19,8 @@ #if defined(ATMOSPHERE_OS_HORIZON) #include +#elif defined(ATMOSPHERE_OS_WINDOWS) || defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS) + #include #else #error "Unknown OS for ams::os::impl::InternalLightEventImpl" #endif diff --git a/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_light_event_impl.os.generic.hpp b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_light_event_impl.os.generic.hpp new file mode 100644 index 000000000..ff57c51cd --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_light_event_impl.os.generic.hpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 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 +#include + +namespace ams::os::impl { + + class TimeoutHelper; + + class InternalLightEventImpl { + private: + u16 m_counter_low; + u8 m_counter_high; + std::atomic m_signal_state; + InternalCriticalSection m_cs; + InternalConditionVariable m_cv; + public: + explicit InternalLightEventImpl(bool signaled) { this->Initialize(signaled); } + ~InternalLightEventImpl() { this->Finalize(); } + + void Initialize(bool signaled); + void Finalize(); + + void SignalWithAutoClear(); + void SignalWithManualClear(); + + void Clear(); + + void WaitWithAutoClear(); + void WaitWithManualClear(); + + bool TryWaitWithAutoClear(); + bool TryWaitWithManualClear(); + + bool TimedWaitWithAutoClear(const TimeoutHelper &timeout_helper); + bool TimedWaitWithManualClear(const TimeoutHelper &timeout_helper); + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_rw_busy_mutex.hpp b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_rw_busy_mutex.hpp index 35fb9758f..6ee8fb8e7 100644 --- a/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_rw_busy_mutex.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_rw_busy_mutex.hpp @@ -19,6 +19,12 @@ #if defined(ATMOSPHERE_OS_HORIZON) #include +#elif defined(ATMOSPHERE_OS_WINDOWS) + #include +#elif defined(ATMOSPHERE_OS_LINUX) + #include +#elif defined(ATMOSPHERE_OS_MACOS) + #include #else #error "Unknown OS for ams::os::impl::InternalReaderWriterBusyMutexImpl" #endif diff --git a/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_rw_busy_mutex_impl.os.horizon.hpp b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_rw_busy_mutex_impl.os.horizon.hpp index 78f50bccc..e8895f4cb 100644 --- a/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_rw_busy_mutex_impl.os.horizon.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_rw_busy_mutex_impl.os.horizon.hpp @@ -16,6 +16,7 @@ #pragma once #include +#include namespace ams::os::impl { @@ -34,4 +35,6 @@ namespace ams::os::impl { void ReleaseWriteLock(); }; + #define AMS_OS_INTERNAL_READER_WRITER_BUSY_MUTEX_IMPL_CONSTANT_INITIALIZER {0} + } diff --git a/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_rw_busy_mutex_impl.os.linux.hpp b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_rw_busy_mutex_impl.os.linux.hpp new file mode 100644 index 000000000..7d3d6221a --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_rw_busy_mutex_impl.os.linux.hpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 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 + +namespace ams::os::impl { + + /* NOTE: The current implementation is based on load/linked store conditional, we should figure out how to do this on x64. */ + + class InternalReaderWriterBusyMutexImpl { + private: + u32 m_value; + public: + constexpr InternalReaderWriterBusyMutexImpl() : m_value(0) { if (!std::is_constant_evaluated()) { AMS_ABORT("TODO: Linux InternalReaderWriterBusyMutexImpl"); } } + + constexpr void Initialize() { m_value = 0; if (!std::is_constant_evaluated()) { AMS_ABORT("TODO: Linux InternalReaderWriterBusyMutexImpl"); } } + + void AcquireReadLock() { AMS_ABORT("TODO: Linux InternalReaderWriterBusyMutexImpl"); } + void ReleaseReadLock() { AMS_ABORT("TODO: Linux InternalReaderWriterBusyMutexImpl"); } + + void AcquireWriteLock() { AMS_ABORT("TODO: Linux InternalReaderWriterBusyMutexImpl"); } + void ReleaseWriteLock() { AMS_ABORT("TODO: Linux InternalReaderWriterBusyMutexImpl"); } + }; + + #define AMS_OS_INTERNAL_READER_WRITER_BUSY_MUTEX_IMPL_CONSTANT_INITIALIZER {0} + +} diff --git a/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_rw_busy_mutex_impl.os.macos.hpp b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_rw_busy_mutex_impl.os.macos.hpp new file mode 100644 index 000000000..a10b99a6e --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_rw_busy_mutex_impl.os.macos.hpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 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 + +namespace ams::os::impl { + + /* NOTE: The current implementation is based on load/linked store conditional, we should figure out how to do this on x64. */ + + class InternalReaderWriterBusyMutexImpl { + private: + u32 m_value; + public: + constexpr InternalReaderWriterBusyMutexImpl() : m_value(0) { if (!std::is_constant_evaluated()) { AMS_ABORT("TODO: macOS InternalReaderWriterBusyMutexImpl"); } } + + constexpr void Initialize() { m_value = 0; if (!std::is_constant_evaluated()) { AMS_ABORT("TODO: macOS InternalReaderWriterBusyMutexImpl"); } } + + void AcquireReadLock() { AMS_ABORT("TODO: macOS InternalReaderWriterBusyMutexImpl"); } + void ReleaseReadLock() { AMS_ABORT("TODO: macOS InternalReaderWriterBusyMutexImpl"); } + + void AcquireWriteLock() { AMS_ABORT("TODO: macOS InternalReaderWriterBusyMutexImpl"); } + void ReleaseWriteLock() { AMS_ABORT("TODO: macOS InternalReaderWriterBusyMutexImpl"); } + }; + + #define AMS_OS_INTERNAL_READER_WRITER_BUSY_MUTEX_IMPL_CONSTANT_INITIALIZER {0} + +} diff --git a/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_rw_busy_mutex_impl.os.windows.hpp b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_rw_busy_mutex_impl.os.windows.hpp new file mode 100644 index 000000000..6882f8d9e --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_rw_busy_mutex_impl.os.windows.hpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 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 + +namespace ams::os::impl { + + /* NOTE: The current implementation is based on load/linked store conditional, we should figure out how to do this on x64. */ + /* We could also consider using https://docs.microsoft.com/en-us/windows/win32/sync/slim-reader-writer--srw--locks */ + + class InternalReaderWriterBusyMutexImpl { + private: + u32 m_value; + public: + constexpr InternalReaderWriterBusyMutexImpl() : m_value(0) { if (!std::is_constant_evaluated()) { AMS_ABORT("TODO: Windows InternalReaderWriterBusyMutexImpl"); } } + + constexpr void Initialize() { m_value = 0; if (!std::is_constant_evaluated()) { AMS_ABORT("TODO: Windows InternalReaderWriterBusyMutexImpl"); } } + + void AcquireReadLock() { AMS_ABORT("TODO: Windows InternalReaderWriterBusyMutexImpl"); } + void ReleaseReadLock() { AMS_ABORT("TODO: Windows InternalReaderWriterBusyMutexImpl"); } + + void AcquireWriteLock() { AMS_ABORT("TODO: Windows InternalReaderWriterBusyMutexImpl"); } + void ReleaseWriteLock() { AMS_ABORT("TODO: Windows InternalReaderWriterBusyMutexImpl"); } + }; + + #define AMS_OS_INTERNAL_READER_WRITER_BUSY_MUTEX_IMPL_CONSTANT_INITIALIZER {0} + +} diff --git a/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_rw_busy_mutex_value.hpp b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_rw_busy_mutex_value.hpp new file mode 100644 index 000000000..526019ece --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/impl/os_internal_rw_busy_mutex_value.hpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 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::impl { + + #if defined(ATMOSPHERE_OS_HORIZON) || defined(ATMOSPHERE_OS_WINDOWS) || defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS) + class InternalReaderWriterBusyMutexValue { + public: + static constexpr inline u8 WriterCountMax = std::numeric_limits::max(); + + static constexpr ALWAYS_INLINE u16 GetReaderCount(u32 v) { + return static_cast(v >> 0); + } + + static constexpr ALWAYS_INLINE u8 GetWriterCurrent(u32 v) { + return static_cast(v >> 16); + } + + static constexpr ALWAYS_INLINE u8 GetWriterNext(u32 v) { + return static_cast(v >> 24); + } + + static constexpr ALWAYS_INLINE u32 IncrementWriterNext(u32 v) { + return v + (1u << 24); + } + + static constexpr ALWAYS_INLINE bool IsWriteLocked(u32 v) { + return GetWriterCurrent(v) != GetWriterNext(v); + } + + static ALWAYS_INLINE u8 *GetWriterCurrentPointer(u32 *p) { + if constexpr (util::IsLittleEndian()) { + return reinterpret_cast(reinterpret_cast(p)) + 2; + } else { + return reinterpret_cast(reinterpret_cast(p)) + 1; + } + } + }; + #else + #error "Unknown OS for ams::os::impl::InternalReaderWriterBusyMutexValue" + #endif + +} diff --git a/libraries/libstratosphere/include/stratosphere/os/impl/os_memory_fence_api.os.generic.hpp b/libraries/libstratosphere/include/stratosphere/os/impl/os_memory_fence_api.os.generic.hpp new file mode 100644 index 000000000..072d7bfcc --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/impl/os_memory_fence_api.os.generic.hpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 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 +#if defined(ATMOSPHERE_ARCH_X64) +#include +#include +#endif + +namespace ams::os::impl { + + #if defined(ATMOSPHERE_ARCH_X64) + + ALWAYS_INLINE void FenceMemoryStoreStore() { __asm__ __volatile__("" ::: "memory"); _mm_sfence(); } + ALWAYS_INLINE void FenceMemoryStoreLoad() { __asm__ __volatile__("" ::: "memory"); _mm_mfence(); } + ALWAYS_INLINE void FenceMemoryStoreAny() { __asm__ __volatile__("" ::: "memory"); _mm_mfence(); } + + ALWAYS_INLINE void FenceMemoryLoadStore() { __asm__ __volatile__("" ::: "memory"); _mm_mfence(); } + ALWAYS_INLINE void FenceMemoryLoadLoad() { __asm__ __volatile__("" ::: "memory"); _mm_lfence(); } + ALWAYS_INLINE void FenceMemoryLoadAny() { __asm__ __volatile__("" ::: "memory"); _mm_mfence(); } + + ALWAYS_INLINE void FenceMemoryAnyStore() { __asm__ __volatile__("" ::: "memory"); _mm_mfence(); } + ALWAYS_INLINE void FenceMemoryAnyLoad() { __asm__ __volatile__("" ::: "memory"); _mm_mfence(); } + ALWAYS_INLINE void FenceMemoryAnyAny() {__asm__ __volatile__("" ::: "memory"); _mm_mfence(); } + + #elif defined(ATMOSPHERE_ARCH_ARM64) + + ALWAYS_INLINE void FenceMemoryStoreStore() { __asm__ __volatile__("dmb ishst" ::: "memory"); } + ALWAYS_INLINE void FenceMemoryStoreLoad() { __asm__ __volatile__("dmb ish" ::: "memory"); } + ALWAYS_INLINE void FenceMemoryStoreAny() { __asm__ __volatile__("dmb ish" ::: "memory"); } + + ALWAYS_INLINE void FenceMemoryLoadStore() { __asm__ __volatile__("dmb ishld" ::: "memory"); } + ALWAYS_INLINE void FenceMemoryLoadLoad() { __asm__ __volatile__("dmb ishld" ::: "memory"); } + ALWAYS_INLINE void FenceMemoryLoadAny() { __asm__ __volatile__("dmb ishld" ::: "memory"); } + + ALWAYS_INLINE void FenceMemoryAnyStore() { __asm__ __volatile__("dmb ish" ::: "memory"); } + ALWAYS_INLINE void FenceMemoryAnyLoad() { __asm__ __volatile__("dmb ish" ::: "memory"); } + ALWAYS_INLINE void FenceMemoryAnyAny() { __asm__ __volatile__("dmb ish" ::: "memory"); } + + #else + + #error "Unknown architecture for os::impl::FenceMemory* (Generic)" + + #endif + +} diff --git a/libraries/libstratosphere/include/stratosphere/os/os_busy_mutex.hpp b/libraries/libstratosphere/include/stratosphere/os/os_busy_mutex.hpp index e3bcb60d3..8b314f8f1 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_busy_mutex.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_busy_mutex.hpp @@ -26,7 +26,7 @@ namespace ams::os { private: BusyMutexType m_mutex; public: - constexpr explicit BusyMutex() : m_mutex{::ams::os::BusyMutexType::State_Initialized, nullptr, {{}}} { /* ... */ } + constexpr explicit BusyMutex() : m_mutex{::ams::os::BusyMutexType::State_Initialized, nullptr, {{AMS_OS_INTERNAL_BUSY_MUTEX_IMPL_CONSTANT_INITIALIZE_ARRAY_VALUES}}} { /* ... */ } ~BusyMutex() { FinalizeBusyMutex(std::addressof(m_mutex)); } diff --git a/libraries/libstratosphere/include/stratosphere/os/os_common_config.hpp b/libraries/libstratosphere/include/stratosphere/os/os_common_config.hpp new file mode 100644 index 000000000..02653ed7a --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_common_config.hpp @@ -0,0 +1,27 @@ +/* + * Copyright (c) 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 { + + #if defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS) + #define AMS_OS_IMPL_USE_PTHREADS + #elif defined(ATMOSPHERE_OS_WINDOWS) + //#define AMS_OS_IMPL_USE_PTHREADS + #endif + +} diff --git a/libraries/libstratosphere/include/stratosphere/os/os_common_types.hpp b/libraries/libstratosphere/include/stratosphere/os/os_common_types.hpp index e90c0a3fd..599d4aa0c 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_common_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_common_types.hpp @@ -15,6 +15,11 @@ */ #pragma once #include +#include + +#if defined(AMS_OS_IMPL_USE_PTHREADS) +#include +#endif namespace ams::os { diff --git a/libraries/libstratosphere/include/stratosphere/os/os_condition_variable.hpp b/libraries/libstratosphere/include/stratosphere/os/os_condition_variable.hpp index 038e2abe4..f77fab9c5 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_condition_variable.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_condition_variable.hpp @@ -29,7 +29,7 @@ namespace ams::os { private: ConditionVariableType m_cv; public: - constexpr ConditionVariable() : m_cv{::ams::os::ConditionVariableType::State_Initialized, {{0}}} { /* ... */ } + constexpr ConditionVariable() : m_cv{::ams::os::ConditionVariableType::State_Initialized, {AMS_OS_INTERNAL_CONDITION_VARIABLE_IMPL_CONSTANT_INITIALIZER}} { /* ... */ } ~ConditionVariable() { FinalizeConditionVariable(std::addressof(m_cv)); } diff --git a/libraries/libstratosphere/include/stratosphere/os/os_condition_variable_types.hpp b/libraries/libstratosphere/include/stratosphere/os/os_condition_variable_types.hpp index 8979a86ce..fbb4f459c 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_condition_variable_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_condition_variable_types.hpp @@ -30,6 +30,7 @@ namespace ams::os { union { s32 _arr[sizeof(impl::InternalConditionVariableStorage) / sizeof(s32)]; impl::InternalConditionVariableStorage _storage; + impl::InternalConditionVariableStorageTypeForConstantInitialize _storage_for_constant_initialize; }; }; static_assert(std::is_trivial::value); diff --git a/libraries/libstratosphere/include/stratosphere/os/os_interrupt_event_common.hpp b/libraries/libstratosphere/include/stratosphere/os/os_interrupt_event_common.hpp index 08d862396..68e087e07 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_interrupt_event_common.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_interrupt_event_common.hpp @@ -18,6 +18,14 @@ namespace ams::os { + #if defined(ATMOSPHERE_OS_HORIZON) using InterruptName = s32; + #elif defined(ATMOSPHERE_OS_WINDOWS) + using InterruptName = const char *; + #elif defined(ATMOSPHERE_OS_LINUX) + using InterruptName = const char *; + #elif defined(ATMOSPHERE_OS_MACOS) + using InterruptName = const char *; + #endif } \ No newline at end of file diff --git a/libraries/libstratosphere/include/stratosphere/os/os_memory_common.hpp b/libraries/libstratosphere/include/stratosphere/os/os_memory_common.hpp index 92ba3dd5d..3668a2ab3 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_memory_common.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_memory_common.hpp @@ -30,7 +30,15 @@ namespace ams::os { MemoryPermission_ReadWrite = MemoryPermission_ReadOnly | MemoryPermission_WriteOnly, }; - using MemoryMapping = svc::MemoryMapping; - using enum svc::MemoryMapping; + #if defined(ATMOSPHERE_OS_HORIZON) + using MemoryMapping = svc::MemoryMapping; + using enum svc::MemoryMapping; + #else + enum MemoryMapping : u32 { + MemoryMapping_IoRegister = 0, + MemoryMapping_Uncached = 1, + MemoryMapping_Memory = 2, + }; + #endif } diff --git a/libraries/libstratosphere/include/stratosphere/os/os_memory_fence_api.hpp b/libraries/libstratosphere/include/stratosphere/os/os_memory_fence_api.hpp index 5820dedcd..b62e4186b 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_memory_fence_api.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_memory_fence_api.hpp @@ -18,6 +18,8 @@ #if defined(ATMOSPHERE_OS_HORIZON) #include +#elif defined(ATMOSPHERE_OS_WINDOWS) || defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS) + #include #else #error "Unknown os for os::MemoryFence*" #endif diff --git a/libraries/libstratosphere/include/stratosphere/os/os_multiple_wait_types.hpp b/libraries/libstratosphere/include/stratosphere/os/os_multiple_wait_types.hpp index 233362004..04ab4742b 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_multiple_wait_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_multiple_wait_types.hpp @@ -34,7 +34,7 @@ namespace ams::os { u8 state; bool is_waiting; - util::TypedStorage impl_storage; + util::TypedStorage impl_storage; }; static_assert(std::is_trivial::value); diff --git a/libraries/libstratosphere/include/stratosphere/os/os_mutex.hpp b/libraries/libstratosphere/include/stratosphere/os/os_mutex.hpp index 8842b1c56..ac2678e7c 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_mutex.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_mutex.hpp @@ -27,7 +27,7 @@ namespace ams::os { private: MutexType m_mutex; public: - constexpr explicit Mutex(bool recursive) : m_mutex{::ams::os::MutexType::State_Initialized, recursive, 0, 0, nullptr, {{0}}} { /* ... */ } + constexpr explicit Mutex(bool recursive) : m_mutex{::ams::os::MutexType::State_Initialized, recursive, 0, 0, nullptr, { AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CONSTANT_INITIALIZER } } { /* ... */ } ~Mutex() { FinalizeMutex(std::addressof(m_mutex)); } diff --git a/libraries/libstratosphere/include/stratosphere/os/os_mutex_types.hpp b/libraries/libstratosphere/include/stratosphere/os/os_mutex_types.hpp index b94af1c30..69c750d2e 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_mutex_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_mutex_types.hpp @@ -36,6 +36,7 @@ namespace ams::os { union { s32 _arr[sizeof(impl::InternalCriticalSectionStorage) / sizeof(s32)]; impl::InternalCriticalSectionStorage _storage; + impl::InternalCriticalSectionStorageTypeForConstantInitialize _storage_for_constant_initialize; }; }; static_assert(std::is_trivial::value); diff --git a/libraries/libstratosphere/include/stratosphere/os/os_native_handle_types.hpp b/libraries/libstratosphere/include/stratosphere/os/os_native_handle_types.hpp index fc033e141..32b12031a 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_native_handle_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_native_handle_types.hpp @@ -20,10 +20,24 @@ namespace ams::os { #if defined(ATMOSPHERE_OS_HORIZON) + using NativeHandle = svc::Handle; static_assert(std::unsigned_integral); constexpr inline NativeHandle InvalidNativeHandle = svc::InvalidHandle; + + #elif defined(ATMOSPHERE_OS_WINDOWS) + + using NativeHandle = void *; + + constexpr inline NativeHandle InvalidNativeHandle = nullptr; + + #elif defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS) + + using NativeHandle = s32; + + constexpr inline NativeHandle InvalidNativeHandle = -1; + #else #error "Unknown OS for os::NativeHandle" #endif diff --git a/libraries/libstratosphere/include/stratosphere/os/os_rw_busy_mutex.hpp b/libraries/libstratosphere/include/stratosphere/os/os_rw_busy_mutex.hpp index 2af94fe1d..86d98da47 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_rw_busy_mutex.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_rw_busy_mutex.hpp @@ -26,7 +26,7 @@ namespace ams::os { private: ReaderWriterBusyMutexType m_rw_mutex; public: - constexpr explicit ReaderWriterBusyMutex() : m_rw_mutex{{0}} { /* ... */ } + constexpr explicit ReaderWriterBusyMutex() : m_rw_mutex{ { AMS_OS_INTERNAL_READER_WRITER_BUSY_MUTEX_IMPL_CONSTANT_INITIALIZER } } { /* ... */ } void AcquireReadLock() { return os::AcquireReadLockBusyMutex(std::addressof(m_rw_mutex)); diff --git a/libraries/libstratosphere/include/stratosphere/os/os_rw_lock.hpp b/libraries/libstratosphere/include/stratosphere/os/os_rw_lock.hpp index e36af0cb4..1bb1f9944 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_rw_lock.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_rw_lock.hpp @@ -27,9 +27,15 @@ namespace ams::os { private: ReaderWriterLockType m_rw_lock; public: - constexpr explicit ReaderWriterLock() : m_rw_lock{{}, 0, ::ams::os::ReaderWriterLockType::State_Initialized, nullptr, 0, {}, {}} { /* ... */ } + constexpr explicit ReaderWriterLock() : m_rw_lock {{ { MakeConstantInitializedLockCount(), 0 } }, 0, ::ams::os::ReaderWriterLockType::State_Initialized, nullptr, 0, {AMS_OS_INTERNAL_CONDITION_VARIABLE_IMPL_CONSTANT_INITIALIZER}, {AMS_OS_INTERNAL_CONDITION_VARIABLE_IMPL_CONSTANT_INITIALIZER} } { + /* ... */ + } - ~ReaderWriterLock() { os::FinalizeReaderWriterLock(std::addressof(m_rw_lock)); } + constexpr ~ReaderWriterLock() { + if (!std::is_constant_evaluated()) { + os::FinalizeReaderWriterLock(std::addressof(m_rw_lock)); + } + } void AcquireReadLock() { return os::AcquireReadLock(std::addressof(m_rw_lock)); diff --git a/libraries/libstratosphere/include/stratosphere/os/os_rw_lock_api.hpp b/libraries/libstratosphere/include/stratosphere/os/os_rw_lock_api.hpp index c5ae44897..a796cf43d 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_rw_lock_api.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_rw_lock_api.hpp @@ -22,7 +22,7 @@ namespace ams::os { struct ReaderWriterLockType; - void InitalizeReaderWriterLock(ReaderWriterLockType *rw_lock); + void InitializeReaderWriterLock(ReaderWriterLockType *rw_lock); void FinalizeReaderWriterLock(ReaderWriterLockType *rw_lock); void AcquireReadLock(ReaderWriterLockType *rw_lock); diff --git a/libraries/libstratosphere/include/stratosphere/os/os_rw_lock_types.hpp b/libraries/libstratosphere/include/stratosphere/os/os_rw_lock_types.hpp index 98b534981..51efc5c32 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_rw_lock_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_rw_lock_types.hpp @@ -33,6 +33,7 @@ namespace ams::os { union { s32 _arr[sizeof(impl::InternalCriticalSectionStorage) / sizeof(s32)]; impl::InternalCriticalSectionStorage cs_storage; + impl::InternalCriticalSectionStorageTypeForConstantInitialize _storage_for_constant_initialize; }; util::BitPack32 counter; }; @@ -59,12 +60,29 @@ namespace ams::os { union { s32 _arr[sizeof(impl::InternalConditionVariableStorage) / sizeof(s32)]; impl::InternalConditionVariableStorage _storage; + impl::InternalConditionVariableStorageTypeForConstantInitialize _storage_for_constant_initialize; } cv_read_lock; union { s32 _arr[sizeof(impl::InternalConditionVariableStorage) / sizeof(s32)]; impl::InternalConditionVariableStorage _storage; + impl::InternalConditionVariableStorageTypeForConstantInitialize _storage_for_constant_initialize; } cv_write_lock; }; static_assert(std::is_trivial::value); + #if defined(ATMOSPHERE_OS_HORIZON) + consteval ReaderWriterLockType::LockCount MakeConstantInitializedLockCount() { return {}; } + #elif defined(ATMOSPHERE_OS_WINDOWS) || defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS) + /* If windows/linux, require that the lock counter have guaranteed alignment, so that we may constant-initialize. */ + static_assert(alignof(ReaderWriterLockType) == sizeof(u64)); + consteval ReaderWriterLockType::LockCount MakeConstantInitializedLockCount() { + return ReaderWriterLockType::LockCount { + { AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CONSTANT_INITIALIZER }, + {}, + }; + } + #else + #error "Unknown OS for constant initialized RW-lock LockCount" + #endif + } diff --git a/libraries/libstratosphere/include/stratosphere/os/os_sdk_condition_variable.hpp b/libraries/libstratosphere/include/stratosphere/os/os_sdk_condition_variable.hpp index c69325dd0..55d3ea775 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_sdk_condition_variable.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_sdk_condition_variable.hpp @@ -26,6 +26,7 @@ namespace ams::os { union { s32 _arr[sizeof(impl::InternalConditionVariableStorage) / sizeof(s32)]; impl::InternalConditionVariableStorage _storage; + impl::InternalConditionVariableStorageTypeForConstantInitialize _storage_for_constant_initialize; }; ALWAYS_INLINE void Initialize() { @@ -52,7 +53,7 @@ namespace ams::os { private: SdkConditionVariableType m_cv; public: - constexpr SdkConditionVariable() : m_cv{{0}} { /* ... */ } + constexpr SdkConditionVariable() : m_cv{{AMS_OS_INTERNAL_CONDITION_VARIABLE_IMPL_CONSTANT_INITIALIZER}} { /* ... */ } ALWAYS_INLINE void Wait(SdkMutex &m) { return m_cv.Wait(m.m_mutex); diff --git a/libraries/libstratosphere/include/stratosphere/os/os_sdk_mutex.hpp b/libraries/libstratosphere/include/stratosphere/os/os_sdk_mutex.hpp index 34b2b272f..d006413bd 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_sdk_mutex.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_sdk_mutex.hpp @@ -22,10 +22,16 @@ namespace ams::os { class SdkConditionVariable; + struct ThreadType; + struct SdkMutexType { + #if !defined(AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD) + os::ThreadType *owner_thread; + #endif union { s32 _arr[sizeof(impl::InternalCriticalSectionStorage) / sizeof(s32)]; impl::InternalCriticalSectionStorage _storage; + impl::InternalCriticalSectionStorageTypeForConstantInitialize _storage_for_constant_initialize; }; }; static_assert(std::is_trivial::value); @@ -44,7 +50,11 @@ namespace ams::os { private: SdkMutexType m_mutex; public: - constexpr SdkMutex() : m_mutex{{0}} { /* ... */ } + #if defined(AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD) + constexpr SdkMutex() : m_mutex{{AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CONSTANT_INITIALIZER}} { /* ... */ } + #else + constexpr SdkMutex() : m_mutex{nullptr, {AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CONSTANT_INITIALIZER}} { /* ... */ } + #endif ALWAYS_INLINE void Lock() { return os::LockSdkMutex(std::addressof(m_mutex)); } ALWAYS_INLINE bool TryLock() { return os::TryLockSdkMutex(std::addressof(m_mutex)); } diff --git a/libraries/libstratosphere/include/stratosphere/os/os_sdk_recursive_mutex.hpp b/libraries/libstratosphere/include/stratosphere/os/os_sdk_recursive_mutex.hpp index 09dcddfc8..ecdf14774 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_sdk_recursive_mutex.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_sdk_recursive_mutex.hpp @@ -23,9 +23,13 @@ namespace ams::os { class SdkConditionVariable; struct SdkRecursiveMutexType { + #if !defined(AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD) + os::ThreadType *owner_thread; + #endif union { s32 _arr[sizeof(impl::InternalCriticalSectionStorage) / sizeof(s32)]; impl::InternalCriticalSectionStorage _storage; + impl::InternalCriticalSectionStorageTypeForConstantInitialize _storage_for_constant_initialize; }; u32 recursive_count; }; @@ -45,7 +49,11 @@ namespace ams::os { private: SdkRecursiveMutexType m_mutex; public: - constexpr SdkRecursiveMutex() : m_mutex{{0}, 0} { /* ... */ } + #if defined(AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD) + constexpr SdkRecursiveMutex() : m_mutex{ { AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CONSTANT_INITIALIZER }, 0 } { /* ... */ } + #else + constexpr SdkRecursiveMutex() : m_mutex{ nullptr, { AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CONSTANT_INITIALIZER }, 0 } { /* ... */ } + #endif ALWAYS_INLINE void Lock() { return os::LockSdkRecursiveMutex(std::addressof(m_mutex)); } ALWAYS_INLINE bool TryLock() { return os::TryLockSdkRecursiveMutex(std::addressof(m_mutex)); } diff --git a/libraries/libstratosphere/include/stratosphere/os/os_sdk_thread_api.hpp b/libraries/libstratosphere/include/stratosphere/os/os_sdk_thread_api.hpp new file mode 100644 index 000000000..923ce91cc --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_sdk_thread_api.hpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 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 +#include +#include + +namespace ams::os { + + ALWAYS_INLINE SdkInternalTlsType *GetSdkInternalTlsArray(ThreadType *thread = os::GetCurrentThread()) { + #if defined(ATMOSPHERE_OS_HORIZON) + return std::addressof(thread->sdk_internal_tls); + #else + return reinterpret_cast(std::addressof(thread->tls_value_array[TlsSlotCountMax])); + #endif + } + +} diff --git a/libraries/libstratosphere/include/stratosphere/os/os_sdk_thread_types.hpp b/libraries/libstratosphere/include/stratosphere/os/os_sdk_thread_types.hpp new file mode 100644 index 000000000..7d4266d7d --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_sdk_thread_types.hpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 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 + +namespace ams::os { + + struct SdkInternalTlsType { + uintptr_t sf_inline_context; + }; + static_assert(util::is_pod::value); + static_assert((sizeof(SdkInternalTlsType) % sizeof(uintptr_t)) == 0); + + constexpr inline size_t SdkInternalTlsCount = sizeof(SdkInternalTlsType) / sizeof(uintptr_t); + static_assert(SdkInternalTlsCount <= SdkTlsSlotCountMax); + +} diff --git a/libraries/libstratosphere/include/stratosphere/os/os_thread_api.hpp b/libraries/libstratosphere/include/stratosphere/os/os_thread_api.hpp index 66066262e..b946b8004 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_thread_api.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_thread_api.hpp @@ -40,8 +40,6 @@ namespace ams::os { s32 ResumeThread(ThreadType *thread); s32 GetThreadSuspendCount(const ThreadType *thread); - void CancelThreadSynchronization(ThreadType *Thread); - /* TODO: void GetThreadContext(ThreadContextInfo *out_context, const ThreadType *thread); */ s32 ChangeThreadPriority(ThreadType *thread, s32 priority); diff --git a/libraries/libstratosphere/include/stratosphere/os/os_thread_local_storage_common.hpp b/libraries/libstratosphere/include/stratosphere/os/os_thread_local_storage_common.hpp index 0afd1cc6f..11d76cbcd 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_thread_local_storage_common.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_thread_local_storage_common.hpp @@ -26,7 +26,7 @@ namespace ams::os { using TlsDestructor = void (*)(uintptr_t arg); - constexpr inline size_t TlsSlotCountMax = 16; + constexpr inline size_t TlsSlotCountMax = 16; constexpr inline size_t SdkTlsSlotCountMax = 16; } diff --git a/libraries/libstratosphere/include/stratosphere/os/os_thread_types.hpp b/libraries/libstratosphere/include/stratosphere/os/os_thread_types.hpp index cbe430fa7..80be04a0b 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_thread_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_thread_types.hpp @@ -21,6 +21,7 @@ #include #include #include +#include namespace ams::os { @@ -30,10 +31,21 @@ namespace ams::os { } + #if !defined(AMS_OS_IMPL_USE_PTHREADS) using ThreadId = u64; + #else + /* TODO: decide whether using pthread_id_np_t or not more thoroughly. */ + #if defined(ATMOSPHERE_OS_MACOS) + #define AMS_OS_IMPL_USE_PTHREADID_NP_FOR_THREAD_ID + #endif - /* TODO */ - using ThreadImpl = ::Thread; + #if defined(AMS_OS_IMPL_USE_PTHREADID_NP_FOR_THREAD_ID) + using ThreadId = u64; + #else + static_assert(sizeof(pthread_t) <= sizeof(u64)); + using ThreadId = pthread_t; + #endif + #endif struct ThreadType { static constexpr u16 Magic = 0xF5A5; @@ -50,6 +62,8 @@ namespace ams::os { util::TypedStorage waitlist; uintptr_t reserved[4]; u8 state; + bool stack_is_aliased; + bool auto_registered; u8 suspend_count; u16 magic; s16 base_priority; @@ -57,21 +71,49 @@ namespace ams::os { char name_buffer[ThreadNameLengthMax]; const char *name_pointer; ThreadId thread_id; + void *original_stack; void *stack; size_t stack_size; ThreadFunction function; + void *initial_fiber; + void *current_fiber; void *argument; - /* NOTE: Here, Nintendo stores the TLS array. This is handled by libnx in our case. */ - /* However, we need to access certain values in other threads' TLS (Nintendo uses a hardcoded layout for SDK tls members...) */ - /* These members are tls slot holders in sdk code, but just normal thread type members under our scheme. */ - uintptr_t atomic_sf_inline_context; - mutable impl::InternalCriticalSectionStorage cs_thread; mutable impl::InternalConditionVariableStorage cv_thread; + /* The following members are arch/os specific. */ + #if defined(AMS_OS_IMPL_USE_PTHREADS) + + mutable uintptr_t tls_value_array[TlsSlotCountMax + SdkTlsSlotCountMax]; + + mutable impl::InternalCriticalSectionStorage cs_pthread_exit; + mutable impl::InternalConditionVariableStorage cv_pthread_exit; + bool exited_pthread; + + pthread_t pthread; + u64 affinity_mask; + int ideal_core; + + #elif defined(ATMOSPHERE_OS_HORIZON) + /* NOTE: Here, Nintendo stores the TLS array. This is handled by libnx in our case. */ + /* However, we need to access certain values in other threads' TLS (Nintendo uses a hardcoded layout for SDK tls members...) */ + /* These members are tls slot holders in sdk code, but just normal thread type members under our scheme. */ + SdkInternalTlsType sdk_internal_tls; + + using ThreadImpl = ::Thread; + ThreadImpl *thread_impl; ThreadImpl thread_impl_storage; + #elif defined(ATMOSPHERE_OS_WINDOWS) + + mutable uintptr_t tls_value_array[TlsSlotCountMax + SdkTlsSlotCountMax]; + + NativeHandle native_handle; + int ideal_core; + u64 affinity_mask; + + #endif }; static_assert(std::is_trivial::value); diff --git a/libraries/libstratosphere/include/stratosphere/os/os_virtual_address_memory.hpp b/libraries/libstratosphere/include/stratosphere/os/os_virtual_address_memory.hpp new file mode 100644 index 000000000..4eb006e69 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_virtual_address_memory.hpp @@ -0,0 +1,21 @@ +/* + * Copyright (c) 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 +#include +#include diff --git a/libraries/libstratosphere/include/stratosphere/os/os_virtual_address_memory_api.hpp b/libraries/libstratosphere/include/stratosphere/os/os_virtual_address_memory_api.hpp new file mode 100644 index 000000000..11a803262 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_virtual_address_memory_api.hpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 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 +#include + +namespace ams::os { + + void InitializeVirtualAddressMemory(); + + Result AllocateAddressRegion(uintptr_t *out, size_t size); + Result AllocateMemory(uintptr_t *out, size_t size); + Result AllocateMemoryPages(uintptr_t address, size_t size); + + Result FreeAddressRegion(uintptr_t address); + Result FreeMemoryPages(uintptr_t address, size_t size); + + VirtualAddressMemoryResourceUsage GetVirtualAddressMemoryResourceUsage(); + + bool IsVirtualAddressMemoryEnabled(); + +} diff --git a/libraries/libstratosphere/include/stratosphere/os/os_memory_virtual_address_api.hpp b/libraries/libstratosphere/include/stratosphere/os/os_virtual_address_memory_common.hpp similarity index 83% rename from libraries/libstratosphere/include/stratosphere/os/os_memory_virtual_address_api.hpp rename to libraries/libstratosphere/include/stratosphere/os/os_virtual_address_memory_common.hpp index b36467e06..3f4ecc908 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_memory_virtual_address_api.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_virtual_address_memory_common.hpp @@ -15,11 +15,9 @@ */ #pragma once #include -#include -#include namespace ams::os { - bool IsVirtualAddressMemoryEnabled(); + constexpr inline size_t AddressRegionAlignment = 64_KB; } diff --git a/libraries/libstratosphere/include/stratosphere/os/os_virtual_address_memory_types.hpp b/libraries/libstratosphere/include/stratosphere/os/os_virtual_address_memory_types.hpp new file mode 100644 index 000000000..4da8365c1 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_virtual_address_memory_types.hpp @@ -0,0 +1,27 @@ +/* + * Copyright (c) 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 + +namespace ams::os { + + struct VirtualAddressMemoryResourceUsage { + size_t assigned_size; + size_t used_size; + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/osdbg/osdbg_thread_api.hpp b/libraries/libstratosphere/include/stratosphere/osdbg/osdbg_thread_api.hpp index 316107b73..e9c233dad 100644 --- a/libraries/libstratosphere/include/stratosphere/osdbg/osdbg_thread_api.hpp +++ b/libraries/libstratosphere/include/stratosphere/osdbg/osdbg_thread_api.hpp @@ -21,7 +21,7 @@ namespace ams::osdbg { struct ThreadInfo; - Result InitializeThreadInfo(ThreadInfo *thread_info, os::NativeHandle debug_handle, const svc::DebugInfoCreateProcess *create_process, const svc::DebugInfoCreateThread *create_thread); + Result InitializeThreadInfo(ThreadInfo *thread_info, os::NativeHandle debug_handle, const osdbg::DebugInfoCreateProcess *create_process, const osdbg::DebugInfoCreateThread *create_thread); Result UpdateThreadInfo(ThreadInfo *thread_info); Result GetThreadName(char *dst, const ThreadInfo *thread_info); diff --git a/libraries/libstratosphere/include/stratosphere/osdbg/osdbg_thread_types.hpp b/libraries/libstratosphere/include/stratosphere/osdbg/osdbg_thread_types.hpp index c4ac6f02d..21671bf91 100644 --- a/libraries/libstratosphere/include/stratosphere/osdbg/osdbg_thread_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/osdbg/osdbg_thread_types.hpp @@ -24,11 +24,21 @@ namespace ams::osdbg { } + #if defined(ATMOSPHERE_OS_HORIZON) + using DebugInfoCreateProcess = svc::DebugInfoCreateProcess; + using DebugInfoCreateThread = svc::DebugInfoCreateThread; + #else + struct DebugInfoCreateProcess{}; + struct DebugInfoCreateThread{}; + #endif + enum ThreadTypeType : u8 { ThreadTypeType_Unknown = 0, ThreadTypeType_Nintendo, ThreadTypeType_Stratosphere, + #if defined(ATMOSPHERE_OS_HORIZON) ThreadTypeType_Libnx, + #endif }; struct ThreadInfo { @@ -42,8 +52,10 @@ namespace ams::osdbg { impl::ThreadTypeCommon *_thread_type; os::NativeHandle _debug_handle; ThreadTypeType _thread_type_type; - svc::DebugInfoCreateProcess _debug_info_create_process; - svc::DebugInfoCreateThread _debug_info_create_thread; + #if defined(ATMOSPHERE_OS_HORIZON) + osdbg::DebugInfoCreateProcess _debug_info_create_process; + osdbg::DebugInfoCreateThread _debug_info_create_thread; + #endif }; } diff --git a/libraries/libstratosphere/include/stratosphere/pm/pm_dmnt_api.hpp b/libraries/libstratosphere/include/stratosphere/pm/pm_dmnt_api.hpp index 82631a8a4..78cbbdc27 100644 --- a/libraries/libstratosphere/include/stratosphere/pm/pm_dmnt_api.hpp +++ b/libraries/libstratosphere/include/stratosphere/pm/pm_dmnt_api.hpp @@ -28,6 +28,9 @@ namespace ams::pm::dmnt { Result GetApplicationProcessId(os::ProcessId *out_process_id); Result HookToCreateApplicationProcess(os::NativeHandle *out_handle); Result AtmosphereGetProcessInfo(os::NativeHandle *out_handle, ncm::ProgramLocation *out_loc, cfg::OverrideStatus *out_status, os::ProcessId process_id); + + #if defined(ATMOSPHERE_OS_HORIZON) Result AtmosphereGetCurrentLimitInfo(u64 *out_current_value, u64 *out_limit_value, ResourceLimitGroup group, svc::LimitableResource resource); + #endif } diff --git a/libraries/libstratosphere/include/stratosphere/powctl/driver/impl/powctl_charge_arbiter.hpp b/libraries/libstratosphere/include/stratosphere/powctl/driver/impl/powctl_charge_arbiter.hpp index a27157e85..5ae8c8507 100644 --- a/libraries/libstratosphere/include/stratosphere/powctl/driver/impl/powctl_charge_arbiter.hpp +++ b/libraries/libstratosphere/include/stratosphere/powctl/driver/impl/powctl_charge_arbiter.hpp @@ -20,6 +20,7 @@ namespace ams::powctl::driver::impl { + #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) class ChargeArbiter { private: const ChargeParametersRule *m_rules; @@ -118,6 +119,7 @@ namespace ams::powctl::driver::impl { void UpdateSelectedRule() { /* Try to find an entry that fits our current requirements. */ const ChargeParametersRule *best_rule = nullptr; + for (size_t i = 0; i < m_num_rules; ++i) { /* Get the current rule. */ const ChargeParametersRule &cur_rule = m_rules[i]; @@ -184,5 +186,6 @@ namespace ams::powctl::driver::impl { m_selected_rule = best_rule; } }; + #endif } \ No newline at end of file diff --git a/libraries/libstratosphere/include/stratosphere/powctl/driver/impl/powctl_charger_parameters.generic.hpp b/libraries/libstratosphere/include/stratosphere/powctl/driver/impl/powctl_charger_parameters.generic.hpp new file mode 100644 index 000000000..03abe7829 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/powctl/driver/impl/powctl_charger_parameters.generic.hpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 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 + +namespace ams::powctl::driver::impl { + + struct ChargeParametersRule { + /* ... */ + }; + + struct UnknownParameterX { + /* ... */ + }; + + struct ChargeParameters { + /* ... */ + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/powctl/driver/impl/powctl_select_charger_parameters.hpp b/libraries/libstratosphere/include/stratosphere/powctl/driver/impl/powctl_select_charger_parameters.hpp index a929f404c..acbb30dc4 100644 --- a/libraries/libstratosphere/include/stratosphere/powctl/driver/impl/powctl_select_charger_parameters.hpp +++ b/libraries/libstratosphere/include/stratosphere/powctl/driver/impl/powctl_select_charger_parameters.hpp @@ -18,9 +18,7 @@ #include #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) - #include - #else - #error "unknown board for powctl::driver::impl::ChargerParameters" + #include #endif \ No newline at end of file diff --git a/libraries/libstratosphere/include/stratosphere/psc/psc_pm_module.hpp b/libraries/libstratosphere/include/stratosphere/psc/psc_pm_module.hpp index b5163d966..2bb2cab70 100644 --- a/libraries/libstratosphere/include/stratosphere/psc/psc_pm_module.hpp +++ b/libraries/libstratosphere/include/stratosphere/psc/psc_pm_module.hpp @@ -20,5 +20,5 @@ #if defined(ATMOSPHERE_OS_HORIZON) #include #else - #error "Unknown OS for psc::PmModule" + #include #endif diff --git a/libraries/libstratosphere/include/stratosphere/psc/psc_pm_module.os.generic.hpp b/libraries/libstratosphere/include/stratosphere/psc/psc_pm_module.os.generic.hpp new file mode 100644 index 000000000..070250e86 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/psc/psc_pm_module.os.generic.hpp @@ -0,0 +1,102 @@ +/* + * Copyright (c) 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 +#include +#include + +namespace ams::psc { + + class PmModule { + NON_COPYABLE(PmModule); + NON_MOVEABLE(PmModule); + private: + os::SystemEvent m_system_event; + bool m_initialized; + PmModuleId m_module_id; + uintptr_t m_reserved; + PmState m_state; + PmFlagSet m_flags; + public: + PmModule() : m_initialized(false), m_module_id(PmModuleId_Reserved0), m_reserved(0), m_state(PmState_FullAwake), m_flags() { /* ... */ } + ~PmModule() { + if (m_initialized) { + R_ABORT_UNLESS(this->Finalize()); + } + } + + Result Initialize(const PmModuleId mid, const PmModuleId *dependencies, u32 dependency_count, os::EventClearMode clear_mode) { + /* TODO: Should we do in-process dependency resolution? */ + AMS_UNUSED(dependencies, dependency_count); + + /* Check that we're not already initialized. */ + R_UNLESS(!m_initialized, psc::ResultAlreadyInitialized()); + + /* Create our event. */ + R_ABORT_UNLESS(os::CreateSystemEvent(m_system_event.GetBase(), clear_mode, false)); + + /* Set our state. */ + m_module_id = mid; + m_initialized = true; + + R_SUCCEED(); + } + + Result Finalize() { + /* Check that we're initialized. */ + R_UNLESS(m_initialized, psc::ResultNotInitialized()); + + /* Destroy our system event. */ + os::DestroySystemEvent(m_system_event.GetBase()); + + /* Mark not initialized. */ + m_initialized = false; + + R_SUCCEED(); + } + + constexpr PmModuleId GetId() const { return m_module_id; } + + Result GetRequest(PmState *out_state, PmFlagSet *out_flags) { + /* Check that we're initialized. */ + R_UNLESS(m_initialized, psc::ResultNotInitialized()); + + /* Set output. */ + *out_state = m_state; + *out_flags = m_flags; + + R_SUCCEED(); + } + + Result Acknowledge(PmState state, Result res) { + /* Check that we're initialized. */ + R_UNLESS(m_initialized, psc::ResultNotInitialized()); + + /* Check the transition was successful. */ + R_ABORT_UNLESS(res); + + AMS_UNUSED(state); + R_SUCCEED(); + } + + os::SystemEvent *GetEventPointer() { + return std::addressof(m_system_event); + } + }; + +} \ No newline at end of file diff --git a/libraries/libstratosphere/include/stratosphere/psc/psc_pm_module_id.hpp b/libraries/libstratosphere/include/stratosphere/psc/psc_pm_module_id.hpp index bf0f4ebaf..b3c8a0f31 100644 --- a/libraries/libstratosphere/include/stratosphere/psc/psc_pm_module_id.hpp +++ b/libraries/libstratosphere/include/stratosphere/psc/psc_pm_module_id.hpp @@ -20,6 +20,8 @@ namespace ams::psc { enum PmModuleId : u32 { + PmModuleId_Reserved0 = 0, + PmModuleId_Usb = 4, PmModuleId_Ethernet = 5, PmModuleId_Fgm = 6, diff --git a/libraries/libstratosphere/include/stratosphere/pwm/driver/pwm_select_driver_api.hpp b/libraries/libstratosphere/include/stratosphere/pwm/driver/pwm_select_driver_api.hpp index bceb87cc6..b5c0f0637 100644 --- a/libraries/libstratosphere/include/stratosphere/pwm/driver/pwm_select_driver_api.hpp +++ b/libraries/libstratosphere/include/stratosphere/pwm/driver/pwm_select_driver_api.hpp @@ -30,7 +30,7 @@ #else - #error "Unknown board for ams::pwm::driver::" + // TODO: #error "Unknown board for ams::pwm::driver::" #endif diff --git a/libraries/libstratosphere/include/stratosphere/pwm/pwm_channel_name.generic.hpp b/libraries/libstratosphere/include/stratosphere/pwm/pwm_channel_name.generic.hpp new file mode 100644 index 000000000..c371a27cf --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/pwm/pwm_channel_name.generic.hpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 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 + +namespace ams::pwm { + + enum ChannelName { + ChannelName_Invalid = 0, + }; + + constexpr inline DeviceCode ConvertToDeviceCode(ChannelName cn) { + switch (cn) { + AMS_UNREACHABLE_DEFAULT_CASE(); + } + return InvalidDeviceCode; + } + + constexpr inline ChannelName ConvertToChannelName(DeviceCode dc) { + switch (dc.GetInternalValue()) { + AMS_UNREACHABLE_DEFAULT_CASE(); + } + return ChannelName_Invalid; + } + +} diff --git a/libraries/libstratosphere/include/stratosphere/pwm/pwm_select_channel_name.hpp b/libraries/libstratosphere/include/stratosphere/pwm/pwm_select_channel_name.hpp index 36a36e337..c85af3835 100644 --- a/libraries/libstratosphere/include/stratosphere/pwm/pwm_select_channel_name.hpp +++ b/libraries/libstratosphere/include/stratosphere/pwm/pwm_select_channel_name.hpp @@ -20,5 +20,5 @@ #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) #include #else - /* Error? */ + #include #endif diff --git a/libraries/libstratosphere/include/stratosphere/ro/ro_types.hpp b/libraries/libstratosphere/include/stratosphere/ro/ro_types.hpp index d6da9e36f..886b771da 100644 --- a/libraries/libstratosphere/include/stratosphere/ro/ro_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/ro/ro_types.hpp @@ -67,7 +67,7 @@ namespace ams::ro { } bool IsProgramIdValid() const { - return (static_cast(m_program_id) & m_certification.program_id_mask) == m_certification.program_id_pattern; + return (m_program_id.value & m_certification.program_id_mask) == m_certification.program_id_pattern; } NrrKind GetNrrKind() const { diff --git a/libraries/libstratosphere/include/stratosphere/rocrt/rocrt.hpp b/libraries/libstratosphere/include/stratosphere/rocrt/rocrt.hpp index 9cc32ed3b..6a4c0ce82 100644 --- a/libraries/libstratosphere/include/stratosphere/rocrt/rocrt.hpp +++ b/libraries/libstratosphere/include/stratosphere/rocrt/rocrt.hpp @@ -44,24 +44,24 @@ namespace ams::rocrt { } } - constexpr inline ModuleHeader *GetModuleHeader(const ModuleHeaderLocation *loc) { + inline ModuleHeader *GetModuleHeader(const ModuleHeaderLocation *loc) { return reinterpret_cast(reinterpret_cast(loc) + loc->header_offset); } - constexpr inline uintptr_t GetDynamicOffset(const ModuleHeader *header, const ModuleHeaderLocation *loc) { + inline uintptr_t GetDynamicOffset(const ModuleHeader *header, const ModuleHeaderLocation *loc) { return reinterpret_cast(loc) + loc->header_offset + header->dynamic_offset; } - constexpr inline uintptr_t GetBssStartAddress(const ModuleHeader *header, const ModuleHeaderLocation *loc) { + inline uintptr_t GetBssStartAddress(const ModuleHeader *header, const ModuleHeaderLocation *loc) { return reinterpret_cast(loc) + loc->header_offset + header->bss_start_offset; } - constexpr inline uintptr_t GetBssEndAddress(const ModuleHeader *header, const ModuleHeaderLocation *loc) { + inline uintptr_t GetBssEndAddress(const ModuleHeader *header, const ModuleHeaderLocation *loc) { return reinterpret_cast(loc) + loc->header_offset + header->bss_end_offset; } - constexpr inline uintptr_t GetModuleOffset(const ModuleHeader *header, const ModuleHeaderLocation *loc) { + inline uintptr_t GetModuleOffset(const ModuleHeader *header, const ModuleHeaderLocation *loc) { return reinterpret_cast(loc) + loc->header_offset + header->module_offset; } diff --git a/libraries/libstratosphere/include/stratosphere/settings/settings_types.hpp b/libraries/libstratosphere/include/stratosphere/settings/settings_types.hpp index 6441fbb33..8d6f3755a 100644 --- a/libraries/libstratosphere/include/stratosphere/settings/settings_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/settings/settings_types.hpp @@ -123,7 +123,7 @@ namespace ams::settings { }; constexpr inline bool operator==(const LanguageCode &lhs, const LanguageCode &rhs) { - return std::strncmp(lhs.name, rhs.name, sizeof(lhs)) == 0; + return util::Strncmp(lhs.name, rhs.name, sizeof(lhs)) == 0; } constexpr inline bool operator!=(const LanguageCode &lhs, const LanguageCode &rhs) { @@ -205,7 +205,11 @@ namespace ams::settings { }; static_assert(util::is_pod::value); + static_assert(sizeof(FirmwareVersion) == 0x100); + + #if defined(ATMOSPHERE_OS_HORIZON) static_assert(sizeof(FirmwareVersion) == sizeof(::SetSysFirmwareVersion)); + #endif constexpr inline bool operator==(const FirmwareVersion &lhs, const FirmwareVersion &rhs) { return lhs.GetVersion() == rhs.GetVersion(); 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 index d2396502f..d13934320 100644 --- 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 @@ -15,6 +15,7 @@ */ #pragma once +#include #include #include #include @@ -110,7 +111,9 @@ namespace ams::sf::cmif { template<> struct ServiceDispatchTraits { static_assert(std::is_base_of::value, "DomainServiceObject must derive from sf::IServiceObject"); + #if AMS_SF_MITM_SUPPORTED static_assert(!std::is_base_of::value, "DomainServiceObject must not derive from sf::IMitmServiceObject"); + #endif using ProcessHandlerType = decltype(ServiceDispatchMeta::ProcessHandler); using DispatchTableType = DomainServiceObjectDispatchTable; 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 index 9037a3bde..c3558ccfd 100644 --- 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 @@ -26,9 +26,9 @@ namespace ams::sf::cmif { public: constexpr PointerAndSize() : m_pointer(0), m_size(0) { /* ... */ } constexpr PointerAndSize(uintptr_t ptr, size_t sz) : m_pointer(ptr), m_size(sz) { /* ... */ } - constexpr PointerAndSize(void *ptr, size_t sz) : PointerAndSize(reinterpret_cast(ptr), sz) { /* ... */ } + PointerAndSize(void *ptr, size_t sz) : PointerAndSize(reinterpret_cast(ptr), sz) { /* ... */ } - constexpr void *GetPointer() const { + void *GetPointer() const { return reinterpret_cast(m_pointer); } 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 index 46615e505..810d578ef 100644 --- a/libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_service_dispatch.hpp +++ b/libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_service_dispatch.hpp @@ -15,6 +15,7 @@ */ #pragma once +#include #include #include #include @@ -137,7 +138,7 @@ namespace ams::sf::cmif { const impl::ServiceDispatchTableBase *DispatchTable; Result (impl::ServiceDispatchTableBase::*ProcessHandler)(ServiceDispatchContext &, const cmif::PointerAndSize &) const; - constexpr uintptr_t GetServiceId() const { + uintptr_t GetServiceId() const { return reinterpret_cast(this->DispatchTable); } }; @@ -160,10 +161,12 @@ namespace ams::sf::cmif { static constexpr inline auto DispatchTable = ServiceDispatchTable<0>(std::array{}); }; + #if AMS_SF_MITM_SUPPORTED template<> struct ServiceDispatchTraits { static constexpr inline auto DispatchTable = ServiceDispatchTable<0>(std::array{}); }; + #endif template constexpr ALWAYS_INLINE const ServiceDispatchMeta *GetServiceDispatchMeta() { diff --git a/libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_api.hpp b/libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_api.hpp index af8fd9765..69d0fd559 100644 --- a/libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_api.hpp +++ b/libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_api.hpp @@ -20,8 +20,16 @@ namespace ams::sf::hipc { + void *GetMessageBufferOnTls(); + constexpr size_t TlsMessageBufferSize = 0x100; + #if defined(ATMOSPHERE_OS_HORIZON) + ALWAYS_INLINE void *GetMessageBufferOnTls() { + return svc::GetThreadLocalRegion()->message_buffer; + } + #endif + enum class ReceiveResult { Success, Closed, @@ -37,4 +45,5 @@ namespace ams::sf::hipc { Result CreateSession(os::NativeHandle *out_server_handle, os::NativeHandle *out_client_handle); + } 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 index 2a9879a72..27355dec8 100644 --- a/libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_manager.hpp +++ b/libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_manager.hpp @@ -15,6 +15,7 @@ */ #pragma once +#include #include #include @@ -38,12 +39,16 @@ namespace ams::sf::hipc { NON_COPYABLE(ServerManagerBase); NON_MOVEABLE(ServerManagerBase); public: + #if AMS_SF_MITM_SUPPORTED using MitmQueryFunction = bool (*)(const sm::MitmProcessInfo &); + #endif private: enum class UserDataTag : uintptr_t { Server = 1, Session = 2, + #if AMS_SF_MITM_SUPPORTED MitmServer = 3, + #endif }; protected: using ServerDomainSessionManager::DomainEntryStorage; @@ -61,8 +66,11 @@ namespace ams::sf::hipc { sm::ServiceName m_service_name; int m_index; bool m_service_managed; + #if AMS_SF_MITM_SUPPORTED bool m_is_mitm_server; + #endif public: + #if AMS_SF_MITM_SUPPORTED void AcknowledgeMitmSession(std::shared_ptr<::Service> *out_fsrv, sm::MitmProcessInfo *out_client_info) { /* Check mitm server. */ AMS_ABORT_UNLESS(m_is_mitm_server); @@ -73,10 +81,13 @@ namespace ams::sf::hipc { /* Get client info. */ R_ABORT_UNLESS(sm::mitm::AcknowledgeSession(out_fsrv->get(), out_client_info, m_service_name)); } + #endif }; protected: static constinit inline bool g_is_any_deferred_supported = false; + #if AMS_SF_MITM_SUPPORTED static constinit inline bool g_is_any_mitm_supported = false; + #endif private: /* Multiple wait management. */ os::MultiWaitType m_multi_wait; @@ -101,13 +112,17 @@ namespace ams::sf::hipc { bool WaitAndProcessImpl(); Result ProcessForServer(os::MultiWaitHolderType *holder); - Result ProcessForMitmServer(os::MultiWaitHolderType *holder); Result ProcessForSession(os::MultiWaitHolderType *holder); + #if AMS_SF_MITM_SUPPORTED + Result ProcessForMitmServer(os::MultiWaitHolderType *holder); + #endif + void RegisterServerImpl(Server *server, os::NativeHandle port_handle, bool is_mitm_server) { server->m_port_handle = port_handle; hipc::AttachMultiWaitHolderForAccept(server, port_handle); + #if AMS_SF_MITM_SUPPORTED server->m_is_mitm_server = is_mitm_server; if (is_mitm_server) { /* Mitm server. */ @@ -117,6 +132,10 @@ namespace ams::sf::hipc { /* Non-mitm server. */ os::SetMultiWaitHolderUserData(server, static_cast(UserDataTag::Server)); } + #else + AMS_UNUSED(is_mitm_server); + os::SetMultiWaitHolderUserData(server, static_cast(UserDataTag::Server)); + #endif os::LinkMultiWaitHolder(std::addressof(m_multi_wait), server); } @@ -158,7 +177,9 @@ namespace ams::sf::hipc { return ResultSuccess(); } + #if AMS_SF_MITM_SUPPORTED Result InstallMitmServerImpl(os::NativeHandle *out_port_handle, sm::ServiceName service_name, MitmQueryFunction query_func); + #endif protected: virtual Server *AllocateServer() = 0; virtual void DestroyServer(Server *server) = 0; @@ -172,6 +193,7 @@ namespace ams::sf::hipc { return ServerSessionManager::AcceptSession(server->m_port_handle, std::move(p)); } + #if AMS_SF_MITM_SUPPORTED template Result AcceptMitmImpl(Server *server, SharedPointer p, std::shared_ptr<::Service> forward_service) { AMS_ABORT_UNLESS(this->CanManageMitmServers()); @@ -200,6 +222,7 @@ namespace ams::sf::hipc { return ResultSuccess(); } + #endif public: ServerManagerBase(DomainEntryStorage *entry_storage, size_t entry_count, bool defer_supported, bool mitm_supported) : ServerDomainSessionManager(entry_storage, entry_count), @@ -216,21 +239,28 @@ namespace ams::sf::hipc { os::InitializeMultiWait(std::addressof(m_deferred_list)); } + virtual ~ServerManagerBase() = default; + static ALWAYS_INLINE bool CanAnyDeferInvokeRequest() { return g_is_any_deferred_supported; } - static ALWAYS_INLINE bool CanAnyManageMitmServers() { - return g_is_any_mitm_supported; - } - ALWAYS_INLINE bool CanDeferInvokeRequest() const { return CanAnyDeferInvokeRequest() && m_is_defer_supported; } + #if AMS_SF_MITM_SUPPORTED + static ALWAYS_INLINE bool CanAnyManageMitmServers() { + return g_is_any_mitm_supported; + } + ALWAYS_INLINE bool CanManageMitmServers() const { return CanAnyManageMitmServers() && m_is_mitm_supported; } + #else + static consteval bool CanAnyManageMitmServers() { return false; } + static consteval bool CanManageMitmServers() { return false; } + #endif template void RegisterObjectForServer(SharedPointer static_object, os::NativeHandle port_handle) { @@ -278,6 +308,10 @@ namespace ams::sf::hipc { } }(); static_assert(DomainCountsValid, "Invalid Domain Counts"); + + #if !(AMS_SF_MITM_SUPPORTED) + static_assert(!ManagerOptions::CanManageMitmServers); + #endif protected: using ServerManagerBase::DomainEntryStorage; using ServerManagerBase::DomainStorage; @@ -289,7 +323,11 @@ namespace ams::sf::hipc { util::TypedStorage m_session_storages[MaxSessions]; bool m_session_allocated[MaxSessions]; u8 m_pointer_buffer_storage[0x10 + (MaxSessions * ManagerOptions::PointerBufferSize)]; + #if AMS_SF_MITM_SUPPORTED u8 m_saved_message_storage[0x10 + (MaxSessions * ((ManagerOptions::CanDeferInvokeRequest || ManagerOptions::CanManageMitmServers) ? hipc::TlsMessageBufferSize : 0))]; + #else + u8 m_saved_message_storage[0x10 + (MaxSessions * ((ManagerOptions::CanDeferInvokeRequest) ? hipc::TlsMessageBufferSize : 0))]; + #endif uintptr_t m_pointer_buffers_start; uintptr_t m_saved_messages_start; @@ -359,6 +397,7 @@ namespace ams::sf::hipc { os::UnlinkMultiWaitHolder(server); os::FinalizeMultiWaitHolder(server); if (server->m_service_managed) { + #if AMS_SF_MITM_SUPPORTED if constexpr (ManagerOptions::CanManageMitmServers) { if (server->m_is_mitm_server) { R_ABORT_UNLESS(sm::mitm::UninstallMitm(server->m_service_name)); @@ -368,6 +407,9 @@ namespace ams::sf::hipc { } else { R_ABORT_UNLESS(sm::UnregisterService(server->m_service_name)); } + #else + R_ABORT_UNLESS(sm::UnregisterService(server->m_service_name)); + #endif os::CloseNativeHandle(server->m_port_handle); } } @@ -430,9 +472,11 @@ namespace ams::sf::hipc { if constexpr (ManagerOptions::CanDeferInvokeRequest) { ServerManagerBase::g_is_any_deferred_supported = true; } + #if AMS_SF_MITM_SUPPORTED if constexpr (ManagerOptions::CanManageMitmServers) { ServerManagerBase::g_is_any_mitm_supported = true; } + #endif } ~ServerManager() { @@ -455,11 +499,13 @@ namespace ams::sf::hipc { } } public: + #if AMS_SF_MITM_SUPPORTED template::type> Result RegisterMitmServer(int port_index, sm::ServiceName service_name) { AMS_ABORT_UNLESS(this->CanManageMitmServers()); return this->template RegisterMitmServerImpl(port_index, cmif::ServiceObjectHolder(), service_name); } + #endif }; } 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 index 69604e2e4..dc8a4c43c 100644 --- 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 @@ -16,6 +16,7 @@ #pragma once #include +#include #include #include #include @@ -48,7 +49,9 @@ namespace ams::sf::hipc { cmif::ServiceObjectHolder m_srv_obj_holder; cmif::PointerAndSize m_pointer_buffer; cmif::PointerAndSize m_saved_message; + #if AMS_SF_MITM_SUPPORTED util::TypedStorage> m_forward_service; + #endif os::NativeHandle m_session_handle; bool m_is_closed; bool m_has_received; @@ -58,9 +61,20 @@ namespace ams::sf::hipc { hipc::AttachMultiWaitHolderForReply(this, h); m_is_closed = false; m_has_received = false; + #if AMS_SF_MITM_SUPPORTED AMS_ABORT_UNLESS(!this->IsMitmSession()); + #endif } + ~ServerSession() { + #if AMS_SF_MITM_SUPPORTED + if (m_has_forward_service) { + util::DestroyAt(m_forward_service); + } + #endif + } + + #if AMS_SF_MITM_SUPPORTED ServerSession(os::NativeHandle h, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv) : m_srv_obj_holder(std::move(obj)), m_session_handle(h), m_has_forward_service(true) { hipc::AttachMultiWaitHolderForReply(this, h); m_is_closed = false; @@ -69,12 +83,6 @@ namespace ams::sf::hipc { AMS_ABORT_UNLESS(util::GetReference(m_forward_service) != nullptr); } - ~ServerSession() { - if (m_has_forward_service) { - util::DestroyAt(m_forward_service); - } - } - ALWAYS_INLINE bool IsMitmSession() const { return m_has_forward_service; } @@ -89,6 +97,7 @@ namespace ams::sf::hipc { static inline std::shared_ptr<::Service> CreateForwardService() { return std::shared_ptr<::Service>(new ::Service(), ForwardServiceDeleter); } + #endif }; class ServerSessionManager { @@ -124,8 +133,11 @@ namespace ams::sf::hipc { void CloseSessionImpl(ServerSession *session); Result RegisterSessionImpl(ServerSession *session_memory, os::NativeHandle session_handle, cmif::ServiceObjectHolder &&obj); Result AcceptSessionImpl(ServerSession *session_memory, os::NativeHandle port_handle, cmif::ServiceObjectHolder &&obj); + + #if AMS_SF_MITM_SUPPORTED Result RegisterMitmSessionImpl(ServerSession *session_memory, os::NativeHandle mitm_session_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv); Result AcceptMitmSessionImpl(ServerSession *session_memory, os::NativeHandle mitm_port_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv); + #endif Result ReceiveRequest(ServerSession *session, const cmif::PointerAndSize &message) { return this->ReceiveRequestImpl(session, message); @@ -145,6 +157,7 @@ namespace ams::sf::hipc { return this->CreateSessionImpl(out, ctor); } + #if AMS_SF_MITM_SUPPORTED Result RegisterMitmSession(ServerSession **out, os::NativeHandle 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)); @@ -158,21 +171,27 @@ namespace ams::sf::hipc { }; return this->CreateSessionImpl(out, ctor); } + #endif public: Result RegisterSession(os::NativeHandle session_handle, cmif::ServiceObjectHolder &&obj); Result AcceptSession(os::NativeHandle port_handle, cmif::ServiceObjectHolder &&obj); + + #if AMS_SF_MITM_SUPPORTED Result RegisterMitmSession(os::NativeHandle session_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv); Result AcceptMitmSession(os::NativeHandle mitm_port_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv); + #endif template Result AcceptSession(os::NativeHandle port_handle, SharedPointer obj) { return this->AcceptSession(port_handle, cmif::ServiceObjectHolder(std::move(obj))); } + #if AMS_SF_MITM_SUPPORTED template Result AcceptMitmSession(os::NativeHandle mitm_port_handle, SharedPointer obj, std::shared_ptr<::Service> &&fsrv) { return this->AcceptMitmSession(mitm_port_handle, cmif::ServiceObjectHolder(std::move(obj)), std::forward>(fsrv)); } + #endif Result ProcessRequest(ServerSession *session, const cmif::PointerAndSize &message); 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 index 942f6a038..cef1c5e3e 100644 --- a/libraries/libstratosphere/include/stratosphere/sf/impl/sf_impl_command_serialization.hpp +++ b/libraries/libstratosphere/include/stratosphere/sf/impl/sf_impl_command_serialization.hpp @@ -145,6 +145,7 @@ namespace ams::sf { } +#if defined(ATMOSPHERE_OS_HORIZON) namespace ams::sf::impl { /* Machinery for filtering type lists. */ @@ -1116,7 +1117,7 @@ namespace ams::sf::impl { } }; - constexpr Result GetCmifOutHeaderPointer(CmifOutHeader **out_header_ptr, cmif::PointerAndSize &out_raw_data) { + inline Result GetCmifOutHeaderPointer(CmifOutHeader **out_header_ptr, cmif::PointerAndSize &out_raw_data) { CmifOutHeader *header = static_cast(out_raw_data.GetPointer()); R_UNLESS(out_raw_data.GetSize() >= sizeof(*header), sf::cmif::ResultInvalidHeaderSize()); out_raw_data = cmif::PointerAndSize(out_raw_data.GetAddress() + sizeof(*header), out_raw_data.GetSize() - sizeof(*header)); @@ -1265,6 +1266,45 @@ namespace ams::sf::impl { } } +#elif defined(ATMOSPHERE_OS_WINDOWS) +namespace ams::sf::impl { + + template + inline Result InvokeServiceCommandImpl(CmifOutHeader **out_header_ptr, cmif::ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) { + /* TODO: Is some kind of emulated serialization interesting/desirable? */ + AMS_UNUSED(out_header_ptr, ctx, in_raw_data); + AMS_ABORT("HIPC serialization not currently supported on Windows."); + } + + +} +#elif defined(ATMOSPHERE_OS_LINUX) +namespace ams::sf::impl { + + template + inline Result InvokeServiceCommandImpl(CmifOutHeader **out_header_ptr, cmif::ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) { + /* TODO: Is some kind of emulated serialization interesting/desirable? */ + AMS_UNUSED(out_header_ptr, ctx, in_raw_data); + AMS_ABORT("HIPC serialization not currently supported on Linux."); + } + + +} +#elif defined(ATMOSPHERE_OS_MACOS) +namespace ams::sf::impl { + + template + inline Result InvokeServiceCommandImpl(CmifOutHeader **out_header_ptr, cmif::ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) { + /* TODO: Is some kind of emulated serialization interesting/desirable? */ + AMS_UNUSED(out_header_ptr, ctx, in_raw_data); + AMS_ABORT("HIPC serialization not currently supported on macOS."); + } + + +} +#else + #error "Unknown OS for sf Command serialization." +#endif namespace ams::sf::impl { diff --git a/libraries/libstratosphere/include/stratosphere/sf/sf_buffers.hpp b/libraries/libstratosphere/include/stratosphere/sf/sf_buffers.hpp index a5e58a5f5..32286f48f 100644 --- a/libraries/libstratosphere/include/stratosphere/sf/sf_buffers.hpp +++ b/libraries/libstratosphere/include/stratosphere/sf/sf_buffers.hpp @@ -116,8 +116,8 @@ namespace ams::sf { constexpr InBufferBase(const cmif::PointerAndSize &pas) : BaseType(pas) { /* ... */ } constexpr InBufferBase(uintptr_t ptr, size_t sz) : BaseType(ptr, sz) { /* ... */ } - constexpr InBufferBase(const void *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } - constexpr InBufferBase(const u8 *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } + InBufferBase(const void *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } + InBufferBase(const u8 *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } }; class OutBufferBase : public BufferBase { @@ -130,8 +130,8 @@ namespace ams::sf { constexpr OutBufferBase(const cmif::PointerAndSize &pas) : BaseType(pas) { /* ... */ } constexpr OutBufferBase(uintptr_t ptr, size_t sz) : BaseType(ptr, sz) { /* ... */ } - constexpr OutBufferBase(void *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } - constexpr OutBufferBase(u8 *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } + OutBufferBase(void *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } + OutBufferBase(u8 *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } }; template @@ -146,8 +146,8 @@ namespace ams::sf { constexpr InBufferImpl(const cmif::PointerAndSize &pas) : BaseType(pas) { /* ... */ } constexpr InBufferImpl(uintptr_t ptr, size_t sz) : BaseType(ptr, sz) { /* ... */ } - constexpr InBufferImpl(const void *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } - constexpr InBufferImpl(const u8 *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } + InBufferImpl(const void *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } + InBufferImpl(const u8 *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } constexpr const u8 *GetPointer() const { return reinterpret_cast(this->GetAddressImpl()); @@ -170,8 +170,8 @@ namespace ams::sf { constexpr OutBufferImpl(const cmif::PointerAndSize &pas) : BaseType(pas) { /* ... */ } constexpr OutBufferImpl(uintptr_t ptr, size_t sz) : BaseType(ptr, sz) { /* ... */ } - constexpr OutBufferImpl(void *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } - constexpr OutBufferImpl(u8 *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } + OutBufferImpl(void *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } + OutBufferImpl(u8 *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } constexpr u8 *GetPointer() const { return reinterpret_cast(this->GetAddressImpl()); @@ -191,7 +191,7 @@ namespace ams::sf { public: constexpr InArrayImpl() : BaseType() { /* ... */ } constexpr InArrayImpl(const cmif::PointerAndSize &pas) : BaseType(pas) { /* ... */ } - constexpr InArrayImpl(const T *ptr, size_t num_elements) : BaseType(reinterpret_cast(ptr), num_elements * sizeof(T)) { /* ... */ } + InArrayImpl(const T *ptr, size_t num_elements) : BaseType(reinterpret_cast(ptr), num_elements * sizeof(T)) { /* ... */ } constexpr const T *GetPointer() const { return reinterpret_cast(this->GetAddressImpl()); @@ -223,7 +223,7 @@ namespace ams::sf { public: constexpr OutArrayImpl() : BaseType() { /* ... */ } constexpr OutArrayImpl(const cmif::PointerAndSize &pas) : BaseType(pas) { /* ... */ } - constexpr OutArrayImpl(T *ptr, size_t num_elements) : BaseType(reinterpret_cast(ptr), num_elements * sizeof(T)) { /* ... */ } + OutArrayImpl(T *ptr, size_t num_elements) : BaseType(reinterpret_cast(ptr), num_elements * sizeof(T)) { /* ... */ } constexpr T *GetPointer() const { return reinterpret_cast(this->GetAddressImpl()); diff --git a/libraries/libstratosphere/include/stratosphere/sf/sf_common.hpp b/libraries/libstratosphere/include/stratosphere/sf/sf_common.hpp index 3b81741c2..ff81a1e46 100644 --- a/libraries/libstratosphere/include/stratosphere/sf/sf_common.hpp +++ b/libraries/libstratosphere/include/stratosphere/sf/sf_common.hpp @@ -18,4 +18,6 @@ #include #include #include -#include \ No newline at end of file +#include +#include +#include \ No newline at end of file diff --git a/libraries/libstratosphere/include/stratosphere/sf/sf_exp_heap_allocator.hpp b/libraries/libstratosphere/include/stratosphere/sf/sf_exp_heap_allocator.hpp index ad1cd1595..5a30b09ee 100644 --- a/libraries/libstratosphere/include/stratosphere/sf/sf_exp_heap_allocator.hpp +++ b/libraries/libstratosphere/include/stratosphere/sf/sf_exp_heap_allocator.hpp @@ -60,7 +60,7 @@ namespace ams::sf { typename std::aligned_storage::type buffer; }; - static constinit inline Globals _globals; + static constinit inline Globals _globals = {}; static void Initialize(int option) { diff --git a/libraries/libstratosphere/include/stratosphere/sf/sf_mitm_config.hpp b/libraries/libstratosphere/include/stratosphere/sf/sf_mitm_config.hpp new file mode 100644 index 000000000..be6613a08 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/sf/sf_mitm_config.hpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 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 + +#if defined(ATMOSPHERE_OS_HORIZON) + #define AMS_SF_MITM_SUPPORTED 1 +#else + #define AMS_SF_MITM_SUPPORTED 0 +#endif + diff --git a/libraries/libstratosphere/include/stratosphere/sf/sf_mitm_dispatch.h b/libraries/libstratosphere/include/stratosphere/sf/sf_mitm_dispatch.h index 07b8b7eac..ea64525a0 100644 --- a/libraries/libstratosphere/include/stratosphere/sf/sf_mitm_dispatch.h +++ b/libraries/libstratosphere/include/stratosphere/sf/sf_mitm_dispatch.h @@ -14,6 +14,9 @@ * along with this program. If not, see . */ #pragma once +#include + +#if AMS_SF_MITM_SUPPORTED #include #ifdef __cplusplus @@ -98,3 +101,5 @@ NX_INLINE Result serviceMitmDispatchImpl( #ifdef __cplusplus } #endif + +#endif \ No newline at end of file diff --git a/libraries/libstratosphere/include/stratosphere/sf/sf_object_factory.hpp b/libraries/libstratosphere/include/stratosphere/sf/sf_object_factory.hpp index 118641bc4..cc5ccd2b1 100644 --- a/libraries/libstratosphere/include/stratosphere/sf/sf_object_factory.hpp +++ b/libraries/libstratosphere/include/stratosphere/sf/sf_object_factory.hpp @@ -297,16 +297,19 @@ namespace ams::sf { template constexpr SharedPointer CreateShared(Allocator *a, Smart &&sp) { + AMS_UNUSED(a); return StaticObjectFactory::template CreateShared(m_allocator, std::forward(sp)); } template constexpr SharedPointer CreateShared(Allocator *a, T *p) { + AMS_UNUSED(a); return StaticObjectFactory::template CreateShared(m_allocator, p); } template constexpr SharedPointer CreateSharedWithoutManagement(Allocator *a, T *p) { + AMS_UNUSED(a); return StaticObjectFactory::template CreateSharedWithoutManagement(m_allocator, p); } }; diff --git a/libraries/libstratosphere/include/stratosphere/sf/sf_out.hpp b/libraries/libstratosphere/include/stratosphere/sf/sf_out.hpp index b9bc21da1..02a52e912 100644 --- a/libraries/libstratosphere/include/stratosphere/sf/sf_out.hpp +++ b/libraries/libstratosphere/include/stratosphere/sf/sf_out.hpp @@ -46,6 +46,9 @@ namespace ams::sf { constexpr Out(T *p) : m_ptr(p) { /* ... */ } constexpr Out(const cmif::PointerAndSize &pas) : m_ptr(reinterpret_cast(pas.GetAddress())) { /* TODO: Is AMS_ABORT_UNLESS(pas.GetSize() >= sizeof(T)); necessary? */ } + template requires (std::integral && std::is_enum::value && std::same_as::type, T>) + constexpr Out(U *p) : m_ptr(reinterpret_cast(p)) { static_assert(sizeof(U) == sizeof(T)); static_assert(alignof(U) == alignof(T)); } + void SetValue(const T& value) const { *m_ptr = value; } diff --git a/libraries/libstratosphere/include/stratosphere/sf/sf_service_object.hpp b/libraries/libstratosphere/include/stratosphere/sf/sf_service_object.hpp index 8f0495327..a6fa1ce41 100644 --- a/libraries/libstratosphere/include/stratosphere/sf/sf_service_object.hpp +++ b/libraries/libstratosphere/include/stratosphere/sf/sf_service_object.hpp @@ -29,26 +29,31 @@ namespace ams::sf { template concept IsServiceObject = std::derived_from; - class IMitmServiceObject : public IServiceObject { - public: - virtual ~IMitmServiceObject() { /* ... */ } - }; + #if AMS_SF_MITM_SUPPORTED + class IMitmServiceObject : public IServiceObject { + public: + virtual ~IMitmServiceObject() { /* ... */ } + }; - class MitmServiceImplBase { - protected: - std::shared_ptr<::Service> m_forward_service; - sm::MitmProcessInfo m_client_info; - public: - MitmServiceImplBase(std::shared_ptr<::Service> &&s, const sm::MitmProcessInfo &c) : m_forward_service(std::move(s)), m_client_info(c) { /* ... */ } - }; + class MitmServiceImplBase { + protected: + std::shared_ptr<::Service> m_forward_service; + sm::MitmProcessInfo m_client_info; + public: + MitmServiceImplBase(std::shared_ptr<::Service> &&s, const sm::MitmProcessInfo &c) : m_forward_service(std::move(s)), m_client_info(c) { /* ... */ } + }; - template - concept IsMitmServiceObject = IsServiceObject && std::derived_from; + template + concept IsMitmServiceObject = IsServiceObject && std::derived_from; - template - concept IsMitmServiceImpl = requires (std::shared_ptr<::Service> &&s, const sm::MitmProcessInfo &c) { - { T(std::forward>(s), c) }; - { T::ShouldMitm(c) } -> std::same_as; - }; + template + concept IsMitmServiceImpl = requires (std::shared_ptr<::Service> &&s, const sm::MitmProcessInfo &c) { + { T(std::forward>(s), c) }; + { T::ShouldMitm(c) } -> std::same_as; + }; + #else + template + concept IsMitmServiceObject = false; + #endif } diff --git a/libraries/libstratosphere/include/stratosphere/sf/sf_shared_object.hpp b/libraries/libstratosphere/include/stratosphere/sf/sf_shared_object.hpp index 1205822c3..3e74dbcdc 100644 --- a/libraries/libstratosphere/include/stratosphere/sf/sf_shared_object.hpp +++ b/libraries/libstratosphere/include/stratosphere/sf/sf_shared_object.hpp @@ -15,6 +15,7 @@ */ #pragma once #include +#include #include namespace ams::sf { diff --git a/libraries/libstratosphere/include/stratosphere/sf/sf_types.hpp b/libraries/libstratosphere/include/stratosphere/sf/sf_types.hpp new file mode 100644 index 000000000..641462308 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/sf/sf_types.hpp @@ -0,0 +1,506 @@ +/* + * Copyright (c) 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 + +#if defined(ATMOSPHERE_OS_WINDOWS) || defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS) + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(ATMOSPHERE_COMPILER_CLANG) +#define AMS_SF_HIPC_PARSE_IMPL_CONSTEXPR ALWAYS_INLINE +#else +#define AMS_SF_HIPC_PARSE_IMPL_CONSTEXPR constexpr ALWAYS_INLINE +#endif + +#define HIPC_AUTO_RECV_STATIC UINT8_MAX +#define HIPC_RESPONSE_NO_PID UINT32_MAX + +typedef struct HipcMetadata { + u32 type; + u32 num_send_statics; + u32 num_send_buffers; + u32 num_recv_buffers; + u32 num_exch_buffers; + u32 num_data_words; + u32 num_recv_statics; // also accepts HIPC_AUTO_RECV_STATIC + u32 send_pid; + u32 num_copy_handles; + u32 num_move_handles; +} HipcMetadata; + +typedef struct HipcHeader { + u32 type : 16; + u32 num_send_statics : 4; + u32 num_send_buffers : 4; + u32 num_recv_buffers : 4; + u32 num_exch_buffers : 4; + u32 num_data_words : 10; + u32 recv_static_mode : 4; + u32 padding : 6; + u32 recv_list_offset : 11; // Unused. + u32 has_special_header : 1; +} HipcHeader; + +typedef struct HipcSpecialHeader { + u32 send_pid : 1; + u32 num_copy_handles : 4; + u32 num_move_handles : 4; + u32 padding : 23; +} HipcSpecialHeader; + +typedef struct HipcStaticDescriptor { + u32 index : 6; + u32 address_high : 6; + u32 address_mid : 4; + u32 size : 16; + u32 address_low; +} HipcStaticDescriptor; + +typedef struct HipcBufferDescriptor { + u32 size_low; + u32 address_low; + u32 mode : 2; + u32 address_high : 22; + u32 size_high : 4; + u32 address_mid : 4; +} HipcBufferDescriptor; + +typedef struct HipcRecvListEntry { + u32 address_low; + u32 address_high : 16; + u32 size : 16; +} HipcRecvListEntry; + +typedef struct HipcRequest { + HipcStaticDescriptor* send_statics; + HipcBufferDescriptor* send_buffers; + HipcBufferDescriptor* recv_buffers; + HipcBufferDescriptor* exch_buffers; + u32* data_words; + HipcRecvListEntry* recv_list; + u32* copy_handles; + u32* move_handles; +} HipcRequest; + +typedef struct HipcParsedRequest { + HipcMetadata meta; + HipcRequest data; + u64 pid; +} HipcParsedRequest; + +typedef struct HipcResponse { + u64 pid; + u32 num_statics; + u32 num_data_words; + u32 num_copy_handles; + u32 num_move_handles; + HipcStaticDescriptor* statics; + u32* data_words; + u32* copy_handles; + u32* move_handles; +} HipcResponse; + +typedef enum HipcBufferMode { + HipcBufferMode_Normal = 0, + HipcBufferMode_NonSecure = 1, + HipcBufferMode_Invalid = 2, + HipcBufferMode_NonDevice = 3, +} HipcBufferMode; + + +AMS_SF_HIPC_PARSE_IMPL_CONSTEXPR HipcStaticDescriptor hipcMakeSendStatic(const void* buffer, size_t size, u8 index) { + return (HipcStaticDescriptor){ + .index = index, + .address_high = (u32)((uintptr_t)buffer >> 36), + .address_mid = (u32)((uintptr_t)buffer >> 32), + .size = (u32)size, + .address_low = (u32)(uintptr_t)buffer, + }; +} + +AMS_SF_HIPC_PARSE_IMPL_CONSTEXPR HipcBufferDescriptor hipcMakeBuffer(const void* buffer, size_t size, HipcBufferMode mode) { + return (HipcBufferDescriptor){ + .size_low = (u32)size, + .address_low = (u32)(uintptr_t)buffer, + .mode = mode, + .address_high = (u32)((uintptr_t)buffer >> 36), + .size_high = (u32)(size >> 32), + .address_mid = (u32)((uintptr_t)buffer >> 32), + }; +} + +AMS_SF_HIPC_PARSE_IMPL_CONSTEXPR HipcRecvListEntry hipcMakeRecvStatic(void* buffer, size_t size) { + return (HipcRecvListEntry){ + .address_low = (u32)((uintptr_t)buffer), + .address_high = (u32)((uintptr_t)buffer >> 32), + .size = (u32)size, + }; +} + +AMS_SF_HIPC_PARSE_IMPL_CONSTEXPR void* hipcGetStaticAddress(const HipcStaticDescriptor* desc) +{ + return (void*)(desc->address_low | ((uintptr_t)desc->address_mid << 32) | ((uintptr_t)desc->address_high << 36)); +} + +AMS_SF_HIPC_PARSE_IMPL_CONSTEXPR size_t hipcGetStaticSize(const HipcStaticDescriptor* desc) +{ + return desc->size; +} + +AMS_SF_HIPC_PARSE_IMPL_CONSTEXPR void* hipcGetBufferAddress(const HipcBufferDescriptor* desc) +{ + return (void*)(desc->address_low | ((uintptr_t)desc->address_mid << 32) | ((uintptr_t)desc->address_high << 36)); +} + +AMS_SF_HIPC_PARSE_IMPL_CONSTEXPR size_t hipcGetBufferSize(const HipcBufferDescriptor* desc) +{ + return desc->size_low | ((size_t)desc->size_high << 32); +} + +AMS_SF_HIPC_PARSE_IMPL_CONSTEXPR HipcRequest hipcCalcRequestLayout(HipcMetadata meta, void* base) { + // Copy handles + u32* copy_handles = NULL; + if (meta.num_copy_handles) { + copy_handles = (u32*)base; + base = copy_handles + meta.num_copy_handles; + } + + // Move handles + u32* move_handles = NULL; + if (meta.num_move_handles) { + move_handles = (u32*)base; + base = move_handles + meta.num_move_handles; + } + + // Send statics + HipcStaticDescriptor* send_statics = NULL; + if (meta.num_send_statics) { + send_statics = (HipcStaticDescriptor*)base; + base = send_statics + meta.num_send_statics; + } + + // Send buffers + HipcBufferDescriptor* send_buffers = NULL; + if (meta.num_send_buffers) { + send_buffers = (HipcBufferDescriptor*)base; + base = send_buffers + meta.num_send_buffers; + } + + // Recv buffers + HipcBufferDescriptor* recv_buffers = NULL; + if (meta.num_recv_buffers) { + recv_buffers = (HipcBufferDescriptor*)base; + base = recv_buffers + meta.num_recv_buffers; + } + + // Exch buffers + HipcBufferDescriptor* exch_buffers = NULL; + if (meta.num_exch_buffers) { + exch_buffers = (HipcBufferDescriptor*)base; + base = exch_buffers + meta.num_exch_buffers; + } + + // Data words + u32* data_words = NULL; + if (meta.num_data_words) { + data_words = (u32*)base; + base = data_words + meta.num_data_words; + } + + // Recv list + HipcRecvListEntry* recv_list = NULL; + if (meta.num_recv_statics) + recv_list = (HipcRecvListEntry*)base; + + return (HipcRequest){ + .send_statics = send_statics, + .send_buffers = send_buffers, + .recv_buffers = recv_buffers, + .exch_buffers = exch_buffers, + .data_words = data_words, + .recv_list = recv_list, + .copy_handles = copy_handles, + .move_handles = move_handles, + }; +} + +AMS_SF_HIPC_PARSE_IMPL_CONSTEXPR HipcRequest hipcMakeRequest(void* base, HipcMetadata meta) { + // Write message header + bool has_special_header = meta.send_pid || meta.num_copy_handles || meta.num_move_handles; + HipcHeader* hdr = (HipcHeader*)base; + base = hdr+1; + *hdr = (HipcHeader){ + .type = meta.type, + .num_send_statics = meta.num_send_statics, + .num_send_buffers = meta.num_send_buffers, + .num_recv_buffers = meta.num_recv_buffers, + .num_exch_buffers = meta.num_exch_buffers, + .num_data_words = meta.num_data_words, + .recv_static_mode = meta.num_recv_statics ? (meta.num_recv_statics != HIPC_AUTO_RECV_STATIC ? 2u + meta.num_recv_statics : 2u) : 0u, + .padding = 0, + .recv_list_offset = 0, + .has_special_header = has_special_header, + }; + + // Write special header + if (has_special_header) { + HipcSpecialHeader* sphdr = (HipcSpecialHeader*)base; + base = sphdr+1; + *sphdr = (HipcSpecialHeader){ + .send_pid = meta.send_pid, + .num_copy_handles = meta.num_copy_handles, + .num_move_handles = meta.num_move_handles, + }; + if (meta.send_pid) + base = (u8*)base + sizeof(u64); + } + + // Calculate layout + return hipcCalcRequestLayout(meta, base); +} + +#define hipcMakeRequestInline(_base,...) hipcMakeRequest((_base),(HipcMetadata){ __VA_ARGS__ }) + +AMS_SF_HIPC_PARSE_IMPL_CONSTEXPR HipcParsedRequest hipcParseRequest(void* base) { + // Parse message header + HipcHeader hdr = {}; + __builtin_memcpy(&hdr, base, sizeof(hdr)); + base = (u8*)base + sizeof(hdr); + u32 num_recv_statics = 0; + u64 pid = 0; + + // Parse recv static mode + if (hdr.recv_static_mode) { + if (hdr.recv_static_mode == 2u) + num_recv_statics = HIPC_AUTO_RECV_STATIC; + else if (hdr.recv_static_mode > 2u) + num_recv_statics = hdr.recv_static_mode - 2u; + } + + // Parse special header + HipcSpecialHeader sphdr = {}; + if (hdr.has_special_header) { + __builtin_memcpy(&sphdr, base, sizeof(sphdr)); + base = (u8*)base + sizeof(sphdr); + + // Read PID descriptor + if (sphdr.send_pid) { + pid = *(u64*)base; + base = (u8*)base + sizeof(u64); + } + } + + const HipcMetadata meta = { + .type = hdr.type, + .num_send_statics = hdr.num_send_statics, + .num_send_buffers = hdr.num_send_buffers, + .num_recv_buffers = hdr.num_recv_buffers, + .num_exch_buffers = hdr.num_exch_buffers, + .num_data_words = hdr.num_data_words, + .num_recv_statics = num_recv_statics, + .send_pid = sphdr.send_pid, + .num_copy_handles = sphdr.num_copy_handles, + .num_move_handles = sphdr.num_move_handles, + }; + + return (HipcParsedRequest){ + .meta = meta, + .data = hipcCalcRequestLayout(meta, base), + .pid = pid, + }; +} + +AMS_SF_HIPC_PARSE_IMPL_CONSTEXPR HipcResponse hipcParseResponse(void* base) { + // Parse header + HipcHeader hdr = {}; + __builtin_memcpy(&hdr, base, sizeof(hdr)); + base = (u8*)base + sizeof(hdr); + + // Initialize response + HipcResponse response = {}; + response.num_statics = hdr.num_send_statics; + response.num_data_words = hdr.num_data_words; + response.pid = HIPC_RESPONSE_NO_PID; + + // Parse special header + if (hdr.has_special_header) + { + HipcSpecialHeader sphdr = {}; + __builtin_memcpy(&sphdr, base, sizeof(sphdr)); + base = (u8*)base + sizeof(sphdr); + + // Update response + response.num_copy_handles = sphdr.num_copy_handles; + response.num_move_handles = sphdr.num_move_handles; + + // Parse PID descriptor + if (sphdr.send_pid) { + response.pid = *(u64*)base; + base = (u8*)base + sizeof(u64); + } + } + + // Copy handles + response.copy_handles = (u32*)base; + base = response.copy_handles + response.num_copy_handles; + + // Move handles + response.move_handles = (u32*)base; + base = response.move_handles + response.num_move_handles; + + // Send statics + response.statics = (HipcStaticDescriptor*)base; + base = response.statics + response.num_statics; + + // Data words + response.data_words = (u32*)base; + + return response; +} + +typedef enum CmifCommandType { + CmifCommandType_Invalid = 0, + CmifCommandType_LegacyRequest = 1, + CmifCommandType_Close = 2, + CmifCommandType_LegacyControl = 3, + CmifCommandType_Request = 4, + CmifCommandType_Control = 5, + CmifCommandType_RequestWithContext = 6, + CmifCommandType_ControlWithContext = 7, +} CmifCommandType; + +typedef enum CmifDomainRequestType { + CmifDomainRequestType_Invalid = 0, + CmifDomainRequestType_SendMessage = 1, + CmifDomainRequestType_Close = 2, +} CmifDomainRequestType; + +typedef struct CmifInHeader { + u32 magic; + u32 version; + u32 command_id; + u32 token; +} CmifInHeader; + +typedef struct CmifOutHeader { + u32 magic; + u32 version; + Result result; + u32 token; +} CmifOutHeader; + +typedef struct CmifDomainInHeader { + u8 type; + u8 num_in_objects; + u16 data_size; + u32 object_id; + u32 padding; + u32 token; +} CmifDomainInHeader; + +typedef struct CmifDomainOutHeader { + u32 num_out_objects; + u32 padding[3]; +} CmifDomainOutHeader; + +typedef struct CmifRequestFormat { + u32 object_id; + u32 request_id; + u32 context; + u32 data_size; + u32 server_pointer_size; + u32 num_in_auto_buffers; + u32 num_out_auto_buffers; + u32 num_in_buffers; + u32 num_out_buffers; + u32 num_inout_buffers; + u32 num_in_pointers; + u32 num_out_pointers; + u32 num_out_fixed_pointers; + u32 num_objects; + u32 num_handles; + u32 send_pid; +} CmifRequestFormat; + +typedef struct CmifRequest { + HipcRequest hipc; + void* data; + u16* out_pointer_sizes; + u32* objects; + u32 server_pointer_size; + u32 cur_in_ptr_id; +} CmifRequest; + +typedef struct CmifResponse { + void* data; + u32* objects; + u32* copy_handles; + u32* move_handles; +} CmifResponse; + +enum { + SfBufferAttr_In = BIT(0), + SfBufferAttr_Out = BIT(1), + SfBufferAttr_HipcMapAlias = BIT(2), + SfBufferAttr_HipcPointer = BIT(3), + SfBufferAttr_FixedSize = BIT(4), + SfBufferAttr_HipcAutoSelect = BIT(5), + SfBufferAttr_HipcMapTransferAllowsNonSecure = BIT(6), + SfBufferAttr_HipcMapTransferAllowsNonDevice = BIT(7), +}; + +typedef struct SfBufferAttrs { + u32 attr0; + u32 attr1; + u32 attr2; + u32 attr3; + u32 attr4; + u32 attr5; + u32 attr6; + u32 attr7; +} SfBufferAttrs; + +typedef struct SfBuffer { + const void* ptr; + size_t size; +} SfBuffer; + +typedef enum SfOutHandleAttr { + SfOutHandleAttr_None = 0, + SfOutHandleAttr_HipcCopy = 1, + SfOutHandleAttr_HipcMove = 2, +} SfOutHandleAttr; + +typedef struct SfOutHandleAttrs { + SfOutHandleAttr attr0; + SfOutHandleAttr attr1; + SfOutHandleAttr attr2; + SfOutHandleAttr attr3; + SfOutHandleAttr attr4; + SfOutHandleAttr attr5; + SfOutHandleAttr attr6; + SfOutHandleAttr attr7; +} SfOutHandleAttrs; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libraries/libstratosphere/include/stratosphere/sm/sm_api.hpp b/libraries/libstratosphere/include/stratosphere/sm/sm_api.hpp index eac646c7d..60f810455 100644 --- a/libraries/libstratosphere/include/stratosphere/sm/sm_api.hpp +++ b/libraries/libstratosphere/include/stratosphere/sm/sm_api.hpp @@ -25,7 +25,7 @@ namespace ams::sm { Result Finalize(); /* Ordinary SM API. */ - Result GetService(Service *out, ServiceName name); + Result GetServiceHandle(os::NativeHandle *out, ServiceName name); Result RegisterService(os::NativeHandle *out, ServiceName name, size_t max_sessions, bool is_light); Result UnregisterService(ServiceName name); diff --git a/libraries/libstratosphere/include/stratosphere/sm/sm_mitm_api.hpp b/libraries/libstratosphere/include/stratosphere/sm/sm_mitm_api.hpp index 22b07cfd3..c38d8ce42 100644 --- a/libraries/libstratosphere/include/stratosphere/sm/sm_mitm_api.hpp +++ b/libraries/libstratosphere/include/stratosphere/sm/sm_mitm_api.hpp @@ -15,9 +15,10 @@ */ #pragma once - #include +#include +#if AMS_SF_MITM_SUPPORTED namespace ams::sm::mitm { /* Mitm API. */ @@ -30,3 +31,4 @@ namespace ams::sm::mitm { Result WaitMitm(ServiceName name); } +#endif diff --git a/libraries/libstratosphere/include/stratosphere/socket.hpp b/libraries/libstratosphere/include/stratosphere/socket.hpp index 1ccbfce25..3cc5213fe 100644 --- a/libraries/libstratosphere/include/stratosphere/socket.hpp +++ b/libraries/libstratosphere/include/stratosphere/socket.hpp @@ -14,9 +14,13 @@ * along with this program. If not, see . */ #pragma once + +#if !defined(ATMOSPHERE_OS_WINDOWS) #include #include #include +#endif + #include #include #include diff --git a/libraries/libstratosphere/include/stratosphere/spl/spl_types.hpp b/libraries/libstratosphere/include/stratosphere/spl/spl_types.hpp index 3accdc621..f49638625 100644 --- a/libraries/libstratosphere/include/stratosphere/spl/spl_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/spl/spl_types.hpp @@ -248,6 +248,7 @@ namespace ams::spl { } +#if defined(ATMOSPHERE_OS_HORIZON) /* Extensions to libnx spl config item enum. */ constexpr inline SplConfigItem SplConfigItem_ExosphereApiVersion = static_cast(65000); constexpr inline SplConfigItem SplConfigItem_ExosphereNeedsReboot = static_cast(65001); @@ -260,3 +261,4 @@ constexpr inline SplConfigItem SplConfigItem_ExosphereEmummcType = static_ constexpr inline SplConfigItem SplConfigItem_ExospherePayloadAddress = static_cast(65008); constexpr inline SplConfigItem SplConfigItem_ExosphereLogConfiguration = static_cast(65009); constexpr inline SplConfigItem SplConfigItem_ExosphereForceEnableUsb30 = static_cast(65010); +#endif diff --git a/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_autogen_interface_macros.hpp b/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_autogen_interface_macros.hpp index 6705ddec2..39de5e0be 100644 --- a/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_autogen_interface_macros.hpp +++ b/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_autogen_interface_macros.hpp @@ -15,13 +15,14 @@ */ #pragma once #include +#include #include #include namespace ams::tipc::impl { template - concept HasDefaultServiceCommandProcessor = requires (T &t, const svc::ipc::MessageBuffer &message_buffer) { + concept HasDefaultServiceCommandProcessor = requires (T &t, const MessageBuffer &message_buffer) { { t.ProcessDefaultServiceCommand(message_buffer) } -> std::same_as; }; @@ -129,7 +130,7 @@ namespace ams::tipc::impl { constexpr explicit ImplTemplateBaseT(Args &&...args) : ImplHolder(std::forward(args)...) { /* ... */ } \ private: \ template \ - ALWAYS_INLINE Result ProcessDefaultMethod(ImplType *impl, const svc::ipc::MessageBuffer &message_buffer) const { \ + ALWAYS_INLINE Result ProcessDefaultMethod(ImplType *impl, const MessageBuffer &message_buffer) const { \ /* Handle a default command. */ \ if constexpr (HasDefaultServiceCommandProcessor) { \ return impl->ProcessDefaultServiceCommand(message_buffer); \ @@ -139,7 +140,7 @@ namespace ams::tipc::impl { } \ \ template \ - ALWAYS_INLINE Result ProcessMethodById(ImplType *impl, const svc::ipc::MessageBuffer &message_buffer, hos::Version fw_ver) const { \ + ALWAYS_INLINE Result ProcessMethodById(ImplType *impl, const MessageBuffer &message_buffer, hos::Version fw_ver) const { \ CMD_MACRO(ImplType, AMS_TIPC_IMPL_PROCESS_METHOD_REQUEST_BY_ID) \ \ return this->ProcessDefaultMethod(impl, message_buffer); \ @@ -159,10 +160,10 @@ namespace ams::tipc::impl { static_assert(::NAMESPACE::Is##INTERFACE); \ \ /* Get accessor to the message buffer. */ \ - const svc::ipc::MessageBuffer message_buffer(svc::ipc::GetMessageBuffer()); \ + const MessageBuffer message_buffer(tipc::GetMessageBuffer()); \ \ /* Get decision variables. */ \ - const auto tag = svc::ipc::MessageBuffer::MessageHeader(message_buffer).GetTag(); \ + const auto tag = MessageBuffer::MessageHeader(message_buffer).GetTag(); \ const auto fw_ver = IsFirmwareVersionAlwaysValid() ? hos::Version_Current : hos::GetVersion(); \ \ /* Process against the command ids. */ \ diff --git a/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_command_serialization.hpp b/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_command_serialization.hpp index 1a4b3504e..aba8cb160 100644 --- a/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_command_serialization.hpp +++ b/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_command_serialization.hpp @@ -29,6 +29,7 @@ namespace ams::tipc { } +#if defined(ATMOSPHERE_OS_HORIZON) namespace ams::tipc::impl { /* Machinery for filtering type lists. */ @@ -302,21 +303,21 @@ namespace ams::tipc::impl { /* tipc-specific accessors. */ static constexpr bool HasInSpecialHeader = HasProcessId || NumInHandles > 0; - static constexpr svc::ipc::MessageBuffer::MessageHeader InMessageHeader{CommandId, HasInSpecialHeader, 0, NumInBuffers, NumOutBuffers, 0, InDataSize / sizeof(u32), 0}; - static constexpr svc::ipc::MessageBuffer::SpecialHeader InSpecialHeader{HasProcessId, NumInCopyHandles, NumInMoveHandles, HasInSpecialHeader}; + static constexpr MessageBuffer::MessageHeader InMessageHeader{CommandId, HasInSpecialHeader, 0, NumInBuffers, NumOutBuffers, 0, InDataSize / sizeof(u32), 0}; + static constexpr MessageBuffer::SpecialHeader InSpecialHeader{HasProcessId, NumInCopyHandles, NumInMoveHandles, HasInSpecialHeader}; - static constexpr auto InMessageProcessIdIndex = svc::ipc::MessageBuffer::GetSpecialDataIndex(InMessageHeader, InSpecialHeader); - static constexpr auto InMessageHandleIndex = svc::ipc::MessageBuffer::GetSpecialDataIndex(InMessageHeader, InSpecialHeader) + (HasProcessId ? sizeof(u64) / sizeof(u32) : 0); - static constexpr auto InMessageBufferIndex = svc::ipc::MessageBuffer::GetMapAliasDescriptorIndex(InMessageHeader, InSpecialHeader); - static constexpr auto InMessageRawDataIndex = svc::ipc::MessageBuffer::GetRawDataIndex(InMessageHeader, InSpecialHeader); + static constexpr auto InMessageProcessIdIndex = MessageBuffer::GetSpecialDataIndex(InMessageHeader, InSpecialHeader); + static constexpr auto InMessageHandleIndex = MessageBuffer::GetSpecialDataIndex(InMessageHeader, InSpecialHeader) + (HasProcessId ? sizeof(u64) / sizeof(u32) : 0); + static constexpr auto InMessageBufferIndex = MessageBuffer::GetMapAliasDescriptorIndex(InMessageHeader, InSpecialHeader); + static constexpr auto InMessageRawDataIndex = MessageBuffer::GetRawDataIndex(InMessageHeader, InSpecialHeader); static constexpr bool HasOutSpecialHeader = NumOutHandles > 0; - static constexpr svc::ipc::MessageBuffer::MessageHeader OutMessageHeader{CommandId, HasOutSpecialHeader, 0, 0, 0, 0, (OutDataSize / sizeof(u32)) + 1, 0}; - static constexpr svc::ipc::MessageBuffer::SpecialHeader OutSpecialHeader{false, NumOutCopyHandles, NumOutMoveHandles, HasOutSpecialHeader}; + static constexpr MessageBuffer::MessageHeader OutMessageHeader{CommandId, HasOutSpecialHeader, 0, 0, 0, 0, (OutDataSize / sizeof(u32)) + 1, 0}; + static constexpr MessageBuffer::SpecialHeader OutSpecialHeader{false, NumOutCopyHandles, NumOutMoveHandles, HasOutSpecialHeader}; - static constexpr auto OutMessageHandleIndex = svc::ipc::MessageBuffer::GetSpecialDataIndex(OutMessageHeader, OutSpecialHeader); - static constexpr auto OutMessageResultIndex = svc::ipc::MessageBuffer::GetRawDataIndex(OutMessageHeader, OutSpecialHeader); + static constexpr auto OutMessageHandleIndex = MessageBuffer::GetSpecialDataIndex(OutMessageHeader, OutSpecialHeader); + static constexpr auto OutMessageResultIndex = MessageBuffer::GetRawDataIndex(OutMessageHeader, OutSpecialHeader); static constexpr auto OutMessageRawDataIndex = OutMessageResultIndex + 1; static constexpr size_t InMessageTotalSize = (InMessageRawDataIndex * sizeof(u32)) + InDataSize; @@ -410,7 +411,7 @@ namespace ams::tipc::impl { return reinterpret_cast(data + Offset); } - constexpr ALWAYS_INLINE void CopyTo(const svc::ipc::MessageBuffer &buffer) const { + constexpr ALWAYS_INLINE void CopyTo(const MessageBuffer &buffer) const { if constexpr (Size > 0) { buffer.SetRawArray(OutIndex, data, Size); } @@ -423,24 +424,24 @@ namespace ams::tipc::impl { static constexpr size_t NumMove = _NumMove; static constexpr size_t NumCopy = _NumCopy; private: - os::NativeHandle move_handles[NumMove]; - os::NativeHandle copy_handles[NumCopy]; + tipc::NativeHandle move_handles[NumMove]; + tipc::NativeHandle copy_handles[NumCopy]; public: ALWAYS_INLINE OutHandleHolder() { /* ... */ } template - constexpr ALWAYS_INLINE os::NativeHandle *GetMoveHandlePointer() { + constexpr ALWAYS_INLINE tipc::NativeHandle *GetMoveHandlePointer() { static_assert(Index < NumMove, "Index < NumMove"); return move_handles + Index; } template - constexpr ALWAYS_INLINE os::NativeHandle *GetCopyHandlePointer() { + constexpr ALWAYS_INLINE tipc::NativeHandle *GetCopyHandlePointer() { static_assert(Index < NumCopy, "Index < NumCopy"); return copy_handles + Index; } - ALWAYS_INLINE void CopyTo(const svc::ipc::MessageBuffer &buffer) const { + ALWAYS_INLINE void CopyTo(const MessageBuffer &buffer) const { #define _TIPC_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(n) do { if constexpr (NumCopy > n) { buffer.SetHandle(OutIndex + n, copy_handles[n]); } } while (0) _TIPC_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(0); _TIPC_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(1); @@ -475,7 +476,7 @@ namespace ams::tipc::impl { using OutRawHolderType = OutRawHolder; using OutHandleHolderType = OutHandleHolder; private: - static constexpr u64 GetMessageHeaderForCheck(const svc::ipc::MessageBuffer::MessageHeader &header) { + static constexpr u64 GetMessageHeaderForCheck(const MessageBuffer::MessageHeader &header) { using Value = util::BitPack32::Field<0, BITSIZEOF(util::BitPack32)>; const util::BitPack32 *data = header.GetData(); @@ -485,7 +486,7 @@ namespace ams::tipc::impl { return static_cast(lower) | (static_cast(upper) << BITSIZEOF(u32)); } - static constexpr u32 GetSpecialHeaderForCheck(const svc::ipc::MessageBuffer::SpecialHeader &header) { + static constexpr u32 GetSpecialHeaderForCheck(const MessageBuffer::SpecialHeader &header) { using Value = util::BitPack32::Field<0, BITSIZEOF(util::BitPack32)>; return header.GetHeader()->Get(); @@ -493,7 +494,7 @@ namespace ams::tipc::impl { /* Argument deserialization. */ template::type> - static ALWAYS_INLINE typename std::tuple_element::type DeserializeArgumentImpl(const svc::ipc::MessageBuffer &message_buffer, const OutRawHolderType &out_raw_holder, OutHandleHolderType &out_handles_holder) { + static ALWAYS_INLINE typename std::tuple_element::type DeserializeArgumentImpl(const MessageBuffer &message_buffer, const OutRawHolderType &out_raw_holder, OutHandleHolderType &out_handles_holder) { constexpr auto Info = CommandMeta::ArgumentSerializationInfos[Index]; if constexpr (Info.arg_type == ArgumentType::InData) { /* New in rawdata. */ @@ -524,12 +525,12 @@ namespace ams::tipc::impl { } else if constexpr (Info.arg_type == ArgumentType::OutHandle) { /* New OutHandle. */ if constexpr (std::same_as) { - os::NativeHandle * const ptr = out_handles_holder.template GetMoveHandlePointer(); - *ptr = os::InvalidNativeHandle; + tipc::NativeHandle * const ptr = out_handles_holder.template GetMoveHandlePointer(); + *ptr = tipc::InvalidNativeHandle; return T(ptr); } else if constexpr (std::same_as) { - os::NativeHandle * const ptr = out_handles_holder.template GetCopyHandlePointer(); - *ptr = os::InvalidNativeHandle; + tipc::NativeHandle * const ptr = out_handles_holder.template GetCopyHandlePointer(); + *ptr = tipc::InvalidNativeHandle; return T(ptr); } else { static_assert(!std::is_same::value, "Invalid OutHandle kind"); @@ -537,19 +538,19 @@ namespace ams::tipc::impl { } else if constexpr (Info.arg_type == ArgumentType::Buffer) { /* NOTE: There are currently no tipc commands which use buffers-with-attributes */ /* If these are added (e.g., NonSecure buffers), implement checking here? */ - constexpr size_t MapAliasDescriptorSize = svc::ipc::MessageBuffer::MapAliasDescriptor::GetDataSize(); + constexpr size_t MapAliasDescriptorSize = MessageBuffer::MapAliasDescriptor::GetDataSize(); if constexpr (Info.is_send_buffer) { /* Input send buffer. */ constexpr auto BufferIndex = CommandMeta::InMessageBufferIndex + (Info.send_map_alias_index * MapAliasDescriptorSize / sizeof(util::BitPack32)); - const svc::ipc::MessageBuffer::MapAliasDescriptor descriptor(message_buffer, BufferIndex); + const MessageBuffer::MapAliasDescriptor descriptor(message_buffer, BufferIndex); return T(descriptor.GetAddress(), descriptor.GetSize()); } else { /* Input receive buffer. */ constexpr auto BufferIndex = CommandMeta::InMessageBufferIndex + ((CommandMeta::NumInBuffers + Info.recv_map_alias_index) * MapAliasDescriptorSize / sizeof(util::BitPack32)); - const svc::ipc::MessageBuffer::MapAliasDescriptor descriptor(message_buffer, BufferIndex); + const MessageBuffer::MapAliasDescriptor descriptor(message_buffer, BufferIndex); return T(descriptor.GetAddress(), descriptor.GetSize()); } } else if constexpr (Info.arg_type == ArgumentType::ProcessId) { @@ -559,7 +560,7 @@ namespace ams::tipc::impl { } } public: - static ALWAYS_INLINE Result ValidateCommandFormat(const svc::ipc::MessageBuffer &message_buffer) { + static ALWAYS_INLINE Result ValidateCommandFormat(const MessageBuffer &message_buffer) { /* Validate the message header. */ constexpr auto ExpectedMessageHeader = GetMessageHeaderForCheck(CommandMeta::InMessageHeader); R_UNLESS(message_buffer.Get64(0) == ExpectedMessageHeader, tipc::ResultInvalidMessageFormat()); @@ -567,7 +568,7 @@ namespace ams::tipc::impl { /* Validate the special header. */ if constexpr (CommandMeta::HasInSpecialHeader) { constexpr auto ExpectedSpecialHeader = GetSpecialHeaderForCheck(CommandMeta::InSpecialHeader); - constexpr auto SpecialHeaderIndex = svc::ipc::MessageBuffer::MessageHeader::GetDataSize() / sizeof(util::BitPack32); + constexpr auto SpecialHeaderIndex = MessageBuffer::MessageHeader::GetDataSize() / sizeof(util::BitPack32); R_UNLESS(message_buffer.Get32(SpecialHeaderIndex) == ExpectedSpecialHeader, tipc::ResultInvalidMessageFormat()); } @@ -575,11 +576,11 @@ namespace ams::tipc::impl { } template - static ALWAYS_INLINE auto DeserializeArgument(const svc::ipc::MessageBuffer &message_buffer, const OutRawHolderType &out_raw_holder, OutHandleHolderType &out_handles_holder) { + static ALWAYS_INLINE auto DeserializeArgument(const MessageBuffer &message_buffer, const OutRawHolderType &out_raw_holder, OutHandleHolderType &out_handles_holder) { return DeserializeArgumentImpl(message_buffer, out_raw_holder, out_handles_holder); } - static ALWAYS_INLINE void SerializeResults(const svc::ipc::MessageBuffer &message_buffer, const Result &result, const OutRawHolderType &out_raw_holder, const OutHandleHolderType &out_handles_holder) { + static ALWAYS_INLINE void SerializeResults(const MessageBuffer &message_buffer, const Result &result, const OutRawHolderType &out_raw_holder, const OutHandleHolderType &out_handles_holder) { /* Set output headers. */ message_buffer.Set(CommandMeta::OutMessageHeader); if constexpr (CommandMeta::HasOutSpecialHeader) { @@ -607,7 +608,7 @@ namespace ams::tipc::impl { }; template - constexpr ALWAYS_INLINE Result InvokeServiceCommandImpl(ClassType *object, const svc::ipc::MessageBuffer &message_buffer) { + constexpr ALWAYS_INLINE Result InvokeServiceCommandImpl(ClassType *object, const MessageBuffer &message_buffer) { using Return = decltype(FunctionTraits::GetReturnImpl(ServiceCommandImpl)); using TrueArgumentsTuple = decltype(FunctionTraits::GetArgumentsImpl(ServiceCommandImpl)); @@ -641,3 +642,97 @@ namespace ams::tipc::impl { } } +#elif defined(ATMOSPHERE_OS_WINDOWS) +namespace ams::tipc::impl { + + template + struct CommandMetaInfo; + + template + struct CommandMetaInfo<_CommandId, std::tuple> { + public: + static constexpr size_t InMessageTotalSize = 0x40; /* TODO */ + static constexpr size_t OutMessageTotalSize = 0x40; /* TODO */ + }; + + template + class CommandProcessor { + public: + static ALWAYS_INLINE Result ValidateCommandFormat(const MessageBuffer &) { + AMS_ABORT("TODO"); + } + }; + + template + ALWAYS_INLINE Result InvokeServiceCommandImpl(ClassType *object, const MessageBuffer &message_buffer) { + /* TODO: Is some kind of emulated serialization interesting/desirable? */ + /* TIPC is generally a huge TODO. */ + AMS_UNUSED(object, message_buffer); + AMS_ABORT("TIPC serialization not currently supported on Windows."); + } + +} +#elif defined(ATMOSPHERE_OS_LINUX) +namespace ams::tipc::impl { + + template + struct CommandMetaInfo; + + template + struct CommandMetaInfo<_CommandId, std::tuple> { + public: + static constexpr size_t InMessageTotalSize = 0x40; /* TODO */ + static constexpr size_t OutMessageTotalSize = 0x40; /* TODO */ + }; + + template + class CommandProcessor { + public: + static ALWAYS_INLINE Result ValidateCommandFormat(const MessageBuffer &) { + AMS_ABORT("TODO"); + } + }; + + template + ALWAYS_INLINE Result InvokeServiceCommandImpl(ClassType *object, const MessageBuffer &message_buffer) { + /* TODO: Is some kind of emulated serialization interesting/desirable? */ + /* TIPC is generally a huge TODO. */ + AMS_UNUSED(object, message_buffer); + AMS_ABORT("TIPC serialization not currently supported on Linux."); + } + +} +#elif defined(ATMOSPHERE_OS_MACOS) +namespace ams::tipc::impl { + + template + struct CommandMetaInfo; + + template + struct CommandMetaInfo<_CommandId, std::tuple> { + public: + static constexpr size_t InMessageTotalSize = 0x40; /* TODO */ + static constexpr size_t OutMessageTotalSize = 0x40; /* TODO */ + }; + + template + class CommandProcessor { + public: + static ALWAYS_INLINE Result ValidateCommandFormat(const MessageBuffer &) { + AMS_ABORT("TODO"); + } + }; + + template + ALWAYS_INLINE Result InvokeServiceCommandImpl(ClassType *object, const MessageBuffer &message_buffer) { + /* TODO: Is some kind of emulated serialization interesting/desirable? */ + /* TIPC is generally a huge TODO. */ + AMS_UNUSED(object, message_buffer); + AMS_ABORT("TIPC serialization not currently supported on macOS."); + } + +} + +#else + #error "Unknown OS for tipc Command serialization." +#endif diff --git a/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_message_api.hpp b/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_message_api.hpp new file mode 100644 index 000000000..f8f488f75 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_message_api.hpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 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 + +#if defined(ATMOSPHERE_OS_HORIZON) + #include +#elif defined(ATMOSPHERE_OS_WINDOWS) + #include +#elif defined(ATMOSPHERE_OS_LINUX) + #include +#elif defined(ATMOSPHERE_OS_MACOS) + #include +#else + #error "Unknown OS for tipc message impl" +#endif diff --git a/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_message_api.os.horizon.hpp b/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_message_api.os.horizon.hpp new file mode 100644 index 000000000..998100f43 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_message_api.os.horizon.hpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 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 +#include + +namespace ams::tipc::impl { + + inline void Reply(tipc::NativeHandle reply_target) { + /* Perform the reply. */ + s32 dummy; + R_TRY_CATCH(svc::ReplyAndReceive(std::addressof(dummy), nullptr, 0, reply_target, 0)) { + R_CATCH(svc::ResultTimedOut) { + /* Timing out is acceptable. */ + } + R_CATCH(svc::ResultSessionClosed) { + /* It's okay if we couldn't reply to a closed session. */ + } + } R_END_TRY_CATCH_WITH_ABORT_UNLESS; + } + + ALWAYS_INLINE Result CloseHandle(tipc::NativeHandle handle) { + return svc::CloseHandle(handle); + } + + ALWAYS_INLINE Result CreateSession(tipc::NativeHandle *out_server_session_handle, tipc::NativeHandle *out_client_session_handle, bool is_light, uintptr_t name) { + return svc::CreateSession(out_server_session_handle, out_client_session_handle, is_light, name); + } + + ALWAYS_INLINE Result AcceptSession(tipc::NativeHandle *out_handle, tipc::NativeHandle port) { + return svc::AcceptSession(out_handle, port); + } + +} diff --git a/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_message_api.os.linux.hpp b/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_message_api.os.linux.hpp new file mode 100644 index 000000000..ea6ac49f3 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_message_api.os.linux.hpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 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 +#include + +namespace ams::tipc::impl { + + inline void Reply(tipc::NativeHandle reply_target) { + AMS_UNUSED(reply_target); + AMS_ABORT("TODO: tipc Linux Reply"); + } + + ALWAYS_INLINE Result CloseHandle(tipc::NativeHandle handle) { + AMS_UNUSED(handle); + AMS_ABORT("TODO: tipc Linux CloseHandle"); + } + + ALWAYS_INLINE Result CreateSession(tipc::NativeHandle *out_server_session_handle, tipc::NativeHandle *out_client_session_handle, bool is_light, uintptr_t name) { + AMS_UNUSED(out_server_session_handle, out_client_session_handle, is_light, name); + AMS_ABORT("TODO: tipc Linux CreateSession"); + } + + ALWAYS_INLINE Result AcceptSession(tipc::NativeHandle *out_handle, tipc::NativeHandle port) { + AMS_UNUSED(out_handle, port); + AMS_ABORT("TODO: tipc Linux AcceptSession"); + } + +} diff --git a/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_message_api.os.macos.hpp b/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_message_api.os.macos.hpp new file mode 100644 index 000000000..dd5d5bd77 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_message_api.os.macos.hpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 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 +#include + +namespace ams::tipc::impl { + + inline void Reply(tipc::NativeHandle reply_target) { + AMS_UNUSED(reply_target); + AMS_ABORT("TODO: tipc macOS Reply"); + } + + ALWAYS_INLINE Result CloseHandle(tipc::NativeHandle handle) { + AMS_UNUSED(handle); + AMS_ABORT("TODO: tipc macOS CloseHandle"); + } + + ALWAYS_INLINE Result CreateSession(tipc::NativeHandle *out_server_session_handle, tipc::NativeHandle *out_client_session_handle, bool is_light, uintptr_t name) { + AMS_UNUSED(out_server_session_handle, out_client_session_handle, is_light, name); + AMS_ABORT("TODO: tipc macOS CreateSession"); + } + + ALWAYS_INLINE Result AcceptSession(tipc::NativeHandle *out_handle, tipc::NativeHandle port) { + AMS_UNUSED(out_handle, port); + AMS_ABORT("TODO: tipc macOS AcceptSession"); + } + +} diff --git a/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_message_api.os.windows.hpp b/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_message_api.os.windows.hpp new file mode 100644 index 000000000..a8bd16254 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_message_api.os.windows.hpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 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 +#include + +namespace ams::tipc::impl { + + inline void Reply(tipc::NativeHandle reply_target) { + AMS_UNUSED(reply_target); + AMS_ABORT("TODO: tipc Windows Reply"); + } + + ALWAYS_INLINE Result CloseHandle(tipc::NativeHandle handle) { + AMS_UNUSED(handle); + AMS_ABORT("TODO: tipc Windows CloseHandle"); + } + + ALWAYS_INLINE Result CreateSession(tipc::NativeHandle *out_server_session_handle, tipc::NativeHandle *out_client_session_handle, bool is_light, uintptr_t name) { + AMS_UNUSED(out_server_session_handle, out_client_session_handle, is_light, name); + AMS_ABORT("TODO: tipc Windows CreateSession"); + } + + ALWAYS_INLINE Result AcceptSession(tipc::NativeHandle *out_handle, tipc::NativeHandle port) { + AMS_UNUSED(out_handle, port); + AMS_ABORT("TODO: tipc Windows AcceptSession"); + } + +} diff --git a/libraries/libstratosphere/include/stratosphere/tipc/tipc_buffers.hpp b/libraries/libstratosphere/include/stratosphere/tipc/tipc_buffers.hpp index 307caf456..9af8bd7c8 100644 --- a/libraries/libstratosphere/include/stratosphere/tipc/tipc_buffers.hpp +++ b/libraries/libstratosphere/include/stratosphere/tipc/tipc_buffers.hpp @@ -60,8 +60,8 @@ namespace ams::tipc { constexpr ALWAYS_INLINE InBufferBase(const tipc::PointerAndSize &pas) : BaseType(pas) { /* ... */ } constexpr ALWAYS_INLINE InBufferBase(uintptr_t ptr, size_t sz) : BaseType(ptr, sz) { /* ... */ } - constexpr ALWAYS_INLINE InBufferBase(const void *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } - constexpr ALWAYS_INLINE InBufferBase(const u8 *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } + ALWAYS_INLINE InBufferBase(const void *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } + ALWAYS_INLINE InBufferBase(const u8 *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } }; class OutBufferBase : public BufferBase { @@ -74,8 +74,8 @@ namespace ams::tipc { constexpr ALWAYS_INLINE OutBufferBase(const tipc::PointerAndSize &pas) : BaseType(pas) { /* ... */ } constexpr ALWAYS_INLINE OutBufferBase(uintptr_t ptr, size_t sz) : BaseType(ptr, sz) { /* ... */ } - constexpr ALWAYS_INLINE OutBufferBase(void *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } - constexpr ALWAYS_INLINE OutBufferBase(u8 *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } + ALWAYS_INLINE OutBufferBase(void *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } + ALWAYS_INLINE OutBufferBase(u8 *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } }; template @@ -89,10 +89,10 @@ namespace ams::tipc { constexpr ALWAYS_INLINE InBufferImpl(const tipc::PointerAndSize &pas) : BaseType(pas) { /* ... */ } constexpr ALWAYS_INLINE InBufferImpl(uintptr_t ptr, size_t sz) : BaseType(ptr, sz) { /* ... */ } - constexpr ALWAYS_INLINE InBufferImpl(const void *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } - constexpr ALWAYS_INLINE InBufferImpl(const u8 *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } + ALWAYS_INLINE InBufferImpl(const void *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } + ALWAYS_INLINE InBufferImpl(const u8 *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } - constexpr ALWAYS_INLINE const u8 *GetPointer() const { + ALWAYS_INLINE const u8 *GetPointer() const { return reinterpret_cast(this->GetAddressImpl()); } @@ -112,10 +112,10 @@ namespace ams::tipc { constexpr ALWAYS_INLINE OutBufferImpl(const tipc::PointerAndSize &pas) : BaseType(pas) { /* ... */ } constexpr ALWAYS_INLINE OutBufferImpl(uintptr_t ptr, size_t sz) : BaseType(ptr, sz) { /* ... */ } - constexpr ALWAYS_INLINE OutBufferImpl(void *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } - constexpr ALWAYS_INLINE OutBufferImpl(u8 *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } + ALWAYS_INLINE OutBufferImpl(void *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } + ALWAYS_INLINE OutBufferImpl(u8 *ptr, size_t sz) : BaseType(reinterpret_cast(ptr), sz) { /* ... */ } - constexpr ALWAYS_INLINE u8 *GetPointer() const { + ALWAYS_INLINE u8 *GetPointer() const { return reinterpret_cast(this->GetAddressImpl()); } @@ -134,9 +134,9 @@ namespace ams::tipc { constexpr ALWAYS_INLINE InArrayImpl(const tipc::PointerAndSize &pas) : BaseType(pas) { /* ... */ } constexpr ALWAYS_INLINE InArrayImpl(uintptr_t ptr, size_t sz) : BaseType(ptr, sz) { /* ... */ } - constexpr ALWAYS_INLINE InArrayImpl(const T *ptr, size_t num_elements) : BaseType(reinterpret_cast(ptr), num_elements * sizeof(T)) { /* ... */ } + ALWAYS_INLINE InArrayImpl(const T *ptr, size_t num_elements) : BaseType(reinterpret_cast(ptr), num_elements * sizeof(T)) { /* ... */ } - constexpr ALWAYS_INLINE const T *GetPointer() const { + ALWAYS_INLINE const T *GetPointer() const { return reinterpret_cast(this->GetAddressImpl()); } @@ -144,7 +144,7 @@ namespace ams::tipc { return this->GetSizeImpl(); } - constexpr ALWAYS_INLINE const T &operator[](size_t i) const { + ALWAYS_INLINE const T &operator[](size_t i) const { return this->GetPointer()[i]; } @@ -167,9 +167,9 @@ namespace ams::tipc { constexpr ALWAYS_INLINE OutArrayImpl(const tipc::PointerAndSize &pas) : BaseType(pas) { /* ... */ } constexpr ALWAYS_INLINE OutArrayImpl(uintptr_t ptr, size_t sz) : BaseType(ptr, sz) { /* ... */ } - constexpr ALWAYS_INLINE OutArrayImpl(T *ptr, size_t num_elements) : BaseType(reinterpret_cast(ptr), num_elements * sizeof(T)) { /* ... */ } + ALWAYS_INLINE OutArrayImpl(T *ptr, size_t num_elements) : BaseType(reinterpret_cast(ptr), num_elements * sizeof(T)) { /* ... */ } - constexpr ALWAYS_INLINE T *GetPointer() const { + ALWAYS_INLINE T *GetPointer() const { return reinterpret_cast(this->GetAddressImpl()); } @@ -177,7 +177,7 @@ namespace ams::tipc { return this->GetSizeImpl(); } - constexpr ALWAYS_INLINE T &operator[](size_t i) const { + ALWAYS_INLINE T &operator[](size_t i) const { return this->GetPointer()[i]; } diff --git a/libraries/libstratosphere/include/stratosphere/tipc/tipc_common.hpp b/libraries/libstratosphere/include/stratosphere/tipc/tipc_common.hpp index 8a7b38e71..f62cf6099 100644 --- a/libraries/libstratosphere/include/stratosphere/tipc/tipc_common.hpp +++ b/libraries/libstratosphere/include/stratosphere/tipc/tipc_common.hpp @@ -17,4 +17,5 @@ #include #include #include -#include \ No newline at end of file +#include +#include diff --git a/libraries/libstratosphere/include/stratosphere/tipc/tipc_deferral_manager.hpp b/libraries/libstratosphere/include/stratosphere/tipc/tipc_deferral_manager.hpp index 6e0cc5480..122595fca 100644 --- a/libraries/libstratosphere/include/stratosphere/tipc/tipc_deferral_manager.hpp +++ b/libraries/libstratosphere/include/stratosphere/tipc/tipc_deferral_manager.hpp @@ -15,6 +15,7 @@ */ #pragma once #include +#include #include #include @@ -56,7 +57,7 @@ namespace ams::tipc { ~DeferrableBaseImpl(); - ALWAYS_INLINE void SetDeferralManager(DeferralManagerBase *manager, os::NativeHandle reply_target, ServiceObjectBase *object) { + ALWAYS_INLINE void SetDeferralManager(DeferralManagerBase *manager, tipc::NativeHandle reply_target, ServiceObjectBase *object) { m_deferral_manager = manager; m_object_holder.InitializeForDeferralManager(reply_target, object); } @@ -68,7 +69,7 @@ namespace ams::tipc { template ALWAYS_INLINE void RegisterRetry(ResumeKey key) { m_resume_key = ConvertToInternalResumeKey(key); - std::memcpy(m_message_buffer_base, svc::ipc::GetMessageBuffer(), m_message_buffer_size); + std::memcpy(m_message_buffer_base, tipc::GetMessageBuffer(), m_message_buffer_size); } template @@ -86,7 +87,7 @@ namespace ams::tipc { m_resume_key = 0; /* Restore message buffer. */ - std::memcpy(svc::ipc::GetMessageBuffer(), m_message_buffer_base, m_message_buffer_size); + std::memcpy(tipc::GetMessageBuffer(), m_message_buffer_base, m_message_buffer_size); /* Process the request. */ return port_manager->ProcessDeferredRequest(m_object_holder); @@ -145,12 +146,11 @@ namespace ams::tipc { public: ALWAYS_INLINE DeferralManagerBase() : m_object_count(0) { /* ... */ } - void AddObject(DeferrableBaseImpl &object, os::NativeHandle reply_target, ServiceObjectBase *service_object) { + void AddObject(DeferrableBaseImpl &object, tipc::NativeHandle reply_target, ServiceObjectBase *service_object) { /* Set ourselves as the manager for the object. */ object.SetDeferralManager(this, reply_target, service_object); /* Add the object to our entries. */ - AMS_ASSERT(m_object_count < N); m_objects_base[m_object_count++] = std::addressof(object); } diff --git a/libraries/libstratosphere/include/stratosphere/tipc/tipc_handles.hpp b/libraries/libstratosphere/include/stratosphere/tipc/tipc_handles.hpp index bba680ec5..4929e7610 100644 --- a/libraries/libstratosphere/include/stratosphere/tipc/tipc_handles.hpp +++ b/libraries/libstratosphere/include/stratosphere/tipc/tipc_handles.hpp @@ -34,28 +34,28 @@ namespace ams::tipc { template<> class Out { private: - os::NativeHandle * const m_ptr; + tipc::NativeHandle * const m_ptr; public: - ALWAYS_INLINE Out(os::NativeHandle *p) : m_ptr(p) { /* ... */ } + ALWAYS_INLINE Out(tipc::NativeHandle *p) : m_ptr(p) { /* ... */ } - ALWAYS_INLINE void SetValue(os::NativeHandle v) const { + ALWAYS_INLINE void SetValue(tipc::NativeHandle v) const { *m_ptr = v; } - ALWAYS_INLINE const os::NativeHandle &GetValue() const { + ALWAYS_INLINE const tipc::NativeHandle &GetValue() const { return *m_ptr; } - ALWAYS_INLINE os::NativeHandle *GetPointer() const { + ALWAYS_INLINE tipc::NativeHandle *GetPointer() const { return m_ptr; } /* Convenience operators. */ - ALWAYS_INLINE os::NativeHandle &operator*() const { + ALWAYS_INLINE tipc::NativeHandle &operator*() const { return *m_ptr; } - ALWAYS_INLINE os::NativeHandle *operator->() const { + ALWAYS_INLINE tipc::NativeHandle *operator->() const { return m_ptr; } }; @@ -63,28 +63,28 @@ namespace ams::tipc { template<> class Out { private: - os::NativeHandle * const m_ptr; + tipc::NativeHandle * const m_ptr; public: - ALWAYS_INLINE Out(os::NativeHandle *p) : m_ptr(p) { /* ... */ } + ALWAYS_INLINE Out(tipc::NativeHandle *p) : m_ptr(p) { /* ... */ } - ALWAYS_INLINE void SetValue(os::NativeHandle v) const { + ALWAYS_INLINE void SetValue(tipc::NativeHandle v) const { *m_ptr = v; } - ALWAYS_INLINE const os::NativeHandle &GetValue() const { + ALWAYS_INLINE const tipc::NativeHandle &GetValue() const { return *m_ptr; } - ALWAYS_INLINE os::NativeHandle *GetPointer() const { + ALWAYS_INLINE tipc::NativeHandle *GetPointer() const { return m_ptr; } /* Convenience operators. */ - ALWAYS_INLINE os::NativeHandle &operator*() const { + ALWAYS_INLINE tipc::NativeHandle &operator*() const { return *m_ptr; } - ALWAYS_INLINE os::NativeHandle *operator->() const { + ALWAYS_INLINE tipc::NativeHandle *operator->() const { return m_ptr; } }; diff --git a/libraries/libstratosphere/include/stratosphere/tipc/tipc_message_types.hpp b/libraries/libstratosphere/include/stratosphere/tipc/tipc_message_types.hpp new file mode 100644 index 000000000..e85f76c1b --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/tipc/tipc_message_types.hpp @@ -0,0 +1,128 @@ +/* + * Copyright (c) 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::tipc { + + namespace impl { + + template + class DummyMessageBuffer { + public: + class MessageHeader { + public: + MessageHeader() { AMS_ABORT("TODO"); } + MessageHeader(const DummyMessageBuffer &) { AMS_ABORT("TODO"); } + + u16 GetTag() const { AMS_ABORT("TODO"); } + }; + class SpecialHeader { + public: + SpecialHeader() { AMS_ABORT("TODO"); } + SpecialHeader(const DummyMessageBuffer &, const MessageHeader &) { AMS_ABORT("TODO"); } + + bool GetHasProcessId() const { AMS_ABORT("TODO"); } + s32 GetCopyHandleCount() const { AMS_ABORT("TODO"); } + }; + public: + DummyMessageBuffer(u32 *) { AMS_ABORT("TODO"); } + DummyMessageBuffer(u32 *, size_t) { AMS_ABORT("TODO"); } + + void SetNull() const { AMS_ABORT("TODO"); } + + HandleType GetHandle(s32) const { AMS_ABORT("TODO"); } + + template + const T &GetRaw(s32) const { AMS_ABORT("TODO"); } + + static s32 GetSpecialDataIndex(const MessageHeader &, const SpecialHeader &) { AMS_ABORT("TODO"); } + static s32 GetRawDataIndex(const MessageHeader &, const SpecialHeader &) { AMS_ABORT("TODO"); } + }; + + } + + #if defined(ATMOSPHERE_OS_HORIZON) + + constexpr inline auto MaximumSessionsPerPort = svc::ArgumentHandleCountMax; + + using NativeHandle = svc::Handle; + constexpr inline NativeHandle InvalidNativeHandle = svc::InvalidHandle; + + using MessageBuffer = ::ams::svc::ipc::MessageBuffer; + + ALWAYS_INLINE u32 *GetMessageBuffer() { return svc::ipc::GetMessageBuffer(); } + + constexpr ALWAYS_INLINE u32 EncodeNativeHandleForMessageQueue(NativeHandle h) { return static_cast(h); } + constexpr ALWAYS_INLINE NativeHandle DecodeNativeHandleForMessageQueue(u32 v) { return static_cast(v); } + + #elif defined(ATMOSPHERE_OS_WINDOWS) + + /* TODO */ + constexpr inline auto MaximumSessionsPerPort = 0x40; + + using NativeHandle = void *; + constexpr inline NativeHandle InvalidNativeHandle = nullptr; + + using MessageBuffer = ::ams::tipc::impl::DummyMessageBuffer; + + ALWAYS_INLINE u32 *GetMessageBuffer() { AMS_ABORT("TODO"); } + + ALWAYS_INLINE u32 EncodeNativeHandleForMessageQueue(NativeHandle) { AMS_ABORT("TODO"); } + ALWAYS_INLINE NativeHandle DecodeNativeHandleForMessageQueue(u32) { AMS_ABORT("TODO"); } + + #elif defined(ATMOSPHERE_OS_LINUX) + + /* TODO */ + constexpr inline auto MaximumSessionsPerPort = 0x40; + + using NativeHandle = s32; + constexpr inline NativeHandle InvalidNativeHandle = -1; + + using MessageBuffer = ::ams::tipc::impl::DummyMessageBuffer; + + ALWAYS_INLINE u32 *GetMessageBuffer() { AMS_ABORT("TODO"); } + + ALWAYS_INLINE u32 EncodeNativeHandleForMessageQueue(NativeHandle) { AMS_ABORT("TODO"); } + ALWAYS_INLINE NativeHandle DecodeNativeHandleForMessageQueue(u32) { AMS_ABORT("TODO"); } + + #elif defined(ATMOSPHERE_OS_MACOS) + + /* TODO */ + constexpr inline auto MaximumSessionsPerPort = 0x40; + + using NativeHandle = s32; + constexpr inline NativeHandle InvalidNativeHandle = -1; + + using MessageBuffer = ::ams::tipc::impl::DummyMessageBuffer; + + ALWAYS_INLINE u32 *GetMessageBuffer() { AMS_ABORT("TODO"); } + + ALWAYS_INLINE u32 EncodeNativeHandleForMessageQueue(NativeHandle) { AMS_ABORT("TODO"); } + ALWAYS_INLINE NativeHandle DecodeNativeHandleForMessageQueue(u32) { AMS_ABORT("TODO"); } + + #else + #error "Unknown OS for tipc platform types." + #endif + + namespace impl { + + + + } + +} + diff --git a/libraries/libstratosphere/include/stratosphere/tipc/tipc_object_holder.hpp b/libraries/libstratosphere/include/stratosphere/tipc/tipc_object_holder.hpp index 003376c6b..cf2f40511 100644 --- a/libraries/libstratosphere/include/stratosphere/tipc/tipc_object_holder.hpp +++ b/libraries/libstratosphere/include/stratosphere/tipc/tipc_object_holder.hpp @@ -30,12 +30,12 @@ namespace ams::tipc { ObjectType_Deferral = ObjectType_Invalid, }; private: - os::NativeHandle m_handle; + tipc::NativeHandle m_handle; ObjectType m_type; bool m_managed; tipc::ServiceObjectBase *m_object; private: - void InitializeImpl(ObjectType type, os::NativeHandle handle, bool managed, tipc::ServiceObjectBase *object) { + void InitializeImpl(ObjectType type, tipc::NativeHandle handle, bool managed, tipc::ServiceObjectBase *object) { /* Validate that the object isn't already constructed. */ AMS_ASSERT(m_type == ObjectType_Invalid); @@ -46,20 +46,20 @@ namespace ams::tipc { m_object = object; } public: - constexpr inline ObjectHolder() : m_handle(os::InvalidNativeHandle), m_type(ObjectType_Invalid), m_managed(false), m_object(nullptr) { /* ... */ } + constexpr inline ObjectHolder() : m_handle(tipc::InvalidNativeHandle), m_type(ObjectType_Invalid), m_managed(false), m_object(nullptr) { /* ... */ } - void InitializeAsPort(os::NativeHandle handle) { + void InitializeAsPort(tipc::NativeHandle handle) { /* NOTE: Nintendo sets ports as managed, but this will cause a nullptr-deref if one is ever closed. */ /* This is theoretically a non-issue, as ports can't be closed, but we will set ours as unmanaged, */ /* just in case. */ this->InitializeImpl(ObjectType_Port, handle, false, nullptr); } - void InitializeAsSession(os::NativeHandle handle, bool managed, tipc::ServiceObjectBase *object) { + void InitializeAsSession(tipc::NativeHandle handle, bool managed, tipc::ServiceObjectBase *object) { this->InitializeImpl(ObjectType_Session, handle, managed, object); } - void InitializeForDeferralManager(os::NativeHandle handle, tipc::ServiceObjectBase *object) { + void InitializeForDeferralManager(tipc::NativeHandle handle, tipc::ServiceObjectBase *object) { this->InitializeImpl(ObjectType_Deferral, handle, false, object); } @@ -75,13 +75,13 @@ namespace ams::tipc { } /* Reset all fields. */ - m_handle = os::InvalidNativeHandle; + m_handle = tipc::InvalidNativeHandle; m_type = ObjectType_Invalid; m_managed = false; m_object = nullptr; } - constexpr os::NativeHandle GetHandle() const { + constexpr tipc::NativeHandle GetHandle() const { return m_handle; } diff --git a/libraries/libstratosphere/include/stratosphere/tipc/tipc_object_manager.hpp b/libraries/libstratosphere/include/stratosphere/tipc/tipc_object_manager.hpp index 7c1e575ce..eecd375af 100644 --- a/libraries/libstratosphere/include/stratosphere/tipc/tipc_object_manager.hpp +++ b/libraries/libstratosphere/include/stratosphere/tipc/tipc_object_manager.hpp @@ -16,6 +16,7 @@ #pragma once #include #include +#include #include #include @@ -37,7 +38,7 @@ namespace ams::tipc { Entry *m_entries_end{}; os::MultiWaitType *m_multi_wait{}; private: - Entry *FindEntry(os::NativeHandle handle) { + Entry *FindEntry(tipc::NativeHandle handle) { for (Entry *cur = m_entries_start; cur != m_entries_end; ++cur) { if (GetReference(cur->object).GetHandle() == handle) { return cur; @@ -76,7 +77,7 @@ namespace ams::tipc { std::scoped_lock lk(m_mutex); /* Find an empty entry. */ - auto *entry = this->FindEntry(os::InvalidNativeHandle); + auto *entry = this->FindEntry(tipc::InvalidNativeHandle); AMS_ABORT_UNLESS(entry != nullptr); /* Set the entry's object. */ @@ -87,7 +88,7 @@ namespace ams::tipc { os::LinkMultiWaitHolder(m_multi_wait, std::addressof(entry->multi_wait_holder)); } - void CloseObject(os::NativeHandle handle) { + void CloseObject(tipc::NativeHandle handle) { /* Lock ourselves. */ std::scoped_lock lk(m_mutex); @@ -103,14 +104,14 @@ namespace ams::tipc { GetReference(entry->object).Destroy(); } - Result ReplyAndReceive(os::MultiWaitHolderType **out_holder, ObjectHolder *out_object, os::NativeHandle reply_target, os::MultiWaitType *multi_wait) { + Result ReplyAndReceive(os::MultiWaitHolderType **out_holder, ObjectHolder *out_object, tipc::NativeHandle reply_target, os::MultiWaitType *multi_wait) { /* Declare signaled holder for processing ahead of time. */ os::MultiWaitHolderType *signaled_holder; /* Reply and receive until we get a newly signaled target. */ Result result = os::SdkReplyAndReceive(out_holder, reply_target, multi_wait); for (signaled_holder = *out_holder; signaled_holder == nullptr; signaled_holder = *out_holder) { - result = os::SdkReplyAndReceive(out_holder, os::InvalidNativeHandle, multi_wait); + result = os::SdkReplyAndReceive(out_holder, tipc::InvalidNativeHandle, multi_wait); } /* Find the entry matching the signaled holder. */ @@ -125,32 +126,23 @@ namespace ams::tipc { } } - void Reply(os::NativeHandle reply_target) { - /* Perform the reply. */ - s32 dummy; - R_TRY_CATCH(svc::ReplyAndReceive(std::addressof(dummy), nullptr, 0, reply_target, 0)) { - R_CATCH(svc::ResultTimedOut) { - /* Timing out is acceptable. */ - } - R_CATCH(svc::ResultSessionClosed) { - /* It's okay if we couldn't reply to a closed session. */ - } - } R_END_TRY_CATCH_WITH_ABORT_UNLESS; + void Reply(tipc::NativeHandle reply_target) { + return tipc::impl::Reply(reply_target); } Result ProcessRequest(ObjectHolder &object) { /* Get the message buffer. */ - const svc::ipc::MessageBuffer message_buffer(svc::ipc::GetMessageBuffer()); + const MessageBuffer message_buffer(tipc::GetMessageBuffer()); /* Get the method id. */ - const auto method_id = svc::ipc::MessageBuffer::MessageHeader(message_buffer).GetTag(); + const auto method_id = MessageBuffer::MessageHeader(message_buffer).GetTag(); /* Process for the method id. */ { /* Ensure that if we fail, we clean up any handles that get sent our way. */ ON_RESULT_FAILURE { - const svc::ipc::MessageBuffer::MessageHeader message_header(message_buffer); - const svc::ipc::MessageBuffer::SpecialHeader special_header(message_buffer, message_header); + const MessageBuffer::MessageHeader message_header(message_buffer); + const MessageBuffer::SpecialHeader special_header(message_buffer, message_header); /* Determine the offset to the start of handles. */ auto offset = message_buffer.GetSpecialDataIndex(message_header, special_header); @@ -160,8 +152,8 @@ namespace ams::tipc { /* Close all copy handles. */ for (auto i = 0; i < special_header.GetCopyHandleCount(); ++i) { - svc::CloseHandle(message_buffer.GetHandle(offset)); - offset += sizeof(ams::svc::Handle) / sizeof(u32); + tipc::impl::CloseHandle(message_buffer.GetHandle(offset)); + offset += sizeof(typename std::remove_reference::type) / sizeof(u32); } }; @@ -191,7 +183,7 @@ namespace ams::tipc { /* Close the object's handle. */ /* NOTE: Nintendo does not check that this succeeds. */ - R_ABORT_UNLESS(svc::CloseHandle(handle)); + R_ABORT_UNLESS(tipc::impl::CloseHandle(handle)); /* Return an error to signify we closed the object. */ R_THROW(tipc::ResultSessionClosed()); diff --git a/libraries/libstratosphere/include/stratosphere/tipc/tipc_pointer_and_size.hpp b/libraries/libstratosphere/include/stratosphere/tipc/tipc_pointer_and_size.hpp index 23e206876..d61369083 100644 --- a/libraries/libstratosphere/include/stratosphere/tipc/tipc_pointer_and_size.hpp +++ b/libraries/libstratosphere/include/stratosphere/tipc/tipc_pointer_and_size.hpp @@ -25,9 +25,9 @@ namespace ams::tipc { public: constexpr PointerAndSize() : m_pointer(0), m_size(0) { /* ... */ } constexpr PointerAndSize(uintptr_t ptr, size_t sz) : m_pointer(ptr), m_size(sz) { /* ... */ } - constexpr PointerAndSize(void *ptr, size_t sz) : PointerAndSize(reinterpret_cast(ptr), sz) { /* ... */ } + PointerAndSize(void *ptr, size_t sz) : PointerAndSize(reinterpret_cast(ptr), sz) { /* ... */ } - constexpr ALWAYS_INLINE void *GetPointer() const { + ALWAYS_INLINE void *GetPointer() const { return reinterpret_cast(m_pointer); } diff --git a/libraries/libstratosphere/include/stratosphere/tipc/tipc_server_manager.hpp b/libraries/libstratosphere/include/stratosphere/tipc/tipc_server_manager.hpp index 18deb2e66..7566b6a40 100644 --- a/libraries/libstratosphere/include/stratosphere/tipc/tipc_server_manager.hpp +++ b/libraries/libstratosphere/include/stratosphere/tipc/tipc_server_manager.hpp @@ -50,16 +50,16 @@ namespace ams::tipc { static_assert(NumPorts > 0); /* Verify that it's possible to service this many sessions, with our port manager count. */ - static_assert(MaxSessions <= NumPorts * svc::ArgumentHandleCountMax); + static_assert(MaxSessions <= NumPorts * MaximumSessionsPerPort); static_assert(util::IsAligned(ThreadStackSize, os::ThreadStackAlignment)); alignas(os::ThreadStackAlignment) static constinit inline u8 s_port_stacks[ThreadStackSize * (NumPorts - 1)]; - template requires (Ix < NumPorts) + template AMS_CONCEPTS_REQUIRES_IF_SUPPORTED(Ix < NumPorts) static constexpr inline size_t SessionsPerPortManager = (Ix == NumPorts - 1) ? ((MaxSessions / NumPorts) + MaxSessions % NumPorts) : ((MaxSessions / NumPorts)); - template requires (Ix < NumPorts) + template AMS_CONCEPTS_REQUIRES_IF_SUPPORTED(Ix < NumPorts) using PortInfo = typename std::tuple_element>::type; static_assert(IsDeferralSupported == (PortInfos::CanDeferInvokeRequest || ...)); @@ -69,7 +69,7 @@ namespace ams::tipc { using DeferralManagerBaseType = typename std::conditional::type; - template requires (Ix < NumPorts) + template AMS_CONCEPTS_REQUIRES_IF_SUPPORTED(Ix < NumPorts) static constexpr inline bool IsPortDeferrable = PortInfo::CanDeferInvokeRequest; public: class PortManagerBase { @@ -125,7 +125,7 @@ namespace ams::tipc { m_deferral_manager = dm; } - void RegisterPort(s32 index, os::NativeHandle port_handle) { + void RegisterPort(s32 index, tipc::NativeHandle port_handle) { /* Set our port number. */ m_port_number = index; @@ -139,7 +139,7 @@ namespace ams::tipc { m_object_manager->AddObject(object); } - os::NativeHandle ProcessRequest(ObjectHolder &object) { + tipc::NativeHandle ProcessRequest(ObjectHolder &object) { /* Acquire exclusive server manager access. */ std::scoped_lock lk(m_server_manager->GetMutex()); @@ -147,13 +147,13 @@ namespace ams::tipc { const Result result = m_object_manager->ProcessRequest(object); if (R_SUCCEEDED(result)) { /* We should reply only if the request isn't deferred. */ - return !IsRequestDeferred() ? object.GetHandle() : os::InvalidNativeHandle; + return !IsRequestDeferred() ? object.GetHandle() : tipc::InvalidNativeHandle; } else { /* Processing failed, so note the session as closed (or close it). */ this->CloseSessionIfNecessary(object, !tipc::ResultSessionClosed::Includes(result)); /* We shouldn't reply on failure. */ - return os::InvalidNativeHandle; + return tipc::InvalidNativeHandle; } } @@ -161,15 +161,15 @@ namespace ams::tipc { void ProcessDeferredRequest(ObjectHolder &object) { static_assert(Enable == IsDeferralSupported); - if (const auto reply_target = this->ProcessRequest(object); reply_target != os::InvalidNativeHandle) { + if (const auto reply_target = this->ProcessRequest(object); reply_target != tipc::InvalidNativeHandle) { m_object_manager->Reply(reply_target); } } - bool ReplyAndReceive(os::MultiWaitHolderType **out_holder, ObjectHolder *out_object, os::NativeHandle reply_target) { + bool ReplyAndReceive(os::MultiWaitHolderType **out_holder, ObjectHolder *out_object, tipc::NativeHandle reply_target) { /* If we don't have a reply target, clear our message buffer. */ - if (reply_target == os::InvalidNativeHandle) { - svc::ipc::MessageBuffer(svc::ipc::GetMessageBuffer()).SetNull(); + if (reply_target == tipc::InvalidNativeHandle) { + tipc::MessageBuffer(tipc::GetMessageBuffer()).SetNull(); } /* Try to reply/receive. */ @@ -192,7 +192,7 @@ namespace ams::tipc { return true; } - void AddSession(os::NativeHandle session_handle, tipc::ServiceObjectBase *service_object) { + void AddSession(tipc::NativeHandle session_handle, tipc::ServiceObjectBase *service_object) { /* Create an object holder for the session. */ tipc::ObjectHolder object; @@ -215,7 +215,7 @@ namespace ams::tipc { case MessageType_AddSession: { /* Get the handle from where it's packed into the message type. */ - const os::NativeHandle session_handle = static_cast(message_type >> BITSIZEOF(u32)); + const tipc::NativeHandle session_handle = tipc::DecodeNativeHandleForMessageQueue(message_type >> BITSIZEOF(u32)); /* Allocate a service object for the port. */ auto *service_object = m_server_manager->AllocateObject(static_cast(message_data), session_handle, *m_deferral_manager); @@ -243,7 +243,7 @@ namespace ams::tipc { m_object_manager->CloseObject(handle); /* Close the handle itself. */ - R_ABORT_UNLESS(svc::CloseHandle(handle)); + R_ABORT_UNLESS(tipc::impl::CloseHandle(handle)); /* Decrement our session count. */ --m_num_sessions; @@ -258,7 +258,7 @@ namespace ams::tipc { m_object_manager->CloseObject(handle); /* Close the handle itself. */ - R_ABORT_UNLESS(svc::CloseHandle(handle)); + R_ABORT_UNLESS(tipc::impl::CloseHandle(handle)); } /* Decrement our session count. */ @@ -286,12 +286,12 @@ namespace ams::tipc { os::SendMessageQueue(std::addressof(m_message_queue), key); } - void TriggerAddSession(os::NativeHandle session_handle, size_t port_index) { + void TriggerAddSession(tipc::NativeHandle session_handle, size_t port_index) { /* Increment our session count. */ ++m_num_sessions; /* Send information about the session as a message. */ - os::SendMessageQueue(std::addressof(m_message_queue), static_cast(MessageType_AddSession) | (static_cast(session_handle) << BITSIZEOF(u32))); + os::SendMessageQueue(std::addressof(m_message_queue), static_cast(MessageType_AddSession) | (static_cast(tipc::EncodeNativeHandleForMessageQueue(session_handle)) << BITSIZEOF(u32))); os::SendMessageQueue(std::addressof(m_message_queue), static_cast(port_index)); } private: @@ -306,11 +306,11 @@ namespace ams::tipc { static bool IsRequestDeferred() { if constexpr (IsDeferralSupported) { /* Get the message buffer. */ - const svc::ipc::MessageBuffer message_buffer(svc::ipc::GetMessageBuffer()); + const tipc::MessageBuffer message_buffer(tipc::GetMessageBuffer()); /* Parse the hipc headers. */ - const svc::ipc::MessageBuffer::MessageHeader message_header(message_buffer); - const svc::ipc::MessageBuffer::SpecialHeader special_header(message_buffer, message_header); + const tipc::MessageBuffer::MessageHeader message_header(message_buffer); + const tipc::MessageBuffer::SpecialHeader special_header(message_buffer, message_header); /* Determine raw data index. */ const auto raw_data_offset = message_buffer.GetRawDataIndex(message_header, special_header); @@ -406,14 +406,14 @@ namespace ams::tipc { } template - void RegisterPort(os::NativeHandle port_handle) { + void RegisterPort(tipc::NativeHandle port_handle) { this->GetPortManager().RegisterPort(static_cast(Ix), port_handle); } template void RegisterPort(sm::ServiceName service_name, size_t max_sessions) { /* Register service. */ - os::NativeHandle port_handle; + tipc::NativeHandle port_handle; R_ABORT_UNLESS(sm::RegisterService(std::addressof(port_handle), service_name, max_sessions, false)); /* Register the port handle. */ @@ -454,7 +454,7 @@ namespace ams::tipc { this->LoopAutoForPort(); } - tipc::ServiceObjectBase *AllocateObject(size_t port_index, os::NativeHandle handle, DeferralManagerBaseType &deferral_manager) { + tipc::ServiceObjectBase *AllocateObject(size_t port_index, tipc::NativeHandle handle, DeferralManagerBaseType &deferral_manager) { /* Check that the port index is valid. */ AMS_ABORT_UNLESS(port_index < NumPorts); @@ -483,13 +483,13 @@ namespace ams::tipc { }(std::make_index_sequence()); } - Result AddSession(os::NativeHandle *out, tipc::ServiceObjectBase *object) { + Result AddSession(tipc::NativeHandle *out, tipc::ServiceObjectBase *object) { /* Acquire exclusive access to ourselves. */ std::scoped_lock lk(m_mutex); /* Create a handle for the session. */ - svc::Handle session_handle; - R_TRY(svc::CreateSession(std::addressof(session_handle), static_cast(out), false, 0)); + tipc::NativeHandle session_handle; + R_TRY(tipc::impl::CreateSession(std::addressof(session_handle), static_cast(out), false, 0)); /* Select the best port manager. */ PortManagerBase *best_manager = nullptr; @@ -505,7 +505,7 @@ namespace ams::tipc { } private: template requires (Ix < NumPorts) - void TryAllocateObject(size_t port_index, os::NativeHandle handle, DeferralManagerBaseType &deferral_manager, tipc::ServiceObjectBase *&allocated) { + void TryAllocateObject(size_t port_index, tipc::NativeHandle handle, DeferralManagerBaseType &deferral_manager, tipc::ServiceObjectBase *&allocated) { /* Check that the port index matches. */ if (port_index == Ix) { /* Check that we haven't already allocated. */ @@ -535,13 +535,13 @@ namespace ams::tipc { Result LoopProcess(PortManagerBase &port_manager) { /* Process requests forever. */ - os::NativeHandle reply_target = os::InvalidNativeHandle; + tipc::NativeHandle reply_target = tipc::InvalidNativeHandle; while (true) { /* Reply to our pending request, and wait to receive a new one. */ os::MultiWaitHolderType *signaled_holder = nullptr; tipc::ObjectHolder signaled_object{}; while (!port_manager.ReplyAndReceive(std::addressof(signaled_holder), std::addressof(signaled_object), reply_target)) { - reply_target = os::InvalidNativeHandle; + reply_target = tipc::InvalidNativeHandle; signaled_object = {}; } @@ -551,13 +551,13 @@ namespace ams::tipc { case ObjectHolder::ObjectType_Port: { /* Try to accept a new session */ - svc::Handle session_handle; - if (R_SUCCEEDED(svc::AcceptSession(std::addressof(session_handle), signaled_object.GetHandle()))) { + tipc::NativeHandle session_handle; + if (R_SUCCEEDED(tipc::impl::AcceptSession(std::addressof(session_handle), signaled_object.GetHandle()))) { this->TriggerAddSession(session_handle, static_cast(port_manager.GetPortIndex())); } /* We have nothing to reply to. */ - reply_target = os::InvalidNativeHandle; + reply_target = tipc::InvalidNativeHandle; } break; case ObjectHolder::ObjectType_Session: @@ -573,12 +573,12 @@ namespace ams::tipc { port_manager.ProcessMessages(); /* We have nothing to reply to. */ - reply_target = os::InvalidNativeHandle; + reply_target = tipc::InvalidNativeHandle; } } } - void TriggerAddSession(os::NativeHandle session_handle, size_t port_index) { + void TriggerAddSession(tipc::NativeHandle session_handle, size_t port_index) { /* Acquire exclusive access to ourselves. */ std::scoped_lock lk(m_mutex); @@ -634,7 +634,7 @@ namespace ams::tipc { static constexpr inline size_t MaxSessions = PortInfo::MaxSessions; /* Verify that it's possible to service this many sessions, with our port manager count. */ - static_assert(MaxSessions <= svc::ArgumentHandleCountMax); + static_assert(MaxSessions <= MaximumSessionsPerPort); public: class PortManagerBase { protected: @@ -651,7 +651,7 @@ namespace ams::tipc { m_object_manager = om; } - void RegisterPort(os::NativeHandle port_handle) { + void RegisterPort(tipc::NativeHandle port_handle) { /* Create an object holder for the port. */ tipc::ObjectHolder object; @@ -662,7 +662,7 @@ namespace ams::tipc { m_object_manager->AddObject(object); } - os::NativeHandle ProcessRequest(ObjectHolder &object) { + tipc::NativeHandle ProcessRequest(ObjectHolder &object) { /* Process the request. */ const Result result = m_object_manager->ProcessRequest(object); if (R_SUCCEEDED(result)) { @@ -675,14 +675,14 @@ namespace ams::tipc { } /* We shouldn't reply on failure. */ - return os::InvalidNativeHandle; + return tipc::InvalidNativeHandle; } } - bool ReplyAndReceive(ObjectHolder *out_object, os::NativeHandle reply_target) { + bool ReplyAndReceive(ObjectHolder *out_object, tipc::NativeHandle reply_target) { /* If we don't have a reply target, clear our message buffer. */ - if (reply_target == os::InvalidNativeHandle) { - svc::ipc::MessageBuffer(svc::ipc::GetMessageBuffer()).SetNull(); + if (reply_target == tipc::InvalidNativeHandle) { + tipc::MessageBuffer(tipc::GetMessageBuffer()).SetNull(); } /* Try to reply/receive. */ @@ -704,7 +704,7 @@ namespace ams::tipc { return true; } - void AddSession(os::NativeHandle session_handle, tipc::ServiceObjectBase *service_object) { + void AddSession(tipc::NativeHandle session_handle, tipc::ServiceObjectBase *service_object) { /* Create an object holder for the session. */ tipc::ObjectHolder object; @@ -723,7 +723,7 @@ namespace ams::tipc { m_object_manager->CloseObject(handle); /* Close the handle itself. */ - R_ABORT_UNLESS(svc::CloseHandle(handle)); + R_ABORT_UNLESS(tipc::impl::CloseHandle(handle)); } }; @@ -756,13 +756,13 @@ namespace ams::tipc { m_port_manager.Initialize(); } - void RegisterPort(os::NativeHandle port_handle) { + void RegisterPort(tipc::NativeHandle port_handle) { m_port_manager.RegisterPort(port_handle); } void RegisterPort(sm::ServiceName service_name, size_t max_sessions) { /* Register service. */ - os::NativeHandle port_handle; + tipc::NativeHandle port_handle; R_ABORT_UNLESS(sm::RegisterService(std::addressof(port_handle), service_name, max_sessions, false)); /* Register the port handle. */ @@ -787,10 +787,10 @@ namespace ams::tipc { return new_object; } - Result AddSession(os::NativeHandle *out, tipc::ServiceObjectBase *object) { + Result AddSession(tipc::NativeHandle *out, tipc::ServiceObjectBase *object) { /* Create a handle for the session. */ - svc::Handle session_handle; - R_TRY(svc::CreateSession(std::addressof(session_handle), static_cast(out), false, 0)); + tipc::NativeHandle session_handle; + R_TRY(tipc::impl::CreateSession(std::addressof(session_handle), static_cast(out), false, 0)); /* Add the session to our manager. */ m_port_manager.AddSession(session_handle, object); @@ -800,12 +800,12 @@ namespace ams::tipc { private: void LoopProcess(PortManagerBase &port_manager) { /* Process requests forever. */ - os::NativeHandle reply_target = os::InvalidNativeHandle; + tipc::NativeHandle reply_target = tipc::InvalidNativeHandle; while (true) { /* Reply to our pending request, and wait to receive a new one. */ tipc::ObjectHolder signaled_object{}; while (!port_manager.ReplyAndReceive(std::addressof(signaled_object), reply_target)) { - reply_target = os::InvalidNativeHandle; + reply_target = tipc::InvalidNativeHandle; } /* A session was signaled, accessible via signaled_object. */ @@ -813,13 +813,13 @@ namespace ams::tipc { case ObjectHolder::ObjectType_Port: { /* Try to accept a new session */ - svc::Handle session_handle; - if (R_SUCCEEDED(svc::AcceptSession(std::addressof(session_handle), signaled_object.GetHandle()))) { + tipc::NativeHandle session_handle; + if (R_SUCCEEDED(tipc::impl::AcceptSession(std::addressof(session_handle), signaled_object.GetHandle()))) { port_manager.AddSession(session_handle, this->AllocateObject()); } /* We have nothing to reply to. */ - reply_target = os::InvalidNativeHandle; + reply_target = tipc::InvalidNativeHandle; } break; case ObjectHolder::ObjectType_Session: diff --git a/libraries/libstratosphere/include/stratosphere/tipc/tipc_service_object.hpp b/libraries/libstratosphere/include/stratosphere/tipc/tipc_service_object.hpp index 7b293bc30..0f65da533 100644 --- a/libraries/libstratosphere/include/stratosphere/tipc/tipc_service_object.hpp +++ b/libraries/libstratosphere/include/stratosphere/tipc/tipc_service_object.hpp @@ -30,7 +30,7 @@ namespace ams::tipc { template class EmplacedImplHolder { - template + template friend class impl::ImplTemplateBaseT; private: using Impl2 = typename EmplacedImplHolderBaseGetter::Type; diff --git a/libraries/libstratosphere/include/stratosphere/tipc/tipc_service_object_base.hpp b/libraries/libstratosphere/include/stratosphere/tipc/tipc_service_object_base.hpp index b579f1fca..edae67bd4 100644 --- a/libraries/libstratosphere/include/stratosphere/tipc/tipc_service_object_base.hpp +++ b/libraries/libstratosphere/include/stratosphere/tipc/tipc_service_object_base.hpp @@ -15,6 +15,7 @@ */ #pragma once #include +#include namespace ams::tipc { diff --git a/libraries/libstratosphere/include/stratosphere/wec/wec_types.hpp b/libraries/libstratosphere/include/stratosphere/wec/wec_types.hpp index 41b5c5245..39d915dea 100644 --- a/libraries/libstratosphere/include/stratosphere/wec/wec_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/wec/wec_types.hpp @@ -17,13 +17,9 @@ #include #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) - #include - #else - - #error "Unknown board for ams::wec::WakeEvent" - + #include #endif namespace ams::wec { diff --git a/libraries/libstratosphere/include/stratosphere/wec/wec_wake_event.generic.hpp b/libraries/libstratosphere/include/stratosphere/wec/wec_wake_event.generic.hpp new file mode 100644 index 000000000..13bae8a53 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/wec/wec_wake_event.generic.hpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 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::wec { + + enum WakeEvent { + WakeEvent_Debug = 0, + + WakeEvent_Count = 1, + }; + + constexpr inline WakeEvent WakeEvent_None = static_cast(-1); + +} diff --git a/libraries/libstratosphere/include/stratosphere/windows.hpp b/libraries/libstratosphere/include/stratosphere/windows.hpp new file mode 100644 index 000000000..3bba751c9 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/windows.hpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 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 + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif + +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#include + +/* Collides with StandardUserSystemClock. */ +#ifdef GetCurrentTime + +ALWAYS_INLINE auto WindowsGetCurrentTime() { + return GetCurrentTime(); +} + +#undef GetCurrentTime + +#endif + +/* Collides with several things. */ +#ifdef FillMemory + +ALWAYS_INLINE auto WindowsFillMemory(PVOID p, SIZE_T l, BYTE v) { + return FillMemory(p, l, v); +} + +#undef FillMemory + +/* Should be provided by winerror.h, but isn't. */ +#if !defined(ERROR_SPACES_NOT_ENOUGH_DRIVES) +#define ERROR_SPACES_NOT_ENOUGH_DRIVES ((DWORD)0x80E7000Bu) +#endif + +#endif diff --git a/libraries/libexosphere/arm64.mk b/libraries/libstratosphere/libstratosphere.mk similarity index 58% rename from libraries/libexosphere/arm64.mk rename to libraries/libstratosphere/libstratosphere.mk index 78e2cc540..e741ef1f6 100644 --- a/libraries/libexosphere/arm64.mk +++ b/libraries/libstratosphere/libstratosphere.mk @@ -1,38 +1,69 @@ -#--------------------------------------------------------------------------------- -# Define the atmosphere board and cpu -#--------------------------------------------------------------------------------- -export ATMOSPHERE_BOARD := nx-hac-001 -export ATMOSPHERE_CPU := arm-cortex-a57 - #--------------------------------------------------------------------------------- # pull in common atmosphere configuration #--------------------------------------------------------------------------------- THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) -include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../config/common.mk +include $(CURRENT_DIRECTORY)/../config/common.mk + +ifeq ($(ATMOSPHERE_BOARD),nx-hac-001) + +#--------------------------------------------------------------------------------- +# pull in switch rules +#--------------------------------------------------------------------------------- +ifeq ($(strip $(DEVKITPRO)),) +$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=/devkitpro") +endif + +include $(DEVKITPRO)/libnx/switch_rules + +endif #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- +ifeq ($(strip $(ATMOSPHERE_COMPILER_NAME)),gcc) +PRECOMPILED_HEADERS := include/stratosphere.hpp +else +PRECOMPILED_HEADERS := +endif -DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_EXOSPHERE -SETTINGS := $(ATMOSPHERE_SETTINGS) -mgeneral-regs-only -ffixed-x18 -Os -Wextra -Werror -fno-non-call-exceptions \ - -Wno-array-bounds \ - -Wno-stringop-overflow \ - -Wno-stringop-overread +ifeq ($(ATMOSPHERE_BUILD_FOR_DEBUGGING),1) +ATMOSPHERE_OPTIMIZATION_FLAG := -Os +else +ATMOSPHERE_OPTIMIZATION_FLAG := -O2 +endif + +DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_STRATOSPHERE -D_GNU_SOURCE +SETTINGS := $(ATMOSPHERE_SETTINGS) $(ATMOSPHERE_OPTIMIZATION_FLAG) -Wextra -Werror -Wno-missing-field-initializers -flto CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE) -CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit -ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE) +CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) +ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) $(DEFINES) + +ifeq ($(ATMOSPHERE_BOARD),nx-hac-001) +LDFLAGS := -specs=$(DEVKITPRO)/libnx/switch.specs $(SETTINGS) -Wl,-Map,$(notdir $*.map) +else +LDFLAGS := -Wl,-Map,$(notdir $*.map) +endif + SOURCES += $(call ALL_SOURCE_DIRS,../libvapours/source) +SOURCES += $(call UNFILTERED_SOURCE_DIRS,source/os) +ifeq ($(ATMOSPHERE_BOARD),nx-hac-001) +LIBS := -lnx +else LIBS := +endif #--------------------------------------------------------------------------------- # list of directories containing libraries, this must be the top level containing # include and lib #--------------------------------------------------------------------------------- -LIBDIRS := $(ATMOSPHERE_LIBRARIES_DIR)/libvapours +ifeq ($(ATMOSPHERE_BOARD),nx-hac-001) +LIBDIRS := $(PORTLIBS) $(LIBNX) $(ATMOSPHERE_LIBDIRS) $(ATMOSPHERE_LIBRARIES_DIR)/libvapours +else +LIBDIRS := $(ATMOSPHERE_LIBDIRS) $(ATMOSPHERE_LIBRARIES_DIR)/libvapours +endif #--------------------------------------------------------------------------------- # no real need to edit anything past this point unless you need to add additional @@ -74,69 +105,28 @@ export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ #--------------------------------------------------------------------------------- -ATMOSPHERE_BUILD_CONFIGS := -all: release - -define ATMOSPHERE_ADD_TARGET - -ATMOSPHERE_BUILD_CONFIGS += $(strip $1) - -$(strip $1): $$(ATMOSPHERE_LIBRARY_DIR)/$(strip $2) - -$$(ATMOSPHERE_LIBRARY_DIR)/$(strip $2) : $$(ATMOSPHERE_LIBRARY_DIR) $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) $$(SOURCES) $$(INCLUDES) $$(GCH_DIRS) - @$$(MAKE) __RECURSIVE__=1 OUTPUT=$$(CURDIR)/$$@ $(3) \ - ATMOSPHERE_GCH_IDENTIFIER="$$(ATMOSPHERE_BOARD_NAME)_$$(ATMOSPHERE_ARCH_NAME)_$(strip $1)" \ - DEPSDIR=$$(CURDIR)/$$(ATMOSPHERE_BUILD_DIR)/$(strip $1) \ - --no-print-directory -C $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) \ - -f $$(THIS_MAKEFILE) - -clean-$(strip $1): - @echo clean $(strip $1) ... - @rm -fr $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) $$(ATMOSPHERE_LIBRARY_DIR)/$(strip $2) - @rm -fr $$(foreach hdr,$$(GCH_DIRS),$$(hdr)/$$(ATMOSPHERE_BOARD_NAME)_$$(ATMOSPHERE_ARCH_NAME)_$(strip $1)) - @for i in $$(GCH_DIRS) $$(ATMOSPHERE_BUILD_DIR) $$(ATMOSPHERE_LIBRARY_DIR); do [ -d $$$$i ] && rmdir --ignore-fail-on-non-empty $$$$i || true; done - -.PHONY: $(strip $1) clean-$(strip $1) $$(ATMOSPHERE_LIBRARY_DIR)/$(strip $2) - -endef - -$(eval $(call ATMOSPHERE_ADD_TARGET, release, $(TARGET).a, \ - ATMOSPHERE_BUILD_SETTINGS="-DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS " \ -)) - -$(eval $(call ATMOSPHERE_ADD_TARGET, debug, $(TARGET)_debug.a, \ - ATMOSPHERE_BUILD_SETTINGS="-DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS -DAMS_BUILD_FOR_DEBUGGING" \ -)) - -$(eval $(call ATMOSPHERE_ADD_TARGET, audit, $(TARGET)_audit.a, \ - ATMOSPHERE_BUILD_SETTINGS="-DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS -DAMS_BUILD_FOR_AUDITING" \ -)) - -#--------------------------------------------------------------------------------- - --include $(ATMOSPHERE_BOARD_NAME)_$(ATMOSPHERE_ARCH_NAME).mk - -ALL_GCH_IDENTIFIERS := $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),$(ATMOSPHERE_BOARD_NAME)_$(ATMOSPHERE_ARCH_NAME)_$(config)) -ALL_GCH_FILES := $(foreach hdr,$(PRECOMPILED_HEADERS:.hpp=.hpp.gch),$(foreach id,$(ALL_GCH_IDENTIFIERS),$(hdr)/$(id))) - .PHONY: clean all -$(ATMOSPHERE_LIBRARY_DIR) $(GCH_DIRS): - @[ -d $@ ] || mkdir -p $@ - -$(ATMOSPHERE_BUILD_DIR)/%: - @[ -d $@ ] || mkdir -p $@ +all: $(ATMOSPHERE_LIBRARY_DIR) $(ATMOSPHERE_BUILD_DIR) $(SOURCES) $(INCLUDES) $(GCH_DIRS) $(CPPFILES) $(CFILES) $(SFILES) + @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURDIR)/$(ATMOSPHERE_LIBRARY_DIR)/$(TARGET).a \ + DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ + --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ + -f $(THIS_MAKEFILE) #--------------------------------------------------------------------------------- clean: - @echo clean ... - @rm -fr $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARY_DIR) *.bz2 $(ALL_GCH_FILES) + @echo clean $(ATMOSPHERE_BUILD_NAME) ... + @rm -fr $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_OUT_DIR) + @rm -fr $(foreach hdr,$(GCH_DIRS),$(hdr)/$(ATMOSPHERE_GCH_IDENTIFIER)) @for i in $(GCH_DIRS); do [ -d $$i ] && rmdir --ignore-fail-on-non-empty $$i || true; done +$(ATMOSPHERE_LIBRARY_DIR) $(ATMOSPHERE_BUILD_DIR) $(GCH_DIRS): + @[ -d $@ ] || mkdir -p $@ + #--------------------------------------------------------------------------------- else -GCH_FILES := $(foreach hdr,$(PRECOMPILED_HEADERS:.hpp=.hpp.gch),$(CURRENT_DIRECTORY)/$(hdr)/$(ATMOSPHERE_GCH_IDENTIFIER)) +GCH_FILES := $(foreach hdr,$(PRECOMPILED_HEADERS:.hpp=.hpp.gch),$(CURRENT_DIRECTORY)/$(hdr)/$(ATMOSPHERE_GCH_IDENTIFIER)) DEPENDS := $(OFILES:.o=.d) $(foreach hdr,$(GCH_FILES),$(notdir $(patsubst %.hpp.gch/,%.d,$(dir $(hdr))))) #--------------------------------------------------------------------------------- @@ -148,7 +138,13 @@ $(OFILES) : $(GCH_FILES) $(OFILES_SRC) : $(HFILES_BIN) -libc.o: CFLAGS += -fno-builtin -fno-lto +ams_environment_weak.os.horizon.o: CXXFLAGS += -fno-lto +hos_version_api_weak_for_unit_test.o: CXXFLAGS += -fno-lto +pm_info_api_weak.o: CXXFLAGS += -fno-lto +hos_stratosphere_api.o: CXXFLAGS += -fno-lto + +init_operator_new.o: CXXFLAGS += -fno-lto +init_libnx_shim.os.horizon.o: CXXFLAGS += -fno-lto #--------------------------------------------------------------------------------- %_bin.h %.bin.o : %.bin diff --git a/libraries/libstratosphere/source/ams/ams_bpc.c b/libraries/libstratosphere/source/ams/ams_bpc.os.horizon.c similarity index 98% rename from libraries/libstratosphere/source/ams/ams_bpc.c rename to libraries/libstratosphere/source/ams/ams_bpc.os.horizon.c index 9bfd4380c..89180e963 100644 --- a/libraries/libstratosphere/source/ams/ams_bpc.c +++ b/libraries/libstratosphere/source/ams/ams_bpc.os.horizon.c @@ -15,7 +15,7 @@ */ #define NX_SERVICE_ASSUME_NON_DOMAIN #include "../service_guard.h" -#include "ams_bpc.h" +#include "ams_bpc.os.horizon.h" static Service g_amsBpcSrv; diff --git a/libraries/libstratosphere/source/ams/ams_bpc.h b/libraries/libstratosphere/source/ams/ams_bpc.os.horizon.h similarity index 100% rename from libraries/libstratosphere/source/ams/ams_bpc.h rename to libraries/libstratosphere/source/ams/ams_bpc.os.horizon.h diff --git a/libraries/libstratosphere/source/ams/ams_emummc_api.cpp b/libraries/libstratosphere/source/ams/ams_emummc_api.cpp index 0258c0567..ce3b7f9f0 100644 --- a/libraries/libstratosphere/source/ams/ams_emummc_api.cpp +++ b/libraries/libstratosphere/source/ams/ams_emummc_api.cpp @@ -58,7 +58,7 @@ namespace ams::emummc { /* Globals. */ constinit os::SdkMutex g_lock; - constinit ExosphereConfig g_exo_config; + constinit ExosphereConfig g_exo_config = {}; constinit bool g_is_emummc; constinit bool g_has_cached; @@ -87,15 +87,23 @@ namespace ams::emummc { g_is_emummc = g_exo_config.base_cfg.magic == StorageMagic && storage != Storage_Emmc; /* Format paths. */ - if (storage == Storage_SdFile) { - util::SNPrintf(g_exo_config.file_cfg.path, sizeof(g_exo_config.file_cfg.path), "/%s", paths->file_path); - } + { + char tmp_path[MaxDirLen + 1]; - util::SNPrintf(g_exo_config.emu_dir_path, sizeof(g_exo_config.emu_dir_path), "/%s", paths->nintendo_path); + /* Format paths. */ + if (storage == Storage_SdFile) { + util::TSNPrintf(tmp_path, sizeof(tmp_path), "/%s", paths->file_path); + R_ABORT_UNLESS(fs::PathFormatter::Normalize(g_exo_config.file_cfg.path, sizeof(g_exo_config.file_cfg.path), tmp_path, std::strlen(tmp_path) + 1, fs::PathFlags{})); + } - /* If we're emummc, implement default nintendo redirection path. */ - if (g_is_emummc && std::strcmp(g_exo_config.emu_dir_path, "/") == 0) { - util::SNPrintf(g_exo_config.emu_dir_path, sizeof(g_exo_config.emu_dir_path), "/emummc/Nintendo_%04x", g_exo_config.base_cfg.id); + util::TSNPrintf(tmp_path, sizeof(tmp_path), "/%s", paths->nintendo_path); + R_ABORT_UNLESS(fs::PathFormatter::Normalize(g_exo_config.emu_dir_path, sizeof(g_exo_config.emu_dir_path), tmp_path, std::strlen(tmp_path) + 1, fs::PathFlags{})); + + /* If we're emummc, implement default nintendo redirection path. */ + if (g_is_emummc && std::strcmp(g_exo_config.emu_dir_path, "/") == 0) { + util::TSNPrintf(tmp_path, sizeof(tmp_path), "/emummc/Nintendo_%04x", g_exo_config.base_cfg.id); + R_ABORT_UNLESS(fs::PathFormatter::Normalize(g_exo_config.emu_dir_path, sizeof(g_exo_config.emu_dir_path), tmp_path, std::strlen(tmp_path) + 1, fs::PathFlags{})); + } } } diff --git a/libraries/libstratosphere/source/ams/ams_environment.cpp b/libraries/libstratosphere/source/ams/ams_environment.os.horizon.cpp similarity index 97% rename from libraries/libstratosphere/source/ams/ams_environment.cpp rename to libraries/libstratosphere/source/ams/ams_environment.os.horizon.cpp index eba47ec33..dec1eedee 100644 --- a/libraries/libstratosphere/source/ams/ams_environment.cpp +++ b/libraries/libstratosphere/source/ams/ams_environment.os.horizon.cpp @@ -14,12 +14,13 @@ * along with this program. If not, see . */ #include -#include "ams_bpc.h" +#include "ams_bpc.os.horizon.h" namespace ams { namespace { + #if defined(ATMOSPHERE_ARCH_ARM64) inline u64 GetPc() { u64 pc; __asm__ __volatile__ ("adr %[pc], ." : [pc]"=&r"(pc) :: ); @@ -30,6 +31,9 @@ namespace ams { u64 fp; u64 lr; }; + #else + #error "Unknown architecture for os Horizon" + #endif } diff --git a/libraries/libstratosphere/source/ams/ams_environment_weak.cpp b/libraries/libstratosphere/source/ams/ams_environment_weak.os.horizon.cpp similarity index 94% rename from libraries/libstratosphere/source/ams/ams_environment_weak.cpp rename to libraries/libstratosphere/source/ams/ams_environment_weak.os.horizon.cpp index 528442ec2..5fd5a917f 100644 --- a/libraries/libstratosphere/source/ams/ams_environment_weak.cpp +++ b/libraries/libstratosphere/source/ams/ams_environment_weak.os.horizon.cpp @@ -45,6 +45,7 @@ namespace ams { } NOINLINE NORETURN void AbortImpl() { + #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) /* Just perform a data abort. */ register u64 addr __asm__("x27") = FatalErrorContext::StdAbortMagicAddress; register u64 val __asm__("x28") = FatalErrorContext::StdAbortMagicValue; @@ -55,6 +56,10 @@ namespace ams { : [val]"r"(val), [addr]"r"(addr) ); } + #else + /* What should be done here? */ + AMS_INFINITE_LOOP(); + #endif __builtin_unreachable(); } diff --git a/libraries/libstratosphere/source/ams/ams_environment_weak.os.linux.cpp b/libraries/libstratosphere/source/ams/ams_environment_weak.os.linux.cpp new file mode 100644 index 000000000..0299f47c5 --- /dev/null +++ b/libraries/libstratosphere/source/ams/ams_environment_weak.os.linux.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 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 + +namespace ams { + + namespace os { + + void Initialize(); + + } + + void *Malloc(size_t size) { + return std::malloc(size); + } + + void Free(void *ptr) { + return std::free(ptr); + } + + void *MallocForRapidJson(size_t size) { + return std::malloc(size); + } + + void *ReallocForRapidJson(void *ptr, size_t size) { + return std::realloc(ptr, size); + } + + void FreeForRapidJson(void *ptr) { + return std::free(ptr); + } + + NORETURN void AbortImpl() { + std::abort(); + } + +} + +extern "C" { + + /* Redefine C++ exception handlers. Requires wrap linker flag. */ + #define WRAP_ABORT_FUNC(func) void NORETURN __wrap_##func(void) { std::abort(); __builtin_unreachable(); } + WRAP_ABORT_FUNC(__cxa_pure_virtual) + #undef WRAP_ABORT_FUNC + +} diff --git a/libraries/libstratosphere/source/ams/ams_environment_weak.os.macos.cpp b/libraries/libstratosphere/source/ams/ams_environment_weak.os.macos.cpp new file mode 100644 index 000000000..0299f47c5 --- /dev/null +++ b/libraries/libstratosphere/source/ams/ams_environment_weak.os.macos.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 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 + +namespace ams { + + namespace os { + + void Initialize(); + + } + + void *Malloc(size_t size) { + return std::malloc(size); + } + + void Free(void *ptr) { + return std::free(ptr); + } + + void *MallocForRapidJson(size_t size) { + return std::malloc(size); + } + + void *ReallocForRapidJson(void *ptr, size_t size) { + return std::realloc(ptr, size); + } + + void FreeForRapidJson(void *ptr) { + return std::free(ptr); + } + + NORETURN void AbortImpl() { + std::abort(); + } + +} + +extern "C" { + + /* Redefine C++ exception handlers. Requires wrap linker flag. */ + #define WRAP_ABORT_FUNC(func) void NORETURN __wrap_##func(void) { std::abort(); __builtin_unreachable(); } + WRAP_ABORT_FUNC(__cxa_pure_virtual) + #undef WRAP_ABORT_FUNC + +} diff --git a/libraries/libstratosphere/source/ams/ams_environment_weak.os.windows.cpp b/libraries/libstratosphere/source/ams/ams_environment_weak.os.windows.cpp new file mode 100644 index 000000000..5162e1b24 --- /dev/null +++ b/libraries/libstratosphere/source/ams/ams_environment_weak.os.windows.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 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 + +extern "C" char **__real___p__acmdln(void); + +namespace ams { + + namespace os { + + void Initialize(); + + } + + void *Malloc(size_t size) { + return std::malloc(size); + } + + void Free(void *ptr) { + return std::free(ptr); + } + + void *MallocForRapidJson(size_t size) { + return std::malloc(size); + } + + void *ReallocForRapidJson(void *ptr, size_t size) { + return std::realloc(ptr, size); + } + + void FreeForRapidJson(void *ptr) { + return std::free(ptr); + } + + NORETURN void AbortImpl() { + std::abort(); + } + +} + +extern "C" { + + /* Redefine C++ exception handlers. Requires wrap linker flag. */ + #define WRAP_ABORT_FUNC(func) void NORETURN __wrap_##func(void) { std::abort(); __builtin_unreachable(); } + WRAP_ABORT_FUNC(__cxa_pure_virtual) + #undef WRAP_ABORT_FUNC + + /* On windows, mingw may attempt to call malloc before we've initialized globals to set up the command line. */ + /* We perform some critical init here, to make that work. */ + char **__wrap___p__acmdln(void) { + ::ams::os::Initialize(); + return __real___p__acmdln(); + } + +} diff --git a/libraries/libstratosphere/source/ams/ams_exosphere_api.cpp b/libraries/libstratosphere/source/ams/ams_exosphere_api.cpp index 5db63628a..6c2a7cccb 100644 --- a/libraries/libstratosphere/source/ams/ams_exosphere_api.cpp +++ b/libraries/libstratosphere/source/ams/ams_exosphere_api.cpp @@ -26,6 +26,7 @@ namespace ams::exosphere { return ApiInfo{ util::BitPack64{exosphere_cfg} }; } + #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) void ForceRebootToRcm() { R_ABORT_UNLESS(spl::impl::SetConfig(spl::ConfigItem::ExosphereNeedsReboot, 1)); } @@ -81,5 +82,6 @@ namespace ams::exosphere { R_ABORT_UNLESS(spl::impl::GetConfig(std::addressof(device_id), spl::ConfigItem::DeviceId)); return device_id; } + #endif } diff --git a/libraries/libstratosphere/source/boot2/boot2_api.cpp b/libraries/libstratosphere/source/boot2/boot2_api.board.nintendo_nx.cpp similarity index 99% rename from libraries/libstratosphere/source/boot2/boot2_api.cpp rename to libraries/libstratosphere/source/boot2/boot2_api.board.nintendo_nx.cpp index a40e95f81..99faee716 100644 --- a/libraries/libstratosphere/source/boot2/boot2_api.cpp +++ b/libraries/libstratosphere/source/boot2/boot2_api.board.nintendo_nx.cpp @@ -162,7 +162,7 @@ namespace ams::boot2 { } bool GetGpioPadLow(DeviceCode device_code) { - gpio::GpioPadSession button; + gpio::GpioPadSession button{}; if (R_FAILED(gpio::OpenSession(std::addressof(button), device_code))) { return false; } @@ -255,7 +255,7 @@ namespace ams::boot2 { /* Read the mitm list off the SD card. */ { char path[fs::EntryNameLengthMax]; - util::SNPrintf(path, sizeof(path), "sdmc:/atmosphere/contents/%016lx/mitm.lst", static_cast(program_id)); + util::SNPrintf(path, sizeof(path), "sdmc:/atmosphere/contents/%016" PRIx64 "/mitm.lst", static_cast(program_id)); fs::FileHandle f; if (R_FAILED(fs::OpenFile(std::addressof(f), path, fs::OpenMode_Read))) { diff --git a/libraries/libstratosphere/source/capsrv/capsrv_screen_shot_control_api.cpp b/libraries/libstratosphere/source/capsrv/capsrv_screen_shot_control_api.cpp index 00a212486..5af5ff69a 100644 --- a/libraries/libstratosphere/source/capsrv/capsrv_screen_shot_control_api.cpp +++ b/libraries/libstratosphere/source/capsrv/capsrv_screen_shot_control_api.cpp @@ -18,18 +18,32 @@ namespace ams::capsrv { Result InitializeScreenShotControl() { + #if defined(ATMOSPHERE_OS_HORIZON) return ::capsscInitialize(); + #else + AMS_ABORT("TODO"); + #endif } void FinalizeScreenShotControl() { + #if defined(ATMOSPHERE_OS_HORIZON) return ::capsscExit(); + #else + AMS_ABORT("TODO"); + #endif } Result CaptureJpegScreenshot(u64 *out_size, void *dst, size_t dst_size, vi::LayerStack layer_stack, TimeSpan timeout) { + #if defined(ATMOSPHERE_OS_HORIZON) return ::capsscCaptureJpegScreenShot(out_size, dst, dst_size, static_cast<::ViLayerStack>(layer_stack), timeout.GetNanoSeconds()); + #else + AMS_UNUSED(out_size, dst, dst_size, layer_stack, timeout); + AMS_ABORT("TODO"); + #endif } Result OpenRawScreenShotReadStreamForDevelop(size_t *out_data_size, s32 *out_width, s32 *out_height, vi::LayerStack layer_stack, TimeSpan timeout) { + #if defined(ATMOSPHERE_OS_HORIZON) u64 data_size, width, height; R_TRY(::capsscOpenRawScreenShotReadStream(std::addressof(data_size), std::addressof(width), std::addressof(height), static_cast<::ViLayerStack>(layer_stack), timeout.GetNanoSeconds())); @@ -38,18 +52,32 @@ namespace ams::capsrv { *out_height = static_cast(height); return ResultSuccess(); + #else + AMS_UNUSED(out_data_size, out_width, out_height, layer_stack, timeout); + AMS_ABORT("TODO"); + #endif } Result ReadRawScreenShotReadStreamForDevelop(size_t *out_read_size, void *dst, size_t dst_size, std::ptrdiff_t offset) { + #if defined(ATMOSPHERE_OS_HORIZON) u64 read_size; R_TRY(::capsscReadRawScreenShotReadStream(std::addressof(read_size), dst, dst_size, static_cast(offset))); *out_read_size = static_cast(read_size); return ResultSuccess(); + #else + AMS_UNUSED(out_read_size, dst, dst_size, offset); + AMS_ABORT("TODO"); + #endif } void CloseRawScreenShotReadStreamForDevelop() { + #if defined(ATMOSPHERE_OS_HORIZON) ::capsscCloseRawScreenShotReadStream(); + #else + AMS_UNUSED(); + AMS_ABORT("TODO"); + #endif } } diff --git a/libraries/libstratosphere/source/cfg/cfg_flags.board.nintendo_nx.inc b/libraries/libstratosphere/source/cfg/cfg_flags.board.nintendo_nx.inc new file mode 100644 index 000000000..be8f42293 --- /dev/null +++ b/libraries/libstratosphere/source/cfg/cfg_flags.board.nintendo_nx.inc @@ -0,0 +1,106 @@ +/* + * Copyright (c) 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 + +namespace ams::cfg { + + namespace { + + std::atomic g_flag_mount_count; + + /* Helper. */ + void GetFlagMountName(char *dst) { + util::SNPrintf(dst, fs::MountNameLengthMax + 1, "#flag%08x", g_flag_mount_count.fetch_add(1)); + } + + bool HasFlagFile(const char *flag_path) { + /* All flags are not present until the SD card is. */ + if (!IsSdCardInitialized()) { + return false; + } + + /* Mount the SD card. */ + char mount_name[fs::MountNameLengthMax + 1]; + GetFlagMountName(mount_name); + if (R_FAILED(fs::MountSdCard(mount_name))) { + return false; + } + ON_SCOPE_EXIT { fs::Unmount(mount_name); }; + + /* Check if the entry exists. */ + char full_path[fs::EntryNameLengthMax + 1]; + util::SNPrintf(full_path, sizeof(full_path), "%s:/%s", mount_name, flag_path[0] == '/' ? flag_path + 1 : flag_path); + + bool has_file; + if (R_FAILED(fs::HasFile(std::addressof(has_file), full_path))) { + return false; + } + + return has_file; + } + + Result DeleteFlagFile(const char *flag_path) { + /* We need the SD card to be available to delete anything. */ + AMS_ABORT_UNLESS(IsSdCardInitialized()); + + /* Mount the sd card. */ + char mount_name[fs::MountNameLengthMax + 1]; + GetFlagMountName(mount_name); + R_TRY(fs::MountSdCard(mount_name)); + ON_SCOPE_EXIT { fs::Unmount(mount_name); }; + + /* Get the flag path. */ + char full_path[fs::EntryNameLengthMax + 1]; + util::SNPrintf(full_path, sizeof(full_path), "%s:/%s", mount_name, flag_path[0] == '/' ? flag_path + 1 : flag_path); + + /* Delete the file. */ + R_TRY(fs::DeleteFile(full_path)); + + return ResultSuccess(); + } + + } + + /* Flag utilities. */ + bool HasFlag(const sm::MitmProcessInfo &process_info, const char *flag) { + return HasContentSpecificFlag(process_info.program_id, flag) || (process_info.override_status.IsHbl() && HasHblFlag(flag)); + } + + bool HasContentSpecificFlag(ncm::ProgramId program_id, const char *flag) { + char content_flag[fs::EntryNameLengthMax + 1]; + util::SNPrintf(content_flag, sizeof(content_flag) - 1, "/atmosphere/contents/%016" PRIx64 "/flags/%s.flag", program_id.value, flag); + return HasFlagFile(content_flag); + } + + bool HasGlobalFlag(const char *flag) { + char global_flag[fs::EntryNameLengthMax + 1]; + util::SNPrintf(global_flag, sizeof(global_flag) - 1, "/atmosphere/flags/%s.flag", flag); + return HasFlagFile(global_flag); + } + + bool HasHblFlag(const char *flag) { + char hbl_flag[0x100]; + util::SNPrintf(hbl_flag, sizeof(hbl_flag) - 1, "hbl_%s", flag); + return HasGlobalFlag(hbl_flag); + } + + Result DeleteGlobalFlag(const char *flag) { + char global_flag[fs::EntryNameLengthMax + 1]; + util::SNPrintf(global_flag, sizeof(global_flag) - 1, "/atmosphere/flags/%s.flag", flag); + return DeleteFlagFile(global_flag); + } + +} diff --git a/libraries/libstratosphere/source/cfg/cfg_flags.cpp b/libraries/libstratosphere/source/cfg/cfg_flags.cpp index d2460b918..44587af1d 100644 --- a/libraries/libstratosphere/source/cfg/cfg_flags.cpp +++ b/libraries/libstratosphere/source/cfg/cfg_flags.cpp @@ -15,92 +15,8 @@ */ #include -namespace ams::cfg { - - namespace { - - std::atomic g_flag_mount_count; - - /* Helper. */ - void GetFlagMountName(char *dst) { - util::SNPrintf(dst, fs::MountNameLengthMax + 1, "#flag%08x", g_flag_mount_count.fetch_add(1)); - } - - bool HasFlagFile(const char *flag_path) { - /* All flags are not present until the SD card is. */ - if (!IsSdCardInitialized()) { - return false; - } - - /* Mount the SD card. */ - char mount_name[fs::MountNameLengthMax + 1]; - GetFlagMountName(mount_name); - if (R_FAILED(fs::MountSdCard(mount_name))) { - return false; - } - ON_SCOPE_EXIT { fs::Unmount(mount_name); }; - - /* Check if the entry exists. */ - char full_path[fs::EntryNameLengthMax + 1]; - util::SNPrintf(full_path, sizeof(full_path), "%s:/%s", mount_name, flag_path[0] == '/' ? flag_path + 1 : flag_path); - - bool has_file; - if (R_FAILED(fs::HasFile(std::addressof(has_file), full_path))) { - return false; - } - - return has_file; - } - - Result DeleteFlagFile(const char *flag_path) { - /* We need the SD card to be available to delete anything. */ - AMS_ABORT_UNLESS(IsSdCardInitialized()); - - /* Mount the sd card. */ - char mount_name[fs::MountNameLengthMax + 1]; - GetFlagMountName(mount_name); - R_TRY(fs::MountSdCard(mount_name)); - ON_SCOPE_EXIT { fs::Unmount(mount_name); }; - - /* Get the flag path. */ - char full_path[fs::EntryNameLengthMax + 1]; - util::SNPrintf(full_path, sizeof(full_path), "%s:/%s", mount_name, flag_path[0] == '/' ? flag_path + 1 : flag_path); - - /* Delete the file. */ - R_TRY(fs::DeleteFile(full_path)); - - return ResultSuccess(); - } - - } - - /* Flag utilities. */ - bool HasFlag(const sm::MitmProcessInfo &process_info, const char *flag) { - return HasContentSpecificFlag(process_info.program_id, flag) || (process_info.override_status.IsHbl() && HasHblFlag(flag)); - } - - bool HasContentSpecificFlag(ncm::ProgramId program_id, const char *flag) { - char content_flag[fs::EntryNameLengthMax + 1]; - util::SNPrintf(content_flag, sizeof(content_flag) - 1, "/atmosphere/contents/%016lx/flags/%s.flag", static_cast(program_id), flag); - return HasFlagFile(content_flag); - } - - bool HasGlobalFlag(const char *flag) { - char global_flag[fs::EntryNameLengthMax + 1]; - util::SNPrintf(global_flag, sizeof(global_flag) - 1, "/atmosphere/flags/%s.flag", flag); - return HasFlagFile(global_flag); - } - - bool HasHblFlag(const char *flag) { - char hbl_flag[0x100]; - util::SNPrintf(hbl_flag, sizeof(hbl_flag) - 1, "hbl_%s", flag); - return HasGlobalFlag(hbl_flag); - } - - Result DeleteGlobalFlag(const char *flag) { - char global_flag[fs::EntryNameLengthMax + 1]; - util::SNPrintf(global_flag, sizeof(global_flag) - 1, "/atmosphere/flags/%s.flag", flag); - return DeleteFlagFile(global_flag); - } - -} +#if defined(ATMOSPHERE_BOARD_NINTENDO_NX) + #include "cfg_flags.board.nintendo_nx.inc" +#else + #include "cfg_flags.generic.inc" +#endif \ No newline at end of file diff --git a/libraries/libstratosphere/source/cfg/cfg_flags.generic.inc b/libraries/libstratosphere/source/cfg/cfg_flags.generic.inc new file mode 100644 index 000000000..ebbe6528a --- /dev/null +++ b/libraries/libstratosphere/source/cfg/cfg_flags.generic.inc @@ -0,0 +1,46 @@ +/* + * Copyright (c) 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 + +namespace ams::cfg { + + /* Flag utilities. */ + bool HasFlag(const sm::MitmProcessInfo &process_info, const char *flag) { + AMS_UNUSED(process_info, flag); + return false; + } + + bool HasContentSpecificFlag(ncm::ProgramId program_id, const char *flag) { + AMS_UNUSED(program_id, flag); + return false; + } + + bool HasGlobalFlag(const char *flag) { + AMS_UNUSED(flag); + return false; + } + + bool HasHblFlag(const char *flag) { + AMS_UNUSED(flag); + return false; + } + + Result DeleteGlobalFlag(const char *flag) { + AMS_UNUSED(flag); + return false; + } + +} diff --git a/libraries/libstratosphere/source/cfg/cfg_override.board.nintendo_nx.inc b/libraries/libstratosphere/source/cfg/cfg_override.board.nintendo_nx.inc new file mode 100644 index 000000000..a91da9268 --- /dev/null +++ b/libraries/libstratosphere/source/cfg/cfg_override.board.nintendo_nx.inc @@ -0,0 +1,443 @@ +/* + * Copyright (c) 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 + +namespace ams::cfg { + + namespace { + + /* Types. */ + struct OverrideKey { + u64 key_combination; + bool override_by_default; + }; + + struct ProgramOverrideKey { + OverrideKey override_key; + ncm::ProgramId program_id; + }; + + constexpr ProgramOverrideKey InvalidProgramOverrideKey = {}; + + constexpr ProgramOverrideKey DefaultAppletPhotoViewerOverrideKey = { + .override_key = { + .key_combination = HidNpadButton_R, + .override_by_default = true, + }, + .program_id = ncm::SystemAppletId::PhotoViewer, + }; + + constexpr size_t MaxProgramOverrideKeys = 8; + + struct HblOverrideConfig { + ProgramOverrideKey program_configs[MaxProgramOverrideKeys]; + impl::OverrideStatusFlag program_as_flags[MaxProgramOverrideKeys]; + OverrideKey override_any_app_key; + impl::OverrideStatusFlag override_any_app_as_flag; + bool override_any_app; + }; + + struct ContentSpecificOverrideConfig { + OverrideKey override_key; + OverrideKey cheat_enable_key; + OverrideLocale locale; + }; + + /* Override globals. */ + OverrideKey g_default_override_key = { + .key_combination = HidNpadButton_L, + .override_by_default = true, + }; + + OverrideKey g_default_cheat_enable_key = { + .key_combination = HidNpadButton_L, + .override_by_default = true, + }; + + HblOverrideConfig g_hbl_override_config = { + .program_configs = { + DefaultAppletPhotoViewerOverrideKey, + InvalidProgramOverrideKey, + InvalidProgramOverrideKey, + InvalidProgramOverrideKey, + InvalidProgramOverrideKey, + InvalidProgramOverrideKey, + InvalidProgramOverrideKey, + InvalidProgramOverrideKey, + }, + .program_as_flags = { + impl::OverrideStatusFlag_AddressSpace64Bit, + impl::OverrideStatusFlag_AddressSpace64Bit, + impl::OverrideStatusFlag_AddressSpace64Bit, + impl::OverrideStatusFlag_AddressSpace64Bit, + impl::OverrideStatusFlag_AddressSpace64Bit, + impl::OverrideStatusFlag_AddressSpace64Bit, + impl::OverrideStatusFlag_AddressSpace64Bit, + impl::OverrideStatusFlag_AddressSpace64Bit, + }, + .override_any_app_key = { + .key_combination = HidNpadButton_R, + .override_by_default = false, + }, + .override_any_app_as_flag = impl::OverrideStatusFlag_AddressSpace64Bit, + .override_any_app = true, + }; + + char g_hbl_sd_path[0x100] = "/atmosphere/hbl.nsp"; + + /* Helpers. */ + OverrideKey ParseOverrideKey(const char *value) { + OverrideKey cfg = {}; + + /* Parse on by default. */ + if (value[0] == '!') { + cfg.override_by_default = true; + value++; + } + + /* Parse key combination. */ + if (strcasecmp(value, "A") == 0) { + cfg.key_combination = HidNpadButton_A; + } else if (strcasecmp(value, "B") == 0) { + cfg.key_combination = HidNpadButton_B; + } else if (strcasecmp(value, "X") == 0) { + cfg.key_combination = HidNpadButton_X; + } else if (strcasecmp(value, "Y") == 0) { + cfg.key_combination = HidNpadButton_Y; + } else if (strcasecmp(value, "LS") == 0) { + cfg.key_combination = HidNpadButton_StickL; + } else if (strcasecmp(value, "RS") == 0) { + cfg.key_combination = HidNpadButton_StickR; + } else if (strcasecmp(value, "L") == 0) { + cfg.key_combination = HidNpadButton_L; + } else if (strcasecmp(value, "R") == 0) { + cfg.key_combination = HidNpadButton_R; + } else if (strcasecmp(value, "ZL") == 0) { + cfg.key_combination = HidNpadButton_ZL; + } else if (strcasecmp(value, "ZR") == 0) { + cfg.key_combination = HidNpadButton_ZR; + } else if (strcasecmp(value, "PLUS") == 0) { + cfg.key_combination = HidNpadButton_Plus; + } else if (strcasecmp(value, "MINUS") == 0) { + cfg.key_combination = HidNpadButton_Minus; + } else if (strcasecmp(value, "DLEFT") == 0) { + cfg.key_combination = HidNpadButton_Left; + } else if (strcasecmp(value, "DUP") == 0) { + cfg.key_combination = HidNpadButton_Up; + } else if (strcasecmp(value, "DRIGHT") == 0) { + cfg.key_combination = HidNpadButton_Right; + } else if (strcasecmp(value, "DDOWN") == 0) { + cfg.key_combination = HidNpadButton_Down; + } else if (strcasecmp(value, "SL") == 0) { + cfg.key_combination = HidNpadButton_AnySL; + } else if (strcasecmp(value, "SR") == 0) { + cfg.key_combination = HidNpadButton_AnySR; + } + + return cfg; + } + + impl::OverrideStatusFlag ParseOverrideAddressSpace(const char *value) { + if (strcasecmp(value, "39_bit") == 0 || strcasecmp(value, "39") == 0) { + return impl::OverrideStatusFlag_AddressSpace64Bit; + } else if (strcasecmp(value, "36_bit") == 0 || strcasecmp(value, "36") == 0) { + return impl::OverrideStatusFlag_AddressSpace64BitDeprecated; + } else if (strcasecmp(value, "32_bit") == 0 || strcasecmp(value, "32") == 0) { + return impl::OverrideStatusFlag_AddressSpace32Bit; + } else if (strcasecmp(value, "32_bit_without_alias") == 0 || + strcasecmp(value, "32_bit_no_alias") == 0 || + strcasecmp(value, "32_without_alias") == 0 || + strcasecmp(value, "32_no_alias") || + strcasecmp(value, "32_bit_without_map") == 0 || + strcasecmp(value, "32_bit_no_map") == 0 || + strcasecmp(value, "32_without_map") == 0 || + strcasecmp(value, "32_no_map") == 0) + { + return impl::OverrideStatusFlag_AddressSpace32BitWithoutAlias; + } else { + /* Default to 39-bit. */ + return impl::OverrideStatusFlag_AddressSpace64Bit; + } + } + + inline void SetHblSpecificProgramId(size_t i, const char *value) { + g_hbl_override_config.program_configs[i].program_id = {strtoul(value, nullptr, 16)}; + } + + inline void SetHblSpecificOverrideKey(size_t i, const char *value) { + g_hbl_override_config.program_configs[i].override_key = ParseOverrideKey(value); + } + + inline void SetHblSpecificAddressSpace(size_t i, const char *value) { + g_hbl_override_config.program_as_flags[i] = ParseOverrideAddressSpace(value); + } + + int OverrideConfigIniHandler(void *user, const char *section, const char *name, const char *value) { + AMS_UNUSED(user); + + /* Taken and modified, with love, from Rajkosto's implementation. */ + if (strcasecmp(section, "hbl_config") == 0) { + if (strcasecmp(name, "program_id") == 0 || strcasecmp(name, "program_id_0") == 0) { + SetHblSpecificProgramId(0, value); + } else if (strcasecmp(name, "program_id_1") == 0) { + SetHblSpecificProgramId(1, value); + } else if (strcasecmp(name, "program_id_2") == 0) { + SetHblSpecificProgramId(2, value); + } else if (strcasecmp(name, "program_id_3") == 0) { + SetHblSpecificProgramId(3, value); + } else if (strcasecmp(name, "program_id_4") == 0) { + SetHblSpecificProgramId(4, value); + } else if (strcasecmp(name, "program_id_5") == 0) { + SetHblSpecificProgramId(5, value); + } else if (strcasecmp(name, "program_id_6") == 0) { + SetHblSpecificProgramId(6, value); + } else if (strcasecmp(name, "program_id_7") == 0) { + SetHblSpecificProgramId(7, value); + } else if (strcasecmp(name, "override_key") == 0 || strcasecmp(name, "override_key_0") == 0) { + SetHblSpecificOverrideKey(0, value); + } else if (strcasecmp(name, "override_key_1") == 0) { + SetHblSpecificOverrideKey(1, value); + } else if (strcasecmp(name, "override_key_2") == 0) { + SetHblSpecificOverrideKey(2, value); + } else if (strcasecmp(name, "override_key_3") == 0) { + SetHblSpecificOverrideKey(3, value); + } else if (strcasecmp(name, "override_key_4") == 0) { + SetHblSpecificOverrideKey(4, value); + } else if (strcasecmp(name, "override_key_5") == 0) { + SetHblSpecificOverrideKey(5, value); + } else if (strcasecmp(name, "override_key_6") == 0) { + SetHblSpecificOverrideKey(6, value); + } else if (strcasecmp(name, "override_key_7") == 0) { + SetHblSpecificOverrideKey(7, value); + } else if (strcasecmp(name, "override_address_space") == 0 || strcasecmp(name, "override_address_space_0") == 0) { + SetHblSpecificAddressSpace(0, value); + } else if (strcasecmp(name, "override_address_space_1") == 0) { + SetHblSpecificAddressSpace(1, value); + } else if (strcasecmp(name, "override_address_space_2") == 0) { + SetHblSpecificAddressSpace(2, value); + } else if (strcasecmp(name, "override_address_space_3") == 0) { + SetHblSpecificAddressSpace(3, value); + } else if (strcasecmp(name, "override_address_space_4") == 0) { + SetHblSpecificAddressSpace(4, value); + } else if (strcasecmp(name, "override_address_space_5") == 0) { + SetHblSpecificAddressSpace(5, value); + } else if (strcasecmp(name, "override_address_space_6") == 0) { + SetHblSpecificAddressSpace(6, value); + } else if (strcasecmp(name, "override_address_space_7") == 0) { + SetHblSpecificAddressSpace(7, value); + } else if (strcasecmp(name, "override_any_app") == 0) { + if (strcasecmp(value, "true") == 0 || strcasecmp(value, "1") == 0) { + g_hbl_override_config.override_any_app = true; + } else if (strcasecmp(value, "false") == 0 || strcasecmp(value, "0") == 0) { + g_hbl_override_config.override_any_app = false; + } else { + /* I guess we default to not changing the value? */ + } + } else if (strcasecmp(name, "override_any_app_key") == 0) { + g_hbl_override_config.override_any_app_key = ParseOverrideKey(value); + } else if (strcasecmp(name, "override_any_app_address_space") == 0) { + g_hbl_override_config.override_any_app_as_flag = ParseOverrideAddressSpace(value); + } else if (strcasecmp(name, "path") == 0) { + while (*value == '/' || *value == '\\') { + value++; + } + util::SNPrintf(g_hbl_sd_path, sizeof(g_hbl_sd_path) - 1, "/%s", value); + g_hbl_sd_path[sizeof(g_hbl_sd_path) - 1] = '\0'; + + for (size_t i = 0; i < sizeof(g_hbl_sd_path); i++) { + if (g_hbl_sd_path[i] == '\\') { + g_hbl_sd_path[i] = '/'; + } + } + } + } else if (strcasecmp(section, "default_config") == 0) { + if (strcasecmp(name, "override_key") == 0) { + g_default_override_key = ParseOverrideKey(value); + } else if (strcasecmp(name, "cheat_enable_key") == 0) { + g_default_cheat_enable_key = ParseOverrideKey(value); + } + } else { + return 0; + } + return 1; + } + + int ContentSpecificIniHandler(void *user, const char *section, const char *name, const char *value) { + ContentSpecificOverrideConfig *config = reinterpret_cast(user); + + if (strcasecmp(section, "override_config") == 0) { + if (strcasecmp(name, "override_key") == 0) { + config->override_key = ParseOverrideKey(value); + } else if (strcasecmp(name, "cheat_enable_key") == 0) { + config->cheat_enable_key = ParseOverrideKey(value); + } else if (strcasecmp(name, "override_language") == 0) { + config->locale.language_code = settings::LanguageCode::Encode(value); + } else if (strcasecmp(name, "override_region") == 0) { + if (strcasecmp(value, "jpn") == 0) { + config->locale.region_code = settings::RegionCode_Japan; + } else if (strcasecmp(value, "usa") == 0) { + config->locale.region_code = settings::RegionCode_America; + } else if (strcasecmp(value, "eur") == 0) { + config->locale.region_code = settings::RegionCode_Europe; + } else if (strcasecmp(value, "aus") == 0) { + config->locale.region_code = settings::RegionCode_Australia; + } else if (strcasecmp(value, "chn") == 0) { + config->locale.region_code = settings::RegionCode_China; + } else if (strcasecmp(value, "kor") == 0) { + config->locale.region_code = settings::RegionCode_Korea; + } else if (strcasecmp(value, "twn") == 0) { + config->locale.region_code = settings::RegionCode_Taiwan; + } + } + } else { + return 0; + } + + return 1; + } + + constexpr inline bool IsOverrideMatch(const OverrideStatus &status, const OverrideKey &cfg) { + bool keys_triggered = ((status.keys_held & cfg.key_combination) != 0); + return (cfg.override_by_default ^ keys_triggered); + } + + inline bool IsAnySpecificHblProgramId(ncm::ProgramId program_id) { + for (size_t i = 0; i < MaxProgramOverrideKeys; i++) { + if (program_id == g_hbl_override_config.program_configs[i].program_id) { + return true; + } + } + return false; + } + + inline bool IsSpecificHblProgramId(size_t i, ncm::ProgramId program_id) { + return program_id == g_hbl_override_config.program_configs[i].program_id; + } + + inline bool IsAnyApplicationHblProgramId(ncm::ProgramId program_id) { + return g_hbl_override_config.override_any_app && ncm::IsApplicationId(program_id) && !IsAnySpecificHblProgramId(program_id); + } + + std::atomic g_ini_mount_count; + + void GetIniMountName(char *dst) { + util::SNPrintf(dst, fs::MountNameLengthMax + 1, "#ini%08x", g_ini_mount_count.fetch_add(1)); + } + + void ParseIniFile(util::ini::Handler handler, const char *path, void *user_ctx) { + /* Mount the SD card. */ + char mount_name[fs::MountNameLengthMax + 1]; + GetIniMountName(mount_name); + if (R_FAILED(fs::MountSdCard(mount_name))) { + return; + } + ON_SCOPE_EXIT { fs::Unmount(mount_name); }; + + /* Open the file. */ + fs::FileHandle file; + { + char full_path[fs::EntryNameLengthMax + 1]; + util::SNPrintf(full_path, sizeof(full_path), "%s:/%s", mount_name, path[0] == '/' ? path + 1 : path); + if (R_FAILED(fs::OpenFile(std::addressof(file), full_path, fs::OpenMode_Read))) { + return; + } + } + ON_SCOPE_EXIT { fs::CloseFile(file); }; + + /* Parse the config. */ + util::ini::ParseFile(file, user_ctx, handler); + } + + void RefreshOverrideConfiguration() { + ParseIniFile(OverrideConfigIniHandler, "/atmosphere/config/override_config.ini", nullptr); + } + + ContentSpecificOverrideConfig GetContentOverrideConfig(ncm::ProgramId program_id) { + char path[fs::EntryNameLengthMax + 1]; + util::SNPrintf(path, sizeof(path), "/atmosphere/contents/%016" PRIx64 "/config.ini", program_id.value); + + ContentSpecificOverrideConfig config = { + .override_key = g_default_override_key, + .cheat_enable_key = g_default_cheat_enable_key, + }; + std::memset(std::addressof(config.locale), 0xCC, sizeof(config.locale)); + + ParseIniFile(ContentSpecificIniHandler, path, std::addressof(config)); + return config; + } + + } + + OverrideStatus CaptureOverrideStatus(ncm::ProgramId program_id) { + OverrideStatus status = {}; + + /* If the SD card isn't initialized, we can't override. */ + if (!IsSdCardInitialized()) { + return status; + } + + /* For system modules and anything launched before the home menu, always override. */ + if (program_id < ncm::SystemAppletId::Start || !pm::info::HasLaunchedBootProgram(ncm::SystemAppletId::Qlaunch)) { + status.SetProgramSpecific(); + return status; + } + + /* Unconditionally refresh override_config.ini contents. */ + RefreshOverrideConfiguration(); + + /* If we can't read the key state, don't override anything. */ + if (R_FAILED(hid::GetKeysHeld(std::addressof(status.keys_held)))) { + return status; + } + + /* Detect Hbl. */ + if (IsAnyApplicationHblProgramId(program_id) && IsOverrideMatch(status, g_hbl_override_config.override_any_app_key)) { + status.SetHbl(); + status.flags &= ~impl::OverrideStatusFlag_AddressSpaceMask; + status.flags |= g_hbl_override_config.override_any_app_as_flag; + } + for (size_t i = 0; i < MaxProgramOverrideKeys; i++) { + if (IsSpecificHblProgramId(i, program_id) && IsOverrideMatch(status, g_hbl_override_config.program_configs[i].override_key)) { + status.SetHbl(); + status.flags &= ~impl::OverrideStatusFlag_AddressSpaceMask; + status.flags |= g_hbl_override_config.program_as_flags[i]; + } + } + + /* Detect content specific keys. */ + const auto content_cfg = GetContentOverrideConfig(program_id); + if (IsOverrideMatch(status, content_cfg.override_key)) { + status.SetProgramSpecific(); + } + + /* Only allow cheat enable if not HBL. */ + if (!status.IsHbl() && IsOverrideMatch(status, content_cfg.cheat_enable_key)) { + status.SetCheatEnabled(); + } + + return status; + } + + OverrideLocale GetOverrideLocale(ncm::ProgramId program_id) { + return GetContentOverrideConfig(program_id).locale; + } + + /* HBL Configuration utilities. */ + const char *GetHblPath() { + return g_hbl_sd_path; + } + +} diff --git a/libraries/libstratosphere/source/cfg/cfg_override.cpp b/libraries/libstratosphere/source/cfg/cfg_override.cpp index 54629ff54..269ba6afc 100644 --- a/libraries/libstratosphere/source/cfg/cfg_override.cpp +++ b/libraries/libstratosphere/source/cfg/cfg_override.cpp @@ -15,429 +15,8 @@ */ #include -namespace ams::cfg { - - namespace { - - /* Types. */ - struct OverrideKey { - u64 key_combination; - bool override_by_default; - }; - - struct ProgramOverrideKey { - OverrideKey override_key; - ncm::ProgramId program_id; - }; - - constexpr ProgramOverrideKey InvalidProgramOverrideKey = {}; - - constexpr ProgramOverrideKey DefaultAppletPhotoViewerOverrideKey = { - .override_key = { - .key_combination = HidNpadButton_R, - .override_by_default = true, - }, - .program_id = ncm::SystemAppletId::PhotoViewer, - }; - - constexpr size_t MaxProgramOverrideKeys = 8; - - struct HblOverrideConfig { - ProgramOverrideKey program_configs[MaxProgramOverrideKeys]; - impl::OverrideStatusFlag program_as_flags[MaxProgramOverrideKeys]; - OverrideKey override_any_app_key; - impl::OverrideStatusFlag override_any_app_as_flag; - bool override_any_app; - }; - - struct ContentSpecificOverrideConfig { - OverrideKey override_key; - OverrideKey cheat_enable_key; - OverrideLocale locale; - }; - - /* Override globals. */ - OverrideKey g_default_override_key = { - .key_combination = HidNpadButton_L, - .override_by_default = true, - }; - - OverrideKey g_default_cheat_enable_key = { - .key_combination = HidNpadButton_L, - .override_by_default = true, - }; - - HblOverrideConfig g_hbl_override_config = { - .program_configs = { - DefaultAppletPhotoViewerOverrideKey, - InvalidProgramOverrideKey, - InvalidProgramOverrideKey, - InvalidProgramOverrideKey, - InvalidProgramOverrideKey, - InvalidProgramOverrideKey, - InvalidProgramOverrideKey, - InvalidProgramOverrideKey, - }, - .program_as_flags = { - impl::OverrideStatusFlag_AddressSpace64Bit, - impl::OverrideStatusFlag_AddressSpace64Bit, - impl::OverrideStatusFlag_AddressSpace64Bit, - impl::OverrideStatusFlag_AddressSpace64Bit, - impl::OverrideStatusFlag_AddressSpace64Bit, - impl::OverrideStatusFlag_AddressSpace64Bit, - impl::OverrideStatusFlag_AddressSpace64Bit, - impl::OverrideStatusFlag_AddressSpace64Bit, - }, - .override_any_app_key = { - .key_combination = HidNpadButton_R, - .override_by_default = false, - }, - .override_any_app_as_flag = impl::OverrideStatusFlag_AddressSpace64Bit, - .override_any_app = true, - }; - - char g_hbl_sd_path[0x100] = "/atmosphere/hbl.nsp"; - - /* Helpers. */ - OverrideKey ParseOverrideKey(const char *value) { - OverrideKey cfg = {}; - - /* Parse on by default. */ - if (value[0] == '!') { - cfg.override_by_default = true; - value++; - } - - /* Parse key combination. */ - if (strcasecmp(value, "A") == 0) { - cfg.key_combination = HidNpadButton_A; - } else if (strcasecmp(value, "B") == 0) { - cfg.key_combination = HidNpadButton_B; - } else if (strcasecmp(value, "X") == 0) { - cfg.key_combination = HidNpadButton_X; - } else if (strcasecmp(value, "Y") == 0) { - cfg.key_combination = HidNpadButton_Y; - } else if (strcasecmp(value, "LS") == 0) { - cfg.key_combination = HidNpadButton_StickL; - } else if (strcasecmp(value, "RS") == 0) { - cfg.key_combination = HidNpadButton_StickR; - } else if (strcasecmp(value, "L") == 0) { - cfg.key_combination = HidNpadButton_L; - } else if (strcasecmp(value, "R") == 0) { - cfg.key_combination = HidNpadButton_R; - } else if (strcasecmp(value, "ZL") == 0) { - cfg.key_combination = HidNpadButton_ZL; - } else if (strcasecmp(value, "ZR") == 0) { - cfg.key_combination = HidNpadButton_ZR; - } else if (strcasecmp(value, "PLUS") == 0) { - cfg.key_combination = HidNpadButton_Plus; - } else if (strcasecmp(value, "MINUS") == 0) { - cfg.key_combination = HidNpadButton_Minus; - } else if (strcasecmp(value, "DLEFT") == 0) { - cfg.key_combination = HidNpadButton_Left; - } else if (strcasecmp(value, "DUP") == 0) { - cfg.key_combination = HidNpadButton_Up; - } else if (strcasecmp(value, "DRIGHT") == 0) { - cfg.key_combination = HidNpadButton_Right; - } else if (strcasecmp(value, "DDOWN") == 0) { - cfg.key_combination = HidNpadButton_Down; - } else if (strcasecmp(value, "SL") == 0) { - cfg.key_combination = HidNpadButton_AnySL; - } else if (strcasecmp(value, "SR") == 0) { - cfg.key_combination = HidNpadButton_AnySR; - } - - return cfg; - } - - impl::OverrideStatusFlag ParseOverrideAddressSpace(const char *value) { - if (strcasecmp(value, "39_bit") == 0 || strcasecmp(value, "39") == 0) { - return impl::OverrideStatusFlag_AddressSpace64Bit; - } else if (strcasecmp(value, "36_bit") == 0 || strcasecmp(value, "36") == 0) { - return impl::OverrideStatusFlag_AddressSpace64BitDeprecated; - } else if (strcasecmp(value, "32_bit") == 0 || strcasecmp(value, "32") == 0) { - return impl::OverrideStatusFlag_AddressSpace32Bit; - } else if (strcasecmp(value, "32_bit_without_alias") == 0 || - strcasecmp(value, "32_bit_no_alias") == 0 || - strcasecmp(value, "32_without_alias") == 0 || - strcasecmp(value, "32_no_alias") || - strcasecmp(value, "32_bit_without_map") == 0 || - strcasecmp(value, "32_bit_no_map") == 0 || - strcasecmp(value, "32_without_map") == 0 || - strcasecmp(value, "32_no_map") == 0) - { - return impl::OverrideStatusFlag_AddressSpace32BitWithoutAlias; - } else { - /* Default to 39-bit. */ - return impl::OverrideStatusFlag_AddressSpace64Bit; - } - } - - inline void SetHblSpecificProgramId(size_t i, const char *value) { - g_hbl_override_config.program_configs[i].program_id = {strtoul(value, nullptr, 16)}; - } - - inline void SetHblSpecificOverrideKey(size_t i, const char *value) { - g_hbl_override_config.program_configs[i].override_key = ParseOverrideKey(value); - } - - inline void SetHblSpecificAddressSpace(size_t i, const char *value) { - g_hbl_override_config.program_as_flags[i] = ParseOverrideAddressSpace(value); - } - - int OverrideConfigIniHandler(void *user, const char *section, const char *name, const char *value) { - AMS_UNUSED(user); - - /* Taken and modified, with love, from Rajkosto's implementation. */ - if (strcasecmp(section, "hbl_config") == 0) { - if (strcasecmp(name, "program_id") == 0 || strcasecmp(name, "program_id_0") == 0) { - SetHblSpecificProgramId(0, value); - } else if (strcasecmp(name, "program_id_1") == 0) { - SetHblSpecificProgramId(1, value); - } else if (strcasecmp(name, "program_id_2") == 0) { - SetHblSpecificProgramId(2, value); - } else if (strcasecmp(name, "program_id_3") == 0) { - SetHblSpecificProgramId(3, value); - } else if (strcasecmp(name, "program_id_4") == 0) { - SetHblSpecificProgramId(4, value); - } else if (strcasecmp(name, "program_id_5") == 0) { - SetHblSpecificProgramId(5, value); - } else if (strcasecmp(name, "program_id_6") == 0) { - SetHblSpecificProgramId(6, value); - } else if (strcasecmp(name, "program_id_7") == 0) { - SetHblSpecificProgramId(7, value); - } else if (strcasecmp(name, "override_key") == 0 || strcasecmp(name, "override_key_0") == 0) { - SetHblSpecificOverrideKey(0, value); - } else if (strcasecmp(name, "override_key_1") == 0) { - SetHblSpecificOverrideKey(1, value); - } else if (strcasecmp(name, "override_key_2") == 0) { - SetHblSpecificOverrideKey(2, value); - } else if (strcasecmp(name, "override_key_3") == 0) { - SetHblSpecificOverrideKey(3, value); - } else if (strcasecmp(name, "override_key_4") == 0) { - SetHblSpecificOverrideKey(4, value); - } else if (strcasecmp(name, "override_key_5") == 0) { - SetHblSpecificOverrideKey(5, value); - } else if (strcasecmp(name, "override_key_6") == 0) { - SetHblSpecificOverrideKey(6, value); - } else if (strcasecmp(name, "override_key_7") == 0) { - SetHblSpecificOverrideKey(7, value); - } else if (strcasecmp(name, "override_address_space") == 0 || strcasecmp(name, "override_address_space_0") == 0) { - SetHblSpecificAddressSpace(0, value); - } else if (strcasecmp(name, "override_address_space_1") == 0) { - SetHblSpecificAddressSpace(1, value); - } else if (strcasecmp(name, "override_address_space_2") == 0) { - SetHblSpecificAddressSpace(2, value); - } else if (strcasecmp(name, "override_address_space_3") == 0) { - SetHblSpecificAddressSpace(3, value); - } else if (strcasecmp(name, "override_address_space_4") == 0) { - SetHblSpecificAddressSpace(4, value); - } else if (strcasecmp(name, "override_address_space_5") == 0) { - SetHblSpecificAddressSpace(5, value); - } else if (strcasecmp(name, "override_address_space_6") == 0) { - SetHblSpecificAddressSpace(6, value); - } else if (strcasecmp(name, "override_address_space_7") == 0) { - SetHblSpecificAddressSpace(7, value); - } else if (strcasecmp(name, "override_any_app") == 0) { - if (strcasecmp(value, "true") == 0 || strcasecmp(value, "1") == 0) { - g_hbl_override_config.override_any_app = true; - } else if (strcasecmp(value, "false") == 0 || strcasecmp(value, "0") == 0) { - g_hbl_override_config.override_any_app = false; - } else { - /* I guess we default to not changing the value? */ - } - } else if (strcasecmp(name, "override_any_app_key") == 0) { - g_hbl_override_config.override_any_app_key = ParseOverrideKey(value); - } else if (strcasecmp(name, "override_any_app_address_space") == 0) { - g_hbl_override_config.override_any_app_as_flag = ParseOverrideAddressSpace(value); - } else if (strcasecmp(name, "path") == 0) { - while (*value == '/' || *value == '\\') { - value++; - } - util::SNPrintf(g_hbl_sd_path, sizeof(g_hbl_sd_path) - 1, "/%s", value); - g_hbl_sd_path[sizeof(g_hbl_sd_path) - 1] = '\0'; - - for (size_t i = 0; i < sizeof(g_hbl_sd_path); i++) { - if (g_hbl_sd_path[i] == '\\') { - g_hbl_sd_path[i] = '/'; - } - } - } - } else if (strcasecmp(section, "default_config") == 0) { - if (strcasecmp(name, "override_key") == 0) { - g_default_override_key = ParseOverrideKey(value); - } else if (strcasecmp(name, "cheat_enable_key") == 0) { - g_default_cheat_enable_key = ParseOverrideKey(value); - } - } else { - return 0; - } - return 1; - } - - int ContentSpecificIniHandler(void *user, const char *section, const char *name, const char *value) { - ContentSpecificOverrideConfig *config = reinterpret_cast(user); - - if (strcasecmp(section, "override_config") == 0) { - if (strcasecmp(name, "override_key") == 0) { - config->override_key = ParseOverrideKey(value); - } else if (strcasecmp(name, "cheat_enable_key") == 0) { - config->cheat_enable_key = ParseOverrideKey(value); - } else if (strcasecmp(name, "override_language") == 0) { - config->locale.language_code = settings::LanguageCode::Encode(value); - } else if (strcasecmp(name, "override_region") == 0) { - if (strcasecmp(value, "jpn") == 0) { - config->locale.region_code = settings::RegionCode_Japan; - } else if (strcasecmp(value, "usa") == 0) { - config->locale.region_code = settings::RegionCode_America; - } else if (strcasecmp(value, "eur") == 0) { - config->locale.region_code = settings::RegionCode_Europe; - } else if (strcasecmp(value, "aus") == 0) { - config->locale.region_code = settings::RegionCode_Australia; - } else if (strcasecmp(value, "chn") == 0) { - config->locale.region_code = settings::RegionCode_China; - } else if (strcasecmp(value, "kor") == 0) { - config->locale.region_code = settings::RegionCode_Korea; - } else if (strcasecmp(value, "twn") == 0) { - config->locale.region_code = settings::RegionCode_Taiwan; - } - } - } else { - return 0; - } - - return 1; - } - - constexpr inline bool IsOverrideMatch(const OverrideStatus &status, const OverrideKey &cfg) { - bool keys_triggered = ((status.keys_held & cfg.key_combination) != 0); - return (cfg.override_by_default ^ keys_triggered); - } - - inline bool IsAnySpecificHblProgramId(ncm::ProgramId program_id) { - for (size_t i = 0; i < MaxProgramOverrideKeys; i++) { - if (program_id == g_hbl_override_config.program_configs[i].program_id) { - return true; - } - } - return false; - } - - inline bool IsSpecificHblProgramId(size_t i, ncm::ProgramId program_id) { - return program_id == g_hbl_override_config.program_configs[i].program_id; - } - - inline bool IsAnyApplicationHblProgramId(ncm::ProgramId program_id) { - return g_hbl_override_config.override_any_app && ncm::IsApplicationId(program_id) && !IsAnySpecificHblProgramId(program_id); - } - - std::atomic g_ini_mount_count; - - void GetIniMountName(char *dst) { - util::SNPrintf(dst, fs::MountNameLengthMax + 1, "#ini%08x", g_ini_mount_count.fetch_add(1)); - } - - void ParseIniFile(util::ini::Handler handler, const char *path, void *user_ctx) { - /* Mount the SD card. */ - char mount_name[fs::MountNameLengthMax + 1]; - GetIniMountName(mount_name); - if (R_FAILED(fs::MountSdCard(mount_name))) { - return; - } - ON_SCOPE_EXIT { fs::Unmount(mount_name); }; - - /* Open the file. */ - fs::FileHandle file; - { - char full_path[fs::EntryNameLengthMax + 1]; - util::SNPrintf(full_path, sizeof(full_path), "%s:/%s", mount_name, path[0] == '/' ? path + 1 : path); - if (R_FAILED(fs::OpenFile(std::addressof(file), full_path, fs::OpenMode_Read))) { - return; - } - } - ON_SCOPE_EXIT { fs::CloseFile(file); }; - - /* Parse the config. */ - util::ini::ParseFile(file, user_ctx, handler); - } - - void RefreshOverrideConfiguration() { - ParseIniFile(OverrideConfigIniHandler, "/atmosphere/config/override_config.ini", nullptr); - } - - ContentSpecificOverrideConfig GetContentOverrideConfig(ncm::ProgramId program_id) { - char path[fs::EntryNameLengthMax + 1]; - util::SNPrintf(path, sizeof(path), "/atmosphere/contents/%016lx/config.ini", static_cast(program_id)); - - ContentSpecificOverrideConfig config = { - .override_key = g_default_override_key, - .cheat_enable_key = g_default_cheat_enable_key, - }; - std::memset(std::addressof(config.locale), 0xCC, sizeof(config.locale)); - - ParseIniFile(ContentSpecificIniHandler, path, std::addressof(config)); - return config; - } - - } - - OverrideStatus CaptureOverrideStatus(ncm::ProgramId program_id) { - OverrideStatus status = {}; - - /* If the SD card isn't initialized, we can't override. */ - if (!IsSdCardInitialized()) { - return status; - } - - /* For system modules and anything launched before the home menu, always override. */ - if (program_id < ncm::SystemAppletId::Start || !pm::info::HasLaunchedBootProgram(ncm::SystemAppletId::Qlaunch)) { - status.SetProgramSpecific(); - return status; - } - - /* Unconditionally refresh override_config.ini contents. */ - RefreshOverrideConfiguration(); - - /* If we can't read the key state, don't override anything. */ - if (R_FAILED(hid::GetKeysHeld(std::addressof(status.keys_held)))) { - return status; - } - - /* Detect Hbl. */ - if (IsAnyApplicationHblProgramId(program_id) && IsOverrideMatch(status, g_hbl_override_config.override_any_app_key)) { - status.SetHbl(); - status.flags &= ~impl::OverrideStatusFlag_AddressSpaceMask; - status.flags |= g_hbl_override_config.override_any_app_as_flag; - } - for (size_t i = 0; i < MaxProgramOverrideKeys; i++) { - if (IsSpecificHblProgramId(i, program_id) && IsOverrideMatch(status, g_hbl_override_config.program_configs[i].override_key)) { - status.SetHbl(); - status.flags &= ~impl::OverrideStatusFlag_AddressSpaceMask; - status.flags |= g_hbl_override_config.program_as_flags[i]; - } - } - - /* Detect content specific keys. */ - const auto content_cfg = GetContentOverrideConfig(program_id); - if (IsOverrideMatch(status, content_cfg.override_key)) { - status.SetProgramSpecific(); - } - - /* Only allow cheat enable if not HBL. */ - if (!status.IsHbl() && IsOverrideMatch(status, content_cfg.cheat_enable_key)) { - status.SetCheatEnabled(); - } - - return status; - } - - OverrideLocale GetOverrideLocale(ncm::ProgramId program_id) { - return GetContentOverrideConfig(program_id).locale; - } - - /* HBL Configuration utilities. */ - const char *GetHblPath() { - return g_hbl_sd_path; - } - -} +#if defined(ATMOSPHERE_BOARD_NINTENDO_NX) + #include "cfg_override.board.nintendo_nx.inc" +#else + #include "cfg_override.generic.inc" +#endif \ No newline at end of file diff --git a/libraries/libstratosphere/source/cfg/cfg_override.generic.inc b/libraries/libstratosphere/source/cfg/cfg_override.generic.inc new file mode 100644 index 000000000..2d6ba4206 --- /dev/null +++ b/libraries/libstratosphere/source/cfg/cfg_override.generic.inc @@ -0,0 +1,35 @@ +/* + * Copyright (c) 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 + +namespace ams::cfg { + + OverrideStatus CaptureOverrideStatus(ncm::ProgramId program_id) { + AMS_UNUSED(program_id); + AMS_ABORT("TODO: How should this work?"); + } + + OverrideLocale GetOverrideLocale(ncm::ProgramId program_id) { + AMS_UNUSED(program_id); + AMS_ABORT("TODO: How should this work?"); + } + + /* HBL Configuration utilities. */ + const char *GetHblPath() { + AMS_ABORT("TODO: How should this work?"); + } + +} diff --git a/libraries/libstratosphere/source/cfg/cfg_sd_card.board.nintendo_nx.inc b/libraries/libstratosphere/source/cfg/cfg_sd_card.board.nintendo_nx.inc new file mode 100644 index 000000000..999f524f0 --- /dev/null +++ b/libraries/libstratosphere/source/cfg/cfg_sd_card.board.nintendo_nx.inc @@ -0,0 +1,96 @@ +/* + * Copyright (c) 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 + +namespace ams::cfg { + + namespace { + + /* Convenience definitions. */ + constexpr sm::ServiceName RequiredServicesForSdCardAccess[] = { + sm::ServiceName::Encode("pcv"), + sm::ServiceName::Encode("gpio"), + sm::ServiceName::Encode("pinmux"), + sm::ServiceName::Encode("psc:m"), + }; + constexpr size_t NumRequiredServicesForSdCardAccess = util::size(RequiredServicesForSdCardAccess); + + /* SD card globals. */ + constinit os::SdkMutex g_sd_card_lock; + constinit bool g_sd_card_initialized = false; + constinit FsFileSystem g_sd_card_filesystem = {}; + + /* SD card helpers. */ + Result CheckSdCardServicesReady() { + for (size_t i = 0; i < NumRequiredServicesForSdCardAccess; i++) { + bool service_present = false; + R_TRY(sm::HasService(std::addressof(service_present), RequiredServicesForSdCardAccess[i])); + if (!service_present) { + return fs::ResultSdCardNotPresent(); + } + } + + return ResultSuccess(); + } + + void WaitSdCardServicesReadyImpl() { + for (size_t i = 0; i < NumRequiredServicesForSdCardAccess; i++) { + R_ABORT_UNLESS(sm::WaitService(RequiredServicesForSdCardAccess[i])); + } + } + + Result TryInitializeSdCard() { + R_TRY(CheckSdCardServicesReady()); + R_ABORT_UNLESS(fsOpenSdCardFileSystem(std::addressof(g_sd_card_filesystem))); + g_sd_card_initialized = true; + return ResultSuccess(); + } + + void InitializeSdCard() { + WaitSdCardServicesReadyImpl(); + R_ABORT_UNLESS(fsOpenSdCardFileSystem(std::addressof(g_sd_card_filesystem))); + g_sd_card_initialized = true; + } + + } + + /* SD card utilities. */ + bool IsSdCardRequiredServicesReady() { + return R_SUCCEEDED(CheckSdCardServicesReady()); + } + + void WaitSdCardRequiredServicesReady() { + WaitSdCardServicesReadyImpl(); + } + + bool IsSdCardInitialized() { + std::scoped_lock lk(g_sd_card_lock); + + if (!g_sd_card_initialized) { + if (R_SUCCEEDED(TryInitializeSdCard())) { + g_sd_card_initialized = true; + } + } + return g_sd_card_initialized; + } + + void WaitSdCardInitialized() { + std::scoped_lock lk(g_sd_card_lock); + + InitializeSdCard(); + } + +} diff --git a/libraries/libstratosphere/source/cfg/cfg_sd_card.cpp b/libraries/libstratosphere/source/cfg/cfg_sd_card.cpp index 999f524f0..f3e243562 100644 --- a/libraries/libstratosphere/source/cfg/cfg_sd_card.cpp +++ b/libraries/libstratosphere/source/cfg/cfg_sd_card.cpp @@ -15,82 +15,8 @@ */ #include -namespace ams::cfg { - - namespace { - - /* Convenience definitions. */ - constexpr sm::ServiceName RequiredServicesForSdCardAccess[] = { - sm::ServiceName::Encode("pcv"), - sm::ServiceName::Encode("gpio"), - sm::ServiceName::Encode("pinmux"), - sm::ServiceName::Encode("psc:m"), - }; - constexpr size_t NumRequiredServicesForSdCardAccess = util::size(RequiredServicesForSdCardAccess); - - /* SD card globals. */ - constinit os::SdkMutex g_sd_card_lock; - constinit bool g_sd_card_initialized = false; - constinit FsFileSystem g_sd_card_filesystem = {}; - - /* SD card helpers. */ - Result CheckSdCardServicesReady() { - for (size_t i = 0; i < NumRequiredServicesForSdCardAccess; i++) { - bool service_present = false; - R_TRY(sm::HasService(std::addressof(service_present), RequiredServicesForSdCardAccess[i])); - if (!service_present) { - return fs::ResultSdCardNotPresent(); - } - } - - return ResultSuccess(); - } - - void WaitSdCardServicesReadyImpl() { - for (size_t i = 0; i < NumRequiredServicesForSdCardAccess; i++) { - R_ABORT_UNLESS(sm::WaitService(RequiredServicesForSdCardAccess[i])); - } - } - - Result TryInitializeSdCard() { - R_TRY(CheckSdCardServicesReady()); - R_ABORT_UNLESS(fsOpenSdCardFileSystem(std::addressof(g_sd_card_filesystem))); - g_sd_card_initialized = true; - return ResultSuccess(); - } - - void InitializeSdCard() { - WaitSdCardServicesReadyImpl(); - R_ABORT_UNLESS(fsOpenSdCardFileSystem(std::addressof(g_sd_card_filesystem))); - g_sd_card_initialized = true; - } - - } - - /* SD card utilities. */ - bool IsSdCardRequiredServicesReady() { - return R_SUCCEEDED(CheckSdCardServicesReady()); - } - - void WaitSdCardRequiredServicesReady() { - WaitSdCardServicesReadyImpl(); - } - - bool IsSdCardInitialized() { - std::scoped_lock lk(g_sd_card_lock); - - if (!g_sd_card_initialized) { - if (R_SUCCEEDED(TryInitializeSdCard())) { - g_sd_card_initialized = true; - } - } - return g_sd_card_initialized; - } - - void WaitSdCardInitialized() { - std::scoped_lock lk(g_sd_card_lock); - - InitializeSdCard(); - } - -} +#if defined(ATMOSPHERE_BOARD_NINTENDO_NX) + #include "cfg_sd_card.board.nintendo_nx.inc" +#else + #include "cfg_sd_card.generic.inc" +#endif \ No newline at end of file diff --git a/libraries/libstratosphere/source/cfg/cfg_sd_card.generic.inc b/libraries/libstratosphere/source/cfg/cfg_sd_card.generic.inc new file mode 100644 index 000000000..acc0e42e9 --- /dev/null +++ b/libraries/libstratosphere/source/cfg/cfg_sd_card.generic.inc @@ -0,0 +1,36 @@ +/* + * Copyright (c) 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 + +namespace ams::cfg { + + bool IsSdCardRequiredServicesReady() { + return true; + } + + void WaitSdCardRequiredServicesReady() { + /* ... */ + } + + bool IsSdCardInitialized() { + return true; + } + + void WaitSdCardInitialized() { + /* ... */ + } + +} diff --git a/libraries/libstratosphere/source/dd/impl/dd_device_address_space_impl.generic.hpp b/libraries/libstratosphere/source/dd/impl/dd_device_address_space_impl.generic.hpp new file mode 100644 index 000000000..9d2f77318 --- /dev/null +++ b/libraries/libstratosphere/source/dd/impl/dd_device_address_space_impl.generic.hpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 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::impl { + + class DeviceAddressSpaceImplByWindows { + public: + static Result Create(DeviceAddressSpaceHandle *, u64, u64) { + R_THROW(dd::ResultNotSupported()); + } + + static void Close(DeviceAddressSpaceHandle) { + /* ... */ + } + + static Result MapAligned(DeviceAddressSpaceHandle, ProcessHandle, u64, size_t, DeviceVirtualAddress, dd::MemoryPermission) { + R_THROW(dd::ResultNotSupported()); + } + + static Result MapNotAligned(DeviceAddressSpaceHandle, ProcessHandle, u64, size_t, DeviceVirtualAddress, dd::MemoryPermission) { + R_THROW(dd::ResultNotSupported()); + } + + static void Unmap(DeviceAddressSpaceHandle, ProcessHandle, u64, size_t, DeviceVirtualAddress) { + /* ... */ + } + + static Result Attach(DeviceAddressSpaceType *, DeviceName) { + R_THROW(dd::ResultNotSupported()); + } + + static void Detach(DeviceAddressSpaceType *, DeviceName) { + /* ... */ + } + }; + + using DeviceAddressSpaceImpl = DeviceAddressSpaceImplByWindows; + +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/dd/impl/dd_device_address_space_impl.hpp b/libraries/libstratosphere/source/dd/impl/dd_device_address_space_impl.hpp index 136389206..92611be8b 100644 --- a/libraries/libstratosphere/source/dd/impl/dd_device_address_space_impl.hpp +++ b/libraries/libstratosphere/source/dd/impl/dd_device_address_space_impl.hpp @@ -19,5 +19,5 @@ #if defined(ATMOSPHERE_OS_HORIZON) #include "dd_device_address_space_impl.os.horizon.hpp" #else - #error "Unknown os for dd::DeviceAddressSpaceImpl" + #include "dd_device_address_space_impl.generic.hpp" #endif diff --git a/libraries/libstratosphere/source/diag/diag_assertion_impl.cpp b/libraries/libstratosphere/source/diag/diag_assertion_impl.cpp index a41f6468b..537ccedd7 100644 --- a/libraries/libstratosphere/source/diag/diag_assertion_impl.cpp +++ b/libraries/libstratosphere/source/diag/diag_assertion_impl.cpp @@ -14,12 +14,14 @@ * along with this program. If not, see . */ #include +#include "impl/diag_print_debug_string.hpp" namespace ams::diag { namespace { inline NORETURN void AbortWithValue(u64 debug) { + #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) /* Just perform a data abort. */ register u64 addr __asm__("x27") = FatalErrorContext::StdAbortMagicAddress; register u64 val __asm__("x28") = FatalErrorContext::StdAbortMagicValue; @@ -32,6 +34,10 @@ namespace ams::diag { : "x0" ); } + #else + AMS_UNUSED(debug); + std::abort(); + #endif __builtin_unreachable(); } @@ -46,7 +52,7 @@ namespace ams::diag { util::VSNPrintf(g_debug_buffer, sizeof(g_debug_buffer), format, vl); - svc::OutputDebugString(g_debug_buffer, strlen(g_debug_buffer)); + diag::impl::PrintDebugString(g_debug_buffer, strlen(g_debug_buffer)); } void DebugLog(const char *format, ...) { @@ -62,8 +68,12 @@ namespace ams::diag { } - NORETURN WEAK_SYMBOL void AssertionFailureImpl(const char *file, int line, const char *func, const char *expr, u64 value, const char *format, ...) { - DebugLog("%016lx: Assertion Failure\n", os::GetCurrentProgramId().value); + NORETURN NOINLINE WEAK_SYMBOL void AssertionFailureImpl(const char *file, int line, const char *func, const char *expr, u64 value, const char *format, ...) { + #if defined(ATMOSPHERE_OS_HORIZON) + DebugLog("%016" PRIx64 ": Assertion Failure\n", os::GetCurrentProgramId().value); + #else + DebugLog("0100000000000000: Assertion Failure\n"); + #endif DebugLog(" Location: %s:%d\n", file, line); DebugLog(" Function: %s\n", func); DebugLog(" Expression: %s\n", expr); @@ -84,8 +94,12 @@ namespace ams::diag { AbortWithValue(value); } - NORETURN WEAK_SYMBOL void AssertionFailureImpl(const char *file, int line, const char *func, const char *expr, u64 value) { - DebugLog("%016lx: Assertion Failure\n", os::GetCurrentProgramId().value); + NORETURN NOINLINE WEAK_SYMBOL void AssertionFailureImpl(const char *file, int line, const char *func, const char *expr, u64 value) { + #if defined(ATMOSPHERE_OS_HORIZON) + DebugLog("%016" PRIx64 ": Assertion Failure\n", os::GetCurrentProgramId().value); + #else + DebugLog("0100000000000000: Assertion Failure\n"); + #endif DebugLog(" Location: %s:%d\n", file, line); DebugLog(" Function: %s\n", func); DebugLog(" Expression: %s\n", expr); @@ -96,8 +110,12 @@ namespace ams::diag { AbortWithValue(value); } - NORETURN WEAK_SYMBOL void AbortImpl(const char *file, int line, const char *func, const char *expr, u64 value, const char *format, ...) { - DebugLog("%016lx: Abort Called\n", os::GetCurrentProgramId().value); + NORETURN NOINLINE WEAK_SYMBOL void AbortImpl(const char *file, int line, const char *func, const char *expr, u64 value, const char *format, ...) { + #if defined(ATMOSPHERE_OS_HORIZON) + DebugLog("%016" PRIx64 ": Abort Called\n", os::GetCurrentProgramId().value); + #else + DebugLog("0100000000000000: Abort Called\n"); + #endif DebugLog(" Location: %s:%d\n", file, line); DebugLog(" Function: %s\n", func); DebugLog(" Expression: %s\n", expr); @@ -118,8 +136,12 @@ namespace ams::diag { AbortWithValue(value); } - NORETURN WEAK_SYMBOL void AbortImpl(const char *file, int line, const char *func, const char *expr, u64 value) { - DebugLog("%016lx: Abort Called\n", os::GetCurrentProgramId().value); + NORETURN NOINLINE WEAK_SYMBOL void AbortImpl(const char *file, int line, const char *func, const char *expr, u64 value) { + #if defined(ATMOSPHERE_OS_HORIZON) + DebugLog("%016" PRIx64 ": Abort Called\n", os::GetCurrentProgramId().value); + #else + DebugLog("0100000000000000: Abort Called\n"); + #endif DebugLog(" Location: %s:%d\n", file, line); DebugLog(" Function: %s\n", func); DebugLog(" Expression: %s\n", expr); @@ -130,7 +152,7 @@ namespace ams::diag { AbortWithValue(value); } - NORETURN WEAK_SYMBOL void AbortImpl() { + NORETURN NOINLINE WEAK_SYMBOL void AbortImpl() { AbortWithValue(0); } diff --git a/libraries/libstratosphere/source/diag/diag_assertion_impl_for_nx_asm.board.nintendo_nx.s b/libraries/libstratosphere/source/diag/diag_assertion_impl_for_nx_asm.board.nintendo_nx.s new file mode 100644 index 000000000..e29c989fe --- /dev/null +++ b/libraries/libstratosphere/source/diag/diag_assertion_impl_for_nx_asm.board.nintendo_nx.s @@ -0,0 +1,37 @@ +/* + * Copyright (c) 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 . + */ + +/* ams::diag::impl::FatalErrorByResultForNx(Result value) */ +.section .text._ZN3ams4diag4impl23FatalErrorByResultForNxENS_6ResultE, "ax", %progbits +.global _ZN3ams4diag4impl23FatalErrorByResultForNxENS_6ResultE +.type _ZN3ams4diag4impl23FatalErrorByResultForNxENS_6ResultE, %function +.balign 0x10 +_ZN3ams4diag4impl23FatalErrorByResultForNxENS_6ResultE: + /* Save x27/x28. */ + stp x27, x28, [sp, #0x10] + + /* Put magic std::abort values into x27/x28. */ + mov x28, #0xcafe + movk x28, #0xdead, lsl#16 + movk x28, #0xf00d, lsl#32 + movk x28, #0xa55a, lsl#48 + mov x27, #8 + + /* Abort */ +0: + str x28, [x27] + nop + b 0b diff --git a/libraries/libstratosphere/source/diag/impl/diag_print_debug_string.hpp b/libraries/libstratosphere/source/diag/impl/diag_print_debug_string.hpp index bc915ae21..a112e8429 100644 --- a/libraries/libstratosphere/source/diag/impl/diag_print_debug_string.hpp +++ b/libraries/libstratosphere/source/diag/impl/diag_print_debug_string.hpp @@ -19,6 +19,11 @@ namespace ams::diag::impl { void PrintDebugString(const char *msg, size_t size); - void PrintDebugString(const char *msg); + + inline void PrintDebugString(const char *msg) { + AMS_AUDIT(msg != nullptr); + + PrintDebugString(msg, std::strlen(msg)); + } } diff --git a/libraries/libstratosphere/source/diag/impl/diag_print_debug_string.os.horizon.cpp b/libraries/libstratosphere/source/diag/impl/diag_print_debug_string.os.horizon.cpp index 154183eed..55bbcb931 100644 --- a/libraries/libstratosphere/source/diag/impl/diag_print_debug_string.os.horizon.cpp +++ b/libraries/libstratosphere/source/diag/impl/diag_print_debug_string.os.horizon.cpp @@ -26,10 +26,4 @@ namespace ams::diag::impl { } } - void PrintDebugString(const char *msg) { - AMS_AUDIT(msg != nullptr); - - PrintDebugString(msg, std::strlen(msg)); - } - } diff --git a/libraries/libstratosphere/source/diag/impl/diag_print_debug_string.os.linux.cpp b/libraries/libstratosphere/source/diag/impl/diag_print_debug_string.os.linux.cpp new file mode 100644 index 000000000..2168e2d3b --- /dev/null +++ b/libraries/libstratosphere/source/diag/impl/diag_print_debug_string.os.linux.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 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 "diag_print_debug_string.hpp" + +namespace ams::diag::impl { + + NOINLINE void PrintDebugString(const char *msg, size_t size) { + AMS_AUDIT(msg != nullptr || size == 0); + + if (size == 0) { + return; + } + + /* TODO: Printf? */ + printf("%s", msg); + } + +} diff --git a/libraries/libstratosphere/source/diag/impl/diag_print_debug_string.os.macos.cpp b/libraries/libstratosphere/source/diag/impl/diag_print_debug_string.os.macos.cpp new file mode 100644 index 000000000..2168e2d3b --- /dev/null +++ b/libraries/libstratosphere/source/diag/impl/diag_print_debug_string.os.macos.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 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 "diag_print_debug_string.hpp" + +namespace ams::diag::impl { + + NOINLINE void PrintDebugString(const char *msg, size_t size) { + AMS_AUDIT(msg != nullptr || size == 0); + + if (size == 0) { + return; + } + + /* TODO: Printf? */ + printf("%s", msg); + } + +} diff --git a/libraries/libstratosphere/source/diag/impl/diag_print_debug_string.os.windows.cpp b/libraries/libstratosphere/source/diag/impl/diag_print_debug_string.os.windows.cpp new file mode 100644 index 000000000..49105fffd --- /dev/null +++ b/libraries/libstratosphere/source/diag/impl/diag_print_debug_string.os.windows.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 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 "diag_print_debug_string.hpp" + +namespace ams::diag::impl { + + NOINLINE void PrintDebugString(const char *msg, size_t size) { + AMS_AUDIT(msg != nullptr || size == 0); + + if (size == 0) { + return; + } + + /* TODO: OutputDebugString? Printf? */ + printf("%s", msg); + } + +} diff --git a/libraries/libstratosphere/source/dmnt/dmntcht.c b/libraries/libstratosphere/source/dmnt/dmntcht.os.horizon.c similarity index 100% rename from libraries/libstratosphere/source/dmnt/dmntcht.c rename to libraries/libstratosphere/source/dmnt/dmntcht.os.horizon.c diff --git a/libraries/libstratosphere/source/erpt/srv/erpt_srv_journal_for_meta.cpp b/libraries/libstratosphere/source/erpt/srv/erpt_srv_journal_for_meta.cpp index 09337fdcd..254c3abd9 100644 --- a/libraries/libstratosphere/source/erpt/srv/erpt_srv_journal_for_meta.cpp +++ b/libraries/libstratosphere/source/erpt/srv/erpt_srv_journal_for_meta.cpp @@ -18,7 +18,7 @@ namespace ams::erpt::srv { - constinit JournalMeta JournalForMeta::s_journal_meta; + constinit JournalMeta JournalForMeta::s_journal_meta = {}; void JournalForMeta::InitializeJournal() { std::memset(std::addressof(s_journal_meta), 0, sizeof(s_journal_meta)); diff --git a/libraries/libstratosphere/source/erpt/srv/erpt_srv_main.cpp b/libraries/libstratosphere/source/erpt/srv/erpt_srv_main.cpp index abb90d897..2ad3d8005 100644 --- a/libraries/libstratosphere/source/erpt/srv/erpt_srv_main.cpp +++ b/libraries/libstratosphere/source/erpt/srv/erpt_srv_main.cpp @@ -25,7 +25,7 @@ namespace ams::erpt::srv { constinit lmem::HeapHandle g_heap_handle; - constinit ams::sf::ExpHeapAllocator g_sf_allocator; + constinit ams::sf::ExpHeapAllocator g_sf_allocator = {}; namespace { diff --git a/libraries/libstratosphere/source/erpt/srv/erpt_srv_reporter.cpp b/libraries/libstratosphere/source/erpt/srv/erpt_srv_reporter.cpp index fa6112afa..1cd23a0c8 100644 --- a/libraries/libstratosphere/source/erpt/srv/erpt_srv_reporter.cpp +++ b/libraries/libstratosphere/source/erpt/srv/erpt_srv_reporter.cpp @@ -33,9 +33,6 @@ namespace ams::erpt::srv { namespace { - constinit os::SdkMutex g_limit_mutex; - constinit bool g_submitted_limit = false; - class AppletActiveTimeInfoList { private: struct AppletActiveTimeInfo { @@ -91,6 +88,7 @@ namespace ams::erpt::srv { constinit AppletActiveTimeInfoList g_applet_active_time_info_list; + #if defined(ATMOSPHERE_OS_HORIZON) Result PullErrorContext(size_t *out_total_size, size_t *out_size, void *dst, size_t dst_size, const err::ContextDescriptor &descriptor, Result result) { s32 unk0; u32 total_size, size; @@ -135,6 +133,9 @@ namespace ams::erpt::srv { record->Add(FieldId_ErrorContext, error_context, error_context_size); } + constinit os::SdkMutex g_limit_mutex; + constinit bool g_submitted_limit = false; + void SubmitResourceLimitLimitContext() { std::scoped_lock lk(g_limit_mutex); if (g_submitted_limit) { @@ -222,6 +223,11 @@ namespace ams::erpt::srv { SubmitResourceLimitLimitContext(); SubmitResourceLimitPeakContext(); } + #else + void SubmitErrorContext(ContextRecord *record, Result result) { + AMS_UNUSED(record, result); + } + #endif Result ValidateCreateReportContext(const ContextEntry *ctx) { R_UNLESS(ctx->category == CategoryId_ErrorInfo, erpt::ResultRequiredContextMissing()); @@ -520,7 +526,9 @@ namespace ams::erpt::srv { R_TRY(Context::SubmitContextRecord(std::move(record))); /* Submit context for resource limits. */ + #if defined(ATMOSPHERE_OS_HORIZON) SubmitResourceLimitContexts(); + #endif return ResultSuccess(); } diff --git a/libraries/libstratosphere/source/erpt/srv/erpt_srv_service.cpp b/libraries/libstratosphere/source/erpt/srv/erpt_srv_service.cpp index 083c661c2..df52d8e3c 100644 --- a/libraries/libstratosphere/source/erpt/srv/erpt_srv_service.cpp +++ b/libraries/libstratosphere/source/erpt/srv/erpt_srv_service.cpp @@ -138,7 +138,7 @@ namespace ams::erpt::srv { } } - constinit util::TypedStorage g_erpt_server_manager; + constinit util::TypedStorage g_erpt_server_manager = {}; } diff --git a/libraries/libstratosphere/source/err/err_api.cpp b/libraries/libstratosphere/source/err/err_api.cpp index d8afcea6f..81c693eb0 100644 --- a/libraries/libstratosphere/source/err/err_api.cpp +++ b/libraries/libstratosphere/source/err/err_api.cpp @@ -31,7 +31,7 @@ namespace ams::err { }; } - ALWAYS_INLINE Result ConvertErrorCodeToResult(const ErrorCode &error_code) { + [[maybe_unused]] ALWAYS_INLINE Result ConvertErrorCodeToResult(const ErrorCode &error_code) { const auto result_value = ::ams::result::impl::ResultTraits::MakeValue(error_code.category - ErrorCodeCategoryPlatformPrefixForResultModule, error_code.number); return ::ams::result::impl::MakeResult(result_value); } diff --git a/libraries/libstratosphere/source/fs/common/fs_file_storage.cpp b/libraries/libstratosphere/source/fs/common/fs_file_storage.cpp index c4426b224..20b53317e 100644 --- a/libraries/libstratosphere/source/fs/common/fs_file_storage.cpp +++ b/libraries/libstratosphere/source/fs/common/fs_file_storage.cpp @@ -90,7 +90,7 @@ namespace ams::fs { } } - Result FileStorageBasedFileSystem::Initialize(std::shared_ptr base_file_system, const char *path, fs::OpenMode mode) { + Result FileStorageBasedFileSystem::Initialize(std::shared_ptr base_file_system, const fs::Path &path, fs::OpenMode mode) { /* Open the file. */ std::unique_ptr base_file; R_TRY(base_file_system->OpenFile(std::addressof(base_file), path, mode)); diff --git a/libraries/libstratosphere/source/fs/fs_access_log.cpp b/libraries/libstratosphere/source/fs/fs_access_log.cpp index 981e33f1f..c665aa497 100644 --- a/libraries/libstratosphere/source/fs/fs_access_log.cpp +++ b/libraries/libstratosphere/source/fs/fs_access_log.cpp @@ -14,6 +14,7 @@ * along with this program. If not, see . */ #include +#include "impl/fs_file_system_proxy_service_object.hpp" #include "fsa/fs_user_mount_table.hpp" #include "fsa/fs_directory_accessor.hpp" #include "fsa/fs_file_accessor.hpp" @@ -21,7 +22,7 @@ #define AMS_FS_IMPL_ACCESS_LOG_AMS_API_VERSION "ams_version: " STRINGIZE(ATMOSPHERE_RELEASE_VERSION_MAJOR) "." STRINGIZE(ATMOSPHERE_RELEASE_VERSION_MINOR) "." STRINGIZE(ATMOSPHERE_RELEASE_VERSION_MICRO) -/* TODO: Other boards? */ +/* TODO: Other specs? */ #define AMS_FS_IMPL_ACCESS_LOG_SPEC "spec: NX" namespace ams::fs { @@ -48,13 +49,15 @@ namespace ams::fs { } Result GetGlobalAccessLogMode(u32 *out) { - /* Use libnx bindings. */ - return ::fsGetGlobalAccessLogMode(out); + const auto fsp = impl::GetFileSystemProxyServiceObject(); + AMS_FS_R_TRY(fsp->GetGlobalAccessLogMode(out)); + R_SUCCEED(); } Result SetGlobalAccessLogMode(u32 mode) { - /* Use libnx bindings. */ - return ::fsSetGlobalAccessLogMode(mode); + const auto fsp = impl::GetFileSystemProxyServiceObject(); + AMS_FS_R_TRY(fsp->SetGlobalAccessLogMode(mode)); + R_SUCCEED(); } void SetLocalAccessLog(bool enabled) { @@ -167,6 +170,15 @@ namespace ams::fs::impl { } } + template<> const char *IdString::ToString(fs::GameCardPartition id) { + switch (id) { + case fs::GameCardPartition::Update: return "Update"; + case fs::GameCardPartition::Normal: return "Normal"; + case fs::GameCardPartition::Secure: return "Secure"; + default: return ToValueString(static_cast(id)); + } + } + namespace { class AccessLogPrinterCallbackManager { @@ -199,8 +211,9 @@ namespace ams::fs::impl { } Result OutputAccessLogToSdCardImpl(const char *log, size_t size) { - /* Use libnx bindings. */ - return ::fsOutputAccessLogToSdCard(log, size); + const auto fsp = impl::GetFileSystemProxyServiceObject(); + AMS_FS_R_TRY(fsp->OutputAccessLogToSdCard(sf::InBuffer(log, size))); + R_SUCCEED(); } void OutputAccessLogToSdCard(const char *format, std::va_list vl) { @@ -291,10 +304,11 @@ namespace ams::fs::impl { OutputAccessLogImpl(log_buffer.get(), log_buffer_size); } - void GetProgramIndexFortAccessLog(u32 *out_index, u32 *out_count) { + void GetProgramIndexForAccessLog(u32 *out_index, u32 *out_count) { if (hos::GetVersion() >= hos::Version_7_0_0) { /* Use libnx bindings if available. */ - R_ABORT_UNLESS(::fsGetProgramIndexForAccessLog(out_index, out_count)); + const auto fsp = impl::GetFileSystemProxyServiceObject(); + R_ABORT_UNLESS(fsp->GetProgramIndexForAccessLog(out_index, out_count)); } else { /* Use hardcoded defaults. */ *out_index = 0; @@ -305,7 +319,7 @@ namespace ams::fs::impl { void OutputAccessLogStart() { /* Get the program index. */ u32 program_index = 0, program_count = 0; - GetProgramIndexFortAccessLog(std::addressof(program_index), std::addressof(program_count)); + GetProgramIndexForAccessLog(std::addressof(program_index), std::addressof(program_count)); /* Print the log buffer. */ if (program_count < 2) { diff --git a/libraries/libstratosphere/source/fs/fs_api.cpp b/libraries/libstratosphere/source/fs/fs_api.cpp index c9d8ce726..f04e3049b 100644 --- a/libraries/libstratosphere/source/fs/fs_api.cpp +++ b/libraries/libstratosphere/source/fs/fs_api.cpp @@ -14,25 +14,182 @@ * along with this program. If not, see . */ #include - -extern "C" { - - extern u32 __nx_fs_num_sessions; - -} +#include "fs_remote_file_system_proxy.hpp" +#include "fs_remote_file_system_proxy_for_loader.hpp" +#include "impl/fs_library.hpp" namespace ams::fs { - /* TODO: FileSystemProxySessionSetting */ + #if defined(ATMOSPHERE_OS_HORIZON) + namespace { + + constinit std::aligned_storage_t<0x80> g_fsp_service_object_buffer; + constinit std::aligned_storage_t<0x80> g_fsp_ldr_service_object_buffer; + constinit bool g_use_static_fsp_service_object_buffer = false; + constinit bool g_use_static_fsp_ldr_service_object_buffer = false; + + class HipcClientAllocator { + public: + using Policy = sf::StatelessAllocationPolicy; + public: + constexpr HipcClientAllocator() = default; + + void *Allocate(size_t size) { + if (g_use_static_fsp_service_object_buffer) { + return std::addressof(g_fsp_service_object_buffer); + } else if (g_use_static_fsp_ldr_service_object_buffer) { + return std::addressof(g_fsp_ldr_service_object_buffer); + } else { + return ::ams::fs::impl::Allocate(size); + } + } + + void Deallocate(void *ptr, size_t size) { + if (ptr == std::addressof(g_fsp_service_object_buffer)) { + return; + } else if (ptr == std::addressof(g_fsp_ldr_service_object_buffer)) { + return; + } else { + return ::ams::fs::impl::Deallocate(ptr, size); + } + } + }; + + enum class FileSystemProxySessionSetting { + SystemNormal = 0, + Application = 1, + SystemMulti = 2, + }; + + constexpr ALWAYS_INLINE int GetSessionCount(FileSystemProxySessionSetting setting) { + switch (setting) { + case FileSystemProxySessionSetting::Application: return 3; + case FileSystemProxySessionSetting::SystemNormal: return 1; + case FileSystemProxySessionSetting::SystemMulti: return 2; + AMS_UNREACHABLE_DEFAULT_CASE(); + } + } + + constinit bool g_is_fsp_object_initialized = false; + constinit FileSystemProxySessionSetting g_fsp_session_setting = FileSystemProxySessionSetting::SystemNormal; + + /* TODO: SessionResourceManager */ + + } + #endif + + namespace { + + constinit sf::SharedPointer g_fsp_service_object; + + sf::SharedPointer GetFileSystemProxyServiceObjectImpl() { + /* Ensure the library is initialized. */ + ::ams::fs::impl::InitializeFileSystemLibrary(); + + sf::SharedPointer fsp_object; + + #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) && defined(ATMOSPHERE_OS_HORIZON) + /* Try to use the custom object. */ + fsp_object = g_fsp_service_object; + + /* If we don't have one, create a remote object. */ + if (fsp_object == nullptr) { + /* Make our next allocation use our static reserved buffer for the service object. */ + g_use_static_fsp_service_object_buffer = true; + ON_SCOPE_EXIT { g_use_static_fsp_service_object_buffer = false; }; + + using ObjectFactory = sf::ObjectFactory; + + /* Create the object. */ + fsp_object = ObjectFactory::CreateSharedEmplaced(GetSessionCount(g_fsp_session_setting)); + AMS_ABORT_UNLESS(fsp_object != nullptr); + + /* Set the current process. */ + fsp_object->SetCurrentProcess({}); + } + #else + /* On non-horizon, use the system object. */ + fsp_object = fssrv::impl::GetFileSystemProxyServiceObject(); + AMS_ABORT_UNLESS(fsp_object != nullptr); + + /* Set the current process. */ + fsp_object->SetCurrentProcess({}); + #endif + + + /* Return the object. */ + return fsp_object; + } + + sf::SharedPointer GetFileSystemProxyForLoaderServiceObjectImpl() { + /* Ensure the library is initialized. */ + ::ams::fs::impl::InitializeFileSystemLibrary(); + + sf::SharedPointer fsp_ldr_object; + + #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) && defined(ATMOSPHERE_OS_HORIZON) + /* Make our next allocation use our static reserved buffer for the service object. */ + g_use_static_fsp_ldr_service_object_buffer = true; + ON_SCOPE_EXIT { g_use_static_fsp_ldr_service_object_buffer = false; }; + + using ObjectFactory = sf::ObjectFactory; + + /* Create the object. */ + fsp_ldr_object = ObjectFactory::CreateSharedEmplaced(); + AMS_ABORT_UNLESS(fsp_ldr_object != nullptr); + #else + /* On non-horizon, use the system object. */ + fsp_ldr_object = fssrv::impl::GetFileSystemProxyForLoaderServiceObject(); + AMS_ABORT_UNLESS(fsp_ldr_object != nullptr); + #endif + + /* Return the object. */ + return fsp_ldr_object; + } + + } + + namespace impl { + + sf::SharedPointer GetFileSystemProxyServiceObject() { + AMS_FUNCTION_LOCAL_STATIC(sf::SharedPointer, s_fsp_service_object, GetFileSystemProxyServiceObjectImpl()); + return s_fsp_service_object; + } + + sf::SharedPointer GetFileSystemProxyForLoaderServiceObject() { + AMS_FUNCTION_LOCAL_STATIC(sf::SharedPointer, s_fsp_ldr_service_object, GetFileSystemProxyForLoaderServiceObjectImpl()); + return s_fsp_ldr_service_object; + } + + } + + void InitializeForHostTool() { + #if !defined(ATMOSPHERE_OS_HORIZON) + AMS_ABORT_UNLESS(impl::GetFileSystemProxyServiceObject() != nullptr); + R_ABORT_UNLESS(::ams::fs::MountHostRoot()); + #endif + } void InitializeForSystem() { - __nx_fs_num_sessions = 1; - R_ABORT_UNLESS(::fsInitialize()); + #if defined(ATMOSPHERE_OS_HORIZON) + AMS_ABORT_UNLESS(!g_is_fsp_object_initialized); + AMS_ABORT_UNLESS(g_fsp_session_setting == FileSystemProxySessionSetting::SystemNormal); + g_fsp_session_setting = FileSystemProxySessionSetting::SystemNormal; + + /* Nintendo doesn't do this, but we have to for timing reasons. */ + AMS_ABORT_UNLESS(impl::GetFileSystemProxyServiceObject() != nullptr); + #endif } void InitializeWithMultiSessionForSystem() { - __nx_fs_num_sessions = 2; - R_ABORT_UNLESS(::fsInitialize()); + #if defined(ATMOSPHERE_OS_HORIZON) + AMS_ABORT_UNLESS(!g_is_fsp_object_initialized); + AMS_ABORT_UNLESS(g_fsp_session_setting == FileSystemProxySessionSetting::SystemNormal); + g_fsp_session_setting = FileSystemProxySessionSetting::SystemMulti; + + /* Nintendo doesn't do this, but we have to for timing reasons. */ + AMS_ABORT_UNLESS(impl::GetFileSystemProxyServiceObject() != nullptr); + #endif } } diff --git a/libraries/libstratosphere/source/fs/fs_application.cpp b/libraries/libstratosphere/source/fs/fs_application.cpp index 996b88121..ec6f0ef3c 100644 --- a/libraries/libstratosphere/source/fs/fs_application.cpp +++ b/libraries/libstratosphere/source/fs/fs_application.cpp @@ -15,26 +15,43 @@ */ #include #include "fsa/fs_mount_utils.hpp" +#include "impl/fs_file_system_service_object_adapter.hpp" +#include "impl/fs_file_system_proxy_service_object.hpp" namespace ams::fs { Result MountApplicationPackage(const char *name, const char *common_path) { - /* Validate the mount name. */ - R_TRY(impl::CheckMountName(name)); + auto mount_impl = [=]() -> Result { + /* Validate the mount name. */ + R_TRY(impl::CheckMountName(name)); - /* Validate the path. */ - R_UNLESS(common_path != nullptr, fs::ResultInvalidPath()); + /* Validate the path. */ + R_UNLESS(common_path != nullptr, fs::ResultInvalidPath()); - /* Open a filesystem using libnx bindings. */ - FsFileSystem fs; - R_TRY(fsOpenFileSystemWithId(std::addressof(fs), ncm::InvalidProgramId.value, static_cast<::FsFileSystemType>(impl::FileSystemProxyType_Package), common_path)); + /* Convert the path for ipc. */ + fssrv::sf::FspPath sf_path; + R_TRY(fs::ConvertToFspPath(std::addressof(sf_path), common_path)); - /* Allocate a new filesystem wrapper. */ - auto fsa = std::make_unique(fs); - R_UNLESS(fsa != nullptr, fs::ResultAllocationFailureInApplicationA()); + /* Open the filesystem. */ + auto fsp = impl::GetFileSystemProxyServiceObject(); + sf::SharedPointer fs; + R_TRY(fsp->OpenFileSystemWithId(std::addressof(fs), sf_path, ncm::InvalidProgramId.value, impl::FileSystemProxyType_Package)); - /* Register. */ - return fsa::Register(name, std::move(fsa)); + /* Allocate a new filesystem wrapper. */ + auto fsa = std::make_unique(std::move(fs)); + R_UNLESS(fsa != nullptr, fs::ResultAllocationFailureInApplicationA()); + + /* Register. */ + R_RETURN(fsa::Register(name, std::move(fsa))); + }; + + /* Perform the mount. */ + AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(mount_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_APPLICATION_PACKAGE(name, common_path))); + + /* Enable access logging. */ + AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name); + + R_SUCCEED(); } } diff --git a/libraries/libstratosphere/source/fs/fs_bis.cpp b/libraries/libstratosphere/source/fs/fs_bis.cpp index 8073d9cd1..f85d403b4 100644 --- a/libraries/libstratosphere/source/fs/fs_bis.cpp +++ b/libraries/libstratosphere/source/fs/fs_bis.cpp @@ -15,6 +15,9 @@ */ #include #include "fsa/fs_mount_utils.hpp" +#include "impl/fs_file_system_service_object_adapter.hpp" +#include "impl/fs_storage_service_object_adapter.hpp" +#include "impl/fs_file_system_proxy_service_object.hpp" namespace ams::fs { @@ -46,43 +49,45 @@ namespace ams::fs { namespace impl { Result MountBisImpl(const char *name, BisPartitionId id, const char *root_path) { - /* Validate the mount name. */ - R_TRY(impl::CheckMountNameAllowingReserved(name)); + auto mount_impl = [=]() -> Result { + /* Validate the mount name. */ + R_TRY(impl::CheckMountNameAllowingReserved(name)); - /* Open the partition. This uses libnx bindings. */ - /* NOTE: Nintendo ignores the root_path here. */ - AMS_UNUSED(root_path); - FsFileSystem fs; - R_TRY(fsOpenBisFileSystem(std::addressof(fs), static_cast<::FsBisPartitionId>(id), "")); + /* Convert the path for ipc. */ + /* NOTE: Nintendo ignores the root_path here. */ + fssrv::sf::FspPath sf_path; + sf_path.str[0] = '\x00'; + AMS_UNUSED(root_path); - /* Allocate a new mountname generator. */ - auto generator = std::make_unique(id); - R_UNLESS(generator != nullptr, fs::ResultAllocationFailureInBisA()); + /* Open the filesystem. */ + auto fsp = impl::GetFileSystemProxyServiceObject(); + sf::SharedPointer fs; + R_TRY(fsp->OpenBisFileSystem(std::addressof(fs), sf_path, static_cast(id))); - /* Allocate a new filesystem wrapper. */ - auto fsa = std::make_unique(fs); - R_UNLESS(fsa != nullptr, fs::ResultAllocationFailureInBisB()); + /* Allocate a new mountname generator. */ + auto generator = std::make_unique(id); + R_UNLESS(generator != nullptr, fs::ResultAllocationFailureInBisA()); - /* Register. */ - return fsa::Register(name, std::move(fsa), std::move(generator)); + /* Allocate a new filesystem wrapper. */ + auto fsa = std::make_unique(std::move(fs)); + R_UNLESS(fsa != nullptr, fs::ResultAllocationFailureInBisB()); + + /* Register. */ + R_RETURN(fsa::Register(name, std::move(fsa), std::move(generator))); + }; + + /* Perform the mount. */ + AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(mount_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_BIS(name, id, root_path))); + + /* Enable access logging. */ + AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name); + + R_SUCCEED(); } Result SetBisRootForHostImpl(BisPartitionId id, const char *root_path) { - /* Ensure the path isn't too long. */ - size_t len = strnlen(root_path, fs::EntryNameLengthMax + 1); - R_UNLESS(len <= fs::EntryNameLengthMax, fs::ResultTooLongPath()); - - fssrv::sf::Path sf_path; - if (len > 0) { - const bool ending_sep = PathNormalizer::IsSeparator(root_path[len - 1]); - FspPathPrintf(std::addressof(sf_path), "%s%s", root_path, ending_sep ? "" : "/"); - } else { - sf_path.str[0] = '\x00'; - } - - /* TODO: Libnx binding for fsSetBisRootForHost */ - AMS_UNUSED(id); - AMS_ABORT(); + AMS_UNUSED(id, root_path); + AMS_ABORT("TODO"); } } @@ -110,21 +115,23 @@ namespace ams::fs { } Result OpenBisPartition(std::unique_ptr *out, BisPartitionId id) { - /* Open the partition. This uses libnx bindings. */ - FsStorage s; - R_TRY(fsOpenBisStorage(std::addressof(s), static_cast<::FsBisPartitionId>(id))); + /* Open the partition. */ + auto fsp = impl::GetFileSystemProxyServiceObject(); + sf::SharedPointer s; + AMS_FS_R_TRY(fsp->OpenBisStorage(std::addressof(s), static_cast(id))); /* Allocate a new storage wrapper. */ - auto storage = std::make_unique(s); - R_UNLESS(storage != nullptr, fs::ResultAllocationFailureInBisC()); + auto storage = std::make_unique(std::move(s)); + AMS_FS_R_UNLESS(storage != nullptr, fs::ResultAllocationFailureInBisC()); *out = std::move(storage); - return ResultSuccess(); + R_SUCCEED(); } Result InvalidateBisCache() { - /* TODO: Libnx binding for this command. */ - AMS_ABORT(); + auto fsp = impl::GetFileSystemProxyServiceObject(); + AMS_FS_R_ABORT_UNLESS(fsp->InvalidateBisCache()); + R_SUCCEED(); } } diff --git a/libraries/libstratosphere/source/fs/fs_code.cpp b/libraries/libstratosphere/source/fs/fs_code.cpp index 81c146d02..36b4e70de 100644 --- a/libraries/libstratosphere/source/fs/fs_code.cpp +++ b/libraries/libstratosphere/source/fs/fs_code.cpp @@ -15,6 +15,8 @@ */ #include #include "fsa/fs_mount_utils.hpp" +#include "impl/fs_file_system_service_object_adapter.hpp" +#include "impl/fs_file_system_proxy_service_object.hpp" namespace ams::fs { @@ -56,7 +58,7 @@ namespace ams::fs { g_mounted_stratosphere_romfs = true; } - return ResultSuccess(); + R_SUCCEED(); } fsa::IFileSystem &GetStratosphereRomFsFileSystem() { @@ -70,32 +72,35 @@ namespace ams::fs { Result OpenCodeFileSystemImpl(CodeVerificationData *out_verification_data, std::unique_ptr *out, const char *path, ncm::ProgramId program_id) { /* Print a path suitable for the remote service. */ fssrv::sf::Path sf_path; - R_TRY(FspPathPrintf(std::addressof(sf_path), "%s", path)); + R_TRY(FormatToFspPath(std::addressof(sf_path), "%s", path)); - /* Open the filesystem using libnx bindings. */ - static_assert(sizeof(CodeVerificationData) == sizeof(::FsCodeInfo)); - ::FsFileSystem fs; - R_TRY(fsldrOpenCodeFileSystem(reinterpret_cast<::FsCodeInfo *>(out_verification_data), program_id.value, sf_path.str, std::addressof(fs))); + /* Open the filesystem. */ + auto fsp = impl::GetFileSystemProxyForLoaderServiceObject(); + R_TRY(fsp->SetCurrentProcess({})); + + sf::SharedPointer fs; + R_TRY(fsp->OpenCodeFileSystem(std::addressof(fs), out_verification_data, sf_path, program_id)); /* Allocate a new filesystem wrapper. */ - auto fsa = std::make_unique(fs); + auto fsa = std::make_unique(std::move(fs)); R_UNLESS(fsa != nullptr, fs::ResultAllocationFailureInCodeA()); *out = std::move(fsa); - return ResultSuccess(); + R_SUCCEED(); } - Result OpenPackageFileSystemImpl(std::unique_ptr *out, const char *common_path) { - /* Open a filesystem using libnx bindings. */ - FsFileSystem fs; - R_TRY(fsOpenFileSystemWithId(std::addressof(fs), ncm::InvalidProgramId.value, static_cast<::FsFileSystemType>(impl::FileSystemProxyType_Package), common_path)); + Result OpenPackageFileSystemImpl(std::unique_ptr *out, const fssrv::sf::FspPath &path) { + /* Open the filesystem. */ + auto fsp = impl::GetFileSystemProxyServiceObject(); + sf::SharedPointer fs; + R_TRY(fsp->OpenFileSystemWithId(std::addressof(fs), path, ncm::InvalidProgramId.value, impl::FileSystemProxyType_Package)); /* Allocate a new filesystem wrapper. */ - auto fsa = std::make_unique(fs); + auto fsa = std::make_unique(std::move(fs)); R_UNLESS(fsa != nullptr, fs::ResultAllocationFailureInCodeA()); *out = std::move(fsa); - return ResultSuccess(); + R_SUCCEED(); } Result OpenSdCardCodeFileSystemImpl(std::unique_ptr *out, ncm::ProgramId program_id) { @@ -104,9 +109,9 @@ namespace ams::fs { /* Print a path to the program's package. */ fssrv::sf::Path sf_path; - R_TRY(FspPathPrintf(std::addressof(sf_path), "%s:/atmosphere/contents/%016lx/exefs.nsp", impl::SdCardFileSystemMountName, program_id.value)); + R_TRY(FormatToFspPath(std::addressof(sf_path), "%s:/atmosphere/contents/%016" PRIx64 "/exefs.nsp", impl::SdCardFileSystemMountName, program_id.value)); - return OpenPackageFileSystemImpl(out, sf_path.str); + R_RETURN(OpenPackageFileSystemImpl(out, sf_path)); } Result OpenStratosphereCodeFileSystemImpl(std::unique_ptr *out, ncm::ProgramId program_id) { @@ -120,11 +125,12 @@ namespace ams::fs { auto &romfs_fs = GetStratosphereRomFsFileSystem(); /* Print a path to the program's package. */ - fssrv::sf::Path sf_path; - R_TRY(FspPathPrintf(std::addressof(sf_path), "/atmosphere/contents/%016lX/exefs.nsp", program_id.value)); + fs::Path path; + R_TRY(path.InitializeWithFormat("/atmosphere/contents/%016" PRIx64 "/exefs.nsp", program_id.value)); + R_TRY(path.Normalize(fs::PathFlags{})); /* Open the package within stratosphere.romfs. */ - R_TRY(romfs_fs.OpenFile(std::addressof(package_file), sf_path.str, fs::OpenMode_Read)); + R_TRY(romfs_fs.OpenFile(std::addressof(package_file), path, fs::OpenMode_Read)); } /* Create a file storage for the program's package. */ @@ -139,7 +145,7 @@ namespace ams::fs { R_TRY(package_fs->Initialize(package_storage)); *out = std::move(package_fs); - return ResultSuccess(); + R_SUCCEED(); } Result OpenSdCardCodeOrStratosphereCodeOrCodeFileSystemImpl(CodeVerificationData *out_verification_data, std::unique_ptr *out, const char *path, ncm::ProgramId program_id) { @@ -150,7 +156,7 @@ namespace ams::fs { R_SUCCEED_IF(R_SUCCEEDED(OpenStratosphereCodeFileSystemImpl(out, program_id))); /* Otherwise, fall back to a normal code fs. */ - return OpenCodeFileSystemImpl(out_verification_data, out, path, program_id); + R_RETURN(OpenCodeFileSystemImpl(out_verification_data, out, path, program_id)); } Result OpenHblCodeFileSystemImpl(std::unique_ptr *out) { @@ -159,93 +165,94 @@ namespace ams::fs { /* Print a path to the hbl package. */ fssrv::sf::Path sf_path; - R_TRY(FspPathPrintf(std::addressof(sf_path), "%s:/%s", impl::SdCardFileSystemMountName, hbl_path[0] == '/' ? hbl_path + 1 : hbl_path)); + R_TRY(FormatToFspPath(std::addressof(sf_path), "%s:/%s", impl::SdCardFileSystemMountName, hbl_path[0] == '/' ? hbl_path + 1 : hbl_path)); - return OpenPackageFileSystemImpl(out, sf_path.str); + R_RETURN(OpenPackageFileSystemImpl(out, sf_path)); } - Result OpenSdCardFileSystemImpl(std::unique_ptr *out) { - /* Open the SD card. This uses libnx bindings. */ - FsFileSystem fs; - R_TRY(fsOpenSdCardFileSystem(std::addressof(fs))); + Result OpenSdCardFileSystemImpl(std::shared_ptr *out) { + /* Open the SD card filesystem. */ + auto fsp = impl::GetFileSystemProxyServiceObject(); + sf::SharedPointer fs; + R_TRY(fsp->OpenSdCardFileSystem(std::addressof(fs))); /* Allocate a new filesystem wrapper. */ - auto fsa = std::make_unique(fs); + auto fsa = std::make_shared(std::move(fs)); R_UNLESS(fsa != nullptr, fs::ResultAllocationFailureInCodeA()); *out = std::move(fsa); - return ResultSuccess(); + R_SUCCEED(); } class OpenFileOnlyFileSystem : public fsa::IFileSystem, public impl::Newable { private: virtual Result DoCommit() override final { - return ResultSuccess(); + R_SUCCEED(); } - virtual Result DoOpenDirectory(std::unique_ptr *out_dir, const char *path, OpenDirectoryMode mode) override final { + virtual Result DoOpenDirectory(std::unique_ptr *out_dir, const fs::Path &path, OpenDirectoryMode mode) override final { AMS_UNUSED(out_dir, path, mode); - return fs::ResultUnsupportedOperation(); + R_THROW(fs::ResultUnsupportedOperation()); } - virtual Result DoGetEntryType(DirectoryEntryType *out, const char *path) override final { + virtual Result DoGetEntryType(DirectoryEntryType *out, const fs::Path &path) override final { AMS_UNUSED(out, path); - return fs::ResultUnsupportedOperation(); + R_THROW(fs::ResultUnsupportedOperation()); } - virtual Result DoCreateFile(const char *path, s64 size, int flags) override final { + virtual Result DoCreateFile(const fs::Path &path, s64 size, int flags) override final { AMS_UNUSED(path, size, flags); - return fs::ResultUnsupportedOperation(); + R_THROW(fs::ResultUnsupportedOperation()); } - virtual Result DoDeleteFile(const char *path) override final { + virtual Result DoDeleteFile(const fs::Path &path) override final { AMS_UNUSED(path); - return fs::ResultUnsupportedOperation(); + R_THROW(fs::ResultUnsupportedOperation()); } - virtual Result DoCreateDirectory(const char *path) override final { + virtual Result DoCreateDirectory(const fs::Path &path) override final { AMS_UNUSED(path); - return fs::ResultUnsupportedOperation(); + R_THROW(fs::ResultUnsupportedOperation()); } - virtual Result DoDeleteDirectory(const char *path) override final { + virtual Result DoDeleteDirectory(const fs::Path &path) override final { AMS_UNUSED(path); - return fs::ResultUnsupportedOperation(); + R_THROW(fs::ResultUnsupportedOperation()); } - virtual Result DoDeleteDirectoryRecursively(const char *path) override final { + virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) override final { AMS_UNUSED(path); - return fs::ResultUnsupportedOperation(); + R_THROW(fs::ResultUnsupportedOperation()); } - virtual Result DoRenameFile(const char *old_path, const char *new_path) override final { + virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) override final { AMS_UNUSED(old_path, new_path); - return fs::ResultUnsupportedOperation(); + R_THROW(fs::ResultUnsupportedOperation()); } - virtual Result DoRenameDirectory(const char *old_path, const char *new_path) override final { + virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) override final { AMS_UNUSED(old_path, new_path); - return fs::ResultUnsupportedOperation(); + R_THROW(fs::ResultUnsupportedOperation()); } - virtual Result DoCleanDirectoryRecursively(const char *path) override final { + virtual Result DoCleanDirectoryRecursively(const fs::Path &path) override final { AMS_UNUSED(path); - return fs::ResultUnsupportedOperation(); + R_THROW(fs::ResultUnsupportedOperation()); } - virtual Result DoGetFreeSpaceSize(s64 *out, const char *path) override final { + virtual Result DoGetFreeSpaceSize(s64 *out, const fs::Path &path) override final { AMS_UNUSED(out, path); - return fs::ResultUnsupportedOperation(); + R_THROW(fs::ResultUnsupportedOperation()); } - virtual Result DoGetTotalSpaceSize(s64 *out, const char *path) override final { + virtual Result DoGetTotalSpaceSize(s64 *out, const fs::Path &path) override final { AMS_UNUSED(out, path); - return fs::ResultUnsupportedOperation(); + R_THROW(fs::ResultUnsupportedOperation()); } virtual Result DoCommitProvisionally(s64 counter) override final { AMS_UNUSED(counter); - return fs::ResultUnsupportedOperation(); + R_THROW(fs::ResultUnsupportedOperation()); } }; @@ -261,32 +268,40 @@ namespace ams::fs { } /* Open an SD card filesystem. */ - std::unique_ptr sd_fs; + std::shared_ptr sd_fs; if (R_FAILED(OpenSdCardFileSystemImpl(std::addressof(sd_fs)))) { return; } /* Create a redirection filesystem to the relevant content folder. */ - char path[fs::EntryNameLengthMax + 1]; - util::SNPrintf(path, sizeof(path), "/atmosphere/contents/%016lx/exefs", program_id.value); - - auto subdir_fs = std::make_unique(std::move(sd_fs), path); + auto subdir_fs = std::make_unique(std::move(sd_fs)); if (subdir_fs == nullptr) { return; } + fs::Path path; + R_ABORT_UNLESS(path.InitializeWithFormat("/atmosphere/contents/%016" PRIx64 "/exefs", program_id.value)); + R_ABORT_UNLESS(path.Normalize(fs::PathFlags{})); + + R_ABORT_UNLESS(subdir_fs->Initialize(path)); + m_sd_content_fs.emplace(std::move(subdir_fs)); } private: - bool IsFileStubbed(const char *path) { + bool IsFileStubbed(const fs::Path &path) { /* If we don't have an sd content fs, nothing is stubbed. */ if (!m_sd_content_fs) { return false; } /* Create a path representing the stub. */ - char stub_path[fs::EntryNameLengthMax + 1]; - util::SNPrintf(stub_path, sizeof(stub_path), "%s.stub", path); + fs::Path stub_path; + if (R_FAILED(stub_path.InitializeWithFormat("%s.stub", path.GetString()))) { + return false; + } + if (R_FAILED(stub_path.Normalize(fs::PathFlags{}))) { + return false; + } /* Query whether we have the file. */ bool has_file; @@ -297,7 +312,7 @@ namespace ams::fs { return has_file; } - virtual Result DoOpenFile(std::unique_ptr *out_file, const char *path, OpenMode mode) override final { + virtual Result DoOpenFile(std::unique_ptr *out_file, const fs::Path &path, OpenMode mode) override final { /* Only allow opening files with mode = read. */ R_UNLESS((mode & fs::OpenMode_All) == fs::OpenMode_Read, fs::ResultInvalidOpenMode()); @@ -310,7 +325,7 @@ namespace ams::fs { R_UNLESS(!this->IsFileStubbed(path), fs::ResultPathNotFound()); /* Open a file from the base code fs. */ - return m_code_fs.OpenFile(out_file, path, mode); + R_RETURN(m_code_fs.OpenFile(out_file, path, mode)); } }; @@ -341,10 +356,10 @@ namespace ams::fs { m_program_id = program_id; m_initialized = true; - return ResultSuccess(); + R_SUCCEED(); } private: - virtual Result DoOpenFile(std::unique_ptr *out_file, const char *path, OpenMode mode) override final { + virtual Result DoOpenFile(std::unique_ptr *out_file, const fs::Path &path, OpenMode mode) override final { /* Ensure that we're initialized. */ R_UNLESS(m_initialized, fs::ResultNotInitialized()); @@ -355,81 +370,111 @@ namespace ams::fs { { fsa::IFileSystem *ecs = fssystem::GetExternalCodeFileSystem(m_program_id); if (ecs != nullptr) { - return ecs->OpenFile(out_file, path, mode); + R_RETURN(ecs->OpenFile(out_file, path, mode)); } } /* If we're hbl, open from the hbl fs. */ if (m_hbl_fs) { - return m_hbl_fs->OpenFile(out_file, path, mode); + R_RETURN(m_hbl_fs->OpenFile(out_file, path, mode)); } /* If we're not hbl, fall back to our code filesystem. */ - return m_code_fs->OpenFile(out_file, path, mode); + R_RETURN(m_code_fs->OpenFile(out_file, path, mode)); } }; } Result MountCode(CodeVerificationData *out, const char *name, const char *path, ncm::ProgramId program_id) { - /* Clear the output. */ - std::memset(out, 0, sizeof(*out)); + auto mount_impl = [=]() -> Result { + /* Clear the output. */ + std::memset(out, 0, sizeof(*out)); - /* Validate the mount name. */ - R_TRY(impl::CheckMountName(name)); + /* Validate the mount name. */ + R_TRY(impl::CheckMountName(name)); - /* Validate the path isn't null. */ - R_UNLESS(path != nullptr, fs::ResultInvalidPath()); + /* Validate the path isn't null. */ + R_UNLESS(path != nullptr, fs::ResultInvalidPath()); - /* Open the code file system. */ - std::unique_ptr fsa; - R_TRY(OpenCodeFileSystemImpl(out, std::addressof(fsa), path, program_id)); + /* Open the code file system. */ + std::unique_ptr fsa; + R_TRY(OpenCodeFileSystemImpl(out, std::addressof(fsa), path, program_id)); - /* Register. */ - return fsa::Register(name, std::move(fsa)); + /* Register. */ + R_RETURN(fsa::Register(name, std::move(fsa))); + }; + + /* Perform the mount. */ + AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(mount_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CODE(name, path, program_id))); + + /* Enable access logging. */ + AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name); + + R_SUCCEED(); } Result MountCodeForAtmosphereWithRedirection(CodeVerificationData *out, const char *name, const char *path, ncm::ProgramId program_id, bool is_hbl, bool is_specific) { - /* Clear the output. */ - std::memset(out, 0, sizeof(*out)); + auto mount_impl = [=]() -> Result { + /* Clear the output. */ + std::memset(out, 0, sizeof(*out)); - /* Validate the mount name. */ - R_TRY(impl::CheckMountName(name)); + /* Validate the mount name. */ + R_TRY(impl::CheckMountName(name)); - /* Validate the path isn't null. */ - R_UNLESS(path != nullptr, fs::ResultInvalidPath()); + /* Validate the path isn't null. */ + R_UNLESS(path != nullptr, fs::ResultInvalidPath()); - /* Create an AtmosphereCodeFileSystem. */ - auto ams_code_fs = std::make_unique(); - R_UNLESS(ams_code_fs != nullptr, fs::ResultAllocationFailureInCodeA()); + /* Create an AtmosphereCodeFileSystem. */ + auto ams_code_fs = std::make_unique(); + R_UNLESS(ams_code_fs != nullptr, fs::ResultAllocationFailureInCodeA()); - /* Initialize the code file system. */ - R_TRY(ams_code_fs->Initialize(out, path, program_id, is_hbl, is_specific)); + /* Initialize the code file system. */ + R_TRY(ams_code_fs->Initialize(out, path, program_id, is_hbl, is_specific)); - /* Register. */ - return fsa::Register(name, std::move(ams_code_fs)); + /* Register. */ + R_RETURN(fsa::Register(name, std::move(ams_code_fs))); + }; + + /* Perform the mount. */ + AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(mount_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CODE(name, path, program_id))); + + /* Enable access logging. */ + AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name); + + R_SUCCEED(); } Result MountCodeForAtmosphere(CodeVerificationData *out, const char *name, const char *path, ncm::ProgramId program_id) { - /* Clear the output. */ - std::memset(out, 0, sizeof(*out)); + auto mount_impl = [=]() -> Result { + /* Clear the output. */ + std::memset(out, 0, sizeof(*out)); - /* Validate the mount name. */ - R_TRY(impl::CheckMountName(name)); + /* Validate the mount name. */ + R_TRY(impl::CheckMountName(name)); - /* Validate the path isn't null. */ - R_UNLESS(path != nullptr, fs::ResultInvalidPath()); + /* Validate the path isn't null. */ + R_UNLESS(path != nullptr, fs::ResultInvalidPath()); - /* Open the code file system. */ - std::unique_ptr fsa; - R_TRY(OpenSdCardCodeOrStratosphereCodeOrCodeFileSystemImpl(out, std::addressof(fsa), path, program_id)); + /* Open the code file system. */ + std::unique_ptr fsa; + R_TRY(OpenSdCardCodeOrStratosphereCodeOrCodeFileSystemImpl(out, std::addressof(fsa), path, program_id)); - /* Create a wrapper fs. */ - auto wrap_fsa = std::make_unique(std::move(fsa), program_id, false); - R_UNLESS(wrap_fsa != nullptr, fs::ResultAllocationFailureInCodeA()); + /* Create a wrapper fs. */ + auto wrap_fsa = std::make_unique(std::move(fsa), program_id, false); + R_UNLESS(wrap_fsa != nullptr, fs::ResultAllocationFailureInCodeA()); - /* Register. */ - return fsa::Register(name, std::move(wrap_fsa)); + /* Register. */ + R_RETURN(fsa::Register(name, std::move(wrap_fsa))); + }; + + /* Perform the mount. */ + AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(mount_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CODE(name, path, program_id))); + + /* Enable access logging. */ + AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name); + + R_SUCCEED(); } } diff --git a/libraries/libstratosphere/source/fs/fs_content.cpp b/libraries/libstratosphere/source/fs/fs_content.cpp index cdd3ed455..ce6c61717 100644 --- a/libraries/libstratosphere/source/fs/fs_content.cpp +++ b/libraries/libstratosphere/source/fs/fs_content.cpp @@ -15,6 +15,8 @@ */ #include #include "fsa/fs_mount_utils.hpp" +#include "impl/fs_file_system_proxy_service_object.hpp" +#include "impl/fs_file_system_service_object_adapter.hpp" namespace ams::fs { @@ -30,45 +32,75 @@ namespace ams::fs { } } - Result MountContentImpl(const char *name, const char *path, u64 id, impl::FileSystemProxyType type) { - /* Open a filesystem using libnx bindings. */ - FsFileSystem fs; - R_TRY(fsOpenFileSystemWithId(std::addressof(fs), id, static_cast<::FsFileSystemType>(type), path)); - - /* Allocate a new filesystem wrapper. */ - auto fsa = std::make_unique(fs); - R_UNLESS(fsa != nullptr, fs::ResultAllocationFailureInContentA()); - - /* Register. */ - return fsa::Register(name, std::move(fsa)); - } - - Result MountContent(const char *name, const char *path, u64 id, ContentType content_type) { + Result MountContentImpl(const char *name, const char *path, u64 id, ContentType type) { /* Validate the mount name. */ R_TRY(impl::CheckMountNameAllowingReserved(name)); /* Validate the path. */ R_UNLESS(path != nullptr, fs::ResultInvalidPath()); - /* Mount the content. */ - return MountContentImpl(name, path, id, ConvertToFileSystemProxyType(content_type)); + /* Convert the path for fsp. */ + fssrv::sf::FspPath sf_path; + R_TRY(fs::ConvertToFspPath(std::addressof(sf_path), path)); + + /* Open the filesystem. */ + auto fsp = impl::GetFileSystemProxyServiceObject(); + sf::SharedPointer fs; + R_TRY(fsp->OpenFileSystemWithId(std::addressof(fs), sf_path, id, ConvertToFileSystemProxyType(type))); + + /* Allocate a new filesystem wrapper. */ + auto fsa = std::make_unique(std::move(fs)); + R_UNLESS(fsa != nullptr, fs::ResultAllocationFailureInContentA()); + + /* Register. */ + R_RETURN(fsa::Register(name, std::move(fsa))); } } Result MountContent(const char *name, const char *path, ContentType content_type) { - /* This API only supports mounting Meta content. */ - AMS_ABORT_UNLESS(content_type == ContentType_Meta); + auto mount_impl = [=]() -> Result { + /* This API only supports mounting Meta content. */ + R_UNLESS(content_type == ContentType_Meta, fs::ResultInvalidArgument()); - return MountContent(name, path, ncm::InvalidProgramId, content_type); + R_RETURN(MountContentImpl(name, path, ncm::InvalidProgramId.value, content_type)); + }; + + /* Perform the mount. */ + AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(mount_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CONTENT_PATH(name, path, content_type))); + + /* Enable access logging. */ + AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name); + + R_SUCCEED(); } Result MountContent(const char *name, const char *path, ncm::ProgramId id, ContentType content_type) { - return MountContent(name, path, id.value, content_type); + auto mount_impl = [=]() -> Result { + R_RETURN(MountContentImpl(name, path, id.value, content_type)); + }; + + /* Perform the mount. */ + AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(mount_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CONTENT_PATH_AND_PROGRAM_ID(name, path, id, content_type))); + + /* Enable access logging. */ + AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name); + + R_SUCCEED(); } Result MountContent(const char *name, const char *path, ncm::DataId id, ContentType content_type) { - return MountContent(name, path, id.value, content_type); + auto mount_impl = [=]() -> Result { + R_RETURN(MountContentImpl(name, path, id.value, content_type)); + }; + + /* Perform the mount. */ + AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(mount_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CONTENT_PATH_AND_DATA_ID(name, path, id, content_type))); + + /* Enable access logging. */ + AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name); + + R_SUCCEED(); } } diff --git a/libraries/libstratosphere/source/fs/fs_content_storage.cpp b/libraries/libstratosphere/source/fs/fs_content_storage.cpp index 8289118a5..b2f580505 100644 --- a/libraries/libstratosphere/source/fs/fs_content_storage.cpp +++ b/libraries/libstratosphere/source/fs/fs_content_storage.cpp @@ -15,6 +15,8 @@ */ #include #include "fsa/fs_mount_utils.hpp" +#include "impl/fs_file_system_service_object_adapter.hpp" +#include "impl/fs_file_system_proxy_service_object.hpp" namespace ams::fs { @@ -28,7 +30,7 @@ namespace ams::fs { virtual Result GenerateCommonMountName(char *dst, size_t dst_size) override { /* Determine how much space we need. */ - const size_t needed_size = strnlen(GetContentStorageMountName(id), MountNameLengthMax) + 2; + const size_t needed_size = util::Strnlen(GetContentStorageMountName(id), MountNameLengthMax) + 2; AMS_ABORT_UNLESS(dst_size >= needed_size); /* Generate the name. */ @@ -56,43 +58,55 @@ namespace ams::fs { } Result MountContentStorage(const char *name, ContentStorageId id) { - /* Validate the mount name. */ - R_TRY(impl::CheckMountNameAllowingReserved(name)); + auto mount_impl = [=]() -> Result { + /* Validate the mount name. */ + R_TRY(impl::CheckMountNameAllowingReserved(name)); - /* It can take some time for the system partition to be ready (if it's on the SD card). */ - /* Thus, we will retry up to 10 times, waiting one second each time. */ - constexpr size_t MaxRetries = 10; - constexpr auto RetryInterval = TimeSpan::FromSeconds(1); + /* It can take some time for the system partition to be ready (if it's on the SD card). */ + /* Thus, we will retry up to 10 times, waiting one second each time. */ + constexpr size_t MaxRetries = 10; + constexpr auto RetryInterval = TimeSpan::FromSeconds(1); - /* Mount the content storage, use libnx bindings. */ - ::FsFileSystem fs; - for (size_t i = 0; i < MaxRetries; i++) { - /* Try to open the filesystem. */ - R_TRY_CATCH(fsOpenContentStorageFileSystem(std::addressof(fs), static_cast<::FsContentStorageId>(id))) { - R_CATCH(fs::ResultSystemPartitionNotReady) { - if (i < MaxRetries - 1) { - os::SleepThread(RetryInterval); - continue; - } else { - return fs::ResultSystemPartitionNotReady(); + /* Mount the content storage */ + auto fsp = impl::GetFileSystemProxyServiceObject(); + + sf::SharedPointer fs; + for (size_t i = 0; i < MaxRetries; i++) { + /* Try to open the filesystem. */ + R_TRY_CATCH(fsp->OpenContentStorageFileSystem(std::addressof(fs), static_cast(id))) { + R_CATCH(fs::ResultSystemPartitionNotReady) { + if (i < MaxRetries - 1) { + os::SleepThread(RetryInterval); + continue; + } else { + R_THROW(fs::ResultSystemPartitionNotReady()); + } } - } - } R_END_TRY_CATCH; + } R_END_TRY_CATCH; - /* The filesystem was opened successfully. */ - break; - } + /* The filesystem was opened successfully. */ + break; + } - /* Allocate a new filesystem wrapper. */ - auto fsa = std::make_unique(fs); - R_UNLESS(fsa != nullptr, fs::ResultAllocationFailureInContentStorageA()); + /* Allocate a new filesystem wrapper. */ + auto fsa = std::make_unique(std::move(fs)); + R_UNLESS(fsa != nullptr, fs::ResultAllocationFailureInContentStorageA()); - /* Allocate a new mountname generator. */ - auto generator = std::make_unique(id); - R_UNLESS(generator != nullptr, fs::ResultAllocationFailureInContentStorageB()); + /* Allocate a new mountname generator. */ + auto generator = std::make_unique(id); + R_UNLESS(generator != nullptr, fs::ResultAllocationFailureInContentStorageB()); - /* Register. */ - return fsa::Register(name, std::move(fsa), std::move(generator)); + /* Register. */ + R_RETURN(fsa::Register(name, std::move(fsa), std::move(generator))); + }; + + /* Perform the mount. */ + AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(mount_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CONTENT_STORAGE(name, id))); + + /* Enable access logging. */ + AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name); + + R_SUCCEED(); } } diff --git a/libraries/libstratosphere/source/fs/fs_data.cpp b/libraries/libstratosphere/source/fs/fs_data.cpp index c2853756a..7cec067fa 100644 --- a/libraries/libstratosphere/source/fs/fs_data.cpp +++ b/libraries/libstratosphere/source/fs/fs_data.cpp @@ -15,19 +15,27 @@ */ #include #include "fsa/fs_mount_utils.hpp" +#include "impl/fs_file_system_proxy_service_object.hpp" +#include "impl/fs_storage_service_object_adapter.hpp" namespace ams::fs::impl { namespace { - Result OpenDataStorageByDataId(std::unique_ptr *out, ncm::DataId data_id, ncm::StorageId storage_id) { - /* Open storage using libnx bindings. */ - ::FsStorage s; - R_TRY_CATCH(fsOpenDataStorageByDataId(std::addressof(s), data_id.value, static_cast<::NcmStorageId>(storage_id))) { + Result OpenDataStorageByDataIdImpl(sf::SharedPointer *out, ncm::DataId data_id, ncm::StorageId storage_id) { + auto fsp = impl::GetFileSystemProxyServiceObject(); + R_TRY_CATCH(fsp->OpenDataStorageByDataId(out, data_id, static_cast(storage_id))) { R_CONVERT(ncm::ResultContentMetaNotFound, fs::ResultTargetNotFound()); } R_END_TRY_CATCH; + R_SUCCEED(); + } - auto storage = std::make_unique(s); + Result OpenDataStorageByDataId(std::unique_ptr *out, ncm::DataId data_id, ncm::StorageId storage_id) { + /* Open storage. */ + sf::SharedPointer s; + AMS_FS_R_TRY(OpenDataStorageByDataIdImpl(std::addressof(s), data_id, storage_id)); + + auto storage = std::make_unique(std::move(s)); R_UNLESS(storage != nullptr, fs::ResultAllocationFailureInDataA()); *out = std::move(storage); @@ -48,13 +56,13 @@ namespace ams::fs::impl { } Result QueryMountDataCacheSize(size_t *out, ncm::DataId data_id, ncm::StorageId storage_id) { - R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); + AMS_FS_R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); std::unique_ptr storage; - R_TRY(OpenDataStorageByDataId(std::addressof(storage), data_id, storage_id)); + AMS_FS_R_TRY(OpenDataStorageByDataId(std::addressof(storage), data_id, storage_id)); size_t size = 0; - R_TRY(RomFsFileSystem::GetRequiredWorkingMemorySize(std::addressof(size), storage.get())); + AMS_FS_R_TRY(RomFsFileSystem::GetRequiredWorkingMemorySize(std::addressof(size), storage.get())); constexpr size_t MinimumCacheSize = 32; *out = std::max(size, MinimumCacheSize); @@ -63,25 +71,25 @@ namespace ams::fs::impl { Result MountData(const char *name, ncm::DataId data_id, ncm::StorageId storage_id) { /* Validate the mount name. */ - R_TRY(impl::CheckMountName(name)); + AMS_FS_R_TRY(impl::CheckMountName(name)); return MountDataImpl(name, data_id, storage_id, nullptr, 0, false, false, false); } Result MountData(const char *name, ncm::DataId data_id, ncm::StorageId storage_id, void *cache_buffer, size_t cache_size) { /* Validate the mount name. */ - R_TRY(impl::CheckMountName(name)); + AMS_FS_R_TRY(impl::CheckMountName(name)); - R_UNLESS(cache_buffer != nullptr, fs::ResultNullptrArgument()); + AMS_FS_R_UNLESS(cache_buffer != nullptr, fs::ResultNullptrArgument()); return MountDataImpl(name, data_id, storage_id, cache_buffer, cache_size, true, false, false); } Result MountData(const char *name, ncm::DataId data_id, ncm::StorageId storage_id, void *cache_buffer, size_t cache_size, bool use_data_cache, bool use_path_cache) { /* Validate the mount name. */ - R_TRY(impl::CheckMountName(name)); + AMS_FS_R_TRY(impl::CheckMountName(name)); - R_UNLESS(cache_buffer != nullptr, fs::ResultNullptrArgument()); + AMS_FS_R_UNLESS(cache_buffer != nullptr, fs::ResultNullptrArgument()); return MountDataImpl(name, data_id, storage_id, cache_buffer, cache_size, true, use_data_cache, use_path_cache); } diff --git a/libraries/libstratosphere/source/fs/fs_device_save_data.cpp b/libraries/libstratosphere/source/fs/fs_device_save_data.cpp index 3fd90faa3..92b1b8ef2 100644 --- a/libraries/libstratosphere/source/fs/fs_device_save_data.cpp +++ b/libraries/libstratosphere/source/fs/fs_device_save_data.cpp @@ -15,6 +15,8 @@ */ #include #include "fsa/fs_mount_utils.hpp" +#include "impl/fs_file_system_proxy_service_object.hpp" +#include "impl/fs_file_system_service_object_adapter.hpp" namespace ams::fs { @@ -26,12 +28,13 @@ namespace ams::fs { /* Validate the mount name. */ R_TRY(impl::CheckMountName(name)); - /* Open the filesystem, use libnx bindings. */ - ::FsFileSystem fs; - R_TRY(fsOpenSaveDataFileSystem(std::addressof(fs), static_cast<::FsSaveDataSpaceId>(DeviceSaveDataSpaceId), reinterpret_cast(std::addressof(attribute)))); + /* Open the filesystem. */ + auto fsp = impl::GetFileSystemProxyServiceObject(); + sf::SharedPointer fs; + R_TRY(fsp->OpenSaveDataFileSystem(std::addressof(fs), static_cast(DeviceSaveDataSpaceId), attribute)); /* Allocate a new filesystem wrapper. */ - auto fsa = std::make_unique(fs); + auto fsa = std::make_unique(std::move(fs)); R_UNLESS(fsa != nullptr, fs::ResultAllocationFailureInDeviceSaveDataA()); /* Register. */ @@ -41,11 +44,27 @@ namespace ams::fs { } Result MountDeviceSaveData(const char *name) { - return MountDeviceSaveDataImpl(name, SaveDataAttribute::Make(ncm::InvalidProgramId, SaveDataType::Device, InvalidUserId, InvalidSystemSaveDataId)); + const auto attr = SaveDataAttribute::Make(ncm::InvalidProgramId, SaveDataType::Device, InvalidUserId, InvalidSystemSaveDataId); + + /* Perform the mount. */ + AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT(MountDeviceSaveDataImpl(name, attr), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT, name)); + + /* Enable access logging. */ + AMS_FS_IMPL_ACCESS_LOG_FS_ACCESSOR_ENABLE(name); + + R_SUCCEED(); } Result MountDeviceSaveData(const char *name, const ncm::ApplicationId application_id) { - return MountDeviceSaveDataImpl(name, SaveDataAttribute::Make(application_id, SaveDataType::Device, InvalidUserId, InvalidSystemSaveDataId)); + const auto attr = SaveDataAttribute::Make(application_id, SaveDataType::Device, InvalidUserId, InvalidSystemSaveDataId); + + /* Perform the mount. */ + AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT(MountDeviceSaveDataImpl(name, attr), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_DEVICE_SAVE_DATA_APPLICATION_ID(name, application_id))); + + /* Enable access logging. */ + AMS_FS_IMPL_ACCESS_LOG_FS_ACCESSOR_ENABLE(name); + + R_SUCCEED(); } } diff --git a/libraries/libstratosphere/source/fs/fs_filesystem_utils.cpp b/libraries/libstratosphere/source/fs/fs_filesystem_utils.cpp index e61f46399..8dc6180a2 100644 --- a/libraries/libstratosphere/source/fs/fs_filesystem_utils.cpp +++ b/libraries/libstratosphere/source/fs/fs_filesystem_utils.cpp @@ -19,24 +19,35 @@ namespace ams::fs { - Result EnsureDirectoryRecursively(const char *path) { + Result EnsureDirectory(const char *path) { /* Get the filesystem accessor and sub path. */ impl::FileSystemAccessor *accessor; const char *sub_path; R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path)); + /* Set up the true sub path. */ + fs::Path sub_fs_path; + R_TRY(accessor->SetUpPath(std::addressof(sub_fs_path), sub_path)); + /* Use the system implementation. */ - return fssystem::EnsureDirectoryRecursively(accessor->GetRawFileSystemUnsafe(), sub_path); + return fssystem::EnsureDirectory(accessor->GetRawFileSystemUnsafe(), sub_fs_path); } - Result EnsureParentDirectoryRecursively(const char *path) { + Result EnsureParentDirectory(const char *path) { /* Get the filesystem accessor and sub path. */ impl::FileSystemAccessor *accessor; const char *sub_path; R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path)); + /* Set up the true sub path. */ + fs::Path sub_fs_path; + R_TRY(accessor->SetUpPath(std::addressof(sub_fs_path), sub_path)); + + /* Convert the path to the parent directory path. */ + R_TRY(sub_fs_path.RemoveChild()); + /* Use the system implementation. */ - return fssystem::EnsureParentDirectoryRecursively(accessor->GetRawFileSystemUnsafe(), sub_path); + return fssystem::EnsureDirectory(accessor->GetRawFileSystemUnsafe(), sub_fs_path); } Result HasFile(bool *out, const char *path) { @@ -45,7 +56,11 @@ namespace ams::fs { const char *sub_path; R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path)); - return fssystem::HasFile(out, accessor->GetRawFileSystemUnsafe(), sub_path); + /* Set up the true sub path. */ + fs::Path sub_fs_path; + R_TRY(accessor->SetUpPath(std::addressof(sub_fs_path), sub_path)); + + return fssystem::HasFile(out, accessor->GetRawFileSystemUnsafe(), sub_fs_path); } Result HasDirectory(bool *out, const char *path) { @@ -54,7 +69,11 @@ namespace ams::fs { const char *sub_path; R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path)); - return fssystem::HasDirectory(out, accessor->GetRawFileSystemUnsafe(), sub_path); + /* Set up the true sub path. */ + fs::Path sub_fs_path; + R_TRY(accessor->SetUpPath(std::addressof(sub_fs_path), sub_path)); + + return fssystem::HasDirectory(out, accessor->GetRawFileSystemUnsafe(), sub_fs_path); } } diff --git a/libraries/libstratosphere/source/fs/fs_game_card.cpp b/libraries/libstratosphere/source/fs/fs_game_card.cpp index 4a80a7931..3a57c2de8 100644 --- a/libraries/libstratosphere/source/fs/fs_game_card.cpp +++ b/libraries/libstratosphere/source/fs/fs_game_card.cpp @@ -15,6 +15,8 @@ */ #include #include "fsa/fs_mount_utils.hpp" +#include "impl/fs_file_system_proxy_service_object.hpp" +#include "impl/fs_file_system_service_object_adapter.hpp" namespace ams::fs { @@ -38,7 +40,7 @@ namespace ams::fs { virtual Result GenerateCommonMountName(char *dst, size_t dst_size) override { /* Determine how much space we need. */ - const size_t needed_size = strnlen(impl::GameCardFileSystemMountName, MountNameLengthMax) + strnlen(GetGameCardMountNameSuffix(m_partition), MountNameLengthMax) + sizeof(GameCardHandle) * 2 + 2; + const size_t needed_size = util::Strnlen(impl::GameCardFileSystemMountName, MountNameLengthMax) + util::Strnlen(GetGameCardMountNameSuffix(m_partition), MountNameLengthMax) + sizeof(GameCardHandle) * 2 + 2; AMS_ABORT_UNLESS(dst_size >= needed_size); /* Generate the name. */ @@ -53,36 +55,49 @@ namespace ams::fs { } Result GetGameCardHandle(GameCardHandle *out) { - /* TODO: fs::DeviceOperator */ - /* Open a DeviceOperator. */ - ::FsDeviceOperator d; - R_TRY(fsOpenDeviceOperator(std::addressof(d))); - ON_SCOPE_EXIT { fsDeviceOperatorClose(std::addressof(d)); }; + auto fsp = impl::GetFileSystemProxyServiceObject(); + + /* Open a device operator. */ + sf::SharedPointer device_operator; + AMS_FS_R_TRY(fsp->OpenDeviceOperator(std::addressof(device_operator))); /* Get the handle. */ - static_assert(sizeof(GameCardHandle) == sizeof(::FsGameCardHandle)); - return fsDeviceOperatorGetGameCardHandle(std::addressof(d), reinterpret_cast<::FsGameCardHandle *>(out)); + u32 handle; + AMS_FS_R_TRY(device_operator->GetGameCardHandle(std::addressof(handle))); + + *out = handle; + R_SUCCEED(); } Result MountGameCardPartition(const char *name, GameCardHandle handle, GameCardPartition partition) { - /* Validate the mount name. */ - R_TRY(impl::CheckMountNameAllowingReserved(name)); + auto mount_impl = [=]() -> Result { + /* Validate the mount name. */ + R_TRY(impl::CheckMountNameAllowingReserved(name)); - /* Open gamecard filesystem. This uses libnx bindings. */ - ::FsFileSystem fs; - const ::FsGameCardHandle _hnd = {handle}; - R_TRY(fsOpenGameCardFileSystem(std::addressof(fs), std::addressof(_hnd), static_cast<::FsGameCardPartition>(partition))); + /* Open the gamecard filesystem. */ + auto fsp = impl::GetFileSystemProxyServiceObject(); + sf::SharedPointer fs; + R_TRY(fsp->OpenGameCardFileSystem(std::addressof(fs), static_cast(handle), static_cast(partition))); - /* Allocate a new filesystem wrapper. */ - auto fsa = std::make_unique(fs); - R_UNLESS(fsa != nullptr, fs::ResultAllocationFailureInGameCardC()); + /* Allocate a new filesystem wrapper. */ + auto fsa = std::make_unique(std::move(fs)); + R_UNLESS(fsa != nullptr, fs::ResultAllocationFailureInGameCardC()); - /* Allocate a new mountname generator. */ - auto generator = std::make_unique(handle, partition); - R_UNLESS(generator != nullptr, fs::ResultAllocationFailureInGameCardD()); + /* Allocate a new mountname generator. */ + auto generator = std::make_unique(handle, partition); + R_UNLESS(generator != nullptr, fs::ResultAllocationFailureInGameCardD()); - /* Register. */ - return fsa::Register(name, std::move(fsa), std::move(generator)); + /* Register. */ + R_RETURN(fsa::Register(name, std::move(fsa), std::move(generator))); + }; + + /* Perform the mount. */ + AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(mount_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_GAME_CARD_PARTITION(name, handle, partition))); + + /* Enable access logging. */ + AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name); + + R_SUCCEED(); } } diff --git a/libraries/libstratosphere/source/fs/fs_host.cpp b/libraries/libstratosphere/source/fs/fs_host.cpp new file mode 100644 index 000000000..ee939b023 --- /dev/null +++ b/libraries/libstratosphere/source/fs/fs_host.cpp @@ -0,0 +1,241 @@ +/* + * Copyright (c) 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 "fsa/fs_mount_utils.hpp" +#include "impl/fs_file_system_proxy_service_object.hpp" +#include "impl/fs_file_system_service_object_adapter.hpp" + +namespace ams::fs { + + namespace { + + class HostRootCommonMountNameGenerator : public fsa::ICommonMountNameGenerator, public impl::Newable { + public: + explicit HostRootCommonMountNameGenerator() { /* ... */ } + + virtual Result GenerateCommonMountName(char *dst, size_t dst_size) override { + /* Determine how much space we need. */ + constexpr size_t RequiredNameBufferSizeSize = AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME_LEN + 1 + 1; + AMS_ASSERT(dst_size >= RequiredNameBufferSizeSize); + AMS_UNUSED(RequiredNameBufferSizeSize); + + /* Generate the name. */ + const auto size = util::SNPrintf(dst, dst_size, AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME ":"); + AMS_ASSERT(static_cast(size) == RequiredNameBufferSizeSize - 1); + AMS_UNUSED(size); + + R_SUCCEED(); + } + }; + + class HostCommonMountNameGenerator : public fsa::ICommonMountNameGenerator, public impl::Newable { + private: + char m_path[fs::EntryNameLengthMax + 1]; + public: + HostCommonMountNameGenerator(const char *path) { + util::Strlcpy(m_path, path, sizeof(m_path)); + } + + virtual Result GenerateCommonMountName(char *dst, size_t dst_size) override { + /* Determine how much space we need. */ + const size_t required_size = AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME_LEN + 1 + util::Strnlen(m_path, sizeof(m_path)) + 1; /* @Host:%s */ + R_UNLESS(dst_size >= required_size, fs::ResultTooLongPath()); + + + /* Generate the name. */ + const auto size = util::SNPrintf(dst, dst_size, AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME ":%s", m_path); + AMS_ASSERT(static_cast(size) == required_size - 1); + AMS_UNUSED(size); + + R_SUCCEED(); + } + }; + + Result OpenHostFileSystemImpl(std::unique_ptr *out, const fssrv::sf::FspPath &path, const MountHostOption &option) { + /* Open the filesystem. */ + auto fsp = impl::GetFileSystemProxyServiceObject(); + sf::SharedPointer fs; + if (option != MountHostOption::None) { + R_TRY(fsp->OpenHostFileSystemWithOption(std::addressof(fs), path, option._value)); + } else { + R_TRY(fsp->OpenHostFileSystem(std::addressof(fs), path)); + } + + /* Allocate a new filesystem wrapper. */ + auto fsa = std::make_unique(std::move(fs)); + R_UNLESS(fsa != nullptr, fs::ResultAllocationFailureInHostA()); + + /* Set the output. */ + *out = std::move(fsa); + R_SUCCEED(); + } + + Result PreMountHost(std::unique_ptr *out, const char *name, const char *path) { + /* Check pre-conditions. */ + AMS_ASSERT(out != nullptr); + + /* Check the mount name. */ + R_TRY(impl::CheckMountName(name)); + + /* Check that path is valid. */ + R_UNLESS(path != nullptr, fs::ResultNullptrArgument()); + + /* Create a new HostCommonMountNameGenerator. */ + *out = std::make_unique(path); + R_UNLESS(out->get() != nullptr, fs::ResultAllocationFailureInHostB()); + + R_SUCCEED(); + } + + } + + namespace impl { + + Result OpenHostFileSystem(std::unique_ptr *out, const char *name, const char *path, const fs::MountHostOption &option) { + /* Validate arguments. */ + R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); + R_UNLESS(name != nullptr, fs::ResultNullptrArgument()); + R_UNLESS(path != nullptr, fs::ResultNullptrArgument()); + + /* Check mount name isn't windows path or reserved. */ + R_UNLESS(!fs::IsWindowsDrive(name), fs::ResultInvalidMountName()); + R_UNLESS(!fs::impl::IsReservedMountName(name), fs::ResultInvalidMountName()); + + /* Convert the path for fsp. */ + fssrv::sf::FspPath sf_path; + R_TRY(fs::ConvertToFspPath(std::addressof(sf_path), path)); + + /* Ensure that the path doesn't correspond to the root. */ + if (sf_path.str[0] == 0) { + sf_path.str[0] = '.'; + sf_path.str[1] = 0; + } + + /* Open the host file system. */ + R_RETURN(OpenHostFileSystemImpl(out, sf_path, option)); + } + + } + + Result MountHost(const char *name, const char *root_path) { + /* Pre-mount host. */ + std::unique_ptr generator; + AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT_UNLESS_R_SUCCEEDED(PreMountHost(std::addressof(generator), name, root_path), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST(name, root_path))); + + /* Open the filesystem. */ + std::unique_ptr fsa; + R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT_UNLESS_R_SUCCEEDED(impl::OpenHostFileSystem(std::addressof(fsa), name, root_path, MountHostOption::None), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST(name, root_path))); + + /* Declare registration helper. */ + auto register_impl = [&]() -> Result { + /* Register. */ + R_RETURN(fsa::Register(name, std::move(fsa), std::move(generator))); + }; + + /* Mount the filesystem. */ + AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT(register_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST(name, root_path))); + + /* Enable access logging. */ + AMS_FS_IMPL_ACCESS_LOG_FS_ACCESSOR_ENABLE(name); + + R_SUCCEED(); + } + + Result MountHost(const char *name, const char *root_path, const MountHostOption &option) { + /* Pre-mount host. */ + std::unique_ptr generator; + AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT_UNLESS_R_SUCCEEDED(PreMountHost(std::addressof(generator), name, root_path), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_WITH_OPTION(name, root_path, option))); + + /* Open the filesystem. */ + std::unique_ptr fsa; + R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT_UNLESS_R_SUCCEEDED(impl::OpenHostFileSystem(std::addressof(fsa), name, root_path, option), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_WITH_OPTION(name, root_path, option))); + + /* Declare registration helper. */ + auto register_impl = [&]() -> Result { + /* Register. */ + R_RETURN(fsa::Register(name, std::move(fsa), std::move(generator))); + }; + + /* Mount the filesystem. */ + AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT(register_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_WITH_OPTION(name, root_path, option))); + + /* Enable access logging. */ + AMS_FS_IMPL_ACCESS_LOG_FS_ACCESSOR_ENABLE(name); + + R_SUCCEED(); + } + + Result MountHostRoot() { + /* Create host root path. */ + fssrv::sf::FspPath sf_path; + sf_path.str[0] = 0; + + /* Open the filesystem. */ + std::unique_ptr fsa; + R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT_UNLESS_R_SUCCEEDED(OpenHostFileSystemImpl(std::addressof(fsa), sf_path, MountHostOption::None), impl::HostRootFileSystemMountName, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_ROOT())); + + /* Declare registration helper. */ + auto register_impl = [&]() -> Result { + /* Allocate a new mountname generator. */ + auto generator = std::make_unique(); + R_UNLESS(generator != nullptr, fs::ResultAllocationFailureInHostC()); + + /* Register. */ + R_RETURN(fsa::Register(impl::HostRootFileSystemMountName, std::move(fsa), std::move(generator))); + }; + + /* Mount the filesystem. */ + AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT(register_impl(), impl::HostRootFileSystemMountName, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_ROOT())); + + /* Enable access logging. */ + AMS_FS_IMPL_ACCESS_LOG_FS_ACCESSOR_ENABLE(impl::HostRootFileSystemMountName); + + R_SUCCEED(); + } + + Result MountHostRoot(const MountHostOption &option) { + /* Create host root path. */ + fssrv::sf::FspPath sf_path; + sf_path.str[0] = 0; + + /* Open the filesystem. */ + std::unique_ptr fsa; + R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT_UNLESS_R_SUCCEEDED(OpenHostFileSystemImpl(std::addressof(fsa), sf_path, option), impl::HostRootFileSystemMountName, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_ROOT_WITH_OPTION(option))); + + /* Declare registration helper. */ + auto register_impl = [&]() -> Result { + /* Allocate a new mountname generator. */ + auto generator = std::make_unique(); + R_UNLESS(generator != nullptr, fs::ResultAllocationFailureInHostC()); + + /* Register. */ + R_RETURN(fsa::Register(impl::HostRootFileSystemMountName, std::move(fsa), std::move(generator))); + }; + + /* Mount the filesystem. */ + AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT(register_impl(), impl::HostRootFileSystemMountName, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_ROOT_WITH_OPTION(option))); + + /* Enable access logging. */ + AMS_FS_IMPL_ACCESS_LOG_FS_ACCESSOR_ENABLE(impl::HostRootFileSystemMountName); + + R_SUCCEED(); + } + + void UnmountHostRoot() { + return Unmount(impl::HostRootFileSystemMountName); + } + +} diff --git a/libraries/libstratosphere/source/fs/fs_image_directory.cpp b/libraries/libstratosphere/source/fs/fs_image_directory.cpp index f4823be5d..51c9163a3 100644 --- a/libraries/libstratosphere/source/fs/fs_image_directory.cpp +++ b/libraries/libstratosphere/source/fs/fs_image_directory.cpp @@ -15,23 +15,36 @@ */ #include #include "fsa/fs_mount_utils.hpp" +#include "impl/fs_file_system_proxy_service_object.hpp" +#include "impl/fs_file_system_service_object_adapter.hpp" namespace ams::fs { Result MountImageDirectory(const char *name, ImageDirectoryId id) { - /* Validate the mount name. */ - R_TRY(impl::CheckMountName(name)); + auto mount_impl = [=]() -> Result { + /* Validate the mount name. */ + R_TRY(impl::CheckMountName(name)); - /* Open the image directory. This uses libnx bindings. */ - FsFileSystem fs; - R_TRY(fsOpenImageDirectoryFileSystem(std::addressof(fs), static_cast<::FsImageDirectoryId>(id))); + /* Open the image directory. */ + auto fsp = impl::GetFileSystemProxyServiceObject(); + sf::SharedPointer fs; + R_TRY(fsp->OpenImageDirectoryFileSystem(std::addressof(fs), static_cast(id))); - /* Allocate a new filesystem wrapper. */ - auto fsa = std::make_unique(fs); - R_UNLESS(fsa != nullptr, fs::ResultAllocationFailureInImageDirectoryA()); + /* Allocate a new filesystem wrapper. */ + auto fsa = std::make_unique(std::move(fs)); + R_UNLESS(fsa != nullptr, fs::ResultAllocationFailureInImageDirectoryA()); - /* Register. */ - return fsa::Register(name, std::move(fsa)); + /* Register. */ + R_RETURN(fsa::Register(name, std::move(fsa))); + }; + + /* Perform the mount. */ + AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(mount_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_IMAGE_DIRECTORY(name, id))); + + /* Enable access logging. */ + AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name); + + R_SUCCEED(); } } diff --git a/libraries/libstratosphere/source/fs/fs_path_normalizer.cpp b/libraries/libstratosphere/source/fs/fs_path_normalizer.cpp deleted file mode 100644 index 2d2e0af2d..000000000 --- a/libraries/libstratosphere/source/fs/fs_path_normalizer.cpp +++ /dev/null @@ -1,570 +0,0 @@ -/* - * Copyright (c) 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 - -namespace ams::fs { - - namespace { - - Result CheckSharedName(const char *path, int len) { - if (len == 1) { - R_UNLESS(path[0] != StringTraits::Dot, fs::ResultInvalidPathFormat()); - } else if (len == 2) { - R_UNLESS(path[0] != StringTraits::Dot || path[1] != StringTraits::Dot, fs::ResultInvalidPathFormat()); - } - - return ResultSuccess(); - } - - Result ParseWindowsPath(const char **out_path, char *out, size_t *out_windows_path_len, bool *out_normalized, const char *path, size_t max_out_size, bool has_mount_name) { - /* Prepare to parse. */ - const char * const path_start = path; - if (out_normalized != nullptr) { - *out_normalized = true; - } - - /* Handle start of path. */ - bool skipped_mount = false; - auto prefix_len = 0; - if (has_mount_name) { - if (PathNormalizer::IsSeparator(path[0]) && path[1] == StringTraits::AlternateDirectorySeparator && path[2] == StringTraits::AlternateDirectorySeparator) { - path += 1; - prefix_len = 1; - } else { - /* Advance past separators. */ - while (PathNormalizer::IsSeparator(path[0])) { - ++path; - } - if (path != path_start) { - if (path - path_start == 1 || IsWindowsDrive(path)) { - prefix_len = 1; - } else { - if (path - path_start > 2 && out_normalized != nullptr) { - *out_normalized = false; - return ResultSuccess(); - } - path -= 2; - skipped_mount = true; - } - } - } - } else if (PathNormalizer::IsSeparator(path[0]) && !IsUnc(path)) { - path += 1; - prefix_len = 1; - } - - - /* Parse the path. */ - const char *trimmed_path = path_start; - if (IsWindowsDrive(path)) { - /* Find the first separator. */ - int i; - for (i = 2; !PathNormalizer::IsNullTerminator(path[i]); ++i) { - if (PathNormalizer::IsAnySeparator(path[i])) { - break; - } - } - trimmed_path = path + i; - - const size_t win_path_len = trimmed_path - path_start; - if (out != nullptr) { - R_UNLESS(win_path_len <= max_out_size, fs::ResultTooLongPath()); - std::memcpy(out, path_start, win_path_len); - } - *out_path = trimmed_path; - *out_windows_path_len = win_path_len; - } else if (IsUnc(path)) { - if (PathNormalizer::IsAnySeparator(path[2])) { - AMS_ASSERT(!has_mount_name); - return fs::ResultInvalidPathFormat(); - } - - int cur_part_ofs = 0; - bool needs_sep_fix = false; - for (auto i = 2; !PathNormalizer::IsNullTerminator(path[i]); ++i) { - if (cur_part_ofs == 0 && path[i] == StringTraits::AlternateDirectorySeparator) { - needs_sep_fix = true; - if (out_normalized != nullptr) { - *out_normalized = false; - return ResultSuccess(); - } - } - if (PathNormalizer::IsAnySeparator(path[i])) { - if (path[i] == StringTraits::AlternateDirectorySeparator) { - needs_sep_fix = true; - } - - if (cur_part_ofs != 0) { - break; - } - - R_UNLESS(!PathNormalizer::IsSeparator(path[i + 1]), fs::ResultInvalidPathFormat()); - - R_TRY(CheckSharedName(path + 2, i - 2)); - - cur_part_ofs = i + 1; - } - if (path[i] == '$' || path[i] == StringTraits::DriveSeparator) { - R_UNLESS(cur_part_ofs != 0, fs::ResultInvalidCharacter()); - R_UNLESS(PathNormalizer::IsAnySeparator(path[i + 1]) || PathNormalizer::IsNullTerminator(path[i + 1]), fs::ResultInvalidPathFormat()); - trimmed_path = path + i + 1; - break; - } - } - - if (trimmed_path == path_start) { - int tr_part_ofs = 0; - int i; - for (i = 2; !PathNormalizer::IsNullTerminator(path[i]); ++i) { - if (PathNormalizer::IsAnySeparator(path[i])) { - if (tr_part_ofs != 0) { - R_TRY(CheckSharedName(path + tr_part_ofs, i - tr_part_ofs)); - trimmed_path = path + i; - break; - } - - R_UNLESS(!PathNormalizer::IsSeparator(path[i + 1]), fs::ResultInvalidPathFormat()); - - R_TRY(CheckSharedName(path + 2, i - 2)); - - cur_part_ofs = i + 1; - } - } - - if (tr_part_ofs != 0 && trimmed_path == path_start) { - R_TRY(CheckSharedName(path + tr_part_ofs, i - tr_part_ofs)); - trimmed_path = path + i; - } - } - - const size_t win_path_len = trimmed_path - path; - const bool prepend_sep = prefix_len != 0 || skipped_mount; - if (out != nullptr) { - R_UNLESS(win_path_len <= max_out_size, fs::ResultTooLongPath()); - if (prepend_sep) { - *(out++) = StringTraits::DirectorySeparator; - } - std::memcpy(out, path, win_path_len); - out[0] = StringTraits::AlternateDirectorySeparator; - out[1] = StringTraits::AlternateDirectorySeparator; - if (needs_sep_fix) { - for (size_t i = 2; i < win_path_len; ++i) { - if (PathNormalizer::IsSeparator(out[i])) { - out[i] = StringTraits::AlternateDirectorySeparator; - } - } - } - } - *out_path = trimmed_path; - *out_windows_path_len = win_path_len + (prepend_sep ? 1 : 0); - } else { - *out_path = trimmed_path; - } - - return ResultSuccess(); - } - - Result SkipWindowsPath(const char **out_path, bool *out_normalized, const char *path, bool has_mount_name) { - size_t windows_path_len; - return ParseWindowsPath(out_path, nullptr, std::addressof(windows_path_len), out_normalized, path, 0, has_mount_name); - } - - Result ParseMountName(const char **out_path, char *out, size_t *out_mount_name_len, const char *path, size_t max_out_size) { - /* Decide on a start. */ - const char *start = PathNormalizer::IsSeparator(path[0]) ? path + 1 : path; - - /* Find the end of the mount name. */ - const char *cur; - for (cur = start; cur < start + MountNameLengthMax + 1; ++cur) { - if (*cur == StringTraits::DriveSeparator) { - ++cur; - break; - } - if (PathNormalizer::IsSeparator(*cur)) { - *out_path = path; - *out_mount_name_len = 0; - return ResultSuccess(); - } - } - R_UNLESS(start < cur - 1, fs::ResultInvalidPathFormat()); - R_UNLESS(cur[-1] == StringTraits::DriveSeparator, fs::ResultInvalidPathFormat()); - - /* Check the mount name doesn't contain a dot. */ - if (cur != start) { - for (const char *p = start; p < cur; ++p) { - R_UNLESS(*p != StringTraits::Dot, fs::ResultInvalidCharacter()); - } - } - - const size_t mount_name_len = cur - path; - if (out != nullptr) { - R_UNLESS(mount_name_len <= max_out_size, fs::ResultTooLongPath()); - std::memcpy(out, path, mount_name_len); - } - *out_path = cur; - *out_mount_name_len = mount_name_len; - - return ResultSuccess(); - } - - Result SkipMountName(const char **out_path, const char *path) { - size_t mount_name_len; - return ParseMountName(out_path, nullptr, std::addressof(mount_name_len), path, 0); - } - - bool IsParentDirectoryPathReplacementNeeded(const char *path) { - if (!PathNormalizer::IsAnySeparator(path[0])) { - return false; - } - - for (auto i = 0; !PathNormalizer::IsNullTerminator(path[i]); ++i) { - if (path[i + 0] == StringTraits::AlternateDirectorySeparator && - path[i + 1] == StringTraits::Dot && - path[i + 2] == StringTraits::Dot && - (PathNormalizer::IsAnySeparator(path[i + 3]) || PathNormalizer::IsNullTerminator(path[i + 3]))) - { - return true; - } - - if (PathNormalizer::IsAnySeparator(path[i + 0]) && - path[i + 1] == StringTraits::Dot && - path[i + 2] == StringTraits::Dot && - path[i + 3] == StringTraits::AlternateDirectorySeparator) - { - return true; - } - } - - return false; - } - - void ReplaceParentDirectoryPath(char *dst, const char *src) { - dst[0] = StringTraits::DirectorySeparator; - - int i = 1; - while (!PathNormalizer::IsNullTerminator(src[i])) { - if (PathNormalizer::IsAnySeparator(src[i - 1]) && - src[i + 0] == StringTraits::Dot && - src[i + 1] == StringTraits::Dot && - PathNormalizer::IsAnySeparator(src[i + 2])) - { - dst[i - 1] = StringTraits::DirectorySeparator; - dst[i + 0] = StringTraits::Dot; - dst[i + 1] = StringTraits::Dot; - dst[i - 2] = StringTraits::DirectorySeparator; - i += 3; - } else { - if (src[i - 1] == StringTraits::AlternateDirectorySeparator && - src[i + 0] == StringTraits::Dot && - src[i + 1] == StringTraits::Dot && - PathNormalizer::IsNullTerminator(src[i + 2])) - { - dst[i - 1] = StringTraits::DirectorySeparator; - dst[i + 0] = StringTraits::Dot; - dst[i + 1] = StringTraits::Dot; - i += 2; - break; - } - - dst[i] = src[i]; - ++i; - } - } - - dst[i] = StringTraits::NullTerminator; - } - - } - - Result PathNormalizer::Normalize(char *out, size_t *out_len, const char *path, size_t max_out_size, bool unc_preserved, bool has_mount_name) { - /* Check pre-conditions. */ - AMS_ASSERT(out != nullptr); - AMS_ASSERT(out_len != nullptr); - AMS_ASSERT(path != nullptr); - - /* If we should, handle the mount name. */ - size_t prefix_len = 0; - if (has_mount_name) { - size_t mount_name_len = 0; - R_TRY(ParseMountName(std::addressof(path), out, std::addressof(mount_name_len), path, max_out_size)); - prefix_len += mount_name_len; - } - - /* Deal with unc. */ - bool is_unc_path = false; - if (unc_preserved) { - const char * const path_start = path; - size_t windows_path_len = 0; - R_TRY(ParseWindowsPath(std::addressof(path), out + prefix_len, std::addressof(windows_path_len), nullptr, path, max_out_size, has_mount_name)); - prefix_len += windows_path_len; - is_unc_path = path != path_start; - } - - /* Paths must start with / */ - R_UNLESS(prefix_len != 0 || IsSeparator(path[0]), fs::ResultInvalidPathFormat()); - - /* Check if parent directory path replacement is needed. */ - std::unique_ptr replacement_path; - if (IsParentDirectoryPathReplacementNeeded(path)) { - /* Allocate a buffer to hold the replacement path. */ - replacement_path = fs::impl::MakeUnique(EntryNameLengthMax + 1); - R_UNLESS(replacement_path != nullptr, fs::ResultAllocationFailureInNew()); - - /* Replace the path. */ - ReplaceParentDirectoryPath(replacement_path.get(), path); - - /* Set path to be the replacement path. */ - path = replacement_path.get(); - } - - bool skip_next_sep = false; - size_t i = 0; - size_t len = prefix_len; - - while (!IsNullTerminator(path[i])) { - if (IsSeparator(path[i])) { - /* Swallow separators. */ - while (IsSeparator(path[++i])) { } - if (IsNullTerminator(path[i])) { - break; - } - - /* Handle skip if needed */ - if (!skip_next_sep) { - if (len + 1 == max_out_size) { - out[len] = StringTraits::NullTerminator; - *out_len = len; - return fs::ResultTooLongPath(); - } - - out[len++] = StringTraits::DirectorySeparator; - } - skip_next_sep = false; - } - - /* See length of current dir. */ - size_t dir_len = 0; - while (!IsSeparator(path[i + dir_len]) && !IsNullTerminator(path[i + dir_len])) { - ++dir_len; - } - - if (IsCurrentDirectory(path + i)) { - skip_next_sep = true; - } else if (IsParentDirectory(path + i)) { - AMS_ASSERT(IsSeparator(out[len - 1])); - if (!is_unc_path) { - AMS_ASSERT(IsSeparator(out[prefix_len])); - } - - /* Walk up a directory. */ - if (len == prefix_len + 1) { - R_UNLESS(is_unc_path, fs::ResultDirectoryUnobtainable()); - --len; - } else { - len -= 2; - do { - if (IsSeparator(out[len])) { - break; - } - --len; - } while (len != prefix_len); - } - - if (!is_unc_path) { - AMS_ASSERT(IsSeparator(out[prefix_len])); - } - - AMS_ASSERT(len < max_out_size); - } else { - /* Copy, possibly truncating. */ - if (len + dir_len + 1 <= max_out_size) { - for (size_t j = 0; j < dir_len; ++j) { - out[len++] = path[i+j]; - } - } else { - const size_t copy_len = max_out_size - 1 - len; - for (size_t j = 0; j < copy_len; ++j) { - out[len++] = path[i+j]; - } - out[len] = StringTraits::NullTerminator; - *out_len = len; - return fs::ResultTooLongPath(); - } - } - - i += dir_len; - } - - if (skip_next_sep) { - --len; - } - - if (!is_unc_path && len == prefix_len && max_out_size > len) { - out[len++] = StringTraits::DirectorySeparator; - } - - R_UNLESS(max_out_size >= len - 1, fs::ResultTooLongPath()); - - /* Null terminate. */ - out[len] = StringTraits::NullTerminator; - *out_len = len; - - /* Assert normalized. */ - { - bool normalized = false; - const auto is_norm_result = IsNormalized(std::addressof(normalized), out, unc_preserved, has_mount_name); - R_ASSERT(is_norm_result); - AMS_ASSERT(normalized); - AMS_UNUSED(is_norm_result, normalized); - } - - return ResultSuccess(); - } - - Result PathNormalizer::IsNormalized(bool *out, const char *path, bool unc_preserved, bool has_mount_name) { - AMS_ASSERT(out != nullptr); - AMS_ASSERT(path != nullptr); - - /* Save the start of the path. */ - const char *path_start = path; - - /* If we should, skip the mount name. */ - if (has_mount_name) { - R_TRY(SkipMountName(std::addressof(path), path)); - R_UNLESS(IsSeparator(*path), fs::ResultInvalidPathFormat()); - } - - /* If we should, handle unc. */ - bool is_unc_path = false; - if (unc_preserved) { - path_start = path; - - /* Skip the windows path. */ - bool normalized_windows = false; - R_TRY(SkipWindowsPath(std::addressof(path), std::addressof(normalized_windows), path, has_mount_name)); - - /* If we're not windows-normalized, we're not normalized. */ - if (!normalized_windows) { - *out = false; - return ResultSuccess(); - } - - /* Handle the case where we're dealing with a unc path. */ - if (path != path_start) { - is_unc_path = true; - if (IsSeparator(path_start[0]) && IsSeparator(path_start[1])) { - *out = false; - return ResultSuccess(); - } - - if (IsNullTerminator(path[0])) { - *out = true; - return ResultSuccess(); - } - } - } - - /* Check if parent directory path replacement is needed. */ - if (IsParentDirectoryPathReplacementNeeded(path)) { - *out = false; - return ResultSuccess(); - } - - /* Nintendo uses a state machine here. */ - enum class PathState { - Start, - Normal, - FirstSeparator, - Separator, - CurrentDir, - ParentDir, - }; - - PathState state = PathState::Start; - for (const char *cur = path; *cur != StringTraits::NullTerminator; ++cur) { - const char c = *cur; - switch (state) { - case PathState::Start: - if (IsSeparator(c)) { - state = PathState::FirstSeparator; - } else { - R_UNLESS(path != path_start, fs::ResultInvalidPathFormat()); - if (c == StringTraits::Dot) { - state = PathState::CurrentDir; - } else { - state = PathState::Normal; - } - } - break; - case PathState::Normal: - if (IsSeparator(c)) { - state = PathState::Separator; - } - break; - case PathState::FirstSeparator: - case PathState::Separator: - if (IsSeparator(c)) { - *out = false; - return ResultSuccess(); - } else if (c == StringTraits::Dot) { - state = PathState::CurrentDir; - } else { - state = PathState::Normal; - } - break; - case PathState::CurrentDir: - if (IsSeparator(c)) { - *out = false; - return ResultSuccess(); - } else if (c == StringTraits::Dot) { - state = PathState::ParentDir; - } else { - state = PathState::Normal; - } - break; - case PathState::ParentDir: - if (IsSeparator(c)) { - *out = false; - return ResultSuccess(); - } else { - state = PathState::Normal; - } - break; - AMS_UNREACHABLE_DEFAULT_CASE(); - } - } - - switch (state) { - case PathState::Start: - return fs::ResultInvalidPathFormat(); - case PathState::Normal: - *out = true; - break; - case PathState::FirstSeparator: - *out = !is_unc_path; - break; - case PathState::CurrentDir: - case PathState::ParentDir: - case PathState::Separator: - *out = false; - break; - AMS_UNREACHABLE_DEFAULT_CASE(); - } - - return ResultSuccess(); - } - -} diff --git a/libraries/libstratosphere/source/fs/fs_path_utils.cpp b/libraries/libstratosphere/source/fs/fs_path_utils.cpp deleted file mode 100644 index 2fd86e883..000000000 --- a/libraries/libstratosphere/source/fs/fs_path_utils.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (c) 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 - -namespace ams::fs { - - namespace { - - class PathVerifier { - private: - u32 m_invalid_chars[6]; - u32 m_separators[2]; - public: - PathVerifier() { - /* Convert all invalid characters. */ - u32 *dst_invalid = m_invalid_chars; - for (const char *cur = ":*?<>|"; *cur != '\x00'; ++cur) { - AMS_ASSERT(dst_invalid < std::end(m_invalid_chars)); - - const auto result = util::ConvertCharacterUtf8ToUtf32(dst_invalid, cur); - AMS_ASSERT(result == util::CharacterEncodingResult_Success); - AMS_UNUSED(result); - - ++dst_invalid; - } - AMS_ASSERT(dst_invalid == std::end(m_invalid_chars)); - - /* Convert all separators. */ - u32 *dst_sep = m_separators; - for (const char *cur = "/\\"; *cur != '\x00'; ++cur) { - AMS_ASSERT(dst_sep < std::end(m_separators)); - - const auto result = util::ConvertCharacterUtf8ToUtf32(dst_sep, cur); - AMS_ASSERT(result == util::CharacterEncodingResult_Success); - AMS_UNUSED(result); - - ++dst_sep; - } - AMS_ASSERT(dst_sep == std::end(m_separators)); - } - - Result Verify(const char *path, int max_path_len, int max_name_len) const { - AMS_ASSERT(path != nullptr); - - auto cur = path; - auto name_len = 0; - - for (auto path_len = 0; path_len <= max_path_len && name_len <= max_name_len; ++path_len) { - /* We're done, if the path is terminated. */ - R_SUCCEED_IF(*cur == '\x00'); - - /* Get the current utf-8 character. */ - util::CharacterEncodingResult result; - char char_buf[4] = {}; - result = util::PickOutCharacterFromUtf8String(char_buf, std::addressof(cur)); - R_UNLESS(result == util::CharacterEncodingResult_Success, fs::ResultInvalidCharacter()); - - /* Convert the current utf-8 character to utf-32. */ - u32 path_char = 0; - result = util::ConvertCharacterUtf8ToUtf32(std::addressof(path_char), char_buf); - R_UNLESS(result == util::CharacterEncodingResult_Success, fs::ResultInvalidCharacter()); - - /* Check if the character is invalid. */ - for (const auto invalid : m_invalid_chars) { - R_UNLESS(path_char != invalid, fs::ResultInvalidCharacter()); - } - - /* Increment name length. */ - ++name_len; - - /* Check for separator. */ - for (const auto sep : m_separators) { - if (path_char == sep) { - name_len = 0; - break; - } - } - } - - /* The path was too long. */ - return fs::ResultTooLongPath(); - } - }; - - PathVerifier g_path_verifier; - - } - - Result VerifyPath(const char *path, int max_path_len, int max_name_len) { - return g_path_verifier.Verify(path, max_path_len, max_name_len); - } - - bool IsSubPath(const char *lhs, const char *rhs) { - AMS_ASSERT(lhs != nullptr); - AMS_ASSERT(rhs != nullptr); - - /* Special case certain paths. */ - if (IsUnc(lhs) && !IsUnc(rhs)) { - return false; - } - if (!IsUnc(lhs) && IsUnc(rhs)) { - return false; - } - if (PathNormalizer::IsSeparator(lhs[0]) && PathNormalizer::IsNullTerminator(lhs[1]) && PathNormalizer::IsSeparator(rhs[0]) && !PathNormalizer::IsNullTerminator(rhs[1])) { - return true; - } - if (PathNormalizer::IsSeparator(rhs[0]) && PathNormalizer::IsNullTerminator(rhs[1]) && PathNormalizer::IsSeparator(lhs[0]) && !PathNormalizer::IsNullTerminator(lhs[1])) { - return true; - } - - /* Check subpath. */ - for (size_t i = 0; /* No terminating condition */; i++) { - if (PathNormalizer::IsNullTerminator(lhs[i])) { - return PathNormalizer::IsSeparator(rhs[i]); - } else if (PathNormalizer::IsNullTerminator(rhs[i])) { - return PathNormalizer::IsSeparator(lhs[i]); - } else if (lhs[i] != rhs[i]) { - return false; - } - } - } - -} diff --git a/libraries/libstratosphere/source/fs/fs_priority.cpp b/libraries/libstratosphere/source/fs/fs_priority.cpp index 2b06781fa..9fe88a96f 100644 --- a/libraries/libstratosphere/source/fs/fs_priority.cpp +++ b/libraries/libstratosphere/source/fs/fs_priority.cpp @@ -118,7 +118,7 @@ namespace ams::fs { Priority GetPriority(os::ThreadType *thread) { fs::Priority priority; - AMS_FS_R_ABORT_UNLESS(AMS_FS_IMPL_ACCESS_LOG(GetPriorityImpl(std::addressof(priority), thread), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_THREAD_ID, thread != nullptr ? os::GetThreadId(thread) : static_cast(0))); + AMS_FS_R_ABORT_UNLESS(AMS_FS_IMPL_ACCESS_LOG(GetPriorityImpl(std::addressof(priority), thread), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_THREAD_ID, reinterpret_cast(thread != nullptr ? os::GetThreadId(thread) : os::ThreadId{}))); return priority; } @@ -137,7 +137,7 @@ namespace ams::fs { PriorityRaw GetPriorityRaw(os::ThreadType *thread) { fs::PriorityRaw priority_raw; - AMS_FS_R_ABORT_UNLESS(AMS_FS_IMPL_ACCESS_LOG(GetPriorityRawImpl(std::addressof(priority_raw), thread), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_THREAD_ID, thread != nullptr ? os::GetThreadId(thread) : static_cast(0))); + AMS_FS_R_ABORT_UNLESS(AMS_FS_IMPL_ACCESS_LOG(GetPriorityRawImpl(std::addressof(priority_raw), thread), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_THREAD_ID, reinterpret_cast(thread != nullptr ? os::GetThreadId(thread) : os::ThreadId{}))); return priority_raw; } @@ -146,7 +146,7 @@ namespace ams::fs { } void SetPriority(os::ThreadType *thread, Priority priority) { - AMS_FS_R_ABORT_UNLESS(AMS_FS_IMPL_ACCESS_LOG(SetPriorityImpl(os::GetCurrentThread(), priority), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_THREAD_ID, thread != nullptr ? os::GetThreadId(thread) : static_cast(0))); + AMS_FS_R_ABORT_UNLESS(AMS_FS_IMPL_ACCESS_LOG(SetPriorityImpl(os::GetCurrentThread(), priority), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_THREAD_ID, reinterpret_cast(thread != nullptr ? os::GetThreadId(thread) : os::ThreadId{}))); } void SetPriorityRawOnCurrentThread(PriorityRaw priority_raw) { @@ -154,7 +154,7 @@ namespace ams::fs { } void SetPriorityRaw(os::ThreadType *thread, PriorityRaw priority_raw) { - AMS_FS_R_ABORT_UNLESS(AMS_FS_IMPL_ACCESS_LOG(SetPriorityRawImpl(os::GetCurrentThread(), priority_raw), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_THREAD_ID, thread != nullptr ? os::GetThreadId(thread) : static_cast(0))); + AMS_FS_R_ABORT_UNLESS(AMS_FS_IMPL_ACCESS_LOG(SetPriorityRawImpl(os::GetCurrentThread(), priority_raw), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_THREAD_ID, reinterpret_cast(thread != nullptr ? os::GetThreadId(thread) : os::ThreadId{}))); } } diff --git a/libraries/libstratosphere/source/fs/fs_remote_file_system_proxy.cpp b/libraries/libstratosphere/source/fs/fs_remote_file_system_proxy.cpp new file mode 100644 index 000000000..db61eb682 --- /dev/null +++ b/libraries/libstratosphere/source/fs/fs_remote_file_system_proxy.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) 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 "fs_remote_file_system_proxy.hpp" +#include "fs_remote_file_system_proxy_for_loader.hpp" + +#if defined(ATMOSPHERE_BOARD_NINTENDO_NX) +extern "C" { + + extern u32 __nx_fs_num_sessions; + +} +#endif + +namespace ams::fs { + + #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) + RemoteFileSystemProxy::RemoteFileSystemProxy(int session_count) { + /* Ensure we can connect to sm. */ + R_ABORT_UNLESS(sm::Initialize()); + ON_SCOPE_EXIT { R_ABORT_UNLESS(sm::Finalize()); }; + + /* Initialize libnx. */ + __nx_fs_num_sessions = static_cast(session_count); + R_ABORT_UNLESS(::fsInitialize()); + } + + RemoteFileSystemProxy::~RemoteFileSystemProxy() { + ::fsExit(); + } + + RemoteFileSystemProxyForLoader::RemoteFileSystemProxyForLoader() { + /* Ensure we can connect to sm. */ + R_ABORT_UNLESS(sm::Initialize()); + ON_SCOPE_EXIT { R_ABORT_UNLESS(sm::Finalize()); }; + + R_ABORT_UNLESS(::fsldrInitialize()); + } + + RemoteFileSystemProxyForLoader::~RemoteFileSystemProxyForLoader() { + ::fsldrExit(); + } + #endif + +} diff --git a/libraries/libstratosphere/source/fs/fs_remote_file_system_proxy.hpp b/libraries/libstratosphere/source/fs/fs_remote_file_system_proxy.hpp new file mode 100644 index 000000000..0d21aaf05 --- /dev/null +++ b/libraries/libstratosphere/source/fs/fs_remote_file_system_proxy.hpp @@ -0,0 +1,467 @@ +/* + * Copyright (c) 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 +#include "../fssrv/impl/fssrv_allocator_for_service_framework.hpp" +#include "impl/fs_remote_event_notifier.hpp" +#include "impl/fs_remote_device_operator.hpp" + +namespace ams::fs { + + #if defined(ATMOSPHERE_OS_HORIZON) + + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wunused-parameter" + + class RemoteFileSystemProxy { + NON_COPYABLE(RemoteFileSystemProxy); + NON_MOVEABLE(RemoteFileSystemProxy); + private: + using ObjectFactory = fssrv::impl::FileSystemObjectFactory; + public: + RemoteFileSystemProxy(int session_count); + ~RemoteFileSystemProxy(); + public: + /* Command interface */ + Result OpenFileSystem(ams::sf::Out> out, const fssrv::sf::FspPath &path, u32 type) { + AMS_ABORT("TODO"); + } + + + Result SetCurrentProcess(const ams::sf::ClientProcessId &client_pid) { + /* Libnx does this for us automatically. */ + AMS_UNUSED(client_pid); + R_SUCCEED(); + } + + Result OpenDataFileSystemByCurrentProcess(ams::sf::Out> out) { + AMS_ABORT("TODO"); + } + + Result OpenFileSystemWithPatch(ams::sf::Out> out, ncm::ProgramId program_id, u32 type) { + AMS_ABORT("TODO"); + } + + + Result OpenFileSystemWithId(ams::sf::Out> out, const fssrv::sf::FspPath &path, u64 program_id, u32 type) { + ::FsFileSystem fs; + R_TRY(fsOpenFileSystemWithId(std::addressof(fs), program_id, static_cast<::FsFileSystemType>(type), path.str)); + + out.SetValue(ObjectFactory::CreateSharedEmplaced(fs)); + R_SUCCEED(); + } + + Result OpenDataFileSystemByProgramId(ams::sf::Out> out, ncm::ProgramId program_id) { + AMS_ABORT("TODO"); + } + + + Result OpenBisFileSystem(ams::sf::Out> out, const fssrv::sf::FspPath &path, u32 id) { + AMS_ABORT("TODO"); + } + + + Result OpenBisStorage(ams::sf::Out> out, u32 id) { + FsStorage s; + R_TRY(fsOpenBisStorage(std::addressof(s), static_cast<::FsBisPartitionId>(id))); + + out.SetValue(ObjectFactory::CreateSharedEmplaced(s)); + R_SUCCEED(); + } + + Result InvalidateBisCache() { + AMS_ABORT("TODO"); + } + + Result OpenHostFileSystem(ams::sf::Out> out, const fssrv::sf::FspPath &path) { + AMS_ABORT("TODO"); + } + + + Result OpenSdCardFileSystem(ams::sf::Out> out) { + ::FsFileSystem fs; + R_TRY(fsOpenSdCardFileSystem(std::addressof(fs))); + + out.SetValue(ObjectFactory::CreateSharedEmplaced(fs)); + R_SUCCEED(); + } + + Result FormatSdCardFileSystem() { + AMS_ABORT("TODO"); + } + + + Result DeleteSaveDataFileSystem(u64 save_data_id) { + AMS_UNUSED(save_data_id); + AMS_ABORT("TODO: libnx binding"); + } + + Result CreateSaveDataFileSystem(const fs::SaveDataAttribute &attribute, const fs::SaveDataCreationInfo &creation_info, const fs::SaveDataMetaInfo &meta_info) { + AMS_ABORT("TODO"); + } + + + Result CreateSaveDataFileSystemBySystemSaveDataId(const fs::SaveDataAttribute &attribute, const fs::SaveDataCreationInfo &creation_info) { + static_assert(sizeof(attribute) == sizeof(::FsSaveDataAttribute)); + static_assert(sizeof(creation_info) == sizeof(::FsSaveDataCreationInfo)); + R_RETURN(fsCreateSaveDataFileSystemBySystemSaveDataId(reinterpret_cast(std::addressof(attribute)), reinterpret_cast(std::addressof(creation_info)))); + } + + Result RegisterSaveDataFileSystemAtomicDeletion(const ams::sf::InBuffer &save_data_ids) { + AMS_ABORT("TODO"); + } + + + Result DeleteSaveDataFileSystemBySaveDataSpaceId(u8 indexer_space_id, u64 save_data_id) { + R_RETURN(fsDeleteSaveDataFileSystemBySaveDataSpaceId(static_cast<::FsSaveDataSpaceId>(indexer_space_id), save_data_id)); + } + + Result FormatSdCardDryRun() { + AMS_ABORT("TODO"); + } + + Result IsExFatSupported(ams::sf::Out out) { + AMS_ABORT("TODO"); + } + + + Result DeleteSaveDataFileSystemBySaveDataAttribute(u8 space_id, const fs::SaveDataAttribute &attribute) { + static_assert(sizeof(attribute) == sizeof(::FsSaveDataAttribute)); + R_RETURN(fsDeleteSaveDataFileSystemBySaveDataAttribute(static_cast<::FsSaveDataSpaceId>(space_id), reinterpret_cast(std::addressof(attribute)))); + } + + Result OpenGameCardStorage(ams::sf::Out> out, u32 handle, u32 partition) { + AMS_ABORT("TODO"); + } + + + Result OpenGameCardFileSystem(ams::sf::Out> out, u32 handle, u32 partition) { + ::FsFileSystem fs; + const ::FsGameCardHandle _hnd = {handle}; + R_TRY(fsOpenGameCardFileSystem(std::addressof(fs), std::addressof(_hnd), static_cast<::FsGameCardPartition>(partition))); + + out.SetValue(ObjectFactory::CreateSharedEmplaced(fs)); + R_SUCCEED(); + } + + Result ExtendSaveDataFileSystem(u8 space_id, u64 save_data_id, s64 available_size, s64 journal_size) { + R_RETURN(::fsExtendSaveDataFileSystem(static_cast<::FsSaveDataSpaceId>(space_id), save_data_id, available_size, journal_size)); + } + + Result DeleteCacheStorage(u16 index) { + AMS_ABORT("TODO"); + } + + Result GetCacheStorageSize(ams::sf::Out out_size, ams::sf::Out out_journal_size, u16 index) { + AMS_ABORT("TODO"); + } + + Result CreateSaveDataFileSystemWithHashSalt(const fs::SaveDataAttribute &attribute, const fs::SaveDataCreationInfo &creation_info, const fs::SaveDataMetaInfo &meta_info, const fs::HashSalt &salt) { + AMS_ABORT("TODO"); + } + + Result OpenHostFileSystemWithOption(ams::sf::Out> out, const fssrv::sf::FspPath &path, u32 option) { + AMS_ABORT("TODO"); + } + + + Result OpenSaveDataFileSystem(ams::sf::Out> out, u8 space_id, const fs::SaveDataAttribute &attribute) { + ::FsFileSystem fs; + R_TRY(fsOpenSaveDataFileSystem(std::addressof(fs), static_cast<::FsSaveDataSpaceId>(space_id), reinterpret_cast(std::addressof(attribute)))); + + out.SetValue(ObjectFactory::CreateSharedEmplaced(fs)); + R_SUCCEED(); + } + + Result OpenSaveDataFileSystemBySystemSaveDataId(ams::sf::Out> out, u8 space_id, const fs::SaveDataAttribute &attribute) { + ::FsFileSystem fs; + R_TRY(fsOpenSaveDataFileSystemBySystemSaveDataId(std::addressof(fs), static_cast<::FsSaveDataSpaceId>(space_id), reinterpret_cast(std::addressof(attribute)))); + + out.SetValue(ObjectFactory::CreateSharedEmplaced(fs)); + R_SUCCEED(); + } + + Result OpenReadOnlySaveDataFileSystem(ams::sf::Out> out, u8 space_id, const fs::SaveDataAttribute &attribute) { + AMS_ABORT("TODO"); + } + + + Result ReadSaveDataFileSystemExtraDataBySaveDataSpaceId(const ams::sf::OutBuffer &buffer, u8 space_id, u64 save_data_id) { + R_RETURN(fsReadSaveDataFileSystemExtraDataBySaveDataSpaceId(buffer.GetPointer(), buffer.GetSize(), static_cast<::FsSaveDataSpaceId>(space_id), save_data_id)); + } + + Result ReadSaveDataFileSystemExtraData(const ams::sf::OutBuffer &buffer, u64 save_data_id) { + R_RETURN(fsReadSaveDataFileSystemExtraData(buffer.GetPointer(), buffer.GetSize(), save_data_id)); + } + + Result WriteSaveDataFileSystemExtraData(u64 save_data_id, u8 space_id, const ams::sf::InBuffer &buffer) { + R_RETURN(fsWriteSaveDataFileSystemExtraData(buffer.GetPointer(), buffer.GetSize(), static_cast<::FsSaveDataSpaceId>(space_id), save_data_id)); + } + + /* ... */ + + Result OpenImageDirectoryFileSystem(ams::sf::Out> out, u32 id) { + ::FsFileSystem fs; + R_TRY(fsOpenImageDirectoryFileSystem(std::addressof(fs), static_cast<::FsImageDirectoryId>(id))); + + out.SetValue(ObjectFactory::CreateSharedEmplaced(fs)); + R_SUCCEED(); + } + + /* ... */ + + Result OpenContentStorageFileSystem(ams::sf::Out> out, u32 id) { + ::FsFileSystem fs; + R_TRY(fsOpenContentStorageFileSystem(std::addressof(fs), static_cast<::FsContentStorageId>(id))); + + out.SetValue(ObjectFactory::CreateSharedEmplaced(fs)); + R_SUCCEED(); + } + + /* ... */ + + Result OpenDataStorageByCurrentProcess(ams::sf::Out> out) { + AMS_ABORT("TODO"); + } + + Result OpenDataStorageByProgramId(ams::sf::Out> out, ncm::ProgramId program_id) { + AMS_ABORT("TODO"); + } + + Result OpenDataStorageByDataId(ams::sf::Out> out, ncm::DataId data_id, u8 storage_id) { + ::FsStorage s; + R_TRY(fsOpenDataStorageByDataId(std::addressof(s), data_id.value, static_cast<::NcmStorageId>(storage_id))); + + out.SetValue(ObjectFactory::CreateSharedEmplaced(s)); + R_SUCCEED(); + } + Result OpenPatchDataStorageByCurrentProcess(ams::sf::Out> out) { + AMS_ABORT("TODO"); + } + + Result OpenDataFileSystemWithProgramIndex(ams::sf::Out> out, u8 index) { + AMS_ABORT("TODO"); + } + + Result OpenDataStorageWithProgramIndex(ams::sf::Out> out, u8 index) { + AMS_ABORT("TODO"); + } + + Result OpenDataStorageByPath(ams::sf::Out> out, const fssrv::sf::FspPath &path, u32 type) { + AMS_ABORT("TODO"); + } + + Result OpenDeviceOperator(ams::sf::Out> out) { + ::FsDeviceOperator d; + R_TRY(fsOpenDeviceOperator(std::addressof(d))); + + out.SetValue(ObjectFactory::CreateSharedEmplaced(d)); + R_SUCCEED(); + } + + Result OpenSdCardDetectionEventNotifier(ams::sf::Out> out) { + ::FsEventNotifier e; + R_TRY(fsOpenSdCardDetectionEventNotifier(std::addressof(e))); + + out.SetValue(ObjectFactory::CreateSharedEmplaced(e)); + R_SUCCEED(); + } + + Result OpenGameCardDetectionEventNotifier(ams::sf::Out> out) { + AMS_ABORT("TODO"); + } + + Result OpenSystemDataUpdateEventNotifier(ams::sf::Out> out) { + AMS_ABORT("TODO"); + } + + Result NotifySystemDataUpdateEvent() { + AMS_ABORT("TODO"); + } + + /* ... */ + + Result SetCurrentPosixTime(s64 posix_time) { + AMS_ABORT("TODO"); + } + + /* ... */ + + Result GetRightsId(ams::sf::Out out, ncm::ProgramId program_id, ncm::StorageId storage_id) { + AMS_ABORT("TODO"); + } + + Result RegisterExternalKey(const fs::RightsId &rights_id, const spl::AccessKey &access_key) { + AMS_ABORT("TODO"); + } + + Result UnregisterAllExternalKey() { + AMS_ABORT("TODO"); + } + + + Result GetRightsIdByPath(ams::sf::Out out, const fssrv::sf::FspPath &path) { + static_assert(sizeof(RightsId) == sizeof(::FsRightsId)); + R_RETURN(fsGetRightsIdByPath(path.str, reinterpret_cast<::FsRightsId *>(out.GetPointer()))); + } + + Result GetRightsIdAndKeyGenerationByPath(ams::sf::Out out, ams::sf::Out out_key_generation, const fssrv::sf::FspPath &path) { + static_assert(sizeof(RightsId) == sizeof(::FsRightsId)); + R_RETURN(fsGetRightsIdAndKeyGenerationByPath(path.str, out_key_generation.GetPointer(), reinterpret_cast<::FsRightsId *>(out.GetPointer()))); + } + + Result SetCurrentPosixTimeWithTimeDifference(s64 posix_time, s32 time_difference) { + AMS_ABORT("TODO"); + } + + Result GetFreeSpaceSizeForSaveData(ams::sf::Out out, u8 space_id) { + AMS_ABORT("TODO"); + } + + Result VerifySaveDataFileSystemBySaveDataSpaceId() { + AMS_ABORT("TODO"); + } + + Result CorruptSaveDataFileSystemBySaveDataSpaceId() { + AMS_ABORT("TODO"); + } + + Result QuerySaveDataInternalStorageTotalSize() { + AMS_ABORT("TODO"); + } + + Result GetSaveDataCommitId() { + AMS_ABORT("TODO"); + } + + Result UnregisterExternalKey(const fs::RightsId &rights_id) { + AMS_ABORT("TODO"); + } + + Result SetSdCardEncryptionSeed(const fs::EncryptionSeed &seed) { + AMS_ABORT("TODO"); + } + + Result SetSdCardAccessibility(bool accessible) { + AMS_ABORT("TODO"); + } + + Result IsSdCardAccessible(ams::sf::Out out) { + AMS_ABORT("TODO"); + } + + Result IsSignedSystemPartitionOnSdCardValid(ams::sf::Out out) { + R_RETURN(fsIsSignedSystemPartitionOnSdCardValid(out.GetPointer())); + } + + Result OpenAccessFailureDetectionEventNotifier() { + AMS_ABORT("TODO"); + } + + /* ... */ + + Result RegisterProgramIndexMapInfo(const ams::sf::InBuffer &buffer, s32 count) { + AMS_ABORT("TODO"); + } + + Result SetBisRootForHost(u32 id, const fssrv::sf::FspPath &path) { + AMS_ABORT("TODO"); + } + + Result SetSaveDataSize(s64 size, s64 journal_size) { + AMS_ABORT("TODO"); + } + + Result SetSaveDataRootPath(const fssrv::sf::FspPath &path) { + AMS_ABORT("TODO"); + } + + Result DisableAutoSaveDataCreation() { + R_RETURN(::fsDisableAutoSaveDataCreation()); + } + + Result SetGlobalAccessLogMode(u32 mode) { + R_RETURN(::fsSetGlobalAccessLogMode(mode)); + } + + Result GetGlobalAccessLogMode(sf::Out out) { + R_RETURN(::fsGetGlobalAccessLogMode(out.GetPointer())); + } + + Result OutputAccessLogToSdCard(const ams::sf::InBuffer &buf) { + R_RETURN(::fsOutputAccessLogToSdCard(reinterpret_cast(buf.GetPointer()), buf.GetSize())); + } + + Result RegisterUpdatePartition() { + AMS_ABORT("TODO"); + } + + Result OpenRegisteredUpdatePartition(ams::sf::Out> out) { + AMS_ABORT("TODO"); + } + + /* ... */ + + Result GetProgramIndexForAccessLog(ams::sf::Out out_idx, ams::sf::Out out_count) { + R_RETURN(::fsGetProgramIndexForAccessLog(out_idx.GetPointer(), out_count.GetPointer())); + } + + Result GetFsStackUsage(ams::sf::Out out, u32 type) { + AMS_ABORT("TODO"); + } + + Result UnsetSaveDataRootPath() { + AMS_ABORT("TODO"); + } + + Result OutputMultiProgramTagAccessLog() { + AMS_ABORT("TODO"); + } + + Result FlushAccessLogOnSdCard() { + AMS_ABORT("TODO"); + } + + Result OutputApplicationInfoAccessLog() { + AMS_ABORT("TODO"); + } + + Result RegisterDebugConfiguration(u32 key, s64 value) { + AMS_ABORT("TODO"); + } + + Result UnregisterDebugConfiguration(u32 key) { + AMS_ABORT("TODO"); + } + + Result OverrideSaveDataTransferTokenSignVerificationKey(const ams::sf::InBuffer &buf) { + AMS_ABORT("TODO"); + } + + Result CorruptSaveDataFileSystemByOffset(u8 space_id, u64 save_data_id, s64 offset) { + AMS_ABORT("TODO"); + } + + /* ... */ + }; + static_assert(fssrv::sf::IsIFileSystemProxy); + + #pragma GCC diagnostic pop + + #endif + +} diff --git a/libraries/libstratosphere/source/fs/fs_remote_file_system_proxy_for_loader.hpp b/libraries/libstratosphere/source/fs/fs_remote_file_system_proxy_for_loader.hpp new file mode 100644 index 000000000..a7cca39b3 --- /dev/null +++ b/libraries/libstratosphere/source/fs/fs_remote_file_system_proxy_for_loader.hpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 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 +#include "../fssrv/impl/fssrv_allocator_for_service_framework.hpp" + +namespace ams::fs { + + #if defined(ATMOSPHERE_OS_HORIZON) + class RemoteFileSystemProxyForLoader { + NON_COPYABLE(RemoteFileSystemProxyForLoader); + NON_MOVEABLE(RemoteFileSystemProxyForLoader); + private: + using ObjectFactory = fssrv::impl::FileSystemObjectFactory; + public: + RemoteFileSystemProxyForLoader(); + ~RemoteFileSystemProxyForLoader(); + public: + Result OpenCodeFileSystemDeprecated(ams::sf::Out> out_fs, const fssrv::sf::Path &path, ncm::ProgramId program_id) { + ::FsCodeInfo dummy; + ::FsFileSystem fs; + R_TRY(fsldrOpenCodeFileSystem(std::addressof(dummy), program_id.value, path.str, std::addressof(fs))); + + out_fs.SetValue(ObjectFactory::CreateSharedEmplaced(fs)); + R_SUCCEED(); + } + + Result OpenCodeFileSystem(ams::sf::Out> out_fs, ams::sf::Out out_verif, const fssrv::sf::Path &path, ncm::ProgramId program_id) { + ::FsFileSystem fs; + R_TRY(fsldrOpenCodeFileSystem(reinterpret_cast<::FsCodeInfo *>(out_verif.GetPointer()), program_id.value, path.str, std::addressof(fs))); + + out_fs.SetValue(ObjectFactory::CreateSharedEmplaced(fs)); + R_SUCCEED(); + } + + Result IsArchivedProgram(ams::sf::Out out, u64 process_id) { + R_RETURN(fsldrIsArchivedProgram(process_id, out.GetPointer())); + } + + Result SetCurrentProcess(const ams::sf::ClientProcessId &client_pid) { + /* Libnx does this for us automatically. */ + AMS_UNUSED(client_pid); + R_SUCCEED(); + } + }; + static_assert(fssrv::sf::IsIFileSystemProxyForLoader); + #endif + +} diff --git a/libraries/libstratosphere/source/fs/fs_rights_id.cpp b/libraries/libstratosphere/source/fs/fs_rights_id.cpp index 87460246e..a090cefbb 100644 --- a/libraries/libstratosphere/source/fs/fs_rights_id.cpp +++ b/libraries/libstratosphere/source/fs/fs_rights_id.cpp @@ -15,17 +15,37 @@ */ #include #include +#include "impl/fs_file_system_proxy_service_object.hpp" namespace ams::fs { Result GetRightsId(RightsId *out, const char *path) { - static_assert(sizeof(RightsId) == sizeof(::FsRightsId)); - return fsGetRightsIdByPath(path, reinterpret_cast<::FsRightsId *>(out)); + AMS_FS_R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); + AMS_FS_R_UNLESS(path != nullptr, fs::ResultNullptrArgument()); + + /* Convert the path for fsp. */ + fssrv::sf::FspPath sf_path; + R_TRY(fs::ConvertToFspPath(std::addressof(sf_path), path)); + + auto fsp = impl::GetFileSystemProxyServiceObject(); + AMS_FS_R_TRY(fsp->GetRightsIdByPath(out, sf_path)); + + R_SUCCEED(); } Result GetRightsId(RightsId *out, u8 *out_key_generation, const char *path) { - static_assert(sizeof(RightsId) == sizeof(::FsRightsId)); - return fsGetRightsIdAndKeyGenerationByPath(path, out_key_generation, reinterpret_cast<::FsRightsId *>(out)); + AMS_FS_R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); + AMS_FS_R_UNLESS(out_key_generation != nullptr, fs::ResultNullptrArgument()); + AMS_FS_R_UNLESS(path != nullptr, fs::ResultNullptrArgument()); + + /* Convert the path for fsp. */ + fssrv::sf::FspPath sf_path; + R_TRY(fs::ConvertToFspPath(std::addressof(sf_path), path)); + + auto fsp = impl::GetFileSystemProxyServiceObject(); + AMS_FS_R_TRY(fsp->GetRightsIdAndKeyGenerationByPath(out, out_key_generation, sf_path)); + + R_SUCCEED(); } } \ No newline at end of file diff --git a/libraries/libstratosphere/source/fs/fs_romfs_filesystem.cpp b/libraries/libstratosphere/source/fs/fs_romfs_filesystem.cpp index 7a222663d..f6c7b9e32 100644 --- a/libraries/libstratosphere/source/fs/fs_romfs_filesystem.cpp +++ b/libraries/libstratosphere/source/fs/fs_romfs_filesystem.cpp @@ -266,11 +266,11 @@ namespace ams::fs { RomFsDirectory(RomFsFileSystem *p, const FindPosition &f, fs::OpenDirectoryMode m) : m_parent(p), m_current_find(f), m_first_find(f), m_mode(m) { /* ... */ } virtual ~RomFsDirectory() override { /* ... */ } public: - virtual Result DoRead(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries) { + virtual Result DoRead(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries) override { return this->ReadInternal(out_count, std::addressof(m_current_find), out_entries, max_entries); } - virtual Result DoGetEntryCount(s64 *out) { + virtual Result DoGetEntryCount(s64 *out) override { FindPosition find = m_first_find; return this->ReadInternal(out, std::addressof(find), nullptr, 0); } @@ -293,9 +293,10 @@ namespace ams::fs { } R_END_TRY_CATCH; if (out_entries) { - R_UNLESS(strnlen(name_buf, NameBufferSize) < NameBufferSize, fs::ResultTooLongPath()); - strncpy(out_entries[i].name, name_buf, fs::EntryNameLengthMax); - out_entries[i].name[fs::EntryNameLengthMax] = '\x00'; + const size_t name_len = util::Strnlen(name_buf, NameBufferSize); + R_UNLESS(name_len < NameBufferSize, fs::ResultTooLongPath()); + std::memcpy(out_entries[i].name, name_buf, name_len); + out_entries[i].name[name_len] = '\x00'; out_entries[i].type = fs::DirectoryEntryType_Directory; out_entries[i].file_size = 0; } @@ -313,9 +314,10 @@ namespace ams::fs { } R_END_TRY_CATCH; if (out_entries) { - R_UNLESS(strnlen(name_buf, NameBufferSize) < NameBufferSize, fs::ResultTooLongPath()); - strncpy(out_entries[i].name, name_buf, fs::EntryNameLengthMax); - out_entries[i].name[fs::EntryNameLengthMax] = '\x00'; + const size_t name_len = util::Strnlen(name_buf, NameBufferSize); + R_UNLESS(name_len < NameBufferSize, fs::ResultTooLongPath()); + std::memcpy(out_entries[i].name, name_buf, name_len); + out_entries[i].name[name_len] = '\x00'; out_entries[i].type = fs::DirectoryEntryType_File; RomFsFileSystem::RomFileTable::FileInfo file_info; @@ -443,48 +445,48 @@ namespace ams::fs { return ResultSuccess(); } - Result RomFsFileSystem::DoCreateFile(const char *path, s64 size, int flags) { + Result RomFsFileSystem::DoCreateFile(const fs::Path &path, s64 size, int flags) { AMS_UNUSED(path, size, flags); return fs::ResultUnsupportedOperationInRomFsFileSystemA(); } - Result RomFsFileSystem::DoDeleteFile(const char *path) { + Result RomFsFileSystem::DoDeleteFile(const fs::Path &path) { AMS_UNUSED(path); return fs::ResultUnsupportedOperationInRomFsFileSystemA(); } - Result RomFsFileSystem::DoCreateDirectory(const char *path) { + Result RomFsFileSystem::DoCreateDirectory(const fs::Path &path) { AMS_UNUSED(path); return fs::ResultUnsupportedOperationInRomFsFileSystemA(); } - Result RomFsFileSystem::DoDeleteDirectory(const char *path) { + Result RomFsFileSystem::DoDeleteDirectory(const fs::Path &path) { AMS_UNUSED(path); return fs::ResultUnsupportedOperationInRomFsFileSystemA(); } - Result RomFsFileSystem::DoDeleteDirectoryRecursively(const char *path) { + Result RomFsFileSystem::DoDeleteDirectoryRecursively(const fs::Path &path) { AMS_UNUSED(path); return fs::ResultUnsupportedOperationInRomFsFileSystemA(); } - Result RomFsFileSystem::DoRenameFile(const char *old_path, const char *new_path) { + Result RomFsFileSystem::DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) { AMS_UNUSED(old_path, new_path); return fs::ResultUnsupportedOperationInRomFsFileSystemA(); } - Result RomFsFileSystem::DoRenameDirectory(const char *old_path, const char *new_path) { + Result RomFsFileSystem::DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) { AMS_UNUSED(old_path, new_path); return fs::ResultUnsupportedOperationInRomFsFileSystemA(); } - Result RomFsFileSystem::DoGetEntryType(fs::DirectoryEntryType *out, const char *path) { + Result RomFsFileSystem::DoGetEntryType(fs::DirectoryEntryType *out, const fs::Path &path) { RomDirectoryInfo dir_info; - R_TRY_CATCH(m_rom_file_table.GetDirectoryInformation(std::addressof(dir_info), path)) { + R_TRY_CATCH(m_rom_file_table.GetDirectoryInformation(std::addressof(dir_info), path.GetString())) { R_CONVERT(fs::ResultDbmNotFound, fs::ResultPathNotFound()) R_CATCH(fs::ResultDbmInvalidOperation) { RomFileTable::FileInfo file_info; - R_TRY(this->GetFileInfo(std::addressof(file_info), path)); + R_TRY(this->GetFileInfo(std::addressof(file_info), path.GetString())); *out = fs::DirectoryEntryType_File; return ResultSuccess(); } @@ -494,14 +496,13 @@ namespace ams::fs { return ResultSuccess(); } - Result RomFsFileSystem::DoOpenFile(std::unique_ptr *out_file, const char *path, fs::OpenMode mode) { + Result RomFsFileSystem::DoOpenFile(std::unique_ptr *out_file, const fs::Path &path, fs::OpenMode mode) { AMS_ASSERT(out_file != nullptr); - AMS_ASSERT(path != nullptr); R_UNLESS((mode & fs::OpenMode_All) == fs::OpenMode_Read, fs::ResultInvalidOpenMode()); RomFileTable::FileInfo file_info; - R_TRY(this->GetFileInfo(std::addressof(file_info), path)); + R_TRY(this->GetFileInfo(std::addressof(file_info), path.GetString())); auto file = std::make_unique(this, m_entry_size + file_info.offset.Get(), m_entry_size + file_info.offset.Get() + file_info.size.Get()); R_UNLESS(file != nullptr, fs::ResultAllocationFailureInRomFsFileSystemB()); @@ -510,12 +511,11 @@ namespace ams::fs { return ResultSuccess(); } - Result RomFsFileSystem::DoOpenDirectory(std::unique_ptr *out_dir, const char *path, fs::OpenDirectoryMode mode) { + Result RomFsFileSystem::DoOpenDirectory(std::unique_ptr *out_dir, const fs::Path &path, fs::OpenDirectoryMode mode) { AMS_ASSERT(out_dir != nullptr); - AMS_ASSERT(path != nullptr); RomFileTable::FindPosition find; - R_TRY_CATCH(m_rom_file_table.FindOpen(std::addressof(find), path)) { + R_TRY_CATCH(m_rom_file_table.FindOpen(std::addressof(find), path.GetString())) { R_CONVERT(fs::ResultDbmNotFound, fs::ResultPathNotFound()) R_CONVERT(fs::ResultDbmInvalidOperation, fs::ResultPathNotFound()) } R_END_TRY_CATCH; @@ -531,19 +531,19 @@ namespace ams::fs { return ResultSuccess(); } - Result RomFsFileSystem::DoGetFreeSpaceSize(s64 *out, const char *path) { + Result RomFsFileSystem::DoGetFreeSpaceSize(s64 *out, const fs::Path &path) { AMS_UNUSED(path); *out = 0; return ResultSuccess(); } - Result RomFsFileSystem::DoGetTotalSpaceSize(s64 *out, const char *path) { + Result RomFsFileSystem::DoGetTotalSpaceSize(s64 *out, const fs::Path &path) { AMS_UNUSED(out, path); return fs::ResultUnsupportedOperationInRomFsFileSystemC(); } - Result RomFsFileSystem::DoCleanDirectoryRecursively(const char *path) { + Result RomFsFileSystem::DoCleanDirectoryRecursively(const fs::Path &path) { AMS_UNUSED(path); return fs::ResultUnsupportedOperationInRomFsFileSystemA(); } diff --git a/libraries/libstratosphere/source/fs/fs_save_data_management.cpp b/libraries/libstratosphere/source/fs/fs_save_data_management.cpp index c9335a9ea..51ff1d14d 100644 --- a/libraries/libstratosphere/source/fs/fs_save_data_management.cpp +++ b/libraries/libstratosphere/source/fs/fs_save_data_management.cpp @@ -15,45 +15,56 @@ */ #include #include "fsa/fs_mount_utils.hpp" +#include "impl/fs_file_system_proxy_service_object.hpp" namespace ams::fs { namespace impl { Result ReadSaveDataFileSystemExtraData(SaveDataExtraData *out, SaveDataId id) { - return fsReadSaveDataFileSystemExtraData(out, sizeof(*out), id); + auto fsp = impl::GetFileSystemProxyServiceObject(); + AMS_FS_R_TRY(fsp->ReadSaveDataFileSystemExtraData(sf::OutBuffer(out, sizeof(*out)), id)); + R_SUCCEED(); } Result ReadSaveDataFileSystemExtraData(SaveDataExtraData *out, SaveDataSpaceId space_id, SaveDataId id) { - return fsReadSaveDataFileSystemExtraDataBySaveDataSpaceId(out, sizeof(*out), static_cast<::FsSaveDataSpaceId>(space_id), id); + auto fsp = impl::GetFileSystemProxyServiceObject(); + AMS_FS_R_TRY(fsp->ReadSaveDataFileSystemExtraDataBySaveDataSpaceId(sf::OutBuffer(out, sizeof(*out)), static_cast(space_id), id)); + R_SUCCEED(); } Result WriteSaveDataFileSystemExtraData(SaveDataSpaceId space_id, SaveDataId id, const SaveDataExtraData &extra_data) { - return fsWriteSaveDataFileSystemExtraData(std::addressof(extra_data), sizeof(extra_data), static_cast<::FsSaveDataSpaceId>(space_id), id); + auto fsp = impl::GetFileSystemProxyServiceObject(); + AMS_FS_R_TRY(fsp->WriteSaveDataFileSystemExtraData(id, static_cast(space_id), sf::InBuffer(std::addressof(extra_data), sizeof(extra_data)))); + R_SUCCEED(); } } void DisableAutoSaveDataCreation() { - /* Use libnx binding. */ - R_ABORT_UNLESS(fsDisableAutoSaveDataCreation()); + auto fsp = impl::GetFileSystemProxyServiceObject(); + AMS_FS_R_ABORT_UNLESS(fsp->DisableAutoSaveDataCreation()); } Result CreateSystemSaveData(SaveDataSpaceId space_id, SystemSaveDataId save_id, UserId user_id, u64 owner_id, s64 size, s64 journal_size, u32 flags) { - const auto attribute = SaveDataAttribute::Make(ncm::InvalidProgramId, SaveDataType::System, user_id, save_id); - const SaveDataCreationInfo info = { - .size = size, - .journal_size = journal_size, - .block_size = DefaultSaveDataBlockSize, - .owner_id = owner_id, - .flags = flags, - .space_id = space_id, - .pseudo = false, + auto create_impl = [=]() -> Result { + const auto attribute = SaveDataAttribute::Make(ncm::InvalidProgramId, SaveDataType::System, user_id, save_id); + const SaveDataCreationInfo info = { + .size = size, + .journal_size = journal_size, + .block_size = DefaultSaveDataBlockSize, + .owner_id = owner_id, + .flags = flags, + .space_id = space_id, + .pseudo = false, + }; + + auto fsp = impl::GetFileSystemProxyServiceObject(); + R_RETURN(fsp->CreateSaveDataFileSystemBySystemSaveDataId(attribute, info)); }; - static_assert(sizeof(SaveDataAttribute) == sizeof(::FsSaveDataAttribute)); - static_assert(sizeof(SaveDataCreationInfo) == sizeof(::FsSaveDataCreationInfo)); - return fsCreateSaveDataFileSystemBySystemSaveDataId(reinterpret_cast(std::addressof(attribute)), reinterpret_cast(std::addressof(info))); + AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM(create_impl(), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_CREATE_SYSTEM_SAVE_DATA(space_id, save_id, user_id, owner_id, size, journal_size, flags))); + R_SUCCEED(); } Result CreateSystemSaveData(SystemSaveDataId save_id, s64 size, s64 journal_size, u32 flags) { @@ -77,20 +88,35 @@ namespace ams::fs { } Result DeleteSaveData(SaveDataId id) { - /* TODO: Libnx binding for DeleteSaveDataFileSystem */ - AMS_UNUSED(id); - AMS_ABORT(); + auto delete_impl = [=]() -> Result { + auto fsp = impl::GetFileSystemProxyServiceObject(); + R_RETURN(fsp->DeleteSaveDataFileSystem(id)); + }; + + AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM(delete_impl(), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_ID, id)); + R_SUCCEED(); } Result DeleteSaveData(SaveDataSpaceId space_id, SaveDataId id) { - return fsDeleteSaveDataFileSystemBySaveDataSpaceId(static_cast<::FsSaveDataSpaceId>(space_id), id); + auto delete_impl = [=]() -> Result { + auto fsp = impl::GetFileSystemProxyServiceObject(); + R_RETURN(fsp->DeleteSaveDataFileSystemBySaveDataSpaceId(static_cast(space_id), id)); + }; + + AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM(delete_impl(), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_DELETE_SAVE_DATA(space_id, id))); + R_SUCCEED(); } Result DeleteSystemSaveData(SaveDataSpaceId space_id, SystemSaveDataId id, UserId user_id) { - const auto attribute = SaveDataAttribute::Make(ncm::InvalidProgramId, SaveDataType::System, user_id, id); + auto delete_impl = [=]() -> Result { + const auto attribute = SaveDataAttribute::Make(ncm::InvalidProgramId, SaveDataType::System, user_id, id); - static_assert(sizeof(attribute) == sizeof(::FsSaveDataAttribute)); - return fsDeleteSaveDataFileSystemBySaveDataAttribute(static_cast<::FsSaveDataSpaceId>(space_id), reinterpret_cast(std::addressof(attribute))); + auto fsp = impl::GetFileSystemProxyServiceObject(); + R_RETURN(fsp->DeleteSaveDataFileSystemBySaveDataAttribute(static_cast(space_id), attribute)); + }; + + AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM(delete_impl(), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_DELETE_SYSTEM_SAVE_DATA(space_id, id, user_id))); + R_SUCCEED(); } Result GetSaveDataFlags(u32 *out, SaveDataId id) { @@ -133,7 +159,13 @@ namespace ams::fs { } Result ExtendSaveData(SaveDataSpaceId space_id, SaveDataId id, s64 available_size, s64 journal_size) { - return ::fsExtendSaveDataFileSystem(static_cast<::FsSaveDataSpaceId>(space_id), static_cast(id), available_size, journal_size); + auto extend_impl = [=]() -> Result { + auto fsp = impl::GetFileSystemProxyServiceObject(); + R_RETURN(fsp->ExtendSaveDataFileSystem(static_cast(space_id), id, available_size, journal_size)); + }; + + AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM(extend_impl(), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_EXTEND_SAVE_DATA(space_id, id, available_size, journal_size))); + R_SUCCEED(); } } diff --git a/libraries/libstratosphere/source/fs/fs_sd_card.cpp b/libraries/libstratosphere/source/fs/fs_sd_card.cpp index 186febf4e..a317ccb54 100644 --- a/libraries/libstratosphere/source/fs/fs_sd_card.cpp +++ b/libraries/libstratosphere/source/fs/fs_sd_card.cpp @@ -15,7 +15,9 @@ */ #include #include "fsa/fs_mount_utils.hpp" -#include "impl/fs_event_notifier_object_adapter.hpp" +#include "impl/fs_file_system_proxy_service_object.hpp" +#include "impl/fs_file_system_service_object_adapter.hpp" +#include "impl/fs_event_notifier_service_object_adapter.hpp" namespace ams::fs { @@ -31,7 +33,7 @@ namespace ams::fs { virtual Result GenerateCommonMountName(char *dst, size_t dst_size) override { /* Determine how much space we need. */ - const size_t needed_size = strnlen(impl::SdCardFileSystemMountName, MountNameLengthMax) + 2; + const size_t needed_size = util::Strnlen(impl::SdCardFileSystemMountName, MountNameLengthMax) + 2; AMS_ABORT_UNLESS(dst_size >= needed_size); /* Generate the name. */ @@ -47,14 +49,15 @@ namespace ams::fs { Result MountSdCard(const char *name) { /* Validate the mount name. */ - R_TRY(impl::CheckMountNameAllowingReserved(name)); + AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT_UNLESS_R_SUCCEEDED(impl::CheckMountNameAllowingReserved(name), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT, name)); - /* Open the SD card. This uses libnx bindings. */ - FsFileSystem fs; - R_TRY(fsOpenSdCardFileSystem(std::addressof(fs))); + /* Open the SD card filesystem. */ + auto fsp = impl::GetFileSystemProxyServiceObject(); + sf::SharedPointer fs; + R_TRY(fsp->OpenSdCardFileSystem(std::addressof(fs))); /* Allocate a new filesystem wrapper. */ - auto fsa = std::make_unique(fs); + auto fsa = std::make_unique(std::move(fs)); R_UNLESS(fsa != nullptr, fs::ResultAllocationFailureInSdCardA()); /* Allocate a new mountname generator. */ @@ -70,47 +73,53 @@ namespace ams::fs { /* Validate the mount name. */ R_TRY(impl::CheckMountName(name)); - /* Open the SD card. This uses libnx bindings. */ - FsFileSystem fs; - R_TRY(fsOpenSdCardFileSystem(std::addressof(fs))); + /* Open the SD card filesystem. */ + auto fsp = impl::GetFileSystemProxyServiceObject(); + sf::SharedPointer fs; + R_TRY(fsp->OpenSdCardFileSystem(std::addressof(fs))); /* Allocate a new filesystem wrapper. */ - std::unique_ptr fsa = std::make_unique(fs); + auto fsa = std::make_shared(std::move(fs)); R_UNLESS(fsa != nullptr, fs::ResultAllocationFailureInSdCardA()); /* Ensure that the error report directory exists. */ - R_TRY(fssystem::EnsureDirectoryRecursively(fsa.get(), AtmosphereErrorReportDirectory)); + constexpr fs::Path fs_path = fs::MakeConstantPath(AtmosphereErrorReportDirectory); + R_TRY(fssystem::EnsureDirectory(fsa.get(), fs_path)); /* Create a subdirectory filesystem. */ - auto subdir_fs = std::make_unique(std::move(fsa), AtmosphereErrorReportDirectory); + auto subdir_fs = std::make_unique(std::move(fsa)); R_UNLESS(subdir_fs != nullptr, fs::ResultAllocationFailureInSdCardA()); + R_TRY(subdir_fs->Initialize(fs_path)); /* Register. */ return fsa::Register(name, std::move(subdir_fs)); } Result OpenSdCardDetectionEventNotifier(std::unique_ptr *out) { + auto fsp = impl::GetFileSystemProxyServiceObject(); + /* Try to open an event notifier. */ - FsEventNotifier notifier; - AMS_FS_R_TRY(fsOpenSdCardDetectionEventNotifier(std::addressof(notifier))); + sf::SharedPointer notifier; + AMS_FS_R_TRY(fsp->OpenSdCardDetectionEventNotifier(std::addressof(notifier))); /* Create an event notifier adapter. */ - auto adapter = std::make_unique(notifier); - R_UNLESS(adapter != nullptr, fs::ResultAllocationFailureInSdCardB()); + auto adapter = std::make_unique(std::move(notifier)); + AMS_FS_R_UNLESS(adapter != nullptr, fs::ResultAllocationFailureInSdCardB()); *out = std::move(adapter); return ResultSuccess(); } bool IsSdCardInserted() { - /* Open device operator. */ - FsDeviceOperator device_operator; - AMS_FS_R_ABORT_UNLESS(::fsOpenDeviceOperator(std::addressof(device_operator))); - ON_SCOPE_EXIT { ::fsDeviceOperatorClose(std::addressof(device_operator)); }; + auto fsp = impl::GetFileSystemProxyServiceObject(); - /* Get SD card inserted. */ + /* Open a device operator. */ + sf::SharedPointer device_operator; + AMS_FS_R_ABORT_UNLESS(fsp->OpenDeviceOperator(std::addressof(device_operator))); + + /* Get insertion status. */ bool inserted; - AMS_FS_R_ABORT_UNLESS(::fsDeviceOperatorIsSdCardInserted(std::addressof(device_operator), std::addressof(inserted))); + AMS_FS_R_ABORT_UNLESS(device_operator->IsSdCardInserted(std::addressof(inserted))); return inserted; } diff --git a/libraries/libstratosphere/source/fs/fs_signed_system_partition.cpp b/libraries/libstratosphere/source/fs/fs_signed_system_partition.cpp index f6d44225b..7ef4c7736 100644 --- a/libraries/libstratosphere/source/fs/fs_signed_system_partition.cpp +++ b/libraries/libstratosphere/source/fs/fs_signed_system_partition.cpp @@ -16,21 +16,30 @@ #include #include "fsa/fs_filesystem_accessor.hpp" #include "fsa/fs_mount_utils.hpp" +#include "impl/fs_file_system_proxy_service_object.hpp" namespace ams::fs { + namespace { + + Result GetSignedSystemPartitionOnSdCardValid(char *out, impl::FileSystemAccessor *accessor) { + R_TRY_CATCH(accessor->QueryEntry(out, sizeof(*out), nullptr, 0, fsa::QueryId::IsSignedSystemPartitionOnSdCardValid, "/")) { + /* If querying isn't supported, then the partition isn't valid. */ + R_CATCH(fs::ResultUnsupportedOperation) { *out = false; } + } R_END_TRY_CATCH_WITH_ABORT_UNLESS; + R_SUCCEED(); + } + + } + bool IsSignedSystemPartitionOnSdCardValid(const char *system_root_path) { /* Get the accessor for the system filesystem. */ impl::FileSystemAccessor *accessor; const char *sub_path; - R_ABORT_UNLESS(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), system_root_path)); + AMS_FS_R_ABORT_UNLESS(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), system_root_path)); char is_valid; - R_TRY_CATCH(accessor->QueryEntry(std::addressof(is_valid), 1, nullptr, 0, fsa::QueryId::IsSignedSystemPartitionOnSdCardValid, "/")) { - /* If querying isn't supported, then the partition isn't valid. */ - R_CATCH(fs::ResultUnsupportedOperation) { is_valid = false; } - } R_END_TRY_CATCH_WITH_ABORT_UNLESS; - + AMS_FS_R_ABORT_UNLESS(GetSignedSystemPartitionOnSdCardValid(std::addressof(is_valid), accessor)); return is_valid; } @@ -40,8 +49,9 @@ namespace ams::fs { AMS_ABORT_UNLESS(hos::Version_4_0_0 <= version && version < hos::Version_8_0_0); /* Check that the partition is valid. */ + auto fsp = impl::GetFileSystemProxyServiceObject(); bool is_valid; - R_ABORT_UNLESS(fsIsSignedSystemPartitionOnSdCardValid(std::addressof(is_valid))); + AMS_FS_R_ABORT_UNLESS(fsp->IsSignedSystemPartitionOnSdCardValid(std::addressof(is_valid))); return is_valid; } diff --git a/libraries/libstratosphere/source/fs/fs_system_data.cpp b/libraries/libstratosphere/source/fs/fs_system_data.cpp index 3147c4b19..201f93fdd 100644 --- a/libraries/libstratosphere/source/fs/fs_system_data.cpp +++ b/libraries/libstratosphere/source/fs/fs_system_data.cpp @@ -19,15 +19,20 @@ namespace ams::fs { Result QueryMountSystemDataCacheSize(size_t *out, ncm::SystemDataId data_id) { - return impl::QueryMountDataCacheSize(out, data_id, ncm::StorageId::BuiltInSystem); + AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM(impl::QueryMountDataCacheSize(out, data_id, ncm::StorageId::BuiltInSystem), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_QUERY_MOUNT_SYSTEM_DATA_CACHE_SIZE(data_id, out))); + R_SUCCEED(); } Result MountSystemData(const char *name, ncm::SystemDataId data_id) { - return impl::MountData(name, data_id, ncm::StorageId::BuiltInSystem); + AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(impl::MountData(name, data_id, ncm::StorageId::BuiltInSystem), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_SYSTEM_DATA(name, data_id))); + AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name); + R_SUCCEED(); } Result MountSystemData(const char *name, ncm::SystemDataId data_id, void *cache_buffer, size_t cache_size) { - return impl::MountData(name, data_id, ncm::StorageId::BuiltInSystem, cache_buffer, cache_size); + AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(impl::MountData(name, data_id, ncm::StorageId::BuiltInSystem, cache_buffer, cache_size), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_SYSTEM_DATA(name, data_id))); + AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name); + R_SUCCEED(); } } diff --git a/libraries/libstratosphere/source/fs/fs_system_save_data.cpp b/libraries/libstratosphere/source/fs/fs_system_save_data.cpp index 5c8aa8940..139939585 100644 --- a/libraries/libstratosphere/source/fs/fs_system_save_data.cpp +++ b/libraries/libstratosphere/source/fs/fs_system_save_data.cpp @@ -15,33 +15,11 @@ */ #include #include "fsa/fs_mount_utils.hpp" +#include "impl/fs_file_system_proxy_service_object.hpp" +#include "impl/fs_file_system_service_object_adapter.hpp" namespace ams::fs { - namespace { - - Result MountSystemSaveDataImpl(const char *name, SaveDataSpaceId space_id, SystemSaveDataId id, UserId user_id, SaveDataType type) { - /* Validate the mount name. */ - R_TRY(impl::CheckMountName(name)); - - /* Create the attribute. */ - const auto attribute = SaveDataAttribute::Make(ncm::InvalidProgramId, type, user_id, id); - static_assert(sizeof(attribute) == sizeof(::FsSaveDataAttribute)); - - /* Open the filesystem, use libnx bindings. */ - ::FsFileSystem fs; - R_TRY(fsOpenSaveDataFileSystemBySystemSaveDataId(std::addressof(fs), static_cast<::FsSaveDataSpaceId>(space_id), reinterpret_cast(std::addressof(attribute)))); - - /* Allocate a new filesystem wrapper. */ - auto fsa = std::make_unique(fs); - R_UNLESS(fsa != nullptr, fs::ResultAllocationFailureInSystemSaveDataA()); - - /* Register. */ - return fsa::Register(name, std::move(fsa)); - } - - } - Result MountSystemSaveData(const char *name, SystemSaveDataId id) { return MountSystemSaveData(name, id, InvalidUserId); } @@ -55,7 +33,29 @@ namespace ams::fs { } Result MountSystemSaveData(const char *name, SaveDataSpaceId space_id, SystemSaveDataId id, UserId user_id) { - return MountSystemSaveDataImpl(name, space_id, id, user_id, SaveDataType::System); + auto mount_impl = [=]() -> Result { + /* Validate the mount name. */ + R_TRY(impl::CheckMountName(name)); + + /* Create the attribute. */ + const auto attribute = SaveDataAttribute::Make(ncm::InvalidProgramId, SaveDataType::System, user_id, id); + + /* Open the filesystem. */ + auto fsp = impl::GetFileSystemProxyServiceObject(); + sf::SharedPointer fs; + R_TRY(fsp->OpenSaveDataFileSystemBySystemSaveDataId(std::addressof(fs), static_cast(space_id), attribute)); + + /* Allocate a new filesystem wrapper. */ + auto fsa = std::make_unique(std::move(fs)); + R_UNLESS(fsa != nullptr, fs::ResultAllocationFailureInSystemSaveDataA()); + + /* Register. */ + return fsa::Register(name, std::move(fsa)); + }; + + AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(mount_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_SYSTEM_SAVE_DATA(name, space_id, id, user_id))); + AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name); + R_SUCCEED(); } } diff --git a/libraries/libstratosphere/source/fs/fsa/fs_filesystem_accessor.cpp b/libraries/libstratosphere/source/fs/fsa/fs_filesystem_accessor.cpp index ce00a1755..d90d1325e 100644 --- a/libraries/libstratosphere/source/fs/fsa/fs_filesystem_accessor.cpp +++ b/libraries/libstratosphere/source/fs/fsa/fs_filesystem_accessor.cpp @@ -24,7 +24,7 @@ namespace ams::fs::impl { template void Remove(List &list, Iter *desired) { - for (auto it = list.cbegin(); it != list.cend(); it++) { + for (auto it = list.cbegin(); it != list.cend(); ++it) { if (it.operator->() == desired) { list.erase(it); return; @@ -35,18 +35,13 @@ namespace ams::fs::impl { AMS_ABORT(); } - Result ValidatePath(const char *mount_name, const char *path) { - const size_t mount_name_len = strnlen(mount_name, MountNameLengthMax); - const size_t path_len = strnlen(path, EntryNameLengthMax); - R_UNLESS(mount_name_len + 1 + path_len <= EntryNameLengthMax, fs::ResultTooLongPath()); - - return ResultSuccess(); - } - - Result ValidateMountName(const char *name) { + Result SetMountName(char *dst, const char *name) { R_UNLESS(name[0] != 0, fs::ResultInvalidMountName()); - R_UNLESS(strnlen(name, sizeof(MountName)) < sizeof(MountName), fs::ResultInvalidMountName()); - return ResultSuccess(); + + const size_t n_len = util::Strlcpy(dst, name, MountNameLengthMax + 1); + R_UNLESS(n_len <= MountNameLengthMax, fs::ResultInvalidMountName()); + + R_SUCCEED(); } template @@ -54,18 +49,21 @@ namespace ams::fs::impl { for (auto it = list.cbegin(); it != list.cend(); it++) { R_UNLESS((it->GetOpenMode() & OpenMode_Write) == 0, fs::ResultWriteModeFileNotClosed()); } - return ResultSuccess(); + R_SUCCEED(); } } FileSystemAccessor::FileSystemAccessor(const char *n, std::unique_ptr &&fs, std::unique_ptr &&generator) : m_impl(std::move(fs)), m_open_list_lock(), m_mount_name_generator(std::move(generator)), - m_access_log_enabled(false), m_data_cache_attachable(false), m_path_cache_attachable(false), m_path_cache_attached(false), m_multi_commit_supported(false) + m_access_log_enabled(false), m_data_cache_attachable(false), m_path_cache_attachable(false), m_path_cache_attached(false), m_multi_commit_supported(false), + m_path_flags() { - R_ABORT_UNLESS(ValidateMountName(n)); - std::strncpy(m_name.str, n, MountNameLengthMax); - m_name.str[MountNameLengthMax] = 0; + R_ABORT_UNLESS(SetMountName(m_name.str, n)); + + if (std::strcmp(m_name.str, AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME) == 0) { + m_path_flags.AllowWindowsPath(); + } } FileSystemAccessor::~FileSystemAccessor() { @@ -83,13 +81,12 @@ namespace ams::fs::impl { Result FileSystemAccessor::GetCommonMountName(char *dst, size_t dst_size) const { R_UNLESS(m_mount_name_generator != nullptr, fs::ResultPreconditionViolation()); - return m_mount_name_generator->GenerateCommonMountName(dst, dst_size); + R_RETURN(m_mount_name_generator->GenerateCommonMountName(dst, dst_size)); } std::shared_ptr FileSystemAccessor::GetMultiCommitTarget() { if (m_multi_commit_supported) { - /* TODO: Support multi commit. */ - AMS_ABORT(); + AMS_ABORT("TODO: Support multi commit"); } return nullptr; } @@ -104,71 +101,126 @@ namespace ams::fs::impl { Remove(m_open_dir_list, d); } + Result FileSystemAccessor::SetUpPath(fs::Path *out, const char *p) { + /* Initialize the path appropriately. */ + bool normalized; + size_t len; + if (R_SUCCEEDED(PathFormatter::IsNormalized(std::addressof(normalized), std::addressof(len), p, m_path_flags)) && normalized) { + /* We can use the input buffer directly. */ + out->SetShallowBuffer(p); + } else { + /* Initialize with appropriate slash replacement. */ + if (m_path_flags.IsWindowsPathAllowed()) { + R_TRY(out->InitializeWithReplaceForwardSlashes(p)); + } else { + R_TRY(out->InitializeWithReplaceBackslash(p)); + } + + /* Ensure we're normalized. */ + R_TRY(out->Normalize(m_path_flags)); + } + + /* Check the path isn't too long. */ + R_UNLESS(out->GetLength() <= fs::EntryNameLengthMax, fs::ResultTooLongPath()); + R_SUCCEED(); + } + Result FileSystemAccessor::CreateFile(const char *path, s64 size, int option) { - R_TRY(ValidatePath(m_name.str, path)); + /* Create path. */ + fs::Path normalized_path; + R_TRY(this->SetUpPath(std::addressof(normalized_path), path)); + if (m_path_cache_attached) { /* TODO: Path cache */ - R_TRY(m_impl->CreateFile(path, size, option)); + R_TRY(m_impl->CreateFile(normalized_path, size, option)); } else { - R_TRY(m_impl->CreateFile(path, size, option)); + R_TRY(m_impl->CreateFile(normalized_path, size, option)); } - return ResultSuccess(); + + R_SUCCEED(); } Result FileSystemAccessor::DeleteFile(const char *path) { - R_TRY(ValidatePath(m_name.str, path)); - return m_impl->DeleteFile(path); + /* Create path. */ + fs::Path normalized_path; + R_TRY(this->SetUpPath(std::addressof(normalized_path), path)); + + R_RETURN(m_impl->DeleteFile(normalized_path)); } Result FileSystemAccessor::CreateDirectory(const char *path) { - R_TRY(ValidatePath(m_name.str, path)); - return m_impl->CreateDirectory(path); + /* Create path. */ + fs::Path normalized_path; + R_TRY(this->SetUpPath(std::addressof(normalized_path), path)); + + R_RETURN(m_impl->CreateDirectory(normalized_path)); } Result FileSystemAccessor::DeleteDirectory(const char *path) { - R_TRY(ValidatePath(m_name.str, path)); - return m_impl->DeleteDirectory(path); + /* Create path. */ + fs::Path normalized_path; + R_TRY(this->SetUpPath(std::addressof(normalized_path), path)); + + R_RETURN(m_impl->DeleteDirectory(normalized_path)); } Result FileSystemAccessor::DeleteDirectoryRecursively(const char *path) { - R_TRY(ValidatePath(m_name.str, path)); - return m_impl->DeleteDirectoryRecursively(path); + /* Create path. */ + fs::Path normalized_path; + R_TRY(this->SetUpPath(std::addressof(normalized_path), path)); + + R_RETURN(m_impl->DeleteDirectoryRecursively(normalized_path)); } Result FileSystemAccessor::RenameFile(const char *old_path, const char *new_path) { - R_TRY(ValidatePath(m_name.str, old_path)); - R_TRY(ValidatePath(m_name.str, new_path)); + /* Create path. */ + fs::Path normalized_old_path; + fs::Path normalized_new_path; + R_TRY(this->SetUpPath(std::addressof(normalized_old_path), old_path)); + R_TRY(this->SetUpPath(std::addressof(normalized_new_path), new_path)); + if (m_path_cache_attached) { /* TODO: Path cache */ - R_TRY(m_impl->RenameFile(old_path, new_path)); + R_TRY(m_impl->RenameFile(normalized_old_path, normalized_new_path)); } else { - R_TRY(m_impl->RenameFile(old_path, new_path)); + R_TRY(m_impl->RenameFile(normalized_old_path, normalized_new_path)); } - return ResultSuccess(); + + R_SUCCEED(); } Result FileSystemAccessor::RenameDirectory(const char *old_path, const char *new_path) { - R_TRY(ValidatePath(m_name.str, old_path)); - R_TRY(ValidatePath(m_name.str, new_path)); + /* Create path. */ + fs::Path normalized_old_path; + fs::Path normalized_new_path; + R_TRY(this->SetUpPath(std::addressof(normalized_old_path), old_path)); + R_TRY(this->SetUpPath(std::addressof(normalized_new_path), new_path)); + if (m_path_cache_attached) { /* TODO: Path cache */ - R_TRY(m_impl->RenameDirectory(old_path, new_path)); + R_TRY(m_impl->RenameDirectory(normalized_old_path, normalized_new_path)); } else { - R_TRY(m_impl->RenameDirectory(old_path, new_path)); + R_TRY(m_impl->RenameDirectory(normalized_old_path, normalized_new_path)); } - return ResultSuccess(); + + R_SUCCEED(); } Result FileSystemAccessor::GetEntryType(DirectoryEntryType *out, const char *path) { - R_TRY(ValidatePath(m_name.str, path)); - return m_impl->GetEntryType(out, path); + /* Create path. */ + fs::Path normalized_path; + R_TRY(this->SetUpPath(std::addressof(normalized_path), path)); + + R_RETURN(m_impl->GetEntryType(out, normalized_path)); } Result FileSystemAccessor::OpenFile(std::unique_ptr *out_file, const char *path, OpenMode mode) { - R_TRY(ValidatePath(m_name.str, path)); + /* Create path. */ + fs::Path normalized_path; + R_TRY(this->SetUpPath(std::addressof(normalized_path), path)); std::unique_ptr file; - R_TRY(m_impl->OpenFile(std::addressof(file), path, mode)); + R_TRY(m_impl->OpenFile(std::addressof(file), normalized_path, mode)); auto accessor = new FileAccessor(std::move(file), this, mode); R_UNLESS(accessor != nullptr, fs::ResultAllocationFailureInFileSystemAccessorA()); @@ -187,14 +239,16 @@ namespace ams::fs::impl { } out_file->reset(accessor); - return ResultSuccess(); + R_SUCCEED(); } Result FileSystemAccessor::OpenDirectory(std::unique_ptr *out_dir, const char *path, OpenDirectoryMode mode) { - R_TRY(ValidatePath(m_name.str, path)); + /* Create path. */ + fs::Path normalized_path; + R_TRY(this->SetUpPath(std::addressof(normalized_path), path)); std::unique_ptr dir; - R_TRY(m_impl->OpenDirectory(std::addressof(dir), path, mode)); + R_TRY(m_impl->OpenDirectory(std::addressof(dir), normalized_path, mode)); auto accessor = new DirectoryAccessor(std::move(dir), *this); R_UNLESS(accessor != nullptr, fs::ResultAllocationFailureInFileSystemAccessorB()); @@ -205,7 +259,7 @@ namespace ams::fs::impl { } out_dir->reset(accessor); - return ResultSuccess(); + R_SUCCEED(); } Result FileSystemAccessor::Commit() { @@ -213,30 +267,47 @@ namespace ams::fs::impl { std::scoped_lock lk(m_open_list_lock); R_ABORT_UNLESS(ValidateNoOpenWriteModeFiles(m_open_file_list)); } - return m_impl->Commit(); + R_RETURN(m_impl->Commit()); } Result FileSystemAccessor::GetFreeSpaceSize(s64 *out, const char *path) { - R_TRY(ValidatePath(m_name.str, path)); - return m_impl->GetFreeSpaceSize(out, path); + /* Create path. */ + fs::Path normalized_path; + R_TRY(this->SetUpPath(std::addressof(normalized_path), path)); + + R_RETURN(m_impl->GetFreeSpaceSize(out, normalized_path)); } Result FileSystemAccessor::GetTotalSpaceSize(s64 *out, const char *path) { - R_TRY(ValidatePath(m_name.str, path)); - return m_impl->GetTotalSpaceSize(out, path); + /* Create path. */ + fs::Path normalized_path; + R_TRY(this->SetUpPath(std::addressof(normalized_path), path)); + + R_RETURN(m_impl->GetTotalSpaceSize(out, normalized_path)); } Result FileSystemAccessor::CleanDirectoryRecursively(const char *path) { - R_TRY(ValidatePath(m_name.str, path)); - return m_impl->CleanDirectoryRecursively(path); + /* Create path. */ + fs::Path normalized_path; + R_TRY(this->SetUpPath(std::addressof(normalized_path), path)); + + R_RETURN(m_impl->CleanDirectoryRecursively(normalized_path)); } Result FileSystemAccessor::GetFileTimeStampRaw(FileTimeStampRaw *out, const char *path) { - return m_impl->GetFileTimeStampRaw(out, path); + /* Create path. */ + fs::Path normalized_path; + R_TRY(this->SetUpPath(std::addressof(normalized_path), path)); + + R_RETURN(m_impl->GetFileTimeStampRaw(out, normalized_path)); } Result FileSystemAccessor::QueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fsa::QueryId query, const char *path) { - return m_impl->QueryEntry(dst, dst_size, src, src_size, query, path); + /* Create path. */ + fs::Path normalized_path; + R_TRY(this->SetUpPath(std::addressof(normalized_path), path)); + + R_RETURN(m_impl->QueryEntry(dst, dst_size, src, src_size, query, normalized_path)); } diff --git a/libraries/libstratosphere/source/fs/fsa/fs_filesystem_accessor.hpp b/libraries/libstratosphere/source/fs/fsa/fs_filesystem_accessor.hpp index a7f8fbf41..d84206460 100644 --- a/libraries/libstratosphere/source/fs/fsa/fs_filesystem_accessor.hpp +++ b/libraries/libstratosphere/source/fs/fsa/fs_filesystem_accessor.hpp @@ -42,6 +42,7 @@ namespace ams::fs::impl { bool m_path_cache_attachable; bool m_path_cache_attached; bool m_multi_commit_supported; + PathFlags m_path_flags; public: FileSystemAccessor(const char *name, std::unique_ptr &&fs, std::unique_ptr &&generator = nullptr); virtual ~FileSystemAccessor(); @@ -93,6 +94,8 @@ namespace ams::fs::impl { private: void NotifyCloseFile(FileAccessor *f); void NotifyCloseDirectory(DirectoryAccessor *d); + public: + Result SetUpPath(fs::Path *out, const char *p); }; } diff --git a/libraries/libstratosphere/source/fs/fsa/fs_mount_utils.cpp b/libraries/libstratosphere/source/fs/fsa/fs_mount_utils.cpp index a10653aed..6937ac7f0 100644 --- a/libraries/libstratosphere/source/fs/fsa/fs_mount_utils.cpp +++ b/libraries/libstratosphere/source/fs/fsa/fs_mount_utils.cpp @@ -23,22 +23,32 @@ namespace ams::fs::impl { namespace { const char *FindMountNameDriveSeparator(const char *path) { - for (const char *cur = path; cur < path + MountNameLengthMax + 1; cur++) { + for (const char *cur = path; cur < path + MountNameLengthMax + 1 && *cur != StringTraits::NullTerminator; ++cur) { if (*cur == StringTraits::DriveSeparator) { return cur; - } else if (PathNormalizer::IsNullTerminator(*cur)) { - break; } } return nullptr; } + constexpr bool IsHostRootPath(const char *path) { + #if defined(ATMOSPHERE_OS_HORIZON) || defined(ATMOSPHERE_OS_WINDOWS) + return fs::IsWindowsDrive(path) || fs::IsUncPath(path); + #elif defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS) + return fs::IsPathAbsolute(path); + #else + #error "Unknown OS for host path identification" + #endif + } + Result GetMountNameAndSubPath(MountName *out_mount_name, const char **out_sub_path, const char *path) { /* Handle the Host-path case. */ - if (fs::IsWindowsDrive(path) || fs::IsUnc(path)) { + if (IsHostRootPath(path)) { std::strncpy(out_mount_name->str, HostRootFileSystemMountName, MountNameLengthMax); out_mount_name->str[MountNameLengthMax] = '\x00'; - return ResultSuccess(); + + *out_sub_path = path; + R_SUCCEED(); } /* Locate the drive separator. */ @@ -47,34 +57,37 @@ namespace ams::fs::impl { /* Ensure the mount name isn't too long. */ const size_t len = drive_separator - path; + R_UNLESS(0 < len, fs::ResultInvalidMountName()); R_UNLESS(len <= MountNameLengthMax, fs::ResultInvalidMountName()); /* Ensure the result sub-path is valid. */ const char *sub_path = drive_separator + 1; - R_UNLESS(!PathNormalizer::IsNullTerminator(sub_path[0]), fs::ResultInvalidMountName()); - R_UNLESS(PathNormalizer::IsAnySeparator(sub_path[0]), fs::ResultInvalidPathFormat()); + + const auto starts_with_dir = (sub_path[0] == StringTraits::DirectorySeparator) || (sub_path[0] == StringTraits::AlternateDirectorySeparator); + R_UNLESS(starts_with_dir, fs::ResultInvalidPathFormat()); /* Set output. */ std::memcpy(out_mount_name->str, path, len); out_mount_name->str[len] = StringTraits::NullTerminator; + *out_sub_path = sub_path; - return ResultSuccess(); + R_SUCCEED(); } } bool IsValidMountName(const char *name) { - if (PathNormalizer::IsNullTerminator(name[0])) { + if (name[0] == StringTraits::NullTerminator) { return false; } - if ((('a' <= name[0] && name[0] <= 'z') || ('A' <= name[0] && name[0] <= 'Z')) && PathNormalizer::IsNullTerminator(name[1])) { + if ((('a' <= name[0] && name[0] <= 'z') || ('A' <= name[0] && name[0] <= 'Z')) && name[1] == StringTraits::NullTerminator) { return false; } size_t len = 0; - for (const char *cur = name; !PathNormalizer::IsNullTerminator(*cur); cur++) { - if (*cur == StringTraits::DriveSeparator || PathNormalizer::IsSeparator(*cur)) { + for (const char *cur = name; *cur != StringTraits::NullTerminator; ++cur) { + if (*cur == StringTraits::DriveSeparator || *cur == StringTraits::DirectorySeparator) { return false; } @@ -83,8 +96,7 @@ namespace ams::fs::impl { } } - /* TODO: N validates that the mount name decodes via utf-8 here. */ - return true; + return util::VerifyUtf8String(name, len); } bool IsReservedMountName(const char *name) { @@ -108,7 +120,7 @@ namespace ams::fs::impl { R_UNLESS(out_sub_path != nullptr, fs::ResultUnexpectedInFindFileSystemA()); R_UNLESS(path != nullptr, fs::ResultNullptrArgument()); - R_UNLESS(strncmp(path, HostRootFileSystemMountName, strnlen(HostRootFileSystemMountName, sizeof(MountName))) != 0, fs::ResultNotMounted()); + R_UNLESS(strncmp(path, HostRootFileSystemMountName, util::Strnlen(HostRootFileSystemMountName, sizeof(MountName))) != 0, fs::ResultNotMounted()); MountName mount_name; R_TRY(GetMountNameAndSubPath(std::addressof(mount_name), out_sub_path, path)); @@ -132,10 +144,6 @@ namespace ams::fs::impl { namespace ams::fs { - namespace { - - } - Result ConvertToFsCommonPath(char *dst, size_t dst_size, const char *src) { /* Ensure neither argument is nullptr. */ AMS_FS_R_UNLESS(dst != nullptr, fs::ResultNullptrArgument()); @@ -150,7 +158,7 @@ namespace ams::fs { AMS_FS_R_TRY(impl::Find(std::addressof(accessor), mount_name.str)); AMS_FS_R_TRY(accessor->GetCommonMountName(dst, dst_size)); - const auto mount_name_len = strnlen(dst, dst_size); + const auto mount_name_len = util::Strnlen(dst, dst_size); const auto common_path_len = util::SNPrintf(dst + mount_name_len, dst_size - mount_name_len, "%s", sub_path); AMS_FS_R_UNLESS(static_cast(common_path_len) < dst_size - mount_name_len, fs::ResultTooLongPath()); diff --git a/libraries/libstratosphere/source/fs/fsa/fs_user_filesystem.cpp b/libraries/libstratosphere/source/fs/fsa/fs_user_filesystem.cpp index 6a4e0267f..6d8f21660 100644 --- a/libraries/libstratosphere/source/fs/fsa/fs_user_filesystem.cpp +++ b/libraries/libstratosphere/source/fs/fsa/fs_user_filesystem.cpp @@ -164,62 +164,27 @@ namespace ams::fs { } Result GetFreeSpaceSize(s64 *out, const char *path) { + /* Find the filesystem without access logging. */ impl::FileSystemAccessor *accessor; - const char *sub_path = nullptr; + const char *sub_path; + AMS_FS_R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path)); - /* Get the accessor. */ - auto find_impl = [&]() -> Result { - R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); - R_UNLESS(path != nullptr, fs::ResultNullptrArgument()); - if (impl::IsValidMountName(path)) { - R_TRY(impl::Find(std::addressof(accessor), path)); - } else { - R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path)); - } - return ResultSuccess(); - }; + /* Get the total space size. */ + AMS_FS_R_TRY(accessor->GetFreeSpaceSize(out, sub_path)); - AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED(find_impl(), AMS_FS_IMPL_ACCESS_LOG_FORMAT_GET_SPACE_SIZE(out, path))); - - /* Get the space size. */ - auto get_size_impl = [&]() -> Result { - R_UNLESS(sub_path == nullptr || std::strcmp(sub_path, "/") == 0, fs::ResultInvalidMountName()); - R_TRY(accessor->GetFreeSpaceSize(out, "/")); - return ResultSuccess(); - }; - - AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_FILESYSTEM(get_size_impl(), nullptr, accessor, AMS_FS_IMPL_ACCESS_LOG_FORMAT_GET_SPACE_SIZE(out, path))); - return ResultSuccess(); + R_SUCCEED(); } Result GetTotalSpaceSize(s64 *out, const char *path) { - /* NOTE: Nintendo does not do access logging here, and does not support mount-name instead of path. */ + /* Find the filesystem without access logging. */ impl::FileSystemAccessor *accessor; - const char *sub_path = nullptr; + const char *sub_path; + AMS_FS_R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path)); - /* Get the accessor. */ - auto find_impl = [&]() -> Result { - R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); - R_UNLESS(path != nullptr, fs::ResultNullptrArgument()); - if (impl::IsValidMountName(path)) { - R_TRY(impl::Find(std::addressof(accessor), path)); - } else { - R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path)); - } - return ResultSuccess(); - }; + /* Get the total space size. */ + AMS_FS_R_TRY(accessor->GetTotalSpaceSize(out, sub_path)); - AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED(find_impl(), AMS_FS_IMPL_ACCESS_LOG_FORMAT_GET_SPACE_SIZE(out, path))); - - /* Get the space size. */ - auto get_size_impl = [&]() -> Result { - R_UNLESS(sub_path == nullptr || std::strcmp(sub_path, "/") == 0, fs::ResultInvalidMountName()); - R_TRY(accessor->GetTotalSpaceSize(out, "/")); - return ResultSuccess(); - }; - - AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_FILESYSTEM(get_size_impl(), nullptr, accessor, AMS_FS_IMPL_ACCESS_LOG_FORMAT_GET_SPACE_SIZE(out, path))); - return ResultSuccess(); + R_SUCCEED(); } Result SetConcatenationFileAttribute(const char *path) { @@ -229,7 +194,7 @@ namespace ams::fs { AMS_FS_R_TRY(accessor->QueryEntry(nullptr, 0, nullptr, 0, fsa::QueryId::SetConcatenationFileAttribute, sub_path)); - return ResultSuccess(); + R_SUCCEED(); } Result OpenFile(FileHandle *out, std::unique_ptr &&file, int mode) { @@ -239,7 +204,7 @@ namespace ams::fs { AMS_FS_R_UNLESS(file_accessor != nullptr, fs::ResultAllocationFailureInNew()); out->handle = file_accessor.release(); - return ResultSuccess(); + R_SUCCEED(); } namespace { @@ -249,7 +214,7 @@ namespace ams::fs { AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED(impl::Find(std::addressof(accessor), mount_name), AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT, mount_name)); AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_FILESYSTEM_WITH_NAME(accessor->Commit(), nullptr, accessor, func_name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT, mount_name)); - return ResultSuccess(); + R_SUCCEED(); } } diff --git a/libraries/libstratosphere/source/fs/fsa/fs_user_filesystem_for_debug.cpp b/libraries/libstratosphere/source/fs/fsa/fs_user_filesystem_for_debug.cpp index ee931a288..81640e2a8 100644 --- a/libraries/libstratosphere/source/fs/fsa/fs_user_filesystem_for_debug.cpp +++ b/libraries/libstratosphere/source/fs/fsa/fs_user_filesystem_for_debug.cpp @@ -36,9 +36,13 @@ namespace ams::fs { } - Result GetFileTimeStampRawForDebug(FileTimeStampRaw *out, const char *path) { - AMS_FS_R_TRY(impl::GetFileTimeStampRawForDebug(out, path)); - return ResultSuccess(); + Result GetFileTimeStamp(FileTimeStamp *out, const char *path) { + fs::FileTimeStampRaw raw; + AMS_FS_R_TRY(impl::GetFileTimeStampRawForDebug(std::addressof(raw), path)); + + static_assert(sizeof(raw) == sizeof(*out)); + std::memcpy(out, std::addressof(raw), sizeof(raw)); + R_SUCCEED(); } } diff --git a/libraries/libstratosphere/source/fs/impl/fs_event_notifier_object_adapter.hpp b/libraries/libstratosphere/source/fs/impl/fs_event_notifier_service_object_adapter.hpp similarity index 64% rename from libraries/libstratosphere/source/fs/impl/fs_event_notifier_object_adapter.hpp rename to libraries/libstratosphere/source/fs/impl/fs_event_notifier_service_object_adapter.hpp index cc7293bb6..364a4586a 100644 --- a/libraries/libstratosphere/source/fs/impl/fs_event_notifier_object_adapter.hpp +++ b/libraries/libstratosphere/source/fs/impl/fs_event_notifier_service_object_adapter.hpp @@ -38,23 +38,4 @@ namespace ams::fs::impl { } }; - class RemoteEventNotifierObjectAdapter final : public ::ams::fs::IEventNotifier, public ::ams::fs::impl::Newable { - private: - ::FsEventNotifier m_notifier; - public: - RemoteEventNotifierObjectAdapter(::FsEventNotifier &n) : m_notifier(n) { /* ... */ } - virtual ~RemoteEventNotifierObjectAdapter() { fsEventNotifierClose(std::addressof(m_notifier)); } - private: - virtual Result DoBindEvent(os::SystemEventType *out, os::EventClearMode clear_mode) override { - /* Get the handle. */ - ::Event e; - R_TRY(fsEventNotifierGetEventHandle(std::addressof(m_notifier), std::addressof(e), false)); - - /* Create the system event. */ - os::AttachReadableHandleToSystemEvent(out, e.revent, true, clear_mode); - - return ResultSuccess(); - } - }; - } diff --git a/libraries/libstratosphere/source/fs/impl/fs_file_system_proxy_service_object.hpp b/libraries/libstratosphere/source/fs/impl/fs_file_system_proxy_service_object.hpp new file mode 100644 index 000000000..2435c10ff --- /dev/null +++ b/libraries/libstratosphere/source/fs/impl/fs_file_system_proxy_service_object.hpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) 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::fs::impl { + + sf::SharedPointer GetFileSystemProxyServiceObject(); + sf::SharedPointer GetFileSystemProxyForLoaderServiceObject(); + +} diff --git a/libraries/libstratosphere/source/fs/impl/fs_file_system_service_object_adapter.hpp b/libraries/libstratosphere/source/fs/impl/fs_file_system_service_object_adapter.hpp new file mode 100644 index 000000000..befca1816 --- /dev/null +++ b/libraries/libstratosphere/source/fs/impl/fs_file_system_service_object_adapter.hpp @@ -0,0 +1,263 @@ +/* + * Copyright (c) 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::fs::impl { + + class FileServiceObjectAdapter : public ::ams::fs::impl::Newable, public ::ams::fs::fsa::IFile { + NON_COPYABLE(FileServiceObjectAdapter); + NON_MOVEABLE(FileServiceObjectAdapter); + private: + sf::SharedPointer m_x; + public: + explicit FileServiceObjectAdapter(sf::SharedPointer &&o) : m_x(o) { /* ... */} + virtual ~FileServiceObjectAdapter() { /* ... */ } + public: + virtual Result DoRead(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) override final { + s64 read_size = 0; + R_TRY(m_x->Read(std::addressof(read_size), offset, sf::OutNonSecureBuffer(buffer, size), static_cast(size), option)); + + *out = static_cast(read_size); + R_SUCCEED(); + } + + virtual Result DoGetSize(s64 *out) override final { + R_RETURN(m_x->GetSize(out)); + } + + virtual Result DoFlush() override final { + R_RETURN(m_x->Flush()); + } + + virtual Result DoWrite(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) override final { + R_RETURN(m_x->Write(offset, sf::InNonSecureBuffer(buffer, size), static_cast(size), option)); + } + + virtual Result DoSetSize(s64 size) override final { + R_RETURN(m_x->SetSize(size)); + } + + virtual Result DoOperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override final { + switch (op_id) { + case OperationId::Invalidate: + { + fs::QueryRangeInfo dummy_range_info; + R_RETURN(m_x->OperateRange(std::addressof(dummy_range_info), static_cast(op_id), offset, size)); + } + case OperationId::QueryRange: + { + R_UNLESS(dst != nullptr, fs::ResultNullptrArgument()); + R_UNLESS(dst_size == sizeof(fs::QueryRangeInfo), fs::ResultInvalidSize()); + + R_RETURN(m_x->OperateRange(reinterpret_cast(dst), static_cast(op_id), offset, size)); + } + default: + { + R_RETURN(m_x->OperateRangeWithBuffer(sf::OutNonSecureBuffer(dst, dst_size), sf::InNonSecureBuffer(src, src_size), static_cast(op_id), offset, size)); + } + } + } + public: + virtual sf::cmif::DomainObjectId GetDomainObjectId() const override final { + AMS_ABORT("Invalid GetDomainObjectId call"); + } + }; + + class DirectoryServiceObjectAdapter : public ::ams::fs::impl::Newable, public ::ams::fs::fsa::IDirectory { + NON_COPYABLE(DirectoryServiceObjectAdapter); + NON_MOVEABLE(DirectoryServiceObjectAdapter); + private: + sf::SharedPointer m_x; + public: + explicit DirectoryServiceObjectAdapter(sf::SharedPointer &&o) : m_x(o) { /* ... */} + virtual ~DirectoryServiceObjectAdapter() { /* ... */ } + public: + virtual Result DoRead(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries) override final { + R_RETURN(m_x->Read(out_count, sf::OutBuffer(out_entries, max_entries * sizeof(*out_entries)))); + } + + virtual Result DoGetEntryCount(s64 *out) override final { + R_RETURN(m_x->GetEntryCount(out)); + } + public: + virtual sf::cmif::DomainObjectId GetDomainObjectId() const override final { + AMS_ABORT("Invalid GetDomainObjectId call"); + } + }; + + class FileSystemServiceObjectAdapter : public ::ams::fs::impl::Newable, public ::ams::fs::fsa::IFileSystem { + NON_COPYABLE(FileSystemServiceObjectAdapter); + NON_MOVEABLE(FileSystemServiceObjectAdapter); + private: + sf::SharedPointer m_x; + public: + explicit FileSystemServiceObjectAdapter(sf::SharedPointer &&o) : m_x(o) { /* ... */} + virtual ~FileSystemServiceObjectAdapter() { /* ... */ } + + sf::SharedPointer GetFileSystem() const { return m_x; } + private: + static Result GetPathForServiceObject(fssrv::sf::Path *out, const fs::Path &path) { + const size_t len = util::Strlcpy(out->str, path.GetString(), sizeof(out->str)); + R_UNLESS(len < sizeof(out->str), fs::ResultTooLongPath()); + R_SUCCEED(); + } + private: + virtual Result DoOpenFile(std::unique_ptr *out_file, const fs::Path &path, OpenMode mode) override final { + /* Convert the path. */ + fssrv::sf::Path fsp_path; + R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path)); + + /* Open the file. */ + sf::SharedPointer file; + R_TRY(m_x->OpenFile(std::addressof(file), fsp_path, mode)); + + /* Create the output fsa file. */ + out_file->reset(new FileServiceObjectAdapter(std::move(file))); + R_UNLESS(out_file != nullptr, fs::ResultAllocationFailureInNew()); + + R_SUCCEED(); + } + + virtual Result DoOpenDirectory(std::unique_ptr *out_dir, const fs::Path &path, OpenDirectoryMode mode) override final { + /* Convert the path. */ + fssrv::sf::Path fsp_path; + R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path)); + + /* Open the directory. */ + sf::SharedPointer dir; + R_TRY(m_x->OpenDirectory(std::addressof(dir), fsp_path, mode)); + + /* Create the output fsa directory. */ + out_dir->reset(new DirectoryServiceObjectAdapter(std::move(dir))); + R_UNLESS(out_dir != nullptr, fs::ResultAllocationFailureInNew()); + + R_SUCCEED(); + } + + virtual Result DoGetEntryType(DirectoryEntryType *out, const fs::Path &path) override final { + /* Convert the path. */ + fssrv::sf::Path fsp_path; + R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path)); + + R_RETURN(m_x->GetEntryType(out, fsp_path)); + } + + virtual Result DoCommit() override final { + R_RETURN(m_x->Commit()); + } + + virtual Result DoCreateFile(const fs::Path &path, s64 size, int flags) override final { + /* Convert the path. */ + fssrv::sf::Path fsp_path; + R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path)); + + R_RETURN(m_x->CreateFile(fsp_path, size, flags)); + } + + virtual Result DoDeleteFile(const fs::Path &path) override final { + /* Convert the path. */ + fssrv::sf::Path fsp_path; + R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path)); + + R_RETURN(m_x->DeleteFile(fsp_path)); + } + + virtual Result DoCreateDirectory(const fs::Path &path) override final { + /* Convert the path. */ + fssrv::sf::Path fsp_path; + R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path)); + + R_RETURN(m_x->CreateDirectory(fsp_path)); + } + + virtual Result DoDeleteDirectory(const fs::Path &path) override final { + /* Convert the path. */ + fssrv::sf::Path fsp_path; + R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path)); + + R_RETURN(m_x->DeleteDirectory(fsp_path)); + } + + virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) override final { + /* Convert the path. */ + fssrv::sf::Path fsp_path; + R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path)); + + R_RETURN(m_x->DeleteDirectoryRecursively(fsp_path)); + } + + virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) override final { + /* Convert the path. */ + fssrv::sf::Path fsp_old_path; + fssrv::sf::Path fsp_new_path; + R_TRY(GetPathForServiceObject(std::addressof(fsp_old_path), old_path)); + R_TRY(GetPathForServiceObject(std::addressof(fsp_new_path), new_path)); + + R_RETURN(m_x->RenameFile(fsp_old_path, fsp_new_path)); + } + + virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) override final { + /* Convert the path. */ + fssrv::sf::Path fsp_old_path; + fssrv::sf::Path fsp_new_path; + R_TRY(GetPathForServiceObject(std::addressof(fsp_old_path), old_path)); + R_TRY(GetPathForServiceObject(std::addressof(fsp_new_path), new_path)); + + R_RETURN(m_x->RenameDirectory(fsp_old_path, fsp_new_path)); + } + + virtual Result DoCleanDirectoryRecursively(const fs::Path &path) override final { + /* Convert the path. */ + fssrv::sf::Path fsp_path; + R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path)); + + R_RETURN(m_x->CleanDirectoryRecursively(fsp_path)); + } + + virtual Result DoGetFreeSpaceSize(s64 *out, const fs::Path &path) override final { + /* Convert the path. */ + fssrv::sf::Path fsp_path; + R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path)); + + R_RETURN(m_x->GetFreeSpaceSize(out, fsp_path)); + } + + virtual Result DoGetTotalSpaceSize(s64 *out, const fs::Path &path) override final { + /* Convert the path. */ + fssrv::sf::Path fsp_path; + R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path)); + + R_RETURN(m_x->GetTotalSpaceSize(out, fsp_path)); + } + + virtual Result DoGetFileTimeStampRaw(fs::FileTimeStampRaw *out, const fs::Path &path) override final { + /* Convert the path. */ + fssrv::sf::Path fsp_path; + R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path)); + + R_RETURN(m_x->GetFileTimeStampRaw(out, fsp_path)); + } + + virtual Result DoQueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const fs::Path &path) override { + fssrv::sf::Path fsp_path; + R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path)); + + R_RETURN(m_x->QueryEntry(sf::OutBuffer(dst, dst_size), sf::InBuffer(src, src_size), static_cast(query), fsp_path)); + } + }; + +} diff --git a/libraries/libstratosphere/source/fs/impl/fs_library.cpp b/libraries/libstratosphere/source/fs/impl/fs_library.cpp new file mode 100644 index 000000000..5574861de --- /dev/null +++ b/libraries/libstratosphere/source/fs/impl/fs_library.cpp @@ -0,0 +1,115 @@ +/* + * Copyright (c) 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 +#include "fs_library.hpp" +#include "fs_file_system_service_object_adapter.hpp" +#include "../../fssrv/impl/fssrv_allocator_for_service_framework.hpp" + +namespace ams::fs::impl { + + #if !defined(ATMOSPHERE_OS_HORIZON) + namespace { + + constexpr size_t SystemHeapSize = 8_MB; + alignas(os::MemoryPageSize) constinit u8 g_system_heap[SystemHeapSize]; + + ALWAYS_INLINE auto &GetSystemHeapAllocator() { + AMS_FUNCTION_LOCAL_STATIC(mem::StandardAllocator, s_system_heap_allocator, g_system_heap, sizeof(g_system_heap)); + return s_system_heap_allocator; + } + + constinit util::optional g_system_heap_memory_resource; + + void *AllocateForSystem(size_t size) { return g_system_heap_memory_resource->Allocate(size); } + void DeallocateForSystem(void *p, size_t size) { return g_system_heap_memory_resource->Deallocate(p, size); } + + [[maybe_unused]] constexpr size_t BufferPoolSize = 6_MB; + [[maybe_unused]] constexpr size_t DeviceBufferSize = 8_MB; + [[maybe_unused]] constexpr size_t BufferManagerHeapSize = 14_MB; + + static_assert(util::IsAligned(BufferManagerHeapSize, os::MemoryBlockUnitSize)); + + //alignas(os::MemoryPageSize) u8 g_buffer_pool[BufferPoolSize]; + //alignas(os::MemoryPageSize) u8 g_device_buffer[DeviceBufferSize]; + //alignas(os::MemoryPageSize) u8 g_buffer_manager_heap[BufferManagerHeapSize]; + // + //alignas(os::MemoryPageSize) u8 g_buffer_manager_work_buffer[64_KB]; + /* TODO: Other work buffers. */ + + /* TODO: Implement pooled threads. */ + // constexpr int PooledThreadCount = 12; + // constexpr size_t PooledThreadStackSize = 32_KB; + // fssystem::PooledThread g_pooled_threads[PooledThreadCount]; + + /* FileSystem creators. */ + constinit util::optional g_local_fs_creator; + constinit util::optional g_subdir_fs_creator; + + constinit fssrv::fscreator::FileSystemCreatorInterfaces g_fs_creator_interfaces = {}; + + Result InitializeFileSystemLibraryImpl() { + /* Set system allocator. */ + fssystem::InitializeAllocator(::ams::fs::impl::Allocate, ::ams::fs::impl::Deallocate); + fssystem::InitializeAllocatorForSystem(::ams::fs::impl::AllocateForSystem, ::ams::fs::impl::DeallocateForSystem); + + /* TODO: Many things. */ + g_system_heap_memory_resource.emplace(std::addressof(GetSystemHeapAllocator())); + + /* Setup fscreators/interfaces. */ + g_local_fs_creator.emplace(true); + g_subdir_fs_creator.emplace(); + + g_fs_creator_interfaces.local_fs_creator = std::addressof(*g_local_fs_creator); + g_fs_creator_interfaces.subdir_fs_creator = std::addressof(*g_subdir_fs_creator); + + /* Initialize fssrv. */ + const fssrv::FileSystemProxyConfiguration config = { + .m_fs_creator_interfaces = std::addressof(g_fs_creator_interfaces), + .m_base_storage_service_impl = nullptr /* TODO */, + .m_base_file_system_service_impl = nullptr /* TODO */, + .m_nca_file_system_service_impl = nullptr /* TODO */, + .m_save_data_file_system_service_impl = nullptr /* TODO */, + .m_access_failure_management_service_impl = nullptr /* TODO */, + .m_time_service_impl = nullptr /* TODO */, + .m_status_report_service_impl = nullptr /* TODO */, + .m_program_registry_service_impl = nullptr /* TODO */, + .m_access_log_service_impl = nullptr /* TODO */, + .m_debug_configuration_service_impl = nullptr /* TODO */, + }; + + fssrv::InitializeForFileSystemProxy(config); + R_SUCCEED(); + } + + class FileSystemLibraryInitializer { + public: + FileSystemLibraryInitializer() { + R_ABORT_UNLESS(InitializeFileSystemLibraryImpl()); + } + }; + + } + #endif + + void InitializeFileSystemLibrary() { + #if !defined(ATMOSPHERE_OS_HORIZON) + AMS_FUNCTION_LOCAL_STATIC(FileSystemLibraryInitializer, s_library_initializer); + AMS_UNUSED(s_library_initializer); + #endif + } + +} diff --git a/libraries/libstratosphere/source/fs/impl/fs_library.hpp b/libraries/libstratosphere/source/fs/impl/fs_library.hpp new file mode 100644 index 000000000..51c1d3c61 --- /dev/null +++ b/libraries/libstratosphere/source/fs/impl/fs_library.hpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 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::fs::impl { + + void InitializeFileSystemLibrary(); + +} diff --git a/libraries/libstratosphere/source/fs/impl/fs_remote_device_operator.hpp b/libraries/libstratosphere/source/fs/impl/fs_remote_device_operator.hpp new file mode 100644 index 000000000..c6e674660 --- /dev/null +++ b/libraries/libstratosphere/source/fs/impl/fs_remote_device_operator.hpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 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::fs::impl { + + #if defined(ATMOSPHERE_OS_HORIZON) + class RemoteDeviceOperator { + private: + ::FsDeviceOperator m_operator; + public: + RemoteDeviceOperator(::FsDeviceOperator &o) : m_operator(o) { /* ... */ } + + virtual ~RemoteDeviceOperator() { + fsDeviceOperatorClose(std::addressof(m_operator)); + } + public: + Result IsSdCardInserted(ams::sf::Out out) { + R_RETURN(fsDeviceOperatorIsSdCardInserted(std::addressof(m_operator), out.GetPointer())); + } + + Result IsGameCardInserted(ams::sf::Out out) { + R_RETURN(fsDeviceOperatorIsGameCardInserted(std::addressof(m_operator), out.GetPointer())); + } + + Result GetGameCardHandle(ams::sf::Out out) { + static_assert(sizeof(::FsGameCardHandle) == sizeof(u32)); + R_RETURN(fsDeviceOperatorGetGameCardHandle(std::addressof(m_operator), reinterpret_cast<::FsGameCardHandle *>(out.GetPointer()))); + } + }; + static_assert(fssrv::sf::IsIDeviceOperator); + #endif + +} diff --git a/libraries/libstratosphere/source/fs/impl/fs_remote_event_notifier.hpp b/libraries/libstratosphere/source/fs/impl/fs_remote_event_notifier.hpp new file mode 100644 index 000000000..c31eeaf30 --- /dev/null +++ b/libraries/libstratosphere/source/fs/impl/fs_remote_event_notifier.hpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 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::fs::impl { + + #if defined(ATMOSPHERE_OS_HORIZON) + class RemoteEventNotifier { + private: + ::FsEventNotifier m_notifier; + public: + RemoteEventNotifier(::FsEventNotifier &n) : m_notifier(n) { /* ... */ } + + virtual ~RemoteEventNotifier() { + fsEventNotifierClose(std::addressof(m_notifier)); + } + public: + Result GetEventHandle(ams::sf::OutCopyHandle out) { + ::Event e; + R_TRY(fsEventNotifierGetEventHandle(std::addressof(m_notifier), std::addressof(e), false)); + + out.SetValue(e.revent, true); + R_SUCCEED(); + } + }; + static_assert(fssrv::sf::IsIEventNotifier); + #endif + +} diff --git a/libraries/libstratosphere/source/fs/impl/fs_storage_service_object_adapter.hpp b/libraries/libstratosphere/source/fs/impl/fs_storage_service_object_adapter.hpp new file mode 100644 index 000000000..8ad5ee109 --- /dev/null +++ b/libraries/libstratosphere/source/fs/impl/fs_storage_service_object_adapter.hpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 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::fs::impl { + + class StorageServiceObjectAdapter : public ::ams::fs::impl::Newable, public ::ams::fs::IStorage { + NON_COPYABLE(StorageServiceObjectAdapter); + NON_MOVEABLE(StorageServiceObjectAdapter); + private: + sf::SharedPointer m_x; + public: + explicit StorageServiceObjectAdapter(sf::SharedPointer &&o) : m_x(o) { /* ... */} + virtual ~StorageServiceObjectAdapter() { /* ... */ } + public: + virtual Result Read(s64 offset, void *buffer, size_t size) override final { + R_RETURN(m_x->Read(offset, sf::OutNonSecureBuffer(buffer, size), static_cast(size))); + } + + virtual Result GetSize(s64 *out) override final { + R_RETURN(m_x->GetSize(out)); + } + + virtual Result Flush() override final { + R_RETURN(m_x->Flush()); + } + + virtual Result Write(s64 offset, const void *buffer, size_t size) override final { + R_RETURN(m_x->Write(offset, sf::InNonSecureBuffer(buffer, size), static_cast(size))); + } + + virtual Result SetSize(s64 size) override final { + R_RETURN(m_x->SetSize(size)); + } + + virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override final { + AMS_UNUSED(src, src_size); + switch (op_id) { + case OperationId::Invalidate: + { + fs::QueryRangeInfo dummy_range_info; + R_RETURN(m_x->OperateRange(std::addressof(dummy_range_info), static_cast(op_id), offset, size)); + } + case OperationId::QueryRange: + { + R_UNLESS(dst != nullptr, fs::ResultNullptrArgument()); + R_UNLESS(dst_size == sizeof(fs::QueryRangeInfo), fs::ResultInvalidSize()); + + R_RETURN(m_x->OperateRange(reinterpret_cast(dst), static_cast(op_id), offset, size)); + } + default: + { + R_THROW(fs::ResultUnsupportedOperationInStorageServiceObjectAdapterA()); + } + } + } + }; + +} diff --git a/libraries/libstratosphere/source/fs/tests/fs_path_formatter_tests.cpp b/libraries/libstratosphere/source/fs/tests/fs_path_formatter_tests.cpp new file mode 100644 index 000000000..f9dcbd774 --- /dev/null +++ b/libraries/libstratosphere/source/fs/tests/fs_path_formatter_tests.cpp @@ -0,0 +1,623 @@ +/* + * Copyright (c) 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 + +namespace ams::fs { + + namespace { + + constexpr size_t DefaultPathBufferSize = fs::EntryNameLengthMax + 1; + + consteval PathFlags DecodeFlags(const char *desc) { + PathFlags flags{}; + + while (*desc) { + switch (*(desc++)) { + case 'B': + flags.AllowBackslash(); + break; + case 'E': + flags.AllowEmptyPath(); + break; + case 'M': + flags.AllowMountName(); + break; + case 'R': + flags.AllowRelativePath(); + break; + case 'W': + flags.AllowWindowsPath(); + break; + case 'C': + flags.AllowAllCharacters(); + break; + AMS_UNREACHABLE_DEFAULT_CASE(); + } + } + + return flags; + } + + consteval size_t Strlen(const char *p) { + size_t len = 0; + + while (p[len] != StringTraits::NullTerminator) { + ++len; + } + + return len; + } + + //#define ENABLE_PRINT_FORMAT_TEST_DEBUGGING + + #if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING) + template + struct Print { + constexpr Print() { + if (std::is_constant_evaluated()) { + __builtin_unreachable(); + } + } + }; + + template + consteval void PrintResultMismatchImpl(u32 e, u32 a) { + if constexpr (N == 32) { + Print{}; + } else { + const bool is_e = (e & (1 << N)) != 0; + const bool is_a = (a & (1 << N)) != 0; + if (is_e) { + if (is_a) { + PrintResultMismatchImpl(e, a); + } else { + PrintResultMismatchImpl(e, a); + } + } else { + if (is_a) { + PrintResultMismatchImpl(e, a); + } else { + PrintResultMismatchImpl(e, a); + } + } + } + } + + consteval void PrintResultMismatch(const Result &lhs, const Result &rhs) { + PrintResultMismatchImpl(lhs.GetDescription(), rhs.GetDescription()); + } + + template + struct PrintMismatchChar { + constexpr PrintMismatchChar() { + if (std::is_constant_evaluated()) { + __builtin_unreachable(); + } + } + }; + + template + consteval void PrintCharacterMismatch(char c) { + if (c == static_cast(C)) { + PrintMismatchChar(C)>{}; + return; + } + + if constexpr (C < std::numeric_limits::max()) { + PrintCharacterMismatch(c); + } + } + + template + consteval void PrintCharacterMismatch(char c, char c2) { + if (c == static_cast(C)) { + PrintCharacterMismatch(C)>(c2); + return; + } + + + if constexpr (C < std::numeric_limits::max()) { + PrintCharacterMismatch(c, c2); + } + } + + template + consteval void PrintCharacterMismatch(size_t ix, char c, char c2) { + if (Ix == ix) { + PrintCharacterMismatch(c, c2); + return; + } + + if constexpr (Ix <= DefaultPathBufferSize) { + PrintCharacterMismatch(ix, c, c2); + } + } + #endif + + consteval bool TestNormalizedImpl(const char *path, const PathFlags &flags, size_t buffer_size, const char *normalized, Result expected_result) { + /* Allocate a buffer to normalize into. */ + char *buffer = new char[buffer_size]; + ON_SCOPE_EXIT { delete[] buffer; }; + buffer[buffer_size - 1] = '\xcc'; + + /* Perform normalization. */ + const Result actual_result = PathFormatter::Normalize(buffer, buffer_size, path, Strlen(path) + 1, flags); + + /* Check that the expected result matches the actual. */ + if (actual_result.GetValue() != expected_result.GetValue()) { + #if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING) + PrintResultMismatch(expected_result.GetValue(), actual_result.GetValue()); + #endif + + return false; + } + + /* Check that the expected string matches the actual. */ + for (size_t i = 0; i < buffer_size; ++i) { + if (normalized[i] != StringTraits::NullTerminator || R_SUCCEEDED(expected_result)) { + if (buffer[i] != normalized[i]) { + #if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING) + PrintCharacterMismatch(i, normalized[i], buffer[i]); + #endif + return false; + } + } + + if (normalized[i] == StringTraits::NullTerminator || buffer[i] == StringTraits::NullTerminator) { + break; + } + } + + return true; + } + + struct NormalizeTestData { + const char *path; + const char *flag_desc; + const char *normalized; + Result result; + size_t buffer_size = DefaultPathBufferSize; + }; + + template + consteval bool DoNormalizeTests(const NormalizeTestData (&tests)[N]) { + if constexpr (Ix >= N) { + return true; + } + + const auto &test = tests[Ix]; + if (!TestNormalizedImpl(test.path, DecodeFlags(test.flag_desc), test.buffer_size, test.normalized, test.result)) { + return false; + } + + if constexpr (Ix < N) { + return DoNormalizeTests(tests); + } else { + AMS_ASSUME(false); + } + } + + consteval bool TestNormalizeEmptyPath() { + constexpr NormalizeTestData Tests[] = { + { "", "", "", fs::ResultInvalidPathFormat() }, + { "", "E", "", ResultSuccess() }, + { "/aa/bb/../cc", "E", "/aa/cc", ResultSuccess() }, + }; + + return DoNormalizeTests(Tests); + } + static_assert(TestNormalizeEmptyPath()); + + consteval bool TestNormalizeMountName() { + constexpr NormalizeTestData Tests[] = { + { "mount:/aa/bb", "", "", fs::ResultInvalidPathFormat() }, + { "mount:/aa/bb", "W", "", fs::ResultInvalidPathFormat() }, + { "mount:/aa/bb", "M", "mount:/aa/bb", ResultSuccess() }, + { "mount:/aa/./bb", "M", "mount:/aa/bb", ResultSuccess() }, + { "mount:\\aa\\bb", "M", "mount:", fs::ResultInvalidPathFormat() }, + { "m:/aa/bb", "M", "", fs::ResultInvalidPathFormat() }, + { "mo>unt:/aa/bb", "M", "", fs::ResultInvalidCharacter() }, + { "moun?t:/aa/bb", "M", "", fs::ResultInvalidCharacter() }, + { "mo&unt:/aa/bb", "M", "mo&unt:/aa/bb", ResultSuccess() }, + { "/aa/./bb", "M", "/aa/bb", ResultSuccess() }, + { "mount/aa/./bb", "M", "", fs::ResultInvalidPathFormat() } + }; + + return DoNormalizeTests(Tests); + } + static_assert(TestNormalizeMountName()); + + consteval bool TestNormalizeWindowsPath() { + constexpr NormalizeTestData Tests[] = { + { "c:/aa/bb", "", "", fs::ResultInvalidPathFormat() }, + { "c:\\aa\\bb", "", "", fs::ResultInvalidCharacter() }, + { "\\\\host\\share", "", "", fs::ResultInvalidCharacter() }, + { "\\\\.\\c:\\", "", "", fs::ResultInvalidCharacter() }, + { "\\\\.\\c:/aa/bb/.", "", "", fs::ResultInvalidCharacter() }, + { "\\\\?\\c:\\", "", "", fs::ResultInvalidCharacter() }, + { "mount:\\\\host\\share\\aa\\bb", "M", "mount:", fs::ResultInvalidCharacter() }, + { "mount:\\\\host/share\\aa\\bb", "M", "mount:", fs::ResultInvalidCharacter() }, + { "c:\\aa\\..\\..\\..\\bb", "W", "c:/bb", ResultSuccess() }, + { "mount:/\\\\aa\\..\\bb", "MW", "mount:", fs::ResultInvalidPathFormat() }, + { "mount:/c:\\aa\\..\\bb", "MW", "mount:c:/bb", ResultSuccess() }, + { "mount:/aa/bb", "MW", "mount:/aa/bb", ResultSuccess() }, + { "/mount:/aa/bb", "MW", "/", fs::ResultInvalidCharacter() }, + { "/mount:/aa/bb", "W", "/", fs::ResultInvalidCharacter() }, + { "a:aa/../bb", "MW", "a:aa/bb", ResultSuccess() }, + { "a:aa\\..\\bb", "MW", "a:aa/bb", ResultSuccess() }, + { "/a:aa\\..\\bb", "W", "/", fs::ResultInvalidCharacter() }, + { "\\\\?\\c:\\.\\aa", "W", "\\\\?\\c:/aa", ResultSuccess() }, + { "\\\\.\\c:\\.\\aa", "W", "\\\\.\\c:/aa", ResultSuccess() }, + { "\\\\.\\mount:\\.\\aa", "W", "\\\\./", fs::ResultInvalidCharacter() }, + { "\\\\./.\\aa", "W", "\\\\./aa", ResultSuccess() }, + { "\\\\/aa", "W", "", fs::ResultInvalidPathFormat() }, + { "\\\\\\aa", "W", "", fs::ResultInvalidPathFormat() }, + { "\\\\", "W", "/", ResultSuccess() }, + { "\\\\host\\share", "W", "\\\\host\\share/", ResultSuccess() }, + { "\\\\host\\share\\path", "W", "\\\\host\\share/path", ResultSuccess() }, + { "\\\\host\\share\\path\\aa\\bb\\..\\cc\\.", "W", "\\\\host\\share/path/aa/cc", ResultSuccess() }, + { "\\\\host\\", "W", "", fs::ResultInvalidPathFormat() }, + { "\\\\ho$st\\share\\path", "W", "", fs::ResultInvalidCharacter() }, + { "\\\\host:\\share\\path", "W", "", fs::ResultInvalidCharacter() }, + { "\\\\..\\share\\path", "W", "", fs::ResultInvalidPathFormat() }, + { "\\\\host\\s:hare\\path", "W", "", fs::ResultInvalidCharacter() }, + { "\\\\host\\.\\path", "W", "", fs::ResultInvalidPathFormat() }, + { "\\\\host\\..\\path", "W", "", fs::ResultInvalidPathFormat() }, + { "\\\\host\\sha:re", "W", "", fs::ResultInvalidCharacter() }, + { ".\\\\host\\share", "RW", "..\\\\host\\share/", ResultSuccess() } + }; + + return DoNormalizeTests(Tests); + } + static_assert(TestNormalizeWindowsPath()); + + consteval bool TestNormalizeRelativePath() { + constexpr NormalizeTestData Tests[] = { + { "./aa/bb", "", "", fs::ResultInvalidPathFormat() }, + { "./aa/bb/../cc", "R", "./aa/cc", ResultSuccess() }, + { ".\\aa/bb/../cc", "R", "..", fs::ResultInvalidCharacter() }, + { ".", "R", ".", ResultSuccess() }, + { "../aa/bb", "R", "", fs::ResultDirectoryUnobtainable() }, + { "/aa/./bb", "R", "/aa/bb", ResultSuccess() }, + { "mount:./aa/bb", "MR", "mount:./aa/bb", ResultSuccess() }, + { "mount:./aa/./bb", "MR", "mount:./aa/bb", ResultSuccess() }, + { "mount:./aa/bb", "M", "mount:", fs::ResultInvalidPathFormat() } + }; + + return DoNormalizeTests(Tests); + } + static_assert(TestNormalizeRelativePath()); + + consteval bool TestNormalizeBackslash() { + constexpr NormalizeTestData Tests[] = { + { "\\aa\\bb\\..\\cc", "", "", fs::ResultInvalidPathFormat() }, + { "\\aa\\bb\\..\\cc", "B", "", fs::ResultInvalidPathFormat() }, + { "/aa\\bb\\..\\cc", "", "", fs::ResultInvalidCharacter() }, + { "/aa\\bb\\..\\cc", "B", "/cc", ResultSuccess() }, + { "/aa\\bb\\cc", "", "", fs::ResultInvalidCharacter() }, + { "/aa\\bb\\cc", "B", "/aa\\bb\\cc", ResultSuccess() }, + { "\\\\host\\share\\path\\aa\\bb\\cc", "W", "\\\\host\\share/path/aa/bb/cc", ResultSuccess() }, + { "\\\\host\\share\\path\\aa\\bb\\cc", "WB", "\\\\host\\share/path/aa/bb/cc", ResultSuccess() }, + { "/aa/bb\\../cc/..\\dd\\..\\ee/..", "", "", fs::ResultInvalidCharacter() }, + { "/aa/bb\\../cc/..\\dd\\..\\ee/..", "B", "/aa", ResultSuccess() } + }; + + return DoNormalizeTests(Tests); + } + static_assert(TestNormalizeBackslash()); + + consteval bool TestNormalizeAllowAllChars() { + constexpr NormalizeTestData Tests[] = { + { "/aa/b:b/cc", "", "/aa/", fs::ResultInvalidCharacter() }, + { "/aa/b*b/cc", "", "/aa/", fs::ResultInvalidCharacter() }, + { "/aa/b?b/cc", "", "/aa/", fs::ResultInvalidCharacter() }, + { "/aa/bb/cc", "", "/aa/", fs::ResultInvalidCharacter() }, + { "/aa/b|b/cc", "", "/aa/", fs::ResultInvalidCharacter() }, + { "/aa/b:b/cc", "C", "/aa/b:b/cc", ResultSuccess() }, + { "/aa/b*b/cc", "C", "/aa/b*b/cc", ResultSuccess() }, + { "/aa/b?b/cc", "C", "/aa/b?b/cc", ResultSuccess() }, + { "/aa/bb/cc", "C", "/aa/b>b/cc", ResultSuccess() }, + { "/aa/b|b/cc", "C", "/aa/b|b/cc", ResultSuccess() }, + { "/aa/b'b/cc", "", "/aa/b'b/cc", ResultSuccess() }, + { "/aa/b\"b/cc", "", "/aa/b\"b/cc", ResultSuccess() }, + { "/aa/b(b/cc", "", "/aa/b(b/cc", ResultSuccess() }, + { "/aa/b)b/cc", "", "/aa/b)b/cc", ResultSuccess() }, + { "/aa/b'b/cc", "C", "/aa/b'b/cc", ResultSuccess() }, + { "/aa/b\"b/cc", "C", "/aa/b\"b/cc", ResultSuccess() }, + { "/aa/b(b/cc", "C", "/aa/b(b/cc", ResultSuccess() }, + { "/aa/b)b/cc", "C", "/aa/b)b/cc", ResultSuccess() }, + { "mount:/aa/bunt:/aa/bb/cc", "MC", "", fs::ResultInvalidCharacter() } + }; + + return DoNormalizeTests(Tests); + } + static_assert(TestNormalizeAllowAllChars()); + + consteval bool TestNormalizeAll() { + constexpr NormalizeTestData Tests[] = { + { "mount:./aa/bb", "WRM", "mount:./aa/bb", ResultSuccess() }, + { "mount:./aa/bb\\cc/dd", "WRM", "mount:./aa/bb/cc/dd", ResultSuccess() }, + { "mount:./aa/bb\\cc/dd", "WRMB", "mount:./aa/bb/cc/dd", ResultSuccess() }, + { "mount:./.c:/aa/bb", "RM", "mount:./", fs::ResultInvalidCharacter() }, + { "mount:.c:/aa/bb", "WRM", "mount:./", fs::ResultInvalidCharacter() }, + { "mount:./cc:/aa/bb", "WRM", "mount:./", fs::ResultInvalidCharacter() }, + { "mount:./\\\\host\\share/aa/bb", "MW", "mount:", fs::ResultInvalidPathFormat() }, + { "mount:./\\\\host\\share/aa/bb", "WRM", "mount:.\\\\host\\share/aa/bb", ResultSuccess() }, + { "mount:.\\\\host\\share/aa/bb", "WRM", "mount:..\\\\host\\share/aa/bb", ResultSuccess() }, + { "mount:..\\\\host\\share/aa/bb", "WRM", "mount:.", fs::ResultDirectoryUnobtainable() }, + { ".\\\\host\\share/aa/bb", "WRM", "..\\\\host\\share/aa/bb", ResultSuccess() }, + { "..\\\\host\\share/aa/bb", "WRM", ".", fs::ResultDirectoryUnobtainable() }, + { "mount:\\\\host\\share/aa/bb", "MW", "mount:\\\\host\\share/aa/bb", ResultSuccess() }, + { "mount:\\aa\\bb", "BM", "mount:", fs::ResultInvalidPathFormat() }, + { "mount:/aa\\bb", "BM", "mount:/aa\\bb", ResultSuccess() }, + { ".//aa/bb", "RW", "./aa/bb", ResultSuccess() }, + { "./aa/bb", "R", "./aa/bb", ResultSuccess() }, + { "./c:/aa/bb", "RW", "./", fs::ResultInvalidCharacter() }, + { "mount:./aa/b:b\\cc/dd", "WRMBC", "mount:./aa/b:b/cc/dd", ResultSuccess() } + }; + + return DoNormalizeTests(Tests); + } + static_assert(TestNormalizeAll()); + + consteval bool TestNormalizeSmallBuffer() { + constexpr NormalizeTestData Tests[] = { + { "/aa/bb", "M", "", fs::ResultTooLongPath(), 1}, + { "mount:/aa/bb", "MR", "", fs::ResultTooLongPath(), 6 }, + { "mount:/aa/bb", "MR", "mount:", fs::ResultTooLongPath(), 7 }, + { "aa/bb", "MR", "./", fs::ResultTooLongPath(), 3 }, + { "\\\\host\\share", "W", "\\\\host\\share", fs::ResultTooLongPath(), 13 } + }; + + return DoNormalizeTests(Tests); + } + static_assert(TestNormalizeSmallBuffer()); + + consteval bool TestIsNormalizedImpl(const char *path, const PathFlags &flags, bool expected_normalized, size_t expected_size, Result expected_result) { + /* Perform normalization checking. */ + bool actual_normalized; + size_t actual_size; + const Result actual_result = PathFormatter::IsNormalized(std::addressof(actual_normalized), std::addressof(actual_size), path, flags); + + /* Check that the expected result matches the actual. */ + if (actual_result.GetValue() != expected_result.GetValue()) { + #if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING) + PrintResultMismatch(expected_result.GetValue(), actual_result.GetValue()); + #endif + + return false; + } + + /* Check that the expected output matches the actual. */ + if (R_SUCCEEDED(expected_result)) { + if (expected_normalized != actual_normalized) { + #if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING) + PrintResultMismatchImpl(static_cast(expected_normalized), static_cast(actual_normalized)); + #endif + return false; + } + + if (expected_normalized) { + if (expected_size != actual_size) { + #if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING) + PrintResultMismatchImpl(static_cast(expected_size), static_cast(actual_size)); + #endif + return false; + } + } + } + + return true; + } + + struct IsNormalizedTestData { + const char *path; + const char *flag_desc; + bool normalized; + size_t len; + Result result; + }; + + template + consteval bool DoIsNormalizedTests(const IsNormalizedTestData (&tests)[N]) { + if constexpr (Ix >= N) { + return true; + } + + const auto &test = tests[Ix]; + if (!TestIsNormalizedImpl(test.path, DecodeFlags(test.flag_desc), test.normalized, test.len, test.result)) { + return false; + } + + if constexpr (Ix < N) { + return DoIsNormalizedTests(tests); + } else { + AMS_ASSUME(false); + } + } + + consteval bool TestIsNormalizedEmptyPath() { + constexpr IsNormalizedTestData Tests[] = { + { "", "", false, 0, fs::ResultInvalidPathFormat() }, + { "", "E", true, 0, ResultSuccess() }, + { "/aa/bb/../cc", "E", false, 0, ResultSuccess() } + }; + + return DoIsNormalizedTests(Tests); + } + static_assert(TestIsNormalizedEmptyPath()); + + consteval bool TestIsNormalizedMountName() { + constexpr IsNormalizedTestData Tests[] = { + { "mount:/aa/bb", "", false, 0, fs::ResultInvalidPathFormat() }, + { "mount:/aa/bb", "W", false, 0, fs::ResultInvalidPathFormat() }, + { "mount:/aa/bb", "M", true, 12, ResultSuccess() }, + { "mount:/aa/./bb", "M", false, 6, ResultSuccess() }, + { "mount:\\aa\\bb", "M", false, 0, fs::ResultInvalidPathFormat() }, + { "m:/aa/bb", "M", false, 0, fs::ResultInvalidPathFormat() }, + { "mo>unt:/aa/bb", "M", false, 0, fs::ResultInvalidCharacter() }, + { "moun?t:/aa/bb", "M", false, 0, fs::ResultInvalidCharacter() }, + { "mo&unt:/aa/bb", "M", true, 13, ResultSuccess() }, + { "/aa/./bb", "M", false, 0, ResultSuccess() }, + { "mount/aa/./bb", "M", false, 0, fs::ResultInvalidPathFormat() } + }; + + return DoIsNormalizedTests(Tests); + } + static_assert(TestIsNormalizedMountName()); + + consteval bool TestIsNormalizedWindowsPath() { + constexpr IsNormalizedTestData Tests[] = { + { "c:/aa/bb", "", false, 0, fs::ResultInvalidPathFormat() }, + { "c:\\aa\\bb", "", false, 0, fs::ResultInvalidPathFormat() }, + { "\\\\host\\share", "", false, 0, fs::ResultInvalidPathFormat() }, + { "\\\\.\\c:\\", "", false, 0, fs::ResultInvalidPathFormat() }, + { "\\\\.\\c:/aa/bb/.", "", false, 0, fs::ResultInvalidPathFormat() }, + { "\\\\?\\c:\\", "", false, 0, fs::ResultInvalidPathFormat() }, + { "mount:\\\\host\\share\\aa\\bb", "M", false, 0, fs::ResultInvalidPathFormat() }, + { "mount:\\\\host/share\\aa\\bb", "M", false, 0, fs::ResultInvalidPathFormat() }, + { "c:\\aa\\..\\..\\..\\bb", "W", false, 0, ResultSuccess() }, + { "mount:/\\\\aa\\..\\bb", "MW", false, 0, ResultSuccess() }, + { "mount:/c:\\aa\\..\\bb", "MW", false, 0, ResultSuccess() }, + { "mount:/aa/bb", "MW", true, 12, ResultSuccess() }, + { "/mount:/aa/bb", "MW", false, 0, fs::ResultInvalidCharacter() }, + { "/mount:/aa/bb", "W", false, 0, fs::ResultInvalidCharacter() }, + { "a:aa/../bb", "MW", false, 8, ResultSuccess() }, + { "a:aa\\..\\bb", "MW", false, 0, ResultSuccess() }, + { "/a:aa\\..\\bb", "W", false, 0, ResultSuccess() }, + { "\\\\?\\c:\\.\\aa", "W", false, 0, ResultSuccess() }, + { "\\\\.\\c:\\.\\aa", "W", false, 0, ResultSuccess() }, + { "\\\\.\\mount:\\.\\aa", "W", false, 0, ResultSuccess() }, + { "\\\\./.\\aa", "W", false, 0, ResultSuccess() }, + { "\\\\/aa", "W", false, 0, fs::ResultInvalidPathFormat() }, + { "\\\\\\aa", "W", false, 0, fs::ResultInvalidPathFormat() }, + { "\\\\", "W", false, 0, ResultSuccess() }, + { "\\\\host\\share", "W", false, 0, ResultSuccess() }, + { "\\\\host\\share\\path", "W", false, 0, ResultSuccess() }, + { "\\\\host\\share\\path\\aa\\bb\\..\\cc\\.", "W", false, 0, ResultSuccess() }, + { "\\\\host\\", "W", false, 0, fs::ResultInvalidPathFormat() }, + { "\\\\ho$st\\share\\path", "W", false, 0, fs::ResultInvalidCharacter() }, + { "\\\\host:\\share\\path", "W", false, 0, fs::ResultInvalidCharacter() }, + { "\\\\..\\share\\path", "W", false, 0, fs::ResultInvalidPathFormat() }, + { "\\\\host\\s:hare\\path", "W", false, 0, fs::ResultInvalidCharacter() }, + { "\\\\host\\.\\path", "W", false, 0, fs::ResultInvalidPathFormat() }, + { "\\\\host\\..\\path", "W", false, 0, fs::ResultInvalidPathFormat() }, + { "\\\\host\\sha:re", "W", false, 0, fs::ResultInvalidCharacter() }, + { ".\\\\host\\share", "RW", false, 0, ResultSuccess() } + }; + + return DoIsNormalizedTests(Tests); + } + static_assert(TestIsNormalizedWindowsPath()); + + consteval bool TestIsNormalizedRelativePath() { + constexpr IsNormalizedTestData Tests[] = { + { "./aa/bb", "", false, 0, fs::ResultInvalidPathFormat() }, + { "./aa/bb/../cc", "R", false, 1, ResultSuccess() }, + { ".\\aa/bb/../cc", "R", false, 0, ResultSuccess() }, + { ".", "R", true, 1, ResultSuccess() }, + { "../aa/bb", "R", false, 0, fs::ResultDirectoryUnobtainable() }, + { "/aa/./bb", "R", false, 0, ResultSuccess() }, + { "mount:./aa/bb", "MR", true, 13, ResultSuccess() }, + { "mount:./aa/./bb", "MR", false, 7, ResultSuccess() }, + { "mount:./aa/bb", "M", false, 0, fs::ResultInvalidPathFormat() } + }; + + return DoIsNormalizedTests(Tests); + } + static_assert(TestIsNormalizedRelativePath()); + + consteval bool TestIsNormalizedBackslash() { + constexpr IsNormalizedTestData Tests[] = { + { "\\aa\\bb\\..\\cc", "", false, 0, fs::ResultInvalidPathFormat() }, + { "\\aa\\bb\\..\\cc", "B", false, 0, fs::ResultInvalidPathFormat() }, + { "/aa\\bb\\..\\cc", "", false, 0, fs::ResultInvalidCharacter() }, + { "/aa\\bb\\..\\cc", "B", false, 0, ResultSuccess() }, + { "/aa\\bb\\cc", "", false, 0, fs::ResultInvalidCharacter() }, + { "/aa\\bb\\cc", "B", true, 9, ResultSuccess() }, + { "\\\\host\\share\\path\\aa\\bb\\cc", "W", false, 0, ResultSuccess() }, + { "\\\\host\\share\\path\\aa\\bb\\cc", "WB", false, 0, ResultSuccess() }, + { "/aa/bb\\../cc/..\\dd\\..\\ee/..", "", false, 0, fs::ResultInvalidCharacter() }, + { "/aa/bb\\../cc/..\\dd\\..\\ee/..", "B", false, 0, ResultSuccess() } + }; + + return DoIsNormalizedTests(Tests); + } + static_assert(TestIsNormalizedBackslash()); + + consteval bool TestIsNormalizedAllowAllCharacters() { + constexpr IsNormalizedTestData Tests[] = { + { "/aa/b:b/cc", "", false, 0, fs::ResultInvalidCharacter() }, + { "/aa/b*b/cc", "", false, 0, fs::ResultInvalidCharacter() }, + { "/aa/b?b/cc", "", false, 0, fs::ResultInvalidCharacter() }, + { "/aa/bb/cc", "", false, 0, fs::ResultInvalidCharacter() }, + { "/aa/b|b/cc", "", false, 0, fs::ResultInvalidCharacter() }, + { "/aa/b:b/cc", "C", true, 10, ResultSuccess() }, + { "/aa/b*b/cc", "C", true, 10, ResultSuccess() }, + { "/aa/b?b/cc", "C", true, 10, ResultSuccess() }, + { "/aa/bb/cc", "C", true, 10, ResultSuccess() }, + { "/aa/b|b/cc", "C", true, 10, ResultSuccess() }, + { "/aa/b'b/cc", "", true, 10, ResultSuccess() }, + { "/aa/b\"b/cc", "", true, 10, ResultSuccess() }, + { "/aa/b(b/cc", "", true, 10, ResultSuccess() }, + { "/aa/b)b/cc", "", true, 10, ResultSuccess() }, + { "/aa/b'b/cc", "C", true, 10, ResultSuccess() }, + { "/aa/b\"b/cc", "C", true, 10, ResultSuccess() }, + { "/aa/b(b/cc", "C", true, 10, ResultSuccess() }, + { "/aa/b)b/cc", "C", true, 10, ResultSuccess() }, + { "mount:/aa/bunt:/aa/bb/cc", "MC", false, 0, fs::ResultInvalidCharacter() } + }; + + return DoIsNormalizedTests(Tests); + } + static_assert(TestIsNormalizedAllowAllCharacters()); + + consteval bool TestIsNormalizedAll() { + constexpr IsNormalizedTestData Tests[] = { + { "mount:./aa/bb", "WRM", true, 13, ResultSuccess() }, + { "mount:./aa/bb\\cc/dd", "WRM", false, 0, ResultSuccess() }, + { "mount:./aa/bb\\cc/dd", "WRMB", true, 19, ResultSuccess() }, + { "mount:./.c:/aa/bb", "RM", false, 0, fs::ResultInvalidCharacter() }, + { "mount:.c:/aa/bb", "WRM", false, 0, ResultSuccess() }, + { "mount:./cc:/aa/bb", "WRM", false, 0, fs::ResultInvalidCharacter() }, + { "mount:./\\\\host\\share/aa/bb", "MW", false, 0, fs::ResultInvalidPathFormat() }, + { "mount:./\\\\host\\share/aa/bb", "WRM", false, 0, ResultSuccess() }, + { "mount:.\\\\host\\share/aa/bb", "WRM", false, 0, ResultSuccess() }, + { "mount:..\\\\host\\share/aa/bb", "WRM", false, 0, ResultSuccess() }, + { ".\\\\host\\share/aa/bb", "WRM", false, 0, ResultSuccess() }, + { "..\\\\host\\share/aa/bb", "WRM", false, 0, ResultSuccess() }, + { "mount:\\\\host\\share/aa/bb", "MW", true, 24, ResultSuccess() }, + { "mount:\\aa\\bb", "BM", false, 0, fs::ResultInvalidPathFormat() }, + { "mount:/aa\\bb", "BM", true, 12, ResultSuccess() }, + { ".//aa/bb", "RW", false, 1, ResultSuccess() }, + { "./aa/bb", "R", true, 7, ResultSuccess() }, + { "./c:/aa/bb", "RW", false, 0, fs::ResultInvalidCharacter() }, + { "mount:./aa/b:b\\cc/dd", "WRMBC", true, 20, ResultSuccess() } + }; + + return DoIsNormalizedTests(Tests); + } + static_assert(TestIsNormalizedAll()); + + } + +} diff --git a/libraries/libstratosphere/source/fs/tests/fs_path_normalizer_tests.cpp b/libraries/libstratosphere/source/fs/tests/fs_path_normalizer_tests.cpp new file mode 100644 index 000000000..2092bdedd --- /dev/null +++ b/libraries/libstratosphere/source/fs/tests/fs_path_normalizer_tests.cpp @@ -0,0 +1,394 @@ +/* + * Copyright (c) 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 + +namespace ams::fs { + + namespace { + + constexpr size_t DefaultPathBufferSize = fs::EntryNameLengthMax + 1; + + //#define ENABLE_PRINT_FORMAT_TEST_DEBUGGING + + #if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING) + template + struct Print { + constexpr Print() { + if (std::is_constant_evaluated()) { + __builtin_unreachable(); + } + } + }; + + template + consteval void PrintResultMismatchImpl(u32 e, u32 a) { + if constexpr (N == 32) { + Print{}; + } else { + const bool is_e = (e & (1 << N)) != 0; + const bool is_a = (a & (1 << N)) != 0; + if (is_e) { + if (is_a) { + PrintResultMismatchImpl(e, a); + } else { + PrintResultMismatchImpl(e, a); + } + } else { + if (is_a) { + PrintResultMismatchImpl(e, a); + } else { + PrintResultMismatchImpl(e, a); + } + } + } + } + + consteval void PrintResultMismatch(const Result &lhs, const Result &rhs) { + PrintResultMismatchImpl(lhs.GetDescription(), rhs.GetDescription()); + } + + template + struct PrintMismatchChar { + constexpr PrintMismatchChar() { + if (std::is_constant_evaluated()) { + __builtin_unreachable(); + } + } + }; + + template + consteval void PrintCharacterMismatch(char c) { + if (c == static_cast(C)) { + PrintMismatchChar(C)>{}; + return; + } + + if constexpr (C < std::numeric_limits::max()) { + PrintCharacterMismatch(c); + } + } + + template + consteval void PrintCharacterMismatch(char c, char c2) { + if (c == static_cast(C)) { + PrintCharacterMismatch(C)>(c2); + return; + } + + + if constexpr (C < std::numeric_limits::max()) { + PrintCharacterMismatch(c, c2); + } + } + + template + consteval void PrintCharacterMismatch(size_t ix, char c, char c2) { + if (Ix == ix) { + PrintCharacterMismatch(c, c2); + return; + } + + if constexpr (Ix <= DefaultPathBufferSize) { + PrintCharacterMismatch(ix, c, c2); + } + } + #endif + + consteval bool TestNormalizeImpl(const char *path, size_t buffer_size, const char *normalized, bool windows_path, bool drive_relative, bool all_chars, size_t expected_length, Result expected_result) { + /* Allocate a buffer to normalize into. */ + char *buffer = new char[buffer_size]; + ON_SCOPE_EXIT { delete[] buffer; }; + buffer[buffer_size - 1] = '\xcc'; + + /* Perform normalization. */ + size_t actual_length; + const Result actual_result = PathNormalizer::Normalize(buffer, std::addressof(actual_length), path, buffer_size, windows_path, drive_relative, all_chars); + + /* Check that the expected result matches the actual. */ + if (actual_result.GetValue() != expected_result.GetValue()) { + #if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING) + PrintResultMismatch(expected_result.GetValue(), actual_result.GetValue()); + #endif + + return false; + } + + /* Check that the expected string matches the actual. */ + for (size_t i = 0; i < buffer_size; ++i) { + if (normalized[i] != StringTraits::NullTerminator || R_SUCCEEDED(expected_result)) { + if (buffer[i] != normalized[i]) { + #if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING) + PrintCharacterMismatch(i, normalized[i], buffer[i]); + #endif + return false; + } + } + + if (normalized[i] == StringTraits::NullTerminator || buffer[i] == StringTraits::NullTerminator) { + break; + } + } + + /* Check that the expected length matches the actual. */ + if (R_SUCCEEDED(expected_result) || fs::ResultTooLongPath::Includes(expected_result)) { + if (expected_length != actual_length) { + #if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING) + PrintResultMismatchImpl(static_cast(expected_length), static_cast(actual_length)); + #endif + return false; + } + } + + return true; + } + + struct NormalizeTestData { + const char *path; + bool windows; + bool rel; + bool allow_all; + const char *normalized; + size_t len; + Result result; + }; + + template + consteval bool DoNormalizeTests(const NormalizeTestData (&tests)[N]) { + if constexpr (Ix >= N) { + return true; + } + + const auto &test = tests[Ix]; + if (!TestNormalizeImpl(test.path, DefaultPathBufferSize, test.normalized, test.windows, test.rel, test.allow_all, test.len, test.result)) { + return false; + } + + if constexpr (Ix < N) { + return DoNormalizeTests(tests); + } else { + AMS_ASSUME(false); + } + } + + consteval bool TestNormalized() { + constexpr NormalizeTestData Tests[] = { + { "/aa/bb/c/", false, true, false, "/aa/bb/c", 8, ResultSuccess() }, + { "aa/bb/c/", false, false, false, "", 0, fs::ResultInvalidPathFormat() }, + { "aa/bb/c/", false, true, false, "/aa/bb/c", 8, ResultSuccess() }, + { "mount:a/b", false, true, false, "/", 0, fs::ResultInvalidCharacter() }, + { "mo|unt:a/b", false, true, true, "/mo|unt:a/b", 11, ResultSuccess() }, + { "/aa/bb/../..", true, false, false, "/", 1, ResultSuccess() }, + { "/aa/bb/../../..", true, false, false, "/", 1, ResultSuccess() }, + { "/aa/bb/../../..", false, false, false, "/aa/bb/", 0, fs::ResultDirectoryUnobtainable() }, + { "aa/bb/../../..", true, true, false, "/", 1, ResultSuccess() }, + { "aa/bb/../../..", false, true, false, "/aa/bb/", 0, fs::ResultDirectoryUnobtainable() }, + { "mount:a/b", false, true, true, "/mount:a/b", 10, ResultSuccess() }, + { "/a|/bb/cc", false, false, true, "/a|/bb/cc", 9, ResultSuccess() }, + { "/>a/bb/cc", false, false, true, "/>a/bb/cc", 9, ResultSuccess() }, + { "/aa/.a/bb/cc", false, false, false, "/", 0, fs::ResultInvalidCharacter() }, + { "/aa/. + consteval bool DoNormalizeTests(const NormalizeTestDataSmallBuffer (&tests)[N]) { + if constexpr (Ix >= N) { + return true; + } + + const auto &test = tests[Ix]; + if (!TestNormalizeImpl(test.path, test.buffer_size, test.normalized, false, false, false, test.len, test.result)) { + return false; + } + + if constexpr (Ix < N) { + return DoNormalizeTests(tests); + } else { + AMS_ASSUME(false); + } + } + + consteval bool TestNormalizedSmallBuffer() { + constexpr NormalizeTestDataSmallBuffer Tests[] = { + { "/aa/bb/cc/", 7, "/aa/bb", 6, fs::ResultTooLongPath() }, + { "/aa/bb/cc/", 8, "/aa/bb/", 7, fs::ResultTooLongPath() }, + { "/aa/bb/cc/", 9, "/aa/bb/c", 8, fs::ResultTooLongPath() }, + { "/aa/bb/cc/", 10, "/aa/bb/cc", 9, ResultSuccess() }, + { "/aa/bb/cc", 9, "/aa/bb/c", 8, fs::ResultTooLongPath() }, + { "/aa/bb/cc", 10, "/aa/bb/cc", 9, ResultSuccess() }, + { "/./aa/./bb/./cc", 9, "/aa/bb/c", 8, fs::ResultTooLongPath() }, + { "/./aa/./bb/./cc", 10, "/aa/bb/cc", 9, ResultSuccess() }, + { "/aa/bb/cc/../../..", 9, "/aa/bb/c", 8, fs::ResultTooLongPath() }, + { "/aa/bb/cc/../../..", 10, "/aa/bb/cc", 9, fs::ResultTooLongPath() }, + { "/aa/bb/.", 7, "/aa/bb", 6, fs::ResultTooLongPath() }, + { "/aa/bb/./", 7, "/aa/bb", 6, fs::ResultTooLongPath() }, + { "/aa/bb/..", 8, "/aa", 3, ResultSuccess() }, + { "/aa/bb", 1, "", 0, fs::ResultTooLongPath() }, + { "/aa/bb", 2, "/", 1, fs::ResultTooLongPath() }, + { "/aa/bb", 3, "/a", 2, fs::ResultTooLongPath() }, + { "aa/bb", 1, "", 0, fs::ResultInvalidPathFormat() } + }; + + return DoNormalizeTests(Tests); + } + static_assert(TestNormalizedSmallBuffer()); + + consteval bool TestIsNormalizedImpl(const char *path, bool allow_all, bool expected_normalized, size_t expected_size, Result expected_result) { + /* Perform normalization checking. */ + bool actual_normalized; + size_t actual_size = 0; + const Result actual_result = PathNormalizer::IsNormalized(std::addressof(actual_normalized), std::addressof(actual_size), path, allow_all); + + /* Check that the expected result matches the actual. */ + if (actual_result.GetValue() != expected_result.GetValue()) { + #if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING) + PrintResultMismatch(expected_result.GetValue(), actual_result.GetValue()); + #endif + + return false; + } + + if (expected_size != actual_size) { + #if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING) + PrintResultMismatchImpl(static_cast(expected_size), static_cast(actual_size)); + #endif + return false; + } + + /* Check that the expected output matches the actual. */ + if (R_SUCCEEDED(expected_result)) { + if (expected_normalized != actual_normalized) { + #if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING) + PrintResultMismatchImpl(static_cast(expected_normalized), static_cast(actual_normalized)); + #endif + return false; + } + } + + return true; + } + + struct IsNormalizedTestData { + const char *path; + bool allow_all; + bool normalized; + size_t len; + Result result; + }; + + template + consteval bool DoIsNormalizedTests(const IsNormalizedTestData (&tests)[N]) { + if constexpr (Ix >= N) { + return true; + } + + const auto &test = tests[Ix]; + if (!TestIsNormalizedImpl(test.path, test.allow_all, test.normalized, test.len, test.result)) { + return false; + } + + if constexpr (Ix < N) { + return DoIsNormalizedTests(tests); + } else { + AMS_ASSUME(false); + } + } + + consteval bool TestIsNormalized() { + constexpr IsNormalizedTestData Tests[] = { + { "/aa/bb/c/", false, false, 9, ResultSuccess() }, + { "aa/bb/c/", false, false, 0, fs::ResultInvalidPathFormat() }, + { "aa/bb/c/", false, false, 0, fs::ResultInvalidPathFormat() }, + { "mount:a/b", false, false, 0, fs::ResultInvalidPathFormat() }, + { "mo|unt:a/b", true, false, 0, fs::ResultInvalidPathFormat() }, + { "/aa/bb/../..", false, false, 0, ResultSuccess() }, + { "/aa/bb/../../..", false, false, 0, ResultSuccess() }, + { "/aa/bb/../../..", false, false, 0, ResultSuccess() }, + { "aa/bb/../../..", false, false, 0, fs::ResultInvalidPathFormat() }, + { "aa/bb/../../..", false, false, 0, fs::ResultInvalidPathFormat() }, + { "mount:a/b", true, false, 0, fs::ResultInvalidPathFormat() }, + { "/a|/bb/cc", true, true, 9, ResultSuccess() }, + { "/>a/bb/cc", true, true, 9, ResultSuccess() }, + { "/aa/.a/bb/cc", false, false, 0, fs::ResultInvalidCharacter() }, + { "/aa/.. + */ +#include + +namespace ams::fs { + + namespace { + + struct IsSubPathTestData { + const char *lhs; + const char *rhs; + bool is_sub_path; + }; + + template + consteval bool DoIsSubPathTests(const IsSubPathTestData (&tests)[N]) { + if constexpr (Ix >= N) { + return true; + } + + const auto &test = tests[Ix]; + if (::ams::fs::IsSubPath(test.lhs, test.rhs) != test.is_sub_path) { + return false; + } + + if constexpr (Ix < N) { + return DoIsSubPathTests(tests); + } else { + AMS_ASSUME(false); + } + } + + consteval bool TestIsSubPath() { + constexpr IsSubPathTestData Tests[] = { + { "//a/b", "/a", false }, + { "/a", "//a/b", false }, + { "//a/b", "\\\\a", false }, + { "//a/b", "//a", true }, + { "/", "/a", true }, + { "/a", "/", true }, + { "/", "/", false }, + { "", "", false }, + { "/", "", true }, + { "/", "mount:/a", false }, + { "mount:/", "mount:/", false }, + { "mount:/a/b", "mount:/a/b", false }, + { "mount:/a/b", "mount:/a/b/c", true }, + { "/a/b", "/a/b/c", true }, + { "/a/b/c", "/a/b", true }, + { "/a/b", "/a/b", false }, + { "/a/b", "/a/b\\c", false } + }; + + return DoIsSubPathTests(Tests); + } + static_assert(TestIsSubPath()); + + } + +} diff --git a/libraries/libstratosphere/source/fssrv/fscreator/fssrv_local_file_system_creator.cpp b/libraries/libstratosphere/source/fssrv/fscreator/fssrv_local_file_system_creator.cpp new file mode 100644 index 000000000..18874e8b0 --- /dev/null +++ b/libraries/libstratosphere/source/fssrv/fscreator/fssrv_local_file_system_creator.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 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 + +namespace ams::fssrv::fscreator { + + Result LocalFileSystemCreator::Create(std::shared_ptr *out, const fs::Path &path, bool case_sensitive, bool ensure_root, Result on_path_not_found) { + /* Check that we're configured for development. */ + R_UNLESS(m_is_development, fs::ResultPermissionDeniedForCreateHostFileSystem()); + + /* Allocate a local filesystem. */ + auto local_fs = fs::AllocateShared(); + R_UNLESS(local_fs != nullptr, fs::ResultAllocationFailureInLocalFileSystemCreatorA()); + + /* If we're supposed to make sure the root path exists, do so. */ + if (ensure_root) { + /* Sanity check that the path will be possible to create. */ + AMS_ASSERT(!path.IsEmpty()); + + /* Initialize the local fs with an empty path. */ + fs::Path empty_path; + R_TRY(empty_path.InitializeAsEmpty()); + R_TRY(local_fs->Initialize(empty_path, fssystem::PathCaseSensitiveMode_CaseInsensitive)); + + /* Ensure the directory exists. */ + if (const Result ensure_result = fssystem::EnsureDirectory(local_fs.get(), path); R_FAILED(ensure_result)) { + if (R_SUCCEEDED(on_path_not_found)) { + R_THROW(ensure_result); + } else { + R_THROW(on_path_not_found); + } + } + } + + /* Initialize the local filesystem. */ + R_TRY_CATCH(local_fs->Initialize(path, case_sensitive ? fssystem::PathCaseSensitiveMode_CaseSensitive : fssystem::PathCaseSensitiveMode_CaseInsensitive)) { + R_CATCH(fs::ResultPathNotFound) { + if (R_SUCCEEDED(on_path_not_found)) { + R_THROW(R_CURRENT_RESULT); + } else { + R_THROW(on_path_not_found); + } + } + } R_END_TRY_CATCH; + + /* Set the output fs. */ + *out = std::move(local_fs); + R_SUCCEED(); + } + +} diff --git a/libraries/libstratosphere/source/fssrv/fscreator/fssrv_subdirectory_file_system_creator.cpp b/libraries/libstratosphere/source/fssrv/fscreator/fssrv_subdirectory_file_system_creator.cpp new file mode 100644 index 000000000..7151368c9 --- /dev/null +++ b/libraries/libstratosphere/source/fssrv/fscreator/fssrv_subdirectory_file_system_creator.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 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 + +namespace ams::fssrv::fscreator { + + Result SubDirectoryFileSystemCreator::Create(std::shared_ptr *out, std::shared_ptr base_fs, const fs::Path &path) { + /* Verify that we can the directory on the base filesystem. */ + { + std::unique_ptr sub_dir; + R_TRY(base_fs->OpenDirectory(std::addressof(sub_dir), path, fs::OpenDirectoryMode_Directory)); + } + + /* Allocate a SubDirectoryFileSystem. */ + auto sub_dir_fs = fs::AllocateShared(std::move(base_fs)); + R_UNLESS(sub_dir_fs != nullptr, fs::ResultAllocationFailureInSubDirectoryFileSystemCreatorA()); + + /* Initialize the new filesystem. */ + R_TRY(sub_dir_fs->Initialize(path)); + + /* Return the new filesystem. */ + *out = std::move(sub_dir_fs); + R_SUCCEED(); + } + +} diff --git a/libraries/libstratosphere/source/fssrv/fssrv_file_system_proxy_api.cpp b/libraries/libstratosphere/source/fssrv/fssrv_file_system_proxy_api.cpp index 1eef9815b..f7f3f1ab7 100644 --- a/libraries/libstratosphere/source/fssrv/fssrv_file_system_proxy_api.cpp +++ b/libraries/libstratosphere/source/fssrv/fssrv_file_system_proxy_api.cpp @@ -42,8 +42,8 @@ namespace ams::fssrv { constexpr size_t NumSessions = FileSystemProxyMaxSessions + ProgramRegistryMaxSessions + FileSystemProxyForLoaderMaxSessions; - constinit os::SemaphoreType g_semaphore_for_file_system_proxy_for_loader; - constinit os::SemaphoreType g_semaphore_for_program_registry; + constinit os::SemaphoreType g_semaphore_for_file_system_proxy_for_loader = {}; + constinit os::SemaphoreType g_semaphore_for_program_registry = {}; class FileSystemProxyServerManager final : public ams::sf::hipc::ServerManager { private: @@ -89,11 +89,11 @@ namespace ams::fssrv { } }; - constinit util::TypedStorage g_server_manager_storage; + constinit util::TypedStorage g_server_manager_storage = {}; constinit FileSystemProxyServerManager *g_server_manager = nullptr; - constinit os::BarrierType g_server_loop_barrier; - constinit os::EventType g_resume_wait_event; + constinit os::BarrierType g_server_loop_barrier = {}; + constinit os::EventType g_resume_wait_event = {}; constinit bool g_is_suspended = false; @@ -103,9 +103,9 @@ namespace ams::fssrv { } - void InitializeForFileSystemProxy(fscreator::FileSystemCreatorInterfaces *fs_creator_interfaces, fssystem::IBufferManager *buffer_manager, bool is_development_function_enabled) { + void InitializeForFileSystemProxy(const FileSystemProxyConfiguration &config) { /* TODO FS-REIMPL */ - AMS_UNUSED(fs_creator_interfaces, buffer_manager, is_development_function_enabled); + AMS_UNUSED(config); } void InitializeFileSystemProxyServer(int threads) { diff --git a/libraries/libstratosphere/source/fssrv/fssrv_file_system_proxy_impl.cpp b/libraries/libstratosphere/source/fssrv/fssrv_file_system_proxy_impl.cpp index 90e3b0abb..a2e1e0534 100644 --- a/libraries/libstratosphere/source/fssrv/fssrv_file_system_proxy_impl.cpp +++ b/libraries/libstratosphere/source/fssrv/fssrv_file_system_proxy_impl.cpp @@ -14,6 +14,8 @@ * along with this program. If not, see . */ #include +#include +#include "impl/fssrv_allocator_for_service_framework.hpp" #include "impl/fssrv_program_info.hpp" namespace ams::fssrv { @@ -27,6 +29,420 @@ namespace ams::fssrv { /* ... */ } + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wunused-parameter" + + Result FileSystemProxyImpl::OpenFileSystem(ams::sf::Out> out, const fssrv::sf::FspPath &path, u32 type) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::FileSystemProxyImpl::SetCurrentProcess(const ams::sf::ClientProcessId &client_pid) { + /* Set current process. */ + m_process_id = client_pid.GetValue().value; + + /* TODO: Allocate NcaFileSystemService. */ + /* TODO: Allocate SaveDataFileSystemService. */ + R_SUCCEED(); + } + + Result FileSystemProxyImpl::OpenDataFileSystemByCurrentProcess(ams::sf::Out> out) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::OpenFileSystemWithPatch(ams::sf::Out> out, ncm::ProgramId program_id, u32 type) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::OpenFileSystemWithId(ams::sf::Out> out, const fssrv::sf::FspPath &path, u64 program_id, u32 type) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::OpenDataFileSystemByProgramId(ams::sf::Out> out, ncm::ProgramId program_id) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::OpenBisFileSystem(ams::sf::Out> out, const fssrv::sf::FspPath &path, u32 id) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::OpenBisStorage(ams::sf::Out> out, u32 id) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::InvalidateBisCache() { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::OpenHostFileSystem(ams::sf::Out> out, const fssrv::sf::FspPath &path) { + /* Invoke the modern API from the legacy API. */ + R_RETURN(this->OpenHostFileSystemWithOption(out, path, fs::MountHostOption::None._value)); + } + + Result FileSystemProxyImpl::OpenSdCardFileSystem(ams::sf::Out> out) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::FormatSdCardFileSystem() { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::DeleteSaveDataFileSystem(u64 save_data_id) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::CreateSaveDataFileSystem(const fs::SaveDataAttribute &attribute, const fs::SaveDataCreationInfo &creation_info, const fs::SaveDataMetaInfo &meta_info) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::CreateSaveDataFileSystemBySystemSaveDataId(const fs::SaveDataAttribute &attribute, const fs::SaveDataCreationInfo &creation_info) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::RegisterSaveDataFileSystemAtomicDeletion(const ams::sf::InBuffer &save_data_ids) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::DeleteSaveDataFileSystemBySaveDataSpaceId(u8 indexer_space_id, u64 save_data_id) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::FormatSdCardDryRun() { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::IsExFatSupported(ams::sf::Out out) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::DeleteSaveDataFileSystemBySaveDataAttribute(u8 space_id, const fs::SaveDataAttribute &attribute) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::OpenGameCardStorage(ams::sf::Out> out, u32 handle, u32 partition) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::OpenGameCardFileSystem(ams::sf::Out> out, u32 handle, u32 partition) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::ExtendSaveDataFileSystem(u8 space_id, u64 save_data_id, s64 available_size, s64 journal_size) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::DeleteCacheStorage(u16 index) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::GetCacheStorageSize(ams::sf::Out out_size, ams::sf::Out out_journal_size, u16 index) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::CreateSaveDataFileSystemWithHashSalt(const fs::SaveDataAttribute &attribute, const fs::SaveDataCreationInfo &creation_info, const fs::SaveDataMetaInfo &meta_info, const fs::HashSalt &salt) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::OpenHostFileSystemWithOption(ams::sf::Out> out, const fssrv::sf::FspPath &path, u32 _option) { + /* TODO: GetProgramInfo */ + /* TODO: GetAccessibility. */ + /* TODO: Check Accessibility CanRead/CanWrite */ + + /* Convert the path. */ + fs::Path normalized_path; + #if defined(ATMOSPHERE_OS_WINDOWS) + R_TRY(normalized_path.Initialize(path.str)); + #else + if (path.str[0] == '/' && path.str[1] == '/') { + R_TRY(normalized_path.Initialize(path.str)); + } else { + R_TRY(normalized_path.InitializeWithReplaceUnc(path.str)); + } + #endif + + /* Normalize the path. */ + fs::PathFlags path_flags; + path_flags.AllowWindowsPath(); + path_flags.AllowRelativePath(); + path_flags.AllowEmptyPath(); + R_TRY(normalized_path.Normalize(path_flags)); + + /* Parse option. */ + const fs::MountHostOption option{ _option }; + + /* TODO: FileSystemProxyCoreImpl::OpenHostFileSystem */ + /* TODO: use creator interfaces */ + std::shared_ptr fs; + { + fssrv::fscreator::LocalFileSystemCreator local_fs_creator(true); + + R_TRY(static_cast(local_fs_creator).Create(std::addressof(fs), normalized_path, option.HasPseudoCaseSensitiveFlag())); + } + + /* Determine path flags for the result fs. */ + fs::PathFlags host_path_flags; + if (path.str[0] == 0) { + host_path_flags.AllowWindowsPath(); + } + + /* Create an interface adapter. */ + auto sf_fs = impl::FileSystemObjectFactory::CreateSharedEmplaced(std::move(fs), host_path_flags, false); + R_UNLESS(sf_fs != nullptr, fs::ResultAllocationFailureInFileSystemProxyImplA()); + + /* Set the output. */ + *out = std::move(sf_fs); + R_SUCCEED(); + } + + Result FileSystemProxyImpl::OpenSaveDataFileSystem(ams::sf::Out> out, u8 space_id, const fs::SaveDataAttribute &attribute) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::OpenSaveDataFileSystemBySystemSaveDataId(ams::sf::Out> out, u8 space_id, const fs::SaveDataAttribute &attribute) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::OpenReadOnlySaveDataFileSystem(ams::sf::Out> out, u8 space_id, const fs::SaveDataAttribute &attribute) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::ReadSaveDataFileSystemExtraDataBySaveDataSpaceId(const ams::sf::OutBuffer &buffer, u8 space_id, u64 save_data_id) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::ReadSaveDataFileSystemExtraData(const ams::sf::OutBuffer &buffer, u64 save_data_id) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::WriteSaveDataFileSystemExtraData(u64 save_data_id, u8 space_id, const ams::sf::InBuffer &buffer) { + AMS_ABORT("TODO"); + } + + /* ... */ + + Result FileSystemProxyImpl::OpenImageDirectoryFileSystem(ams::sf::Out> out, u32 id) { + AMS_ABORT("TODO"); + } + + /* ... */ + + Result FileSystemProxyImpl::OpenContentStorageFileSystem(ams::sf::Out> out, u32 id) { + AMS_ABORT("TODO"); + } + + /* ... */ + + Result FileSystemProxyImpl::OpenDataStorageByCurrentProcess(ams::sf::Out> out) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::OpenDataStorageByProgramId(ams::sf::Out> out, ncm::ProgramId program_id) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::OpenDataStorageByDataId(ams::sf::Out> out, ncm::DataId data_id, u8 storage_id) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::OpenPatchDataStorageByCurrentProcess(ams::sf::Out> out) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::OpenDataFileSystemWithProgramIndex(ams::sf::Out> out, u8 index) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::OpenDataStorageWithProgramIndex(ams::sf::Out> out, u8 index) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::OpenDataStorageByPath(ams::sf::Out> out, const fssrv::sf::FspPath &path, u32 type) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::OpenDeviceOperator(ams::sf::Out> out) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::OpenSdCardDetectionEventNotifier(ams::sf::Out> out) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::OpenGameCardDetectionEventNotifier(ams::sf::Out> out) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::OpenSystemDataUpdateEventNotifier(ams::sf::Out> out) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::NotifySystemDataUpdateEvent() { + AMS_ABORT("TODO"); + } + + /* ... */ + + Result FileSystemProxyImpl::SetCurrentPosixTime(s64 posix_time) { + AMS_ABORT("TODO"); + } + + /* ... */ + + Result FileSystemProxyImpl::GetRightsId(ams::sf::Out out, ncm::ProgramId program_id, ncm::StorageId storage_id) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::RegisterExternalKey(const fs::RightsId &rights_id, const spl::AccessKey &access_key) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::UnregisterAllExternalKey() { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::GetRightsIdByPath(ams::sf::Out out, const fssrv::sf::FspPath &path) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::GetRightsIdAndKeyGenerationByPath(ams::sf::Out out, ams::sf::Out out_key_generation, const fssrv::sf::FspPath &path) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::SetCurrentPosixTimeWithTimeDifference(s64 posix_time, s32 time_difference) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::GetFreeSpaceSizeForSaveData(ams::sf::Out out, u8 space_id) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::VerifySaveDataFileSystemBySaveDataSpaceId() { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::CorruptSaveDataFileSystemBySaveDataSpaceId() { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::QuerySaveDataInternalStorageTotalSize() { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::GetSaveDataCommitId() { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::UnregisterExternalKey(const fs::RightsId &rights_id) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::SetSdCardEncryptionSeed(const fs::EncryptionSeed &seed) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::SetSdCardAccessibility(bool accessible) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::IsSdCardAccessible(ams::sf::Out out) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::IsSignedSystemPartitionOnSdCardValid(ams::sf::Out out) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::OpenAccessFailureDetectionEventNotifier() { + AMS_ABORT("TODO"); + } + + /* ... */ + + Result FileSystemProxyImpl::RegisterProgramIndexMapInfo(const ams::sf::InBuffer &buffer, s32 count) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::SetBisRootForHost(u32 id, const fssrv::sf::FspPath &path) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::SetSaveDataSize(s64 size, s64 journal_size) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::SetSaveDataRootPath(const fssrv::sf::FspPath &path) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::DisableAutoSaveDataCreation() { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::SetGlobalAccessLogMode(u32 mode) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::GetGlobalAccessLogMode(ams::sf::Out out) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::OutputAccessLogToSdCard(const ams::sf::InBuffer &buf) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::RegisterUpdatePartition() { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::OpenRegisteredUpdatePartition(ams::sf::Out> out) { + AMS_ABORT("TODO"); + } + + /* ... */ + + Result FileSystemProxyImpl::GetProgramIndexForAccessLog(ams::sf::Out out_idx, ams::sf::Out out_count) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::GetFsStackUsage(ams::sf::Out out, u32 type) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::UnsetSaveDataRootPath() { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::OutputMultiProgramTagAccessLog() { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::FlushAccessLogOnSdCard() { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::OutputApplicationInfoAccessLog() { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::RegisterDebugConfiguration(u32 key, s64 value) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::UnregisterDebugConfiguration(u32 key) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::OverrideSaveDataTransferTokenSignVerificationKey(const ams::sf::InBuffer &buf) { + AMS_ABORT("TODO"); + } + + Result FileSystemProxyImpl::CorruptSaveDataFileSystemByOffset(u8 space_id, u64 save_data_id, s64 offset) { + AMS_ABORT("TODO"); + } + + /* ... */ + + #pragma GCC diagnostic pop + Result FileSystemProxyImpl::OpenCodeFileSystemDeprecated(ams::sf::Out> out_fs, const fssrv::sf::Path &path, ncm::ProgramId program_id) { AMS_ABORT("TODO"); AMS_UNUSED(out_fs, path, program_id); @@ -42,12 +458,4 @@ namespace ams::fssrv { AMS_UNUSED(out, process_id); } - Result FileSystemProxyImpl::SetCurrentProcess(const ams::sf::ClientProcessId &client_pid) { - /* Set current process. */ - m_process_id = client_pid.GetValue().value; - - /* TODO: Allocate NcaFileSystemService. */ - AMS_ABORT("TODO"); - } - } diff --git a/libraries/libstratosphere/source/fssrv/fssrv_filesystem_interface_adapter.cpp b/libraries/libstratosphere/source/fssrv/fssrv_filesystem_interface_adapter.cpp index 177e6a4d1..5bf4a313f 100644 --- a/libraries/libstratosphere/source/fssrv/fssrv_filesystem_interface_adapter.cpp +++ b/libraries/libstratosphere/source/fssrv/fssrv_filesystem_interface_adapter.cpp @@ -16,77 +16,83 @@ #include #include #include "impl/fssrv_allocator_for_service_framework.hpp" +#include "fssrv_retry_utility.hpp" namespace ams::fssrv::impl { - FileInterfaceAdapter::FileInterfaceAdapter(std::unique_ptr &&file, FileSystemInterfaceAdapter *parent, util::unique_lock &&sema) - : m_parent_filesystem(parent, true), m_base_file(std::move(file)), m_open_count_semaphore(std::move(sema)) + namespace { + + constexpr const char *RootDirectory = "/"; + + } + + FileInterfaceAdapter::FileInterfaceAdapter(std::unique_ptr &&file, FileSystemInterfaceAdapter *parent, bool allow_all) + : m_parent_filesystem(parent, true), m_base_file(std::move(file)), m_allow_all_operations(allow_all) { /* ... */ } - FileInterfaceAdapter::~FileInterfaceAdapter() { - /* ... */ - } - - void FileInterfaceAdapter::InvalidateCache() { - AMS_ABORT_UNLESS(m_parent_filesystem->IsDeepRetryEnabled()); - std::scoped_lock scoped_write_lock(m_parent_filesystem->GetReaderWriterLockForCacheInvalidation()); - m_base_file->OperateRange(nullptr, 0, fs::OperationId::Invalidate, 0, std::numeric_limits::max(), nullptr, 0); - } - Result FileInterfaceAdapter::Read(ams::sf::Out out, s64 offset, const ams::sf::OutNonSecureBuffer &buffer, s64 size, fs::ReadOption option) { - /* TODO: N retries on fs::ResultDataCorrupted, we may want to eventually. */ - /* TODO: Deep retry */ - R_UNLESS(offset >= 0, fs::ResultInvalidOffset()); - R_UNLESS(size >= 0, fs::ResultInvalidSize()); + /* Check pre-conditions. */ + R_UNLESS(0 <= offset, fs::ResultInvalidOffset()); + R_UNLESS(0 <= size, fs::ResultInvalidSize()); + R_UNLESS(size <= static_cast(buffer.GetSize()), fs::ResultInvalidSize()); + /* Read the data, retrying on corruption. */ size_t read_size = 0; - R_TRY(m_base_file->Read(std::addressof(read_size), offset, buffer.GetPointer(), static_cast(size), option)); + R_TRY(RetryFinitelyForDataCorrupted([&] () ALWAYS_INLINE_LAMBDA { + R_RETURN(m_base_file->Read(std::addressof(read_size), offset, buffer.GetPointer(), static_cast(size), option)); + })); - out.SetValue(read_size); - return ResultSuccess(); + /* Set the output size. */ + *out = read_size; + R_SUCCEED(); } Result FileInterfaceAdapter::Write(s64 offset, const ams::sf::InNonSecureBuffer &buffer, s64 size, fs::WriteOption option) { - /* TODO: N increases thread priority temporarily when writing. We may want to eventually. */ - R_UNLESS(offset >= 0, fs::ResultInvalidOffset()); - R_UNLESS(size >= 0, fs::ResultInvalidSize()); + /* Check pre-conditions. */ + R_UNLESS(0 <= offset, fs::ResultInvalidOffset()); + R_UNLESS(0 <= size, fs::ResultInvalidSize()); + R_UNLESS(size <= static_cast(buffer.GetSize()), fs::ResultInvalidSize()); - auto read_lock = m_parent_filesystem->AcquireCacheInvalidationReadLock(); - return m_base_file->Write(offset, buffer.GetPointer(), size, option); + /* Temporarily increase our thread's priority. */ + fssystem::ScopedThreadPriorityChangerByAccessPriority cp(fssystem::ScopedThreadPriorityChangerByAccessPriority::AccessMode::Write); + + R_RETURN(m_base_file->Write(offset, buffer.GetPointer(), size, option)); } Result FileInterfaceAdapter::Flush() { - auto read_lock = m_parent_filesystem->AcquireCacheInvalidationReadLock(); - return m_base_file->Flush(); + R_RETURN(m_base_file->Flush()); } Result FileInterfaceAdapter::SetSize(s64 size) { R_UNLESS(size >= 0, fs::ResultInvalidSize()); - auto read_lock = m_parent_filesystem->AcquireCacheInvalidationReadLock(); - return m_base_file->SetSize(size); + R_RETURN(m_base_file->SetSize(size)); } Result FileInterfaceAdapter::GetSize(ams::sf::Out out) { - auto read_lock = m_parent_filesystem->AcquireCacheInvalidationReadLock(); - return m_base_file->GetSize(out.GetPointer()); + /* Get the size, retrying on corruption. */ + R_RETURN(RetryFinitelyForDataCorrupted([&] () ALWAYS_INLINE_LAMBDA { + R_RETURN(m_base_file->GetSize(out.GetPointer())); + })); } Result FileInterfaceAdapter::OperateRange(ams::sf::Out out, s32 op_id, s64 offset, s64 size) { /* N includes this redundant check, so we will too. */ R_UNLESS(out.GetPointer() != nullptr, fs::ResultNullptrArgument()); + /* Clear the range info. */ out->Clear(); - if (op_id == static_cast(fs::OperationId::QueryRange)) { - auto read_lock = m_parent_filesystem->AcquireCacheInvalidationReadLock(); + if (op_id == static_cast(fs::OperationId::QueryRange)) { fs::FileQueryRangeInfo info; R_TRY(m_base_file->OperateRange(std::addressof(info), sizeof(info), fs::OperationId::QueryRange, offset, size, nullptr, 0)); out->Merge(info); + } else if (op_id == static_cast(fs::OperationId::Invalidate)) { + R_TRY(m_base_file->OperateRange(nullptr, 0, fs::OperationId::Invalidate, offset, size, nullptr, 0)); } - return ResultSuccess(); + R_SUCCEED(); } Result FileInterfaceAdapter::OperateRangeWithBuffer(const ams::sf::OutNonSecureBuffer &out_buf, const ams::sf::InNonSecureBuffer &in_buf, s32 op_id, s64 offset, s64 size) { @@ -99,265 +105,275 @@ namespace ams::fssrv::impl { /* Lazy load/unprepared operations are always allowed to be performed with buffer. */ break; default: - /* TODO: Nintendo requires that a class member here be true here, but this class member seems to always be false. */ - /* If this changes (or reverse engineering is wrong), this should be updated. */ - return fs::ResultPermissionDenied(); + R_UNLESS(m_allow_all_operations, fs::ResultPermissionDenied()); } /* Perform the operation. */ - R_TRY(m_base_file->OperateRange(out_buf.GetPointer(), out_buf.GetSize(), static_cast(op_id), offset, size, in_buf.GetPointer(), in_buf.GetSize())); - - return ResultSuccess(); + R_RETURN(m_base_file->OperateRange(out_buf.GetPointer(), out_buf.GetSize(), static_cast(op_id), offset, size, in_buf.GetPointer(), in_buf.GetSize())); } - DirectoryInterfaceAdapter::DirectoryInterfaceAdapter(std::unique_ptr &&dir, FileSystemInterfaceAdapter *parent, util::unique_lock &&sema) - : m_parent_filesystem(parent, true), m_base_dir(std::move(dir)), m_open_count_semaphore(std::move(sema)) + DirectoryInterfaceAdapter::DirectoryInterfaceAdapter(std::unique_ptr &&dir, FileSystemInterfaceAdapter *parent, bool allow_all) + : m_parent_filesystem(parent, true), m_base_dir(std::move(dir)), m_allow_all_operations(allow_all) { /* ... */ } - DirectoryInterfaceAdapter::~DirectoryInterfaceAdapter() { - /* ... */ - } - Result DirectoryInterfaceAdapter::Read(ams::sf::Out out, const ams::sf::OutBuffer &out_entries) { - auto read_lock = m_parent_filesystem->AcquireCacheInvalidationReadLock(); - + /* Get the maximum number of entries we can read into the buffer. */ const s64 max_num_entries = out_entries.GetSize() / sizeof(fs::DirectoryEntry); R_UNLESS(max_num_entries >= 0, fs::ResultInvalidSize()); - /* TODO: N retries on fs::ResultDataCorrupted, we may want to eventually. */ - return m_base_dir->Read(out.GetPointer(), reinterpret_cast(out_entries.GetPointer()), max_num_entries); + /* Get the size, retrying on corruption. */ + s64 num_read = 0; + R_TRY(RetryFinitelyForDataCorrupted([&] () ALWAYS_INLINE_LAMBDA { + R_RETURN(m_base_dir->Read(std::addressof(num_read), reinterpret_cast(out_entries.GetPointer()), max_num_entries)); + })); + + /* Set the output. */ + *out = num_read; + R_SUCCEED(); + } Result DirectoryInterfaceAdapter::GetEntryCount(ams::sf::Out out) { - auto read_lock = m_parent_filesystem->AcquireCacheInvalidationReadLock(); - return m_base_dir->GetEntryCount(out.GetPointer()); + R_RETURN(m_base_dir->GetEntryCount(out.GetPointer())); } - FileSystemInterfaceAdapter::FileSystemInterfaceAdapter(std::shared_ptr &&fs, bool open_limited) - : m_base_fs(std::move(fs)), m_open_count_limited(open_limited), m_deep_retry_enabled(false) - { - /* ... */ - } - - FileSystemInterfaceAdapter::~FileSystemInterfaceAdapter() { - /* ... */ - } - - bool FileSystemInterfaceAdapter::IsDeepRetryEnabled() const { - return m_deep_retry_enabled; - } - - bool FileSystemInterfaceAdapter::IsAccessFailureDetectionObserved() const { - /* TODO: This calls into fssrv::FileSystemProxyImpl, which we don't have yet. */ - AMS_ABORT_UNLESS(false); - } - - util::optional> FileSystemInterfaceAdapter::AcquireCacheInvalidationReadLock() { - util::optional> lock; - if (m_deep_retry_enabled) { - lock.emplace(m_invalidation_lock); + Result FileSystemInterfaceAdapter::SetUpPath(fs::Path *out, const fssrv::sf::Path &sf_path) { + /* Initialize the fs path. */ + if (m_path_flags.IsWindowsPathAllowed()) { + R_TRY(out->InitializeWithReplaceUnc(sf_path.str)); + } else { + R_TRY(out->Initialize(sf_path.str)); } - return lock; - } - os::ReaderWriterLock &FileSystemInterfaceAdapter::GetReaderWriterLockForCacheInvalidation() { - return m_invalidation_lock; + /* Ensure the path is normalized. */ + R_RETURN(out->Normalize(m_path_flags)); } Result FileSystemInterfaceAdapter::CreateFile(const fssrv::sf::Path &path, s64 size, s32 option) { - auto read_lock = this->AcquireCacheInvalidationReadLock(); - + /* Check pre-conditions. */ R_UNLESS(size >= 0, fs::ResultInvalidSize()); - PathNormalizer normalizer(path.str); - R_UNLESS(normalizer.GetPath() != nullptr, normalizer.GetResult()); + /* Normalize the input path. */ + fs::Path fs_path; + R_TRY(this->SetUpPath(std::addressof(fs_path), path)); - return m_base_fs->CreateFile(normalizer.GetPath(), size, option); + R_RETURN(m_base_fs->CreateFile(fs_path, size, option)); } Result FileSystemInterfaceAdapter::DeleteFile(const fssrv::sf::Path &path) { - auto read_lock = this->AcquireCacheInvalidationReadLock(); + /* Normalize the input path. */ + fs::Path fs_path; + R_TRY(this->SetUpPath(std::addressof(fs_path), path)); - PathNormalizer normalizer(path.str); - R_UNLESS(normalizer.GetPath() != nullptr, normalizer.GetResult()); - - return m_base_fs->DeleteFile(normalizer.GetPath()); + R_RETURN(m_base_fs->DeleteFile(fs_path)); } Result FileSystemInterfaceAdapter::CreateDirectory(const fssrv::sf::Path &path) { - auto read_lock = this->AcquireCacheInvalidationReadLock(); + /* Normalize the input path. */ + fs::Path fs_path; + R_TRY(this->SetUpPath(std::addressof(fs_path), path)); - PathNormalizer normalizer(path.str); - R_UNLESS(normalizer.GetPath() != nullptr, normalizer.GetResult()); + /* Sanity check that the directory isn't the root. */ + R_UNLESS(fs_path != RootDirectory, fs::ResultPathAlreadyExists()); - R_UNLESS(strncmp(normalizer.GetPath(), "/", 2) != 0, fs::ResultPathAlreadyExists()); - - return m_base_fs->CreateDirectory(normalizer.GetPath()); + R_RETURN(m_base_fs->CreateDirectory(fs_path)); } Result FileSystemInterfaceAdapter::DeleteDirectory(const fssrv::sf::Path &path) { - auto read_lock = this->AcquireCacheInvalidationReadLock(); + /* Normalize the input path. */ + fs::Path fs_path; + R_TRY(this->SetUpPath(std::addressof(fs_path), path)); - PathNormalizer normalizer(path.str); - R_UNLESS(normalizer.GetPath() != nullptr, normalizer.GetResult()); + /* Sanity check that the directory isn't the root. */ + R_UNLESS(fs_path != RootDirectory, fs::ResultDirectoryNotDeletable()); - R_UNLESS(strncmp(normalizer.GetPath(), "/", 2) != 0, fs::ResultDirectoryNotDeletable()); - - return m_base_fs->DeleteDirectory(normalizer.GetPath()); + R_RETURN(m_base_fs->DeleteDirectory(fs_path)); } Result FileSystemInterfaceAdapter::DeleteDirectoryRecursively(const fssrv::sf::Path &path) { - auto read_lock = this->AcquireCacheInvalidationReadLock(); + /* Normalize the input path. */ + fs::Path fs_path; + R_TRY(this->SetUpPath(std::addressof(fs_path), path)); - PathNormalizer normalizer(path.str); - R_UNLESS(normalizer.GetPath() != nullptr, normalizer.GetResult()); + /* Sanity check that the directory isn't the root. */ + R_UNLESS(fs_path != RootDirectory, fs::ResultDirectoryNotDeletable()); - R_UNLESS(strncmp(normalizer.GetPath(), "/", 2) != 0, fs::ResultDirectoryNotDeletable()); - - return m_base_fs->DeleteDirectoryRecursively(normalizer.GetPath()); + R_RETURN(m_base_fs->DeleteDirectoryRecursively(fs_path)); } Result FileSystemInterfaceAdapter::RenameFile(const fssrv::sf::Path &old_path, const fssrv::sf::Path &new_path) { - auto read_lock = this->AcquireCacheInvalidationReadLock(); + /* Normalize the input paths. */ + fs::Path fs_old_path; + fs::Path fs_new_path; + R_TRY(this->SetUpPath(std::addressof(fs_old_path), old_path)); + R_TRY(this->SetUpPath(std::addressof(fs_new_path), new_path)); - PathNormalizer old_normalizer(old_path.str); - PathNormalizer new_normalizer(new_path.str); - R_UNLESS(old_normalizer.GetPath() != nullptr, old_normalizer.GetResult()); - R_UNLESS(new_normalizer.GetPath() != nullptr, new_normalizer.GetResult()); - - return m_base_fs->RenameFile(old_normalizer.GetPath(), new_normalizer.GetPath()); + R_RETURN(m_base_fs->RenameFile(fs_old_path, fs_new_path)); } Result FileSystemInterfaceAdapter::RenameDirectory(const fssrv::sf::Path &old_path, const fssrv::sf::Path &new_path) { - auto read_lock = this->AcquireCacheInvalidationReadLock(); + /* Normalize the input paths. */ + fs::Path fs_old_path; + fs::Path fs_new_path; + R_TRY(this->SetUpPath(std::addressof(fs_old_path), old_path)); + R_TRY(this->SetUpPath(std::addressof(fs_new_path), new_path)); - PathNormalizer old_normalizer(old_path.str); - PathNormalizer new_normalizer(new_path.str); - R_UNLESS(old_normalizer.GetPath() != nullptr, old_normalizer.GetResult()); - R_UNLESS(new_normalizer.GetPath() != nullptr, new_normalizer.GetResult()); + R_UNLESS(!fs::IsSubPath(fs_old_path.GetString(), fs_new_path.GetString()), fs::ResultDirectoryNotRenamable()); - const bool is_subpath = fs::IsSubPath(old_normalizer.GetPath(), new_normalizer.GetPath()); - R_UNLESS(!is_subpath, fs::ResultDirectoryNotRenamable()); - - return m_base_fs->RenameFile(old_normalizer.GetPath(), new_normalizer.GetPath()); + R_RETURN(m_base_fs->RenameDirectory(fs_old_path, fs_new_path)); } Result FileSystemInterfaceAdapter::GetEntryType(ams::sf::Out out, const fssrv::sf::Path &path) { - auto read_lock = this->AcquireCacheInvalidationReadLock(); - - PathNormalizer normalizer(path.str); - R_UNLESS(normalizer.GetPath() != nullptr, normalizer.GetResult()); + /* Normalize the input path. */ + fs::Path fs_path; + R_TRY(this->SetUpPath(std::addressof(fs_path), path)); static_assert(sizeof(*out.GetPointer()) == sizeof(fs::DirectoryEntryType)); - return m_base_fs->GetEntryType(reinterpret_cast(out.GetPointer()), normalizer.GetPath()); + R_RETURN(m_base_fs->GetEntryType(reinterpret_cast(out.GetPointer()), fs_path)); } Result FileSystemInterfaceAdapter::OpenFile(ams::sf::Out> out, const fssrv::sf::Path &path, u32 mode) { - auto read_lock = this->AcquireCacheInvalidationReadLock(); + /* Normalize the input path. */ + fs::Path fs_path; + R_TRY(this->SetUpPath(std::addressof(fs_path), path)); - util::unique_lock open_count_semaphore; - if (m_open_count_limited) { - /* TODO: This calls into fssrv::FileSystemProxyImpl, which we don't have yet. */ - AMS_ABORT_UNLESS(false); + /* Open the file, retrying on corruption. */ + std::unique_ptr file; + R_TRY(RetryFinitelyForDataCorrupted([&] () ALWAYS_INLINE_LAMBDA { + R_RETURN(m_base_fs->OpenFile(std::addressof(file), fs_path, static_cast(mode))); + })); + + /* If we're a mitm interface, we should preserve the resulting target object id. */ + if (m_is_mitm_interface) { + /* TODO: This is a hack to get the mitm API to work. Better solution? */ + const auto target_object_id = file->GetDomainObjectId(); + + ams::sf::SharedPointer file_intf = FileSystemObjectFactory::CreateSharedEmplaced(std::move(file), this, m_allow_all_operations); + R_UNLESS(file_intf != nullptr, fs::ResultAllocationFailureInFileSystemInterfaceAdapter()); + + out.SetValue(std::move(file_intf), target_object_id); + } else { + ams::sf::SharedPointer file_intf = FileSystemObjectFactory::CreateSharedEmplaced(std::move(file), this, m_allow_all_operations); + R_UNLESS(file_intf != nullptr, fs::ResultAllocationFailureInFileSystemInterfaceAdapter()); + + out.SetValue(std::move(file_intf)); } - PathNormalizer normalizer(path.str); - R_UNLESS(normalizer.GetPath() != nullptr, normalizer.GetResult()); - - /* TODO: N retries on fs::ResultDataCorrupted, we may want to eventually. */ - std::unique_ptr file; - R_TRY(m_base_fs->OpenFile(std::addressof(file), normalizer.GetPath(), static_cast(mode))); - - /* TODO: This is a hack to get the mitm API to work. Better solution? */ - const auto target_object_id = file->GetDomainObjectId(); - - /* TODO: N creates an nn::fssystem::AsynchronousAccessFile here. */ - - ams::sf::SharedPointer file_intf = FileSystemObjectFactory::CreateSharedEmplaced(std::move(file), this, std::move(open_count_semaphore)); - R_UNLESS(file_intf != nullptr, fs::ResultAllocationFailureInFileSystemInterfaceAdapter()); - - out.SetValue(std::move(file_intf), target_object_id); - return ResultSuccess(); + R_SUCCEED(); } Result FileSystemInterfaceAdapter::OpenDirectory(ams::sf::Out> out, const fssrv::sf::Path &path, u32 mode) { - auto read_lock = this->AcquireCacheInvalidationReadLock(); + /* Normalize the input path. */ + fs::Path fs_path; + R_TRY(this->SetUpPath(std::addressof(fs_path), path)); - util::unique_lock open_count_semaphore; - if (m_open_count_limited) { - /* TODO: This calls into fssrv::FileSystemProxyImpl, which we don't have yet. */ - AMS_ABORT_UNLESS(false); + /* Open the directory, retrying on corruption. */ + std::unique_ptr dir; + R_TRY(RetryFinitelyForDataCorrupted([&] () ALWAYS_INLINE_LAMBDA { + R_RETURN(m_base_fs->OpenDirectory(std::addressof(dir), fs_path, static_cast(mode))); + })); + + /* If we're a mitm interface, we should preserve the resulting target object id. */ + if (m_is_mitm_interface) { + /* TODO: This is a hack to get the mitm API to work. Better solution? */ + const auto target_object_id = dir->GetDomainObjectId(); + + ams::sf::SharedPointer dir_intf = FileSystemObjectFactory::CreateSharedEmplaced(std::move(dir), this, m_allow_all_operations); + R_UNLESS(dir_intf != nullptr, fs::ResultAllocationFailureInFileSystemInterfaceAdapter()); + + out.SetValue(std::move(dir_intf), target_object_id); + } else { + ams::sf::SharedPointer dir_intf = FileSystemObjectFactory::CreateSharedEmplaced(std::move(dir), this, m_allow_all_operations); + R_UNLESS(dir_intf != nullptr, fs::ResultAllocationFailureInFileSystemInterfaceAdapter()); + + out.SetValue(std::move(dir_intf)); } - PathNormalizer normalizer(path.str); - R_UNLESS(normalizer.GetPath() != nullptr, normalizer.GetResult()); - - /* TODO: N retries on fs::ResultDataCorrupted, we may want to eventually. */ - std::unique_ptr dir; - R_TRY(m_base_fs->OpenDirectory(std::addressof(dir), normalizer.GetPath(), static_cast(mode))); - - /* TODO: This is a hack to get the mitm API to work. Better solution? */ - const auto target_object_id = dir->GetDomainObjectId(); - - ams::sf::SharedPointer dir_intf = FileSystemObjectFactory::CreateSharedEmplaced(std::move(dir), this, std::move(open_count_semaphore)); - R_UNLESS(dir_intf != nullptr, fs::ResultAllocationFailureInFileSystemInterfaceAdapter()); - - out.SetValue(std::move(dir_intf), target_object_id); - return ResultSuccess(); + R_SUCCEED(); } Result FileSystemInterfaceAdapter::Commit() { - auto read_lock = this->AcquireCacheInvalidationReadLock(); - - return m_base_fs->Commit(); + R_RETURN(m_base_fs->Commit()); } Result FileSystemInterfaceAdapter::GetFreeSpaceSize(ams::sf::Out out, const fssrv::sf::Path &path) { - auto read_lock = this->AcquireCacheInvalidationReadLock(); + /* Normalize the input path. */ + fs::Path fs_path; + R_TRY(this->SetUpPath(std::addressof(fs_path), path)); - PathNormalizer normalizer(path.str); - R_UNLESS(normalizer.GetPath() != nullptr, normalizer.GetResult()); - - return m_base_fs->GetFreeSpaceSize(out.GetPointer(), normalizer.GetPath()); + R_RETURN(m_base_fs->GetFreeSpaceSize(out.GetPointer(), fs_path)); } Result FileSystemInterfaceAdapter::GetTotalSpaceSize(ams::sf::Out out, const fssrv::sf::Path &path) { - auto read_lock = this->AcquireCacheInvalidationReadLock(); + /* Normalize the input path. */ + fs::Path fs_path; + R_TRY(this->SetUpPath(std::addressof(fs_path), path)); - PathNormalizer normalizer(path.str); - R_UNLESS(normalizer.GetPath() != nullptr, normalizer.GetResult()); - - return m_base_fs->GetTotalSpaceSize(out.GetPointer(), normalizer.GetPath()); + R_RETURN(m_base_fs->GetTotalSpaceSize(out.GetPointer(), fs_path)); } Result FileSystemInterfaceAdapter::CleanDirectoryRecursively(const fssrv::sf::Path &path) { - auto read_lock = this->AcquireCacheInvalidationReadLock(); + /* Normalize the input path. */ + fs::Path fs_path; + R_TRY(this->SetUpPath(std::addressof(fs_path), path)); - PathNormalizer normalizer(path.str); - R_UNLESS(normalizer.GetPath() != nullptr, normalizer.GetResult()); - - return m_base_fs->CleanDirectoryRecursively(normalizer.GetPath()); + R_RETURN(m_base_fs->CleanDirectoryRecursively(fs_path)); } Result FileSystemInterfaceAdapter::GetFileTimeStampRaw(ams::sf::Out out, const fssrv::sf::Path &path) { - auto read_lock = this->AcquireCacheInvalidationReadLock(); + /* Normalize the input path. */ + fs::Path fs_path; + R_TRY(this->SetUpPath(std::addressof(fs_path), path)); - PathNormalizer normalizer(path.str); - R_UNLESS(normalizer.GetPath() != nullptr, normalizer.GetResult()); - - return m_base_fs->GetFileTimeStampRaw(out.GetPointer(), normalizer.GetPath()); + R_RETURN(m_base_fs->GetFileTimeStampRaw(out.GetPointer(), fs_path)); } Result FileSystemInterfaceAdapter::QueryEntry(const ams::sf::OutBuffer &out_buf, const ams::sf::InBuffer &in_buf, s32 query_id, const fssrv::sf::Path &path) { - auto read_lock = this->AcquireCacheInvalidationReadLock(); + /* Check that we have permission to perform the operation. */ + switch (static_cast(query_id)) { + using enum fs::fsa::QueryId; + case SetConcatenationFileAttribute: + case IsSignedSystemPartitionOnSdCardValid: + case QueryUnpreparedFileInformation: + /* Only certain operations are unconditionally allowable. */ + break; + default: + R_UNLESS(m_allow_all_operations, fs::ResultPermissionDenied()); + } - /* TODO: Nintendo does not normalize the path. Should we? */ + /* Normalize the input path. */ + fs::Path fs_path; + R_TRY(this->SetUpPath(std::addressof(fs_path), path)); - char *dst = reinterpret_cast< char *>(out_buf.GetPointer()); + char *dst = reinterpret_cast(out_buf.GetPointer()); const char *src = reinterpret_cast(in_buf.GetPointer()); - return m_base_fs->QueryEntry(dst, out_buf.GetSize(), src, in_buf.GetSize(), static_cast(query_id), path.str); + R_RETURN(m_base_fs->QueryEntry(dst, out_buf.GetSize(), src, in_buf.GetSize(), static_cast(query_id), fs_path)); } + #if defined(ATMOSPHERE_OS_HORIZON) + Result RemoteFileSystem::OpenFile(ams::sf::Out> out, const fssrv::sf::Path &path, u32 mode) { + FsFile f; + R_TRY(fsFsOpenFile(std::addressof(m_base_fs), path.str, mode, std::addressof(f))); + + auto intf = FileSystemObjectFactory::CreateSharedEmplaced(f); + R_UNLESS(intf != nullptr, fs::ResultAllocationFailureInFileSystemInterfaceAdapter()); + + out.SetValue(std::move(intf)); + R_SUCCEED(); + } + + Result RemoteFileSystem::OpenDirectory(ams::sf::Out> out, const fssrv::sf::Path &path, u32 mode) { + FsDir d; + R_TRY(fsFsOpenDirectory(std::addressof(m_base_fs), path.str, mode, std::addressof(d))); + + auto intf = FileSystemObjectFactory::CreateSharedEmplaced(d); + R_UNLESS(intf != nullptr, fs::ResultAllocationFailureInFileSystemInterfaceAdapter()); + + out.SetValue(std::move(intf)); + R_SUCCEED(); + } + #endif + } diff --git a/libraries/libstratosphere/source/fssrv/fssrv_path_normalizer.cpp b/libraries/libstratosphere/source/fssrv/fssrv_path_normalizer.cpp deleted file mode 100644 index 7bf2052a2..000000000 --- a/libraries/libstratosphere/source/fssrv/fssrv_path_normalizer.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 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 - -namespace ams::fssrv { - - Result PathNormalizer::Normalize(const char **out_path, Buffer *out_buf, const char *path, bool preserve_unc, bool preserve_tail_sep, bool has_mount_name) { - /* Check pre-conditions. */ - AMS_ASSERT(out_path != nullptr); - AMS_ASSERT(out_buf != nullptr); - - /* Clear output. */ - *out_path = nullptr; - *out_buf = Buffer(); - - /* Check if we're normalized. */ - bool normalized = false; - R_TRY(fs::PathNormalizer::IsNormalized(std::addressof(normalized), path, preserve_unc, has_mount_name)); - - if (normalized) { - /* If we're already normalized, no allocation is needed. */ - *out_path = path; - } else { - /* Allocate a new buffer. */ - auto buffer = fs::impl::MakeUnique(fs::EntryNameLengthMax + 1); - R_UNLESS(buffer != nullptr, fs::ResultAllocationFailureInPathNormalizer()); - - /* Generate normalized path. */ - size_t normalized_len = 0; - R_TRY(fs::PathNormalizer::Normalize(buffer.get(), std::addressof(normalized_len), path, fs::EntryNameLengthMax + 1, preserve_unc, has_mount_name)); - - /* Preserve the tail separator, if we should. */ - if (preserve_tail_sep) { - if (fs::PathNormalizer::IsSeparator(path[strnlen(path, fs::EntryNameLengthMax) - 1]) && !fs::PathNormalizer::IsSeparator(buffer[normalized_len - 1])) { - AMS_ASSERT(normalized_len < fs::EntryNameLengthMax); - buffer[normalized_len] = fs::StringTraits::DirectorySeparator; - buffer[normalized_len + 1] = fs::StringTraits::NullTerminator; - } - } - - /* Save output. */ - *out_path = buffer.get(); - *out_buf = std::move(buffer); - } - - return ResultSuccess(); - } - -} diff --git a/libraries/libstratosphere/source/fssrv/fssrv_retry_utility.hpp b/libraries/libstratosphere/source/fssrv/fssrv_retry_utility.hpp new file mode 100644 index 000000000..a77840d28 --- /dev/null +++ b/libraries/libstratosphere/source/fssrv/fssrv_retry_utility.hpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 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::fssrv::impl { + + template + ALWAYS_INLINE Result RetryFinitelyForDataCorrupted(F f) { + /* All official uses of this retry once, for two tries total. */ + constexpr auto MaxTryCount = 2; + + /* Perform the operation, retrying on fs::ResultDataCorrupted. */ + auto tries = 0; + while (true) { + /* Try to perform the operation. */ + const auto rc = f(); + + /* If we should, retry. */ + if (fs::ResultDataCorrupted::Includes(rc)) { + if ((++tries) < MaxTryCount) { + continue; + } + } + + /* Ensure the current attempt succeeded. */ + R_TRY(rc); + + /* Return success. */ + R_SUCCEED(); + } + } + +} diff --git a/libraries/libstratosphere/source/fssrv/fssrv_storage_interface_adapter.cpp b/libraries/libstratosphere/source/fssrv/fssrv_storage_interface_adapter.cpp index b29f5ca6d..b466d2be3 100644 --- a/libraries/libstratosphere/source/fssrv/fssrv_storage_interface_adapter.cpp +++ b/libraries/libstratosphere/source/fssrv/fssrv_storage_interface_adapter.cpp @@ -15,80 +15,62 @@ */ #include #include +#include "fssrv_retry_utility.hpp" namespace ams::fssrv::impl { - StorageInterfaceAdapter::StorageInterfaceAdapter(fs::IStorage *storage) : m_base_storage(storage) { - /* ... */ - } - - StorageInterfaceAdapter::StorageInterfaceAdapter(std::unique_ptr storage) : m_base_storage(storage.release()) { - /* ... */ - } - - StorageInterfaceAdapter::StorageInterfaceAdapter(std::shared_ptr storage) : m_base_storage(std::move(storage)) { - /* ... */ - } - - StorageInterfaceAdapter::~StorageInterfaceAdapter() { - /* ... */ - } - - util::optional> StorageInterfaceAdapter::AcquireCacheInvalidationReadLock() { - util::optional> lock; - if (m_deep_retry_enabled) { - lock.emplace(m_invalidation_lock); - } - return lock; - } - Result StorageInterfaceAdapter::Read(s64 offset, const ams::sf::OutNonSecureBuffer &buffer, s64 size) { - /* TODO: N retries on fs::ResultDataCorrupted, we may want to eventually. */ - /* TODO: Deep retry */ - R_UNLESS(offset >= 0, fs::ResultInvalidOffset()); - R_UNLESS(size >= 0, fs::ResultInvalidSize()); - return m_base_storage->Read(offset, buffer.GetPointer(), size); + /* Check pre-conditions. */ + R_UNLESS(0 <= offset, fs::ResultInvalidOffset()); + R_UNLESS(0 <= size, fs::ResultInvalidSize()); + R_UNLESS(size <= static_cast(buffer.GetSize()), fs::ResultInvalidSize()); + + R_RETURN(RetryFinitelyForDataCorrupted([&] () ALWAYS_INLINE_LAMBDA { + R_RETURN(m_base_storage->Read(offset, buffer.GetPointer(), size)); + })); } Result StorageInterfaceAdapter::Write(s64 offset, const ams::sf::InNonSecureBuffer &buffer, s64 size) { - /* TODO: N increases thread priority temporarily when writing. We may want to eventually. */ - R_UNLESS(offset >= 0, fs::ResultInvalidOffset()); - R_UNLESS(size >= 0, fs::ResultInvalidSize()); + /* Check pre-conditions. */ + R_UNLESS(0 <= offset, fs::ResultInvalidOffset()); + R_UNLESS(0 <= size, fs::ResultInvalidSize()); + R_UNLESS(size <= static_cast(buffer.GetSize()), fs::ResultInvalidSize()); - auto read_lock = this->AcquireCacheInvalidationReadLock(); - return m_base_storage->Write(offset, buffer.GetPointer(), size); + /* Temporarily increase our thread's priority. */ + fssystem::ScopedThreadPriorityChangerByAccessPriority cp(fssystem::ScopedThreadPriorityChangerByAccessPriority::AccessMode::Write); + + R_RETURN(m_base_storage->Write(offset, buffer.GetPointer(), size)); } Result StorageInterfaceAdapter::Flush() { - auto read_lock = this->AcquireCacheInvalidationReadLock(); - return m_base_storage->Flush(); + R_RETURN(m_base_storage->Flush()); } Result StorageInterfaceAdapter::SetSize(s64 size) { R_UNLESS(size >= 0, fs::ResultInvalidSize()); - auto read_lock = this->AcquireCacheInvalidationReadLock(); - return m_base_storage->SetSize(size); + R_RETURN(m_base_storage->SetSize(size)); } Result StorageInterfaceAdapter::GetSize(ams::sf::Out out) { - auto read_lock = this->AcquireCacheInvalidationReadLock(); - return m_base_storage->GetSize(out.GetPointer()); + R_RETURN(m_base_storage->GetSize(out.GetPointer())); } Result StorageInterfaceAdapter::OperateRange(ams::sf::Out out, s32 op_id, s64 offset, s64 size) { /* N includes this redundant check, so we will too. */ R_UNLESS(out.GetPointer() != nullptr, fs::ResultNullptrArgument()); + /* Clear the range info. */ out->Clear(); - if (op_id == static_cast(fs::OperationId::QueryRange)) { - auto read_lock = this->AcquireCacheInvalidationReadLock(); - fs::StorageQueryRangeInfo info; + if (op_id == static_cast(fs::OperationId::QueryRange)) { + fs::FileQueryRangeInfo info; R_TRY(m_base_storage->OperateRange(std::addressof(info), sizeof(info), fs::OperationId::QueryRange, offset, size, nullptr, 0)); out->Merge(info); + } else if (op_id == static_cast(fs::OperationId::Invalidate)) { + R_TRY(m_base_storage->OperateRange(nullptr, 0, fs::OperationId::Invalidate, offset, size, nullptr, 0)); } - return ResultSuccess(); + R_SUCCEED(); } } diff --git a/libraries/libstratosphere/source/fssrv/impl/fssrv_program_info.cpp b/libraries/libstratosphere/source/fssrv/impl/fssrv_program_info.cpp index 0a5b8a2bc..7fe1ca96a 100644 --- a/libraries/libstratosphere/source/fssrv/impl/fssrv_program_info.cpp +++ b/libraries/libstratosphere/source/fssrv/impl/fssrv_program_info.cpp @@ -20,15 +20,7 @@ namespace ams::fssrv::impl { namespace { - constinit os::SdkMutex g_mutex; - constinit bool g_initialized = false; - - constinit u64 g_initial_process_id_min = 0; - constinit u64 g_initial_process_id_max = 0; - - constinit u64 g_current_process_id = 0; - - constinit std::aligned_storage<0x80>::type g_static_buffer_for_program_info_for_initial_process; + constinit std::aligned_storage<0x80>::type g_static_buffer_for_program_info_for_initial_process = {}; template class StaticAllocatorForProgramInfoForInitialProcess : public std::allocator { @@ -56,6 +48,16 @@ namespace ams::fssrv::impl { constexpr const u32 FileAccessControlForInitialProgram[0x1C / sizeof(u32)] = {0x00000001, 0x00000000, 0x80000000, 0x0000001C, 0x00000000, 0x0000001C, 0x00000000}; constexpr const u32 FileAccessControlDescForInitialProgram[0x2C / sizeof(u32)] = {0x00000001, 0x00000000, 0x80000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF}; + #if defined(ATMOSPHERE_OS_HORIZON) + + constinit os::SdkMutex g_mutex; + constinit bool g_initialized = false; + + constinit u64 g_initial_process_id_min = 0; + constinit u64 g_initial_process_id_max = 0; + + constinit u64 g_current_process_id = 0; + ALWAYS_INLINE void InitializeInitialAndCurrentProcessId() { if (AMS_UNLIKELY(!g_initialized)) { std::scoped_lock lk(g_mutex); @@ -75,45 +77,49 @@ namespace ams::fssrv::impl { } } } + #endif } std::shared_ptr ProgramInfo::GetProgramInfoForInitialProcess() { - static constinit os::SdkMutex s_mutex; - static constinit bool s_initialized = false; - static constinit std::shared_ptr s_initial_program_info = nullptr; + class ProgramInfoHelper : public ProgramInfo { + public: + ProgramInfoHelper(const void *data, s64 data_size, const void *desc, s64 desc_size) : ProgramInfo(data, data_size, desc, desc_size) { /* ... */ } + }; - /* Ensure we've initialized the program info. */ - if (AMS_UNLIKELY(!s_initialized)) { - std::scoped_lock lk(s_mutex); - if (AMS_LIKELY(!s_initialized)) { - class ProgramInfoHelper : public ProgramInfo { - public: - ProgramInfoHelper(const void *data, s64 data_size, const void *desc, s64 desc_size) : ProgramInfo(data, data_size, desc, desc_size) { /* ... */ } - }; - - s_initial_program_info = std::allocate_shared(StaticAllocatorForProgramInfoForInitialProcess{}, FileAccessControlForInitialProgram, sizeof(FileAccessControlForInitialProgram), FileAccessControlDescForInitialProgram, sizeof(FileAccessControlDescForInitialProgram)); - s_initialized = true; - } - } + AMS_FUNCTION_LOCAL_STATIC(std::shared_ptr, s_initial_program_info, std::allocate_shared(StaticAllocatorForProgramInfoForInitialProcess{}, FileAccessControlForInitialProgram, sizeof(FileAccessControlForInitialProgram), FileAccessControlDescForInitialProgram, sizeof(FileAccessControlDescForInitialProgram))); return s_initial_program_info; } bool IsInitialProgram(u64 process_id) { + #if defined(ATMOSPHERE_OS_HORIZON) /* Initialize/sanity check. */ InitializeInitialAndCurrentProcessId(); AMS_ABORT_UNLESS(g_initial_process_id_min > 0); /* Check process id in range. */ return g_initial_process_id_min <= process_id && process_id <= g_initial_process_id_max; + #elif defined(ATMOSPHERE_OS_WINDOWS) || defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS) + AMS_UNUSED(process_id); + return true; + #else + #error "Unknown os for fssrv::impl::IsInitialProgram" + #endif } bool IsCurrentProcess(u64 process_id) { + #if defined(ATMOSPHERE_OS_HORIZON) /* Initialize. */ InitializeInitialAndCurrentProcessId(); return process_id == g_current_process_id; + #elif defined(ATMOSPHERE_OS_WINDOWS) || defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS) + AMS_UNUSED(process_id); + return true; + #else + #error "Unknown os for fssrv::impl::IsCurrentProcess" + #endif } } diff --git a/libraries/libstratosphere/source/fssrv/impl/fssrv_program_info.hpp b/libraries/libstratosphere/source/fssrv/impl/fssrv_program_info.hpp index 10607d7f9..6b54ed69f 100644 --- a/libraries/libstratosphere/source/fssrv/impl/fssrv_program_info.hpp +++ b/libraries/libstratosphere/source/fssrv/impl/fssrv_program_info.hpp @@ -41,7 +41,7 @@ namespace ams::fssrv::impl { public: static std::shared_ptr GetProgramInfoForInitialProcess(); private: - ProgramInfo(const void *data, s64 data_size, const void *desc, s64 desc_size) : m_process_id(0), m_program_id(0), m_storage_id(static_cast(0)) /* TODO: m_access_control */ { + ProgramInfo(const void *data, s64 data_size, const void *desc, s64 desc_size) : m_process_id(os::InvalidProcessId), m_program_id(ncm::InvalidProgramId), m_storage_id(static_cast(0)) /* TODO: m_access_control */ { /* TODO */ AMS_UNUSED(data, data_size, desc, desc_size); } diff --git a/libraries/libstratosphere/source/fssrv/impl/fssrv_utility.cpp b/libraries/libstratosphere/source/fssrv/impl/fssrv_utility.cpp new file mode 100644 index 000000000..993285ac2 --- /dev/null +++ b/libraries/libstratosphere/source/fssrv/impl/fssrv_utility.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (c) 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 "fssrv_utility.hpp" + +#if defined(ATMOSPHERE_OS_LINUX) +#include +#elif defined(ATMOSPHERE_OS_MACOS) +#include +#endif + +namespace ams::fssystem { + + class PathOnExecutionDirectory { + private: + char m_path[fs::EntryNameLengthMax + 1]; + public: + PathOnExecutionDirectory() { + #if defined(ATMOSPHERE_OS_WINDOWS) + { + /* Get the module file name. */ + wchar_t module_file_name[fs::EntryNameLengthMax + 1]; + if (::GetModuleFileNameW(0, module_file_name, util::size(module_file_name)) == 0) { + AMS_FS_R_ABORT_UNLESS(fs::ResultUnexpectedInPathOnExecutionDirectoryA()); + } + + /* Split the path. */ + wchar_t drive_name[3]; + wchar_t dir_name[fs::EntryNameLengthMax + 1]; + ::_wsplitpath_s(module_file_name, drive_name, util::size(drive_name), dir_name, util::size(dir_name), nullptr, 0, nullptr, 0); + + /* Print the drive and directory. */ + wchar_t path[fs::EntryNameLengthMax + 1]; + ::swprintf_s(path, util::size(path), L"%s%s", drive_name, dir_name); + + /* Convert to utf-8. */ + const auto res = ::WideCharToMultiByte(CP_UTF8, 0, path, -1, m_path, util::size(m_path), nullptr, nullptr); + if (res == 0) { + AMS_FS_R_ABORT_UNLESS(fs::ResultUnexpectedInPathOnExecutionDirectoryB()); + } + } + #elif defined(ATMOSPHERE_OS_LINUX) + { + char full_path[PATH_MAX] = {}; + if (::readlink("/proc/self/exe", full_path, sizeof(full_path)) == -1) { + AMS_FS_R_ABORT_UNLESS(fs::ResultUnexpectedInPathOnExecutionDirectoryA()); + } + + const int len = std::strlen(full_path); + std::memcpy(m_path, full_path, len + 1); + + for (int i = len - 1; i >= 0; --i) { + if (m_path[i] == '/') { + m_path[i + 1] = 0; + break; + } + } + } + #elif defined(ATMOSPHERE_OS_MACOS) + { + char full_path[PATH_MAX + 1] = {}; + uint32_t size = sizeof(full_path); + AMS_ABORT_UNLESS(_NSGetExecutablePath(full_path, std::addressof(size)) == 0); + + const int len = std::strlen(full_path); + std::memcpy(m_path, full_path, len + 1); + + for (int i = len - 1; i >= 0; --i) { + if (m_path[i] == '/') { + m_path[i + 1] = 0; + break; + } + } + } + #else + AMS_ABORT("TODO: Unknown OS for PathOnExecutionDirectory"); + #endif + } + + const char *Get() const { + return m_path; + } + }; + +} + +namespace ams::fssrv::impl { + + const char *GetExecutionDirectoryPath() { + AMS_FUNCTION_LOCAL_STATIC(fssystem::PathOnExecutionDirectory, s_path_on_execution_directory); + return s_path_on_execution_directory.Get(); + } + +} diff --git a/libraries/libstratosphere/source/fssrv/impl/fssrv_utility.hpp b/libraries/libstratosphere/source/fssrv/impl/fssrv_utility.hpp new file mode 100644 index 000000000..fcf057aad --- /dev/null +++ b/libraries/libstratosphere/source/fssrv/impl/fssrv_utility.hpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 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::fssrv::impl { + + const char *GetExecutionDirectoryPath(); + +} diff --git a/libraries/libstratosphere/source/fssystem/fssystem_crypto_configuration.cpp b/libraries/libstratosphere/source/fssystem/fssystem_crypto_configuration.cpp index 56cd79df0..05c2db6c5 100644 --- a/libraries/libstratosphere/source/fssystem/fssystem_crypto_configuration.cpp +++ b/libraries/libstratosphere/source/fssystem/fssystem_crypto_configuration.cpp @@ -206,7 +206,7 @@ namespace ams::fssystem { /* Setup the keyslot cache. */ for (s32 i = 0; i < KeySlotCacheEntryCount; i++) { - s32 slot_index; + s32 slot_index = -1; R_ABORT_UNLESS(spl::AllocateAesKeySlot(std::addressof(slot_index))); g_key_slot_cache_entry[i].emplace(slot_index); g_key_slot_cache.AddEntry(std::addressof(g_key_slot_cache_entry[i].value())); diff --git a/libraries/libstratosphere/source/fssystem/fssystem_directory_redirection_filesystem.cpp b/libraries/libstratosphere/source/fssystem/fssystem_directory_redirection_filesystem.cpp deleted file mode 100644 index b8be9c3d3..000000000 --- a/libraries/libstratosphere/source/fssystem/fssystem_directory_redirection_filesystem.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (c) 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 - -namespace ams::fssystem { - - DirectoryRedirectionFileSystem::DirectoryRedirectionFileSystem(std::shared_ptr fs, const char *before, const char *after, bool unc) - : PathResolutionFileSystem(fs, unc) - { - m_before_dir = nullptr; - m_after_dir = nullptr; - R_ABORT_UNLESS(this->Initialize(before, after)); - } - - DirectoryRedirectionFileSystem::DirectoryRedirectionFileSystem(std::unique_ptr fs, const char *before, const char *after, bool unc) - : PathResolutionFileSystem(std::move(fs), unc) - { - m_before_dir = nullptr; - m_after_dir = nullptr; - R_ABORT_UNLESS(this->Initialize(before, after)); - } - - DirectoryRedirectionFileSystem::~DirectoryRedirectionFileSystem() { - if (m_before_dir != nullptr) { - fs::impl::Deallocate(m_before_dir, m_before_dir_len); - } - if (m_after_dir != nullptr) { - fs::impl::Deallocate(m_after_dir, m_after_dir_len); - } - } - - Result DirectoryRedirectionFileSystem::GetNormalizedDirectoryPath(char **out, size_t *out_size, const char *dir) { - /* Clear output. */ - *out = nullptr; - *out_size = 0; - - /* Make sure the path isn't too long. */ - R_UNLESS(strnlen(dir, fs::EntryNameLengthMax + 1) <= fs::EntryNameLengthMax, fs::ResultTooLongPath()); - - /* Normalize the path. */ - char normalized_path[fs::EntryNameLengthMax + 2]; - size_t normalized_path_len; - R_TRY(fs::PathNormalizer::Normalize(normalized_path, &normalized_path_len, dir, sizeof(normalized_path), this->IsUncPreserved(), false)); - - /* Ensure terminating '/' */ - if (!fs::PathNormalizer::IsSeparator(normalized_path[normalized_path_len - 1])) { - AMS_ASSERT(normalized_path_len + 2 < sizeof(normalized_path)); - normalized_path[normalized_path_len] = fs::StringTraits::DirectorySeparator; - normalized_path[normalized_path_len + 1] = fs::StringTraits::NullTerminator; - - ++normalized_path_len; - } - - /* Allocate new path. */ - const size_t size = normalized_path_len + 1; - char *new_dir = static_cast(fs::impl::Allocate(size)); - AMS_ABORT_UNLESS(new_dir != nullptr); - /* TODO: custom fs::ResultAllocationFailure? */ - - /* Copy path in. */ - std::memcpy(new_dir, normalized_path, normalized_path_len); - new_dir[normalized_path_len] = fs::StringTraits::NullTerminator; - - /* Set output. */ - *out = new_dir; - *out_size = size; - return ResultSuccess(); - } - - Result DirectoryRedirectionFileSystem::Initialize(const char *before, const char *after) { - /* Normalize both directories. */ - this->GetNormalizedDirectoryPath(std::addressof(m_before_dir), std::addressof(m_before_dir_len), before); - this->GetNormalizedDirectoryPath(std::addressof(m_after_dir), std::addressof(m_after_dir_len), after); - - return ResultSuccess(); - } - - Result DirectoryRedirectionFileSystem::ResolveFullPath(char *out, size_t out_size, const char *relative_path) { - /* Check pre-conditions. */ - AMS_ASSERT(relative_path[0] == '/'); - AMS_ASSERT(m_before_dir_len >= 2); - AMS_ASSERT(m_after_dir_len >= 2); - AMS_ASSERT(m_after_dir_len <= out_size); - AMS_ASSERT(fs::PathNormalizer::IsNullTerminator(m_before_dir[m_before_dir_len - 1])); - AMS_ASSERT(fs::PathNormalizer::IsSeparator(m_before_dir[m_before_dir_len - 2])); - AMS_ASSERT(fs::PathNormalizer::IsNullTerminator(m_after_dir[m_after_dir_len - 1])); - AMS_ASSERT(fs::PathNormalizer::IsSeparator(m_after_dir[m_after_dir_len - 2])); - - /* Normalize the relative path. */ - char normalized_rel_path[fs::EntryNameLengthMax + 1]; - size_t normalized_rel_path_len; - R_TRY(fs::PathNormalizer::Normalize(normalized_rel_path, std::addressof(normalized_rel_path_len), relative_path, sizeof(normalized_rel_path), this->IsUncPreserved(), false)); - - const bool is_prefixed = std::memcmp(normalized_rel_path, m_before_dir, m_before_dir_len - 2) == 0 && - (fs::PathNormalizer::IsSeparator(normalized_rel_path[m_before_dir_len - 2]) || fs::PathNormalizer::IsNullTerminator(normalized_rel_path[m_before_dir_len - 2])); - if (is_prefixed) { - const size_t before_prefix_len = m_before_dir_len - 2; - const size_t after_prefix_len = m_after_dir_len - 2; - const size_t final_str_len = after_prefix_len + normalized_rel_path_len - before_prefix_len; - R_UNLESS(final_str_len < out_size, fs::ResultTooLongPath()); - - /* Copy normalized path. */ - std::memcpy(out, m_after_dir, after_prefix_len); - std::memcpy(out + after_prefix_len, normalized_rel_path + before_prefix_len, normalized_rel_path_len - before_prefix_len); - out[final_str_len] = fs::StringTraits::NullTerminator; - } else { - /* Path is not prefixed. */ - R_UNLESS(normalized_rel_path_len + 1 <= out_size, fs::ResultTooLongPath()); - std::memcpy(out, normalized_rel_path, normalized_rel_path_len); - out[normalized_rel_path_len] = fs::StringTraits::NullTerminator; - } - - return ResultSuccess(); - } - -} diff --git a/libraries/libstratosphere/source/fssystem/fssystem_directory_savedata_filesystem.cpp b/libraries/libstratosphere/source/fssystem/fssystem_directory_savedata_filesystem.cpp index 152c6d10b..34d84bcf5 100644 --- a/libraries/libstratosphere/source/fssystem/fssystem_directory_savedata_filesystem.cpp +++ b/libraries/libstratosphere/source/fssystem/fssystem_directory_savedata_filesystem.cpp @@ -19,13 +19,15 @@ namespace ams::fssystem { namespace { - constexpr size_t IdealWorkBufferSize = 0x100000; /* 1 MiB */ + constexpr size_t IdealWorkBufferSize = 1_MB; + constexpr size_t MinimumWorkBufferSize = 1_KB; - constexpr const char CommittedDirectoryPath[] = "/0/"; - constexpr const char WorkingDirectoryPath[] = "/1/"; - constexpr const char SynchronizingDirectoryPath[] = "/_/"; + constexpr const fs::Path CommittedDirectoryPath = fs::MakeConstantPath("/0"); + constexpr const fs::Path WorkingDirectoryPath = fs::MakeConstantPath("/1"); + constexpr const fs::Path SynchronizingDirectoryPath = fs::MakeConstantPath("/_"); + constexpr const fs::Path LockFilePath = fs::MakeConstantPath("/.lock"); - class DirectorySaveDataFile : public fs::fsa::IFile { + class DirectorySaveDataFile : public fs::fsa::IFile, public fs::impl::Newable { private: std::unique_ptr m_base_file; DirectorySaveDataFileSystem *m_parent_fs; @@ -38,7 +40,7 @@ namespace ams::fssystem { virtual ~DirectorySaveDataFile() { /* Observe closing of writable file. */ if (m_open_mode & fs::OpenMode_Write) { - m_parent_fs->OnWritableFileClose(); + m_parent_fs->DecrementWriteOpenFileCount(); } } public: @@ -73,25 +75,14 @@ namespace ams::fssystem { } - DirectorySaveDataFileSystem::DirectorySaveDataFileSystem(std::shared_ptr fs) - : PathResolutionFileSystem(fs), m_accessor_mutex(), m_open_writable_files(0) - { - /* ... */ - } + Result DirectorySaveDataFileSystem::Initialize(bool journaling_supported, bool multi_commit_supported, bool journaling_enabled) { + /* Configure ourselves. */ + m_is_journaling_supported = journaling_supported; + m_is_multi_commit_supported = multi_commit_supported; + m_is_journaling_enabled = journaling_enabled; - DirectorySaveDataFileSystem::DirectorySaveDataFileSystem(std::unique_ptr fs) - : PathResolutionFileSystem(std::move(fs)), m_accessor_mutex(), m_open_writable_files(0) - { - /* ... */ - } - - DirectorySaveDataFileSystem::~DirectorySaveDataFileSystem() { - /* ... */ - } - - Result DirectorySaveDataFileSystem::Initialize() { - /* Nintendo does not acquire the lock here, but I think we probably should. */ - std::scoped_lock lk(m_accessor_mutex); + /* Ensure that we can initialize further by acquiring a lock on the filesystem. */ + R_TRY(this->AcquireLockFile()); fs::DirectoryEntryType type; @@ -100,44 +91,35 @@ namespace ams::fssystem { /* If path isn't found, create working directory and committed directory. */ R_CATCH(fs::ResultPathNotFound) { R_TRY(m_base_fs->CreateDirectory(WorkingDirectoryPath)); - R_TRY(m_base_fs->CreateDirectory(CommittedDirectoryPath)); + + if (m_is_journaling_supported) { + R_TRY(m_base_fs->CreateDirectory(CommittedDirectoryPath)); + } } } R_END_TRY_CATCH; - /* Now check for the committed directory. */ - R_TRY_CATCH(m_base_fs->GetEntryType(std::addressof(type), CommittedDirectoryPath)) { - /* Committed doesn't exist, so synchronize and rename. */ - R_CATCH(fs::ResultPathNotFound) { - R_TRY(this->SynchronizeDirectory(SynchronizingDirectoryPath, WorkingDirectoryPath)); - R_TRY(m_base_fs->RenameDirectory(SynchronizingDirectoryPath, CommittedDirectoryPath)); - return ResultSuccess(); - } - } R_END_TRY_CATCH; + /* If we support journaling, we need to set up the committed directory. */ + if (m_is_journaling_supported) { + /* Now check for the committed directory. */ + R_TRY_CATCH(m_base_fs->GetEntryType(std::addressof(type), CommittedDirectoryPath)) { + /* Committed doesn't exist, so synchronize and rename. */ + R_CATCH(fs::ResultPathNotFound) { + R_TRY(this->SynchronizeDirectory(SynchronizingDirectoryPath, WorkingDirectoryPath)); + R_TRY(m_base_fs->RenameDirectory(SynchronizingDirectoryPath, CommittedDirectoryPath)); + R_SUCCEED(); + } + } R_END_TRY_CATCH; - /* The committed directory exists, so synchronize it to the working directory. */ - return this->SynchronizeDirectory(WorkingDirectoryPath, CommittedDirectoryPath); - } - - Result DirectorySaveDataFileSystem::AllocateWorkBuffer(std::unique_ptr *out, size_t *out_size, size_t size) { - /* Repeatedly try to allocate until success. */ - while (size > 0x200) { - /* Allocate the buffer. */ - if (auto mem = new (std::nothrow) u8[size]; mem != nullptr) { - out->reset(mem); - *out_size = size; - return ResultSuccess(); - } else { - /* Divide size by two. */ - size >>= 1; + /* The committed directory exists, so if we should, synchronize it to the working directory. */ + if (m_is_journaling_enabled) { + R_TRY(this->SynchronizeDirectory(WorkingDirectoryPath, CommittedDirectoryPath)); } } - /* TODO: Return a result here? Nintendo does not, but they have other allocation failed results. */ - /* Consider returning fs::ResultFsAllocationFailureInDirectorySaveDataFileSystem? */ - AMS_ABORT_UNLESS(false); + R_SUCCEED(); } - Result DirectorySaveDataFileSystem::SynchronizeDirectory(const char *dst, const char *src) { + Result DirectorySaveDataFileSystem::SynchronizeDirectory(const fs::Path &dst, const fs::Path &src) { /* Delete destination dir and recreate it. */ R_TRY_CATCH(m_base_fs->DeleteDirectoryRecursively(dst)) { R_CATCH(fs::ResultPathNotFound) { /* Nintendo returns error unconditionally, but I think that's a bug in their code. */} @@ -146,132 +128,239 @@ namespace ams::fssystem { R_TRY(m_base_fs->CreateDirectory(dst)); /* Get a work buffer to work with. */ - std::unique_ptr work_buf; - size_t work_buf_size; - R_TRY(this->AllocateWorkBuffer(std::addressof(work_buf), std::addressof(work_buf_size), IdealWorkBufferSize)); + fssystem::PooledBuffer buffer; + buffer.AllocateParticularlyLarge(IdealWorkBufferSize, MinimumWorkBufferSize); /* Copy the directory recursively. */ - return fssystem::CopyDirectoryRecursively(m_base_fs, dst, src, work_buf.get(), work_buf_size); + fs::DirectoryEntry dir_entry_buffer = {}; + R_RETURN(fssystem::CopyDirectoryRecursively(m_base_fs, dst, src, std::addressof(dir_entry_buffer), buffer.GetBuffer(), buffer.GetSize())); } - Result DirectorySaveDataFileSystem::ResolveFullPath(char *out, size_t out_size, const char *relative_path) { - R_UNLESS(strnlen(relative_path, fs::EntryNameLengthMax + 1) < fs::EntryNameLengthMax + 1, fs::ResultTooLongPath()); - R_UNLESS(fs::PathNormalizer::IsSeparator(relative_path[0]), fs::ResultInvalidPath()); - - /* Copy working directory path. */ - std::strncpy(out, WorkingDirectoryPath, out_size); - out[out_size - 1] = fs::StringTraits::NullTerminator; - - /* Normalize it. */ - constexpr size_t WorkingDirectoryPathLength = sizeof(WorkingDirectoryPath) - 1; - size_t normalized_length; - return fs::PathNormalizer::Normalize(out + WorkingDirectoryPathLength - 1, std::addressof(normalized_length), relative_path, out_size - (WorkingDirectoryPathLength - 1)); + Result DirectorySaveDataFileSystem::ResolvePath(fs::Path *out, const fs::Path &path) { + const fs::Path &directory = (m_is_journaling_supported && !m_is_journaling_enabled) ? CommittedDirectoryPath : WorkingDirectoryPath; + R_RETURN(out->Combine(directory, path)); } - void DirectorySaveDataFileSystem::OnWritableFileClose() { + Result DirectorySaveDataFileSystem::AcquireLockFile() { + /* If we already have a lock file, we don't need to lock again. */ + R_SUCCEED_IF(m_lock_file != nullptr); + + /* Open the lock file. */ + std::unique_ptr file; + R_TRY_CATCH(m_base_fs->OpenFile(std::addressof(file), LockFilePath, fs::OpenMode_ReadWrite)) { + /* If the lock file doesn't yet exist, we may need to create it. */ + R_CATCH(fs::ResultPathNotFound) { + R_TRY(m_base_fs->CreateFile(LockFilePath, 0)); + R_TRY(m_base_fs->OpenFile(std::addressof(file), LockFilePath, fs::OpenMode_ReadWrite)); + } + } R_END_TRY_CATCH; + + /* Set our lock file. */ + m_lock_file = std::move(file); + R_SUCCEED(); + } + + void DirectorySaveDataFileSystem::DecrementWriteOpenFileCount() { std::scoped_lock lk(m_accessor_mutex); - m_open_writable_files--; - /* Nintendo does not check this, but I think it's sensible to do so. */ - AMS_ABORT_UNLESS(m_open_writable_files >= 0); + --m_open_writable_files; } - Result DirectorySaveDataFileSystem::CopySaveFromFileSystem(fs::fsa::IFileSystem *save_fs) { - /* If the input save is null, there's nothing to copy. */ - R_SUCCEED_IF(save_fs == nullptr); - - /* Get a work buffer to work with. */ - std::unique_ptr work_buf; - size_t work_buf_size; - R_TRY(this->AllocateWorkBuffer(std::addressof(work_buf), std::addressof(work_buf_size), IdealWorkBufferSize)); - - /* Copy the directory recursively. */ - R_TRY(fssystem::CopyDirectoryRecursively(m_base_fs, save_fs, fs::PathNormalizer::RootPath, fs::PathNormalizer::RootPath, work_buf.get(), work_buf_size)); - - return this->Commit(); - } - - /* Overridden from IPathResolutionFileSystem */ - Result DirectorySaveDataFileSystem::DoOpenFile(std::unique_ptr *out_file, const char *path, fs::OpenMode mode) { - char full_path[fs::EntryNameLengthMax + 1]; - R_TRY(this->ResolveFullPath(full_path, sizeof(full_path), path)); + Result DirectorySaveDataFileSystem::DoCreateFile(const fs::Path &path, s64 size, int option) { + /* Resolve the final path. */ + fs::Path resolved; + R_TRY(this->ResolvePath(std::addressof(resolved), path)); + /* Lock ourselves. */ std::scoped_lock lk(m_accessor_mutex); + + R_RETURN(m_base_fs->CreateFile(resolved, size, option)); + } + Result DirectorySaveDataFileSystem::DoDeleteFile(const fs::Path &path) { + /* Resolve the final path. */ + fs::Path resolved; + R_TRY(this->ResolvePath(std::addressof(resolved), path)); + + /* Lock ourselves. */ + std::scoped_lock lk(m_accessor_mutex); + + R_RETURN(m_base_fs->DeleteFile(resolved)); + } + + Result DirectorySaveDataFileSystem::DoCreateDirectory(const fs::Path &path) { + /* Resolve the final path. */ + fs::Path resolved; + R_TRY(this->ResolvePath(std::addressof(resolved), path)); + + /* Lock ourselves. */ + std::scoped_lock lk(m_accessor_mutex); + + R_RETURN(m_base_fs->CreateDirectory(resolved)); + } + + Result DirectorySaveDataFileSystem::DoDeleteDirectory(const fs::Path &path) { + /* Resolve the final path. */ + fs::Path resolved; + R_TRY(this->ResolvePath(std::addressof(resolved), path)); + + /* Lock ourselves. */ + std::scoped_lock lk(m_accessor_mutex); + + R_RETURN(m_base_fs->DeleteDirectory(resolved)); + } + + Result DirectorySaveDataFileSystem::DoDeleteDirectoryRecursively(const fs::Path &path) { + /* Resolve the final path. */ + fs::Path resolved; + R_TRY(this->ResolvePath(std::addressof(resolved), path)); + + /* Lock ourselves. */ + std::scoped_lock lk(m_accessor_mutex); + + R_RETURN(m_base_fs->DeleteDirectoryRecursively(resolved)); + } + + Result DirectorySaveDataFileSystem::DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) { + /* Resolve the final paths. */ + fs::Path old_resolved; + fs::Path new_resolved; + R_TRY(this->ResolvePath(std::addressof(old_resolved), old_path)); + R_TRY(this->ResolvePath(std::addressof(new_resolved), new_path)); + + /* Lock ourselves. */ + std::scoped_lock lk(m_accessor_mutex); + + R_RETURN(m_base_fs->RenameFile(old_resolved, new_resolved)); + } + + Result DirectorySaveDataFileSystem::DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) { + /* Resolve the final paths. */ + fs::Path old_resolved; + fs::Path new_resolved; + R_TRY(this->ResolvePath(std::addressof(old_resolved), old_path)); + R_TRY(this->ResolvePath(std::addressof(new_resolved), new_path)); + + /* Lock ourselves. */ + std::scoped_lock lk(m_accessor_mutex); + + R_RETURN(m_base_fs->RenameDirectory(old_resolved, new_resolved)); + } + + Result DirectorySaveDataFileSystem::DoGetEntryType(fs::DirectoryEntryType *out, const fs::Path &path) { + /* Resolve the final path. */ + fs::Path resolved; + R_TRY(this->ResolvePath(std::addressof(resolved), path)); + + /* Lock ourselves. */ + std::scoped_lock lk(m_accessor_mutex); + + R_RETURN(m_base_fs->GetEntryType(out, resolved)); + } + + Result DirectorySaveDataFileSystem::DoOpenFile(std::unique_ptr *out_file, const fs::Path &path, fs::OpenMode mode) { + /* Resolve the final path. */ + fs::Path resolved; + R_TRY(this->ResolvePath(std::addressof(resolved), path)); + + /* Lock ourselves. */ + std::scoped_lock lk(m_accessor_mutex); + + /* Open base file. */ std::unique_ptr base_file; - R_TRY(m_base_fs->OpenFile(std::addressof(base_file), full_path, mode)); + R_TRY(m_base_fs->OpenFile(std::addressof(base_file), resolved, mode)); - std::unique_ptr file(new (std::nothrow) DirectorySaveDataFile(std::move(base_file), this, mode)); + /* Make DirectorySaveDataFile. */ + std::unique_ptr file = std::make_unique(std::move(base_file), this, mode); R_UNLESS(file != nullptr, fs::ResultAllocationFailureInDirectorySaveDataFileSystem()); + /* Increment our open writable files, if the file is writable. */ if (mode & fs::OpenMode_Write) { - m_open_writable_files++; + ++m_open_writable_files; } + /* Set the output. */ *out_file = std::move(file); - return ResultSuccess(); + R_SUCCEED(); + } + + Result DirectorySaveDataFileSystem::DoOpenDirectory(std::unique_ptr *out_dir, const fs::Path &path, fs::OpenDirectoryMode mode) { + /* Resolve the final path. */ + fs::Path resolved; + R_TRY(this->ResolvePath(std::addressof(resolved), path)); + + /* Lock ourselves. */ + std::scoped_lock lk(m_accessor_mutex); + + R_RETURN(m_base_fs->OpenDirectory(out_dir, resolved, mode)); } Result DirectorySaveDataFileSystem::DoCommit() { - /* Here, Nintendo does the following (with retries): */ - /* - Rename Committed -> Synchronizing. */ - /* - Synchronize Working -> Synchronizing (deleting Synchronizing). */ - /* - Rename Synchronizing -> Committed. */ + /* Lock ourselves. */ std::scoped_lock lk(m_accessor_mutex); - R_UNLESS(m_open_writable_files == 0, fs::ResultPreconditionViolation()); + /* If we aren't journaling, we don't need to do anything. */ + R_SUCCEED_IF(!m_is_journaling_enabled); + R_SUCCEED_IF(!m_is_journaling_supported); - const auto RenameCommitedDir = [&]() { return m_base_fs->RenameDirectory(CommittedDirectoryPath, SynchronizingDirectoryPath); }; - const auto SynchronizeWorkingDir = [&]() { return this->SynchronizeDirectory(SynchronizingDirectoryPath, WorkingDirectoryPath); }; - const auto RenameSynchronizingDir = [&]() { return m_base_fs->RenameDirectory(SynchronizingDirectoryPath, CommittedDirectoryPath); }; + /* Check that there are no open files blocking the commit. */ + R_UNLESS(m_open_writable_files == 0, fs::ResultWriteModeFileNotClosed()); - /* Rename Committed -> Synchronizing. */ - R_TRY(fssystem::RetryFinitelyForTargetLocked(std::move(RenameCommitedDir))); + /* Remove the previous commit by renaming the folder. */ + R_TRY(fssystem::RetryFinitelyForTargetLocked([&] () ALWAYS_INLINE_LAMBDA { R_RETURN(m_base_fs->RenameDirectory(CommittedDirectoryPath, SynchronizingDirectoryPath)); })); - /* - Synchronize Working -> Synchronizing (deleting Synchronizing). */ - R_TRY(fssystem::RetryFinitelyForTargetLocked(std::move(SynchronizeWorkingDir))); + /* Synchronize the working directory to the synchronizing directory. */ + R_TRY(fssystem::RetryFinitelyForTargetLocked([&] () ALWAYS_INLINE_LAMBDA { R_RETURN(this->SynchronizeDirectory(SynchronizingDirectoryPath, WorkingDirectoryPath)); })); - /* - Rename Synchronizing -> Committed. */ - R_TRY(fssystem::RetryFinitelyForTargetLocked(std::move(RenameSynchronizingDir))); + /* Rename the synchronized directory to commit it. */ + R_TRY(fssystem::RetryFinitelyForTargetLocked([&] () ALWAYS_INLINE_LAMBDA { R_RETURN(m_base_fs->RenameDirectory(SynchronizingDirectoryPath, CommittedDirectoryPath)); })); - /* TODO: Should I call m_base_fs->Commit()? Nintendo does not. */ - return ResultSuccess(); + R_SUCCEED(); + } + + Result DirectorySaveDataFileSystem::DoGetFreeSpaceSize(s64 *out, const fs::Path &path) { + /* Lock ourselves. */ + std::scoped_lock lk(m_accessor_mutex); + + /* Get the free space size in our working directory. */ + AMS_UNUSED(path); + R_RETURN(m_base_fs->GetFreeSpaceSize(out, WorkingDirectoryPath)); + } + + Result DirectorySaveDataFileSystem::DoGetTotalSpaceSize(s64 *out, const fs::Path &path) { + /* Lock ourselves. */ + std::scoped_lock lk(m_accessor_mutex); + + /* Get the free space size in our working directory. */ + AMS_UNUSED(path); + R_RETURN(m_base_fs->GetTotalSpaceSize(out, WorkingDirectoryPath)); + } + + Result DirectorySaveDataFileSystem::DoCleanDirectoryRecursively(const fs::Path &path) { + /* Resolve the final path. */ + fs::Path resolved; + R_TRY(this->ResolvePath(std::addressof(resolved), path)); + + /* Lock ourselves. */ + std::scoped_lock lk(m_accessor_mutex); + + R_RETURN(m_base_fs->CleanDirectoryRecursively(resolved)); } - /* Overridden from IPathResolutionFileSystem but not commands. */ Result DirectorySaveDataFileSystem::DoCommitProvisionally(s64 counter) { - /* Nintendo does nothing here. */ + /* Check that we support multi-commit. */ + R_UNLESS(m_is_multi_commit_supported, fs::ResultUnsupportedOperationInDirectorySaveDataFileSystemA()); + + /* Do nothing. */ AMS_UNUSED(counter); - return ResultSuccess(); + R_SUCCEED(); } Result DirectorySaveDataFileSystem::DoRollback() { - /* Initialize overwrites the working directory with the committed directory. */ - return this->Initialize(); - } + /* On non-journaled savedata, there's nothing to roll back to. */ + R_SUCCEED_IF(!m_is_journaling_supported); - /* Explicitly overridden to be not implemented. */ - Result DirectorySaveDataFileSystem::DoGetFreeSpaceSize(s64 *out, const char *path) { - AMS_UNUSED(out, path); - return fs::ResultNotImplemented(); - } - - Result DirectorySaveDataFileSystem::DoGetTotalSpaceSize(s64 *out, const char *path) { - AMS_UNUSED(out, path); - return fs::ResultNotImplemented(); - } - - Result DirectorySaveDataFileSystem::DoGetFileTimeStampRaw(fs::FileTimeStampRaw *out, const char *path) { - AMS_UNUSED(out, path); - return fs::ResultNotImplemented(); - } - - Result DirectorySaveDataFileSystem::DoQueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const char *path) { - AMS_UNUSED(dst, dst_size, src, src_size, query, path); - return fs::ResultNotImplemented(); - } - - Result DirectorySaveDataFileSystem::DoFlush() { - return fs::ResultNotImplemented(); + /* Perform a re-initialize. */ + R_RETURN(this->Initialize(m_is_journaling_supported, m_is_multi_commit_supported, m_is_journaling_enabled)); } } diff --git a/libraries/libstratosphere/source/fssystem/fssystem_external_code.cpp b/libraries/libstratosphere/source/fssystem/fssystem_external_code.cpp index aeb9ab12f..566776579 100644 --- a/libraries/libstratosphere/source/fssystem/fssystem_external_code.cpp +++ b/libraries/libstratosphere/source/fssystem/fssystem_external_code.cpp @@ -17,6 +17,7 @@ namespace ams::fssystem { + #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) namespace { constexpr inline size_t MaxExternalCodeFileSystem = 0x10; @@ -72,5 +73,21 @@ namespace ams::fssystem { g_hnd_map.Remove(program_id); } } + #else + fs::fsa::IFileSystem *GetExternalCodeFileSystem(ncm::ProgramId program_id) { + AMS_UNUSED(program_id); + return nullptr; + } + + Result CreateExternalCode(os::NativeHandle *out, ncm::ProgramId program_id) { + AMS_UNUSED(out, program_id); + R_THROW(fs::ResultNotImplemented()); + } + + void DestroyExternalCode(ncm::ProgramId program_id) { + AMS_UNUSED(program_id); + } + #endif + } diff --git a/libraries/libstratosphere/source/fssystem/fssystem_file_system_proxy_api.cpp b/libraries/libstratosphere/source/fssystem/fssystem_file_system_proxy_api.cpp index 5697c1416..0e6539f71 100644 --- a/libraries/libstratosphere/source/fssystem/fssystem_file_system_proxy_api.cpp +++ b/libraries/libstratosphere/source/fssystem/fssystem_file_system_proxy_api.cpp @@ -39,9 +39,9 @@ namespace ams::fssystem { constexpr size_t MaxCacheCount = 1024; constexpr size_t BlockSize = 16_KB; - alignas(os::MemoryPageSize) u8 g_exp_heap_buffer[ExpHeapSize]; - lmem::HeapHandle g_exp_heap_handle = nullptr; - fssrv::PeakCheckableMemoryResourceFromExpHeap g_exp_allocator(ExpHeapSize); + alignas(os::MemoryPageSize) constinit u8 g_exp_heap_buffer[ExpHeapSize]; + constinit lmem::HeapHandle g_exp_heap_handle = nullptr; + constinit fssrv::PeakCheckableMemoryResourceFromExpHeap g_exp_allocator(ExpHeapSize); void InitializeExpHeap() { if (g_exp_heap_handle == nullptr) { @@ -70,25 +70,25 @@ namespace ams::fssystem { lmem::FreeToExpHeap(g_exp_heap_handle, p); } - alignas(os::MemoryPageSize) u8 g_device_buffer[DeviceBufferSize]; + alignas(os::MemoryPageSize) constinit u8 g_device_buffer[DeviceBufferSize] = {}; - alignas(os::MemoryPageSize) u8 g_buffer_pool[BufferPoolSize]; + alignas(os::MemoryPageSize) constinit u8 g_buffer_pool[BufferPoolSize] = {}; - util::TypedStorage g_buffer_allocator; - util::TypedStorage g_allocator; + constinit util::TypedStorage g_buffer_allocator = {}; + constinit util::TypedStorage g_allocator = {}; /* TODO: Nintendo uses os::SetMemoryHeapSize (svc::SetHeapSize) and os::AllocateMemoryBlock for the BufferManager heap. */ /* It's unclear how we should handle this in ams.mitm (especially hoping to reuse some logic for fs reimpl). */ /* Should we be doing the same(?) */ - util::TypedStorage g_buffer_manager; - alignas(os::MemoryPageSize) u8 g_buffer_manager_heap[BufferManagerHeapSize]; + constinit util::TypedStorage g_buffer_manager = {}; + alignas(os::MemoryPageSize) constinit u8 g_buffer_manager_heap[BufferManagerHeapSize] = {}; /* FileSystem creators. */ - util::TypedStorage g_rom_fs_creator; - util::TypedStorage g_partition_fs_creator; - util::TypedStorage g_storage_on_nca_creator; + constinit util::TypedStorage g_rom_fs_creator = {}; + constinit util::TypedStorage g_partition_fs_creator = {}; + constinit util::TypedStorage g_storage_on_nca_creator = {}; - fssrv::fscreator::FileSystemCreatorInterfaces g_fs_creator_interfaces = {}; + constinit fssrv::fscreator::FileSystemCreatorInterfaces g_fs_creator_interfaces = {}; } @@ -162,7 +162,21 @@ namespace ams::fssystem { /* TODO FS-REIMPL: Sd Card detection, speed emulation. */ /* Initialize fssrv. TODO FS-REIMPL: More arguments, more actions taken. */ - fssrv::InitializeForFileSystemProxy(std::addressof(g_fs_creator_interfaces), GetPointer(g_buffer_manager), is_development_function_enabled); + const fssrv::FileSystemProxyConfiguration config = { + .m_fs_creator_interfaces = std::addressof(g_fs_creator_interfaces), + .m_base_storage_service_impl = nullptr /* TODO */, + .m_base_file_system_service_impl = nullptr /* TODO */, + .m_nca_file_system_service_impl = nullptr /* TODO */, + .m_save_data_file_system_service_impl = nullptr /* TODO */, + .m_access_failure_management_service_impl = nullptr /* TODO */, + .m_time_service_impl = nullptr /* TODO */, + .m_status_report_service_impl = nullptr /* TODO */, + .m_program_registry_service_impl = std::addressof(program_registry_service), + .m_access_log_service_impl = nullptr /* TODO */, + .m_debug_configuration_service_impl = nullptr /* TODO */, + }; + + fssrv::InitializeForFileSystemProxy(config); /* TODO FS-REIMPL: GetFileSystemProxyServiceObject(), set current process, initialize global service object. */ @@ -241,7 +255,21 @@ namespace ams::fssystem { }; /* Initialize fssrv. TODO FS-REIMPL: More arguments, more actions taken. */ - fssrv::InitializeForFileSystemProxy(std::addressof(g_fs_creator_interfaces), GetPointer(g_buffer_manager), is_development_function_enabled); + const fssrv::FileSystemProxyConfiguration config = { + .m_fs_creator_interfaces = std::addressof(g_fs_creator_interfaces), + .m_base_storage_service_impl = nullptr /* TODO */, + .m_base_file_system_service_impl = nullptr /* TODO */, + .m_nca_file_system_service_impl = nullptr /* TODO */, + .m_save_data_file_system_service_impl = nullptr /* TODO */, + .m_access_failure_management_service_impl = nullptr /* TODO */, + .m_time_service_impl = nullptr /* TODO */, + .m_status_report_service_impl = nullptr /* TODO */, + .m_program_registry_service_impl = nullptr /* TODO */, + .m_access_log_service_impl = nullptr /* TODO */, + .m_debug_configuration_service_impl = nullptr /* TODO */, + }; + + fssrv::InitializeForFileSystemProxy(config); /* Disable auto-abort in fs library code. */ fs::SetEnabledAutoAbort(false); diff --git a/libraries/libstratosphere/source/fssystem/fssystem_local_file_system.cpp b/libraries/libstratosphere/source/fssystem/fssystem_local_file_system.cpp new file mode 100644 index 000000000..8571a5fc8 --- /dev/null +++ b/libraries/libstratosphere/source/fssystem/fssystem_local_file_system.cpp @@ -0,0 +1,1751 @@ +/* + * Copyright (c) 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 +#if defined(ATMOSPHERE_OS_WINDOWS) +#include +#include +#elif defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS) +#include +#include +#include +#include +#include +#include +#endif + +#if defined(ATMOSPHERE_OS_LINUX) +#include +#elif defined(ATMOSPHERE_OS_MACOS) +extern "C" ssize_t __getdirentries64(int fd, char *buffer, size_t buffer_size, uintptr_t *basep); +#endif + +#if !defined(ATMOSPHERE_OS_HORIZON) +namespace ams::fssystem { + + namespace { + + constexpr s64 NanoSecondsPerWindowsTick = 100; + constexpr s64 WindowsTicksPerSecond = TimeSpan::FromSeconds(1).GetNanoSeconds() / TimeSpan::FromNanoSeconds(NanoSecondsPerWindowsTick).GetNanoSeconds(); + constexpr s64 OffsetToConvertToPosixTime = 11644473600; + + [[maybe_unused]] constexpr ALWAYS_INLINE s64 ConvertWindowsTimeToPosixTime(s64 windows_ticks) { + return (windows_ticks / WindowsTicksPerSecond) - OffsetToConvertToPosixTime; + } + + [[maybe_unused]] constexpr ALWAYS_INLINE s64 ConvertPosixTimeToWindowsTime(s64 posix_sec, s64 posix_ns = 0) { + return ((posix_sec + OffsetToConvertToPosixTime) * WindowsTicksPerSecond) + util::DivideUp(posix_ns, NanoSecondsPerWindowsTick); + } + + #if defined(ATMOSPHERE_OS_WINDOWS) + constexpr int MaxFilePathLength = MAX_PATH - 1; + constexpr int MaxDirectoryPathLength = MaxFilePathLength - (8 + 1 + 3); + static_assert(MaxFilePathLength == 259); + static_assert(MaxDirectoryPathLength == 247); + + bool AreLongPathsEnabledImpl() { + /* Get handle to ntdll. */ + const HMODULE module = ::GetModuleHandleW(L"ntdll"); + if (module == nullptr) { + return true; + } + + /* Get function pointer to long paths enabled. */ + const auto enabled_funcptr = ::GetProcAddress(module, "RtlAreLongPathsEnabled"); + if (enabled_funcptr == nullptr) { + return true; + } + + /* Get whether long paths are enabled. */ + using FunctionType = BOOLEAN (NTAPI *)(); + return reinterpret_cast(reinterpret_cast(enabled_funcptr))(); + } + + Result ConvertLastErrorToResult() { + switch (::GetLastError()) { + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + case ERROR_NO_MORE_FILES: + case ERROR_BAD_NETPATH: + case ERROR_BAD_NET_NAME: + case ERROR_DIRECTORY: + case ERROR_BAD_DEVICE: + case ERROR_CONNECTION_UNAVAIL: + case ERROR_NO_NET_OR_BAD_PATH: + case ERROR_NOT_CONNECTED: + R_THROW(fs::ResultPathNotFound()); + case ERROR_ACCESS_DENIED: + case ERROR_SHARING_VIOLATION: + R_THROW(fs::ResultTargetLocked()); + case ERROR_HANDLE_EOF: + R_THROW(fs::ResultOutOfRange()); + case ERROR_FILE_EXISTS: + case ERROR_ALREADY_EXISTS: + R_THROW(fs::ResultPathAlreadyExists()); + case ERROR_DISK_FULL: + case ERROR_SPACES_NOT_ENOUGH_DRIVES: + R_THROW(fs::ResultNotEnoughFreeSpace()); + case ERROR_DIR_NOT_EMPTY: + R_THROW(fs::ResultDirectoryNotEmpty()); + case ERROR_BAD_PATHNAME: + R_THROW(fs::ResultInvalidPathFormat()); + case ERROR_FILENAME_EXCED_RANGE: + R_THROW(fs::ResultTooLongPath()); + default: + //printf("Returning ConvertLastErrorToResult() -> ResultUnexpectedInLocalFileSystemE, last_error=0x%08x\n", static_cast(::GetLastError())); + R_THROW(fs::ResultUnexpectedInLocalFileSystemE()); + } + } + + Result WaitDeletionCompletion(const wchar_t *native_path) { + /* Wait for the path to be deleted. */ + constexpr int MaxTryCount = 25; + for (int i = 0; i < MaxTryCount; ++i) { + /* Get the file attributes. */ + const auto attr = ::GetFileAttributesW(native_path); + + /* If they're not invalid, we're done. */ + R_SUCCEED_IF(attr != INVALID_FILE_ATTRIBUTES); + + /* Get last error. */ + const auto err = ::GetLastError(); + + /* If error was file not found, the delete is complete. */ + R_SUCCEED_IF(err == ERROR_FILE_NOT_FOUND); + + /* If the error was access denied, we want to try again. */ + R_UNLESS(err == ERROR_ACCESS_DENIED, ConvertLastErrorToResult()); + } + + /* We received access denied 25 times in a row. */ + R_THROW(fs::ResultTargetLocked()); + } + + Result GetEntryTypeImpl(fs::DirectoryEntryType *out, const wchar_t *native_path) { + const auto res = ::GetFileAttributesW(native_path); + if (res == INVALID_FILE_ATTRIBUTES) { + switch (::GetLastError()) { + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + case ERROR_ACCESS_DENIED: + case ERROR_BAD_NETPATH: + case ERROR_BAD_NET_NAME: + case ERROR_BAD_DEVICE: + case ERROR_CONNECTION_UNAVAIL: + case ERROR_NO_NET_OR_BAD_PATH: + case ERROR_NOT_CONNECTED: + R_THROW(fs::ResultPathNotFound()); + default: + //printf("Returning GetEntryTypeImpl() -> ResultUnexpectedInLocalFileSystemF, last_error=0x%08x\n", static_cast(::GetLastError())); + R_THROW(fs::ResultUnexpectedInLocalFileSystemF()); + } + } + + *out = (res & FILE_ATTRIBUTE_DIRECTORY) ? fs::DirectoryEntryType_Directory : fs::DirectoryEntryType_File; + R_SUCCEED(); + } + + Result SetFileSizeImpl(HANDLE handle, s64 size) { + /* Seek to the desired size. */ + LONG high = size >> BITSIZEOF(LONG); + ::SetFilePointer(handle, static_cast(size), std::addressof(high), FILE_BEGIN); + + /* Set the file size. */ + R_UNLESS(::SetEndOfFile(handle), ConvertLastErrorToResult()); + + R_SUCCEED(); + } + + class LocalFile : public ::ams::fs::fsa::IFile, public ::ams::fs::impl::Newable { + private: + const HANDLE m_handle; + const fs::OpenMode m_open_mode; + public: + LocalFile(HANDLE h, fs::OpenMode m) : m_handle(h), m_open_mode(m) { /* ... */ } + + virtual ~LocalFile() { + ::CloseHandle(m_handle); + } + public: + virtual Result DoRead(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) override { + /* Check that read is possible. */ + size_t dry_read_size; + R_TRY(this->DryRead(std::addressof(dry_read_size), offset, size, option, m_open_mode)); + + /* If we have nothing to read, we don't need to do anything. */ + if (dry_read_size == 0) { + *out = 0; + R_SUCCEED(); + } + + /* Prepare to do asynchronous IO. */ + OVERLAPPED overlapped = {}; + overlapped.Offset = static_cast(offset); + overlapped.OffsetHigh = static_cast(offset >> BITSIZEOF(DWORD)); + overlapped.hEvent = ::CreateEvent(nullptr, true, false, nullptr); + R_UNLESS(overlapped.hEvent != nullptr, fs::ResultUnexpectedInLocalFileSystemA()); + ON_SCOPE_EXIT { ::CloseHandle(overlapped.hEvent); }; + + /* Read from the file. */ + DWORD size_read; + if (!::ReadFile(m_handle, buffer, static_cast(size), std::addressof(size_read), std::addressof(overlapped))) { + /* If we fail for reason other than io pending, return the error result. */ + const auto err = ::GetLastError(); + R_UNLESS(err == ERROR_IO_PENDING, ConvertLastErrorToResult()); + + /* Get the wait result. */ + if (!::GetOverlappedResult(m_handle, std::addressof(overlapped), std::addressof(size_read), true)) { + /* We failed...check if it's because we're at the end of the file. */ + R_UNLESS(::GetLastError() == ERROR_HANDLE_EOF, ConvertLastErrorToResult()); + + /* Get the file size. */ + LARGE_INTEGER file_size; + R_UNLESS(::GetFileSizeEx(m_handle, std::addressof(file_size)), ConvertLastErrorToResult()); + + /* Check the filesize matches offset. */ + R_UNLESS(file_size.QuadPart == offset, ConvertLastErrorToResult()); + } + } + + /* Set the output read size. */ + *out = size_read; + R_SUCCEED(); + } + + virtual Result DoGetSize(s64 *out) override { + /* Get the file size. */ + LARGE_INTEGER size; + R_UNLESS(::GetFileSizeEx(m_handle, std::addressof(size)), fs::ResultUnexpectedInLocalFileSystemD()); + + /* Set the output. */ + *out = size.QuadPart; + R_SUCCEED(); + } + + virtual Result DoFlush() override { + /* If we're not writable, we have nothing to flush. */ + R_SUCCEED_IF((m_open_mode & fs::OpenMode_Write) == 0); + + /* Flush our buffer. */ + R_UNLESS(::FlushFileBuffers(m_handle), fs::ResultUnexpectedInLocalFileSystemC()); + R_SUCCEED(); + } + + virtual Result DoWrite(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) override { + /* Verify that we can write. */ + bool needs_append; + R_TRY(this->DryWrite(std::addressof(needs_append), offset, size, option, m_open_mode)); + + /* If we need to, perform the write. */ + if (size != 0) { + /* Prepare to do asynchronous IO. */ + OVERLAPPED overlapped = {}; + overlapped.Offset = static_cast(offset); + overlapped.OffsetHigh = static_cast(offset >> BITSIZEOF(DWORD)); + overlapped.hEvent = ::CreateEvent(nullptr, true, false, nullptr); + R_UNLESS(overlapped.hEvent != nullptr, fs::ResultUnexpectedInLocalFileSystemA()); + ON_SCOPE_EXIT { ::CloseHandle(overlapped.hEvent); }; + + /* Write to the file. */ + DWORD size_written; + if (!::WriteFile(m_handle, buffer, static_cast(size), std::addressof(size_written), std::addressof(overlapped))) { + /* If we fail for reason other than io pending, return the error result. */ + const auto err = ::GetLastError(); + R_UNLESS(err == ERROR_IO_PENDING, ConvertLastErrorToResult()); + + /* Get the wait result. */ + R_UNLESS(::GetOverlappedResult(m_handle, std::addressof(overlapped), std::addressof(size_written), true), ConvertLastErrorToResult()); + } + + /* Check that a correct amount of data was written. */ + R_UNLESS(size_written >= size, fs::ResultNotEnoughFreeSpace()); + + /* Sanity check that we wrote the right amount. */ + AMS_ASSERT(size_written == size); + } + + /* If we need to, flush. */ + if (option.HasFlushFlag()) { + R_TRY(this->Flush()); + } + + R_SUCCEED(); + } + + virtual Result DoSetSize(s64 size) override { + /* Verify we can set the size. */ + R_TRY(this->DrySetSize(size, m_open_mode)); + + /* Try to set the file size. */ + R_RETURN(SetFileSizeImpl(m_handle, size)); + } + + virtual Result DoOperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override { + AMS_UNUSED(offset, size, src, src_size); + switch (op_id) { + case fs::OperationId::Invalidate: + R_SUCCEED(); + case fs::OperationId::QueryRange: + R_UNLESS(dst != nullptr, fs::ResultNullptrArgument()); + R_UNLESS(dst_size == sizeof(fs::QueryRangeInfo), fs::ResultInvalidSize()); + static_cast(dst)->Clear(); + R_SUCCEED(); + default: + R_THROW(fs::ResultUnsupportedOperationInLocalFileA()); + } + } + public: + virtual sf::cmif::DomainObjectId GetDomainObjectId() const override { + AMS_ABORT("GetDomainObjectId() should never be called on a LocalFile"); + } + }; + + class LocalDirectory : public ::ams::fs::fsa::IDirectory, public ::ams::fs::impl::Newable { + private: + std::unique_ptr m_path; + HANDLE m_dir_handle; + HANDLE m_search_handle; + fs::OpenDirectoryMode m_open_mode; + public: + LocalDirectory(HANDLE d, HANDLE s, fs::OpenDirectoryMode m, std::unique_ptr &&p) : m_path(std::move(p)), m_dir_handle(d), m_search_handle(s) { + m_open_mode = static_cast(util::ToUnderlying(m) & ~util::ToUnderlying(fs::OpenDirectoryMode_NotRequireFileSize)); + } + + virtual ~LocalDirectory() { + ::FindClose(m_search_handle); + ::CloseHandle(m_dir_handle); + } + public: + virtual Result DoRead(s64 *out_count, fs::DirectoryEntry *out_entries, s64 max_entries) override { + auto read_count = 0; + while (read_count < max_entries) { + /* Read the next file. */ + WIN32_FIND_DATAW fd; + std::memset(fd.cFileName, 0, sizeof(fd.cFileName)); + if (!::FindNextFileW(m_search_handle, std::addressof(fd))) { + /* Check that we failed because we ran out of files. */ + R_UNLESS(::GetLastError() == ERROR_NO_MORE_FILES, ConvertLastErrorToResult()); + break; + } + + /* If we shouldn't create an entry, continue. */ + if (!this->IsReadTarget(fd)) { + continue; + } + + /* Create the entry. */ + auto &entry = out_entries[read_count++]; + + std::memset(entry.name, 0, sizeof(entry.name)); + const auto wide_res = ::WideCharToMultiByte(CP_UTF8, 0, fd.cFileName, -1, entry.name, sizeof(entry.name), nullptr, nullptr); + R_UNLESS(wide_res != 0, fs::ResultInvalidPath()); + + entry.type = (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? fs::DirectoryEntryType_Directory : fs::DirectoryEntryType_File; + + entry.file_size = static_cast(fd.nFileSizeLow) | static_cast(static_cast(fd.nFileSizeHigh) << BITSIZEOF(fd.nFileSizeLow)); + } + + /* Set the output read count. */ + *out_count = read_count; + R_SUCCEED(); + } + + virtual Result DoGetEntryCount(s64 *out) override { + /* Open a new search handle. */ + WIN32_FIND_DATAW fd; + auto handle = ::FindFirstFileW(m_path.get(), std::addressof(fd)); + R_UNLESS(handle != INVALID_HANDLE_VALUE, ConvertLastErrorToResult()); + ON_SCOPE_EXIT { ::FindClose(handle); }; + + /* Iterate to get the total entry count. */ + auto entry_count = 0; + while (::FindNextFileW(handle, std::addressof(fd))) { + if (this->IsReadTarget(fd)) { + ++entry_count; + } + } + + /* Check that we stopped iterating because we ran out of files. */ + R_UNLESS(::GetLastError() == ERROR_NO_MORE_FILES, ConvertLastErrorToResult()); + + /* Set the output. */ + *out = entry_count; + R_SUCCEED(); + } + private: + bool IsReadTarget(const WIN32_FIND_DATAW &fd) const { + /* If the file is "..", don't return it. */ + if (::wcsncmp(fd.cFileName, L"..", 3) == 0 || ::wcsncmp(fd.cFileName, L".", 2) == 0) { + return false; + } + + /* Return whether our open mode supports the target. */ + if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + return m_open_mode != fs::OpenDirectoryMode_File; + } else { + return m_open_mode != fs::OpenDirectoryMode_Directory; + } + } + public: + virtual sf::cmif::DomainObjectId GetDomainObjectId() const override { + AMS_ABORT("GetDomainObjectId() should never be called on a LocalDirectory"); + } + }; + + #else + constexpr int MaxFilePathLength = PATH_MAX - 1; + constexpr int MaxDirectoryPathLength = PATH_MAX - 1; + + #if defined (ATMOSPHERE_OS_LINUX) + struct linux_dirent64 { + ino64_t d_ino; + off64_t d_off; + unsigned short d_reclen; + unsigned char d_type; + char d_name[]; + }; + + using NativeDirectoryEntryType = struct linux_dirent64; + #else + using NativeDirectoryEntryType = struct dirent; + #endif + + bool AreLongPathsEnabledImpl() { + /* TODO: How does this work on linux/macos? */ + return true; + } + + enum ErrnoSource { + ErrnoSource_OpenFile, // 0 + ErrnoSource_CreateFile, // 1 + ErrnoSource_Unlink, // 2 + ErrnoSource_Pread, // 3 + ErrnoSource_Pwrite, // 4 + ErrnoSource_Ftruncate, // 5 + // + ErrnoSource_OpenDirectory, // 6 + ErrnoSource_Mkdir, // 7 + ErrnoSource_Rmdir, // 8 + ErrnoSource_GetDents, // 9 + // + ErrnoSource_RenameDirectory, // 10 + ErrnoSource_RenameFile, // 11 + // + ErrnoSource_Stat, // 12 + ErrnoSource_Statvfs, // 13 + }; + + Result ConvertErrnoToResult(ErrnoSource source) { + switch (errno) { + case ENOENT: + R_THROW(fs::ResultPathNotFound()); + case EEXIST: + switch (source) { + case ErrnoSource_Rmdir: + R_THROW(fs::ResultDirectoryNotEmpty()); + default: + R_THROW(fs::ResultPathAlreadyExists()); + } + case ENOTDIR: + switch (source) { + case ErrnoSource_Rmdir: + R_THROW(fs::ResultPathNotFound()); + default: + R_THROW(fs::ResultPathNotFound()); + } + case EISDIR: + switch (source) { + case ErrnoSource_CreateFile: + R_THROW(fs::ResultPathAlreadyExists()); + case ErrnoSource_OpenFile: + case ErrnoSource_Unlink: + R_THROW(fs::ResultPathNotFound()); + default: + R_THROW(fs::ResultUnexpectedInLocalFileSystemE()); + } + case ENOTEMPTY: + R_THROW(fs::ResultDirectoryNotEmpty()); + case EACCES: + case EINTR: + R_THROW(fs::ResultTargetLocked()); + default: + //printf("Returning default errno -> result, errno=%d, source=%d\n", errno, static_cast(source)); + R_THROW(fs::ResultUnexpectedInLocalFileSystemE()); + } + } + + Result WaitDeletionCompletion(const char *native_path) { + /* TODO: Does linux need to wait for delete to complete? */ + AMS_UNUSED(native_path); + R_SUCCEED(); + } + + + Result GetEntryTypeImpl(fs::DirectoryEntryType *out, const char *native_path) { + struct stat st; + R_UNLESS(::stat(native_path, std::addressof(st)) == 0, ConvertErrnoToResult(ErrnoSource_Stat)); + + *out = (S_ISDIR(st.st_mode)) ? fs::DirectoryEntryType_Directory : fs::DirectoryEntryType_File; + R_SUCCEED(); + } + + auto RetryForEIntr(auto f) { + decltype(f()) res; + do { + res = f(); + } while (res < 0 && errno == EINTR); + return res; + }; + + void CloseFileDescriptor(int handle) { + const int res = RetryForEIntr([&] () ALWAYS_INLINE_LAMBDA { + return ::close(handle); + }); + AMS_ASSERT(res == 0); + AMS_UNUSED(res); + } + + Result SetFileSizeImpl(int handle, s64 size) { + const auto res = RetryForEIntr([&] () ALWAYS_INLINE_LAMBDA { return ::ftruncate(handle, size); }); + R_UNLESS(res == 0, ConvertErrnoToResult(ErrnoSource_Ftruncate)); + R_SUCCEED(); + } + + class LocalFile : public ::ams::fs::fsa::IFile, public ::ams::fs::impl::Newable { + private: + const int m_handle; + const fs::OpenMode m_open_mode; + public: + LocalFile(int h, fs::OpenMode m) : m_handle(h), m_open_mode(m) { /* ... */ } + + virtual ~LocalFile() { + CloseFileDescriptor(m_handle); + } + public: + virtual Result DoRead(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) override { + /* Check that read is possible. */ + size_t dry_read_size; + R_TRY(this->DryRead(std::addressof(dry_read_size), offset, size, option, m_open_mode)); + + /* If we have nothing to read, we don't need to do anything. */ + if (dry_read_size == 0) { + *out = 0; + R_SUCCEED(); + } + + /* Read. */ + const auto read_size = RetryForEIntr([&] () ALWAYS_INLINE_LAMBDA -> ssize_t { return ::pread(m_handle, buffer, size, offset); }); + R_UNLESS(read_size >= 0, ConvertErrnoToResult(ErrnoSource_Pread)); + + /* Set output. */ + *out = static_cast(read_size); + R_SUCCEED(); + } + + virtual Result DoGetSize(s64 *out) override { + /* Get the file size. */ + const auto size = RetryForEIntr([&] () ALWAYS_INLINE_LAMBDA -> s64 { return ::lseek(m_handle, 0, SEEK_END); }); + R_UNLESS(size >= 0, fs::ResultUnexpectedInLocalFileSystemD()); + + /* Set the output. */ + *out = size; + R_SUCCEED(); + } + + virtual Result DoFlush() override { + /* If we're not writable, we have nothing to flush. */ + R_SUCCEED_IF((m_open_mode & fs::OpenMode_Write) == 0); + + /* Flush our buffer. */ + const auto res = RetryForEIntr([&] () ALWAYS_INLINE_LAMBDA { return ::fsync(m_handle); }); + R_UNLESS(res == 0, fs::ResultUnexpectedInLocalFileSystemC()); + R_SUCCEED(); + } + + virtual Result DoWrite(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) override { + /* Verify that we can write. */ + bool needs_append; + R_TRY(this->DryWrite(std::addressof(needs_append), offset, size, option, m_open_mode)); + + /* If we need to, perform the write. */ + if (size != 0) { + /* Read. */ + const auto size_written = RetryForEIntr([&] () ALWAYS_INLINE_LAMBDA -> ssize_t { return ::pwrite(m_handle, buffer, size, offset); }); + R_UNLESS(size_written >= 0, ConvertErrnoToResult(ErrnoSource_Pwrite)); + + /* Check that a correct amount of data was written. */ + R_UNLESS(static_cast(size_written) >= size, fs::ResultNotEnoughFreeSpace()); + + /* Sanity check that we wrote the right amount. */ + AMS_ASSERT(static_cast(size_written) == size); + } + + /* If we need to, flush. */ + if (option.HasFlushFlag()) { + R_TRY(this->Flush()); + } + + R_SUCCEED(); + } + + virtual Result DoSetSize(s64 size) override { + /* Verify we can set the size. */ + R_TRY(this->DrySetSize(size, m_open_mode)); + + /* Try to set the file size. */ + R_RETURN(SetFileSizeImpl(m_handle, size)); + } + + virtual Result DoOperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override { + AMS_UNUSED(offset, size, src, src_size); + switch (op_id) { + case fs::OperationId::Invalidate: + R_SUCCEED(); + case fs::OperationId::QueryRange: + R_UNLESS(dst != nullptr, fs::ResultNullptrArgument()); + R_UNLESS(dst_size == sizeof(fs::QueryRangeInfo), fs::ResultInvalidSize()); + static_cast(dst)->Clear(); + R_SUCCEED(); + default: + R_THROW(fs::ResultUnsupportedOperationInLocalFileA()); + } + } + public: + virtual sf::cmif::DomainObjectId GetDomainObjectId() const override { + AMS_ABORT("GetDomainObjectId() should never be called on a LocalFile"); + } + }; + + class LocalDirectory : public ::ams::fs::fsa::IDirectory, public ::ams::fs::impl::Newable { + private: + std::unique_ptr m_path; + int m_dir_handle; + fs::OpenDirectoryMode m_open_mode; + bool m_not_require_file_size; + + std::unique_ptr m_temp_entries; + int m_temp_entries_count; + int m_temp_entries_ofs; + + #if defined(ATMOSPHERE_OS_MACOS) + uintptr_t m_basep = 0; + #endif + public: + LocalDirectory(int d, int s, fs::OpenDirectoryMode m, std::unique_ptr &&p) : m_path(std::move(p)), m_dir_handle(d), m_temp_entries(nullptr), m_temp_entries_count(0), m_temp_entries_ofs(0) { + m_open_mode = static_cast(util::ToUnderlying(m) & ~util::ToUnderlying(fs::OpenDirectoryMode_NotRequireFileSize)); + m_not_require_file_size = m & fs::OpenDirectoryMode_NotRequireFileSize; + AMS_ASSERT(s < 0); + AMS_UNUSED(s); + } + + virtual ~LocalDirectory() { + CloseFileDescriptor(m_dir_handle); + } + public: + virtual Result DoRead(s64 *out_count, fs::DirectoryEntry *out_entries, s64 max_entries) override { + auto read_count = 0; + + /* Copy out any pending entries from a previous call. */ + while (m_temp_entries_ofs < m_temp_entries_count && read_count < max_entries) { + out_entries[read_count++] = m_temp_entries[m_temp_entries_ofs++]; + } + + /* If we're done with our temporary entries, release them. */ + if (m_temp_entries_ofs == m_temp_entries_count) { + m_temp_entries.reset(); + m_temp_entries_ofs = 0; + m_temp_entries_count = 0; + } + + if (read_count < max_entries) { + /* Declare buffer to hold temporary path. */ + char path_buf[PATH_MAX]; + auto base_path_len = std::strlen(m_path.get()); + std::memcpy(path_buf, m_path.get(), base_path_len); + if (path_buf[base_path_len - 1] != '/') { + path_buf[base_path_len++] = '/'; + } + + #if defined(ATMOSPHERE_OS_LINUX) + char buf[1_KB]; + #else + char buf[2_KB]; + #endif + NativeDirectoryEntryType *ent = nullptr; + while (read_count < max_entries) { + /* Read next entries. */ + #if defined (ATMOSPHERE_OS_LINUX) + const auto nread = ::syscall(SYS_getdents64, m_dir_handle, buf, sizeof(buf)); + #elif defined(ATMOSPHERE_OS_MACOS) + const auto nread = ::__getdirentries64(m_dir_handle, buf, sizeof(buf), std::addressof(m_basep)); + #else + #error "Unknown OS to read from directory FD" + #endif + R_UNLESS(nread >= 0, ConvertErrnoToResult(ErrnoSource_GetDents)); + + /* If we read nothing, we've hit the end of the directory. */ + if (nread == 0) { + break; + } + + /* Determine the number of entries we read. */ + auto cur_read_entries = 0; + for (auto pos = 0; pos < nread; pos += ent->d_reclen) { + /* Get the native entry. */ + ent = reinterpret_cast(buf + pos); + + /* If the entry isn't a read target, ignore it. */ + if (IsReadTarget(ent)) { + ++cur_read_entries; + } + } + + /* If we'll end up reading more than we can fit, allocate a temporary buffer. */ + if (read_count + cur_read_entries > max_entries) { + /* Allocate temporary entries. */ + m_temp_entries_count = (read_count + cur_read_entries) - max_entries; + m_temp_entries_ofs = 0; + + /* TODO: Non-fatal? */ + m_temp_entries = fs::impl::MakeUnique(m_temp_entries_count); + AMS_ABORT_UNLESS(m_temp_entries != nullptr); + } + + /* Iterate received entries. */ + for (auto pos = 0; pos < nread; pos += ent->d_reclen) { + /* Get the native entry. */ + ent = reinterpret_cast(buf + pos); + + /* If the entry isn't a read target, ignore it. */ + if (!IsReadTarget(ent)) { + continue; + } + + /* Decide on the output entry. */ + fs::DirectoryEntry *out_entry; + if (read_count < max_entries) { + out_entry = std::addressof(out_entries[read_count++]); + } else { + out_entry = std::addressof(m_temp_entries[m_temp_entries_ofs++]); + } + + /* Setup the output entry. */ + { + std::memset(out_entry->name, 0, sizeof(out_entry->name)); + + const auto name_len = std::strlen(ent->d_name); + std::memcpy(out_entry->name, ent->d_name, name_len + 1); + + out_entry->type = (ent->d_type == DT_DIR) ? fs::DirectoryEntryType_Directory : fs::DirectoryEntryType_File; + + /* If we have to, get the filesize. This is (unfortunately) expensive on linux. */ + if (out_entry->type == fs::DirectoryEntryType_File && !m_not_require_file_size) { + /* Set up the temporary file path. */ + std::memcpy(path_buf + base_path_len, ent->d_name, name_len + 1); + + /* Get the file stats. */ + struct stat st; + R_UNLESS(::stat(path_buf, std::addressof(st)) == 0, ConvertErrnoToResult(ErrnoSource_Stat)); + + out_entry->file_size = static_cast(st.st_size); + } + } + } + + /* Ensure our temporary entries are correct. */ + if (m_temp_entries != nullptr) { + AMS_ASSERT(read_count == max_entries); + AMS_ASSERT(m_temp_entries_ofs == m_temp_entries_count); + m_temp_entries_ofs = 0; + } + } + } + + /* Set the output read count. */ + *out_count = read_count; + R_SUCCEED(); + } + + virtual Result DoGetEntryCount(s64 *out) override { + /* Open the directory anew. */ + const auto handle = RetryForEIntr([&] () ALWAYS_INLINE_LAMBDA { return ::open(m_path.get(), O_RDONLY | O_DIRECTORY); }); + R_UNLESS(handle >= 0, ConvertErrnoToResult(ErrnoSource_OpenDirectory)); + ON_SCOPE_EXIT { CloseFileDescriptor(handle); }; + + /* Iterate to get the total entry count. */ + auto entry_count = 0; + { + #if defined(ATMOSPHERE_OS_LINUX) + char buf[1_KB]; + #else + char buf[2_KB]; + uintptr_t basep = 0; + #endif + + NativeDirectoryEntryType *ent = nullptr; + while (true) { + /* Read next entries. */ + #if defined (ATMOSPHERE_OS_LINUX) + const auto nread = ::syscall(SYS_getdents64, handle, buf, sizeof(buf)); + #elif defined(ATMOSPHERE_OS_MACOS) + const auto nread = ::__getdirentries64(handle, buf, sizeof(buf), std::addressof(basep)); + #else + #error "Unknown OS to read from directory FD" + #endif + + R_UNLESS(nread >= 0, ConvertErrnoToResult(ErrnoSource_GetDents)); + + /* If we read nothing, we've hit the end of the directory. */ + if (nread == 0) { + break; + } + + /* Iterate received entries. */ + for (auto pos = 0; pos < nread; pos += ent->d_reclen) { + /* Get the entry. */ + ent = reinterpret_cast(buf + pos); + + /* If the entry is a read target, increment our count. */ + if (IsReadTarget(ent)) { + ++entry_count; + } + } + } + } + + *out = entry_count; + R_SUCCEED(); + } + private: + bool IsReadTarget(const NativeDirectoryEntryType *ent) const { + /* If the file is "..", don't return it. */ + if (std::strcmp(ent->d_name, ".") == 0 || std::strcmp(ent->d_name, "..") == 0) { + return false; + } + + /* Return whether our open mode supports the target. */ + if (ent->d_type == DT_DIR) { + return m_open_mode != fs::OpenDirectoryMode_File; + } else { + return m_open_mode != fs::OpenDirectoryMode_Directory; + } + } + public: + virtual sf::cmif::DomainObjectId GetDomainObjectId() const override { + AMS_ABORT("GetDomainObjectId() should never be called on a LocalDirectory"); + } + }; + + #endif + + bool AreLongPathsEnabled() { + AMS_FUNCTION_LOCAL_STATIC(bool, s_enabled, AreLongPathsEnabledImpl()); + return s_enabled; + } + + } + + Result LocalFileSystem::Initialize(const fs::Path &root_path, fssystem::PathCaseSensitiveMode case_sensitive_mode) { + /* Initialize our root path. */ + R_TRY(m_root_path.Initialize(root_path)); + + /* If we're not empty, we'll need to convert to a native path. */ + if (m_root_path.IsEmpty()) { + /* Reset our native path, since we're acting without a root. */ + m_native_path_buffer.reset(nullptr); + m_native_path_length = 0; + } else { + /* Convert to native path. */ + NativePathBuffer native_path = nullptr; + int native_len = 0; + #if defined(ATMOSPHERE_OS_WINDOWS) + { + /* Get path length. */ + native_len = ::MultiByteToWideChar(CP_UTF8, 0, m_root_path.GetString(), -1, nullptr, 0); + + /* Allocate our native path buffer. */ + native_path = fs::impl::MakeUnique(native_len + 1); + R_UNLESS(native_path != nullptr, fs::ResultAllocationFailureInMakeUnique()); + + /* Convert path. */ + const auto res = ::MultiByteToWideChar(CP_UTF8, 0, m_root_path.GetString(), -1, native_path.get(), native_len); + R_UNLESS(res != 0, fs::ResultTooLongPath()); + R_UNLESS(res <= static_cast(fs::EntryNameLengthMax + 1), fs::ResultTooLongPath()); + + /* Fix up directory separators. */ + for (NativeCharacterType *p = native_path.get(); *p != 0; ++p) { + if (*p == '/') { + *p = '\\'; + } + } + } + #else + { + /* Get path size. */ + native_len = std::strlen(m_root_path.GetString()); + + /* Tentatively assume other operating systems do the sane thing and use utf-8 strings. */ + native_path = fs::impl::MakeUnique(native_len + 1); + R_UNLESS(native_path != nullptr, fs::ResultAllocationFailureInMakeUnique()); + + /* Copy in path. */ + std::memcpy(native_path.get(), m_root_path.GetString(), native_len + 1); + } + #endif + + /* Temporarily set case sensitive mode to insensitive, and verify we can get the root directory. */ + m_case_sensitive_mode = fssystem::PathCaseSensitiveMode_CaseInsensitive; + { + constexpr fs::Path RequiredRootPath = fs::MakeConstantPath("/"); + + fs::DirectoryEntryType type; + R_TRY(this->GetEntryType(std::addressof(type), RequiredRootPath)); + + R_UNLESS(type == fs::DirectoryEntryType_Directory, fs::ResultPathNotFound()); + } + + /* Set our native path members. */ + m_native_path_buffer = std::move(native_path); + m_native_path_length = native_len; + } + + /* Set our case sensitive mode. */ + m_case_sensitive_mode = case_sensitive_mode; + R_SUCCEED(); + } + + Result LocalFileSystem::GetCaseSensitivePath(int *out_size, char *dst, size_t dst_size, const char *path, const char *work_path) { + AMS_UNUSED(out_size, dst, dst_size, path, work_path); + AMS_ABORT("TODO"); + } + + Result LocalFileSystem::CheckPathCaseSensitively(const NativeCharacterType *path, const NativeCharacterType *root_path, NativeCharacterType *cs_buf, size_t cs_size, bool check_case_sensitivity) { + AMS_UNUSED(path, root_path, cs_buf, cs_size, check_case_sensitivity); + AMS_ABORT("TODO"); + } + + Result LocalFileSystem::ResolveFullPath(NativePathBuffer *out, const fs::Path &path, int max_len, int min_len, bool check_case_sensitivity) { + /* Create the full path. */ + fs::Path full_path; + R_TRY(full_path.Combine(m_root_path, path)); + + /* Check that the path is valid. */ + fs::PathFlags flags; + flags.AllowWindowsPath(); + flags.AllowRelativePath(); + flags.AllowEmptyPath(); + R_TRY(fs::PathFormatter::CheckPathFormat(full_path.GetString(), flags)); + + /* Check the path's character count. */ + #if defined(ATMOSPHERE_OS_WINDOWS) + AreLongPathsEnabled(); + // TODO: R_TRY(fs::CheckCharacterCountForWindows(full_path.GetString(), MaxBasePathLength, AreLongPathsEnabled() ? 0 : max_len)); + AMS_UNUSED(max_len); + #else + AreLongPathsEnabled(); + /* TODO: Check character count for linux/macos? */ + AMS_UNUSED(max_len); + #endif + + + /* Convert to native path. */ + NativePathBuffer native_path = nullptr; + #if defined(ATMOSPHERE_OS_WINDOWS) + { + /* Get path length. */ + const int native_len = ::MultiByteToWideChar(CP_UTF8, 0, full_path.GetString(), -1, nullptr, 0); + + /* Allocate our native path buffer. */ + native_path = fs::impl::MakeUnique(native_len + min_len + 1); + R_UNLESS(native_path != nullptr, fs::ResultAllocationFailureInMakeUnique()); + + /* Convert path. */ + const auto res = ::MultiByteToWideChar(CP_UTF8, 0, full_path.GetString(), -1, native_path.get(), native_len); + R_UNLESS(res != 0, fs::ResultTooLongPath()); + R_UNLESS(res <= native_len, fs::ResultTooLongPath()); + + /* Fix up directory separators. */ + s32 len = 0; + for (NativeCharacterType *p = native_path.get(); *p != 0; ++p) { + if (*p == '/') { + *p = '\\'; + } + ++len; + } + + /* Fix up trailing : */ + if (native_path[len - 1] == ':') { + native_path[len] = '\\'; + native_path[len + 1] = 0; + } + + /* If case sensitivity is required, allocate case sensitive buffer. */ + if (m_case_sensitive_mode == PathCaseSensitiveMode_CaseSensitive && native_path[0] != 0) { + /* Allocate case sensitive buffer. */ + auto case_sensitive_buffer_size = sizeof(NativeCharacterType) * (m_native_path_length + native_len + 1 + fs::EntryNameLengthMax); + NativePathBuffer case_sensitive_path_buffer = fs::impl::MakeUnique(case_sensitive_buffer_size / sizeof(NativeCharacterType)); + R_UNLESS(case_sensitive_path_buffer != nullptr, fs::ResultAllocationFailureInMakeUnique()); + + /* Get root path. */ + const NativeCharacterType *root_path = m_native_path_buffer.get() != nullptr ? m_native_path_buffer.get() : L""; + + /* Perform case sensitive path checking. */ + R_TRY(this->CheckPathCaseSensitively(native_path.get(), root_path, case_sensitive_path_buffer.get(), case_sensitive_buffer_size, check_case_sensitivity)); + } + + /* Set default path, if empty. */ + if (native_path[0] == 0) { + native_path[0] = '.'; + native_path[1] = '\\'; + native_path[2] = 0; + } + } + #else + { + /* Get path size. */ + const int native_len = std::strlen(full_path.GetString()); + + /* Tentatively assume other operating systems do the sane thing and use utf-8 strings. */ + native_path = fs::impl::MakeUnique(native_len + min_len + 1); + R_UNLESS(native_path != nullptr, fs::ResultAllocationFailureInMakeUnique()); + + /* Copy in path. */ + std::memcpy(native_path.get(), full_path.GetString(), native_len + 1); + + /* TODO: Is case sensitivity adjustment needed here? */ + AMS_UNUSED(check_case_sensitivity); + } + #endif + + /* Set the output path. */ + *out = std::move(native_path); + R_SUCCEED(); + } + + Result LocalFileSystem::DoGetDiskFreeSpace(s64 *out_free, s64 *out_total, s64 *out_total_free, const fs::Path &path) { + /* Resolve the path. */ + NativePathBuffer native_path; + R_TRY(this->ResolveFullPath(std::addressof(native_path), path, MaxFilePathLength, 0, false)); + + /* Get the disk free space. */ + #if defined(ATMOSPHERE_OS_WINDOWS) + { + ULARGE_INTEGER free, total, total_free; + R_UNLESS(::GetDiskFreeSpaceExW(native_path.get(), std::addressof(free), std::addressof(total), std::addressof(total_free)), ConvertLastErrorToResult()); + + *out_free = static_cast(free.QuadPart); + *out_total = static_cast(total.QuadPart); + *out_total_free = static_cast(total_free.QuadPart); + } + #else + { + struct statvfs st; + const auto res = RetryForEIntr([&] () ALWAYS_INLINE_LAMBDA { return ::statvfs(native_path.get(), std::addressof(st)); }); + R_UNLESS(res >= 0, ConvertErrnoToResult(ErrnoSource_Statvfs)); + + *out_free = static_cast(st.f_bavail) * static_cast(st.f_frsize); + *out_total = static_cast(st.f_blocks) * static_cast(st.f_frsize); + *out_total_free = static_cast(st.f_bfree) * static_cast(st.f_frsize); + } + #endif + + R_SUCCEED(); + } + + Result LocalFileSystem::DeleteDirectoryRecursivelyInternal(const NativeCharacterType *path, bool delete_top) { + #if defined(ATMOSPHERE_OS_WINDOWS) + { + /* Get the path length. */ + const auto path_len = ::wcslen(path); + + /* Allocate a new path buffer. */ + NativePathBuffer cur_path_buf = fs::impl::MakeUnique(path_len + MAX_PATH); + R_UNLESS(cur_path_buf.get() != nullptr, fs::ResultAllocationFailureInMakeUnique()); + + /* Copy the path into the temporary buffer. */ + ::wcscpy(cur_path_buf.get(), path); + ::wcscat(cur_path_buf.get(), L"\\*"); + + /* Iterate the directory, deleting all contents. */ + { + /* Begin finding. */ + WIN32_FIND_DATAW fd; + const auto handle = ::FindFirstFileW(cur_path_buf.get(), std::addressof(fd)); + R_UNLESS(handle != INVALID_HANDLE_VALUE, ConvertLastErrorToResult()); + ON_SCOPE_EXIT { ::FindClose(handle); }; + + /* Clear the path from \\* to path\\ */ + wchar_t * const dst = cur_path_buf.get() + path_len + 1; + *dst = 0; + + /* Loop files. */ + while (::FindNextFileW(handle, std::addressof(fd))) { + /* Skip . and .. */ + if (::wcsncmp(fd.cFileName, L"..", 3) == 0 || ::wcsncmp(fd.cFileName, L".", 2) == 0) { + continue; + } + + /* Copy the current filename to our working path. */ + ::wcscpy(dst, fd.cFileName); + + if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + /* If a directory, delete it recursively. */ + R_TRY(this->DeleteDirectoryRecursivelyInternal(cur_path_buf.get(), true)); + } else { + /* If a file, just delete it. */ + auto delete_file = [&]() -> Result { + R_UNLESS(::DeleteFileW(cur_path_buf.get()), ConvertLastErrorToResult()); + R_SUCCEED(); + }; + + R_TRY(fssystem::RetryToAvoidTargetLocked(delete_file)); + R_TRY(WaitDeletionCompletion(cur_path_buf.get())); + } + } + + /* Check that we stopped iterating because we ran out of files. */ + R_UNLESS(::GetLastError() == ERROR_NO_MORE_FILES, ConvertLastErrorToResult()); + } + + /* If we should, delete the top level directory. */ + if (delete_top) { + auto delete_impl = [&] () -> Result { + R_UNLESS(::RemoveDirectoryW(path), ConvertLastErrorToResult()); + R_SUCCEED(); + }; + + /* Perform the delete. */ + R_TRY(fssystem::RetryToAvoidTargetLocked(delete_impl)); + + /* Wait for the deletion to complete. */ + R_TRY(WaitDeletionCompletion(path)); + } + } + #else + { + /* Get the path length. */ + const auto path_len = std::strlen(path); + + /* Allocate a temporary buffer. */ + NativePathBuffer cur_path_buf = fs::impl::MakeUnique(path_len + PATH_MAX); + R_UNLESS(cur_path_buf.get() != nullptr, fs::ResultAllocationFailureInMakeUnique()); + + /* Copy the path into the temporary buffer. */ + std::memcpy(cur_path_buf.get(), path, path_len); + auto ofs = path_len; + if (cur_path_buf.get()[ofs - 1] != '/') { + cur_path_buf.get()[ofs++] = '/'; + } + + /* Iterate the directory, deleting all contents. */ + { + /* Open the directory. */ + const auto handle = RetryForEIntr([&] () ALWAYS_INLINE_LAMBDA { return ::open(path, O_RDONLY | O_DIRECTORY); }); + R_UNLESS(handle >= 0, ConvertErrnoToResult(ErrnoSource_OpenDirectory)); + ON_SCOPE_EXIT { CloseFileDescriptor(handle); }; + + #if defined(ATMOSPHERE_OS_LINUX) + char buf[1_KB]; + #else + char buf[2_KB]; + uintptr_t basep = 0; + #endif + + NativeDirectoryEntryType *ent = nullptr; + static_assert(sizeof(*ent) <= sizeof(buf)); + while (true) { + /* Read next entries. */ + #if defined (ATMOSPHERE_OS_LINUX) + const auto nread = ::syscall(SYS_getdents64, handle, buf, sizeof(buf)); + #elif defined(ATMOSPHERE_OS_MACOS) + const auto nread = ::__getdirentries64(handle, buf, sizeof(buf), std::addressof(basep)); + #else + #error "Unknown OS to read from directory FD" + #endif + R_UNLESS(nread >= 0, ConvertErrnoToResult(ErrnoSource_GetDents)); + + /* If we read nothing, we've hit the end of the directory. */ + if (nread == 0) { + break; + } + + /* Iterate received entries. */ + for (auto pos = 0; pos < nread; pos += ent->d_reclen) { + /* Get the entry. */ + ent = reinterpret_cast(buf + pos); + + /* Skip . and .. */ + if (std::strcmp(ent->d_name, ".") == 0 || std::strcmp(ent->d_name, "..") == 0) { + continue; + } + + /* Get the entry name length. */ + const int e_len = std::strlen(ent->d_name); + std::memcpy(cur_path_buf.get() + ofs, ent->d_name, e_len + 1); + + /* Get the dir type. */ + const auto d_type = ent->d_type; + + if (d_type == DT_DIR) { + /* If a directory, recursively delete it. */ + R_TRY(this->DeleteDirectoryRecursivelyInternal(cur_path_buf.get(), true)); + } else { + /* If a file, just delete it. */ + auto delete_file = [&]() -> Result { + const auto res = ::unlink(cur_path_buf.get()); + R_UNLESS(res >= 0, ConvertErrnoToResult(ErrnoSource_Unlink)); + R_SUCCEED(); + }; + + R_TRY(fssystem::RetryToAvoidTargetLocked(delete_file)); + R_TRY(WaitDeletionCompletion(cur_path_buf.get())); + } + } + } + } + + /* If we should, delete the top level directory. */ + if (delete_top) { + auto delete_impl = [&] () -> Result { + R_UNLESS(::rmdir(path) == 0, ConvertErrnoToResult(ErrnoSource_Rmdir)); + R_SUCCEED(); + }; + + /* Perform the delete. */ + R_TRY(fssystem::RetryToAvoidTargetLocked(delete_impl)); + + /* Wait for the deletion to complete. */ + R_TRY(WaitDeletionCompletion(path)); + } + } + #endif + + R_SUCCEED(); + } + + Result LocalFileSystem::DoCreateFile(const fs::Path &path, s64 size, int flags) { + AMS_UNUSED(flags); + + /* Resolve the path. */ + NativePathBuffer native_path; + R_TRY(this->ResolveFullPath(std::addressof(native_path), path, MaxFilePathLength, 0, false)); + + /* Create the file. */ + #if defined(ATMOSPHERE_OS_WINDOWS) + { + /* Get handle to created file. */ + const auto handle = ::CreateFileW(native_path.get(), GENERIC_WRITE, 0, nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr); + if (handle == INVALID_HANDLE_VALUE) { + /* If we failed because of target locked, it may be the case that the path already exists as a directory. */ + R_TRY_CATCH(ConvertLastErrorToResult()) { + R_CATCH(fs::ResultTargetLocked) { + /* Get the file attributes. */ + const auto attr = ::GetFileAttributesW(native_path.get()); + + /* Check they're valid. */ + R_UNLESS(attr != INVALID_FILE_ATTRIBUTES, R_CURRENT_RESULT); + + /* Check that they specify a directory. */ + R_UNLESS((attr & FILE_ATTRIBUTE_DIRECTORY) != 0, R_CURRENT_RESULT); + + /* The path is an existing directory. */ + R_THROW(fs::ResultPathAlreadyExists()); + } + } R_END_TRY_CATCH; + } + ON_SCOPE_EXIT { ::CloseHandle(handle); }; + + /* Set the file as sparse. */ + { + DWORD dummy; + ::DeviceIoControl(handle, FSCTL_SET_SPARSE, nullptr, 0, nullptr, 0, std::addressof(dummy), nullptr); + } + + /* Set the file size. */ + if (size > 0) { + R_TRY(SetFileSizeImpl(handle, size)); + } + } + #else + { + /* Create the file. */ + const auto handle = RetryForEIntr([&] () ALWAYS_INLINE_LAMBDA -> int { + return ::open(native_path.get(), O_WRONLY | O_CREAT | O_EXCL, 0666); + }); + R_UNLESS(handle >= 0, ConvertErrnoToResult(ErrnoSource_CreateFile)); + ON_SCOPE_EXIT { CloseFileDescriptor(handle); }; + + /* Set the file as sparse. */ + /* TODO: How do you do this on macos/linux? */ + + /* Set the file size. */ + if (size > 0) { + R_TRY(SetFileSizeImpl(handle, size)); + } + } + #endif + + R_SUCCEED(); + } + + Result LocalFileSystem::DoDeleteFile(const fs::Path &path) { + /* Resolve the path. */ + NativePathBuffer native_path; + R_TRY(this->ResolveFullPath(std::addressof(native_path), path, MaxFilePathLength, 0, true)); + + /* Delete the file, retrying on target locked. */ + auto delete_impl = [&] () -> Result { + #if defined(ATMOSPHERE_OS_WINDOWS) + { + /* Try to delete the file directly. */ + R_SUCCEED_IF(::DeleteFileW(native_path.get())); + + /* Convert the last error to a result. */ + const auto last_error_result = ConvertLastErrorToResult(); + + /* Check if access denied; it may indicate we tried to open a directory. */ + R_UNLESS(::GetLastError() == ERROR_ACCESS_DENIED, last_error_result); + + /* Check if we tried to open a directory. */ + fs::DirectoryEntryType type; + R_TRY(GetEntryTypeImpl(std::addressof(type), native_path.get())); + + /* If the type is anything other than directory, perform generic result conversion. */ + R_UNLESS(type == fs::DirectoryEntryType_Directory, last_error_result); + + /* Return path not found, for trying to open a file as a directory. */ + R_THROW(fs::ResultPathNotFound()); + } + #else + { + /* If on macOS, we need to check if the path is a directory before trying to unlink it. */ + /* This is because unlink succeeds on directories when executing as superuser. */ + #if defined(ATMOSPHERE_OS_MACOS) + { + /* Check if we tried to open a directory. */ + fs::DirectoryEntryType type; + R_TRY(GetEntryTypeImpl(std::addressof(type), native_path.get())); + R_UNLESS(type == fs::DirectoryEntryType_File, fs::ResultPathNotFound()); + } + #endif + + /* Delete the file. */ + const auto res = ::unlink(native_path.get()); + R_UNLESS(res >= 0, ConvertErrnoToResult(ErrnoSource_Unlink)); + } + #endif + + R_SUCCEED(); + }; + + /* Perform the delete. */ + R_TRY(fssystem::RetryToAvoidTargetLocked(delete_impl)); + + /* Wait for the deletion to complete. */ + R_RETURN(WaitDeletionCompletion(native_path.get())); + } + + Result LocalFileSystem::DoCreateDirectory(const fs::Path &path) { + /* Check for path validity. */ + R_UNLESS(path != "/", fs::ResultPathNotFound()); + R_UNLESS(path != ".", fs::ResultPathNotFound()); + + /* Resolve the path. */ + NativePathBuffer native_path; + R_TRY(this->ResolveFullPath(std::addressof(native_path), path, MaxDirectoryPathLength, 0, false)); + + /* Create the directory. */ + #if defined(ATMOSPHERE_OS_WINDOWS) + R_UNLESS(::CreateDirectoryW(native_path.get(), nullptr), ConvertLastErrorToResult()); + #else + R_UNLESS(::mkdir(native_path.get(), 0777) == 0, ConvertErrnoToResult(ErrnoSource_Mkdir)); + #endif + + R_SUCCEED(); + } + + Result LocalFileSystem::DoDeleteDirectory(const fs::Path &path) { + /* Resolve the path. */ + NativePathBuffer native_path; + R_TRY(this->ResolveFullPath(std::addressof(native_path), path, MaxFilePathLength, 0, true)); + + /* Delete the directory, retrying on target locked. */ + auto delete_impl = [&] () -> Result { + #if defined(ATMOSPHERE_OS_WINDOWS) + R_UNLESS(::RemoveDirectoryW(native_path.get()), ConvertLastErrorToResult()); + #else + R_UNLESS(::rmdir(native_path.get()) == 0, ConvertErrnoToResult(ErrnoSource_Rmdir)); + #endif + + R_SUCCEED(); + }; + + /* Perform the delete. */ + R_TRY(fssystem::RetryToAvoidTargetLocked(delete_impl)); + + /* Wait for the deletion to complete. */ + R_RETURN(WaitDeletionCompletion(native_path.get())); + } + + Result LocalFileSystem::DoDeleteDirectoryRecursively(const fs::Path &path) { + /* Resolve the path. */ + NativePathBuffer native_path; + R_TRY(this->ResolveFullPath(std::addressof(native_path), path, MaxFilePathLength, 0, true)); + + /* Delete the directory. */ + R_RETURN(this->DeleteDirectoryRecursivelyInternal(native_path.get(), true)); + } + + Result LocalFileSystem::DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) { + /* Resolve the old path. */ + NativePathBuffer native_old_path; + R_TRY(this->ResolveFullPath(std::addressof(native_old_path), old_path, MaxFilePathLength, 0, true)); + + /* Resolve the new path. */ + NativePathBuffer native_new_path; + R_TRY(this->ResolveFullPath(std::addressof(native_new_path), new_path, MaxFilePathLength, 0, false)); + + /* Check that the old path is a file. */ + fs::DirectoryEntryType type; + R_TRY(GetEntryTypeImpl(std::addressof(type), native_old_path.get())); + R_UNLESS(type == fs::DirectoryEntryType_File, fs::ResultPathNotFound()); + + /* Perform the rename. */ + auto rename_impl = [&]() -> Result { + #if defined(ATMOSPHERE_OS_WINDOWS) + if (!::MoveFileW(native_old_path.get(), native_new_path.get())) { + R_TRY_CATCH(ConvertLastErrorToResult()) { + R_CATCH(fs::ResultTargetLocked) { + /* If we're performing a self rename, succeed. */ + R_SUCCEED_IF(::wcscmp(native_old_path.get(), native_new_path.get()) == 0); + + /* Otherwise, check if the new path already exists. */ + const auto attr = ::GetFileAttributesW(native_new_path.get()); + R_UNLESS(attr == INVALID_FILE_ATTRIBUTES, fs::ResultPathAlreadyExists()); + + /* Return the original result. */ + R_THROW(R_CURRENT_RESULT); + } + } R_END_TRY_CATCH; + } + #else + { + /* ::rename() will destroy an existing file at new path...so check for that case ahead of time. */ + { + struct stat st; + R_UNLESS(::stat(native_new_path.get(), std::addressof(st)) < 0, fs::ResultPathAlreadyExists()); + } + + /* Rename the file. */ + R_UNLESS(::rename(native_old_path.get(), native_new_path.get()) == 0, ConvertErrnoToResult(ErrnoSource_RenameFile)); + } + #endif + R_SUCCEED(); + }; + + R_RETURN(fssystem::RetryToAvoidTargetLocked(rename_impl)); + } + + Result LocalFileSystem::DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) { + /* Resolve the old path. */ + NativePathBuffer native_old_path; + R_TRY(this->ResolveFullPath(std::addressof(native_old_path), old_path, MaxDirectoryPathLength, 0, true)); + + /* Resolve the new path. */ + NativePathBuffer native_new_path; + R_TRY(this->ResolveFullPath(std::addressof(native_new_path), new_path, MaxDirectoryPathLength, 0, false)); + + /* Check that the old path is a file. */ + fs::DirectoryEntryType type; + R_TRY(GetEntryTypeImpl(std::addressof(type), native_old_path.get())); + R_UNLESS(type == fs::DirectoryEntryType_Directory, fs::ResultPathNotFound()); + + /* Perform the rename. */ + auto rename_impl = [&]() -> Result { + #if defined(ATMOSPHERE_OS_WINDOWS) + if (!::MoveFileW(native_old_path.get(), native_new_path.get())) { + R_TRY_CATCH(ConvertLastErrorToResult()) { + R_CATCH(fs::ResultTargetLocked) { + /* If we're performing a self rename, succeed. */ + R_SUCCEED_IF(::wcscmp(native_old_path.get(), native_new_path.get()) == 0); + + /* Otherwise, check if the new path already exists. */ + const auto attr = ::GetFileAttributesW(native_new_path.get()); + R_UNLESS(attr == INVALID_FILE_ATTRIBUTES, fs::ResultPathAlreadyExists()); + + /* Return the original result. */ + R_THROW(R_CURRENT_RESULT); + } + } R_END_TRY_CATCH; + } + #else + { + /* ::rename() will overwrite an existing empty directory at the target, so check for that ahead of time. */ + { + struct stat st; + R_UNLESS(::stat(native_new_path.get(), std::addressof(st)) < 0, fs::ResultPathAlreadyExists()); + } + + /* Rename the directory. */ + R_UNLESS(::rename(native_old_path.get(), native_new_path.get()) == 0, ConvertErrnoToResult(ErrnoSource_RenameDirectory)); + } + #endif + R_SUCCEED(); + }; + + R_RETURN(fssystem::RetryToAvoidTargetLocked(rename_impl)); + } + + Result LocalFileSystem::DoGetEntryType(fs::DirectoryEntryType *out, const fs::Path &path) { + /* Resolve the path. */ + NativePathBuffer native_path; + R_TRY(this->ResolveFullPath(std::addressof(native_path), path, MaxFilePathLength, 0, true)); + + /* Get the entry type. */ + R_RETURN(GetEntryTypeImpl(out, native_path.get())); + } + + Result LocalFileSystem::DoOpenFile(std::unique_ptr *out_file, const fs::Path &path, fs::OpenMode mode) { + /* Resolve the path. */ + NativePathBuffer native_path; + R_TRY(this->ResolveFullPath(std::addressof(native_path), path, MaxFilePathLength, 0, true)); + + /* Open the file, retrying on target locked. */ + auto open_impl = [&] () -> Result { + #if defined(ATMOSPHERE_OS_WINDOWS) + /* Open a windows file handle. */ + const DWORD desired_access = ((mode & fs::OpenMode_Read) ? GENERIC_READ : 0) | ((mode & fs::OpenMode_Write) ? GENERIC_WRITE : 0); + const auto file_handle = ::CreateFileW(native_path.get(), desired_access, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, nullptr); + if (file_handle == INVALID_HANDLE_VALUE) { + /* Convert the last error to a result. */ + const auto last_error_result = ConvertLastErrorToResult(); + + /* Check if access denied; it may indicate we tried to open a directory. */ + R_UNLESS(::GetLastError() == ERROR_ACCESS_DENIED, last_error_result); + + /* Check if we tried to open a directory. */ + fs::DirectoryEntryType type; + R_TRY(GetEntryTypeImpl(std::addressof(type), native_path.get())); + + /* If the type isn't file, return path not found. */ + R_UNLESS(type == fs::DirectoryEntryType_File, fs::ResultPathNotFound()); + + /* Return the error we encountered earlier. */ + R_THROW(last_error_result); + } + ON_RESULT_FAILURE { ::CloseHandle(file_handle); }; + #else + const bool is_read = (mode & fs::OpenMode_Read); + const bool is_write = (mode & fs::OpenMode_Write); + int file_handle = RetryForEIntr([&] () ALWAYS_INLINE_LAMBDA { + return ::open(native_path.get(), (is_read && is_write) ? (O_RDWR) : (is_write ? (O_WRONLY) : (is_read ? (O_RDONLY) : (0)))); + }); + R_UNLESS(file_handle >= 0, ConvertErrnoToResult(ErrnoSource_OpenFile)); + ON_RESULT_FAILURE { CloseFileDescriptor(file_handle); }; + #endif + + /* Create a new local file. */ + auto file = std::make_unique(file_handle, mode); + R_UNLESS(file != nullptr, fs::ResultAllocationFailureInLocalFileSystemA()); + + /* Set the output file. */ + *out_file = std::move(file); + R_SUCCEED(); + }; + + R_RETURN(fssystem::RetryToAvoidTargetLocked(open_impl)); + } + + Result LocalFileSystem::DoOpenDirectory(std::unique_ptr *out_dir, const fs::Path &path, fs::OpenDirectoryMode mode) { + /* Resolve the path. */ + NativePathBuffer native_path; + R_TRY(this->ResolveFullPath(std::addressof(native_path), path, MaxFilePathLength, 3, true)); + + /* Open the directory, retrying on target locked. */ + auto open_impl = [&] () -> Result { + #if defined(ATMOSPHERE_OS_WINDOWS) + /* Open a handle file handle. */ + const auto dir_handle = ::CreateFileW(native_path.get(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); + R_UNLESS(dir_handle != INVALID_HANDLE_VALUE, ConvertLastErrorToResult()); + ON_RESULT_FAILURE { ::CloseHandle(dir_handle); }; + + /* Fix up the path for us to perform a windows search. */ + const auto native_len = ::wcslen(native_path.get()); + const bool has_sep = native_len > 0 && native_path[native_len - 1] == '\\'; + if (has_sep) { + native_path[native_len + 0] = '*'; + native_path[native_len + 1] = 0; + } else { + native_path[native_len + 0] = '\\'; + native_path[native_len + 1] = '*'; + native_path[native_len + 2] = 0; + } + + /* Open windows search handle. */ + WIN32_FIND_DATAW fd; + const auto search_handle = ::FindFirstFileW(native_path.get(), std::addressof(fd)); + if (search_handle == INVALID_HANDLE_VALUE) { + /* Convert the last error to a result. */ + const auto last_error_result = ConvertLastErrorToResult(); + + /* Fix the path, so that we can check if we tried to open a file. */ + native_path[native_len] = 0; + + /* Check if we tried to open a directory. */ + fs::DirectoryEntryType type; + R_TRY(GetEntryTypeImpl(std::addressof(type), native_path.get())); + + /* If the type isn't directory, return path not found. */ + R_UNLESS(type == fs::DirectoryEntryType_Directory, fs::ResultPathNotFound()); + + /* Return the error we encountered earlier. */ + R_THROW(last_error_result); + } + ON_RESULT_FAILURE_2 { ::CloseHandle(search_handle); }; + #else + /* Open the directory. */ + const auto dir_handle = RetryForEIntr([&] () ALWAYS_INLINE_LAMBDA { return ::open(native_path.get(), O_RDONLY | O_DIRECTORY); }); + R_UNLESS(dir_handle >= 0, ConvertErrnoToResult(ErrnoSource_OpenDirectory)); + ON_RESULT_FAILURE { CloseFileDescriptor(dir_handle); }; + + /* Non-windows doesn't have separate search handle. */ + const auto search_handle = -1; + #endif + + /* Create a new local directory. */ + auto dir = std::make_unique(dir_handle, search_handle, mode, std::move(native_path)); + R_UNLESS(dir != nullptr, fs::ResultAllocationFailureInLocalFileSystemB()); + + /* Set the output directory. */ + *out_dir = std::move(dir); + R_SUCCEED(); + }; + + R_RETURN(fssystem::RetryToAvoidTargetLocked(open_impl)); + } + + Result LocalFileSystem::DoCommit() { + R_SUCCEED(); + } + + Result LocalFileSystem::DoGetFreeSpaceSize(s64 *out, const fs::Path &path) { + s64 dummy; + R_RETURN(this->DoGetDiskFreeSpace(out, std::addressof(dummy), std::addressof(dummy), path)); + } + + Result LocalFileSystem::DoGetTotalSpaceSize(s64 *out, const fs::Path &path) { + s64 dummy; + R_RETURN(this->DoGetDiskFreeSpace(std::addressof(dummy), out, std::addressof(dummy), path)); + } + + Result LocalFileSystem::DoCleanDirectoryRecursively(const fs::Path &path) { + /* Resolve the path. */ + NativePathBuffer native_path; + R_TRY(this->ResolveFullPath(std::addressof(native_path), path, MaxFilePathLength, 0, true)); + + /* Delete the directory. */ + R_RETURN(this->DeleteDirectoryRecursivelyInternal(native_path.get(), false)); + } + + Result LocalFileSystem::DoGetFileTimeStampRaw(fs::FileTimeStampRaw *out, const fs::Path &path) { + /* Resolve the path. */ + NativePathBuffer native_path; + R_TRY(this->ResolveFullPath(std::addressof(native_path), path, MaxFilePathLength, 0, true)); + + /* Get the file timestamp. */ + #if defined(ATMOSPHERE_OS_WINDOWS) + { + /* Get the file attributes. */ + WIN32_FILE_ATTRIBUTE_DATA attr; + R_UNLESS(::GetFileAttributesExW(native_path.get(), GetFileExInfoStandard, std::addressof(attr)), ConvertLastErrorToResult()); + + /* Check that the file isn't a directory. */ + R_UNLESS((attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0, fs::ResultPathNotFound()); + + /* Decode the FILETIME values. */ + const s64 create = static_cast(static_cast(attr.ftCreationTime.dwLowDateTime ) | (static_cast(attr.ftCreationTime.dwHighDateTime ) << BITSIZEOF(attr.ftCreationTime.dwLowDateTime ))); + const s64 access = static_cast(static_cast(attr.ftLastAccessTime.dwLowDateTime) | (static_cast(attr.ftLastAccessTime.dwHighDateTime) << BITSIZEOF(attr.ftLastAccessTime.dwLowDateTime))); + const s64 modify = static_cast(static_cast(attr.ftLastWriteTime.dwLowDateTime ) | (static_cast(attr.ftLastWriteTime.dwHighDateTime ) << BITSIZEOF(attr.ftLastWriteTime.dwLowDateTime ))); + + /* Set the output timestamps. */ + if (m_use_posix_time) { + out->create = ConvertWindowsTimeToPosixTime(create); + out->access = ConvertWindowsTimeToPosixTime(access); + out->modify = ConvertWindowsTimeToPosixTime(modify); + } else { + out->create = create; + out->access = access; + out->modify = modify; + } + + /* We're not using local timestamps. */ + out->is_local_time = false; + } + #else + { + /* Get the file stats. */ + struct stat st; + R_UNLESS(::stat(native_path.get(), std::addressof(st)) == 0, ConvertErrnoToResult(ErrnoSource_Stat)); + + /* Check that the path isn't a directory. */ + R_UNLESS(!(S_ISDIR(st.st_mode)), fs::ResultPathNotFound()); + + /* Set the output timestamps. */ + #if defined(ATMOSPHERE_OS_LINUX) + if (m_use_posix_time) { + out->create = st.st_ctim.tv_sec; + out->access = st.st_atim.tv_sec; + out->modify = st.st_mtim.tv_sec; + } else { + out->create = ConvertPosixTimeToWindowsTime(st.st_ctim.tv_sec, st.st_ctim.tv_nsec); + out->access = ConvertPosixTimeToWindowsTime(st.st_atim.tv_sec, st.st_atim.tv_nsec); + out->modify = ConvertPosixTimeToWindowsTime(st.st_mtim.tv_sec, st.st_mtim.tv_nsec); + } + #else + if (m_use_posix_time) { + out->create = st.st_ctimespec.tv_sec; + out->access = st.st_atimespec.tv_sec; + out->modify = st.st_mtimespec.tv_sec; + } else { + out->create = ConvertPosixTimeToWindowsTime(st.st_ctimespec.tv_sec, st.st_ctimespec.tv_nsec); + out->access = ConvertPosixTimeToWindowsTime(st.st_atimespec.tv_sec, st.st_atimespec.tv_nsec); + out->modify = ConvertPosixTimeToWindowsTime(st.st_mtimespec.tv_sec, st.st_mtimespec.tv_nsec); + } + #endif + + /* We're not using local timestamps. */ + out->is_local_time = false; + } + #endif + + R_SUCCEED(); + } + + Result LocalFileSystem::DoQueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const fs::Path &path) { + AMS_UNUSED(dst, dst_size, src, src_size, query, path); + R_THROW(fs::ResultUnsupportedOperation()); + } + + Result LocalFileSystem::DoCommitProvisionally(s64 counter) { + AMS_UNUSED(counter); + R_SUCCEED(); + } + + Result LocalFileSystem::DoRollback() { + R_SUCCEED(); + } + +} +#endif \ No newline at end of file diff --git a/libraries/libstratosphere/source/fssystem/fssystem_nca_file_system_driver.cpp b/libraries/libstratosphere/source/fssystem/fssystem_nca_file_system_driver.cpp index b5060f138..c468deb40 100644 --- a/libraries/libstratosphere/source/fssystem/fssystem_nca_file_system_driver.cpp +++ b/libraries/libstratosphere/source/fssystem/fssystem_nca_file_system_driver.cpp @@ -292,13 +292,13 @@ namespace ams::fssystem { using IntegrityLevelInfo = NcaFsHeader::HashData::IntegrityMetaInfo::LevelHashInfo; using IntegrityDataInfo = IntegrityLevelInfo::HierarchicalIntegrityVerificationLevelInformation; - inline const Sha256DataRegion &GetSha256DataRegion(const NcaFsHeader::HashData &hash_data) { - return hash_data.hierarchical_sha256_data.hash_layer_region[1]; - } + // inline const Sha256DataRegion &GetSha256DataRegion(const NcaFsHeader::HashData &hash_data) { + // return hash_data.hierarchical_sha256_data.hash_layer_region[1]; + // } - inline const IntegrityDataInfo &GetIntegrityDataInfo(const NcaFsHeader::HashData &hash_data) { - return hash_data.integrity_meta_info.level_hash_info.info[hash_data.integrity_meta_info.level_hash_info.max_layers - 2]; - } + // inline const IntegrityDataInfo &GetIntegrityDataInfo(const NcaFsHeader::HashData &hash_data) { + // return hash_data.integrity_meta_info.level_hash_info.info[hash_data.integrity_meta_info.level_hash_info.max_layers - 2]; + // } } @@ -706,7 +706,7 @@ namespace ams::fssystem { Result NcaFileSystemDriver::CreateSparseStorage(std::shared_ptr *out, s64 *out_fs_data_offset, std::shared_ptr *out_sparse_storage, std::shared_ptr *out_meta_storage, s32 index, const NcaAesCtrUpperIv &upper_iv, const NcaSparseInfo &sparse_info) { /* Validate preconditions. */ AMS_ASSERT(out != nullptr); - AMS_ASSERT(base_storage != nullptr); + AMS_ASSERT(out_fs_data_offset != nullptr); /* Check the sparse info generation. */ R_UNLESS(sparse_info.generation != 0, fs::ResultInvalidNcaHeader()); diff --git a/libraries/libstratosphere/source/fssystem/fssystem_nca_reader.cpp b/libraries/libstratosphere/source/fssystem/fssystem_nca_reader.cpp index d1d1e440c..d605dae12 100644 --- a/libraries/libstratosphere/source/fssystem/fssystem_nca_reader.cpp +++ b/libraries/libstratosphere/source/fssystem/fssystem_nca_reader.cpp @@ -375,7 +375,7 @@ namespace ams::fssystem { /* Generate the hash. */ Hash hash; - crypto::GenerateSha256Hash(std::addressof(hash), sizeof(hash), std::addressof(m_data), sizeof(NcaFsHeader)); + crypto::GenerateSha256(std::addressof(hash), sizeof(hash), std::addressof(m_data), sizeof(NcaFsHeader)); /* Validate the hash. */ R_UNLESS(crypto::IsSameBytes(std::addressof(reader.GetFsHeaderHash(index)), std::addressof(hash), sizeof(Hash)), fs::ResultNcaFsHeaderHashVerificationFailed()); diff --git a/libraries/libstratosphere/source/fssystem/fssystem_partition_file_system.cpp b/libraries/libstratosphere/source/fssystem/fssystem_partition_file_system.cpp index 1e323dcda..639173e07 100644 --- a/libraries/libstratosphere/source/fssystem/fssystem_partition_file_system.cpp +++ b/libraries/libstratosphere/source/fssystem/fssystem_partition_file_system.cpp @@ -19,6 +19,8 @@ namespace ams::fssystem { namespace { + constexpr const char RootPath[] = "/"; + class PartitionFileSystemDefaultAllocator : public MemoryResource { private: virtual void *AllocateImpl(size_t size, size_t alignment) override { @@ -53,7 +55,7 @@ namespace ams::fssystem { virtual Result DoGetSize(s64 *out) override final { *out = m_partition_entry->size; - return ResultSuccess(); + R_SUCCEED(); } virtual Result DoFlush() override final { @@ -61,7 +63,7 @@ namespace ams::fssystem { R_SUCCEED_IF((m_mode & fs::OpenMode_Write) == 0); /* Flush base storage. */ - return m_parent->m_base_storage->Flush(); + R_RETURN(m_parent->m_base_storage->Flush()); } virtual Result DoWrite(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) override final { @@ -78,12 +80,12 @@ namespace ams::fssystem { R_UNLESS(static_cast(offset + size) <= static_cast(m_partition_entry->size), fs::ResultInvalidSize()); /* Write to the base storage. */ - return m_parent->m_base_storage->Write(m_parent->m_meta_data_size + m_partition_entry->offset + offset, buffer, size); + R_RETURN(m_parent->m_base_storage->Write(m_parent->m_meta_data_size + m_partition_entry->offset + offset, buffer, size)); } virtual Result DoSetSize(s64 size) override final { R_TRY(this->DrySetSize(size, m_mode)); - return fs::ResultUnsupportedOperationInPartitionFileA(); + R_RETURN(fs::ResultUnsupportedOperationInPartitionFileA()); } virtual Result DoOperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override final { @@ -96,7 +98,7 @@ namespace ams::fssystem { case fs::OperationId::QueryRange: break; default: - return fs::ResultUnsupportedOperationInPartitionFileB(); + R_THROW(fs::ResultUnsupportedOperationInPartitionFileB()); } /* Validate offset and size. */ @@ -105,7 +107,7 @@ namespace ams::fssystem { R_UNLESS(static_cast(offset + size) <= static_cast(m_partition_entry->size), fs::ResultInvalidSize()); R_UNLESS(static_cast(offset + size) >= offset, fs::ResultInvalidSize()); - return m_parent->m_base_storage->OperateRange(dst, dst_size, op_id, m_parent->m_meta_data_size + m_partition_entry->offset + offset, size, src, src_size); + R_RETURN(m_parent->m_base_storage->OperateRange(dst, dst_size, op_id, m_parent->m_meta_data_size + m_partition_entry->offset + offset, size, src, src_size)); } public: virtual sf::cmif::DomainObjectId GetDomainObjectId() const override { @@ -125,7 +127,7 @@ namespace ams::fssystem { /* Set output size. */ *out = read_size; - return ResultSuccess(); + R_SUCCEED(); } template<> @@ -213,7 +215,7 @@ namespace ams::fssystem { /* Set output size. */ *out = read_size; - return ResultSuccess(); + R_SUCCEED(); } template @@ -229,7 +231,7 @@ namespace ams::fssystem { /* There are no subdirectories. */ if ((m_mode & fs::OpenDirectoryMode_File) == 0) { *out_count = 0; - return ResultSuccess(); + R_SUCCEED(); } /* Calculate number of entries. */ @@ -247,7 +249,7 @@ namespace ams::fssystem { } *out_count = entry_count; - return ResultSuccess(); + R_SUCCEED(); } virtual Result DoGetEntryCount(s64 *out) override final { @@ -258,7 +260,7 @@ namespace ams::fssystem { *out = 0; } - return ResultSuccess(); + R_SUCCEED(); } virtual sf::cmif::DomainObjectId GetDomainObjectId() const override { @@ -294,13 +296,13 @@ namespace ams::fssystem { m_base_storage = base_storage; m_meta_data_size = m_meta_data->GetMetaDataSize(); m_initialized = true; - return ResultSuccess(); + R_SUCCEED(); } template Result PartitionFileSystemCore::Initialize(std::unique_ptr &&meta_data, std::shared_ptr base_storage) { m_unique_meta_data = std::move(meta_data); - return this->Initialize(m_unique_meta_data.get(), base_storage); + R_RETURN(this->Initialize(m_unique_meta_data.get(), base_storage)); } template @@ -314,24 +316,24 @@ namespace ams::fssystem { m_meta_data = meta_data; m_meta_data_size = m_meta_data->GetMetaDataSize(); m_initialized = true; - return ResultSuccess(); + R_SUCCEED(); } template Result PartitionFileSystemCore::Initialize(fs::IStorage *base_storage) { - return this->Initialize(base_storage, std::addressof(g_partition_filesystem_default_allocator)); + R_RETURN(this->Initialize(base_storage, std::addressof(g_partition_filesystem_default_allocator))); } template Result PartitionFileSystemCore::Initialize(std::shared_ptr base_storage) { m_shared_storage = std::move(base_storage); - return this->Initialize(m_shared_storage.get()); + R_RETURN(this->Initialize(m_shared_storage.get())); } template Result PartitionFileSystemCore::Initialize(std::shared_ptr base_storage, MemoryResource *allocator) { m_shared_storage = std::move(base_storage); - return this->Initialize(m_shared_storage.get(), allocator); + R_RETURN(this->Initialize(m_shared_storage.get(), allocator)); } template @@ -345,114 +347,116 @@ namespace ams::fssystem { /* Output offset. */ *out_offset = m_meta_data_size + m_meta_data->GetEntry(entry_index)->offset; - return ResultSuccess(); + R_SUCCEED(); } template - Result PartitionFileSystemCore::DoGetEntryType(fs::DirectoryEntryType *out, const char *path) { + Result PartitionFileSystemCore::DoGetEntryType(fs::DirectoryEntryType *out, const fs::Path &path) { /* Validate preconditions. */ R_UNLESS(m_initialized, fs::ResultPreconditionViolation()); - R_UNLESS(fs::PathNormalizer::IsSeparator(path[0]), fs::ResultInvalidPathFormat()); + + const char * const p = path.GetString(); + R_UNLESS(p[0] == RootPath[0], fs::ResultInvalidPathFormat()); /* Check if the path is for a directory. */ - if (std::strncmp(path, fs::PathNormalizer::RootPath, sizeof(fs::PathNormalizer::RootPath)) == 0) { + if (util::Strncmp(p, RootPath, sizeof(RootPath))) { *out = fs::DirectoryEntryType_Directory; - return ResultSuccess(); + R_SUCCEED(); } /* Ensure that path is for a file. */ - R_UNLESS(m_meta_data->GetEntryIndex(path + 1) >= 0, fs::ResultPathNotFound()); + R_UNLESS(m_meta_data->GetEntryIndex(p + 1) >= 0, fs::ResultPathNotFound()); *out = fs::DirectoryEntryType_File; - return ResultSuccess(); + R_SUCCEED(); } template - Result PartitionFileSystemCore::DoOpenFile(std::unique_ptr *out_file, const char *path, fs::OpenMode mode) { + Result PartitionFileSystemCore::DoOpenFile(std::unique_ptr *out_file, const fs::Path &path, fs::OpenMode mode) { /* Validate preconditions. */ R_UNLESS(m_initialized, fs::ResultPreconditionViolation()); /* Obtain and validate the entry index. */ - const s32 entry_index = m_meta_data->GetEntryIndex(path + 1); + const s32 entry_index = m_meta_data->GetEntryIndex(path.GetString() + 1); R_UNLESS(entry_index >= 0, fs::ResultPathNotFound()); /* Create and output the file directory. */ std::unique_ptr file = std::make_unique(this, m_meta_data->GetEntry(entry_index), mode); R_UNLESS(file != nullptr, fs::ResultAllocationFailureInPartitionFileSystemB()); *out_file = std::move(file); - return ResultSuccess(); + R_SUCCEED(); } template - Result PartitionFileSystemCore::DoOpenDirectory(std::unique_ptr *out_dir, const char *path, fs::OpenDirectoryMode mode) { + Result PartitionFileSystemCore::DoOpenDirectory(std::unique_ptr *out_dir, const fs::Path &path, fs::OpenDirectoryMode mode) { /* Validate preconditions. */ - R_UNLESS(m_initialized, fs::ResultPreconditionViolation()); - R_UNLESS(std::strncmp(path, fs::PathNormalizer::RootPath, sizeof(fs::PathNormalizer::RootPath)) == 0, fs::ResultPathNotFound()); + R_UNLESS(m_initialized, fs::ResultPreconditionViolation()); + R_UNLESS(path == RootPath, fs::ResultPathNotFound()); /* Create and output the partition directory. */ std::unique_ptr directory = std::make_unique(this, mode); R_UNLESS(directory != nullptr, fs::ResultAllocationFailureInPartitionFileSystemC()); *out_dir = std::move(directory); - return ResultSuccess(); + R_SUCCEED(); } template Result PartitionFileSystemCore::DoCommit() { - return ResultSuccess(); + R_SUCCEED(); } template - Result PartitionFileSystemCore::DoCleanDirectoryRecursively(const char *path) { + Result PartitionFileSystemCore::DoCleanDirectoryRecursively(const fs::Path &path) { AMS_UNUSED(path); - return fs::ResultUnsupportedOperationInPartitionFileSystemA(); + R_THROW(fs::ResultUnsupportedOperationInPartitionFileSystemA()); } template - Result PartitionFileSystemCore::DoCreateDirectory(const char *path) { + Result PartitionFileSystemCore::DoCreateDirectory(const fs::Path &path) { AMS_UNUSED(path); - return fs::ResultUnsupportedOperationInPartitionFileSystemA(); + R_THROW(fs::ResultUnsupportedOperationInPartitionFileSystemA()); } template - Result PartitionFileSystemCore::DoCreateFile(const char *path, s64 size, int option) { + Result PartitionFileSystemCore::DoCreateFile(const fs::Path &path, s64 size, int option) { AMS_UNUSED(path, size, option); - return fs::ResultUnsupportedOperationInPartitionFileSystemA(); + R_THROW(fs::ResultUnsupportedOperationInPartitionFileSystemA()); } template - Result PartitionFileSystemCore::DoDeleteDirectory(const char *path) { + Result PartitionFileSystemCore::DoDeleteDirectory(const fs::Path &path) { AMS_UNUSED(path); - return fs::ResultUnsupportedOperationInPartitionFileSystemA(); + R_THROW(fs::ResultUnsupportedOperationInPartitionFileSystemA()); } template - Result PartitionFileSystemCore::DoDeleteDirectoryRecursively(const char *path) { + Result PartitionFileSystemCore::DoDeleteDirectoryRecursively(const fs::Path &path) { AMS_UNUSED(path); - return fs::ResultUnsupportedOperationInPartitionFileSystemA(); + R_THROW(fs::ResultUnsupportedOperationInPartitionFileSystemA()); } template - Result PartitionFileSystemCore::DoDeleteFile(const char *path) { + Result PartitionFileSystemCore::DoDeleteFile(const fs::Path &path) { AMS_UNUSED(path); - return fs::ResultUnsupportedOperationInPartitionFileSystemA(); + R_THROW(fs::ResultUnsupportedOperationInPartitionFileSystemA()); } template - Result PartitionFileSystemCore::DoRenameDirectory(const char *old_path, const char *new_path) { + Result PartitionFileSystemCore::DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) { AMS_UNUSED(old_path, new_path); - return fs::ResultUnsupportedOperationInPartitionFileSystemA(); + R_THROW(fs::ResultUnsupportedOperationInPartitionFileSystemA()); } template - Result PartitionFileSystemCore::DoRenameFile(const char *old_path, const char *new_path) { + Result PartitionFileSystemCore::DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) { AMS_UNUSED(old_path, new_path); - return fs::ResultUnsupportedOperationInPartitionFileSystemA(); + R_THROW(fs::ResultUnsupportedOperationInPartitionFileSystemA()); } template Result PartitionFileSystemCore::DoCommitProvisionally(s64 counter) { AMS_UNUSED(counter); - return fs::ResultUnsupportedOperationInPartitionFileSystemB(); + R_THROW(fs::ResultUnsupportedOperationInPartitionFileSystemB()); } template class PartitionFileSystemCore; diff --git a/libraries/libstratosphere/source/fssystem/fssystem_romfs_filesystem.cpp b/libraries/libstratosphere/source/fssystem/fssystem_romfs_filesystem.cpp index cacfe8f18..822c2465d 100644 --- a/libraries/libstratosphere/source/fssystem/fssystem_romfs_filesystem.cpp +++ b/libraries/libstratosphere/source/fssystem/fssystem_romfs_filesystem.cpp @@ -37,26 +37,26 @@ namespace ams::fssystem { virtual ~RomFsFile() { /* ... */ } public: virtual Result DoRead(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) override { - R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([=, this]() -> Result { + R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([&]() -> Result { size_t read_size = 0; R_TRY(this->DryRead(std::addressof(read_size), offset, size, option, fs::OpenMode_Read)); R_TRY(m_parent->GetBaseStorage()->Read(offset + m_start, buffer, read_size)); *out = read_size; - return ResultSuccess(); + R_SUCCEED(); }, AMS_CURRENT_FUNCTION_NAME)); - return ResultSuccess(); + R_SUCCEED(); } virtual Result DoGetSize(s64 *out) override { *out = this->GetSize(); - return ResultSuccess(); + R_SUCCEED(); } virtual Result DoFlush() override { - return ResultSuccess(); + R_SUCCEED(); } virtual Result DoWrite(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) override { @@ -66,12 +66,12 @@ namespace ams::fssystem { R_TRY(this->DryWrite(std::addressof(needs_append), offset, size, option, fs::OpenMode_Read)); AMS_ASSERT(needs_append == false); - return fs::ResultUnsupportedOperationInRomFsFileA(); + R_THROW(fs::ResultUnsupportedOperationInRomFsFileA()); } virtual Result DoSetSize(s64 size) override { R_TRY(this->DrySetSize(size, fs::OpenMode_Read)); - return fs::ResultUnsupportedOperationInRomFsFileA(); + R_THROW(fs::ResultUnsupportedOperationInRomFsFileA()); } virtual Result DoOperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override { @@ -87,14 +87,14 @@ namespace ams::fssystem { operate_size = this->GetSize() - offset; } - R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([=, this]() -> Result { + R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([&]() -> Result { R_TRY(m_parent->GetBaseStorage()->OperateRange(dst, dst_size, op_id, m_start + offset, operate_size, src, src_size)); - return ResultSuccess(); + R_SUCCEED(); }, AMS_CURRENT_FUNCTION_NAME)); - return ResultSuccess(); + R_SUCCEED(); } default: - return fs::ResultUnsupportedOperationInRomFsFileB(); + R_THROW(fs::ResultUnsupportedOperationInRomFsFileB()); } } public: @@ -115,21 +115,21 @@ namespace ams::fssystem { RomFsDirectory(RomFsFileSystem *p, const FindPosition &f, fs::OpenDirectoryMode m) : m_parent(p), m_current_find(f), m_first_find(f), m_mode(m) { /* ... */ } virtual ~RomFsDirectory() override { /* ... */ } public: - virtual Result DoRead(s64 *out_count, fs::DirectoryEntry *out_entries, s64 max_entries) { - R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([=, this]() -> Result { - return this->ReadInternal(out_count, std::addressof(m_current_find), out_entries, max_entries); + virtual Result DoRead(s64 *out_count, fs::DirectoryEntry *out_entries, s64 max_entries) override { + R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([&]() -> Result { + R_RETURN(this->ReadInternal(out_count, std::addressof(m_current_find), out_entries, max_entries)); }, AMS_CURRENT_FUNCTION_NAME)); - return ResultSuccess(); + R_SUCCEED(); } - virtual Result DoGetEntryCount(s64 *out) { + virtual Result DoGetEntryCount(s64 *out) override { FindPosition find = m_first_find; R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([&]() -> Result { R_TRY(this->ReadInternal(out, std::addressof(find), nullptr, 0)); - return ResultSuccess(); + R_SUCCEED(); }, AMS_CURRENT_FUNCTION_NAME)); - return ResultSuccess(); + R_SUCCEED(); } private: Result ReadInternal(s64 *out_count, FindPosition *find, fs::DirectoryEntry *out_entries, s64 max_entries) { @@ -179,7 +179,7 @@ namespace ams::fssystem { } *out_count = i; - return ResultSuccess(); + R_SUCCEED(); } public: virtual sf::cmif::DomainObjectId GetDomainObjectId() const override { @@ -211,11 +211,11 @@ namespace ams::fssystem { R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([&]() -> Result { R_TRY(storage->Read(0, std::addressof(header), sizeof(header))); - return ResultSuccess(); + R_SUCCEED(); }, AMS_CURRENT_FUNCTION_NAME)); *out = CalculateRequiredWorkingMemorySize(header); - return ResultSuccess(); + R_SUCCEED(); } Result RomFsFileSystem::Initialize(fs::IStorage *base, void *work, size_t work_size, bool use_cache) { @@ -272,93 +272,99 @@ namespace ams::fssystem { /* Set members. */ m_entry_size = header.body_offset; m_base_storage = base; - return ResultSuccess(); + R_SUCCEED(); } Result RomFsFileSystem::Initialize(std::shared_ptr base, void *work, size_t work_size, bool use_cache) { m_shared_storage = std::move(base); - return this->Initialize(m_shared_storage.get(), work, work_size, use_cache); + R_RETURN(this->Initialize(m_shared_storage.get(), work, work_size, use_cache)); } Result RomFsFileSystem::GetFileInfo(RomFileTable::FileInfo *out, const char *path) { - R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([=, this]() -> Result { + R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([&]() -> Result { R_TRY_CATCH(m_rom_file_table.OpenFile(out, path)) { - R_CONVERT(fs::ResultDbmNotFound, fs::ResultPathNotFound()); + R_CONVERT(fs::ResultDbmNotFound, fs::ResultPathNotFound()); } R_END_TRY_CATCH; - return ResultSuccess(); + R_SUCCEED(); }, AMS_CURRENT_FUNCTION_NAME)); - return ResultSuccess(); + R_SUCCEED(); } - Result RomFsFileSystem::GetFileBaseOffset(s64 *out, const char *path) { + Result RomFsFileSystem::GetFileBaseOffset(s64 *out, const fs::Path &path) { + R_TRY(this->CheckPathFormat(path)); + RomFileTable::FileInfo info; R_TRY(this->GetFileInfo(std::addressof(info), path)); *out = m_entry_size + info.offset.Get(); - return ResultSuccess(); + R_SUCCEED(); } - Result RomFsFileSystem::DoCreateFile(const char *path, s64 size, int flags) { + Result RomFsFileSystem::DoCreateFile(const fs::Path &path, s64 size, int flags) { AMS_UNUSED(path, size, flags); - return fs::ResultUnsupportedOperationInRomFsFileSystemA(); + R_THROW(fs::ResultUnsupportedOperationInRomFsFileSystemA()); } - Result RomFsFileSystem::DoDeleteFile(const char *path) { + Result RomFsFileSystem::DoDeleteFile(const fs::Path &path) { AMS_UNUSED(path); - return fs::ResultUnsupportedOperationInRomFsFileSystemA(); + R_THROW(fs::ResultUnsupportedOperationInRomFsFileSystemA()); } - Result RomFsFileSystem::DoCreateDirectory(const char *path) { + Result RomFsFileSystem::DoCreateDirectory(const fs::Path &path) { AMS_UNUSED(path); - return fs::ResultUnsupportedOperationInRomFsFileSystemA(); + R_THROW(fs::ResultUnsupportedOperationInRomFsFileSystemA()); } - Result RomFsFileSystem::DoDeleteDirectory(const char *path) { + Result RomFsFileSystem::DoDeleteDirectory(const fs::Path &path) { AMS_UNUSED(path); - return fs::ResultUnsupportedOperationInRomFsFileSystemA(); + R_THROW(fs::ResultUnsupportedOperationInRomFsFileSystemA()); } - Result RomFsFileSystem::DoDeleteDirectoryRecursively(const char *path) { + Result RomFsFileSystem::DoDeleteDirectoryRecursively(const fs::Path &path) { AMS_UNUSED(path); - return fs::ResultUnsupportedOperationInRomFsFileSystemA(); + R_THROW(fs::ResultUnsupportedOperationInRomFsFileSystemA()); } - Result RomFsFileSystem::DoRenameFile(const char *old_path, const char *new_path) { + Result RomFsFileSystem::DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) { AMS_UNUSED(old_path, new_path); - return fs::ResultUnsupportedOperationInRomFsFileSystemA(); + R_THROW(fs::ResultUnsupportedOperationInRomFsFileSystemA()); } - Result RomFsFileSystem::DoRenameDirectory(const char *old_path, const char *new_path) { + Result RomFsFileSystem::DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) { AMS_UNUSED(old_path, new_path); - return fs::ResultUnsupportedOperationInRomFsFileSystemA(); + R_THROW(fs::ResultUnsupportedOperationInRomFsFileSystemA()); } - Result RomFsFileSystem::DoGetEntryType(fs::DirectoryEntryType *out, const char *path) { - R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([=, this]() -> Result { + Result RomFsFileSystem::DoGetEntryType(fs::DirectoryEntryType *out, const fs::Path &path) { + R_TRY(this->CheckPathFormat(path)); + + R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([&]() -> Result { fs::RomDirectoryInfo dir_info; - R_TRY_CATCH(m_rom_file_table.GetDirectoryInformation(std::addressof(dir_info), path)) { + R_TRY_CATCH(m_rom_file_table.GetDirectoryInformation(std::addressof(dir_info), path.GetString())) { R_CONVERT(fs::ResultDbmNotFound, fs::ResultPathNotFound()) R_CATCH(fs::ResultDbmInvalidOperation) { RomFileTable::FileInfo file_info; R_TRY(this->GetFileInfo(std::addressof(file_info), path)); *out = fs::DirectoryEntryType_File; - return ResultSuccess(); + R_SUCCEED(); } } R_END_TRY_CATCH; *out = fs::DirectoryEntryType_Directory; - return ResultSuccess(); + R_SUCCEED(); }, AMS_CURRENT_FUNCTION_NAME)); - return ResultSuccess(); + R_SUCCEED(); } - Result RomFsFileSystem::DoOpenFile(std::unique_ptr *out_file, const char *path, fs::OpenMode mode) { + Result RomFsFileSystem::DoOpenFile(std::unique_ptr *out_file, const fs::Path &path, fs::OpenMode mode) { R_UNLESS(mode == fs::OpenMode_Read, fs::ResultInvalidOpenMode()); + R_TRY(this->CheckPathFormat(path)); + RomFileTable::FileInfo file_info; R_TRY(this->GetFileInfo(std::addressof(file_info), path)); @@ -366,45 +372,47 @@ namespace ams::fssystem { R_UNLESS(file != nullptr, fs::ResultAllocationFailureInRomFsFileSystemC()); *out_file = std::move(file); - return ResultSuccess(); + R_SUCCEED(); } - Result RomFsFileSystem::DoOpenDirectory(std::unique_ptr *out_dir, const char *path, fs::OpenDirectoryMode mode) { + Result RomFsFileSystem::DoOpenDirectory(std::unique_ptr *out_dir, const fs::Path &path, fs::OpenDirectoryMode mode) { + R_TRY(this->CheckPathFormat(path)); + RomFileTable::FindPosition find; R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([&]() -> Result { - R_TRY_CATCH(m_rom_file_table.FindOpen(std::addressof(find), path)) { - R_CONVERT(fs::ResultDbmNotFound, fs::ResultPathNotFound()) + R_TRY_CATCH(m_rom_file_table.FindOpen(std::addressof(find), path.GetString())) { + R_CONVERT(fs::ResultDbmNotFound, fs::ResultPathNotFound()) } R_END_TRY_CATCH; - return ResultSuccess(); + R_SUCCEED(); }, AMS_CURRENT_FUNCTION_NAME)); auto dir = std::make_unique(this, find, mode); R_UNLESS(dir != nullptr, fs::ResultAllocationFailureInRomFsFileSystemD()); *out_dir = std::move(dir); - return ResultSuccess(); + R_SUCCEED(); } Result RomFsFileSystem::DoCommit() { - return ResultSuccess(); + R_SUCCEED(); } - Result RomFsFileSystem::DoGetFreeSpaceSize(s64 *out, const char *path) { + Result RomFsFileSystem::DoGetFreeSpaceSize(s64 *out, const fs::Path &path) { AMS_UNUSED(path); *out = 0; - return ResultSuccess(); + R_SUCCEED(); } - Result RomFsFileSystem::DoCleanDirectoryRecursively(const char *path) { + Result RomFsFileSystem::DoCleanDirectoryRecursively(const fs::Path &path) { AMS_UNUSED(path); - return fs::ResultUnsupportedOperationInRomFsFileSystemA(); + R_THROW(fs::ResultUnsupportedOperationInRomFsFileSystemA()); } Result RomFsFileSystem::DoCommitProvisionally(s64 counter) { AMS_UNUSED(counter); - return fs::ResultUnsupportedOperationInRomFsFileSystemB(); + R_THROW(fs::ResultUnsupportedOperationInRomFsFileSystemB()); } } diff --git a/libraries/libstratosphere/source/fssystem/fssystem_subdirectory_filesystem.cpp b/libraries/libstratosphere/source/fssystem/fssystem_subdirectory_filesystem.cpp deleted file mode 100644 index 61b5f26fc..000000000 --- a/libraries/libstratosphere/source/fssystem/fssystem_subdirectory_filesystem.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 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 - -namespace ams::fssystem { - - SubDirectoryFileSystem::SubDirectoryFileSystem(std::shared_ptr fs, const char *bp, bool unc) - : PathResolutionFileSystem(fs, unc) - { - m_base_path = nullptr; - R_ABORT_UNLESS(this->Initialize(bp)); - } - - SubDirectoryFileSystem::SubDirectoryFileSystem(std::unique_ptr fs, const char *bp, bool unc) - : PathResolutionFileSystem(std::move(fs), unc) - { - m_base_path = nullptr; - R_ABORT_UNLESS(this->Initialize(bp)); - } - - SubDirectoryFileSystem::~SubDirectoryFileSystem() { - if (m_base_path != nullptr) { - fs::impl::Deallocate(m_base_path, m_base_path_len); - } - } - - Result SubDirectoryFileSystem::Initialize(const char *bp) { - /* Make sure the path isn't too long. */ - R_UNLESS(strnlen(bp, fs::EntryNameLengthMax + 1) <= fs::EntryNameLengthMax, fs::ResultTooLongPath()); - - /* Normalize the path. */ - char normalized_path[fs::EntryNameLengthMax + 2]; - size_t normalized_path_len; - R_TRY(fs::PathNormalizer::Normalize(normalized_path, std::addressof(normalized_path_len), bp, sizeof(normalized_path), this->IsUncPreserved())); - - /* Ensure terminating '/' */ - if (!fs::PathNormalizer::IsSeparator(normalized_path[normalized_path_len - 1])) { - AMS_ASSERT(normalized_path_len + 2 < sizeof(normalized_path)); - normalized_path[normalized_path_len] = fs::StringTraits::DirectorySeparator; - normalized_path[normalized_path_len + 1] = fs::StringTraits::NullTerminator; - - ++normalized_path_len; - } - - /* Allocate new path. */ - m_base_path_len = normalized_path_len + 1; - m_base_path = static_cast(fs::impl::Allocate(m_base_path_len)); - R_UNLESS(m_base_path != nullptr, fs::ResultAllocationFailureInSubDirectoryFileSystem()); - - /* Copy path in. */ - std::memcpy(m_base_path, normalized_path, normalized_path_len); - m_base_path[normalized_path_len] = fs::StringTraits::NullTerminator; - return ResultSuccess(); - } - - Result SubDirectoryFileSystem::ResolveFullPath(char *out, size_t out_size, const char *relative_path) { - /* Ensure path will fit. */ - R_UNLESS(m_base_path_len + strnlen(relative_path, fs::EntryNameLengthMax + 1) <= out_size, fs::ResultTooLongPath()); - - /* Copy base path. */ - std::memcpy(out, m_base_path, m_base_path_len); - - /* Normalize it. */ - const size_t prefix_size = m_base_path_len - 2; - size_t normalized_len; - return fs::PathNormalizer::Normalize(out + prefix_size, std::addressof(normalized_len), relative_path, out_size - prefix_size, this->IsUncPreserved(), false); - } - -} diff --git a/libraries/libstratosphere/source/fssystem/fssystem_utility.cpp b/libraries/libstratosphere/source/fssystem/fssystem_utility.cpp index 0b91df0a6..9d912ff2c 100644 --- a/libraries/libstratosphere/source/fssystem/fssystem_utility.cpp +++ b/libraries/libstratosphere/source/fssystem/fssystem_utility.cpp @@ -19,39 +19,43 @@ namespace ams::fssystem { namespace { - inline Result EnsureDirectory(fs::fsa::IFileSystem *fs, const char *path) { - R_TRY_CATCH(fs->CreateDirectory(path)) { - R_CATCH(fs::ResultPathAlreadyExists) { /* If path already exists, there's no problem. */ } - } R_END_TRY_CATCH; + Result EnsureDirectoryImpl(fs::fsa::IFileSystem *fs, const fs::Path &path) { + /* Create work path. */ + fs::Path work_path; + R_TRY(work_path.Initialize(path)); - return ResultSuccess(); + /* Create a directory path parser. */ + fs::DirectoryPathParser parser; + R_TRY(parser.Initialize(std::addressof(work_path))); + + bool is_finished; + do { + /* Get the current path. */ + const fs::Path &cur_path = parser.GetCurrentPath(); + + /* Get the entry type for the current path. */ + fs::DirectoryEntryType type; + R_TRY_CATCH(fs->GetEntryType(std::addressof(type), cur_path)) { + R_CATCH(fs::ResultPathNotFound) { + /* The path doesn't exist. We should create it. */ + R_TRY(fs->CreateDirectory(cur_path)); + + /* Get the updated entry type. */ + R_TRY(fs->GetEntryType(std::addressof(type), cur_path)); + } + } R_END_TRY_CATCH; + + /* Verify that the current entry isn't a file. */ + R_UNLESS(type != fs::DirectoryEntryType_File, fs::ResultPathAlreadyExists()); + + /* Advance to the next part of the path. */ + R_TRY(parser.ReadNext(std::addressof(is_finished))); + } while (!is_finished); + + R_SUCCEED(); } - Result EnsureDirectoryRecursivelyImpl(fs::fsa::IFileSystem *fs, const char *path, bool create_last) { - /* Normalize the path. */ - char normalized_path[fs::EntryNameLengthMax + 1]; - size_t normalized_path_len; - R_TRY(fs::PathNormalizer::Normalize(normalized_path, std::addressof(normalized_path_len), path, sizeof(normalized_path))); - - /* Repeatedly call CreateDirectory on each directory leading to the target. */ - for (size_t i = 1; i < normalized_path_len; i++) { - /* If we detect a separator, create the directory. */ - if (fs::PathNormalizer::IsSeparator(normalized_path[i])) { - normalized_path[i] = fs::StringTraits::NullTerminator; - R_TRY(EnsureDirectory(fs, normalized_path)); - normalized_path[i] = fs::StringTraits::DirectorySeparator; - } - } - - /* Create the last directory if requested. */ - if (create_last) { - R_TRY(EnsureDirectory(fs, normalized_path)); - } - - return ResultSuccess(); - } - - Result HasEntry(bool *out, fs::fsa::IFileSystem *fsa, const char *path, fs::DirectoryEntryType type) { + Result HasEntry(bool *out, fs::fsa::IFileSystem *fsa, const fs::Path &path, fs::DirectoryEntryType type) { /* Set out to false initially. */ *out = false; @@ -64,30 +68,27 @@ namespace ams::fssystem { /* We succeeded. */ *out = entry_type == type; - return ResultSuccess(); + R_SUCCEED(); } } - Result CopyFile(fs::fsa::IFileSystem *dst_fs, fs::fsa::IFileSystem *src_fs, const char *dst_parent_path, const char *src_path, const fs::DirectoryEntry *entry, void *work_buf, size_t work_buf_size) { + Result CopyFile(fs::fsa::IFileSystem *dst_fs, fs::fsa::IFileSystem *src_fs, const fs::Path &dst_path, const fs::Path &src_path, void *work_buf, size_t work_buf_size) { /* Open source file. */ std::unique_ptr src_file; R_TRY(src_fs->OpenFile(std::addressof(src_file), src_path, fs::OpenMode_Read)); + /* Get the file size. */ + s64 file_size; + R_TRY(src_file->GetSize(std::addressof(file_size))); + /* Open dst file. */ std::unique_ptr dst_file; - { - char dst_path[fs::EntryNameLengthMax + 1]; - const size_t original_size = static_cast(util::SNPrintf(dst_path, sizeof(dst_path), "%s%s", dst_parent_path, entry->name)); - /* TODO: Error code? N aborts here. */ - AMS_ABORT_UNLESS(original_size < sizeof(dst_path)); - - R_TRY(dst_fs->CreateFile(dst_path, entry->file_size)); - R_TRY(dst_fs->OpenFile(std::addressof(dst_file), dst_path, fs::OpenMode_Write)); - } + R_TRY(dst_fs->CreateFile(dst_path, file_size)); + R_TRY(dst_fs->OpenFile(std::addressof(dst_file), dst_path, fs::OpenMode_Write)); /* Read/Write file in work buffer sized chunks. */ - s64 remaining = entry->file_size; + s64 remaining = file_size; s64 offset = 0; while (remaining > 0) { size_t read_size; @@ -98,59 +99,63 @@ namespace ams::fssystem { offset += read_size; } - return ResultSuccess(); + R_SUCCEED(); } - 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) { - char dst_path_buf[fs::EntryNameLengthMax + 1]; - const size_t original_size = static_cast(util::SNPrintf(dst_path_buf, sizeof(dst_path_buf), "%s", dst_path)); - AMS_ABORT_UNLESS(original_size < sizeof(dst_path_buf)); + Result CopyDirectoryRecursively(fs::fsa::IFileSystem *dst_fs, fs::fsa::IFileSystem *src_fs, const fs::Path &dst_path, const fs::Path &src_path, fs::DirectoryEntry *entry, void *work_buf, size_t work_buf_size) { + /* Set up the destination work path to point at the target directory. */ + fs::Path dst_work_path; + R_TRY(dst_work_path.Initialize(dst_path)); - return IterateDirectoryRecursively(src_fs, src_path, - [&](const char *path, const fs::DirectoryEntry &entry) -> Result { /* On Enter Directory */ - AMS_UNUSED(path); - - /* Update path, create new dir. */ - std::strncat(dst_path_buf, entry.name, sizeof(dst_path_buf) - strnlen(dst_path_buf, sizeof(dst_path_buf) - 1) - 1); - std::strncat(dst_path_buf, "/", sizeof(dst_path_buf) - strnlen(dst_path_buf, sizeof(dst_path_buf) - 1) - 1); - return dst_fs->CreateDirectory(dst_path_buf); - }, - [&](const char *path, const fs::DirectoryEntry &entry) -> Result { /* On Exit Directory */ + /* Iterate, copying files. */ + R_RETURN(IterateDirectoryRecursively(src_fs, src_path, entry, + [&](const fs::Path &path, const fs::DirectoryEntry &entry) -> Result { /* On Enter Directory */ AMS_UNUSED(path, entry); - /* Check we have a parent directory. */ - const size_t len = strnlen(dst_path_buf, sizeof(dst_path_buf)); - R_UNLESS(len >= 2, fs::ResultInvalidPathFormat()); + /* Append the current entry to the dst work path. */ + R_TRY(dst_work_path.AppendChild(entry.name)); - /* Find previous separator, add null terminator */ - char *cur = dst_path_buf + len - 2; - while (!fs::PathNormalizer::IsSeparator(*cur) && cur > dst_path_buf) { - cur--; - } - cur[1] = fs::StringTraits::NullTerminator; - - return ResultSuccess(); + /* Create the directory. */ + R_RETURN(dst_fs->CreateDirectory(dst_work_path)); }, - [&](const char *path, const fs::DirectoryEntry &entry) -> Result { /* On File */ - return CopyFile(dst_fs, src_fs, dst_path_buf, path, std::addressof(entry), work_buf, work_buf_size); + [&](const fs::Path &path, const fs::DirectoryEntry &entry) -> Result { /* On Exit Directory */ + AMS_UNUSED(path, entry); + + /* Remove the directory we're leaving from the dst work path. */ + R_RETURN(dst_work_path.RemoveChild()); + }, + [&](const fs::Path &path, const fs::DirectoryEntry &entry) -> Result { /* On File */ + /* Append the current entry to the dst work path. */ + R_TRY(dst_work_path.AppendChild(entry.name)); + + /* Copy the file. */ + R_TRY(fssystem::CopyFile(dst_fs, src_fs, dst_work_path, path, work_buf, work_buf_size)); + + /* Remove the current entry from the dst work path. */ + R_RETURN(dst_work_path.RemoveChild()); } - ); + )); } - Result HasFile(bool *out, fs::fsa::IFileSystem *fs, const char *path) { - return HasEntry(out, fs, path, fs::DirectoryEntryType_File); + Result HasFile(bool *out, fs::fsa::IFileSystem *fs, const fs::Path &path) { + R_RETURN(HasEntry(out, fs, path, fs::DirectoryEntryType_File)); } - Result HasDirectory(bool *out, fs::fsa::IFileSystem *fs, const char *path) { - return HasEntry(out, fs, path, fs::DirectoryEntryType_Directory); + Result HasDirectory(bool *out, fs::fsa::IFileSystem *fs, const fs::Path &path) { + R_RETURN(HasEntry(out, fs, path, fs::DirectoryEntryType_Directory)); } - Result EnsureDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *path) { - return EnsureDirectoryRecursivelyImpl(fs, path, true); - } + Result EnsureDirectory(fs::fsa::IFileSystem *fs, const fs::Path &path) { + /* First, check if the directory already exists. If it does, we're good to go. */ + fs::DirectoryEntryType type; + R_TRY_CATCH(fs->GetEntryType(std::addressof(type), path)) { + /* If the directory doesn't already exist, we should create it. */ + R_CATCH(fs::ResultPathNotFound) { + R_TRY(EnsureDirectoryImpl(fs, path)); + } + } R_END_TRY_CATCH; - Result EnsureParentDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *path) { - return EnsureDirectoryRecursivelyImpl(fs, path, false); + R_SUCCEED(); } void AddCounter(void *_counter, size_t counter_size, u64 value) { diff --git a/libraries/libstratosphere/source/fssystem/save/fssystem_hierarchical_integrity_verification_storage.cpp b/libraries/libstratosphere/source/fssystem/save/fssystem_hierarchical_integrity_verification_storage.cpp index 60c4c80fb..80f46c398 100644 --- a/libraries/libstratosphere/source/fssystem/save/fssystem_hierarchical_integrity_verification_storage.cpp +++ b/libraries/libstratosphere/source/fssystem/save/fssystem_hierarchical_integrity_verification_storage.cpp @@ -167,7 +167,7 @@ namespace ams::fssystem::save { /* Initialize the top level verification storage. */ { fs::HashSalt mac; - crypto::GenerateHmacSha256Mac(mac.value, sizeof(mac), info.seed.value, sizeof(info.seed), KeyArray[0].key, KeyArray[0].size); + crypto::GenerateHmacSha256(mac.value, sizeof(mac), info.seed.value, sizeof(info.seed), KeyArray[0].key, KeyArray[0].size); m_verify_storages[0].Initialize(storage[HierarchicalStorageInformation::MasterStorage], storage[HierarchicalStorageInformation::Layer1Storage], static_cast(1) << info.info[0].block_order, HashSize, m_buffers->buffers[m_max_layers - 2], hgf, mac, false, storage_type); } @@ -202,7 +202,7 @@ namespace ams::fssystem::save { { fs::SubStorage buffer_storage(std::addressof(m_buffer_storages[level]), 0, info.info[level].size); fs::HashSalt mac; - crypto::GenerateHmacSha256Mac(mac.value, sizeof(mac), info.seed.value, sizeof(info.seed), KeyArray[level + 1].key, KeyArray[level + 1].size); + crypto::GenerateHmacSha256(mac.value, sizeof(mac), info.seed.value, sizeof(info.seed), KeyArray[level + 1].key, KeyArray[level + 1].size); m_verify_storages[level + 1].Initialize(buffer_storage, storage[level + 2], static_cast(1) << info.info[level + 1].block_order, static_cast(1) << info.info[level].block_order, m_buffers->buffers[m_max_layers - 2], hgf, mac, false, storage_type); } @@ -216,7 +216,7 @@ namespace ams::fssystem::save { { fs::SubStorage buffer_storage(std::addressof(m_buffer_storages[level]), 0, info.info[level].size); fs::HashSalt mac; - crypto::GenerateHmacSha256Mac(mac.value, sizeof(mac), info.seed.value, sizeof(info.seed), KeyArray[level + 1].key, KeyArray[level + 1].size); + crypto::GenerateHmacSha256(mac.value, sizeof(mac), info.seed.value, sizeof(info.seed), KeyArray[level + 1].key, KeyArray[level + 1].size); m_verify_storages[level + 1].Initialize(buffer_storage, storage[level + 2], static_cast(1) << info.info[level + 1].block_order, static_cast(1) << info.info[level].block_order, m_buffers->buffers[m_max_layers - 2], hgf, mac, true, storage_type); } diff --git a/libraries/libstratosphere/source/gpio/driver/gpio_driver_service_api.cpp b/libraries/libstratosphere/source/gpio/driver/gpio_driver_service_api.cpp index 3d06b9d99..355b9a94f 100644 --- a/libraries/libstratosphere/source/gpio/driver/gpio_driver_service_api.cpp +++ b/libraries/libstratosphere/source/gpio/driver/gpio_driver_service_api.cpp @@ -44,11 +44,15 @@ namespace ams::gpio::driver { } void SetInitialGpioConfig() { + #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) return board::SetInitialGpioConfig(); + #endif } void SetInitialWakePinConfig() { + #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) return board::SetInitialWakePinConfig(); + #endif } } diff --git a/libraries/libstratosphere/source/gpio/gpio_client_api.cpp b/libraries/libstratosphere/source/gpio/gpio_client_api.cpp index 41e2b9ca9..714e5d201 100644 --- a/libraries/libstratosphere/source/gpio/gpio_client_api.cpp +++ b/libraries/libstratosphere/source/gpio/gpio_client_api.cpp @@ -22,10 +22,12 @@ namespace ams::gpio { constinit os::SdkMutex g_init_mutex; constinit int g_initialize_count = 0; - constinit bool g_remote = false; ams::sf::SharedPointer g_manager; + #if defined(ATMOSPHERE_OS_HORIZON) + constinit bool g_remote = false; ams::sf::UnmanagedServiceObject g_remote_manager_impl; + #endif gpio::sf::IPadSession *GetInterface(GpioPadSession *session) { AMS_ASSERT(session->_session != nullptr); @@ -38,9 +40,13 @@ namespace ams::gpio { std::scoped_lock lk(g_init_mutex); if ((g_initialize_count++) == 0) { + #if defined(ATMOSPHERE_OS_HORIZON) R_ABORT_UNLESS(::gpioInitialize()); g_manager = g_remote_manager_impl.GetShared(); g_remote = true; + #else + AMS_ABORT("TODO"); + #endif } } @@ -60,9 +66,13 @@ namespace ams::gpio { if ((--g_initialize_count) == 0) { g_manager = nullptr; + #if defined(ATMOSPHERE_OS_HORIZON) if (g_remote) { ::gpioExit(); } + #else + AMS_ABORT("TODO"); + #endif } } diff --git a/libraries/libstratosphere/source/gpio/gpio_remote_manager_impl.cpp b/libraries/libstratosphere/source/gpio/gpio_remote_manager_impl.cpp index 425c658b8..351bfbbdc 100644 --- a/libraries/libstratosphere/source/gpio/gpio_remote_manager_impl.cpp +++ b/libraries/libstratosphere/source/gpio/gpio_remote_manager_impl.cpp @@ -18,6 +18,7 @@ namespace ams::gpio { + #if defined(ATMOSPHERE_OS_HORIZON) namespace { struct GpioRemoteManagerTag; @@ -48,5 +49,6 @@ namespace ams::gpio { out.SetValue(RemoteObjectFactory::CreateSharedEmplaced(p)); return ResultSuccess(); } + #endif } diff --git a/libraries/libstratosphere/source/gpio/gpio_remote_manager_impl.hpp b/libraries/libstratosphere/source/gpio/gpio_remote_manager_impl.hpp index 768f6a598..c29777e93 100644 --- a/libraries/libstratosphere/source/gpio/gpio_remote_manager_impl.hpp +++ b/libraries/libstratosphere/source/gpio/gpio_remote_manager_impl.hpp @@ -19,6 +19,7 @@ namespace ams::gpio { + #if defined(ATMOSPHERE_OS_HORIZON) class RemoteManagerImpl { public: RemoteManagerImpl() { /* ... */ } @@ -82,5 +83,6 @@ namespace ams::gpio { }; static_assert(gpio::sf::IsIManager); + #endif } diff --git a/libraries/libstratosphere/source/gpio/gpio_remote_pad_session_impl.hpp b/libraries/libstratosphere/source/gpio/gpio_remote_pad_session_impl.hpp index ce7d4815b..f4931aa18 100644 --- a/libraries/libstratosphere/source/gpio/gpio_remote_pad_session_impl.hpp +++ b/libraries/libstratosphere/source/gpio/gpio_remote_pad_session_impl.hpp @@ -18,6 +18,7 @@ namespace ams::gpio { + #if defined(ATMOSPHERE_OS_HORIZON) class RemotePadSessionImpl { private: ::GpioPadSession m_srv; @@ -111,5 +112,6 @@ namespace ams::gpio { } }; static_assert(gpio::sf::IsIPadSession); + #endif } diff --git a/libraries/libstratosphere/source/hid/hid_api.cpp b/libraries/libstratosphere/source/hid/hid_api.cpp index 954f9f4b1..b038acf0e 100644 --- a/libraries/libstratosphere/source/hid/hid_api.cpp +++ b/libraries/libstratosphere/source/hid/hid_api.cpp @@ -17,6 +17,7 @@ namespace ams::hid { + #if defined(ATMOSPHERE_OS_HORIZON) namespace { /* Global lock. */ @@ -87,5 +88,6 @@ namespace ams::hid { return ResultSuccess(); } + #endif } diff --git a/libraries/libstratosphere/source/hos/hos_stratosphere_api.cpp b/libraries/libstratosphere/source/hos/hos_stratosphere_api.cpp index aa4446b76..2a54ef06b 100644 --- a/libraries/libstratosphere/source/hos/hos_stratosphere_api.cpp +++ b/libraries/libstratosphere/source/hos/hos_stratosphere_api.cpp @@ -18,10 +18,11 @@ namespace ams::os { - void InitializeForStratosphereInternal(); + void Initialize(); } +#if defined(ATMOSPHERE_OS_HORIZON) extern "C" { /* Provide libnx address space allocation shim. */ @@ -30,6 +31,7 @@ extern "C" { } } +#endif namespace ams::hos { @@ -53,13 +55,15 @@ namespace ams::hos { void InitializeForStratosphere() { /* Initialize the global os resource managers. This *must* be done before anything else in stratosphere. */ - os::InitializeForStratosphereInternal(); + os::Initialize(); /* Initialize hos::Version API. */ hos::InitializeVersionInternal(CanAllowTemporaryApproximateVersion()); + #if defined(ATMOSPHERE_OS_HORIZON) /* Check that we're running under mesosphere. */ AMS_ABORT_UNLESS(IsUnitTestProgramForSetVersion() || svc::IsKernelMesosphere()); + #endif } } diff --git a/libraries/libstratosphere/source/hos/hos_version_api.cpp b/libraries/libstratosphere/source/hos/hos_version_api.cpp index 7abf07df0..128025352 100644 --- a/libraries/libstratosphere/source/hos/hos_version_api.cpp +++ b/libraries/libstratosphere/source/hos/hos_version_api.cpp @@ -33,6 +33,7 @@ namespace ams::hos { return ResultSuccess(); } + #if defined(ATMOSPHERE_OS_HORIZON) Result GetApproximateExosphereApiInfo(exosphere::ApiInfo *out) { u64 exosphere_cfg; @@ -43,20 +44,28 @@ namespace ams::hos { *out = { exosphere_cfg }; return ResultSuccess(); } + #endif exosphere::ApiInfo GetExosphereApiInfo(bool allow_approximate) { exosphere::ApiInfo info; + #if defined(ATMOSPHERE_OS_HORIZON) while (true) { if (R_SUCCEEDED(GetExosphereApiInfo(std::addressof(info)))) { - return info; + break; } if (allow_approximate && R_SUCCEEDED(GetApproximateExosphereApiInfo(std::addressof(info)))) { - return info; + break; } svc::SleepThread(TimeSpan::FromMilliSeconds(25).GetNanoSeconds()); } + #else + AMS_UNUSED(allow_approximate); + R_ABORT_UNLESS(GetExosphereApiInfo(std::addressof(info))); + #endif + + return info; } } @@ -118,6 +127,8 @@ namespace ams::hos { } } + + #if defined(ATMOSPHERE_OS_HORIZON) /* Set the version for libnx. */ { const u32 major = (static_cast(current) >> 24) & 0xFF; @@ -125,6 +136,7 @@ namespace ams::hos { const u32 micro = (static_cast(current) >> 8) & 0xFF; hosversionSet((BIT(31)) | (MAKEHOSVERSION(major, minor, micro))); } + #endif } ::ams::hos::Version GetVersion() { diff --git a/libraries/libstratosphere/source/hos/hos_version_api_private.cpp b/libraries/libstratosphere/source/hos/hos_version_api_private.cpp index d34fcdb8a..79afeb04d 100644 --- a/libraries/libstratosphere/source/hos/hos_version_api_private.cpp +++ b/libraries/libstratosphere/source/hos/hos_version_api_private.cpp @@ -19,6 +19,7 @@ namespace ams::hos { namespace { + #if defined(ATMOSPHERE_OS_HORIZON) settings::FirmwareVersion GetSettingsFirmwareVersion() { /* Mount the system version title. */ R_ABORT_UNLESS(ams::fs::MountSystemData("sysver", ncm::SystemDataId::SystemVersion)); @@ -35,12 +36,14 @@ namespace ams::hos { return firmware_version; } + #endif } void InitializeVersionInternal(bool allow_approximate); void SetNonApproximateVersionInternal() { + #if defined(ATMOSPHERE_OS_HORIZON) /* Get the settings . */ const auto firmware_version = GetSettingsFirmwareVersion(); @@ -49,6 +52,7 @@ namespace ams::hos { /* Update our own version value. */ InitializeVersionInternal(false); + #endif } } diff --git a/libraries/libstratosphere/source/hos/hos_version_api_weak_for_unit_test.cpp b/libraries/libstratosphere/source/hos/hos_version_api_weak_for_unit_test.cpp index 8f79a62be..a1797f026 100644 --- a/libraries/libstratosphere/source/hos/hos_version_api_weak_for_unit_test.cpp +++ b/libraries/libstratosphere/source/hos/hos_version_api_weak_for_unit_test.cpp @@ -18,7 +18,11 @@ namespace ams::hos { WEAK_SYMBOL bool IsUnitTestProgramForSetVersion() { + #if defined(ATMOSPHERE_OS_HORIZON) return false; + #else + return true; + #endif } } diff --git a/libraries/libstratosphere/source/htc/server/driver/htc_htclow_driver.cpp b/libraries/libstratosphere/source/htc/server/driver/htc_htclow_driver.cpp index 48822f71d..fb8209916 100644 --- a/libraries/libstratosphere/source/htc/server/driver/htc_htclow_driver.cpp +++ b/libraries/libstratosphere/source/htc/server/driver/htc_htclow_driver.cpp @@ -75,7 +75,7 @@ namespace ams::htc::server::driver { R_UNLESS(!m_disconnection_emulation_enabled, htclow::ResultConnectionFailure()); /* Begin connecting. */ - u32 task_id; + u32 task_id{}; R_TRY(m_manager->ConnectBegin(std::addressof(task_id), GetHtclowChannel(channel, m_module_id))); /* Wait for the task to complete. */ @@ -104,7 +104,7 @@ namespace ams::htc::server::driver { size_t sent; for (sent = 0; sent < static_cast(src_size); sent += cur_send) { /* Begin sending. */ - u32 task_id; + u32 task_id{}; R_TRY(m_manager->SendBegin(std::addressof(task_id), std::addressof(cur_send), static_cast(src) + sent, static_cast(src_size) - sent, GetHtclowChannel(channel, m_module_id))); /* Wait for the task to complete. */ @@ -125,7 +125,7 @@ namespace ams::htc::server::driver { const bool blocking = option != htclow::ReceiveOption_NonBlocking; /* Begin receiving. */ - u32 task_id; + u32 task_id{}; R_TRY(m_manager->ReceiveBegin(std::addressof(task_id), GetHtclowChannel(channel, m_module_id), blocking ? 1 : 0)); /* Wait for the task to complete. */ diff --git a/libraries/libstratosphere/source/htc/server/htc_htcmisc_hipc_server.cpp b/libraries/libstratosphere/source/htc/server/htc_htcmisc_hipc_server.cpp index 41b04c9a0..9c875f998 100644 --- a/libraries/libstratosphere/source/htc/server/htc_htcmisc_hipc_server.cpp +++ b/libraries/libstratosphere/source/htc/server/htc_htcmisc_hipc_server.cpp @@ -28,7 +28,7 @@ namespace ams::htc::server { using ServerOptions = sf::hipc::DefaultServerManagerOptions; using ServerManager = sf::hipc::ServerManager; - constinit util::TypedStorage g_server_manager_storage; + constinit util::TypedStorage g_server_manager_storage = {}; constinit ServerManager *g_server_manager = nullptr; constinit HtcmiscImpl *g_misc_impl = nullptr; diff --git a/libraries/libstratosphere/source/htc/server/htc_htcmisc_impl.cpp b/libraries/libstratosphere/source/htc/server/htc_htcmisc_impl.cpp index 07f89cbaa..1923c7151 100644 --- a/libraries/libstratosphere/source/htc/server/htc_htcmisc_impl.cpp +++ b/libraries/libstratosphere/source/htc/server/htc_htcmisc_impl.cpp @@ -82,7 +82,7 @@ namespace ams::htc::server { Result HtcmiscImpl::GetEnvironmentVariable(size_t *out_size, char *dst, size_t dst_size, const char *name, size_t name_size) { /* Begin the task. */ - u32 task_id; + u32 task_id{}; R_TRY(m_rpc_client.Begin(std::addressof(task_id), name, name_size)); /* Wait for the task to complete. */ @@ -96,7 +96,7 @@ namespace ams::htc::server { Result HtcmiscImpl::GetEnvironmentVariableLength(size_t *out_size, const char *name, size_t name_size) { /* Begin the task. */ - u32 task_id; + u32 task_id{}; R_TRY(m_rpc_client.Begin(std::addressof(task_id), name, name_size)); /* Wait for the task to complete. */ @@ -110,7 +110,7 @@ namespace ams::htc::server { Result HtcmiscImpl::RunOnHostBegin(u32 *out_task_id, os::NativeHandle *out_event, const char *args, size_t args_size) { /* Begin the task. */ - u32 task_id; + u32 task_id{}; R_TRY(m_rpc_client.Begin(std::addressof(task_id), args, args_size)); /* Detach the task. */ diff --git a/libraries/libstratosphere/source/htc/server/rpc/htc_htcmisc_rpc_tasks.hpp b/libraries/libstratosphere/source/htc/server/rpc/htc_htcmisc_rpc_tasks.hpp index 3d70c6d75..44e409c4e 100644 --- a/libraries/libstratosphere/source/htc/server/rpc/htc_htcmisc_rpc_tasks.hpp +++ b/libraries/libstratosphere/source/htc/server/rpc/htc_htcmisc_rpc_tasks.hpp @@ -59,7 +59,7 @@ namespace ams::htc::server::rpc { HtcmiscPacketCategory category; HtcmiscPacketType type; s64 body_size; - u32 task_id; + u32 task_id{}; u64 params[5]; char data[]; }; diff --git a/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_client.cpp b/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_client.cpp index ec67205de..b50846016 100644 --- a/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_client.cpp +++ b/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_client.cpp @@ -287,7 +287,7 @@ namespace ams::htc::server::rpc { while (true) { /* Get a task. */ Task *task; - u32 task_id; + u32 task_id{}; PacketCategory category; do { /* Dequeue a task. */ diff --git a/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_client.hpp b/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_client.hpp index dd9fafdff..8c3d35b75 100644 --- a/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_client.hpp +++ b/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_client.hpp @@ -112,7 +112,7 @@ namespace ams::htc::server::rpc { std::scoped_lock lk(m_mutex); /* Allocate a free task id. */ - u32 task_id; + u32 task_id{}; R_TRY(m_task_id_free_list.Allocate(std::addressof(task_id))); /* Create the new task. */ diff --git a/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_task_table.hpp b/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_task_table.hpp index 47789594a..62637b490 100644 --- a/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_task_table.hpp +++ b/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_task_table.hpp @@ -34,11 +34,17 @@ namespace ams::htc::server::rpc { /* htcs::ReceiveSmallTask/htcs::ReceiveSendTask are the largest tasks, containing an inline 0xE000 buffer. */ /* We allow for ~0x100 task overhead from the additional events those contain. */ /* NOTE: Nintendo hardcodes a maximum size of 0xE1D8, despite SendSmallTask being 0xE098 as of latest check. */ + #if defined(ATMOSPHERE_OS_HORIZON) static constexpr size_t MaxTaskSize = 0xE100; + #elif defined(ATMOSPHERE_OS_MACOS) + static constexpr size_t MaxTaskSize = 0xE400; + #else + static constexpr size_t MaxTaskSize = 0xE1D8; + #endif using TaskStorage = typename std::aligned_storage::type; private: - bool m_valid[MaxRpcCount]; - TaskStorage m_storages[MaxRpcCount]; + bool m_valid[MaxRpcCount]{}; + TaskStorage m_storages[MaxRpcCount]{}; private: template ALWAYS_INLINE T *GetPointer(u32 index) { diff --git a/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_tasks.hpp b/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_tasks.hpp index 2ecb519cf..817072b67 100644 --- a/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_tasks.hpp +++ b/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_tasks.hpp @@ -32,7 +32,7 @@ namespace ams::htc::server::rpc { PacketCategory category; u16 type; s64 body_size; - u32 task_id; + u32 task_id{}; u64 params[5]; char data[]; }; diff --git a/libraries/libstratosphere/source/htcfs/htcfs_client.cpp b/libraries/libstratosphere/source/htcfs/htcfs_client.cpp index c42516ee8..377b68010 100644 --- a/libraries/libstratosphere/source/htcfs/htcfs_client.cpp +++ b/libraries/libstratosphere/source/htcfs/htcfs_client.cpp @@ -20,8 +20,8 @@ namespace ams::htcfs { namespace { - constinit util::TypedStorage g_client_storage; - [[maybe_unused]] constinit bool g_initialized; + constinit util::TypedStorage g_client_storage = {}; + [[maybe_unused]] constinit bool g_initialized = false; } diff --git a/libraries/libstratosphere/source/htcfs/htcfs_file_system_service_object.cpp b/libraries/libstratosphere/source/htcfs/htcfs_file_system_service_object.cpp index 93489a74f..18bde1fd6 100644 --- a/libraries/libstratosphere/source/htcfs/htcfs_file_system_service_object.cpp +++ b/libraries/libstratosphere/source/htcfs/htcfs_file_system_service_object.cpp @@ -73,7 +73,7 @@ namespace ams::htcfs { R_TRY(ConvertOpenMode(std::addressof(fs_open_mode), open_mode)); /* Open the file. */ - s32 handle; + s32 handle = -1; R_TRY(htcfs::GetClient().OpenFile(std::addressof(handle), path.str, fs_open_mode, case_sensitive)); /* Set the output file. */ @@ -120,7 +120,7 @@ namespace ams::htcfs { R_UNLESS(IsValidPath(path), htcfs::ResultInvalidArgument()); /* Open the directory. */ - s32 handle; + s32 handle = -1; R_TRY(htcfs::GetClient().OpenDirectory(std::addressof(handle), path.str, static_cast(open_mode), case_sensitive)); /* Set the output directory. */ diff --git a/libraries/libstratosphere/source/htclow/driver/htclow_usb_impl.cpp b/libraries/libstratosphere/source/htclow/driver/htclow_usb_impl.cpp index 905baef45..4ed2b0864 100644 --- a/libraries/libstratosphere/source/htclow/driver/htclow_usb_impl.cpp +++ b/libraries/libstratosphere/source/htclow/driver/htclow_usb_impl.cpp @@ -303,11 +303,11 @@ namespace ams::htclow::driver { R_ABORT_UNLESS(g_ds_client.GetState(std::addressof(usb_state))); switch (usb_state) { - case UsbState_Detached: - case UsbState_Suspended: + case usb::UsbState_Detached: + case usb::UsbState_Suspended: InvokeAvailabilityChangeCallback(UsbAvailability_Unavailable); break; - case UsbState_Configured: + case usb::UsbState_Configured: InvokeAvailabilityChangeCallback(UsbAvailability_Available); break; default: diff --git a/libraries/libstratosphere/source/htclow/htclow_channel.cpp b/libraries/libstratosphere/source/htclow/htclow_channel.cpp index 4f3251eb9..1069ce88c 100644 --- a/libraries/libstratosphere/source/htclow/htclow_channel.cpp +++ b/libraries/libstratosphere/source/htclow/htclow_channel.cpp @@ -49,7 +49,7 @@ namespace ams::htclow { const auto channel = impl::ConvertChannelType(m_channel); /* Begin the flush. */ - u32 task_id; + u32 task_id{}; R_TRY(m_manager->ConnectBegin(std::addressof(task_id), channel)); /* Wait for the task to finish. */ @@ -61,7 +61,7 @@ namespace ams::htclow { Result Channel::Flush() { /* Begin the flush. */ - u32 task_id; + u32 task_id{}; R_TRY(m_manager->FlushBegin(std::addressof(task_id), impl::ConvertChannelType(m_channel))); /* Wait for the task to finish. */ @@ -128,7 +128,7 @@ namespace ams::htclow { AMS_ASSERT(util::IsIntValueRepresentable(size - total_sent)); /* Begin the send. */ - u32 task_id; + u32 task_id{}; const auto begin_result = m_manager->SendBegin(std::addressof(task_id), std::addressof(cur_sent), static_cast(src) + total_sent, size - total_sent, channel); if (R_FAILED(begin_result)) { if (total_sent != 0) { @@ -192,7 +192,7 @@ namespace ams::htclow { const bool blocking = option != ReceiveOption_NonBlocking; /* Begin the receive. */ - u32 task_id; + u32 task_id{}; R_TRY(m_manager->ReceiveBegin(std::addressof(task_id), channel, blocking ? 1 : 0)); /* Wait for the task to finish. */ @@ -214,7 +214,7 @@ namespace ams::htclow { const auto channel = impl::ConvertChannelType(m_channel); /* Begin the wait. */ - u32 task_id; + u32 task_id{}; R_TRY(m_manager->WaitReceiveBegin(std::addressof(task_id), channel, size)); diff --git a/libraries/libstratosphere/source/htclow/mux/htclow_mux_channel_impl.cpp b/libraries/libstratosphere/source/htclow/mux/htclow_mux_channel_impl.cpp index 2b53b4948..e1fa8ab65 100644 --- a/libraries/libstratosphere/source/htclow/mux/htclow_mux_channel_impl.cpp +++ b/libraries/libstratosphere/source/htclow/mux/htclow_mux_channel_impl.cpp @@ -237,7 +237,7 @@ namespace ams::htclow::mux { m_state_machine->SetConnecting(m_channel); /* Allocate a task. */ - u32 task_id; + u32 task_id{}; R_TRY(m_task_manager->AllocateTask(std::addressof(task_id), m_channel)); /* Configure the task. */ @@ -295,7 +295,7 @@ namespace ams::htclow::mux { R_TRY(this->CheckState({ChannelState_Connected})); /* Allocate a task. */ - u32 task_id; + u32 task_id{}; R_TRY(m_task_manager->AllocateTask(std::addressof(task_id), m_channel)); /* Configure the task. */ @@ -316,7 +316,7 @@ namespace ams::htclow::mux { R_TRY(this->CheckState({ChannelState_Connected, ChannelState_Disconnected})); /* Allocate a task. */ - u32 task_id; + u32 task_id{}; R_TRY(m_task_manager->AllocateTask(std::addressof(task_id), m_channel)); /* Configure the task. */ @@ -389,7 +389,7 @@ namespace ams::htclow::mux { R_TRY(this->CheckState({ChannelState_Connected})); /* Allocate a task. */ - u32 task_id; + u32 task_id{}; R_TRY(m_task_manager->AllocateTask(std::addressof(task_id), m_channel)); /* Send the data. */ diff --git a/libraries/libstratosphere/source/htclow/mux/htclow_mux_send_buffer.cpp b/libraries/libstratosphere/source/htclow/mux/htclow_mux_send_buffer.cpp index b8f8c96d0..24ee42718 100644 --- a/libraries/libstratosphere/source/htclow/mux/htclow_mux_send_buffer.cpp +++ b/libraries/libstratosphere/source/htclow/mux/htclow_mux_send_buffer.cpp @@ -93,7 +93,7 @@ namespace ams::htclow::mux { /* Determine the sendable size. */ const auto offset = total_send_size - ring_buffer_data_size; - const auto sendable_size = m_flow_control_enabled ? std::min(share - offset, ring_buffer_data_size) : ring_buffer_data_size; + const auto sendable_size = m_flow_control_enabled ? std::min(share - offset, ring_buffer_data_size) : ring_buffer_data_size; if (sendable_size == 0) { return false; } diff --git a/libraries/libstratosphere/source/htclow/mux/htclow_mux_task_manager.cpp b/libraries/libstratosphere/source/htclow/mux/htclow_mux_task_manager.cpp index f2083a936..10d4e8036 100644 --- a/libraries/libstratosphere/source/htclow/mux/htclow_mux_task_manager.cpp +++ b/libraries/libstratosphere/source/htclow/mux/htclow_mux_task_manager.cpp @@ -20,7 +20,7 @@ namespace ams::htclow::mux { os::EventType *TaskManager::GetTaskEvent(u32 task_id) { /* Check pre-conditions. */ - AMS_ASSERT(0 <= task_id && task_id < MaxTaskCount); + AMS_ASSERT(task_id < MaxTaskCount); AMS_ASSERT(m_valid[task_id]); return std::addressof(m_tasks[task_id].event); @@ -28,7 +28,7 @@ namespace ams::htclow::mux { EventTrigger TaskManager::GetTrigger(u32 task_id) { /* Check pre-conditions. */ - AMS_ASSERT(0 <= task_id && task_id < MaxTaskCount); + AMS_ASSERT(task_id < MaxTaskCount); AMS_ASSERT(m_valid[task_id]); return m_tasks[task_id].event_trigger; @@ -61,7 +61,7 @@ namespace ams::htclow::mux { void TaskManager::FreeTask(u32 task_id) { /* Check pre-conditions. */ - AMS_ASSERT(0 <= task_id && task_id < MaxTaskCount); + AMS_ASSERT(task_id < MaxTaskCount); /* Invalidate the task. */ if (m_valid[task_id]) { @@ -72,7 +72,7 @@ namespace ams::htclow::mux { void TaskManager::ConfigureConnectTask(u32 task_id) { /* Check pre-conditions. */ - AMS_ASSERT(0 <= task_id && task_id < MaxTaskCount); + AMS_ASSERT(task_id < MaxTaskCount); AMS_ASSERT(m_valid[task_id]); /* Set the task type. */ @@ -81,7 +81,7 @@ namespace ams::htclow::mux { void TaskManager::ConfigureFlushTask(u32 task_id) { /* Check pre-conditions. */ - AMS_ASSERT(0 <= task_id && task_id < MaxTaskCount); + AMS_ASSERT(task_id < MaxTaskCount); AMS_ASSERT(m_valid[task_id]); /* Set the task type. */ @@ -90,7 +90,7 @@ namespace ams::htclow::mux { void TaskManager::ConfigureReceiveTask(u32 task_id, size_t size) { /* Check pre-conditions. */ - AMS_ASSERT(0 <= task_id && task_id < MaxTaskCount); + AMS_ASSERT(task_id < MaxTaskCount); AMS_ASSERT(m_valid[task_id]); /* Set the task type. */ @@ -102,7 +102,7 @@ namespace ams::htclow::mux { void TaskManager::ConfigureSendTask(u32 task_id) { /* Check pre-conditions. */ - AMS_ASSERT(0 <= task_id && task_id < MaxTaskCount); + AMS_ASSERT(task_id < MaxTaskCount); AMS_ASSERT(m_valid[task_id]); /* Set the task type. */ diff --git a/libraries/libstratosphere/source/htcs/client/htcs_session.cpp b/libraries/libstratosphere/source/htcs/client/htcs_session.os.horizon.cpp similarity index 100% rename from libraries/libstratosphere/source/htcs/client/htcs_session.cpp rename to libraries/libstratosphere/source/htcs/client/htcs_session.os.horizon.cpp diff --git a/libraries/libstratosphere/source/htcs/client/htcs_session.os.windows.cpp b/libraries/libstratosphere/source/htcs/client/htcs_session.os.windows.cpp new file mode 100644 index 000000000..55d5f0ed1 --- /dev/null +++ b/libraries/libstratosphere/source/htcs/client/htcs_session.os.windows.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 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 "htcs_session.hpp" + +namespace ams::htcs::client { + + void InitializeSessionManager(tma::IHtcsManager **out_manager, tma::IHtcsManager **out_monitor, u32 num_sessions) { + AMS_UNUSED(out_manager, out_monitor, num_sessions); + AMS_ABORT("TODO"); + } + + void FinalizeSessionManager() { + AMS_ABORT("TODO"); + } + +} diff --git a/libraries/libstratosphere/source/htcs/htcs_socket.cpp b/libraries/libstratosphere/source/htcs/htcs_socket.cpp index 06a70710b..8b28b1a17 100644 --- a/libraries/libstratosphere/source/htcs/htcs_socket.cpp +++ b/libraries/libstratosphere/source/htcs/htcs_socket.cpp @@ -30,7 +30,7 @@ namespace ams::htcs { constinit void *g_buffer = nullptr; constinit size_t g_buffer_size = 0; - constinit os::TlsSlot g_tls_slot; + constinit os::TlsSlot g_tls_slot = {}; constinit tma::IHtcsManager *g_manager = nullptr; constinit tma::IHtcsManager *g_monitor = nullptr; diff --git a/libraries/libstratosphere/source/htcs/impl/htcs_manager_impl.cpp b/libraries/libstratosphere/source/htcs/impl/htcs_manager_impl.cpp index 3a60aec93..06dba184f 100644 --- a/libraries/libstratosphere/source/htcs/impl/htcs_manager_impl.cpp +++ b/libraries/libstratosphere/source/htcs/impl/htcs_manager_impl.cpp @@ -100,7 +100,7 @@ namespace ams::htcs::impl { Result HtcsManagerImpl::SendStart(u32 *out_task_id, os::NativeHandle *out_handle, const char *buffer, s64 size, s32 desc, s32 flags) { /* Start the send. */ - u32 task_id; + u32 task_id{}; os::NativeHandle handle; R_TRY(m_service.SendSmallStart(std::addressof(task_id), std::addressof(handle), desc, size, flags)); @@ -158,7 +158,7 @@ namespace ams::htcs::impl { Result HtcsManagerImpl::StartSelect(u32 *out_task_id, os::NativeHandle *out_handle, Span read_handles, Span write_handles, Span exception_handles, s64 tv_sec, s64 tv_usec) { /* Start the select. */ - u32 task_id; + u32 task_id{}; os::NativeHandle handle = os::InvalidNativeHandle; const Result result = m_service.SelectStart(std::addressof(task_id), std::addressof(handle), read_handles, write_handles, exception_handles, tv_sec, tv_usec); diff --git a/libraries/libstratosphere/source/htcs/impl/htcs_service.cpp b/libraries/libstratosphere/source/htcs/impl/htcs_service.cpp index fb1ec8ee1..7e5d39eea 100644 --- a/libraries/libstratosphere/source/htcs/impl/htcs_service.cpp +++ b/libraries/libstratosphere/source/htcs/impl/htcs_service.cpp @@ -29,7 +29,7 @@ namespace ams::htcs::impl { m_driver->SetDisconnectionEmulationEnabled(enable_disconnection_emulation); /* Begin the task. */ - u32 task_id; + u32 task_id{}; R_TRY(m_rpc_client->Begin(std::addressof(task_id))); /* Wait for the task to complete. */ @@ -48,7 +48,7 @@ namespace ams::htcs::impl { Result HtcsService::DestroySocket(s32 desc) { /* Begin the task. */ - u32 task_id; + u32 task_id{}; R_TRY(m_rpc_client->Begin(std::addressof(task_id), desc)); /* Wait for the task to complete. */ @@ -71,7 +71,7 @@ namespace ams::htcs::impl { R_UNLESS(IsValidName(address.port_name), htcs::ResultInvalidArgument()); /* Begin the task. */ - u32 task_id; + u32 task_id{}; R_TRY(m_rpc_client->Begin(std::addressof(task_id), desc, address.peer_name, address.port_name)); /* Wait for the task to complete. */ @@ -93,7 +93,7 @@ namespace ams::htcs::impl { R_UNLESS(IsValidName(address.port_name), htcs::ResultInvalidArgument()); /* Begin the task. */ - u32 task_id; + u32 task_id{}; R_TRY(m_rpc_client->Begin(std::addressof(task_id), desc, address.peer_name, address.port_name)); /* Wait for the task to complete. */ @@ -110,7 +110,7 @@ namespace ams::htcs::impl { Result HtcsService::Listen(s32 *out_err, s32 desc, s32 backlog_count) { /* Begin the task. */ - u32 task_id; + u32 task_id{}; R_TRY(m_rpc_client->Begin(std::addressof(task_id), desc, backlog_count)); /* Wait for the task to complete. */ @@ -127,7 +127,7 @@ namespace ams::htcs::impl { Result HtcsService::Receive(s32 *out_err, s64 *out_size, char *buffer, s64 size, s32 desc, s32 flags) { /* Begin the task. */ - u32 task_id; + u32 task_id{}; R_TRY(m_rpc_client->Begin(std::addressof(task_id), desc, size, static_cast(flags))); /* Wait for the task to complete. */ @@ -141,7 +141,7 @@ namespace ams::htcs::impl { Result HtcsService::Send(s32 *out_err, s64 *out_size, const char *buffer, s64 size, s32 desc, s32 flags) { /* Begin the task. */ - u32 task_id; + u32 task_id{}; R_TRY(m_rpc_client->Begin(std::addressof(task_id), desc, size, static_cast(flags))); /* Send the data. */ @@ -162,7 +162,7 @@ namespace ams::htcs::impl { Result HtcsService::Shutdown(s32 *out_err, s32 desc, s32 how) { /* Begin the task. */ - u32 task_id; + u32 task_id{}; R_TRY(m_rpc_client->Begin(std::addressof(task_id), desc, static_cast(how))); /* Wait for the task to complete. */ @@ -179,7 +179,7 @@ namespace ams::htcs::impl { Result HtcsService::Fcntl(s32 *out_err, s32 *out_res, s32 desc, s32 command, s32 value) { /* Begin the task. */ - u32 task_id; + u32 task_id{}; R_TRY(m_rpc_client->Begin(std::addressof(task_id), desc, command, value)); /* Wait for the task to complete. */ @@ -198,7 +198,7 @@ namespace ams::htcs::impl { Result HtcsService::AcceptStart(u32 *out_task_id, os::NativeHandle *out_handle, s32 desc) { /* Begin the task. */ - u32 task_id; + u32 task_id{}; R_TRY(m_rpc_client->Begin(std::addressof(task_id), desc)); /* Detach the task. */ @@ -224,7 +224,7 @@ namespace ams::htcs::impl { Result HtcsService::ReceiveSmallStart(u32 *out_task_id, os::NativeHandle *out_handle, s64 size, s32 desc, s32 flags) { /* Begin the task. */ - u32 task_id; + u32 task_id{}; R_TRY(m_rpc_client->Begin(std::addressof(task_id), desc, size, static_cast(flags))); /* Detach the task. */ @@ -251,7 +251,7 @@ namespace ams::htcs::impl { Result HtcsService::SendSmallStart(u32 *out_task_id, os::NativeHandle *out_handle, s32 desc, s64 size, s32 flags) { /* Begin the task. */ - u32 task_id; + u32 task_id{}; R_TRY(m_rpc_client->Begin(std::addressof(task_id), desc, size, static_cast(flags))); /* Detach the task. */ @@ -287,7 +287,7 @@ namespace ams::htcs::impl { Result HtcsService::SendStart(u32 *out_task_id, os::NativeHandle *out_handle, s32 desc, s64 size, s32 flags) { /* Begin the task. */ - u32 task_id; + u32 task_id{}; R_TRY(m_rpc_client->Begin(std::addressof(task_id), desc, size, static_cast(flags))); /* Detach the task. */ @@ -333,7 +333,7 @@ namespace ams::htcs::impl { Result HtcsService::ReceiveStart(u32 *out_task_id, os::NativeHandle *out_handle, s64 size, s32 desc, s32 flags) { /* Begin the task. */ - u32 task_id; + u32 task_id{}; R_TRY(m_rpc_client->Begin(std::addressof(task_id), desc, size, static_cast(flags))); /* Detach the task. */ @@ -348,8 +348,8 @@ namespace ams::htcs::impl { R_TRY(m_rpc_client->VerifyTaskIdWithHandle(task_id, desc)); /* Get the result. */ - htcs::SocketError err; - s64 recv_size; + htcs::SocketError err{}; + s64 recv_size{}; const Result result = m_rpc_client->GetResult(task_id, std::addressof(err), std::addressof(recv_size)); if (R_FAILED(result) || err != HTCS_ENONE) { /* Finish the task. */ @@ -385,7 +385,7 @@ namespace ams::htcs::impl { Result HtcsService::SelectStart(u32 *out_task_id, os::NativeHandle *out_handle, Span read_handles, Span write_handles, Span exception_handles, s64 tv_sec, s64 tv_usec) { /* Begin the task. */ - u32 task_id; + u32 task_id{}; R_TRY(m_rpc_client->Begin(std::addressof(task_id), read_handles, write_handles, exception_handles, tv_sec, tv_usec)); /* Detach the task. */ diff --git a/libraries/libstratosphere/source/htcs/impl/rpc/htcs_rpc_select_task.cpp b/libraries/libstratosphere/source/htcs/impl/rpc/htcs_rpc_select_task.cpp index eef41bb54..9872a2456 100644 --- a/libraries/libstratosphere/source/htcs/impl/rpc/htcs_rpc_select_task.cpp +++ b/libraries/libstratosphere/source/htcs/impl/rpc/htcs_rpc_select_task.cpp @@ -23,9 +23,9 @@ namespace ams::htcs::impl::rpc { R_UNLESS(this->IsValid(), htcs::ResultInvalidTask()); /* Sanity check the spans. */ - AMS_ASSERT(0 <= read_handles.size() && read_handles.size() < static_cast(SocketCountMax)); - AMS_ASSERT(0 <= write_handles.size() && write_handles.size() < static_cast(SocketCountMax)); - AMS_ASSERT(0 <= exception_handles.size() && exception_handles.size() < static_cast(SocketCountMax)); + AMS_ASSERT(read_handles.size() < static_cast(SocketCountMax)); + AMS_ASSERT(write_handles.size() < static_cast(SocketCountMax)); + AMS_ASSERT(exception_handles.size() < static_cast(SocketCountMax)); /* Set our arguments. */ m_read_handle_count = static_cast(read_handles.size()); diff --git a/libraries/libstratosphere/source/htcs/impl/rpc/htcs_rpc_tasks.hpp b/libraries/libstratosphere/source/htcs/impl/rpc/htcs_rpc_tasks.hpp index 3414e467e..5e4ec879d 100644 --- a/libraries/libstratosphere/source/htcs/impl/rpc/htcs_rpc_tasks.hpp +++ b/libraries/libstratosphere/source/htcs/impl/rpc/htcs_rpc_tasks.hpp @@ -66,7 +66,7 @@ namespace ams::htcs::impl::rpc { HtcsPacketCategory category; HtcsPacketType type; s64 body_size; - u32 task_id; + u32 task_id{}; s64 params[5]; char data[]; }; diff --git a/libraries/libstratosphere/source/i2c/driver/board/nintendo/nx/i2c_driver_api.cpp b/libraries/libstratosphere/source/i2c/driver/board/nintendo/nx/i2c_driver_api.cpp index 09a174e2f..2b4dad7bb 100644 --- a/libraries/libstratosphere/source/i2c/driver/board/nintendo/nx/i2c_driver_api.cpp +++ b/libraries/libstratosphere/source/i2c/driver/board/nintendo/nx/i2c_driver_api.cpp @@ -95,8 +95,8 @@ namespace ams::i2c::driver::board::nintendo::nx { } } - constinit util::TypedStorage g_bus_accessor_manager; - constinit util::TypedStorage g_device_manager; + constinit util::TypedStorage g_bus_accessor_manager = {}; + constinit util::TypedStorage g_device_manager = {}; } diff --git a/libraries/libstratosphere/source/init/init_malloc.cpp b/libraries/libstratosphere/source/init/init_malloc.cpp index 9d0515514..2d1850c15 100644 --- a/libraries/libstratosphere/source/init/init_malloc.cpp +++ b/libraries/libstratosphere/source/init/init_malloc.cpp @@ -15,18 +15,34 @@ */ #include +/* NOTE: If AMS_INIT_USE_STANDARD_ALLOCATOR_FOR_MALLOC is defined, the relevant os primitives should be hooked up. */ +#if defined(ATMOSPHERE_OS_HORIZON) + #define AMS_INIT_USE_STANDARD_ALLOCATOR_FOR_MALLOC +#elif defined(ATMOSPHERE_OS_WINDOWS) + //#define AMS_INIT_USE_STANDARD_ALLOCATOR_FOR_MALLOC +#elif defined(ATMOSPHERE_OS_LINUX) + //#define AMS_INIT_USE_STANDARD_ALLOCATOR_FOR_MALLOC +#elif defined(ATMOSPHERE_OS_MACOS) + //#define AMS_INIT_USE_STANDARD_ALLOCATOR_FOR_MALLOC +#else + #error "Unknown OS for enabling StandardAllocator backing impl for malloc" +#endif + namespace ams::init { namespace { + #if defined(AMS_INIT_USE_STANDARD_ALLOCATOR_FOR_MALLOC) constinit void *g_malloc_region_address = nullptr; constinit size_t g_malloc_region_size = 0; - constinit util::TypedStorage g_malloc_allocator; + constinit util::TypedStorage g_malloc_allocator = {}; + #endif } void InitializeAllocator(void *address, size_t size, bool cache_enabled) { + #if defined(AMS_INIT_USE_STANDARD_ALLOCATOR_FOR_MALLOC) /* Check pre-conditions. */ AMS_ABORT_UNLESS(g_malloc_region_size == 0); AMS_ABORT_UNLESS(size > 0); @@ -40,21 +56,34 @@ namespace ams::init { /* Set malloc globals. */ g_malloc_region_address = address; g_malloc_region_size = size; + #else + AMS_UNUSED(address, size, cache_enabled); + #endif } void InitializeAllocator(void *address, size_t size) { return InitializeAllocator(address, size, false); } + void InitializeDefaultAllocator() { + /* TODO: What should default heap size be? This uses virtual address space memory. */ + return InitializeAllocator(nullptr, 128_MB, false); + } + mem::StandardAllocator *GetAllocator() { + #if defined(AMS_INIT_USE_STANDARD_ALLOCATOR_FOR_MALLOC) /* Check pre-conditions. */ AMS_ASSERT(g_malloc_region_size > 0); return util::GetPointer(g_malloc_allocator); + #else + return nullptr; + #endif } } +#if defined(AMS_INIT_USE_STANDARD_ALLOCATOR_FOR_MALLOC) extern "C" void *malloc(size_t size) { /* We require that an allocator region exists. */ if (::ams::init::g_malloc_region_size == 0) { @@ -145,3 +174,4 @@ extern "C" size_t malloc_usable_size(void *ptr) { return ::ams::util::GetReference(::ams::init::g_malloc_allocator).GetSizeOf(ptr); } +#endif \ No newline at end of file diff --git a/libraries/libstratosphere/source/init/init_operator_new.cpp b/libraries/libstratosphere/source/init/init_operator_new.cpp index d7c55c15c..8657f162d 100644 --- a/libraries/libstratosphere/source/init/init_operator_new.cpp +++ b/libraries/libstratosphere/source/init/init_operator_new.cpp @@ -19,15 +19,15 @@ WEAK_SYMBOL void *operator new(size_t size) { return std::malloc(size); } -WEAK_SYMBOL void *operator new(size_t size, const std::nothrow_t &) { +WEAK_SYMBOL void *operator new(size_t size, const std::nothrow_t &) noexcept { return std::malloc(size); } -WEAK_SYMBOL void operator delete(void *p) { +WEAK_SYMBOL void operator delete(void *p) noexcept { return std::free(p); } -WEAK_SYMBOL void operator delete(void *p, size_t) { +WEAK_SYMBOL void operator delete(void *p, size_t) noexcept { return std::free(p); } @@ -35,14 +35,14 @@ WEAK_SYMBOL void *operator new[](size_t size) { return std::malloc(size); } -WEAK_SYMBOL void *operator new[](size_t size, const std::nothrow_t &) { +WEAK_SYMBOL void *operator new[](size_t size, const std::nothrow_t &) noexcept { return std::malloc(size); } -WEAK_SYMBOL void operator delete[](void *p) { +WEAK_SYMBOL void operator delete[](void *p) noexcept { return std::free(p); } -WEAK_SYMBOL void operator delete[](void *p, size_t) { +WEAK_SYMBOL void operator delete[](void *p, size_t) noexcept { return std::free(p); } diff --git a/libraries/libstratosphere/source/ldr/ldr_ams.c b/libraries/libstratosphere/source/ldr/ldr_ams.os.horizon.c similarity index 97% rename from libraries/libstratosphere/source/ldr/ldr_ams.c rename to libraries/libstratosphere/source/ldr/ldr_ams.os.horizon.c index e629c3b42..7d0b4f907 100644 --- a/libraries/libstratosphere/source/ldr/ldr_ams.c +++ b/libraries/libstratosphere/source/ldr/ldr_ams.os.horizon.c @@ -15,10 +15,10 @@ */ #include -#include "ldr_ams.h" +#include "ldr_ams.os.horizon.h" static Result _ldrAtmosphereHasLaunchedBootProgram(Service *srv, bool *out, u64 program_id) { - u8 tmp; + u8 tmp = 0; Result rc = serviceDispatchInOut(srv, 65000, program_id, tmp); if (R_SUCCEEDED(rc) && out) *out = tmp & 1; return rc; diff --git a/libraries/libstratosphere/source/ldr/ldr_ams.h b/libraries/libstratosphere/source/ldr/ldr_ams.os.horizon.h similarity index 100% rename from libraries/libstratosphere/source/ldr/ldr_ams.h rename to libraries/libstratosphere/source/ldr/ldr_ams.os.horizon.h diff --git a/libraries/libstratosphere/source/ldr/ldr_pm_api.cpp b/libraries/libstratosphere/source/ldr/ldr_pm_api.os.horizon.cpp similarity index 98% rename from libraries/libstratosphere/source/ldr/ldr_pm_api.cpp rename to libraries/libstratosphere/source/ldr/ldr_pm_api.os.horizon.cpp index 0ad1d405c..90d6f4f9b 100644 --- a/libraries/libstratosphere/source/ldr/ldr_pm_api.cpp +++ b/libraries/libstratosphere/source/ldr/ldr_pm_api.os.horizon.cpp @@ -14,7 +14,7 @@ * along with this program. If not, see . */ #include -#include "ldr_ams.h" +#include "ldr_ams.os.horizon.h" namespace ams::ldr::pm { diff --git a/libraries/libstratosphere/source/ldr/ldr_shell_api.cpp b/libraries/libstratosphere/source/ldr/ldr_shell_api.os.horizon.cpp similarity index 100% rename from libraries/libstratosphere/source/ldr/ldr_shell_api.cpp rename to libraries/libstratosphere/source/ldr/ldr_shell_api.os.horizon.cpp diff --git a/libraries/libstratosphere/source/lm/lm_remote_log_service.cpp b/libraries/libstratosphere/source/lm/lm_remote_log_service.cpp index 5ebe3a1e4..46a6e7ab9 100644 --- a/libraries/libstratosphere/source/lm/lm_remote_log_service.cpp +++ b/libraries/libstratosphere/source/lm/lm_remote_log_service.cpp @@ -19,6 +19,7 @@ namespace ams::lm { + #if defined(ATMOSPHERE_OS_HORIZON) namespace { struct LmRemoteLogServiceTag; @@ -57,10 +58,15 @@ namespace ams::lm { } sf::SharedPointer CreateLogService() { - ::Service srv; - R_ABORT_UNLESS(sm::GetService(std::addressof(srv), LogServiceName)); + os::NativeHandle h; + R_ABORT_UNLESS(sm::GetServiceHandle(std::addressof(h), LogServiceName)); - return RemoteObjectFactory::CreateSharedEmplaced<::ams::lm::ILogService, RemoteLogService>(srv); + return RemoteObjectFactory::CreateSharedEmplaced<::ams::lm::ILogService, RemoteLogService>(h); } + #else + sf::SharedPointer CreateLogService() { + AMS_ABORT("TODO"); + } + #endif } diff --git a/libraries/libstratosphere/source/lm/lm_remote_log_service.hpp b/libraries/libstratosphere/source/lm/lm_remote_log_service.hpp index c948008b8..c785283cc 100644 --- a/libraries/libstratosphere/source/lm/lm_remote_log_service.hpp +++ b/libraries/libstratosphere/source/lm/lm_remote_log_service.hpp @@ -19,6 +19,7 @@ namespace ams::lm { + #if defined(ATMOSPHERE_OS_HORIZON) /* TODO: Real libnx primitives? */ #define NX_SERVICE_ASSUME_NON_DOMAIN @@ -48,7 +49,9 @@ namespace ams::lm { private: ::Service m_srv; public: - RemoteLogService(::Service &s) : m_srv(s) { /* ... */ } + RemoteLogService(os::NativeHandle h) { + ::serviceCreate(std::addressof(m_srv), h); + } ~RemoteLogService() { ::serviceClose(std::addressof(m_srv)); } public: /* Actual commands. */ @@ -57,6 +60,7 @@ namespace ams::lm { static_assert(lm::IsILogService); #undef NX_SERVICE_ASSUME_NON_DOMAIN + #endif sf::SharedPointer CreateLogService(); diff --git a/libraries/libstratosphere/source/lm/srv/lm_custom_sink_buffer.hpp b/libraries/libstratosphere/source/lm/srv/lm_custom_sink_buffer.hpp index 4484653d1..dc34af9e7 100644 --- a/libraries/libstratosphere/source/lm/srv/lm_custom_sink_buffer.hpp +++ b/libraries/libstratosphere/source/lm/srv/lm_custom_sink_buffer.hpp @@ -29,7 +29,7 @@ namespace ams::lm::srv { size_t m_used_buffer_size; FlushFunction m_flush_function; public: - constexpr explicit CustomSinkBuffer(void *buffer, size_t buffer_size, FlushFunction f) : m_buffer(static_cast(buffer)), m_buffer_size(buffer_size), m_used_buffer_size(0), m_flush_function(f) { + constexpr explicit CustomSinkBuffer(u8 *buffer, size_t buffer_size, FlushFunction f) : m_buffer(buffer), m_buffer_size(buffer_size), m_used_buffer_size(0), m_flush_function(f) { AMS_ASSERT(m_buffer != nullptr); AMS_ASSERT(m_buffer_size > 0); AMS_ASSERT(m_flush_function != nullptr); diff --git a/libraries/libstratosphere/source/lm/srv/lm_flush_thread.cpp b/libraries/libstratosphere/source/lm/srv/lm_flush_thread.cpp index 8fac0c1b3..238f7140d 100644 --- a/libraries/libstratosphere/source/lm/srv/lm_flush_thread.cpp +++ b/libraries/libstratosphere/source/lm/srv/lm_flush_thread.cpp @@ -30,7 +30,7 @@ namespace ams::lm::srv { constinit u8 g_fs_heap[32_KB]; constinit lmem::HeapHandle g_fs_heap_handle; - constinit os::ThreadType g_flush_thread; + constinit os::ThreadType g_flush_thread = {}; os::Event g_stop_event(os::EventClearMode_ManualClear); os::Event g_sd_logging_event(os::EventClearMode_ManualClear); diff --git a/libraries/libstratosphere/source/lm/srv/lm_ipc_server.cpp b/libraries/libstratosphere/source/lm/srv/lm_ipc_server.cpp index 8ae083a4b..c019184ee 100644 --- a/libraries/libstratosphere/source/lm/srv/lm_ipc_server.cpp +++ b/libraries/libstratosphere/source/lm/srv/lm_ipc_server.cpp @@ -39,12 +39,12 @@ namespace ams::lm::srv { using ServerManager = sf::hipc::ServerManager; - constinit util::TypedStorage g_server_manager_storage; + constinit util::TypedStorage g_server_manager_storage = {}; constinit ServerManager *g_server_manager = nullptr; - constinit util::TypedStorage g_pm_module_storage; - constinit psc::PmModule *g_pm_module; - constinit os::MultiWaitHolderType g_pm_module_holder; + constinit util::TypedStorage g_pm_module_storage = {}; + constinit psc::PmModule *g_pm_module = nullptr; + constinit os::MultiWaitHolderType g_pm_module_holder = {}; constexpr const psc::PmModuleId PmModuleDependencies[] = { psc::PmModuleId_TmaHostIo, psc::PmModuleId_Fs }; diff --git a/libraries/libstratosphere/source/lm/srv/lm_log_buffer.hpp b/libraries/libstratosphere/source/lm/srv/lm_log_buffer.hpp index 1d5623184..1663c27af 100644 --- a/libraries/libstratosphere/source/lm/srv/lm_log_buffer.hpp +++ b/libraries/libstratosphere/source/lm/srv/lm_log_buffer.hpp @@ -42,7 +42,7 @@ namespace ams::lm::srv { bool m_push_canceled; size_t m_push_ready_wait_count; public: - constexpr explicit LogBuffer(void *buffer, size_t buffer_size, FlushFunction f) + constexpr explicit LogBuffer(u8 *buffer, size_t buffer_size, FlushFunction f) : m_buffers{}, m_push_buffer(m_buffers + 0), m_flush_buffer(m_buffers + 1), m_buffer_size(buffer_size / 2), m_flush_function(f), m_push_buffer_mutex{}, m_flush_buffer_mutex{}, m_cv_push_ready{}, m_cv_flush_ready{}, @@ -52,8 +52,8 @@ namespace ams::lm::srv { AMS_ASSERT(buffer_size > 0); AMS_ASSERT(f != nullptr); - m_buffers[0].m_head = static_cast(buffer); - m_buffers[1].m_head = static_cast(buffer) + (buffer_size / 2); + m_buffers[0].m_head = buffer; + m_buffers[1].m_head = buffer + (buffer_size / 2); } static LogBuffer &GetDefaultInstance(); diff --git a/libraries/libstratosphere/source/lm/srv/lm_log_packet_parser.cpp b/libraries/libstratosphere/source/lm/srv/lm_log_packet_parser.cpp index cc6401b1e..1a0e95b3e 100644 --- a/libraries/libstratosphere/source/lm/srv/lm_log_packet_parser.cpp +++ b/libraries/libstratosphere/source/lm/srv/lm_log_packet_parser.cpp @@ -256,7 +256,7 @@ namespace ams::lm::srv { } if (is_text_log) { - const size_t sendable_size = std::min(size, remaining); + const size_t sendable_size = std::min(size, remaining); callback(reinterpret_cast(cur), sendable_size, arg); } diff --git a/libraries/libstratosphere/source/lm/srv/lm_sd_card_logger.cpp b/libraries/libstratosphere/source/lm/srv/lm_sd_card_logger.cpp index 311563f34..21d90ba29 100644 --- a/libraries/libstratosphere/source/lm/srv/lm_sd_card_logger.cpp +++ b/libraries/libstratosphere/source/lm/srv/lm_sd_card_logger.cpp @@ -133,7 +133,7 @@ namespace ams::lm::srv { /* Ensure the directory. */ /* NOTE: Nintendo does not perform recusrive directory ensure, only a single CreateDirectory level. */ - return R_SUCCEEDED(fs::EnsureDirectoryRecursively(path)); + return R_SUCCEEDED(fs::EnsureDirectory(path)); } bool MakeLogFilePathWithoutExtension(char *dst, size_t size, const char *dir) { diff --git a/libraries/libstratosphere/source/lmem/impl/lmem_impl_common_heap.hpp b/libraries/libstratosphere/source/lmem/impl/lmem_impl_common_heap.hpp index 001257ef1..f05361de8 100644 --- a/libraries/libstratosphere/source/lmem/impl/lmem_impl_common_heap.hpp +++ b/libraries/libstratosphere/source/lmem/impl/lmem_impl_common_heap.hpp @@ -41,19 +41,19 @@ namespace ams::lmem::impl { } }; - constexpr inline MemoryRange MakeMemoryRange(void *address, size_t size) { + ALWAYS_INLINE MemoryRange MakeMemoryRange(void *address, size_t size) { return MemoryRange{ .address = reinterpret_cast(address), .size = size }; } - constexpr inline void *GetHeapStartAddress(HeapHandle handle) { + ALWAYS_INLINE void *GetHeapStartAddress(HeapHandle handle) { return handle->heap_start; } - constexpr inline size_t GetPointerDifference(const void *start, const void *end) { + ALWAYS_INLINE size_t GetPointerDifference(const void *start, const void *end) { return reinterpret_cast(end) - reinterpret_cast(start); } - constexpr inline size_t GetPointerDifference(uintptr_t start, uintptr_t end) { + constexpr ALWAYS_INLINE size_t GetPointerDifference(uintptr_t start, uintptr_t end) { return end - start; } diff --git a/libraries/libstratosphere/source/lmem/impl/lmem_impl_exp_heap.cpp b/libraries/libstratosphere/source/lmem/impl/lmem_impl_exp_heap.cpp index 21b5d1189..05e329a78 100644 --- a/libraries/libstratosphere/source/lmem/impl/lmem_impl_exp_heap.cpp +++ b/libraries/libstratosphere/source/lmem/impl/lmem_impl_exp_heap.cpp @@ -42,19 +42,19 @@ namespace ams::lmem::impl { return handle->magic == ExpHeapMagic; } - inline ExpHeapHead *GetExpHeapHead(HeapHead *heap_head) { + [[maybe_unused]] inline ExpHeapHead *GetExpHeapHead(HeapHead *heap_head) { return std::addressof(heap_head->impl_head.exp_heap_head); } - inline const ExpHeapHead *GetExpHeapHead(const HeapHead *heap_head) { + [[maybe_unused]] inline const ExpHeapHead *GetExpHeapHead(const HeapHead *heap_head) { return std::addressof(heap_head->impl_head.exp_heap_head); } - inline HeapHead *GetHeapHead(ExpHeapHead *exp_heap_head) { + [[maybe_unused]] inline HeapHead *GetHeapHead(ExpHeapHead *exp_heap_head) { return util::GetParentPointer<&HeapHead::impl_head>(util::GetParentPointer<&ImplementationHeapHead::exp_heap_head>(exp_heap_head)); } - inline const HeapHead *GetHeapHead(const ExpHeapHead *exp_heap_head) { + [[maybe_unused]] inline const HeapHead *GetHeapHead(const ExpHeapHead *exp_heap_head) { return util::GetParentPointer<&HeapHead::impl_head>(util::GetParentPointer<&ImplementationHeapHead::exp_heap_head>(exp_heap_head)); } diff --git a/libraries/libstratosphere/source/lmem/impl/lmem_impl_unit_heap.cpp b/libraries/libstratosphere/source/lmem/impl/lmem_impl_unit_heap.cpp index fc6a78ce8..22bf7c3b7 100644 --- a/libraries/libstratosphere/source/lmem/impl/lmem_impl_unit_heap.cpp +++ b/libraries/libstratosphere/source/lmem/impl/lmem_impl_unit_heap.cpp @@ -30,7 +30,7 @@ namespace ams::lmem::impl { return std::addressof(heap_head->impl_head.unit_heap_head); } - constexpr inline const UnitHeapHead *GetUnitHeapHead(const HeapHead *heap_head) { + [[maybe_unused]] constexpr inline const UnitHeapHead *GetUnitHeapHead(const HeapHead *heap_head) { return std::addressof(heap_head->impl_head.unit_heap_head); } diff --git a/libraries/libstratosphere/source/lr/lr_api.cpp b/libraries/libstratosphere/source/lr/lr_api.cpp index a952b0cec..3d241e103 100644 --- a/libraries/libstratosphere/source/lr/lr_api.cpp +++ b/libraries/libstratosphere/source/lr/lr_api.cpp @@ -14,67 +14,52 @@ * along with this program. If not, see . */ #include -#include "lr_remote_location_resolver_impl.hpp" -#include "lr_remote_registered_location_resolver_impl.hpp" +#include "lr_location_resolver_manager_factory.hpp" namespace ams::lr { namespace { - bool g_initialized; + constinit sf::SharedPointer g_location_resolver_manager; - /* TODO: This belongs inside lr_location_resolver_manager_factory */ - struct LocationResolverManagerAllocatorTag; - using LocationResolverManagerAllocator = sf::ExpHeapStaticAllocator<1_KB, LocationResolverManagerAllocatorTag>; - - using LocationResolverManagerFactory = sf::ObjectFactory; - - class StaticAllocatorInitializer { - public: - StaticAllocatorInitializer() { - LocationResolverManagerAllocator::Initialize(lmem::CreateOption_None); - } - } g_static_allocator_initializer; } void Initialize() { - AMS_ASSERT(!g_initialized); - R_ABORT_UNLESS(lrInitialize()); - g_initialized = true; + AMS_ASSERT(g_location_resolver_manager == nullptr); + g_location_resolver_manager = GetLocationResolverManagerService(); } void Finalize() { - AMS_ASSERT(g_initialized); - lrExit(); - g_initialized = false; + AMS_ASSERT(g_location_resolver_manager != nullptr); + g_location_resolver_manager = nullptr; } Result OpenLocationResolver(LocationResolver *out, ncm::StorageId storage_id) { - LrLocationResolver lr; - R_TRY(lrOpenLocationResolver(static_cast(storage_id), std::addressof(lr))); + sf::SharedPointer lr; + R_TRY(g_location_resolver_manager->OpenLocationResolver(std::addressof(lr), storage_id)); - *out = LocationResolver(LocationResolverManagerFactory::CreateSharedEmplaced(lr)); - return ResultSuccess(); + *out = LocationResolver(std::move(lr)); + R_SUCCEED(); } Result OpenRegisteredLocationResolver(RegisteredLocationResolver *out) { - LrRegisteredLocationResolver lr; - R_TRY(lrOpenRegisteredLocationResolver(std::addressof(lr))); + sf::SharedPointer lr; + R_TRY(g_location_resolver_manager->OpenRegisteredLocationResolver(std::addressof(lr))); - *out = RegisteredLocationResolver(LocationResolverManagerFactory::CreateSharedEmplaced(lr)); - return ResultSuccess(); + *out = RegisteredLocationResolver(std::move(lr)); + R_SUCCEED(); } Result OpenAddOnContentLocationResolver(AddOnContentLocationResolver *out) { - /* TODO: libnx binding */ - AMS_UNUSED(out); - AMS_ABORT(); + sf::SharedPointer lr; + R_TRY(g_location_resolver_manager->OpenAddOnContentLocationResolver(std::addressof(lr))); + + *out = AddOnContentLocationResolver(std::move(lr)); + R_SUCCEED(); } Result RefreshLocationResolver(ncm::StorageId storage_id) { - /* TODO: libnx binding */ - AMS_UNUSED(storage_id); - AMS_ABORT(); + R_RETURN(g_location_resolver_manager->RefreshLocationResolver(storage_id)); } } diff --git a/libraries/libstratosphere/source/lr/lr_location_resolver_manager_factory.cpp b/libraries/libstratosphere/source/lr/lr_location_resolver_manager_factory.cpp new file mode 100644 index 000000000..089185569 --- /dev/null +++ b/libraries/libstratosphere/source/lr/lr_location_resolver_manager_factory.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 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 +#include "lr_remote_location_resolver_manager_impl.hpp" + +namespace ams::lr { + + namespace { + + class StaticAllocatorInitializer { + public: + StaticAllocatorInitializer() { + LocationResolverManagerAllocator::Initialize(lmem::CreateOption_None); + } + } g_static_allocator_initializer; + + } + + sf::SharedPointer GetLocationResolverManagerService() { + #if defined(ATMOSPHERE_OS_HORIZON) + return LocationResolverManagerFactory::CreateSharedEmplaced(); + #else + return LocationResolverManagerFactory::CreateSharedEmplaced(); + #endif + } +} diff --git a/libraries/libstratosphere/source/lr/lr_location_resolver_manager_factory.hpp b/libraries/libstratosphere/source/lr/lr_location_resolver_manager_factory.hpp new file mode 100644 index 000000000..1550fb125 --- /dev/null +++ b/libraries/libstratosphere/source/lr/lr_location_resolver_manager_factory.hpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 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::lr { + + struct LocationResolverManagerAllocatorTag; + using LocationResolverManagerAllocator = sf::ExpHeapStaticAllocator<1_KB, LocationResolverManagerAllocatorTag>; + + using LocationResolverManagerFactory = sf::ObjectFactory; + + sf::SharedPointer GetLocationResolverManagerService(); + +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/lr/lr_remote_location_resolver_impl.hpp b/libraries/libstratosphere/source/lr/lr_remote_location_resolver_impl.hpp index b84003098..d6ba3007d 100644 --- a/libraries/libstratosphere/source/lr/lr_remote_location_resolver_impl.hpp +++ b/libraries/libstratosphere/source/lr/lr_remote_location_resolver_impl.hpp @@ -18,6 +18,7 @@ namespace ams::lr { + #if defined(ATMOSPHERE_OS_HORIZON) class RemoteLocationResolverImpl { private: ::LrLocationResolver m_srv; @@ -155,5 +156,6 @@ namespace ams::lr { } }; static_assert(lr::IsILocationResolver); + #endif } diff --git a/libraries/libstratosphere/source/lr/lr_remote_location_resolver_manager_impl.hpp b/libraries/libstratosphere/source/lr/lr_remote_location_resolver_manager_impl.hpp new file mode 100644 index 000000000..0965dae33 --- /dev/null +++ b/libraries/libstratosphere/source/lr/lr_remote_location_resolver_manager_impl.hpp @@ -0,0 +1,61 @@ +/* + * Copyright (c) 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 "lr_location_resolver_manager_factory.hpp" +#include "lr_remote_location_resolver_impl.hpp" +#include "lr_remote_registered_location_resolver_impl.hpp" + +namespace ams::lr { + + #if defined(ATMOSPHERE_OS_HORIZON) + class RemoteLocationResolverManagerImpl { + public: + RemoteLocationResolverManagerImpl() { R_ABORT_UNLESS(::lrInitialize()); } + + ~RemoteLocationResolverManagerImpl() { ::lrExit(); } + public: + /* Actual commands. */ + Result OpenLocationResolver(sf::Out> out, ncm::StorageId storage_id) { + LrLocationResolver lr; + R_TRY(::lrOpenLocationResolver(static_cast<::NcmStorageId>(storage_id), std::addressof(lr))); + + *out = LocationResolverManagerFactory::CreateSharedEmplaced(lr); + R_SUCCEED(); + } + + Result OpenRegisteredLocationResolver(sf::Out> out) { + LrRegisteredLocationResolver lr; + R_TRY(::lrOpenRegisteredLocationResolver(std::addressof(lr))); + + *out = LocationResolverManagerFactory::CreateSharedEmplaced(lr); + R_SUCCEED(); + } + + Result RefreshLocationResolver(ncm::StorageId storage_id) { + AMS_UNUSED(storage_id); + AMS_ABORT("TODO: libnx binding"); + } + + Result OpenAddOnContentLocationResolver(sf::Out> out) { + AMS_UNUSED(out); + AMS_ABORT("TODO: libnx binding"); + } + }; + static_assert(lr::IsILocationResolverManager); + #endif + +} diff --git a/libraries/libstratosphere/source/lr/lr_remote_registered_location_resolver_impl.hpp b/libraries/libstratosphere/source/lr/lr_remote_registered_location_resolver_impl.hpp index 20687a5c0..f0aada3ae 100644 --- a/libraries/libstratosphere/source/lr/lr_remote_registered_location_resolver_impl.hpp +++ b/libraries/libstratosphere/source/lr/lr_remote_registered_location_resolver_impl.hpp @@ -19,6 +19,7 @@ namespace ams::lr { + #if defined(ATMOSPHERE_OS_HORIZON) class RemoteRegisteredLocationResolverImpl { private: ::LrRegisteredLocationResolver m_srv; @@ -110,5 +111,6 @@ namespace ams::lr { } }; static_assert(lr::IsIRegisteredLocationResolver); + #endif } diff --git a/libraries/libstratosphere/source/mem/impl/heap/mem_impl_heap_central_heap.cpp b/libraries/libstratosphere/source/mem/impl/heap/mem_impl_heap_central_heap.cpp index e52b05348..35e043efd 100644 --- a/libraries/libstratosphere/source/mem/impl/heap/mem_impl_heap_central_heap.cpp +++ b/libraries/libstratosphere/source/mem/impl/heap/mem_impl_heap_central_heap.cpp @@ -117,7 +117,7 @@ namespace ams::mem::impl::heap { if (real_size == 0) { return nullptr; } - AMS_ASSERT(cls < TlsHeapStatic::NumClassInfo); + AMS_ASSERT(static_cast(cls) < TlsHeapStatic::NumClassInfo); return m_tls_heap_central->CacheSmallMemory(cls, align); } @@ -128,7 +128,7 @@ namespace ams::mem::impl::heap { if (!util::IsAligned(reinterpret_cast(ptr), MinimumAlignment)) { return 0; } - AMS_ASSERT(cls < TlsHeapStatic::NumClassInfo); + AMS_ASSERT(static_cast(cls) < TlsHeapStatic::NumClassInfo); return TlsHeapStatic::GetChunkSize(cls); } else if (ptr != nullptr) { return m_tls_heap_central->GetAllocationSize(ptr); @@ -151,7 +151,7 @@ namespace ams::mem::impl::heap { const auto cls = m_tls_heap_central->GetClassFromPointer(ptr); if (cls >= 0) { - AMS_ASSERT(cls < TlsHeapStatic::NumClassInfo); + AMS_ASSERT(static_cast(cls) < TlsHeapStatic::NumClassInfo); if (cls) { return m_tls_heap_central->UncacheSmallMemory(ptr); } else { @@ -266,26 +266,22 @@ namespace ams::mem::impl::heap { return m_tls_heap_central->WalkAllocatedPointers(callback, user_data); } - errno_t CentralHeap::QueryV(int query, std::va_list vl) { - return this->QueryVImpl(query, std::addressof(vl)); - } - errno_t CentralHeap::Query(int query, ...) { std::va_list vl; va_start(vl, query); - auto err = this->QueryVImpl(query, std::addressof(vl)); + auto err = this->QueryV(query, vl); va_end(vl); return err; } - errno_t CentralHeap::QueryVImpl(int _query, std::va_list *vl_ptr) { + errno_t CentralHeap::QueryV(int _query, std::va_list vl) { const AllocQuery query = static_cast(_query); switch (query) { case AllocQuery_Dump: case AllocQuery_DumpJson: { - auto dump_mode = static_cast(va_arg(*vl_ptr, int)); - auto fd = va_arg(*vl_ptr, int); + auto dump_mode = static_cast(va_arg(vl, int)); + auto fd = va_arg(vl, int); if (m_tls_heap_central) { m_tls_heap_central->Dump(dump_mode, fd, query == AllocQuery_DumpJson); } @@ -293,7 +289,7 @@ namespace ams::mem::impl::heap { } case AllocQuery_PageSize: { - size_t *out = va_arg(*vl_ptr, size_t *); + size_t *out = va_arg(vl, size_t *); if (out) { *out = PageSize; } @@ -304,7 +300,7 @@ namespace ams::mem::impl::heap { case AllocQuery_SystemSize: case AllocQuery_MaxAllocatableSize: { - size_t *out = va_arg(*vl_ptr, size_t *); + size_t *out = va_arg(vl, size_t *); if (!out) { return 0; } @@ -333,7 +329,7 @@ namespace ams::mem::impl::heap { } case AllocQuery_IsClean: { - int *out = va_arg(*vl_ptr, int *); + int *out = va_arg(vl, int *); if (out) { *out = !m_tls_heap_central || m_tls_heap_central->IsClean(); } @@ -341,7 +337,7 @@ namespace ams::mem::impl::heap { } case AllocQuery_HeapHash: { - HeapHash *out = va_arg(*vl_ptr, HeapHash *); + HeapHash *out = va_arg(vl, HeapHash *); if (out) { if (m_tls_heap_central) { m_tls_heap_central->CalculateHeapHash(out); @@ -358,37 +354,37 @@ namespace ams::mem::impl::heap { case AllocQuery_SetColor: { /* NOTE: Nintendo does not check that the ptr is not null for this query, even though they do for other queries. */ - void *ptr = va_arg(*vl_ptr, void *); - int color = va_arg(*vl_ptr, int); + void *ptr = va_arg(vl, void *); + int color = va_arg(vl, int); return m_tls_heap_central->SetColor(ptr, color); } case AllocQuery_GetColor: { /* NOTE: Nintendo does not check that the ptr is not null for this query, even though they do for other queries. */ - void *ptr = va_arg(*vl_ptr, void *); - int *out = va_arg(*vl_ptr, int *); + void *ptr = va_arg(vl, void *); + int *out = va_arg(vl, int *); return m_tls_heap_central->GetColor(ptr, out); } case AllocQuery_SetName: { /* NOTE: Nintendo does not check that the ptr is not null for this query, even though they do for other queries. */ - void *ptr = va_arg(*vl_ptr, void *); - const char *name = va_arg(*vl_ptr, const char *); + void *ptr = va_arg(vl, void *); + const char *name = va_arg(vl, const char *); return m_tls_heap_central->SetName(ptr, name); } case AllocQuery_GetName: { /* NOTE: Nintendo does not check that the ptr is not null for this query, even though they do for other queries. */ - void *ptr = va_arg(*vl_ptr, void *); - char *dst = va_arg(*vl_ptr, char *); - size_t dst_size = va_arg(*vl_ptr, size_t); + void *ptr = va_arg(vl, void *); + char *dst = va_arg(vl, char *); + size_t dst_size = va_arg(vl, size_t); return m_tls_heap_central->GetName(ptr, dst, dst_size); } case AllocQuery_FreeSizeMapped: case AllocQuery_MaxAllocatableSizeMapped: { /* NOTE: Nintendo does not check that the ptr is not null for this query, even though they do for other queries. */ - size_t *out = va_arg(*vl_ptr, size_t *); + size_t *out = va_arg(vl, size_t *); size_t free_size; size_t max_allocatable_size; auto err = m_tls_heap_central->GetMappedMemStats(std::addressof(free_size), std::addressof(max_allocatable_size)); diff --git a/libraries/libstratosphere/source/mem/impl/heap/mem_impl_heap_tls_heap_cache.cpp b/libraries/libstratosphere/source/mem/impl/heap/mem_impl_heap_tls_heap_cache.cpp index 4727cdcf0..d65c3ce2a 100644 --- a/libraries/libstratosphere/source/mem/impl/heap/mem_impl_heap_tls_heap_cache.cpp +++ b/libraries/libstratosphere/source/mem/impl/heap/mem_impl_heap_tls_heap_cache.cpp @@ -122,7 +122,7 @@ namespace ams::mem::impl::heap { } if (const size_t cls = TlsHeapStatic::GetClassFromSize(size); cls != 0) { - AMS_ASSERT(cls < TlsHeapStatic::NumClassInfo); + AMS_ASSERT(static_cast(cls) < TlsHeapStatic::NumClassInfo); return tls_heap_cache->m_central->CacheSmallMemory(cls); } else { /* If allocating a huge size, release our cache. */ @@ -141,7 +141,7 @@ namespace ams::mem::impl::heap { } if (size_t cls = TlsHeapStatic::GetClassFromSize(size); cls != 0) { - AMS_ASSERT(cls < TlsHeapStatic::NumClassInfo); + AMS_ASSERT(static_cast(cls) < TlsHeapStatic::NumClassInfo); /* Allocate a chunk. */ void *ptr = tls_heap_cache->m_small_mem_lists[cls]; if (ptr == nullptr) { @@ -208,7 +208,7 @@ namespace ams::mem::impl::heap { return nullptr; } - AMS_ASSERT(cls < TlsHeapStatic::NumClassInfo); + AMS_ASSERT(static_cast(cls) < TlsHeapStatic::NumClassInfo); return tls_heap_cache->m_central->CacheSmallMemory(cls, align); } else { /* If allocating a huge size, release our cache. */ @@ -243,7 +243,7 @@ namespace ams::mem::impl::heap { return nullptr; } - AMS_ASSERT(cls < TlsHeapStatic::NumClassInfo); + AMS_ASSERT(static_cast(cls) < TlsHeapStatic::NumClassInfo); /* Allocate a chunk. */ void *ptr = tls_heap_cache->m_small_mem_lists[cls]; @@ -294,7 +294,7 @@ namespace ams::mem::impl::heap { return tls_heap_cache->m_central->UncacheLargeMemory(ptr); } - AMS_ASSERT(cls < TlsHeapStatic::NumClassInfo); + AMS_ASSERT(static_cast(cls) < TlsHeapStatic::NumClassInfo); if (cls >= 0) { return tls_heap_cache->m_central->UncacheSmallMemory(ptr); @@ -312,7 +312,7 @@ namespace ams::mem::impl::heap { return tls_heap_cache->m_central->UncacheLargeMemory(ptr); } - AMS_ASSERT(cls < TlsHeapStatic::NumClassInfo); + AMS_ASSERT(static_cast(cls) < TlsHeapStatic::NumClassInfo); if (cls >= 0) { *reinterpret_cast(ptr) = tls_heap_cache->m_small_mem_lists[cls]; diff --git a/libraries/libstratosphere/source/mem/impl/heap/mem_impl_heap_tls_heap_central.cpp b/libraries/libstratosphere/source/mem/impl/heap/mem_impl_heap_tls_heap_central.cpp index 6b3fd5756..216808218 100644 --- a/libraries/libstratosphere/source/mem/impl/heap/mem_impl_heap_tls_heap_central.cpp +++ b/libraries/libstratosphere/source/mem/impl/heap/mem_impl_heap_tls_heap_central.cpp @@ -394,7 +394,7 @@ namespace ams::mem::impl::heap { this->AddToFreeBlockList(span); m_num_threads = 1; - m_static_thread_quota = std::min((m_span_table.total_pages * TlsHeapStatic::PageSize) / sizeof(void *), 2_MB); + m_static_thread_quota = std::min((m_span_table.total_pages * TlsHeapStatic::PageSize) / sizeof(void *), 2_MB); m_dynamic_thread_quota = m_static_thread_quota; m_use_virtual_memory = use_virtual_memory; @@ -940,10 +940,10 @@ namespace ams::mem::impl::heap { m_physical_page_flags[i] = 2; } } else { - const void *set_flag = ::memchr(std::addressof(m_physical_page_flags[i]), 1, idx_end - i); + const void *set_flag = util::Memchr(std::addressof(m_physical_page_flags[i]), 1, idx_end - i); if (set_flag) { const uintptr_t set_idx = reinterpret_cast(set_flag) - m_physical_page_flags; - const void *lst_flag = ::memrchr(std::addressof(m_physical_page_flags[set_idx]), 1, idx_end - set_idx); + const void *lst_flag = util::Memrchr(std::addressof(m_physical_page_flags[set_idx]), 1, idx_end - set_idx); const uintptr_t lst_idx = (lst_flag) ? (reinterpret_cast(lst_flag) - m_physical_page_flags + 1) : idx_end; std::memset(std::addressof(m_physical_page_flags[set_idx]), 2, lst_idx - set_idx); } diff --git a/libraries/libstratosphere/source/mem/impl/mem_impl_platform.os.horizon.cpp b/libraries/libstratosphere/source/mem/impl/mem_impl_platform.os.horizon.cpp index 5cf49303b..e13d3096a 100644 --- a/libraries/libstratosphere/source/mem/impl/mem_impl_platform.os.horizon.cpp +++ b/libraries/libstratosphere/source/mem/impl/mem_impl_platform.os.horizon.cpp @@ -20,27 +20,9 @@ namespace ams::mem::impl { namespace { - constinit os::SdkMutex g_virt_mem_enabled_lock; - constinit bool g_virt_mem_enabled_detected = false; - constinit bool g_virt_mem_enabled = false; - - void EnsureVirtualAddressMemoryDetected() { - if (AMS_LIKELY(g_virt_mem_enabled_detected)) { - return; - } - - std::scoped_lock lk(g_virt_mem_enabled_lock); - - if (AMS_UNLIKELY(g_virt_mem_enabled_detected)) { - return; - } - - g_virt_mem_enabled = os::IsVirtualAddressMemoryEnabled(); - } - ALWAYS_INLINE bool IsVirtualAddressMemoryEnabled() { - EnsureVirtualAddressMemoryDetected(); - return g_virt_mem_enabled; + AMS_FUNCTION_LOCAL_STATIC(bool, s_virt_mem_enabled, os::IsVirtualAddressMemoryEnabled()); + return s_virt_mem_enabled; } ALWAYS_INLINE errno_t ConvertResult(Result result) { diff --git a/libraries/libstratosphere/source/mem/impl/mem_impl_platform.os.linux.cpp b/libraries/libstratosphere/source/mem/impl/mem_impl_platform.os.linux.cpp new file mode 100644 index 000000000..b7dd6b538 --- /dev/null +++ b/libraries/libstratosphere/source/mem/impl/mem_impl_platform.os.linux.cpp @@ -0,0 +1,142 @@ +/* + * Copyright (c) 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 +#include "mem_impl_platform.hpp" + +namespace ams::mem::impl { + + errno_t virtual_alloc(void **ptr, size_t size) { + /* Ensure size is non-zero. */ + if (size == 0) { + return EINVAL; + } + + /* Allocate virtual memory. */ + if (const auto address = ::mmap(nullptr, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); address != MAP_FAILED) { + *ptr = reinterpret_cast(address); + return 0; + } else { + return errno; + } + } + + errno_t virtual_free(void *ptr, size_t size) { + /* Ensure pointer/size aren't zero. */ + if (ptr == nullptr || size == 0) { + return EINVAL; + } + + /* Free the memory. */ + if (::munmap(ptr, size) == 0) { + return 0; + } else { + return errno; + } + } + + errno_t physical_alloc(void *ptr, size_t size, Prot prot) { + /* Ensure pointer isn't zero. */ + if (ptr == nullptr) { + return EINVAL; + } + + /* Convert the protection. */ + int native_prot; + switch (util::ToUnderlying(prot)) { + case Prot_none: + native_prot = PROT_NONE; + break; + case Prot_read: + native_prot = PROT_READ; + break; + case Prot_write: + case Prot_write | Prot_read: + native_prot = PROT_READ | PROT_WRITE; + break; + case Prot_exec: + native_prot = PROT_EXEC; + break; + case Prot_exec | Prot_read: + native_prot = PROT_READ | PROT_EXEC; + break; + case Prot_exec | Prot_write: + case Prot_exec | Prot_write | Prot_read: + native_prot = PROT_READ | PROT_WRITE | PROT_EXEC; + break; + default: + return EINVAL; + } + + if (::mprotect(ptr, size, native_prot)) { + return 0; + } else { + return errno; + } + } + + errno_t physical_free(void *ptr, size_t size) { + /* Detect empty allocation. */ + const uintptr_t aligned_start = util::AlignUp(reinterpret_cast(ptr), os::MemoryPageSize); + const uintptr_t aligned_end = util::AlignDown(reinterpret_cast(ptr) + size, os::MemoryPageSize); + const size_t aligned_size = aligned_end - aligned_start; + if (aligned_end <= aligned_start) { + return 0; + } + + if (::mprotect(reinterpret_cast(aligned_start), aligned_size, PROT_NONE)) { + return 0; + } else { + return errno; + } + } + + size_t strlcpy(char *dst, const char *src, size_t size) { + const size_t src_size = std::strlen(src); + if (src_size >= size) { + if (size) { + std::memcpy(dst, src, size - 1); + dst[size - 1] = 0; + } + } else { + std::memcpy(dst, src, src_size + 1); + } + return src_size; + } + + errno_t gen_random(void *dst, size_t dst_size) { + /* TODO: CryptGenRandom? */ + os::GenerateRandomBytes(dst, dst_size); + return 0; + } + + errno_t epochtime(s64 *dst) { + /* TODO: Something more sane than this. */ + auto ts = os::ConvertToTimeSpan(os::GetSystemTick()); + *dst = (ts.GetNanoSeconds() / INT64_C(100)) + INT64_C(0x8A09F909AE60000); + return 0; + } + + errno_t getcpu(s32 *out) { + if (const auto core = sched_getcpu(); core >= 0) { + *out = core; + return 0; + } else { + return errno; + } + } + +} diff --git a/libraries/libstratosphere/source/mem/impl/mem_impl_platform.os.macos.cpp b/libraries/libstratosphere/source/mem/impl/mem_impl_platform.os.macos.cpp new file mode 100644 index 000000000..788b26186 --- /dev/null +++ b/libraries/libstratosphere/source/mem/impl/mem_impl_platform.os.macos.cpp @@ -0,0 +1,177 @@ +/* + * Copyright (c) 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 +#include "mem_impl_platform.hpp" + +#if defined(ATMOSPHERE_ARCH_X64) +#include +#endif + +namespace ams::mem::impl { + + errno_t virtual_alloc(void **ptr, size_t size) { + /* Ensure size is non-zero. */ + if (size == 0) { + return EINVAL; + } + + /* Allocate virtual memory. */ + if (const auto address = ::mmap(nullptr, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); address != MAP_FAILED) { + *ptr = reinterpret_cast(address); + return 0; + } else { + return errno; + } + } + + errno_t virtual_free(void *ptr, size_t size) { + /* Ensure pointer/size aren't zero. */ + if (ptr == nullptr || size == 0) { + return EINVAL; + } + + /* Free the memory. */ + if (::munmap(ptr, size) == 0) { + return 0; + } else { + return errno; + } + } + + errno_t physical_alloc(void *ptr, size_t size, Prot prot) { + /* Ensure pointer isn't zero. */ + if (ptr == nullptr) { + return EINVAL; + } + + /* Convert the protection. */ + int native_prot; + switch (util::ToUnderlying(prot)) { + case Prot_none: + native_prot = PROT_NONE; + break; + case Prot_read: + native_prot = PROT_READ; + break; + case Prot_write: + case Prot_write | Prot_read: + native_prot = PROT_READ | PROT_WRITE; + break; + case Prot_exec: + native_prot = PROT_EXEC; + break; + case Prot_exec | Prot_read: + native_prot = PROT_READ | PROT_EXEC; + break; + case Prot_exec | Prot_write: + case Prot_exec | Prot_write | Prot_read: + native_prot = PROT_READ | PROT_WRITE | PROT_EXEC; + break; + default: + return EINVAL; + } + + if (::mprotect(ptr, size, native_prot)) { + return 0; + } else { + return errno; + } + } + + errno_t physical_free(void *ptr, size_t size) { + /* Detect empty allocation. */ + const uintptr_t aligned_start = util::AlignUp(reinterpret_cast(ptr), os::MemoryPageSize); + const uintptr_t aligned_end = util::AlignDown(reinterpret_cast(ptr) + size, os::MemoryPageSize); + const size_t aligned_size = aligned_end - aligned_start; + if (aligned_end <= aligned_start) { + return 0; + } + + if (::mprotect(reinterpret_cast(aligned_start), aligned_size, PROT_NONE)) { + return 0; + } else { + return errno; + } + } + + size_t strlcpy(char *dst, const char *src, size_t size) { + const size_t src_size = std::strlen(src); + if (src_size >= size) { + if (size) { + std::memcpy(dst, src, size - 1); + dst[size - 1] = 0; + } + } else { + std::memcpy(dst, src, src_size + 1); + } + return src_size; + } + + errno_t gen_random(void *dst, size_t dst_size) { + /* TODO: CryptGenRandom? */ + os::GenerateRandomBytes(dst, dst_size); + return 0; + } + + errno_t epochtime(s64 *dst) { + /* TODO: Something more sane than this. */ + auto ts = os::ConvertToTimeSpan(os::GetSystemTick()); + *dst = (ts.GetNanoSeconds() / INT64_C(100)) + INT64_C(0x8A09F909AE60000); + return 0; + } + + errno_t getcpu(s32 *out) { + if (__builtin_available(macOS 11.0, *)) { + /* On macOS 11.0+, we can use the exposed API they added. */ + size_t cpu_number = 0; + const auto res = pthread_cpu_number_np(std::addressof(cpu_number)); + AMS_ASSERT(res == 0); + AMS_UNUSED(res); + + *out = static_cast(cpu_number); + return 0; + } else { + #if defined(ATMOSPHERE_ARCH_X64) + { + uint32_t cpu_info[4]; + __cpuid_count(1, 0, cpu_info[0], cpu_info[1], cpu_info[2], cpu_info[3]); + + s32 core; + if ((cpu_info[3] & (1 << 9)) == 0) { + core = 0; + } else { + core = static_cast(cpu_info[1] >> 24); + } + + *out = core; + return 0; + } + #elif defined(ATMOSPHERE_ARCH_ARM64) + { + /* Read from TSD, per https://github.com/apple-oss-distributions/xnu/blob/e6231be02a03711ca404e5121a151b24afbff733/libsyscall/os/tsd.h#L68 */ + uint64_t p; + __asm__ __volatile__ ("mrs %0, TPIDR_EL0" : "=r" (p)); + *out = static_cast(p & 0xF); + return 0; + } + #else + AMS_ABORT("Unknown architecture to get current cpu on fallback path on macOS"); + #endif + } + } + +} diff --git a/libraries/libstratosphere/source/mem/impl/mem_impl_platform.os.windows.cpp b/libraries/libstratosphere/source/mem/impl/mem_impl_platform.os.windows.cpp new file mode 100644 index 000000000..7f4424485 --- /dev/null +++ b/libraries/libstratosphere/source/mem/impl/mem_impl_platform.os.windows.cpp @@ -0,0 +1,158 @@ +/* + * Copyright (c) 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 +#include "mem_impl_platform.hpp" + +namespace ams::mem::impl { + + namespace { + + errno_t ConvertGetLastError(DWORD error, errno_t fallback = EIO) { + /* TODO: Implement this? */ + AMS_UNUSED(error); + return fallback; + } + + } + + errno_t virtual_alloc(void **ptr, size_t size) { + /* Ensure size is non-zero. */ + if (size == 0) { + return EINVAL; + } + + /* Allocate virtual memory. */ + if (void *mem = ::VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_READWRITE); mem != nullptr) { + *ptr = mem; + return 0; + } else { + return ConvertGetLastError(::GetLastError()); + } + } + + errno_t virtual_free(void *ptr, size_t size) { + /* Ensure pointer/size aren't zero. */ + if (ptr == nullptr || size == 0) { + return EINVAL; + } + + /* Free the memory. */ + if (::VirtualFree(ptr, 0, MEM_RELEASE)) { + return 0; + } else { + return ConvertGetLastError(::GetLastError()); + } + } + + errno_t physical_alloc(void *ptr, size_t size, Prot prot) { + /* Ensure pointer isn't zero. */ + if (ptr == nullptr) { + return EINVAL; + } + + /* Convert the protection. */ + DWORD fl_protect; + switch (util::ToUnderlying(prot)) { + case Prot_none: + fl_protect = PAGE_NOACCESS; + break; + case Prot_read: + fl_protect = PAGE_READONLY; + break; + case Prot_write: + case Prot_write | Prot_read: + fl_protect = PAGE_READWRITE; + break; + case Prot_exec: + fl_protect = PAGE_EXECUTE; + break; + case Prot_exec | Prot_read: + fl_protect = PAGE_EXECUTE_READ; + break; + case Prot_exec | Prot_write: + case Prot_exec | Prot_write | Prot_read: + fl_protect = PAGE_EXECUTE_READWRITE; + break; + default: + return EINVAL; + } + + if (::VirtualAlloc(ptr, size, MEM_COMMIT, fl_protect)) { + return 0; + } else { + return ConvertGetLastError(::GetLastError()); + } + } + + errno_t physical_free(void *ptr, size_t size) { + /* Detect empty allocation. */ + const uintptr_t aligned_start = util::AlignUp(reinterpret_cast(ptr), os::MemoryPageSize); + const uintptr_t aligned_end = util::AlignDown(reinterpret_cast(ptr) + size, os::MemoryPageSize); + const size_t aligned_size = aligned_end - aligned_start; + if (aligned_end <= aligned_start) { + return 0; + } + + if (::VirtualFree(reinterpret_cast(aligned_start), aligned_size, MEM_DECOMMIT)) { + return 0; + } else { + return ConvertGetLastError(::GetLastError()); + } + } + + size_t strlcpy(char *dst, const char *src, size_t size) { + const size_t src_size = std::strlen(src); + if (src_size >= size) { + if (size) { + std::memcpy(dst, src, size - 1); + dst[size - 1] = 0; + } + } else { + std::memcpy(dst, src, src_size + 1); + } + return src_size; + } + + errno_t gen_random(void *dst, size_t dst_size) { + /* TODO: CryptGenRandom? */ + os::GenerateRandomBytes(dst, dst_size); + return 0; + } + + errno_t epochtime(s64 *dst) { + /* TODO: Something more sane than this. */ + auto ts = os::ConvertToTimeSpan(os::GetSystemTick()); + *dst = (ts.GetNanoSeconds() / INT64_C(100)) + INT64_C(0x8A09F909AE60000); + return 0; + } + + errno_t getcpu(s32 *out) { + AMS_FUNCTION_LOCAL_STATIC(bool, s_has_processor_ex, ::IsWindows7OrGreater()); + + if (s_has_processor_ex) { + PROCESSOR_NUMBER pnum; + ::GetCurrentProcessorNumberEx(std::addressof(pnum)); + + *out = (pnum.Group << 8) | pnum.Number; + } else { + *out = ::GetCurrentProcessorNumber(); + } + + return 0; + } + +} diff --git a/libraries/libstratosphere/source/ncm/ncm_api.cpp b/libraries/libstratosphere/source/ncm/ncm_api.cpp index 614f641a2..59f5a441e 100644 --- a/libraries/libstratosphere/source/ncm/ncm_api.cpp +++ b/libraries/libstratosphere/source/ncm/ncm_api.cpp @@ -14,28 +14,37 @@ * along with this program. If not, see . */ #include +#include "ncm_content_manager_factory.hpp" #include "ncm_remote_content_manager_impl.hpp" namespace ams::ncm { namespace { - sf::SharedPointer g_content_manager; + constinit sf::SharedPointer g_content_manager; - sf::UnmanagedServiceObject g_remote_manager_impl; + #if defined(ATMOSPHERE_OS_HORIZON) + constinit util::TypedStorage> g_remote_manager_storage = {}; + #endif } void Initialize() { AMS_ASSERT(g_content_manager == nullptr); - R_ABORT_UNLESS(ncmInitialize()); - g_content_manager = g_remote_manager_impl.GetShared(); + #if defined(ATMOSPHERE_OS_HORIZON) + util::ConstructAt(g_remote_manager_storage); + g_content_manager = util::GetReference(g_remote_manager_storage).GetShared(); + #else + g_content_manager = CreateDefaultContentManager(ContentManagerConfig{}); + #endif } void Finalize() { AMS_ASSERT(g_content_manager != nullptr); g_content_manager.Reset(); - ncmExit(); + #if defined(ATMOSPHERE_OS_HORIZON) + util::DestroyAt(g_remote_manager_storage); + #endif } void InitializeWithObject(sf::SharedPointer manager_object) { diff --git a/libraries/libstratosphere/source/ncm/ncm_content_id_utils.cpp b/libraries/libstratosphere/source/ncm/ncm_content_id_utils.cpp index fbe60734a..772f3e13e 100644 --- a/libraries/libstratosphere/source/ncm/ncm_content_id_utils.cpp +++ b/libraries/libstratosphere/source/ncm/ncm_content_id_utils.cpp @@ -34,7 +34,7 @@ namespace ams::ncm { /* Convert each character pair to a byte until we reach the end. */ for (size_t i = 0; i < src_size; i += 2) { char tmp[3]; - strlcpy(tmp, src + i, sizeof(tmp)); + util::Strlcpy(tmp, src + i, sizeof(tmp)); char *err = nullptr; reinterpret_cast(dst)[i / 2] = static_cast(std::strtoul(tmp, std::addressof(err), 16)); diff --git a/libraries/libstratosphere/source/ncm/ncm_content_manager_factory.cpp b/libraries/libstratosphere/source/ncm/ncm_content_manager_factory.cpp new file mode 100644 index 000000000..462ce5db8 --- /dev/null +++ b/libraries/libstratosphere/source/ncm/ncm_content_manager_factory.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (c) 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 "ncm_content_manager_factory.hpp" + +namespace ams::ncm { + + sf::SharedPointer CreateDefaultContentManager(const ContentManagerConfig &config) { + auto ref = sf::CreateSharedObjectEmplaced(); + R_ABORT_UNLESS(ref.GetImpl().Initialize(config)); + return ref; + } + +} diff --git a/libraries/libstratosphere/source/ncm/ncm_content_manager_factory.hpp b/libraries/libstratosphere/source/ncm/ncm_content_manager_factory.hpp new file mode 100644 index 000000000..8d0176ae5 --- /dev/null +++ b/libraries/libstratosphere/source/ncm/ncm_content_manager_factory.hpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 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 { + + sf::SharedPointer CreateDefaultContentManager(const ContentManagerConfig &config); + +} diff --git a/libraries/libstratosphere/source/ncm/ncm_content_manager_impl.cpp b/libraries/libstratosphere/source/ncm/ncm_content_manager_impl.cpp index 5ed0bf4fc..d55dd1a59 100644 --- a/libraries/libstratosphere/source/ncm/ncm_content_manager_impl.cpp +++ b/libraries/libstratosphere/source/ncm/ncm_content_manager_impl.cpp @@ -266,7 +266,7 @@ namespace ams::ncm { ON_SCOPE_EXIT { fs::Unmount(root->mount_name); }; /* Ensure the path exists for us to import to. */ - R_TRY(fs::EnsureDirectoryRecursively(root->path)); + R_TRY(fs::EnsureDirectory(root->path)); /* Copy the file from bis to our save. */ R_TRY(impl::CopyFile(savedata_db_path, bis_db_path)); @@ -395,7 +395,7 @@ namespace ams::ncm { ON_SCOPE_EXIT { fs::Unmount(root->mount_name); }; /* Ensure the content storage root's path exists. */ - R_TRY(fs::EnsureDirectoryRecursively(root->path)); + R_TRY(fs::EnsureDirectory(root->path)); /* Initialize content and placeholder directories for the root. */ return ContentStorageImpl::InitializeBase(root->path); @@ -415,7 +415,7 @@ namespace ams::ncm { ON_SCOPE_EXIT { fs::Unmount(root->mount_name); }; /* Ensure the content meta database root's path exists. */ - R_TRY(fs::EnsureDirectoryRecursively(root->path)); + R_TRY(fs::EnsureDirectory(root->path)); /* Commit our changes. */ return fs::CommitSaveData(root->mount_name); @@ -542,7 +542,7 @@ namespace ams::ncm { /* Mount based on the storage type. */ if (storage_id == StorageId::GameCard) { - fs::GameCardHandle handle; + fs::GameCardHandle handle{}; R_TRY(fs::GetGameCardHandle(std::addressof(handle))); R_TRY(fs::MountGameCardPartition(root->mount_name, handle, fs::GameCardPartition::Secure)); } else { diff --git a/libraries/libstratosphere/source/ncm/ncm_content_meta_utils.cpp b/libraries/libstratosphere/source/ncm/ncm_content_meta_utils.cpp index 539fe42e9..e5798aab7 100644 --- a/libraries/libstratosphere/source/ncm/ncm_content_meta_utils.cpp +++ b/libraries/libstratosphere/source/ncm/ncm_content_meta_utils.cpp @@ -94,7 +94,7 @@ namespace ams::ncm { PackagedContentMetaReader reader(meta.Get(), meta.GetSize()); /* Define a helper to output the base meta infos. */ - const auto ReadMetaInfoListFromBase = [&] ALWAYS_INLINE_LAMBDA () -> Result { + const auto ReadMetaInfoListFromBase = [&] () ALWAYS_INLINE_LAMBDA -> Result { /* Output the base content meta info count. */ *out_count = reader.GetContentMetaCount(); diff --git a/libraries/libstratosphere/source/ncm/ncm_content_storage_impl.cpp b/libraries/libstratosphere/source/ncm/ncm_content_storage_impl.cpp index 2048935b1..a09a92599 100644 --- a/libraries/libstratosphere/source/ncm/ncm_content_storage_impl.cpp +++ b/libraries/libstratosphere/source/ncm/ncm_content_storage_impl.cpp @@ -36,7 +36,7 @@ namespace ams::ncm { Result EnsureContentDirectory(ContentId id, MakeContentPathFunction func, const char *root_path) { PathString path; MakeContentPath(std::addressof(path), id, func, root_path); - return fs::EnsureParentDirectoryRecursively(path); + return fs::EnsureParentDirectory(path); } Result DeleteContentFile(ContentId id, MakeContentPathFunction func, const char *root_path) { @@ -303,11 +303,11 @@ namespace ams::ncm { /* Create the content directory. */ MakeBaseContentDirectoryPath(std::addressof(path), root_path); - R_TRY(fs::EnsureDirectoryRecursively(path)); + R_TRY(fs::EnsureDirectory(path)); /* Create the placeholder directory. */ PlaceHolderAccessor::MakeBaseDirectoryPath(std::addressof(path), root_path); - return fs::EnsureDirectoryRecursively(path); + return fs::EnsureDirectory(path); } Result ContentStorageImpl::CleanupBase(const char *root_path) { diff --git a/libraries/libstratosphere/source/ncm/ncm_content_storage_impl.hpp b/libraries/libstratosphere/source/ncm/ncm_content_storage_impl.hpp index e495acc87..237620532 100644 --- a/libraries/libstratosphere/source/ncm/ncm_content_storage_impl.hpp +++ b/libraries/libstratosphere/source/ncm/ncm_content_storage_impl.hpp @@ -38,7 +38,7 @@ namespace ams::ncm { fs::DirectoryEntry m_entries[MaxDirectoryEntries]{}; s64 m_entry_count{}; public: - constexpr ContentIterator() = default; + constexpr ContentIterator() { /* ... */ } ~ContentIterator(); Result Initialize(const char *root_path, size_t max_depth); @@ -48,6 +48,7 @@ namespace ams::ncm { Result OpenDirectory(const char *dir); Result LoadEntries(); }; + static_assert(std::is_constructible::value); protected: PlaceHolderAccessor m_placeholder_accessor; ContentId m_cached_content_id; diff --git a/libraries/libstratosphere/source/ncm/ncm_make_path.cpp b/libraries/libstratosphere/source/ncm/ncm_make_path.cpp index 6da88e3f6..e300d586a 100644 --- a/libraries/libstratosphere/source/ncm/ncm_make_path.cpp +++ b/libraries/libstratosphere/source/ncm/ncm_make_path.cpp @@ -39,19 +39,19 @@ namespace ams::ncm { u16 Get16BitSha256HashPrefix(ContentId id) { u8 hash[crypto::Sha256Generator::HashSize]; - crypto::GenerateSha256Hash(hash, sizeof(hash), std::addressof(id), sizeof(id)); + crypto::GenerateSha256(hash, sizeof(hash), std::addressof(id), sizeof(id)); return static_cast(hash[0]) | (static_cast(hash[1]) << 8); } u8 Get8BitSha256HashPrefix(ContentId id) { u8 hash[crypto::Sha256Generator::HashSize]; - crypto::GenerateSha256Hash(hash, sizeof(hash), std::addressof(id), sizeof(id)); + crypto::GenerateSha256(hash, sizeof(hash), std::addressof(id), sizeof(id)); return hash[0]; } u8 Get8BitSha256HashPrefix(PlaceHolderId id) { u8 hash[crypto::Sha256Generator::HashSize]; - crypto::GenerateSha256Hash(hash, sizeof(hash), std::addressof(id), sizeof(id)); + crypto::GenerateSha256(hash, sizeof(hash), std::addressof(id), sizeof(id)); return hash[0]; } diff --git a/libraries/libstratosphere/source/ncm/ncm_placeholder_accessor.cpp b/libraries/libstratosphere/source/ncm/ncm_placeholder_accessor.cpp index 5f6eab016..ab5e49a0b 100644 --- a/libraries/libstratosphere/source/ncm/ncm_placeholder_accessor.cpp +++ b/libraries/libstratosphere/source/ncm/ncm_placeholder_accessor.cpp @@ -39,13 +39,6 @@ namespace ams::ncm { func(out, id, path); } - ALWAYS_INLINE Result ConvertNotFoundResult(Result r) { - R_TRY_CATCH(r) { - R_CONVERT(ams::fs::ResultPathNotFound, ncm::ResultPlaceHolderNotFound()) - } R_END_TRY_CATCH; - return ResultSuccess(); - } - } void PlaceHolderAccessor::MakePath(PathString *out_placeholder_path, PlaceHolderId placeholder_id) const { @@ -59,7 +52,7 @@ namespace ams::ncm { Result PlaceHolderAccessor::EnsurePlaceHolderDirectory(PlaceHolderId placeholder_id) { PathString path; this->MakePath(std::addressof(path), placeholder_id); - return fs::EnsureParentDirectoryRecursively(path); + return fs::EnsureParentDirectory(path); } Result PlaceHolderAccessor::GetPlaceHolderIdFromFileName(PlaceHolderId *out, const char *name) { @@ -71,7 +64,7 @@ namespace ams::ncm { PlaceHolderId placeholder_id = {}; for (size_t i = 0; i < sizeof(placeholder_id); i++) { char tmp[3]; - strlcpy(tmp, name + i * 2, sizeof(tmp)); + util::Strlcpy(tmp, name + i * 2, sizeof(tmp)); char *err = nullptr; reinterpret_cast(std::addressof(placeholder_id))[i] = static_cast(std::strtoul(tmp, std::addressof(err), 16)); diff --git a/libraries/libstratosphere/source/ncm/ncm_remote_content_manager_impl.hpp b/libraries/libstratosphere/source/ncm/ncm_remote_content_manager_impl.hpp index ab19d8b31..3b1b5e8c4 100644 --- a/libraries/libstratosphere/source/ncm/ncm_remote_content_manager_impl.hpp +++ b/libraries/libstratosphere/source/ncm/ncm_remote_content_manager_impl.hpp @@ -20,14 +20,15 @@ namespace ams::ncm { + #if defined(ATMOSPHERE_OS_HORIZON) class RemoteContentManagerImpl { private: /* TODO: sf::ProxyObjectAllocator */ using ObjectFactory = sf::ObjectFactory>; public: - RemoteContentManagerImpl() { /* ... */ } + RemoteContentManagerImpl() { R_ABORT_UNLESS(::ncmInitialize()); } - ~RemoteContentManagerImpl() { /* ... */ } + ~RemoteContentManagerImpl() { ::ncmExit(); } public: Result CreateContentStorage(StorageId storage_id) { return ::ncmCreateContentStorage(static_cast(storage_id)); @@ -100,5 +101,6 @@ namespace ams::ncm { } }; static_assert(ncm::IsIContentManager); + #endif } diff --git a/libraries/libstratosphere/source/ncm/ncm_remote_content_meta_database_impl.hpp b/libraries/libstratosphere/source/ncm/ncm_remote_content_meta_database_impl.hpp index da5d09378..f4a111ca8 100644 --- a/libraries/libstratosphere/source/ncm/ncm_remote_content_meta_database_impl.hpp +++ b/libraries/libstratosphere/source/ncm/ncm_remote_content_meta_database_impl.hpp @@ -18,6 +18,7 @@ namespace ams::ncm { + #if defined(ATMOSPHERE_OS_HORIZON) class RemoteContentMetaDatabaseImpl { private: ::NcmContentMetaDatabase m_srv; @@ -169,5 +170,6 @@ namespace ams::ncm { } }; static_assert(ncm::IsIContentMetaDatabase); + #endif } diff --git a/libraries/libstratosphere/source/ncm/ncm_remote_content_storage_impl.hpp b/libraries/libstratosphere/source/ncm/ncm_remote_content_storage_impl.hpp index 2e70fb189..255c6100b 100644 --- a/libraries/libstratosphere/source/ncm/ncm_remote_content_storage_impl.hpp +++ b/libraries/libstratosphere/source/ncm/ncm_remote_content_storage_impl.hpp @@ -18,6 +18,7 @@ namespace ams::ncm { + #if defined(ATMOSPHERE_OS_HORIZON) class RemoteContentStorageImpl { private: ::NcmContentStorage m_srv; @@ -209,5 +210,6 @@ namespace ams::ncm { } }; static_assert(ncm::IsIContentStorage); + #endif } diff --git a/libraries/libstratosphere/source/ncm/ncm_storage_utils.cpp b/libraries/libstratosphere/source/ncm/ncm_storage_utils.cpp index 3697df77e..313333801 100644 --- a/libraries/libstratosphere/source/ncm/ncm_storage_utils.cpp +++ b/libraries/libstratosphere/source/ncm/ncm_storage_utils.cpp @@ -80,28 +80,6 @@ namespace ams::ncm { return ResultSuccess(); } - namespace { - - constexpr const char * const StorageIdStrings[] = { - "None", - "Host", - "GameCard", - "BuiltInSystem", - "BuiltInUser", - "SdCard" - }; - - constexpr const char * const StorageIdStringsForPlayReport[] = { - "None", - "Host", - "Card", - "BuildInSystem", - "BuildInUser", - "SdCard" - }; - - } - const char *GetStorageIdString(StorageId storage_id) { switch (storage_id) { case StorageId::None: return "None"; diff --git a/libraries/libstratosphere/source/nim/nim_network_install_manager_api.cpp b/libraries/libstratosphere/source/nim/nim_network_install_manager_api.cpp index 509a5a80d..a2eaffd02 100644 --- a/libraries/libstratosphere/source/nim/nim_network_install_manager_api.cpp +++ b/libraries/libstratosphere/source/nim/nim_network_install_manager_api.cpp @@ -17,11 +17,13 @@ namespace ams::nim { + #if defined(ATMOSPHERE_OS_HORIZON) namespace { - bool g_initialized; + constinit bool g_initialized; } + /* Management. */ void InitializeForNetworkInstallManager() { AMS_ASSERT(!g_initialized); @@ -49,5 +51,24 @@ namespace ams::nim { return count; } + #else + /* Management. */ + void InitializeForNetworkInstallManager() { + AMS_ABORT("TODO: nim logic on non-libnx platform"); + } + + void FinalizeForNetworkInstallManager() { + AMS_ABORT("TODO: nim logic on non-libnx platform"); + } + + /* Service API. */ + Result DestroySystemUpdateTask(const SystemUpdateTaskId &) { + AMS_ABORT("TODO: nim logic on non-libnx platform"); + } + + s32 ListSystemUpdateTask(SystemUpdateTaskId *, size_t) { + AMS_ABORT("TODO: nim logic on non-libnx platform"); + } + #endif } diff --git a/libraries/libstratosphere/source/os/impl/os_address_space_allocator.hpp b/libraries/libstratosphere/source/os/impl/os_address_space_allocator.hpp index 80ca8137c..c8197a858 100644 --- a/libraries/libstratosphere/source/os/impl/os_address_space_allocator.hpp +++ b/libraries/libstratosphere/source/os/impl/os_address_space_allocator.hpp @@ -47,8 +47,8 @@ namespace ams::os::impl { } -#ifdef ATMOSPHERE_OS_HORIZON +#if defined(ATMOSPHERE_OS_HORIZON) #include "os_address_space_allocator_impl.os.horizon.hpp" #else - #error "Unknown OS for AddressSpaceAllocator" + #include "os_address_space_allocator_impl.generic.hpp" #endif diff --git a/libraries/libstratosphere/source/os/impl/os_address_space_allocator_impl.generic.hpp b/libraries/libstratosphere/source/os/impl/os_address_space_allocator_impl.generic.hpp new file mode 100644 index 000000000..abcd1de53 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_address_space_allocator_impl.generic.hpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 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::impl { + + class AddressSpaceAllocator final : public AddressSpaceAllocatorBase { + private: + using Base = AddressSpaceAllocatorBase; + public: + using Base::Base; + public: + virtual bool CheckFreeSpace(uintptr_t address, size_t size) override { + AMS_UNUSED(address, size); + return true; + } + }; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_aslr_space_manager_impl.os.linux.hpp b/libraries/libstratosphere/source/os/impl/os_aslr_space_manager_impl.os.linux.hpp new file mode 100644 index 000000000..20bf70cbc --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_aslr_space_manager_impl.os.linux.hpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 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_address_space_allocator_forbidden_region.hpp" + +namespace ams::os::impl { + + class AslrSpaceManagerLinuxImpl { + NON_COPYABLE(AslrSpaceManagerLinuxImpl); + NON_MOVEABLE(AslrSpaceManagerLinuxImpl); + public: + constexpr AslrSpaceManagerLinuxImpl() = default; + + static constexpr ALWAYS_INLINE const AddressSpaceAllocatorForbiddenRegion *GetForbiddenRegions() { + return nullptr; + } + + static constexpr ALWAYS_INLINE size_t GetForbiddenRegionCount() { + return 0; + } + + static constexpr ALWAYS_INLINE u64 GetHeapSpaceBeginAddress() { + return 8_GB; + } + + static constexpr ALWAYS_INLINE u64 GetHeapSpaceSize() { + return 4_GB; + } + + static constexpr ALWAYS_INLINE u64 GetAliasSpaceBeginAddress() { + return 60_GB; + } + + static constexpr ALWAYS_INLINE u64 GetAliasSpaceSize() { + return 4_GB; + } + + static constexpr ALWAYS_INLINE u64 GetAslrSpaceBeginAddress() { + return 2_MB; + } + + static constexpr ALWAYS_INLINE u64 GetAslrSpaceEndAddress() { + return 64_GB; + } + }; + + using AslrSpaceManagerImpl = AslrSpaceManagerLinuxImpl; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_aslr_space_manager_impl.os.macos.hpp b/libraries/libstratosphere/source/os/impl/os_aslr_space_manager_impl.os.macos.hpp new file mode 100644 index 000000000..20bf70cbc --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_aslr_space_manager_impl.os.macos.hpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 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_address_space_allocator_forbidden_region.hpp" + +namespace ams::os::impl { + + class AslrSpaceManagerLinuxImpl { + NON_COPYABLE(AslrSpaceManagerLinuxImpl); + NON_MOVEABLE(AslrSpaceManagerLinuxImpl); + public: + constexpr AslrSpaceManagerLinuxImpl() = default; + + static constexpr ALWAYS_INLINE const AddressSpaceAllocatorForbiddenRegion *GetForbiddenRegions() { + return nullptr; + } + + static constexpr ALWAYS_INLINE size_t GetForbiddenRegionCount() { + return 0; + } + + static constexpr ALWAYS_INLINE u64 GetHeapSpaceBeginAddress() { + return 8_GB; + } + + static constexpr ALWAYS_INLINE u64 GetHeapSpaceSize() { + return 4_GB; + } + + static constexpr ALWAYS_INLINE u64 GetAliasSpaceBeginAddress() { + return 60_GB; + } + + static constexpr ALWAYS_INLINE u64 GetAliasSpaceSize() { + return 4_GB; + } + + static constexpr ALWAYS_INLINE u64 GetAslrSpaceBeginAddress() { + return 2_MB; + } + + static constexpr ALWAYS_INLINE u64 GetAslrSpaceEndAddress() { + return 64_GB; + } + }; + + using AslrSpaceManagerImpl = AslrSpaceManagerLinuxImpl; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_aslr_space_manager_impl.os.windows.hpp b/libraries/libstratosphere/source/os/impl/os_aslr_space_manager_impl.os.windows.hpp new file mode 100644 index 000000000..54068dce6 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_aslr_space_manager_impl.os.windows.hpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 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_address_space_allocator_forbidden_region.hpp" + +namespace ams::os::impl { + + class AslrSpaceManagerWindowsImpl { + NON_COPYABLE(AslrSpaceManagerWindowsImpl); + NON_MOVEABLE(AslrSpaceManagerWindowsImpl); + public: + constexpr AslrSpaceManagerWindowsImpl() = default; + + static constexpr ALWAYS_INLINE const AddressSpaceAllocatorForbiddenRegion *GetForbiddenRegions() { + return nullptr; + } + + static constexpr ALWAYS_INLINE size_t GetForbiddenRegionCount() { + return 0; + } + + static constexpr ALWAYS_INLINE u64 GetHeapSpaceBeginAddress() { + return 8_GB; + } + + static constexpr ALWAYS_INLINE u64 GetHeapSpaceSize() { + return 4_GB; + } + + static constexpr ALWAYS_INLINE u64 GetAliasSpaceBeginAddress() { + return 60_GB; + } + + static constexpr ALWAYS_INLINE u64 GetAliasSpaceSize() { + return 4_GB; + } + + static constexpr ALWAYS_INLINE u64 GetAslrSpaceBeginAddress() { + return 2_MB; + } + + static constexpr ALWAYS_INLINE u64 GetAslrSpaceEndAddress() { + return 64_GB; + } + }; + + using AslrSpaceManagerImpl = AslrSpaceManagerWindowsImpl; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_aslr_space_manager_types.hpp b/libraries/libstratosphere/source/os/impl/os_aslr_space_manager_types.hpp index 8d0a45a62..91b99fda5 100644 --- a/libraries/libstratosphere/source/os/impl/os_aslr_space_manager_types.hpp +++ b/libraries/libstratosphere/source/os/impl/os_aslr_space_manager_types.hpp @@ -17,8 +17,14 @@ #include #include "os_address_space_allocator.hpp" -#ifdef ATMOSPHERE_OS_HORIZON +#if defined(ATMOSPHERE_OS_HORIZON) #include "os_aslr_space_manager_impl.os.horizon.hpp" +#elif defined(ATMOSPHERE_OS_WINDOWS) + #include "os_aslr_space_manager_impl.os.windows.hpp" +#elif defined(ATMOSPHERE_OS_LINUX) + #include "os_aslr_space_manager_impl.os.linux.hpp" +#elif defined(ATMOSPHERE_OS_MACOS) + #include "os_aslr_space_manager_impl.os.macos.hpp" #else #error "Unknown OS for AslrSpaceManagerImpl" #endif diff --git a/libraries/libstratosphere/source/os/impl/os_cache_impl.hpp b/libraries/libstratosphere/source/os/impl/os_cache_impl.hpp index 7b2830a3e..7d3a23f21 100644 --- a/libraries/libstratosphere/source/os/impl/os_cache_impl.hpp +++ b/libraries/libstratosphere/source/os/impl/os_cache_impl.hpp @@ -16,8 +16,14 @@ #pragma once #include -#ifdef ATMOSPHERE_OS_HORIZON +#if defined(ATMOSPHERE_OS_HORIZON) #include "os_cache_impl.os.horizon.hpp" +#elif defined(ATMOSPHERE_OS_WINDOWS) + #include "os_cache_impl.os.windows.hpp" +#elif defined(ATMOSPHERE_OS_LINUX) + #include "os_cache_impl.os.linux.hpp" +#elif defined(ATMOSPHERE_OS_MACOS) + #include "os_cache_impl.os.linux.hpp" #else - #error "Unknown OS for ThreadManagerImpl" + #error "Unknown OS for CacheImpl" #endif diff --git a/libraries/libstratosphere/source/os/impl/os_cache_impl.os.linux.hpp b/libraries/libstratosphere/source/os/impl/os_cache_impl.os.linux.hpp new file mode 100644 index 000000000..d1cff2ea7 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_cache_impl.os.linux.hpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 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::impl { + + inline void FlushDataCacheImpl(const void *addr, size_t size) { + #if defined(ATMOSPHERE_ARCH_ARM64) + { + /* Declare helper variables. */ + uintptr_t cache_type_register = 0; + uintptr_t cache_line_size = 0; + const uintptr_t end_addr = reinterpret_cast(addr) + size; + + /* Get the cache type register. */ + __asm__ __volatile__("mrs %[cache_type_register], ctr_el0" : [cache_type_register]"=r"(cache_type_register)); + + /* Calculate cache line size. */ + cache_line_size = 4 << ((cache_type_register >> 16) & 0xF); + + /* Iterate, flushing cache lines. */ + for (uintptr_t cur = reinterpret_cast(addr) & ~(cache_line_size - 1); cur < end_addr; cur += cache_line_size) { + __asm__ __volatile__ ("dc civac, %[cur]" :: [cur]"r"(cur)); + } + + /* Insert a memory barrier, now that memory has been flushed. */ + __asm__ __volatile__("dsb sy" ::: "memory"); + } + #elif defined(ATMOSPHERE_ARCH_X64) || defined(ATMOSPHERE_ARCH_X86) + /* Theoretically, do nothing here? */ + AMS_UNUSED(addr, size); + __asm__ __volatile__("" ::: "memory"); + #else + #error "Unknown architecture for linux DataCache" + #endif + } + + inline void FlushEntireDataCacheImpl() { + #if defined(ATMOSPHERE_ARCH_X64) || defined(ATMOSPHERE_ARCH_X86) + /* Theoretically, do nothing here? */ + __asm__ __volatile__("" ::: "memory"); + #elif defined(ATMOSPHERE_ARCH_ARM64) + AMS_ABORT("FlushEntireDataCacheImpl called on arm64 linux"); + #else + #error "Unknown architecture for linux DataCache" + #endif + } + +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/os/impl/os_cache_impl.os.macos.hpp b/libraries/libstratosphere/source/os/impl/os_cache_impl.os.macos.hpp new file mode 100644 index 000000000..4c6543ba9 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_cache_impl.os.macos.hpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 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::impl { + + inline void FlushDataCacheImpl(const void *addr, size_t size) { + #if defined(ATMOSPHERE_ARCH_ARM64) + { + /* Declare helper variables. */ + uintptr_t cache_type_register = 0; + uintptr_t cache_line_size = 0; + const uintptr_t end_addr = reinterpret_cast(addr) + size; + + /* Get the cache type register. */ + __asm__ __volatile__("mrs %[cache_type_register], ctr_el0" : [cache_type_register]"=r"(cache_type_register)); + + /* Calculate cache line size. */ + cache_line_size = 4 << ((cache_type_register >> 16) & 0xF); + + /* Iterate, flushing cache lines. */ + for (uintptr_t cur = reinterpret_cast(addr) & ~(cache_line_size - 1); cur < end_addr; cur += cache_line_size) { + __asm__ __volatile__ ("dc civac, %[cur]" :: [cur]"r"(cur)); + } + + /* Insert a memory barrier, now that memory has been flushed. */ + __asm__ __volatile__("dsb sy" ::: "memory"); + } + #elif defined(ATMOSPHERE_ARCH_X64) || defined(ATMOSPHERE_ARCH_X86) + /* Theoretically, do nothing here? */ + AMS_UNUSED(addr, size); + __asm__ __volatile__("" ::: "memory"); + #else + #error "Unknown architecture for macOS DataCache" + #endif + } + + inline void FlushEntireDataCacheImpl() { + #if defined(ATMOSPHERE_ARCH_X64) || defined(ATMOSPHERE_ARCH_X86) + /* Theoretically, do nothing here? */ + __asm__ __volatile__("" ::: "memory"); + #elif defined(ATMOSPHERE_ARCH_ARM64) + AMS_ABORT("FlushEntireDataCacheImpl called on arm64 macOS"); + #else + #error "Unknown architecture for macOS DataCache" + #endif + } + +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/os/impl/os_cache_impl.os.windows.hpp b/libraries/libstratosphere/source/os/impl/os_cache_impl.os.windows.hpp new file mode 100644 index 000000000..03885080f --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_cache_impl.os.windows.hpp @@ -0,0 +1,61 @@ +/* + * Copyright (c) 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::impl { + + inline void FlushDataCacheImpl(const void *addr, size_t size) { + #if defined(ATMOSPHERE_ARCH_ARM64) + { + /* Declare helper variables. */ + uintptr_t cache_type_register = 0; + uintptr_t cache_line_size = 0; + const uintptr_t end_addr = reinterpret_cast(addr) + size; + + /* Get the cache type register. */ + __asm__ __volatile__("mrs %[cache_type_register], ctr_el0" : [cache_type_register]"=r"(cache_type_register)); + + /* Calculate cache line size. */ + cache_line_size = 4 << ((cache_type_register >> 16) & 0xF); + + /* Iterate, flushing cache lines. */ + for (uintptr_t cur = reinterpret_cast(addr) & ~(cache_line_size - 1); cur < end_addr; cur += cache_line_size) { + __asm__ __volatile__ ("dc civac, %[cur]" :: [cur]"r"(cur)); + } + + /* Insert a memory barrier, now that memory has been flushed. */ + __asm__ __volatile__("dsb sy" ::: "memory"); + } + #elif defined(ATMOSPHERE_ARCH_X64) || defined(ATMOSPHERE_ARCH_X86) + /* Theoretically, do nothing here? */ + AMS_UNUSED(addr, size); + __asm__ __volatile__("" ::: "memory"); + #else + #error "Unknown architecture for windows DataCache" + #endif + } + + inline void FlushEntireDataCacheImpl() { + #if defined(ATMOSPHERE_ARCH_X64) || defined(ATMOSPHERE_ARCH_X86) + /* Theoretically, do nothing here? */ + __asm__ __volatile__("" ::: "memory"); + #else + #error "Unknown architecture for windows DataCache" + #endif + } + +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/os/impl/os_giant_lock.hpp b/libraries/libstratosphere/source/os/impl/os_giant_lock.hpp new file mode 100644 index 000000000..9ef695455 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_giant_lock.hpp @@ -0,0 +1,27 @@ +/* + * Copyright (c) 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_giant_lock_types.hpp" +#include "os_resource_manager.hpp" + +namespace ams::os::impl { + + ALWAYS_INLINE GiantLock &GetGiantLock() { + return GetResourceManager().GetGiantLock(); + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_giant_lock.os.horizon.hpp b/libraries/libstratosphere/source/os/impl/os_giant_lock.os.horizon.hpp new file mode 100644 index 000000000..5abe5d147 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_giant_lock.os.horizon.hpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) 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::impl { + + class GiantLockHorizonImpl{}; + + using GiantLock = GiantLockHorizonImpl; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_giant_lock.os.linux.cpp b/libraries/libstratosphere/source/os/impl/os_giant_lock.os.linux.cpp new file mode 100644 index 000000000..d16c3e0a5 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_giant_lock.os.linux.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 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 "os_giant_lock.os.linux.hpp" +#include +#include +#include + +namespace ams::os::impl { + + #define AMS_OS_IMPL_GIANT_LOCK_FILE_PATH "/tmp/.ams_os_giant_lock" + + void GiantLockLinuxImpl::Lock() { + m_fd = ::open(AMS_OS_IMPL_GIANT_LOCK_FILE_PATH, O_RDWR | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR); + AMS_ABORT_UNLESS(m_fd >= 0); + + while (::lockf(m_fd, F_LOCK, 0) < 0) { + AMS_ABORT_UNLESS(errno == EINTR); + } + } + + void GiantLockLinuxImpl::Unlock() { + AMS_ASSERT(m_fd >= 0); + + while (::lockf(m_fd, F_ULOCK, 0) < 0) { + AMS_ABORT_UNLESS(errno == EINTR); + } + + while (::close(m_fd) < 0) { + AMS_ABORT_UNLESS(errno == EINTR); + } + + m_fd = os::InvalidNativeHandle; + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_giant_lock.os.linux.hpp b/libraries/libstratosphere/source/os/impl/os_giant_lock.os.linux.hpp new file mode 100644 index 000000000..d5846424c --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_giant_lock.os.linux.hpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 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::impl { + + class GiantLockLinuxImpl { + private: + s32 m_fd = -1; + public: + void Lock(); + void Unlock(); + + ALWAYS_INLINE void lock() { + this->Lock(); + } + + ALWAYS_INLINE void unlock() { + this->Unlock(); + } + }; + + using GiantLock = GiantLockLinuxImpl; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_giant_lock.os.macos.cpp b/libraries/libstratosphere/source/os/impl/os_giant_lock.os.macos.cpp new file mode 100644 index 000000000..f565a5976 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_giant_lock.os.macos.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 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 "os_giant_lock.os.macos.hpp" +#include +#include +#include + +namespace ams::os::impl { + + #define AMS_OS_IMPL_GIANT_LOCK_FILE_PATH "/tmp/.ams_os_giant_lock" + + void GiantLockMacosImpl::Lock() { + m_fd = ::open(AMS_OS_IMPL_GIANT_LOCK_FILE_PATH, O_RDWR | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR); + AMS_ABORT_UNLESS(m_fd >= 0); + + while (::lockf(m_fd, F_LOCK, 0) < 0) { + AMS_ABORT_UNLESS(errno == EINTR); + } + } + + void GiantLockMacosImpl::Unlock() { + AMS_ASSERT(m_fd >= 0); + + while (::lockf(m_fd, F_ULOCK, 0) < 0) { + AMS_ABORT_UNLESS(errno == EINTR); + } + + while (::close(m_fd) < 0) { + AMS_ABORT_UNLESS(errno == EINTR); + } + + m_fd = os::InvalidNativeHandle; + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_giant_lock.os.macos.hpp b/libraries/libstratosphere/source/os/impl/os_giant_lock.os.macos.hpp new file mode 100644 index 000000000..c079857d9 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_giant_lock.os.macos.hpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 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::impl { + + class GiantLockMacosImpl { + private: + s32 m_fd = -1; + public: + void Lock(); + void Unlock(); + + ALWAYS_INLINE void lock() { + this->Lock(); + } + + ALWAYS_INLINE void unlock() { + this->Unlock(); + } + }; + + using GiantLock = GiantLockMacosImpl; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_giant_lock.os.windows.cpp b/libraries/libstratosphere/source/os/impl/os_giant_lock.os.windows.cpp new file mode 100644 index 000000000..2116689cc --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_giant_lock.os.windows.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 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 "os_giant_lock.os.windows.hpp" + +namespace ams::os::impl { + + GiantLockWindowsImpl::GiantLockWindowsImpl() { + const NativeHandle handle = ::CreateMutexA(nullptr, false, "AMS_OS_STRATOSPHERE_GIANT_LOCK"); + AMS_ASSERT(handle != InvalidNativeHandle); + + m_handle = handle; + } + + GiantLockWindowsImpl::~GiantLockWindowsImpl() { + const auto ret = ::CloseHandle(m_handle); + AMS_ASSERT(ret != 0); + AMS_UNUSED(ret); + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_giant_lock.os.windows.hpp b/libraries/libstratosphere/source/os/impl/os_giant_lock.os.windows.hpp new file mode 100644 index 000000000..8776ae395 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_giant_lock.os.windows.hpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 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::impl { + + class GiantLockWindowsImpl { + private: + NativeHandle m_handle; + public: + GiantLockWindowsImpl(); + ~GiantLockWindowsImpl(); + + ALWAYS_INLINE void lock() { + ::WaitForSingleObject(m_handle, INFINITE); + } + + ALWAYS_INLINE void unlock() { + ::ReleaseMutex(m_handle); + } + }; + + using GiantLock = GiantLockWindowsImpl; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_giant_lock_types.hpp b/libraries/libstratosphere/source/os/impl/os_giant_lock_types.hpp new file mode 100644 index 000000000..734af2de6 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_giant_lock_types.hpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 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 + +#if defined(ATMOSPHERE_OS_HORIZON) + #include "os_giant_lock.os.horizon.hpp" +#elif defined(ATMOSPHERE_OS_WINDOWS) + #include "os_giant_lock.os.windows.hpp" +#elif defined(ATMOSPHERE_OS_LINUX) + #include "os_giant_lock.os.linux.hpp" +#elif defined(ATMOSPHERE_OS_MACOS) + #include "os_giant_lock.os.macos.hpp" +#else + #error "Unknown OS for GiantLock" +#endif diff --git a/libraries/libstratosphere/source/os/os_stratosphere_api.os.horizon.cpp b/libraries/libstratosphere/source/os/impl/os_initialize.os.horizon.cpp similarity index 95% rename from libraries/libstratosphere/source/os/os_stratosphere_api.os.horizon.cpp rename to libraries/libstratosphere/source/os/impl/os_initialize.os.horizon.cpp index 7651ae886..fbea1a802 100644 --- a/libraries/libstratosphere/source/os/os_stratosphere_api.os.horizon.cpp +++ b/libraries/libstratosphere/source/os/impl/os_initialize.os.horizon.cpp @@ -14,7 +14,7 @@ * along with this program. If not, see . */ #include -#include "impl/os_resource_manager.hpp" +#include "os_resource_manager.hpp" extern "C" { extern u8 __argdata__[]; } @@ -134,13 +134,19 @@ namespace ams::os { return idx; } - } void SetHostArgc(int argc); void SetHostArgv(char **argv); - void InitializeForStratosphereInternal() { + void Initialize() { + /* Only allow os::Initialize to be called once. */ + AMS_FUNCTION_LOCAL_STATIC_CONSTINIT(bool, s_initialized, false); + if (s_initialized) { + return; + } + s_initialized = true; + /* Initialize the global os resource manager. */ os::impl::ResourceManagerHolder::InitializeResourceManagerInstance(); diff --git a/libraries/libstratosphere/source/os/impl/os_initialize.os.linux.cpp b/libraries/libstratosphere/source/os/impl/os_initialize.os.linux.cpp new file mode 100644 index 000000000..448169f9e --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_initialize.os.linux.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 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 "os_resource_manager.hpp" + +namespace ams { + + void Main(); + + namespace init { + + void InitializeDefaultAllocator(); + + } + + /* TODO: This should probably instead be a custom init::Initialize*()? */ + namespace fs { + + void InitializeForHostTool(); + + } + +} + +namespace ams::os { + + void SetHostArgc(int argc); + void SetHostArgv(char **argv); + + [[gnu::constructor(101)]] void Initialize() { + /* Only allow os::Initialize to be called once. */ + AMS_FUNCTION_LOCAL_STATIC_CONSTINIT(bool, s_initialized, false); + if (s_initialized) { + return; + } + s_initialized = true; + + /* Initialize the global os resource manager. */ + os::impl::ResourceManagerHolder::InitializeResourceManagerInstance(); + + /* Initialize virtual address memory. */ + os::InitializeVirtualAddressMemory(); + + /* Ensure that the init library's allocator has been setup. */ + init::InitializeDefaultAllocator(); + } + +} + +extern "C" int main(int argc, char **argv) { + /* Ensure os library is initialized. */ + ::ams::os::Initialize(); + + /* Set argc/argv. */ + ::ams::os::SetHostArgc(argc); + ::ams::os::SetHostArgv(argv); + + /* Ensure filesystem library is initialized. */ + ::ams::fs::InitializeForHostTool(); + + /* Call main. */ + ::ams::Main(); + + /* TODO: Should we try to implement a custom exit here? */ + return 0; +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/os/impl/os_initialize.os.macos.cpp b/libraries/libstratosphere/source/os/impl/os_initialize.os.macos.cpp new file mode 100644 index 000000000..448169f9e --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_initialize.os.macos.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 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 "os_resource_manager.hpp" + +namespace ams { + + void Main(); + + namespace init { + + void InitializeDefaultAllocator(); + + } + + /* TODO: This should probably instead be a custom init::Initialize*()? */ + namespace fs { + + void InitializeForHostTool(); + + } + +} + +namespace ams::os { + + void SetHostArgc(int argc); + void SetHostArgv(char **argv); + + [[gnu::constructor(101)]] void Initialize() { + /* Only allow os::Initialize to be called once. */ + AMS_FUNCTION_LOCAL_STATIC_CONSTINIT(bool, s_initialized, false); + if (s_initialized) { + return; + } + s_initialized = true; + + /* Initialize the global os resource manager. */ + os::impl::ResourceManagerHolder::InitializeResourceManagerInstance(); + + /* Initialize virtual address memory. */ + os::InitializeVirtualAddressMemory(); + + /* Ensure that the init library's allocator has been setup. */ + init::InitializeDefaultAllocator(); + } + +} + +extern "C" int main(int argc, char **argv) { + /* Ensure os library is initialized. */ + ::ams::os::Initialize(); + + /* Set argc/argv. */ + ::ams::os::SetHostArgc(argc); + ::ams::os::SetHostArgv(argv); + + /* Ensure filesystem library is initialized. */ + ::ams::fs::InitializeForHostTool(); + + /* Call main. */ + ::ams::Main(); + + /* TODO: Should we try to implement a custom exit here? */ + return 0; +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/os/impl/os_initialize.os.windows.cpp b/libraries/libstratosphere/source/os/impl/os_initialize.os.windows.cpp new file mode 100644 index 000000000..0b279238c --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_initialize.os.windows.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (c) 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 "os_resource_manager.hpp" + +namespace ams { + + void Main(); + + namespace init { + + void InitializeDefaultAllocator(); + + } + + /* TODO: This should probably instead be a custom init::Initialize*()? */ + namespace fs { + + void InitializeForHostTool(); + + } + +} + +namespace ams::os { + + void SetHostArgc(int argc); + void SetHostArgv(char **argv); + + namespace { + + void SetupWindowsConsole(DWORD which) { + /* Get handle to standard device. */ + const auto handle = ::GetStdHandle(which); + if (handle == INVALID_HANDLE_VALUE) { + return; + } + + /* Get the console mode. */ + DWORD mode; + if (!::GetConsoleMode(handle, std::addressof(mode))) { + return; + } + + /* Enable printing with ANSI escape codes. */ + mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + + /* Set console mode. */ + ::SetConsoleMode(handle, mode); + } + + } + + void Initialize() { + /* Only allow os::Initialize to be called once. */ + AMS_FUNCTION_LOCAL_STATIC_CONSTINIT(bool, s_initialized, false); + if (s_initialized) { + return; + } + s_initialized = true; + + /* Initialize the global os resource manager. */ + os::impl::ResourceManagerHolder::InitializeResourceManagerInstance(); + + /* Initialize virtual address memory. */ + os::InitializeVirtualAddressMemory(); + + /* Ensure that the init library's allocator has been setup. */ + init::InitializeDefaultAllocator(); + + /* Try to set up the windows console. */ + SetupWindowsConsole(STD_OUTPUT_HANDLE); + SetupWindowsConsole(STD_ERROR_HANDLE); + } + +} + +extern "C" int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { + /* Ensure os library is initialized. */ + ::ams::os::Initialize(); + + /* Set argc/argv. */ + ::ams::os::SetHostArgc(__argc); + ::ams::os::SetHostArgv(__argv); + + /* Ensure filesystem library is initialized. */ + ::ams::fs::InitializeForHostTool(); + + /* Call main. */ + ::ams::Main(); + + /* TODO: Should we try to implement a custom exit here? */ + return 0; +} diff --git a/libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.hpp b/libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.hpp index f3b72d929..10a251fb4 100644 --- a/libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.hpp +++ b/libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.hpp @@ -18,6 +18,12 @@ #if defined(ATMOSPHERE_OS_HORIZON) #include "os_inter_process_event_impl.os.horizon.hpp" +#elif defined(ATMOSPHERE_OS_WINDOWS) + #include "os_inter_process_event_impl.os.windows.hpp" +#elif defined(ATMOSPHERE_OS_LINUX) + #include "os_inter_process_event_impl.os.linux.hpp" +#elif defined(ATMOSPHERE_OS_MACOS) + #include "os_inter_process_event_impl.os.macos.hpp" #else #error "Unknown OS for ams::os::InterProcessEventImpl" #endif \ No newline at end of file diff --git a/libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.os.horizon.cpp b/libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.os.horizon.cpp index 5db8cbbc0..5d75b31e2 100644 --- a/libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.os.horizon.cpp +++ b/libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.os.horizon.cpp @@ -20,7 +20,7 @@ namespace ams::os::impl { - Result InterProcessEventImpl::Create(NativeHandle *out_write, NativeHandle *out_read) { + Result InterProcessEventHorizonImpl::Create(NativeHandle *out_write, NativeHandle *out_read) { /* Create the event handles. */ svc::Handle wh, rh; R_TRY_CATCH(svc::CreateEvent(std::addressof(wh), std::addressof(rh))) { @@ -32,21 +32,21 @@ namespace ams::os::impl { return ResultSuccess(); } - void InterProcessEventImpl::Close(NativeHandle handle) { + void InterProcessEventHorizonImpl::Close(NativeHandle handle) { if (handle != os::InvalidNativeHandle) { R_ABORT_UNLESS(svc::CloseHandle(handle)); } } - void InterProcessEventImpl::Signal(NativeHandle handle) { + void InterProcessEventHorizonImpl::Signal(NativeHandle handle) { R_ABORT_UNLESS(svc::SignalEvent(handle)); } - void InterProcessEventImpl::Clear(NativeHandle handle) { + void InterProcessEventHorizonImpl::Clear(NativeHandle handle) { R_ABORT_UNLESS(svc::ClearEvent(handle)); } - void InterProcessEventImpl::Wait(NativeHandle handle, bool auto_clear) { + void InterProcessEventHorizonImpl::Wait(NativeHandle handle, bool auto_clear) { while (true) { /* Continuously wait, until success. */ s32 index; @@ -67,7 +67,7 @@ namespace ams::os::impl { } } - bool InterProcessEventImpl::TryWait(NativeHandle handle, bool auto_clear) { + bool InterProcessEventHorizonImpl::TryWait(NativeHandle handle, bool auto_clear) { /* If we're auto clear, just try to reset. */ if (auto_clear) { return R_SUCCEEDED(svc::ResetSignal(handle)); @@ -93,7 +93,7 @@ namespace ams::os::impl { } } - bool InterProcessEventImpl::TimedWait(NativeHandle handle, bool auto_clear, TimeSpan timeout) { + bool InterProcessEventHorizonImpl::TimedWait(NativeHandle handle, bool auto_clear, TimeSpan timeout) { TimeoutHelper timeout_helper(timeout); while (true) { diff --git a/libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.os.horizon.hpp b/libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.os.horizon.hpp index b13b783a7..eb6d2b16b 100644 --- a/libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.os.horizon.hpp +++ b/libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.os.horizon.hpp @@ -18,7 +18,7 @@ namespace ams::os::impl { - class InterProcessEventImpl { + class InterProcessEventHorizonImpl { public: static Result Create(NativeHandle *out_write, NativeHandle *out_read); static void Close(NativeHandle handle); @@ -29,4 +29,6 @@ namespace ams::os::impl { static bool TimedWait(NativeHandle handle, bool auto_clear, TimeSpan timeout); }; + using InterProcessEventImpl = InterProcessEventHorizonImpl; + } \ No newline at end of file diff --git a/libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.os.linux.cpp b/libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.os.linux.cpp new file mode 100644 index 000000000..2fd362396 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.os.linux.cpp @@ -0,0 +1,169 @@ +/* + * Copyright (c) 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 "os_inter_process_event.hpp" +#include "os_inter_process_event_impl.os.linux.hpp" +#include "os_timeout_helper.hpp" + +#include +#include +#include + +namespace ams::os::impl { + + namespace { + + bool PollEvent(NativeHandle handle, s64 ns) { + struct pollfd pfd; + pfd.fd = handle; + pfd.events = POLLIN; + pfd.revents = 0; + + /* Determine timeout. */ + constexpr s64 NanoSecondsPerSecond = TimeSpan::FromSeconds(1).GetNanoSeconds(); + struct timespec ts = { .tv_sec = (ns / NanoSecondsPerSecond), .tv_nsec = ns % NanoSecondsPerSecond }; + + s32 res; + do { + res = ::ppoll(std::addressof(pfd), 1, ns >= 0 ? std::addressof(ts) : nullptr, nullptr); + } while (res < 0 && errno == EINTR); + + AMS_ASSERT(res == 0); + return pfd.revents & POLLIN; + } + + } + + bool InterProcessEventLinuxImpl::ResetEventSignal(NativeHandle handle) { + u64 dummy; + s32 res; + do { + res = ::read(handle, std::addressof(dummy), sizeof(dummy)); + } while (res < 0 && errno == EINTR); + + AMS_ASSERT(res == sizeof(u64) || (res < 0 && errno == EAGAIN)); + if (res == sizeof(u64)) { + AMS_ASSERT(dummy > 0); + } + + return res == sizeof(u64); + } + + Result InterProcessEventLinuxImpl::CreateSingle(NativeHandle *out_event) { + /* Create the event handle. */ + os::NativeHandle event; + do { + event = ::eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); + } while (event < 0 && errno == EINTR); + R_UNLESS(event != os::InvalidNativeHandle, os::ResultOutOfResource()); + + /* Set the output. */ + *out_event = event; + R_SUCCEED(); + } + + Result InterProcessEventLinuxImpl::Create(NativeHandle *out_write, NativeHandle *out_read) { + /* Create the writable handle. */ + os::NativeHandle write; + R_TRY(CreateSingle(std::addressof(write))); + ON_RESULT_FAILURE { Close(write); }; + + /* Create the read handle. */ + os::NativeHandle read; + do { + read = ::dup(write); + } while (read < 0 && errno == EINTR); + R_UNLESS(read != os::InvalidNativeHandle, os::ResultOutOfResource()); + + /* Set the output. */ + *out_write = write; + *out_read = read; + R_SUCCEED(); + } + + void InterProcessEventLinuxImpl::Close(NativeHandle handle) { + if (handle != os::InvalidNativeHandle) { + s32 ret; + do { + ret = ::close(handle); + } while (ret < 0 && errno == EINTR); + AMS_ASSERT(ret == 0); + } + } + + void InterProcessEventLinuxImpl::Signal(NativeHandle handle) { + const u64 counter_add = 1; + + s32 ret; + do { + ret = ::write(handle, std::addressof(counter_add), sizeof(counter_add)); + } while (ret < 0 && errno == EINTR); + AMS_ASSERT(ret == sizeof(counter_add)); + } + + void InterProcessEventLinuxImpl::Clear(NativeHandle handle) { + ResetEventSignal(handle); + } + + void InterProcessEventLinuxImpl::Wait(NativeHandle handle, bool auto_clear) { + while (true) { + /* Continuously wait, until success. */ + auto ret = PollEvent(handle, -1); + AMS_ASSERT(ret); + AMS_UNUSED(ret); + + /* If we're not obligated to clear, we're done. */ + if (!auto_clear) { + return; + } + + /* Try to reset. */ + if (ResetEventSignal(handle)) { + return; + } + } + } + + bool InterProcessEventLinuxImpl::TryWait(NativeHandle handle, bool auto_clear) { + /* If we're auto clear, just try to reset. */ + if (auto_clear) { + return ResetEventSignal(handle); + } + + return PollEvent(handle, 0); + } + + bool InterProcessEventLinuxImpl::TimedWait(NativeHandle handle, bool auto_clear, TimeSpan timeout) { + TimeoutHelper timeout_helper(timeout); + + do { + if (const auto res = PollEvent(handle, timeout_helper.GetTimeLeftOnTarget().GetNanoSeconds()); res) { + /* If we're not obligated to clear, we're done. */ + if (!auto_clear) { + return true; + } + + /* Try to reset. */ + if (ResetEventSignal(handle)) { + return true; + } + } + } while (!timeout_helper.TimedOut()); + + return false; + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.os.linux.hpp b/libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.os.linux.hpp new file mode 100644 index 000000000..d17324237 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.os.linux.hpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 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::impl { + + class InterProcessEventLinuxImpl { + public: + static Result CreateSingle(NativeHandle *out_event); + static Result Create(NativeHandle *out_write, NativeHandle *out_read); + static void Close(NativeHandle handle); + static void Signal(NativeHandle handle); + static void Clear(NativeHandle handle); + static void Wait(NativeHandle handle, bool auto_clear); + static bool TryWait(NativeHandle handle, bool auto_clear); + static bool TimedWait(NativeHandle handle, bool auto_clear, TimeSpan timeout); + private: + static bool ResetEventSignal(NativeHandle handle); + }; + + using InterProcessEventImpl = InterProcessEventLinuxImpl; + +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.os.macos.cpp b/libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.os.macos.cpp new file mode 100644 index 000000000..486a1b8f8 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.os.macos.cpp @@ -0,0 +1,172 @@ +/* + * Copyright (c) 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 "os_inter_process_event.hpp" +#include "os_inter_process_event_impl.os.macos.hpp" +#include "os_timeout_helper.hpp" + +#include +#include +#include + +namespace ams::os::impl { + + namespace { + + /* On macOS, the maximum size of a pipe buffer is 64_KB. */ + static constexpr size_t PipeBufferSizeMax = 64_KB; + + constinit char g_shared_pipe_read_buffer[PipeBufferSizeMax]; + + bool PollEvent(NativeHandle handle, s64 ns) { + struct pollfd pfd; + pfd.fd = handle; + pfd.events = POLLIN; + pfd.revents = 0; + + /* Determine timeout. */ + constexpr s64 NanoSecondsPerMilliSecond = TimeSpan::FromMilliSeconds(1).GetNanoSeconds(); + + /* TODO: Will macos ever support ppoll? */ + const int timeout = static_cast(ns >= 0 ? (ns / NanoSecondsPerMilliSecond) : -1); + + s32 res; + do { + res = ::poll(std::addressof(pfd), 1, timeout); + } while (res < 0 && errno == EINTR); + + AMS_ASSERT(res == 0); + return pfd.revents & POLLIN; + } + + } + + bool InterProcessEventMacosImpl::ResetEventSignal(NativeHandle handle) { + s32 res; + do { + res = ::read(handle, g_shared_pipe_read_buffer, sizeof(g_shared_pipe_read_buffer)); + } while (res < 0 && errno == EINTR); + + if (res > 0) { + AMS_ASSERT(res <= static_cast(sizeof(g_shared_pipe_read_buffer))); + } else { + AMS_ASSERT(res < 0); + AMS_ASSERT(errno == EAGAIN); + } + + return res > 0; + } + + Result InterProcessEventMacosImpl::Create(NativeHandle *out_write, NativeHandle *out_read) { + /* Create the handles. */ + os::NativeHandle handles[2]; + s32 res; + do { + res = ::pipe(handles); + } while (res < 0 && errno == EINTR); + R_UNLESS(res == 0, os::ResultOutOfResource()); + ON_RESULT_FAILURE { Close(handles[0]); Close(handles[1]); }; + + /* Set as non-blocking. */ + do { + res = ::fcntl(handles[0], F_SETFL, O_NONBLOCK); + } while (res < 0 && errno == EINTR); + R_UNLESS(res == 0, os::ResultOutOfResource()); + + do { + res = ::fcntl(handles[1], F_SETFL, O_NONBLOCK); + } while (res < 0 && errno == EINTR); + R_UNLESS(res == 0, os::ResultOutOfResource()); + + /* Set the output. */ + *out_read = handles[0]; + *out_write = handles[1]; + R_SUCCEED(); + } + + void InterProcessEventMacosImpl::Close(NativeHandle handle) { + if (handle != os::InvalidNativeHandle) { + s32 ret; + do { + ret = ::close(handle); + } while (ret < 0 && errno == EINTR); + AMS_ASSERT(ret == 0); + } + } + + void InterProcessEventMacosImpl::Signal(NativeHandle handle) { + const u8 data = 0xCC; + + s32 ret; + do { + ret = ::write(handle, std::addressof(data), sizeof(data)); + } while (ret < 0 && errno == EINTR); + AMS_ASSERT(ret == sizeof(data) || (ret < 0 && errno == EAGAIN)); + } + + void InterProcessEventMacosImpl::Clear(NativeHandle handle) { + ResetEventSignal(handle); + } + + void InterProcessEventMacosImpl::Wait(NativeHandle handle, bool auto_clear) { + while (true) { + /* Continuously wait, until success. */ + auto ret = PollEvent(handle, -1); + AMS_ASSERT(ret); + AMS_UNUSED(ret); + + /* If we're not obligated to clear, we're done. */ + if (!auto_clear) { + return; + } + + /* Try to reset. */ + if (ResetEventSignal(handle)) { + return; + } + } + } + + bool InterProcessEventMacosImpl::TryWait(NativeHandle handle, bool auto_clear) { + /* If we're auto clear, just try to reset. */ + if (auto_clear) { + return ResetEventSignal(handle); + } + + return PollEvent(handle, 0); + } + + bool InterProcessEventMacosImpl::TimedWait(NativeHandle handle, bool auto_clear, TimeSpan timeout) { + TimeoutHelper timeout_helper(timeout); + + do { + if (const auto res = PollEvent(handle, timeout_helper.GetTimeLeftOnTarget().GetNanoSeconds()); res) { + /* If we're not obligated to clear, we're done. */ + if (!auto_clear) { + return true; + } + + /* Try to reset. */ + if (ResetEventSignal(handle)) { + return true; + } + } + } while (!timeout_helper.TimedOut()); + + return false; + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.os.macos.hpp b/libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.os.macos.hpp new file mode 100644 index 000000000..e4c9e67d2 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.os.macos.hpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 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::impl { + + class InterProcessEventMacosImpl { + public: + static Result Create(NativeHandle *out_write, NativeHandle *out_read); + static void Close(NativeHandle handle); + static void Signal(NativeHandle handle); + static void Clear(NativeHandle handle); + static void Wait(NativeHandle handle, bool auto_clear); + static bool TryWait(NativeHandle handle, bool auto_clear); + static bool TimedWait(NativeHandle handle, bool auto_clear, TimeSpan timeout); + private: + static bool ResetEventSignal(NativeHandle handle); + }; + + using InterProcessEventImpl = InterProcessEventMacosImpl; + +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.os.windows.cpp b/libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.os.windows.cpp new file mode 100644 index 000000000..dc7d2caed --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.os.windows.cpp @@ -0,0 +1,124 @@ +/* + * Copyright (c) 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 "os_inter_process_event.hpp" +#include "os_inter_process_event_impl.os.windows.hpp" +#include "os_giant_lock.hpp" +#include "os_timeout_helper.hpp" + +namespace ams::os::impl { + + bool InterProcessEventWindowsImpl::ResetEventSignal(NativeHandle handle) { + std::scoped_lock lk(GetGiantLock()); + + if (auto ret = ::WaitForSingleObject(handle, 0); ret == WAIT_OBJECT_0) { + ::ResetEvent(handle); + return true; + } else { + return false; + } + } + + Result InterProcessEventWindowsImpl::Create(NativeHandle *out_write, NativeHandle *out_read) { + /* Create the writable handle. */ + auto write = ::CreateEvent(nullptr, true, false, nullptr); + AMS_ASSERT(write != os::InvalidNativeHandle); + + /* Create the read handle. */ + os::NativeHandle read; + const auto cur_proc = ::GetCurrentProcess(); + const auto ret = ::DuplicateHandle(cur_proc, write, cur_proc, std::addressof(read), 0, false, DUPLICATE_SAME_ACCESS); + AMS_ASSERT(ret != 0); + AMS_UNUSED(ret); + + /* Set the output. */ + *out_write = write; + *out_read = read; + R_SUCCEED(); + } + + void InterProcessEventWindowsImpl::Close(NativeHandle handle) { + if (handle != os::InvalidNativeHandle) { + const auto ret = ::CloseHandle(handle); + AMS_ASSERT(ret != 0); + AMS_UNUSED(ret); + } + } + + void InterProcessEventWindowsImpl::Signal(NativeHandle handle) { + const auto ret = ::SetEvent(handle); + AMS_ASSERT(ret != 0); + AMS_UNUSED(ret); + } + + void InterProcessEventWindowsImpl::Clear(NativeHandle handle) { + const auto ret = ::ResetEvent(handle); + AMS_ASSERT(ret != 0); + AMS_UNUSED(ret); + } + + void InterProcessEventWindowsImpl::Wait(NativeHandle handle, bool auto_clear) { + while (true) { + /* Continuously wait, until success. */ + auto ret = ::WaitForSingleObject(handle, INFINITE); + AMS_ASSERT(ret == WAIT_OBJECT_0); + AMS_UNUSED(ret); + + /* If we're not obligated to clear, we're done. */ + if (!auto_clear) { + return; + } + + /* Try to reset. */ + if (ResetEventSignal(handle)) { + return; + } + } + } + + bool InterProcessEventWindowsImpl::TryWait(NativeHandle handle, bool auto_clear) { + /* If we're auto clear, just try to reset. */ + if (auto_clear) { + return ResetEventSignal(handle); + } + + const auto ret = ::WaitForSingleObject(handle, 0); + AMS_ASSERT((ret == WAIT_OBJECT_0) || (ret == WAIT_TIMEOUT)); + + return ret == WAIT_OBJECT_0; + } + + bool InterProcessEventWindowsImpl::TimedWait(NativeHandle handle, bool auto_clear, TimeSpan timeout) { + TimeoutHelper timeout_helper(timeout); + + do { + if (const auto res = ::WaitForSingleObject(handle, timeout_helper.GetTimeLeftOnTarget()); res == WAIT_OBJECT_0) { + /* If we're not obligated to clear, we're done. */ + if (!auto_clear) { + return true; + } + + /* Try to reset. */ + if (ResetEventSignal(handle)) { + return true; + } + } + } while (!timeout_helper.TimedOut()); + + return false; + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.os.windows.hpp b/libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.os.windows.hpp new file mode 100644 index 000000000..3b1e30a56 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.os.windows.hpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 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::impl { + + class InterProcessEventWindowsImpl { + public: + static Result Create(NativeHandle *out_write, NativeHandle *out_read); + static void Close(NativeHandle handle); + static void Signal(NativeHandle handle); + static void Clear(NativeHandle handle); + static void Wait(NativeHandle handle, bool auto_clear); + static bool TryWait(NativeHandle handle, bool auto_clear); + static bool TimedWait(NativeHandle handle, bool auto_clear, TimeSpan timeout); + private: + static bool ResetEventSignal(NativeHandle handle); + }; + + using InterProcessEventImpl = InterProcessEventWindowsImpl; + +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/os/impl/os_internal_condition_variable_impl.os.windows.cpp b/libraries/libstratosphere/source/os/impl/os_internal_condition_variable_impl.os.windows.cpp new file mode 100644 index 000000000..d683e9696 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_internal_condition_variable_impl.os.windows.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) 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 "os_internal_critical_section_impl.os.windows.hpp" +#include "os_timeout_helper.hpp" +#include "os_thread_manager.hpp" + +namespace ams::os::impl { + + struct WindowsConditionVariable { + CONDITION_VARIABLE cv; + }; + + void InternalConditionVariableImpl::Initialize() { + ::InitializeConditionVariable(std::addressof(util::GetReference(m_windows_cv_storage).cv)); + } + + void InternalConditionVariableImpl::Finalize() { + /* ... */ + } + + void InternalConditionVariableImpl::Signal() { + ::WakeConditionVariable(std::addressof(util::GetReference(m_windows_cv_storage).cv)); + } + + void InternalConditionVariableImpl::Broadcast() { + ::WakeAllConditionVariable(std::addressof(util::GetReference(m_windows_cv_storage).cv)); + } + + void InternalConditionVariableImpl::Wait(InternalCriticalSection *cs) { + ::SleepConditionVariableCS(std::addressof(util::GetReference(m_windows_cv_storage).cv), std::addressof(util::GetReference(cs->Get()->m_windows_critical_section_storage).cs), INFINITE); + } + + ConditionVariableStatus InternalConditionVariableImpl::TimedWait(InternalCriticalSection *cs, const TimeoutHelper &timeout_helper) { + const auto ret = ::SleepConditionVariableCS(std::addressof(util::GetReference(m_windows_cv_storage).cv), std::addressof(util::GetReference(cs->Get()->m_windows_critical_section_storage).cs), timeout_helper.GetTimeLeftOnTarget()); + if (ret == 0) { + if (::GetLastError() == ERROR_TIMEOUT) { + return ConditionVariableStatus::TimedOut; + } + } + + return ConditionVariableStatus::Success; + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_internal_condition_variable_impl.pthread.cpp b/libraries/libstratosphere/source/os/impl/os_internal_condition_variable_impl.pthread.cpp new file mode 100644 index 000000000..225bb4901 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_internal_condition_variable_impl.pthread.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 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 "os_timeout_helper.hpp" +#include "os_thread_manager.hpp" + +#if defined(AMS_OS_IMPL_USE_PTHREADS) +namespace ams::os::impl { + + namespace { + + } + + void InternalConditionVariableImpl::Initialize() { + /* TODO: What should be done here? */ + } + + void InternalConditionVariableImpl::Finalize() { + /* TODO: What should be done here? */ + } + + void InternalConditionVariableImpl::Signal() { + AMS_ABORT_UNLESS(pthread_cond_signal(std::addressof(m_pthread_cond)) == 0); + } + + void InternalConditionVariableImpl::Broadcast() { + AMS_ABORT_UNLESS(pthread_cond_broadcast(std::addressof(m_pthread_cond)) == 0); + } + + void InternalConditionVariableImpl::Wait(InternalCriticalSection *cs) { + AMS_ABORT_UNLESS(pthread_cond_wait(std::addressof(m_pthread_cond), std::addressof(cs->Get()->m_pthread_mutex)) == 0); + } + + ConditionVariableStatus InternalConditionVariableImpl::TimedWait(InternalCriticalSection *cs, const TimeoutHelper &timeout_helper) { + struct timespec ts; + const auto gettime_res = clock_gettime(CLOCK_REALTIME, std::addressof(ts)); + AMS_ASSERT(gettime_res == 0); + AMS_UNUSED(gettime_res); + + constexpr s64 NanoSecondsPerSecond = TimeSpan::FromSeconds(1).GetNanoSeconds(); + const s64 ns = timeout_helper.GetTimeLeftOnTarget().GetNanoSeconds(); + ts.tv_sec += (ns / NanoSecondsPerSecond); + ts.tv_nsec += (ns % NanoSecondsPerSecond); + if (ts.tv_nsec >= NanoSecondsPerSecond) { + ts.tv_sec += ts.tv_nsec / NanoSecondsPerSecond; + ts.tv_nsec %= NanoSecondsPerSecond; + } + + const auto res = pthread_cond_timedwait(std::addressof(m_pthread_cond), std::addressof(cs->Get()->m_pthread_mutex), std::addressof(ts)); + + if (res != 0) { + AMS_ABORT_UNLESS(errno == ETIMEDOUT); + return ConditionVariableStatus::TimedOut; + } + + return ConditionVariableStatus::Success; + } + +} +#endif diff --git a/libraries/libstratosphere/source/os/impl/os_internal_critical_section_impl.os.windows.cpp b/libraries/libstratosphere/source/os/impl/os_internal_critical_section_impl.os.windows.cpp new file mode 100644 index 000000000..2ede6cedf --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_internal_critical_section_impl.os.windows.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 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 "os_internal_critical_section_impl.os.windows.hpp" + +namespace ams::os::impl { + + void InternalCriticalSectionImpl::Initialize() { + ::InitializeCriticalSection(std::addressof(util::GetReference(m_windows_critical_section_storage).cs)); + } + + void InternalCriticalSectionImpl::Finalize() { + ::DeleteCriticalSection(std::addressof(util::GetReference(m_windows_critical_section_storage).cs)); + } + + void InternalCriticalSectionImpl::Enter() { + ::EnterCriticalSection(std::addressof(util::GetReference(m_windows_critical_section_storage).cs)); + } + + bool InternalCriticalSectionImpl::TryEnter() { + return ::TryEnterCriticalSection(std::addressof(util::GetReference(m_windows_critical_section_storage).cs)) != 0; + } + + void InternalCriticalSectionImpl::Leave() { + return ::LeaveCriticalSection(std::addressof(util::GetReference(m_windows_critical_section_storage).cs)); + } + + bool InternalCriticalSectionImpl::IsLockedByCurrentThread() const { + /* Get the cs. */ + CRITICAL_SECTION * const cs = std::addressof(util::GetReference(m_windows_critical_section_storage).cs); + + /* If the critical section has no owning thread, it's not locked. */ + if (cs->OwningThread == nullptr) { + return false; + } + + /* If it has an owner, TryLock() will succeed if and only if we own the critical section. */ + if (::TryEnterCriticalSection(cs) == 0) { + return false; + } + + /* We now hold the critical section. To avoid a race, check that we didn't just acquire it by chance. */ + const auto holds_lock = cs->RecursionCount > 1; + + /* Leave, since we just successfully entered. */ + ::LeaveCriticalSection(cs); + + return holds_lock; + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_internal_critical_section_impl.os.windows.hpp b/libraries/libstratosphere/source/os/impl/os_internal_critical_section_impl.os.windows.hpp new file mode 100644 index 000000000..d522a3037 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_internal_critical_section_impl.os.windows.hpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) 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::impl { + + struct WindowsCriticalSection { + mutable CRITICAL_SECTION cs; + }; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_internal_critical_section_impl.pthread.cpp b/libraries/libstratosphere/source/os/impl/os_internal_critical_section_impl.pthread.cpp new file mode 100644 index 000000000..e1d0b80ed --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_internal_critical_section_impl.pthread.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (c) 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 +#if defined(ATMOSPHERE_OS_LINUX) +#include +#include +#endif + +#if defined(AMS_OS_IMPL_USE_PTHREADS) +namespace ams::os::impl { + + #if defined(AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD) + namespace { + + #if defined(ATMOSPHERE_OS_LINUX) + + template + concept IsGlibcPthreadMutexImplementationWithOwnerField = requires (T &t) { + { t.__data.__owner } -> std::convertible_to; + }; + + static_assert(IsGlibcPthreadMutexImplementationWithOwnerField); + + #endif + + + } + #endif + + void InternalCriticalSectionImpl::Initialize() { + /* TODO: What should be done here? */ + } + + void InternalCriticalSectionImpl::Finalize() { + /* TODO: What should be done here? */ + } + + void InternalCriticalSectionImpl::Enter() { + AMS_ABORT_UNLESS(pthread_mutex_lock(std::addressof(m_pthread_mutex)) == 0); + } + + bool InternalCriticalSectionImpl::TryEnter() { + return pthread_mutex_trylock(std::addressof(m_pthread_mutex)) == 0; + } + + void InternalCriticalSectionImpl::Leave() { + AMS_ABORT_UNLESS(pthread_mutex_unlock(std::addressof(m_pthread_mutex)) == 0); + } + + #if defined(AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD) + bool InternalCriticalSectionImpl::IsLockedByCurrentThread() const { + /* TODO: This should be less of a terrible hack. */ + #if defined(ATMOSPHERE_OS_LINUX) + return m_pthread_mutex.__data.__owner == ::syscall(SYS_gettid); + #else + #error "Unknown OS/underlying implementation for pthread InternalCriticalSectionImpl::IsLockedByCurrentThread()" + #endif + } + #endif + +} +#endif diff --git a/libraries/libstratosphere/source/os/impl/os_internal_light_event_impl.os.generic.hpp b/libraries/libstratosphere/source/os/impl/os_internal_light_event_impl.os.generic.hpp new file mode 100644 index 000000000..6d4974649 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_internal_light_event_impl.os.generic.hpp @@ -0,0 +1,241 @@ +/* + * Copyright (c) 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::impl { + + namespace { + + constexpr inline u8 LightEventState_NotSignaled = -1; + constexpr inline u8 LightEventState_Invalid = 0; + constexpr inline u8 LightEventState_Signaled = 1; + + static_assert(LightEventState_NotSignaled == 0xFF); + + ALWAYS_INLINE bool AtomicAutoClearLightEvent(std::atomic &signal_state) { + u8 expected = LightEventState_Signaled; + return signal_state.compare_exchange_strong(expected, LightEventState_NotSignaled); + } + + ALWAYS_INLINE u32 GetBroadcastCounterUnsafe(u16 &low, u8 &high) { + const u32 upper = high; + return (upper << BITSIZEOF(low)) | low; + } + + ALWAYS_INLINE void IncrementBroadcastCounterUnsafe(u16 &low, u8 &high) { + if ((++low) == 0) { + ++high; + } + } + + } + + void InternalLightEventImpl::Initialize(bool signaled) { + /* Set broadcast counter. */ + m_counter_low = 0; + m_counter_high = 0; + + /* Set initial state. */ + m_signal_state = signaled ? LightEventState_Signaled : LightEventState_NotSignaled; + } + + void InternalLightEventImpl::Finalize() { + /* Set final state. */ + m_signal_state = LightEventState_Invalid; + } + + void InternalLightEventImpl::SignalWithAutoClear() { + /* Signal only if we need to. */ + if (m_signal_state.load(std::memory_order_acquire) == LightEventState_NotSignaled) { + /* Lock ourselves. */ + std::scoped_lock lk(m_cs); + + /* Set our state to signaled. */ + m_signal_state = LightEventState_Signaled; + + /* Signal to any waiters. */ + m_cv.Signal(); + } + } + + void InternalLightEventImpl::SignalWithManualClear() { + /* Signal only if we need to. */ + if (m_signal_state.load(std::memory_order_acquire) == LightEventState_NotSignaled) { + /* Lock ourselves. */ + std::scoped_lock lk(m_cs); + + /* Set our state to signaled. */ + m_signal_state = LightEventState_Signaled; + + /* Increment our broadcast counter. */ + IncrementBroadcastCounterUnsafe(m_counter_low, m_counter_high); + + /* Broadcast to any waiters. */ + m_cv.Broadcast(); + } + } + + void InternalLightEventImpl::Clear() { + /* Clear only if we need to. */ + if (m_signal_state.load(std::memory_order_acquire) == LightEventState_Signaled) { + /* Lock ourselves. */ + std::scoped_lock lk(m_cs); + + /* Set our state to signaled. */ + m_signal_state = LightEventState_NotSignaled; + } + } + + void InternalLightEventImpl::WaitWithAutoClear() { + /* Loop waiting. */ + while (true) { + /* Get the current state. */ + const auto state = m_signal_state.load(std::memory_order_acquire); + + /* If we're not signaled, stop looping so we can properly wait to be signaled. */ + if (state == LightEventState_NotSignaled) { + break; + } + + /* If we're signaled, try to reset. */ + if (state == LightEventState_Signaled && AtomicAutoClearLightEvent(m_signal_state)) { + return; + } + } + + /* Wait explicitly on the not-signaled event. */ + std::scoped_lock lk(m_cs); + + while (m_signal_state == LightEventState_NotSignaled) { + m_cv.Wait(std::addressof(m_cs)); + } + + /* Set our state to not signaled. */ + m_signal_state = LightEventState_NotSignaled; + } + + void InternalLightEventImpl::WaitWithManualClear() { + /* Loop waiting. */ + while (true) { + /* Get the current m_signal_state. */ + const auto state = m_signal_state.load(std::memory_order_acquire); + + /* If we're not signaled, stop looping so we can properly wait to be signaled. */ + if (state == LightEventState_NotSignaled) { + break; + } + + /* If we're signaled, we're done. */ + if (state == LightEventState_Signaled) { + return; + } + } + + /* Wait explicitly on the not-signaled event. */ + std::scoped_lock lk(m_cs); + + /* Get the broadcast counter. */ + const auto bc = GetBroadcastCounterUnsafe(m_counter_low, m_counter_high); + + while (m_signal_state == LightEventState_NotSignaled) { + /* Check if a broadcast has occurred. */ + if (bc != GetBroadcastCounterUnsafe(m_counter_low, m_counter_high)) { + break; + } + + m_cv.Wait(std::addressof(m_cs)); + } + } + + bool InternalLightEventImpl::TryWaitWithAutoClear() { + return m_signal_state.load(std::memory_order_acquire) == LightEventState_Signaled && AtomicAutoClearLightEvent(m_signal_state); + } + + bool InternalLightEventImpl::TryWaitWithManualClear() { + return m_signal_state.load(std::memory_order_acquire) == LightEventState_Signaled; + } + + bool InternalLightEventImpl::TimedWaitWithAutoClear(const TimeoutHelper &timeout_helper) { + /* Loop waiting. */ + while (true) { + /* Get the current state. */ + const auto state = m_signal_state.load(std::memory_order_acquire); + + /* If we're not signaled, stop looping so we can properly wait to be signaled. */ + if (state == LightEventState_NotSignaled) { + break; + } + + /* If we're signaled, try to reset. */ + if (state == LightEventState_Signaled && AtomicAutoClearLightEvent(m_signal_state)) { + return true; + } + } + + /* Wait explicitly on the not-signaled event. */ + std::scoped_lock lk(m_cs); + + while (m_signal_state == LightEventState_NotSignaled) { + if (m_cv.TimedWait(std::addressof(m_cs), timeout_helper) == ConditionVariableStatus::TimedOut) { + return false; + } + } + + /* Set our state to not signaled. */ + m_signal_state = LightEventState_NotSignaled; + + return true; + } + + bool InternalLightEventImpl::TimedWaitWithManualClear(const TimeoutHelper &timeout_helper) { + /* Loop waiting. */ + while (true) { + /* Get the current m_signal_state. */ + const auto state = m_signal_state.load(std::memory_order_acquire); + + /* If we're not signaled, stop looping so we can properly wait to be signaled. */ + if (state == LightEventState_NotSignaled) { + break; + } + + /* If we're signaled, we're done. */ + if (state == LightEventState_Signaled) { + return true; + } + } + + /* Wait explicitly on the not-signaled event. */ + std::scoped_lock lk(m_cs); + + /* Get the broadcast counter. */ + const auto bc = GetBroadcastCounterUnsafe(m_counter_low, m_counter_high); + + while (m_signal_state == LightEventState_NotSignaled) { + /* Check if a broadcast has occurred. */ + if (bc != GetBroadcastCounterUnsafe(m_counter_low, m_counter_high)) { + break; + } + + if (m_cv.TimedWait(std::addressof(m_cs), timeout_helper) == ConditionVariableStatus::TimedOut) { + return false; + } + } + + return true; + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_internal_rw_busy_mutex_impl.os.horizon.hpp b/libraries/libstratosphere/source/os/impl/os_internal_rw_busy_mutex_impl.os.horizon.hpp index 8961d8436..1e47e62c0 100644 --- a/libraries/libstratosphere/source/os/impl/os_internal_rw_busy_mutex_impl.os.horizon.hpp +++ b/libraries/libstratosphere/source/os/impl/os_internal_rw_busy_mutex_impl.os.horizon.hpp @@ -20,28 +20,6 @@ namespace ams::os::impl { namespace { - constexpr inline u8 WriterCountMax = std::numeric_limits::max(); - - ALWAYS_INLINE u16 GetReaderCount(u32 v) { - return static_cast(v >> 0); - } - - ALWAYS_INLINE u8 GetWriterCurrent(u32 v) { - return static_cast(v >> 16); - } - - ALWAYS_INLINE u8 GetWriterNext(u32 v) { - return static_cast(v >> 24); - } - - ALWAYS_INLINE u32 IncrementWriterNext(u32 v) { - return v + (1u << 24); - } - - ALWAYS_INLINE bool IsWriteLocked(u32 v) { - return GetWriterCurrent(v) != GetWriterNext(v); - } - ALWAYS_INLINE void PrefetchForBusyMutex(u32 *p) { /* Nintendo does PRFM pstl1keep. */ __builtin_prefetch(p, 1); @@ -79,16 +57,8 @@ namespace ams::os::impl { return result == 0; } - ALWAYS_INLINE u8 *GetWriterCurrentPointerForBusyMutex(u32 *p) { - if constexpr (util::IsLittleEndian()) { - return reinterpret_cast(reinterpret_cast(p)) + 2; - } else { - return reinterpret_cast(reinterpret_cast(p)) + 1; - } - } - ALWAYS_INLINE void StoreReleaseWriteLockValueForBusyMutex(u32 *p) { - u8 * const p8 = GetWriterCurrentPointerForBusyMutex(p); + u8 * const p8 = InternalReaderWriterBusyMutexValue::GetWriterCurrentPointer(p); u8 v; __asm__ __volatile__("ldrb %w[v], %[p8]\n" @@ -125,11 +95,11 @@ namespace ams::os::impl { const u32 v = LoadAcquireExclusiveForBusyMutex(p); /* We can only acquire read lock if not write-locked. */ - const bool write_locked = IsWriteLocked(v); + const bool write_locked = InternalReaderWriterBusyMutexValue::IsWriteLocked(v); if (AMS_LIKELY(!write_locked)) { /* Check that we don't overflow the reader count. */ const u32 new_v = v + 1; - AMS_ABORT_UNLESS(GetReaderCount(new_v) != 0); + AMS_ABORT_UNLESS(InternalReaderWriterBusyMutexValue::GetReaderCount(new_v) != 0); /* Try to store our updated lock value. */ if (AMS_LIKELY(StoreExclusiveForBusyMutex(p, new_v))) { @@ -162,7 +132,7 @@ namespace ams::os::impl { do { /* Get and validate the current value. */ v = LoadExclusiveForBusyMutex(p); - AMS_ABORT_UNLESS(GetReaderCount(v) != 0); + AMS_ABORT_UNLESS(InternalReaderWriterBusyMutexValue::GetReaderCount(v) != 0); } while (!StoreReleaseExclusiveForBusyMutex(p, v - 1)); } @@ -207,10 +177,10 @@ namespace ams::os::impl { const u32 v = LoadAcquireExclusiveForBusyMutex(p); /* Check that we can write lock. */ - AMS_ABORT_UNLESS(static_cast(GetWriterNext(v) - GetWriterCurrent(v)) < WriterCountMax); + AMS_ABORT_UNLESS(static_cast(InternalReaderWriterBusyMutexValue::GetWriterNext(v) - InternalReaderWriterBusyMutexValue::GetWriterCurrent(v)) < InternalReaderWriterBusyMutexValue::WriterCountMax); /* Determine our write-lock number. */ - const u32 new_v = IncrementWriterNext(v); + const u32 new_v = InternalReaderWriterBusyMutexValue::IncrementWriterNext(v); /* Try to store our updated lock value. */ if (AMS_UNLIKELY(!StoreExclusiveForBusyMutex(p, new_v))) { @@ -226,7 +196,7 @@ namespace ams::os::impl { } /* Wait until the lock is truly acquired. */ - if (GetReaderCount(new_v) != 0 || GetWriterNext(v) != GetWriterCurrent(new_v)) { + if (InternalReaderWriterBusyMutexValue::GetReaderCount(new_v) != 0 || InternalReaderWriterBusyMutexValue::GetWriterNext(v) != InternalReaderWriterBusyMutexValue::GetWriterCurrent(new_v)) { /* Send an event, so that we can immediately wait without fail. */ SendEventLocalForBusyMutex(); @@ -236,7 +206,7 @@ namespace ams::os::impl { /* Get the updated value. */ const u32 cur_v = LoadAcquireExclusiveForBusyMutex(p); - if (GetReaderCount(cur_v) == 0 && GetWriterNext(v) == GetWriterCurrent(cur_v)) { + if (InternalReaderWriterBusyMutexValue::GetReaderCount(cur_v) == 0 && InternalReaderWriterBusyMutexValue::GetWriterNext(v) == InternalReaderWriterBusyMutexValue::GetWriterCurrent(cur_v)) { break; } } @@ -249,7 +219,7 @@ namespace ams::os::impl { void InternalReaderWriterBusyMutexImpl::ReleaseWriteLock() { /* Check pre-conditions. */ - AMS_ABORT_UNLESS(IsWriteLocked(m_value)); + AMS_ABORT_UNLESS(InternalReaderWriterBusyMutexValue::IsWriteLocked(m_value)); /* Get pointer to our value. */ u32 * const p = std::addressof(m_value); diff --git a/libraries/libstratosphere/source/os/impl/os_internal_rw_busy_mutex_impl.os.linux.hpp b/libraries/libstratosphere/source/os/impl/os_internal_rw_busy_mutex_impl.os.linux.hpp new file mode 100644 index 000000000..14b82cff4 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_internal_rw_busy_mutex_impl.os.linux.hpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 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::impl { + + /* TODO */ + +} diff --git a/libraries/libstratosphere/source/os/impl/os_internal_rw_busy_mutex_impl.os.macos.hpp b/libraries/libstratosphere/source/os/impl/os_internal_rw_busy_mutex_impl.os.macos.hpp new file mode 100644 index 000000000..14b82cff4 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_internal_rw_busy_mutex_impl.os.macos.hpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 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::impl { + + /* TODO */ + +} diff --git a/libraries/libstratosphere/source/os/impl/os_internal_rw_busy_mutex_impl.os.windows.hpp b/libraries/libstratosphere/source/os/impl/os_internal_rw_busy_mutex_impl.os.windows.hpp new file mode 100644 index 000000000..14b82cff4 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_internal_rw_busy_mutex_impl.os.windows.hpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 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::impl { + + /* TODO */ + +} diff --git a/libraries/libstratosphere/source/os/impl/os_interrupt_event_impl.hpp b/libraries/libstratosphere/source/os/impl/os_interrupt_event_impl.hpp index e4dccfe5c..0980592f4 100644 --- a/libraries/libstratosphere/source/os/impl/os_interrupt_event_impl.hpp +++ b/libraries/libstratosphere/source/os/impl/os_interrupt_event_impl.hpp @@ -18,6 +18,12 @@ #if defined(ATMOSPHERE_OS_HORIZON) #include "os_interrupt_event_target_impl.os.horizon.hpp" +#elif defined(ATMOSPHERE_OS_WINDOWS) + #include "os_interrupt_event_target_impl.os.windows.hpp" +#elif defined(ATMOSPHERE_OS_LINUX) + #include "os_interrupt_event_target_impl.os.linux.hpp" +#elif defined(ATMOSPHERE_OS_MACOS) + #include "os_interrupt_event_target_impl.os.macos.hpp" #else #error "Unknown OS for ams::os::InterruptEventImpl" #endif diff --git a/libraries/libstratosphere/source/os/impl/os_interrupt_event_target_impl.os.linux.hpp b/libraries/libstratosphere/source/os/impl/os_interrupt_event_target_impl.os.linux.hpp new file mode 100644 index 000000000..3ccfba29d --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_interrupt_event_target_impl.os.linux.hpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 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::impl { + + class InterruptEventLinuxImpl { + private: + NativeHandle m_handle; + bool m_manual_clear; + public: + explicit InterruptEventLinuxImpl(InterruptName name, EventClearMode mode) { + AMS_UNUSED(name, mode); + AMS_ABORT("TODO"); + } + + ~InterruptEventLinuxImpl() { + AMS_ABORT("TODO"); + } + + void Clear() { AMS_ABORT("TODO"); } + void Wait() { AMS_ABORT("TODO"); } + bool TryWait() { AMS_ABORT("TODO"); } + bool TimedWait(TimeSpan) { AMS_ABORT("TODO"); } + + TriBool IsSignaled() { + return TriBool::Undefined; + } + + NativeHandle GetHandle() const { + return m_handle; + } + }; + + using InterruptEventTargetImpl = InterruptEventLinuxImpl; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_interrupt_event_target_impl.os.macos.hpp b/libraries/libstratosphere/source/os/impl/os_interrupt_event_target_impl.os.macos.hpp new file mode 100644 index 000000000..7d0bd28f2 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_interrupt_event_target_impl.os.macos.hpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 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::impl { + + class InterruptEventMacosImpl { + private: + NativeHandle m_handle; + bool m_manual_clear; + public: + explicit InterruptEventMacosImpl(InterruptName name, EventClearMode mode) { + AMS_UNUSED(name, mode); + AMS_ABORT("TODO"); + } + + ~InterruptEventMacosImpl() { + AMS_ABORT("TODO"); + } + + void Clear() { AMS_ABORT("TODO"); } + void Wait() { AMS_ABORT("TODO"); } + bool TryWait() { AMS_ABORT("TODO"); } + bool TimedWait(TimeSpan) { AMS_ABORT("TODO"); } + + TriBool IsSignaled() { + return TriBool::Undefined; + } + + NativeHandle GetHandle() const { + return m_handle; + } + }; + + using InterruptEventTargetImpl = InterruptEventMacosImpl; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_interrupt_event_target_impl.os.windows.cpp b/libraries/libstratosphere/source/os/impl/os_interrupt_event_target_impl.os.windows.cpp new file mode 100644 index 000000000..1b33aeb9a --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_interrupt_event_target_impl.os.windows.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (c) 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 "os_interrupt_event_target_impl.os.windows.hpp" +#include "os_timeout_helper.hpp" +#include "os_giant_lock.hpp" + +namespace ams::os::impl { + + InterruptEventWindowsImpl::InterruptEventWindowsImpl(InterruptName name, EventClearMode clear_mode) { + const NativeHandle handle = ::OpenEvent(EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE, reinterpret_cast(name)); + AMS_ASSERT(handle != InvalidNativeHandle); + + m_handle = handle; + m_manual_clear = (clear_mode == EventClearMode_ManualClear); + } + + InterruptEventWindowsImpl::~InterruptEventWindowsImpl() { + const auto ret = ::CloseHandle(m_handle); + AMS_ASSERT(ret != 0); + AMS_UNUSED(ret); + } + + bool InterruptEventWindowsImpl::ResetEventSignal() { + std::scoped_lock lk(GetGiantLock()); + + if (auto ret = ::WaitForSingleObject(m_handle, 0); ret == WAIT_OBJECT_0) { + ::ResetEvent(m_handle); + return true; + } else { + return false; + } + } + + void InterruptEventWindowsImpl::Clear() { + const auto ret = ::ResetEvent(m_handle); + AMS_ASSERT(ret != 0); + AMS_UNUSED(ret); + } + + void InterruptEventWindowsImpl::Wait() { + while (true) { + /* Continuously wait, until success. */ + auto ret = ::WaitForSingleObject(m_handle, INFINITE); + AMS_ASSERT(ret == WAIT_OBJECT_0); + AMS_UNUSED(ret); + + /* If we're not obligated to clear, we're done. */ + if (m_manual_clear) { + return; + } + + /* Try to reset. */ + if (this->ResetEventSignal()) { + return; + } + } + } + + bool InterruptEventWindowsImpl::TryWait() { + /* If we're auto clear, just try to reset. */ + if (!m_manual_clear) { + return this->ResetEventSignal(); + } + + const auto ret = ::WaitForSingleObject(m_handle, 0); + AMS_ASSERT((ret == WAIT_OBJECT_0) || (ret == WAIT_TIMEOUT)); + + return ret == WAIT_OBJECT_0; + } + + bool InterruptEventWindowsImpl::TimedWait(TimeSpan timeout) { + TimeoutHelper timeout_helper(timeout); + + do { + if (const auto res = ::WaitForSingleObject(m_handle, timeout_helper.GetTimeLeftOnTarget()); res == WAIT_OBJECT_0) { + /* If we're not obligated to clear, we're done. */ + if (m_manual_clear) { + return true; + } + + /* Try to reset. */ + if (this->ResetEventSignal()) { + return true; + } + } + } while (!timeout_helper.TimedOut()); + + return false; + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_interrupt_event_target_impl.os.windows.hpp b/libraries/libstratosphere/source/os/impl/os_interrupt_event_target_impl.os.windows.hpp new file mode 100644 index 000000000..cca5d90ac --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_interrupt_event_target_impl.os.windows.hpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 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::impl { + + class InterruptEventWindowsImpl { + private: + NativeHandle m_handle; + bool m_manual_clear; + public: + explicit InterruptEventWindowsImpl(InterruptName name, EventClearMode mode); + ~InterruptEventWindowsImpl(); + + void Clear(); + void Wait(); + bool TryWait(); + bool TimedWait(TimeSpan timeout); + + TriBool IsSignaled() { + return TriBool::Undefined; + } + + NativeHandle GetHandle() const { + return m_handle; + } + private: + bool ResetEventSignal(); + }; + + using InterruptEventTargetImpl = InterruptEventWindowsImpl; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_io_region_impl.os.windows.cpp b/libraries/libstratosphere/source/os/impl/os_io_region_impl.os.windows.cpp new file mode 100644 index 000000000..65e070023 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_io_region_impl.os.windows.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) 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 "os_io_region_impl.hpp" + +namespace ams::os::impl { + + Result IoRegionImpl::CreateIoRegion(NativeHandle *out, NativeHandle io_pool_handle, uintptr_t address, size_t size, MemoryMapping mapping, MemoryPermission permission) { + AMS_UNUSED(out, io_pool_handle, address, size, mapping, permission); + R_THROW(os::ResultNotSupported()); + } + + Result IoRegionImpl::MapIoRegion(void **out, NativeHandle handle, size_t size, MemoryPermission perm) { + AMS_UNUSED(out, handle, size, perm); + R_THROW(os::ResultNotSupported()); + } + + void IoRegionImpl::UnmapIoRegion(NativeHandle handle, void *address, size_t size) { + AMS_UNUSED(handle, address, size); + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_multiple_wait_impl.cpp b/libraries/libstratosphere/source/os/impl/os_multiple_wait_impl.cpp index 8b3f7d60c..b4f07fd6f 100644 --- a/libraries/libstratosphere/source/os/impl/os_multiple_wait_impl.cpp +++ b/libraries/libstratosphere/source/os/impl/os_multiple_wait_impl.cpp @@ -122,12 +122,16 @@ namespace ams::os::impl { break; default: /* 0 - 0x3F, valid. */ { - AMS_ASSERT(0 <= index && index < static_cast(MaximumHandleCount)); + if constexpr (MaximumHandleCount > 0) { + AMS_ASSERT(0 <= index && index < static_cast(MaximumHandleCount)); - std::scoped_lock lk(m_cs_wait); - m_signaled_holder = objects[index]; - *out = objects[index]; - return wait_result; + std::scoped_lock lk(m_cs_wait); + m_signaled_holder = objects[index]; + *out = objects[index]; + return wait_result; + } else { + AMS_ABORT_UNLESS(MaximumHandleCount > 0); + } } break; } diff --git a/libraries/libstratosphere/source/os/impl/os_multiple_wait_impl.hpp b/libraries/libstratosphere/source/os/impl/os_multiple_wait_impl.hpp index 6afa41376..a079a518a 100644 --- a/libraries/libstratosphere/source/os/impl/os_multiple_wait_impl.hpp +++ b/libraries/libstratosphere/source/os/impl/os_multiple_wait_impl.hpp @@ -18,6 +18,12 @@ #if defined(ATMOSPHERE_OS_HORIZON) #include "os_multiple_wait_target_impl.os.horizon.hpp" +#elif defined(ATMOSPHERE_OS_WINDOWS) + #include "os_multiple_wait_target_impl.os.windows.hpp" +#elif defined(ATMOSPHERE_OS_LINUX) + #include "os_multiple_wait_target_impl.os.linux.hpp" +#elif defined(ATMOSPHERE_OS_MACOS) + #include "os_multiple_wait_target_impl.os.macos.hpp" #else #error "Unknown OS for ams::os::MultiWaitTargetImpl" #endif diff --git a/libraries/libstratosphere/source/os/impl/os_multiple_wait_target_impl.os.linux.cpp b/libraries/libstratosphere/source/os/impl/os_multiple_wait_target_impl.os.linux.cpp new file mode 100644 index 000000000..1045ba72c --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_multiple_wait_target_impl.os.linux.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (c) 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 "os_multiple_wait_holder_base.hpp" +#include "os_multiple_wait_impl.hpp" +#include "os_timeout_helper.hpp" +#include "os_inter_process_event_impl.os.linux.hpp" + +#include + +namespace ams::os::impl { + + MultiWaitLinuxImpl::MultiWaitLinuxImpl() { + R_ABORT_UNLESS(InterProcessEventLinuxImpl::CreateSingle(std::addressof(m_cancel_event))); + } + + MultiWaitLinuxImpl::~MultiWaitLinuxImpl() { + InterProcessEventLinuxImpl::Close(m_cancel_event); + + m_cancel_event = InvalidNativeHandle; + } + + void MultiWaitLinuxImpl::CancelWait() { + InterProcessEventLinuxImpl::Signal(m_cancel_event); + } + + Result MultiWaitLinuxImpl::PollNativeHandlesImpl(s32 *out_index, s32 num, NativeHandle arr[], s32 array_size, s64 ns) { + /* Check that we can add our cancel handle to the wait. */ + AMS_ABORT_UNLESS(array_size <= static_cast(MaximumHandleCount)); + AMS_UNUSED(array_size); + + /* Create poll fds. */ + struct pollfd pfds[MaximumHandleCount + 1]; + for (auto i = 0; i < num; ++i) { + pfds[i].fd = arr[i]; + pfds[i].events = POLLIN; + pfds[i].revents = 0; + } + + pfds[num].fd = m_cancel_event; + pfds[num].events = POLLIN; + pfds[num].revents = 0; + + /* Determine timeout. */ + constexpr s64 NanoSecondsPerSecond = TimeSpan::FromSeconds(1).GetNanoSeconds(); + struct timespec ts = { .tv_sec = (ns / NanoSecondsPerSecond), .tv_nsec = ns % NanoSecondsPerSecond }; + + /* Wait. */ + while (true) { + const auto ret = ::ppoll(pfds, num + 1, ns >= 0 ? std::addressof(ts) : nullptr, nullptr); + if (ret < 0) { + /* Treat EINTR like a cancellation event; this will lead to a re-poll if nothing is signaled. */ + AMS_ABORT_UNLESS(errno == EINTR); + + *out_index = MultiWaitImpl::WaitCancelled; + R_SUCCEED(); + } + + /* Determine what event was polled. */ + if (ret == 0) { + *out_index = MultiWaitImpl::WaitTimedOut; + R_SUCCEED(); + } else if (pfds[num].revents != 0) { + *out_index = MultiWaitImpl::WaitCancelled; + + /* Reset our cancel event. */ + InterProcessEventLinuxImpl::Clear(m_cancel_event); + + R_SUCCEED(); + } else { + for (auto i = 0; i < num; ++i) { + if (pfds[i].revents != 0) { + *out_index = i; + R_SUCCEED(); + } + } + + AMS_ABORT("This should be impossible?"); + } + } + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_multiple_wait_target_impl.os.linux.hpp b/libraries/libstratosphere/source/os/impl/os_multiple_wait_target_impl.os.linux.hpp new file mode 100644 index 000000000..b735efaa4 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_multiple_wait_target_impl.os.linux.hpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 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_thread_manager.hpp" + +namespace ams::os::impl { + + class MultiWaitLinuxImpl { + public: + /* TODO: This can potentially be higher. */ + static constexpr size_t MaximumHandleCount = 64; + private: + NativeHandle m_cancel_event; + private: + Result PollNativeHandlesImpl(s32 *out_index, s32 num, NativeHandle arr[], s32 array_size, s64 ns); + Result ReplyAndReceiveImpl(s32 *out_index, s32 num, NativeHandle arr[], s32 array_size, s64 ns, NativeHandle reply_target); + public: + MultiWaitLinuxImpl(); + ~MultiWaitLinuxImpl(); + + void CancelWait(); + + Result WaitAny(s32 *out_index, NativeHandle arr[], s32 array_size, s32 num) { + return this->PollNativeHandlesImpl(out_index, num, arr, array_size, static_cast(-1)); + } + + Result TryWaitAny(s32 *out_index, NativeHandle arr[], s32 array_size, s32 num) { + return this->PollNativeHandlesImpl(out_index, num, arr, array_size, 0); + } + + Result TimedWaitAny(s32 *out_index, NativeHandle arr[], s32 array_size, s32 num, TimeSpan ts) { + return this->PollNativeHandlesImpl(out_index, num, arr, array_size, ts.GetNanoSeconds()); + } + + Result ReplyAndReceive(s32 *out_index, NativeHandle arr[], s32 array_size, s32 num, NativeHandle reply_target) { + return this->ReplyAndReceiveImpl(out_index, num, arr, array_size, std::numeric_limits::max(), reply_target); + } + + Result TimedReplyAndReceive(s32 *out_index, NativeHandle arr[], s32 array_size, s32 num, NativeHandle reply_target, TimeSpan ts) { + return this->ReplyAndReceiveImpl(out_index, num, arr, array_size, ts.GetNanoSeconds(), reply_target); + } + + void SetCurrentThreadHandleForCancelWait() { + /* ... */ + } + + void ClearCurrentThreadHandleForCancelWait() { + /* ... */ + } + }; + + using MultiWaitTargetImpl = MultiWaitLinuxImpl; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_multiple_wait_target_impl.os.macos.cpp b/libraries/libstratosphere/source/os/impl/os_multiple_wait_target_impl.os.macos.cpp new file mode 100644 index 000000000..923bb46c4 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_multiple_wait_target_impl.os.macos.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (c) 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 "os_multiple_wait_holder_base.hpp" +#include "os_multiple_wait_impl.hpp" +#include "os_timeout_helper.hpp" +#include "os_inter_process_event_impl.os.macos.hpp" + +#include + +namespace ams::os::impl { + + MultiWaitMacosImpl::MultiWaitMacosImpl() { + R_ABORT_UNLESS(InterProcessEventMacosImpl::Create(std::addressof(m_cancel_write_handle), std::addressof(m_cancel_read_handle))); + } + + MultiWaitMacosImpl::~MultiWaitMacosImpl() { + InterProcessEventMacosImpl::Close(m_cancel_write_handle); + InterProcessEventMacosImpl::Close(m_cancel_read_handle); + + m_cancel_write_handle = InvalidNativeHandle; + m_cancel_read_handle = InvalidNativeHandle; + } + + void MultiWaitMacosImpl::CancelWait() { + InterProcessEventMacosImpl::Signal(m_cancel_write_handle); + } + + Result MultiWaitMacosImpl::PollNativeHandlesImpl(s32 *out_index, s32 num, NativeHandle arr[], s32 array_size, s64 ns) { + /* Check that we can add our cancel handle to the wait. */ + AMS_ABORT_UNLESS(array_size <= static_cast(MaximumHandleCount)); + AMS_UNUSED(array_size); + + /* Create poll fds. */ + struct pollfd pfds[MaximumHandleCount + 1]; + for (auto i = 0; i < num; ++i) { + pfds[i].fd = arr[i]; + pfds[i].events = POLLIN; + pfds[i].revents = 0; + } + + pfds[num].fd = m_cancel_read_handle; + pfds[num].events = POLLIN; + pfds[num].revents = 0; + + /* Determine timeout. */ + constexpr s64 NanoSecondsPerMilliSecond = TimeSpan::FromMilliSeconds(1).GetNanoSeconds(); + + /* TODO: Will macos ever support ppoll? */ + const int timeout = static_cast(ns >= 0 ? (ns / NanoSecondsPerMilliSecond) : -1); + + /* Wait. */ + while (true) { + const auto ret = ::poll(pfds, num + 1, timeout); + if (ret < 0) { + /* Treat EINTR like a cancellation event; this will lead to a re-poll if nothing is signaled. */ + AMS_ABORT_UNLESS(errno == EINTR); + + *out_index = MultiWaitImpl::WaitCancelled; + R_SUCCEED(); + } + + /* Determine what event was polled. */ + if (ret == 0) { + *out_index = MultiWaitImpl::WaitTimedOut; + R_SUCCEED(); + } else if (pfds[num].revents != 0) { + *out_index = MultiWaitImpl::WaitCancelled; + + /* Reset our cancel event. */ + InterProcessEventMacosImpl::Clear(m_cancel_read_handle); + + R_SUCCEED(); + } else { + for (auto i = 0; i < num; ++i) { + if (pfds[i].revents != 0) { + *out_index = i; + R_SUCCEED(); + } + } + + AMS_ABORT("This should be impossible?"); + } + } + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_multiple_wait_target_impl.os.macos.hpp b/libraries/libstratosphere/source/os/impl/os_multiple_wait_target_impl.os.macos.hpp new file mode 100644 index 000000000..6da54d4dc --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_multiple_wait_target_impl.os.macos.hpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 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_thread_manager.hpp" + +namespace ams::os::impl { + + class MultiWaitMacosImpl { + public: + /* TODO: This can potentially be higher. */ + static constexpr size_t MaximumHandleCount = 64; + private: + NativeHandle m_cancel_read_handle; + NativeHandle m_cancel_write_handle; + private: + Result PollNativeHandlesImpl(s32 *out_index, s32 num, NativeHandle arr[], s32 array_size, s64 ns); + Result ReplyAndReceiveImpl(s32 *out_index, s32 num, NativeHandle arr[], s32 array_size, s64 ns, NativeHandle reply_target); + public: + MultiWaitMacosImpl(); + ~MultiWaitMacosImpl(); + + void CancelWait(); + + Result WaitAny(s32 *out_index, NativeHandle arr[], s32 array_size, s32 num) { + return this->PollNativeHandlesImpl(out_index, num, arr, array_size, static_cast(-1)); + } + + Result TryWaitAny(s32 *out_index, NativeHandle arr[], s32 array_size, s32 num) { + return this->PollNativeHandlesImpl(out_index, num, arr, array_size, 0); + } + + Result TimedWaitAny(s32 *out_index, NativeHandle arr[], s32 array_size, s32 num, TimeSpan ts) { + return this->PollNativeHandlesImpl(out_index, num, arr, array_size, ts.GetNanoSeconds()); + } + + Result ReplyAndReceive(s32 *out_index, NativeHandle arr[], s32 array_size, s32 num, NativeHandle reply_target) { + return this->ReplyAndReceiveImpl(out_index, num, arr, array_size, std::numeric_limits::max(), reply_target); + } + + Result TimedReplyAndReceive(s32 *out_index, NativeHandle arr[], s32 array_size, s32 num, NativeHandle reply_target, TimeSpan ts) { + return this->ReplyAndReceiveImpl(out_index, num, arr, array_size, ts.GetNanoSeconds(), reply_target); + } + + void SetCurrentThreadHandleForCancelWait() { + /* ... */ + } + + void ClearCurrentThreadHandleForCancelWait() { + /* ... */ + } + }; + + using MultiWaitTargetImpl = MultiWaitMacosImpl; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_multiple_wait_target_impl.os.windows.cpp b/libraries/libstratosphere/source/os/impl/os_multiple_wait_target_impl.os.windows.cpp new file mode 100644 index 000000000..a40aff736 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_multiple_wait_target_impl.os.windows.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 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 "os_multiple_wait_holder_base.hpp" +#include "os_multiple_wait_impl.hpp" +#include "os_timeout_helper.hpp" + +namespace ams::os::impl { + + Result MultiWaitWindowsImpl::WaitForMultipleObjectsImpl(s32 *out_index, s32 num, NativeHandle arr[], s32 array_size, DWORD wait_ms) { + /* Check that we can add our cancel handle to the wait. */ + AMS_ABORT_UNLESS(num + 1 <= array_size); + AMS_UNUSED(array_size); + + /* Add our cancel handle. */ + arr[num] = m_cancel_event; + + /* Wait. */ + auto result = ::WaitForMultipleObjects(num + 1, arr, FALSE, wait_ms); + if (result == WAIT_TIMEOUT) { + *out_index = MultiWaitImpl::WaitTimedOut; + } else { + const s32 index = result - WAIT_OBJECT_0; + AMS_ASSERT((0 <= index) && (index <= num)); + if (index == num) { + *out_index = MultiWaitImpl::WaitCancelled; + } else { + *out_index = index; + } + } + + R_SUCCEED(); + } + + Result MultiWaitWindowsImpl::TimedWaitAny(s32 *out_index, NativeHandle arr[], s32 array_size, s32 num, TimeSpan ts) { + impl::TimeoutHelper timeout(ts); + + do { + s32 idx; + R_TRY(WaitForMultipleObjectsImpl(std::addressof(idx), num, arr, array_size, timeout.GetTimeLeftOnTarget())); + if (idx != MultiWaitImpl::WaitTimedOut) { + *out_index = idx; + R_SUCCEED(); + } + } while (!timeout.TimedOut()); + + *out_index = MultiWaitImpl::WaitTimedOut; + R_SUCCEED(); + } + + Result MultiWaitWindowsImpl::ReplyAndReceiveImpl(s32 *out_index, s32 num, NativeHandle arr[], s32 array_size, s64 ns, NativeHandle reply_target) { + AMS_UNUSED(out_index, num, arr, array_size, ns, reply_target); + R_ABORT_UNLESS(os::ResultNotImplemented()); + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_multiple_wait_target_impl.os.windows.hpp b/libraries/libstratosphere/source/os/impl/os_multiple_wait_target_impl.os.windows.hpp new file mode 100644 index 000000000..07dd1403d --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_multiple_wait_target_impl.os.windows.hpp @@ -0,0 +1,75 @@ +/* + * Copyright (c) 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_thread_manager.hpp" + +namespace ams::os::impl { + + class MultiWaitWindowsImpl { + public: + static constexpr size_t MaximumHandleCount = static_cast(MAXIMUM_WAIT_OBJECTS); + private: + os::NativeHandle m_cancel_event; + private: + Result WaitForMultipleObjectsImpl(s32 *out_index, s32 num, NativeHandle arr[], s32 array_size, DWORD wait_ms); + Result ReplyAndReceiveImpl(s32 *out_index, s32 num, NativeHandle arr[], s32 array_size, s64 ns, NativeHandle reply_target); + public: + MultiWaitWindowsImpl() { + m_cancel_event = ::CreateEvent(nullptr, false, false, nullptr); + AMS_ASSERT(m_cancel_event != os::InvalidNativeHandle); + } + + ~MultiWaitWindowsImpl() { + const auto ret = ::CloseHandle(m_cancel_event); + AMS_ASSERT(ret != 0); + AMS_UNUSED(ret); + } + + void CancelWait() { + ::SetEvent(m_cancel_event); + } + + Result WaitAny(s32 *out_index, NativeHandle arr[], s32 array_size, s32 num) { + return this->WaitForMultipleObjectsImpl(out_index, num, arr, array_size, INFINITE); + } + + Result TryWaitAny(s32 *out_index, NativeHandle arr[], s32 array_size, s32 num) { + return this->WaitForMultipleObjectsImpl(out_index, num, arr, array_size, 0); + } + + Result TimedWaitAny(s32 *out_index, NativeHandle arr[], s32 array_size, s32 num, TimeSpan ts); + + Result ReplyAndReceive(s32 *out_index, NativeHandle arr[], s32 array_size, s32 num, NativeHandle reply_target) { + return this->ReplyAndReceiveImpl(out_index, num, arr, array_size, std::numeric_limits::max(), reply_target); + } + + Result TimedReplyAndReceive(s32 *out_index, NativeHandle arr[], s32 array_size, s32 num, NativeHandle reply_target, TimeSpan ts) { + return this->ReplyAndReceiveImpl(out_index, num, arr, array_size, ts.GetNanoSeconds(), reply_target); + } + + void SetCurrentThreadHandleForCancelWait() { + /* ... */ + } + + void ClearCurrentThreadHandleForCancelWait() { + /* ... */ + } + }; + + using MultiWaitTargetImpl = MultiWaitWindowsImpl; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_native_handle_impl.hpp b/libraries/libstratosphere/source/os/impl/os_native_handle_impl.hpp index ef3708166..bb5fc5c2c 100644 --- a/libraries/libstratosphere/source/os/impl/os_native_handle_impl.hpp +++ b/libraries/libstratosphere/source/os/impl/os_native_handle_impl.hpp @@ -18,6 +18,12 @@ #if defined(ATMOSPHERE_OS_HORIZON) #include "os_native_handle_impl.os.horizon.hpp" +#elif defined(ATMOSPHERE_OS_WINDOWS) + #include "os_native_handle_impl.os.windows.hpp" +#elif defined(ATMOSPHERE_OS_LINUX) + #include "os_native_handle_impl.os.linux.hpp" +#elif defined(ATMOSPHERE_OS_MACOS) + #include "os_native_handle_impl.os.macos.hpp" #else #error "Unknown OS for ams::os::NativeHandleImpl" #endif \ No newline at end of file diff --git a/libraries/libstratosphere/source/os/impl/os_native_handle_impl.os.linux.hpp b/libraries/libstratosphere/source/os/impl/os_native_handle_impl.os.linux.hpp new file mode 100644 index 000000000..8cc4e3344 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_native_handle_impl.os.linux.hpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 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 + +namespace ams::os::impl { + + class NativeHandleLinuxImpl { + public: + static ALWAYS_INLINE void Close(NativeHandle handle) { + s32 ret; + do { + ret = ::close(handle); + } while (ret < 0 && errno == EINTR); + + AMS_ASSERT(ret == 0); + } + }; + + using NativeHandleImpl = NativeHandleLinuxImpl; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_native_handle_impl.os.macos.hpp b/libraries/libstratosphere/source/os/impl/os_native_handle_impl.os.macos.hpp new file mode 100644 index 000000000..b0ca8b540 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_native_handle_impl.os.macos.hpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 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 + +namespace ams::os::impl { + + class NativeHandleMacosImpl { + public: + static ALWAYS_INLINE void Close(NativeHandle handle) { + s32 ret; + do { + ret = ::close(handle); + } while (ret < 0 && errno == EINTR); + + AMS_ASSERT(ret == 0); + } + }; + + using NativeHandleImpl = NativeHandleMacosImpl; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_native_handle_impl.os.windows.hpp b/libraries/libstratosphere/source/os/impl/os_native_handle_impl.os.windows.hpp new file mode 100644 index 000000000..e181cb478 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_native_handle_impl.os.windows.hpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 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::impl { + + class NativeHandleWindowsImpl { + public: + static ALWAYS_INLINE void Close(NativeHandle handle) { + const auto ret = ::CloseHandle(handle); + AMS_ASSERT(ret != 0); + AMS_UNUSED(ret); + } + }; + + using NativeHandleImpl = NativeHandleWindowsImpl; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_process_handle_impl.hpp b/libraries/libstratosphere/source/os/impl/os_process_handle_impl.hpp index 5cc05761e..c5417336d 100644 --- a/libraries/libstratosphere/source/os/impl/os_process_handle_impl.hpp +++ b/libraries/libstratosphere/source/os/impl/os_process_handle_impl.hpp @@ -18,6 +18,12 @@ #if defined(ATMOSPHERE_OS_HORIZON) #include "os_process_handle_impl.os.horizon.hpp" +#elif defined(ATMOSPHERE_OS_WINDOWS) + #include "os_process_handle_impl.os.windows.hpp" +#elif defined(ATMOSPHERE_OS_LINUX) + #include "os_process_handle_impl.os.linux.hpp" +#elif defined(ATMOSPHERE_OS_MACOS) + #include "os_process_handle_impl.os.macos.hpp" #else #error "Unknown OS for ams::os::ProcessHandleImpl" #endif \ No newline at end of file diff --git a/libraries/libstratosphere/source/os/impl/os_process_handle_impl.os.linux.hpp b/libraries/libstratosphere/source/os/impl/os_process_handle_impl.os.linux.hpp new file mode 100644 index 000000000..1192cb9d8 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_process_handle_impl.os.linux.hpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 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::impl { + + class ProcessHandleLinuxImpl { + public: + static consteval NativeHandle GetCurrentProcessHandle() { + /* TODO: PseudoHandle define? */ + return -2; + } + + static ALWAYS_INLINE Result GetProcessId(ProcessId *out, NativeHandle handle) { + AMS_UNUSED(out, handle); + AMS_ABORT("TODO"); + } + + static ALWAYS_INLINE Result GetProgramId(ncm::ProgramId *out, NativeHandle handle) { + AMS_UNUSED(out, handle); + AMS_ABORT("TODO"); + } + }; + + using ProcessHandleImpl = ProcessHandleLinuxImpl; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_process_handle_impl.os.macos.hpp b/libraries/libstratosphere/source/os/impl/os_process_handle_impl.os.macos.hpp new file mode 100644 index 000000000..4b2d958a2 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_process_handle_impl.os.macos.hpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 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::impl { + + class ProcessHandleMacosImpl { + public: + static consteval NativeHandle GetCurrentProcessHandle() { + /* TODO: PseudoHandle define? */ + return -2; + } + + static ALWAYS_INLINE Result GetProcessId(ProcessId *out, NativeHandle handle) { + AMS_UNUSED(out, handle); + AMS_ABORT("TODO"); + } + + static ALWAYS_INLINE Result GetProgramId(ncm::ProgramId *out, NativeHandle handle) { + AMS_UNUSED(out, handle); + AMS_ABORT("TODO"); + } + }; + + using ProcessHandleImpl = ProcessHandleMacosImpl; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_process_handle_impl.os.windows.hpp b/libraries/libstratosphere/source/os/impl/os_process_handle_impl.os.windows.hpp new file mode 100644 index 000000000..5146698ca --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_process_handle_impl.os.windows.hpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 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::impl { + + class ProcessHandleWindowsImpl { + public: + static ALWAYS_INLINE NativeHandle GetCurrentProcessHandle() { + return ::GetCurrentProcess(); + } + + static ALWAYS_INLINE Result GetProcessId(ProcessId *out, NativeHandle handle) { + AMS_UNUSED(out, handle); + AMS_ABORT("TODO"); + } + + static ALWAYS_INLINE Result GetProgramId(ncm::ProgramId *out, NativeHandle handle) { + AMS_UNUSED(out, handle); + AMS_ABORT("TODO"); + } + }; + + using ProcessHandleImpl = ProcessHandleWindowsImpl; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_random_impl.os.linux.cpp b/libraries/libstratosphere/source/os/impl/os_random_impl.os.linux.cpp new file mode 100644 index 000000000..9923f9189 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_random_impl.os.linux.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) 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 + +namespace ams::os::impl { + + void InitializeRandomImpl(util::TinyMT *mt) { + /* Initialize twister based on system tick. */ + mt->Initialize(os::GetSystemTick().GetInt64Value()); + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_random_impl.os.macos.cpp b/libraries/libstratosphere/source/os/impl/os_random_impl.os.macos.cpp new file mode 100644 index 000000000..9923f9189 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_random_impl.os.macos.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) 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 + +namespace ams::os::impl { + + void InitializeRandomImpl(util::TinyMT *mt) { + /* Initialize twister based on system tick. */ + mt->Initialize(os::GetSystemTick().GetInt64Value()); + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_random_impl.os.windows.cpp b/libraries/libstratosphere/source/os/impl/os_random_impl.os.windows.cpp new file mode 100644 index 000000000..9923f9189 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_random_impl.os.windows.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) 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 + +namespace ams::os::impl { + + void InitializeRandomImpl(util::TinyMT *mt) { + /* Initialize twister based on system tick. */ + mt->Initialize(os::GetSystemTick().GetInt64Value()); + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_resource_manager.hpp b/libraries/libstratosphere/source/os/impl/os_resource_manager.hpp index 5170850a1..ea6f0e575 100644 --- a/libraries/libstratosphere/source/os/impl/os_resource_manager.hpp +++ b/libraries/libstratosphere/source/os/impl/os_resource_manager.hpp @@ -19,6 +19,9 @@ #include "os_thread_manager_types.hpp" #include "os_tick_manager_impl.hpp" #include "os_aslr_space_manager_types.hpp" +#include "os_tls_manager_types.hpp" +#include "os_giant_lock_types.hpp" +#include "os_vamm_manager_types.hpp" namespace ams::os::impl { @@ -28,21 +31,26 @@ namespace ams::os::impl { AslrSpaceManager m_aslr_space_manager{}; /* TODO */ ThreadManager m_thread_manager{}; - /* TODO */ + //TlsManager m_tls_manager{}; TickManager m_tick_manager{}; /* TODO */ + VammManager m_vamm_manager; + GiantLock m_giant_lock{}; public: OsResourceManager() = default; constexpr ALWAYS_INLINE RngManager &GetRngManager() { return m_rng_manager; } constexpr ALWAYS_INLINE AslrSpaceManager &GetAslrSpaceManager() { return m_aslr_space_manager; } constexpr ALWAYS_INLINE ThreadManager &GetThreadManager() { return m_thread_manager; } + //constexpr ALWAYS_INLINE TlsManager &GetTlsManager() { return m_tls_manager; } constexpr ALWAYS_INLINE TickManager &GetTickManager() { return m_tick_manager; } + constexpr ALWAYS_INLINE VammManager &GetVammManager() { return m_vamm_manager; } + constexpr ALWAYS_INLINE GiantLock &GetGiantLock() { return m_giant_lock; } }; class ResourceManagerHolder { private: - static util::TypedStorage s_resource_manager_storage; + static constinit util::TypedStorage s_resource_manager_storage; private: constexpr ResourceManagerHolder() { /* ... */ } public: diff --git a/libraries/libstratosphere/source/os/impl/os_rng_manager_impl.os.linux.cpp b/libraries/libstratosphere/source/os/impl/os_rng_manager_impl.os.linux.cpp new file mode 100644 index 000000000..91094ec93 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_rng_manager_impl.os.linux.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 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 "os_rng_manager_impl.hpp" + +namespace ams::os::impl { + + void RngManager::Initialize() { + /* Initialize twister based on system tick. */ + m_mt.Initialize(os::GetSystemTick().GetInt64Value()); + + /* Note that we've initialized. */ + m_initialized = true; + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_rng_manager_impl.os.macos.cpp b/libraries/libstratosphere/source/os/impl/os_rng_manager_impl.os.macos.cpp new file mode 100644 index 000000000..91094ec93 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_rng_manager_impl.os.macos.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 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 "os_rng_manager_impl.hpp" + +namespace ams::os::impl { + + void RngManager::Initialize() { + /* Initialize twister based on system tick. */ + m_mt.Initialize(os::GetSystemTick().GetInt64Value()); + + /* Note that we've initialized. */ + m_initialized = true; + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_rng_manager_impl.os.windows.cpp b/libraries/libstratosphere/source/os/impl/os_rng_manager_impl.os.windows.cpp new file mode 100644 index 000000000..91094ec93 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_rng_manager_impl.os.windows.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 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 "os_rng_manager_impl.hpp" + +namespace ams::os::impl { + + void RngManager::Initialize() { + /* Initialize twister based on system tick. */ + m_mt.Initialize(os::GetSystemTick().GetInt64Value()); + + /* Note that we've initialized. */ + m_initialized = true; + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_rw_lock_impl.hpp b/libraries/libstratosphere/source/os/impl/os_rw_lock_impl.hpp index 379c45442..7fa63e0e2 100644 --- a/libraries/libstratosphere/source/os/impl/os_rw_lock_impl.hpp +++ b/libraries/libstratosphere/source/os/impl/os_rw_lock_impl.hpp @@ -19,7 +19,7 @@ #if defined(ATMOSPHERE_OS_HORIZON) #include "os_rw_lock_target_impl.os.horizon.hpp" #else - #error "Unknown OS for os::ReaderWriterLockTargetImpl" + #include "os_rw_lock_target_impl.os.generic.hpp" #endif namespace ams::os::impl { diff --git a/libraries/libstratosphere/source/os/impl/os_rw_lock_target_impl.os.generic.cpp b/libraries/libstratosphere/source/os/impl/os_rw_lock_target_impl.os.generic.cpp new file mode 100644 index 000000000..e76dd6b96 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_rw_lock_target_impl.os.generic.cpp @@ -0,0 +1,238 @@ +/* + * Copyright (c) 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 "os_rw_lock_impl.hpp" +#include "os_thread_manager.hpp" + +namespace ams::os::impl { + + void ReaderWriterLockHorizonImpl::AcquireReadLock(os::ReaderWriterLockType *rw_lock) { + /* Acquire exclusive access. */ + std::scoped_lock lk(util::GetReference(GetLockCount(rw_lock).cs_storage)); + + /* Get the lock into a state where we can safely increment the read lock count. */ + if (rw_lock->owner_thread == impl::GetCurrentThread()) { + /* If we're the owner thread, we should hold the write lock. */ + AMS_ASSERT(GetWriteLocked(GetLockCount(rw_lock)) == 1); + } else { + /* Wait until we're not write locked, and there are no write lock waiters. */ + while (true) { + /* Check if we're write locked. */ + if (GetWriteLocked(GetLockCount(rw_lock)) != 1) { + /* We're not, so check if we have write lock waiters. */ + if (GetWriteLockWaiterCount(GetLockCount(rw_lock)) == 0) { + break; + } + } + + /* We're write locked, or we have write lock waiters. */ + IncReadLockWaiterCount(GetLockCount(rw_lock)); + util::GetReference(rw_lock->cv_read_lock._storage).Wait(util::GetPointer(GetLockCount(rw_lock).cs_storage)); + DecReadLockWaiterCount(GetLockCount(rw_lock)); + } + + /* Verify we're in the desired state. */ + AMS_ASSERT(GetWriteLockCount(*rw_lock) == 0); + AMS_ASSERT(rw_lock->owner_thread == nullptr); + } + + /* Increment the read lock count. */ + IncReadLockCount(GetLockCount(rw_lock)); + } + + bool ReaderWriterLockHorizonImpl::TryAcquireReadLock(os::ReaderWriterLockType *rw_lock) { + /* Acquire exclusive access. */ + std::scoped_lock lk(util::GetReference(GetLockCount(rw_lock).cs_storage)); + + /* Try to get the lock into a state where we can safely increment the read lock count. */ + if (rw_lock->owner_thread == impl::GetCurrentThread()) { + /* If we're the owner thread, we should hold the write lock. */ + AMS_ASSERT(GetWriteLocked(GetLockCount(rw_lock)) == 1); + } else { + /* We can only read lock if we're not write locked, and there are no write lock waiters. */ + if (GetWriteLocked(GetLockCount(rw_lock)) == 1) { + return false; + } + if (GetWriteLockWaiterCount(GetLockCount(rw_lock)) != 0) { + return false; + } + + /* Verify we're in the desired state. */ + AMS_ASSERT(GetWriteLockCount(*rw_lock) == 0); + AMS_ASSERT(rw_lock->owner_thread == nullptr); + } + + /* Increment the read lock count. */ + IncReadLockCount(GetLockCount(rw_lock)); + return true; + } + + void ReaderWriterLockHorizonImpl::ReleaseReadLock(os::ReaderWriterLockType *rw_lock) { + /* Acquire exclusive access. */ + std::scoped_lock lk(util::GetReference(GetLockCount(rw_lock).cs_storage)); + + /* Sanity check that we hold the read lock. */ + AMS_ASSERT(GetReadLockCount(GetLockCount(rw_lock)) > 0); + + /* Decrement the read lock count. */ + DecReadLockCount(GetLockCount(rw_lock)); + + /* If we're the owner of the write lock, we may need to check if this causes a full release/signal to waiters. */ + if (rw_lock->owner_thread == impl::GetCurrentThread()) { + /* Sanity check that we're write locked. */ + AMS_ASSERT(GetWriteLocked(GetLockCount(rw_lock)) == 1); + + /* If we've called ReleaseWriteLock and have no remaining read locks, we may need to signal/broadcast. */ + if (GetWriteLockCount(*rw_lock) == 0 && GetReadLockCount(GetLockCount(rw_lock)) == 0) { + /* Clear lock owner. */ + rw_lock->owner_thread = nullptr; + + /* Clear write locked. */ + ClearWriteLocked(GetLockCount(rw_lock)); + + /* If we have lock waiters, signal them. */ + if (GetWriteLockWaiterCount(GetLockCount(rw_lock)) != 0) { + util::GetReference(rw_lock->cv_write_lock._storage).Signal(); + } else if (GetReadLockWaiterCount(GetLockCount(rw_lock)) != 0) { + util::GetReference(rw_lock->cv_read_lock._storage).Broadcast(); + } + } + } else { + /* Sanity check that our read lock release was fine. */ + AMS_ASSERT(GetWriteLockCount(*rw_lock) == 0); + AMS_ASSERT(GetWriteLocked(GetLockCount(rw_lock)) == 0); + AMS_ASSERT(rw_lock->owner_thread == nullptr); + + /* We need to signal if there are no remaining read locks. */ + if (GetReadLockCount(GetLockCount(rw_lock)) == 0) { + if (GetWriteLockWaiterCount(GetLockCount(rw_lock)) != 0) { + util::GetReference(rw_lock->cv_write_lock._storage).Signal(); + } + } + } + } + + void ReaderWriterLockHorizonImpl::AcquireWriteLock(os::ReaderWriterLockType *rw_lock) { + /* Acquire exclusive access. */ + std::scoped_lock lk(util::GetReference(GetLockCount(rw_lock).cs_storage)); + + /* Get the lock into a state where we can safely increment the read lock count. */ + if (rw_lock->owner_thread == impl::GetCurrentThread()) { + /* If we're the owner thread, we should hold the write lock. */ + AMS_ASSERT(GetWriteLocked(GetLockCount(rw_lock)) == 1); + + /* Increment the write lock count. */ + IncWriteLockCount(*rw_lock); + } else { + /* Wait until we're not read locked and not write locked. */ + while (true) { + /* Check if we're read locked. */ + if (GetReadLockCount(GetLockCount(rw_lock)) == 0) { + /* We're not, so check if we're write locked. */ + if (GetWriteLocked(GetLockCount(rw_lock)) != 1) { + break; + } + } + + /* We're write locked or read locked. */ + IncWriteLockWaiterCount(GetLockCount(rw_lock)); + util::GetReference(rw_lock->cv_write_lock._storage).Wait(util::GetPointer(GetLockCount(rw_lock).cs_storage)); + DecWriteLockWaiterCount(GetLockCount(rw_lock)); + } + + /* Verify we're in the desired state. */ + AMS_ASSERT(GetWriteLockCount(*rw_lock) == 0); + AMS_ASSERT(rw_lock->owner_thread == nullptr); + + /* Increment the write lock count. */ + IncWriteLockCount(*rw_lock); + + /* Set write locked. */ + SetWriteLocked(GetLockCount(rw_lock)); + + /* Set ourselves as the owner. */ + rw_lock->owner_thread = impl::GetCurrentThread(); + } + } + + bool ReaderWriterLockHorizonImpl::TryAcquireWriteLock(os::ReaderWriterLockType *rw_lock) { + /* Acquire exclusive access. */ + std::scoped_lock lk(util::GetReference(GetLockCount(rw_lock).cs_storage)); + + /* Get the lock into a state where we can safely increment the read lock count. */ + if (rw_lock->owner_thread == impl::GetCurrentThread()) { + /* If we're the owner thread, we should hold the write lock. */ + AMS_ASSERT(GetWriteLocked(GetLockCount(rw_lock)) == 1); + + /* Increment the write lock count. */ + IncWriteLockCount(*rw_lock); + } else { + /* Check if we're read locked. */ + if (GetReadLockCount(GetLockCount(rw_lock)) != 0) { + return false; + } + /* We're not, so check if we're write locked. */ + if (GetWriteLocked(GetLockCount(rw_lock)) == 1) { + return false; + } + + /* Verify we're in the desired state. */ + AMS_ASSERT(GetWriteLockCount(*rw_lock) == 0); + AMS_ASSERT(rw_lock->owner_thread == nullptr); + + /* Increment the write lock count. */ + IncWriteLockCount(*rw_lock); + + /* Set write locked. */ + SetWriteLocked(GetLockCount(rw_lock)); + + /* Set ourselves as the owner. */ + rw_lock->owner_thread = impl::GetCurrentThread(); + } + + return true; + } + + void ReaderWriterLockHorizonImpl::ReleaseWriteLock(os::ReaderWriterLockType *rw_lock) { + /* Acquire exclusive access. */ + std::scoped_lock lk(util::GetReference(GetLockCount(rw_lock).cs_storage)); + + /* Sanity check our state. */ + AMS_ASSERT(GetWriteLockCount(*rw_lock) > 0); + AMS_ASSERT(GetWriteLocked(GetLockCount(rw_lock)) != 0); + AMS_ASSERT(rw_lock->owner_thread == impl::GetCurrentThread()); + + /* Decrement the write lock count. */ + DecWriteLockCount(*rw_lock); + + /* If we have no remaining write locks, we may need to signal/release. */ + if (GetWriteLockCount(*rw_lock) == 0 && GetReadLockCount(GetLockCount(rw_lock)) == 0) { + /* Clear lock owner. */ + rw_lock->owner_thread = nullptr; + + /* Clear write locked. */ + ClearWriteLocked(GetLockCount(rw_lock)); + + /* If we have lock waiters, signal them. */ + if (GetWriteLockWaiterCount(GetLockCount(rw_lock)) != 0) { + util::GetReference(rw_lock->cv_write_lock._storage).Signal(); + } else if (GetReadLockWaiterCount(GetLockCount(rw_lock)) != 0) { + util::GetReference(rw_lock->cv_read_lock._storage).Broadcast(); + } + } + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_rw_lock_target_impl.os.generic.hpp b/libraries/libstratosphere/source/os/impl/os_rw_lock_target_impl.os.generic.hpp new file mode 100644 index 000000000..d71e6b32d --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_rw_lock_target_impl.os.generic.hpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 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::impl { + + class ReaderWriterLockHorizonImpl { + private: + using LockCount = os::ReaderWriterLockType::LockCount; + public: + static void AcquireReadLock(os::ReaderWriterLockType *rw_lock); + static bool TryAcquireReadLock(os::ReaderWriterLockType *rw_lock); + static void ReleaseReadLock(os::ReaderWriterLockType *rw_lock); + + static void AcquireWriteLock(os::ReaderWriterLockType *rw_lock); + static bool TryAcquireWriteLock(os::ReaderWriterLockType *rw_lock); + static void ReleaseWriteLock(os::ReaderWriterLockType *rw_lock); + }; + + using ReaderWriterLockTargetImpl = ReaderWriterLockHorizonImpl; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_thread_manager.cpp b/libraries/libstratosphere/source/os/impl/os_thread_manager.cpp index f6478795a..3db465401 100644 --- a/libraries/libstratosphere/source/os/impl/os_thread_manager.cpp +++ b/libraries/libstratosphere/source/os/impl/os_thread_manager.cpp @@ -23,7 +23,10 @@ namespace ams::os::impl { - void SetupThreadObjectUnsafe(ThreadType *thread, ThreadImpl *thread_impl, ThreadFunction function, void *arg, void *stack, size_t stack_size, s32 priority) { + void SetupThreadObjectUnsafe(ThreadType *thread, void *platform, ThreadFunction function, void *arg, void *stack, size_t stack_size, s32 priority) { + /* Clear the thread object. */ + std::memset(thread, 0, sizeof(*thread)); + /* Setup objects. */ util::ConstructAt(thread->cs_thread); util::ConstructAt(thread->cv_thread); @@ -32,20 +35,37 @@ namespace ams::os::impl { util::ConstructAt(thread->waitlist); /* Set member variables. */ - thread->magic = os::ThreadType::Magic; - thread->version = 0; - thread->thread_impl = (thread_impl != nullptr) ? thread_impl : std::addressof(thread->thread_impl_storage); - thread->function = function; - thread->argument = arg; - thread->stack = stack; - thread->stack_size = stack_size; - thread->base_priority = priority; - thread->suspend_count = 0; - thread->name_buffer[0] = '\x00'; - thread->name_pointer = thread->name_buffer; + thread->magic = os::ThreadType::Magic; + thread->stack_is_aliased = false; + thread->auto_registered = false; + thread->version = 0; + thread->function = function; + thread->argument = arg; + thread->original_stack = stack; + thread->stack = stack; + thread->stack_size = stack_size; + thread->base_priority = priority; + thread->suspend_count = 0; + thread->initial_fiber = nullptr; + thread->current_fiber = nullptr; + thread->name_buffer[0] = '\x00'; + thread->name_pointer = thread->name_buffer; - /* Set internal tls variables. */ - thread->atomic_sf_inline_context = 0; + /* Set platform variables. */ + #if defined(AMS_OS_IMPL_USE_PTHREADS) + util::ConstructAt(thread->cs_pthread_exit); + util::ConstructAt(thread->cv_pthread_exit); + thread->exited_pthread = false; + + std::memset(thread->tls_value_array, 0, sizeof(thread->tls_value_array)); + AMS_UNUSED(platform); + #elif defined(ATMOSPHERE_OS_HORIZON) + std::memset(std::addressof(thread->sdk_internal_tls), 0, sizeof(thread->sdk_internal_tls)); + thread->thread_impl = (platform != nullptr) ? static_cast(platform) : std::addressof(thread->thread_impl_storage); + #else + std::memset(thread->tls_value_array, 0, sizeof(thread->tls_value_array)); + AMS_UNUSED(platform); + #endif /* Mark initialized. */ thread->state = ThreadType::State_Initialized; @@ -74,36 +94,61 @@ namespace ams::os::impl { } ThreadManager::ThreadManager() : m_impl(std::addressof(m_main_thread)), m_total_thread_stack_size(0), m_num_created_threads(0) { + m_total_thread_stack_size = 0; + m_num_created_threads = 0; + m_main_thread.state = ThreadType::State_Started; this->SetCurrentThread(std::addressof(m_main_thread)); - this->PlaceThreadObjectUnderThreadManagerSafe(std::addressof(m_main_thread)); } + void ThreadManager::CleanupThread(ThreadType *thread) { + /* TODO: TLS Manager->InvokeTlsDestructors(); */ + + std::scoped_lock lk(GetReference(thread->cs_thread)); + + thread->state = ThreadType::State_Terminated; + + GetReference(thread->cv_thread).Broadcast(); + GetReference(thread->waitlist).SignalAllThreads(); + } + void ThreadManager::CleanupThread() { - ThreadType *thread = this->GetCurrentThread(); + return this->CleanupThread(this->GetCurrentThread()); + } - { - std::scoped_lock lk(GetReference(thread->cs_thread)); - - thread->state = ThreadType::State_Terminated; - - GetReference(thread->cv_thread).Broadcast(); - GetReference(thread->waitlist).SignalAllThreads(); + bool ThreadManager::CreateAliasStackUnsafe(ThreadType *thread) { + void *alias_stack; + if (m_impl.MapAliasStack(std::addressof(alias_stack), thread->stack, thread->stack_size)) { + thread->stack_is_aliased = true; + thread->stack = alias_stack; + return true; + } else { + return false; } } + void ThreadManager::DeleteAliasStackUnsafe(ThreadType *thread) { + AMS_ABORT_UNLESS(m_impl.UnmapAliasStack(thread->stack, thread->original_stack, thread->stack_size)); + + thread->stack_is_aliased = false; + thread->stack = thread->original_stack; + } + Result ThreadManager::CreateThread(ThreadType *thread, ThreadFunction function, void *argument, void *stack, size_t stack_size, s32 priority, s32 ideal_core) { SetupThreadObjectUnsafe(thread, nullptr, function, argument, stack, stack_size, priority); + AMS_ABORT_UNLESS(this->CreateAliasStackUnsafe(thread)); + ON_RESULT_FAILURE { + this->DeleteAliasStackUnsafe(thread); + thread->state = ThreadType::State_NotInitialized; + }; - auto guard = SCOPE_GUARD { thread->state = ThreadType::State_NotInitialized; }; R_TRY(m_impl.CreateThread(thread, ideal_core)); - guard.Cancel(); this->PlaceThreadObjectUnderThreadManagerSafe(thread); - return ResultSuccess(); + R_SUCCEED(); } Result ThreadManager::CreateThread(ThreadType *thread, ThreadFunction function, void *argument, void *stack, size_t stack_size, s32 priority) { @@ -123,27 +168,33 @@ namespace ams::os::impl { m_impl.WaitForThreadExit(thread); - AMS_ASSERT(thread->state == ThreadType::State_Initialized); + this->DestroyThreadObject(thread); + } + void ThreadManager::DestroyThreadObject(ThreadType *thread) { { std::scoped_lock lk(GetReference(thread->cs_thread)); - /* NOTE: Here Nintendo would cleanup the alias stack. */ - - m_impl.DestroyThreadUnsafe(thread); - - thread->state = ThreadType::State_NotInitialized; - - util::DestroyAt(thread->waitlist); - - thread->name_buffer[0] = '\x00'; - thread->magic = 0xCCCC; - { std::scoped_lock tlk(m_cs); this->EraseFromAllThreadsListUnsafe(thread); } + + if (thread->stack_is_aliased) { + this->DeleteAliasStackUnsafe(thread); + } + + m_impl.DestroyThreadUnsafe(thread); + + thread->state = ThreadType::State_NotInitialized; + + thread->name_buffer[0] = '\x00'; + thread->magic = 0xCCCC; + + util::DestroyAt(thread->waitlist); } + util::DestroyAt(thread->cs_thread); + util::DestroyAt(thread->cv_thread); } void ThreadManager::StartThread(ThreadType *thread) { @@ -163,7 +214,9 @@ namespace ams::os::impl { { std::scoped_lock lk(GetReference(thread->cs_thread)); - /* Note: Here Nintendo would cleanup the alias stack. */ + if (thread->stack_is_aliased) { + this->DeleteAliasStackUnsafe(thread); + } } } @@ -173,7 +226,9 @@ namespace ams::os::impl { if (result) { std::scoped_lock lk(GetReference(thread->cs_thread)); - /* Note: Here Nintendo would cleanup the alias stack. */ + if (thread->stack_is_aliased) { + this->DeleteAliasStackUnsafe(thread); + } } return result; @@ -182,7 +237,7 @@ namespace ams::os::impl { s32 ThreadManager::SuspendThread(ThreadType *thread) { std::scoped_lock lk(GetReference(thread->cs_thread)); - auto prev_suspend_count = thread->suspend_count; + const auto prev_suspend_count = thread->suspend_count; AMS_ASSERT(prev_suspend_count < ThreadSuspendCountMax); thread->suspend_count = prev_suspend_count + 1; @@ -195,7 +250,7 @@ namespace ams::os::impl { s32 ThreadManager::ResumeThread(ThreadType *thread) { std::scoped_lock lk(GetReference(thread->cs_thread)); - auto prev_suspend_count = thread->suspend_count; + const auto prev_suspend_count = thread->suspend_count; if (prev_suspend_count > 0) { thread->suspend_count = prev_suspend_count - 1; if (prev_suspend_count == 1) { @@ -205,11 +260,15 @@ namespace ams::os::impl { return prev_suspend_count; } - void ThreadManager::CancelThreadSynchronization(ThreadType *thread) { - std::scoped_lock lk(GetReference(thread->cs_thread)); + #if !defined(ATMOSPHERE_OS_HORIZON) + void ThreadManager::SetZeroToAllThreadsTlsSafe(int slot) { + std::scoped_lock lk(m_cs); - m_impl.CancelThreadSynchronizationUnsafe(thread); + for (auto it = m_all_threads_list.begin(); it != m_all_threads_list.end(); ++it) { + it->tls_value_array[slot] = 0; + } } + #endif /* TODO void ThreadManager::GetThreadContext(ThreadContextInfo *out_context, const ThreadType *thread); */ diff --git a/libraries/libstratosphere/source/os/impl/os_thread_manager.hpp b/libraries/libstratosphere/source/os/impl/os_thread_manager.hpp index bf3b5e25f..6721cfa21 100644 --- a/libraries/libstratosphere/source/os/impl/os_thread_manager.hpp +++ b/libraries/libstratosphere/source/os/impl/os_thread_manager.hpp @@ -30,11 +30,16 @@ namespace ams::os::impl { return GetThreadManager().GetCurrentThread(); } + #if !defined(AMS_OS_IMPL_USE_PTHREADS) ALWAYS_INLINE NativeHandle GetCurrentThreadHandle() { - /* return GetCurrentThread()->thread_impl->handle; */ + #if defined(ATMOSPHERE_OS_HORIZON) return ::threadGetCurHandle(); + #else + return GetCurrentThread()->native_handle; + #endif } + #endif - void SetupThreadObjectUnsafe(ThreadType *thread, ThreadImpl *thread_impl, ThreadFunction function, void *arg, void *stack, size_t stack_size, s32 priority); + void SetupThreadObjectUnsafe(ThreadType *thread, void *platform, ThreadFunction function, void *arg, void *stack, size_t stack_size, s32 priority); } diff --git a/libraries/libstratosphere/source/os/impl/os_thread_manager_impl.os.horizon.cpp b/libraries/libstratosphere/source/os/impl/os_thread_manager_impl.os.horizon.cpp index 2bce07e5c..438b79428 100644 --- a/libraries/libstratosphere/source/os/impl/os_thread_manager_impl.os.horizon.cpp +++ b/libraries/libstratosphere/source/os/impl/os_thread_manager_impl.os.horizon.cpp @@ -50,14 +50,15 @@ namespace ams::os::impl { ThreadManagerHorizonImpl::ThreadManagerHorizonImpl(ThreadType *main_thread) { /* Get the thread impl object from libnx. */ - ThreadImpl *thread_impl = ::threadGetSelf(); + ThreadType::ThreadImpl *thread_impl = ::threadGetSelf(); + auto * const original_thread_impl = thread_impl; /* Hack around libnx's main thread, to ensure stratosphere thread type consistency. */ { auto *tlr = reinterpret_cast(svc::GetThreadLocalRegion()); for (size_t i = sizeof(svc::ThreadLocalRegion) / sizeof(uintptr_t); i > 0; --i) { - if (auto *candidate = reinterpret_cast(tlr[i - 1]); candidate == thread_impl) { - ThreadImpl *embedded_thread = std::addressof(main_thread->thread_impl_storage); + if (auto *candidate = reinterpret_cast(tlr[i - 1]); candidate == thread_impl) { + ThreadType::ThreadImpl *embedded_thread = std::addressof(main_thread->thread_impl_storage); *embedded_thread = *thread_impl; @@ -78,6 +79,9 @@ namespace ams::os::impl { SetupThreadObjectUnsafe(main_thread, thread_impl, nullptr, nullptr, thread_impl->stack_mirror, thread_impl->stack_sz, ConvertToUserPriority(horizon_priority)); + /* Fix up the thread impl. */ + *thread_impl = *original_thread_impl; + /* Set the thread id. */ u64 thread_id; R_ABORT_UNLESS(svc::GetThreadId(std::addressof(thread_id), thread_impl->handle)); @@ -184,10 +188,6 @@ namespace ams::os::impl { R_ABORT_UNLESS(svc::SetThreadActivity(thread->thread_impl->handle, svc::ThreadActivity_Runnable)); } - void ThreadManagerHorizonImpl::CancelThreadSynchronizationUnsafe(ThreadType *thread) { - R_ABORT_UNLESS(svc::CancelSynchronization(thread->thread_impl->handle)); - } - /* TODO: void GetThreadContextUnsafe(ThreadContextInfo *out_context, const ThreadType *thread); */ s32 ThreadManagerHorizonImpl::GetCurrentCoreNumber() const { @@ -218,5 +218,18 @@ namespace ams::os::impl { return core_mask; } + bool ThreadManagerHorizonImpl::MapAliasStack(void **out, void *stack, size_t size) { + /* TODO: This will need to be real, if we ever stop using libnx threads. */ + AMS_UNUSED(stack, size); + *out = stack; + return true; + } + + bool ThreadManagerHorizonImpl::UnmapAliasStack(void *alias_stack, void *original_stack, size_t size) { + /* TODO: This will need to be real, if we ever stop using libnx threads. */ + AMS_UNUSED(alias_stack, original_stack, size); + return true; + } + } diff --git a/libraries/libstratosphere/source/os/impl/os_thread_manager_impl.os.horizon.hpp b/libraries/libstratosphere/source/os/impl/os_thread_manager_impl.os.horizon.hpp index 8a8350aad..8f13cc01d 100644 --- a/libraries/libstratosphere/source/os/impl/os_thread_manager_impl.os.horizon.hpp +++ b/libraries/libstratosphere/source/os/impl/os_thread_manager_impl.os.horizon.hpp @@ -47,8 +47,6 @@ namespace ams::os::impl { void SuspendThreadUnsafe(ThreadType *thread); void ResumeThreadUnsafe(ThreadType *thread); - void CancelThreadSynchronizationUnsafe(ThreadType *thread); - /* TODO: void GetThreadContextUnsafe(ThreadContextInfo *out_context, const ThreadType *thread); */ void NotifyThreadNameChangedImpl(const ThreadType *thread) const { AMS_UNUSED(thread); } @@ -68,10 +66,17 @@ namespace ams::os::impl { void GetThreadCoreMask(s32 *out_ideal_core, u64 *out_affinity_mask, const ThreadType *thread) const; u64 GetThreadAvailableCoreMask() const; + bool MapAliasStack(void **out, void *stack, size_t size); + bool UnmapAliasStack(void *alias_stack, void *original_stack, size_t size); + NORETURN void ExitProcessImpl() { svc::ExitProcess(); AMS_ABORT("Process was exited"); } + + NORETURN void QuickExit() { + AMS_ABORT("TODO: make QuickExit properly a thing"); + } }; using ThreadManagerImpl = ThreadManagerHorizonImpl; diff --git a/libraries/libstratosphere/source/os/impl/os_thread_manager_impl.os.windows.cpp b/libraries/libstratosphere/source/os/impl/os_thread_manager_impl.os.windows.cpp new file mode 100644 index 000000000..0e43caca0 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_thread_manager_impl.os.windows.cpp @@ -0,0 +1,262 @@ +/* + * Copyright (c) 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 "os_thread_manager_impl.os.windows.hpp" +#include "os_thread_manager.hpp" + +namespace ams::os::impl { + + namespace { + + constexpr size_t DefaultStackSize = 1_MB; + + class ScopedSaveLastError { + NON_COPYABLE(ScopedSaveLastError); + NON_MOVEABLE(ScopedSaveLastError); + private: + DWORD m_last_error; + public: + ALWAYS_INLINE ScopedSaveLastError() : m_last_error(::GetLastError()) { /* ... */ } + ALWAYS_INLINE ~ScopedSaveLastError() { ::SetLastError(m_last_error); } + }; + + unsigned __stdcall InvokeThread(void *arg) { + ThreadType *thread = static_cast(arg); + + /* Invoke the thread. */ + ThreadManager::InvokeThread(thread); + + return 0; + } + + os::NativeHandle DuplicateThreadHandle(os::NativeHandle thread_handle) { + /* Get the thread's windows handle. */ + os::NativeHandle windows_handle = os::InvalidNativeHandle; + AMS_ABORT_UNLESS(::DuplicateHandle(::GetCurrentProcess(), thread_handle, ::GetCurrentProcess(), std::addressof(windows_handle), 0, 0, DUPLICATE_SAME_ACCESS)); + + return windows_handle; + } + + os::ThreadType *DynamicAllocateAndRegisterThreadType() { + /* Get the thread manager. */ + auto &thread_manager = GetThreadManager(); + + /* Allocate a thread. */ + auto *thread = thread_manager.AllocateThreadType(); + AMS_ABORT_UNLESS(thread != nullptr); + + /* Setup the thread object. */ + SetupThreadObjectUnsafe(thread, nullptr, nullptr, nullptr, nullptr, 0, DefaultThreadPriority); + thread->state = ThreadType::State_Started; + thread->auto_registered = true; + + /* Set the thread's windows handle. */ + thread->native_handle = DuplicateThreadHandle(::GetCurrentThread()); + thread->ideal_core = ::GetCurrentProcessorNumber(); + thread->affinity_mask = thread_manager.GetThreadAvailableCoreMask(); + + /* Place the object under the thread manager. */ + thread_manager.PlaceThreadObjectUnderThreadManagerSafe(thread); + + return thread; + } + + } + + ThreadManagerWindowsImpl::ThreadManagerWindowsImpl(ThreadType *main_thread) : m_tls_index(::TlsAlloc()) { + /* Verify tls index is valid. */ + AMS_ASSERT(m_tls_index != TLS_OUT_OF_INDEXES); + + /* Setup the main thread object. */ + SetupThreadObjectUnsafe(main_thread, nullptr, nullptr, nullptr, nullptr, DefaultStackSize, DefaultThreadPriority); + + + /* Setup the main thread's windows handle information. */ + main_thread->native_handle = DuplicateThreadHandle(::GetCurrentThread()); + main_thread->ideal_core = ::GetCurrentProcessorNumber(); + main_thread->affinity_mask = this->GetThreadAvailableCoreMask(); + } + + Result ThreadManagerWindowsImpl::CreateThread(ThreadType *thread, s32 ideal_core) { + /* Create the thread. */ + os::NativeHandle thread_handle = reinterpret_cast(_beginthreadex(nullptr, thread->stack_size, &InvokeThread, thread, CREATE_SUSPENDED, 0)); + AMS_ASSERT(thread_handle != os::InvalidNativeHandle); + + /* Set the thread's windows handle information. */ + thread->native_handle = thread_handle; + thread->ideal_core = ideal_core; + thread->affinity_mask = this->GetThreadAvailableCoreMask(); + + R_SUCCEED(); + } + + void ThreadManagerWindowsImpl::DestroyThreadUnsafe(ThreadType *thread) { + /* Close the thread's handle. */ + const auto ret = ::CloseHandle(thread->native_handle); + AMS_ASSERT(ret); + AMS_UNUSED(ret); + + thread->native_handle = os::InvalidNativeHandle; + } + + void ThreadManagerWindowsImpl::StartThread(const ThreadType *thread) { + ScopedSaveLastError save_error; + + /* Resume the thread. */ + const auto ret = ::ResumeThread(thread->native_handle); + AMS_ASSERT(ret == 1); + AMS_UNUSED(ret); + } + + void ThreadManagerWindowsImpl::WaitForThreadExit(ThreadType *thread) { + ::WaitForSingleObject(thread->native_handle, INFINITE); + } + + bool ThreadManagerWindowsImpl::TryWaitForThreadExit(ThreadType *thread) { + return ::WaitForSingleObject(thread->native_handle, 0) == 0; + } + + void ThreadManagerWindowsImpl::YieldThread() { + ::Sleep(0); + } + + bool ThreadManagerWindowsImpl::ChangePriority(ThreadType *thread, s32 priority) { + AMS_UNUSED(thread, priority); + return true; + } + + s32 ThreadManagerWindowsImpl::GetCurrentPriority(const ThreadType *thread) const { + return thread->base_priority; + } + + ThreadId ThreadManagerWindowsImpl::GetThreadId(const ThreadType *thread) const { + ScopedSaveLastError save_error; + + const auto thread_id = ::GetThreadId(thread->native_handle); + AMS_ASSERT(thread_id != 0); + + return thread_id; + } + + void ThreadManagerWindowsImpl::SuspendThreadUnsafe(ThreadType *thread) { + ScopedSaveLastError save_error; + + const auto ret = ::SuspendThread(thread->native_handle); + AMS_ASSERT(ret == 0); + AMS_UNUSED(ret); + } + + void ThreadManagerWindowsImpl::ResumeThreadUnsafe(ThreadType *thread) { + ScopedSaveLastError save_error; + + const auto ret = ::ResumeThread(thread->native_handle); + AMS_ASSERT(ret == 1); + AMS_UNUSED(ret); + } + + /* TODO: void ThreadManagerWindowsImpl::GetThreadContextUnsafe(ThreadContextInfo *out_context, const ThreadType *thread); */ + + void ThreadManagerWindowsImpl::NotifyThreadNameChangedImpl(const ThreadType *thread) const { + /* TODO */ + AMS_UNUSED(thread); + } + + void ThreadManagerWindowsImpl::SetCurrentThread(ThreadType *thread) const { + ScopedSaveLastError save_error; + + ::TlsSetValue(m_tls_index, thread); + } + + ThreadType *ThreadManagerWindowsImpl::GetCurrentThread() const { + ScopedSaveLastError save_error; + + /* Get the thread from tls index. */ + ThreadType *thread = static_cast(static_cast(::TlsGetValue(m_tls_index))); + + /* If the thread's TLS isn't set, we need to find it (and set tls) or make it. */ + if (thread == nullptr) { + /* Try to find the thread. */ + thread = GetThreadManager().FindThreadTypeById(::GetCurrentThreadId()); + if (thread == nullptr) { + /* Create the thread. */ + thread = DynamicAllocateAndRegisterThreadType(); + } + + /* Set the thread's TLS. */ + this->SetCurrentThread(thread); + } + + return thread; + } + + s32 ThreadManagerWindowsImpl::GetCurrentCoreNumber() const { + ScopedSaveLastError save_error; + + return ::GetCurrentProcessorNumber(); + } + + void ThreadManagerWindowsImpl::SetThreadCoreMask(ThreadType *thread, s32 ideal_core, u64 affinity_mask) const { + ScopedSaveLastError save_error; + + /* If we should use the default, set the actual ideal core. */ + if (ideal_core == IdealCoreUseDefault) { + affinity_mask = this->GetThreadAvailableCoreMask(); + ideal_core = util::CountTrailingZeros(affinity_mask); + affinity_mask = static_cast(1) << ideal_core; + } + + /* Lock the thread. */ + std::scoped_lock lk(util::GetReference(thread->cs_thread)); + + /* Set the thread's affinity mask. */ + const auto old = ::SetThreadAffinityMask(thread->native_handle, affinity_mask); + AMS_ABORT_UNLESS(old != 0); + + /* Set the ideal core. */ + if (ideal_core != IdealCoreNoUpdate) { + thread->ideal_core = ideal_core; + } + + /* Set the tracked affinity mask. */ + thread->affinity_mask = affinity_mask; + } + + void ThreadManagerWindowsImpl::GetThreadCoreMask(s32 *out_ideal_core, u64 *out_affinity_mask, const ThreadType *thread) const { + ScopedSaveLastError save_error; + + /* Lock the thread. */ + std::scoped_lock lk(util::GetReference(thread->cs_thread)); + + /* Set the output. */ + if (out_ideal_core != nullptr) { + *out_ideal_core = thread->ideal_core; + } + if (out_affinity_mask != nullptr) { + *out_affinity_mask = thread->affinity_mask; + } + } + + u64 ThreadManagerWindowsImpl::GetThreadAvailableCoreMask() const { + ScopedSaveLastError save_error; + + /* Get the process's affinity mask. */ + u64 process_affinity, system_affinity; + AMS_ABORT_UNLESS(::GetProcessAffinityMask(::GetCurrentProcess(), std::addressof(process_affinity), std::addressof(system_affinity)) != 0); + + return process_affinity; + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_thread_manager_impl.os.windows.hpp b/libraries/libstratosphere/source/os/impl/os_thread_manager_impl.os.windows.hpp new file mode 100644 index 000000000..b7a8ae4ad --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_thread_manager_impl.os.windows.hpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 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::impl { + + class ThreadManagerWindowsImpl { + NON_COPYABLE(ThreadManagerWindowsImpl); + NON_MOVEABLE(ThreadManagerWindowsImpl); + private: + DWORD m_tls_index; + public: + explicit ThreadManagerWindowsImpl(ThreadType *main_thread); + + Result CreateThread(ThreadType *thread, s32 ideal_core); + void DestroyThreadUnsafe(ThreadType *thread); + void StartThread(const ThreadType *thread); + void WaitForThreadExit(ThreadType *thread); + bool TryWaitForThreadExit(ThreadType *thread); + void YieldThread(); + bool ChangePriority(ThreadType *thread, s32 priority); + s32 GetCurrentPriority(const ThreadType *thread) const; + ThreadId GetThreadId(const ThreadType *thread) const; + + void SuspendThreadUnsafe(ThreadType *thread); + void ResumeThreadUnsafe(ThreadType *thread); + + /* TODO: void GetThreadContextUnsafe(ThreadContextInfo *out_context, const ThreadType *thread); */ + + void NotifyThreadNameChangedImpl(const ThreadType *thread) const; + + void SetCurrentThread(ThreadType *thread) const; + + ThreadType *GetCurrentThread() const; + + s32 GetCurrentCoreNumber() const; + s32 GetDefaultCoreNumber() const { return 0; } + + void SetThreadCoreMask(ThreadType *thread, s32 ideal_core, u64 affinity_mask) const; + void GetThreadCoreMask(s32 *out_ideal_core, u64 *out_affinity_mask, const ThreadType *thread) const; + u64 GetThreadAvailableCoreMask() const; + + bool MapAliasStack(void **out, void *stack, size_t size) { + AMS_UNUSED(stack, size); + *out = nullptr; + return true; + } + + bool UnmapAliasStack(void *alias_stack, void *original_stack, size_t size) { + AMS_UNUSED(alias_stack, original_stack, size); + return true; + } + + NORETURN void ExitProcessImpl() { + AMS_ABORT("TODO: Just exit?"); + } + + NORETURN void QuickExit() { + AMS_ABORT("TODO: Just exit?"); + } + }; + + using ThreadManagerImpl = ThreadManagerWindowsImpl; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_thread_manager_impl.pthread.cpp b/libraries/libstratosphere/source/os/impl/os_thread_manager_impl.pthread.cpp new file mode 100644 index 000000000..827eab090 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_thread_manager_impl.pthread.cpp @@ -0,0 +1,20 @@ +/* + * Copyright (c) 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 + +#if defined(AMS_OS_IMPL_USE_PTHREADS) + #include "os_thread_manager_impl.pthread.inc" +#endif diff --git a/libraries/libstratosphere/source/os/impl/os_thread_manager_impl.pthread.hpp b/libraries/libstratosphere/source/os/impl/os_thread_manager_impl.pthread.hpp new file mode 100644 index 000000000..dfc867cb3 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_thread_manager_impl.pthread.hpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 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::impl { + + class ThreadManagerPthreadImpl { + NON_COPYABLE(ThreadManagerPthreadImpl); + NON_MOVEABLE(ThreadManagerPthreadImpl); + private: + pthread_key_t m_tls_key; + public: + explicit ThreadManagerPthreadImpl(ThreadType *main_thread); + + Result CreateThread(ThreadType *thread, s32 ideal_core); + void DestroyThreadUnsafe(ThreadType *thread); + void StartThread(const ThreadType *thread); + void WaitForThreadExit(ThreadType *thread); + bool TryWaitForThreadExit(ThreadType *thread); + void YieldThread(); + bool ChangePriority(ThreadType *thread, s32 priority); + s32 GetCurrentPriority(const ThreadType *thread) const; + ThreadId GetThreadId(const ThreadType *thread) const; + + void SuspendThreadUnsafe(ThreadType *thread); + void ResumeThreadUnsafe(ThreadType *thread); + + /* TODO: void GetThreadContextUnsafe(ThreadContextInfo *out_context, const ThreadType *thread); */ + + void NotifyThreadNameChangedImpl(const ThreadType *thread) const; + + void SetCurrentThread(ThreadType *thread) const; + + ThreadType *GetCurrentThread() const; + + s32 GetCurrentCoreNumber() const; + s32 GetDefaultCoreNumber() const { return 0; } + + void SetThreadCoreMask(ThreadType *thread, s32 ideal_core, u64 affinity_mask) const; + void GetThreadCoreMask(s32 *out_ideal_core, u64 *out_affinity_mask, const ThreadType *thread) const; + u64 GetThreadAvailableCoreMask() const; + + bool MapAliasStack(void **out, void *stack, size_t size) { + AMS_UNUSED(stack, size); + *out = nullptr; + return true; + } + + bool UnmapAliasStack(void *alias_stack, void *original_stack, size_t size) { + AMS_UNUSED(alias_stack, original_stack, size); + return true; + } + + NORETURN void ExitProcessImpl() { + AMS_ABORT("TODO: Just exit?"); + } + + NORETURN void QuickExit() { + AMS_ABORT("TODO: Just exit?"); + } + }; + + using ThreadManagerImpl = ThreadManagerPthreadImpl; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_thread_manager_impl.pthread.inc b/libraries/libstratosphere/source/os/impl/os_thread_manager_impl.pthread.inc new file mode 100644 index 000000000..7e8774365 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_thread_manager_impl.pthread.inc @@ -0,0 +1,367 @@ +/* + * Copyright (c) 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 "os_thread_manager_impl.pthread.hpp" +#include "os_thread_manager.hpp" + +#include + +#if defined(ATMOSPHERE_OS_LINUX) +#include +#elif defined(ATMOSPHERE_OS_MACOS) +#include +#include +#include + +namespace { + + struct cpu_set_t { + uint64_t affinity_mask; + }; + + ALWAYS_INLINE void CPU_ZERO(cpu_set_t *cs) { cs->affinity_mask = 0; } + ALWAYS_INLINE void CPU_SET(int core, cpu_set_t *cs) { cs->affinity_mask |= (UINT64_C(1) << core); } + ALWAYS_INLINE bool CPU_ISSET(int core, cpu_set_t *cs) { return cs->affinity_mask & (UINT64_C(1) << core); } + + constexpr size_t CPU_SETSIZE = BITSIZEOF(cpu_set_t{}.affinity_mask); + + int sched_getaffinity(pid_t pid, size_t cpu_size, cpu_set_t *cs) { + /* Ignore the process id/cpu size arguments. */ + static_cast(pid); + static_cast(cpu_size); + + /* Get the core count. */ + int32_t core_count = 0; + size_t size = sizeof(core_count); + if (const auto ret = ::sysctlbyname("machdep.cpu.core_count", std::addressof(core_count), std::addressof(size), 0, 0); ret != 0) { + return ret; + } + + /* Set our cpu set structure. */ + cs->affinity_mask = 0; + for (auto i = 0; i < core_count; ++i) { + cs->affinity_mask |= (UINT64_C(1) << i); + } + + return 0; + } + + int pthread_setaffinity_np(pthread_t thread, size_t cpu_size, cpu_set_t *cs) { + /* Ignore the cpu size argument. */ + static_cast(cpu_size); + + /* If the thread is allowed to be on more than one core, we'll ignore it. */ + /* TODO: Do this properly? */ + if (const auto pc = std::popcount(cs->affinity_mask); pc == 0 || pc > 1) { + return 0; + } + + /* Create policy to bind to the core. */ + thread_affinity_policy_data_t policy = { std::countr_zero(cs->affinity_mask) }; + + /* Get the underlying mach thread. */ + thread_port_t mach_thread = pthread_mach_thread_np(thread); + + /* Set the policy. */ + thread_policy_set(mach_thread, THREAD_AFFINITY_POLICY, reinterpret_cast(std::addressof(policy)), 1); + + return 0; + } + +} +#else +#error "Unknown OS for pthread CoreId get" +#endif + +namespace ams::os::impl { + + namespace { + + constexpr size_t DefaultStackSize = 1_MB; + + void *InvokeThread(void *arg) { + ThreadType *thread = static_cast(arg); + + /* Invoke the thread. */ + ThreadManager::InvokeThread(thread); + + /* Set exit state. */ + { + std::scoped_lock lk(util::GetReference(thread->cs_pthread_exit)); + AMS_ASSERT(thread->exited_pthread == false); + + thread->exited_pthread = true; + util::GetReference(thread->cv_pthread_exit).Broadcast(); + } + + return nullptr; + } + + os::ThreadType *DynamicAllocateAndRegisterThreadType() { + /* Get the thread manager. */ + auto &thread_manager = GetThreadManager(); + + /* Allocate a thread. */ + auto *thread = thread_manager.AllocateThreadType(); + AMS_ABORT_UNLESS(thread != nullptr); + + /* Setup the thread object. */ + SetupThreadObjectUnsafe(thread, nullptr, nullptr, nullptr, nullptr, 0, DefaultThreadPriority); + thread->state = ThreadType::State_Started; + thread->auto_registered = true; + + /* Set the thread's pthread handle. */ + thread->pthread = pthread_self(); + thread->ideal_core = thread_manager.GetCurrentCoreNumber(); + thread->affinity_mask = thread_manager.GetThreadAvailableCoreMask(); + + /* Place the object under the thread manager. */ + thread_manager.PlaceThreadObjectUnderThreadManagerSafe(thread); + + return thread; + } + + } + + ThreadManagerPthreadImpl::ThreadManagerPthreadImpl(ThreadType *main_thread) { + /* Create tls slot for thread pointer. */ + AMS_ABORT_UNLESS(pthread_key_create(std::addressof(m_tls_key), nullptr) == 0); + + /* Setup the main thread object. */ + SetupThreadObjectUnsafe(main_thread, nullptr, nullptr, nullptr, nullptr, DefaultStackSize, DefaultThreadPriority); + + /* Setup the main thread's pthread information. */ + main_thread->pthread = pthread_self(); + main_thread->ideal_core = this->GetCurrentCoreNumber(); + main_thread->affinity_mask = this->GetThreadAvailableCoreMask(); + } + + Result ThreadManagerPthreadImpl::CreateThread(ThreadType *thread, s32 ideal_core) { + /* Create the assert. */ + /* TODO: Check for failure properly. */ + pthread_t pthread; + const auto res = pthread_create(std::addressof(pthread), nullptr, &InvokeThread, thread); + AMS_ASSERT(res == 0); + + /* Set the thread's pthread handle information. */ + thread->pthread = pthread; + thread->ideal_core = ideal_core; + thread->affinity_mask = this->GetThreadAvailableCoreMask(); + + R_SUCCEED(); + } + + void ThreadManagerPthreadImpl::DestroyThreadUnsafe(ThreadType *thread) { + /* The thread must have exited. */ + { + std::scoped_lock lk(util::GetReference(thread->cs_pthread_exit)); + AMS_ABORT_UNLESS(thread->exited_pthread); + } + + /* Join the thread. */ + const auto ret = pthread_join(thread->pthread, nullptr); + AMS_ASSERT(ret == 0); + AMS_UNUSED(ret); + } + + void ThreadManagerPthreadImpl::StartThread(const ThreadType *thread) { + /* Nothing is actually needed here, because pthreads cannot start suspended. */ + /* TODO: Should we add a condvar/mutex for thread start? */ + AMS_UNUSED(thread); + } + + void ThreadManagerPthreadImpl::WaitForThreadExit(ThreadType *thread) { + /* Wait for the thread to exit. */ + { + std::scoped_lock lk(util::GetReference(thread->cs_pthread_exit)); + while (!thread->exited_pthread) { + util::GetReference(thread->cv_pthread_exit).Wait(util::GetPointer(thread->cs_pthread_exit)); + } + } + } + + bool ThreadManagerPthreadImpl::TryWaitForThreadExit(ThreadType *thread) { + /* Check if the thread has exited. */ + std::scoped_lock lk(util::GetReference(thread->cs_pthread_exit)); + + return thread->exited_pthread; + } + + void ThreadManagerPthreadImpl::YieldThread() { + #if defined(ATMOSPHERE_OS_MACOS) + sched_yield(); + #else + const auto ret = pthread_yield(); + AMS_ASSERT(ret == 0); + AMS_UNUSED(ret); + #endif + } + + bool ThreadManagerPthreadImpl::ChangePriority(ThreadType *thread, s32 priority) { + /* TODO: Should we set the thread's niceness value? */ + AMS_UNUSED(thread, priority); + return true; + } + + s32 ThreadManagerPthreadImpl::GetCurrentPriority(const ThreadType *thread) const { + return thread->base_priority; + } + + ThreadId ThreadManagerPthreadImpl::GetThreadId(const ThreadType *thread) const { + #if defined(AMS_OS_IMPL_USE_PTHREADID_NP_FOR_THREAD_ID) + ThreadId tid; + const auto ret = pthread_threadid_np(thread->pthread, std::addressof(tid)); + AMS_ABORT_UNLESS(ret == 0); + + return tid; + #else + return thread->pthread; + #endif + } + + void ThreadManagerPthreadImpl::SuspendThreadUnsafe(ThreadType *thread) { + AMS_UNUSED(thread); + AMS_ABORT("TODO: Linux SuspendThread Signal/Pause impl?"); + } + + void ThreadManagerPthreadImpl::ResumeThreadUnsafe(ThreadType *thread) { + AMS_UNUSED(thread); + AMS_ABORT("TODO: ResumeThread Signal/Pause impl?"); + } + + void ThreadManagerPthreadImpl::NotifyThreadNameChangedImpl(const ThreadType *thread) const { + /* TODO */ + AMS_UNUSED(thread); + } + + void ThreadManagerPthreadImpl::SetCurrentThread(ThreadType *thread) const { + const auto ret = pthread_setspecific(m_tls_key, thread); + AMS_ASSERT(ret == 0); + AMS_UNUSED(ret); + } + + ThreadType *ThreadManagerPthreadImpl::GetCurrentThread() const { + /* Get the thread from tls index. */ + ThreadType *thread = static_cast(pthread_getspecific(m_tls_key)); + + /* If the thread's TLS isn't set, we need to find it (and set tls) or make it. */ + if (thread == nullptr) { + /* Get the current thread id. */ + ThreadId self_tid; + pthread_t self_thread = pthread_self(); + #if defined(AMS_OS_IMPL_USE_PTHREADID_NP_FOR_THREAD_ID) + const auto ret = pthread_threadid_np(self_thread, std::addressof(self_tid)); + AMS_ABORT_UNLESS(ret == 0); + #else + self_tid = self_thread; + #endif + + /* Try to find the thread. */ + thread = GetThreadManager().FindThreadTypeById(self_tid); + if (thread == nullptr) { + /* Create the thread. */ + thread = DynamicAllocateAndRegisterThreadType(); + } + + /* Set the thread's TLS. */ + this->SetCurrentThread(thread); + } + + return thread; + } + + s32 ThreadManagerPthreadImpl::GetCurrentCoreNumber() const { + #if defined(ATMOSPHERE_OS_LINUX) + const auto core = sched_getcpu(); + AMS_ABORT_UNLESS(core >= 0); + return core; + #elif defined(ATMOSPHERE_OS_MACOS) + return 0; + #else + AMS_ABORT("TODO: Unknown OS GetCurrentCoreNumber() under pthreads"); + #endif + } + + void ThreadManagerPthreadImpl::SetThreadCoreMask(ThreadType *thread, s32 ideal_core, u64 affinity_mask) const { + /* If we should use the default, set the actual ideal core. */ + if (ideal_core == IdealCoreUseDefault) { + affinity_mask = this->GetThreadAvailableCoreMask(); + ideal_core = util::CountTrailingZeros(affinity_mask); + affinity_mask = static_cast(1) << ideal_core; + } + + /* Lock the thread. */ + std::scoped_lock lk(util::GetReference(thread->cs_thread)); + + /* Build the cpu affinity. */ + cpu_set_t cpuset; + CPU_ZERO(std::addressof(cpuset)); + for (size_t i = 0; i < std::min(BITSIZEOF(affinity_mask), CPU_SETSIZE); ++i) { + if ((static_cast(1) << i) & affinity_mask) { + CPU_SET(i, std::addressof(cpuset)); + } + } + + /* Set the cpu affinity. */ + const auto ret = pthread_setaffinity_np(thread->pthread, sizeof(cpuset), std::addressof(cpuset)); + AMS_ABORT_UNLESS(ret == 0); + + /* Set the ideal core. */ + if (ideal_core != IdealCoreNoUpdate) { + thread->ideal_core = ideal_core; + } + + /* Set the tracked affinity mask. */ + thread->affinity_mask = affinity_mask; + } + + void ThreadManagerPthreadImpl::GetThreadCoreMask(s32 *out_ideal_core, u64 *out_affinity_mask, const ThreadType *thread) const { + /* Lock the thread. */ + std::scoped_lock lk(util::GetReference(thread->cs_thread)); + + /* Set the output. */ + if (out_ideal_core != nullptr) { + *out_ideal_core = thread->ideal_core; + } + if (out_affinity_mask != nullptr) { + *out_affinity_mask = thread->affinity_mask; + } + } + + u64 ThreadManagerPthreadImpl::GetThreadAvailableCoreMask() const { + #if defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS) + cpu_set_t cpuset; + CPU_ZERO(std::addressof(cpuset)); + + const auto ret = sched_getaffinity(0, sizeof(cpuset), std::addressof(cpuset)); + AMS_ASSERT(ret == 0); + AMS_UNUSED(ret); + + u64 mask = 0; + for (size_t i = 0; i < std::min(BITSIZEOF(mask), CPU_SETSIZE); ++i) { + if (CPU_ISSET(i, std::addressof(cpuset))) { + mask |= static_cast(1) << i; + } + } + + AMS_ASSERT(mask != 0); + return mask; + #else + AMS_ABORT("TODO: Unknown OS GetThreadAvailableCoreMask() under pthreads"); + #endif + } + +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/os/impl/os_thread_manager_types.hpp b/libraries/libstratosphere/source/os/impl/os_thread_manager_types.hpp index 2e3a1e753..723066737 100644 --- a/libraries/libstratosphere/source/os/impl/os_thread_manager_types.hpp +++ b/libraries/libstratosphere/source/os/impl/os_thread_manager_types.hpp @@ -16,8 +16,12 @@ #pragma once #include -#ifdef ATMOSPHERE_OS_HORIZON +#if defined(AMS_OS_IMPL_USE_PTHREADS) + #include "os_thread_manager_impl.pthread.hpp" +#elif defined(ATMOSPHERE_OS_HORIZON) #include "os_thread_manager_impl.os.horizon.hpp" +#elif defined(ATMOSPHERE_OS_WINDOWS) + #include "os_thread_manager_impl.os.windows.hpp" #else #error "Unknown OS for ThreadManagerImpl" #endif @@ -65,12 +69,14 @@ namespace ams::os::impl { ThreadManager(); void CleanupThread(); + void CleanupThread(ThreadType *thread); s32 GetThreadCountForDebug() const { return m_num_created_threads; } Result CreateThread(ThreadType *thread, ThreadFunction function, void *argument, void *stack, size_t stack_size, s32 priority, s32 ideal_core); Result CreateThread(ThreadType *thread, ThreadFunction function, void *argument, void *stack, size_t stack_size, s32 priority); void DestroyThread(ThreadType *thread); + void DestroyThreadObject(ThreadType *thread); void StartThread(ThreadType *thread); void WaitThread(ThreadType *thread); bool TryWaitThread(ThreadType *thread); @@ -84,8 +90,8 @@ namespace ams::os::impl { s32 SuspendThread(ThreadType *thread); s32 ResumeThread(ThreadType *thread); - void CancelThreadSynchronization(ThreadType *thread); - + void ExitProcess() { return m_impl.ExitProcessImpl(); } + void QuickExit() { return m_impl.QuickExit(); } /* TODO void GetThreadContext(ThreadContextInfo *out_context, const ThreadType *thread); */ void SetInitialThreadNameUnsafe(ThreadType *thread); @@ -97,6 +103,8 @@ namespace ams::os::impl { void GetThreadCoreMask(s32 *out_ideal_core, u64 *out_affinity_mask, const ThreadType *thread) const { return m_impl.GetThreadCoreMask(out_ideal_core, out_affinity_mask, thread); } u64 GetThreadAvailableCoreMask() const { return m_impl.GetThreadAvailableCoreMask(); } + void SetZeroToAllThreadsTlsSafe(int slot); + void PushBackToAllThreadsListUnsafe(ThreadType *thread) { m_all_threads_list.push_back(*thread); ++m_num_created_threads; @@ -128,11 +136,11 @@ namespace ams::os::impl { } ThreadType *AllocateThreadType() const { - return reinterpret_cast(std::malloc(sizeof(ThreadType))); + return static_cast(ams::Malloc(sizeof(ThreadType))); } void FreeThreadType(ThreadType *thread) const { - std::free(thread); + ams::Free(thread); } const ThreadType *GetMainThread() const { @@ -146,6 +154,22 @@ namespace ams::os::impl { ThreadId GetThreadId(const ThreadType *thread) { return m_impl.GetThreadId(thread); } + + ThreadType *FindThreadTypeById(ThreadId id) { + std::scoped_lock lk(m_cs); + + for (auto rit = m_all_threads_list.rbegin(); rit != m_all_threads_list.rend(); ++rit) { + auto * const thread = std::addressof(*rit); + if (this->GetThreadId(thread) == id) { + return thread; + } + } + + return nullptr; + } + private: + bool CreateAliasStackUnsafe(ThreadType *thread); + void DeleteAliasStackUnsafe(ThreadType *thread); public: static void InvokeThread(ThreadType *thread); }; diff --git a/libraries/libstratosphere/source/os/impl/os_tick_manager_impl.hpp b/libraries/libstratosphere/source/os/impl/os_tick_manager_impl.hpp index a8a580709..558f5a4ec 100644 --- a/libraries/libstratosphere/source/os/impl/os_tick_manager_impl.hpp +++ b/libraries/libstratosphere/source/os/impl/os_tick_manager_impl.hpp @@ -16,8 +16,14 @@ #pragma once #include -#ifdef ATMOSPHERE_OS_HORIZON +#if defined(ATMOSPHERE_OS_HORIZON) #include "os_tick_manager_impl.os.horizon.hpp" +#elif defined(ATMOSPHERE_OS_WINDOWS) + #include "os_tick_manager_impl.os.windows.hpp" +#elif defined(ATMOSPHERE_OS_LINUX) + #include "os_tick_manager_impl.std_chrono.hpp" +#elif defined(ATMOSPHERE_OS_MACOS) + #include "os_tick_manager_impl.std_chrono.hpp" #else #error "Unknown OS for TickManagerImpl" #endif @@ -31,7 +37,11 @@ namespace ams::os::impl { private: TickManagerImpl m_impl; public: + #if defined(ATMOSPHERE_OS_HORIZON) constexpr TickManager() : m_impl() { /* ... */ } + #else + TickManager() : m_impl() { /* ... */ } + #endif ALWAYS_INLINE Tick GetTick() const { return m_impl.GetTick(); diff --git a/libraries/libstratosphere/source/os/impl/os_tick_manager_impl.os.windows.hpp b/libraries/libstratosphere/source/os/impl/os_tick_manager_impl.os.windows.hpp new file mode 100644 index 000000000..50dc0a599 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_tick_manager_impl.os.windows.hpp @@ -0,0 +1,85 @@ +/* + * Copyright (c) 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 + +namespace ams::os::impl { + + class TickManagerImpl { + private: + s64 m_tick_frequency; + TimeSpan m_max_time; + s64 m_max_tick; + public: + TickManagerImpl() { + /* Get the tick frequency. */ + ::timeBeginPeriod(1); + + LARGE_INTEGER freq; + ::QueryPerformanceFrequency(std::addressof(freq)); + m_tick_frequency = static_cast(freq.QuadPart); + + /* Set maximums. */ + constexpr s64 TickFrequencyForNanoSecondResolution = TimeSpan::FromSeconds(1).GetNanoSeconds(); + if (m_tick_frequency <= TickFrequencyForNanoSecondResolution) { + m_max_tick = m_tick_frequency * (std::numeric_limits::max() / TickFrequencyForNanoSecondResolution); + m_max_time = TimeSpan::FromNanoSeconds(std::numeric_limits::max()); + } else { + m_max_tick = std::numeric_limits::max(); + m_max_time = TimeSpan::FromSeconds(std::numeric_limits::max() / m_tick_frequency); + } + } + + ~TickManagerImpl() { + ::timeEndPeriod(1); + } + + ALWAYS_INLINE Tick GetTick() const { + LARGE_INTEGER freq; + ::QueryPerformanceFrequency(std::addressof(freq)); + return Tick(static_cast(freq.QuadPart)); + } + + ALWAYS_INLINE Tick GetSystemTickOrdered() const { + LARGE_INTEGER freq; + + PerformOrderingForGetSystemTickOrdered(); + ::QueryPerformanceFrequency(std::addressof(freq)); + PerformOrderingForGetSystemTickOrdered(); + + return Tick(static_cast(freq.QuadPart)); + } + + ALWAYS_INLINE s64 GetTickFrequency() const { + return m_tick_frequency; + } + + ALWAYS_INLINE s64 GetMaxTick() const { + return m_max_tick; + } + + ALWAYS_INLINE s64 GetMaxTimeSpanNs() const { + return m_max_time.GetNanoSeconds(); + } + private: + static ALWAYS_INLINE void PerformOrderingForGetSystemTickOrdered() { + int a = 0, b, c = 0, d; + __asm__ __volatile__("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(a), "2"(c) : "memory"); + } + }; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_tick_manager_impl.std_chrono.hpp b/libraries/libstratosphere/source/os/impl/os_tick_manager_impl.std_chrono.hpp new file mode 100644 index 000000000..950a5815f --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_tick_manager_impl.std_chrono.hpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 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 + +namespace ams::os::impl { + + class TickManagerImpl { + private: + using StandardClock = typename std::conditional::type; + using TimePoint = std::chrono::time_point; + private: + TimePoint m_start_time; + public: + TickManagerImpl() : m_start_time(StandardClock::now()) { /* ... */ } + + ALWAYS_INLINE Tick GetTick() const { + return Tick(static_cast((StandardClock::now() - m_start_time).count())); + } + + ALWAYS_INLINE Tick GetSystemTickOrdered() const { + PerformOrderingForGetSystemTickOrdered(true); + ON_SCOPE_EXIT { PerformOrderingForGetSystemTickOrdered(false); }; + + return Tick(static_cast((StandardClock::now() - m_start_time).count())); + } + + static constexpr ALWAYS_INLINE s64 GetTickFrequency() { + return static_cast(StandardClock::period::den) / static_cast(StandardClock::period::num); + } + + static constexpr ALWAYS_INLINE s64 GetMaxTick() { + static_assert(GetTickFrequency() <= TimeSpan::FromSeconds(1).GetNanoSeconds()); + return (std::numeric_limits::max() / TimeSpan::FromSeconds(1).GetNanoSeconds()) * GetTickFrequency(); + } + + static constexpr ALWAYS_INLINE s64 GetMaxTimeSpanNs() { + static_assert(GetTickFrequency() <= TimeSpan::FromSeconds(1).GetNanoSeconds()); + return TimeSpan::FromNanoSeconds(std::numeric_limits::max()).GetNanoSeconds(); + } + private: + static ALWAYS_INLINE void PerformOrderingForGetSystemTickOrdered(bool before) { + #if defined(ATMOSPHERE_ARCH_X64) || defined(ATMOSPHERE_ARCH_X86) + int a = 0, b, c = 0, d; + __asm__ __volatile__("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(a), "2"(c) : "memory"); + AMS_UNUSED(before); + #elif defined(ATMOSPHERE_ARCH_ARM64) + if (before) { + __asm__ __volatile__("dsb ish" ::: "memory"); + } + __asm__ __volatile__("isb" ::: "memory"); + #else + #error "Unknown architecture for std::chrono TickManager ordering." + #endif + } + }; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_timeout_helper.hpp b/libraries/libstratosphere/source/os/impl/os_timeout_helper.hpp index 72dfc507b..756134951 100644 --- a/libraries/libstratosphere/source/os/impl/os_timeout_helper.hpp +++ b/libraries/libstratosphere/source/os/impl/os_timeout_helper.hpp @@ -19,6 +19,12 @@ #if defined(ATMOSPHERE_OS_HORIZON) #include "os_timeout_helper_impl.os.horizon.hpp" +#elif defined(ATMOSPHERE_OS_WINDOWS) + #include "os_timeout_helper_impl.os.windows.hpp" +#elif defined(ATMOSPHERE_OS_LINUX) + #include "os_timeout_helper_impl.os.linux.hpp" +#elif defined(ATMOSPHERE_OS_MACOS) + #include "os_timeout_helper_impl.os.macos.hpp" #else #error "Unknown OS for ams::os::TimeoutHelper" #endif diff --git a/libraries/libstratosphere/source/os/impl/os_timeout_helper_impl.os.linux.cpp b/libraries/libstratosphere/source/os/impl/os_timeout_helper_impl.os.linux.cpp new file mode 100644 index 000000000..5f036bd3c --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_timeout_helper_impl.os.linux.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 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 "os_timeout_helper_impl.os.linux.hpp" + +#include + +namespace ams::os::impl { + + void TimeoutHelperImpl::Sleep(TimeSpan tm) { + /* If asked to sleep for no time, do nothing */ + if (tm == 0) { + return; + } + + constexpr s64 NanoSecondsPerSecond = TimeSpan::FromSeconds(1).GetNanoSeconds(); + const s64 ns = tm.GetNanoSeconds(); + struct timespec ts = { .tv_sec = (ns / NanoSecondsPerSecond), .tv_nsec = ns % NanoSecondsPerSecond }; + + while (true) { + const auto ret = ::nanosleep(std::addressof(ts), std::addressof(ts)); + if (ret == 0) { + break; + } + + AMS_ASSERT(errno == EINTR); + } + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_timeout_helper_impl.os.linux.hpp b/libraries/libstratosphere/source/os/impl/os_timeout_helper_impl.os.linux.hpp new file mode 100644 index 000000000..052369967 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_timeout_helper_impl.os.linux.hpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 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_tick_manager.hpp" + +namespace ams::os::impl { + + using TargetTimeSpan = ::ams::TimeSpan; + + class TimeoutHelperImpl { + public: + static TargetTimeSpan ConvertToImplTime(Tick tick) { + return impl::GetTickManager().ConvertToTimeSpan(tick); + } + + static void Sleep(TimeSpan tm); + }; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_timeout_helper_impl.os.macos.cpp b/libraries/libstratosphere/source/os/impl/os_timeout_helper_impl.os.macos.cpp new file mode 100644 index 000000000..c03b9391f --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_timeout_helper_impl.os.macos.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 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 "os_timeout_helper_impl.os.macos.hpp" + +#include + +namespace ams::os::impl { + + void TimeoutHelperImpl::Sleep(TimeSpan tm) { + /* If asked to sleep for no time, do nothing */ + if (tm == 0) { + return; + } + + constexpr s64 NanoSecondsPerSecond = TimeSpan::FromSeconds(1).GetNanoSeconds(); + const s64 ns = tm.GetNanoSeconds(); + struct timespec ts = { .tv_sec = (ns / NanoSecondsPerSecond), .tv_nsec = ns % NanoSecondsPerSecond }; + + while (true) { + const auto ret = ::nanosleep(std::addressof(ts), std::addressof(ts)); + if (ret == 0) { + break; + } + + AMS_ASSERT(errno == EINTR); + } + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_timeout_helper_impl.os.macos.hpp b/libraries/libstratosphere/source/os/impl/os_timeout_helper_impl.os.macos.hpp new file mode 100644 index 000000000..052369967 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_timeout_helper_impl.os.macos.hpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 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_tick_manager.hpp" + +namespace ams::os::impl { + + using TargetTimeSpan = ::ams::TimeSpan; + + class TimeoutHelperImpl { + public: + static TargetTimeSpan ConvertToImplTime(Tick tick) { + return impl::GetTickManager().ConvertToTimeSpan(tick); + } + + static void Sleep(TimeSpan tm); + }; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_timeout_helper_impl.os.windows.cpp b/libraries/libstratosphere/source/os/impl/os_timeout_helper_impl.os.windows.cpp new file mode 100644 index 000000000..5a666161a --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_timeout_helper_impl.os.windows.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 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 "os_timeout_helper_impl.os.windows.hpp" +#include "os_thread_manager.hpp" + +namespace ams::os::impl { + + void TimeoutHelperImpl::Sleep(TimeSpan tm) { + /* If asked to sleep for no time, do nothing */ + if (tm == 0) { + return; + } + + /* Get the end tick. */ + auto &tick_manager = GetTickManager(); + u64 tick_current = tick_manager.GetTick().GetInt64Value(); + u64 tick_timeout = tick_manager.ConvertToTick(tm).GetInt64Value(); + u64 tick_end = tick_current + tick_timeout + 1; + + const auto end = os::Tick(std::min(std::numeric_limits::max(), tick_end)); + while (true) { + const auto tick = tick_manager.GetTick(); + if (tick >= end) { + return; + } + + ::Sleep(ConvertToImplTime(end - tick)); + } + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_timeout_helper_impl.os.windows.hpp b/libraries/libstratosphere/source/os/impl/os_timeout_helper_impl.os.windows.hpp new file mode 100644 index 000000000..c6b7ce284 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_timeout_helper_impl.os.windows.hpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 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_tick_manager.hpp" + +namespace ams::os::impl { + + using TargetTimeSpan = DWORD; + + class TimeoutHelperImpl { + public: + static TargetTimeSpan ConvertToImplTime(Tick tick) { + constexpr s64 MaxTime = std::numeric_limits::max() - TimeSpan::FromMilliSeconds(1).GetNanoSeconds(); + constexpr auto Ratio = TimeSpan::FromMilliSeconds(1); + constexpr auto NanoS = TimeSpan::FromNanoSeconds(1); + + const auto time = TimeSpan::FromNanoSeconds(std::min(MaxTime, impl::GetTickManager().ConvertToTimeSpan(tick).GetNanoSeconds())); + + return static_cast((time + Ratio - NanoS).GetMilliSeconds()); + } + + static void Sleep(TimeSpan tm); + }; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_tls_manager.cpp b/libraries/libstratosphere/source/os/impl/os_tls_manager.cpp new file mode 100644 index 000000000..765c506b5 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_tls_manager.cpp @@ -0,0 +1,142 @@ +/* + * Copyright (c) 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 "os_tls_manager.hpp" +#include "os_thread_manager.hpp" + +namespace ams::os::impl { + + /* TODO: Should we migrate away from libnx to this on NX at some point? */ + #if !defined(ATMOSPHERE_OS_HORIZON) + namespace { + + constexpr auto TryCallDestructorCount = 4; + + void DefaultTlsDestructor(uintptr_t) { + /* ... */ + } + + } + + void TlsManager::InvokeTlsDestructors() { + /* Get the curent thread. */ + auto * const thread = impl::GetCurrentThread(); + + /* Call all destructors. */ + for (int slot = 0; slot < static_cast(TotalTlsSlotCountMax); ++slot) { + if (const auto destructor = m_destructors[slot]; destructor != nullptr) { + destructor(thread->tls_value_array[slot]); + } + + thread->tls_value_array[slot] = 0; + } + + /* Verify all tls values are wiped, trying up to four times. */ + for (auto i = 0; i < TryCallDestructorCount; ++i) { + bool all_cleared = true; + for (auto slot = 0; slot < static_cast(TotalTlsSlotCountMax); ++slot) { + if (thread->tls_value_array[slot] != 0) { + all_cleared = false; + + if (const auto destructor = m_destructors[slot]; destructor != nullptr) { + destructor(thread->tls_value_array[slot]); + } + + thread->tls_value_array[slot] = 0; + } + } + + if (all_cleared) { + break; + } + } + } + + bool TlsManager::AllocateTlsSlot(TlsSlot *out, TlsDestructor destructor, bool sdk) { + /* Decide on a slot. */ + int slot; + { + /* Lock appropriately. */ + std::scoped_lock lk(util::GetReference(impl::GetCurrentThread()->cs_thread)); + std::scoped_lock lk2(m_cs); + + /* If we're out of tls slots, fail. */ + if (!sdk && m_used >= static_cast(TlsSlotCountMax)) { + return false; + } + + /* Get a slot. */ + slot = SearchUnusedTlsSlotUnsafe(sdk); + + /* Set the destructor. */ + m_destructors[slot] = (destructor != nullptr) ? destructor : DefaultTlsDestructor; + + /* Increment our used count, if the slot was a user slot. */ + if (!sdk) { + ++m_used; + } + } + + /* Zero the slot in all threads. */ + GetThreadManager().SetZeroToAllThreadsTlsSafe(slot); + + /* Set the output slot's value. */ + out->_value = slot; + return true; + } + + void TlsManager::FreeTlsSlot(TlsSlot slot) { + /* Get the slot's index. */ + const auto slot_idx = slot._value; + + /* Lock appropriately. */ + std::scoped_lock lk(util::GetReference(impl::GetCurrentThread()->cs_thread)); + std::scoped_lock lk2(m_cs); + + /* Verify the slot is allocated. */ + AMS_ABORT_UNLESS(m_destructors[slot_idx] != nullptr); + + /* Free the slot. */ + m_destructors[slot_idx] = nullptr; + + /* Decrement our used count, if the slot was a user slot. */ + if (slot_idx < TlsSlotCountMax) { + --m_used; + } + } + + int TlsManager::SearchUnusedTlsSlotUnsafe(bool sdk) { + if (sdk) { + /* Search backwards for an unused slot. */ + for (int slot = static_cast(TotalTlsSlotCountMax) - 1; slot >= static_cast(TlsSlotCountMax + SdkInternalTlsCount); --slot) { + if (m_destructors[slot] == nullptr) { + return slot; + } + } + AMS_ABORT("Failed to allocate SdkTlsSlot"); + } else { + /* Search forwards for an unused slot. */ + for (int slot = 0; slot < static_cast(TlsSlotCountMax); ++slot) { + if (m_destructors[slot] == nullptr) { + return slot; + } + } + AMS_ABORT("Failed to allocate TlsSlot"); + } + } + #endif + +} diff --git a/libraries/libstratosphere/source/os/impl/os_tls_manager.hpp b/libraries/libstratosphere/source/os/impl/os_tls_manager.hpp new file mode 100644 index 000000000..a36ff0fa0 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_tls_manager.hpp @@ -0,0 +1,27 @@ +/* + * Copyright (c) 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_resource_manager.hpp" + +namespace ams::os::impl { + + ALWAYS_INLINE TlsManager &GetTlsManager() { + AMS_FUNCTION_LOCAL_STATIC_CONSTINIT(TlsManager, s_tls_manager); + return s_tls_manager; + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_tls_manager_types.hpp b/libraries/libstratosphere/source/os/impl/os_tls_manager_types.hpp new file mode 100644 index 000000000..d59f92de1 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_tls_manager_types.hpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 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::impl { + + static constexpr size_t TotalTlsSlotCountMax = TlsSlotCountMax + SdkTlsSlotCountMax; + + class TlsManager { + NON_COPYABLE(TlsManager); + NON_MOVEABLE(TlsManager); + private: + TlsDestructor m_destructors[TotalTlsSlotCountMax]; + InternalCriticalSection m_cs; + int m_used; + public: + consteval TlsManager() : m_destructors(), m_cs(), m_used() { /* ... */ } + + void InvokeTlsDestructors(); + bool AllocateTlsSlot(TlsSlot *out, TlsDestructor destructor, bool sdk); + void FreeTlsSlot(TlsSlot slot); + + int GetUsedTlsSlots() const { return m_used; } + + static consteval int GetMaxTlsSlots() { return TotalTlsSlotCountMax; } + private: + int SearchUnusedTlsSlotUnsafe(bool sdk); + }; + +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/os/impl/os_vamm_manager.cpp b/libraries/libstratosphere/source/os/impl/os_vamm_manager.cpp new file mode 100644 index 000000000..3414b2a77 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_vamm_manager.cpp @@ -0,0 +1,397 @@ +/* + * Copyright (c) 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 "os_vamm_manager.hpp" + +#if defined(ATMOSPHERE_OS_HORIZON) + #include "os_vamm_manager_impl.os.horizon.hpp" +#elif defined(ATMOSPHERE_OS_WINDOWS) + #include "os_vamm_manager_impl.os.windows.hpp" +#elif defined(ATMOSPHERE_OS_LINUX) + #include "os_vamm_manager_impl.os.linux.hpp" +#elif defined(ATMOSPHERE_OS_MACOS) + #include "os_vamm_manager_impl.os.macos.hpp" +#else + #error "Unknown OS for VammManagerImpl" +#endif + + +namespace ams::os::impl { + + namespace { + + enum AddressAllocationResult { + AddressAllocationResult_Success, + AddressAllocationResult_OutOfMemory, + AddressAllocationResult_OutOfSpace, + }; + + class AddressRegion : public util::IntrusiveRedBlackTreeBaseNode { + private: + uintptr_t m_address; + size_t m_size; + public: + ALWAYS_INLINE AddressRegion(uintptr_t a, size_t s) : m_address(a), m_size(s) { /* ... */ } + + constexpr ALWAYS_INLINE uintptr_t GetAddressBegin() const { return m_address; } + constexpr ALWAYS_INLINE uintptr_t GetAddressEnd() const { return m_address + m_size; } + constexpr ALWAYS_INLINE size_t GetSize() const { return m_size; } + + constexpr ALWAYS_INLINE bool IsContained(uintptr_t address) const { + if (address < m_address) { + return false; + } else if (address < this->GetAddressEnd()) { + return true; + } else { + return false; + } + } + + constexpr ALWAYS_INLINE bool IsContained(uintptr_t address, size_t size) const { + const uintptr_t end = address + size; + + if (!(address <= end)) { + return false; + } + if (!(this->GetAddressBegin() <= address)) { + return false; + } + if (!(end <= this->GetAddressEnd())) { + return false; + } + + return true; + } + }; + + struct AddressRegionCompare { + using RedBlackKeyType = uintptr_t; + + static constexpr ALWAYS_INLINE int Compare(const RedBlackKeyType a, const RedBlackKeyType &b) { + if (a < b) { + return -1; + } else if (a > b) { + return 1; + } else { + return 0; + } + } + + static constexpr ALWAYS_INLINE int Compare(const RedBlackKeyType &a, const AddressRegion &b) { + return Compare(a, b.GetAddressBegin()); + } + + static constexpr ALWAYS_INLINE int Compare(const AddressRegion &a, const AddressRegion &b) { + return Compare(a.GetAddressBegin(), b.GetAddressBegin()); + } + }; + + using AddressRegionTree = util::IntrusiveRedBlackTreeBaseTraits::TreeType; + + class DynamicUnitHeap { + private: + static constexpr size_t PhysicalMemoryUnitSize = MemoryPageSize; + private: + uintptr_t m_start; + uintptr_t m_limit; + uintptr_t m_end; + util::TypedStorage m_head; + lmem::HeapHandle m_heap; + public: + DynamicUnitHeap(uintptr_t address, size_t size, size_t unit_size) : m_start(address), m_end(address + size) { + /* Allocate the start of our buffer. */ + VammManagerImpl::AllocatePhysicalMemoryImpl(m_start, PhysicalMemoryUnitSize); + + /* Set our current limit. */ + m_limit = m_start + PhysicalMemoryUnitSize; + + /* Initialize our heap. */ + m_heap = lmem::CreateUnitHeap(reinterpret_cast(m_start), PhysicalMemoryUnitSize, unit_size, lmem::CreateOption_None, alignof(u64), util::GetPointer(m_head)); + } + + void *Allocate() { + void *alloc = lmem::AllocateFromUnitHeap(m_heap); + if (alloc == nullptr) { + this->Extend(); + alloc = lmem::AllocateFromUnitHeap(m_heap); + } + return alloc; + } + + void Free(void *p) { + lmem::FreeToUnitHeap(m_heap, p); + } + private: + void Extend() { + AMS_ABORT_UNLESS(m_limit < m_end); + + if (R_SUCCEEDED(VammManagerImpl::AllocatePhysicalMemoryImpl(m_limit, PhysicalMemoryUnitSize))) { + m_limit += PhysicalMemoryUnitSize; + lmem::ExtendUnitHeap(m_heap, PhysicalMemoryUnitSize); + } + } + }; + + } + + class AddressRegionManager { + private: + static constexpr size_t UnitHeapRegionSize = 1_GB - 2_MB; + private: + uintptr_t m_start; + size_t m_size; + AddressRegionTree m_tree; + DynamicUnitHeap m_heap; + public: + AddressRegionManager(uintptr_t start, size_t size) : m_start(start), m_size(size), m_heap(start, UnitHeapRegionSize, sizeof(AddressRegion)) { + /* Insert a block in the tree for our heap. */ + m_tree.insert(*(new (m_heap.Allocate()) AddressRegion(m_start, UnitHeapRegionSize))); + + /* Insert a zero-size block in the tree at the end of our heap. */ + m_tree.insert(*(new (m_heap.Allocate()) AddressRegion(m_start + size, 0))); + } + + AddressAllocationResult Allocate(AddressRegion **out, size_t size) { + /* Allocate a region. */ + void *p = m_heap.Allocate(); + if (p == nullptr) { + return AddressAllocationResult_OutOfMemory; + } + + /* Determine alignment for the specified size. */ + const size_t align = SelectAlignment(size); + + /* Iterate, looking for an appropriate region. */ + auto *region = std::addressof(m_tree.back()); + while (true) { + /* Get the previous region. */ + auto *prev = region->GetPrev(); + if (prev == nullptr) { + break; + } + + /* Get the space between prev and the current region. */ + const uintptr_t space_start = prev->GetAddressEnd() + MemoryPageSize; + const uintptr_t space_end = region->GetAddressBegin() - MemoryPageSize; + const size_t space_size = space_end - space_start; + + /* If there's enough space in the region, consider it further. */ + if (space_size >= size) { + /* Determine the allocation region extents. */ + const uintptr_t alloc_start = util::AlignUp(space_start, align); + const uintptr_t alloc_end = alloc_start + size; + + /* If the allocation works, use it. */ + if (alloc_end <= space_end) { + auto *address_region = new (p) AddressRegion(alloc_start, size); + m_tree.insert(*address_region); + *out = address_region; + return AddressAllocationResult_Success; + } + } + + /* Otherwise, continue. */ + region = prev; + } + + /* We ran out of space to allocate. */ + return AddressAllocationResult_OutOfSpace; + } + + void Free(AddressRegion *region) { + m_tree.erase(m_tree.iterator_to(*region)); + m_heap.Free(region); + } + + bool IsAlreadyAllocated(uintptr_t address, size_t size) const { + /* Find the first region >= our address. */ + auto region = std::addressof(*(m_tree.nfind_key(address))); + if (region == nullptr) { + return false; + } + + /* If the address matches, return whether the region is contained. */ + if (region->GetAddressBegin() == address) { + return size <= region->GetSize(); + } + + /* Otherwise, check the previous entry. */ + if (region = region->GetPrev(); region == nullptr) { + return false; + } + + return region->IsContained(address, size); + } + + AddressRegion *Find(uintptr_t address) const { + return std::addressof(*(m_tree.find_key(address))); + } + private: + static constexpr size_t SelectAlignment(size_t size) { + if (size < 4_MB) { + if (size < 2_MB) { + return 64_KB; + } else { + return 2_MB; + } + } else { + if (size < 32_MB) { + return 4_MB; + } else if (size < 1_GB) { + return 32_MB; + } else { + return 1_GB; + } + } + } + }; + + namespace { + + constinit util::TypedStorage g_address_region_manager_storage = {}; + + } + + VammManager::VammManager() : m_lock(), m_region_manager(nullptr) { + /* Get the reserved region. */ + VammManagerImpl::GetReservedRegionImpl(std::addressof(m_reserved_region_start), std::addressof(m_reserved_region_size)); + } + + void VammManager::InitializeIfEnabled() { + /* Acquire exclusive/writer access. */ + std::scoped_lock lk(m_lock); + + /* Initialize, if we haven't already. */ + if (m_region_manager == nullptr && IsVirtualAddressMemoryEnabled()) { + m_region_manager = util::ConstructAt(g_address_region_manager_storage, m_reserved_region_start, m_reserved_region_size); + } + } + + Result VammManager::AllocateAddressRegion(uintptr_t *out, size_t size) { + /* Allocate an address. */ + uintptr_t address; + { + /* Lock access to our region manager. */ + std::scoped_lock lk(m_lock); + AMS_ASSERT(m_region_manager != nullptr); + + /* Allocate an address region. */ + AddressRegion *region; + switch (m_region_manager->Allocate(std::addressof(region), size)) { + case AddressAllocationResult_Success: + address = region->GetAddressBegin(); + break; + case AddressAllocationResult_OutOfSpace: + R_THROW(os::ResultOutOfVirtualAddressSpace()); + default: + R_THROW(os::ResultOutOfMemory()); + } + } + + /* Set the output. */ + *out = address; + R_SUCCEED(); + } + + Result VammManager::AllocateMemory(uintptr_t *out, size_t size) { + /* Allocate an address. */ + uintptr_t address; + { + /* Lock access to our region manager. */ + std::scoped_lock lk(m_lock); + AMS_ASSERT(m_region_manager != nullptr); + + /* Allocate an address region. */ + AddressRegion *region; + switch (m_region_manager->Allocate(std::addressof(region), size)) { + case AddressAllocationResult_Success: + address = region->GetAddressBegin(); + break; + case AddressAllocationResult_OutOfSpace: + R_THROW(os::ResultOutOfVirtualAddressSpace()); + default: + R_THROW(os::ResultOutOfMemory()); + } + ON_RESULT_FAILURE { m_region_manager->Free(region); }; + + /* Allocate memory at the region. */ + R_TRY(VammManagerImpl::AllocatePhysicalMemoryImpl(address, size)); + } + + /* Set the output. */ + *out = address; + R_SUCCEED(); + } + + Result VammManager::AllocateMemoryPages(uintptr_t address, size_t size) { + /* Acquire read access to our region manager. */ + std::shared_lock lk(m_lock); + AMS_ASSERT(m_region_manager != nullptr); + + /* Check that the region was previously allocated by a call to AllocateAddressRegion. */ + R_UNLESS(m_region_manager->IsAlreadyAllocated(address, size), os::ResultInvalidParameter()); + + /* Allocate the memory. */ + R_RETURN(VammManagerImpl::AllocatePhysicalMemoryImpl(address, size)); + } + + Result VammManager::FreeAddressRegion(uintptr_t address) { + /* Lock access to our region manager. */ + std::scoped_lock lk(m_lock); + AMS_ASSERT(m_region_manager != nullptr); + + /* Verify the region can be freed. */ + auto *region = m_region_manager->Find(address); + R_UNLESS(region != nullptr, os::ResultInvalidParameter()); + + /* Free any memory present at the address. */ + R_TRY(VammManagerImpl::FreePhysicalMemoryImpl(address, region->GetSize())); + + /* Free the region. */ + m_region_manager->Free(region); + R_SUCCEED(); + } + + Result VammManager::FreeMemoryPages(uintptr_t address, size_t size) { + /* Acquire read access to our region manager. */ + std::shared_lock lk(m_lock); + AMS_ASSERT(m_region_manager != nullptr); + + /* Check that the region was previously allocated by a call to AllocateAddressRegion. */ + R_UNLESS(m_region_manager->IsAlreadyAllocated(address, size), os::ResultInvalidParameter()); + + /* Free the memory. */ + R_RETURN(VammManagerImpl::FreePhysicalMemoryImpl(address, size)); + } + + VirtualAddressMemoryResourceUsage VammManager::GetVirtualAddressMemoryResourceUsage() { + const size_t assigned_size = VammManagerImpl::GetExtraSystemResourceAssignedSize(); + const size_t used_size = VammManagerImpl::GetExtraSystemResourceUsedSize(); + + /* Decide on an actual used size. */ + const size_t reported_used_size = std::min(assigned_size, used_size + 512_KB); + + return VirtualAddressMemoryResourceUsage { + .assigned_size = assigned_size, + .used_size = reported_used_size, + }; + } + + bool VammManager::IsVirtualAddressMemoryEnabled() { + return VammManagerImpl::IsVirtualAddressMemoryEnabled(); + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_vamm_manager.hpp b/libraries/libstratosphere/source/os/impl/os_vamm_manager.hpp new file mode 100644 index 000000000..03e2fbb65 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_vamm_manager.hpp @@ -0,0 +1,26 @@ +/* + * Copyright (c) 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_resource_manager.hpp" + +namespace ams::os::impl { + + ALWAYS_INLINE VammManager &GetVammManager() { + return GetResourceManager().GetVammManager(); + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_vamm_manager_impl.os.horizon.hpp b/libraries/libstratosphere/source/os/impl/os_vamm_manager_impl.os.horizon.hpp new file mode 100644 index 000000000..dad8aee6f --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_vamm_manager_impl.os.horizon.hpp @@ -0,0 +1,67 @@ +/* + * Copyright (c) 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::impl { + + class VammManagerHorizonImpl { + public: + static void GetReservedRegionImpl(uintptr_t *out_start, uintptr_t *out_size) { + u64 start, size; + R_ABORT_UNLESS(svc::GetInfo(std::addressof(start), svc::InfoType_AliasRegionAddress, svc::PseudoHandle::CurrentProcess, 0)); + R_ABORT_UNLESS(svc::GetInfo(std::addressof(size), svc::InfoType_AliasRegionSize, svc::PseudoHandle::CurrentProcess, 0)); + *out_start = start; + *out_size = size; + } + + static Result AllocatePhysicalMemoryImpl(uintptr_t address, size_t size) { + R_TRY_CATCH(svc::MapPhysicalMemory(address, size)) { + R_CONVERT(svc::ResultOutOfResource, os::ResultOutOfResource()) + R_CONVERT(svc::ResultOutOfMemory, os::ResultOutOfMemory()) + R_CONVERT(svc::ResultLimitReached, os::ResultOutOfMemory()) + } R_END_TRY_CATCH_WITH_ABORT_UNLESS; + R_SUCCEED(); + } + + static Result FreePhysicalMemoryImpl(uintptr_t address, size_t size) { + R_TRY_CATCH(svc::UnmapPhysicalMemory(address, size)) { + R_CONVERT(svc::ResultInvalidCurrentMemory, os::ResultBusy()) + R_CONVERT(svc::ResultOutOfResource, os::ResultOutOfResource()) + R_CONVERT(svc::ResultOutOfMemory, os::ResultOutOfMemory()) + R_CONVERT(svc::ResultLimitReached, os::ResultOutOfMemory()) + } R_END_TRY_CATCH_WITH_ABORT_UNLESS; + R_SUCCEED(); + } + + static size_t GetExtraSystemResourceAssignedSize() { + u64 v; + return R_SUCCEEDED(svc::GetInfo(std::addressof(v), svc::InfoType_SystemResourceSizeTotal, svc::PseudoHandle::CurrentProcess, 0)) ? v : 0; + } + + static size_t GetExtraSystemResourceUsedSize() { + u64 v; + return R_SUCCEEDED(svc::GetInfo(std::addressof(v), svc::InfoType_SystemResourceSizeUsed, svc::PseudoHandle::CurrentProcess, 0)) ? v : 0; + } + + static bool IsVirtualAddressMemoryEnabled() { + return GetExtraSystemResourceAssignedSize() > 0; + } + }; + + using VammManagerImpl = VammManagerHorizonImpl; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_vamm_manager_impl.os.linux.hpp b/libraries/libstratosphere/source/os/impl/os_vamm_manager_impl.os.linux.hpp new file mode 100644 index 000000000..9f6ad083b --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_vamm_manager_impl.os.linux.hpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 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 + +namespace ams::os::impl { + + class VammManagerLinuxImpl { + public: + static void GetReservedRegionImpl(uintptr_t *out_start, uintptr_t *out_size) { + /* Reserve a 64 GB region of virtual address space. */ + constexpr size_t ReservedRegionSize = 64_GB; + const auto reserved = ::mmap(nullptr, ReservedRegionSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + AMS_ABORT_UNLESS(reserved != MAP_FAILED); + + *out_start = reinterpret_cast(reserved); + *out_size = ReservedRegionSize; + } + + static Result AllocatePhysicalMemoryImpl(uintptr_t address, size_t size) { + R_UNLESS(::mprotect(reinterpret_cast(address), size, PROT_READ | PROT_WRITE) == 0, os::ResultOutOfMemory()); + R_SUCCEED(); + } + + static Result FreePhysicalMemoryImpl(uintptr_t address, size_t size) { + R_UNLESS(::mprotect(reinterpret_cast(address), size, PROT_NONE) == 0, os::ResultBusy()); + R_SUCCEED(); + } + + static consteval size_t GetExtraSystemResourceAssignedSize() { + return 0; + } + + static consteval size_t GetExtraSystemResourceUsedSize() { + return 0; + } + + static consteval bool IsVirtualAddressMemoryEnabled() { + return true; + } + }; + + using VammManagerImpl = VammManagerLinuxImpl; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_vamm_manager_impl.os.macos.hpp b/libraries/libstratosphere/source/os/impl/os_vamm_manager_impl.os.macos.hpp new file mode 100644 index 000000000..16eb23bf0 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_vamm_manager_impl.os.macos.hpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 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 + +namespace ams::os::impl { + + class VammManagerMacosImpl { + public: + static void GetReservedRegionImpl(uintptr_t *out_start, uintptr_t *out_size) { + /* Reserve a 64 GB region of virtual address space. */ + constexpr size_t ReservedRegionSize = 64_GB; + const auto reserved = ::mmap(nullptr, ReservedRegionSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + AMS_ABORT_UNLESS(reserved != MAP_FAILED); + + *out_start = reinterpret_cast(reserved); + *out_size = ReservedRegionSize; + } + + static Result AllocatePhysicalMemoryImpl(uintptr_t address, size_t size) { + R_UNLESS(::mprotect(reinterpret_cast(address), size, PROT_READ | PROT_WRITE) == 0, os::ResultOutOfMemory()); + R_SUCCEED(); + } + + static Result FreePhysicalMemoryImpl(uintptr_t address, size_t size) { + R_UNLESS(::mprotect(reinterpret_cast(address), size, PROT_NONE) == 0, os::ResultBusy()); + R_SUCCEED(); + } + + static consteval size_t GetExtraSystemResourceAssignedSize() { + return 0; + } + + static consteval size_t GetExtraSystemResourceUsedSize() { + return 0; + } + + static consteval bool IsVirtualAddressMemoryEnabled() { + return true; + } + }; + + using VammManagerImpl = VammManagerMacosImpl; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_vamm_manager_impl.os.windows.hpp b/libraries/libstratosphere/source/os/impl/os_vamm_manager_impl.os.windows.hpp new file mode 100644 index 000000000..edee21b9f --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_vamm_manager_impl.os.windows.hpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) 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::impl { + + class VammManagerWindowsImpl { + public: + static void GetReservedRegionImpl(uintptr_t *out_start, uintptr_t *out_size) { + /* Reserve a 64 GB region of virtual address space. */ + constexpr size_t ReservedRegionSize = 64_GB; + const auto reserved = ::VirtualAlloc(nullptr, ReservedRegionSize, MEM_RESERVE, PAGE_READWRITE); + AMS_ABORT_UNLESS(reserved != nullptr); + + *out_start = reinterpret_cast(reserved); + *out_size = ReservedRegionSize; + } + + static Result AllocatePhysicalMemoryImpl(uintptr_t address, size_t size) { + R_UNLESS(::VirtualAlloc(reinterpret_cast(address), size, MEM_COMMIT, PAGE_READWRITE) != nullptr, os::ResultOutOfMemory()); + R_SUCCEED(); + } + + static Result FreePhysicalMemoryImpl(uintptr_t address, size_t size) { + R_UNLESS(::VirtualFree(reinterpret_cast(address), size, MEM_DECOMMIT), os::ResultBusy()); + R_SUCCEED(); + } + + static consteval size_t GetExtraSystemResourceAssignedSize() { + return 0; + } + + static consteval size_t GetExtraSystemResourceUsedSize() { + return 0; + } + + static consteval bool IsVirtualAddressMemoryEnabled() { + return true; + } + }; + + using VammManagerImpl = VammManagerWindowsImpl; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_vamm_manager_types.hpp b/libraries/libstratosphere/source/os/impl/os_vamm_manager_types.hpp new file mode 100644 index 000000000..d6b0c1d91 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_vamm_manager_types.hpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 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::impl { + + class AddressRegionManager; + + class VammManager { + NON_COPYABLE(VammManager); + NON_MOVEABLE(VammManager); + private: + uintptr_t m_reserved_region_start; + uintptr_t m_reserved_region_size; + ReaderWriterLock m_lock; + AddressRegionManager *m_region_manager; + public: + VammManager(); + + void InitializeIfEnabled(); + + Result AllocateAddressRegion(uintptr_t *out, size_t size); + Result AllocateMemory(uintptr_t *out, size_t size); + Result AllocateMemoryPages(uintptr_t address, size_t size); + + Result FreeAddressRegion(uintptr_t address); + Result FreeMemoryPages(uintptr_t address, size_t size); + + VirtualAddressMemoryResourceUsage GetVirtualAddressMemoryResourceUsage(); + public: + static bool IsVirtualAddressMemoryEnabled(); + }; + +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/os/os_barrier.cpp b/libraries/libstratosphere/source/os/os_barrier.cpp index c74534b24..0e4a04c65 100644 --- a/libraries/libstratosphere/source/os/os_barrier.cpp +++ b/libraries/libstratosphere/source/os/os_barrier.cpp @@ -25,7 +25,9 @@ namespace ams::os { ALWAYS_INLINE u64 GetBarrierBaseCounterImpl(const BarrierType *barrier) { /* Check pre-conditions. */ + #if defined(AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD) AMS_ASSERT(util::GetReference(barrier->cs_barrier).IsLockedByCurrentThread()); + #endif /* Convert two u32s to u64. */ return (static_cast(barrier->base_counter_lower) << 0) | (static_cast(barrier->base_counter_upper) << BITSIZEOF(barrier->base_counter_lower)); @@ -33,7 +35,9 @@ namespace ams::os { ALWAYS_INLINE void SetBarrierBaseCounterImpl(BarrierType *barrier, u64 value) { /* Check pre-conditions. */ + #if defined(AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD) AMS_ASSERT(util::GetReference(barrier->cs_barrier).IsLockedByCurrentThread()); + #endif /* Store as two u32s. */ barrier->base_counter_lower = static_cast(value >> 0); diff --git a/libraries/libstratosphere/source/os/os_busy_mutex.cpp b/libraries/libstratosphere/source/os/os_busy_mutex.cpp index 70c30e71a..cbd6807ce 100644 --- a/libraries/libstratosphere/source/os/os_busy_mutex.cpp +++ b/libraries/libstratosphere/source/os/os_busy_mutex.cpp @@ -19,7 +19,7 @@ #if defined(ATMOSPHERE_OS_HORIZON) #include "impl/os_internal_busy_mutex_impl.os.horizon.hpp" #else - #error "Unknown OS for ams::os::impl::InternalBusyMutexImpl" + /* Generic implementation already included in */ #endif namespace ams::os { diff --git a/libraries/libstratosphere/source/os/os_io_region.cpp b/libraries/libstratosphere/source/os/os_io_region.cpp index 2bb603d50..e720ae145 100644 --- a/libraries/libstratosphere/source/os/os_io_region.cpp +++ b/libraries/libstratosphere/source/os/os_io_region.cpp @@ -39,7 +39,7 @@ namespace ams::os { Result CreateIoRegion(IoRegionType *io_region, NativeHandle io_pool_handle, uintptr_t address, size_t size, MemoryMapping mapping, MemoryPermission permission) { /* Check pre-conditions. */ AMS_ASSERT(io_region != nullptr); - AMS_ASSERT(io_pool_handle != svc::InvalidHandle); + AMS_ASSERT(io_pool_handle != os::InvalidNativeHandle); AMS_ASSERT(util::IsAligned(address, os::MemoryPageSize)); AMS_ASSERT(util::IsAligned(size, os::MemoryPageSize)); AMS_ASSERT(mapping == MemoryMapping_IoRegister || mapping == MemoryMapping_Uncached || mapping == MemoryMapping_Memory); @@ -63,7 +63,7 @@ namespace ams::os { /* Check pre-conditions. */ AMS_ASSERT(io_region != nullptr); AMS_ASSERT(util::IsAligned(size, os::MemoryPageSize)); - AMS_ASSERT(handle != svc::InvalidHandle); + AMS_ASSERT(handle != os::InvalidNativeHandle); /* Setup the object. */ InitializeIoRegion(io_region, handle, size, managed); @@ -85,7 +85,7 @@ namespace ams::os { } /* Clear members. */ - io_region->handle = svc::InvalidHandle; + io_region->handle = os::InvalidNativeHandle; io_region->handle_managed = false; io_region->mapped_address = nullptr; io_region->size = 0; diff --git a/libraries/libstratosphere/source/os/os_light_event.cpp b/libraries/libstratosphere/source/os/os_light_event.cpp index 22478cd7d..40496a395 100644 --- a/libraries/libstratosphere/source/os/os_light_event.cpp +++ b/libraries/libstratosphere/source/os/os_light_event.cpp @@ -19,7 +19,7 @@ #if defined(ATMOSPHERE_OS_HORIZON) #include "impl/os_internal_light_event_impl.os.horizon.hpp" #else - #error "Unknown OS for ams::os::impl::InternalLightEventImpl" + #include "impl/os_internal_light_event_impl.os.generic.hpp" #endif namespace ams::os { diff --git a/libraries/libstratosphere/source/os/os_message_queue.cpp b/libraries/libstratosphere/source/os/os_message_queue.cpp index 2917763cd..71206809d 100644 --- a/libraries/libstratosphere/source/os/os_message_queue.cpp +++ b/libraries/libstratosphere/source/os/os_message_queue.cpp @@ -51,7 +51,7 @@ namespace ams::os { } void FinalizeMessageQueue(MessageQueueType *mq) { - AMS_ASSERT(mq->state = MessageQueueType::State_Initialized); + AMS_ASSERT(mq->state == MessageQueueType::State_Initialized); AMS_ASSERT(GetReference(mq->waitlist_not_empty).IsEmpty()); AMS_ASSERT(GetReference(mq->waitlist_not_full).IsEmpty()); diff --git a/libraries/libstratosphere/source/os/os_multiple_wait.cpp b/libraries/libstratosphere/source/os/os_multiple_wait.cpp index 47d2b3308..97db6db2b 100644 --- a/libraries/libstratosphere/source/os/os_multiple_wait.cpp +++ b/libraries/libstratosphere/source/os/os_multiple_wait.cpp @@ -91,7 +91,10 @@ namespace ams::os { AMS_ASSERT(!holder_base->IsLinked()); - std::destroy_at(holder_base); + /* Destroy. */ + static_assert(std::is_trivially_destructible::value); + /* std::destroy_at(holder_base); */ + AMS_UNUSED(holder_base); } void LinkMultiWaitHolder(MultiWaitType *multi_wait, MultiWaitHolderType *holder) { diff --git a/libraries/libstratosphere/source/os/os_rw_busy_mutex.cpp b/libraries/libstratosphere/source/os/os_rw_busy_mutex.cpp index 21d68928a..76839e640 100644 --- a/libraries/libstratosphere/source/os/os_rw_busy_mutex.cpp +++ b/libraries/libstratosphere/source/os/os_rw_busy_mutex.cpp @@ -18,6 +18,12 @@ #if defined(ATMOSPHERE_OS_HORIZON) #include "impl/os_internal_rw_busy_mutex_impl.os.horizon.hpp" +#elif defined(ATMOSPHERE_OS_WINDOWS) + #include "impl/os_internal_rw_busy_mutex_impl.os.windows.hpp" +#elif defined(ATMOSPHERE_OS_LINUX) + #include "impl/os_internal_rw_busy_mutex_impl.os.linux.hpp" +#elif defined(ATMOSPHERE_OS_MACOS) + #include "impl/os_internal_rw_busy_mutex_impl.os.macos.hpp" #else #error "Unknown OS for ams::os::impl::InternalReaderWriterBusyMutexImpl" #endif diff --git a/libraries/libstratosphere/source/os/os_sdk_mutex.cpp b/libraries/libstratosphere/source/os/os_sdk_mutex.cpp index 7f03df21f..31c888024 100644 --- a/libraries/libstratosphere/source/os/os_sdk_mutex.cpp +++ b/libraries/libstratosphere/source/os/os_sdk_mutex.cpp @@ -14,17 +14,30 @@ * along with this program. If not, see . */ #include +#if !defined(AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD) +#include "impl/os_thread_manager.hpp" +#endif namespace ams::os { void InitializeSdkMutex(SdkMutexType *mutex) { /* Initialize the critical section. */ GetReference(mutex->_storage).Initialize(); + + /* If the underlying critical section can't readily be checked, set owner thread. */ + #if !defined(AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD) + mutex->owner_thread = nullptr; + #endif } bool IsSdkMutexLockedByCurrentThread(const SdkMutexType *mutex) { + #if defined(AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD) /* Check whether the critical section is held. */ return GetReference(mutex->_storage).IsLockedByCurrentThread(); + #else + /* Check if the current thread is owner. */ + return mutex->owner_thread == os::impl::GetCurrentThread(); + #endif } void LockSdkMutex(SdkMutexType *mutex) { @@ -32,7 +45,12 @@ namespace ams::os { AMS_ABORT_UNLESS(!IsSdkMutexLockedByCurrentThread(mutex)); /* Enter the critical section. */ - return GetReference(mutex->_storage).Enter(); + GetReference(mutex->_storage).Enter(); + + /* If necessary, set owner thread. */ + #if !defined(AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD) + mutex->owner_thread = os::impl::GetCurrentThread(); + #endif } bool TryLockSdkMutex(SdkMutexType *mutex) { @@ -40,15 +58,29 @@ namespace ams::os { AMS_ABORT_UNLESS(!IsSdkMutexLockedByCurrentThread(mutex)); /* Try to enter the critical section. */ - return GetReference(mutex->_storage).TryEnter(); + const bool res = GetReference(mutex->_storage).TryEnter(); + + /* If necessary, set owner thread. */ + #if !defined(AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD) + if (res) { + mutex->owner_thread = os::impl::GetCurrentThread(); + } + #endif + + return res; } void UnlockSdkMutex(SdkMutexType *mutex) { /* Check pre-conditions. */ AMS_ABORT_UNLESS(IsSdkMutexLockedByCurrentThread(mutex)); + /* If necessary, clear owner thread. */ + #if !defined(AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD) + mutex->owner_thread = nullptr; + #endif + /* Leave the critical section. */ - return GetReference(mutex->_storage).Leave(); + GetReference(mutex->_storage).Leave(); } } diff --git a/libraries/libstratosphere/source/os/os_sdk_recursive_mutex.cpp b/libraries/libstratosphere/source/os/os_sdk_recursive_mutex.cpp index 0c1f746a2..0ecc25244 100644 --- a/libraries/libstratosphere/source/os/os_sdk_recursive_mutex.cpp +++ b/libraries/libstratosphere/source/os/os_sdk_recursive_mutex.cpp @@ -14,6 +14,9 @@ * along with this program. If not, see . */ #include +#if !defined(AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD) +#include "impl/os_thread_manager.hpp" +#endif namespace ams::os { @@ -23,17 +26,32 @@ namespace ams::os { /* Set recursive count. */ rmutex->recursive_count = 0; + + /* If the underlying critical section can't readily be checked, set owner thread. */ + #if !defined(AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD) + rmutex->owner_thread = nullptr; + #endif } bool IsSdkRecursiveMutexLockedByCurrentThread(const SdkRecursiveMutexType *rmutex) { + #if defined(AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD) /* Check whether the critical section is held. */ return GetReference(rmutex->_storage).IsLockedByCurrentThread(); + #else + /* Check if the current thread is owner. */ + return rmutex->owner_thread == os::impl::GetCurrentThread(); + #endif } void LockSdkRecursiveMutex(SdkRecursiveMutexType *rmutex) { /* If we don't hold the mutex, enter the critical section. */ if (!IsSdkRecursiveMutexLockedByCurrentThread(rmutex)) { GetReference(rmutex->_storage).Enter(); + + /* If necessary, set owner thread. */ + #if !defined(AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD) + rmutex->owner_thread = os::impl::GetCurrentThread(); + #endif } /* Increment (and check) recursive count. */ @@ -47,6 +65,11 @@ namespace ams::os { if (!GetReference(rmutex->_storage).TryEnter()) { return false; } + + /* If necessary, set owner thread. */ + #if !defined(AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD) + rmutex->owner_thread = os::impl::GetCurrentThread(); + #endif } /* Increment (and check) recursive count. */ @@ -62,6 +85,11 @@ namespace ams::os { /* Decrement recursive count, and leave critical section if we no longer hold the mutex. */ if ((--rmutex->recursive_count) == 0) { + /* If necessary, clear owner thread. */ + #if !defined(AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD) + rmutex->owner_thread = nullptr; + #endif + GetReference(rmutex->_storage).Leave(); } } diff --git a/libraries/libstratosphere/source/os/os_sdk_thread_local_storage_api.cpp b/libraries/libstratosphere/source/os/os_sdk_thread_local_storage_api.cpp index 79e505d00..2acdfdbdb 100644 --- a/libraries/libstratosphere/source/os/os_sdk_thread_local_storage_api.cpp +++ b/libraries/libstratosphere/source/os/os_sdk_thread_local_storage_api.cpp @@ -14,13 +14,21 @@ * along with this program. If not, see . */ #include +#include "impl/os_tls_manager.hpp" namespace ams::os { + #if defined(ATMOSPHERE_OS_HORIZON) /* TODO: Nintendo reserves half the TLS slots for SDK usage. */ /* We don't have that ability...how should this work? */ Result SdkAllocateTlsSlot(TlsSlot *out, TlsDestructor destructor) { return os::AllocateTlsSlot(out, destructor); } + #else + Result SdkAllocateTlsSlot(TlsSlot *out, TlsDestructor destructor) { + R_UNLESS(impl::GetTlsManager().AllocateTlsSlot(out, destructor, true), os::ResultOutOfResource()); + R_SUCCEED(); + } + #endif } diff --git a/libraries/libstratosphere/source/os/os_semaphore.cpp b/libraries/libstratosphere/source/os/os_semaphore.cpp index 42f6a88b7..2bf76cbeb 100644 --- a/libraries/libstratosphere/source/os/os_semaphore.cpp +++ b/libraries/libstratosphere/source/os/os_semaphore.cpp @@ -40,7 +40,7 @@ namespace ams::os { } void FinalizeSemaphore(SemaphoreType *sema) { - AMS_ASSERT(sema->state = SemaphoreType::State_Initialized); + AMS_ASSERT(sema->state == SemaphoreType::State_Initialized); AMS_ASSERT(GetReference(sema->waitlist).IsEmpty()); diff --git a/libraries/libstratosphere/source/os/os_system_event.cpp b/libraries/libstratosphere/source/os/os_system_event.cpp index a649398de..f132bbf34 100644 --- a/libraries/libstratosphere/source/os/os_system_event.cpp +++ b/libraries/libstratosphere/source/os/os_system_event.cpp @@ -43,17 +43,17 @@ namespace ams::os { } void AttachSystemEvent(SystemEventType *event, NativeHandle read_handle, bool read_handle_managed, NativeHandle write_handle, bool write_handle_managed, EventClearMode clear_mode) { - AMS_ASSERT(read_handle != svc::InvalidHandle || write_handle != svc::InvalidHandle); + AMS_ASSERT(read_handle != os::InvalidNativeHandle || write_handle != os::InvalidNativeHandle); impl::AttachInterProcessEvent(std::addressof(event->inter_process_event), read_handle, read_handle_managed, write_handle, write_handle_managed, clear_mode); event->state = SystemEventType::State_InitializedAsInterProcessEvent; } void AttachReadableHandleToSystemEvent(SystemEventType *event, NativeHandle read_handle, bool manage_read_handle, EventClearMode clear_mode) { - return AttachSystemEvent(event, read_handle, manage_read_handle, svc::InvalidHandle, false, clear_mode); + return AttachSystemEvent(event, read_handle, manage_read_handle, os::InvalidNativeHandle, false, clear_mode); } void AttachWritableHandleToSystemEvent(SystemEventType *event, NativeHandle write_handle, bool manage_write_handle, EventClearMode clear_mode) { - return AttachSystemEvent(event, svc::InvalidHandle, false, write_handle, manage_write_handle, clear_mode); + return AttachSystemEvent(event, os::InvalidNativeHandle, false, write_handle, manage_write_handle, clear_mode); } NativeHandle DetachReadableHandleOfSystemEvent(SystemEventType *event) { diff --git a/libraries/libstratosphere/source/os/os_thread.cpp b/libraries/libstratosphere/source/os/os_thread.cpp index 0536ec0dd..272b524b2 100644 --- a/libraries/libstratosphere/source/os/os_thread.cpp +++ b/libraries/libstratosphere/source/os/os_thread.cpp @@ -110,12 +110,6 @@ namespace ams::os { return thread->suspend_count; } - void CancelThreadSynchronization(ThreadType *thread) { - AMS_ASSERT(thread->state == ThreadType::State_Started || thread->state == ThreadType::State_Terminated); - - return impl::GetThreadManager().CancelThreadSynchronization(thread); - } - /* TODO: void GetThreadContext(ThreadContextInfo *out_context, const ThreadType *thread); */ s32 ChangeThreadPriority(ThreadType *thread, s32 priority) { diff --git a/libraries/libstratosphere/source/os/os_thread_local_storage_api.cpp b/libraries/libstratosphere/source/os/os_thread_local_storage_api.cpp index 6e734db5b..4fa7afb22 100644 --- a/libraries/libstratosphere/source/os/os_thread_local_storage_api.cpp +++ b/libraries/libstratosphere/source/os/os_thread_local_storage_api.cpp @@ -14,11 +14,12 @@ * along with this program. If not, see . */ #include +#include "impl/os_thread_manager.hpp" +#include "impl/os_tls_manager.hpp" namespace ams::os { - /* TODO: How will this work without libnx? */ - + #if defined(ATMOSPHERE_OS_HORIZON) namespace { using LibnxTlsDestructor = void (*)(void *); @@ -44,5 +45,28 @@ namespace ams::os { void SetTlsValue(TlsSlot slot, uintptr_t value) { ::threadTlsSet(static_cast(slot._value), reinterpret_cast(value)); } + #else + + Result AllocateTlsSlot(TlsSlot *out, TlsDestructor destructor) { + R_UNLESS(impl::GetTlsManager().AllocateTlsSlot(out, destructor, false), os::ResultOutOfResource()); + R_SUCCEED(); + } + + void FreeTlsSlot(TlsSlot slot) { + AMS_ASSERT(slot._value < impl::TotalTlsSlotCountMax); + impl::GetTlsManager().FreeTlsSlot(slot); + } + + uintptr_t GetTlsValue(TlsSlot slot) { + AMS_ASSERT(slot._value < impl::TotalTlsSlotCountMax); + return impl::GetCurrentThread()->tls_value_array[slot._value]; + } + + void SetTlsValue(TlsSlot slot, uintptr_t value) { + AMS_ASSERT(slot._value < impl::TotalTlsSlotCountMax); + impl::GetCurrentThread()->tls_value_array[slot._value] = value; + } + + #endif } diff --git a/libraries/libstratosphere/source/os/os_transfer_memory.cpp b/libraries/libstratosphere/source/os/os_transfer_memory.cpp index 53a232881..6042ad8d8 100644 --- a/libraries/libstratosphere/source/os/os_transfer_memory.cpp +++ b/libraries/libstratosphere/source/os/os_transfer_memory.cpp @@ -57,7 +57,7 @@ namespace ams::os { void AttachTransferMemory(TransferMemoryType *tmem, size_t size, NativeHandle handle, bool managed) { AMS_ASSERT(size > 0); AMS_ASSERT(util::IsAligned(size, os::MemoryPageSize)); - AMS_ASSERT(handle != svc::InvalidHandle); + AMS_ASSERT(handle != os::InvalidNativeHandle); /* Setup the object. */ SetupTransferMemoryType(tmem, size, handle, managed); diff --git a/libraries/libstratosphere/source/os/os_virtual_address_memory.cpp b/libraries/libstratosphere/source/os/os_virtual_address_memory.cpp index 368d2d1f8..f36bf1553 100644 --- a/libraries/libstratosphere/source/os/os_virtual_address_memory.cpp +++ b/libraries/libstratosphere/source/os/os_virtual_address_memory.cpp @@ -14,25 +14,54 @@ * along with this program. If not, see . */ #include +#include "impl/os_vamm_manager.hpp" namespace ams::os { - namespace { + void InitializeVirtualAddressMemory() { + return impl::GetVammManager().InitializeIfEnabled(); + } - /* TODO: Remove, add VammManager/horizon-impl */ - size_t GetSystemResourceSize() { - u64 v; - if (R_SUCCEEDED(svc::GetInfo(std::addressof(v), svc::InfoType_SystemResourceSizeTotal, os::GetCurrentProcessHandle(), 0))) { - return v; - } else { - return 0; - } - } + Result AllocateAddressRegion(uintptr_t *out, size_t size) { + AMS_ASSERT(size > 0); + AMS_ASSERT(util::IsAligned(size, MemoryPageSize)); + R_RETURN(impl::GetVammManager().AllocateAddressRegion(out, size)); + } + + Result AllocateMemory(uintptr_t *out, size_t size) { + AMS_ASSERT(size > 0); + AMS_ASSERT(util::IsAligned(size, MemoryPageSize)); + + R_RETURN(impl::GetVammManager().AllocateMemory(out, size)); + } + + Result AllocateMemoryPages(uintptr_t address, size_t size) { + AMS_ASSERT(size > 0); + AMS_ASSERT(util::IsAligned(size, MemoryPageSize)); + AMS_ASSERT(util::IsAligned(address, MemoryPageSize)); + + R_RETURN(impl::GetVammManager().AllocateMemoryPages(address, size)); + } + + Result FreeAddressRegion(uintptr_t address) { + R_RETURN(impl::GetVammManager().FreeAddressRegion(address)); + } + + Result FreeMemoryPages(uintptr_t address, size_t size) { + AMS_ASSERT(size > 0); + AMS_ASSERT(util::IsAligned(size, MemoryPageSize)); + AMS_ASSERT(util::IsAligned(address, MemoryPageSize)); + + R_RETURN(impl::GetVammManager().FreeMemoryPages(address, size)); + } + + VirtualAddressMemoryResourceUsage GetVirtualAddressMemoryResourceUsage() { + return impl::GetVammManager().GetVirtualAddressMemoryResourceUsage(); } bool IsVirtualAddressMemoryEnabled() { - return GetSystemResourceSize() > 0; + return impl::VammManager::IsVirtualAddressMemoryEnabled(); } } diff --git a/libraries/libstratosphere/source/osdbg/impl/osdbg_thread_info.generic.hpp b/libraries/libstratosphere/source/osdbg/impl/osdbg_thread_info.generic.hpp new file mode 100644 index 000000000..82ce69602 --- /dev/null +++ b/libraries/libstratosphere/source/osdbg/impl/osdbg_thread_info.generic.hpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 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 "osdbg_types.hpp" + +namespace ams::osdbg::impl { + + class ThreadInfoGenericImpl { + public: + static Result FillWithCurrentInfo(ThreadInfo *info) { + /* TODO */ + AMS_UNUSED(info); + R_THROW(osdbg::ResultCannotGetThreadInfo()); + } + }; + + using ThreadInfoImpl = ThreadInfoGenericImpl; + +} diff --git a/libraries/libstratosphere/source/osdbg/osdbg_thread.cpp b/libraries/libstratosphere/source/osdbg/osdbg_thread.cpp index 6bb9235e1..555c02b11 100644 --- a/libraries/libstratosphere/source/osdbg/osdbg_thread.cpp +++ b/libraries/libstratosphere/source/osdbg/osdbg_thread.cpp @@ -18,45 +18,51 @@ #if defined(ATMOSPHERE_OS_HORIZON) #include "impl/osdbg_thread_info.os.horizon.hpp" #else - #error "Unknown OS for ams::osdbg::ThreadInfo" + #include "impl/osdbg_thread_info.generic.hpp" #endif namespace ams::osdbg { - Result InitializeThreadInfo(ThreadInfo *thread_info, os::NativeHandle debug_handle, const svc::DebugInfoCreateProcess *create_process, const svc::DebugInfoCreateThread *create_thread) { + Result InitializeThreadInfo(ThreadInfo *thread_info, os::NativeHandle debug_handle, const osdbg::DebugInfoCreateProcess *create_process, const osdbg::DebugInfoCreateThread *create_thread) { /* Set basic fields. */ thread_info->_thread_type = nullptr; thread_info->_thread_type_type = ThreadTypeType_Unknown; thread_info->_debug_handle = debug_handle; + #if defined(ATMOSPHERE_OS_HORIZON) thread_info->_debug_info_create_process = *create_process; thread_info->_debug_info_create_thread = *create_thread; + #else + AMS_UNUSED(create_process, create_thread); + #endif /* Update the current info. */ - return impl::ThreadInfoImpl::FillWithCurrentInfo(thread_info); + R_RETURN(impl::ThreadInfoImpl::FillWithCurrentInfo(thread_info)); } Result UpdateThreadInfo(ThreadInfo *thread_info) { /* Update the current info. */ - return impl::ThreadInfoImpl::FillWithCurrentInfo(thread_info); + R_RETURN(impl::ThreadInfoImpl::FillWithCurrentInfo(thread_info)); } Result GetThreadName(char *dst, const ThreadInfo *thread_info) { - /* Get the name pointer. */ - const auto name_pointer = GetThreadNamePointer(thread_info); - + #if defined(ATMOSPHERE_OS_HORIZON) /* Read the name. */ - if (name_pointer != 0) { - return svc::ReadDebugProcessMemory(reinterpret_cast(dst), thread_info->_debug_handle, name_pointer, os::ThreadNameLengthMax); + if (const auto name_pointer = GetThreadNamePointer(thread_info); name_pointer != 0) { + R_RETURN(svc::ReadDebugProcessMemory(reinterpret_cast(dst), thread_info->_debug_handle, name_pointer, os::ThreadNameLengthMax)); } else { /* Special-case libnx threads. */ if (thread_info->_thread_type_type == ThreadTypeType_Libnx) { - util::TSNPrintf(dst, os::ThreadNameLengthMax, "libnx Thread_0x%010lx", reinterpret_cast(thread_info->_thread_type)); + util::TSNPrintf(dst, os::ThreadNameLengthMax, "libnx Thread_0x%010" PRIx64 "", reinterpret_cast(thread_info->_thread_type)); } else { - util::TSNPrintf(dst, os::ThreadNameLengthMax, "Thread_0x%010lx", reinterpret_cast(thread_info->_thread_type)); + util::TSNPrintf(dst, os::ThreadNameLengthMax, "Thread_0x%010" PRIx64 "", reinterpret_cast(thread_info->_thread_type)); } - return ResultSuccess(); + R_SUCCEED(); } + #else + util::TSNPrintf(dst, os::ThreadNameLengthMax, "Thread_0x%010" PRIx64 "", static_cast(reinterpret_cast(thread_info->_thread_type))); + R_SUCCEED(); + #endif } } diff --git a/libraries/libstratosphere/source/patcher/patcher_api.cpp b/libraries/libstratosphere/source/patcher/patcher_api.cpp index 3157d4960..f74259bd0 100644 --- a/libraries/libstratosphere/source/patcher/patcher_api.cpp +++ b/libraries/libstratosphere/source/patcher/patcher_api.cpp @@ -27,7 +27,7 @@ namespace ams::patcher { constexpr const char Ips32HeadMagic[5] = {'I', 'P', 'S', '3', '2'}; constexpr const char Ips32TailMagic[4] = {'E', 'E', 'O', 'F'}; constexpr const char *IpsFileExtension = ".ips"; - constexpr size_t IpsFileExtensionLength = std::strlen(IpsFileExtension); + constexpr size_t IpsFileExtensionLength = util::Strlen(IpsFileExtension); constexpr size_t ModuleIpsPatchLength = 2 * sizeof(ro::ModuleId) + IpsFileExtensionLength; /* Global data. */ diff --git a/libraries/libstratosphere/source/pgl/pgl_remote_event_observer.hpp b/libraries/libstratosphere/source/pgl/pgl_remote_event_observer.hpp index eb64edc0c..df57985e3 100644 --- a/libraries/libstratosphere/source/pgl/pgl_remote_event_observer.hpp +++ b/libraries/libstratosphere/source/pgl/pgl_remote_event_observer.hpp @@ -18,6 +18,7 @@ namespace ams::pgl { + #if defined(ATMOSPHERE_OS_HORIZON) class RemoteEventObserver { NON_COPYABLE(RemoteEventObserver); NON_MOVEABLE(RemoteEventObserver); @@ -55,5 +56,6 @@ namespace ams::pgl { }; static_assert(pgl::sf::IsIEventObserver); static_assert(pgl::tipc::IsIEventObserver); + #endif } \ No newline at end of file diff --git a/libraries/libstratosphere/source/pgl/pgl_shell_api.cpp b/libraries/libstratosphere/source/pgl/pgl_shell_api.cpp index 12988a84b..d8b548961 100644 --- a/libraries/libstratosphere/source/pgl/pgl_shell_api.cpp +++ b/libraries/libstratosphere/source/pgl/pgl_shell_api.cpp @@ -56,6 +56,7 @@ namespace ams::pgl { FreeToStaticExpHeap(obj); } + #if defined(ATMOSPHERE_OS_HORIZON) Result Initialize() { return ::pglInitialize(); } @@ -134,5 +135,74 @@ namespace ams::pgl { return ResultSuccess(); } + #else + Result Initialize() { + AMS_ABORT("TODO"); + } + + void Finalize() { + AMS_ABORT("TODO"); + } + + Result LaunchProgram(os::ProcessId *out, const ncm::ProgramLocation &loc, u32 process_flags, u8 pgl_flags) { + AMS_UNUSED(out, loc, process_flags, pgl_flags); + AMS_ABORT("TODO"); + } + + Result TerminateProcess(os::ProcessId process_id) { + AMS_UNUSED(process_id); + AMS_ABORT("TODO"); + } + + Result LaunchProgramFromHost(os::ProcessId *out, const char *content_path, u32 process_flags) { + AMS_UNUSED(out, content_path, process_flags); + AMS_ABORT("TODO"); + } + + Result GetHostContentMetaInfo(pgl::ContentMetaInfo *out, const char *content_path) { + AMS_UNUSED(out, content_path); + AMS_ABORT("TODO"); + } + + Result GetApplicationProcessId(os::ProcessId *out) { + AMS_UNUSED(out); + AMS_ABORT("TODO"); + } + + Result BoostSystemMemoryResourceLimit(u64 size) { + AMS_UNUSED(size); + AMS_ABORT("TODO"); + } + + Result IsProcessTracked(bool *out, os::ProcessId process_id) { + AMS_UNUSED(out, process_id); + AMS_ABORT("TODO"); + } + + Result EnableApplicationCrashReport(bool enabled) { + AMS_UNUSED(enabled); + AMS_ABORT("TODO"); + } + + Result IsApplicationCrashReportEnabled(bool *out) { + AMS_UNUSED(out); + AMS_ABORT("TODO"); + } + + Result EnableApplicationAllThreadDumpOnCrash(bool enabled) { + AMS_UNUSED(enabled); + AMS_ABORT("TODO"); + } + + Result TriggerApplicationSnapShotDumper(const char *arg, SnapShotDumpType dump_type) { + AMS_UNUSED(arg, dump_type); + AMS_ABORT("TODO"); + } + + Result GetEventObserver(pgl::EventObserver *out) { + AMS_UNUSED(out); + AMS_ABORT("TODO"); + } + #endif } \ No newline at end of file diff --git a/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell.cpp b/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell.cpp index fa0b73645..ed78d1854 100644 --- a/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell.cpp +++ b/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell.cpp @@ -43,14 +43,14 @@ namespace ams::pgl::srv { constinit bool g_enable_jit_debug = false; constexpr inline size_t ProcessControlTaskStackSize = 8_KB; - constinit os::ThreadType g_process_control_task_thread; + constinit os::ThreadType g_process_control_task_thread = {}; alignas(os::ThreadStackAlignment) constinit u8 g_process_control_task_stack[ProcessControlTaskStackSize]; constinit os::SdkMutex g_observer_list_mutex; constinit util::IntrusiveListBaseTraits::ListType g_observer_list; constinit os::SdkMutex g_process_data_mutex; - constinit ProcessData g_process_data[ProcessDataCount]; + constinit ProcessData g_process_data[ProcessDataCount] = {}; constinit os::ProcessId g_crashed_process_id = os::InvalidProcessId; constinit os::ProcessId g_creport_process_id = os::InvalidProcessId; @@ -215,7 +215,7 @@ namespace ams::pgl::srv { /* Generate arguments. */ char arguments[0x40]; - const size_t len = util::SNPrintf(arguments, sizeof(arguments), "%ld %d %d %d", static_cast(static_cast(process_id)), GetCrashReportDetailedArgument(data_flags), GetCrashReportScreenShotArgument(data_flags), g_enable_jit_debug); + const size_t len = util::SNPrintf(arguments, sizeof(arguments), "%" PRId64 " %d %d %d", static_cast(static_cast(process_id)), GetCrashReportDetailedArgument(data_flags), GetCrashReportScreenShotArgument(data_flags), g_enable_jit_debug); if (R_FAILED(ldr::SetProgramArgument(ncm::SystemProgramId::Creport, arguments, len + 1))) { return; } diff --git a/libraries/libstratosphere/source/pinmux/driver/pinmux_select_board_impl.hpp b/libraries/libstratosphere/source/pinmux/driver/pinmux_select_board_impl.hpp index 1793903b2..0d52cf0e5 100644 --- a/libraries/libstratosphere/source/pinmux/driver/pinmux_select_board_impl.hpp +++ b/libraries/libstratosphere/source/pinmux/driver/pinmux_select_board_impl.hpp @@ -25,6 +25,30 @@ #else - #error "Unknown board for pinmux driver" + // TODO: #error "Unknown board for pinmux driver" + + namespace ams::pinmux::driver::board { + + inline void Initialize() { + AMS_ABORT("TODO"); + } + + inline void Finalize() { + AMS_ABORT("TODO"); + } + + inline bool IsInitialized() { + AMS_ABORT("TODO"); + } + + inline void SetInitialConfig() { + AMS_ABORT("TODO"); + } + + inline void SetInitialDrivePadConfig() { + AMS_ABORT("TODO"); + } + + } #endif \ No newline at end of file diff --git a/libraries/libstratosphere/source/pm/pm_ams.c b/libraries/libstratosphere/source/pm/pm_ams.os.horizon.c similarity index 98% rename from libraries/libstratosphere/source/pm/pm_ams.c rename to libraries/libstratosphere/source/pm/pm_ams.os.horizon.c index 98478defa..b7b3d249a 100644 --- a/libraries/libstratosphere/source/pm/pm_ams.c +++ b/libraries/libstratosphere/source/pm/pm_ams.os.horizon.c @@ -15,14 +15,14 @@ */ #include -#include "pm_ams.h" +#include "pm_ams.os.horizon.h" Result pminfoAtmosphereGetProcessId(u64 *out_pid, u64 program_id) { return serviceDispatchInOut(pminfoGetServiceSession(), 65000, program_id, *out_pid); } Result pminfoAtmosphereHasLaunchedBootProgram(bool *out, u64 program_id) { - u8 tmp; + u8 tmp = 0; Result rc = serviceDispatchInOut(pminfoGetServiceSession(), 65001, program_id, tmp); if (R_SUCCEEDED(rc) && out) *out = tmp & 1; return rc; diff --git a/libraries/libstratosphere/source/pm/pm_ams.h b/libraries/libstratosphere/source/pm/pm_ams.os.horizon.h similarity index 94% rename from libraries/libstratosphere/source/pm/pm_ams.h rename to libraries/libstratosphere/source/pm/pm_ams.os.horizon.h index c66c75994..099752eee 100644 --- a/libraries/libstratosphere/source/pm/pm_ams.h +++ b/libraries/libstratosphere/source/pm/pm_ams.os.horizon.h @@ -5,6 +5,9 @@ * @copyright libnx Authors */ #pragma once + +#if defined(ATMOSPHERE_OS_HORIZON) + #include #ifdef __cplusplus @@ -25,4 +28,6 @@ Result pmdmntAtmosphereGetCurrentLimitInfo(u64 *out_cur, u64 *out_lim, u32 group #ifdef __cplusplus } +#endif + #endif \ No newline at end of file diff --git a/libraries/libstratosphere/source/pm/pm_boot_mode_api.cpp b/libraries/libstratosphere/source/pm/pm_boot_mode_api.cpp index a4a5db954..20cb16e4d 100644 --- a/libraries/libstratosphere/source/pm/pm_boot_mode_api.cpp +++ b/libraries/libstratosphere/source/pm/pm_boot_mode_api.cpp @@ -19,6 +19,7 @@ namespace ams::pm::bm { /* Boot Mode API. */ /* Both functions should be weakly linked, so that they can be overridden by ams::boot2 as needed. */ + #if defined(ATMOSPHERE_OS_HORIZON) BootMode WEAK_SYMBOL GetBootMode() { PmBootMode boot_mode = PmBootMode_Normal; R_ABORT_UNLESS(pmbmGetBootMode(std::addressof(boot_mode))); @@ -28,5 +29,14 @@ namespace ams::pm::bm { void WEAK_SYMBOL SetMaintenanceBoot() { R_ABORT_UNLESS(pmbmSetMaintenanceBoot()); } + #else + BootMode WEAK_SYMBOL GetBootMode() { + AMS_ABORT("TODO"); + } + + void WEAK_SYMBOL SetMaintenanceBoot() { + AMS_ABORT("TODO"); + } + #endif } diff --git a/libraries/libstratosphere/source/pm/pm_dmnt_api.cpp b/libraries/libstratosphere/source/pm/pm_dmnt_api.cpp index fd382ada7..2f1b29353 100644 --- a/libraries/libstratosphere/source/pm/pm_dmnt_api.cpp +++ b/libraries/libstratosphere/source/pm/pm_dmnt_api.cpp @@ -15,11 +15,12 @@ */ #include -#include "pm_ams.h" +#include "pm_ams.os.horizon.h" namespace ams::pm::dmnt { /* Debug Monitor API. */ + #if defined(ATMOSPHERE_OS_HORIZON) Result StartProcess(os::ProcessId process_id) { return pmdmntStartProcess(static_cast(process_id)); } @@ -52,5 +53,6 @@ namespace ams::pm::dmnt { *out_limit_value = 0; return pmdmntAtmosphereGetCurrentLimitInfo(out_current_value, out_limit_value, group, resource); } + #endif } diff --git a/libraries/libstratosphere/source/pm/pm_info_api.cpp b/libraries/libstratosphere/source/pm/pm_info_api.cpp index d46fad90f..978defda2 100644 --- a/libraries/libstratosphere/source/pm/pm_info_api.cpp +++ b/libraries/libstratosphere/source/pm/pm_info_api.cpp @@ -14,11 +14,12 @@ * along with this program. If not, see . */ #include -#include "pm_ams.h" +#include "pm_ams.os.horizon.h" namespace ams::pm::info { /* Information API. */ + #if defined(ATMOSPHERE_OS_HORIZON) Result GetProgramId(ncm::ProgramId *out_program_id, os::ProcessId process_id) { return pminfoGetProgramId(reinterpret_cast(out_program_id), static_cast(process_id)); } @@ -56,5 +57,6 @@ namespace ams::pm::info { return IsHblProcessId(out, process_id); } + #endif } diff --git a/libraries/libstratosphere/source/pm/pm_info_api_weak.cpp b/libraries/libstratosphere/source/pm/pm_info_api_weak.cpp index 56f72787b..0c826f5c1 100644 --- a/libraries/libstratosphere/source/pm/pm_info_api_weak.cpp +++ b/libraries/libstratosphere/source/pm/pm_info_api_weak.cpp @@ -14,16 +14,18 @@ * along with this program. If not, see . */ #include -#include "pm_ams.h" +#include "pm_ams.os.horizon.h" namespace ams::pm::info { /* Information API. */ + #if defined(ATMOSPHERE_OS_HORIZON) Result WEAK_SYMBOL HasLaunchedBootProgram(bool *out, ncm::ProgramId program_id) { bool has_launched = false; R_TRY(pminfoAtmosphereHasLaunchedBootProgram(std::addressof(has_launched), static_cast(program_id))); *out = has_launched; return ResultSuccess(); } + #endif } diff --git a/libraries/libstratosphere/source/pm/pm_shell_api.cpp b/libraries/libstratosphere/source/pm/pm_shell_api.cpp index 1d3622642..7dc4f2d9e 100644 --- a/libraries/libstratosphere/source/pm/pm_shell_api.cpp +++ b/libraries/libstratosphere/source/pm/pm_shell_api.cpp @@ -18,6 +18,7 @@ namespace ams::pm::shell { /* Shell API. */ + #if defined(ATMOSPHERE_OS_HORIZON) Result WEAK_SYMBOL LaunchProgram(os::ProcessId *out, const ncm::ProgramLocation &loc, u32 launch_flags) { static_assert(sizeof(ncm::ProgramLocation) == sizeof(NcmProgramLocation)); static_assert(alignof(ncm::ProgramLocation) == alignof(NcmProgramLocation)); @@ -52,5 +53,6 @@ namespace ams::pm::shell { Result EnableApplicationExtraThread() { return ::pmshellEnableApplicationExtraThread(); } + #endif } diff --git a/libraries/libstratosphere/source/powctl/impl/board/nintendo/nx/powctl_battery_driver.cpp b/libraries/libstratosphere/source/powctl/impl/board/nintendo/nx/powctl_battery_driver.cpp index aef142cd4..dbc81e7c1 100644 --- a/libraries/libstratosphere/source/powctl/impl/board/nintendo/nx/powctl_battery_driver.cpp +++ b/libraries/libstratosphere/source/powctl/impl/board/nintendo/nx/powctl_battery_driver.cpp @@ -138,7 +138,7 @@ namespace ams::powctl::impl::board::nintendo::nx { R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); /* Get the value. */ - double percent; + double percent{}; AMS_POWCTL_DRIVER_LOCKED_R_TRY_WITH_RETRY(GetMax17050Driver().GetChargePercentage(std::addressof(percent))); /* Set output. */ @@ -152,7 +152,7 @@ namespace ams::powctl::impl::board::nintendo::nx { R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); /* Get the value. */ - double percent; + double percent{}; AMS_POWCTL_DRIVER_LOCKED_R_TRY_WITH_RETRY(GetMax17050Driver().GetVoltageFuelGaugePercentage(std::addressof(percent))); /* Set output. */ @@ -166,7 +166,7 @@ namespace ams::powctl::impl::board::nintendo::nx { R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); /* Get the value. */ - double mah; + double mah{}; AMS_POWCTL_DRIVER_LOCKED_R_TRY_WITH_RETRY(GetMax17050Driver().GetFullCapacity(std::addressof(mah), SenseResistorValue)); /* Set output. */ @@ -180,7 +180,7 @@ namespace ams::powctl::impl::board::nintendo::nx { R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); /* Get the value. */ - double mah; + double mah{}; AMS_POWCTL_DRIVER_LOCKED_R_TRY_WITH_RETRY(GetMax17050Driver().GetRemainingCapacity(std::addressof(mah), SenseResistorValue)); /* Set output. */ @@ -239,7 +239,7 @@ namespace ams::powctl::impl::board::nintendo::nx { R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); /* Get the value. */ - double ma; + double ma{}; AMS_POWCTL_DRIVER_LOCKED_R_TRY_WITH_RETRY(GetMax17050Driver().GetAverageCurrent(std::addressof(ma), SenseResistorValue)); /* Set output. */ @@ -253,7 +253,7 @@ namespace ams::powctl::impl::board::nintendo::nx { R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); /* Get the value. */ - double ma; + double ma{}; AMS_POWCTL_DRIVER_LOCKED_R_TRY_WITH_RETRY(GetMax17050Driver().GetCurrent(std::addressof(ma), SenseResistorValue)); /* Set output. */ @@ -350,7 +350,7 @@ namespace ams::powctl::impl::board::nintendo::nx { R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); /* Get the battery cycles. */ - u16 cycles; + u16 cycles{}; AMS_POWCTL_DRIVER_LOCKED_R_TRY_WITH_RETRY(GetMax17050Driver().GetCycles(std::addressof(cycles))); /* Set output. */ @@ -373,7 +373,7 @@ namespace ams::powctl::impl::board::nintendo::nx { R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); /* Get the value. */ - double percent; + double percent{}; AMS_POWCTL_DRIVER_LOCKED_R_TRY_WITH_RETRY(GetMax17050Driver().GetAge(std::addressof(percent))); /* Set output. */ @@ -387,7 +387,7 @@ namespace ams::powctl::impl::board::nintendo::nx { R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); /* Get the value. */ - double temp; + double temp{}; AMS_POWCTL_DRIVER_LOCKED_R_TRY_WITH_RETRY(GetMax17050Driver().GetTemperature(std::addressof(temp))); /* Set output. */ @@ -401,7 +401,7 @@ namespace ams::powctl::impl::board::nintendo::nx { R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); /* Get the value. */ - u8 max_temp; + u8 max_temp{}; AMS_POWCTL_DRIVER_LOCKED_R_TRY_WITH_RETRY(GetMax17050Driver().GetMaximumTemperature(std::addressof(max_temp))); /* Set output. */ @@ -455,7 +455,7 @@ namespace ams::powctl::impl::board::nintendo::nx { R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); /* Get the value. */ - double ms; + double ms{}; AMS_POWCTL_DRIVER_LOCKED_R_TRY_WITH_RETRY(GetMax17050Driver().GetAverageVCellTime(std::addressof(ms))); /* Set output. */ diff --git a/libraries/libstratosphere/source/powctl/impl/board/nintendo/nx/powctl_charger_driver.cpp b/libraries/libstratosphere/source/powctl/impl/board/nintendo/nx/powctl_charger_driver.cpp index 361397ef7..d620d3cf4 100644 --- a/libraries/libstratosphere/source/powctl/impl/board/nintendo/nx/powctl_charger_driver.cpp +++ b/libraries/libstratosphere/source/powctl/impl/board/nintendo/nx/powctl_charger_driver.cpp @@ -137,7 +137,7 @@ namespace ams::powctl::impl::board::nintendo::nx { *out = ChargeCurrentState_NotCharging; } else { /* Get force 20 percent charge state. */ - bool force_20_percent; + bool force_20_percent = false; AMS_POWCTL_DRIVER_LOCKED_R_TRY_WITH_RETRY(GetBq24193Driver().GetForce20PercentChargeCurrent(std::addressof(force_20_percent))); /* Set output appropriately. */ @@ -277,7 +277,7 @@ namespace ams::powctl::impl::board::nintendo::nx { /* Validate arguments. */ R_UNLESS(device != nullptr, powctl::ResultInvalidArgument()); - bq24193::ChargerStatus bq_status; + bq24193::ChargerStatus bq_status = static_cast(~0); AMS_POWCTL_DRIVER_LOCKED_R_TRY_WITH_RETRY(GetBq24193Driver().GetChargerStatus(std::addressof(bq_status))); switch (bq_status) { diff --git a/libraries/libstratosphere/source/powctl/impl/powctl_device_management.cpp b/libraries/libstratosphere/source/powctl/impl/powctl_device_management.cpp index 28e10c179..336578374 100644 --- a/libraries/libstratosphere/source/powctl/impl/powctl_device_management.cpp +++ b/libraries/libstratosphere/source/powctl/impl/powctl_device_management.cpp @@ -20,7 +20,7 @@ namespace ams::powctl::impl { namespace { - constinit os::ThreadType g_interrupt_thread; + constinit os::ThreadType g_interrupt_thread = {}; constexpr inline size_t InterruptThreadStackSize = os::MemoryPageSize; alignas(os::MemoryPageSize) u8 g_interrupt_thread_stack[InterruptThreadStackSize]; diff --git a/libraries/libstratosphere/source/powctl/impl/powctl_select_board_driver.hpp b/libraries/libstratosphere/source/powctl/impl/powctl_select_board_driver.hpp index c24f24ec3..d37d9a9c7 100644 --- a/libraries/libstratosphere/source/powctl/impl/powctl_select_board_driver.hpp +++ b/libraries/libstratosphere/source/powctl/impl/powctl_select_board_driver.hpp @@ -27,6 +27,18 @@ #else - #error "Unknown board for ams::powctl::impl" + // TODO #error "Unknown board for ams::powctl::impl" + + namespace ams::powctl::impl::board { + + inline void Initialize(bool) { + AMS_ABORT("TODO"); + } + + inline void Finalize() { + AMS_ABORT("TODO"); + } + + } #endif diff --git a/libraries/libstratosphere/source/psc/psc_pm_module.os.horizon.cpp b/libraries/libstratosphere/source/psc/psc_pm_module.os.horizon.cpp index 80594f734..144d98ab4 100644 --- a/libraries/libstratosphere/source/psc/psc_pm_module.os.horizon.cpp +++ b/libraries/libstratosphere/source/psc/psc_pm_module.os.horizon.cpp @@ -34,7 +34,7 @@ namespace ams::psc { } - PmModule::PmModule() : m_intf(nullptr), m_initialized(false), m_reserved(0) { /* ... */ } + PmModule::PmModule() : m_intf(nullptr), m_initialized(false), m_module_id(PmModuleId_Reserved0), m_reserved(0) { /* ... */ } PmModule::~PmModule() { if (m_initialized) { diff --git a/libraries/libstratosphere/source/ro/impl/ro_ro_exception_info.cpp b/libraries/libstratosphere/source/ro/impl/ro_ro_exception_info.os.horizon.cpp similarity index 100% rename from libraries/libstratosphere/source/ro/impl/ro_ro_exception_info.cpp rename to libraries/libstratosphere/source/ro/impl/ro_ro_exception_info.os.horizon.cpp diff --git a/libraries/libstratosphere/source/scs/scs_shell.cpp b/libraries/libstratosphere/source/scs/scs_shell.cpp index e645ab11e..f6662827f 100644 --- a/libraries/libstratosphere/source/scs/scs_shell.cpp +++ b/libraries/libstratosphere/source/scs/scs_shell.cpp @@ -39,8 +39,8 @@ namespace ams::scs { class SocketInfoManager { private: - SocketInfo m_infos[MaxSocketInfo]; - int m_count; + SocketInfo m_infos[MaxSocketInfo]{}; + int m_count{}; public: constexpr SocketInfoManager() = default; @@ -95,9 +95,9 @@ namespace ams::scs { class ProgramInfoManager { private: - s32 m_next_info_id; - ProgramInfo m_infos[MaxProgramInfo]; - int m_count; + s32 m_next_info_id{}; + ProgramInfo m_infos[MaxProgramInfo]{}; + int m_count{}; public: constexpr ProgramInfoManager() = default; @@ -179,7 +179,7 @@ namespace ams::scs { }; alignas(os::ThreadStackAlignment) constinit u8 g_thread_stack[os::MemoryPageSize]; - constinit os::ThreadType g_thread; + constinit os::ThreadType g_thread = {}; constinit ProcessEventHandler g_common_start_handler; constinit ProcessEventHandler g_common_exit_handler; diff --git a/libraries/libstratosphere/source/settings/impl/settings_configuration_id_impl.cpp b/libraries/libstratosphere/source/settings/impl/settings_configuration_id_impl.cpp index 99e0900c2..b2f166c6b 100644 --- a/libraries/libstratosphere/source/settings/impl/settings_configuration_id_impl.cpp +++ b/libraries/libstratosphere/source/settings/impl/settings_configuration_id_impl.cpp @@ -19,8 +19,13 @@ namespace ams::settings::impl { Result GetConfigurationId1(settings::factory::ConfigurationId1 *out) { + #if defined(ATMOSPHERE_OS_HORIZON) static_assert(sizeof(*out) == sizeof(::SetCalConfigurationId1)); return ::setcalGetConfigurationId1(reinterpret_cast<::SetCalConfigurationId1 *>(out)); + #else + AMS_UNUSED(out); + AMS_ABORT("TODO"); + #endif } } diff --git a/libraries/libstratosphere/source/settings/impl/settings_error_report_impl.cpp b/libraries/libstratosphere/source/settings/impl/settings_error_report_impl.cpp index fd9fadde6..0d44d4db3 100644 --- a/libraries/libstratosphere/source/settings/impl/settings_error_report_impl.cpp +++ b/libraries/libstratosphere/source/settings/impl/settings_error_report_impl.cpp @@ -19,8 +19,13 @@ namespace ams::settings::impl { Result GetErrorReportSharePermission(s32 *out) { + #if defined(ATMOSPHERE_OS_HORIZON) static_assert(sizeof(*out) == sizeof(::SetSysErrorReportSharePermission)); return ::setsysGetErrorReportSharePermission(reinterpret_cast<::SetSysErrorReportSharePermission *>(out)); + #else + AMS_UNUSED(out); + AMS_ABORT("TODO"); + #endif } } diff --git a/libraries/libstratosphere/source/settings/impl/settings_firmware_version_impl.cpp b/libraries/libstratosphere/source/settings/impl/settings_firmware_version_impl.cpp index 30758ab33..938c2a12e 100644 --- a/libraries/libstratosphere/source/settings/impl/settings_firmware_version_impl.cpp +++ b/libraries/libstratosphere/source/settings/impl/settings_firmware_version_impl.cpp @@ -19,8 +19,13 @@ namespace ams::settings::impl { Result GetFirmwareVersion(settings::system::FirmwareVersion *out) { + #if defined(ATMOSPHERE_OS_HORIZON) static_assert(sizeof(*out) == sizeof(::SetSysFirmwareVersion)); return ::setsysGetFirmwareVersion(reinterpret_cast<::SetSysFirmwareVersion *>(out)); + #else + AMS_UNUSED(out); + AMS_ABORT("TODO"); + #endif } } diff --git a/libraries/libstratosphere/source/settings/impl/settings_key_value_store.cpp b/libraries/libstratosphere/source/settings/impl/settings_key_value_store.cpp index b95cdccec..687a5707c 100644 --- a/libraries/libstratosphere/source/settings/impl/settings_key_value_store.cpp +++ b/libraries/libstratosphere/source/settings/impl/settings_key_value_store.cpp @@ -646,7 +646,6 @@ namespace ams::settings::impl { Result LoadKeyValueStoreMapEntries(Map *out, T &data, F load) { /* Check pre-conditions. */ AMS_ASSERT(out != nullptr); - AMS_ASSERT(load != nullptr); /* Read the number of entries. */ s64 offset = 0; @@ -665,7 +664,6 @@ namespace ams::settings::impl { Result LoadKeyValueStoreMapEntry(Map *out, T &data, s64 &offset, F load) { /* Check pre-conditions. */ AMS_ASSERT(out != nullptr); - AMS_ASSERT(load != nullptr); /* Read the size of the key. */ u32 key_size = 0; @@ -892,9 +890,6 @@ namespace ams::settings::impl { template Result SaveKeyValueStoreMap(T &data, const Map &map, F test) { - /* Check preconditions. */ - AMS_ASSERT(test != nullptr); - /* Create the save data if necessary. */ R_TRY_CATCH(data.Create(HeapMemorySize)) { R_CATCH(fs::ResultPathAlreadyExists) { /* It's okay if the save data already exists. */ } @@ -1114,7 +1109,7 @@ namespace ams::settings::impl { Result KeyValueStore::GetValueSize(u64 *out_value_size, const SettingsItemKey &item_key) { /* Check preconditions. */ - AMS_ASSERT(out_count != nullptr); + AMS_ASSERT(out_value_size != nullptr); /* Acquire exclusive access to global state. */ std::scoped_lock lk(g_key_value_store_mutex); @@ -1380,7 +1375,7 @@ namespace ams::settings::impl { Result GetKeyValueStoreItemCountForDebug(u64 *out_count) { /* Check preconditions. */ - AMS_ASSERT(out != nullptr); + AMS_ASSERT(out_count != nullptr); /* Acquire exclusive access to global state. */ std::scoped_lock lk(g_key_value_store_mutex); diff --git a/libraries/libstratosphere/source/settings/impl/settings_platform_region_impl.cpp b/libraries/libstratosphere/source/settings/impl/settings_platform_region_impl.cpp index 63da51b98..dd5e98e66 100644 --- a/libraries/libstratosphere/source/settings/impl/settings_platform_region_impl.cpp +++ b/libraries/libstratosphere/source/settings/impl/settings_platform_region_impl.cpp @@ -19,8 +19,13 @@ namespace ams::settings::impl { Result GetPlatformRegion(s32 *out) { + #if defined(ATMOSPHERE_OS_HORIZON) static_assert(sizeof(*out) == sizeof(::SetSysPlatformRegion)); return ::setsysGetPlatformRegion(reinterpret_cast<::SetSysPlatformRegion *>(out)); + #else + AMS_UNUSED(out); + AMS_ABORT("TODO"); + #endif } } diff --git a/libraries/libstratosphere/source/settings/impl/settings_product_model_impl.cpp b/libraries/libstratosphere/source/settings/impl/settings_product_model_impl.cpp index 1b458a663..dd60dac06 100644 --- a/libraries/libstratosphere/source/settings/impl/settings_product_model_impl.cpp +++ b/libraries/libstratosphere/source/settings/impl/settings_product_model_impl.cpp @@ -19,8 +19,13 @@ namespace ams::settings::impl { Result GetProductModel(s32 *out) { + #if defined(ATMOSPHERE_OS_HORIZON) static_assert(sizeof(*out) == sizeof(::SetSysProductModel)); return ::setsysGetProductModel(reinterpret_cast<::SetSysProductModel *>(out)); + #else + AMS_UNUSED(out); + AMS_ABORT("TODO"); + #endif } } diff --git a/libraries/libstratosphere/source/settings/impl/settings_region_impl.cpp b/libraries/libstratosphere/source/settings/impl/settings_region_impl.cpp index 54ef6ca64..1347b607e 100644 --- a/libraries/libstratosphere/source/settings/impl/settings_region_impl.cpp +++ b/libraries/libstratosphere/source/settings/impl/settings_region_impl.cpp @@ -19,8 +19,13 @@ namespace ams::settings::impl { Result GetRegionCode(s32 *out) { + #if defined(ATMOSPHERE_OS_HORIZON) static_assert(sizeof(*out) == sizeof(::SetRegion)); return ::setGetRegionCode(reinterpret_cast<::SetRegion *>(out)); + #else + AMS_UNUSED(out); + AMS_ABORT("TODO"); + #endif } } diff --git a/libraries/libstratosphere/source/settings/impl/settings_serial_number_impl.cpp b/libraries/libstratosphere/source/settings/impl/settings_serial_number_impl.cpp index aebc8125d..b048f407f 100644 --- a/libraries/libstratosphere/source/settings/impl/settings_serial_number_impl.cpp +++ b/libraries/libstratosphere/source/settings/impl/settings_serial_number_impl.cpp @@ -19,13 +19,23 @@ namespace ams::settings::impl { Result GetSerialNumber(settings::factory::SerialNumber *out) { + #if defined(ATMOSPHERE_OS_HORIZON) static_assert(sizeof(*out) == sizeof(::SetCalSerialNumber)); return ::setcalGetSerialNumber(reinterpret_cast<::SetCalSerialNumber *>(out)); + #else + AMS_UNUSED(out); + AMS_ABORT("TODO"); + #endif } Result GetSerialNumber(settings::system::SerialNumber *out) { + #if defined(ATMOSPHERE_OS_HORIZON) static_assert(sizeof(*out) == sizeof(::SetSysSerialNumber)); return ::setsysGetSerialNumber(reinterpret_cast<::SetSysSerialNumber *>(out)); + #else + AMS_UNUSED(out); + AMS_ABORT("TODO"); + #endif } } diff --git a/libraries/libstratosphere/source/settings/settings_fwdbg_api.cpp b/libraries/libstratosphere/source/settings/settings_fwdbg_api.cpp index 62c6c1eb7..360309b8b 100644 --- a/libraries/libstratosphere/source/settings/settings_fwdbg_api.cpp +++ b/libraries/libstratosphere/source/settings/settings_fwdbg_api.cpp @@ -17,6 +17,7 @@ namespace ams::settings::fwdbg { + #if defined(ATMOSPHERE_OS_HORIZON) bool IsDebugModeEnabled() { bool value = false; R_ABORT_UNLESS(::setsysGetDebugModeFlag(std::addressof(value))); @@ -34,5 +35,20 @@ namespace ams::settings::fwdbg { R_ABORT_UNLESS(setsysGetSettingsItemValue(name, key, dst, dst_size, &size)); return size; } + #else + bool IsDebugModeEnabled() { + AMS_ABORT("TODO"); + } + + size_t WEAK_SYMBOL GetSettingsItemValueSize(const char *name, const char *key) { + AMS_UNUSED(name, key); + AMS_ABORT("TODO"); + } + + size_t WEAK_SYMBOL GetSettingsItemValue(void *dst, size_t dst_size, const char *name, const char *key) { + AMS_UNUSED(dst, dst_size, name, key); + AMS_ABORT("TODO"); + } + #endif } diff --git a/libraries/libstratosphere/source/sf/cmif/sf_cmif_domain_service_object.cpp b/libraries/libstratosphere/source/sf/cmif/sf_cmif_domain_service_object.cpp index f94a321a7..b3ab676cf 100644 --- a/libraries/libstratosphere/source/sf/cmif/sf_cmif_domain_service_object.cpp +++ b/libraries/libstratosphere/source/sf/cmif/sf_cmif_domain_service_object.cpp @@ -21,9 +21,11 @@ namespace ams::sf::cmif { return this->ProcessMessageImpl(ctx, static_cast(ctx.srv_obj)->GetServerDomain(), in_raw_data); } + #if AMS_SF_MITM_SUPPORTED Result DomainServiceObjectDispatchTable::ProcessMessageForMitm(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) const { return this->ProcessMessageForMitmImpl(ctx, static_cast(ctx.srv_obj)->GetServerDomain(), in_raw_data); } + #endif Result DomainServiceObjectDispatchTable::ProcessMessageImpl(ServiceDispatchContext &ctx, ServerDomainBase *domain, const cmif::PointerAndSize &in_raw_data) const { const CmifDomainInHeader *in_header = reinterpret_cast(in_raw_data.GetPointer()); @@ -59,6 +61,7 @@ namespace ams::sf::cmif { } } + #if AMS_SF_MITM_SUPPORTED Result DomainServiceObjectDispatchTable::ProcessMessageForMitmImpl(ServiceDispatchContext &ctx, ServerDomainBase *domain, const cmif::PointerAndSize &in_raw_data) const { const CmifDomainInHeader *in_header = reinterpret_cast(in_raw_data.GetPointer()); R_UNLESS(in_raw_data.GetSize() >= sizeof(*in_header), sf::cmif::ResultInvalidHeaderSize()); @@ -106,6 +109,7 @@ namespace ams::sf::cmif { return sf::cmif::ResultInvalidInHeader(); } } + #endif Result DomainServiceObjectProcessor::PrepareForProcess(const ServiceDispatchContext &ctx, const ServerMessageRuntimeMetadata runtime_metadata) const { /* Validate in object count. */ diff --git a/libraries/libstratosphere/source/sf/cmif/sf_cmif_inline_context.cpp b/libraries/libstratosphere/source/sf/cmif/sf_cmif_inline_context.cpp index a0b11b04c..af6447e5d 100644 --- a/libraries/libstratosphere/source/sf/cmif/sf_cmif_inline_context.cpp +++ b/libraries/libstratosphere/source/sf/cmif/sf_cmif_inline_context.cpp @@ -21,25 +21,36 @@ namespace ams::sf { namespace { - ALWAYS_INLINE std::atomic *GetAtomicSfInlineContext(os::ThreadType *thread) { - static_assert(sizeof(thread->atomic_sf_inline_context) >= sizeof(std::atomic)); - return reinterpret_cast *>(std::addressof(thread->atomic_sf_inline_context)); - } + #if !defined(ATMOSPHERE_COMPILER_CLANG) + ALWAYS_INLINE util::AtomicRef GetAtomicSfInlineContext(os::ThreadType *thread = os::GetCurrentThread()) { + uintptr_t * const p = std::addressof(os::GetSdkInternalTlsArray(thread)->sf_inline_context); - ALWAYS_INLINE std::atomic *GetAtomicSfInlineContext() { - return GetAtomicSfInlineContext(os::GetCurrentThread()); + return util::AtomicRef(*p); } + #else + ALWAYS_INLINE util::Atomic &GetAtomicSfInlineContext(os::ThreadType *thread = os::GetCurrentThread()) { + uintptr_t * const p = std::addressof(os::GetSdkInternalTlsArray(thread)->sf_inline_context); + static_assert(sizeof(std::atomic) == sizeof(uintptr_t)); + static_assert(sizeof(util::Atomic) == sizeof(std::atomic)); + + return *reinterpret_cast *>(p); + } + #endif ALWAYS_INLINE void OnSetInlineContext(os::ThreadType *thread) { + #if defined(ATMOSPHERE_OS_HORIZON) /* Ensure that libnx receives the priority value. */ ::fsSetPriority(static_cast<::FsPriority>(::ams::sf::GetFsInlineContext(thread))); + #else + AMS_UNUSED(thread); + #endif } } InlineContext GetInlineContext() { /* Get the context. */ - uintptr_t thread_context = GetAtomicSfInlineContext()->load(); + uintptr_t thread_context = GetAtomicSfInlineContext().Load(); /* Copy it out. */ InlineContext ctx; @@ -59,7 +70,7 @@ namespace ams::sf { std::memcpy(std::addressof(new_context_value), std::addressof(ctx), sizeof(ctx)); /* Get the old context. */ - uintptr_t old_context_value = GetAtomicSfInlineContext(cur_thread)->exchange(new_context_value); + uintptr_t old_context_value = GetAtomicSfInlineContext(cur_thread).Exchange(new_context_value); /* Convert and copy it out. */ InlineContext old_ctx; @@ -71,21 +82,32 @@ namespace ams::sf { namespace { - ALWAYS_INLINE std::atomic *GetAtomicFsInlineContext(os::ThreadType *thread) { - static_assert(sizeof(thread->atomic_sf_inline_context) >= sizeof(std::atomic)); - return reinterpret_cast *>(std::addressof(thread->atomic_sf_inline_context)); + #if !defined(ATMOSPHERE_COMPILER_CLANG) + ALWAYS_INLINE util::AtomicRef GetAtomicFsInlineContext(os::ThreadType *thread) { + uintptr_t * const p = std::addressof(os::GetSdkInternalTlsArray(thread)->sf_inline_context); + + return util::AtomicRef(*reinterpret_cast(p)); } + #else + ALWAYS_INLINE util::Atomic &GetAtomicFsInlineContext(os::ThreadType *thread) { + uintptr_t * const p = std::addressof(os::GetSdkInternalTlsArray(thread)->sf_inline_context); + static_assert(sizeof(std::atomic) == sizeof(u8)); + static_assert(sizeof(util::Atomic) == sizeof(std::atomic)); + + return *reinterpret_cast *>(reinterpret_cast(p)); + } + #endif } u8 GetFsInlineContext(os::ThreadType *thread) { - return GetAtomicFsInlineContext(thread)->load(); + return GetAtomicFsInlineContext(thread).Load(); } u8 SetFsInlineContext(os::ThreadType *thread, u8 ctx) { ON_SCOPE_EXIT { cmif::OnSetInlineContext(thread); }; - return GetAtomicFsInlineContext(thread)->exchange(ctx); + return GetAtomicFsInlineContext(thread).Exchange(ctx); } } diff --git a/libraries/libstratosphere/source/sf/cmif/sf_cmif_service_dispatch.cpp b/libraries/libstratosphere/source/sf/cmif/sf_cmif_service_dispatch.cpp index d24522787..117c1f806 100644 --- a/libraries/libstratosphere/source/sf/cmif/sf_cmif_service_dispatch.cpp +++ b/libraries/libstratosphere/source/sf/cmif/sf_cmif_service_dispatch.cpp @@ -19,6 +19,13 @@ namespace ams::sf::cmif { namespace { + constexpr inline u32 InHeaderMagic = util::FourCC<'S','F','C','I'>::Code; + constexpr inline u32 OutHeaderMagic = util::FourCC<'S','F','C','O'>::Code; + #if defined(ATMOSPHERE_OS_HORIZON) + static_assert(InHeaderMagic == CMIF_IN_HEADER_MAGIC); + static_assert(OutHeaderMagic == CMIF_OUT_HEADER_MAGIC); + #endif + ALWAYS_INLINE decltype(ServiceCommandMeta::handler) FindCommandHandlerByBinarySearch(const ServiceCommandMeta *entries, const size_t entry_count, const u32 cmd_id, const hos::Version hos_version) { /* Binary search for the handler. */ ssize_t lo = 0; @@ -84,7 +91,7 @@ namespace ams::sf::cmif { /* Parse the CMIF in header. */ const CmifInHeader *in_header = reinterpret_cast(in_raw_data.GetPointer()); R_UNLESS(in_raw_data.GetSize() >= sizeof(*in_header), sf::cmif::ResultInvalidHeaderSize()); - R_UNLESS(in_header->magic == CMIF_IN_HEADER_MAGIC && in_header->version <= max_cmif_version, sf::cmif::ResultInvalidInHeader()); + R_UNLESS(in_header->magic == InHeaderMagic && in_header->version <= max_cmif_version, sf::cmif::ResultInvalidInHeader()); const cmif::PointerAndSize in_message_raw_data = cmif::PointerAndSize(in_raw_data.GetAddress() + sizeof(*in_header), in_raw_data.GetSize() - sizeof(*in_header)); const u32 cmd_id = in_header->command_id; @@ -108,11 +115,12 @@ namespace ams::sf::cmif { } /* Write output header to raw data. */ - *out_header = CmifOutHeader{CMIF_OUT_HEADER_MAGIC, 0, command_result.GetValue(), 0}; + *out_header = CmifOutHeader{OutHeaderMagic, 0, command_result.GetValue(), 0}; return ResultSuccess(); } + #if AMS_SF_MITM_SUPPORTED Result impl::ServiceDispatchTableBase::ProcessMessageForMitmImpl(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data, const ServiceCommandMeta *entries, const size_t entry_count) const { /* Get versioning info. */ const auto hos_version = hos::GetVersion(); @@ -121,7 +129,7 @@ namespace ams::sf::cmif { /* Parse the CMIF in header. */ const CmifInHeader *in_header = reinterpret_cast(in_raw_data.GetPointer()); R_UNLESS(in_raw_data.GetSize() >= sizeof(*in_header), sf::cmif::ResultInvalidHeaderSize()); - R_UNLESS(in_header->magic == CMIF_IN_HEADER_MAGIC && in_header->version <= max_cmif_version, sf::cmif::ResultInvalidInHeader()); + R_UNLESS(in_header->magic == InHeaderMagic && in_header->version <= max_cmif_version, sf::cmif::ResultInvalidInHeader()); const cmif::PointerAndSize in_message_raw_data = cmif::PointerAndSize(in_raw_data.GetAddress() + sizeof(*in_header), in_raw_data.GetSize() - sizeof(*in_header)); const u32 cmd_id = in_header->command_id; @@ -154,9 +162,10 @@ namespace ams::sf::cmif { } /* Write output header to raw data. */ - *out_header = CmifOutHeader{CMIF_OUT_HEADER_MAGIC, 0, command_result.GetValue(), 0}; + *out_header = CmifOutHeader{OutHeaderMagic, 0, command_result.GetValue(), 0}; return ResultSuccess(); } + #endif } diff --git a/libraries/libstratosphere/source/sf/hipc/sf_hipc_api.cpp b/libraries/libstratosphere/source/sf/hipc/sf_hipc_api.os.horizon.cpp similarity index 96% rename from libraries/libstratosphere/source/sf/hipc/sf_hipc_api.cpp rename to libraries/libstratosphere/source/sf/hipc/sf_hipc_api.os.horizon.cpp index 06eb16e1d..6c5b6d55f 100644 --- a/libraries/libstratosphere/source/sf/hipc/sf_hipc_api.cpp +++ b/libraries/libstratosphere/source/sf/hipc/sf_hipc_api.os.horizon.cpp @@ -21,7 +21,7 @@ namespace ams::sf::hipc { ALWAYS_INLINE Result ReceiveImpl(os::NativeHandle session_handle, void *message_buf, size_t message_buf_size) { s32 unused_index; - if (message_buf == svc::GetThreadLocalRegion()->message_buffer) { + if (message_buf == hipc::GetMessageBufferOnTls()) { /* Consider: AMS_ABORT_UNLESS(message_buf_size == TlsMessageBufferSize); */ return svc::ReplyAndReceive(&unused_index, &session_handle, 1, svc::InvalidHandle, std::numeric_limits::max()); } else { @@ -31,7 +31,7 @@ namespace ams::sf::hipc { ALWAYS_INLINE Result ReplyImpl(os::NativeHandle session_handle, void *message_buf, size_t message_buf_size) { s32 unused_index; - if (message_buf == svc::GetThreadLocalRegion()->message_buffer) { + if (message_buf == hipc::GetMessageBufferOnTls()) { /* Consider: AMS_ABORT_UNLESS(message_buf_size == TlsMessageBufferSize); */ return svc::ReplyAndReceive(&unused_index, &session_handle, 0, session_handle, 0); } else { diff --git a/libraries/libstratosphere/source/sf/hipc/sf_hipc_mitm_query_api.cpp b/libraries/libstratosphere/source/sf/hipc/sf_hipc_mitm_query_api.cpp index 8fb68eaaf..494f70392 100644 --- a/libraries/libstratosphere/source/sf/hipc/sf_hipc_mitm_query_api.cpp +++ b/libraries/libstratosphere/source/sf/hipc/sf_hipc_mitm_query_api.cpp @@ -16,6 +16,8 @@ #include #include "sf_hipc_mitm_query_api.hpp" +#if AMS_SF_MITM_SUPPORTED + #define AMS_SF_HIPC_IMPL_I_MITM_QUERY_SERVICE_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 65000, void, ShouldMitm, (sf::Out out, const sm::MitmProcessInfo &client_info), (out, client_info)) @@ -74,3 +76,5 @@ namespace ams::sf::hipc::impl { } } + +#endif diff --git a/libraries/libstratosphere/source/sf/hipc/sf_hipc_mitm_query_api.hpp b/libraries/libstratosphere/source/sf/hipc/sf_hipc_mitm_query_api.hpp index 0cd1518d4..1b4a08f97 100644 --- a/libraries/libstratosphere/source/sf/hipc/sf_hipc_mitm_query_api.hpp +++ b/libraries/libstratosphere/source/sf/hipc/sf_hipc_mitm_query_api.hpp @@ -18,6 +18,8 @@ namespace ams::sf::hipc::impl { + #if AMS_SF_MITM_SUPPORTED void RegisterMitmQueryHandle(os::NativeHandle query_handle, ServerManagerBase::MitmQueryFunction query_func); + #endif } diff --git a/libraries/libstratosphere/source/sf/hipc/sf_hipc_server_domain_session_manager.cpp b/libraries/libstratosphere/source/sf/hipc/sf_hipc_server_domain_session_manager.cpp index 07d82763e..52441446e 100644 --- a/libraries/libstratosphere/source/sf/hipc/sf_hipc_server_domain_session_manager.cpp +++ b/libraries/libstratosphere/source/sf/hipc/sf_hipc_server_domain_session_manager.cpp @@ -32,7 +32,9 @@ namespace ams::sf::hipc { private: ServerDomainSessionManager *m_manager; ServerSession *m_session; + #if AMS_SF_MITM_SUPPORTED const bool m_is_mitm_session; + #endif private: Result CloneCurrentObjectImpl(sf::OutMoveHandle &out_client_handle, ServerSessionManager *tagged_manager) { /* Clone the object. */ @@ -44,8 +46,11 @@ namespace ams::sf::hipc { R_ABORT_UNLESS(hipc::CreateSession(std::addressof(server_handle), std::addressof(client_handle))); /* Register with manager. */ + #if AMS_SF_MITM_SUPPORTED if (!m_is_mitm_session) { + #endif R_ABORT_UNLESS(tagged_manager->RegisterSession(server_handle, std::move(clone))); + #if AMS_SF_MITM_SUPPORTED } else { /* Check that we can create a mitm session. */ AMS_ABORT_UNLESS(ServerManagerBase::CanAnyManageMitmServers()); @@ -55,15 +60,18 @@ namespace ams::sf::hipc { R_ABORT_UNLESS(serviceClone(util::GetReference(m_session->m_forward_service).get(), new_forward_service.get())); R_ABORT_UNLESS(tagged_manager->RegisterMitmSession(server_handle, std::move(clone), std::move(new_forward_service))); } + #endif /* Set output client handle. */ out_client_handle.SetValue(client_handle, false); return ResultSuccess(); } public: - explicit HipcManagerImpl(ServerDomainSessionManager *m, ServerSession *s) : m_manager(m), m_session(s), m_is_mitm_session(s->IsMitmSession()) { - /* ... */ - } + #if AMS_SF_MITM_SUPPORTED + explicit HipcManagerImpl(ServerDomainSessionManager *m, ServerSession *s) : m_manager(m), m_session(s), m_is_mitm_session(s->IsMitmSession()) { /* ... */ } + #else + explicit HipcManagerImpl(ServerDomainSessionManager *m, ServerSession *s) : m_manager(m), m_session(s) { /* ... */ } + #endif Result ConvertCurrentObjectToDomain(sf::Out out) { /* Allocate a domain. */ @@ -72,6 +80,7 @@ namespace ams::sf::hipc { /* Set up the new domain object. */ cmif::DomainObjectId object_id = cmif::InvalidDomainObjectId; + #if AMS_SF_MITM_SUPPORTED if (m_is_mitm_session) { /* Check that we can create a mitm session. */ AMS_ABORT_UNLESS(ServerManagerBase::CanAnyManageMitmServers()); @@ -93,6 +102,9 @@ namespace ams::sf::hipc { /* Set the new object holder. */ m_session->m_srv_obj_holder = cmif::ServiceObjectHolder(std::move(cmif_domain)); } else { + #else + { + #endif /* Make a new shared pointer to manage the allocated domain. */ SharedPointer cmif_domain(domain, false); @@ -119,6 +131,7 @@ namespace ams::sf::hipc { /* Get domain object. */ auto &&object = domain->GetObject(object_id); + #if AMS_SF_MITM_SUPPORTED if (!object) { R_UNLESS(m_is_mitm_session, sf::hipc::ResultDomainObjectNotFound()); @@ -131,8 +144,15 @@ namespace ams::sf::hipc { out.SetValue(handle, false); return ResultSuccess(); } + #else + R_UNLESS(!!(object), sf::hipc::ResultDomainObjectNotFound()); + #endif + #if AMS_SF_MITM_SUPPORTED if (!m_is_mitm_session || (ServerManagerBase::CanAnyManageMitmServers() && object_id.value != serviceGetObjectId(util::GetReference(m_session->m_forward_service).get()))) { + #else + { + #endif /* Create new session handles. */ os::NativeHandle server_handle, client_handle; R_ABORT_UNLESS(hipc::CreateSession(std::addressof(server_handle), std::addressof(client_handle))); @@ -142,6 +162,7 @@ namespace ams::sf::hipc { /* Set output client handle. */ out.SetValue(client_handle, false); + #if AMS_SF_MITM_SUPPORTED } else { /* Check that we can create a mitm session. */ AMS_ABORT_UNLESS(ServerManagerBase::CanAnyManageMitmServers()); @@ -161,6 +182,7 @@ namespace ams::sf::hipc { /* Set output client handle. */ out.SetValue(client_handle, false); + #endif } return ResultSuccess(); diff --git a/libraries/libstratosphere/source/sf/hipc/sf_hipc_server_manager.cpp b/libraries/libstratosphere/source/sf/hipc/sf_hipc_server_manager.cpp index 7e8f3cbb9..99fb35b9e 100644 --- a/libraries/libstratosphere/source/sf/hipc/sf_hipc_server_manager.cpp +++ b/libraries/libstratosphere/source/sf/hipc/sf_hipc_server_manager.cpp @@ -18,6 +18,7 @@ namespace ams::sf::hipc { + #if AMS_SF_MITM_SUPPORTED Result ServerManagerBase::InstallMitmServerImpl(os::NativeHandle *out_port_handle, sm::ServiceName service_name, ServerManagerBase::MitmQueryFunction query_func) { /* Install the Mitm. */ os::NativeHandle query_handle; @@ -31,6 +32,7 @@ namespace ams::sf::hipc { return ResultSuccess(); } + #endif void ServerManagerBase::RegisterServerSessionToWait(ServerSession *session) { session->m_has_received = false; @@ -79,8 +81,10 @@ namespace ams::sf::hipc { void ServerManagerBase::AddUserMultiWaitHolder(os::MultiWaitHolderType *holder) { const auto user_data_tag = static_cast(os::GetMultiWaitHolderUserData(holder)); AMS_ABORT_UNLESS(user_data_tag != UserDataTag::Server); - AMS_ABORT_UNLESS(user_data_tag != UserDataTag::MitmServer); AMS_ABORT_UNLESS(user_data_tag != UserDataTag::Session); + #if AMS_SF_MITM_SUPPORTED + AMS_ABORT_UNLESS(user_data_tag != UserDataTag::MitmServer); + #endif this->LinkToDeferredList(holder); } @@ -98,6 +102,7 @@ namespace ams::sf::hipc { } } + #if AMS_SF_MITM_SUPPORTED Result ServerManagerBase::ProcessForMitmServer(os::MultiWaitHolderType *holder) { AMS_ABORT_UNLESS(static_cast(os::GetMultiWaitHolderUserData(holder)) == UserDataTag::MitmServer); @@ -107,13 +112,14 @@ namespace ams::sf::hipc { /* Create resources for new session. */ return this->OnNeedsToAccept(server->m_index, server); } + #endif Result ServerManagerBase::ProcessForSession(os::MultiWaitHolderType *holder) { AMS_ABORT_UNLESS(static_cast(os::GetMultiWaitHolderUserData(holder)) == UserDataTag::Session); ServerSession *session = static_cast(holder); - cmif::PointerAndSize tls_message(svc::GetThreadLocalRegion()->message_buffer, hipc::TlsMessageBufferSize); + cmif::PointerAndSize tls_message(hipc::GetMessageBufferOnTls(), hipc::TlsMessageBufferSize); if (this->CanDeferInvokeRequest()) { const cmif::PointerAndSize &saved_message = session->m_saved_message; AMS_ABORT_UNLESS(tls_message.GetSize() == saved_message.GetSize()); @@ -136,12 +142,14 @@ namespace ams::sf::hipc { R_TRY(this->ReceiveRequest(session, tls_message)); session->m_has_received = true; + #if AMS_SF_MITM_SUPPORTED if (this->CanManageMitmServers()) { const cmif::PointerAndSize &saved_message = session->m_saved_message; AMS_ABORT_UNLESS(tls_message.GetSize() == saved_message.GetSize()); std::memcpy(saved_message.GetPointer(), tls_message.GetPointer(), tls_message.GetSize()); } + #endif } R_TRY_CATCH(this->ProcessRequest(session, tls_message)) { @@ -157,11 +165,13 @@ namespace ams::sf::hipc { switch (static_cast(os::GetMultiWaitHolderUserData(holder))) { case UserDataTag::Server: return this->ProcessForServer(holder); + case UserDataTag::Session: + return this->ProcessForSession(holder); + #if AMS_SF_MITM_SUPPORTED case UserDataTag::MitmServer: AMS_ABORT_UNLESS(this->CanManageMitmServers()); return this->ProcessForMitmServer(holder); - case UserDataTag::Session: - return this->ProcessForSession(holder); + #endif AMS_UNREACHABLE_DEFAULT_CASE(); } } diff --git a/libraries/libstratosphere/source/sf/hipc/sf_hipc_server_session_manager.cpp b/libraries/libstratosphere/source/sf/hipc/sf_hipc_server_session_manager.cpp index bf4545b82..64996c5db 100644 --- a/libraries/libstratosphere/source/sf/hipc/sf_hipc_server_session_manager.cpp +++ b/libraries/libstratosphere/source/sf/hipc/sf_hipc_server_session_manager.cpp @@ -19,6 +19,7 @@ namespace ams::sf::hipc { namespace { + #if AMS_SF_MITM_SUPPORTED constexpr inline void PreProcessCommandBufferForMitm(const cmif::ServiceDispatchContext &ctx, const cmif::PointerAndSize &pointer_buffer, uintptr_t cmd_buffer) { /* TODO: Less gross method of editing command buffer? */ if (ctx.request.meta.send_pid) { @@ -36,9 +37,11 @@ namespace ams::sf::hipc { *reinterpret_cast(cmd_buffer + old_recv_list_offset) = hipcMakeRecvStatic(pointer_buffer.GetPointer(), pointer_buffer.GetSize()); } } + #endif } + #if AMS_SF_MITM_SUPPORTED Result ServerSession::ForwardRequest(const cmif::ServiceDispatchContext &ctx) const { AMS_ABORT_UNLESS(ServerManagerBase::CanAnyManageMitmServers()); AMS_ABORT_UNLESS(this->IsMitmSession()); @@ -48,7 +51,7 @@ namespace ams::sf::hipc { AMS_ABORT_UNLESS(m_saved_message.GetSize() == TlsMessageBufferSize); /* Get TLS message buffer. */ - u32 * const message_buffer = svc::GetThreadLocalRegion()->message_buffer; + u32 * const message_buffer = static_cast(hipc::GetMessageBufferOnTls()); /* Copy saved TLS in. */ std::memcpy(message_buffer, m_saved_message.GetPointer(), m_saved_message.GetSize()); @@ -72,6 +75,7 @@ namespace ams::sf::hipc { return ResultSuccess(); } + #endif void ServerSessionManager::DestroySession(ServerSession *session) { /* Destroy object. */ @@ -104,7 +108,12 @@ namespace ams::sf::hipc { Result ServerSessionManager::AcceptSessionImpl(ServerSession *session_memory, os::NativeHandle port_handle, cmif::ServiceObjectHolder &&obj) { /* Create session handle. */ os::NativeHandle session_handle; + #if defined(ATMOSPHERE_OS_HORIZON) R_TRY(svc::AcceptSession(std::addressof(session_handle), port_handle)); + #else + AMS_UNUSED(port_handle); + AMS_ABORT("TODO"); + #endif auto session_guard = SCOPE_GUARD { os::CloseNativeHandle(session_handle); }; @@ -115,6 +124,7 @@ namespace ams::sf::hipc { return ResultSuccess(); } + #if AMS_SF_MITM_SUPPORTED Result ServerSessionManager::RegisterMitmSessionImpl(ServerSession *session_memory, os::NativeHandle mitm_session_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv) { AMS_ABORT_UNLESS(ServerManagerBase::CanAnyManageMitmServers()); @@ -149,6 +159,7 @@ namespace ams::sf::hipc { session_guard.Cancel(); return ResultSuccess(); } + #endif Result ServerSessionManager::RegisterSession(os::NativeHandle session_handle, cmif::ServiceObjectHolder &&obj) { /* We don't actually care about what happens to the session. It'll get linked. */ @@ -162,6 +173,7 @@ namespace ams::sf::hipc { return this->AcceptSession(std::addressof(session_ptr), port_handle, std::forward(obj)); } + #if AMS_SF_MITM_SUPPORTED Result ServerSessionManager::RegisterMitmSession(os::NativeHandle mitm_session_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv) { /* We don't actually care about what happens to the session. It'll get linked. */ ServerSession *session_ptr = nullptr; @@ -173,6 +185,7 @@ namespace ams::sf::hipc { ServerSession *session_ptr = nullptr; return this->AcceptMitmSession(std::addressof(session_ptr), mitm_port_handle, std::forward(obj), std::forward>(fsrv)); } + #endif Result ServerSessionManager::ReceiveRequestImpl(ServerSession *session, const cmif::PointerAndSize &message) { const cmif::PointerAndSize &pointer_buffer = session->m_pointer_buffer; @@ -207,7 +220,7 @@ namespace ams::sf::hipc { namespace { - constexpr ALWAYS_INLINE u32 GetCmifCommandType(const cmif::PointerAndSize &message) { + ALWAYS_INLINE u32 GetCmifCommandType(const cmif::PointerAndSize &message) { HipcHeader hdr = {}; __builtin_memcpy(std::addressof(hdr), message.GetPointer(), sizeof(hdr)); return hdr.type; diff --git a/libraries/libstratosphere/source/sf/sf_default_allocation_policy.cpp b/libraries/libstratosphere/source/sf/sf_default_allocation_policy.cpp index fc3718a7e..e81a75887 100644 --- a/libraries/libstratosphere/source/sf/sf_default_allocation_policy.cpp +++ b/libraries/libstratosphere/source/sf/sf_default_allocation_policy.cpp @@ -89,7 +89,7 @@ namespace ams::sf { return DefaultDeallocate(buffer, size, alignment); } - virtual bool IsEqualImpl(const MemoryResource &resource) const { + virtual bool IsEqualImpl(const MemoryResource &resource) const override { return this == std::addressof(resource); } }; diff --git a/libraries/libstratosphere/source/sm/sm_ams.c b/libraries/libstratosphere/source/sm/sm_ams.os.horizon.c similarity index 98% rename from libraries/libstratosphere/source/sm/sm_ams.c rename to libraries/libstratosphere/source/sm/sm_ams.os.horizon.c index 181838170..b10650481 100644 --- a/libraries/libstratosphere/source/sm/sm_ams.c +++ b/libraries/libstratosphere/source/sm/sm_ams.os.horizon.c @@ -15,10 +15,10 @@ */ #define NX_SERVICE_ASSUME_NON_DOMAIN #include "../service_guard.h" -#include "sm_ams.h" +#include "sm_ams.os.horizon.h" static Result _smAtmosphereCmdHas(bool *out, SmServiceName name, u32 cmd_id) { - u8 tmp; + u8 tmp = 0; Result rc = tipcDispatchInOut(smGetServiceSessionTipc(), cmd_id, name, tmp); if (R_SUCCEEDED(rc) && out) *out = tmp & 1; return rc; diff --git a/libraries/libstratosphere/source/sm/sm_ams.h b/libraries/libstratosphere/source/sm/sm_ams.os.horizon.h similarity index 95% rename from libraries/libstratosphere/source/sm/sm_ams.h rename to libraries/libstratosphere/source/sm/sm_ams.os.horizon.h index f53f98670..778b07a11 100644 --- a/libraries/libstratosphere/source/sm/sm_ams.h +++ b/libraries/libstratosphere/source/sm/sm_ams.os.horizon.h @@ -5,6 +5,9 @@ * @copyright libnx Authors */ #pragma once + +#if defined(ATMOSPHERE_OS_HORIZON) + #include #ifdef __cplusplus @@ -31,4 +34,6 @@ Result smAtmosphereMitmAcknowledgeSession(Service *srv_out, void *info_out, SmSe #ifdef __cplusplus } +#endif + #endif \ No newline at end of file diff --git a/libraries/libstratosphere/source/sm/sm_api.cpp b/libraries/libstratosphere/source/sm/sm_api.cpp index bd3b66f29..47cd30f90 100644 --- a/libraries/libstratosphere/source/sm/sm_api.cpp +++ b/libraries/libstratosphere/source/sm/sm_api.cpp @@ -18,6 +18,7 @@ namespace ams::sm { + #if defined(ATMOSPHERE_OS_HORIZON) namespace { constinit int g_ref_count = 0; @@ -45,8 +46,8 @@ namespace ams::sm { } /* Ordinary SM API. */ - Result GetService(Service *out, ServiceName name) { - return smGetServiceWrapper(out, impl::ConvertName(name)); + Result GetServiceHandle(os::NativeHandle *out, ServiceName name) { + return smGetServiceOriginal(out, impl::ConvertName(name)); } Result RegisterService(os::NativeHandle *out, ServiceName name, size_t max_sessions, bool is_light) { @@ -65,5 +66,41 @@ namespace ams::sm { Result WaitService(ServiceName name) { return smAtmosphereWaitService(impl::ConvertName(name)); } + #else + Result Initialize() { + R_SUCCEED(); + } + + Result Finalize() { + R_SUCCEED(); + } + + /* Ordinary SM API. */ + Result GetServiceHandle(os::NativeHandle *out, ServiceName name) { + AMS_UNUSED(out, name); + AMS_ABORT("TODO?"); + } + + Result RegisterService(os::NativeHandle *out, ServiceName name, size_t max_sessions, bool is_light) { + AMS_UNUSED(out, name, max_sessions, is_light); + AMS_ABORT("TODO?"); + } + + Result UnregisterService(ServiceName name) { + AMS_UNUSED(name); + AMS_ABORT("TODO?"); + } + + /* Atmosphere extensions. */ + Result HasService(bool *out, ServiceName name) { + AMS_UNUSED(out, name); + AMS_ABORT("TODO?"); + } + + Result WaitService(ServiceName name) { + AMS_UNUSED(name); + AMS_ABORT("TODO?"); + } + #endif } diff --git a/libraries/libstratosphere/source/sm/sm_manager_api.cpp b/libraries/libstratosphere/source/sm/sm_manager_api.cpp index 80372381c..3a74fa1f6 100644 --- a/libraries/libstratosphere/source/sm/sm_manager_api.cpp +++ b/libraries/libstratosphere/source/sm/sm_manager_api.cpp @@ -15,10 +15,14 @@ */ #include #include "sm_utils.hpp" -#include "smm_ams.h" + +#if defined(ATMOSPHERE_OS_HORIZON) +#include "smm_ams.os.horizon.h" +#endif namespace ams::sm::manager { + #if defined(ATMOSPHERE_OS_HORIZON) /* Manager API. */ Result RegisterProcess(os::ProcessId process_id, ncm::ProgramId program_id, cfg::OverrideStatus status, const void *acid, size_t acid_size, const void *aci, size_t aci_size) { static_assert(sizeof(status) == sizeof(CfgOverrideStatus), "CfgOverrideStatus definition"); @@ -37,5 +41,6 @@ namespace ams::sm::manager { Result HasMitm(bool *out, ServiceName name) { return smManagerAtmosphereHasMitm(out, impl::ConvertName(name)); } + #endif } diff --git a/libraries/libstratosphere/source/sm/sm_mitm_api.cpp b/libraries/libstratosphere/source/sm/sm_mitm_api.cpp index 82e392f1d..fa31d0ac8 100644 --- a/libraries/libstratosphere/source/sm/sm_mitm_api.cpp +++ b/libraries/libstratosphere/source/sm/sm_mitm_api.cpp @@ -18,6 +18,8 @@ namespace ams::sm::mitm { + #if defined(ATMOSPHERE_OS_HORIZON) + #if AMS_SF_MITM_SUPPORTED /* Mitm API. */ Result InstallMitm(os::NativeHandle *out_port, os::NativeHandle *out_query, ServiceName name) { return impl::DoWithPerThreadSession([&](TipcService *fwd) { @@ -50,5 +52,7 @@ namespace ams::sm::mitm { Result WaitMitm(ServiceName name) { return smAtmosphereWaitMitm(impl::ConvertName(name)); } + #endif + #endif } diff --git a/libraries/libstratosphere/source/sm/sm_utils.hpp b/libraries/libstratosphere/source/sm/sm_utils.hpp index a7d6f6cad..2edc9830b 100644 --- a/libraries/libstratosphere/source/sm/sm_utils.hpp +++ b/libraries/libstratosphere/source/sm/sm_utils.hpp @@ -16,10 +16,14 @@ #pragma once #include -#include "sm_ams.h" + +#if defined(ATMOSPHERE_OS_HORIZON) +#include "sm_ams.os.horizon.h" +#endif namespace ams::sm::impl { + #if defined(ATMOSPHERE_OS_HORIZON) /* Utilities. */ os::SdkRecursiveMutex &GetMitmAcknowledgementSessionMutex(); os::SdkRecursiveMutex &GetPerThreadSessionMutex(); @@ -52,5 +56,6 @@ namespace ams::sm::impl { static_assert(sizeof(SmServiceName) == sizeof(sm::ServiceName)); return std::bit_cast(name); } + #endif } diff --git a/libraries/libstratosphere/source/sm/smm_ams.c b/libraries/libstratosphere/source/sm/smm_ams.os.horizon.c similarity index 98% rename from libraries/libstratosphere/source/sm/smm_ams.c rename to libraries/libstratosphere/source/sm/smm_ams.os.horizon.c index 6e8e7475f..1238a5015 100644 --- a/libraries/libstratosphere/source/sm/smm_ams.c +++ b/libraries/libstratosphere/source/sm/smm_ams.os.horizon.c @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#include "smm_ams.h" +#include "smm_ams.os.horizon.h" Result smManagerAtmosphereEndInitialDefers(void) { return tipcDispatch(smManagerTipcGetServiceSession(), 65000); diff --git a/libraries/libstratosphere/source/sm/smm_ams.h b/libraries/libstratosphere/source/sm/smm_ams.os.horizon.h similarity index 93% rename from libraries/libstratosphere/source/sm/smm_ams.h rename to libraries/libstratosphere/source/sm/smm_ams.os.horizon.h index 0f9c1d127..51a66853f 100644 --- a/libraries/libstratosphere/source/sm/smm_ams.h +++ b/libraries/libstratosphere/source/sm/smm_ams.os.horizon.h @@ -5,6 +5,9 @@ * @copyright libnx Authors */ #pragma once + +#if defined(ATMOSPHERE_OS_HORIZON) + #include #ifdef __cplusplus @@ -22,4 +25,6 @@ Result smManagerAtmosphereHasMitm(bool *out, SmServiceName name); #ifdef __cplusplus } +#endif + #endif \ No newline at end of file diff --git a/libraries/libstratosphere/source/spl/impl/spl_api_impl.cpp b/libraries/libstratosphere/source/spl/impl/spl_api_impl.cpp index a4183c389..91a27718f 100644 --- a/libraries/libstratosphere/source/spl/impl/spl_api_impl.cpp +++ b/libraries/libstratosphere/source/spl/impl/spl_api_impl.cpp @@ -64,7 +64,7 @@ namespace ams::spl::impl { /* KeySlot management. */ constinit AesKeySlotCache g_aes_keyslot_cache; - constinit util::optional g_aes_keyslot_cache_entry[PhysicalAesKeySlotCount]; + constinit util::optional g_aes_keyslot_cache_entry[PhysicalAesKeySlotCount] = {}; constinit bool g_is_physical_keyslot_allowed = false; constinit bool g_is_modern_device_unique_data = true; @@ -84,7 +84,7 @@ namespace ams::spl::impl { constexpr inline s32 MakeVirtualAesKeySlot(s32 index) { const s32 virt_slot = index + AesKeySlotMin; - AMS_ASSERT(IsVirtualKeySlot(virt_slot)); + AMS_ASSERT(IsVirtualAesKeySlot(virt_slot)); return virt_slot; } @@ -108,8 +108,8 @@ namespace ams::spl::impl { }; constinit bool g_is_aes_keyslot_allocated[AesKeySlotCount]; - constinit AesKeySlotContents g_aes_keyslot_contents[AesKeySlotCount]; - constinit AesKeySlotContents g_aes_physical_keyslot_contents_for_backwards_compatibility[PhysicalAesKeySlotCount]; + constinit AesKeySlotContents g_aes_keyslot_contents[AesKeySlotCount] = {}; + constinit AesKeySlotContents g_aes_physical_keyslot_contents_for_backwards_compatibility[PhysicalAesKeySlotCount] = {}; void ClearPhysicalAesKeySlot(s32 keyslot) { AMS_ASSERT(IsPhysicalAesKeySlot(keyslot)); @@ -204,27 +204,38 @@ namespace ams::spl::impl { /* Global variables. */ alignas(os::MemoryPageSize) constinit u8 g_work_buffer[WorkBufferSizeMax]; - constinit util::TypedStorage g_drbg; + constinit util::TypedStorage g_drbg = {}; constinit os::InterruptName g_interrupt_name; - constinit os::InterruptEventType g_interrupt; - constinit util::TypedStorage g_aes_keyslot_available_event; + constinit os::InterruptEventType g_interrupt = {}; + constinit util::TypedStorage g_aes_keyslot_available_event = {}; constinit os::SdkMutex g_operation_lock; - constinit dd::DeviceAddressSpaceType g_device_address_space; + constinit dd::DeviceAddressSpaceType g_device_address_space = {}; + + #if defined(ATMOSPHERE_OS_HORIZON) constinit u32 g_work_buffer_mapped_address; + #else + constinit uintptr_t g_work_buffer_mapped_address; + #endif constinit BootReasonValue g_boot_reason; constinit bool g_is_boot_reason_initialized; /* Initialization functionality. */ void InitializeAsyncOperation() { + #if defined(ATMOSPHERE_OS_HORIZON) u64 interrupt_number; impl::GetConfig(std::addressof(interrupt_number), ConfigItem::SecurityEngineInterruptNumber); g_interrupt_name = static_cast(interrupt_number); os::InitializeInterruptEvent(std::addressof(g_interrupt), g_interrupt_name, os::EventClearMode_AutoClear); + #else + AMS_UNUSED(g_interrupt_name); + AMS_ABORT("TODO: How should this work?"); + #endif } void InitializeDeviceAddressSpace() { + #if defined(ATMOSPHERE_OS_HORIZON) /* Create device address space. */ R_ABORT_UNLESS(dd::CreateDeviceAddressSpace(std::addressof(g_device_address_space), 0, (1ul << 32))); @@ -236,6 +247,11 @@ namespace ams::spl::impl { g_work_buffer_mapped_address = WorkBufferBase + (work_buffer_address % DeviceAddressSpaceAlign); R_ABORT_UNLESS(dd::MapDeviceAddressSpaceAligned(std::addressof(g_device_address_space), dd::GetCurrentProcessHandle(), work_buffer_address, dd::DeviceAddressSpaceMemoryRegionAlignment, g_work_buffer_mapped_address, dd::MemoryPermission_ReadWrite)); + #else + /* Just set the work buffer address directly. */ + AMS_UNUSED(WorkBufferBase, g_device_address_space); + g_work_buffer_mapped_address = reinterpret_cast(g_work_buffer); + #endif } void InitializeCtrDrbg() { diff --git a/libraries/libstratosphere/source/spl/impl/spl_device_address_mapper.hpp b/libraries/libstratosphere/source/spl/impl/spl_device_address_mapper.hpp index 606b77b03..90aba8f27 100644 --- a/libraries/libstratosphere/source/spl/impl/spl_device_address_mapper.hpp +++ b/libraries/libstratosphere/source/spl/impl/spl_device_address_mapper.hpp @@ -28,11 +28,17 @@ namespace ams::spl::impl { DeviceAddressMapper(dd::DeviceAddressSpaceType *das, u64 process_address, size_t size, dd::DeviceVirtualAddress device_address, dd::MemoryPermission permission) : m_das(das), m_process_address(process_address), m_size(size), m_device_address(device_address) { + #if defined(ATMOSPHERE_OS_HORIZON) R_ABORT_UNLESS(dd::MapDeviceAddressSpaceAligned(m_das, dd::GetCurrentProcessHandle(), m_process_address, m_size, m_device_address, permission)); + #else + AMS_UNUSED(permission); + #endif } ~DeviceAddressMapper() { + #if defined(ATMOSPHERE_OS_HORIZON) dd::UnmapDeviceAddressSpace(m_das, dd::GetCurrentProcessHandle(), m_process_address, m_size, m_device_address); + #endif } }; diff --git a/libraries/libstratosphere/source/spl/smc/spl_secure_monitor_api.cpp b/libraries/libstratosphere/source/spl/smc/spl_secure_monitor_api.os.horizon.cpp similarity index 100% rename from libraries/libstratosphere/source/spl/smc/spl_secure_monitor_api.cpp rename to libraries/libstratosphere/source/spl/smc/spl_secure_monitor_api.os.horizon.cpp diff --git a/libraries/libstratosphere/source/spl/spl_api.cpp b/libraries/libstratosphere/source/spl/spl_api.cpp index e296579c1..525ccd081 100644 --- a/libraries/libstratosphere/source/spl/spl_api.cpp +++ b/libraries/libstratosphere/source/spl/spl_api.cpp @@ -17,6 +17,9 @@ namespace ams::spl { + /* BIG TODO: How to deal with this? */ + #if defined(ATMOSPHERE_OS_HORIZON) + namespace { enum class InitializeMode { @@ -295,4 +298,6 @@ namespace ams::spl { } } + #endif + } diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_api.cpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_api.cpp index f08498037..1c5c3bc59 100644 --- a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_api.cpp +++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_api.cpp @@ -50,19 +50,19 @@ namespace ams::sprofile::srv { using ServerManager = sf::hipc::ServerManager; - constinit util::TypedStorage g_profile_manager; + constinit util::TypedStorage g_profile_manager = {}; - constinit util::TypedStorage> g_bg_service_object; - constinit util::TypedStorage> g_sp_service_object; + constinit util::TypedStorage> g_bg_service_object = {}; + constinit util::TypedStorage> g_sp_service_object = {}; - constinit util::TypedStorage g_server_manager; + constinit util::TypedStorage g_server_manager = {}; alignas(os::ThreadStackAlignment) constinit u8 g_ipc_thread_stack[0x3000]; constinit u8 g_heap[16_KB]; - constinit os::ThreadType g_ipc_thread; + constinit os::ThreadType g_ipc_thread = {}; - constinit lmem::HeapHandle g_heap_handle; + constinit lmem::HeapHandle g_heap_handle = nullptr; constinit sf::ExpHeapMemoryResource g_sf_memory_resource; void IpcServerThreadFunction(void *) { diff --git a/libraries/libstratosphere/source/time/time_api.cpp b/libraries/libstratosphere/source/time/time_api.cpp index 69b91366e..737deaa70 100644 --- a/libraries/libstratosphere/source/time/time_api.cpp +++ b/libraries/libstratosphere/source/time/time_api.cpp @@ -15,11 +15,13 @@ */ #include +#if defined(ATMOSPHERE_OS_HORIZON) extern "C" { extern TimeServiceType __nx_time_service_type; } +#endif namespace ams::time { @@ -48,6 +50,7 @@ namespace ams::time { return ResultSuccess(); } + #if defined(ATMOSPHERE_OS_HORIZON) switch (mode) { case InitializeMode_Normal: __nx_time_service_type = ::TimeServiceType_User; break; case InitializeMode_Menu: __nx_time_service_type = ::TimeServiceType_Menu; break; @@ -58,6 +61,9 @@ namespace ams::time { } R_TRY(::timeInitialize()); + #else + AMS_ABORT("TODO"); + #endif g_initialize_count++; g_initialize_mode = mode; @@ -87,7 +93,11 @@ namespace ams::time { if (g_initialize_count > 0) { if ((--g_initialize_count) == 0) { + #if defined(ATMOSPHERE_OS_HORIZON) ::timeExit(); + #else + AMS_ABORT("TODO"); + #endif g_initialize_mode = InitializeMode_None; } } diff --git a/libraries/libstratosphere/source/time/time_standard_network_system_clock.cpp b/libraries/libstratosphere/source/time/time_standard_network_system_clock.cpp index dad2cdcb2..295a2f6e0 100644 --- a/libraries/libstratosphere/source/time/time_standard_network_system_clock.cpp +++ b/libraries/libstratosphere/source/time/time_standard_network_system_clock.cpp @@ -18,8 +18,13 @@ namespace ams::time { Result StandardNetworkSystemClock::GetCurrentTime(PosixTime *out) { + #if defined(ATMOSPHERE_OS_HORIZON) static_assert(sizeof(*out) == sizeof(u64)); return ::timeGetCurrentTime(::TimeType_NetworkSystemClock, reinterpret_cast(out)); + #else + AMS_UNUSED(out); + AMS_ABORT("TODO"); + #endif } StandardNetworkSystemClock::time_point StandardNetworkSystemClock::now() { diff --git a/libraries/libstratosphere/source/time/time_standard_steady_clock.cpp b/libraries/libstratosphere/source/time/time_standard_steady_clock.cpp index b2e04322a..4e8496a37 100644 --- a/libraries/libstratosphere/source/time/time_standard_steady_clock.cpp +++ b/libraries/libstratosphere/source/time/time_standard_steady_clock.cpp @@ -18,14 +18,26 @@ namespace ams::time { Result GetStandardSteadyClockCurrentTimePoint(SteadyClockTimePoint *out) { + #if defined(ATMOSPHERE_OS_HORIZON) static_assert(sizeof(*out) == sizeof(::TimeSteadyClockTimePoint)); return ::timeGetStandardSteadyClockTimePoint(reinterpret_cast<::TimeSteadyClockTimePoint *>(out)); + #else + AMS_UNUSED(out); + AMS_ABORT("TODO"); + #endif } TimeSpan GetStandardSteadyClockInternalOffset() { - static_assert(sizeof(TimeSpanType) == sizeof(s64)); TimeSpanType offset; + + #if defined(ATMOSPHERE_OS_HORIZON) + static_assert(sizeof(TimeSpanType) == sizeof(s64)); R_ABORT_UNLESS(::timeGetStandardSteadyClockInternalOffset(reinterpret_cast(std::addressof(offset)))); + #else + AMS_UNUSED(offset); + AMS_ABORT("TODO"); + #endif + return offset; } diff --git a/libraries/libstratosphere/source/time/time_standard_user_system_clock.cpp b/libraries/libstratosphere/source/time/time_standard_user_system_clock.cpp index 6bd641f28..0663585bd 100644 --- a/libraries/libstratosphere/source/time/time_standard_user_system_clock.cpp +++ b/libraries/libstratosphere/source/time/time_standard_user_system_clock.cpp @@ -18,8 +18,13 @@ namespace ams::time { Result StandardUserSystemClock::GetCurrentTime(PosixTime *out) { + #if defined(ATMOSPHERE_OS_HORIZON) static_assert(sizeof(*out) == sizeof(u64)); return ::timeGetCurrentTime(::TimeType_UserSystemClock, reinterpret_cast(out)); + #else + AMS_UNUSED(out); + AMS_ABORT("TODO"); + #endif } StandardUserSystemClock::time_point StandardUserSystemClock::now() { diff --git a/libraries/libstratosphere/source/updater/updater_api.cpp b/libraries/libstratosphere/source/updater/updater_api.cpp index 98d600655..a34fbcbf7 100644 --- a/libraries/libstratosphere/source/updater/updater_api.cpp +++ b/libraries/libstratosphere/source/updater/updater_api.cpp @@ -297,6 +297,7 @@ namespace ams::updater { } /* Only preserve autorcm if on a unit with unpatched rcm bug. */ + #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) if (HasAutoRcmPreserve(boot_image_update_type) && !exosphere::IsRcmBugPatched()) { R_TRY(boot0_accessor.PreserveAutoRcm(bct, work, Boot0Partition::BctNormalSub)); R_TRY(boot0_accessor.Write(bct, BctSize, Boot0Partition::BctNormalSub)); @@ -305,6 +306,9 @@ namespace ams::updater { R_TRY(boot0_accessor.Write(bct, BctSize, Boot0Partition::BctNormalMain)); } } else { + #else + { + #endif R_TRY(boot0_accessor.Write(bct, BctSize, Boot0Partition::BctNormalSub)); if (!custom_public_key) { R_TRY(boot0_accessor.Write(bct, BctSize, Boot0Partition::BctNormalMain)); @@ -366,6 +370,7 @@ namespace ams::updater { R_TRY(boot0_accessor.UpdateEks(bct, work)); } /* Only preserve autorcm if on a unit with unpatched rcm bug. */ + #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) if (HasAutoRcmPreserve(boot_image_update_type) && !exosphere::IsRcmBugPatched()) { R_TRY(boot0_accessor.PreserveAutoRcm(bct, work, Boot0Partition::BctSafeSub)); R_TRY(boot0_accessor.Write(bct, BctSize, Boot0Partition::BctSafeSub)); @@ -374,6 +379,9 @@ namespace ams::updater { R_TRY(boot0_accessor.Write(bct, BctSize, Boot0Partition::BctSafeMain)); } } else { + #else + { + #endif R_TRY(boot0_accessor.Write(bct, BctSize, Boot0Partition::BctSafeSub)); if (!custom_public_key) { R_TRY(boot0_accessor.Write(bct, BctSize, Boot0Partition::BctSafeMain)); @@ -428,7 +436,7 @@ namespace ams::updater { } u8 file_hash[crypto::Sha256Generator::HashSize]; - crypto::GenerateSha256Hash(file_hash, sizeof(file_hash), bct, BctSize); + crypto::GenerateSha256(file_hash, sizeof(file_hash), bct, BctSize); return CompareHash(file_hash, stored_hash, sizeof(file_hash)); } diff --git a/libraries/libstratosphere/source/updater/updater_bis_management.cpp b/libraries/libstratosphere/source/updater/updater_bis_management.cpp index 1cfe0f639..0ed210d5c 100644 --- a/libraries/libstratosphere/source/updater/updater_bis_management.cpp +++ b/libraries/libstratosphere/source/updater/updater_bis_management.cpp @@ -102,7 +102,7 @@ namespace ams::updater { size_t written = 0; while (written < size) { - size_t cur_write_size = std::min(work_buffer_size, size - written); + size_t cur_write_size = std::min(work_buffer_size, size - written); R_TRY(this->Write(offset + written, work_buffer, cur_write_size)); written += cur_write_size; } @@ -118,8 +118,8 @@ namespace ams::updater { size_t total_read = 0; while (total_read < hash_size) { - size_t cur_read_size = std::min(work_buffer_size, size - total_read); - size_t cur_update_size = std::min(cur_read_size, hash_size - total_read); + size_t cur_read_size = std::min(work_buffer_size, size - total_read); + size_t cur_update_size = std::min(cur_read_size, hash_size - total_read); R_TRY(this->Read(work_buffer, cur_read_size, offset + total_read)); generator.Update(work_buffer, cur_update_size); diff --git a/libraries/libstratosphere/source/usb/usb_device.cpp b/libraries/libstratosphere/source/usb/usb_device.cpp index ddfcd0142..61072e05e 100644 --- a/libraries/libstratosphere/source/usb/usb_device.cpp +++ b/libraries/libstratosphere/source/usb/usb_device.cpp @@ -36,9 +36,12 @@ namespace ams::usb { /* Connect to usb:ds. */ /* NOTE: Here, Nintendo does m_domain.InitializeByDomain<...>(...); m_domain.SetSessionCount(1); */ { - Service srv; - R_TRY(sm::GetService(std::addressof(srv), sm::ServiceName::Encode("usb:ds"))); + #if defined(ATMOSPHERE_OS_HORIZON) + os::NativeHandle h; + R_TRY(sm::GetServiceHandle(std::addressof(h), sm::ServiceName::Encode("usb:ds"))); + ::Service srv; + ::serviceCreate(&srv, h); R_ABORT_UNLESS(serviceConvertToDomain(std::addressof(srv))); using Allocator = decltype(m_allocator); @@ -51,6 +54,9 @@ namespace ams::usb { } else { m_ds_service = ObjectFactory::CreateSharedEmplaced(std::addressof(m_allocator), srv, std::addressof(m_allocator)); } + #else + AMS_ABORT("TODO"); + #endif } /* Bind the client process. */ diff --git a/libraries/libstratosphere/source/usb/usb_remote_ds_endpoint.cpp b/libraries/libstratosphere/source/usb/usb_remote_ds_endpoint.cpp index 65f73c17d..f9bfa9bec 100644 --- a/libraries/libstratosphere/source/usb/usb_remote_ds_endpoint.cpp +++ b/libraries/libstratosphere/source/usb/usb_remote_ds_endpoint.cpp @@ -18,6 +18,7 @@ namespace ams::usb { + #if defined(ATMOSPHERE_OS_HORIZON) Result RemoteDsEndpoint::PostBufferAsync(sf::Out out_urb_id, u64 address, u32 size) { const struct { u32 size; @@ -62,5 +63,6 @@ namespace ams::usb { serviceAssumeDomain(std::addressof(m_srv)); return serviceDispatchIn(std::addressof(m_srv), 5, in); } + #endif } diff --git a/libraries/libstratosphere/source/usb/usb_remote_ds_endpoint.hpp b/libraries/libstratosphere/source/usb/usb_remote_ds_endpoint.hpp index bd95914fc..88e94f23e 100644 --- a/libraries/libstratosphere/source/usb/usb_remote_ds_endpoint.hpp +++ b/libraries/libstratosphere/source/usb/usb_remote_ds_endpoint.hpp @@ -18,6 +18,7 @@ namespace ams::usb { + #if defined(ATMOSPHERE_OS_HORIZON) class RemoteDsEndpoint { private: Service m_srv; @@ -33,5 +34,6 @@ namespace ams::usb { Result SetZlt(bool zlt); }; static_assert(ds::IsIDsEndpoint); + #endif } diff --git a/libraries/libstratosphere/source/usb/usb_remote_ds_interface.cpp b/libraries/libstratosphere/source/usb/usb_remote_ds_interface.cpp index ac26a1ce2..bd89e4491 100644 --- a/libraries/libstratosphere/source/usb/usb_remote_ds_interface.cpp +++ b/libraries/libstratosphere/source/usb/usb_remote_ds_interface.cpp @@ -19,6 +19,7 @@ namespace ams::usb { + #if defined(ATMOSPHERE_OS_HORIZON) Result RemoteDsInterface::RegisterEndpoint(u8 endpoint_address, sf::Out> out) { Service srv; @@ -149,6 +150,7 @@ namespace ams::usb { serviceAssumeDomain(std::addressof(m_srv)); return serviceDispatch(std::addressof(m_srv), 3); } + #endif } diff --git a/libraries/libstratosphere/source/usb/usb_remote_ds_interface.hpp b/libraries/libstratosphere/source/usb/usb_remote_ds_interface.hpp index 2ab730739..fd767be05 100644 --- a/libraries/libstratosphere/source/usb/usb_remote_ds_interface.hpp +++ b/libraries/libstratosphere/source/usb/usb_remote_ds_interface.hpp @@ -18,6 +18,7 @@ namespace ams::usb { + #if defined(ATMOSPHERE_OS_HORIZON) class RemoteDsInterface { private: using Allocator = sf::ExpHeapAllocator; @@ -44,5 +45,6 @@ namespace ams::usb { Result Disable(); }; static_assert(ds::IsIDsInterface); + #endif } diff --git a/libraries/libstratosphere/source/usb/usb_remote_ds_root_service.cpp b/libraries/libstratosphere/source/usb/usb_remote_ds_root_service.cpp index 9d9093cd8..58c33a001 100644 --- a/libraries/libstratosphere/source/usb/usb_remote_ds_root_service.cpp +++ b/libraries/libstratosphere/source/usb/usb_remote_ds_root_service.cpp @@ -19,6 +19,7 @@ namespace ams::usb { + #if defined(ATMOSPHERE_OS_HORIZON) Result RemoteDsRootService::GetService(sf::Out> out) { Service srv; @@ -29,5 +30,6 @@ namespace ams::usb { return ResultSuccess(); } + #endif } diff --git a/libraries/libstratosphere/source/usb/usb_remote_ds_root_service.hpp b/libraries/libstratosphere/source/usb/usb_remote_ds_root_service.hpp index 78d3eb17b..5cd0aee28 100644 --- a/libraries/libstratosphere/source/usb/usb_remote_ds_root_service.hpp +++ b/libraries/libstratosphere/source/usb/usb_remote_ds_root_service.hpp @@ -18,6 +18,7 @@ namespace ams::usb { + #if defined(ATMOSPHERE_OS_HORIZON) class RemoteDsRootService { private: using Allocator = sf::ExpHeapAllocator; @@ -32,5 +33,6 @@ namespace ams::usb { Result GetService(sf::Out> out); }; static_assert(ds::IsIDsRootService); + #endif } diff --git a/libraries/libstratosphere/source/usb/usb_remote_ds_service.cpp b/libraries/libstratosphere/source/usb/usb_remote_ds_service.cpp index 532424a09..efab02ac3 100644 --- a/libraries/libstratosphere/source/usb/usb_remote_ds_service.cpp +++ b/libraries/libstratosphere/source/usb/usb_remote_ds_service.cpp @@ -19,6 +19,7 @@ namespace ams::usb { + #if defined(ATMOSPHERE_OS_HORIZON) Result RemoteDsService::Bind(usb::ComplexId complex_id, sf::CopyHandle &&process_h) { if (hos::GetVersion() >= hos::Version_11_0_0) { serviceAssumeDomain(std::addressof(m_srv)); @@ -115,5 +116,6 @@ namespace ams::usb { serviceAssumeDomain(std::addressof(m_srv)); return serviceDispatch(std::addressof(m_srv), hos::GetVersion() >= hos::Version_11_0_0 ? 10 : 11); } + #endif } diff --git a/libraries/libstratosphere/source/usb/usb_remote_ds_service.hpp b/libraries/libstratosphere/source/usb/usb_remote_ds_service.hpp index 663d36b49..35102529a 100644 --- a/libraries/libstratosphere/source/usb/usb_remote_ds_service.hpp +++ b/libraries/libstratosphere/source/usb/usb_remote_ds_service.hpp @@ -18,6 +18,7 @@ namespace ams::usb { + #if defined(ATMOSPHERE_OS_HORIZON) class RemoteDsService { private: using Allocator = sf::ExpHeapAllocator; @@ -42,5 +43,6 @@ namespace ams::usb { Result Disable(); }; static_assert(ds::IsIDsService); + #endif } diff --git a/libraries/libstratosphere/source/util/ini.c b/libraries/libstratosphere/source/util/ini.c index 501e9224f..426430c9b 100644 --- a/libraries/libstratosphere/source/util/ini.c +++ b/libraries/libstratosphere/source/util/ini.c @@ -70,10 +70,7 @@ static char* find_chars_or_comment(const char* s, const char* chars) /* Version of strncpy that ensures dest (size bytes) is null-terminated. */ static char* strncpy0(char* dest, const char* src, size_t size) { -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wstringop-truncation" strncpy(dest, src, size - 1); -#pragma GCC diagnostic pop dest[size - 1] = '\0'; return dest; } diff --git a/libraries/libstratosphere/source/wec/wec_api.cpp b/libraries/libstratosphere/source/wec/wec_api.cpp index c23b14f85..36b06396f 100644 --- a/libraries/libstratosphere/source/wec/wec_api.cpp +++ b/libraries/libstratosphere/source/wec/wec_api.cpp @@ -15,10 +15,10 @@ */ #include -/* TODO: How much of this should be namespaced under BOARD_NINTENDO_NX? */ - namespace ams::wec { + /* TODO: How much of this should be namespaced under BOARD_NINTENDO_NX? */ + #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) namespace { constexpr inline dd::PhysicalAddress ApbdevPmc = 0x7000E400; @@ -108,5 +108,6 @@ namespace ams::wec { UpdateControlBit(ApbdevPmc + offset, (1u << index), en); } } + #endif } diff --git a/libraries/libvapours/include/vapours/allocator.hpp b/libraries/libvapours/include/vapours/allocator.hpp index 01f0d384e..b5d294bfe 100644 --- a/libraries/libvapours/include/vapours/allocator.hpp +++ b/libraries/libvapours/include/vapours/allocator.hpp @@ -49,6 +49,8 @@ namespace ams { ALWAYS_INLINE bool IsEqual(const MemoryResource &resource) const { return this->IsEqualImpl(resource); } + public: + constexpr ~MemoryResource() = default; protected: virtual void *AllocateImpl(size_t size, size_t alignment) = 0; virtual void DeallocateImpl(void *buffer, size_t size, size_t alignment) = 0; diff --git a/libraries/libvapours/include/vapours/assert.hpp b/libraries/libvapours/include/vapours/assert.hpp index fa5b6ff50..836013437 100644 --- a/libraries/libvapours/include/vapours/assert.hpp +++ b/libraries/libvapours/include/vapours/assert.hpp @@ -18,12 +18,12 @@ namespace ams::diag { - NORETURN NOINLINE void AssertionFailureImpl(const char *file, int line, const char *func, const char *expr, u64 value, const char *format, ...) __attribute__((format(printf, 6, 7))); - NORETURN NOINLINE void AssertionFailureImpl(const char *file, int line, const char *func, const char *expr, u64 value); + NORETURN void AssertionFailureImpl(const char *file, int line, const char *func, const char *expr, u64 value, const char *format, ...) __attribute__((format(printf, 6, 7))); + NORETURN void AssertionFailureImpl(const char *file, int line, const char *func, const char *expr, u64 value); - NORETURN NOINLINE void AbortImpl(const char *file, int line, const char *func, const char *expr, u64 value, const char *format, ...) __attribute__((format(printf, 6, 7))); - NORETURN NOINLINE void AbortImpl(const char *file, int line, const char *func, const char *expr, u64 value); - NORETURN NOINLINE void AbortImpl(); + NORETURN void AbortImpl(const char *file, int line, const char *func, const char *expr, u64 value, const char *format, ...) __attribute__((format(printf, 6, 7))); + NORETURN void AbortImpl(const char *file, int line, const char *func, const char *expr, u64 value); + NORETURN void AbortImpl(); } @@ -36,12 +36,16 @@ namespace ams::diag { #endif #ifdef AMS_ENABLE_ASSERTIONS -#define AMS_ASSERT_IMPL(expr, ...) \ - ({ \ - if (const bool __tmp_ams_assert_val = static_cast(expr); AMS_UNLIKELY(!__tmp_ams_assert_val)) { \ - AMS_CALL_ASSERT_FAIL_IMPL(#expr, ## __VA_ARGS__); \ - } \ - }) +#define AMS_ASSERT_IMPL(expr, ...) \ + { \ + if (std::is_constant_evaluated()) { \ + AMS_ASSUME(static_cast(expr)); \ + } else { \ + if (const bool __tmp_ams_assert_val = static_cast(expr); (!__tmp_ams_assert_val)) { \ + AMS_CALL_ASSERT_FAIL_IMPL(#expr, ## __VA_ARGS__); \ + } \ + } \ + } #elif defined(AMS_PRESERVE_ASSERTION_EXPRESSIONS) #define AMS_ASSERT_IMPL(expr, ...) AMS_UNUSED(expr, ## __VA_ARGS__) #else @@ -62,9 +66,13 @@ namespace ams::diag { #define AMS_ABORT(...) AMS_CALL_ABORT_IMPL("", ## __VA_ARGS__) -#define AMS_ABORT_UNLESS(expr, ...) \ - ({ \ - if (const bool __tmp_ams_assert_val = static_cast(expr); AMS_UNLIKELY(!__tmp_ams_assert_val)) { \ - AMS_CALL_ABORT_IMPL(#expr, ##__VA_ARGS__); \ - } \ - }) +#define AMS_ABORT_UNLESS(expr, ...) \ + { \ + if (std::is_constant_evaluated()) { \ + AMS_ASSUME(static_cast(expr)); \ + } else { \ + if (const bool __tmp_ams_assert_val = static_cast(expr); AMS_UNLIKELY(!__tmp_ams_assert_val)) { \ + AMS_CALL_ABORT_IMPL(#expr, ##__VA_ARGS__); \ + } \ + } \ + } diff --git a/libraries/libvapours/include/vapours/common.hpp b/libraries/libvapours/include/vapours/common.hpp index a6c078981..7fcc1daa6 100644 --- a/libraries/libvapours/include/vapours/common.hpp +++ b/libraries/libvapours/include/vapours/common.hpp @@ -16,6 +16,7 @@ #pragma once #include #include +#include #if defined(AMS_FORCE_DISABLE_DETAILED_ASSERTIONS) && defined(AMS_FORCE_ENABLE_DETAILED_ASSERTIONS) #error "Invalid detailed assertions state" diff --git a/libraries/libvapours/include/vapours/compiler.hpp b/libraries/libvapours/include/vapours/compiler.hpp new file mode 100644 index 000000000..90efa405a --- /dev/null +++ b/libraries/libvapours/include/vapours/compiler.hpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) 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 + +#if defined(ATMOSPHERE_COMPILER_CLANG) +#include +#elif defined(ATMOSPHERE_COMPILER_GCC) +#include +#endif diff --git a/libraries/libvapours/include/vapours/crypto.hpp b/libraries/libvapours/include/vapours/crypto.hpp index ffc5a5ac7..db768d96c 100644 --- a/libraries/libvapours/include/vapours/crypto.hpp +++ b/libraries/libvapours/include/vapours/crypto.hpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include diff --git a/libraries/libvapours/include/vapours/crypto/crypto_hmac_sha1_generator.hpp b/libraries/libvapours/include/vapours/crypto/crypto_hmac_sha1_generator.hpp index d1a9f32ba..dbd42f470 100644 --- a/libraries/libvapours/include/vapours/crypto/crypto_hmac_sha1_generator.hpp +++ b/libraries/libvapours/include/vapours/crypto/crypto_hmac_sha1_generator.hpp @@ -22,6 +22,10 @@ namespace ams::crypto { using HmacSha1Generator = HmacGenerator; - void GenerateHmacSha1Mac(void *dst, size_t dst_size, const void *data, size_t data_size, const void *key, size_t key_size); + void GenerateHmacSha1(void *dst, size_t dst_size, const void *data, size_t data_size, const void *key, size_t key_size); + + ALWAYS_INLINE void GenerateHmacSha1Mac(void *dst, size_t dst_size, const void *data, size_t data_size, const void *key, size_t key_size) { + return GenerateHmacSha1(dst, dst_size, data, data_size, key, key_size); + } } diff --git a/libraries/libvapours/include/vapours/crypto/crypto_hmac_sha256_generator.hpp b/libraries/libvapours/include/vapours/crypto/crypto_hmac_sha256_generator.hpp index d1a494d20..914f459e3 100644 --- a/libraries/libvapours/include/vapours/crypto/crypto_hmac_sha256_generator.hpp +++ b/libraries/libvapours/include/vapours/crypto/crypto_hmac_sha256_generator.hpp @@ -22,6 +22,10 @@ namespace ams::crypto { using HmacSha256Generator = HmacGenerator; - void GenerateHmacSha256Mac(void *dst, size_t dst_size, const void *data, size_t data_size, const void *key, size_t key_size); + void GenerateHmacSha256(void *dst, size_t dst_size, const void *data, size_t data_size, const void *key, size_t key_size); + + ALWAYS_INLINE void GenerateHmacSha256Mac(void *dst, size_t dst_size, const void *data, size_t data_size, const void *key, size_t key_size) { + return GenerateHmacSha256(dst, dst_size, data, data_size, key, key_size); + } } diff --git a/libraries/libvapours/include/vapours/crypto/crypto_md5_generator.hpp b/libraries/libvapours/include/vapours/crypto/crypto_md5_generator.hpp index a6f56eb13..f156fc8e0 100644 --- a/libraries/libvapours/include/vapours/crypto/crypto_md5_generator.hpp +++ b/libraries/libvapours/include/vapours/crypto/crypto_md5_generator.hpp @@ -58,6 +58,10 @@ namespace ams::crypto { } }; - void GenerateMd5Hash(void *dst, size_t dst_size, const void *src, size_t src_size); + void GenerateMd5(void *dst, size_t dst_size, const void *src, size_t src_size); + + ALWAYS_INLINE void GenerateMd5Hash(void *dst, size_t dst_size, const void *src, size_t src_size) { + return GenerateMd5(dst, dst_size, src, src_size); + } } diff --git a/libraries/libvapours/include/vapours/crypto/crypto_sha1_generator.hpp b/libraries/libvapours/include/vapours/crypto/crypto_sha1_generator.hpp index 3cf7f7c45..eaca09ed0 100644 --- a/libraries/libvapours/include/vapours/crypto/crypto_sha1_generator.hpp +++ b/libraries/libvapours/include/vapours/crypto/crypto_sha1_generator.hpp @@ -58,6 +58,10 @@ namespace ams::crypto { } }; - void GenerateSha1Hash(void *dst, size_t dst_size, const void *src, size_t src_size); + void GenerateSha1(void *dst, size_t dst_size, const void *src, size_t src_size); + + ALWAYS_INLINE void GenerateSha1Hash(void *dst, size_t dst_size, const void *src, size_t src_size) { + return GenerateSha1(dst, dst_size, src, src_size); + } } diff --git a/libraries/libvapours/include/vapours/crypto/crypto_sha256_generator.hpp b/libraries/libvapours/include/vapours/crypto/crypto_sha256_generator.hpp index bdab35f97..f4cfc7f7d 100644 --- a/libraries/libvapours/include/vapours/crypto/crypto_sha256_generator.hpp +++ b/libraries/libvapours/include/vapours/crypto/crypto_sha256_generator.hpp @@ -79,6 +79,10 @@ namespace ams::crypto { } }; - void GenerateSha256Hash(void *dst, size_t dst_size, const void *src, size_t src_size); + void GenerateSha256(void *dst, size_t dst_size, const void *src, size_t src_size); + + ALWAYS_INLINE void GenerateSha256Hash(void *dst, size_t dst_size, const void *src, size_t src_size) { + return GenerateSha256(dst, dst_size, src, src_size); + } } diff --git a/libraries/libvapours/include/vapours/crypto/crypto_sha3_generator.hpp b/libraries/libvapours/include/vapours/crypto/crypto_sha3_generator.hpp new file mode 100644 index 000000000..c2bcee036 --- /dev/null +++ b/libraries/libvapours/include/vapours/crypto/crypto_sha3_generator.hpp @@ -0,0 +1,125 @@ +/* + * Copyright (c) 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 +#include +#include + +namespace ams::crypto { + + struct Sha3Context { + u32 hash_size; + u32 buffered_bytes; + u64 internal_state[25]; + }; + + namespace impl { + + template + struct Sha3Asn1IdentifierByte; + + template<> struct Sha3Asn1IdentifierByte<224 / BITSIZEOF(u8)> { static constexpr u8 Value = 0x07; }; + template<> struct Sha3Asn1IdentifierByte<256 / BITSIZEOF(u8)> { static constexpr u8 Value = 0x08; }; + template<> struct Sha3Asn1IdentifierByte<384 / BITSIZEOF(u8)> { static constexpr u8 Value = 0x09; }; + template<> struct Sha3Asn1IdentifierByte<512 / BITSIZEOF(u8)> { static constexpr u8 Value = 0x0A; }; + + } + + template + class Sha3Generator { + NON_COPYABLE(Sha3Generator); + NON_MOVEABLE(Sha3Generator); + private: + using Impl = impl::Sha3Impl<_HashSize>; + public: + static constexpr size_t HashSize = Impl::HashSize; + static constexpr size_t BlockSize = Impl::BlockSize; + + static constexpr inline u8 Asn1Identifier[] = { + 0x30, 0x31, /* Sequence, size 0x31 */ + 0x30, 0x0D, /* Sequence, size 0x0D */ + 0x06, 0x09, /* Object Identifier */ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, impl::Sha3Asn1IdentifierByte::Value, /* SHA3-*** */ + 0x05, 0x00, /* Null */ + 0x04, 0x20, /* Octet string, size 0x20 */ + }; + static constexpr size_t Asn1IdentifierSize = util::size(Asn1Identifier); + private: + Impl m_impl; + public: + Sha3Generator() { /* ... */ } + + void Initialize() { + m_impl.Initialize(); + } + + void Update(const void *data, size_t size) { + m_impl.Update(data, size); + } + + void GetHash(void *dst, size_t size) { + m_impl.GetHash(dst, size); + } + + void InitializeWithContext(const Sha3Context *context) { + m_impl.InitializeWithContext(context); + } + + void GetContext(Sha3Context *context) const { + m_impl.GetContext(context); + } + }; + + using Sha3224Generator = Sha3Generator<224 / BITSIZEOF(u8)>; + using Sha3256Generator = Sha3Generator<256 / BITSIZEOF(u8)>; + using Sha3384Generator = Sha3Generator<384 / BITSIZEOF(u8)>; + using Sha3512Generator = Sha3Generator<512 / BITSIZEOF(u8)>; + + inline void GenerateSha3224(void *dst, size_t dst_size, const void *src, size_t src_size) { + Sha3224Generator generator; + + generator.Initialize(); + generator.Update(src, src_size); + generator.GetHash(dst, dst_size); + } + + inline void GenerateSha3256(void *dst, size_t dst_size, const void *src, size_t src_size) { + Sha3256Generator generator; + + generator.Initialize(); + generator.Update(src, src_size); + generator.GetHash(dst, dst_size); + } + + inline void GenerateSha3384(void *dst, size_t dst_size, const void *src, size_t src_size) { + Sha3384Generator generator; + + generator.Initialize(); + generator.Update(src, src_size); + generator.GetHash(dst, dst_size); + } + + inline void GenerateSha3512(void *dst, size_t dst_size, const void *src, size_t src_size) { + Sha3512Generator generator; + + generator.Initialize(); + generator.Update(src, src_size); + generator.GetHash(dst, dst_size); + } + +} diff --git a/libraries/libvapours/include/vapours/crypto/impl/crypto_ctr_mode_impl.hpp b/libraries/libvapours/include/vapours/crypto/impl/crypto_ctr_mode_impl.hpp index dc1427c3d..b1125056b 100644 --- a/libraries/libvapours/include/vapours/crypto/impl/crypto_ctr_mode_impl.hpp +++ b/libraries/libvapours/include/vapours/crypto/impl/crypto_ctr_mode_impl.hpp @@ -174,7 +174,11 @@ namespace ams::crypto::impl { } template<> void CtrModeImpl::ProcessBlocks(u8 *dst, const u8 *src, size_t num_blocks); + + /* TODO: Optimized x64 CTR-192/256? */ + #if defined(ATMOSPHERE_ARCH_ARM64) template<> void CtrModeImpl::ProcessBlocks(u8 *dst, const u8 *src, size_t num_blocks); template<> void CtrModeImpl::ProcessBlocks(u8 *dst, const u8 *src, size_t num_blocks); + #endif } diff --git a/libraries/libvapours/include/vapours/crypto/impl/crypto_sha1_impl.hpp b/libraries/libvapours/include/vapours/crypto/impl/crypto_sha1_impl.hpp index 2bcaa4434..10339bc48 100644 --- a/libraries/libvapours/include/vapours/crypto/impl/crypto_sha1_impl.hpp +++ b/libraries/libvapours/include/vapours/crypto/impl/crypto_sha1_impl.hpp @@ -29,25 +29,30 @@ namespace ams::crypto::impl { static constexpr size_t HashSize = 0x14; static constexpr size_t BlockSize = 0x40; private: - struct State { - u32 intermediate_hash[HashSize / sizeof(u32)]; - u8 buffer[BlockSize]; - u64 bits_consumed; - size_t num_buffered; - bool finalized; + enum State { + State_None, + State_Initialized, + State_Done, }; private: + u32 m_intermediate_hash[HashSize / sizeof(u32)]; + u8 m_buffer[BlockSize]; + size_t m_buffered_bytes; + u64 m_bits_consumed; State m_state; public: - Sha1Impl() { m_state.finalized = false; } + Sha1Impl() : m_state(State_None) { /* ... */ } ~Sha1Impl() { - static_assert(std::is_trivially_destructible::value); - ClearMemory(std::addressof(m_state), sizeof(m_state)); + ClearMemory(this, sizeof(*this)); } void Initialize(); void Update(const void *data, size_t size); void GetHash(void *dst, size_t size); + private: + void ProcessBlock(const void *data); + void ProcessBlocks(const u8 *data, size_t block_count); + void ProcessLastBlock(); }; /* static_assert(HashFunction); */ diff --git a/libraries/libvapours/include/vapours/crypto/impl/crypto_sha256_impl.hpp b/libraries/libvapours/include/vapours/crypto/impl/crypto_sha256_impl.hpp index 4621c2d3a..663121dfe 100644 --- a/libraries/libvapours/include/vapours/crypto/impl/crypto_sha256_impl.hpp +++ b/libraries/libvapours/include/vapours/crypto/impl/crypto_sha256_impl.hpp @@ -34,20 +34,21 @@ namespace ams::crypto::impl { static constexpr size_t HashSize = 0x20; static constexpr size_t BlockSize = 0x40; private: - struct State { - u32 intermediate_hash[HashSize / sizeof(u32)]; - u8 buffer[BlockSize]; - u64 bits_consumed; - size_t num_buffered; - bool finalized; + enum State { + State_None, + State_Initialized, + State_Done, }; private: + u32 m_intermediate_hash[HashSize / sizeof(u32)]; + u8 m_buffer[BlockSize]; + size_t m_buffered_bytes; + u64 m_bits_consumed; State m_state; public: - Sha256Impl() { m_state.finalized = false; } + Sha256Impl() : m_state(State_None) { /* ... */ } ~Sha256Impl() { - static_assert(std::is_trivially_destructible::value); - ClearMemory(std::addressof(m_state), sizeof(m_state)); + ClearMemory(this, sizeof(*this)); } void Initialize(); @@ -57,14 +58,18 @@ namespace ams::crypto::impl { void InitializeWithContext(const Sha256Context *context); size_t GetContext(Sha256Context *context) const; - size_t GetBufferedDataSize() const { return m_state.num_buffered; } + size_t GetBufferedDataSize() const { return m_buffered_bytes; } void GetBufferedData(void *dst, size_t dst_size) const { AMS_ASSERT(dst_size >= this->GetBufferedDataSize()); AMS_UNUSED(dst_size); - std::memcpy(dst, m_state.buffer, this->GetBufferedDataSize()); + std::memcpy(dst, m_buffer, m_buffered_bytes); } + private: + void ProcessBlock(const void *data); + void ProcessBlocks(const u8 *data, size_t block_count); + void ProcessLastBlock(); }; static_assert(HashFunction); diff --git a/libraries/libvapours/include/vapours/crypto/impl/crypto_sha3_impl.hpp b/libraries/libvapours/include/vapours/crypto/impl/crypto_sha3_impl.hpp new file mode 100644 index 000000000..009ffcd7a --- /dev/null +++ b/libraries/libvapours/include/vapours/crypto/impl/crypto_sha3_impl.hpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) 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 +#include +#include +#include + +namespace ams::crypto { + + struct Sha3Context; + +} + +namespace ams::crypto::impl { + + template + class Sha3Impl { + public: + static constexpr size_t InternalStateSize = 200; + static constexpr size_t HashSize = _HashSize; + static constexpr size_t BlockSize = InternalStateSize - 2 * HashSize; + private: + enum State { + State_None, + State_Initialized, + State_Done, + }; + private: + u64 m_internal_state[InternalStateSize / sizeof(u64)]; + size_t m_buffered_bytes; + State m_state; + public: + Sha3Impl() : m_state(State_None) { /* ... */ } + ~Sha3Impl() { + ClearMemory(this, sizeof(*this)); + } + + void Initialize(); + void Update(const void *data, size_t size); + void GetHash(void *dst, size_t size); + + void InitializeWithContext(const Sha3Context *context); + void GetContext(Sha3Context *context) const; + private: + void ProcessBlock(); + void ProcessLastBlock(); + }; + + static_assert(HashFunction>); + static_assert(HashFunction>); + static_assert(HashFunction>); + static_assert(HashFunction>); + +} diff --git a/libraries/libvapours/include/vapours/crypto/impl/crypto_xts_mode_impl.hpp b/libraries/libvapours/include/vapours/crypto/impl/crypto_xts_mode_impl.hpp index 78136240b..033fc5495 100644 --- a/libraries/libvapours/include/vapours/crypto/impl/crypto_xts_mode_impl.hpp +++ b/libraries/libvapours/include/vapours/crypto/impl/crypto_xts_mode_impl.hpp @@ -125,6 +125,7 @@ namespace ams::crypto::impl { size_t ProcessRemainingData(u8 *dst, const u8 *src, size_t size); }; + #if defined(ATMOSPHERE_ARCH_ARM64) template<> size_t XtsModeImpl::Update(void *dst, size_t dst_size, const void *src, size_t src_size); template<> size_t XtsModeImpl::Update(void *dst, size_t dst_size, const void *src, size_t src_size); template<> size_t XtsModeImpl::Update(void *dst, size_t dst_size, const void *src, size_t src_size); @@ -132,5 +133,6 @@ namespace ams::crypto::impl { template<> size_t XtsModeImpl::Update(void *dst, size_t dst_size, const void *src, size_t src_size); template<> size_t XtsModeImpl::Update(void *dst, size_t dst_size, const void *src, size_t src_size); template<> size_t XtsModeImpl::Update(void *dst, size_t dst_size, const void *src, size_t src_size); + #endif } diff --git a/libraries/libvapours/include/vapours/dd/dd_common_types.hpp b/libraries/libvapours/include/vapours/dd/dd_common_types.hpp index 502aa784c..b9f8fa3f5 100644 --- a/libraries/libvapours/include/vapours/dd/dd_common_types.hpp +++ b/libraries/libvapours/include/vapours/dd/dd_common_types.hpp @@ -24,6 +24,8 @@ namespace ams::dd { using PhysicalAddress = u64; using DeviceVirtualAddress = u64; + #if defined(ATMOSPHERE_OS_HORIZON) static_assert(std::same_as); + #endif } diff --git a/libraries/libvapours/include/vapours/defines.hpp b/libraries/libvapours/include/vapours/defines.hpp index 66359fbd2..9f8eb5ffd 100644 --- a/libraries/libvapours/include/vapours/defines.hpp +++ b/libraries/libvapours/include/vapours/defines.hpp @@ -18,6 +18,34 @@ /* Any broadly useful language defines should go here. */ +#if defined(ATMOSPHERE_OS_WINDOWS) + #if defined(ATMOSPHERE_ARCH_ARM64) || defined(ATMOSPHERE_ARCH_X64) + static_assert(sizeof(size_t) == sizeof(uint64_t)); + + #define PRIuZ PRIu64 + #define PRIxZ PRIx64 + #define PRIXZ PRIX64 + #elif defined(ATMOSPHERE_ARCH_ARM) || defined(ATMOSPHERE_ARCH_X86) + static_assert(sizeof(size_t) == sizeof(uint32_t)); + + #define PRIuZ PRIu32 + #define PRIxZ PRIx32 + #define PRIXZ PRIX32 + #endif +#else + #define PRIuZ "zu" + #define PRIxZ "zx" + #define PRIXZ "zX" +#endif + +#if defined(__clang__) + #define ATMOSPHERE_COMPILER_CLANG +#elif defined(__GNUG__) || defined(__GNUC__) + #define ATMOSPHERE_COMPILER_GCC +#else + #error "Unknown compiler!" +#endif + #define NON_COPYABLE(cls) \ cls(const cls&) = delete; \ cls& operator=(const cls&) = delete @@ -41,6 +69,10 @@ #define STRINGIZE(x) STRINGIZE_IMPL(x) #define STRINGIZE_IMPL(x) #x +#ifndef PACKED +#define PACKED __attribute__((packed)) +#endif + #ifdef __COUNTER__ #define ANONYMOUS_VARIABLE(pref) CONCATENATE(pref, __COUNTER__) #else diff --git a/libraries/libvapours/include/vapours/freebsd/tree.hpp b/libraries/libvapours/include/vapours/freebsd/tree.hpp index 8e19edabd..2dcab2fb6 100644 --- a/libraries/libvapours/include/vapours/freebsd/tree.hpp +++ b/libraries/libvapours/include/vapours/freebsd/tree.hpp @@ -30,8 +30,7 @@ #include #include -#pragma GCC push_options -#pragma GCC optimize ("-O3") +AMS_PRAGMA_BEGIN_OPTIMIZE_O3() /* * This file defines data structures for red-black trees. @@ -626,4 +625,4 @@ namespace ams::freebsd { } -#pragma GCC pop_options +AMS_PRAGMA_END_OPTIMIZE() diff --git a/libraries/libvapours/include/vapours/impl/compiler_impl.clang.hpp b/libraries/libvapours/include/vapours/impl/compiler_impl.clang.hpp new file mode 100644 index 000000000..5b7360d21 --- /dev/null +++ b/libraries/libvapours/include/vapours/impl/compiler_impl.clang.hpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) 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 + +#define AMS_PRAGMA_BEGIN_OPTIMIZE_O3() +#define AMS_PRAGMA_BEGIN_OPTIMIZE_OS() +#define AMS_PRAGMA_END_OPTIMIZE() + +#define AMS_CONCEPTS_REQUIRES_IF_SUPPORTED(__EXPR__) diff --git a/libraries/libvapours/include/vapours/impl/compiler_impl.gcc.hpp b/libraries/libvapours/include/vapours/impl/compiler_impl.gcc.hpp new file mode 100644 index 000000000..df99944ad --- /dev/null +++ b/libraries/libvapours/include/vapours/impl/compiler_impl.gcc.hpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 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 + +#define AMS_PRAGMA_BEGIN_OPTIMIZE_O3() \ + _Pragma("GCC push_options") \ + _Pragma("GCC optimize (\"-O3\")") + +#define AMS_PRAGMA_BEGIN_OPTIMIZE_OS() \ + _Pragma("GCC push_options") \ + _Pragma("GCC optimize (\"-Os\")") + +#define AMS_PRAGMA_END_OPTIMIZE() \ + _Pragma("GCC pop_options") + +#define AMS_CONCEPTS_REQUIRES_IF_SUPPORTED(__EXPR__) requires (__EXPR__) diff --git a/libraries/libvapours/include/vapours/includes.hpp b/libraries/libvapours/include/vapours/includes.hpp index 47e0b5554..94a73b94f 100644 --- a/libraries/libvapours/include/vapours/includes.hpp +++ b/libraries/libvapours/include/vapours/includes.hpp @@ -16,6 +16,9 @@ #pragma once +/* Unconditionally include type-traits as first header. */ +#include + /* C headers. */ #include #include @@ -28,7 +31,6 @@ #include /* C++ headers. */ -#include #include #include #include @@ -52,11 +54,20 @@ #include #include +#if defined(ATMOSPHERE_OS_HORIZON) && defined(ATMOSPHERE_BOARD_NINTENDO_NX) + /* Libnx. */ #include #else +/* Non-switch code can't include libnx. */ +#include "types.hpp" + +#endif + +#else + /* Non-EL0 code can't include libnx. */ #include "types.hpp" diff --git a/libraries/libvapours/include/vapours/results/fs_results.hpp b/libraries/libvapours/include/vapours/results/fs_results.hpp index 0f30b2efa..d3384d52a 100644 --- a/libraries/libvapours/include/vapours/results/fs_results.hpp +++ b/libraries/libvapours/include/vapours/results/fs_results.hpp @@ -56,68 +56,76 @@ namespace ams::fs { R_DEFINE_ERROR_RESULT(SystemPartitionNotReady, 3100); R_DEFINE_ERROR_RANGE(AllocationFailure, 3200, 3499); - R_DEFINE_ERROR_RESULT(AllocationFailureInFileSystemAccessorA, 3211); - R_DEFINE_ERROR_RESULT(AllocationFailureInFileSystemAccessorB, 3212); - R_DEFINE_ERROR_RESULT(AllocationFailureInApplicationA, 3213); - R_DEFINE_ERROR_RESULT(AllocationFailureInBisA, 3215); - R_DEFINE_ERROR_RESULT(AllocationFailureInBisB, 3216); - R_DEFINE_ERROR_RESULT(AllocationFailureInBisC, 3217); - R_DEFINE_ERROR_RESULT(AllocationFailureInCodeA, 3218); - R_DEFINE_ERROR_RESULT(AllocationFailureInContentA, 3219); - R_DEFINE_ERROR_RESULT(AllocationFailureInContentStorageA, 3220); - R_DEFINE_ERROR_RESULT(AllocationFailureInContentStorageB, 3221); - R_DEFINE_ERROR_RESULT(AllocationFailureInDataA, 3222); - R_DEFINE_ERROR_RESULT(AllocationFailureInDataB, 3223); - R_DEFINE_ERROR_RESULT(AllocationFailureInDeviceSaveDataA, 3224); - R_DEFINE_ERROR_RESULT(AllocationFailureInGameCardA, 3225); - R_DEFINE_ERROR_RESULT(AllocationFailureInGameCardB, 3226); - R_DEFINE_ERROR_RESULT(AllocationFailureInGameCardC, 3227); - R_DEFINE_ERROR_RESULT(AllocationFailureInGameCardD, 3228); - R_DEFINE_ERROR_RESULT(AllocationFailureInImageDirectoryA, 3232); - R_DEFINE_ERROR_RESULT(AllocationFailureInSdCardA, 3244); - R_DEFINE_ERROR_RESULT(AllocationFailureInSdCardB, 3245); - R_DEFINE_ERROR_RESULT(AllocationFailureInSystemSaveDataA, 3246); - R_DEFINE_ERROR_RESULT(AllocationFailureInRomFsFileSystemA, 3247); - R_DEFINE_ERROR_RESULT(AllocationFailureInRomFsFileSystemB, 3248); - R_DEFINE_ERROR_RESULT(AllocationFailureInRomFsFileSystemC, 3249); - R_DEFINE_ERROR_RESULT(AllocationFailureInFileSystemProxyCoreImplD, 3256); - R_DEFINE_ERROR_RESULT(AllocationFailureInFileSystemProxyCoreImplE, 3257); - R_DEFINE_ERROR_RESULT(AllocationFailureInProgramRegistryManagerA, 3258); - R_DEFINE_ERROR_RESULT(AllocationFailureInPartitionFileSystemCreatorA, 3280); - R_DEFINE_ERROR_RESULT(AllocationFailureInRomFileSystemCreatorA, 3281); - R_DEFINE_ERROR_RESULT(AllocationFailureInStorageOnNcaCreatorA, 3288); - R_DEFINE_ERROR_RESULT(AllocationFailureInStorageOnNcaCreatorB, 3289); - R_DEFINE_ERROR_RESULT(AllocationFailureInFileSystemBuddyHeapA, 3294); - R_DEFINE_ERROR_RESULT(AllocationFailureInFileSystemBufferManagerA, 3295); - R_DEFINE_ERROR_RESULT(AllocationFailureInBlockCacheBufferedStorageA, 3296); - R_DEFINE_ERROR_RESULT(AllocationFailureInBlockCacheBufferedStorageB, 3297); - R_DEFINE_ERROR_RESULT(AllocationFailureInIntegrityVerificationStorageA, 3304); - R_DEFINE_ERROR_RESULT(AllocationFailureInIntegrityVerificationStorageB, 3305); - R_DEFINE_ERROR_RESULT(AllocationFailureInDirectorySaveDataFileSystem, 3321); - R_DEFINE_ERROR_RESULT(AllocationFailureInNcaFileSystemDriverI, 3341); - R_DEFINE_ERROR_RESULT(AllocationFailureInPartitionFileSystemA, 3347); - R_DEFINE_ERROR_RESULT(AllocationFailureInPartitionFileSystemB, 3348); - R_DEFINE_ERROR_RESULT(AllocationFailureInPartitionFileSystemC, 3349); - R_DEFINE_ERROR_RESULT(AllocationFailureInPartitionFileSystemMetaA, 3350); - R_DEFINE_ERROR_RESULT(AllocationFailureInPartitionFileSystemMetaB, 3351); - R_DEFINE_ERROR_RESULT(AllocationFailureInRomFsFileSystemD, 3352); - R_DEFINE_ERROR_RESULT(AllocationFailureInSubDirectoryFileSystem, 3355); - R_DEFINE_ERROR_RESULT(AllocationFailureInNcaReaderA, 3363); - R_DEFINE_ERROR_RESULT(AllocationFailureInRegisterA, 3365); - R_DEFINE_ERROR_RESULT(AllocationFailureInRegisterB, 3366); - R_DEFINE_ERROR_RESULT(AllocationFailureInPathNormalizer, 3367); - R_DEFINE_ERROR_RESULT(AllocationFailureInDbmRomKeyValueStorage, 3375); - R_DEFINE_ERROR_RESULT(AllocationFailureInRomFsFileSystemE, 3377); - R_DEFINE_ERROR_RESULT(AllocationFailureInReadOnlyFileSystemA, 3386); - R_DEFINE_ERROR_RESULT(AllocationFailureInAesCtrCounterExtendedStorageA, 3399); - R_DEFINE_ERROR_RESULT(AllocationFailureInAesCtrCounterExtendedStorageB, 3400); - R_DEFINE_ERROR_RESULT(AllocationFailureInFileSystemInterfaceAdapter, 3407); - R_DEFINE_ERROR_RESULT(AllocationFailureInBufferedStorageA, 3411); - R_DEFINE_ERROR_RESULT(AllocationFailureInIntegrityRomFsStorageA, 3412); - R_DEFINE_ERROR_RESULT(AllocationFailureInNew, 3420); - R_DEFINE_ERROR_RESULT(AllocationFailureInMakeUnique, 3422); - R_DEFINE_ERROR_RESULT(AllocationFailureInAllocateShared, 3423); - R_DEFINE_ERROR_RESULT(AllocationFailurePooledBufferNotEnoughSize, 3424); + R_DEFINE_ERROR_RESULT(AllocationFailureInFileSystemAccessorA, 3211); + R_DEFINE_ERROR_RESULT(AllocationFailureInFileSystemAccessorB, 3212); + R_DEFINE_ERROR_RESULT(AllocationFailureInApplicationA, 3213); + R_DEFINE_ERROR_RESULT(AllocationFailureInBisA, 3215); + R_DEFINE_ERROR_RESULT(AllocationFailureInBisB, 3216); + R_DEFINE_ERROR_RESULT(AllocationFailureInBisC, 3217); + R_DEFINE_ERROR_RESULT(AllocationFailureInCodeA, 3218); + R_DEFINE_ERROR_RESULT(AllocationFailureInContentA, 3219); + R_DEFINE_ERROR_RESULT(AllocationFailureInContentStorageA, 3220); + R_DEFINE_ERROR_RESULT(AllocationFailureInContentStorageB, 3221); + R_DEFINE_ERROR_RESULT(AllocationFailureInDataA, 3222); + R_DEFINE_ERROR_RESULT(AllocationFailureInDataB, 3223); + R_DEFINE_ERROR_RESULT(AllocationFailureInDeviceSaveDataA, 3224); + R_DEFINE_ERROR_RESULT(AllocationFailureInGameCardA, 3225); + R_DEFINE_ERROR_RESULT(AllocationFailureInGameCardB, 3226); + R_DEFINE_ERROR_RESULT(AllocationFailureInGameCardC, 3227); + R_DEFINE_ERROR_RESULT(AllocationFailureInGameCardD, 3228); + R_DEFINE_ERROR_RESULT(AllocationFailureInHostA, 3229); + R_DEFINE_ERROR_RESULT(AllocationFailureInHostB, 3230); + R_DEFINE_ERROR_RESULT(AllocationFailureInHostC, 3231); + R_DEFINE_ERROR_RESULT(AllocationFailureInImageDirectoryA, 3232); + R_DEFINE_ERROR_RESULT(AllocationFailureInSdCardA, 3244); + R_DEFINE_ERROR_RESULT(AllocationFailureInSdCardB, 3245); + R_DEFINE_ERROR_RESULT(AllocationFailureInSystemSaveDataA, 3246); + R_DEFINE_ERROR_RESULT(AllocationFailureInRomFsFileSystemA, 3247); + R_DEFINE_ERROR_RESULT(AllocationFailureInRomFsFileSystemB, 3248); + R_DEFINE_ERROR_RESULT(AllocationFailureInRomFsFileSystemC, 3249); + R_DEFINE_ERROR_RESULT(AllocationFailureInFileSystemProxyCoreImplD, 3256); + R_DEFINE_ERROR_RESULT(AllocationFailureInFileSystemProxyCoreImplE, 3257); + R_DEFINE_ERROR_RESULT(AllocationFailureInProgramRegistryManagerA, 3258); + R_DEFINE_ERROR_RESULT(AllocationFailureInLocalFileSystemCreatorA, 3279); + R_DEFINE_ERROR_RESULT(AllocationFailureInPartitionFileSystemCreatorA, 3280); + R_DEFINE_ERROR_RESULT(AllocationFailureInRomFileSystemCreatorA, 3281); + R_DEFINE_ERROR_RESULT(AllocationFailureInStorageOnNcaCreatorA, 3288); + R_DEFINE_ERROR_RESULT(AllocationFailureInStorageOnNcaCreatorB, 3289); + R_DEFINE_ERROR_RESULT(AllocationFailureInSubDirectoryFileSystemCreatorA, 3290); + R_DEFINE_ERROR_RESULT(AllocationFailureInFileSystemBuddyHeapA, 3294); + R_DEFINE_ERROR_RESULT(AllocationFailureInFileSystemBufferManagerA, 3295); + R_DEFINE_ERROR_RESULT(AllocationFailureInBlockCacheBufferedStorageA, 3296); + R_DEFINE_ERROR_RESULT(AllocationFailureInBlockCacheBufferedStorageB, 3297); + R_DEFINE_ERROR_RESULT(AllocationFailureInIntegrityVerificationStorageA, 3304); + R_DEFINE_ERROR_RESULT(AllocationFailureInIntegrityVerificationStorageB, 3305); + R_DEFINE_ERROR_RESULT(AllocationFailureInDirectorySaveDataFileSystem, 3321); + R_DEFINE_ERROR_RESULT(AllocationFailureInLocalFileSystemA, 3322); + R_DEFINE_ERROR_RESULT(AllocationFailureInLocalFileSystemB, 3323); + R_DEFINE_ERROR_RESULT(AllocationFailureInNcaFileSystemDriverI, 3341); + R_DEFINE_ERROR_RESULT(AllocationFailureInPartitionFileSystemA, 3347); + R_DEFINE_ERROR_RESULT(AllocationFailureInPartitionFileSystemB, 3348); + R_DEFINE_ERROR_RESULT(AllocationFailureInPartitionFileSystemC, 3349); + R_DEFINE_ERROR_RESULT(AllocationFailureInPartitionFileSystemMetaA, 3350); + R_DEFINE_ERROR_RESULT(AllocationFailureInPartitionFileSystemMetaB, 3351); + R_DEFINE_ERROR_RESULT(AllocationFailureInRomFsFileSystemD, 3352); + R_DEFINE_ERROR_RESULT(AllocationFailureInSubDirectoryFileSystem, 3355); + R_DEFINE_ERROR_RESULT(AllocationFailureInNcaReaderA, 3363); + R_DEFINE_ERROR_RESULT(AllocationFailureInRegisterA, 3365); + R_DEFINE_ERROR_RESULT(AllocationFailureInRegisterB, 3366); + R_DEFINE_ERROR_RESULT(AllocationFailureInPathNormalizer, 3367); + R_DEFINE_ERROR_RESULT(AllocationFailureInDbmRomKeyValueStorage, 3375); + R_DEFINE_ERROR_RESULT(AllocationFailureInRomFsFileSystemE, 3377); + R_DEFINE_ERROR_RESULT(AllocationFailureInReadOnlyFileSystemA, 3386); + R_DEFINE_ERROR_RESULT(AllocationFailureInAesCtrCounterExtendedStorageA, 3399); + R_DEFINE_ERROR_RESULT(AllocationFailureInAesCtrCounterExtendedStorageB, 3400); + R_DEFINE_ERROR_RESULT(AllocationFailureInFileSystemInterfaceAdapter, 3407); + R_DEFINE_ERROR_RESULT(AllocationFailureInBufferedStorageA, 3411); + R_DEFINE_ERROR_RESULT(AllocationFailureInIntegrityRomFsStorageA, 3412); + R_DEFINE_ERROR_RESULT(AllocationFailureInNew, 3420); + R_DEFINE_ERROR_RESULT(AllocationFailureInFileSystemProxyImplA, 3421); + R_DEFINE_ERROR_RESULT(AllocationFailureInMakeUnique, 3422); + R_DEFINE_ERROR_RESULT(AllocationFailureInAllocateShared, 3423); + R_DEFINE_ERROR_RESULT(AllocationFailurePooledBufferNotEnoughSize, 3424); R_DEFINE_ERROR_RANGE(Internal, 3000, 7999); R_DEFINE_ERROR_RANGE(MmcAccessFailed, 3500, 3999); @@ -284,12 +292,22 @@ namespace ams::fs { R_DEFINE_ERROR_RESULT(GameCardLogoDataCorrupted, 4781); R_DEFINE_ERROR_RANGE(Unexpected, 5000, 5999); - R_DEFINE_ERROR_RESULT(UnexpectedInAesCtrStorageA, 5315); - R_DEFINE_ERROR_RESULT(UnexpectedInAesXtsStorageA, 5316); - R_DEFINE_ERROR_RESULT(UnexpectedInFindFileSystemA, 5319); - R_DEFINE_ERROR_RESULT(UnexpectedInCompressedStorageA, 5324); - R_DEFINE_ERROR_RESULT(UnexpectedInCompressedStorageB, 5325); - R_DEFINE_ERROR_RESULT(UnexpectedInCompressedStorageC, 5326); + R_DEFINE_ERROR_RESULT(UnexpectedInLocalFileSystemA, 5305); + R_DEFINE_ERROR_RESULT(UnexpectedInLocalFileSystemB, 5306); + R_DEFINE_ERROR_RESULT(UnexpectedInLocalFileSystemC, 5307); + R_DEFINE_ERROR_RESULT(UnexpectedInLocalFileSystemD, 5308); + R_DEFINE_ERROR_RESULT(UnexpectedInLocalFileSystemE, 5309); + R_DEFINE_ERROR_RESULT(UnexpectedInLocalFileSystemF, 5310); + R_DEFINE_ERROR_RESULT(UnexpectedInPathOnExecutionDirectoryA, 5312); + R_DEFINE_ERROR_RESULT(UnexpectedInPathOnExecutionDirectoryB, 5313); + R_DEFINE_ERROR_RESULT(UnexpectedInPathOnExecutionDirectoryC, 5314); + R_DEFINE_ERROR_RESULT(UnexpectedInAesCtrStorageA, 5315); + R_DEFINE_ERROR_RESULT(UnexpectedInAesXtsStorageA, 5316); + R_DEFINE_ERROR_RESULT(UnexpectedInFindFileSystemA, 5319); + R_DEFINE_ERROR_RESULT(UnexpectedInCompressedStorageA, 5324); + R_DEFINE_ERROR_RESULT(UnexpectedInCompressedStorageB, 5325); + R_DEFINE_ERROR_RESULT(UnexpectedInCompressedStorageC, 5326); + R_DEFINE_ERROR_RESULT(UnexpectedInPathA, 5328); R_DEFINE_ERROR_RANGE(PreconditionViolation, 6000, 6499); R_DEFINE_ERROR_RANGE(InvalidArgument, 6001, 6199); @@ -334,6 +352,7 @@ namespace ams::fs { R_DEFINE_ERROR_RESULT(UnsupportedOperationInFileStorageA, 6306); R_DEFINE_ERROR_RESULT(UnsupportedOperationInFileStorageB, 6307); R_DEFINE_ERROR_RESULT(UnsupportedOperationInSwitchStorageA, 6308); + R_DEFINE_ERROR_RESULT(UnsupportedOperationInStorageServiceObjectAdapterA, 6309); R_DEFINE_ERROR_RESULT(UnsupportedOperationInAesCtrCounterExtendedStorageA, 6310); R_DEFINE_ERROR_RESULT(UnsupportedOperationInAesCtrCounterExtendedStorageB, 6311); R_DEFINE_ERROR_RESULT(UnsupportedOperationInAesCtrCounterExtendedStorageC, 6312); @@ -372,9 +391,12 @@ namespace ams::fs { R_DEFINE_ERROR_RESULT(UnsupportedOperationInPartitionFileSystemB, 6375); R_DEFINE_ERROR_RESULT(UnsupportedOperationInPartitionFileA, 6376); R_DEFINE_ERROR_RESULT(UnsupportedOperationInPartitionFileB, 6377); + R_DEFINE_ERROR_RESULT(UnsupportedOperationInLocalFileA, 6378); + R_DEFINE_ERROR_RESULT(UnsupportedOperationInDirectorySaveDataFileSystemA, 6384); R_DEFINE_ERROR_RESULT(UnsupportedOperationInCompressedStorageA, 6387); R_DEFINE_ERROR_RANGE(PermissionDenied, 6400, 6449); + R_DEFINE_ERROR_RESULT(PermissionDeniedForCreateHostFileSystem, 6403); R_DEFINE_ERROR_RESULT(PortAcceptableCountLimited, 6450); R_DEFINE_ERROR_RESULT(NeedFlush, 6454); diff --git a/libraries/libvapours/include/vapours/results/os_results.hpp b/libraries/libvapours/include/vapours/results/os_results.hpp index 783fd6c7c..62a6344c6 100644 --- a/libraries/libvapours/include/vapours/results/os_results.hpp +++ b/libraries/libvapours/include/vapours/results/os_results.hpp @@ -23,6 +23,7 @@ namespace ams::os { R_DEFINE_ERROR_RESULT(Busy, 4); + R_DEFINE_ERROR_RESULT(InvalidParameter, 7); R_DEFINE_ERROR_RESULT(OutOfMemory, 8); R_DEFINE_ERROR_RESULT(OutOfResource, 9); @@ -41,4 +42,7 @@ namespace ams::os { R_DEFINE_ERROR_RESULT(SessionClosedForReply, 511); R_DEFINE_ERROR_RESULT(ReceiveListBroken, 512); + R_DEFINE_ERROR_RESULT(NotImplemented, 1000); + R_DEFINE_ERROR_RESULT(NotSupported, 1001); + } diff --git a/libraries/libvapours/include/vapours/results/results_common.hpp b/libraries/libvapours/include/vapours/results/results_common.hpp index 8fd613674..ec03e67d6 100644 --- a/libraries/libvapours/include/vapours/results/results_common.hpp +++ b/libraries/libvapours/include/vapours/results/results_common.hpp @@ -219,6 +219,14 @@ namespace ams { } + #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) && defined(ATMOSPHERE_ARCH_ARM64) && defined(ATMOSPHERE_IS_STRATOSPHERE) + namespace diag::impl { + + void FatalErrorByResultForNx(Result result) noexcept NORETURN; + + } + #endif + } /* Macros for defining new results. */ @@ -353,61 +361,66 @@ namespace ams::result::impl { /// Returns a result. #define R_THROW(res_expr) \ - ({ \ + { \ const ::ams::Result _tmp_r_throw_rc = (res_expr); \ if constexpr (std::same_as) { __TmpCurrentResultReference = _tmp_r_throw_rc; } \ return _tmp_r_throw_rc; \ - }) + } /// Returns ResultSuccess() #define R_SUCCEED() R_THROW(::ams::ResultSuccess()) /// Evaluates an expression that returns a result, and returns the result if it would fail. #define R_TRY(res_expr) \ - ({ \ + { \ if (const auto _tmp_r_try_rc = (res_expr); R_FAILED(_tmp_r_try_rc)) { \ R_THROW(_tmp_r_try_rc); \ } \ - }) + } /// Return a result. #define R_RETURN(res_expr) R_THROW(res_expr) -#ifdef AMS_ENABLE_DEBUG_PRINT -#define AMS_CALL_ON_RESULT_ASSERTION_IMPL(cond, val) ::ams::result::impl::OnResultAssertion(__FILE__, __LINE__, __PRETTY_FUNCTION__, cond, val) -#define AMS_CALL_ON_RESULT_ABORT_IMPL(cond, val) ::ams::result::impl::OnResultAbort(__FILE__, __LINE__, __PRETTY_FUNCTION__, cond, val) +#if defined(ATMOSPHERE_BOARD_NINTENDO_NX) && defined(ATMOSPHERE_IS_STRATOSPHERE) && !defined(AMS_ENABLE_DETAILED_ASSERTIONS) && !defined(AMS_BUILD_FOR_DEBUGGING) && !defined(AMS_BUILD_FOR_AUDITING) + #define AMS_CALL_ON_RESULT_ASSERTION_IMPL(cond, val) do { ::ams::diag::impl::FatalErrorByResultForNx(val); AMS_INFINITE_LOOP(); AMS_ASSUME(false); } while (false) + #define AMS_CALL_ON_RESULT_ABORT_IMPL(cond, val) do { ::ams::diag::impl::FatalErrorByResultForNx(val); AMS_INFINITE_LOOP(); AMS_ASSUME(false); } while (false) #else -#define AMS_CALL_ON_RESULT_ASSERTION_IMPL(cond, val) ::ams::result::impl::OnResultAssertion("", 0, "", "", val) -#define AMS_CALL_ON_RESULT_ABORT_IMPL(cond, val) ::ams::result::impl::OnResultAbort("", 0, "", "", val) + #if defined(AMS_ENABLE_DETAILED_ASSERTIONS) + #define AMS_CALL_ON_RESULT_ASSERTION_IMPL(cond, val) ::ams::result::impl::OnResultAssertion(__FILE__, __LINE__, __PRETTY_FUNCTION__, cond, val) + #define AMS_CALL_ON_RESULT_ABORT_IMPL(cond, val) ::ams::result::impl::OnResultAbort(__FILE__, __LINE__, __PRETTY_FUNCTION__, cond, val) + #else + #define AMS_CALL_ON_RESULT_ASSERTION_IMPL(cond, val) ::ams::result::impl::OnResultAssertion("", 0, "", "", val) + #define AMS_CALL_ON_RESULT_ABORT_IMPL(cond, val) ::ams::result::impl::OnResultAbort("", 0, "", "", val) + #endif #endif /// Evaluates an expression that returns a result, and asserts the result if it would fail. #ifdef AMS_ENABLE_ASSERTIONS #define R_ASSERT(res_expr) \ - ({ \ + { \ if (const auto _tmp_r_assert_rc = (res_expr); AMS_UNLIKELY(R_FAILED(_tmp_r_assert_rc))) { \ AMS_CALL_ON_RESULT_ASSERTION_IMPL(#res_expr, _tmp_r_assert_rc); \ } \ - }) + } #else #define R_ASSERT(res_expr) AMS_UNUSED((res_expr)); #endif /// Evaluates an expression that returns a result, and aborts if the result would fail. #define R_ABORT_UNLESS(res_expr) \ - ({ \ + { \ if (const auto _tmp_r_abort_rc = (res_expr); AMS_UNLIKELY(R_FAILED(_tmp_r_abort_rc))) { \ AMS_CALL_ON_RESULT_ABORT_IMPL(#res_expr, _tmp_r_abort_rc); \ } \ - }) + } /// Evaluates a boolean expression, and returns a result unless that expression is true. #define R_UNLESS(expr, res) \ - ({ \ + { \ if (!(expr)) { \ R_THROW(res); \ } \ - }) + } /// Evaluates a boolean expression, and succeeds if that expression is true. #define R_SUCCEED_IF(expr) R_UNLESS(!(expr), ResultSuccess()) @@ -415,24 +428,24 @@ namespace ams::result::impl { /// Helpers for pattern-matching on a result expression, if the result would fail. #define R_CURRENT_RESULT _tmp_r_try_catch_current_result -#define R_TRY_CATCH(res_expr) \ - ({ \ +#define R_TRY_CATCH(res_expr) \ + { \ const auto R_CURRENT_RESULT = (res_expr); \ - if (R_FAILED(R_CURRENT_RESULT)) { \ + if (R_FAILED(R_CURRENT_RESULT)) { \ if (false) -#define R_CATCH(...) \ +#define R_CATCH(...) \ } else if (::ams::result::impl::EvaluateAnyResultIncludes<__VA_ARGS__>(R_CURRENT_RESULT)) { \ if (true) -#define R_CATCH_MODULE(__module__) \ +#define R_CATCH_MODULE(__module__) \ } else if ((R_CURRENT_RESULT).GetModule() == ::ams::R_NAMESPACE_MODULE_ID(__module__)) { \ if (true) #define R_CONVERT(catch_type, convert_type) \ R_CATCH(catch_type) { R_THROW(static_cast<::ams::Result>(convert_type)); } -#define R_CATCH_ALL() \ +#define R_CATCH_ALL() \ } else if (R_FAILED(R_CURRENT_RESULT)) { \ if (true) @@ -442,26 +455,26 @@ namespace ams::result::impl { #define R_CATCH_RETHROW(catch_type) \ R_CONVERT(catch_type, R_CURRENT_RESULT) -#define R_END_TRY_CATCH \ +#define R_END_TRY_CATCH \ else if (R_FAILED(R_CURRENT_RESULT)) { \ - R_THROW(R_CURRENT_RESULT); \ - } \ - } \ - }) + R_THROW(R_CURRENT_RESULT); \ + } \ + } \ + } -#define R_END_TRY_CATCH_WITH_ASSERT \ - else { \ +#define R_END_TRY_CATCH_WITH_ASSERT \ + else { \ R_ASSERT(R_CURRENT_RESULT); \ - } \ - } \ - }) + } \ + } \ + } -#define R_END_TRY_CATCH_WITH_ABORT_UNLESS \ - else { \ +#define R_END_TRY_CATCH_WITH_ABORT_UNLESS \ + else { \ R_ABORT_UNLESS(R_CURRENT_RESULT); \ - } \ - } \ - }) + } \ + } \ + } diff --git a/libraries/libvapours/include/vapours/svc.hpp b/libraries/libvapours/include/vapours/svc.hpp index 6bb7003e2..657a6f5d1 100644 --- a/libraries/libvapours/include/vapours/svc.hpp +++ b/libraries/libvapours/include/vapours/svc.hpp @@ -19,8 +19,10 @@ #include #include +#if defined(ATMOSPHERE_OS_HORIZON) #include #include #include #include #include +#endif \ No newline at end of file diff --git a/libraries/libvapours/include/vapours/types.hpp b/libraries/libvapours/include/vapours/types.hpp index 364455805..e7b75a8f0 100644 --- a/libraries/libvapours/include/vapours/types.hpp +++ b/libraries/libvapours/include/vapours/types.hpp @@ -17,7 +17,6 @@ #include #include #include -#include /* NOTE: This file serves as a substitute for libnx . */ diff --git a/libraries/libvapours/include/vapours/util/arch/arm64/util_atomic.hpp b/libraries/libvapours/include/vapours/util/arch/arm64/util_atomic.hpp index 27fc7eb9c..543126026 100644 --- a/libraries/libvapours/include/vapours/util/arch/arm64/util_atomic.hpp +++ b/libraries/libvapours/include/vapours/util/arch/arm64/util_atomic.hpp @@ -52,7 +52,9 @@ namespace ams::util { template using AtomicStorage = typename AtomicIntegerStorage::Type; - static_assert(std::same_as, uintptr_t>); + + static_assert(std::same_as, u64>); + static_assert(std::same_as, u8>); static_assert(std::same_as, u8>); static_assert(std::same_as, u16>); diff --git a/libraries/libvapours/include/vapours/util/arch/generic/util_atomic.hpp b/libraries/libvapours/include/vapours/util/arch/generic/util_atomic.hpp index e44df5600..a3af22266 100644 --- a/libraries/libvapours/include/vapours/util/arch/generic/util_atomic.hpp +++ b/libraries/libvapours/include/vapours/util/arch/generic/util_atomic.hpp @@ -83,7 +83,7 @@ namespace ams::util { template ALWAYS_INLINE void Store(T arg) { - return m_v.store(Order); + return m_v.store(arg, Order); } template @@ -135,6 +135,8 @@ namespace ams::util { ALWAYS_INLINE T operator--(int) { static_assert(Enable == HasArithmeticFunctions); return this->FetchSub(1); } }; + /* TODO: Clang does not yet define std::atomic_ref, so if we want this we will have to implement it ourselves. */ + #if !defined(ATMOSPHERE_COMPILER_CLANG) template class AtomicRef { NON_MOVEABLE(AtomicRef); @@ -218,6 +220,7 @@ namespace ams::util { template::type> ALWAYS_INLINE T operator--(int) const { static_assert(Enable == HasArithmeticFunctions); return this->FetchSub(1); } }; + #endif } \ No newline at end of file diff --git a/libraries/libvapours/include/vapours/util/util_alignment.hpp b/libraries/libvapours/include/vapours/util/util_alignment.hpp index 2e1ed5e09..017c82ce2 100644 --- a/libraries/libvapours/include/vapours/util/util_alignment.hpp +++ b/libraries/libvapours/include/vapours/util/util_alignment.hpp @@ -49,32 +49,32 @@ namespace ams::util { } template<> - constexpr ALWAYS_INLINE void *AlignUp(void *value, size_t alignment) { + ALWAYS_INLINE void *AlignUp(void *value, size_t alignment) { return reinterpret_cast(AlignUp(reinterpret_cast(value), alignment)); } template<> - constexpr ALWAYS_INLINE const void *AlignUp(const void *value, size_t alignment) { + ALWAYS_INLINE const void *AlignUp(const void *value, size_t alignment) { return reinterpret_cast(AlignUp(reinterpret_cast(value), alignment)); } template<> - constexpr ALWAYS_INLINE void *AlignDown(void *value, size_t alignment) { + ALWAYS_INLINE void *AlignDown(void *value, size_t alignment) { return reinterpret_cast(AlignDown(reinterpret_cast(value), alignment)); } template<> - constexpr ALWAYS_INLINE const void *AlignDown(const void *value, size_t alignment) { + ALWAYS_INLINE const void *AlignDown(const void *value, size_t alignment) { return reinterpret_cast(AlignDown(reinterpret_cast(value), alignment)); } template<> - constexpr ALWAYS_INLINE bool IsAligned(void *value, size_t alignment) { + ALWAYS_INLINE bool IsAligned(void *value, size_t alignment) { return IsAligned(reinterpret_cast(value), alignment); } template<> - constexpr ALWAYS_INLINE bool IsAligned(const void *value, size_t alignment) { + ALWAYS_INLINE bool IsAligned(const void *value, size_t alignment) { return IsAligned(reinterpret_cast(value), alignment); } diff --git a/libraries/libvapours/include/vapours/util/util_character_encoding.hpp b/libraries/libvapours/include/vapours/util/util_character_encoding.hpp index 95c0c53a3..60087b0e7 100644 --- a/libraries/libvapours/include/vapours/util/util_character_encoding.hpp +++ b/libraries/libvapours/include/vapours/util/util_character_encoding.hpp @@ -26,8 +26,143 @@ namespace ams::util { CharacterEncodingResult_InvalidFormat = 2, }; - CharacterEncodingResult ConvertCharacterUtf8ToUtf32(u32 *dst, const char *src); + namespace impl { - CharacterEncodingResult PickOutCharacterFromUtf8String(char *dst, const char **str); + class CharacterEncodingHelper { + public: + static constexpr int8_t Utf8NBytesInnerTable[0x100 + 1] = { + -1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8, + }; + + static constexpr ALWAYS_INLINE char GetUtf8NBytes(size_t i) { + return static_cast(Utf8NBytesInnerTable[1 + i]); + } + }; + + } + + constexpr inline CharacterEncodingResult ConvertCharacterUtf8ToUtf32(u32 *dst, const char *src) { + /* Check pre-conditions. */ + AMS_ASSERT(dst != nullptr); + AMS_ASSERT(src != nullptr); + + /* Perform the conversion. */ + const auto *p = src; + switch (impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast(p[0]))) { + case 1: + *dst = static_cast(p[0]); + return CharacterEncodingResult_Success; + case 2: + if ((static_cast(p[0]) & 0x1E) != 0) { + if (impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast(p[1])) == 0) { + *dst = (static_cast(p[0] & 0x1F) << 6) | (static_cast(p[1] & 0x3F) << 0); + return CharacterEncodingResult_Success; + } + } + break; + case 3: + if (impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast(p[1])) == 0 && impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast(p[2])) == 0) { + const u32 c = (static_cast(p[0] & 0xF) << 12) | (static_cast(p[1] & 0x3F) << 6) | (static_cast(p[2] & 0x3F) << 0); + if ((c & 0xF800) != 0 && (c & 0xF800) != 0xD800) { + *dst = c; + return CharacterEncodingResult_Success; + } + } + return CharacterEncodingResult_InvalidFormat; + case 4: + if (impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast(p[1])) == 0 && impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast(p[2])) == 0 && impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast(p[3])) == 0) { + const u32 c = (static_cast(p[0] & 0x7) << 18) | (static_cast(p[1] & 0x3F) << 12) | (static_cast(p[2] & 0x3F) << 6) | (static_cast(p[3] & 0x3F) << 0); + if (c >= 0x10000 && c < 0x110000) { + *dst = c; + return CharacterEncodingResult_Success; + } + } + return CharacterEncodingResult_InvalidFormat; + default: + break; + } + + /* We failed to convert. */ + return CharacterEncodingResult_InvalidFormat; + } + + constexpr inline CharacterEncodingResult PickOutCharacterFromUtf8String(char *dst, const char **str) { + /* Check pre-conditions. */ + AMS_ASSERT(dst != nullptr); + AMS_ASSERT(str != nullptr); + AMS_ASSERT(*str != nullptr); + + /* Clear the output. */ + dst[0] = 0; + dst[1] = 0; + dst[2] = 0; + dst[3] = 0; + + /* Perform the conversion. */ + const auto *p = *str; + u32 c = static_cast(*p); + switch (impl::CharacterEncodingHelper::GetUtf8NBytes(c)) { + case 1: + dst[0] = (*str)[0]; + ++(*str); + break; + case 2: + if ((p[0] & 0x1E) != 0) { + if (impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast(p[1])) == 0) { + c = (static_cast(p[0] & 0x1F) << 6) | (static_cast(p[1] & 0x3F) << 0); + dst[0] = (*str)[0]; + dst[1] = (*str)[1]; + (*str) += 2; + break; + } + } + return CharacterEncodingResult_InvalidFormat; + case 3: + if (impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast(p[1])) == 0 && impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast(p[2])) == 0) { + c = (static_cast(p[0] & 0xF) << 12) | (static_cast(p[1] & 0x3F) << 6) | (static_cast(p[2] & 0x3F) << 0); + if ((c & 0xF800) != 0 && (c & 0xF800) != 0xD800) { + dst[0] = (*str)[0]; + dst[1] = (*str)[1]; + dst[2] = (*str)[2]; + (*str) += 3; + break; + } + } + return CharacterEncodingResult_InvalidFormat; + case 4: + if (impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast(p[1])) == 0 && impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast(p[2])) == 0 && impl::CharacterEncodingHelper::GetUtf8NBytes(static_cast(p[3])) == 0) { + c = (static_cast(p[0] & 0x7) << 18) | (static_cast(p[1] & 0x3F) << 12) | (static_cast(p[2] & 0x3F) << 6) | (static_cast(p[3] & 0x3F) << 0); + if (c >= 0x10000 && c < 0x110000) { + dst[0] = (*str)[0]; + dst[1] = (*str)[1]; + dst[2] = (*str)[2]; + dst[3] = (*str)[3]; + (*str) += 4; + break; + } + } + return CharacterEncodingResult_InvalidFormat; + default: + return CharacterEncodingResult_InvalidFormat; + } + + return CharacterEncodingResult_Success; + } } diff --git a/libraries/libvapours/include/vapours/util/util_intrusive_list.hpp b/libraries/libvapours/include/vapours/util/util_intrusive_list.hpp index 5d9576430..271db8c07 100644 --- a/libraries/libvapours/include/vapours/util/util_intrusive_list.hpp +++ b/libraries/libvapours/include/vapours/util/util_intrusive_list.hpp @@ -21,8 +21,7 @@ namespace ams::util { - #pragma GCC push_options - #pragma GCC optimize ("-O3") + AMS_PRAGMA_BEGIN_OPTIMIZE_O3() /* Forward declare implementation class for Node. */ namespace impl { @@ -627,6 +626,6 @@ namespace ams::util { } }; - #pragma GCC pop_options + AMS_PRAGMA_END_OPTIMIZE() } \ No newline at end of file diff --git a/libraries/libvapours/include/vapours/util/util_intrusive_red_black_tree.hpp b/libraries/libvapours/include/vapours/util/util_intrusive_red_black_tree.hpp index 00a7201e3..e8a3963e4 100644 --- a/libraries/libvapours/include/vapours/util/util_intrusive_red_black_tree.hpp +++ b/libraries/libvapours/include/vapours/util/util_intrusive_red_black_tree.hpp @@ -22,8 +22,7 @@ namespace ams::util { - #pragma GCC push_options - #pragma GCC optimize ("-O3") + AMS_PRAGMA_BEGIN_OPTIMIZE_O3() namespace impl { @@ -583,6 +582,6 @@ namespace ams::util { } }; - #pragma GCC pop_options + AMS_PRAGMA_END_OPTIMIZE() } diff --git a/libraries/libvapours/include/vapours/util/util_parent_of_member.hpp b/libraries/libvapours/include/vapours/util/util_parent_of_member.hpp index fb4ea630d..029e9746e 100644 --- a/libraries/libvapours/include/vapours/util/util_parent_of_member.hpp +++ b/libraries/libvapours/include/vapours/util/util_parent_of_member.hpp @@ -124,17 +124,47 @@ namespace ams::util { template> requires (std::derived_from> || std::same_as>) struct OffsetOf : public std::integral_constant, MemberPtr>::Value> {}; + #if defined(ATMOSPHERE_COMPILER_CLANG) + template + struct OffsetOfCalculatorTheSadWayForClangSupport { + static ALWAYS_INLINE std::ptrdiff_t Calculate() { + const union Union { + ParentType p; + char c; + + Union() : c() { /* ... */ } + ~Union() { /* ... */ } + } U; + + const auto *parent = std::addressof(U.p); + const auto *target = std::addressof(parent->*Ptr); + + return static_cast(static_cast(target)) - static_cast(static_cast(parent)); + } + }; + #endif + } template> ALWAYS_INLINE RealParentType &GetParentReference(impl::GetMemberType *member) { + /* TODO: If clang resolves compiler-bugs in consteval (or if my std proposal makes it into a future C++ standard), we should go back to constexpr. */ + #if defined(ATMOSPHERE_COMPILER_CLANG) + const std::ptrdiff_t Offset = impl::OffsetOfCalculatorTheSadWayForClangSupport, MemberPtr>::Calculate(); + #else constexpr std::ptrdiff_t Offset = impl::OffsetOf::value; + #endif return *static_cast(static_cast(static_cast(static_cast(member)) - Offset)); } template> ALWAYS_INLINE RealParentType const &GetParentReference(impl::GetMemberType const *member) { + /* TODO: If clang resolves compiler-bugs in consteval (or if my std proposal makes it into a future C++ standard), we should go back to constexpr. */ + #if defined(ATMOSPHERE_COMPILER_CLANG) + const std::ptrdiff_t Offset = impl::OffsetOfCalculatorTheSadWayForClangSupport, MemberPtr>::Calculate(); + #else constexpr std::ptrdiff_t Offset = impl::OffsetOf::value; + #endif return *static_cast(static_cast(static_cast(static_cast(member)) - Offset)); } diff --git a/libraries/libvapours/include/vapours/util/util_string_util.hpp b/libraries/libvapours/include/vapours/util/util_string_util.hpp index be7a22aab..67f799dd4 100644 --- a/libraries/libvapours/include/vapours/util/util_string_util.hpp +++ b/libraries/libvapours/include/vapours/util/util_string_util.hpp @@ -88,6 +88,18 @@ namespace ams::util { return static_cast(cur - src); } + template + constexpr int Strlen(const T *str) { + AMS_ASSERT(str != nullptr); + + int length = 0; + while (*str++) { + ++length; + } + + return length; + } + template constexpr int Strnlen(const T *str, int count) { AMS_ASSERT(str != nullptr); @@ -101,4 +113,50 @@ namespace ams::util { return length; } + #if defined(ATMOSPHERE_IS_STRATOSPHERE) + ALWAYS_INLINE void *Memchr(void *s, int c, size_t n) { + return const_cast(::memchr(s, c, n)); + } + + ALWAYS_INLINE const void *Memchr(const void *s, int c, size_t n) { + return ::memchr(s, c, n); + } + + inline void *Memrchr(void *s, int c, size_t n) { + #if !(defined(__MINGW32__) || defined(__MINGW64__) || defined(ATMOSPHERE_OS_MACOS)) + return const_cast(::memrchr(s, c, n)); + #else + /* TODO: Optimized implementation? */ + if (AMS_LIKELY(n > 0)) { + const u8 *p = static_cast(s); + const u8 v = static_cast(c); + while ((n--) != 0) { + if (p[n] == v) { + return const_cast(static_cast(p + n)); + } + } + } + return nullptr; + #endif + } + + inline const void *Memrchr(const void *s, int c, size_t n) { + #if !(defined(__MINGW32__) || defined(__MINGW64__) || defined(ATMOSPHERE_OS_MACOS)) + return ::memrchr(s, c, n); + #else + /* TODO: Optimized implementation? */ + if (AMS_LIKELY(n > 0)) { + const u8 *p = static_cast(s); + const u8 v = static_cast(c); + while ((n--) != 0) { + if (p[n] == v) { + return static_cast(p + n); + } + } + } + return nullptr; + #endif + } + #endif + } diff --git a/libraries/libvapours/source/crypto/crypto_hmac_sha1_generator.cpp b/libraries/libvapours/source/crypto/crypto_hmac_sha1_generator.cpp index 8518a1ac4..9e1ffec81 100644 --- a/libraries/libvapours/source/crypto/crypto_hmac_sha1_generator.cpp +++ b/libraries/libvapours/source/crypto/crypto_hmac_sha1_generator.cpp @@ -17,7 +17,7 @@ namespace ams::crypto { - void GenerateHmacSha1Mac(void *dst, size_t dst_size, const void *data, size_t data_size, const void *key, size_t key_size) { + void GenerateHmacSha1(void *dst, size_t dst_size, const void *data, size_t data_size, const void *key, size_t key_size) { HmacSha1Generator hmac; hmac.Initialize(key, key_size); diff --git a/libraries/libvapours/source/crypto/crypto_hmac_sha256_generator.cpp b/libraries/libvapours/source/crypto/crypto_hmac_sha256_generator.cpp index 6bec307d7..e430de282 100644 --- a/libraries/libvapours/source/crypto/crypto_hmac_sha256_generator.cpp +++ b/libraries/libvapours/source/crypto/crypto_hmac_sha256_generator.cpp @@ -17,7 +17,7 @@ namespace ams::crypto { - void GenerateHmacSha256Mac(void *dst, size_t dst_size, const void *data, size_t data_size, const void *key, size_t key_size) { + void GenerateHmacSha256(void *dst, size_t dst_size, const void *data, size_t data_size, const void *key, size_t key_size) { HmacSha256Generator hmac; hmac.Initialize(key, key_size); diff --git a/libraries/libvapours/source/crypto/crypto_md5_generator.cpp b/libraries/libvapours/source/crypto/crypto_md5_generator.cpp index a04aa5709..8c1b9b4db 100644 --- a/libraries/libvapours/source/crypto/crypto_md5_generator.cpp +++ b/libraries/libvapours/source/crypto/crypto_md5_generator.cpp @@ -17,7 +17,7 @@ namespace ams::crypto { - void GenerateMd5Hash(void *dst, size_t dst_size, const void *src, size_t src_size) { + void GenerateMd5(void *dst, size_t dst_size, const void *src, size_t src_size) { Md5Generator gen; gen.Initialize(); diff --git a/libraries/libvapours/source/crypto/crypto_sha1_generator.cpp b/libraries/libvapours/source/crypto/crypto_sha1_generator.cpp index 79afe2c4f..575dc384c 100644 --- a/libraries/libvapours/source/crypto/crypto_sha1_generator.cpp +++ b/libraries/libvapours/source/crypto/crypto_sha1_generator.cpp @@ -17,7 +17,7 @@ namespace ams::crypto { - void GenerateSha1Hash(void *dst, size_t dst_size, const void *src, size_t src_size) { + void GenerateSha1(void *dst, size_t dst_size, const void *src, size_t src_size) { Sha1Generator gen; gen.Initialize(); diff --git a/libraries/libvapours/source/crypto/crypto_sha256_generator.cpp b/libraries/libvapours/source/crypto/crypto_sha256_generator.cpp index fe98e8013..2d2488e06 100644 --- a/libraries/libvapours/source/crypto/crypto_sha256_generator.cpp +++ b/libraries/libvapours/source/crypto/crypto_sha256_generator.cpp @@ -17,7 +17,7 @@ namespace ams::crypto { - void GenerateSha256Hash(void *dst, size_t dst_size, const void *src, size_t src_size) { + void GenerateSha256(void *dst, size_t dst_size, const void *src, size_t src_size) { Sha256Generator gen; gen.Initialize(); diff --git a/libraries/libvapours/source/crypto/impl/crypto_aes_impl.arch.arm64.cpp b/libraries/libvapours/source/crypto/impl/crypto_aes_impl.arch.arm64.cpp index 24bc8782c..af32910e7 100644 --- a/libraries/libvapours/source/crypto/impl/crypto_aes_impl.arch.arm64.cpp +++ b/libraries/libvapours/source/crypto/impl/crypto_aes_impl.arch.arm64.cpp @@ -14,15 +14,111 @@ * along with this program. If not, see . */ #include +#if defined(ATMOSPHERE_IS_STRATOSPHERE) +#include +#endif namespace ams::crypto::impl { -#ifdef ATMOSPHERE_IS_STRATOSPHERE +#if defined(ATMOSPHERE_IS_STRATOSPHERE) + namespace { - constexpr bool IsSupportedKeySize(size_t size) { - return size == 16 || size == 24 || size == 32; + /* Helper macros to setup for inline AES asm */ + #define AES_ENC_DEC_SETUP_VARS() \ + const auto *ctx = reinterpret_cast *>(m_round_keys); \ + static_assert(sizeof(*ctx) == sizeof(m_round_keys)); \ + \ + uint8x16_t tmp = vld1q_u8((const uint8_t *)src); \ + uint8x16_t tmp2 + + #define AES_ENC_DEC_OUTPUT_VARS() \ + [tmp]"+w"(tmp), [tmp2]"=w"(tmp2) + + #define AES_ENC_DEC_STORE_RESULT() \ + vst1q_u8((uint8_t *)dst, tmp) + + /* Helper macros to do AES encryption, via inline asm. */ + #define AES_ENC_ROUND(n) \ + "ldr %q[tmp2], %[round_key_" #n "]\n" \ + "aese %[tmp].16b, %[tmp2].16b\n" \ + "aesmc %[tmp].16b, %[tmp].16b\n" + + #define AES_ENC_FINAL_ROUND() \ + "ldr %q[tmp2], %[round_key_second_last]\n" \ + "aese %[tmp].16b, %[tmp2].16b\n" \ + "ldr %q[tmp2], %[round_key_last]\n" \ + "eor %[tmp].16b, %[tmp].16b, %[tmp2].16b" + + #define AES_ENC_INPUT_ROUND_KEY(num_rounds, n) \ + [round_key_##n]"m"(ctx->round_keys[(n-1)]) + + #define AES_ENC_INPUT_LAST_ROUND_KEYS(num_rounds) \ + [round_key_second_last]"m"(ctx->round_keys[(num_rounds - 1)]), \ + [round_key_last]"m"(ctx->round_keys[(num_rounds)]) + + /* Helper macros to do AES decryption, via inline asm. */ + #define AES_DEC_ROUND(n) \ + "ldr %q[tmp2], %[round_key_" #n "]\n" \ + "aesd %[tmp].16b, %[tmp2].16b\n" \ + "aesimc %[tmp].16b, %[tmp].16b\n" + + #define AES_DEC_FINAL_ROUND() \ + "ldr %q[tmp2], %[round_key_second_last]\n" \ + "aesd %[tmp].16b, %[tmp2].16b\n" \ + "ldr %q[tmp2], %[round_key_last]\n" \ + "eor %[tmp].16b, %[tmp].16b, %[tmp2].16b" + + #define AES_DEC_INPUT_ROUND_KEY(num_rounds, n) \ + [round_key_##n]"m"(ctx->round_keys[(num_rounds + 1 - n)]) + + #define AES_DEC_INPUT_LAST_ROUND_KEYS(num_rounds) \ + [round_key_second_last]"m"(ctx->round_keys[1]), \ + [round_key_last]"m"(ctx->round_keys[0]) + + + constexpr const u8 RoundKeyRcon0[] = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36, 0x6C, 0xD8, 0xAB, 0x4D, 0x9A, 0x2F, + 0x5E, 0xBC, 0x63, 0xC6, 0x97, 0x35, 0x6A, 0xD4, 0xB3, 0x7D, 0xFA, 0xEF, 0xC5, 0x91, + }; + + constexpr const u8 SubBytesTable[0x100] = { + 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, + 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, + 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, + 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, + 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, + 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, + 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, + 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, + 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, + 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, + 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, + 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, + 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, + 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, + 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, + 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16, + }; + + constexpr auto AesWordByte0Shift = 0 * BITSIZEOF(u8); + constexpr auto AesWordByte1Shift = 1 * BITSIZEOF(u8); + constexpr auto AesWordByte2Shift = 2 * BITSIZEOF(u8); + constexpr auto AesWordByte3Shift = 3 * BITSIZEOF(u8); + + constexpr u32 SubBytesAndRotate(u32 v) { + return (static_cast(SubBytesTable[(v >> AesWordByte0Shift) & 0xFFu]) << AesWordByte3Shift) ^ + (static_cast(SubBytesTable[(v >> AesWordByte1Shift) & 0xFFu]) << AesWordByte0Shift) ^ + (static_cast(SubBytesTable[(v >> AesWordByte2Shift) & 0xFFu]) << AesWordByte1Shift) ^ + (static_cast(SubBytesTable[(v >> AesWordByte3Shift) & 0xFFu]) << AesWordByte2Shift); + } + + constexpr u32 SubBytes(u32 v) { + return (static_cast(SubBytesTable[(v >> AesWordByte0Shift) & 0xFFu]) << AesWordByte0Shift) ^ + (static_cast(SubBytesTable[(v >> AesWordByte1Shift) & 0xFFu]) << AesWordByte1Shift) ^ + (static_cast(SubBytesTable[(v >> AesWordByte2Shift) & 0xFFu]) << AesWordByte2Shift) ^ + (static_cast(SubBytesTable[(v >> AesWordByte3Shift) & 0xFFu]) << AesWordByte3Shift); } } @@ -34,78 +130,360 @@ namespace ams::crypto::impl { template void AesImpl::Initialize(const void *key, size_t key_size, bool is_encrypt) { - static_assert(IsSupportedKeySize(KeySize)); + /* Check pre-conditions. */ AMS_ASSERT(key_size == KeySize); AMS_UNUSED(key_size); - if constexpr (KeySize == 16) { - /* Aes 128. */ - static_assert(sizeof(m_round_keys) == sizeof(::Aes128Context)); - aes128ContextCreate(reinterpret_cast(m_round_keys), key, is_encrypt); - } else if constexpr (KeySize == 24) { - /* Aes 192. */ - static_assert(sizeof(m_round_keys) == sizeof(::Aes192Context)); - aes192ContextCreate(reinterpret_cast(m_round_keys), key, is_encrypt); - } else if constexpr (KeySize == 32) { - /* Aes 256. */ - static_assert(sizeof(m_round_keys) == sizeof(::Aes256Context)); - aes256ContextCreate(reinterpret_cast(m_round_keys), key, is_encrypt); - } else { - /* Invalid key size. */ - static_assert(!std::is_same, AesImpl>::value); + /* Set up key. */ + u32 *dst = m_round_keys; + std::memcpy(dst, key, KeySize); + + /* Perform key scheduling. */ + constexpr auto InitialKeyWords = KeySize / sizeof(u32); + u32 tmp = dst[InitialKeyWords - 1]; + + for (auto i = InitialKeyWords; i < (RoundCount + 1) * 4; ++i) { + const auto idx_in_key = i % InitialKeyWords; + if (idx_in_key == 0) { + /* At start of key word, we need to handle sub/rotate/rcon. */ + tmp = SubBytesAndRotate(tmp); + tmp ^= (RoundKeyRcon0[i / InitialKeyWords - 1] << AesWordByte0Shift); + } else if ((InitialKeyWords > 6) && idx_in_key == 4) { + /* Halfway into a 256-bit key word, we need to do an additional subbytes. */ + tmp = SubBytes(tmp); + } + + /* Set the key word. */ + tmp ^= dst[i - InitialKeyWords]; + dst[i] = tmp; + } + + /* If decrypting, perform inverse mix columns on all round keys. */ + if (!is_encrypt) { + auto *key8 = reinterpret_cast(m_round_keys) + BlockSize; + + for (auto i = 1; i < RoundCount; ++i) { + vst1q_u8(key8, vaesimcq_u8(vld1q_u8(key8))); + key8 += BlockSize; + } } } template void AesImpl::EncryptBlock(void *dst, size_t dst_size, const void *src, size_t src_size) const { - static_assert(IsSupportedKeySize(KeySize)); - AMS_ASSERT(src_size >= BlockSize); - AMS_ASSERT(dst_size >= BlockSize); AMS_UNUSED(src_size, dst_size); - if constexpr (KeySize == 16) { - /* Aes 128. */ - static_assert(sizeof(m_round_keys) == sizeof(::Aes128Context)); - aes128EncryptBlock(reinterpret_cast(m_round_keys), dst, src); - } else if constexpr (KeySize == 24) { - /* Aes 192. */ - static_assert(sizeof(m_round_keys) == sizeof(::Aes192Context)); - aes192EncryptBlock(reinterpret_cast(m_round_keys), dst, src); - } else if constexpr (KeySize == 32) { - /* Aes 256. */ - static_assert(sizeof(m_round_keys) == sizeof(::Aes256Context)); - aes256EncryptBlock(reinterpret_cast(m_round_keys), dst, src); - } else { - /* Invalid key size. */ - static_assert(!std::is_same, AesImpl>::value); + /* Get the key. */ + const u8 *key8 = reinterpret_cast(m_round_keys); + + /* Read the block. */ + uint8x16_t block = vld1q_u8(static_cast(src)); + + /* Encrypt block. */ + for (auto round = 1; round < RoundCount; ++round) { + /* Do aes round. */ + block = vaeseq_u8(block, vld1q_u8(key8)); + key8 += BlockSize; + + /* Do mix columns. */ + block = vaesmcq_u8(block); } + + /* Do last aes round. */ + block = vaeseq_u8(block, vld1q_u8(key8)); + key8 += BlockSize; + + /* Add the final round key. */ + block = veorq_u8(block, vld1q_u8(key8)); + + /* Store the block. */ + vst1q_u8(static_cast(dst), block); } template void AesImpl::DecryptBlock(void *dst, size_t dst_size, const void *src, size_t src_size) const { - static_assert(IsSupportedKeySize(KeySize)); - AMS_ASSERT(src_size >= BlockSize); - AMS_ASSERT(dst_size >= BlockSize); AMS_UNUSED(src_size, dst_size); - if constexpr (KeySize == 16) { - /* Aes 128. */ - static_assert(sizeof(m_round_keys) == sizeof(::Aes128Context)); - aes128DecryptBlock(reinterpret_cast(m_round_keys), dst, src); - } else if constexpr (KeySize == 24) { - /* Aes 192. */ - static_assert(sizeof(m_round_keys) == sizeof(::Aes192Context)); - aes192DecryptBlock(reinterpret_cast(m_round_keys), dst, src); - } else if constexpr (KeySize == 32) { - /* Aes 256. */ - static_assert(sizeof(m_round_keys) == sizeof(::Aes256Context)); - aes256DecryptBlock(reinterpret_cast(m_round_keys), dst, src); - } else { - /* Invalid key size. */ - static_assert(!std::is_same, AesImpl>::value); + /* Get the key. */ + const u8 *key8 = reinterpret_cast(m_round_keys) + (RoundCount + BlockSize); + + /* Read the block. */ + uint8x16_t block = vld1q_u8(static_cast(src)); + + /* Encrypt block. */ + for (auto round = RoundCount; round > 1; --round) { + /* Do aes round. */ + block = vaesdq_u8(block, vld1q_u8(key8)); + key8 -= BlockSize; + + /* Do mix columns. */ + block = vaesimcq_u8(block); } + + /* Do last aes round. */ + block = vaesdq_u8(block, vld1q_u8(key8)); + key8 -= BlockSize; + + /* Add the first round key. */ + block = veorq_u8(block, vld1q_u8(key8)); + + /* Store the block. */ + vst1q_u8(static_cast(dst), block); } + /* Specializations when building specifically for cortex-a57 (or for apple M* processors). */ + #if defined(ATMOSPHERE_CPU_CORTEX_A57) || defined(ATMOSPHERE_OS_MACOS) + + namespace { + + template + struct RoundKeyHelper { + u8 round_keys[AesImpl::RoundCount + 1][AesImpl::BlockSize]; + }; + + } + + template<> + void AesImpl<16>::EncryptBlock(void *dst, size_t dst_size, const void *src, size_t src_size) const { + AMS_UNUSED(src_size, dst_size); + + /* Setup for asm */ + AES_ENC_DEC_SETUP_VARS(); + + /* Use optimized assembly to do all rounds. */ + __asm__ __volatile__ ( + AES_ENC_ROUND(1) + AES_ENC_ROUND(2) + AES_ENC_ROUND(3) + AES_ENC_ROUND(4) + AES_ENC_ROUND(5) + AES_ENC_ROUND(6) + AES_ENC_ROUND(7) + AES_ENC_ROUND(8) + AES_ENC_ROUND(9) + AES_ENC_FINAL_ROUND() + : AES_ENC_DEC_OUTPUT_VARS() + : AES_ENC_INPUT_ROUND_KEY(RoundCount, 1), + AES_ENC_INPUT_ROUND_KEY(RoundCount, 2), + AES_ENC_INPUT_ROUND_KEY(RoundCount, 3), + AES_ENC_INPUT_ROUND_KEY(RoundCount, 4), + AES_ENC_INPUT_ROUND_KEY(RoundCount, 5), + AES_ENC_INPUT_ROUND_KEY(RoundCount, 6), + AES_ENC_INPUT_ROUND_KEY(RoundCount, 7), + AES_ENC_INPUT_ROUND_KEY(RoundCount, 8), + AES_ENC_INPUT_ROUND_KEY(RoundCount, 9), + AES_ENC_INPUT_LAST_ROUND_KEYS(RoundCount) + ); + + /* Store result. */ + AES_ENC_DEC_STORE_RESULT(); + } + + template<> + void AesImpl<24>::EncryptBlock(void *dst, size_t dst_size, const void *src, size_t src_size) const { + AMS_UNUSED(src_size, dst_size); + + /* Setup for asm */ + AES_ENC_DEC_SETUP_VARS(); + + /* Use optimized assembly to do all rounds. */ + __asm__ __volatile__ ( + AES_ENC_ROUND(1) + AES_ENC_ROUND(2) + AES_ENC_ROUND(3) + AES_ENC_ROUND(4) + AES_ENC_ROUND(5) + AES_ENC_ROUND(6) + AES_ENC_ROUND(7) + AES_ENC_ROUND(8) + AES_ENC_ROUND(9) + AES_ENC_ROUND(10) + AES_ENC_ROUND(11) + AES_ENC_FINAL_ROUND() + : AES_ENC_DEC_OUTPUT_VARS() + : AES_ENC_INPUT_ROUND_KEY(RoundCount, 1), + AES_ENC_INPUT_ROUND_KEY(RoundCount, 2), + AES_ENC_INPUT_ROUND_KEY(RoundCount, 3), + AES_ENC_INPUT_ROUND_KEY(RoundCount, 4), + AES_ENC_INPUT_ROUND_KEY(RoundCount, 5), + AES_ENC_INPUT_ROUND_KEY(RoundCount, 6), + AES_ENC_INPUT_ROUND_KEY(RoundCount, 7), + AES_ENC_INPUT_ROUND_KEY(RoundCount, 8), + AES_ENC_INPUT_ROUND_KEY(RoundCount, 9), + AES_ENC_INPUT_ROUND_KEY(RoundCount, 10), + AES_ENC_INPUT_ROUND_KEY(RoundCount, 11), + AES_ENC_INPUT_LAST_ROUND_KEYS(RoundCount) + ); + + /* Store result. */ + AES_ENC_DEC_STORE_RESULT(); + } + + template<> + void AesImpl<32>::EncryptBlock(void *dst, size_t dst_size, const void *src, size_t src_size) const { + AMS_UNUSED(src_size, dst_size); + + /* Setup for asm */ + AES_ENC_DEC_SETUP_VARS(); + + /* Use optimized assembly to do all rounds. */ + __asm__ __volatile__ ( + AES_ENC_ROUND(1) + AES_ENC_ROUND(2) + AES_ENC_ROUND(3) + AES_ENC_ROUND(4) + AES_ENC_ROUND(5) + AES_ENC_ROUND(6) + AES_ENC_ROUND(7) + AES_ENC_ROUND(8) + AES_ENC_ROUND(9) + AES_ENC_ROUND(10) + AES_ENC_ROUND(11) + AES_ENC_ROUND(12) + AES_ENC_ROUND(13) + AES_ENC_FINAL_ROUND() + : AES_ENC_DEC_OUTPUT_VARS() + : AES_ENC_INPUT_ROUND_KEY(RoundCount, 1), + AES_ENC_INPUT_ROUND_KEY(RoundCount, 2), + AES_ENC_INPUT_ROUND_KEY(RoundCount, 3), + AES_ENC_INPUT_ROUND_KEY(RoundCount, 4), + AES_ENC_INPUT_ROUND_KEY(RoundCount, 5), + AES_ENC_INPUT_ROUND_KEY(RoundCount, 6), + AES_ENC_INPUT_ROUND_KEY(RoundCount, 7), + AES_ENC_INPUT_ROUND_KEY(RoundCount, 8), + AES_ENC_INPUT_ROUND_KEY(RoundCount, 9), + AES_ENC_INPUT_ROUND_KEY(RoundCount, 10), + AES_ENC_INPUT_ROUND_KEY(RoundCount, 11), + AES_ENC_INPUT_ROUND_KEY(RoundCount, 12), + AES_ENC_INPUT_ROUND_KEY(RoundCount, 13), + AES_ENC_INPUT_LAST_ROUND_KEYS(RoundCount) + ); + + /* Store result. */ + AES_ENC_DEC_STORE_RESULT(); + } + + template<> + void AesImpl<16>::DecryptBlock(void *dst, size_t dst_size, const void *src, size_t src_size) const { + AMS_UNUSED(src_size, dst_size); + + /* Setup for asm */ + AES_ENC_DEC_SETUP_VARS(); + + /* Use optimized assembly to do all rounds. */ + __asm__ __volatile__ ( + AES_DEC_ROUND(1) + AES_DEC_ROUND(2) + AES_DEC_ROUND(3) + AES_DEC_ROUND(4) + AES_DEC_ROUND(5) + AES_DEC_ROUND(6) + AES_DEC_ROUND(7) + AES_DEC_ROUND(8) + AES_DEC_ROUND(9) + AES_DEC_FINAL_ROUND() + : AES_ENC_DEC_OUTPUT_VARS() + : AES_DEC_INPUT_ROUND_KEY(RoundCount, 1), + AES_DEC_INPUT_ROUND_KEY(RoundCount, 2), + AES_DEC_INPUT_ROUND_KEY(RoundCount, 3), + AES_DEC_INPUT_ROUND_KEY(RoundCount, 4), + AES_DEC_INPUT_ROUND_KEY(RoundCount, 5), + AES_DEC_INPUT_ROUND_KEY(RoundCount, 6), + AES_DEC_INPUT_ROUND_KEY(RoundCount, 7), + AES_DEC_INPUT_ROUND_KEY(RoundCount, 8), + AES_DEC_INPUT_ROUND_KEY(RoundCount, 9), + AES_DEC_INPUT_LAST_ROUND_KEYS(RoundCount) + ); + + /* Store result. */ + AES_ENC_DEC_STORE_RESULT(); + } + + template<> + void AesImpl<24>::DecryptBlock(void *dst, size_t dst_size, const void *src, size_t src_size) const { + AMS_UNUSED(src_size, dst_size); + + /* Setup for asm */ + AES_ENC_DEC_SETUP_VARS(); + + /* Use optimized assembly to do all rounds. */ + __asm__ __volatile__ ( + AES_DEC_ROUND(1) + AES_DEC_ROUND(2) + AES_DEC_ROUND(3) + AES_DEC_ROUND(4) + AES_DEC_ROUND(5) + AES_DEC_ROUND(6) + AES_DEC_ROUND(7) + AES_DEC_ROUND(8) + AES_DEC_ROUND(9) + AES_DEC_ROUND(10) + AES_DEC_ROUND(11) + AES_DEC_FINAL_ROUND() + : AES_ENC_DEC_OUTPUT_VARS() + : AES_DEC_INPUT_ROUND_KEY(RoundCount, 1), + AES_DEC_INPUT_ROUND_KEY(RoundCount, 2), + AES_DEC_INPUT_ROUND_KEY(RoundCount, 3), + AES_DEC_INPUT_ROUND_KEY(RoundCount, 4), + AES_DEC_INPUT_ROUND_KEY(RoundCount, 5), + AES_DEC_INPUT_ROUND_KEY(RoundCount, 6), + AES_DEC_INPUT_ROUND_KEY(RoundCount, 7), + AES_DEC_INPUT_ROUND_KEY(RoundCount, 8), + AES_DEC_INPUT_ROUND_KEY(RoundCount, 9), + AES_DEC_INPUT_ROUND_KEY(RoundCount, 10), + AES_DEC_INPUT_ROUND_KEY(RoundCount, 11), + AES_DEC_INPUT_LAST_ROUND_KEYS(RoundCount) + ); + + /* Store result. */ + AES_ENC_DEC_STORE_RESULT(); + } + + template<> + void AesImpl<32>::DecryptBlock(void *dst, size_t dst_size, const void *src, size_t src_size) const { + AMS_UNUSED(src_size, dst_size); + + /* Setup for asm */ + AES_ENC_DEC_SETUP_VARS(); + + /* Use optimized assembly to do all rounds. */ + __asm__ __volatile__ ( + AES_DEC_ROUND(1) + AES_DEC_ROUND(2) + AES_DEC_ROUND(3) + AES_DEC_ROUND(4) + AES_DEC_ROUND(5) + AES_DEC_ROUND(6) + AES_DEC_ROUND(7) + AES_DEC_ROUND(8) + AES_DEC_ROUND(9) + AES_DEC_ROUND(10) + AES_DEC_ROUND(11) + AES_DEC_ROUND(12) + AES_DEC_ROUND(13) + AES_DEC_FINAL_ROUND() + : AES_ENC_DEC_OUTPUT_VARS() + : AES_DEC_INPUT_ROUND_KEY(RoundCount, 1), + AES_DEC_INPUT_ROUND_KEY(RoundCount, 2), + AES_DEC_INPUT_ROUND_KEY(RoundCount, 3), + AES_DEC_INPUT_ROUND_KEY(RoundCount, 4), + AES_DEC_INPUT_ROUND_KEY(RoundCount, 5), + AES_DEC_INPUT_ROUND_KEY(RoundCount, 6), + AES_DEC_INPUT_ROUND_KEY(RoundCount, 7), + AES_DEC_INPUT_ROUND_KEY(RoundCount, 8), + AES_DEC_INPUT_ROUND_KEY(RoundCount, 9), + AES_DEC_INPUT_ROUND_KEY(RoundCount, 10), + AES_DEC_INPUT_ROUND_KEY(RoundCount, 11), + AES_DEC_INPUT_ROUND_KEY(RoundCount, 12), + AES_DEC_INPUT_ROUND_KEY(RoundCount, 13), + AES_DEC_INPUT_LAST_ROUND_KEYS(RoundCount) + ); + + /* Store result. */ + AES_ENC_DEC_STORE_RESULT(); + } + + #endif /* Explicitly instantiate the three supported key sizes. */ template class AesImpl<16>; diff --git a/libraries/libvapours/source/crypto/impl/crypto_aes_impl.arch.x64.cpp b/libraries/libvapours/source/crypto/impl/crypto_aes_impl.arch.x64.cpp new file mode 100644 index 000000000..be40a4fc5 --- /dev/null +++ b/libraries/libvapours/source/crypto/impl/crypto_aes_impl.arch.x64.cpp @@ -0,0 +1,435 @@ +/* + * Copyright (c) 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 "crypto_aes_impl.arch.x64.hpp" + +namespace ams::crypto::impl { + + namespace { + + constexpr bool IsSupportedKeySize(size_t size) { + return size == 16 || size == 24 || size == 32; + } + + constexpr int WordsPerBlock = AesImpl<16>::BlockSize / sizeof(u32); + static_assert(AesImpl<16>::BlockSize == AesImpl<24>::BlockSize); + static_assert(AesImpl<16>::BlockSize == AesImpl<32>::BlockSize); + + bool GetAesNiAvailabilityImpl() { + /* Call cpu id. */ + int a = 0, b = 0, c = 0, d = 0; + __asm__ __volatile__("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(1) : "memory"); + + /* Check for AES-NI and SSE2. */ + return (c & (1 << 25)) && (d & (1 << 26)); + } + + static_assert(util::IsLittleEndian()); + + constexpr const u8 RoundKeyRcon0[] = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36, 0x6C, 0xD8, 0xAB, 0x4D, 0x9A, 0x2F, + 0x5E, 0xBC, 0x63, 0xC6, 0x97, 0x35, 0x6A, 0xD4, 0xB3, 0x7D, 0xFA, 0xEF, 0xC5, 0x91, + }; + + constexpr const u8 SubBytesTable[0x100] = { + 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, + 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, + 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, + 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, + 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, + 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, + 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, + 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, + 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, + 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, + 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, + 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, + 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, + 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, + 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, + 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16, + }; + + constexpr const u8 InvSubBytesTable[0x100] = { + 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, + 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, + 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, + 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, + 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, + 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, + 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, + 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, + 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, + 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, + 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, + 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, + 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, + 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, + 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D, + }; + + constexpr bool IsSubBytesTableValid() { + for (size_t i = 0; i < 0x100; ++i) { + if (SubBytesTable[InvSubBytesTable[i]] != i) { + return false; + } + if (InvSubBytesTable[SubBytesTable[i]] != i) { + return false; + } + } + + return true; + } + + static_assert(IsSubBytesTableValid()); + + constexpr const u32 EncryptTable[0x100] = { + 0xA56363C6, 0x847C7CF8, 0x997777EE, 0x8D7B7BF6, 0x0DF2F2FF, 0xBD6B6BD6, 0xB16F6FDE, 0x54C5C591, + 0x50303060, 0x03010102, 0xA96767CE, 0x7D2B2B56, 0x19FEFEE7, 0x62D7D7B5, 0xE6ABAB4D, 0x9A7676EC, + 0x45CACA8F, 0x9D82821F, 0x40C9C989, 0x877D7DFA, 0x15FAFAEF, 0xEB5959B2, 0xC947478E, 0x0BF0F0FB, + 0xECADAD41, 0x67D4D4B3, 0xFDA2A25F, 0xEAAFAF45, 0xBF9C9C23, 0xF7A4A453, 0x967272E4, 0x5BC0C09B, + 0xC2B7B775, 0x1CFDFDE1, 0xAE93933D, 0x6A26264C, 0x5A36366C, 0x413F3F7E, 0x02F7F7F5, 0x4FCCCC83, + 0x5C343468, 0xF4A5A551, 0x34E5E5D1, 0x08F1F1F9, 0x937171E2, 0x73D8D8AB, 0x53313162, 0x3F15152A, + 0x0C040408, 0x52C7C795, 0x65232346, 0x5EC3C39D, 0x28181830, 0xA1969637, 0x0F05050A, 0xB59A9A2F, + 0x0907070E, 0x36121224, 0x9B80801B, 0x3DE2E2DF, 0x26EBEBCD, 0x6927274E, 0xCDB2B27F, 0x9F7575EA, + 0x1B090912, 0x9E83831D, 0x742C2C58, 0x2E1A1A34, 0x2D1B1B36, 0xB26E6EDC, 0xEE5A5AB4, 0xFBA0A05B, + 0xF65252A4, 0x4D3B3B76, 0x61D6D6B7, 0xCEB3B37D, 0x7B292952, 0x3EE3E3DD, 0x712F2F5E, 0x97848413, + 0xF55353A6, 0x68D1D1B9, 0x00000000, 0x2CEDEDC1, 0x60202040, 0x1FFCFCE3, 0xC8B1B179, 0xED5B5BB6, + 0xBE6A6AD4, 0x46CBCB8D, 0xD9BEBE67, 0x4B393972, 0xDE4A4A94, 0xD44C4C98, 0xE85858B0, 0x4ACFCF85, + 0x6BD0D0BB, 0x2AEFEFC5, 0xE5AAAA4F, 0x16FBFBED, 0xC5434386, 0xD74D4D9A, 0x55333366, 0x94858511, + 0xCF45458A, 0x10F9F9E9, 0x06020204, 0x817F7FFE, 0xF05050A0, 0x443C3C78, 0xBA9F9F25, 0xE3A8A84B, + 0xF35151A2, 0xFEA3A35D, 0xC0404080, 0x8A8F8F05, 0xAD92923F, 0xBC9D9D21, 0x48383870, 0x04F5F5F1, + 0xDFBCBC63, 0xC1B6B677, 0x75DADAAF, 0x63212142, 0x30101020, 0x1AFFFFE5, 0x0EF3F3FD, 0x6DD2D2BF, + 0x4CCDCD81, 0x140C0C18, 0x35131326, 0x2FECECC3, 0xE15F5FBE, 0xA2979735, 0xCC444488, 0x3917172E, + 0x57C4C493, 0xF2A7A755, 0x827E7EFC, 0x473D3D7A, 0xAC6464C8, 0xE75D5DBA, 0x2B191932, 0x957373E6, + 0xA06060C0, 0x98818119, 0xD14F4F9E, 0x7FDCDCA3, 0x66222244, 0x7E2A2A54, 0xAB90903B, 0x8388880B, + 0xCA46468C, 0x29EEEEC7, 0xD3B8B86B, 0x3C141428, 0x79DEDEA7, 0xE25E5EBC, 0x1D0B0B16, 0x76DBDBAD, + 0x3BE0E0DB, 0x56323264, 0x4E3A3A74, 0x1E0A0A14, 0xDB494992, 0x0A06060C, 0x6C242448, 0xE45C5CB8, + 0x5DC2C29F, 0x6ED3D3BD, 0xEFACAC43, 0xA66262C4, 0xA8919139, 0xA4959531, 0x37E4E4D3, 0x8B7979F2, + 0x32E7E7D5, 0x43C8C88B, 0x5937376E, 0xB76D6DDA, 0x8C8D8D01, 0x64D5D5B1, 0xD24E4E9C, 0xE0A9A949, + 0xB46C6CD8, 0xFA5656AC, 0x07F4F4F3, 0x25EAEACF, 0xAF6565CA, 0x8E7A7AF4, 0xE9AEAE47, 0x18080810, + 0xD5BABA6F, 0x887878F0, 0x6F25254A, 0x722E2E5C, 0x241C1C38, 0xF1A6A657, 0xC7B4B473, 0x51C6C697, + 0x23E8E8CB, 0x7CDDDDA1, 0x9C7474E8, 0x211F1F3E, 0xDD4B4B96, 0xDCBDBD61, 0x868B8B0D, 0x858A8A0F, + 0x907070E0, 0x423E3E7C, 0xC4B5B571, 0xAA6666CC, 0xD8484890, 0x05030306, 0x01F6F6F7, 0x120E0E1C, + 0xA36161C2, 0x5F35356A, 0xF95757AE, 0xD0B9B969, 0x91868617, 0x58C1C199, 0x271D1D3A, 0xB99E9E27, + 0x38E1E1D9, 0x13F8F8EB, 0xB398982B, 0x33111122, 0xBB6969D2, 0x70D9D9A9, 0x898E8E07, 0xA7949433, + 0xB69B9B2D, 0x221E1E3C, 0x92878715, 0x20E9E9C9, 0x49CECE87, 0xFF5555AA, 0x78282850, 0x7ADFDFA5, + 0x8F8C8C03, 0xF8A1A159, 0x80898909, 0x170D0D1A, 0xDABFBF65, 0x31E6E6D7, 0xC6424284, 0xB86868D0, + 0xC3414182, 0xB0999929, 0x772D2D5A, 0x110F0F1E, 0xCBB0B07B, 0xFC5454A8, 0xD6BBBB6D, 0x3A16162C, + }; + + constexpr const u32 DecryptTable[0x100] = { + 0x50A7F451, 0x5365417E, 0xC3A4171A, 0x965E273A, 0xCB6BAB3B, 0xF1459D1F, 0xAB58FAAC, 0x9303E34B, + 0x55FA3020, 0xF66D76AD, 0x9176CC88, 0x254C02F5, 0xFCD7E54F, 0xD7CB2AC5, 0x80443526, 0x8FA362B5, + 0x495AB1DE, 0x671BBA25, 0x980EEA45, 0xE1C0FE5D, 0x02752FC3, 0x12F04C81, 0xA397468D, 0xC6F9D36B, + 0xE75F8F03, 0x959C9215, 0xEB7A6DBF, 0xDA595295, 0x2D83BED4, 0xD3217458, 0x2969E049, 0x44C8C98E, + 0x6A89C275, 0x78798EF4, 0x6B3E5899, 0xDD71B927, 0xB64FE1BE, 0x17AD88F0, 0x66AC20C9, 0xB43ACE7D, + 0x184ADF63, 0x82311AE5, 0x60335197, 0x457F5362, 0xE07764B1, 0x84AE6BBB, 0x1CA081FE, 0x942B08F9, + 0x58684870, 0x19FD458F, 0x876CDE94, 0xB7F87B52, 0x23D373AB, 0xE2024B72, 0x578F1FE3, 0x2AAB5566, + 0x0728EBB2, 0x03C2B52F, 0x9A7BC586, 0xA50837D3, 0xF2872830, 0xB2A5BF23, 0xBA6A0302, 0x5C8216ED, + 0x2B1CCF8A, 0x92B479A7, 0xF0F207F3, 0xA1E2694E, 0xCDF4DA65, 0xD5BE0506, 0x1F6234D1, 0x8AFEA6C4, + 0x9D532E34, 0xA055F3A2, 0x32E18A05, 0x75EBF6A4, 0x39EC830B, 0xAAEF6040, 0x069F715E, 0x51106EBD, + 0xF98A213E, 0x3D06DD96, 0xAE053EDD, 0x46BDE64D, 0xB58D5491, 0x055DC471, 0x6FD40604, 0xFF155060, + 0x24FB9819, 0x97E9BDD6, 0xCC434089, 0x779ED967, 0xBD42E8B0, 0x888B8907, 0x385B19E7, 0xDBEEC879, + 0x470A7CA1, 0xE90F427C, 0xC91E84F8, 0x00000000, 0x83868009, 0x48ED2B32, 0xAC70111E, 0x4E725A6C, + 0xFBFF0EFD, 0x5638850F, 0x1ED5AE3D, 0x27392D36, 0x64D90F0A, 0x21A65C68, 0xD1545B9B, 0x3A2E3624, + 0xB1670A0C, 0x0FE75793, 0xD296EEB4, 0x9E919B1B, 0x4FC5C080, 0xA220DC61, 0x694B775A, 0x161A121C, + 0x0ABA93E2, 0xE52AA0C0, 0x43E0223C, 0x1D171B12, 0x0B0D090E, 0xADC78BF2, 0xB9A8B62D, 0xC8A91E14, + 0x8519F157, 0x4C0775AF, 0xBBDD99EE, 0xFD607FA3, 0x9F2601F7, 0xBCF5725C, 0xC53B6644, 0x347EFB5B, + 0x7629438B, 0xDCC623CB, 0x68FCEDB6, 0x63F1E4B8, 0xCADC31D7, 0x10856342, 0x40229713, 0x2011C684, + 0x7D244A85, 0xF83DBBD2, 0x1132F9AE, 0x6DA129C7, 0x4B2F9E1D, 0xF330B2DC, 0xEC52860D, 0xD0E3C177, + 0x6C16B32B, 0x99B970A9, 0xFA489411, 0x2264E947, 0xC48CFCA8, 0x1A3FF0A0, 0xD82C7D56, 0xEF903322, + 0xC74E4987, 0xC1D138D9, 0xFEA2CA8C, 0x360BD498, 0xCF81F5A6, 0x28DE7AA5, 0x268EB7DA, 0xA4BFAD3F, + 0xE49D3A2C, 0x0D927850, 0x9BCC5F6A, 0x62467E54, 0xC2138DF6, 0xE8B8D890, 0x5EF7392E, 0xF5AFC382, + 0xBE805D9F, 0x7C93D069, 0xA92DD56F, 0xB31225CF, 0x3B99ACC8, 0xA77D1810, 0x6E639CE8, 0x7BBB3BDB, + 0x097826CD, 0xF418596E, 0x01B79AEC, 0xA89A4F83, 0x656E95E6, 0x7EE6FFAA, 0x08CFBC21, 0xE6E815EF, + 0xD99BE7BA, 0xCE366F4A, 0xD4099FEA, 0xD67CB029, 0xAFB2A431, 0x31233F2A, 0x3094A5C6, 0xC066A235, + 0x37BC4E74, 0xA6CA82FC, 0xB0D090E0, 0x15D8A733, 0x4A9804F1, 0xF7DAEC41, 0x0E50CD7F, 0x2FF69117, + 0x8DD64D76, 0x4DB0EF43, 0x544DAACC, 0xDF0496E4, 0xE3B5D19E, 0x1B886A4C, 0xB81F2CC1, 0x7F516546, + 0x04EA5E9D, 0x5D358C01, 0x737487FA, 0x2E410BFB, 0x5A1D67B3, 0x52D2DB92, 0x335610E9, 0x1347D66D, + 0x8C61D79A, 0x7A0CA137, 0x8E14F859, 0x893C13EB, 0xEE27A9CE, 0x35C961B7, 0xEDE51CE1, 0x3CB1477A, + 0x59DFD29C, 0x3F73F255, 0x79CE1418, 0xBF37C773, 0xEACDF753, 0x5BAAFD5F, 0x146F3DDF, 0x86DB4478, + 0x81F3AFCA, 0x3EC468B9, 0x2C342438, 0x5F40A3C2, 0x72C31D16, 0x0C25E2BC, 0x8B493C28, 0x41950DFF, + 0x7101A839, 0xDEB30C08, 0x9CE4B4D8, 0x90C15664, 0x6184CB7B, 0x70B632D5, 0x745C6C48, 0x4257B8D0, + }; + + constexpr auto AesWordByte0Shift = 0 * BITSIZEOF(u8); + constexpr auto AesWordByte1Shift = 1 * BITSIZEOF(u8); + constexpr auto AesWordByte2Shift = 2 * BITSIZEOF(u8); + constexpr auto AesWordByte3Shift = 3 * BITSIZEOF(u8); + + constexpr auto AesMixShift = 3 * BITSIZEOF(u8); + + constexpr void InverseMixColumns(u32 *dst, const u32 *src) { + for (auto i = 0; i < WordsPerBlock; ++i) { + const u32 v0 = src[i]; + const u32 v1 = (((v0 & 0x7F7F7F7Fu) << 1) ^ (((v0 & 0x80808080) >> 7) * 0x1B)); + const u32 v2 = (((v1 & 0x7F7F7F7Fu) << 1) ^ (((v1 & 0x80808080) >> 7) * 0x1B)); + const u32 v3 = (((v2 & 0x7F7F7F7Fu) << 1) ^ (((v2 & 0x80808080) >> 7) * 0x1B)); + + u32 v = v0 ^ v3; + v ^= util::RotateLeft(v, AesMixShift) ^ v2; + v ^= util::RotateLeft(v, AesMixShift) ^ v1; + v ^= util::RotateLeft(v, AesMixShift) ^ v0; + + dst[i] = v; + } + } + + constexpr u32 SubBytesAndRotate(u32 v) { + return (static_cast(SubBytesTable[(v >> AesWordByte0Shift) & 0xFFu]) << AesWordByte3Shift) ^ + (static_cast(SubBytesTable[(v >> AesWordByte1Shift) & 0xFFu]) << AesWordByte0Shift) ^ + (static_cast(SubBytesTable[(v >> AesWordByte2Shift) & 0xFFu]) << AesWordByte1Shift) ^ + (static_cast(SubBytesTable[(v >> AesWordByte3Shift) & 0xFFu]) << AesWordByte2Shift); + } + + constexpr u32 SubBytes(u32 v) { + return (static_cast(SubBytesTable[(v >> AesWordByte0Shift) & 0xFFu]) << AesWordByte0Shift) ^ + (static_cast(SubBytesTable[(v >> AesWordByte1Shift) & 0xFFu]) << AesWordByte1Shift) ^ + (static_cast(SubBytesTable[(v >> AesWordByte2Shift) & 0xFFu]) << AesWordByte2Shift) ^ + (static_cast(SubBytesTable[(v >> AesWordByte3Shift) & 0xFFu]) << AesWordByte3Shift); + } + + constexpr u32 ShiftSubMix(u32 v0, u32 v1, u32 v2, u32 v3) { + return (util::RotateLeft(static_cast(EncryptTable[(v0 >> AesWordByte0Shift) & 0xFFu]), AesWordByte0Shift)) ^ + (util::RotateLeft(static_cast(EncryptTable[(v1 >> AesWordByte1Shift) & 0xFFu]), AesWordByte1Shift)) ^ + (util::RotateLeft(static_cast(EncryptTable[(v2 >> AesWordByte2Shift) & 0xFFu]), AesWordByte2Shift)) ^ + (util::RotateLeft(static_cast(EncryptTable[(v3 >> AesWordByte3Shift) & 0xFFu]), AesWordByte3Shift)); + } + + constexpr u32 ShiftSub(u32 v0, u32 v1, u32 v2, u32 v3) { + return (static_cast(SubBytesTable[(v0 >> AesWordByte0Shift) & 0xFFu]) << AesWordByte0Shift) ^ + (static_cast(SubBytesTable[(v1 >> AesWordByte1Shift) & 0xFFu]) << AesWordByte1Shift) ^ + (static_cast(SubBytesTable[(v2 >> AesWordByte2Shift) & 0xFFu]) << AesWordByte2Shift) ^ + (static_cast(SubBytesTable[(v3 >> AesWordByte3Shift) & 0xFFu]) << AesWordByte3Shift); + } + + constexpr u32 InvShiftSubMix(u32 v0, u32 v1, u32 v2, u32 v3) { + return (util::RotateLeft(static_cast(DecryptTable[(v0 >> AesWordByte0Shift) & 0xFFu]), AesWordByte0Shift)) ^ + (util::RotateLeft(static_cast(DecryptTable[(v1 >> AesWordByte1Shift) & 0xFFu]), AesWordByte1Shift)) ^ + (util::RotateLeft(static_cast(DecryptTable[(v2 >> AesWordByte2Shift) & 0xFFu]), AesWordByte2Shift)) ^ + (util::RotateLeft(static_cast(DecryptTable[(v3 >> AesWordByte3Shift) & 0xFFu]), AesWordByte3Shift)); + } + + constexpr u32 InvShiftSub(u32 v0, u32 v1, u32 v2, u32 v3) { + return (static_cast(InvSubBytesTable[(v0 >> AesWordByte0Shift) & 0xFFu]) << AesWordByte0Shift) ^ + (static_cast(InvSubBytesTable[(v1 >> AesWordByte1Shift) & 0xFFu]) << AesWordByte1Shift) ^ + (static_cast(InvSubBytesTable[(v2 >> AesWordByte2Shift) & 0xFFu]) << AesWordByte2Shift) ^ + (static_cast(InvSubBytesTable[(v3 >> AesWordByte3Shift) & 0xFFu]) << AesWordByte3Shift); + } + + } + + const bool g_is_aes_ni_available = GetAesNiAvailabilityImpl(); + + template + AesImpl::~AesImpl() { + ClearMemory(this, sizeof(*this)); + } + + template + void AesImpl::Initialize(const void *key, size_t key_size, bool is_encrypt) { + /* Check pre-conditions. */ + static_assert(IsSupportedKeySize(KeySize)); + AMS_ASSERT(key != nullptr); + AMS_ASSERT(key_size == KeySize); + AMS_UNUSED(key_size); + + /* Set up key. */ + u32 *dst = m_round_keys; + std::memcpy(dst, key, KeySize); + + /* Perform key scheduling. */ + constexpr auto InitialKeyWords = KeySize / sizeof(u32); + u32 tmp = dst[InitialKeyWords - 1]; + + for (auto i = InitialKeyWords; i < (RoundCount + 1) * 4; ++i) { + const auto idx_in_key = i % InitialKeyWords; + if (idx_in_key == 0) { + /* At start of key word, we need to handle sub/rotate/rcon. */ + tmp = SubBytesAndRotate(tmp); + tmp ^= (RoundKeyRcon0[i / InitialKeyWords - 1] << AesWordByte0Shift); + } else if ((InitialKeyWords > 6) && idx_in_key == 4) { + /* Halfway into a 256-bit key word, we need to do an additional subbytes. */ + tmp = SubBytes(tmp); + } + + /* Set the key word. */ + tmp ^= dst[i - InitialKeyWords]; + dst[i] = tmp; + } + + /* If decrypting, perform inverse mix columns on all round keys. */ + if (!is_encrypt) { + if (IsAesNiAvailable()) { + auto *key8 = reinterpret_cast(m_round_keys) + BlockSize; + + for (auto i = 1; i < RoundCount; ++i) { + auto * const key128 = reinterpret_cast<__m128i *>(key8); + _mm_storeu_si128(key128, _mm_aesimc_si128(_mm_loadu_si128(key128))); + key8 += BlockSize; + } + } else { + for (auto i = 1; i < RoundCount; ++i) { + InverseMixColumns(m_round_keys + WordsPerBlock * i, m_round_keys + WordsPerBlock * i); + } + } + } + } + + template + void AesImpl::EncryptBlock(void *dst, size_t dst_size, const void *src, size_t src_size) const { + static_assert(IsSupportedKeySize(KeySize)); + AMS_ASSERT(dst_size == BlockSize && src_size == BlockSize); + AMS_UNUSED(dst_size, src_size); + + /* Perform block encryption. */ + if (IsAesNiAvailable()) { + const auto *key8 = reinterpret_cast(m_round_keys); + + /* Load the block. */ + auto block = _mm_loadu_si128(reinterpret_cast(src)); + + /* Add the first round key. */ + block = _mm_xor_si128(block, _mm_loadu_si128(reinterpret_cast(key8))); + key8 += BlockSize; + + /* Perform aes round on remaining round keys. */ + for (auto i = 1; i < RoundCount; ++i) { + block = _mm_aesenc_si128(block, _mm_loadu_si128(reinterpret_cast(key8))); + key8 += BlockSize; + } + + /* Do final update. */ + block = _mm_aesenclast_si128(block, _mm_loadu_si128(reinterpret_cast(key8))); + + /* Store the output. */ + _mm_storeu_si128(reinterpret_cast<__m128i *>(dst), block); + } else { + static_assert(WordsPerBlock == 4); + + /* Without AES-NI, we'll operate on words. */ + const u32 *key32 = m_round_keys; + const u32 *src32 = static_cast(src); + u32 *dst32 = static_cast< u32 *>(dst); + + /* Add the first round key. */ + u32 v0 = src32[0] ^ key32[0]; + u32 v1 = src32[1] ^ key32[1]; + u32 v2 = src32[2] ^ key32[2]; + u32 v3 = src32[3] ^ key32[3]; + key32 += 4; + + /* Perform each round. */ + auto round = RoundCount; + while (--round > 0) { + /* Perform aes round. */ + const u32 e0 = ShiftSubMix(v0, v1, v2, v3); + const u32 e1 = ShiftSubMix(v1, v2, v3, v0); + const u32 e2 = ShiftSubMix(v2, v3, v0, v1); + const u32 e3 = ShiftSubMix(v3, v0, v1, v2); + + /* Add the round key. */ + v0 = e0 ^ key32[0]; + v1 = e1 ^ key32[1]; + v2 = e2 ^ key32[2]; + v3 = e3 ^ key32[3]; + key32 += 4; + } + + /* Perform the final round. */ + dst32[0] = key32[0] ^ ShiftSub(v0, v1, v2, v3); + dst32[1] = key32[1] ^ ShiftSub(v1, v2, v3, v0); + dst32[2] = key32[2] ^ ShiftSub(v2, v3, v0, v1); + dst32[3] = key32[3] ^ ShiftSub(v3, v0, v1, v2); + } + } + + template + void AesImpl::DecryptBlock(void *dst, size_t dst_size, const void *src, size_t src_size) const { + static_assert(IsSupportedKeySize(KeySize)); + AMS_ASSERT(dst_size == BlockSize && src_size == BlockSize); + AMS_UNUSED(dst_size, src_size); + + /* Perform block decryption. */ + if (IsAesNiAvailable()) { + const auto *key8 = reinterpret_cast(m_round_keys) + (RoundCount * BlockSize); + + /* Load the block. */ + auto block = _mm_loadu_si128(reinterpret_cast(src)); + + /* Add the final round key. */ + block = _mm_xor_si128(block, _mm_loadu_si128(reinterpret_cast(key8))); + key8 -= BlockSize; + + /* Perform aes invround on remaining round keys. */ + for (auto i = RoundCount; i > 1; --i) { + block = _mm_aesdec_si128(block, _mm_loadu_si128(reinterpret_cast(key8))); + key8 -= BlockSize; + } + + /* Do final update. */ + block = _mm_aesdeclast_si128(block, _mm_loadu_si128(reinterpret_cast(key8))); + + /* Store the output. */ + _mm_storeu_si128(reinterpret_cast<__m128i *>(dst), block); + } else { + static_assert(WordsPerBlock == 4); + + /* Without AES-NI, we'll operate on words. */ + const u32 *key32 = m_round_keys + WordsPerBlock * RoundCount; + const u32 *src32 = static_cast(src); + u32 *dst32 = static_cast< u32 *>(dst); + + /* Add the final round key. */ + u32 v0 = src32[0] ^ key32[0]; + u32 v1 = src32[1] ^ key32[1]; + u32 v2 = src32[2] ^ key32[2]; + u32 v3 = src32[3] ^ key32[3]; + key32 -= 4; + + /* Perform each round. */ + auto round = RoundCount; + while (--round > 0) { + /* Perform aes inv round. */ + const u32 e0 = InvShiftSubMix(v0, v3, v2, v1); + const u32 e1 = InvShiftSubMix(v1, v0, v3, v2); + const u32 e2 = InvShiftSubMix(v2, v1, v0, v3); + const u32 e3 = InvShiftSubMix(v3, v2, v1, v0); + + /* Add the round key. */ + v0 = e0 ^ key32[0]; + v1 = e1 ^ key32[1]; + v2 = e2 ^ key32[2]; + v3 = e3 ^ key32[3]; + key32 -= 4; + } + + /* Perform the final round. */ + dst32[0] = key32[0] ^ InvShiftSub(v0, v3, v2, v1); + dst32[1] = key32[1] ^ InvShiftSub(v1, v0, v3, v2); + dst32[2] = key32[2] ^ InvShiftSub(v2, v1, v0, v3); + dst32[3] = key32[3] ^ InvShiftSub(v3, v2, v1, v0); + } + } + + /* Explicitly instantiate the three supported key sizes. */ + template class AesImpl<16>; + template class AesImpl<24>; + template class AesImpl<32>; + +} \ No newline at end of file diff --git a/libraries/libvapours/source/crypto/impl/crypto_aes_impl.arch.x64.hpp b/libraries/libvapours/source/crypto/impl/crypto_aes_impl.arch.x64.hpp new file mode 100644 index 000000000..a6563440a --- /dev/null +++ b/libraries/libvapours/source/crypto/impl/crypto_aes_impl.arch.x64.hpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 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 + +namespace ams::crypto::impl { + + extern const bool g_is_aes_ni_available; + + ALWAYS_INLINE bool IsAesNiAvailable() { + return g_is_aes_ni_available; + } + +} diff --git a/libraries/libvapours/source/crypto/impl/crypto_bignum_operations.cpp b/libraries/libvapours/source/crypto/impl/crypto_bignum_operations.cpp index 31371663d..75042c58d 100644 --- a/libraries/libvapours/source/crypto/impl/crypto_bignum_operations.cpp +++ b/libraries/libvapours/source/crypto/impl/crypto_bignum_operations.cpp @@ -45,7 +45,7 @@ namespace ams::crypto::impl { return static_cast(half) << BITSIZEOF(BigNum::HalfWord); } - constexpr ALWAYS_INLINE BigNum::Word ToLowerHalf(BigNum::HalfWord half) { + [[maybe_unused]] constexpr ALWAYS_INLINE BigNum::Word ToLowerHalf(BigNum::HalfWord half) { static_assert(sizeof(BigNum::Word) == sizeof(BigNum::HalfWord) * 2); return static_cast(half); } @@ -422,4 +422,69 @@ namespace ams::crypto::impl { return true; } + #if !defined(ATMOSPHERE_ARCH_ARM64) + BigNum::Word BigNum::Add(Word *dst, const Word *lhs, const Word *rhs, size_t num_words) { + Word carry = 0; + + for (size_t i = 0; i < num_words; ++i) { + Word v; + if ((v = lhs[i] + carry) < carry) { + v = rhs[i]; + } else if ((v += rhs[i]) < rhs[i]) { + carry = 1; + } else { + carry = 0; + } + + dst[i] = v; + } + + return carry; + } + + BigNum::Word BigNum::Sub(Word *dst, const Word *lhs, const Word *rhs, size_t num_words) { + Word borrow = 0; + + for (size_t i = 0; i < num_words; ++i) { + Word v; + if ((v = lhs[i] - borrow) > (BigNum::MaxWord - borrow)) { + v = BigNum::MaxWord - rhs[i]; + } else if ((v -= rhs[i]) > (BigNum::MaxWord - rhs[i])) { + borrow = 1; + } else { + borrow = 0; + } + + dst[i] = v; + } + + return borrow; + } + + BigNum::Word BigNum::MultAdd(Word *dst, const Word *w, size_t num_words, Word mult) { + /* If multiplying by zero, nothing to do. */ + if (mult == 0) { + return 0; + } + + Word carry = 0, work[2]; + for (size_t i = 0; i < num_words; i++) { + /* Multiply, calculate carry for next. */ + MultWord(work, mult, w[i]); + if ((dst[i] += carry) < carry) { + carry = 1; + } else { + carry = 0; + } + + if ((dst[i] += work[0]) < work[0]) { + carry++; + } + carry += work[1]; + } + + return carry; + } + #endif + } \ No newline at end of file diff --git a/libraries/libvapours/source/crypto/impl/crypto_bignum_operations_asm.arch.arm64.s b/libraries/libvapours/source/crypto/impl/crypto_bignum_operations_asm.arch.arm64.s index 734a4eddf..437434a77 100644 --- a/libraries/libvapours/source/crypto/impl/crypto_bignum_operations_asm.arch.arm64.s +++ b/libraries/libvapours/source/crypto/impl/crypto_bignum_operations_asm.arch.arm64.s @@ -15,9 +15,14 @@ */ /* ams::crypto::impl::BigNum::Add(Word *dst, const Word *lhs, const Word *rhs, size_t num_words) */ +#if !defined(ATMOSPHERE_OS_MACOS) .section .text._ZN3ams6crypto4impl6BigNum3AddEPjPKjS5_m, "ax", %progbits .global _ZN3ams6crypto4impl6BigNum3AddEPjPKjS5_m .type _ZN3ams6crypto4impl6BigNum3AddEPjPKjS5_m, %function +#else +.text +.global _ZN3ams6crypto4impl6BigNum3AddEPjPKjS5_m +#endif .balign 0x10 _ZN3ams6crypto4impl6BigNum3AddEPjPKjPKjm: /* Check if we have anything to do at all. */ @@ -106,9 +111,14 @@ _ZN3ams6crypto4impl6BigNum3AddEPjPKjPKjm: ret /* ams::crypto::impl::BigNum::Sub(Word *dst, const Word *lhs, const Word *rhs, size_t num_words) */ +#if !defined(ATMOSPHERE_OS_MACOS) .section .text._ZN3ams6crypto4impl6BigNum3SubEPjPKjS5_m, "ax", %progbits .global _ZN3ams6crypto4impl6BigNum3SubEPjPKjS5_m .type _ZN3ams6crypto4impl6BigNum3SubEPjPKjS5_m, %function +#else +.text +.global _ZN3ams6crypto4impl6BigNum3SubEPjPKjS5_m +#endif .balign 0x10 _ZN3ams6crypto4impl6BigNum3SubEPjPKjS5_m: /* Check if we have anything to do at all. */ @@ -198,9 +208,14 @@ _ZN3ams6crypto4impl6BigNum3SubEPjPKjS5_m: ret /* ams::crypto::impl::BigNum::MultAdd(Word *dst, const Word *w, size_t num_words, Word mult) */ +#if !defined(ATMOSPHERE_OS_MACOS) .section .text._ZN3ams6crypto4impl6BigNum7MultAddEPjPKjmj, "ax", %progbits .global _ZN3ams6crypto4impl6BigNum7MultAddEPjPKjmj .type _ZN3ams6crypto4impl6BigNum7MultAddEPjPKjmj, %function +#else +.text +.global _ZN3ams6crypto4impl6BigNum7MultAddEPjPKjmj +#endif .balign 0x10 _ZN3ams6crypto4impl6BigNum7MultAddEPjPKjmj: /* Check if we have anything to do at all. */ diff --git a/libraries/libvapours/source/crypto/impl/crypto_ctr_mode_impl.arch.arm64.cpp b/libraries/libvapours/source/crypto/impl/crypto_ctr_mode_impl.arch.arm64.cpp index 6b171967d..10080f7e1 100644 --- a/libraries/libvapours/source/crypto/impl/crypto_ctr_mode_impl.arch.arm64.cpp +++ b/libraries/libvapours/source/crypto/impl/crypto_ctr_mode_impl.arch.arm64.cpp @@ -114,11 +114,11 @@ namespace ams::crypto::impl { while (num_blocks >= 3) { /* Read blocks in. Keep them in registers for XOR later. */ const uint8x16_t block0 = vld1q_u8(src); - src += AES_BLOCK_SIZE; + src += AesEncryptor128::BlockSize; const uint8x16_t block1 = vld1q_u8(src); - src += AES_BLOCK_SIZE; + src += AesEncryptor128::BlockSize; const uint8x16_t block2 = vld1q_u8(src); - src += AES_BLOCK_SIZE; + src += AesEncryptor128::BlockSize; /* We'll be encrypting the three CTRs. */ uint8x16_t tmp0 = ctr0, tmp1 = ctr1, tmp2 = ctr2; @@ -178,11 +178,11 @@ namespace ams::crypto::impl { /* Store to output. */ vst1q_u8(dst, tmp0); - dst += AES_BLOCK_SIZE; + dst += AesEncryptor128::BlockSize; vst1q_u8(dst, tmp1); - dst += AES_BLOCK_SIZE; + dst += AesEncryptor128::BlockSize; vst1q_u8(dst, tmp2); - dst += AES_BLOCK_SIZE; + dst += AesEncryptor128::BlockSize; num_blocks -= 3; } @@ -191,7 +191,7 @@ namespace ams::crypto::impl { while (num_blocks >= 1) { /* Read block in, keep in register for XOR. */ const uint8x16_t block0 = vld1q_u8(src); - src += AES_BLOCK_SIZE; + src += AesEncryptor128::BlockSize; /* We'll be encrypting the CTR. */ uint8x16_t tmp0 = ctr0; @@ -232,7 +232,7 @@ namespace ams::crypto::impl { /* Store to output. */ vst1q_u8(dst, tmp0); - dst += AES_BLOCK_SIZE; + dst += AesEncryptor128::BlockSize; num_blocks--; } @@ -270,11 +270,11 @@ namespace ams::crypto::impl { while (num_blocks >= 3) { /* Read blocks in. Keep them in registers for XOR later. */ const uint8x16_t block0 = vld1q_u8(src); - src += AES_BLOCK_SIZE; + src += AesEncryptor192::BlockSize; const uint8x16_t block1 = vld1q_u8(src); - src += AES_BLOCK_SIZE; + src += AesEncryptor192::BlockSize; const uint8x16_t block2 = vld1q_u8(src); - src += AES_BLOCK_SIZE; + src += AesEncryptor192::BlockSize; /* We'll be encrypting the three CTRs. */ uint8x16_t tmp0 = ctr0, tmp1 = ctr1, tmp2 = ctr2; @@ -338,11 +338,11 @@ namespace ams::crypto::impl { /* Store to output. */ vst1q_u8(dst, tmp0); - dst += AES_BLOCK_SIZE; + dst += AesEncryptor192::BlockSize; vst1q_u8(dst, tmp1); - dst += AES_BLOCK_SIZE; + dst += AesEncryptor192::BlockSize; vst1q_u8(dst, tmp2); - dst += AES_BLOCK_SIZE; + dst += AesEncryptor192::BlockSize; num_blocks -= 3; } @@ -351,7 +351,7 @@ namespace ams::crypto::impl { while (num_blocks >= 1) { /* Read block in, keep in register for XOR. */ const uint8x16_t block0 = vld1q_u8(src); - src += AES_BLOCK_SIZE; + src += AesEncryptor192::BlockSize; /* We'll be encrypting the CTR. */ uint8x16_t tmp0 = ctr0; @@ -396,7 +396,7 @@ namespace ams::crypto::impl { /* Store to output. */ vst1q_u8(dst, tmp0); - dst += AES_BLOCK_SIZE; + dst += AesEncryptor192::BlockSize; num_blocks--; } @@ -436,11 +436,11 @@ namespace ams::crypto::impl { while (num_blocks >= 3) { /* Read blocks in. Keep them in registers for XOR later. */ const uint8x16_t block0 = vld1q_u8(src); - src += AES_BLOCK_SIZE; + src += AesEncryptor256::BlockSize; const uint8x16_t block1 = vld1q_u8(src); - src += AES_BLOCK_SIZE; + src += AesEncryptor256::BlockSize; const uint8x16_t block2 = vld1q_u8(src); - src += AES_BLOCK_SIZE; + src += AesEncryptor256::BlockSize; /* We'll be encrypting the three CTRs. */ uint8x16_t tmp0 = ctr0, tmp1 = ctr1, tmp2 = ctr2; @@ -509,11 +509,11 @@ namespace ams::crypto::impl { /* Store to output. */ vst1q_u8(dst, tmp0); - dst += AES_BLOCK_SIZE; + dst += AesEncryptor256::BlockSize; vst1q_u8(dst, tmp1); - dst += AES_BLOCK_SIZE; + dst += AesEncryptor256::BlockSize; vst1q_u8(dst, tmp2); - dst += AES_BLOCK_SIZE; + dst += AesEncryptor256::BlockSize; num_blocks -= 3; } @@ -522,7 +522,7 @@ namespace ams::crypto::impl { while (num_blocks >= 1) { /* Read block in, keep in register for XOR. */ const uint8x16_t block0 = vld1q_u8(src); - src += AES_BLOCK_SIZE; + src += AesEncryptor256::BlockSize; /* We'll be encrypting the CTR. */ uint8x16_t tmp0 = ctr0; @@ -571,7 +571,7 @@ namespace ams::crypto::impl { /* Store to output. */ vst1q_u8(dst, tmp0); - dst += AES_BLOCK_SIZE; + dst += AesEncryptor256::BlockSize; num_blocks--; } diff --git a/libraries/libvapours/source/crypto/impl/crypto_ctr_mode_impl.arch.x64.cpp b/libraries/libvapours/source/crypto/impl/crypto_ctr_mode_impl.arch.x64.cpp new file mode 100644 index 000000000..a2899d81a --- /dev/null +++ b/libraries/libvapours/source/crypto/impl/crypto_ctr_mode_impl.arch.x64.cpp @@ -0,0 +1,269 @@ +/* + * Copyright (c) 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 "crypto_aes_impl.arch.x64.hpp" + +namespace ams::crypto::impl { + + template<> void CtrModeImpl::ProcessBlocks(u8 *dst, const u8 *src, size_t num_blocks) { + /* Check pre-conditions. */ + AMS_ASSERT(src != nullptr); + AMS_ASSERT(dst != nullptr); + + /* If we have aes-ni, use an optimized impl. */ + if (IsAesNiAvailable()) { + /* Load all keys into sse2 registers. */ + const u8 *raw_round_keys = m_block_cipher->GetRoundKey(); + const __m128i round_keys[AesEncryptor128::RoundKeySize / BlockSize] = { + _mm_loadu_si128(reinterpret_cast(raw_round_keys + BlockSize * 0)), + _mm_loadu_si128(reinterpret_cast(raw_round_keys + BlockSize * 1)), + _mm_loadu_si128(reinterpret_cast(raw_round_keys + BlockSize * 2)), + _mm_loadu_si128(reinterpret_cast(raw_round_keys + BlockSize * 3)), + _mm_loadu_si128(reinterpret_cast(raw_round_keys + BlockSize * 4)), + _mm_loadu_si128(reinterpret_cast(raw_round_keys + BlockSize * 5)), + _mm_loadu_si128(reinterpret_cast(raw_round_keys + BlockSize * 6)), + _mm_loadu_si128(reinterpret_cast(raw_round_keys + BlockSize * 7)), + _mm_loadu_si128(reinterpret_cast(raw_round_keys + BlockSize * 8)), + _mm_loadu_si128(reinterpret_cast(raw_round_keys + BlockSize * 9)), + _mm_loadu_si128(reinterpret_cast(raw_round_keys + BlockSize * 10)), + }; + static_assert(AesEncryptor128::RoundKeySize / BlockSize == 11); + + /* Declare constant for counter math. */ + const __m128i One = _mm_setr_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); + + /* Process eight blocks at a time, while we can. */ + constexpr const auto UnrolledBlockCount = 8; + constexpr const auto CounterThreshold = static_cast(0x100 - UnrolledBlockCount); + + /* Load the counter. */ + auto counter = _mm_loadu_si128(reinterpret_cast(m_counter)); + + size_t cur_blocks; + for (cur_blocks = 0; cur_blocks + UnrolledBlockCount <= num_blocks; cur_blocks += UnrolledBlockCount) { + __m128i b0; + __m128i b1; + __m128i b2; + __m128i b3; + __m128i b4; + __m128i b5; + __m128i b6; + __m128i b7; + + __m128i key = round_keys[0]; + + /* Get the last byte of the block. */ + static_assert(util::IsLittleEndian()); + const u8 counter_val = _mm_extract_epi16(counter, 7) >> BITSIZEOF(u8); + + /* Do initial encryption of each block. */ + if (CounterThreshold <= counter_val) { + /* We'll overwrap, so take slow path for counter. */ + _mm_storeu_si128(reinterpret_cast<__m128i *>(m_counter), counter); + + b0 = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(m_counter)), key); + this->IncrementCounter(); + b1 = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(m_counter)), key); + this->IncrementCounter(); + b2 = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(m_counter)), key); + this->IncrementCounter(); + b3 = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(m_counter)), key); + this->IncrementCounter(); + b4 = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(m_counter)), key); + this->IncrementCounter(); + b5 = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(m_counter)), key); + this->IncrementCounter(); + b6 = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(m_counter)), key); + this->IncrementCounter(); + b7 = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(m_counter)), key); + this->IncrementCounter(); + + counter = _mm_loadu_si128(reinterpret_cast(m_counter)); + } else { + /* We can take the fast path for the counter. */ + b0 = _mm_xor_si128(counter, key); + counter = _mm_add_epi64(counter, One); + b1 = _mm_xor_si128(counter, key); + counter = _mm_add_epi64(counter, One); + b2 = _mm_xor_si128(counter, key); + counter = _mm_add_epi64(counter, One); + b3 = _mm_xor_si128(counter, key); + counter = _mm_add_epi64(counter, One); + b4 = _mm_xor_si128(counter, key); + counter = _mm_add_epi64(counter, One); + b5 = _mm_xor_si128(counter, key); + counter = _mm_add_epi64(counter, One); + b6 = _mm_xor_si128(counter, key); + counter = _mm_add_epi64(counter, One); + b7 = _mm_xor_si128(counter, key); + counter = _mm_add_epi64(counter, One); + } + + /* Do encryption for all rounds. */ + key = round_keys[1]; + b0 = _mm_aesenc_si128(b0, key); + b1 = _mm_aesenc_si128(b1, key); + b2 = _mm_aesenc_si128(b2, key); + b3 = _mm_aesenc_si128(b3, key); + b4 = _mm_aesenc_si128(b4, key); + b5 = _mm_aesenc_si128(b5, key); + b6 = _mm_aesenc_si128(b6, key); + b7 = _mm_aesenc_si128(b7, key); + + key = round_keys[2]; + b0 = _mm_aesenc_si128(b0, key); + b1 = _mm_aesenc_si128(b1, key); + b2 = _mm_aesenc_si128(b2, key); + b3 = _mm_aesenc_si128(b3, key); + b4 = _mm_aesenc_si128(b4, key); + b5 = _mm_aesenc_si128(b5, key); + b6 = _mm_aesenc_si128(b6, key); + b7 = _mm_aesenc_si128(b7, key); + + key = round_keys[3]; + b0 = _mm_aesenc_si128(b0, key); + b1 = _mm_aesenc_si128(b1, key); + b2 = _mm_aesenc_si128(b2, key); + b3 = _mm_aesenc_si128(b3, key); + b4 = _mm_aesenc_si128(b4, key); + b5 = _mm_aesenc_si128(b5, key); + b6 = _mm_aesenc_si128(b6, key); + b7 = _mm_aesenc_si128(b7, key); + + key = round_keys[4]; + b0 = _mm_aesenc_si128(b0, key); + b1 = _mm_aesenc_si128(b1, key); + b2 = _mm_aesenc_si128(b2, key); + b3 = _mm_aesenc_si128(b3, key); + b4 = _mm_aesenc_si128(b4, key); + b5 = _mm_aesenc_si128(b5, key); + b6 = _mm_aesenc_si128(b6, key); + b7 = _mm_aesenc_si128(b7, key); + + key = round_keys[5]; + b0 = _mm_aesenc_si128(b0, key); + b1 = _mm_aesenc_si128(b1, key); + b2 = _mm_aesenc_si128(b2, key); + b3 = _mm_aesenc_si128(b3, key); + b4 = _mm_aesenc_si128(b4, key); + b5 = _mm_aesenc_si128(b5, key); + b6 = _mm_aesenc_si128(b6, key); + b7 = _mm_aesenc_si128(b7, key); + + key = round_keys[6]; + b0 = _mm_aesenc_si128(b0, key); + b1 = _mm_aesenc_si128(b1, key); + b2 = _mm_aesenc_si128(b2, key); + b3 = _mm_aesenc_si128(b3, key); + b4 = _mm_aesenc_si128(b4, key); + b5 = _mm_aesenc_si128(b5, key); + b6 = _mm_aesenc_si128(b6, key); + b7 = _mm_aesenc_si128(b7, key); + + key = round_keys[7]; + b0 = _mm_aesenc_si128(b0, key); + b1 = _mm_aesenc_si128(b1, key); + b2 = _mm_aesenc_si128(b2, key); + b3 = _mm_aesenc_si128(b3, key); + b4 = _mm_aesenc_si128(b4, key); + b5 = _mm_aesenc_si128(b5, key); + b6 = _mm_aesenc_si128(b6, key); + b7 = _mm_aesenc_si128(b7, key); + + key = round_keys[8]; + b0 = _mm_aesenc_si128(b0, key); + b1 = _mm_aesenc_si128(b1, key); + b2 = _mm_aesenc_si128(b2, key); + b3 = _mm_aesenc_si128(b3, key); + b4 = _mm_aesenc_si128(b4, key); + b5 = _mm_aesenc_si128(b5, key); + b6 = _mm_aesenc_si128(b6, key); + b7 = _mm_aesenc_si128(b7, key); + + key = round_keys[9]; + b0 = _mm_aesenc_si128(b0, key); + b1 = _mm_aesenc_si128(b1, key); + b2 = _mm_aesenc_si128(b2, key); + b3 = _mm_aesenc_si128(b3, key); + b4 = _mm_aesenc_si128(b4, key); + b5 = _mm_aesenc_si128(b5, key); + b6 = _mm_aesenc_si128(b6, key); + b7 = _mm_aesenc_si128(b7, key); + + key = round_keys[10]; + b0 = _mm_aesenclast_si128(b0, key); + b1 = _mm_aesenclast_si128(b1, key); + b2 = _mm_aesenclast_si128(b2, key); + b3 = _mm_aesenclast_si128(b3, key); + b4 = _mm_aesenclast_si128(b4, key); + b5 = _mm_aesenclast_si128(b5, key); + b6 = _mm_aesenclast_si128(b6, key); + b7 = _mm_aesenclast_si128(b7, key); + + /* Write the blocks. */ + _mm_storeu_si128(reinterpret_cast<__m128i *>(dst + BlockSize * 0), _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(src + BlockSize * 0)), b0)); + _mm_storeu_si128(reinterpret_cast<__m128i *>(dst + BlockSize * 1), _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(src + BlockSize * 1)), b1)); + _mm_storeu_si128(reinterpret_cast<__m128i *>(dst + BlockSize * 2), _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(src + BlockSize * 2)), b2)); + _mm_storeu_si128(reinterpret_cast<__m128i *>(dst + BlockSize * 3), _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(src + BlockSize * 3)), b3)); + _mm_storeu_si128(reinterpret_cast<__m128i *>(dst + BlockSize * 4), _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(src + BlockSize * 4)), b4)); + _mm_storeu_si128(reinterpret_cast<__m128i *>(dst + BlockSize * 5), _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(src + BlockSize * 5)), b5)); + _mm_storeu_si128(reinterpret_cast<__m128i *>(dst + BlockSize * 6), _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(src + BlockSize * 6)), b6)); + _mm_storeu_si128(reinterpret_cast<__m128i *>(dst + BlockSize * 7), _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(src + BlockSize * 7)), b7)); + + src += BlockSize * UnrolledBlockCount; + dst += BlockSize * UnrolledBlockCount; + } + + /* Store the updated counter. */ + _mm_storeu_si128(reinterpret_cast<__m128i *>(m_counter), counter); + + /* Process blocks one at a time. */ + for (/* ... */; cur_blocks < num_blocks; ++cur_blocks) { + /* Load current counter. */ + __m128i b = _mm_loadu_si128(reinterpret_cast(m_counter)); + + /* Do aes rounds. */ + b = _mm_xor_si128(b, round_keys[0]); + b = _mm_aesenc_si128(b, round_keys[1]); + b = _mm_aesenc_si128(b, round_keys[2]); + b = _mm_aesenc_si128(b, round_keys[3]); + b = _mm_aesenc_si128(b, round_keys[4]); + b = _mm_aesenc_si128(b, round_keys[5]); + b = _mm_aesenc_si128(b, round_keys[6]); + b = _mm_aesenc_si128(b, round_keys[7]); + b = _mm_aesenc_si128(b, round_keys[8]); + b = _mm_aesenc_si128(b, round_keys[9]); + b = _mm_aesenclast_si128(b, round_keys[10]); + + /* Write the block. */ + _mm_storeu_si128(reinterpret_cast<__m128i *>(dst), _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(src)), b)); + + /* Advance. */ + src += BlockSize; + dst += BlockSize; + this->IncrementCounter(); + } + } else { + /* Fall back to the default implementation. */ + while (num_blocks--) { + this->ProcessBlock(dst, src, BlockSize); + dst += BlockSize; + src += BlockSize; + } + } + } + +} diff --git a/libraries/libvapours/source/crypto/impl/crypto_sha1_impl.arch.arm64.cpp b/libraries/libvapours/source/crypto/impl/crypto_sha1_impl.arch.arm64.cpp index e01c9132d..b78ed33e5 100644 --- a/libraries/libvapours/source/crypto/impl/crypto_sha1_impl.arch.arm64.cpp +++ b/libraries/libvapours/source/crypto/impl/crypto_sha1_impl.arch.arm64.cpp @@ -15,31 +15,233 @@ */ #include +#if defined(ATMOSPHERE_IS_STRATOSPHERE) +#include + namespace ams::crypto::impl { -#ifdef ATMOSPHERE_IS_STRATOSPHERE + namespace { + + constexpr const u32 RoundConstants[4] = { + 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 + }; + + /* Define for loading work var from message. */ + #define SHA1_LOAD_W_FROM_MESSAGE(which) \ + w[which] = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(data))); \ + data += 0x10 + + #define SHA1_CALCULATE_W_FROM_PREVIOUS(i) \ + w[i] = vsha1su1q_u32(vsha1su0q_u32(w[i-4], w[i-3], w[i-2]), w[i-1]) + + /* Define for doing four rounds of SHA1. */ + #define SHA1_DO_ROUND(r, insn, constant) \ + do { \ + const u32 a = vgetq_lane_u32(cur_abcd, 0); \ + cur_abcd = v##insn##q_u32(cur_abcd, cur_e, vaddq_u32(w[r], constant)); \ + cur_e = vsha1h_u32(a); \ + } while (0) + + + } void Sha1Impl::Initialize() { - static_assert(sizeof(m_state) == sizeof(::Sha1Context)); - ::sha1ContextCreate(reinterpret_cast<::Sha1Context *>(std::addressof(m_state))); + /* Reset buffered bytes/bits. */ + m_buffered_bytes = 0; + m_bits_consumed = 0; + + /* Set intermediate hash. */ + m_intermediate_hash[0] = 0x67452301; + m_intermediate_hash[1] = 0xEFCDAB89; + m_intermediate_hash[2] = 0x98BADCFE; + m_intermediate_hash[3] = 0x10325476; + m_intermediate_hash[4] = 0xC3D2E1F0; + + /* Set state. */ + m_state = State_Initialized; } void Sha1Impl::Update(const void *data, size_t size) { - static_assert(sizeof(m_state) == sizeof(::Sha1Context)); - ::sha1ContextUpdate(reinterpret_cast<::Sha1Context *>(std::addressof(m_state)), data, size); + /* Verify we're in a state to update. */ + AMS_ASSERT(m_state == State_Initialized); + + /* Advance our input bit count. */ + m_bits_consumed += BITSIZEOF(u8) * (((m_buffered_bytes + size) / BlockSize) * BlockSize); + + /* Process anything we have buffered. */ + const u8 *data8 = static_cast(data); + size_t remaining = size; + + if (m_buffered_bytes > 0) { + const size_t copy_size = std::min(BlockSize - m_buffered_bytes, remaining); + std::memcpy(m_buffer + m_buffered_bytes, data8, copy_size); + + data8 += copy_size; + remaining -= copy_size; + m_buffered_bytes += copy_size; + + /* Process a block, if we filled one. */ + if (m_buffered_bytes == BlockSize) { + this->ProcessBlock(m_buffer); + m_buffered_bytes = 0; + } + } + + /* Process blocks, if we have any. */ + if (remaining >= BlockSize) { + const size_t blocks = remaining / BlockSize; + + this->ProcessBlocks(data8, blocks); + data8 += BlockSize * blocks; + remaining -= BlockSize * blocks; + } + + /* Copy any leftover data to our buffer. */ + if (remaining > 0) { + m_buffered_bytes = remaining; + std::memcpy(m_buffer, data8, remaining); + } } void Sha1Impl::GetHash(void *dst, size_t size) { - static_assert(sizeof(m_state) == sizeof(::Sha1Context)); + /* Verify we're in a state to get hash. */ + AMS_ASSERT(m_state == State_Initialized || m_state == State_Done); AMS_ASSERT(size >= HashSize); AMS_UNUSED(size); - ::sha1ContextGetHash(reinterpret_cast<::Sha1Context *>(std::addressof(m_state)), dst); + + /* If we need to, process the last block. */ + if (m_state == State_Initialized) { + this->ProcessLastBlock(); + m_state = State_Done; + } + + /* Copy the output hash. */ + if constexpr (util::IsLittleEndian()) { + static_assert(HashSize % sizeof(u32) == 0); + + u32 *dst_32 = static_cast(dst); + for (size_t i = 0; i < HashSize / sizeof(u32); ++i) { + dst_32[i] = util::LoadBigEndian(m_intermediate_hash + i); + } + } else { + std::memcpy(dst, m_intermediate_hash, HashSize); + } } -#else + ALWAYS_INLINE void Sha1Impl::ProcessBlock(const void *data) { + return this->ProcessBlocks(static_cast(data), 1); + } - /* TODO: Non-EL0 implementation. */ + void Sha1Impl::ProcessBlocks(const u8 *data, size_t block_count) { + /* Setup round constants. */ + const uint32x4_t k0 = vdupq_n_u32(RoundConstants[0]); + const uint32x4_t k1 = vdupq_n_u32(RoundConstants[1]); + const uint32x4_t k2 = vdupq_n_u32(RoundConstants[2]); + const uint32x4_t k3 = vdupq_n_u32(RoundConstants[3]); -#endif + /* Load hash variables with intermediate state. */ + uint32x4_t cur_abcd = vld1q_u32(m_intermediate_hash + 0); + u32 cur_e = m_intermediate_hash[4]; -} \ No newline at end of file + /* Actually do hash processing blocks. */ + do { + /* Save current state. */ + const uint32x4_t prev_abcd = cur_abcd; + const u32 prev_e = cur_e; + + uint32x4_t w[20]; + + /* Setup w[0-3] with message. */ + SHA1_LOAD_W_FROM_MESSAGE(0); + SHA1_LOAD_W_FROM_MESSAGE(1); + SHA1_LOAD_W_FROM_MESSAGE(2); + SHA1_LOAD_W_FROM_MESSAGE(3); + + /* Calculate w[4-19], w[i] = sha1su1(sha1su0(w[i-4], w[i-3], w[i-2]), w[i-1]); */ + SHA1_CALCULATE_W_FROM_PREVIOUS(4); + SHA1_CALCULATE_W_FROM_PREVIOUS(5); + SHA1_CALCULATE_W_FROM_PREVIOUS(6); + SHA1_CALCULATE_W_FROM_PREVIOUS(7); + SHA1_CALCULATE_W_FROM_PREVIOUS(8); + SHA1_CALCULATE_W_FROM_PREVIOUS(9); + SHA1_CALCULATE_W_FROM_PREVIOUS(10); + SHA1_CALCULATE_W_FROM_PREVIOUS(11); + SHA1_CALCULATE_W_FROM_PREVIOUS(12); + SHA1_CALCULATE_W_FROM_PREVIOUS(13); + SHA1_CALCULATE_W_FROM_PREVIOUS(14); + SHA1_CALCULATE_W_FROM_PREVIOUS(15); + SHA1_CALCULATE_W_FROM_PREVIOUS(16); + SHA1_CALCULATE_W_FROM_PREVIOUS(17); + SHA1_CALCULATE_W_FROM_PREVIOUS(18); + SHA1_CALCULATE_W_FROM_PREVIOUS(19); + + /* Do round calculations 0-20. Uses sha1c, k0. */ + SHA1_DO_ROUND(0, sha1c, k0); + SHA1_DO_ROUND(1, sha1c, k0); + SHA1_DO_ROUND(2, sha1c, k0); + SHA1_DO_ROUND(3, sha1c, k0); + SHA1_DO_ROUND(4, sha1c, k0); + + /* Do round calculations 20-40. Uses sha1p, k1. */ + SHA1_DO_ROUND(5, sha1p, k1); + SHA1_DO_ROUND(6, sha1p, k1); + SHA1_DO_ROUND(7, sha1p, k1); + SHA1_DO_ROUND(8, sha1p, k1); + SHA1_DO_ROUND(9, sha1p, k1); + + /* Do round calculations 40-60. Uses sha1m, k2. */ + SHA1_DO_ROUND(10, sha1m, k2); + SHA1_DO_ROUND(11, sha1m, k2); + SHA1_DO_ROUND(12, sha1m, k2); + SHA1_DO_ROUND(13, sha1m, k2); + SHA1_DO_ROUND(14, sha1m, k2); + + /* Do round calculations 60-80. Uses sha1p, k3. */ + SHA1_DO_ROUND(15, sha1p, k3); + SHA1_DO_ROUND(16, sha1p, k3); + SHA1_DO_ROUND(17, sha1p, k3); + SHA1_DO_ROUND(18, sha1p, k3); + SHA1_DO_ROUND(19, sha1p, k3); + + /* Add to previous. */ + cur_abcd = vaddq_u32(cur_abcd, prev_abcd); + cur_e = cur_e + prev_e; + } while (--block_count != 0); + + /* Save result to intermediate hash. */ + vst1q_u32(m_intermediate_hash, cur_abcd); + m_intermediate_hash[4] = cur_e; + } + + void Sha1Impl::ProcessLastBlock() { + /* Setup the final block. */ + constexpr const auto BlockSizeWithoutSizeField = BlockSize - sizeof(u64); + + /* Increment our bits consumed. */ + m_bits_consumed += BITSIZEOF(u8) * m_buffered_bytes; + + /* Add 0x80 terminator. */ + m_buffer[m_buffered_bytes++] = 0x80; + + /* If we can process the size field directly, do so, otherwise set up to process it. */ + if (m_buffered_bytes <= BlockSizeWithoutSizeField) { + /* Clear up to size field. */ + std::memset(m_buffer + m_buffered_bytes, 0, BlockSizeWithoutSizeField - m_buffered_bytes); + } else { + /* Consume full block */ + std::memset(m_buffer + m_buffered_bytes, 0, BlockSize - m_buffered_bytes); + this->ProcessBlock(m_buffer); + + /* Clear up to size field. */ + std::memset(m_buffer, 0, BlockSizeWithoutSizeField); + } + + /* Store the size field. */ + util::StoreBigEndian(reinterpret_cast(m_buffer + BlockSizeWithoutSizeField), m_bits_consumed); + + /* Process the final block. */ + this->ProcessBlock(m_buffer); + } + +} +#endif \ No newline at end of file diff --git a/libraries/libvapours/source/crypto/impl/crypto_sha1_impl.arch.generic.cpp b/libraries/libvapours/source/crypto/impl/crypto_sha1_impl.arch.generic.cpp new file mode 100644 index 000000000..2eda14d78 --- /dev/null +++ b/libraries/libvapours/source/crypto/impl/crypto_sha1_impl.arch.generic.cpp @@ -0,0 +1,225 @@ +/* + * Copyright (c) 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 + +namespace ams::crypto::impl { + + namespace { + + constexpr const u32 RoundConstants[4] = { + 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 + }; + + constexpr ALWAYS_INLINE u32 Choose(u32 x, u32 y, u32 z) { + return (x & y) ^ ((~x) & z); + } + + constexpr ALWAYS_INLINE u32 Majority(u32 x, u32 y, u32 z) { + return (x & y) ^ (x & z) ^ (y & z); + } + + constexpr ALWAYS_INLINE u32 Parity(u32 x, u32 y, u32 z) { + return x ^ y ^ z; + } + + } + + void Sha1Impl::Initialize() { + /* Reset buffered bytes/bits. */ + m_buffered_bytes = 0; + m_bits_consumed = 0; + + /* Set intermediate hash. */ + m_intermediate_hash[0] = 0x67452301; + m_intermediate_hash[1] = 0xEFCDAB89; + m_intermediate_hash[2] = 0x98BADCFE; + m_intermediate_hash[3] = 0x10325476; + m_intermediate_hash[4] = 0xC3D2E1F0; + + /* Set state. */ + m_state = State_Initialized; + } + + void Sha1Impl::Update(const void *data, size_t size) { + /* Verify we're in a state to update. */ + AMS_ASSERT(m_state == State_Initialized); + + /* Advance our input bit count. */ + m_bits_consumed += BITSIZEOF(u8) * (((m_buffered_bytes + size) / BlockSize) * BlockSize); + + /* Process anything we have buffered. */ + const u8 *data8 = static_cast(data); + size_t remaining = size; + + if (m_buffered_bytes > 0) { + const size_t copy_size = std::min(BlockSize - m_buffered_bytes, remaining); + std::memcpy(m_buffer + m_buffered_bytes, data8, copy_size); + + data8 += copy_size; + remaining -= copy_size; + m_buffered_bytes += copy_size; + + /* Process a block, if we filled one. */ + if (m_buffered_bytes == BlockSize) { + this->ProcessBlock(m_buffer); + m_buffered_bytes = 0; + } + } + + /* Process blocks, while we have any. */ + while (remaining >= BlockSize) { + this->ProcessBlock(data8); + data8 += BlockSize; + remaining -= BlockSize; + } + + /* Copy any leftover data to our buffer. */ + if (remaining > 0) { + m_buffered_bytes = remaining; + std::memcpy(m_buffer, data8, remaining); + } + } + + void Sha1Impl::GetHash(void *dst, size_t size) { + /* Verify we're in a state to get hash. */ + AMS_ASSERT(m_state == State_Initialized || m_state == State_Done); + AMS_ASSERT(size >= HashSize); + AMS_UNUSED(size); + + /* If we need to, process the last block. */ + if (m_state == State_Initialized) { + this->ProcessLastBlock(); + m_state = State_Done; + } + + /* Copy the output hash. */ + if constexpr (util::IsLittleEndian()) { + static_assert(HashSize % sizeof(u32) == 0); + + u32 *dst_32 = static_cast(dst); + for (size_t i = 0; i < HashSize / sizeof(u32); ++i) { + dst_32[i] = util::LoadBigEndian(m_intermediate_hash + i); + } + } else { + std::memcpy(dst, m_intermediate_hash, HashSize); + } + } + + void Sha1Impl::ProcessBlock(const void *data) { + /* Load work variables. */ + u32 a = m_intermediate_hash[0]; + u32 b = m_intermediate_hash[1]; + u32 c = m_intermediate_hash[2]; + u32 d = m_intermediate_hash[3]; + u32 e = m_intermediate_hash[4]; + u32 tmp; + size_t i; + + /* Copy the input. */ + u32 w[80]; + if constexpr (util::IsLittleEndian()) { + static_assert(BlockSize % sizeof(u32) == 0); + + const u32 *src_32 = static_cast(data); + for (size_t i = 0; i < BlockSize / sizeof(u32); ++i) { + w[i] = util::LoadBigEndian(src_32 + i); + } + } else { + std::memcpy(w, data, BlockSize); + } + + /* Initialize the rest of w. */ + for (i = BlockSize / sizeof(u32); i < util::size(w); ++i) { + const u32 *prev = w + (i - BlockSize / sizeof(u32)); + w[i] = util::RotateLeft(prev[0] ^ prev[2] ^ prev[8] ^ prev[13], 1); + } + + /* Perform rounds. */ + for (i = 0; i < 20; ++i) { + tmp = util::RotateLeft(a, 5) + Choose(b, c, d) + e + w[i] + RoundConstants[0]; + e = d; + d = c; + c = util::RotateLeft(b, 30); + b = a; + a = tmp; + } + + for (/* ... */; i < 40; ++i) { + tmp = util::RotateLeft(a, 5) + Parity(b, c, d) + e + w[i] + RoundConstants[1]; + e = d; + d = c; + c = util::RotateLeft(b, 30); + b = a; + a = tmp; + } + + for (/* ... */; i < 60; ++i) { + tmp = util::RotateLeft(a, 5) + Majority(b, c, d) + e + w[i] + RoundConstants[2]; + e = d; + d = c; + c = util::RotateLeft(b, 30); + b = a; + a = tmp; + } + + for (/* ... */; i < 80; ++i) { + tmp = util::RotateLeft(a, 5) + Parity(b, c, d) + e + w[i] + RoundConstants[3]; + e = d; + d = c; + c = util::RotateLeft(b, 30); + b = a; + a = tmp; + } + + /* Update intermediate hash. */ + m_intermediate_hash[0] += a; + m_intermediate_hash[1] += b; + m_intermediate_hash[2] += c; + m_intermediate_hash[3] += d; + m_intermediate_hash[4] += e; + } + + void Sha1Impl::ProcessLastBlock() { + /* Setup the final block. */ + constexpr const auto BlockSizeWithoutSizeField = BlockSize - sizeof(u64); + + /* Increment our bits consumed. */ + m_bits_consumed += BITSIZEOF(u8) * m_buffered_bytes; + + /* Add 0x80 terminator. */ + m_buffer[m_buffered_bytes++] = 0x80; + + /* If we can process the size field directly, do so, otherwise set up to process it. */ + if (m_buffered_bytes <= BlockSizeWithoutSizeField) { + /* Clear up to size field. */ + std::memset(m_buffer + m_buffered_bytes, 0, BlockSizeWithoutSizeField - m_buffered_bytes); + } else { + /* Consume full block */ + std::memset(m_buffer + m_buffered_bytes, 0, BlockSize - m_buffered_bytes); + this->ProcessBlock(m_buffer); + + /* Clear up to size field. */ + std::memset(m_buffer, 0, BlockSizeWithoutSizeField); + } + + /* Store the size field. */ + util::StoreBigEndian(reinterpret_cast(m_buffer + BlockSizeWithoutSizeField), m_bits_consumed); + + /* Process the final block. */ + this->ProcessBlock(m_buffer); + } + +} diff --git a/libraries/libvapours/source/crypto/impl/crypto_sha256_impl.arch.arm64.cpp b/libraries/libvapours/source/crypto/impl/crypto_sha256_impl.arch.arm64.cpp index 6235dd037..a332d7658 100644 --- a/libraries/libvapours/source/crypto/impl/crypto_sha256_impl.arch.arm64.cpp +++ b/libraries/libvapours/source/crypto/impl/crypto_sha256_impl.arch.arm64.cpp @@ -15,53 +15,313 @@ */ #include +#if defined(ATMOSPHERE_IS_STRATOSPHERE) +#include + namespace ams::crypto::impl { -#ifdef ATMOSPHERE_IS_STRATOSPHERE + namespace { + + alignas(Sha256Impl::BlockSize) constexpr const u32 RoundConstants[0x40] = { + 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, + 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, + 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, + 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, + 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, + 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, + 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, + 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, + 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, + 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, + 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, + 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, + 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, + 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, + 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, + 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2, + }; + + } void Sha256Impl::Initialize() { - static_assert(sizeof(m_state) == sizeof(::Sha256Context)); - ::sha256ContextCreate(reinterpret_cast<::Sha256Context *>(std::addressof(m_state))); + /* Reset buffered bytes/bits. */ + m_buffered_bytes = 0; + m_bits_consumed = 0; + + /* Set intermediate hash. */ + m_intermediate_hash[0] = 0x6A09E667; + m_intermediate_hash[1] = 0xBB67AE85; + m_intermediate_hash[2] = 0x3C6EF372; + m_intermediate_hash[3] = 0xA54FF53A; + m_intermediate_hash[4] = 0x510E527F; + m_intermediate_hash[5] = 0x9B05688C; + m_intermediate_hash[6] = 0x1F83D9AB; + m_intermediate_hash[7] = 0x5BE0CD19; + + /* Set state. */ + m_state = State_Initialized; } void Sha256Impl::Update(const void *data, size_t size) { - static_assert(sizeof(m_state) == sizeof(::Sha256Context)); - ::sha256ContextUpdate(reinterpret_cast<::Sha256Context *>(std::addressof(m_state)), data, size); + /* Verify we're in a state to update. */ + AMS_ASSERT(m_state == State_Initialized); + + /* Advance our input bit count. */ + m_bits_consumed += BITSIZEOF(u8) * (((m_buffered_bytes + size) / BlockSize) * BlockSize); + + /* Process anything we have buffered. */ + const u8 *data8 = static_cast(data); + size_t remaining = size; + + if (m_buffered_bytes > 0) { + const size_t copy_size = std::min(BlockSize - m_buffered_bytes, remaining); + std::memcpy(m_buffer + m_buffered_bytes, data8, copy_size); + + data8 += copy_size; + remaining -= copy_size; + m_buffered_bytes += copy_size; + + /* Process a block, if we filled one. */ + if (m_buffered_bytes == BlockSize) { + this->ProcessBlock(m_buffer); + m_buffered_bytes = 0; + } + } + + /* Process blocks, if we have any. */ + if (remaining >= BlockSize) { + const size_t blocks = remaining / BlockSize; + + this->ProcessBlocks(data8, blocks); + data8 += BlockSize * blocks; + remaining -= BlockSize * blocks; + } + + /* Copy any leftover data to our buffer. */ + if (remaining > 0) { + m_buffered_bytes = remaining; + std::memcpy(m_buffer, data8, remaining); + } } void Sha256Impl::GetHash(void *dst, size_t size) { - static_assert(sizeof(m_state) == sizeof(::Sha256Context)); + /* Verify we're in a state to get hash. */ + AMS_ASSERT(m_state == State_Initialized || m_state == State_Done); AMS_ASSERT(size >= HashSize); AMS_UNUSED(size); - ::sha256ContextGetHash(reinterpret_cast<::Sha256Context *>(std::addressof(m_state)), dst); + /* If we need to, process the last block. */ + if (m_state == State_Initialized) { + this->ProcessLastBlock(); + m_state = State_Done; + } + + /* Copy the output hash. */ + if constexpr (util::IsLittleEndian()) { + static_assert(HashSize % sizeof(u32) == 0); + + u32 *dst_32 = static_cast(dst); + for (size_t i = 0; i < HashSize / sizeof(u32); ++i) { + dst_32[i] = util::LoadBigEndian(m_intermediate_hash + i); + } + } else { + std::memcpy(dst, m_intermediate_hash, HashSize); + } } void Sha256Impl::InitializeWithContext(const Sha256Context *context) { - static_assert(sizeof(m_state) == sizeof(::Sha256Context)); - /* Copy state in from the context. */ - std::memcpy(m_state.intermediate_hash, context->intermediate_hash, sizeof(m_state.intermediate_hash)); - m_state.bits_consumed = context->bits_consumed; + std::memcpy(m_intermediate_hash, context->intermediate_hash, sizeof(m_intermediate_hash)); + m_bits_consumed = context->bits_consumed; - /* Clear the rest of state. */ - std::memset(m_state.buffer, 0, sizeof(m_state.buffer)); - m_state.num_buffered = 0; - m_state.finalized = false; + /* Reset other fields. */ + m_buffered_bytes = 0; + m_state = State_Initialized; } size_t Sha256Impl::GetContext(Sha256Context *context) const { - static_assert(sizeof(m_state) == sizeof(::Sha256Context)); - std::memcpy(context->intermediate_hash, m_state.intermediate_hash, sizeof(context->intermediate_hash)); - context->bits_consumed = m_state.bits_consumed; + /* Check our state. */ + AMS_ASSERT(m_state == State_Initialized); - return m_state.num_buffered; + /* Copy out the context. */ + std::memcpy(context->intermediate_hash, m_intermediate_hash, sizeof(context->intermediate_hash)); + context->bits_consumed = m_bits_consumed; + + return m_buffered_bytes; } -#else + ALWAYS_INLINE void Sha256Impl::ProcessBlock(const void *data) { + return this->ProcessBlocks(static_cast(data), 1); + } - /* TODO: Non-EL0 implementation. */ + void Sha256Impl::ProcessBlocks(const u8 *data, size_t block_count) { + /* Load previous hash with intermediate state, current hash with zeroes. */ + uint32x4_t prev_hash0 = vld1q_u32(m_intermediate_hash + 0); + uint32x4_t prev_hash1 = vld1q_u32(m_intermediate_hash + 4); + uint32x4_t cur_hash0 = vdupq_n_u32(0); + uint32x4_t cur_hash1 = vdupq_n_u32(0); -#endif + /* Process blocks. */ + do { + uint32x4_t round_constant0, round_constant1; + uint32x4_t data0, data1, data2, data3; + uint32x4_t tmp0, tmp1, tmp2, tmp3; + uint32x4_t tmp_hash; -} \ No newline at end of file + /* Use optimized ASM implementation to process the block. */ + __asm__ __volatile__ ( + "ldp %q[data0], %q[data1], [%[data]], #0x20\n" + "ldp %q[data2], %q[data3], [%[data]], #0x20\n" + "add %[cur_hash0].4s, %[cur_hash0].4s, %[prev_hash0].4s\n" + "ldp %q[round_constant0], %q[round_constant1], [%[round_constants], 0x00]\n" + "add %[cur_hash1].4s, %[cur_hash1].4s, %[prev_hash1].4s\n" + "rev32 %[data0].16b, %[data0].16b\n" + "rev32 %[data1].16b, %[data1].16b\n" + "rev32 %[data2].16b, %[data2].16b\n" + "rev32 %[data3].16b, %[data3].16b\n" + "add %[tmp0].4s, %[data0].4s, %[round_constant0].4s\n" + "add %[tmp1].4s, %[data1].4s, %[round_constant1].4s\n" + "ldp %q[round_constant0], %q[round_constant1], [%[round_constants], 0x20]\n" + "sha256su0 %[data0].4s, %[data1].4s\n" + "mov %[prev_hash0].16b, %[cur_hash0].16b\n" + "sha256h %q[cur_hash0], %q[cur_hash1], %[tmp0].4s\n" + "mov %[prev_hash1].16b, %[cur_hash1].16b\n" + "sha256h2 %q[cur_hash1], %q[prev_hash0], %[tmp0].4s\n" + "sha256su0 %[data1].4s, %[data2].4s\n" + "sha256su1 %[data0].4s, %[data2].4s, %[data3].4s\n" + "add %[tmp2].4s, %[data2].4s, %[round_constant0].4s\n" + "mov %[tmp_hash].16b, %[cur_hash0].16b\n" + "sha256h %q[cur_hash0], %q[cur_hash1], %[tmp1].4s\n" + "sha256h2 %q[cur_hash1], %q[tmp_hash], %[tmp1].4s\n" + "sha256su0 %[data2].4s, %[data3].4s\n" + "sha256su1 %[data1].4s, %[data3].4s, %[data0].4s\n" + "add %[tmp3].4s, %[data3].4s, %[round_constant1].4s\n" + "mov %[tmp_hash].16b, %[cur_hash0].16b\n" + "ldp %q[round_constant0], %q[round_constant1], [%[round_constants], 0x40]\n" + "sha256h %q[cur_hash0], %q[cur_hash1], %[tmp2].4s\n" + "sha256h2 %q[cur_hash1], %q[tmp_hash], %[tmp2].4s\n" + "sha256su0 %[data3].4s, %[data0].4s\n" + "sha256su1 %[data2].4s, %[data0].4s, %[data1].4s\n" + "add %[tmp0].4s, %[data0].4s, %[round_constant0].4s\n" + "mov %[tmp_hash].16b, %[cur_hash0].16b\n" + "sha256h %q[cur_hash0], %q[cur_hash1], %[tmp3].4s\n" + "sha256h2 %q[cur_hash1], %q[tmp_hash], %[tmp3].4s\n" + "sha256su0 %[data0].4s, %[data1].4s\n" + "sha256su1 %[data3].4s, %[data1].4s, %[data2].4s\n" + "add %[tmp1].4s, %[data1].4s, %[round_constant1].4s\n" + "mov %[tmp_hash].16b, %[cur_hash0].16b\n" + "ldp %q[round_constant0], %q[round_constant1], [%[round_constants], 0x60]\n" + "sha256h %q[cur_hash0], %q[cur_hash1], %[tmp0].4s\n" + "sha256h2 %q[cur_hash1], %q[tmp_hash], %[tmp0].4s\n" + "sha256su0 %[data1].4s, %[data2].4s\n" + "sha256su1 %[data0].4s, %[data2].4s, %[data3].4s\n" + "add %[tmp2].4s, %[data2].4s, %[round_constant0].4s\n" + "mov %[tmp_hash].16b, %[cur_hash0].16b\n" + "sha256h %q[cur_hash0], %q[cur_hash1], %[tmp1].4s\n" + "sha256h2 %q[cur_hash1], %q[tmp_hash], %[tmp1].4s\n" + "sha256su0 %[data2].4s, %[data3].4s\n" + "sha256su1 %[data1].4s, %[data3].4s, %[data0].4s\n" + "add %[tmp3].4s, %[data3].4s, %[round_constant1].4s\n" + "mov %[tmp_hash].16b, %[cur_hash0].16b\n" + "ldp %q[round_constant0], %q[round_constant1], [%[round_constants], 0x80]\n" + "sha256h %q[cur_hash0], %q[cur_hash1], %[tmp2].4s\n" + "sha256h2 %q[cur_hash1], %q[tmp_hash], %[tmp2].4s\n" + "sha256su0 %[data3].4s, %[data0].4s\n" + "sha256su1 %[data2].4s, %[data0].4s, %[data1].4s\n" + "add %[tmp0].4s, %[data0].4s, %[round_constant0].4s\n" + "mov %[tmp_hash].16b, %[cur_hash0].16b\n" + "sha256h %q[cur_hash0], %q[cur_hash1], %[tmp3].4s\n" + "sha256h2 %q[cur_hash1], %q[tmp_hash], %[tmp3].4s\n" + "sha256su0 %[data0].4s, %[data1].4s\n" + "sha256su1 %[data3].4s, %[data1].4s, %[data2].4s\n" + "add %[tmp1].4s, %[data1].4s, %[round_constant1].4s\n" + "mov %[tmp_hash].16b, %[cur_hash0].16b\n" + "ldp %q[round_constant0], %q[round_constant1], [%[round_constants], 0xA0]\n" + "sha256h %q[cur_hash0], %q[cur_hash1], %[tmp0].4s\n" + "sha256h2 %q[cur_hash1], %q[tmp_hash], %[tmp0].4s\n" + "sha256su0 %[data1].4s, %[data2].4s\n" + "sha256su1 %[data0].4s, %[data2].4s, %[data3].4s\n" + "add %[tmp2].4s, %[data2].4s, %[round_constant0].4s\n" + "mov %[tmp_hash].16b, %[cur_hash0].16b\n" + "sha256h %q[cur_hash0], %q[cur_hash1], %[tmp1].4s\n" + "sha256h2 %q[cur_hash1], %q[tmp_hash], %[tmp1].4s\n" + "sha256su0 %[data2].4s, %[data3].4s\n" + "sha256su1 %[data1].4s, %[data3].4s, %[data0].4s\n" + "add %[tmp3].4s, %[data3].4s, %[round_constant1].4s\n" + "mov %[tmp_hash].16b, %[cur_hash0].16b\n" + "ldp %q[round_constant0], %q[round_constant1], [%[round_constants], 0xC0]\n" + "sha256h %q[cur_hash0], %q[cur_hash1], %[tmp2].4s\n" + "sha256h2 %q[cur_hash1], %q[tmp_hash], %[tmp2].4s\n" + "sha256su0 %[data3].4s, %[data0].4s\n" + "sha256su1 %[data2].4s, %[data0].4s, %[data1].4s\n" + "add %[tmp0].4s, %[data0].4s, %[round_constant0].4s\n" + "mov %[tmp_hash].16b, %[cur_hash0].16b\n" + "sha256h %q[cur_hash0], %q[cur_hash1], %[tmp3].4s\n" + "sha256h2 %q[cur_hash1], %q[tmp_hash], %[tmp3].4s\n" + "sha256su1 %[data3].4s, %[data1].4s, %[data2].4s\n" + "add %[tmp1].4s, %[data1].4s, %[round_constant1].4s\n" + "mov %[tmp_hash].16b, %[cur_hash0].16b\n" + "ldp %q[round_constant0], %q[round_constant1], [%[round_constants], 0xE0]\n" + "sha256h %q[cur_hash0], %q[cur_hash1], %[tmp0].4s\n" + "sha256h2 %q[cur_hash1], %q[tmp_hash], %[tmp0].4s\n" + "add %[tmp2].4s, %[data2].4s, %[round_constant0].4s\n" + "mov %[tmp_hash].16b, %[cur_hash0].16b\n" + "sha256h %q[cur_hash0], %q[cur_hash1], %[tmp1].4s\n" + "sha256h2 %q[cur_hash1], %q[tmp_hash], %[tmp1].4s\n" + "add %[tmp3].4s, %[data3].4s, %[round_constant1].4s\n" + "mov %[tmp_hash].16b, %[cur_hash0].16b\n" + "sha256h %q[cur_hash0], %q[cur_hash1], %[tmp2].4s\n" + "sha256h2 %q[cur_hash1], %q[tmp_hash], %[tmp2].4s\n" + "mov %[tmp_hash].16b, %[cur_hash0].16b\n" + "sha256h %q[cur_hash0], %q[cur_hash1], %[tmp3].4s\n" + "sha256h2 %q[cur_hash1], %q[tmp_hash], %[tmp3].4s\n" + : [data0]"=w"(data0), [data1]"=w"(data1), [data2]"=w"(data2), [data3]"=w"(data3), + [tmp0]"=w"(tmp0), [tmp1]"=w"(tmp1), [tmp2]"=w"(tmp2), [tmp3]"=w"(tmp3), + [round_constant0]"=w"(round_constant0), [round_constant1]"=w"(round_constant1), + [cur_hash0]"+w"(cur_hash0), [cur_hash1]"+w"(cur_hash1), + [prev_hash0]"+w"(prev_hash0), [prev_hash1]"+w"(prev_hash1), + [tmp_hash]"=w"(tmp_hash), [data]"+r"(data) + : [round_constants]"r"(RoundConstants) + : + ); + } while (--block_count != 0); + + /* Add hashes together, and store. */ + cur_hash0 = vaddq_u32(prev_hash0, cur_hash0); + cur_hash1 = vaddq_u32(prev_hash1, cur_hash1); + vst1q_u32(m_intermediate_hash + 0, cur_hash0); + vst1q_u32(m_intermediate_hash + 4, cur_hash1); + } + + void Sha256Impl::ProcessLastBlock() { + /* Setup the final block. */ + constexpr const auto BlockSizeWithoutSizeField = BlockSize - sizeof(u64); + + /* Increment our bits consumed. */ + m_bits_consumed += BITSIZEOF(u8) * m_buffered_bytes; + + /* Add 0x80 terminator. */ + m_buffer[m_buffered_bytes++] = 0x80; + + /* If we can process the size field directly, do so, otherwise set up to process it. */ + if (m_buffered_bytes <= BlockSizeWithoutSizeField) { + /* Clear up to size field. */ + std::memset(m_buffer + m_buffered_bytes, 0, BlockSizeWithoutSizeField - m_buffered_bytes); + } else { + /* Consume full block */ + std::memset(m_buffer + m_buffered_bytes, 0, BlockSize - m_buffered_bytes); + this->ProcessBlock(m_buffer); + + /* Clear up to size field. */ + std::memset(m_buffer, 0, BlockSizeWithoutSizeField); + } + + /* Store the size field. */ + util::StoreBigEndian(reinterpret_cast(m_buffer + BlockSizeWithoutSizeField), m_bits_consumed); + + /* Process the final block. */ + this->ProcessBlock(m_buffer); + } + +} +#endif \ No newline at end of file diff --git a/libraries/libvapours/source/crypto/impl/crypto_sha256_impl.arch.generic.cpp b/libraries/libvapours/source/crypto/impl/crypto_sha256_impl.arch.generic.cpp new file mode 100644 index 000000000..ba7076c75 --- /dev/null +++ b/libraries/libvapours/source/crypto/impl/crypto_sha256_impl.arch.generic.cpp @@ -0,0 +1,260 @@ +/* + * Copyright (c) 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 + +namespace ams::crypto::impl { + + namespace { + + alignas(Sha256Impl::BlockSize) constexpr const u32 RoundConstants[0x40] = { + 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, + 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, + 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, + 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, + 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, + 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, + 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, + 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, + 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, + 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, + 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, + 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, + 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, + 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, + 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, + 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2, + }; + + constexpr ALWAYS_INLINE u32 Choose(u32 x, u32 y, u32 z) { + return (x & y) ^ ((~x) & z); + } + + constexpr ALWAYS_INLINE u32 Majority(u32 x, u32 y, u32 z) { + return (x & y) ^ (x & z) ^ (y & z); + } + + constexpr ALWAYS_INLINE u32 LargeSigma0(u32 x) { + return util::RotateRight(x, 2) ^ util::RotateRight(x, 13) ^ util::RotateRight(x, 22); + } + + constexpr ALWAYS_INLINE u32 LargeSigma1(u32 x) { + return util::RotateRight(x, 6) ^ util::RotateRight(x, 11) ^ util::RotateRight(x, 25); + } + + constexpr ALWAYS_INLINE u32 SmallSigma0(u32 x) { + return util::RotateRight(x, 7) ^ util::RotateRight(x, 18) ^ (x >> 3); + } + + constexpr ALWAYS_INLINE u32 SmallSigma1(u32 x) { + return util::RotateRight(x, 17) ^ util::RotateRight(x, 19) ^ (x >> 10); + } + + } + + void Sha256Impl::Initialize() { + /* Reset buffered bytes/bits. */ + m_buffered_bytes = 0; + m_bits_consumed = 0; + + /* Set intermediate hash. */ + m_intermediate_hash[0] = 0x6A09E667; + m_intermediate_hash[1] = 0xBB67AE85; + m_intermediate_hash[2] = 0x3C6EF372; + m_intermediate_hash[3] = 0xA54FF53A; + m_intermediate_hash[4] = 0x510E527F; + m_intermediate_hash[5] = 0x9B05688C; + m_intermediate_hash[6] = 0x1F83D9AB; + m_intermediate_hash[7] = 0x5BE0CD19; + + /* Set state. */ + m_state = State_Initialized; + } + + void Sha256Impl::Update(const void *data, size_t size) { + /* Verify we're in a state to update. */ + AMS_ASSERT(m_state == State_Initialized); + + /* Advance our input bit count. */ + m_bits_consumed += BITSIZEOF(u8) * (((m_buffered_bytes + size) / BlockSize) * BlockSize); + + /* Process anything we have buffered. */ + const u8 *data8 = static_cast(data); + size_t remaining = size; + + if (m_buffered_bytes > 0) { + const size_t copy_size = std::min(BlockSize - m_buffered_bytes, remaining); + std::memcpy(m_buffer + m_buffered_bytes, data8, copy_size); + + data8 += copy_size; + remaining -= copy_size; + m_buffered_bytes += copy_size; + + /* Process a block, if we filled one. */ + if (m_buffered_bytes == BlockSize) { + this->ProcessBlock(m_buffer); + m_buffered_bytes = 0; + } + } + + /* Process blocks, if we have any. */ + while (remaining >= BlockSize) { + this->ProcessBlock(data8); + data8 += BlockSize; + remaining -= BlockSize; + } + + /* Copy any leftover data to our buffer. */ + if (remaining > 0) { + m_buffered_bytes = remaining; + std::memcpy(m_buffer, data8, remaining); + } + } + + void Sha256Impl::GetHash(void *dst, size_t size) { + /* Verify we're in a state to get hash. */ + AMS_ASSERT(m_state == State_Initialized || m_state == State_Done); + AMS_ASSERT(size >= HashSize); + AMS_UNUSED(size); + + /* If we need to, process the last block. */ + if (m_state == State_Initialized) { + this->ProcessLastBlock(); + m_state = State_Done; + } + + /* Copy the output hash. */ + if constexpr (util::IsLittleEndian()) { + static_assert(HashSize % sizeof(u32) == 0); + + u32 *dst_32 = static_cast(dst); + for (size_t i = 0; i < HashSize / sizeof(u32); ++i) { + dst_32[i] = util::LoadBigEndian(m_intermediate_hash + i); + } + } else { + std::memcpy(dst, m_intermediate_hash, HashSize); + } + } + + void Sha256Impl::InitializeWithContext(const Sha256Context *context) { + /* Copy state in from the context. */ + std::memcpy(m_intermediate_hash, context->intermediate_hash, sizeof(m_intermediate_hash)); + m_bits_consumed = context->bits_consumed; + + /* Reset other fields. */ + m_buffered_bytes = 0; + m_state = State_Initialized; + } + + size_t Sha256Impl::GetContext(Sha256Context *context) const { + /* Check our state. */ + AMS_ASSERT(m_state == State_Initialized); + + /* Copy out the context. */ + std::memcpy(context->intermediate_hash, m_intermediate_hash, sizeof(context->intermediate_hash)); + context->bits_consumed = m_bits_consumed; + + return m_buffered_bytes; + } + + void Sha256Impl::ProcessBlock(const void *data) { + /* Load work variables. */ + u32 a = m_intermediate_hash[0]; + u32 b = m_intermediate_hash[1]; + u32 c = m_intermediate_hash[2]; + u32 d = m_intermediate_hash[3]; + u32 e = m_intermediate_hash[4]; + u32 f = m_intermediate_hash[5]; + u32 g = m_intermediate_hash[6]; + u32 h = m_intermediate_hash[7]; + u32 tmp[2]; + size_t i; + + /* Copy the input. */ + u32 w[64]; + if constexpr (util::IsLittleEndian()) { + static_assert(BlockSize % sizeof(u32) == 0); + + const u32 *src_32 = static_cast(data); + for (size_t i = 0; i < BlockSize / sizeof(u32); ++i) { + w[i] = util::LoadBigEndian(src_32 + i); + } + } else { + std::memcpy(w, data, BlockSize); + } + + /* Initialize the rest of w. */ + for (i = BlockSize / sizeof(u32); i < util::size(w); ++i) { + const u32 *prev = w + (i - BlockSize / sizeof(u32)); + w[i] = prev[0] + SmallSigma0(prev[1]) + prev[9] + SmallSigma1(prev[14]); + } + + /* Perform rounds. */ + for (i = 0; i < 64; ++i) { + tmp[0] = h + LargeSigma1(e) + Choose(e, f, g) + RoundConstants[i] + w[i]; + tmp[1] = LargeSigma0(a) + Majority(a, b, c); + + h = g; + g = f; + f = e; + e = d + tmp[0]; + d = c; + c = b; + b = a; + a = tmp[0] + tmp[1]; + } + + /* Update intermediate hash. */ + m_intermediate_hash[0] += a; + m_intermediate_hash[1] += b; + m_intermediate_hash[2] += c; + m_intermediate_hash[3] += d; + m_intermediate_hash[4] += e; + m_intermediate_hash[5] += f; + m_intermediate_hash[6] += g; + m_intermediate_hash[7] += h; + } + + void Sha256Impl::ProcessLastBlock() { + /* Setup the final block. */ + constexpr const auto BlockSizeWithoutSizeField = BlockSize - sizeof(u64); + + /* Increment our bits consumed. */ + m_bits_consumed += BITSIZEOF(u8) * m_buffered_bytes; + + /* Add 0x80 terminator. */ + m_buffer[m_buffered_bytes++] = 0x80; + + /* If we can process the size field directly, do so, otherwise set up to process it. */ + if (m_buffered_bytes <= BlockSizeWithoutSizeField) { + /* Clear up to size field. */ + std::memset(m_buffer + m_buffered_bytes, 0, BlockSizeWithoutSizeField - m_buffered_bytes); + } else { + /* Consume full block */ + std::memset(m_buffer + m_buffered_bytes, 0, BlockSize - m_buffered_bytes); + this->ProcessBlock(m_buffer); + + /* Clear up to size field. */ + std::memset(m_buffer, 0, BlockSizeWithoutSizeField); + } + + /* Store the size field. */ + util::StoreBigEndian(reinterpret_cast(m_buffer + BlockSizeWithoutSizeField), m_bits_consumed); + + /* Process the final block. */ + this->ProcessBlock(m_buffer); + } + +} diff --git a/libraries/libvapours/source/crypto/impl/crypto_sha3_impl.cpp b/libraries/libvapours/source/crypto/impl/crypto_sha3_impl.cpp new file mode 100644 index 000000000..5da8b159a --- /dev/null +++ b/libraries/libvapours/source/crypto/impl/crypto_sha3_impl.cpp @@ -0,0 +1,240 @@ +/* + * Copyright (c) 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 + +namespace ams::crypto::impl { + + namespace { + + constexpr auto NumRounds = 24; + + constexpr const u64 IotaRoundConstant[NumRounds] = { + UINT64_C(0x0000000000000001), UINT64_C(0x0000000000008082), + UINT64_C(0x800000000000808A), UINT64_C(0x8000000080008000), + UINT64_C(0x000000000000808B), UINT64_C(0x0000000080000001), + UINT64_C(0x8000000080008081), UINT64_C(0x8000000000008009), + UINT64_C(0x000000000000008A), UINT64_C(0x0000000000000088), + UINT64_C(0x0000000080008009), UINT64_C(0x000000008000000A), + UINT64_C(0x000000008000808B), UINT64_C(0x800000000000008B), + UINT64_C(0x8000000000008089), UINT64_C(0x8000000000008003), + UINT64_C(0x8000000000008002), UINT64_C(0x8000000000000080), + UINT64_C(0x000000000000800A), UINT64_C(0x800000008000000A), + UINT64_C(0x8000000080008081), UINT64_C(0x8000000000008080), + UINT64_C(0x0000000080000001), UINT64_C(0x8000000080008008) + }; + + constexpr const int RhoShiftBit[NumRounds] = { + 1, 3, 6, 10, 15, 21, 28, 36, + 45, 55, 2, 14, 27, 41, 56, 8, + 25, 43, 62, 18, 39, 61, 20, 44 + }; + + constexpr const int RhoNextIndex[NumRounds] = { + 10, 7, 11, 17, 18, 3, 5, 16, + 8, 21, 24, 4, 15, 23, 19, 13, + 12, 2, 20, 14, 22, 9, 6, 1 + }; + + } + + template + void Sha3Impl::Initialize() { + /* Clear internal state. */ + std::memset(m_internal_state, 0, sizeof(m_internal_state)); + + /* Reset buffered bytes. */ + m_buffered_bytes = 0; + + /* Set state. */ + m_state = State_Initialized; + } + + template + void Sha3Impl::Update(const void *data, size_t size) { + /* Verify we're in a state to update. */ + AMS_ASSERT(m_state == State_Initialized); + + /* Process we have anything buffered. */ + const u8 *data8 = static_cast(data); + size_t remaining = size; + if (m_buffered_bytes > 0) { + /* Determine how much we can copy. */ + const size_t copy_size = std::min(BlockSize - m_buffered_bytes, remaining); + + /* Mix the bytes into our state. */ + u8 *dst8 = reinterpret_cast(m_internal_state) + m_buffered_bytes; + for (size_t i = 0; i < copy_size; ++i) { + dst8[i] ^= data8[i]; + } + + /* Advance. */ + data8 += copy_size; + remaining -= copy_size; + m_buffered_bytes += copy_size; + + /* Process a block, if we filled one. */ + if (m_buffered_bytes == BlockSize) { + this->ProcessBlock(); + m_buffered_bytes = 0; + } + } + + /* Process blocks, if we have any. */ + while (remaining >= BlockSize) { + /* Mix the bytes into our state. */ + u8 *dst8 = reinterpret_cast(m_internal_state); + for (size_t i = 0; i < BlockSize; ++i) { + dst8[i] ^= data8[i]; + } + + this->ProcessBlock(); + + data8 += BlockSize; + remaining -= BlockSize; + } + + /* Copy any leftover data to our buffer. */ + if (remaining > 0) { + u8 *dst8 = reinterpret_cast(m_internal_state); + for (size_t i = 0; i < remaining; ++i) { + dst8[i] ^= data8[i]; + } + + m_buffered_bytes = remaining; + } + } + + template + void Sha3Impl::GetHash(void *dst, size_t size) { + /* Verify we're in a state to get hash. */ + AMS_ASSERT(m_state == State_Initialized || m_state == State_Done); + AMS_ASSERT(size >= HashSize); + AMS_UNUSED(size); + + /* If we need to, process the last block. */ + if (m_state == State_Initialized) { + this->ProcessLastBlock(); + m_state = State_Done; + } + + /* Copy the output hash. */ + std::memcpy(dst, m_internal_state, HashSize); + } + + template + void Sha3Impl::InitializeWithContext(const Sha3Context *context) { + /* Check the context is for the right hash size. */ + AMS_ASSERT(context->hash_size == HashSize); + + /* Set buffered bytes. */ + m_buffered_bytes = context->buffered_bytes; + + /* Copy state in from the context. */ + std::memcpy(m_internal_state, context->internal_state, sizeof(m_internal_state)); + + /* Reset other fields. */ + m_state = State_Initialized; + } + + template + void Sha3Impl::GetContext(Sha3Context *context) const { + /* Check our state. */ + AMS_ASSERT(m_state == State_Initialized); + + /* Set the output hash size. */ + context->hash_size = HashSize; + + /* Set buffered bytes. */ + context->buffered_bytes = m_buffered_bytes; + + /* Copy out the context. */ + std::memcpy(context->internal_state, m_internal_state, sizeof(context->internal_state)); + } + + template + void Sha3Impl::ProcessBlock() { + /* Ensure correct endianness. */ + if constexpr (util::IsBigEndian()) { + for (size_t i = 0; i < util::size(m_internal_state); ++i) { + m_internal_state[i] = util::LoadLittleEndian(m_internal_state + i); + } + } + + /* Perform all rounds. */ + uint64_t tmp, C[5]; + for (auto round = 0; round < NumRounds; ++round) { + /* Handle theta. */ + for (size_t i = 0; i < 5; ++i) { + C[i] = m_internal_state[i] ^ m_internal_state[i + 5] ^ m_internal_state[i + 10] ^ m_internal_state[i + 15] ^ m_internal_state[i + 20]; + } + + for (size_t i = 0; i < 5; ++i) { + tmp = C[(i + 4) % 5] ^ util::RotateLeft(C[(i + 1) % 5], 1); + for (size_t j = 0; j < 5; ++j) { + m_internal_state[5 * j + i] ^= tmp; + } + } + + /* Handle rho/pi. */ + tmp = m_internal_state[1]; + for (size_t i = 0; i < NumRounds; ++i) { + const auto rho_next_idx = RhoNextIndex[i]; + C[0] = m_internal_state[rho_next_idx]; + m_internal_state[rho_next_idx] = util::RotateLeft(tmp, RhoShiftBit[i]); + tmp = C[0]; + } + + /* Handle chi. */ + for (size_t i = 0; i < 5; ++i) { + for (size_t j = 0; j < 5; ++j) { + C[j] = m_internal_state[5 * i + j]; + } + for (size_t j = 0; j < 5; ++j) { + m_internal_state[5 * i + j] ^= (~C[(j + 1) % 5]) & C[(j + 2) % 5]; + } + } + + /* Handle iota. */ + m_internal_state[0] ^= IotaRoundConstant[round]; + } + /* Ensure correct endianness. */ + if constexpr (util::IsBigEndian()) { + for (size_t i = 0; i < util::size(m_internal_state); ++i) { + util::StoreLittleEndian(m_internal_state + i, m_internal_state[i]); + } + } + } + + template + void Sha3Impl::ProcessLastBlock() { + /* Mix final bits (011) into our state. */ + reinterpret_cast(m_internal_state)[m_buffered_bytes] ^= 0b110; + + /* Mix in the high bit of the last word in our block. */ + constexpr u64 FinalMask = UINT64_C(0x8000000000000000); + m_internal_state[(BlockSize / sizeof(u64)) - 1] ^= FinalMask; + + /* Process the last block. */ + this->ProcessBlock(); + } + + /* Explicitly instantiate the supported hash sizes. */ + template class Sha3Impl<224 / BITSIZEOF(u8)>; + template class Sha3Impl<256 / BITSIZEOF(u8)>; + template class Sha3Impl<384 / BITSIZEOF(u8)>; + template class Sha3Impl<512 / BITSIZEOF(u8)>; + +} diff --git a/libraries/libvapours/source/dd/dd_io_mapping.cpp b/libraries/libvapours/source/dd/dd_io_mapping.os.horizon.cpp similarity index 100% rename from libraries/libvapours/source/dd/dd_io_mapping.cpp rename to libraries/libvapours/source/dd/dd_io_mapping.os.horizon.cpp diff --git a/libraries/libvapours/source/dd/impl/dd_cache_impl.os.linux.hpp b/libraries/libvapours/source/dd/impl/dd_cache_impl.os.linux.hpp new file mode 100644 index 000000000..4fe82cd07 --- /dev/null +++ b/libraries/libvapours/source/dd/impl/dd_cache_impl.os.linux.hpp @@ -0,0 +1,89 @@ +/* + * Copyright (c) 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 +#if defined(ATMOSPHERE_IS_STRATOSPHERE) +#include +#else +#include +#endif + +namespace ams::dd::impl { + + void StoreDataCacheImpl(void *addr, size_t size) { + #if defined(ATMOSPHERE_ARCH_ARM64) + /* On aarch64, we can use cache maintenance instructions. */ + + /* Get cache line size. */ + uintptr_t ctr_el0 = 0; + __asm__ __volatile__("mrs %[ctr_el0], ctr_el0" : [ctr_el0]"=r"(ctr_el0)); + const uintptr_t cache_line_size = 4 << ((ctr_el0 >> 16) & 0xF); + + /* Invalidate the cache. */ + const uintptr_t start_addr = reinterpret_cast(addr) & ~(cache_line_size - 1); + const uintptr_t end_addr = reinterpret_cast(addr) + size; + for (uintptr_t cur = start_addr; cur < end_addr; cur += cache_line_size) { + __asm__ __volatile__("dc cvac, %[cur]" : : [cur]"r"(cur)); + } + + /* Add a memory barrier. */ + __asm__ __volatile__("dsb sy" ::: "memory"); + #elif defined(ATMOSPHERE_ARCH_X64) || defined(ATMOSPHERE_ARCH_X86) + /* Don't do anything, cache maintenance isn't available/relevant to userland. */ + AMS_UNUSED(addr, size); + #else + #error "Unknown architecture for linux dd::StoreDataCacheImpl" + #endif + } + + void FlushDataCacheImpl(void *addr, size_t size) { + #if defined(ATMOSPHERE_ARCH_ARM64) + /* On aarch64, we can use cache maintenance instructions. */ + + /* Get cache line size. */ + uintptr_t ctr_el0 = 0; + __asm__ __volatile__("mrs %[ctr_el0], ctr_el0" : [ctr_el0]"=r"(ctr_el0)); + const uintptr_t cache_line_size = 4 << ((ctr_el0 >> 16) & 0xF); + + /* Invalidate the cache. */ + const uintptr_t start_addr = reinterpret_cast(addr) & ~(cache_line_size - 1); + const uintptr_t end_addr = reinterpret_cast(addr) + size; + for (uintptr_t cur = start_addr; cur < end_addr; cur += cache_line_size) { + __asm__ __volatile__("dc civac, %[cur]" : : [cur]"r"(cur)); + } + + /* Add a memory barrier. */ + __asm__ __volatile__("dsb sy" ::: "memory"); + #elif defined(ATMOSPHERE_ARCH_X64) || defined(ATMOSPHERE_ARCH_X86) + /* Don't do anything, cache maintenance isn't available/relevant to userland. */ + AMS_UNUSED(addr, size); + #else + #error "Unknown architecture for linux dd::FlushDataCacheImpl" + #endif + } + + void InvalidateDataCacheImpl(void *addr, size_t size) { + #if defined(ATMOSPHERE_ARCH_ARM64) + /* Just perform a flush, which is clean + invalidate. */ + return FlushDataCacheImpl(addr, size); + #elif defined(ATMOSPHERE_ARCH_X64) || defined(ATMOSPHERE_ARCH_X86) + /* Don't do anything, cache maintenance isn't available/relevant to userland. */ + AMS_UNUSED(addr, size); + #else + #error "Unknown architecture for linux dd::InvalidateDataCacheImpl" + #endif + } + +} diff --git a/libraries/libvapours/source/dd/impl/dd_cache_impl.os.macos.hpp b/libraries/libvapours/source/dd/impl/dd_cache_impl.os.macos.hpp new file mode 100644 index 000000000..444f8e685 --- /dev/null +++ b/libraries/libvapours/source/dd/impl/dd_cache_impl.os.macos.hpp @@ -0,0 +1,89 @@ +/* + * Copyright (c) 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 +#if defined(ATMOSPHERE_IS_STRATOSPHERE) +#include +#else +#include +#endif + +namespace ams::dd::impl { + + void StoreDataCacheImpl(void *addr, size_t size) { + #if defined(ATMOSPHERE_ARCH_ARM64) + /* On aarch64, we can use cache maintenance instructions. */ + + /* Get cache line size. */ + uintptr_t ctr_el0 = 0; + __asm__ __volatile__("mrs %[ctr_el0], ctr_el0" : [ctr_el0]"=r"(ctr_el0)); + const uintptr_t cache_line_size = 4 << ((ctr_el0 >> 16) & 0xF); + + /* Invalidate the cache. */ + const uintptr_t start_addr = reinterpret_cast(addr) & ~(cache_line_size - 1); + const uintptr_t end_addr = reinterpret_cast(addr) + size; + for (uintptr_t cur = start_addr; cur < end_addr; cur += cache_line_size) { + __asm__ __volatile__("dc cvac, %[cur]" : : [cur]"r"(cur)); + } + + /* Add a memory barrier. */ + __asm__ __volatile__("dsb sy" ::: "memory"); + #elif defined(ATMOSPHERE_ARCH_X64) || defined(ATMOSPHERE_ARCH_X86) + /* Don't do anything, cache maintenance isn't available/relevant to userland. */ + AMS_UNUSED(addr, size); + #else + #error "Unknown architecture for macOS dd::StoreDataCacheImpl" + #endif + } + + void FlushDataCacheImpl(void *addr, size_t size) { + #if defined(ATMOSPHERE_ARCH_ARM64) + /* On aarch64, we can use cache maintenance instructions. */ + + /* Get cache line size. */ + uintptr_t ctr_el0 = 0; + __asm__ __volatile__("mrs %[ctr_el0], ctr_el0" : [ctr_el0]"=r"(ctr_el0)); + const uintptr_t cache_line_size = 4 << ((ctr_el0 >> 16) & 0xF); + + /* Invalidate the cache. */ + const uintptr_t start_addr = reinterpret_cast(addr) & ~(cache_line_size - 1); + const uintptr_t end_addr = reinterpret_cast(addr) + size; + for (uintptr_t cur = start_addr; cur < end_addr; cur += cache_line_size) { + __asm__ __volatile__("dc civac, %[cur]" : : [cur]"r"(cur)); + } + + /* Add a memory barrier. */ + __asm__ __volatile__("dsb sy" ::: "memory"); + #elif defined(ATMOSPHERE_ARCH_X64) || defined(ATMOSPHERE_ARCH_X86) + /* Don't do anything, cache maintenance isn't available/relevant to userland. */ + AMS_UNUSED(addr, size); + #else + #error "Unknown architecture for macOS dd::FlushDataCacheImpl" + #endif + } + + void InvalidateDataCacheImpl(void *addr, size_t size) { + #if defined(ATMOSPHERE_ARCH_ARM64) + /* Just perform a flush, which is clean + invalidate. */ + return FlushDataCacheImpl(addr, size); + #elif defined(ATMOSPHERE_ARCH_X64) || defined(ATMOSPHERE_ARCH_X86) + /* Don't do anything, cache maintenance isn't available/relevant to userland. */ + AMS_UNUSED(addr, size); + #else + #error "Unknown architecture for macOS dd::InvalidateDataCacheImpl" + #endif + } + +} diff --git a/libraries/libvapours/source/dd/impl/dd_cache_impl.os.windows.hpp b/libraries/libvapours/source/dd/impl/dd_cache_impl.os.windows.hpp new file mode 100644 index 000000000..7dba8676c --- /dev/null +++ b/libraries/libvapours/source/dd/impl/dd_cache_impl.os.windows.hpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 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 +#if defined(ATMOSPHERE_IS_STRATOSPHERE) +#include +#else +#include +#endif + +namespace ams::dd::impl { + + void StoreDataCacheImpl(void *addr, size_t size) { + #if defined(ATMOSPHERE_ARCH_X64) || defined(ATMOSPHERE_ARCH_X86) + /* Don't do anything, cache maintenance isn't available/relevant to userland. */ + AMS_UNUSED(addr, size); + #else + #error "Unknown architecture for windows dd::StoreDataCacheImpl" + #endif + } + + void FlushDataCacheImpl(void *addr, size_t size) { + #if defined(ATMOSPHERE_ARCH_X64) || defined(ATMOSPHERE_ARCH_X86) + /* Don't do anything, cache maintenance isn't available/relevant to userland. */ + AMS_UNUSED(addr, size); + #else + #error "Unknown architecture for windows dd::FlushDataCacheImpl" + #endif + } + + void InvalidateDataCacheImpl(void *addr, size_t size) { + #if defined(ATMOSPHERE_ARCH_X64) || defined(ATMOSPHERE_ARCH_X86) + /* Don't do anything, cache maintenance isn't available/relevant to userland. */ + AMS_UNUSED(addr, size); + #else + #error "Unknown architecture for windows dd::InvalidateDataCacheImpl" + #endif + } + +} diff --git a/libraries/libvapours/source/dd/impl/dd_select_cache_impl.hpp b/libraries/libvapours/source/dd/impl/dd_select_cache_impl.hpp index f32aa2cf6..5292da7e7 100644 --- a/libraries/libvapours/source/dd/impl/dd_select_cache_impl.hpp +++ b/libraries/libvapours/source/dd/impl/dd_select_cache_impl.hpp @@ -17,6 +17,12 @@ #if defined(ATMOSPHERE_OS_HORIZON) #include "dd_cache_impl.os.horizon.hpp" +#elif defined(ATMOSPHERE_OS_WINDOWS) + #include "dd_cache_impl.os.windows.hpp" +#elif defined(ATMOSPHERE_OS_LINUX) + #include "dd_cache_impl.os.linux.hpp" +#elif defined(ATMOSPHERE_OS_MACOS) + #include "dd_cache_impl.os.macos.hpp" #else #error "Unknown OS for ams::dd::CacheImpl" #endif diff --git a/libraries/libvapours/source/sdmmc/impl/sdmmc_port_gc_asic0.cpp b/libraries/libvapours/source/sdmmc/impl/sdmmc_port_gc_asic0.board.nintendo_nx.cpp similarity index 100% rename from libraries/libvapours/source/sdmmc/impl/sdmmc_port_gc_asic0.cpp rename to libraries/libvapours/source/sdmmc/impl/sdmmc_port_gc_asic0.board.nintendo_nx.cpp diff --git a/libraries/libvapours/source/sdmmc/impl/sdmmc_port_mmc0.cpp b/libraries/libvapours/source/sdmmc/impl/sdmmc_port_mmc0.board.nintendo_nx.cpp similarity index 100% rename from libraries/libvapours/source/sdmmc/impl/sdmmc_port_mmc0.cpp rename to libraries/libvapours/source/sdmmc/impl/sdmmc_port_mmc0.board.nintendo_nx.cpp diff --git a/libraries/libvapours/source/sdmmc/impl/sdmmc_port_sd_card0.cpp b/libraries/libvapours/source/sdmmc/impl/sdmmc_port_sd_card0.board.nintendo_nx.cpp similarity index 100% rename from libraries/libvapours/source/sdmmc/impl/sdmmc_port_sd_card0.cpp rename to libraries/libvapours/source/sdmmc/impl/sdmmc_port_sd_card0.board.nintendo_nx.cpp diff --git a/libraries/libvapours/source/sdmmc/impl/sdmmc_sd_host_standard_controller.hpp b/libraries/libvapours/source/sdmmc/impl/sdmmc_sd_host_standard_controller.hpp index 0d91209e7..f6501547c 100644 --- a/libraries/libvapours/source/sdmmc/impl/sdmmc_sd_host_standard_controller.hpp +++ b/libraries/libvapours/source/sdmmc/impl/sdmmc_sd_host_standard_controller.hpp @@ -174,12 +174,12 @@ namespace ams::sdmmc::impl { return false; } - virtual Result Tuning(SpeedMode speed_mode, u32 command_index) { + virtual Result Tuning(SpeedMode speed_mode, u32 command_index) override { AMS_UNUSED(speed_mode, command_index); AMS_ABORT("Tuning not supported\n"); } - virtual void SaveTuningStatusForHs400() { + virtual void SaveTuningStatusForHs400() override { AMS_ABORT("SaveTuningStatusForHs400 not supported\n"); } diff --git a/libraries/libvapours/source/sdmmc/impl/sdmmc_timer.cpp b/libraries/libvapours/source/sdmmc/impl/sdmmc_timer.cpp index 7999af03f..b3d825581 100644 --- a/libraries/libvapours/source/sdmmc/impl/sdmmc_timer.cpp +++ b/libraries/libvapours/source/sdmmc/impl/sdmmc_timer.cpp @@ -43,6 +43,9 @@ namespace ams::sdmmc::impl { __asm__ __volatile__("dsb sy" ::: "memory"); #elif defined(ATMOSPHERE_ARCH_ARM) __asm__ __volatile__("dsb" ::: "memory"); + #elif defined(ATMOSPHERE_ARCH_X64) || defined(ATMOSPHERE_ARCH_X86) + /* Nothing needed? */ + __asm__ __volatile__("" ::: "memory"); #else #error "Unknown architecture for DataSynchronizationBarrier" #endif @@ -51,6 +54,9 @@ namespace ams::sdmmc::impl { ALWAYS_INLINE void InstructionSynchronizationBarrier() { #if defined(ATMOSPHERE_ARCH_ARM64) || defined(ATMOSPHERE_ARCH_ARM) __asm__ __volatile__("isb" ::: "memory"); + #elif defined(ATMOSPHERE_ARCH_X64) || defined(ATMOSPHERE_ARCH_X86) + /* Nothing needed? */ + __asm__ __volatile__("" ::: "memory"); #else #error "Unknown architecture for InstructionSynchronizationBarrier" #endif diff --git a/libraries/libvapours/source/util/util_character_encoding.cpp b/libraries/libvapours/source/util/util_character_encoding.cpp deleted file mode 100644 index 2ea2897d8..000000000 --- a/libraries/libvapours/source/util/util_character_encoding.cpp +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (c) 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 - -namespace ams::util { - - namespace { - - constexpr inline int8_t Utf8NBytesInnerTable[0x100 + 1] = { - -1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8, - }; - - constexpr inline const char * const Utf8NBytesTable = static_cast(static_cast(Utf8NBytesInnerTable + 1)); - - } - - CharacterEncodingResult ConvertCharacterUtf8ToUtf32(u32 *dst, const char *src) { - /* Check pre-conditions. */ - AMS_ASSERT(dst != nullptr); - AMS_ASSERT(src != nullptr); - - /* Perform the conversion. */ - const unsigned char *p = reinterpret_cast(src); - switch (Utf8NBytesTable[p[0]]) { - case 1: - *dst = static_cast(p[0]); - return CharacterEncodingResult_Success; - case 2: - if ((p[0] & 0x1E) != 0) { - if (Utf8NBytesTable[p[1]] == 0) { - *dst = (static_cast(p[0] & 0x1F) << 6) | (static_cast(p[1] & 0x3F) << 0); - return CharacterEncodingResult_Success; - } - } - break; - case 3: - if (Utf8NBytesTable[p[1]] == 0 && Utf8NBytesTable[p[2]] == 0) { - const u32 c = (static_cast(p[0] & 0xF) << 12) | (static_cast(p[1] & 0x3F) << 6) | (static_cast(p[2] & 0x3F) << 0); - if ((c & 0xF800) != 0 && (c & 0xF800) != 0xD800) { - *dst = c; - return CharacterEncodingResult_Success; - } - } - return CharacterEncodingResult_InvalidFormat; - case 4: - if (Utf8NBytesTable[p[1]] == 0 && Utf8NBytesTable[p[2]] == 0 && Utf8NBytesTable[p[3]] == 0) { - const u32 c = (static_cast(p[0] & 0x7) << 18) | (static_cast(p[1] & 0x3F) << 12) | (static_cast(p[2] & 0x3F) << 6) | (static_cast(p[3] & 0x3F) << 0); - if (c >= 0x10000 && c < 0x110000) { - *dst = c; - return CharacterEncodingResult_Success; - } - } - return CharacterEncodingResult_InvalidFormat; - default: - break; - } - - /* We failed to convert. */ - return CharacterEncodingResult_InvalidFormat; - } - - CharacterEncodingResult PickOutCharacterFromUtf8String(char *dst, const char **str) { - /* Check pre-conditions. */ - AMS_ASSERT(dst != nullptr); - AMS_ASSERT(str != nullptr); - AMS_ASSERT(*str != nullptr); - - /* Clear the output. */ - dst[0] = 0; - dst[1] = 0; - dst[2] = 0; - dst[3] = 0; - - /* Perform the conversion. */ - const unsigned char *p = reinterpret_cast(*str); - u32 c = *p; - switch (Utf8NBytesTable[c]) { - case 1: - dst[0] = (*str)[0]; - ++(*str); - break; - case 2: - if ((p[0] & 0x1E) != 0) { - if (Utf8NBytesTable[p[1]] == 0) { - c = (static_cast(p[0] & 0x1F) << 6) | (static_cast(p[1] & 0x3F) << 0); - dst[0] = (*str)[0]; - dst[1] = (*str)[1]; - (*str) += 2; - break; - } - } - return CharacterEncodingResult_InvalidFormat; - case 3: - if (Utf8NBytesTable[p[1]] == 0 && Utf8NBytesTable[p[2]] == 0) { - c = (static_cast(p[0] & 0xF) << 12) | (static_cast(p[1] & 0x3F) << 6) | (static_cast(p[2] & 0x3F) << 0); - if ((c & 0xF800) != 0 && (c & 0xF800) != 0xD800) { - dst[0] = (*str)[0]; - dst[1] = (*str)[1]; - dst[2] = (*str)[2]; - (*str) += 3; - break; - } - } - return CharacterEncodingResult_InvalidFormat; - case 4: - if (Utf8NBytesTable[p[1]] == 0 && Utf8NBytesTable[p[2]] == 0 && Utf8NBytesTable[p[3]] == 0) { - c = (static_cast(p[0] & 0x7) << 18) | (static_cast(p[1] & 0x3F) << 12) | (static_cast(p[2] & 0x3F) << 6) | (static_cast(p[3] & 0x3F) << 0); - if (c >= 0x10000 && c < 0x110000) { - dst[0] = (*str)[0]; - dst[1] = (*str)[1]; - dst[2] = (*str)[2]; - dst[3] = (*str)[3]; - (*str) += 4; - break; - } - } - return CharacterEncodingResult_InvalidFormat; - default: - return CharacterEncodingResult_InvalidFormat; - } - - return CharacterEncodingResult_Success; - } - -} diff --git a/libraries/libvapours/source/util/util_format_string.cpp b/libraries/libvapours/source/util/util_format_string.cpp index c2631313c..e27bb4457 100644 --- a/libraries/libvapours/source/util/util_format_string.cpp +++ b/libraries/libvapours/source/util/util_format_string.cpp @@ -17,8 +17,7 @@ namespace ams::util { - #pragma GCC push_options - #pragma GCC optimize ("-Os") + AMS_PRAGMA_BEGIN_OPTIMIZE_O3() namespace { @@ -403,7 +402,7 @@ namespace ams::util { } - #pragma GCC pop_options + AMS_PRAGMA_END_OPTIMIZE() int TVSNPrintf(char *dst, size_t dst_size, const char *fmt, std::va_list vl) { return TVSNPrintfImpl(dst, dst_size, fmt, vl); diff --git a/mesosphere/Makefile b/mesosphere/Makefile index 451a68a3e..05c8b1679 100644 --- a/mesosphere/Makefile +++ b/mesosphere/Makefile @@ -1,59 +1,42 @@ ATMOSPHERE_BUILD_CONFIGS := -all: release +all: nx_release + +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) define ATMOSPHERE_ADD_TARGET ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -$(strip $1): mesosphere$(strip $2).bin - -mesosphere$(strip $2).bin: kernel/kernel$(strip $2).bin kernel_ldr/kernel_ldr$(strip $2).bin - @python build_mesosphere.py kernel_ldr/kernel_ldr$(strip $2).bin kernel/kernel$(strip $2).bin mesosphere$(strip $2).bin $(4) - @echo "Built mesosphere$(strip $2).bin..." - -kernel/kernel$(strip $2).bin: check_libmeso$(strip $1) - @$$(MAKE) -C kernel $(strip $1) $(3) - -kernel_ldr/kernel_ldr$(strip $2).bin: check_libmeso$(strip $1) - @$$(MAKE) -C kernel_ldr $(strip $1) $(3) - -check_libmeso$(strip $1): - @$$(MAKE) -C ../libraries/libmesosphere $(strip $1) $(3) +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/mesosphere.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) clean-$(strip $1): - @$$(MAKE) -C ../libraries/libmesosphere clean-$(strip $1) $(3) - @$$(MAKE) -C kernel clean-$(strip $1) $(3) - @$$(MAKE) -C kernel_ldr clean-$(strip $1) $(3) - @rm -f mesosphere$(strip $2).bin + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/mesosphere.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) endef -$(eval $(call ATMOSPHERE_ADD_TARGET, release, ,,)) -$(eval $(call ATMOSPHERE_ADD_TARGET, debug, _debug,,)) -$(eval $(call ATMOSPHERE_ADD_TARGET, audit, _audit,,)) +define ATMOSPHERE_ADD_TARGETS -$(eval $(call ATMOSPHERE_ADD_TARGET, qemu_virt_release, _qemu_virt, \ - ATMOSPHERE_BOARD="qemu-virt" \ - ATMOSPHERE_CPU="arm-cortex-a57" \ - , ../tests/TestSvc/TestSvc.kip \ +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ )) -$(eval $(call ATMOSPHERE_ADD_TARGET, qemu_virt_debug, _qemu_virt_debug, \ - ATMOSPHERE_BOARD="qemu-virt" \ - ATMOSPHERE_CPU="arm-cortex-a57" \ - , ../tests/TestSvc/TestSvc.kip \ +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ )) -$(eval $(call ATMOSPHERE_ADD_TARGET, qemu_virt_audit, _qemu_virt_audit, \ - ATMOSPHERE_BOARD="qemu-virt" \ - ATMOSPHERE_CPU="arm-cortex-a57" \ - , ../tests/TestSvc/TestSvc.kip \ +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ )) -clean: - @$(MAKE) -C ../libraries/libmesosphere clean - @$(MAKE) -C kernel clean - @$(MAKE) -C kernel_ldr clean - @rm -f mesosphere*.bin +endef -.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),$(config) clean-$(config)) +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) +$(eval $(call ATMOSPHERE_ADD_TARGETS, qemu_virt_a57, qemu-virt, arm-cortex-a57,)) + +clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) + +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/mesosphere/kernel/Makefile b/mesosphere/kernel/Makefile index 840249d77..f52b77a99 100644 --- a/mesosphere/kernel/Makefile +++ b/mesosphere/kernel/Makefile @@ -1,146 +1,42 @@ -#--------------------------------------------------------------------------------- -# pull in common atmosphere configuration -#--------------------------------------------------------------------------------- +ATMOSPHERE_BUILD_CONFIGS := +all: nx_release + THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) -include $(CURRENT_DIRECTORY)/../../libraries/config/templates/mesosphere.mk - -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(__RECURSIVE__),1) -#--------------------------------------------------------------------------------- - -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) - -CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) -CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) -SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),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_BIN := $(addsuffix .h,$(subst .,_,$(subst -,_,$(BINFILES)))) - -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I. - -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) - -export TOPDIR := $(CURRENT_DIRECTORY) - -OUTPUT_BASE := $(TOPDIR)/$(notdir $(TOPDIR)) - -#--------------------------------------------------------------------------------- - -ATMOSPHERE_BUILD_CONFIGS := -all: release define ATMOSPHERE_ADD_TARGET ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -$(strip $1): check_libmeso_$(strip $1) $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) - @$$(MAKE) __RECURSIVE__=1 OUTPUT=$$(OUTPUT_BASE)$(strip $2) $(3) \ - DEPSDIR=$$(CURDIR)/$$(ATMOSPHERE_BUILD_DIR)/$(strip $1) \ - LIBMESOSPHERE_NAME=mesosphere$(strip $2) \ - --no-print-directory -C $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) \ - -f $$(THIS_MAKEFILE) - -check_libmeso_$(strip $1): - @$$(MAKE) --no-print-directory -C ../../libraries/libmesosphere $(strip $1) +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/kernel.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) clean-$(strip $1): - @echo clean $(strip $1) ... - @rm -fr $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) $$(OUTPUT_BASE)$(strip $2).bin $$(OUTPUT_BASE)$(strip $2).elf + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/kernel.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) endef -$(eval $(call ATMOSPHERE_ADD_TARGET, release, , \ - ATMOSPHERE_BUILD_SETTINGS="" \ +define ATMOSPHERE_ADD_TARGETS + +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ )) -$(eval $(call ATMOSPHERE_ADD_TARGET, debug, _debug, \ - ATMOSPHERE_BUILD_SETTINGS="-DMESOSPHERE_BUILD_FOR_DEBUGGING" \ +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ )) -$(eval $(call ATMOSPHERE_ADD_TARGET, audit, _audit, \ - ATMOSPHERE_BUILD_SETTINGS="-DMESOSPHERE_BUILD_FOR_AUDITING" \ +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ )) -$(eval $(call ATMOSPHERE_ADD_TARGET, qemu_virt_release, _qemu_virt, \ - ATMOSPHERE_BUILD_SETTINGS="" \ -)) +endef -$(eval $(call ATMOSPHERE_ADD_TARGET, qemu_virt_debug, _qemu_virt_debug, \ - ATMOSPHERE_BUILD_SETTINGS="-DMESOSPHERE_BUILD_FOR_DEBUGGING" \ -)) +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) +$(eval $(call ATMOSPHERE_ADD_TARGETS, qemu_virt_a57, qemu-virt, arm-cortex-a57,)) -$(eval $(call ATMOSPHERE_ADD_TARGET, qemu_virt_audit, _qemu_virt_audit, \ - ATMOSPHERE_BUILD_SETTINGS="-DMESOSPHERE_BUILD_FOR_AUDITING" \ -)) - -$(ATMOSPHERE_BUILD_DIR)/%: - @[ -d $@ ] || mkdir -p $@ - -#--------------------------------------------------------------------------------- clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) -.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),$(config) clean-$(config)) - -#--------------------------------------------------------------------------------- -else - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- -$(OUTPUT).bin : $(OUTPUT).elf - $(OBJCOPY) -S -O binary $< $@ - @echo built ... $(notdir $@) - -$(OUTPUT).elf : $(OFILES) - -$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libmesosphere/$(ATMOSPHERE_LIBRARY_DIR)/lib$(LIBMESOSPHERE_NAME).a - -%.elf: - @echo linking $(notdir $@) - $(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ - @$(NM) -CSn $@ > $(notdir $*.lst) - -$(OFILES_SRC) : $(HFILES_BIN) - -kern_libc_generic.o: CFLAGS += -fno-builtin -kern_kernel_instantiations.o: CXXFLAGS += -flto - -#--------------------------------------------------------------------------------- -# you need a rule like this for each extension you use as binary data -#--------------------------------------------------------------------------------- -%.bin.o %_bin.h: %.bin -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) - --include $(DEPENDS) - -#--------------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------------- \ No newline at end of file +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/mesosphere/kernel/kernel.mk b/mesosphere/kernel/kernel.mk new file mode 100644 index 000000000..9d9896fab --- /dev/null +++ b/mesosphere/kernel/kernel.mk @@ -0,0 +1,112 @@ +#--------------------------------------------------------------------------------- +# pull in common atmosphere configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(CURRENT_DIRECTORY)/../../libraries/config/templates/mesosphere.mk + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(__RECURSIVE__),1) +#--------------------------------------------------------------------------------- + +export ATMOSPHERE_TOPDIR := $(CURRENT_DIRECTORY) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) +CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) +SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),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_BIN := $(addsuffix .h,$(subst .,_,$(subst -,_,$(BINFILES)))) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I. + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) + +.PHONY: clean all check_lib + +#--------------------------------------------------------------------------------- +all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libmesosphere/$(ATMOSPHERE_LIBRARY_DIR)/libmesosphere.a + @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/$(notdir $(ATMOSPHERE_TOPDIR)) \ + DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ + --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ + -f $(THIS_MAKEFILE) + +$(ATMOSPHERE_LIBRARIES_DIR)/libmesosphere/$(ATMOSPHERE_LIBRARY_DIR)/libmesosphere.a: check_lib + @$(SILENTCMD)echo "Checked library." + +ifeq ($(ATMOSPHERE_CHECKED_LIBMESOSPHERE),1) +check_lib: +else +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libmesosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libmesosphere/libmesosphere.mk +endif + +$(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): + @[ -d $@ ] || mkdir -p $@ + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_OUT_DIR) + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT).bin : $(OUTPUT).elf + $(OBJCOPY) -S -O binary $< $@ + @echo built ... $(notdir $@) + +$(OUTPUT).elf : $(OFILES) $(ATMOSPHERE_LIBRARIES_DIR)/libmesosphere/$(ATMOSPHERE_LIBRARY_DIR)/libmesosphere.a + +%.elf: + @echo linking $(notdir $@) + $(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ + @$(NM) -CSn $@ > $(notdir $*.lst) + +$(OFILES_SRC) : $(HFILES_BIN) + +kern_libc_generic.o: CFLAGS += -fno-builtin +kern_kernel_instantiations.o: CXXFLAGS += -flto + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o %_bin.h: %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- \ No newline at end of file diff --git a/mesosphere/kernel/kernel.specs b/mesosphere/kernel/kernel.specs index c83d201a5..b849ab5cf 100644 --- a/mesosphere/kernel/kernel.specs +++ b/mesosphere/kernel/kernel.specs @@ -1,7 +1,7 @@ %rename link old_link *link: -%(old_link) -T %:getenv(TOPDIR /kernel.ld) -pie --gc-sections -z text -z nodynamic-undefined-weak -nostdlib -nostartfiles +%(old_link) -T %:getenv(ATMOSPHERE_TOPDIR /kernel.ld) -pie --gc-sections -z text -z nodynamic-undefined-weak -nostdlib -nostartfiles *startfile: crti%O%s crtbegin%O%s diff --git a/mesosphere/kernel_ldr/Makefile b/mesosphere/kernel_ldr/Makefile index b2ecc536d..15a6367b1 100644 --- a/mesosphere/kernel_ldr/Makefile +++ b/mesosphere/kernel_ldr/Makefile @@ -1,145 +1,42 @@ -#--------------------------------------------------------------------------------- -# pull in common atmosphere configuration -#--------------------------------------------------------------------------------- +ATMOSPHERE_BUILD_CONFIGS := +all: nx_release + THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) -include $(CURRENT_DIRECTORY)/../../libraries/config/templates/mesosphere.mk - -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(__RECURSIVE__),1) -#--------------------------------------------------------------------------------- - -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) - -CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) -CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) -SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),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_BIN := $(addsuffix .h,$(subst .,_,$(subst -,_,$(BINFILES)))) - -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I. - -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) - -export TOPDIR := $(CURRENT_DIRECTORY) - -OUTPUT_BASE := $(TOPDIR)/$(notdir $(TOPDIR)) - -#--------------------------------------------------------------------------------- - -ATMOSPHERE_BUILD_CONFIGS := -all: release define ATMOSPHERE_ADD_TARGET ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -$(strip $1): check_libmeso_$(strip $1) $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) - @$$(MAKE) __RECURSIVE__=1 OUTPUT=$$(OUTPUT_BASE)$(strip $2) $(3) \ - DEPSDIR=$$(CURDIR)/$$(ATMOSPHERE_BUILD_DIR)/$(strip $1) \ - LIBMESOSPHERE_NAME=mesosphere$(strip $2) \ - --no-print-directory -C $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) \ - -f $$(THIS_MAKEFILE) - -check_libmeso_$(strip $1): - @$$(MAKE) --no-print-directory -C ../../libraries/libmesosphere $(strip $1) +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/kernel_ldr.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) clean-$(strip $1): - @echo clean $(strip $1) ... - @rm -fr $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) $$(OUTPUT_BASE)$(strip $2).bin $$(OUTPUT_BASE)$(strip $2).elf + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/kernel_ldr.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) endef -$(eval $(call ATMOSPHERE_ADD_TARGET, release, , \ - ATMOSPHERE_BUILD_SETTINGS="" \ +define ATMOSPHERE_ADD_TARGETS + +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ )) -$(eval $(call ATMOSPHERE_ADD_TARGET, debug, _debug, \ - ATMOSPHERE_BUILD_SETTINGS="-DMESOSPHERE_BUILD_FOR_DEBUGGING" \ +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ )) -$(eval $(call ATMOSPHERE_ADD_TARGET, audit, _audit, \ - ATMOSPHERE_BUILD_SETTINGS="-DMESOSPHERE_BUILD_FOR_AUDITING" \ +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ )) -$(eval $(call ATMOSPHERE_ADD_TARGET, qemu_virt_release, _qemu_virt, \ - ATMOSPHERE_BUILD_SETTINGS="" \ -)) +endef -$(eval $(call ATMOSPHERE_ADD_TARGET, qemu_virt_debug, _qemu_virt_debug, \ - ATMOSPHERE_BUILD_SETTINGS="-DMESOSPHERE_BUILD_FOR_DEBUGGING" \ -)) +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) +$(eval $(call ATMOSPHERE_ADD_TARGETS, qemu_virt_a57, qemu-virt, arm-cortex-a57,)) -$(eval $(call ATMOSPHERE_ADD_TARGET, qemu_virt_audit, _qemu_virt_audit, \ - ATMOSPHERE_BUILD_SETTINGS="-DMESOSPHERE_BUILD_FOR_AUDITING" \ -)) - -$(ATMOSPHERE_BUILD_DIR)/%: - @[ -d $@ ] || mkdir -p $@ - -#--------------------------------------------------------------------------------- clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) -.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),$(config) clean-$(config)) - -#--------------------------------------------------------------------------------- -else - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- -$(OUTPUT).bin : $(OUTPUT).elf - $(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@ - @echo built ... $(notdir $@) - -$(OUTPUT).elf : $(OFILES) - -$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libmesosphere/$(ATMOSPHERE_LIBRARY_DIR)/lib$(LIBMESOSPHERE_NAME).a - -%.elf: - @echo linking $(notdir $@) - $(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ - @$(NM) -CSn $@ > $(notdir $*.lst) - -$(OFILES_SRC) : $(HFILES_BIN) - -kern_libc_generic.o: CFLAGS += -fno-builtin - -#--------------------------------------------------------------------------------- -# you need a rule like this for each extension you use as binary data -#--------------------------------------------------------------------------------- -%.bin.o %_bin.h: %.bin -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) - --include $(DEPENDS) - -#--------------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------------- \ No newline at end of file +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/mesosphere/kernel_ldr/kernel_ldr.mk b/mesosphere/kernel_ldr/kernel_ldr.mk new file mode 100644 index 000000000..9d9896fab --- /dev/null +++ b/mesosphere/kernel_ldr/kernel_ldr.mk @@ -0,0 +1,112 @@ +#--------------------------------------------------------------------------------- +# pull in common atmosphere configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(CURRENT_DIRECTORY)/../../libraries/config/templates/mesosphere.mk + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(__RECURSIVE__),1) +#--------------------------------------------------------------------------------- + +export ATMOSPHERE_TOPDIR := $(CURRENT_DIRECTORY) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) +CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) +SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),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_BIN := $(addsuffix .h,$(subst .,_,$(subst -,_,$(BINFILES)))) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I. + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) + +.PHONY: clean all check_lib + +#--------------------------------------------------------------------------------- +all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libmesosphere/$(ATMOSPHERE_LIBRARY_DIR)/libmesosphere.a + @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/$(notdir $(ATMOSPHERE_TOPDIR)) \ + DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ + --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ + -f $(THIS_MAKEFILE) + +$(ATMOSPHERE_LIBRARIES_DIR)/libmesosphere/$(ATMOSPHERE_LIBRARY_DIR)/libmesosphere.a: check_lib + @$(SILENTCMD)echo "Checked library." + +ifeq ($(ATMOSPHERE_CHECKED_LIBMESOSPHERE),1) +check_lib: +else +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libmesosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libmesosphere/libmesosphere.mk +endif + +$(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): + @[ -d $@ ] || mkdir -p $@ + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_OUT_DIR) + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT).bin : $(OUTPUT).elf + $(OBJCOPY) -S -O binary $< $@ + @echo built ... $(notdir $@) + +$(OUTPUT).elf : $(OFILES) $(ATMOSPHERE_LIBRARIES_DIR)/libmesosphere/$(ATMOSPHERE_LIBRARY_DIR)/libmesosphere.a + +%.elf: + @echo linking $(notdir $@) + $(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ + @$(NM) -CSn $@ > $(notdir $*.lst) + +$(OFILES_SRC) : $(HFILES_BIN) + +kern_libc_generic.o: CFLAGS += -fno-builtin +kern_kernel_instantiations.o: CXXFLAGS += -flto + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o %_bin.h: %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- \ No newline at end of file diff --git a/mesosphere/kernel_ldr/kernel_ldr.specs b/mesosphere/kernel_ldr/kernel_ldr.specs index fb2f88f49..1c6fb7205 100644 --- a/mesosphere/kernel_ldr/kernel_ldr.specs +++ b/mesosphere/kernel_ldr/kernel_ldr.specs @@ -1,7 +1,7 @@ %rename link old_link *link: -%(old_link) -T %:getenv(TOPDIR /kernel_ldr.ld) -pie --gc-sections -z text -z nodynamic-undefined-weak -nostdlib -nostartfiles +%(old_link) -T %:getenv(ATMOSPHERE_TOPDIR /kernel_ldr.ld) -pie --gc-sections -z text -z nodynamic-undefined-weak -nostdlib -nostartfiles *startfile: crti%O%s crtbegin%O%s diff --git a/mesosphere/mesosphere.mk b/mesosphere/mesosphere.mk new file mode 100644 index 000000000..6008bc480 --- /dev/null +++ b/mesosphere/mesosphere.mk @@ -0,0 +1,49 @@ +#--------------------------------------------------------------------------------- +# pull in common atmosphere configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(CURRENT_DIRECTORY)/../libraries/config/common.mk + +all: $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/mesosphere.bin + +$(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/mesosphere.bin: $(CURRENT_DIRECTORY)/kernel/$(ATMOSPHERE_OUT_DIR)/kernel.bin $(CURRENT_DIRECTORY)/kernel_ldr/$(ATMOSPHERE_OUT_DIR)/kernel_ldr.bin $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR) + @python build_mesosphere.py $(CURRENT_DIRECTORY)/kernel_ldr/$(ATMOSPHERE_OUT_DIR)/kernel_ldr.bin $(CURRENT_DIRECTORY)/kernel/$(ATMOSPHERE_OUT_DIR)/kernel.bin $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/mesosphere.bin + @echo "Built mesosphere.bin..." + +$(CURRENT_DIRECTORY)/kernel/$(ATMOSPHERE_OUT_DIR)/kernel.bin: check_kernel + @$(SILENTCMD)echo "Checked kernel." + +$(CURRENT_DIRECTORY)/kernel_ldr/$(ATMOSPHERE_OUT_DIR)/kernel_ldr.bin: check_kernel_ldr + @$(SILENTCMD)echo "Checked kernel ldr." + +$(ATMOSPHERE_LIBRARIES_DIR)/libmesosphere/$(ATMOSPHERE_LIBRARY_DIR)/libmesosphere.a: check_lib + @$(SILENTCMD)echo "Checked library." + +check_kernel: $(ATMOSPHERE_LIBRARIES_DIR)/libmesosphere/$(ATMOSPHERE_LIBRARY_DIR)/libmesosphere.a + @$(SILENTCMD)echo "Checking kernel..." + @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/kernel -f $(CURRENT_DIRECTORY)/kernel/kernel.mk ATMOSPHERE_CHECKED_LIBMESOSPHERE=1 + +check_kernel_ldr: $(ATMOSPHERE_LIBRARIES_DIR)/libmesosphere/$(ATMOSPHERE_LIBRARY_DIR)/libmesosphere.a + @$(SILENTCMD)echo "Checking kernel ldr..." + @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/kernel_ldr -f $(CURRENT_DIRECTORY)/kernel_ldr/kernel_ldr.mk ATMOSPHERE_CHECKED_LIBMESOSPHERE=1 + +ifeq ($(ATMOSPHERE_CHECKED_LIBMESOSPHERE),1) +check_lib: +else +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libmesosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libmesosphere/libmesosphere.mk +endif + + +$(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR): + @[ -d $@ ] || mkdir -p $@ + +clean: + @echo clean ... + @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/kernel -f $(CURRENT_DIRECTORY)/kernel/kernel.mk clean + @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/kernel_ldr -f $(CURRENT_DIRECTORY)/kernel_ldr/kernel_ldr.mk clean + @rm -fr $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/mesosphere.bin + @for i in $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR); do [ -d $$i ] && rmdir --ignore-fail-on-non-empty $$i || true; done + +.PHONY: all clean check_lib check_kernel check_kernel_ldr \ No newline at end of file diff --git a/stratosphere/LogManager/Makefile b/stratosphere/LogManager/Makefile index aab86a63a..d681240e5 100644 --- a/stratosphere/LogManager/Makefile +++ b/stratosphere/LogManager/Makefile @@ -1,113 +1,41 @@ -#--------------------------------------------------------------------------------- -# pull in common stratosphere sysmodule configuration -#--------------------------------------------------------------------------------- -include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk +ATMOSPHERE_BUILD_CONFIGS := +all: nx_release -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(BUILD),$(notdir $(CURDIR))) -#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) -export OUTPUT := $(CURDIR)/$(TARGET) -export TOPDIR := $(CURDIR) +define ATMOSPHERE_ADD_TARGET -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) +ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -export DEPSDIR := $(CURDIR)/$(BUILD) +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) -CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) -SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) +clean-$(strip $1): + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) +endef -#--------------------------------------------------------------------------------- -# use CXX for linking C++ projects, CC for standard C -#--------------------------------------------------------------------------------- -ifeq ($(strip $(CPPFILES)),) -#--------------------------------------------------------------------------------- - export LD := $(CC) -#--------------------------------------------------------------------------------- -else -#--------------------------------------------------------------------------------- - export LD := $(CXX) -#--------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------- +define ATMOSPHERE_ADD_TARGETS -export OFILES := $(addsuffix .o,$(BINFILES)) \ - $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ +)) -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I$(CURDIR)/$(BUILD) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ +)) -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ +)) -export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) +endef -ifeq ($(strip $(CONFIG_JSON)),) - jsons := $(wildcard *.json) - ifneq (,$(findstring $(TARGET).json,$(jsons))) - export APP_JSON := $(TOPDIR)/$(TARGET).json - else - ifneq (,$(findstring config.json,$(jsons))) - export APP_JSON := $(TOPDIR)/config.json - endif - endif -else - export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) -endif +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) -.PHONY: $(BUILD) clean all +clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) -#--------------------------------------------------------------------------------- -all: $(BUILD) - -$(BUILD): - @[ -d $@ ] || mkdir -p $@ - @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile - -#--------------------------------------------------------------------------------- -clean: - @echo clean ... - @rm -fr $(BUILD) $(TARGET).nsp $(TARGET).npdm $(TARGET).nso $(TARGET).elf - - -#--------------------------------------------------------------------------------- -else -.PHONY: all - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- -all : $(OUTPUT).nsp - -ifeq ($(strip $(APP_JSON)),) -$(OUTPUT).nsp : $(OUTPUT).nso -else -$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm -endif - -$(OUTPUT).nso : $(OUTPUT).elf - -$(OUTPUT).elf : $(OFILES) - -#--------------------------------------------------------------------------------- -# you need a rule like this for each extension you use as binary data -#--------------------------------------------------------------------------------- -%.bin.o : %.bin -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) - --include $(DEPENDS) - -#--------------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------------- +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/stratosphere/LogManager/system_module.mk b/stratosphere/LogManager/system_module.mk new file mode 100644 index 000000000..d6de42efc --- /dev/null +++ b/stratosphere/LogManager/system_module.mk @@ -0,0 +1,131 @@ +#--------------------------------------------------------------------------------- +# pull in common stratosphere sysmodule configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk + +ATMOSPHERE_SYSTEM_MODULE_TARGETS := nsp + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(__RECURSIVE__),1) +#--------------------------------------------------------------------------------- + +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) +CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) +SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) + +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + $(foreach dir,$(AMS_LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) $(foreach dir,$(AMS_LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) + +export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) + +ifeq ($(strip $(CONFIG_JSON)),) + jsons := $(wildcard *.json) + ifneq (,$(findstring $(TARGET).json,$(jsons))) + export APP_JSON := $(TOPDIR)/$(TARGET).json + else + ifneq (,$(findstring config.json,$(jsons))) + export APP_JSON := $(TOPDIR)/config.json + endif + endif +else + export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) +endif + +.PHONY: clean all check_lib + +#--------------------------------------------------------------------------------- +all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURDIR)/$(ATMOSPHERE_OUT_DIR)/$(TARGET) \ + DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ + --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ + -f $(THIS_MAKEFILE) + +$(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a: check_lib + @$(SILENTCMD)echo "Checked library." + +ifeq ($(ATMOSPHERE_CHECKED_LIBSTRATOSPHERE),1) +check_lib: +else +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/libstratosphere.mk +endif + +$(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): + @[ -d $@ ] || mkdir -p $@ + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) + + +#--------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +all : $(foreach target,$(ATMOSPHERE_SYSTEM_MODULE_TARGETS),$(OUTPUT).$(target)) + +$(OUTPUT).kip : $(OUTPUT).elf +$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm +$(OUTPUT).nso : $(OUTPUT).elf + +$(OUTPUT).elf : $(OFILES) + +$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + +%.npdm : %.npdm.json + @echo built ... $< $@ + @npdmtool $< $@ + @echo built ... $(notdir $@) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/stratosphere/Makefile b/stratosphere/Makefile index 082453c83..9423a8f3d 100644 --- a/stratosphere/Makefile +++ b/stratosphere/Makefile @@ -1,12 +1,41 @@ -MODULES := loader ncm pm sm boot ams_mitm spl eclct.stub ro creport fatal dmnt boot2 erpt pgl jpegdec LogManager cs htc TioServer dmnt.gen2 +ATMOSPHERE_BUILD_CONFIGS := +all: nx_release -SUBFOLDERS := $(MODULES) +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) -TOPTARGETS := all clean +define ATMOSPHERE_ADD_TARGET -$(TOPTARGETS): $(SUBFOLDERS) +ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -$(SUBFOLDERS): - $(MAKE) -C $@ $(MAKECMDGOALS) +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/stratosphere.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -.PHONY: $(TOPTARGETS) $(SUBFOLDERS) +clean-$(strip $1): + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/stratosphere.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) + +endef + +define ATMOSPHERE_ADD_TARGETS + +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ +)) + +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ +)) + +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ +)) + +endef + +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) + +clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) + +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/stratosphere/TioServer/Makefile b/stratosphere/TioServer/Makefile index aab86a63a..d681240e5 100644 --- a/stratosphere/TioServer/Makefile +++ b/stratosphere/TioServer/Makefile @@ -1,113 +1,41 @@ -#--------------------------------------------------------------------------------- -# pull in common stratosphere sysmodule configuration -#--------------------------------------------------------------------------------- -include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk +ATMOSPHERE_BUILD_CONFIGS := +all: nx_release -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(BUILD),$(notdir $(CURDIR))) -#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) -export OUTPUT := $(CURDIR)/$(TARGET) -export TOPDIR := $(CURDIR) +define ATMOSPHERE_ADD_TARGET -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) +ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -export DEPSDIR := $(CURDIR)/$(BUILD) +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) -CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) -SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) +clean-$(strip $1): + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) +endef -#--------------------------------------------------------------------------------- -# use CXX for linking C++ projects, CC for standard C -#--------------------------------------------------------------------------------- -ifeq ($(strip $(CPPFILES)),) -#--------------------------------------------------------------------------------- - export LD := $(CC) -#--------------------------------------------------------------------------------- -else -#--------------------------------------------------------------------------------- - export LD := $(CXX) -#--------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------- +define ATMOSPHERE_ADD_TARGETS -export OFILES := $(addsuffix .o,$(BINFILES)) \ - $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ +)) -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I$(CURDIR)/$(BUILD) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ +)) -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ +)) -export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) +endef -ifeq ($(strip $(CONFIG_JSON)),) - jsons := $(wildcard *.json) - ifneq (,$(findstring $(TARGET).json,$(jsons))) - export APP_JSON := $(TOPDIR)/$(TARGET).json - else - ifneq (,$(findstring config.json,$(jsons))) - export APP_JSON := $(TOPDIR)/config.json - endif - endif -else - export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) -endif +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) -.PHONY: $(BUILD) clean all +clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) -#--------------------------------------------------------------------------------- -all: $(BUILD) - -$(BUILD): - @[ -d $@ ] || mkdir -p $@ - @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile - -#--------------------------------------------------------------------------------- -clean: - @echo clean ... - @rm -fr $(BUILD) $(TARGET).nsp $(TARGET).npdm $(TARGET).nso $(TARGET).elf - - -#--------------------------------------------------------------------------------- -else -.PHONY: all - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- -all : $(OUTPUT).nsp - -ifeq ($(strip $(APP_JSON)),) -$(OUTPUT).nsp : $(OUTPUT).nso -else -$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm -endif - -$(OUTPUT).nso : $(OUTPUT).elf - -$(OUTPUT).elf : $(OFILES) - -#--------------------------------------------------------------------------------- -# you need a rule like this for each extension you use as binary data -#--------------------------------------------------------------------------------- -%.bin.o : %.bin -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) - --include $(DEPENDS) - -#--------------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------------- +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/stratosphere/TioServer/source/tio_file_server_processor.cpp b/stratosphere/TioServer/source/tio_file_server_processor.cpp index f5d465845..7a1f6e3bb 100644 --- a/stratosphere/TioServer/source/tio_file_server_processor.cpp +++ b/stratosphere/TioServer/source/tio_file_server_processor.cpp @@ -592,7 +592,7 @@ namespace ams::tio { } /* Get the file timestamp. */ - response_header.result = fs::GetFileTimeStampRawForDebug(std::addressof(out.file_timestamp), param->path); + response_header.result = fs::impl::GetFileTimeStampRawForDebug(std::addressof(out.file_timestamp), param->path); if (R_FAILED(response_header.result)) { break; } diff --git a/stratosphere/TioServer/system_module.mk b/stratosphere/TioServer/system_module.mk new file mode 100644 index 000000000..d6de42efc --- /dev/null +++ b/stratosphere/TioServer/system_module.mk @@ -0,0 +1,131 @@ +#--------------------------------------------------------------------------------- +# pull in common stratosphere sysmodule configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk + +ATMOSPHERE_SYSTEM_MODULE_TARGETS := nsp + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(__RECURSIVE__),1) +#--------------------------------------------------------------------------------- + +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) +CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) +SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) + +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + $(foreach dir,$(AMS_LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) $(foreach dir,$(AMS_LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) + +export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) + +ifeq ($(strip $(CONFIG_JSON)),) + jsons := $(wildcard *.json) + ifneq (,$(findstring $(TARGET).json,$(jsons))) + export APP_JSON := $(TOPDIR)/$(TARGET).json + else + ifneq (,$(findstring config.json,$(jsons))) + export APP_JSON := $(TOPDIR)/config.json + endif + endif +else + export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) +endif + +.PHONY: clean all check_lib + +#--------------------------------------------------------------------------------- +all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURDIR)/$(ATMOSPHERE_OUT_DIR)/$(TARGET) \ + DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ + --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ + -f $(THIS_MAKEFILE) + +$(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a: check_lib + @$(SILENTCMD)echo "Checked library." + +ifeq ($(ATMOSPHERE_CHECKED_LIBSTRATOSPHERE),1) +check_lib: +else +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/libstratosphere.mk +endif + +$(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): + @[ -d $@ ] || mkdir -p $@ + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) + + +#--------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +all : $(foreach target,$(ATMOSPHERE_SYSTEM_MODULE_TARGETS),$(OUTPUT).$(target)) + +$(OUTPUT).kip : $(OUTPUT).elf +$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm +$(OUTPUT).nso : $(OUTPUT).elf + +$(OUTPUT).elf : $(OFILES) + +$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + +%.npdm : %.npdm.json + @echo built ... $< $@ + @npdmtool $< $@ + @echo built ... $(notdir $@) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/stratosphere/ams_mitm/Makefile b/stratosphere/ams_mitm/Makefile index 1957b6cdb..d681240e5 100644 --- a/stratosphere/ams_mitm/Makefile +++ b/stratosphere/ams_mitm/Makefile @@ -1,107 +1,41 @@ -#--------------------------------------------------------------------------------- -# pull in common stratosphere sysmodule configuration -#--------------------------------------------------------------------------------- -include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk +ATMOSPHERE_BUILD_CONFIGS := +all: nx_release -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(BUILD),$(notdir $(CURDIR))) -#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) -export OUTPUT := $(CURDIR)/$(TARGET) -export TOPDIR := $(CURDIR) +define ATMOSPHERE_ADD_TARGET -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) +ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -export DEPSDIR := $(CURDIR)/$(BUILD) +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) -CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) -SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) +clean-$(strip $1): + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) +endef -#--------------------------------------------------------------------------------- -# use CXX for linking C++ projects, CC for standard C -#--------------------------------------------------------------------------------- -ifeq ($(strip $(CPPFILES)),) -#--------------------------------------------------------------------------------- - export LD := $(CC) -#--------------------------------------------------------------------------------- -else -#--------------------------------------------------------------------------------- - export LD := $(CXX) -#--------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------- +define ATMOSPHERE_ADD_TARGETS -export OFILES := $(addsuffix .o,$(BINFILES)) \ - $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ +)) -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I$(CURDIR)/$(BUILD) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ +)) -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ +)) -export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) +endef -ifeq ($(strip $(CONFIG_JSON)),) - jsons := $(wildcard *.json) - ifneq (,$(findstring $(TARGET).json,$(jsons))) - export APP_JSON := $(TOPDIR)/$(TARGET).json - else - ifneq (,$(findstring config.json,$(jsons))) - export APP_JSON := $(TOPDIR)/config.json - endif - endif -else - export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) -endif +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) -.PHONY: $(BUILD) clean all +clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) -#--------------------------------------------------------------------------------- -all: $(BUILD) - -$(BUILD): - @[ -d $@ ] || mkdir -p $@ - @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile - -#--------------------------------------------------------------------------------- -clean: - @echo clean ... - @rm -fr $(BUILD) $(TARGET).kip $(TARGET).elf - - -#--------------------------------------------------------------------------------- -else -.PHONY: all - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- -all : $(OUTPUT).kip - -$(OUTPUT).kip : $(OUTPUT).elf - -$(OUTPUT).elf : $(OFILES) - -#--------------------------------------------------------------------------------- -# you need a rule like this for each extension you use as binary data -#--------------------------------------------------------------------------------- -%.bin.o : %.bin -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) - --include $(DEPENDS) - -#--------------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------------- +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/stratosphere/ams_mitm/source/amsmitm_prodinfo_utils.cpp b/stratosphere/ams_mitm/source/amsmitm_prodinfo_utils.cpp index 4236a845b..8722877fd 100644 --- a/stratosphere/ams_mitm/source/amsmitm_prodinfo_utils.cpp +++ b/stratosphere/ams_mitm/source/amsmitm_prodinfo_utils.cpp @@ -114,7 +114,7 @@ namespace ams::mitm { Sha256Hash calc_hash; ON_SCOPE_EXIT { ::ams::crypto::ClearMemory(std::addressof(calc_hash), sizeof(calc_hash)); }; - ::ams::crypto::GenerateSha256Hash(std::addressof(calc_hash), sizeof(calc_hash), data, data_size); + ::ams::crypto::GenerateSha256(std::addressof(calc_hash), sizeof(calc_hash), data, data_size); return ::ams::crypto::IsSameBytes(std::addressof(calc_hash), std::addressof(hash), sizeof(Sha256Hash)); } @@ -182,7 +182,7 @@ namespace ams::mitm { } else { static_assert(Block::IsShaBlock); std::memset(std::addressof(block), 0, Block::Size); - ::ams::crypto::GenerateSha256Hash(std::addressof(block.sha256_hash), sizeof(block.sha256_hash), std::addressof(block), Block::Size - sizeof(block.sha256_hash)); + ::ams::crypto::GenerateSha256(std::addressof(block.sha256_hash), sizeof(block.sha256_hash), std::addressof(block), Block::Size - sizeof(block.sha256_hash)); } } @@ -224,7 +224,7 @@ namespace ams::mitm { Blank(info.GetBlock()); /* Set header hash. */ - crypto::GenerateSha256Hash(std::addressof(info.header.body_hash), sizeof(info.header.body_hash), std::addressof(info.body), sizeof(info.body)); + crypto::GenerateSha256(std::addressof(info.header.body_hash), sizeof(info.header.body_hash), std::addressof(info.body), sizeof(info.body)); } bool IsValidHeader(const CalibrationInfo &cal) { @@ -375,7 +375,7 @@ namespace ams::mitm { AMS_ABORT_UNLESS(IsValidForSecureBackup(src->info)); /* Set the Sha256 hash. */ - crypto::GenerateSha256Hash(std::addressof(src->hash), sizeof(src->hash), std::addressof(src->info), sizeof(src->info)); + crypto::GenerateSha256(std::addressof(src->hash), sizeof(src->hash), std::addressof(src->info), sizeof(src->info)); /* Validate the hash. */ AMS_ABORT_UNLESS(IsValidSha256Hash(src->hash, std::addressof(src->info), sizeof(src->info))); @@ -407,7 +407,7 @@ namespace ams::mitm { util::SNPrintf(dst, dst_size, "automatic_backups/%s_PRODINFO.bin", sn); } else { Sha256Hash hash; - crypto::GenerateSha256Hash(std::addressof(hash), sizeof(hash), std::addressof(info), sizeof(info)); + crypto::GenerateSha256(std::addressof(hash), sizeof(hash), std::addressof(info), sizeof(info)); ON_SCOPE_EXIT { crypto::ClearMemory(std::addressof(hash), sizeof(hash)); }; if (IsValid(info)) { @@ -484,7 +484,7 @@ namespace ams::mitm { data_buffer[2] = os::GetSystemTick().GetInt64Value(); } - return crypto::GenerateSha256Hash(dst, sizeof(*dst), data_buffer, sizeof(data_buffer)); + return crypto::GenerateSha256(dst, sizeof(*dst), data_buffer, sizeof(data_buffer)); } void FillWithGarbage(void *dst, size_t dst_size) { @@ -579,7 +579,7 @@ namespace ams::mitm { } else { Sha256Hash hash; ON_SCOPE_EXIT { crypto::ClearMemory(std::addressof(hash), sizeof(hash)); }; - crypto::GenerateSha256Hash(std::addressof(hash), sizeof(hash), std::addressof(g_calibration_info), sizeof(g_calibration_info)); + crypto::GenerateSha256(std::addressof(hash), sizeof(hash), std::addressof(g_calibration_info), sizeof(g_calibration_info)); util::SNPrintf(out_name, out_name_size, "%02X%02X%02X%02X", hash.data[0], hash.data[1], hash.data[2], hash.data[3]); } diff --git a/stratosphere/ams_mitm/source/fs_mitm/fs_mitm_service.cpp b/stratosphere/ams_mitm/source/fs_mitm/fs_mitm_service.cpp index 8fbf79d01..90c24abfb 100644 --- a/stratosphere/ams_mitm/source/fs_mitm/fs_mitm_service.cpp +++ b/stratosphere/ams_mitm/source/fs_mitm/fs_mitm_service.cpp @@ -30,7 +30,7 @@ namespace ams::mitm::fs { namespace { - constexpr const char AtmosphereHblWebContentDir[] = "/atmosphere/hbl_html/"; + constexpr const ams::fs::Path AtmosphereHblWebContentDirPath = fs::MakeConstantPath("/atmosphere/hbl_html/"); constexpr const char ProgramWebContentDir[] = "/manual_html/"; constinit os::SdkMutex g_boot0_detect_lock; @@ -77,7 +77,7 @@ namespace ams::mitm::fs { /* Hbl html directory must exist. */ { FsDir d; - R_UNLESS(R_SUCCEEDED(mitm::fs::OpenSdDirectory(std::addressof(d), AtmosphereHblWebContentDir, fs::OpenDirectoryMode_Directory)), sm::mitm::ResultShouldForwardToSession()); + R_UNLESS(R_SUCCEEDED(mitm::fs::OpenSdDirectory(std::addressof(d), AtmosphereHblWebContentDirPath.GetString(), fs::OpenDirectoryMode_Directory)), sm::mitm::ResultShouldForwardToSession()); fsDirClose(std::addressof(d)); } @@ -87,7 +87,10 @@ namespace ams::mitm::fs { const sf::cmif::DomainObjectId target_object_id{serviceGetObjectId(std::addressof(sd_fs.s))}; std::unique_ptr sd_ifs = std::make_unique(sd_fs); - out.SetValue(MakeSharedFileSystem(std::make_shared(std::make_unique(std::move(sd_ifs), AtmosphereHblWebContentDir)), false), target_object_id); + auto subdir_fs = std::make_unique(std::move(sd_ifs)); + R_TRY(subdir_fs->Initialize(AtmosphereHblWebContentDirPath)); + + out.SetValue(MakeSharedFileSystem(std::make_shared(std::move(subdir_fs)), false), target_object_id); return ResultSuccess(); } @@ -106,12 +109,17 @@ namespace ams::mitm::fs { std::unique_ptr sd_ifs = std::make_unique(sd_fs); /* Format the subdirectory path. */ - char program_web_content_path[fs::EntryNameLengthMax + 1]; - FormatAtmosphereSdPath(program_web_content_path, sizeof(program_web_content_path), program_id, ProgramWebContentDir); + char program_web_content_raw_path[0x100]; + FormatAtmosphereSdPath(program_web_content_raw_path, sizeof(program_web_content_raw_path), program_id, ProgramWebContentDir); + + ams::fs::Path program_web_content_path; + R_TRY(program_web_content_path.SetShallowBuffer(program_web_content_raw_path)); /* Make a new filesystem. */ { - std::unique_ptr subdir_fs = std::make_unique(std::move(sd_ifs), program_web_content_path); + auto subdir_fs = std::make_unique(std::move(sd_ifs)); + R_TRY(subdir_fs->Initialize(program_web_content_path)); + std::shared_ptr new_fs = nullptr; /* Try to open the existing fs. */ @@ -165,7 +173,7 @@ namespace ams::mitm::fs { Result FsMitmService::OpenSdCardFileSystem(sf::Out> out) { /* We only care about redirecting this for NS/emummc. */ R_UNLESS(m_client_info.program_id == ncm::SystemProgramId::Ns, sm::mitm::ResultShouldForwardToSession()); - R_UNLESS(emummc::IsActive(), sm::mitm::ResultShouldForwardToSession()); + R_UNLESS(emummc::IsActive(), sm::mitm::ResultShouldForwardToSession()); /* Create a new SD card filesystem. */ FsFileSystem sd_fs; @@ -173,7 +181,9 @@ namespace ams::mitm::fs { const sf::cmif::DomainObjectId target_object_id{serviceGetObjectId(std::addressof(sd_fs.s))}; /* Return output filesystem. */ - std::shared_ptr redir_fs = std::make_shared(std::make_shared(sd_fs), "/Nintendo", emummc::GetNintendoDirPath()); + auto redir_fs = std::make_shared(std::make_unique(sd_fs)); + R_TRY(redir_fs->InitializeWithFixedPath("/Nintendo", emummc::GetNintendoDirPath())); + out.SetValue(MakeSharedFileSystem(std::move(redir_fs), false), target_object_id); return ResultSuccess(); } @@ -209,8 +219,12 @@ namespace ams::mitm::fs { /* Verify that we can open the save directory, and that it exists. */ const ncm::ProgramId application_id = attribute.program_id == ncm::InvalidProgramId ? m_client_info.program_id : attribute.program_id; - char save_dir_path[fs::EntryNameLengthMax + 1]; - R_TRY(mitm::fs::SaveUtil::GetDirectorySaveDataPath(save_dir_path, sizeof(save_dir_path), application_id, space_id, attribute)); + + char save_dir_raw_path[0x100]; + R_TRY(mitm::fs::SaveUtil::GetDirectorySaveDataPath(save_dir_raw_path, sizeof(save_dir_raw_path), application_id, space_id, attribute)); + + ams::fs::Path save_dir_path; + R_TRY(save_dir_path.SetShallowBuffer(save_dir_raw_path)); /* Check if this is the first time we're making the save. */ bool is_new_save = false; @@ -223,19 +237,25 @@ namespace ams::mitm::fs { } /* Ensure the directory exists. */ - R_TRY(fssystem::EnsureDirectoryRecursively(sd_ifs.get(), save_dir_path)); + R_TRY(fssystem::EnsureDirectory(sd_ifs.get(), save_dir_path)); /* Create directory savedata filesystem. */ - std::unique_ptr subdir_fs = std::make_unique(sd_ifs, save_dir_path); + auto subdir_fs = std::make_unique(sd_ifs); + R_TRY(subdir_fs->Initialize(save_dir_path)); + std::shared_ptr dirsave_ifs = std::make_shared(std::move(subdir_fs)); /* Ensure correct directory savedata filesystem state. */ - R_TRY(dirsave_ifs->Initialize()); + R_TRY(dirsave_ifs->Initialize(true, true, true)); /* If it's the first time we're making the save, copy existing savedata over. */ if (is_new_save) { /* TODO: Check error? */ - dirsave_ifs->CopySaveFromFileSystem(save_ifs.get()); + fs::DirectoryEntry work_entry; + constexpr const fs::Path root_path = fs::MakeConstantPath("/"); + + u8 savedata_copy_buffer[2_KB]; + fssystem::CopyDirectoryRecursively(dirsave_ifs.get(), save_ifs.get(), root_path, root_path, std::addressof(work_entry), savedata_copy_buffer, sizeof(savedata_copy_buffer)); } /* Set output. */ @@ -265,19 +285,20 @@ namespace ams::mitm::fs { /* Set output storage. */ if (bis_partition_id == FsBisPartitionId_BootPartition1Root) { if (IsBoot0CustomPublicKey(bis_storage)) { - out.SetValue(MakeSharedStorage(new CustomPublicKeyBoot0Storage(bis_storage, m_client_info, spl::GetSocType())), target_object_id); + out.SetValue(MakeSharedStorage(std::make_shared(bis_storage, m_client_info, spl::GetSocType())), target_object_id); } else { - out.SetValue(MakeSharedStorage(new Boot0Storage(bis_storage, m_client_info)), target_object_id); + out.SetValue(MakeSharedStorage(std::make_shared(bis_storage, m_client_info)), target_object_id); } } else if (bis_partition_id == FsBisPartitionId_CalibrationBinary) { - out.SetValue(MakeSharedStorage(new CalibrationBinaryStorage(bis_storage, m_client_info)), target_object_id); + out.SetValue(MakeSharedStorage(std::make_shared(bis_storage, m_client_info)), target_object_id); } else { if (can_write_bis || can_write_bis_for_choi_support) { /* We can write, so create a writable storage. */ - out.SetValue(MakeSharedStorage(new RemoteStorage(bis_storage)), target_object_id); + out.SetValue(MakeSharedStorage(std::make_shared(bis_storage)), target_object_id); } else { /* We can only read, so create a readable storage. */ - out.SetValue(MakeSharedStorage(new ReadOnlyStorageAdapter(new RemoteStorage(bis_storage))), target_object_id); + std::unique_ptr unique_bis = std::make_unique(bis_storage); + out.SetValue(MakeSharedStorage(std::make_shared(std::move(unique_bis))), target_object_id); } } diff --git a/stratosphere/ams_mitm/source/fs_mitm/fsmitm_readonly_layered_filesystem.hpp b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_readonly_layered_filesystem.hpp index 2ba41ad76..22edd7662 100644 --- a/stratosphere/ams_mitm/source/fs_mitm/fsmitm_readonly_layered_filesystem.hpp +++ b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_readonly_layered_filesystem.hpp @@ -27,52 +27,52 @@ namespace ams::mitm::fs { virtual ~ReadOnlyLayeredFileSystem() { /* ... */ } private: - virtual Result DoCreateFile(const char *path, s64 size, int flags) override final { + virtual Result DoCreateFile(const ams::fs::Path &path, s64 size, int flags) override final { AMS_UNUSED(path, size, flags); return ams::fs::ResultUnsupportedOperation(); } - virtual Result DoDeleteFile(const char *path) override final { + virtual Result DoDeleteFile(const ams::fs::Path &path) override final { AMS_UNUSED(path); return ams::fs::ResultUnsupportedOperation(); } - virtual Result DoCreateDirectory(const char *path) override final { + virtual Result DoCreateDirectory(const ams::fs::Path &path) override final { AMS_UNUSED(path); return ams::fs::ResultUnsupportedOperation(); } - virtual Result DoDeleteDirectory(const char *path) override final { + virtual Result DoDeleteDirectory(const ams::fs::Path &path) override final { AMS_UNUSED(path); return ams::fs::ResultUnsupportedOperation(); } - virtual Result DoDeleteDirectoryRecursively(const char *path) override final { + virtual Result DoDeleteDirectoryRecursively(const ams::fs::Path &path) override final { AMS_UNUSED(path); return ams::fs::ResultUnsupportedOperation(); } - virtual Result DoRenameFile(const char *old_path, const char *new_path) override final { + virtual Result DoRenameFile(const ams::fs::Path &old_path, const ams::fs::Path &new_path) override final { AMS_UNUSED(old_path, new_path); return ams::fs::ResultUnsupportedOperation(); } - virtual Result DoRenameDirectory(const char *old_path, const char *new_path) override final { + virtual Result DoRenameDirectory(const ams::fs::Path &old_path, const ams::fs::Path &new_path) override final { AMS_UNUSED(old_path, new_path); return ams::fs::ResultUnsupportedOperation(); } - virtual Result DoGetEntryType(ams::fs::DirectoryEntryType *out, const char *path) override final { + virtual Result DoGetEntryType(ams::fs::DirectoryEntryType *out, const ams::fs::Path &path) override final { R_SUCCEED_IF(R_SUCCEEDED(m_fs_1.GetEntryType(out, path))); return m_fs_2.GetEntryType(out, path); } - virtual Result DoOpenFile(std::unique_ptr *out_file, const char *path, ams::fs::OpenMode mode) override final { + virtual Result DoOpenFile(std::unique_ptr *out_file, const ams::fs::Path &path, ams::fs::OpenMode mode) override final { R_SUCCEED_IF(R_SUCCEEDED(m_fs_1.OpenFile(out_file, path, mode))); return m_fs_2.OpenFile(out_file, path, mode); } - virtual Result DoOpenDirectory(std::unique_ptr *out_dir, const char *path, ams::fs::OpenDirectoryMode mode) override final { + virtual Result DoOpenDirectory(std::unique_ptr *out_dir, const ams::fs::Path &path, ams::fs::OpenDirectoryMode mode) override final { R_SUCCEED_IF(R_SUCCEEDED(m_fs_1.OpenDirectory(out_dir, path, mode))); return m_fs_2.OpenDirectory(out_dir, path, mode); } @@ -81,22 +81,22 @@ namespace ams::mitm::fs { return ResultSuccess(); } - virtual Result DoGetFreeSpaceSize(s64 *out, const char *path) { + virtual Result DoGetFreeSpaceSize(s64 *out, const ams::fs::Path &path) { AMS_UNUSED(out, path); return ams::fs::ResultUnsupportedOperation(); } - virtual Result DoGetTotalSpaceSize(s64 *out, const char *path) { + virtual Result DoGetTotalSpaceSize(s64 *out, const ams::fs::Path &path) { AMS_UNUSED(out, path); return ams::fs::ResultUnsupportedOperation(); } - virtual Result DoCleanDirectoryRecursively(const char *path) { + virtual Result DoCleanDirectoryRecursively(const ams::fs::Path &path) { AMS_UNUSED(path); return ams::fs::ResultUnsupportedOperation(); } - virtual Result DoGetFileTimeStampRaw(ams::fs::FileTimeStampRaw *out, const char *path) { + virtual Result DoGetFileTimeStampRaw(ams::fs::FileTimeStampRaw *out, const ams::fs::Path &path) { R_SUCCEED_IF(R_SUCCEEDED(m_fs_1.GetFileTimeStampRaw(out, path))); return m_fs_2.GetFileTimeStampRaw(out, path); } diff --git a/stratosphere/ams_mitm/source/fs_mitm/fsmitm_romfs.hpp b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_romfs.hpp index c05ea0af4..f89ae2c9e 100644 --- a/stratosphere/ams_mitm/source/fs_mitm/fsmitm_romfs.hpp +++ b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_romfs.hpp @@ -269,7 +269,7 @@ namespace ams::mitm::fs::romfs { size_t m_file_hash_table_size; size_t m_file_partition_size; - ams::fs::DirectoryEntry m_dir_entry; + ::FsDirectoryEntry m_dir_entry; DataSourceType m_cur_source_type; private: void VisitDirectory(FsFileSystem *fs, BuildDirectoryContext *parent); diff --git a/stratosphere/ams_mitm/source/sysupdater/sysupdater_fs_utils.cpp b/stratosphere/ams_mitm/source/sysupdater/sysupdater_fs_utils.cpp index 1d9f5f07b..c8ac7951f 100644 --- a/stratosphere/ams_mitm/source/sysupdater/sysupdater_fs_utils.cpp +++ b/stratosphere/ams_mitm/source/sysupdater/sysupdater_fs_utils.cpp @@ -25,22 +25,25 @@ namespace ams::mitm::sysupdater { constexpr inline const size_t NcaExtensionSize = 4; constexpr inline const size_t NspExtensionSize = 4; + constexpr const ams::fs::PathFlags SdCardContentMetaPathNormalizePathFlags = [] { + fs::PathFlags flags{}; + flags.AllowMountName(); + return flags; + }(); + static_assert(NcaExtensionSize == NspExtensionSize); constexpr inline const size_t NcaNspExtensionSize = NcaExtensionSize; - constexpr inline std::underlying_type::type SdCardContentMetaPathNormalizeOption = fssrv::PathNormalizer::Option_PreserveTailSeparator | - fssrv::PathNormalizer::Option_HasMountName; - Result CheckNcaOrNsp(const char **path) { /* Ensure that the path is currently at the mount name delimeter. */ - R_UNLESS(std::strncmp(*path, ams::fs::impl::MountNameDelimiter, strnlen(ams::fs::impl::MountNameDelimiter, ams::fs::EntryNameLengthMax)) == 0, fs::ResultPathNotFound()); + R_UNLESS(util::Strncmp(*path, ams::fs::impl::MountNameDelimiter, util::Strnlen(ams::fs::impl::MountNameDelimiter, ams::fs::EntryNameLengthMax)) == 0, fs::ResultPathNotFound()); /* Advance past the :. */ static_assert(ams::fs::impl::MountNameDelimiter[0] == ':'); *path += 1; /* Ensure path is long enough for the extension. */ - const auto path_len = strnlen(*path, ams::fs::EntryNameLengthMax); + const size_t path_len = util::Strnlen(*path, ams::fs::EntryNameLengthMax); R_UNLESS(path_len > NcaNspExtensionSize, fs::ResultPathNotFound()); /* Get the extension. */ @@ -56,7 +59,7 @@ namespace ams::mitm::sysupdater { Result ParseMountName(const char **path, std::shared_ptr *out) { /* The equivalent function here supports all the common mount names; we'll only support the SD card, system content storage. */ - if (const auto mount_len = strnlen(ams::fs::impl::SdCardFileSystemMountName, ams::fs::MountNameLengthMax); std::strncmp(*path, ams::fs::impl::SdCardFileSystemMountName, mount_len) == 0) { + if (const auto mount_len = util::Strnlen(ams::fs::impl::SdCardFileSystemMountName, ams::fs::MountNameLengthMax); util::Strncmp(*path, ams::fs::impl::SdCardFileSystemMountName, mount_len) == 0) { /* Advance the path. */ *path += mount_len; @@ -70,7 +73,7 @@ namespace ams::mitm::sysupdater { /* Set the output fs. */ *out = std::move(fsa); - } else if (const auto mount_len = strnlen(ams::fs::impl::ContentStorageSystemMountName, ams::fs::MountNameLengthMax); std::strncmp(*path, ams::fs::impl::ContentStorageSystemMountName, mount_len) == 0) { + } else if (const auto mount_len = util::Strnlen(ams::fs::impl::ContentStorageSystemMountName, ams::fs::MountNameLengthMax); util::Strncmp(*path, ams::fs::impl::ContentStorageSystemMountName, mount_len) == 0) { /* Advance the path. */ *path += mount_len; @@ -89,7 +92,7 @@ namespace ams::mitm::sysupdater { } /* Ensure that there's something that could be a mount name delimiter. */ - R_UNLESS(strnlen(*path, fs::EntryNameLengthMax) != 0, fs::ResultPathNotFound()); + R_UNLESS(util::Strnlen(*path, fs::EntryNameLengthMax) != 0, fs::ResultPathNotFound()); return ResultSuccess(); } @@ -115,10 +118,8 @@ namespace ams::mitm::sysupdater { work_path += NspExtensionSize; /* Get the nsp path. */ - char nsp_path[fs::EntryNameLengthMax + 1]; - R_UNLESS(static_cast(work_path - *path) <= sizeof(nsp_path), fs::ResultTooLongPath()); - std::memcpy(nsp_path, *path, work_path - *path); - nsp_path[work_path - *path] = '\x00'; + ams::fs::Path nsp_path; + R_TRY(nsp_path.InitializeWithNormalization(*path, work_path - *path)); /* Open the file storage. */ std::shared_ptr file_storage = fssystem::AllocateShared(); @@ -138,7 +139,12 @@ namespace ams::mitm::sysupdater { /* Open the file storage. */ std::shared_ptr file_storage = fssystem::AllocateShared(); R_UNLESS(file_storage != nullptr, fs::ResultAllocationFailureInFileSystemProxyCoreImplE()); - R_TRY(file_storage->Initialize(std::move(base_fs), *path, ams::fs::OpenMode_Read)); + + /* Get the nca path. */ + ams::fs::Path nca_path; + R_TRY(nca_path.InitializeWithNormalization(*path)); + + R_TRY(file_storage->Initialize(std::move(base_fs), nca_path, ams::fs::OpenMode_Read)); /* Create the nca reader. */ std::shared_ptr nca_reader; @@ -196,7 +202,7 @@ namespace ams::mitm::sysupdater { /* Open meta storage. */ std::shared_ptr storage; std::shared_ptr splitter; - fssystem::NcaFsHeader::FsType fs_type; + fssystem::NcaFsHeader::FsType fs_type = static_cast(~0); R_TRY(OpenMetaStorage(std::addressof(storage), std::addressof(splitter), std::move(nca_reader), std::addressof(fs_type))); /* Open the appropriate interface. */ @@ -230,12 +236,12 @@ namespace ams::mitm::sysupdater { R_UNLESS(path != nullptr, fs::ResultInvalidPath()); /* Normalize the path. */ - fssrv::PathNormalizer normalized_path(path, SdCardContentMetaPathNormalizeOption); - R_TRY(normalized_path.GetResult()); + char normalized_path[fs::EntryNameLengthMax + 1]; + R_TRY(ams::fs::PathFormatter::Normalize(normalized_path, sizeof(normalized_path), path, std::strlen(path) + 1, SdCardContentMetaPathNormalizePathFlags)); /* Open the filesystem. */ std::shared_ptr fs; - R_TRY(OpenContentMetaFileSystem(std::addressof(fs), normalized_path.GetPath())); + R_TRY(OpenContentMetaFileSystem(std::addressof(fs), normalized_path)); /* Create a holder for the fs. */ std::unique_ptr unique_fs = std::make_unique(std::move(fs)); diff --git a/stratosphere/ams_mitm/source/sysupdater/sysupdater_service.cpp b/stratosphere/ams_mitm/source/sysupdater/sysupdater_service.cpp index a4d808a58..496cf5550 100644 --- a/stratosphere/ams_mitm/source/sysupdater/sysupdater_service.cpp +++ b/stratosphere/ams_mitm/source/sysupdater/sysupdater_service.cpp @@ -506,7 +506,7 @@ namespace ams::mitm::sysupdater { R_TRY(FormatUserPackagePath(std::addressof(package_root), path)); /* Ensure that we can create an update context. */ - R_TRY(fs::EnsureDirectoryRecursively("@Sdcard:/atmosphere/update/")); + R_TRY(fs::EnsureDirectory("@Sdcard:/atmosphere/update/")); const char *context_path = "@Sdcard:/atmosphere/update/cup.ctx"; /* Create and initialize the update task. */ diff --git a/stratosphere/ams_mitm/system_module.mk b/stratosphere/ams_mitm/system_module.mk new file mode 100644 index 000000000..af1d82213 --- /dev/null +++ b/stratosphere/ams_mitm/system_module.mk @@ -0,0 +1,131 @@ +#--------------------------------------------------------------------------------- +# pull in common stratosphere sysmodule configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk + +ATMOSPHERE_SYSTEM_MODULE_TARGETS := kip + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(__RECURSIVE__),1) +#--------------------------------------------------------------------------------- + +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) +CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) +SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) + +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + $(foreach dir,$(AMS_LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) $(foreach dir,$(AMS_LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) + +export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) + +ifeq ($(strip $(CONFIG_JSON)),) + jsons := $(wildcard *.json) + ifneq (,$(findstring $(TARGET).json,$(jsons))) + export APP_JSON := $(TOPDIR)/$(TARGET).json + else + ifneq (,$(findstring config.json,$(jsons))) + export APP_JSON := $(TOPDIR)/config.json + endif + endif +else + export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) +endif + +.PHONY: clean all check_lib + +#--------------------------------------------------------------------------------- +all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURDIR)/$(ATMOSPHERE_OUT_DIR)/$(TARGET) \ + DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ + --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ + -f $(THIS_MAKEFILE) + +$(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a: check_lib + @$(SILENTCMD)echo "Checked library." + +ifeq ($(ATMOSPHERE_CHECKED_LIBSTRATOSPHERE),1) +check_lib: +else +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/libstratosphere.mk +endif + +$(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): + @[ -d $@ ] || mkdir -p $@ + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) + + +#--------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +all : $(foreach target,$(ATMOSPHERE_SYSTEM_MODULE_TARGETS),$(OUTPUT).$(target)) + +$(OUTPUT).kip : $(OUTPUT).elf +$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm +$(OUTPUT).nso : $(OUTPUT).elf + +$(OUTPUT).elf : $(OFILES) + +$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + +%.npdm : %.npdm.json + @echo built ... $< $@ + @npdmtool $< $@ + @echo built ... $(notdir $@) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/stratosphere/boot/Makefile b/stratosphere/boot/Makefile index a944797aa..d681240e5 100644 --- a/stratosphere/boot/Makefile +++ b/stratosphere/boot/Makefile @@ -1,113 +1,41 @@ -#--------------------------------------------------------------------------------- -# pull in common stratosphere sysmodule configuration -#--------------------------------------------------------------------------------- -include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk +ATMOSPHERE_BUILD_CONFIGS := +all: nx_release -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(BUILD),$(notdir $(CURDIR))) -#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) -export OUTPUT := $(CURDIR)/$(TARGET) -export TOPDIR := $(CURDIR) +define ATMOSPHERE_ADD_TARGET -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) $(TOPDIR)/../../fusee +ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -export DEPSDIR := $(CURDIR)/$(BUILD) +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) -CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) -SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) +clean-$(strip $1): + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) fusee.bin +endef -#--------------------------------------------------------------------------------- -# use CXX for linking C++ projects, CC for standard C -#--------------------------------------------------------------------------------- -ifeq ($(strip $(CPPFILES)),) -#--------------------------------------------------------------------------------- - export LD := $(CC) -#--------------------------------------------------------------------------------- -else -#--------------------------------------------------------------------------------- - export LD := $(CXX) -#--------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------- +define ATMOSPHERE_ADD_TARGETS -export OFILES := $(addsuffix .o,$(BINFILES)) \ - $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ +)) -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I$(CURDIR)/$(BUILD) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ +)) -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ +)) -export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) +endef -ifeq ($(strip $(CONFIG_JSON)),) - jsons := $(wildcard *.json) - ifneq (,$(findstring $(TARGET).json,$(jsons))) - export APP_JSON := $(TOPDIR)/$(TARGET).json - else - ifneq (,$(findstring config.json,$(jsons))) - export APP_JSON := $(TOPDIR)/config.json - endif - endif -else - export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) -endif +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) -.PHONY: $(BUILD) check_fusee clean all +clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) -#--------------------------------------------------------------------------------- -all: $(BUILD) - -check_fusee: - @$(MAKE) -C $(TOPDIR)/../../fusee release - -$(BUILD): check_fusee - @[ -d $@ ] || mkdir -p $@ - @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile - -#--------------------------------------------------------------------------------- -clean: - @echo clean ... - @$(MAKE) -C $(TOPDIR)/../../fusee clean - @rm -fr $(BUILD) $(TARGET).kip $(TARGET).elf - - -#--------------------------------------------------------------------------------- -else -.PHONY: all - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- -all : $(OUTPUT).kip - -$(OUTPUT).kip : $(OUTPUT).elf - -$(OUTPUT).elf : $(OFILES) - -boot_power_utils.o: fusee.bin.o - -#--------------------------------------------------------------------------------- -# you need a rule like this for each extension you use as binary data -#--------------------------------------------------------------------------------- -fusee.bin.o: fusee.bin -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) - --include $(DEPENDS) - -#--------------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------------- +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/stratosphere/boot/system_module.mk b/stratosphere/boot/system_module.mk new file mode 100644 index 000000000..be26006df --- /dev/null +++ b/stratosphere/boot/system_module.mk @@ -0,0 +1,141 @@ +#--------------------------------------------------------------------------------- +# pull in common stratosphere sysmodule configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk + +ATMOSPHERE_SYSTEM_MODULE_TARGETS := kip + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(__RECURSIVE__),1) +#--------------------------------------------------------------------------------- + +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) $(ATMOSPHERE_LIBRARIES_DIR)/../fusee/$(ATMOSPHERE_BOOT_OUT_DIR) + +CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) +CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) +SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) + +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) fusee.bin + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + $(foreach dir,$(AMS_LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) $(foreach dir,$(AMS_LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) + +export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) + +ifeq ($(strip $(CONFIG_JSON)),) + jsons := $(wildcard *.json) + ifneq (,$(findstring $(TARGET).json,$(jsons))) + export APP_JSON := $(TOPDIR)/$(TARGET).json + else + ifneq (,$(findstring config.json,$(jsons))) + export APP_JSON := $(TOPDIR)/config.json + endif + endif +else + export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) +endif + +.PHONY: clean all check_lib check_fusee + +#--------------------------------------------------------------------------------- +all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURDIR)/$(ATMOSPHERE_OUT_DIR)/$(TARGET) \ + DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ + --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ + -f $(THIS_MAKEFILE) + +$(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a: check_lib check_fusee + @$(SILENTCMD)echo "Checked library." + +ifeq ($(ATMOSPHERE_CHECKED_LIBSTRATOSPHERE),1) +check_lib: +else +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/libstratosphere.mk +endif + +ifeq ($(ATMOSPHERE_CHECKED_FUSEE),1) +check_fusee: +else +check_fusee: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/../fusee -f $(ATMOSPHERE_LIBRARIES_DIR)/../fusee/Makefile $(ATMOSPHERE_MAKEFILE_TARGET) + @$(SILENTCMD)echo $(VPATH) +endif + +$(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): + @[ -d $@ ] || mkdir -p $@ + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) + + +#--------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +all : $(foreach target,$(ATMOSPHERE_SYSTEM_MODULE_TARGETS),$(OUTPUT).$(target)) + +$(OUTPUT).kip : $(OUTPUT).elf +$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm +$(OUTPUT).nso : $(OUTPUT).elf + +$(OUTPUT).elf : $(OFILES) + +$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + +%.npdm : %.npdm.json + @echo built ... $< $@ + @npdmtool $< $@ + @echo built ... $(notdir $@) + +boot_power_utils.o: fusee.bin.o + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +fusee.bin.o: fusee.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/stratosphere/boot2/Makefile b/stratosphere/boot2/Makefile index aab86a63a..d681240e5 100644 --- a/stratosphere/boot2/Makefile +++ b/stratosphere/boot2/Makefile @@ -1,113 +1,41 @@ -#--------------------------------------------------------------------------------- -# pull in common stratosphere sysmodule configuration -#--------------------------------------------------------------------------------- -include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk +ATMOSPHERE_BUILD_CONFIGS := +all: nx_release -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(BUILD),$(notdir $(CURDIR))) -#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) -export OUTPUT := $(CURDIR)/$(TARGET) -export TOPDIR := $(CURDIR) +define ATMOSPHERE_ADD_TARGET -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) +ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -export DEPSDIR := $(CURDIR)/$(BUILD) +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) -CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) -SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) +clean-$(strip $1): + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) +endef -#--------------------------------------------------------------------------------- -# use CXX for linking C++ projects, CC for standard C -#--------------------------------------------------------------------------------- -ifeq ($(strip $(CPPFILES)),) -#--------------------------------------------------------------------------------- - export LD := $(CC) -#--------------------------------------------------------------------------------- -else -#--------------------------------------------------------------------------------- - export LD := $(CXX) -#--------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------- +define ATMOSPHERE_ADD_TARGETS -export OFILES := $(addsuffix .o,$(BINFILES)) \ - $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ +)) -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I$(CURDIR)/$(BUILD) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ +)) -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ +)) -export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) +endef -ifeq ($(strip $(CONFIG_JSON)),) - jsons := $(wildcard *.json) - ifneq (,$(findstring $(TARGET).json,$(jsons))) - export APP_JSON := $(TOPDIR)/$(TARGET).json - else - ifneq (,$(findstring config.json,$(jsons))) - export APP_JSON := $(TOPDIR)/config.json - endif - endif -else - export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) -endif +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) -.PHONY: $(BUILD) clean all +clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) -#--------------------------------------------------------------------------------- -all: $(BUILD) - -$(BUILD): - @[ -d $@ ] || mkdir -p $@ - @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile - -#--------------------------------------------------------------------------------- -clean: - @echo clean ... - @rm -fr $(BUILD) $(TARGET).nsp $(TARGET).npdm $(TARGET).nso $(TARGET).elf - - -#--------------------------------------------------------------------------------- -else -.PHONY: all - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- -all : $(OUTPUT).nsp - -ifeq ($(strip $(APP_JSON)),) -$(OUTPUT).nsp : $(OUTPUT).nso -else -$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm -endif - -$(OUTPUT).nso : $(OUTPUT).elf - -$(OUTPUT).elf : $(OFILES) - -#--------------------------------------------------------------------------------- -# you need a rule like this for each extension you use as binary data -#--------------------------------------------------------------------------------- -%.bin.o : %.bin -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) - --include $(DEPENDS) - -#--------------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------------- +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/stratosphere/boot2/system_module.mk b/stratosphere/boot2/system_module.mk new file mode 100644 index 000000000..d6de42efc --- /dev/null +++ b/stratosphere/boot2/system_module.mk @@ -0,0 +1,131 @@ +#--------------------------------------------------------------------------------- +# pull in common stratosphere sysmodule configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk + +ATMOSPHERE_SYSTEM_MODULE_TARGETS := nsp + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(__RECURSIVE__),1) +#--------------------------------------------------------------------------------- + +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) +CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) +SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) + +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + $(foreach dir,$(AMS_LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) $(foreach dir,$(AMS_LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) + +export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) + +ifeq ($(strip $(CONFIG_JSON)),) + jsons := $(wildcard *.json) + ifneq (,$(findstring $(TARGET).json,$(jsons))) + export APP_JSON := $(TOPDIR)/$(TARGET).json + else + ifneq (,$(findstring config.json,$(jsons))) + export APP_JSON := $(TOPDIR)/config.json + endif + endif +else + export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) +endif + +.PHONY: clean all check_lib + +#--------------------------------------------------------------------------------- +all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURDIR)/$(ATMOSPHERE_OUT_DIR)/$(TARGET) \ + DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ + --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ + -f $(THIS_MAKEFILE) + +$(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a: check_lib + @$(SILENTCMD)echo "Checked library." + +ifeq ($(ATMOSPHERE_CHECKED_LIBSTRATOSPHERE),1) +check_lib: +else +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/libstratosphere.mk +endif + +$(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): + @[ -d $@ ] || mkdir -p $@ + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) + + +#--------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +all : $(foreach target,$(ATMOSPHERE_SYSTEM_MODULE_TARGETS),$(OUTPUT).$(target)) + +$(OUTPUT).kip : $(OUTPUT).elf +$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm +$(OUTPUT).nso : $(OUTPUT).elf + +$(OUTPUT).elf : $(OFILES) + +$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + +%.npdm : %.npdm.json + @echo built ... $< $@ + @npdmtool $< $@ + @echo built ... $(notdir $@) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/stratosphere/creport/Makefile b/stratosphere/creport/Makefile index aab86a63a..d681240e5 100644 --- a/stratosphere/creport/Makefile +++ b/stratosphere/creport/Makefile @@ -1,113 +1,41 @@ -#--------------------------------------------------------------------------------- -# pull in common stratosphere sysmodule configuration -#--------------------------------------------------------------------------------- -include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk +ATMOSPHERE_BUILD_CONFIGS := +all: nx_release -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(BUILD),$(notdir $(CURDIR))) -#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) -export OUTPUT := $(CURDIR)/$(TARGET) -export TOPDIR := $(CURDIR) +define ATMOSPHERE_ADD_TARGET -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) +ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -export DEPSDIR := $(CURDIR)/$(BUILD) +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) -CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) -SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) +clean-$(strip $1): + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) +endef -#--------------------------------------------------------------------------------- -# use CXX for linking C++ projects, CC for standard C -#--------------------------------------------------------------------------------- -ifeq ($(strip $(CPPFILES)),) -#--------------------------------------------------------------------------------- - export LD := $(CC) -#--------------------------------------------------------------------------------- -else -#--------------------------------------------------------------------------------- - export LD := $(CXX) -#--------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------- +define ATMOSPHERE_ADD_TARGETS -export OFILES := $(addsuffix .o,$(BINFILES)) \ - $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ +)) -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I$(CURDIR)/$(BUILD) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ +)) -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ +)) -export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) +endef -ifeq ($(strip $(CONFIG_JSON)),) - jsons := $(wildcard *.json) - ifneq (,$(findstring $(TARGET).json,$(jsons))) - export APP_JSON := $(TOPDIR)/$(TARGET).json - else - ifneq (,$(findstring config.json,$(jsons))) - export APP_JSON := $(TOPDIR)/config.json - endif - endif -else - export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) -endif +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) -.PHONY: $(BUILD) clean all +clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) -#--------------------------------------------------------------------------------- -all: $(BUILD) - -$(BUILD): - @[ -d $@ ] || mkdir -p $@ - @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile - -#--------------------------------------------------------------------------------- -clean: - @echo clean ... - @rm -fr $(BUILD) $(TARGET).nsp $(TARGET).npdm $(TARGET).nso $(TARGET).elf - - -#--------------------------------------------------------------------------------- -else -.PHONY: all - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- -all : $(OUTPUT).nsp - -ifeq ($(strip $(APP_JSON)),) -$(OUTPUT).nsp : $(OUTPUT).nso -else -$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm -endif - -$(OUTPUT).nso : $(OUTPUT).elf - -$(OUTPUT).elf : $(OFILES) - -#--------------------------------------------------------------------------------- -# you need a rule like this for each extension you use as binary data -#--------------------------------------------------------------------------------- -%.bin.o : %.bin -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) - --include $(DEPENDS) - -#--------------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------------- +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/stratosphere/creport/source/creport_crash_report.cpp b/stratosphere/creport/source/creport_crash_report.cpp index 0cb467600..9936102e5 100644 --- a/stratosphere/creport/source/creport_crash_report.cpp +++ b/stratosphere/creport/source/creport_crash_report.cpp @@ -51,8 +51,8 @@ namespace ams::creport { } void TryCreateReportDirectories() { - fs::EnsureDirectoryRecursively("sdmc:/atmosphere/crash_reports/dumps"); - fs::EnsureDirectoryRecursively("sdmc:/atmosphere/fatal_reports/dumps"); + fs::EnsureDirectory("sdmc:/atmosphere/crash_reports/dumps"); + fs::EnsureDirectory("sdmc:/atmosphere/fatal_reports/dumps"); } constexpr const char *GetDebugExceptionString(const svc::DebugException type) { diff --git a/stratosphere/creport/system_module.mk b/stratosphere/creport/system_module.mk new file mode 100644 index 000000000..d6de42efc --- /dev/null +++ b/stratosphere/creport/system_module.mk @@ -0,0 +1,131 @@ +#--------------------------------------------------------------------------------- +# pull in common stratosphere sysmodule configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk + +ATMOSPHERE_SYSTEM_MODULE_TARGETS := nsp + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(__RECURSIVE__),1) +#--------------------------------------------------------------------------------- + +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) +CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) +SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) + +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + $(foreach dir,$(AMS_LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) $(foreach dir,$(AMS_LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) + +export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) + +ifeq ($(strip $(CONFIG_JSON)),) + jsons := $(wildcard *.json) + ifneq (,$(findstring $(TARGET).json,$(jsons))) + export APP_JSON := $(TOPDIR)/$(TARGET).json + else + ifneq (,$(findstring config.json,$(jsons))) + export APP_JSON := $(TOPDIR)/config.json + endif + endif +else + export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) +endif + +.PHONY: clean all check_lib + +#--------------------------------------------------------------------------------- +all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURDIR)/$(ATMOSPHERE_OUT_DIR)/$(TARGET) \ + DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ + --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ + -f $(THIS_MAKEFILE) + +$(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a: check_lib + @$(SILENTCMD)echo "Checked library." + +ifeq ($(ATMOSPHERE_CHECKED_LIBSTRATOSPHERE),1) +check_lib: +else +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/libstratosphere.mk +endif + +$(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): + @[ -d $@ ] || mkdir -p $@ + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) + + +#--------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +all : $(foreach target,$(ATMOSPHERE_SYSTEM_MODULE_TARGETS),$(OUTPUT).$(target)) + +$(OUTPUT).kip : $(OUTPUT).elf +$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm +$(OUTPUT).nso : $(OUTPUT).elf + +$(OUTPUT).elf : $(OFILES) + +$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + +%.npdm : %.npdm.json + @echo built ... $< $@ + @npdmtool $< $@ + @echo built ... $(notdir $@) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/stratosphere/cs/Makefile b/stratosphere/cs/Makefile index aab86a63a..d681240e5 100644 --- a/stratosphere/cs/Makefile +++ b/stratosphere/cs/Makefile @@ -1,113 +1,41 @@ -#--------------------------------------------------------------------------------- -# pull in common stratosphere sysmodule configuration -#--------------------------------------------------------------------------------- -include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk +ATMOSPHERE_BUILD_CONFIGS := +all: nx_release -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(BUILD),$(notdir $(CURDIR))) -#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) -export OUTPUT := $(CURDIR)/$(TARGET) -export TOPDIR := $(CURDIR) +define ATMOSPHERE_ADD_TARGET -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) +ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -export DEPSDIR := $(CURDIR)/$(BUILD) +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) -CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) -SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) +clean-$(strip $1): + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) +endef -#--------------------------------------------------------------------------------- -# use CXX for linking C++ projects, CC for standard C -#--------------------------------------------------------------------------------- -ifeq ($(strip $(CPPFILES)),) -#--------------------------------------------------------------------------------- - export LD := $(CC) -#--------------------------------------------------------------------------------- -else -#--------------------------------------------------------------------------------- - export LD := $(CXX) -#--------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------- +define ATMOSPHERE_ADD_TARGETS -export OFILES := $(addsuffix .o,$(BINFILES)) \ - $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ +)) -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I$(CURDIR)/$(BUILD) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ +)) -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ +)) -export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) +endef -ifeq ($(strip $(CONFIG_JSON)),) - jsons := $(wildcard *.json) - ifneq (,$(findstring $(TARGET).json,$(jsons))) - export APP_JSON := $(TOPDIR)/$(TARGET).json - else - ifneq (,$(findstring config.json,$(jsons))) - export APP_JSON := $(TOPDIR)/config.json - endif - endif -else - export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) -endif +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) -.PHONY: $(BUILD) clean all +clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) -#--------------------------------------------------------------------------------- -all: $(BUILD) - -$(BUILD): - @[ -d $@ ] || mkdir -p $@ - @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile - -#--------------------------------------------------------------------------------- -clean: - @echo clean ... - @rm -fr $(BUILD) $(TARGET).nsp $(TARGET).npdm $(TARGET).nso $(TARGET).elf - - -#--------------------------------------------------------------------------------- -else -.PHONY: all - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- -all : $(OUTPUT).nsp - -ifeq ($(strip $(APP_JSON)),) -$(OUTPUT).nsp : $(OUTPUT).nso -else -$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm -endif - -$(OUTPUT).nso : $(OUTPUT).elf - -$(OUTPUT).elf : $(OFILES) - -#--------------------------------------------------------------------------------- -# you need a rule like this for each extension you use as binary data -#--------------------------------------------------------------------------------- -%.bin.o : %.bin -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) - --include $(DEPENDS) - -#--------------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------------- +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/stratosphere/cs/system_module.mk b/stratosphere/cs/system_module.mk new file mode 100644 index 000000000..d6de42efc --- /dev/null +++ b/stratosphere/cs/system_module.mk @@ -0,0 +1,131 @@ +#--------------------------------------------------------------------------------- +# pull in common stratosphere sysmodule configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk + +ATMOSPHERE_SYSTEM_MODULE_TARGETS := nsp + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(__RECURSIVE__),1) +#--------------------------------------------------------------------------------- + +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) +CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) +SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) + +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + $(foreach dir,$(AMS_LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) $(foreach dir,$(AMS_LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) + +export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) + +ifeq ($(strip $(CONFIG_JSON)),) + jsons := $(wildcard *.json) + ifneq (,$(findstring $(TARGET).json,$(jsons))) + export APP_JSON := $(TOPDIR)/$(TARGET).json + else + ifneq (,$(findstring config.json,$(jsons))) + export APP_JSON := $(TOPDIR)/config.json + endif + endif +else + export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) +endif + +.PHONY: clean all check_lib + +#--------------------------------------------------------------------------------- +all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURDIR)/$(ATMOSPHERE_OUT_DIR)/$(TARGET) \ + DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ + --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ + -f $(THIS_MAKEFILE) + +$(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a: check_lib + @$(SILENTCMD)echo "Checked library." + +ifeq ($(ATMOSPHERE_CHECKED_LIBSTRATOSPHERE),1) +check_lib: +else +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/libstratosphere.mk +endif + +$(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): + @[ -d $@ ] || mkdir -p $@ + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) + + +#--------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +all : $(foreach target,$(ATMOSPHERE_SYSTEM_MODULE_TARGETS),$(OUTPUT).$(target)) + +$(OUTPUT).kip : $(OUTPUT).elf +$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm +$(OUTPUT).nso : $(OUTPUT).elf + +$(OUTPUT).elf : $(OFILES) + +$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + +%.npdm : %.npdm.json + @echo built ... $< $@ + @npdmtool $< $@ + @echo built ... $(notdir $@) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/stratosphere/dmnt.gen2/Makefile b/stratosphere/dmnt.gen2/Makefile index aab86a63a..d681240e5 100644 --- a/stratosphere/dmnt.gen2/Makefile +++ b/stratosphere/dmnt.gen2/Makefile @@ -1,113 +1,41 @@ -#--------------------------------------------------------------------------------- -# pull in common stratosphere sysmodule configuration -#--------------------------------------------------------------------------------- -include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk +ATMOSPHERE_BUILD_CONFIGS := +all: nx_release -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(BUILD),$(notdir $(CURDIR))) -#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) -export OUTPUT := $(CURDIR)/$(TARGET) -export TOPDIR := $(CURDIR) +define ATMOSPHERE_ADD_TARGET -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) +ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -export DEPSDIR := $(CURDIR)/$(BUILD) +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) -CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) -SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) +clean-$(strip $1): + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) +endef -#--------------------------------------------------------------------------------- -# use CXX for linking C++ projects, CC for standard C -#--------------------------------------------------------------------------------- -ifeq ($(strip $(CPPFILES)),) -#--------------------------------------------------------------------------------- - export LD := $(CC) -#--------------------------------------------------------------------------------- -else -#--------------------------------------------------------------------------------- - export LD := $(CXX) -#--------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------- +define ATMOSPHERE_ADD_TARGETS -export OFILES := $(addsuffix .o,$(BINFILES)) \ - $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ +)) -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I$(CURDIR)/$(BUILD) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ +)) -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ +)) -export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) +endef -ifeq ($(strip $(CONFIG_JSON)),) - jsons := $(wildcard *.json) - ifneq (,$(findstring $(TARGET).json,$(jsons))) - export APP_JSON := $(TOPDIR)/$(TARGET).json - else - ifneq (,$(findstring config.json,$(jsons))) - export APP_JSON := $(TOPDIR)/config.json - endif - endif -else - export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) -endif +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) -.PHONY: $(BUILD) clean all +clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) -#--------------------------------------------------------------------------------- -all: $(BUILD) - -$(BUILD): - @[ -d $@ ] || mkdir -p $@ - @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile - -#--------------------------------------------------------------------------------- -clean: - @echo clean ... - @rm -fr $(BUILD) $(TARGET).nsp $(TARGET).npdm $(TARGET).nso $(TARGET).elf - - -#--------------------------------------------------------------------------------- -else -.PHONY: all - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- -all : $(OUTPUT).nsp - -ifeq ($(strip $(APP_JSON)),) -$(OUTPUT).nsp : $(OUTPUT).nso -else -$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm -endif - -$(OUTPUT).nso : $(OUTPUT).elf - -$(OUTPUT).elf : $(OFILES) - -#--------------------------------------------------------------------------------- -# you need a rule like this for each extension you use as binary data -#--------------------------------------------------------------------------------- -%.bin.o : %.bin -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) - --include $(DEPENDS) - -#--------------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------------- +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/stratosphere/dmnt.gen2/system_module.mk b/stratosphere/dmnt.gen2/system_module.mk new file mode 100644 index 000000000..d6de42efc --- /dev/null +++ b/stratosphere/dmnt.gen2/system_module.mk @@ -0,0 +1,131 @@ +#--------------------------------------------------------------------------------- +# pull in common stratosphere sysmodule configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk + +ATMOSPHERE_SYSTEM_MODULE_TARGETS := nsp + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(__RECURSIVE__),1) +#--------------------------------------------------------------------------------- + +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) +CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) +SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) + +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + $(foreach dir,$(AMS_LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) $(foreach dir,$(AMS_LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) + +export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) + +ifeq ($(strip $(CONFIG_JSON)),) + jsons := $(wildcard *.json) + ifneq (,$(findstring $(TARGET).json,$(jsons))) + export APP_JSON := $(TOPDIR)/$(TARGET).json + else + ifneq (,$(findstring config.json,$(jsons))) + export APP_JSON := $(TOPDIR)/config.json + endif + endif +else + export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) +endif + +.PHONY: clean all check_lib + +#--------------------------------------------------------------------------------- +all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURDIR)/$(ATMOSPHERE_OUT_DIR)/$(TARGET) \ + DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ + --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ + -f $(THIS_MAKEFILE) + +$(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a: check_lib + @$(SILENTCMD)echo "Checked library." + +ifeq ($(ATMOSPHERE_CHECKED_LIBSTRATOSPHERE),1) +check_lib: +else +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/libstratosphere.mk +endif + +$(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): + @[ -d $@ ] || mkdir -p $@ + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) + + +#--------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +all : $(foreach target,$(ATMOSPHERE_SYSTEM_MODULE_TARGETS),$(OUTPUT).$(target)) + +$(OUTPUT).kip : $(OUTPUT).elf +$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm +$(OUTPUT).nso : $(OUTPUT).elf + +$(OUTPUT).elf : $(OFILES) + +$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + +%.npdm : %.npdm.json + @echo built ... $< $@ + @npdmtool $< $@ + @echo built ... $(notdir $@) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/stratosphere/dmnt/Makefile b/stratosphere/dmnt/Makefile index aab86a63a..d681240e5 100644 --- a/stratosphere/dmnt/Makefile +++ b/stratosphere/dmnt/Makefile @@ -1,113 +1,41 @@ -#--------------------------------------------------------------------------------- -# pull in common stratosphere sysmodule configuration -#--------------------------------------------------------------------------------- -include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk +ATMOSPHERE_BUILD_CONFIGS := +all: nx_release -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(BUILD),$(notdir $(CURDIR))) -#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) -export OUTPUT := $(CURDIR)/$(TARGET) -export TOPDIR := $(CURDIR) +define ATMOSPHERE_ADD_TARGET -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) +ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -export DEPSDIR := $(CURDIR)/$(BUILD) +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) -CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) -SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) +clean-$(strip $1): + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) +endef -#--------------------------------------------------------------------------------- -# use CXX for linking C++ projects, CC for standard C -#--------------------------------------------------------------------------------- -ifeq ($(strip $(CPPFILES)),) -#--------------------------------------------------------------------------------- - export LD := $(CC) -#--------------------------------------------------------------------------------- -else -#--------------------------------------------------------------------------------- - export LD := $(CXX) -#--------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------- +define ATMOSPHERE_ADD_TARGETS -export OFILES := $(addsuffix .o,$(BINFILES)) \ - $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ +)) -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I$(CURDIR)/$(BUILD) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ +)) -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ +)) -export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) +endef -ifeq ($(strip $(CONFIG_JSON)),) - jsons := $(wildcard *.json) - ifneq (,$(findstring $(TARGET).json,$(jsons))) - export APP_JSON := $(TOPDIR)/$(TARGET).json - else - ifneq (,$(findstring config.json,$(jsons))) - export APP_JSON := $(TOPDIR)/config.json - endif - endif -else - export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) -endif +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) -.PHONY: $(BUILD) clean all +clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) -#--------------------------------------------------------------------------------- -all: $(BUILD) - -$(BUILD): - @[ -d $@ ] || mkdir -p $@ - @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile - -#--------------------------------------------------------------------------------- -clean: - @echo clean ... - @rm -fr $(BUILD) $(TARGET).nsp $(TARGET).npdm $(TARGET).nso $(TARGET).elf - - -#--------------------------------------------------------------------------------- -else -.PHONY: all - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- -all : $(OUTPUT).nsp - -ifeq ($(strip $(APP_JSON)),) -$(OUTPUT).nsp : $(OUTPUT).nso -else -$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm -endif - -$(OUTPUT).nso : $(OUTPUT).elf - -$(OUTPUT).elf : $(OFILES) - -#--------------------------------------------------------------------------------- -# you need a rule like this for each extension you use as binary data -#--------------------------------------------------------------------------------- -%.bin.o : %.bin -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) - --include $(DEPENDS) - -#--------------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------------- +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/stratosphere/dmnt/source/cheat/impl/dmnt_cheat_api.cpp b/stratosphere/dmnt/source/cheat/impl/dmnt_cheat_api.cpp index 37de31161..d300b2930 100644 --- a/stratosphere/dmnt/source/cheat/impl/dmnt_cheat_api.cpp +++ b/stratosphere/dmnt/source/cheat/impl/dmnt_cheat_api.cpp @@ -181,7 +181,11 @@ namespace ams::dmnt::cheat::impl { m_unsafe_break_event.Signal(); /* Knock out the debug events thread. */ - os::CancelThreadSynchronization(std::addressof(m_debug_events_thread)); + { + std::scoped_lock lk(util::GetReference(m_debug_events_thread.cs_thread)); + + R_ABORT_UNLESS(svc::CancelSynchronization(m_debug_events_thread.thread_impl->handle)); + } /* Close resources. */ R_ABORT_UNLESS(svc::CloseHandle(m_cheat_process_debug_handle)); diff --git a/stratosphere/dmnt/source/cheat/impl/dmnt_cheat_vm.cpp b/stratosphere/dmnt/source/cheat/impl/dmnt_cheat_vm.cpp index eeac104d6..2d56ab4c6 100644 --- a/stratosphere/dmnt/source/cheat/impl/dmnt_cheat_vm.cpp +++ b/stratosphere/dmnt/source/cheat/impl/dmnt_cheat_vm.cpp @@ -21,7 +21,7 @@ namespace ams::dmnt::cheat::impl { void CheatVirtualMachine::DebugLog(u32 log_id, u64 value) { /* Just unconditionally try to create the log folder. */ - fs::EnsureDirectoryRecursively("sdmc:/atmosphere/cheat_vm_logs"); + fs::EnsureDirectory("sdmc:/atmosphere/cheat_vm_logs"); fs::FileHandle log_file; { diff --git a/stratosphere/dmnt/system_module.mk b/stratosphere/dmnt/system_module.mk new file mode 100644 index 000000000..f002f764a --- /dev/null +++ b/stratosphere/dmnt/system_module.mk @@ -0,0 +1,132 @@ +#--------------------------------------------------------------------------------- +# pull in common stratosphere sysmodule configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk + +ATMOSPHERE_SYSTEM_MODULE_TARGETS := nsp + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(__RECURSIVE__),1) +#--------------------------------------------------------------------------------- + +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) +CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) +SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) + +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + $(foreach dir,$(AMS_LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) $(foreach dir,$(AMS_LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) + +export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) + +ifeq ($(strip $(CONFIG_JSON)),) + jsons := $(wildcard *.json) + ifneq (,$(findstring $(TARGET).json,$(jsons))) + export APP_JSON := $(TOPDIR)/$(TARGET).json + else + ifneq (,$(findstring config.json,$(jsons))) + export APP_JSON := $(TOPDIR)/config.json + endif + endif +else + export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) +endif + +.PHONY: clean all check_lib + +#--------------------------------------------------------------------------------- +all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURDIR)/$(ATMOSPHERE_OUT_DIR)/$(TARGET) \ + DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ + --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ + -f $(THIS_MAKEFILE) + +$(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a: check_lib + @$(SILENTCMD)echo "Checked library." + + +ifeq ($(ATMOSPHERE_CHECKED_LIBSTRATOSPHERE),1) +check_lib: +else +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/libstratosphere.mk +endif + +$(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): + @[ -d $@ ] || mkdir -p $@ + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) + + +#--------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +all : $(foreach target,$(ATMOSPHERE_SYSTEM_MODULE_TARGETS),$(OUTPUT).$(target)) + +$(OUTPUT).kip : $(OUTPUT).elf +$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm +$(OUTPUT).nso : $(OUTPUT).elf + +$(OUTPUT).elf : $(OFILES) + +$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + +%.npdm : %.npdm.json + @echo built ... $< $@ + @npdmtool $< $@ + @echo built ... $(notdir $@) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/stratosphere/eclct.stub/Makefile b/stratosphere/eclct.stub/Makefile index aab86a63a..d681240e5 100644 --- a/stratosphere/eclct.stub/Makefile +++ b/stratosphere/eclct.stub/Makefile @@ -1,113 +1,41 @@ -#--------------------------------------------------------------------------------- -# pull in common stratosphere sysmodule configuration -#--------------------------------------------------------------------------------- -include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk +ATMOSPHERE_BUILD_CONFIGS := +all: nx_release -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(BUILD),$(notdir $(CURDIR))) -#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) -export OUTPUT := $(CURDIR)/$(TARGET) -export TOPDIR := $(CURDIR) +define ATMOSPHERE_ADD_TARGET -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) +ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -export DEPSDIR := $(CURDIR)/$(BUILD) +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) -CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) -SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) +clean-$(strip $1): + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) +endef -#--------------------------------------------------------------------------------- -# use CXX for linking C++ projects, CC for standard C -#--------------------------------------------------------------------------------- -ifeq ($(strip $(CPPFILES)),) -#--------------------------------------------------------------------------------- - export LD := $(CC) -#--------------------------------------------------------------------------------- -else -#--------------------------------------------------------------------------------- - export LD := $(CXX) -#--------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------- +define ATMOSPHERE_ADD_TARGETS -export OFILES := $(addsuffix .o,$(BINFILES)) \ - $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ +)) -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I$(CURDIR)/$(BUILD) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ +)) -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ +)) -export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) +endef -ifeq ($(strip $(CONFIG_JSON)),) - jsons := $(wildcard *.json) - ifneq (,$(findstring $(TARGET).json,$(jsons))) - export APP_JSON := $(TOPDIR)/$(TARGET).json - else - ifneq (,$(findstring config.json,$(jsons))) - export APP_JSON := $(TOPDIR)/config.json - endif - endif -else - export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) -endif +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) -.PHONY: $(BUILD) clean all +clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) -#--------------------------------------------------------------------------------- -all: $(BUILD) - -$(BUILD): - @[ -d $@ ] || mkdir -p $@ - @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile - -#--------------------------------------------------------------------------------- -clean: - @echo clean ... - @rm -fr $(BUILD) $(TARGET).nsp $(TARGET).npdm $(TARGET).nso $(TARGET).elf - - -#--------------------------------------------------------------------------------- -else -.PHONY: all - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- -all : $(OUTPUT).nsp - -ifeq ($(strip $(APP_JSON)),) -$(OUTPUT).nsp : $(OUTPUT).nso -else -$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm -endif - -$(OUTPUT).nso : $(OUTPUT).elf - -$(OUTPUT).elf : $(OFILES) - -#--------------------------------------------------------------------------------- -# you need a rule like this for each extension you use as binary data -#--------------------------------------------------------------------------------- -%.bin.o : %.bin -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) - --include $(DEPENDS) - -#--------------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------------- +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/stratosphere/eclct.stub/system_module.mk b/stratosphere/eclct.stub/system_module.mk new file mode 100644 index 000000000..d6de42efc --- /dev/null +++ b/stratosphere/eclct.stub/system_module.mk @@ -0,0 +1,131 @@ +#--------------------------------------------------------------------------------- +# pull in common stratosphere sysmodule configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk + +ATMOSPHERE_SYSTEM_MODULE_TARGETS := nsp + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(__RECURSIVE__),1) +#--------------------------------------------------------------------------------- + +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) +CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) +SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) + +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + $(foreach dir,$(AMS_LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) $(foreach dir,$(AMS_LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) + +export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) + +ifeq ($(strip $(CONFIG_JSON)),) + jsons := $(wildcard *.json) + ifneq (,$(findstring $(TARGET).json,$(jsons))) + export APP_JSON := $(TOPDIR)/$(TARGET).json + else + ifneq (,$(findstring config.json,$(jsons))) + export APP_JSON := $(TOPDIR)/config.json + endif + endif +else + export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) +endif + +.PHONY: clean all check_lib + +#--------------------------------------------------------------------------------- +all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURDIR)/$(ATMOSPHERE_OUT_DIR)/$(TARGET) \ + DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ + --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ + -f $(THIS_MAKEFILE) + +$(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a: check_lib + @$(SILENTCMD)echo "Checked library." + +ifeq ($(ATMOSPHERE_CHECKED_LIBSTRATOSPHERE),1) +check_lib: +else +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/libstratosphere.mk +endif + +$(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): + @[ -d $@ ] || mkdir -p $@ + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) + + +#--------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +all : $(foreach target,$(ATMOSPHERE_SYSTEM_MODULE_TARGETS),$(OUTPUT).$(target)) + +$(OUTPUT).kip : $(OUTPUT).elf +$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm +$(OUTPUT).nso : $(OUTPUT).elf + +$(OUTPUT).elf : $(OFILES) + +$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + +%.npdm : %.npdm.json + @echo built ... $< $@ + @npdmtool $< $@ + @echo built ... $(notdir $@) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/stratosphere/erpt/Makefile b/stratosphere/erpt/Makefile index aab86a63a..d681240e5 100644 --- a/stratosphere/erpt/Makefile +++ b/stratosphere/erpt/Makefile @@ -1,113 +1,41 @@ -#--------------------------------------------------------------------------------- -# pull in common stratosphere sysmodule configuration -#--------------------------------------------------------------------------------- -include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk +ATMOSPHERE_BUILD_CONFIGS := +all: nx_release -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(BUILD),$(notdir $(CURDIR))) -#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) -export OUTPUT := $(CURDIR)/$(TARGET) -export TOPDIR := $(CURDIR) +define ATMOSPHERE_ADD_TARGET -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) +ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -export DEPSDIR := $(CURDIR)/$(BUILD) +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) -CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) -SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) +clean-$(strip $1): + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) +endef -#--------------------------------------------------------------------------------- -# use CXX for linking C++ projects, CC for standard C -#--------------------------------------------------------------------------------- -ifeq ($(strip $(CPPFILES)),) -#--------------------------------------------------------------------------------- - export LD := $(CC) -#--------------------------------------------------------------------------------- -else -#--------------------------------------------------------------------------------- - export LD := $(CXX) -#--------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------- +define ATMOSPHERE_ADD_TARGETS -export OFILES := $(addsuffix .o,$(BINFILES)) \ - $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ +)) -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I$(CURDIR)/$(BUILD) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ +)) -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ +)) -export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) +endef -ifeq ($(strip $(CONFIG_JSON)),) - jsons := $(wildcard *.json) - ifneq (,$(findstring $(TARGET).json,$(jsons))) - export APP_JSON := $(TOPDIR)/$(TARGET).json - else - ifneq (,$(findstring config.json,$(jsons))) - export APP_JSON := $(TOPDIR)/config.json - endif - endif -else - export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) -endif +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) -.PHONY: $(BUILD) clean all +clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) -#--------------------------------------------------------------------------------- -all: $(BUILD) - -$(BUILD): - @[ -d $@ ] || mkdir -p $@ - @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile - -#--------------------------------------------------------------------------------- -clean: - @echo clean ... - @rm -fr $(BUILD) $(TARGET).nsp $(TARGET).npdm $(TARGET).nso $(TARGET).elf - - -#--------------------------------------------------------------------------------- -else -.PHONY: all - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- -all : $(OUTPUT).nsp - -ifeq ($(strip $(APP_JSON)),) -$(OUTPUT).nsp : $(OUTPUT).nso -else -$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm -endif - -$(OUTPUT).nso : $(OUTPUT).elf - -$(OUTPUT).elf : $(OFILES) - -#--------------------------------------------------------------------------------- -# you need a rule like this for each extension you use as binary data -#--------------------------------------------------------------------------------- -%.bin.o : %.bin -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) - --include $(DEPENDS) - -#--------------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------------- +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/stratosphere/erpt/system_module.mk b/stratosphere/erpt/system_module.mk new file mode 100644 index 000000000..d6de42efc --- /dev/null +++ b/stratosphere/erpt/system_module.mk @@ -0,0 +1,131 @@ +#--------------------------------------------------------------------------------- +# pull in common stratosphere sysmodule configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk + +ATMOSPHERE_SYSTEM_MODULE_TARGETS := nsp + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(__RECURSIVE__),1) +#--------------------------------------------------------------------------------- + +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) +CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) +SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) + +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + $(foreach dir,$(AMS_LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) $(foreach dir,$(AMS_LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) + +export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) + +ifeq ($(strip $(CONFIG_JSON)),) + jsons := $(wildcard *.json) + ifneq (,$(findstring $(TARGET).json,$(jsons))) + export APP_JSON := $(TOPDIR)/$(TARGET).json + else + ifneq (,$(findstring config.json,$(jsons))) + export APP_JSON := $(TOPDIR)/config.json + endif + endif +else + export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) +endif + +.PHONY: clean all check_lib + +#--------------------------------------------------------------------------------- +all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURDIR)/$(ATMOSPHERE_OUT_DIR)/$(TARGET) \ + DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ + --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ + -f $(THIS_MAKEFILE) + +$(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a: check_lib + @$(SILENTCMD)echo "Checked library." + +ifeq ($(ATMOSPHERE_CHECKED_LIBSTRATOSPHERE),1) +check_lib: +else +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/libstratosphere.mk +endif + +$(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): + @[ -d $@ ] || mkdir -p $@ + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) + + +#--------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +all : $(foreach target,$(ATMOSPHERE_SYSTEM_MODULE_TARGETS),$(OUTPUT).$(target)) + +$(OUTPUT).kip : $(OUTPUT).elf +$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm +$(OUTPUT).nso : $(OUTPUT).elf + +$(OUTPUT).elf : $(OFILES) + +$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + +%.npdm : %.npdm.json + @echo built ... $< $@ + @npdmtool $< $@ + @echo built ... $(notdir $@) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/stratosphere/fatal/Makefile b/stratosphere/fatal/Makefile index aab86a63a..d681240e5 100644 --- a/stratosphere/fatal/Makefile +++ b/stratosphere/fatal/Makefile @@ -1,113 +1,41 @@ -#--------------------------------------------------------------------------------- -# pull in common stratosphere sysmodule configuration -#--------------------------------------------------------------------------------- -include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk +ATMOSPHERE_BUILD_CONFIGS := +all: nx_release -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(BUILD),$(notdir $(CURDIR))) -#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) -export OUTPUT := $(CURDIR)/$(TARGET) -export TOPDIR := $(CURDIR) +define ATMOSPHERE_ADD_TARGET -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) +ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -export DEPSDIR := $(CURDIR)/$(BUILD) +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) -CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) -SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) +clean-$(strip $1): + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) +endef -#--------------------------------------------------------------------------------- -# use CXX for linking C++ projects, CC for standard C -#--------------------------------------------------------------------------------- -ifeq ($(strip $(CPPFILES)),) -#--------------------------------------------------------------------------------- - export LD := $(CC) -#--------------------------------------------------------------------------------- -else -#--------------------------------------------------------------------------------- - export LD := $(CXX) -#--------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------- +define ATMOSPHERE_ADD_TARGETS -export OFILES := $(addsuffix .o,$(BINFILES)) \ - $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ +)) -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I$(CURDIR)/$(BUILD) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ +)) -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ +)) -export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) +endef -ifeq ($(strip $(CONFIG_JSON)),) - jsons := $(wildcard *.json) - ifneq (,$(findstring $(TARGET).json,$(jsons))) - export APP_JSON := $(TOPDIR)/$(TARGET).json - else - ifneq (,$(findstring config.json,$(jsons))) - export APP_JSON := $(TOPDIR)/config.json - endif - endif -else - export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) -endif +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) -.PHONY: $(BUILD) clean all +clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) -#--------------------------------------------------------------------------------- -all: $(BUILD) - -$(BUILD): - @[ -d $@ ] || mkdir -p $@ - @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile - -#--------------------------------------------------------------------------------- -clean: - @echo clean ... - @rm -fr $(BUILD) $(TARGET).nsp $(TARGET).npdm $(TARGET).nso $(TARGET).elf - - -#--------------------------------------------------------------------------------- -else -.PHONY: all - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- -all : $(OUTPUT).nsp - -ifeq ($(strip $(APP_JSON)),) -$(OUTPUT).nsp : $(OUTPUT).nso -else -$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm -endif - -$(OUTPUT).nso : $(OUTPUT).elf - -$(OUTPUT).elf : $(OFILES) - -#--------------------------------------------------------------------------------- -# you need a rule like this for each extension you use as binary data -#--------------------------------------------------------------------------------- -%.bin.o : %.bin -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) - --include $(DEPENDS) - -#--------------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------------- +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/stratosphere/fatal/source/fatal_task_error_report.cpp b/stratosphere/fatal/source/fatal_task_error_report.cpp index 190bebbbe..c0ba05458 100644 --- a/stratosphere/fatal/source/fatal_task_error_report.cpp +++ b/stratosphere/fatal/source/fatal_task_error_report.cpp @@ -24,7 +24,7 @@ namespace ams::fatal::srv { /* Helpers. */ void TryEnsureReportDirectories() { - fs::EnsureDirectoryRecursively("sdmc:/atmosphere/fatal_reports/dumps"); + fs::EnsureDirectory("sdmc:/atmosphere/fatal_reports/dumps"); } bool TryGetCurrentTimestamp(u64 *out) { diff --git a/stratosphere/fatal/source/stb_truetype.h b/stratosphere/fatal/source/stb_truetype.h index a89cd7919..ca82fb8cd 100644 --- a/stratosphere/fatal/source/stb_truetype.h +++ b/stratosphere/fatal/source/stb_truetype.h @@ -2931,17 +2931,17 @@ static void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edg y1 = e->ey; } - if (x0 == x) + if (x0 == x) { STBTT_assert(x1 <= x+1); - else if (x0 == x+1) + } else if (x0 == x+1) { STBTT_assert(x1 >= x); - else if (x0 <= x) + } else if (x0 <= x) { STBTT_assert(x1 <= x); - else if (x0 >= x+1) + } else if (x0 >= x+1) { STBTT_assert(x1 >= x+1); - else + } else { STBTT_assert(x1 >= x && x1 <= x+1); - + } if (x0 <= x && x1 <= x) scanline[x] += e->direction * (y1-y0); else if (x0 >= x+1 && x1 >= x+1) diff --git a/stratosphere/fatal/system_module.mk b/stratosphere/fatal/system_module.mk new file mode 100644 index 000000000..d6de42efc --- /dev/null +++ b/stratosphere/fatal/system_module.mk @@ -0,0 +1,131 @@ +#--------------------------------------------------------------------------------- +# pull in common stratosphere sysmodule configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk + +ATMOSPHERE_SYSTEM_MODULE_TARGETS := nsp + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(__RECURSIVE__),1) +#--------------------------------------------------------------------------------- + +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) +CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) +SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) + +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + $(foreach dir,$(AMS_LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) $(foreach dir,$(AMS_LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) + +export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) + +ifeq ($(strip $(CONFIG_JSON)),) + jsons := $(wildcard *.json) + ifneq (,$(findstring $(TARGET).json,$(jsons))) + export APP_JSON := $(TOPDIR)/$(TARGET).json + else + ifneq (,$(findstring config.json,$(jsons))) + export APP_JSON := $(TOPDIR)/config.json + endif + endif +else + export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) +endif + +.PHONY: clean all check_lib + +#--------------------------------------------------------------------------------- +all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURDIR)/$(ATMOSPHERE_OUT_DIR)/$(TARGET) \ + DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ + --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ + -f $(THIS_MAKEFILE) + +$(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a: check_lib + @$(SILENTCMD)echo "Checked library." + +ifeq ($(ATMOSPHERE_CHECKED_LIBSTRATOSPHERE),1) +check_lib: +else +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/libstratosphere.mk +endif + +$(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): + @[ -d $@ ] || mkdir -p $@ + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) + + +#--------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +all : $(foreach target,$(ATMOSPHERE_SYSTEM_MODULE_TARGETS),$(OUTPUT).$(target)) + +$(OUTPUT).kip : $(OUTPUT).elf +$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm +$(OUTPUT).nso : $(OUTPUT).elf + +$(OUTPUT).elf : $(OFILES) + +$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + +%.npdm : %.npdm.json + @echo built ... $< $@ + @npdmtool $< $@ + @echo built ... $(notdir $@) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/stratosphere/fs/Makefile b/stratosphere/fs/Makefile index 1957b6cdb..d681240e5 100644 --- a/stratosphere/fs/Makefile +++ b/stratosphere/fs/Makefile @@ -1,107 +1,41 @@ -#--------------------------------------------------------------------------------- -# pull in common stratosphere sysmodule configuration -#--------------------------------------------------------------------------------- -include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk +ATMOSPHERE_BUILD_CONFIGS := +all: nx_release -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(BUILD),$(notdir $(CURDIR))) -#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) -export OUTPUT := $(CURDIR)/$(TARGET) -export TOPDIR := $(CURDIR) +define ATMOSPHERE_ADD_TARGET -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) +ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -export DEPSDIR := $(CURDIR)/$(BUILD) +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) -CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) -SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) +clean-$(strip $1): + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) +endef -#--------------------------------------------------------------------------------- -# use CXX for linking C++ projects, CC for standard C -#--------------------------------------------------------------------------------- -ifeq ($(strip $(CPPFILES)),) -#--------------------------------------------------------------------------------- - export LD := $(CC) -#--------------------------------------------------------------------------------- -else -#--------------------------------------------------------------------------------- - export LD := $(CXX) -#--------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------- +define ATMOSPHERE_ADD_TARGETS -export OFILES := $(addsuffix .o,$(BINFILES)) \ - $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ +)) -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I$(CURDIR)/$(BUILD) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ +)) -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ +)) -export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) +endef -ifeq ($(strip $(CONFIG_JSON)),) - jsons := $(wildcard *.json) - ifneq (,$(findstring $(TARGET).json,$(jsons))) - export APP_JSON := $(TOPDIR)/$(TARGET).json - else - ifneq (,$(findstring config.json,$(jsons))) - export APP_JSON := $(TOPDIR)/config.json - endif - endif -else - export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) -endif +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) -.PHONY: $(BUILD) clean all +clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) -#--------------------------------------------------------------------------------- -all: $(BUILD) - -$(BUILD): - @[ -d $@ ] || mkdir -p $@ - @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile - -#--------------------------------------------------------------------------------- -clean: - @echo clean ... - @rm -fr $(BUILD) $(TARGET).kip $(TARGET).elf - - -#--------------------------------------------------------------------------------- -else -.PHONY: all - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- -all : $(OUTPUT).kip - -$(OUTPUT).kip : $(OUTPUT).elf - -$(OUTPUT).elf : $(OFILES) - -#--------------------------------------------------------------------------------- -# you need a rule like this for each extension you use as binary data -#--------------------------------------------------------------------------------- -%.bin.o : %.bin -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) - --include $(DEPENDS) - -#--------------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------------- +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/stratosphere/fs/system_module.mk b/stratosphere/fs/system_module.mk new file mode 100644 index 000000000..19c207d9a --- /dev/null +++ b/stratosphere/fs/system_module.mk @@ -0,0 +1,131 @@ +#--------------------------------------------------------------------------------- +# pull in common stratosphere sysmodule configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk + +ATMOSPHERE_SYSTEM_MODULE_TARGETS := kip + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(__RECURSIVE__),1) +#--------------------------------------------------------------------------------- + +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) +CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) +SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) + +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + $(foreach dir,$(AMS_LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) $(foreach dir,$(AMS_LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) + +export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) + +ifeq ($(strip $(CONFIG_JSON)),) + jsons := $(wildcard *.json) + ifneq (,$(findstring $(TARGET).json,$(jsons))) + export APP_JSON := $(TOPDIR)/$(TARGET).json + else + ifneq (,$(findstring config.json,$(jsons))) + export APP_JSON := $(TOPDIR)/config.json + endif + endif +else + export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) +endif + +.PHONY: clean all check_lib + +#--------------------------------------------------------------------------------- +all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURDIR)/$(ATMOSPHERE_OUT_DIR)/$(TARGET) \ + DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ + --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ + -f $(THIS_MAKEFILE) + +$(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a: check_lib + @$(SILENTCMD)echo "Checked library." + +ifeq ($(ATMOSPHERE_CHECKED_LIBSTRATOSPHERE),1) +check_lib: +else +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/libstratosphere.mk +endif + +$(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): + @[ -d $@ ] || mkdir -p $@ + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) + + +#--------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +all : $(foreach target,$(ATMOSPHERE_SYSTEM_MODULE_TARGETS),$(OUTPUT).$(target)) + +$(OUTPUT).kip : $(OUTPUT).elf +$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm +$(OUTPUT).nso : $(OUTPUT).elf + +$(OUTPUT).elf : $(OFILES) + +$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + +%.npdm : %.npdm.json + @echo built ... $< $@ + @npdmtool $< $@ + @echo built ... $(notdir $@) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/stratosphere/htc/Makefile b/stratosphere/htc/Makefile index aab86a63a..d681240e5 100644 --- a/stratosphere/htc/Makefile +++ b/stratosphere/htc/Makefile @@ -1,113 +1,41 @@ -#--------------------------------------------------------------------------------- -# pull in common stratosphere sysmodule configuration -#--------------------------------------------------------------------------------- -include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk +ATMOSPHERE_BUILD_CONFIGS := +all: nx_release -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(BUILD),$(notdir $(CURDIR))) -#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) -export OUTPUT := $(CURDIR)/$(TARGET) -export TOPDIR := $(CURDIR) +define ATMOSPHERE_ADD_TARGET -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) +ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -export DEPSDIR := $(CURDIR)/$(BUILD) +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) -CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) -SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) +clean-$(strip $1): + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) +endef -#--------------------------------------------------------------------------------- -# use CXX for linking C++ projects, CC for standard C -#--------------------------------------------------------------------------------- -ifeq ($(strip $(CPPFILES)),) -#--------------------------------------------------------------------------------- - export LD := $(CC) -#--------------------------------------------------------------------------------- -else -#--------------------------------------------------------------------------------- - export LD := $(CXX) -#--------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------- +define ATMOSPHERE_ADD_TARGETS -export OFILES := $(addsuffix .o,$(BINFILES)) \ - $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ +)) -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I$(CURDIR)/$(BUILD) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ +)) -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ +)) -export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) +endef -ifeq ($(strip $(CONFIG_JSON)),) - jsons := $(wildcard *.json) - ifneq (,$(findstring $(TARGET).json,$(jsons))) - export APP_JSON := $(TOPDIR)/$(TARGET).json - else - ifneq (,$(findstring config.json,$(jsons))) - export APP_JSON := $(TOPDIR)/config.json - endif - endif -else - export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) -endif +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) -.PHONY: $(BUILD) clean all +clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) -#--------------------------------------------------------------------------------- -all: $(BUILD) - -$(BUILD): - @[ -d $@ ] || mkdir -p $@ - @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile - -#--------------------------------------------------------------------------------- -clean: - @echo clean ... - @rm -fr $(BUILD) $(TARGET).nsp $(TARGET).npdm $(TARGET).nso $(TARGET).elf - - -#--------------------------------------------------------------------------------- -else -.PHONY: all - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- -all : $(OUTPUT).nsp - -ifeq ($(strip $(APP_JSON)),) -$(OUTPUT).nsp : $(OUTPUT).nso -else -$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm -endif - -$(OUTPUT).nso : $(OUTPUT).elf - -$(OUTPUT).elf : $(OFILES) - -#--------------------------------------------------------------------------------- -# you need a rule like this for each extension you use as binary data -#--------------------------------------------------------------------------------- -%.bin.o : %.bin -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) - --include $(DEPENDS) - -#--------------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------------- +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/stratosphere/htc/system_module.mk b/stratosphere/htc/system_module.mk new file mode 100644 index 000000000..d6de42efc --- /dev/null +++ b/stratosphere/htc/system_module.mk @@ -0,0 +1,131 @@ +#--------------------------------------------------------------------------------- +# pull in common stratosphere sysmodule configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk + +ATMOSPHERE_SYSTEM_MODULE_TARGETS := nsp + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(__RECURSIVE__),1) +#--------------------------------------------------------------------------------- + +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) +CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) +SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) + +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + $(foreach dir,$(AMS_LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) $(foreach dir,$(AMS_LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) + +export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) + +ifeq ($(strip $(CONFIG_JSON)),) + jsons := $(wildcard *.json) + ifneq (,$(findstring $(TARGET).json,$(jsons))) + export APP_JSON := $(TOPDIR)/$(TARGET).json + else + ifneq (,$(findstring config.json,$(jsons))) + export APP_JSON := $(TOPDIR)/config.json + endif + endif +else + export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) +endif + +.PHONY: clean all check_lib + +#--------------------------------------------------------------------------------- +all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURDIR)/$(ATMOSPHERE_OUT_DIR)/$(TARGET) \ + DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ + --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ + -f $(THIS_MAKEFILE) + +$(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a: check_lib + @$(SILENTCMD)echo "Checked library." + +ifeq ($(ATMOSPHERE_CHECKED_LIBSTRATOSPHERE),1) +check_lib: +else +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/libstratosphere.mk +endif + +$(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): + @[ -d $@ ] || mkdir -p $@ + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) + + +#--------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +all : $(foreach target,$(ATMOSPHERE_SYSTEM_MODULE_TARGETS),$(OUTPUT).$(target)) + +$(OUTPUT).kip : $(OUTPUT).elf +$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm +$(OUTPUT).nso : $(OUTPUT).elf + +$(OUTPUT).elf : $(OFILES) + +$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + +%.npdm : %.npdm.json + @echo built ... $< $@ + @npdmtool $< $@ + @echo built ... $(notdir $@) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/stratosphere/jpegdec/Makefile b/stratosphere/jpegdec/Makefile index 5886f7495..d681240e5 100644 --- a/stratosphere/jpegdec/Makefile +++ b/stratosphere/jpegdec/Makefile @@ -1,130 +1,41 @@ -#--------------------------------------------------------------------------------- -# pull in common stratosphere sysmodule configuration -#--------------------------------------------------------------------------------- -include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk +ATMOSPHERE_BUILD_CONFIGS := +all: nx_release -#--------------------------------------------------------------------------------- -# jpegdec uses libjpeg-turbo. -#--------------------------------------------------------------------------------- -LIBS += -ljpeg +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) -#--------------------------------------------------------------------------------- -# jpegdec overrides libjpeg-turbo's memory allocation routines. -#--------------------------------------------------------------------------------- -CXXWRAPS += -Wl,--wrap,jpeg_get_small -CXXWRAPS += -Wl,--wrap,jpeg_get_large -CXXWRAPS += -Wl,--wrap,jpeg_free_small -CXXWRAPS += -Wl,--wrap,jpeg_free_large -CXXWRAPS += -Wl,--wrap,sprintf -CXXWRAPS += -Wl,--wrap,fprintf -CXXWRAPS += -Wl,--wrap,getenv -CXXWRAPS += -Wl,--wrap,sscanf +define ATMOSPHERE_ADD_TARGET -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(BUILD),$(notdir $(CURDIR))) -#--------------------------------------------------------------------------------- +ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -export OUTPUT := $(CURDIR)/$(TARGET) -export TOPDIR := $(CURDIR) +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) +clean-$(strip $1): + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -export DEPSDIR := $(CURDIR)/$(BUILD) +endef -CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) -CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) -SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) +define ATMOSPHERE_ADD_TARGETS -BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ +)) -#--------------------------------------------------------------------------------- -# use CXX for linking C++ projects, CC for standard C -#--------------------------------------------------------------------------------- -ifeq ($(strip $(CPPFILES)),) -#--------------------------------------------------------------------------------- - export LD := $(CC) -#--------------------------------------------------------------------------------- -else -#--------------------------------------------------------------------------------- - export LD := $(CXX) -#--------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------- +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ +)) -export OFILES := $(addsuffix .o,$(BINFILES)) \ - $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ +)) -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I$(CURDIR)/$(BUILD) +endef -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) -export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) +clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) -ifeq ($(strip $(CONFIG_JSON)),) - jsons := $(wildcard *.json) - ifneq (,$(findstring $(TARGET).json,$(jsons))) - export APP_JSON := $(TOPDIR)/$(TARGET).json - else - ifneq (,$(findstring config.json,$(jsons))) - export APP_JSON := $(TOPDIR)/config.json - endif - endif -else - export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) -endif - -.PHONY: $(BUILD) clean all - -#--------------------------------------------------------------------------------- -all: $(BUILD) - -$(BUILD): - @[ -d $@ ] || mkdir -p $@ - @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile - -#--------------------------------------------------------------------------------- -clean: - @echo clean ... - @rm -fr $(BUILD) $(TARGET).nsp $(TARGET).npdm $(TARGET).nso $(TARGET).elf - - -#--------------------------------------------------------------------------------- -else -.PHONY: all - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- -all : $(OUTPUT).nsp - -ifeq ($(strip $(APP_JSON)),) -$(OUTPUT).nsp : $(OUTPUT).nso -else -$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm -endif - -$(OUTPUT).nso : $(OUTPUT).elf - -$(OUTPUT).elf : $(OFILES) - -#--------------------------------------------------------------------------------- -# you need a rule like this for each extension you use as binary data -#--------------------------------------------------------------------------------- -%.bin.o : %.bin -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) - --include $(DEPENDS) - -#--------------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------------- +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/stratosphere/jpegdec/system_module.mk b/stratosphere/jpegdec/system_module.mk new file mode 100644 index 000000000..5c3013904 --- /dev/null +++ b/stratosphere/jpegdec/system_module.mk @@ -0,0 +1,148 @@ +#--------------------------------------------------------------------------------- +# pull in common stratosphere sysmodule configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk + +ATMOSPHERE_SYSTEM_MODULE_TARGETS := nsp + +#--------------------------------------------------------------------------------- +# jpegdec uses libjpeg-turbo. +#--------------------------------------------------------------------------------- +LIBS += -ljpeg + +#--------------------------------------------------------------------------------- +# jpegdec overrides libjpeg-turbo's memory allocation routines. +#--------------------------------------------------------------------------------- +CXXWRAPS += -Wl,--wrap,jpeg_get_small +CXXWRAPS += -Wl,--wrap,jpeg_get_large +CXXWRAPS += -Wl,--wrap,jpeg_free_small +CXXWRAPS += -Wl,--wrap,jpeg_free_large +CXXWRAPS += -Wl,--wrap,sprintf +CXXWRAPS += -Wl,--wrap,fprintf +CXXWRAPS += -Wl,--wrap,getenv +CXXWRAPS += -Wl,--wrap,sscanf + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(__RECURSIVE__),1) +#--------------------------------------------------------------------------------- + +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) +CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) +SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) + +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + $(foreach dir,$(AMS_LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) $(foreach dir,$(AMS_LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) + +export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) + +ifeq ($(strip $(CONFIG_JSON)),) + jsons := $(wildcard *.json) + ifneq (,$(findstring $(TARGET).json,$(jsons))) + export APP_JSON := $(TOPDIR)/$(TARGET).json + else + ifneq (,$(findstring config.json,$(jsons))) + export APP_JSON := $(TOPDIR)/config.json + endif + endif +else + export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) +endif + +.PHONY: clean all check_lib + +#--------------------------------------------------------------------------------- +all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURDIR)/$(ATMOSPHERE_OUT_DIR)/$(TARGET) \ + DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ + --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ + -f $(THIS_MAKEFILE) + +$(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a: check_lib + @$(SILENTCMD)echo "Checked library." + +ifeq ($(ATMOSPHERE_CHECKED_LIBSTRATOSPHERE),1) +check_lib: +else +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/libstratosphere.mk +endif + +$(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): + @[ -d $@ ] || mkdir -p $@ + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) + + +#--------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +all : $(foreach target,$(ATMOSPHERE_SYSTEM_MODULE_TARGETS),$(OUTPUT).$(target)) + +$(OUTPUT).kip : $(OUTPUT).elf +$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm +$(OUTPUT).nso : $(OUTPUT).elf + +$(OUTPUT).elf : $(OFILES) + +$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + +%.npdm : %.npdm.json + @echo built ... $< $@ + @npdmtool $< $@ + @echo built ... $(notdir $@) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/stratosphere/loader/Makefile b/stratosphere/loader/Makefile index 1957b6cdb..d681240e5 100644 --- a/stratosphere/loader/Makefile +++ b/stratosphere/loader/Makefile @@ -1,107 +1,41 @@ -#--------------------------------------------------------------------------------- -# pull in common stratosphere sysmodule configuration -#--------------------------------------------------------------------------------- -include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk +ATMOSPHERE_BUILD_CONFIGS := +all: nx_release -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(BUILD),$(notdir $(CURDIR))) -#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) -export OUTPUT := $(CURDIR)/$(TARGET) -export TOPDIR := $(CURDIR) +define ATMOSPHERE_ADD_TARGET -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) +ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -export DEPSDIR := $(CURDIR)/$(BUILD) +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) -CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) -SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) +clean-$(strip $1): + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) +endef -#--------------------------------------------------------------------------------- -# use CXX for linking C++ projects, CC for standard C -#--------------------------------------------------------------------------------- -ifeq ($(strip $(CPPFILES)),) -#--------------------------------------------------------------------------------- - export LD := $(CC) -#--------------------------------------------------------------------------------- -else -#--------------------------------------------------------------------------------- - export LD := $(CXX) -#--------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------- +define ATMOSPHERE_ADD_TARGETS -export OFILES := $(addsuffix .o,$(BINFILES)) \ - $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ +)) -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I$(CURDIR)/$(BUILD) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ +)) -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ +)) -export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) +endef -ifeq ($(strip $(CONFIG_JSON)),) - jsons := $(wildcard *.json) - ifneq (,$(findstring $(TARGET).json,$(jsons))) - export APP_JSON := $(TOPDIR)/$(TARGET).json - else - ifneq (,$(findstring config.json,$(jsons))) - export APP_JSON := $(TOPDIR)/config.json - endif - endif -else - export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) -endif +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) -.PHONY: $(BUILD) clean all +clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) -#--------------------------------------------------------------------------------- -all: $(BUILD) - -$(BUILD): - @[ -d $@ ] || mkdir -p $@ - @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile - -#--------------------------------------------------------------------------------- -clean: - @echo clean ... - @rm -fr $(BUILD) $(TARGET).kip $(TARGET).elf - - -#--------------------------------------------------------------------------------- -else -.PHONY: all - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- -all : $(OUTPUT).kip - -$(OUTPUT).kip : $(OUTPUT).elf - -$(OUTPUT).elf : $(OFILES) - -#--------------------------------------------------------------------------------- -# you need a rule like this for each extension you use as binary data -#--------------------------------------------------------------------------------- -%.bin.o : %.bin -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) - --include $(DEPENDS) - -#--------------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------------- +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/stratosphere/loader/source/ldr_process_creation.cpp b/stratosphere/loader/source/ldr_process_creation.cpp index da1a7c39c..92c3e878b 100644 --- a/stratosphere/loader/source/ldr_process_creation.cpp +++ b/stratosphere/loader/source/ldr_process_creation.cpp @@ -560,7 +560,7 @@ namespace ams::ldr { /* Check hash if necessary. */ if (check_hash) { u8 hash[crypto::Sha256Generator::HashSize]; - crypto::GenerateSha256Hash(hash, sizeof(hash), reinterpret_cast(map_base), segment->size); + crypto::GenerateSha256(hash, sizeof(hash), reinterpret_cast(map_base), segment->size); R_UNLESS(std::memcmp(hash, file_hash, sizeof(hash)) == 0, ldr::ResultInvalidNso()); } diff --git a/stratosphere/loader/system_module.mk b/stratosphere/loader/system_module.mk new file mode 100644 index 000000000..19c207d9a --- /dev/null +++ b/stratosphere/loader/system_module.mk @@ -0,0 +1,131 @@ +#--------------------------------------------------------------------------------- +# pull in common stratosphere sysmodule configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk + +ATMOSPHERE_SYSTEM_MODULE_TARGETS := kip + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(__RECURSIVE__),1) +#--------------------------------------------------------------------------------- + +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) +CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) +SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) + +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + $(foreach dir,$(AMS_LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) $(foreach dir,$(AMS_LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) + +export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) + +ifeq ($(strip $(CONFIG_JSON)),) + jsons := $(wildcard *.json) + ifneq (,$(findstring $(TARGET).json,$(jsons))) + export APP_JSON := $(TOPDIR)/$(TARGET).json + else + ifneq (,$(findstring config.json,$(jsons))) + export APP_JSON := $(TOPDIR)/config.json + endif + endif +else + export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) +endif + +.PHONY: clean all check_lib + +#--------------------------------------------------------------------------------- +all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURDIR)/$(ATMOSPHERE_OUT_DIR)/$(TARGET) \ + DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ + --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ + -f $(THIS_MAKEFILE) + +$(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a: check_lib + @$(SILENTCMD)echo "Checked library." + +ifeq ($(ATMOSPHERE_CHECKED_LIBSTRATOSPHERE),1) +check_lib: +else +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/libstratosphere.mk +endif + +$(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): + @[ -d $@ ] || mkdir -p $@ + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) + + +#--------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +all : $(foreach target,$(ATMOSPHERE_SYSTEM_MODULE_TARGETS),$(OUTPUT).$(target)) + +$(OUTPUT).kip : $(OUTPUT).elf +$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm +$(OUTPUT).nso : $(OUTPUT).elf + +$(OUTPUT).elf : $(OFILES) + +$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + +%.npdm : %.npdm.json + @echo built ... $< $@ + @npdmtool $< $@ + @echo built ... $(notdir $@) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/stratosphere/ncm/Makefile b/stratosphere/ncm/Makefile index 1957b6cdb..d681240e5 100644 --- a/stratosphere/ncm/Makefile +++ b/stratosphere/ncm/Makefile @@ -1,107 +1,41 @@ -#--------------------------------------------------------------------------------- -# pull in common stratosphere sysmodule configuration -#--------------------------------------------------------------------------------- -include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk +ATMOSPHERE_BUILD_CONFIGS := +all: nx_release -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(BUILD),$(notdir $(CURDIR))) -#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) -export OUTPUT := $(CURDIR)/$(TARGET) -export TOPDIR := $(CURDIR) +define ATMOSPHERE_ADD_TARGET -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) +ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -export DEPSDIR := $(CURDIR)/$(BUILD) +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) -CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) -SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) +clean-$(strip $1): + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) +endef -#--------------------------------------------------------------------------------- -# use CXX for linking C++ projects, CC for standard C -#--------------------------------------------------------------------------------- -ifeq ($(strip $(CPPFILES)),) -#--------------------------------------------------------------------------------- - export LD := $(CC) -#--------------------------------------------------------------------------------- -else -#--------------------------------------------------------------------------------- - export LD := $(CXX) -#--------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------- +define ATMOSPHERE_ADD_TARGETS -export OFILES := $(addsuffix .o,$(BINFILES)) \ - $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ +)) -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I$(CURDIR)/$(BUILD) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ +)) -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ +)) -export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) +endef -ifeq ($(strip $(CONFIG_JSON)),) - jsons := $(wildcard *.json) - ifneq (,$(findstring $(TARGET).json,$(jsons))) - export APP_JSON := $(TOPDIR)/$(TARGET).json - else - ifneq (,$(findstring config.json,$(jsons))) - export APP_JSON := $(TOPDIR)/config.json - endif - endif -else - export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) -endif +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) -.PHONY: $(BUILD) clean all +clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) -#--------------------------------------------------------------------------------- -all: $(BUILD) - -$(BUILD): - @[ -d $@ ] || mkdir -p $@ - @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile - -#--------------------------------------------------------------------------------- -clean: - @echo clean ... - @rm -fr $(BUILD) $(TARGET).kip $(TARGET).elf - - -#--------------------------------------------------------------------------------- -else -.PHONY: all - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- -all : $(OUTPUT).kip - -$(OUTPUT).kip : $(OUTPUT).elf - -$(OUTPUT).elf : $(OFILES) - -#--------------------------------------------------------------------------------- -# you need a rule like this for each extension you use as binary data -#--------------------------------------------------------------------------------- -%.bin.o : %.bin -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) - --include $(DEPENDS) - -#--------------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------------- +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/stratosphere/ncm/system_module.mk b/stratosphere/ncm/system_module.mk new file mode 100644 index 000000000..19c207d9a --- /dev/null +++ b/stratosphere/ncm/system_module.mk @@ -0,0 +1,131 @@ +#--------------------------------------------------------------------------------- +# pull in common stratosphere sysmodule configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk + +ATMOSPHERE_SYSTEM_MODULE_TARGETS := kip + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(__RECURSIVE__),1) +#--------------------------------------------------------------------------------- + +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) +CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) +SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) + +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + $(foreach dir,$(AMS_LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) $(foreach dir,$(AMS_LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) + +export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) + +ifeq ($(strip $(CONFIG_JSON)),) + jsons := $(wildcard *.json) + ifneq (,$(findstring $(TARGET).json,$(jsons))) + export APP_JSON := $(TOPDIR)/$(TARGET).json + else + ifneq (,$(findstring config.json,$(jsons))) + export APP_JSON := $(TOPDIR)/config.json + endif + endif +else + export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) +endif + +.PHONY: clean all check_lib + +#--------------------------------------------------------------------------------- +all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURDIR)/$(ATMOSPHERE_OUT_DIR)/$(TARGET) \ + DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ + --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ + -f $(THIS_MAKEFILE) + +$(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a: check_lib + @$(SILENTCMD)echo "Checked library." + +ifeq ($(ATMOSPHERE_CHECKED_LIBSTRATOSPHERE),1) +check_lib: +else +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/libstratosphere.mk +endif + +$(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): + @[ -d $@ ] || mkdir -p $@ + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) + + +#--------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +all : $(foreach target,$(ATMOSPHERE_SYSTEM_MODULE_TARGETS),$(OUTPUT).$(target)) + +$(OUTPUT).kip : $(OUTPUT).elf +$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm +$(OUTPUT).nso : $(OUTPUT).elf + +$(OUTPUT).elf : $(OFILES) + +$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + +%.npdm : %.npdm.json + @echo built ... $< $@ + @npdmtool $< $@ + @echo built ... $(notdir $@) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/stratosphere/pgl/Makefile b/stratosphere/pgl/Makefile index aab86a63a..d681240e5 100644 --- a/stratosphere/pgl/Makefile +++ b/stratosphere/pgl/Makefile @@ -1,113 +1,41 @@ -#--------------------------------------------------------------------------------- -# pull in common stratosphere sysmodule configuration -#--------------------------------------------------------------------------------- -include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk +ATMOSPHERE_BUILD_CONFIGS := +all: nx_release -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(BUILD),$(notdir $(CURDIR))) -#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) -export OUTPUT := $(CURDIR)/$(TARGET) -export TOPDIR := $(CURDIR) +define ATMOSPHERE_ADD_TARGET -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) +ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -export DEPSDIR := $(CURDIR)/$(BUILD) +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) -CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) -SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) +clean-$(strip $1): + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) +endef -#--------------------------------------------------------------------------------- -# use CXX for linking C++ projects, CC for standard C -#--------------------------------------------------------------------------------- -ifeq ($(strip $(CPPFILES)),) -#--------------------------------------------------------------------------------- - export LD := $(CC) -#--------------------------------------------------------------------------------- -else -#--------------------------------------------------------------------------------- - export LD := $(CXX) -#--------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------- +define ATMOSPHERE_ADD_TARGETS -export OFILES := $(addsuffix .o,$(BINFILES)) \ - $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ +)) -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I$(CURDIR)/$(BUILD) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ +)) -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ +)) -export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) +endef -ifeq ($(strip $(CONFIG_JSON)),) - jsons := $(wildcard *.json) - ifneq (,$(findstring $(TARGET).json,$(jsons))) - export APP_JSON := $(TOPDIR)/$(TARGET).json - else - ifneq (,$(findstring config.json,$(jsons))) - export APP_JSON := $(TOPDIR)/config.json - endif - endif -else - export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) -endif +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) -.PHONY: $(BUILD) clean all +clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) -#--------------------------------------------------------------------------------- -all: $(BUILD) - -$(BUILD): - @[ -d $@ ] || mkdir -p $@ - @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile - -#--------------------------------------------------------------------------------- -clean: - @echo clean ... - @rm -fr $(BUILD) $(TARGET).nsp $(TARGET).npdm $(TARGET).nso $(TARGET).elf - - -#--------------------------------------------------------------------------------- -else -.PHONY: all - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- -all : $(OUTPUT).nsp - -ifeq ($(strip $(APP_JSON)),) -$(OUTPUT).nsp : $(OUTPUT).nso -else -$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm -endif - -$(OUTPUT).nso : $(OUTPUT).elf - -$(OUTPUT).elf : $(OFILES) - -#--------------------------------------------------------------------------------- -# you need a rule like this for each extension you use as binary data -#--------------------------------------------------------------------------------- -%.bin.o : %.bin -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) - --include $(DEPENDS) - -#--------------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------------- +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/stratosphere/pgl/system_module.mk b/stratosphere/pgl/system_module.mk new file mode 100644 index 000000000..d6de42efc --- /dev/null +++ b/stratosphere/pgl/system_module.mk @@ -0,0 +1,131 @@ +#--------------------------------------------------------------------------------- +# pull in common stratosphere sysmodule configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk + +ATMOSPHERE_SYSTEM_MODULE_TARGETS := nsp + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(__RECURSIVE__),1) +#--------------------------------------------------------------------------------- + +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) +CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) +SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) + +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + $(foreach dir,$(AMS_LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) $(foreach dir,$(AMS_LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) + +export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) + +ifeq ($(strip $(CONFIG_JSON)),) + jsons := $(wildcard *.json) + ifneq (,$(findstring $(TARGET).json,$(jsons))) + export APP_JSON := $(TOPDIR)/$(TARGET).json + else + ifneq (,$(findstring config.json,$(jsons))) + export APP_JSON := $(TOPDIR)/config.json + endif + endif +else + export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) +endif + +.PHONY: clean all check_lib + +#--------------------------------------------------------------------------------- +all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURDIR)/$(ATMOSPHERE_OUT_DIR)/$(TARGET) \ + DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ + --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ + -f $(THIS_MAKEFILE) + +$(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a: check_lib + @$(SILENTCMD)echo "Checked library." + +ifeq ($(ATMOSPHERE_CHECKED_LIBSTRATOSPHERE),1) +check_lib: +else +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/libstratosphere.mk +endif + +$(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): + @[ -d $@ ] || mkdir -p $@ + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) + + +#--------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +all : $(foreach target,$(ATMOSPHERE_SYSTEM_MODULE_TARGETS),$(OUTPUT).$(target)) + +$(OUTPUT).kip : $(OUTPUT).elf +$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm +$(OUTPUT).nso : $(OUTPUT).elf + +$(OUTPUT).elf : $(OFILES) + +$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + +%.npdm : %.npdm.json + @echo built ... $< $@ + @npdmtool $< $@ + @echo built ... $(notdir $@) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/stratosphere/pm/Makefile b/stratosphere/pm/Makefile index 1957b6cdb..d681240e5 100644 --- a/stratosphere/pm/Makefile +++ b/stratosphere/pm/Makefile @@ -1,107 +1,41 @@ -#--------------------------------------------------------------------------------- -# pull in common stratosphere sysmodule configuration -#--------------------------------------------------------------------------------- -include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk +ATMOSPHERE_BUILD_CONFIGS := +all: nx_release -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(BUILD),$(notdir $(CURDIR))) -#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) -export OUTPUT := $(CURDIR)/$(TARGET) -export TOPDIR := $(CURDIR) +define ATMOSPHERE_ADD_TARGET -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) +ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -export DEPSDIR := $(CURDIR)/$(BUILD) +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) -CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) -SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) +clean-$(strip $1): + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) +endef -#--------------------------------------------------------------------------------- -# use CXX for linking C++ projects, CC for standard C -#--------------------------------------------------------------------------------- -ifeq ($(strip $(CPPFILES)),) -#--------------------------------------------------------------------------------- - export LD := $(CC) -#--------------------------------------------------------------------------------- -else -#--------------------------------------------------------------------------------- - export LD := $(CXX) -#--------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------- +define ATMOSPHERE_ADD_TARGETS -export OFILES := $(addsuffix .o,$(BINFILES)) \ - $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ +)) -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I$(CURDIR)/$(BUILD) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ +)) -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ +)) -export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) +endef -ifeq ($(strip $(CONFIG_JSON)),) - jsons := $(wildcard *.json) - ifneq (,$(findstring $(TARGET).json,$(jsons))) - export APP_JSON := $(TOPDIR)/$(TARGET).json - else - ifneq (,$(findstring config.json,$(jsons))) - export APP_JSON := $(TOPDIR)/config.json - endif - endif -else - export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) -endif +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) -.PHONY: $(BUILD) clean all +clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) -#--------------------------------------------------------------------------------- -all: $(BUILD) - -$(BUILD): - @[ -d $@ ] || mkdir -p $@ - @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile - -#--------------------------------------------------------------------------------- -clean: - @echo clean ... - @rm -fr $(BUILD) $(TARGET).kip $(TARGET).elf - - -#--------------------------------------------------------------------------------- -else -.PHONY: all - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- -all : $(OUTPUT).kip - -$(OUTPUT).kip : $(OUTPUT).elf - -$(OUTPUT).elf : $(OFILES) - -#--------------------------------------------------------------------------------- -# you need a rule like this for each extension you use as binary data -#--------------------------------------------------------------------------------- -%.bin.o : %.bin -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) - --include $(DEPENDS) - -#--------------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------------- +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/stratosphere/pm/source/impl/pm_process_manager.cpp b/stratosphere/pm/source/impl/pm_process_manager.cpp index 7b1e39f88..2da99fdef 100644 --- a/stratosphere/pm/source/impl/pm_process_manager.cpp +++ b/stratosphere/pm/source/impl/pm_process_manager.cpp @@ -659,8 +659,8 @@ namespace ams::pm::impl { /* Boot API. */ Result NotifyBootFinished() { - static bool g_has_boot_finished = false; - if (!g_has_boot_finished) { + AMS_FUNCTION_LOCAL_STATIC_CONSTINIT(bool, s_has_boot_finished, false); + if (!s_has_boot_finished) { /* Set program verification disabled, if we should. */ /* NOTE: Nintendo does not check the result of this. */ if (spl::IsDisabledProgramVerification()) { @@ -672,7 +672,8 @@ namespace ams::pm::impl { } boot2::LaunchPreSdCardBootProgramsAndBoot2(); - g_has_boot_finished = true; + + s_has_boot_finished = true; os::SignalSystemEvent(std::addressof(g_boot_finished_event)); } return ResultSuccess(); diff --git a/stratosphere/pm/system_module.mk b/stratosphere/pm/system_module.mk new file mode 100644 index 000000000..19c207d9a --- /dev/null +++ b/stratosphere/pm/system_module.mk @@ -0,0 +1,131 @@ +#--------------------------------------------------------------------------------- +# pull in common stratosphere sysmodule configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk + +ATMOSPHERE_SYSTEM_MODULE_TARGETS := kip + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(__RECURSIVE__),1) +#--------------------------------------------------------------------------------- + +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) +CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) +SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) + +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + $(foreach dir,$(AMS_LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) $(foreach dir,$(AMS_LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) + +export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) + +ifeq ($(strip $(CONFIG_JSON)),) + jsons := $(wildcard *.json) + ifneq (,$(findstring $(TARGET).json,$(jsons))) + export APP_JSON := $(TOPDIR)/$(TARGET).json + else + ifneq (,$(findstring config.json,$(jsons))) + export APP_JSON := $(TOPDIR)/config.json + endif + endif +else + export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) +endif + +.PHONY: clean all check_lib + +#--------------------------------------------------------------------------------- +all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURDIR)/$(ATMOSPHERE_OUT_DIR)/$(TARGET) \ + DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ + --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ + -f $(THIS_MAKEFILE) + +$(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a: check_lib + @$(SILENTCMD)echo "Checked library." + +ifeq ($(ATMOSPHERE_CHECKED_LIBSTRATOSPHERE),1) +check_lib: +else +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/libstratosphere.mk +endif + +$(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): + @[ -d $@ ] || mkdir -p $@ + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) + + +#--------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +all : $(foreach target,$(ATMOSPHERE_SYSTEM_MODULE_TARGETS),$(OUTPUT).$(target)) + +$(OUTPUT).kip : $(OUTPUT).elf +$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm +$(OUTPUT).nso : $(OUTPUT).elf + +$(OUTPUT).elf : $(OFILES) + +$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + +%.npdm : %.npdm.json + @echo built ... $< $@ + @npdmtool $< $@ + @echo built ... $(notdir $@) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/stratosphere/ro/Makefile b/stratosphere/ro/Makefile index aab86a63a..d681240e5 100644 --- a/stratosphere/ro/Makefile +++ b/stratosphere/ro/Makefile @@ -1,113 +1,41 @@ -#--------------------------------------------------------------------------------- -# pull in common stratosphere sysmodule configuration -#--------------------------------------------------------------------------------- -include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk +ATMOSPHERE_BUILD_CONFIGS := +all: nx_release -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(BUILD),$(notdir $(CURDIR))) -#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) -export OUTPUT := $(CURDIR)/$(TARGET) -export TOPDIR := $(CURDIR) +define ATMOSPHERE_ADD_TARGET -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) +ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -export DEPSDIR := $(CURDIR)/$(BUILD) +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) -CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) -SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) +clean-$(strip $1): + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) +endef -#--------------------------------------------------------------------------------- -# use CXX for linking C++ projects, CC for standard C -#--------------------------------------------------------------------------------- -ifeq ($(strip $(CPPFILES)),) -#--------------------------------------------------------------------------------- - export LD := $(CC) -#--------------------------------------------------------------------------------- -else -#--------------------------------------------------------------------------------- - export LD := $(CXX) -#--------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------- +define ATMOSPHERE_ADD_TARGETS -export OFILES := $(addsuffix .o,$(BINFILES)) \ - $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ +)) -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I$(CURDIR)/$(BUILD) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ +)) -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ +)) -export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) +endef -ifeq ($(strip $(CONFIG_JSON)),) - jsons := $(wildcard *.json) - ifneq (,$(findstring $(TARGET).json,$(jsons))) - export APP_JSON := $(TOPDIR)/$(TARGET).json - else - ifneq (,$(findstring config.json,$(jsons))) - export APP_JSON := $(TOPDIR)/config.json - endif - endif -else - export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) -endif +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) -.PHONY: $(BUILD) clean all +clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) -#--------------------------------------------------------------------------------- -all: $(BUILD) - -$(BUILD): - @[ -d $@ ] || mkdir -p $@ - @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile - -#--------------------------------------------------------------------------------- -clean: - @echo clean ... - @rm -fr $(BUILD) $(TARGET).nsp $(TARGET).npdm $(TARGET).nso $(TARGET).elf - - -#--------------------------------------------------------------------------------- -else -.PHONY: all - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- -all : $(OUTPUT).nsp - -ifeq ($(strip $(APP_JSON)),) -$(OUTPUT).nsp : $(OUTPUT).nso -else -$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm -endif - -$(OUTPUT).nso : $(OUTPUT).elf - -$(OUTPUT).elf : $(OFILES) - -#--------------------------------------------------------------------------------- -# you need a rule like this for each extension you use as binary data -#--------------------------------------------------------------------------------- -%.bin.o : %.bin -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) - --include $(DEPENDS) - -#--------------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------------- +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/stratosphere/ro/source/impl/ro_nrr_utils.cpp b/stratosphere/ro/source/impl/ro_nrr_utils.cpp index 1f5685e76..cf05678a8 100644 --- a/stratosphere/ro/source/impl/ro_nrr_utils.cpp +++ b/stratosphere/ro/source/impl/ro_nrr_utils.cpp @@ -242,7 +242,7 @@ namespace ams::ro::impl { nrr_mcm.Cancel(); /* Save a copy of the hash that we verified. */ - crypto::GenerateSha256Hash(out_hash, out_hash_size, nrr_header->GetSignedArea(), nrr_header->GetSignedAreaSize()); + crypto::GenerateSha256(out_hash, out_hash_size, nrr_header->GetSignedArea(), nrr_header->GetSignedAreaSize()); *out_header = nrr_header; *out_mapped_code_address = code_address; diff --git a/stratosphere/ro/source/impl/ro_service_impl.cpp b/stratosphere/ro/source/impl/ro_service_impl.cpp index 91ef21017..36cf7a1bf 100644 --- a/stratosphere/ro/source/impl/ro_service_impl.cpp +++ b/stratosphere/ro/source/impl/ro_service_impl.cpp @@ -205,7 +205,7 @@ namespace ams::ro::impl { Result ValidateHasNroHash(const NroHeader *nro_header) const { /* Calculate hash. */ Sha256Hash hash; - crypto::GenerateSha256Hash(std::addressof(hash), sizeof(hash), nro_header, nro_header->GetSize()); + crypto::GenerateSha256(std::addressof(hash), sizeof(hash), nro_header, nro_header->GetSize()); for (size_t i = 0; i < MaxNrrInfos; i++) { /* Ensure we only check NRRs that are used. */ diff --git a/stratosphere/ro/system_module.mk b/stratosphere/ro/system_module.mk new file mode 100644 index 000000000..d6de42efc --- /dev/null +++ b/stratosphere/ro/system_module.mk @@ -0,0 +1,131 @@ +#--------------------------------------------------------------------------------- +# pull in common stratosphere sysmodule configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk + +ATMOSPHERE_SYSTEM_MODULE_TARGETS := nsp + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(__RECURSIVE__),1) +#--------------------------------------------------------------------------------- + +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) +CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) +SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) + +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + $(foreach dir,$(AMS_LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) $(foreach dir,$(AMS_LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) + +export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) + +ifeq ($(strip $(CONFIG_JSON)),) + jsons := $(wildcard *.json) + ifneq (,$(findstring $(TARGET).json,$(jsons))) + export APP_JSON := $(TOPDIR)/$(TARGET).json + else + ifneq (,$(findstring config.json,$(jsons))) + export APP_JSON := $(TOPDIR)/config.json + endif + endif +else + export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) +endif + +.PHONY: clean all check_lib + +#--------------------------------------------------------------------------------- +all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURDIR)/$(ATMOSPHERE_OUT_DIR)/$(TARGET) \ + DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ + --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ + -f $(THIS_MAKEFILE) + +$(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a: check_lib + @$(SILENTCMD)echo "Checked library." + +ifeq ($(ATMOSPHERE_CHECKED_LIBSTRATOSPHERE),1) +check_lib: +else +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/libstratosphere.mk +endif + +$(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): + @[ -d $@ ] || mkdir -p $@ + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) + + +#--------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +all : $(foreach target,$(ATMOSPHERE_SYSTEM_MODULE_TARGETS),$(OUTPUT).$(target)) + +$(OUTPUT).kip : $(OUTPUT).elf +$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm +$(OUTPUT).nso : $(OUTPUT).elf + +$(OUTPUT).elf : $(OFILES) + +$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + +%.npdm : %.npdm.json + @echo built ... $< $@ + @npdmtool $< $@ + @echo built ... $(notdir $@) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/stratosphere/sm/Makefile b/stratosphere/sm/Makefile index 1957b6cdb..d681240e5 100644 --- a/stratosphere/sm/Makefile +++ b/stratosphere/sm/Makefile @@ -1,107 +1,41 @@ -#--------------------------------------------------------------------------------- -# pull in common stratosphere sysmodule configuration -#--------------------------------------------------------------------------------- -include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk +ATMOSPHERE_BUILD_CONFIGS := +all: nx_release -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(BUILD),$(notdir $(CURDIR))) -#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) -export OUTPUT := $(CURDIR)/$(TARGET) -export TOPDIR := $(CURDIR) +define ATMOSPHERE_ADD_TARGET -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) +ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -export DEPSDIR := $(CURDIR)/$(BUILD) +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) -CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) -SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) +clean-$(strip $1): + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) +endef -#--------------------------------------------------------------------------------- -# use CXX for linking C++ projects, CC for standard C -#--------------------------------------------------------------------------------- -ifeq ($(strip $(CPPFILES)),) -#--------------------------------------------------------------------------------- - export LD := $(CC) -#--------------------------------------------------------------------------------- -else -#--------------------------------------------------------------------------------- - export LD := $(CXX) -#--------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------- +define ATMOSPHERE_ADD_TARGETS -export OFILES := $(addsuffix .o,$(BINFILES)) \ - $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ +)) -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I$(CURDIR)/$(BUILD) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ +)) -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ +)) -export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) +endef -ifeq ($(strip $(CONFIG_JSON)),) - jsons := $(wildcard *.json) - ifneq (,$(findstring $(TARGET).json,$(jsons))) - export APP_JSON := $(TOPDIR)/$(TARGET).json - else - ifneq (,$(findstring config.json,$(jsons))) - export APP_JSON := $(TOPDIR)/config.json - endif - endif -else - export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) -endif +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) -.PHONY: $(BUILD) clean all +clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) -#--------------------------------------------------------------------------------- -all: $(BUILD) - -$(BUILD): - @[ -d $@ ] || mkdir -p $@ - @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile - -#--------------------------------------------------------------------------------- -clean: - @echo clean ... - @rm -fr $(BUILD) $(TARGET).kip $(TARGET).elf - - -#--------------------------------------------------------------------------------- -else -.PHONY: all - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- -all : $(OUTPUT).kip - -$(OUTPUT).kip : $(OUTPUT).elf - -$(OUTPUT).elf : $(OFILES) - -#--------------------------------------------------------------------------------- -# you need a rule like this for each extension you use as binary data -#--------------------------------------------------------------------------------- -%.bin.o : %.bin -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) - --include $(DEPENDS) - -#--------------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------------- +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/stratosphere/sm/system_module.mk b/stratosphere/sm/system_module.mk new file mode 100644 index 000000000..19c207d9a --- /dev/null +++ b/stratosphere/sm/system_module.mk @@ -0,0 +1,131 @@ +#--------------------------------------------------------------------------------- +# pull in common stratosphere sysmodule configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk + +ATMOSPHERE_SYSTEM_MODULE_TARGETS := kip + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(__RECURSIVE__),1) +#--------------------------------------------------------------------------------- + +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) +CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) +SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) + +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + $(foreach dir,$(AMS_LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) $(foreach dir,$(AMS_LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) + +export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) + +ifeq ($(strip $(CONFIG_JSON)),) + jsons := $(wildcard *.json) + ifneq (,$(findstring $(TARGET).json,$(jsons))) + export APP_JSON := $(TOPDIR)/$(TARGET).json + else + ifneq (,$(findstring config.json,$(jsons))) + export APP_JSON := $(TOPDIR)/config.json + endif + endif +else + export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) +endif + +.PHONY: clean all check_lib + +#--------------------------------------------------------------------------------- +all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURDIR)/$(ATMOSPHERE_OUT_DIR)/$(TARGET) \ + DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ + --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ + -f $(THIS_MAKEFILE) + +$(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a: check_lib + @$(SILENTCMD)echo "Checked library." + +ifeq ($(ATMOSPHERE_CHECKED_LIBSTRATOSPHERE),1) +check_lib: +else +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/libstratosphere.mk +endif + +$(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): + @[ -d $@ ] || mkdir -p $@ + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) + + +#--------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +all : $(foreach target,$(ATMOSPHERE_SYSTEM_MODULE_TARGETS),$(OUTPUT).$(target)) + +$(OUTPUT).kip : $(OUTPUT).elf +$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm +$(OUTPUT).nso : $(OUTPUT).elf + +$(OUTPUT).elf : $(OFILES) + +$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + +%.npdm : %.npdm.json + @echo built ... $< $@ + @npdmtool $< $@ + @echo built ... $(notdir $@) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/stratosphere/spl/Makefile b/stratosphere/spl/Makefile index 1957b6cdb..d681240e5 100644 --- a/stratosphere/spl/Makefile +++ b/stratosphere/spl/Makefile @@ -1,107 +1,41 @@ -#--------------------------------------------------------------------------------- -# pull in common stratosphere sysmodule configuration -#--------------------------------------------------------------------------------- -include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk +ATMOSPHERE_BUILD_CONFIGS := +all: nx_release -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(BUILD),$(notdir $(CURDIR))) -#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) -export OUTPUT := $(CURDIR)/$(TARGET) -export TOPDIR := $(CURDIR) +define ATMOSPHERE_ADD_TARGET -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) +ATMOSPHERE_BUILD_CONFIGS += $(strip $1) -export DEPSDIR := $(CURDIR)/$(BUILD) +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) -CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) -SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) +clean-$(strip $1): + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/system_module.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) -BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) +endef -#--------------------------------------------------------------------------------- -# use CXX for linking C++ projects, CC for standard C -#--------------------------------------------------------------------------------- -ifeq ($(strip $(CPPFILES)),) -#--------------------------------------------------------------------------------- - export LD := $(CC) -#--------------------------------------------------------------------------------- -else -#--------------------------------------------------------------------------------- - export LD := $(CXX) -#--------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------- +define ATMOSPHERE_ADD_TARGETS -export OFILES := $(addsuffix .o,$(BINFILES)) \ - $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ +)) -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I$(CURDIR)/$(BUILD) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ +)) -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ +)) -export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) +endef -ifeq ($(strip $(CONFIG_JSON)),) - jsons := $(wildcard *.json) - ifneq (,$(findstring $(TARGET).json,$(jsons))) - export APP_JSON := $(TOPDIR)/$(TARGET).json - else - ifneq (,$(findstring config.json,$(jsons))) - export APP_JSON := $(TOPDIR)/config.json - endif - endif -else - export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) -endif +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) -.PHONY: $(BUILD) clean all +clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) -#--------------------------------------------------------------------------------- -all: $(BUILD) - -$(BUILD): - @[ -d $@ ] || mkdir -p $@ - @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile - -#--------------------------------------------------------------------------------- -clean: - @echo clean ... - @rm -fr $(BUILD) $(TARGET).kip $(TARGET).elf - - -#--------------------------------------------------------------------------------- -else -.PHONY: all - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- -all : $(OUTPUT).kip - -$(OUTPUT).kip : $(OUTPUT).elf - -$(OUTPUT).elf : $(OFILES) - -#--------------------------------------------------------------------------------- -# you need a rule like this for each extension you use as binary data -#--------------------------------------------------------------------------------- -%.bin.o : %.bin -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) - --include $(DEPENDS) - -#--------------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------------- +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/stratosphere/spl/system_module.mk b/stratosphere/spl/system_module.mk new file mode 100644 index 000000000..19c207d9a --- /dev/null +++ b/stratosphere/spl/system_module.mk @@ -0,0 +1,131 @@ +#--------------------------------------------------------------------------------- +# pull in common stratosphere sysmodule configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk + +ATMOSPHERE_SYSTEM_MODULE_TARGETS := kip + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(__RECURSIVE__),1) +#--------------------------------------------------------------------------------- + +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) +CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) +SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) + +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + $(foreach dir,$(AMS_LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) $(foreach dir,$(AMS_LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) + +export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) + +ifeq ($(strip $(CONFIG_JSON)),) + jsons := $(wildcard *.json) + ifneq (,$(findstring $(TARGET).json,$(jsons))) + export APP_JSON := $(TOPDIR)/$(TARGET).json + else + ifneq (,$(findstring config.json,$(jsons))) + export APP_JSON := $(TOPDIR)/config.json + endif + endif +else + export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) +endif + +.PHONY: clean all check_lib + +#--------------------------------------------------------------------------------- +all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURDIR)/$(ATMOSPHERE_OUT_DIR)/$(TARGET) \ + DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ + --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ + -f $(THIS_MAKEFILE) + +$(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a: check_lib + @$(SILENTCMD)echo "Checked library." + +ifeq ($(ATMOSPHERE_CHECKED_LIBSTRATOSPHERE),1) +check_lib: +else +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/libstratosphere.mk +endif + +$(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): + @[ -d $@ ] || mkdir -p $@ + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) + + +#--------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +all : $(foreach target,$(ATMOSPHERE_SYSTEM_MODULE_TARGETS),$(OUTPUT).$(target)) + +$(OUTPUT).kip : $(OUTPUT).elf +$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm +$(OUTPUT).nso : $(OUTPUT).elf + +$(OUTPUT).elf : $(OFILES) + +$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + +%.npdm : %.npdm.json + @echo built ... $< $@ + @npdmtool $< $@ + @echo built ... $(notdir $@) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/stratosphere/stratosphere.mk b/stratosphere/stratosphere.mk new file mode 100644 index 000000000..5b06a6d98 --- /dev/null +++ b/stratosphere/stratosphere.mk @@ -0,0 +1,29 @@ +#--------------------------------------------------------------------------------- +# pull in common atmosphere configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) +include $(CURRENT_DIRECTORY)/../libraries/config/common.mk + +ALL_MODULES := loader boot ncm pm sm ams_mitm spl eclct.stub ro creport fatal dmnt boot2 erpt pgl jpegdec LogManager cs htc TioServer dmnt.gen2 + +all: $(ALL_MODULES) + +$(ALL_MODULES): check_lib + @$(SILENTCMD)echo Checking $@... + @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/$@ -f $(CURRENT_DIRECTORY)/$@/system_module.mk ATMOSPHERE_CHECKED_LIBSTRATOSPHERE=1 + +$(foreach module,$(ALL_MODULES),clean-$(module)): + @$(SILENTCMD)echo Cleaning $(@:clean-%=%)... + @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/$(@:clean-%=%) -f $(CURRENT_DIRECTORY)/$(@:clean-%=%)/system_module.mk clean + +ifeq ($(ATMOSPHERE_CHECKED_LIBSTRATOSPHERE),1) +check_lib: +else +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/libstratosphere.mk +endif + +clean: $(foreach module,$(ALL_MODULES),clean-$(module)) + +.PHONY: all clean check_lib $(foreach module,$(ALL_MODULES),$(module) clean-$(module)) \ No newline at end of file diff --git a/tests/TestFs/Makefile b/tests/TestFs/Makefile new file mode 100644 index 000000000..4f16374da --- /dev/null +++ b/tests/TestFs/Makefile @@ -0,0 +1,51 @@ +ATMOSPHERE_BUILD_CONFIGS := +all: nx_release + +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) + +define ATMOSPHERE_ADD_TARGET + +ATMOSPHERE_BUILD_CONFIGS += $(strip $1) + +$(strip $1): + @echo "Building $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/unit_test.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) + +clean-$(strip $1): + @echo "Cleaning $(strip $1)" + @$$(MAKE) -f $(CURRENT_DIRECTORY)/unit_test.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) + +endef + +define ATMOSPHERE_ADD_TARGETS + +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, $(strip $2)release, $(strip $3), $(strip $4), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $5)" $(strip $6) \ +)) + +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, $(strip $2)debug, $(strip $3), $(strip $4), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $5) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 $(strip $6) \ +)) + +$(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, $(strip $2)audit, $(strip $3), $(strip $4), \ + ATMOSPHERE_BUILD_SETTINGS="$(strip $5) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 $(strip $6) \ +)) + +endef + + +$(eval $(call ATMOSPHERE_ADD_TARGETS, nx, , nx-hac-001, arm-cortex-a57,,)) + +$(eval $(call ATMOSPHERE_ADD_TARGETS, win_x64, , generic_windows, generic_x64,,)) + +$(eval $(call ATMOSPHERE_ADD_TARGETS, linux_x64, , generic_linux, generic_x64,,)) +$(eval $(call ATMOSPHERE_ADD_TARGETS, linux_x64_clang, clang_, generic_linux, generic_x64,, ATMOSPHERE_COMPILER_NAME="clang")) +$(eval $(call ATMOSPHERE_ADD_TARGETS, linux_arm64_clang, clang_, generic_linux, generic_arm64,, ATMOSPHERE_COMPILER_NAME="clang")) + +$(eval $(call ATMOSPHERE_ADD_TARGETS, macos_x64, , generic_macos, generic_x64,,)) +$(eval $(call ATMOSPHERE_ADD_TARGETS, macos_arm64, , generic_macos, generic_arm64,,)) + +clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) + +.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) diff --git a/tests/TestFs/source/test.cpp b/tests/TestFs/source/test.cpp new file mode 100644 index 000000000..3d159603a --- /dev/null +++ b/tests/TestFs/source/test.cpp @@ -0,0 +1,852 @@ +#include + +namespace ams { + + namespace fssrv::impl { + + const char *GetExecutionDirectoryPath(); + + } + + namespace { + + void GetPath(char *dst, size_t dst_size, const char *src) { + if (fs::IsPathAbsolute(src)) { + util::SNPrintf(dst, dst_size, "%s", src); + } else { + util::SNPrintf(dst, dst_size, "%s%s", fssrv::impl::GetExecutionDirectoryPath(), src); + } + } + + #define TEST_R_EXPECT(__EXPR__, __EXPECTED__) \ + ({ \ + const Result __test_result = (__EXPR__); \ + if (!(__EXPECTED__ ::Includes(__test_result))) { \ + printf("Unexpected result: %s gave 0x%08x (2%03d-%04d)\n", # __EXPR__, __test_result.GetValue(), __test_result.GetModule(), __test_result.GetDescription()); \ + return; \ + } \ + __test_result; \ + }) + + #define TEST_R_TRY(__EXPR__) \ + ({ \ + const Result __test_result = (__EXPR__); \ + if (R_FAILED(__test_result)) { \ + printf("Unexpected result: %s gave 0x%08x (2%03d-%04d)\n", # __EXPR__, __test_result.GetValue(), __test_result.GetModule(), __test_result.GetDescription()); \ + return; \ + } \ + __test_result; \ + }) + + u8 g_buffer[64_KB]; + + void DoFsTests() { + /* Declare buffer to hold any work paths we have. */ + char path_buf[fs::EntryNameLengthMax + 1]; + char path_buf2[fs::EntryNameLengthMax + 1]; + #define FORMAT_PATH(S) ({ GetPath(path_buf, sizeof(path_buf), S); path_buf; }) + #define FORMAT_PATH2(S) ({ GetPath(path_buf2, sizeof(path_buf2), S); path_buf2; }) + AMS_UNUSED(path_buf); + AMS_UNUSED(path_buf2); + + /* Clear anything from a previous test run, no obligation for this to succeed. */ + fs::DeleteDirectoryRecursively(FORMAT_PATH("./test_dir/")); + + /* Verify that the test directory does not exist. */ + fs::DirectoryEntryType entry_type; + TEST_R_EXPECT(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/")), fs::ResultPathNotFound); + + /* Create the subdirectory. */ + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/"))); + + /* Verify the test directory exists and is a directory. */ + TEST_R_TRY(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/"))); + AMS_ABORT_UNLESS(entry_type == fs::DirectoryEntryType_Directory); + + /* ==================================================================================================================== */ + /* Create File */ + /* ==================================================================================================================== */ + + /* Create a file. */ + TEST_R_EXPECT(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/test_rand.bin")), fs::ResultPathNotFound); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/test_rand.bin"), sizeof(g_buffer))); + + /* Check the file has correct entry type. */ + TEST_R_TRY(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/test_rand.bin"))); + AMS_ABORT_UNLESS(entry_type == fs::DirectoryEntryType_File); + + /* Create already existing file -> fs::ResultPathAlreadyExists(). */ + TEST_R_EXPECT(fs::CreateFile(FORMAT_PATH("./test_dir/test_rand.bin"), sizeof(g_buffer)), fs::ResultPathAlreadyExists); + + /* Create already existing dir -> fs::ResultPathAlreadyExists(). */ + TEST_R_EXPECT(fs::CreateFile(FORMAT_PATH("./test_dir/"), sizeof(g_buffer)), fs::ResultPathAlreadyExists); + + /* Create file without parent existing -> fs::ResultPathNotFound(). */ + TEST_R_EXPECT(fs::CreateFile(FORMAT_PATH("./test_dir/aaa/bbb.bin"), sizeof(g_buffer)), fs::ResultPathNotFound); + + /* ==================================================================================================================== */ + /* Create Directory */ + /* ==================================================================================================================== */ + + /* Create the subdirectory. */ + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/test_subdir/"))); + + /* Verify the test directory exists and is a directory. */ + TEST_R_TRY(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/test_subdir/"))); + AMS_ABORT_UNLESS(entry_type == fs::DirectoryEntryType_Directory); + + /* Create already existing file -> fs::ResultPathAlreadyExists(). */ + TEST_R_EXPECT(fs::CreateDirectory(FORMAT_PATH("./test_dir/test_rand.bin")), fs::ResultPathAlreadyExists); + + /* Create already existing dir -> fs::ResultPathAlreadyExists(). */ + TEST_R_EXPECT(fs::CreateDirectory(FORMAT_PATH("./test_dir/")), fs::ResultPathAlreadyExists); + + /* Create dir without parent existing -> fs::ResultPathAlreadyExists(). */ + TEST_R_EXPECT(fs::CreateDirectory(FORMAT_PATH("./test_dir/aaa/bbb/")), fs::ResultPathNotFound); + + /* ==================================================================================================================== */ + /* Delete File */ + /* ==================================================================================================================== */ + + /* Delete file succeeds. */ + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/tmp_for_delete.bin"), sizeof(g_buffer))); + TEST_R_TRY(fs::DeleteFile(FORMAT_PATH("./test_dir/tmp_for_delete.bin"))); + + /* Delete on invalid path -> fs::ResultPathNotFound(). */ + TEST_R_EXPECT(fs::DeleteFile(FORMAT_PATH("./test_dir/invalid")), fs::ResultPathNotFound); + + /* Delete on directory -> fs::ResultPathNotFound(). */ + TEST_R_EXPECT(fs::DeleteFile(FORMAT_PATH("./test_dir/test_subdir/")), fs::ResultPathNotFound); + + /* ==================================================================================================================== */ + /* Delete Directory */ + /* ==================================================================================================================== */ + + /* Delete dir succeeds. */ + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/tmp_for_delete/"))); + TEST_R_TRY(fs::DeleteDirectory(FORMAT_PATH("./test_dir/tmp_for_delete/"))); + + /* Delete on invalid path -> fs::ResultPathNotFound(). */ + TEST_R_EXPECT(fs::DeleteDirectory(FORMAT_PATH("./test_dir/invalid/")), fs::ResultPathNotFound); + + /* Delete on file -> fs::ResultPathNotFound(). */ + TEST_R_EXPECT(fs::DeleteDirectory(FORMAT_PATH("./test_dir/test_rand.bin")), fs::ResultPathNotFound); + + /* Delete on non-empty directory -> fs::ResultDirectoryNotEmpty(). */ + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/tmp_for_delete/"))); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/tmp_for_delete/tmp_for_delete.bin"), sizeof(g_buffer))); + TEST_R_EXPECT(fs::DeleteDirectory(FORMAT_PATH("./test_dir/tmp_for_delete/")), fs::ResultDirectoryNotEmpty); + TEST_R_TRY(fs::DeleteFile(FORMAT_PATH("./test_dir/tmp_for_delete/tmp_for_delete.bin"))); + TEST_R_TRY(fs::DeleteDirectory(FORMAT_PATH("./test_dir/tmp_for_delete/"))); + + /* ==================================================================================================================== */ + /* Delete Directory Recursively */ + /* ==================================================================================================================== */ + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/"))); + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/"))); + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/"))); + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/"))); + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/"))); + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/"))); + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/"))); + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/"))); + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/"))); + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/0/"))); + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/"))); + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/"))); + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/"))); + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/b/"))); + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/b/0/"))); + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/b/0/0/"))); + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/b/0/0/0/"))); + + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/x.bin"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/x.bin"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/x.bin"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/x.bin"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/x.bin"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/x.bin"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/x.bin"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/x.bin"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/x.bin"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/0/x.bin"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/0/y.bin"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/0/z.bin"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/x.bin"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/x.bin"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/x.bin"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/b/x.bin"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/b/0/x.bin"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/b/0/0/x.bin"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/b/0/0/0/x.bin"), 0)); + + TEST_R_TRY(fs::DeleteDirectoryRecursively(FORMAT_PATH("./test_dir/0/"))); + + /* Verify the test directory still exists and is a directory. */ + TEST_R_TRY(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/"))); + AMS_ABORT_UNLESS(entry_type == fs::DirectoryEntryType_Directory); + + /* Verify the recursive directory doesn't. */ + TEST_R_EXPECT(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/0/")), fs::ResultPathNotFound); + + /* Delete recursive on invalid path -> fs::ResultPathNotFound(). */ + TEST_R_EXPECT(fs::DeleteDirectoryRecursively(FORMAT_PATH("./test_dir/invalid/")), fs::ResultPathNotFound); + + /* Delete recursive on file -> fs::ResultPathNotFound(). */ + TEST_R_EXPECT(fs::DeleteDirectoryRecursively(FORMAT_PATH("./test_dir/test_rand.bin")), fs::ResultPathNotFound); + + /* ==================================================================================================================== */ + /* Clean Directory Recursively */ + /* ==================================================================================================================== */ + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/"))); + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/"))); + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/"))); + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/"))); + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/"))); + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/"))); + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/"))); + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/"))); + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/"))); + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/0/"))); + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/"))); + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/"))); + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/"))); + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/b/"))); + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/b/0/"))); + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/b/0/0/"))); + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/b/0/0/0/"))); + + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/x.bin"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/x.bin"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/x.bin"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/x.bin"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/x.bin"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/x.bin"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/x.bin"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/x.bin"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/x.bin"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/0/x.bin"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/0/y.bin"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/0/z.bin"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/x.bin"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/x.bin"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/x.bin"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/b/x.bin"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/b/0/x.bin"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/b/0/0/x.bin"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/b/0/0/0/x.bin"), 0)); + + TEST_R_TRY(fs::CleanDirectoryRecursively(FORMAT_PATH("./test_dir/0/"))); + + /* Verify the recursive directory still exists and is a directory. */ + TEST_R_TRY(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/0/"))); + AMS_ABORT_UNLESS(entry_type == fs::DirectoryEntryType_Directory); + + /* Delete the recursive directory. */ + TEST_R_TRY(fs::DeleteDirectory(FORMAT_PATH("./test_dir/0/"))); + + /* Clean recursive on invalid path -> fs::ResultPathNotFound(). */ + TEST_R_EXPECT(fs::CleanDirectoryRecursively(FORMAT_PATH("./test_dir/invalid/")), fs::ResultPathNotFound); + + /* Clean recursive on file -> fs::ResultPathNotFound(). */ + TEST_R_EXPECT(fs::CleanDirectoryRecursively(FORMAT_PATH("./test_dir/test_rand.bin")), fs::ResultPathNotFound); + + /* ==================================================================================================================== */ + /* Rename File */ + /* ==================================================================================================================== */ + + /* Rename succeeds. */ + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/a.bin"), 1_KB)); + TEST_R_TRY(fs::RenameFile(FORMAT_PATH("./test_dir/a.bin"), FORMAT_PATH2("./test_dir/b.bin"))); + + TEST_R_EXPECT(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/a.bin")), fs::ResultPathNotFound); + TEST_R_TRY(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/b.bin"))); + AMS_ABORT_UNLESS(entry_type == fs::DirectoryEntryType_File); + + /* Rename non-existing -> fs::ResultPathNotFound */ + TEST_R_EXPECT(fs::RenameFile(FORMAT_PATH("./test_dir/invalid"), FORMAT_PATH2("./test_dir/invalid2")), fs::ResultPathNotFound); + + /* Rename valid -> already existing gives fs::ResultPathAlreadyExists */ + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/a.bin"), 1_KB)); + TEST_R_EXPECT(fs::RenameFile(FORMAT_PATH("./test_dir/a.bin"), FORMAT_PATH2("./test_dir/b.bin")), fs::ResultPathAlreadyExists); + + /* Rename valid -> directory gives fs::ResultPathAlreadyExists */ + TEST_R_EXPECT(fs::RenameFile(FORMAT_PATH("./test_dir/a.bin"), FORMAT_PATH2("./test_dir/test_subdir/")), fs::ResultPathAlreadyExists); + + /* Rename directory -> fs::ResultPathNotFound */ + TEST_R_EXPECT(fs::RenameFile(FORMAT_PATH("./test_dir/test_subdir/"), FORMAT_PATH2("./test_dir/c.bin")), fs::ResultPathNotFound); + + /* Invalid doesn't affect the file/dir. */ + TEST_R_TRY(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/a.bin"))); + AMS_ABORT_UNLESS(entry_type == fs::DirectoryEntryType_File); + TEST_R_TRY(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/test_subdir/"))); + AMS_ABORT_UNLESS(entry_type == fs::DirectoryEntryType_Directory); + + /* ==================================================================================================================== */ + /* Rename Directory */ + /* ==================================================================================================================== */ + + /* Rename succeeds. */ + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/dir_a/"))); + TEST_R_TRY(fs::RenameDirectory(FORMAT_PATH("./test_dir/dir_a/"), FORMAT_PATH2("./test_dir/dir_b/"))); + + TEST_R_EXPECT(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/dir_a/")), fs::ResultPathNotFound); + TEST_R_TRY(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/dir_b/"))); + AMS_ABORT_UNLESS(entry_type == fs::DirectoryEntryType_Directory); + + /* Rename non-existing -> fs::ResultPathNotFound */ + TEST_R_EXPECT(fs::RenameDirectory(FORMAT_PATH("./test_dir/invalid"), FORMAT_PATH2("./test_dir/invalid2")), fs::ResultPathNotFound); + + /* Rename valid -> already existing gives fs::ResultPathAlreadyExists */ + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/dir_a/"))); + TEST_R_EXPECT(fs::RenameDirectory(FORMAT_PATH("./test_dir/dir_a/"), FORMAT_PATH2("./test_dir/dir_b/")), fs::ResultPathAlreadyExists); + + /* Rename valid -> file gives fs::ResultPathAlreadyExists */ + TEST_R_EXPECT(fs::RenameDirectory(FORMAT_PATH("./test_dir/dir_a/"), FORMAT_PATH2("./test_dir/a.bin")), fs::ResultPathAlreadyExists); + + /* Rename file -> fs::ResultPathNotFound */ + TEST_R_EXPECT(fs::RenameDirectory(FORMAT_PATH("./test_dir/a.bin"), FORMAT_PATH2("./test_dir/dir_c/")), fs::ResultPathNotFound); + + /* Invalid doesn't affect the file/dir. */ + TEST_R_TRY(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/a.bin"))); + AMS_ABORT_UNLESS(entry_type == fs::DirectoryEntryType_File); + TEST_R_TRY(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/dir_a/"))); + AMS_ABORT_UNLESS(entry_type == fs::DirectoryEntryType_Directory); + + /* ==================================================================================================================== */ + /* Get Entry Type */ + /* ==================================================================================================================== */ + + /* File -> file. */ + TEST_R_TRY(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/a.bin"))); + AMS_ABORT_UNLESS(entry_type == fs::DirectoryEntryType_File); + + /* Dir -> dir */ + TEST_R_TRY(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/dir_a/"))); + AMS_ABORT_UNLESS(entry_type == fs::DirectoryEntryType_Directory); + + /* Invalid -> fs::ResultPathNotFound */ + TEST_R_EXPECT(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/invalid")), fs::ResultPathNotFound); + + /* ==================================================================================================================== */ + /* Get Free Space Size */ + /* ==================================================================================================================== */ + + s64 free_size = 0; + TEST_R_TRY(fs::GetFreeSpaceSize(std::addressof(free_size), FORMAT_PATH("./test_dir/"))); + AMS_ABORT_UNLESS(free_size > 0); + + /* ==================================================================================================================== */ + /* Get Total Space Size */ + /* ==================================================================================================================== */ + + s64 total_size = 0; + TEST_R_TRY(fs::GetTotalSpaceSize(std::addressof(total_size), FORMAT_PATH("./test_dir/"))); + AMS_ABORT_UNLESS(total_size >= free_size); + + /* ==================================================================================================================== */ + /* Get File Time Stamp */ + /* ==================================================================================================================== */ + + /* Get timestamp succeeds. */ + fs::FileTimeStamp timestamp; + TEST_R_TRY(fs::GetFileTimeStamp(std::addressof(timestamp), FORMAT_PATH("./test_dir/a.bin"))); + AMS_ABORT_UNLESS(timestamp.create.value > 0); + AMS_ABORT_UNLESS(timestamp.access.value > 0); + AMS_ABORT_UNLESS(timestamp.modify.value > 0); + AMS_ABORT_UNLESS(!timestamp.is_local_time); + + /* Invalid -> fs::ResultPathNotFound */ + TEST_R_EXPECT(fs::GetFileTimeStamp(std::addressof(timestamp), FORMAT_PATH("./test_dir/invalid")), fs::ResultPathNotFound); + + /* Directory -> fs::ResultPathNotFound */ + TEST_R_EXPECT(fs::GetFileTimeStamp(std::addressof(timestamp), FORMAT_PATH("./test_dir/dir_a/")), fs::ResultPathNotFound); + + /* ==================================================================================================================== */ + /* Query Entry */ + /* ==================================================================================================================== */ + + TEST_R_EXPECT(fs::SetConcatenationFileAttribute(FORMAT_PATH("./test_dir/")), fs::ResultUnsupportedOperation); + + /* ==================================================================================================================== */ + /* Open File */ + /* ==================================================================================================================== */ + + /* Open valid succeeds. */ + fs::FileHandle file; + TEST_R_TRY(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/a.bin"), fs::OpenMode_ReadWrite | fs::OpenMode_AllowAppend)); + fs::CloseFile(file); + + /* Open invalid -> path not found. */ + TEST_R_EXPECT(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/invalid"), fs::OpenMode_ReadWrite | fs::OpenMode_AllowAppend), fs::ResultPathNotFound); + + /* Open directory -> path not found. */ + TEST_R_EXPECT(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/dir_a/"), fs::OpenMode_ReadWrite | fs::OpenMode_AllowAppend), fs::ResultPathNotFound); + + /* Open with invalid mode -> fs::ResultInvalidOpenMode */ + TEST_R_EXPECT(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/a.bin"), static_cast(~0u)), fs::ResultInvalidOpenMode); + + /* Read only file is read only. */ + { + s64 file_size; + u8 buf[1_KB]; + + { + TEST_R_TRY(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/a.bin"), fs::OpenMode_Read)); + ON_SCOPE_EXIT { fs::CloseFile(file); }; + + /* File size matches create. */ + TEST_R_TRY(fs::GetFileSize(std::addressof(file_size), file)); + AMS_ABORT_UNLESS(file_size == 1_KB); + + /* Read succeeds. */ + TEST_R_TRY(fs::ReadFile(file, 0, buf, sizeof(buf))); + + /* Completely empty read ok. */ + TEST_R_TRY(fs::ReadFile(file, 0, nullptr, 0)); + + /* Flush succeeds. */ + TEST_R_TRY(fs::FlushFile(file)); + } + + /* Incorrect arguments return incorrect results. */ + { + TEST_R_TRY(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/a.bin"), fs::OpenMode_Read)); + ON_SCOPE_EXIT { fs::CloseFile(file); }; + + TEST_R_EXPECT(fs::ReadFile(file, -1, buf, sizeof(buf)), fs::ResultOutOfRange); + } + { + TEST_R_TRY(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/a.bin"), fs::OpenMode_Read)); + ON_SCOPE_EXIT { fs::CloseFile(file); }; + + TEST_R_EXPECT(fs::ReadFile(file, 0, buf, -1), fs::ResultOutOfRange); + } + { + TEST_R_TRY(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/a.bin"), fs::OpenMode_Read)); + ON_SCOPE_EXIT { fs::CloseFile(file); }; + + TEST_R_EXPECT(fs::ReadFile(file, 0, nullptr, sizeof(buf)), fs::ResultNullptrArgument); + } + + /* Write fails. */ + { + TEST_R_TRY(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/a.bin"), fs::OpenMode_Read)); + ON_SCOPE_EXIT { fs::CloseFile(file); }; + + TEST_R_EXPECT(fs::WriteFile(file, 0, g_buffer, sizeof(g_buffer), fs::WriteOption::None), fs::ResultWriteNotPermitted); + } + + /* Set size fails. */ + { + TEST_R_TRY(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/a.bin"), fs::OpenMode_Read)); + ON_SCOPE_EXIT { fs::CloseFile(file); }; + + TEST_R_EXPECT(fs::SetFileSize(file, 2_KB), fs::ResultWriteNotPermitted); + } + + /* File size unchanged by bad set size. */ + { + TEST_R_TRY(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/a.bin"), fs::OpenMode_Read)); + ON_SCOPE_EXIT { fs::CloseFile(file); }; + + TEST_R_TRY(fs::GetFileSize(std::addressof(file_size), file)); + AMS_ABORT_UNLESS(file_size == 1_KB); + } + } + + /* Write only file is writable but not readable. */ + { + s64 file_size; + u8 buf[1_KB]; + + { + TEST_R_TRY(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/a.bin"), fs::OpenMode_Write)); + ON_SCOPE_EXIT { fs::CloseFile(file); }; + + /* Write succeeds. */ + std::memset(buf, 0xcc, sizeof(buf)); + TEST_R_TRY(fs::WriteFile(file, 0, buf, sizeof(buf), fs::WriteOption::None)); + + /* Flush succeeds. */ + TEST_R_TRY(fs::FlushFile(file)); + + /* Write with flush succeeds. */ + TEST_R_TRY(fs::WriteFile(file, 0, buf, sizeof(buf), fs::WriteOption::Flush)); + + /* Get size succeeds. */ + TEST_R_TRY(fs::GetFileSize(std::addressof(file_size), file)); + AMS_ABORT_UNLESS(file_size == 1_KB); + + /* Set size succeeds. */ + TEST_R_TRY(fs::SetFileSize(file, 2_KB)); + TEST_R_TRY(fs::GetFileSize(std::addressof(file_size), file)); + AMS_ABORT_UNLESS(file_size == 2_KB); + + /* Write at updated size works. */ + TEST_R_TRY(fs::WriteFile(file, 1_KB, buf, sizeof(buf), fs::WriteOption::Flush)); + + /* Truncate down succeeds. */ + TEST_R_TRY(fs::SetFileSize(file, 1_KB)); + TEST_R_TRY(fs::GetFileSize(std::addressof(file_size), file)); + AMS_ABORT_UNLESS(file_size == 1_KB); + + /* Completely empty write ok. */ + TEST_R_TRY(fs::WriteFile(file, 0, nullptr, 0, fs::WriteOption::Flush)); + } + + /* Incorrect arguments return incorrect results. */ + { + TEST_R_TRY(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/a.bin"), fs::OpenMode_Write)); + ON_SCOPE_EXIT { fs::CloseFile(file); }; + + TEST_R_EXPECT(fs::WriteFile(file, -1, buf, sizeof(buf), fs::WriteOption::None), fs::ResultOutOfRange); + } + { + TEST_R_TRY(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/a.bin"), fs::OpenMode_Write)); + ON_SCOPE_EXIT { fs::CloseFile(file); }; + + TEST_R_EXPECT(fs::WriteFile(file, 0, buf, -1, fs::WriteOption::None), fs::ResultOutOfRange); + } + { + TEST_R_TRY(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/a.bin"), fs::OpenMode_Write)); + ON_SCOPE_EXIT { fs::CloseFile(file); }; + + TEST_R_EXPECT(fs::WriteFile(file, 0, nullptr, sizeof(buf), fs::WriteOption::None), fs::ResultNullptrArgument); + } + { + TEST_R_TRY(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/a.bin"), fs::OpenMode_Write)); + ON_SCOPE_EXIT { fs::CloseFile(file); }; + + TEST_R_EXPECT(fs::WriteFile(file, 1_KB, buf, sizeof(buf), fs::WriteOption::None), fs::ResultFileExtensionWithoutOpenModeAllowAppend); + } + + /* Read fails. */ + { + TEST_R_TRY(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/a.bin"), fs::OpenMode_Write)); + ON_SCOPE_EXIT { fs::CloseFile(file); }; + + TEST_R_EXPECT(fs::ReadFile(file, 0, buf, sizeof(buf)), fs::ResultReadNotPermitted); + } + + /* Appending works with OpenMode_AllowAppend. */ + { + TEST_R_TRY(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/a.bin"), fs::OpenMode_Write | fs::OpenMode_AllowAppend)); + ON_SCOPE_EXIT { fs::CloseFile(file); }; + + TEST_R_TRY(fs::GetFileSize(std::addressof(file_size), file)); + AMS_ABORT_UNLESS(file_size == 1_KB); + + for (size_t i = 0; i < sizeof(buf); ++i) { + buf[i] = static_cast(i); + } + TEST_R_TRY(fs::WriteFile(file, 1_KB, buf, sizeof(buf), fs::WriteOption::Flush)); + + TEST_R_TRY(fs::GetFileSize(std::addressof(file_size), file)); + AMS_ABORT_UNLESS(file_size == 2_KB); + } + + /* Data is persistent. */ + { + TEST_R_TRY(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/a.bin"), fs::OpenMode_ReadWrite)); + ON_SCOPE_EXIT { fs::CloseFile(file); }; + + TEST_R_TRY(fs::ReadFile(file, 0, buf, sizeof(buf))); + + for (size_t i = 0; i < 1_KB; ++i) { + AMS_ABORT_UNLESS(buf[i] == 0xCC); + } + + TEST_R_TRY(fs::ReadFile(file, 1_KB, buf, sizeof(buf))); + + for (size_t i = 0; i < 1_KB; ++i) { + AMS_ABORT_UNLESS(buf[i] == static_cast(i)); + } + + TEST_R_TRY(fs::WriteFile(file, 0, buf, sizeof(buf), fs::WriteOption::Flush)); + + TEST_R_TRY(fs::SetFileSize(file, 1_KB)); + + TEST_R_TRY(fs::GetFileSize(std::addressof(file_size), file)); + AMS_ABORT_UNLESS(file_size == 1_KB); + + TEST_R_TRY(fs::ReadFile(file, 0, buf, sizeof(buf))); + + for (size_t i = 0; i < 1_KB; ++i) { + AMS_ABORT_UNLESS(buf[i] == static_cast(i)); + } + } + } + + /* More involved file data test using random buffer. */ + { + u8 buf[1_KB]; + /* Write random data. */ + { + TEST_R_TRY(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/test_rand.bin"), fs::OpenMode_Write)); + ON_SCOPE_EXIT { fs::CloseFile(file); }; + + /* Get a bunch of random data. */ + os::GenerateRandomBytes(g_buffer, sizeof(g_buffer)); + + /* Write it to disk. */ + TEST_R_TRY(fs::WriteFile(file, 0, g_buffer, sizeof(g_buffer), fs::WriteOption::None)); + TEST_R_TRY(fs::FlushFile(file)); + } + + /* Read and verify random data. */ + { + TEST_R_TRY(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/test_rand.bin"), fs::OpenMode_Read)); + ON_SCOPE_EXIT { fs::CloseFile(file); }; + + u32 ofs; + for (size_t i = 0; i < 1000; ++i) { + os::GenerateRandomBytes(std::addressof(ofs), sizeof(ofs)); + ofs %= (sizeof(g_buffer) - sizeof(buf)); + + TEST_R_TRY(fs::ReadFile(file, ofs, buf, sizeof(buf))); + AMS_ABORT_UNLESS(std::memcmp(buf, g_buffer + ofs, sizeof(buf)) == 0); + } + } + } + + /* ==================================================================================================================== */ + /* Open Directory */ + /* ==================================================================================================================== */ + fs::DirectoryHandle dir; + TEST_R_TRY(fs::OpenDirectory(std::addressof(dir), FORMAT_PATH("./test_dir/dir_a/"), fs::OpenDirectoryMode_All | fs::OpenDirectoryMode_NotRequireFileSize)); + fs::CloseDirectory(dir); + + /* Open invalid -> path not found. */ + TEST_R_EXPECT(fs::OpenDirectory(std::addressof(dir), FORMAT_PATH("./test_dir/invalid"), fs::OpenDirectoryMode_All | fs::OpenDirectoryMode_NotRequireFileSize), fs::ResultPathNotFound); + + /* Open file -> path not found. */ + TEST_R_EXPECT(fs::OpenDirectory(std::addressof(dir), FORMAT_PATH("./test_dir/a.bin"), fs::OpenDirectoryMode_All | fs::OpenDirectoryMode_NotRequireFileSize), fs::ResultPathNotFound); + + /* Open with invalid mode -> fs::ResultInvalidOpenMode */ + TEST_R_EXPECT(fs::OpenDirectory(std::addressof(dir), FORMAT_PATH("./test_dir/dir_a/"), static_cast(~0u)), fs::ResultInvalidOpenMode); + + /* Populate test directory with three files and two dirs. */ + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/dir_a/f0"), 0)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/dir_a/f1"), 1_KB)); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/dir_a/f2"), 0x42069)); + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/dir_a/d0"))); + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/dir_a/d1"))); + TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/dir_a/d0/file"), 0)); + TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/dir_a/d0/dir/"))); + + /* Directory tests. */ + { + bool seen_file[3]; + bool seen_dir[2]; + + constexpr s64 NumFiles = util::size(seen_file); + constexpr s64 NumDirs = util::size(seen_dir); + constexpr s64 NumAll = NumFiles + NumDirs; + + fs::DirectoryEntry entries[2 * NumAll]; + s64 entry_count; + + auto ResetSeenFiles = [&] () { for (auto &b : seen_file) { b = false; } }; + auto ResetSeenDirs = [&] () { for (auto &b : seen_dir) { b = false; } }; + auto ResetSeenAll = [&] () { ResetSeenFiles(); ResetSeenDirs(); }; + + auto CheckSeenFiles = [&] () { for (const auto b : seen_file) { AMS_ABORT_UNLESS(b); } }; + auto CheckSeenDirs = [&] () { for (const auto b : seen_dir) { AMS_ABORT_UNLESS(b); } }; + auto CheckSeenAll = [&] () { CheckSeenFiles(); CheckSeenDirs(); }; + + auto CheckNotSeenFiles = [&] () { for (const auto b : seen_file) { AMS_ABORT_UNLESS(!b); } }; + auto CheckNotSeenDirs = [&] () { for (const auto b : seen_dir) { AMS_ABORT_UNLESS(!b); } }; + + auto CheckDirectoryEntry = [&] (const fs::DirectoryEntry &entry) { + /* Check name. */ + AMS_ABORT_UNLESS(entry.name[0] == 'f' || entry.name[0] == 'd'); + AMS_ABORT_UNLESS('0' <= entry.name[1] && entry.name[1] <= '9'); + AMS_ABORT_UNLESS(entry.name[2] == 0); + + /* Check type. */ + if (entry.name[0] == 'f') { + AMS_ABORT_UNLESS(entry.type == fs::DirectoryEntryType_File); + + /* If file, check size. */ + switch (entry.name[1]) { + case '0': AMS_ABORT_UNLESS(entry.file_size == 0); break; + case '1': AMS_ABORT_UNLESS(entry.file_size == 1_KB); break; + case '2': AMS_ABORT_UNLESS(entry.file_size == 0x42069); break; + } + + AMS_ABORT_UNLESS(!seen_file[(entry.name[1] - '0')]); + seen_file[(entry.name[1] - '0')] = true; + } else { + AMS_ABORT_UNLESS(entry.type == fs::DirectoryEntryType_Directory); + + AMS_ABORT_UNLESS(!seen_dir[(entry.name[1] - '0')]); + seen_dir[(entry.name[1] - '0')] = true; + } + }; + + /* Get EntryCount is correct. */ + { + /* All returns all entries. */ + { + TEST_R_TRY(fs::OpenDirectory(std::addressof(dir), FORMAT_PATH("./test_dir/dir_a/"), fs::OpenDirectoryMode_All)); + ON_SCOPE_EXIT { fs::CloseDirectory(dir); }; + + TEST_R_TRY(fs::GetDirectoryEntryCount(std::addressof(entry_count), dir)); + AMS_ABORT_UNLESS(entry_count == NumAll); + } + + /* File returns only files, and does not count things in subdirectories. */ + { + TEST_R_TRY(fs::OpenDirectory(std::addressof(dir), FORMAT_PATH("./test_dir/dir_a/"), fs::OpenDirectoryMode_File)); + ON_SCOPE_EXIT { fs::CloseDirectory(dir); }; + + TEST_R_TRY(fs::GetDirectoryEntryCount(std::addressof(entry_count), dir)); + AMS_ABORT_UNLESS(entry_count == NumFiles); + } + + /* Dir returns only dirs, and does not count things in subdirectories. */ + { + TEST_R_TRY(fs::OpenDirectory(std::addressof(dir), FORMAT_PATH("./test_dir/dir_a/"), fs::OpenDirectoryMode_Directory)); + ON_SCOPE_EXIT { fs::CloseDirectory(dir); }; + + TEST_R_TRY(fs::GetDirectoryEntryCount(std::addressof(entry_count), dir)); + AMS_ABORT_UNLESS(entry_count == NumDirs); + } + } + + /* Read is correct, N at a time. */ + for (s64 at_a_time = 1; at_a_time <= 2 * NumAll; ++at_a_time) { + /* All returns all entries. */ + { + ResetSeenAll(); + + TEST_R_TRY(fs::OpenDirectory(std::addressof(dir), FORMAT_PATH("./test_dir/dir_a/"), fs::OpenDirectoryMode_All)); + ON_SCOPE_EXIT { fs::CloseDirectory(dir); }; + + TEST_R_TRY(fs::GetDirectoryEntryCount(std::addressof(entry_count), dir)); + AMS_ABORT_UNLESS(entry_count == NumAll); + + s64 remaining = entry_count; + while (remaining > 0) { + s64 cur; + TEST_R_TRY(fs::ReadDirectory(std::addressof(cur), entries, dir, at_a_time)); + AMS_ABORT_UNLESS(cur <= remaining); + AMS_ABORT_UNLESS(cur == std::min(at_a_time, remaining)); + + for (s64 i = 0; i < cur; ++i) { + CheckDirectoryEntry(entries[i]); + } + + remaining -= cur; + } + + CheckSeenAll(); + + /* Read succeeds at end of dir. */ + s64 cur; + TEST_R_TRY(fs::ReadDirectory(std::addressof(cur), entries, dir, at_a_time)); + AMS_ABORT_UNLESS(cur == 0); + + /* Get entry count still shows correct value. */ + s64 entry_count2; + TEST_R_TRY(fs::GetDirectoryEntryCount(std::addressof(entry_count2), dir)); + AMS_ABORT_UNLESS(entry_count2 == entry_count); + } + + /* File returns only files. */ + { + ResetSeenAll(); + + TEST_R_TRY(fs::OpenDirectory(std::addressof(dir), FORMAT_PATH("./test_dir/dir_a/"), fs::OpenDirectoryMode_File)); + ON_SCOPE_EXIT { fs::CloseDirectory(dir); }; + + TEST_R_TRY(fs::GetDirectoryEntryCount(std::addressof(entry_count), dir)); + AMS_ABORT_UNLESS(entry_count == NumFiles); + + s64 remaining = entry_count; + while (remaining > 0) { + s64 cur; + TEST_R_TRY(fs::ReadDirectory(std::addressof(cur), entries, dir, at_a_time)); + AMS_ABORT_UNLESS(cur <= remaining); + AMS_ABORT_UNLESS(cur == std::min(at_a_time, remaining)); + + for (s64 i = 0; i < cur; ++i) { + CheckDirectoryEntry(entries[i]); + } + + remaining -= cur; + } + + CheckSeenFiles(); + CheckNotSeenDirs(); + + /* Read succeeds at end of dir. */ + s64 cur; + TEST_R_TRY(fs::ReadDirectory(std::addressof(cur), entries, dir, at_a_time)); + AMS_ABORT_UNLESS(cur == 0); + + /* Get entry count still shows correct value. */ + s64 entry_count2; + TEST_R_TRY(fs::GetDirectoryEntryCount(std::addressof(entry_count2), dir)); + AMS_ABORT_UNLESS(entry_count2 == entry_count); + } + + /* Directory returns only dirs. */ + { + ResetSeenAll(); + + TEST_R_TRY(fs::OpenDirectory(std::addressof(dir), FORMAT_PATH("./test_dir/dir_a/"), fs::OpenDirectoryMode_Directory)); + ON_SCOPE_EXIT { fs::CloseDirectory(dir); }; + + TEST_R_TRY(fs::GetDirectoryEntryCount(std::addressof(entry_count), dir)); + AMS_ABORT_UNLESS(entry_count == NumDirs); + + s64 remaining = entry_count; + while (remaining > 0) { + s64 cur; + TEST_R_TRY(fs::ReadDirectory(std::addressof(cur), entries, dir, at_a_time)); + AMS_ABORT_UNLESS(cur <= remaining); + AMS_ABORT_UNLESS(cur == std::min(at_a_time, remaining)); + + for (s64 i = 0; i < cur; ++i) { + CheckDirectoryEntry(entries[i]); + } + + remaining -= cur; + } + + CheckSeenDirs(); + CheckNotSeenFiles(); + + /* Read succeeds at end of dir. */ + s64 cur; + TEST_R_TRY(fs::ReadDirectory(std::addressof(cur), entries, dir, at_a_time)); + AMS_ABORT_UNLESS(cur == 0); + + /* Get entry count still shows correct value. */ + s64 entry_count2; + TEST_R_TRY(fs::GetDirectoryEntryCount(std::addressof(entry_count2), dir)); + AMS_ABORT_UNLESS(entry_count2 == entry_count); + } + } + } + + /* ==================================================================================================================== */ + /* Cleanup */ + /* ==================================================================================================================== */ + TEST_R_TRY(fs::DeleteDirectoryRecursively(FORMAT_PATH("./test_dir/"))); + } + + } + + + void Main() { + fs::SetEnabledAutoAbort(false); + + printf("Doing FS test!\n"); + DoFsTests(); + printf("All tests completed!\n"); + } + +} \ No newline at end of file diff --git a/tests/TestFs/unit_test.mk b/tests/TestFs/unit_test.mk new file mode 100644 index 000000000..508777b98 --- /dev/null +++ b/tests/TestFs/unit_test.mk @@ -0,0 +1,155 @@ +#--------------------------------------------------------------------------------- +# pull in common stratosphere sysmodule configuration +#--------------------------------------------------------------------------------- +THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) +include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk + +ifeq ($(ATMOSPHERE_BOARD),nx-hac-001) +export BOARD_TARGET_SUFFIX := .kip +else ifeq ($(ATMOSPHERE_BOARD),generic_windows) +export BOARD_TARGET_SUFFIX := .exe +else ifeq ($(ATMOSPHERE_BOARD),generic_linux) +export BOARD_TARGET_SUFFIX := +else ifeq ($(ATMOSPHERE_BOARD),generic_macos) +export BOARD_TARGET_SUFFIX := +else +export BOARD_TARGET_SUFFIX := $(TARGET) +endif + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(__RECURSIVE__),1) +#--------------------------------------------------------------------------------- + +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) +CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) +SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) + +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + $(foreach dir,$(AMS_LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) $(foreach dir,$(AMS_LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) + +export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) + +ifeq ($(strip $(CONFIG_JSON)),) + jsons := $(wildcard *.json) + ifneq (,$(findstring $(TARGET).json,$(jsons))) + export APP_JSON := $(TOPDIR)/$(TARGET).json + else + ifneq (,$(findstring config.json,$(jsons))) + export APP_JSON := $(TOPDIR)/config.json + endif + endif +else + export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) +endif + +.PHONY: clean all check_lib + +#--------------------------------------------------------------------------------- +all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURDIR)/$(ATMOSPHERE_OUT_DIR)/$(TARGET) \ + DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ + --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ + -f $(THIS_MAKEFILE) + +$(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a: check_lib + @$(SILENTCMD)echo "Checked library." + +check_lib: + @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/libstratosphere.mk + +$(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): + @[ -d $@ ] || mkdir -p $@ + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(BOARD_TARGET) $(TARGET).elf + @for i in $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR); do [ -d $$i ] && rmdir --ignore-fail-on-non-empty $$i || true; done + + +#--------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +all : $(OUTPUT)$(BOARD_TARGET_SUFFIX) + +%.kip : %.elf + +%.nsp : %.nso %.npdm + +%.nso: %.elf + + +#--------------------------------------------------------------------------------- +$(OUTPUT).elf: $(OFILES) $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + @echo linking $(notdir $@) + $(SILENTCMD)$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ + $(SILENTCMD)$(NM) -CSn $@ > $(notdir $(OUTPUT).lst) + +$(OUTPUT).exe: $(OFILES) $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + @echo linking $(notdir $@) + $(SILENTCMD)$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ + $(SILENTCMD)$(NM) -CSn $@ > $(notdir $*.lst) + + +ifeq ($(strip $(BOARD_TARGET_SUFFIX)),) +$(OUTPUT): $(OFILES) $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/$(ATMOSPHERE_LIBRARY_DIR)/libstratosphere.a + @echo linking $(notdir $@) + $(SILENTCMD)$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ + $(SILENTCMD)$(NM) -CSn $@ > $(notdir $@.lst) +endif + +%.npdm : %.npdm.json + @echo built ... $< $@ + @npdmtool $< $@ + @echo built ... $(notdir $@) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#---------------------------------------------------------------------------------------