mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-27 17:11:00 +01:00
git subrepo clone https://github.com/Atmosphere-NX/Atmosphere-libs libraries
subrepo: subdir: "libraries" merged: "07af583b" upstream: origin: "https://github.com/Atmosphere-NX/Atmosphere-libs" branch: "master" commit: "07af583b" git-subrepo: version: "0.4.0" origin: "https://github.com/ingydotnet/git-subrepo" commit: "5d6aba9"
This commit is contained in:
parent
28717bfd27
commit
0105455086
74
libraries/.gitignore
vendored
Normal file
74
libraries/.gitignore
vendored
Normal 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
0
libraries/.gitmodules
vendored
Normal file
12
libraries/.gitrepo
Normal file
12
libraries/.gitrepo
Normal 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
339
libraries/LICENSE
Normal 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
10
libraries/Makefile
Normal 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
30
libraries/README.md
Normal 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.
|
11
libraries/config/arch/arm64/arch.mk
Normal file
11
libraries/config/arch/arm64/arch.mk
Normal 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 +=
|
5
libraries/config/board/nintendo/switch/board.mk
Normal file
5
libraries/config/board/nintendo/switch/board.mk
Normal 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 +=
|
74
libraries/config/common.mk
Normal file
74
libraries/config/common.mk
Normal 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
|
5
libraries/config/os/horizon/os.mk
Normal file
5
libraries/config/os/horizon/os.mk
Normal file
@ -0,0 +1,5 @@
|
||||
export ATMOSPHERE_DEFINES += -DATMOSPHERE_OS_HORIZON
|
||||
export ATMOSPHERE_SETTINGS +=
|
||||
export ATMOSPHERE_CFLAGS +=
|
||||
export ATMOSPHERE_CXXFLAGS +=
|
||||
export ATMOSPHERE_ASFLAGS +=
|
52
libraries/config/templates/stratosphere.mk
Normal file
52
libraries/config/templates/stratosphere.mk
Normal 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
|
140
libraries/libstratosphere/Makefile
Normal file
140
libraries/libstratosphere/Makefile
Normal 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
|
||||
#---------------------------------------------------------------------------------------
|
||||
|
31
libraries/libstratosphere/README.md
Normal file
31
libraries/libstratosphere/README.md
Normal 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__
|
58
libraries/libstratosphere/include/stratosphere.hpp
Normal file
58
libraries/libstratosphere/include/stratosphere.hpp
Normal 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"
|
22
libraries/libstratosphere/include/stratosphere/ams.hpp
Normal file
22
libraries/libstratosphere/include/stratosphere/ams.hpp
Normal 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"
|
@ -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();
|
||||
|
||||
}
|
@ -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);
|
||||
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
120
libraries/libstratosphere/include/stratosphere/ams/ams_types.hpp
Normal file
120
libraries/libstratosphere/include/stratosphere/ams/ams_types.hpp
Normal 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
|
||||
|
||||
}
|
19
libraries/libstratosphere/include/stratosphere/boot2.hpp
Normal file
19
libraries/libstratosphere/include/stratosphere/boot2.hpp
Normal 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"
|
@ -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();
|
||||
|
||||
}
|
19
libraries/libstratosphere/include/stratosphere/cfg.hpp
Normal file
19
libraries/libstratosphere/include/stratosphere/cfg.hpp
Normal 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"
|
@ -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();
|
||||
|
||||
}
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
20
libraries/libstratosphere/include/stratosphere/dd.hpp
Normal file
20
libraries/libstratosphere/include/stratosphere/dd.hpp
Normal 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"
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
|
||||
}
|
19
libraries/libstratosphere/include/stratosphere/dmnt.hpp
Normal file
19
libraries/libstratosphere/include/stratosphere/dmnt.hpp
Normal 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"
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
19
libraries/libstratosphere/include/stratosphere/fatal.hpp
Normal file
19
libraries/libstratosphere/include/stratosphere/fatal.hpp
Normal 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"
|
@ -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));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
28
libraries/libstratosphere/include/stratosphere/fs.hpp
Normal file
28
libraries/libstratosphere/include/stratosphere/fs.hpp
Normal 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"
|
@ -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;
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -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));
|
||||
|
||||
}
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -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,
|
||||
};
|
||||
|
||||
}
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
@ -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);
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -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));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -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();
|
||||
};
|
||||
};
|
||||
|
||||
}
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
19
libraries/libstratosphere/include/stratosphere/fssrv.hpp
Normal file
19
libraries/libstratosphere/include/stratosphere/fssrv.hpp
Normal 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"
|
@ -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"
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -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),
|
||||
};
|
||||
};
|
||||
|
||||
}
|
@ -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),
|
||||
};
|
||||
};
|
||||
|
||||
}
|
22
libraries/libstratosphere/include/stratosphere/fssystem.hpp
Normal file
22
libraries/libstratosphere/include/stratosphere/fssystem.hpp
Normal 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"
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
19
libraries/libstratosphere/include/stratosphere/hid.hpp
Normal file
19
libraries/libstratosphere/include/stratosphere/hid.hpp
Normal 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"
|
@ -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);
|
||||
|
||||
}
|
20
libraries/libstratosphere/include/stratosphere/hos.hpp
Normal file
20
libraries/libstratosphere/include/stratosphere/hos.hpp
Normal 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"
|
@ -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,
|
||||
};
|
||||
|
||||
}
|
@ -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();
|
||||
|
||||
}
|
24
libraries/libstratosphere/include/stratosphere/kvdb.hpp
Normal file
24
libraries/libstratosphere/include/stratosphere/kvdb.hpp
Normal 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"
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
};
|
||||
}
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -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));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
20
libraries/libstratosphere/include/stratosphere/ldr.hpp
Normal file
20
libraries/libstratosphere/include/stratosphere/ldr.hpp
Normal 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"
|
@ -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);
|
||||
|
||||
}
|
242
libraries/libstratosphere/include/stratosphere/ldr/ldr_types.hpp
Normal file
242
libraries/libstratosphere/include/stratosphere/ldr/ldr_types.hpp
Normal 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!");
|
||||
|
||||
}
|
20
libraries/libstratosphere/include/stratosphere/map.hpp
Normal file
20
libraries/libstratosphere/include/stratosphere/map.hpp
Normal 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"
|
@ -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);
|
||||
|
||||
}
|
122
libraries/libstratosphere/include/stratosphere/map/map_types.hpp
Normal file
122
libraries/libstratosphere/include/stratosphere/map/map_types.hpp
Normal 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;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
19
libraries/libstratosphere/include/stratosphere/ncm.hpp
Normal file
19
libraries/libstratosphere/include/stratosphere/ncm.hpp
Normal 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"
|
447
libraries/libstratosphere/include/stratosphere/ncm/ncm_types.hpp
Normal file
447
libraries/libstratosphere/include/stratosphere/ncm/ncm_types.hpp
Normal 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");
|
||||
|
||||
}
|
34
libraries/libstratosphere/include/stratosphere/os.hpp
Normal file
34
libraries/libstratosphere/include/stratosphere/os.hpp
Normal 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"
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
101
libraries/libstratosphere/include/stratosphere/os/os_mutex.hpp
Normal file
101
libraries/libstratosphere/include/stratosphere/os/os_mutex.hpp
Normal 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();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
110
libraries/libstratosphere/include/stratosphere/os/os_thread.hpp
Normal file
110
libraries/libstratosphere/include/stratosphere/os/os_thread.hpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -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();
|
||||
};
|
||||
|
||||
}
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
19
libraries/libstratosphere/include/stratosphere/patcher.hpp
Normal file
19
libraries/libstratosphere/include/stratosphere/patcher.hpp
Normal 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"
|
@ -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
Loading…
Reference in New Issue
Block a user