subrepo:
  subdir:   "libraries"
  merged:   "07af583b"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "07af583b"
git-subrepo:
  version:  "0.4.0"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "5d6aba9"
This commit is contained in:
Michael Scire 2019-12-09 03:57:37 -08:00 committed by SciresM
parent 28717bfd27
commit 0105455086
294 changed files with 29915 additions and 0 deletions

74
libraries/.gitignore vendored Normal file
View file

@ -0,0 +1,74 @@
# Prerequisites
*.d
# Object files
*.o
*.ko
*.obj
*.elf
# Linker output
*.ilk
*.map
*.exp
*.lst
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Switch Executables
*.nso
*.nro
*.nacp
*.npdm
*.pfs0
*.nsp
*.kip
# Debug files
*.dSYM/
*.su
*.idb
*.pdb
# Kernel Module Compile Results
*.mod*
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf
# Distribution files
*.tgz
*.zip
.**/
# NOTE: make sure to make exceptions to this pattern when needed!
*.bin
**/out
**/build

0
libraries/.gitmodules vendored Normal file
View file

12
libraries/.gitrepo Normal file
View file

@ -0,0 +1,12 @@
; DO NOT EDIT (unless you know what you are doing)
;
; This subdirectory is a git "subrepo", and this file is maintained by the
; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme
;
[subrepo]
remote = https://github.com/Atmosphere-NX/Atmosphere-libs
branch = master
commit = 07af583bb81df9b40be5a54659ba598d8ce9d767
parent = 71fd69eb5ac820a94d0098e9137394ef95cd837d
method = merge
cmdver = 0.4.0

339
libraries/LICENSE Normal file
View file

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

10
libraries/Makefile Normal file
View file

@ -0,0 +1,10 @@
ATMOSPHERE_LIBRARIES := libstratosphere
TOPTARGETS := all clean
$(TOPTARGETS): $(ATMOSPHERE_LIBRARIES)
$(ATMOSPHERE_LIBRARIES):
$(MAKE) -C $@ $(MAKECMDGOALS)
.PHONY: $(TOPTARGETS) $(ATMOSPHERE_LIBRARIES)

30
libraries/README.md Normal file
View file

