diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..4b4dfad1e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,25 @@ +--- +name: Bug Report +about: Something doesn't work correctly in Atmosphère. + +--- + +## Bug Report + +### What's the issue you encountered? + +### How can the issue be reproduced? + +### Crash report? + +(If a crash report was created under /atmosphere/crash_reports/, please upload it to +[gist](https://gist.github.com/) and paste the link here.) + +### Environment? + +- What bootloader (fusee, hekate, etc) was Atmosphère launched by: +- Official release or unofficial build: +- Do you have additional kips you're loading: +- Additional info about your environment: + +### Additional context? diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..3b93d9d25 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,12 @@ +--- +name: Feature Request +about: You want to suggest a new feature for Atmosphère. + +--- + +## Feature Request + +### What feature are you suggesting? + +### Why would this feature be useful? + diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md new file mode 100644 index 000000000..6cc1915b9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/question.md @@ -0,0 +1,12 @@ +--- +name: Question +about: Please ask questions in the ReSwitched discord, instead of making issues. + +--- + +We would like to use GitHub to keep track of problems/feature requests. + +If you have a question, please join the ReSwitched discord for help. + +- Discord link: https://discordapp.com/invite/DThbZ7z + diff --git a/.gitignore b/.gitignore index e39d9f114..f55c55a62 100644 --- a/.gitignore +++ b/.gitignore @@ -61,6 +61,10 @@ Module.symvers Mkfile.old dkms.conf +# Distribution files +*.tgz +*.zip + .**/ # NOTE: make sure to make exceptions to this pattern when needed! diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..5f85b18b6 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "common/include/boost"] + path = common/include/boost + url = https://github.com/Atmosphere-NX/ext-boost.git diff --git a/Makefile b/Makefile index 014cb646c..c10b6eb7a 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,55 @@ -TOPTARGETS := all clean +TOPTARGETS := all clean dist +AMSREV := $(shell git rev-parse --short HEAD) +ifneq (, $(strip $(shell git status --porcelain 2>/dev/null))) + AMSREV := $(AMSREV)-dirty +endif -all: fusee -fusee: +all: fusee stratosphere exosphere thermosphere + +thermosphere: + $(MAKE) -C thermosphere all + +exosphere: thermosphere + $(MAKE) -C exosphere all + +stratosphere: exosphere + $(MAKE) -C stratosphere all + +fusee: exosphere stratosphere $(MAKE) -C $@ all clean: $(MAKE) -C fusee clean + rm -rf out + +dist: all + $(eval MAJORVER = $(shell grep '\ATMOSPHERE_RELEASE_VERSION_MAJOR\b' common/include/atmosphere/version.h \ + | tr -s [:blank:] \ + | cut -d' ' -f3)) + $(eval MINORVER = $(shell grep '\ATMOSPHERE_RELEASE_VERSION_MINOR\b' common/include/atmosphere/version.h \ + | tr -s [:blank:] \ + | cut -d' ' -f3)) + $(eval MICROVER = $(shell grep '\ATMOSPHERE_RELEASE_VERSION_MICRO\b' common/include/atmosphere/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 -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000036 + mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000032 + cp fusee/fusee-secondary/fusee-secondary.bin atmosphere-$(AMSVER)/fusee-secondary.bin + cp common/defaults/BCT.ini atmosphere-$(AMSVER)/BCT.ini + cp common/defaults/loader.ini atmosphere-$(AMSVER)/atmosphere/loader.ini + cp stratosphere/creport/creport.nsp atmosphere-$(AMSVER)/atmosphere/titles/0100000000000036/exefs.nsp + cp stratosphere/set_mitm/set_mitm.nsp atmosphere-$(AMSVER)/atmosphere/titles/0100000000000032/exefs.nsp + touch atmosphere-$(AMSVER)/atmosphere/titles/0100000000000032/boot2.flag + cd atmosphere-$(AMSVER); zip -r ../atmosphere-$(AMSVER).zip ./*; cd ../; + rm -r atmosphere-$(AMSVER) + mkdir out + mv atmosphere-$(AMSVER).zip out/atmosphere-$(AMSVER).zip + cp fusee/fusee-primary/fusee-primary.bin out/fusee-primary.bin + .PHONY: $(TOPTARGETS) fusee diff --git a/common/defaults/BCT.ini b/common/defaults/BCT.ini new file mode 100644 index 000000000..3a8600340 --- /dev/null +++ b/common/defaults/BCT.ini @@ -0,0 +1,5 @@ +BCT0 +[stage1] +stage2_path = fusee-secondary.bin +stage2_addr = 0xF0000000 +stage2_entrypoint = 0xF0000000 \ No newline at end of file diff --git a/common/defaults/loader.ini b/common/defaults/loader.ini new file mode 100644 index 000000000..1049ef9dd --- /dev/null +++ b/common/defaults/loader.ini @@ -0,0 +1,4 @@ +[config] +hbl_tid=010000000000100D +hbl_path=atmosphere/hbl.nsp +override_key=!R \ No newline at end of file diff --git a/exosphere/src/version.h b/common/include/atmosphere/version.h similarity index 76% rename from exosphere/src/version.h rename to common/include/atmosphere/version.h index 99200b843..9ab1693ad 100644 --- a/exosphere/src/version.h +++ b/common/include/atmosphere/version.h @@ -14,10 +14,11 @@ * along with this program. If not, see . */ -#ifndef EXOSPHERE_VERSION_H -#define EXOSPHERE_VERSION_H +#ifndef ATMOSPHERE_VERSION_H +#define ATMOSPHERE_VERSION_H -#define EXOSPHERE_RELEASE_VERSION_MAJOR 0 -#define EXOSPHERE_RELEASE_VERSION_MINOR 1 +#define ATMOSPHERE_RELEASE_VERSION_MAJOR 0 +#define ATMOSPHERE_RELEASE_VERSION_MINOR 7 +#define ATMOSPHERE_RELEASE_VERSION_MICRO 3 #endif \ No newline at end of file diff --git a/common/include/boost b/common/include/boost new file mode 160000 index 000000000..fc6429e46 --- /dev/null +++ b/common/include/boost @@ -0,0 +1 @@ +Subproject commit fc6429e46398e16178b828a3a20e1bee9c56443d diff --git a/docs/building.md b/docs/building.md new file mode 100644 index 000000000..47d230b8a --- /dev/null +++ b/docs/building.md @@ -0,0 +1,6 @@ +# Building Atmosphère +The process for building Atmosphère is similar to building Fusée Gelée payloads and other Switch apps. + +In order to build Atmosphère you must have devkitARM and devkitA64 installed on your computer. You can find instructions on how to install and setup devkitARM and devkitA64 on various OSes [here](https://devkitpro.org/wiki/Getting_Started). + +Once you have finished installing devkitARM and devkitA64, simply clone the Atmosphère repo, change to it and run `make`. diff --git a/docs/changelog.md b/docs/changelog.md new file mode 100644 index 000000000..7aefb2474 --- /dev/null +++ b/docs/changelog.md @@ -0,0 +1,79 @@ +# Changelog +## 0.7.3 ++ Loader and fs.mitm now try to reload loader.ini before reading it. This allows for changing the override button combination/HBL title id at runtime. ++ Added a MitM between set:sys and qlaunch, used to override the system version string displayed in system settings. + + The displayed system version will now display ` (AMS ..)`. ++ General system stability improvements to enhance the user's experience. +## 0.7.2 ++ Fixed a bug in fs.mitm's LayeredFS read implementation that caused some games to crash when trying to read files. ++ Fixed a bug affecting 1.0.0 that caused games to crash with fatal error 2001-0106 on boot. ++ Improved filenames output by the make dist target. ++ General system stability improvements to enhance the user's experience. + +## 0.7.1 ++ Fixed a bug preventing consoles on 4.0.0-4.1.0 from going to sleep and waking back up. ++ Fixed a bug preventing consoles on < 4.0.0 from booting without specific KIPs on the SD card. ++ An API was added to Atmosphère's Service Manager for deferring acquisition of all handles for specific services until after early initialization is completed. ++ General system stability improvements to enhance the user's experience. + +## 0.7.0 ++ First official release of Atmosphère. ++ Supports the following featureset: + + Fusée, a custom bootloader. + + Supports loading/customizing of arbitrary KIPs from the SD card. + + Supports loading a custom kernel from the SD card ("/atmosphere/kernel.bin"). + + Supports compile-time defined kernel patches on a per-firmware basis. + + All patches at paths like /atmosphere/kip_patches//.ips will be applied to the relevant KIPs, allowing for easy distribution of patches supporting multiple versions. + + Both the IPS and IPS32 formats are supported. + + All patches at paths like /atmosphere/kernel_patches//.ips will be applied to the kernel, allowing for easy distribution of patches supporting multiple versions. + + Both the IPS and IPS32 formats are supported. + + Configurable by editing BCT.ini on the SD card. + + Atmosphère should also be launchable by the alternative hekate bootloader, for those who prefer it. + + Exosphère, a fully-featured custom secure monitor. + + Exosphere is a re-implementation of Nintendo's TrustZone firmware, fully replicating all of its features. + + In addition, it has been extended to provide information on current Atmosphere API version, for homebrew wishing to make use of it. + + Stratosphère, a set of custom system modules. This includes: + + A loader system module. + + Reimplementation of Nintendo's loader, fully replicating all original functionality. + + Configurable by editing /atmosphere/loader.ini + + First class support for the Homebrew Loader. + + An exefs NSP (default "/atmosphere/hbl.nsp") will be used in place of the victim title's exefs. + + By default, HBL will replace the album applet, but any application should also be supported. + + Extended to support arbitrary redirection of executable content to the SD card. + + Files will be preferentially loaded from /atmosphere/titles//exefs/, if present. + + Files present in the original exefs a user wants to mark as not present may be "stubbed" by creating a .stub file on the SD. + + If present, a PFS0 at /atmosphere/titles//exefs.nsp will fully replace the original exefs. + + Redirection is optionally toggleable by holding down certain buttons (by default, holding R disables redirection). + + Full support for patching NSO content is implemented. + + All patches at paths like /atmosphere/exefs_patches//.ips will be applied, allowing for easy distribution of patches supporting multiple firmware versions and/or titles. + + Both the IPS and IPS32 formats are supported. + + Extended to support launching content from loose executable files on the SD card, without requiring any official installation. + + This is done by specifying FsStorageId_None on launch. + + A service manager system module. + + Reimplementation of Nintendo's service manager, fully replicating all original functionality. + + Compile-time support for reintroduction of "smhax", allowing clients to optionally skip service access verification by skipping initialization. + + Extended to allow homebrew to acquire more handles to privileged services than Nintendo natively allows. + + Extended to add a new API for installing Man-In-The-Middle listeners for arbitrary services. + + API can additionally be used to safely detect whether a service has been registered in a non-blocking way with no side-effects. + + Full API documentation to come. + + A process manager system module. + + Reimplementation of Nintendo's process manager, fully replicating all original functionality. + + Extended to allow homebrew to acquire handles to arbitrary processes, and thus read/modify system memory without blocking execution. + + Extended to allow homebrew to retrieve information about system resource limits. + + Extended by embedding a full, extended implementation of Nintendo's boot2 system module. + + Title launch order has been optimized in order to grant access to the SD card faster. + + The error-collection system module is intentionally not launched, preventing many system telemetry error reports from being generated at all. + + Users may place their own custom sysmodules on the SD card and flag them for automatic boot2 launch by creating a /atmosphere/titles//boot2.flag file on their SD card. + + A custom fs.mitm system module. + + Uses Atmosphère's MitM API in order to provide an easy means for users to modify game content. + + Intercepts all FS commands sent by games, with special handling for commands used to mount RomFS/DLC content to enable easy creation and distribution of game/DLC mods. + + fs.mitm will parse the base RomFS image for a game, a RomFS image located at /atmosphere/titles/<title ID>/romfs.bin, and all loose files in /atmosphere/titles/<title ID>/romfs/, and merge them together into a single RomFS image. + + When merging, loose files are preferred to content in the SD card romfs.bin image, and files from the SD card image are preferred to those in the base image. + + Can additionally be used to intercept commands sent by arbitrary system titles (excepting those launched before SD card is active), by creating a /atmosphere/titles/<title ID>/fsmitm.flag file on the SD card. + + Can be forcibly disabled for any title, by creating a /atmosphere/titles/<title ID>/fsmitm_disable.flag file on the SD card. + + Redirection is optionally toggleable by holding down certain buttons (by default, holding R disables redirection). + + A custom crash report system module. + + Serves as a drop-in replacement for Nintendo's own creport system module. + + Generates detailed, human-readable reports on system crashes, saving to /atmosphere/crash_reports/<timestamp>_<title ID>.log. + + Because reports are not sent to the erpt sysmodule, this disables all crash report related telemetry. + + General system stability improvements to enhance the user's experience. diff --git a/docs/components/exosphere.md b/docs/components/exosphere.md new file mode 100644 index 000000000..b8a1103c8 --- /dev/null +++ b/docs/components/exosphere.md @@ -0,0 +1,10 @@ +# Exosphère +Exosphère is a reimplementation of Arm's TrustZone (TZ), also known as Secure Monitor (Secure_Monitor.bin). It has the highest privilege mode available on the Switch’s processor, and has access to everything on the console. + +Exosphère will potentially play a big role in Jamais Vu and Déja Vu, which are upcoming software exploits for the Switch, allowing one to launch Atmosphère on a Fusée-Gélee patched (ipatched) Switch console, and will also enable one to launch into CFW directly from the Switch itself without the use of any sort of external device, such as a computer or RCM jig, provided they are on a low enough system firmware. + +## TrustZone/Secure Monitor +TrustZone is responsible for all the cryptographic operations on the Switch. The idea behind the way it operates is that all the keys stay in the TrustZone, and userspace only gets "handles" to them. This would make sure that keydata never leaks and is kept secure. It also has a few more responsibilities, such as power management, providing a source of random numbers, and providing access to various pieces of information that are stored in the fuses. + +## Extensions +Exosphère currently only contains one extension, an SMC allowing homebrew to find which version of Atmosphère is currently running, in order to find out what extensions are allowed to be used. diff --git a/docs/components/fusee/BCT.md b/docs/components/fusee/BCT.md new file mode 100644 index 000000000..35c9f8246 --- /dev/null +++ b/docs/components/fusee/BCT.md @@ -0,0 +1,26 @@ +# BCT.ini +BCT.ini is the configuration file used by fusée-primary and fusée-secondary. It is read by fusee-primary.bin to setup and boot fusee-secondary.bin and is also read by fusee-secondary.bin to configure Exosphère or to specify the environment it should boot. + +## Configuration +This file is located at the root of your SD. +``` +BCT0 +[stage1] +stage2_path = fusee-secondary.bin +stage2_addr = 0xF0000000 +stage2_entrypoint = 0xF0000000 +``` +Add the following lines and replace the `X` according to the following list if you have trouble booting past the firmware version detection. +`target_firmware` is the OFW major version. +``` +[exosphere] +target_firmware = X +``` +``` +1.0.0 = 1 +2.X.X = 2 +3.X.X = 3 +4.X.X = 4 +5.X.X = 5 +6.0.0 = 6 +``` diff --git a/docs/components/fusee/fusee.md b/docs/components/fusee/fusee.md new file mode 100644 index 000000000..64c9575bd --- /dev/null +++ b/docs/components/fusee/fusee.md @@ -0,0 +1,20 @@ +# Fusée +Fusée (not to be confused with Fusée Gelée) is a custom bootloader needed to start Atmosphère and replaces Nintendo's Package1loader/bootloader. It currently utilizes the [Tegra X1 RCM Vulnerability](https://nvidia.custhelp.com/app/answers/detail/a_id/4660/~/security-notice%3A-nvidia-tegra-rcm-vulnerability) in order to function. + +Fusée is split into two separate parts: fusée-primary and fusée-secondary. This is due to the RCM Vulnerability only allowing payloads of a limited filesize to be sent to the device. + +As of June 2018, there are new Switch systems being sold that prevent Fusée (or any payload that requires the Fusée Gelée exploit) from working due to having an ipatched bootrom. All ipatched systems share the HAC-S-JXE-C3 product code. While Fusée cannot work on these ipatched units, they still come on firmware 4.1.0, which is vulnerable to the upcoming Déja Vu software exploit. Note that if you update past 4.1.0 on one of these ipatched units, your odds of being able to install Atmosphère or run any homebrew become practically non-existent. + +Additionally, a hardware revision of the Switch known as “Mariko” is believed to be in development. No such units have been seen in stores yet, but it is expected Nintendo will roll them out silently. The Mariko units will most likely patch the bootrom vulnerability Fusée Gelée, which is currently used to access CFW, and will likely have their own proprietary bootloader. + +## Fusée-Primary +Fusée-primary is the payload file (fusee-primary.bin) sent to the Switch from an external device. Once sent, fusée-primary makes initial preparations before loading fusée-secondary from the Switch’s SD Card. + +Fusée-primary can be configured via the [BCT.ini](../fusee/BCT.md) file located on the Switch’s SD card. + +## Fusée-Secondary +Fusée-secondary is a payload file that stays on the root of the Switch’s SD Card (fusee-secondary.bin). It is automatically launched once fusée-primary has finished, and is responsible for preparing the Switch’s hardware for future running environments, such as the homebrew menu. Fusée-secondary is also responsible for validating and launching Exosphère. + +Fusée-secondary contains various [.kip modules](/docs/main.md#modules). These modules modify existing features in the OS, and can also add new ones. + +Fusée is also capable of chainloading other payloads such as Linux. diff --git a/docs/components/stratosphere.md b/docs/components/stratosphere.md new file mode 100644 index 000000000..58813ab77 --- /dev/null +++ b/docs/components/stratosphere.md @@ -0,0 +1,10 @@ +# Stratosphère +Stratosphère allows customization of the Horizon OS and Switch kernel. It includes custom sysmodules that extend the kernel and provide new features. It also includes a reimplementation of the loader sysmodules to hook important system actions. + +The sysmodules that Stratosphère includes are: ++ [boot](../modules/boot.md): This module boots the system and initalizes hardware. ++ [creport](../modules/creport.md): Reimplementation of Nintendo’s crash report system. Dumps all error logs to the SD card instead of saving them to the NAND and sending them to Nintendo. ++ [fs_mitm](../modules/fs_mitm.md): This module can log, deny, delay, replace, and redirect any request made to the File System. ++ [loader](../modules/loader.md): Enables modifying the code of binaries that are not stored inside the kernel. ++ [pm](../modules/pm.md): Reimplementation of Nintendo’s Process Manager. ++ [sm](../modules/sm.md): Reimplementation of Nintendo’s Service Manager. diff --git a/docs/components/thermosphere.md b/docs/components/thermosphere.md new file mode 100644 index 000000000..c29483598 --- /dev/null +++ b/docs/components/thermosphere.md @@ -0,0 +1,6 @@ +# Thermosphère +Thermosphère is a hypervisor based implementation of emuNAND. An emuNAND is a copy of the firmware on the Switch’s internal memory (sysNAND), and is typically installed on an external SD Card. + +An emuNAND operates completely independently of the sysNAND. This allows one to make or test various modifications and homebrew safely without needing to restore their NAND backup afterwards by testing things on the emuNAND, and switching back to the sysNAND when finished. In the case of past Nintendo systems such as the 3DS, an emuNAND could also be used to update your system to the latest firmware while keeping your sysNAND on a lower version, however this may be more difficult to do on the Switch due to Nintendo using efuse technology for major system updates. + +Thermosphère is currently planned to be included in the 1.0 release of Atmosphère. diff --git a/docs/components/troposphere.md b/docs/components/troposphere.md new file mode 100644 index 000000000..2664843d8 --- /dev/null +++ b/docs/components/troposphere.md @@ -0,0 +1,2 @@ +# Troposphère +Troposphère contains various application-level modifications to the OS, such as launching homebrew directly from the homemenu or executing cheat/gameshark codes, similar to Luma3DS. Troposphère is not yet implemented in Atmosphère. diff --git a/docs/main.md b/docs/main.md new file mode 100644 index 000000000..02f3efc39 --- /dev/null +++ b/docs/main.md @@ -0,0 +1,29 @@ +# Atmosphère +Atmosphère is a work-in-progress customized firmware for the Nintendo Switch. Atmosphère consists of several different components, each in charge of performing different system functions of the Nintendo Switch. + +The components of Atmosphère are: ++ [Fusée](../docs/components/fusee/fusee.md), a custom bootloader. ++ [Exosphère](../docs/components/exosphere.md), a fully-featured custom secure monitor. ++ [Stratosphère](../docs/components/stratosphere.md), a set of custom system modules. ++ [Thermosphère](../docs/components/thermosphere.md), a hypervisor-based emuNAND implementation. This component has not been implemented yet. ++ [Troposphère](../docs/components/troposphere.md), Application-level patches to the Horizon OS. This component has also not been implemented yet. + +### Modules +The Stratosphère component of Atmosphère contains various modules. These have a `.kip` extension. They provide custom features, extend existing features, or replace Nintendo sysmodules. + +Stratosphère's modules include: ++ [boot](../docs/modules/boot.md) ++ [creport](../docs/modules/creport.md) ++ [fs_mitm](../docs/modules/fs_mitm.md) ++ [loader](../docs/modules/loader.md) ++ [pm](../docs/modules/pm.md) ++ [sm](../docs/modules/sm.md) + +### Building Atmosphère +A guide to building Atmosphère can be found [here](../docs/building.md). + +### Upcoming Features +A list of planned features for Atmosphère can be found [here](../docs/roadmap.md). + +### Release History +A changelog of previous versions of Atmosphère can be found [here](../docs/changelog.md). diff --git a/docs/modules/boot.md b/docs/modules/boot.md new file mode 100644 index 000000000..53013b32c --- /dev/null +++ b/docs/modules/boot.md @@ -0,0 +1,2 @@ +# boot +The boot module is responsible for booting the system and initalizing hardware. A second boot module known as boot2 is integrated with the [pm (process manager)](../modules/pm.md) sysmodule in Atmosphère, and launches other processes. diff --git a/docs/modules/creport.md b/docs/modules/creport.md new file mode 100644 index 000000000..a6a996f43 --- /dev/null +++ b/docs/modules/creport.md @@ -0,0 +1,2 @@ +# creport +creport is a reimplementation of Nintendo's crash reporter. Atmosphère's creport catches all error logs that would have been saved to the NAND and instead saves them to the SD card for debugging purposes. This is helpful because the errors no longer go to Nintendo and developers of homebrew can still see the errors to help with the debugging process. creport catches system errors, game crashes, and homebrew crashes. diff --git a/docs/modules/fs_mitm.md b/docs/modules/fs_mitm.md new file mode 100644 index 000000000..345c42275 --- /dev/null +++ b/docs/modules/fs_mitm.md @@ -0,0 +1,2 @@ +# fs_mitm +fs_mitm is a sysmodule that enables intercepting file system operations. This module can log, deny, delay, replace, or redirect any request made to the filesystem. It enables LayeredFS to function, which allows for game mods. diff --git a/docs/modules/loader.md b/docs/modules/loader.md new file mode 100644 index 000000000..6bde97faa --- /dev/null +++ b/docs/modules/loader.md @@ -0,0 +1,68 @@ +# loader + +loader is a reimplementation of the loader sysmodule. This module is responsible for creating processes from executable NSO images and registering their access control with the kernel, sm, and fs. + +## Atmosphère Extensions + +Atmosphère extends this module to allow executables to be replaced or patched by files stored on the SD card. Note that a few services are required for SD card access and therefore cannot be replaced or patched in this manner. This includes psc, bus, and pcv. + +### Exefs Replacement + +TODO: details on buttons affecting this. + +When a process is created, loader will search for several NSO filenames in the title's exefs directory. +These filenames are, in this order: + + - rtld + - main + - subsdk0 + - subsdk1 + - ... + - subsdk9 + - sdk + +Each NSO that is found will be loaded into the process contiguously. The process's entrypoint is at the first NSO to be loaded, usually `rtld` or `main`. + +Additionally, when a process is loaded, loader will search for a `main.npdm` file in the exefs directory specifying the title's permissions. + +Atmosphère extends this functionality by also searching for these files on the SD card. When searching for a file, loader will first check if it exists on the SD card. If it does, that file will be used instead. Otherwise, it will use the copy located in the exefs, if that is present. The following directory will be searched. + +``` +sdmc:/atmosphere/titles/<title id>/exefs/ +``` + +This allows the replacement of applets, sysmodules, or even games with homebrew versions. + +In order to prevent an NSO from being loaded even if it exists in the exefs, loader will also check if a stub file exists. If such a file exists, the NSO will not be loaded. The files should be named like `rtld.stub`, `main.stub`, etc. and may be empty. + +### NSO Patching + +TODO: details on buttons affecting this. + +When an NSO is loaded, the stratosphere implementatin of loader will search for IPS patch files on the SD card in the following locations. +``` +sdmc:/atmosphere/exefs_patches/<patchset name>/<nso build id>.ips +``` +This organization allows patchsets affecting multiple NSOs to be distributed as a single directory. Patches will be searched for in each patchset directory. The name of each patch file should match the hexadecimal build ID of the NSO to affect, except that trailing zero bytes may be left off. Because the NSO build ID is unique for every NSO, this means patches will only apply to the files they are meant to apply to. + +Patch files are accepted in either IPS format or IPS32 format. + +Because NSO files are compressed, patch files are not made between the original version of a compressed NSO and the modified version of such an NSO. Instead, they are made between the uncompressed version of an NSO and the modified (and still uncompressed) version of that NSO. This also means that a patch file cannot be manually applied to the compressed version of an NSO; it must be applied to the uncompressed version. The Stratosphere implementation of loader will correctly apply these patches while loading the process regardless of whether the NSO it finds is compressed or not. + +When authoring patches, [hactool](https://github.com/SciresM/hactool) can be used to find an NSO's build ID and to uncompress NSOs. Recent versions of the [ReSwitched IDA loaders](https://github.com/reswitched/loaders) can be used to load uncompressed NSOs into IDA in such a way that you can [apply patches to the input file](https://www.hex-rays.com/products/ida/support/idadoc/1618.shtml). From there, any IPS tool can be used to create the patch between the original NSO and the patched NSO. Note that if the NSO you are patching is larger than 16 MiB, you will have to use a tool that supports IPS32. + +### HBL Support + +Atmosphère can use the loader module in order to turn any game on your Switch's home menu into a launchpoint for the Homebrew Menu, rather than launching it through the album applet. This allows one to launch the Homebrew Menu with access to the ~3.2GB of RAM that the Switch reserves for games and applications, as opposed to the 442MB of RAM we are limited to when launching the Homebrew Menu from the album. This also means that it is no longer necessary to install homebrew as `.nsp` files on your Switch so long as you are using this method, as the only reason to do so is to allow the homebrew to access all of the Switch's available memory. + +In order to setup this method you will need the latest release of [hbmenu](https://github.com/switchbrew/nx-hbmenu/releases), and the latest release of [hbloader](https://github.com/switchbrew/nx-hbloader/releases). Place `hbmenu.nro` on the root of your Switch's SD Card, and place `hbl.nsp` in the atmosphere folder. From there, simply configure `loader.ini` in the atmosphere folder by replacing the Title ID in the ini (hbl_tid) (it is the Title ID for the album by default) with the Title ID of whatever game you wish to use to launch the Homebrew Menu. A list of Title IDs for Switch Games can be found [here](https://switchbrew.org/wiki/Title_list/Games). Afterwards you may reinsert your SD Card into your Switch and boot into Atmosphère as you normally would. You should now be able to boot into the Homebrew Menu by launching your designated game of choice. + +### Button Overrides + +By default `loader.ini` is configured to launch the Homebrew Menu when launching the game normally, and launching the game when selecting the game while holding down R. If you wish to change this, you can modify the override_key section of `loader.ini`. Placing an exclamation point in front of whatever button you wish to use will make it so that you will only launch the actual game while holding down that button, otherwise you will go into the Homebrew Menu. Removing the exclamation point will reverse this, meaning that you will boot into the Homebrew Menu only while holding down the assigned button when launching the game. + +For example, `override_key=!R` will run the game only while holding down R when launching it, otherwise it will boot into the Homebrew Menu. `override_key=R` will only boot into the Homebrew Menu while holding down R when launching the game, otherwise it will launch the game as normal. + +### SM MITM Integration + +When the Stratosphere implementation of loader creates a new process, it notifies [sm](sm.md) through the `AtmosphereAssociatePidTidForMitm` command to notify any MITM services of new processes' identities. diff --git a/docs/modules/pm.md b/docs/modules/pm.md new file mode 100644 index 000000000..fe00ee18a --- /dev/null +++ b/docs/modules/pm.md @@ -0,0 +1,23 @@ +# pm + +pm is a reimplementation of Nintendo's process manager. This module is responsible for tracking running processes on the system, and managing resource limits. pm is also required to create and manage processes for homebrew applications. + +## Atmosphère Extensions + +There are a few ways in which the Stratosphere implementation of pm differs intentionally from the stock pm. + +### IPC: AtmosphereGetProcessHandle + +The Stratosphere implementation of pm adds an additional command to the [`pm:dmnt`](https://reswitched.github.io/SwIPC/ifaces.html#nn::pm::detail::IDebugMonitorInterface) interface, called `AtmosphereGetProcessHandle`. Its command ID is `65000` on all system firmware versions. It takes a `u64 process_id` and returns a process handle for the specified process, if that process is known. Notable exceptions include KIPs, which are not known to pm. If the specified process cannot be found, error code 0x20F is returned. + +The SwIPC definition for this command follows. +``` +interface nn::pm::detail::IDebugMonitorInterface is pm:dmnt { + ... + [65000] AtmosphereGetProcessHandle(u64 pid) -> handle<copy, process> process_handle; +} +``` + +### Extra System Memory for Sysmodules + +The Stratosphere implementation of pm shrinks the APPLET memory pool by 24 MiB by default, giving this memory to the SYSTEM pool. This allows custom sysmodules to use more memory without hitting the SYSTEM memory limit. diff --git a/docs/modules/sm.md b/docs/modules/sm.md new file mode 100644 index 000000000..8852975f8 --- /dev/null +++ b/docs/modules/sm.md @@ -0,0 +1,69 @@ +# sm + +sm is a reimplementation of Nintendo's service manager. It allows Atmosphère to add or remove process handle limits, add new services, or intercept service calls. This allows high-level intercepting of Horizon OS functionality. + +## Atmosphère Extensions + +There are a few ways in which the Stratosphere implementation of sm differs intentionally from the stock sm. + +### IPC: MITM Commands + +The Stratosphere implementation of sm adds a few additional commands to the [`sm:`](https://reswitched.github.io/SwIPC/ifaces.html#nn::sm::detail::IUserInterface) port session. + +Their SwIPC definitions follow. +``` +interface nn::sm::detail::IUserInterface is sm: { + ... + [65000] AtmosphereInstallMitm(ServiceName service) -> handle<port, move> service, handle<server_session, move> query; + [65001] AtmosphereUninstallMitm(ServiceName service); + [65002] AtmosphereAssociatePidTidForMitm(u64 pid, u64 tid); +} +``` + +#### AtmosphereInstallMitm + +This command alters the registration for the named service, in order to allow services to intercept communication between client processes and their intended services. It is used by [fs_mitm](fs_mitm.md). + +It takes the name of the service to install an MITM for, and returns two handles. The first is a port handle, similar to those returned from the [RegisterService](https://reswitched.github.io/SwIPC/ifaces.html#nn::sm::detail::IUserInterface(2)) command. The second is the server side of a session, called the query session. This session will used by sm to determine whether or not a new session should be intercepted, and to inform the MITM service of the identity of new processes. + +The query session is expected to implement the following interface. +``` +interface MitmQueryService { + [65000] ShouldMitm(u64 pid) -> u64 should_mitm; + [65001] AssociatePidTid(u64 pid, u64 tid); +} +``` + +The `ShouldMitm` command is invoked whenever a process attempts to make a new connection to the MITM'd service. It should return `0` if the process's connection should not be intercepted. Any other value will cause the process's connection to be intercepted. If the command returns an error code, the process's connection will not be intercepted. + +The `AssociatePidTid` command is invoked on all MITM query sessions whenever a new process is created, in order to inform those services of the identity of a newly created process before it attempts to connect to any services. + +If the process that installed the MITM attempts to connect to the service, it will always connect to the original service. + +This command requires that the session be initialized, returning error code 0x415 if it is not. +If the given service name is invalid, error code 0xC15 is returned. +If the user does not have service registration permission for the named service, error code 0x1015 is returned. +If the service has not yet been registered, error code 0xE15 is returned. +If the service already has an MITM installed, error code 0x815 is returned. + +#### AtmosphereUninstallMitm + +Removes any installed MITM for the named service. + +This command requires that the session be initialized, returning error code 0x415 if it is not. + +#### AtmosphereAssociatePidTidForMitm + +This command is used internally by the Stratosphere implementation of the [loader](loader.md) sysmodule, when a new process is created. It will call the `AssociatePidTid` command on every registered MITM query session. + +If the given process ID refers to a kernel internal process, error code 0x1015 is returned. This command requires that the session be initialized, returning error code 0x415 if it is not. + +### Minimum Session Limit + +When a service is registered, the sysmodule registering it must specify a limit on the number of sessions that are allowed to be active for that service at a time. This is used to ensure that services like `fs-pr`, `fs-ldr`, and `ldr:pm` can only be connected to once, adding an additional layer of safety over the regular service verification to ensure that those services are only connected to by the highly priveleged process they are intended to be used by. + +By default, the Stratosphere implementation of PM will raise any session limits to at least 8, meaning that for services like `fs-pr` and those mentioned above, up to 8 processes will be able to connect to those sessions, leaving 7 sessions for homebrew to use. + +### Weak Service Verification + +In system firmware versions before 3.0.1, if a process did not call the [Initialize](https://reswitched.github.io/SwIPC/ifaces.html#nn::sm::detail::IUserInterface(0)) command on its `sm:` session, normally used to inform sm of the process's identity, sm would assume that the process was a kernel internal process and skip any service registration or access checks. The Stratosphere implementation of sm reimplements this vulnerability, allowing homebrew processes to skip service registration and access checks. diff --git a/docs/roadmap.md b/docs/roadmap.md new file mode 100644 index 000000000..03367dff9 --- /dev/null +++ b/docs/roadmap.md @@ -0,0 +1,16 @@ +# Planned Features +The following features are planned to be added in future versions of Atmosphère: ++ Thermosphère, a hypervisor-based emunand implementation. ++ A feature-rich debugging toolset (a component of Stratosphère). + + A custom debug monitor system module, providing an API for debugging Switch's processes. This may not be a reimplementation of Nintendo's own debug monitor. + + This should include a gdbstub implementation, possibly borrowing from Luma3DS's. + + This API should be additionally usable for RAM Editing/"Cheat Engine" purposes. + + A custom shell system module, providing an means for users to perform various RPC (with support for common/interesting functionality) on their Switch remotely. This may not be a reimplementation of Nintendo's own shell. + + This should support client connections over both Wi-Fi and USB. + + A custom logging system module, providing a means for other Atmosphère components (and possibly Nintendo's own system modules) to log debug output. + + This should support logging to the SD card, over Wi-Fi, and over USB. ++ An application-level plugin system. + + This will, ideally, work somewhat like NTR-CFW's plugin system on the 3DS, allowing users to run their own code in a game's process in their own thread. ++ An AR Code/Gameshark analog implementation, allowing for easy sharing/development of cheat codes to run on device. ++ Further extensions to existing Atmosphère components. ++ General system stability improvements to enhance the user's experience. diff --git a/exosphere/Makefile b/exosphere/Makefile index 77e3e02da..efadefc58 100644 --- a/exosphere/Makefile +++ b/exosphere/Makefile @@ -20,7 +20,7 @@ TARGET := $(notdir $(CURDIR)) BUILD := build SOURCES := src src/dbg DATA := data -INCLUDES := include +INCLUDES := include ../common/include #--------------------------------------------------------------------------------- # options for code generation diff --git a/exosphere/src/configitem.c b/exosphere/src/configitem.c index 577f74502..389bbcaec 100644 --- a/exosphere/src/configitem.c +++ b/exosphere/src/configitem.c @@ -15,6 +15,7 @@ */ #include <stdint.h> +#include <atmosphere/version.h> #include "bootconfig.h" #include "configitem.h" @@ -25,7 +26,6 @@ #include "utils.h" #include "masterkey.h" #include "exocfg.h" -#include "version.h" static bool g_battery_profile = false; @@ -151,7 +151,11 @@ uint32_t configitem_get(ConfigItem item, uint64_t *p_outvalue) { break; case CONFIGITEM_EXOSPHERE_VERSION: /* UNOFFICIAL: Gets information about the current exosphere version. */ - *p_outvalue = (EXOSPHERE_RELEASE_VERSION_MAJOR << 24) | (EXOSPHERE_RELEASE_VERSION_MINOR << 16) | (exosphere_get_target_firmware() << 8) | (mkey_get_revision() << 0); + *p_outvalue = ((uint64_t)(ATMOSPHERE_RELEASE_VERSION_MAJOR & 0xFF) << 32ull) | + ((uint64_t)(ATMOSPHERE_RELEASE_VERSION_MINOR & 0xFF) << 24ull) | + ((uint64_t)(ATMOSPHERE_RELEASE_VERSION_MICRO & 0xFF) << 16ull) | + ((uint64_t)(exosphere_get_target_firmware() & 0xFF) << 8ull) | + ((uint64_t)(mkey_get_revision() & 0xFF) << 0ull); break; default: result = 2; diff --git a/exosphere/src/package2.c b/exosphere/src/package2.c index 6e1620bc1..1281f9498 100644 --- a/exosphere/src/package2.c +++ b/exosphere/src/package2.c @@ -304,7 +304,7 @@ static bool validate_package2_metadata(package2_meta_t *metadata) { /* Perform version checks. */ /* We will be compatible with all package2s released before current, but not newer ones. */ - if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_500_CURRENT) { + if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_600_CURRENT) { return true; } @@ -331,7 +331,7 @@ static uint32_t decrypt_and_validate_header(package2_header_t *header) { } /* Ensure we successfully decrypted the header. */ - if (mkey_rev > mkey_get_revision()) { + if (mkey_rev > mkey_get_revision()) { panic(0xFAF00003); } } else if (!validate_package2_metadata(&header->metadata)) { @@ -478,7 +478,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) { MAKE_REG32(PMC_BASE + 0x334) |= 0x10; switch (exosphere_get_target_firmware()) { case EXOSPHERE_TARGET_FIRMWARE_400: - MAKE_REG32(PMC_BASE + 0x360) = 5; + MAKE_REG32(PMC_BASE + 0x360) = 0x105; break; case EXOSPHERE_TARGET_FIRMWARE_500: MAKE_REG32(PMC_BASE + 0x360) = 6; diff --git a/exosphere/src/package2.h b/exosphere/src/package2.h index ec0dfba3e..9553fa8fe 100644 --- a/exosphere/src/package2.h +++ b/exosphere/src/package2.h @@ -66,14 +66,16 @@ static inline uintptr_t get_nx_bootloader_mailbox_base(void) { #define PACKAGE2_MAXVER_300 0x4 #define PACKAGE2_MAXVER_302 0x5 #define PACKAGE2_MAXVER_400_410 0x6 -#define PACKAGE2_MAXVER_500_CURRENT 0x7 +#define PACKAGE2_MAXVER_500_510 0x7 +#define PACKAGE2_MAXVER_600_CURRENT 0x8 #define PACKAGE2_MINVER_100 0x3 #define PACKAGE2_MINVER_200 0x4 #define PACKAGE2_MINVER_300 0x5 #define PACKAGE2_MINVER_302 0x6 #define PACKAGE2_MINVER_400_410 0x7 -#define PACKAGE2_MINVER_500_CURRENT 0x8 +#define PACKAGE2_MINVER_500_510 0x8 +#define PACKAGE2_MINVER_600_CURRENT 0x9 typedef struct { union { diff --git a/fusee/fusee-primary/Makefile b/fusee/fusee-primary/Makefile index 34307fcbe..8dce2efff 100644 --- a/fusee/fusee-primary/Makefile +++ b/fusee/fusee-primary/Makefile @@ -20,7 +20,7 @@ TARGET := $(notdir $(CURDIR)) BUILD := build SOURCES := src src/sdmmc src/lib src/lib/fatfs src/display DATA := data -INCLUDES := include +INCLUDES := include ../../common/include #--------------------------------------------------------------------------------- # options for code generation diff --git a/fusee/fusee-secondary/Makefile b/fusee/fusee-secondary/Makefile index 55377889f..9055bbf59 100644 --- a/fusee/fusee-secondary/Makefile +++ b/fusee/fusee-secondary/Makefile @@ -23,7 +23,7 @@ TARGET := $(notdir $(CURDIR)) BUILD := build SOURCES := src src/sdmmc src/lib src/lib/fatfs src/display DATA := data -INCLUDES := include +INCLUDES := include ../../common/include #--------------------------------------------------------------------------------- # options for code generation @@ -69,7 +69,7 @@ ifneq ($(BUILD),$(notdir $(CURDIR))) export OUTPUT := $(CURDIR)/$(TARGET) export TOPDIR := $(CURDIR) -export KIPDIRS := $(AMS)/stratosphere/loader $(AMS)/stratosphere/pm $(AMS)/stratosphere/sm $(AMS)/stratosphere/boot +export KIPDIRS := $(AMS)/stratosphere/loader $(AMS)/stratosphere/pm $(AMS)/stratosphere/sm $(AMS)/stratosphere/boot $(AMS)/stratosphere/fs_mitm export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ $(foreach dir,$(DATA),$(CURDIR)/$(dir)) \ $(AMS)/exosphere $(AMS)/thermosphere $(KIPDIRS) @@ -79,7 +79,7 @@ export DEPSDIR := $(CURDIR)/$(BUILD) CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) -KIPFILES := loader.kip pm.kip sm.kip boot_100.kip boot_200.kip +KIPFILES := loader.kip pm.kip sm.kip fs_mitm.kip boot_100.kip boot_200.kip BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) exosphere.bin thermosphere.bin splash_screen.bmp $(KIPFILES) #--------------------------------------------------------------------------------- diff --git a/fusee/fusee-secondary/src/ips.c b/fusee/fusee-secondary/src/ips.c new file mode 100644 index 000000000..41c2840a6 --- /dev/null +++ b/fusee/fusee-secondary/src/ips.c @@ -0,0 +1,335 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <dirent.h> +#include <string.h> +#include <ctype.h> +#include "utils.h" +#include "se.h" +#include "lib/log.h" +#include "ips.h" + +/* IPS Patching adapted from Luma3DS (https://github.com/AuroraWright/Luma3DS/blob/master/sysmodules/loader/source/patcher.c) */ + +#define IPS_MAGIC "PATCH" +#define IPS_TAIL "EOF" + +#define IPS32_MAGIC "IPS32" +#define IPS32_TAIL "EEOF" + +/* Applies an IPS/IPS32 patch to memory, disregarding writes to the first prot_size bytes. */ +static void apply_ips_patch(uint8_t *mem, size_t mem_size, size_t prot_size, bool is_ips32, FILE *f_ips) { + uint8_t buffer[4]; + while (fread(buffer, is_ips32 ? 4 : 3, 1, f_ips) == 1) { + if (is_ips32 && memcmp(buffer, IPS32_TAIL, 4) == 0) { + break; + } else if (!is_ips32 && memcmp(buffer, IPS_TAIL, 3) == 0) { + break; + } + + /* Offset of patch. */ + uint32_t patch_offset; + if (is_ips32) { + patch_offset = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]; + } else { + patch_offset = (buffer[0] << 16) | (buffer[1] << 8) | (buffer[2]); + } + + /* Size of patch. */ + if (fread(buffer, 2, 1, f_ips) != 1) { + break; + } + uint32_t patch_size = (buffer[0] << 8) | (buffer[1]); + + /* Check for RLE encoding. */ + if (patch_size == 0) { + /* Size of RLE. */ + if (fread(buffer, 2, 1, f_ips) != 1) { + break; + } + + uint32_t rle_size = (buffer[0] << 8) | (buffer[1]); + + /* Value for RLE. */ + if (fread(buffer, 1, 1, f_ips) != 1) { + break; + } + + if (patch_offset < prot_size) { + if (patch_offset + rle_size > prot_size) { + uint32_t diff = prot_size - patch_offset; + patch_offset += diff; + rle_size -= diff; + goto IPS_RLE_PATCH_OFFSET_WITHIN_BOUNDS; + } + } else { + IPS_RLE_PATCH_OFFSET_WITHIN_BOUNDS: + if (patch_offset + rle_size > mem_size) { + rle_size = mem_size - patch_offset; + } + memset(mem + patch_offset, buffer[0], rle_size); + } + } else { + uint32_t read_size; + if (patch_offset < prot_size) { + if (patch_offset + patch_size > prot_size) { + uint32_t diff = prot_size - patch_offset; + patch_offset += diff; + patch_size -= diff; + fseek(f_ips, diff, SEEK_CUR); + goto IPS_DATA_PATCH_OFFSET_WITHIN_BOUNDS; + } else { + fseek(f_ips, patch_size, SEEK_CUR); + } + } else { + IPS_DATA_PATCH_OFFSET_WITHIN_BOUNDS: + read_size = patch_size; + if (patch_offset + read_size > mem_size) { + read_size = mem_size - patch_offset; + } + if (fread(mem + patch_offset, read_size, 1, f_ips) != 1) { + break; + } + if (patch_size > read_size) { + fseek(f_ips, patch_size - read_size, SEEK_CUR); + } + } + } + } +} + + +static inline uint8_t hex_nybble_to_u8(const char nybble) { + if ('0' <= nybble && nybble <= '9') { + return nybble - '0'; + } else if ('a' <= nybble && nybble <= 'f') { + return nybble - 'a' + 0xa; + } else { + return nybble - 'A' + 0xA; + } +} + +static bool name_matches_hash(const char *name, size_t name_len, const void *hash, size_t hash_size) { + /* Validate name is hex build id. */ + for (unsigned int i = 0; i < name_len - 4; i++) { + if (isxdigit(name[i]) == 0) { + return false; + } + } + + /* Read hash from name. */ + uint8_t hash_from_name[0x20] = {0}; + for (unsigned int name_ofs = 0, id_ofs = 0; name_ofs < name_len - 4; id_ofs++) { + hash_from_name[id_ofs] |= hex_nybble_to_u8(name[name_ofs++]) << 4; + hash_from_name[id_ofs] |= hex_nybble_to_u8(name[name_ofs++]); + } + + return memcmp(hash, hash_from_name, hash_size) == 0; + +} + +static bool has_ips_patches(const char *dir, const void *hash, size_t hash_size) { + bool any_patches = false; + char path[0x301] = {0}; + snprintf(path, sizeof(path) - 1, "%s", dir); + DIR *patches_dir = opendir(path); + struct dirent *pdir_ent; + if (patches_dir != NULL) { + /* Iterate over the patches directory to find patch subdirectories. */ + while ((pdir_ent = readdir(patches_dir)) != NULL && !any_patches) { + if (strcmp(pdir_ent->d_name, ".") == 0 || strcmp(pdir_ent->d_name, "..") == 0) { + continue; + } + snprintf(path, sizeof(path) - 1, "%s/%s", dir, pdir_ent->d_name); + DIR *patch_dir = opendir(path); + struct dirent *ent; + if (patch_dir != NULL) { + /* Iterate over the patch subdirectory to find .ips patches. */ + while ((ent = readdir(patch_dir)) != NULL && !any_patches) { + if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) { + continue; + } + size_t name_len = strlen(ent->d_name); + if ((4 < name_len && name_len <= 0x44) && ((name_len & 1) == 0) && strcmp(ent->d_name + name_len - 4, ".ips") == 0 && name_matches_hash(ent->d_name, name_len, hash, hash_size)) { + snprintf(path, sizeof(path) - 1, "%s/%s/%s", dir, pdir_ent->d_name, ent->d_name); + FILE *f_ips = fopen(path, "rb"); + if (f_ips != NULL) { + uint8_t header[5]; + if (fread(header, 5, 1, f_ips) == 1) { + if (memcmp(header, IPS_MAGIC, 5) == 0 || memcmp(header, IPS32_MAGIC, 5) == 0) { + any_patches = true; + } + } + fclose(f_ips); + } + } + } + closedir(patch_dir); + } + } + closedir(patches_dir); + } + + return any_patches; +} + +static void apply_ips_patches(const char *dir, void *mem, size_t mem_size, size_t prot_size, const void *hash, size_t hash_size) { + char path[0x301] = {0}; + snprintf(path, sizeof(path) - 1, "%s", dir); + DIR *patches_dir = opendir(path); + struct dirent *pdir_ent; + if (patches_dir != NULL) { + /* Iterate over the patches directory to find patch subdirectories. */ + while ((pdir_ent = readdir(patches_dir)) != NULL) { + if (strcmp(pdir_ent->d_name, ".") == 0 || strcmp(pdir_ent->d_name, "..") == 0) { + continue; + } + snprintf(path, sizeof(path) - 1, "%s/%s", dir, pdir_ent->d_name); + DIR *patch_dir = opendir(path); + struct dirent *ent; + if (patch_dir != NULL) { + /* Iterate over the patch subdirectory to find .ips patches. */ + while ((ent = readdir(patch_dir)) != NULL) { + if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) { + continue; + } + size_t name_len = strlen(ent->d_name); + if ((4 < name_len && name_len <= 0x44) && ((name_len & 1) == 0) && strcmp(ent->d_name + name_len - 4, ".ips") == 0 && name_matches_hash(ent->d_name, name_len, hash, hash_size)) { + snprintf(path, sizeof(path) - 1, "%s/%s/%s", dir, pdir_ent->d_name, ent->d_name); + FILE *f_ips = fopen(path, "rb"); + if (f_ips != NULL) { + uint8_t header[5]; + if (fread(header, 5, 1, f_ips) == 1) { + if (memcmp(header, IPS_MAGIC, 5) == 0) { + apply_ips_patch(mem, mem_size, prot_size, false, f_ips); + } else if (memcmp(header, IPS32_MAGIC, 5) == 0) { + apply_ips_patch(mem, mem_size, prot_size, true, f_ips); + } + } + fclose(f_ips); + } + } + } + closedir(patch_dir); + } + } + closedir(patches_dir); + } +} + +void apply_kernel_ips_patches(void *kernel, size_t kernel_size) { + uint8_t hash[0x20]; + se_calculate_sha256(hash, kernel, kernel_size); + apply_ips_patches("atmosphere/kernel_patches", kernel, kernel_size, 0, hash, sizeof(hash)); +} + +static void kip1_blz_uncompress(void *hdr_end) { + uint8_t *u8_hdr_end = (uint8_t *)hdr_end; + uint32_t addl_size = ((u8_hdr_end[-4]) << 0) | ((u8_hdr_end[-3]) << 8) | ((u8_hdr_end[-2]) << 16) | ((u8_hdr_end[-1]) << 24); + uint32_t header_size = ((u8_hdr_end[-8]) << 0) | ((u8_hdr_end[-7]) << 8) | ((u8_hdr_end[-6]) << 16) | ((u8_hdr_end[-5]) << 24); + uint32_t cmp_and_hdr_size = ((u8_hdr_end[-12]) << 0) | ((u8_hdr_end[-11]) << 8) | ((u8_hdr_end[-10]) << 16) | ((u8_hdr_end[-9]) << 24); + + unsigned char *cmp_start = (unsigned char *)(((uintptr_t)hdr_end) - cmp_and_hdr_size); + uint32_t cmp_ofs = cmp_and_hdr_size - header_size; + uint32_t out_ofs = cmp_and_hdr_size + addl_size; + + while (out_ofs) { + unsigned char control = cmp_start[--cmp_ofs]; + for (unsigned int i = 0; i < 8; i++) { + if (control & 0x80) { + if (cmp_ofs < 2) { + fatal_error("KIP1 decompression out of bounds!\n"); + } + cmp_ofs -= 2; + uint16_t seg_val = ((unsigned int)cmp_start[cmp_ofs+1] << 8) | cmp_start[cmp_ofs]; + uint32_t seg_size = ((seg_val >> 12) & 0xF) + 3; + uint32_t seg_ofs = (seg_val & 0x0FFF) + 3; + if (out_ofs < seg_size) { + /* Kernel restricts segment copy to stay in bounds. */ + seg_size = out_ofs; + } + out_ofs -= seg_size; + + for (unsigned int j = 0; j < seg_size; j++) { + cmp_start[out_ofs + j] = cmp_start[out_ofs + j + seg_ofs]; + } + } else { + /* Copy directly. */ + if (cmp_ofs < 1) { + fatal_error("KIP1 decompression out of bounds!\n"); + } + cmp_start[--out_ofs] = cmp_start[--cmp_ofs]; + } + control <<= 1; + if (out_ofs == 0) { + return; + } + } + } +} + +static kip1_header_t *kip1_uncompress(kip1_header_t *kip, size_t *size) { + kip1_header_t new_header = *kip; + for (unsigned int i = 0; i < 3; i++) { + new_header.section_headers[i].compressed_size = new_header.section_headers[i].out_size; + } + new_header.flags &= 0xF8; + + *size = kip1_get_size_from_header(&new_header); + + unsigned char *new_kip = calloc(1, *size); + if (new_kip == NULL) { + return NULL; + } + *((kip1_header_t *)new_kip) = new_header; + + size_t new_offset = 0x100; + size_t old_offset = 0x100; + for (unsigned int i = 0; i < 3; i++) { + memcpy(new_kip + new_offset, (unsigned char *)kip + old_offset, kip->section_headers[i].compressed_size); + if (kip->flags & (1 << i)) { + kip1_blz_uncompress(new_kip + new_offset + kip->section_headers[i].compressed_size); + } + new_offset += kip->section_headers[i].out_size; + old_offset += kip->section_headers[i].compressed_size; + } + + return (kip1_header_t *)new_kip; +} + +kip1_header_t *apply_kip_ips_patches(kip1_header_t *kip, size_t kip_size) { + uint8_t hash[0x20]; + se_calculate_sha256(hash, kip, kip_size); + + if (!has_ips_patches("atmosphere/kip_patches", hash, sizeof(hash))) { + return NULL; + } + + print(SCREEN_LOG_LEVEL_MANDATORY, "[NXBOOT]: Patching KIP %08x%08x...\n", (uint32_t)(kip->title_id >> 32), (uint32_t)kip->title_id); + + + size_t uncompressed_kip_size; + kip1_header_t *uncompressed_kip = kip1_uncompress(kip, &uncompressed_kip_size); + if (uncompressed_kip == NULL) { + return NULL; + } + + apply_ips_patches("atmosphere/kip_patches", uncompressed_kip, uncompressed_kip_size, 0x100, hash, sizeof(hash)); + return uncompressed_kip; +} diff --git a/fusee/fusee-secondary/src/ips.h b/fusee/fusee-secondary/src/ips.h new file mode 100644 index 000000000..6db00a1f1 --- /dev/null +++ b/fusee/fusee-secondary/src/ips.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef FUSEE_IPS_H +#define FUSEE_IPS_H + +#include "utils.h" +#include "kip.h" +#include <stdint.h> + +void apply_kernel_ips_patches(void *kernel, size_t kernel_size); +kip1_header_t *apply_kip_ips_patches(kip1_header_t *kip, size_t kip_size); + +#endif diff --git a/fusee/fusee-secondary/src/kernel_patches.c b/fusee/fusee-secondary/src/kernel_patches.c index f0741350a..909a066aa 100644 --- a/fusee/fusee-secondary/src/kernel_patches.c +++ b/fusee/fusee-secondary/src/kernel_patches.c @@ -18,6 +18,7 @@ #include "utils.h" #include "se.h" #include "kernel_patches.h" +#include "ips.h" #define MAKE_BRANCH(a, o) 0x14000000 | ((((o) - (a)) >> 2) & 0x3FFFFFF) @@ -510,9 +511,13 @@ const kernel_info_t *get_kernel_info(void *kernel, size_t size) { return NULL; } -void package2_patch_kernel(void *_kernel, size_t size) { +void package2_patch_kernel(void *_kernel, size_t size, bool is_sd_kernel) { const kernel_info_t *kernel_info = get_kernel_info(_kernel, size); - if (kernel_info == NULL) { + + /* Apply IPS patches. */ + apply_kernel_ips_patches(_kernel, size); + + if (kernel_info == NULL && !is_sd_kernel) { /* Should this be fatal? */ fatal_error("kernel_patcher: unable to identify kernel!\n"); } diff --git a/fusee/fusee-secondary/src/kernel_patches.h b/fusee/fusee-secondary/src/kernel_patches.h index 7dc2c7795..1dfb21fbf 100644 --- a/fusee/fusee-secondary/src/kernel_patches.h +++ b/fusee/fusee-secondary/src/kernel_patches.h @@ -19,6 +19,6 @@ #include "utils.h" -void package2_patch_kernel(void *kernel, size_t kernel_size); +void package2_patch_kernel(void *kernel, size_t kernel_size, bool is_sd_kernel); #endif \ No newline at end of file diff --git a/fusee/fusee-secondary/src/main.c b/fusee/fusee-secondary/src/main.c index d10e6e7cb..753efc0aa 100644 --- a/fusee/fusee-secondary/src/main.c +++ b/fusee/fusee-secondary/src/main.c @@ -101,13 +101,13 @@ int main(int argc, void **argv) { g_do_nxboot = loader_ctx->chainload_entrypoint == 0; if (g_do_nxboot) { - print(SCREEN_LOG_LEVEL_INFO, "Now performing nxboot.\n"); + print(SCREEN_LOG_LEVEL_MANDATORY, "Now performing nxboot.\n"); uint32_t boot_memaddr = nxboot_main(); nxboot_finish(boot_memaddr); } else { /* TODO: What else do we want to do in terms of argc/argv? */ const char *path = get_loader_ctx()->file_paths_to_load[get_loader_ctx()->file_id_of_entrypoint]; - print(SCREEN_LOG_LEVEL_INFO, "Now chainloading.\n"); + print(SCREEN_LOG_LEVEL_MANDATORY, "Now chainloading.\n"); g_chainloader_argc = 1; strcpy(g_chainloader_arg_data, path); } diff --git a/fusee/fusee-secondary/src/nxboot.c b/fusee/fusee-secondary/src/nxboot.c index 83fb6ca3a..9b9c73ed2 100644 --- a/fusee/fusee-secondary/src/nxboot.c +++ b/fusee/fusee-secondary/src/nxboot.c @@ -292,6 +292,8 @@ uint32_t nxboot_main(void) { fatal_error("[NXBOOT]: Failed to detect target firmware!\n"); else print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT]: Detected target firmware %ld!\n", target_firmware); + + print(SCREEN_LOG_LEVEL_MANDATORY, "[NXBOOT]: Loaded firmware from eMMC...\n"); /* Setup boot configuration for Exosphère. */ nxboot_configure_exosphere(target_firmware); @@ -357,7 +359,7 @@ uint32_t nxboot_main(void) { pmc->scratch1 = (uint32_t)warmboot_memaddr; } - print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT]: Rebuilding package2...\n"); + print(SCREEN_LOG_LEVEL_MANDATORY, "[NXBOOT]: Rebuilding package2...\n"); /* Patch package2, adding Thermosphère + custom KIPs. */ package2_rebuild_and_copy(package2, MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware); diff --git a/fusee/fusee-secondary/src/package2.c b/fusee/fusee-secondary/src/package2.c index 50eada5f8..1d2fb3a5c 100644 --- a/fusee/fusee-secondary/src/package2.c +++ b/fusee/fusee-secondary/src/package2.c @@ -23,6 +23,7 @@ #include "kernel_patches.h" #include "kip.h" #include "se.h" +#include "fs_utils.h" #define u8 uint8_t #define u32 uint32_t @@ -47,6 +48,7 @@ void package2_rebuild_and_copy(package2_header_t *package2, uint32_t target_firm size_t rebuilt_package2_size; void *kernel; size_t kernel_size; + bool is_sd_kernel = false; void *thermosphere; size_t thermosphere_size; ini1_header_t *orig_ini1, *rebuilt_ini1; @@ -63,9 +65,28 @@ void package2_rebuild_and_copy(package2_header_t *package2, uint32_t target_firm if (thermosphere_size != 0 && package2->metadata.section_sizes[PACKAGE2_SECTION_UNUSED] != 0) { fatal_error(u8"Error: Package2 has no unused section for Thermosphère!\n"); } + + /* Load Kernel from SD, if possible. */ + { + size_t sd_kernel_size = get_file_size("atmosphere/kernel.bin"); + if (sd_kernel_size != 0) { + if (sd_kernel_size > PACKAGE2_SIZE_MAX) { + fatal_error("Error: atmosphere/kernel.bin is too large!\n"); + } + kernel = malloc(sd_kernel_size); + if (kernel == NULL) { + fatal_error("Error: failed to allocate kernel!\n"); + } + if (read_from_file(kernel, sd_kernel_size, "atmosphere/kernel.bin") != sd_kernel_size) { + fatal_error("Error: failed to read atmosphere/kernel.bin!\n"); + } + kernel_size = sd_kernel_size; + is_sd_kernel = true; + } + } /* Perform any patches we want to the NX kernel. */ - package2_patch_kernel(kernel, kernel_size); + package2_patch_kernel(kernel, kernel_size, is_sd_kernel); print(SCREEN_LOG_LEVEL_DEBUG, "Rebuilding the INI1 section...\n"); package2_get_src_section((void *)&orig_ini1, package2, PACKAGE2_SECTION_INI1); @@ -283,6 +304,7 @@ static ini1_header_t *package2_rebuild_ini1(ini1_header_t *ini1, uint32_t target ini1_header_t *inis_to_merge[STRATOSPHERE_INI1_MAX] = {0}; ini1_header_t *merged; + inis_to_merge[STRATOSPHERE_INI1_SDFILES] = stratosphere_get_sd_files_ini1(); inis_to_merge[STRATOSPHERE_INI1_EMBEDDED] = stratosphere_get_ini1(target_firmware); inis_to_merge[STRATOSPHERE_INI1_PACKAGE2] = ini1; diff --git a/fusee/fusee-secondary/src/stratosphere.c b/fusee/fusee-secondary/src/stratosphere.c index 22d058b92..2a07e1ff0 100644 --- a/fusee/fusee-secondary/src/stratosphere.c +++ b/fusee/fusee-secondary/src/stratosphere.c @@ -17,11 +17,14 @@ #include <stdio.h> #include <stdlib.h> #include <stdint.h> +#include <dirent.h> #include "exocfg.h" #include "utils.h" #include "package2.h" #include "stratosphere.h" #include "fs_utils.h" +#include "ips.h" +#include "lib/log.h" #define u8 uint8_t #define u32 uint32_t @@ -34,16 +37,18 @@ #undef u32 static ini1_header_t *g_stratosphere_ini1 = NULL; +static ini1_header_t *g_sd_files_ini1 = NULL; static bool g_stratosphere_loader_enabled = true; static bool g_stratosphere_sm_enabled = true; static bool g_stratosphere_pm_enabled = true; +static bool g_stratosphere_fs_mitm_enabled = true; static bool g_stratosphere_boot_enabled = false; extern const uint8_t boot_100_kip[], boot_200_kip[]; -extern const uint8_t loader_kip[], pm_kip[], sm_kip[]; +extern const uint8_t loader_kip[], pm_kip[], sm_kip[], fs_mitm_kip[]; extern const uint32_t boot_100_kip_size, boot_200_kip_size; -extern const uint32_t loader_kip_size, pm_kip_size, sm_kip_size; +extern const uint32_t loader_kip_size, pm_kip_size, sm_kip_size, fs_mitm_kip_size; /* GCC doesn't consider the size as const... we have to write it ourselves. */ @@ -83,6 +88,11 @@ ini1_header_t *stratosphere_get_ini1(uint32_t target_firmware) { num_processes++; } + if (g_stratosphere_fs_mitm_enabled) { + size += fs_mitm_kip_size; + num_processes++; + } + if (g_stratosphere_boot_enabled) { size += boot_kip_size; num_processes++; @@ -117,6 +127,11 @@ ini1_header_t *stratosphere_get_ini1(uint32_t target_firmware) { data += sm_kip_size; } + if (g_stratosphere_fs_mitm_enabled) { + memcpy(data, fs_mitm_kip, fs_mitm_kip_size); + data += fs_mitm_kip_size; + } + if (g_stratosphere_boot_enabled) { memcpy(data, boot_kip, boot_kip_size); data += boot_kip_size; @@ -126,13 +141,111 @@ ini1_header_t *stratosphere_get_ini1(uint32_t target_firmware) { } void stratosphere_free_ini1(void) { - free(g_stratosphere_ini1); - g_stratosphere_ini1 = NULL; + if (g_stratosphere_ini1 != NULL) { + free(g_stratosphere_ini1); + g_stratosphere_ini1 = NULL; + } + if (g_sd_files_ini1 != NULL) { + free(g_sd_files_ini1); + g_sd_files_ini1 = NULL; + } +} + + + +static void try_add_sd_kip(ini1_header_t *ini1, const char *kip_path) { + size_t file_size = get_file_size(kip_path); + + if (ini1->size + file_size > PACKAGE2_SIZE_MAX) { + fatal_error("Failed to load %s: INI1 would be too large!\n", kip_path); + } + + kip1_header_t kip_header; + if (read_from_file(&kip_header, sizeof(kip_header), kip_path) != sizeof(kip_header) || kip_header.magic != MAGIC_KIP1) { + return; + } + + size_t kip_size = kip1_get_size_from_header(&kip_header); + if (kip_size > file_size) { + fatal_error("Failed to load %s: KIP size is corrupt!\n", kip_path); + } + + if (read_from_file(ini1->kip_data + ini1->size - sizeof(ini1_header_t), kip_size, kip_path) != kip_size) { + /* TODO: is this error fatal? */ + return; + } + + ini1->size += kip_size; + ini1->num_processes++; +} + +ini1_header_t *stratosphere_get_sd_files_ini1(void) { + if (g_sd_files_ini1 != NULL) { + return g_sd_files_ini1; + } + + /* Allocate space. */ + g_sd_files_ini1 = (ini1_header_t *)malloc(PACKAGE2_SIZE_MAX); + g_sd_files_ini1->magic = MAGIC_INI1; + g_sd_files_ini1->size = sizeof(ini1_header_t); + g_sd_files_ini1->num_processes = 0; + g_sd_files_ini1->_0xC = 0; + + /* Load all kips from /atmosphere/kips/<*>.kip or /atmosphere/kips/<*>/<*>.kip. */ + DIR *kips_dir = opendir("atmosphere/kips"); + struct dirent *ent; + if (kips_dir != NULL) { + while ((ent = readdir(kips_dir)) != NULL) { + if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) { + continue; + } + + char kip_path[0x301] = {0}; + snprintf(kip_path, 0x300, "atmosphere/kips/%s", ent->d_name); + + struct stat kip_stat; + if (stat(kip_path, &kip_stat) == -1) { + continue; + } + + if ((kip_stat.st_mode & S_IFMT) == S_IFREG) { + /* If file, add to ini1. */ + try_add_sd_kip(g_sd_files_ini1, kip_path); + } else if ((kip_stat.st_mode & S_IFMT) == S_IFDIR) { + /* Otherwise, allow one level of nesting. */ + DIR *sub_dir = opendir(kip_path); + struct dirent *sub_ent; + if (sub_dir != NULL) { + while ((sub_ent = readdir(sub_dir)) != NULL) { + if (strcmp(sub_ent->d_name, ".") == 0 || strcmp(sub_ent->d_name, "..") == 0) { + continue; + } + + /* Reuse kip path variable. */ + memset(kip_path, 0, sizeof(kip_path)); + snprintf(kip_path, 0x300, "atmosphere/kips/%s/%s", ent->d_name, sub_ent->d_name); + + if (stat(kip_path, &kip_stat) == -1) { + continue; + } + + if ((kip_stat.st_mode & S_IFMT) == S_IFREG) { + /* If file, add to ini1. */ + try_add_sd_kip(g_sd_files_ini1, kip_path); + } + } + closedir(sub_dir); + } + } + } + closedir(kips_dir); + } + + return g_sd_files_ini1; } /* Merges some number of INI1s into a single INI1. It's assumed that the INIs are in order of preference. */ ini1_header_t *stratosphere_merge_inis(ini1_header_t **inis, size_t num_inis) { - char sd_path[0x100] = {0}; uint32_t total_num_processes = 0; /* Validate all ini headers. */ @@ -159,7 +272,6 @@ ini1_header_t *stratosphere_merge_inis(ini1_header_t **inis, size_t num_inis) { merged->num_processes = 0; merged->_0xC = 0; size_t remaining_size = PACKAGE2_SIZE_MAX - sizeof(ini1_header_t); - size_t read_size; unsigned char *current_dst_kip = merged->kip_data; @@ -184,31 +296,26 @@ ini1_header_t *stratosphere_merge_inis(ini1_header_t **inis, size_t num_inis) { if (already_loaded) { continue; } + + print(SCREEN_LOG_LEVEL_MANDATORY, "[NXBOOT]: Loading KIP %08x%08x...\n", (uint32_t)(current_kip->title_id >> 32), (uint32_t)current_kip->title_id); - /* TODO: What folder should these be read out of? */ - snprintf(sd_path, sizeof(sd_path), "atmosphere/titles/%016llX/%016llX.kip", current_kip->title_id, current_kip->title_id); - - /* Try to load an override KIP from SD, if possible. */ - read_size = read_from_file(current_dst_kip, remaining_size, sd_path); - if (read_size != 0) { - kip1_header_t *sd_kip = (kip1_header_t *)(current_dst_kip); - if (read_size < sizeof(kip1_header_t) || sd_kip->magic != MAGIC_KIP1) { - fatal_error("%s is not a KIP1?\n", sd_path); - } else if (sd_kip->title_id != current_kip->title_id) { - fatal_error("%s has wrong Title ID!\n", sd_path); - } - size_t expected_sd_kip_size = kip1_get_size_from_header(sd_kip); - if (expected_sd_kip_size != read_size) { - fatal_error("%s has wrong size or there is not enough space (expected 0x%zx, read 0x%zx)!\n", - sd_path, expected_sd_kip_size, read_size); - } - remaining_size -= expected_sd_kip_size; - current_dst_kip += expected_sd_kip_size; - } else { - size_t current_kip_size = kip1_get_size_from_header(current_kip); - if (current_kip_size > remaining_size) { + size_t current_kip_size = kip1_get_size_from_header(current_kip); + if (current_kip_size > remaining_size) { + fatal_error("Not enough space for all the KIP1s!\n"); + } + + kip1_header_t *patched_kip = apply_kip_ips_patches(current_kip, current_kip_size); + if (patched_kip != NULL) { + size_t patched_kip_size = kip1_get_size_from_header(patched_kip); + if (patched_kip_size > remaining_size) { fatal_error("Not enough space for all the KIP1s!\n"); } + memcpy(current_dst_kip, patched_kip, patched_kip_size); + remaining_size -= patched_kip_size; + current_dst_kip += patched_kip_size; + + free(patched_kip); + } else { memcpy(current_dst_kip, current_kip, current_kip_size); remaining_size -= current_kip_size; current_dst_kip += current_kip_size; diff --git a/fusee/fusee-secondary/src/stratosphere.h b/fusee/fusee-secondary/src/stratosphere.h index 33915555b..2ae43f1be 100644 --- a/fusee/fusee-secondary/src/stratosphere.h +++ b/fusee/fusee-secondary/src/stratosphere.h @@ -20,11 +20,13 @@ #include "utils.h" #include "kip.h" -#define STRATOSPHERE_INI1_EMBEDDED 0x0 -#define STRATOSPHERE_INI1_PACKAGE2 0x1 -#define STRATOSPHERE_INI1_MAX 0x2 +#define STRATOSPHERE_INI1_SDFILES 0x0 +#define STRATOSPHERE_INI1_EMBEDDED 0x1 +#define STRATOSPHERE_INI1_PACKAGE2 0x2 +#define STRATOSPHERE_INI1_MAX 0x3 ini1_header_t *stratosphere_get_ini1(uint32_t target_firmware); +ini1_header_t *stratosphere_get_sd_files_ini1(void); void stratosphere_free_ini1(void); ini1_header_t *stratosphere_merge_inis(ini1_header_t **inis, unsigned int num_inis); diff --git a/stratosphere/Makefile b/stratosphere/Makefile index 1c1e5b1e5..559327b9e 100644 --- a/stratosphere/Makefile +++ b/stratosphere/Makefile @@ -1,4 +1,4 @@ -KIPS := loader pm sm boot fs_mitm creport +KIPS := loader pm sm boot fs_mitm set_mitm creport #TODO: boot2 ? diff --git a/stratosphere/boot/Makefile b/stratosphere/boot/Makefile index b4ff11df6..57b69f6e0 100644 --- a/stratosphere/boot/Makefile +++ b/stratosphere/boot/Makefile @@ -21,7 +21,7 @@ TARGET := $(notdir $(CURDIR)) BUILD := build SOURCES := source DATA := data -INCLUDES := include +INCLUDES := include ../../common/include EXEFS_SRC := exefs_src DEFINES := -DDISABLE_IPC diff --git a/stratosphere/boot/source/boot_main.cpp b/stratosphere/boot/source/boot_main.cpp index e636ff6c5..9eb94f170 100644 --- a/stratosphere/boot/source/boot_main.cpp +++ b/stratosphere/boot/source/boot_main.cpp @@ -83,6 +83,8 @@ void __appInit(void) { fatalSimple(0xCAFE << 4 | 2); fsdevMountSdmc(); + + CheckAtmosphereVersion(); } void __appExit(void) { diff --git a/stratosphere/creport/Makefile b/stratosphere/creport/Makefile index 67fd1e2f4..c042e968d 100644 --- a/stratosphere/creport/Makefile +++ b/stratosphere/creport/Makefile @@ -21,7 +21,7 @@ TARGET := $(notdir $(CURDIR)) BUILD := build SOURCES := source DATA := data -INCLUDES := include +INCLUDES := include ../../common/include EXEFS_SRC := exefs_src DEFINES := -DDISABLE_IPC diff --git a/stratosphere/fs_mitm/Makefile b/stratosphere/fs_mitm/Makefile index 41a6cf79f..e8b1f047a 100644 --- a/stratosphere/fs_mitm/Makefile +++ b/stratosphere/fs_mitm/Makefile @@ -21,7 +21,7 @@ TARGET := $(notdir $(CURDIR)) BUILD := build SOURCES := source DATA := data -INCLUDES := include +INCLUDES := include ../../common/include EXEFS_SRC := exefs_src DEFINES := -DDISABLE_IPC diff --git a/stratosphere/fs_mitm/fs_mitm.json b/stratosphere/fs_mitm/fs_mitm.json index 7733b4bbf..d90a68b96 100644 --- a/stratosphere/fs_mitm/fs_mitm.json +++ b/stratosphere/fs_mitm/fs_mitm.json @@ -13,63 +13,64 @@ { "type": "syscalls", "value": { - "svcSetHeapSize": "0x01", - "svcSetMemoryPermission": "0x02", - "svcSetMemoryAttribute": "0x03", - "svcMapMemory": "0x04", - "svcUnmapMemory": "0x05", - "svcQueryMemory": "0x06", - "svcExitProcess": "0x07", - "svcCreateThread": "0x08", - "svcStartThread": "0x09", - "svcExitThread": "0x0a", - "svcSleepThread": "0x0b", - "svcGetThreadPriority": "0x0c", - "svcSetThreadPriority": "0x0d", - "svcGetThreadCoreMask": "0x0e", - "svcSetThreadCoreMask": "0x0f", - "svcGetCurrentProcessorNumber": "0x10", - "svcSignalEvent": "0x11", - "svcClearEvent": "0x12", - "svcMapSharedMemory": "0x13", - "svcUnmapSharedMemory": "0x14", - "svcCreateTransferMemory": "0x15", - "svcCloseHandle": "0x16", - "svcResetSignal": "0x17", - "svcWaitSynchronization": "0x18", - "svcCancelSynchronization": "0x19", - "svcArbitrateLock": "0x1a", - "svcArbitrateUnlock": "0x1b", - "svcWaitProcessWideKeyAtomic": "0x1c", - "svcSignalProcessWideKey": "0x1d", - "svcGetSystemTick": "0x1e", - "svcConnectToNamedPort": "0x1f", - "svcSendSyncRequestLight": "0x20", - "svcSendSyncRequest": "0x21", - "svcSendSyncRequestWithUserBuffer": "0x22", - "svcSendAsyncRequestWithUserBuffer": "0x23", - "svcGetProcessId": "0x24", - "svcGetThreadId": "0x25", - "svcBreak": "0x26", - "svcOutputDebugString": "0x27", - "svcReturnFromException": "0x28", - "svcGetInfo": "0x29", - "svcWaitForAddress": "0x34", - "svcSignalToAddress": "0x35", - "svcCreateSession": "0x40", - "svcAcceptSession": "0x41", - "svcReplyAndReceiveLight": "0x42", - "svcReplyAndReceive": "0x43", - "svcReplyAndReceiveWithUserBuffer": "0x44", - "svcCreateEvent": "0x45", - "svcCreateInterruptEvent": "0x53", - "svcQueryIoMapping": "0x55", - "svcCreateDeviceAddressSpace": "0x56", - "svcAttachDeviceAddressSpace": "0x57", - "svcDetachDeviceAddressSpace": "0x58", - "svcMapDeviceAddressSpaceAligned": "0x5a", - "svcUnmapDeviceAddressSpace": "0x5c", - "svcGetSystemInfo": "0x6f" + "svcSetHeapSize": "0x01", + "svcSetMemoryPermission": "0x02", + "svcSetMemoryAttribute": "0x03", + "svcMapMemory": "0x04", + "svcUnmapMemory": "0x05", + "svcQueryMemory": "0x06", + "svcExitProcess": "0x07", + "svcCreateThread": "0x08", + "svcStartThread": "0x09", + "svcExitThread": "0x0a", + "svcSleepThread": "0x0b", + "svcGetThreadPriority": "0x0c", + "svcSetThreadPriority": "0x0d", + "svcGetThreadCoreMask": "0x0e", + "svcSetThreadCoreMask": "0x0f", + "svcGetCurrentProcessorNumber": "0x10", + "svcSignalEvent": "0x11", + "svcClearEvent": "0x12", + "svcMapSharedMemory": "0x13", + "svcUnmapSharedMemory": "0x14", + "svcCreateTransferMemory": "0x15", + "svcCloseHandle": "0x16", + "svcResetSignal": "0x17", + "svcWaitSynchronization": "0x18", + "svcCancelSynchronization": "0x19", + "svcArbitrateLock": "0x1a", + "svcArbitrateUnlock": "0x1b", + "svcWaitProcessWideKeyAtomic": "0x1c", + "svcSignalProcessWideKey": "0x1d", + "svcGetSystemTick": "0x1e", + "svcConnectToNamedPort": "0x1f", + "svcSendSyncRequestLight": "0x20", + "svcSendSyncRequest": "0x21", + "svcSendSyncRequestWithUserBuffer": "0x22", + "svcSendAsyncRequestWithUserBuffer": "0x23", + "svcGetProcessId": "0x24", + "svcGetThreadId": "0x25", + "svcBreak": "0x26", + "svcOutputDebugString": "0x27", + "svcReturnFromException": "0x28", + "svcGetInfo": "0x29", + "svcWaitForAddress": "0x34", + "svcSignalToAddress": "0x35", + "svcCreateSession": "0x40", + "svcAcceptSession": "0x41", + "svcReplyAndReceiveLight": "0x42", + "svcReplyAndReceive": "0x43", + "svcReplyAndReceiveWithUserBuffer": "0x44", + "svcCreateEvent": "0x45", + "svcCreateInterruptEvent": "0x53", + "svcReadWriteRegister": "0x4E", + "svcQueryIoMapping": "0x55", + "svcCreateDeviceAddressSpace": "0x56", + "svcAttachDeviceAddressSpace": "0x57", + "svcDetachDeviceAddressSpace": "0x58", + "svcMapDeviceAddressSpaceAligned": "0x5a", + "svcUnmapDeviceAddressSpace": "0x5c", + "svcGetSystemInfo": "0x6f" } } ] diff --git a/stratosphere/fs_mitm/source/debug.cpp b/stratosphere/fs_mitm/source/debug.cpp index 35844b65e..1531eff48 100644 --- a/stratosphere/fs_mitm/source/debug.cpp +++ b/stratosphere/fs_mitm/source/debug.cpp @@ -24,7 +24,5 @@ void Reboot() { } void Log(const void *data, int size) { - (void)(data); - (void)(size); /* ... */ } \ No newline at end of file diff --git a/stratosphere/fs_mitm/source/fs_istorage.hpp b/stratosphere/fs_mitm/source/fs_istorage.hpp index d6827839f..2f21b6b7e 100644 --- a/stratosphere/fs_mitm/source/fs_istorage.hpp +++ b/stratosphere/fs_mitm/source/fs_istorage.hpp @@ -21,21 +21,19 @@ #include "debug.hpp" -enum class FsIStorageCmd { - Read = 0, - Write = 1, - Flush = 2, - SetSize = 3, - GetSize = 4, - OperateRange = 5, +enum FsIStorageCmd : u32 { + FsIStorageCmd_Read = 0, + FsIStorageCmd_Write = 1, + FsIStorageCmd_Flush = 2, + FsIStorageCmd_SetSize = 3, + FsIStorageCmd_GetSize = 4, + FsIStorageCmd_OperateRange = 5, }; class IStorage { public: virtual ~IStorage(); - - virtual IStorage *Clone() = 0; - + virtual Result Read(void *buffer, size_t size, u64 offset) = 0; virtual Result Write(void *buffer, size_t size, u64 offset) = 0; virtual Result Flush() = 0; @@ -51,88 +49,59 @@ class IStorageInterface : public IServiceObject { IStorageInterface(IStorage *s) : base_storage(s) { /* ... */ }; - - IStorageInterface *clone() override { - return new IStorageInterface(this->base_storage->Clone()); - } - + ~IStorageInterface() { delete base_storage; }; - Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) final { - Result rc = 0xF601; - switch ((FsIStorageCmd)cmd_id) { - case FsIStorageCmd::Read: - rc = WrapIpcCommandImpl<&IStorageInterface::read>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case FsIStorageCmd::Write: - rc = WrapIpcCommandImpl<&IStorageInterface::write>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case FsIStorageCmd::Flush: - rc = WrapIpcCommandImpl<&IStorageInterface::flush>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case FsIStorageCmd::SetSize: - rc = WrapIpcCommandImpl<&IStorageInterface::set_size>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case FsIStorageCmd::GetSize: - rc = WrapIpcCommandImpl<&IStorageInterface::get_size>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case FsIStorageCmd::OperateRange: - if (kernelAbove400()) { - rc = WrapIpcCommandImpl<&IStorageInterface::operate_range>(this, r, out_c, pointer_buffer, pointer_buffer_size); - } - break; - default: - break; - } - return rc; - }; - - Result handle_deferred() final { - /* TODO: Panic, we can never defer. */ - return 0; - }; private: /* Actual command API. */ - virtual std::tuple<Result> read(OutBuffer<u8, BufferType_Type1> buffer, u64 offset, u64 size) final { - return {this->base_storage->Read(buffer.buffer, std::min(buffer.num_elements, size), offset)}; + virtual Result Read(OutBuffer<u8, BufferType_Type1> buffer, u64 offset, u64 size) final { + return this->base_storage->Read(buffer.buffer, std::min(buffer.num_elements, size), offset); }; - virtual std::tuple<Result> write(InBuffer<u8, BufferType_Type1> buffer, u64 offset, u64 size) final { - return {this->base_storage->Write(buffer.buffer, std::min(buffer.num_elements, size), offset)}; + virtual Result Write(InBuffer<u8, BufferType_Type1> buffer, u64 offset, u64 size) final { + return this->base_storage->Write(buffer.buffer, std::min(buffer.num_elements, size), offset); }; - virtual std::tuple<Result> flush() final { - return {this->base_storage->Flush()}; + virtual Result Flush() final { + return this->base_storage->Flush(); }; - virtual std::tuple<Result> set_size(u64 size) final { - return {this->base_storage->SetSize(size)}; + virtual Result SetSize(u64 size) final { + return this->base_storage->SetSize(size); }; - virtual std::tuple<Result, u64> get_size() final { - u64 out_size = 0; - Result rc = this->base_storage->GetSize(&out_size); - return {rc, out_size}; + virtual Result GetSize(Out<u64> size) final { + return this->base_storage->GetSize(size.GetPointer()); }; - virtual std::tuple<Result, FsRangeInfo> operate_range(u32 operation_type, u64 offset, u64 size) final { - FsRangeInfo out_range_info = {0}; - Result rc = this->base_storage->OperateRange(operation_type, offset, size, &out_range_info); - return {rc, out_range_info}; + virtual Result OperateRange(Out<FsRangeInfo> range_info, u32 operation_type, u64 offset, u64 size) final { + return this->base_storage->OperateRange(operation_type, offset, size, range_info.GetPointer()); + }; + public: + DEFINE_SERVICE_DISPATCH_TABLE { + /* 1.0.0- */ + MakeServiceCommandMeta<FsIStorageCmd_Read, &IStorageInterface::Read>(), + MakeServiceCommandMeta<FsIStorageCmd_Write, &IStorageInterface::Write>(), + MakeServiceCommandMeta<FsIStorageCmd_Flush, &IStorageInterface::Flush>(), + MakeServiceCommandMeta<FsIStorageCmd_SetSize, &IStorageInterface::SetSize>(), + MakeServiceCommandMeta<FsIStorageCmd_GetSize, &IStorageInterface::GetSize>(), + + /* 4.0.0- */ + MakeServiceCommandMeta<FsIStorageCmd_OperateRange, &IStorageInterface::OperateRange, FirmwareVersion_400>(), }; }; class IROStorage : public IStorage { public: virtual Result Read(void *buffer, size_t size, u64 offset) = 0; - Result Write(void *buffer, size_t size, u64 offset) final { + virtual Result Write(void *buffer, size_t size, u64 offset) final { (void)(buffer); (void)(offset); (void)(size); return 0x313802; }; - Result Flush() final { + virtual Result Flush() final { return 0x0; }; - Result SetSize(u64 size) final { + virtual Result SetSize(u64 size) final { (void)(size); return 0x313802; }; diff --git a/stratosphere/fs_mitm/source/fs_shim.c b/stratosphere/fs_mitm/source/fs_shim.c index 0c510dbba..134d83498 100644 --- a/stratosphere/fs_mitm/source/fs_shim.c +++ b/stratosphere/fs_mitm/source/fs_shim.c @@ -17,47 +17,6 @@ #include <switch.h> #include "fs_shim.h" -/* Necessary evil. */ -Result ipcCopyFromDomain(Handle session, u32 object_id, Service *out) { - u32* buf = (u32*)armGetTls(); - - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - u32 object_id; - } *raw; - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - buf[0] = IpcCommandType_Control; - raw->magic = SFCI_MAGIC; - raw->cmd_id = 1; - raw->object_id = object_id; - - Result rc = ipcDispatch(session); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct ipcCopyFromDomainResponse { - u64 magic; - u64 result; - } *raw = (struct ipcCopyFromDomainResponse*)r.Raw; - - rc = raw->result; - - if (R_SUCCEEDED(rc)) { - serviceCreate(out, r.Handles[0]); - } - } - - return rc; -} - - /* Missing fsp-srv commands. */ Result fsOpenDataStorageByCurrentProcessFwd(Service* s, FsStorage* out) { IpcCommand c; @@ -68,7 +27,7 @@ Result fsOpenDataStorageByCurrentProcessFwd(Service* s, FsStorage* out) { u64 cmd_id; } *raw; - raw = ipcPrepareHeader(&c, sizeof(*raw)); + raw = serviceIpcPrepareHeader(s, &c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 200; @@ -77,60 +36,25 @@ Result fsOpenDataStorageByCurrentProcessFwd(Service* s, FsStorage* out) { if (R_SUCCEEDED(rc)) { IpcParsedCommand r; - ipcParse(&r); - struct { u64 magic; u64 result; - } *resp = r.Raw; + } *resp; + + serviceIpcParse(s, &r, sizeof(*resp)); + resp = r.Raw; rc = resp->result; if (R_SUCCEEDED(rc)) { - serviceCreate(&out->s, r.Handles[0]); + serviceCreateSubservice(&out->s, s, &r, 0); } } return rc; } -Result fsOpenDataStorageByCurrentProcessFromDomainFwd(Service* s, u32 *out_object_id) { - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - } *raw; - - raw = ipcPrepareHeaderForDomain(&c, sizeof(*raw), s->object_id); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 200; - - Result rc = serviceIpcDispatch(s); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParseForDomain(&r); - - struct { - u64 magic; - u64 result; - u32 object_id; - } *resp = r.Raw; - - rc = resp->result; - - if (R_SUCCEEDED(rc)) { - *out_object_id = resp->object_id; - } - } - - return rc; -} - -Result fsOpenDataStorageByDataId(Service* s, FsStorageId storage_id, u64 data_id, FsStorage* out) { +Result fsOpenDataStorageByDataIdFwd(Service* s, FsStorageId storage_id, u64 data_id, FsStorage* out) { IpcCommand c; ipcInitialize(&c); @@ -141,7 +65,7 @@ Result fsOpenDataStorageByDataId(Service* s, FsStorageId storage_id, u64 data_id u64 data_id; } *raw; - raw = ipcPrepareHeader(&c, sizeof(*raw)); + raw = serviceIpcPrepareHeader(s, &c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 202; @@ -152,58 +76,18 @@ Result fsOpenDataStorageByDataId(Service* s, FsStorageId storage_id, u64 data_id if (R_SUCCEEDED(rc)) { IpcParsedCommand r; - ipcParse(&r); - struct { u64 magic; u64 result; - } *resp = r.Raw; + } *resp; + + serviceIpcParse(s, &r, sizeof(*resp)); + resp = r.Raw; rc = resp->result; if (R_SUCCEEDED(rc)) { - serviceCreate(&out->s, r.Handles[0]); - } - } - - return rc; -} - - -Result fsOpenDataStorageByDataIdFromDomain(Service* s, FsStorageId storage_id, u64 data_id, u32 *out_object_id) { - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - FsStorageId storage_id; - u64 data_id; - } *raw; - - raw = ipcPrepareHeaderForDomain(&c, sizeof(*raw), s->object_id); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 202; - raw->storage_id = storage_id; - raw->data_id = data_id; - - Result rc = serviceIpcDispatch(s); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParseForDomain(&r); - - struct { - u64 magic; - u64 result; - u32 object_id; - } *resp = r.Raw; - - rc = resp->result; - - if (R_SUCCEEDED(rc)) { - *out_object_id = resp->object_id; + serviceCreateSubservice(&out->s, s, &r, 0); } } @@ -223,7 +107,7 @@ Result fsFileOperateRange(FsFile* f, u32 op_id, u64 off, u64 len, FsRangeInfo *o u64 len; } *raw; - raw = ipcPrepareHeader(&c, sizeof(*raw)); + raw = serviceIpcPrepareHeader(&f->s, &c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 5; @@ -235,13 +119,14 @@ Result fsFileOperateRange(FsFile* f, u32 op_id, u64 off, u64 len, FsRangeInfo *o if (R_SUCCEEDED(rc)) { IpcParsedCommand r; - ipcParse(&r); - struct { u64 magic; u64 result; FsRangeInfo range_info; - } *resp = r.Raw; + } *resp; + + serviceIpcParse(&f->s, &r, sizeof(*resp)); + resp = r.Raw; rc = resp->result; if (R_SUCCEEDED(rc) && out) *out = resp->range_info; @@ -263,7 +148,7 @@ Result fsStorageOperateRange(FsStorage* s, u32 op_id, u64 off, u64 len, FsRangeI u64 len; } *raw; - raw = ipcPrepareHeader(&c, sizeof(*raw)); + raw = serviceIpcPrepareHeader(&s->s, &c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 5; @@ -275,13 +160,14 @@ Result fsStorageOperateRange(FsStorage* s, u32 op_id, u64 off, u64 len, FsRangeI if (R_SUCCEEDED(rc)) { IpcParsedCommand r; - ipcParse(&r); - struct { u64 magic; u64 result; FsRangeInfo range_info; - } *resp = r.Raw; + } *resp; + + serviceIpcParse(&s->s, &r, sizeof(*resp)); + resp = r.Raw; rc = resp->result; if (R_SUCCEEDED(rc) && out) *out = resp->range_info; diff --git a/stratosphere/fs_mitm/source/fs_shim.h b/stratosphere/fs_mitm/source/fs_shim.h index 9030078e7..d73c2595b 100644 --- a/stratosphere/fs_mitm/source/fs_shim.h +++ b/stratosphere/fs_mitm/source/fs_shim.h @@ -16,14 +16,9 @@ typedef struct { u32 flags[0x40/sizeof(u32)]; } FsRangeInfo; -/* Necessary evils. */ -Result ipcCopyFromDomain(Handle session, u32 object_id, Service *out); - /* Missing fsp-srv commands. */ Result fsOpenDataStorageByCurrentProcessFwd(Service* s, FsStorage* out); -Result fsOpenDataStorageByCurrentProcessFromDomainFwd(Service* s, u32 *out_object_id); -Result fsOpenDataStorageByDataId(Service* s, FsStorageId storage_id, u64 data_id, FsStorage* out); -Result fsOpenDataStorageByDataIdFromDomain(Service* s, FsStorageId storage_id, u64 data_id, u32 *out_object_id); +Result fsOpenDataStorageByDataIdFwd(Service* s, FsStorageId storage_id, u64 data_id, FsStorage* out); /* Missing FS File commands. */ Result fsFileOperateRange(FsFile* f, u32 op_id, u64 off, u64 len, FsRangeInfo *out); diff --git a/stratosphere/fs_mitm/source/fsmitm_layeredrom.cpp b/stratosphere/fs_mitm/source/fsmitm_layeredrom.cpp index 4a11580fa..ed6ad63a1 100644 --- a/stratosphere/fs_mitm/source/fsmitm_layeredrom.cpp +++ b/stratosphere/fs_mitm/source/fsmitm_layeredrom.cpp @@ -124,12 +124,14 @@ Result LayeredRomFS::Read(void *buffer, size_t size, u64 offset) { fatalSimple(0xF601); } read_so_far += cur_read_size; + offset += cur_read_size; } else { /* Handle padding explicitly. */ cur_source_ind++; /* Zero out the padding we skip, here. */ - memset((void *)((uintptr_t)buffer + read_so_far), 0, ((*this->p_source_infos)[cur_source_ind]).virtual_offset - (cur_source->virtual_offset + cur_source->size)); - read_so_far += ((*this->p_source_infos)[cur_source_ind]).virtual_offset - (cur_source->virtual_offset + cur_source->size); + memset((void *)((uintptr_t)buffer + read_so_far), 0, ((*this->p_source_infos)[cur_source_ind]).virtual_offset - offset); + read_so_far += ((*this->p_source_infos)[cur_source_ind]).virtual_offset - offset; + offset = ((*this->p_source_infos)[cur_source_ind]).virtual_offset; } } diff --git a/stratosphere/fs_mitm/source/fsmitm_layeredrom.hpp b/stratosphere/fs_mitm/source/fsmitm_layeredrom.hpp index 3e6061651..01be3af01 100644 --- a/stratosphere/fs_mitm/source/fsmitm_layeredrom.hpp +++ b/stratosphere/fs_mitm/source/fsmitm_layeredrom.hpp @@ -32,16 +32,12 @@ class LayeredRomFS : public IROStorage { /* Information about the merged RomFS. */ u64 title_id; std::shared_ptr<std::vector<RomFSSourceInfo>> p_source_infos; - - LayeredRomFS *Clone() override { - return new LayeredRomFS(*this); - }; public: LayeredRomFS(std::shared_ptr<RomInterfaceStorage> s_r, std::shared_ptr<RomFileStorage> f_r, u64 tid); virtual ~LayeredRomFS() = default; - Result Read(void *buffer, size_t size, u64 offset) override; - Result GetSize(u64 *out_size) override; - Result OperateRange(u32 operation_type, u64 offset, u64 size, FsRangeInfo *out_range_info) override; + virtual Result Read(void *buffer, size_t size, u64 offset) override; + virtual Result GetSize(u64 *out_size) override; + virtual Result OperateRange(u32 operation_type, u64 offset, u64 size, FsRangeInfo *out_range_info) override; }; diff --git a/stratosphere/fs_mitm/source/fsmitm_main.cpp b/stratosphere/fs_mitm/source/fsmitm_main.cpp index e6271b10d..1c12d9db1 100644 --- a/stratosphere/fs_mitm/source/fsmitm_main.cpp +++ b/stratosphere/fs_mitm/source/fsmitm_main.cpp @@ -22,13 +22,7 @@ #include <switch.h> #include <stratosphere.hpp> -#include "sm_mitm.h" - -#include "mitm_server.hpp" #include "fsmitm_service.hpp" -#include "fsmitm_worker.hpp" - -#include "mitm_query_service.hpp" #include "fsmitm_utils.hpp" @@ -67,58 +61,32 @@ void __appInit(void) { fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_SM)); } - rc = smMitMInitialize(); - if (R_FAILED(rc)) { - fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_SM)); - } - rc = fsInitialize(); if (R_FAILED(rc)) { fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_FS)); } - - rc = splInitialize(); - if (R_FAILED(rc)) { - fatalSimple(0xCAFE << 4 | 3); - } - - /* Check for exosphere API compatibility. */ - u64 exosphere_cfg; - if (R_SUCCEEDED(splGetConfig((SplConfigItem)65000, &exosphere_cfg))) { - /* MitM requires Atmosphere API 0.1. */ - u16 api_version = (exosphere_cfg >> 16) & 0xFFFF; - if (api_version < 0x0001) { - fatalSimple(0xCAFE << 4 | 0xFE); - } - } else { - fatalSimple(0xCAFE << 4 | 0xFF); - } - - //splExit(); + CheckAtmosphereVersion(); } void __appExit(void) { /* Cleanup services. */ fsExit(); - smMitMExit(); smExit(); } +struct FsMitmManagerOptions { + static const size_t PointerBufferSize = 0x800; + static const size_t MaxDomains = 0x10; + static const size_t MaxDomainObjects = 0x4000; +}; +using FsMitmManager = WaitableManager<FsMitmManagerOptions>; + int main(int argc, char **argv) { - Thread worker_thread = {0}; Thread sd_initializer_thread = {0}; + Thread hid_initializer_thread = {0}; consoleDebugInit(debugDevice_SVC); - - consoleDebugInit(debugDevice_SVC); - - if (R_FAILED(threadCreate(&worker_thread, &FsMitMWorker::Main, NULL, 0x20000, 45, 0))) { - /* TODO: Panic. */ - } - if (R_FAILED(threadStart(&worker_thread))) { - /* TODO: Panic. */ - } - + if (R_FAILED(threadCreate(&sd_initializer_thread, &Utils::InitializeSdThreadFunc, NULL, 0x4000, 0x15, 0))) { /* TODO: Panic. */ } @@ -126,18 +94,23 @@ int main(int argc, char **argv) /* TODO: Panic. */ } + if (R_FAILED(threadCreate(&hid_initializer_thread, &Utils::InitializeHidThreadFunc, NULL, 0x4000, 0x15, 0))) { + /* TODO: Panic. */ + } + if (R_FAILED(threadStart(&hid_initializer_thread))) { + /* TODO: Panic. */ + } + /* TODO: What's a good timeout value to use here? */ - auto server_manager = std::make_unique<MultiThreadedWaitableManager>(1, U64_MAX, 0x20000); - //auto server_manager = std::make_unique<WaitableManager>(U64_MAX); + auto server_manager = new FsMitmManager(5); /* Create fsp-srv mitm. */ - ISession<MitMQueryService<FsMitMService>> *fs_query_srv = NULL; - MitMServer<FsMitMService> *fs_srv = new MitMServer<FsMitMService>(&fs_query_srv, "fsp-srv", 61); - server_manager->add_waitable(fs_srv); - server_manager->add_waitable(fs_query_srv); - + AddMitmServerToManager<FsMitmService>(server_manager, "fsp-srv", 61); + /* Loop forever, servicing our services. */ - server_manager->process(); + server_manager->Process(); + + delete server_manager; return 0; } diff --git a/stratosphere/fs_mitm/source/fsmitm_romfsbuild.cpp b/stratosphere/fs_mitm/source/fsmitm_romfsbuild.cpp index 3a1afb780..4a01bff77 100644 --- a/stratosphere/fs_mitm/source/fsmitm_romfsbuild.cpp +++ b/stratosphere/fs_mitm/source/fsmitm_romfsbuild.cpp @@ -400,7 +400,7 @@ void RomFSBuildContext::Build(std::vector<RomFSSourceInfo> *out_infos) { header->file_table_ofs = header->file_hash_table_ofs + header->file_hash_table_size; /* For debugging, uncomment this to get a log of the generated metadata tables. */ - /* + { FsFileSystem sd_fs; if (R_SUCCEEDED(fsMountSdcard(&sd_fs))) { @@ -415,7 +415,7 @@ void RomFSBuildContext::Build(std::vector<RomFSSourceInfo> *out_infos) { fsFsClose(&sd_fs); } } - */ + out_infos->emplace_back(header->dir_hash_table_ofs, this->dir_hash_table_size + this->dir_table_size + this->file_hash_table_size + this->file_table_size, metadata, RomFSDataSource::Memory); } diff --git a/stratosphere/fs_mitm/source/fsmitm_romstorage.hpp b/stratosphere/fs_mitm/source/fsmitm_romstorage.hpp index cc378cd1f..c421a2147 100644 --- a/stratosphere/fs_mitm/source/fsmitm_romstorage.hpp +++ b/stratosphere/fs_mitm/source/fsmitm_romstorage.hpp @@ -35,10 +35,6 @@ class RomFileStorage : public IROStorage { fsFileClose(base_file); delete base_file; }; - - RomFileStorage *Clone() override { - return new RomFileStorage(this->base_file); - }; public: Result Read(void *buffer, size_t size, u64 offset) override { size_t out_sz = 0; @@ -72,10 +68,6 @@ class RomInterfaceStorage : public IROStorage { fsStorageClose(base_storage); delete base_storage; }; - - RomInterfaceStorage *Clone() override { - return new RomInterfaceStorage(this->base_storage); - }; public: Result Read(void *buffer, size_t size, u64 offset) override { return fsStorageRead(this->base_storage, offset, buffer, size); diff --git a/stratosphere/fs_mitm/source/fsmitm_service.cpp b/stratosphere/fs_mitm/source/fsmitm_service.cpp index 07f5c3156..a9f1e30a5 100644 --- a/stratosphere/fs_mitm/source/fsmitm_service.cpp +++ b/stratosphere/fs_mitm/source/fsmitm_service.cpp @@ -18,149 +18,115 @@ #include "fsmitm_service.hpp" #include "fs_shim.h" -#include "fsmitm_worker.hpp" #include "fsmitm_utils.hpp" #include "fsmitm_romstorage.hpp" #include "fsmitm_layeredrom.hpp" -#include "mitm_query_service.hpp" #include "debug.hpp" -Result FsMitMService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) { - Result rc = 0xF601; - if (this->has_initialized) { - switch (static_cast<FspSrvCmd>(cmd_id)) { - case FspSrvCmd::OpenDataStorageByCurrentProcess: - rc = WrapIpcCommandImpl<&FsMitMService::open_data_storage_by_current_process>(this, r, out_c, pointer_buffer, pointer_buffer_size); +void FsMitmService::PostProcess(IMitmServiceObject *obj, IpcResponseContext *ctx) { + auto this_ptr = static_cast<FsMitmService *>(obj); + switch ((FspSrvCmd)ctx->cmd_id) { + case FspSrvCmd_SetCurrentProcess: + if (R_SUCCEEDED(ctx->rc)) { + this_ptr->has_initialized = true; + this_ptr->process_id = ctx->request.Pid; + this_ptr->title_id = this_ptr->process_id; + if (R_FAILED(MitmQueryUtils::GetAssociatedTidForPid(this_ptr->process_id, &this_ptr->title_id))) { + /* Log here, if desired. */ + } break; - case FspSrvCmd::OpenDataStorageByDataId: - rc = WrapIpcCommandImpl<&FsMitMService::open_data_storage_by_data_id>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - default: - break; - } - } else { - if (static_cast<FspSrvCmd>(cmd_id) == FspSrvCmd::SetCurrentProcess) { - if (r.HasPid) { - this->init_pid = r.Pid; } - } - } - return rc; -} - -void FsMitMService::postprocess(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) { - struct { - u64 magic; - u64 result; - } *resp = (decltype(resp))r.Raw; - - u64 *tls = (u64 *)armGetTls(); - std::array<u64, 0x100/sizeof(u64)> backup_tls; - std::copy(tls, tls + backup_tls.size(), backup_tls.begin()); - - Result rc = (Result)resp->result; - switch (static_cast<FspSrvCmd>(cmd_id)) { - case FspSrvCmd::SetCurrentProcess: - if (R_SUCCEEDED(rc)) { - this->has_initialized = true; - } - this->process_id = this->init_pid; - this->title_id = this->process_id; - if (R_FAILED(MitMQueryUtils::get_associated_tid_for_pid(this->process_id, &this->title_id))) { - /* Log here, if desired. */ - } - std::copy(backup_tls.begin(), backup_tls.end(), tls); break; default: break; } - resp->result = rc; -} - -Result FsMitMService::handle_deferred() { - /* This service is never deferrable. */ - return 0; } /* Add redirection for RomFS to the SD card. */ -std::tuple<Result, OutSession<IStorageInterface>> FsMitMService::open_data_storage_by_current_process() { - IPCSession<IStorageInterface> *out_session = NULL; - std::shared_ptr<IStorageInterface> out_storage = nullptr; +Result FsMitmService::OpenDataStorageByCurrentProcess(Out<std::shared_ptr<IStorageInterface>> out_storage) { + std::shared_ptr<IStorageInterface> storage = nullptr; u32 out_domain_id = 0; - Result rc; + Result rc = 0; + + ON_SCOPE_EXIT { + if (R_SUCCEEDED(rc)) { + out_storage.SetValue(std::move(storage)); + if (out_storage.IsDomain()) { + out_storage.ChangeObjectId(out_domain_id); + } + } + }; + if (this->romfs_storage != nullptr) { - if (this->get_owner() != NULL) { - rc = fsOpenDataStorageByCurrentProcessFromDomainFwd(this->forward_service, &out_domain_id); + if (out_storage.IsDomain()) { + FsStorage s = {0}; + rc = fsOpenDataStorageByCurrentProcessFwd(this->forward_service.get(), &s); + if (R_SUCCEEDED(rc)) { + out_domain_id = s.s.object_id; + } } else { rc = 0; } if (R_SUCCEEDED(rc)) { - out_storage = this->romfs_storage; - out_session = new IPCSession<IStorageInterface>(out_storage); + storage = this->romfs_storage; } } else { FsStorage data_storage; FsFile data_file; + + rc = fsOpenDataStorageByCurrentProcessFwd(this->forward_service.get(), &data_storage); - if (this->get_owner() == NULL) { - rc = fsOpenDataStorageByCurrentProcessFwd(this->forward_service, &data_storage); - } else { - rc = fsOpenDataStorageByCurrentProcessFromDomainFwd(this->forward_service, &out_domain_id); - if (R_SUCCEEDED(rc)) { - rc = ipcCopyFromDomain(this->forward_service->handle, out_domain_id, &data_storage.s); - } - } Log(armGetTls(), 0x100); if (R_SUCCEEDED(rc)) { /* TODO: Is there a sensible path that ends in ".romfs" we can use?" */ if (R_SUCCEEDED(Utils::OpenSdFileForAtmosphere(this->title_id, "romfs.bin", FS_OPEN_READ, &data_file))) { - out_storage = std::make_shared<IStorageInterface>(new LayeredRomFS(std::make_shared<RomInterfaceStorage>(data_storage), std::make_shared<RomFileStorage>(data_file), this->title_id)); + storage = std::make_shared<IStorageInterface>(new LayeredRomFS(std::make_shared<RomInterfaceStorage>(data_storage), std::make_shared<RomFileStorage>(data_file), this->title_id)); } else { - out_storage = std::make_shared<IStorageInterface>(new LayeredRomFS(std::make_shared<RomInterfaceStorage>(data_storage), nullptr, this->title_id)); + storage = std::make_shared<IStorageInterface>(new LayeredRomFS(std::make_shared<RomInterfaceStorage>(data_storage), nullptr, this->title_id)); } - this->romfs_storage = out_storage; - out_session = new IPCSession<IStorageInterface>(out_storage); - if (this->get_owner() == NULL) { - FsMitMWorker::AddWaitable(out_session); + this->romfs_storage = storage; + if (out_storage.IsDomain()) { + out_domain_id = data_storage.s.object_id; } } } - OutSession out_s = OutSession(out_session); - out_s.domain_id = out_domain_id; - return {rc, out_s}; + return rc; } /* Add redirection for System Data Archives to the SD card. */ -std::tuple<Result, OutSession<IStorageInterface>> FsMitMService::open_data_storage_by_data_id(u64 sid, u64 data_id) { +Result FsMitmService::OpenDataStorageByDataId(Out<std::shared_ptr<IStorageInterface>> out_storage, u64 data_id, u8 sid) { FsStorageId storage_id = (FsStorageId)sid; - IPCSession<IStorageInterface> *out_session = NULL; FsStorage data_storage; FsFile data_file; + + std::shared_ptr<IStorageInterface> storage = nullptr; u32 out_domain_id = 0; - Result rc; - if (this->get_owner() == NULL) { - rc = fsOpenDataStorageByDataId(this->forward_service, storage_id, data_id, &data_storage); - } else { - rc = fsOpenDataStorageByDataIdFromDomain(this->forward_service, storage_id, data_id, &out_domain_id); + Result rc = 0; + + ON_SCOPE_EXIT { if (R_SUCCEEDED(rc)) { - rc = ipcCopyFromDomain(this->forward_service->handle, out_domain_id, &data_storage.s); + out_storage.SetValue(std::move(storage)); + if (out_storage.IsDomain()) { + out_storage.ChangeObjectId(out_domain_id); + } } - } + }; + + rc = fsOpenDataStorageByDataIdFwd(this->forward_service.get(), storage_id, data_id, &data_storage); + if (R_SUCCEEDED(rc)) { /* TODO: Is there a sensible path that ends in ".romfs" we can use?" */ if (R_SUCCEEDED(Utils::OpenSdFileForAtmosphere(data_id, "romfs.bin", FS_OPEN_READ, &data_file))) { - out_session = new IPCSession<IStorageInterface>(std::make_shared<IStorageInterface>(new LayeredRomFS(std::make_shared<RomInterfaceStorage>(data_storage), std::make_shared<RomFileStorage>(data_file), data_id))); + storage = std::make_shared<IStorageInterface>(new LayeredRomFS(std::make_shared<RomInterfaceStorage>(data_storage), std::make_shared<RomFileStorage>(data_file), data_id)); } else { - out_session = new IPCSession<IStorageInterface>(std::make_shared<IStorageInterface>(new LayeredRomFS(std::make_shared<RomInterfaceStorage>(data_storage), nullptr, data_id))); + storage = std::make_shared<IStorageInterface>(new LayeredRomFS(std::make_shared<RomInterfaceStorage>(data_storage), nullptr, data_id)); } - if (this->get_owner() == NULL) { - FsMitMWorker::AddWaitable(out_session); + if (out_storage.IsDomain()) { + out_domain_id = data_storage.s.object_id; } } - OutSession out_s = OutSession(out_session); - out_s.domain_id = out_domain_id; - return {rc, out_s}; + return rc; } \ No newline at end of file diff --git a/stratosphere/fs_mitm/source/fsmitm_service.hpp b/stratosphere/fs_mitm/source/fsmitm_service.hpp index b1bd62d9c..75dc7b426 100644 --- a/stratosphere/fs_mitm/source/fsmitm_service.hpp +++ b/stratosphere/fs_mitm/source/fsmitm_service.hpp @@ -16,49 +16,41 @@ #pragma once #include <switch.h> -#include <stratosphere/iserviceobject.hpp> -#include "imitmserviceobject.hpp" +#include <stratosphere.hpp> #include "fs_istorage.hpp" #include "fsmitm_utils.hpp" -enum class FspSrvCmd { - SetCurrentProcess = 1, - OpenDataStorageByCurrentProcess = 200, - OpenDataStorageByDataId = 202, +enum FspSrvCmd : u32 { + FspSrvCmd_SetCurrentProcess = 1, + FspSrvCmd_OpenDataStorageByCurrentProcess = 200, + FspSrvCmd_OpenDataStorageByDataId = 202, }; -class FsMitMService : public IMitMServiceObject { +class FsMitmService : public IMitmServiceObject { private: bool has_initialized = false; - u64 init_pid = 0; std::shared_ptr<IStorageInterface> romfs_storage; public: - FsMitMService(Service *s) : IMitMServiceObject(s) { + FsMitmService(std::shared_ptr<Service> s) : IMitmServiceObject(s) { /* ... */ } - static bool should_mitm(u64 pid, u64 tid) { - return tid >= 0x0100000000010000ULL || Utils::HasSdMitMFlag(tid); + static bool ShouldMitm(u64 pid, u64 tid) { + if (Utils::HasSdDisableMitMFlag(tid)) { + return false; + } + return (tid >= 0x0100000000010000ULL || Utils::HasSdMitMFlag(tid)) && Utils::HasOverrideButton(tid); } - FsMitMService *clone() override { - auto new_srv = new FsMitMService((Service *)&this->forward_service); - this->clone_to(new_srv); - return new_srv; - } - - void clone_to(void *o) override { - FsMitMService *other = (FsMitMService *)o; - other->has_initialized = has_initialized; - other->init_pid = init_pid; - } - - virtual Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size); - virtual void postprocess(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size); - virtual Result handle_deferred(); - + static void PostProcess(IMitmServiceObject *obj, IpcResponseContext *ctx); + protected: /* Overridden commands. */ - std::tuple<Result, OutSession<IStorageInterface>> open_data_storage_by_current_process(); - std::tuple<Result, OutSession<IStorageInterface>> open_data_storage_by_data_id(u64 storage_id, u64 data_id); + Result OpenDataStorageByCurrentProcess(Out<std::shared_ptr<IStorageInterface>> out); + Result OpenDataStorageByDataId(Out<std::shared_ptr<IStorageInterface>> out, u64 data_id, u8 storage_id); + public: + DEFINE_SERVICE_DISPATCH_TABLE { + MakeServiceCommandMeta<FspSrvCmd_OpenDataStorageByCurrentProcess, &FsMitmService::OpenDataStorageByCurrentProcess>(), + MakeServiceCommandMeta<FspSrvCmd_OpenDataStorageByDataId, &FsMitmService::OpenDataStorageByDataId>(), + }; }; diff --git a/stratosphere/fs_mitm/source/fsmitm_utils.cpp b/stratosphere/fs_mitm/source/fsmitm_utils.cpp index a98a1b739..aa22bb5c3 100644 --- a/stratosphere/fs_mitm/source/fsmitm_utils.cpp +++ b/stratosphere/fs_mitm/source/fsmitm_utils.cpp @@ -18,14 +18,23 @@ #include <stratosphere.hpp> #include <atomic> #include <algorithm> +#include <strings.h> -#include "sm_mitm.h" #include "debug.hpp" #include "fsmitm_utils.hpp" +#include "ini.h" static FsFileSystem g_sd_filesystem = {0}; static std::vector<u64> g_mitm_flagged_tids; +static std::vector<u64> g_disable_mitm_flagged_tids; static std::atomic_bool g_has_initialized = false; +static std::atomic_bool g_has_hid_session = false; + +static u64 g_override_key_combination = KEY_R; +static bool g_override_by_default = true; + +/* Static buffer for loader.ini contents at runtime. */ +static char g_config_ini_data[0x800]; static bool IsHexadecimal(const char *str) { while (*str) { @@ -72,20 +81,45 @@ void Utils::InitializeSdThreadFunc(void *args) { g_mitm_flagged_tids.push_back(title_id); fsFileClose(&f); } + + memset(title_path, 0, sizeof(title_path)); + strcpy(title_path, "/atmosphere/titles/"); + strcat(title_path, dir_entry.name); + strcat(title_path, "/fsmitm_disable.flag"); + if (R_SUCCEEDED(fsFsOpenFile(&g_sd_filesystem, title_path, FS_OPEN_READ, &f))) { + g_disable_mitm_flagged_tids.push_back(title_id); + fsFileClose(&f); + } } } fsDirClose(&titles_dir); } + Utils::RefreshConfiguration(); + g_has_initialized = true; svcExitThread(); } +void Utils::InitializeHidThreadFunc(void *args) { + while (R_FAILED(hidInitialize())) { + svcSleepThread(1000ULL); + } + + g_has_hid_session = true; + + svcExitThread(); +} + bool Utils::IsSdInitialized() { return g_has_initialized; } +bool Utils::IsHidInitialized() { + return g_has_hid_session; +} + Result Utils::OpenSdFile(const char *fn, int flags, FsFile *out) { if (!IsSdInitialized()) { return 0xFA202; @@ -189,3 +223,115 @@ bool Utils::HasSdMitMFlag(u64 tid) { } return false; } + +bool Utils::HasSdDisableMitMFlag(u64 tid) { + if (IsSdInitialized()) { + return std::find(g_disable_mitm_flagged_tids.begin(), g_disable_mitm_flagged_tids.end(), tid) != g_disable_mitm_flagged_tids.end(); + } + return false; +} + +Result Utils::GetKeysDown(u64 *keys) { + if (!Utils::IsHidInitialized()) { + return MAKERESULT(Module_Libnx, LibnxError_InitFail_HID); + } + + hidScanInput(); + *keys = hidKeysDown(CONTROLLER_P1_AUTO); + + return 0x0; +} + +bool Utils::HasOverrideButton(u64 tid) { + if (tid < 0x0100000000010000ULL || !IsSdInitialized()) { + /* Disable button override disable for non-applications. */ + return true; + } + + /* Unconditionally refresh loader.ini contents. */ + RefreshConfiguration(); + + u64 kDown = 0; + bool keys_triggered = (R_SUCCEEDED(GetKeysDown(&kDown)) && ((kDown & g_override_key_combination) != 0)); + return IsSdInitialized() && (g_override_by_default ^ keys_triggered); +} + +static int FsMitMIniHandler(void *user, const char *section, const char *name, const char *value) { + /* Taken and modified, with love, from Rajkosto's implementation. */ + if (strcasecmp(section, "config") == 0) { + if (strcasecmp(name, "override_key") == 0) { + if (value[0] == '!') { + g_override_by_default = true; + value++; + } else { + g_override_by_default = false; + } + + if (strcasecmp(value, "A") == 0) { + g_override_key_combination = KEY_A; + } else if (strcasecmp(value, "B") == 0) { + g_override_key_combination = KEY_B; + } else if (strcasecmp(value, "X") == 0) { + g_override_key_combination = KEY_X; + } else if (strcasecmp(value, "Y") == 0) { + g_override_key_combination = KEY_Y; + } else if (strcasecmp(value, "LS") == 0) { + g_override_key_combination = KEY_LSTICK; + } else if (strcasecmp(value, "RS") == 0) { + g_override_key_combination = KEY_RSTICK; + } else if (strcasecmp(value, "L") == 0) { + g_override_key_combination = KEY_L; + } else if (strcasecmp(value, "R") == 0) { + g_override_key_combination = KEY_R; + } else if (strcasecmp(value, "ZL") == 0) { + g_override_key_combination = KEY_ZL; + } else if (strcasecmp(value, "ZR") == 0) { + g_override_key_combination = KEY_ZR; + } else if (strcasecmp(value, "PLUS") == 0) { + g_override_key_combination = KEY_PLUS; + } else if (strcasecmp(value, "MINUS") == 0) { + g_override_key_combination = KEY_MINUS; + } else if (strcasecmp(value, "DLEFT") == 0) { + g_override_key_combination = KEY_DLEFT; + } else if (strcasecmp(value, "DUP") == 0) { + g_override_key_combination = KEY_DUP; + } else if (strcasecmp(value, "DRIGHT") == 0) { + g_override_key_combination = KEY_DRIGHT; + } else if (strcasecmp(value, "DDOWN") == 0) { + g_override_key_combination = KEY_DDOWN; + } else if (strcasecmp(value, "SL") == 0) { + g_override_key_combination = KEY_SL; + } else if (strcasecmp(value, "SR") == 0) { + g_override_key_combination = KEY_SR; + } else { + g_override_key_combination = 0; + } + } + } else { + return 0; + } + return 1; +} + + +void Utils::RefreshConfiguration() { + FsFile config_file; + if (R_FAILED(fsFsOpenFile(&g_sd_filesystem, "/atmosphere/loader.ini", FS_OPEN_READ, &config_file))) { + return; + } + + u64 size; + if (R_FAILED(fsFileGetSize(&config_file, &size))) { + return; + } + + size = std::min(size, (decltype(size))0x7FF); + + /* Read in string. */ + std::fill(g_config_ini_data, g_config_ini_data + 0x800, 0); + size_t r_s; + fsFileRead(&config_file, 0, g_config_ini_data, size, &r_s); + fsFileClose(&config_file); + + ini_parse_string(g_config_ini_data, FsMitMIniHandler, NULL); +} \ No newline at end of file diff --git a/stratosphere/fs_mitm/source/fsmitm_utils.hpp b/stratosphere/fs_mitm/source/fsmitm_utils.hpp index e1480d0d1..42d547481 100644 --- a/stratosphere/fs_mitm/source/fsmitm_utils.hpp +++ b/stratosphere/fs_mitm/source/fsmitm_utils.hpp @@ -37,4 +37,13 @@ class Utils { /* SD card Initialization + MitM detection. */ static void InitializeSdThreadFunc(void *args); static bool HasSdMitMFlag(u64 tid); + static bool HasSdDisableMitMFlag(u64 tid); + + + static bool IsHidInitialized(); + static void InitializeHidThreadFunc(void *args); + static Result GetKeysDown(u64 *keys); + static bool HasOverrideButton(u64 tid); + private: + static void RefreshConfiguration(); }; \ No newline at end of file diff --git a/stratosphere/fs_mitm/source/fsmitm_worker.cpp b/stratosphere/fs_mitm/source/fsmitm_worker.cpp deleted file mode 100644 index 24cba1168..000000000 --- a/stratosphere/fs_mitm/source/fsmitm_worker.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2018 Atmosphère-NX - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <mutex> -#include <switch.h> -#include <stratosphere.hpp> -#include "fsmitm_worker.hpp" - -static SystemEvent *g_new_waitable_event = NULL; - -static HosMutex g_new_waitable_mutex; -static HosSemaphore g_sema_new_waitable_finish; - -static std::unique_ptr<WaitableManager> g_worker_waiter; - -Result FsMitMWorker::AddWaitableCallback(void *arg, Handle *handles, size_t num_handles, u64 timeout) { - (void)arg; - svcClearEvent(handles[0]); - g_sema_new_waitable_finish.Signal(); - return 0; -} - -void FsMitMWorker::AddWaitable(IWaitable *waitable) { - g_worker_waiter->add_waitable(waitable); - std::scoped_lock lk{g_new_waitable_mutex}; - g_new_waitable_event->signal_event(); - g_sema_new_waitable_finish.Wait(); -} - -void FsMitMWorker::Main(void *arg) { - /* Initialize waitable event. */ - g_new_waitable_event = new SystemEvent(NULL, &FsMitMWorker::AddWaitableCallback); - - /* Make a new waitable manager. */ - g_worker_waiter = std::make_unique<WaitableManager>(U64_MAX); - g_worker_waiter->add_waitable(g_new_waitable_event); - - /* Service processes. */ - g_worker_waiter->process(); -} diff --git a/stratosphere/fs_mitm/source/ini.c b/stratosphere/fs_mitm/source/ini.c new file mode 100644 index 000000000..63626c72d --- /dev/null +++ b/stratosphere/fs_mitm/source/ini.c @@ -0,0 +1,269 @@ +/* inih -- simple .INI file parser + +inih is released under the New BSD license (see LICENSE.txt). Go to the project +home page for more info: + +https://github.com/benhoyt/inih + +*/ + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include <stdio.h> +#include <ctype.h> +#include <string.h> + +#include "ini.h" + +#if !INI_USE_STACK +#include <stdlib.h> +#endif + +#define MAX_SECTION 50 +#define MAX_NAME 50 + +/* Used by ini_parse_string() to keep track of string parsing state. */ +typedef struct { + const char* ptr; + size_t num_left; +} ini_parse_string_ctx; + +/* Strip whitespace chars off end of given string, in place. Return s. */ +static char* rstrip(char* s) +{ + char* p = s + strlen(s); + while (p > s && isspace((unsigned char)(*--p))) + *p = '\0'; + return s; +} + +/* Return pointer to first non-whitespace char in given string. */ +static char* lskip(const char* s) +{ + while (*s && isspace((unsigned char)(*s))) + s++; + return (char*)s; +} + +/* Return pointer to first char (of chars) or inline comment in given string, + or pointer to null at end of string if neither found. Inline comment must + be prefixed by a whitespace character to register as a comment. */ +static char* find_chars_or_comment(const char* s, const char* chars) +{ +#if INI_ALLOW_INLINE_COMMENTS + int was_space = 0; + while (*s && (!chars || !strchr(chars, *s)) && + !(was_space && strchr(INI_INLINE_COMMENT_PREFIXES, *s))) { + was_space = isspace((unsigned char)(*s)); + s++; + } +#else + while (*s && (!chars || !strchr(chars, *s))) { + s++; + } +#endif + return (char*)s; +} + +/* Version of strncpy that ensures dest (size bytes) is null-terminated. */ +static char* strncpy0(char* dest, const char* src, size_t size) +{ + strncpy(dest, src, size - 1); + dest[size - 1] = '\0'; + return dest; +} + +/* See documentation in header file. */ +int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler, + void* user) +{ + /* Uses a fair bit of stack (use heap instead if you need to) */ +#if INI_USE_STACK + char line[INI_MAX_LINE]; + int max_line = INI_MAX_LINE; +#else + char* line; + int max_line = INI_INITIAL_ALLOC; +#endif +#if INI_ALLOW_REALLOC + char* new_line; + int offset; +#endif + char section[MAX_SECTION] = ""; + char prev_name[MAX_NAME] = ""; + + char* start; + char* end; + char* name; + char* value; + int lineno = 0; + int error = 0; + +#if !INI_USE_STACK + line = (char*)malloc(INI_INITIAL_ALLOC); + if (!line) { + return -2; + } +#endif + +#if INI_HANDLER_LINENO +#define HANDLER(u, s, n, v) handler(u, s, n, v, lineno) +#else +#define HANDLER(u, s, n, v) handler(u, s, n, v) +#endif + + /* Scan through stream line by line */ + while (reader(line, max_line, stream) != NULL) { +#if INI_ALLOW_REALLOC + offset = strlen(line); + while (offset == max_line - 1 && line[offset - 1] != '\n') { + max_line *= 2; + if (max_line > INI_MAX_LINE) + max_line = INI_MAX_LINE; + new_line = realloc(line, max_line); + if (!new_line) { + free(line); + return -2; + } + line = new_line; + if (reader(line + offset, max_line - offset, stream) == NULL) + break; + if (max_line >= INI_MAX_LINE) + break; + offset += strlen(line + offset); + } +#endif + + lineno++; + + start = line; +#if INI_ALLOW_BOM + if (lineno == 1 && (unsigned char)start[0] == 0xEF && + (unsigned char)start[1] == 0xBB && + (unsigned char)start[2] == 0xBF) { + start += 3; + } +#endif + start = lskip(rstrip(start)); + + if (strchr(INI_START_COMMENT_PREFIXES, *start)) { + /* Start-of-line comment */ + } +#if INI_ALLOW_MULTILINE + else if (*prev_name && *start && start > line) { + /* Non-blank line with leading whitespace, treat as continuation + of previous name's value (as per Python configparser). */ + if (!HANDLER(user, section, prev_name, start) && !error) + error = lineno; + } +#endif + else if (*start == '[') { + /* A "[section]" line */ + end = find_chars_or_comment(start + 1, "]"); + if (*end == ']') { + *end = '\0'; + strncpy0(section, start + 1, sizeof(section)); + *prev_name = '\0'; + } + else if (!error) { + /* No ']' found on section line */ + error = lineno; + } + } + else if (*start) { + /* Not a comment, must be a name[=:]value pair */ + end = find_chars_or_comment(start, "=:"); + if (*end == '=' || *end == ':') { + *end = '\0'; + name = rstrip(start); + value = end + 1; +#if INI_ALLOW_INLINE_COMMENTS + end = find_chars_or_comment(value, NULL); + if (*end) + *end = '\0'; +#endif + value = lskip(value); + rstrip(value); + + /* Valid name[=:]value pair found, call handler */ + strncpy0(prev_name, name, sizeof(prev_name)); + if (!HANDLER(user, section, name, value) && !error) + error = lineno; + } + else if (!error) { + /* No '=' or ':' found on name[=:]value line */ + error = lineno; + } + } + +#if INI_STOP_ON_FIRST_ERROR + if (error) + break; +#endif + } + +#if !INI_USE_STACK + free(line); +#endif + + return error; +} + +/* See documentation in header file. */ +int ini_parse_file(FILE* file, ini_handler handler, void* user) +{ + return ini_parse_stream((ini_reader)fgets, file, handler, user); +} + +/* See documentation in header file. */ +int ini_parse(const char* filename, ini_handler handler, void* user) +{ + FILE* file; + int error; + + file = fopen(filename, "r"); + if (!file) + return -1; + error = ini_parse_file(file, handler, user); + fclose(file); + return error; +} + +/* An ini_reader function to read the next line from a string buffer. This + is the fgets() equivalent used by ini_parse_string(). */ +static char* ini_reader_string(char* str, int num, void* stream) { + ini_parse_string_ctx* ctx = (ini_parse_string_ctx*)stream; + const char* ctx_ptr = ctx->ptr; + size_t ctx_num_left = ctx->num_left; + char* strp = str; + char c; + + if (ctx_num_left == 0 || num < 2) + return NULL; + + while (num > 1 && ctx_num_left != 0) { + c = *ctx_ptr++; + ctx_num_left--; + *strp++ = c; + if (c == '\n') + break; + num--; + } + + *strp = '\0'; + ctx->ptr = ctx_ptr; + ctx->num_left = ctx_num_left; + return str; +} + +/* See documentation in header file. */ +int ini_parse_string(const char* string, ini_handler handler, void* user) { + ini_parse_string_ctx ctx; + + ctx.ptr = string; + ctx.num_left = strlen(string); + return ini_parse_stream((ini_reader)ini_reader_string, &ctx, handler, + user); +} diff --git a/stratosphere/fs_mitm/source/ini.h b/stratosphere/fs_mitm/source/ini.h new file mode 100644 index 000000000..f45ba40ba --- /dev/null +++ b/stratosphere/fs_mitm/source/ini.h @@ -0,0 +1,130 @@ +/* inih -- simple .INI file parser + +inih is released under the New BSD license (see LICENSE.txt). Go to the project +home page for more info: + +https://github.com/benhoyt/inih + +*/ + +#ifndef __INI_H__ +#define __INI_H__ + +/* Make this header file easier to include in C++ code */ +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdio.h> + +/* Nonzero if ini_handler callback should accept lineno parameter. */ +#ifndef INI_HANDLER_LINENO +#define INI_HANDLER_LINENO 0 +#endif + +/* Typedef for prototype of handler function. */ +#if INI_HANDLER_LINENO +typedef int (*ini_handler)(void* user, const char* section, + const char* name, const char* value, + int lineno); +#else +typedef int (*ini_handler)(void* user, const char* section, + const char* name, const char* value); +#endif + +/* Typedef for prototype of fgets-style reader function. */ +typedef char* (*ini_reader)(char* str, int num, void* stream); + +/* Parse given INI-style file. May have [section]s, name=value pairs + (whitespace stripped), and comments starting with ';' (semicolon). Section + is "" if name=value pair parsed before any section heading. name:value + pairs are also supported as a concession to Python's configparser. + + For each name=value pair parsed, call handler function with given user + pointer as well as section, name, and value (data only valid for duration + of handler call). Handler should return nonzero on success, zero on error. + + Returns 0 on success, line number of first error on parse error (doesn't + stop on first error), -1 on file open error, or -2 on memory allocation + error (only when INI_USE_STACK is zero). +*/ +int ini_parse(const char* filename, ini_handler handler, void* user); + +/* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't + close the file when it's finished -- the caller must do that. */ +int ini_parse_file(FILE* file, ini_handler handler, void* user); + +/* Same as ini_parse(), but takes an ini_reader function pointer instead of + filename. Used for implementing custom or string-based I/O (see also + ini_parse_string). */ +int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler, + void* user); + +/* Same as ini_parse(), but takes a zero-terminated string with the INI data +instead of a file. Useful for parsing INI data from a network socket or +already in memory. */ +int ini_parse_string(const char* string, ini_handler handler, void* user); + +/* Nonzero to allow multi-line value parsing, in the style of Python's + configparser. If allowed, ini_parse() will call the handler with the same + name for each subsequent line parsed. */ +#ifndef INI_ALLOW_MULTILINE +#define INI_ALLOW_MULTILINE 1 +#endif + +/* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of + the file. See http://code.google.com/p/inih/issues/detail?id=21 */ +#ifndef INI_ALLOW_BOM +#define INI_ALLOW_BOM 1 +#endif + +/* Chars that begin a start-of-line comment. Per Python configparser, allow + both ; and # comments at the start of a line by default. */ +#ifndef INI_START_COMMENT_PREFIXES +#define INI_START_COMMENT_PREFIXES ";#" +#endif + +/* Nonzero to allow inline comments (with valid inline comment characters + specified by INI_INLINE_COMMENT_PREFIXES). Set to 0 to turn off and match + Python 3.2+ configparser behaviour. */ +#ifndef INI_ALLOW_INLINE_COMMENTS +#define INI_ALLOW_INLINE_COMMENTS 1 +#endif +#ifndef INI_INLINE_COMMENT_PREFIXES +#define INI_INLINE_COMMENT_PREFIXES ";" +#endif + +/* Nonzero to use stack for line buffer, zero to use heap (malloc/free). */ +#ifndef INI_USE_STACK +#define INI_USE_STACK 1 +#endif + +/* Maximum line length for any line in INI file (stack or heap). Note that + this must be 3 more than the longest line (due to '\r', '\n', and '\0'). */ +#ifndef INI_MAX_LINE +#define INI_MAX_LINE 200 +#endif + +/* Nonzero to allow heap line buffer to grow via realloc(), zero for a + fixed-size buffer of INI_MAX_LINE bytes. Only applies if INI_USE_STACK is + zero. */ +#ifndef INI_ALLOW_REALLOC +#define INI_ALLOW_REALLOC 0 +#endif + +/* Initial size in bytes for heap line buffer. Only applies if INI_USE_STACK + is zero. */ +#ifndef INI_INITIAL_ALLOC +#define INI_INITIAL_ALLOC 200 +#endif + +/* Stop parsing on first error (default is to keep parsing). */ +#ifndef INI_STOP_ON_FIRST_ERROR +#define INI_STOP_ON_FIRST_ERROR 0 +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __INI_H__ */ diff --git a/stratosphere/fs_mitm/source/mitm_query_service.hpp b/stratosphere/fs_mitm/source/mitm_query_service.hpp deleted file mode 100644 index a1153c496..000000000 --- a/stratosphere/fs_mitm/source/mitm_query_service.hpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2018 Atmosphère-NX - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#pragma once -#include <switch.h> -#include <stratosphere/iserviceobject.hpp> - -#include "debug.hpp" - -enum MitMQueryServiceCommand { - MQS_Cmd_ShouldMitm = 65000, - MQS_Cmd_AssociatePidTid = 65001 -}; - -namespace MitMQueryUtils { - Result get_associated_tid_for_pid(u64 pid, u64 *tid); - - void associate_pid_to_tid(u64 pid, u64 tid); -} - - -template <typename T> -class MitMQueryService : public IServiceObject { - public: - MitMQueryService<T> *clone() override { - return new MitMQueryService<T>(); - } - Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) override { - Log(armGetTls(), 0x100); - switch (cmd_id) { - case MQS_Cmd_ShouldMitm: - return WrapIpcCommandImpl<&MitMQueryService::should_mitm>(this, r, out_c, pointer_buffer, pointer_buffer_size); - case MQS_Cmd_AssociatePidTid: - return WrapIpcCommandImpl<&MitMQueryService::associate_pid_tid>(this, r, out_c, pointer_buffer, pointer_buffer_size); - default: - return 0xF601; - } - if (cmd_id == 65000) { - - } else { - return 0xF601; - } - } - Result handle_deferred() override { - /* This service is never deferrable. */ - return 0; - } - - protected: - std::tuple<Result, u64> should_mitm(u64 pid) { - u64 should_mitm = 0; - u64 tid = 0; - if (R_SUCCEEDED(MitMQueryUtils::get_associated_tid_for_pid(pid, &tid))) { - should_mitm = T::should_mitm(pid, tid); - } - return {0, should_mitm}; - } - std::tuple<Result> associate_pid_tid(u64 pid, u64 tid) { - MitMQueryUtils::associate_pid_to_tid(pid, tid); - return {0x0}; - } -}; \ No newline at end of file diff --git a/stratosphere/fs_mitm/source/mitm_server.hpp b/stratosphere/fs_mitm/source/mitm_server.hpp deleted file mode 100644 index 4054dd9ac..000000000 --- a/stratosphere/fs_mitm/source/mitm_server.hpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2018 Atmosphère-NX - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#pragma once -#include <switch.h> -#include <stratosphere.hpp> - -#include "mitm_query_service.hpp" -#include "sm_mitm.h" -#include "mitm_session.hpp" - -#include "debug.hpp" - -template <typename T> -class MitMSession; - -template <typename T> -class MitMServer final : public IServer<T> { - static_assert(std::is_base_of<IServiceObject, T>::value, "Service Objects must derive from IServiceObject"); - private: - char mitm_name[9]; - - public: - MitMServer(ISession<MitMQueryService<T>> **out_query_session, const char *service_name, unsigned int max_s, bool s_d = false) : IServer<T>(service_name, max_s, s_d) { - Handle tmp_hnd; - Handle out_query_h; - Result rc; - - if (R_SUCCEEDED((rc = smGetServiceOriginal(&tmp_hnd, smEncodeName(service_name))))) { - svcCloseHandle(tmp_hnd); - } else { - fatalSimple(rc); - } - strncpy(mitm_name, service_name, 8); - mitm_name[8] = '\x00'; - if (R_FAILED((rc = smMitMInstall(&this->port_handle, &out_query_h, mitm_name)))) { - fatalSimple(rc); - } - *out_query_session = new ServiceSession<MitMQueryService<T>>(NULL, out_query_h, 0); - } - - virtual ~MitMServer() { - if (this->port_handle) { - if (R_FAILED(smMitMUninstall(this->mitm_name))) { - /* TODO: Panic. */ - } - /* svcCloseHandle(port_handle); was called by ~IServer. */ - } - } - - ISession<T> *get_new_session(Handle session_h) override { - return new MitMSession<T>(this, session_h, 0, mitm_name); - } -}; - - diff --git a/stratosphere/fs_mitm/source/mitm_session.hpp b/stratosphere/fs_mitm/source/mitm_session.hpp deleted file mode 100644 index 0d535b529..000000000 --- a/stratosphere/fs_mitm/source/mitm_session.hpp +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Copyright (c) 2018 Atmosphère-NX - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#pragma once -#include <switch.h> -#include <stratosphere.hpp> -#include "imitmserviceobject.hpp" - -#include "mitm_query_service.hpp" -#include "mitm_server.hpp" -#include "fsmitm_worker.hpp" - -#include "debug.hpp" - -template <typename T> -class MitMServer; - -template <typename T> -class MitMSession final : public ISession<T> { - static_assert(std::is_base_of<IMitMServiceObject, T>::value, "MitM Service Objects must derive from IMitMServiceObject"); - - /* This will be for the actual session. */ - Service forward_service; - IpcParsedCommand cur_out_r; - u32 mitm_domain_id = 0; - bool got_first_message; - - public: - MitMSession<T>(MitMServer<T> *s, Handle s_h, Handle c_h, const char *srv) : ISession<T>(s, s_h, c_h, NULL, 0), got_first_message(false) { - this->server = s; - this->server_handle = s_h; - this->client_handle = c_h; - if (R_FAILED(smMitMGetService(&forward_service, srv))) { - /* TODO: Panic. */ - } - size_t pointer_buffer_size = 0; - if (R_FAILED(ipcQueryPointerBufferSize(forward_service.handle, &pointer_buffer_size))) { - /* TODO: Panic. */ - } - this->service_object = std::make_shared<T>(&forward_service); - this->pointer_buffer.resize(pointer_buffer_size); - } - MitMSession<T>(MitMServer<T> *s, Handle s_h, Handle c_h, Handle f_h) : ISession<T>(s, s_h, c_h, NULL, 0), got_first_message(true) { - this->server = s; - this->server_handle = s_h; - this->client_handle = c_h; - serviceCreate(&this->forward_service, f_h); - size_t pointer_buffer_size = 0; - if (R_FAILED(ipcQueryPointerBufferSize(forward_service.handle, &pointer_buffer_size))) { - /* TODO: Panic. */ - } - this->service_object = std::make_shared<T>(&forward_service); - this->pointer_buffer.resize(pointer_buffer_size); - } - - virtual ~MitMSession() { - serviceClose(&forward_service); - } - - Result handle_message(IpcParsedCommand &r) override { - IpcCommand c; - ipcInitialize(&c); - u64 cmd_id = ((u32 *)r.Raw)[2]; - Result retval = 0xF601; - - cur_out_r.NumHandles = 0; - - Log(armGetTls(), 0x100); - - u32 *cmdbuf = (u32 *)armGetTls(); - if (r.CommandType == IpcCommandType_Close) { - Reboot(); - } - - if (r.CommandType == IpcCommandType_Request || r.CommandType == IpcCommandType_RequestWithContext) { - std::shared_ptr<IServiceObject> obj; - if (r.IsDomainMessage) { - obj = this->domain->get_domain_object(r.ThisObjectId); - if (obj != nullptr && r.MessageType == DomainMessageType_Close) { - if (r.ThisObjectId == this->mitm_domain_id) { - Reboot(); - } - this->domain->delete_object(r.ThisObjectId); - struct { - u64 magic; - u64 result; - } *o_resp; - - o_resp = (decltype(o_resp)) ipcPrepareHeaderForDomain(&c, sizeof(*o_resp), 0); - *(DomainMessageHeader *)((uintptr_t)o_resp - sizeof(DomainMessageHeader)) = {0}; - o_resp->magic = SFCO_MAGIC; - o_resp->result = 0x0; - Log(armGetTls(), 0x100); - return o_resp->result; - } - } else { - obj = this->service_object; - } - if (obj != nullptr) { - retval = obj->dispatch(r, c, cmd_id, (u8 *)this->pointer_buffer.data(), this->pointer_buffer.size()); - if (R_SUCCEEDED(retval)) { - if (r.IsDomainMessage) { - ipcParseForDomain(&cur_out_r); - } else { - ipcParse(&cur_out_r); - } - return retval; - } - } - } else if (r.CommandType == IpcCommandType_Control || r.CommandType == IpcCommandType_ControlWithContext) { - /* Ipc Clone Current Object. */ - retval = serviceIpcDispatch(&forward_service); - Log(armGetTls(), 0x100); - if (R_SUCCEEDED(retval)) { - ipcParse(&cur_out_r); - struct { - u64 magic; - u64 result; - } *resp = (decltype(resp))cur_out_r.Raw; - retval = resp->result; - if ((cmd_id == IpcCtrl_Cmd_CloneCurrentObject || cmd_id == IpcCtrl_Cmd_CloneCurrentObjectEx)) { - if (R_SUCCEEDED(retval)) { - Handle s_h; - Handle c_h; - Result rc; - if (R_FAILED((rc = svcCreateSession(&s_h, &c_h, 0, 0)))) { - fatalSimple(rc); - } - - if (cur_out_r.NumHandles != 1) { - Reboot(); - } - - MitMSession<T> *new_sess = new MitMSession<T>((MitMServer<T> *)this->server, s_h, c_h, cur_out_r.Handles[0]); - new_sess->service_object = this->service_object; - - if (this->is_domain) { - new_sess->is_domain = true; - new_sess->domain = this->domain; - new_sess->mitm_domain_id = this->mitm_domain_id; - new_sess->forward_service.type = this->forward_service.type; - new_sess->forward_service.object_id = this->forward_service.object_id; - } - this->get_manager()->add_waitable(new_sess); - ipcSendHandleMove(&c, c_h); - struct { - u64 magic; - u64 result; - } *o_resp; - - o_resp = (decltype(o_resp)) ipcPrepareHeader(&c, sizeof(*o_resp)); - o_resp->magic = SFCO_MAGIC; - o_resp->result = 0x0; - } - } - } - Log(armGetTls(), 0x100); - return retval; - } - - /* 0xF601 --> Dispatch onwards. */ - if (retval == 0xF601) { - /* Patch PID Descriptor, if relevant. */ - if (r.HasPid) { - /* [ctrl 0] [ctrl 1] [handle desc 0] [pid low] [pid high] */ - cmdbuf[4] = 0xFFFE0000UL | (cmdbuf[4] & 0xFFFFUL); - } - - Log(armGetTls(), 0x100); - retval = serviceIpcDispatch(&forward_service); - if (R_SUCCEEDED(retval)) { - if (r.IsDomainMessage) { - ipcParseForDomain(&cur_out_r); - } else { - ipcParse(&cur_out_r); - } - - struct { - u64 magic; - u64 result; - } *resp = (decltype(resp))cur_out_r.Raw; - - retval = resp->result; - } - } - - Log(armGetTls(), 0x100); - Log(&cmd_id, sizeof(u64)); - u64 retval_for_log = retval; - Log(&retval_for_log, sizeof(u64)); - if (R_FAILED(retval)) { - //Reboot(); - } - - return retval; - } - - void postprocess(IpcParsedCommand &r, u64 cmd_id) override { - if (this->active_object == this->service_object && (r.CommandType == IpcCommandType_Request || r.CommandType == IpcCommandType_RequestWithContext)) { - IpcCommand c; - ipcInitialize(&c); - this->service_object->postprocess(cur_out_r, c, cmd_id, (u8 *)this->pointer_buffer.data(), this->pointer_buffer.size()); - } else if (r.CommandType == IpcCommandType_Control || r.CommandType == IpcCommandType_ControlWithContext) { - if (cmd_id == IpcCtrl_Cmd_ConvertCurrentObjectToDomain) { - this->is_domain = true; - this->domain = std::make_shared<DomainOwner>(); - struct { - u64 magic; - u64 result; - u32 domain_id; - } *resp = (decltype(resp))cur_out_r.Raw; - Result rc; - if (R_FAILED((rc = this->domain->set_object(this->service_object, resp->domain_id)))) { - fatalSimple(rc); - } - this->mitm_domain_id = resp->domain_id; - this->forward_service.type = ServiceType_Domain; - this->forward_service.object_id = resp->domain_id; - } - } - } - - void cleanup() override { - /* Clean up copy handles. */ - for (unsigned int i = 0; i < cur_out_r.NumHandles; i++) { - if (cur_out_r.WasHandleCopied[i]) { - svcCloseHandle(cur_out_r.Handles[i]); - } - } - } -}; diff --git a/stratosphere/libstratosphere/Makefile b/stratosphere/libstratosphere/Makefile index ff0e010e7..70ba1949b 100644 --- a/stratosphere/libstratosphere/Makefile +++ b/stratosphere/libstratosphere/Makefile @@ -18,7 +18,7 @@ include $(DEVKITPRO)/libnx/switch_rules TARGET := $(notdir $(CURDIR)) SOURCES := source DATA := data -INCLUDES := include +INCLUDES := include ../../common/include #--------------------------------------------------------------------------------- # options for code generation diff --git a/stratosphere/libstratosphere/include/boost/callable_traits.hpp b/stratosphere/libstratosphere/include/boost/callable_traits.hpp deleted file mode 100644 index 87f0fa622..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits.hpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_BOOST_CLBL_TRTS_HPP -#define BOOST_CLBL_TRTS_BOOST_CLBL_TRTS_HPP - -#include <boost/callable_traits/detail/core.hpp> -#include <boost/callable_traits/add_member_const.hpp> -#include <boost/callable_traits/add_member_cv.hpp> -#include <boost/callable_traits/add_member_lvalue_reference.hpp> -#include <boost/callable_traits/add_member_rvalue_reference.hpp> -#include <boost/callable_traits/add_member_volatile.hpp> -#include <boost/callable_traits/add_noexcept.hpp> -#include <boost/callable_traits/add_transaction_safe.hpp> -#include <boost/callable_traits/add_varargs.hpp> -#include <boost/callable_traits/apply_member_pointer.hpp> -#include <boost/callable_traits/apply_return.hpp> -#include <boost/callable_traits/args.hpp> -#include <boost/callable_traits/class_of.hpp> -#include <boost/callable_traits/function_type.hpp> -#include <boost/callable_traits/has_member_qualifiers.hpp> -#include <boost/callable_traits/has_varargs.hpp> -#include <boost/callable_traits/has_void_return.hpp> -#include <boost/callable_traits/is_const_member.hpp> -#include <boost/callable_traits/is_invocable.hpp> -#include <boost/callable_traits/is_lvalue_reference_member.hpp> -#include <boost/callable_traits/is_reference_member.hpp> -#include <boost/callable_traits/is_rvalue_reference_member.hpp> -#include <boost/callable_traits/is_noexcept.hpp> -#include <boost/callable_traits/is_transaction_safe.hpp> -#include <boost/callable_traits/is_volatile_member.hpp> -#include <boost/callable_traits/qualified_class_of.hpp> -#include <boost/callable_traits/remove_member_const.hpp> -#include <boost/callable_traits/remove_member_cv.hpp> -#include <boost/callable_traits/remove_member_reference.hpp> -#include <boost/callable_traits/remove_member_volatile.hpp> -#include <boost/callable_traits/remove_noexcept.hpp> -#include <boost/callable_traits/remove_transaction_safe.hpp> -#include <boost/callable_traits/remove_varargs.hpp> -#include <boost/callable_traits/return_type.hpp> - -#endif diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/add_member_const.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/add_member_const.hpp deleted file mode 100644 index cd7280ef8..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/add_member_const.hpp +++ /dev/null @@ -1,105 +0,0 @@ -/* - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_ADD_MEMBER_CONST_HPP -#define BOOST_CLBL_TRTS_ADD_MEMBER_CONST_HPP - -#include <boost/callable_traits/detail/core.hpp> - -namespace boost { namespace callable_traits { - -//[ add_member_const_hpp -/*` -[section:ref_add_member_const add_member_const] -[heading Header] -``#include <boost/callable_traits/add_member_const.hpp>`` -[heading Definition] -*/ - -template<typename T> -using add_member_const_t = //see below -//<- -#ifdef BOOST_CLBL_TRTS_DISABLE_ABOMINABLE_FUNCTIONS - - detail::sfinae_try< - typename detail::traits<T>::add_member_const, - - detail::fail_when_same<typename detail::traits<T>::add_member_const, - detail::abominable_functions_not_supported_on_this_compiler, - this_compiler_doesnt_support_abominable_function_types>, - - detail::fail_if_invalid<typename detail::traits<T>::add_member_const, - member_qualifiers_are_illegal_for_this_type>>; -#else - - detail::try_but_fail_if_invalid< - typename detail::traits<T>::add_member_const, - member_qualifiers_are_illegal_for_this_type>; - -#endif // #ifdef BOOST_CLBL_TRTS_DISABLE_ABOMINABLE_FUNCTIONS - -namespace detail { - - template<typename T, typename = std::false_type> - struct add_member_const_impl {}; - - template<typename T> - struct add_member_const_impl <T, typename std::is_same< - add_member_const_t<T>, detail::dummy>::type> - { - using type = add_member_const_t<T>; - }; -} - -//-> - -template<typename T> -struct add_member_const : detail::add_member_const_impl<T> {}; - -//<- -}} // namespace boost::callable_traits -//-> - - -/*` -[heading Constraints] -* `T` must be a function type or a member function pointer type -* If `T` is a pointer, it may not be cv/ref qualified - -[heading Behavior] -* A substitution failure occurs if the constraints are violated. -* Adds a member `const` qualifier to `T`, if not already present. - -[heading Input/Output Examples] -[table - [[`T`] [`add_member_const_t<T>`]] - [[`int()`] [`int() const`]] - [[`int(foo::*)()`] [`int(foo::*)() const`]] - [[`int(foo::*)() &`] [`int(foo::*)() const &`]] - [[`int(foo::*)() &&`] [`int(foo::*)() const &&`]] - [[`int(foo::*)() const`] [`int(foo::*)() const`]] - [[`int(foo::*)() volatile`] [`int(foo::*)() const volatile`]] - [[`int(foo::*)() transaction_safe`] [`int(foo::*)() const transaction_safe`]] - [[`int`] [(substitution failure)]] - [[`int (&)()`] [(substitution failure)]] - [[`int (*)()`] [(substitution failure)]] - [[`int foo::*`] [(substitution failure)]] - [[`int (foo::* const)()`] [(substitution failure)]] -] - -[heading Example Program] -[import ../example/add_member_const.cpp] -[add_member_const] -[endsect] -*/ -//] - -#endif // #ifndef BOOST_CLBL_TRTS_ADD_MEMBER_CONST_HPP - - - diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/add_member_cv.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/add_member_cv.hpp deleted file mode 100644 index e11cc0754..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/add_member_cv.hpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_ADD_MEMBER_CV_HPP -#define BOOST_CLBL_TRTS_ADD_MEMBER_CV_HPP - -#include <boost/callable_traits/detail/core.hpp> - -namespace boost { namespace callable_traits { - -//[ add_member_cv_hpp -/*` -[section:ref_add_member_cv add_member_cv] -[heading Header] -``#include <boost/callable_traits/add_member_cv.hpp>`` -[heading Definition] -*/ - -template<typename T> -using add_member_cv_t = //see below -//<- -#ifdef BOOST_CLBL_TRTS_DISABLE_ABOMINABLE_FUNCTIONS - - detail::sfinae_try< - typename detail::traits<T>::add_member_cv, - - detail::fail_when_same<typename detail::traits<T>::add_member_cv, - detail::abominable_functions_not_supported_on_this_compiler, - this_compiler_doesnt_support_abominable_function_types>, - - detail::fail_if_invalid<typename detail::traits<T>::add_member_cv, - member_qualifiers_are_illegal_for_this_type>>; -#else - - detail::try_but_fail_if_invalid< - typename detail::traits<T>::add_member_cv, - member_qualifiers_are_illegal_for_this_type>; - -#endif // #ifdef BOOST_CLBL_TRTS_DISABLE_ABOMINABLE_FUNCTIONS - -namespace detail { - - template<typename T, typename = std::false_type> - struct add_member_cv_impl {}; - - template<typename T> - struct add_member_cv_impl <T, typename std::is_same< - add_member_cv_t<T>, detail::dummy>::type> - { - using type = add_member_cv_t<T>; - }; -} - -//-> - -template<typename T> -struct add_member_cv : detail::add_member_cv_impl<T> {}; - -//<- -}} // namespace boost::callable_traits -//-> - -/*` -[heading Constraints] -* `T` must be a function type or a member function pointer type -* If `T` is a pointer, it may not be cv/ref qualified - -[heading Behavior] -* A substitution failure occurs if the constraints are violated. -* Adds member `const` and `volatile` qualifiers to `T`, if not already present. - -[heading Input/Output Examples] -[table - [[`T`] [`add_member_cv_t<T>`]] - [[`int()`] [`int() const volatile`]] - [[`int(foo::*)()`] [`int(foo::*)() const volatile`]] - [[`int(foo::*)() &`] [`int(foo::*)() const volatile &`]] - [[`int(foo::*)() &&`] [`int(foo::*)() const volatile &&`]] - [[`int(foo::*)() const`] [`int(foo::*)() const volatile`]] - [[`int(foo::*)() volatile`] [`int(foo::*)() const volatile`]] - [[`int(foo::*)() transaction_safe`] [`int(foo::*)() const volatile transaction_safe`]] - [[`int`] [(substitution failure)]] - [[`int (&)()`] [(substitution failure)]] - [[`int (*)()`] [(substitution failure)]] - [[`int foo::*`] [(substitution failure)]] - [[`int (foo::* const)()`] [(substitution failure)]] -] - -[heading Example Program] -[import ../example/add_member_cv.cpp] -[add_member_cv] -[endsect] -*/ -//] - -#endif diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/add_member_lvalue_reference.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/add_member_lvalue_reference.hpp deleted file mode 100644 index e23d71a00..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/add_member_lvalue_reference.hpp +++ /dev/null @@ -1,114 +0,0 @@ -/* - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_ADD_MEMBER_LVALUE_REFERENCE_HPP -#define BOOST_CLBL_TRTS_ADD_MEMBER_LVALUE_REFERENCE_HPP - -#include <boost/callable_traits/detail/core.hpp> - -namespace boost { namespace callable_traits { - -//[ add_member_lvalue_reference_hpp -/*` -[section:ref_add_member_lvalue_reference add_member_lvalue_reference] -[heading Header] -``#include <boost/callable_traits/add_member_lvalue_reference.hpp>`` -[heading Definition] -*/ - -#ifdef BOOST_CLBL_TRTS_DISABLE_REFERENCE_QUALIFIERS - -template<typename T> -struct add_member_lvalue_reference_t { - static_assert(std::is_same<T, detail::dummy>::value, - "Reference member qualifiers are not supported by this configuration."); -}; - -#else - -template<typename T> -using add_member_lvalue_reference_t = //see below -//<- -#ifdef BOOST_CLBL_TRTS_DISABLE_ABOMINABLE_FUNCTIONS - - detail::sfinae_try< - typename detail::traits<T>::add_member_lvalue_reference, - - detail::fail_when_same<typename detail::traits<T>::add_member_lvalue_reference, - detail::abominable_functions_not_supported_on_this_compiler, - this_compiler_doesnt_support_abominable_function_types>, - - detail::fail_if_invalid< - typename detail::traits<T>::add_member_lvalue_reference, - member_qualifiers_are_illegal_for_this_type>>; -#else - - detail::try_but_fail_if_invalid< - typename detail::traits<T>::add_member_lvalue_reference, - member_qualifiers_are_illegal_for_this_type>; - -#endif // #ifdef BOOST_CLBL_TRTS_DISABLE_ABOMINABLE_FUNCTIONS -#endif // #ifdef BOOST_CLBL_TRTS_DISABLE_REFERENCE_QUALIFIERS - -namespace detail { - - template<typename T, typename = std::false_type> - struct add_member_lvalue_reference_impl {}; - - template<typename T> - struct add_member_lvalue_reference_impl <T, typename std::is_same< - add_member_lvalue_reference_t<T>, detail::dummy>::type> - { - using type = add_member_lvalue_reference_t<T>; - }; -} -//-> - -template<typename T> -struct add_member_lvalue_reference - : detail::add_member_lvalue_reference_impl<T> {}; - -//<- -}} // namespace boost::callable_traits -//-> - -/*` -[heading Constraints] -* `T` must be a function type or a member function pointer type -* If `T` is a pointer, it may not be cv/ref qualified - -[heading Behavior] -* A substitution failure occurs if the constraints are violated. -* Adds a member lvalue reference qualifier (`&`) to `T`, if not already present. -* If an rvalue reference qualifier is present, the lvalue reference qualifier replaces it (in accordance with reference collapsing rules). - -[heading Input/Output Examples] -[table - [[`T`] [`add_member_lvalue_reference_t<T>`]] - [[`int()`] [`int() &`]] - [[`int(foo::*)()`] [`int(foo::*)() &`]] - [[`int(foo::*)() &`] [`int(foo::*)() &`]] - [[`int(foo::*)() &&`] [`int(foo::*)() &`]] - [[`int(foo::*)() const`] [`int(foo::*)() const &`]] - [[`int(foo::*)() transaction_safe`] [`int(foo::*)() & transaction_safe`]] - [[`int`] [(substitution failure)]] - [[`int (&)()`] [(substitution failure)]] - [[`int (*)()`] [(substitution failure)]] - [[`int foo::*`] [(substitution failure)]] - [[`int (foo::* const)()`] [(substitution failure)]] -] - -[heading Example Program] -[import ../example/add_member_lvalue_reference.cpp] -[add_member_lvalue_reference] -[endsect] -*/ -//] - -#endif - diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/add_member_rvalue_reference.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/add_member_rvalue_reference.hpp deleted file mode 100644 index 84e3c5eaf..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/add_member_rvalue_reference.hpp +++ /dev/null @@ -1,113 +0,0 @@ -/* - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_ADD_MEMBER_RVALUE_REFERENCE_HPP -#define BOOST_CLBL_TRTS_ADD_MEMBER_RVALUE_REFERENCE_HPP - -#include <boost/callable_traits/detail/core.hpp> - -namespace boost { namespace callable_traits { - -//[ add_member_rvalue_reference_hpp -/*` -[section:ref_add_member_rvalue_reference add_member_rvalue_reference] -[heading Header] -``#include <boost/callable_traits/add_member_rvalue_reference.hpp>`` -[heading Definition] -*/ - -#ifdef BOOST_CLBL_TRTS_DISABLE_REFERENCE_QUALIFIERS - -template<typename T> -struct add_member_rvalue_reference_t { - static_assert(std::is_same<T, detail::dummy>::value, - "Reference member qualifiers are not supported by this configuration."); -}; - -#else - -template<typename T> -using add_member_rvalue_reference_t = //see below -//<- -#ifdef BOOST_CLBL_TRTS_DISABLE_ABOMINABLE_FUNCTIONS - - detail::sfinae_try< - typename detail::traits<T>::add_member_rvalue_reference, - - detail::fail_when_same<typename detail::traits<T>::add_member_rvalue_reference, - detail::abominable_functions_not_supported_on_this_compiler, - this_compiler_doesnt_support_abominable_function_types>, - - detail::fail_if_invalid<typename detail::traits<T>::add_member_rvalue_reference, - member_qualifiers_are_illegal_for_this_type>>; -#else - - detail::try_but_fail_if_invalid< - typename detail::traits<T>::add_member_rvalue_reference, - member_qualifiers_are_illegal_for_this_type>; - -#endif // #ifdef BOOST_CLBL_TRTS_DISABLE_ABOMINABLE_FUNCTIONS -#endif // #ifdef BOOST_CLBL_TRTS_DISABLE_REFERENCE_QUALIFIERS - -namespace detail { - - template<typename T, typename = std::false_type> - struct add_member_rvalue_reference_impl {}; - - template<typename T> - struct add_member_rvalue_reference_impl <T, typename std::is_same< - add_member_rvalue_reference_t<T>, detail::dummy>::type> - { - using type = add_member_rvalue_reference_t<T>; - }; -} -//-> - - -template<typename T> -struct add_member_rvalue_reference - : detail::add_member_rvalue_reference_impl<T> {}; - -//<- -}} // namespace boost::callable_traits -//-> - -/*` -[heading Constraints] -* `T` must be a function type or a member function pointer type -* If `T` is a pointer, it may not be cv/ref qualified - -[heading Behavior] -* A substitution failure occurs if the constraints are violated. -* Adds a member rvalue reference qualifier (`&&`) to `T`, if not already present. -* If an lvalue reference qualifier is present, the lvalue reference qualifier remains (in accordance with reference collapsing rules). - -[heading Input/Output Examples] -[table - [[`T`] [`add_member_rvalue_reference_t<T>`]] - [[`int()`] [`int() &&`]] - [[`int(foo::*)()`] [`int(foo::*)() &&`]] - [[`int(foo::*)() &`] [`int(foo::*)() &`]] - [[`int(foo::*)() &&`] [`int(foo::*)() &&`]] - [[`int(foo::*)() const`] [`int(foo::*)() const &&`]] - [[`int(foo::*)() transaction_safe`] [`int(foo::*)() && transaction_safe`]] - [[`int`] [(substitution failure)]] - [[`int (&)()`] [(substitution failure)]] - [[`int (*)()`] [(substitution failure)]] - [[`int foo::*`] [(substitution failure)]] - [[`int (foo::* const)()`] [(substitution failure)]] -] - -[heading Example Program] -[import ../example/add_member_rvalue_reference.cpp] -[add_member_rvalue_reference] -[endsect][/section:ref_add_member_rvalue_reference] -*/ -//] - -#endif diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/add_member_volatile.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/add_member_volatile.hpp deleted file mode 100644 index cb0a508a6..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/add_member_volatile.hpp +++ /dev/null @@ -1,100 +0,0 @@ -/* - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_ADD_MEMBER_VOLATILE_HPP -#define BOOST_CLBL_TRTS_ADD_MEMBER_VOLATILE_HPP - -#include <boost/callable_traits/detail/core.hpp> - -namespace boost { namespace callable_traits { - -//[ add_member_volatile_hpp -/*` -[section:ref_add_member_volatile add_member_volatile] -[heading Header] -``#include <boost/callable_traits/add_member_volatile.hpp>`` -[heading Definition] -*/ - -template<typename T> -using add_member_volatile_t = //see below -//<- -#ifdef BOOST_CLBL_TRTS_DISABLE_ABOMINABLE_FUNCTIONS - - detail::sfinae_try< - typename detail::traits<T>::add_member_volatile, - - detail::fail_when_same<typename detail::traits<T>::add_member_volatile, - detail::abominable_functions_not_supported_on_this_compiler, - this_compiler_doesnt_support_abominable_function_types>, - - detail::fail_if_invalid< - typename detail::traits<T>::add_member_volatile, - member_qualifiers_are_illegal_for_this_type>>; -#else - - detail::try_but_fail_if_invalid< - typename detail::traits<T>::add_member_volatile, - member_qualifiers_are_illegal_for_this_type>; - -#endif // #ifdef BOOST_CLBL_TRTS_DISABLE_ABOMINABLE_FUNCTIONS - -namespace detail { - - template<typename T, typename = std::false_type> - struct add_member_volatile_impl {}; - - template<typename T> - struct add_member_volatile_impl <T, typename std::is_same< - add_member_volatile_t<T>, detail::dummy>::type> - { - using type = add_member_volatile_t<T>; - }; -} -//-> - -template<typename T> -struct add_member_volatile : detail::add_member_volatile_impl<T> {}; - -//<- -}} // namespace boost::callable_traits -//-> - -/*` -[heading Constraints] -* `T` must be a function type or a member function pointer type -* If `T` is a pointer, it may not be cv/ref qualified - -[heading Behavior] -* A substitution failure occurs if the constraints are violated. -* Adds a member volatile qualifier to `T`, if not already present. - -[heading Input/Output Examples] -[table - [[`T`] [`add_member_volatile_t<T>`]] - [[`int()`] [`int() volatile`]] - [[`int(foo::*)()`] [`int(foo::*)() volatile`]] - [[`int(foo::*)() &`] [`int(foo::*)() volatile &`]] - [[`int(foo::*)() &&`] [`int(foo::*)() volatile &&`]] - [[`int(foo::*)() const`] [`int(foo::*)() const volatile`]] - [[`int(foo::*)() transaction_safe`] [`int(foo::*)() volatile transaction_safe`]] - [[`int`] [(substitution failure)]] - [[`int (&)()`] [(substitution failure)]] - [[`int (*)()`] [(substitution failure)]] - [[`int foo::*`] [(substitution failure)]] - [[`int (foo::* const)()`] [(substitution failure)]] -] - -[heading Example Program] -[import ../example/add_member_volatile.cpp] -[add_member_volatile] -[endsect][/section:ref_add_member_volatile] -*/ -//] - -#endif diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/add_noexcept.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/add_noexcept.hpp deleted file mode 100644 index 92b2dc55a..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/add_noexcept.hpp +++ /dev/null @@ -1,108 +0,0 @@ -/* -@file add_noexcept - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_ADD_NOEXCEPT_HPP -#define BOOST_CLBL_TRTS_ADD_NOEXCEPT_HPP - -#include <boost/callable_traits/detail/core.hpp> - -namespace boost { namespace callable_traits { - -BOOST_CLBL_TRTS_DEFINE_SFINAE_ERROR_ORIGIN(add_noexcept) -BOOST_CLBL_TRTS_SFINAE_MSG(add_noexcept, cannot_add_noexcept_to_this_type) - -#ifndef BOOST_CLBL_TRTS_ENABLE_NOEXCEPT_TYPES -template<typename T> -struct add_noexcept_t { - static_assert(std::is_same<T, detail::dummy>::value, - "noexcept types not supported by this configuration."); -}; - -template<typename T> -struct add_noexcept { - static_assert(std::is_same<T, detail::dummy>::value, - "noexcept types not supported by this configuration."); -}; - -#else - -//[ add_noexcept_hpp -/*` -[section:ref_add_noexcept add_noexcept] -[heading Header] -``#include <boost/callable_traits/add_noexcept.hpp>`` -[heading Definition] -*/ - -template<typename T> -using add_noexcept_t = //see below -//<- - detail::try_but_fail_if_invalid< - typename detail::traits<T>::add_noexcept, - cannot_add_noexcept_to_this_type>; - -namespace detail { - - template<typename T, typename = std::false_type> - struct add_noexcept_impl {}; - - template<typename T> - struct add_noexcept_impl <T, typename std::is_same< - add_noexcept_t<T>, detail::dummy>::type> - { - using type = add_noexcept_t<T>; - }; -} -//-> - -template<typename T> -struct add_noexcept : detail::add_noexcept_impl<T> {}; - -//<- -#endif // #ifdef BOOST_CLBL_TRTS_ENABLE_NOEXCEPT_TYPES -}} // namespace boost::callable_traits -//-> - -/*` -[heading Constraints] -* `T` must be one of the following: - * function type - * function pointer type - * function reference type - * member function pointer type -* If `T` is a pointer, it may not be cv/ref qualified - -[heading Behavior] -* A substitution failure occurs if the constraints are violated. -* Adds a `noexcept` specifier to `T`, if not already present. - -[heading Input/Output Examples] -[table - [[`T`] [`add_noexcept_t<T>`]] - [[`int()`] [`int() noexcept`]] - [[`int (&)()`] [`int(&)() noexcept`]] - [[`int (*)()`] [`int(*)() noexcept`]] - [[`int(foo::*)()`] [`int(foo::*)() noexcept`]] - [[`int(foo::*)() &`] [`int(foo::*)() & noexcept`]] - [[`int(foo::*)() &&`] [`int(foo::*)() && noexcept`]] - [[`int(foo::*)() const transaction_safe`] [`int(foo::*)() const transaction_safe noexcept`]] - [[`int(foo::*)() noexcept`] [`int(foo::*)() noexcept`]] - [[`int`] [(substitution failure)]] - [[`int foo::*`] [(substitution failure)]] - [[`int (*&)()`] [(substitution failure)]] -] - -[heading Example Program] -[import ../example/add_noexcept.cpp] -[add_noexcept] -[endsect] -*/ -//] - -#endif // #ifndef BOOST_CLBL_TRTS_ADD_NOEXCEPT_HPP diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/add_transaction_safe.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/add_transaction_safe.hpp deleted file mode 100644 index 2a634ba64..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/add_transaction_safe.hpp +++ /dev/null @@ -1,110 +0,0 @@ -/* -@file add_transaction_safe - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_ADD_TRANSACTION_SAFE_HPP -#define BOOST_CLBL_TRTS_ADD_TRANSACTION_SAFE_HPP - -#include <boost/callable_traits/detail/core.hpp> - -namespace boost { namespace callable_traits { - -BOOST_CLBL_TRTS_DEFINE_SFINAE_ERROR_ORIGIN(add_transaction_safe) -BOOST_CLBL_TRTS_SFINAE_MSG(add_transaction_safe, cannot_add_transaction_safe_to_this_type) - -#ifndef BOOST_CLBL_TRTS_ENABLE_TRANSACTION_SAFE -template<typename T> -struct add_transaction_safe_t { - static_assert(std::is_same<T, detail::dummy>::value, - "transaction_safe not supported by this configuration."); -}; - -template<typename T> -struct add_transaction_safe { - static_assert(std::is_same<T, detail::dummy>::value, - "transaction_safe not supported by this configuration."); -}; - -#else - -//[ add_transaction_safe_hpp -/*` -[section:ref_add_transaction_safe add_transaction_safe] -[heading Header] -``#include <boost/callable_traits/add_transaction_safe.hpp>`` -[heading Definition] -*/ - - -template<typename T> -using add_transaction_safe_t = //see below -//<- - detail::try_but_fail_if_invalid< - typename detail::traits<T>::add_transaction_safe, - cannot_add_transaction_safe_to_this_type>; - -namespace detail { - - template<typename T, typename = std::false_type> - struct add_transaction_safe_impl {}; - - template<typename T> - struct add_transaction_safe_impl <T, typename std::is_same< - add_transaction_safe_t<T>, detail::dummy>::type> - { - using type = add_transaction_safe_t<T>; - }; -} -//-> - -template<typename T> -struct add_transaction_safe - : detail::add_transaction_safe_impl<T> {}; - -//<- -#endif // #ifndef BOOST_CLBL_TRTS_ENABLE_TRANSACTION_SAFE -}} // namespace boost::callable_traits -//-> - -/*` -[heading Constraints] -* `T` must be one of the following: - * function type - * function pointer type - * function reference type - * member function pointer type -* If `T` is a pointer, it may not be cv/ref qualified - -[heading Behavior] -* A substitution failure occurs if the constraints are violated. -* Adds the `transaction_safe` specifier to `T`, if not already present. - -[heading Input/Output Examples] -[table - [[`T`] [`add_transaction_safe_t<T>`]] - [[`int()`] [`int() transaction_safe`]] - [[`int (&)()`] [`int(&)() transaction_safe`]] - [[`int (*)()`] [`int(*)() transaction_safe`]] - [[`int(foo::*)()`] [`int(foo::*)() transaction_safe`]] - [[`int(foo::*)() &`] [`int(foo::*)() & transaction_safe`]] - [[`int(foo::*)() &&`] [`int(foo::*)() && transaction_safe`]] - [[`int(foo::*)() const`] [`int(foo::*)() const transaction_safe`]] - [[`int(foo::*)() transaction_safe`] [`int(foo::*)() transaction_safe`]] - [[`int`] [(substitution failure)]] - [[`int foo::*`] [(substitution failure)]] - [[`int (*&)()`] [(substitution failure)]] -] - -[heading Example Program] -[import ../example/add_transaction_safe.cpp] -[add_transaction_safe] -[endsect] -*/ -//] - -#endif // #ifndef BOOST_CLBL_TRTS_ADD_TRANSACTION_SAFE_HPP diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/add_varargs.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/add_varargs.hpp deleted file mode 100644 index 9357e38ba..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/add_varargs.hpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_ADD_VARARGS_HPP -#define BOOST_CLBL_TRTS_ADD_VARARGS_HPP - -#include <boost/callable_traits/detail/core.hpp> - -namespace boost { namespace callable_traits { - -//[ add_varargs_hpp -/*` -[section:ref_add_varargs add_varargs] -[heading Header] -``#include <boost/callable_traits/add_varargs.hpp>`` -[heading Definition] -*/ - -template<typename T> -using add_varargs_t = //see below -//<- - detail::try_but_fail_if_invalid< - typename detail::traits<T>::add_varargs, - varargs_are_illegal_for_this_type>; - -namespace detail { - - template<typename T, typename = std::false_type> - struct add_varargs_impl {}; - - template<typename T> - struct add_varargs_impl <T, typename std::is_same< - add_varargs_t<T>, detail::dummy>::type> - { - using type = add_varargs_t<T>; - }; -} -//-> - -template<typename T> -struct add_varargs : detail::add_varargs_impl<T> {}; - -//<- -}} // namespace boost::callable_traits -//-> - -/*` -[heading Constraints] -* `T` must be one of the following: - * function type - * function pointer type - * function reference type - * member function pointer type -* If `T` is a pointer, it may not be cv/ref qualified - -[heading Behavior] -* A substitution failure occurs if the constraints are violated. -* Adds C-style variadics (`...`) to the signature of `T`, if not already present. - -[heading Input/Output Examples] -[table - [[`T`] [`add_varargs_t<T>`]] - [[`int()`] [`int(...)`]] - [[`int(int)`] [`int(int, ...)`]] - [[`int (&)()`] [`int(&)(...)`]] - [[`int (*)()`] [`int(*)(...)`]] - [[`int (*)(...)`] [`int(*)(...)`]] - [[`int(foo::*)()`] [`int(foo::*)(...)`]] - [[`int(foo::*)() &`] [`int(foo::*)(...) &`]] - [[`int(foo::*)() &&`] [`int(foo::*)(...) &&`]] - [[`int(foo::*)() const`] [`int(foo::*)(...) const`]] - [[`int(foo::*)() transaction_safe`] [`int(foo::*)(...) transaction_safe`]] - [[`int`] [(substitution failure)]] - [[`int foo::*`] [(substitution failure)]] - [[`int (*&)()`] [(substitution failure)]] -] - -[heading Example Program] -[import ../example/add_varargs.cpp] -[add_varargs] -[endsect] -*/ -//] - -#endif diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/apply_member_pointer.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/apply_member_pointer.hpp deleted file mode 100644 index efd3f9575..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/apply_member_pointer.hpp +++ /dev/null @@ -1,123 +0,0 @@ -/* - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_APPLY_MEMBER_POINTER_HPP -#define BOOST_CLBL_TRTS_APPLY_MEMBER_POINTER_HPP - -#include <boost/callable_traits/detail/core.hpp> - -namespace boost { namespace callable_traits { - -BOOST_CLBL_TRTS_DEFINE_SFINAE_ERROR_ORIGIN(apply_member_pointer) -BOOST_CLBL_TRTS_SFINAE_MSG(apply_member_pointer, members_cannot_have_a_type_of_void) -BOOST_CLBL_TRTS_SFINAE_MSG(apply_member_pointer, second_template_argument_must_be_a_class_or_struct) - -namespace detail { - - template<typename T, typename C, bool = std::is_class<C>::value> - struct make_member_pointer; - - template<typename T, typename C> - struct make_member_pointer<T, C, true> { - using type = typename std::remove_reference<T>::type C::*; - }; - - template<typename C> - struct make_member_pointer<void, C, true> { - using type = invalid_type; - }; - - template<typename T, typename C> - struct make_member_pointer<T, C, false> { - using type = error_type<T>; - }; - - template<typename T, typename C> - using make_member_pointer_t = typename make_member_pointer<T, C>::type; -} - -//[ apply_member_pointer_hpp -/*` -[section:ref_apply_member_pointer apply_member_pointer] -[heading Header] -``#include <boost/callable_traits/apply_member_pointer.hpp>`` -[heading Definition] -*/ - -template<typename T, typename C> -using apply_member_pointer_t = //see below -//<- - detail::sfinae_try< - detail::fallback_if_invalid< - typename detail::traits<T>::template apply_member_pointer<C>, - typename detail::make_member_pointer<T, C>::type>, - - detail::fail_when_same<void, T, members_cannot_have_a_type_of_void>, - - detail::fail_if<!std::is_class<C>::value, - second_template_argument_must_be_a_class_or_struct> >; - -namespace detail { - - template<typename T, typename C, typename = std::false_type> - struct apply_member_pointer_impl {}; - - template<typename T, typename C> - struct apply_member_pointer_impl <T, C, typename std::is_same< - apply_member_pointer_t<T, C>, detail::dummy>::type> - { - using type = apply_member_pointer_t<T, C>; - }; -} - -//-> - -template<typename T, typename C> -struct apply_member_pointer : detail::apply_member_pointer_impl<T, C> {}; - -//<- -}} // namespace boost::callable_traits -//-> - -/*` -[heading Constraints] -* `T` may be any type except `void` -* `C` must be a user-defined type - -[heading Behavior] -* A substitution failure occurs if the constraints are violated. -* When `T` is a function, function pointer (unqualified), or function reference, then the aliased type is a member function pointer of `C` with the same parameters and return type. -* When `T` is a member function pointer (unqualified) of any type, the aliased type is a member function pointer of `C` with the same parameters and return type. -* Otherwise, the aliased type is a member data pointer equivalent to `std::remove_reference_t<T> C::*`. - -[heading Input/Output Examples] -[table - [[`T`] [`apply_member_pointer_t<T, foo>`]] - [[`int()`] [`int(foo::*)()`]] - [[`int (&)()`] [`int(foo::*)()`]] - [[`int (*)()`] [`int(foo::*)()`]] - [[`int(bar::*)()`] [`int(foo::*)()`]] - [[`int(bar::*)() &`] [`int(foo::*)() &`]] - [[`int(bar::*)() &&`] [`int(foo::*)() &&`]] - [[`int(bar::*)() const`] [`int(foo::*)() const`]] - [[`int(bar::*)() transaction_safe`] [`int(foo::*)() transaction_safe`]] - [[`int bar::*`] [`int foo::*`]] - [[`int`] [`int foo::*`]] - [[`int &`] [`int foo::*`]] - [[`const int &`] [`const int foo::*`]] - [[`int (*const)()`] [`int (*const foo::*)()`]] - [[`void`] [(substitution failure)]] -] - -[heading Example Program] -[import ../example/apply_member_pointer.cpp] -[apply_member_pointer] -[endsect] -*/ -//] -#endif diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/apply_return.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/apply_return.hpp deleted file mode 100644 index 6ed5ab74e..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/apply_return.hpp +++ /dev/null @@ -1,109 +0,0 @@ -/* - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_APPLY_RETURN_HPP -#define BOOST_CLBL_TRTS_APPLY_RETURN_HPP - -#include <boost/callable_traits/detail/core.hpp> - -namespace boost { namespace callable_traits { - -BOOST_CLBL_TRTS_DEFINE_SFINAE_ERROR_ORIGIN(apply_return) -BOOST_CLBL_TRTS_SFINAE_MSG(apply_return, invalid_types_for_apply_return) - -namespace detail { - - template<typename T, typename R> - struct apply_return_helper { - using type = typename detail::traits<T>::template apply_return<R>; - }; - - //special case - template<typename... Args, typename R> - struct apply_return_helper<std::tuple<Args...>, R> { - using type = R(Args...); - }; -} - -//[ apply_return_hpp -/*` -[section:ref_apply_return apply_return] -[heading Header] -``#include <boost/callable_traits/apply_return.hpp>`` -[heading Definition] -*/ - -template<typename T, typename R> -using apply_return_t = //see below -//<- - detail::try_but_fail_if_invalid< - typename detail::apply_return_helper<T, R>::type, - invalid_types_for_apply_return>; - -namespace detail { - - template<typename T, typename R, typename = std::false_type> - struct apply_return_impl {}; - - template<typename T, typename R> - struct apply_return_impl <T, R, typename std::is_same< - apply_return_t<T, R>, detail::dummy>::type> - { - using type = apply_return_t<T, R>; - }; -} - //-> - -template<typename T, typename R> -struct apply_return : detail::apply_return_impl<T, R> {}; - -//<- -}} // namespace boost::callable_traits -//-> - -/*` -[heading Constraints] -* `T` must one of the following: - * `std::tuple` template instantiation - * function - * function pointer - * function reference - * member function pointer - * member data pointer -* If `T` is a pointer, it may not be cv/ref qualified - -[heading Behavior] -* When `T` is `std::tuple<Args...>`, the aliased type is `R(Args...)`. -* When `T` is a function, function pointer, function reference, or member function pointer, the aliased type's return type is `R`, but is otherwise identical to `T`. -* When `T` is a member data pointer of class `foo` to a `U` type (such that `T` is `U foo::*`), the aliased type is `R foo::*`. - -[heading Input/Output Examples] -[table - [[`T`] [`apply_return_t<T, float>`]] - [[`std::tuple<int, int>`] [`float(int, int)`]] - [[`int()`] [`float()`]] - [[`int (&)()`] [`float(&)()`]] - [[`int (*)()`] [`float(*)()`]] - [[`int (*)(...)`] [`float(*)()`]] - [[`int(foo::*)()`] [`float(foo::*)()`]] - [[`int(foo::*)() &`] [`float(foo::*)() &`]] - [[`int(foo::*)() &&`] [`float(foo::*)() &&`]] - [[`int(foo::*)() const`] [`float(foo::*)() const`]] - [[`int(foo::*)() transaction_safe`] [`float(foo::*)() transaction_safe`]] - [[`int foo::*`] [`float foo::*`]] - [[`int`] [(substitution failure)]] - [[`int (*const)()`] [(substitution failure)]] -] - -[heading Example Program] -[/import ../example/apply_return.cpp] -[apply_return] -[endsect] -*/ -//] -#endif diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/args.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/args.hpp deleted file mode 100644 index 6dcaaccc1..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/args.hpp +++ /dev/null @@ -1,97 +0,0 @@ -/* - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_ARGS_HPP -#define BOOST_CLBL_TRTS_ARGS_HPP - -#include <boost/callable_traits/detail/core.hpp> - -namespace boost { namespace callable_traits { - -//[ args_hpp -/*`[section:ref_args args] -[heading Header] -``#include <boost/callable_traits/args.hpp>`` -[heading Definition] -*/ - -template<typename T, template<class...> class Container = std::tuple> -using args_t = //see below -//<- - detail::try_but_fail_if_invalid< - typename detail::traits< - detail::shallow_decay<T>>::template expand_args<Container>, - cannot_expand_the_parameter_list_of_first_template_argument>; - -namespace detail { - - template<typename T, template<class...> class Container, - typename = std::false_type> - struct args_impl {}; - - template<typename T, template<class...> class Container> - struct args_impl <T, Container, typename std::is_same< - args_t<T, Container>, detail::dummy>::type> - { - using type = args_t<T, Container>; - }; -} - -//-> - -template<typename T, - template<class...> class Container = std::tuple> -struct args : detail::args_impl<T, Container> {}; - -//<- -}} // namespace boost::callable_traits -//-> - -/*` -[heading Constraints] -* `T` must be one of the following: - * function - * function pointer - * function reference - * member function pointer - * member data pointer - * user-defined type with a non-overloaded `operator()` - * type of a non-generic lambda - -[heading Behavior] -* When the constraints are violated, a substitution failure occurs. -* When `T` is a function, function pointer, or function reference, the aliased type is `Container` instantiated with the function's parameter types. -* When `T` is a function object, the aliased type is `Container` instantiated with the `T::operator()` parameter types. -* When `T` is a member function pointer, the aliased type is a `Container` instantiation, where the first type argument is a reference to the parent class of `T`, qualified according to the member qualifiers on `T`, such that the first type is equivalent to `boost::callable_traits::qualified_class_of_t<T>`. The subsequent type arguments, if any, are the parameter types of the member function. -* When `T` is a member data pointer, the aliased type is `Container` with a single element, which is a `const` reference to the parent class of `T`. - -[heading Input/Output Examples] -[table - [[`T`] [`args_t<T>`]] - [[`void(float, char, int)`] [`std::tuple<float, char, int>`]] - [[`void(*)(float, char, int)`] [`std::tuple<float, char, int`]] - [[`void(&)(float, char, int)`] [`std::tuple<float, char, int`]] - [[`void(float, char, int) const &&`][`std::tuple<float, char, int>`]] - [[`void(*)()`] [`std::tuple<>`]] - [[`void(foo::* const &)(float, char, int)`] [`std::tuple<foo&, float, char, int>`]] - [[`int(foo::*)(int) const`] [`std::tuple<const foo&, int>`]] - [[`void(foo::*)() volatile &&`] [`std::tuple<volatile foo &&>`]] - [[`int foo::*`] [`std::tuple<const foo&>`]] - [[`const int foo::*`] [`std::tuple<const foo&>`]] - [[`int`] [(substitution failure)]] - [[`int (*const)()`] [(substitution failure)]] -] - -[heading Example Program] -[import ../example/args.cpp] -[args] -[endsect] -*/ -//] - -#endif // #ifndef BOOST_CLBL_TRTS_ARGS_HPP diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/class_of.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/class_of.hpp deleted file mode 100644 index a9eee7970..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/class_of.hpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_class_of_HPP -#define BOOST_CLBL_TRTS_class_of_HPP - -#include <boost/callable_traits/detail/core.hpp> - -namespace boost { namespace callable_traits { - -//[ class_of_hpp -/*` -[section:ref_class_of class_of] -[heading Header] -``#include <boost/callable_traits/class_of.hpp>`` -[heading Definition] -*/ - -template<typename T> -using class_of_t = //see below -//<- - detail::try_but_fail_if_invalid< - typename detail::traits<detail::shallow_decay<T>>::class_type, - type_is_not_a_member_pointer>; - -namespace detail { - - template<typename T, typename = std::false_type> - struct class_of_impl {}; - - template<typename T> - struct class_of_impl <T, typename std::is_same< - class_of_t<T>, detail::dummy>::type> - { - using type = class_of_t<T>; - }; -} - -//-> - -template<typename T> -struct class_of : detail::class_of_impl<T> {}; - -//<- -}} // namespace boost::callable_traits -//-> - -/*` -[heading Constraints] -* `T` must be a member pointer - -[heading Behavior] -* A substitution failure occurs if the constraints are violated. -* The aliased type is the parent class of the member. In other words, if `T` is expanded to `U C::*`, the aliased type is `C`. - -[heading Input/Output Examples] -[table - [[`T`] [`class_of_t<T>`]] - [[`int foo::*`] [`foo`]] - [[`void(foo::* const &)() const`] [`foo`]] -] - -[heading Example Program] -[import ../example/class_of.cpp] -[class_of] -[endsect] -*/ -//] - -#endif // #ifndef BOOST_CLBL_TRTS_class_of_HPP diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/detail/config.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/detail/config.hpp deleted file mode 100644 index 946458187..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/detail/config.hpp +++ /dev/null @@ -1,109 +0,0 @@ -/* -@Copyright Barrett Adair 2016-2017 - -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_DETAIL_CONFIG_HPP -#define BOOST_CLBL_TRTS_DETAIL_CONFIG_HPP - -#include <type_traits> -#include <tuple> -#include <utility> -#include <cstdint> - -#define BOOST_CLBL_TRTS_EMPTY_ -#define BOOST_CLBL_TRTS_EMPTY BOOST_CLBL_TRTS_EMPTY_ - -#ifdef __cpp_transactional_memory -# define BOOST_CLBL_TRTS_ENABLE_TRANSACTION_SAFE -#endif - -#ifdef __cpp_inline_variables -# define BOOST_CLBL_TRAITS_INLINE_VAR inline -#else -# define BOOST_CLBL_TRAITS_INLINE_VAR -#endif - -#ifdef __cpp_noexcept_function_type -# define BOOST_CLBL_TRTS_ENABLE_NOEXCEPT_TYPES -#endif - -#ifdef BOOST_CLBL_TRTS_ENABLE_TRANSACTION_SAFE -# define BOOST_CLBL_TRTS_TRANSACTION_SAFE_SPECIFIER transaction_safe -#else -# define BOOST_CLBL_TRTS_TRANSACTION_SAFE_SPECIFIER -#endif - -#ifndef __clang__ -# if defined(__GNUC__) -# define BOOST_CLBL_TRTS_GCC -# if __GNUC__ >= 6 -# define BOOST_CLBL_TRTS_GCC_AT_LEAST_6_0_0 -# endif -# if __GNUC__ < 5 -# define BOOST_CLBL_TRTS_GCC_OLDER_THAN_5_0_0 -# endif -# if __GNUC__ >= 5 -# define BOOST_CLBL_TRTS_GCC_AT_LEAST_4_9_2 -# elif __GNUC__ == 4 && __GNUC_MINOR__ == 9 && __GNUC_PATCHLEVEL__ >= 2 -# define BOOST_CLBL_TRTS_GCC_AT_LEAST_4_9_2 -# else -# define BOOST_CLBL_TRTS_GCC_OLDER_THAN_4_9_2 -# endif //#if __GNUC__ >= 5 -# endif //#if defined __GNUC__ -#endif // #ifndef __clang__ - -#ifdef _MSC_VER -# ifdef __clang__ -# define BOOST_CLBL_TRTS_CLANG_C2 -# else -# define BOOST_CLBL_TRTS_MSVC -# endif // #ifdef __clang__ -#endif // #ifdef _MSC_VER - -#define BOOST_CLBL_TRTS_IX_SEQ(...) ::std::index_sequence< __VA_ARGS__ > -#define BOOST_CLBL_TRTS_MAKE_IX_SEQ(...) ::std::make_index_sequence< __VA_ARGS__ > -#define BOOST_CLBL_TRTS_DISJUNCTION(...) ::std::disjunction< __VA_ARGS__ > - -#ifndef __cpp_variable_templates -# define BOOST_CLBL_TRTS_DISABLE_VARIABLE_TEMPLATES -#endif - -#ifndef __cpp_lib_logical_traits -# include <boost/callable_traits/detail/polyfills/disjunction.hpp> -#endif //__cpp_lib_logical_traits - -#ifndef __cpp_lib_integer_sequence -# include <boost/callable_traits/detail/polyfills/make_index_sequence.hpp> -#endif // __cpp_lib_integer_sequence - -#if defined(BOOST_CLBL_TRTS_MSVC) && !defined(BOOST_DISABLE_WIN32) -# define BOOST_CLBL_TRTS_DEFAULT_VARARGS_CC __cdecl -# define BOOST_CLBL_TRTS_PMF_VARGARGS_CDECL_DEFAULT -#else -# define BOOST_CLBL_TRTS_DEFAULT_VARARGS_CC -#endif // #if defined(BOOST_CLBL_TRTS_MSVC) && !defined(BOOST_DISABLE_WIN32)) - -#if (defined(BOOST_CLBL_TRTS_GCC) && !defined(BOOST_CLBL_TRTS_GCC_AT_LEAST_4_9_2)) || defined(__INTEL_COMPILER) -# define BOOST_CLBL_TRTS_DISABLE_REFERENCE_QUALIFIERS -# define BOOST_CLBL_TRTS_DISABLE_ABOMINABLE_FUNCTIONS -#endif // #if defined BOOST_CLBL_TRTS_GCC && !defined(BOOST_CLBL_TRTS_GCC_AT_LEAST_4_9_2) - -#ifdef BOOST_CLBL_TRTS_DISABLE_ABOMINABLE_FUNCTIONS -# define BOOST_CLBL_TRTS_ABOMINABLE_CONST BOOST_CLBL_TRTS_EMPTY -# define BOOST_CLBL_TRTS_ABOMINABLE_VOLATILE BOOST_CLBL_TRTS_EMPTY -#else -# define BOOST_CLBL_TRTS_ABOMINABLE_CONST const -# define BOOST_CLBL_TRTS_ABOMINABLE_VOLATILE volatile -#endif // #ifdef BOOST_CLBL_TRTS_DISABLE_ABOMINABLE_FUNCTIONS - -#ifdef BOOST_CLBL_TRTS_ENABLE_NOEXCEPT_TYPES -# define BOOST_CLBL_TRTS_NOEXCEPT_SPECIFIER noexcept -#else -# define BOOST_CLBL_TRTS_NOEXCEPT_SPECIFIER BOOST_CLBL_TRTS_EMPTY -#endif // #ifdef BOOST_CLBL_TRTS_ENABLE_NOEXCEPT_TYPES - -#endif // #ifndef BOOST_CLBL_TRTS_DETAIL_CONFIG_HPP diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/detail/core.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/detail/core.hpp deleted file mode 100644 index 77560283b..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/detail/core.hpp +++ /dev/null @@ -1,19 +0,0 @@ -/* - -@Copyright Barrett Adair 2016-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_DETAIL_CORE_HPP -#define BOOST_CLBL_TRTS_DETAIL_CORE_HPP - -#include <boost/callable_traits/detail/utility.hpp> -#include <boost/callable_traits/detail/traits.hpp> -#include <boost/callable_traits/detail/function_object.hpp> -#include <boost/callable_traits/detail/function.hpp> -#include <boost/callable_traits/detail/pmf.hpp> -#include <boost/callable_traits/detail/pmd.hpp> - -#endif // #ifndef BOOST_CLBL_TRTS_DETAIL_CORE_HPP diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/detail/default_callable_traits.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/detail/default_callable_traits.hpp deleted file mode 100644 index 84970783a..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/detail/default_callable_traits.hpp +++ /dev/null @@ -1,207 +0,0 @@ -/* -Copyright Barrett Adair 2016-2017 - -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http ://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_DETAIL_DEFAULT_BOOST_CLBL_TRTS_HPP -#define BOOST_CLBL_TRTS_DETAIL_DEFAULT_BOOST_CLBL_TRTS_HPP - -namespace boost { namespace callable_traits { namespace detail { - -template<typename T = void> -struct default_callable_traits { - - // value is used by all traits classes to participate - // in the <callable_traits/detail/traits.hpp> disjunction. - static constexpr bool value = false; - - // used facilitate the disjunction in - // <callable_traits/detail/traits.hpp> - using traits = default_callable_traits; - - using error_t = error_type<T>; - - // represents the type under consideration - using type = error_t; - - // std::true_type for callables with C-style variadics - using has_varargs = std::false_type; - - using return_type = error_t; - - // arg_types is a std::tuple of argument types for - // callables that are not overloaded/templated function objects. - // arg_types IS defined in terms of INVOKE, which means - // a PMF's arg_types tuple will use a reference to its - // parent class as the first argument, with qualifiers added to - // match the PMF's own qualifiers. - using arg_types = error_t; - - // arg_types without the decltype(*this) parameter for member functions - using non_invoke_arg_types = error_t; - - // An "approximation" of a callable type, in the form - // of a plain function type. Defined in terms of INVOKE. - // An identity alias for qualified/unqualified plain function - // types. - using function_type = error_t; - - // Used to smoothen the edges between PMFs and function objects - using function_object_signature = error_t; - - // An identity alias for qualified/unqualified plain function - // types. Equivalent to remove_member_pointer for PMFs. Same - // as function_type for other callable types. - using qualified_function_type = error_t; - - // Removes C-style variadics from a signature, if present. - // Aliases error_t for function objects and PMDs. - using remove_varargs = error_t; - - // Adds C-style variadics to a signature. Aliases - // error_t for function objects and PMDs. - using add_varargs = error_t; - - // std::true_type when the signature includes noexcept, when - // the feature is available - using is_noexcept = std::false_type; - - // adds noexcept to a signature if the feature is available - using add_noexcept = error_t; - - // removes noexcept from a signature if present - using remove_noexcept = error_t; - - // std::true_type when the signature includes transaction_safe, when - // the feature is available - using is_transaction_safe = std::false_type; - - // adds transaction_safe to a signature if the feature is available - using add_transaction_safe = error_t; - - // removes transaction_safe from a signature if present - using remove_transaction_safe = error_t; - - // The class of a PMD or PMF. error_t for other types - using class_type = error_t; - - // The qualified reference type of class_type. error_t - // for non-member-pointers. - using invoke_type = error_t; - - // Removes reference qualifiers from a signature. - using remove_reference = error_t; - - // Adds an lvalue qualifier to a signature, in arbitrary - // accordance with C++11 reference collapsing rules. - using add_member_lvalue_reference = error_t; - - // Adds an rvalue qualifier to a signature, in arbitrary - // accordance with C++11 reference collapsing rules. - using add_member_rvalue_reference = error_t; - - // Adds a const qualifier to a signature. - using add_member_const = error_t; - - // Adds a volatile qualifier to a signature. - using add_member_volatile = error_t; - - // Adds both const and volatile qualifiers to a signature. - using add_member_cv = error_t; - - // Removes a const qualifier from a signature, if present. - using remove_member_const = error_t; - - // Removes a volatile qualifier from a signature, if present. - using remove_member_volatile = error_t; - - // Removes both const and volatile qualifiers from a - // signature, if any. - using remove_member_cv = error_t; - - // Removes the member pointer from PMDs and PMFs. An identity - // alias for other callable types. - using remove_member_pointer = error_t; - - // Changes the parent class type for PMDs and PMFs. Turns - // function pointers, function references, and - // qualified/unqualified function types into PMFs. Turns - // everything else into member data pointers. - template<typename C, - typename U = T, - typename K = typename std::remove_reference<U>::type, - typename L = typename std::conditional< - std::is_same<void, K>::value, error_t, K>::type, - typename Class = typename std::conditional< - std::is_class<C>::value, C, error_t>::type> - using apply_member_pointer = typename std::conditional< - std::is_same<L, error_t>::value || std::is_same<Class, error_t>::value, - error_t, L Class::*>::type; - - // Changes the return type of PMFs, function pointers, function - // references, and qualified/unqualified function types. Changes - // the data type of PMDs. error_t for function objects. - template<typename> - using apply_return = error_t; - - // Expands the argument types into a template - template<template<class...> class Container> - using expand_args = error_t; - - template<template<class...> class Container, typename... RightArgs> - using expand_args_left = error_t; - - template<template<class...> class Container, typename... LeftArgs> - using expand_args_right = error_t; - - using clear_args = error_t; - - template<typename... NewArgs> - using push_front = error_t; - - template<typename... NewArgs> - using push_back = error_t; - - template<std::size_t ElementCount> - using pop_front = error_t; - - template<std::size_t ElementCount> - using pop_back = error_t; - - template<std::size_t Index, typename... NewArgs> - using insert_args = error_t; - - template<std::size_t Index, std::size_t Count> - using remove_args = error_t; - - template<std::size_t Index, typename... NewArgs> - using replace_args = error_t; - - static constexpr qualifier_flags cv_flags = cv_of<T>::value; - static constexpr qualifier_flags ref_flags = ref_of<T>::value; - static constexpr qualifier_flags q_flags = cv_flags | ref_flags; - - using has_member_qualifiers = std::integral_constant<bool, q_flags != default_>; - using is_const_member = std::integral_constant<bool, 0 < (cv_flags & const_)>; - using is_volatile_member = std::integral_constant<bool, 0 < (cv_flags & volatile_)>; - using is_cv_member = std::integral_constant<bool, cv_flags == (const_ | volatile_)>; - -#ifdef BOOST_CLBL_TRTS_DISABLE_REFERENCE_QUALIFIERS - using is_reference_member = std::false_type; - using is_lvalue_reference_member = std::false_type; - using is_rvalue_reference_member = std::false_type; -#else - using is_reference_member = std::integral_constant<bool, 0 < ref_flags>; - using is_lvalue_reference_member = std::integral_constant<bool, ref_flags == lref_>; - using is_rvalue_reference_member = std::integral_constant<bool, ref_flags == rref_>; -#endif //#ifdef BOOST_CLBL_TRTS_DISABLE_REFERENCE_QUALIFIERS - -}; - -}}} // namespace boost::callable_traits::detail - -#endif // BOOST_CLBL_TRTS_DETAIL_DEFAULT_BOOST_CLBL_TRTS_HPP - diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/detail/forward_declarations.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/detail/forward_declarations.hpp deleted file mode 100644 index 9327759f6..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/detail/forward_declarations.hpp +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef BOOST_CLBL_TRTS_DETAIL_FORWARD_DECLARATIONS -#define BOOST_CLBL_TRTS_DETAIL_FORWARD_DECLARATIONS -#include <boost/callable_traits/detail/config.hpp> -#include <boost/callable_traits/detail/default_callable_traits.hpp> - -namespace boost { namespace callable_traits { namespace detail { - -template<typename T> -struct function; - -template<typename T> -struct has_normal_call_operator -{ - template<typename N, N Value> - struct check { check(std::nullptr_t) {} }; - - template<typename U> - static std::int8_t test( - check<decltype(&U::operator()), &U::operator()>); - - template<typename> - static std::int16_t test(...); - - static constexpr bool value = - sizeof(test<T>(nullptr)) == sizeof(std::int8_t); -}; - -struct callable_dummy { - void operator()() {} -}; - -template<typename T> -using default_to_function_object = typename std::conditional< - has_normal_call_operator<T>::value, - T, callable_dummy>::type; - -template<typename T> -struct pmf; - -template<typename T> -struct pmd; - -template<typename F, typename T = typename std::remove_reference<F>::type> -using function_object_base = typename std::conditional< - has_normal_call_operator<T>::value, - pmf<decltype(&default_to_function_object<T>::operator())>, - default_callable_traits<T>>::type; - -template<typename T, typename Base = function_object_base<T>> -struct function_object; - -}}} // namespace boost::callable_traits::detail - -#endif // #ifndef BOOST_CLBL_TRTS_DETAIL_FORWARD_DECLARATIONS diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/detail/function.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/detail/function.hpp deleted file mode 100644 index 624c704d2..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/detail/function.hpp +++ /dev/null @@ -1,192 +0,0 @@ -/* - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_DETAIL_FUNCTION_HPP -#define BOOST_CLBL_TRTS_DETAIL_FUNCTION_HPP - -#include <boost/callable_traits/detail/config.hpp> -#include <boost/callable_traits/detail/qualifier_flags.hpp> -#include <boost/callable_traits/detail/forward_declarations.hpp> -#include <boost/callable_traits/detail/set_function_qualifiers.hpp> -#include <boost/callable_traits/detail/default_callable_traits.hpp> - -namespace boost { namespace callable_traits { namespace detail { - -template<typename T> -struct function : default_callable_traits<T> {}; - -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS -#define BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS -#include <boost/callable_traits/detail/unguarded/function.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - -#ifndef BOOST_CLBL_TRTS_DISABLE_ABOMINABLE_FUNCTIONS - -#define BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS const -#include <boost/callable_traits/detail/unguarded/function.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - -#define BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS volatile -#include <boost/callable_traits/detail/unguarded/function.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - -#define BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS const volatile -#include <boost/callable_traits/detail/unguarded/function.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - -#ifndef BOOST_CLBL_TRTS_DISABLE_REFERENCE_QUALIFIERS - -#define BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS & -#include <boost/callable_traits/detail/unguarded/function.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - -#define BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS && -#include <boost/callable_traits/detail/unguarded/function.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - -#define BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS const & -#include <boost/callable_traits/detail/unguarded/function.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - -#define BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS const && -#include <boost/callable_traits/detail/unguarded/function.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - -#define BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS volatile & -#include <boost/callable_traits/detail/unguarded/function.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - -#define BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS volatile && -#include <boost/callable_traits/detail/unguarded/function.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - -#define BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS const volatile & -#include <boost/callable_traits/detail/unguarded/function.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - -#define BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS const volatile && -#include <boost/callable_traits/detail/unguarded/function.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - -#endif // #ifndef BOOST_CLBL_TRTS_DISABLE_REFERENCE_QUALIFIERS -#endif // #ifndef BOOST_CLBL_TRTS_DISABLE_ABOMINABLE_FUNCTIONS - -// function pointers - -#define BOOST_CLBL_TRTS_CC_TAG dummy -#define BOOST_CLBL_TRTS_VARARGS_CC BOOST_CLBL_TRTS_DEFAULT_VARARGS_CC -#define BOOST_CLBL_TRTS_CC -#define BOOST_CLBL_TRTS_ST -#include <boost/callable_traits/detail/unguarded/function_ptr.hpp> -#include <boost/callable_traits/detail/unguarded/function_ptr_varargs.hpp> -#undef BOOST_CLBL_TRTS_ST -#undef BOOST_CLBL_TRTS_CC -#undef BOOST_CLBL_TRTS_CC_TAG -#undef BOOST_CLBL_TRTS_VARARGS_CC - -/* ? -#ifdef BOOST_CLBL_TRTS_ENABLE_CDECL -#define BOOST_CLBL_TRTS_CC_TAG cdecl_tag -#define BOOST_CLBL_TRTS_VARARGS_CC __cdecl -#define BOOST_CLBL_TRTS_CC __cdecl -#define BOOST_CLBL_TRTS_ST -#include <boost/callable_traits/detail/unguarded/function_ptr.hpp> -#undef BOOST_CLBL_TRTS_ST -#undef BOOST_CLBL_TRTS_CC -#undef BOOST_CLBL_TRTS_CC_TAG -#undef BOOST_CLBL_TRTS_VARARGS_CC -#endif*/ - -#ifdef BOOST_CLBL_TRTS_ENABLE_STDCALL -#define BOOST_CLBL_TRTS_CC_TAG stdcall_tag -#define BOOST_CLBL_TRTS_VARARGS_CC BOOST_CLBL_TRTS_DEFAULT_VARARGS_CC -#define BOOST_CLBL_TRTS_CC __stdcall -#define BOOST_CLBL_TRTS_ST -#include <boost/callable_traits/detail/unguarded/function_ptr.hpp> -#undef BOOST_CLBL_TRTS_ST -#undef BOOST_CLBL_TRTS_CC -#undef BOOST_CLBL_TRTS_CC_TAG -#undef BOOST_CLBL_TRTS_VARARGS_CC -#endif - -#ifdef BOOST_CLBL_TRTS_ENABLE_FASTCALL -#define BOOST_CLBL_TRTS_CC_TAG fastcall_tag -#define BOOST_CLBL_TRTS_VARARGS_CC BOOST_CLBL_TRTS_DEFAULT_VARARGS_CC -#define BOOST_CLBL_TRTS_CC __fastcall -#define BOOST_CLBL_TRTS_ST -#include <boost/callable_traits/detail/unguarded/function_ptr.hpp> -#undef BOOST_CLBL_TRTS_CC -#undef BOOST_CLBL_TRTS_ST -#undef BOOST_CLBL_TRTS_CC_TAG -#undef BOOST_CLBL_TRTS_VARARGS_CC -#endif - -#ifdef BOOST_CLBL_TRTS_ENABLE_PASCAL -#define BOOST_CLBL_TRTS_CC_TAG pascal_tag -#define BOOST_CLBL_TRTS_VARARGS_CC BOOST_CLBL_TRTS_DEFAULT_VARARGS_CC -#define BOOST_CLBL_TRTS_CC -#define BOOST_CLBL_TRTS_ST pascal -#include <boost/callable_traits/detail/unguarded/function_ptr.hpp> -#undef BOOST_CLBL_TRTS_CC -#undef BOOST_CLBL_TRTS_ST -#undef BOOST_CLBL_TRTS_CC_TAG -#undef BOOST_CLBL_TRTS_VARARGS_CC -#endif - -template<typename T> -struct function<T&> : std::conditional<function<T>::value, - function<T>, default_callable_traits<T&>>::type { - - static constexpr const bool value = !std::is_pointer<T>::value; - - using traits = function; - using base = function<T>; - using type = T&; - using remove_varargs = typename base::remove_varargs&; - using add_varargs = typename base::add_varargs&; - - using remove_member_reference = reference_error; - using add_member_lvalue_reference = reference_error; - using add_member_rvalue_reference = reference_error; - using add_member_const = reference_error; - using add_member_volatile = reference_error; - using add_member_cv = reference_error; - using remove_member_const = reference_error; - using remove_member_volatile = reference_error; - using remove_member_cv = reference_error; - - template<typename NewReturn> - using apply_return = typename base::template apply_return<NewReturn>&; - - using clear_args = typename base::clear_args&; - - template<typename... NewArgs> - using push_front = typename base::template push_front<NewArgs...>&; - - template<typename... NewArgs> - using push_back = typename base::template push_back<NewArgs...>&; - - template<std::size_t Count> - using pop_back = typename base::template pop_back<Count>&; - - template<std::size_t Count> - using pop_front = typename base::template pop_front<Count>&; - - template<std::size_t Index, typename... NewArgs> - using insert_args = typename base::template insert_args<Index, NewArgs...>&; - - template<std::size_t Index, std::size_t Count> - using remove_args = typename base::template remove_args<Index, Count>&; - - template<std::size_t Index, typename... NewArgs> - using replace_args = typename base::template replace_args<Index, NewArgs...>&; -}; - -}}} // namespace boost::callable_traits::detail - -#endif // #ifndef BOOST_CLBL_TRTS_DETAIL_FUNCTION_HPP diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/detail/function_object.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/detail/function_object.hpp deleted file mode 100644 index d12fc00e6..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/detail/function_object.hpp +++ /dev/null @@ -1,107 +0,0 @@ -/* - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_DETAIL_FUNCTION_OBJECT_HPP -#define BOOST_CLBL_TRTS_DETAIL_FUNCTION_OBJECT_HPP - -#include <boost/callable_traits/detail/pmf.hpp> -#include <boost/callable_traits/detail/default_callable_traits.hpp> -#include <boost/callable_traits/detail/forward_declarations.hpp> -#include <boost/callable_traits/detail/utility.hpp> - -namespace boost { namespace callable_traits { namespace detail { - -template<typename T, typename Base> -struct function_object : Base { - - using type = T; - using error_t = error_type<T>; - using function_type = typename Base::function_object_signature; - using arg_types = typename Base::non_invoke_arg_types; - using non_invoke_arg_types = arg_types; - - static constexpr const bool value = std::is_class< - typename std::remove_reference<T>::type>::value; - - using traits = function_object; - using class_type = error_t; - using invoke_type = error_t; - using remove_varargs = error_t; - using add_varargs = error_t; - using is_noexcept = typename Base::is_noexcept; - using add_noexcept = error_t; - using remove_noexcept = error_t; - using is_transaction_safe = typename Base::is_transaction_safe; - using add_transaction_safe = error_t; - using remove_transaction_safe = error_t; - using clear_args = error_t; - - template<template<class...> class Container> - using expand_args = typename function<function_type>::template - expand_args<Container>; - - template<template<class...> class Container, typename... RightArgs> - using expand_args_left = typename function<function_type>::template - expand_args_left<Container, RightArgs...>; - - template<template<class...> class Container, typename... LeftArgs> - using expand_args_right = typename function<function_type>::template - expand_args_right<Container, LeftArgs...>; - - template<typename C, typename U = T> - using apply_member_pointer = - typename std::remove_reference<U>::type C::*; - - template<typename> - using apply_return = error_t; - - template<typename...> - using push_front = error_t; - - template<typename...> - using push_back = error_t; - - template<std::size_t ElementCount> - using pop_args_front = error_t; - - template<std::size_t ElementCount> - using pop_args_back = error_t; - - template<std::size_t Index, typename... NewArgs> - using insert_args = error_t; - - template<std::size_t Index, std::size_t Count> - using remove_args = error_t; - - template<std::size_t Index, typename... NewArgs> - using replace_args = error_t; - - template<std::size_t Count> - using pop_front = error_t; - - template<std::size_t Count> - using pop_back = error_t; - - using remove_member_reference = error_t; - using add_member_lvalue_reference = error_t; - using add_member_rvalue_reference = error_t; - using add_member_const = error_t; - using add_member_volatile = error_t; - using add_member_cv = error_t; - using remove_member_const = error_t; - using remove_member_volatile = error_t; - using remove_member_cv = error_t; -}; - -template<typename T, typename U, typename Base> -struct function_object <T U::*, Base> - : default_callable_traits<> {}; - -}}} // namespace boost::callable_traits::detail - -#endif // #ifndef BOOST_CLBL_TRTS_DETAIL_FUNCTION_OBJECT_HPP diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/detail/is_invocable_impl.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/detail/is_invocable_impl.hpp deleted file mode 100644 index 323886572..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/detail/is_invocable_impl.hpp +++ /dev/null @@ -1,148 +0,0 @@ - /*! -@file - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_IS_INVOCABLE_IMPL_HPP -#define BOOST_CLBL_TRTS_IS_INVOCABLE_IMPL_HPP - -#include <boost/callable_traits/detail/config.hpp> -#include <boost/callable_traits/detail/forward_declarations.hpp> -#include <boost/callable_traits/detail/utility.hpp> -#include <type_traits> -#include <utility> - -namespace boost { namespace callable_traits { namespace detail { - - template<typename T> - struct can_dereference_t - { - template<typename> - struct check {}; - - template<typename U> - static std::int8_t test( - check<typename std::remove_reference<decltype(*std::declval<U>())>::type>* - ); - - template<typename> - static std::int16_t test(...); - - static constexpr const bool value = - sizeof(test<T>(nullptr)) == sizeof(std::int8_t); - }; - - //returns std::true_type for pointers and smart pointers - template<typename T> - using can_dereference = std::integral_constant<bool, - can_dereference_t<T>::value>; - - - template<typename T, typename = std::true_type> - struct generalize_t { - using type = T; - }; - - template<typename T> - struct generalize_t<T, std::integral_constant<bool, - can_dereference<T>::value && !is_reference_wrapper<T>::value - >>{ - using type = decltype(*std::declval<T>()); - }; - - template<typename T> - struct generalize_t<T, is_reference_wrapper<T>> { - using type = decltype(std::declval<T>().get()); - }; - - // When T is a pointer, generalize<T> is the resulting type of the - // pointer dereferenced. When T is an std::reference_wrapper, generalize<T> - // is the underlying reference type. Otherwise, generalize<T> is T. - template<typename T> - using generalize = typename generalize_t<T>::type; - - // handles the member pointer rules of INVOKE - template<typename Base, typename T, - typename IsBaseOf = std::is_base_of<Base, shallow_decay<T>>, - typename IsSame = std::is_same<Base, shallow_decay<T>>> - using generalize_if_dissimilar = typename std::conditional< - IsBaseOf::value || IsSame::value, T, generalize<T>>::type; - - template<typename Traits, bool = Traits::is_const_member::value - || Traits::is_volatile_member::value - || Traits::is_lvalue_reference_member::value - || Traits::is_rvalue_reference_member::value> - struct test_invoke { - - template<typename... Rgs, - typename U = typename Traits::type> - auto operator()(Rgs&&... rgs) const -> - success<decltype(std::declval<U>()(static_cast<Rgs&&>(rgs)...))>; - - auto operator()(...) const -> substitution_failure; - }; - - template<typename F> - struct test_invoke<function<F>, true /*abominable*/> { - auto operator()(...) const -> substitution_failure; - }; - - template<typename Pmf, bool Ignored> - struct test_invoke<pmf<Pmf>, Ignored> { - - using class_t = typename pmf<Pmf>::class_type; - - template<typename U, typename... Rgs, - typename Obj = generalize_if_dissimilar<class_t, U&&>> - auto operator()(U&& u, Rgs&&... rgs) const -> - success<decltype((std::declval<Obj>().*std::declval<Pmf>())(static_cast<Rgs&&>(rgs)...))>; - - auto operator()(...) const -> substitution_failure; - }; - - template<typename Pmd, bool Ignored> - struct test_invoke<pmd<Pmd>, Ignored> { - - using class_t = typename pmd<Pmd>::class_type; - - template<typename U, - typename Obj = generalize_if_dissimilar<class_t, U&&>> - auto operator()(U&& u) const -> - success<decltype(std::declval<Obj>().*std::declval<Pmd>())>; - - auto operator()(...) const -> substitution_failure; - }; - - template<typename T, typename... Args> - struct is_invocable_impl { - using traits = detail::traits<T>; - using test = detail::test_invoke<traits>; - using result = decltype(test{}(::std::declval<Args>()...)); - using type = std::integral_constant<bool, result::value>; - }; - - template<typename... Args> - struct is_invocable_impl<void, Args...> { - using type = std::false_type; - }; - - template<typename IsInvocable, typename Ret, typename T, typename... Args> - struct is_invocable_r_impl { - using traits = detail::traits<T>; - using test = detail::test_invoke<traits>; - using result = decltype(test{}(::std::declval<Args>()...)); - using type = typename std::is_convertible<typename result::_::type, Ret>::type; - }; - - template<typename Ret, typename T, typename... Args> - struct is_invocable_r_impl<std::false_type, Ret, T, Args...> { - using type = std::false_type; - }; - -}}} // namespace boost::callable_traits::detail - -#endif // #ifndef BOOST_CLBL_TRTS_IS_INVOCABLE_IMPL_HPP diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/detail/parameter_index_helper.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/detail/parameter_index_helper.hpp deleted file mode 100644 index 430217591..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/detail/parameter_index_helper.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef BOOST_CLBL_TRTS_PARAMETER_INDEX_HELPER_HPP -#define BOOST_CLBL_TRTS_PARAMETER_INDEX_HELPER_HPP - -#include <boost/callable_traits/detail/config.hpp> - -namespace boost { namespace callable_traits { namespace detail { - -template<std::size_t I, typename T, bool IgnoreThisPointer = false, - bool AllowPlus1 = false, std::size_t Count = 0> -struct parameter_index_helper { - - using error_t = error_type<T>; - - using args_tuple = typename std::conditional<IgnoreThisPointer, - typename detail::traits<T>::non_invoke_arg_types, - typename detail::traits<T>::arg_types>::type; - - static constexpr bool has_parameter_list = - !std::is_same<args_tuple, invalid_type>::value - && !std::is_same<args_tuple, reference_error>::value; - - using temp_tuple = typename std::conditional<has_parameter_list, - args_tuple, std::tuple<error_t>>::type; - - static constexpr std::size_t parameter_list_size = - std::tuple_size<temp_tuple>::value; - - static constexpr bool is_out_of_range = has_parameter_list && - I >= parameter_list_size + static_cast<std::size_t>(AllowPlus1); - - static constexpr bool is_count_out_of_range = has_parameter_list && - I + Count > parameter_list_size + static_cast<std::size_t>(AllowPlus1); - - static constexpr std::size_t index = - has_parameter_list && !is_out_of_range ? I : 0; - - static constexpr std::size_t count = - has_parameter_list && !is_count_out_of_range ? Count : 0; - - using permissive_tuple = typename std::conditional< - has_parameter_list && !is_out_of_range, - args_tuple, std::tuple<error_t>>::type; - - using permissive_function = typename std::conditional< - has_parameter_list && !is_out_of_range, - T, error_t(error_t)>::type; -}; - -}}} // namespace boost::callable_traits::detail - -#endif // #ifndef BOOST_CLBL_TRTS_PARAMETER_INDEX_HELPER_HPP diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/detail/pmd.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/detail/pmd.hpp deleted file mode 100644 index 13a2c4463..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/detail/pmd.hpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_DETAIL_PMD_HPP -#define BOOST_CLBL_TRTS_DETAIL_PMD_HPP - -#include <boost/callable_traits/detail/forward_declarations.hpp> -#include <boost/callable_traits/detail/function.hpp> -#include <boost/callable_traits/detail/traits.hpp> -#include <boost/callable_traits/detail/default_callable_traits.hpp> -#include <boost/callable_traits/detail/utility.hpp> - -namespace boost { namespace callable_traits { namespace detail { - -template<typename T> -struct pmd : default_callable_traits<T> {}; - -template<typename D, typename T> -struct pmd<D T::*> : default_callable_traits<> { - - static constexpr bool value = true; - - using traits = pmd; - using class_type = T; - using invoke_type = T const &; - using type = D T::*; - using function_type = typename std::add_lvalue_reference<D>::type(invoke_type); - using qualified_function_type = D(invoke_type); - using arg_types = std::tuple<invoke_type>; - using non_invoke_arg_types = std::tuple<>; - - using return_type = typename std::add_lvalue_reference<D>::type; - - template<typename C> - using apply_member_pointer = D C::*; - - template<typename R> - using apply_return = R T::*; - - template<template<class...> class Container> - using expand_args = Container<invoke_type>; - - using is_member_pointer = std::true_type; -}; - -}}} // namespace boost::callable_traits::detail - -#endif diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/detail/pmf.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/detail/pmf.hpp deleted file mode 100644 index 5284e0d59..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/detail/pmf.hpp +++ /dev/null @@ -1,97 +0,0 @@ -/* - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_DETAIL_PMF_HPP -#define BOOST_CLBL_TRTS_DETAIL_PMF_HPP - -#include <boost/callable_traits/detail/forward_declarations.hpp> -#include <boost/callable_traits/detail/set_function_qualifiers.hpp> -#include <boost/callable_traits/detail/qualifier_flags.hpp> -#include <boost/callable_traits/detail/default_callable_traits.hpp> -#include <boost/callable_traits/detail/utility.hpp> - -namespace boost { namespace callable_traits { namespace detail { - -template<qualifier_flags Applied, bool IsTransactionSafe, bool IsNoExcept, - typename CallingConvention, typename T, typename Return, - typename... Args> -struct set_member_function_qualifiers_t; - -template<qualifier_flags Applied, bool IsTransactionSafe, bool IsNoexcept, - typename CallingConvention, typename T, typename Return, - typename... Args> -struct set_varargs_member_function_qualifiers_t; - -template<qualifier_flags Flags, bool IsTransactionSafe, bool IsNoexcept, - typename... Ts> -using set_member_function_qualifiers = - typename set_member_function_qualifiers_t<Flags, IsTransactionSafe, - IsNoexcept, Ts...>::type; - -template<qualifier_flags Flags, bool IsTransactionSafe, bool IsNoexcept, - typename... Ts> -using set_varargs_member_function_qualifiers = - typename set_varargs_member_function_qualifiers_t<Flags, - IsTransactionSafe, IsNoexcept, Ts...>::type; - -template<typename T> -struct pmf : default_callable_traits<T> {}; - -#define BOOST_CLBL_TRTS_CC_TAG dummy -#define BOOST_CLBL_TRTS_VARARGS_CC BOOST_CLBL_TRTS_DEFAULT_VARARGS_CC -#define BOOST_CLBL_TRTS_CC -#include <boost/callable_traits/detail/unguarded/pmf.hpp> -#undef BOOST_CLBL_TRTS_CC -#undef BOOST_CLBL_TRTS_CC_TAG -#undef BOOST_CLBL_TRTS_VARARGS_CC - -#define BOOST_CLBL_TRTS_CC_TAG dummy -#define BOOST_CLBL_TRTS_VARARGS_CC BOOST_CLBL_TRTS_DEFAULT_VARARGS_CC -#define BOOST_CLBL_TRTS_CC -#include <boost/callable_traits/detail/unguarded/pmf_varargs.hpp> -#undef BOOST_CLBL_TRTS_CC -#undef BOOST_CLBL_TRTS_CC_TAG -#undef BOOST_CLBL_TRTS_VARARGS_CC - -#ifdef BOOST_CLBL_TRTS_ENABLE_CDECL -#define BOOST_CLBL_TRTS_CC_TAG cdecl_tag -#define BOOST_CLBL_TRTS_VARARGS_CC __cdecl -#define BOOST_CLBL_TRTS_CC __cdecl -#include <boost/callable_traits/detail/unguarded/pmf.hpp> -#undef BOOST_CLBL_TRTS_CC -#undef BOOST_CLBL_TRTS_CC_TAG -#undef BOOST_CLBL_TRTS_VARARGS_CC -#endif // #ifdef BOOST_CLBL_TRTS_ENABLE_CDECL - -// Defining this macro enables undocumented features, likely broken. -// Too much work to maintain, but knock yourself out -#ifdef BOOST_CLBL_TRTS_ENABLE_STDCALL -#define BOOST_CLBL_TRTS_CC_TAG stdcall_tag -#define BOOST_CLBL_TRTS_VARARGS_CC BOOST_CLBL_TRTS_DEFAULT_VARARGS_CC -#define BOOST_CLBL_TRTS_CC __stdcall -#include <boost/callable_traits/detail/unguarded/pmf.hpp> -#undef BOOST_CLBL_TRTS_CC -#undef BOOST_CLBL_TRTS_CC_TAG -#undef BOOST_CLBL_TRTS_VARARGS_CC -#endif // #ifdef BOOST_CLBL_TRTS_ENABLE_STDCALL - -// Defining this macro enables undocumented features, likely broken. -// Too much work to officially maintain, but knock yourself out -#ifdef BOOST_CLBL_TRTS_ENABLE_FASTCALL -#define BOOST_CLBL_TRTS_CC_TAG fastcall_tag -#define BOOST_CLBL_TRTS_VARARGS_CC BOOST_CLBL_TRTS_DEFAULT_VARARGS_CC -#define BOOST_CLBL_TRTS_CC __fastcall -#include <boost/callable_traits/detail/unguarded/pmf.hpp> -#undef BOOST_CLBL_TRTS_CC -#undef BOOST_CLBL_TRTS_CC_TAG -#undef BOOST_CLBL_TRTS_VARARGS_CC -#endif // #ifdef BOOST_CLBL_TRTS_ENABLE_FASTCALL - -}}} // namespace boost::callable_traits::detail - -#endif // #ifndef BOOST_CLBL_TRTS_DETAIL_PMF_HPP diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/detail/polyfills/disjunction.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/detail/polyfills/disjunction.hpp deleted file mode 100644 index dc4f65c7c..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/detail/polyfills/disjunction.hpp +++ /dev/null @@ -1,31 +0,0 @@ -/* -Copyright Barrett Adair 2015-2017 - -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_DETAIL_POLYFILLS_DISJUNCTION_HPP -#define BOOST_CLBL_TRTS_DETAIL_POLYFILLS_DISJUNCTION_HPP - -#undef BOOST_CLBL_TRTS_DISJUNCTION -#define BOOST_CLBL_TRTS_DISJUNCTION(...) \ - ::boost::callable_traits::detail::disjunction<__VA_ARGS__> - -namespace boost { namespace callable_traits { namespace detail { - -//polyfill for C++17 std::disjunction -template<typename...> -struct disjunction : std::false_type {}; - -template<typename T> -struct disjunction<T> : T {}; - -template<typename T, typename... Ts> -struct disjunction<T, Ts...> - : std::conditional<T::value != false, T, disjunction<Ts...>>::type {}; - -}}} // namespace boost::callable_traits::detail - -#endif // #ifndef BOOST_CLBL_TRTS_DETAIL_POLYFILLS_DISJUNCTION_HPP diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/detail/polyfills/make_index_sequence.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/detail/polyfills/make_index_sequence.hpp deleted file mode 100644 index a4a6e820c..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/detail/polyfills/make_index_sequence.hpp +++ /dev/null @@ -1,50 +0,0 @@ -/* -Copyright Barrett Adair 2016-2017 - -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) -*/ - -#ifndef BOOST_CLBL_TRTS_DETAIL_POLYFILLS_MAKE_INDEX_SEQUENCE_HPP -#define BOOST_CLBL_TRTS_DETAIL_POLYFILLS_MAKE_INDEX_SEQUENCE_HPP - -#undef BOOST_CLBL_TRTS_IX_SEQ -#define BOOST_CLBL_TRTS_IX_SEQ(...) \ - ::boost::callable_traits::detail::index_sequence<__VA_ARGS__> - -#undef BOOST_CLBL_TRTS_MAKE_IX_SEQ -#define BOOST_CLBL_TRTS_MAKE_IX_SEQ(...) \ - ::boost::callable_traits::detail::make_index_sequence<__VA_ARGS__> - -namespace boost { namespace callable_traits { namespace detail { - -template<std::size_t...> -struct index_sequence { using type = index_sequence; }; - -template<typename, typename> -struct concat; - -template<std::size_t... I1, std::size_t... I2> -struct concat<index_sequence<I1...>, index_sequence<I2...>> - : index_sequence<I1..., (sizeof...(I1)+I2)...> {}; - -template<std::size_t N> - struct make_index_sequence_t; - -template<std::size_t N> -struct make_index_sequence_t : concat< - typename make_index_sequence_t<N/2>::type, - typename make_index_sequence_t<N - N/2>::type >::type {}; - -template<> -struct make_index_sequence_t<0> : index_sequence<> {}; - -template<> -struct make_index_sequence_t<1> : index_sequence<0> {}; - -template<std::size_t... I> -using make_index_sequence = typename make_index_sequence_t<I...>::type; - -}}} // namespace boost::callable_traits::detail - -#endif // #ifndef BOOST_CLBL_TRTS_DETAIL_POLYFILLS_MAKE_INDEX_SEQUENCE_HPP diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/detail/qualifier_flags.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/detail/qualifier_flags.hpp deleted file mode 100644 index f69d246c4..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/detail/qualifier_flags.hpp +++ /dev/null @@ -1,123 +0,0 @@ -/* -Defines `qualifier_flags` - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_QUALIFIER_FLAGS_HPP -#define BOOST_CLBL_TRTS_QUALIFIER_FLAGS_HPP - -#include <boost/callable_traits/detail/config.hpp> - -namespace boost { namespace callable_traits { namespace detail { - -//bit qualifier_flags used to signify cv/ref qualifiers -using qualifier_flags = std::uint32_t; - -/* - | && & V C | --------------------------------------------- -0 | 0 0 0 0 | default -1 | 0 0 0 1 | const -2 | 0 0 1 0 | volatile -3 | 0 0 1 1 | const volatile --------------------------------------------- -4 | 0 1 0 0 | & -5 | 0 1 0 1 | const & -6 | 0 1 1 0 | volatile & -7 | 0 1 1 1 | const volatile & --------------------------------------------- -8 | 1 0 0 0 | && -9 | 1 0 0 1 | const && -10 | 1 0 1 0 | volatile && -11 | 1 0 1 1 | const volatile && - -*/ - -// Flag representing the default qualifiers on a type -// or member function overload. -constexpr qualifier_flags default_ = 0; - -// Flag representing a const qualifier on a type or -// member function overload. -constexpr qualifier_flags const_ = 1; - -// Flag representing a volatile qualifier on a type -// or member function overload. -constexpr qualifier_flags volatile_ = 2; - -#ifdef BOOST_CLBL_TRTS_DISABLE_REFERENCE_QUALIFIERS - -constexpr qualifier_flags lref_ = default_; -constexpr qualifier_flags rref_ = default_; -#else - -// Flag representing an lvalue reference type, or -// an lvalue-reference-qualified member function -// overload. -constexpr qualifier_flags lref_ = 4; - -// Flag representing an lvalue reference type, or -// an rvalue-reference-qualified member function -// overload. -constexpr qualifier_flags rref_ = 8; - -#endif //#ifdef BOOST_CLBL_TRTS_DISABLE_REFERENCE_QUALIFIERS - -constexpr qualifier_flags cv_ = 3; - -template<qualifier_flags Flags> -using remove_const_flag = std::integral_constant< - qualifier_flags, Flags & ~const_>; - -template<qualifier_flags Flags> -using is_const = std::integral_constant<bool, - (Flags & const_) != 0>; - -template<qualifier_flags Flags> -using remove_volatile_flag = std::integral_constant< - qualifier_flags, Flags & ~volatile_>; - -template<typename U, typename T = typename std::remove_reference<U>::type> -using cv_of = std::integral_constant<qualifier_flags, - (std::is_const<T>::value ? const_ : default_) - | (std::is_volatile<T>::value ? volatile_ : default_)>; - -template<typename T> -using ref_of = std::integral_constant<qualifier_flags, - std::is_rvalue_reference<T>::value ? rref_ - : (std::is_lvalue_reference<T>::value ? lref_ - : default_)>; - -//bit-flag implementation of C++11 reference collapsing rules -template<qualifier_flags Existing, - qualifier_flags Other, - bool AlreadyHasRef = (Existing & (lref_ | rref_)) != 0, - bool AlreadyHasLRef = (Existing & lref_) == lref_, - bool IsAddingLRef = (Other & lref_) == lref_ -> -using collapse_flags = std::integral_constant<qualifier_flags, - !AlreadyHasRef ? (Existing | Other) - : (AlreadyHasLRef ? (Existing | (Other & ~rref_)) - : (IsAddingLRef ? ((Existing & ~rref_) | Other ) - : (Existing | Other)))>; - -template<typename T> struct flag_map { static constexpr qualifier_flags value = default_; }; -template<typename T> struct flag_map<T &> { static constexpr qualifier_flags value = lref_; }; -template<typename T> struct flag_map<T &&> { static constexpr qualifier_flags value = rref_; }; -template<typename T> struct flag_map<T const> { static constexpr qualifier_flags value = const_; }; -template<typename T> struct flag_map<T const &> { static constexpr qualifier_flags value = const_ | lref_; }; -template<typename T> struct flag_map<T const &&> { static constexpr qualifier_flags value = const_ | rref_; }; -template<typename T> struct flag_map<T volatile> { static constexpr qualifier_flags value = volatile_; }; -template<typename T> struct flag_map<T volatile &> { static constexpr qualifier_flags value = volatile_ | lref_; }; -template<typename T> struct flag_map<T volatile &&> { static constexpr qualifier_flags value = volatile_ | rref_; }; -template<typename T> struct flag_map<T const volatile> { static constexpr qualifier_flags value = const_ | volatile_; }; -template<typename T> struct flag_map<T const volatile &> { static constexpr qualifier_flags value = const_ | volatile_ | lref_; }; -template<typename T> struct flag_map<T const volatile &&> { static constexpr qualifier_flags value = const_ | volatile_ | rref_; }; - -}}} // namespace boost::callable_traits::detail - -#endif // #ifndef BOOST_CLBL_TRTS_QUALIFIER_FLAGS_HPP diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/detail/set_function_qualifiers.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/detail/set_function_qualifiers.hpp deleted file mode 100644 index 9dc7f405a..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/detail/set_function_qualifiers.hpp +++ /dev/null @@ -1,120 +0,0 @@ -/* - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_DETAIL_SET_FUNCTION_QUALIFIERS_HPP -#define BOOST_CLBL_TRTS_DETAIL_SET_FUNCTION_QUALIFIERS_HPP - -#include <boost/callable_traits/detail/qualifier_flags.hpp> - -#define BOOST_CLBL_TRTS_SET_FUNCTION_QUALIFIERS(QUAL) \ -template<typename Return, typename... Args> \ -struct set_function_qualifiers_t < \ - flag_map<int QUAL>::value, false, false, Return, Args...> { \ - using type = Return(Args...) QUAL; \ -}; \ - \ -template<typename Return, typename... Args> \ -struct set_function_qualifiers_t < \ - flag_map<int QUAL>::value, true, false, Return, Args...> { \ - using type = Return(Args...) QUAL \ - BOOST_CLBL_TRTS_TRANSACTION_SAFE_SPECIFIER; \ -}; \ - \ -template<typename Return, typename... Args> \ -struct set_function_qualifiers_t < \ - flag_map<int QUAL>::value, false, true, Return, Args...> { \ - using type = Return(Args...) QUAL \ - BOOST_CLBL_TRTS_NOEXCEPT_SPECIFIER; \ -}; \ - \ -template<typename Return, typename... Args> \ -struct set_function_qualifiers_t < \ - flag_map<int QUAL>::value, true, true, Return, Args...> { \ - using type = Return(Args...) QUAL \ - BOOST_CLBL_TRTS_TRANSACTION_SAFE_SPECIFIER \ - BOOST_CLBL_TRTS_NOEXCEPT_SPECIFIER; \ -}; \ - \ -template<typename Return, typename... Args> \ -struct set_varargs_function_qualifiers_t < \ - flag_map<int QUAL>::value, false, false, Return, Args...> { \ - using type = Return(Args..., ...) QUAL; \ -}; \ - \ -template<typename Return, typename... Args> \ -struct set_varargs_function_qualifiers_t < \ - flag_map<int QUAL>::value, true, false, Return, Args...> { \ - using type = Return(Args..., ...) QUAL \ - BOOST_CLBL_TRTS_TRANSACTION_SAFE_SPECIFIER; \ -}; \ - \ -template<typename Return, typename... Args> \ -struct set_varargs_function_qualifiers_t < \ - flag_map<int QUAL>::value, false, true, Return, Args...> { \ - using type = Return(Args..., ...) QUAL \ - BOOST_CLBL_TRTS_NOEXCEPT_SPECIFIER; \ -}; \ - \ -template<typename Return, typename... Args> \ -struct set_varargs_function_qualifiers_t < \ - flag_map<int QUAL>::value, true, true, Return, Args...> { \ - using type = Return(Args..., ...) QUAL \ - BOOST_CLBL_TRTS_TRANSACTION_SAFE_SPECIFIER \ - BOOST_CLBL_TRTS_NOEXCEPT_SPECIFIER; \ -} \ -/**/ - -namespace boost { namespace callable_traits { namespace detail { - - template<qualifier_flags Applied, bool IsTransactionSafe, - bool IsNoexcept, typename Return, typename... Args> - struct set_function_qualifiers_t { - using type = Return(Args...); - }; - - template<qualifier_flags Applied, bool IsTransactionSafe, - bool IsNoexcept, typename Return, typename... Args> - struct set_varargs_function_qualifiers_t { - using type = Return(Args..., ...); - }; - -#ifndef BOOST_CLBL_TRTS_DISABLE_ABOMINABLE_FUNCTIONS - - BOOST_CLBL_TRTS_SET_FUNCTION_QUALIFIERS(const); - BOOST_CLBL_TRTS_SET_FUNCTION_QUALIFIERS(volatile); - BOOST_CLBL_TRTS_SET_FUNCTION_QUALIFIERS(const volatile); - -#ifndef BOOST_CLBL_TRTS_DISABLE_REFERENCE_QUALIFIERS - - BOOST_CLBL_TRTS_SET_FUNCTION_QUALIFIERS(&); - BOOST_CLBL_TRTS_SET_FUNCTION_QUALIFIERS(&&); - BOOST_CLBL_TRTS_SET_FUNCTION_QUALIFIERS(const &); - BOOST_CLBL_TRTS_SET_FUNCTION_QUALIFIERS(const &&); - BOOST_CLBL_TRTS_SET_FUNCTION_QUALIFIERS(volatile &); - BOOST_CLBL_TRTS_SET_FUNCTION_QUALIFIERS(volatile &&); - BOOST_CLBL_TRTS_SET_FUNCTION_QUALIFIERS(const volatile &); - BOOST_CLBL_TRTS_SET_FUNCTION_QUALIFIERS(const volatile &&); - -#endif // #ifndef BOOST_CLBL_TRTS_DISABLE_REFERENCE_QUALIFIERS -#endif // #ifndef BOOST_CLBL_TRTS_DISABLE_ABOMINABLE_FUNCTIONS - - template<qualifier_flags Flags, bool IsTransactionSafe, bool IsNoexcept, - typename... Ts> - using set_function_qualifiers = - typename set_function_qualifiers_t<Flags, IsTransactionSafe, IsNoexcept, - Ts...>::type; - - template<qualifier_flags Flags, bool IsTransactionSafe, bool IsNoexcept, - typename... Ts> - using set_varargs_function_qualifiers = - typename set_varargs_function_qualifiers_t<Flags, IsTransactionSafe, - IsNoexcept, Ts...>::type; - -}}} // namespace boost::callable_traits::detail - -#endif //BOOST_CLBL_TRTS_DETAIL_SET_FUNCTION_QUALIFIERS_HPP diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/detail/sfinae_errors.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/detail/sfinae_errors.hpp deleted file mode 100644 index 485d17259..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/detail/sfinae_errors.hpp +++ /dev/null @@ -1,89 +0,0 @@ -/* -@Copyright Barrett Adair 2016-2017 - -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_SFINAE_ERRORS_HPP -#define BOOST_CLBL_TRTS_SFINAE_ERRORS_HPP - -#include <boost/callable_traits/detail/config.hpp> - -namespace boost { namespace callable_traits { namespace detail { - - struct sfinae_error{}; - - template<typename T> - struct success { - static constexpr bool value = true; - struct _ { using type = T; }; - }; - - template<bool B, typename T> - struct fail_if : T { - static_assert(std::is_base_of<sfinae_error, T>::value, - "incorrect usage of fail_if"); - - static constexpr bool value = B; - }; - - template<typename T, typename... FailIfs> - using sfinae_try = typename BOOST_CLBL_TRTS_DISJUNCTION( - FailIfs..., success<T>)::_::type; - - template<typename FailMsg, typename ForceTwoPhaseLookup> - struct fail { - using type = typename std::conditional<std::is_same<ForceTwoPhaseLookup, std::false_type>::value, - FailMsg, FailMsg>::type::_::type; - }; - -}}} // namespace boost::callable_traits::detail - -#define BOOST_CLBL_TRTS_PP_CAT_(x, y) x ## y -#define BOOST_CLBL_TRTS_PP_CAT(x, y) BOOST_CLBL_TRTS_PP_CAT_(x, y) - -#define BOOST_CLBL_TRTS_DEFINE_SFINAE_ERROR_ORIGIN(origin) \ -namespace error { \ - template<typename ErrorMessage> \ - struct origin : \ - ::boost::callable_traits::detail::sfinae_error \ - { struct _ {}; }; \ -} \ -/**/ - -#define BOOST_CLBL_TRTS_SFINAE_MSG(origin, name) \ -struct BOOST_CLBL_TRTS_PP_CAT(name, _ ){}; \ -struct name : error::origin< \ - BOOST_CLBL_TRTS_PP_CAT(name, _ )>{}; \ -/**/ - -namespace boost { namespace callable_traits { - - BOOST_CLBL_TRTS_DEFINE_SFINAE_ERROR_ORIGIN(parameters) - BOOST_CLBL_TRTS_SFINAE_MSG(parameters, index_out_of_range_for_parameter_list) - BOOST_CLBL_TRTS_SFINAE_MSG(parameters, cannot_determine_parameters_for_this_type) - - BOOST_CLBL_TRTS_DEFINE_SFINAE_ERROR_ORIGIN(varargs) - BOOST_CLBL_TRTS_SFINAE_MSG(varargs, varargs_are_illegal_for_this_type) - - BOOST_CLBL_TRTS_DEFINE_SFINAE_ERROR_ORIGIN(member_qualifiers) - BOOST_CLBL_TRTS_SFINAE_MSG(member_qualifiers, member_qualifiers_are_illegal_for_this_type) - BOOST_CLBL_TRTS_SFINAE_MSG(member_qualifiers, this_compiler_doesnt_support_abominable_function_types) - - BOOST_CLBL_TRTS_DEFINE_SFINAE_ERROR_ORIGIN(transaction_safe_) - BOOST_CLBL_TRTS_SFINAE_MSG(transaction_safe_, transaction_safe_is_not_supported_by_this_configuration) - - BOOST_CLBL_TRTS_DEFINE_SFINAE_ERROR_ORIGIN(expand_args) - BOOST_CLBL_TRTS_SFINAE_MSG(expand_args, cannot_expand_the_parameter_list_of_first_template_argument) - - BOOST_CLBL_TRTS_DEFINE_SFINAE_ERROR_ORIGIN(member_pointer_required) - BOOST_CLBL_TRTS_SFINAE_MSG(member_pointer_required, type_is_not_a_member_pointer) - - BOOST_CLBL_TRTS_DEFINE_SFINAE_ERROR_ORIGIN(reference_error) - BOOST_CLBL_TRTS_SFINAE_MSG(reference_error, reference_type_not_supported_by_this_metafunction) - -}} // namespace boost::callable_traits - -#endif // #ifndef BOOST_CLBL_TRTS_SFINAE_ERRORS_HPP diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/detail/traits.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/detail/traits.hpp deleted file mode 100644 index e5a587f0b..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/detail/traits.hpp +++ /dev/null @@ -1,29 +0,0 @@ -/* - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_DETAIL_TRAITS_HPP -#define BOOST_CLBL_TRTS_DETAIL_TRAITS_HPP - -#include <boost/callable_traits/detail/forward_declarations.hpp> -#include <boost/callable_traits/detail/utility.hpp> - -namespace boost { namespace callable_traits { namespace detail { - - // Here is where the magic happens - template<typename T> - using traits = typename BOOST_CLBL_TRTS_DISJUNCTION( - function_object<unwrap_reference<T>>, - function<T>, - pmf<T>, - pmd<T>, - default_callable_traits<T> - )::traits; - -}}} // namespace boost::callable_traits::detail - -#endif // #ifndef BOOST_CLBL_TRTS_DETAIL_TRAITS_HPP diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/function.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/function.hpp deleted file mode 100644 index a1d32e90a..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/function.hpp +++ /dev/null @@ -1,23 +0,0 @@ -/* -Copyright (c) 2016 Barrett Adair - -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -HEADER GUARDS INTENTIONALLY OMITTED -DO NOT INCLUDE THIS HEADER DIRECTLY -*/ - -#define BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE -#define BOOST_CLBL_TRTS_IS_TRANSACTION_SAFE std::false_type -#include <boost/callable_traits/detail/unguarded/function_2.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE -#undef BOOST_CLBL_TRTS_IS_TRANSACTION_SAFE - -#ifdef BOOST_CLBL_TRTS_ENABLE_TRANSACTION_SAFE -#define BOOST_CLBL_TRTS_IS_TRANSACTION_SAFE std::true_type -#define BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE transaction_safe -#include <boost/callable_traits/detail/unguarded/function_2.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE -#undef BOOST_CLBL_TRTS_IS_TRANSACTION_SAFE -#endif // #ifdef BOOST_CLBL_TRTS_ENABLE_TRANSACTION_SAFE \ No newline at end of file diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/function_2.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/function_2.hpp deleted file mode 100644 index 562b4e933..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/function_2.hpp +++ /dev/null @@ -1,23 +0,0 @@ -/* -Copyright (c) 2016 Barrett Adair - -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -HEADER GUARDS INTENTIONALLY OMITTED -DO NOT INCLUDE THIS HEADER DIRECTLY -*/ - -#define BOOST_CLBL_TRTS_NOEXCEPT_SPEC -#define BOOST_CLBL_TRTS_IS_NOEXCEPT std::false_type -#include <boost/callable_traits/detail/unguarded/function_3.hpp> -#undef BOOST_CLBL_TRTS_NOEXCEPT_SPEC -#undef BOOST_CLBL_TRTS_IS_NOEXCEPT - -#ifdef BOOST_CLBL_TRTS_ENABLE_NOEXCEPT_TYPES -#define BOOST_CLBL_TRTS_NOEXCEPT_SPEC noexcept -#define BOOST_CLBL_TRTS_IS_NOEXCEPT std::true_type -#include <boost/callable_traits/detail/unguarded/function_3.hpp> -#undef BOOST_CLBL_TRTS_NOEXCEPT_SPEC -#undef BOOST_CLBL_TRTS_IS_NOEXCEPT -#endif // #ifdef BOOST_CLBL_TRTS_ENABLE_NOEXCEPT_TYPES \ No newline at end of file diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/function_3.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/function_3.hpp deleted file mode 100644 index 2c329c411..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/function_3.hpp +++ /dev/null @@ -1,260 +0,0 @@ -/* -Copyright (c) 2016 Barrett Adair - -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -HEADER GUARDS INTENTIONALLY OMITTED -DO NOT INCLUDE THIS HEADER DIRECTLY - -macros used: - -BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - the function-level qualifiers for the - current inclusion (combinations of `const` `volatile` `&` `&&`, or nothing) - -BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - the transaction_safe specifier for - the current include (`transaction_safe` or nothing) - -BOOST_CLBL_TRTS_IS_TRANSACTION_SAFE - `std::true_type` or `std::false_type`, - tied on whether BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE is `transaction_safe` - -BOOST_CLBL_TRTS_TRANSACTION_SAFE_SPECIFIER - `transaction_safe` when - BOOST_CLBL_TRTS_ENABLE_TRANSACTION_SAFE is enabled, otherwise nothing - -BOOST_CLBL_TRTS_NOEXCEPT_SPEC - the noexcept specifier for - the current include (`noexcept` or nothing) - -BOOST_CLBL_TRTS_IS_NOEXCEPT - `std::true_type` or `std::false_type`, - tied on whether BOOST_CLBL_TRTS_NOEXCEPT_SPEC is `noexcept` - -BOOST_CLBL_TRTS_NOEXCEPT_SPECIFIER - `noexcept` if - BOOST_CLBL_TRTS_ENABLE_NOEXCEPT_TYPES is defined, otherwise nothing - -*/ - -template<typename Return, typename... Args> -struct function<Return(Args...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPEC> - : default_callable_traits<dummy BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS> { - - static constexpr bool value = true; - - using traits = function; - - using return_type = Return; - - using arg_types = std::tuple<Args...>; - using non_invoke_arg_types = arg_types; - - using type = Return(Args...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - using function_type = Return(Args...); - - using qualified_function_type = Return(Args...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - using remove_varargs = type; - - using add_varargs = Return (Args..., ...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - using is_noexcept = BOOST_CLBL_TRTS_IS_NOEXCEPT; - - using remove_noexcept = Return(Args...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE; - - using add_noexcept = Return(Args...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPECIFIER; - - using is_transaction_safe = BOOST_CLBL_TRTS_IS_TRANSACTION_SAFE; - - using remove_transaction_safe = Return(Args...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - using add_transaction_safe = Return(Args...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_TRANSACTION_SAFE_SPECIFIER - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - using qualifiers = default_callable_traits<dummy BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS>; - - template<qualifier_flags Flags> - using set_qualifiers = set_function_qualifiers<Flags, is_transaction_safe::value, - is_noexcept::value, Return, Args...>; - - #ifdef BOOST_CLBL_TRTS_DISABLE_ABOMINABLE_FUNCTIONS - - using add_member_lvalue_reference = abominable_functions_not_supported_on_this_compiler; - using add_member_rvalue_reference = abominable_functions_not_supported_on_this_compiler; - using add_member_const = abominable_functions_not_supported_on_this_compiler; - using add_member_volatile = abominable_functions_not_supported_on_this_compiler; - using add_member_cv = abominable_functions_not_supported_on_this_compiler; - - #else - - using add_member_lvalue_reference = set_qualifiers< - collapse_flags<qualifiers::q_flags, lref_>::value>; - - using add_member_rvalue_reference = set_qualifiers< - collapse_flags<qualifiers::q_flags, rref_>::value>; - - using add_member_const = set_qualifiers<qualifiers::q_flags | const_>; - - using add_member_volatile = set_qualifiers<qualifiers::q_flags | volatile_>; - - using add_member_cv = set_qualifiers<qualifiers::q_flags | cv_>; - - #endif // #ifdef BOOST_CLBL_TRTS_DISABLE_ABOMINABLE_FUNCTIONS - - using remove_member_reference = set_qualifiers<qualifiers::cv_flags>; - - using remove_member_const = set_qualifiers< - qualifiers::ref_flags | remove_const_flag<qualifiers::cv_flags>::value>; - - using remove_member_volatile = set_qualifiers< - qualifiers::ref_flags | remove_volatile_flag<qualifiers::cv_flags>::value>; - - using remove_member_cv = set_qualifiers<qualifiers::ref_flags>; - - template<typename U> - using apply_member_pointer = add_member_pointer<type, U>; - - template<typename NewReturn> - using apply_return = NewReturn(Args...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - template<template<class...> class Container> - using expand_args = Container<Args...>; - - using is_member_pointer = std::false_type; -}; - - -template<typename Return, typename... Args> -struct function<Return (Args..., ...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPEC> - : default_callable_traits<dummy BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS> { - - static constexpr bool value = true; - - using has_varargs = std::true_type; - using traits = function; - using return_type = Return; - using arg_types = std::tuple<Args...>; - - using type = Return (Args..., ...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - using function_type = Return(Args..., ...); - - using qualified_function_type = Return(Args..., ...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - using remove_varargs = Return (Args...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - using add_varargs = type; - - using is_noexcept = BOOST_CLBL_TRTS_IS_NOEXCEPT; - - using remove_noexcept = Return(Args..., ...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE; - - using add_noexcept = Return(Args..., ...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPECIFIER; - - using is_transaction_safe = BOOST_CLBL_TRTS_IS_TRANSACTION_SAFE; - - using remove_transaction_safe = Return(Args..., ...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - using add_transaction_safe = Return(Args..., ...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_TRANSACTION_SAFE_SPECIFIER - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - using qualifiers = default_callable_traits<dummy BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS>; - - template<qualifier_flags Flags> - using set_qualifiers = set_varargs_function_qualifiers<Flags, is_transaction_safe::value, - is_noexcept::value, Return, Args...>; - - #ifdef BOOST_CLBL_TRTS_DISABLE_ABOMINABLE_FUNCTIONS - - using add_member_lvalue_reference = abominable_functions_not_supported_on_this_compiler; - using add_member_rvalue_reference = abominable_functions_not_supported_on_this_compiler; - using add_member_const = abominable_functions_not_supported_on_this_compiler; - using add_member_volatile = abominable_functions_not_supported_on_this_compiler; - using add_member_cv = abominable_functions_not_supported_on_this_compiler; - - #else - - using add_member_lvalue_reference = set_qualifiers< - collapse_flags<qualifiers::q_flags, lref_>::value>; - - using add_member_rvalue_reference = set_qualifiers< - collapse_flags<qualifiers::q_flags, rref_>::value>; - - using add_member_const = set_qualifiers<qualifiers::q_flags | const_>; - - using add_member_volatile = set_qualifiers<qualifiers::q_flags | volatile_>; - - using add_member_cv = set_qualifiers<qualifiers::q_flags | cv_>; - - #endif // #ifdef BOOST_CLBL_TRTS_DISABLE_ABOMINABLE_FUNCTIONS - - using remove_member_reference = set_qualifiers<qualifiers::cv_flags>; - - using remove_member_const = set_qualifiers< - qualifiers::ref_flags | remove_const_flag<qualifiers::cv_flags>::value>; - - using remove_member_volatile = set_qualifiers< - qualifiers::ref_flags | remove_volatile_flag<qualifiers::cv_flags>::value>; - - using remove_member_cv = set_qualifiers<qualifiers::ref_flags>; - - template<typename U> - using apply_member_pointer = - Return( BOOST_CLBL_TRTS_DEFAULT_VARARGS_CC U::*)(Args..., ...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - template<typename NewReturn> - using apply_return = NewReturn(Args..., ...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - template<template<class...> class Container> - using expand_args = Container<Args...>; - - using is_member_pointer = std::false_type; -}; diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/function_ptr.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/function_ptr.hpp deleted file mode 100644 index 4aa8ad593..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/function_ptr.hpp +++ /dev/null @@ -1,25 +0,0 @@ -/* -Copyright (c) 2016 Modified Work Barrett Adair - -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -HEADER GUARDS INTENTIONALLY OMITTED -DO NOT INCLUDE THIS HEADER DIRECTLY -*/ - -#define BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE -#define BOOST_CLBL_TRTS_IS_TRANSACTION_SAFE std::false_type -#include <boost/callable_traits/detail/unguarded/function_ptr_2.hpp> - -#undef BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE -#undef BOOST_CLBL_TRTS_IS_TRANSACTION_SAFE - -#ifdef BOOST_CLBL_TRTS_ENABLE_TRANSACTION_SAFE -#define BOOST_CLBL_TRTS_IS_TRANSACTION_SAFE std::true_type -#define BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE transaction_safe -#include <boost/callable_traits/detail/unguarded/function_ptr_2.hpp> -#endif - -#undef BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE -#undef BOOST_CLBL_TRTS_IS_TRANSACTION_SAFE diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/function_ptr_2.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/function_ptr_2.hpp deleted file mode 100644 index b54f2ed80..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/function_ptr_2.hpp +++ /dev/null @@ -1,23 +0,0 @@ -/* -Copyright (c) 2016 Barrett Adair - -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -HEADER GUARDS INTENTIONALLY OMITTED -DO NOT INCLUDE THIS HEADER DIRECTLY -*/ - -#define BOOST_CLBL_TRTS_NOEXCEPT_SPEC -#define BOOST_CLBL_TRTS_IS_NOEXCEPT std::false_type -#include <boost/callable_traits/detail/unguarded/function_ptr_3.hpp> -#undef BOOST_CLBL_TRTS_NOEXCEPT_SPEC -#undef BOOST_CLBL_TRTS_IS_NOEXCEPT - -#ifdef BOOST_CLBL_TRTS_ENABLE_NOEXCEPT_TYPES -#define BOOST_CLBL_TRTS_NOEXCEPT_SPEC noexcept -#define BOOST_CLBL_TRTS_IS_NOEXCEPT std::true_type -#include <boost/callable_traits/detail/unguarded/function_ptr_3.hpp> -#undef BOOST_CLBL_TRTS_NOEXCEPT_SPEC -#undef BOOST_CLBL_TRTS_IS_NOEXCEPT -#endif // #ifdef BOOST_CLBL_TRTS_ENABLE_NOEXCEPT_TYPES \ No newline at end of file diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/function_ptr_3.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/function_ptr_3.hpp deleted file mode 100644 index e657b57ef..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/function_ptr_3.hpp +++ /dev/null @@ -1,94 +0,0 @@ -/* -Copyright (c) 2016 Modified Work Barrett Adair - -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -HEADER GUARDS INTENTIONALLY OMITTED -DO NOT INCLUDE THIS HEADER DIRECTLY - -macros used: - -BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - the transaction_safe specifier for - the current include (`transaction_safe` or nothing) - -BOOST_CLBL_TRTS_IS_TRANSACTION_SAFE - `std::true_type` or `std::false_type`, - tied on whether BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE is `transaction_safe` - -BOOST_CLBL_TRTS_TRANSACTION_SAFE_SPECIFIER - `transaction_safe` when - BOOST_CLBL_TRTS_ENABLE_TRANSACTION_SAFE is enabled, otherwise nothing - -BOOST_CLBL_TRTS_NOEXCEPT_SPEC - the noexcept specifier for - the current include (`noexcept` or nothing) - -BOOST_CLBL_TRTS_IS_NOEXCEPT - `std::true_type` or `std::false_type`, - tied on whether BOOST_CLBL_TRTS_NOEXCEPT_SPEC is `noexcept` - -BOOST_CLBL_TRTS_NOEXCEPT_SPECIFIER - `noexcept` if - BOOST_CLBL_TRTS_ENABLE_NOEXCEPT_TYPES is defined, otherwise nothing -*/ - -template<typename Return, typename... Args> -struct function< - BOOST_CLBL_TRTS_ST Return(BOOST_CLBL_TRTS_CC *)(Args...) - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPEC> - : default_callable_traits<> { - - static constexpr bool value = true; - - using traits = function; - - using return_type = Return; - - using arg_types = std::tuple<Args...>; - using non_invoke_arg_types = arg_types; - - using type = BOOST_CLBL_TRTS_ST Return(BOOST_CLBL_TRTS_CC *)(Args...) - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE; - - using function_type = Return(Args...); - using qualified_function_type = function_type; - using remove_varargs = type; - - using add_varargs = - BOOST_CLBL_TRTS_ST Return (BOOST_CLBL_TRTS_VARARGS_CC *)(Args..., ...) - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - using is_noexcept = BOOST_CLBL_TRTS_IS_NOEXCEPT; - - using remove_noexcept = Return(BOOST_CLBL_TRTS_CC *)(Args...) - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE; - - using add_noexcept = Return(BOOST_CLBL_TRTS_CC *)(Args...) - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPECIFIER; - - using is_transaction_safe = BOOST_CLBL_TRTS_IS_TRANSACTION_SAFE; - - using remove_transaction_safe = Return(BOOST_CLBL_TRTS_CC *)(Args...) - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - using add_transaction_safe = Return(BOOST_CLBL_TRTS_CC *)(Args...) - BOOST_CLBL_TRTS_TRANSACTION_SAFE_SPECIFIER - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - template<typename U> - using apply_member_pointer = - BOOST_CLBL_TRTS_ST Return(BOOST_CLBL_TRTS_CC U::*)(Args...) - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - template<typename NewReturn> - using apply_return = - BOOST_CLBL_TRTS_ST NewReturn(BOOST_CLBL_TRTS_CC *)(Args...) - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - template<template<class...> class Container> - using expand_args = Container<Args...>; - - using is_member_pointer = std::false_type; -}; - diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/function_ptr_varargs.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/function_ptr_varargs.hpp deleted file mode 100644 index 625f0d62e..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/function_ptr_varargs.hpp +++ /dev/null @@ -1,23 +0,0 @@ -/* -Copyright (c) 2016 Modified Work Barrett Adair - -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -HEADER GUARDS INTENTIONALLY OMITTED -DO NOT INCLUDE THIS HEADER DIRECTLY -*/ - -#define BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE -#define BOOST_CLBL_TRTS_IS_TRANSACTION_SAFE std::false_type -#include <boost/callable_traits/detail/unguarded/function_ptr_varargs_2.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE -#undef BOOST_CLBL_TRTS_IS_TRANSACTION_SAFE - -#ifdef BOOST_CLBL_TRTS_ENABLE_TRANSACTION_SAFE -#define BOOST_CLBL_TRTS_IS_TRANSACTION_SAFE std::true_type -#define BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE transaction_safe -#include <boost/callable_traits/detail/unguarded/function_ptr_varargs_2.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE -#undef BOOST_CLBL_TRTS_IS_TRANSACTION_SAFE -#endif // #ifdef BOOST_CLBL_TRTS_ENABLE_TRANSACTION_SAFE \ No newline at end of file diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/function_ptr_varargs_2.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/function_ptr_varargs_2.hpp deleted file mode 100644 index 9ed68fc13..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/function_ptr_varargs_2.hpp +++ /dev/null @@ -1,23 +0,0 @@ -/* -Copyright (c) 2016 Barrett Adair - -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -HEADER GUARDS INTENTIONALLY OMITTED -DO NOT INCLUDE THIS HEADER DIRECTLY -*/ - -#define BOOST_CLBL_TRTS_NOEXCEPT_SPEC -#define BOOST_CLBL_TRTS_IS_NOEXCEPT std::false_type -#include <boost/callable_traits/detail/unguarded/function_ptr_varargs_3.hpp> -#undef BOOST_CLBL_TRTS_NOEXCEPT_SPEC -#undef BOOST_CLBL_TRTS_IS_NOEXCEPT - -#ifdef BOOST_CLBL_TRTS_ENABLE_NOEXCEPT_TYPES -#define BOOST_CLBL_TRTS_NOEXCEPT_SPEC noexcept -#define BOOST_CLBL_TRTS_IS_NOEXCEPT std::true_type -#include <boost/callable_traits/detail/unguarded/function_ptr_varargs_3.hpp> -#undef BOOST_CLBL_TRTS_NOEXCEPT_SPEC -#undef BOOST_CLBL_TRTS_IS_NOEXCEPT -#endif // #ifdef BOOST_CLBL_TRTS_ENABLE_NOEXCEPT_TYPES \ No newline at end of file diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/function_ptr_varargs_3.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/function_ptr_varargs_3.hpp deleted file mode 100644 index 42e22931a..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/function_ptr_varargs_3.hpp +++ /dev/null @@ -1,98 +0,0 @@ -/* -Copyright (c) 2016 Modified Work Barrett Adair - -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -HEADER GUARDS INTENTIONALLY OMITTED -DO NOT INCLUDE THIS HEADER DIRECTLY - -macros used: - -BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - the transaction_safe specifier for - the current include (`transaction_safe` or nothing) - -BOOST_CLBL_TRTS_IS_TRANSACTION_SAFE - `std::true_type` or `std::false_type`, - tied on whether BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE is `transaction_safe` - -BOOST_CLBL_TRTS_TRANSACTION_SAFE_SPECIFIER - `transaction_safe` when - BOOST_CLBL_TRTS_ENABLE_TRANSACTION_SAFE is enabled, otherwise nothing - -BOOST_CLBL_TRTS_NOEXCEPT_SPEC - the noexcept specifier for - the current include (`noexcept` or nothing) - -BOOST_CLBL_TRTS_IS_NOEXCEPT - `std::true_type` or `std::false_type`, - tied on whether BOOST_CLBL_TRTS_NOEXCEPT_SPEC is `noexcept` - -BOOST_CLBL_TRTS_NOEXCEPT_SPECIFIER - `noexcept` if - BOOST_CLBL_TRTS_ENABLE_NOEXCEPT_TYPES is defined, otherwise nothing -*/ - -template<typename Return, typename... Args> -struct function<BOOST_CLBL_TRTS_ST Return(BOOST_CLBL_TRTS_VARARGS_CC *)(Args..., ...) - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPEC> - : default_callable_traits<> { - - static constexpr bool value = true; - - using has_varargs = std::true_type; - - using traits = function; - - using return_type = Return; - - using arg_types = std::tuple<Args...>; - using non_invoke_arg_types = arg_types; - - using type = - BOOST_CLBL_TRTS_ST Return(BOOST_CLBL_TRTS_VARARGS_CC *)(Args..., ...) - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - using function_type = Return(Args..., ...); - - using qualified_function_type = function_type; - - using remove_varargs = - BOOST_CLBL_TRTS_ST Return(BOOST_CLBL_TRTS_CC *)(Args...) - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE; - - using add_varargs = type; - - using is_noexcept = BOOST_CLBL_TRTS_IS_NOEXCEPT; - - using remove_noexcept = BOOST_CLBL_TRTS_ST Return(BOOST_CLBL_TRTS_CC *)(Args..., ...) - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE; - - using add_noexcept = BOOST_CLBL_TRTS_ST Return(BOOST_CLBL_TRTS_CC *)(Args..., ...) - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPECIFIER; - - using is_transaction_safe = BOOST_CLBL_TRTS_IS_TRANSACTION_SAFE; - - using remove_transaction_safe = Return(BOOST_CLBL_TRTS_VARARGS_CC *)(Args..., ...) - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - using add_transaction_safe = Return(BOOST_CLBL_TRTS_VARARGS_CC *)(Args..., ...) - BOOST_CLBL_TRTS_TRANSACTION_SAFE_SPECIFIER - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - template<typename U> - using apply_member_pointer = - BOOST_CLBL_TRTS_ST Return(BOOST_CLBL_TRTS_VARARGS_CC U::*)(Args..., ...) - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - template<typename NewReturn> - using apply_return = - BOOST_CLBL_TRTS_ST NewReturn(BOOST_CLBL_TRTS_VARARGS_CC *)(Args..., ...) - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - template<template<class...> class Container> - using expand_args = Container<Args...>; - - using is_member_pointer = std::false_type; -}; - diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/pmf.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/pmf.hpp deleted file mode 100644 index de9e7a34a..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/pmf.hpp +++ /dev/null @@ -1,94 +0,0 @@ -/* -Copyright (c) 2001 Peter Dimov and Multi Media Ltd. -Copyright (c) 2016 Modified Work Barrett Adair - -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -HEADER GUARDS INTENTIONALLY OMITTED -DO NOT INCLUDE THIS HEADER DIRECTLY - -*/ - -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS -#undef BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS - - -#define BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS -#define BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS -#include <boost/callable_traits/detail/unguarded/pmf_2.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS -#undef BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS - -#define BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS const -#define BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS \ - BOOST_CLBL_TRTS_ABOMINABLE_CONST -#include <boost/callable_traits/detail/unguarded/pmf_2.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS -#undef BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS - -#define BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS volatile -#define BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS \ - BOOST_CLBL_TRTS_ABOMINABLE_VOLATILE -#include <boost/callable_traits/detail/unguarded/pmf_2.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS -#undef BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS - -#define BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS const volatile -#define BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS \ - BOOST_CLBL_TRTS_ABOMINABLE_CONST BOOST_CLBL_TRTS_ABOMINABLE_VOLATILE -#include <boost/callable_traits/detail/unguarded/pmf_2.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS -#undef BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS - -#ifndef BOOST_CLBL_TRTS_DISABLE_REFERENCE_QUALIFIERS - -#define BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS & -#define BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS & -#include <boost/callable_traits/detail/unguarded/pmf_2.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS -#undef BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS - -#define BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS && -#define BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS && -#include <boost/callable_traits/detail/unguarded/pmf_2.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS -#undef BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS - -#define BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS const & -#define BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS const & -#include <boost/callable_traits/detail/unguarded/pmf_2.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS -#undef BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS - -#define BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS volatile & -#define BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS volatile & -#include <boost/callable_traits/detail/unguarded/pmf_2.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS -#undef BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS - -#define BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS const volatile & -#define BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS const volatile & -#include <boost/callable_traits/detail/unguarded/pmf_2.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS -#undef BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS - -#define BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS const && -#define BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS const && -#include <boost/callable_traits/detail/unguarded/pmf_2.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS -#undef BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS - -#define BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS volatile && -#define BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS volatile && -#include <boost/callable_traits/detail/unguarded/pmf_2.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS -#undef BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS - -#define BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS const volatile && -#define BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS const volatile && -#include <boost/callable_traits/detail/unguarded/pmf_2.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS -#undef BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS - -#endif // #ifndef BOOST_CLBL_TRTS_DISABLE_REFERENCE_QUALIFIERS diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/pmf_2.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/pmf_2.hpp deleted file mode 100644 index e3568fb14..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/pmf_2.hpp +++ /dev/null @@ -1,74 +0,0 @@ -/* -Copyright (c) 2016 Barrett Adair - -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -HEADER GUARDS INTENTIONALLY OMITTED -DO NOT INCLUDE THIS HEADER DIRECTLY - -*/ - -template<typename Return, typename T, typename... Args> -struct set_member_function_qualifiers_t< - flag_map<int BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS>::value, - false, // IsTransactionSafe - false, // IsNoexcept - BOOST_CLBL_TRTS_CC_TAG, T, Return, Args...> { - - using type = Return(BOOST_CLBL_TRTS_CC T::*)(Args...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS; -}; - -template<typename Return, typename T, typename... Args> -struct set_member_function_qualifiers_t< - flag_map<int BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS>::value, - false, - true, - BOOST_CLBL_TRTS_CC_TAG, T, Return, Args...> { - - using type = Return(BOOST_CLBL_TRTS_CC T::*)(Args...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_NOEXCEPT_SPECIFIER; -}; - -template<typename Return, typename T, typename... Args> -struct set_member_function_qualifiers_t< - flag_map<int BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS>::value, - true, - false, - BOOST_CLBL_TRTS_CC_TAG, T, Return, Args...> { - - using type = Return(BOOST_CLBL_TRTS_CC T::*)(Args...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_TRANSACTION_SAFE_SPECIFIER; -}; - -template<typename Return, typename T, typename... Args> -struct set_member_function_qualifiers_t< - flag_map<int BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS>::value, - true, - true, - BOOST_CLBL_TRTS_CC_TAG, T, Return, Args...> { - - using type = Return(BOOST_CLBL_TRTS_CC T::*)(Args...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_TRANSACTION_SAFE_SPECIFIER - BOOST_CLBL_TRTS_NOEXCEPT_SPECIFIER; -}; - -#define BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE -#define BOOST_CLBL_TRTS_IS_TRANSACTION_SAFE std::false_type -#include <boost/callable_traits/detail/unguarded/pmf_3.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE -#undef BOOST_CLBL_TRTS_IS_TRANSACTION_SAFE - -#ifdef BOOST_CLBL_TRTS_ENABLE_TRANSACTION_SAFE - -#define BOOST_CLBL_TRTS_IS_TRANSACTION_SAFE std::true_type -#define BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE transaction_safe -#include <boost/callable_traits/detail/unguarded/pmf_3.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE -#undef BOOST_CLBL_TRTS_IS_TRANSACTION_SAFE - -#endif diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/pmf_3.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/pmf_3.hpp deleted file mode 100644 index 62b34f2bc..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/pmf_3.hpp +++ /dev/null @@ -1,23 +0,0 @@ -/* -Copyright (c) 2016 Barrett Adair - -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -HEADER GUARDS INTENTIONALLY OMITTED -DO NOT INCLUDE THIS HEADER DIRECTLY -*/ - -#define BOOST_CLBL_TRTS_NOEXCEPT_SPEC -#define BOOST_CLBL_TRTS_IS_NOEXCEPT std::false_type -#include <boost/callable_traits/detail/unguarded/pmf_4.hpp> -#undef BOOST_CLBL_TRTS_NOEXCEPT_SPEC -#undef BOOST_CLBL_TRTS_IS_NOEXCEPT - -#ifdef BOOST_CLBL_TRTS_ENABLE_NOEXCEPT_TYPES -#define BOOST_CLBL_TRTS_NOEXCEPT_SPEC noexcept -#define BOOST_CLBL_TRTS_IS_NOEXCEPT std::true_type -#include <boost/callable_traits/detail/unguarded/pmf_4.hpp> -#undef BOOST_CLBL_TRTS_NOEXCEPT_SPEC -#undef BOOST_CLBL_TRTS_IS_NOEXCEPT -#endif // #ifdef BOOST_CLBL_TRTS_ENABLE_NOEXCEPT_TYPES \ No newline at end of file diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/pmf_4.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/pmf_4.hpp deleted file mode 100644 index 5a1f48ce2..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/pmf_4.hpp +++ /dev/null @@ -1,147 +0,0 @@ -/* -Copyright (c) 2016 Barrett Adair - -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -HEADER GUARDS INTENTIONALLY OMITTED -DO NOT INCLUDE THIS HEADER DIRECTLY - -BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - the function-level qualifiers for the - current inclusion (combinations of `const` `volatile` `&` `&&`, or nothing) - -BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - the transaction_safe specifier for - the current include (`transaction_safe` or nothing) - -BOOST_CLBL_TRTS_IS_TRANSACTION_SAFE - `std::true_type` or `std::false_type`, - tied on whether BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE is `transaction_safe` - -BOOST_CLBL_TRTS_TRANSACTION_SAFE_SPECIFIER - `transaction_safe` when - BOOST_CLBL_TRTS_ENABLE_TRANSACTION_SAFE is defined, otherwise nothing - -BOOST_CLBL_TRTS_NOEXCEPT_SPEC - the noexcept specifier for - the current include (`noexcept` or nothing) - -BOOST_CLBL_TRTS_IS_NOEXCEPT - `std::true_type` or `std::false_type`, - tied on whether BOOST_CLBL_TRTS_NOEXCEPT_SPEC is `noexcept` - -BOOST_CLBL_TRTS_NOEXCEPT_SPECIFIER - `noexcept` if - BOOST_CLBL_TRTS_ENABLE_NOEXCEPT_TYPES is defined, otherwise nothing -*/ - -template<typename Return, typename T, typename... Args> -struct pmf<Return(BOOST_CLBL_TRTS_CC T::*)(Args...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPEC> - : default_callable_traits<dummy BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS> { - - static constexpr bool value = true; - - using traits = pmf; - - using return_type = Return; - - using type = Return(BOOST_CLBL_TRTS_CC T::*)(Args...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - using invoke_type = typename std::conditional< - std::is_rvalue_reference<T BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS>::value, - T BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS, - typename std::add_lvalue_reference<T BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS>::type - >::type; - - using arg_types = std::tuple<invoke_type, Args...>; - using non_invoke_arg_types = std::tuple<Args...>; - - using function_object_signature = Return(Args...); - - using function_type = Return(invoke_type, Args...); - - using qualified_function_type = Return(Args...) - BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - using remove_varargs = type; - - using add_varargs = - Return(BOOST_CLBL_TRTS_VARARGS_CC T::*)(Args..., ...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - using is_noexcept = BOOST_CLBL_TRTS_IS_NOEXCEPT; - - using remove_noexcept = Return(BOOST_CLBL_TRTS_CC T::*)(Args...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE; - - using add_noexcept = Return(BOOST_CLBL_TRTS_CC T::*)(Args...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPECIFIER; - - using is_transaction_safe = BOOST_CLBL_TRTS_IS_TRANSACTION_SAFE; - - using remove_transaction_safe = Return(BOOST_CLBL_TRTS_CC T::*)(Args...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - using add_transaction_safe = Return(BOOST_CLBL_TRTS_CC T::*)(Args...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_TRANSACTION_SAFE_SPECIFIER - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - using class_type = T; - - using qualifiers = default_callable_traits<dummy BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS>; - - template<qualifier_flags Flags> - using set_qualifiers = set_member_function_qualifiers< - Flags, is_transaction_safe::value, is_noexcept::value, - BOOST_CLBL_TRTS_CC_TAG, T, Return, Args...>; - - using remove_member_reference = set_qualifiers<qualifiers::cv_flags>; - - using add_member_lvalue_reference = set_qualifiers< - collapse_flags<qualifiers::q_flags, lref_>::value>; - - using add_member_rvalue_reference = set_qualifiers< - collapse_flags<qualifiers::q_flags, rref_>::value>; - - using add_member_const = set_qualifiers<qualifiers::q_flags | const_>; - - using add_member_volatile = set_qualifiers<qualifiers::q_flags | volatile_>; - - using add_member_cv = set_qualifiers<qualifiers::q_flags | cv_>; - - using remove_member_const = set_qualifiers< - qualifiers::ref_flags | remove_const_flag<qualifiers::cv_flags>::value>; - - using remove_member_volatile = set_qualifiers< - qualifiers::ref_flags | remove_volatile_flag<qualifiers::cv_flags>::value>; - - using remove_member_cv = set_qualifiers<qualifiers::ref_flags>; - - template<typename U> - using apply_member_pointer = - Return(BOOST_CLBL_TRTS_CC U::*)(Args...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - template<typename NewReturn> - using apply_return = - NewReturn(BOOST_CLBL_TRTS_CC T::*)(Args...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - template<template<class...> class Container> - using expand_args = Container<invoke_type, Args...>; - - using is_member_pointer = std::true_type; -}; diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/pmf_varargs.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/pmf_varargs.hpp deleted file mode 100644 index bd40f2bdf..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/pmf_varargs.hpp +++ /dev/null @@ -1,89 +0,0 @@ -/* -Copyright (c) 2016 Barrett Adair - -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -HEADER GUARDS INTENTIONALLY OMITTED -DO NOT INCLUDE THIS HEADER DIRECTLY - -*/ - -#define BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS -#define BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS -#include <boost/callable_traits/detail/unguarded/pmf_varargs_2.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS -#undef BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS - -#define BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS const -#define BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS \ - BOOST_CLBL_TRTS_ABOMINABLE_CONST -#include <boost/callable_traits/detail/unguarded/pmf_varargs_2.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS -#undef BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS - -#define BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS volatile -#define BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS \ - BOOST_CLBL_TRTS_ABOMINABLE_VOLATILE -#include <boost/callable_traits/detail/unguarded/pmf_varargs_2.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS -#undef BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS - -#define BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS const volatile -#define BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS \ - BOOST_CLBL_TRTS_ABOMINABLE_CONST BOOST_CLBL_TRTS_ABOMINABLE_VOLATILE -#include <boost/callable_traits/detail/unguarded/pmf_varargs_2.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS -#undef BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS - -#ifndef BOOST_CLBL_TRTS_DISABLE_REFERENCE_QUALIFIERS - -#define BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS & -#define BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS & -#include <boost/callable_traits/detail/unguarded/pmf_varargs_2.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS -#undef BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS - -#define BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS && -#define BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS && -#include <boost/callable_traits/detail/unguarded/pmf_varargs_2.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS -#undef BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS - -#define BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS const & -#define BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS const & -#include <boost/callable_traits/detail/unguarded/pmf_varargs_2.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS -#undef BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS - -#define BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS volatile & -#define BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS volatile & -#include <boost/callable_traits/detail/unguarded/pmf_varargs_2.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS -#undef BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS - -#define BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS const volatile & -#define BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS const volatile & -#include <boost/callable_traits/detail/unguarded/pmf_varargs_2.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS -#undef BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS - -#define BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS const && -#define BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS const && -#include <boost/callable_traits/detail/unguarded/pmf_varargs_2.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS -#undef BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS - -#define BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS volatile && -#define BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS volatile && -#include <boost/callable_traits/detail/unguarded/pmf_varargs_2.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS -#undef BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS - -#define BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS const volatile && -#define BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS const volatile && -#include <boost/callable_traits/detail/unguarded/pmf_varargs_2.hpp> -#undef BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS -#undef BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS - -#endif // #ifndef BOOST_CLBL_TRTS_DISABLE_REFERENCE_QUALIFIERS \ No newline at end of file diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/pmf_varargs_2.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/pmf_varargs_2.hpp deleted file mode 100644 index 5de066819..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/pmf_varargs_2.hpp +++ /dev/null @@ -1,78 +0,0 @@ -/* -Copyright (c) 2016 Barrett Adair - -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -HEADER GUARDS INTENTIONALLY OMITTED -DO NOT INCLUDE THIS HEADER DIRECTLY - -*/ - -template<typename T, typename Return, typename... Args> -struct set_varargs_member_function_qualifiers_t < - flag_map<int BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS>::value, - false, // IsTransactionSafe - false, // IsNoexcept - BOOST_CLBL_TRTS_CC_TAG, T, Return, Args...> { - - using type = - Return(BOOST_CLBL_TRTS_VARARGS_CC T::*)(Args..., ...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS; -}; - -template<typename T, typename Return, typename... Args> -struct set_varargs_member_function_qualifiers_t < - flag_map<int BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS>::value, - false, - true, - BOOST_CLBL_TRTS_CC_TAG, T, Return, Args...> { - - using type = - Return(BOOST_CLBL_TRTS_VARARGS_CC T::*)(Args..., ...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS BOOST_CLBL_TRTS_NOEXCEPT_SPECIFIER; -}; - -template<typename T, typename Return, typename... Args> -struct set_varargs_member_function_qualifiers_t < - flag_map<int BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS>::value, - true, - false, - BOOST_CLBL_TRTS_CC_TAG, T, Return, Args...> { - - using type = - Return(BOOST_CLBL_TRTS_VARARGS_CC T::*)(Args..., ...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_TRANSACTION_SAFE_SPECIFIER; -}; - -template<typename T, typename Return, typename... Args> -struct set_varargs_member_function_qualifiers_t < - flag_map<int BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS>::value, - true, - true, - BOOST_CLBL_TRTS_CC_TAG, T, Return, Args...> { - - using type = - Return(BOOST_CLBL_TRTS_VARARGS_CC T::*)(Args..., ...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_TRANSACTION_SAFE_SPECIFIER - BOOST_CLBL_TRTS_NOEXCEPT_SPECIFIER; -}; - -#define BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE -#define BOOST_CLBL_TRTS_IS_TRANSACTION_SAFE std::false_type -#include <boost/callable_traits/detail/unguarded/pmf_varargs_3.hpp> - -#undef BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE -#undef BOOST_CLBL_TRTS_IS_TRANSACTION_SAFE - -#ifdef BOOST_CLBL_TRTS_ENABLE_TRANSACTION_SAFE - -#define BOOST_CLBL_TRTS_IS_TRANSACTION_SAFE std::true_type -#define BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE transaction_safe -#include <boost/callable_traits/detail/unguarded/pmf_varargs_3.hpp> -#endif - -#undef BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE -#undef BOOST_CLBL_TRTS_IS_TRANSACTION_SAFE diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/pmf_varargs_3.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/pmf_varargs_3.hpp deleted file mode 100644 index 905a5a6d9..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/pmf_varargs_3.hpp +++ /dev/null @@ -1,23 +0,0 @@ -/* -Copyright (c) 2016 Barrett Adair - -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -HEADER GUARDS INTENTIONALLY OMITTED -DO NOT INCLUDE THIS HEADER DIRECTLY -*/ - -#define BOOST_CLBL_TRTS_NOEXCEPT_SPEC -#define BOOST_CLBL_TRTS_IS_NOEXCEPT std::false_type -#include <boost/callable_traits/detail/unguarded/pmf_varargs_4.hpp> -#undef BOOST_CLBL_TRTS_NOEXCEPT_SPEC -#undef BOOST_CLBL_TRTS_IS_NOEXCEPT - -#ifdef BOOST_CLBL_TRTS_ENABLE_NOEXCEPT_TYPES -#define BOOST_CLBL_TRTS_NOEXCEPT_SPEC noexcept -#define BOOST_CLBL_TRTS_IS_NOEXCEPT std::true_type -#include <boost/callable_traits/detail/unguarded/pmf_varargs_4.hpp> -#undef BOOST_CLBL_TRTS_NOEXCEPT_SPEC -#undef BOOST_CLBL_TRTS_IS_NOEXCEPT -#endif // #ifdef BOOST_CLBL_TRTS_ENABLE_NOEXCEPT_TYPES \ No newline at end of file diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/pmf_varargs_4.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/pmf_varargs_4.hpp deleted file mode 100644 index ca33ebf96..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/detail/unguarded/pmf_varargs_4.hpp +++ /dev/null @@ -1,149 +0,0 @@ -/* -Copyright (c) 2016 Barrett Adair - -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -HEADER GUARDS INTENTIONALLY OMITTED -DO NOT INCLUDE THIS HEADER DIRECTLY - -BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - the function-level qualifiers for the - current inclusion (combinations of `const` `volatile` `&` `&&`, or nothing) - -BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - the transaction_safe specifier for - the current include (`transaction_safe` or nothing) - -BOOST_CLBL_TRTS_IS_TRANSACTION_SAFE - `std::true_type` or `std::false_type`, - tied on whether BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE is `transaction_safe` - -BOOST_CLBL_TRTS_TRANSACTION_SAFE_SPECIFIER - `transaction_safe` when - BOOST_CLBL_TRTS_ENABLE_TRANSACTION_SAFE is enabled, otherwise nothing - -BOOST_CLBL_TRTS_NOEXCEPT_SPEC - the noexcept specifier for - the current include (`noexcept` or nothing) - -BOOST_CLBL_TRTS_IS_NOEXCEPT - `std::true_type` or `std::false_type`, - tied on whether BOOST_CLBL_TRTS_NOEXCEPT_SPEC is `noexcept` - -BOOST_CLBL_TRTS_NOEXCEPT_SPECIFIER - `noexcept` if - BOOST_CLBL_TRTS_ENABLE_NOEXCEPT_TYPES is defined, otherwise nothing -*/ - -template<typename Return, typename T, typename... Args> -struct pmf<Return(BOOST_CLBL_TRTS_VARARGS_CC T::*)(Args..., ...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPEC> - : default_callable_traits<dummy BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS> { - - static constexpr bool value = true; - - using has_varargs = std::true_type; - - using traits = pmf; - - using return_type = Return; - - using type = Return(BOOST_CLBL_TRTS_VARARGS_CC T::*)(Args..., ...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - using invoke_type = typename std::conditional< - std::is_rvalue_reference<T BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS>::value, - T BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS, - typename std::add_lvalue_reference<T BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS>::type - >::type; - - using arg_types = std::tuple<invoke_type, Args...>; - using non_invoke_arg_types = std::tuple<Args...>; - - using function_object_signature = Return(Args..., ...); - - using function_type = Return(invoke_type, Args..., ...); - - using qualified_function_type = Return(Args..., ...) - BOOST_CLBL_TRTS_INCLUDE_ABOMINABLE_QUALIFIERS - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - using remove_varargs = - Return(BOOST_CLBL_TRTS_CC T::*)(Args...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - using add_varargs = type; - - using is_noexcept = BOOST_CLBL_TRTS_IS_NOEXCEPT; - - using remove_noexcept = Return(BOOST_CLBL_TRTS_CC T::*)(Args..., ...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE; - - using add_noexcept = Return(BOOST_CLBL_TRTS_CC T::*)(Args..., ...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPECIFIER; - - using is_transaction_safe = BOOST_CLBL_TRTS_IS_TRANSACTION_SAFE; - - using remove_transaction_safe = Return(BOOST_CLBL_TRTS_VARARGS_CC T::*)(Args..., ...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - using add_transaction_safe = Return(BOOST_CLBL_TRTS_VARARGS_CC T::*)(Args..., ...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_TRANSACTION_SAFE_SPECIFIER - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - using class_type = T; - - using qualifiers = default_callable_traits<dummy BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS>; - - template<qualifier_flags Flags> - using set_qualifiers = set_varargs_member_function_qualifiers< - Flags, is_transaction_safe::value, is_noexcept::value, - BOOST_CLBL_TRTS_CC_TAG, T, Return, Args...>; - - using remove_member_reference = set_qualifiers<qualifiers::cv_flags>; - - using add_member_lvalue_reference = set_qualifiers< - collapse_flags<qualifiers::q_flags, lref_>::value>; - - using add_member_rvalue_reference = set_qualifiers< - collapse_flags<qualifiers::q_flags, rref_>::value>; - - using add_member_const = set_qualifiers<qualifiers::q_flags | const_>; - - using add_member_volatile = set_qualifiers<qualifiers::q_flags | volatile_>; - - using add_member_cv = set_qualifiers<qualifiers::q_flags | cv_>; - - using remove_member_const = set_qualifiers< - qualifiers::ref_flags | remove_const_flag<qualifiers::cv_flags>::value>; - - using remove_member_volatile = set_qualifiers< - qualifiers::ref_flags | remove_volatile_flag<qualifiers::cv_flags>::value>; - - using remove_member_cv = set_qualifiers<qualifiers::ref_flags>; - - template<typename U> - using apply_member_pointer = - Return(BOOST_CLBL_TRTS_VARARGS_CC U::*)(Args..., ...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - template<typename NewReturn> - using apply_return = - NewReturn(BOOST_CLBL_TRTS_VARARGS_CC T::*)(Args..., ...) - BOOST_CLBL_TRTS_INCLUDE_QUALIFIERS - BOOST_CLBL_TRTS_INCLUDE_TRANSACTION_SAFE - BOOST_CLBL_TRTS_NOEXCEPT_SPEC; - - template<template<class...> class Container> - using expand_args = Container<invoke_type, Args...>; - - using is_member_pointer = std::true_type; -}; diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/detail/utility.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/detail/utility.hpp deleted file mode 100644 index d5a28cc3c..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/detail/utility.hpp +++ /dev/null @@ -1,111 +0,0 @@ -/* - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_DETAIL_UTILITY_HPP -#define BOOST_CLBL_TRTS_DETAIL_UTILITY_HPP - -#include <boost/callable_traits/detail/config.hpp> -#include <boost/callable_traits/detail/sfinae_errors.hpp> -#include <boost/callable_traits/detail/qualifier_flags.hpp> - -namespace boost { namespace callable_traits { namespace detail { - -struct cdecl_tag{}; -struct stdcall_tag{}; -struct fastcall_tag{}; -struct pascal_tag{}; - -struct invalid_type { invalid_type() = delete; }; -struct reference_error { reference_error() = delete; }; - -template<typename T> -using error_type = typename std::conditional< - std::is_reference<T>::value, reference_error, invalid_type>::type; - -#ifdef BOOST_CLBL_TRTS_DISABLE_ABOMINABLE_FUNCTIONS -struct abominable_functions_not_supported_on_this_compiler{}; -#endif - -// used to convey "this type doesn't matter" in code -struct dummy {}; - -// used as return type in failed SFINAE tests -struct substitution_failure : std::false_type{}; - -template<bool Value> -using bool_type = std::integral_constant<bool, Value>; - -// shorthand for std::tuple_element -template<std::size_t I, typename Tup> -using at = typename std::tuple_element<I, Tup>::type; - -template<typename T, typename Class> -using add_member_pointer = T Class::*; - -template<typename L, typename R, typename ErrorType> - using fail_when_same = fail_if<std::is_same<L, R>::value, ErrorType>; - -template<typename T, typename ErrorType, - typename U = typename std::remove_reference<T>::type> -using try_but_fail_if_invalid = sfinae_try<T, - fail_when_same<U, invalid_type, ErrorType>, - fail_when_same<U, reference_error, - reference_type_not_supported_by_this_metafunction>>; - -template<typename T, typename ErrorType, - typename U = typename std::remove_reference<T>::type, - bool is_reference_error = std::is_same<reference_error, U>::value> -using fail_if_invalid = fail_if< - std::is_same<U, invalid_type>::value || is_reference_error, - typename std::conditional<is_reference_error, - reference_type_not_supported_by_this_metafunction, ErrorType>::type>; - -template<typename T, typename Fallback> -using fallback_if_invalid = typename std::conditional< - std::is_same<T, invalid_type>::value, Fallback, T>::type; - -template<typename T, template<class> class Alias, typename U = Alias<T>> -struct force_sfinae { - using type = U; -}; - -template<typename T> -using shallow_decay = typename std::remove_cv< - typename std::remove_reference<T>::type>::type; - -template<typename T> -struct is_reference_wrapper_t { - using type = std::false_type; -}; - -template<typename T> -struct is_reference_wrapper_t<std::reference_wrapper<T>> { - using type = std::true_type; -}; - -template<typename T> -using is_reference_wrapper = - typename is_reference_wrapper_t<shallow_decay<T>>::type; - -template<typename T, typename = std::true_type> -struct unwrap_reference_t { - using type = T; -}; - -template<typename T> -struct unwrap_reference_t<T, is_reference_wrapper<T>> { - using type = decltype(std::declval<T>().get()); -}; - -// removes std::reference_wrapper -template<typename T> -using unwrap_reference = typename unwrap_reference_t<T>::type; - -}}} // namespace boost::callable_traits::detail - -#endif // #ifndef BOOST_CLBL_TRTS_DETAIL_UTILITY_HPP diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/function_type.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/function_type.hpp deleted file mode 100644 index a3305f7bf..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/function_type.hpp +++ /dev/null @@ -1,97 +0,0 @@ -/* - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_FUNCTION_TYPE_HPP -#define BOOST_CLBL_TRTS_FUNCTION_TYPE_HPP - -#include <boost/callable_traits/detail/core.hpp> - -namespace boost { namespace callable_traits { - -//[ function_type_hpp -/*`[section:ref_function_type function_type] -[heading Header] -``#include <boost/callable_traits/function_type.hpp>`` -[heading Definition] -*/ - -template<typename T> -using function_type_t = //see below -//<- - detail::try_but_fail_if_invalid<typename detail::traits< - detail::shallow_decay<T>>::function_type, - cannot_determine_parameters_for_this_type>; - -namespace detail { - - template<typename T, typename = std::false_type> - struct function_type_impl {}; - - template<typename T> - struct function_type_impl <T, typename std::is_same< - function_type_t<T>, detail::dummy>::type> - { - using type = function_type_t<T>; - }; -} - -//-> - -template<typename T> -struct function_type : detail::function_type_impl<T> {}; - -//<- -}} // namespace boost::callable_traits -//-> - -/*` -[heading Constraints] -* `T` must be one of the following: - * function - * function pointer - * function reference - * member function pointer - * member data pointer - * user-defined type with a non-overloaded `operator()` - * type of a non-generic lambda - -[heading Behavior] -* When the constraints are violated, a substitution failure occurs. -* When `T` is a function, the aliased type is identical to `T`, except that the aliased function type will not have member qualifiers or the `transaction_safe` specifier. -* When `T` is a function pointer, the aliased type is equivalent to `std::remove_pointer_t<T>`. -* When `T` is a function reference, the aliased type is equivalent to `std::remove_reference_t<T>`. -* When `T` is a function object, the aliased type is a function type with the same return type and parameter list as `T`'s `operator()`. -* When `T` is a member function pointer, the aliased type is a function type with the same return type as `T`, and the first parameter is a reference to the parent class of `T`, qualified according to the member qualifiers on `T`. The subsequent parameters, if any, are the parameter types of `T`. -* When `T` is a member data pointer, the aliased type is a function type returning the underlying member type of `T`, taking a single parameter, which is a `const` reference to the parent type of `T`. -* In all cases, the aliased function type will not have member qualifiers, and will not have the `transaction_safe` specifier. - -[heading Input/Output Examples] -[table - [[`T`] [`function_type_t<T>`]] - [[`void(int)`] [`void(int)`]] - [[`void(int) const`] [`void(int)`]] - [[`void(int) transaction_safe`] [`void(int)`]] - [[`void(*const &)(int)`] [`void(int)`]] - [[`void(&)(int)`] [`void(int)`]] - [[`void(* volatile)()`] [`void()`]] - [[`int(foo::*)(int)`] [`int(foo&, int)`]] - [[`int(foo::*)(int) const`] [`int(const foo&, int)`]] - [[`void(foo::*)() volatile &&`] [`void(volatile foo&&)`]] - [[`int foo::*`] [`int(const foo&)`]] - [[`const int foo::*`] [`int(const foo&)`]] - [[`int`] [(substitution failure)]] -] - -[heading Example Program] -[import ../example/function_type.cpp] -[function_type] -[endsect] -*/ -//] - -#endif diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/has_member_qualifiers.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/has_member_qualifiers.hpp deleted file mode 100644 index 3ab44d3b0..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/has_member_qualifiers.hpp +++ /dev/null @@ -1,99 +0,0 @@ -/* - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_HAS_MEMBER_QUALIFIERS_HPP -#define BOOST_CLBL_TRTS_HAS_MEMBER_QUALIFIERS_HPP - -#include <boost/callable_traits/detail/core.hpp> - -namespace boost { namespace callable_traits { - -//[ has_member_qualifiers_hpp -/*`[section:ref_has_member_qualifiers has_member_qualifiers] -[heading Header] -``#include <boost/callable_traits/has_member_qualifiers.hpp>`` -[heading Definition] -*/ - -// inherits from either std::true_type or std::false_type -template<typename T> -struct has_member_qualifiers; - -//<- -template<typename T> -struct has_member_qualifiers : detail::traits< - detail::shallow_decay<T>>::has_member_qualifiers { - - using type = typename detail::traits< - detail::shallow_decay<T>>::has_member_qualifiers; -}; - -// older compilers don't support variable templates -#ifdef BOOST_CLBL_TRTS_DISABLE_VARIABLE_TEMPLATES - -template<typename T> -struct has_member_qualifiers_v { - static_assert(std::is_same<T, detail::dummy>::value, - "Variable templates not supported on this compiler."); -}; - -#else -//-> -// only available when variable templates are supported -template<typename T> -//<- -BOOST_CLBL_TRAITS_INLINE_VAR -//-> -constexpr bool has_member_qualifiers_v = //see below -//<- - detail::traits<detail::shallow_decay<T>>::has_member_qualifiers::value; - -#endif - -}} // namespace boost::callable_traits -//-> - -/*` -[heading Constraints] -* none - -[heading Behavior] -* `std::false_type` is inherited by `has_member_qualifiers<T>` and is aliased by `typename has_member_qualifiers<T>::type`, except when one of the following criteria is met, in which case `std::true_type` would be similarly inherited and aliased: - * `T` is a function with member qualifiers - * `T` is a member function pointer with member qualifiers - * `T` is a function object with a member-qualified `operator()` -* On compilers that support variable templates, `has_member_qualifiers_v<T>` is equivalent to `has_member_qualifiers<T>::value`. - -[heading Input/Output Examples] -[table - [[`T`] [`has_member_qualifiers_v<T>`]] - [[`void() const`] [`true`]] - [[`void() const transaction_safe`] [`true`]] - [[`void() volatile &&`] [`true`]] - [[`int(foo::*)() &`] [`true`]] - [[`void(foo::*)() const`] [`true`]] - [[`void(foo::*&)() const`] [`true`]] - [[`void(foo::* const)() const`] [`true`]] - [[`void()`] [`false`]] - [[`void() transaction_safe`] [`false`]] - [[`void(*)()`] [`false`]] - [[`void(*&)()`] [`false`]] - [[`int`] [`false`]] - [[`const int`] [`false`]] - [[`int foo::*`] [`false`]] - [[`const int foo::*`] [`false`]] -] - -[heading Example Program] -[import ../example/has_member_qualifiers.cpp] -[has_member_qualifiers] -[endsect] -*/ -//] - -#endif //BOOST_CLBL_TRTS_HAS_MEMBER_QUALIFIERS_HPP diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/has_varargs.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/has_varargs.hpp deleted file mode 100644 index 7f7982417..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/has_varargs.hpp +++ /dev/null @@ -1,94 +0,0 @@ -/* - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_HAS_VARARGS_HPP -#define BOOST_CLBL_TRTS_HAS_VARARGS_HPP - -#include <boost/callable_traits/detail/core.hpp> - -namespace boost { namespace callable_traits { - -//[ has_varargs_hpp -/*`[section:ref_has_varargs has_varargs] -[heading Header] -``#include <boost/callable_traits/has_varargs.hpp>`` -[heading Definition] -*/ - - -// inherits from either std::true_type or std::false_type -template<typename T> -struct has_varargs; - -//<- -template<typename T> -struct has_varargs : detail::traits< - detail::shallow_decay<T>>::has_varargs { - - using type = typename detail::traits< - detail::shallow_decay<T>>::has_varargs; -}; - -#ifdef BOOST_CLBL_TRTS_DISABLE_VARIABLE_TEMPLATES - -template<typename T> -struct has_varargs_v { - static_assert(std::is_same<T, detail::dummy>::value, - "Variable templates not supported on this compiler."); -}; - -#else -//-> -// only available when variable templates are supported -template<typename T> -//<- -BOOST_CLBL_TRAITS_INLINE_VAR -//-> -constexpr bool has_varargs_v = //see below -//<- - detail::traits<detail::shallow_decay<T>>::has_varargs::value; - -#endif - -}} // namespace boost::callable_traits -//-> - -/*` -[heading Constraints] -* none - -[heading Behavior] -* `std::false_type` is inherited by `has_varargs<T>` and is aliased by `typename has_varargs<T>::type`, except when one of the following criteria is met, in which case `std::true_type` would be similarly inherited and aliased: - * `T` is a function, function pointer, or function reference where the function's parameter list includes C-style variadics. - * `T` is a pointer to a member function with C-style variadics in the parameter list. - * `T` is a function object with a non-overloaded `operator()`, which has C-style variadics in the parameter list of its `operator()`. -* On compilers that support variable templates, `has_varargs_v<T>` is equivalent to `has_varargs<T>::value`. - -[heading Input/Output Examples] -[table - [[`T`] [`has_varargs_v<T>`]] - [[`void(...)`] [`true`]] - [[`void(int, ...) const`] [`true`]] - [[`void(* volatile)(...)`] [`true`]] - [[`void(&)(...)`] [`true`]] - [[`void(foo::*)(...) const`] [`true`]] - [[`void(*)()`] [`false`]] - [[`void(*&)()`] [`false`]] - [[`int`] [`false`]] - [[`const int`] [`false`]] - [[`int foo::*`] [`false`]] -] - -[heading Example Program] -[import ../example/has_varargs.cpp] -[has_varargs] -[endsect] -*/ -//] - -#endif diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/has_void_return.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/has_void_return.hpp deleted file mode 100644 index 06f80f3dd..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/has_void_return.hpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_HAS_VOID_RETURN_HPP -#define BOOST_CLBL_TRTS_HAS_VOID_RETURN_HPP - -#include <boost/callable_traits/detail/core.hpp> - -namespace boost { namespace callable_traits { - -//[ has_void_return_hpp -/*`[section:ref_has_void_return has_void_return] -[heading Header] -``#include <boost/callable_traits/has_void_return.hpp>`` -[heading Definition] -*/ - -// inherits from either std::true_type or std::false_type -template<typename T> -struct has_void_return; - -//<- -template<typename T> -struct has_void_return - : std::is_same<typename detail::traits< - detail::shallow_decay<T>>::return_type, void> {}; - -#ifdef BOOST_CLBL_TRTS_DISABLE_VARIABLE_TEMPLATES - -template<typename T> -struct has_void_return_v { - static_assert(std::is_same<T, detail::dummy>::value, - "Variable templates not supported on this compiler."); -}; - -#else -//-> - -// only available when variable templates are supported -template<typename T> -//<- -BOOST_CLBL_TRAITS_INLINE_VAR -//-> -constexpr bool has_void_return_v = //see below -//<- - std::is_same<typename detail::traits< - detail::shallow_decay<T>>::return_type, void>::value; - -#endif - -}} // namespace boost::callable_traits -//-> - - -/*` -[heading Constraints] -* none - -[heading Behavior] -* `std::false_type` is inherited by `has_void_return<T>` and is aliased by `typename has_void_return<T>::type`, except when one of the following criteria is met, in which case `std::true_type` would be similarly inherited and aliased: - * `T` is a function, function pointer, or function reference where the function's return type is `void`. - * `T` is a pointer to a member function whose return type is `void`. - * `T` is a function object with a non-overloaded `operator()`, where the `operator()` function returns `void`. -* On compilers that support variable templates, `has_void_return_v<T>` is equivalent to `has_void_return<T>::value`. - -[heading Input/Output Examples] -[table - [[`T`] [`has_void_return_v<T>`]] - [[`void()`] [`true`]] - [[`void(int) const`] [`true`]] - [[`void(* const &)()`] [`true`]] - [[`void(&)()`] [`true`]] - [[`void(foo::*)() const`] [`true`]] - [[`int(*)()`] [`false`]] - [[`int(*&)()`] [`false`]] - [[`int`] [`false`]] - [[`int foo::*`] [`false`]] - [[`void* foo::*`] [`false`]] -] - -[heading Example Program] -[import ../example/has_void_return.cpp] -[has_void_return] -[endsect] -*/ -//] - -#endif diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/is_const_member.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/is_const_member.hpp deleted file mode 100644 index f0a7ad252..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/is_const_member.hpp +++ /dev/null @@ -1,97 +0,0 @@ -/* - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_IS_CONST_MEMBER_HPP -#define BOOST_CLBL_TRTS_IS_CONST_MEMBER_HPP - -#include <boost/callable_traits/detail/core.hpp> - -namespace boost { namespace callable_traits { - -//[ is_const_member_hpp -/*`[section:ref_is_const_member is_const_member] -[heading Header] -``#include <boost/callable_traits/is_const_member.hpp>`` -[heading Definition] -*/ - -// inherits from either std::true_type or std::false_type -template<typename T> -struct is_const_member; - -//<- -template<typename T> -struct is_const_member - : detail::traits<detail::shallow_decay<T>>::is_const_member { - using type = typename detail::traits< - detail::shallow_decay<T>>::is_const_member; -}; - -#ifdef BOOST_CLBL_TRTS_DISABLE_VARIABLE_TEMPLATES - -template<typename T> -struct is_const_member_v { - static_assert(std::is_same<T, detail::dummy>::value, - "Variable templates not supported on this compiler."); -}; - -#else -//-> -// only available when variable templates are supported -template<typename T> -//<- -BOOST_CLBL_TRAITS_INLINE_VAR -//-> -constexpr bool is_const_member_v = //see below -//<- - detail::traits<detail::shallow_decay<T>>::is_const_member::value; - -#endif - -}} // namespace boost::callable_traits -//-> - -/*` -[heading Constraints] -* none - -[heading Behavior] -* `is_const_member<T>::value` is `true` when either: - * `T` is a function type with a `const` member qualifier - * `T` is a pointer to a member function with a `const` member qualifier - * `T` is a function object with a non-overloaded `operator()`, where the `operator()` has a `const` member qualifier -* On compilers that support variable templates, `is_const_member_v<T>` is equivalent to `is_const_member<T>::value`. - -[heading Input/Output Examples] -[table - [[`T`] [`is_const_member_v<T>`]] - [[`int() const`] [`true`]] - [[`int() const volatile`] [`true`]] - [[`int() const & transaction_safe`] [`true`]] - [[`int() const &&`] [`true`]] - [[`int(foo::*&)() const`] [`true`]] - [[`int(foo::*)() const volatile`] [`true`]] - [[`int(foo::*)() const volatile &&`][`true`]] - [[`int(foo::* const)() const`] [`true`]] - [[`int()`] [`false`]] - [[`int() volatile`] [`false`]] - [[`int() &&`] [`false`]] - [[`int(*)()`] [`false`]] - [[`int`] [`false`]] - [[`int foo::*`] [`false`]] - [[`const int foo::*`] [`false`]] -] - -[heading Example Program] -[import ../example/is_const_member.cpp] -[is_const_member] -[endsect] -*/ -//] - -#endif // #ifndef BOOST_CLBL_TRTS_IS_CONST_MEMBER_HPP diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/is_cv_member.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/is_cv_member.hpp deleted file mode 100644 index 6e95545ee..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/is_cv_member.hpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_IS_CV_MEMBER_HPP -#define BOOST_CLBL_TRTS_IS_CV_MEMBER_HPP - -#include <boost/callable_traits/detail/core.hpp> - -namespace boost { namespace callable_traits { - -//[ is_cv_member_hpp -/*`[section:ref_is_cv_member is_cv_member] -[heading Header] -``#include <boost/callable_traits/is_cv_member.hpp>`` -[heading Definition] -*/ - -// inherits from either std::true_type or std::false_type -template<typename T> -struct is_cv_member; - -//<- -template<typename T> -struct is_cv_member - : detail::traits<detail::shallow_decay<T>>::is_cv_member { - using type = typename detail::traits< - detail::shallow_decay<T>>::is_cv_member; -}; - -#ifdef BOOST_CLBL_TRTS_DISABLE_VARIABLE_TEMPLATES - -template<typename T> -struct is_cv_member_v { - static_assert(std::is_same<T, detail::dummy>::value, - "Variable templates not supported on this compiler."); -}; - -#else -//-> -// only available when variable templates are supported -template<typename T> -//<- -BOOST_CLBL_TRAITS_INLINE_VAR -//-> -constexpr bool is_cv_member_v = //see below -//<- - detail::traits<detail::shallow_decay<T>>::is_cv_member::value; - -#endif - -}} // namespace boost::callable_traits -//-> - -/*` -[heading Constraints] -* none - -[heading Behavior] -* `is_cv_member<T>::value` is `true` when either: - * `T` is a function type with both `const` and `volatile` member qualifiers - * `T` is a pointer to a member function with both `const` and `volatile` member qualifiers - * `T` is a function object with a non-overloaded `operator()`, where the `operator()` has both `const` and `volatile` member qualifiers -* On compilers that support variable templates, `is_cv_member_v<T>` is equivalent to `is_cv_member<T>::value`. - -[heading Input/Output Examples] -[table - [[`T`] [`is_cv_member_v<T>`]] - [[`int() const volatile`] [`true`]] - [[`int() const volatile &`] [`true`]] - [[`int(foo::* const &)() const volatile`] [`true`]] - [[`int() const`] [`false`]] - [[`int() volatile`] [`false`]] - [[`int(foo::*)() const`] [`false`]] - [[`int() const`] [`false`]] - [[`int() volatile`] [`false`]] - [[`int() &&`] [`false`]] - [[`int(*)()`] [`false`]] - [[`int`] [`false`]] - [[`int foo::*`] [`false`]] - [[`const int foo::*`] [`false`]] -] - -[heading Example Program] -[import ../example/is_cv_member.cpp] -[is_cv_member] -[endsect] -*/ -//] - -#endif // #ifndef BOOST_CLBL_TRTS_IS_CV_MEMBER_HPP diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/is_invocable.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/is_invocable.hpp deleted file mode 100644 index 892d8fb71..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/is_invocable.hpp +++ /dev/null @@ -1,103 +0,0 @@ -/* - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_IS_INVOCABLE_HPP -#define BOOST_CLBL_TRTS_IS_INVOCABLE_HPP - -#include <boost/callable_traits/detail/core.hpp> -#include <boost/callable_traits/detail/is_invocable_impl.hpp> - -namespace boost { namespace callable_traits { - -//[ is_invocable_hpp -/*`[section:ref_is_invocable is_invocable] -[heading Header] -``#include <boost/callable_traits/is_invocable.hpp>`` -[heading Definition] -*/ - -// inherits from either std::true_type or std::false_type -template<typename T, typename... Args> -struct is_invocable; - -// inherits from either std::true_type or std::false_type -template<typename Ret, typename T, typename... Args> -struct is_invocable_r; - -//<- -template<typename T, typename... Args> -struct is_invocable : detail::is_invocable_impl<T, Args...>::type { - using type = typename detail::is_invocable_impl<T, Args...>::type; -}; - -template<typename Ret, typename T, typename... Args> -struct is_invocable_r - : detail::is_invocable_r_impl< - typename detail::is_invocable_impl<T, Args...>::type, Ret, T, Args...>::type -{ - using type = typename detail::is_invocable_r_impl< - typename detail::is_invocable_impl<T, Args...>::type, Ret, T, Args...>::type; -}; - -#ifdef BOOST_CLBL_TRTS_DISABLE_VARIABLE_TEMPLATES - -template<typename T, typename... Args> -struct is_invocable_v { - static_assert(std::is_same<T, detail::dummy>::value, - "Variable templates not supported on this compiler."); -}; - -template<typename Ret, typename T, typename... Args> -struct is_invocable_r_v { - static_assert(std::is_same<T, detail::dummy>::value, - "Variable templates not supported on this compiler."); -}; - -#else -//-> -// only available when variable templates are supported -template<typename T, typename... Args> -//<- -BOOST_CLBL_TRAITS_INLINE_VAR -//-> -constexpr bool is_invocable_v = //see below -//<- - detail::is_invocable_impl<detail::traits<T>, Args...>::type::value; -//-> - -// only available when variable templates are supported -template<typename Ret, typename T, typename... Args> -//<- -BOOST_CLBL_TRAITS_INLINE_VAR -//-> -constexpr bool is_invocable_r_v = //see below -//<- - detail::is_invocable_r_impl< - typename detail::is_invocable_impl<T, Args...>::type, - Ret, T, Args...>::type::value; -#endif - -}} // namespace boost::callable_traits -//-> - -/*` -[heading Constraints] -* none - -[heading Behavior] -* standalone c++11 implementation of c++17 `std::is_invocable`, `std::is_invocable_r` -[note ref-qualified overloads of `operator()` with different signatures are not handled correctly yet.] - -[heading Example Program] -[import ../example/is_invocable.cpp] -[is_invocable] -[endsect] -*/ -//] - -#endif // #ifndef BOOST_CLBL_TRTS_IS_INVOCABLE_HPP diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/is_lvalue_reference_member.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/is_lvalue_reference_member.hpp deleted file mode 100644 index 89500cb93..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/is_lvalue_reference_member.hpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_IS_LVALUE_REFERENCE_MEMBER_HPP -#define BOOST_CLBL_TRTS_IS_LVALUE_REFERENCE_MEMBER_HPP - -#include <boost/callable_traits/detail/core.hpp> - -namespace boost { namespace callable_traits { - -//[ is_lvalue_reference_member_hpp -/*`[section:ref_is_lvalue_reference_member is_lvalue_reference_member] -[heading Header] -``#include <boost/callable_traits/is_lvalue_reference_member.hpp>`` -[heading Definition] -*/ - - -// inherits from either std::true_type or std::false_type -template<typename T> -struct is_lvalue_reference_member; - -//<- -template<typename T> -struct is_lvalue_reference_member - : detail::traits<detail::shallow_decay<T>>::is_lvalue_reference_member { - using type = typename detail::traits< - detail::shallow_decay<T>>::is_lvalue_reference_member; -}; - -#ifdef BOOST_CLBL_TRTS_DISABLE_VARIABLE_TEMPLATES - -template<typename T> -struct is_lvalue_reference_member_v { - static_assert(std::is_same<T, detail::dummy>::value, - "Variable templates not supported on this compiler."); -}; - -#else -//-> -// only available when variable templates are supported -template<typename T> -//<- -BOOST_CLBL_TRAITS_INLINE_VAR -//-> -constexpr bool is_lvalue_reference_member_v = //see below -//<- - detail::traits<detail::shallow_decay<T>>::is_lvalue_reference_member::value; - -#endif - -}} // namespace boost::callable_traits -//-> - -/*` -[heading Constraints] -* none - -[heading Behavior] -* `is_lvalue_reference_member<T>::value` is `true` when either: - * `T` is a function type with a '&' member qualifier - * `T` is a pointer to a member function with a '&' member qualifiers - * `T` is a function object with a non-overloaded `operator()`, where the `operator()` has a '&' member qualifier -* On compilers that support variable templates, `is_lvalue_reference_member_v<T>` is equivalent to `is_lvalue_reference_member<T>::value`. - -[heading Input/Output Examples] -[table - [[`T`] [`is_lvalue_reference_member_v<T>`]] - [[`int() &`] [`true`]] - [[`int(foo::* const)() const &`] [`true`]] - [[`int() const`] [`false`]] - [[`int() volatile`] [`false`]] - [[`int(foo::*)() const`] [`false`]] - [[`int() const`] [`false`]] - [[`int() volatile`] [`false`]] - [[`int() &&`] [`false`]] - [[`int(*)()`] [`false`]] - [[`int`] [`false`]] - [[`int foo::*`] [`false`]] - [[`const int foo::*`] [`false`]] -] - -[heading Example Program] -[import ../example/is_lvalue_reference_member.cpp] -[is_lvalue_reference_member] -[endsect] -*/ -//] - -#endif // #ifndef BOOST_CLBL_TRTS_IS_LVALUE_REFERENCE_MEMBER_HPP diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/is_noexcept.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/is_noexcept.hpp deleted file mode 100644 index 36320f689..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/is_noexcept.hpp +++ /dev/null @@ -1,95 +0,0 @@ -/* -@file is_noexcept - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_IS_NOEXCEPT_HPP -#define BOOST_CLBL_TRTS_IS_NOEXCEPT_HPP - -#include <boost/callable_traits/detail/core.hpp> - -namespace boost { namespace callable_traits { - -//[ is_noexcept_hpp -/*`[section:ref_is_noexcept is_noexcept] -[heading Header] -``#include <boost/callable_traits/is_noexcept.hpp>`` -[heading Definition] -*/ - -// inherits from either std::true_type or std::false_type -template<typename T> -struct is_noexcept; - -//<- -template<typename T> -struct is_noexcept : detail::traits<detail::shallow_decay<T>>::is_noexcept { - using type = typename detail::traits< - detail::shallow_decay<T>>::is_noexcept; -}; - -#ifdef BOOST_CLBL_TRTS_DISABLE_VARIABLE_TEMPLATES - -template<typename T> -struct is_noexcept_v { - static_assert(std::is_same<T, detail::dummy>::value, - "Variable templates not supported on this compiler."); -}; - -#else -//-> -// only available when variable templates are supported -template<typename T> -//<- -BOOST_CLBL_TRAITS_INLINE_VAR -//-> -constexpr bool is_noexcept_v = //see below -//<- - detail::traits<detail::shallow_decay<T>>::is_noexcept::value; - -#endif - -}} // namespace boost::callable_traits -//-> - -/*` -[heading Constraints] -* none -* -[heading Behavior] -* `is_noexcept<T>::value` is `true` when either: - * `T` is a function type, function pointer type, function reference type, or member function pointer type where the function has a `noexcept` specifier - * `T` is a function object with a non-overloaded `operator()`, where the `operator()` has a `noexcept` specifier -* On compilers that support variable templates, `is_noexcept_v<T>` is equivalent to `is_noexcept<T>::value`. - -[heading Input/Output Examples] -[table - [[`T`] [`is_noexcept_v<T>`]] - [[`int() const noexcept`] [`true`]] - [[`int(* const &)() noexcept`] [`true`]] - [[`int(&)() noexcept`] [`true`]] - [[`int(foo::*)() noexcept`] [`true`]] - [[`int() const`] [`false`]] - [[`int() volatile`] [`false`]] - [[`int(foo::*)() const`] [`false`]] - [[`int() const`] [`false`]] - [[`int() volatile`] [`false`]] - [[`int() &`] [`false`]] - [[`int(*)()`] [`false`]] - [[`int`] [`false`]] - [[`int foo::*`] [`false`]] - [[`const int foo::*`] [`false`]] -] - -[heading Example Program] -[import ../example/is_noexcept.cpp] -[is_noexcept] -[endsect] -*/ -//] - -#endif // #ifndef BOOST_CLBL_TRTS_IS_NOEXCEPT_HPP diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/is_reference_member.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/is_reference_member.hpp deleted file mode 100644 index ef893a04d..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/is_reference_member.hpp +++ /dev/null @@ -1,98 +0,0 @@ -/* - -@Copyright Barrett Adair 2015-2017 - -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_IS_REFERENCE_MEMBER_HPP -#define BOOST_CLBL_TRTS_IS_REFERENCE_MEMBER_HPP - -#include <boost/callable_traits/detail/core.hpp> - -namespace boost { namespace callable_traits { - -//[ is_reference_member_hpp -/*`[section:ref_is_reference_member is_reference_member] -[heading Header] -``#include <boost/callable_traits/is_reference_member.hpp>`` -[heading Definition] -*/ - - -// inherits from either std::true_type or std::false_type -template<typename T> -struct is_reference_member; - -//<- -template<typename T> -struct is_reference_member : detail::traits< - detail::shallow_decay<T>>::is_reference_member { - - using type = typename detail::traits< - detail::shallow_decay<T>>::is_reference_member; -}; - -#ifdef BOOST_CLBL_TRTS_DISABLE_VARIABLE_TEMPLATES - -template<typename T> -struct is_reference_member_v { - static_assert(std::is_same<T, detail::dummy>::value, - "Variable templates not supported on this compiler."); -}; - -#else -//-> -// only available when variable templates are supported -template<typename T> -//<- -BOOST_CLBL_TRAITS_INLINE_VAR -//-> -constexpr bool is_reference_member_v = //see below -//<- - detail::traits<detail::shallow_decay<T>>::is_reference_member::value; - -#endif - -}} // namespace boost::callable_traits -//-> - -/*` -[heading Constraints] -* none - -[heading Behavior] -* `is_reference_member<T>::value` is `true` when either: - * `T` is a function type with a '&' or '&&' member qualifier - * `T` is a pointer to a member function with a '&' or '&&' member qualifiers - * `T` is a function object with a non-overloaded `operator()`, where the `operator()` has a '&' or '&&' member qualifier -* On compilers that support variable templates, `is_reference_member_v<T>` is equivalent to `is_reference_member<T>::value`. - -[heading Input/Output Examples] -[table - [[`T`] [`is_reference_member_v<T>`]] - [[`int() &`] [`true`]] - [[`int() const &&`] [`true`]] - [[`int(foo::* const)() &&`] [`true`]] - [[`int(foo::*)(...) volatile &`] [`true`]] - [[`int() const`] [`false`]] - [[`int() volatile`] [`false`]] - [[`int(foo::*)() const`] [`false`]] - [[`int() const`] [`false`]] - [[`int() volatile`] [`false`]] - [[`int(*)()`] [`false`]] - [[`int`] [`false`]] - [[`int foo::*`] [`false`]] - [[`const int foo::*`] [`false`]] -] - -[heading Example Program] -[import ../example/is_reference_member.cpp] -[is_reference_member] -[endsect] -*/ -//] - -#endif // #ifndef BOOST_CLBL_TRTS_IS_REFERENCE_MEMBER_HPP diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/is_rvalue_reference_member.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/is_rvalue_reference_member.hpp deleted file mode 100644 index a852ce6e1..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/is_rvalue_reference_member.hpp +++ /dev/null @@ -1,97 +0,0 @@ -/* - -@Copyright Barrett Adair 2015-2017 - -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_IS_RVALUE_REFERENCE_MEMBER_HPP -#define BOOST_CLBL_TRTS_IS_RVALUE_REFERENCE_MEMBER_HPP - -#include <boost/callable_traits/detail/core.hpp> - -namespace boost { namespace callable_traits { - -//[ is_rvalue_reference_member_hpp -/*`[section:ref_is_rvalue_reference_member is_rvalue_reference_member] -[heading Header] -``#include <boost/callable_traits/is_rvalue_reference_member.hpp>`` -[heading Definition] -*/ - - -// inherits from either std::true_type or std::false_type -template<typename T> -struct is_rvalue_reference_member; - -//<- -template<typename T> -struct is_rvalue_reference_member : detail::traits< - detail::shallow_decay<T>>::is_rvalue_reference_member { - - using type = typename detail::traits< - detail::shallow_decay<T>>::is_rvalue_reference_member; -}; - -#ifdef BOOST_CLBL_TRTS_DISABLE_VARIABLE_TEMPLATES - -template<typename T> -struct is_rvalue_reference_member_v { - static_assert(std::is_same<T, detail::dummy>::value, - "Variable templates not supported on this compiler."); -}; - -#else -//-> -// only available when variable templates are supported -template<typename T> -//<- -BOOST_CLBL_TRAITS_INLINE_VAR -//-> -constexpr bool is_rvalue_reference_member_v = //see below -//<- - detail::traits<detail::shallow_decay<T>>::is_rvalue_reference_member::value; - -#endif - -}} // namespace boost::callable_traits -//-> - -/*` -[heading Constraints] -* none - -[heading Behavior] -* `is_rvalue_reference_member<T>::value` is `true` when either: - * `T` is a function type with a '&&' member qualifier - * `T` is a pointer to a member function with a '&&' member qualifiers - * `T` is a function object with a non-overloaded `operator()`, where the `operator()` has a '&&' member qualifier -* On compilers that support variable templates, `is_rvalue_reference_member_v<T>` is equivalent to `is_rvalue_reference_member<T>::value`. - -[heading Input/Output Examples] -[table - [[`T`] [`is_rvalue_reference_member_v<T>`]] - [[`int() const &&`] [`true`]] - [[`int(foo::*)() &&`] [`true`]] - [[`int() const`] [`false`]] - [[`int() volatile`] [`false`]] - [[`int(foo::* volatile)() const`] [`false`]] - [[`int() const`] [`false`]] - [[`int() volatile`] [`false`]] - [[`int() &`] [`false`]] - [[`int(*)()`] [`false`]] - [[`int`] [`false`]] - [[`int foo::*`] [`false`]] - [[`const int foo::*`] [`false`]] -] - -[heading Example Program] -[import ../example/is_rvalue_reference_member.cpp] -[is_rvalue_reference_member] -[endsect] -*/ -//] - -#endif // #ifndef BOOST_CLBL_TRTS_IS_RVALUE_REFERENCE_MEMBER_HPP diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/is_transaction_safe.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/is_transaction_safe.hpp deleted file mode 100644 index 51c98c53e..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/is_transaction_safe.hpp +++ /dev/null @@ -1,98 +0,0 @@ -/* -@file is_transaction_safe - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_IS_TRANSACTION_SAFE_HPP -#define BOOST_CLBL_TRTS_IS_TRANSACTION_SAFE_HPP - -#include <boost/callable_traits/detail/core.hpp> - -namespace boost { namespace callable_traits { - -//[ is_transaction_safe_hpp -/*`[section:ref_is_transaction_safe is_transaction_safe] -[heading Header] -``#include <boost/callable_traits/is_transaction_safe.hpp>`` -[heading Definition] -*/ - - -// inherits from either std::true_type or std::false_type -template<typename T> -struct is_transaction_safe; - -//<- -template<typename T> -struct is_transaction_safe : detail::traits< - detail::shallow_decay<T>>::is_transaction_safe { - - using type = typename detail::traits< - detail::shallow_decay<T>>::is_transaction_safe; -}; - -#ifdef BOOST_CLBL_TRTS_DISABLE_VARIABLE_TEMPLATES - -template<typename T> -struct is_transaction_safe_v { - static_assert(std::is_same<T, detail::dummy>::value, - "Variable templates not supported on this compiler."); -}; - -#else -//-> -// only available when variable templates are supported -template<typename T> -//<- -BOOST_CLBL_TRAITS_INLINE_VAR -//-> -constexpr bool is_transaction_safe_v = //see below -//<- - detail::traits<detail::shallow_decay<T>>::is_transaction_safe::value; - -#endif - -}} // namespace boost::callable_traits -//-> - -/*` -[heading Constraints] -* none -* -[heading Behavior] -* `is_transaction_safe<T>::value` is `true` when either: - * `T` is a function type, function pointer type, function reference type, or member function pointer type where the function has a `transaction_safe` specifier - * `T` is a function object with a non-overloaded `operator()`, where the `operator()` has a `transaction_safe` specifier -* On compilers that support variable templates, `is_transaction_safe_v<T>` is equivalent to `is_transaction_safe<T>::value`. - -[heading Input/Output Examples] -[table - [[`T`] [`is_transaction_safe_v<T>`]] - [[`int() const transaction_safe`] [`true`]] - [[`int(*)() transaction_safe`] [`true`]] - [[`int(&)() transaction_safe`] [`true`]] - [[`int(foo::* const)() transaction_safe`] [`true`]] - [[`int() const`] [`false`]] - [[`int() volatile`] [`false`]] - [[`int(foo::*)() const`] [`false`]] - [[`int() const`] [`false`]] - [[`int() volatile`] [`false`]] - [[`int() &`] [`false`]] - [[`int(*)()`] [`false`]] - [[`int`] [`false`]] - [[`int foo::*`] [`false`]] - [[`const int foo::*`] [`false`]] -] - -[heading Example Program] -[import ../example/is_transaction_safe.cpp] -[is_transaction_safe] -[endsect] -*/ -//] - -#endif // #ifndef BOOST_CLBL_TRTS_IS_TRANSACTION_SAFE_HPP diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/is_volatile_member.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/is_volatile_member.hpp deleted file mode 100644 index 2309eec62..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/is_volatile_member.hpp +++ /dev/null @@ -1,100 +0,0 @@ -/* - * -@Copyright Barrett Adair 2015-2017 - -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_IS_VOLATILE_MEMBER_HPP -#define BOOST_CLBL_TRTS_IS_VOLATILE_MEMBER_HPP - -#include <boost/callable_traits/detail/core.hpp> - -namespace boost { namespace callable_traits { - -//[ is_volatile_member_hpp -/*`[section:ref_is_volatile_member is_volatile_member] -[heading Header] -``#include <boost/callable_traits/is_volatile_member.hpp>`` -[heading Definition] -*/ - - -// inherits from either std::true_type or std::false_type -template<typename T> -struct is_volatile_member; - -//<- -template<typename T> -struct is_volatile_member : detail::traits< - detail::shallow_decay<T>>::is_volatile_member { - - using type = typename detail::traits< - detail::shallow_decay<T>>::is_volatile_member; -}; - -#ifdef BOOST_CLBL_TRTS_DISABLE_VARIABLE_TEMPLATES - -template<typename T> -struct is_volatile_member_v { - static_assert(std::is_same<T, detail::dummy>::value, - "Variable templates not supported on this compiler."); -}; - -#else -//-> -// only available when variable templates are supported -template<typename T> -//<- -BOOST_CLBL_TRAITS_INLINE_VAR -//-> -constexpr bool is_volatile_member_v = //see below -//<- - detail::traits<detail::shallow_decay<T>>::is_volatile_member::value; - -#endif - -}} // namespace boost::callable_traits -//-> - - -/*` -[heading Constraints] -* none - -[heading Behavior] -* `is_volatile_member<T>::value` is `true` when either: - * `T` is a function type with a `volatile` member qualifier - * `T` is a pointer to a member function with a `volatile` member qualifier - * `T` is a function object with a non-overloaded `operator()`, where the `operator()` has a `volatile` member qualifier -* On compilers that support variable templates, `is_volatile_member_v<T>` is equivalent to `is_volatile_member<T>::value`. - -[heading Input/Output Examples] -[table - [[`T`] [`is_volatile_member_v<T>`]] - [[`int() volatile`] [`true`]] - [[`int() const volatile`] [`true`]] - [[`int() volatile &&`] [`true`]] - [[`int(foo::*)() volatile`] [`true`]] - [[`int(foo::* const)() volatile`] [`true`]] - [[`int(foo::*)() const volatile`] [`true`]] - [[`int(foo::*)() const volatile &&`][`true`]] - [[`int()`] [`false`]] - [[`int() const`] [`false`]] - [[`int() &&`] [`false`]] - [[`int(*)()`] [`false`]] - [[`int`] [`false`]] - [[`int foo::*`] [`false`]] - [[`volatile int foo::*`] [`false`]] -] - -[heading Example Program] -[import ../example/is_volatile_member.cpp] -[is_volatile_member] -[endsect] -*/ -//] - -#endif // #ifndef BOOST_CLBL_TRTS_IS_VOLATILE_MEMBER_HPP diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/qualified_class_of.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/qualified_class_of.hpp deleted file mode 100644 index 9f9e58117..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/qualified_class_of.hpp +++ /dev/null @@ -1,81 +0,0 @@ -/* - -@Copyright Barrett Adair 2015-2017 - -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_QUALIFIED_class_of_HPP -#define BOOST_CLBL_TRTS_QUALIFIED_class_of_HPP - -#include <boost/callable_traits/detail/core.hpp> - -namespace boost { namespace callable_traits { - -//[ qualified_class_of_hpp -/*` -[section:ref_qualified_class_of qualified_class_of] -[heading Header] -``#include <boost/callable_traits/qualified_class_of.hpp>`` -[heading Definition] -*/ - -template<typename T> -using qualified_class_of_t = //see below -//<- - detail::try_but_fail_if_invalid< - typename detail::traits<detail::shallow_decay<T>>::invoke_type, - type_is_not_a_member_pointer>; - -namespace detail { - - template<typename T, typename = std::false_type> - struct qualified_class_of_impl {}; - - template<typename T> - struct qualified_class_of_impl <T, typename std::is_same< - qualified_class_of_t<T>, detail::dummy>::type> - { - using type = qualified_class_of_t<T>; - }; -} - -//-> - -template<typename T> -struct qualified_class_of : detail::qualified_class_of_impl<T> {}; - -//<- -}} // namespace boost::callable_traits -//-> - -/*` -[heading Constraints] -* `T` must be a member pointer - -[heading Behavior] -* A substitution failure occurs if the constraints are violated. -* If `T` is a member function pointer, the aliased type is the parent class of the member, qualified according to the member qualifiers on `T`. If `T` does not have a member reference qualifier, then the aliased type will be an lvalue reference. -* If `T` is a member data pointer, the aliased type is equivalent to `ct::class_of<T> const &`. - -[heading Input/Output Examples] -[table - [[`T`] [`qualified_class_of_t<T>`]] - [[`void(foo::*)()`] [`foo &`]] - [[`void(foo::* volatile)() const`] [`foo const &`]] - [[`void(foo::*)() &&`] [`foo &&`]] - [[`void(foo::*&)() volatile &&`] [`foo volatile &&`]] - [[`int foo::*`] [`foo const &`]] - [[`const int foo::*`] [`foo const &`]] -] - -[heading Example Program] -[import ../example/qualified_class_of.cpp] -[qualified_class_of] -[endsect] -*/ -//] - -#endif // #ifndef BOOST_CLBL_TRTS_QUALIFIED_class_of_HPP diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/remove_member_const.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/remove_member_const.hpp deleted file mode 100644 index 132680082..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/remove_member_const.hpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_REMOVE_MEMBER_CONST_HPP -#define BOOST_CLBL_TRTS_REMOVE_MEMBER_CONST_HPP - -#include <boost/callable_traits/detail/core.hpp> - -namespace boost { namespace callable_traits { - -//[ remove_member_const_hpp -/*` -[section:ref_remove_member_const remove_member_const] -[heading Header] -``#include <boost/callable_traits/remove_member_const.hpp>`` -[heading Definition] -*/ - -template<typename T> -using remove_member_const_t = //see below -//<- - detail::try_but_fail_if_invalid< - typename detail::traits<T>::remove_member_const, - member_qualifiers_are_illegal_for_this_type>; - -namespace detail { - - template<typename T, typename = std::false_type> - struct remove_member_const_impl {}; - - template<typename T> - struct remove_member_const_impl <T, typename std::is_same< - remove_member_const_t<T>, detail::dummy>::type> - { - using type = remove_member_const_t<T>; - }; -} - -//-> - -template<typename T> -struct remove_member_const : detail::remove_member_const_impl<T> {}; - -//<- -}} // namespace boost::callable_traits -//-> - -/*` -[heading Constraints] -* `T` must be a function type or a member function pointer type -* If `T` is a pointer, it may not be cv/ref qualified - -[heading Behavior] -* A substitution failure occurs if the constraints are violated. -* Removes the member `const` qualifier from `T`, if present. - -[heading Input/Output Examples] -[table - [[`T`] [`remove_member_const_t<T>`]] - [[`int() const`] [`int()`]] - [[`int(foo::*)() const`] [`int(foo::*)()`]] - [[`int(foo::*)() const &`] [`int(foo::*)() &`]] - [[`int(foo::*)() const &&`] [`int(foo::*)() &&`]] - [[`int(foo::*)() const`] [`int(foo::*)()`]] - [[`int(foo::*)() const volatile`] [`int(foo::*)() volatile`]] - [[`int`] [(substitution failure)]] - [[`int (&)()`] [(substitution failure)]] - [[`int (*)()`] [(substitution failure)]] - [[`int foo::*`] [(substitution failure)]] - [[`int (foo::* const)()`] [(substitution failure)]] -] - -[heading Example Program] -[import ../example/remove_member_const.cpp] -[remove_member_const] -[endsect] -*/ -//] - -#endif // #ifndef BOOST_CLBL_TRTS_REMOVE_MEMBER_CONST_HPP diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/remove_member_cv.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/remove_member_cv.hpp deleted file mode 100644 index 30d99a082..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/remove_member_cv.hpp +++ /dev/null @@ -1,87 +0,0 @@ -/* - -@Copyright Barrett Adair 2015-2017 - -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_REMOVE_MEMBER_CV_HPP -#define BOOST_CLBL_TRTS_REMOVE_MEMBER_CV_HPP - -#include <boost/callable_traits/detail/core.hpp> - -namespace boost { namespace callable_traits { - -//[ remove_member_cv_hpp -/*` -[section:ref_remove_member_cv remove_member_cv] -[heading Header] -``#include <boost/callable_traits/remove_member_cv.hpp>`` -[heading Definition] -*/ - -template<typename T> -using remove_member_cv_t = //see below -//<- - detail::try_but_fail_if_invalid< - typename detail::traits<T>::remove_member_cv, - member_qualifiers_are_illegal_for_this_type>; - -namespace detail { - - template<typename T, typename = std::false_type> - struct remove_member_cv_impl {}; - - template<typename T> - struct remove_member_cv_impl <T, typename std::is_same< - remove_member_cv_t<T>, detail::dummy>::type> - { - using type = remove_member_cv_t<T>; - }; -} - -//-> - -template<typename T> -struct remove_member_cv : detail::remove_member_cv_impl<T> {}; - -//<- -}} // namespace boost::callable_traits -//-> - -/*` -[heading Constraints] -* `T` must be a function type or a member function pointer type -* If `T` is a pointer, it may not be cv/ref qualified - -[heading Behavior] -* A substitution failure occurs if the constraints are violated. -* Removes member `const` and/or `volatile` qualifiers from `T`, if present. - -[heading Input/Output Examples] -[table - [[`T`] [`remove_member_cv_t<T>`]] - [[`int() const volatile`] [`int()`]] - [[`int(foo::*)() const volatile`] [`int(foo::*)()`]] - [[`int(foo::*)() volatile`] [`int(foo::*)()`]] - [[`int(foo::*)() const`] [`int(foo::*)()`]] - [[`int(foo::*)() const &`] [`int(foo::*)() &`]] - [[`int(foo::*)() const &&`] [`int(foo::*)() &&`]] - [[`int(foo::*)() const`] [`int(foo::*)()`]] - [[`int`] [(substitution failure)]] - [[`int (&)()`] [(substitution failure)]] - [[`int (*)()`] [(substitution failure)]] - [[`int foo::*`] [(substitution failure)]] - [[`int (foo::* const)()`] [(substitution failure)]] -] - -[heading Example Program] -[import ../example/remove_member_cv.cpp] -[remove_member_cv] -[endsect] -*/ -//] - -#endif // #ifndef BOOST_CLBL_TRTS_REMOVE_MEMBER_CV_HPP diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/remove_member_reference.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/remove_member_reference.hpp deleted file mode 100644 index d4e4b62ce..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/remove_member_reference.hpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_REMOVE_MEMBER_REFERENCE_HPP -#define BOOST_CLBL_TRTS_REMOVE_MEMBER_REFERENCE_HPP - -#include <boost/callable_traits/detail/core.hpp> - -namespace boost { namespace callable_traits { - -//[ remove_member_reference_hpp -/*` -[section:ref_remove_member_reference remove_member_reference] -[heading Header] -``#include <boost/callable_traits/remove_member_reference.hpp>`` -[heading Definition] -*/ - -template<typename T> -using remove_member_reference_t = //see below -//<- - detail::try_but_fail_if_invalid< - typename detail::traits<T>::remove_member_reference, - member_qualifiers_are_illegal_for_this_type>; - -namespace detail { - - template<typename T, typename = std::false_type> - struct remove_member_reference_impl {}; - - template<typename T> - struct remove_member_reference_impl <T, typename std::is_same< - remove_member_reference_t<T>, detail::dummy>::type> - { - using type = remove_member_reference_t<T>; - }; -} - -//-> - -template<typename T> -struct remove_member_reference - : detail::remove_member_reference_impl<T> {}; - -//<- -}} // namespace boost::callable_traits -//-> - -/*` -[heading Constraints] -* `T` must be a function type or a member function pointer type -* If `T` is a pointer, it may not be cv/ref qualified - -[heading Behavior] -* A substitution failure occuers if the constraints are violated. -* Removes member `&` or `&&` qualifiers from `T`, if present. - -[heading Input/Output Examples] -[table - [[`T`] [`remove_member_const_t<T>`]] - [[`int() &`] [`int()`]] - [[`int(foo::*)() &`] [`int(foo::*)()`]] - [[`int(foo::*)() const &`] [`int(foo::*)() const`]] - [[`int(foo::*)() const &&`] [`int(foo::*)() const`]] - [[`int(foo::*)()`] [`int(foo::*)()`]] - [[`int`] [(substitution failure)]] - [[`int (&)()`] [(substitution failure)]] - [[`int (*)()`] [(substitution failure)]] - [[`int foo::*`] [(substitution failure)]] - [[`int (foo::* const)()`] [(substitution failure)]] -] - -[heading Example Program] -[import ../example/remove_member_reference.cpp] -[remove_member_reference] -[endsect] -*/ -//] - -#endif // #ifndef BOOST_CLBL_TRTS_REMOVE_MEMBER_REFERENCE_HPP diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/remove_member_volatile.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/remove_member_volatile.hpp deleted file mode 100644 index d20c79684..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/remove_member_volatile.hpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_REMOVE_MEMBER_VOLATILE_HPP -#define BOOST_CLBL_TRTS_REMOVE_MEMBER_VOLATILE_HPP - -#include <boost/callable_traits/detail/core.hpp> - -namespace boost { namespace callable_traits { - -//[ remove_member_volatile_hpp -/*` -[section:ref_remove_member_volatile remove_member_volatile] -[heading Header] -``#include <boost/callable_traits/remove_member_volatile.hpp>`` -[heading Definition] -*/ - -template<typename T> -using remove_member_volatile_t = //see below -//<- - detail::try_but_fail_if_invalid< - typename detail::traits<T>::remove_member_volatile, - member_qualifiers_are_illegal_for_this_type>; - -namespace detail { - - template<typename T, typename = std::false_type> - struct remove_member_volatile_impl {}; - - template<typename T> - struct remove_member_volatile_impl <T, typename std::is_same< - remove_member_volatile_t<T>, detail::dummy>::type> - { - using type = remove_member_volatile_t<T>; - }; -} - -//-> - -template<typename T> -struct remove_member_volatile : detail::remove_member_volatile_impl<T> {}; - -//<- -}} // namespace boost::callable_traits -//-> - -/*` -[heading Constraints] -* `T` must be a function type or a member function pointer type -* If `T` is a pointer, it may not be cv/ref qualified - -[heading Behavior] -* A substitution failure occurs if the constraints are violated. -* Removes the member `volatile` qualifier from `T`, if present. - -[heading Input/Output Examples] -[table - [[`T`] [`remove_member_volatile_t<T>`]] - [[`int() volatile`] [`int()`]] - [[`int(foo::*)() volatile`] [`int(foo::*)()`]] - [[`int(foo::*)() volatile &`] [`int(foo::*)() &`]] - [[`int(foo::*)() volatile &&`] [`int(foo::*)() &&`]] - [[`int(foo::*)() volatile`] [`int(foo::*)()`]] - [[`int(foo::*)() const volatile`] [`int(foo::*)() const`]] - [[`int`] [(substitution failure)]] - [[`int (&)()`] [(substitution failure)]] - [[`int (*)()`] [(substitution failure)]] - [[`int foo::*`] [(substitution failure)]] - [[`int (foo::* const)()`] [(substitution failure)]] -] - -[heading Example Program] -[import ../example/remove_member_volatile.cpp] -[remove_member_volatile] -[endsect] -*/ -//] - -#endif // #ifndef BOOST_CLBL_TRTS_REMOVE_MEMBER_VOLATILE_HPP diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/remove_noexcept.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/remove_noexcept.hpp deleted file mode 100644 index 7b1fcb347..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/remove_noexcept.hpp +++ /dev/null @@ -1,93 +0,0 @@ -/* -@file remove_noexcept - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_REMOVE_NOEXCEPT_HPP -#define BOOST_CLBL_TRTS_REMOVE_NOEXCEPT_HPP - -#include <boost/callable_traits/detail/core.hpp> - -namespace boost { namespace callable_traits { - -BOOST_CLBL_TRTS_DEFINE_SFINAE_ERROR_ORIGIN(remove_noexcept) -BOOST_CLBL_TRTS_SFINAE_MSG(remove_noexcept, cannot_remove_noexcept_from_this_type) - -//[ remove_noexcept_hpp -/*` -[section:ref_remove_noexcept remove_noexcept] -[heading Header] -``#include <boost/callable_traits/remove_noexcept.hpp>`` -[heading Definition] -*/ - -template<typename T> -using remove_noexcept_t = //see below -//<- - detail::try_but_fail_if_invalid< - typename detail::traits<T>::remove_noexcept, - cannot_remove_noexcept_from_this_type>; - -namespace detail { - - template<typename T, typename = std::false_type> - struct remove_noexcept_impl {}; - - template<typename T> - struct remove_noexcept_impl <T, typename std::is_same< - remove_noexcept_t<T>, detail::dummy>::type> - { - using type = remove_noexcept_t<T>; - }; -} - -//-> - -template<typename T> -struct remove_noexcept : detail::remove_noexcept_impl<T> {}; - -//<- -}} // namespace boost::callable_traits -//-> - -/*` - -[heading Constraints] -* `T` must be one of the following: - * function type - * function pointer type - * function reference type - * member function pointer type -* If `T` is a pointer, it may not be cv/ref qualified - -[heading Behavior] -* A substitution failure occurs if the constraints are violated. -* Removes the `noexcept` specifier from `T`, if present. - -[heading Input/Output Examples] -[table - [[`T`] [`remove_noexcept_t<T>`]] - [[`int() const noexcept`] [`int() const`]] - [[`int(*)() noexcept`] [`int(*)()`]] - [[`int(&)() noexcept`] [`int(&)()`]] - [[`int(foo::*)() noexcept`] [`int(foo::*)()`]] - [[`int() const`] [`int() const`]] - [[`int(*)()`] [`int(*)()`]] - [[`int(&)()`] [`int(&)()`]] - [[`int`] [(substitution failure)]] - [[`int foo::*`] [(substitution failure)]] - [[`int (foo::* const)()`] [(substitution failure)]] -] - -[heading Example Program] -[import ../example/remove_noexcept.cpp] -[remove_noexcept] -[endsect] -*/ -//] - -#endif // #ifndef BOOST_CLBL_TRTS_REMOVE_NOEXCEPT_HPP diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/remove_transaction_safe.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/remove_transaction_safe.hpp deleted file mode 100644 index 4e37a3666..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/remove_transaction_safe.hpp +++ /dev/null @@ -1,93 +0,0 @@ -/* -@file remove_transaction_safe - -@Copyright Barrett Adair 2015-2017 -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_REMOVE_TRANSACTION_SAFE_HPP -#define BOOST_CLBL_TRTS_REMOVE_TRANSACTION_SAFE_HPP - -#include <boost/callable_traits/detail/core.hpp> - -namespace boost { namespace callable_traits { - -BOOST_CLBL_TRTS_DEFINE_SFINAE_ERROR_ORIGIN(remove_transaction_safe) -BOOST_CLBL_TRTS_SFINAE_MSG(remove_transaction_safe, cannot_remove_transaction_safe_from_this_type) - -//[ remove_transaction_safe_hpp -/*` -[section:ref_remove_transaction_safe remove_transaction_safe] -[heading Header] -``#include <boost/callable_traits/remove_transaction_safe.hpp>`` -[heading Definition] -*/ - -template<typename T> -using remove_transaction_safe_t = //see below -//<- - detail::try_but_fail_if_invalid< - typename detail::traits<T>::remove_transaction_safe, - cannot_remove_transaction_safe_from_this_type>; - -namespace detail { - - template<typename T, typename = std::false_type> - struct remove_transaction_safe_impl {}; - - template<typename T> - struct remove_transaction_safe_impl <T, typename std::is_same< - remove_transaction_safe_t<T>, detail::dummy>::type> - { - using type = remove_transaction_safe_t<T>; - }; -} - -//-> - -template<typename T> -struct remove_transaction_safe : detail::remove_transaction_safe_impl<T> {}; - -//<- -}} // namespace boost::callable_traits -//-> - -/*` - -[heading Constraints] -* `T` must be one of the following: - * function type - * function pointer type - * function reference type - * member function pointer type -* If `T` is a pointer, it may not be cv/ref qualified - -[heading Behavior] -* A substitution failure occurs if the constraints are violated. -* Removes the member `transaction_safe` specifier from `T`, if present. - -[heading Input/Output Examples] -[table - [[`T`] [`remove_transaction_safe_t<T>`]] - [[`int() const transaction_safe`] [`int() const`]] - [[`int(*)() transaction_safe`] [`int(*)()`]] - [[`int(&)() transaction_safe`] [`int(&)()`]] - [[`int(foo::*)() transaction_safe`] [`int(foo::*)()`]] - [[`int() const`] [`int() const`]] - [[`int(*)()`] [`int(*)()`]] - [[`int(&)()`] [`int(&)()`]] - [[`int`] [(substitution failure)]] - [[`int foo::*`] [(substitution failure)]] - [[`int (foo::* const)()`] [(substitution failure)]] -] - -[heading Example Program] -[import ../example/remove_transaction_safe.cpp] -[remove_transaction_safe] -[endsect] -*/ -//] - -#endif // #ifndef BOOST_CLBL_TRTS_REMOVE_TRANSACTION_SAFE_HPP diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/remove_varargs.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/remove_varargs.hpp deleted file mode 100644 index 874651c60..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/remove_varargs.hpp +++ /dev/null @@ -1,91 +0,0 @@ -/* - -@Copyright Barrett Adair 2015-2017 - -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_REMOVE_VARARGS_HPP -#define BOOST_CLBL_TRTS_REMOVE_VARARGS_HPP - -#include <boost/callable_traits/detail/core.hpp> - -namespace boost { namespace callable_traits { - -//[ remove_varargs_hpp -/*` -[section:ref_remove_varargs remove_varargs] -[heading Header] -``#include <boost/callable_traits/remove_varargs.hpp>`` -[heading Definition] -*/ - -template<typename T> -using remove_varargs_t = //see below -//<- - detail::try_but_fail_if_invalid< - typename detail::traits<T>::remove_varargs, - varargs_are_illegal_for_this_type>; - -namespace detail { - - template<typename T, typename = std::false_type> - struct remove_varargs_impl {}; - - template<typename T> - struct remove_varargs_impl <T, typename std::is_same< - remove_varargs_t<T>, detail::dummy>::type> - { - using type = remove_varargs_t<T>; - }; -} - -//-> - -template<typename T> -struct remove_varargs : detail::remove_varargs_impl<T> {}; - -//<- -}} // namespace boost::callable_traits -//-> - -/*` -[heading Constraints] -* `T` must be one of the following: - * function type - * function pointer type - * function reference type - * member function pointer type -* If `T` is a pointer, it may not be cv/ref qualified - -[heading Behavior] -* A substitution failure occurs if the constraints are violated. -* Removes C-style variadics (`...`) from the signature of `T`, if present. - -[heading Input/Output Examples] -[table - [[`T`] [`remove_varargs_t<T>`]] - [[`int(...)`] [`int()`]] - [[`int(int, ...)`] [`int(int)`]] - [[`int (&)(...)`] [`int(&)()`]] - [[`int (*)()`] [`int(*)()`]] - [[`int(foo::*)(...)`] [`int(foo::*)()`]] - [[`int(foo::*)(...) &`] [`int(foo::*)() &`]] - [[`int(foo::*)(...) &&`] [`int(foo::*)() &&`]] - [[`int(foo::*)(...) const`] [`int(foo::*)() const`]] - [[`int(foo::*)(...) transaction_safe`] [`int(foo::*)() transaction_safe`]] - [[`int`] [(substitution failure)]] - [[`int foo::*`] [(substitution failure)]] - [[`int (* const)()`] [(substitution failure)]] -] - -[heading Example Program] -[import ../example/remove_varargs.cpp] -[remove_varargs] -[endsect] -*/ -//] - -#endif // #ifndef BOOST_CLBL_TRTS_REMOVE_VARARGS_HPP diff --git a/stratosphere/libstratosphere/include/boost/callable_traits/return_type.hpp b/stratosphere/libstratosphere/include/boost/callable_traits/return_type.hpp deleted file mode 100644 index 586b0d249..000000000 --- a/stratosphere/libstratosphere/include/boost/callable_traits/return_type.hpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - -@Copyright Barrett Adair 2015-2017 - -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -*/ - -#ifndef BOOST_CLBL_TRTS_RESULT_OF_HPP -#define BOOST_CLBL_TRTS_RESULT_OF_HPP - -#include <boost/callable_traits/detail/core.hpp> - -namespace boost { namespace callable_traits { - -BOOST_CLBL_TRTS_DEFINE_SFINAE_ERROR_ORIGIN(return_type) -BOOST_CLBL_TRTS_SFINAE_MSG(return_type, unable_to_determine_return_type) - -//[ return_type_hpp -/*` -[section:ref_return_type return_type] -[heading Header] -``#include <boost/callable_traits/return_type.hpp>`` -[heading Definition] -*/ - -template<typename T> -using return_type_t = //see below -//<- - detail::try_but_fail_if_invalid< - typename detail::traits<detail::shallow_decay<T>>::return_type, - unable_to_determine_return_type>; - -namespace detail { - - template<typename T, typename = std::false_type> - struct return_type_impl {}; - - template<typename T> - struct return_type_impl <T, typename std::is_same< - return_type_t<T>, detail::dummy>::type> - { - using type = return_type_t<T>; - }; -} - -//-> - -template<typename T> -struct return_type : detail::return_type_impl<T> {}; - -//<- -}} // namespace boost::callable_traits -//-> - -/*` -[heading Constraints] -* `T` must be one of the following: - * function - * function pointer - * function reference - * member function pointer - * member data pointer - * user-defined type with a non-overloaded `operator()` - * type of a non-generic lambda - -[heading Behavior] -* When the constraints are violated, a substitution failure occurs. -* The aliased type is the return type of `T`. - -[heading Input/Output Examples] -[table - [[`T`] [`return_type_t<T, std::tuple>`]] - [[`void()`] [`void`]] - [[`float(*)()`] [`float`]] - [[`const char*(&)()`] [`const char *`]] - [[`int(foo::*)() const`] [`int`]] - [[`int`] [(substitution failure)]] - [[`int (*const)()`] [(substitution failure)]] -] - -[heading Example Program] -[import ../example/return_type.cpp] -[return_type] -[endsect] -*/ -//] - -#endif // #ifndef BOOST_CLBL_TRTS_RESULT_OF_HPP diff --git a/stratosphere/libstratosphere/include/stratosphere.hpp b/stratosphere/libstratosphere/include/stratosphere.hpp index fdd8b9d24..503f6f7f1 100644 --- a/stratosphere/libstratosphere/include/stratosphere.hpp +++ b/stratosphere/libstratosphere/include/stratosphere.hpp @@ -16,20 +16,17 @@ #pragma once -#include "stratosphere/ipc_templating.hpp" +#include "stratosphere/version_check.hpp" +#include "stratosphere/scope_guard.hpp" -#include "stratosphere/iwaitable.hpp" -#include "stratosphere/iserviceobject.hpp" -#include "stratosphere/iserver.hpp" -#include "stratosphere/ipcsession.hpp" -#include "stratosphere/servicesession.hpp" -#include "stratosphere/serviceserver.hpp" -#include "stratosphere/managedportserver.hpp" -#include "stratosphere/existingportserver.hpp" - -#include "stratosphere/ievent.hpp" -#include "stratosphere/systemevent.hpp" #include "stratosphere/hossynch.hpp" +#include "stratosphere/iwaitable.hpp" +#include "stratosphere/event.hpp" -#include "stratosphere/waitablemanager.hpp" -#include "stratosphere/multithreadedwaitablemanager.hpp" +#include "stratosphere/waitable_manager.hpp" + +#include "stratosphere/ipc.hpp" + +#include "stratosphere/mitm.hpp" + +#include "stratosphere/services.hpp" \ No newline at end of file diff --git a/stratosphere/libstratosphere/include/stratosphere/domainowner.hpp b/stratosphere/libstratosphere/include/stratosphere/domainowner.hpp deleted file mode 100644 index 74500eb63..000000000 --- a/stratosphere/libstratosphere/include/stratosphere/domainowner.hpp +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2018 Atmosphère-NX - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#pragma once -#include <switch.h> -#include <algorithm> -#include <memory> -#include <type_traits> - -#include "iserviceobject.hpp" - -#define DOMAIN_ID_MAX 0x1000 - -class IServiceObject; - -class DomainOwner { - private: - std::array<std::shared_ptr<IServiceObject>, DOMAIN_ID_MAX> domain_objects; - public: - /* Shared ptrs should auto delete here. */ - virtual ~DomainOwner() = default; - - std::shared_ptr<IServiceObject> get_domain_object(unsigned int i) { - if (i < DOMAIN_ID_MAX) { - return domain_objects[i]; - } - return nullptr; - } - - Result reserve_object(std::shared_ptr<IServiceObject> object, unsigned int *out_i) { - auto object_it = std::find(domain_objects.begin() + 4, domain_objects.end(), nullptr); - if (object_it == domain_objects.end()) { - return 0x1900B; - } - - *out_i = std::distance(domain_objects.begin(), object_it); - *object_it = object; - object->set_owner(this); - return 0; - } - - Result set_object(std::shared_ptr<IServiceObject> object, unsigned int i) { - if (domain_objects[i] == nullptr) { - domain_objects[i] = object; - object->set_owner(this); - return 0; - } - return 0x1900B; - } - - unsigned int get_object_id(std::shared_ptr<IServiceObject> object) { - auto object_it = std::find(domain_objects.begin(), domain_objects.end(), object); - return std::distance(domain_objects.begin(), object_it); - } - - void delete_object(unsigned int i) { - domain_objects[i].reset(); - } - - void delete_object(std::shared_ptr<IServiceObject> object) { - auto object_it = std::find(domain_objects.begin(), domain_objects.end(), object); - if (object_it != domain_objects.end()) { - object_it->reset(); - } - } -}; diff --git a/stratosphere/libstratosphere/include/stratosphere/event.hpp b/stratosphere/libstratosphere/include/stratosphere/event.hpp new file mode 100644 index 000000000..ba726d557 --- /dev/null +++ b/stratosphere/libstratosphere/include/stratosphere/event.hpp @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once +#include <switch.h> +#include <algorithm> +#include <vector> + +#include "iwaitable.hpp" + +class IEvent : public IWaitable { + public: + /* Information members. */ + Handle r_h; + Handle w_h; + bool autoclear; + public: + IEvent(bool a = false) : r_h(INVALID_HANDLE), w_h(INVALID_HANDLE), autoclear(a) { } + IEvent(Handle r, bool a = false) : r_h(r), w_h(INVALID_HANDLE), autoclear(a) { } + IEvent(Handle r, Handle w, bool a = false) : r_h(r), w_h(w), autoclear(a) { } + + ~IEvent() { + if (r_h != INVALID_HANDLE) { + svcCloseHandle(r_h); + } + if (w_h != INVALID_HANDLE) { + svcCloseHandle(w_h); + } + } + + /* Make it non-copyable */ + IEvent() = delete; + IEvent(const IEvent &) = delete; + IEvent& operator=(const IEvent&) = delete; + + + bool IsAutoClear() { + return this->autoclear; + } + + void Clear() { + std::scoped_lock<HosMutex> lock(this->sig_lock); + this->is_signaled = false; + if (this->r_h != INVALID_HANDLE) { + svcResetSignal(this->r_h); + } + } + + void Signal() { + std::scoped_lock<HosMutex> lock(this->sig_lock); + + if (this->w_h == INVALID_HANDLE && this->r_h != INVALID_HANDLE) { + /* We can't signal an event if we only have a read handle. */ + std::abort(); + } + + if (this->w_h == INVALID_HANDLE && this->is_signaled) { + return; + } + + this->is_signaled = true; + + if (this->w_h != INVALID_HANDLE) { + svcSignalEvent(this->w_h); + } else { + this->NotifyManagerSignaled(); + } + } + + virtual Result HandleSignaled(u64 timeout) = 0; + + /* IWaitable */ + virtual Handle GetHandle() override { + return this->r_h; + } +}; + +template<class F> +class HosEvent : public IEvent { + private: + F callback; + public: + HosEvent(F f, bool a = false) : IEvent(a), callback(std::move(f)) { } + HosEvent(Handle r, F f, bool a = false) : IEvent(r, a), callback(std::move(f)) { } + HosEvent(Handle r, Handle w, F f, bool a = false) : IEvent(r, w, a), callback(std::move(f)) { } + + virtual Result HandleSignaled(u64 timeout) override { + if (this->IsAutoClear()) { + this->Clear(); + } + return this->callback(timeout); + } +}; + +template <class F> +static IEvent *CreateHosEvent(F f, bool autoclear = false) { + return new HosEvent<F>(INVALID_HANDLE, INVALID_HANDLE, std::move(f), autoclear); +} + +template <class F> +static IEvent *CreateSystemEvent(F f, bool autoclear = false) { + + Handle w_h, r_h; + if (R_FAILED(svcCreateEvent(&w_h, &r_h))) { + std::abort(); + } + + return new HosEvent<F>(r_h, w_h, std::move(f), autoclear); +} + +template <bool a = false> +static IEvent *CreateWriteOnlySystemEvent() { + return CreateSystemEvent([](u64 timeout) { std::abort(); return 0; }, a); +} diff --git a/stratosphere/libstratosphere/include/stratosphere/firmware_version.hpp b/stratosphere/libstratosphere/include/stratosphere/firmware_version.hpp new file mode 100644 index 000000000..312c68c67 --- /dev/null +++ b/stratosphere/libstratosphere/include/stratosphere/firmware_version.hpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +enum FirmwareVersion : u32 { + FirmwareVersion_Min = 0, + FirmwareVersion_100 = FirmwareVersion_Min, + FirmwareVersion_200 = 1, + FirmwareVersion_300 = 2, + FirmwareVersion_400 = 3, + FirmwareVersion_500 = 4, + FirmwareVersion_600 = 5, + FirmwareVersion_Current = FirmwareVersion_600, + FirmwareVersion_Max = 32, +}; + +static inline FirmwareVersion GetRuntimeFirmwareVersion() { + FirmwareVersion fw = FirmwareVersion_Min; + if (kernelAbove200()) { + fw = FirmwareVersion_200; + } + if (kernelAbove300()) { + fw = FirmwareVersion_300; + } + if (kernelAbove400()) { + fw = FirmwareVersion_400; + } + if (kernelAbove500()) { + fw = FirmwareVersion_500; + } + if (kernelAbove600()) { + fw = FirmwareVersion_600; + } + return fw; +} diff --git a/stratosphere/libstratosphere/include/stratosphere/hossynch.hpp b/stratosphere/libstratosphere/include/stratosphere/hossynch.hpp index b923a4ec1..73ca16d76 100644 --- a/stratosphere/libstratosphere/include/stratosphere/hossynch.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/hossynch.hpp @@ -16,6 +16,7 @@ #pragma once #include <switch.h> +#include <mutex> class HosMutex { private: @@ -40,6 +41,18 @@ class HosMutex { return mutexTryLock(GetMutex()); } + void Lock() { + lock(); + } + + void Unlock() { + unlock(); + } + + bool TryLock() { + return try_lock(); + } + friend class HosCondVar; }; @@ -65,6 +78,18 @@ class HosRecursiveMutex { bool try_lock() { return rmutexTryLock(GetMutex()); } + + void Lock() { + lock(); + } + + void Unlock() { + unlock(); + } + + bool TryLock() { + return try_lock(); + } }; class HosCondVar { diff --git a/stratosphere/libstratosphere/include/stratosphere/ievent.hpp b/stratosphere/libstratosphere/include/stratosphere/ievent.hpp deleted file mode 100644 index d1c93ef63..000000000 --- a/stratosphere/libstratosphere/include/stratosphere/ievent.hpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2018 Atmosphère-NX - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#pragma once -#include <switch.h> -#include <algorithm> -#include <vector> - -#include "iwaitable.hpp" - -typedef Result (*EventCallback)(void *arg, Handle *handles, size_t num_handles, u64 timeout); - -class IEvent : public IWaitable { - protected: - std::vector<Handle> handles; - EventCallback callback; - void *arg; - - public: - IEvent(Handle wait_h, void *a, EventCallback callback) { - if (wait_h) { - this->handles.push_back(wait_h); - } - this->arg = a; - this->callback = callback; - } - - ~IEvent() { - std::for_each(handles.begin(), handles.end(), svcCloseHandle); - } - - virtual Result signal_event() = 0; - - /* IWaitable */ - virtual Handle get_handle() { - if (handles.size() > 0) { - return this->handles[0]; - } - return 0; - } - - - virtual void handle_deferred() { - /* TODO: Panic, because we can never defer an event. */ - } - - virtual Result handle_signaled(u64 timeout) { - return this->callback(this->arg, this->handles.data(), this->handles.size(), timeout); - } - - static Result PanicCallback(void *arg, Handle *handles, size_t num_handles, u64 timeout) { - /* TODO: Panic. */ - return 0xCAFE; - } -}; diff --git a/stratosphere/libstratosphere/include/stratosphere/existingportserver.hpp b/stratosphere/libstratosphere/include/stratosphere/ipc.hpp similarity index 59% rename from stratosphere/libstratosphere/include/stratosphere/existingportserver.hpp rename to stratosphere/libstratosphere/include/stratosphere/ipc.hpp index 360ed286b..e035fda52 100644 --- a/stratosphere/libstratosphere/include/stratosphere/existingportserver.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/ipc.hpp @@ -15,17 +15,8 @@ */ #pragma once -#include <switch.h> -#include "iserver.hpp" -template <typename T> -class ExistingPortServer : public IServer<T> { - public: - ExistingPortServer(Handle port_h, unsigned int max_s, bool s_d = false) : IServer<T>(NULL, max_s, s_d) { - this->port_handle = port_h; - } - - ISession<T> *get_new_session(Handle session_h) override { - return new ServiceSession<T>(this, session_h, 0); - } -}; \ No newline at end of file +#include "ipc/ipc_service_object.hpp" +#include "ipc/ipc_serialization.hpp" + +#include "ipc/ipc_service_session.hpp" \ No newline at end of file diff --git a/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_buffers.hpp b/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_buffers.hpp new file mode 100644 index 000000000..6bf2f71c0 --- /dev/null +++ b/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_buffers.hpp @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once +#include <switch.h> +#include <type_traits> + +enum class IpcBufferType { + InBuffer, + OutBuffer, + InPointer, + OutPointer, +}; + +/* Base for In/Out Buffers. */ +struct IpcBufferBase {}; + +struct InOutBufferBase : public IpcBufferBase {}; + +/* Represents an A descriptor. */ +struct InBufferBase : public InOutBufferBase {}; + +template <typename T, BufferType e_t = BufferType_Normal> +struct InBuffer : public InBufferBase { + T *buffer; + size_t num_elements; + BufferType type; + static const BufferType expected_type = e_t; + + /* Convenience. */ + T& operator[](size_t i) const { + return buffer[i]; + } + + InBuffer(void *b, size_t n, BufferType t) : buffer((T *)b), num_elements(n/sizeof(T)), type(t) { } +}; + +/* Represents a B descriptor. */ +struct OutBufferBase : public InOutBufferBase {}; + +template <typename T, BufferType e_t = BufferType_Normal> +struct OutBuffer : OutBufferBase { + T *buffer; + size_t num_elements; + BufferType type; + static const BufferType expected_type = e_t; + + /* Convenience. */ + T& operator[](size_t i) const { + return buffer[i]; + } + + OutBuffer(void *b, size_t n, BufferType t) : buffer((T *)b), num_elements(n/sizeof(T)), type(t) { } +}; + +/* Represents an X descriptor. */ +struct InPointerBase : public IpcBufferBase {}; + +template <typename T> +struct InPointer : public InPointerBase { + T *pointer; + size_t num_elements; + + /* Convenience. */ + T& operator[](size_t i) const { + return pointer[i]; + } + + InPointer(void *p, size_t n) : pointer((T *)p), num_elements(n/sizeof(T)) { } +}; + +/* Represents a C descriptor. */ +struct OutPointerWithServerSizeBase : public IpcBufferBase {}; + +template <typename T, size_t N> +struct OutPointerWithServerSize : public OutPointerWithServerSizeBase { + T *pointer; + static const size_t num_elements = N; + static const size_t element_size = sizeof(T); + + /* Convenience. */ + T& operator[](size_t i) const { + return pointer[i]; + } + + OutPointerWithServerSize(void *p) : pointer((T *)p) { } + OutPointerWithServerSize(void *p, size_t n) : pointer((T *)p) { } +}; + +struct OutPointerWithClientSizeBase : public IpcBufferBase {}; + +/* Represents a C descriptor with size in raw data. */ +template <typename T> +struct OutPointerWithClientSize : public OutPointerWithClientSizeBase { + T *pointer; + size_t num_elements; + + /* Convenience. */ + T& operator[](size_t i) const { + return pointer[i]; + } + + OutPointerWithClientSize(void *p, size_t n) : pointer((T *)p), num_elements(n/sizeof(T)) { } +}; diff --git a/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_domain_object.hpp b/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_domain_object.hpp new file mode 100644 index 000000000..1394fc095 --- /dev/null +++ b/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_domain_object.hpp @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once +#include <switch.h> +#include <algorithm> +#include <memory> +#include <type_traits> + +#include "ipc_service_object.hpp" + +class IDomainObject; + +class DomainManager { + public: + virtual std::shared_ptr<IDomainObject> AllocateDomain() = 0; + virtual void FreeDomain(IDomainObject *domain) = 0; + virtual Result ReserveObject(IDomainObject *domain, u32 *out_object_id) = 0; + virtual Result ReserveSpecificObject(IDomainObject *domain, u32 object_id) = 0; + virtual void SetObject(IDomainObject *domain, u32 object_id, ServiceObjectHolder&& holder) = 0; + virtual ServiceObjectHolder *GetObject(IDomainObject *domain, u32 object_id) = 0; + virtual Result FreeObject(IDomainObject *domain, u32 object_id) = 0; + virtual Result ForceFreeObject(u32 object_id) = 0; +}; + +class IDomainObject : public IServiceObject { + private: + DomainManager *manager; + public: + IDomainObject(DomainManager *m) : manager(m) {} + + virtual ~IDomainObject() override { + this->manager->FreeDomain(this); + } + + DomainManager *GetManager() { + return this->manager; + } + + ServiceObjectHolder *GetObject(u32 object_id) { + return this->manager->GetObject(this, object_id); + } + + Result ReserveObject(u32 *out_object_id) { + return this->manager->ReserveObject(this, out_object_id); + } + + Result ReserveSpecificObject(u32 object_id) { + return this->manager->ReserveSpecificObject(this, object_id); + } + + void SetObject(u32 object_id, ServiceObjectHolder&& holder) { + this->manager->SetObject(this, object_id, std::move(holder)); + } + + Result FreeObject(u32 object_id) { + return this->manager->FreeObject(this, object_id); + } + + Result ForceFreeObject(u32 object_id) { + return this->manager->ForceFreeObject(object_id); + } + + public: + DEFINE_SERVICE_DISPATCH_TABLE { + /* IDomainObject has no callable functions. */ + }; +}; + +static constexpr bool IsDomainObject(ServiceObjectHolder &holder) { + return holder.GetServiceId() == ServiceObjectId<IDomainObject>(); +} + +static constexpr bool IsDomainObject(ServiceObjectHolder *holder) { + return holder->GetServiceId() == ServiceObjectId<IDomainObject>(); +} + +/* Out for service impl. */ +template <typename ServiceImpl> +class Out<std::shared_ptr<ServiceImpl>> : public OutSessionTag { + static_assert(std::is_base_of_v<IServiceObject, ServiceImpl>, "OutSessions must be shared_ptr<IServiceObject>!"); + + template<typename, typename> + friend class Out; + + private: + std::shared_ptr<ServiceImpl> *srv; + IDomainObject *domain = nullptr; + u32 *object_id = nullptr; + public: + Out<std::shared_ptr<ServiceImpl>>(std::shared_ptr<IServiceObject> *s, IDomainObject *dm, u32 *o) : srv(reinterpret_cast<std::shared_ptr<ServiceImpl> *>(s)), domain(dm), object_id(o) { } + + ServiceObjectHolder GetHolder() { + std::shared_ptr<ServiceImpl> clone = *srv; + return ServiceObjectHolder(std::move(clone)); + } + + bool IsDomain() { + return domain != nullptr; + } + + u32 GetObjectId() { + return *object_id; + } + + void ChangeObjectId(u32 o) { + domain->ForceFreeObject(*object_id); + domain->ReserveSpecificObject(o); + *object_id = o; + } + + void SetValue(std::shared_ptr<ServiceImpl> &&s) { + *this->srv = std::move(s); + } +}; diff --git a/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_out.hpp b/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_out.hpp new file mode 100644 index 000000000..fbd186d28 --- /dev/null +++ b/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_out.hpp @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once +#include <switch.h> +#include <type_traits> + +/* Declare false allowed struct. */ +template <typename> +struct AllowedOut : std::false_type {}; + +struct OutDataTag{}; +struct OutHandleTag{}; +struct OutSessionTag{}; + +/* Define out struct, so that we can get errors on enable_if */ +template <typename T, typename Allowed = void> +class Out { + static_assert(std::is_pod<T>::value && !std::is_pod<T>::value, "Invalid IPC Out Type!"); +}; + +template <typename T> +class Out<T, typename std::enable_if<std::is_trivial<T>::value || AllowedOut<T>::value>::type> : public OutDataTag { +private: + T *obj; +public: + Out(T *o) : obj(o) { } + + void SetValue(const T& t) { + *obj = t; + } + + const T& GetValue() { + return *obj; + } + + T *GetPointer() { + return obj; + } + + /* Convenience operators. */ + T& operator*() { + return *obj; + } + + T* operator->() { + return obj; + } +}; + +template <typename T> +class Out<T*> { + static_assert(std::is_pod<T>::value && !std::is_pod<T>::value, "Invalid IPC Out Type (Raw Pointer)!"); +}; + +template <typename T> +struct OutHelper; + +template <typename T> +struct OutHelper<Out<T>> { + using type = T; +}; \ No newline at end of file diff --git a/stratosphere/libstratosphere/include/stratosphere/managedportserver.hpp b/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_response_context.hpp similarity index 52% rename from stratosphere/libstratosphere/include/stratosphere/managedportserver.hpp rename to stratosphere/libstratosphere/include/stratosphere/ipc/ipc_response_context.hpp index f61545f74..4e2ed8345 100644 --- a/stratosphere/libstratosphere/include/stratosphere/managedportserver.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_response_context.hpp @@ -16,18 +16,29 @@ #pragma once #include <switch.h> -#include "iserver.hpp" -template <typename T> -class ManagedPortServer : public IServer<T> { - public: - ManagedPortServer(const char *service_name, unsigned int max_s, bool s_d = false) : IServer<T>(service_name, max_s, s_d) { - if (R_FAILED(svcManageNamedPort(&this->port_handle, service_name, this->max_sessions))) { - /* TODO: panic */ - } - } - - ISession<T> *get_new_session(Handle session_h) override { - return new ServiceSession<T>(this, session_h, 0); - } +#include "ipc_service_object.hpp" +#include "ipc_domain_object.hpp" + +#include "ipc_special.hpp" + +#include "ipc_session_manager_base.hpp" + +struct IpcResponseContext { + /* Request/Reply data. */ + IpcParsedCommand request; + IpcCommand reply; + u8 out_data[0x100]; + std::shared_ptr<IServiceObject> *out_objs[8]; + Handle out_object_server_handles[8]; + IpcHandle out_handles[8]; + u32 out_object_ids[8]; + IpcCommandType cmd_type; + u64 cmd_id; + Result rc; + /* Context. */ + SessionManagerBase *manager; + ServiceObjectHolder *obj_holder; + unsigned char *pb; + size_t pb_size; }; \ No newline at end of file diff --git a/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_serialization.hpp b/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_serialization.hpp new file mode 100644 index 000000000..1e4e77afa --- /dev/null +++ b/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_serialization.hpp @@ -0,0 +1,664 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once +#include <switch.h> +#include <cstdlib> +#include <cstring> +#include <tuple> +#include <boost/callable_traits.hpp> +#include <type_traits> +#include <memory> + +#include "ipc_out.hpp" +#include "ipc_buffers.hpp" +#include "ipc_special.hpp" + +#include "ipc_domain_object.hpp" + +#include "ipc_response_context.hpp" + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" + +template<typename Tuple> +struct PopFront; + +template<typename Head, typename... Tail> +struct PopFront<std::tuple<Head, Tail...>> { + using type = std::tuple<Tail...>; +}; + +template <typename ...> struct WhichType; + +template <typename...> +struct TypeList{}; + +template <typename... T1s, typename... T2s> +constexpr auto Concatenate(TypeList<T1s...>, TypeList<T2s...>) { + return TypeList<T1s..., T2s...>{}; +} + +template <template <typename> typename Condition, typename R> +constexpr auto FilterTypes(R result, TypeList<>) { + return result; +} + +template <template <typename> typename Condition, typename R, typename T, typename... Ts> +constexpr auto FilterTypes(R result, TypeList<T, Ts...>) { + if constexpr (Condition<T>{}) + return FilterTypes<Condition>(Concatenate(result, TypeList<T>{}), TypeList<Ts...>{}); + else + return FilterTypes<Condition>(result, TypeList<Ts...>{}); +} + +template<typename Types> struct TypeListToTuple; + +template<typename... Types> +struct TypeListToTuple<TypeList<Types...>> { + using type = std::tuple<Types...>; +}; + +template <template <typename> typename Condition, typename... Types> +using FilteredTypes = typename TypeListToTuple<std::decay_t<decltype(FilterTypes<Condition>(TypeList<>{}, TypeList<Types...>{}))>>::type; + +enum class ArgType { + InData, + OutData, + InHandle, + OutHandle, + InSession, + OutSession, + PidDesc, + InBuffer, + OutBuffer, + InPointer, + OutPointerClientSize, + OutPointerServerSize, +}; + +template<typename X> +constexpr ArgType GetArgType() { + if constexpr (std::is_base_of_v<OutDataTag, X>) { + return ArgType::OutData; + } else if constexpr (std::is_base_of_v<OutSessionTag, X>) { + return ArgType::OutSession; + } else if constexpr (std::is_base_of_v<OutHandleTag, X>) { + return ArgType::OutHandle; + } else if constexpr (std::is_base_of_v<InBufferBase, X>) { + return ArgType::InBuffer; + } else if constexpr (std::is_base_of_v<OutBufferBase, X>) { + return ArgType::OutBuffer; + } else if constexpr (std::is_base_of_v<InPointerBase, X>) { + return ArgType::InPointer; + } else if constexpr (std::is_base_of_v<OutPointerWithClientSizeBase, X>) { + return ArgType::OutPointerClientSize; + } else if constexpr (std::is_base_of_v<OutPointerWithServerSizeBase, X>) { + return ArgType::OutPointerServerSize; + } else if constexpr (std::is_base_of_v<PidDescriptorTag, X>) { + return ArgType::PidDesc; + } else if constexpr (std::is_base_of_v<IpcHandleTag, X>) { + return ArgType::InHandle; + } else if constexpr (std::is_trivial_v<X> && !std::is_pointer_v<X>) { + return ArgType::InData; + } else { + static_assert(std::is_pod_v<X> && !std::is_pod_v<X>, "Unhandled InSession!"); + return ArgType::InSession; + } +} + +template<ArgType ArgT> +struct ArgTypeFilter { + template<typename X> + using type = std::conditional_t<GetArgType<X>() == ArgT, std::true_type, std::false_type>; +}; + +template<ArgType ArgT> +struct IsArgTypeBuffer { + static constexpr bool value = ArgT == ArgType::InBuffer || ArgT == ArgType::OutBuffer || ArgT == ArgType::InPointer || ArgT == ArgType::OutPointerClientSize || ArgT == ArgType::OutPointerServerSize; +}; + +struct ArgTypeBufferFilter { + template<typename X> + using type = std::conditional_t<IsArgTypeBuffer<GetArgType<X>()>::value, std::true_type, std::false_type>; +}; + +template<ArgType ArgT> +struct IsArgTypeInData { + static constexpr bool value = ArgT == ArgType::InData || ArgT == ArgType::PidDesc; +}; + +struct ArgTypeInDataFilter { + template<typename X> + using type = std::conditional_t<IsArgTypeInData<GetArgType<X>()>::value, std::true_type, std::false_type>; +}; + +template<typename T> +struct RawDataHelper { + static_assert(GetArgType<T>() == ArgType::InData || GetArgType<T>() == ArgType::PidDesc); + static constexpr size_t align = (GetArgType<T>() == ArgType::InData) ? __alignof__(T) : __alignof__(u64); + static constexpr size_t size = (GetArgType<T>() == ArgType::InData) ? sizeof(T) : sizeof(u64); +}; + +template<typename T> +struct RawDataHelper<Out<T>> { + static_assert(GetArgType<T>() == ArgType::InData); + static constexpr size_t align = __alignof(T); + static constexpr size_t size = sizeof(T); +}; + +template<typename Ts> +struct RawDataComputer; + +template<typename... Ts> +struct RawDataComputer<std::tuple<Ts...>> { + /* https://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs,2604 */ + static constexpr void QuickSort(std::array<size_t, sizeof...(Ts)> &map, std::array<size_t, sizeof...(Ts)> &values, int left, int right) { + do { + int i = left; + int j = right; + int x = map[i + ((j - i) >> 1)]; + do { + while (i < static_cast<int>(sizeof...(Ts)) && values[x] > values[map[i]]) i++; + while (j >= 0 && values[x] < values[map[j]]) j--; + if (i > j) break; + if (i < j) { + const size_t temp = map[i]; + map[i] = map[j]; + map[j] = temp; + } + i++; + j--; + } while (i <= j); + if (j - left <= right - i) { + if (left < j) QuickSort(map, values, left, j); + left = i; + } else { + if (i < right) QuickSort(map, values, i, right); + right = j; + } + } while (left < right); + } + + static constexpr void StableSort(std::array<size_t, sizeof...(Ts)> &map, std::array<size_t, sizeof...(Ts)> &values) { + /* First, quicksort a copy of the map. */ + std::array<size_t, sizeof...(Ts)> map_unstable(map); + QuickSort(map_unstable, values, 0, sizeof...(Ts)-1); + + /* Now, create stable sorted map from unstably quicksorted indices (via repeated insertion sort on element runs). */ + for (size_t i = 0; i < sizeof...(Ts); i++) { + map[i] = map_unstable[i]; + for (ssize_t j = i-1; j >= 0 && values[map[j]] == values[map[j+1]] && map[j] > map[j+1]; j--) { + const size_t temp = map[j]; + map[j] = map[j+1]; + map[j+1] = temp; + } + } + } + + static constexpr std::array<size_t, sizeof...(Ts)+1> GetOffsets() { + std::array<size_t, sizeof...(Ts)+1> offsets = {}; + offsets[0] = 0; + if constexpr (sizeof...(Ts) > 0) { + /* Get size, alignment for each type. */ + std::array<size_t, sizeof...(Ts)> sizes = { RawDataHelper<Ts>::size... }; + std::array<size_t, sizeof...(Ts)> aligns = { RawDataHelper<Ts>::align... }; + + /* We want to sort...by alignment. */ + std::array<size_t, sizeof...(Ts)> map = {}; + for (size_t i = 0; i < sizeof...(Ts); i++) { map[i] = i; } + StableSort(map, aligns); + + /* Iterate over sorted types. */ + size_t cur_offset = 0; + for (size_t i = 0; i < sizeof...(Ts); i++) { + const size_t align = aligns[map[i]]; + if (cur_offset % align != 0) { + cur_offset += align - (cur_offset % align); + } + offsets[map[i]] = cur_offset; + cur_offset += sizes[map[i]]; + } + offsets[sizeof...(Ts)] = cur_offset; + } + return offsets; + } + + static constexpr std::array<size_t, sizeof...(Ts)+1> offsets = GetOffsets(); +}; + +template <typename _Args, typename _ReturnType> +struct CommandMetaInfo; + +template<typename... _Args, typename _ReturnType> +struct CommandMetaInfo<std::tuple<_Args...>, _ReturnType> { + using Args = std::tuple<_Args...>; + using ReturnType = _ReturnType; + + static constexpr bool ReturnsResult = std::is_same_v<ReturnType, Result>; + static constexpr bool ReturnsVoid = std::is_same_v<ReturnType, void>; + + using InDatas = FilteredTypes<ArgTypeInDataFilter::type, _Args...>; + using OutDatas = FilteredTypes<ArgTypeFilter<ArgType::OutData>::type, _Args...>; + using InHandles = FilteredTypes<ArgTypeFilter<ArgType::InHandle>::type, _Args...>; + using OutHandles = FilteredTypes<ArgTypeFilter<ArgType::OutHandle>::type, _Args...>; + using InSessions = FilteredTypes<ArgTypeFilter<ArgType::InSession>::type, _Args...>; + using OutSessions = FilteredTypes<ArgTypeFilter<ArgType::OutSession>::type, _Args...>; + using PidDescs = FilteredTypes<ArgTypeFilter<ArgType::PidDesc>::type, _Args...>; + + using InBuffers = FilteredTypes<ArgTypeFilter<ArgType::InBuffer>::type, _Args...>; + using OutBuffers = FilteredTypes<ArgTypeFilter<ArgType::OutBuffer>::type, _Args...>; + using InPointers = FilteredTypes<ArgTypeFilter<ArgType::InPointer>::type, _Args...>; + using ClientSizeOutPointers = FilteredTypes<ArgTypeFilter<ArgType::OutPointerClientSize>::type, _Args...>; + using ServerSizeOutPointers = FilteredTypes<ArgTypeFilter<ArgType::OutPointerServerSize>::type, _Args...>; + using Buffers = FilteredTypes<ArgTypeBufferFilter::type, _Args...>; + + static constexpr size_t NumInDatas = std::tuple_size_v<InDatas>; + static constexpr size_t NumOutDatas = std::tuple_size_v<OutDatas>; + static constexpr size_t NumInHandles = std::tuple_size_v<InHandles>; + static constexpr size_t NumOutHandles = std::tuple_size_v<OutHandles>; + static constexpr size_t NumInSessions = std::tuple_size_v<InSessions>; + static constexpr size_t NumOutSessions = std::tuple_size_v<OutSessions>; + static constexpr size_t NumPidDescs = std::tuple_size_v<PidDescs>; + + static constexpr size_t NumInBuffers = std::tuple_size_v<InBuffers>; + static constexpr size_t NumOutBuffers = std::tuple_size_v<OutBuffers>; + static constexpr size_t NumInPointers = std::tuple_size_v<InPointers>; + static constexpr size_t NumClientSizeOutPointers = std::tuple_size_v<ClientSizeOutPointers>; + static constexpr size_t NumServerSizeOutPointers = std::tuple_size_v<ServerSizeOutPointers>; + static constexpr size_t NumBuffers = std::tuple_size_v<Buffers>; + + static_assert(NumInSessions == 0, "InSessions not yet supported!"); + static_assert(NumPidDescs == 0 || NumPidDescs == 1, "Methods can only take in 0 or 1 PIDs!"); + static_assert(NumBuffers <= 8, "Methods can only take in <= 8 Buffers!"); + static_assert(NumInHandles <= 8, "Methods can take in <= 8 Handles!"); + static_assert(NumOutHandles + NumOutSessions <= 8, "Methods can only return <= 8 Handles+Sessions!"); + + static constexpr std::array<size_t, NumInDatas+1> InDataOffsets = RawDataComputer<InDatas>::offsets; + static constexpr size_t InRawArgSize = InDataOffsets[NumInDatas]; + static constexpr size_t InRawArgSizeWithOutPointers = ((InRawArgSize + NumClientSizeOutPointers * sizeof(u16)) + 3) & ~3; + + static constexpr std::array<size_t, NumOutDatas+1> OutDataOffsets = RawDataComputer<OutDatas>::offsets; + static constexpr size_t OutRawArgSize = OutDataOffsets[NumOutDatas]; +}; + + +/* ================================================================================= */ +/* Actual wrapping implementation goes here. */ + +/* Validator. */ +struct Validator { + + template <typename T> + static constexpr bool ValidateCommandArgument(IpcResponseContext *ctx, size_t& a_index, size_t& b_index, size_t& x_index, size_t& h_index, size_t& cur_c_size_offset, size_t& total_c_size) { + constexpr ArgType argT = GetArgType<T>(); + if constexpr (argT == ArgType::InBuffer) { + return ctx->request.Buffers[a_index] != nullptr && ctx->request.BufferDirections[a_index] == BufferDirection_Send && ctx->request.BufferTypes[a_index++] == T::expected_type; + } else if constexpr (argT == ArgType::OutBuffer) { + return ctx->request.Buffers[b_index] != nullptr && ctx->request.BufferDirections[b_index] == BufferDirection_Recv && ctx->request.BufferTypes[b_index++] == T::expected_type; + } else if constexpr (argT == ArgType::InPointer) { + return ctx->request.Statics[x_index++] != nullptr; + } else if constexpr (argT == ArgType::InHandle) { + if constexpr (std::is_same_v<T, MovedHandle>) { + return !ctx->request.WasHandleCopied[h_index++]; + } else if constexpr (std::is_same_v<T, CopiedHandle>) { + return ctx->request.WasHandleCopied[h_index++]; + } + } else { + if constexpr (argT == ArgType::OutPointerServerSize) { + total_c_size += T::num_elements * sizeof(T); + } else if constexpr (argT == ArgType::OutPointerServerSize) { + total_c_size += *((u16 *)((uintptr_t)(ctx->request.Raw) + 0x10 + cur_c_size_offset)); + cur_c_size_offset += sizeof(u16); + } + return true; + } + } + + template <typename Ts> + struct ValidateCommandTuple; + + template <typename ...Ts> + struct ValidateCommandTuple<std::tuple<Ts...>> { + static constexpr bool IsValid(IpcResponseContext *ctx, size_t& a_index, size_t& b_index, size_t& x_index, size_t& h_index, size_t& cur_c_size_offset, size_t& total_c_size) { + return (ValidateCommandArgument<Ts>(ctx, a_index, b_index, x_index, h_index, cur_c_size_offset, total_c_size) && ...); + } + }; + + template<typename MetaInfo> + static constexpr Result Validate(IpcResponseContext *ctx) { + if (ctx->request.RawSize < MetaInfo::InRawArgSizeWithOutPointers) { + return 0xF601; + } + + if (ctx->request.NumBuffers != MetaInfo::NumInBuffers + MetaInfo::NumOutBuffers) { + return 0xF601; + } + + if (ctx->request.NumStatics != MetaInfo::NumInPointers) { + return 0xF601; + } + + if (ctx->request.NumStaticsOut != MetaInfo::NumClientSizeOutPointers + MetaInfo::NumServerSizeOutPointers) { + return 0xF601; + } + + if (ctx->request.NumHandles != MetaInfo::NumInHandles) { + return 0xF601; + } + + + if ((ctx->request.HasPid && MetaInfo::NumPidDescs == 0) || (!ctx->request.HasPid && MetaInfo::NumPidDescs != 0)) { + return 0xF601; + } + + if (((u32 *)ctx->request.Raw)[0] != SFCI_MAGIC) { + return 0xF601; + } + + size_t a_index = 0, b_index = MetaInfo::NumInBuffers, x_index = 0, h_index = 0; + size_t cur_c_size_offset = MetaInfo::InRawArgSize + (0x10 - ((uintptr_t)ctx->request.Raw - (uintptr_t)ctx->request.RawWithoutPadding)); + size_t total_c_size = 0; + + if (!ValidateCommandTuple<typename MetaInfo::Args>::IsValid(ctx, a_index, b_index, x_index, h_index, cur_c_size_offset, total_c_size)) { + return 0xF601; + } + + if (total_c_size > ctx->pb_size) { + return 0xF601; + } + + return 0; + } +}; + +/* ================================================================================= */ + +/* Decoder. */ +template<typename MetaInfo> +struct Decoder { + + template<typename T> + static constexpr T DecodeCommandArgument(IpcResponseContext *ctx, size_t& a_index, size_t& b_index, size_t& x_index, size_t& c_index, size_t& in_h_index, size_t& out_h_index, size_t& out_obj_index, size_t& in_data_index, size_t& out_data_index, size_t& pb_offset, size_t& c_sz_offset) { + constexpr ArgType argT = GetArgType<T>(); + if constexpr (argT == ArgType::InBuffer) { + const T& value = T(ctx->request.Buffers[a_index], ctx->request.BufferSizes[a_index], ctx->request.BufferTypes[a_index]); + ++a_index; + return value; + } else if constexpr (argT == ArgType::OutBuffer) { + const T& value = T(ctx->request.Buffers[b_index], ctx->request.BufferSizes[b_index], ctx->request.BufferTypes[b_index]); + ++b_index; + return value; + } else if constexpr (argT == ArgType::InPointer) { + const T& value = T(ctx->request.Statics[x_index], ctx->request.StaticSizes[x_index]); + ++x_index; + return value; + } else if constexpr (argT == ArgType::InHandle) { + return T(ctx->request.Handles[in_h_index++]); + } else if constexpr (argT == ArgType::OutHandle) { + return T(&ctx->out_handles[out_h_index++]); + } else if constexpr (argT == ArgType::PidDesc) { + uintptr_t ptr = ((uintptr_t)ctx->request.Raw + 0x10 + MetaInfo::InDataOffsets[in_data_index++]); + *(u64 *)ptr = ctx->request.Pid; + return T(ctx->request.Pid); + } else if constexpr (argT == ArgType::InData) { + uintptr_t ptr = ((uintptr_t)ctx->request.Raw + 0x10 + MetaInfo::InDataOffsets[in_data_index++]); + if constexpr (std::is_same_v<bool, T>) { + return *((u8 *)ptr) & 1; + } else { + return *((T *)ptr); + } + } else if constexpr (argT == ArgType::OutData) { + uintptr_t ptr = ((uintptr_t)ctx->out_data + MetaInfo::OutDataOffsets[out_data_index++]); + return T(reinterpret_cast<typename OutHelper<T>::type *>(ptr)); + } else if constexpr (argT == ArgType::OutPointerClientSize || argT == ArgType::OutPointerServerSize) { + u16 sz; + if constexpr(argT == ArgType::OutPointerServerSize) { + sz = T::element_size; + } else { + sz = *(const u16 *)((uintptr_t)ctx->request.Raw + 0x10 + c_sz_offset); + } + u8* buf = ctx->pb + pb_offset; + c_sz_offset += sizeof(u16); + pb_offset += sz; + ipcAddSendStatic(&ctx->reply, buf, sz, c_index++); + return T(buf, sz); + } else if constexpr (argT == ArgType::OutSession) { + if (IsDomainObject(ctx->obj_holder)) { + const T& value = T(ctx->out_objs[out_obj_index], ctx->obj_holder->GetServiceObject<IDomainObject>(), &ctx->out_object_ids[out_obj_index]); + out_obj_index++; + return value; + } else { + const T& value = T(ctx->out_objs[out_obj_index], nullptr, 0); + out_obj_index++; + return value; + } + } + } + + template <typename Ts> + struct DecodeTuple; + + template <typename ...Ts> + struct DecodeTuple<std::tuple<Ts...>> { + static constexpr std::tuple<Ts...> GetArgs(IpcResponseContext *ctx, size_t& a_index, size_t& b_index, size_t& x_index, size_t& c_index, size_t& in_h_index, size_t& out_h_index, size_t& out_obj_index, size_t& in_data_index, size_t& out_data_index, size_t& pb_offset, size_t& c_sz_offset) { + return std::tuple<Ts... > { + DecodeCommandArgument<Ts>(ctx, a_index, b_index, x_index, c_index, in_h_index, out_h_index, out_obj_index, in_data_index, out_data_index, pb_offset, c_sz_offset) + ... + }; + } + }; + + + static constexpr typename MetaInfo::Args Decode(IpcResponseContext *ctx) { + size_t a_index = 0, b_index = MetaInfo::NumInBuffers, x_index = 0, c_index = 0, in_h_index = 0, out_h_index = 0, out_obj_index = 0; + size_t in_data_index = 0x0, out_data_index = 0, pb_offset = 0; + size_t c_sz_offset = MetaInfo::InRawArgSize + (0x10 - ((uintptr_t)ctx->request.Raw - (uintptr_t)ctx->request.RawWithoutPadding)); + return DecodeTuple<typename MetaInfo::Args>::GetArgs(ctx, a_index, b_index, x_index, c_index, in_h_index, out_h_index, out_obj_index, in_data_index, out_data_index, pb_offset, c_sz_offset); + } +}; + +/* ================================================================================= */ + +template<typename MetaInfo, typename T> +static constexpr void EncodeArgument(IpcResponseContext *ctx, size_t&out_obj_index, T& arg) { + constexpr ArgType argT = GetArgType<T>(); + if constexpr (argT == ArgType::OutHandle) { + if constexpr (std::is_same_v<MovedHandle, typename OutHelper<T>::type>) { + ipcSendHandleMove(&ctx->reply, arg.GetValue().handle); + } else { + ipcSendHandleCopy(&ctx->reply, arg.GetValue().handle); + } + } else if constexpr (argT == ArgType::OutSession) { + if (IsDomainObject(ctx->obj_holder)) { + auto domain = ctx->obj_holder->GetServiceObject<IDomainObject>(); + domain->SetObject(arg.GetObjectId(), std::move(arg.GetHolder())); + } else { + ctx->manager->AddSession(ctx->out_object_server_handles[out_obj_index++], std::move(arg.GetHolder())); + } + } +} + +template<typename MetaInfo, typename ArgsTuple> +struct Encoder; + +template <typename MetaInfo, typename ...Args> +struct Encoder<MetaInfo, std::tuple<Args...>> { + + static constexpr void EncodeFailure(IpcResponseContext *ctx, Result rc) { + memset(armGetTls(), 0, 0x100); + ipcInitialize(&ctx->reply); + struct { + u64 magic; + u64 result; + } *raw; + + if (IsDomainObject(ctx->obj_holder)) { + raw = (decltype(raw))ipcPrepareHeaderForDomain(&ctx->reply, sizeof(*raw), 0); + auto resp_header = (DomainResponseHeader *)((uintptr_t)raw - sizeof(DomainResponseHeader)); + *resp_header = {0}; + } else { + raw = (decltype(raw))ipcPrepareHeader(&ctx->reply, sizeof(*raw)); + } + raw->magic = SFCO_MAGIC; + raw->result = rc; + } + + + + static constexpr void EncodeSuccess(IpcResponseContext *ctx, Args... args) { + size_t out_obj_index = 0; + + ((EncodeArgument<MetaInfo, Args>(ctx, out_obj_index, args)), ...); + + const bool is_domain = IsDomainObject(ctx->obj_holder); + + if (!is_domain) { + for (unsigned int i = 0; i < MetaInfo::NumOutSessions; i++) { + ipcSendHandleMove(&ctx->reply, ctx->out_handles[MetaInfo::NumOutHandles + i].handle); + } + } + + struct { + u64 magic; + u64 result; + } *raw; + if (is_domain) { + raw = (decltype(raw))ipcPrepareHeaderForDomain(&ctx->reply, sizeof(*raw) + MetaInfo::OutRawArgSize, 0); + auto resp_header = (DomainResponseHeader *)((uintptr_t)raw - sizeof(DomainResponseHeader)); + *resp_header = {0}; + resp_header->NumObjectIds = MetaInfo::NumOutSessions; + } else { + raw = (decltype(raw))ipcPrepareHeader(&ctx->reply, sizeof(*raw)+ MetaInfo::OutRawArgSize); + } + + raw->magic = SFCO_MAGIC; + raw->result = 0; + + memcpy((void *)((uintptr_t)raw + sizeof(*raw)), ctx->out_data, MetaInfo::OutRawArgSize); + if (is_domain) { + memcpy((void *)((uintptr_t)raw + sizeof(*raw) + MetaInfo::OutRawArgSize), ctx->out_object_ids, sizeof(*ctx->out_object_ids) * MetaInfo::NumOutSessions); + } + } + +}; + +/* ================================================================================= */ + +template<auto IpcCommandImpl> +constexpr Result WrapIpcCommandImpl(IpcResponseContext *ctx) { + using InArgs = typename PopFront<typename boost::callable_traits::args_t<decltype(IpcCommandImpl)>>::type; + using OutArgs = typename boost::callable_traits::return_type_t<decltype(IpcCommandImpl)>; + using ClassType = typename boost::callable_traits::class_of_t<decltype(IpcCommandImpl)>; + + using CommandMetaData = CommandMetaInfo<InArgs, OutArgs>; + + static_assert(CommandMetaData::ReturnsResult || CommandMetaData::ReturnsVoid, "IpcCommandImpls must return Result or void"); + + ipcInitialize(&ctx->reply); + memset(ctx->out_data, 0, CommandMetaData::OutRawArgSize); + + Result rc = Validator::Validate<CommandMetaData>(ctx); + + if (R_FAILED(rc)) { + return 0xAAEE; + } + + ClassType *this_ptr = nullptr; + if (IsDomainObject(ctx->obj_holder)) { + this_ptr = ctx->obj_holder->GetServiceObject<IDomainObject>()->GetObject(ctx->request.InThisObjectId)->GetServiceObject<ClassType>(); + } else { + this_ptr = ctx->obj_holder->GetServiceObject<ClassType>(); + } + if (this_ptr == nullptr) { + return 0xBBEE; + } + + std::shared_ptr<IServiceObject> out_objects[CommandMetaData::NumOutSessions]; + + /* Allocate out object IDs. */ + size_t num_out_objects; + if (IsDomainObject(ctx->obj_holder)) { + for (num_out_objects = 0; num_out_objects < CommandMetaData::NumOutSessions; num_out_objects++) { + if (R_FAILED((rc = ctx->obj_holder->GetServiceObject<IDomainObject>()->ReserveObject(&ctx->out_object_ids[num_out_objects])))) { + break; + } + ctx->out_objs[num_out_objects] = &out_objects[num_out_objects]; + } + } else { + for (num_out_objects = 0; num_out_objects < CommandMetaData::NumOutSessions; num_out_objects++) { + Handle server_h, client_h; + if (R_FAILED((rc = SessionManagerBase::CreateSessionHandles(&server_h, &client_h)))) { + break; + } + ctx->out_object_server_handles[num_out_objects] = server_h; + ctx->out_handles[CommandMetaData::NumOutHandles + num_out_objects].handle = client_h; + ctx->out_objs[num_out_objects] = &out_objects[num_out_objects]; + } + } + + ON_SCOPE_EXIT { + /* Clean up objects as necessary. */ + if (IsDomainObject(ctx->obj_holder) && R_FAILED(rc)) { + for (unsigned int i = 0; i < num_out_objects; i++) { + ctx->obj_holder->GetServiceObject<IDomainObject>()->FreeObject(ctx->out_object_ids[i]); + } + } else { + for (unsigned int i = 0; i < num_out_objects; i++) { + svcCloseHandle(ctx->out_object_server_handles[i]); + svcCloseHandle(ctx->out_handles[CommandMetaData::NumOutHandles + i].handle); + } + } + + for (unsigned int i = 0; i < num_out_objects; i++) { + ctx->out_objs[i] = nullptr; + } + }; + + if (R_SUCCEEDED(rc)) { + auto args = Decoder<CommandMetaData>::Decode(ctx); + + if constexpr (CommandMetaData::ReturnsResult) { + rc = std::apply( [=](auto&&... args) { return (this_ptr->*IpcCommandImpl)(args...); }, args); + } else { + std::apply( [=](auto&&... args) { (this_ptr->*IpcCommandImpl)(args...); }, args); + } + + if (R_SUCCEEDED(rc)) { + std::apply(Encoder<CommandMetaData, decltype(args)>::EncodeSuccess, std::tuple_cat(std::make_tuple(ctx), args)); + } else { + std::apply(Encoder<CommandMetaData, decltype(args)>::EncodeFailure, std::tuple_cat(std::make_tuple(ctx), std::make_tuple(rc))); + } + } else { + std::apply(Encoder<CommandMetaData, typename CommandMetaData::Args>::EncodeFailure, std::tuple_cat(std::make_tuple(ctx), std::make_tuple(rc))); + } + + return rc; +} + + +template <u32 c, auto CommandImpl, FirmwareVersion l = FirmwareVersion_Min, FirmwareVersion h = FirmwareVersion_Max> +inline static constexpr ServiceCommandMeta MakeServiceCommandMeta() { + return { + .fw_low = l, + .fw_high = h, + .cmd_id = c, + .handler = WrapIpcCommandImpl<CommandImpl>, + }; +}; + + +#pragma GCC diagnostic pop diff --git a/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_service_object.hpp b/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_service_object.hpp new file mode 100644 index 000000000..8803da33f --- /dev/null +++ b/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_service_object.hpp @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once +#include <switch.h> +#include <memory> +#include <type_traits> + +#include "ipc_out.hpp" + +#include "../firmware_version.hpp" + +class IpcResponseContext; + +struct ServiceCommandMeta { + FirmwareVersion fw_low = FirmwareVersion_Max; + FirmwareVersion fw_high = FirmwareVersion_Max; + u32 cmd_id = 0; + Result (*handler)(IpcResponseContext *) = nullptr; +}; + +class IServiceObject { + public: + virtual ~IServiceObject() { } +}; + +#define SERVICE_DISPATCH_TABLE_NAME s_DispatchTable +#define DEFINE_SERVICE_DISPATCH_TABLE static constexpr ServiceCommandMeta SERVICE_DISPATCH_TABLE_NAME[] + +template <typename T> +static constexpr size_t DispatchTableEntryCount() { + static_assert(std::is_base_of<IServiceObject, T>::value, "DispatchTable owners must derive from IServiceObject"); + return sizeof(T::SERVICE_DISPATCH_TABLE_NAME)/sizeof(ServiceCommandMeta); +} +template <typename T> +static constexpr const ServiceCommandMeta* DispatchTable() { + static_assert(std::is_base_of<IServiceObject, T>::value, "DispatchTable owners must derive from IServiceObject"); + return reinterpret_cast<const ServiceCommandMeta*>(&T::SERVICE_DISPATCH_TABLE_NAME); +} + +template <typename T> +static constexpr uintptr_t ServiceObjectId() { + static_assert(std::is_base_of<IServiceObject, T>::value, "Service Objects must derive from IServiceObject"); + return reinterpret_cast<uintptr_t>(&T::SERVICE_DISPATCH_TABLE_NAME); +} + +class ServiceObjectHolder { + private: + std::shared_ptr<IServiceObject> srv; + const ServiceCommandMeta *dispatch_table; + size_t entry_count; + + /* Private copy constructor. */ + ServiceObjectHolder(const ServiceObjectHolder& other) : srv(other.srv), dispatch_table(other.dispatch_table), entry_count(other.entry_count) { } + ServiceObjectHolder& operator=(const ServiceObjectHolder& other); + public: + /* Templated constructor ensures correct type id at runtime. */ + template <typename ServiceImpl> + explicit ServiceObjectHolder(std::shared_ptr<ServiceImpl>&& s) : srv(std::move(s)), dispatch_table(DispatchTable<ServiceImpl>()), entry_count(DispatchTableEntryCount<ServiceImpl>()) { } + + template <typename ServiceImpl> + ServiceImpl *GetServiceObject() const { + if (GetServiceId() == ServiceObjectId<ServiceImpl>()) { + return static_cast<ServiceImpl *>(this->srv.get()); + } + return nullptr; + } + + template<typename ServiceImpl> + ServiceImpl *GetServiceObjectUnsafe() const { + return static_cast<ServiceImpl *>(this->srv.get()); + } + + const ServiceCommandMeta *GetDispatchTable() const { + return this->dispatch_table; + } + + size_t GetDispatchTableEntryCount() const { + return this->entry_count; + } + + constexpr uintptr_t GetServiceId() const { + return reinterpret_cast<uintptr_t>(this->dispatch_table); + } + + /* Default constructor, move constructor, move assignment operator. */ + ServiceObjectHolder() : srv(nullptr), dispatch_table(nullptr) { } + + ServiceObjectHolder(ServiceObjectHolder&& other) : srv(std::move(other.srv)), dispatch_table(std::move(other.dispatch_table)), entry_count(std::move(other.entry_count)) { } + + ServiceObjectHolder& operator=(ServiceObjectHolder&& other) { + this->srv = other.srv; + this->dispatch_table = other.dispatch_table; + this->entry_count = other.entry_count; + other.Reset(); + return *this; + } + + explicit operator bool() const { + return this->srv != nullptr; + } + + bool operator!() const { + return this->srv == nullptr; + } + + void Reset() { + this->srv.reset(); + this->dispatch_table = nullptr; + this->entry_count = 0; + } + + ServiceObjectHolder Clone() const { + ServiceObjectHolder clone(*this); + return clone; + } +}; diff --git a/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_service_session.hpp b/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_service_session.hpp new file mode 100644 index 000000000..3b25e8721 --- /dev/null +++ b/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_service_session.hpp @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once +#include <switch.h> + +#include "../iwaitable.hpp" +#include "ipc_service_object.hpp" +#include "ipc_serialization.hpp" + +enum HipcControlCommand : u32 { + HipcControlCommand_ConvertCurrentObjectToDomain = 0, + HipcControlCommand_CopyFromCurrentDomain = 1, + HipcControlCommand_CloneCurrentObject = 2, + HipcControlCommand_QueryPointerBufferSize = 3, + HipcControlCommand_CloneCurrentObjectEx = 4 +}; + + +#define RESULT_DEFER_SESSION (0x6580A) + + +class ServiceSession : public IWaitable +{ + protected: + Handle session_handle; + std::vector<unsigned char> pointer_buffer; + ServiceObjectHolder obj_holder; + ServiceObjectHolder control_holder = ServiceObjectHolder(std::make_shared<IHipcControlService>(this)); + u8 backup_tls[0x100]; + + ServiceSession(Handle s_h) : session_handle(s_h) { } + public: + template<typename T> + ServiceSession(Handle s_h, size_t pbs) : session_handle(s_h), pointer_buffer(pbs), obj_holder(std::make_shared<T>()) { } + + ServiceSession(Handle s_h, size_t pbs, ServiceObjectHolder &&h) : session_handle(s_h), pointer_buffer(pbs), obj_holder(std::move(h)) { } + + virtual ~ServiceSession() override { + svcCloseHandle(this->session_handle); + } + + SessionManagerBase *GetSessionManager() { + return static_cast<SessionManagerBase *>(this->GetManager()); + } + + DomainManager *GetDomainManager() { + return static_cast<DomainManager *>(this->GetSessionManager()); + } + + Result Receive() { + int handle_index; + /* Prepare pointer buffer... */ + IpcCommand c; + ipcInitialize(&c); + if (this->pointer_buffer.size() > 0) { + ipcAddRecvStatic(&c, this->pointer_buffer.data(), this->pointer_buffer.size(), 0); + ipcPrepareHeader(&c, 0); + + /* Fix libnx bug in serverside C descriptor handling. */ + ((u32 *)armGetTls())[1] &= 0xFFFFC3FF; + ((u32 *)armGetTls())[1] |= (2) << 10; + } else { + ipcPrepareHeader(&c, 0); + } + + /* Receive. */ + Result rc = svcReplyAndReceive(&handle_index, &this->session_handle, 1, 0, U64_MAX); + if (R_SUCCEEDED(rc)) { + std::memcpy(this->backup_tls, armGetTls(), sizeof(this->backup_tls)); + } + + return rc; + } + + Result Reply() { + int handle_index; + return svcReplyAndReceive(&handle_index, &this->session_handle, 0, this->session_handle, 0); + } + + /* For preparing basic replies. */ + Result PrepareBasicResponse(IpcResponseContext *ctx, Result rc) { + ipcInitialize(&ctx->reply); + struct { + u64 magic; + u64 result; + } *raw = (decltype(raw))ipcPrepareHeader(&ctx->reply, sizeof(*raw)); + + raw->magic = SFCO_MAGIC; + raw->result = rc; + return raw->result; + } + + Result PrepareBasicDomainResponse(IpcResponseContext *ctx, Result rc) { + ipcInitialize(&ctx->reply); + struct { + DomainResponseHeader hdr; + u64 magic; + u64 result; + } *raw = (decltype(raw))ipcPrepareHeader(&ctx->reply, sizeof(*raw)); + + raw->hdr = (DomainResponseHeader){0}; + raw->magic = SFCO_MAGIC; + raw->result = rc; + return raw->result; + } + + /* For making a new response context. */ + void InitializeResponseContext(IpcResponseContext *ctx) { + std::memset(ctx, 0, sizeof(*ctx)); + ctx->manager = this->GetSessionManager(); + ctx->obj_holder = &this->obj_holder; + ctx->pb = this->pointer_buffer.data(); + ctx->pb_size = this->pointer_buffer.size(); + } + + /* IWaitable */ + virtual Handle GetHandle() { + return this->session_handle; + } + + virtual Result GetResponse(IpcResponseContext *ctx) { + Result rc = 0xF601; + FirmwareVersion fw = GetRuntimeFirmwareVersion(); + + const ServiceCommandMeta *dispatch_table = ctx->obj_holder->GetDispatchTable(); + size_t entry_count = ctx->obj_holder->GetDispatchTableEntryCount(); + + if (IsDomainObject(ctx->obj_holder)) { + switch (ctx->request.InMessageType) { + case DomainMessageType_Invalid: + return 0xF601; + case DomainMessageType_Close: + return PrepareBasicDomainResponse(ctx, ctx->obj_holder->GetServiceObject<IDomainObject>()->FreeObject(ctx->request.InThisObjectId)); + case DomainMessageType_SendMessage: + { + auto sub_obj = ctx->obj_holder->GetServiceObject<IDomainObject>()->GetObject(ctx->request.InThisObjectId); + if (sub_obj == nullptr) { + return PrepareBasicDomainResponse(ctx, 0x3D80B); + } + dispatch_table = sub_obj->GetDispatchTable(); + entry_count = sub_obj->GetDispatchTableEntryCount(); + } + } + } + + for (size_t i = 0; i < entry_count; i++) { + if (ctx->cmd_id == dispatch_table[i].cmd_id && dispatch_table[i].fw_low <= fw && fw <= dispatch_table[i].fw_high) { + rc = dispatch_table[i].handler(ctx); + break; + } + } + + return rc; + } + + virtual Result HandleReceived() { + IpcResponseContext ctx; + this->InitializeResponseContext(&ctx); + + ctx.cmd_type = (IpcCommandType)(*(u16 *)(armGetTls())); + + ctx.rc = 0; + + /* Parse based on command type. */ + switch (ctx.cmd_type) { + case IpcCommandType_Invalid: + case IpcCommandType_LegacyRequest: + case IpcCommandType_LegacyControl: + return 0xF601; + case IpcCommandType_Close: + { + /* Clean up gracefully. */ + PrepareBasicResponse(&ctx, 0); + this->Reply(); + } + return 0xF601; + case IpcCommandType_Control: + case IpcCommandType_ControlWithContext: + ctx.rc = ipcParse(&ctx.request); + ctx.obj_holder = &this->control_holder; + break; + case IpcCommandType_Request: + case IpcCommandType_RequestWithContext: + if (IsDomainObject(&this->obj_holder)) { + ctx.rc = ipcParseDomainRequest(&ctx.request); + } else { + ctx.rc = ipcParse(&ctx.request); + } + break; + default: + return 0xF601; + } + + + if (R_SUCCEEDED(ctx.rc)) { + ctx.cmd_id = ((u32 *)ctx.request.Raw)[2]; + this->PreProcessRequest(&ctx); + ctx.rc = this->GetResponse(&ctx); + } + + if (ctx.rc == RESULT_DEFER_SESSION) { + /* Session defer. */ + this->SetDeferred(true); + } else if (ctx.rc == 0xF601) { + /* Session close, nothing to do. */ + } else { + if (R_SUCCEEDED(ctx.rc)) { + this->PostProcessResponse(&ctx); + } + + ctx.rc = this->Reply(); + + if (ctx.rc == 0xEA01) { + ctx.rc = 0x0; + } + + this->CleanupResponse(&ctx); + } + + return ctx.rc; + } + + virtual void HandleDeferred() override { + memcpy(armGetTls(), this->backup_tls, sizeof(this->backup_tls)); + Result rc = this->HandleReceived(); + + if (rc != RESULT_DEFER_SESSION) { + this->SetDeferred(false); + if (rc == 0xF601) { + svcCloseHandle(this->GetHandle()); + } + } + } + + virtual Result HandleSignaled(u64 timeout) { + Result rc; + + if (R_SUCCEEDED(rc = this->Receive())) { + rc = this->HandleReceived(); + } + + return rc; + } + + virtual void PreProcessRequest(IpcResponseContext *ctx) { + /* ... */ + (void)(ctx); + } + + virtual void PostProcessResponse(IpcResponseContext *ctx) { + /* ... */ + (void)(ctx); + } + + virtual void CleanupResponse(IpcResponseContext *ctx) { + std::memset(this->backup_tls, 0, sizeof(this->backup_tls)); + } + + + public: + class IHipcControlService : public IServiceObject { + private: + ServiceSession *session; + public: + explicit IHipcControlService(ServiceSession *s) : session(s) { + + } + + virtual ~IHipcControlService() override { } + + Result ConvertCurrentObjectToDomain(Out<u32> object_id) { + /* Allocate new domain. */ + auto new_domain = this->session->GetDomainManager()->AllocateDomain(); + if (new_domain == nullptr) { + return 0x1900B; + } + + /* Reserve an object in the domain for our session. */ + u32 reserved_id; + Result rc = new_domain->ReserveObject(&reserved_id); + if (R_FAILED(rc)) { + return rc; + } + new_domain->SetObject(reserved_id, std::move(this->session->obj_holder)); + this->session->obj_holder = std::move(ServiceObjectHolder(std::move(new_domain))); + + /* Return the object id. */ + object_id.SetValue(reserved_id); + return 0; + } + + Result CopyFromCurrentDomain(Out<MovedHandle> out_h, u32 id) { + auto domain = this->session->obj_holder.GetServiceObject<IDomainObject>(); + if (domain == nullptr) { + return 0x3D60B; + } + + + auto object = domain->GetObject(id); + if (object == nullptr) { + return 0x3D80B; + } + + Handle server_h, client_h; + if (R_FAILED(SessionManagerBase::CreateSessionHandles(&server_h, &client_h))) { + /* N aborts here. Should we error code? */ + std::abort(); + } + + this->session->GetSessionManager()->AddSession(server_h, std::move(object->Clone())); + out_h.SetValue(client_h); + return 0; + } + + void CloneCurrentObject(Out<MovedHandle> out_h) { + Handle server_h, client_h; + if (R_FAILED(SessionManagerBase::CreateSessionHandles(&server_h, &client_h))) { + /* N aborts here. Should we error code? */ + std::abort(); + } + + this->session->GetSessionManager()->AddSession(server_h, std::move(this->session->obj_holder.Clone())); + out_h.SetValue(client_h); + } + + void QueryPointerBufferSize(Out<u16> size) { + size.SetValue(this->session->pointer_buffer.size()); + } + + void CloneCurrentObjectEx(Out<MovedHandle> out_h, u32 which) { + /* TODO: Figure out what this u32 controls. */ + return CloneCurrentObject(out_h); + } + + public: + DEFINE_SERVICE_DISPATCH_TABLE { + MakeServiceCommandMeta<HipcControlCommand_ConvertCurrentObjectToDomain, &ServiceSession::IHipcControlService::ConvertCurrentObjectToDomain>(), + MakeServiceCommandMeta<HipcControlCommand_CopyFromCurrentDomain, &ServiceSession::IHipcControlService::CopyFromCurrentDomain>(), + MakeServiceCommandMeta<HipcControlCommand_CloneCurrentObject, &ServiceSession::IHipcControlService::CloneCurrentObject>(), + MakeServiceCommandMeta<HipcControlCommand_QueryPointerBufferSize, &ServiceSession::IHipcControlService::QueryPointerBufferSize>(), + MakeServiceCommandMeta<HipcControlCommand_CloneCurrentObjectEx, &ServiceSession::IHipcControlService::CloneCurrentObjectEx>(), + }; + }; +}; diff --git a/stratosphere/libstratosphere/include/stratosphere/servicesession.hpp b/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_session_manager_base.hpp similarity index 56% rename from stratosphere/libstratosphere/include/stratosphere/servicesession.hpp rename to stratosphere/libstratosphere/include/stratosphere/ipc/ipc_session_manager_base.hpp index 7b452c870..3da68038d 100644 --- a/stratosphere/libstratosphere/include/stratosphere/servicesession.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_session_manager_base.hpp @@ -15,22 +15,20 @@ */ #pragma once -#include <switch.h> -#include <type_traits> +#include <atomic> -#include "ipc_templating.hpp" -#include "iserviceobject.hpp" -#include "iwaitable.hpp" -#include "iserver.hpp" -#include "isession.hpp" +#include "../waitable_manager_base.hpp" +#include "ipc_service_object.hpp" -template <typename T> -class ServiceSession final : public ISession<T> { - static_assert(std::is_base_of<IServiceObject, T>::value, "Service Objects must derive from IServiceObject"); - +class SessionManagerBase : public WaitableManagerBase, public DomainManager { public: - ServiceSession<T>(IServer<T> *s, Handle s_h, Handle c_h, size_t pbs = 0x400) : ISession<T>(s, s_h, c_h, pbs) { - /* ... */ + SessionManagerBase() = default; + virtual ~SessionManagerBase() = default; + + virtual void AddSession(Handle server_h, ServiceObjectHolder &&service) = 0; + + static Result CreateSessionHandles(Handle *server_h, Handle *client_h) { + return svcCreateSession(server_h, client_h, 0, 0); } - }; + diff --git a/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_special.hpp b/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_special.hpp new file mode 100644 index 000000000..3b613b366 --- /dev/null +++ b/stratosphere/libstratosphere/include/stratosphere/ipc/ipc_special.hpp @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once +#include <switch.h> +#include <type_traits> + +#include "ipc_out.hpp" + +/* Represents an input PID. */ +struct PidDescriptorTag{}; + +struct PidDescriptor : public PidDescriptorTag { + u64 pid; + + void operator=(u64 &p) { + pid = p; + } + + PidDescriptor(u64 p) : pid(p) { } +}; + +struct IpcHandleTag{}; + +struct IpcHandle : public IpcHandleTag { + Handle handle; +}; + +/* Represents a moved handle. */ +struct MovedHandle : public IpcHandle { + void operator=(const Handle &h) { + this->handle = h; + } + + void operator=(const IpcHandle &o) { + this->handle = o.handle; + } + + MovedHandle(Handle h) { + this->handle = h; + } +}; + +/* Represents a copied handle. */ +struct CopiedHandle : public IpcHandle { + void operator=(const Handle &h) { + handle = h; + } + + void operator=(const IpcHandle &o) { + this->handle = o.handle; + } + + CopiedHandle(Handle h) { + this->handle = h; + } +}; + +template <> +class Out<MovedHandle> : public OutHandleTag { +private: + MovedHandle *obj; +public: + Out(IpcHandle *o) : obj(static_cast<MovedHandle *>(o)) { } + + void SetValue(const Handle& h) { + *obj = h; + } + + void SetValue(const MovedHandle& o) { + *obj = o; + } + + const MovedHandle& GetValue() { + return *obj; + } + + MovedHandle* GetPointer() { + return obj; + } + + Handle* GetHandlePointer() { + return &obj->handle; + } + + /* Convenience operators. */ + MovedHandle& operator*() { + return *obj; + } + + MovedHandle* operator->() { + return obj; + } +}; + +template <> +class Out<CopiedHandle> : public OutHandleTag { +private: + CopiedHandle *obj; +public: + Out(IpcHandle *o) : obj(static_cast<CopiedHandle *>(o)) { } + + void SetValue(const Handle& h) { + *obj = h; + } + + void SetValue(const CopiedHandle& o) { + *obj = o; + } + + const CopiedHandle& GetValue() { + return *obj; + } + + CopiedHandle* GetPointer() { + return obj; + } + + Handle* GetHandlePointer() { + return &obj->handle; + } + + /* Convenience operators. */ + CopiedHandle& operator*() { + return *obj; + } + + CopiedHandle* operator->() { + return obj; + } +}; \ No newline at end of file diff --git a/stratosphere/libstratosphere/include/stratosphere/ipc_templating.hpp b/stratosphere/libstratosphere/include/stratosphere/ipc_templating.hpp deleted file mode 100644 index 7f9c2c89e..000000000 --- a/stratosphere/libstratosphere/include/stratosphere/ipc_templating.hpp +++ /dev/null @@ -1,561 +0,0 @@ -/* - * Copyright (c) 2018 Atmosphère-NX - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#pragma once -#include <switch.h> -#include <cstdlib> -#include <cstring> -#include <tuple> -#include "../boost/callable_traits.hpp" -#include <type_traits> - -#include "domainowner.hpp" - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-but-set-variable" - -/* Base for In/Out Buffers. */ -struct IpcBufferBase {}; - -/* Represents an A descriptor. */ -struct InBufferBase : IpcBufferBase {}; - -template <typename T, BufferType e_t = BufferType_Normal> -struct InBuffer : InBufferBase { - T *buffer; - size_t num_elements; - BufferType type; - static const BufferType expected_type = e_t; - - InBuffer(void *b, size_t n, BufferType t) : buffer((T *)b), num_elements(n/sizeof(T)), type(t) { } -}; - -/* Represents a B descriptor. */ -struct OutBufferBase : IpcBufferBase {}; - -template <typename T, BufferType e_t = BufferType_Normal> -struct OutBuffer : OutBufferBase { - T *buffer; - size_t num_elements; - BufferType type; - static const BufferType expected_type = e_t; - - OutBuffer(void *b, size_t n, BufferType t) : buffer((T *)b), num_elements(n/sizeof(T)), type(t) { } -}; - -/* Represents an X descriptor. */ -template <typename T> -struct InPointer : IpcBufferBase { - T *pointer; - size_t num_elements; - - InPointer(void *p, size_t n) : pointer((T *)p), num_elements(n/sizeof(T)) { } -}; - -/* Represents a C descriptor. */ -struct OutPointerWithServerSizeBase : IpcBufferBase {}; - -template <typename T, size_t n> -struct OutPointerWithServerSize : OutPointerWithServerSizeBase { - T *pointer; - static const size_t num_elements = n; - - OutPointerWithServerSize(void *p) : pointer((T *)p) { } -}; - -/* Represents a C descriptor with size in raw data. */ -template <typename T> -struct OutPointerWithClientSize : IpcBufferBase { - T *pointer; - size_t num_elements; - - OutPointerWithClientSize(void *p, size_t n) : pointer((T *)p), num_elements(n/sizeof(T)) { } -}; - -/* Represents an input PID. */ -struct PidDescriptor { - u64 pid; - - PidDescriptor(u64 p) : pid(p) { } -}; - -/* Represents a moved handle. */ -struct MovedHandle { - Handle handle; - - MovedHandle(Handle h) : handle(h) { } -}; - -/* Represents a copied handle. */ -struct CopiedHandle { - Handle handle; - - CopiedHandle(Handle h) : handle(h) { } -}; - -/* Forward declarations. */ -template <typename T> -class ISession; - -/* Represents an output ServiceObject. */ -struct OutSessionBase {}; - -template <typename T> -struct OutSession : OutSessionBase { - ISession<T> *session; - u32 domain_id; - - OutSession(ISession<T> *s) : session(s), domain_id(DOMAIN_ID_MAX) { } -}; - -/* Utilities. */ -template <typename T, template <typename...> class Template> -struct is_specialization_of { - static const bool value = false; -}; - -template <template <typename...> class Template, typename... Args> -struct is_specialization_of<Template<Args...>, Template> { - static const bool value = true; -}; - -template<typename Tuple> -struct pop_front; - -template<typename Head, typename... Tail> -struct pop_front<std::tuple<Head, Tail...>> { - using type = std::tuple<Tail...>; -}; - -template <typename T> -struct is_ipc_buffer { - static const bool value = std::is_base_of<IpcBufferBase, T>::value; -}; - -template <typename T> -struct is_ipc_handle { - static const size_t value = (std::is_same<T, MovedHandle>::value || std::is_same<T, CopiedHandle>::value) ? 1 : 0; -}; - -template <typename T> -struct is_out_session { - static const bool value = std::is_base_of<OutSessionBase, T>::value; -}; - -template <typename T> -struct size_in_raw_data { - static const size_t value = (is_ipc_buffer<T>::value || is_ipc_handle<T>::value || is_out_session<T>::value) ? 0 : ((sizeof(T) < sizeof(u32)) ? sizeof(u32) : (sizeof(T) + 3) & (~3)); -}; - -template <typename ...Args> -struct size_in_raw_data_for_arguments { - static const size_t value = (size_in_raw_data<Args>::value + ... + 0); -}; - -template <typename ...Args> -struct num_out_sessions_in_arguments { - static const size_t value = ((is_out_session<Args>::value ? 1 : 0) + ... + 0); -}; - -template <typename T> -struct size_in_raw_data_with_out_pointers { - static const size_t value = is_specialization_of<T, OutPointerWithClientSize>::value ? 2 : size_in_raw_data<T>::value; -}; - -template <typename ...Args> -struct size_in_raw_data_with_out_pointers_for_arguments { - static const size_t value = ((size_in_raw_data_with_out_pointers<Args>::value + ... + 0) + 3) & ~3; -}; - -template <typename T> -struct is_ipc_inbuffer { - static const size_t value = (std::is_base_of<InBufferBase, T>::value) ? 1 : 0; -}; - -template <typename ...Args> -struct num_inbuffers_in_arguments { - static const size_t value = (is_ipc_inbuffer<Args>::value + ... + 0); -}; - -template <typename T> -struct is_ipc_inpointer { - static const size_t value = (is_specialization_of<T, InPointer>::value) ? 1 : 0; -}; - -template <typename ...Args> -struct num_inpointers_in_arguments { - static const size_t value = (is_ipc_inpointer<Args>::value + ... + 0); -}; - -template <typename T> -struct is_ipc_outpointer { - static const size_t value = (is_specialization_of<T, OutPointerWithClientSize>::value || std::is_base_of<OutPointerWithServerSizeBase, T>::value) ? 1 : 0; -}; - -template <typename ...Args> -struct num_outpointers_in_arguments { - static const size_t value = (is_ipc_outpointer<Args>::value + ... + 0); -}; - -template <typename T> -struct is_ipc_inoutbuffer { - static const size_t value = (std::is_base_of<InBufferBase, T>::value || std::is_base_of<OutBufferBase, T>::value) ? 1 : 0; -}; - -template <typename ...Args> -struct num_inoutbuffers_in_arguments { - static const size_t value = (is_ipc_inoutbuffer<Args>::value + ... + 0); -}; - -template <typename ...Args> -struct num_handles_in_arguments { - static const size_t value = (is_ipc_handle<Args>::value + ... + 0); -}; - -template <typename ...Args> -struct num_pids_in_arguments { - static const size_t value = ((std::is_same<Args, PidDescriptor>::value ? 1 : 0) + ... + 0); -}; - -template<typename T> -T GetValueFromIpcParsedCommand(IpcParsedCommand& r, IpcCommand& out_c, u8 *pointer_buffer, size_t& pointer_buffer_offset, size_t& cur_rawdata_index, size_t& cur_c_size_offset, size_t& a_index, size_t& b_index, size_t& x_index, size_t& c_index, size_t& h_index) { - const size_t old_rawdata_index = cur_rawdata_index; - const size_t old_c_size_offset = cur_c_size_offset; - const size_t old_pointer_buffer_offset = pointer_buffer_offset; - if constexpr (std::is_base_of<InBufferBase, T>::value) { - const T& value = T(r.Buffers[a_index], r.BufferSizes[a_index], r.BufferTypes[a_index]); - ++a_index; - return value; - } else if constexpr (std::is_base_of<OutBufferBase, T>::value) { - const T& value = T(r.Buffers[b_index], r.BufferSizes[b_index], r.BufferTypes[b_index]); - ++b_index; - return value; - } else if constexpr (is_specialization_of<T, InPointer>::value) { - const T& value{r.Statics[x_index], r.StaticSizes[x_index]}; - ++x_index; - return value; - } else if constexpr (std::is_base_of<OutPointerWithServerSizeBase, T>::value) { - T t = T(pointer_buffer + old_pointer_buffer_offset); - ipcAddSendStatic(&out_c, pointer_buffer + old_pointer_buffer_offset, t.num_elements * sizeof(*t.pointer), c_index++); - return t; - } else if constexpr (is_specialization_of<T, OutPointerWithClientSize>::value) { - cur_c_size_offset += sizeof(u16); - u16 sz = *((u16 *)((u8 *)(r.Raw) + old_c_size_offset)); - pointer_buffer_offset += sz; - ipcAddSendStatic(&out_c, pointer_buffer + old_pointer_buffer_offset, sz, c_index++); - return T(pointer_buffer + old_pointer_buffer_offset, sz); - } else if constexpr (is_ipc_handle<T>::value) { - return r.Handles[h_index++]; - } else if constexpr (std::is_same<T, PidDescriptor>::value) { - cur_rawdata_index += sizeof(u64) / sizeof(u32); - return PidDescriptor(r.Pid); - } else if constexpr (std::is_same<T, bool>::value) { - /* Official bools accept non-zero values with low bit unset as false. */ - cur_rawdata_index += size_in_raw_data<T>::value / sizeof(u32); - return ((*(((u32 *)r.Raw + old_rawdata_index))) & 1) == 1; - } else { - cur_rawdata_index += size_in_raw_data<T>::value / sizeof(u32); - return *((T *)((u32 *)r.Raw + old_rawdata_index)); - } -} - -template <typename T> -bool ValidateIpcParsedCommandArgument(IpcParsedCommand& r, size_t& cur_rawdata_index, size_t& cur_c_size_offset, size_t& a_index, size_t& b_index, size_t& x_index, size_t& c_index, size_t& h_index, size_t& total_c_size) { - const size_t old_c_size_offset = cur_c_size_offset; - if constexpr (std::is_base_of<InBufferBase, T>::value) { - return r.Buffers[a_index] != NULL && r.BufferDirections[a_index] == BufferDirection_Send && r.BufferTypes[a_index++] == T::expected_type; - } else if constexpr (std::is_base_of<OutBufferBase, T>::value) { - return r.Buffers[b_index] != NULL && r.BufferDirections[b_index] == BufferDirection_Recv && r.BufferTypes[b_index++] == T::expected_type; - } else if constexpr (is_specialization_of<T, InPointer>::value) { - return r.Statics[x_index] != NULL; - } else if constexpr (std::is_base_of<OutPointerWithServerSizeBase, T>::value) { - total_c_size += T::num_elements; - return true; - } else if constexpr (is_specialization_of<T, OutPointerWithClientSize>::value) { - cur_c_size_offset += sizeof(u16); - u16 sz = *((u16 *)((u8 *)(r.Raw) + old_c_size_offset)); - total_c_size += sz; - return true; - } else if constexpr (std::is_same<T, MovedHandle>::value) { - return !r.WasHandleCopied[h_index++]; - } else if constexpr (std::is_same<T, CopiedHandle>::value) { - return r.WasHandleCopied[h_index++]; - } else { - return true; - } -} - -/* Validator. */ -template <typename ArgsTuple> -struct Validator; - -template<typename... Args> -struct Validator<std::tuple<Args...>> { - IpcParsedCommand &r; - size_t pointer_buffer_size; - - Result operator()() { - if (r.RawSize < size_in_raw_data_with_out_pointers_for_arguments<Args... >::value) { - return 0xF601; - } - - if (r.NumBuffers != num_inoutbuffers_in_arguments<Args... >::value) { - return 0xF601; - } - - if (r.NumStatics != num_inpointers_in_arguments<Args... >::value) { - return 0xF601; - } - - if (r.NumStaticsOut != num_outpointers_in_arguments<Args... >::value) { - return 0xF601; - } - - if (r.NumHandles != num_handles_in_arguments<Args... >::value) { - return 0xF601; - } - - constexpr size_t num_pids = num_pids_in_arguments<Args... >::value; - - static_assert(num_pids <= 1, "Number of PID descriptors in IpcCommandImpl cannot be > 1"); - - if ((r.HasPid && num_pids == 0) || (!r.HasPid && num_pids)) { - return 0xF601; - } - - if (((u32 *)r.Raw)[0] != SFCI_MAGIC) { - //return 0xF601; - } - - size_t a_index = 0, b_index = num_inbuffers_in_arguments<Args ...>::value, x_index = 0, c_index = 0, h_index = 0; - size_t cur_rawdata_index = 4; - size_t cur_c_size_offset = 0x10 + size_in_raw_data_for_arguments<Args... >::value + (0x10 - ((uintptr_t)r.Raw - (uintptr_t)r.RawWithoutPadding)); - size_t total_c_size = 0; - - if (!(ValidateIpcParsedCommandArgument<Args>(r, cur_rawdata_index, cur_c_size_offset, a_index, b_index, x_index, c_index, h_index, total_c_size) && ...)) { - return 0xF601; - } - - if (total_c_size > pointer_buffer_size) { - return 0xF601; - } - - return 0; - } -}; - - -/* Decoder. */ -template<typename OutTuple, typename ArgsTuple> -struct Decoder; - -template<typename OutTuple, typename... Args> -struct Decoder<OutTuple, std::tuple<Args...>> { - static std::tuple<Args...> Decode(IpcParsedCommand& r, IpcCommand &out_c, u8 *pointer_buffer) { - size_t a_index = 0, b_index = num_inbuffers_in_arguments<Args ...>::value, x_index = 0, c_index = 0, h_index = 0; - size_t cur_rawdata_index = 4; - size_t cur_c_size_offset = 0x10 + size_in_raw_data_for_arguments<Args... >::value + (0x10 - ((uintptr_t)r.Raw - (uintptr_t)r.RawWithoutPadding)); - size_t pointer_buffer_offset = 0; - return std::tuple<Args... > { - GetValueFromIpcParsedCommand<Args>(r, out_c, pointer_buffer, pointer_buffer_offset, cur_rawdata_index, cur_c_size_offset, a_index, b_index, x_index, c_index, h_index) - ... - }; - } -}; - -/* Encoder. */ -template<typename ArgsTuple> -struct Encoder; - -template<typename T> -constexpr size_t GetAndUpdateOffsetIntoRawData(DomainOwner *domain_owner, size_t& offset) { - auto old = offset; - - if (old == 0) { - offset += sizeof(u64); - } else { - if constexpr (is_out_session<T>::value) { - if (domain_owner) { - offset += sizeof(u32); - } - } else { - offset += size_in_raw_data<T>::value; - } - } - - return old; -} - -template<typename T> -void EncodeValueIntoIpcMessageBeforePrepare(DomainOwner *domain_owner, IpcCommand *c, T &value) { - if constexpr (std::is_same<T, MovedHandle>::value) { - ipcSendHandleMove(c, value.handle); - } else if constexpr (std::is_same<T, CopiedHandle>::value) { - ipcSendHandleCopy(c, value.handle); - } else if constexpr (std::is_same<T, PidDescriptor>::value) { - ipcSendPid(c); - } else if constexpr (is_out_session<T>::value) { - if (domain_owner && value.session) { - /* TODO: Check error... */ - if (value.domain_id != DOMAIN_ID_MAX) { - domain_owner->set_object(value.session->get_service_object(), value.domain_id); - } else { - domain_owner->reserve_object(value.session->get_service_object(), &value.domain_id); - } - value.session->close_handles(); - delete value.session; - } else { - ipcSendHandleMove(c, value.session ? value.session->get_client_handle() : 0x0); - } - } -} - -template<typename T> -void EncodeValueIntoIpcMessageAfterPrepare(DomainOwner *domain_owner, u8 *cur_out, T value) { - if constexpr (is_ipc_handle<T>::value || std::is_same<T, PidDescriptor>::value) { - /* Do nothing. */ - } else if constexpr (is_out_session<T>::value) { - if (domain_owner) { - *((u32 *)cur_out) = value.domain_id; - } - } else { - *((T *)(cur_out)) = value; - } -} - -template<typename... Args> -struct Encoder<std::tuple<Args...>> { - IpcCommand &out_command; - - auto operator()(DomainOwner *domain_owner, Args... args) { - static_assert(sizeof...(Args) > 0, "IpcCommandImpls must return std::tuple<Result, ...>"); - size_t offset = 0; - - u8 *tls = (u8 *)armGetTls(); - - std::fill(tls, tls + 0x100, 0x00); - - ((EncodeValueIntoIpcMessageBeforePrepare<Args>(domain_owner, &out_command, args)), ...); - - /* Remove the extra space resulting from first Result type. */ - struct { - u64 magic; - u64 result; - } *raw; - if (domain_owner == NULL) { - raw = (decltype(raw))ipcPrepareHeader(&out_command, sizeof(*raw) + size_in_raw_data_for_arguments<Args... >::value - sizeof(Result)); - } else { - raw = (decltype(raw))ipcPrepareHeaderForDomain(&out_command, sizeof(*raw) + size_in_raw_data_for_arguments<Args... >::value + (num_out_sessions_in_arguments<Args... >::value * sizeof(u32)) - sizeof(Result), 0); - *((DomainMessageHeader *)((uintptr_t)raw - sizeof(DomainMessageHeader))) = {0}; - } - - - raw->magic = SFCO_MAGIC; - - u8 *raw_data = (u8 *)&raw->result; - - ((EncodeValueIntoIpcMessageAfterPrepare<Args>(domain_owner, raw_data + GetAndUpdateOffsetIntoRawData<Args>(domain_owner, offset), args)), ...); - - Result rc = raw->result; - - if (R_FAILED(rc)) { - std::fill(tls, tls + 0x100, 0x00); - ipcInitialize(&out_command); - raw = (decltype(raw))ipcPrepareHeader(&out_command, sizeof(raw)); - raw->magic = SFCO_MAGIC; - raw->result = rc; - } - - return rc; - } -}; - - -template<auto IpcCommandImpl, typename Class, typename... Args> -Result WrapDeferredIpcCommandImpl(Class *this_ptr, Args... args) { - using InArgs = typename boost::callable_traits::args_t<decltype(IpcCommandImpl)>; - using InArgsWithoutThis = typename pop_front<InArgs>::type; - using OutArgs = typename boost::callable_traits::return_type_t<decltype(IpcCommandImpl)>; - - static_assert(is_specialization_of<OutArgs, std::tuple>::value, "IpcCommandImpls must return std::tuple<Result, ...>"); - static_assert(std::is_same_v<std::tuple_element_t<0, OutArgs>, Result>, "IpcCommandImpls must return std::tuple<Result, ...>"); - static_assert(std::is_same_v<InArgsWithoutThis, std::tuple<Args...>>, "Invalid Deferred Wrapped IpcCommandImpl arguments!"); - - IpcCommand out_command; - - ipcInitialize(&out_command); - - auto tuple_args = std::make_tuple(args...); - auto result = std::apply( [=](auto&&... a) { return (this_ptr->*IpcCommandImpl)(a...); }, tuple_args); - - DomainOwner *down = NULL; - - return std::apply(Encoder<OutArgs>{out_command}, std::tuple_cat(std::make_tuple(down), result)); -} - -template<auto IpcCommandImpl, typename Class> -Result WrapIpcCommandImpl(Class *this_ptr, IpcParsedCommand& r, IpcCommand &out_command, u8 *pointer_buffer, size_t pointer_buffer_size) { - using InArgs = typename boost::callable_traits::args_t<decltype(IpcCommandImpl)>; - using InArgsWithoutThis = typename pop_front<InArgs>::type; - using OutArgs = typename boost::callable_traits::return_type_t<decltype(IpcCommandImpl)>; - - static_assert(is_specialization_of<OutArgs, std::tuple>::value, "IpcCommandImpls must return std::tuple<Result, ...>"); - static_assert(std::is_same_v<std::tuple_element_t<0, OutArgs>, Result>, "IpcCommandImpls must return std::tuple<Result, ...>"); - - ipcInitialize(&out_command); - - Result rc = Validator<InArgsWithoutThis>{r, pointer_buffer_size}(); - - if (R_FAILED(rc)) { - return 0xF601; - } - - auto args = Decoder<OutArgs, InArgsWithoutThis>::Decode(r, out_command, pointer_buffer); - auto result = std::apply( [=](auto&&... args) { return (this_ptr->*IpcCommandImpl)(args...); }, args); - DomainOwner *down = NULL; - if (r.IsDomainMessage) { - down = this_ptr->get_owner(); - } - - return std::apply(Encoder<OutArgs>{out_command}, std::tuple_cat(std::make_tuple(down), result)); -} - -template<auto IpcCommandImpl> -Result WrapStaticIpcCommandImpl(IpcParsedCommand& r, IpcCommand &out_command, u8 *pointer_buffer, size_t pointer_buffer_size) { - using InArgs = typename boost::callable_traits::args_t<decltype(IpcCommandImpl)>; - using OutArgs = typename boost::callable_traits::return_type_t<decltype(IpcCommandImpl)>; - - static_assert(is_specialization_of<OutArgs, std::tuple>::value, "IpcCommandImpls must return std::tuple<Result, ...>"); - static_assert(std::is_same_v<std::tuple_element_t<0, OutArgs>, Result>, "IpcCommandImpls must return std::tuple<Result, ...>"); - - ipcInitialize(&out_command); - - Result rc = Validator<InArgs>{r, pointer_buffer_size}(); - - if (R_FAILED(rc)) { - return 0xF601; - } - - auto args = Decoder<OutArgs, InArgs>::Decode(r, out_command, pointer_buffer); - auto result = std::apply(IpcCommandImpl, args); - DomainOwner *down = NULL; - - return std::apply(Encoder<OutArgs>{out_command}, std::tuple_cat(std::make_tuple(down), result)); -} - -#pragma GCC diagnostic pop - -#include "isession.hpp" diff --git a/stratosphere/libstratosphere/include/stratosphere/ipcsession.hpp b/stratosphere/libstratosphere/include/stratosphere/ipcsession.hpp deleted file mode 100644 index e95593280..000000000 --- a/stratosphere/libstratosphere/include/stratosphere/ipcsession.hpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2018 Atmosphère-NX - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#pragma once -#include <switch.h> -#include <type_traits> - -#include "ipc_templating.hpp" -#include "iserviceobject.hpp" -#include "iwaitable.hpp" -#include "isession.hpp" - -template <typename T> -class IPCSession final : public ISession<T> { - static_assert(std::is_base_of<IServiceObject, T>::value, "Service Objects must derive from IServiceObject"); - - public: - IPCSession<T>(size_t pbs = 0x400) : ISession<T>(NULL, 0, 0, 0) { - Result rc; - if (R_FAILED((rc = svcCreateSession(&this->server_handle, &this->client_handle, 0, 0)))) { - fatalSimple(rc); - } - this->service_object = std::make_shared<T>(); - this->pointer_buffer.resize(pbs); - } - - IPCSession<T>(std::shared_ptr<T> so, size_t pbs = 0x400) : ISession<T>(NULL, 0, 0, so, 0) { - Result rc; - if (R_FAILED((rc = svcCreateSession(&this->server_handle, &this->client_handle, 0, 0)))) { - fatalSimple(rc); - } - this->pointer_buffer.resize(pbs); - } -}; diff --git a/stratosphere/libstratosphere/include/stratosphere/iserviceobject.hpp b/stratosphere/libstratosphere/include/stratosphere/iserviceobject.hpp deleted file mode 100644 index 2e8c13570..000000000 --- a/stratosphere/libstratosphere/include/stratosphere/iserviceobject.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2018 Atmosphère-NX - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#pragma once -#include <switch.h> - -template <typename T> -class ISession; - -class DomainOwner; - -class IServiceObject { - private: - DomainOwner *owner = NULL; - public: - virtual ~IServiceObject() { } - - virtual IServiceObject *clone() = 0; - - bool is_domain() { return this->owner != NULL; } - DomainOwner *get_owner() { return this->owner; } - void set_owner(DomainOwner *owner) { this->owner = owner; } - virtual Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) = 0; - virtual Result handle_deferred() = 0; -}; - -#include "domainowner.hpp" diff --git a/stratosphere/libstratosphere/include/stratosphere/isession.hpp b/stratosphere/libstratosphere/include/stratosphere/isession.hpp deleted file mode 100644 index 842dfd412..000000000 --- a/stratosphere/libstratosphere/include/stratosphere/isession.hpp +++ /dev/null @@ -1,290 +0,0 @@ -/* - * Copyright (c) 2018 Atmosphère-NX - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#pragma once -#include <switch.h> -#include <type_traits> - -#include "ipc_templating.hpp" -#include "iserviceobject.hpp" -#include "iwaitable.hpp" -#include "iserver.hpp" - -#include "domainowner.hpp" - -enum IpcControlCommand { - IpcCtrl_Cmd_ConvertCurrentObjectToDomain = 0, - IpcCtrl_Cmd_CopyFromCurrentDomain = 1, - IpcCtrl_Cmd_CloneCurrentObject = 2, - IpcCtrl_Cmd_QueryPointerBufferSize = 3, - IpcCtrl_Cmd_CloneCurrentObjectEx = 4 -}; - -#define RESULT_DEFER_SESSION (0x6580A) - - -template <typename T> -class IServer; - -class IServiceObject; - -template <typename T> -class ISession : public IWaitable { - static_assert(std::is_base_of<IServiceObject, T>::value, "Service Objects must derive from IServiceObject"); - protected: - std::shared_ptr<T> service_object; - IServer<T> *server; - Handle server_handle; - Handle client_handle; - std::vector<char> pointer_buffer; - - bool is_domain = false; - std::shared_ptr<DomainOwner> domain; - - - std::shared_ptr<IServiceObject> active_object; - - public: - ISession<T>(IServer<T> *s, Handle s_h, Handle c_h, size_t pbs = 0x400) : server(s), server_handle(s_h), client_handle(c_h), pointer_buffer(pbs) { - this->service_object = std::make_shared<T>(); - } - - ISession<T>(IServer<T> *s, Handle s_h, Handle c_h, std::shared_ptr<T> so, size_t pbs = 0x400) : service_object(so), server(s), server_handle(s_h), client_handle(c_h), pointer_buffer(pbs) { - } - - ~ISession() override { - if (server_handle) { - svcCloseHandle(server_handle); - } - if (client_handle) { - svcCloseHandle(client_handle); - } - } - - void close_handles() { - if (server_handle) { - svcCloseHandle(server_handle); - server_handle = 0; - } - if (client_handle) { - svcCloseHandle(client_handle); - client_handle = 0; - } - } - - std::shared_ptr<T> get_service_object() { return this->service_object; } - Handle get_server_handle() { return this->server_handle; } - Handle get_client_handle() { return this->client_handle; } - - - DomainOwner *get_owner() { return this->is_domain ? this->domain.get() : NULL; } - - /* IWaitable */ - Handle get_handle() override { - return this->server_handle; - } - - void handle_deferred() override { - Result rc = this->service_object->handle_deferred(); - int handle_index; - - if (rc != RESULT_DEFER_SESSION) { - this->set_deferred(false); - if (rc == 0xF601) { - svcCloseHandle(this->get_handle()); - } else { - rc = svcReplyAndReceive(&handle_index, &this->server_handle, 0, this->server_handle, 0); - } - } - } - - - virtual Result handle_message(IpcParsedCommand &r) { - Result retval = 0xF601; - - IpcCommand c; - ipcInitialize(&c); - - if (r.IsDomainMessage && this->active_object == NULL) { - return 0xF601; - } - - - if (r.IsDomainMessage && r.MessageType == DomainMessageType_Close) { - this->domain->delete_object(this->active_object); - this->active_object = NULL; - struct { - u64 magic; - u64 result; - } *raw = (decltype(raw))ipcPrepareHeader(&c, sizeof(*raw)); - - raw->magic = SFCO_MAGIC; - raw->result = 0x0; - return 0x0; - } - - u64 cmd_id = ((u32 *)r.Raw)[2]; - switch (r.CommandType) { - case IpcCommandType_Close: - /* TODO: This should close the session and clean up its resources. */ - retval = 0xF601; - break; - case IpcCommandType_LegacyControl: - /* TODO: What does this allow one to do? */ - retval = 0xF601; - break; - case IpcCommandType_LegacyRequest: - /* TODO: What does this allow one to do? */ - retval = 0xF601; - break; - case IpcCommandType_Request: - case IpcCommandType_RequestWithContext: - retval = this->active_object->dispatch(r, c, cmd_id, (u8 *)pointer_buffer.data(), pointer_buffer.size()); - break; - case IpcCommandType_Control: - case IpcCommandType_ControlWithContext: - retval = this->dispatch_control_command(r, c, cmd_id); - break; - case IpcCommandType_Invalid: - default: - retval = 0xF601; - break; - } - - return retval; - } - - virtual void postprocess(IpcParsedCommand &r, u64 cmd_id) { - /* ... */ - (void)(r); - (void)(cmd_id); - } - - virtual void cleanup() { - /* ... */ - } - - Result handle_signaled(u64 timeout) override { - Result rc; - int handle_index; - - /* Prepare pointer buffer... */ - IpcCommand c_for_reply; - ipcInitialize(&c_for_reply); - ipcAddRecvStatic(&c_for_reply, this->pointer_buffer.data(), this->pointer_buffer.size(), 0); - ipcPrepareHeader(&c_for_reply, 0); - - if (R_SUCCEEDED(rc = svcReplyAndReceive(&handle_index, &this->server_handle, 1, 0, U64_MAX))) { - if (handle_index != 0) { - /* TODO: Panic? */ - } - IpcParsedCommand r; - u64 cmd_id; - - - Result retval = ipcParse(&r); - if (R_SUCCEEDED(retval)) { - if (this->is_domain && (r.CommandType == IpcCommandType_Request || r.CommandType == IpcCommandType_RequestWithContext)) { - retval = ipcParseForDomain(&r); - if (!r.IsDomainMessage || r.ThisObjectId >= DOMAIN_ID_MAX) { - retval = 0xF601; - } else { - this->active_object = this->domain->get_domain_object(r.ThisObjectId); - } - } else { - this->active_object = this->service_object; - } - } - if (R_SUCCEEDED(retval)) { - cmd_id = ((u32 *)r.Raw)[2]; - } - if (R_SUCCEEDED(retval)) { - retval = this->handle_message(r); - } - - if (retval == RESULT_DEFER_SESSION) { - /* Session defer. */ - this->active_object.reset(); - this->set_deferred(true); - rc = retval; - } else if (retval == 0xF601) { - /* Session close. */ - this->active_object.reset(); - rc = retval; - } else { - if (R_SUCCEEDED(retval)) { - this->postprocess(r, cmd_id); - } - this->active_object.reset(); - rc = svcReplyAndReceive(&handle_index, &this->server_handle, 0, this->server_handle, 0); - if (rc == 0xEA01) { - rc = 0x0; - } - this->cleanup(); - } - } - - return rc; - } - - Result dispatch_control_command(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id) { - Result rc = 0xF601; - - /* TODO: Implement. */ - switch ((IpcControlCommand)cmd_id) { - case IpcCtrl_Cmd_ConvertCurrentObjectToDomain: - rc = WrapIpcCommandImpl<&ISession::ConvertCurrentObjectToDomain>(this, r, out_c, (u8 *)this->pointer_buffer.data(), pointer_buffer.size()); - break; - case IpcCtrl_Cmd_CopyFromCurrentDomain: - rc = WrapIpcCommandImpl<&ISession::CopyFromCurrentDomain>(this, r, out_c, (u8 *)this->pointer_buffer.data(), pointer_buffer.size()); - break; - case IpcCtrl_Cmd_CloneCurrentObject: - rc = WrapIpcCommandImpl<&ISession::CloneCurrentObject>(this, r, out_c, (u8 *)this->pointer_buffer.data(), pointer_buffer.size()); - break; - case IpcCtrl_Cmd_QueryPointerBufferSize: - rc = WrapIpcCommandImpl<&ISession::QueryPointerBufferSize>(this, r, out_c, (u8 *)this->pointer_buffer.data(), pointer_buffer.size()); - break; - case IpcCtrl_Cmd_CloneCurrentObjectEx: - rc = WrapIpcCommandImpl<&ISession::CloneCurrentObjectEx>(this, r, out_c, (u8 *)this->pointer_buffer.data(), pointer_buffer.size()); - break; - default: - break; - } - - return rc; - } - - /* Control commands. */ - std::tuple<Result> ConvertCurrentObjectToDomain() { - /* TODO */ - return {0xF601}; - } - std::tuple<Result> CopyFromCurrentDomain() { - /* TODO */ - return {0xF601}; - } - std::tuple<Result> CloneCurrentObject() { - /* TODO */ - return {0xF601}; - } - std::tuple<Result, u32> QueryPointerBufferSize() { - return {0x0, (u32)this->pointer_buffer.size()}; - } - std::tuple<Result> CloneCurrentObjectEx() { - /* TODO */ - return {0xF601}; - } -}; diff --git a/stratosphere/libstratosphere/include/stratosphere/iwaitable.hpp b/stratosphere/libstratosphere/include/stratosphere/iwaitable.hpp index 1fff3f874..175996067 100644 --- a/stratosphere/libstratosphere/include/stratosphere/iwaitable.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/iwaitable.hpp @@ -18,47 +18,61 @@ #include <switch.h> -#include "waitablemanagerbase.hpp" - -class WaitableManager; +#include "waitable_manager_base.hpp" +#include "hossynch.hpp" class IWaitable { private: u64 wait_priority = 0; bool is_deferred = false; - WaitableManagerBase *manager; + WaitableManagerBase *manager = nullptr; + protected: + HosMutex sig_lock; + bool is_signaled = false; public: - virtual ~IWaitable() { } + virtual ~IWaitable() = default; - virtual void handle_deferred() = 0; - virtual Handle get_handle() = 0; - virtual Result handle_signaled(u64 timeout) = 0; - - WaitableManager *get_manager() { - return (WaitableManager *)this->manager; + virtual void HandleDeferred() { + /* ... */ } - void set_manager(WaitableManagerBase *m) { + bool IsSignaled() { + std::scoped_lock<HosMutex> lock(this->sig_lock); + return this->is_signaled; + } + + virtual Handle GetHandle() = 0; + virtual Result HandleSignaled(u64 timeout) = 0; + + WaitableManagerBase *GetManager() { + return this->manager; + } + + void SetManager(WaitableManagerBase *m) { this->manager = m; } - void update_priority() { + void UpdatePriority() { if (manager) { - this->wait_priority = this->manager->get_priority(); + this->wait_priority = this->manager->GetNextPriority(); } } - bool get_deferred() { + bool IsDeferred() { return this->is_deferred; } - void set_deferred(bool d) { + void SetDeferred(bool d) { this->is_deferred = d; } - static bool compare(IWaitable *a, IWaitable *b) { - return (a->wait_priority < b->wait_priority) && !a->is_deferred; + static bool Compare(IWaitable *a, IWaitable *b) { + return (a->wait_priority < b->wait_priority) && !a->IsDeferred() && (a->GetHandle() != INVALID_HANDLE); + } + + void NotifyManagerSignaled() { + if (this->manager) { + this->manager->NotifySignaled(this); + } } }; - -#include "waitablemanager.hpp" \ No newline at end of file diff --git a/stratosphere/libstratosphere/include/stratosphere/mitm.hpp b/stratosphere/libstratosphere/include/stratosphere/mitm.hpp new file mode 100644 index 000000000..3d1b35259 --- /dev/null +++ b/stratosphere/libstratosphere/include/stratosphere/mitm.hpp @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include "mitm/sm_mitm.h" + +#include "ipc.hpp" + +#include "mitm/imitmserviceobject.hpp" +#include "mitm/mitm_query_service.hpp" +#include "mitm/mitm_session.hpp" +#include "mitm/mitm_server.hpp" \ No newline at end of file diff --git a/stratosphere/fs_mitm/source/imitmserviceobject.hpp b/stratosphere/libstratosphere/include/stratosphere/mitm/imitmserviceobject.hpp similarity index 56% rename from stratosphere/fs_mitm/source/imitmserviceobject.hpp rename to stratosphere/libstratosphere/include/stratosphere/mitm/imitmserviceobject.hpp index 8952903e9..e37ba152c 100644 --- a/stratosphere/fs_mitm/source/imitmserviceobject.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/mitm/imitmserviceobject.hpp @@ -20,26 +20,24 @@ #include <stratosphere.hpp> -#include "debug.hpp" - -class IMitMServiceObject : public IServiceObject { +class IMitmServiceObject : public IServiceObject { protected: - Service *forward_service; + std::shared_ptr<Service> forward_service; u64 process_id = 0; u64 title_id = 0; public: - IMitMServiceObject(Service *s) : forward_service(s) { - + IMitmServiceObject(std::shared_ptr<Service> s) : forward_service(s) {} + + virtual u64 GetTitleId() { + return this->title_id; } - static bool should_mitm(u64 pid, u64 tid) { - return true; + virtual u64 GetProcessId() { + return this->process_id; } + + static bool ShouldMitm(u64 pid, u64 tid); - virtual void clone_to(void *o) = 0; protected: - virtual ~IMitMServiceObject() = default; - virtual Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) = 0; - virtual void postprocess(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) = 0; - virtual Result handle_deferred() = 0; + virtual ~IMitmServiceObject() = default; }; diff --git a/stratosphere/libstratosphere/include/stratosphere/mitm/mitm_query_service.hpp b/stratosphere/libstratosphere/include/stratosphere/mitm/mitm_query_service.hpp new file mode 100644 index 000000000..621c4cfb6 --- /dev/null +++ b/stratosphere/libstratosphere/include/stratosphere/mitm/mitm_query_service.hpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once +#include <switch.h> +#include <stratosphere.hpp> + +enum MitmQueryServiceCommand { + MQS_Cmd_ShouldMitm = 65000, + MQS_Cmd_AssociatePidTid = 65001 +}; + +namespace MitmQueryUtils { + Result GetAssociatedTidForPid(u64 pid, u64 *tid); + + void AssociatePidToTid(u64 pid, u64 tid); +} + +template <typename T> +class MitmQueryService : public IServiceObject { + protected: + void ShouldMitm(Out<bool> should_mitm, u64 pid) { + should_mitm.SetValue(false); + u64 tid = 0; + if (R_SUCCEEDED(MitmQueryUtils::GetAssociatedTidForPid(pid, &tid))) { + should_mitm.SetValue(T::ShouldMitm(pid, tid)); + } + } + void AssociatePidToTid(u64 pid, u64 tid) { + MitmQueryUtils::AssociatePidToTid(pid, tid); + } + public: + DEFINE_SERVICE_DISPATCH_TABLE { + MakeServiceCommandMeta<MQS_Cmd_ShouldMitm, &MitmQueryService<T>::ShouldMitm>(), + MakeServiceCommandMeta<MQS_Cmd_AssociatePidTid, &MitmQueryService<T>::AssociatePidToTid>(), + }; +}; \ No newline at end of file diff --git a/stratosphere/libstratosphere/include/stratosphere/mitm/mitm_server.hpp b/stratosphere/libstratosphere/include/stratosphere/mitm/mitm_server.hpp new file mode 100644 index 000000000..113df8a55 --- /dev/null +++ b/stratosphere/libstratosphere/include/stratosphere/mitm/mitm_server.hpp @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once +#include <switch.h> + +#include "mitm_query_service.hpp" +#include "sm_mitm.h" +#include "mitm_session.hpp" + +template <typename T> +class MitmServer : public IWaitable { + static_assert(std::is_base_of<IMitmServiceObject, T>::value, "MitM Service Objects must derive from IMitmServiceObject"); + private: + Handle port_handle; + unsigned int max_sessions; + char mitm_name[9]; + + public: + MitmServer(Handle *out_query_h, const char *service_name, unsigned int max_s) : port_handle(0), max_sessions(max_s) { + Handle tmp_hnd; + Result rc = smMitMInitialize(); + if (R_FAILED(rc)) { + fatalSimple(rc); + } + + if (R_SUCCEEDED((rc = smGetServiceOriginal(&tmp_hnd, smEncodeName(service_name))))) { + svcCloseHandle(tmp_hnd); + } else { + fatalSimple(rc); + } + strncpy(mitm_name, service_name, 8); + mitm_name[8] = '\x00'; + if (R_FAILED((rc = smMitMInstall(&this->port_handle, out_query_h, mitm_name)))) { + fatalSimple(rc); + } + + smMitMExit(); + } + + virtual ~MitmServer() override { + if (this->port_handle) { + if (R_FAILED(smMitMUninstall(this->mitm_name))) { + std::abort(); + } + svcCloseHandle(port_handle); + } + } + + SessionManagerBase *GetSessionManager() { + return static_cast<SessionManagerBase *>(this->GetManager()); + } + + /* IWaitable */ + virtual Handle GetHandle() override { + return this->port_handle; + } + + virtual Result HandleSignaled(u64 timeout) override { + /* If this server's port was signaled, accept a new session. */ + Handle session_h; + Result rc = svcAcceptSession(&session_h, this->port_handle); + if (R_FAILED(rc)) { + return rc; + } + + /* Create a forward service for this instance. */ + std::shared_ptr<Service>forward_service(new Service(), [](Service *s) { + /* Custom deleter to ensure service is open as long as necessary. */ + serviceClose(s); + delete s; + }); + + rc = smMitMInitialize(); + if (R_FAILED(rc)) { + fatalSimple(rc); + } + + if (R_FAILED(smMitMGetService(forward_service.get(), mitm_name))) { + /* TODO: Panic. */ + } + + smMitMExit(); + + this->GetSessionManager()->AddWaitable(new MitmSession(session_h, forward_service, std::make_shared<T>(forward_service))); + return 0; + } + +}; + +template<typename T> +static void AddMitmServerToManager(SessionManagerBase *manager, const char *srv_name, unsigned int max_sessions) { + Handle query_h; + auto *srv = new MitmServer<T>(&query_h, srv_name, max_sessions); + manager->AddSession(query_h, std::move(ServiceObjectHolder(std::move(std::make_shared<MitmQueryService<T>>())))); + manager->AddWaitable(srv); +} + + diff --git a/stratosphere/libstratosphere/include/stratosphere/mitm/mitm_session.hpp b/stratosphere/libstratosphere/include/stratosphere/mitm/mitm_session.hpp new file mode 100644 index 000000000..f4df504f1 --- /dev/null +++ b/stratosphere/libstratosphere/include/stratosphere/mitm/mitm_session.hpp @@ -0,0 +1,314 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once +#include <switch.h> +#include <stratosphere.hpp> +#include "imitmserviceobject.hpp" + +#include "mitm_query_service.hpp" + +class MitmSession final : public ServiceSession { + private: + /* This will be for the actual session. */ + std::shared_ptr<Service> forward_service; + + /* Store a handler for the service. */ + void (*service_post_process_handler)(IMitmServiceObject *, IpcResponseContext *); + + /* For cleanup usage. */ + u32 num_fwd_copy_hnds = 0; + Handle fwd_copy_hnds[8]; + public: + template<typename T> + MitmSession(Handle s_h, std::shared_ptr<Service> fs, std::shared_ptr<T> srv) : ServiceSession(s_h) { + this->forward_service = std::move(fs); + this->obj_holder = std::move(ServiceObjectHolder(std::move(srv))); + + this->service_post_process_handler = T::PostProcess; + + size_t pbs; + if (R_FAILED(ipcQueryPointerBufferSize(forward_service->handle, &pbs))) { + std::abort(); + } + this->pointer_buffer.resize(pbs); + this->control_holder.Reset(); + this->control_holder = std::move(ServiceObjectHolder(std::move(std::make_shared<IMitmHipcControlService>(this)))); + } + + MitmSession(Handle s_h, std::shared_ptr<Service> fs, ServiceObjectHolder &&h, void (*pph)(IMitmServiceObject *, IpcResponseContext *)) : ServiceSession(s_h) { + this->session_handle = s_h; + this->forward_service = std::move(fs); + this->obj_holder = std::move(h); + + this->service_post_process_handler = pph; + + size_t pbs; + if (R_FAILED(ipcQueryPointerBufferSize(forward_service->handle, &pbs))) { + std::abort(); + } + this->pointer_buffer.resize(pbs); + this->control_holder.Reset(); + this->control_holder = std::move(ServiceObjectHolder(std::move(std::make_shared<IMitmHipcControlService>(this)))); + } + + virtual void PreProcessRequest(IpcResponseContext *ctx) override { + u32 *cmdbuf = (u32 *)armGetTls(); + u32 *backup_cmdbuf = (u32 *)this->backup_tls; + if (ctx->request.HasPid) { + /* [ctrl 0] [ctrl 1] [handle desc 0] [pid low] [pid high] */ + cmdbuf[4] = 0xFFFE0000UL | (cmdbuf[4] & 0xFFFFUL); + backup_cmdbuf[4] = cmdbuf[4]; + } + } + + Result ForwardRequest(IpcResponseContext *ctx) { + IpcParsedCommand r; + Result rc = serviceIpcDispatch(this->forward_service.get()); + if (R_SUCCEEDED(rc)) { + if (ctx->request.IsDomainRequest) { + /* We never work with out object ids, so this should be fine. */ + ipcParseDomainResponse(&r, 0); + } else { + ipcParse(&r); + } + + struct { + u64 magic; + u64 result; + } *resp = (decltype(resp))r.Raw; + + rc = resp->result; + + for (unsigned int i = 0; i < r.NumHandles; i++) { + if (r.WasHandleCopied[i]) { + this->fwd_copy_hnds[num_fwd_copy_hnds++] = r.Handles[i]; + } + } + } + return rc; + } + + virtual Result GetResponse(IpcResponseContext *ctx) { + Result rc = 0xF601; + FirmwareVersion fw = GetRuntimeFirmwareVersion(); + + const ServiceCommandMeta *dispatch_table = ctx->obj_holder->GetDispatchTable(); + size_t entry_count = ctx->obj_holder->GetDispatchTableEntryCount(); + + if (IsDomainObject(ctx->obj_holder)) { + switch (ctx->request.InMessageType) { + case DomainMessageType_Invalid: + return 0xF601; + case DomainMessageType_Close: + rc = ForwardRequest(ctx); + if (R_SUCCEEDED(rc)) { + ctx->obj_holder->GetServiceObject<IDomainObject>()->FreeObject(ctx->request.InThisObjectId); + } + if (R_SUCCEEDED(rc) && ctx->request.InThisObjectId == serviceGetObjectId(this->forward_service.get())) { + /* If we're not longer MitMing anything, we don't need a mitm session. */ + this->Reply(); + this->GetSessionManager()->AddSession(this->session_handle, std::move(this->obj_holder)); + this->session_handle = 0; + return 0xF601; + } + return rc; + case DomainMessageType_SendMessage: + { + auto sub_obj = ctx->obj_holder->GetServiceObject<IDomainObject>()->GetObject(ctx->request.InThisObjectId); + if (sub_obj == nullptr) { + rc = ForwardRequest(ctx); + return rc; + } + dispatch_table = sub_obj->GetDispatchTable(); + entry_count = sub_obj->GetDispatchTableEntryCount(); + } + } + } + + bool found_entry = false; + + for (size_t i = 0; i < entry_count; i++) { + if (ctx->cmd_id == dispatch_table[i].cmd_id && dispatch_table[i].fw_low <= fw && fw <= dispatch_table[i].fw_high) { + rc = dispatch_table[i].handler(ctx); + found_entry = true; + break; + } + } + + if (!found_entry) { + memcpy(armGetTls(), this->backup_tls, sizeof(this->backup_tls)); + rc = ForwardRequest(ctx); + } + + return rc; + } + + virtual void PostProcessResponse(IpcResponseContext *ctx) override { + if ((ctx->cmd_type == IpcCommandType_Request || ctx->cmd_type == IpcCommandType_RequestWithContext) && R_SUCCEEDED(ctx->rc)) { + if (!IsDomainObject(ctx->obj_holder) || ctx->request.InThisObjectId == serviceGetObjectId(this->forward_service.get())) { + IMitmServiceObject *obj; + if (!IsDomainObject(ctx->obj_holder)) { + obj = ctx->obj_holder->GetServiceObjectUnsafe<IMitmServiceObject>(); + } else { + obj = ctx->obj_holder->GetServiceObject<IDomainObject>()->GetObject(ctx->request.InThisObjectId)->GetServiceObjectUnsafe<IMitmServiceObject>(); + } + this->service_post_process_handler(obj, ctx); + } + } + } + + virtual void CleanupResponse(IpcResponseContext *ctx) override { + /* Cleanup tls backup. */ + std::memset(this->backup_tls, 0, sizeof(this->backup_tls)); + + /* Clean up copy handles. */ + for (unsigned int i = 0; i < ctx->request.NumHandles; i++) { + if (ctx->request.WasHandleCopied[i]) { + svcCloseHandle(ctx->request.Handles[i]); + } + } + for (unsigned int i = 0; i < this->num_fwd_copy_hnds; i++) { + svcCloseHandle(this->fwd_copy_hnds[i]); + } + this->num_fwd_copy_hnds = 0; + } + + public: + class IMitmHipcControlService : public IServiceObject { + private: + MitmSession *session; + public: + explicit IMitmHipcControlService(MitmSession *s) : session(s) { + + } + + virtual ~IMitmHipcControlService() override { } + + public: + Result ConvertCurrentObjectToDomain(Out<u32> object_id) { + if (IsDomainObject(this->session->obj_holder)) { + return 0xF601; + } + + Result rc = serviceConvertToDomain(this->session->forward_service.get()); + if (R_FAILED(rc)) { + return rc; + } + + u32 expected_id = serviceGetObjectId(this->session->forward_service.get()); + + /* Allocate new domain. */ + auto new_domain = this->session->GetDomainManager()->AllocateDomain(); + if (new_domain == nullptr) { + /* If our domains mismatch, we're in trouble. */ + return 0xF601; + } + + /* Reserve the expected object in the domain for our session. */ + if (R_FAILED(new_domain->ReserveSpecificObject(expected_id))) { + return 0xF601; + } + new_domain->SetObject(expected_id, std::move(this->session->obj_holder)); + this->session->obj_holder = std::move(ServiceObjectHolder(std::move(new_domain))); + + /* Return the object id. */ + object_id.SetValue(expected_id); + return 0; + } + + Result CopyFromCurrentDomain(Out<MovedHandle> out_h, u32 id) { + auto domain = this->session->obj_holder.GetServiceObject<IDomainObject>(); + if (domain == nullptr) { + return 0x3D60B; + } + + + auto object = domain->GetObject(id); + if (object == nullptr) { + /* Forward onwards. */ + u32 *buf = (u32 *)armGetTls(); + buf[0] = IpcCommandType_Control; + buf[1] = 0xA; + buf[4] = SFCI_MAGIC; + buf[5] = 0; + buf[6] = 1; + buf[7] = 0; + buf[8] = id; + buf[9] = 0; + Result rc = ipcDispatch(this->session->forward_service->handle); + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + ipcParse(&r); + struct { + u64 magic; + u64 result; + } *raw = (decltype(raw))r.Raw; + rc = raw->result; + + if (R_SUCCEEDED(rc)) { + out_h.SetValue(r.Handles[0]); + this->session->fwd_copy_hnds[this->session->num_fwd_copy_hnds++] = r.Handles[0]; + } + } + return rc; + } + + Handle server_h, client_h; + if (R_FAILED(SessionManagerBase::CreateSessionHandles(&server_h, &client_h))) { + /* N aborts here. Should we error code? */ + std::abort(); + } + out_h.SetValue(client_h); + + if (id == serviceGetObjectId(this->session->forward_service.get())) { + this->session->GetSessionManager()->AddWaitable(new MitmSession(server_h, this->session->forward_service, std::move(object->Clone()), this->session->service_post_process_handler)); + } else { + this->session->GetSessionManager()->AddSession(server_h, std::move(object->Clone())); + } + return 0; + } + + void CloneCurrentObject(Out<MovedHandle> out_h) { + Handle server_h, client_h; + if (R_FAILED(SessionManagerBase::CreateSessionHandles(&server_h, &client_h))) { + /* N aborts here. Should we error code? */ + std::abort(); + } + + this->session->GetSessionManager()->AddWaitable(new MitmSession(server_h, this->session->forward_service, std::move(this->session->obj_holder.Clone()), this->session->service_post_process_handler)); + out_h.SetValue(client_h); + } + + void QueryPointerBufferSize(Out<u16> size) { + size.SetValue(this->session->pointer_buffer.size()); + } + + void CloneCurrentObjectEx(Out<MovedHandle> out_h, u32 which) { + /* TODO: Figure out what this u32 controls. */ + return CloneCurrentObject(out_h); + } + + public: + DEFINE_SERVICE_DISPATCH_TABLE { + MakeServiceCommandMeta<HipcControlCommand_ConvertCurrentObjectToDomain, &MitmSession::IMitmHipcControlService::ConvertCurrentObjectToDomain>(), + MakeServiceCommandMeta<HipcControlCommand_CopyFromCurrentDomain, &MitmSession::IMitmHipcControlService::CopyFromCurrentDomain>(), + MakeServiceCommandMeta<HipcControlCommand_CloneCurrentObject, &MitmSession::IMitmHipcControlService::CloneCurrentObject>(), + MakeServiceCommandMeta<HipcControlCommand_QueryPointerBufferSize, &MitmSession::IMitmHipcControlService::QueryPointerBufferSize>(), + MakeServiceCommandMeta<HipcControlCommand_CloneCurrentObjectEx, &MitmSession::IMitmHipcControlService::CloneCurrentObjectEx>(), + }; + }; +}; diff --git a/stratosphere/fs_mitm/source/sm_mitm.h b/stratosphere/libstratosphere/include/stratosphere/mitm/sm_mitm.h similarity index 91% rename from stratosphere/fs_mitm/source/sm_mitm.h rename to stratosphere/libstratosphere/include/stratosphere/mitm/sm_mitm.h index 302153cd9..4b521c88c 100644 --- a/stratosphere/fs_mitm/source/sm_mitm.h +++ b/stratosphere/libstratosphere/include/stratosphere/mitm/sm_mitm.h @@ -17,6 +17,8 @@ Result smMitMGetService(Service* service_out, const char *name); Result smMitMInstall(Handle *handle_out, Handle *query_out, const char *name); Result smMitMUninstall(const char *name); +Result smMitMIsRegistered(const char *name); + #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/stratosphere/libstratosphere/include/stratosphere/multithreadedwaitablemanager.hpp b/stratosphere/libstratosphere/include/stratosphere/multithreadedwaitablemanager.hpp deleted file mode 100644 index d223000db..000000000 --- a/stratosphere/libstratosphere/include/stratosphere/multithreadedwaitablemanager.hpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2018 Atmosphère-NX - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#pragma once -#include <switch.h> -#include <vector> - -#include "waitablemanager.hpp" -#include "systemevent.hpp" - -class MultiThreadedWaitableManager : public WaitableManager { - protected: - u32 num_threads; - Thread *threads; - HosMutex get_waitable_lock; - SystemEvent *new_waitable_event; - public: - MultiThreadedWaitableManager(u32 n, u64 t, u32 ss = 0x8000) : WaitableManager(t), num_threads(n-1) { - u32 prio; - u32 cpuid = svcGetCurrentProcessorNumber(); - Result rc; - threads = new Thread[num_threads]; - if (R_FAILED((rc = svcGetThreadPriority(&prio, CUR_THREAD_HANDLE)))) { - fatalSimple(rc); - } - for (unsigned int i = 0; i < num_threads; i++) { - threads[i] = {0}; - threadCreate(&threads[i], &MultiThreadedWaitableManager::thread_func, this, ss, prio, cpuid); - } - new_waitable_event = new SystemEvent(this, &MultiThreadedWaitableManager::add_waitable_callback); - this->waitables.push_back(new_waitable_event); - } - ~MultiThreadedWaitableManager() override { - /* TODO: Exit the threads? */ - } - - IWaitable *get_waitable(); - - void add_waitable(IWaitable *waitable) override; - void process() override; - void process_until_timeout() override; - - static Result add_waitable_callback(void *this_ptr, Handle *handles, size_t num_handles, u64 timeout); - static void thread_func(void *this_ptr); -}; \ No newline at end of file diff --git a/stratosphere/libstratosphere/include/stratosphere/scope_guard.hpp b/stratosphere/libstratosphere/include/stratosphere/scope_guard.hpp new file mode 100644 index 000000000..fa611a518 --- /dev/null +++ b/stratosphere/libstratosphere/include/stratosphere/scope_guard.hpp @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + /* Scope guard logic lovingly taken from Andrei Alexandrescu's "Systemic Error Handling in C++" */ +#pragma once + +#include <utility> + +template<class F> +class ScopeGuard { +private: + F f; + bool active; +public: + ScopeGuard(F f) : f(std::move(f)), active(true) { } + ~ScopeGuard() { if (active) { f(); } } + void Cancel() { active = false; } + + ScopeGuard() = delete; + ScopeGuard(const ScopeGuard &) = delete; + ScopeGuard& operator=(const ScopeGuard&) = delete; + ScopeGuard(ScopeGuard&& rhs) : f(std::move(rhs.f)), active(rhs.active) { + rhs.Cancel(); + } +}; + +template<class F> +ScopeGuard<F> MakeScopeGuard(F f) { + return ScopeGuard<F>(std::move(f)); +} + +enum class ScopeGuardOnExit {}; + +template <typename F> +ScopeGuard<F> operator+(ScopeGuardOnExit, F&& f) { + return ScopeGuard<F>(std::forward<F>(f)); +} + +#define CONCATENATE_IMPL(S1, s2) s1##s2 +#define CONCATENATE(s1, s2) CONCATENATE_IMPL(s1, s2) + +#ifdef __COUNTER__ +#define ANONYMOUS_VARIABLE(pref) CONCATENATE(pref, __COUNTER__) +#else +#define ANONYMOUS_VARIABLE(pref) CONCATENATE(pref, __LINE__) +#endif + +#define ON_SCOPE_EXIT auto ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE_) = ScopeGuardOnExit() + [&]() \ No newline at end of file diff --git a/stratosphere/libstratosphere/include/stratosphere/iserver.hpp b/stratosphere/libstratosphere/include/stratosphere/servers.hpp similarity index 54% rename from stratosphere/libstratosphere/include/stratosphere/iserver.hpp rename to stratosphere/libstratosphere/include/stratosphere/servers.hpp index 1b32ebcd5..7771157f1 100644 --- a/stratosphere/libstratosphere/include/stratosphere/iserver.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/servers.hpp @@ -16,48 +16,36 @@ #pragma once #include <switch.h> -#include <algorithm> -#include <type_traits> -#include "iserviceobject.hpp" #include "iwaitable.hpp" -#include "isession.hpp" +#include "ipc.hpp" -template <typename T> -class ISession; - -template <typename T> +template<typename T> class IServer : public IWaitable { static_assert(std::is_base_of<IServiceObject, T>::value, "Service Objects must derive from IServiceObject"); protected: Handle port_handle; unsigned int max_sessions; - bool supports_domains; public: - IServer(const char *service_name, unsigned int max_s, bool s_d = false) : max_sessions(max_s), supports_domains(s_d) { - - } + IServer(unsigned int max_s) : port_handle(0), max_sessions(max_s) { } virtual ~IServer() { if (port_handle) { svcCloseHandle(port_handle); } } + + SessionManagerBase *GetSessionManager() { + return static_cast<SessionManagerBase *>(this->GetManager()); + } - virtual ISession<T> *get_new_session(Handle session_h) = 0; - /* IWaitable */ - virtual Handle get_handle() { + virtual Handle GetHandle() override { return this->port_handle; } - - virtual void handle_deferred() { - /* TODO: Panic, because we can never defer a server. */ - } - - virtual Result handle_signaled(u64 timeout) { + virtual Result HandleSignaled(u64 timeout) override { /* If this server's port was signaled, accept a new session. */ Handle session_h; Result rc = svcAcceptSession(&session_h, this->port_handle); @@ -65,7 +53,35 @@ class IServer : public IWaitable { return rc; } - this->get_manager()->add_waitable(this->get_new_session(session_h)); + this->GetSessionManager()->AddSession(session_h, std::move(ServiceObjectHolder(std::move(std::make_shared<T>())))); return 0; } }; + +template <typename T> +class ServiceServer : public IServer<T> { + public: + ServiceServer(const char *service_name, unsigned int max_s) : IServer<T>(max_s) { + if (R_FAILED(smRegisterService(&this->port_handle, service_name, false, this->max_sessions))) { + /* TODO: Panic. */ + } + } +}; + +template <typename T> +class ExistingPortServer : public IServer<T> { + public: + ExistingPortServer(Handle port_h, unsigned int max_s) : IServer<T>(max_s) { + this->port_handle = port_h; + } +}; + +template <typename T> +class ManagedPortServer : public IServer<T> { + public: + ManagedPortServer(const char *service_name, unsigned int max_s) : IServer<T>(max_s) { + if (R_FAILED(svcManageNamedPort(&this->port_handle, service_name, this->max_sessions))) { + /* TODO: panic */ + } + } +}; \ No newline at end of file diff --git a/stratosphere/libstratosphere/include/stratosphere/services.hpp b/stratosphere/libstratosphere/include/stratosphere/services.hpp new file mode 100644 index 000000000..7db234698 --- /dev/null +++ b/stratosphere/libstratosphere/include/stratosphere/services.hpp @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include "ipc.hpp" + +#include "services/smm_ams.h" \ No newline at end of file diff --git a/stratosphere/fs_mitm/source/fsmitm_worker.hpp b/stratosphere/libstratosphere/include/stratosphere/services/smm_ams.h similarity index 71% rename from stratosphere/fs_mitm/source/fsmitm_worker.hpp rename to stratosphere/libstratosphere/include/stratosphere/services/smm_ams.h index 68c5ea4e4..85973929f 100644 --- a/stratosphere/fs_mitm/source/fsmitm_worker.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/services/smm_ams.h @@ -16,12 +16,16 @@ #pragma once #include <switch.h> -#include <stratosphere.hpp> -class FsMitMWorker { - private: - static Result AddWaitableCallback(void *arg, Handle *handles, size_t num_handles, u64 timeout); - public: - static void Main(void *arg); - static void AddWaitable(IWaitable *waitable); -}; \ No newline at end of file +#ifdef __cplusplus +extern "C" { +#endif + +Result smManagerAmsInitialize(void); +void smManagerAmsExit(void); + +Result smManagerAmsEndInitialDefers(void); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/stratosphere/libstratosphere/include/stratosphere/serviceserver.hpp b/stratosphere/libstratosphere/include/stratosphere/serviceserver.hpp deleted file mode 100644 index f796beb26..000000000 --- a/stratosphere/libstratosphere/include/stratosphere/serviceserver.hpp +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2018 Atmosphère-NX - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#pragma once -#include <switch.h> -#include "iserver.hpp" - -template <typename T> -class ServiceServer : public IServer<T> { - public: - ServiceServer(const char *service_name, unsigned int max_s, bool s_d = false) : IServer<T>(service_name, max_s, s_d) { - if (R_FAILED(smRegisterService(&this->port_handle, service_name, false, this->max_sessions))) { - /* TODO: Panic. */ - } - } - - ISession<T> *get_new_session(Handle session_h) override { - return new ServiceSession<T>(this, session_h, 0); - } -}; \ No newline at end of file diff --git a/stratosphere/libstratosphere/include/stratosphere/systemevent.hpp b/stratosphere/libstratosphere/include/stratosphere/systemevent.hpp deleted file mode 100644 index a22254f67..000000000 --- a/stratosphere/libstratosphere/include/stratosphere/systemevent.hpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2018 Atmosphère-NX - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#pragma once -#include <switch.h> - -#include "iwaitable.hpp" -#include "ievent.hpp" - -#define SYSTEMEVENT_INDEX_WAITHANDLE 0 -#define SYSTEMEVENT_INDEX_SGNLHANDLE 1 - -class SystemEvent final : public IEvent { - public: - SystemEvent(void *a, EventCallback callback) : IEvent(0, a, callback) { - Handle wait_h; - Handle sig_h; - if (R_FAILED(svcCreateEvent(&sig_h, &wait_h))) { - /* TODO: Panic. */ - } - - this->handles.push_back(wait_h); - this->handles.push_back(sig_h); - } - - Result signal_event() override { - return svcSignalEvent(this->handles[SYSTEMEVENT_INDEX_SGNLHANDLE]); - } -}; diff --git a/stratosphere/libstratosphere/include/stratosphere/version_check.hpp b/stratosphere/libstratosphere/include/stratosphere/version_check.hpp new file mode 100644 index 000000000..336ea837c --- /dev/null +++ b/stratosphere/libstratosphere/include/stratosphere/version_check.hpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once +#include <switch.h> +#include <atmosphere/version.h> + +static inline void GetAtmosphereApiVersion(u32 *major, u32 *minor, u32 *micro, u32 *target_fw, u32 *mkey_rev) { + if (R_FAILED(splInitialize())) { + fatalSimple(0xCAFE << 4 | 0xD); + } + + /* Check for exosphere API compatibility. */ + u64 exosphere_cfg; + if (R_FAILED(splGetConfig((SplConfigItem)65000, &exosphere_cfg))) { + fatalSimple(0xCAFE << 4 | 0xE); + } + + if (mkey_rev) { + *mkey_rev = (u32)((exosphere_cfg >> 0x00) & 0xFF); + } + + if (target_fw) { + *target_fw = (u32)((exosphere_cfg >> 0x08) & 0xFF); + } + + if (micro) { + *micro = (u32)((exosphere_cfg >> 0x10) & 0xFF); + } + + if (minor) { + *minor = (u32)((exosphere_cfg >> 0x18) & 0xFF); + } + + if (major) { + *major = (u32)((exosphere_cfg >> 0x20) & 0xFF); + } + + splExit(); +} + +static inline u32 MakeAtmosphereVersion(u32 major, u32 minor, u32 micro) { + return (major << 16) | (minor << 8) | micro; +} + +static inline void CheckAtmosphereVersion() { + u32 major, minor, micro; + GetAtmosphereApiVersion(&major, &minor, µ, nullptr, nullptr); + + if (MakeAtmosphereVersion(major, minor, micro) < MakeAtmosphereVersion(ATMOSPHERE_RELEASE_VERSION_MAJOR, ATMOSPHERE_RELEASE_VERSION_MINOR, ATMOSPHERE_RELEASE_VERSION_MICRO)) { + fatalSimple(0xCAFE << 4 | 0xF); + } +} \ No newline at end of file diff --git a/stratosphere/libstratosphere/include/stratosphere/waitable_manager.hpp b/stratosphere/libstratosphere/include/stratosphere/waitable_manager.hpp new file mode 100644 index 000000000..099c8dfbd --- /dev/null +++ b/stratosphere/libstratosphere/include/stratosphere/waitable_manager.hpp @@ -0,0 +1,336 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include <switch.h> +#include <memory> + +#include "../meta_tools.hpp" + +#include "waitable_manager_base.hpp" +#include "event.hpp" +#include "ipc.hpp" +#include "servers.hpp" + +#include "scope_guard.hpp" + +static inline Handle GetCurrentThreadHandle() { + /* TODO: Wait for libnx to add a way for me to call getThreadVars() */ + return *((Handle *)((uintptr_t)armGetTls() + 0x1E4)); +} + +struct DefaultManagerOptions { + static constexpr size_t PointerBufferSize = 0; + static constexpr size_t MaxDomains = 0; + static constexpr size_t MaxDomainObjects = 0; +}; + +struct DomainEntry { + ServiceObjectHolder obj_holder; + IDomainObject *owner = nullptr; +}; + +template<typename ManagerOptions = DefaultManagerOptions> +class WaitableManager : public SessionManagerBase { + private: + /* Domain Manager */ + HosMutex domain_lock; + std::array<std::weak_ptr<IDomainObject>, ManagerOptions::MaxDomains> domains; + std::array<bool, ManagerOptions::MaxDomains> is_domain_allocated; + std::array<DomainEntry, ManagerOptions::MaxDomainObjects> domain_objects; + + /* Waitable Manager */ + std::vector<IWaitable *> to_add_waitables; + std::vector<IWaitable *> waitables; + u32 num_threads; + Thread *threads; + HosMutex process_lock; + HosMutex signal_lock; + HosMutex add_lock; + IEvent *new_waitable_event = nullptr; + + IWaitable *next_signaled = nullptr; + Handle cur_thread_handle = INVALID_HANDLE; + public: + WaitableManager(u32 n, u32 ss = 0x8000) : num_threads(n-1) { + u32 prio; + u32 cpuid = svcGetCurrentProcessorNumber(); + Result rc; + threads = new Thread[num_threads]; + if (num_threads) { + if (R_FAILED((rc = svcGetThreadPriority(&prio, CUR_THREAD_HANDLE)))) { + fatalSimple(rc); + } + for (unsigned int i = 0; i < num_threads; i++) { + threads[i] = {0}; + threadCreate(&threads[i], &WaitableManager::ProcessLoop, this, ss, prio, cpuid); + } + } + new_waitable_event = CreateSystemEvent([](u64 timeout) { return 0; }, true); + } + + ~WaitableManager() override { + /* This should call the destructor for every waitable. */ + std::for_each(waitables.begin(), waitables.end(), std::default_delete<IWaitable>{}); + + /* TODO: Exit the threads? */ + } + + virtual void AddWaitable(IWaitable *w) override { + std::scoped_lock lk{this->add_lock}; + this->to_add_waitables.push_back(w); + w->SetManager(this); + this->new_waitable_event->Signal(); + } + + virtual void NotifySignaled(IWaitable *w) override { + std::scoped_lock lk{this->signal_lock}; + if (this->next_signaled == nullptr && w != this->new_waitable_event) { + this->next_signaled = w; + } + svcCancelSynchronization(this->cur_thread_handle); + } + + virtual void Process() override { + /* Add initial set of waitables. */ + AddWaitablesInternal(); + + Result rc; + for (unsigned int i = 0; i < num_threads; i++) { + if (R_FAILED((rc = threadStart(&threads[i])))) { + fatalSimple(rc); + } + } + + ProcessLoop(this); + } + private: + static void ProcessLoop(void *t) { + WaitableManager *this_ptr = (WaitableManager *)t; + while (true) { + IWaitable *w = this_ptr->GetWaitable(); + if (w) { + Result rc = w->HandleSignaled(0); + if (rc == 0xF601) { + /* Close! */ + delete w; + } else { + this_ptr->AddWaitable(w); + } + } + + } + } + + IWaitable *GetWaitable() { + std::scoped_lock lk{this->process_lock}; + this->next_signaled = nullptr; + IWaitable *result = nullptr; + + if (this->new_waitable_event->IsSignaled()) { + AddWaitablesInternal(); + } + + this->cur_thread_handle = GetCurrentThreadHandle(); + ON_SCOPE_EXIT { + this->cur_thread_handle = INVALID_HANDLE; + }; + + /* First, see if anything's already signaled. */ + for (auto &w : this->waitables) { + if (w->IsSignaled()) { + result = w; + } + } + + /* It's possible somebody signaled us while we were iterating. */ + { + std::scoped_lock lk{this->signal_lock}; + if (this->next_signaled != nullptr) result = this->next_signaled; + } + + if (result == nullptr) { + std::vector<Handle> handles; + std::vector<IWaitable *> wait_list; + + int handle_index = 0; + Result rc; + while (result == nullptr) { + /* Sort waitables by priority. */ + std::sort(this->waitables.begin(), this->waitables.end(), IWaitable::Compare); + + /* Copy out handles. */ + handles.resize(this->waitables.size() + 1); + wait_list.resize(this->waitables.size() + 1); + handles[0] = this->new_waitable_event->GetHandle(); + wait_list[0] = this->new_waitable_event; + unsigned int num_handles = 1; + for (unsigned int i = 0; i < this->waitables.size(); i++) { + Handle h = this->waitables[i]->GetHandle(); + if (h != INVALID_HANDLE) { + wait_list[num_handles] = this->waitables[i]; + handles[num_handles++] = h; + } + } + + + /* Do deferred callback for each waitable. This has to happen before we wait on anything else. */ + for (auto & waitable : this->waitables) { + if (waitable->IsDeferred()) { + waitable->HandleDeferred(); + } + } + + /* Wait forever. */ + rc = svcWaitSynchronization(&handle_index, handles.data(), num_handles, U64_MAX); + + IWaitable *w = wait_list[handle_index]; + size_t w_ind = std::distance(this->waitables.begin(), std::find(this->waitables.begin(), this->waitables.end(), w)); + + if (R_SUCCEEDED(rc)) { + if (handle_index == 0) { + AddWaitablesInternal(); + continue; + } + std::for_each(waitables.begin(), waitables.begin() + w_ind, std::mem_fn(&IWaitable::UpdatePriority)); + result = w; + } else if (rc == 0xEA01) { + /* Timeout: Just update priorities. */ + std::for_each(waitables.begin(), waitables.end(), std::mem_fn(&IWaitable::UpdatePriority)); + } else if (rc == 0xEC01) { + /* svcCancelSynchronization was called. */ + std::scoped_lock lk{this->signal_lock}; + if (this->next_signaled != nullptr) result = this->next_signaled; + } else if (rc != 0xF601 && rc != 0xE401) { + std::abort(); + } else { + if (handle_index == 0) { + std::abort(); + } + + this->waitables.erase(this->waitables.begin() + w_ind); + std::for_each(waitables.begin(), waitables.begin() + w_ind - 1, std::mem_fn(&IWaitable::UpdatePriority)); + delete w; + } + } + } + + this->waitables.erase(std::remove_if(this->waitables.begin(), this->waitables.end(), [&](IWaitable *w) { return w == result; }), this->waitables.end()); + + return result; + } + + void AddWaitablesInternal() { + { + std::scoped_lock lk{this->add_lock}; + this->waitables.insert(this->waitables.end(), this->to_add_waitables.begin(), this->to_add_waitables.end()); + this->to_add_waitables.clear(); + this->new_waitable_event->Clear(); + } + } + /* Session Manager */ + public: + virtual void AddSession(Handle server_h, ServiceObjectHolder &&service) override { + this->AddWaitable(new ServiceSession(server_h, ManagerOptions::PointerBufferSize, std::move(service))); + } + + /* Domain Manager */ + public: + virtual std::shared_ptr<IDomainObject> AllocateDomain() override { + std::scoped_lock lk{this->domain_lock}; + for (size_t i = 0; i < ManagerOptions::MaxDomains; i++) { + if (!this->is_domain_allocated[i]) { + auto new_domain = std::make_shared<IDomainObject>(this); + this->domains[i] = new_domain; + this->is_domain_allocated[i] = true; + return new_domain; + } + } + return nullptr; + } + + void FreeDomain(IDomainObject *domain) override { + std::scoped_lock lk{this->domain_lock}; + for (size_t i = 0; i < ManagerOptions::MaxDomainObjects; i++) { + FreeObject(domain, i+1); + } + for (size_t i = 0; i < ManagerOptions::MaxDomains; i++) { + auto observe = this->domains[i].lock(); + if (observe.get() == domain) { + this->is_domain_allocated[i] = false; + break; + } + } + } + + virtual Result ReserveObject(IDomainObject *domain, u32 *out_object_id) override { + std::scoped_lock lk{this->domain_lock}; + for (size_t i = 0; i < ManagerOptions::MaxDomainObjects; i++) { + if (this->domain_objects[i].owner == nullptr) { + this->domain_objects[i].owner = domain; + *out_object_id = i+1; + return 0; + } + } + return 0x25A0A; + } + + virtual Result ReserveSpecificObject(IDomainObject *domain, u32 object_id) override { + std::scoped_lock lk{this->domain_lock}; + if (this->domain_objects[object_id-1].owner == nullptr) { + this->domain_objects[object_id-1].owner = domain; + return 0; + } + return 0x25A0A; + } + + virtual void SetObject(IDomainObject *domain, u32 object_id, ServiceObjectHolder&& holder) override { + std::scoped_lock lk{this->domain_lock}; + if (this->domain_objects[object_id-1].owner == domain) { + this->domain_objects[object_id-1].obj_holder = std::move(holder); + } + } + + virtual ServiceObjectHolder *GetObject(IDomainObject *domain, u32 object_id) override { + std::scoped_lock lk{this->domain_lock}; + if (this->domain_objects[object_id-1].owner == domain) { + return &this->domain_objects[object_id-1].obj_holder; + } + return nullptr; + } + + virtual Result FreeObject(IDomainObject *domain, u32 object_id) override { + std::scoped_lock lk{this->domain_lock}; + if (this->domain_objects[object_id-1].owner == domain) { + this->domain_objects[object_id-1].obj_holder.Reset(); + this->domain_objects[object_id-1].owner = nullptr; + return 0x0; + } + return 0x3D80B; + } + + virtual Result ForceFreeObject(u32 object_id) override { + std::scoped_lock lk{this->domain_lock}; + if (this->domain_objects[object_id-1].owner != nullptr) { + this->domain_objects[object_id-1].obj_holder.Reset(); + this->domain_objects[object_id-1].owner = nullptr; + return 0x0; + } + return 0x3D80B; + } +}; + diff --git a/stratosphere/libstratosphere/include/stratosphere/waitablemanagerbase.hpp b/stratosphere/libstratosphere/include/stratosphere/waitable_manager_base.hpp similarity index 80% rename from stratosphere/libstratosphere/include/stratosphere/waitablemanagerbase.hpp rename to stratosphere/libstratosphere/include/stratosphere/waitable_manager_base.hpp index 247592a4e..777403b21 100644 --- a/stratosphere/libstratosphere/include/stratosphere/waitablemanagerbase.hpp +++ b/stratosphere/libstratosphere/include/stratosphere/waitable_manager_base.hpp @@ -15,9 +15,9 @@ */ #pragma once -#include <switch.h> #include <atomic> -#include <vector> + +class IWaitable; class WaitableManagerBase { std::atomic<u64> cur_priority = 0; @@ -25,7 +25,13 @@ class WaitableManagerBase { WaitableManagerBase() = default; virtual ~WaitableManagerBase() = default; - u64 get_priority() { + u64 GetNextPriority() { return std::atomic_fetch_add(&cur_priority, (u64)1); } + + virtual void AddWaitable(IWaitable *w) = 0; + virtual void NotifySignaled(IWaitable *w) = 0; + + virtual void Process() = 0; }; + diff --git a/stratosphere/libstratosphere/include/stratosphere/waitablemanager.hpp b/stratosphere/libstratosphere/include/stratosphere/waitablemanager.hpp deleted file mode 100644 index 54f45e06d..000000000 --- a/stratosphere/libstratosphere/include/stratosphere/waitablemanager.hpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2018 Atmosphère-NX - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#pragma once -#include <switch.h> -#include <algorithm> -#include <memory> -#include <vector> - -#include "waitablemanagerbase.hpp" -#include "iwaitable.hpp" -#include "hossynch.hpp" - -class IWaitable; - -class WaitableManager : public WaitableManagerBase { - protected: - std::vector<IWaitable *> to_add_waitables; - std::vector<IWaitable *> waitables; - u64 timeout = 0; - HosMutex lock; - std::atomic_bool has_new_items = false; - private: - void process_internal(bool break_on_timeout); - public: - WaitableManager(u64 t) : timeout(t) { } - ~WaitableManager() override { - /* This should call the destructor for every waitable. */ - std::for_each(waitables.begin(), waitables.end(), std::default_delete<IWaitable>{}); - } - - virtual void add_waitable(IWaitable *waitable); - virtual void process(); - virtual void process_until_timeout(); -}; diff --git a/stratosphere/fs_mitm/source/mitm_query_service.cpp b/stratosphere/libstratosphere/source/mitm_query_service.cpp similarity index 87% rename from stratosphere/fs_mitm/source/mitm_query_service.cpp rename to stratosphere/libstratosphere/source/mitm_query_service.cpp index e4d88d076..eb3654575 100644 --- a/stratosphere/fs_mitm/source/mitm_query_service.cpp +++ b/stratosphere/libstratosphere/source/mitm_query_service.cpp @@ -17,13 +17,12 @@ #include <mutex> #include <switch.h> #include <stratosphere.hpp> -#include "mitm_query_service.hpp" static std::vector<u64> g_known_pids; static std::vector<u64> g_known_tids; static HosMutex g_pid_tid_mutex; -Result MitMQueryUtils::get_associated_tid_for_pid(u64 pid, u64 *tid) { +Result MitmQueryUtils::GetAssociatedTidForPid(u64 pid, u64 *tid) { Result rc = 0xCAFE; std::scoped_lock lk{g_pid_tid_mutex}; for (unsigned int i = 0; i < g_known_pids.size(); i++) { @@ -36,7 +35,7 @@ Result MitMQueryUtils::get_associated_tid_for_pid(u64 pid, u64 *tid) { return rc; } -void MitMQueryUtils::associate_pid_to_tid(u64 pid, u64 tid) { +void MitmQueryUtils::AssociatePidToTid(u64 pid, u64 tid) { std::scoped_lock lk{g_pid_tid_mutex}; g_known_pids.push_back(pid); g_known_tids.push_back(tid); diff --git a/stratosphere/libstratosphere/source/multithreadedwaitablemanager.cpp b/stratosphere/libstratosphere/source/multithreadedwaitablemanager.cpp deleted file mode 100644 index 3c5ec1356..000000000 --- a/stratosphere/libstratosphere/source/multithreadedwaitablemanager.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (c) 2018 Atmosphère-NX - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <switch.h> - -#include <algorithm> -#include <functional> -#include <mutex> - -#include <stratosphere/multithreadedwaitablemanager.hpp> - -void MultiThreadedWaitableManager::process() { - Result rc; - for (unsigned int i = 0; i < num_threads; i++) { - if (R_FAILED((rc = threadStart(&threads[i])))) { - fatalSimple(rc); - } - } - MultiThreadedWaitableManager::thread_func(this); -} - -void MultiThreadedWaitableManager::process_until_timeout() { - /* TODO: Panic. */ -} - -void MultiThreadedWaitableManager::add_waitable(IWaitable *waitable) { - std::scoped_lock lk{this->lock}; - this->to_add_waitables.push_back(waitable); - waitable->set_manager(this); - this->new_waitable_event->signal_event(); -} - - -IWaitable *MultiThreadedWaitableManager::get_waitable() { - std::vector<Handle> handles; - - int handle_index = 0; - Result rc; - std::scoped_lock lk{this->get_waitable_lock}; - while (1) { - /* Sort waitables by priority. */ - std::sort(this->waitables.begin(), this->waitables.end(), IWaitable::compare); - - /* Copy out handles. */ - handles.resize(this->waitables.size()); - std::transform(this->waitables.begin(), this->waitables.end(), handles.begin(), [](IWaitable *w) { return w->get_handle(); }); - - rc = svcWaitSynchronization(&handle_index, handles.data(), this->waitables.size(), this->timeout); - IWaitable *w = this->waitables[handle_index]; - if (R_SUCCEEDED(rc)) { - std::for_each(waitables.begin(), waitables.begin() + handle_index, std::mem_fn(&IWaitable::update_priority)); - this->waitables.erase(this->waitables.begin() + handle_index); - } else if (rc == 0xEA01) { - /* Timeout. */ - std::for_each(waitables.begin(), waitables.end(), std::mem_fn(&IWaitable::update_priority)); - } else if (rc != 0xF601 && rc != 0xE401) { - /* TODO: Panic. When can this happen? */ - } else { - std::for_each(waitables.begin(), waitables.begin() + handle_index, std::mem_fn(&IWaitable::update_priority)); - this->waitables.erase(this->waitables.begin() + handle_index); - delete w; - } - - /* Do deferred callback for each waitable. */ - for (auto & waitable : this->waitables) { - if (waitable->get_deferred()) { - waitable->handle_deferred(); - } - } - - /* Return waitable. */ - if (R_SUCCEEDED(rc)) { - if (w == this->new_waitable_event) { - w->handle_signaled(0); - this->waitables.push_back(w); - } else { - return w; - } - } - } -} - -Result MultiThreadedWaitableManager::add_waitable_callback(void *arg, Handle *handles, size_t num_handles, u64 timeout) { - MultiThreadedWaitableManager *this_ptr = (MultiThreadedWaitableManager *)arg; - svcClearEvent(handles[0]); - std::scoped_lock lk{this_ptr->lock}; - this_ptr->waitables.insert(this_ptr->waitables.end(), this_ptr->to_add_waitables.begin(), this_ptr->to_add_waitables.end()); - this_ptr->to_add_waitables.clear(); - return 0; -} - -void MultiThreadedWaitableManager::thread_func(void *t) { - MultiThreadedWaitableManager *this_ptr = (MultiThreadedWaitableManager *)t; - while (1) { - IWaitable *w = this_ptr->get_waitable(); - if (w) { - Result rc = w->handle_signaled(0); - if (rc == 0xF601) { - /* Close! */ - delete w; - } else { - this_ptr->add_waitable(w); - } - } - } -} diff --git a/stratosphere/fs_mitm/source/sm_mitm.c b/stratosphere/libstratosphere/source/sm_mitm.c similarity index 99% rename from stratosphere/fs_mitm/source/sm_mitm.c rename to stratosphere/libstratosphere/source/sm_mitm.c index 0ab1c5d55..0bbb284df 100644 --- a/stratosphere/fs_mitm/source/sm_mitm.c +++ b/stratosphere/libstratosphere/source/sm_mitm.c @@ -16,7 +16,7 @@ #include <switch.h> #include <switch/arm/atomics.h> -#include "sm_mitm.h" +#include <stratosphere/mitm/sm_mitm.h> static Handle g_smMitmHandle = INVALID_HANDLE; static u64 g_refCnt; diff --git a/stratosphere/libstratosphere/source/smm_ams.c b/stratosphere/libstratosphere/source/smm_ams.c new file mode 100644 index 000000000..2ac9e4e6e --- /dev/null +++ b/stratosphere/libstratosphere/source/smm_ams.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <switch.h> +#include <switch/arm/atomics.h> +#include <stratosphere/services/smm_ams.h> + +static Service g_smManagerAmsSrv; +static u64 g_smManagerAmsRefcnt; + +Result smManagerAmsInitialize(void) { + atomicIncrement64(&g_smManagerAmsRefcnt); + + if (serviceIsActive(&g_smManagerAmsSrv)) + return 0; + + return smGetService(&g_smManagerAmsSrv, "sm:m"); +} + +void smManagerAmsExit(void) { + if (atomicDecrement64(&g_smManagerAmsRefcnt) == 0) + serviceClose(&g_smManagerAmsSrv); +} + +Result smManagerAmsEndInitialDefers(void) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = serviceIpcPrepareHeader(&g_smManagerAmsSrv, &c, sizeof(*raw)); + raw->magic = SFCI_MAGIC; + raw->cmd_id = 65000; + + + Result rc = serviceIpcDispatch(&g_smManagerAmsSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_smManagerAmsSrv, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; + +} \ No newline at end of file diff --git a/stratosphere/libstratosphere/source/waitablemanager.cpp b/stratosphere/libstratosphere/source/waitablemanager.cpp deleted file mode 100644 index 35706a006..000000000 --- a/stratosphere/libstratosphere/source/waitablemanager.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2018 Atmosphère-NX - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <switch.h> - -#include <algorithm> -#include <functional> -#include <mutex> - -#include <stratosphere/waitablemanager.hpp> - -void WaitableManager::add_waitable(IWaitable *waitable) { - std::scoped_lock lk{this->lock}; - this->to_add_waitables.push_back(waitable); - waitable->set_manager(this); - this->has_new_items = true; -} - -void WaitableManager::process_internal(bool break_on_timeout) { - std::vector<Handle> handles; - - int handle_index = 0; - Result rc; - - while (1) { - /* Add new items, if relevant. */ - if (this->has_new_items) { - std::scoped_lock lk{this->lock}; - this->waitables.insert(this->waitables.end(), this->to_add_waitables.begin(), this->to_add_waitables.end()); - this->to_add_waitables.clear(); - this->has_new_items = false; - } - - /* Sort waitables by priority. */ - std::sort(this->waitables.begin(), this->waitables.end(), IWaitable::compare); - - /* Copy out handles. */ - handles.resize(this->waitables.size()); - std::transform(this->waitables.begin(), this->waitables.end(), handles.begin(), [](IWaitable *w) { return w->get_handle(); }); - - - rc = svcWaitSynchronization(&handle_index, handles.data(), this->waitables.size(), this->timeout); - if (R_SUCCEEDED(rc)) { - /* Handle a signaled waitable. */ - /* TODO: What timeout should be passed here? */ - - rc = this->waitables[handle_index]->handle_signaled(0); - - std::for_each(waitables.begin(), waitables.begin() + handle_index, std::mem_fn(&IWaitable::update_priority)); - } else if (rc == 0xEA01) { - /* Timeout. */ - std::for_each(waitables.begin(), waitables.end(), std::mem_fn(&IWaitable::update_priority)); - if (break_on_timeout) { - return; - } - } else if (rc != 0xF601) { - /* TODO: Panic. When can this happen? */ - } - - if (rc == 0xF601) { - /* handles[handle_index] was closed! */ - - /* Close the handle. */ - svcCloseHandle(handles[handle_index]); - - IWaitable *to_delete = this->waitables[handle_index]; - - /* If relevant, remove from waitables. */ - this->waitables.erase(this->waitables.begin() + handle_index); - - /* Delete it. */ - delete to_delete; - - std::for_each(waitables.begin(), waitables.begin() + handle_index, std::mem_fn(&IWaitable::update_priority)); - } - - /* Do deferred callback for each waitable. */ - for (auto & waitable : this->waitables) { - if (waitable->get_deferred()) { - waitable->handle_deferred(); - } - } - } -} - -void WaitableManager::process() { - WaitableManager::process_internal(false); -} - -void WaitableManager::process_until_timeout() { - WaitableManager::process_internal(true); -} diff --git a/stratosphere/loader/Makefile b/stratosphere/loader/Makefile index 41a6cf79f..e8b1f047a 100644 --- a/stratosphere/loader/Makefile +++ b/stratosphere/loader/Makefile @@ -21,7 +21,7 @@ TARGET := $(notdir $(CURDIR)) BUILD := build SOURCES := source DATA := data -INCLUDES := include +INCLUDES := include ../../common/include EXEFS_SRC := exefs_src DEFINES := -DDISABLE_IPC diff --git a/stratosphere/loader/loader.json b/stratosphere/loader/loader.json index e4f16cc7c..76ab67e85 100644 --- a/stratosphere/loader/loader.json +++ b/stratosphere/loader/loader.json @@ -13,60 +13,63 @@ { "type": "syscalls", "value": { - "svcSetHeapSize": "0x01", - "svcSetMemoryPermission": "0x02", - "svcSetMemoryAttribute": "0x03", - "svcMapMemory": "0x04", - "svcUnmapMemory": "0x05", - "svcQueryMemory": "0x06", - "svcExitProcess": "0x07", - "svcCreateThread": "0x08", - "svcStartThread": "0x09", - "svcExitThread": "0x0A", - "svcSleepThread": "0x0B", - "svcGetThreadPriority": "0x0C", - "svcSetThreadPriority": "0x0D", - "svcGetThreadCoreMask": "0x0E", - "svcSetThreadCoreMask": "0x0F", - "svcGetCurrentProcessorNumber": "0x10", - "svcSignalEvent": "0x11", - "svcClearEvent": "0x12", - "svcMapSharedMemory": "0x13", - "svcUnmapSharedMemory": "0x14", - "svcCreateTransferMemory": "0x15", - "svcCloseHandle": "0x16", - "svcResetSignal": "0x17", - "svcWaitSynchronization": "0x18", - "svcCancelSynchronization": "0x19", - "svcArbitrateLock": "0x1A", - "svcArbitrateUnlock": "0x1B", - "svcWaitProcessWideKeyAtomic": "0x1C", - "svcSignalProcessWideKey": "0x1D", - "svcGetSystemTick": "0x1E", - "svcConnectToNamedPort": "0x1F", - "svcSendSyncRequestLight": "0x20", - "svcSendSyncRequest": "0x21", - "svcSendSyncRequestWithUserBuffer": "0x22", - "svcSendAsyncRequestWithUserBuffer": "0x23", - "svcGetProcessId": "0x24", - "svcGetThreadId": "0x25", - "svcBreak": "0x26", - "svcOutputDebugString": "0x27", - "svcReturnFromException": "0x28", - "svcGetInfo": "0x29", - "svcWaitForAddress": "0x34", - "svcSignalToAddress": "0x35", - "svcCreateSession": "0x40", - "svcAcceptSession": "0x41", - "svcReplyAndReceiveLight": "0x42", - "svcReplyAndReceive": "0x43", - "svcReplyAndReceiveWithUserBuffer": "0x44", - "svcSetProcessMemoryPermission": "0x73", - "svcMapProcessMemory": "0x74", - "svcUnmapProcessMemory": "0x75", - "svcMapProcessCodeMemory": "0x77", - "svcUnmapProcessCodeMemory": "0x78", - "svcCreateProcess": "0x79" + "svcSetHeapSize" : "0x01", + "svcSetMemoryPermission" : "0x02", + "svcSetMemoryAttribute" : "0x03", + "svcMapMemory" : "0x04", + "svcUnmapMemory" : "0x05", + "svcQueryMemory" : "0x06", + "svcExitProcess" : "0x07", + "svcCreateThread" : "0x08", + "svcStartThread" : "0x09", + "svcExitThread" : "0x0A", + "svcSleepThread" : "0x0B", + "svcGetThreadPriority" : "0x0C", + "svcSetThreadPriority" : "0x0D", + "svcGetThreadCoreMask" : "0x0E", + "svcSetThreadCoreMask" : "0x0F", + "svcGetCurrentProcessorNumber" : "0x10", + "svcSignalEvent" : "0x11", + "svcClearEvent" : "0x12", + "svcMapSharedMemory" : "0x13", + "svcUnmapSharedMemory" : "0x14", + "svcCreateTransferMemory" : "0x15", + "svcCloseHandle" : "0x16", + "svcResetSignal" : "0x17", + "svcWaitSynchronization" : "0x18", + "svcCancelSynchronization" : "0x19", + "svcArbitrateLock" : "0x1A", + "svcArbitrateUnlock" : "0x1B", + "svcWaitProcessWideKeyAtomic" : "0x1C", + "svcSignalProcessWideKey" : "0x1D", + "svcGetSystemTick" : "0x1E", + "svcConnectToNamedPort" : "0x1F", + "svcSendSyncRequestLight" : "0x20", + "svcSendSyncRequest" : "0x21", + "svcSendSyncRequestWithUserBuffer" : "0x22", + "svcSendAsyncRequestWithUserBuffer" : "0x23", + "svcGetProcessId" : "0x24", + "svcGetThreadId" : "0x25", + "svcBreak" : "0x26", + "svcOutputDebugString" : "0x27", + "svcReturnFromException" : "0x28", + "svcGetInfo" : "0x29", + "svcWaitForAddress" : "0x34", + "svcSignalToAddress" : "0x35", + "svcCreateSession" : "0x40", + "svcAcceptSession" : "0x41", + "svcReplyAndReceiveLight" : "0x42", + "svcReplyAndReceive" : "0x43", + "svcReplyAndReceiveWithUserBuffer" : "0x44", + "svcCreateEvent" : "0x45", + "svcReadWriteRegister" : "0x4E", + "svcQueryIoMapping" : "0x55", + "svcSetProcessMemoryPermission" : "0x73", + "svcMapProcessMemory" : "0x74", + "svcUnmapProcessMemory" : "0x75", + "svcMapProcessCodeMemory" : "0x77", + "svcUnmapProcessCodeMemory" : "0x78", + "svcCreateProcess" : "0x79" } } ] diff --git a/stratosphere/loader/source/ldr_content_management.cpp b/stratosphere/loader/source/ldr_content_management.cpp index c822d3281..4fa73c093 100644 --- a/stratosphere/loader/source/ldr_content_management.cpp +++ b/stratosphere/loader/source/ldr_content_management.cpp @@ -19,11 +19,12 @@ #include <strings.h> #include <vector> #include <algorithm> +#include <map> #include "ldr_registration.hpp" #include "ldr_content_management.hpp" #include "ldr_hid.hpp" - +#include "ldr_npdm.hpp" #include "ini.h" @@ -40,6 +41,12 @@ static u64 g_override_key_combination = KEY_R; static bool g_override_by_default = true; static u64 g_override_hbl_tid = 0x010000000000100D; +/* Static buffer for loader.ini contents at runtime. */ +static char g_config_ini_data[0x800]; + +/* SetExternalContentSource extension */ +static std::map<u64, ContentManagement::ExternalContentSource> g_external_content_sources; + Result ContentManagement::MountCode(u64 tid, FsStorageId sid) { char path[FS_MAX_PATH] = {0}; Result rc; @@ -49,7 +56,11 @@ Result ContentManagement::MountCode(u64 tid, FsStorageId sid) { TryMountSdCard(); } - if (ShouldOverrideContents() && R_SUCCEEDED(MountCodeNspOnSd(tid))) { + if (g_has_initialized_fs_dev) { + RefreshConfigurationData(); + } + + if (ShouldOverrideContents(tid) && R_SUCCEEDED(MountCodeNspOnSd(tid))) { return 0x0; } @@ -92,7 +103,7 @@ Result ContentManagement::UnmountCode() { void ContentManagement::TryMountHblNspOnSd() { - char path[FS_MAX_PATH+1] = {0}; + char path[FS_MAX_PATH + 1] = {0}; strncpy(path, g_hbl_sd_path, FS_MAX_PATH); for (unsigned int i = 0; i < FS_MAX_PATH && path[i] != '\x00'; i++) { if (path[i] == '\\') { @@ -259,24 +270,17 @@ static int LoaderIniHandler(void *user, const char *section, const char *name, c return 1; } -void ContentManagement::LoadConfiguration(FILE *config) { +void ContentManagement::RefreshConfigurationData() { + FILE *config = fopen("sdmc:/atmosphere/loader.ini", "r"); if (config == NULL) { return; } - char *config_str = new char[0x800]; - if (config_str != NULL) { - /* Read in string. */ - std::fill(config_str, config_str + FS_MAX_PATH, 0); - fread(config_str, 1, 0x7FF, config); - config_str[strlen(config_str)] = 0x0; - - ini_parse_string(config_str, LoaderIniHandler, NULL); - - delete[] config_str; - } - + std::fill(g_config_ini_data, g_config_ini_data + 0x800, 0); + fread(g_config_ini_data, 1, 0x7FF, config); fclose(config); + + ini_parse_string(g_config_ini_data, LoaderIniHandler, NULL); } void ContentManagement::TryMountSdCard() { @@ -293,7 +297,6 @@ void ContentManagement::TryMountSdCard() { } if (R_SUCCEEDED(fsdevMountSdmc())) { - ContentManagement::LoadConfiguration(fopen("sdmc:/atmosphere/loader.ini", "r")); g_has_initialized_fs_dev = true; } } @@ -303,7 +306,7 @@ bool ContentManagement::ShouldReplaceWithHBL(u64 tid) { return g_mounted_hbl_nsp && tid == g_override_hbl_tid; } -bool ContentManagement::ShouldOverrideContents() { +bool ContentManagement::ShouldOverrideContents(u64 tid) { if (HasCreatedTitle(0x0100000000001000)) { u64 kDown = 0; bool keys_triggered = (R_SUCCEEDED(HidManagement::GetKeysDown(&kDown)) && ((kDown & g_override_key_combination) != 0)); @@ -312,4 +315,55 @@ bool ContentManagement::ShouldOverrideContents() { /* Always redirect before qlaunch. */ return g_has_initialized_fs_dev; } -} \ No newline at end of file +} + +/* SetExternalContentSource extension */ +ContentManagement::ExternalContentSource *ContentManagement::GetExternalContentSource(u64 tid) { + auto i = g_external_content_sources.find(tid); + if (i == g_external_content_sources.end()) { + return nullptr; + } else { + return &i->second; + } +} + +Result ContentManagement::SetExternalContentSource(u64 tid, FsFileSystem filesystem) { + if (g_external_content_sources.size() >= 16) { + return 0x409; /* LAUNCH_QUEUE_FULL */ + } + + /* Remove any existing ECS for this title. */ + ClearExternalContentSource(tid); + + char mountpoint[32]; + ExternalContentSource::GenerateMountpointName(tid, mountpoint, sizeof(mountpoint)); + if (fsdevMountDevice(mountpoint, filesystem) == -1) { + return 0x7802; /* specified mount name already exists */ + } + g_external_content_sources.emplace( + std::piecewise_construct, + std::make_tuple(tid), + std::make_tuple(tid, mountpoint)); + + return 0; +} + +void ContentManagement::ClearExternalContentSource(u64 tid) { + auto i = g_external_content_sources.find(tid); + if (i != g_external_content_sources.end()) { + g_external_content_sources.erase(i); + } +} + +void ContentManagement::ExternalContentSource::GenerateMountpointName(u64 tid, char *out, size_t max_length) { + snprintf(out, max_length, "ecs-%016lx", tid); +} + +ContentManagement::ExternalContentSource::ExternalContentSource(u64 tid, const char *mountpoint) : tid(tid) { + strncpy(this->mountpoint, mountpoint, sizeof(this->mountpoint)); + NpdmUtils::InvalidateCache(tid); +} + +ContentManagement::ExternalContentSource::~ExternalContentSource() { + fsdevUnmountDevice(mountpoint); +} diff --git a/stratosphere/loader/source/ldr_content_management.hpp b/stratosphere/loader/source/ldr_content_management.hpp index c241092a4..a9974530a 100644 --- a/stratosphere/loader/source/ldr_content_management.hpp +++ b/stratosphere/loader/source/ldr_content_management.hpp @@ -34,9 +34,29 @@ class ContentManagement { static bool HasCreatedTitle(u64 tid); static void SetCreatedTitle(u64 tid); - static void LoadConfiguration(FILE *config); + static void RefreshConfigurationData(); static void TryMountSdCard(); static bool ShouldReplaceWithHBL(u64 tid); - static bool ShouldOverrideContents(); + static bool ShouldOverrideContents(u64 tid); + + /* SetExternalContentSource extension */ + class ExternalContentSource { + public: + static void GenerateMountpointName(u64 tid, char *out, size_t max_length); + + ExternalContentSource(u64 tid, const char *mountpoint); + ~ExternalContentSource(); + + ExternalContentSource(const ExternalContentSource &other) = delete; + ExternalContentSource(ExternalContentSource &&other) = delete; + ExternalContentSource &operator=(const ExternalContentSource &other) = delete; + ExternalContentSource &operator=(ExternalContentSource &&other) = delete; + + const u64 tid; + char mountpoint[32]; + }; + static ExternalContentSource *GetExternalContentSource(u64 tid); /* returns nullptr if no ECS is set */ + static Result SetExternalContentSource(u64 tid, FsFileSystem filesystem); /* takes ownership of filesystem */ + static void ClearExternalContentSource(u64 tid); }; diff --git a/stratosphere/loader/source/ldr_debug_monitor.cpp b/stratosphere/loader/source/ldr_debug_monitor.cpp index a2e12e3f8..d7dd77489 100644 --- a/stratosphere/loader/source/ldr_debug_monitor.cpp +++ b/stratosphere/loader/source/ldr_debug_monitor.cpp @@ -22,42 +22,18 @@ #include "ldr_launch_queue.hpp" #include "ldr_registration.hpp" -Result DebugMonitorService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) { - Result rc = 0xF601; - - switch ((DebugMonitorServiceCmd)cmd_id) { - case Dmnt_Cmd_AddTitleToLaunchQueue: - rc = WrapIpcCommandImpl<&DebugMonitorService::add_title_to_launch_queue>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Dmnt_Cmd_ClearLaunchQueue: - rc = WrapIpcCommandImpl<&DebugMonitorService::clear_launch_queue>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Dmnt_Cmd_GetNsoInfo: - rc = WrapIpcCommandImpl<&DebugMonitorService::get_nso_info>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - default: - break; - } - return rc; +Result DebugMonitorService::AddTitleToLaunchQueue(u64 tid, InPointer<char> args, u32 args_size) { + if (args.num_elements < args_size) args_size = args.num_elements; + return LaunchQueue::Add(tid, args.pointer, args_size); } -std::tuple<Result> DebugMonitorService::add_title_to_launch_queue(u64 args_size, u64 tid, InPointer<char> args) { - fprintf(stderr, "Add to launch queue: %p, %zX\n", args.pointer, std::min(args_size, args.num_elements)); - return {LaunchQueue::add(tid, args.pointer, std::min(args_size, args.num_elements))}; +void DebugMonitorService::ClearLaunchQueue() { + LaunchQueue::Clear(); } -std::tuple<Result> DebugMonitorService::clear_launch_queue(u64 dat) { - fprintf(stderr, "Clear launch queue: %lx\n", dat); - LaunchQueue::clear(); - return {0}; -} - -std::tuple<Result, u32> DebugMonitorService::get_nso_info(u64 pid, OutPointerWithClientSize<Registration::NsoInfo> out) { - u32 out_num_nsos = 0; - +Result DebugMonitorService::GetNsoInfo(Out<u32> count, OutPointerWithClientSize<Registration::NsoInfo> out, u64 pid) { + /* Zero out the output memory. */ std::fill(out.pointer, out.pointer + out.num_elements, (const Registration::NsoInfo){0}); - - Result rc = Registration::GetNsoInfosForProcessId(out.pointer, out.num_elements, pid, &out_num_nsos); - - return {rc, out_num_nsos}; + /* Actually return the nso infos. */ + return Registration::GetNsoInfosForProcessId(out.pointer, out.num_elements, pid, count.GetPointer()); } diff --git a/stratosphere/loader/source/ldr_debug_monitor.hpp b/stratosphere/loader/source/ldr_debug_monitor.hpp index d1b1c4e8a..fa466706d 100644 --- a/stratosphere/loader/source/ldr_debug_monitor.hpp +++ b/stratosphere/loader/source/ldr_debug_monitor.hpp @@ -17,7 +17,7 @@ #pragma once #include <switch.h> -#include <stratosphere/iserviceobject.hpp> +#include <stratosphere.hpp> #include "ldr_registration.hpp" enum DebugMonitorServiceCmd { @@ -26,21 +26,16 @@ enum DebugMonitorServiceCmd { Dmnt_Cmd_GetNsoInfo = 2 }; -class DebugMonitorService final : public IServiceObject { - public: - Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) override; - Result handle_deferred() override { - /* This service will never defer. */ - return 0; - } - - DebugMonitorService *clone() override { - return new DebugMonitorService(); - } - +class DebugMonitorService final : public IServiceObject { private: /* Actual commands. */ - std::tuple<Result> add_title_to_launch_queue(u64 args_size, u64 tid, InPointer<char> args); - std::tuple<Result> clear_launch_queue(u64 dat); - std::tuple<Result, u32> get_nso_info(u64 pid, OutPointerWithClientSize<Registration::NsoInfo> out); + Result AddTitleToLaunchQueue(u64 tid, InPointer<char> args, u32 args_size); + void ClearLaunchQueue(); + Result GetNsoInfo(Out<u32> count, OutPointerWithClientSize<Registration::NsoInfo> out, u64 pid); + public: + DEFINE_SERVICE_DISPATCH_TABLE { + MakeServiceCommandMeta<Dmnt_Cmd_AddTitleToLaunchQueue, &DebugMonitorService::AddTitleToLaunchQueue>(), + MakeServiceCommandMeta<Dmnt_Cmd_ClearLaunchQueue, &DebugMonitorService::ClearLaunchQueue>(), + MakeServiceCommandMeta<Dmnt_Cmd_GetNsoInfo, &DebugMonitorService::GetNsoInfo>(), + }; }; diff --git a/stratosphere/loader/source/ldr_hid.cpp b/stratosphere/loader/source/ldr_hid.cpp index 8bad9377b..a7ca176f0 100644 --- a/stratosphere/loader/source/ldr_hid.cpp +++ b/stratosphere/loader/source/ldr_hid.cpp @@ -20,8 +20,6 @@ #include "ldr_content_management.hpp" #include "ldr_hid.hpp" -static bool g_has_opened_hid_session = false; - Result HidManagement::GetKeysDown(u64 *keys) { if (!ContentManagement::HasCreatedTitle(0x0100000000000013) || R_FAILED(hidInitialize())) { return MAKERESULT(Module_Libnx, LibnxError_InitFail_HID); diff --git a/stratosphere/loader/source/ldr_launch_queue.cpp b/stratosphere/loader/source/ldr_launch_queue.cpp index 8fda8585b..8f6933e42 100644 --- a/stratosphere/loader/source/ldr_launch_queue.cpp +++ b/stratosphere/loader/source/ldr_launch_queue.cpp @@ -23,12 +23,12 @@ static std::array<LaunchQueue::LaunchItem, LAUNCH_QUEUE_SIZE> g_launch_queue = {0}; -Result LaunchQueue::add(u64 tid, const char *args, u64 arg_size) { +Result LaunchQueue::Add(u64 tid, const char *args, u64 arg_size) { if(arg_size > LAUNCH_QUEUE_ARG_SIZE_MAX) { return 0x209; } - int idx = get_free_index(tid); + int idx = GetFreeIndex(tid); if(idx == LAUNCH_QUEUE_FULL) return 0x409; @@ -39,22 +39,22 @@ Result LaunchQueue::add(u64 tid, const char *args, u64 arg_size) { return 0x0; } -Result LaunchQueue::add_copy(u64 tid_base, u64 tid) { - int idx = get_index(tid_base); +Result LaunchQueue::AddCopy(u64 tid_base, u64 tid) { + int idx = GetIndex(tid_base); if (idx == LAUNCH_QUEUE_FULL) { return 0x0; } - return add(tid, g_launch_queue[idx].args, g_launch_queue[idx].arg_size); + return Add(tid, g_launch_queue[idx].args, g_launch_queue[idx].arg_size); } -Result LaunchQueue::add_item(const LaunchItem *item) { +Result LaunchQueue::AddItem(const LaunchItem *item) { if(item->arg_size > LAUNCH_QUEUE_ARG_SIZE_MAX) { return 0x209; } - int idx = get_free_index(item->tid); + int idx = GetFreeIndex(item->tid); if(idx == LAUNCH_QUEUE_FULL) return 0x409; @@ -62,7 +62,7 @@ Result LaunchQueue::add_item(const LaunchItem *item) { return 0x0; } -int LaunchQueue::get_index(u64 tid) { +int LaunchQueue::GetIndex(u64 tid) { auto it = std::find_if(g_launch_queue.begin(), g_launch_queue.end(), member_equals_fn(&LaunchQueue::LaunchItem::tid, tid)); if (it == g_launch_queue.end()) { return LAUNCH_QUEUE_FULL; @@ -70,7 +70,7 @@ int LaunchQueue::get_index(u64 tid) { return std::distance(g_launch_queue.begin(), it); } -int LaunchQueue::get_free_index(u64 tid) { +int LaunchQueue::GetFreeIndex(u64 tid) { for(unsigned int i = 0; i < LAUNCH_QUEUE_SIZE; i++) { if(g_launch_queue[i].tid == tid || g_launch_queue[i].tid == 0x0) { return i; @@ -79,19 +79,19 @@ int LaunchQueue::get_free_index(u64 tid) { return LAUNCH_QUEUE_FULL; } -bool LaunchQueue::contains(u64 tid) { - return get_index(tid) != LAUNCH_QUEUE_FULL; +bool LaunchQueue::Contains(u64 tid) { + return GetIndex(tid) != LAUNCH_QUEUE_FULL; } -void LaunchQueue::clear() { +void LaunchQueue::Clear() { for (unsigned int i = 0; i < LAUNCH_QUEUE_SIZE; i++) { g_launch_queue[i].tid = 0; } } -LaunchQueue::LaunchItem *LaunchQueue::get_item(u64 tid) { - int idx = get_index(tid); +LaunchQueue::LaunchItem *LaunchQueue::GetItem(u64 tid) { + int idx = GetIndex(tid); if (idx == LAUNCH_QUEUE_FULL) { return NULL; } diff --git a/stratosphere/loader/source/ldr_launch_queue.hpp b/stratosphere/loader/source/ldr_launch_queue.hpp index 74a2a03c9..234cd3be5 100644 --- a/stratosphere/loader/source/ldr_launch_queue.hpp +++ b/stratosphere/loader/source/ldr_launch_queue.hpp @@ -30,13 +30,13 @@ class LaunchQueue { char args[LAUNCH_QUEUE_ARG_SIZE_MAX]; }; - static LaunchQueue::LaunchItem *get_item(u64 tid); + static LaunchQueue::LaunchItem *GetItem(u64 tid); - static Result add(u64 tid, const char *args, u64 arg_size); - static Result add_item(const LaunchItem *item); - static Result add_copy(u64 tid_base, u64 new_tid); - static int get_index(u64 tid); - static int get_free_index(u64 tid); - static bool contains(u64 tid); - static void clear(); + static Result Add(u64 tid, const char *args, u64 arg_size); + static Result AddItem(const LaunchItem *item); + static Result AddCopy(u64 tid_base, u64 new_tid); + static int GetIndex(u64 tid); + static int GetFreeIndex(u64 tid); + static bool Contains(u64 tid); + static void Clear(); }; \ No newline at end of file diff --git a/stratosphere/loader/source/ldr_main.cpp b/stratosphere/loader/source/ldr_main.cpp index a8d69bf85..8db791cd0 100644 --- a/stratosphere/loader/source/ldr_main.cpp +++ b/stratosphere/loader/source/ldr_main.cpp @@ -80,19 +80,7 @@ void __appInit(void) { fatalSimple(0xCAFE << 4 | 2); } - rc = splInitialize(); - if (R_FAILED(rc)) { - fatalSimple(0xCAFE << 4 | 3); - } - - /* Check for exosphere API compatibility. */ - u64 exosphere_cfg; - if (R_FAILED(splGetConfig((SplConfigItem)65000, &exosphere_cfg))) { - //fatalSimple(0xCAFE << 4 | 0xFF); - /* TODO: Does Loader need to know about target firmware/master key revision? If so, extract from exosphere_cfg. */ - } - - //splExit(); + CheckAtmosphereVersion(); } void __appExit(void) { @@ -104,24 +92,31 @@ void __appExit(void) { smExit(); } +struct LoaderServerOptions { + static constexpr size_t PointerBufferSize = 0x400; + static constexpr size_t MaxDomains = 0; + static constexpr size_t MaxDomainObjects = 0; +}; + int main(int argc, char **argv) { consoleDebugInit(debugDevice_SVC); + + auto server_manager = new WaitableManager<LoaderServerOptions>(1); - /* TODO: What's a good timeout value to use here? */ - auto server_manager = std::make_unique<WaitableManager>(U64_MAX); - /* Add services to manager. */ - server_manager->add_waitable(new ServiceServer<ProcessManagerService>("ldr:pm", 1)); - server_manager->add_waitable(new ServiceServer<ShellService>("ldr:shel", 3)); - server_manager->add_waitable(new ServiceServer<DebugMonitorService>("ldr:dmnt", 2)); - if (!kernelAbove300()) { + server_manager->AddWaitable(new ServiceServer<ProcessManagerService>("ldr:pm", 1)); + server_manager->AddWaitable(new ServiceServer<ShellService>("ldr:shel", 3)); + server_manager->AddWaitable(new ServiceServer<DebugMonitorService>("ldr:dmnt", 2)); + if (GetRuntimeFirmwareVersion() < FirmwareVersion_300) { /* On 1.0.0-2.3.0, Loader services ldr:ro instead of ro. */ - server_manager->add_waitable(new ServiceServer<RelocatableObjectsService>("ldr:ro", 0x20)); + server_manager->AddWaitable(new ServiceServer<RelocatableObjectsService>("ldr:ro", 0x20)); } - + /* Loop forever, servicing our services. */ - server_manager->process(); + server_manager->Process(); + + delete server_manager; return 0; } diff --git a/stratosphere/loader/source/ldr_npdm.cpp b/stratosphere/loader/source/ldr_npdm.cpp index 2bb9eb669..7eb114cfc 100644 --- a/stratosphere/loader/source/ldr_npdm.cpp +++ b/stratosphere/loader/source/ldr_npdm.cpp @@ -33,6 +33,12 @@ Result NpdmUtils::LoadNpdmFromCache(u64 tid, NpdmInfo *out) { return 0; } +FILE *NpdmUtils::OpenNpdmFromECS(ContentManagement::ExternalContentSource *ecs) { + std::fill(g_npdm_path, g_npdm_path + FS_MAX_PATH, 0); + snprintf(g_npdm_path, FS_MAX_PATH, "%s:/main.npdm", ecs->mountpoint); + return fopen(g_npdm_path, "rb"); +} + FILE *NpdmUtils::OpenNpdmFromHBL() { std::fill(g_npdm_path, g_npdm_path + FS_MAX_PATH, 0); snprintf(g_npdm_path, FS_MAX_PATH, "hbl:/main.npdm"); @@ -53,7 +59,12 @@ FILE *NpdmUtils::OpenNpdmFromSdCard(u64 title_id) { FILE *NpdmUtils::OpenNpdm(u64 title_id) { - if (ContentManagement::ShouldOverrideContents()) { + ContentManagement::ExternalContentSource *ecs = nullptr; + if ((ecs = ContentManagement::GetExternalContentSource(title_id)) != nullptr) { + return OpenNpdmFromECS(ecs); + } + + if (ContentManagement::ShouldOverrideContents(title_id)) { if (ContentManagement::ShouldReplaceWithHBL(title_id)) { return OpenNpdmFromHBL(); } @@ -182,7 +193,7 @@ Result NpdmUtils::LoadNpdm(u64 tid, NpdmInfo *out) { info->acid->title_id_range_max = tid; info->aci0->title_id = tid; - if (ContentManagement::ShouldOverrideContents() && ContentManagement::ShouldReplaceWithHBL(tid) + if (ContentManagement::ShouldOverrideContents(tid) && ContentManagement::ShouldReplaceWithHBL(tid) && R_SUCCEEDED(LoadNpdmInternal(OpenNpdmFromExeFS(), &g_original_npdm_cache))) { NpdmInfo *original_info = &g_original_npdm_cache.info; /* Fix pool partition. */ @@ -190,7 +201,7 @@ Result NpdmUtils::LoadNpdm(u64 tid, NpdmInfo *out) { info->acid->flags = (info->acid->flags & 0xFFFFFFC3) | (original_info->acid->flags & 0x0000003C); } /* Fix application type. */ - const u32 original_application_type = GetApplicationType((u32 *)original_info->aci0_kac, original_info->aci0->kac_size/sizeof(u32)) & 7; + const u32 original_application_type = GetApplicationTypeRaw((u32 *)original_info->aci0_kac, original_info->aci0->kac_size/sizeof(u32)) & 7; u32 *caps = (u32 *)info->aci0_kac; for (unsigned int i = 0; i < info->aci0->kac_size/sizeof(u32); i++) { if ((caps[i] & 0x3FFF) == 0x1FFF) { @@ -489,4 +500,21 @@ u32 NpdmUtils::GetApplicationType(u32 *caps, size_t num_caps) { } } return application_type; -} \ No newline at end of file +} + +/* Like GetApplicationType, except this returns the raw kac descriptor value. */ +u32 NpdmUtils::GetApplicationTypeRaw(u32 *caps, size_t num_caps) { + u32 application_type = 0; + for (unsigned int i = 0; i < num_caps; i++) { + if ((caps[i] & 0x3FFF) == 0x1FFF) { + return (caps[i] >> 14) & 7; + } + } + return application_type; +} + +void NpdmUtils::InvalidateCache(u64 tid) { + if (g_npdm_cache.info.title_id == tid) { + g_npdm_cache.info = (const NpdmUtils::NpdmInfo){0}; + } +} diff --git a/stratosphere/loader/source/ldr_npdm.hpp b/stratosphere/loader/source/ldr_npdm.hpp index 3a7e721ee..2d4610f58 100644 --- a/stratosphere/loader/source/ldr_npdm.hpp +++ b/stratosphere/loader/source/ldr_npdm.hpp @@ -19,6 +19,7 @@ #include <cstdio> #include "ldr_registration.hpp" +#include "ldr_content_management.hpp" /* for ExternalContentSource */ #define MAGIC_META 0x4154454D #define MAGIC_ACI0 0x30494341 @@ -96,17 +97,20 @@ class NpdmUtils { static_assert(sizeof(NpdmAci0) == 0x40, "Incorrectly defined NpdmAci0!"); static u32 GetApplicationType(u32 *caps, size_t num_caps); + static u32 GetApplicationTypeRaw(u32 *caps, size_t num_caps); static Result ValidateCapabilityAgainstRestrictions(u32 *restrict_caps, size_t num_restrict_caps, u32 *&cur_cap, size_t &caps_remaining); static Result ValidateCapabilities(u32 *acid_caps, size_t num_acid_caps, u32 *aci0_caps, size_t num_aci0_caps); - + static FILE *OpenNpdmFromECS(ContentManagement::ExternalContentSource *ecs); static FILE *OpenNpdmFromHBL(); static FILE *OpenNpdmFromExeFS(); static FILE *OpenNpdmFromSdCard(u64 tid); static FILE *OpenNpdm(u64 tid); static Result LoadNpdm(u64 tid, NpdmInfo *out); static Result LoadNpdmFromCache(u64 tid, NpdmInfo *out); + + static void InvalidateCache(u64 tid); private: static Result LoadNpdmInternal(FILE *f_npdm, NpdmCache *cache); -}; \ No newline at end of file +}; diff --git a/stratosphere/loader/source/ldr_nso.cpp b/stratosphere/loader/source/ldr_nso.cpp index 451093e7c..bdc65eb3d 100644 --- a/stratosphere/loader/source/ldr_nso.cpp +++ b/stratosphere/loader/source/ldr_nso.cpp @@ -31,6 +31,12 @@ static bool g_nso_present[NSO_NUM_MAX] = {0}; static char g_nso_path[FS_MAX_PATH] = {0}; +FILE *NsoUtils::OpenNsoFromECS(unsigned int index, ContentManagement::ExternalContentSource *ecs) { + std::fill(g_nso_path, g_nso_path + FS_MAX_PATH, 0); + snprintf(g_nso_path, FS_MAX_PATH, "%s:/%s", ecs->mountpoint, NsoUtils::GetNsoFileName(index)); + return fopen(g_nso_path, "rb"); +} + FILE *NsoUtils::OpenNsoFromHBL(unsigned int index) { std::fill(g_nso_path, g_nso_path + FS_MAX_PATH, 0); snprintf(g_nso_path, FS_MAX_PATH, "hbl:/%s", NsoUtils::GetNsoFileName(index)); @@ -61,7 +67,12 @@ bool NsoUtils::CheckNsoStubbed(unsigned int index, u64 title_id) { } FILE *NsoUtils::OpenNso(unsigned int index, u64 title_id) { - if (ContentManagement::ShouldOverrideContents()) { + ContentManagement::ExternalContentSource *ecs = nullptr; + if ((ecs = ContentManagement::GetExternalContentSource(title_id)) != nullptr) { + return OpenNsoFromECS(index, ecs); + } + + if (ContentManagement::ShouldOverrideContents(title_id)) { if (ContentManagement::ShouldReplaceWithHBL(title_id)) { return OpenNsoFromHBL(index); } diff --git a/stratosphere/loader/source/ldr_nso.hpp b/stratosphere/loader/source/ldr_nso.hpp index 364943346..6de7f6677 100644 --- a/stratosphere/loader/source/ldr_nso.hpp +++ b/stratosphere/loader/source/ldr_nso.hpp @@ -18,6 +18,8 @@ #include <switch.h> #include <cstdio> +#include "ldr_content_management.hpp" /* for ExternalContentSource */ + #define MAGIC_NSO0 0x304F534E #define NSO_NUM_MAX 13 @@ -96,7 +98,8 @@ class NsoUtils { return "?"; } } - + + static FILE *OpenNsoFromECS(unsigned int index, ContentManagement::ExternalContentSource *ecs); static FILE *OpenNsoFromHBL(unsigned int index); static FILE *OpenNsoFromExeFS(unsigned int index); static FILE *OpenNsoFromSdCard(unsigned int index, u64 title_id); diff --git a/stratosphere/loader/source/ldr_process_creation.cpp b/stratosphere/loader/source/ldr_process_creation.cpp index 40d9d716d..74c4b095e 100644 --- a/stratosphere/loader/source/ldr_process_creation.cpp +++ b/stratosphere/loader/source/ldr_process_creation.cpp @@ -215,6 +215,8 @@ Result ProcessCreation::CreateProcess(Handle *out_process_h, u64 index, char *nc rc = 0; CREATE_PROCESS_END: + /* ECS is a one-shot operation. */ + ContentManagement::ClearExternalContentSource(target_process->tid_sid.title_id); if (mounted_code) { if (R_SUCCEEDED(rc) && target_process->tid_sid.storage_id != FsStorageId_None) { rc = ContentManagement::UnmountCode(); diff --git a/stratosphere/loader/source/ldr_process_manager.cpp b/stratosphere/loader/source/ldr_process_manager.cpp index a1be87408..b1cae6ac4 100644 --- a/stratosphere/loader/source/ldr_process_manager.cpp +++ b/stratosphere/loader/source/ldr_process_manager.cpp @@ -22,68 +22,45 @@ #include "ldr_content_management.hpp" #include "ldr_npdm.hpp" -Result ProcessManagerService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) { - Result rc = 0xF601; - - switch ((ProcessManagerServiceCmd)cmd_id) { - case Pm_Cmd_CreateProcess: - rc = WrapIpcCommandImpl<&ProcessManagerService::create_process>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Pm_Cmd_GetProgramInfo: - rc = WrapIpcCommandImpl<&ProcessManagerService::get_program_info>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Pm_Cmd_RegisterTitle: - rc = WrapIpcCommandImpl<&ProcessManagerService::register_title>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Pm_Cmd_UnregisterTitle: - rc = WrapIpcCommandImpl<&ProcessManagerService::unregister_title>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - default: - break; - } - return rc; -} - -std::tuple<Result, MovedHandle> ProcessManagerService::create_process(u64 flags, u64 index, CopiedHandle reslimit_h) { +Result ProcessManagerService::CreateProcess(Out<MovedHandle> proc_h, u64 index, u32 flags, CopiedHandle reslimit_h) { Result rc; Registration::TidSid tid_sid; LaunchQueue::LaunchItem *launch_item; char nca_path[FS_MAX_PATH] = {0}; - Handle process_h = 0; - fprintf(stderr, "CreateProcess(%016lx, %016lx, %08x);\n", flags, index, reslimit_h.handle); + fprintf(stderr, "CreateProcess(%016lx, %08x, %08x);\n", index, flags, reslimit_h.handle); rc = Registration::GetRegisteredTidSid(index, &tid_sid); if (R_FAILED(rc)) { - return {rc, MovedHandle{process_h}}; + return rc; } if (tid_sid.storage_id != FsStorageId_None) { rc = ContentManagement::ResolveContentPathForTidSid(nca_path, &tid_sid); if (R_FAILED(rc)) { - return {rc, MovedHandle{process_h}}; + return rc; } } - launch_item = LaunchQueue::get_item(tid_sid.title_id); + launch_item = LaunchQueue::GetItem(tid_sid.title_id); - rc = ProcessCreation::CreateProcess(&process_h, index, nca_path, launch_item, flags, reslimit_h.handle); + rc = ProcessCreation::CreateProcess(proc_h.GetHandlePointer(), index, nca_path, launch_item, flags, reslimit_h.handle); if (R_SUCCEEDED(rc)) { ContentManagement::SetCreatedTitle(tid_sid.title_id); } - return {rc, MovedHandle{process_h}}; + return rc; } -std::tuple<Result> ProcessManagerService::get_program_info(Registration::TidSid tid_sid, OutPointerWithServerSize<ProcessManagerService::ProgramInfo, 0x1> out_program_info) { +Result ProcessManagerService::GetProgramInfo(OutPointerWithServerSize<ProcessManagerService::ProgramInfo, 0x1> out_program_info, Registration::TidSid tid_sid) { Result rc; char nca_path[FS_MAX_PATH] = {0}; /* Zero output. */ std::fill(out_program_info.pointer, out_program_info.pointer + out_program_info.num_elements, (const ProcessManagerService::ProgramInfo){0}); - rc = populate_program_info_buffer(out_program_info.pointer, &tid_sid); + rc = PopulateProgramInfoBuffer(out_program_info.pointer, &tid_sid); if (R_FAILED(rc)) { return {rc}; @@ -100,31 +77,22 @@ std::tuple<Result> ProcessManagerService::get_program_info(Registration::TidSid return {rc}; } - rc = LaunchQueue::add_copy(tid_sid.title_id, out_program_info.pointer->title_id); + rc = LaunchQueue::AddCopy(tid_sid.title_id, out_program_info.pointer->title_id); } return {rc}; } -std::tuple<Result, u64> ProcessManagerService::register_title(Registration::TidSid tid_sid) { - u64 out_index = 0; - if (Registration::RegisterTidSid(&tid_sid, &out_index)) { - return {0, out_index}; - } else { - return {0xE09, out_index}; - } +Result ProcessManagerService::RegisterTitle(Out<u64> index, Registration::TidSid tid_sid) { + return Registration::RegisterTidSid(&tid_sid, index.GetPointer()) ? 0 : 0xE09; } -std::tuple<Result> ProcessManagerService::unregister_title(u64 index) { - if (Registration::UnregisterIndex(index)) { - return {0}; - } else { - return {0x1009}; - } +Result ProcessManagerService::UnregisterTitle(u64 index) { + return Registration::UnregisterIndex(index) ? 0 : 0x1009; } -Result ProcessManagerService::populate_program_info_buffer(ProcessManagerService::ProgramInfo *out, Registration::TidSid *tid_sid) { +Result ProcessManagerService::PopulateProgramInfoBuffer(ProcessManagerService::ProgramInfo *out, Registration::TidSid *tid_sid) { NpdmUtils::NpdmInfo info; Result rc; bool mounted_code = false; diff --git a/stratosphere/loader/source/ldr_process_manager.hpp b/stratosphere/loader/source/ldr_process_manager.hpp index c177a03b2..7cb4bc85e 100644 --- a/stratosphere/loader/source/ldr_process_manager.hpp +++ b/stratosphere/loader/source/ldr_process_manager.hpp @@ -16,7 +16,7 @@ #pragma once #include <switch.h> -#include <stratosphere/iserviceobject.hpp> +#include <stratosphere.hpp> #include "ldr_registration.hpp" #include "ldr_process_creation.hpp" @@ -42,26 +42,21 @@ class ProcessManagerService final : public IServiceObject { u8 ac_buffer[0x3E0]; }; - static_assert(sizeof(ProcessManagerService::ProgramInfo) == 0x400, "Incorrect ProgramInfo definition."); - - public: - Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) override; - Result handle_deferred() override { - /* This service will never defer. */ - return 0; - } - - ProcessManagerService *clone() override { - return new ProcessManagerService(); - } - + static_assert(sizeof(ProcessManagerService::ProgramInfo) == 0x400, "Incorrect ProgramInfo definition."); private: /* Actual commands. */ - std::tuple<Result, MovedHandle> create_process(u64 flags, u64 index, CopiedHandle reslimit_h); - std::tuple<Result> get_program_info(Registration::TidSid tid_sid, OutPointerWithServerSize<ProcessManagerService::ProgramInfo, 0x1> out_program_info); - std::tuple<Result, u64> register_title(Registration::TidSid tid_sid); - std::tuple<Result> unregister_title(u64 index); + Result CreateProcess(Out<MovedHandle> proc_h, u64 index, u32 flags, CopiedHandle reslimit_h); + Result GetProgramInfo(OutPointerWithServerSize<ProcessManagerService::ProgramInfo, 0x1> out_program_info, Registration::TidSid tid_sid); + Result RegisterTitle(Out<u64> index, Registration::TidSid tid_sid); + Result UnregisterTitle(u64 index); /* Utilities */ - Result populate_program_info_buffer(ProcessManagerService::ProgramInfo *out, Registration::TidSid *tid_sid); + Result PopulateProgramInfoBuffer(ProcessManagerService::ProgramInfo *out, Registration::TidSid *tid_sid); + public: + DEFINE_SERVICE_DISPATCH_TABLE { + MakeServiceCommandMeta<Pm_Cmd_CreateProcess, &ProcessManagerService::CreateProcess>(), + MakeServiceCommandMeta<Pm_Cmd_GetProgramInfo, &ProcessManagerService::GetProgramInfo>(), + MakeServiceCommandMeta<Pm_Cmd_RegisterTitle, &ProcessManagerService::RegisterTitle>(), + MakeServiceCommandMeta<Pm_Cmd_UnregisterTitle, &ProcessManagerService::UnregisterTitle>(), + }; }; diff --git a/stratosphere/loader/source/ldr_ro_service.cpp b/stratosphere/loader/source/ldr_ro_service.cpp index 4529710f9..013476499 100644 --- a/stratosphere/loader/source/ldr_ro_service.cpp +++ b/stratosphere/loader/source/ldr_ro_service.cpp @@ -24,71 +24,34 @@ #include "ldr_map.hpp" #include "ldr_nro.hpp" -Result RelocatableObjectsService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) { - Result rc = 0xF601; - - switch ((RoServiceCmd)cmd_id) { - case Ro_Cmd_LoadNro: - rc = WrapIpcCommandImpl<&RelocatableObjectsService::load_nro>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Ro_Cmd_UnloadNro: - rc = WrapIpcCommandImpl<&RelocatableObjectsService::unload_nro>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Ro_Cmd_LoadNrr: - rc = WrapIpcCommandImpl<&RelocatableObjectsService::load_nrr>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Ro_Cmd_UnloadNrr: - rc = WrapIpcCommandImpl<&RelocatableObjectsService::unload_nrr>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Ro_Cmd_Initialize: - rc = WrapIpcCommandImpl<&RelocatableObjectsService::initialize>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - default: - break; - } - - return rc; -} - - -std::tuple<Result, u64> RelocatableObjectsService::load_nro(PidDescriptor pid_desc, u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size) { - Result rc; - u64 out_address = 0; +Result RelocatableObjectsService::LoadNro(Out<u64> load_address, PidDescriptor pid_desc, u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size) { Registration::Process *target_proc = NULL; if (!this->has_initialized || this->process_id != pid_desc.pid) { - rc = 0xAE09; - goto LOAD_NRO_END; + return 0xAE09; } if (nro_address & 0xFFF) { - rc = 0xA209; - goto LOAD_NRO_END; + return 0xA209; } if (nro_address + nro_size <= nro_address || !nro_size || (nro_size & 0xFFF)) { - rc = 0xA409; - goto LOAD_NRO_END; + return 0xA409; } if (bss_size && bss_address + bss_size <= bss_address) { - rc = 0xA409; - goto LOAD_NRO_END; + return 0xA409; } /* Ensure no overflow for combined sizes. */ if (U64_MAX - nro_size < bss_size) { - rc = 0xA409; - goto LOAD_NRO_END; + return 0xA409; } target_proc = Registration::GetProcessByProcessId(pid_desc.pid); if (target_proc == NULL || (target_proc->owner_ro_service != NULL && (RelocatableObjectsService *)(target_proc->owner_ro_service) != this)) { - rc = 0xAC09; - goto LOAD_NRO_END; + return 0xAC09; } target_proc->owner_ro_service = this; - rc = NroUtils::LoadNro(target_proc, this->process_handle, nro_address, nro_size, bss_address, bss_size, &out_address); -LOAD_NRO_END: - return {rc, out_address}; + return NroUtils::LoadNro(target_proc, this->process_handle, nro_address, nro_size, bss_address, bss_size, load_address.GetPointer()); } -std::tuple<Result> RelocatableObjectsService::unload_nro(PidDescriptor pid_desc, u64 nro_address) { +Result RelocatableObjectsService::UnloadNro(PidDescriptor pid_desc, u64 nro_address) { Registration::Process *target_proc = NULL; if (!this->has_initialized || this->process_id != pid_desc.pid) { return 0xAE09; @@ -106,37 +69,42 @@ std::tuple<Result> RelocatableObjectsService::unload_nro(PidDescriptor pid_desc, return Registration::RemoveNroInfo(target_proc->index, this->process_handle, nro_address); } -std::tuple<Result> RelocatableObjectsService::load_nrr(PidDescriptor pid_desc, u64 nrr_address, u64 nrr_size) { - Result rc; +Result RelocatableObjectsService::LoadNrr(PidDescriptor pid_desc, u64 nrr_address, u64 nrr_size) { + Result rc = 0; Registration::Process *target_proc = NULL; MappedCodeMemory nrr_info = {0}; + ON_SCOPE_EXIT { + if (R_FAILED(rc) && nrr_info.IsActive()) { + nrr_info.Close(); + } + }; if (!this->has_initialized || this->process_id != pid_desc.pid) { rc = 0xAE09; - goto LOAD_NRR_END; + return rc; } if (nrr_address & 0xFFF) { rc = 0xA209; - goto LOAD_NRR_END; + return rc; } if (nrr_address + nrr_size <= nrr_address || !nrr_size || (nrr_size & 0xFFF)) { rc = 0xA409; - goto LOAD_NRR_END; + return rc; } target_proc = Registration::GetProcessByProcessId(pid_desc.pid); if (target_proc == NULL || (target_proc->owner_ro_service != NULL && (RelocatableObjectsService *)(target_proc->owner_ro_service) != this)) { rc = 0xAC09; - goto LOAD_NRR_END; + return rc; } target_proc->owner_ro_service = this; if (R_FAILED((rc = nrr_info.Open(this->process_handle, target_proc->is_64_bit_addspace, nrr_address, nrr_size)))) { - goto LOAD_NRR_END; + return rc; } if (R_FAILED((rc = nrr_info.Map()))) { - goto LOAD_NRR_END; + return rc; } rc = NroUtils::ValidateNrrHeader((NroUtils::NrrHeader *)nrr_info.mapped_address, nrr_size, target_proc->title_id); @@ -144,16 +112,10 @@ std::tuple<Result> RelocatableObjectsService::load_nrr(PidDescriptor pid_desc, u Registration::AddNrrInfo(target_proc->index, &nrr_info); } -LOAD_NRR_END: - if (R_FAILED(rc)) { - if (nrr_info.IsActive()) { - nrr_info.Close(); - } - } - return {rc}; + return rc; } -std::tuple<Result> RelocatableObjectsService::unload_nrr(PidDescriptor pid_desc, u64 nrr_address) { +Result RelocatableObjectsService::UnloadNrr(PidDescriptor pid_desc, u64 nrr_address) { Registration::Process *target_proc = NULL; if (!this->has_initialized || this->process_id != pid_desc.pid) { return 0xAE09; @@ -171,9 +133,8 @@ std::tuple<Result> RelocatableObjectsService::unload_nrr(PidDescriptor pid_desc, return Registration::RemoveNrrInfo(target_proc->index, nrr_address); } -std::tuple<Result> RelocatableObjectsService::initialize(PidDescriptor pid_desc, CopiedHandle process_h) { +Result RelocatableObjectsService::Initialize(PidDescriptor pid_desc, CopiedHandle process_h) { u64 handle_pid; - Result rc = 0xAE09; if (R_SUCCEEDED(svcGetProcessId(&handle_pid, process_h.handle)) && handle_pid == pid_desc.pid) { if (this->has_initialized) { svcCloseHandle(this->process_handle); @@ -181,7 +142,7 @@ std::tuple<Result> RelocatableObjectsService::initialize(PidDescriptor pid_desc, this->process_handle = process_h.handle; this->process_id = handle_pid; this->has_initialized = true; - rc = 0; + return 0; } - return {rc}; + return 0xAE09; } diff --git a/stratosphere/loader/source/ldr_ro_service.hpp b/stratosphere/loader/source/ldr_ro_service.hpp index 3e622587e..05bd9d058 100644 --- a/stratosphere/loader/source/ldr_ro_service.hpp +++ b/stratosphere/loader/source/ldr_ro_service.hpp @@ -17,7 +17,7 @@ #pragma once #include <switch.h> -#include <stratosphere/iserviceobject.hpp> +#include <stratosphere.hpp> #include "ldr_registration.hpp" enum RoServiceCmd { @@ -33,27 +33,26 @@ class RelocatableObjectsService final : public IServiceObject { u64 process_id = U64_MAX; bool has_initialized = false; public: - ~RelocatableObjectsService() { + virtual ~RelocatableObjectsService() override { Registration::CloseRoService(this, this->process_handle); if (this->has_initialized) { svcCloseHandle(this->process_handle); } } - Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) override; - Result handle_deferred() override { - /* This service will never defer. */ - return 0; - } - - RelocatableObjectsService *clone() override { - return new RelocatableObjectsService(*this); - } private: /* Actual commands. */ - std::tuple<Result, u64> load_nro(PidDescriptor pid_desc, u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size); - std::tuple<Result> unload_nro(PidDescriptor pid_desc, u64 nro_address); - std::tuple<Result> load_nrr(PidDescriptor pid_desc, u64 nrr_address, u64 nrr_size); - std::tuple<Result> unload_nrr(PidDescriptor pid_desc, u64 nrr_address); - std::tuple<Result> initialize(PidDescriptor pid_desc, CopiedHandle process_h); + Result LoadNro(Out<u64> load_address, PidDescriptor pid_desc, u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size); + Result UnloadNro(PidDescriptor pid_desc, u64 nro_address); + Result LoadNrr(PidDescriptor pid_desc, u64 nrr_address, u64 nrr_size); + Result UnloadNrr(PidDescriptor pid_desc, u64 nrr_address); + Result Initialize(PidDescriptor pid_desc, CopiedHandle process_h); + public: + DEFINE_SERVICE_DISPATCH_TABLE { + MakeServiceCommandMeta<Ro_Cmd_LoadNro, &RelocatableObjectsService::LoadNro>(), + MakeServiceCommandMeta<Ro_Cmd_UnloadNro, &RelocatableObjectsService::UnloadNro>(), + MakeServiceCommandMeta<Ro_Cmd_LoadNrr, &RelocatableObjectsService::LoadNrr>(), + MakeServiceCommandMeta<Ro_Cmd_UnloadNrr, &RelocatableObjectsService::UnloadNrr>(), + MakeServiceCommandMeta<Ro_Cmd_Initialize, &RelocatableObjectsService::Initialize>(), + }; }; diff --git a/stratosphere/loader/source/ldr_shell.cpp b/stratosphere/loader/source/ldr_shell.cpp index 664388d08..4574c5af4 100644 --- a/stratosphere/loader/source/ldr_shell.cpp +++ b/stratosphere/loader/source/ldr_shell.cpp @@ -18,31 +18,30 @@ #include <stratosphere.hpp> #include "ldr_shell.hpp" #include "ldr_launch_queue.hpp" +#include "ldr_content_management.hpp" -Result ShellService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) { - - Result rc = 0xF601; - - switch ((ShellServiceCmd)cmd_id) { - case Shell_Cmd_AddTitleToLaunchQueue: - rc = WrapIpcCommandImpl<&ShellService::add_title_to_launch_queue>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Shell_Cmd_ClearLaunchQueue: - rc = WrapIpcCommandImpl<&ShellService::clear_launch_queue>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - default: - break; +Result ShellService::AddTitleToLaunchQueue(u64 tid, InPointer<char> args, u32 args_size) { + if (args.num_elements < args_size) args_size = args.num_elements; + return LaunchQueue::Add(tid, args.pointer, args_size); +} + +void ShellService::ClearLaunchQueue() { + LaunchQueue::Clear(); +} + +/* SetExternalContentSource extension */ +Result ShellService::SetExternalContentSource(Out<MovedHandle> out, u64 tid) { + Handle server_h; + Handle client_h; + + Result rc; + if (R_FAILED(rc = svcCreateSession(&server_h, &client_h, 0, 0))) { + return rc; } - return rc; -} -std::tuple<Result> ShellService::add_title_to_launch_queue(u64 args_size, u64 tid, InPointer<char> args) { - fprintf(stderr, "Add to launch queue: %p, %zX\n", args.pointer, std::min(args_size, args.num_elements)); - return {LaunchQueue::add(tid, args.pointer, std::min(args_size, args.num_elements))}; -} - -std::tuple<Result> ShellService::clear_launch_queue(u64 dat) { - fprintf(stderr, "Clear launch queue: %lx\n", dat); - LaunchQueue::clear(); - return {0}; + Service service; + serviceCreate(&service, client_h); + ContentManagement::SetExternalContentSource(tid, FsFileSystem {service}); + out.SetValue(server_h); + return 0; } diff --git a/stratosphere/loader/source/ldr_shell.hpp b/stratosphere/loader/source/ldr_shell.hpp index 7cc95f858..69d6f2107 100644 --- a/stratosphere/loader/source/ldr_shell.hpp +++ b/stratosphere/loader/source/ldr_shell.hpp @@ -16,27 +16,27 @@ #pragma once #include <switch.h> -#include <stratosphere/iserviceobject.hpp> +#include <stratosphere.hpp> enum ShellServiceCmd { Shell_Cmd_AddTitleToLaunchQueue = 0, - Shell_Cmd_ClearLaunchQueue = 1 + Shell_Cmd_ClearLaunchQueue = 1, + + Shell_Cmd_AtmosphereSetExternalContentSource = 65000, }; class ShellService final : public IServiceObject { - public: - Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) override; - Result handle_deferred() override { - /* This service will never defer. */ - return 0; - } - - ShellService *clone() override { - return new ShellService(); - } - private: /* Actual commands. */ - std::tuple<Result> add_title_to_launch_queue(u64 args_size, u64 tid, InPointer<char> args); - std::tuple<Result> clear_launch_queue(u64 dat); + Result AddTitleToLaunchQueue(u64 tid, InPointer<char> args, u32 args_size); + void ClearLaunchQueue(); + + /* Atmosphere commands. */ + Result SetExternalContentSource(Out<MovedHandle> out, u64 tid); + public: + DEFINE_SERVICE_DISPATCH_TABLE { + MakeServiceCommandMeta<Shell_Cmd_AddTitleToLaunchQueue, &ShellService::AddTitleToLaunchQueue>(), + MakeServiceCommandMeta<Shell_Cmd_ClearLaunchQueue, &ShellService::ClearLaunchQueue>(), + MakeServiceCommandMeta<Shell_Cmd_AtmosphereSetExternalContentSource, &ShellService::SetExternalContentSource>(), + }; }; diff --git a/stratosphere/pm/Makefile b/stratosphere/pm/Makefile index c819c77fd..c3b31a855 100644 --- a/stratosphere/pm/Makefile +++ b/stratosphere/pm/Makefile @@ -21,7 +21,7 @@ TARGET := $(notdir $(CURDIR)) BUILD := build SOURCES := source DATA := data -INCLUDES := include +INCLUDES := include ../../common/include EXEFS_SRC := exefs_src DEFINES := -DDISABLE_IPC diff --git a/stratosphere/pm/pm.json b/stratosphere/pm/pm.json index 4af73d589..0fd963c2b 100644 --- a/stratosphere/pm/pm.json +++ b/stratosphere/pm/pm.json @@ -1,7 +1,7 @@ { "name": "ProcessMana", "title_id": "0x0100000000000003", - "main_thread_stack_size": "0x00001000", + "main_thread_stack_size": "0x00002000", "main_thread_priority": 49, "default_cpu_id": 3, "process_category": 1, @@ -13,64 +13,64 @@ { "type": "syscalls", "value": { - "svcSetHeapSize": "0x01", - "svcSetMemoryPermission": "0x02", - "svcSetMemoryAttribute": "0x03", - "svcMapMemory": "0x04", - "svcUnmapMemory": "0x05", - "svcQueryMemory": "0x06", - "svcExitProcess": "0x07", - "svcCreateThread": "0x08", - "svcStartThread": "0x09", - "svcExitThread": "0x0a", - "svcSleepThread": "0x0b", - "svcGetThreadPriority": "0x0c", - "svcSetThreadPriority": "0x0d", - "svcGetThreadCoreMask": "0x0e", - "svcSetThreadCoreMask": "0x0f", - "svcGetCurrentProcessorNumber": "0x10", - "svcSignalEvent": "0x11", - "svcClearEvent": "0x12", - "svcMapSharedMemory": "0x13", - "svcUnmapSharedMemory": "0x14", - "svcCreateTransferMemory": "0x15", - "svcCloseHandle": "0x16", - "svcResetSignal": "0x17", - "svcWaitSynchronization": "0x18", - "svcCancelSynchronization": "0x19", - "svcArbitrateLock": "0x1a", - "svcArbitrateUnlock": "0x1b", - "svcWaitProcessWideKeyAtomic": "0x1c", - "svcSignalProcessWideKey": "0x1d", - "svcGetSystemTick": "0x1e", - "svcConnectToNamedPort": "0x1f", - "svcSendSyncRequestLight": "0x20", - "svcSendSyncRequest": "0x21", - "svcSendSyncRequestWithUserBuffer": "0x22", - "svcSendAsyncRequestWithUserBuffer": "0x23", - "svcGetProcessId": "0x24", - "svcGetThreadId": "0x25", - "svcBreak": "0x26", - "svcOutputDebugString": "0x27", - "svcReturnFromException": "0x28", - "svcGetInfo": "0x29", - "svcGetResourceLimitLimitValue": "0x30", - "svcGetResourceLimitCurrentValue": "0x31", - "svcWaitForAddress": "0x34", - "svcSignalToAddress": "0x35", - "svcCreateSession": "0x40", - "svcAcceptSession": "0x41", - "svcReplyAndReceiveLight": "0x42", - "svcReplyAndReceive": "0x43", - "svcReplyAndReceiveWithUserBuffer": "0x44", - "svcCreateEvent": "0x45", - "svcStartProcess": "0x7a", - "svcTerminateProcess": "0x7b", - "svcGetProcessInfo": "0x7c", - "svcCreateResourceLimit": "0x7d", - "svcSetResourceLimitLimitValue": "0x7e", - "svcSetUnsafeLimit": "0x4a", - "svcGetSystemInfo": "0x6f" + "svcSetHeapSize": "0x01", + "svcSetMemoryPermission": "0x02", + "svcSetMemoryAttribute": "0x03", + "svcMapMemory": "0x04", + "svcUnmapMemory": "0x05", + "svcQueryMemory": "0x06", + "svcExitProcess": "0x07", + "svcCreateThread": "0x08", + "svcStartThread": "0x09", + "svcExitThread": "0x0a", + "svcSleepThread": "0x0b", + "svcGetThreadPriority": "0x0c", + "svcSetThreadPriority": "0x0d", + "svcGetThreadCoreMask": "0x0e", + "svcSetThreadCoreMask": "0x0f", + "svcGetCurrentProcessorNumber": "0x10", + "svcSignalEvent": "0x11", + "svcClearEvent": "0x12", + "svcMapSharedMemory": "0x13", + "svcUnmapSharedMemory": "0x14", + "svcCreateTransferMemory": "0x15", + "svcCloseHandle": "0x16", + "svcResetSignal": "0x17", + "svcWaitSynchronization": "0x18", + "svcCancelSynchronization": "0x19", + "svcArbitrateLock": "0x1a", + "svcArbitrateUnlock": "0x1b", + "svcWaitProcessWideKeyAtomic": "0x1c", + "svcSignalProcessWideKey": "0x1d", + "svcGetSystemTick": "0x1e", + "svcConnectToNamedPort": "0x1f", + "svcSendSyncRequestLight": "0x20", + "svcSendSyncRequest": "0x21", + "svcSendSyncRequestWithUserBuffer": "0x22", + "svcSendAsyncRequestWithUserBuffer": "0x23", + "svcGetProcessId": "0x24", + "svcGetThreadId": "0x25", + "svcBreak": "0x26", + "svcOutputDebugString": "0x27", + "svcReturnFromException": "0x28", + "svcGetInfo": "0x29", + "svcGetResourceLimitLimitValue": "0x30", + "svcGetResourceLimitCurrentValue": "0x31", + "svcWaitForAddress": "0x34", + "svcSignalToAddress": "0x35", + "svcCreateSession": "0x40", + "svcAcceptSession": "0x41", + "svcReplyAndReceiveLight": "0x42", + "svcReplyAndReceive": "0x43", + "svcReplyAndReceiveWithUserBuffer": "0x44", + "svcCreateEvent": "0x45", + "svcSetUnsafeLimit": "0x4a", + "svcStartProcess": "0x7a", + "svcTerminateProcess": "0x7b", + "svcGetProcessInfo": "0x7c", + "svcCreateResourceLimit": "0x7d", + "svcSetResourceLimitLimitValue": "0x7e", + "svcGetSystemInfo": "0x6f" } } ] diff --git a/stratosphere/pm/source/pm_boot2.cpp b/stratosphere/pm/source/pm_boot2.cpp index 2f22c9d11..3a6844621 100644 --- a/stratosphere/pm/source/pm_boot2.cpp +++ b/stratosphere/pm/source/pm_boot2.cpp @@ -173,7 +173,7 @@ void EmbeddedBoot2::Main() { } closedir(titles_dir); } - + /* We no longer need the SD card. */ fsdevUnmountAll(); } diff --git a/stratosphere/pm/source/pm_boot_mode.cpp b/stratosphere/pm/source/pm_boot_mode.cpp index 7b83ee1e8..b8158acf9 100644 --- a/stratosphere/pm/source/pm_boot_mode.cpp +++ b/stratosphere/pm/source/pm_boot_mode.cpp @@ -20,33 +20,10 @@ static bool g_is_maintenance_boot = false; -Result BootModeService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) { - Result rc = 0xF601; - - switch ((BootModeCmd)cmd_id) { - case BootMode_Cmd_GetBootMode: - rc = WrapIpcCommandImpl<&BootModeService::get_boot_mode>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case BootMode_Cmd_SetMaintenanceBoot: - rc = WrapIpcCommandImpl<&BootModeService::set_maintenance_boot>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - default: - break; - } - - return rc; +void BootModeService::GetBootMode(Out<u32> out) { + out.SetValue(g_is_maintenance_boot); } -Result BootModeService::handle_deferred() { - /* This service is never deferrable. */ - return 0; -} - -std::tuple<Result, bool> BootModeService::get_boot_mode() { - return {0, g_is_maintenance_boot}; -} - -std::tuple<Result> BootModeService::set_maintenance_boot() { +void BootModeService::SetMaintenanceBoot() { g_is_maintenance_boot = true; - return {0}; } diff --git a/stratosphere/pm/source/pm_boot_mode.hpp b/stratosphere/pm/source/pm_boot_mode.hpp index 097dace3a..1aadf8c42 100644 --- a/stratosphere/pm/source/pm_boot_mode.hpp +++ b/stratosphere/pm/source/pm_boot_mode.hpp @@ -16,24 +16,21 @@ #pragma once #include <switch.h> -#include <stratosphere/iserviceobject.hpp> +#include <stratosphere.hpp> enum BootModeCmd { BootMode_Cmd_GetBootMode = 0, BootMode_Cmd_SetMaintenanceBoot = 1 }; -class BootModeService final : public IServiceObject { - public: - Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) override; - Result handle_deferred() override; - - BootModeService *clone() override { - return new BootModeService(*this); - } - +class BootModeService final : public IServiceObject { private: /* Actual commands. */ - std::tuple<Result, bool> get_boot_mode(); - std::tuple<Result> set_maintenance_boot(); + void GetBootMode(Out<u32> out); + void SetMaintenanceBoot(); + public: + DEFINE_SERVICE_DISPATCH_TABLE { + MakeServiceCommandMeta<BootMode_Cmd_GetBootMode, &BootModeService::GetBootMode>(), + MakeServiceCommandMeta<BootMode_Cmd_SetMaintenanceBoot, &BootModeService::SetMaintenanceBoot>(), + }; }; diff --git a/stratosphere/pm/source/pm_debug_monitor.cpp b/stratosphere/pm/source/pm_debug_monitor.cpp index 95362c1ea..a9d4312d2 100644 --- a/stratosphere/pm/source/pm_debug_monitor.cpp +++ b/stratosphere/pm/source/pm_debug_monitor.cpp @@ -17,144 +17,91 @@ #include <switch.h> #include <stratosphere.hpp> #include "pm_registration.hpp" +#include "pm_resource_limits.hpp" #include "pm_debug_monitor.hpp" -Result DebugMonitorService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) { - Result rc = 0xF601; - if (kernelAbove500()) { - switch ((DmntCmd_5X)cmd_id) { - case Dmnt_Cmd_5X_GetDebugProcessIds: - rc = WrapIpcCommandImpl<&DebugMonitorService::get_debug_process_ids>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Dmnt_Cmd_5X_LaunchDebugProcess: - rc = WrapIpcCommandImpl<&DebugMonitorService::launch_debug_process>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Dmnt_Cmd_5X_GetTitleProcessId: - rc = WrapIpcCommandImpl<&DebugMonitorService::get_title_process_id>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Dmnt_Cmd_5X_EnableDebugForTitleId: - rc = WrapIpcCommandImpl<&DebugMonitorService::enable_debug_for_tid>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Dmnt_Cmd_5X_GetApplicationProcessId: - rc = WrapIpcCommandImpl<&DebugMonitorService::get_application_process_id>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Dmnt_Cmd_5X_EnableDebugForApplication: - rc = WrapIpcCommandImpl<&DebugMonitorService::enable_debug_for_application>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Dmnt_Cmd_6X_DisableDebug: - if (kernelAbove600()) { - rc = WrapIpcCommandImpl<&DebugMonitorService::disable_debug>(this, r, out_c, pointer_buffer, pointer_buffer_size); - } - break; - case Dmnt_Cmd_5X_AtmosphereGetProcessHandle: - rc = WrapIpcCommandImpl<&DebugMonitorService::get_process_handle>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - default: - break; - } - } else { - switch ((DmntCmd)cmd_id) { - case Dmnt_Cmd_GetUnknownStub: - rc = WrapIpcCommandImpl<&DebugMonitorService::get_unknown_stub>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Dmnt_Cmd_GetDebugProcessIds: - rc = WrapIpcCommandImpl<&DebugMonitorService::get_debug_process_ids>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Dmnt_Cmd_LaunchDebugProcess: - rc = WrapIpcCommandImpl<&DebugMonitorService::launch_debug_process>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Dmnt_Cmd_GetTitleProcessId: - rc = WrapIpcCommandImpl<&DebugMonitorService::get_title_process_id>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Dmnt_Cmd_EnableDebugForTitleId: - rc = WrapIpcCommandImpl<&DebugMonitorService::enable_debug_for_tid>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Dmnt_Cmd_GetApplicationProcessId: - rc = WrapIpcCommandImpl<&DebugMonitorService::get_application_process_id>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Dmnt_Cmd_EnableDebugForApplication: - rc = WrapIpcCommandImpl<&DebugMonitorService::enable_debug_for_application>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Dmnt_Cmd_AtmosphereGetProcessHandle: - rc = WrapIpcCommandImpl<&DebugMonitorService::get_process_handle>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - default: - break; - } + +Result DebugMonitorService::GetUnknownStub(Out<u32> count, OutBuffer<u8> out_buf, u64 in_unk) { + /* This command seems stubbed. */ + if (out_buf.num_elements >> 31) { + return 0xC0F; } - return rc; + count.SetValue(0); + return 0x0; } -Result DebugMonitorService::handle_deferred() { - /* This service is never deferrable. */ - return 0; -} - - -std::tuple<Result, u32> DebugMonitorService::get_unknown_stub(u64 unknown, OutBuffer<u8> out_unknown) { - /* This command seem stubbed on retail. */ - if (out_unknown.num_elements >> 31) { - return {0xC0F, 0}; - } - return {0x0, 0}; -} - -std::tuple<Result, u32> DebugMonitorService::get_debug_process_ids(OutBuffer<u64> out_pids) { - u32 num_out = 0; - Result rc; +Result DebugMonitorService::GetDebugProcessIds(Out<u32> count, OutBuffer<u64> out_pids) { if (out_pids.num_elements >> 31) { - return {0xC0F, 0}; + return 0xC0F; } - rc = Registration::GetDebugProcessIds(out_pids.buffer, out_pids.num_elements, &num_out); - return {rc, num_out}; + return Registration::GetDebugProcessIds(out_pids.buffer, out_pids.num_elements, count.GetPointer()); } -std::tuple<Result> DebugMonitorService::launch_debug_process(u64 pid) { - return {Registration::LaunchDebugProcess(pid)}; +Result DebugMonitorService::LaunchDebugProcess(u64 pid) { + return Registration::LaunchDebugProcess(pid); } -std::tuple<Result, u64> DebugMonitorService::get_title_process_id(u64 tid) { +Result DebugMonitorService::GetTitleProcessId(Out<u64> pid, u64 tid) { auto auto_lock = Registration::GetProcessListUniqueLock(); std::shared_ptr<Registration::Process> proc = Registration::GetProcessByTitleId(tid); if (proc != nullptr) { - return {0, proc->pid}; - } else { - return {0x20F, 0}; + pid.SetValue(proc->pid); + return 0; } + return 0x20F; } -std::tuple<Result, CopiedHandle> DebugMonitorService::enable_debug_for_tid(u64 tid) { - Handle h = 0; - Result rc = Registration::EnableDebugForTitleId(tid, &h); - return {rc, h}; +Result DebugMonitorService::EnableDebugForTitleId(Out<CopiedHandle> event, u64 tid) { + return Registration::EnableDebugForTitleId(tid, event.GetHandlePointer()); } -std::tuple<Result, u64> DebugMonitorService::get_application_process_id() { +Result DebugMonitorService::GetApplicationProcessId(Out<u64> pid) { auto auto_lock = Registration::GetProcessListUniqueLock(); std::shared_ptr<Registration::Process> app_proc; if (Registration::HasApplicationProcess(&app_proc)) { - return {0, app_proc->pid}; + pid.SetValue(app_proc->pid); + return 0x0; } - return {0x20F, 0}; + return 0x20F; } -std::tuple<Result, CopiedHandle> DebugMonitorService::enable_debug_for_application() { - Handle h = 0; - Result rc = Registration::EnableDebugForApplication(&h); - return {rc, h}; +Result DebugMonitorService::EnableDebugForApplication(Out<CopiedHandle> event) { + return Registration::EnableDebugForApplication(event.GetHandlePointer()); } -std::tuple<Result> DebugMonitorService::disable_debug(u32 which) { - return {Registration::DisableDebug(which)}; +Result DebugMonitorService::DisableDebug(u32 which) { + return Registration::DisableDebug(which); } -std::tuple<Result, CopiedHandle> DebugMonitorService::get_process_handle(u64 pid) { - std::shared_ptr<Registration::Process> proc = Registration::GetProcess(pid); - if(proc == NULL) { - return {0x20F, 0}; +Result DebugMonitorService::AtmosphereGetProcessHandle(Out<CopiedHandle> proc_hand, u64 pid) { + auto proc = Registration::GetProcess(pid); + if(proc != nullptr) { + proc_hand.SetValue(proc->handle); + return 0; } - return {0, proc->handle}; + return 0x20F; +} + +Result DebugMonitorService::AtmosphereGetCurrentLimitInfo(Out<u64> cur_val, Out<u64> lim_val, u32 category, u32 resource) { + Result rc; + if(category > ResourceLimitUtils::ResourceLimitCategory::ResourceLimitCategory_Applet) { + return 0xF001; + } + + Handle limit_h = ResourceLimitUtils::GetResourceLimitHandleByCategory((ResourceLimitUtils::ResourceLimitCategory) category); + + rc = svcGetResourceLimitCurrentValue(cur_val.GetPointer(), limit_h, (LimitableResource) resource); + if(R_FAILED(rc)) { + return rc; + } + + rc = svcGetResourceLimitLimitValue(lim_val.GetPointer(), limit_h, (LimitableResource) resource); + if(R_FAILED(rc)) { + return rc; + } + + return 0; } diff --git a/stratosphere/pm/source/pm_debug_monitor.hpp b/stratosphere/pm/source/pm_debug_monitor.hpp index ee6c66b12..88445bc60 100644 --- a/stratosphere/pm/source/pm_debug_monitor.hpp +++ b/stratosphere/pm/source/pm_debug_monitor.hpp @@ -16,7 +16,7 @@ #pragma once #include <switch.h> -#include <stratosphere/iserviceobject.hpp> +#include <stratosphere.hpp> #include "pm_registration.hpp" @@ -28,11 +28,7 @@ enum DmntCmd { Dmnt_Cmd_EnableDebugForTitleId = 4, Dmnt_Cmd_GetApplicationProcessId = 5, Dmnt_Cmd_EnableDebugForApplication = 6, - - Dmnt_Cmd_AtmosphereGetProcessHandle = 65000 -}; - -enum DmntCmd_5X { + Dmnt_Cmd_5X_GetDebugProcessIds = 0, Dmnt_Cmd_5X_LaunchDebugProcess = 1, Dmnt_Cmd_5X_GetTitleProcessId = 2, @@ -42,29 +38,49 @@ enum DmntCmd_5X { Dmnt_Cmd_6X_DisableDebug = 6, - Dmnt_Cmd_5X_AtmosphereGetProcessHandle = 65000 + Dmnt_Cmd_AtmosphereGetProcessHandle = 65000, + Dmnt_Cmd_AtmosphereGetCurrentLimitInfo = 65001, }; class DebugMonitorService final : public IServiceObject { - public: - Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) override; - Result handle_deferred() override; - - DebugMonitorService *clone() override { - return new DebugMonitorService(*this); - } - private: /* Actual commands. */ - std::tuple<Result, u32> get_unknown_stub(u64 unknown, OutBuffer<u8> out_unknown); - std::tuple<Result, u32> get_debug_process_ids(OutBuffer<u64> out_processes); - std::tuple<Result> launch_debug_process(u64 pid); - std::tuple<Result, u64> get_title_process_id(u64 tid); - std::tuple<Result, CopiedHandle> enable_debug_for_tid(u64 tid); - std::tuple<Result, u64> get_application_process_id(); - std::tuple<Result, CopiedHandle> enable_debug_for_application(); - std::tuple<Result> disable_debug(u32 which); + Result GetUnknownStub(Out<u32> count, OutBuffer<u8> out_buf, u64 in_unk); + Result GetDebugProcessIds(Out<u32> count, OutBuffer<u64> out_pids); + Result LaunchDebugProcess(u64 pid); + Result GetTitleProcessId(Out<u64> pid, u64 tid); + Result EnableDebugForTitleId(Out<CopiedHandle> event, u64 tid); + Result GetApplicationProcessId(Out<u64> pid); + Result EnableDebugForApplication(Out<CopiedHandle> event); + Result DisableDebug(u32 which); /* Atmosphere commands. */ - std::tuple<Result, CopiedHandle> get_process_handle(u64 pid); + Result AtmosphereGetProcessHandle(Out<CopiedHandle> proc_hand, u64 pid); + Result AtmosphereGetCurrentLimitInfo(Out<u64> cur_val, Out<u64> lim_val, u32 category, u32 resource); + public: + DEFINE_SERVICE_DISPATCH_TABLE { + /* 1.0.0-4.1.0 */ + MakeServiceCommandMeta<Dmnt_Cmd_GetUnknownStub, &DebugMonitorService::GetUnknownStub, FirmwareVersion_Min, FirmwareVersion_400>(), + MakeServiceCommandMeta<Dmnt_Cmd_GetDebugProcessIds, &DebugMonitorService::GetDebugProcessIds, FirmwareVersion_Min, FirmwareVersion_400>(), + MakeServiceCommandMeta<Dmnt_Cmd_LaunchDebugProcess, &DebugMonitorService::LaunchDebugProcess, FirmwareVersion_Min, FirmwareVersion_400>(), + MakeServiceCommandMeta<Dmnt_Cmd_GetTitleProcessId, &DebugMonitorService::GetTitleProcessId, FirmwareVersion_Min, FirmwareVersion_400>(), + MakeServiceCommandMeta<Dmnt_Cmd_EnableDebugForTitleId, &DebugMonitorService::EnableDebugForTitleId, FirmwareVersion_Min, FirmwareVersion_400>(), + MakeServiceCommandMeta<Dmnt_Cmd_GetApplicationProcessId, &DebugMonitorService::GetApplicationProcessId, FirmwareVersion_Min, FirmwareVersion_400>(), + MakeServiceCommandMeta<Dmnt_Cmd_EnableDebugForApplication, &DebugMonitorService::EnableDebugForApplication, FirmwareVersion_Min, FirmwareVersion_400>(), + + /* 5.0.0-* */ + MakeServiceCommandMeta<Dmnt_Cmd_5X_GetDebugProcessIds, &DebugMonitorService::GetDebugProcessIds, FirmwareVersion_500>(), + MakeServiceCommandMeta<Dmnt_Cmd_5X_LaunchDebugProcess, &DebugMonitorService::LaunchDebugProcess, FirmwareVersion_500>(), + MakeServiceCommandMeta<Dmnt_Cmd_5X_GetTitleProcessId, &DebugMonitorService::GetTitleProcessId, FirmwareVersion_500>(), + MakeServiceCommandMeta<Dmnt_Cmd_5X_EnableDebugForTitleId, &DebugMonitorService::EnableDebugForTitleId, FirmwareVersion_500>(), + MakeServiceCommandMeta<Dmnt_Cmd_5X_GetApplicationProcessId, &DebugMonitorService::GetApplicationProcessId, FirmwareVersion_500>(), + MakeServiceCommandMeta<Dmnt_Cmd_5X_EnableDebugForApplication, &DebugMonitorService::EnableDebugForApplication, FirmwareVersion_500>(), + + /* 6.0.0-* */ + MakeServiceCommandMeta<Dmnt_Cmd_6X_DisableDebug, &DebugMonitorService::DisableDebug, FirmwareVersion_600>(), + + /* Atmosphere extensions. */ + MakeServiceCommandMeta<Dmnt_Cmd_AtmosphereGetProcessHandle, &DebugMonitorService::AtmosphereGetProcessHandle>(), + MakeServiceCommandMeta<Dmnt_Cmd_AtmosphereGetCurrentLimitInfo, &DebugMonitorService::AtmosphereGetCurrentLimitInfo>(), + }; }; diff --git a/stratosphere/pm/source/pm_info.cpp b/stratosphere/pm/source/pm_info.cpp index 437c75a8c..4498a9f1a 100644 --- a/stratosphere/pm/source/pm_info.cpp +++ b/stratosphere/pm/source/pm_info.cpp @@ -18,32 +18,13 @@ #include "pm_registration.hpp" #include "pm_info.hpp" -Result InformationService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) { - Result rc = 0xF601; - - switch ((InformationCmd)cmd_id) { - case Information_Cmd_GetTitleId: - rc = WrapIpcCommandImpl<&InformationService::get_title_id>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - default: - break; - } - - return rc; -} - -Result InformationService::handle_deferred() { - /* This service is never deferrable. */ - return 0; -} - -std::tuple<Result, u64> InformationService::get_title_id(u64 pid) { +Result InformationService::GetTitleId(Out<u64> tid, u64 pid) { auto auto_lock = Registration::GetProcessListUniqueLock(); std::shared_ptr<Registration::Process> proc = Registration::GetProcess(pid); if (proc != NULL) { - return {0x0, proc->tid_sid.title_id}; - } else { - return {0x20F, 0x0}; + tid.SetValue(proc->tid_sid.title_id); + return 0; } + return 0x20F; } diff --git a/stratosphere/pm/source/pm_info.hpp b/stratosphere/pm/source/pm_info.hpp index bc7ce5cd9..ea0879576 100644 --- a/stratosphere/pm/source/pm_info.hpp +++ b/stratosphere/pm/source/pm_info.hpp @@ -17,22 +17,17 @@ #pragma once #include <switch.h> #include <stratosphere.hpp> -#include <stratosphere/iserviceobject.hpp> enum InformationCmd { Information_Cmd_GetTitleId = 0, }; class InformationService final : public IServiceObject { - public: - Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) override; - Result handle_deferred() override; - - InformationService *clone() override { - return new InformationService(*this); - } - private: /* Actual commands. */ - std::tuple<Result, u64> get_title_id(u64 pid); + Result GetTitleId(Out<u64> tid, u64 pid); + public: + DEFINE_SERVICE_DISPATCH_TABLE { + MakeServiceCommandMeta<Information_Cmd_GetTitleId, &InformationService::GetTitleId>(), + }; }; diff --git a/stratosphere/pm/source/pm_main.cpp b/stratosphere/pm/source/pm_main.cpp index 04200ba15..2e15f12c8 100644 --- a/stratosphere/pm/source/pm_main.cpp +++ b/stratosphere/pm/source/pm_main.cpp @@ -56,6 +56,20 @@ void __libnx_initheap(void) { fake_heap_end = (char*)addr + size; } +void RegisterPrivilegedProcessesWithFs() { + /* Ensures that all privileged processes are registered with full FS permissions. */ + constexpr u64 PRIVILEGED_PROCESS_MIN = 0; + constexpr u64 PRIVILEGED_PROCESS_MAX = 0x4F; + + const u32 PRIVILEGED_FAH[0x1C/sizeof(u32)] = {0x00000001, 0x00000000, 0x80000000, 0x0000001C, 0x00000000, 0x0000001C, 0x00000000}; + const u32 PRIVILEGED_FAC[0x2C/sizeof(u32)] = {0x00000001, 0x00000000, 0x80000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF}; + + for (u64 pid = PRIVILEGED_PROCESS_MIN; pid <= PRIVILEGED_PROCESS_MAX; pid++) { + fsprUnregisterProgram(pid); + fsprRegisterProgram(pid, pid, FsStorageId_NandSystem, PRIVILEGED_FAH, sizeof(PRIVILEGED_FAH), PRIVILEGED_FAC, sizeof(PRIVILEGED_FAC)); + } +} + void __appInit(void) { Result rc; @@ -64,27 +78,33 @@ void __appInit(void) { fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_SM)); } - rc = fsInitialize(); - if (R_FAILED(rc)) { - fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_FS)); - } - - rc = lrInitialize(); + rc = fsprInitialize(); if (R_FAILED(rc)) { fatalSimple(0xCAFE << 4 | 1); } - rc = fsprInitialize(); - if (R_FAILED(rc)) { + /* This works around a bug with process permissions on < 4.0.0. */ + RegisterPrivilegedProcessesWithFs(); + + rc = smManagerAmsInitialize(); + if (R_SUCCEEDED(rc)) { + smManagerAmsEndInitialDefers(); + smManagerAmsExit(); + } else { fatalSimple(0xCAFE << 4 | 2); } - rc = ldrPmInitialize(); + rc = smManagerInitialize(); + if (R_FAILED(rc)) { + fatalSimple(0xCAFE << 4 | 3); + } + + rc = lrInitialize(); if (R_FAILED(rc)) { fatalSimple(0xCAFE << 4 | 4); } - rc = smManagerInitialize(); + rc = ldrPmInitialize(); if (R_FAILED(rc)) { fatalSimple(0xCAFE << 4 | 5); } @@ -94,12 +114,12 @@ void __appInit(void) { fatalSimple(0xCAFE << 4 | 6); } - /* Check for exosphere API compatibility. */ - u64 exosphere_cfg; - if (R_FAILED(splGetConfig((SplConfigItem)65000, &exosphere_cfg))) { - fatalSimple(0xCAFE << 4 | 0xFF); - /* TODO: Does PM need to know about target firmware/master key revision? If so, extract from exosphere_cfg. */ + rc = fsInitialize(); + if (R_FAILED(rc)) { + fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_FS)); } + + CheckAtmosphereVersion(); } void __appExit(void) { @@ -129,16 +149,16 @@ int main(int argc, char **argv) } /* TODO: What's a good timeout value to use here? */ - WaitableManager *server_manager = new WaitableManager(U64_MAX); + auto server_manager = new WaitableManager(1); /* TODO: Create services. */ - server_manager->add_waitable(new ServiceServer<ShellService>("pm:shell", 3)); - server_manager->add_waitable(new ServiceServer<DebugMonitorService>("pm:dmnt", 2)); - server_manager->add_waitable(new ServiceServer<BootModeService>("pm:bm", 5)); - server_manager->add_waitable(new ServiceServer<InformationService>("pm:info", 1)); + server_manager->AddWaitable(new ServiceServer<ShellService>("pm:shell", 3)); + server_manager->AddWaitable(new ServiceServer<DebugMonitorService>("pm:dmnt", 2)); + server_manager->AddWaitable(new ServiceServer<BootModeService>("pm:bm", 5)); + server_manager->AddWaitable(new ServiceServer<InformationService>("pm:info", 1)); /* Loop forever, servicing our services. */ - server_manager->process(); + server_manager->Process(); /* Cleanup. */ delete server_manager; diff --git a/stratosphere/pm/source/pm_process_track.cpp b/stratosphere/pm/source/pm_process_track.cpp index 6de7f8603..bfb2aa623 100644 --- a/stratosphere/pm/source/pm_process_track.cpp +++ b/stratosphere/pm/source/pm_process_track.cpp @@ -21,12 +21,11 @@ void ProcessTracking::MainLoop(void *arg) { /* Make a new waitable manager. */ - MultiThreadedWaitableManager *process_waiter = new MultiThreadedWaitableManager(1, U64_MAX); - process_waiter->add_waitable(Registration::GetProcessLaunchStartEvent()); - Registration::SetProcessListManager(process_waiter); + auto process_waiter = new WaitableManager(1); + process_waiter->AddWaitable(Registration::GetProcessLaunchStartEvent()); /* Service processes. */ - process_waiter->process(); + process_waiter->Process(); delete process_waiter; svcExitThread(); diff --git a/stratosphere/pm/source/pm_process_wait.hpp b/stratosphere/pm/source/pm_process_wait.hpp index 49a85a594..14df0468a 100644 --- a/stratosphere/pm/source/pm_process_wait.hpp +++ b/stratosphere/pm/source/pm_process_wait.hpp @@ -28,41 +28,28 @@ class ProcessWaiter final : public IWaitable { /* ... */ } - std::shared_ptr<Registration::Process> get_process() { + std::shared_ptr<Registration::Process> GetProcess() { return this->process; } /* IWaitable */ - Handle get_handle() override { + Handle GetHandle() override { return this->process->handle; } - void handle_deferred() override { - /* TODO: Panic, because we can never be deferred. */ - } - - Result handle_signaled(u64 timeout) override { - return Registration::HandleSignaledProcess(this->get_process()); + Result HandleSignaled(u64 timeout) override { + return Registration::HandleSignaledProcess(this->GetProcess()); } }; class ProcessList final { private: HosRecursiveMutex mutex; - WaitableManager *manager; public: std::vector<std::shared_ptr<Registration::Process>> processes; - auto get_unique_lock() { + auto GetUniqueLock() { return std::unique_lock{this->mutex}; } - - void set_manager(WaitableManager *manager) { - this->manager = manager; - } - - WaitableManager *get_manager() { - return this->manager; - } }; diff --git a/stratosphere/pm/source/pm_registration.cpp b/stratosphere/pm/source/pm_registration.cpp index 4e3c8cfff..529b892e8 100644 --- a/stratosphere/pm/source/pm_registration.cpp +++ b/stratosphere/pm/source/pm_registration.cpp @@ -25,7 +25,7 @@ static ProcessList g_process_list; static ProcessList g_dead_process_list; -static SystemEvent *g_process_launch_start_event = NULL; +static IEvent *g_process_launch_start_event = nullptr; static HosSemaphore g_sema_finish_launch; static HosMutex g_process_launch_mutex; @@ -34,29 +34,27 @@ static Registration::ProcessLaunchState g_process_launch_state; static std::atomic_bool g_debug_next_application(false); static std::atomic<u64> g_debug_on_launch_tid(0); -static SystemEvent *g_process_event = NULL; -static SystemEvent *g_debug_title_event = NULL; -static SystemEvent *g_debug_application_event = NULL; +static IEvent *g_process_event = nullptr; +static IEvent *g_debug_title_event = nullptr; +static IEvent *g_debug_application_event = nullptr; std::unique_lock<HosRecursiveMutex> Registration::GetProcessListUniqueLock() { - return g_process_list.get_unique_lock(); -} - -void Registration::SetProcessListManager(WaitableManager *m) { - g_process_list.set_manager(m); + return g_process_list.GetUniqueLock(); } void Registration::InitializeSystemResources() { - g_process_event = new SystemEvent(NULL, &IEvent::PanicCallback); - g_debug_title_event = new SystemEvent(NULL, &IEvent::PanicCallback); - g_debug_application_event = new SystemEvent(NULL, &IEvent::PanicCallback); - g_process_launch_start_event = new SystemEvent(NULL, &Registration::ProcessLaunchStartCallback); + g_process_event = CreateWriteOnlySystemEvent(); + g_debug_title_event = CreateWriteOnlySystemEvent(); + g_debug_application_event = CreateWriteOnlySystemEvent(); + + /* Auto-clear non-system event. */ + g_process_launch_start_event = CreateSystemEvent(&Registration::ProcessLaunchStartCallback); ResourceLimitUtils::InitializeLimits(); } -Result Registration::ProcessLaunchStartCallback(void *arg, Handle *handles, size_t num_handles, u64 timeout) { - svcClearEvent(handles[0]); +Result Registration::ProcessLaunchStartCallback(u64 timeout) { + g_process_launch_start_event->Clear(); Registration::HandleProcessLaunch(); return 0; } @@ -138,11 +136,11 @@ void Registration::HandleProcessLaunch() { /* Signal, if relevant. */ if (new_process.tid_sid.title_id == g_debug_on_launch_tid.load()) { - g_debug_title_event->signal_event(); + g_debug_title_event->Signal(); g_debug_on_launch_tid = 0; rc = 0; } else if ((new_process.flags & PROCESSFLAGS_APPLICATION) && g_debug_next_application.load()) { - g_debug_application_event->signal_event(); + g_debug_application_event->Signal(); g_debug_next_application = false; rc = 0; } else if (LAUNCHFLAGS_STARTSUSPENDED(launch_flags)) { @@ -151,7 +149,7 @@ void Registration::HandleProcessLaunch() { rc = svcStartProcess(new_process.handle, program_info.main_thread_priority, program_info.default_cpu_id, program_info.main_thread_stack_size); if (R_SUCCEEDED(rc)) { - SetProcessState(new_process.pid, ProcessState_DebugDetached); + SetProcessState(new_process.pid, ProcessState_Running); } } @@ -181,6 +179,7 @@ HANDLE_PROCESS_LAUNCH_END: if (R_SUCCEEDED(rc)) { *out_pid = new_process.pid; } + g_sema_finish_launch.Signal(); } @@ -195,7 +194,7 @@ Result Registration::LaunchDebugProcess(u64 pid) { return 0x20F; } - if (proc->state >= ProcessState_DebugDetached) { + if (proc->state >= ProcessState_Running) { return 0x40F; } @@ -205,7 +204,7 @@ Result Registration::LaunchDebugProcess(u64 pid) { } if (R_SUCCEEDED((rc = svcStartProcess(proc->handle, program_info.main_thread_priority, program_info.default_cpu_id, program_info.main_thread_stack_size)))) { - proc->state = ProcessState_DebugDetached; + proc->state = ProcessState_Running; } return rc; @@ -220,9 +219,9 @@ Result Registration::LaunchProcess(u64 title_id, FsStorageId storage_id, u64 lau g_process_launch_state.out_pid = out_pid; /* Start a launch, and wait for it to exit. */ - g_process_launch_start_event->signal_event(); + g_process_launch_start_event->Signal(); g_sema_finish_launch.Wait(); - + return g_process_launch_state.result; } @@ -246,14 +245,14 @@ Result Registration::HandleSignaledProcess(std::shared_ptr<Registration::Process } switch (process->state) { case ProcessState_Created: - case ProcessState_DebugAttached: + case ProcessState_CreatedAttached: case ProcessState_Exiting: break; - case ProcessState_DebugDetached: + case ProcessState_Running: if (process->flags & PROCESSFLAGS_NOTIFYDEBUGEVENTS) { process->flags &= ~(PROCESSFLAGS_DEBUGEVENTPENDING | PROCESSFLAGS_DEBUGSUSPENDED); process->flags |= PROCESSFLAGS_DEBUGEVENTPENDING; - g_process_event->signal_event(); + g_process_event->Signal(); } if (kernelAbove200() && process->flags & PROCESSFLAGS_NOTIFYDEBUGSPECIAL) { process->flags &= ~(PROCESSFLAGS_NOTIFYDEBUGSPECIAL | PROCESSFLAGS_DEBUGDETACHED); @@ -262,18 +261,18 @@ Result Registration::HandleSignaledProcess(std::shared_ptr<Registration::Process break; case ProcessState_Crashed: process->flags |= (PROCESSFLAGS_CRASHED | PROCESSFLAGS_CRASH_DEBUG); - g_process_event->signal_event(); + g_process_event->Signal(); break; - case ProcessState_Running: + case ProcessState_RunningAttached: if (process->flags & PROCESSFLAGS_NOTIFYDEBUGEVENTS) { process->flags &= ~(PROCESSFLAGS_DEBUGEVENTPENDING | PROCESSFLAGS_DEBUGSUSPENDED); process->flags |= PROCESSFLAGS_DEBUGEVENTPENDING; - g_process_event->signal_event(); + g_process_event->Signal(); } break; case ProcessState_Exited: if (process->flags & PROCESSFLAGS_NOTIFYWHENEXITED && !kernelAbove500()) { - g_process_event->signal_event(); + g_process_event->Signal(); } else { FinalizeExitedProcess(process); } @@ -281,7 +280,7 @@ Result Registration::HandleSignaledProcess(std::shared_ptr<Registration::Process case ProcessState_DebugSuspended: if (process->flags & PROCESSFLAGS_NOTIFYDEBUGEVENTS) { process->flags |= (PROCESSFLAGS_DEBUGEVENTPENDING | PROCESSFLAGS_DEBUGSUSPENDED); - g_process_event->signal_event(); + g_process_event->Signal(); } break; } @@ -310,7 +309,7 @@ void Registration::FinalizeExitedProcess(std::shared_ptr<Registration::Process> /* Insert into dead process list, if relevant. */ if (signal_debug_process_5x) { - auto lk = g_dead_process_list.get_unique_lock(); + auto lk = g_dead_process_list.GetUniqueLock(); g_dead_process_list.processes.push_back(process); } @@ -319,14 +318,14 @@ void Registration::FinalizeExitedProcess(std::shared_ptr<Registration::Process> auto_lock.unlock(); if (signal_debug_process_5x) { - g_process_event->signal_event(); + g_process_event->Signal(); } } void Registration::AddProcessToList(std::shared_ptr<Registration::Process> process) { auto auto_lock = GetProcessListUniqueLock(); g_process_list.processes.push_back(process); - g_process_list.get_manager()->add_waitable(new ProcessWaiter(process)); + g_process_launch_start_event->GetManager()->AddWaitable(new ProcessWaiter(process)); } void Registration::RemoveProcessFromList(u64 pid) { @@ -412,14 +411,14 @@ Result Registration::GetDebugProcessIds(u64 *out_pids, u32 max_out, u32 *num_out } Handle Registration::GetProcessEventHandle() { - return g_process_event->get_handle(); + return g_process_event->GetHandle(); } void Registration::GetProcessEventType(u64 *out_pid, u64 *out_type) { auto auto_lock = GetProcessListUniqueLock(); for (auto &p : g_process_list.processes) { - if (kernelAbove200() && p->state >= ProcessState_DebugDetached && p->flags & PROCESSFLAGS_DEBUGDETACHED) { + if (kernelAbove200() && p->state >= ProcessState_Running && p->flags & PROCESSFLAGS_DEBUGDETACHED) { p->flags &= ~PROCESSFLAGS_DEBUGDETACHED; *out_pid = p->pid; *out_type = kernelAbove500() ? PROCESSEVENTTYPE_500_DEBUGDETACHED : PROCESSEVENTTYPE_DEBUGDETACHED; @@ -451,7 +450,7 @@ void Registration::GetProcessEventType(u64 *out_pid, u64 *out_type) { } if (kernelAbove500()) { auto_lock.unlock(); - auto dead_process_list_lock = g_dead_process_list.get_unique_lock(); + auto dead_process_list_lock = g_dead_process_list.GetUniqueLock(); if (g_dead_process_list.processes.size()) { std::shared_ptr<Registration::Process> process = g_dead_process_list.processes[0]; g_dead_process_list.processes.erase(g_dead_process_list.processes.begin()); @@ -471,13 +470,13 @@ Result Registration::EnableDebugForTitleId(u64 tid, Handle *out) { g_debug_on_launch_tid = old; return 0x80F; } - *out = g_debug_title_event->get_handle(); + *out = g_debug_title_event->GetHandle(); return 0x0; } Result Registration::EnableDebugForApplication(Handle *out) { g_debug_next_application = true; - *out = g_debug_application_event->get_handle(); + *out = g_debug_application_event->GetHandle(); return 0; } diff --git a/stratosphere/pm/source/pm_registration.hpp b/stratosphere/pm/source/pm_registration.hpp index 6f0459124..8b440ade4 100644 --- a/stratosphere/pm/source/pm_registration.hpp +++ b/stratosphere/pm/source/pm_registration.hpp @@ -172,8 +172,7 @@ class Registration { static void InitializeSystemResources(); static IWaitable *GetProcessLaunchStartEvent(); static std::unique_lock<HosRecursiveMutex> GetProcessListUniqueLock(); - static void SetProcessListManager(WaitableManager *m); - static Result ProcessLaunchStartCallback(void *arg, Handle *handles, size_t num_handles, u64 timeout); + static Result ProcessLaunchStartCallback(u64 timeout); static Result HandleSignaledProcess(std::shared_ptr<Process> process); static void FinalizeExitedProcess(std::shared_ptr<Process> process); diff --git a/stratosphere/pm/source/pm_resource_limits.cpp b/stratosphere/pm/source/pm_resource_limits.cpp index 97c699221..67a4aa773 100644 --- a/stratosphere/pm/source/pm_resource_limits.cpp +++ b/stratosphere/pm/source/pm_resource_limits.cpp @@ -182,7 +182,12 @@ void ResourceLimitUtils::InitializeLimits() { /* Atmosphere: Allocate extra memory (24 MiB) to SYSTEM away from Applet. */ for (unsigned int i = 0; i < 6; i++) { g_memory_resource_limits[i][0] += ATMOSPHERE_EXTRA_SYSTEM_MEMORY_FOR_SYSMODULES; - g_memory_resource_limits[i][2] -= ATMOSPHERE_EXTRA_SYSTEM_MEMORY_FOR_SYSMODULES; + /* On < 4.0.0, taking from application instead of applet fixes a rare hang on boot. */ + if (kernelAbove400()) { + g_memory_resource_limits[i][2] -= ATMOSPHERE_EXTRA_SYSTEM_MEMORY_FOR_SYSMODULES; + } else { + g_memory_resource_limits[i][1] -= ATMOSPHERE_EXTRA_SYSTEM_MEMORY_FOR_SYSMODULES; + } } /* Set resource limits. */ @@ -224,6 +229,10 @@ Handle ResourceLimitUtils::GetResourceLimitHandle(u16 application_type) { } } +Handle ResourceLimitUtils::GetResourceLimitHandleByCategory(ResourceLimitCategory category) { + return g_resource_limit_handles[category]; +} + Result ResourceLimitUtils::BoostSystemMemoryResourceLimit(u64 boost_size) { Result rc = 0; if (boost_size > g_memory_resource_limits[g_memory_limit_type][ResourceLimitCategory_Application]) { diff --git a/stratosphere/pm/source/pm_resource_limits.hpp b/stratosphere/pm/source/pm_resource_limits.hpp index 36d46fcd0..c06706e02 100644 --- a/stratosphere/pm/source/pm_resource_limits.hpp +++ b/stratosphere/pm/source/pm_resource_limits.hpp @@ -28,5 +28,6 @@ class ResourceLimitUtils { static void InitializeLimits(); static void EnsureApplicationResourcesAvailable(); static Handle GetResourceLimitHandle(u16 application_type); + static Handle GetResourceLimitHandleByCategory(ResourceLimitCategory category); static Result BoostSystemMemoryResourceLimit(u64 boost_size); }; \ No newline at end of file diff --git a/stratosphere/pm/source/pm_shell.cpp b/stratosphere/pm/source/pm_shell.cpp index 4a9653367..a1e6dbd12 100644 --- a/stratosphere/pm/source/pm_shell.cpp +++ b/stratosphere/pm/source/pm_shell.cpp @@ -23,170 +23,84 @@ static bool g_has_boot_finished = false; -Result ShellService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) { - Result rc = 0xF601; - - if (kernelAbove500()) { - switch ((ShellCmd_5X)cmd_id) { - case Shell_Cmd_5X_LaunchProcess: - rc = WrapIpcCommandImpl<&ShellService::launch_process>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Shell_Cmd_5X_TerminateProcessId: - rc = WrapIpcCommandImpl<&ShellService::terminate_process_id>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Shell_Cmd_5X_TerminateTitleId: - rc = WrapIpcCommandImpl<&ShellService::terminate_title_id>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Shell_Cmd_5X_GetProcessWaitEvent: - rc = WrapIpcCommandImpl<&ShellService::get_process_wait_event>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Shell_Cmd_5X_GetProcessEventType: - rc = WrapIpcCommandImpl<&ShellService::get_process_event_type>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Shell_Cmd_5X_NotifyBootFinished: - rc = WrapIpcCommandImpl<&ShellService::notify_boot_finished>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Shell_Cmd_5X_GetApplicationProcessId: - rc = WrapIpcCommandImpl<&ShellService::get_application_process_id>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Shell_Cmd_5X_BoostSystemMemoryResourceLimit: - rc = WrapIpcCommandImpl<&ShellService::boost_system_memory_resource_limit>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - default: - break; - } - } else { - switch ((ShellCmd)cmd_id) { - case Shell_Cmd_LaunchProcess: - rc = WrapIpcCommandImpl<&ShellService::launch_process>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Shell_Cmd_TerminateProcessId: - rc = WrapIpcCommandImpl<&ShellService::terminate_process_id>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Shell_Cmd_TerminateTitleId: - rc = WrapIpcCommandImpl<&ShellService::terminate_title_id>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Shell_Cmd_GetProcessWaitEvent: - rc = WrapIpcCommandImpl<&ShellService::get_process_wait_event>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Shell_Cmd_GetProcessEventType: - rc = WrapIpcCommandImpl<&ShellService::get_process_event_type>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Shell_Cmd_FinalizeExitedProcess: - rc = WrapIpcCommandImpl<&ShellService::finalize_exited_process>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Shell_Cmd_ClearProcessNotificationFlag: - rc = WrapIpcCommandImpl<&ShellService::clear_process_notification_flag>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Shell_Cmd_NotifyBootFinished: - rc = WrapIpcCommandImpl<&ShellService::notify_boot_finished>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Shell_Cmd_GetApplicationProcessId: - rc = WrapIpcCommandImpl<&ShellService::get_application_process_id>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Shell_Cmd_BoostSystemMemoryResourceLimit: - rc = WrapIpcCommandImpl<&ShellService::boost_system_memory_resource_limit>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - default: - break; - } - } - - return rc; +Result ShellService::LaunchProcess(Out<u64> pid, Registration::TidSid tid_sid, u32 launch_flags) { + return Registration::LaunchProcessByTidSid(tid_sid, launch_flags, pid.GetPointer()); } -Result ShellService::handle_deferred() { - /* This service is never deferrable. */ - return 0; -} - -std::tuple<Result, u64> ShellService::launch_process(u64 launch_flags, Registration::TidSid tid_sid) { - u64 pid = 0; - Result rc = Registration::LaunchProcessByTidSid(tid_sid, launch_flags, &pid); - return {rc, pid}; -} - -std::tuple<Result> ShellService::terminate_process_id(u64 pid) { +Result ShellService::TerminateProcessId(u64 pid) { auto auto_lock = Registration::GetProcessListUniqueLock(); - std::shared_ptr<Registration::Process> proc = Registration::GetProcess(pid); + auto proc = Registration::GetProcess(pid); + if (proc != nullptr) { + return svcTerminateProcess(proc->handle); + } else { + return 0x20F; + } +} + +Result ShellService::TerminateTitleId(u64 tid) { + auto auto_lock = Registration::GetProcessListUniqueLock(); + + auto proc = Registration::GetProcessByTitleId(tid); if (proc != NULL) { - return {svcTerminateProcess(proc->handle)}; + return svcTerminateProcess(proc->handle); } else { - return {0x20F}; + return 0x20F; } } -std::tuple<Result> ShellService::terminate_title_id(u64 tid) { +void ShellService::GetProcessWaitEvent(Out<CopiedHandle> event) { + event.SetValue(Registration::GetProcessEventHandle()); +} + +void ShellService::GetProcessEventType(Out<u64> type, Out<u64> pid) { + Registration::GetProcessEventType(pid.GetPointer(), type.GetPointer()); +} + +Result ShellService::FinalizeExitedProcess(u64 pid) { auto auto_lock = Registration::GetProcessListUniqueLock(); - std::shared_ptr<Registration::Process> proc = Registration::GetProcessByTitleId(tid); - if (proc != NULL) { - return {svcTerminateProcess(proc->handle)}; - } else { - return {0x20F}; - } -} - -std::tuple<Result, CopiedHandle> ShellService::get_process_wait_event() { - return {0x0, Registration::GetProcessEventHandle()}; -} - -std::tuple<Result, u64, u64> ShellService::get_process_event_type() { - u64 type, pid; - Registration::GetProcessEventType(&pid, &type); - return {0x0, type, pid}; -} - -std::tuple<Result> ShellService::finalize_exited_process(u64 pid) { - auto auto_lock = Registration::GetProcessListUniqueLock(); - - std::shared_ptr<Registration::Process> proc = Registration::GetProcess(pid); + auto proc = Registration::GetProcess(pid); if (proc == NULL) { - return {0x20F}; + return 0x20F; } else if (proc->state != ProcessState_Exited) { - return {0x60F}; + return 0x60F; } else { Registration::FinalizeExitedProcess(proc); - return {0x0}; + return 0x0; } } -std::tuple<Result> ShellService::clear_process_notification_flag(u64 pid) { +Result ShellService::ClearProcessNotificationFlag(u64 pid) { auto auto_lock = Registration::GetProcessListUniqueLock(); - std::shared_ptr<Registration::Process> proc = Registration::GetProcess(pid); + auto proc = Registration::GetProcess(pid); if (proc != NULL) { proc->flags &= ~PROCESSFLAGS_CRASHED; - return {0x0}; + return 0x0; } else { - return {0x20F}; + return 0x20F; } } -std::tuple<Result> ShellService::notify_boot_finished() { +void ShellService::NotifyBootFinished() { if (!g_has_boot_finished) { g_has_boot_finished = true; EmbeddedBoot2::Main(); } - return {0}; } -std::tuple<Result, u64> ShellService::get_application_process_id() { +Result ShellService::GetApplicationProcessId(Out<u64> pid) { auto auto_lock = Registration::GetProcessListUniqueLock(); std::shared_ptr<Registration::Process> app_proc; if (Registration::HasApplicationProcess(&app_proc)) { - return {0, app_proc->pid}; + pid.SetValue(app_proc->pid); + return 0; } - return {0x20F, 0}; + return 0x20F; } -std::tuple<Result> ShellService::boost_system_memory_resource_limit(u64 sysmem_size) { - if (!kernelAbove400()) { - return {0xF601}; - } - - /* TODO */ - return {ResourceLimitUtils::BoostSystemMemoryResourceLimit(sysmem_size)}; +Result ShellService::BoostSystemMemoryResourceLimit(u64 sysmem_size) { + return ResourceLimitUtils::BoostSystemMemoryResourceLimit(sysmem_size); } diff --git a/stratosphere/pm/source/pm_shell.hpp b/stratosphere/pm/source/pm_shell.hpp index c5b63c030..cd707a510 100644 --- a/stratosphere/pm/source/pm_shell.hpp +++ b/stratosphere/pm/source/pm_shell.hpp @@ -16,7 +16,7 @@ #pragma once #include <switch.h> -#include <stratosphere/iserviceobject.hpp> +#include <stratosphere.hpp> #include "pm_registration.hpp" @@ -46,26 +46,43 @@ enum ShellCmd_5X { Shell_Cmd_5X_BoostSystemMemoryResourceLimit = 7 }; -class ShellService final : public IServiceObject { - public: - Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) override; - Result handle_deferred() override; - - ShellService *clone() override { - return new ShellService(*this); - } - - +class ShellService final : public IServiceObject { private: /* Actual commands. */ - std::tuple<Result, u64> launch_process(u64 launch_flags, Registration::TidSid tid_sid); - std::tuple<Result> terminate_process_id(u64 pid); - std::tuple<Result> terminate_title_id(u64 tid); - std::tuple<Result, CopiedHandle> get_process_wait_event(); - std::tuple<Result, u64, u64> get_process_event_type(); - std::tuple<Result> finalize_exited_process(u64 pid); - std::tuple<Result> clear_process_notification_flag(u64 pid); - std::tuple<Result> notify_boot_finished(); - std::tuple<Result, u64> get_application_process_id(); - std::tuple<Result> boost_system_memory_resource_limit(u64 sysmem_size); + Result LaunchProcess(Out<u64> pid, Registration::TidSid tid_sid, u32 launch_flags); + Result TerminateProcessId(u64 pid); + Result TerminateTitleId(u64 tid); + void GetProcessWaitEvent(Out<CopiedHandle> event); + void GetProcessEventType(Out<u64> type, Out<u64> pid); + Result FinalizeExitedProcess(u64 pid); + Result ClearProcessNotificationFlag(u64 pid); + void NotifyBootFinished(); + Result GetApplicationProcessId(Out<u64> pid); + Result BoostSystemMemoryResourceLimit(u64 sysmem_size); + public: + DEFINE_SERVICE_DISPATCH_TABLE { + /* 1.0.0-4.0.0 */ + MakeServiceCommandMeta<Shell_Cmd_LaunchProcess, &ShellService::LaunchProcess, FirmwareVersion_Min, FirmwareVersion_400>(), + MakeServiceCommandMeta<Shell_Cmd_TerminateProcessId, &ShellService::TerminateProcessId, FirmwareVersion_Min, FirmwareVersion_400>(), + MakeServiceCommandMeta<Shell_Cmd_TerminateTitleId, &ShellService::TerminateTitleId, FirmwareVersion_Min, FirmwareVersion_400>(), + MakeServiceCommandMeta<Shell_Cmd_GetProcessWaitEvent, &ShellService::GetProcessWaitEvent, FirmwareVersion_Min, FirmwareVersion_400>(), + MakeServiceCommandMeta<Shell_Cmd_GetProcessEventType, &ShellService::GetProcessEventType, FirmwareVersion_Min, FirmwareVersion_400>(), + MakeServiceCommandMeta<Shell_Cmd_FinalizeExitedProcess, &ShellService::FinalizeExitedProcess, FirmwareVersion_Min, FirmwareVersion_400>(), + MakeServiceCommandMeta<Shell_Cmd_ClearProcessNotificationFlag, &ShellService::ClearProcessNotificationFlag, FirmwareVersion_Min, FirmwareVersion_400>(), + MakeServiceCommandMeta<Shell_Cmd_NotifyBootFinished, &ShellService::NotifyBootFinished, FirmwareVersion_Min, FirmwareVersion_400>(), + MakeServiceCommandMeta<Shell_Cmd_GetApplicationProcessId, &ShellService::GetApplicationProcessId, FirmwareVersion_Min, FirmwareVersion_400>(), + + /* 4.0.0-4.0.0 */ + MakeServiceCommandMeta<Shell_Cmd_BoostSystemMemoryResourceLimit, &ShellService::BoostSystemMemoryResourceLimit, FirmwareVersion_400, FirmwareVersion_400>(), + + /* 5.0.0-* */ + MakeServiceCommandMeta<Shell_Cmd_5X_LaunchProcess, &ShellService::LaunchProcess, FirmwareVersion_500>(), + MakeServiceCommandMeta<Shell_Cmd_5X_TerminateProcessId, &ShellService::TerminateProcessId, FirmwareVersion_500>(), + MakeServiceCommandMeta<Shell_Cmd_5X_TerminateTitleId, &ShellService::TerminateTitleId, FirmwareVersion_500>(), + MakeServiceCommandMeta<Shell_Cmd_5X_GetProcessWaitEvent, &ShellService::GetProcessWaitEvent, FirmwareVersion_500>(), + MakeServiceCommandMeta<Shell_Cmd_5X_GetProcessEventType, &ShellService::GetProcessEventType, FirmwareVersion_500>(), + MakeServiceCommandMeta<Shell_Cmd_5X_NotifyBootFinished, &ShellService::NotifyBootFinished, FirmwareVersion_500>(), + MakeServiceCommandMeta<Shell_Cmd_5X_GetApplicationProcessId, &ShellService::GetApplicationProcessId, FirmwareVersion_500>(), + MakeServiceCommandMeta<Shell_Cmd_5X_BoostSystemMemoryResourceLimit, &ShellService::BoostSystemMemoryResourceLimit, FirmwareVersion_500>(), + }; }; diff --git a/stratosphere/set_mitm/Makefile b/stratosphere/set_mitm/Makefile new file mode 100644 index 000000000..c042e968d --- /dev/null +++ b/stratosphere/set_mitm/Makefile @@ -0,0 +1,159 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- + +ifeq ($(strip $(DEVKITPRO)),) +$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro") +endif + +TOPDIR ?= $(CURDIR) +include $(DEVKITPRO)/libnx/switch_rules + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# DATA is a list of directories containing data files +# INCLUDES is a list of directories containing header files +# EXEFS_SRC is the optional input directory containing data copied into exefs, if anything this normally should only contain "main.npdm". +#--------------------------------------------------------------------------------- +TARGET := $(notdir $(CURDIR)) +BUILD := build +SOURCES := source +DATA := data +INCLUDES := include ../../common/include +EXEFS_SRC := exefs_src + +DEFINES := -DDISABLE_IPC + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +ARCH := -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE + +CFLAGS := -g -Wall -O2 -ffunction-sections \ + $(ARCH) $(DEFINES) + +CFLAGS += $(INCLUDE) -D__SWITCH__ + +CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++17 + +ASFLAGS := -g $(ARCH) +LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) + +LIBS := -lstratosphere -lnx + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(PORTLIBS) $(LIBNX) $(CURDIR)/../libstratosphere + + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export OUTPUT := $(CURDIR)/$(TARGET) +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +export DEPSDIR := $(CURDIR)/$(BUILD) + +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.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) \ + -I$(CURDIR)/$(BUILD) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) + +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: $(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 +#--------------------------------------------------------------------------------------- diff --git a/stratosphere/set_mitm/set_mitm.json b/stratosphere/set_mitm/set_mitm.json new file mode 100644 index 000000000..1383e7e2c --- /dev/null +++ b/stratosphere/set_mitm/set_mitm.json @@ -0,0 +1,98 @@ +{ + "name": "set.mitm", + "title_id": "0x0100000000000032", + "title_id_range_min": "0x0100000000000032", + "title_id_range_max": "0x0100000000000032", + "main_thread_stack_size": "0x00004000", + "main_thread_priority": 49, + "default_cpu_id": 3, + "process_category": 0, + "is_retail": true, + "pool_partition": 2, + "is_64_bit": true, + "address_space_type": 3, + "filesystem_access": { + "permissions": "0xFFFFFFFFFFFFFFFF" + }, + "service_access": { + "fatal:u": false, + "fsp-srv": false, + "spl:": false, + "set:sys": false, + "set:sys": true + }, + "kernel_capabilities": { + "kernel_flags": { + "highest_thread_priority": 63, + "lowest_thread_priority": 24, + "lowest_cpu_id": 3, + "highest_cpu_id": 3 + }, + "syscalls": { + + "svcSetHeapSize": "0x01", + "svcSetMemoryPermission": "0x02", + "svcSetMemoryAttribute": "0x03", + "svcMapMemory": "0x04", + "svcUnmapMemory": "0x05", + "svcQueryMemory": "0x06", + "svcExitProcess": "0x07", + "svcCreateThread": "0x08", + "svcStartThread": "0x09", + "svcExitThread": "0x0a", + "svcSleepThread": "0x0b", + "svcGetThreadPriority": "0x0c", + "svcSetThreadPriority": "0x0d", + "svcGetThreadCoreMask": "0x0e", + "svcSetThreadCoreMask": "0x0f", + "svcGetCurrentProcessorNumber": "0x10", + "svcSignalEvent": "0x11", + "svcClearEvent": "0x12", + "svcMapSharedMemory": "0x13", + "svcUnmapSharedMemory": "0x14", + "svcCreateTransferMemory": "0x15", + "svcCloseHandle": "0x16", + "svcResetSignal": "0x17", + "svcWaitSynchronization": "0x18", + "svcCancelSynchronization": "0x19", + "svcArbitrateLock": "0x1a", + "svcArbitrateUnlock": "0x1b", + "svcWaitProcessWideKeyAtomic": "0x1c", + "svcSignalProcessWideKey": "0x1d", + "svcGetSystemTick": "0x1e", + "svcConnectToNamedPort": "0x1f", + "svcSendSyncRequestLight": "0x20", + "svcSendSyncRequest": "0x21", + "svcSendSyncRequestWithUserBuffer": "0x22", + "svcSendAsyncRequestWithUserBuffer": "0x23", + "svcGetProcessId": "0x24", + "svcGetThreadId": "0x25", + "svcBreak": "0x26", + "svcOutputDebugString": "0x27", + "svcReturnFromException": "0x28", + "svcGetInfo": "0x29", + "svcWaitForAddress": "0x34", + "svcSignalToAddress": "0x35", + "svcCreateSession": "0x40", + "svcAcceptSession": "0x41", + "svcReplyAndReceiveLight": "0x42", + "svcReplyAndReceive": "0x43", + "svcReplyAndReceiveWithUserBuffer": "0x44", + "svcCreateEvent": "0x45", + "svcCreateInterruptEvent": "0x53", + "svcReadWriteRegister": "0x4E", + "svcQueryIoMapping": "0x55", + "svcCreateDeviceAddressSpace": "0x56", + "svcAttachDeviceAddressSpace": "0x57", + "svcDetachDeviceAddressSpace": "0x58", + "svcMapDeviceAddressSpaceAligned": "0x5a", + "svcUnmapDeviceAddressSpace": "0x5c", + "svcGetSystemInfo": "0x6f" + }, + "min_kernel_version": "0x0060", + "debug_flags": { + "allow_debug": false, + "force_debug": true + } + } +} \ No newline at end of file diff --git a/stratosphere/set_mitm/source/setmitm_main.cpp b/stratosphere/set_mitm/source/setmitm_main.cpp new file mode 100644 index 000000000..c03f5099d --- /dev/null +++ b/stratosphere/set_mitm/source/setmitm_main.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <cstdlib> +#include <cstdint> +#include <cstring> +#include <malloc.h> + +#include <switch.h> +#include <stratosphere.hpp> + +#include "setsys_mitm_service.hpp" + +extern "C" { + extern u32 __start__; + + u32 __nx_applet_type = AppletType_None; + + #define INNER_HEAP_SIZE 0x20000 + size_t nx_inner_heap_size = INNER_HEAP_SIZE; + char nx_inner_heap[INNER_HEAP_SIZE]; + + void __libnx_initheap(void); + void __appInit(void); + void __appExit(void); +} + + +void __libnx_initheap(void) { + void* addr = nx_inner_heap; + size_t size = nx_inner_heap_size; + + /* Newlib */ + extern char* fake_heap_start; + extern char* fake_heap_end; + + fake_heap_start = (char*)addr; + fake_heap_end = (char*)addr + size; +} + +void __appInit(void) { + Result rc; + + rc = smInitialize(); + if (R_FAILED(rc)) { + fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_SM)); + } + + rc = setsysInitialize(); + if (R_FAILED(rc)) { + fatalSimple(rc); + } + + CheckAtmosphereVersion(); +} + +void __appExit(void) { + /* Cleanup services. */ + setsysExit(); + smExit(); +} + +struct SetSysManagerOptions { + static const size_t PointerBufferSize = 0x100; + static const size_t MaxDomains = 4; + static const size_t MaxDomainObjects = 0x100; +}; + +using SetMitmManager = WaitableManager<SetSysManagerOptions>; + +int main(int argc, char **argv) +{ + consoleDebugInit(debugDevice_SVC); + + /* TODO: What's a good timeout value to use here? */ + auto server_manager = new SetMitmManager(1); + + /* Create fsp-srv mitm. */ + AddMitmServerToManager<SetSysMitmService>(server_manager, "set:sys", 4); + + /* Loop forever, servicing our services. */ + server_manager->Process(); + + delete server_manager; + + return 0; +} + diff --git a/stratosphere/set_mitm/source/setsys_mitm_service.cpp b/stratosphere/set_mitm/source/setsys_mitm_service.cpp new file mode 100644 index 000000000..60e1c5e2c --- /dev/null +++ b/stratosphere/set_mitm/source/setsys_mitm_service.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <mutex> +#include <switch.h> +#include "setsys_mitm_service.hpp" + +static HosMutex g_version_mutex; +static bool g_got_version = false; +static SetSysFirmwareVersion g_fw_version = {0}; + +static Result _GetFirmwareVersion(SetSysFirmwareVersion *out) { + std::scoped_lock<HosMutex> lock(g_version_mutex); + if (!g_got_version) { + Result rc = setsysGetFirmwareVersion(&g_fw_version); + if (R_FAILED(rc)) { + return rc; + } + + /* Modify the output firmware version. */ + { + u32 major, minor, micro; + char display_version[sizeof(g_fw_version.display_version)] = {0}; + + GetAtmosphereApiVersion(&major, &minor, µ, nullptr, nullptr); + snprintf(display_version, sizeof(display_version), "%s (AMS %u.%u.%u)", g_fw_version.display_version, major, minor, micro); + + memcpy(g_fw_version.display_version, display_version, sizeof(g_fw_version.display_version)); + } + + g_got_version = true; + } + + *out = g_fw_version; + return 0; +} + +void SetSysMitmService::PostProcess(IMitmServiceObject *obj, IpcResponseContext *ctx) { + /* No commands need postprocessing. */ +} + +Result SetSysMitmService::GetFirmwareVersion(OutPointerWithServerSize<SetSysFirmwareVersion, 0x1> out) { + Result rc = _GetFirmwareVersion(out.pointer); + + /* GetFirmwareVersion sanitizes these fields. */ + if (R_SUCCEEDED(rc)) { + out.pointer->revision_major = 0; + out.pointer->revision_minor = 0; + } + + return rc; +} + +Result SetSysMitmService::GetFirmwareVersion2(OutPointerWithServerSize<SetSysFirmwareVersion, 0x1> out) { + return _GetFirmwareVersion(out.pointer); +} \ No newline at end of file diff --git a/stratosphere/set_mitm/source/setsys_mitm_service.hpp b/stratosphere/set_mitm/source/setsys_mitm_service.hpp new file mode 100644 index 000000000..2e3da205f --- /dev/null +++ b/stratosphere/set_mitm/source/setsys_mitm_service.hpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once +#include <switch.h> +#include <stratosphere.hpp> + +enum SetSysCmd : u32 { + SetSysCmd_GetFirmwareVersion = 3, + SetSysCmd_GetFirmwareVersion2 = 4, +}; + +class SetSysMitmService : public IMitmServiceObject { + public: + SetSysMitmService(std::shared_ptr<Service> s) : IMitmServiceObject(s) { + /* ... */ + } + + static bool ShouldMitm(u64 pid, u64 tid) { + /* Only MitM qlaunch, maintenance. */ + return tid == 0x0100000000001000ULL || tid == 0x0100000000001015ULL; + } + + static void PostProcess(IMitmServiceObject *obj, IpcResponseContext *ctx); + + protected: + /* Overridden commands. */ + Result GetFirmwareVersion(OutPointerWithServerSize<SetSysFirmwareVersion, 0x1> out); + Result GetFirmwareVersion2(OutPointerWithServerSize<SetSysFirmwareVersion, 0x1> out); + public: + DEFINE_SERVICE_DISPATCH_TABLE { + MakeServiceCommandMeta<SetSysCmd_GetFirmwareVersion, &SetSysMitmService::GetFirmwareVersion>(), + MakeServiceCommandMeta<SetSysCmd_GetFirmwareVersion2, &SetSysMitmService::GetFirmwareVersion2>(), + }; +}; diff --git a/stratosphere/sm/Makefile b/stratosphere/sm/Makefile index a0da4da5b..dae1cae4a 100644 --- a/stratosphere/sm/Makefile +++ b/stratosphere/sm/Makefile @@ -21,7 +21,7 @@ TARGET := $(notdir $(CURDIR)) BUILD := build SOURCES := source DATA := data -INCLUDES := include +INCLUDES := include ../../common/include EXEFS_SRC := exefs_src DEFINES := -DDISABLE_IPC @@ -34,7 +34,7 @@ ARCH := -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE CFLAGS := -g -Wall -O2 -ffunction-sections \ $(ARCH) $(DEFINES) -CFLAGS += $(INCLUDE) -D__SWITCH__ -DSM_ENABLE_SMHAX -DSM_ENABLE_MITM -DSM_MINIMUM_SESSION_LIMIT=8 +CFLAGS += $(INCLUDE) -D__SWITCH__ -DSM_ENABLE_SMHAX -DSM_ENABLE_MITM -DSM_ENABLE_INIT_DEFERS -DSM_MINIMUM_SESSION_LIMIT=8 CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++17 diff --git a/stratosphere/sm/sm.json b/stratosphere/sm/sm.json index 101c741e1..cff1006d0 100644 --- a/stratosphere/sm/sm.json +++ b/stratosphere/sm/sm.json @@ -1,7 +1,7 @@ { "name": "sm", "title_id": "0x0100000000000004", - "main_thread_stack_size": "0x1000", + "main_thread_stack_size": "0x2000", "main_thread_priority": 27, "default_cpu_id": 3, "process_category": 1, @@ -13,58 +13,59 @@ { "type": "syscalls", "value": { - "svcSetHeapSize": "0x01", - "svcSetMemoryPermission": "0x02", - "svcSetMemoryAttribute": "0x03", - "svcMapMemory": "0x04", - "svcUnmapMemory": "0x05", - "svcQueryMemory": "0x06", - "svcExitProcess": "0x07", - "svcCreateThread": "0x08", - "svcStartThread": "0x09", - "svcExitThread": "0x0A", - "svcSleepThread": "0x0B", - "svcGetThreadPriority": "0x0C", - "svcSetThreadPriority": "0x0D", - "svcGetThreadCoreMask": "0x0E", - "svcSetThreadCoreMask": "0x0F", - "svcGetCurrentProcessorNumber": "0x10", - "svcSignalEvent": "0x11", - "svcClearEvent": "0x12", - "svcMapSharedMemory": "0x13", - "svcUnmapSharedMemory": "0x14", - "svcCreateTransferMemory": "0x15", - "svcCloseHandle": "0x16", - "svcResetSignal": "0x17", - "svcWaitSynchronization": "0x18", - "svcCancelSynchronization": "0x19", - "svcArbitrateLock": "0x1A", - "svcArbitrateUnlock": "0x1B", - "svcWaitProcessWideKeyAtomic": "0x1C", - "svcSignalProcessWideKey": "0x1D", - "svcGetSystemTick": "0x1E", - "svcConnectToNamedPort": "0x1F", - "svcSendSyncRequestLight": "0x20", - "svcSendSyncRequest": "0x21", - "svcSendSyncRequestWithUserBuffer": "0x22", - "svcSendAsyncRequestWithUserBuffer": "0x23", - "svcGetProcessId": "0x24", - "svcGetThreadId": "0x25", - "svcBreak": "0x26", - "svcOutputDebugString": "0x27", - "svcReturnFromException": "0x28", - "svcGetInfo": "0x29", - "svcWaitForAddress": "0x34", - "svcSignalToAddress": "0x35", - "svcCreateSession": "0x40", - "svcAcceptSession": "0x41", - "svcReplyAndReceiveLight": "0x42", - "svcReplyAndReceive": "0x43", - "svcReplyAndReceiveWithUserBuffer": "0x44", - "svcGetMemoryInfo": "0x6F", - "svcCreatePort": "0x70", - "svcManageNamedPort": "0x71", - "svcConnectToPort": "0x72" + "svcSetHeapSize" : "0x01", + "svcSetMemoryPermission" : "0x02", + "svcSetMemoryAttribute" : "0x03", + "svcMapMemory" : "0x04", + "svcUnmapMemory" : "0x05", + "svcQueryMemory" : "0x06", + "svcExitProcess" : "0x07", + "svcCreateThread" : "0x08", + "svcStartThread" : "0x09", + "svcExitThread" : "0x0A", + "svcSleepThread" : "0x0B", + "svcGetThreadPriority" : "0x0C", + "svcSetThreadPriority" : "0x0D", + "svcGetThreadCoreMask" : "0x0E", + "svcSetThreadCoreMask" : "0x0F", + "svcGetCurrentProcessorNumber" : "0x10", + "svcSignalEvent" : "0x11", + "svcClearEvent" : "0x12", + "svcMapSharedMemory" : "0x13", + "svcUnmapSharedMemory" : "0x14", + "svcCreateTransferMemory" : "0x15", + "svcCloseHandle" : "0x16", + "svcResetSignal" : "0x17", + "svcWaitSynchronization" : "0x18", + "svcCancelSynchronization" : "0x19", + "svcArbitrateLock" : "0x1A", + "svcArbitrateUnlock" : "0x1B", + "svcWaitProcessWideKeyAtomic" : "0x1C", + "svcSignalProcessWideKey" : "0x1D", + "svcGetSystemTick" : "0x1E", + "svcConnectToNamedPort" : "0x1F", + "svcSendSyncRequestLight" : "0x20", + "svcSendSyncRequest" : "0x21", + "svcSendSyncRequestWithUserBuffer" : "0x22", + "svcSendAsyncRequestWithUserBuffer" : "0x23", + "svcGetProcessId" : "0x24", + "svcGetThreadId" : "0x25", + "svcBreak" : "0x26", + "svcOutputDebugString" : "0x27", + "svcReturnFromException" : "0x28", + "svcGetInfo" : "0x29", + "svcWaitForAddress" : "0x34", + "svcSignalToAddress" : "0x35", + "svcCreateSession" : "0x40", + "svcAcceptSession" : "0x41", + "svcReplyAndReceiveLight" : "0x42", + "svcReplyAndReceive" : "0x43", + "svcReplyAndReceiveWithUserBuffer" : "0x44", + "svcCreateEvent" : "0x45", + "svcGetMemoryInfo" : "0x6F", + "svcCreatePort" : "0x70", + "svcManageNamedPort" : "0x71", + "svcConnectToPort" : "0x72" } } ] diff --git a/stratosphere/sm/source/sm_main.cpp b/stratosphere/sm/source/sm_main.cpp index d9381b821..60ceb3c45 100644 --- a/stratosphere/sm/source/sm_main.cpp +++ b/stratosphere/sm/source/sm_main.cpp @@ -61,15 +61,18 @@ void __appExit(void) { /* Nothing to clean up, because we're sm. */ } + + + int main(int argc, char **argv) { consoleDebugInit(debugDevice_SVC); /* TODO: What's a good timeout value to use here? */ - WaitableManager *server_manager = new WaitableManager(U64_MAX); - + auto server_manager = new WaitableManager(1); + /* Create sm:, (and thus allow things to register to it). */ - server_manager->add_waitable(new ManagedPortServer<UserService>("sm:", 0x40)); + server_manager->AddWaitable(new ManagedPortServer<UserService>("sm:", 0x40)); /* Create sm:m manually. */ Handle smm_h; @@ -78,10 +81,10 @@ int main(int argc, char **argv) while (1) { } } - server_manager->add_waitable(new ExistingPortServer<ManagerService>(smm_h, 1)); - + server_manager->AddWaitable(new ExistingPortServer<ManagerService>(smm_h, 1)); + /* Loop forever, servicing our services. */ - server_manager->process(); + server_manager->Process(); /* Cleanup. */ delete server_manager; diff --git a/stratosphere/sm/source/sm_manager_service.cpp b/stratosphere/sm/source/sm_manager_service.cpp index 04190f7ed..1ae5ca624 100644 --- a/stratosphere/sm/source/sm_manager_service.cpp +++ b/stratosphere/sm/source/sm_manager_service.cpp @@ -19,31 +19,15 @@ #include "sm_manager_service.hpp" #include "sm_registration.hpp" -Result ManagerService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) { - Result rc = 0xF601; - switch ((ManagerServiceCmd)cmd_id) { - case Manager_Cmd_RegisterProcess: - rc = WrapIpcCommandImpl<&ManagerService::register_process>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case Manager_Cmd_UnregisterProcess: - rc = WrapIpcCommandImpl<&ManagerService::unregister_process>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - default: - break; - } - return rc; +Result ManagerService::RegisterProcess(u64 pid, InBuffer<u8> acid_sac, InBuffer<u8> aci0_sac) { + return Registration::RegisterProcess(pid, acid_sac.buffer, acid_sac.num_elements, aci0_sac.buffer, aci0_sac.num_elements); } -Result ManagerService::handle_deferred() { - /* This service is never deferrable. */ - return 0; +Result ManagerService::UnregisterProcess(u64 pid) { + return Registration::UnregisterProcess(pid); } - -std::tuple<Result> ManagerService::register_process(u64 pid, InBuffer<u8> acid_sac, InBuffer<u8> aci0_sac) { - return {Registration::RegisterProcess(pid, acid_sac.buffer, acid_sac.num_elements, aci0_sac.buffer, aci0_sac.num_elements)}; +void ManagerService::AtmosphereEndInitDefers() { + Registration::EndInitDefers(); } -std::tuple<Result> ManagerService::unregister_process(u64 pid) { - return {Registration::UnregisterProcess(pid)}; -} diff --git a/stratosphere/sm/source/sm_manager_service.hpp b/stratosphere/sm/source/sm_manager_service.hpp index f64b26a03..080c4c93e 100644 --- a/stratosphere/sm/source/sm_manager_service.hpp +++ b/stratosphere/sm/source/sm_manager_service.hpp @@ -16,24 +16,27 @@ #pragma once #include <switch.h> -#include <stratosphere/iserviceobject.hpp> +#include <stratosphere.hpp> enum ManagerServiceCmd { Manager_Cmd_RegisterProcess = 0, - Manager_Cmd_UnregisterProcess = 1 + Manager_Cmd_UnregisterProcess = 1, + + + Manager_Cmd_AtmosphereEndInitDefers = 65000, }; class ManagerService final : public IServiceObject { - public: - Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) override; - Result handle_deferred() override; - - ManagerService *clone() override { - return new ManagerService(); - } - private: /* Actual commands. */ - std::tuple<Result> register_process(u64 pid, InBuffer<u8> acid_sac, InBuffer<u8> aci0_sac); - std::tuple<Result> unregister_process(u64 pid); + virtual Result RegisterProcess(u64 pid, InBuffer<u8> acid_sac, InBuffer<u8> aci0_sac); + virtual Result UnregisterProcess(u64 pid); + virtual void AtmosphereEndInitDefers(); + public: + DEFINE_SERVICE_DISPATCH_TABLE { + MakeServiceCommandMeta<Manager_Cmd_RegisterProcess, &ManagerService::RegisterProcess>(), + MakeServiceCommandMeta<Manager_Cmd_UnregisterProcess, &ManagerService::UnregisterProcess>(), + + MakeServiceCommandMeta<Manager_Cmd_AtmosphereEndInitDefers, &ManagerService::AtmosphereEndInitDefers>(), + }; }; diff --git a/stratosphere/sm/source/sm_registration.cpp b/stratosphere/sm/source/sm_registration.cpp index 63def66d9..0932db1f7 100644 --- a/stratosphere/sm/source/sm_registration.cpp +++ b/stratosphere/sm/source/sm_registration.cpp @@ -16,7 +16,7 @@ #include <switch.h> #include <algorithm> -#include <stratosphere/servicesession.hpp> +#include <stratosphere.hpp> #include "sm_registration.hpp" #include "meta_tools.hpp" @@ -26,6 +26,7 @@ static std::array<Registration::Service, REGISTRATION_LIST_MAX_SERVICE> g_servic static u64 g_initial_process_id_low = 0; static u64 g_initial_process_id_high = 0; static bool g_determined_initial_process_ids = false; +static bool g_end_init_defers = false; u64 GetServiceNameLength(u64 service) { u64 service_name_len = 0; @@ -36,6 +37,38 @@ u64 GetServiceNameLength(u64 service) { return service_name_len; } +/* Atmosphere extension utilities. */ +void Registration::EndInitDefers() { + g_end_init_defers = true; +} + +constexpr u64 EncodeNameConstant(const char *name) { + u64 service = 0; + for (unsigned int i = 0; i < sizeof(service); i++) { + if (name[i] == '\x00') { + break; + } + service |= ((u64)name[i]) << (8 * i); + } + return service; +} + +bool Registration::ShouldInitDefer(u64 service) { + /* Only enable if compile-time generated. */ +#ifndef SM_ENABLE_INIT_DEFERS + return false; +#endif + + if (g_end_init_defers) { + return false; + } + + /* This is a mechanism by which certain services will always be deferred until sm:m receives a special command. */ + /* This can be extended with more services as needed at a later date. */ + constexpr u64 FSP_SRV = EncodeNameConstant("fsp-srv"); + return service == FSP_SRV; +} + /* Utilities. */ Registration::Process *Registration::GetProcessForPid(u64 pid) { auto process_it = std::find_if(g_process_list.begin(), g_process_list.end(), member_equals_fn(&Process::pid, pid)); @@ -188,11 +221,13 @@ bool Registration::HasService(u64 service) { Result Registration::GetServiceHandle(u64 pid, u64 service, Handle *out) { Registration::Service *target_service = GetService(service); - if (target_service == NULL) { + if (target_service == NULL || ShouldInitDefer(service)) { /* Note: This defers the result until later. */ return RESULT_DEFER_SESSION; } + /* */ + *out = 0; Result rc; if (target_service->mitm_pid == 0 || target_service->mitm_pid == pid) { @@ -215,7 +250,7 @@ Result Registration::GetServiceHandle(u64 pid, u64 service, Handle *out) { struct { u64 magic; u64 result; - u64 should_mitm; + bool should_mitm; } *resp = ((decltype(resp))r.Raw); rc = resp->result; if (R_SUCCEEDED(rc)) { diff --git a/stratosphere/sm/source/sm_registration.hpp b/stratosphere/sm/source/sm_registration.hpp index 630a72181..9a30652bc 100644 --- a/stratosphere/sm/source/sm_registration.hpp +++ b/stratosphere/sm/source/sm_registration.hpp @@ -46,6 +46,9 @@ class Registration { }; /* Utilities. */ + static void EndInitDefers(); + static bool ShouldInitDefer(u64 service); + static Registration::Process *GetProcessForPid(u64 pid); static Registration::Process *GetFreeProcess(); static Registration::Service *GetService(u64 service); diff --git a/stratosphere/sm/source/sm_types.hpp b/stratosphere/sm/source/sm_types.hpp new file mode 100644 index 000000000..6ac9bce92 --- /dev/null +++ b/stratosphere/sm/source/sm_types.hpp @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once +struct SmServiceName { + char name[sizeof(u64)]; +}; + +static_assert(__alignof__(SmServiceName) == 1, "SmServiceName definition!"); \ No newline at end of file diff --git a/stratosphere/sm/source/sm_user_service.cpp b/stratosphere/sm/source/sm_user_service.cpp index 0f8927ed8..138ceac8c 100644 --- a/stratosphere/sm/source/sm_user_service.cpp +++ b/stratosphere/sm/source/sm_user_service.cpp @@ -15,116 +15,90 @@ */ #include <switch.h> -#include <stratosphere/servicesession.hpp> +#include <stratosphere.hpp> #include "sm_user_service.hpp" #include "sm_registration.hpp" -Result UserService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) { - Result rc = 0xF601; - switch ((UserServiceCmd)cmd_id) { - case User_Cmd_Initialize: - rc = WrapIpcCommandImpl<&UserService::initialize>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case User_Cmd_GetService: - rc = WrapIpcCommandImpl<&UserService::get_service>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case User_Cmd_RegisterService: - rc = WrapIpcCommandImpl<&UserService::register_service>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case User_Cmd_UnregisterService: - rc = WrapIpcCommandImpl<&UserService::unregister_service>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; -#ifdef SM_ENABLE_MITM - case User_Cmd_AtmosphereInstallMitm: - rc = WrapIpcCommandImpl<&UserService::install_mitm>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case User_Cmd_AtmosphereUninstallMitm: - rc = WrapIpcCommandImpl<&UserService::uninstall_mitm>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; - case User_Cmd_AtmosphereAssociatePidTidForMitm: - rc = WrapIpcCommandImpl<&UserService::associate_pid_tid_for_mitm>(this, r, out_c, pointer_buffer, pointer_buffer_size); - break; +Result UserService::Initialize(PidDescriptor pid) { + this->pid = pid.pid; + this->has_initialized = true; + return 0; +} + +Result UserService::GetService(Out<MovedHandle> out_h, SmServiceName service) { + Handle session_h = 0; + Result rc = 0x415; + +#ifdef SM_ENABLE_SMHAX + if (!this->has_initialized) { + rc = Registration::GetServiceForPid(Registration::GetInitialProcessId(), smEncodeName(service.name), &session_h); + } #endif - default: - break; + if (this->has_initialized) { + rc = Registration::GetServiceForPid(this->pid, smEncodeName(service.name), &session_h); + } + + if (R_SUCCEEDED(rc)) { + out_h.SetValue(session_h); } return rc; } -Result UserService::handle_deferred() { - /* If we're deferred, GetService failed. */ - return WrapDeferredIpcCommandImpl<&UserService::deferred_get_service>(this, this->deferred_service);; -} - - -std::tuple<Result> UserService::initialize(PidDescriptor pid) { - this->pid = pid.pid; - this->has_initialized = true; - return {0}; -} - -std::tuple<Result, MovedHandle> UserService::get_service(u64 service) { - Handle session_h = 0; - Result rc = 0x415; -#ifdef SM_ENABLE_SMHAX - if (!this->has_initialized) { - rc = Registration::GetServiceForPid(Registration::GetInitialProcessId(), service, &session_h); - } -#endif - if (this->has_initialized) { - rc = Registration::GetServiceForPid(this->pid, service, &session_h); - } - /* It's possible that this will end up deferring us...take that into account. */ - if (rc == RESULT_DEFER_SESSION) { - this->deferred_service = service; - } - return {rc, MovedHandle{session_h}}; -} - -std::tuple<Result, MovedHandle> UserService::deferred_get_service(u64 service) { - Handle session_h = 0; - Result rc = Registration::GetServiceHandle(this->pid, service, &session_h); - return {rc, MovedHandle{session_h}}; -} - -std::tuple<Result, MovedHandle> UserService::register_service(u64 service, u8 is_light, u32 max_sessions) { +Result UserService::RegisterService(Out<MovedHandle> out_h, SmServiceName service, u32 max_sessions, bool is_light) { Handle service_h = 0; Result rc = 0x415; #ifdef SM_ENABLE_SMHAX if (!this->has_initialized) { - rc = Registration::RegisterServiceForPid(Registration::GetInitialProcessId(), service, max_sessions, (is_light & 1) != 0, &service_h); + rc = Registration::RegisterServiceForPid(Registration::GetInitialProcessId(), smEncodeName(service.name), max_sessions, (is_light & 1) != 0, &service_h); } #endif if (this->has_initialized) { - rc = Registration::RegisterServiceForPid(this->pid, service, max_sessions, (is_light & 1) != 0, &service_h); + rc = Registration::RegisterServiceForPid(this->pid, smEncodeName(service.name), max_sessions, (is_light & 1) != 0, &service_h); } - return {rc, MovedHandle{service_h}}; + + if (R_SUCCEEDED(rc)) { + out_h.SetValue(service_h); + } + return rc; } -std::tuple<Result> UserService::unregister_service(u64 service) { +Result UserService::UnregisterService(SmServiceName service) { Result rc = 0x415; #ifdef SM_ENABLE_SMHAX if (!this->has_initialized) { - rc = Registration::UnregisterServiceForPid(Registration::GetInitialProcessId(), service); + rc = Registration::UnregisterServiceForPid(Registration::GetInitialProcessId(), smEncodeName(service.name)); } #endif if (this->has_initialized) { - rc = Registration::UnregisterServiceForPid(this->pid, service); + rc = Registration::UnregisterServiceForPid(this->pid, smEncodeName(service.name)); } - return {rc}; + return rc; } -std::tuple<Result, MovedHandle, MovedHandle> UserService::install_mitm(u64 service) { +Result UserService::AtmosphereInstallMitm(Out<MovedHandle> srv_h, Out<MovedHandle> qry_h, SmServiceName service) { Handle service_h = 0; Handle query_h = 0; Result rc = 0x415; if (this->has_initialized) { - rc = Registration::InstallMitmForPid(this->pid, service, &service_h, &query_h); + rc = Registration::InstallMitmForPid(this->pid, smEncodeName(service.name), &service_h, &query_h); } - return {rc, MovedHandle{service_h}, MovedHandle{query_h}}; + + if (R_SUCCEEDED(rc)) { + srv_h.SetValue(service_h); + qry_h.SetValue(query_h); + } + return rc; } -std::tuple<Result> UserService::associate_pid_tid_for_mitm(u64 pid, u64 tid) { +Result UserService::AtmosphereUninstallMitm(SmServiceName service) { + Result rc = 0x415; + if (this->has_initialized) { + rc = Registration::UninstallMitmForPid(this->pid, smEncodeName(service.name)); + } + return rc; +} + +Result UserService::AtmosphereAssociatePidTidForMitm(u64 pid, u64 tid) { Result rc = 0x415; if (this->has_initialized) { if (Registration::IsInitialProcess(pid)) { @@ -133,13 +107,5 @@ std::tuple<Result> UserService::associate_pid_tid_for_mitm(u64 pid, u64 tid) { rc = Registration::AssociatePidTidForMitm(pid, tid); } } - return {rc}; + return rc; } - -std::tuple<Result> UserService::uninstall_mitm(u64 service) { - Result rc = 0x415; - if (this->has_initialized) { - rc = Registration::UninstallMitmForPid(this->pid, service); - } - return {rc}; -} \ No newline at end of file diff --git a/stratosphere/sm/source/sm_user_service.hpp b/stratosphere/sm/source/sm_user_service.hpp index 8f3250472..f99f65bc2 100644 --- a/stratosphere/sm/source/sm_user_service.hpp +++ b/stratosphere/sm/source/sm_user_service.hpp @@ -16,7 +16,8 @@ #pragma once #include <switch.h> -#include <stratosphere/iserviceobject.hpp> +#include <stratosphere.hpp> +#include "sm_types.hpp" enum UserServiceCmd { User_Cmd_Initialize = 0, @@ -30,32 +31,31 @@ enum UserServiceCmd { }; class UserService final : public IServiceObject { - u64 pid = U64_MAX; - bool has_initialized = false; - u64 deferred_service = 0; - - public: - Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) override; - Result handle_deferred() override; - - UserService *clone() override { - auto new_srv = new UserService(); - new_srv->pid = pid; - new_srv->has_initialized = has_initialized; - new_srv->deferred_service = deferred_service; - return new_srv; - } - private: + u64 pid = U64_MAX; + bool has_initialized = false; + /* Actual commands. */ - std::tuple<Result> initialize(PidDescriptor pid); - std::tuple<Result, MovedHandle> get_service(u64 service); - std::tuple<Result, MovedHandle> deferred_get_service(u64 service); - std::tuple<Result, MovedHandle> register_service(u64 service, u8 is_light, u32 max_sessions); - std::tuple<Result> unregister_service(u64 service); + virtual Result Initialize(PidDescriptor pid); + virtual Result GetService(Out<MovedHandle> out_h, SmServiceName service); + virtual Result RegisterService(Out<MovedHandle> out_h, SmServiceName service, u32 max_sessions, bool is_light); + virtual Result UnregisterService(SmServiceName service); /* Atmosphere commands. */ - std::tuple<Result, MovedHandle, MovedHandle> install_mitm(u64 service); - std::tuple<Result> uninstall_mitm(u64 service); - std::tuple<Result> associate_pid_tid_for_mitm(u64 pid, u64 tid); + virtual Result AtmosphereInstallMitm(Out<MovedHandle> srv_h, Out<MovedHandle> qry_h, SmServiceName service); + virtual Result AtmosphereUninstallMitm(SmServiceName service); + virtual Result AtmosphereAssociatePidTidForMitm(u64 pid, u64 tid); + public: + DEFINE_SERVICE_DISPATCH_TABLE { + MakeServiceCommandMeta<User_Cmd_Initialize, &UserService::Initialize>(), + MakeServiceCommandMeta<User_Cmd_GetService, &UserService::GetService>(), + MakeServiceCommandMeta<User_Cmd_RegisterService, &UserService::RegisterService>(), + MakeServiceCommandMeta<User_Cmd_UnregisterService, &UserService::UnregisterService>(), + +#ifdef SM_ENABLE_MITM + MakeServiceCommandMeta<User_Cmd_AtmosphereInstallMitm, &UserService::AtmosphereInstallMitm>(), + MakeServiceCommandMeta<User_Cmd_AtmosphereUninstallMitm, &UserService::AtmosphereUninstallMitm>(), + MakeServiceCommandMeta<User_Cmd_AtmosphereAssociatePidTidForMitm, &UserService::AtmosphereAssociatePidTidForMitm>(), +#endif + }; }; diff --git a/thermosphere/Makefile b/thermosphere/Makefile index f62bcf1f1..76f6a100b 100644 --- a/thermosphere/Makefile +++ b/thermosphere/Makefile @@ -20,7 +20,7 @@ TARGET := $(notdir $(CURDIR)) BUILD := build SOURCES := src src/lib DATA := data -INCLUDES := include +INCLUDES := include ../common/include #--------------------------------------------------------------------------------- # options for code generation diff --git a/thermosphere/src/main.c b/thermosphere/src/main.c index fed8e0f69..ea4a1219c 100644 --- a/thermosphere/src/main.c +++ b/thermosphere/src/main.c @@ -141,5 +141,5 @@ void main_el1(void * fdt) } // If we've made it here, we failed to boot, and we can't recover. - panic("We should launch Horizon, here!"); + panic("We should launch Horizon here!"); }