Compare commits

..

42 Commits

Author SHA1 Message Date
Michael Scire
79d7e9197c dmnt: revise per WerWolv's feedback. 2020-04-16 23:16:33 -07:00
Michael Scire
11b8a92458 dmnt: implement break/continue, static reg commands 2020-04-16 21:16:55 -07:00
Michael Scire
332dbdd497 git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "c1fe12fc"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "c1fe12fc"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2020-04-16 20:06:20 -07:00
SciresM
98cc051387 pgl: Reimplement the pgl sysmodule (#896)
* pgl: add skeleton folder to stratosphere

* pgl: Add service interface for IShellInterface

* pgl: begin skeletoning shell service, implement two commands.

* pgl: Implement three more commands.

* pgl: implement bool tracking commands

* pgl: Implement TriggerApplicationSnapShotDumper

* pgl: implement InitializeProcessControlTask

* pgl: Implement pgl::srv::Initialize

* pgl: Implement main()

* pgl: Implement (Get)ShellEventObserver

* pgl: implement LaunchProgramFromHost, GetHostContentMetaInfo

* pgl: Implement ProcessControlTask

* settings: fix duplicate object name

* pgl: fix minor bugs in impl
2020-04-16 19:55:47 -07:00
Michael Scire
f2944d36ba kern: amend syntax 2020-04-16 18:00:42 -07:00
Michael Scire
46d79387e8 mesosphere: implement KMemoryBlockManager::UpdateLock 2020-04-16 17:58:51 -07:00
Michael Scire
0bb2c0a04f licensing: update exemptions (approved by contributors). 2020-04-16 17:33:04 -07:00
Michael Scire
eca2b453ae pgl: update with client C++ bindings 2020-04-15 20:07:20 -07:00
Michael Scire
e14dc18bd3 pgl: skeleton api 2020-04-15 17:37:11 -07:00
Michael Scire
c7743c6098 git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "96825c75"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "96825c75"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2020-04-15 11:55:50 -07:00
Michael Scire
d81a3bdc36 bump version to 0.11.1 2020-04-15 01:34:35 -07:00
Michael Scire
32e5283ac2 bump version to 0.11.1 2020-04-15 01:30:12 -07:00
Michael Scire
1d9a4f47fd exosphere: set cpuactlr to guarantee it holds non reset value 2020-04-15 01:26:28 -07:00
Michael Scire
3f5f9b60ea exosphere: ... 2020-04-15 00:14:36 -07:00
Michael Scire
08e1b4d116 docs: fix partial changelog 2020-04-14 14:12:57 -07:00
Michael Scire
683580861f docs: add changelog for 0.11.0 2020-04-14 13:54:17 -07:00
Michael Scire
7d30460214 exosphere: fix reentrancy of se interrupt handler 2020-04-14 12:23:08 -07:00
Michael Scire
d7ba3291ed git subrepo push emummc
subrepo:
  subdir:   "emummc"
  merged:   "b168ddf5"
upstream:
  origin:   "https://github.com/m4xw/emuMMC"
  branch:   "develop"
  commit:   "b168ddf5"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2020-04-14 11:17:12 -07:00
Michael Scire
c07f54f370 emummc: fix for svcQueryIoMapping abi change 2020-04-14 11:15:19 -07:00
Michael Scire
6fe8ada37a ncm/build dist: minor fixes 2020-04-14 10:20:27 -07:00
Michael Scire
94b10b5779 ams: fix boot sysmodule/kernel for 10.0.0 2020-04-14 10:11:58 -07:00
Michael Scire
9b677c81a5 fusee: support passing target firmware to kernel loader. 2020-04-14 10:11:58 -07:00
Adubbz
a25be61e94 ncm: update to 10.0.0 (#879) 2020-04-14 10:11:51 -07:00
Michael Scire
116e00c21c kernel_ldr: update to support 10.0.0 2020-04-14 07:38:01 -07:00
Michael Scire
122b0775f1 git subrepo clone --force --branch=develop https://github.com/m4xw/emummc
subrepo:
  subdir:   "emummc"
  merged:   "f35ce000"
upstream:
  origin:   "https://github.com/m4xw/emummc"
  branch:   "develop"
  commit:   "f35ce000"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2020-04-14 04:49:43 -07:00
Michael Scire
11f840b1e3 creport: update for 10.0.0 2020-04-14 04:48:57 -07:00
Michael Scire
36039ddbb7 git subrepo push emummc
subrepo:
  subdir:   "emummc"
  merged:   "9dd60229"
upstream:
  origin:   "https://github.com/m4xw/emuMMC"
  branch:   "develop"
  commit:   "9dd60229"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2020-04-14 04:35:26 -07:00
Michael Scire
5347f0d583 emummc: add support for 10.0.0 2020-04-14 04:34:35 -07:00
Michael Scire
408dde533f emummc: lie to git subrepo 2020-04-14 04:34:15 -07:00
Michael Scire
b15b46a68e fusee: identify 10.x fs kip 2020-04-14 03:45:11 -07:00
Michael Scire
ba6f298618 fs: add nogc patches for 10.0.0 2020-04-14 03:41:03 -07:00
Michael Scire
c6424921a6 10.0.0 + a new sysmodule reimplementation probably merits 0.11.0 2020-04-14 03:34:35 -07:00
Michael Scire
8547802904 boot2: update for 10.0.0 2020-04-14 03:30:03 -07:00
Michael Scire
353e27b9e2 ldr: update 10.0.0 conditionals 2020-04-14 03:20:23 -07:00
Michael Scire
4a38a36036 exo: fix c/p error 2020-04-14 03:03:04 -07:00
Michael Scire
200d2df785 pm: Update to support 10.0.0 2020-04-14 02:54:55 -07:00
Michael Scire
73552c86c3 loader: update for 10.0.0 2020-04-14 02:45:28 -07:00
Michael Scire
dd80e1f463 loader: update anti-downgrade tables for 10.0.0 2020-04-13 23:44:01 -07:00
Michael Scire
15c929a0e4 fusee: add support for 10.0.0 2020-04-13 23:35:52 -07:00
Michael Scire
aa4c79cd9c exosphere: update to support 10.0.0 2020-04-13 23:30:54 -07:00
Michael Scire
6719abec65 hos::Version: rename enum members 2020-04-13 22:19:44 -07:00
SciresM
79b9e07ee9 erpt: reimplement the sysmodule (#875)
* erpt: reimplement the sysmodule

* fatal: update for latest bindings

* erpt: amend logic for culling orphan attachments
2020-04-13 17:07:37 -07:00
220 changed files with 5353 additions and 756 deletions

View File

@@ -58,6 +58,7 @@ dist-no-debug: all
mkdir atmosphere-$(AMSVER)/switch
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000008
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/010000000000000D
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/010000000000002B
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000032
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000034
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000036
@@ -82,6 +83,7 @@ dist-no-debug: all
cp -r config_templates/hbl_html atmosphere-$(AMSVER)/atmosphere/hbl_html
cp stratosphere/boot2/boot2.nsp atmosphere-$(AMSVER)/atmosphere/contents/0100000000000008/exefs.nsp
cp stratosphere/dmnt/dmnt.nsp atmosphere-$(AMSVER)/atmosphere/contents/010000000000000D/exefs.nsp
cp stratosphere/erpt/erpt.nsp atmosphere-$(AMSVER)/atmosphere/contents/010000000000002B/exefs.nsp
cp stratosphere/eclct.stub/eclct.stub.nsp atmosphere-$(AMSVER)/atmosphere/contents/0100000000000032/exefs.nsp
cp stratosphere/fatal/fatal.nsp atmosphere-$(AMSVER)/atmosphere/contents/0100000000000034/exefs.nsp
cp stratosphere/creport/creport.nsp atmosphere-$(AMSVER)/atmosphere/contents/0100000000000036/exefs.nsp
@@ -133,6 +135,7 @@ dist: dist-no-debug
cp stratosphere/ro/ro.elf atmosphere-$(AMSVER)-debug/ro.elf
cp stratosphere/sm/sm.elf atmosphere-$(AMSVER)-debug/sm.elf
cp stratosphere/spl/spl.elf atmosphere-$(AMSVER)-debug/spl.elf
cp stratosphere/erpt/erpt.elf atmosphere-$(AMSVER)-debug/erpt.elf
cd atmosphere-$(AMSVER)-debug; zip -r ../atmosphere-$(AMSVER)-debug.zip ./*; cd ../;
rm -r atmosphere-$(AMSVER)-debug
mv atmosphere-$(AMSVER)-debug.zip out/atmosphere-$(AMSVER)-debug.zip

View File

@@ -27,7 +27,7 @@ This software is licensed under the terms of the GPLv2, with exemptions for spec
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 Atmosphère project as GPLv2 or later.
* The [yuzu Nintendo Switch emulator](https://github.com/yuzu-emu/yuzu) and the [Ryujinx Team and Contributors](https://github.com/orgs/Ryujinx) are exempt from GPLv2 licensing. They are permitted, each at their individual discretion, to instead license any source code authored for the Atmosphère project as either GPLv2 or later or the [MIT license](https://github.com/Atmosphere-NX/Atmosphere/blob/master/docs/licensing_exemptions/MIT_LICENSE). In doing so, they may alter, supplement, or entirely remove the copyright notice for each file they choose to relicense. Neither the Atmosphère project nor its individual contributors shall assert their moral rights against any of the aforementioned projects.
* [Nintendo](https://github.com/Nintendo) is exempt from GPLv2 licensing and may (at its option) instead license any source code authored for the Atmosphère project under the Zero-Clause BSD license.
Credits

View File

@@ -1,4 +1,34 @@
# Changelog
## 0.11.1
+ A bug was fixed that could cause owls to flicker under certain circumstances.
+ For those interested in technical details, in 10.0.0 kernelldr/kernel no longer set cpuactlr_el1, assuming that it was set correctly by the secure monitor.
+ However, exosphere did not set cpuactlr_el1. This meant that the register held the reset value going into boot.
+ This caused a variety of highly erratic symptoms, including causing basically any game to crash seemingly randomly.
+ A number of other major inaccuracies in exosphere were corrected.
+ General system stability improvements to enhance the user's experience.
## 0.11.0
+ Support was added for 10.0.0.
+ Exosphere has been updated to reflect the new key import semantics in 10.0.0.
+ kernel_ldr now implements physical ASLR for the kernel's backing pages.
+ Loader, NCM, and PM have been updated to reflect the changes Nintendo made in 10.0.0.
+ Creport was updated to use the new `pgl` service to terminate processes instead of `ns:dev`.
+ A reimplementation of the `erpt` (error reports) system module was added.
+ In previous versions of Atmosphere, a majority of error reports were prevented via a combination of custom creport, fatal, and stubbed eclct.
+ However, error reports were still generated via some system actions.
+ Most notably, any time the error applet appeared, an error report was generated.
+ By default, atmosphere disabled the *uploading* of error reports, but going online in OFW after an error report occurred in Atmosphere could lead to undesirable telemetry.
+ Atmosphere's `erpt` reimplementation allows the system to interact with existing error reports as expected.
+ However, all new error reports are instead saved to the sd card (`/atmosphere/erpt_reports`), and are not committed to the system savegame.
+ Users curious about what kind of telemetry is being prevented can view the reports as they're generated in there.
+ Reports are saved as msgpack (as this is what Nintendo uses).
+ Please note, not all telemetry is disabled. Play reports and System reports will continue to function unmodified.
+ With atmosphere's `erpt` implementation, homebrew can now use the native error applet to display errors without worrying about generating undesirable telemetry.
+ libstratosphere and libvapours received a number of improvements.
+ With thanks to @Adubbz for his work, the NCM namespace now has client code.
+ This lays the groundwork for first-class system update/downgrade homebrew support in the near future.
+ In particular, code implementing the os namespace is significantly more accurate.
+ In addition, Nintendo's allocators were implemented, allowing for identical memory efficiency versus Nintendo's implementations.
+ General system stability improvements to enhance the user's experience.
## 0.10.5
+ Changes were made to the way fs.mitm builds images when providing a layeredfs romfs.
+ Building romfs metadata previously had a memory cost of about ~4-5x the file table size.

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018-2020 Atmosphère-NX
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -6,7 +6,7 @@
[subrepo]
remote = https://github.com/m4xw/emuMMC
branch = develop
commit = d12dd5464422029a1e5601916517ec3f1c81d8d0
parent = 259a1a7513236a1de4d373bc6cb99032ede2c626
commit = b168ddf5fbb31013ff529a4859110c82b11eb361
parent = c07f54f3709a4710e0aead6c91139fa0893b5e5c
method = rebase
cmdver = 0.4.1

View File

@@ -2,7 +2,7 @@
*A SDMMC driver replacement for Nintendo's Filesystem Services, by **m4xw***
### Supported Horizon Versions
**1.0.0 - 9.1.0**
**1.0.0 - 10.0.0**
## Features
* Arbitrary SDMMC backend selection

View File

@@ -45,6 +45,8 @@
#include "offsets/900_exfat.h"
#include "offsets/910.h"
#include "offsets/910_exfat.h"
#include "offsets/1000.h"
#include "offsets/1000_exfat.h"
#include "../utils/fatal.h"
#define GET_OFFSET_STRUCT_NAME(vers) g_offsets##vers
@@ -100,6 +102,8 @@ DEFINE_OFFSET_STRUCT(_900);
DEFINE_OFFSET_STRUCT(_900_EXFAT);
DEFINE_OFFSET_STRUCT(_910);
DEFINE_OFFSET_STRUCT(_910_EXFAT);
DEFINE_OFFSET_STRUCT(_1000);
DEFINE_OFFSET_STRUCT(_1000_EXFAT);
const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
switch (version) {
@@ -161,6 +165,10 @@ const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
return &(GET_OFFSET_STRUCT_NAME(_910));
case FS_VER_9_1_0_EXFAT:
return &(GET_OFFSET_STRUCT_NAME(_910_EXFAT));
case FS_VER_10_0_0:
return &(GET_OFFSET_STRUCT_NAME(_1000));
case FS_VER_10_0_0_EXFAT:
return &(GET_OFFSET_STRUCT_NAME(_1000_EXFAT));
default:
fatal_abort(Fatal_UnknownVersion);
}

View File

@@ -65,6 +65,9 @@ enum FS_VER
FS_VER_9_1_0,
FS_VER_9_1_0_EXFAT,
FS_VER_10_0_0,
FS_VER_10_0_0_EXFAT,
FS_VER_MAX,
};

View File

@@ -0,0 +1,58 @@
/*
* Copyright (c) 2019 m4xw <m4x@m4xw.net>
* Copyright (c) 2019 Atmosphere-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __FS_1000_H__
#define __FS_1000_H__
// Accessor vtable getters
#define FS_OFFSET_1000_SDMMC_ACCESSOR_GC 0x14DC90
#define FS_OFFSET_1000_SDMMC_ACCESSOR_SD 0x14BDA0
#define FS_OFFSET_1000_SDMMC_ACCESSOR_NAND 0x146C20
// Hooks
#define FS_OFFSET_1000_SDMMC_WRAPPER_READ 0x142380
#define FS_OFFSET_1000_SDMMC_WRAPPER_WRITE 0x142460
#define FS_OFFSET_1000_RTLD 0x634
#define FS_OFFSET_1000_RTLD_DESTINATION 0x9C
#define FS_OFFSET_1000_CLKRST_SET_MIN_V_CLK_RATE 0x1415A0
// Misc funcs
#define FS_OFFSET_1000_LOCK_MUTEX 0x28910
#define FS_OFFSET_1000_UNLOCK_MUTEX 0x28960
#define FS_OFFSET_1000_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1422E0
// Misc Data
#define FS_OFFSET_1000_SD_MUTEX 0xE273E8
#define FS_OFFSET_1000_NAND_MUTEX 0xE22DA0
#define FS_OFFSET_1000_ACTIVE_PARTITION 0xE22DE0
#define FS_OFFSET_1000_SDMMC_DAS_HANDLE 0xE0AB90
// NOPs
#define FS_OFFSET_1000_SD_DAS_INIT 0x151CEC
// Nintendo Paths
#define FS_OFFSET_1000_NINTENDO_PATHS \
{ \
{.opcode_reg = 3, .adrp_offset = 0x0006BBA4, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 3, .adrp_offset = 0x00078520, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 3, .adrp_offset = 0x0007ED0C, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x0009115C, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
}
#endif // __FS_1000_H__

View File

@@ -0,0 +1,58 @@
/*
* Copyright (c) 2019 m4xw <m4x@m4xw.net>
* Copyright (c) 2019 Atmosphere-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __FS_1000_EXFAT_H__
#define __FS_1000_EXFAT_H__
// Accessor vtable getters
#define FS_OFFSET_1000_EXFAT_SDMMC_ACCESSOR_GC 0x14DC90
#define FS_OFFSET_1000_EXFAT_SDMMC_ACCESSOR_SD 0x14BDA0
#define FS_OFFSET_1000_EXFAT_SDMMC_ACCESSOR_NAND 0x146C20
// Hooks
#define FS_OFFSET_1000_EXFAT_SDMMC_WRAPPER_READ 0x142380
#define FS_OFFSET_1000_EXFAT_SDMMC_WRAPPER_WRITE 0x142460
#define FS_OFFSET_1000_EXFAT_RTLD 0x634
#define FS_OFFSET_1000_EXFAT_RTLD_DESTINATION 0x9C
#define FS_OFFSET_1000_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1415A0
// Misc funcs
#define FS_OFFSET_1000_EXFAT_LOCK_MUTEX 0x28910
#define FS_OFFSET_1000_EXFAT_UNLOCK_MUTEX 0x28960
#define FS_OFFSET_1000_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1422E0
// Misc Data
#define FS_OFFSET_1000_EXFAT_SD_MUTEX 0xE353E8
#define FS_OFFSET_1000_EXFAT_NAND_MUTEX 0xE30DA0
#define FS_OFFSET_1000_EXFAT_ACTIVE_PARTITION 0xE30DE0
#define FS_OFFSET_1000_EXFAT_SDMMC_DAS_HANDLE 0xE18B90
// NOPs
#define FS_OFFSET_1000_EXFAT_SD_DAS_INIT 0x151CEC
// Nintendo Paths
#define FS_OFFSET_1000_EXFAT_NINTENDO_PATHS \
{ \
{.opcode_reg = 3, .adrp_offset = 0x0006BBA4, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 3, .adrp_offset = 0x00078520, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 3, .adrp_offset = 0x0007ED0C, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 4, .adrp_offset = 0x0009115C, .add_rel_offset = 0x00000004}, \
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
}
#endif // __FS_1000_EXFAT_H__

View File

@@ -36,7 +36,6 @@ sdmmc_storage_t sd_storage;
// init vars
bool custom_driver = true;
extern const volatile emuMMC_ctx_t emuMMC_ctx;
// FS funcs
_sdmmc_accessor_gc sdmmc_accessor_gc;
@@ -344,7 +343,7 @@ uint64_t sdmmc_wrapper_controller_close(int mmc_id)
{
return 0;
}
if (mmc_id == FS_SDMMC_EMMC)
{
// Close file handles and unmount

View File

@@ -50,8 +50,18 @@ extern "C" {
* @return Result code.
* @note Syscall number 0x55.
* @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available.
* @warning Only exists on [10.0.0+]. For older versions use \ref svcLegacyQueryIoMapping.
*/
Result svcQueryIoMapping(u64* virtaddr, u64 physaddr, u64 size);
Result svcQueryIoMapping(u64* virtaddr, u64* out_size, u64 physaddr, u64 size);
/**
* @brief Returns a virtual address mapped to a given IO range.
* @return Result code.
* @note Syscall number 0x55.
* @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available.
* @warning Only exists on [1.0.0-9.2.0]. For newer versions use \ref svcQueryIoMapping.
*/
Result svcLegacyQueryIoMapping(u64* virtaddr, u64 physaddr, u64 size);
/**
* @brief Attaches a device address space to a device.

View File

@@ -17,6 +17,15 @@
.endm
SVC_BEGIN svcQueryIoMapping
STP X0, X1, [SP, #-16]!
SVC 0x55
LDP X3, X4, [SP], #16
STR X1, [X3]
STR X2, [X4]
RET
SVC_END
SVC_BEGIN svcLegacyQueryIoMapping
STR X0, [SP, #-16]!
SVC 0x55
LDR X2, [SP], #16

View File

@@ -25,11 +25,12 @@ enum FatalReason
Fatal_InvalidAccessor,
Fatal_ReadNoAccessor,
Fatal_WriteNoAccessor,
Fatal_IoMapping,
Fatal_IoMappingLegacy,
Fatal_UnknownVersion,
Fatal_BadResult,
Fatal_GetConfig,
Fatal_CloseAccessor,
Fatal_IoMapping,
Fatal_Max
};

View File

@@ -38,8 +38,15 @@ static inline uintptr_t _GetIoMapping(u64 io_addr, u64 io_size)
u64 vaddr;
u64 aligned_addr = (io_addr & ~0xFFFul);
u64 aligned_size = io_size + (io_addr - aligned_addr);
if (svcQueryIoMapping(&vaddr, aligned_addr, aligned_size) != 0) {
fatal_abort(Fatal_IoMapping);
if (emuMMC_ctx.fs_ver >= FS_VER_10_0_0) {
u64 out_size;
if (svcQueryIoMapping(&vaddr, &out_size, aligned_addr, aligned_size) != 0) {
fatal_abort(Fatal_IoMapping);
}
} else {
if (svcLegacyQueryIoMapping(&vaddr, aligned_addr, aligned_size) != 0) {
fatal_abort(Fatal_IoMappingLegacy);
}
}
return (uintptr_t)(vaddr + (io_addr - aligned_addr));
}

View File

@@ -19,6 +19,7 @@
#define _UTIL_H_
#include "types.h"
#include "../emuMMC/emummc_ctx.h"
intptr_t QueryIoMapping(u64 addr, u64 size);
#define byte_swap_32(num) ((num >> 24) & 0xff) | ((num << 8) & 0xff0000) | \
@@ -37,4 +38,6 @@ void usleep(u64 ticks);
void msleep(u64 milliseconds);
void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops);
extern volatile emuMMC_ctx_t emuMMC_ctx;
#endif

View File

@@ -263,19 +263,20 @@ uint32_t fuse_get_5x_key_generation(void) {
/* Returns the fuse version expected for the firmware. */
uint32_t fuse_get_expected_fuse_version(uint32_t target_firmware) {
static const uint8_t expected_versions[ATMOSPHERE_TARGET_FIRMWARE_COUNT+1] = {
[ATMOSPHERE_TARGET_FIRMWARE_100] = 1,
[ATMOSPHERE_TARGET_FIRMWARE_200] = 2,
[ATMOSPHERE_TARGET_FIRMWARE_300] = 3,
/* [ATMOSPHERE_TARGET_FIRMWARE_302] = 4, */
[ATMOSPHERE_TARGET_FIRMWARE_400] = 5,
[ATMOSPHERE_TARGET_FIRMWARE_500] = 6,
[ATMOSPHERE_TARGET_FIRMWARE_600] = 7,
[ATMOSPHERE_TARGET_FIRMWARE_620] = 8,
[ATMOSPHERE_TARGET_FIRMWARE_700] = 9,
[ATMOSPHERE_TARGET_FIRMWARE_800] = 9,
[ATMOSPHERE_TARGET_FIRMWARE_810] = 10,
[ATMOSPHERE_TARGET_FIRMWARE_900] = 11,
[ATMOSPHERE_TARGET_FIRMWARE_910] = 12,
[ATMOSPHERE_TARGET_FIRMWARE_100] = 1,
[ATMOSPHERE_TARGET_FIRMWARE_200] = 2,
[ATMOSPHERE_TARGET_FIRMWARE_300] = 3,
/* [ATMOSPHERE_TARGET_FIRMWARE_302] = 4, */
[ATMOSPHERE_TARGET_FIRMWARE_400] = 5,
[ATMOSPHERE_TARGET_FIRMWARE_500] = 6,
[ATMOSPHERE_TARGET_FIRMWARE_600] = 7,
[ATMOSPHERE_TARGET_FIRMWARE_620] = 8,
[ATMOSPHERE_TARGET_FIRMWARE_700] = 9,
[ATMOSPHERE_TARGET_FIRMWARE_800] = 9,
[ATMOSPHERE_TARGET_FIRMWARE_810] = 10,
[ATMOSPHERE_TARGET_FIRMWARE_900] = 11,
[ATMOSPHERE_TARGET_FIRMWARE_910] = 12,
[ATMOSPHERE_TARGET_FIRMWARE_1000] = 13,
};
if (target_firmware > ATMOSPHERE_TARGET_FIRMWARE_COUNT) {

32
exosphere/src/mc0.h Normal file
View File

@@ -0,0 +1,32 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef EXOSPHERE_MC0_H
#define EXOSPHERE_MC0_H
#include <stdint.h>
#include "memory_map.h"
/* Exosphere driver for the Tegra X1 MC0. */
static inline uintptr_t get_mc0_base(void) {
return MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_MC0);
}
#define MC0_BASE (get_mc0_base())
#define MAKE_MC0_REG(n) MAKE_REG32(MC0_BASE + n)
#endif

32
exosphere/src/mc1.h Normal file
View File

@@ -0,0 +1,32 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef EXOSPHERE_MC0_H
#define EXOSPHERE_MC0_H
#include <stdint.h>
#include "memory_map.h"
/* Exosphere driver for the Tegra X1 MC1. */
static inline uintptr_t get_mc1_base(void) {
return MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_MC1);
}
#define MC1_BASE (get_mc1_base())
#define MAKE_MC1_REG(n) MAKE_REG32(MC1_BASE + n)
#endif

View File

@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef EXOSPHERE_MEMORY_MAP_H
#define EXOSPHERE_MEMORY_MAP_H
@@ -48,9 +48,11 @@
#define _MMAPDEV15 ( 0x6000D000ull, 0x1000ull, true ) /* GPIO-1 - GPIO-8 */
#define _MMAPDEV16 ( 0x7000C000ull, 0x1000ull, true ) /* I2C-I2C4 */
#define _MMAPDEV17 ( 0x6000F000ull, 0x1000ull, true ) /* Exception vectors */
#define _MMAPDEV18 ( 0x00000000ull, 0x1000ull, true ) /* AMS irampage, NOT mapped at startup */
#define _MMAPDEV19 ( 0x00000000ull, 0x1000ull, true ) /* AMS userpage, NOT mapped at startup */
#define _MMAPDEV20 ( 0x40038000ull, 0x5000ull, true ) /* DEBUG: IRAM */
#define _MMAPDEV18 ( 0x7001C000ull, 0x1000ull, true ) /* MC0 */
#define _MMAPDEV19 ( 0x7001D000ull, 0x1000ull, true ) /* MC1 */
#define _MMAPDEV20 ( 0x00000000ull, 0x1000ull, true ) /* AMS irampage, NOT mapped at startup */
#define _MMAPDEV21 ( 0x00000000ull, 0x1000ull, true ) /* AMS userpage, NOT mapped at startup */
#define _MMAPDEV22 ( 0x40038000ull, 0x1000ull, true ) /* DEBUG: IRAM */
/* MMIO 7.0.0+. (addr). */
#define _MMAPDEV7X0 ( 0x50041000ull ) /* ARM Interrupt Distributor */
@@ -71,9 +73,11 @@
#define _MMAPDEV7X15 ( 0x6000D000ull ) /* GPIO-1 - GPIO-8 */
#define _MMAPDEV7X16 ( 0x7000C000ull ) /* I2C-I2C4 */
#define _MMAPDEV7X17 ( 0x6000F000ull ) /* Exception vectors */
#define _MMAPDEV7X18 ( 0x00000000ull ) /* AMS irampage, NOT mapped at startup */
#define _MMAPDEV7X19 ( 0x00000000ull ) /* AMS userpage, NOT mapped at startup */
#define _MMAPDEV7X20 ( 0x40038000ull ) /* DEBUG: IRAM */
#define _MMAPDEV7X18 ( 0x7001C000ull ) /* MC0 */
#define _MMAPDEV7X19 ( 0x7001D000ull ) /* MC1 */
#define _MMAPDEV7X20 ( 0x00000000ull ) /* AMS irampage, NOT mapped at startup */
#define _MMAPDEV7X21 ( 0x00000000ull ) /* AMS userpage, NOT mapped at startup */
#define _MMAPDEV7X22 ( 0x40038000ull ) /* DEBUG: IRAM */
/* LP0 entry ram segments (addr, size, additional attributes) */
#define _MMAPLP0ES0 ( 0x40020000ull, 0x10000ull, MMU_PTE_BLOCK_NS | ATTRIB_MEMTYPE_DEVICE ) /* Encrypted TZRAM */
@@ -133,10 +137,12 @@
#define MMIO_DEVID_GPIO 15
#define MMIO_DEVID_DTV_I2C234 16
#define MMIO_DEVID_EXCEPTION_VECTORS 17
#define MMIO_DEVID_AMS_IRAM_PAGE 18
#define MMIO_DEVID_AMS_USER_PAGE 19
#define MMIO_DEVID_DEBUG_IRAM 20
#define MMIO_DEVID_MAX 21
#define MMIO_DEVID_MC0 18
#define MMIO_DEVID_MC1 19
#define MMIO_DEVID_AMS_IRAM_PAGE 20
#define MMIO_DEVID_AMS_USER_PAGE 21
#define MMIO_DEVID_DEBUG_IRAM 22
#define MMIO_DEVID_MAX 23
#define LP0_ENTRY_RAM_SEGMENT_ID_ENCRYPTED_TZRAM 0
#define LP0_ENTRY_RAM_SEGMENT_ID_LP0_ENTRY_CODE 1

View File

@@ -149,6 +149,7 @@ static void setup_se(void) {
case ATMOSPHERE_TARGET_FIRMWARE_810:
case ATMOSPHERE_TARGET_FIRMWARE_900:
case ATMOSPHERE_TARGET_FIRMWARE_910:
case ATMOSPHERE_TARGET_FIRMWARE_1000:
derive_new_device_keys(KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY);
break;
}
@@ -338,7 +339,7 @@ static bool validate_package2_metadata(package2_meta_t *metadata) {
/* Perform version checks. */
/* We will be compatible with all package2s released before current, but not newer ones. */
if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_910_CURRENT) {
if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_1000_CURRENT) {
return true;
}
@@ -466,6 +467,7 @@ static void copy_warmboot_bin_to_dram() {
case ATMOSPHERE_TARGET_FIRMWARE_810:
case ATMOSPHERE_TARGET_FIRMWARE_900:
case ATMOSPHERE_TARGET_FIRMWARE_910:
case ATMOSPHERE_TARGET_FIRMWARE_1000:
warmboot_src = (uint8_t *)0x4003E000;
break;
}
@@ -551,6 +553,9 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
case ATMOSPHERE_TARGET_FIRMWARE_910:
MAKE_REG32(PMC_BASE + 0x360) = 0x18C;
break;
case ATMOSPHERE_TARGET_FIRMWARE_1000:
MAKE_REG32(PMC_BASE + 0x360) = 0x1AD;
break;
}
}

View File

@@ -73,7 +73,8 @@ static inline uintptr_t get_nx_bootloader_mailbox_base(unsigned int targetfw) {
#define PACKAGE2_MAXVER_700_800 0xA
#define PACKAGE2_MAXVER_810 0xB
#define PACKAGE2_MAXVER_900 0xC
#define PACKAGE2_MAXVER_910_CURRENT 0xD
#define PACKAGE2_MAXVER_910_920 0xD
#define PACKAGE2_MAXVER_1000_CURRENT 0xE
#define PACKAGE2_MINVER_100 0x3
#define PACKAGE2_MINVER_200 0x4
@@ -86,7 +87,8 @@ static inline uintptr_t get_nx_bootloader_mailbox_base(unsigned int targetfw) {
#define PACKAGE2_MINVER_700_800 0xB
#define PACKAGE2_MINVER_810 0xC
#define PACKAGE2_MINVER_900 0xD
#define PACKAGE2_MINVER_910_CURRENT 0xE
#define PACKAGE2_MINVER_910_920 0xE
#define PACKAGE2_MINVER_1000_CURRENT 0xF
typedef struct {
union {

View File

@@ -0,0 +1,20 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 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 "rsa_common.h"
/* Instantiate the shared RSA data inside a single translation unit. */
rsa_shared_data_t g_rsa_shared_data = {};

View File

@@ -0,0 +1,36 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef EXOSPHERE_RSA_COMMON_H
#define EXOSPHERE_RSA_COMMON_H
#include <stdint.h>
typedef union {
struct {
uint8_t user_data[0x100];
} storage_exp_mod;
struct {
uint32_t master_key_rev;
uint32_t type;
uint64_t expected_label_hash[4];
} unwrap_titlekey;
} rsa_shared_data_t __attribute__((aligned(4)));
_Static_assert(sizeof(rsa_shared_data_t) == 0x100);
extern rsa_shared_data_t g_rsa_shared_data;
#endif

View File

@@ -13,7 +13,7 @@
* 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 <string.h>
#include "utils.h"
@@ -47,24 +47,25 @@ void ll_init(volatile se_ll_t *ll, void *buffer, size_t size) {
ll->addr_info.address = 0;
ll->addr_info.size = 0;
}
flush_dcache_range((uint8_t *)ll, (uint8_t *)ll + sizeof(*ll));
}
void set_security_engine_callback(unsigned int (*callback)(void)) {
if (callback == NULL || g_se_callback != NULL) {
generic_panic();
}
/* Set the callback. */
g_se_callback = callback;
/* Enable SE Interrupt firing for async op. */
se_get_regs()->SE_INT_ENABLE = 0x10;
}
/* Fires on Security Engine operation completion. */
void se_operation_completed(void) {
se_get_regs()->SE_INT_ENABLE = 0;
if (g_se_callback != NULL) {
g_se_callback();
unsigned int (*callback)(void) = g_se_callback;
if (callback != NULL) {
g_se_callback = NULL;
callback();
}
}
@@ -103,7 +104,7 @@ void se_validate_stored_vector(void) {
uint8_t calc_vector[0x10];
se_generate_test_vector(calc_vector);
/* Ensure nobody's messed with the security engine while we slept. */
if (memcmp(calc_vector, g_se_stored_test_vector, 0x10) != 0) {
generic_panic();
@@ -122,7 +123,7 @@ void se_generate_stored_vector(void) {
/* Set the flags for an AES keyslot. */
void set_aes_keyslot_flags(unsigned int keyslot, unsigned int flags) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX) {
generic_panic();
}
@@ -141,7 +142,7 @@ void set_aes_keyslot_flags(unsigned int keyslot, unsigned int flags) {
/* Set the flags for an RSA keyslot. */
void set_rsa_keyslot_flags(unsigned int keyslot, unsigned int flags) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_RSA_MAX) {
generic_panic();
}
@@ -160,7 +161,7 @@ void set_rsa_keyslot_flags(unsigned int keyslot, unsigned int flags) {
void clear_aes_keyslot(unsigned int keyslot) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX) {
generic_panic();
}
@@ -174,7 +175,7 @@ void clear_aes_keyslot(unsigned int keyslot) {
void clear_rsa_keyslot(unsigned int keyslot) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_RSA_MAX) {
generic_panic();
}
@@ -194,7 +195,7 @@ void clear_rsa_keyslot(unsigned int keyslot) {
void set_aes_keyslot(unsigned int keyslot, const void *key, size_t key_size) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX || key_size > KEYSIZE_AES_MAX) {
generic_panic();
}
@@ -207,7 +208,7 @@ void set_aes_keyslot(unsigned int keyslot, const void *key, size_t key_size) {
void set_rsa_keyslot(unsigned int keyslot, const void *modulus, size_t modulus_size, const void *exponent, size_t exp_size) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_RSA_MAX || modulus_size > KEYSIZE_RSA_MAX || exp_size > KEYSIZE_RSA_MAX) {
generic_panic();
}
@@ -228,7 +229,7 @@ void set_rsa_keyslot(unsigned int keyslot, const void *modulus, size_t modulus_
void set_aes_keyslot_iv(unsigned int keyslot, const void *iv, size_t iv_size) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX || iv_size > 0x10) {
generic_panic();
}
@@ -241,7 +242,7 @@ void set_aes_keyslot_iv(unsigned int keyslot, const void *iv, size_t iv_size) {
void clear_aes_keyslot_iv(unsigned int keyslot) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX) {
generic_panic();
}
@@ -260,7 +261,7 @@ void set_se_ctr(const void *ctr) {
void decrypt_data_into_keyslot(unsigned int keyslot_dst, unsigned int keyslot_src, const void *wrapped_key, size_t wrapped_key_size) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot_dst >= KEYSLOT_AES_MAX || keyslot_src >= KEYSIZE_AES_MAX || wrapped_key_size > KEYSIZE_AES_MAX) {
generic_panic();
}
@@ -276,7 +277,7 @@ void decrypt_data_into_keyslot(unsigned int keyslot_dst, unsigned int keyslot_sr
void se_aes_crypt_insecure_internal(unsigned int keyslot, uint32_t out_ll_paddr, uint32_t in_ll_paddr, size_t size, unsigned int crypt_config, bool encrypt, unsigned int (*callback)(void)) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX) {
generic_panic();
}
@@ -304,9 +305,6 @@ void se_aes_crypt_insecure_internal(unsigned int keyslot, uint32_t out_ll_paddr,
/* Set the callback, for after the async operation. */
set_security_engine_callback(callback);
/* Enable SE Interrupt firing for async op. */
se->SE_INT_ENABLE = 0x10;
/* Setup Input/Output lists */
se->SE_IN_LL_ADDR = in_ll_paddr;
se->SE_OUT_LL_ADDR = out_ll_paddr;
@@ -338,7 +336,7 @@ void se_aes_cbc_decrypt_insecure(unsigned int keyslot, uint32_t out_ll_paddr, ui
se_aes_crypt_insecure_internal(keyslot, out_ll_paddr, in_ll_paddr, size, 0x66, false, callback);
}
void se_exp_mod(unsigned int keyslot, void *buf, size_t size, unsigned int (*callback)(void)) {
void se_exp_mod(unsigned int keyslot, const void *buf, size_t size, unsigned int (*callback)(void)) {
volatile tegra_se_t *se = se_get_regs();
uint8_t stack_buf[KEYSIZE_RSA_MAX];
@@ -348,7 +346,7 @@ void se_exp_mod(unsigned int keyslot, void *buf, size_t size, unsigned int (*cal
/* Endian swap the input. */
for (size_t i = 0; i < size; i++) {
stack_buf[i] = *((uint8_t *)buf + size - i - 1);
stack_buf[i] = *((const uint8_t *)buf + size - i - 1);
}
se->SE_CONFIG = (ALG_RSA | DST_RSAREG);
@@ -358,9 +356,6 @@ void se_exp_mod(unsigned int keyslot, void *buf, size_t size, unsigned int (*cal
set_security_engine_callback(callback);
/* Enable SE interrupt firing for async op. */
se->SE_INT_ENABLE = 0x10;
flush_dcache_range(stack_buf, stack_buf + KEYSIZE_RSA_MAX);
trigger_se_rsa_op(stack_buf, size);
@@ -468,7 +463,7 @@ bool se_rsa2048_pss_verify(const void *signature, size_t signature_size, const v
void trigger_se_rsa_op(void *buf, size_t size) {
volatile tegra_se_t *se = se_get_regs();
se_ll_t in_ll;
ll_init(&in_ll, (void *)buf, size);
/* Set the input LL. */
@@ -491,19 +486,19 @@ void trigger_se_blocking_op(unsigned int op, void *dst, size_t dst_size, const v
ll_init(&in_ll, (void *)src, src_size);
ll_init(&out_ll, dst, dst_size);
__dsb_sy();
/* Set the LLs. */
se->SE_IN_LL_ADDR = (uint32_t) get_physical_address(&in_ll);
se->SE_OUT_LL_ADDR = (uint32_t) get_physical_address(&out_ll);
/* Set registers for operation. */
se->SE_ERR_STATUS = se->SE_ERR_STATUS;
se->SE_INT_STATUS = se->SE_INT_STATUS;
se->SE_OPERATION = op;
(void)(se->SE_OPERATION);
__dsb_ish();
while (!(se->SE_INT_STATUS & 0x10)) { /* Wait a while */ }
@@ -538,7 +533,7 @@ void se_perform_aes_block_operation(void *dst, size_t dst_size, const void *src,
void se_aes_ctr_crypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, const void *ctr, size_t ctr_size) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX || ctr_size != 0x10) {
generic_panic();
}
@@ -548,7 +543,7 @@ void se_aes_ctr_crypt(unsigned int keyslot, void *dst, size_t dst_size, const vo
}
if (dst_size) {
flush_dcache_range((uint8_t *)dst, (uint8_t *)dst + dst_size);
}
}
unsigned int num_blocks = src_size >> 4;
@@ -576,12 +571,12 @@ void se_aes_ctr_crypt(unsigned int keyslot, void *dst, size_t dst_size, const vo
if (dst_size) {
flush_dcache_range((uint8_t *)dst, (uint8_t *)dst + dst_size);
}
}
}
void se_aes_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, unsigned int config_high) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX || dst_size != 0x10 || src_size != 0x10) {
generic_panic();
}
@@ -606,7 +601,7 @@ void se_aes_256_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_si
void se_aes_ecb_decrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX || dst_size != 0x10 || src_size != 0x10) {
generic_panic();
}
@@ -632,15 +627,15 @@ void shift_left_xor_rb(uint8_t *key) {
void se_compute_aes_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size, unsigned int config_high) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX) {
generic_panic();
}
if (data_size) {
flush_dcache_range((uint8_t *)data, (uint8_t *)data + data_size);
}
/* Generate the derived key, to be XOR'd with final output block. */
uint8_t derived_key[0x10] = {0};
se_aes_ecb_encrypt_block(keyslot, derived_key, sizeof(derived_key), derived_key, sizeof(derived_key), config_high);
@@ -652,7 +647,7 @@ void se_compute_aes_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, con
se->SE_CONFIG = (ALG_AES_ENC | DST_HASHREG) | (config_high << 16);
se->SE_CRYPTO_CONFIG = (keyslot << 24) | (0x145);
clear_aes_keyslot_iv(keyslot);
unsigned int num_blocks = (data_size + 0xF) >> 4;
/* Handle aligned blocks. */
if (num_blocks > 1) {
@@ -660,7 +655,7 @@ void se_compute_aes_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, con
trigger_se_blocking_op(OP_START, NULL, 0, data, data_size);
se->SE_CRYPTO_CONFIG |= 0x80;
}
/* Create final block. */
uint8_t last_block[0x10] = {0};
if (data_size & 0xF) {
@@ -669,11 +664,11 @@ void se_compute_aes_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, con
} else if (data_size >= 0x10) {
memcpy(last_block, data + data_size - 0x10, 0x10);
}
for (unsigned int i = 0; i < 0x10; i++) {
last_block[i] ^= derived_key[i];
}
/* Perform last operation. */
se->SE_CRYPTO_LAST_BLOCK = 0;
flush_dcache_range(last_block, last_block + sizeof(last_block));
@@ -694,11 +689,11 @@ void se_compute_aes_256_cmac(unsigned int keyslot, void *cmac, size_t cmac_size,
void se_aes_256_cbc_encrypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, const void *iv) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX || src_size < 0x10) {
generic_panic();
}
se->SE_CONFIG = (ALG_AES_ENC | DST_MEMORY) | (0x202 << 16);
se->SE_CRYPTO_CONFIG = (keyslot << 24) | 0x144;
set_aes_keyslot_iv(keyslot, iv, 0x10);
@@ -709,7 +704,7 @@ void se_aes_256_cbc_encrypt(unsigned int keyslot, void *dst, size_t dst_size, co
/* SHA256 Implementation. */
void se_calculate_sha256(void *dst, const void *src, size_t src_size) {
volatile tegra_se_t *se = se_get_regs();
/* Setup config for SHA256, size = BITS(src_size) */
se->SE_CONFIG = (ENCMODE_SHA256 | ALG_SHA | DST_HASHREG);
se->SE_SHA_CONFIG = 1;
@@ -721,7 +716,7 @@ void se_calculate_sha256(void *dst, const void *src, size_t src_size) {
se->SE_SHA_MSG_LEFT[1] = 0;
se->SE_SHA_MSG_LEFT[2] = 0;
se->SE_SHA_MSG_LEFT[3] = 0;
/* Trigger the operation. */
trigger_se_blocking_op(OP_START, NULL, 0, src, src_size);
@@ -734,7 +729,7 @@ void se_calculate_sha256(void *dst, const void *src, size_t src_size) {
/* RNG API */
void se_initialize_rng(unsigned int keyslot) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX) {
generic_panic();
}
@@ -754,7 +749,7 @@ void se_initialize_rng(unsigned int keyslot) {
void se_generate_random(unsigned int keyslot, void *dst, size_t size) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX) {
generic_panic();
}
@@ -777,7 +772,7 @@ void se_generate_random(unsigned int keyslot, void *dst, size_t size) {
/* SE context save API. */
void se_set_in_context_save_mode(bool is_context_save_mode) {
volatile tegra_se_t *se = se_get_regs();
uint32_t val = se->SE_SE_SECURITY;
if (is_context_save_mode) {
val |= 0x10000;
@@ -791,7 +786,7 @@ void se_set_in_context_save_mode(bool is_context_save_mode) {
void se_generate_random_key(unsigned int dst_keyslot, unsigned int rng_keyslot) {
volatile tegra_se_t *se = se_get_regs();
if (dst_keyslot >= KEYSLOT_AES_MAX || rng_keyslot >= KEYSLOT_AES_MAX) {
generic_panic();
}
@@ -801,7 +796,7 @@ void se_generate_random_key(unsigned int dst_keyslot, unsigned int rng_keyslot)
se->SE_CRYPTO_CONFIG = (rng_keyslot << 24) | 0x108;
se->SE_RNG_CONFIG = 4;
se->SE_CRYPTO_LAST_BLOCK = 0;
/* Generate low part of key. */
se->SE_CRYPTO_KEYTABLE_DST = (dst_keyslot << 8);
trigger_se_blocking_op(OP_START, NULL, 0, NULL, 0);
@@ -812,7 +807,7 @@ void se_generate_random_key(unsigned int dst_keyslot, unsigned int rng_keyslot)
void se_generate_srk(unsigned int srkgen_keyslot) {
volatile tegra_se_t *se = se_get_regs();
se->SE_CONFIG = (ALG_RNG | DST_SRK);
se->SE_CRYPTO_CONFIG = (srkgen_keyslot << 24) | 0x108;
se->SE_RNG_CONFIG = 6;
@@ -847,24 +842,24 @@ void se_save_context(unsigned int srkgen_keyslot, unsigned int rng_keyslot, void
/* Generate the SRK (context save encryption key). */
se_generate_random_key(srkgen_keyslot, rng_keyslot);
se_generate_srk(srkgen_keyslot);
flush_dcache_range(work_buf, work_buf + 0x10);
se_generate_random(rng_keyslot, work_buf, 0x10);
flush_dcache_range(work_buf, work_buf + 0x10);
/* Save random initial block. */
se->SE_CONFIG = (ALG_AES_ENC | DST_MEMORY);
se->SE_CTX_SAVE_CONFIG = (CTX_SAVE_SRC_MEM);
se->SE_CRYPTO_LAST_BLOCK = 0;
se_encrypt_with_srk(dst, 0x10, work_buf, 0x10);
/* Save Sticky Bits. */
for (unsigned int i = 0; i < 0x2; i++) {
se->SE_CTX_SAVE_CONFIG = (CTX_SAVE_SRC_STICKY_BITS) | (i << CTX_SAVE_STICKY_BIT_INDEX_SHIFT);
se->SE_CRYPTO_LAST_BLOCK = 0;
se_encrypt_with_srk(dst + 0x10 + (i * 0x10), 0x10, NULL, 0);
}
/* Save AES Key Table. */
for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) {
se->SE_CTX_SAVE_CONFIG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_LOW_BITS);
@@ -874,21 +869,21 @@ void se_save_context(unsigned int srkgen_keyslot, unsigned int rng_keyslot, void
se->SE_CRYPTO_LAST_BLOCK = 0;
se_encrypt_with_srk(dst + 0x40 + (i * 0x20), 0x10, NULL, 0);
}
/* Save AES Original IVs. */
for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) {
se->SE_CTX_SAVE_CONFIG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_ORIGINAL_IV);
se->SE_CRYPTO_LAST_BLOCK = 0;
se_encrypt_with_srk(dst + 0x230 + (i * 0x10), 0x10, NULL, 0);
}
/* Save AES Updated IVs */
for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) {
se->SE_CTX_SAVE_CONFIG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_UPDATED_IV);
se->SE_CRYPTO_LAST_BLOCK = 0;
se_encrypt_with_srk(dst + 0x330 + (i * 0x10), 0x10, NULL, 0);
}
/* Save RSA Keytable. */
uint8_t *rsa_ctx_out = (uint8_t *)dst + 0x430;
for (unsigned int rsa_key = 0; rsa_key < KEYSLOT_RSA_MAX; rsa_key++) {
@@ -901,13 +896,13 @@ void se_save_context(unsigned int srkgen_keyslot, unsigned int rng_keyslot, void
}
}
}
/* Save "Known Pattern. " */
static const uint8_t context_save_known_pattern[0x10] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
se->SE_CTX_SAVE_CONFIG = (CTX_SAVE_SRC_MEM);
se->SE_CRYPTO_LAST_BLOCK = 0;
se_encrypt_with_srk(dst + 0x830, 0x10, context_save_known_pattern, 0x10);
/* Save SRK into PMC registers. */
se->SE_CTX_SAVE_CONFIG = (CTX_SAVE_SRC_SRK);
se->SE_CRYPTO_LAST_BLOCK = 0;

View File

@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef EXOSPHERE_SE_H
#define EXOSPHERE_SE_H
@@ -213,7 +213,7 @@ void se_aes_256_cbc_encrypt(unsigned int keyslot, void *dst, size_t dst_size, co
void se_calculate_sha256(void *dst, const void *src, size_t src_size);
/* RSA API */
void se_exp_mod(unsigned int keyslot, void *buf, size_t size, unsigned int (*callback)(void));
void se_exp_mod(unsigned int keyslot, const void *buf, size_t size, unsigned int (*callback)(void));
void se_get_exp_mod_output(void *buf, size_t size);
void se_synchronous_exp_mod(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size);
bool se_rsa2048_pss_verify(const void *signature, size_t signature_size, const void *modulus, size_t modulus_size, const void *data, size_t data_size);

View File

@@ -25,6 +25,8 @@
#include "synchronization.h"
#include "masterkey.h"
#include "mc.h"
#include "mc0.h"
#include "mc1.h"
#include "memory_map.h"
#include "pmc.h"
#include "randomcache.h"
@@ -188,6 +190,7 @@ void set_version_specific_smcs(void) {
case ATMOSPHERE_TARGET_FIRMWARE_810:
case ATMOSPHERE_TARGET_FIRMWARE_900:
case ATMOSPHERE_TARGET_FIRMWARE_910:
case ATMOSPHERE_TARGET_FIRMWARE_1000:
/* No more LoadSecureExpModKey. */
g_smc_user_table[0xE].handler = NULL;
g_smc_user_table[0xC].id = 0xC300D60C;
@@ -433,19 +436,18 @@ uint32_t smc_get_result(smc_args_t *args) {
}
uint32_t smc_exp_mod_get_result(void *buf, uint64_t size) {
if (get_exp_mod_done() != 1) {
return 3;
uint32_t res = get_exp_mod_result();
if (res == 0) {
if (size == 0x100) {
se_get_exp_mod_output(buf, 0x100);
/* smc_exp_mod is done now. */
clear_user_smc_in_progress();
res = 0;
} else {
res = 2;
}
}
if (size != 0x100) {
return 2;
}
se_get_exp_mod_output(buf, 0x100);
/* smc_exp_mod is done now. */
clear_user_smc_in_progress();
return 0;
return res;
}
uint32_t smc_exp_mod(smc_args_t *args) {
@@ -508,30 +510,31 @@ uint32_t smc_unwrap_rsa_oaep_wrapped_titlekey_get_result(void *buf, uint64_t siz
uint8_t aes_wrapped_titlekey[0x10];
uint8_t titlekey[0x10];
uint64_t sealed_titlekey[2];
if (get_exp_mod_done() != 1) {
return 3;
uint32_t res = get_exp_mod_result();
if (res == 0) {
if (size == 0x10) {
se_get_exp_mod_output(rsa_wrapped_titlekey, 0x100);
if (tkey_rsa_oaep_unwrap(aes_wrapped_titlekey, 0x10, rsa_wrapped_titlekey, 0x100) == 0x10) {
tkey_aes_unwrap(titlekey, 0x10, aes_wrapped_titlekey, 0x10);
seal_titlekey(sealed_titlekey, 0x10, titlekey, 0x10);
p_sealed_key[0] = sealed_titlekey[0];
p_sealed_key[1] = sealed_titlekey[1];
res = 0;
} else {
/* Failed to extract RSA OAEP wrapped key. */
res = 2;
}
/* smc_unwrap_rsa_oaep_wrapped_titlekey is done now. */
clear_user_smc_in_progress();
} else {
res = 2;
}
}
if (size != 0x10) {
return 2;
}
se_get_exp_mod_output(rsa_wrapped_titlekey, 0x100);
if (tkey_rsa_oaep_unwrap(aes_wrapped_titlekey, 0x10, rsa_wrapped_titlekey, 0x100) != 0x10) {
/* Failed to extract RSA OAEP wrapped key. */
clear_user_smc_in_progress();
return 2;
}
tkey_aes_unwrap(titlekey, 0x10, aes_wrapped_titlekey, 0x10);
seal_titlekey(sealed_titlekey, 0x10, titlekey, 0x10);
p_sealed_key[0] = sealed_titlekey[0];
p_sealed_key[1] = sealed_titlekey[1];
/* smc_unwrap_rsa_oaep_wrapped_titlekey is done now. */
clear_user_smc_in_progress();
return 0;
return res;
}
uint32_t smc_unwrap_rsa_oaep_wrapped_titlekey(smc_args_t *args) {
@@ -616,7 +619,7 @@ uint32_t smc_read_write_register(smc_args_t *args) {
}
/* Check for PMC registers. */
if (0x7000E400 <= address && address <= 0x7000EFFF) {
const uint8_t pmc_whitelist[0x28] = {
static const uint8_t pmc_whitelist[0x28] = {
0xB9, 0xF9, 0x07, 0x00, 0x00, 0x00, 0x80, 0x03,
0x00, 0x00, 0x00, 0x17, 0x00, 0xC4, 0x07, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x00,
@@ -632,39 +635,83 @@ uint32_t smc_read_write_register(smc_args_t *args) {
} else {
return 2;
}
} else if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400 && MMIO_GET_DEVICE_PA(MMIO_DEVID_MC) <= address &&
address < MMIO_GET_DEVICE_PA(MMIO_DEVID_MC) + MMIO_GET_DEVICE_SIZE(MMIO_DEVID_MC)) {
/* Memory Controller RW supported only on 4.0.0+ */
const uint8_t mc_whitelist[0x68] = {
0x9F, 0x31, 0x30, 0x00, 0xF0, 0xFF, 0xF7, 0x01,
0xCD, 0xFE, 0xC0, 0xFE, 0x00, 0x00, 0x00, 0x00,
0x03, 0x40, 0x73, 0x3E, 0x2F, 0x00, 0x00, 0x6E,
0x30, 0x05, 0x06, 0xB0, 0x71, 0xC8, 0x43, 0x04,
0x80, 0x1F, 0x08, 0x80, 0x03, 0x00, 0x0E, 0x00,
0x08, 0x00, 0xE0, 0x00, 0x0E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x30, 0xF0, 0x03, 0x03, 0x30,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x31, 0x00, 0x40, 0x00, 0x00,
0x00, 0x03, 0x00, 0x00, 0xE4, 0xFF, 0xFF, 0x01,
0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0xFE, 0x0F,
0x01, 0x00, 0x80, 0x00, 0x00, 0x08, 0x00, 0x00
};
uint32_t offset = (uint32_t)(address - 0x70019000);
uint32_t wl_ind = (offset >> 5);
/* If address is whitelisted, allow write. */
if (wl_ind < sizeof(mc_whitelist) && (mc_whitelist[wl_ind] & (1 << ((offset >> 2) & 0x7)))) {
p_mmio = (volatile uint32_t *)(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_MC) + offset);
} else {
/* These addresses are not allowed by the whitelist. */
/* They correspond to SMMU DISABLE for the BPMP, and for APB-DMA. */
/* However, smcReadWriteRegister returns 0 for these addresses despite not actually performing the write. */
/* This is "probably" to fuck with hackers who got access to smcReadWriteRegister and are trying to get */
/* control of the BPMP for jamais vu etc., since there's no other reason to return 0 despite failure. */
if (address == 0x7001923C || address == 0x70019298) {
return 0;
} else {
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_500) {
static const uint8_t mc_whitelist_5x[0xD00/(sizeof(uint32_t) * 8)] = {
0x9F, 0x31, 0x30, 0x00, 0xF0, 0xFF, 0xF7, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x40, 0x73, 0x3E, 0x2F, 0x00, 0x00, 0x6E,
0x30, 0x05, 0x06, 0xB0, 0x71, 0xC8, 0x43, 0x04,
0x80, 0xFF, 0x08, 0x80, 0x03, 0x38, 0x8E, 0x1F,
0xC8, 0xFF, 0xFF, 0x00, 0x0E, 0x00, 0x00, 0x00,
0xF0, 0x1F, 0x00, 0x30, 0xF0, 0x03, 0x03, 0x30,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x31, 0x00, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xE4, 0xFF, 0xFF, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x0F,
0x01, 0x00, 0x80, 0x00, 0x00, 0x08, 0x00, 0x00
};
static const uint8_t mc01_whitelist_5x[0xC00/(sizeof(uint32_t) * 8)] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xCD, 0xFE, 0xC0, 0xFE, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x06, 0x00,
};
static const struct {
uint32_t phys_addr;
uint32_t size;
uint64_t virt_addr;
const uint8_t *whitelist;
} register_whitelists[3] = {
{ MMIO_GET_DEVICE_PA(MMIO_DEVID_MC), sizeof(mc_whitelist_5x) * (sizeof(uint32_t) * 8), MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_MC), mc_whitelist_5x },
{ MMIO_GET_DEVICE_PA(MMIO_DEVID_MC0), sizeof(mc01_whitelist_5x) * (sizeof(uint32_t) * 8), MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_MC0), mc01_whitelist_5x },
{ MMIO_GET_DEVICE_PA(MMIO_DEVID_MC1), sizeof(mc01_whitelist_5x) * (sizeof(uint32_t) * 8), MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_MC1), mc01_whitelist_5x },
};
for (unsigned int which = 0; which < 3; which++) {
if (register_whitelists[which].phys_addr <= address && address < register_whitelists[which].phys_addr + register_whitelists[which].size) {
uint32_t offset = (uint32_t)(address - register_whitelists[which].phys_addr);
uint32_t wl_ind = (offset >> 5);
/* If address is whitelisted, allow write. */
if (register_whitelists[which].whitelist[wl_ind] & (1 << ((offset >> 2) & 0x7))) {
p_mmio = (volatile uint32_t *)(register_whitelists[which].virt_addr + offset);
}
break;
}
}
} else if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) {
if (MMIO_GET_DEVICE_PA(MMIO_DEVID_MC) <= address && address < MMIO_GET_DEVICE_PA(MMIO_DEVID_MC) + 0xD00) {
/* Memory Controller RW supported only on 4.0.0+ */
static const uint8_t mc_whitelist[0x68] = {
0x9F, 0x31, 0x30, 0x00, 0xF0, 0xFF, 0xF7, 0x01,
0xCD, 0xFE, 0xC0, 0xFE, 0x00, 0x00, 0x00, 0x00,
0x03, 0x40, 0x73, 0x3E, 0x2F, 0x00, 0x00, 0x6E,
0x30, 0x05, 0x06, 0xB0, 0x71, 0xC8, 0x43, 0x04,
0x80, 0x1F, 0x08, 0x80, 0x03, 0x00, 0x0E, 0x00,
0x08, 0x00, 0xE0, 0x00, 0x0E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x30, 0xF0, 0x03, 0x03, 0x30,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x31, 0x00, 0x40, 0x00, 0x00,
0x00, 0x03, 0x00, 0x00, 0xE4, 0xFF, 0xFF, 0x01,
0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0xFE, 0x0F,
0x01, 0x00, 0x80, 0x00, 0x00, 0x08, 0x00, 0x00
};
uint32_t offset = (uint32_t)(address - MMIO_GET_DEVICE_PA(MMIO_DEVID_MC));
uint32_t wl_ind = (offset >> 5);
/* If address is whitelisted, allow write. */
if (mc_whitelist[wl_ind] & (1 << ((offset >> 2) & 0x7))) {
p_mmio = (volatile uint32_t *)(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_MC) + offset);
}
}
return 2;
}
}
@@ -683,9 +730,16 @@ uint32_t smc_read_write_register(smc_args_t *args) {
/* Return old value. */
args->X[1] = old_value;
return 0;
} else if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400 && (address == 0x7001923C || address == 0x70019298)) {
/* These addresses are not allowed by the whitelist. */
/* They correspond to SMMU DISABLE for the BPMP, and for APB-DMA. */
/* However, smcReadWriteRegister returns 0 for these addresses despite not actually performing the write. */
/* This is "probably" to fuck with hackers who got access to smcReadWriteRegister and are trying to get */
/* control of the BPMP for jamais vu etc., since there's no other reason to return 0 despite failure. */
return 0;
} else {
return 2;
}
return 2;
}

View File

@@ -34,12 +34,93 @@
/* Globals. */
static bool g_crypt_aes_done = false;
static bool g_exp_mod_done = false;
static uint32_t g_exp_mod_result = 0;
static uint8_t g_imported_exponents[4][0x100];
static __attribute__((aligned(4))) uint8_t g_imported_exponents[4][0x100];
static __attribute__((aligned(4))) uint8_t g_imported_moduli[4][0x100];
static bool g_is_modulus_verified[4];
static __attribute__((aligned(4))) const uint8_t g_rsa_public_key[4] = { 0x00, 0x01, 0x00, 0x01 };
static __attribute__((aligned(4))) const uint8_t g_rsa_test_vector[0x100] = {
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D'
};
static uint32_t g_test_exp_mod_keyslot = 0;
static uint32_t g_test_exp_mod_usecase = 0;
static bool g_test_exp_mod_in_progress = false;
static uint8_t g_rsausecase_to_cryptousecase[5] = {1, 2, 3, 5, 6};
static void import_rsa_exponent(unsigned int which, const uint8_t *exponent, uint64_t size) {
g_is_modulus_verified[which] = false;
for (unsigned int i = 0; i < 0x100; i++) {
g_imported_exponents[which][i] = exponent[i];
g_imported_moduli[which][i] = 0;
}
}
static void import_rsa_modulus(unsigned int which, const uint8_t *modulus, uint64_t size) {
uint64_t clamped_size = 0x100;
if (size <= 0x100) {
clamped_size = size;
}
if (clamped_size != 0) {
/* The official secure monitor implements this via bit-fiddling, */
/* and to prevent accidental inaccuracy we will too. */
/* It's probably done to prevent errors on negative sizes. */
uint64_t remaining = 0x100;
if (size != 0x100 && (~size >= ~0xFFFFFFFFFFFFFEFFULL)) {
remaining = size;
}
memcpy(&g_imported_moduli[which][0], modulus, remaining);
}
}
static bool load_imported_rsa_keypair(unsigned int keyslot, unsigned int which) {
if (!g_is_modulus_verified[which]) {
return false;
}
set_rsa_keyslot(keyslot, g_imported_moduli[which], 0x100, g_imported_exponents[which], 0x100);
return true;
}
static void test_rsa_modulus_public(unsigned int which, unsigned int keyslot, const uint8_t *modulus, uint64_t modulus_size, unsigned int (*callback)(void)) {
import_rsa_modulus(which, modulus, modulus_size);
set_rsa_keyslot(keyslot, modulus, modulus_size, g_rsa_public_key, 0x4);
se_exp_mod(keyslot, g_rsa_test_vector, 0x100, callback);
}
static void test_rsa_modulus_private(unsigned int which, unsigned int keyslot, unsigned int (*callback)(void)) {
uint8_t exponentiated_data[0x100];
se_get_exp_mod_output(exponentiated_data, sizeof(exponentiated_data));
set_rsa_keyslot(keyslot, g_imported_moduli[which], 0x100, g_imported_exponents[which], 0x100);
se_exp_mod(keyslot, exponentiated_data, 0x100, callback);
}
static void validate_rsa_result(unsigned int which) {
char result[0x100];
se_get_exp_mod_output(result, sizeof(result));
if (memcmp(result, g_rsa_test_vector, sizeof(result)) == 0) {
g_is_modulus_verified[which] = true;
}
}
static bool is_user_keyslot_valid(unsigned int keyslot) {
switch (exosphere_get_target_firmware()) {
case ATMOSPHERE_TARGET_FIRMWARE_100:
@@ -55,27 +136,45 @@ static bool is_user_keyslot_valid(unsigned int keyslot) {
case ATMOSPHERE_TARGET_FIRMWARE_810:
case ATMOSPHERE_TARGET_FIRMWARE_900:
case ATMOSPHERE_TARGET_FIRMWARE_910:
case ATMOSPHERE_TARGET_FIRMWARE_1000:
default:
return keyslot <= 5;
}
}
void set_exp_mod_done(bool done) {
g_exp_mod_done = done;
void set_exp_mod_result(uint32_t result) {
g_exp_mod_result = result;
}
bool get_exp_mod_done(void) {
return g_exp_mod_done;
uint32_t get_exp_mod_result(void) {
return g_exp_mod_result;
}
uint32_t exp_mod_done_handler(void) {
set_exp_mod_done(true);
set_exp_mod_result(0);
se_trigger_interrupt();
return 0;
}
static uint32_t test_exp_mod_done_handler(void) {
if (g_test_exp_mod_in_progress) {
g_test_exp_mod_in_progress = false;
test_rsa_modulus_private(g_test_exp_mod_usecase, g_test_exp_mod_keyslot, test_exp_mod_done_handler);
} else {
validate_rsa_result(g_test_exp_mod_usecase);
if (load_imported_rsa_keypair(g_test_exp_mod_keyslot, g_test_exp_mod_usecase)) {
se_exp_mod(g_test_exp_mod_keyslot, g_rsa_shared_data.storage_exp_mod.user_data, 0x100, exp_mod_done_handler);
} else {
set_exp_mod_result(2);
se_trigger_interrupt();
}
}
return 0;
}
uint32_t user_exp_mod(smc_args_t *args) {
uint8_t modulus[0x100];
uint8_t exponent[0x100];
@@ -108,7 +207,8 @@ uint32_t user_exp_mod(smc_args_t *args) {
return 2;
}
set_exp_mod_done(false);
set_exp_mod_result(3);
/* Hardcode RSA keyslot 0. */
set_rsa_keyslot(0, modulus, 0x100, exponent, exponent_size);
se_exp_mod(0, input, 0x100, exp_mod_done_handler);
@@ -650,10 +750,21 @@ uint32_t user_secure_exp_mod(smc_args_t *args) {
return 2;
}
set_exp_mod_done(false);
set_exp_mod_result(3);
/* Hardcode RSA keyslot 0. */
set_rsa_keyslot(0, modulus, 0x100, g_imported_exponents[exponent_id], 0x100);
se_exp_mod(0, input, 0x100, exp_mod_done_handler);
if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_1000) {
set_rsa_keyslot(0, modulus, 0x100, g_imported_exponents[exponent_id], 0x100);
se_exp_mod(0, input, 0x100, exp_mod_done_handler);
} else if (load_imported_rsa_keypair(0, exponent_id)) {
se_exp_mod(0, input, 0x100, exp_mod_done_handler);
} else {
memcpy(g_rsa_shared_data.storage_exp_mod.user_data, input, 0x100);
g_test_exp_mod_keyslot = 0;
g_test_exp_mod_usecase = exponent_id;
g_test_exp_mod_in_progress = true;
test_rsa_modulus_public(exponent_id, 0, modulus, 0x100, test_exp_mod_done_handler);
}
return 0;
}
@@ -700,7 +811,7 @@ uint32_t user_unwrap_rsa_oaep_wrapped_titlekey(smc_args_t *args) {
return 2;
}
set_exp_mod_done(false);
set_exp_mod_result(3);
/* Expected label_hash occupies args->X[3] to args->X[6]. */
tkey_set_expected_label_hash(&args->X[3]);
@@ -879,6 +990,7 @@ uint32_t user_decrypt_or_import_rsa_key(smc_args_t *args) {
}
unsigned int exponent_id;
bool import_modulus;
switch (usecase) {
case 0:
@@ -888,22 +1000,33 @@ uint32_t user_decrypt_or_import_rsa_key(smc_args_t *args) {
return 0;
case 1:
exponent_id = 1;
import_modulus = false;
break;
case 2:
exponent_id = 0;
import_modulus = true;
break;
case 3:
exponent_id = 2;
import_modulus = false;
break;
case 4:
exponent_id = 3;
import_modulus = true;
break;
default:
generic_panic();
}
/* Copy key to global. */
memcpy(g_imported_exponents[exponent_id], user_data, 0x100);
/* Modulus import isn't implemented on < 10.0.0. */
import_modulus &= (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_1000);
/* Import the key. */
import_rsa_exponent(exponent_id, user_data, 0x100);
if (import_modulus) {
import_rsa_modulus(exponent_id, user_data + 0x100, 0x100);
g_is_modulus_verified[exponent_id] = true;
}
return 0;
}

View File

@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef EXOSPHERE_SMC_USER_H
#define EXOSPHERE_SMC_USER_H
@@ -41,7 +41,7 @@ uint32_t user_decrypt_or_import_rsa_key(smc_args_t *args);
void set_crypt_aes_done(bool done);
bool get_crypt_aes_done(void);
void set_exp_mod_done(bool done);
bool get_exp_mod_done(void);
void set_exp_mod_result(uint32_t result);
uint32_t get_exp_mod_result(void);
#endif

View File

@@ -13,7 +13,7 @@
* 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 <stdint.h>
#include <string.h>
@@ -25,14 +25,10 @@
#include "masterkey.h"
#include "se.h"
static uint64_t g_tkey_expected_label_hash[4];
static unsigned int g_tkey_master_key_rev = MASTERKEY_REVISION_MAX;
static unsigned int g_tkey_type = 0;
/* Set the expected db prefix. */
void tkey_set_expected_label_hash(uint64_t *label_hash) {
for (unsigned int i = 0; i < 4; i++) {
g_tkey_expected_label_hash[i] = label_hash[i];
g_rsa_shared_data.unwrap_titlekey.expected_label_hash[i] = label_hash[i];
}
}
@@ -40,7 +36,7 @@ void tkey_set_master_key_rev(unsigned int master_key_rev) {
if (master_key_rev >= MASTERKEY_REVISION_MAX) {
generic_panic();
}
g_tkey_master_key_rev = master_key_rev;
g_rsa_shared_data.unwrap_titlekey.master_key_rev = master_key_rev;
}
static void tkey_validate_type(unsigned int type) {
@@ -51,7 +47,7 @@ static void tkey_validate_type(unsigned int type) {
void tkey_set_type(unsigned int type) {
tkey_validate_type(type);
g_tkey_type = type;
g_rsa_shared_data.unwrap_titlekey.type = type;
}
/* Reference for MGF1 can be found here: https://en.wikipedia.org/wiki/Mask_generation_function#MGF1 */
@@ -116,7 +112,7 @@ size_t tkey_rsa_oaep_unwrap(void *dst, size_t dst_size, void *src, size_t src_si
uint8_t *db = message + 0x21;
/* This will be passed to smc_unwrap_rsa_oaep_wrapped_titlekey. */
uint8_t *expected_label_hash = (uint8_t *)(&g_tkey_expected_label_hash[0]);
uint8_t *expected_label_hash = (uint8_t *)(&g_rsa_shared_data.unwrap_titlekey.expected_label_hash[0]);
/* Unmask the salt. */
calculate_mgf1_and_xor(salt, 0x20, db, 0xDF);
@@ -171,13 +167,13 @@ static const uint8_t titlekek_sources[TITLEKEY_TYPE_MAX+1][0x10] = {
};
void tkey_aes_unwrap(void *dst, size_t dst_size, const void *src, size_t src_size) {
if (g_tkey_master_key_rev >= MASTERKEY_REVISION_MAX || dst_size != 0x10 || src_size != 0x10) {
if (g_rsa_shared_data.unwrap_titlekey.master_key_rev >= MASTERKEY_REVISION_MAX || dst_size != 0x10 || src_size != 0x10) {
generic_panic();
}
/* Generate the appropriate titlekek into keyslot 9. */
unsigned int master_keyslot = mkey_get_keyslot(g_tkey_master_key_rev);
decrypt_data_into_keyslot(KEYSLOT_SWITCH_TEMPKEY, master_keyslot, titlekek_sources[g_tkey_type], 0x10);
unsigned int master_keyslot = mkey_get_keyslot(g_rsa_shared_data.unwrap_titlekey.master_key_rev);
decrypt_data_into_keyslot(KEYSLOT_SWITCH_TEMPKEY, master_keyslot, titlekek_sources[g_rsa_shared_data.unwrap_titlekey.type], 0x10);
/* Unwrap the titlekey using the titlekek. */
se_aes_ecb_decrypt_block(KEYSLOT_SWITCH_TEMPKEY, dst, 0x10, src, 0x10);

View File

@@ -13,11 +13,12 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef EXOSPHERE_TITLEKEY_H
#define EXOSPHERE_TITLEKEY_H
#include <stdint.h>
#include "rsa_common.h"
#define TITLEKEY_TYPE_MAX 0x1

View File

@@ -13,7 +13,7 @@
* 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 "utils.h"
#include "memory_map.h"
#include "mc.h"
@@ -65,7 +65,7 @@ void init_dma_controllers(unsigned int target_firmware) {
MAKE_REG32(0x6000C038) = 0x0;
/* MSELECT_CONFIG_0 |= WRAP_TO_INCR_SLAVE0(APC) | WRAP_TO_INCR_SLAVE1(PCIe) | WRAP_TO_INCR_SLAVE2(GPU) */
MAKE_REG32(0x50060000) |= 0x38000000;
MAKE_REG32(0x50060000) = (MAKE_REG32(0x50060000) & 0xC4FFFFFF) | 0x38000000;
/* AHB_ARBITRATION_DISABLE_0 - Disables USB, USB2, and AHB-DMA from arbitration */
MAKE_REG32(0x6000C004) = 0x40060;
@@ -99,7 +99,7 @@ void init_dma_controllers(unsigned int target_firmware) {
MAKE_REG32(0x60020038) = 0;
/* MSELECT_CONFIG_0 |= WRAP_TO_INCR_SLAVE0(APC) | WRAP_TO_INCR_SLAVE1(PCIe) | WRAP_TO_INCR_SLAVE2(GPU) */
MAKE_REG32(0x50060000) |= 0x38000000;
MAKE_REG32(0x50060000) |= (MAKE_REG32(0x50060000) & 0xC4FFFFFF) | 0x38000000;
/* AHB_ARBITRATION_PRIORITY_CTRL_0 - Select high prio group with prio 7 */
MAKE_REG32(0x6000C008) = 0xE0000001;
@@ -111,6 +111,14 @@ void init_dma_controllers(unsigned int target_firmware) {
void _set_memory_registers_enable_mmu(const uintptr_t ttbr0) {
static const uintptr_t vbar = TZRAM_GET_SEGMENT_ADDRESS(TZRAM_SEGEMENT_ID_SECMON_EVT) + 0x800;
/*
- Non-cacheable load forwarding enabled
- Disable load-pass DMB.
- NOTE: This and this alone is done via inline asm, due to register argument limits.
*/
static const uint64_t cpuactlr = 0x800000001000000ull;
__asm__ __volatile__("msr s3_1_c15_c2_0, %0" :: "r"(cpuactlr) : "memory", "cc");
/*
- Disable table walk descriptor access prefetch.
@@ -197,12 +205,12 @@ void warmboot_init(void) {
*/
flush_dcache_all();
invalidate_icache_all();
/* On warmboot (not cpu_on) only */
if (VIRT_MC_SECURITY_CFG3 == 0) {
init_dma_controllers(g_exosphere_target_firmware_for_init);
}
/*identity_remap_tzram();*/
/* Nintendo pointlessly fully invalidate the TLB & invalidate the data cache on the modified ranges here */
if (g_exosphere_target_firmware_for_init < ATMOSPHERE_TARGET_FIRMWARE_500) {

View File

@@ -82,6 +82,9 @@ typedef enum {
FS_VER_9_1_0,
FS_VER_9_1_0_EXFAT,
FS_VER_10_0_0,
FS_VER_10_0_0_EXFAT,
FS_VER_MAX,
} emummc_fs_ver_t;

View File

@@ -417,6 +417,9 @@ static const uint8_t g_fs_hashes[FS_VER_MAX][0x8] = {
"\xB5\xE7\xA6\x4C\x6F\x5C\x4F\xE3", /* FS_VER_9_1_0 */
"\xF1\x96\xD1\x44\xD0\x44\x45\xB6", /* FS_VER_9_1_0_EXFAT */
"\x3E\xEB\xD9\xB7\xBC\xD1\xB5\xE0", /* FS_VER_10_0_0 */
"\x81\x7E\xA2\xB0\xB7\x02\xC1\xF3", /* FS_VER_10_0_0_EXFAT */
};
kip1_header_t *apply_kip_ips_patches(kip1_header_t *kip, size_t kip_size, emummc_fs_ver_t *out_fs_ver) {

View File

@@ -486,20 +486,77 @@ static const instruction_t MAKE_KERNEL_PATCH_NAME(900, proc_id_send)[] = {0xA9BF
static const uint8_t MAKE_KERNEL_PATTERN_NAME(900, proc_id_recv)[] = {0x68, 0x03, 0x40, 0xF9, 0x08, 0x1D, 0x40, 0xF9, 0xE0, 0x03, 0x1B, 0xAA, 0x00, 0x01, 0x3F, 0xD6, 0xE8, 0x03, 0x17, 0x2A, 0xF7, 0x0A, 0x00, 0x11, 0x08, 0xF5, 0x7E, 0xD3};
static const instruction_t MAKE_KERNEL_PATCH_NAME(900, proc_id_recv)[] = {0xA9BF2FEA, 0xF9404BEB, 0x2A1703EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400368, 0xF9401D08, 0xAA1B03E0, 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0};
/*
stp x10, x11, [sp, #-0x10]!
ldr x11, [sp, #0xC0]
mov w10, w22
lsl x10, x10, #2
ldr x10, [x11, x10]
mov x9, #0x0000ffffffffffff
and x8, x10, x9
mov x9, #0xffff000000000000
and x10, x10, x9
mov x9, #0xfffe000000000000
cmp x10, x9
beq #0x20
stp x8, x9, [sp, #-0x10]!
ldr x8, [x23]
ldr x8, [x8, #0x38]
mov x0, x23
blr x8
ldp x8, x9, [sp],#0x10
mov x8, x0
ldp x10, x11, [sp],#0x10
mov x0, x8
*/
static const uint8_t MAKE_KERNEL_PATTERN_NAME(1000, proc_id_send)[] = {0xE8, 0x02, 0x40, 0xF9, 0x08, 0x1D, 0x40, 0xF9, 0xE0, 0x03, 0x17, 0xAA, 0x00, 0x01, 0x3F, 0xD6, 0x08, 0x4B, 0x36, 0x8B, 0x09, 0xFC, 0x60, 0xD3, 0x00, 0x25, 0x00, 0x29};
static const instruction_t MAKE_KERNEL_PATCH_NAME(1000, proc_id_send)[] = {0xA9BF2FEA, 0xF94063EB, 0x2A1603EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF94002E8, 0xF9401D08, 0xAA1703E0, 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0};
/*
stp x10, x11, [sp, #-0x10]!
ldr x11, [sp, #0xC8]
mov w10, w26
lsl x10, x10, #2
ldr x10, [x11, x10]
mov x9, #0x0000ffffffffffff
and x8, x10, x9
mov x9, #0xffff000000000000
and x10, x10, x9
mov x9, #0xfffe000000000000
cmp x10, x9
beq #0x20
stp x8, x9, [sp, #-0x10]!
ldr x8, [x28]
ldr x8, [x8, #0x38]
mov x0, x28
blr x8
ldp x8, x9, [sp],#0x10
mov x8, x0
ldp x10, x11, [sp],#0x10
mov x0, x8
*/
static const uint8_t MAKE_KERNEL_PATTERN_NAME(1000, proc_id_recv)[] = {0x88, 0x03, 0x40, 0xF9, 0x08, 0x1D, 0x40, 0xF9, 0xE0, 0x03, 0x1C, 0xAA, 0x00, 0x01, 0x3F, 0xD6, 0xE8, 0x87, 0x40, 0xF9, 0x08, 0x49, 0x3A, 0x8B, 0x09, 0xFC, 0x60, 0xD3};
static const instruction_t MAKE_KERNEL_PATCH_NAME(1000, proc_id_recv)[] = {0xA9BF2FEA, 0xF94067EB, 0x2A1A03EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400388, 0xF9401D08, 0xAA1C03E0, 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0};
/* svcControlCodeMemory Patches */
/* b.eq -> nop */
static const instruction_t MAKE_KERNEL_PATCH_NAME(500, svc_control_codememory)[] = {MAKE_NOP};
static const instruction_t MAKE_KERNEL_PATCH_NAME(600, svc_control_codememory)[] = {MAKE_NOP};
static const instruction_t MAKE_KERNEL_PATCH_NAME(700, svc_control_codememory)[] = {MAKE_NOP};
static const instruction_t MAKE_KERNEL_PATCH_NAME(800, svc_control_codememory)[] = {MAKE_NOP};
static const instruction_t MAKE_KERNEL_PATCH_NAME(900, svc_control_codememory)[] = {MAKE_NOP};
static const instruction_t MAKE_KERNEL_PATCH_NAME(500, svc_control_codememory)[] = {MAKE_NOP};
static const instruction_t MAKE_KERNEL_PATCH_NAME(600, svc_control_codememory)[] = {MAKE_NOP};
static const instruction_t MAKE_KERNEL_PATCH_NAME(700, svc_control_codememory)[] = {MAKE_NOP};
static const instruction_t MAKE_KERNEL_PATCH_NAME(800, svc_control_codememory)[] = {MAKE_NOP};
static const instruction_t MAKE_KERNEL_PATCH_NAME(900, svc_control_codememory)[] = {MAKE_NOP};
static const instruction_t MAKE_KERNEL_PATCH_NAME(1000, svc_control_codememory)[] = {MAKE_NOP};
static const instruction_t MAKE_KERNEL_PATCH_NAME(500, system_memory_increase)[] = {0x52A3C008}; /* MOV W8, #0x1E000000 */
static const instruction_t MAKE_KERNEL_PATCH_NAME(600, system_memory_increase)[] = {0x52A3B008}; /* MOV W8, #0x1D800000 */
static const instruction_t MAKE_KERNEL_PATCH_NAME(700, system_memory_increase)[] = {0x52A3B008}; /* MOV W8, #0x1D800000 */
static const instruction_t MAKE_KERNEL_PATCH_NAME(800, system_memory_increase)[] = {0x52A3B013}; /* MOV W19, #0x1D800000 */
static const instruction_t MAKE_KERNEL_PATCH_NAME(900, system_memory_increase)[] = {0x52A3B013}; /* MOV W19, #0x1D800000 */
static const instruction_t MAKE_KERNEL_PATCH_NAME(500, system_memory_increase)[] = {0x52A3C008}; /* MOV W8, #0x1E000000 */
static const instruction_t MAKE_KERNEL_PATCH_NAME(600, system_memory_increase)[] = {0x52A3B008}; /* MOV W8, #0x1D800000 */
static const instruction_t MAKE_KERNEL_PATCH_NAME(700, system_memory_increase)[] = {0x52A3B008}; /* MOV W8, #0x1D800000 */
static const instruction_t MAKE_KERNEL_PATCH_NAME(800, system_memory_increase)[] = {0x52A3B013}; /* MOV W19, #0x1D800000 */
static const instruction_t MAKE_KERNEL_PATCH_NAME(900, system_memory_increase)[] = {0x52A3B013}; /* MOV W19, #0x1D800000 */
static const instruction_t MAKE_KERNEL_PATCH_NAME(1000, system_memory_increase)[] = {0x52A3B013}; /* MOV W19, #0x1D800000 */
/* Hook Definitions. */
static const kernel_patch_t g_kernel_patches_100[] = {
@@ -735,6 +792,35 @@ static const kernel_patch_t g_kernel_patches_900[] = {
}
};
static const kernel_patch_t g_kernel_patches_1000[] = {
{ /* Send Message Process ID Patch. */
.pattern_size = 0x1C,
.pattern = MAKE_KERNEL_PATTERN_NAME(1000, proc_id_send),
.pattern_hook_offset = 0x0,
.payload_num_instructions = sizeof(MAKE_KERNEL_PATCH_NAME(1000, proc_id_send))/sizeof(instruction_t),
.branch_back_offset = 0x10,
.payload = MAKE_KERNEL_PATCH_NAME(1000, proc_id_send)
},
{ /* Receive Message Process ID Patch. */
.pattern_size = 0x1C,
.pattern = MAKE_KERNEL_PATTERN_NAME(1000, proc_id_recv),
.pattern_hook_offset = 0x0,
.payload_num_instructions = sizeof(MAKE_KERNEL_PATCH_NAME(1000, proc_id_recv))/sizeof(instruction_t),
.branch_back_offset = 0x10,
.payload = MAKE_KERNEL_PATCH_NAME(1000, proc_id_recv)
},
{ /* svcControlCodeMemory Patch. */
.payload_num_instructions = sizeof(MAKE_KERNEL_PATCH_NAME(1000, svc_control_codememory))/sizeof(instruction_t),
.payload = MAKE_KERNEL_PATCH_NAME(1000, svc_control_codememory),
.patch_offset = 0x45DAC,
},
{ /* System Memory Increase Patch. */
.payload_num_instructions = sizeof(MAKE_KERNEL_PATCH_NAME(1000, system_memory_increase))/sizeof(instruction_t),
.payload = MAKE_KERNEL_PATCH_NAME(1000, system_memory_increase),
.patch_offset = 0x66950,
}
};
#define KERNEL_PATCHES(vers) .num_patches = sizeof(g_kernel_patches_##vers)/sizeof(kernel_patch_t), .patches = g_kernel_patches_##vers,
/* Kernel Infos. */
@@ -811,6 +897,15 @@ static const kernel_info_t g_kernel_infos[] = {
.embedded_ini_ptr = 0x180,
.free_code_space_offset = 0x65780,
KERNEL_PATCHES(900)
},
{ /* 10.0.0. */
.hash = {0x59, 0x31, 0xE6, 0x46, 0xF7, 0xAA, 0x15, 0x59, 0x78, 0xC7, 0xB3, 0xA5, 0xFA, 0x80, 0xE2, 0xC0, 0xCA, 0x6F, 0x31, 0x97, 0x3D, 0x86, 0x8A, 0x69, 0xF3, 0xBF, 0xE6, 0xE5, 0x61, 0xA7, 0x1B, 0x5B, },
.hash_offset = 0x1B8,
.hash_size = 0x93000 - 0x1B8,
.embedded_ini_offset = 0x93000,
.embedded_ini_ptr = 0x178,
.free_code_space_offset = 0x67790,
KERNEL_PATCHES(1000)
}
};
@@ -855,7 +950,7 @@ const kernel_info_t *get_kernel_info(void *kernel, size_t size) {
return NULL;
}
void package2_patch_kernel(void *_kernel, size_t *kernel_size, bool is_sd_kernel, void **out_ini1) {
void package2_patch_kernel(void *_kernel, size_t *kernel_size, bool is_sd_kernel, void **out_ini1, uint32_t target_firmware) {
const kernel_info_t *kernel_info = get_kernel_info(_kernel, *kernel_size);
*out_ini1 = NULL;
@@ -876,6 +971,12 @@ void package2_patch_kernel(void *_kernel, size_t *kernel_size, bool is_sd_kernel
const uint32_t kernel_ldr_offset = *((volatile uint64_t *)((uintptr_t)_kernel + kernel_info->embedded_ini_ptr + 8));
memcpy((void *)((uintptr_t)_kernel + kernel_ldr_offset), kernel_ldr_bin, kernel_ldr_bin_size);
/* Set target firmware for our kernel loader. */
uint32_t *kldr_u32 = (uint32_t *)((uintptr_t)_kernel + kernel_ldr_offset);
if (kldr_u32[1] == 0x30444C4D) {
kldr_u32[2] = target_firmware;
}
/* Update size. */
*kernel_size = kernel_ldr_offset + kernel_ldr_bin_size;

View File

@@ -19,6 +19,6 @@
#include "utils.h"
void package2_patch_kernel(void *kernel, size_t *kernel_size, bool is_sd_kernel, void **out_ini1);
void package2_patch_kernel(void *kernel, size_t *kernel_size, bool is_sd_kernel, void **out_ini1, uint32_t target_firmware);
#endif

View File

@@ -160,6 +160,7 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui
desired_keyblob = MASTERKEY_REVISION_900;
/* Fallthrough */
case ATMOSPHERE_TARGET_FIRMWARE_910:
case ATMOSPHERE_TARGET_FIRMWARE_1000:
desired_keyblob = MASTERKEY_REVISION_910_CURRENT;
break;
default:

View File

@@ -232,6 +232,8 @@ static uint32_t nxboot_get_target_firmware(const void *package1loader) {
return ATMOSPHERE_TARGET_FIRMWARE_900;
} else if (memcmp(package1loader_header->build_timestamp, "20191021", 8) == 0) {
return ATMOSPHERE_TARGET_FIRMWARE_910;
} else if (memcmp(package1loader_header->build_timestamp, "20200303", 8) == 0) {
return ATMOSPHERE_TARGET_FIRMWARE_1000;
} else {
fatal_error("[NXBOOT] Unable to identify package1!\n");
}

View File

@@ -87,7 +87,7 @@ void package2_rebuild_and_copy(package2_header_t *package2, uint32_t target_firm
}
/* Perform any patches we want to the NX kernel. */
package2_patch_kernel(kernel, &kernel_size, is_sd_kernel, (void *)&orig_ini1);
package2_patch_kernel(kernel, &kernel_size, is_sd_kernel, (void *)&orig_ini1, target_firmware);
/* Ensure we know where embedded INI is if present, and we don't if not. */
if ((target_firmware < ATMOSPHERE_TARGET_FIRMWARE_800 && orig_ini1 != NULL) ||
@@ -232,7 +232,7 @@ static bool package2_validate_metadata(package2_meta_t *metadata, uint8_t data[]
/* Perform version checks. */
/* We will be compatible with all package2s released before current, but not newer ones. */
if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_910_CURRENT) {
if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_1000_CURRENT) {
return true;
}

View File

@@ -39,7 +39,8 @@
#define PACKAGE2_MAXVER_700_800 0xA
#define PACKAGE2_MAXVER_810 0xB
#define PACKAGE2_MAXVER_900 0xC
#define PACKAGE2_MAXVER_910_CURRENT 0xD
#define PACKAGE2_MAXVER_910_920 0xD
#define PACKAGE2_MAXVER_1000_CURRENT 0xE
#define PACKAGE2_MINVER_100 0x3
#define PACKAGE2_MINVER_200 0x4
@@ -52,7 +53,8 @@
#define PACKAGE2_MINVER_700_800 0xB
#define PACKAGE2_MINVER_810 0xC
#define PACKAGE2_MINVER_900 0xD
#define PACKAGE2_MINVER_910_CURRENT 0xE
#define PACKAGE2_MINVER_910_920 0xE
#define PACKAGE2_MINVER_1000_CURRENT 0xF
#define NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS ((void *)(0xA9800000ull))

View File

@@ -6,7 +6,7 @@
[subrepo]
remote = https://github.com/Atmosphere-NX/Atmosphere-libs
branch = master
commit = da6eac986d7f67ca3dcc3a8df0c191ffbea4686f
parent = eb48e7cc5943bd594b3166cb888d3dadb0474107
commit = c1fe12fcbd661ae47673af5f224804c92eebdbb5
parent = 98cc051387515977dcdede8ab0f1b09077f2f24b
method = merge
cmdver = 0.4.1

View File

@@ -10,7 +10,7 @@ This software is licensed under the terms of the GPLv2, with exemptions for spec
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.
* The [yuzu Nintendo Switch emulator](https://github.com/yuzu-emu/yuzu) and the [Ryujinx Team and Contributors](https://github.com/orgs/Ryujinx) are exempt from GPLv2 licensing. They are permitted, each at their individual discretion, to instead license any source code authored for the atmosphere-libs project as either GPLv2 or later or the [MIT license](https://github.com/Atmosphere-NX/Atmosphere/blob/master/docs/licensing_exemptions/MIT_LICENSE). In doing so, they may alter, supplement, or entirely remove the copyright notice for each file they choose to relicense. Neither the Atmosphère project nor its individual contributors shall assert their moral rights against any of the aforementioned projects.
* [Nintendo](https://github.com/Nintendo) is exempt from GPLv2 licensing and may (at its option) instead license any source code authored for the atmosphere-libs project under the Zero-Clause BSD license.
Credits

View File

@@ -10,7 +10,7 @@ This software is licensed under the terms of the GPLv2, with exemptions for spec
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 libmesosphere project as GPLv2 or later.
* The [yuzu Nintendo Switch emulator](https://github.com/yuzu-emu/yuzu) and the [Ryujinx Team and Contributors](https://github.com/orgs/Ryujinx) are exempt from GPLv2 licensing. They are permitted, each at their individual discretion, to instead license any source code authored for the libmesosphere project as either GPLv2 or later or the [MIT license](https://github.com/Atmosphere-NX/Atmosphere/blob/master/docs/licensing_exemptions/MIT_LICENSE). In doing so, they may alter, supplement, or entirely remove the copyright notice for each file they choose to relicense. Neither the Atmosphère project nor its individual contributors shall assert their moral rights against any of the aforementioned projects.
* [Nintendo](https://github.com/Nintendo) is exempt from GPLv2 licensing and may (at its option) instead license any source code authored for the libmesosphere project under the Zero-Clause BSD license.
Credits

View File

@@ -19,6 +19,7 @@
#include <mesosphere/kern_k_typed_address.hpp>
#include <mesosphere/kern_select_cpu.hpp>
#include <mesosphere/arch/arm64/kern_k_page_table_entry.hpp>
#include <mesosphere/kern_select_system_control.hpp>
namespace ams::kern::arch::arm64::init {
@@ -64,6 +65,220 @@ namespace ams::kern::arch::arm64::init {
/* The MMU is necessarily not yet turned on, if we are creating an initial page table. */
std::memset(reinterpret_cast<void *>(GetInteger(address)), 0, PageSize);
}
private:
size_t NOINLINE GetBlockCount(KVirtualAddress virt_addr, size_t size, size_t block_size) {
const KVirtualAddress end_virt_addr = virt_addr + size;
size_t count = 0;
while (virt_addr < end_virt_addr) {
L1PageTableEntry *l1_entry = GetL1Entry(this->l1_table, virt_addr);
/* If an L1 block is mapped or we're empty, advance by L1BlockSize. */
if (l1_entry->IsBlock() || l1_entry->IsEmpty()) {
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), L1BlockSize));
MESOSPHERE_INIT_ABORT_UNLESS(static_cast<size_t>(end_virt_addr - virt_addr) >= L1BlockSize);
virt_addr += L1BlockSize;
if (l1_entry->IsBlock() && block_size == L1BlockSize) {
count++;
}
continue;
}
/* Non empty and non-block must be table. */
MESOSPHERE_INIT_ABORT_UNLESS(l1_entry->IsTable());
/* Table, so check if we're mapped in L2. */
L2PageTableEntry *l2_entry = GetL2Entry(l1_entry, virt_addr);
if (l2_entry->IsBlock() || l2_entry->IsEmpty()) {
const size_t advance_size = (l2_entry->IsBlock() && l2_entry->IsContiguous()) ? L2ContiguousBlockSize : L2BlockSize;
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), advance_size));
MESOSPHERE_INIT_ABORT_UNLESS(static_cast<size_t>(end_virt_addr - virt_addr) >= advance_size);
virt_addr += advance_size;
if (l2_entry->IsBlock() && block_size == advance_size) {
count++;
}
continue;
}
/* Non empty and non-block must be table. */
MESOSPHERE_INIT_ABORT_UNLESS(l2_entry->IsTable());
/* Table, so check if we're mapped in L3. */
L3PageTableEntry *l3_entry = GetL3Entry(l2_entry, virt_addr);
/* L3 must be block or empty. */
MESOSPHERE_INIT_ABORT_UNLESS(l3_entry->IsBlock() || l3_entry->IsEmpty());
const size_t advance_size = (l3_entry->IsBlock() && l3_entry->IsContiguous()) ? L3ContiguousBlockSize : L3BlockSize;
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), advance_size));
MESOSPHERE_INIT_ABORT_UNLESS(static_cast<size_t>(end_virt_addr - virt_addr) >= advance_size);
virt_addr += advance_size;
if (l3_entry->IsBlock() && block_size == advance_size) {
count++;
}
}
return count;
}
KVirtualAddress NOINLINE GetBlockByIndex(KVirtualAddress virt_addr, size_t size, size_t block_size, size_t index) {
const KVirtualAddress end_virt_addr = virt_addr + size;
size_t count = 0;
while (virt_addr < end_virt_addr) {
L1PageTableEntry *l1_entry = GetL1Entry(this->l1_table, virt_addr);
/* If an L1 block is mapped or we're empty, advance by L1BlockSize. */
if (l1_entry->IsBlock() || l1_entry->IsEmpty()) {
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), L1BlockSize));
MESOSPHERE_INIT_ABORT_UNLESS(static_cast<size_t>(end_virt_addr - virt_addr) >= L1BlockSize);
if (l1_entry->IsBlock() && block_size == L1BlockSize) {
if ((count++) == index) {
return virt_addr;
}
}
virt_addr += L1BlockSize;
continue;
}
/* Non empty and non-block must be table. */
MESOSPHERE_INIT_ABORT_UNLESS(l1_entry->IsTable());
/* Table, so check if we're mapped in L2. */
L2PageTableEntry *l2_entry = GetL2Entry(l1_entry, virt_addr);
if (l2_entry->IsBlock() || l2_entry->IsEmpty()) {
const size_t advance_size = (l2_entry->IsBlock() && l2_entry->IsContiguous()) ? L2ContiguousBlockSize : L2BlockSize;
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), advance_size));
MESOSPHERE_INIT_ABORT_UNLESS(static_cast<size_t>(end_virt_addr - virt_addr) >= advance_size);
if (l2_entry->IsBlock() && block_size == advance_size) {
if ((count++) == index) {
return virt_addr;
}
}
virt_addr += advance_size;
continue;
}
/* Non empty and non-block must be table. */
MESOSPHERE_INIT_ABORT_UNLESS(l2_entry->IsTable());
/* Table, so check if we're mapped in L3. */
L3PageTableEntry *l3_entry = GetL3Entry(l2_entry, virt_addr);
/* L3 must be block or empty. */
MESOSPHERE_INIT_ABORT_UNLESS(l3_entry->IsBlock() || l3_entry->IsEmpty());
const size_t advance_size = (l3_entry->IsBlock() && l3_entry->IsContiguous()) ? L3ContiguousBlockSize : L3BlockSize;
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), advance_size));
MESOSPHERE_INIT_ABORT_UNLESS(static_cast<size_t>(end_virt_addr - virt_addr) >= advance_size);
if (l3_entry->IsBlock() && block_size == advance_size) {
if ((count++) == index) {
return virt_addr;
}
}
virt_addr += advance_size;
}
return Null<KVirtualAddress>;
}
PageTableEntry *GetMappingEntry(KVirtualAddress virt_addr, size_t block_size) {
L1PageTableEntry *l1_entry = GetL1Entry(this->l1_table, virt_addr);
if (l1_entry->IsBlock()) {
MESOSPHERE_INIT_ABORT_UNLESS(block_size == L1BlockSize);
return l1_entry;
}
MESOSPHERE_INIT_ABORT_UNLESS(l1_entry->IsTable());
/* Table, so check if we're mapped in L2. */
L2PageTableEntry *l2_entry = GetL2Entry(l1_entry, virt_addr);
if (l2_entry->IsBlock()) {
const size_t real_size = (l2_entry->IsContiguous()) ? L2ContiguousBlockSize : L2BlockSize;
MESOSPHERE_INIT_ABORT_UNLESS(real_size == block_size);
return l2_entry;
}
MESOSPHERE_INIT_ABORT_UNLESS(l2_entry->IsTable());
/* Table, so check if we're mapped in L3. */
L3PageTableEntry *l3_entry = GetL3Entry(l2_entry, virt_addr);
/* L3 must be block. */
MESOSPHERE_INIT_ABORT_UNLESS(l3_entry->IsBlock());
const size_t real_size = (l3_entry->IsContiguous()) ? L3ContiguousBlockSize : L3BlockSize;
MESOSPHERE_INIT_ABORT_UNLESS(real_size == block_size);
return l3_entry;
}
void NOINLINE SwapBlocks(KVirtualAddress src_virt_addr, KVirtualAddress dst_virt_addr, size_t block_size, bool do_copy) {
static_assert(L2ContiguousBlockSize / L2BlockSize == L3ContiguousBlockSize / L3BlockSize);
const bool contig = (block_size == L2ContiguousBlockSize || block_size == L3ContiguousBlockSize);
const size_t num_mappings = contig ? L2ContiguousBlockSize / L2BlockSize : 1;
/* Unmap the source. */
PageTableEntry *src_entry = this->GetMappingEntry(src_virt_addr, block_size);
const auto src_saved = *src_entry;
for (size_t i = 0; i < num_mappings; i++) {
*src_entry = InvalidPageTableEntry;
}
/* Unmap the target. */
PageTableEntry *dst_entry = this->GetMappingEntry(dst_virt_addr, block_size);
const auto dst_saved = *dst_entry;
for (size_t i = 0; i < num_mappings; i++) {
*dst_entry = InvalidPageTableEntry;
}
/* Invalidate the entire tlb. */
cpu::DataSynchronizationBarrierInnerShareable();
cpu::InvalidateEntireTlb();
/* Copy data, if we should. */
const u64 negative_block_size_for_mask = static_cast<u64>(-static_cast<s64>(block_size));
const u64 offset_mask = negative_block_size_for_mask & ((1ul << 36) - 1);
const KVirtualAddress copy_src_addr = KVirtualAddress(src_saved.GetRawAttributesUnsafeForSwap() & offset_mask);
const KVirtualAddress copy_dst_addr = KVirtualAddress(dst_saved.GetRawAttributesUnsafeForSwap() & offset_mask);
if (block_size && do_copy) {
u8 tmp[0x100];
for (size_t ofs = 0; ofs < block_size; ofs += sizeof(tmp)) {
std::memcpy(tmp, GetVoidPointer(copy_src_addr + ofs), sizeof(tmp));
std::memcpy(GetVoidPointer(copy_src_addr + ofs), GetVoidPointer(copy_dst_addr + ofs), sizeof(tmp));
std::memcpy(GetVoidPointer(copy_dst_addr + ofs), tmp, sizeof(tmp));
}
}
/* Swap the mappings. */
const u64 attr_preserve_mask = (negative_block_size_for_mask | 0xFFFF000000000000ul) ^ ((1ul << 36) - 1);
const size_t shift_for_contig = contig ? 4 : 0;
size_t advanced_size = 0;
const u64 src_attr_val = src_saved.GetRawAttributesUnsafeForSwap() & attr_preserve_mask;
const u64 dst_attr_val = dst_saved.GetRawAttributesUnsafeForSwap() & attr_preserve_mask;
for (size_t i = 0; i < num_mappings; i++) {
reinterpret_cast<u64 *>(src_entry)[i] = GetInteger(copy_dst_addr + (advanced_size >> shift_for_contig)) | src_attr_val;
reinterpret_cast<u64 *>(dst_entry)[i] = GetInteger(copy_src_addr + (advanced_size >> shift_for_contig)) | dst_attr_val;
advanced_size += block_size;
}
cpu::DataSynchronizationBarrierInnerShareable();
}
void NOINLINE PhysicallyRandomize(KVirtualAddress virt_addr, size_t size, size_t block_size, bool do_copy) {
const size_t block_count = this->GetBlockCount(virt_addr, size, block_size);
if (block_count > 1) {
for (size_t cur_block = 0; cur_block < block_count; cur_block++) {
const size_t target_block = KSystemControl::Init::GenerateRandomRange(cur_block, block_count - 1);
if (cur_block != target_block) {
const KVirtualAddress cur_virt_addr = this->GetBlockByIndex(virt_addr, size, block_size, cur_block);
const KVirtualAddress target_virt_addr = this->GetBlockByIndex(virt_addr, size, block_size, target_block);
MESOSPHERE_INIT_ABORT_UNLESS(cur_virt_addr != Null<KVirtualAddress>);
MESOSPHERE_INIT_ABORT_UNLESS(target_virt_addr != Null<KVirtualAddress>);
this->SwapBlocks(cur_virt_addr, target_virt_addr, block_size, do_copy);
}
}
}
}
public:
void NOINLINE Map(KVirtualAddress virt_addr, size_t size, KPhysicalAddress phys_addr, const PageTableEntry &attr, IPageAllocator &allocator) {
/* Ensure that addresses and sizes are page aligned. */
@@ -363,32 +578,62 @@ namespace ams::kern::arch::arm64::init {
cpu::DataSynchronizationBarrierInnerShareable();
}
void PhysicallyRandomize(KVirtualAddress virt_addr, size_t size, bool do_copy) {
this->PhysicallyRandomize(virt_addr, size, L1BlockSize, do_copy);
this->PhysicallyRandomize(virt_addr, size, L2ContiguousBlockSize, do_copy);
this->PhysicallyRandomize(virt_addr, size, L2BlockSize, do_copy);
this->PhysicallyRandomize(virt_addr, size, L3ContiguousBlockSize, do_copy);
this->PhysicallyRandomize(virt_addr, size, L3BlockSize, do_copy);
}
};
class KInitialPageAllocator : public KInitialPageTable::IPageAllocator {
private:
uintptr_t next_address;
public:
constexpr ALWAYS_INLINE KInitialPageAllocator() : next_address(Null<uintptr_t>) { /* ... */ }
struct State {
uintptr_t next_address;
uintptr_t free_bitmap;
};
private:
State state;
public:
constexpr ALWAYS_INLINE KInitialPageAllocator() : state{} { /* ... */ }
ALWAYS_INLINE void Initialize(uintptr_t address) {
this->next_address = address;
this->state.next_address = address + BITSIZEOF(this->state.free_bitmap) * PageSize;
this->state.free_bitmap = ~uintptr_t();
}
ALWAYS_INLINE uintptr_t GetFinalNextAddress() {
const uintptr_t final_address = this->next_address;
this->next_address = Null<uintptr_t>;
return final_address;
ALWAYS_INLINE void InitializeFromState(uintptr_t state_val) {
if (kern::GetTargetFirmware() >= kern::TargetFirmware_10_0_0) {
this->state = *reinterpret_cast<State *>(state_val);
} else {
this->state.next_address = state_val;
this->state.free_bitmap = 0;
}
}
ALWAYS_INLINE uintptr_t GetFinalState() {
return this->GetFinalNextAddress();
ALWAYS_INLINE void GetFinalState(State *out) {
*out = this->state;
this->state = {};
}
public:
virtual KPhysicalAddress Allocate() override {
MESOSPHERE_INIT_ABORT_UNLESS(this->next_address != Null<uintptr_t>);
const uintptr_t allocated = this->next_address;
this->next_address += PageSize;
MESOSPHERE_INIT_ABORT_UNLESS(this->state.next_address != Null<uintptr_t>);
uintptr_t allocated = this->state.next_address;
if (this->state.free_bitmap != 0) {
u64 index;
uintptr_t mask;
do {
index = KSystemControl::Init::GenerateRandomRange(0, BITSIZEOF(this->state.free_bitmap) - 1);
mask = (static_cast<uintptr_t>(1) << index);
} while ((this->state.free_bitmap & mask) == 0);
this->state.free_bitmap &= ~mask;
allocated = this->state.next_address - ((BITSIZEOF(this->state.free_bitmap) - index) * PageSize);
} else {
this->state.next_address += PageSize;
}
std::memset(reinterpret_cast<void *>(allocated), 0, PageSize);
return allocated;
}

View File

@@ -31,6 +31,12 @@ namespace ams::kern::arch::arm64 {
public:
struct InvalidTag{};
enum ExtensionTag : u64 {
ExtensionTag_IsValidBit = (1ul << 56),
ExtensionTag_IsValid = (ExtensionTag_IsValidBit | (1ul << 0)),
ExtensionTag_IsBlockMask = (ExtensionTag_IsValidBit | (1ul << 1)),
};
enum Permission : u64 {
Permission_KernelRWX = ((0ul << 53) | (1ul << 54) | (0ul << 6)),
Permission_KernelRX = ((0ul << 53) | (1ul << 54) | (2ul << 6)),
@@ -89,7 +95,7 @@ namespace ams::kern::arch::arm64 {
/* Construct a new attribute. */
constexpr ALWAYS_INLINE PageTableEntry(Permission perm, PageAttribute p_a, Shareable share)
: attributes(static_cast<u64>(perm) | static_cast<u64>(AccessFlag_Accessed) | static_cast<u64>(p_a) | static_cast<u64>(share))
: attributes(static_cast<u64>(perm) | static_cast<u64>(AccessFlag_Accessed) | static_cast<u64>(p_a) | static_cast<u64>(share) | static_cast<u64>(ExtensionTag_IsValid))
{
/* ... */
}
@@ -134,8 +140,9 @@ namespace ams::kern::arch::arm64 {
constexpr ALWAYS_INLINE bool IsReadOnly() const { return this->GetBits(7, 1) != 0; }
constexpr ALWAYS_INLINE bool IsUserAccessible() const { return this->GetBits(6, 1) != 0; }
constexpr ALWAYS_INLINE bool IsNonSecure() const { return this->GetBits(5, 1) != 0; }
constexpr ALWAYS_INLINE bool IsBlock() const { return this->GetBits(0, 2) == 0x1; }
constexpr ALWAYS_INLINE bool IsBlock() const { return (this->attributes & ExtensionTag_IsBlockMask) == ExtensionTag_IsValidBit; }
constexpr ALWAYS_INLINE bool IsTable() const { return this->GetBits(0, 2) == 0x3; }
constexpr ALWAYS_INLINE bool IsEmpty() const { return this->GetBits(0, 2) == 0x0; }
constexpr ALWAYS_INLINE decltype(auto) SetContiguousAllowed(bool en) { this->SetBit(55, !en); return *this; }
constexpr ALWAYS_INLINE decltype(auto) SetUserExecuteNever(bool en) { this->SetBit(54, en); return *this; }
@@ -157,6 +164,10 @@ namespace ams::kern::arch::arm64 {
return this->attributes == attr;
}
constexpr ALWAYS_INLINE u64 GetRawAttributesUnsafeForSwap() const {
return this->attributes;
}
protected:
constexpr ALWAYS_INLINE u64 GetRawAttributes() const {
return this->attributes;
@@ -186,7 +197,7 @@ namespace ams::kern::arch::arm64 {
}
constexpr ALWAYS_INLINE L1PageTableEntry(KPhysicalAddress phys_addr, const PageTableEntry &attr, bool contig)
: PageTableEntry(attr, (static_cast<u64>(contig) << 52) | GetInteger(phys_addr) | 0x1)
: PageTableEntry(attr, (static_cast<u64>(contig) << 52) | GetInteger(phys_addr) | PageTableEntry::ExtensionTag_IsValid)
{
/* ... */
}
@@ -231,7 +242,7 @@ namespace ams::kern::arch::arm64 {
}
constexpr ALWAYS_INLINE L2PageTableEntry(KPhysicalAddress phys_addr, const PageTableEntry &attr, bool contig)
: PageTableEntry(attr, (static_cast<u64>(contig) << 52) | GetInteger(phys_addr) | 0x1)
: PageTableEntry(attr, (static_cast<u64>(contig) << 52) | GetInteger(phys_addr) | PageTableEntry::ExtensionTag_IsValid)
{
/* ... */
}
@@ -264,12 +275,12 @@ namespace ams::kern::arch::arm64 {
constexpr ALWAYS_INLINE L3PageTableEntry(InvalidTag) : PageTableEntry(InvalidTag{}) { /* ... */ }
constexpr ALWAYS_INLINE L3PageTableEntry(KPhysicalAddress phys_addr, const PageTableEntry &attr, bool contig)
: PageTableEntry(attr, (static_cast<u64>(contig) << 52) | GetInteger(phys_addr) | 0x3)
: PageTableEntry(attr, (static_cast<u64>(contig) << 52) | GetInteger(phys_addr) | 0x2 | PageTableEntry::ExtensionTag_IsValid)
{
/* ... */
}
constexpr ALWAYS_INLINE bool IsBlock() const { return this->GetBits(0, 2) == 0x3; }
constexpr ALWAYS_INLINE bool IsBlock() const { return (GetRawAttributes() & ExtensionTag_IsBlockMask) == ExtensionTag_IsBlockMask; }
constexpr ALWAYS_INLINE KPhysicalAddress GetBlock() const {
return this->SelectBits(12, 36);

View File

@@ -20,6 +20,24 @@ namespace ams::kern {
constexpr size_t PageSize = 4_KB;
enum TargetFirmware : u32 {
TargetFirmware_1_0_0 = ATMOSPHERE_TARGET_FIRMWARE_100,
TargetFirmware_2_0_0 = ATMOSPHERE_TARGET_FIRMWARE_200,
TargetFirmware_3_0_0 = ATMOSPHERE_TARGET_FIRMWARE_300,
TargetFirmware_4_0_0 = ATMOSPHERE_TARGET_FIRMWARE_400,
TargetFirmware_5_0_0 = ATMOSPHERE_TARGET_FIRMWARE_500,
TargetFirmware_6_0_0 = ATMOSPHERE_TARGET_FIRMWARE_600,
TargetFirmware_6_2_0 = ATMOSPHERE_TARGET_FIRMWARE_620,
TargetFirmware_7_0_0 = ATMOSPHERE_TARGET_FIRMWARE_700,
TargetFirmware_8_0_0 = ATMOSPHERE_TARGET_FIRMWARE_800,
TargetFirmware_8_1_0 = ATMOSPHERE_TARGET_FIRMWARE_810,
TargetFirmware_9_0_0 = ATMOSPHERE_TARGET_FIRMWARE_900,
TargetFirmware_9_1_0 = ATMOSPHERE_TARGET_FIRMWARE_910,
TargetFirmware_10_0_0 = ATMOSPHERE_TARGET_FIRMWARE_1000,
};
TargetFirmware GetTargetFirmware();
}
#if 1 || defined(AMS_BUILD_FOR_AUDITING)

View File

@@ -94,6 +94,7 @@ namespace ams::kern {
KProcessAddress FindFreeArea(KProcessAddress region_start, size_t region_num_pages, size_t num_pages, size_t alignment, size_t offset, size_t guard_pages) const;
void Update(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages, KMemoryState state, KMemoryPermission perm, KMemoryAttribute attr);
void UpdateLock(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages, void (KMemoryBlock::*lock_func)(KMemoryPermission new_perm), KMemoryPermission perm);
iterator FindIterator(KProcessAddress address) const {
return this->memory_block_tree.find(KMemoryBlock(address, 1, KMemoryState_Free, KMemoryPermission_None, KMemoryAttribute_None));

View File

@@ -197,6 +197,7 @@ namespace ams::kern {
cur_address += cur_info.GetSize();
remaining_pages -= cur_info.GetNumPages();
}
it++;
}
/* Find the iterator now that we've updated. */
@@ -227,6 +228,86 @@ namespace ams::kern {
}
}
void KMemoryBlockManager::UpdateLock(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages, void (KMemoryBlock::*lock_func)(KMemoryPermission new_perm), KMemoryPermission perm) {
/* Ensure for auditing that we never end up with an invalid tree. */
KScopedMemoryBlockManagerAuditor auditor(this);
MESOSPHERE_ASSERT(util::IsAligned(GetInteger(address), PageSize));
KProcessAddress cur_address = address;
size_t remaining_pages = num_pages;
iterator it = this->FindIterator(address);
iterator prev = it, next = it;
bool check_coalesce_prev = false, check_coalesce_next = false;
while (remaining_pages > 0) {
const size_t remaining_size = remaining_pages * PageSize;
KMemoryInfo cur_info = it->GetMemoryInfo();
/* If we need to, create a new block before and insert it. */
if (cur_info.address != GetInteger(cur_address)) {
KMemoryBlock *new_block = allocator->Allocate();
it->Split(new_block, cur_address);
it = this->memory_block_tree.insert(*new_block);
it++;
cur_info = it->GetMemoryInfo();
cur_address = cur_info.GetAddress();
} else if (cur_address == address && cur_address != this->start_address) {
/* If there's a previous, we should check for coalescing. */
check_coalesce_prev = true;
prev--;
} else if (cur_info.GetSize() > remaining_size) {
/* If we need to, create a new block after and insert it. */
KMemoryBlock *new_block = allocator->Allocate();
it->Split(new_block, cur_address + remaining_size);
it = this->memory_block_tree.insert(*new_block);
cur_info = it->GetMemoryInfo();
} else if (cur_info.GetSize() == remaining_size) {
/* Otherwise if we can map precisely, we may need to check for coalescing against next block. */
next = it;
++next;
if (next != this->memory_block_tree.end()) {
check_coalesce_next = true;
}
}
/* Call the locked update function. */
(std::addressof(*it)->*lock_func)(perm);
cur_address += cur_info.GetSize();
remaining_pages -= cur_info.GetNumPages();
it++;
}
/* If we should try to coalesce prev, do so. */
if (check_coalesce_prev) {
it = prev;
it++;
if (prev->HasSameProperties(*it)) {
KMemoryBlock *block = std::addressof(*it);
const size_t pages = it->GetNumPages();
this->memory_block_tree.erase(it);
allocator->Free(block);
prev->Add(pages);
}
}
/* If we should try to coalesce next, do so. */
if (check_coalesce_next) {
it = next;
it--;
if (it->HasSameProperties(*next)) {
KMemoryBlock *block = std::addressof(*next);
const size_t pages = next->GetNumPages();
this->memory_block_tree.erase(next);
allocator->Free(block);
it->Add(pages);
}
}
}
/* Debug. */
bool KMemoryBlockManager::CheckState() const {
/* If we fail, we should dump blocks. */

View File

@@ -14,7 +14,7 @@ This software is licensed under the terms of the GPLv2, with exemptions for spec
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.
* The [yuzu Nintendo Switch emulator](https://github.com/yuzu-emu/yuzu) and the [Ryujinx Team and Contributors](https://github.com/orgs/Ryujinx) are exempt from GPLv2 licensing. They are permitted, each at their individual discretion, to instead license any source code authored for the libstratosphere project as either GPLv2 or later or the [MIT license](https://github.com/Atmosphere-NX/Atmosphere/blob/master/docs/licensing_exemptions/MIT_LICENSE). In doing so, they may alter, supplement, or entirely remove the copyright notice for each file they choose to relicense. Neither the Atmosphère project nor its individual contributors shall assert their moral rights against any of the aforementioned projects.
* [Nintendo](https://github.com/Nintendo) is exempt from GPLv2 licensing and may (at its option) instead license any source code authored for the libstratosphere project under the Zero-Clause BSD license.
Credits

View File

@@ -51,6 +51,7 @@
#include <stratosphere/ncm.hpp>
#include <stratosphere/nim.hpp>
#include <stratosphere/patcher.hpp>
#include <stratosphere/pgl.hpp>
#include <stratosphere/psc.hpp>
#include <stratosphere/pm.hpp>
#include <stratosphere/reg.hpp>

View File

@@ -35,6 +35,7 @@ namespace ams::exosphere {
AMS_DEFINE_TARGET_FIRMWARE_ENUM(810),
AMS_DEFINE_TARGET_FIRMWARE_ENUM(900),
AMS_DEFINE_TARGET_FIRMWARE_ENUM(910),
AMS_DEFINE_TARGET_FIRMWARE_ENUM(1000),
};
#undef AMS_DEFINE_TARGET_FIRMWARE_ENUM

View File

@@ -54,15 +54,15 @@ namespace ams::erpt::sf {
DEFINE_SERVICE_DISPATCH_TABLE {
MAKE_SERVICE_COMMAND_META(SubmitContext),
MAKE_SERVICE_COMMAND_META(CreateReport),
MAKE_SERVICE_COMMAND_META(SetInitialLaunchSettingsCompletionTime, hos::Version_300),
MAKE_SERVICE_COMMAND_META(ClearInitialLaunchSettingsCompletionTime, hos::Version_300),
MAKE_SERVICE_COMMAND_META(UpdatePowerOnTime, hos::Version_300),
MAKE_SERVICE_COMMAND_META(UpdateAwakeTime, hos::Version_300),
MAKE_SERVICE_COMMAND_META(SubmitMultipleCategoryContext, hos::Version_500),
MAKE_SERVICE_COMMAND_META(UpdateApplicationLaunchTime, hos::Version_600),
MAKE_SERVICE_COMMAND_META(ClearApplicationLaunchTime, hos::Version_600),
MAKE_SERVICE_COMMAND_META(SubmitAttachment, hos::Version_800),
MAKE_SERVICE_COMMAND_META(CreateReportWithAttachments, hos::Version_800),
MAKE_SERVICE_COMMAND_META(SetInitialLaunchSettingsCompletionTime, hos::Version_3_0_0),
MAKE_SERVICE_COMMAND_META(ClearInitialLaunchSettingsCompletionTime, hos::Version_3_0_0),
MAKE_SERVICE_COMMAND_META(UpdatePowerOnTime, hos::Version_3_0_0),
MAKE_SERVICE_COMMAND_META(UpdateAwakeTime, hos::Version_3_0_0),
MAKE_SERVICE_COMMAND_META(SubmitMultipleCategoryContext, hos::Version_5_0_0),
MAKE_SERVICE_COMMAND_META(UpdateApplicationLaunchTime, hos::Version_6_0_0),
MAKE_SERVICE_COMMAND_META(ClearApplicationLaunchTime, hos::Version_6_0_0),
MAKE_SERVICE_COMMAND_META(SubmitAttachment, hos::Version_8_0_0),
MAKE_SERVICE_COMMAND_META(CreateReportWithAttachments, hos::Version_8_0_0),
};
};

View File

@@ -41,10 +41,10 @@ namespace ams::erpt::sf {
DEFINE_SERVICE_DISPATCH_TABLE {
MAKE_SERVICE_COMMAND_META(GetReportList),
MAKE_SERVICE_COMMAND_META(GetEvent),
MAKE_SERVICE_COMMAND_META(CleanupReports, hos::Version_400),
MAKE_SERVICE_COMMAND_META(DeleteReport, hos::Version_500),
MAKE_SERVICE_COMMAND_META(GetStorageUsageStatistics, hos::Version_500),
MAKE_SERVICE_COMMAND_META(GetAttachmentList, hos::Version_800),
MAKE_SERVICE_COMMAND_META(CleanupReports, hos::Version_4_0_0),
MAKE_SERVICE_COMMAND_META(DeleteReport, hos::Version_5_0_0),
MAKE_SERVICE_COMMAND_META(GetStorageUsageStatistics, hos::Version_5_0_0),
MAKE_SERVICE_COMMAND_META(GetAttachmentList, hos::Version_8_0_0),
};
};

View File

@@ -38,7 +38,7 @@ namespace ams::erpt::sf {
DEFINE_SERVICE_DISPATCH_TABLE {
MAKE_SERVICE_COMMAND_META(OpenReport),
MAKE_SERVICE_COMMAND_META(OpenManager),
MAKE_SERVICE_COMMAND_META(OpenAttachment, hos::Version_800),
MAKE_SERVICE_COMMAND_META(OpenAttachment, hos::Version_8_0_0),
};
};

View File

@@ -19,9 +19,17 @@
namespace ams::fs {
Result MountCode(const char *name, const char *path, ncm::ProgramId program_id);
struct CodeInfo {
u8 signature[crypto::Rsa2048PssSha256Verifier::SignatureSize];
u8 hash[crypto::Rsa2048PssSha256Verifier::HashSize];
bool is_signed;
u8 reserved[3];
};
static_assert(sizeof(CodeInfo) == crypto::Rsa2048PssSha256Verifier::SignatureSize + crypto::Rsa2048PssSha256Verifier::HashSize + 4);
Result MountCodeForAtmosphereWithRedirection(const char *name, const char *path, ncm::ProgramId program_id, bool is_hbl, bool is_specific);
Result MountCodeForAtmosphere(const char *name, const char *path, ncm::ProgramId program_id);
Result MountCode(CodeInfo *out, const char *name, const char *path, ncm::ProgramId program_id);
Result MountCodeForAtmosphereWithRedirection(CodeInfo *out, const char *name, const char *path, ncm::ProgramId program_id, bool is_hbl, bool is_specific);
Result MountCodeForAtmosphere(CodeInfo *out, const char *name, const char *path, ncm::ProgramId program_id);
}

View File

@@ -72,7 +72,7 @@ namespace ams::fssrv::impl {
MAKE_SERVICE_COMMAND_META(GetSize),
/* 4.0.0- */
MAKE_SERVICE_COMMAND_META(OperateRange, hos::Version_400),
MAKE_SERVICE_COMMAND_META(OperateRange, hos::Version_4_0_0),
};
};
@@ -181,11 +181,11 @@ namespace ams::fssrv::impl {
MAKE_SERVICE_COMMAND_META(GetTotalSpaceSize),
/* 3.0.0- */
MAKE_SERVICE_COMMAND_META(CleanDirectoryRecursively, hos::Version_300),
MAKE_SERVICE_COMMAND_META(GetFileTimeStampRaw, hos::Version_300),
MAKE_SERVICE_COMMAND_META(CleanDirectoryRecursively, hos::Version_3_0_0),
MAKE_SERVICE_COMMAND_META(GetFileTimeStampRaw, hos::Version_3_0_0),
/* 4.0.0- */
MAKE_SERVICE_COMMAND_META(QueryEntry, hos::Version_400),
MAKE_SERVICE_COMMAND_META(QueryEntry, hos::Version_4_0_0),
};
};

View File

@@ -71,7 +71,7 @@ namespace ams::fssrv::impl {
MAKE_SERVICE_COMMAND_META(GetSize),
/* 4.0.0- */
MAKE_SERVICE_COMMAND_META(OperateRange, hos::Version_400),
MAKE_SERVICE_COMMAND_META(OperateRange, hos::Version_4_0_0),
};
};

View File

@@ -17,6 +17,7 @@
#pragma once
#include <stratosphere/fssystem/fssystem_utility.hpp>
#include <stratosphere/fssystem/fssystem_external_code.hpp>
#include <stratosphere/fssystem/fssystem_acid_sign_key.hpp>
#include <stratosphere/fssystem/fssystem_partition_file_system.hpp>
#include <stratosphere/fssystem/fssystem_partition_file_system_meta.hpp>
#include <stratosphere/fssystem/fssystem_path_tool.hpp>

View File

@@ -0,0 +1,111 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 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::fssystem {
constexpr inline size_t AcidSignatureKeyGenerationMax = 1;
constexpr inline size_t AcidSignatureKeyModulusSize = 0x100;
constexpr inline const u8 AcidSignatureKeyModulusDev[AcidSignatureKeyGenerationMax + 1][AcidSignatureKeyModulusSize] = {
{
0xD6, 0x34, 0xA5, 0x78, 0x6C, 0x68, 0xCE, 0x5A, 0xC2, 0x37, 0x17, 0xF3, 0x82, 0x45, 0xC6, 0x89,
0xE1, 0x2D, 0x06, 0x67, 0xBF, 0xB4, 0x06, 0x19, 0x55, 0x6B, 0x27, 0x66, 0x0C, 0xA4, 0xB5, 0x87,
0x81, 0x25, 0xF4, 0x30, 0xBC, 0x53, 0x08, 0x68, 0xA2, 0x48, 0x49, 0x8C, 0x3F, 0x38, 0x40, 0x9C,
0xC4, 0x26, 0xF4, 0x79, 0xE2, 0xA1, 0x85, 0xF5, 0x5C, 0x7F, 0x58, 0xBA, 0xA6, 0x1C, 0xA0, 0x8B,
0x84, 0x16, 0x14, 0x6F, 0x85, 0xD9, 0x7C, 0xE1, 0x3C, 0x67, 0x22, 0x1E, 0xFB, 0xD8, 0xA7, 0xA5,
0x9A, 0xBF, 0xEC, 0x0E, 0xCF, 0x96, 0x7E, 0x85, 0xC2, 0x1D, 0x49, 0x5D, 0x54, 0x26, 0xCB, 0x32,
0x7C, 0xF6, 0xBB, 0x58, 0x03, 0x80, 0x2B, 0x5D, 0xF7, 0xFB, 0xD1, 0x9D, 0xC7, 0xC6, 0x2E, 0x53,
0xC0, 0x6F, 0x39, 0x2C, 0x1F, 0xA9, 0x92, 0xF2, 0x4D, 0x7D, 0x4E, 0x74, 0xFF, 0xE4, 0xEF, 0xE4,
0x7C, 0x3D, 0x34, 0x2A, 0x71, 0xA4, 0x97, 0x59, 0xFF, 0x4F, 0xA2, 0xF4, 0x66, 0x78, 0xD8, 0xBA,
0x99, 0xE3, 0xE6, 0xDB, 0x54, 0xB9, 0xE9, 0x54, 0xA1, 0x70, 0xFC, 0x05, 0x1F, 0x11, 0x67, 0x4B,
0x26, 0x8C, 0x0C, 0x3E, 0x03, 0xD2, 0xA3, 0x55, 0x5C, 0x7D, 0xC0, 0x5D, 0x9D, 0xFF, 0x13, 0x2F,
0xFD, 0x19, 0xBF, 0xED, 0x44, 0xC3, 0x8C, 0xA7, 0x28, 0xCB, 0xE5, 0xE0, 0xB1, 0xA7, 0x9C, 0x33,
0x8D, 0xB8, 0x6E, 0xDE, 0x87, 0x18, 0x22, 0x60, 0xC4, 0xAE, 0xF2, 0x87, 0x9F, 0xCE, 0x09, 0x5C,
0xB5, 0x99, 0xA5, 0x9F, 0x49, 0xF2, 0xD7, 0x58, 0xFA, 0xF9, 0xC0, 0x25, 0x7D, 0xD6, 0xCB, 0xF3,
0xD8, 0x6C, 0xA2, 0x69, 0x91, 0x68, 0x73, 0xB1, 0x94, 0x6F, 0xA3, 0xF3, 0xB9, 0x7D, 0xF8, 0xE0,
0x72, 0x9E, 0x93, 0x7B, 0x7A, 0xA2, 0x57, 0x60, 0xB7, 0x5B, 0xA9, 0x84, 0xAE, 0x64, 0x88, 0x69
},
{
0xBC, 0xA5, 0x6A, 0x7E, 0xEA, 0x38, 0x34, 0x62, 0xA6, 0x10, 0x18, 0x3C, 0xE1, 0x63, 0x7B, 0xF0,
0xD3, 0x08, 0x8C, 0xF5, 0xC5, 0xC4, 0xC7, 0x93, 0xE9, 0xD9, 0xE6, 0x32, 0xF3, 0xA0, 0xF6, 0x6E,
0x8A, 0x98, 0x76, 0x47, 0x33, 0x47, 0x65, 0x02, 0x70, 0xDC, 0x86, 0x5F, 0x3D, 0x61, 0x5A, 0x70,
0xBC, 0x5A, 0xCA, 0xCA, 0x50, 0xAD, 0x61, 0x7E, 0xC9, 0xEC, 0x27, 0xFF, 0xE8, 0x64, 0x42, 0x9A,
0xEE, 0xBE, 0xC3, 0xD1, 0x0B, 0xC0, 0xE9, 0xBF, 0x83, 0x8D, 0xC0, 0x0C, 0xD8, 0x00, 0x5B, 0x76,
0x90, 0xD2, 0x4B, 0x30, 0x84, 0x35, 0x8B, 0x1E, 0x20, 0xB7, 0xE4, 0xDC, 0x63, 0xE5, 0xDF, 0xCD,
0x00, 0x5F, 0x81, 0x5F, 0x67, 0xC5, 0x8B, 0xDF, 0xFC, 0xE1, 0x37, 0x5F, 0x07, 0xD9, 0xDE, 0x4F,
0xE6, 0x7B, 0xF1, 0xFB, 0xA1, 0x5A, 0x71, 0x40, 0xFE, 0xBA, 0x1E, 0xAE, 0x13, 0x22, 0xD2, 0xFE,
0x37, 0xA2, 0xB6, 0x8B, 0xAB, 0xEB, 0x84, 0x81, 0x4E, 0x7C, 0x1E, 0x02, 0xD1, 0xFB, 0xD7, 0x5D,
0x11, 0x84, 0x64, 0xD2, 0x4D, 0xBB, 0x50, 0x00, 0x67, 0x54, 0xE2, 0x77, 0x89, 0xBA, 0x0B, 0xE7,
0x05, 0x57, 0x9A, 0x22, 0x5A, 0xEC, 0x76, 0x1C, 0xFD, 0xE8, 0xA8, 0x18, 0x16, 0x41, 0x65, 0x03,
0xFA, 0xC4, 0xA6, 0x31, 0x5C, 0x1A, 0x7F, 0xAB, 0x11, 0xC8, 0x4A, 0x99, 0xB9, 0xE6, 0xCF, 0x62,
0x21, 0xA6, 0x72, 0x47, 0xDB, 0xBA, 0x96, 0x26, 0x4E, 0x2E, 0xD4, 0x8C, 0x46, 0xD6, 0xA7, 0x1A,
0x6C, 0x32, 0xA7, 0xDF, 0x85, 0x1C, 0x03, 0xC3, 0x6D, 0xA9, 0xE9, 0x68, 0xF4, 0x17, 0x1E, 0xB2,
0x70, 0x2A, 0xA1, 0xE5, 0xE1, 0xF3, 0x8F, 0x6F, 0x63, 0xAC, 0xEB, 0x72, 0x0B, 0x4C, 0x4A, 0x36,
0x3C, 0x60, 0x91, 0x9F, 0x6E, 0x1C, 0x71, 0xEA, 0xD0, 0x78, 0x78, 0xA0, 0x2E, 0xC6, 0x32, 0x6B
}
};
constexpr inline const u8 AcidSignatureKeyModulusProd[AcidSignatureKeyGenerationMax + 1][AcidSignatureKeyModulusSize] = {
{
0xDD, 0xC8, 0xDD, 0xF2, 0x4E, 0x6D, 0xF0, 0xCA, 0x9E, 0xC7, 0x5D, 0xC7, 0x7B, 0xAD, 0xFE, 0x7D,
0x23, 0x89, 0x69, 0xB6, 0xF2, 0x06, 0xA2, 0x02, 0x88, 0xE1, 0x55, 0x91, 0xAB, 0xCB, 0x4D, 0x50,
0x2E, 0xFC, 0x9D, 0x94, 0x76, 0xD6, 0x4C, 0xD8, 0xFF, 0x10, 0xFA, 0x5E, 0x93, 0x0A, 0xB4, 0x57,
0xAC, 0x51, 0xC7, 0x16, 0x66, 0xF4, 0x1A, 0x54, 0xC2, 0xC5, 0x04, 0x3D, 0x1B, 0xFE, 0x30, 0x20,
0x8A, 0xAC, 0x6F, 0x6F, 0xF5, 0xC7, 0xB6, 0x68, 0xB8, 0xC9, 0x40, 0x6B, 0x42, 0xAD, 0x11, 0x21,
0xE7, 0x8B, 0xE9, 0x75, 0x01, 0x86, 0xE4, 0x48, 0x9B, 0x0A, 0x0A, 0xF8, 0x7F, 0xE8, 0x87, 0xF2,
0x82, 0x01, 0xE6, 0xA3, 0x0F, 0xE4, 0x66, 0xAE, 0x83, 0x3F, 0x4E, 0x9F, 0x5E, 0x01, 0x30, 0xA4,
0x00, 0xB9, 0x9A, 0xAE, 0x5F, 0x03, 0xCC, 0x18, 0x60, 0xE5, 0xEF, 0x3B, 0x5E, 0x15, 0x16, 0xFE,
0x1C, 0x82, 0x78, 0xB5, 0x2F, 0x47, 0x7C, 0x06, 0x66, 0x88, 0x5D, 0x35, 0xA2, 0x67, 0x20, 0x10,
0xE7, 0x6C, 0x43, 0x68, 0xD3, 0xE4, 0x5A, 0x68, 0x2A, 0x5A, 0xE2, 0x6D, 0x73, 0xB0, 0x31, 0x53,
0x1C, 0x20, 0x09, 0x44, 0xF5, 0x1A, 0x9D, 0x22, 0xBE, 0x12, 0xA1, 0x77, 0x11, 0xE2, 0xA1, 0xCD,
0x40, 0x9A, 0xA2, 0x8B, 0x60, 0x9B, 0xEF, 0xA0, 0xD3, 0x48, 0x63, 0xA2, 0xF8, 0xA3, 0x2C, 0x08,
0x56, 0x52, 0x2E, 0x60, 0x19, 0x67, 0x5A, 0xA7, 0x9F, 0xDC, 0x3F, 0x3F, 0x69, 0x2B, 0x31, 0x6A,
0xB7, 0x88, 0x4A, 0x14, 0x84, 0x80, 0x33, 0x3C, 0x9D, 0x44, 0xB7, 0x3F, 0x4C, 0xE1, 0x75, 0xEA,
0x37, 0xEA, 0xE8, 0x1E, 0x7C, 0x77, 0xB7, 0xC6, 0x1A, 0xA2, 0xF0, 0x9F, 0x10, 0x61, 0xCD, 0x7B,
0x5B, 0x32, 0x4C, 0x37, 0xEF, 0xB1, 0x71, 0x68, 0x53, 0x0A, 0xED, 0x51, 0x7D, 0x35, 0x22, 0xFD
},
{
0xE7, 0xAA, 0x25, 0xC8, 0x01, 0xA5, 0x14, 0x6B, 0x01, 0x60, 0x3E, 0xD9, 0x96, 0x5A, 0xBF, 0x90,
0xAC, 0xA7, 0xFD, 0x9B, 0x5B, 0xBD, 0x8A, 0x26, 0xB0, 0xCB, 0x20, 0x28, 0x9A, 0x72, 0x12, 0xF5,
0x20, 0x65, 0xB3, 0xB9, 0x84, 0x58, 0x1F, 0x27, 0xBC, 0x7C, 0xA2, 0xC9, 0x9E, 0x18, 0x95, 0xCF,
0xC2, 0x73, 0x2E, 0x74, 0x8C, 0x66, 0xE5, 0x9E, 0x79, 0x2B, 0xB8, 0x07, 0x0C, 0xB0, 0x4E, 0x8E,
0xAB, 0x85, 0x21, 0x42, 0xC4, 0xC5, 0x6D, 0x88, 0x9C, 0xDB, 0x15, 0x95, 0x3F, 0x80, 0xDB, 0x7A,
0x9A, 0x7D, 0x41, 0x56, 0x25, 0x17, 0x18, 0x42, 0x4D, 0x8C, 0xAC, 0xA5, 0x7B, 0xDB, 0x42, 0x5D,
0x59, 0x35, 0x45, 0x5D, 0x8A, 0x02, 0xB5, 0x70, 0xC0, 0x72, 0x35, 0x46, 0xD0, 0x1D, 0x60, 0x01,
0x4A, 0xCC, 0x1C, 0x46, 0xD3, 0xD6, 0x35, 0x52, 0xD6, 0xE1, 0xF8, 0x3B, 0x5D, 0xEA, 0xDD, 0xB8,
0xFE, 0x7D, 0x50, 0xCB, 0x35, 0x23, 0x67, 0x8B, 0xB6, 0xE4, 0x74, 0xD2, 0x60, 0xFC, 0xFD, 0x43,
0xBF, 0x91, 0x08, 0x81, 0xC5, 0x4F, 0x5D, 0x16, 0x9A, 0xC4, 0x9A, 0xC6, 0xF6, 0xF3, 0xE1, 0xF6,
0x5C, 0x07, 0xAA, 0x71, 0x6C, 0x13, 0xA4, 0xB1, 0xB3, 0x66, 0xBF, 0x90, 0x4C, 0x3D, 0xA2, 0xC4,
0x0B, 0xB8, 0x3D, 0x7A, 0x8C, 0x19, 0xFA, 0xFF, 0x6B, 0xB9, 0x1F, 0x02, 0xCC, 0xB6, 0xD3, 0x0C,
0x7D, 0x19, 0x1F, 0x47, 0xF9, 0xC7, 0x40, 0x01, 0xFA, 0x46, 0xEA, 0x0B, 0xD4, 0x02, 0xE0, 0x3D,
0x30, 0x9A, 0x1A, 0x0F, 0xEA, 0xA7, 0x66, 0x55, 0xF7, 0xCB, 0x28, 0xE2, 0xBB, 0x99, 0xE4, 0x83,
0xC3, 0x43, 0x03, 0xEE, 0xDC, 0x1F, 0x02, 0x23, 0xDD, 0xD1, 0x2D, 0x39, 0xA4, 0x65, 0x75, 0x03,
0xEF, 0x37, 0x9C, 0x06, 0xD6, 0xFA, 0xA1, 0x15, 0xF0, 0xDB, 0x17, 0x47, 0x26, 0x4F, 0x49, 0x03
}
};
static_assert(sizeof(AcidSignatureKeyModulusProd) == sizeof(AcidSignatureKeyModulusDev));
constexpr inline const u8 AcidSignatureKeyExponent[] = {
0x01, 0x00, 0x01
};
constexpr inline size_t AcidSignatureKeyExponentSize = util::size(AcidSignatureKeyExponent);
}

View File

@@ -20,19 +20,20 @@
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_Min = 0,
Version_1_0_0 = Version_Min,
Version_2_0_0 = 1,
Version_3_0_0 = 2,
Version_4_0_0 = 3,
Version_5_0_0 = 4,
Version_6_0_0 = 5,
Version_7_0_0 = 6,
Version_8_0_0 = 7,
Version_8_1_0 = 8,
Version_9_0_0 = 9,
Version_9_1_0 = 10,
Version_10_0_0 = 11,
Version_Current = Version_10_0_0,
Version_Max = 32,
};

View File

@@ -16,5 +16,6 @@
#pragma once
#include "ldr/ldr_types.hpp"
#include "ldr/ldr_pm_api.hpp"
#include <stratosphere/ldr/ldr_types.hpp>
#include <stratosphere/ldr/ldr_shell_api.hpp>
#include <stratosphere/ldr/ldr_pm_api.hpp>

View File

@@ -24,6 +24,7 @@ namespace ams::ldr::pm {
Result GetProgramInfo(ProgramInfo *out, const ncm::ProgramLocation &loc);
Result PinProgram(PinId *out, const ncm::ProgramLocation &loc);
Result UnpinProgram(PinId pin_id);
Result SetEnabledProgramVerification(bool enabled);
Result HasLaunchedProgram(bool *out, ncm::ProgramId program_id);
/* Atmosphere extension API. */

View File

@@ -0,0 +1,31 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 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 <stratosphere/ncm/ncm_ids.hpp>
#include <stratosphere/ldr/ldr_types.hpp>
namespace ams::ldr {
/* Shell API. */
Result InitializeForShell();
Result FinalizeForShell();
Result SetProgramArgument(ncm::ProgramId program_id, const void *arg, size_t size);
Result FlushArguments();
}

View File

@@ -221,7 +221,8 @@ namespace ams::ldr {
};
u32 magic;
u8 reserved_04[8];
u32 signature_key_generation;
u8 reserved_08[4];
u8 flags;
u8 reserved_0D;
u8 main_thread_priority;

View File

@@ -49,7 +49,7 @@ namespace ams::lr {
Result RegisterAddOnContentStorage(ncm::DataId id, ncm::ApplicationId application_id, ncm::StorageId storage_id) {
AMS_ASSERT(this->interface);
if (hos::GetVersion() >= hos::Version_900) {
if (hos::GetVersion() >= hos::Version_9_0_0) {
return this->interface->RegisterAddOnContentStorage(id, application_id, storage_id);
} else {
return this->interface->RegisterAddOnContentStorageDeprecated(id, storage_id);

View File

@@ -39,12 +39,12 @@ namespace ams::lr {
virtual Result UnregisterApplicationAddOnContent(ncm::ApplicationId id) = 0;
public:
DEFINE_SERVICE_DISPATCH_TABLE {
MAKE_SERVICE_COMMAND_META(ResolveAddOnContentPath, hos::Version_200),
MAKE_SERVICE_COMMAND_META(RegisterAddOnContentStorageDeprecated, hos::Version_200, hos::Version_810),
MAKE_SERVICE_COMMAND_META(RegisterAddOnContentStorage, hos::Version_900),
MAKE_SERVICE_COMMAND_META(UnregisterAllAddOnContentPath, hos::Version_200),
MAKE_SERVICE_COMMAND_META(RefreshApplicationAddOnContent, hos::Version_900),
MAKE_SERVICE_COMMAND_META(UnregisterApplicationAddOnContent, hos::Version_900),
MAKE_SERVICE_COMMAND_META(ResolveAddOnContentPath, hos::Version_2_0_0),
MAKE_SERVICE_COMMAND_META(RegisterAddOnContentStorageDeprecated, hos::Version_2_0_0, hos::Version_8_1_0),
MAKE_SERVICE_COMMAND_META(RegisterAddOnContentStorage, hos::Version_9_0_0),
MAKE_SERVICE_COMMAND_META(UnregisterAllAddOnContentPath, hos::Version_2_0_0),
MAKE_SERVICE_COMMAND_META(RefreshApplicationAddOnContent, hos::Version_9_0_0),
MAKE_SERVICE_COMMAND_META(UnregisterApplicationAddOnContent, hos::Version_9_0_0),
};
};

View File

@@ -88,27 +88,27 @@ namespace ams::lr {
MAKE_SERVICE_COMMAND_META(ResolveApplicationControlPath),
MAKE_SERVICE_COMMAND_META(ResolveApplicationHtmlDocumentPath),
MAKE_SERVICE_COMMAND_META(ResolveDataPath),
MAKE_SERVICE_COMMAND_META(RedirectApplicationControlPathDeprecated, hos::Version_100, hos::Version_810),
MAKE_SERVICE_COMMAND_META(RedirectApplicationControlPath, hos::Version_900),
MAKE_SERVICE_COMMAND_META(RedirectApplicationHtmlDocumentPathDeprecated, hos::Version_100, hos::Version_810),
MAKE_SERVICE_COMMAND_META(RedirectApplicationHtmlDocumentPath, hos::Version_900),
MAKE_SERVICE_COMMAND_META(RedirectApplicationControlPathDeprecated, hos::Version_1_0_0, hos::Version_8_1_0),
MAKE_SERVICE_COMMAND_META(RedirectApplicationControlPath, hos::Version_9_0_0),
MAKE_SERVICE_COMMAND_META(RedirectApplicationHtmlDocumentPathDeprecated, hos::Version_1_0_0, hos::Version_8_1_0),
MAKE_SERVICE_COMMAND_META(RedirectApplicationHtmlDocumentPath, hos::Version_9_0_0),
MAKE_SERVICE_COMMAND_META(ResolveApplicationLegalInformationPath),
MAKE_SERVICE_COMMAND_META(RedirectApplicationLegalInformationPathDeprecated, hos::Version_100, hos::Version_810),
MAKE_SERVICE_COMMAND_META(RedirectApplicationLegalInformationPath, hos::Version_900),
MAKE_SERVICE_COMMAND_META(RedirectApplicationLegalInformationPathDeprecated, hos::Version_1_0_0, hos::Version_8_1_0),
MAKE_SERVICE_COMMAND_META(RedirectApplicationLegalInformationPath, hos::Version_9_0_0),
MAKE_SERVICE_COMMAND_META(Refresh),
MAKE_SERVICE_COMMAND_META(RedirectApplicationProgramPathDeprecated, hos::Version_500, hos::Version_810),
MAKE_SERVICE_COMMAND_META(RedirectApplicationProgramPath, hos::Version_900),
MAKE_SERVICE_COMMAND_META(ClearApplicationRedirectionDeprecated, hos::Version_500, hos::Version_810),
MAKE_SERVICE_COMMAND_META(ClearApplicationRedirection, hos::Version_900),
MAKE_SERVICE_COMMAND_META(EraseProgramRedirection, hos::Version_500),
MAKE_SERVICE_COMMAND_META(EraseApplicationControlRedirection, hos::Version_500),
MAKE_SERVICE_COMMAND_META(EraseApplicationHtmlDocumentRedirection, hos::Version_500),
MAKE_SERVICE_COMMAND_META(EraseApplicationLegalInformationRedirection, hos::Version_500),
MAKE_SERVICE_COMMAND_META(ResolveProgramPathForDebug, hos::Version_700),
MAKE_SERVICE_COMMAND_META(RedirectProgramPathForDebug, hos::Version_700),
MAKE_SERVICE_COMMAND_META(RedirectApplicationProgramPathForDebugDeprecated, hos::Version_700, hos::Version_810),
MAKE_SERVICE_COMMAND_META(RedirectApplicationProgramPathForDebug, hos::Version_900),
MAKE_SERVICE_COMMAND_META(EraseProgramRedirectionForDebug, hos::Version_700),
MAKE_SERVICE_COMMAND_META(RedirectApplicationProgramPathDeprecated, hos::Version_5_0_0, hos::Version_8_1_0),
MAKE_SERVICE_COMMAND_META(RedirectApplicationProgramPath, hos::Version_9_0_0),
MAKE_SERVICE_COMMAND_META(ClearApplicationRedirectionDeprecated, hos::Version_5_0_0, hos::Version_8_1_0),
MAKE_SERVICE_COMMAND_META(ClearApplicationRedirection, hos::Version_9_0_0),
MAKE_SERVICE_COMMAND_META(EraseProgramRedirection, hos::Version_5_0_0),
MAKE_SERVICE_COMMAND_META(EraseApplicationControlRedirection, hos::Version_5_0_0),
MAKE_SERVICE_COMMAND_META(EraseApplicationHtmlDocumentRedirection, hos::Version_5_0_0),
MAKE_SERVICE_COMMAND_META(EraseApplicationLegalInformationRedirection, hos::Version_5_0_0),
MAKE_SERVICE_COMMAND_META(ResolveProgramPathForDebug, hos::Version_7_0_0),
MAKE_SERVICE_COMMAND_META(RedirectProgramPathForDebug, hos::Version_7_0_0),
MAKE_SERVICE_COMMAND_META(RedirectApplicationProgramPathForDebugDeprecated, hos::Version_7_0_0, hos::Version_8_1_0),
MAKE_SERVICE_COMMAND_META(RedirectApplicationProgramPathForDebug, hos::Version_9_0_0),
MAKE_SERVICE_COMMAND_META(EraseProgramRedirectionForDebug, hos::Version_7_0_0),
};
};

View File

@@ -56,19 +56,19 @@ namespace ams::lr {
public:
DEFINE_SERVICE_DISPATCH_TABLE {
MAKE_SERVICE_COMMAND_META(ResolveProgramPath),
MAKE_SERVICE_COMMAND_META(RegisterProgramPathDeprecated, hos::Version_100, hos::Version_810),
MAKE_SERVICE_COMMAND_META(RegisterProgramPath, hos::Version_900),
MAKE_SERVICE_COMMAND_META(RegisterProgramPathDeprecated, hos::Version_1_0_0, hos::Version_8_1_0),
MAKE_SERVICE_COMMAND_META(RegisterProgramPath, hos::Version_9_0_0),
MAKE_SERVICE_COMMAND_META(UnregisterProgramPath),
MAKE_SERVICE_COMMAND_META(RedirectProgramPathDeprecated, hos::Version_100, hos::Version_810),
MAKE_SERVICE_COMMAND_META(RedirectProgramPath, hos::Version_900),
MAKE_SERVICE_COMMAND_META(ResolveHtmlDocumentPath, hos::Version_200),
MAKE_SERVICE_COMMAND_META(RegisterHtmlDocumentPathDeprecated, hos::Version_200, hos::Version_810),
MAKE_SERVICE_COMMAND_META(RegisterHtmlDocumentPath, hos::Version_900),
MAKE_SERVICE_COMMAND_META(UnregisterHtmlDocumentPath, hos::Version_200),
MAKE_SERVICE_COMMAND_META(RedirectHtmlDocumentPathDeprecated, hos::Version_200, hos::Version_810),
MAKE_SERVICE_COMMAND_META(RedirectHtmlDocumentPath, hos::Version_900),
MAKE_SERVICE_COMMAND_META(Refresh, hos::Version_700),
MAKE_SERVICE_COMMAND_META(RefreshExcluding, hos::Version_900),
MAKE_SERVICE_COMMAND_META(RedirectProgramPathDeprecated, hos::Version_1_0_0, hos::Version_8_1_0),
MAKE_SERVICE_COMMAND_META(RedirectProgramPath, hos::Version_9_0_0),
MAKE_SERVICE_COMMAND_META(ResolveHtmlDocumentPath, hos::Version_2_0_0),
MAKE_SERVICE_COMMAND_META(RegisterHtmlDocumentPathDeprecated, hos::Version_2_0_0, hos::Version_8_1_0),
MAKE_SERVICE_COMMAND_META(RegisterHtmlDocumentPath, hos::Version_9_0_0),
MAKE_SERVICE_COMMAND_META(UnregisterHtmlDocumentPath, hos::Version_2_0_0),
MAKE_SERVICE_COMMAND_META(RedirectHtmlDocumentPathDeprecated, hos::Version_2_0_0, hos::Version_8_1_0),
MAKE_SERVICE_COMMAND_META(RedirectHtmlDocumentPath, hos::Version_9_0_0),
MAKE_SERVICE_COMMAND_META(Refresh, hos::Version_7_0_0),
MAKE_SERVICE_COMMAND_META(RefreshExcluding, hos::Version_9_0_0),
};
};

View File

@@ -68,7 +68,7 @@ namespace ams::lr {
void RedirectApplicationControlPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) {
AMS_ASSERT(this->interface != nullptr);
if (hos::GetVersion() >= hos::Version_900) {
if (hos::GetVersion() >= hos::Version_9_0_0) {
R_ABORT_UNLESS(this->interface->RedirectApplicationControlPath(path, id, owner_id));
} else {
R_ABORT_UNLESS(this->interface->RedirectApplicationControlPathDeprecated(path, id));
@@ -77,7 +77,7 @@ namespace ams::lr {
void RedirectApplicationHtmlDocumentPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) {
AMS_ASSERT(this->interface != nullptr);
if (hos::GetVersion() >= hos::Version_900) {
if (hos::GetVersion() >= hos::Version_9_0_0) {
R_ABORT_UNLESS(this->interface->RedirectApplicationHtmlDocumentPath(path, id, owner_id));
} else {
R_ABORT_UNLESS(this->interface->RedirectApplicationHtmlDocumentPathDeprecated(path, id));
@@ -91,7 +91,7 @@ namespace ams::lr {
void RedirectApplicationLegalInformationPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) {
AMS_ASSERT(this->interface != nullptr);
if (hos::GetVersion() >= hos::Version_900) {
if (hos::GetVersion() >= hos::Version_9_0_0) {
R_ABORT_UNLESS(this->interface->RedirectApplicationLegalInformationPath(path, id, owner_id));
} else {
R_ABORT_UNLESS(this->interface->RedirectApplicationLegalInformationPathDeprecated(path, id));
@@ -105,7 +105,7 @@ namespace ams::lr {
void RedirectApplicationProgramPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) {
AMS_ASSERT(this->interface != nullptr);
if (hos::GetVersion() >= hos::Version_900) {
if (hos::GetVersion() >= hos::Version_9_0_0) {
R_ABORT_UNLESS(this->interface->RedirectApplicationProgramPath(path, id, owner_id));
} else {
R_ABORT_UNLESS(this->interface->RedirectApplicationProgramPathDeprecated(path, id));
@@ -114,13 +114,13 @@ namespace ams::lr {
Result ClearApplicationRedirection() {
AMS_ASSERT(this->interface != nullptr);
AMS_ASSERT(hos::GetVersion() < hos::Version_900);
AMS_ASSERT(hos::GetVersion() < hos::Version_9_0_0);
return this->ClearApplicationRedirection(nullptr, 0);
}
Result ClearApplicationRedirection(const ncm::ProgramId *excluding_ids, size_t num_ids) {
AMS_ASSERT(this->interface != nullptr);
if (hos::GetVersion() >= hos::Version_900) {
if (hos::GetVersion() >= hos::Version_9_0_0) {
return this->interface->ClearApplicationRedirection(sf::InArray<ncm::ProgramId>(excluding_ids, num_ids));
} else {
return this->interface->ClearApplicationRedirectionDeprecated();
@@ -159,7 +159,7 @@ namespace ams::lr {
void RedirectApplicationProgramPathForDebug(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) {
AMS_ASSERT(this->interface != nullptr);
if (hos::GetVersion() >= hos::Version_900) {
if (hos::GetVersion() >= hos::Version_9_0_0) {
R_ABORT_UNLESS(this->interface->RedirectApplicationProgramPathForDebug(path, id, owner_id));
} else {
R_ABORT_UNLESS(this->interface->RedirectApplicationProgramPathForDebugDeprecated(path, id));

View File

@@ -40,7 +40,7 @@ namespace ams::lr {
MAKE_SERVICE_COMMAND_META(OpenLocationResolver),
MAKE_SERVICE_COMMAND_META(OpenRegisteredLocationResolver),
MAKE_SERVICE_COMMAND_META(RefreshLocationResolver),
MAKE_SERVICE_COMMAND_META(OpenAddOnContentLocationResolver, hos::Version_200),
MAKE_SERVICE_COMMAND_META(OpenAddOnContentLocationResolver, hos::Version_2_0_0),
};
};

View File

@@ -49,7 +49,7 @@ namespace ams::lr {
Result RegisterProgramPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) {
AMS_ASSERT(this->interface);
if (hos::GetVersion() >= hos::Version_900) {
if (hos::GetVersion() >= hos::Version_9_0_0) {
return this->interface->RegisterProgramPath(path, id, owner_id);
} else {
return this->interface->RegisterProgramPathDeprecated(path, id);
@@ -63,7 +63,7 @@ namespace ams::lr {
void RedirectProgramPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) {
AMS_ASSERT(this->interface);
if (hos::GetVersion() >= hos::Version_900) {
if (hos::GetVersion() >= hos::Version_9_0_0) {
R_ABORT_UNLESS(this->interface->RedirectProgramPath(path, id, owner_id));
} else {
R_ABORT_UNLESS(this->interface->RedirectProgramPathDeprecated(path, id));
@@ -77,7 +77,7 @@ namespace ams::lr {
Result RegisterHtmlDocumentPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) {
AMS_ASSERT(this->interface);
if (hos::GetVersion() >= hos::Version_900) {
if (hos::GetVersion() >= hos::Version_9_0_0) {
return this->interface->RegisterHtmlDocumentPath(path, id, owner_id);
} else {
return this->interface->RegisterHtmlDocumentPathDeprecated(path, id);
@@ -91,7 +91,7 @@ namespace ams::lr {
void RedirectHtmlDocumentPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) {
AMS_ASSERT(this->interface);
if (hos::GetVersion() >= hos::Version_900) {
if (hos::GetVersion() >= hos::Version_9_0_0) {
R_ABORT_UNLESS(this->interface->RedirectHtmlDocumentPath(path, id, owner_id));
} else {
R_ABORT_UNLESS(this->interface->RedirectHtmlDocumentPathDeprecated(path, id));

View File

@@ -33,6 +33,7 @@
#include <stratosphere/ncm/ncm_install_task_base.hpp>
#include <stratosphere/ncm/ncm_install_task_data.hpp>
#include <stratosphere/ncm/ncm_install_task_occupied_size.hpp>
#include <stratosphere/ncm/ncm_memory_report.hpp>
#include <stratosphere/ncm/ncm_package_install_task_base.hpp>
#include <stratosphere/ncm/ncm_package_install_task.hpp>
#include <stratosphere/ncm/ncm_package_system_update_task.hpp>

View File

@@ -27,7 +27,7 @@ namespace ams::ncm {
}
bool ShouldBuildDatabase() const {
return hos::GetVersion() < hos::Version_400 || this->build_system_database;
return hos::GetVersion() < hos::Version_4_0_0 || this->build_system_database;
}
bool ShouldImportDatabaseFromSignedSystemPartitionOnSd() const {

View File

@@ -30,14 +30,32 @@
namespace ams::ncm {
class ContentMetaMemoryResource {
class ContentMetaMemoryResource : public MemoryResource {
private:
mem::StandardAllocator allocator;
sf::StandardAllocatorMemoryResource memory_resource;
size_t peak_total_alloc_size;
size_t peak_alloc_size;
public:
ContentMetaMemoryResource(void *heap, size_t heap_size) : allocator(heap, heap_size), memory_resource(std::addressof(allocator)) { /* ... */ }
explicit ContentMetaMemoryResource(void *heap, size_t heap_size) : allocator(heap, heap_size) { /* ... */ }
MemoryResource *Get() { return std::addressof(this->memory_resource); }
mem::StandardAllocator *GetAllocator() { return std::addressof(this->allocator); }
size_t GetPeakTotalAllocationSize() const { return this->peak_total_alloc_size; }
size_t GetPeakAllocationSize() const { return this->peak_alloc_size; }
private:
virtual void *AllocateImpl(size_t size, size_t alignment) override {
void *mem = this->allocator.Allocate(size, alignment);
this->peak_total_alloc_size = std::max(this->allocator.Hash().allocated_size, this->peak_total_alloc_size);
this->peak_alloc_size = std::max(size, this->peak_alloc_size);
return mem;
}
virtual void DeallocateImpl(void *buffer, size_t size, size_t alignment) override {
return this->allocator.Free(buffer);
}
virtual bool IsEqualImpl(const MemoryResource &resource) const override {
return this == std::addressof(resource);
}
};
struct SystemSaveDataInfo {
@@ -127,6 +145,7 @@ namespace ams::ncm {
virtual Result ActivateContentMetaDatabase(StorageId storage_id) override;
virtual Result InactivateContentMetaDatabase(StorageId storage_id) override;
virtual Result InvalidateRightsIdCache() override;
virtual Result GetMemoryReport(sf::Out<MemoryReport> out) override;
};
}

View File

@@ -144,25 +144,25 @@ namespace ams::ncm {
Result GetRightsId(ams::fs::RightsId *out_rights_id, PlaceHolderId placeholder_id) {
AMS_ASSERT(this->interface != nullptr);
AMS_ABORT_UNLESS(hos::GetVersion() < hos::Version_300);
AMS_ABORT_UNLESS(hos::GetVersion() < hos::Version_3_0_0);
return this->interface->GetRightsIdFromPlaceHolderIdDeprecated(out_rights_id, placeholder_id);
}
Result GetRightsId(ncm::RightsId *out_rights_id, PlaceHolderId placeholder_id) {
AMS_ASSERT(this->interface != nullptr);
AMS_ABORT_UNLESS(hos::GetVersion() >= hos::Version_300);
AMS_ABORT_UNLESS(hos::GetVersion() >= hos::Version_3_0_0);
return this->interface->GetRightsIdFromPlaceHolderId(out_rights_id, placeholder_id);
}
Result GetRightsId(ams::fs::RightsId *out_rights_id, ContentId content_id) {
AMS_ASSERT(this->interface != nullptr);
AMS_ABORT_UNLESS(hos::GetVersion() < hos::Version_300);
AMS_ABORT_UNLESS(hos::GetVersion() < hos::Version_3_0_0);
return this->interface->GetRightsIdFromContentIdDeprecated(out_rights_id, content_id);
}
Result GetRightsId(ncm::RightsId *out_rights_id, ContentId content_id) {
AMS_ASSERT(this->interface != nullptr);
AMS_ABORT_UNLESS(hos::GetVersion() >= hos::Version_300);
AMS_ABORT_UNLESS(hos::GetVersion() >= hos::Version_3_0_0);
return this->interface->GetRightsIdFromContentId(out_rights_id, content_id);
}

View File

@@ -16,6 +16,7 @@
#pragma once
#include <stratosphere/ncm/ncm_i_content_storage.hpp>
#include <stratosphere/ncm/ncm_i_content_meta_database.hpp>
#include <stratosphere/ncm/ncm_memory_report.hpp>
namespace ams::ncm {
@@ -36,6 +37,7 @@ namespace ams::ncm {
ActivateContentMetaDatabase = 11,
InactivateContentMetaDatabase = 12,
InvalidateRightsIdCache = 13,
GetMemoryReport = 14,
};
public:
virtual Result CreateContentStorage(StorageId storage_id) = 0;
@@ -52,6 +54,7 @@ namespace ams::ncm {
virtual Result ActivateContentMetaDatabase(StorageId storage_id) = 0;
virtual Result InactivateContentMetaDatabase(StorageId storage_id) = 0;
virtual Result InvalidateRightsIdCache() = 0;
virtual Result GetMemoryReport(sf::Out<MemoryReport> out) = 0;
public:
DEFINE_SERVICE_DISPATCH_TABLE {
MAKE_SERVICE_COMMAND_META(CreateContentStorage),
@@ -60,14 +63,15 @@ namespace ams::ncm {
MAKE_SERVICE_COMMAND_META(VerifyContentMetaDatabase),
MAKE_SERVICE_COMMAND_META(OpenContentStorage),
MAKE_SERVICE_COMMAND_META(OpenContentMetaDatabase),
MAKE_SERVICE_COMMAND_META(CloseContentStorageForcibly, hos::Version_100, hos::Version_100),
MAKE_SERVICE_COMMAND_META(CloseContentMetaDatabaseForcibly, hos::Version_100, hos::Version_100),
MAKE_SERVICE_COMMAND_META(CloseContentStorageForcibly, hos::Version_1_0_0, hos::Version_1_0_0),
MAKE_SERVICE_COMMAND_META(CloseContentMetaDatabaseForcibly, hos::Version_1_0_0, hos::Version_1_0_0),
MAKE_SERVICE_COMMAND_META(CleanupContentMetaDatabase),
MAKE_SERVICE_COMMAND_META(ActivateContentStorage, hos::Version_200),
MAKE_SERVICE_COMMAND_META(InactivateContentStorage, hos::Version_200),
MAKE_SERVICE_COMMAND_META(ActivateContentMetaDatabase, hos::Version_200),
MAKE_SERVICE_COMMAND_META(InactivateContentMetaDatabase, hos::Version_200),
MAKE_SERVICE_COMMAND_META(InvalidateRightsIdCache, hos::Version_900),
MAKE_SERVICE_COMMAND_META(ActivateContentStorage, hos::Version_2_0_0),
MAKE_SERVICE_COMMAND_META(InactivateContentStorage, hos::Version_2_0_0),
MAKE_SERVICE_COMMAND_META(ActivateContentMetaDatabase, hos::Version_2_0_0),
MAKE_SERVICE_COMMAND_META(InactivateContentMetaDatabase, hos::Version_2_0_0),
MAKE_SERVICE_COMMAND_META(InvalidateRightsIdCache, hos::Version_9_0_0),
MAKE_SERVICE_COMMAND_META(GetMemoryReport, hos::Version_10_0_0),
};
};

View File

@@ -43,6 +43,8 @@ namespace ams::ncm {
GetAttributes = 18,
GetRequiredApplicationVersion = 19,
GetContentIdByTypeAndIdOffset = 20,
GetCount = 21,
GetOwnerApplicationId = 22,
};
public:
/* Actual commands. */
@@ -67,6 +69,8 @@ namespace ams::ncm {
virtual Result GetAttributes(sf::Out<u8> out_attributes, const ContentMetaKey &key) = 0;
virtual Result GetRequiredApplicationVersion(sf::Out<u32> out_version, const ContentMetaKey &key) = 0;
virtual Result GetContentIdByTypeAndIdOffset(sf::Out<ContentId> out_content_id, const ContentMetaKey &key, ContentType type, u8 id_offset) = 0;
virtual Result GetCount(sf::Out<u32> out_count) = 0;
virtual Result GetOwnerApplicationId(sf::Out<ApplicationId> out_id, const ContentMetaKey &key) = 0;
public:
DEFINE_SERVICE_DISPATCH_TABLE {
MAKE_SERVICE_COMMAND_META(Set),
@@ -88,8 +92,10 @@ namespace ams::ncm {
MAKE_SERVICE_COMMAND_META(HasContent),
MAKE_SERVICE_COMMAND_META(ListContentMetaInfo),
MAKE_SERVICE_COMMAND_META(GetAttributes),
MAKE_SERVICE_COMMAND_META(GetRequiredApplicationVersion, hos::Version_200),
MAKE_SERVICE_COMMAND_META(GetContentIdByTypeAndIdOffset, hos::Version_500),
MAKE_SERVICE_COMMAND_META(GetRequiredApplicationVersion, hos::Version_2_0_0),
MAKE_SERVICE_COMMAND_META(GetContentIdByTypeAndIdOffset, hos::Version_5_0_0),
MAKE_SERVICE_COMMAND_META(GetCount, hos::Version_10_0_0),
MAKE_SERVICE_COMMAND_META(GetOwnerApplicationId, hos::Version_10_0_0),
};
};

View File

@@ -110,20 +110,20 @@ namespace ams::ncm {
MAKE_SERVICE_COMMAND_META(ListContentId),
MAKE_SERVICE_COMMAND_META(GetSizeFromContentId),
MAKE_SERVICE_COMMAND_META(DisableForcibly),
MAKE_SERVICE_COMMAND_META(RevertToPlaceHolder, hos::Version_200),
MAKE_SERVICE_COMMAND_META(SetPlaceHolderSize, hos::Version_200),
MAKE_SERVICE_COMMAND_META(ReadContentIdFile, hos::Version_200),
MAKE_SERVICE_COMMAND_META(GetRightsIdFromPlaceHolderIdDeprecated, hos::Version_200, hos::Version_200),
MAKE_SERVICE_COMMAND_META(GetRightsIdFromPlaceHolderId, hos::Version_300),
MAKE_SERVICE_COMMAND_META(GetRightsIdFromContentIdDeprecated, hos::Version_200, hos::Version_200),
MAKE_SERVICE_COMMAND_META(GetRightsIdFromContentId, hos::Version_300),
MAKE_SERVICE_COMMAND_META(WriteContentForDebug, hos::Version_200),
MAKE_SERVICE_COMMAND_META(GetFreeSpaceSize, hos::Version_200),
MAKE_SERVICE_COMMAND_META(GetTotalSpaceSize, hos::Version_200),
MAKE_SERVICE_COMMAND_META(FlushPlaceHolder, hos::Version_300),
MAKE_SERVICE_COMMAND_META(GetSizeFromPlaceHolderId, hos::Version_400),
MAKE_SERVICE_COMMAND_META(RepairInvalidFileAttribute, hos::Version_400),
MAKE_SERVICE_COMMAND_META(GetRightsIdFromPlaceHolderIdWithCache, hos::Version_800),
MAKE_SERVICE_COMMAND_META(RevertToPlaceHolder, hos::Version_2_0_0),
MAKE_SERVICE_COMMAND_META(SetPlaceHolderSize, hos::Version_2_0_0),
MAKE_SERVICE_COMMAND_META(ReadContentIdFile, hos::Version_2_0_0),
MAKE_SERVICE_COMMAND_META(GetRightsIdFromPlaceHolderIdDeprecated, hos::Version_2_0_0, hos::Version_2_0_0),
MAKE_SERVICE_COMMAND_META(GetRightsIdFromPlaceHolderId, hos::Version_3_0_0),
MAKE_SERVICE_COMMAND_META(GetRightsIdFromContentIdDeprecated, hos::Version_2_0_0, hos::Version_2_0_0),
MAKE_SERVICE_COMMAND_META(GetRightsIdFromContentId, hos::Version_3_0_0),
MAKE_SERVICE_COMMAND_META(WriteContentForDebug, hos::Version_2_0_0),
MAKE_SERVICE_COMMAND_META(GetFreeSpaceSize, hos::Version_2_0_0),
MAKE_SERVICE_COMMAND_META(GetTotalSpaceSize, hos::Version_2_0_0),
MAKE_SERVICE_COMMAND_META(FlushPlaceHolder, hos::Version_3_0_0),
MAKE_SERVICE_COMMAND_META(GetSizeFromPlaceHolderId, hos::Version_4_0_0),
MAKE_SERVICE_COMMAND_META(RepairInvalidFileAttribute, hos::Version_4_0_0),
MAKE_SERVICE_COMMAND_META(GetRightsIdFromPlaceHolderIdWithCache, hos::Version_8_0_0),
};
};

View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2019-2020 Adubbz, Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 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 <stratosphere/os.hpp>
#include <stratosphere/lmem/lmem_common.hpp>
namespace ams::ncm {
struct MemoryResourceState {
size_t peak_total_alloc_size;
size_t peak_alloc_size;
size_t allocatable_size;
size_t total_free_size;
};
static_assert(sizeof(MemoryResourceState) == 0x20);
struct MemoryReport {
MemoryResourceState system_content_meta_resource_state;
MemoryResourceState sd_and_user_content_meta_resource_state;
MemoryResourceState gamecard_content_meta_resource_state;
MemoryResourceState heap_resource_state;
};
static_assert(sizeof(MemoryReport) == 0x80);
class HeapState {
private:
os::Mutex mutex;
lmem::HeapHandle heap_handle;
size_t total_alloc_size;
size_t peak_total_alloc_size;
size_t peak_alloc_size;
public:
constexpr HeapState() : mutex(false), heap_handle(nullptr), total_alloc_size(0), peak_total_alloc_size(0), peak_alloc_size(0) { /* ... */ }
void Initialize(lmem::HeapHandle heap_handle);
void Allocate(size_t size);
void Free(size_t size);
void GetMemoryResourceState(MemoryResourceState *out);
};
HeapState &GetHeapState();
}

View File

@@ -95,6 +95,7 @@ namespace ams::ncm {
static const SystemProgramId Dt;
static const SystemProgramId Nd;
static const SystemProgramId Ngct;
static const SystemProgramId Pgl;
static const SystemProgramId End;
};
@@ -192,6 +193,7 @@ namespace ams::ncm {
inline constexpr const SystemProgramId SystemProgramId::Dt = { 0x010000000000003Ful };
inline constexpr const SystemProgramId SystemProgramId::Nd = { 0x0100000000000040ul };
inline constexpr const SystemProgramId SystemProgramId::Ngct = { 0x0100000000000041ul };
inline constexpr const SystemProgramId SystemProgramId::Pgl = { 0x0100000000000042ul };
inline constexpr const SystemProgramId SystemProgramId::End = { 0x01000000000007FFul };
@@ -400,6 +402,34 @@ namespace ams::ncm {
return true;
}
struct SystemDebugAppletId {
u64 value;
constexpr operator ProgramId() const {
return { this->value };
}
static const SystemDebugAppletId Start;
static const SystemDebugAppletId SnapShotDumper;
static const SystemDebugAppletId End;
};
inline constexpr const SystemDebugAppletId SystemDebugAppletId::Start = { 0x0100000000002000ul };
inline constexpr const SystemDebugAppletId SystemDebugAppletId::SnapShotDumper = { 0x0100000000002071ul };
inline constexpr const SystemDebugAppletId SystemDebugAppletId::End = { 0x0100000000002FFFul };
inline constexpr bool IsSystemDebugAppletId(const ProgramId &program_id) {
return SystemDebugAppletId::Start <= program_id && program_id <= SystemDebugAppletId::End;
}
inline constexpr bool IsSystemDebugAppletId(const SystemDebugAppletId &program_id) {
return true;
}
struct LibraryAppletId {
u64 value;

View File

@@ -27,6 +27,7 @@
#include <stratosphere/os/os_random.hpp>
#include <stratosphere/os/os_mutex.hpp>
#include <stratosphere/os/os_condition_variable.hpp>
#include <stratosphere/os/os_sdk_mutex.hpp>
#include <stratosphere/os/os_rw_lock.hpp>
#include <stratosphere/os/os_semaphore.hpp>
#include <stratosphere/os/os_event.hpp>

View File

@@ -0,0 +1,60 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 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 <stratosphere/os/impl/os_internal_critical_section.hpp>
namespace ams::os {
class SdkConditionVariable;
struct SdkMutexType {
union {
s32 _arr[sizeof(impl::InternalCriticalSectionStorage) / sizeof(s32)];
impl::InternalCriticalSectionStorage _storage;
};
};
static_assert(std::is_trivial<SdkMutexType>::value);
void InitializeSdkMutex(SdkMutexType *mutex);
void LockSdkMutex(SdkMutexType *mutex);
bool TryLockSdkMutex(SdkMutexType *mutex);
void UnlockSdkMutex(SdkMutexType *mutex);
bool IsSdkMutexLockedByCurrentThread(const SdkMutexType *mutex);
class SdkMutex {
private:
friend class SdkConditionVariable;
private:
SdkMutexType mutex;
public:
constexpr SdkMutex() : mutex{{0}} { /* ... */ }
ALWAYS_INLINE void Lock() { return os::LockSdkMutex(std::addressof(this->mutex)); }
ALWAYS_INLINE bool TryLock() { return os::TryLockSdkMutex(std::addressof(this->mutex)); }
ALWAYS_INLINE void Unlock() { return os::UnlockSdkMutex(std::addressof(this->mutex)); }
ALWAYS_INLINE bool IsLockedByCurrentThread() const { return os::IsSdkMutexLockedByCurrentThread(std::addressof(this->mutex)); }
ALWAYS_INLINE void lock() { return this->Lock(); }
ALWAYS_INLINE bool try_lock() { return this->TryLock(); }
ALWAYS_INLINE void unlock() { return this->Unlock(); }
};
}

View File

@@ -0,0 +1,23 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 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 <stratosphere/pgl/pgl_types.hpp>
#include <stratosphere/pgl/pgl_event_observer.hpp>
#include <stratosphere/pgl/pgl_shell_api.hpp>
#include <stratosphere/pgl/pgl_shell_api.hpp>
#include <stratosphere/pgl/srv/pgl_srv_api.hpp>

View File

@@ -0,0 +1,58 @@
/*
* Copyright (c) 2019-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 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 <stratosphere/os.hpp>
#include <stratosphere/pm.hpp>
#include <stratosphere/pgl/pgl_types.hpp>
#include <stratosphere/pgl/sf/pgl_sf_i_event_observer.hpp>
namespace ams::pgl {
class EventObserver {
NON_COPYABLE(EventObserver);
private:
std::shared_ptr<pgl::sf::IEventObserver> interface;
public:
EventObserver() { /* ... */ }
explicit EventObserver(std::shared_ptr<pgl::sf::IEventObserver> intf) : interface(std::move(intf)) { /* ... */ }
EventObserver(EventObserver &&rhs) {
this->interface = std::move(rhs.interface);
}
EventObserver &operator=(EventObserver &&rhs) {
EventObserver(std::move(rhs)).Swap(*this);
return *this;
}
void Swap(EventObserver &rhs) {
std::swap(this->interface, rhs.interface);
}
public:
Result GetSystemEvent(os::SystemEventType *out) {
ams::sf::CopyHandle handle;
R_TRY(this->interface->GetProcessEventHandle(std::addressof(handle)));
os::AttachSystemEvent(out, handle.GetValue(), true, svc::InvalidHandle, false, os::EventClearMode_AutoClear);
return ResultSuccess();
}
Result GetProcessEventInfo(pm::ProcessEventInfo *out) {
return this->interface->GetProcessEventInfo(out);
}
};
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 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 <stratosphere/pgl/pgl_types.hpp>
#include <stratosphere/pgl/pgl_event_observer.hpp>
namespace ams::pgl {
Result Initialize();
void Finalize();
Result LaunchProgram(os::ProcessId *out, const ncm::ProgramLocation &loc, u32 process_flags, u8 pgl_flags);
Result TerminateProcess(os::ProcessId process_id);
Result LaunchProgramFromHost(os::ProcessId *out, const char *content_path, u32 process_flags);
Result GetHostContentMetaInfo(pgl::ContentMetaInfo *out, const char *content_path);
Result GetApplicationProcessId(os::ProcessId *out);
Result BoostSystemMemoryResourceLimit(u64 size);
Result IsProcessTracked(bool *out, os::ProcessId process_id);
Result EnableApplicationCrashReport(bool enabled);
Result IsApplicationCrashReportEnabled(bool *out);
Result EnableApplicationAllThreadDumpOnCrash(bool enabled);
Result TriggerApplicationSnapShotDumper(const char *arg, SnapShotDumpType dump_type);
Result GetEventObserver(pgl::EventObserver *out);
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 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 <stratosphere/os.hpp>
#include <stratosphere/pm.hpp>
#include <stratosphere/ncm.hpp>
namespace ams::pgl {
enum LaunchFlags : u8 {
LaunchFlags_None = 0,
LaunchFlags_EnableDetailedCrashReport = (1 << 0),
LaunchFlags_EnableCrashReportScreenShotForProduction = (1 << 1),
LaunchFlags_EnableCrashReportScreenShotForDevelop = (1 << 2),
};
enum class SnapShotDumpType : u32 {
None = 0,
Auto = 1,
Full = 2,
};
/* TODO: Is this really nn::ncm::Content<Something>Info? */
struct ContentMetaInfo {
u64 id;
u32 version;
ncm::ContentType content_type;
u8 id_offset;
u8 reserved_0E[2];
static constexpr ContentMetaInfo Make(u64 id, u32 version, ncm::ContentType content_type, u8 id_offset) {
return {
.id = id,
.version = version,
.content_type = content_type,
.id_offset = id_offset,
};
}
};
static_assert(sizeof(ContentMetaInfo) == 0x10 && std::is_pod<ContentMetaInfo>::value);
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 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 <stratosphere/os.hpp>
#include <stratosphere/pm.hpp>
#include <stratosphere/pgl/pgl_types.hpp>
namespace ams::pgl::sf {
class IEventObserver : public ams::sf::IServiceObject {
protected:
enum class CommandId {
GetProcessEventHandle = 0,
GetProcessEventInfo = 1,
};
public:
/* Actual commands. */
virtual Result GetProcessEventHandle(ams::sf::OutCopyHandle out) = 0;
virtual Result GetProcessEventInfo(ams::sf::Out<pm::ProcessEventInfo> out) = 0;
public:
DEFINE_SERVICE_DISPATCH_TABLE {
MAKE_SERVICE_COMMAND_META(GetProcessEventHandle),
MAKE_SERVICE_COMMAND_META(GetProcessEventInfo),
};
};
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 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 <stratosphere/os.hpp>
#include <stratosphere/pm.hpp>
#include <stratosphere/pgl/pgl_types.hpp>
#include <stratosphere/pgl/sf/pgl_sf_i_event_observer.hpp>
namespace ams::pgl::sf {
class IShellInterface : public ams::sf::IServiceObject {
protected:
enum class CommandId {
LaunchProgram = 0,
TerminateProcess = 1,
LaunchProgramFromHost = 2,
GetHostContentMetaInfo = 4,
GetApplicationProcessId = 5,
BoostSystemMemoryResourceLimit = 6,
IsProcessTracked = 7,
EnableApplicationCrashReport = 8,
IsApplicationCrashReportEnabled = 9,
EnableApplicationAllThreadDumpOnCrash = 10,
TriggerApplicationSnapShotDumper = 12,
GetShellEventObserver = 20,
};
public:
/* Actual commands. */
virtual Result LaunchProgram(ams::sf::Out<os::ProcessId> out, const ncm::ProgramLocation &loc, u32 pm_flags, u8 pgl_flags) = 0;
virtual Result TerminateProcess(os::ProcessId process_id) = 0;
virtual Result LaunchProgramFromHost(ams::sf::Out<os::ProcessId> out, const ams::sf::InBuffer &content_path, u32 pm_flags) = 0;
virtual Result GetHostContentMetaInfo(ams::sf::Out<pgl::ContentMetaInfo> out, const ams::sf::InBuffer &content_path) = 0;
virtual Result GetApplicationProcessId(ams::sf::Out<os::ProcessId> out) = 0;
virtual Result BoostSystemMemoryResourceLimit(u64 size) = 0;
virtual Result IsProcessTracked(ams::sf::Out<bool> out, os::ProcessId process_id) = 0;
virtual Result EnableApplicationCrashReport(bool enabled) = 0;
virtual Result IsApplicationCrashReportEnabled(ams::sf::Out<bool> out) = 0;
virtual Result EnableApplicationAllThreadDumpOnCrash(bool enabled) = 0;
virtual Result TriggerApplicationSnapShotDumper(SnapShotDumpType dump_type, const ams::sf::InBuffer &arg) = 0;
virtual Result GetShellEventObserver(ams::sf::Out<std::shared_ptr<pgl::sf::IEventObserver>> out) = 0;
public:
DEFINE_SERVICE_DISPATCH_TABLE {
MAKE_SERVICE_COMMAND_META(LaunchProgram),
MAKE_SERVICE_COMMAND_META(TerminateProcess),
MAKE_SERVICE_COMMAND_META(LaunchProgramFromHost),
MAKE_SERVICE_COMMAND_META(GetHostContentMetaInfo),
MAKE_SERVICE_COMMAND_META(GetApplicationProcessId),
MAKE_SERVICE_COMMAND_META(BoostSystemMemoryResourceLimit),
MAKE_SERVICE_COMMAND_META(IsProcessTracked),
MAKE_SERVICE_COMMAND_META(EnableApplicationCrashReport),
MAKE_SERVICE_COMMAND_META(IsApplicationCrashReportEnabled),
MAKE_SERVICE_COMMAND_META(EnableApplicationAllThreadDumpOnCrash),
MAKE_SERVICE_COMMAND_META(TriggerApplicationSnapShotDumper),
MAKE_SERVICE_COMMAND_META(GetShellEventObserver),
};
};
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 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 <stratosphere/pgl/pgl_types.hpp>
#include <stratosphere/pgl/srv/pgl_srv_shell_interface.hpp>
namespace ams::pgl::srv {
void Initialize(ShellInterface *interface, MemoryResource *mr);
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 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 <stratosphere/pgl/pgl_types.hpp>
#include <stratosphere/pgl/sf/pgl_sf_i_shell_interface.hpp>
namespace ams::pgl::srv {
class ShellInterface final : public pgl::sf::IShellInterface {
NON_COPYABLE(ShellInterface);
NON_MOVEABLE(ShellInterface);
private:
MemoryResource *memory_resource;
public:
constexpr ShellInterface() : memory_resource(nullptr) { /* ... */ }
void Initialize(MemoryResource *mr) {
AMS_ASSERT(this->memory_resource == nullptr);
this->memory_resource = mr;
}
public:
/* Interface commands. */
virtual Result LaunchProgram(ams::sf::Out<os::ProcessId> out, const ncm::ProgramLocation &loc, u32 pm_flags, u8 pgl_flags) override final;
virtual Result TerminateProcess(os::ProcessId process_id) override final;
virtual Result LaunchProgramFromHost(ams::sf::Out<os::ProcessId> out, const ams::sf::InBuffer &content_path, u32 pm_flags) override final;
virtual Result GetHostContentMetaInfo(ams::sf::Out<pgl::ContentMetaInfo> out, const ams::sf::InBuffer &content_path) override final;
virtual Result GetApplicationProcessId(ams::sf::Out<os::ProcessId> out) override final;
virtual Result BoostSystemMemoryResourceLimit(u64 size) override final;
virtual Result IsProcessTracked(ams::sf::Out<bool> out, os::ProcessId process_id) override final;
virtual Result EnableApplicationCrashReport(bool enabled) override final;
virtual Result IsApplicationCrashReportEnabled(ams::sf::Out<bool> out) override final;
virtual Result EnableApplicationAllThreadDumpOnCrash(bool enabled) override final;
virtual Result TriggerApplicationSnapShotDumper(SnapShotDumpType dump_type, const ams::sf::InBuffer &arg) override final;
virtual Result GetShellEventObserver(ams::sf::Out<std::shared_ptr<pgl::sf::IEventObserver>> out) override final;
};
}

View File

@@ -23,6 +23,12 @@
namespace ams::pm::shell {
/* Shell API. */
Result LaunchProgram(os::ProcessId *out_process_id, const ncm::ProgramLocation &loc, u32 launch_flags);
Result LaunchProgram(os::ProcessId *out, const ncm::ProgramLocation &loc, u32 launch_flags);
Result TerminateProcess(os::ProcessId process_id);
Result GetProcessEventEvent(os::SystemEvent *out);
Result GetProcessEventInfo(ProcessEventInfo *out);
Result GetApplicationProcessIdForShell(os::ProcessId *out);
Result BoostSystemMemoryResourceLimit(u64 size);
Result EnableApplicationExtraThread();
}

View File

@@ -32,7 +32,66 @@ namespace ams::pm {
ResourceLimitGroup_Count,
};
using LimitableResource = ::LimitableResource;
enum LaunchFlags : u32 {
LaunchFlags_None = 0,
LaunchFlags_SignalOnExit = (1 << 0),
LaunchFlags_SignalOnStart = (1 << 1),
LaunchFlags_SignalOnException = (1 << 2),
LaunchFlags_SignalOnDebugEvent = (1 << 3),
LaunchFlags_StartSuspended = (1 << 4),
LaunchFlags_DisableAslr = (1 << 5),
};
enum LaunchFlagsDeprecated : u32 {
LaunchFlagsDeprecated_None = 0,
LaunchFlagsDeprecated_SignalOnExit = (1 << 0),
LaunchFlagsDeprecated_StartSuspended = (1 << 1),
LaunchFlagsDeprecated_SignalOnException = (1 << 2),
LaunchFlagsDeprecated_DisableAslr = (1 << 3),
LaunchFlagsDeprecated_SignalOnDebugEvent = (1 << 4),
LaunchFlagsDeprecated_SignalOnStart = (1 << 5),
};
constexpr inline u32 LaunchFlagsMask = (1 << 6) - 1;
enum class ProcessEvent : u32 {
None = 0,
Exited = 1,
Started = 2,
Exception = 3,
DebugRunning = 4,
DebugBreak = 5,
};
enum class ProcessEventDeprecated : u32 {
None = 0,
Exception = 1,
Exited = 2,
DebugRunning = 3,
DebugBreak = 4,
Started = 5,
};
inline u32 GetProcessEventValue(ProcessEvent event) {
if (hos::GetVersion() >= hos::Version_5_0_0) {
return static_cast<u32>(event);
}
switch (event) {
case ProcessEvent::None:
return static_cast<u32>(ProcessEventDeprecated::None);
case ProcessEvent::Exited:
return static_cast<u32>(ProcessEventDeprecated::Exited);
case ProcessEvent::Started:
return static_cast<u32>(ProcessEventDeprecated::Started);
case ProcessEvent::Exception:
return static_cast<u32>(ProcessEventDeprecated::Exception);
case ProcessEvent::DebugRunning:
return static_cast<u32>(ProcessEventDeprecated::DebugRunning);
case ProcessEvent::DebugBreak:
return static_cast<u32>(ProcessEventDeprecated::DebugBreak);
AMS_UNREACHABLE_DEFAULT_CASE();
}
}
struct ProcessEventInfo {
u32 event;

View File

@@ -43,7 +43,7 @@ namespace ams::psc::sf {
MAKE_SERVICE_COMMAND_META(GetRequest),
MAKE_SERVICE_COMMAND_META(Acknowledge),
MAKE_SERVICE_COMMAND_META(Finalize),
MAKE_SERVICE_COMMAND_META(AcknowledgeEx, hos::Version_600), /* TODO: This is really 5.1.0... */
MAKE_SERVICE_COMMAND_META(AcknowledgeEx, hos::Version_6_0_0), /* TODO: This is really 5.1.0... */
};
};

View File

@@ -19,6 +19,7 @@
#include "settings/settings_types.hpp"
#include "settings/settings_fwdbg_types.hpp"
#include "settings/settings_fwdbg_api.hpp"
#include "settings/system/settings_error_report.hpp"
#include "settings/system/settings_firmware_version.hpp"
#include "settings/system/settings_product_model.hpp"
#include "settings/system/settings_region.hpp"

View File

@@ -0,0 +1,31 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 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 <stratosphere/settings/settings_types.hpp>
namespace ams::settings::system {
enum ErrorReportSharePermission {
ErrorReportSharePermission_NotConfirmed = 0,
ErrorReportSharePermission_Granted = 1,
ErrorReportSharePermission_Denied = 2,
};
ErrorReportSharePermission GetErrorReportSharePermission();
}

View File

@@ -16,15 +16,16 @@
#pragma once
#include "sf/sf_common.hpp"
#include "sf/sf_mem_utility.hpp"
#include "sf/sf_service_object.hpp"
#include "sf/hipc/sf_hipc_server_session_manager.hpp"
#include <stratosphere/sf/sf_common.hpp>
#include <stratosphere/sf/sf_lmem_utility.hpp>
#include <stratosphere/sf/sf_mem_utility.hpp>
#include <stratosphere/sf/sf_service_object.hpp>
#include <stratosphere/sf/hipc/sf_hipc_server_session_manager.hpp>
#include "sf/sf_out.hpp"
#include "sf/sf_buffers.hpp"
#include "sf/impl/sf_impl_command_serialization.hpp"
#include <stratosphere/sf/sf_out.hpp>
#include <stratosphere/sf/sf_buffers.hpp>
#include <stratosphere/sf/impl/sf_impl_command_serialization.hpp>
#include "sf/hipc/sf_hipc_server_manager.hpp"
#include <stratosphere/sf/hipc/sf_hipc_server_manager.hpp>
#include "sf/sf_mitm_dispatch.h"
#include <stratosphere/sf/sf_mitm_dispatch.h>

View File

@@ -0,0 +1,67 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 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 <stratosphere/sf/sf_common.hpp>
#include <stratosphere/lmem.hpp>
namespace ams::sf {
class ExpHeapMemoryResource : public MemoryResource {
private:
lmem::HeapHandle handle;
public:
explicit ExpHeapMemoryResource(lmem::HeapHandle h) : handle(h) { /* ... */ }
lmem::HeapHandle GetHandle() const { return this->handle; }
private:
virtual void *AllocateImpl(size_t size, size_t alignment) override {
return lmem::AllocateFromExpHeap(this->handle, size, static_cast<int>(alignment));
}
virtual void DeallocateImpl(void *buffer, size_t size, size_t alignment) override {
return lmem::FreeToExpHeap(this->handle, buffer);
}
virtual bool IsEqualImpl(const MemoryResource &resource) const {
return this == std::addressof(resource);
}
};
class UnitHeapMemoryResource : public MemoryResource {
private:
lmem::HeapHandle handle;
public:
explicit UnitHeapMemoryResource(lmem::HeapHandle h) : handle(h) { /* ... */ }
lmem::HeapHandle GetHandle() const { return this->handle; }
private:
virtual void *AllocateImpl(size_t size, size_t alignment) override {
AMS_ASSERT(size <= lmem::GetUnitHeapUnitSize(this->handle));
AMS_ASSERT(alignment <= static_cast<size_t>(lmem::GetUnitHeapAlignment(this->handle)));
return lmem::AllocateFromUnitHeap(this->handle);
}
virtual void DeallocateImpl(void *buffer, size_t size, size_t alignment) override {
return lmem::FreeToUnitHeap(this->handle, buffer);
}
virtual bool IsEqualImpl(const MemoryResource &resource) const {
return this == std::addressof(resource);
}
};
}

View File

@@ -21,6 +21,7 @@ namespace ams::spl {
HardwareType GetHardwareType();
MemoryArrangement GetMemoryArrangement();
bool IsDisabledProgramVerification();
bool IsDevelopmentHardware();
bool IsDevelopmentFunctionEnabled();
bool IsMariko();

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