@ -0,0 +1,30 @@
![License](https://img.shields.io/badge/License-GPLv2-blue.svg)
Atmosphere-libs is a collection of libraries for doing operating system development for the Nintendo Switch.
Licensing
=====
This software is licensed under the terms of the GPLv2, with exemptions for specific projects noted below.
You can find a copy of the license in the [LICENSE file](LICENSE).
Exemptions:
* The [yuzu emulator project](https://github.com/yuzu-emu/yuzu) is exempt from GPLv2 licensing and may (at its option) instead license any source code authored for the atmosphere-libs project as GPLv2 or later.
Credits
=====
Atmosphere-libs is currently being developed and maintained by __SciresM__.<br>
In addition to those credited in [Atmosphère's credits](https://github.com/Atmosphere-NX/Atmosphere/blob/master/README.md#Credits), we would like to thank for contributing to atmosphere-libs in some significant way:
* @[devkitPro](https://github.com/devkitPro)
* @[yellows8](https://github.com/yellows8)
* @[qlutoo](https://github.com/plutooo)
* @[hedgeberg](https://github.com/hedgeberg)
* @[Nintendo](https://github.com/Nintendo)
* @[NVidia](https://github.com/NVidia)
* @[Kaphotics](https://github.com/kwsch)
Additional credits may be found in the README.md for specific libraries.

View file

@ -0,0 +1,11 @@
ifeq ($(strip $(DEVKITPRO)),)
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
endif
include $(DEVKITPRO)/devkitA64/base_rules
export ATMOSPHERE_DEFINES += -DATMOSPHERE_ARCH_ARM64
export ATMOSPHERE_SETTINGS += -march=armv8-a -mtp=soft
export ATMOSPHERE_CFLAGS +=
export ATMOSPHERE_CXXFLAGS +=
export ATMOSPHERE_ASFLAGS +=

View file

@ -0,0 +1,5 @@
export ATMOSPHERE_DEFINES += -DATMOSPHERE_BOARD_NINTENDO_SWITCH -D__SWITCH__
export ATMOSPHERE_SETTINGS += -mtune=cortex-a57
export ATMOSPHERE_CFLAGS +=
export ATMOSPHERE_CXXFLAGS +=
export ATMOSPHERE_ASFLAGS +=

View file

@ -0,0 +1,74 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
export ATMOSPHERE_CONFIG_MAKE_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
export ATMOSPHERE_LIBRARIES_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/..
ifeq ($(strip $(ATMOSPHERE_BOARD)),)
export ATMOSPHERE_BOARD := nx-hac-001
endif
export ATMOSPHERE_DEFINES := -DATMOSPHERE
export ATMOSPHERE_SETTINGS := -fPIE -g
export ATMOSPHERE_CFLAGS := -Wall -ffunction-sections -fdata-sections -fno-strict-aliasing -fwrapv \
-fno-asynchronous-unwind-tables -fno-unwind-tables -fno-stack-protector
export ATMOSPHERE_CXXFLAGS := -fno-rtti -fno-exceptions -std=gnu++17
export ATMOSPHERE_ASFLAGS :=
ifeq ($(ATMOSPHERE_BOARD),nx-hac-001)
export ATMOSPHERE_ARCH_DIR := arch/arm64
export ATMOSPHERE_BOARD_DIR := board/nintendo/switch
export ATMOSPHERE_OS_DIR := os/horizon
export ATMOSPHERE_ARCH_NAME := arm64
export ATMOSPHERE_BOARD_NAME := nintendo_switch
export ATMOSPHERE_OS_NAME := horizon
endif
export ATMOSPHERE_ARCH_MAKE_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/$(ATMOSPHERE_ARCH_DIR)
export ATMOSPHERE_BOARD_MAKE_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/$(ATMOSPHERE_BOARD_DIR)
export ATMOSPHERE_OS_MAKE_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/$(ATMOSPHERE_OS_DIR)
include $(ATMOSPHERE_ARCH_MAKE_DIR)/arch.mk
include $(ATMOSPHERE_BOARD_MAKE_DIR)/board.mk
include $(ATMOSPHERE_OS_MAKE_DIR)/os.mk
#---------------------------------------------------------------------------------
# get atmosphere git revision information
#---------------------------------------------------------------------------------
export ATMOSPHERE_GIT_BRANCH := $(shell git symbolic-ref --short HEAD)
ifeq ($(strip $(shell git status --porcelain 2>/dev/null)),)
export ATMOSPHERE_GIT_REVISION := $(ATMOSPHERE_GIT_BRANCH)-$(shell git rev-parse --short HEAD)
else
export ATMOSPHERE_GIT_REVISION := $(ATMOSPHERE_GIT_BRANCH)-$(shell git rev-parse --short HEAD)-dirty
endif
ATMOSPHERE_DEFINES += -DATMOSPHERE_GIT_BRANCH=\"$(ATMOSPHERE_GIT_BRANCH)\" -DATMOSPHERE_GIT_REVISION=\"$(ATMOSPHERE_GIT_REVISION)\"
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# SOURCES is a list of directories containing source code
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
#---------------------------------------------------------------------------------
export TARGET := $(notdir $(CURDIR))
export BUILD := build
export DATA := data
export INCLUDES := include
export SOURCES ?= $(shell find source -type d \
-not \( -path source/arch -prune \) \
-not \( -path source/board -prune \) \)
ifneq ($(strip $(wildcard source/$(ATMOSPHERE_ARCH_DIR)./.*)),)
SOURCES += $(shell find source/$(ATMOSPHERE_ARCH_DIR) -type d)
endif
ifneq ($(strip $(wildcard source/$(ATMOSPHERE_BOARD_DIR)./.*)),)
SOURCES += $(shell find source/$(ATMOSPHERE_BOARD_DIR) -type d)
endif
ifneq ($(strip $(wildcard source/$(ATMOSPHERE_OS_DIR)./.*)),)
SOURCES += $(shell find source/$(ATMOSPHERE_OS_DIR) -type d)
endif

View file

@ -0,0 +1,5 @@
export ATMOSPHERE_DEFINES += -DATMOSPHERE_OS_HORIZON
export ATMOSPHERE_SETTINGS +=
export ATMOSPHERE_CFLAGS +=
export ATMOSPHERE_CXXFLAGS +=
export ATMOSPHERE_ASFLAGS +=

View file

@ -0,0 +1,52 @@
#---------------------------------------------------------------------------------
# pull in common atmosphere configuration
#---------------------------------------------------------------------------------
include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../common.mk
#---------------------------------------------------------------------------------
# pull in switch rules
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITPRO)),)
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
endif
include $(DEVKITPRO)/libnx/switch_rules
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
export DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_STRATOSPHERE
export SETTINGS := $(ATMOSPHERE_SETTINGS) -O2
export CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
export CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS)
export ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS)
export CXXWRAPS := -Wl,--wrap,__cxa_pure_virtual \
-Wl,--wrap,__cxa_throw \
-Wl,--wrap,__cxa_rethrow \
-Wl,--wrap,__cxa_allocate_exception \
-Wl,--wrap,__cxa_free_exception \
-Wl,--wrap,__cxa_begin_catch \
-Wl,--wrap,__cxa_end_catch \
-Wl,--wrap,__cxa_call_unexpected \
-Wl,--wrap,__cxa_call_terminate \
-Wl,--wrap,__gxx_personality_v0 \
-Wl,--wrap,_Unwind_Resume \
-Wl,--wrap,_ZSt19__throw_logic_errorPKc \
-Wl,--wrap,_ZSt20__throw_length_errorPKc \
-Wl,--wrap,_ZNSt11logic_errorC2EPKc
export LDFLAGS := -specs=$(DEVKITPRO)/libnx/switch.specs $(SETTINGS) $(CXXWRAPS) -Wl,-Map,$(notdir $*.map)
export LIBS := -lstratosphere -lnx
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
export LIBDIRS := $(PORTLIBS) $(LIBNX) $(ATMOSPHERE_LIBRARIES_DIR)/libvapours $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere
#---------------------------------------------------------------------------------
# stratosphere sysmodules may (but usually do not) have an exefs source dir
#---------------------------------------------------------------------------------
export EXEFS_SRC := exefs_src

View file

@ -0,0 +1,140 @@
#---------------------------------------------------------------------------------
# pull in common atmosphere configuration
#---------------------------------------------------------------------------------
include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../config/common.mk
#---------------------------------------------------------------------------------
# pull in switch rules
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITPRO)),)
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
endif
include $(DEVKITPRO)/libnx/switch_rules
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_STRATOSPHERE
SETTINGS := $(ATMOSPHERE_SETTINGS) -O2
CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -flto
ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS)
LDFLAGS := -specs=$(DEVKITPRO)/libnx/switch.specs $(SETTINGS) -Wl,-Map,$(notdir $*.map)
LIBS := -lnx
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(PORTLIBS) $(LIBNX) $(ATMOSPHERE_LIBRARIES_DIR)/libvapours
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
CFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.c)) $(notdir $(wildcard $(dir)/*.board.*.c)) $(notdir $(wildcard $(dir)/*.os.*.c)), \
$(notdir $(wildcard $(dir)/*.c))))
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).c)))
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).c)))
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).c)))
CPPFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.cpp)) $(notdir $(wildcard $(dir)/*.board.*.cpp)) $(notdir $(wildcard $(dir)/*.os.*.cpp)), \
$(notdir $(wildcard $(dir)/*.cpp))))
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).cpp)))
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).cpp)))
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).cpp)))
SFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.s)) $(notdir $(wildcard $(dir)/*.board.*.s)) $(notdir $(wildcard $(dir)/*.os.*.s)), \
$(notdir $(wildcard $(dir)/*.s))))
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).s)))
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).s)))
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).s)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
export HFILES := $(addsuffix .h,$(subst .,_,$(BINFILES)))
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I.
.PHONY: clean all
#---------------------------------------------------------------------------------
all: lib/$(TARGET).a
lib:
@[ -d $@ ] || mkdir -p $@
release:
@[ -d $@ ] || mkdir -p $@
lib/$(TARGET).a : lib release $(SOURCES) $(INCLUDES)
@$(MAKE) BUILD=release OUTPUT=$(CURDIR)/$@ \
BUILD_CFLAGS="-DNDEBUG=1 -O2" \
DEPSDIR=$(CURDIR)/release \
--no-print-directory -C release \
-f $(CURDIR)/Makefile
dist-bin: all
@tar --exclude=*~ -cjf $(TARGET).tar.bz2 include lib
dist-src:
@tar --exclude=*~ -cjf $(TARGET)-src.tar.bz2 include source Makefile
dist: dist-src dist-bin
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr release lib *.bz2
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT) : $(OFILES)
$(OFILES_SRC) : $(HFILES)
#---------------------------------------------------------------------------------
%_bin.h %.bin.o : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

View file

@ -0,0 +1,31 @@
![License](https://img.shields.io/badge/License-GPLv2-blue.svg)
libstratosphere is a work-in-progress C++ library for development of system modules for the Nintendo Switch.
It is built around extending [libnx](https://github.com/switchbrew/libnx).
It also provides bindings for custom extensions to Horizon OS implemented by [Atmosphère](https://github.com/Atmosphere-NX).
Licensing
=====
This software is licensed under the terms of the GPLv2, with exemptions for specific projects noted below.
You can find a copy of the license in the [LICENSE file](LICENSE).
Exemptions:
* The [yuzu emulator project](https://github.com/yuzu-emu/yuzu) is exempt from GPLv2 licensing and may (at its option) instead license any source code authored for the libstratosphere project as GPLv2 or later.
Credits
=====
libstratosphere is currently being developed and maintained by __SciresM__.<br>
In addition to those credited in [Atmosphère's credits](https://github.com/Atmosphere-NX/Atmosphere/blob/master/README.md#Credits), we would like to thank for contributing to libstratosphere in some significant way:
* __hthh__
* __fincs__
* __lioncash__
* __misson20000__
* __neobrain__
* __yellows8__

View file

@ -0,0 +1,58 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
/* libvapours (pulls in util, svc, results). */
#include <vapours.hpp>
/* Libstratosphere-only utility. */
#include "stratosphere/util.hpp"
/* Critical modules with no dependencies. */
#include "stratosphere/ams.hpp"
#include "stratosphere/os.hpp"
#include "stratosphere/dd.hpp"
/* Lots of things depend on NCM, for Program IDs. */
#include "stratosphere/ncm.hpp"
/* At this point, just include the rest alphabetically. */
/* TODO: Figure out optimal order. */
#include "stratosphere/boot2.hpp"
#include "stratosphere/cfg.hpp"
#include "stratosphere/dmnt.hpp"
#include "stratosphere/fatal.hpp"
#include "stratosphere/hid.hpp"
#include "stratosphere/hos.hpp"
#include "stratosphere/kvdb.hpp"
#include "stratosphere/ldr.hpp"
#include "stratosphere/map.hpp"
#include "stratosphere/patcher.hpp"
#include "stratosphere/pm.hpp"
#include "stratosphere/reg.hpp"
#include "stratosphere/rnd.hpp"
#include "stratosphere/ro.hpp"
#include "stratosphere/settings.hpp"
#include "stratosphere/sf.hpp"
#include "stratosphere/sm.hpp"
#include "stratosphere/spl.hpp"
#include "stratosphere/updater.hpp"
/* Include FS last. */
#include "stratosphere/fs.hpp"
#include "stratosphere/fssrv.hpp"
#include "stratosphere/fssystem.hpp"

View file

@ -0,0 +1,22 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "ams/ams_types.hpp"
#include "ams/ams_exosphere_api.hpp"
#include "ams/ams_emummc_api.hpp"
#include "ams/ams_environment.hpp"

View file

@ -0,0 +1,31 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "ams_types.hpp"
namespace ams::emummc {
/* Get whether emummc is active. */
bool IsActive();
/* Get Nintendo redirection path. */
const char *GetNintendoDirPath();
/* Get Emummc folderpath, NULL if not file-based. */
const char *GetFilePath();
}

View file

@ -0,0 +1,25 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "ams_types.hpp"
namespace ams {
/* Will be called by libstratosphere on crash. */
void CrashHandler(ThreadExceptionDump *ctx);
}

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "ams_types.hpp"
namespace ams::exosphere {
ApiInfo GetApiInfo();
void ForceRebootToRcm();
void ForceRebootToIramPayload();
void ForceShutdown();
bool IsRcmBugPatched();
void CopyToIram(uintptr_t iram_dst, const void *dram_src, size_t size);
void CopyFromIram(void *dram_dst, uintptr_t iram_src, size_t size);
}
namespace ams {
/* Version checking utility. */
inline void CheckApiVersion() {
const u32 runtime_version = exosphere::GetApiInfo().GetVersion();
const u32 build_version = exosphere::GetVersion(ATMOSPHERE_RELEASE_VERSION);
if (runtime_version < build_version) {
R_ASSERT(exosphere::ResultVersionMismatch());
}
}
}

View file

@ -0,0 +1,120 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include "../sf/sf_buffer_tags.hpp"
#include "../hos.hpp"
namespace ams::exosphere {
#define AMS_DEFINE_TARGET_FIRMWARE_ENUM(n) TargetFirmware_##n = ATMOSPHERE_TARGET_FIRMWARE_##n
enum TargetFirmware : u32 {
AMS_DEFINE_TARGET_FIRMWARE_ENUM(100),
AMS_DEFINE_TARGET_FIRMWARE_ENUM(200),
AMS_DEFINE_TARGET_FIRMWARE_ENUM(300),
AMS_DEFINE_TARGET_FIRMWARE_ENUM(400),
AMS_DEFINE_TARGET_FIRMWARE_ENUM(500),
AMS_DEFINE_TARGET_FIRMWARE_ENUM(600),
AMS_DEFINE_TARGET_FIRMWARE_ENUM(620),
AMS_DEFINE_TARGET_FIRMWARE_ENUM(700),
AMS_DEFINE_TARGET_FIRMWARE_ENUM(800),
AMS_DEFINE_TARGET_FIRMWARE_ENUM(810),
AMS_DEFINE_TARGET_FIRMWARE_ENUM(900),
AMS_DEFINE_TARGET_FIRMWARE_ENUM(910),
};
#undef AMS_DEFINE_TARGET_FIRMWARE_ENUM
constexpr inline u32 GetVersion(u32 major, u32 minor, u32 micro) {
return (major << 16) | (minor << 8) | (micro);
}
struct ApiInfo {
u32 major_version;
u32 minor_version;
u32 micro_version;
TargetFirmware target_firmware;
u32 master_key_revision;
constexpr u32 GetVersion() const {
return ::ams::exosphere::GetVersion(this->major_version, this->minor_version, this->micro_version);
}
constexpr TargetFirmware GetTargetFirmware() const {
return this->target_firmware;
}
constexpr u32 GetMasterKeyRevision() const {
return this->master_key_revision;
}
};
}
namespace ams {
struct FatalErrorContext : sf::LargeData, sf::PrefersMapAliasTransferMode {
static constexpr size_t MaxStackTrace = 0x20;
static constexpr size_t MaxStackDumpSize = 0x100;
static constexpr size_t NumGprs = 29;
static constexpr uintptr_t StdAbortMagicAddress = 0x8;
static constexpr u64 StdAbortMagicValue = 0xA55AF00DDEADCAFEul;
static constexpr u32 StdAbortErrorDesc = 0xFFE;
static constexpr u32 DataAbortErrorDesc = 0x101;
static constexpr u32 Magic = 0x31454641;
u32 magic;
u32 error_desc;
u64 program_id;
union {
u64 gprs[32];
struct {
u64 _gprs[29];
u64 fp;
u64 lr;
u64 sp;
};
};
u64 pc;
u64 module_base;
u32 pstate;
u32 afsr0;
u32 afsr1;
u32 esr;
u64 far;
u64 report_identifier; /* Normally just system tick. */
u64 stack_trace_size;
u64 stack_dump_size;
u64 stack_trace[MaxStackTrace];
u8 stack_dump[MaxStackDumpSize];
};
static_assert(sizeof(FatalErrorContext) == 0x350, "sizeof(FatalErrorContext)");
static_assert(std::is_pod<FatalErrorContext>::value, "FatalErrorContext");
#ifdef ATMOSPHERE_GIT_BRANCH
NX_CONSTEXPR const char *GetGitBranch() {
return ATMOSPHERE_GIT_BRANCH;
}
#endif
#ifdef ATMOSPHERE_GIT_REVISION
NX_CONSTEXPR const char *GetGitRevision() {
return ATMOSPHERE_GIT_REVISION;
}
#endif
}

View file

@ -0,0 +1,19 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "boot2/boot2_api.hpp"

View file

@ -0,0 +1,30 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
namespace ams::boot2 {
/* Boot2 API. */
/* Normally invoked by PM. */
void LaunchPreSdCardBootProgramsAndBoot2();
/* Normally invoked by boot2. */
void LaunchPostSdCardBootPrograms();
}

View file

@ -0,0 +1,19 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "cfg/cfg_api.hpp"

View file

@ -0,0 +1,49 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "cfg_types.hpp"
#include "cfg_locale_types.hpp"
#include "../sm/sm_types.hpp"
namespace ams::cfg {
/* Privileged Process configuration. */
bool IsInitialProcess();
void GetInitialProcessRange(os::ProcessId *out_min, os::ProcessId *out_max);
/* SD card configuration. */
bool IsSdCardRequiredServicesReady();
void WaitSdCardRequiredServicesReady();
bool IsSdCardInitialized();
void WaitSdCardInitialized();
/* Override key utilities. */
OverrideStatus CaptureOverrideStatus(ncm::ProgramId program_id);
/* Locale utilities. */
OverrideLocale GetOverrideLocale(ncm::ProgramId program_id);
/* Flag utilities. */
bool HasFlag(const sm::MitmProcessInfo &process_info, const char *flag);
bool HasContentSpecificFlag(ncm::ProgramId program_id, const char *flag);
bool HasGlobalFlag(const char *flag);
/* HBL Configuration utilities. */
bool IsHblProgramId(ncm::ProgramId program_id);
bool HasHblFlag(const char *flag);
const char *GetHblPath();
}

View file

@ -0,0 +1,27 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "cfg_types.hpp"
#include "../settings/settings_types.hpp"
namespace ams::cfg {
struct OverrideLocale {
settings::LanguageCode language_code;
settings::RegionCode region_code;
};
}

View file

@ -0,0 +1,62 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "../os/os_common_types.hpp"
#include "../ncm/ncm_types.hpp"
namespace ams::cfg {
namespace impl {
enum OverrideStatusFlag : u64 {
OverrideStatusFlag_Hbl = BIT(0),
OverrideStatusFlag_ProgramSpecific = BIT(1),
OverrideStatusFlag_CheatEnabled = BIT(2),
};
}
struct OverrideStatus {
u64 keys_held;
u64 flags;
constexpr inline u64 GetKeysHeld() const { return this->keys_held; }
#define DEFINE_FLAG_ACCESSORS(flag) \
constexpr inline bool Is##flag() const { return this->flags & impl::OverrideStatusFlag_##flag; } \
constexpr inline void Set##flag() { this->flags |= impl::OverrideStatusFlag_##flag; } \
constexpr inline void Clear##flag() { this->flags &= ~u64(impl::OverrideStatusFlag_##flag); }
DEFINE_FLAG_ACCESSORS(Hbl)
DEFINE_FLAG_ACCESSORS(ProgramSpecific)
DEFINE_FLAG_ACCESSORS(CheatEnabled)
#undef DEFINE_FLAG_ACCESSORS
};
static_assert(sizeof(OverrideStatus) == 0x10, "sizeof(OverrideStatus)");
static_assert(std::is_pod<OverrideStatus>::value, "std::is_pod<OverrideStatus>::value");
constexpr inline bool operator==(const OverrideStatus &lhs, const OverrideStatus &rhs) {
return std::memcmp(&lhs, &rhs, sizeof(lhs)) == 0;
}
constexpr inline bool operator!=(const OverrideStatus &lhs, const OverrideStatus &rhs) {
return !(lhs == rhs);
}
}

View file

@ -0,0 +1,20 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "dd/dd_io_mappings.hpp"
#include "dd/dd_process_handle.hpp"

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
namespace ams::dd {
uintptr_t QueryIoMapping(uintptr_t phys_addr, size_t size);
u32 ReadRegister(uintptr_t phys_addr);
void WriteRegister(uintptr_t phys_addr, u32 value);
u32 ReadWriteRegister(uintptr_t phys_addr, u32 value, u32 mask);
/* Convenience Helper. */
inline uintptr_t GetIoMapping(uintptr_t phys_addr, size_t size) {
const uintptr_t io_mapping = QueryIoMapping(phys_addr, size);
AMS_ASSERT(io_mapping);
return io_mapping;
}
}

View file

@ -0,0 +1,24 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
namespace ams::dd {
::Handle GetCurrentProcessHandle();
}

View file

@ -0,0 +1,19 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "dmnt/dmnt_cheat_types.hpp"

View file

@ -0,0 +1,66 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "../os/os_common_types.hpp"
#include "../ncm/ncm_types.hpp"
#include "../sf/sf_buffer_tags.hpp"
namespace ams::dmnt::cheat {
struct CheatProcessMetadata {
struct MemoryRegionExtents {
u64 base;
u64 size;
};
os::ProcessId process_id;
ncm::ProgramId program_id;
MemoryRegionExtents main_nso_extents;
MemoryRegionExtents heap_extents;
MemoryRegionExtents alias_extents;
MemoryRegionExtents aslr_extents;
u8 main_nso_build_id[0x20];
};
static_assert(std::is_pod<CheatProcessMetadata>::value && sizeof(CheatProcessMetadata) == 0x70, "CheatProcessMetadata definition!");
struct CheatDefinition : sf::LargeData, sf::PrefersMapAliasTransferMode {
char readable_name[0x40];
uint32_t num_opcodes;
uint32_t opcodes[0x100];
};
struct CheatEntry : sf::LargeData, sf::PrefersMapAliasTransferMode {
bool enabled;
uint32_t cheat_id;
CheatDefinition definition;
};
static_assert(std::is_pod<CheatDefinition>::value, "CheatDefinition");
static_assert(std::is_pod<CheatEntry>::value, "CheatEntry");
struct FrozenAddressValue {
u64 value;
u8 width;
};
struct FrozenAddressEntry {
u64 address;
FrozenAddressValue value;
};
}

View file

@ -0,0 +1,19 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "fatal/fatal_types.hpp"

View file

@ -0,0 +1,348 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include "../ncm/ncm_types.hpp"
#include "../sf/sf_buffer_tags.hpp"
namespace ams::fatal {
namespace aarch64 {
enum RegisterName {
RegisterName_X0 = 0,
RegisterName_X1 = 1,
RegisterName_X2 = 2,
RegisterName_X3 = 3,
RegisterName_X4 = 4,
RegisterName_X5 = 5,
RegisterName_X6 = 6,
RegisterName_X7 = 7,
RegisterName_X8 = 8,
RegisterName_X9 = 9,
RegisterName_X10 = 10,
RegisterName_X11 = 11,
RegisterName_X12 = 12,
RegisterName_X13 = 13,
RegisterName_X14 = 14,
RegisterName_X15 = 15,
RegisterName_X16 = 16,
RegisterName_X17 = 17,
RegisterName_X18 = 18,
RegisterName_X19 = 19,
RegisterName_X20 = 20,
RegisterName_X21 = 21,
RegisterName_X22 = 22,
RegisterName_X23 = 23,
RegisterName_X24 = 24,
RegisterName_X25 = 25,
RegisterName_X26 = 26,
RegisterName_X27 = 27,
RegisterName_X28 = 28,
RegisterName_FP = 29,
RegisterName_LR = 30,
RegisterName_SP = 31,
RegisterName_PC = 32,
RegisterName_GeneralPurposeCount,
RegisterName_PState = 33,
RegisterName_Afsr0 = 34,
RegisterName_Afsr1 = 35,
RegisterName_Esr = 36,
RegisterName_Far = 37,
RegisterName_Count,
};
struct CpuContext {
using RegisterType = u64;
static constexpr size_t MaxStackTraceDepth = 0x20;
static constexpr const char *RegisterNameStrings[RegisterName_Count] = {
u8"X0",
u8"X1",
u8"X2",
u8"X3",
u8"X4",
u8"X5",
u8"X6",
u8"X7",
u8"X8",
u8"X9",
u8"X10",
u8"X11",
u8"X12",
u8"X13",
u8"X14",
u8"X15",
u8"X16",
u8"X17",
u8"X18",
u8"X19",
u8"X20",
u8"X21",
u8"X22",
u8"X23",
u8"X24",
u8"X25",
u8"X26",
u8"X27",
u8"X28",
u8"FP",
u8"LR",
u8"SP",
u8"PC",
u8"PState",
u8"Afsr0",
u8"Afsr1",
u8"Esr",
u8"Far",
};
/* Registers, exception context. N left names for these fields in fatal .rodata. */
union {
struct {
union {
RegisterType x[RegisterName_GeneralPurposeCount];
struct {
RegisterType _x[RegisterName_FP];
RegisterType fp;
RegisterType lr;
RegisterType sp;
RegisterType pc;
};
};
RegisterType pstate;
RegisterType afsr0;
RegisterType afsr1;
RegisterType esr;
RegisterType far;
};
RegisterType registers[RegisterName_Count];
};
/* Misc. */
RegisterType stack_trace[MaxStackTraceDepth];
RegisterType base_address;
RegisterType register_set_flags;
u32 stack_trace_size;
void ClearState() {
std::memset(this, 0, sizeof(*this));
}
void SetProgramIdForAtmosphere(ncm::ProgramId program_id) {
/* Right now, we mux program ID in through afsr when creport. */
/* TODO: Better way to do this? */
this->afsr0 = static_cast<RegisterType>(program_id);
}
ncm::ProgramId GetProgramIdForAtmosphere() const {
return ncm::ProgramId{this->afsr0};
}
void SetRegisterValue(RegisterName name, RegisterType value) {
this->registers[name] = value;
this->register_set_flags |= (RegisterType(1) << name);
}
bool HasRegisterValue(RegisterName name) const {
return this->register_set_flags & (RegisterType(1) << name);
}
void SetBaseAddress(RegisterType base_addr) {
this->base_address = base_addr;
}
};
}
namespace aarch32 {
enum RegisterName {
RegisterName_R0 = 0,
RegisterName_R1 = 1,
RegisterName_R2 = 2,
RegisterName_R3 = 3,
RegisterName_R4 = 4,
RegisterName_R5 = 5,
RegisterName_R6 = 6,
RegisterName_R7 = 7,
RegisterName_R8 = 8,
RegisterName_R9 = 9,
RegisterName_R10 = 10,
RegisterName_FP = 11,
RegisterName_IP = 12,
RegisterName_LR = 13,
RegisterName_SP = 14,
RegisterName_PC = 15,
RegisterName_GeneralPurposeCount,
RegisterName_PState = 16,
RegisterName_Afsr0 = 17,
RegisterName_Afsr1 = 18,
RegisterName_Esr = 29,
RegisterName_Far = 20,
RegisterName_Count,
};
struct CpuContext {
using RegisterType = u32;
static constexpr size_t MaxStackTraceDepth = 0x20;
static constexpr const char *RegisterNameStrings[RegisterName_Count] = {
u8"R0",
u8"R1",
u8"R2",
u8"R3",
u8"R4",
u8"R5",
u8"R6",
u8"R7",
u8"R8",
u8"R9",
u8"R10",
u8"FP",
u8"IP",
u8"LR",
u8"SP",
u8"PC",
u8"PState",
u8"Afsr0",
u8"Afsr1",
u8"Esr",
u8"Far",
};
/* Registers, exception context. N left names for these fields in fatal .rodata. */
union {
struct {
union {
RegisterType r[RegisterName_GeneralPurposeCount];
struct {
RegisterType _x[RegisterName_FP];
RegisterType fp;
RegisterType ip;
RegisterType lr;
RegisterType sp;
RegisterType pc;
};
};
RegisterType pstate;
RegisterType afsr0;
RegisterType afsr1;
RegisterType esr;
RegisterType far;
};
RegisterType registers[RegisterName_Count];
};
/* Misc. Yes, stack_trace_size is really laid out differently than aarch64... */
RegisterType stack_trace[MaxStackTraceDepth];
u32 stack_trace_size;
RegisterType base_address;
RegisterType register_set_flags;
void ClearState() {
std::memset(this, 0, sizeof(*this));
}
void SetProgramIdForAtmosphere(ncm::ProgramId program_id) {
/* Right now, we mux program ID in through afsr when creport. */
/* TODO: Better way to do this? */
this->afsr0 = static_cast<RegisterType>(static_cast<u64>(program_id) >> 0);
this->afsr1 = static_cast<RegisterType>(static_cast<u64>(program_id) >> 32);
}
ncm::ProgramId GetProgramIdForAtmosphere() const {
return ncm::ProgramId{(static_cast<u64>(this->afsr1) << 32ul) | (static_cast<u64>(this->afsr0) << 0ul)};
}
void SetRegisterValue(RegisterName name, RegisterType value) {
this->registers[name] = value;
this->register_set_flags |= (RegisterType(1) << name);
}
bool HasRegisterValue(RegisterName name) const {
return this->register_set_flags & (RegisterType(1) << name);
}
void SetBaseAddress(RegisterType base_addr) {
this->base_address = base_addr;
}
};
}
struct CpuContext : sf::LargeData, sf::PrefersMapAliasTransferMode {
enum Architecture {
Architecture_Aarch64 = 0,
Architecture_Aarch32 = 1,
};
union {
aarch64::CpuContext aarch64_ctx;
aarch32::CpuContext aarch32_ctx;
};
Architecture architecture;
u32 type;
void ClearState() {
std::memset(this, 0, sizeof(*this));
}
};
static_assert(std::is_pod<aarch64::CpuContext>::value && sizeof(aarch64::CpuContext) == 0x248, "aarch64::CpuContext definition!");
static_assert(std::is_pod<aarch32::CpuContext>::value && sizeof(aarch32::CpuContext) == 0xE0, "aarch32::CpuContext definition!");
static_assert(std::is_pod<CpuContext>::value && sizeof(CpuContext) == 0x250, "CpuContext definition!");
namespace srv {
struct ThrowContext {
Result result;
ncm::ProgramId program_id;
char proc_name[0xD];
bool is_creport;
CpuContext cpu_ctx;
bool generate_error_report;
Event erpt_event;
Event battery_event;
size_t stack_dump_size;
u8 stack_dump[0x100];
void ClearState() {
this->result = ResultSuccess();
this->program_id = ncm::ProgramId::Invalid;
std::memset(this->proc_name, 0, sizeof(this->proc_name));
this->is_creport = false;
std::memset(&this->cpu_ctx, 0, sizeof(this->cpu_ctx));
this->generate_error_report = false;
std::memset(&this->erpt_event, 0, sizeof(this->erpt_event));
std::memset(&this->battery_event, 0, sizeof(this->battery_event));
this->stack_dump_size = 0;
std::memset(this->stack_dump, 0, sizeof(this->stack_dump));
}
};
}
}

View file

@ -0,0 +1,28 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "fs/fs_common.hpp"
#include "fs/fsa/fs_ifile.hpp"
#include "fs/fsa/fs_idirectory.hpp"
#include "fs/fsa/fs_ifilesystem.hpp"
#include "fs/fs_remote_filesystem.hpp"
#include "fs/fs_istorage.hpp"
#include "fs/fs_remote_storage.hpp"
#include "fs/fs_file_storage.hpp"
#include "fs/fs_query_range.hpp"
#include "fs/fs_path_tool.hpp"
#include "fs/fs_path_utils.hpp"

View file

@ -0,0 +1,27 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include "../os.hpp"
#include "../ncm.hpp"
#include "../sf.hpp"
namespace ams::fs {
/* TODO: Better place for this? */
constexpr inline size_t MountNameLengthMax = 15;
}

View file

@ -0,0 +1,25 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "fs_common.hpp"
namespace ams::fs {
constexpr inline size_t EntryNameLengthMax = 0x300;
using DirectoryEntry = ::FsDirectoryEntry;
}

View file

@ -0,0 +1,63 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "fs_common.hpp"
namespace ams::fs {
struct ReadOption {
u32 value;
static const ReadOption None;
};
inline constexpr const ReadOption ReadOption::None = {FsReadOption_None};
inline constexpr bool operator==(const ReadOption &lhs, const ReadOption &rhs) {
return lhs.value == rhs.value;
}
inline constexpr bool operator!=(const ReadOption &lhs, const ReadOption &rhs) {
return !(lhs == rhs);
}
static_assert(std::is_pod<ReadOption>::value && sizeof(ReadOption) == sizeof(u32));
struct WriteOption {
u32 value;
constexpr inline bool HasFlushFlag() const {
return this->value & FsWriteOption_Flush;
}
static const WriteOption None;
static const WriteOption Flush;
};
inline constexpr const WriteOption WriteOption::None = {FsWriteOption_None};
inline constexpr const WriteOption WriteOption::Flush = {FsWriteOption_Flush};
inline constexpr bool operator==(const WriteOption &lhs, const WriteOption &rhs) {
return lhs.value == rhs.value;
}
inline constexpr bool operator!=(const WriteOption &lhs, const WriteOption &rhs) {
return !(lhs == rhs);
}
static_assert(std::is_pod<WriteOption>::value && sizeof(WriteOption) == sizeof(u32));
}

View file

@ -0,0 +1,56 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "fs_common.hpp"
#include "fs_istorage.hpp"
#include "fsa/fs_ifile.hpp"
namespace ams::fs {
class FileStorage : public IStorage {
private:
static constexpr s64 InvalidSize = -1;
private:
std::unique_ptr<fsa::IFile> unique_file;
std::shared_ptr<fsa::IFile> shared_file;
fsa::IFile *base_file;
s64 size;
public:
FileStorage(fsa::IFile *f) : unique_file(f), size(InvalidSize) {
this->base_file = this->unique_file.get();
}
FileStorage(std::unique_ptr<fsa::IFile> f) : unique_file(std::move(f)), size(InvalidSize) {
this->base_file = this->unique_file.get();
}
FileStorage(std::shared_ptr<fsa::IFile> f) : shared_file(f), size(InvalidSize) {
this->base_file = this->shared_file.get();
}
virtual ~FileStorage() { /* ... */ }
protected:
Result UpdateSize();
public:
virtual Result Read(s64 offset, void *buffer, size_t size) override;
virtual Result Write(s64 offset, const void *buffer, size_t size) override;
virtual Result Flush() override;
virtual Result GetSize(s64 *out_size) override;
virtual Result SetSize(s64 size) override;
virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override;
};
}

View file

@ -0,0 +1,52 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "fs_common.hpp"
namespace ams::fs {
enum OpenMode {
OpenMode_Read = ::FsOpenMode_Read,
OpenMode_Write = ::FsOpenMode_Write,
OpenMode_Append = ::FsOpenMode_Append,
OpenMode_ReadWrite = (OpenMode_Read | OpenMode_Write),
OpenMode_All = (OpenMode_ReadWrite | OpenMode_Append),
};
enum OpenDirectoryMode {
OpenDirectoryMode_Directory = ::FsDirOpenMode_ReadDirs,
OpenDirectoryMode_File = ::FsDirOpenMode_ReadFiles,
OpenDirectoryMode_All = (OpenDirectoryMode_Directory | OpenDirectoryMode_File),
/* TODO: Separate enum, like N? */
OpenDirectoryMode_NotRequireFileSize = ::FsDirOpenMode_NoFileSize,
};
enum DirectoryEntryType {
DirectoryEntryType_Directory = ::FsDirEntryType_Dir,
DirectoryEntryType_File = ::FsDirEntryType_File,
};
enum CreateOption {
CreateOption_None = 0,
CreateOption_BigFile = ::FsCreateOption_BigFile,
};
using FileTimeStampRaw = ::FsTimeStampRaw;
}

View file

@ -0,0 +1,106 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "fs_common.hpp"
#include "fs_file.hpp"
#include "fs_operate_range.hpp"
namespace ams::fs {
class IStorage {
public:
virtual ~IStorage() { /* ... */ }
virtual Result Read(s64 offset, void *buffer, size_t size) = 0;
virtual Result Write(s64 offset, const void *buffer, size_t size) {
return fs::ResultUnsupportedOperation();
}
virtual Result Flush() = 0;
virtual Result SetSize(s64 size) {
return fs::ResultUnsupportedOperation();
}
virtual Result GetSize(s64 *out) = 0;
virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) {
return fs::ResultUnsupportedOperation();
}
virtual Result OperateRange(OperationId op_id, s64 offset, s64 size) {
return this->OperateRange(nullptr, 0, op_id, offset, size, nullptr, 0);
}
public:
static inline bool IsRangeValid(s64 offset, s64 size, s64 total_size) {
return offset >= 0 &&
size >= 0 &&
size <= total_size &&
offset <= (total_size - size);
}
static inline bool IsRangeValid(s64 offset, size_t size, s64 total_size) {
return IsRangeValid(offset, static_cast<s64>(size), total_size);
}
static inline bool IsOffsetAndSizeValid(s64 offset, s64 size) {
return offset >= 0 &&
size >= 0 &&
offset <= (offset + size);
}
static inline bool IsOffsetAndSizeValid(s64 offset, size_t size) {
return IsOffsetAndSizeValid(offset, static_cast<s64>(size));
}
};
class ReadOnlyStorageAdapter : public IStorage {
private:
std::shared_ptr<IStorage> shared_storage;
std::unique_ptr<IStorage> unique_storage;
IStorage *storage;
public:
ReadOnlyStorageAdapter(IStorage *s) : unique_storage(s) {
this->storage = this->unique_storage.get();
}
ReadOnlyStorageAdapter(std::shared_ptr<IStorage> s) : shared_storage(s) {
this->storage = this->shared_storage.get();
}
ReadOnlyStorageAdapter(std::unique_ptr<IStorage> s) : unique_storage(std::move(s)) {
this->storage = this->unique_storage.get();
}
virtual ~ReadOnlyStorageAdapter() { /* ... */ }
public:
virtual Result Read(s64 offset, void *buffer, size_t size) {
return this->storage->Read(offset, buffer, size);
}
virtual Result Flush() {
return this->storage->Flush();
}
virtual Result GetSize(s64 *out) {
return this->storage->GetSize(out);
}
virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override {
return this->storage->OperateRange(dst, dst_size, op_id, offset, size, src, src_size);
}
};
}

View file

@ -0,0 +1,28 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "fs_common.hpp"
namespace ams::fs {
enum class OperationId : u64 {
Clear = ::FsOperationId_Clear,
ClearSignature = ::FsOperationId_ClearSignature,
InvalidateCache = ::FsOperationId_InvalidateCache,
QueryRange = ::FsOperationId_QueryRange,
};
}

View file

@ -0,0 +1,73 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "fs_common.hpp"
#include "../fssrv/fssrv_sf_path.hpp"
namespace ams::fs {
namespace StringTraits {
constexpr inline char DirectorySeparator = '/';
constexpr inline char DriveSeparator = ':';
constexpr inline char Dot = '.';
constexpr inline char NullTerminator = '\x00';
}
class PathTool {
public:
static constexpr const char RootPath[] = "/";
public:
static constexpr inline bool IsSeparator(char c) {
return c == StringTraits::DirectorySeparator;
}
static constexpr inline bool IsNullTerminator(char c) {
return c == StringTraits::NullTerminator;
}
static constexpr inline bool IsDot(char c) {
return c == StringTraits::Dot;
}
static constexpr inline bool IsWindowsDriveCharacter(char c) {
return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
}
static constexpr inline bool IsDriveSeparator(char c) {
return c == StringTraits::DriveSeparator;
}
static constexpr inline bool IsWindowsAbsolutePath(const char *p) {
return IsWindowsDriveCharacter(p[0]) && IsDriveSeparator(p[1]);
}
static constexpr inline bool IsCurrentDirectory(const char *p) {
return IsDot(p[0]) && (IsSeparator(p[1]) || IsNullTerminator(p[1]));
}
static constexpr inline bool IsParentDirectory(const char *p) {
return IsDot(p[0]) && IsDot(p[1]) && (IsSeparator(p[2]) || IsNullTerminator(p[2]));
}
static Result Normalize(char *out, size_t *out_len, const char *src, size_t max_out_size, bool unc_preserved = false);
static Result IsNormalized(bool *out, const char *path);
static bool IsSubPath(const char *lhs, const char *rhs);
};
}

View file

@ -0,0 +1,48 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "fs_common.hpp"
#include "../fssrv/fssrv_sf_path.hpp"
namespace ams::fs {
inline void Replace(char *dst, size_t dst_size, char old_char, char new_char) {
for (char *cur = dst; cur < dst + dst_size && *cur != '\x00'; cur++) {
if (*cur == old_char) {
*cur = new_char;
}
}
}
inline Result FspPathPrintf(fssrv::sf::FspPath *dst, const char *format, ...) {
/* Format the path. */
std::va_list va_list;
va_start(va_list, format);
const size_t len = std::vsnprintf(dst->str, sizeof(dst->str), format, va_list);
va_end(va_list);
/* Validate length. */
R_UNLESS(len < sizeof(dst->str), fs::ResultTooLongPath());
/* Fix slashes. */
Replace(dst->str, sizeof(dst->str) - 1, '\\', '/');
return ResultSuccess();
}
Result VerifyPath(const char *path, size_t max_path_len, size_t max_name_len);
}

View file

@ -0,0 +1,45 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "fs_common.hpp"
namespace ams::fs {
struct QueryRangeInfo {
u32 aes_ctr_key_type;
u32 speed_emulation_type;
u32 reserved[0x38 / sizeof(u32)];
void Clear() {
this->aes_ctr_key_type = 0;
this->speed_emulation_type = 0;
std::memset(this->reserved, 0, sizeof(this->reserved));
}
void Merge(const QueryRangeInfo &rhs) {
this->aes_ctr_key_type |= rhs.aes_ctr_key_type;
this->speed_emulation_type |= rhs.speed_emulation_type;
}
};
static_assert(std::is_pod<QueryRangeInfo>::value);
static_assert(sizeof(QueryRangeInfo) == 0x40);
static_assert(sizeof(QueryRangeInfo) == sizeof(::FsRangeInfo));
using FileQueryRangeInfo = QueryRangeInfo;
using StorageQueryRangeInfo = QueryRangeInfo;
}

View file

@ -0,0 +1,179 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "fs_common.hpp"
#include "fsa/fs_ifile.hpp"
#include "fsa/fs_idirectory.hpp"
#include "fsa/fs_ifilesystem.hpp"
namespace ams::fs {
class RemoteFile : public fsa::IFile {
private:
std::unique_ptr<::FsFile> base_file;
public:
RemoteFile(::FsFile *f) : base_file(f) { /* ... */ }
RemoteFile(std::unique_ptr<::FsFile> f) : base_file(std::move(f)) { /* ... */ }
RemoteFile(::FsFile f) {
this->base_file = std::make_unique<::FsFile>(f);
}
virtual ~RemoteFile() { fsFileClose(this->base_file.get()); }
public:
virtual Result ReadImpl(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) override final {
return fsFileRead(this->base_file.get(), offset, buffer, size, option.value, out);
}
virtual Result GetSizeImpl(s64 *out) override final {
return fsFileGetSize(this->base_file.get(), out);
}
virtual Result FlushImpl() override final {
return fsFileFlush(this->base_file.get());
}
virtual Result WriteImpl(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) override final {
return fsFileWrite(this->base_file.get(), offset, buffer, size, option.value);
}
virtual Result SetSizeImpl(s64 size) override final {
return fsFileSetSize(this->base_file.get(), size);
}
virtual Result OperateRangeImpl(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override final {
/* TODO: How should this be handled? */
return fs::ResultNotImplemented();
}
public:
virtual sf::cmif::DomainObjectId GetDomainObjectId() const override {
return sf::cmif::DomainObjectId{serviceGetObjectId(&this->base_file->s)};
}
};
class RemoteDirectory : public fsa::IDirectory {
private:
std::unique_ptr<::FsDir> base_dir;
public:
RemoteDirectory(::FsDir *d) : base_dir(d) { /* ... */ }
RemoteDirectory(std::unique_ptr<::FsDir> d) : base_dir(std::move(d)) { /* ... */ }
RemoteDirectory(::FsDir d) {
this->base_dir = std::make_unique<::FsDir>(d);
}
virtual ~RemoteDirectory() { fsDirClose(this->base_dir.get()); }
public:
virtual Result ReadImpl(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries) override final {
return fsDirRead(this->base_dir.get(), out_count, max_entries, out_entries);
}
virtual Result GetEntryCountImpl(s64 *out) override final {
return fsDirGetEntryCount(this->base_dir.get(), out);
}
public:
virtual sf::cmif::DomainObjectId GetDomainObjectId() const override {
return sf::cmif::DomainObjectId{serviceGetObjectId(&this->base_dir->s)};
}
};
class RemoteFileSystem : public fsa::IFileSystem {
private:
std::unique_ptr<::FsFileSystem> base_fs;
public:
RemoteFileSystem(::FsFileSystem *fs) : base_fs(fs) { /* ... */ }
RemoteFileSystem(std::unique_ptr<::FsFileSystem> fs) : base_fs(std::move(fs)) { /* ... */ }
RemoteFileSystem(::FsFileSystem fs) {
this->base_fs = std::make_unique<::FsFileSystem>(fs);
}
virtual ~RemoteFileSystem() { fsFsClose(this->base_fs.get()); }
public:
virtual Result CreateFileImpl(const char *path, s64 size, int flags) override final {
return fsFsCreateFile(this->base_fs.get(), path, size, flags);
}
virtual Result DeleteFileImpl(const char *path) override final {
return fsFsDeleteFile(this->base_fs.get(), path);
}
virtual Result CreateDirectoryImpl(const char *path) override final {
return fsFsCreateDirectory(this->base_fs.get(), path);
}
virtual Result DeleteDirectoryImpl(const char *path) override final {
return fsFsDeleteDirectory(this->base_fs.get(), path);
}
virtual Result DeleteDirectoryRecursivelyImpl(const char *path) override final {
return fsFsDeleteDirectoryRecursively(this->base_fs.get(), path);
}
virtual Result RenameFileImpl(const char *old_path, const char *new_path) override final {
return fsFsRenameFile(this->base_fs.get(), old_path, new_path);
}
virtual Result RenameDirectoryImpl(const char *old_path, const char *new_path) override final {
return fsFsRenameDirectory(this->base_fs.get(), old_path, new_path);
}
virtual Result GetEntryTypeImpl(DirectoryEntryType *out, const char *path) override final {
static_assert(sizeof(::FsDirEntryType) == sizeof(DirectoryEntryType));
return fsFsGetEntryType(this->base_fs.get(), path, reinterpret_cast<::FsDirEntryType *>(out));
}
virtual Result OpenFileImpl(std::unique_ptr<fsa::IFile> *out_file, const char *path, OpenMode mode) override final {
FsFile f;
R_TRY(fsFsOpenFile(this->base_fs.get(), path, mode, &f));
*out_file = std::make_unique<RemoteFile>(f);
return ResultSuccess();
}
virtual Result OpenDirectoryImpl(std::unique_ptr<fsa::IDirectory> *out_dir, const char *path, OpenDirectoryMode mode) override final {
FsDir d;
R_TRY(fsFsOpenDirectory(this->base_fs.get(), path, mode, &d));
*out_dir = std::make_unique<RemoteDirectory>(d);
return ResultSuccess();
}
virtual Result CommitImpl() override final {
return fsFsCommit(this->base_fs.get());
}
virtual Result GetFreeSpaceSizeImpl(s64 *out, const char *path) {
return fsFsGetFreeSpace(this->base_fs.get(), path, out);
}
virtual Result GetTotalSpaceSizeImpl(s64 *out, const char *path) {
return fsFsGetTotalSpace(this->base_fs.get(), path, out);
}
virtual Result CleanDirectoryRecursivelyImpl(const char *path) {
return fsFsCleanDirectoryRecursively(this->base_fs.get(), path);
}
virtual Result GetFileTimeStampRawImpl(FileTimeStampRaw *out, const char *path) {
static_assert(sizeof(FileTimeStampRaw) == sizeof(::FsTimeStampRaw));
return fsFsGetFileTimeStampRaw(this->base_fs.get(), path, reinterpret_cast<::FsTimeStampRaw *>(out));
}
virtual Result QueryEntryImpl(char *dst, size_t dst_size, const char *src, size_t src_size, fsa::QueryId query, const char *path) {
return fsFsQueryEntry(this->base_fs.get(), dst, dst_size, src, src_size, path, static_cast<FsFileSystemQueryId>(query));
}
};
}

View file

@ -0,0 +1,60 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "fs_common.hpp"
#include "fs_istorage.hpp"
namespace ams::fs {
class RemoteStorage : public IStorage {
private:
std::unique_ptr<::FsStorage> base_storage;
public:
RemoteStorage(::FsStorage *s) : base_storage(s) { /* ... */ }
RemoteStorage(std::unique_ptr<::FsStorage> s) : base_storage(std::move(s)) { /* ... */ }
RemoteStorage(::FsStorage s) {
this->base_storage = std::make_unique<::FsStorage>(s);
}
virtual ~RemoteStorage() { fsStorageClose(this->base_storage.get()); }
public:
virtual Result Read(s64 offset, void *buffer, size_t size) override {
return fsStorageRead(this->base_storage.get(), offset, buffer, size);
};
virtual Result Write(s64 offset, const void *buffer, size_t size) override {
return fsStorageWrite(this->base_storage.get(), offset, buffer, size);
};
virtual Result Flush() override {
return fsStorageFlush(this->base_storage.get());
};
virtual Result GetSize(s64 *out_size) override {
return fsStorageGetSize(this->base_storage.get(), out_size);
};
virtual Result SetSize(s64 size) override {
return fsStorageSetSize(this->base_storage.get(), size);
};
virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override {
/* TODO: How to deal with this? */
return fs::ResultUnsupportedOperation();
};
};
}

View file

@ -0,0 +1,52 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "../fs_common.hpp"
#include "../fs_directory.hpp"
namespace ams::fs::fsa {
class IDirectory {
public:
virtual ~IDirectory() { /* ... */ }
Result Read(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries) {
R_UNLESS(out_count != nullptr, fs::ResultNullptrArgument());
if (max_entries == 0) {
*out_count = 0;
return ResultSuccess();
}
R_UNLESS(out_entries != nullptr, fs::ResultNullptrArgument());
R_UNLESS(max_entries > 0, fs::ResultInvalidArgument());
return this->ReadImpl(out_count, out_entries, max_entries);
}
Result GetEntryCount(s64 *out) {
R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
return this->GetEntryCountImpl(out);
}
public:
/* TODO: This is a hack to allow the mitm API to work. Find a better way? */
virtual sf::cmif::DomainObjectId GetDomainObjectId() const = 0;
protected:
/* ...? */
private:
virtual Result ReadImpl(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries) = 0;
virtual Result GetEntryCountImpl(s64 *out) = 0;
};
}

View file

@ -0,0 +1,95 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "../fs_common.hpp"
#include "../fs_file.hpp"
#include "../fs_operate_range.hpp"
namespace ams::fs::fsa {
class IFile {
public:
virtual ~IFile() { /* ... */ }
Result Read(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) {
R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
if (size == 0) {
*out = 0;
return ResultSuccess();
}
R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument());
R_UNLESS(offset >= 0, fs::ResultOutOfRange());
const s64 signed_size = static_cast<s64>(size);
R_UNLESS(signed_size >= 0, fs::ResultOutOfRange());
R_UNLESS((std::numeric_limits<s64>::max() - offset) >= signed_size, fs::ResultOutOfRange());
return this->ReadImpl(out, offset, buffer, size, option);
}
Result Read(size_t *out, s64 offset, void *buffer, size_t size) {
return this->Read(out, offset, buffer, size, ReadOption::None);
}
Result GetSize(s64 *out) {
R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
return this->GetSizeImpl(out);
}
Result Flush() {
return this->FlushImpl();
}
Result Write(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) {
if (size == 0) {
if (option.HasFlushFlag()) {
R_TRY(this->Flush());
}
return ResultSuccess();
}
R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument());
R_UNLESS(offset >= 0, fs::ResultOutOfRange());
const s64 signed_size = static_cast<s64>(size);
R_UNLESS(signed_size >= 0, fs::ResultOutOfRange());
R_UNLESS((std::numeric_limits<s64>::max() - offset) >= signed_size, fs::ResultOutOfRange());
return this->WriteImpl(offset, buffer, size, option);
}
Result SetSize(s64 size) {
R_UNLESS(size >= 0, fs::ResultOutOfRange());
return this->SetSizeImpl(size);
}
Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) {
return this->OperateRangeImpl(dst, dst_size, op_id, offset, size, src, src_size);
}
Result OperateRange(fs::OperationId op_id, s64 offset, s64 size) {
return this->OperateRangeImpl(nullptr, 0, op_id, offset, size, nullptr, 0);
}
public:
/* TODO: This is a hack to allow the mitm API to work. Find a better way? */
virtual sf::cmif::DomainObjectId GetDomainObjectId() const = 0;
protected:
/* ...? */
private:
virtual Result ReadImpl(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) = 0;
virtual Result GetSizeImpl(s64 *out) = 0;
virtual Result FlushImpl() = 0;
virtual Result WriteImpl(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) = 0;
virtual Result SetSizeImpl(s64 size) = 0;
virtual Result OperateRangeImpl(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) = 0;
};
}

View file

@ -0,0 +1,191 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "../fs_common.hpp"
#include "../fs_filesystem.hpp"
namespace ams::fs::fsa {
class IFile;
class IDirectory;
enum class QueryId {
SetConcatenationFileAttribute = FsFileSystemQueryId_SetConcatenationFileAttribute
};
class IFileSystem {
public:
virtual ~IFileSystem() { /* ... */ }
Result CreateFile(const char *path, s64 size, int option) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
R_UNLESS(size >= 0, fs::ResultOutOfRange());
return this->CreateFileImpl(path, size, option);
}
Result CreateFile(const char *path, s64 size) {
return this->CreateFile(path, size, 0);
}
Result DeleteFile(const char *path) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
return this->DeleteFileImpl(path);
}
Result CreateDirectory(const char *path) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
return this->CreateDirectoryImpl(path);
}
Result DeleteDirectory(const char *path) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
return this->DeleteDirectoryImpl(path);
}
Result DeleteDirectoryRecursively(const char *path) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
return this->DeleteDirectoryRecursivelyImpl(path);
}
Result RenameFile(const char *old_path, const char *new_path) {
R_UNLESS(old_path != nullptr, fs::ResultInvalidPath());
R_UNLESS(new_path != nullptr, fs::ResultInvalidPath());
return this->RenameFileImpl(old_path, new_path);
}
Result RenameDirectory(const char *old_path, const char *new_path) {
R_UNLESS(old_path != nullptr, fs::ResultInvalidPath());
R_UNLESS(new_path != nullptr, fs::ResultInvalidPath());
return this->RenameDirectoryImpl(old_path, new_path);
}
Result GetEntryType(DirectoryEntryType *out, const char *path) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
return this->GetEntryTypeImpl(out, path);
}
Result OpenFile(std::unique_ptr<IFile> *out_file, const char *path, OpenMode mode) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
R_UNLESS(out_file != nullptr, fs::ResultNullptrArgument());
R_UNLESS((mode & OpenMode_ReadWrite) != 0, fs::ResultInvalidArgument());
R_UNLESS((mode & ~OpenMode_All) == 0, fs::ResultInvalidArgument());
return this->OpenFileImpl(out_file, path, mode);
}
Result OpenDirectory(std::unique_ptr<IDirectory> *out_dir, const char *path, OpenDirectoryMode mode) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
R_UNLESS(out_dir != nullptr, fs::ResultNullptrArgument());
R_UNLESS((mode & OpenDirectoryMode_All) != 0, fs::ResultInvalidArgument());
R_UNLESS((mode & ~OpenDirectoryMode_All) == 0, fs::ResultInvalidArgument());
return this->OpenDirectoryImpl(out_dir, path, mode);
}
Result Commit() {
return this->CommitImpl();
}
Result GetFreeSpaceSize(s64 *out, const char *path) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
return this->GetFreeSpaceSizeImpl(out, path);
}
Result GetTotalSpaceSize(s64 *out, const char *path) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
return this->GetTotalSpaceSizeImpl(out, path);
}
Result CleanDirectoryRecursively(const char *path) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
return this->CleanDirectoryRecursivelyImpl(path);
}
Result GetFileTimeStampRaw(FileTimeStampRaw *out, const char *path) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
return this->GetFileTimeStampRawImpl(out, path);
}
Result QueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, QueryId query, const char *path) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
return this->QueryEntryImpl(dst, dst_size, src, src_size, query, path);
}
/* These aren't accessible as commands. */
Result CommitProvisionally(s64 counter) {
return this->CommitProvisionallyImpl(counter);
}
Result Rollback() {
return this->RollbackImpl();
}
Result Flush() {
return this->FlushImpl();
}
protected:
/* ...? */
private:
virtual Result CreateFileImpl(const char *path, s64 size, int flags) = 0;
virtual Result DeleteFileImpl(const char *path) = 0;
virtual Result CreateDirectoryImpl(const char *path) = 0;
virtual Result DeleteDirectoryImpl(const char *path) = 0;
virtual Result DeleteDirectoryRecursivelyImpl(const char *path) = 0;
virtual Result RenameFileImpl(const char *old_path, const char *new_path) = 0;
virtual Result RenameDirectoryImpl(const char *old_path, const char *new_path) = 0;
virtual Result GetEntryTypeImpl(fs::DirectoryEntryType *out, const char *path) = 0;
virtual Result OpenFileImpl(std::unique_ptr<fs::fsa::IFile> *out_file, const char *path, fs::OpenMode mode) = 0;
virtual Result OpenDirectoryImpl(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const char *path, fs::OpenDirectoryMode mode) = 0;
virtual Result CommitImpl() = 0;
virtual Result GetFreeSpaceSizeImpl(s64 *out, const char *path) {
return fs::ResultNotImplemented();
}
virtual Result GetTotalSpaceSizeImpl(s64 *out, const char *path) {
return fs::ResultNotImplemented();
}
virtual Result CleanDirectoryRecursivelyImpl(const char *path) = 0;
virtual Result GetFileTimeStampRawImpl(fs::FileTimeStampRaw *out, const char *path) {
return fs::ResultNotImplemented();
}
virtual Result QueryEntryImpl(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const char *path) {
return fs::ResultNotImplemented();
}
/* These aren't accessible as commands. */
virtual Result CommitProvisionallyImpl(s64 counter) {
return fs::ResultNotImplemented();
}
virtual Result RollbackImpl() {
return fs::ResultNotImplemented();
}
virtual Result FlushImpl() {
return fs::ResultNotImplemented();
}
};
}

View file

@ -0,0 +1,19 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "fssrv/fssrv_sf_path.hpp"
#include "fssrv/fssrv_path_normalizer.hpp"

View file

@ -0,0 +1,18 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "interface_adapters/fssrv_storage_interface_adapter.hpp"
#include "interface_adapters/fssrv_filesystem_interface_adapter.hpp"

View file

@ -0,0 +1,66 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "../fs/fs_common.hpp"
namespace ams::fssrv {
/* This is in fssrv::detail in official code. */
/* TODO: Consider moving to ::impl? */
class PathNormalizer {
public:
enum Option : u32 {
Option_None = BIT(0),
Option_PreserveUnc = BIT(1),
Option_PreserveTailSeparator = BIT(2),
Option_HasMountName = BIT(3),
Option_AcceptEmpty = BIT(4),
};
private:
using Buffer = std::unique_ptr<char[]>;
private:
Buffer buffer;
const char *path;
Result result;
private:
static Result Normalize(const char **out_path, Buffer *out_buf, const char *path, bool preserve_unc, bool preserve_tail_sep, bool has_mount_name);
public:
explicit PathNormalizer(const char *p) : buffer(), path(nullptr), result(ResultSuccess()) {
this->result = Normalize(&this->path, &this->buffer, p, false, false, false);
}
PathNormalizer(const char *p, u32 option) : buffer(), path(nullptr), result(ResultSuccess()) {
if ((option & Option_AcceptEmpty) && p[0] == '\x00') {
this->path = path;
} else {
const bool preserve_unc = (option & Option_PreserveUnc);
const bool preserve_tail_sep = (option & Option_PreserveTailSeparator);
const bool has_mount_name = (option & Option_HasMountName);
this->result = Normalize(&this->path, &this->buffer, p, preserve_unc, preserve_tail_sep, has_mount_name);
}
}
inline Result GetResult() const {
return this->result;
}
inline const char * GetPath() const {
return this->path;
}
};
}

View file

@ -0,0 +1,50 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "../fs/fs_common.hpp"
#include "../fs/fs_directory.hpp"
#include "../sf/sf_buffer_tags.hpp"
namespace ams::fssrv::sf {
struct Path : ams::sf::LargeData {
char str[fs::EntryNameLengthMax + 1];
static constexpr Path Encode(const char *p) {
Path path = {};
for (size_t i = 0; i < sizeof(path) - 1; i++) {
path.str[i] = p[i];
if (p[i] == '\x00') {
break;
}
}
return path;
}
static constexpr size_t GetPathLength(const Path &path) {
size_t len = 0;
for (size_t i = 0; i < sizeof(path) - 1 && path.str[i] != '\x00'; i++) {
len++;
}
return len;
}
};
static_assert(std::is_pod<Path>::value && sizeof(Path) == FS_MAX_PATH);
using FspPath = Path;
}

View file

@ -0,0 +1,192 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "../../fs/fs_common.hpp"
#include "../../fs/fs_file.hpp"
#include "../../fs/fs_directory.hpp"
#include "../../fs/fs_filesystem.hpp"
#include "../../fs/fs_query_range.hpp"
#include "../../fssrv/fssrv_sf_path.hpp"
#include "../../fssystem/fssystem_utility.hpp"
namespace ams::fs::fsa {
class IFile;
class IDirectory;
class IFileSystem;
}
namespace ams::fssrv::impl {
class FileSystemInterfaceAdapter;
class FileInterfaceAdapter final : public ams::sf::IServiceObject {
NON_COPYABLE(FileInterfaceAdapter);
public:
enum class CommandId {
Read = 0,
Write = 1,
Flush = 2,
SetSize = 3,
GetSize = 4,
OperateRange = 5,
};
private:
std::shared_ptr<FileSystemInterfaceAdapter> parent_filesystem;
std::unique_ptr<fs::fsa::IFile> base_file;
std::unique_lock<fssystem::SemaphoreAdapter> open_count_semaphore;
public:
FileInterfaceAdapter(std::unique_ptr<fs::fsa::IFile> &&file, std::shared_ptr<FileSystemInterfaceAdapter> &&parent, std::unique_lock<fssystem::SemaphoreAdapter> &&sema);
~FileInterfaceAdapter();
private:
void InvalidateCache();
public:
/* Command API. */
Result Read(ams::sf::Out<s64> out, s64 offset, const ams::sf::OutNonSecureBuffer &buffer, s64 size, fs::ReadOption option);
Result Write(s64 offset, const ams::sf::InNonSecureBuffer &buffer, s64 size, fs::WriteOption option);
Result Flush();
Result SetSize(s64 size);
Result GetSize(ams::sf::Out<s64> out);
Result OperateRange(ams::sf::Out<fs::FileQueryRangeInfo> out, s32 op_id, s64 offset, s64 size);
public:
DEFINE_SERVICE_DISPATCH_TABLE {
/* 1.0.0- */
MAKE_SERVICE_COMMAND_META(Read),
MAKE_SERVICE_COMMAND_META(Write),
MAKE_SERVICE_COMMAND_META(Flush),
MAKE_SERVICE_COMMAND_META(SetSize),
MAKE_SERVICE_COMMAND_META(GetSize),
/* 4.0.0- */
MAKE_SERVICE_COMMAND_META(OperateRange, hos::Version_400),
};
};
class DirectoryInterfaceAdapter final : public ams::sf::IServiceObject {
NON_COPYABLE(DirectoryInterfaceAdapter);
public:
enum class CommandId {
Read = 0,
GetEntryCount = 1,
};
private:
std::shared_ptr<FileSystemInterfaceAdapter> parent_filesystem;
std::unique_ptr<fs::fsa::IDirectory> base_dir;
std::unique_lock<fssystem::SemaphoreAdapter> open_count_semaphore;
public:
DirectoryInterfaceAdapter(std::unique_ptr<fs::fsa::IDirectory> &&dir, std::shared_ptr<FileSystemInterfaceAdapter> &&parent, std::unique_lock<fssystem::SemaphoreAdapter> &&sema);
~DirectoryInterfaceAdapter();
public:
/* Command API */
Result Read(ams::sf::Out<s64> out, const ams::sf::OutBuffer &out_entries);
Result GetEntryCount(ams::sf::Out<s64> out);
public:
DEFINE_SERVICE_DISPATCH_TABLE {
MAKE_SERVICE_COMMAND_META(Read),
MAKE_SERVICE_COMMAND_META(GetEntryCount),
};
};
class FileSystemInterfaceAdapter final : public std::enable_shared_from_this<FileSystemInterfaceAdapter>, public ams::sf::IServiceObject {
NON_COPYABLE(FileSystemInterfaceAdapter);
public:
enum class CommandId {
/* 1.0.0+ */
CreateFile = 0,
DeleteFile = 1,
CreateDirectory = 2,
DeleteDirectory = 3,
DeleteDirectoryRecursively = 4,
RenameFile = 5,
RenameDirectory = 6,
GetEntryType = 7,
OpenFile = 8,
OpenDirectory = 9,
Commit = 10,
GetFreeSpaceSize = 11,
GetTotalSpaceSize = 12,
/* 3.0.0+ */
CleanDirectoryRecursively = 13,
GetFileTimeStampRaw = 14,
/* 4.0.0+ */
QueryEntry = 15,
};
private:
std::shared_ptr<fs::fsa::IFileSystem> base_fs;
std::unique_lock<fssystem::SemaphoreAdapter> mount_count_semaphore;
os::ReadWriteLock invalidation_lock;
bool open_count_limited;
bool deep_retry_enabled = false;
public:
FileSystemInterfaceAdapter(std::shared_ptr<fs::fsa::IFileSystem> &&fs, bool open_limited);
/* TODO: Other constructors. */
~FileSystemInterfaceAdapter();
public:
bool IsDeepRetryEnabled() const;
bool IsAccessFailureDetectionObserved() const;
std::optional<std::shared_lock<os::ReadWriteLock>> AcquireCacheInvalidationReadLock();
os::ReadWriteLock &GetReadWriteLockForCacheInvalidation();
public:
/* Command API. */
Result CreateFile(const fssrv::sf::Path &path, s64 size, s32 option);
Result DeleteFile(const fssrv::sf::Path &path);
Result CreateDirectory(const fssrv::sf::Path &path);
Result DeleteDirectory(const fssrv::sf::Path &path);
Result DeleteDirectoryRecursively(const fssrv::sf::Path &path);
Result RenameFile(const fssrv::sf::Path &old_path, const fssrv::sf::Path &new_path);
Result RenameDirectory(const fssrv::sf::Path &old_path, const fssrv::sf::Path &new_path);
Result GetEntryType(ams::sf::Out<u32> out, const fssrv::sf::Path &path);
Result OpenFile(ams::sf::Out<std::shared_ptr<FileInterfaceAdapter>> out, const fssrv::sf::Path &path, u32 mode);
Result OpenDirectory(ams::sf::Out<std::shared_ptr<DirectoryInterfaceAdapter>> out, const fssrv::sf::Path &path, u32 mode);
Result Commit();
Result GetFreeSpaceSize(ams::sf::Out<s64> out, const fssrv::sf::Path &path);
Result GetTotalSpaceSize(ams::sf::Out<s64> out, const fssrv::sf::Path &path);
Result CleanDirectoryRecursively(const fssrv::sf::Path &path);
Result GetFileTimeStampRaw(ams::sf::Out<fs::FileTimeStampRaw> out, const fssrv::sf::Path &path);
Result QueryEntry(const ams::sf::OutBuffer &out_buf, const ams::sf::InBuffer &in_buf, s32 query_id, const fssrv::sf::Path &path);
public:
DEFINE_SERVICE_DISPATCH_TABLE {
/* 1.0.0- */
MAKE_SERVICE_COMMAND_META(CreateFile),
MAKE_SERVICE_COMMAND_META(DeleteFile),
MAKE_SERVICE_COMMAND_META(CreateDirectory),
MAKE_SERVICE_COMMAND_META(DeleteDirectory),
MAKE_SERVICE_COMMAND_META(DeleteDirectoryRecursively),
MAKE_SERVICE_COMMAND_META(RenameFile),
MAKE_SERVICE_COMMAND_META(RenameDirectory),
MAKE_SERVICE_COMMAND_META(GetEntryType),
MAKE_SERVICE_COMMAND_META(OpenFile),
MAKE_SERVICE_COMMAND_META(OpenDirectory),
MAKE_SERVICE_COMMAND_META(Commit),
MAKE_SERVICE_COMMAND_META(GetFreeSpaceSize),
MAKE_SERVICE_COMMAND_META(GetTotalSpaceSize),
/* 3.0.0- */
MAKE_SERVICE_COMMAND_META(CleanDirectoryRecursively, hos::Version_300),
MAKE_SERVICE_COMMAND_META(GetFileTimeStampRaw, hos::Version_300),
/* 4.0.0- */
MAKE_SERVICE_COMMAND_META(QueryEntry, hos::Version_400),
};
};
}

View file

@ -0,0 +1,78 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "../../fs/fs_common.hpp"
#include "../../fs/fs_query_range.hpp"
#include "../../fssystem/fssystem_utility.hpp"
namespace ams::fs {
class IStorage;
}
namespace ams::fssrv::impl {
class StorageInterfaceAdapter final : public ams::sf::IServiceObject {
NON_COPYABLE(StorageInterfaceAdapter);
public:
enum class CommandId {
Read = 0,
Write = 1,
Flush = 2,
SetSize = 3,
GetSize = 4,
OperateRange = 5,
};
private:
/* TODO: Nintendo uses fssystem::AsynchronousAccessStorage here. */
std::shared_ptr<fs::IStorage> base_storage;
std::unique_lock<fssystem::SemaphoreAdapter> open_count_semaphore;
os::ReadWriteLock invalidation_lock;
/* TODO: DataStorageContext. */
bool deep_retry_enabled = false;
public:
StorageInterfaceAdapter(fs::IStorage *storage);
StorageInterfaceAdapter(std::unique_ptr<fs::IStorage> storage);
explicit StorageInterfaceAdapter(std::shared_ptr<fs::IStorage> &&storage);
/* TODO: Other constructors. */
~StorageInterfaceAdapter();
private:
std::optional<std::shared_lock<os::ReadWriteLock>> AcquireCacheInvalidationReadLock();
private:
/* Command API. */
Result Read(s64 offset, const ams::sf::OutNonSecureBuffer &buffer, s64 size);
Result Write(s64 offset, const ams::sf::InNonSecureBuffer &buffer, s64 size);
Result Flush();
Result SetSize(s64 size);
Result GetSize(ams::sf::Out<s64> out);
Result OperateRange(ams::sf::Out<fs::StorageQueryRangeInfo> out, s32 op_id, s64 offset, s64 size);
public:
DEFINE_SERVICE_DISPATCH_TABLE {
/* 1.0.0- */
MAKE_SERVICE_COMMAND_META(Read),
MAKE_SERVICE_COMMAND_META(Write),
MAKE_SERVICE_COMMAND_META(Flush),
MAKE_SERVICE_COMMAND_META(SetSize),
MAKE_SERVICE_COMMAND_META(GetSize),
/* 4.0.0- */
MAKE_SERVICE_COMMAND_META(OperateRange, hos::Version_400),
};
};
}

View file

@ -0,0 +1,22 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "fssystem/fssystem_utility.hpp"
#include "fssystem/fssystem_path_tool.hpp"
#include "fssystem/fssystem_subdirectory_filesystem.hpp"
#include "fssystem/fssystem_directory_redirection_filesystem.hpp"
#include "fssystem/fssystem_directory_savedata_filesystem.hpp"

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "impl/fssystem_path_resolution_filesystem.hpp"
namespace ams::fssystem {
class DirectoryRedirectionFileSystem : public impl::IPathResolutionFileSystem<DirectoryRedirectionFileSystem> {
NON_COPYABLE(DirectoryRedirectionFileSystem);
private:
using PathResolutionFileSystem = impl::IPathResolutionFileSystem<DirectoryRedirectionFileSystem>;
friend class impl::IPathResolutionFileSystem<DirectoryRedirectionFileSystem>;
private:
char *before_dir;
size_t before_dir_len;
char *after_dir;
size_t after_dir_len;
public:
DirectoryRedirectionFileSystem(std::shared_ptr<fs::fsa::IFileSystem> fs, const char *before, const char *after, bool unc = false);
DirectoryRedirectionFileSystem(std::unique_ptr<fs::fsa::IFileSystem> fs, const char *before, const char *after, bool unc = false);
virtual ~DirectoryRedirectionFileSystem();
protected:
inline std::optional<std::scoped_lock<os::Mutex>> GetAccessorLock() const {
/* No accessor lock is needed. */
return std::nullopt;
}
private:
Result GetNormalizedDirectoryPath(char **out, size_t *out_size, const char *dir);
Result Initialize(const char *before, const char *after);
Result ResolveFullPath(char *out, size_t out_size, const char *relative_path);
};
}

View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "impl/fssystem_path_resolution_filesystem.hpp"
namespace ams::fssystem {
class DirectorySaveDataFileSystem : public impl::IPathResolutionFileSystem<DirectorySaveDataFileSystem> {
NON_COPYABLE(DirectorySaveDataFileSystem);
private:
using PathResolutionFileSystem = impl::IPathResolutionFileSystem<DirectorySaveDataFileSystem>;
friend class impl::IPathResolutionFileSystem<DirectorySaveDataFileSystem>;
private:
os::Mutex accessor_mutex;
s32 open_writable_files;
public:
DirectorySaveDataFileSystem(std::shared_ptr<fs::fsa::IFileSystem> fs);
DirectorySaveDataFileSystem(std::unique_ptr<fs::fsa::IFileSystem> fs);
Result Initialize();
virtual ~DirectorySaveDataFileSystem();
protected:
inline std::optional<std::scoped_lock<os::Mutex>> GetAccessorLock() {
/* We have a real accessor lock that we want to use. */
return std::make_optional<std::scoped_lock<os::Mutex>>(this->accessor_mutex);
}
private:
Result AllocateWorkBuffer(std::unique_ptr<u8[]> *out, size_t *out_size, size_t ideal_size);
Result SynchronizeDirectory(const char *dst, const char *src);
Result ResolveFullPath(char *out, size_t out_size, const char *relative_path);
public:
void OnWritableFileClose();
Result CopySaveFromFileSystem(fs::fsa::IFileSystem *save_fs);
public:
/* Overridden from IPathResolutionFileSystem */
virtual Result OpenFileImpl(std::unique_ptr<fs::fsa::IFile> *out_file, const char *path, fs::OpenMode mode) override;
virtual Result CommitImpl() override;
/* Overridden from IPathResolutionFileSystem but not commands. */
virtual Result CommitProvisionallyImpl(s64 counter) override;
virtual Result RollbackImpl() override;
/* Explicitly overridden to be not implemented. */
virtual Result GetFreeSpaceSizeImpl(s64 *out, const char *path) override;
virtual Result GetTotalSpaceSizeImpl(s64 *out, const char *path) override;
virtual Result GetFileTimeStampRawImpl(fs::FileTimeStampRaw *out, const char *path) override;
virtual Result QueryEntryImpl(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const char *path) override;
virtual Result FlushImpl() override;
};
}

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "../fs/fs_common.hpp"
#include "../fs/fs_path_tool.hpp"
namespace ams::fssystem {
namespace StringTraits = ::ams::fs::StringTraits;
using PathTool = ::ams::fs::PathTool;
}

View file

@ -0,0 +1,44 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "impl/fssystem_path_resolution_filesystem.hpp"
namespace ams::fssystem {
class SubDirectoryFileSystem : public impl::IPathResolutionFileSystem<SubDirectoryFileSystem> {
NON_COPYABLE(SubDirectoryFileSystem);
private:
using PathResolutionFileSystem = impl::IPathResolutionFileSystem<SubDirectoryFileSystem>;
friend class impl::IPathResolutionFileSystem<SubDirectoryFileSystem>;
private:
char *base_path;
size_t base_path_len;
public:
SubDirectoryFileSystem(std::shared_ptr<fs::fsa::IFileSystem> fs, const char *bp, bool unc = false);
SubDirectoryFileSystem(std::unique_ptr<fs::fsa::IFileSystem> fs, const char *bp, bool unc = false);
virtual ~SubDirectoryFileSystem();
protected:
inline std::optional<std::scoped_lock<os::Mutex>> GetAccessorLock() const {
/* No accessor lock is needed. */
return std::nullopt;
}
private:
Result Initialize(const char *bp);
Result ResolveFullPath(char *out, size_t out_size, const char *relative_path);
};
}

View file

@ -0,0 +1,169 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "../fs/fs_common.hpp"
#include "../fs/fs_file.hpp"
#include "../fs/fs_directory.hpp"
#include "../fs/fs_filesystem.hpp"
#include "fssystem_path_tool.hpp"
namespace ams::fssystem {
namespace impl {
/* Iteration. */
template<typename OnEnterDir, typename OnExitDir, typename OnFile>
Result IterateDirectoryRecursivelyImpl(fs::fsa::IFileSystem *fs, char *work_path, size_t work_path_size, fs::DirectoryEntry *dir_ent, OnEnterDir on_enter_dir, OnExitDir on_exit_dir, OnFile on_file) {
/* Open the directory. */
std::unique_ptr<fs::fsa::IDirectory> dir;
R_TRY(fs->OpenDirectory(&dir, work_path, fs::OpenDirectoryMode_All));
const size_t parent_len = strnlen(work_path, work_path_size - 1);
/* Read and handle entries. */
while (true) {
/* Read a single entry. */
s64 read_count = 0;
R_TRY(dir->Read(&read_count, dir_ent, 1));
/* If we're out of entries, we're done. */
if (read_count == 0) {
break;
}
/* Validate child path size. */
const size_t child_name_len = strnlen(dir_ent->name, sizeof(dir_ent->name) - 1);
const bool is_dir = dir_ent->type == fs::DirectoryEntryType_Directory;
const size_t separator_size = is_dir ? 1 : 0;
R_UNLESS(parent_len + child_name_len + separator_size < work_path_size, fs::ResultTooLongPath());
/* Set child path. */
std::strncat(work_path, dir_ent->name, work_path_size - parent_len - 1);
{
if (is_dir) {
/* Enter directory. */
R_TRY(on_enter_dir(work_path, *dir_ent));
/* Append separator, recurse. */
std::strncat(work_path, "/", work_path_size - (parent_len + child_name_len) - 1);
R_TRY(IterateDirectoryRecursivelyImpl(fs, work_path, work_path_size, dir_ent, on_enter_dir, on_exit_dir, on_file));
/* Exit directory. */
R_TRY(on_exit_dir(work_path, *dir_ent));
} else {
/* Call file handler. */
R_TRY(on_file(work_path, *dir_ent));
}
}
/* Restore parent path. */
work_path[parent_len] = StringTraits::NullTerminator;
}
return ResultSuccess();
}
/* TODO: Cleanup. */
}
/* Iteration API */
template<typename OnEnterDir, typename OnExitDir, typename OnFile>
Result IterateDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *root_path, char *work_path, size_t work_path_size, fs::DirectoryEntry *dir_ent_buf, OnEnterDir on_enter_dir, OnExitDir on_exit_dir, OnFile on_file) {
AMS_ASSERT(work_path_size >= fs::EntryNameLengthMax + 1);
/* Get size of the root path. */
size_t root_path_len = strnlen(root_path, fs::EntryNameLengthMax + 1);
R_UNLESS(root_path_len <= fs::EntryNameLengthMax, fs::ResultTooLongPath());
/* Copy root path in, add a / if necessary. */
std::memcpy(work_path, root_path, root_path_len);
if (!PathTool::IsSeparator(work_path[root_path_len - 1])) {
work_path[root_path_len++] = StringTraits::DirectorySeparator;
}
/* Make sure the result path is still valid. */
R_UNLESS(root_path_len <= fs::EntryNameLengthMax, fs::ResultTooLongPath());
work_path[root_path_len] = StringTraits::NullTerminator;
return impl::IterateDirectoryRecursivelyImpl(fs, work_path, work_path_size, dir_ent_buf, on_enter_dir, on_exit_dir, on_file);
}
template<typename OnEnterDir, typename OnExitDir, typename OnFile>
Result IterateDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *root_path, OnEnterDir on_enter_dir, OnExitDir on_exit_dir, OnFile on_file) {
fs::DirectoryEntry dir_entry = {};
char work_path[fs::EntryNameLengthMax + 1] = {};
return IterateDirectoryRecursively(fs, root_path, work_path, sizeof(work_path), &dir_entry, on_enter_dir, on_exit_dir, on_file);
}
template<typename OnEnterDir, typename OnExitDir, typename OnFile>
Result IterateDirectoryRecursively(fs::fsa::IFileSystem *fs, OnEnterDir on_enter_dir, OnExitDir on_exit_dir, OnFile on_file) {
return IterateDirectoryRecursively(fs, PathTool::RootPath, on_enter_dir, on_exit_dir, on_file);
}
/* TODO: Cleanup API */
/* Copy API. */
Result CopyFile(fs::fsa::IFileSystem *dst_fs, fs::fsa::IFileSystem *src_fs, const char *dst_parent_path, const char *src_path, const fs::DirectoryEntry *dir_ent, void *work_buf, size_t work_buf_size);
NX_INLINE Result CopyFile(fs::fsa::IFileSystem *fs, const char *dst_parent_path, const char *src_path, const fs::DirectoryEntry *dir_ent, void *work_buf, size_t work_buf_size) {
return CopyFile(fs, fs, dst_parent_path, src_path, dir_ent, work_buf, work_buf_size);
}
Result CopyDirectoryRecursively(fs::fsa::IFileSystem *dst_fs, fs::fsa::IFileSystem *src_fs, const char *dst_path, const char *src_path, void *work_buf, size_t work_buf_size);
NX_INLINE Result CopyDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *dst_path, const char *src_path, void *work_buf, size_t work_buf_size) {
return CopyDirectoryRecursively(fs, fs, dst_path, src_path, work_buf, work_buf_size);
}
/* Semaphore adapter class. */
class SemaphoreAdapter : public os::Semaphore {
public:
SemaphoreAdapter(int c, int mc) : os::Semaphore(c, mc) { /* ... */ }
bool try_lock() {
return this->TryAcquire();
}
void unlock() {
this->Release();
}
};
/* Other utility. */
Result EnsureDirectoryExistsRecursively(fs::fsa::IFileSystem *fs, const char *path);
template<typename F>
NX_INLINE Result RetryFinitelyForTargetLocked(F f) {
/* Retry up to 10 times, 100ms between retries. */
constexpr s32 MaxRetryCount = 10;
constexpr u64 RetryWaitTime = 100'000'000ul;
s32 remaining_retries = MaxRetryCount;
while (true) {
R_TRY_CATCH(f()) {
R_CATCH(fs::ResultTargetLocked) {
R_UNLESS(remaining_retries > 0, fs::ResultTargetLocked());
remaining_retries--;
svcSleepThread(RetryWaitTime);
continue;
}
} R_END_TRY_CATCH;
return ResultSuccess();
}
}
}

View file

@ -0,0 +1,194 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "../../fs/fs_common.hpp"
#include "../../fs/fsa/fs_ifile.hpp"
#include "../../fs/fsa/fs_idirectory.hpp"
#include "../../fs/fsa/fs_ifilesystem.hpp"
namespace ams::fssystem::impl {
template<typename Impl>
class IPathResolutionFileSystem : public fs::fsa::IFileSystem {
NON_COPYABLE(IPathResolutionFileSystem);
private:
std::shared_ptr<fs::fsa::IFileSystem> shared_fs;
std::unique_ptr<fs::fsa::IFileSystem> unique_fs;
bool unc_preserved;
protected:
fs::fsa::IFileSystem * const base_fs;
public:
IPathResolutionFileSystem(std::shared_ptr<fs::fsa::IFileSystem> fs, bool unc = false) : shared_fs(std::move(fs)), unc_preserved(unc), base_fs(shared_fs.get()) {
/* ... */
}
IPathResolutionFileSystem(std::unique_ptr<fs::fsa::IFileSystem> fs, bool unc = false) : unique_fs(std::move(fs)), unc_preserved(unc), base_fs(unique_fs.get()) {
/* ... */
}
virtual ~IPathResolutionFileSystem() { /* ... */ }
protected:
constexpr inline bool IsUncPreserved() const {
return this->unc_preserved;
}
public:
virtual Result CreateFileImpl(const char *path, s64 size, int option) override {
char full_path[fs::EntryNameLengthMax + 1];
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->CreateFile(full_path, size, option);
}
virtual Result DeleteFileImpl(const char *path) override {
char full_path[fs::EntryNameLengthMax + 1];
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->DeleteFile(full_path);
}
virtual Result CreateDirectoryImpl(const char *path) override {
char full_path[fs::EntryNameLengthMax + 1];
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->CreateDirectory(full_path);
}
virtual Result DeleteDirectoryImpl(const char *path) override {
char full_path[fs::EntryNameLengthMax + 1];
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->DeleteDirectory(full_path);
}
virtual Result DeleteDirectoryRecursivelyImpl(const char *path) override {
char full_path[fs::EntryNameLengthMax + 1];
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->DeleteDirectoryRecursively(full_path);
}
virtual Result RenameFileImpl(const char *old_path, const char *new_path) override {
char old_full_path[fs::EntryNameLengthMax + 1];
char new_full_path[fs::EntryNameLengthMax + 1];
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(old_full_path, sizeof(old_full_path), old_path));
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(new_full_path, sizeof(new_full_path), new_path));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->RenameFile(old_full_path, new_full_path);
}
virtual Result RenameDirectoryImpl(const char *old_path, const char *new_path) override {
char old_full_path[fs::EntryNameLengthMax + 1];
char new_full_path[fs::EntryNameLengthMax + 1];
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(old_full_path, sizeof(old_full_path), old_path));
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(new_full_path, sizeof(new_full_path), new_path));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->RenameDirectory(old_full_path, new_full_path);
}
virtual Result GetEntryTypeImpl(fs::DirectoryEntryType *out, const char *path) override {
char full_path[fs::EntryNameLengthMax + 1];
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->GetEntryType(out, full_path);
}
virtual Result OpenFileImpl(std::unique_ptr<fs::fsa::IFile> *out_file, const char *path, fs::OpenMode mode) override {
char full_path[fs::EntryNameLengthMax + 1];
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->OpenFile(out_file, full_path, mode);
}
virtual Result OpenDirectoryImpl(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const char *path, fs::OpenDirectoryMode mode) override {
char full_path[fs::EntryNameLengthMax + 1];
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->OpenDirectory(out_dir, full_path, mode);
}
virtual Result CommitImpl() override {
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->Commit();
}
virtual Result GetFreeSpaceSizeImpl(s64 *out, const char *path) override {
char full_path[fs::EntryNameLengthMax + 1];
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->GetFreeSpaceSize(out, full_path);
}
virtual Result GetTotalSpaceSizeImpl(s64 *out, const char *path) override {
char full_path[fs::EntryNameLengthMax + 1];
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->GetTotalSpaceSize(out, full_path);
}
virtual Result CleanDirectoryRecursivelyImpl(const char *path) override {
char full_path[fs::EntryNameLengthMax + 1];
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->CleanDirectoryRecursively(full_path);
}
virtual Result GetFileTimeStampRawImpl(fs::FileTimeStampRaw *out, const char *path) override {
char full_path[fs::EntryNameLengthMax + 1];
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->GetFileTimeStampRaw(out, full_path);
}
virtual Result QueryEntryImpl(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const char *path) override {
char full_path[fs::EntryNameLengthMax + 1];
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->QueryEntry(dst, dst_size, src, src_size, query, full_path);
}
/* These aren't accessible as commands. */
virtual Result CommitProvisionallyImpl(s64 counter) override {
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->CommitProvisionally(counter);
}
virtual Result RollbackImpl() override {
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->Rollback();
}
virtual Result FlushImpl() override {
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->Flush();
}
};
}

View file

@ -0,0 +1,19 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "hid/hid_api.hpp"

View file

@ -0,0 +1,24 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
namespace ams::hid {
/* Key API. */
Result GetKeysHeld(u64 *out);
}

View file

@ -0,0 +1,20 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "hos/hos_types.hpp"
#include "hos/hos_version_api.hpp"

View file

@ -0,0 +1,39 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
namespace ams::hos {
enum Version : u16 {
Version_Min = 0,
Version_100 = Version_Min,
Version_200 = 1,
Version_300 = 2,
Version_400 = 3,
Version_500 = 4,
Version_600 = 5,
Version_700 = 6,
Version_800 = 7,
Version_810 = 8,
Version_900 = 9,
Version_910 = 10,
Version_Current = Version_910,
Version_Max = 32,
};
}

View file

@ -0,0 +1,25 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "hos_types.hpp"
namespace ams::hos {
::ams::hos::Version GetVersion();
void SetVersionForLibnx();
}

View file

@ -0,0 +1,24 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "kvdb/kvdb_auto_buffer.hpp"
#include "kvdb/kvdb_bounded_string.hpp"
#include "kvdb/kvdb_archive.hpp"
#include "kvdb/kvdb_memory_key_value_store.hpp"
#include "kvdb/kvdb_file_key_value_store.hpp"
#include "kvdb/kvdb_file_key_value_cache.hpp"

View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "kvdb_auto_buffer.hpp"
namespace ams::kvdb {
/* Functionality for parsing/generating a key value archive. */
class ArchiveReader {
private:
AutoBuffer &buffer;
size_t offset;
public:
ArchiveReader(AutoBuffer &b) : buffer(b), offset(0) { /* ... */ }
private:
Result Peek(void *dst, size_t size);
Result Read(void *dst, size_t size);
public:
Result ReadEntryCount(size_t *out);
Result GetEntrySize(size_t *out_key_size, size_t *out_value_size);
Result ReadEntry(void *out_key, size_t key_size, void *out_value, size_t value_size);
};
class ArchiveWriter {
private:
AutoBuffer &buffer;
size_t offset;
public:
ArchiveWriter(AutoBuffer &b) : buffer(b), offset(0) { /* ... */ }
private:
Result Write(const void *src, size_t size);
public:
void WriteHeader(size_t entry_count);
void WriteEntry(const void *key, size_t key_size, const void *value, size_t value_size);
};
class ArchiveSizeHelper {
private:
size_t size;
public:
ArchiveSizeHelper();
void AddEntry(size_t key_size, size_t value_size);
size_t GetSize() const {
return this->size;
}
};
}

View file

@ -0,0 +1,90 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
namespace ams::kvdb {
class AutoBuffer {
NON_COPYABLE(AutoBuffer);
private:
u8 *buffer;
size_t size;
public:
AutoBuffer() : buffer(nullptr), size(0) { /* ... */ }
~AutoBuffer() {
this->Reset();
}
AutoBuffer(AutoBuffer &&rhs) {
this->buffer = rhs.buffer;
this->size = rhs.size;
rhs.buffer = nullptr;
rhs.size = 0;
}
AutoBuffer& operator=(AutoBuffer &&rhs) {
rhs.Swap(*this);
return *this;
}
void Swap(AutoBuffer &rhs) {
std::swap(this->buffer, rhs.buffer);
std::swap(this->size, rhs.size);
}
void Reset() {
if (this->buffer != nullptr) {
std::free(this->buffer);
this->buffer = nullptr;
this->size = 0;
}
}
u8 *Get() const {
return this->buffer;
}
size_t GetSize() const {
return this->size;
}
Result Initialize(size_t size) {
/* Check that we're not already initialized. */
AMS_ASSERT(this->buffer == nullptr);
/* Allocate a buffer. */
this->buffer = static_cast<u8 *>(std::malloc(size));
if (this->buffer == nullptr) {
return ResultAllocationFailed();
}
this->size = size;
return ResultSuccess();
}
Result Initialize(const void *buf, size_t size) {
/* Create a new buffer of the right size. */
R_TRY(this->Initialize(size));
/* Copy the input data in. */
std::memcpy(this->buffer, buf, size);
return ResultSuccess();
}
};
}

View file

@ -0,0 +1,145 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
namespace ams::kvdb {
/* Represents a string with a backing buffer of N bytes. */
template<size_t N>
class BoundedString {
static_assert(N > 0, "BoundedString requires non-zero backing buffer!");
private:
char buffer[N];
private:
/* Utility. */
static inline void CheckLength(size_t len) {
AMS_ASSERT(len < N);
}
public:
/* Constructors. */
constexpr BoundedString() {
buffer[0] = 0;
}
explicit constexpr BoundedString(const char *s) {
this->Set(s);
}
/* Static constructors. */
static constexpr BoundedString<N> Make(const char *s) {
return BoundedString<N>(s);
}
static constexpr BoundedString<N> MakeFormat(const char *format, ...) __attribute__((format (printf, 1, 2))) {
BoundedString<N> string;
std::va_list args;
va_start(args, format);
CheckLength(std::vsnprintf(string.buffer, N, format, args));
va_end(args);
return string;
}
/* Getters. */
size_t GetLength() const {
return strnlen(this->buffer, N);
}
const char *Get() const {
return this->buffer;
}
operator const char *() const {
return this->buffer;
}
/* Setters. */
void Set(const char *s) {
/* Ensure string can fit in our buffer. */
CheckLength(strnlen(s, N));
std::strncpy(this->buffer, s, N);
}
void SetFormat(const char *format, ...) __attribute__((format (printf, 2, 3))) {
/* Format into the buffer, abort if too large. */
std::va_list args;
va_start(args, format);
CheckLength(std::vsnprintf(this->buffer, N, format, args));
va_end(args);
}
/* Append to existing. */
void Append(const char *s) {
const size_t length = GetLength();
CheckLength(length + strnlen(s, N));
std::strncat(this->buffer, s, N - length - 1);
}
void Append(char c) {
const size_t length = GetLength();
CheckLength(length + 1);
this->buffer[length] = c;
this->buffer[length + 1] = 0;
}
void AppendFormat(const char *format, ...) __attribute__((format (printf, 2, 3))) {
const size_t length = GetLength();
std::va_list args;
va_start(args, format);
CheckLength(std::vsnprintf(this->buffer + length, N - length, format, args) + length);
va_end(args);
}
/* Substring utilities. */
void GetSubstring(char *dst, size_t dst_size, size_t offset, size_t length) const {
/* Make sure output buffer can hold the substring. */
AMS_ASSERT(offset + length <= GetLength());
AMS_ASSERT(dst_size > length);
/* Copy substring to dst. */
std::strncpy(dst, this->buffer + offset, length);
dst[length] = 0;
}
BoundedString<N> GetSubstring(size_t offset, size_t length) const {
BoundedString<N> string;
GetSubstring(string.buffer, N, offset, length);
return string;
}
/* Comparison. */
constexpr bool operator==(const BoundedString<N> &rhs) const {
return std::strncmp(this->buffer, rhs.buffer, N) == 0;
}
constexpr bool operator!=(const BoundedString<N> &rhs) const {
return !(*this == rhs);
}
bool EndsWith(const char *s, size_t offset) const {
return std::strncmp(this->buffer + offset, s, N - offset) == 0;
}
bool EndsWith(const char *s) const {
const size_t suffix_length = strnlen(s, N);
const size_t length = GetLength();
return suffix_length <= length && EndsWith(s, length - suffix_length);
}
};
}

View file

@ -0,0 +1,391 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <sys/stat.h>
#include "kvdb_bounded_string.hpp"
#include "kvdb_file_key_value_store.hpp"
namespace ams::kvdb {
namespace impl {
template<class Key, size_t Capacity>
class LruList {
private:
/* Subtypes. */
struct LruHeader {
u32 entry_count;
};
public:
static constexpr size_t BufferSize = sizeof(Key) * Capacity;
static constexpr size_t FileSize = sizeof(LruHeader) + BufferSize;
using Path = FileKeyValueStore::Path;
private:
Path file_path;
Key *keys;
LruHeader header;
public:
static Result CreateNewList(const char *path) {
/* Create new lru_list.dat. */
R_TRY(fsdevCreateFile(path, FileSize, 0));
/* Open the file. */
FILE *fp = fopen(path, "r+b");
R_UNLESS(fp != nullptr, fsdevGetLastResult());
ON_SCOPE_EXIT { fclose(fp); };
/* Write new header with zero entries to the file. */
LruHeader new_header = { .entry_count = 0, };
R_UNLESS(fwrite(&new_header, sizeof(new_header), 1, fp) == 1, fsdevGetLastResult());
return ResultSuccess();
}
private:
void RemoveIndex(size_t i) {
AMS_ASSERT(i < this->GetCount());
std::memmove(this->keys + i, this->keys + i + 1, sizeof(*this->keys) * (this->GetCount() - (i + 1)));
this->DecrementCount();
}
void IncrementCount() {
this->header.entry_count++;
}
void DecrementCount() {
this->header.entry_count--;
}
public:
LruList() : keys(nullptr), header({}) { /* ... */ }
Result Initialize(const char *path, void *buf, size_t size) {
/* Only initialize once, and ensure we have sufficient memory. */
AMS_ASSERT(this->keys == nullptr);
AMS_ASSERT(size >= BufferSize);
/* Setup member variables. */
this->keys = static_cast<Key *>(buf);
this->file_path.Set(path);
std::memset(this->keys, 0, BufferSize);
/* Open file. */
FILE *fp = fopen(this->file_path, "rb");
R_UNLESS(fp != nullptr, fsdevGetLastResult());
ON_SCOPE_EXIT { fclose(fp); };
/* Read header. */
R_UNLESS(fread(&this->header, sizeof(this->header), 1, fp) == 1, fsdevGetLastResult());
/* Read entries. */
const size_t count = this->GetCount();
if (count > 0) {
R_UNLESS(fread(this->keys, std::min(BufferSize, sizeof(Key) * count), 1, fp) == 1, fsdevGetLastResult());
}
return ResultSuccess();
}
Result Save() {
/* Open file. */
FILE *fp = fopen(this->file_path, "r+b");
R_UNLESS(fp != nullptr, fsdevGetLastResult());
ON_SCOPE_EXIT { fclose(fp); };
/* Write header. */
R_UNLESS(fwrite(&this->header, sizeof(this->header), 1, fp) == 1, fsdevGetLastResult());
/* Write entries. */
R_UNLESS(fwrite(this->keys, BufferSize, 1, fp) == 1, fsdevGetLastResult());
/* Flush. */
fflush(fp);
return ResultSuccess();
}
size_t GetCount() const {
return this->header.entry_count;
}
bool IsEmpty() const {
return this->GetCount() == 0;
}
bool IsFull() const {
return this->GetCount() >= Capacity;
}
Key Get(size_t i) const {
AMS_ASSERT(i < this->GetCount());
return this->keys[i];
}
Key Peek() const {
AMS_ASSERT(!this->IsEmpty());
return this->Get(0);
}
void Push(const Key &key) {
AMS_ASSERT(!this->IsFull());
this->keys[this->GetCount()] = key;
this->IncrementCount();
}
Key Pop() {
AMS_ASSERT(!this->IsEmpty());
this->RemoveIndex(0);
}
bool Remove(const Key &key) {
const size_t count = this->GetCount();
/* Iterate over the list, removing the last entry that matches the key. */
for (size_t i = 0; i < count; i++) {
if (this->keys[count - 1 - i] == key) {
this->RemoveIndex(count - 1 - i);
return true;
}
}
return false;
}
bool Contains(const Key &key) const {
const size_t count = this->GetCount();
/* Iterate over the list, checking to see if we have the key. */
for (size_t i = 0; i < count; i++) {
if (this->keys[count - 1 - i] == key) {
return true;
}
}
return false;
}
bool Update(const Key &key) {
if (this->Remove(key)) {
this->Push(key);
return true;
}
return false;
}
};
}
template<class Key, size_t Capacity>
class FileKeyValueCache {
static_assert(std::is_pod<Key>::value, "FileKeyValueCache Key must be pod!");
static_assert(sizeof(Key) <= FileKeyValueStore::MaxKeySize, "FileKeyValueCache Key is too big!");
public:
using LeastRecentlyUsedList = impl::LruList<Key, Capacity>;
/* Note: Nintendo code in NS uses Path = BoundedString<0x180> here. */
/* It's unclear why, since they use 0x300 everywhere else. */
/* We'll just use 0x300, since it shouldn't make a difference, */
/* as FileKeyValueStore paths are limited to 0x100 anyway. */
using Path = typename LeastRecentlyUsedList::Path;
private:
FileKeyValueStore kvs;
LeastRecentlyUsedList lru_list;
private:
static constexpr Path GetLeastRecentlyUsedListPath(const char *dir) {
return Path::MakeFormat("%s/%s", dir, "lru_list.dat");
}
static constexpr Path GetFileKeyValueStorePath(const char *dir) {
return Path::MakeFormat("%s/%s", dir, "kvs");
}
static Result Exists(bool *out, const char *path, bool is_dir) {
/* Set out to false initially. */
*out = false;
/* Check that the path exists, and that our entry type is correct. */
{
struct stat st;
if (stat(path, &st) != 0) {
R_TRY_CATCH(fsdevGetLastResult()) {
/* If the path doesn't exist, nothing has gone wrong. */
R_CONVERT(fs::ResultPathNotFound, ResultSuccess());
} R_END_TRY_CATCH;
}
if (is_dir) {
R_UNLESS((S_ISDIR(st.st_mode)), ResultInvalidFilesystemState());
} else {
R_UNLESS((S_ISREG(st.st_mode)), ResultInvalidFilesystemState());
}
}
*out = true;
return ResultSuccess();
}
static Result DirectoryExists(bool *out, const char *path) {
return Exists(out, path, true);
}
static Result FileExists(bool *out, const char *path) {
return Exists(out, path, false);
}
public:
static Result CreateNewCache(const char *dir) {
/* Make a new key value store filesystem, and a new lru_list.dat. */
R_TRY(LeastRecentlyUsedList::CreateNewList(GetLeastRecentlyUsedListPath(dir)));
R_UNLESS(mkdir(GetFileKeyValueStorePath(dir), 0) == 0, fsdevGetLastResult());
return ResultSuccess();
}
static Result ValidateExistingCache(const char *dir) {
/* Check for existence. */
bool has_lru = false, has_kvs = false;
R_TRY(FileExists(&has_lru, GetLeastRecentlyUsedListPath(dir)));
R_TRY(DirectoryExists(&has_kvs, GetFileKeyValueStorePath(dir)));
/* If neither exists, CreateNewCache was never called. */
R_UNLESS(has_lru || has_kvs, ResultNotCreated());
/* If one exists but not the other, we have an invalid state. */
R_UNLESS(has_lru && has_kvs, ResultInvalidFilesystemState());
return ResultSuccess();
}
private:
void RemoveOldestKey() {
const Key &oldest_key = this->lru_list.Peek();
this->lru_list.Pop();
this->kvs.Remove(oldest_key);
}
public:
Result Initialize(const char *dir, void *buf, size_t size) {
/* Initialize list. */
R_TRY(this->lru_list.Initialize(GetLeastRecentlyUsedListPath(dir), buf, size));
/* Initialize kvs. */
/* NOTE: Despite creating the kvs folder and returning an error if it does not exist, */
/* Nintendo does not use the kvs folder, and instead uses the passed dir. */
/* This causes lru_list.dat to be in the same directory as the store's .val files */
/* instead of in the same directory as a folder containing the store's .val files. */
/* This is probably a Nintendo bug, but because system saves contain data in the wrong */
/* layout it can't really be fixed without breaking existing devices... */
R_TRY(this->kvs.Initialize(dir));
return ResultSuccess();
}
size_t GetCount() const {
return this->lru_list.GetCount();
}
size_t GetCapacity() const {
return Capacity;
}
Key GetKey(size_t i) const {
return this->lru_list.Get(i);
}
bool Contains(const Key &key) const {
return this->lru_list.Contains(key);
}
Result Get(size_t *out_size, void *out_value, size_t max_out_size, const Key &key) {
/* Note that we accessed the key. */
this->lru_list.Update(key);
return this->kvs.Get(out_size, out_value, max_out_size, key);
}
template<typename Value>
Result Get(Value *out_value, const Key &key) {
/* Note that we accessed the key. */
this->lru_list.Update(key);
return this->kvs.Get(out_value, key);
}
Result GetSize(size_t *out_size, const Key &key) {
return this->kvs.GetSize(out_size, key);
}
Result Set(const Key &key, const void *value, size_t value_size) {
if (this->lru_list.Update(key)) {
/* If an entry for the key exists, delete the existing value file. */
this->kvs.Remove(key);
} else {
/* If the list is full, we need to remove the oldest key. */
if (this->lru_list.IsFull()) {
this->RemoveOldestKey();
}
/* Add the key to the list. */
this->lru_list.Push(key);
}
/* Loop, trying to save the new value to disk. */
while (true) {
/* Try to set the key. */
R_TRY_CATCH(this->kvs.Set(key, value, value_size)) {
R_CATCH(fs::ResultNotEnoughFreeSpace) {
/* If our entry is the only thing in the Lru list, remove it. */
if (this->lru_list.GetCount() == 1) {
this->lru_list.Pop();
R_TRY(this->lru_list.Save());
return fs::ResultNotEnoughFreeSpace();
}
/* Otherwise, remove the oldest element from the cache and try again. */
this->RemoveOldestKey();
continue;
}
} R_END_TRY_CATCH;
/* If we got here, we succeeded. */
break;
}
/* Save the list. */
R_TRY(this->lru_list.Save());
return ResultSuccess();
}
template<typename Value>
Result Set(const Key &key, const Value &value) {
return this->Set(key, &value, sizeof(Value));
}
Result Remove(const Key &key) {
/* Remove the key. */
this->lru_list.Remove(key);
R_TRY(this->kvs.Remove(key));
R_TRY(this->lru_list.Save());
return ResultSuccess();
}
Result RemoveAll() {
/* TODO: Nintendo doesn't check errors here. Should we? */
while (!this->lru_list.IsEmpty()) {
this->RemoveOldestKey();
}
R_TRY(this->lru_list.Save());
return ResultSuccess();
}
};
}

View file

@ -0,0 +1,122 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "../os.hpp"
#include "kvdb_bounded_string.hpp"
namespace ams::kvdb {
class FileKeyValueStore {
NON_COPYABLE(FileKeyValueStore);
NON_MOVEABLE(FileKeyValueStore);
public:
static constexpr size_t MaxPathLength = 0x300; /* TODO: FS_MAX_PATH - 1? */
static constexpr size_t MaxFileLength = 0xFF;
static constexpr char FileExtension[5] = ".val";
static constexpr size_t FileExtensionLength = sizeof(FileExtension) - 1;
static constexpr size_t MaxKeySize = (MaxFileLength - FileExtensionLength) / 2;
using Path = kvdb::BoundedString<MaxPathLength>;
using FileName = kvdb::BoundedString<MaxFileLength>;
private:
/* Subtypes. */
struct Entry {
u8 key[MaxKeySize];
void *value;
size_t key_size;
size_t value_size;
};
static_assert(std::is_pod<Entry>::value, "FileKeyValueStore::Entry definition!");
class Cache {
private:
u8 *backing_buffer = nullptr;
size_t backing_buffer_size = 0;
size_t backing_buffer_free_offset = 0;
Entry *entries = nullptr;
size_t count = 0;
size_t capacity = 0;
private:
void *Allocate(size_t size);
bool HasEntries() const {
return this->entries != nullptr && this->capacity != 0;
}
public:
Result Initialize(void *buffer, size_t buffer_size, size_t capacity);
void Invalidate();
std::optional<size_t> TryGet(void *out_value, size_t max_out_size, const void *key, size_t key_size);
std::optional<size_t> TryGetSize(const void *key, size_t key_size);
void Set(const void *key, size_t key_size, const void *value, size_t value_size);
bool Contains(const void *key, size_t key_size);
};
private:
os::Mutex lock;
Path dir_path;
Cache cache;
private:
Path GetPath(const void *key, size_t key_size);
Result GetKey(size_t *out_size, void *out_key, size_t max_out_size, const FileName &file_name);
public:
FileKeyValueStore() { /* ... */ }
/* Basic accessors. */
Result Initialize(const char *dir);
Result InitializeWithCache(const char *dir, void *cache_buffer, size_t cache_buffer_size, size_t cache_capacity);
Result Get(size_t *out_size, void *out_value, size_t max_out_size, const void *key, size_t key_size);
Result GetSize(size_t *out_size, const void *key, size_t key_size);
Result Set(const void *key, size_t key_size, const void *value, size_t value_size);
Result Remove(const void *key, size_t key_size);
/* Niceties. */
template<typename Key>
Result Get(size_t *out_size, void *out_value, size_t max_out_size, const Key &key) {
static_assert(std::is_pod<Key>::value && sizeof(Key) <= MaxKeySize, "Invalid FileKeyValueStore Key!");
return this->Get(out_size, out_value, max_out_size, &key, sizeof(Key));
}
template<typename Key, typename Value>
Result Get(Value *out_value, const Key &key) {
static_assert(std::is_pod<Value>::value && !std::is_pointer<Value>::value, "Invalid FileKeyValueStore Value!");
size_t size = 0;
R_TRY(this->Get(&size, out_value, sizeof(Value), key));
AMS_ASSERT(size >= sizeof(Value));
return ResultSuccess();
}
template<typename Key>
Result GetSize(size_t *out_size, const Key &key) {
return this->GetSize(out_size, &key, sizeof(Key));
}
template<typename Key>
Result Set(const Key &key, const void *value, size_t value_size) {
static_assert(std::is_pod<Key>::value && sizeof(Key) <= MaxKeySize, "Invalid FileKeyValueStore Key!");
return this->Set(&key, sizeof(Key), value, value_size);
}
template<typename Key, typename Value>
Result Set(const Key &key, const Value &value) {
static_assert(std::is_pod<Value>::value && !std::is_pointer<Value>::value, "Invalid FileKeyValueStore Value!");
return this->Set(key, &value, sizeof(Value));
}
template<typename Key>
Result Remove(const Key &key) {
return this->Remove(&key, sizeof(Key));
}
};
}

View file

@ -0,0 +1,525 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <sys/stat.h>
#include "kvdb_auto_buffer.hpp"
#include "kvdb_archive.hpp"
#include "kvdb_bounded_string.hpp"
namespace ams::kvdb {
template<class Key>
class MemoryKeyValueStore {
static_assert(std::is_pod<Key>::value, "KeyValueStore Keys must be pod!");
NON_COPYABLE(MemoryKeyValueStore);
NON_MOVEABLE(MemoryKeyValueStore);
public:
/* Subtypes. */
class Entry {
private:
Key key;
void *value;
size_t value_size;
public:
constexpr Entry(const Key &k, void *v, size_t s) : key(k), value(v), value_size(s) { /* ... */ }
const Key &GetKey() const {
return this->key;
}
template<typename Value = void>
Value *GetValuePointer() {
/* Size check. Note: Nintendo does not size check. */
if constexpr (!std::is_same<Value, void>::value) {
AMS_ASSERT(sizeof(Value) <= this->value_size);
/* Ensure we only get pod. */
static_assert(std::is_pod<Value>::value, "KeyValueStore Values must be pod");
}
return reinterpret_cast<Value *>(this->value);
}
template<typename Value = void>
const Value *GetValuePointer() const {
/* Size check. Note: Nintendo does not size check. */
if constexpr (!std::is_same<Value, void>::value) {
AMS_ASSERT(sizeof(Value) <= this->value_size);
/* Ensure we only get pod. */
static_assert(std::is_pod<Value>::value, "KeyValueStore Values must be pod");
}
return reinterpret_cast<Value *>(this->value);
}
template<typename Value>
Value &GetValue() {
return *(this->GetValuePointer<Value>());
}
template<typename Value>
const Value &GetValue() const {
return *(this->GetValuePointer<Value>());
}
size_t GetValueSize() const {
return this->value_size;
}
constexpr inline bool operator<(const Key &rhs) const {
return key < rhs;
}
constexpr inline bool operator==(const Key &rhs) const {
return key == rhs;
}
};
class Index {
private:
size_t count;
size_t capacity;
Entry *entries;
public:
Index() : count(0), capacity(0), entries(nullptr) { /* ... */ }
~Index() {
if (this->entries != nullptr) {
this->ResetEntries();
std::free(this->entries);
this->entries = nullptr;
}
}
size_t GetCount() const {
return this->count;
}
size_t GetCapacity() const {
return this->capacity;
}
void ResetEntries() {
for (size_t i = 0; i < this->count; i++) {
std::free(this->entries[i].GetValuePointer());
}
this->count = 0;
}
Result Initialize(size_t capacity) {
this->entries = reinterpret_cast<Entry *>(std::malloc(sizeof(Entry) * capacity));
R_UNLESS(this->entries != nullptr, ResultAllocationFailed());
this->capacity = capacity;
return ResultSuccess();
}
Result Set(const Key &key, const void *value, size_t value_size) {
/* Allocate new value. */
void *new_value = std::malloc(value_size);
R_UNLESS(new_value != nullptr, ResultAllocationFailed());
auto value_guard = SCOPE_GUARD { std::free(new_value); };
std::memcpy(new_value, value, value_size);
/* Find entry for key. */
Entry *it = this->lower_bound(key);
if (it != this->end() && it->GetKey() == key) {
/* Entry already exists. Free old value. */
std::free(it->GetValuePointer());
} else {
/* We need to add a new entry. Check we have room, move future keys forward. */
R_UNLESS(this->count < this->capacity, ResultOutOfKeyResource());
std::memmove(it + 1, it, sizeof(*it) * (this->end() - it));
this->count++;
}
/* Save the new Entry in the map. */
value_guard.Cancel();
*it = Entry(key, new_value, value_size);
return ResultSuccess();
}
Result AddUnsafe(const Key &key, void *value, size_t value_size) {
R_UNLESS(this->count < this->capacity, ResultOutOfKeyResource());
this->entries[this->count++] = Entry(key, value, value_size);
return ResultSuccess();
}
Result Remove(const Key &key) {
/* Find entry for key. */
Entry *it = this->find(key);
R_UNLESS(it != this->end(), ResultKeyNotFound());
/* Free the value, move entries back. */
std::free(it->GetValuePointer());
std::memmove(it, it + 1, sizeof(*it) * (this->end() - (it + 1)));
this->count--;
return ResultSuccess();
}
Entry *begin() {
return this->GetBegin();
}
const Entry *begin() const {
return this->GetBegin();
}
Entry *end() {
return this->GetEnd();
}
const Entry *end() const {
return this->GetEnd();
}
const Entry *cbegin() const {
return this->begin();
}
const Entry *cend() const {
return this->end();
}
Entry *lower_bound(const Key &key) {
return this->GetLowerBound(key);
}
const Entry *lower_bound(const Key &key) const {
return this->GetLowerBound(key);
}
Entry *find(const Key &key) {
return this->Find(key);
}
const Entry *find(const Key &key) const {
return this->Find(key);
}
private:
Entry *GetBegin() {
return this->entries;
}
const Entry *GetBegin() const {
return this->entries;
}
Entry *GetEnd() {
return this->GetBegin() + this->count;
}
const Entry *GetEnd() const {
return this->GetBegin() + this->count;
}
Entry *GetLowerBound(const Key &key) {
return std::lower_bound(this->GetBegin(), this->GetEnd(), key);
}
const Entry *GetLowerBound(const Key &key) const {
return std::lower_bound(this->GetBegin(), this->GetEnd(), key);
}
Entry *Find(const Key &key) {
auto it = this->GetLowerBound(key);
auto end = this->GetEnd();
if (it != end && it->GetKey() == key) {
return it;
}
return end;
}
const Entry *Find(const Key &key) const {
auto it = this->GetLowerBound(key);
auto end = this->GetEnd();
if (it != end && it->GetKey() == key) {
return it;
}
return end;
}
};
private:
static constexpr size_t MaxPathLen = 0x300; /* TODO: FS_MAX_PATH - 1? */
using Path = kvdb::BoundedString<MaxPathLen>;
private:
Index index;
Path path;
Path temp_path;
public:
MemoryKeyValueStore() { /* ... */ }
Result Initialize(const char *dir, size_t capacity) {
/* Ensure that the passed path is a directory. */
{
struct stat st;
R_UNLESS(stat(dir, &st) == 0, fs::ResultPathNotFound());
R_UNLESS((S_ISDIR(st.st_mode)), fs::ResultPathNotFound());
}
/* Set paths. */
this->path.SetFormat("%s%s", dir, "/imkvdb.arc");
this->temp_path.SetFormat("%s%s", dir, "/imkvdb.tmp");
/* Initialize our index. */
R_TRY(this->index.Initialize(capacity));
return ResultSuccess();
}
Result Initialize(size_t capacity) {
/* This initializes without an archive file. */
/* A store initialized this way cannot have its contents loaded from or flushed to disk. */
this->path.Set("");
this->temp_path.Set("");
/* Initialize our index. */
R_TRY(this->index.Initialize(capacity));
return ResultSuccess();
}
size_t GetCount() const {
return this->index.GetCount();
}
size_t GetCapacity() const {
return this->index.GetCapacity();
}
Result Load() {
/* Reset any existing entries. */
this->index.ResetEntries();
/* Try to read the archive -- note, path not found is a success condition. */
/* This is because no archive file = no entries, so we're in the right state. */
AutoBuffer buffer;
R_TRY_CATCH(this->ReadArchiveFile(&buffer)) {
R_CONVERT(fs::ResultPathNotFound, ResultSuccess());
} R_END_TRY_CATCH;
/* Parse entries from the buffer. */
{
ArchiveReader reader(buffer);
size_t entry_count = 0;
R_TRY(reader.ReadEntryCount(&entry_count));
for (size_t i = 0; i < entry_count; i++) {
/* Get size of key/value. */
size_t key_size = 0, value_size = 0;
R_TRY(reader.GetEntrySize(&key_size, &value_size));
/* Allocate memory for value. */
void *new_value = std::malloc(value_size);
R_UNLESS(new_value != nullptr, ResultAllocationFailed());
auto value_guard = SCOPE_GUARD { std::free(new_value); };
/* Read key and value. */
Key key;
R_TRY(reader.ReadEntry(&key, sizeof(key), new_value, value_size));
R_TRY(this->index.AddUnsafe(key, new_value, value_size));
/* We succeeded, so cancel the value guard to prevent deallocation. */
value_guard.Cancel();
}
}
return ResultSuccess();
}
Result Save() {
/* Create a buffer to hold the archive. */
AutoBuffer buffer;
R_TRY(buffer.Initialize(this->GetArchiveSize()));
/* Write the archive to the buffer. */
{
ArchiveWriter writer(buffer);
writer.WriteHeader(this->GetCount());
for (const auto &it : this->index) {
const auto &key = it.GetKey();
writer.WriteEntry(&key, sizeof(Key), it.GetValuePointer(), it.GetValueSize());
}
}
/* Save the buffer to disk. */
return this->Commit(buffer);
}
Result Set(const Key &key, const void *value, size_t value_size) {
return this->index.Set(key, value, value_size);
}
template<typename Value>
Result Set(const Key &key, const Value &value) {
/* Only allow setting pod. */
static_assert(std::is_pod<Value>::value, "KeyValueStore Values must be pod");
return this->Set(key, &value, sizeof(Value));
}
template<typename Value>
Result Set(const Key &key, const Value *value) {
/* Only allow setting pod. */
static_assert(std::is_pod<Value>::value, "KeyValueStore Values must be pod");
return this->Set(key, value, sizeof(Value));
}
Result Get(size_t *out_size, void *out_value, size_t max_out_size, const Key &key) {
/* Find entry. */
auto it = this->find(key);
R_UNLESS(it != this->end(), ResultKeyNotFound());
size_t size = std::min(max_out_size, it->GetValueSize());
std::memcpy(out_value, it->GetValuePointer(), size);
*out_size = size;
return ResultSuccess();
}
template<typename Value = void>
Result GetValuePointer(Value **out_value, const Key &key) {
/* Find entry. */
auto it = this->find(key);
R_UNLESS(it != this->end(), ResultKeyNotFound());
*out_value = it->template GetValuePointer<Value>();
return ResultSuccess();
}
template<typename Value = void>
Result GetValuePointer(const Value **out_value, const Key &key) const {
/* Find entry. */
auto it = this->find(key);
R_UNLESS(it != this->end(), ResultKeyNotFound());
*out_value = it->template GetValuePointer<Value>();
return ResultSuccess();
}
template<typename Value>
Result GetValue(Value *out_value, const Key &key) const {
/* Find entry. */
auto it = this->find(key);
R_UNLESS(it != this->end(), ResultKeyNotFound());
*out_value = it->template GetValue<Value>();
return ResultSuccess();
}
Result GetValueSize(size_t *out_size, const Key &key) const {
/* Find entry. */
auto it = this->find(key);
R_UNLESS(it != this->end(), ResultKeyNotFound());
*out_size = it->GetValueSize();
return ResultSuccess();
}
Result Remove(const Key &key) {
return this->index.Remove(key);
}
Entry *begin() {
return this->index.begin();
}
const Entry *begin() const {
return this->index.begin();
}
Entry *end() {
return this->index.end();
}
const Entry *end() const {
return this->index.end();
}
const Entry *cbegin() const {
return this->index.cbegin();
}
const Entry *cend() const {
return this->index.cend();
}
Entry *lower_bound(const Key &key) {
return this->index.lower_bound(key);
}
const Entry *lower_bound(const Key &key) const {
return this->index.lower_bound(key);
}
Entry *find(const Key &key) {
return this->index.find(key);
}
const Entry *find(const Key &key) const {
return this->index.find(key);
}
private:
Result Commit(const AutoBuffer &buffer) {
/* Try to delete temporary archive, but allow deletion failure (it may not exist). */
std::remove(this->temp_path.Get());
/* Create new temporary archive. */
R_TRY(fsdevCreateFile(this->temp_path.Get(), buffer.GetSize(), 0));
/* Write data to the temporary archive. */
{
FILE *f = fopen(this->temp_path, "r+b");
R_UNLESS(f != nullptr, fsdevGetLastResult());
ON_SCOPE_EXIT { fclose(f); };
R_UNLESS(fwrite(buffer.Get(), buffer.GetSize(), 1, f) == 1, fsdevGetLastResult());
}
/* Try to delete the saved archive, but allow deletion failure. */
std::remove(this->path.Get());
/* Rename the path. */
R_UNLESS(std::rename(this->temp_path.Get(), this->path.Get()) == 0, fsdevGetLastResult());
return ResultSuccess();
}
size_t GetArchiveSize() const {
ArchiveSizeHelper size_helper;
for (const auto &it : this->index) {
size_helper.AddEntry(sizeof(Key), it.GetValueSize());
}
return size_helper.GetSize();
}
Result ReadArchiveFile(AutoBuffer *dst) const {
/* Open the file. */
FILE *f = fopen(this->path, "rb");
R_UNLESS(f != nullptr, fsdevGetLastResult());
ON_SCOPE_EXIT { fclose(f); };
/* Get the archive file size. */
fseek(f, 0, SEEK_END);
const size_t archive_size = ftell(f);
fseek(f, 0, SEEK_SET);
/* Make a new buffer, read the file. */
R_TRY(dst->Initialize(archive_size));
R_UNLESS(fread(dst->Get(), archive_size, 1, f) == 1, fsdevGetLastResult());
return ResultSuccess();
}
};
}

View file

@ -0,0 +1,20 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "ldr/ldr_types.hpp"
#include "ldr/ldr_pm_api.hpp"

View file

@ -0,0 +1,33 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "ldr_types.hpp"
namespace ams::ldr::pm {
/* Process Manager API. */
Result CreateProcess(Handle *out, PinId pin_id, u32 flags, Handle reslimit);
Result GetProgramInfo(ProgramInfo *out, const ncm::ProgramLocation &loc);
Result PinProgram(PinId *out, const ncm::ProgramLocation &loc);
Result UnpinProgram(PinId pin_id);
Result HasLaunchedProgram(bool *out, ncm::ProgramId program_id);
/* Atmosphere extension API. */
Result AtmosphereGetProgramInfo(ProgramInfo *out, cfg::OverrideStatus *out_status, const ncm::ProgramLocation &loc);
Result AtmospherePinProgram(PinId *out, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status);
}

View file

@ -0,0 +1,242 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include "../ncm/ncm_types.hpp"
#include "../sf/sf_buffer_tags.hpp"
namespace ams::ldr {
/* General types. */
struct ProgramInfo : sf::LargeData {
u8 main_thread_priority;
u8 default_cpu_id;
u16 flags;
u32 main_thread_stack_size;
ncm::ProgramId program_id;
u32 acid_sac_size;
u32 aci_sac_size;
u32 acid_fac_size;
u32 aci_fah_size;
u8 ac_buffer[0x3E0];
};
static_assert(std::is_pod<ProgramInfo>::value && sizeof(ProgramInfo) == 0x400, "ProgramInfo definition!");
enum ProgramInfoFlag {
ProgramInfoFlag_SystemModule = (0 << 0),
ProgramInfoFlag_Application = (1 << 0),
ProgramInfoFlag_Applet = (2 << 0),
ProgramInfoFlag_InvalidType = (3 << 0),
ProgramInfoFlag_ApplicationTypeMask = (3 << 0),
ProgramInfoFlag_AllowDebug = (1 << 2),
};
enum CreateProcessFlag {
CreateProcessFlag_EnableDebug = (1 << 0),
CreateProcessFlag_DisableAslr = (1 << 1),
};
struct ProgramArguments {
u32 allocated_size;
u32 arguments_size;
u8 reserved[0x18];
u8 arguments[];
};
static_assert(sizeof(ProgramArguments) == 0x20, "ProgramArguments definition!");
struct PinId {
u64 value;
};
inline bool operator==(const PinId &lhs, const PinId &rhs) {
return lhs.value == rhs.value;
}
inline bool operator!=(const PinId &lhs, const PinId &rhs) {
return lhs.value != rhs.value;
}
static_assert(sizeof(PinId) == sizeof(u64) && std::is_pod<PinId>::value, "PinId definition!");
/* Import ModuleInfo from libnx. */
using ModuleInfo = ::LoaderModuleInfo;
/* NSO types. */
struct NsoHeader {
static constexpr u32 Magic = 0x304F534E;
enum Segment : size_t {
Segment_Text = 0,
Segment_Ro = 1,
Segment_Rw = 2,
Segment_Count,
};
enum Flag : u32 {
Flag_CompressedText = (1 << 0),
Flag_CompressedRo = (1 << 1),
Flag_CompressedRw = (1 << 2),
Flag_CheckHashText = (1 << 3),
Flag_CheckHashRo = (1 << 4),
Flag_CheckHashRw = (1 << 5),
};
struct SegmentInfo {
u32 file_offset;
u32 dst_offset;
u32 size;
u32 reserved;
};
u32 magic;
u32 version;
u32 reserved_08;
u32 flags;
union {
struct {
u32 text_file_offset;
u32 text_dst_offset;
u32 text_size;
u32 unk_file_offset;
u32 ro_file_offset;
u32 ro_dst_offset;
u32 ro_size;
u32 unk_size;
u32 rw_file_offset;
u32 rw_dst_offset;
u32 rw_size;
u32 bss_size;
};
SegmentInfo segments[Segment_Count];
};
u8 build_id[sizeof(ModuleInfo::build_id)];
union {
u32 compressed_sizes[Segment_Count];
struct {
u32 text_compressed_size;
u32 ro_compressed_size;
u32 rw_compressed_size;
};
};
u8 reserved_6C[0x34];
union {
u8 segment_hashes[Segment_Count][SHA256_HASH_SIZE];
struct {
u8 text_hash[SHA256_HASH_SIZE];
u8 ro_hash[SHA256_HASH_SIZE];
u8 rw_hash[SHA256_HASH_SIZE];
};
};
};
static_assert(sizeof(NsoHeader) == 0x100 && std::is_pod<NsoHeader>::value, "NsoHeader definition!");
/* NPDM types. */
struct Aci {
static constexpr u32 Magic = 0x30494341;
u32 magic;
u8 reserved_04[0xC];
ncm::ProgramId program_id;
u8 reserved_18[0x8];
u32 fah_offset;
u32 fah_size;
u32 sac_offset;
u32 sac_size;
u32 kac_offset;
u32 kac_size;
u8 reserved_38[0x8];
};
static_assert(sizeof(Aci) == 0x40 && std::is_pod<Aci>::value, "Aci definition!");
struct Acid {
static constexpr u32 Magic = 0x44494341;
enum AcidFlag {
AcidFlag_Production = (1 << 0),
AcidFlag_UnqualifiedApproval = (1 << 1),
AcidFlag_DeprecatedUseSecureMemory = (1 << 2),
AcidFlag_PoolPartitionShift = 2,
AcidFlag_PoolPartitionMask = (3 << AcidFlag_PoolPartitionShift),
};
enum PoolPartition {
PoolPartition_Application = (svc::CreateProcessFlag_PoolPartitionApplication >> svc::CreateProcessFlag_PoolPartitionShift),
PoolPartition_Applet = (svc::CreateProcessFlag_PoolPartitionApplet >> svc::CreateProcessFlag_PoolPartitionShift),
PoolPartition_System = (svc::CreateProcessFlag_PoolPartitionSystem >> svc::CreateProcessFlag_PoolPartitionShift),
PoolPartition_SystemNonSecure = (svc::CreateProcessFlag_PoolPartitionSystemNonSecure >> svc::CreateProcessFlag_PoolPartitionShift),
};
u8 signature[0x100];
u8 modulus[0x100];
u32 magic;
u32 size;
u8 version;
u8 reserved_209[3];
u32 flags;
ncm::ProgramId program_id_min;
ncm::ProgramId program_id_max;
u32 fac_offset;
u32 fac_size;
u32 sac_offset;
u32 sac_size;
u32 kac_offset;
u32 kac_size;
u8 reserved_238[0x8];
};
static_assert(sizeof(Acid) == 0x240 && std::is_pod<Acid>::value, "Acid definition!");
struct Npdm {
static constexpr u32 Magic = 0x4154454D;
enum MetaFlag {
MetaFlag_Is64Bit = (1 << 0),
MetaFlag_AddressSpaceTypeShift = 1,
MetaFlag_AddressSpaceTypeMask = (7 << MetaFlag_AddressSpaceTypeShift),
MetaFlag_OptimizeMemoryAllocation = (1 << 4),
};
enum AddressSpaceType {
AddressSpaceType_32Bit = (svc::CreateProcessFlag_AddressSpace32Bit >> svc::CreateProcessFlag_AddressSpaceShift),
AddressSpaceType_64BitDeprecated = (svc::CreateProcessFlag_AddressSpace64BitDeprecated >> svc::CreateProcessFlag_AddressSpaceShift),
AddressSpaceType_32BitWithoutAlias = (svc::CreateProcessFlag_AddressSpace32BitWithoutAlias >> svc::CreateProcessFlag_AddressSpaceShift),
AddressSpaceType_64Bit = (svc::CreateProcessFlag_AddressSpace64Bit >> svc::CreateProcessFlag_AddressSpaceShift),
};
u32 magic;
u8 reserved_04[8];
u8 flags;
u8 reserved_0D;
u8 main_thread_priority;
u8 default_cpu_id;
u8 reserved_10[4];
u32 system_resource_size;
u32 version;
u32 main_thread_stack_size;
char program_name[0x10];
char product_code[0x10];
u8 reserved_40[0x30];
u32 aci_offset;
u32 aci_size;
u32 acid_offset;
u32 acid_size;
};
static_assert(sizeof(Npdm) == 0x80 && std::is_pod<Npdm>::value, "Npdm definition!");
}

View file

@ -0,0 +1,20 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "map/map_types.hpp"
#include "map/map_api.hpp"

View file

@ -0,0 +1,28 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "map_types.hpp"
namespace ams::map {
/* Public API. */
Result GetProcessAddressSpaceInfo(AddressSpaceInfo *out, Handle process_h);
Result LocateMappableSpace(uintptr_t *out_address, size_t size);
Result MapCodeMemoryInProcess(MappedCodeMemory &out_mcm, Handle process_handle, uintptr_t base_address, size_t size);
bool CanAddGuardRegionsInProcess(Handle process_handle, uintptr_t address, size_t size);
}

View file

@ -0,0 +1,122 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
namespace ams::map {
/* Types. */
struct AddressSpaceInfo {
uintptr_t heap_base;
size_t heap_size;
uintptr_t heap_end;
uintptr_t alias_base;
size_t alias_size;
uintptr_t alias_end;
uintptr_t aslr_base;
size_t aslr_size;
uintptr_t aslr_end;
};
static constexpr uintptr_t AslrBase32Bit = 0x0000200000ul;
static constexpr size_t AslrSize32Bit = 0x003FE00000ul;
static constexpr uintptr_t AslrBase64BitDeprecated = 0x0008000000ul;
static constexpr size_t AslrSize64BitDeprecated = 0x0078000000ul;
static constexpr uintptr_t AslrBase64Bit = 0x0008000000ul;
static constexpr size_t AslrSize64Bit = 0x7FF8000000ul;
class AutoCloseMap {
private:
Handle process_handle;
Result result;
void *mapped_address;
uintptr_t base_address;
size_t size;
public:
AutoCloseMap(uintptr_t mp, Handle p_h, uintptr_t ba, size_t sz) : process_handle(p_h), mapped_address(reinterpret_cast<void *>(mp)), base_address(ba), size(sz) {
this->result = svcMapProcessMemory(this->mapped_address, this->process_handle, this->base_address, this->size);
}
~AutoCloseMap() {
if (this->process_handle != INVALID_HANDLE && R_SUCCEEDED(this->result)) {
R_ASSERT(svcUnmapProcessMemory(this->mapped_address, this->process_handle, this->base_address, this->size));
}
}
Result GetResult() const {
return this->result;
}
bool IsSuccess() const {
return R_SUCCEEDED(this->result);
}
void Invalidate() {
this->process_handle = INVALID_HANDLE;
}
};
class MappedCodeMemory {
private:
Handle process_handle;
Result result;
uintptr_t dst_address;
uintptr_t src_address;
size_t size;
public:
MappedCodeMemory(Result init_res) : process_handle(INVALID_HANDLE), result(init_res), dst_address(0), src_address(0), size(0) {
/* ... */
}
MappedCodeMemory(Handle p_h, uintptr_t dst, uintptr_t src, size_t sz) : process_handle(p_h), dst_address(dst), src_address(src), size(sz) {
this->result = svcMapProcessCodeMemory(this->process_handle, this->dst_address, this->src_address, this->size);
}
~MappedCodeMemory() {
if (this->process_handle != INVALID_HANDLE && R_SUCCEEDED(this->result) && this->size > 0) {
R_ASSERT(svcUnmapProcessCodeMemory(this->process_handle, this->dst_address, this->src_address, this->size));
}
}
uintptr_t GetDstAddress() const {
return this->dst_address;
}
Result GetResult() const {
return this->result;
}
bool IsSuccess() const {
return R_SUCCEEDED(this->result);
}
void Invalidate() {
this->process_handle = INVALID_HANDLE;
}
MappedCodeMemory &operator=(MappedCodeMemory &&o) {
this->process_handle = o.process_handle;
this->result = o.result;
this->dst_address = o.dst_address;
this->src_address = o.src_address;
this->size = o.size;
o.Invalidate();
return *this;
}
};
}

View file

@ -0,0 +1,19 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "ncm/ncm_types.hpp"

View file

@ -0,0 +1,447 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
namespace ams::ncm {
/* Storage IDs. */
enum class StorageId : u8 {
#define DEFINE_ENUM_MEMBER(nm) nm = NcmStorageId_##nm
DEFINE_ENUM_MEMBER(None),
DEFINE_ENUM_MEMBER(Host),
DEFINE_ENUM_MEMBER(GameCard),
DEFINE_ENUM_MEMBER(BuiltInSystem),
DEFINE_ENUM_MEMBER(BuiltInUser),
DEFINE_ENUM_MEMBER(SdCard),
DEFINE_ENUM_MEMBER(Any),
#undef DEFINE_ENUM_MEMBER
};
/* Program IDs (Formerly: Title IDs). */
struct ProgramId {
u64 value;
inline explicit operator u64() const {
return this->value;
}
/* Invalid Program ID. */
static const ProgramId Invalid;
/* System Modules. */
static const ProgramId SystemStart;
static const ProgramId Fs;
static const ProgramId Loader;
static const ProgramId Ncm;
static const ProgramId Pm;
static const ProgramId Sm;
static const ProgramId Boot;
static const ProgramId Usb;
static const ProgramId Tma;
static const ProgramId Boot2;
static const ProgramId Settings;
static const ProgramId Bus;
static const ProgramId Bluetooth;
static const ProgramId Bcat;
static const ProgramId Dmnt;
static const ProgramId Friends;
static const ProgramId Nifm;
static const ProgramId Ptm;
static const ProgramId Shell;
static const ProgramId BsdSockets;
static const ProgramId Hid;
static const ProgramId Audio;
static const ProgramId LogManager;
static const ProgramId Wlan;
static const ProgramId Cs;
static const ProgramId Ldn;
static const ProgramId NvServices;
static const ProgramId Pcv;
static const ProgramId Ppc;
static const ProgramId NvnFlinger;
static const ProgramId Pcie;
static const ProgramId Account;
static const ProgramId Ns;
static const ProgramId Nfc;
static const ProgramId Psc;
static const ProgramId CapSrv;
static const ProgramId Am;
static const ProgramId Ssl;
static const ProgramId Nim;
static const ProgramId Cec;
static const ProgramId Tspm;
static const ProgramId Spl;
static const ProgramId Lbl;
static const ProgramId Btm;
static const ProgramId Erpt;
static const ProgramId Time;
static const ProgramId Vi;
static const ProgramId Pctl;
static const ProgramId Npns;
static const ProgramId Eupld;
static const ProgramId Arp;
static const ProgramId Glue;
static const ProgramId Eclct;
static const ProgramId Es;
static const ProgramId Fatal;
static const ProgramId Grc;
static const ProgramId Creport;
static const ProgramId Ro;
static const ProgramId Profiler;
static const ProgramId Sdb;
static const ProgramId Migration;
static const ProgramId Jit;
static const ProgramId JpegDec;
static const ProgramId SafeMode;
static const ProgramId Olsc;
static const ProgramId Dt;
static const ProgramId Nd;
static const ProgramId Ngct;
static const ProgramId SystemEnd;
/* System Data Archives. */
static const ProgramId ArchiveStart;
static const ProgramId ArchiveCertStore;
static const ProgramId ArchiveErrorMessage;
static const ProgramId ArchiveMiiModel;
static const ProgramId ArchiveBrowserDll;
static const ProgramId ArchiveHelp;
static const ProgramId ArchiveSharedFont;
static const ProgramId ArchiveNgWord;
static const ProgramId ArchiveSsidList;
static const ProgramId ArchiveDictionary;
static const ProgramId ArchiveSystemVersion;
static const ProgramId ArchiveAvatarImage;
static const ProgramId ArchiveLocalNews;
static const ProgramId ArchiveEula;
static const ProgramId ArchiveUrlBlackList;
static const ProgramId ArchiveTimeZoneBinar;
static const ProgramId ArchiveCertStoreCruiser;
static const ProgramId ArchiveFontNintendoExtension;
static const ProgramId ArchiveFontStandard;
static const ProgramId ArchiveFontKorean;
static const ProgramId ArchiveFontChineseTraditional;
static const ProgramId ArchiveFontChineseSimple;
static const ProgramId ArchiveFontBfcpx;
static const ProgramId ArchiveSystemUpdate;
static const ProgramId ArchiveFirmwareDebugSettings;
static const ProgramId ArchiveBootImagePackage;
static const ProgramId ArchiveBootImagePackageSafe;
static const ProgramId ArchiveBootImagePackageExFat;
static const ProgramId ArchiveBootImagePackageExFatSafe;
static const ProgramId ArchiveFatalMessage;
static const ProgramId ArchiveControllerIcon;
static const ProgramId ArchivePlatformConfigIcosa;
static const ProgramId ArchivePlatformConfigCopper;
static const ProgramId ArchivePlatformConfigHoag;
static const ProgramId ArchiveControllerFirmware;
static const ProgramId ArchiveNgWord2;
static const ProgramId ArchivePlatformConfigIcosaMariko;
static const ProgramId ArchiveApplicationBlackList;
static const ProgramId ArchiveRebootlessSystemUpdateVersion;
static const ProgramId ArchiveContentActionTable;
static const ProgramId ArchiveEnd;
/* System Applets. */
static const ProgramId AppletStart;
static const ProgramId AppletQlaunch;
static const ProgramId AppletAuth;
static const ProgramId AppletCabinet;
static const ProgramId AppletController;
static const ProgramId AppletDataErase;
static const ProgramId AppletError;
static const ProgramId AppletNetConnect;
static const ProgramId AppletPlayerSelect;
static const ProgramId AppletSwkbd;
static const ProgramId AppletMiiEdit;
static const ProgramId AppletWeb;
static const ProgramId AppletShop;
static const ProgramId AppletOverlayDisp;
static const ProgramId AppletPhotoViewer;
static const ProgramId AppletSet;
static const ProgramId AppletOfflineWeb;
static const ProgramId AppletLoginShare;
static const ProgramId AppletWifiWebAuth;
static const ProgramId AppletStarter;
static const ProgramId AppletMyPage;
static const ProgramId AppletPlayReport;
static const ProgramId AppletMaintenanceMenu;
static const ProgramId AppletGift;
static const ProgramId AppletDummyShop;
static const ProgramId AppletUserMigration;
static const ProgramId AppletEncounter;
static const ProgramId AppletStory;
static const ProgramId AppletEnd;
/* Debug Applets. */
/* Debug Modules. */
/* Factory Setup. */
/* Applications. */
static const ProgramId ApplicationStart;
static const ProgramId ApplicationEnd;
/* Atmosphere Extensions. */
static const ProgramId AtmosphereMitm;
};
/* Invalid Program ID. */
inline constexpr const ProgramId ProgramId::Invalid = {};
inline constexpr const ProgramId InvalidProgramId = ProgramId::Invalid;
/* System Modules. */
inline constexpr const ProgramId ProgramId::SystemStart = { 0x0100000000000000ul };
inline constexpr const ProgramId ProgramId::Fs = { 0x0100000000000000ul };
inline constexpr const ProgramId ProgramId::Loader = { 0x0100000000000001ul };
inline constexpr const ProgramId ProgramId::Ncm = { 0x0100000000000002ul };
inline constexpr const ProgramId ProgramId::Pm = { 0x0100000000000003ul };
inline constexpr const ProgramId ProgramId::Sm = { 0x0100000000000004ul };
inline constexpr const ProgramId ProgramId::Boot = { 0x0100000000000005ul };
inline constexpr const ProgramId ProgramId::Usb = { 0x0100000000000006ul };
inline constexpr const ProgramId ProgramId::Tma = { 0x0100000000000007ul };
inline constexpr const ProgramId ProgramId::Boot2 = { 0x0100000000000008ul };
inline constexpr const ProgramId ProgramId::Settings = { 0x0100000000000009ul };
inline constexpr const ProgramId ProgramId::Bus = { 0x010000000000000Aul };
inline constexpr const ProgramId ProgramId::Bluetooth = { 0x010000000000000Bul };
inline constexpr const ProgramId ProgramId::Bcat = { 0x010000000000000Cul };
inline constexpr const ProgramId ProgramId::Dmnt = { 0x010000000000000Dul };
inline constexpr const ProgramId ProgramId::Friends = { 0x010000000000000Eul };
inline constexpr const ProgramId ProgramId::Nifm = { 0x010000000000000Ful };
inline constexpr const ProgramId ProgramId::Ptm = { 0x0100000000000010ul };
inline constexpr const ProgramId ProgramId::Shell = { 0x0100000000000011ul };
inline constexpr const ProgramId ProgramId::BsdSockets = { 0x0100000000000012ul };
inline constexpr const ProgramId ProgramId::Hid = { 0x0100000000000013ul };
inline constexpr const ProgramId ProgramId::Audio = { 0x0100000000000014ul };
inline constexpr const ProgramId ProgramId::LogManager = { 0x0100000000000015ul };
inline constexpr const ProgramId ProgramId::Wlan = { 0x0100000000000016ul };
inline constexpr const ProgramId ProgramId::Cs = { 0x0100000000000017ul };
inline constexpr const ProgramId ProgramId::Ldn = { 0x0100000000000018ul };
inline constexpr const ProgramId ProgramId::NvServices = { 0x0100000000000019ul };
inline constexpr const ProgramId ProgramId::Pcv = { 0x010000000000001Aul };
inline constexpr const ProgramId ProgramId::Ppc = { 0x010000000000001Bul };
inline constexpr const ProgramId ProgramId::NvnFlinger = { 0x010000000000001Cul };
inline constexpr const ProgramId ProgramId::Pcie = { 0x010000000000001Dul };
inline constexpr const ProgramId ProgramId::Account = { 0x010000000000001Eul };
inline constexpr const ProgramId ProgramId::Ns = { 0x010000000000001Ful };
inline constexpr const ProgramId ProgramId::Nfc = { 0x0100000000000020ul };
inline constexpr const ProgramId ProgramId::Psc = { 0x0100000000000021ul };
inline constexpr const ProgramId ProgramId::CapSrv = { 0x0100000000000022ul };
inline constexpr const ProgramId ProgramId::Am = { 0x0100000000000023ul };
inline constexpr const ProgramId ProgramId::Ssl = { 0x0100000000000024ul };
inline constexpr const ProgramId ProgramId::Nim = { 0x0100000000000025ul };
inline constexpr const ProgramId ProgramId::Cec = { 0x0100000000000026ul };
inline constexpr const ProgramId ProgramId::Tspm = { 0x0100000000000027ul };
inline constexpr const ProgramId ProgramId::Spl = { 0x0100000000000028ul };
inline constexpr const ProgramId ProgramId::Lbl = { 0x0100000000000029ul };
inline constexpr const ProgramId ProgramId::Btm = { 0x010000000000002Aul };
inline constexpr const ProgramId ProgramId::Erpt = { 0x010000000000002Bul };
inline constexpr const ProgramId ProgramId::Time = { 0x010000000000002Cul };
inline constexpr const ProgramId ProgramId::Vi = { 0x010000000000002Dul };
inline constexpr const ProgramId ProgramId::Pctl = { 0x010000000000002Eul };
inline constexpr const ProgramId ProgramId::Npns = { 0x010000000000002Ful };
inline constexpr const ProgramId ProgramId::Eupld = { 0x0100000000000030ul };
inline constexpr const ProgramId ProgramId::Arp = { 0x0100000000000031ul };
inline constexpr const ProgramId ProgramId::Glue = { 0x0100000000000031ul };
inline constexpr const ProgramId ProgramId::Eclct = { 0x0100000000000032ul };
inline constexpr const ProgramId ProgramId::Es = { 0x0100000000000033ul };
inline constexpr const ProgramId ProgramId::Fatal = { 0x0100000000000034ul };
inline constexpr const ProgramId ProgramId::Grc = { 0x0100000000000035ul };
inline constexpr const ProgramId ProgramId::Creport = { 0x0100000000000036ul };
inline constexpr const ProgramId ProgramId::Ro = { 0x0100000000000037ul };
inline constexpr const ProgramId ProgramId::Profiler = { 0x0100000000000038ul };
inline constexpr const ProgramId ProgramId::Sdb = { 0x0100000000000039ul };
inline constexpr const ProgramId ProgramId::Migration = { 0x010000000000003Aul };
inline constexpr const ProgramId ProgramId::Jit = { 0x010000000000003Bul };
inline constexpr const ProgramId ProgramId::JpegDec = { 0x010000000000003Cul };
inline constexpr const ProgramId ProgramId::SafeMode = { 0x010000000000003Dul };
inline constexpr const ProgramId ProgramId::Olsc = { 0x010000000000003Eul };
inline constexpr const ProgramId ProgramId::Dt = { 0x010000000000003Ful };
inline constexpr const ProgramId ProgramId::Nd = { 0x0100000000000040ul };
inline constexpr const ProgramId ProgramId::Ngct = { 0x0100000000000041ul };
inline constexpr const ProgramId ProgramId::SystemEnd = { 0x01000000000007FFul };
/* System Data Archives. */
inline constexpr const ProgramId ProgramId::ArchiveStart = { 0x0100000000000800ul };
inline constexpr const ProgramId ProgramId::ArchiveCertStore = { 0x0100000000000800ul };
inline constexpr const ProgramId ProgramId::ArchiveErrorMessage = { 0x0100000000000801ul };
inline constexpr const ProgramId ProgramId::ArchiveMiiModel = { 0x0100000000000802ul };
inline constexpr const ProgramId ProgramId::ArchiveBrowserDll = { 0x0100000000000803ul };
inline constexpr const ProgramId ProgramId::ArchiveHelp = { 0x0100000000000804ul };
inline constexpr const ProgramId ProgramId::ArchiveSharedFont = { 0x0100000000000805ul };
inline constexpr const ProgramId ProgramId::ArchiveNgWord = { 0x0100000000000806ul };
inline constexpr const ProgramId ProgramId::ArchiveSsidList = { 0x0100000000000807ul };
inline constexpr const ProgramId ProgramId::ArchiveDictionary = { 0x0100000000000808ul };
inline constexpr const ProgramId ProgramId::ArchiveSystemVersion = { 0x0100000000000809ul };
inline constexpr const ProgramId ProgramId::ArchiveAvatarImage = { 0x010000000000080Aul };
inline constexpr const ProgramId ProgramId::ArchiveLocalNews = { 0x010000000000080Bul };
inline constexpr const ProgramId ProgramId::ArchiveEula = { 0x010000000000080Cul };
inline constexpr const ProgramId ProgramId::ArchiveUrlBlackList = { 0x010000000000080Dul };
inline constexpr const ProgramId ProgramId::ArchiveTimeZoneBinar = { 0x010000000000080Eul };
inline constexpr const ProgramId ProgramId::ArchiveCertStoreCruiser = { 0x010000000000080Ful };
inline constexpr const ProgramId ProgramId::ArchiveFontNintendoExtension = { 0x0100000000000810ul };
inline constexpr const ProgramId ProgramId::ArchiveFontStandard = { 0x0100000000000811ul };
inline constexpr const ProgramId ProgramId::ArchiveFontKorean = { 0x0100000000000812ul };
inline constexpr const ProgramId ProgramId::ArchiveFontChineseTraditional = { 0x0100000000000813ul };
inline constexpr const ProgramId ProgramId::ArchiveFontChineseSimple = { 0x0100000000000814ul };
inline constexpr const ProgramId ProgramId::ArchiveFontBfcpx = { 0x0100000000000815ul };
inline constexpr const ProgramId ProgramId::ArchiveSystemUpdate = { 0x0100000000000816ul };
inline constexpr const ProgramId ProgramId::ArchiveFirmwareDebugSettings = { 0x0100000000000818ul };
inline constexpr const ProgramId ProgramId::ArchiveBootImagePackage = { 0x0100000000000819ul };
inline constexpr const ProgramId ProgramId::ArchiveBootImagePackageSafe = { 0x010000000000081Aul };
inline constexpr const ProgramId ProgramId::ArchiveBootImagePackageExFat = { 0x010000000000081Bul };
inline constexpr const ProgramId ProgramId::ArchiveBootImagePackageExFatSafe = { 0x010000000000081Cul };
inline constexpr const ProgramId ProgramId::ArchiveFatalMessage = { 0x010000000000081Dul };
inline constexpr const ProgramId ProgramId::ArchiveControllerIcon = { 0x010000000000081Eul };
inline constexpr const ProgramId ProgramId::ArchivePlatformConfigIcosa = { 0x010000000000081Ful };
inline constexpr const ProgramId ProgramId::ArchivePlatformConfigCopper = { 0x0100000000000820ul };
inline constexpr const ProgramId ProgramId::ArchivePlatformConfigHoag = { 0x0100000000000821ul };
inline constexpr const ProgramId ProgramId::ArchiveControllerFirmware = { 0x0100000000000822ul };
inline constexpr const ProgramId ProgramId::ArchiveNgWord2 = { 0x0100000000000823ul };
inline constexpr const ProgramId ProgramId::ArchivePlatformConfigIcosaMariko = { 0x0100000000000824ul };
inline constexpr const ProgramId ProgramId::ArchiveApplicationBlackList = { 0x0100000000000825ul };
inline constexpr const ProgramId ProgramId::ArchiveRebootlessSystemUpdateVersion = { 0x0100000000000826ul };
inline constexpr const ProgramId ProgramId::ArchiveContentActionTable = { 0x0100000000000827ul };
inline constexpr const ProgramId ProgramId::ArchiveEnd = { 0x0100000000000FFFul };
/* System Applets. */
inline constexpr const ProgramId ProgramId::AppletStart = { 0x0100000000001000ul };
inline constexpr const ProgramId ProgramId::AppletQlaunch = { 0x0100000000001000ul };
inline constexpr const ProgramId ProgramId::AppletAuth = { 0x0100000000001001ul };
inline constexpr const ProgramId ProgramId::AppletCabinet = { 0x0100000000001002ul };
inline constexpr const ProgramId ProgramId::AppletController = { 0x0100000000001003ul };
inline constexpr const ProgramId ProgramId::AppletDataErase = { 0x0100000000001004ul };
inline constexpr const ProgramId ProgramId::AppletError = { 0x0100000000001005ul };
inline constexpr const ProgramId ProgramId::AppletNetConnect = { 0x0100000000001006ul };
inline constexpr const ProgramId ProgramId::AppletPlayerSelect = { 0x0100000000001007ul };
inline constexpr const ProgramId ProgramId::AppletSwkbd = { 0x0100000000001008ul };
inline constexpr const ProgramId ProgramId::AppletMiiEdit = { 0x0100000000001009ul };
inline constexpr const ProgramId ProgramId::AppletWeb = { 0x010000000000100Aul };
inline constexpr const ProgramId ProgramId::AppletShop = { 0x010000000000100Bul };
inline constexpr const ProgramId ProgramId::AppletOverlayDisp = { 0x010000000000100Cul };
inline constexpr const ProgramId ProgramId::AppletPhotoViewer = { 0x010000000000100Dul };
inline constexpr const ProgramId ProgramId::AppletSet = { 0x010000000000100Eul };
inline constexpr const ProgramId ProgramId::AppletOfflineWeb = { 0x010000000000100Ful };
inline constexpr const ProgramId ProgramId::AppletLoginShare = { 0x0100000000001010ul };
inline constexpr const ProgramId ProgramId::AppletWifiWebAuth = { 0x0100000000001011ul };
inline constexpr const ProgramId ProgramId::AppletStarter = { 0x0100000000001012ul };
inline constexpr const ProgramId ProgramId::AppletMyPage = { 0x0100000000001013ul };
inline constexpr const ProgramId ProgramId::AppletPlayReport = { 0x0100000000001014ul };
inline constexpr const ProgramId ProgramId::AppletMaintenanceMenu = { 0x0100000000001015ul };
inline constexpr const ProgramId ProgramId::AppletGift = { 0x010000000000101Aul };
inline constexpr const ProgramId ProgramId::AppletDummyShop = { 0x010000000000101Bul };
inline constexpr const ProgramId ProgramId::AppletUserMigration = { 0x010000000000101Cul };
inline constexpr const ProgramId ProgramId::AppletEncounter = { 0x010000000000101Dul };
inline constexpr const ProgramId ProgramId::AppletStory = { 0x0100000000001020ul };
inline constexpr const ProgramId ProgramId::AppletEnd = { 0x0100000000001FFFul };
/* Debug Applets. */
/* Debug Modules. */
/* Factory Setup. */
/* Applications. */
inline constexpr const ProgramId ProgramId::ApplicationStart = { 0x0100000000010000ul };
inline constexpr const ProgramId ProgramId::ApplicationEnd = { 0x01FFFFFFFFFFFFFFul };
/* Atmosphere Extensions. */
inline constexpr const ProgramId ProgramId::AtmosphereMitm = { 0x010041544D530000ul };
inline constexpr bool operator==(const ProgramId &lhs, const ProgramId &rhs) {
return lhs.value == rhs.value;
}
inline constexpr bool operator!=(const ProgramId &lhs, const ProgramId &rhs) {
return lhs.value != rhs.value;
}
inline constexpr bool operator<(const ProgramId &lhs, const ProgramId &rhs) {
return lhs.value < rhs.value;
}
inline constexpr bool operator<=(const ProgramId &lhs, const ProgramId &rhs) {
return lhs.value <= rhs.value;
}
inline constexpr bool operator>(const ProgramId &lhs, const ProgramId &rhs) {
return lhs.value > rhs.value;
}
inline constexpr bool operator>=(const ProgramId &lhs, const ProgramId &rhs) {
return lhs.value >= rhs.value;
}
inline constexpr bool IsSystemProgramId(const ProgramId &program_id) {
return ProgramId::SystemStart <= program_id && program_id <= ProgramId::SystemEnd;
}
inline constexpr bool IsArchiveProgramId(const ProgramId &program_id) {
return ProgramId::ArchiveStart <= program_id && program_id <= ProgramId::ArchiveEnd;
}
inline constexpr bool IsAppletProgramId(const ProgramId &program_id) {
return ProgramId::AppletStart <= program_id && program_id <= ProgramId::AppletEnd;
}
inline constexpr bool IsApplicationProgramId(const ProgramId &program_id) {
return ProgramId::ApplicationStart <= program_id && program_id <= ProgramId::ApplicationEnd;
}
inline constexpr bool IsWebAppletProgramId(const ProgramId &program_id) {
return program_id == ProgramId::AppletWeb ||
program_id == ProgramId::AppletShop ||
program_id == ProgramId::AppletOfflineWeb ||
program_id == ProgramId::AppletLoginShare ||
program_id == ProgramId::AppletWifiWebAuth;
}
static_assert(sizeof(ProgramId) == sizeof(u64) && std::is_pod<ProgramId>::value, "ProgramId definition!");
/* Program Location. */
struct ProgramLocation {
ProgramId program_id;
u8 storage_id;
static constexpr ProgramLocation Make(ProgramId program_id, StorageId storage_id) {
return { .program_id = program_id, .storage_id = static_cast<u8>(storage_id), };
}
};
static_assert(sizeof(ProgramLocation) == 0x10 && std::is_pod<ProgramLocation>::value, "ProgramLocation definition!");
static_assert(sizeof(ProgramLocation) == sizeof(::NcmProgramLocation) && alignof(ProgramLocation) == alignof(::NcmProgramLocation), "ProgramLocation Libnx Compatibility");
}

View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "os/os_common_types.hpp"
#include "os/os_memory_common.hpp"
#include "os/os_managed_handle.hpp"
#include "os/os_process_handle.hpp"
#include "os/os_mutex.hpp"
#include "os/os_condvar.hpp"
#include "os/os_rw_lock.hpp"
#include "os/os_semaphore.hpp"
#include "os/os_timeout_helper.hpp"
#include "os/os_event.hpp"
#include "os/os_system_event.hpp"
#include "os/os_interrupt_event.hpp"
#include "os/os_thread.hpp"
#include "os/os_message_queue.hpp"
#include "os/os_waitable_holder.hpp"
#include "os/os_waitable_manager.hpp"

View file

@ -0,0 +1,81 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
namespace ams::os {
enum class TriBool {
False = 0,
True = 1,
Undefined = 2,
};
enum class MessageQueueWaitKind {
ForNotEmpty,
ForNotFull,
};
struct ProcessId {
u64 value;
inline constexpr explicit operator u64() const {
return this->value;
}
/* Invalid Process ID. */
static const ProcessId Invalid;
};
inline constexpr const ProcessId ProcessId::Invalid = {static_cast<u64>(-1ull)};
inline constexpr const ProcessId InvalidProcessId = ProcessId::Invalid;
NX_INLINE Result TryGetProcessId(os::ProcessId *out, ::Handle process_handle) {
return svcGetProcessId(&out->value, process_handle);
}
NX_INLINE os::ProcessId GetProcessId(::Handle process_handle) {
os::ProcessId process_id;
R_ASSERT(TryGetProcessId(&process_id, process_handle));
return process_id;
}
inline constexpr bool operator==(const ProcessId &lhs, const ProcessId &rhs) {
return lhs.value == rhs.value;
}
inline constexpr bool operator!=(const ProcessId &lhs, const ProcessId &rhs) {
return lhs.value != rhs.value;
}
inline constexpr bool operator<(const ProcessId &lhs, const ProcessId &rhs) {
return lhs.value < rhs.value;
}
inline constexpr bool operator<=(const ProcessId &lhs, const ProcessId &rhs) {
return lhs.value <= rhs.value;
}
inline constexpr bool operator>(const ProcessId &lhs, const ProcessId &rhs) {
return lhs.value > rhs.value;
}
inline constexpr bool operator>=(const ProcessId &lhs, const ProcessId &rhs) {
return lhs.value >= rhs.value;
}
}

View file

@ -0,0 +1,70 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "os_mutex.hpp"
namespace ams::os {
enum class ConditionVariableStatus {
TimedOut = 0,
Success = 1,
};
class ConditionVariable {
NON_COPYABLE(ConditionVariable);
NON_MOVEABLE(ConditionVariable);
private:
CondVar cv;
public:
ConditionVariable() {
condvarInit(&cv);
}
ConditionVariableStatus TimedWait(::Mutex *m, u64 timeout) {
if (timeout > 0) {
/* Abort on any error other than timed out/success. */
R_TRY_CATCH(condvarWaitTimeout(&this->cv, m, timeout)) {
R_CATCH(svc::ResultTimedOut) { return ConditionVariableStatus::TimedOut; }
} R_END_TRY_CATCH_WITH_ASSERT;
return ConditionVariableStatus::Success;
}
return ConditionVariableStatus::TimedOut;
}
void Wait(::Mutex *m) {
R_ASSERT(condvarWait(&this->cv, m));
}
ConditionVariableStatus TimedWait(os::Mutex *m, u64 timeout) {
return this->TimedWait(m->GetMutex(), timeout);
}
void Wait(os::Mutex *m) {
return this->Wait(m->GetMutex());
}
void Signal() {
condvarWakeOne(&this->cv);
}
void Broadcast() {
condvarWakeAll(&this->cv);
}
};
}

View file

@ -0,0 +1,53 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "os_mutex.hpp"
#include "os_condvar.hpp"
#include "os_timeout_helper.hpp"
namespace ams::os {
namespace impl {
class WaitableObjectList;
class WaitableHolderOfEvent;
}
class Event {
friend class impl::WaitableHolderOfEvent;
NON_COPYABLE(Event);
NON_MOVEABLE(Event);
private:
util::TypedStorage<impl::WaitableObjectList, sizeof(util::IntrusiveListNode), alignof(util::IntrusiveListNode)> waitable_object_list_storage;
Mutex lock;
ConditionVariable cv;
u64 counter = 0;
bool auto_clear;
bool signaled;
public:
Event(bool a = true, bool s = false);
~Event();
void Signal();
void Reset();
void Wait();
bool TryWait();
bool TimedWait(u64 ns);
};
}

View file

@ -0,0 +1,49 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "os_managed_handle.hpp"
namespace ams::os {
namespace impl {
class WaitableHolderOfInterruptEvent;
}
class InterruptEvent {
friend class impl::WaitableHolderOfInterruptEvent;
NON_COPYABLE(InterruptEvent);
NON_MOVEABLE(InterruptEvent);
private:
ManagedHandle handle;
bool auto_clear;
bool is_initialized;
public:
InterruptEvent() : auto_clear(true), is_initialized(false) { }
InterruptEvent(u32 interrupt_id, bool autoclear = true);
Result Initialize(u32 interrupt_id, bool autoclear = true);
void Finalize();
void Reset();
void Wait();
bool TryWait();
bool TimedWait(u64 ns);
};
}

View file

@ -0,0 +1,82 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "os_common_types.hpp"
namespace ams::os {
class ManagedHandle {
NON_COPYABLE(ManagedHandle);
private:
Handle hnd;
public:
ManagedHandle() : hnd(INVALID_HANDLE) { /* ... */ }
ManagedHandle(Handle h) : hnd(h) { /* ... */ }
~ManagedHandle() {
if (this->hnd != INVALID_HANDLE) {
R_ASSERT(svcCloseHandle(this->hnd));
this->hnd = INVALID_HANDLE;
}
}
ManagedHandle(ManagedHandle&& rhs) {
this->hnd = rhs.hnd;
rhs.hnd = INVALID_HANDLE;
}
ManagedHandle& operator=(ManagedHandle&& rhs) {
rhs.Swap(*this);
return *this;
}
explicit operator bool() const {
return this->hnd != INVALID_HANDLE;
}
void Swap(ManagedHandle& rhs) {
std::swap(this->hnd, rhs.hnd);
}
Handle Get() const {
return this->hnd;
}
Handle *GetPointer() {
return &this->hnd;
}
Handle *GetPointerAndClear() {
this->Clear();
return this->GetPointer();
}
Handle Move() {
const Handle h = this->hnd;
this->hnd = INVALID_HANDLE;
return h;
}
void Reset(Handle h) {
ManagedHandle(h).Swap(*this);
}
void Clear() {
this->Reset(INVALID_HANDLE);
}
};
}

View file

@ -0,0 +1,25 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
namespace ams::os {
constexpr inline size_t MemoryPageSize = 0x1000;
constexpr inline size_t MemoryBlockUnitSize = 0x200000;
}

View file

@ -0,0 +1,89 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "os_mutex.hpp"
#include "os_condvar.hpp"
namespace ams::os {
namespace impl {
class WaitableObjectList;
template<MessageQueueWaitKind WaitKind>
class WaitableHolderOfMessageQueue;
}
class MessageQueue {
template<MessageQueueWaitKind WaitKind>
friend class impl::WaitableHolderOfMessageQueue;
NON_COPYABLE(MessageQueue);
NON_MOVEABLE(MessageQueue);
private:
util::TypedStorage<impl::WaitableObjectList, sizeof(util::IntrusiveListNode), alignof(util::IntrusiveListNode)> waitlist_not_empty;
util::TypedStorage<impl::WaitableObjectList, sizeof(util::IntrusiveListNode), alignof(util::IntrusiveListNode)> waitlist_not_full;
Mutex queue_lock;
ConditionVariable cv_not_full;
ConditionVariable cv_not_empty;
std::unique_ptr<uintptr_t[]> buffer;
size_t capacity;
size_t count;
size_t offset;
private:
constexpr inline bool IsFull() const {
return this->count >= this->capacity;
}
constexpr inline bool IsEmpty() const {
return this->count == 0;
}
void SendInternal(uintptr_t data);
void SendNextInternal(uintptr_t data);
uintptr_t ReceiveInternal();
uintptr_t PeekInternal();
public:
MessageQueue(std::unique_ptr<uintptr_t[]> buf, size_t c);
~MessageQueue();
/* For convenience. */
MessageQueue(size_t c) : MessageQueue(std::make_unique<uintptr_t[]>(c), c) { /* ... */ }
/* Sending (FIFO functionality) */
void Send(uintptr_t data);
bool TrySend(uintptr_t data);
bool TimedSend(uintptr_t data, u64 timeout);
/* Sending (LIFO functionality) */
void SendNext(uintptr_t data);
bool TrySendNext(uintptr_t data);
bool TimedSendNext(uintptr_t data, u64 timeout);
/* Receive functionality */
void Receive(uintptr_t *out);
bool TryReceive(uintptr_t *out);
bool TimedReceive(uintptr_t *out, u64 timeout);
/* Peek functionality */
void Peek(uintptr_t *out);
bool TryPeek(uintptr_t *out);
bool TimedPeek(uintptr_t *out, u64 timeout);
};
}

View file

@ -0,0 +1,101 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "os_common_types.hpp"
namespace ams::os {
class ConditionVariable;
class Mutex {
NON_COPYABLE(Mutex);
NON_MOVEABLE(Mutex);
friend class ams::os::ConditionVariable;
private:
::Mutex m;
private:
::Mutex *GetMutex() {
return &this->m;
}
public:
Mutex() {
mutexInit(GetMutex());
}
void lock() {
mutexLock(GetMutex());
}
void unlock() {
mutexUnlock(GetMutex());
}
bool try_lock() {
return mutexTryLock(GetMutex());
}
void Lock() {
lock();
}
void Unlock() {
unlock();
}
bool TryLock() {
return try_lock();
}
};
class RecursiveMutex {
private:
::RMutex m;
private:
::RMutex *GetMutex() {
return &this->m;
}
public:
RecursiveMutex() {
rmutexInit(GetMutex());
}
void lock() {
rmutexLock(GetMutex());
}
void unlock() {
rmutexUnlock(GetMutex());
}
bool try_lock() {
return rmutexTryLock(GetMutex());
}
void Lock() {
lock();
}
void Unlock() {
unlock();
}
bool TryLock() {
return try_lock();
}
};
}

View file

@ -0,0 +1,28 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "os_managed_handle.hpp"
namespace ams::os {
::Handle GetCurrentProcessHandle();
NX_INLINE ProcessId GetCurrentProcessId() {
return GetProcessId(GetCurrentProcessHandle());
}
}

View file

@ -0,0 +1,89 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "os_common_types.hpp"
namespace ams::os {
class ReadWriteLock {
NON_COPYABLE(ReadWriteLock);
NON_MOVEABLE(ReadWriteLock);
private:
::RwLock r;
public:
ReadWriteLock() {
rwlockInit(&this->r);
}
bool IsWriteLockHeldByCurrentThread() const {
return rwlockIsWriteLockHeldByCurrentThread(const_cast<::RwLock *>(&this->r));
}
bool IsLockOwner() const {
return rwlockIsOwnedByCurrentThread(const_cast<::RwLock *>(&this->r));
}
void AcquireReadLock() {
rwlockReadLock(&this->r);
}
void ReleaseReadLock() {
rwlockReadUnlock(&this->r);
}
bool TryAcquireReadLock() {
return rwlockTryReadLock(&this->r);
}
void AcquireWriteLock() {
rwlockWriteLock(&this->r);
}
void ReleaseWriteLock() {
rwlockWriteUnlock(&this->r);
}
bool TryAcquireWriteLock() {
return rwlockTryWriteLock(&this->r);
}
void lock_shared() {
this->AcquireReadLock();
}
void unlock_shared() {
this->ReleaseReadLock();
}
bool try_lock_shared() {
return this->TryAcquireReadLock();
}
void lock() {
this->AcquireWriteLock();
}
void unlock() {
this->ReleaseWriteLock();
}
bool try_lock() {
return this->TryAcquireWriteLock();
}
};
}

View file

@ -0,0 +1,56 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "os_mutex.hpp"
#include "os_condvar.hpp"
namespace ams::os {
namespace impl {
class WaitableObjectList;
class WaitableHolderOfSemaphore;
}
class Semaphore {
friend class impl::WaitableHolderOfSemaphore;
NON_COPYABLE(Semaphore);
NON_MOVEABLE(Semaphore);
private:
util::TypedStorage<impl::WaitableObjectList, sizeof(util::IntrusiveListNode), alignof(util::IntrusiveListNode)> waitlist;
os::Mutex mutex;
os::ConditionVariable condvar;
int count;
int max_count;
public:
explicit Semaphore(int c, int mc);
~Semaphore();
void Acquire();
bool TryAcquire();
bool TimedAcquire(u64 timeout);
void Release();
void Release(int count);
constexpr inline int GetCurrentCount() const {
return this->count;
}
};
}

View file

@ -0,0 +1,80 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "os_event.hpp"
namespace ams::os {
class WaitableHolder;
namespace impl {
class InterProcessEvent;
}
enum class SystemEventState {
Uninitialized,
Event,
InterProcessEvent,
};
class SystemEvent {
friend class WaitableHolder;
NON_COPYABLE(SystemEvent);
NON_MOVEABLE(SystemEvent);
private:
union {
util::TypedStorage<Event, sizeof(Event), alignof(Event)> storage_for_event;
util::TypedStorage<impl::InterProcessEvent, 3 * sizeof(Handle), alignof(Handle)> storage_for_inter_process_event;
};
SystemEventState state;
private:
Event &GetEvent();
const Event &GetEvent() const;
impl::InterProcessEvent &GetInterProcessEvent();
const impl::InterProcessEvent &GetInterProcessEvent() const;
public:
SystemEvent() : state(SystemEventState::Uninitialized) { /* ... */ }
SystemEvent(bool inter_process, bool autoclear = true);
SystemEvent(Handle read_handle, bool manage_read_handle, Handle write_handle, bool manage_write_handle, bool autoclear = true);
SystemEvent(Handle read_handle, bool manage_read_handle, bool autoclear = true) : SystemEvent(read_handle, manage_read_handle, INVALID_HANDLE, false, autoclear) { /* ... */ }
~SystemEvent();
Result InitializeAsEvent(bool autoclear = true);
Result InitializeAsInterProcessEvent(bool autoclear = true);
void AttachHandles(Handle read_handle, bool manage_read_handle, Handle write_handle, bool manage_write_handle, bool autoclear = true);
void AttachReadableHandle(Handle read_handle, bool manage_read_handle, bool autoclear = true);
void AttachWritableHandle(Handle write_handle, bool manage_write_handle, bool autoclear = true);
Handle DetachReadableHandle();
Handle DetachWritableHandle();
Handle GetReadableHandle() const;
Handle GetWritableHandle() const;
void Finalize();
SystemEventState GetState() const {
return this->state;
}
void Signal();
void Reset();
void Wait();
bool TryWait();
bool TimedWait(u64 ns);
};
}

View file

@ -0,0 +1,110 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "os_common_types.hpp"
#include "os_memory_common.hpp"
namespace ams::os {
class Thread {
NON_COPYABLE(Thread);
NON_MOVEABLE(Thread);
private:
::Thread thr;
public:
constexpr Thread() : thr{} { /* ... */ }
Result Initialize(ThreadFunc entry, void *arg, void *stack_mem, size_t stack_sz, int prio, int cpuid = -2) {
return threadCreate(&this->thr, entry, arg, stack_mem, stack_sz, prio, cpuid);
}
Result Initialize(ThreadFunc entry, void *arg, size_t stack_sz, int prio, int cpuid = -2) {
return threadCreate(&this->thr, entry, arg, nullptr, stack_sz, prio, cpuid);
}
Handle GetHandle() const {
return this->thr.handle;
}
Result Start() {
return threadStart(&this->thr);
}
Result Wait() {
return threadWaitForExit(&this->thr);
}
Result Join() {
R_TRY(threadWaitForExit(&this->thr));
R_TRY(threadClose(&this->thr));
return ResultSuccess();
}
Result CancelSynchronization() {
return svcCancelSynchronization(this->thr.handle);
}
};
template<size_t StackSize>
class StaticThread {
NON_COPYABLE(StaticThread);
NON_MOVEABLE(StaticThread);
static_assert(util::IsAligned(StackSize, os::MemoryPageSize), "StaticThread must have aligned resource size");
private:
alignas(os::MemoryPageSize) u8 stack_mem[StackSize];
::Thread thr;
public:
constexpr StaticThread() : stack_mem{}, thr{} { /* ... */ }
constexpr StaticThread(ThreadFunc entry, void *arg, int prio, int cpuid = -2) : StaticThread() {
R_ASSERT(this->Initialize(entry, arg, prio, cpuid));
}
Result Initialize(ThreadFunc entry, void *arg, int prio, int cpuid = -2) {
return threadCreate(&this->thr, entry, arg, this->stack_mem, StackSize, prio, cpuid);
}
Handle GetHandle() const {
return this->thr.handle;
}
Result Start() {
return threadStart(&this->thr);
}
Result Wait() {
return threadWaitForExit(&this->thr);
}
Result Join() {
R_TRY(threadWaitForExit(&this->thr));
R_TRY(threadClose(&this->thr));
return ResultSuccess();
}
Result CancelSynchronization() {
return svcCancelSynchronization(this->thr.handle);
}
};
NX_INLINE u32 GetCurrentThreadPriority() {
u32 prio;
R_ASSERT(svcGetThreadPriority(&prio, CUR_THREAD_HANDLE));
return prio;
}
}

View file

@ -0,0 +1,63 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "os_common_types.hpp"
namespace ams::os {
class TimeoutHelper {
private:
u64 end_tick;
public:
TimeoutHelper(u64 ns) {
/* Special case zero-time timeouts. */
if (ns == 0) {
end_tick = 0;
return;
}
u64 cur_tick = armGetSystemTick();
this->end_tick = cur_tick + NsToTick(ns) + 1;
}
static constexpr inline u64 NsToTick(u64 ns) {
return (ns * 12) / 625;
}
static constexpr inline u64 TickToNs(u64 tick) {
return (tick * 625) / 12;
}
inline bool TimedOut() const {
if (this->end_tick == 0) {
return true;
}
return armGetSystemTick() >= this->end_tick;
}
inline u64 NsUntilTimeout() const {
u64 diff = TickToNs(this->end_tick - armGetSystemTick());
if (this->TimedOut()) {
return 0;
}
return diff;
}
};
}

View file

@ -0,0 +1,67 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "os_common_types.hpp"
namespace ams::os {
class WaitableManager;
class Event;
class SystemEvent;
class InterruptEvent;
class Thread;
class MessageQueue;
class Semaphore;
namespace impl {
class WaitableHolderImpl;
}
class WaitableHolder {
friend class WaitableManager;
NON_COPYABLE(WaitableHolder);
NON_MOVEABLE(WaitableHolder);
private:
util::TypedStorage<impl::WaitableHolderImpl, 2 * sizeof(util::IntrusiveListNode) + 3 * sizeof(void *), alignof(void *)> impl_storage;
uintptr_t user_data;
public:
static constexpr size_t ImplStorageSize = sizeof(impl_storage);
public:
WaitableHolder(Handle handle);
WaitableHolder(Event *event);
WaitableHolder(SystemEvent *event);
WaitableHolder(InterruptEvent *event);
WaitableHolder(Thread *thread);
WaitableHolder(Semaphore *semaphore);
WaitableHolder(MessageQueue *message_queue, MessageQueueWaitKind wait_kind);
~WaitableHolder();
void SetUserData(uintptr_t data) {
this->user_data = data;
}
uintptr_t GetUserData() const {
return this->user_data;
}
void UnlinkFromWaitableManager();
};
}

View file

@ -0,0 +1,51 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "os_mutex.hpp"
namespace ams::os {
class WaitableHolder;
namespace impl {
class WaitableManagerImpl;
}
class WaitableManager {
NON_COPYABLE(WaitableManager);
NON_MOVEABLE(WaitableManager);
private:
util::TypedStorage<impl::WaitableManagerImpl, sizeof(util::IntrusiveListNode) + sizeof(Mutex) + 2 * sizeof(void *) + sizeof(Handle), alignof(void *)> impl_storage;
public:
static constexpr size_t ImplStorageSize = sizeof(impl_storage);
public:
WaitableManager();
~WaitableManager();
/* Wait. */
WaitableHolder *WaitAny();
WaitableHolder *TryWaitAny();
WaitableHolder *TimedWaitAny(u64 timeout);
/* Link. */
void LinkWaitableHolder(WaitableHolder *holder);
void UnlinkAll();
void MoveAllFrom(WaitableManager *other);
};
}

View file

@ -0,0 +1,19 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "patcher/patcher_api.hpp"

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "../ro/ro_types.hpp"
namespace ams::patcher {
/* Helper for applying to code binaries. */
void LocateAndApplyIpsPatchesToModule(const char *patch_dir, size_t protected_size, size_t offset, const ro::ModuleId *module_id, u8 *mapped_module, size_t mapped_size);
}

Some files were not shown because too many files have changed in this diff Show more